@praneeth_54/agentdoctor 2.1.0 → 3.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 +86 -3
- package/README.md +490 -290
- package/dist/agent/chat/deterministic.d.ts +6 -0
- package/dist/agent/chat/deterministic.js +180 -0
- package/dist/agent/chat/service.js +8 -14
- package/dist/agent/context/retrieve.d.ts +2 -1
- package/dist/agent/context/retrieve.js +14 -1
- package/dist/agent/index.d.ts +2 -0
- package/dist/agent/index.js +1 -0
- package/dist/agent/loop.d.ts +2 -0
- package/dist/agent/loop.js +31 -0
- package/dist/agent/roles.d.ts +12 -0
- package/dist/agent/roles.js +138 -0
- package/dist/agent/runtime.d.ts +21 -5
- package/dist/agent/runtime.js +141 -28
- package/dist/agent/tools/execute.d.ts +2 -0
- package/dist/agent/tools/execute.js +49 -43
- package/dist/agent/tools/write.d.ts +1 -1
- package/dist/agent/tools/write.js +18 -4
- package/dist/ai/config.js +1 -0
- package/dist/ai/providers/adversarial-local.d.ts +7 -0
- package/dist/ai/providers/adversarial-local.js +146 -0
- package/dist/ai/redact.d.ts +1 -0
- package/dist/ai/redact.js +47 -7
- package/dist/ai/types.d.ts +1 -1
- package/dist/cli/commands/agent.d.ts +2 -0
- package/dist/cli/commands/agent.js +32 -11
- package/dist/cli/commands/architecture.js +7 -2
- package/dist/cli/commands/brain.js +7 -2
- package/dist/cli/commands/chat.js +15 -7
- package/dist/cli/commands/complete.js +13 -3
- package/dist/cli/commands/fix.js +6 -0
- package/dist/cli/commands/learn.js +7 -2
- package/dist/cli/commands/mcp.js +7 -3
- package/dist/cli/commands/platform.js +7 -2
- package/dist/cli/commands/policy-graph-run.js +7 -0
- package/dist/cli/commands/product.d.ts +19 -0
- package/dist/cli/commands/product.js +157 -0
- package/dist/cli/commands/scan.js +6 -0
- package/dist/cli/commands/start.d.ts +15 -0
- package/dist/cli/commands/start.js +86 -0
- package/dist/cli/commands/v2.js +61 -11
- package/dist/cli/commands/verify.js +6 -0
- package/dist/cli/program.js +141 -0
- package/dist/cli/safe-root.d.ts +17 -0
- package/dist/cli/safe-root.js +32 -0
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/core/brain-cli/service.js +5 -2
- package/dist/core/monorepo/detect.js +10 -0
- package/dist/core/secrets/scan.js +9 -0
- package/dist/core/understanding/brain/storage/store.d.ts +4 -0
- package/dist/core/understanding/brain/storage/store.js +22 -2
- package/dist/dashboard/page.d.ts +2 -0
- package/dist/dashboard/page.js +53 -0
- package/dist/dashboard/server.js +117 -140
- package/dist/dashboard/ui/client.d.ts +2 -0
- package/dist/dashboard/ui/client.js +2 -0
- package/dist/dashboard/ui/styles.d.ts +2 -0
- package/dist/dashboard/ui/styles.js +138 -0
- package/dist/discovery/files.js +13 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/dist/intelligence/graph/build.js +46 -38
- package/dist/intelligence/graph/incremental.d.ts +2 -0
- package/dist/intelligence/graph/incremental.js +9 -0
- package/dist/intelligence/resolve/imports.js +1 -1
- package/dist/languages/dart.d.ts +10 -0
- package/dist/languages/dart.js +99 -0
- package/dist/languages/go.d.ts +13 -7
- package/dist/languages/go.js +84 -24
- package/dist/languages/index.d.ts +5 -1
- package/dist/languages/index.js +13 -36
- package/dist/languages/java.d.ts +10 -0
- package/dist/languages/java.js +80 -0
- package/dist/languages/kotlin.d.ts +10 -0
- package/dist/languages/kotlin.js +85 -0
- package/dist/languages/rust.d.ts +10 -0
- package/dist/languages/rust.js +93 -0
- package/dist/languages/types.d.ts +4 -3
- package/dist/mcp/agent/registry.d.ts +1 -1
- package/dist/mcp/agent/registry.js +109 -23
- package/dist/mcp/intelligence/handlers.d.ts +3 -0
- package/dist/mcp/intelligence/handlers.js +28 -0
- package/dist/mcp/intelligence/path-safety.d.ts +6 -1
- package/dist/mcp/intelligence/path-safety.js +55 -2
- package/dist/mcp/intelligence/registry.d.ts +1 -1
- package/dist/mcp/intelligence/registry.js +30 -1
- package/dist/platform/graph/build.js +9 -0
- package/dist/product/api/doctor.d.ts +14 -0
- package/dist/product/api/doctor.js +185 -0
- package/dist/product/api/openapi.d.ts +7 -0
- package/dist/product/api/openapi.js +122 -0
- package/dist/product/approval/model.d.ts +30 -0
- package/dist/product/approval/model.js +64 -0
- package/dist/product/approval/session.d.ts +49 -0
- package/dist/product/approval/session.js +134 -0
- package/dist/product/database/doctor.d.ts +30 -0
- package/dist/product/database/doctor.js +184 -0
- package/dist/product/decisions/ledger.d.ts +36 -0
- package/dist/product/decisions/ledger.js +141 -0
- package/dist/product/deps/analyze.d.ts +46 -0
- package/dist/product/deps/analyze.js +137 -0
- package/dist/product/deps/lockfiles.d.ts +25 -0
- package/dist/product/deps/lockfiles.js +200 -0
- package/dist/product/discovery/roots.d.ts +52 -0
- package/dist/product/discovery/roots.js +231 -0
- package/dist/product/dna/build.d.ts +50 -0
- package/dist/product/dna/build.js +255 -0
- package/dist/product/eval/lab.d.ts +17 -0
- package/dist/product/eval/lab.js +218 -0
- package/dist/product/events/doctor.d.ts +21 -0
- package/dist/product/events/doctor.js +147 -0
- package/dist/product/evidence-scan.d.ts +12 -0
- package/dist/product/evidence-scan.js +46 -0
- package/dist/product/evolution/timeline.d.ts +29 -0
- package/dist/product/evolution/timeline.js +123 -0
- package/dist/product/features/intelligence.d.ts +23 -0
- package/dist/product/features/intelligence.js +158 -0
- package/dist/product/forensic/mode.d.ts +25 -0
- package/dist/product/forensic/mode.js +70 -0
- package/dist/product/graph/enrich-languages.d.ts +20 -0
- package/dist/product/graph/enrich-languages.js +168 -0
- package/dist/product/health/code-health.d.ts +20 -0
- package/dist/product/health/code-health.js +149 -0
- package/dist/product/index.d.ts +72 -0
- package/dist/product/index.js +36 -0
- package/dist/product/ledger/change-ledger.d.ts +23 -0
- package/dist/product/ledger/change-ledger.js +64 -0
- package/dist/product/map/software-map.d.ts +17 -0
- package/dist/product/map/software-map.js +96 -0
- package/dist/product/memory/institutional.d.ts +16 -0
- package/dist/product/memory/institutional.js +92 -0
- package/dist/product/ops/incident.d.ts +20 -0
- package/dist/product/ops/incident.js +61 -0
- package/dist/product/ops/infra.d.ts +15 -0
- package/dist/product/ops/infra.js +112 -0
- package/dist/product/org/model.d.ts +34 -0
- package/dist/product/org/model.js +195 -0
- package/dist/product/privacy/doctor.d.ts +13 -0
- package/dist/product/privacy/doctor.js +90 -0
- package/dist/product/requirements/trace.d.ts +21 -0
- package/dist/product/requirements/trace.js +166 -0
- package/dist/product/search/index.d.ts +29 -0
- package/dist/product/search/index.js +116 -0
- package/dist/product/search/software-search.d.ts +19 -0
- package/dist/product/search/software-search.js +105 -0
- package/dist/product/security/doctor.d.ts +23 -0
- package/dist/product/security/doctor.js +124 -0
- package/dist/product/self/diagnose.d.ts +15 -0
- package/dist/product/self/diagnose.js +82 -0
- package/dist/product/techdebt/roadmap.d.ts +20 -0
- package/dist/product/techdebt/roadmap.js +118 -0
- package/dist/product/testbrain/analyze.d.ts +29 -0
- package/dist/product/testbrain/analyze.js +129 -0
- package/dist/product/truth.d.ts +12 -0
- package/dist/product/truth.js +30 -0
- package/dist/product/twin/digital-twin.d.ts +23 -0
- package/dist/product/twin/digital-twin.js +52 -0
- package/dist/product/twin/store.d.ts +21 -0
- package/dist/product/twin/store.js +78 -0
- package/dist/product/whatif/engine.d.ts +28 -0
- package/dist/product/whatif/engine.js +91 -0
- package/dist/project/ownership.d.ts +65 -0
- package/dist/project/ownership.js +169 -0
- package/dist/utils/fs.js +10 -2
- package/package.json +1 -1
package/dist/ai/redact.js
CHANGED
|
@@ -1,18 +1,58 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Redaction for outbound model payloads.
|
|
3
3
|
* Extends the local-ai redaction patterns; never send raw secrets to providers.
|
|
4
|
+
* Patterns avoid nested unbounded quantifiers (ReDoS-safe).
|
|
4
5
|
*/
|
|
5
|
-
const
|
|
6
|
+
const REDACTED = "[REDACTED]";
|
|
7
|
+
const SIMPLE_SECRET_PATTERNS = [
|
|
6
8
|
/\b(AKIA[0-9A-Z]{16})\b/g,
|
|
7
9
|
/\b(ghp_[A-Za-z0-9]{36})\b/g,
|
|
8
|
-
/\b(sk-[A-Za-z0-9]{20,})\b/g,
|
|
9
|
-
|
|
10
|
-
/\b((?:export\s+)?(?:AWS_SECRET_ACCESS_KEY|GITHUB_TOKEN|NPM_TOKEN|OPENAI_API_KEY|ANTHROPIC_API_KEY|STRIPE_SECRET_KEY|AGENTDOCTOR_AI_API_KEY)\s*=\s*)(['"]?)[^\s'"]+\2/gi,
|
|
10
|
+
/\b(sk-[A-Za-z0-9]{20,80})\b/g,
|
|
11
|
+
/\b((?:export\s+)?(?:AWS_SECRET_ACCESS_KEY|GITHUB_TOKEN|NPM_TOKEN|OPENAI_API_KEY|ANTHROPIC_API_KEY|STRIPE_SECRET_KEY|AGENTDOCTOR_AI_API_KEY)\s*=\s*)(\S+)/gi,
|
|
11
12
|
];
|
|
13
|
+
/** Linear scan — avoids polynomial backtracking on PEM fences. */
|
|
14
|
+
function redactPrivateKeyBlocks(text) {
|
|
15
|
+
const beginToken = "-----BEGIN ";
|
|
16
|
+
const endToken = "-----END ";
|
|
17
|
+
const keySuffix = "PRIVATE KEY-----";
|
|
18
|
+
let out = "";
|
|
19
|
+
let i = 0;
|
|
20
|
+
while (i < text.length) {
|
|
21
|
+
const start = text.indexOf(beginToken, i);
|
|
22
|
+
if (start === -1) {
|
|
23
|
+
out += text.slice(i);
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
out += text.slice(i, start);
|
|
27
|
+
const afterBegin = start + beginToken.length;
|
|
28
|
+
const keyLabelEnd = text.indexOf(keySuffix, afterBegin);
|
|
29
|
+
if (keyLabelEnd === -1 || keyLabelEnd - afterBegin > 64) {
|
|
30
|
+
out += text.slice(start, afterBegin);
|
|
31
|
+
i = afterBegin;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const headerEnd = keyLabelEnd + keySuffix.length;
|
|
35
|
+
const endStart = text.indexOf(endToken, headerEnd);
|
|
36
|
+
if (endStart === -1) {
|
|
37
|
+
out += text.slice(start, headerEnd);
|
|
38
|
+
i = headerEnd;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
const endLabelEnd = text.indexOf(keySuffix, endStart + endToken.length);
|
|
42
|
+
if (endLabelEnd === -1 || endLabelEnd - (endStart + endToken.length) > 64) {
|
|
43
|
+
out += text.slice(start, headerEnd);
|
|
44
|
+
i = headerEnd;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
out += REDACTED;
|
|
48
|
+
i = endLabelEnd + keySuffix.length;
|
|
49
|
+
}
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
12
52
|
export function redactForModel(text) {
|
|
13
|
-
let out = text;
|
|
14
|
-
for (const re of
|
|
15
|
-
out = out.replace(re, "
|
|
53
|
+
let out = redactPrivateKeyBlocks(text);
|
|
54
|
+
for (const re of SIMPLE_SECRET_PATTERNS) {
|
|
55
|
+
out = out.replace(re, (_m, prefix) => typeof prefix === "string" && prefix.includes("=") ? `${prefix}${REDACTED}` : REDACTED);
|
|
16
56
|
}
|
|
17
57
|
return out;
|
|
18
58
|
}
|
package/dist/ai/types.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Provider-agnostic model types for AgentDoctor 2.1 Project AI Agent.
|
|
3
3
|
* The model reasons; AgentDoctor owns context, tools, and verification.
|
|
4
4
|
*/
|
|
5
|
-
export type AiProviderId = "none" | "mock" | "openai-compatible" | "ollama" | "anthropic" | "gemini";
|
|
5
|
+
export type AiProviderId = "none" | "deterministic" | "mock" | "openai-compatible" | "ollama" | "anthropic" | "gemini";
|
|
6
6
|
export type ChatRole = "system" | "user" | "assistant" | "tool";
|
|
7
7
|
export interface ChatMessage {
|
|
8
8
|
role: ChatRole;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type AgentRole } from "../../agent/roles.js";
|
|
1
2
|
import { type ExitCode } from "../../types/index.js";
|
|
2
3
|
/**
|
|
3
4
|
* agentdoctor plan — produce an implementation plan (no writes unless --apply elsewhere).
|
|
@@ -24,4 +25,5 @@ export declare function runAgentCommand(options: {
|
|
|
24
25
|
applyOpsJson?: string;
|
|
25
26
|
verify?: boolean;
|
|
26
27
|
runTests?: boolean;
|
|
28
|
+
role?: AgentRole;
|
|
27
29
|
}): Promise<ExitCode>;
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import { approvePlan, buildAgentPlan, formatAgentPlan } from "../../agent/plan.js";
|
|
2
2
|
import { evaluateApproval, formatApprovalPrompt } from "../../agent/approvals.js";
|
|
3
3
|
import { runCodingLoop } from "../../agent/loop.js";
|
|
4
|
+
import { runRoleAgent } from "../../agent/roles.js";
|
|
4
5
|
import { executeAgentTool, getToolSpec, listAgentToolSpecs, newToolCall, } from "../../agent/tools/index.js";
|
|
5
6
|
import { EXIT_CODES } from "../../types/index.js";
|
|
6
|
-
import {
|
|
7
|
+
import { resolveCliProjectRoot } from "../safe-root.js";
|
|
7
8
|
import { colors } from "../../utils/colors.js";
|
|
8
9
|
/**
|
|
9
10
|
* agentdoctor plan — produce an implementation plan (no writes unless --apply elsewhere).
|
|
10
11
|
*/
|
|
11
12
|
export async function runPlanCommand(options) {
|
|
12
|
-
const
|
|
13
|
+
const gated = await resolveCliProjectRoot(options.root ?? process.cwd());
|
|
14
|
+
if (!gated.ok) {
|
|
15
|
+
console.error(`Error: ${gated.message}`);
|
|
16
|
+
return gated.code;
|
|
17
|
+
}
|
|
18
|
+
const root = gated.root;
|
|
13
19
|
const plan = await buildAgentPlan({ root, goal: options.goal });
|
|
14
20
|
if (options.approve) {
|
|
15
21
|
const approved = approvePlan(plan, true);
|
|
@@ -34,7 +40,12 @@ export async function runPlanCommand(options) {
|
|
|
34
40
|
* agentdoctor agent — inspect, plan, and (with --approve) mutate via controlled tools.
|
|
35
41
|
*/
|
|
36
42
|
export async function runAgentCommand(options) {
|
|
37
|
-
const
|
|
43
|
+
const gated = await resolveCliProjectRoot(options.root ?? process.cwd());
|
|
44
|
+
if (!gated.ok) {
|
|
45
|
+
console.error(`Error: ${gated.message}`);
|
|
46
|
+
return gated.code;
|
|
47
|
+
}
|
|
48
|
+
const root = gated.root;
|
|
38
49
|
const approvedByHuman = options.approve === true;
|
|
39
50
|
if (options.listTools) {
|
|
40
51
|
const tools = listAgentToolSpecs({ includeWrite: true, includeExecute: true });
|
|
@@ -107,14 +118,24 @@ export async function runAgentCommand(options) {
|
|
|
107
118
|
return EXIT_CODES.USAGE_ERROR;
|
|
108
119
|
}
|
|
109
120
|
}
|
|
110
|
-
const result =
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
121
|
+
const result = options.role
|
|
122
|
+
? await runRoleAgent({
|
|
123
|
+
role: options.role,
|
|
124
|
+
root,
|
|
125
|
+
goal: options.goal,
|
|
126
|
+
approvedByHuman: true,
|
|
127
|
+
...(toolCalls ? { toolCalls } : {}),
|
|
128
|
+
verify: options.verify !== false,
|
|
129
|
+
runTests: options.runTests === true,
|
|
130
|
+
})
|
|
131
|
+
: await runCodingLoop({
|
|
132
|
+
root,
|
|
133
|
+
goal: options.goal,
|
|
134
|
+
approvedByHuman: true,
|
|
135
|
+
...(toolCalls ? { toolCalls } : {}),
|
|
136
|
+
verify: options.verify !== false,
|
|
137
|
+
runTests: options.runTests === true,
|
|
138
|
+
});
|
|
118
139
|
if (options.json) {
|
|
119
140
|
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
120
141
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EXIT_CODES } from "../../types/index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { resolveCliProjectRoot } from "../safe-root.js";
|
|
3
3
|
import { buildIntelligenceGraph } from "../../intelligence/graph/build.js";
|
|
4
4
|
import { buildC4Views } from "../../architecture/c4.js";
|
|
5
5
|
import { checkArchitectureAtRoot, explainArchitecture, initArchitecture, loadArchitectureContract, } from "../../architecture/contract.js";
|
|
@@ -7,7 +7,12 @@ function printJson(value) {
|
|
|
7
7
|
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
8
8
|
}
|
|
9
9
|
export async function runArchitectureCommand(options) {
|
|
10
|
-
const
|
|
10
|
+
const gated = await resolveCliProjectRoot(options.root ?? process.cwd());
|
|
11
|
+
if (!gated.ok) {
|
|
12
|
+
console.error(`Error: ${gated.message}`);
|
|
13
|
+
return gated.code;
|
|
14
|
+
}
|
|
15
|
+
const root = gated.root;
|
|
11
16
|
try {
|
|
12
17
|
switch (options.action) {
|
|
13
18
|
case "init": {
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import { EXIT_CODES } from "../../types/index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { resolveCliProjectRoot } from "../safe-root.js";
|
|
3
3
|
import { exportBrain, getBrainStatus, importBrain, initBrainStore, inspectBrainSummary, listBrainSnapshots, loadLatestBrain, rebuildBrain, searchBrain, showBrainSnapshot, } from "../../core/brain-cli/service.js";
|
|
4
4
|
import { listProposals, reviewProposal, writeBrainProductSnapshot, } from "../../core/brain-product/init.js";
|
|
5
5
|
function printJson(value) {
|
|
6
6
|
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
7
7
|
}
|
|
8
8
|
export async function runBrainCommand(options) {
|
|
9
|
-
const
|
|
9
|
+
const gated = await resolveCliProjectRoot(options.root);
|
|
10
|
+
if (!gated.ok) {
|
|
11
|
+
console.error(`Error: ${gated.message}`);
|
|
12
|
+
return gated.code;
|
|
13
|
+
}
|
|
14
|
+
const root = gated.root;
|
|
10
15
|
const json = options.json === true;
|
|
11
16
|
try {
|
|
12
17
|
switch (options.action) {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import readline from "node:readline/promises";
|
|
2
2
|
import { stdin as input, stdout as output } from "node:process";
|
|
3
|
-
import { ChatService,
|
|
3
|
+
import { ChatService, formatChatResponseForCli } from "../../agent/chat/index.js";
|
|
4
4
|
import { MockModelProvider, createModelProvider, loadAiConfig } from "../../ai/index.js";
|
|
5
5
|
import { EXIT_CODES } from "../../types/index.js";
|
|
6
|
-
import {
|
|
6
|
+
import { resolveCliProjectRoot } from "../safe-root.js";
|
|
7
7
|
import { colors } from "../../utils/colors.js";
|
|
8
8
|
function printBanner(options) {
|
|
9
9
|
const lines = [
|
|
@@ -51,7 +51,12 @@ function printHelp() {
|
|
|
51
51
|
].join("\n"));
|
|
52
52
|
}
|
|
53
53
|
export async function runAskCommand(options) {
|
|
54
|
-
const
|
|
54
|
+
const gated = await resolveCliProjectRoot(options.root ?? process.cwd());
|
|
55
|
+
if (!gated.ok) {
|
|
56
|
+
console.error(`Error: ${gated.message}`);
|
|
57
|
+
return gated.code;
|
|
58
|
+
}
|
|
59
|
+
const root = gated.root;
|
|
55
60
|
const provider = options.useMock ? new MockModelProvider() : createModelProvider(loadAiConfig());
|
|
56
61
|
const chat = new ChatService({
|
|
57
62
|
root,
|
|
@@ -78,7 +83,12 @@ export async function runAskCommand(options) {
|
|
|
78
83
|
}
|
|
79
84
|
}
|
|
80
85
|
export async function runChatCommand(options) {
|
|
81
|
-
const
|
|
86
|
+
const gated = await resolveCliProjectRoot(options.root ?? process.cwd());
|
|
87
|
+
if (!gated.ok) {
|
|
88
|
+
console.error(`Error: ${gated.message}`);
|
|
89
|
+
return gated.code;
|
|
90
|
+
}
|
|
91
|
+
const root = gated.root;
|
|
82
92
|
const provider = options.useMock ? new MockModelProvider() : createModelProvider(loadAiConfig());
|
|
83
93
|
const chat = new ChatService({
|
|
84
94
|
root,
|
|
@@ -94,9 +104,7 @@ export async function runChatCommand(options) {
|
|
|
94
104
|
frameworks: started.summary.frameworks,
|
|
95
105
|
});
|
|
96
106
|
if (provider.id === "none" && !options.useMock) {
|
|
97
|
-
process.stdout.write(
|
|
98
|
-
await chat.end();
|
|
99
|
-
return EXIT_CODES.USAGE_ERROR;
|
|
107
|
+
process.stdout.write("Deterministic project chat (no LLM). Architecture, auth, and dependency questions use local analyzers.\n\n");
|
|
100
108
|
}
|
|
101
109
|
const scripted = options.scriptedInputs ? [...options.scriptedInputs] : undefined;
|
|
102
110
|
const rl = scripted === undefined
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EXIT_CODES } from "../../types/index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { resolveCliProjectRoot } from "../safe-root.js";
|
|
3
3
|
import { runProjectInit } from "../../core/brain-product/init.js";
|
|
4
4
|
import { buildIntelligenceGraph } from "../../intelligence/graph/build.js";
|
|
5
5
|
import { analyzeGitIntelligence, deadCodeCategory } from "../../intelligence/git/analyze.js";
|
|
@@ -14,7 +14,12 @@ function printJson(value) {
|
|
|
14
14
|
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
15
15
|
}
|
|
16
16
|
export async function runInitCommand(options) {
|
|
17
|
-
const
|
|
17
|
+
const gated = await resolveCliProjectRoot(options.root ?? process.cwd());
|
|
18
|
+
if (!gated.ok) {
|
|
19
|
+
console.error(`Error: ${gated.message}`);
|
|
20
|
+
return gated.code;
|
|
21
|
+
}
|
|
22
|
+
const root = gated.root;
|
|
18
23
|
const result = await runProjectInit(root, {
|
|
19
24
|
...(options.name ? { projectName: options.name } : {}),
|
|
20
25
|
...(options.domain ? { businessDomain: options.domain } : {}),
|
|
@@ -27,7 +32,12 @@ export async function runInitCommand(options) {
|
|
|
27
32
|
return EXIT_CODES.SUCCESS;
|
|
28
33
|
}
|
|
29
34
|
export async function runV2SurfaceCommand(options) {
|
|
30
|
-
const
|
|
35
|
+
const gated = await resolveCliProjectRoot(options.root ?? process.cwd());
|
|
36
|
+
if (!gated.ok) {
|
|
37
|
+
console.error(`Error: ${gated.message}`);
|
|
38
|
+
return gated.code;
|
|
39
|
+
}
|
|
40
|
+
const root = gated.root;
|
|
31
41
|
try {
|
|
32
42
|
switch (options.action) {
|
|
33
43
|
case "graph-ast": {
|
package/dist/cli/commands/fix.js
CHANGED
|
@@ -6,6 +6,7 @@ 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";
|
|
8
8
|
import { scan } from "../../core/scanner/scan.js";
|
|
9
|
+
import { classifyBroadUserScanRoot } from "../../product/discovery/roots.js";
|
|
9
10
|
import { colors } from "../../utils/colors.js";
|
|
10
11
|
/**
|
|
11
12
|
* Safe Repository Mutation — apply allowlisted agent-config exclusions.
|
|
@@ -16,6 +17,11 @@ export async function runFixCommand(options) {
|
|
|
16
17
|
console.error(`Error: not a directory: ${target}`);
|
|
17
18
|
return EXIT_CODES.USAGE_ERROR;
|
|
18
19
|
}
|
|
20
|
+
const broad = classifyBroadUserScanRoot(target);
|
|
21
|
+
if (broad.blocked) {
|
|
22
|
+
console.error(`Error: ${broad.reason}`);
|
|
23
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
24
|
+
}
|
|
19
25
|
const dryRun = options.dryRun === true;
|
|
20
26
|
const yes = options.yes === true;
|
|
21
27
|
try {
|
|
@@ -2,9 +2,14 @@ import { MockModelProvider, createModelProvider, loadAiConfig } from "../../ai/i
|
|
|
2
2
|
import { StudentService } from "../../agent/student.js";
|
|
3
3
|
import { parseAgentMode, defaultStudentMode } from "../../agent/modes.js";
|
|
4
4
|
import { EXIT_CODES } from "../../types/index.js";
|
|
5
|
-
import {
|
|
5
|
+
import { resolveCliProjectRoot } from "../safe-root.js";
|
|
6
6
|
export async function runLearnCommand(options) {
|
|
7
|
-
const
|
|
7
|
+
const gated = await resolveCliProjectRoot(options.root ?? process.cwd());
|
|
8
|
+
if (!gated.ok) {
|
|
9
|
+
console.error(`Error: ${gated.message}`);
|
|
10
|
+
return gated.code;
|
|
11
|
+
}
|
|
12
|
+
const root = gated.root;
|
|
8
13
|
const mode = parseAgentMode(options.mode) ?? defaultStudentMode();
|
|
9
14
|
const provider = options.useMock ? new MockModelProvider() : createModelProvider(loadAiConfig());
|
|
10
15
|
const resolvedMode = options.build
|
package/dist/cli/commands/mcp.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { EXIT_CODES } from "../../types/index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { resolveCliProjectRoot } from "../safe-root.js";
|
|
3
3
|
import { runAgentDoctorMcpStdio } from "../../mcp/agentdoctor/server.js";
|
|
4
4
|
/**
|
|
5
5
|
* Start combined AgentDoctor MCP (Brain tools + intelligence tools) over STDIO.
|
|
6
6
|
*/
|
|
7
7
|
export async function runMcpCommand(options) {
|
|
8
|
-
const
|
|
8
|
+
const gated = await resolveCliProjectRoot(options.root);
|
|
9
|
+
if (!gated.ok) {
|
|
10
|
+
console.error(`Error: ${gated.message}`);
|
|
11
|
+
return gated.code;
|
|
12
|
+
}
|
|
9
13
|
await runAgentDoctorMcpStdio({
|
|
10
|
-
root,
|
|
14
|
+
root: gated.root,
|
|
11
15
|
buildIfMissing: options.buildIfMissing !== false,
|
|
12
16
|
});
|
|
13
17
|
return EXIT_CODES.SUCCESS;
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { EXIT_CODES } from "../../types/index.js";
|
|
3
|
-
import {
|
|
3
|
+
import { resolveCliProjectRoot } from "../safe-root.js";
|
|
4
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
5
|
import { buildRepositoryGraph } from "../../platform/graph/build.js";
|
|
6
6
|
function printJson(value) {
|
|
7
7
|
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
8
8
|
}
|
|
9
9
|
export async function runPlatformCommand(options) {
|
|
10
|
-
const
|
|
10
|
+
const gated = await resolveCliProjectRoot(options.root ?? process.cwd());
|
|
11
|
+
if (!gated.ok) {
|
|
12
|
+
console.error(`Error: ${gated.message}`);
|
|
13
|
+
return gated.code;
|
|
14
|
+
}
|
|
15
|
+
const root = gated.root;
|
|
11
16
|
try {
|
|
12
17
|
switch (options.action) {
|
|
13
18
|
case "scan": {
|
|
@@ -3,6 +3,7 @@ import { runControlledCommand } from "../../enforcement/runner.js";
|
|
|
3
3
|
import { graphBuild, graphRebuild, graphStatus, graphUpdate, } from "../../intelligence/graph/incremental.js";
|
|
4
4
|
import { buildIntelligenceGraph } from "../../intelligence/graph/build.js";
|
|
5
5
|
import { EXIT_CODES } from "../../types/index.js";
|
|
6
|
+
import { resolveCliProjectRoot } from "../safe-root.js";
|
|
6
7
|
function emit(json, value, human) {
|
|
7
8
|
if (json) {
|
|
8
9
|
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
@@ -13,6 +14,12 @@ function emit(json, value, human) {
|
|
|
13
14
|
}
|
|
14
15
|
export async function runGraphSurfaceCommand(options) {
|
|
15
16
|
try {
|
|
17
|
+
const gated = await resolveCliProjectRoot(options.root);
|
|
18
|
+
if (!gated.ok) {
|
|
19
|
+
console.error(`Error: ${gated.message}`);
|
|
20
|
+
return gated.code;
|
|
21
|
+
}
|
|
22
|
+
options = { ...options, root: gated.root };
|
|
16
23
|
const mode = options.mode ?? "auto";
|
|
17
24
|
if (options.action === "status") {
|
|
18
25
|
const status = await graphStatus({ root: options.root });
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type ExitCode } from "../../types/index.js";
|
|
2
|
+
import { type AgentRole } from "../../agent/roles.js";
|
|
3
|
+
export type ProductCommandAction = "requirements" | "api" | "database" | "events" | "dependency" | "health-code" | "map" | "what-if" | "decisions" | "forensic" | "twin" | "eval-lab" | "self-check" | "infra" | "incident" | "security-doctor" | "privacy-doctor" | "search" | "tech-debt" | "features" | "evolution" | "memory" | "org" | "role-agent" | "test-brain";
|
|
4
|
+
export declare function runProductCommand(options: {
|
|
5
|
+
action: ProductCommandAction;
|
|
6
|
+
root?: string;
|
|
7
|
+
json?: boolean;
|
|
8
|
+
target?: string;
|
|
9
|
+
changedFiles?: string[];
|
|
10
|
+
query?: string;
|
|
11
|
+
role?: AgentRole;
|
|
12
|
+
goal?: string;
|
|
13
|
+
approve?: boolean;
|
|
14
|
+
apply?: boolean;
|
|
15
|
+
}): Promise<ExitCode>;
|
|
16
|
+
export declare function runChangeLedgerListCommand(options: {
|
|
17
|
+
root?: string;
|
|
18
|
+
json?: boolean;
|
|
19
|
+
}): Promise<ExitCode>;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { EXIT_CODES } from "../../types/index.js";
|
|
2
|
+
import { resolveCliProjectRoot } from "../safe-root.js";
|
|
3
|
+
import { resolveTargetArgument } from "./scan.js";
|
|
4
|
+
import { traceRequirements, analyzeApiSurface, analyzeDatabaseSchema, analyzeEvents, analyzeDependencies, analyzeCodeHealth, buildSoftwareMap, analyzeWhatIf, loadDecisionLedger, runForensicAnalysis, buildSoftwareDigitalTwin, runEvalLab, diagnoseAgentDoctorSelf, analyzeInfra, buildIncidentHypotheses, readChangeLedger, analyzeSecuritySurface, analyzePrivacySurface, searchSymbolsAndConcepts, buildTechnicalDebtRoadmap, analyzeFeatureIntelligence, buildSoftwareEvolutionTimeline, queryMemory, loadOrganizationModel, analyzeTestBrain, } from "../../product/index.js";
|
|
5
|
+
import { runRoleAgent } from "../../agent/roles.js";
|
|
6
|
+
function printJson(value) {
|
|
7
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
8
|
+
}
|
|
9
|
+
export async function runProductCommand(options) {
|
|
10
|
+
const gated = await resolveCliProjectRoot(options.root ?? resolveTargetArgument(undefined));
|
|
11
|
+
if (!gated.ok) {
|
|
12
|
+
console.error(`Error: ${gated.message}`);
|
|
13
|
+
return gated.code;
|
|
14
|
+
}
|
|
15
|
+
const root = gated.root;
|
|
16
|
+
try {
|
|
17
|
+
let payload;
|
|
18
|
+
switch (options.action) {
|
|
19
|
+
case "requirements":
|
|
20
|
+
payload = await traceRequirements(root);
|
|
21
|
+
break;
|
|
22
|
+
case "api":
|
|
23
|
+
payload = await analyzeApiSurface(root);
|
|
24
|
+
break;
|
|
25
|
+
case "database":
|
|
26
|
+
payload = await analyzeDatabaseSchema(root);
|
|
27
|
+
break;
|
|
28
|
+
case "events":
|
|
29
|
+
payload = await analyzeEvents(root);
|
|
30
|
+
break;
|
|
31
|
+
case "dependency":
|
|
32
|
+
payload = await analyzeDependencies(root);
|
|
33
|
+
break;
|
|
34
|
+
case "health-code":
|
|
35
|
+
payload = await analyzeCodeHealth(root);
|
|
36
|
+
break;
|
|
37
|
+
case "map":
|
|
38
|
+
payload = await buildSoftwareMap(root);
|
|
39
|
+
break;
|
|
40
|
+
case "what-if":
|
|
41
|
+
if (!options.target) {
|
|
42
|
+
console.error("Error: what-if requires a file path or symbol target (--target or argument)");
|
|
43
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
44
|
+
}
|
|
45
|
+
payload = await analyzeWhatIf(root, options.target);
|
|
46
|
+
break;
|
|
47
|
+
case "decisions":
|
|
48
|
+
payload = await loadDecisionLedger(root);
|
|
49
|
+
break;
|
|
50
|
+
case "forensic":
|
|
51
|
+
payload = await runForensicAnalysis(root);
|
|
52
|
+
break;
|
|
53
|
+
case "twin":
|
|
54
|
+
payload = await buildSoftwareDigitalTwin(root);
|
|
55
|
+
break;
|
|
56
|
+
case "eval-lab":
|
|
57
|
+
payload = await runEvalLab(root);
|
|
58
|
+
break;
|
|
59
|
+
case "self-check":
|
|
60
|
+
payload = await diagnoseAgentDoctorSelf(root);
|
|
61
|
+
break;
|
|
62
|
+
case "infra":
|
|
63
|
+
payload = await analyzeInfra(root);
|
|
64
|
+
break;
|
|
65
|
+
case "incident":
|
|
66
|
+
payload = await buildIncidentHypotheses(root, options.changedFiles ? { changedFiles: options.changedFiles } : undefined);
|
|
67
|
+
break;
|
|
68
|
+
case "security-doctor":
|
|
69
|
+
payload = await analyzeSecuritySurface(root);
|
|
70
|
+
break;
|
|
71
|
+
case "privacy-doctor":
|
|
72
|
+
payload = await analyzePrivacySurface(root);
|
|
73
|
+
break;
|
|
74
|
+
case "search":
|
|
75
|
+
if (!options.query?.trim()) {
|
|
76
|
+
console.error("Error: search requires a query (--query or argument)");
|
|
77
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
78
|
+
}
|
|
79
|
+
payload = await searchSymbolsAndConcepts(root, options.query);
|
|
80
|
+
break;
|
|
81
|
+
case "tech-debt":
|
|
82
|
+
payload = await buildTechnicalDebtRoadmap(root);
|
|
83
|
+
break;
|
|
84
|
+
case "features":
|
|
85
|
+
payload = await analyzeFeatureIntelligence(root);
|
|
86
|
+
break;
|
|
87
|
+
case "evolution":
|
|
88
|
+
payload = await buildSoftwareEvolutionTimeline(root);
|
|
89
|
+
break;
|
|
90
|
+
case "memory":
|
|
91
|
+
if (!options.query?.trim()) {
|
|
92
|
+
console.error("Error: memory requires a query (--query or argument)");
|
|
93
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
94
|
+
}
|
|
95
|
+
payload = await queryMemory(root, options.query);
|
|
96
|
+
break;
|
|
97
|
+
case "org":
|
|
98
|
+
payload = await loadOrganizationModel(root);
|
|
99
|
+
break;
|
|
100
|
+
case "test-brain":
|
|
101
|
+
payload = await analyzeTestBrain({ root });
|
|
102
|
+
break;
|
|
103
|
+
case "role-agent":
|
|
104
|
+
if (!options.role || !options.goal?.trim()) {
|
|
105
|
+
console.error("Error: role-agent requires --role and --goal");
|
|
106
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
107
|
+
}
|
|
108
|
+
if (options.apply && !options.approve) {
|
|
109
|
+
console.error("Error: role-agent --apply requires --approve");
|
|
110
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
111
|
+
}
|
|
112
|
+
payload = await runRoleAgent({
|
|
113
|
+
role: options.role,
|
|
114
|
+
goal: options.goal,
|
|
115
|
+
root,
|
|
116
|
+
approvedByHuman: options.approve === true,
|
|
117
|
+
});
|
|
118
|
+
break;
|
|
119
|
+
default:
|
|
120
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
121
|
+
}
|
|
122
|
+
if (options.json) {
|
|
123
|
+
printJson(payload);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
const action = options.action;
|
|
127
|
+
process.stdout.write(`AgentDoctor ${action} completed for ${root}\n`);
|
|
128
|
+
if (action === "self-check" && payload && typeof payload === "object" && "ok" in payload) {
|
|
129
|
+
process.stdout.write(` ok: ${payload.ok}\n`);
|
|
130
|
+
}
|
|
131
|
+
if (action === "eval-lab" && payload && typeof payload === "object" && "passed" in payload) {
|
|
132
|
+
process.stdout.write(` passed: ${payload.passed}\n`);
|
|
133
|
+
}
|
|
134
|
+
process.stdout.write(" (use --json for full report)\n");
|
|
135
|
+
}
|
|
136
|
+
return EXIT_CODES.SUCCESS;
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
140
|
+
console.error(`Error: ${message}`);
|
|
141
|
+
return EXIT_CODES.INTERNAL_ERROR;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
export async function runChangeLedgerListCommand(options) {
|
|
145
|
+
const gated = await resolveCliProjectRoot(options.root);
|
|
146
|
+
if (!gated.ok) {
|
|
147
|
+
console.error(`Error: ${gated.message}`);
|
|
148
|
+
return gated.code;
|
|
149
|
+
}
|
|
150
|
+
const root = gated.root;
|
|
151
|
+
const payload = await readChangeLedger(root);
|
|
152
|
+
if (options.json)
|
|
153
|
+
printJson(payload);
|
|
154
|
+
else
|
|
155
|
+
process.stdout.write(`Change ledger entries: ${payload.entries.length}\n`);
|
|
156
|
+
return EXIT_CODES.SUCCESS;
|
|
157
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { evaluateScanPolicy } from "../../core/policy/evaluate.js";
|
|
3
3
|
import { scan } from "../../core/scanner/scan.js";
|
|
4
|
+
import { classifyBroadUserScanRoot } from "../../product/discovery/roots.js";
|
|
4
5
|
import { emitGithubReports } from "../../reporters/github/emit.js";
|
|
5
6
|
import { renderJsonReport } from "../../reporters/json/report.js";
|
|
6
7
|
import { renderTerminalReport } from "../../reporters/terminal/report.js";
|
|
@@ -13,6 +14,11 @@ export async function runScanCommand(options) {
|
|
|
13
14
|
console.error(`Error: not a directory: ${target}`);
|
|
14
15
|
return EXIT_CODES.USAGE_ERROR;
|
|
15
16
|
}
|
|
17
|
+
const broad = classifyBroadUserScanRoot(target);
|
|
18
|
+
if (broad.blocked) {
|
|
19
|
+
console.error(`Error: ${broad.reason}`);
|
|
20
|
+
return EXIT_CODES.USAGE_ERROR;
|
|
21
|
+
}
|
|
16
22
|
try {
|
|
17
23
|
const result = await scan({
|
|
18
24
|
cwd: target,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ExitCode } from "../../types/index.js";
|
|
2
|
+
export declare function runStartCommand(options: {
|
|
3
|
+
root?: string;
|
|
4
|
+
json?: boolean;
|
|
5
|
+
select?: string;
|
|
6
|
+
maxEntries?: number;
|
|
7
|
+
initBrain?: boolean;
|
|
8
|
+
rebuildBrain?: boolean;
|
|
9
|
+
listOnly?: boolean;
|
|
10
|
+
}): Promise<ExitCode>;
|
|
11
|
+
export declare function runDnaCommand(options: {
|
|
12
|
+
root?: string;
|
|
13
|
+
json?: boolean;
|
|
14
|
+
persist?: boolean;
|
|
15
|
+
}): Promise<ExitCode>;
|