@praneeth_54/agentdoctor 2.1.0 → 3.0.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.
Files changed (129) hide show
  1. package/CHANGELOG.md +57 -3
  2. package/README.md +489 -290
  3. package/dist/agent/chat/deterministic.d.ts +6 -0
  4. package/dist/agent/chat/deterministic.js +180 -0
  5. package/dist/agent/chat/service.js +8 -14
  6. package/dist/agent/index.d.ts +2 -0
  7. package/dist/agent/index.js +1 -0
  8. package/dist/agent/loop.d.ts +2 -0
  9. package/dist/agent/loop.js +31 -0
  10. package/dist/agent/roles.d.ts +12 -0
  11. package/dist/agent/roles.js +138 -0
  12. package/dist/agent/runtime.d.ts +21 -5
  13. package/dist/agent/runtime.js +141 -28
  14. package/dist/agent/tools/execute.d.ts +2 -0
  15. package/dist/agent/tools/execute.js +10 -0
  16. package/dist/ai/config.js +1 -0
  17. package/dist/ai/redact.d.ts +1 -0
  18. package/dist/ai/redact.js +47 -7
  19. package/dist/ai/types.d.ts +1 -1
  20. package/dist/cli/commands/agent.d.ts +2 -0
  21. package/dist/cli/commands/agent.js +19 -8
  22. package/dist/cli/commands/chat.js +2 -4
  23. package/dist/cli/commands/product.d.ts +19 -0
  24. package/dist/cli/commands/product.js +147 -0
  25. package/dist/cli/commands/start.d.ts +15 -0
  26. package/dist/cli/commands/start.js +80 -0
  27. package/dist/cli/program.js +141 -0
  28. package/dist/constants.d.ts +1 -1
  29. package/dist/constants.js +1 -1
  30. package/dist/dashboard/server.js +255 -53
  31. package/dist/index.d.ts +4 -0
  32. package/dist/index.js +2 -0
  33. package/dist/intelligence/graph/build.js +36 -8
  34. package/dist/intelligence/resolve/imports.js +1 -1
  35. package/dist/languages/dart.d.ts +10 -0
  36. package/dist/languages/dart.js +99 -0
  37. package/dist/languages/go.d.ts +13 -7
  38. package/dist/languages/go.js +84 -24
  39. package/dist/languages/index.d.ts +5 -1
  40. package/dist/languages/index.js +13 -36
  41. package/dist/languages/java.d.ts +10 -0
  42. package/dist/languages/java.js +80 -0
  43. package/dist/languages/kotlin.d.ts +10 -0
  44. package/dist/languages/kotlin.js +85 -0
  45. package/dist/languages/rust.d.ts +10 -0
  46. package/dist/languages/rust.js +93 -0
  47. package/dist/languages/types.d.ts +4 -3
  48. package/dist/mcp/agent/registry.d.ts +1 -1
  49. package/dist/mcp/agent/registry.js +109 -23
  50. package/dist/mcp/intelligence/handlers.d.ts +3 -0
  51. package/dist/mcp/intelligence/handlers.js +28 -0
  52. package/dist/mcp/intelligence/registry.d.ts +1 -1
  53. package/dist/mcp/intelligence/registry.js +30 -1
  54. package/dist/product/api/doctor.d.ts +14 -0
  55. package/dist/product/api/doctor.js +185 -0
  56. package/dist/product/api/openapi.d.ts +7 -0
  57. package/dist/product/api/openapi.js +122 -0
  58. package/dist/product/approval/model.d.ts +30 -0
  59. package/dist/product/approval/model.js +64 -0
  60. package/dist/product/approval/session.d.ts +49 -0
  61. package/dist/product/approval/session.js +134 -0
  62. package/dist/product/database/doctor.d.ts +30 -0
  63. package/dist/product/database/doctor.js +184 -0
  64. package/dist/product/decisions/ledger.d.ts +24 -0
  65. package/dist/product/decisions/ledger.js +110 -0
  66. package/dist/product/deps/analyze.d.ts +46 -0
  67. package/dist/product/deps/analyze.js +137 -0
  68. package/dist/product/deps/lockfiles.d.ts +25 -0
  69. package/dist/product/deps/lockfiles.js +200 -0
  70. package/dist/product/discovery/roots.d.ts +42 -0
  71. package/dist/product/discovery/roots.js +215 -0
  72. package/dist/product/dna/build.d.ts +50 -0
  73. package/dist/product/dna/build.js +255 -0
  74. package/dist/product/eval/lab.d.ts +17 -0
  75. package/dist/product/eval/lab.js +218 -0
  76. package/dist/product/events/doctor.d.ts +21 -0
  77. package/dist/product/events/doctor.js +147 -0
  78. package/dist/product/evidence-scan.d.ts +12 -0
  79. package/dist/product/evidence-scan.js +46 -0
  80. package/dist/product/evolution/timeline.d.ts +29 -0
  81. package/dist/product/evolution/timeline.js +123 -0
  82. package/dist/product/features/intelligence.d.ts +23 -0
  83. package/dist/product/features/intelligence.js +158 -0
  84. package/dist/product/forensic/mode.d.ts +25 -0
  85. package/dist/product/forensic/mode.js +70 -0
  86. package/dist/product/graph/enrich-languages.d.ts +20 -0
  87. package/dist/product/graph/enrich-languages.js +193 -0
  88. package/dist/product/health/code-health.d.ts +20 -0
  89. package/dist/product/health/code-health.js +149 -0
  90. package/dist/product/index.d.ts +69 -0
  91. package/dist/product/index.js +35 -0
  92. package/dist/product/ledger/change-ledger.d.ts +23 -0
  93. package/dist/product/ledger/change-ledger.js +64 -0
  94. package/dist/product/map/software-map.d.ts +17 -0
  95. package/dist/product/map/software-map.js +95 -0
  96. package/dist/product/memory/institutional.d.ts +16 -0
  97. package/dist/product/memory/institutional.js +87 -0
  98. package/dist/product/ops/incident.d.ts +20 -0
  99. package/dist/product/ops/incident.js +61 -0
  100. package/dist/product/ops/infra.d.ts +15 -0
  101. package/dist/product/ops/infra.js +112 -0
  102. package/dist/product/org/model.d.ts +34 -0
  103. package/dist/product/org/model.js +195 -0
  104. package/dist/product/privacy/doctor.d.ts +13 -0
  105. package/dist/product/privacy/doctor.js +90 -0
  106. package/dist/product/requirements/trace.d.ts +21 -0
  107. package/dist/product/requirements/trace.js +166 -0
  108. package/dist/product/search/index.d.ts +29 -0
  109. package/dist/product/search/index.js +116 -0
  110. package/dist/product/search/software-search.d.ts +19 -0
  111. package/dist/product/search/software-search.js +100 -0
  112. package/dist/product/security/doctor.d.ts +23 -0
  113. package/dist/product/security/doctor.js +124 -0
  114. package/dist/product/self/diagnose.d.ts +15 -0
  115. package/dist/product/self/diagnose.js +82 -0
  116. package/dist/product/techdebt/roadmap.d.ts +20 -0
  117. package/dist/product/techdebt/roadmap.js +118 -0
  118. package/dist/product/testbrain/analyze.d.ts +29 -0
  119. package/dist/product/testbrain/analyze.js +129 -0
  120. package/dist/product/truth.d.ts +12 -0
  121. package/dist/product/truth.js +30 -0
  122. package/dist/product/twin/digital-twin.d.ts +23 -0
  123. package/dist/product/twin/digital-twin.js +52 -0
  124. package/dist/product/twin/store.d.ts +21 -0
  125. package/dist/product/twin/store.js +70 -0
  126. package/dist/product/whatif/engine.d.ts +28 -0
  127. package/dist/product/whatif/engine.js +70 -0
  128. package/dist/utils/fs.js +10 -2
  129. package/package.json +1 -1
