@praneeth_54/agentdoctor 0.3.0-beta → 1.1.0
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 +105 -1
- package/README.md +64 -31
- package/dist/agents/inspect.js +58 -51
- package/dist/cli/commands/brain-mcp.d.ts +9 -0
- package/dist/cli/commands/brain-mcp.js +38 -0
- package/dist/cli/commands/explain.js +1 -1
- package/dist/cli/commands/fix.js +22 -6
- package/dist/cli/commands/scan.d.ts +5 -0
- package/dist/cli/commands/scan.js +25 -6
- package/dist/cli/commands/verify.d.ts +6 -0
- package/dist/cli/commands/verify.js +25 -11
- package/dist/cli/program.js +61 -7
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/core/fix/apply.d.ts +5 -1
- package/dist/core/fix/apply.js +34 -14
- package/dist/core/fix/plan.d.ts +1 -1
- package/dist/core/fix/plan.js +110 -3
- package/dist/core/fix/render.d.ts +2 -0
- package/dist/core/fix/render.js +57 -9
- package/dist/core/fix/run.js +5 -1
- package/dist/core/fix/types.d.ts +1 -1
- package/dist/core/fix/types.js +5 -1
- package/dist/core/fix/writers/claude-settings.d.ts +16 -0
- package/dist/core/fix/writers/claude-settings.js +100 -0
- package/dist/core/fix/writers/codex-config.d.ts +22 -0
- package/dist/core/fix/writers/codex-config.js +183 -0
- package/dist/core/fix/writers/cursorignore.js +2 -8
- package/dist/core/path-resolution/index.d.ts +5 -0
- package/dist/core/path-resolution/index.js +5 -0
- package/dist/core/path-resolution/prepare.d.ts +33 -0
- package/dist/core/path-resolution/prepare.js +98 -0
- package/dist/core/policy/evaluate.d.ts +44 -0
- package/dist/core/policy/evaluate.js +120 -0
- package/dist/core/rules/claude-deny.d.ts +8 -0
- package/dist/core/rules/claude-deny.js +39 -0
- package/dist/core/rules/codex-deny.d.ts +5 -0
- package/dist/core/rules/codex-deny.js +42 -0
- package/dist/core/rules/context/generated-directory.js +43 -9
- package/dist/core/rules/context/large-log-file.js +27 -10
- package/dist/core/rules/ignore.js +2 -5
- package/dist/core/rules/instructions/missing-path-reference.d.ts +5 -1
- package/dist/core/rules/instructions/missing-path-reference.js +24 -6
- package/dist/core/rules/path-kind.d.ts +15 -2
- package/dist/core/rules/path-kind.js +113 -10
- package/dist/core/rules/security/env-file-exposure.js +9 -24
- package/dist/core/rules/text-cache.js +46 -40
- package/dist/core/understanding/architecture/index.d.ts +4 -0
- package/dist/core/understanding/architecture/index.js +3 -0
- package/dist/core/understanding/architecture/infer.d.ts +6 -0
- package/dist/core/understanding/architecture/infer.js +39 -0
- package/dist/core/understanding/architecture/models.d.ts +23 -0
- package/dist/core/understanding/architecture/models.js +127 -0
- package/dist/core/understanding/architecture/patterns/distribution.d.ts +2 -0
- package/dist/core/understanding/architecture/patterns/distribution.js +115 -0
- package/dist/core/understanding/architecture/patterns/index.d.ts +2 -0
- package/dist/core/understanding/architecture/patterns/index.js +8 -0
- package/dist/core/understanding/architecture/patterns/layered.d.ts +2 -0
- package/dist/core/understanding/architecture/patterns/layered.js +279 -0
- package/dist/core/understanding/architecture/patterns/structural.d.ts +2 -0
- package/dist/core/understanding/architecture/patterns/structural.js +197 -0
- package/dist/core/understanding/architecture/rules.d.ts +4 -0
- package/dist/core/understanding/architecture/rules.js +6 -0
- package/dist/core/understanding/architecture/types.d.ts +52 -0
- package/dist/core/understanding/architecture/types.js +1 -0
- package/dist/core/understanding/brain/build.d.ts +13 -0
- package/dist/core/understanding/brain/build.js +158 -0
- package/dist/core/understanding/brain/claims/index.d.ts +3 -0
- package/dist/core/understanding/brain/claims/index.js +2 -0
- package/dist/core/understanding/brain/claims/lifecycle.d.ts +16 -0
- package/dist/core/understanding/brain/claims/lifecycle.js +78 -0
- package/dist/core/understanding/brain/claims/types.d.ts +32 -0
- package/dist/core/understanding/brain/claims/types.js +25 -0
- package/dist/core/understanding/brain/components/index.d.ts +17 -0
- package/dist/core/understanding/brain/components/index.js +97 -0
- package/dist/core/understanding/brain/components/types.d.ts +16 -0
- package/dist/core/understanding/brain/components/types.js +8 -0
- package/dist/core/understanding/brain/confidence.d.ts +19 -0
- package/dist/core/understanding/brain/confidence.js +39 -0
- package/dist/core/understanding/brain/contract.d.ts +17 -0
- package/dist/core/understanding/brain/contract.js +100 -0
- package/dist/core/understanding/brain/contradictions/index.d.ts +12 -0
- package/dist/core/understanding/brain/contradictions/index.js +57 -0
- package/dist/core/understanding/brain/contradictions/types.d.ts +12 -0
- package/dist/core/understanding/brain/contradictions/types.js +8 -0
- package/dist/core/understanding/brain/delta.d.ts +25 -0
- package/dist/core/understanding/brain/delta.js +116 -0
- package/dist/core/understanding/brain/evidence/index.d.ts +3 -0
- package/dist/core/understanding/brain/evidence/index.js +2 -0
- package/dist/core/understanding/brain/evidence/redact.d.ts +4 -0
- package/dist/core/understanding/brain/evidence/redact.js +36 -0
- package/dist/core/understanding/brain/evidence/types.d.ts +34 -0
- package/dist/core/understanding/brain/evidence/types.js +35 -0
- package/dist/core/understanding/brain/explain.d.ts +17 -0
- package/dist/core/understanding/brain/explain.js +33 -0
- package/dist/core/understanding/brain/index.d.ts +28 -0
- package/dist/core/understanding/brain/index.js +16 -0
- package/dist/core/understanding/brain/migrate.d.ts +21 -0
- package/dist/core/understanding/brain/migrate.js +47 -0
- package/dist/core/understanding/brain/query.d.ts +60 -0
- package/dist/core/understanding/brain/query.js +92 -0
- package/dist/core/understanding/brain/security.d.ts +3 -0
- package/dist/core/understanding/brain/security.js +43 -0
- package/dist/core/understanding/brain/storage/index.d.ts +2 -0
- package/dist/core/understanding/brain/storage/index.js +1 -0
- package/dist/core/understanding/brain/storage/store.d.ts +53 -0
- package/dist/core/understanding/brain/storage/store.js +305 -0
- package/dist/core/understanding/brain/trace.d.ts +24 -0
- package/dist/core/understanding/brain/trace.js +207 -0
- package/dist/core/understanding/brain/types.d.ts +32 -0
- package/dist/core/understanding/brain/types.js +8 -0
- package/dist/core/understanding/brain/version.d.ts +13 -0
- package/dist/core/understanding/brain/version.js +7 -0
- package/dist/core/understanding/delta/compare.d.ts +26 -0
- package/dist/core/understanding/delta/compare.js +74 -0
- package/dist/core/understanding/delta/index.d.ts +2 -0
- package/dist/core/understanding/delta/index.js +1 -0
- package/dist/core/understanding/dependencies/discover.d.ts +7 -0
- package/dist/core/understanding/dependencies/discover.js +550 -0
- package/dist/core/understanding/dependencies/extract.d.ts +10 -0
- package/dist/core/understanding/dependencies/extract.js +189 -0
- package/dist/core/understanding/dependencies/index.d.ts +4 -0
- package/dist/core/understanding/dependencies/index.js +3 -0
- package/dist/core/understanding/dependencies/models.d.ts +12 -0
- package/dist/core/understanding/dependencies/models.js +125 -0
- package/dist/core/understanding/dependencies/types.d.ts +27 -0
- package/dist/core/understanding/dependencies/types.js +1 -0
- package/dist/core/understanding/domain/discover.d.ts +14 -0
- package/dist/core/understanding/domain/discover.js +90 -0
- package/dist/core/understanding/domain/index.d.ts +2 -0
- package/dist/core/understanding/domain/index.js +1 -0
- package/dist/core/understanding/entrypoints/discover.d.ts +6 -0
- package/dist/core/understanding/entrypoints/discover.js +62 -0
- package/dist/core/understanding/entrypoints/extract.d.ts +19 -0
- package/dist/core/understanding/entrypoints/extract.js +43 -0
- package/dist/core/understanding/entrypoints/index.d.ts +4 -0
- package/dist/core/understanding/entrypoints/index.js +3 -0
- package/dist/core/understanding/entrypoints/models.d.ts +26 -0
- package/dist/core/understanding/entrypoints/models.js +216 -0
- package/dist/core/understanding/entrypoints/types.d.ts +20 -0
- package/dist/core/understanding/entrypoints/types.js +1 -0
- package/dist/core/understanding/index.d.ts +32 -0
- package/dist/core/understanding/index.js +18 -0
- package/dist/core/understanding/mind/build.d.ts +16 -0
- package/dist/core/understanding/mind/build.js +134 -0
- package/dist/core/understanding/mind/index.d.ts +6 -0
- package/dist/core/understanding/mind/index.js +3 -0
- package/dist/core/understanding/mind/query.d.ts +33 -0
- package/dist/core/understanding/mind/query.js +39 -0
- package/dist/core/understanding/mind/types.d.ts +24 -0
- package/dist/core/understanding/mind/types.js +7 -0
- package/dist/core/understanding/model/builder.d.ts +9 -0
- package/dist/core/understanding/model/builder.js +209 -0
- package/dist/core/understanding/model/ids.d.ts +7 -0
- package/dist/core/understanding/model/ids.js +48 -0
- package/dist/core/understanding/model/index.d.ts +7 -0
- package/dist/core/understanding/model/index.js +6 -0
- package/dist/core/understanding/model/schema.d.ts +12 -0
- package/dist/core/understanding/model/schema.js +33 -0
- package/dist/core/understanding/model/serializer.d.ts +9 -0
- package/dist/core/understanding/model/serializer.js +46 -0
- package/dist/core/understanding/model/types.d.ts +110 -0
- package/dist/core/understanding/model/types.js +1 -0
- package/dist/core/understanding/model/validator.d.ts +5 -0
- package/dist/core/understanding/model/validator.js +126 -0
- package/dist/core/understanding/model/version.d.ts +9 -0
- package/dist/core/understanding/model/version.js +7 -0
- package/dist/core/understanding/ownership/discover.d.ts +12 -0
- package/dist/core/understanding/ownership/discover.js +242 -0
- package/dist/core/understanding/ownership/index.d.ts +2 -0
- package/dist/core/understanding/ownership/index.js +1 -0
- package/dist/core/understanding/ownership/types.d.ts +23 -0
- package/dist/core/understanding/ownership/types.js +1 -0
- package/dist/core/understanding/query/engine.d.ts +24 -0
- package/dist/core/understanding/query/engine.js +35 -0
- package/dist/core/understanding/query/errors.d.ts +13 -0
- package/dist/core/understanding/query/errors.js +26 -0
- package/dist/core/understanding/query/executor.d.ts +8 -0
- package/dist/core/understanding/query/executor.js +34 -0
- package/dist/core/understanding/query/index.d.ts +7 -0
- package/dist/core/understanding/query/index.js +5 -0
- package/dist/core/understanding/query/models.d.ts +102 -0
- package/dist/core/understanding/query/models.js +1 -0
- package/dist/core/understanding/query/query.d.ts +68 -0
- package/dist/core/understanding/query/query.js +145 -0
- package/dist/core/understanding/query/registry.d.ts +8 -0
- package/dist/core/understanding/query/registry.js +340 -0
- package/dist/core/understanding/query/types.d.ts +63 -0
- package/dist/core/understanding/query/types.js +1 -0
- package/dist/core/understanding/relationships/discover.d.ts +11 -0
- package/dist/core/understanding/relationships/discover.js +517 -0
- package/dist/core/understanding/relationships/extract.d.ts +14 -0
- package/dist/core/understanding/relationships/extract.js +165 -0
- package/dist/core/understanding/relationships/index.d.ts +4 -0
- package/dist/core/understanding/relationships/index.js +3 -0
- package/dist/core/understanding/relationships/models.d.ts +21 -0
- package/dist/core/understanding/relationships/models.js +185 -0
- package/dist/core/understanding/relationships/types.d.ts +42 -0
- package/dist/core/understanding/relationships/types.js +1 -0
- package/dist/core/understanding/risks/discover.d.ts +8 -0
- package/dist/core/understanding/risks/discover.js +155 -0
- package/dist/core/understanding/risks/index.d.ts +2 -0
- package/dist/core/understanding/risks/index.js +1 -0
- package/dist/core/understanding/risks/types.d.ts +26 -0
- package/dist/core/understanding/risks/types.js +1 -0
- package/dist/core/understanding/shared/domain-lexicon.d.ts +9 -0
- package/dist/core/understanding/shared/domain-lexicon.js +107 -0
- package/dist/core/understanding/shared/index.d.ts +2 -0
- package/dist/core/understanding/shared/index.js +2 -0
- package/dist/core/understanding/shared/tokens.d.ts +7 -0
- package/dist/core/understanding/shared/tokens.js +141 -0
- package/dist/core/understanding/snapshot/identity.d.ts +24 -0
- package/dist/core/understanding/snapshot/identity.js +79 -0
- package/dist/core/understanding/snapshot/index.d.ts +2 -0
- package/dist/core/understanding/snapshot/index.js +1 -0
- package/dist/core/understanding/types/index.d.ts +22 -0
- package/dist/core/understanding/types/index.js +1 -0
- package/dist/core/understanding/understand/formatter.d.ts +10 -0
- package/dist/core/understanding/understand/formatter.js +115 -0
- package/dist/core/understanding/understand/index.d.ts +4 -0
- package/dist/core/understanding/understand/index.js +3 -0
- package/dist/core/understanding/understand/service.d.ts +17 -0
- package/dist/core/understanding/understand/service.js +76 -0
- package/dist/core/understanding/understand/summary.d.ts +14 -0
- package/dist/core/understanding/understand/summary.js +39 -0
- package/dist/core/understanding/understand/types.d.ts +31 -0
- package/dist/core/understanding/understand/types.js +1 -0
- package/dist/discovery/files.js +7 -2
- package/dist/discovery/log-like.d.ts +2 -0
- package/dist/discovery/log-like.js +7 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/mcp/brain/compile.d.ts +9 -0
- package/dist/mcp/brain/compile.js +42 -0
- package/dist/mcp/brain/errors.d.ts +12 -0
- package/dist/mcp/brain/errors.js +23 -0
- package/dist/mcp/brain/index.d.ts +11 -0
- package/dist/mcp/brain/index.js +8 -0
- package/dist/mcp/brain/provenance.d.ts +29 -0
- package/dist/mcp/brain/provenance.js +59 -0
- package/dist/mcp/brain/schemas.d.ts +13 -0
- package/dist/mcp/brain/schemas.js +105 -0
- package/dist/mcp/brain/security/root.d.ts +6 -0
- package/dist/mcp/brain/security/root.js +66 -0
- package/dist/mcp/brain/server.d.ts +12 -0
- package/dist/mcp/brain/server.js +46 -0
- package/dist/mcp/brain/session.d.ts +33 -0
- package/dist/mcp/brain/session.js +117 -0
- package/dist/mcp/brain/tools/handlers.d.ts +13 -0
- package/dist/mcp/brain/tools/handlers.js +483 -0
- package/dist/mcp/brain/tools/registry.d.ts +9 -0
- package/dist/mcp/brain/tools/registry.js +191 -0
- package/dist/reporters/github/annotations.d.ts +8 -0
- package/dist/reporters/github/annotations.js +42 -0
- package/dist/reporters/github/emit.d.ts +23 -0
- package/dist/reporters/github/emit.js +31 -0
- package/dist/reporters/github/summary.d.ts +20 -0
- package/dist/reporters/github/summary.js +111 -0
- package/dist/reporters/terminal/report.d.ts +5 -0
- package/dist/reporters/terminal/report.js +68 -5
- package/dist/reporters/verify/terminal.d.ts +4 -0
- package/dist/reporters/verify/terminal.js +26 -0
- package/dist/utils/fs.d.ts +5 -0
- package/dist/utils/fs.js +34 -0
- package/dist/utils/path.d.ts +5 -0
- package/dist/utils/path.js +16 -0
- package/package.json +15 -1
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { inferArchitectures } from "../../core/understanding/architecture/index.js";
|
|
3
|
+
import { buildProjectBrain } from "../../core/understanding/brain/index.js";
|
|
4
|
+
import { discoverDependencies } from "../../core/understanding/dependencies/index.js";
|
|
5
|
+
import { discoverDomains } from "../../core/understanding/domain/index.js";
|
|
6
|
+
import { discoverEntrypoints } from "../../core/understanding/entrypoints/index.js";
|
|
7
|
+
import { buildProjectModel } from "../../core/understanding/model/index.js";
|
|
8
|
+
import { discoverRelationships } from "../../core/understanding/relationships/index.js";
|
|
9
|
+
/**
|
|
10
|
+
* Compile discovery passes → ProjectModel → ProjectBrain for an explicit root.
|
|
11
|
+
*/
|
|
12
|
+
export async function compileProjectBrain(projectRoot, options = {}) {
|
|
13
|
+
const domains = await discoverDomains({ cwd: projectRoot });
|
|
14
|
+
const entrypoints = await discoverEntrypoints({ cwd: projectRoot });
|
|
15
|
+
const dependencies = await discoverDependencies({ cwd: projectRoot });
|
|
16
|
+
const relationships = await discoverRelationships({
|
|
17
|
+
cwd: projectRoot,
|
|
18
|
+
domains,
|
|
19
|
+
entrypoints,
|
|
20
|
+
dependencies,
|
|
21
|
+
});
|
|
22
|
+
const architectures = inferArchitectures({
|
|
23
|
+
domains,
|
|
24
|
+
entrypoints,
|
|
25
|
+
dependencies,
|
|
26
|
+
relationships,
|
|
27
|
+
});
|
|
28
|
+
const model = buildProjectModel({
|
|
29
|
+
domains,
|
|
30
|
+
entrypoints,
|
|
31
|
+
dependencies,
|
|
32
|
+
relationships,
|
|
33
|
+
architectures,
|
|
34
|
+
projectName: path.basename(projectRoot),
|
|
35
|
+
...(options.generatedAt !== undefined ? { generatedAt: options.generatedAt } : {}),
|
|
36
|
+
});
|
|
37
|
+
return buildProjectBrain(model, {
|
|
38
|
+
cwd: projectRoot,
|
|
39
|
+
...(options.previousClaims !== undefined ? { previousClaims: options.previousClaims } : {}),
|
|
40
|
+
...(options.generatedAt !== undefined ? { generatedAt: options.generatedAt } : {}),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type BrainMcpErrorCode = "invalid_root" | "path_escape" | "brain_not_found" | "brain_corrupt" | "unsupported_query" | "invalid_argument" | "not_found" | "read_only" | "internal";
|
|
2
|
+
export declare class BrainMcpError extends Error {
|
|
3
|
+
readonly code: BrainMcpErrorCode;
|
|
4
|
+
constructor(code: BrainMcpErrorCode, message: string);
|
|
5
|
+
}
|
|
6
|
+
export declare function toToolErrorPayload(error: unknown): {
|
|
7
|
+
ok: false;
|
|
8
|
+
error: {
|
|
9
|
+
code: BrainMcpErrorCode | "unknown";
|
|
10
|
+
message: string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export class BrainMcpError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
constructor(code, message) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = "BrainMcpError";
|
|
6
|
+
this.code = code;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export function toToolErrorPayload(error) {
|
|
10
|
+
if (error instanceof BrainMcpError) {
|
|
11
|
+
return { ok: false, error: { code: error.code, message: error.message } };
|
|
12
|
+
}
|
|
13
|
+
if (error instanceof Error) {
|
|
14
|
+
const message = error.message;
|
|
15
|
+
if (/checksum|corrupt|incompatible|contract|schema/i.test(message) ||
|
|
16
|
+
error.name === "BrainStorageError" ||
|
|
17
|
+
error.name === "BrainContractError") {
|
|
18
|
+
return { ok: false, error: { code: "brain_corrupt", message } };
|
|
19
|
+
}
|
|
20
|
+
return { ok: false, error: { code: "internal", message } };
|
|
21
|
+
}
|
|
22
|
+
return { ok: false, error: { code: "unknown", message: "unknown error" } };
|
|
23
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { startBrainMcpServer, runBrainMcpStdio } from "./server.js";
|
|
2
|
+
export type { StartBrainMcpServerOptions } from "./server.js";
|
|
3
|
+
export { BrainMcpSession } from "./session.js";
|
|
4
|
+
export type { BrainMcpSessionOptions } from "./session.js";
|
|
5
|
+
export { compileProjectBrain } from "./compile.js";
|
|
6
|
+
export { BrainMcpError, toToolErrorPayload } from "./errors.js";
|
|
7
|
+
export { wrapProvenance, stableJson, snapshotProvenance } from "./provenance.js";
|
|
8
|
+
export { resolveProjectRoot, assertPathInsideProject } from "./security/root.js";
|
|
9
|
+
export { listBrainMcpTools, invokeBrainMcpTool, BRAIN_MCP_TOOL_NAMES } from "./tools/registry.js";
|
|
10
|
+
export type { BrainMcpToolName } from "./tools/registry.js";
|
|
11
|
+
export { BRAIN_MCP_QUERY_TYPES, BRAIN_MCP_TRACE_MODES, resolveQueryType, resolveTraceMode, } from "./schemas.js";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { startBrainMcpServer, runBrainMcpStdio } from "./server.js";
|
|
2
|
+
export { BrainMcpSession } from "./session.js";
|
|
3
|
+
export { compileProjectBrain } from "./compile.js";
|
|
4
|
+
export { BrainMcpError, toToolErrorPayload } from "./errors.js";
|
|
5
|
+
export { wrapProvenance, stableJson, snapshotProvenance } from "./provenance.js";
|
|
6
|
+
export { resolveProjectRoot, assertPathInsideProject } from "./security/root.js";
|
|
7
|
+
export { listBrainMcpTools, invokeBrainMcpTool, BRAIN_MCP_TOOL_NAMES } from "./tools/registry.js";
|
|
8
|
+
export { BRAIN_MCP_QUERY_TYPES, BRAIN_MCP_TRACE_MODES, resolveQueryType, resolveTraceMode, } from "./schemas.js";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ProjectBrain } from "../../core/understanding/brain/index.js";
|
|
2
|
+
export interface SnapshotProvenance {
|
|
3
|
+
id: string;
|
|
4
|
+
schemaVersion: string;
|
|
5
|
+
contentHash: string;
|
|
6
|
+
createdAt: string;
|
|
7
|
+
brainId: string;
|
|
8
|
+
projectName: string;
|
|
9
|
+
}
|
|
10
|
+
export interface BrainMcpEnvelope<T> {
|
|
11
|
+
ok: true;
|
|
12
|
+
result: T;
|
|
13
|
+
evidenceIds: readonly string[];
|
|
14
|
+
confidence: number;
|
|
15
|
+
snapshot: SnapshotProvenance;
|
|
16
|
+
claimStatus?: string;
|
|
17
|
+
metadata: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
export declare function snapshotProvenance(brain: ProjectBrain): SnapshotProvenance;
|
|
20
|
+
export declare function wrapProvenance<T>(options: {
|
|
21
|
+
brain: ProjectBrain;
|
|
22
|
+
result: T;
|
|
23
|
+
evidenceIds?: readonly string[];
|
|
24
|
+
confidence?: number;
|
|
25
|
+
claimStatus?: string;
|
|
26
|
+
metadata?: Record<string, unknown>;
|
|
27
|
+
}): BrainMcpEnvelope<T>;
|
|
28
|
+
/** Stable JSON for determinism checks (drops timing). */
|
|
29
|
+
export declare function stableJson(value: unknown): string;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export function snapshotProvenance(brain) {
|
|
2
|
+
return {
|
|
3
|
+
id: brain.snapshot.id,
|
|
4
|
+
schemaVersion: brain.metadata.schemaVersion,
|
|
5
|
+
contentHash: brain.snapshot.contentHash,
|
|
6
|
+
createdAt: brain.snapshot.generatedAt,
|
|
7
|
+
brainId: brain.metadata.brainId,
|
|
8
|
+
projectName: brain.metadata.projectName,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export function wrapProvenance(options) {
|
|
12
|
+
const envelope = {
|
|
13
|
+
ok: true,
|
|
14
|
+
result: options.result,
|
|
15
|
+
evidenceIds: options.evidenceIds ?? [],
|
|
16
|
+
confidence: options.confidence ?? 0,
|
|
17
|
+
snapshot: snapshotProvenance(options.brain),
|
|
18
|
+
metadata: options.metadata ?? {},
|
|
19
|
+
};
|
|
20
|
+
if (options.claimStatus !== undefined) {
|
|
21
|
+
envelope.claimStatus = options.claimStatus;
|
|
22
|
+
}
|
|
23
|
+
return envelope;
|
|
24
|
+
}
|
|
25
|
+
/** Stable JSON for determinism checks (drops timing). */
|
|
26
|
+
export function stableJson(value) {
|
|
27
|
+
return `${JSON.stringify(sortKeysDeep(stripTiming(value)))}\n`;
|
|
28
|
+
}
|
|
29
|
+
function stripTiming(value) {
|
|
30
|
+
if (Array.isArray(value)) {
|
|
31
|
+
return value.map(stripTiming);
|
|
32
|
+
}
|
|
33
|
+
if (value && typeof value === "object") {
|
|
34
|
+
const record = value;
|
|
35
|
+
const next = {};
|
|
36
|
+
for (const [key, entry] of Object.entries(record)) {
|
|
37
|
+
if (key === "executionTimeMs" || key === "timingMs") {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
next[key] = stripTiming(entry);
|
|
41
|
+
}
|
|
42
|
+
return next;
|
|
43
|
+
}
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
function sortKeysDeep(value) {
|
|
47
|
+
if (Array.isArray(value)) {
|
|
48
|
+
return value.map(sortKeysDeep);
|
|
49
|
+
}
|
|
50
|
+
if (value && typeof value === "object") {
|
|
51
|
+
const record = value;
|
|
52
|
+
const sorted = {};
|
|
53
|
+
for (const key of Object.keys(record).sort((a, b) => a.localeCompare(b))) {
|
|
54
|
+
sorted[key] = sortKeysDeep(record[key]);
|
|
55
|
+
}
|
|
56
|
+
return sorted;
|
|
57
|
+
}
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { BrainQueryType } from "../../core/understanding/brain/index.js";
|
|
2
|
+
import type { TraceMode } from "../../core/understanding/brain/index.js";
|
|
3
|
+
export declare const BRAIN_MCP_QUERY_TYPES: readonly ["ProjectSummary", "ListDomains", "ListComponents", "ListEntrypoints", "ListDependencies", "ListRelationships", "ListArchitectures", "ListOwnership", "ListRisks", "ListClaims", "ListEvidence", "ListContradictions", "ListUnknowns", "ListInvalidations", "Impact", "BlastRadius"];
|
|
4
|
+
export declare const BRAIN_MCP_TRACE_MODES: readonly ["dependencies", "dependents", "entrypoint-downstream", "blast-radius", "domain-modules"];
|
|
5
|
+
export declare const CLAIM_STATUSES: readonly ["ACTIVE", "INVALIDATED", "SUPERSEDED", "CONTRADICTED"];
|
|
6
|
+
export type ClaimStatusFilter = (typeof CLAIM_STATUSES)[number];
|
|
7
|
+
export declare function resolveQueryType(input: string): BrainQueryType;
|
|
8
|
+
export declare function resolveTraceMode(input: string | undefined): TraceMode;
|
|
9
|
+
export declare function parseClaimStatus(input: string | undefined): ClaimStatusFilter | undefined;
|
|
10
|
+
export declare function requireString(value: unknown, field: string, options?: {
|
|
11
|
+
allowEmpty?: boolean;
|
|
12
|
+
}): string;
|
|
13
|
+
export declare function asObject(value: unknown): Record<string, unknown>;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { BrainMcpError } from "./errors.js";
|
|
2
|
+
export const BRAIN_MCP_QUERY_TYPES = [
|
|
3
|
+
"ProjectSummary",
|
|
4
|
+
"ListDomains",
|
|
5
|
+
"ListComponents",
|
|
6
|
+
"ListEntrypoints",
|
|
7
|
+
"ListDependencies",
|
|
8
|
+
"ListRelationships",
|
|
9
|
+
"ListArchitectures",
|
|
10
|
+
"ListOwnership",
|
|
11
|
+
"ListRisks",
|
|
12
|
+
"ListClaims",
|
|
13
|
+
"ListEvidence",
|
|
14
|
+
"ListContradictions",
|
|
15
|
+
"ListUnknowns",
|
|
16
|
+
"ListInvalidations",
|
|
17
|
+
"Impact",
|
|
18
|
+
"BlastRadius",
|
|
19
|
+
];
|
|
20
|
+
export const BRAIN_MCP_TRACE_MODES = [
|
|
21
|
+
"dependencies",
|
|
22
|
+
"dependents",
|
|
23
|
+
"entrypoint-downstream",
|
|
24
|
+
"blast-radius",
|
|
25
|
+
"domain-modules",
|
|
26
|
+
];
|
|
27
|
+
export const CLAIM_STATUSES = ["ACTIVE", "INVALIDATED", "SUPERSEDED", "CONTRADICTED"];
|
|
28
|
+
const QUERY_ALIASES = {
|
|
29
|
+
project_summary: "ProjectSummary",
|
|
30
|
+
find_component: "ListComponents",
|
|
31
|
+
find_module: "ListComponents",
|
|
32
|
+
find_entrypoint: "ListEntrypoints",
|
|
33
|
+
find_ownership: "ListOwnership",
|
|
34
|
+
find_risks: "ListRisks",
|
|
35
|
+
find_claims: "ListClaims",
|
|
36
|
+
find_dependencies: "ListDependencies",
|
|
37
|
+
find_relationships: "ListRelationships",
|
|
38
|
+
list_domains: "ListDomains",
|
|
39
|
+
list_components: "ListComponents",
|
|
40
|
+
list_entrypoints: "ListEntrypoints",
|
|
41
|
+
list_dependencies: "ListDependencies",
|
|
42
|
+
list_relationships: "ListRelationships",
|
|
43
|
+
list_architectures: "ListArchitectures",
|
|
44
|
+
list_ownership: "ListOwnership",
|
|
45
|
+
list_risks: "ListRisks",
|
|
46
|
+
list_claims: "ListClaims",
|
|
47
|
+
list_evidence: "ListEvidence",
|
|
48
|
+
list_contradictions: "ListContradictions",
|
|
49
|
+
list_unknowns: "ListUnknowns",
|
|
50
|
+
list_invalidations: "ListInvalidations",
|
|
51
|
+
impact: "Impact",
|
|
52
|
+
blast_radius: "BlastRadius",
|
|
53
|
+
};
|
|
54
|
+
export function resolveQueryType(input) {
|
|
55
|
+
const trimmed = input.trim();
|
|
56
|
+
if (BRAIN_MCP_QUERY_TYPES.includes(trimmed)) {
|
|
57
|
+
return trimmed;
|
|
58
|
+
}
|
|
59
|
+
const alias = QUERY_ALIASES[trimmed.toLowerCase()];
|
|
60
|
+
if (alias) {
|
|
61
|
+
return alias;
|
|
62
|
+
}
|
|
63
|
+
throw new BrainMcpError("unsupported_query", `unsupported query type "${input}"; supported: ${BRAIN_MCP_QUERY_TYPES.join(", ")}`);
|
|
64
|
+
}
|
|
65
|
+
export function resolveTraceMode(input) {
|
|
66
|
+
if (input === undefined || input.trim() === "") {
|
|
67
|
+
return "blast-radius";
|
|
68
|
+
}
|
|
69
|
+
const trimmed = input.trim();
|
|
70
|
+
if (BRAIN_MCP_TRACE_MODES.includes(trimmed)) {
|
|
71
|
+
return trimmed;
|
|
72
|
+
}
|
|
73
|
+
throw new BrainMcpError("invalid_argument", `unsupported trace mode "${input}"; supported: ${BRAIN_MCP_TRACE_MODES.join(", ")}`);
|
|
74
|
+
}
|
|
75
|
+
export function parseClaimStatus(input) {
|
|
76
|
+
if (input === undefined || input.trim() === "") {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
const trimmed = input.trim().toUpperCase();
|
|
80
|
+
if (CLAIM_STATUSES.includes(trimmed)) {
|
|
81
|
+
return trimmed;
|
|
82
|
+
}
|
|
83
|
+
throw new BrainMcpError("invalid_argument", `invalid claim status "${input}"; expected one of ${CLAIM_STATUSES.join(", ")}`);
|
|
84
|
+
}
|
|
85
|
+
export function requireString(value, field, options = {}) {
|
|
86
|
+
if (typeof value !== "string") {
|
|
87
|
+
throw new BrainMcpError("invalid_argument", `${field} must be a string`);
|
|
88
|
+
}
|
|
89
|
+
if (!options.allowEmpty && value.trim().length === 0) {
|
|
90
|
+
throw new BrainMcpError("invalid_argument", `${field} must not be empty`);
|
|
91
|
+
}
|
|
92
|
+
if (/[\r\n\0]/.test(value)) {
|
|
93
|
+
throw new BrainMcpError("invalid_argument", `${field} must not contain control characters`);
|
|
94
|
+
}
|
|
95
|
+
return value.trim();
|
|
96
|
+
}
|
|
97
|
+
export function asObject(value) {
|
|
98
|
+
if (value === undefined || value === null) {
|
|
99
|
+
return {};
|
|
100
|
+
}
|
|
101
|
+
if (typeof value !== "object" || Array.isArray(value)) {
|
|
102
|
+
throw new BrainMcpError("invalid_argument", "arguments must be an object");
|
|
103
|
+
}
|
|
104
|
+
return value;
|
|
105
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve and validate an explicit project root for Brain MCP.
|
|
3
|
+
* Never falls back to process.cwd(). Rejects traversal and symlink escapes.
|
|
4
|
+
*/
|
|
5
|
+
export declare function resolveProjectRoot(explicitRoot: string): Promise<string>;
|
|
6
|
+
export declare function assertPathInsideProject(projectRoot: string, candidate: string): Promise<string>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { isPathInsideRoot } from "../../../utils/path.js";
|
|
4
|
+
import { BrainMcpError } from "../errors.js";
|
|
5
|
+
/**
|
|
6
|
+
* Resolve and validate an explicit project root for Brain MCP.
|
|
7
|
+
* Never falls back to process.cwd(). Rejects traversal and symlink escapes.
|
|
8
|
+
*/
|
|
9
|
+
export async function resolveProjectRoot(explicitRoot) {
|
|
10
|
+
const trimmed = explicitRoot.trim();
|
|
11
|
+
if (!trimmed) {
|
|
12
|
+
throw new BrainMcpError("invalid_root", "project root is required (pass --root)");
|
|
13
|
+
}
|
|
14
|
+
if (/[\r\n\0]/.test(trimmed)) {
|
|
15
|
+
throw new BrainMcpError("invalid_root", "project root must not contain control characters");
|
|
16
|
+
}
|
|
17
|
+
const resolved = path.resolve(trimmed);
|
|
18
|
+
let real;
|
|
19
|
+
try {
|
|
20
|
+
real = await fs.realpath(resolved);
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
const code = error && typeof error === "object" && "code" in error ? String(error.code) : "";
|
|
24
|
+
if (code === "ENOENT") {
|
|
25
|
+
throw new BrainMcpError("invalid_root", `project root does not exist: ${resolved}`);
|
|
26
|
+
}
|
|
27
|
+
throw new BrainMcpError("invalid_root", `cannot resolve project root: ${resolved}`);
|
|
28
|
+
}
|
|
29
|
+
let stat;
|
|
30
|
+
try {
|
|
31
|
+
stat = await fs.stat(real);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
throw new BrainMcpError("invalid_root", `project root is not accessible: ${real}`);
|
|
35
|
+
}
|
|
36
|
+
if (!stat.isDirectory()) {
|
|
37
|
+
throw new BrainMcpError("invalid_root", `project root must be a directory: ${real}`);
|
|
38
|
+
}
|
|
39
|
+
// Lexical resolve must stay aligned with realpath (symlink escape of the input itself).
|
|
40
|
+
if (!isPathInsideRoot(real, resolved) && path.resolve(resolved) !== real) {
|
|
41
|
+
// Input may be a symlink to real — require real to be the canonical root we use.
|
|
42
|
+
}
|
|
43
|
+
return real;
|
|
44
|
+
}
|
|
45
|
+
export async function assertPathInsideProject(projectRoot, candidate) {
|
|
46
|
+
const resolved = path.resolve(projectRoot, candidate);
|
|
47
|
+
if (!isPathInsideRoot(projectRoot, resolved)) {
|
|
48
|
+
throw new BrainMcpError("path_escape", "path escapes project root");
|
|
49
|
+
}
|
|
50
|
+
let real;
|
|
51
|
+
try {
|
|
52
|
+
real = await fs.realpath(resolved);
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
const code = error && typeof error === "object" && "code" in error ? String(error.code) : "";
|
|
56
|
+
if (code === "ENOENT") {
|
|
57
|
+
// Non-existent paths are allowed for validation of relative refs; still check lexical.
|
|
58
|
+
return resolved;
|
|
59
|
+
}
|
|
60
|
+
throw new BrainMcpError("path_escape", "cannot resolve path inside project root");
|
|
61
|
+
}
|
|
62
|
+
if (!isPathInsideRoot(projectRoot, real)) {
|
|
63
|
+
throw new BrainMcpError("path_escape", "path escapes project root via symlink");
|
|
64
|
+
}
|
|
65
|
+
return real;
|
|
66
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import { BrainMcpSession, type BrainMcpSessionOptions } from "./session.js";
|
|
3
|
+
export type StartBrainMcpServerOptions = BrainMcpSessionOptions;
|
|
4
|
+
/**
|
|
5
|
+
* Start the AgentDoctor Brain MCP server over STDIO.
|
|
6
|
+
* Protocol traffic goes to stdout; diagnostics to stderr only.
|
|
7
|
+
*/
|
|
8
|
+
export declare function startBrainMcpServer(options: StartBrainMcpServerOptions): Promise<{
|
|
9
|
+
server: Server;
|
|
10
|
+
session: BrainMcpSession;
|
|
11
|
+
}>;
|
|
12
|
+
export declare function runBrainMcpStdio(options: StartBrainMcpServerOptions): Promise<void>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
4
|
+
import { PACKAGE_VERSION } from "../../constants.js";
|
|
5
|
+
import { BrainMcpSession } from "./session.js";
|
|
6
|
+
import { invokeBrainMcpTool, listBrainMcpTools } from "./tools/registry.js";
|
|
7
|
+
/**
|
|
8
|
+
* Start the AgentDoctor Brain MCP server over STDIO.
|
|
9
|
+
* Protocol traffic goes to stdout; diagnostics to stderr only.
|
|
10
|
+
*/
|
|
11
|
+
export async function startBrainMcpServer(options) {
|
|
12
|
+
const session = new BrainMcpSession(options);
|
|
13
|
+
await session.initialize();
|
|
14
|
+
const server = new Server({
|
|
15
|
+
name: "agentdoctor-brain",
|
|
16
|
+
version: PACKAGE_VERSION,
|
|
17
|
+
}, {
|
|
18
|
+
capabilities: {
|
|
19
|
+
tools: {},
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
23
|
+
tools: listBrainMcpTools(),
|
|
24
|
+
}));
|
|
25
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
26
|
+
const name = request.params.name;
|
|
27
|
+
const args = request.params.arguments ?? {};
|
|
28
|
+
const { structured, isError } = await invokeBrainMcpTool(session, name, args);
|
|
29
|
+
return {
|
|
30
|
+
content: [
|
|
31
|
+
{
|
|
32
|
+
type: "text",
|
|
33
|
+
text: JSON.stringify(structured),
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
structuredContent: structured,
|
|
37
|
+
isError,
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
const transport = new StdioServerTransport();
|
|
41
|
+
await server.connect(transport);
|
|
42
|
+
return { server, session };
|
|
43
|
+
}
|
|
44
|
+
export async function runBrainMcpStdio(options) {
|
|
45
|
+
await startBrainMcpServer(options);
|
|
46
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { LocalBrainStore, type ProjectBrain, type SnapshotMeta } from "../../core/understanding/brain/index.js";
|
|
2
|
+
export interface BrainMcpSessionOptions {
|
|
3
|
+
/** Explicit project root — required. Never defaults to process.cwd(). */
|
|
4
|
+
root: string;
|
|
5
|
+
/** When true, rebuild brain if no snapshot exists. Default true. */
|
|
6
|
+
buildIfMissing?: boolean;
|
|
7
|
+
/** Optional fixed timestamp for deterministic rebuilds in tests. */
|
|
8
|
+
generatedAt?: string;
|
|
9
|
+
/** stderr logger — never write protocol traffic. */
|
|
10
|
+
log?: (message: string) => void;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Holds a loaded ProjectBrain for the lifetime of an MCP server process.
|
|
14
|
+
* Brain is loaded once; tools query the in-memory snapshot.
|
|
15
|
+
*/
|
|
16
|
+
export declare class BrainMcpSession {
|
|
17
|
+
private readonly options;
|
|
18
|
+
private root;
|
|
19
|
+
private store;
|
|
20
|
+
private brain;
|
|
21
|
+
private readonly buildIfMissing;
|
|
22
|
+
private readonly generatedAt;
|
|
23
|
+
private readonly log;
|
|
24
|
+
constructor(options: BrainMcpSessionOptions);
|
|
25
|
+
initialize(): Promise<void>;
|
|
26
|
+
getProjectRoot(): string;
|
|
27
|
+
getStore(): LocalBrainStore;
|
|
28
|
+
getBrain(): ProjectBrain;
|
|
29
|
+
rebuild(): Promise<ProjectBrain>;
|
|
30
|
+
loadSnapshot(snapshotId: string): Promise<ProjectBrain>;
|
|
31
|
+
listSnapshots(): Promise<SnapshotMeta[]>;
|
|
32
|
+
compareSnapshots(leftId: string, rightId: string): Promise<import("../../core/understanding/brain/index.js").SnapshotComparison>;
|
|
33
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { LocalBrainStore, } from "../../core/understanding/brain/index.js";
|
|
2
|
+
import { compileProjectBrain } from "./compile.js";
|
|
3
|
+
import { BrainMcpError } from "./errors.js";
|
|
4
|
+
import { resolveProjectRoot } from "./security/root.js";
|
|
5
|
+
/**
|
|
6
|
+
* Holds a loaded ProjectBrain for the lifetime of an MCP server process.
|
|
7
|
+
* Brain is loaded once; tools query the in-memory snapshot.
|
|
8
|
+
*/
|
|
9
|
+
export class BrainMcpSession {
|
|
10
|
+
options;
|
|
11
|
+
root = null;
|
|
12
|
+
store = null;
|
|
13
|
+
brain = null;
|
|
14
|
+
buildIfMissing;
|
|
15
|
+
generatedAt;
|
|
16
|
+
log;
|
|
17
|
+
constructor(options) {
|
|
18
|
+
this.options = options;
|
|
19
|
+
this.buildIfMissing = options.buildIfMissing !== false;
|
|
20
|
+
this.generatedAt = options.generatedAt;
|
|
21
|
+
this.log = options.log ?? ((message) => process.stderr.write(`${message}\n`));
|
|
22
|
+
}
|
|
23
|
+
async initialize() {
|
|
24
|
+
this.root = await resolveProjectRoot(this.options.root);
|
|
25
|
+
this.store = LocalBrainStore.underRepo(this.root);
|
|
26
|
+
let loaded = null;
|
|
27
|
+
try {
|
|
28
|
+
loaded = await this.store.loadLatest();
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
const message = error instanceof Error ? error.message : "corrupt brain store";
|
|
32
|
+
throw new BrainMcpError("brain_corrupt", message);
|
|
33
|
+
}
|
|
34
|
+
if (loaded) {
|
|
35
|
+
this.brain = loaded;
|
|
36
|
+
this.log(`agentdoctor brain-mcp: loaded snapshot ${loaded.snapshot.id} from ${this.root}`);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (!this.buildIfMissing) {
|
|
40
|
+
throw new BrainMcpError("brain_not_found", "no Project Brain snapshot found; rebuild with brain_snapshot action=rebuild");
|
|
41
|
+
}
|
|
42
|
+
this.log(`agentdoctor brain-mcp: no snapshot found; compiling Project Brain…`);
|
|
43
|
+
await this.rebuild();
|
|
44
|
+
}
|
|
45
|
+
getProjectRoot() {
|
|
46
|
+
if (!this.root) {
|
|
47
|
+
throw new BrainMcpError("invalid_root", "session not initialized");
|
|
48
|
+
}
|
|
49
|
+
return this.root;
|
|
50
|
+
}
|
|
51
|
+
getStore() {
|
|
52
|
+
if (!this.store) {
|
|
53
|
+
throw new BrainMcpError("internal", "session not initialized");
|
|
54
|
+
}
|
|
55
|
+
return this.store;
|
|
56
|
+
}
|
|
57
|
+
getBrain() {
|
|
58
|
+
if (!this.brain) {
|
|
59
|
+
throw new BrainMcpError("brain_not_found", "no Project Brain loaded; rebuild with brain_snapshot action=rebuild");
|
|
60
|
+
}
|
|
61
|
+
return this.brain;
|
|
62
|
+
}
|
|
63
|
+
async rebuild() {
|
|
64
|
+
const root = this.getProjectRoot();
|
|
65
|
+
const store = this.getStore();
|
|
66
|
+
const previous = this.brain;
|
|
67
|
+
const brain = await compileProjectBrain(root, {
|
|
68
|
+
...(previous ? { previousClaims: previous.claims } : {}),
|
|
69
|
+
...(this.generatedAt !== undefined ? { generatedAt: this.generatedAt } : {}),
|
|
70
|
+
});
|
|
71
|
+
try {
|
|
72
|
+
await store.saveSnapshot(brain);
|
|
73
|
+
this.log(`agentdoctor brain-mcp: saved snapshot ${brain.snapshot.id}`);
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
const message = error instanceof Error ? error.message : "";
|
|
77
|
+
if (/refusing overwrite/i.test(message)) {
|
|
78
|
+
// Model identity unchanged while claim lifecycle/content differs — keep memory fresh.
|
|
79
|
+
this.log(`agentdoctor brain-mcp: snapshot ${brain.snapshot.id} unchanged structurally; refreshed in-memory brain`);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
throw error instanceof BrainMcpError
|
|
83
|
+
? error
|
|
84
|
+
: new BrainMcpError("brain_corrupt", message || "failed to save snapshot");
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
this.brain = brain;
|
|
88
|
+
return brain;
|
|
89
|
+
}
|
|
90
|
+
async loadSnapshot(snapshotId) {
|
|
91
|
+
const store = this.getStore();
|
|
92
|
+
try {
|
|
93
|
+
const brain = await store.loadSnapshot(snapshotId);
|
|
94
|
+
this.brain = brain;
|
|
95
|
+
return brain;
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
const message = error instanceof Error ? error.message : "failed to load snapshot";
|
|
99
|
+
if (/not found|ENOENT/i.test(message)) {
|
|
100
|
+
throw new BrainMcpError("not_found", message);
|
|
101
|
+
}
|
|
102
|
+
throw new BrainMcpError("brain_corrupt", message);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async listSnapshots() {
|
|
106
|
+
return this.getStore().listSnapshots();
|
|
107
|
+
}
|
|
108
|
+
async compareSnapshots(leftId, rightId) {
|
|
109
|
+
try {
|
|
110
|
+
return await this.getStore().compareSnapshots(leftId, rightId);
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
const message = error instanceof Error ? error.message : "compare failed";
|
|
114
|
+
throw new BrainMcpError("brain_corrupt", message);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type BrainMcpEnvelope } from "../provenance.js";
|
|
2
|
+
import type { BrainMcpSession } from "../session.js";
|
|
3
|
+
export type ToolResult = BrainMcpEnvelope<unknown>;
|
|
4
|
+
export declare function handleBrainOverview(session: BrainMcpSession): Promise<ToolResult>;
|
|
5
|
+
export declare function handleBrainQuery(session: BrainMcpSession, rawArgs: unknown): Promise<ToolResult>;
|
|
6
|
+
export declare function handleBrainExplain(session: BrainMcpSession, rawArgs: unknown): Promise<ToolResult>;
|
|
7
|
+
export declare function handleBrainTrace(session: BrainMcpSession, rawArgs: unknown): Promise<ToolResult>;
|
|
8
|
+
export declare function handleBrainClaims(session: BrainMcpSession, rawArgs: unknown): Promise<ToolResult>;
|
|
9
|
+
export declare function handleBrainEvidence(session: BrainMcpSession, rawArgs: unknown): Promise<ToolResult>;
|
|
10
|
+
export declare function handleBrainOwnership(session: BrainMcpSession, rawArgs: unknown): Promise<ToolResult>;
|
|
11
|
+
export declare function handleBrainRisk(session: BrainMcpSession, rawArgs: unknown): Promise<ToolResult>;
|
|
12
|
+
export declare function handleBrainDelta(session: BrainMcpSession, rawArgs: unknown): Promise<ToolResult>;
|
|
13
|
+
export declare function handleBrainSnapshot(session: BrainMcpSession, rawArgs: unknown): Promise<ToolResult>;
|