@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,4 @@
|
|
|
1
|
+
export { discoverRelationships, scoreRelationshipConfidence } from "./discover.js";
|
|
2
|
+
export { classifyComponent, classifyRoleFromPath, extractSemanticSignals, pascalCaseName, } from "./extract.js";
|
|
3
|
+
export { ROLE_PAIR_RULES, findRolePairRule } from "./models.js";
|
|
4
|
+
export type { ClassifiedComponent, ComponentRole, RelationshipDiscoveryOptions, RelationshipDiscoveryResult, RelationshipKind, RelationshipMatch, RelationshipStrength, SemanticSignal, } from "./types.js";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ComponentRole, RelationshipKind, RelationshipStrength } from "./types.js";
|
|
2
|
+
export interface RolePairRule {
|
|
3
|
+
source: ComponentRole;
|
|
4
|
+
target: ComponentRole;
|
|
5
|
+
relationship: RelationshipKind;
|
|
6
|
+
baseConfidence: number;
|
|
7
|
+
strength: RelationshipStrength;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Deterministic semantic layer rules. Only applied when both roles are evidenced.
|
|
11
|
+
*/
|
|
12
|
+
export declare const ROLE_PAIR_RULES: readonly RolePairRule[];
|
|
13
|
+
export declare const ROLE_PATH_PATTERNS: ReadonlyArray<{
|
|
14
|
+
role: ComponentRole;
|
|
15
|
+
pattern: RegExp;
|
|
16
|
+
}>;
|
|
17
|
+
export declare const STRENGTH_BOOST: Readonly<Record<RelationshipStrength, number>>;
|
|
18
|
+
export declare function clampConfidence(value: number): number;
|
|
19
|
+
export declare function strengthRank(strength: RelationshipStrength): number;
|
|
20
|
+
export declare function maxStrength(a: RelationshipStrength, b: RelationshipStrength): RelationshipStrength;
|
|
21
|
+
export declare function findRolePairRule(source: ComponentRole, target: ComponentRole): RolePairRule | undefined;
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic semantic layer rules. Only applied when both roles are evidenced.
|
|
3
|
+
*/
|
|
4
|
+
export const ROLE_PAIR_RULES = [
|
|
5
|
+
{
|
|
6
|
+
source: "Controller",
|
|
7
|
+
target: "Service",
|
|
8
|
+
relationship: "USES",
|
|
9
|
+
baseConfidence: 0.96,
|
|
10
|
+
strength: "medium",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
source: "Service",
|
|
14
|
+
target: "Repository",
|
|
15
|
+
relationship: "USES",
|
|
16
|
+
baseConfidence: 0.95,
|
|
17
|
+
strength: "medium",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
source: "Repository",
|
|
21
|
+
target: "Database",
|
|
22
|
+
relationship: "USES",
|
|
23
|
+
baseConfidence: 0.94,
|
|
24
|
+
strength: "medium",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
source: "Route",
|
|
28
|
+
target: "Controller",
|
|
29
|
+
relationship: "EXPOSES",
|
|
30
|
+
baseConfidence: 0.93,
|
|
31
|
+
strength: "medium",
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
source: "Widget",
|
|
35
|
+
target: "Bloc",
|
|
36
|
+
relationship: "USES",
|
|
37
|
+
baseConfidence: 0.92,
|
|
38
|
+
strength: "medium",
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
source: "Bloc",
|
|
42
|
+
target: "Repository",
|
|
43
|
+
relationship: "USES",
|
|
44
|
+
baseConfidence: 0.91,
|
|
45
|
+
strength: "medium",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
source: "API",
|
|
49
|
+
target: "Service",
|
|
50
|
+
relationship: "CALLS",
|
|
51
|
+
baseConfidence: 0.9,
|
|
52
|
+
strength: "medium",
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
source: "Module",
|
|
56
|
+
target: "Configuration",
|
|
57
|
+
relationship: "CONFIGURES",
|
|
58
|
+
baseConfidence: 0.9,
|
|
59
|
+
strength: "medium",
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
source: "Module",
|
|
63
|
+
target: "Controller",
|
|
64
|
+
relationship: "PROVIDES",
|
|
65
|
+
baseConfidence: 0.88,
|
|
66
|
+
strength: "medium",
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
source: "Module",
|
|
70
|
+
target: "Service",
|
|
71
|
+
relationship: "PROVIDES",
|
|
72
|
+
baseConfidence: 0.88,
|
|
73
|
+
strength: "medium",
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
source: "EntryPoint",
|
|
77
|
+
target: "Feature",
|
|
78
|
+
relationship: "ENTERS",
|
|
79
|
+
baseConfidence: 0.9,
|
|
80
|
+
strength: "medium",
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
source: "Package",
|
|
84
|
+
target: "Module",
|
|
85
|
+
relationship: "CONTAINS",
|
|
86
|
+
baseConfidence: 0.9,
|
|
87
|
+
strength: "strong",
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
source: "Package",
|
|
91
|
+
target: "Feature",
|
|
92
|
+
relationship: "OWNS",
|
|
93
|
+
baseConfidence: 0.88,
|
|
94
|
+
strength: "strong",
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
source: "Feature",
|
|
98
|
+
target: "Domain",
|
|
99
|
+
relationship: "PROVIDES",
|
|
100
|
+
baseConfidence: 0.85,
|
|
101
|
+
strength: "medium",
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
source: "Feature",
|
|
105
|
+
target: "Controller",
|
|
106
|
+
relationship: "CONTAINS",
|
|
107
|
+
baseConfidence: 0.86,
|
|
108
|
+
strength: "strong",
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
source: "Feature",
|
|
112
|
+
target: "Service",
|
|
113
|
+
relationship: "CONTAINS",
|
|
114
|
+
baseConfidence: 0.86,
|
|
115
|
+
strength: "strong",
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
source: "Service",
|
|
119
|
+
target: "Service",
|
|
120
|
+
relationship: "CALLS",
|
|
121
|
+
baseConfidence: 0.8,
|
|
122
|
+
strength: "weak",
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
source: "Controller",
|
|
126
|
+
target: "Repository",
|
|
127
|
+
relationship: "USES",
|
|
128
|
+
baseConfidence: 0.84,
|
|
129
|
+
strength: "weak",
|
|
130
|
+
},
|
|
131
|
+
];
|
|
132
|
+
export const ROLE_PATH_PATTERNS = [
|
|
133
|
+
// Filename-specific roles first (win over directory names like apps/api/)
|
|
134
|
+
{ role: "Module", pattern: /\.module\.(t|j)sx?$/i },
|
|
135
|
+
{ role: "Configuration", pattern: /(^|\/|[-_.])config(uration)?([-_.]|$)/i },
|
|
136
|
+
{ role: "Controller", pattern: /(^|\/|[-_.])controllers?([-_.]|$)|controller\.(t|j)sx?$/i },
|
|
137
|
+
{ role: "Service", pattern: /(^|\/|[-_.])services?([-_.]|$)|service\.(t|j)sx?$/i },
|
|
138
|
+
{ role: "Repository", pattern: /(^|\/|[-_.])repositor(y|ies)([-_.]|$)|repository\.(t|j)sx?$/i },
|
|
139
|
+
{
|
|
140
|
+
role: "Database",
|
|
141
|
+
pattern: /(^|\/|[-_.])(entity|entities|schema|models?|prisma|migration)([-_.]|$)/i,
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
role: "Route",
|
|
145
|
+
pattern: /(^|\/)routes?\/|(^|\/|[-_.])router([-_.]|$)|routes?\.(t|j)sx?$|web\.php$/i,
|
|
146
|
+
},
|
|
147
|
+
{ role: "Widget", pattern: /widget\.(dart|tsx?|jsx?)$|_widget\.dart$/i },
|
|
148
|
+
{ role: "Bloc", pattern: /bloc\.(dart|tsx?)$|cubit\.dart$/i },
|
|
149
|
+
{
|
|
150
|
+
role: "EntryPoint",
|
|
151
|
+
pattern: /(^|\/)main\.(t|j)sx?$|(^|\/)main\.dart$|(^|\/)index\.(t|j)sx?$/i,
|
|
152
|
+
},
|
|
153
|
+
// Broad directory heuristics last
|
|
154
|
+
{ role: "API", pattern: /(^|\/)api\/[^/]+$|api\.(t|j)sx?$/i },
|
|
155
|
+
];
|
|
156
|
+
export const STRENGTH_BOOST = {
|
|
157
|
+
strong: 0.03,
|
|
158
|
+
medium: 0,
|
|
159
|
+
weak: -0.05,
|
|
160
|
+
};
|
|
161
|
+
export function clampConfidence(value) {
|
|
162
|
+
if (value < 0) {
|
|
163
|
+
return 0;
|
|
164
|
+
}
|
|
165
|
+
if (value > 0.99) {
|
|
166
|
+
return 0.99;
|
|
167
|
+
}
|
|
168
|
+
return Math.round(value * 100) / 100;
|
|
169
|
+
}
|
|
170
|
+
export function strengthRank(strength) {
|
|
171
|
+
switch (strength) {
|
|
172
|
+
case "strong":
|
|
173
|
+
return 3;
|
|
174
|
+
case "medium":
|
|
175
|
+
return 2;
|
|
176
|
+
case "weak":
|
|
177
|
+
return 1;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
export function maxStrength(a, b) {
|
|
181
|
+
return strengthRank(a) >= strengthRank(b) ? a : b;
|
|
182
|
+
}
|
|
183
|
+
export function findRolePairRule(source, target) {
|
|
184
|
+
return ROLE_PAIR_RULES.find((rule) => rule.source === source && rule.target === target);
|
|
185
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { DependencyDiscoveryResult } from "../dependencies/types.js";
|
|
2
|
+
import type { EntrypointDiscoveryResult } from "../entrypoints/types.js";
|
|
3
|
+
import type { DomainDiscoveryResult } from "../types/index.js";
|
|
4
|
+
export type RelationshipKind = "USES" | "OWNS" | "IMPLEMENTS" | "DEPENDS_ON" | "CALLS" | "CONFIGURES" | "EXPOSES" | "ENTERS" | "CONTAINS" | "PROVIDES" | "CONSUMES";
|
|
5
|
+
export type RelationshipStrength = "strong" | "medium" | "weak";
|
|
6
|
+
export type ComponentRole = "Controller" | "Service" | "Repository" | "Database" | "Route" | "Widget" | "Bloc" | "API" | "Module" | "Configuration" | "EntryPoint" | "Feature" | "Domain" | "Package" | "Component";
|
|
7
|
+
export interface RelationshipMatch {
|
|
8
|
+
source: string;
|
|
9
|
+
target: string;
|
|
10
|
+
relationship: RelationshipKind;
|
|
11
|
+
confidence: number;
|
|
12
|
+
evidence: string[];
|
|
13
|
+
strength: RelationshipStrength;
|
|
14
|
+
bidirectional?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface RelationshipDiscoveryResult {
|
|
17
|
+
relationships: RelationshipMatch[];
|
|
18
|
+
timingMs: number;
|
|
19
|
+
filesConsidered: number;
|
|
20
|
+
filesInspected: number;
|
|
21
|
+
}
|
|
22
|
+
export interface RelationshipDiscoveryOptions {
|
|
23
|
+
cwd?: string;
|
|
24
|
+
minConfidence?: number;
|
|
25
|
+
maxReadBytes?: number;
|
|
26
|
+
/** Injected dependency graph; when omitted, runs discoverDependencies. */
|
|
27
|
+
dependencies?: DependencyDiscoveryResult;
|
|
28
|
+
/** Injected entrypoints; when omitted, runs discoverEntrypoints. */
|
|
29
|
+
entrypoints?: EntrypointDiscoveryResult;
|
|
30
|
+
/** Injected domains; when omitted, runs discoverDomains. */
|
|
31
|
+
domains?: DomainDiscoveryResult;
|
|
32
|
+
}
|
|
33
|
+
export interface ClassifiedComponent {
|
|
34
|
+
name: string;
|
|
35
|
+
role: ComponentRole;
|
|
36
|
+
file: string;
|
|
37
|
+
}
|
|
38
|
+
export interface SemanticSignal {
|
|
39
|
+
kind: "constructor-injection" | "implements" | "extends" | "bloc-provider" | "entity" | "call";
|
|
40
|
+
label: string;
|
|
41
|
+
relatedName?: string;
|
|
42
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ProjectModel } from "../model/types.js";
|
|
2
|
+
import { type OwnershipDiscoveryResult } from "../ownership/index.js";
|
|
3
|
+
import type { RiskDiscoveryOptions, RiskDiscoveryResult } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Discover change-danger risks from ProjectModel (+ optional ownership).
|
|
6
|
+
* Deterministic; evidence-required; never invents vulnerability claims.
|
|
7
|
+
*/
|
|
8
|
+
export declare function discoverRisks(model: ProjectModel, ownership?: OwnershipDiscoveryResult, options?: RiskDiscoveryOptions): RiskDiscoveryResult;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { ownersForPath } from "../ownership/index.js";
|
|
2
|
+
function clampConfidence(value) {
|
|
3
|
+
if (value < 0) {
|
|
4
|
+
return 0;
|
|
5
|
+
}
|
|
6
|
+
if (value > 1) {
|
|
7
|
+
return 1;
|
|
8
|
+
}
|
|
9
|
+
return Math.round(value * 100) / 100;
|
|
10
|
+
}
|
|
11
|
+
function countFanIn(model) {
|
|
12
|
+
const fanIn = new Map();
|
|
13
|
+
for (const dep of model.dependencies) {
|
|
14
|
+
const bucket = fanIn.get(dep.to) ?? { count: 0, evidence: [] };
|
|
15
|
+
bucket.count += 1;
|
|
16
|
+
bucket.evidence.push(...dep.evidence);
|
|
17
|
+
fanIn.set(dep.to, bucket);
|
|
18
|
+
}
|
|
19
|
+
return fanIn;
|
|
20
|
+
}
|
|
21
|
+
function countCoupling(model) {
|
|
22
|
+
const coupling = new Map();
|
|
23
|
+
const bump = (key, evidence) => {
|
|
24
|
+
const bucket = coupling.get(key) ?? { count: 0, evidence: [] };
|
|
25
|
+
bucket.count += 1;
|
|
26
|
+
bucket.evidence.push(...evidence);
|
|
27
|
+
coupling.set(key, bucket);
|
|
28
|
+
};
|
|
29
|
+
for (const rel of model.relationships) {
|
|
30
|
+
bump(rel.source, rel.evidence);
|
|
31
|
+
bump(rel.target, rel.evidence);
|
|
32
|
+
}
|
|
33
|
+
return coupling;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Discover change-danger risks from ProjectModel (+ optional ownership).
|
|
37
|
+
* Deterministic; evidence-required; never invents vulnerability claims.
|
|
38
|
+
*/
|
|
39
|
+
export function discoverRisks(model, ownership, options = {}) {
|
|
40
|
+
const started = performance.now();
|
|
41
|
+
const centralityThreshold = options.centralityThreshold ?? 3;
|
|
42
|
+
const couplingThreshold = options.couplingThreshold ?? 4;
|
|
43
|
+
const minConfidence = options.minConfidence ?? 0.5;
|
|
44
|
+
const risks = [];
|
|
45
|
+
const unknowns = [];
|
|
46
|
+
for (const entry of model.entrypoints) {
|
|
47
|
+
risks.push({
|
|
48
|
+
kind: "critical-entrypoint",
|
|
49
|
+
target: entry.file,
|
|
50
|
+
severity: "high",
|
|
51
|
+
confidence: clampConfidence(Math.min(0.9, 0.55 + entry.confidence * 0.35)),
|
|
52
|
+
evidence: [...entry.evidence, `entrypoint:${entry.framework}`],
|
|
53
|
+
rationale: "Entrypoints are high-blast-radius change surfaces",
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
const fanIn = countFanIn(model);
|
|
57
|
+
for (const [target, bucket] of fanIn) {
|
|
58
|
+
if (bucket.count < centralityThreshold) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
risks.push({
|
|
62
|
+
kind: "dependency-centrality",
|
|
63
|
+
target,
|
|
64
|
+
severity: bucket.count >= centralityThreshold * 2 ? "high" : "medium",
|
|
65
|
+
confidence: clampConfidence(Math.min(0.92, 0.5 + bucket.count * 0.08)),
|
|
66
|
+
evidence: [...new Set(bucket.evidence)].sort((a, b) => a.localeCompare(b)).slice(0, 12),
|
|
67
|
+
rationale: `${bucket.count} inbound dependencies — changes here fan out`,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
const coupling = countCoupling(model);
|
|
71
|
+
for (const [target, bucket] of coupling) {
|
|
72
|
+
if (bucket.count < couplingThreshold) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
risks.push({
|
|
76
|
+
kind: "high-coupling",
|
|
77
|
+
target,
|
|
78
|
+
severity: bucket.count >= couplingThreshold * 2 ? "high" : "medium",
|
|
79
|
+
confidence: clampConfidence(Math.min(0.9, 0.48 + bucket.count * 0.07)),
|
|
80
|
+
evidence: [...new Set(bucket.evidence)].sort((a, b) => a.localeCompare(b)).slice(0, 12),
|
|
81
|
+
rationale: `${bucket.count} relationship edges — tightly coupled change surface`,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
for (const arch of model.architectures) {
|
|
85
|
+
if (arch.conflictingEvidence.length === 0) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
risks.push({
|
|
89
|
+
kind: "architecture-conflict",
|
|
90
|
+
target: arch.pattern,
|
|
91
|
+
severity: "medium",
|
|
92
|
+
confidence: clampConfidence(Math.min(0.85, 0.4 + arch.conflictingEvidence.length * 0.1)),
|
|
93
|
+
evidence: [...arch.conflictingEvidence, ...arch.evidence].slice(0, 12),
|
|
94
|
+
rationale: "Architecture hypothesis has conflicting evidence — change guidance is weaker",
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
if (ownership) {
|
|
98
|
+
const candidates = [
|
|
99
|
+
...model.entrypoints.map((e) => e.file),
|
|
100
|
+
...model.domains.flatMap((d) => d.paths.slice(0, 3)),
|
|
101
|
+
];
|
|
102
|
+
const seen = new Set();
|
|
103
|
+
for (const candidate of candidates) {
|
|
104
|
+
const key = candidate.replace(/\\/g, "/");
|
|
105
|
+
if (seen.has(key)) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
seen.add(key);
|
|
109
|
+
const owner = ownersForPath(key, ownership.ownerships);
|
|
110
|
+
if (owner) {
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
risks.push({
|
|
114
|
+
kind: "unclear-ownership",
|
|
115
|
+
target: key,
|
|
116
|
+
severity: "medium",
|
|
117
|
+
confidence: 0.7,
|
|
118
|
+
evidence: [`path:${key}`, "ownership:none"],
|
|
119
|
+
rationale: "No CODEOWNERS / MAINTAINERS / package maintainers evidence covers this path",
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
if (ownership.unknowns.length > 0 && ownership.ownerships.length === 0) {
|
|
123
|
+
unknowns.push(...ownership.unknowns);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
unknowns.push("Ownership input omitted — unclear-ownership risks not evaluated");
|
|
128
|
+
}
|
|
129
|
+
if (model.dependencies.length === 0) {
|
|
130
|
+
unknowns.push("No dependencies modeled — centrality risks unavailable");
|
|
131
|
+
}
|
|
132
|
+
const filtered = risks
|
|
133
|
+
.filter((risk) => risk.confidence >= minConfidence)
|
|
134
|
+
.sort((a, b) => severityRank(b.severity) - severityRank(a.severity) ||
|
|
135
|
+
b.confidence - a.confidence ||
|
|
136
|
+
a.kind.localeCompare(b.kind) ||
|
|
137
|
+
a.target.localeCompare(b.target));
|
|
138
|
+
return {
|
|
139
|
+
risks: filtered,
|
|
140
|
+
timingMs: Math.max(0, Math.round(performance.now() - started)),
|
|
141
|
+
unknowns: [...new Set(unknowns)].sort((a, b) => a.localeCompare(b)),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function severityRank(severity) {
|
|
145
|
+
switch (severity) {
|
|
146
|
+
case "high":
|
|
147
|
+
return 3;
|
|
148
|
+
case "medium":
|
|
149
|
+
return 2;
|
|
150
|
+
case "low":
|
|
151
|
+
return 1;
|
|
152
|
+
default:
|
|
153
|
+
return 0;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { discoverRisks } from "./discover.js";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export type RiskKind = "critical-entrypoint" | "dependency-centrality" | "unclear-ownership" | "architecture-conflict" | "high-coupling";
|
|
2
|
+
export type RiskSeverity = "high" | "medium" | "low";
|
|
3
|
+
/**
|
|
4
|
+
* Change-danger risk: how dangerous is modifying this part of the software?
|
|
5
|
+
* Not generic SAST.
|
|
6
|
+
*/
|
|
7
|
+
export interface RiskMatch {
|
|
8
|
+
kind: RiskKind;
|
|
9
|
+
target: string;
|
|
10
|
+
severity: RiskSeverity;
|
|
11
|
+
confidence: number;
|
|
12
|
+
evidence: readonly string[];
|
|
13
|
+
rationale: string;
|
|
14
|
+
}
|
|
15
|
+
export interface RiskDiscoveryResult {
|
|
16
|
+
risks: RiskMatch[];
|
|
17
|
+
timingMs: number;
|
|
18
|
+
unknowns: string[];
|
|
19
|
+
}
|
|
20
|
+
export interface RiskDiscoveryOptions {
|
|
21
|
+
/** Minimum fan-in for dependency-centrality. Default 3. */
|
|
22
|
+
centralityThreshold?: number;
|
|
23
|
+
/** Minimum relationship edges for high-coupling. Default 4. */
|
|
24
|
+
couplingThreshold?: number;
|
|
25
|
+
minConfidence?: number;
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic synonym → canonical domain label map.
|
|
3
|
+
* First matching synonym wins for a token; evidence aggregates per canonical name.
|
|
4
|
+
*/
|
|
5
|
+
export declare const DOMAIN_LEXICON: ReadonlyArray<{
|
|
6
|
+
name: string;
|
|
7
|
+
synonyms: readonly string[];
|
|
8
|
+
}>;
|
|
9
|
+
export declare function domainForToken(token: string): string | undefined;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic synonym → canonical domain label map.
|
|
3
|
+
* First matching synonym wins for a token; evidence aggregates per canonical name.
|
|
4
|
+
*/
|
|
5
|
+
export const DOMAIN_LEXICON = [
|
|
6
|
+
{
|
|
7
|
+
name: "Payments",
|
|
8
|
+
synonyms: [
|
|
9
|
+
"payment",
|
|
10
|
+
"payments",
|
|
11
|
+
"billing",
|
|
12
|
+
"invoice",
|
|
13
|
+
"invoices",
|
|
14
|
+
"checkout",
|
|
15
|
+
"stripe",
|
|
16
|
+
"paypal",
|
|
17
|
+
"refund",
|
|
18
|
+
"refunds",
|
|
19
|
+
"subscription",
|
|
20
|
+
"subscriptions",
|
|
21
|
+
"charge",
|
|
22
|
+
"charges",
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: "Auth",
|
|
27
|
+
synonyms: [
|
|
28
|
+
"auth",
|
|
29
|
+
"authentication",
|
|
30
|
+
"authorization",
|
|
31
|
+
"login",
|
|
32
|
+
"logout",
|
|
33
|
+
"oauth",
|
|
34
|
+
"oidc",
|
|
35
|
+
"sso",
|
|
36
|
+
"session",
|
|
37
|
+
"sessions",
|
|
38
|
+
"password",
|
|
39
|
+
"passwords",
|
|
40
|
+
"jwt",
|
|
41
|
+
"rbac",
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: "Users",
|
|
46
|
+
synonyms: [
|
|
47
|
+
"user",
|
|
48
|
+
"users",
|
|
49
|
+
"account",
|
|
50
|
+
"accounts",
|
|
51
|
+
"profile",
|
|
52
|
+
"profiles",
|
|
53
|
+
"identity",
|
|
54
|
+
"identities",
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: "Orders",
|
|
59
|
+
synonyms: ["order", "orders", "cart", "carts", "checkoutcart", "fulfillment"],
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: "Notifications",
|
|
63
|
+
synonyms: [
|
|
64
|
+
"notification",
|
|
65
|
+
"notifications",
|
|
66
|
+
"notify",
|
|
67
|
+
"email",
|
|
68
|
+
"emails",
|
|
69
|
+
"mailer",
|
|
70
|
+
"sms",
|
|
71
|
+
"push",
|
|
72
|
+
"webhook",
|
|
73
|
+
"webhooks",
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: "Inventory",
|
|
78
|
+
synonyms: ["inventory", "stock", "sku", "skus", "warehouse", "catalog", "catalogue"],
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: "Shipping",
|
|
82
|
+
synonyms: ["shipping", "shipment", "shipments", "delivery", "logistics", "carrier"],
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: "Admin",
|
|
86
|
+
synonyms: ["admin", "admins", "backoffice", "dashboard"],
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: "Analytics",
|
|
90
|
+
synonyms: ["analytics", "metrics", "telemetry", "tracking", "reporting", "reports"],
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: "Search",
|
|
94
|
+
synonyms: ["search", "elasticsearch", "opensearch", "solr", "indexer", "indexing"],
|
|
95
|
+
},
|
|
96
|
+
];
|
|
97
|
+
const TOKEN_TO_DOMAIN = new Map();
|
|
98
|
+
for (const entry of DOMAIN_LEXICON) {
|
|
99
|
+
for (const synonym of entry.synonyms) {
|
|
100
|
+
if (!TOKEN_TO_DOMAIN.has(synonym)) {
|
|
101
|
+
TOKEN_TO_DOMAIN.set(synonym, entry.name);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
export function domainForToken(token) {
|
|
106
|
+
return TOKEN_TO_DOMAIN.get(token);
|
|
107
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Path / name segments ignored when mining domain tokens. */
|
|
2
|
+
export declare const DOMAIN_STOP_SEGMENTS: Set<string>;
|
|
3
|
+
/**
|
|
4
|
+
* Split a relative path into lowercase semantic tokens.
|
|
5
|
+
* Deterministic: camelCase, snake_case, kebab-case, path segments.
|
|
6
|
+
*/
|
|
7
|
+
export declare function tokenizeRelativePath(relativePath: string): string[];
|