@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.
Files changed (267) hide show
  1. package/CHANGELOG.md +105 -1
  2. package/README.md +64 -31
  3. package/dist/agents/inspect.js +58 -51
  4. package/dist/cli/commands/brain-mcp.d.ts +9 -0
  5. package/dist/cli/commands/brain-mcp.js +38 -0
  6. package/dist/cli/commands/explain.js +1 -1
  7. package/dist/cli/commands/fix.js +22 -6
  8. package/dist/cli/commands/scan.d.ts +5 -0
  9. package/dist/cli/commands/scan.js +25 -6
  10. package/dist/cli/commands/verify.d.ts +6 -0
  11. package/dist/cli/commands/verify.js +25 -11
  12. package/dist/cli/program.js +61 -7
  13. package/dist/constants.d.ts +1 -1
  14. package/dist/constants.js +1 -1
  15. package/dist/core/fix/apply.d.ts +5 -1
  16. package/dist/core/fix/apply.js +34 -14
  17. package/dist/core/fix/plan.d.ts +1 -1
  18. package/dist/core/fix/plan.js +110 -3
  19. package/dist/core/fix/render.d.ts +2 -0
  20. package/dist/core/fix/render.js +57 -9
  21. package/dist/core/fix/run.js +5 -1
  22. package/dist/core/fix/types.d.ts +1 -1
  23. package/dist/core/fix/types.js +5 -1
  24. package/dist/core/fix/writers/claude-settings.d.ts +16 -0
  25. package/dist/core/fix/writers/claude-settings.js +100 -0
  26. package/dist/core/fix/writers/codex-config.d.ts +22 -0
  27. package/dist/core/fix/writers/codex-config.js +183 -0
  28. package/dist/core/fix/writers/cursorignore.js +2 -8
  29. package/dist/core/path-resolution/index.d.ts +5 -0
  30. package/dist/core/path-resolution/index.js +5 -0
  31. package/dist/core/path-resolution/prepare.d.ts +33 -0
  32. package/dist/core/path-resolution/prepare.js +98 -0
  33. package/dist/core/policy/evaluate.d.ts +44 -0
  34. package/dist/core/policy/evaluate.js +120 -0
  35. package/dist/core/rules/claude-deny.d.ts +8 -0
  36. package/dist/core/rules/claude-deny.js +39 -0
  37. package/dist/core/rules/codex-deny.d.ts +5 -0
  38. package/dist/core/rules/codex-deny.js +42 -0
  39. package/dist/core/rules/context/generated-directory.js +43 -9
  40. package/dist/core/rules/context/large-log-file.js +27 -10
  41. package/dist/core/rules/ignore.js +2 -5
  42. package/dist/core/rules/instructions/missing-path-reference.d.ts +5 -1
  43. package/dist/core/rules/instructions/missing-path-reference.js +24 -6
  44. package/dist/core/rules/path-kind.d.ts +15 -2
  45. package/dist/core/rules/path-kind.js +113 -10
  46. package/dist/core/rules/security/env-file-exposure.js +9 -24
  47. package/dist/core/rules/text-cache.js +46 -40
  48. package/dist/core/understanding/architecture/index.d.ts +4 -0
  49. package/dist/core/understanding/architecture/index.js +3 -0
  50. package/dist/core/understanding/architecture/infer.d.ts +6 -0
  51. package/dist/core/understanding/architecture/infer.js +39 -0
  52. package/dist/core/understanding/architecture/models.d.ts +23 -0
  53. package/dist/core/understanding/architecture/models.js +127 -0
  54. package/dist/core/understanding/architecture/patterns/distribution.d.ts +2 -0
  55. package/dist/core/understanding/architecture/patterns/distribution.js +115 -0
  56. package/dist/core/understanding/architecture/patterns/index.d.ts +2 -0
  57. package/dist/core/understanding/architecture/patterns/index.js +8 -0
  58. package/dist/core/understanding/architecture/patterns/layered.d.ts +2 -0
  59. package/dist/core/understanding/architecture/patterns/layered.js +279 -0
  60. package/dist/core/understanding/architecture/patterns/structural.d.ts +2 -0
  61. package/dist/core/understanding/architecture/patterns/structural.js +197 -0
  62. package/dist/core/understanding/architecture/rules.d.ts +4 -0
  63. package/dist/core/understanding/architecture/rules.js +6 -0
  64. package/dist/core/understanding/architecture/types.d.ts +52 -0
  65. package/dist/core/understanding/architecture/types.js +1 -0
  66. package/dist/core/understanding/brain/build.d.ts +13 -0
  67. package/dist/core/understanding/brain/build.js +158 -0
  68. package/dist/core/understanding/brain/claims/index.d.ts +3 -0
  69. package/dist/core/understanding/brain/claims/index.js +2 -0
  70. package/dist/core/understanding/brain/claims/lifecycle.d.ts +16 -0
  71. package/dist/core/understanding/brain/claims/lifecycle.js +78 -0
  72. package/dist/core/understanding/brain/claims/types.d.ts +32 -0
  73. package/dist/core/understanding/brain/claims/types.js +25 -0
  74. package/dist/core/understanding/brain/components/index.d.ts +17 -0
  75. package/dist/core/understanding/brain/components/index.js +97 -0
  76. package/dist/core/understanding/brain/components/types.d.ts +16 -0
  77. package/dist/core/understanding/brain/components/types.js +8 -0
  78. package/dist/core/understanding/brain/confidence.d.ts +19 -0
  79. package/dist/core/understanding/brain/confidence.js +39 -0
  80. package/dist/core/understanding/brain/contract.d.ts +17 -0
  81. package/dist/core/understanding/brain/contract.js +100 -0
  82. package/dist/core/understanding/brain/contradictions/index.d.ts +12 -0
  83. package/dist/core/understanding/brain/contradictions/index.js +57 -0
  84. package/dist/core/understanding/brain/contradictions/types.d.ts +12 -0
  85. package/dist/core/understanding/brain/contradictions/types.js +8 -0
  86. package/dist/core/understanding/brain/delta.d.ts +25 -0
  87. package/dist/core/understanding/brain/delta.js +116 -0
  88. package/dist/core/understanding/brain/evidence/index.d.ts +3 -0
  89. package/dist/core/understanding/brain/evidence/index.js +2 -0
  90. package/dist/core/understanding/brain/evidence/redact.d.ts +4 -0
  91. package/dist/core/understanding/brain/evidence/redact.js +36 -0
  92. package/dist/core/understanding/brain/evidence/types.d.ts +34 -0
  93. package/dist/core/understanding/brain/evidence/types.js +35 -0
  94. package/dist/core/understanding/brain/explain.d.ts +17 -0
  95. package/dist/core/understanding/brain/explain.js +33 -0
  96. package/dist/core/understanding/brain/index.d.ts +28 -0
  97. package/dist/core/understanding/brain/index.js +16 -0
  98. package/dist/core/understanding/brain/migrate.d.ts +21 -0
  99. package/dist/core/understanding/brain/migrate.js +47 -0
  100. package/dist/core/understanding/brain/query.d.ts +60 -0
  101. package/dist/core/understanding/brain/query.js +92 -0
  102. package/dist/core/understanding/brain/security.d.ts +3 -0
  103. package/dist/core/understanding/brain/security.js +43 -0
  104. package/dist/core/understanding/brain/storage/index.d.ts +2 -0
  105. package/dist/core/understanding/brain/storage/index.js +1 -0
  106. package/dist/core/understanding/brain/storage/store.d.ts +53 -0
  107. package/dist/core/understanding/brain/storage/store.js +305 -0
  108. package/dist/core/understanding/brain/trace.d.ts +24 -0
  109. package/dist/core/understanding/brain/trace.js +207 -0
  110. package/dist/core/understanding/brain/types.d.ts +32 -0
  111. package/dist/core/understanding/brain/types.js +8 -0
  112. package/dist/core/understanding/brain/version.d.ts +13 -0
  113. package/dist/core/understanding/brain/version.js +7 -0
  114. package/dist/core/understanding/delta/compare.d.ts +26 -0
  115. package/dist/core/understanding/delta/compare.js +74 -0
  116. package/dist/core/understanding/delta/index.d.ts +2 -0
  117. package/dist/core/understanding/delta/index.js +1 -0
  118. package/dist/core/understanding/dependencies/discover.d.ts +7 -0
  119. package/dist/core/understanding/dependencies/discover.js +550 -0
  120. package/dist/core/understanding/dependencies/extract.d.ts +10 -0
  121. package/dist/core/understanding/dependencies/extract.js +189 -0
  122. package/dist/core/understanding/dependencies/index.d.ts +4 -0
  123. package/dist/core/understanding/dependencies/index.js +3 -0
  124. package/dist/core/understanding/dependencies/models.d.ts +12 -0
  125. package/dist/core/understanding/dependencies/models.js +125 -0
  126. package/dist/core/understanding/dependencies/types.d.ts +27 -0
  127. package/dist/core/understanding/dependencies/types.js +1 -0
  128. package/dist/core/understanding/domain/discover.d.ts +14 -0
  129. package/dist/core/understanding/domain/discover.js +90 -0
  130. package/dist/core/understanding/domain/index.d.ts +2 -0
  131. package/dist/core/understanding/domain/index.js +1 -0
  132. package/dist/core/understanding/entrypoints/discover.d.ts +6 -0
  133. package/dist/core/understanding/entrypoints/discover.js +62 -0
  134. package/dist/core/understanding/entrypoints/extract.d.ts +19 -0
  135. package/dist/core/understanding/entrypoints/extract.js +43 -0
  136. package/dist/core/understanding/entrypoints/index.d.ts +4 -0
  137. package/dist/core/understanding/entrypoints/index.js +3 -0
  138. package/dist/core/understanding/entrypoints/models.d.ts +26 -0
  139. package/dist/core/understanding/entrypoints/models.js +216 -0
  140. package/dist/core/understanding/entrypoints/types.d.ts +20 -0
  141. package/dist/core/understanding/entrypoints/types.js +1 -0
  142. package/dist/core/understanding/index.d.ts +32 -0
  143. package/dist/core/understanding/index.js +18 -0
  144. package/dist/core/understanding/mind/build.d.ts +16 -0
  145. package/dist/core/understanding/mind/build.js +134 -0
  146. package/dist/core/understanding/mind/index.d.ts +6 -0
  147. package/dist/core/understanding/mind/index.js +3 -0
  148. package/dist/core/understanding/mind/query.d.ts +33 -0
  149. package/dist/core/understanding/mind/query.js +39 -0
  150. package/dist/core/understanding/mind/types.d.ts +24 -0
  151. package/dist/core/understanding/mind/types.js +7 -0
  152. package/dist/core/understanding/model/builder.d.ts +9 -0
  153. package/dist/core/understanding/model/builder.js +209 -0
  154. package/dist/core/understanding/model/ids.d.ts +7 -0
  155. package/dist/core/understanding/model/ids.js +48 -0
  156. package/dist/core/understanding/model/index.d.ts +7 -0
  157. package/dist/core/understanding/model/index.js +6 -0
  158. package/dist/core/understanding/model/schema.d.ts +12 -0
  159. package/dist/core/understanding/model/schema.js +33 -0
  160. package/dist/core/understanding/model/serializer.d.ts +9 -0
  161. package/dist/core/understanding/model/serializer.js +46 -0
  162. package/dist/core/understanding/model/types.d.ts +110 -0
  163. package/dist/core/understanding/model/types.js +1 -0
  164. package/dist/core/understanding/model/validator.d.ts +5 -0
  165. package/dist/core/understanding/model/validator.js +126 -0
  166. package/dist/core/understanding/model/version.d.ts +9 -0
  167. package/dist/core/understanding/model/version.js +7 -0
  168. package/dist/core/understanding/ownership/discover.d.ts +12 -0
  169. package/dist/core/understanding/ownership/discover.js +242 -0
  170. package/dist/core/understanding/ownership/index.d.ts +2 -0
  171. package/dist/core/understanding/ownership/index.js +1 -0
  172. package/dist/core/understanding/ownership/types.d.ts +23 -0
  173. package/dist/core/understanding/ownership/types.js +1 -0
  174. package/dist/core/understanding/query/engine.d.ts +24 -0
  175. package/dist/core/understanding/query/engine.js +35 -0
  176. package/dist/core/understanding/query/errors.d.ts +13 -0
  177. package/dist/core/understanding/query/errors.js +26 -0
  178. package/dist/core/understanding/query/executor.d.ts +8 -0
  179. package/dist/core/understanding/query/executor.js +34 -0
  180. package/dist/core/understanding/query/index.d.ts +7 -0
  181. package/dist/core/understanding/query/index.js +5 -0
  182. package/dist/core/understanding/query/models.d.ts +102 -0
  183. package/dist/core/understanding/query/models.js +1 -0
  184. package/dist/core/understanding/query/query.d.ts +68 -0
  185. package/dist/core/understanding/query/query.js +145 -0
  186. package/dist/core/understanding/query/registry.d.ts +8 -0
  187. package/dist/core/understanding/query/registry.js +340 -0
  188. package/dist/core/understanding/query/types.d.ts +63 -0
  189. package/dist/core/understanding/query/types.js +1 -0
  190. package/dist/core/understanding/relationships/discover.d.ts +11 -0
  191. package/dist/core/understanding/relationships/discover.js +517 -0
  192. package/dist/core/understanding/relationships/extract.d.ts +14 -0
  193. package/dist/core/understanding/relationships/extract.js +165 -0
  194. package/dist/core/understanding/relationships/index.d.ts +4 -0
  195. package/dist/core/understanding/relationships/index.js +3 -0
  196. package/dist/core/understanding/relationships/models.d.ts +21 -0
  197. package/dist/core/understanding/relationships/models.js +185 -0
  198. package/dist/core/understanding/relationships/types.d.ts +42 -0
  199. package/dist/core/understanding/relationships/types.js +1 -0
  200. package/dist/core/understanding/risks/discover.d.ts +8 -0
  201. package/dist/core/understanding/risks/discover.js +155 -0
  202. package/dist/core/understanding/risks/index.d.ts +2 -0
  203. package/dist/core/understanding/risks/index.js +1 -0
  204. package/dist/core/understanding/risks/types.d.ts +26 -0
  205. package/dist/core/understanding/risks/types.js +1 -0
  206. package/dist/core/understanding/shared/domain-lexicon.d.ts +9 -0
  207. package/dist/core/understanding/shared/domain-lexicon.js +107 -0
  208. package/dist/core/understanding/shared/index.d.ts +2 -0
  209. package/dist/core/understanding/shared/index.js +2 -0
  210. package/dist/core/understanding/shared/tokens.d.ts +7 -0
  211. package/dist/core/understanding/shared/tokens.js +141 -0
  212. package/dist/core/understanding/snapshot/identity.d.ts +24 -0
  213. package/dist/core/understanding/snapshot/identity.js +79 -0
  214. package/dist/core/understanding/snapshot/index.d.ts +2 -0
  215. package/dist/core/understanding/snapshot/index.js +1 -0
  216. package/dist/core/understanding/types/index.d.ts +22 -0
  217. package/dist/core/understanding/types/index.js +1 -0
  218. package/dist/core/understanding/understand/formatter.d.ts +10 -0
  219. package/dist/core/understanding/understand/formatter.js +115 -0
  220. package/dist/core/understanding/understand/index.d.ts +4 -0
  221. package/dist/core/understanding/understand/index.js +3 -0
  222. package/dist/core/understanding/understand/service.d.ts +17 -0
  223. package/dist/core/understanding/understand/service.js +76 -0
  224. package/dist/core/understanding/understand/summary.d.ts +14 -0
  225. package/dist/core/understanding/understand/summary.js +39 -0
  226. package/dist/core/understanding/understand/types.d.ts +31 -0
  227. package/dist/core/understanding/understand/types.js +1 -0
  228. package/dist/discovery/files.js +7 -2
  229. package/dist/discovery/log-like.d.ts +2 -0
  230. package/dist/discovery/log-like.js +7 -0
  231. package/dist/index.d.ts +2 -0
  232. package/dist/index.js +1 -0
  233. package/dist/mcp/brain/compile.d.ts +9 -0
  234. package/dist/mcp/brain/compile.js +42 -0
  235. package/dist/mcp/brain/errors.d.ts +12 -0
  236. package/dist/mcp/brain/errors.js +23 -0
  237. package/dist/mcp/brain/index.d.ts +11 -0
  238. package/dist/mcp/brain/index.js +8 -0
  239. package/dist/mcp/brain/provenance.d.ts +29 -0
  240. package/dist/mcp/brain/provenance.js +59 -0
  241. package/dist/mcp/brain/schemas.d.ts +13 -0
  242. package/dist/mcp/brain/schemas.js +105 -0
  243. package/dist/mcp/brain/security/root.d.ts +6 -0
  244. package/dist/mcp/brain/security/root.js +66 -0
  245. package/dist/mcp/brain/server.d.ts +12 -0
  246. package/dist/mcp/brain/server.js +46 -0
  247. package/dist/mcp/brain/session.d.ts +33 -0
  248. package/dist/mcp/brain/session.js +117 -0
  249. package/dist/mcp/brain/tools/handlers.d.ts +13 -0
  250. package/dist/mcp/brain/tools/handlers.js +483 -0
  251. package/dist/mcp/brain/tools/registry.d.ts +9 -0
  252. package/dist/mcp/brain/tools/registry.js +191 -0
  253. package/dist/reporters/github/annotations.d.ts +8 -0
  254. package/dist/reporters/github/annotations.js +42 -0
  255. package/dist/reporters/github/emit.d.ts +23 -0
  256. package/dist/reporters/github/emit.js +31 -0
  257. package/dist/reporters/github/summary.d.ts +20 -0
  258. package/dist/reporters/github/summary.js +111 -0
  259. package/dist/reporters/terminal/report.d.ts +5 -0
  260. package/dist/reporters/terminal/report.js +68 -5
  261. package/dist/reporters/verify/terminal.d.ts +4 -0
  262. package/dist/reporters/verify/terminal.js +26 -0
  263. package/dist/utils/fs.d.ts +5 -0
  264. package/dist/utils/fs.js +34 -0
  265. package/dist/utils/path.d.ts +5 -0
  266. package/dist/utils/path.js +16 -0
  267. package/package.json +15 -1
