@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,232 @@
|
|
|
1
|
+
import { EXIT_CODES } from "../../types/index.js";
|
|
2
|
+
import { resolveRepoRoot } from "../../utils/path.js";
|
|
3
|
+
import { runProjectInit } from "../../core/brain-product/init.js";
|
|
4
|
+
import { buildIntelligenceGraph } from "../../intelligence/graph/build.js";
|
|
5
|
+
import { analyzeGitIntelligence, deadCodeCategory } from "../../intelligence/git/analyze.js";
|
|
6
|
+
import { buildC4Views } from "../../architecture/c4.js";
|
|
7
|
+
import { createKnowledgeRecord, listKnowledge, retrieveAuthoritative, transitionKnowledge, } from "../../knowledge/store.js";
|
|
8
|
+
import { authenticateLocalDev, authorize, registerLocalDevUser } from "../../team/auth.js";
|
|
9
|
+
import { runControlledCommand } from "../../enforcement/runner.js";
|
|
10
|
+
import { analyzeTestImpact, analyzeRenameImpact, buildRepositoryGraph, } from "../../platform/index.js";
|
|
11
|
+
import { CONTRACTS_VERSION, DEFAULT_FEATURE_FLAGS } from "../../contracts/index.js";
|
|
12
|
+
import { platformFindingToContract } from "../../contracts/adapters.js";
|
|
13
|
+
function printJson(value) {
|
|
14
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
15
|
+
}
|
|
16
|
+
export async function runInitCommand(options) {
|
|
17
|
+
const root = resolveRepoRoot(options.root ?? process.cwd());
|
|
18
|
+
const result = await runProjectInit(root, {
|
|
19
|
+
...(options.name ? { projectName: options.name } : {}),
|
|
20
|
+
...(options.domain ? { businessDomain: options.domain } : {}),
|
|
21
|
+
});
|
|
22
|
+
if (options.json)
|
|
23
|
+
printJson(result);
|
|
24
|
+
else {
|
|
25
|
+
process.stdout.write(`AgentDoctor init wrote ${result.artifacts.length} PROPOSED artifacts under .agentdoctor/repository-brain/proposals/\nNone are approved facts until: agentdoctor brain review --artifact <id> --decision approved\n`);
|
|
26
|
+
}
|
|
27
|
+
return EXIT_CODES.SUCCESS;
|
|
28
|
+
}
|
|
29
|
+
export async function runV2SurfaceCommand(options) {
|
|
30
|
+
const root = resolveRepoRoot(options.root ?? process.cwd());
|
|
31
|
+
try {
|
|
32
|
+
switch (options.action) {
|
|
33
|
+
case "graph-ast": {
|
|
34
|
+
const graph = await buildIntelligenceGraph({
|
|
35
|
+
root,
|
|
36
|
+
mode: options.mode ?? "auto",
|
|
37
|
+
});
|
|
38
|
+
if (options.json)
|
|
39
|
+
printJson(graph);
|
|
40
|
+
else
|
|
41
|
+
process.stdout.write(`graph builder=${graph.builder} nodes=${graph.nodes.length} edges=${graph.edges.length} astFiles=${graph.astFilesParsed}\n`);
|
|
42
|
+
return EXIT_CODES.SUCCESS;
|
|
43
|
+
}
|
|
44
|
+
case "health":
|
|
45
|
+
case "git-intel": {
|
|
46
|
+
const report = await analyzeGitIntelligence(root);
|
|
47
|
+
if (options.json)
|
|
48
|
+
printJson(report);
|
|
49
|
+
else
|
|
50
|
+
process.stdout.write(`git-intel hotspots=${report.hotspots.length} coChanges=${report.coChanges.length} git=${report.gitAvailable}\n`);
|
|
51
|
+
return EXIT_CODES.SUCCESS;
|
|
52
|
+
}
|
|
53
|
+
case "c4": {
|
|
54
|
+
const graph = await buildIntelligenceGraph({ root, mode: "auto" });
|
|
55
|
+
const views = buildC4Views(graph);
|
|
56
|
+
if (options.json)
|
|
57
|
+
printJson({ views, featureFlag: DEFAULT_FEATURE_FLAGS.architectureC4 });
|
|
58
|
+
else
|
|
59
|
+
process.stdout.write(`C4 views: ${views.map((v) => v.level).join(", ")}\n`);
|
|
60
|
+
return EXIT_CODES.SUCCESS;
|
|
61
|
+
}
|
|
62
|
+
case "dead-code-demo": {
|
|
63
|
+
const sample = deadCodeCategory({
|
|
64
|
+
exported: true,
|
|
65
|
+
referenced: false,
|
|
66
|
+
frameworkEntry: false,
|
|
67
|
+
dynamicHint: false,
|
|
68
|
+
});
|
|
69
|
+
if (options.json)
|
|
70
|
+
printJson(sample);
|
|
71
|
+
else
|
|
72
|
+
process.stdout.write(`${sample.category} confidence=${sample.confidence}\n`);
|
|
73
|
+
return EXIT_CODES.SUCCESS;
|
|
74
|
+
}
|
|
75
|
+
case "knowledge-create": {
|
|
76
|
+
if (!options.title || !options.content) {
|
|
77
|
+
console.error("Error: --title and --content required");
|
|
78
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
79
|
+
}
|
|
80
|
+
const rec = await createKnowledgeRecord({
|
|
81
|
+
root,
|
|
82
|
+
title: options.title,
|
|
83
|
+
content: options.content,
|
|
84
|
+
status: "draft",
|
|
85
|
+
});
|
|
86
|
+
if (options.json)
|
|
87
|
+
printJson(rec);
|
|
88
|
+
else
|
|
89
|
+
process.stdout.write(`Created draft knowledge ${rec.id}\n`);
|
|
90
|
+
return EXIT_CODES.SUCCESS;
|
|
91
|
+
}
|
|
92
|
+
case "knowledge-list": {
|
|
93
|
+
const list = await listKnowledge(root);
|
|
94
|
+
if (options.json)
|
|
95
|
+
printJson({ records: list });
|
|
96
|
+
else
|
|
97
|
+
for (const r of list)
|
|
98
|
+
process.stdout.write(`${r.id} [${r.status}] ${r.title}\n`);
|
|
99
|
+
return EXIT_CODES.SUCCESS;
|
|
100
|
+
}
|
|
101
|
+
case "knowledge-transition": {
|
|
102
|
+
if (!options.id || !options.decision) {
|
|
103
|
+
console.error("Error: --id and --decision required");
|
|
104
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
105
|
+
}
|
|
106
|
+
const rec = await transitionKnowledge({
|
|
107
|
+
root,
|
|
108
|
+
id: options.id,
|
|
109
|
+
to: options.decision,
|
|
110
|
+
});
|
|
111
|
+
if (options.json)
|
|
112
|
+
printJson(rec);
|
|
113
|
+
else
|
|
114
|
+
process.stdout.write(`${rec.id} -> ${rec.status}\n`);
|
|
115
|
+
return EXIT_CODES.SUCCESS;
|
|
116
|
+
}
|
|
117
|
+
case "knowledge-query": {
|
|
118
|
+
const list = await listKnowledge(root);
|
|
119
|
+
const result = retrieveAuthoritative(list, options.query ?? "");
|
|
120
|
+
if (options.json)
|
|
121
|
+
printJson(result);
|
|
122
|
+
else
|
|
123
|
+
process.stdout.write(result.abstain
|
|
124
|
+
? `ABSTAIN: ${result.reason}\n`
|
|
125
|
+
: `AUTHORITATIVE: ${result.record?.title}\n`);
|
|
126
|
+
return EXIT_CODES.SUCCESS;
|
|
127
|
+
}
|
|
128
|
+
case "team-register": {
|
|
129
|
+
if (!options.username || !options.password) {
|
|
130
|
+
console.error("Error: --username and --password required (local-dev auth only)");
|
|
131
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
132
|
+
}
|
|
133
|
+
const user = await registerLocalDevUser({
|
|
134
|
+
root,
|
|
135
|
+
username: options.username,
|
|
136
|
+
password: options.password,
|
|
137
|
+
role: "admin",
|
|
138
|
+
});
|
|
139
|
+
if (options.json)
|
|
140
|
+
printJson({ ...user, notice: "local-dev auth — not enterprise SSO" });
|
|
141
|
+
else
|
|
142
|
+
process.stdout.write(`Registered local-dev user ${user.username} (${user.id})\n`);
|
|
143
|
+
return EXIT_CODES.SUCCESS;
|
|
144
|
+
}
|
|
145
|
+
case "team-login": {
|
|
146
|
+
if (!options.username || !options.password) {
|
|
147
|
+
console.error("Error: --username and --password required");
|
|
148
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
149
|
+
}
|
|
150
|
+
const session = await authenticateLocalDev({
|
|
151
|
+
root,
|
|
152
|
+
username: options.username,
|
|
153
|
+
password: options.password,
|
|
154
|
+
});
|
|
155
|
+
if (options.json)
|
|
156
|
+
printJson({ ...session, notice: "local-dev session — not enterprise SSO" });
|
|
157
|
+
else
|
|
158
|
+
process.stdout.write(`token=${session.token} expires=${session.expiresAt}\n`);
|
|
159
|
+
return EXIT_CODES.SUCCESS;
|
|
160
|
+
}
|
|
161
|
+
case "team-authorize": {
|
|
162
|
+
if (!options.token) {
|
|
163
|
+
console.error("Error: --token required");
|
|
164
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
165
|
+
}
|
|
166
|
+
const result = await authorize(root, options.token, "member");
|
|
167
|
+
if (options.json)
|
|
168
|
+
printJson(result);
|
|
169
|
+
else
|
|
170
|
+
process.stdout.write(`${result.ok ? "OK" : "DENIED"}: ${result.reason}\n`);
|
|
171
|
+
return EXIT_CODES.SUCCESS;
|
|
172
|
+
}
|
|
173
|
+
case "enforce-check": {
|
|
174
|
+
if (!options.command) {
|
|
175
|
+
console.error("Error: --command required");
|
|
176
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
177
|
+
}
|
|
178
|
+
const result = await runControlledCommand({ root, command: options.command });
|
|
179
|
+
if (options.json)
|
|
180
|
+
printJson(result);
|
|
181
|
+
else
|
|
182
|
+
process.stdout.write(`enforced=${result.enforced} status=${result.decision.executionStatus} decision=${result.decision.decision}\n`);
|
|
183
|
+
return EXIT_CODES.SUCCESS;
|
|
184
|
+
}
|
|
185
|
+
case "impact": {
|
|
186
|
+
const impact = await analyzeTestImpact({ root });
|
|
187
|
+
if (options.json)
|
|
188
|
+
printJson({ kind: "test-impact", contractsVersion: CONTRACTS_VERSION, impact });
|
|
189
|
+
else
|
|
190
|
+
process.stdout.write(`impact mode=${impact.mode} recommendedTests=${impact.recommendedTests.length}\n`);
|
|
191
|
+
return EXIT_CODES.SUCCESS;
|
|
192
|
+
}
|
|
193
|
+
case "refactor-impact": {
|
|
194
|
+
if (!options.symbol) {
|
|
195
|
+
console.error("Error: --symbol required");
|
|
196
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
197
|
+
}
|
|
198
|
+
const graph = await buildRepositoryGraph(root);
|
|
199
|
+
const impact = await analyzeRenameImpact({ root, symbol: options.symbol, graph });
|
|
200
|
+
if (options.json)
|
|
201
|
+
printJson(impact);
|
|
202
|
+
else
|
|
203
|
+
process.stdout.write(`refactor ${options.symbol} affected=${impact.affectedFiles.length}\n`);
|
|
204
|
+
return EXIT_CODES.SUCCESS;
|
|
205
|
+
}
|
|
206
|
+
case "contracts-demo": {
|
|
207
|
+
const sample = platformFindingToContract({
|
|
208
|
+
id: "demo",
|
|
209
|
+
module: "demo",
|
|
210
|
+
severity: "info",
|
|
211
|
+
title: "demo",
|
|
212
|
+
message: "demo",
|
|
213
|
+
recommendation: "n/a",
|
|
214
|
+
confidence: 1,
|
|
215
|
+
evidence: [{ kind: "verified", detail: "ok" }],
|
|
216
|
+
});
|
|
217
|
+
if (options.json)
|
|
218
|
+
printJson({ contractsVersion: CONTRACTS_VERSION, sample });
|
|
219
|
+
else
|
|
220
|
+
process.stdout.write(`contracts ${CONTRACTS_VERSION}\n`);
|
|
221
|
+
return EXIT_CODES.SUCCESS;
|
|
222
|
+
}
|
|
223
|
+
default:
|
|
224
|
+
console.error(`Error: unknown action ${options.action}`);
|
|
225
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
230
|
+
return EXIT_CODES.INTERNAL_ERROR;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
@@ -13,7 +13,7 @@ export async function runExplainCommand(ruleId) {
|
|
|
13
13
|
const rule = getRuleById(ruleId.trim());
|
|
14
14
|
if (!rule) {
|
|
15
15
|
console.error(`Error: unknown rule id "${ruleId}"`);
|
|
16
|
-
console.error("Run agentdoctor explain with a documented rule from docs/rules.md");
|
|
16
|
+
console.error("Run agentdoctor explain with a documented rule from docs/reference/rules.md");
|
|
17
17
|
return EXIT_CODES.USAGE_ERROR;
|
|
18
18
|
}
|
|
19
19
|
const agents = rule.affectedAgents?.map((id) => AGENT_DISPLAY_NAMES[id] ?? id).join(", ") ??
|
package/dist/cli/commands/fix.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EXIT_CODES } from "../../types/index.js";
|
|
2
2
|
import { isDirectory } from "../../utils/fs.js";
|
|
3
3
|
import { resolveRepoRoot } from "../../utils/path.js";
|
|
4
|
-
import { applyFixPlan, readClaudeSettings, readCodexConfig, readCursorignore, } from "../../core/fix/apply.js";
|
|
4
|
+
import { applyFixPlan, readClaudeSettings, readCodexConfig, readCursorignore, readSimpleIgnore, } from "../../core/fix/apply.js";
|
|
5
5
|
import { buildFixPlan } from "../../core/fix/plan.js";
|
|
6
6
|
import { renderFixPlanTerminal } from "../../core/fix/render.js";
|
|
7
7
|
import { runFix } from "../../core/fix/run.js";
|
|
@@ -25,14 +25,22 @@ export async function runFixCommand(options) {
|
|
|
25
25
|
const cursorContent = await readCursorignore(plan.root);
|
|
26
26
|
const claudeSettingsContent = await readClaudeSettings(plan.root);
|
|
27
27
|
const codexConfigContent = await readCodexConfig(plan.root);
|
|
28
|
+
const geminiignoreContent = await readSimpleIgnore(plan.root, ".geminiignore");
|
|
29
|
+
const aiderignoreContent = await readSimpleIgnore(plan.root, ".aiderignore");
|
|
28
30
|
const applyResult = await applyFixPlan(plan, { dryRun: true });
|
|
29
31
|
process.stdout.write(renderFixPlanTerminal(plan, {
|
|
30
32
|
dryRun: true,
|
|
31
33
|
cursorContent,
|
|
32
34
|
claudeSettingsContent,
|
|
33
35
|
codexConfigContent,
|
|
36
|
+
geminiignoreContent,
|
|
37
|
+
aiderignoreContent,
|
|
34
38
|
applyResult,
|
|
35
39
|
}));
|
|
40
|
+
if (applyResult.error) {
|
|
41
|
+
console.error(`Error: ${applyResult.error}`);
|
|
42
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
43
|
+
}
|
|
36
44
|
return EXIT_CODES.SUCCESS;
|
|
37
45
|
}
|
|
38
46
|
const { plan, applyResult, cancelled } = await runFix({
|
|
@@ -47,13 +55,23 @@ export async function runFixCommand(options) {
|
|
|
47
55
|
const cursorContentAfter = await readCursorignore(plan.root);
|
|
48
56
|
const claudeSettingsAfter = await readClaudeSettings(plan.root);
|
|
49
57
|
const codexConfigAfter = await readCodexConfig(plan.root);
|
|
58
|
+
const geminiignoreAfter = await readSimpleIgnore(plan.root, ".geminiignore");
|
|
59
|
+
const aiderignoreAfter = await readSimpleIgnore(plan.root, ".aiderignore");
|
|
50
60
|
process.stdout.write(renderFixPlanTerminal(plan, {
|
|
51
61
|
dryRun: false,
|
|
52
62
|
cursorContent: cursorContentAfter,
|
|
53
63
|
claudeSettingsContent: claudeSettingsAfter,
|
|
54
64
|
codexConfigContent: codexConfigAfter,
|
|
65
|
+
geminiignoreContent: geminiignoreAfter,
|
|
66
|
+
aiderignoreContent: aiderignoreAfter,
|
|
55
67
|
applyResult,
|
|
56
68
|
}));
|
|
69
|
+
if (applyResult.error) {
|
|
70
|
+
console.error(`Error: ${applyResult.error}`);
|
|
71
|
+
return isFixConfigOrPermissionError(applyResult.error)
|
|
72
|
+
? EXIT_CODES.USAGE_ERROR
|
|
73
|
+
: EXIT_CODES.INTERNAL_ERROR;
|
|
74
|
+
}
|
|
57
75
|
if (applyResult.writtenFiles.length > 0) {
|
|
58
76
|
const after = await scan({ cwd: target });
|
|
59
77
|
const remainingSafeContext = after.findings.filter((f) => f.fixability === "safe" &&
|
|
@@ -73,8 +91,10 @@ export async function runFixCommand(options) {
|
|
|
73
91
|
}
|
|
74
92
|
function isFixConfigOrPermissionError(message) {
|
|
75
93
|
return (message.includes("refusing") ||
|
|
94
|
+
message.includes("not allowlisted") ||
|
|
76
95
|
message.includes("not valid JSON") ||
|
|
77
96
|
message.includes("EACCES") ||
|
|
78
97
|
message.includes("EPERM") ||
|
|
79
|
-
message.includes("permission denied")
|
|
98
|
+
message.includes("permission denied") ||
|
|
99
|
+
message.includes("symlink"));
|
|
80
100
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ExitCode } from "../../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Start combined AgentDoctor MCP (Brain tools + intelligence tools) over STDIO.
|
|
4
|
+
*/
|
|
5
|
+
export declare function runMcpCommand(options: {
|
|
6
|
+
root: string;
|
|
7
|
+
buildIfMissing?: boolean;
|
|
8
|
+
}): Promise<ExitCode>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { EXIT_CODES } from "../../types/index.js";
|
|
2
|
+
import { resolveRepoRoot } from "../../utils/path.js";
|
|
3
|
+
import { runAgentDoctorMcpStdio } from "../../mcp/agentdoctor/server.js";
|
|
4
|
+
/**
|
|
5
|
+
* Start combined AgentDoctor MCP (Brain tools + intelligence tools) over STDIO.
|
|
6
|
+
*/
|
|
7
|
+
export async function runMcpCommand(options) {
|
|
8
|
+
const root = resolveRepoRoot(options.root);
|
|
9
|
+
await runAgentDoctorMcpStdio({
|
|
10
|
+
root,
|
|
11
|
+
buildIfMissing: options.buildIfMissing !== false,
|
|
12
|
+
});
|
|
13
|
+
return EXIT_CODES.SUCCESS;
|
|
14
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ExitCode } from "../../types/index.js";
|
|
2
|
+
export declare function runPlatformCommand(options: {
|
|
3
|
+
action: string;
|
|
4
|
+
root?: string;
|
|
5
|
+
json?: boolean;
|
|
6
|
+
query?: string;
|
|
7
|
+
symbol?: string;
|
|
8
|
+
left?: string;
|
|
9
|
+
right?: string;
|
|
10
|
+
command?: string;
|
|
11
|
+
path?: string;
|
|
12
|
+
actionType?: string;
|
|
13
|
+
sessionId?: string;
|
|
14
|
+
failClosed?: boolean;
|
|
15
|
+
coverage?: string;
|
|
16
|
+
since?: string;
|
|
17
|
+
}): Promise<ExitCode>;
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { EXIT_CODES } from "../../types/index.js";
|
|
3
|
+
import { resolveRepoRoot } from "../../utils/path.js";
|
|
4
|
+
import { analyzeRenameImpact, analyzeTestImpact, appendSessionEvent, buildProvenance, compareCommits, createSession, endSession, evaluateAgentAction, exportSessionMarkdown, formatTestImpactHuman, listSessions, loadSession, persistTestImpactReport, planContext, runPlatformScan, saveProvenance, EVALUATE_ONLY, } from "../../platform/index.js";
|
|
5
|
+
import { buildRepositoryGraph } from "../../platform/graph/build.js";
|
|
6
|
+
function printJson(value) {
|
|
7
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
8
|
+
}
|
|
9
|
+
export async function runPlatformCommand(options) {
|
|
10
|
+
const root = resolveRepoRoot(options.root ?? process.cwd());
|
|
11
|
+
try {
|
|
12
|
+
switch (options.action) {
|
|
13
|
+
case "scan": {
|
|
14
|
+
const result = await runPlatformScan(root);
|
|
15
|
+
if (options.json)
|
|
16
|
+
printJson({
|
|
17
|
+
findingCount: result.snapshot.findings.length,
|
|
18
|
+
nodeCount: result.snapshot.graph.nodes.length,
|
|
19
|
+
testImpact: result.snapshot.testImpact,
|
|
20
|
+
readiness: result.snapshot.readiness.categories.map((c) => ({
|
|
21
|
+
id: c.id,
|
|
22
|
+
score: c.score,
|
|
23
|
+
})),
|
|
24
|
+
reports: result.reportPaths,
|
|
25
|
+
limitations: result.snapshot.limitations,
|
|
26
|
+
});
|
|
27
|
+
else {
|
|
28
|
+
process.stdout.write(`AgentDoctor 2.0 platform scan\n findings: ${result.snapshot.findings.length}\n graph nodes: ${result.snapshot.graph.nodes.length}\n test-impact recommendations: ${result.testImpact.recommendedTests.length}\n reports: ${Object.keys(result.reportPaths).join(", ")}\n`);
|
|
29
|
+
}
|
|
30
|
+
return EXIT_CODES.SUCCESS;
|
|
31
|
+
}
|
|
32
|
+
case "graph": {
|
|
33
|
+
const graph = await buildRepositoryGraph(root);
|
|
34
|
+
if (options.json)
|
|
35
|
+
printJson(graph);
|
|
36
|
+
else
|
|
37
|
+
process.stdout.write(`Graph nodes=${graph.nodes.length} edges=${graph.edges.length}\n`);
|
|
38
|
+
return EXIT_CODES.SUCCESS;
|
|
39
|
+
}
|
|
40
|
+
case "test-impact": {
|
|
41
|
+
const report = await analyzeTestImpact({
|
|
42
|
+
root,
|
|
43
|
+
...(options.coverage ? { coveragePath: options.coverage } : {}),
|
|
44
|
+
...(options.since ? { since: options.since } : {}),
|
|
45
|
+
});
|
|
46
|
+
const out = await persistTestImpactReport(root, report);
|
|
47
|
+
if (options.json)
|
|
48
|
+
printJson({ ...report, reportPath: out });
|
|
49
|
+
else {
|
|
50
|
+
process.stdout.write(formatTestImpactHuman(report));
|
|
51
|
+
process.stdout.write(` wrote: ${out}\n`);
|
|
52
|
+
}
|
|
53
|
+
return EXIT_CODES.SUCCESS;
|
|
54
|
+
}
|
|
55
|
+
case "firewall-check":
|
|
56
|
+
case "policy-check": {
|
|
57
|
+
const verdict = await evaluateAgentAction(root, {
|
|
58
|
+
actionId: randomUUID(),
|
|
59
|
+
agentId: "cli",
|
|
60
|
+
timestamp: new Date().toISOString(),
|
|
61
|
+
type: options.actionType ?? "shell",
|
|
62
|
+
params: {
|
|
63
|
+
...(options.command ? { command: options.command } : {}),
|
|
64
|
+
...(options.path ? { path: options.path } : {}),
|
|
65
|
+
},
|
|
66
|
+
repositoryRoot: root,
|
|
67
|
+
}, { failClosed: options.failClosed === true });
|
|
68
|
+
if (options.json)
|
|
69
|
+
printJson({ ...verdict, notice: EVALUATE_ONLY });
|
|
70
|
+
else
|
|
71
|
+
process.stdout.write(`Action Policy Evaluator\n ${EVALUATE_ONLY}\n decision=${verdict.decision} risk=${verdict.riskLevel} reason=${verdict.reason} executed=${verdict.executionResult}\n`);
|
|
72
|
+
return EXIT_CODES.SUCCESS;
|
|
73
|
+
}
|
|
74
|
+
case "session-start": {
|
|
75
|
+
const session = await createSession({ root, agentId: "cli" });
|
|
76
|
+
process.stdout.write(`session ${session.id}\n`);
|
|
77
|
+
return EXIT_CODES.SUCCESS;
|
|
78
|
+
}
|
|
79
|
+
case "session-show": {
|
|
80
|
+
if (!options.sessionId) {
|
|
81
|
+
console.error("Error: --session <id> required");
|
|
82
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
83
|
+
}
|
|
84
|
+
const session = await loadSession(root, options.sessionId);
|
|
85
|
+
if (!session) {
|
|
86
|
+
console.error("Error: session not found");
|
|
87
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
88
|
+
}
|
|
89
|
+
if (options.json)
|
|
90
|
+
printJson(session);
|
|
91
|
+
else
|
|
92
|
+
process.stdout.write(exportSessionMarkdown(session));
|
|
93
|
+
return EXIT_CODES.SUCCESS;
|
|
94
|
+
}
|
|
95
|
+
case "session-list": {
|
|
96
|
+
const ids = await listSessions(root);
|
|
97
|
+
if (options.json)
|
|
98
|
+
printJson({ sessions: ids });
|
|
99
|
+
else
|
|
100
|
+
process.stdout.write(ids.length ? `${ids.join("\n")}\n` : "No sessions.\n");
|
|
101
|
+
return EXIT_CODES.SUCCESS;
|
|
102
|
+
}
|
|
103
|
+
case "provenance": {
|
|
104
|
+
if (!options.path) {
|
|
105
|
+
console.error("Error: --path <file> required");
|
|
106
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
107
|
+
}
|
|
108
|
+
const record = buildProvenance({ root, file: options.path });
|
|
109
|
+
const out = await saveProvenance(root, record);
|
|
110
|
+
if (options.json)
|
|
111
|
+
printJson(record);
|
|
112
|
+
else
|
|
113
|
+
process.stdout.write(`Wrote ${out}\n`);
|
|
114
|
+
return EXIT_CODES.SUCCESS;
|
|
115
|
+
}
|
|
116
|
+
case "context": {
|
|
117
|
+
const graph = await buildRepositoryGraph(root);
|
|
118
|
+
const plan = await planContext({
|
|
119
|
+
root,
|
|
120
|
+
graph,
|
|
121
|
+
query: options.query ?? "src",
|
|
122
|
+
});
|
|
123
|
+
if (options.json)
|
|
124
|
+
printJson(plan);
|
|
125
|
+
else
|
|
126
|
+
process.stdout.write(`tokens=${plan.estimatedTokens}/${plan.budgetTokens} selected=${plan.selected.length}\n`);
|
|
127
|
+
return EXIT_CODES.SUCCESS;
|
|
128
|
+
}
|
|
129
|
+
case "refactor": {
|
|
130
|
+
if (!options.symbol) {
|
|
131
|
+
console.error("Error: --symbol required");
|
|
132
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
133
|
+
}
|
|
134
|
+
const graph = await buildRepositoryGraph(root);
|
|
135
|
+
const impact = await analyzeRenameImpact({ root, symbol: options.symbol, graph });
|
|
136
|
+
if (options.json)
|
|
137
|
+
printJson(impact);
|
|
138
|
+
else
|
|
139
|
+
process.stdout.write(`symbol=${impact.symbol} affected=${impact.affectedFiles.length} risk=${impact.risk}\n`);
|
|
140
|
+
return EXIT_CODES.SUCCESS;
|
|
141
|
+
}
|
|
142
|
+
case "time-machine": {
|
|
143
|
+
if (!options.left || !options.right) {
|
|
144
|
+
console.error("Error: --left and --right refs required");
|
|
145
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
146
|
+
}
|
|
147
|
+
const cmp = await compareCommits({
|
|
148
|
+
root,
|
|
149
|
+
left: options.left,
|
|
150
|
+
right: options.right,
|
|
151
|
+
});
|
|
152
|
+
if (options.json)
|
|
153
|
+
printJson(cmp);
|
|
154
|
+
else
|
|
155
|
+
process.stdout.write(`${cmp.summary}\n`);
|
|
156
|
+
return EXIT_CODES.SUCCESS;
|
|
157
|
+
}
|
|
158
|
+
case "demo-session": {
|
|
159
|
+
const session = await createSession({ root, agentId: "demo-agent", model: "unknown" });
|
|
160
|
+
await appendSessionEvent(session, {
|
|
161
|
+
type: "tool-call",
|
|
162
|
+
summary: "Proposed shell: npm test",
|
|
163
|
+
detail: { command: "npm test" },
|
|
164
|
+
risk: "low",
|
|
165
|
+
});
|
|
166
|
+
const verdict = await evaluateAgentAction(root, {
|
|
167
|
+
actionId: randomUUID(),
|
|
168
|
+
agentId: "demo-agent",
|
|
169
|
+
timestamp: new Date().toISOString(),
|
|
170
|
+
type: "shell",
|
|
171
|
+
params: { command: "npm test" },
|
|
172
|
+
repositoryRoot: root,
|
|
173
|
+
});
|
|
174
|
+
await appendSessionEvent(session, {
|
|
175
|
+
type: "policy",
|
|
176
|
+
summary: `Action Policy Evaluator ${verdict.decision}: ${verdict.reason}`,
|
|
177
|
+
risk: verdict.riskLevel === "critical" ? "critical" : "low",
|
|
178
|
+
});
|
|
179
|
+
await endSession(session);
|
|
180
|
+
if (options.json)
|
|
181
|
+
printJson({ sessionId: session.id, verdict, notice: EVALUATE_ONLY });
|
|
182
|
+
else
|
|
183
|
+
process.stdout.write(`demo session ${session.id} (${EVALUATE_ONLY})\n`);
|
|
184
|
+
return EXIT_CODES.SUCCESS;
|
|
185
|
+
}
|
|
186
|
+
default:
|
|
187
|
+
console.error(`Error: unknown platform action: ${options.action}`);
|
|
188
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
193
|
+
return EXIT_CODES.INTERNAL_ERROR;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export declare function runGraphSurfaceCommand(options: {
|
|
2
|
+
action: "build" | "update" | "rebuild" | "status" | "show";
|
|
3
|
+
root: string;
|
|
4
|
+
mode?: string;
|
|
5
|
+
json?: boolean;
|
|
6
|
+
}): Promise<number>;
|
|
7
|
+
export declare function runPolicyCheckCommand(options: {
|
|
8
|
+
root: string;
|
|
9
|
+
command: string;
|
|
10
|
+
json?: boolean;
|
|
11
|
+
failClosed?: boolean;
|
|
12
|
+
}): Promise<number>;
|
|
13
|
+
export declare function runPolicyExplainCommand(options: {
|
|
14
|
+
root: string;
|
|
15
|
+
command: string;
|
|
16
|
+
json?: boolean;
|
|
17
|
+
failClosed?: boolean;
|
|
18
|
+
}): Promise<number>;
|
|
19
|
+
export declare function runPolicyEnforceCommand(options: {
|
|
20
|
+
root: string;
|
|
21
|
+
command: string;
|
|
22
|
+
execute?: boolean;
|
|
23
|
+
json?: boolean;
|
|
24
|
+
failClosed?: boolean;
|
|
25
|
+
}): Promise<number>;
|
|
26
|
+
export declare function runRunExplainCommand(options: {
|
|
27
|
+
root: string;
|
|
28
|
+
command: string;
|
|
29
|
+
json?: boolean;
|
|
30
|
+
failClosed?: boolean;
|
|
31
|
+
shell?: boolean;
|
|
32
|
+
}): Promise<number>;
|
|
33
|
+
export declare function runRunCommand(options: {
|
|
34
|
+
root: string;
|
|
35
|
+
argv: string[];
|
|
36
|
+
shell?: boolean;
|
|
37
|
+
timeoutMs?: number;
|
|
38
|
+
json?: boolean;
|
|
39
|
+
failClosed?: boolean;
|
|
40
|
+
}): Promise<number>;
|