@@ -0,0 +1,80 @@
1
+ import { EXIT_CODES } from "../../types/index.js";
2
+ import { initBrainStore, rebuildBrain, getBrainStatus } from "../../core/brain-cli/service.js";
3
+ import { discoverProjectRoots } from "../../product/discovery/roots.js";
4
+ import { buildProjectDna, persistProjectDna } from "../../product/dna/build.js";
5
+ import { resolveRepoRoot } from "../../utils/path.js";
6
+ function printJson(value) {
7
+ process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
8
+ }
9
+ export async function runStartCommand(options) {
10
+ const prefer = options.select ?? options.root;
11
+ const discovery = await discoverProjectRoots({
12
+ cwd: prefer ? resolveRepoRoot(prefer) : process.cwd(),
13
+ ...(prefer ? { prefer: resolveRepoRoot(prefer) } : {}),
14
+ ...(options.maxEntries !== undefined ? { maxEntries: options.maxEntries } : {}),
15
+ autoSelect: !options.listOnly,
16
+ });
17
+ if (options.listOnly || discovery.blocked || !discovery.selected) {
18
+ if (options.json) {
19
+ printJson({ discovery, dna: null, brain: null });
20
+ return discovery.blocked ? EXIT_CODES.USAGE_ERROR : EXIT_CODES.SUCCESS;
21
+ }
22
+ if (discovery.blocked) {
23
+ process.stderr.write(`Blocked: ${discovery.blockReason}\n`);
24
+ return EXIT_CODES.USAGE_ERROR;
25
+ }
26
+ process.stdout.write("Project candidates:\n");
27
+ if (discovery.candidates.length === 0) {
28
+ process.stdout.write(" (none found — navigate into a project or pass a path)\n");
29
+ return EXIT_CODES.USAGE_ERROR;
30
+ }
31
+ for (const [i, c] of discovery.candidates.entries()) {
32
+ process.stdout.write(` [${i + 1}] ${c.root}\n score=${c.score} markers=${c.markers.join(", ")} (${c.reason})\n`);
33
+ }
34
+ process.stdout.write("\nRe-run with --select <path> to initialize that project.\n");
35
+ return EXIT_CODES.SUCCESS;
36
+ }
37
+ const root = discovery.selected.root;
38
+ const dna = await persistProjectDna(root);
39
+ let brainStatus = null;
40
+ if (options.initBrain !== false) {
41
+ brainStatus = await initBrainStore(root);
42
+ if (options.rebuildBrain) {
43
+ await rebuildBrain(root);
44
+ brainStatus = await getBrainStatus(root);
45
+ }
46
+ }
47
+ const payload = { discovery, dna, brain: brainStatus };
48
+ if (options.json) {
49
+ printJson(payload);
50
+ }
51
+ else {
52
+ process.stdout.write(`AgentDoctor start\n`);
53
+ process.stdout.write(` root: ${root}\n`);
54
+ process.stdout.write(` fingerprint: ${dna.fingerprint}\n`);
55
+ process.stdout.write(` type: ${dna.projectType}\n`);
56
+ process.stdout.write(` languages: ${dna.languages.join(", ") || "(none)"}\n`);
57
+ process.stdout.write(` frameworks: ${dna.frameworks.join(", ") || "(none)"}\n`);
58
+ process.stdout.write(` files: ${dna.counts.files} (source ${dna.counts.sourceFiles}, tests ${dna.counts.testFiles})\n`);
59
+ if (brainStatus) {
60
+ process.stdout.write(` brain: ${brainStatus.hasSnapshot ? `snapshot ${brainStatus.latestSnapshotId}` : "initialized (no snapshot yet — run with --rebuild-brain or brain rebuild)"}\n`);
61
+ }
62
+ process.stdout.write(` DNA written to .agentdoctor/dna/project-dna.json\n`);
63
+ }
64
+ return EXIT_CODES.SUCCESS;
65
+ }
66
+ export async function runDnaCommand(options) {
67
+ const root = resolveRepoRoot(options.root ?? process.cwd());
68
+ const dna = options.persist ? await persistProjectDna(root) : await buildProjectDna(root);
69
+ if (options.json) {
70
+ printJson(dna);
71
+ }
72
+ else {
73
+ process.stdout.write(`Project DNA: ${dna.name} (${dna.fingerprint})\n`);
74
+ process.stdout.write(` type: ${dna.projectType}\n`);
75
+ process.stdout.write(` languages: ${dna.languages.join(", ") || "(none)"}\n`);
76
+ process.stdout.write(` frameworks: ${dna.frameworks.join(", ") || "(none)"}\n`);
77
+ process.stdout.write(` monorepo: ${dna.monorepo.isMonorepo ? dna.monorepo.tool : "no"}\n`);
78
+ }
79
+ return EXIT_CODES.SUCCESS;
80
+ }
@@ -20,6 +20,8 @@ import { runWorkspaceCommand } from "./commands/workspace.js";
20
20
  import { runAskCommand, runChatCommand } from "./commands/chat.js";