@@ -0,0 +1,145 @@
1
+ import { QueryValidationError } from "./errors.js";
2
+ function requireNonEmptyString(value, field) {
3
+ if (typeof value !== "string" || value.trim().length === 0) {
4
+ throw new QueryValidationError(`${field} must be a non-empty string`);
5
+ }
6
+ return value.trim();
7
+ }
8
+ function optionalString(value, field) {
9
+ if (value === undefined) {
10
+ return undefined;
11
+ }
12
+ return requireNonEmptyString(value, field);
13
+ }
14
+ /**
15
+ * Validate and normalize a raw query object into a typed Query.
16
+ */
17
+ export function validateQuery(input) {
18
+ if (!input || typeof input !== "object") {
19
+ throw new QueryValidationError("query must be an object");
20
+ }
21
+ const record = input;
22
+ if (typeof record.type !== "string") {
23
+ throw new QueryValidationError("query.type is required");
24
+ }
25
+ switch (record.type) {
26
+ case "RepositorySummary":
27
+ return { type: "RepositorySummary" };
28
+ case "ListDomains":
29
+ return { type: "ListDomains" };
30
+ case "ListEntrypoints":
31
+ return { type: "ListEntrypoints" };
32
+ case "ListArchitectures":
33
+ return { type: "ListArchitectures" };
34
+ case "ListRelationships":
35
+ return { type: "ListRelationships" };
36
+ case "ListDependencies":
37
+ return { type: "ListDependencies" };
38
+ case "Statistics":
39
+ return { type: "Statistics" };
40
+ case "FindDomain":
41
+ return { type: "FindDomain", name: requireNonEmptyString(record.name, "name") };
42
+ case "FindEntrypoint": {
43
+ const file = optionalString(record.file, "file");
44
+ const framework = optionalString(record.framework, "framework");
45
+ const id = optionalString(record.id, "id");
46
+ if (!file && !framework && !id) {
47
+ throw new QueryValidationError("FindEntrypoint requires file, framework, or id");
48
+ }
49
+ const query = { type: "FindEntrypoint" };
50
+ if (file !== undefined) {
51
+ query.file = file;
52
+ }
53
+ if (framework !== undefined) {
54
+ query.framework = framework;
55
+ }
56
+ if (id !== undefined) {
57
+ query.id = id;
58
+ }
59
+ return query;
60
+ }
61
+ case "FindArchitecture":
62
+ return {
63
+ type: "FindArchitecture",
64
+ pattern: requireNonEmptyString(record.pattern, "pattern"),
65
+ };
66
+ case "FindComponent":
67
+ return { type: "FindComponent", name: requireNonEmptyString(record.name, "name") };
68
+ case "FindRelationship": {
69
+ const source = optionalString(record.source, "source");
70
+ const target = optionalString(record.target, "target");
71
+ const relationship = optionalString(record.relationship, "relationship");
72
+ const id = optionalString(record.id, "id");
73
+ if (!source && !target && !relationship && !id) {
74
+ throw new QueryValidationError("FindRelationship requires source, target, relationship, or id");
75
+ }
76
+ const query = { type: "FindRelationship" };
77
+ if (source !== undefined) {
78
+ query.source = source;
79
+ }
80
+ if (target !== undefined) {
81
+ query.target = target;
82
+ }
83
+ if (relationship !== undefined) {
84
+ query.relationship = relationship;
85
+ }
86
+ if (id !== undefined) {
87
+ query.id = id;
88
+ }
89
+ return query;
90
+ }
91
+ case "FindDependency": {
92
+ const from = optionalString(record.from, "from");
93
+ const to = optionalString(record.to, "to");
94
+ const dependencyType = optionalString(record.dependencyType, "dependencyType");
95
+ const id = optionalString(record.id, "id");
96
+ if (!from && !to && !dependencyType && !id) {
97
+ throw new QueryValidationError("FindDependency requires from, to, dependencyType, or id");
98
+ }
99
+ const query = { type: "FindDependency" };
100
+ if (from !== undefined) {
101
+ query.from = from;
102
+ }
103
+ if (to !== undefined) {
104
+ query.to = to;
105
+ }
106
+ if (dependencyType !== undefined) {
107
+ query.dependencyType = dependencyType;
108
+ }
109
+ if (id !== undefined) {
110
+ query.id = id;
111
+ }
112
+ return query;
113
+ }
114
+ case "FindEvidence":
115
+ return { type: "FindEvidence", needle: requireNonEmptyString(record.needle, "needle") };
116
+ default:
117
+ throw new QueryValidationError(`unsupported query type: ${String(record.type)}`);
118
+ }
119
+ }
120
+ function pickDefined(base, fields) {
121
+ const out = { ...base };
122
+ for (const [key, value] of Object.entries(fields)) {
123
+ if (value !== undefined) {
124
+ out[key] = value;
125
+ }
126
+ }
127
+ return out;
128
+ }
129
+ /** Typed query constructors (internal ergonomics). */
130
+ export const Queries = {
131
+ repositorySummary: () => ({ type: "RepositorySummary" }),
132
+ listDomains: () => ({ type: "ListDomains" }),
133
+ listEntrypoints: () => ({ type: "ListEntrypoints" }),
134
+ listArchitectures: () => ({ type: "ListArchitectures" }),
135
+ listRelationships: () => ({ type: "ListRelationships" }),
136
+ listDependencies: () => ({ type: "ListDependencies" }),
137
+ findDomain: (name) => ({ type: "FindDomain", name }),
138
+ findEntrypoint: (options) => pickDefined({ type: "FindEntrypoint" }, options),
139
+ findArchitecture: (pattern) => ({ type: "FindArchitecture", pattern }),
140
+ findComponent: (name) => ({ type: "FindComponent", name }),
141
+ findRelationship: (options) => pickDefined({ type: "FindRelationship" }, options),
142
+ findDependency: (options) => pickDefined({ type: "FindDependency" }, options),
143
+ findEvidence: (needle) => ({ type: "FindEvidence", needle }),
144
+ statistics: () => ({ type: "Statistics" }),
145
+ };
@@ -0,0 +1,8 @@
1
+ import type { QueryHandlerContext, QueryHandlerOutput, QueryResultMap } from "./models.js";
2
+ import type { Query, QueryType } from "./types.js";
3
+ type Handler<T extends QueryType> = (query: Extract<Query, {
4
+ type: T;
5
+ }>, ctx: QueryHandlerContext) => QueryHandlerOutput<QueryResultMap[T]>;
6
+ export declare function getQueryHandler<T extends QueryType>(type: T): Handler<T>;
7
+ export declare function listSupportedQueryTypes(): QueryType[];
8
+ export {};
@@ -0,0 +1,340 @@
1
+ import { QueryNotFoundError } from "./errors.js";
2
+ function average(values) {
3
+ if (values.length === 0) {
4
+ return 0;
5
+ }
6
+ const sum = values.reduce((acc, value) => acc + value, 0);
7
+ return Math.round((sum / values.length) * 100) / 100;
8
+ }
9
+ function includesIgnoreCase(haystack, needle) {
10
+ return haystack.toLowerCase().includes(needle.toLowerCase());
11
+ }
12
+ function equalsIgnoreCase(left, right) {
13
+ return left.toLowerCase() === right.toLowerCase();
14
+ }
15
+ function domainRelatedPaths(domain) {
16
+ return [...domain.paths, ...domain.evidence];
17
+ }
18
+ function entrypointsForDomain(model, domain) {
19
+ const paths = domainRelatedPaths(domain);
20
+ return model.entrypoints.filter((entry) => paths.some((path) => includesIgnoreCase(path, entry.file) || includesIgnoreCase(entry.file, path)));
21
+ }
22
+ function relationshipsForDomain(model, domain) {
23
+ return model.relationships.filter((rel) => equalsIgnoreCase(rel.source, domain.name) ||
24
+ equalsIgnoreCase(rel.target, domain.name) ||
25
+ rel.evidence.some((e) => includesIgnoreCase(e, domain.name)) ||
26
+ domainRelatedPaths(domain).some((path) => includesIgnoreCase(rel.source, path) ||
27
+ includesIgnoreCase(rel.target, path) ||
28
+ rel.evidence.some((e) => includesIgnoreCase(e, path))));
29
+ }
30
+ function dependenciesForDomain(model, domain) {
31
+ return model.dependencies.filter((dep) => equalsIgnoreCase(dep.from, domain.name) ||
32
+ equalsIgnoreCase(dep.to, domain.name) ||
33
+ dep.evidence.some((e) => includesIgnoreCase(e, domain.name)));
34
+ }
35
+ function architecturesForDomain(model, domain) {
36
+ const related = model.architectures.filter((arch) => arch.evidence.some((e) => includesIgnoreCase(e, domain.name)) ||
37
+ arch.matchedRules.some((r) => includesIgnoreCase(r, domain.name)));
38
+ if (related.length > 0) {
39
+ return related;
40
+ }
41
+ // Fall back to top architectures when domain exists but has no direct arch mentions.
42
+ return model.architectures.slice(0, 3);
43
+ }
44
+ const handlers = {
45
+ RepositorySummary: (_query, ctx) => {
46
+ const { model } = ctx;
47
+ const result = {
48
+ projectName: model.metadata.project.name,
49
+ schemaVersion: model.metadata.schemaVersion,
50
+ compilerVersion: model.compilerMetadata.compilerVersion,
51
+ generatedAt: model.compilerMetadata.generatedAt,
52
+ topDomains: model.summary.topDomains,
53
+ topArchitectures: model.summary.topArchitectures,
54
+ frameworks: model.summary.frameworks,
55
+ statistics: model.summary.statistics,
56
+ };
57
+ return {
58
+ result,
59
+ evidence: [...model.metadata.evidence],
60
+ confidence: model.metadata.confidence,
61
+ };
62
+ },
63
+ ListDomains: (_query, ctx) => {
64
+ const domains = ctx.model.domains;
65
+ const result = { domains, count: domains.length };
66
+ return {
67
+ result,
68
+ evidence: domains.flatMap((d) => d.evidence).slice(0, 20),
69
+ confidence: average(domains.map((d) => d.confidence)),
70
+ };
71
+ },
72
+ ListEntrypoints: (_query, ctx) => {
73
+ const entrypoints = ctx.model.entrypoints;
74
+ const result = { entrypoints, count: entrypoints.length };
75
+ return {
76
+ result,
77
+ evidence: entrypoints.flatMap((e) => e.evidence).slice(0, 20),
78
+ confidence: average(entrypoints.map((e) => e.confidence)),
79
+ };
80
+ },
81
+ ListArchitectures: (_query, ctx) => {
82
+ const architectures = ctx.model.architectures;
83
+ const result = { architectures, count: architectures.length };
84
+ return {
85
+ result,
86
+ evidence: architectures.flatMap((a) => a.evidence).slice(0, 20),
87
+ confidence: average(architectures.map((a) => a.confidence)),
88
+ };
89
+ },
90
+ ListRelationships: (_query, ctx) => {
91
+ const relationships = ctx.model.relationships;
92
+ const result = { relationships, count: relationships.length };
93
+ return {
94
+ result,
95
+ evidence: relationships.flatMap((r) => r.evidence).slice(0, 20),
96
+ confidence: average(relationships.map((r) => r.confidence)),
97
+ };
98
+ },
99
+ ListDependencies: (_query, ctx) => {
100
+ const dependencies = ctx.model.dependencies;
101
+ const result = { dependencies, count: dependencies.length };
102
+ return {
103
+ result,
104
+ evidence: dependencies.flatMap((d) => d.evidence).slice(0, 20),
105
+ confidence: average(dependencies.map((d) => d.confidence)),
106
+ };
107
+ },
108
+ FindDomain: (query, ctx) => {
109
+ const domain = ctx.model.domains.find((d) => equalsIgnoreCase(d.name, query.name));
110
+ if (!domain) {
111
+ throw new QueryNotFoundError(`domain not found: ${query.name}`);
112
+ }
113
+ const entrypoints = entrypointsForDomain(ctx.model, domain);
114
+ const relationships = relationshipsForDomain(ctx.model, domain);
115
+ const dependencies = dependenciesForDomain(ctx.model, domain);
116
+ const architectures = architecturesForDomain(ctx.model, domain);
117
+ const result = {
118
+ domain,
119
+ entrypoints,
120
+ relationships,
121
+ dependencies,
122
+ architectures,
123
+ };
124
+ return {
125
+ result,
126
+ evidence: [
127
+ ...domain.evidence,
128
+ ...entrypoints.flatMap((e) => e.evidence).slice(0, 5),
129
+ ...relationships.flatMap((r) => r.evidence).slice(0, 5),
130
+ ],
131
+ confidence: domain.confidence,
132
+ };
133
+ },
134
+ FindEntrypoint: (query, ctx) => {
135
+ const entrypoint = ctx.model.entrypoints.find((entry) => {
136
+ if (query.id && entry.id === query.id) {
137
+ return true;
138
+ }
139
+ if (query.file && equalsIgnoreCase(entry.file, query.file)) {
140
+ return true;
141
+ }
142
+ if (query.framework &&
143
+ equalsIgnoreCase(entry.framework, query.framework) &&
144
+ !query.file &&
145
+ !query.id) {
146
+ return true;
147
+ }
148
+ if (query.framework &&
149
+ query.file &&
150
+ equalsIgnoreCase(entry.framework, query.framework) &&
151
+ equalsIgnoreCase(entry.file, query.file)) {
152
+ return true;
153
+ }
154
+ return false;
155
+ });
156
+ if (!entrypoint) {
157
+ throw new QueryNotFoundError("entrypoint not found");
158
+ }
159
+ const result = { entrypoint };
160
+ return {
161
+ result,
162
+ evidence: [...entrypoint.evidence],
163
+ confidence: entrypoint.confidence,
164
+ };
165
+ },
166
+ FindArchitecture: (query, ctx) => {
167
+ const architecture = ctx.model.architectures.find((arch) => equalsIgnoreCase(arch.pattern, query.pattern));
168
+ if (!architecture) {
169
+ throw new QueryNotFoundError(`architecture not found: ${query.pattern}`);
170
+ }
171
+ const result = { architecture };
172
+ return {
173
+ result,
174
+ evidence: [...architecture.evidence, ...architecture.matchedRules],
175
+ confidence: architecture.confidence,
176
+ };
177
+ },
178
+ FindComponent: (query, ctx) => {
179
+ const name = query.name;
180
+ const asRelationshipSource = ctx.model.relationships.filter((r) => equalsIgnoreCase(r.source, name));
181
+ const asRelationshipTarget = ctx.model.relationships.filter((r) => equalsIgnoreCase(r.target, name));
182
+ const asDependencyEndpoint = ctx.model.dependencies.filter((d) => equalsIgnoreCase(d.from, name) || equalsIgnoreCase(d.to, name));
183
+ const matchingEntrypoints = ctx.model.entrypoints.filter((e) => includesIgnoreCase(e.file, name) || e.evidence.some((ev) => includesIgnoreCase(ev, name)));
184
+ const matchingDomains = ctx.model.domains.filter((d) => equalsIgnoreCase(d.name, name) || d.evidence.some((ev) => includesIgnoreCase(ev, name)));
185
+ if (asRelationshipSource.length === 0 &&
186
+ asRelationshipTarget.length === 0 &&
187
+ asDependencyEndpoint.length === 0 &&
188
+ matchingEntrypoints.length === 0 &&
189
+ matchingDomains.length === 0) {
190
+ throw new QueryNotFoundError(`component not found: ${name}`);
191
+ }
192
+ const result = {
193
+ name,
194
+ asRelationshipSource,
195
+ asRelationshipTarget,
196
+ asDependencyEndpoint,
197
+ matchingEntrypoints,
198
+ matchingDomains,
199
+ };
200
+ const confidences = [
201
+ ...asRelationshipSource.map((r) => r.confidence),
202
+ ...asRelationshipTarget.map((r) => r.confidence),
203
+ ...asDependencyEndpoint.map((d) => d.confidence),
204
+ ...matchingEntrypoints.map((e) => e.confidence),
205
+ ...matchingDomains.map((d) => d.confidence),
206
+ ];
207
+ return {
208
+ result,
209
+ evidence: [
210
+ ...asRelationshipSource.flatMap((r) => r.evidence),
211
+ ...asRelationshipTarget.flatMap((r) => r.evidence),
212
+ ...asDependencyEndpoint.flatMap((d) => d.evidence),
213
+ ].slice(0, 30),
214
+ confidence: average(confidences),
215
+ };
216
+ },
217
+ FindRelationship: (query, ctx) => {
218
+ const matches = ctx.model.relationships.filter((rel) => {
219
+ if (query.id) {
220
+ return rel.id === query.id;
221
+ }
222
+ if (query.source && !equalsIgnoreCase(rel.source, query.source)) {
223
+ return false;
224
+ }
225
+ if (query.target && !equalsIgnoreCase(rel.target, query.target)) {
226
+ return false;
227
+ }
228
+ if (query.relationship && !equalsIgnoreCase(rel.relationship, query.relationship)) {
229
+ return false;
230
+ }
231
+ return Boolean(query.source || query.target || query.relationship);
232
+ });
233
+ const relationship = matches[0];
234
+ if (!relationship) {
235
+ throw new QueryNotFoundError("relationship not found");
236
+ }
237
+ const result = { relationship };
238
+ return {
239
+ result,
240
+ evidence: [...relationship.evidence],
241
+ confidence: relationship.confidence,
242
+ };
243
+ },
244
+ FindDependency: (query, ctx) => {
245
+ const matches = ctx.model.dependencies.filter((dep) => {
246
+ if (query.id) {
247
+ return dep.id === query.id;
248
+ }
249
+ if (query.from && !equalsIgnoreCase(dep.from, query.from)) {
250
+ return false;
251
+ }
252
+ if (query.to && !equalsIgnoreCase(dep.to, query.to)) {
253
+ return false;
254
+ }
255
+ if (query.dependencyType && !equalsIgnoreCase(dep.type, query.dependencyType)) {
256
+ return false;
257
+ }
258
+ return Boolean(query.from || query.to || query.dependencyType);
259
+ });
260
+ const dependency = matches[0];
261
+ if (!dependency) {
262
+ throw new QueryNotFoundError("dependency not found");
263
+ }
264
+ const result = { dependency };
265
+ return {
266
+ result,
267
+ evidence: [...dependency.evidence],
268
+ confidence: dependency.confidence,
269
+ };
270
+ },
271
+ FindEvidence: (query, ctx) => {
272
+ const needle = query.needle;
273
+ const hits = [];
274
+ const push = (collection, id, label, evidence) => {
275
+ const matched = evidence.filter((item) => includesIgnoreCase(item, needle));
276
+ if (matched.length > 0) {
277
+ hits.push({ collection, id, label, evidence: matched });
278
+ }
279
+ };
280
+ push("metadata", ctx.model.metadata.id, ctx.model.metadata.project.name, ctx.model.metadata.evidence);
281
+ for (const domain of ctx.model.domains) {
282
+ push("domains", domain.id, domain.name, domain.evidence);
283
+ }
284
+ for (const entry of ctx.model.entrypoints) {
285
+ push("entrypoints", entry.id, entry.file, entry.evidence);
286
+ }
287
+ for (const dep of ctx.model.dependencies) {
288
+ push("dependencies", dep.id, `${dep.from}->${dep.to}`, dep.evidence);
289
+ }
290
+ for (const rel of ctx.model.relationships) {
291
+ push("relationships", rel.id, `${rel.source}->${rel.target}`, rel.evidence);
292
+ }
293
+ for (const arch of ctx.model.architectures) {
294
+ push("architectures", arch.id, arch.pattern, [
295
+ ...arch.evidence,
296
+ ...arch.matchedRules,
297
+ ...arch.conflictingEvidence,
298
+ ...arch.unknowns,
299
+ ]);
300
+ }
301
+ hits.sort((a, b) => a.collection.localeCompare(b.collection) || a.label.localeCompare(b.label));
302
+ if (hits.length === 0) {
303
+ throw new QueryNotFoundError(`evidence not found for needle: ${needle}`);
304
+ }
305
+ const result = { needle, hits, count: hits.length };
306
+ return {
307
+ result,
308
+ evidence: hits.flatMap((hit) => hit.evidence).slice(0, 40),
309
+ confidence: Math.min(0.99, 0.5 + Math.min(hits.length, 10) * 0.04),
310
+ };
311
+ },
312
+ Statistics: (_query, ctx) => {
313
+ const result = {
314
+ summary: ctx.model.summary,
315
+ model: {
316
+ projectName: ctx.model.metadata.project.name,
317
+ schemaVersion: ctx.model.metadata.schemaVersion,
318
+ compilerVersion: ctx.model.compilerMetadata.compilerVersion,
319
+ generatedAt: ctx.model.compilerMetadata.generatedAt,
320
+ },
321
+ };
322
+ return {
323
+ result,
324
+ evidence: [
325
+ `domains:${ctx.model.summary.statistics.domainCount}`,
326
+ `entrypoints:${ctx.model.summary.statistics.entrypointCount}`,
327
+ `dependencies:${ctx.model.summary.statistics.dependencyCount}`,
328
+ `relationships:${ctx.model.summary.statistics.relationshipCount}`,
329
+ `architectures:${ctx.model.summary.statistics.architectureCount}`,
330
+ ],
331
+ confidence: ctx.model.summary.statistics.averageConfidence,
332
+ };
333
+ },
334
+ };
335
+ export function getQueryHandler(type) {
336
+ return handlers[type];
337
+ }
338
+ export function listSupportedQueryTypes() {
339
+ return Object.keys(handlers).sort((a, b) => a.localeCompare(b));
340
+ }
@@ -0,0 +1,63 @@
1
+ export type QueryType = "RepositorySummary" | "ListDomains" | "ListEntrypoints" | "ListArchitectures" | "ListRelationships" | "ListDependencies" | "FindDomain" | "FindEntrypoint" | "FindArchitecture" | "FindComponent" | "FindRelationship" | "FindDependency" | "FindEvidence" | "Statistics";
2
+ export type Query = {
3
+ type: "RepositorySummary";
4
+ } | {
5
+ type: "ListDomains";
6
+ } | {
7
+ type: "ListEntrypoints";
8
+ } | {
9
+ type: "ListArchitectures";
10
+ } | {
11
+ type: "ListRelationships";
12
+ } | {
13
+ type: "ListDependencies";
14
+ } | {
15
+ type: "FindDomain";
16
+ name: string;
17
+ } | {
18
+ type: "FindEntrypoint";
19
+ file?: string;
20
+ framework?: string;
21
+ id?: string;
22
+ } | {
23
+ type: "FindArchitecture";
24
+ pattern: string;
25
+ } | {
26
+ type: "FindComponent";
27
+ name: string;
28
+ } | {
29
+ type: "FindRelationship";
30
+ source?: string;
31
+ target?: string;
32
+ relationship?: string;
33
+ id?: string;
34
+ } | {
35
+ type: "FindDependency";
36
+ from?: string;
37
+ to?: string;
38
+ dependencyType?: string;
39
+ id?: string;
40
+ } | {
41
+ type: "FindEvidence";
42
+ needle: string;
43
+ } | {
44
+ type: "Statistics";
45
+ };
46
+ export interface QueryMetadata {
47
+ queryType: QueryType;
48
+ projectName: string;
49
+ modelId: string;
50
+ schemaVersion: string;
51
+ compilerVersion: string;
52
+ modelGeneratedAt: string;
53
+ }
54
+ /**
55
+ * Canonical envelope returned by every query execution.
56
+ */
57
+ export interface QueryResponse<T> {
58
+ result: T;
59
+ evidence: readonly string[];
60
+ confidence: number;
61
+ metadata: QueryMetadata;
62
+ executionTimeMs: number;
63
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ import type { RelationshipDiscoveryOptions, RelationshipDiscoveryResult, RelationshipStrength } from "./types.js";
2
+ /**
3
+ * Discover semantic component relationships using deterministic heuristics.
4
+ * Reuses dependency, entrypoint, and domain discovery. Isolated from scan/CLI.
5
+ */
6
+ export declare function discoverRelationships(options?: RelationshipDiscoveryOptions): Promise<RelationshipDiscoveryResult>;
7
+ export declare function scoreRelationshipConfidence(options: {
8
+ base: number;
9
+ strength: RelationshipStrength;
10
+ evidenceCount: number;
11
+ }): number;