21
21
  import { runAgentCommand, runPlanCommand } from "./commands/agent.js";
22
22
  import { runLearnCommand } from "./commands/learn.js";
23
+ import { runProductCommand } from "./commands/product.js";
24
+ import { runStartCommand, runDnaCommand } from "./commands/start.js";
23
25
  import { collectOpsHealth } from "../ops/health.js";
24
26
  import { listSessions, loadSession } from "../platform/sessions/store.js";
25
27
  import { exportReports } from "../platform/reports/export.js";
@@ -1282,6 +1284,7 @@ export function createProgram() {
1282
1284
  .option("--list-tools", "List available agent tools", false)
1283
1285
  .option("--tool <name>", "Run a single tool by name")
1284
1286
  .option("--goal <text>", "Build a change plan for this goal")
1287
+ .option("--role <role>", "Specialized role for plan/apply (planner, coder, tester, reviewer, security, …)")
1285
1288
  .option("--approve", "Record explicit human approval", false)
1286
1289
  .option("--apply", "Apply approved changes (requires --approve)", false)
1287
1290
  .option("--apply-ops <json>", "JSON array of {name, arguments} tool ops for --apply")
@@ -1294,6 +1297,7 @@ export function createProgram() {
1294
1297
  listTools: Boolean(options.listTools),
1295
1298
  ...(options.tool !== undefined ? { tool: options.tool } : {}),
1296
1299
  ...(options.goal !== undefined ? { goal: options.goal } : {}),
1300
+ ...(options.role !== undefined ? { role: options.role } : {}),
1297
1301
  approve: Boolean(options.approve),
1298
1302
  apply: Boolean(options.apply),
1299
1303
  ...(options.applyOps !== undefined ? { applyOpsJson: options.applyOps } : {}),
@@ -1543,6 +1547,143 @@ export function createProgram() {
1543
1547
  const code = await runExplainCommand(rule);
1544
1548
  process.exitCode = code;
1545
1549
  });
1550
+ function bindProductCommand(name, description, action) {
1551
+ program
1552
+ .command(name)
1553
+ .description(description)
1554
+ .argument("[path]", "Repository path")
1555
+ .option("--json", "Emit JSON report", false)
1556
+ .action(async (pathArg, _options, command) => {
1557
+ const options = command.optsWithGlobals();
1558
+ process.exitCode = await runProductCommand({
1559
+ action,
1560
+ root: resolveTargetArgument(pathArg),
1561
+ json: Boolean(options.json),
1562
+ });
1563
+ });
1564
+ }
1565
+ program
1566
+ .command("start")
1567
+ .description("Safe project discovery: detect project root, build Project DNA, initialize Project Brain")
1568
+ .argument("[path]", "Optional project path (default: cwd)")
1569
+ .option("--list", "List candidates without initializing", false)
1570
+ .option("--select <path>", "Explicitly select a project root")
1571
+ .option("--max-entries <n>", "Refuse scans larger than this entry budget", "25000")
1572
+ .option("--no-init-brain", "Skip Project Brain store initialization")
1573
+ .option("--rebuild-brain", "Compile Project Brain after init", false)
1574
+ .option("--json", "Emit JSON", false)
1575
+ .action(async (pathArg, options) => {
1576
+ process.exitCode = await runStartCommand({
1577
+ ...(pathArg !== undefined ? { root: resolveTargetArgument(pathArg) } : {}),
1578
+ listOnly: Boolean(options.list),
1579
+ ...(options.select !== undefined ? { select: options.select } : {}),
1580
+ maxEntries: Number(options.maxEntries ?? 25000),
1581
+ initBrain: options.initBrain !== false,
1582
+ rebuildBrain: Boolean(options.rebuildBrain),
1583
+ json: Boolean(options.json),
1584
+ });
1585
+ });
1586
+ program
1587
+ .command("dna")
1588
+ .description("Build deterministic Project DNA fingerprint")
1589
+ .argument("[path]", "Repository path")
1590
+ .option("--persist", "Write .agentdoctor/dna/project-dna.json", false)
1591
+ .option("--json", "Emit JSON", false)
1592
+ .action(async (pathArg, options) => {
1593
+ process.exitCode = await runDnaCommand({
1594
+ root: resolveTargetArgument(pathArg),
1595
+ persist: Boolean(options.persist),
1596
+ json: Boolean(options.json),
1597
+ });
1598
+ });
1599
+ bindProductCommand("requirements", "Trace requirements from markdown docs (evidence-backed)", "requirements");
1600
+ bindProductCommand("api", "Discover HTTP route patterns (regex evidence)", "api");
1601
+ bindProductCommand("database", "Discover schema objects from migrations/SQL/Prisma", "database");
1602
+ bindProductCommand("events", "Detect queues, workers, cron, and event markers", "events");
1603
+ bindProductCommand("dependency", "Analyze direct dependencies and workspace duplicates", "dependency");
1604
+ bindProductCommand("deps", "Alias for dependency", "dependency");
1605
+ bindProductCommand("health-code", "Aggregate code health indicators with evidence", "health-code");
1606
+ bindProductCommand("code-health", "Alias for health-code", "health-code");
1607
+ bindProductCommand("map", "Build navigable software map from project layout", "map");
1608
+ bindProductCommand("decisions", "Load ADR files and decision ledger", "decisions");
1609
+ bindProductCommand("forensic", "Read-only forensic analysis (git + ledgers + brain)", "forensic");
1610
+ bindProductCommand("twin", "Software digital twin snapshot", "twin");
1611
+ bindProductCommand("eval-lab", "Run evaluation lab fixture checks", "eval-lab");
1612
+ bindProductCommand("self-check", "Self-diagnosis of AgentDoctor installation", "self-check");
1613
+ bindProductCommand("infra", "Detect Docker/K8s/Terraform/CI artifacts", "infra");
1614
+ bindProductCommand("incident", "Build incident timeline hypotheses", "incident");
1615
+ bindProductCommand("security-doctor", "Security heuristics: secrets, auth markers, dangerous patterns", "security-doctor");
1616
+ bindProductCommand("test-brain", "Test Brain: test-impact plus graph file↔test mapping", "test-brain");
1617
+ bindProductCommand("privacy-doctor", "PII-ish pattern scan (not legal compliance)", "privacy-doctor");
1618
+ bindProductCommand("tech-debt", "Technical debt roadmap (TODO/FIXME, architecture, tests)", "tech-debt");
1619
+ bindProductCommand("features", "Feature intelligence (flows + API links)", "features");
1620
+ bindProductCommand("evolution", "Software evolution timeline from git + ledger", "evolution");
1621
+ bindProductCommand("org", "Load organization model (.agentdoctor/org)", "org");
1622
+ program
1623
+ .command("memory")
1624
+ .description("Query institutional memory (brain + ledgers)")
1625
+ .argument("<query>", "Memory query")
1626
+ .argument("[path]", "Repository path")
1627
+ .option("--json", "Emit JSON report", false)
1628
+ .action(async (query, pathArg, _options, command) => {
1629
+ const options = command.optsWithGlobals();
1630
+ process.exitCode = await runProductCommand({
1631
+ action: "memory",
1632
+ query,
1633
+ root: resolveTargetArgument(pathArg),
1634
+ json: Boolean(options.json),
1635
+ });
1636
+ });
1637
+ program
1638
+ .command("search")
1639
+ .description("Search symbols and concepts (brain + bounded file scan)")
1640
+ .argument("<query>", "Search query")
1641
+ .argument("[path]", "Repository path")
1642
+ .option("--json", "Emit JSON report", false)
1643
+ .action(async (query, pathArg, _options, command) => {
1644
+ const options = command.optsWithGlobals();
1645
+ process.exitCode = await runProductCommand({
1646
+ action: "search",
1647
+ query,
1648
+ root: resolveTargetArgument(pathArg),
1649
+ json: Boolean(options.json),
1650
+ });
1651
+ });
1652
+ program
1653
+ .command("role-agent")
1654
+ .description("Run the coding loop with a specialized agent role")
1655
+ .argument("[path]", "Repository path")
1656
+ .requiredOption("--role <role>", "Agent role (planner, coder, tester, reviewer, security, …)")
1657
+ .requiredOption("--goal <text>", "Goal for the role agent")
1658
+ .option("--approve", "Record human approval for writes", false)
1659
+ .option("--apply", "Apply changes (requires --approve)", false)
1660
+ .option("--json", "Emit JSON", false)
1661
+ .action(async (pathArg, options) => {
1662
+ process.exitCode = await runProductCommand({
1663
+ action: "role-agent",
1664
+ root: resolveTargetArgument(pathArg),
1665
+ role: options.role,
1666
+ goal: options.goal,
1667
+ approve: Boolean(options.approve),
1668
+ apply: Boolean(options.apply),
1669
+ json: Boolean(options.json),
1670
+ });
1671
+ });
1672
+ program
1673
+ .command("what-if")
1674
+ .description("Graph-backed change impact for a file or symbol")
1675
+ .argument("<target>", "File path or symbol")
1676
+ .argument("[path]", "Repository path")
1677
+ .option("--json", "Emit JSON report", false)
1678
+ .action(async (target, pathArg, _options, command) => {
1679
+ const options = command.optsWithGlobals();
1680
+ process.exitCode = await runProductCommand({
1681
+ action: "what-if",
1682
+ root: resolveTargetArgument(pathArg),
1683
+ target,
1684
+ json: Boolean(options.json),
1685
+ });
1686
+ });
1546
1687
  program
1547
1688
  .command("doctor")
1548
1689
  .description("Check AgentDoctor installation health")
@@ -1,5 +1,5 @@
1
1
  import type { AgentId } from "./types/index.js";
2
- export declare const PACKAGE_VERSION = "2.1.0";
2
+ export declare const PACKAGE_VERSION = "3.0.0";
3
3
  export declare const DEFAULT_MAX_FILE_SIZE_BYTES: number;
4
4
  /** Directories skipped during normal discovery (unless a rule needs them later). */
5
5
  export declare const DEFAULT_IGNORE_DIRECTORIES: Set<string>;
package/dist/constants.js CHANGED
@@ -1,4 +1,4 @@
1
- export const PACKAGE_VERSION = "2.1.0";
1
+ export const PACKAGE_VERSION = "3.0.0";
2
2
  export const DEFAULT_MAX_FILE_SIZE_BYTES = 2 * 1024 * 1024; // 2 MiB
3
3
  /** Directories skipped during normal discovery (unless a rule needs them later). */
4
4
  export const DEFAULT_IGNORE_DIRECTORIES = new Set([
@@ -24,6 +24,25 @@ import { sanitizeForOutput } from "../utils/path.js";
24
24
  import { createModelProvider, loadAiConfig } from "../ai/index.js";
25
25
  import { ChatService } from "../agent/chat/service.js";
26
26
  import { formatChatResponseForCli } from "../agent/chat/response.js";
27
+ import { buildProjectDna } from "../product/dna/build.js";
28
+ import { buildSoftwareMap } from "../product/map/software-map.js";
29
+ import { buildSoftwareDigitalTwin } from "../product/twin/store.js";
30
+ import { analyzeCodeHealth } from "../product/health/code-health.js";
31
+ import { traceRequirements } from "../product/requirements/trace.js";
32
+ import { analyzeApiSurface } from "../product/api/doctor.js";
33
+ import { analyzeDatabaseSchema } from "../product/database/doctor.js";
34
+ import { analyzeEvents } from "../product/events/doctor.js";
35
+ import { analyzeDependencies } from "../product/deps/analyze.js";
36
+ import { analyzeSecuritySurface } from "../product/security/doctor.js";
37
+ import { searchSymbolsAndConcepts } from "../product/search/software-search.js";
38
+ import { analyzeWhatIf } from "../product/whatif/engine.js";
39
+ import { runForensicAnalysis } from "../product/forensic/mode.js";
40
+ import { buildIncidentHypotheses } from "../product/ops/incident.js";
41
+ import { analyzeInfra } from "../product/ops/infra.js";
42
+ import { analyzeFeatureIntelligence } from "../product/features/intelligence.js";
43
+ import { buildSoftwareEvolutionTimeline } from "../product/evolution/timeline.js";
44
+ import { queryMemory } from "../product/memory/institutional.js";
45
+ import { loadDecisionLedger } from "../product/decisions/ledger.js";
27
46
  function safeJsonError(error) {
28
47
  const raw = error instanceof Error ? error.message : String(error);
29
48
  const { text } = redactSecrets(sanitizeForOutput(raw));
@@ -99,40 +118,104 @@ function htmlPage() {
99
118
  </header>
100
119
  <main>
101
120
  <nav aria-label="Views" style="display:flex;flex-wrap:wrap;gap:0.75rem;font-size:0.9rem">
102
- <a href="#overview">Overview</a>
103
- <a href="#scan">Safety scan</a>
104
- <a href="#platform">Platform</a>
105
- <a href="#brain">Brain</a>
121
+ <a href="#home">Home</a>
122
+ <a href="#dna">DNA</a>
106
123
  <a href="#graph">Graph</a>
107
- <a href="#knowledge">Knowledge</a>
108
- <a href="#chat">Project Chat</a>
109
- <a href="#meta">Audit / baselines</a>
124
+ <a href="#chat">Chat</a>
125
+ <a href="#security">Security</a>
126
+ <a href="#twin">Twin</a>
127
+ <a href="#requirements">Requirements</a>
128
+ <a href="#map">Map</a>
129
+ <a href="#features">Features</a>
130
+ <a href="#deps">Deps</a>
131
+ <a href="#search">Search</a>
132
+ <a href="#whatif">What-if</a>
133
+ <a href="#forensic">Forensic</a>
134
+ <a href="#incident">Incident</a>
135
+ <a href="#infra">Infra</a>
136
+ <a href="#evolution">Evolution</a>
137
+ <a href="#memory">Memory</a>
138
+ <a href="#decisions">Decisions</a>
139
+ <a href="#health">Health</a>
140
+ <a href="#agent">Doctors</a>
110
141
  </nav>
111
- <section id="overview">
112
- <h2>Overview</h2>
142
+ <section id="home" data-route="home">
143
+ <h2>Home</h2>
113
144
  <pre id="status" class="muted">Loading…</pre>
114
145
  </section>
115
- <section id="scan">
116
- <h2>Safety scan</h2>
117
- <pre id="scanBody" class="muted">Loading…</pre>
146
+ <section id="dna" data-route="dna" hidden>
147
+ <h2>Project DNA</h2>
148
+ <pre id="dnaBody" class="muted">Loading…</pre>
118
149
  </section>
119
- <section id="platform">
120
- <h2>Platform snapshot (incl. test-impact)</h2>
121
- <pre id="platformBody" class="muted">Loading…</pre>
150
+ <section id="graph" data-route="graph" hidden>
151
+ <h2>Graph / Git / C4</h2>
152
+ <pre id="graphBody" class="muted">Loading…</pre>
122
153
  </section>
123
- <section id="brain">
124
- <h2>Project Brain</h2>
125
- <pre id="brainBody" class="muted">Loading…</pre>
154
+ <section id="security" data-route="security" hidden>
155
+ <h2>Security doctor</h2>
156
+ <pre id="securityBody" class="muted">Loading…</pre>
126
157
  </section>
127
- <section id="graph">
128
- <h2>Intelligence graph / git / C4</h2>
129
- <pre id="graphBody" class="muted">Loading…</pre>
158
+ <section id="twin" data-route="twin" hidden>
159
+ <h2>Digital twin</h2>
160
+ <pre id="twinBody" class="muted">Loading…</pre>
161
+ </section>
162
+ <section id="requirements" data-route="requirements" hidden>
163
+ <h2>Requirements trace</h2>
164
+ <pre id="requirementsBody" class="muted">Loading…</pre>
165
+ </section>
166
+ <section id="map" data-route="map" hidden>
167
+ <h2>Software map</h2>
168
+ <pre id="mapBody" class="muted">Loading…</pre>
169
+ </section>
170
+ <section id="features" data-route="features" hidden>
171
+ <h2>Feature intelligence</h2>
172
+ <pre id="featuresBody" class="muted">Loading…</pre>
173
+ </section>
174
+ <section id="deps" data-route="deps" hidden>
175
+ <h2>Dependencies</h2>
176
+ <pre id="depsBody" class="muted">Loading…</pre>
177
+ </section>
178
+ <section id="search" data-route="search" hidden>
179
+ <h2>Software search</h2>
180
+ <pre id="searchBody" class="muted">Loading…</pre>
181
+ </section>
182
+ <section id="whatif" data-route="whatif" hidden>
183
+ <h2>What-if</h2>
184
+ <pre id="whatifBody" class="muted">Loading…</pre>
185
+ </section>
186
+ <section id="forensic" data-route="forensic" hidden>
187
+ <h2>Forensic</h2>
188
+ <pre id="forensicBody" class="muted">Loading…</pre>
130
189
  </section>
131
- <section id="knowledge">
132
- <h2>Governed knowledge</h2>
133
- <pre id="knowledgeBody" class="muted">Loading…</pre>
190
+ <section id="incident" data-route="incident" hidden>
191
+ <h2>Incident</h2>
192
+ <pre id="incidentBody" class="muted">Loading…</pre>
134
193
  </section>
135
- <section id="chat">
194
+ <section id="infra" data-route="infra" hidden>
195
+ <h2>Infra</h2>
196
+ <pre id="infraBody" class="muted">Loading…</pre>
197
+ </section>
198
+ <section id="evolution" data-route="evolution" hidden>
199
+ <h2>Evolution</h2>
200
+ <pre id="evolutionBody" class="muted">Loading…</pre>
201
+ </section>
202
+ <section id="memory" data-route="memory" hidden>
203
+ <h2>Institutional memory</h2>
204
+ <pre id="memoryBody" class="muted">Loading…</pre>
205
+ </section>
206
+ <section id="decisions" data-route="decisions" hidden>
207
+ <h2>Decisions</h2>
208
+ <pre id="decisionsBody" class="muted">Loading…</pre>
209
+ </section>
210
+ <section id="health" data-route="health" hidden>
211
+ <h2>Code health</h2>
212
+ <pre id="healthBody" class="muted">Loading…</pre>
213
+ </section>
214
+ <section id="agent" data-route="agent" hidden>
215
+ <h2>Product doctors (API, DB, events)</h2>
216
+ <pre id="agentBody" class="muted">Loading…</pre>
217
+ </section>
218
+ <section id="chat" data-route="chat" hidden>
136
219
  <h2>Project Chat</h2>
137
220
  <p class="muted">Ask about this repository. Answers use evidence + truth labels. No file writes from this panel.</p>
138
221
  <div style="display:grid;grid-template-columns:1.4fr 1fr;gap:1rem">
@@ -147,30 +230,70 @@ function htmlPage() {
147
230
  </div>
148
231
  </div>
149
232
  </section>
150
- <section id="meta">
151
- <h2>Safe Fix audit / baselines / sessions</h2>
152
- <pre id="metaBody" class="muted">Loading…</pre>
153
- </section>
154
233
  </main>
155
234
  <script>
235
+ const routes = ['home','dna','graph','chat','security','twin','requirements','map','features','deps','search','whatif','forensic','incident','infra','evolution','memory','decisions','health','agent'];
236
+ function showRoute(name) {
237
+ const r = routes.includes(name) ? name : 'home';
238
+ for (const el of document.querySelectorAll('[data-route]')) {
239
+ el.hidden = el.getAttribute('data-route') !== r;
240
+ }
241
+ location.hash = r;
242
+ }
243
+ window.addEventListener('hashchange', () => showRoute((location.hash || '#home').slice(1)));
244
+ showRoute((location.hash || '#home').slice(1));
245
+
246
+ async function loadSection(route) {
247
+ const map = {
248
+ dna: [['dnaBody','/api/dna']],
249
+ graph: [['graphBody','/api/v2/graph']],
250
+ security: [['securityBody','/api/security']],
251
+ twin: [['twinBody','/api/twin']],
252
+ requirements: [['requirementsBody','/api/requirements']],
253
+ map: [['mapBody','/api/map']],
254
+ features: [['featuresBody','/api/features']],
255
+ deps: [['depsBody','/api/deps']],
256
+ search: [['searchBody','/api/search?q=main']],
257
+ whatif: [['whatifBody','/api/what-if?target=src']],
258
+ forensic: [['forensicBody','/api/forensic']],
259
+ incident: [['incidentBody','/api/incident']],
260
+ infra: [['infraBody','/api/infra']],
261
+ evolution: [['evolutionBody','/api/evolution']],
262
+ memory: [['memoryBody','/api/memory?q=change']],
263
+ decisions: [['decisionsBody','/api/decisions']],
264
+ health: [['healthBody','/api/health']],
265
+ agent: [['agentBody','/api/api-doctor']],
266
+ };
267
+ if (route === 'home') {
268
+ const [status, scan, brain, platform] = await Promise.all([
269
+ fetch('/api/status').then(r => r.json()),
270
+ fetch('/api/scan').then(r => r.json()),
271
+ fetch('/api/brain').then(r => r.json()),
272
+ fetch('/api/platform').then(r => r.json()),
273
+ ]);
274
+ document.getElementById('status').textContent = JSON.stringify({ status, scan, brain, platform }, null, 2);
275
+ return;
276
+ }
277
+ if (route === 'agent') {
278
+ const [api, db, events] = await Promise.all([
279
+ fetch('/api/api-doctor').then(r => r.json()),
280
+ fetch('/api/database').then(r => r.json()),
281
+ fetch('/api/events').then(r => r.json()),
282
+ ]);
283
+ document.getElementById('agentBody').textContent = JSON.stringify({ api, db, events }, null, 2);
284
+ return;
285
+ }
286
+ const loaders = map[route] || [];
287
+ for (const [elId, url] of loaders) {
288
+ const data = await fetch(url).then(r => r.json());
289
+ document.getElementById(elId).textContent = JSON.stringify(data, null, 2);
290
+ }
291
+ }
156
292
  async function load() {
157
- const [status, scan, brain, meta, platform, graph, knowledge] = await Promise.all([
158
- fetch('/api/status').then(r => r.json()),
159
- fetch('/api/scan').then(r => r.json()),
160
- fetch('/api/brain').then(r => r.json()),
161
- fetch('/api/meta').then(r => r.json()),
162
- fetch('/api/platform').then(r => r.json()),
163
- fetch('/api/v2/graph').then(r => r.json()),
164
- fetch('/api/v2/knowledge').then(r => r.json()),
165
- ]);
166
- document.getElementById('status').textContent = JSON.stringify(status, null, 2);
167
- document.getElementById('scanBody').textContent = JSON.stringify(scan, null, 2);
168
- document.getElementById('brainBody').textContent = JSON.stringify(brain, null, 2);
169
- document.getElementById('metaBody').textContent = JSON.stringify(meta, null, 2);
170
- document.getElementById('platformBody').textContent = JSON.stringify(platform, null, 2);
171
- document.getElementById('graphBody').textContent = JSON.stringify(graph, null, 2);
172
- document.getElementById('knowledgeBody').textContent = JSON.stringify(knowledge, null, 2);
293
+ const route = (location.hash || '#home').slice(1) || 'home';
294
+ await loadSection(route);
173
295
  }
296
+ window.addEventListener('hashchange', () => load().catch(err => console.error(err)));
174
297
  load().catch(err => {
175
298
  document.getElementById('status').textContent = String(err);
176
299
  });
@@ -246,14 +369,6 @@ export async function startDashboardServer(options) {
246
369
  return;
247
370
  }
248
371
  const provider = options.chatProvider ?? createModelProvider(loadAiConfig());
249
- if (provider.id === "none") {
250
- sendJson(res, 503, {
251
- error: "provider-none",
252
- message: "AI chat is not configured. Set AGENTDOCTOR_AI_PROVIDER to mock or an OpenAI-compatible provider. Silent mock fallback is disabled.",
253
- status: "provider-none",
254
- });
255
- return;
256
- }
257
372
  const chat = new ChatService({
258
373
  root,
259
374
  provider,
@@ -451,6 +566,93 @@ export async function startDashboardServer(options) {
451
566
  });
452
567
  return;
453
568
  }
569
+ if (url.pathname === "/api/dna") {
570
+ sendJson(res, 200, await buildProjectDna(root));
571
+ return;
572
+ }
573
+ if (url.pathname === "/api/map") {
574
+ sendJson(res, 200, await buildSoftwareMap(root));
575
+ return;
576
+ }
577
+ if (url.pathname === "/api/twin") {
578
+ sendJson(res, 200, await buildSoftwareDigitalTwin(root));
579
+ return;
580
+ }
581
+ if (url.pathname === "/api/health-code") {
582
+ sendJson(res, 200, await analyzeCodeHealth(root));
583
+ return;
584
+ }
585
+ if (url.pathname === "/api/requirements") {
586
+ sendJson(res, 200, await traceRequirements(root));
587
+ return;
588
+ }
589
+ if (url.pathname === "/api/api-doctor") {
590
+ sendJson(res, 200, await analyzeApiSurface(root));
591
+ return;
592
+ }
593
+ if (url.pathname === "/api/database") {
594
+ sendJson(res, 200, await analyzeDatabaseSchema(root));
595
+ return;
596
+ }
597
+ if (url.pathname === "/api/events") {
598
+ sendJson(res, 200, await analyzeEvents(root));
599
+ return;
600
+ }
601
+ if (url.pathname === "/api/deps") {
602
+ sendJson(res, 200, await analyzeDependencies(root));
603
+ return;
604
+ }
605
+ if (url.pathname === "/api/security") {
606
+ sendJson(res, 200, await analyzeSecuritySurface(root));
607
+ return;
608
+ }
609
+ if (url.pathname === "/api/search") {
610
+ const q = url.searchParams.get("q") ?? "";
611
+ sendJson(res, 200, await searchSymbolsAndConcepts(root, q));
612
+ return;
613
+ }
614
+ if (url.pathname === "/api/what-if") {
615
+ const target = url.searchParams.get("target") ?? "";
616
+ if (!target.trim()) {
617
+ sendJson(res, 400, { error: "target query param required" });
618
+ return;
619
+ }
620
+ sendJson(res, 200, await analyzeWhatIf(root, target));
621
+ return;
622
+ }
623
+ if (url.pathname === "/api/forensic") {
624
+ sendJson(res, 200, await runForensicAnalysis(root));
625
+ return;
626
+ }
627
+ if (url.pathname === "/api/incident") {
628
+ sendJson(res, 200, await buildIncidentHypotheses(root));
629
+ return;
630
+ }
631
+ if (url.pathname === "/api/infra") {
632
+ sendJson(res, 200, await analyzeInfra(root));
633
+ return;
634
+ }
635
+ if (url.pathname === "/api/features") {
636
+ sendJson(res, 200, await analyzeFeatureIntelligence(root));
637
+ return;
638
+ }
639
+ if (url.pathname === "/api/evolution") {
640
+ sendJson(res, 200, await buildSoftwareEvolutionTimeline(root));
641
+ return;
642
+ }
643
+ if (url.pathname === "/api/memory") {
644
+ const q = url.searchParams.get("q") ?? "";
645
+ sendJson(res, 200, await queryMemory(root, q));
646
+ return;
647
+ }
648
+ if (url.pathname === "/api/decisions") {
649
+ sendJson(res, 200, await loadDecisionLedger(root));
650
+ return;
651
+ }
652
+ if (url.pathname === "/api/health") {
653
+ sendJson(res, 200, await analyzeCodeHealth(root));
654
+ return;
655
+ }
454
656
  if (url.pathname === "/api/v2/projects" || url.pathname === "/api/v2/workspaces") {
455
657
  sendJson(res, 200, {
456
658
  mode: "local-single-repo",
package/dist/index.d.ts CHANGED
@@ -62,4 +62,8 @@ export type { ChatTurnResponse, ChatServiceOptions, TruthClaim, ProjectChatSumma
62
62
  export { listAgentToolSpecs, getToolSpec, riskForTool, executeAgentTool, isReadTool, newToolCall, evaluateApproval, formatApprovalPrompt, buildAgentPlan, formatAgentPlan, approvePlan, runCodingLoop, verifyAgentWork, formatVerificationReport, } from "./agent/index.js";
63
63
  export type { AgentToolName, AgentToolSpec, AgentToolCall, AgentToolResult, AgentRiskLevel, ApprovalRequest, ApprovalResult, ApprovalDecision, AgentPlan, AgentPlanStep, CodingLoopOptions, CodingLoopResult, AgentVerificationReport, VerificationCheck, } from "./agent/index.js";
64
64
  export { getModeProfile, defaultStudentMode, parseAgentMode, modeAllowsMutation, modeBlocksToolCategory, StudentService, } from "./agent/index.js";
65
+ export { traceRequirements, analyzeApiSurface, analyzeDatabaseSchema, analyzeEvents, analyzeDependencies, analyzeCodeHealth, buildSoftwareMap, appendChangeLedgerEntry, readChangeLedger, analyzeWhatIf, loadDecisionLedger, runForensicAnalysis, assertForensicReadOnly, buildSoftwareDigitalTwin, runEvalLab, diagnoseAgentDoctorSelf, analyzeInfra, buildIncidentHypotheses, enrichGraphWithLanguageAdapters, analyzeSecuritySurface, analyzePrivacySurface, searchSymbolsAndConcepts, buildTechnicalDebtRoadmap, loadOrganizationModel, saveOrganizationModel, linkProjectToOrgModel, analyzeFeatureIntelligence, buildSoftwareEvolutionTimeline, queryMemory, evaluateApprovalRecord, formatApprovalRecordSummary, issueApprovalGrant, consumeApprovalGrant, hashPlanPayload, hashFileWritePlan, minProductTruth, truthLabelDescription, } from "./product/index.js";
66
+ export type { TruthLabel as ProductTruthLabel, ProductEvidence, RequirementsTraceReport, ApiDoctorReport, DatabaseDoctorReport, EventsDoctorReport, DependencyAnalysisReport, CodeHealthReport, SoftwareMap, ChangeLedgerEntry, WhatIfReport, DecisionRecord, ForensicAnalysisReport, SoftwareDigitalTwin, EvalLabReport, SelfDiagnoseReport, InfraReport, IncidentReport, LanguageGraphEnrichmentStats, SecurityDoctorReport, PrivacyDoctorReport, SoftwareSearchReport, TechnicalDebtRoadmap, OrganizationModel, FeatureIntelligenceReport, SoftwareEvolutionReport, InstitutionalMemoryQueryResult, ApprovalRecord, } from "./product/index.js";
67
+ export { rolePrompt, roleAllowedTools, runRoleAgent } from "./agent/roles.js";
68
+ export type { AgentRole, RoleAgentOptions } from "./agent/roles.js";
65
69
  export type { AgentMode, ModeProfile, StudentDocSection, BuildWithMeResult, } from "./agent/index.js";
package/dist/index.js CHANGED
@@ -44,3 +44,5 @@ export { ChatService, createChatService, ChatMemory, CHAT_PROVIDER_NONE_MESSAGE,
44
44
  /** AgentDoctor 2.1 agent tools + plan (M3). */
45
45
  export { listAgentToolSpecs, getToolSpec, riskForTool, executeAgentTool, isReadTool, newToolCall, evaluateApproval, formatApprovalPrompt, buildAgentPlan, formatAgentPlan, approvePlan, runCodingLoop, verifyAgentWork, formatVerificationReport, } from "./agent/index.js";
46
46
  export { getModeProfile, defaultStudentMode, parseAgentMode, modeAllowsMutation, modeBlocksToolCategory, StudentService, } from "./agent/index.js";
47
+ export { traceRequirements, analyzeApiSurface, analyzeDatabaseSchema, analyzeEvents, analyzeDependencies, analyzeCodeHealth, buildSoftwareMap, appendChangeLedgerEntry, readChangeLedger, analyzeWhatIf, loadDecisionLedger, runForensicAnalysis, assertForensicReadOnly, buildSoftwareDigitalTwin, runEvalLab, diagnoseAgentDoctorSelf, analyzeInfra, buildIncidentHypotheses, enrichGraphWithLanguageAdapters, analyzeSecuritySurface, analyzePrivacySurface, searchSymbolsAndConcepts, buildTechnicalDebtRoadmap, loadOrganizationModel, saveOrganizationModel, linkProjectToOrgModel, analyzeFeatureIntelligence, buildSoftwareEvolutionTimeline, queryMemory, evaluateApprovalRecord, formatApprovalRecordSummary, issueApprovalGrant, consumeApprovalGrant, hashPlanPayload, hashFileWritePlan, minProductTruth, truthLabelDescription, } from "./product/index.js";
48
+ export { rolePrompt, roleAllowedTools, runRoleAgent } from "./agent/roles.js";