@monoes/monograph 1.5.6 → 1.5.7
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/README.md +25 -9
- package/dist/src/mcp-tools/impact.d.ts.map +1 -1
- package/dist/src/mcp-tools/impact.js +1 -10
- package/dist/src/mcp-tools/impact.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +12 -9
- package/.monomind/data/ranked-context.json +0 -5
- package/.monomind/loops/mastermind-review-1782162423447.json +0 -16
- package/.monomind/sessions/session-1777578175215.json +0 -15
- package/.monomind/sessions/session-1777823684507.json +0 -15
- package/.monomind/sessions/session-1777928944749.json +0 -15
- package/.monomind/sessions/session-1778052902210.json +0 -15
- package/.monomind/sessions/session-1778056744636.json +0 -15
- package/.monomind/sessions/session-1778061077599.json +0 -15
- package/.monomind/sessions/session-1778102154764.json +0 -15
- package/__tests__/analysis/shape-extractor.test.ts +0 -124
- package/__tests__/analysis/surprise-scorer.test.ts +0 -154
- package/__tests__/cache/extraction-cache.test.ts +0 -45
- package/__tests__/cli/ai-context.test.ts +0 -175
- package/__tests__/cli/augment.test.ts +0 -128
- package/__tests__/cli/doctor.test.ts +0 -125
- package/__tests__/cli/eval-server.test.ts +0 -89
- package/__tests__/cli/setup.test.ts +0 -178
- package/__tests__/cli/skill-gen.test.ts +0 -280
- package/__tests__/export/formats.test.ts +0 -82
- package/__tests__/fixtures/sample.c +0 -25
- package/__tests__/fixtures/sample.cpp +0 -32
- package/__tests__/fixtures/sample.dart +0 -34
- package/__tests__/fixtures/sample.kt +0 -30
- package/__tests__/fixtures/sample.php +0 -30
- package/__tests__/fixtures/sample.py +0 -11
- package/__tests__/fixtures/sample.rb +0 -26
- package/__tests__/fixtures/sample.swift +0 -42
- package/__tests__/fixtures/sample.ts +0 -17
- package/__tests__/fixtures/sample.vue +0 -40
- package/__tests__/groups/group-search.test.ts +0 -221
- package/__tests__/groups/group-sync.test.ts +0 -336
- package/__tests__/integration/build-atomicity.test.ts +0 -61
- package/__tests__/integration/call-attribution.test.ts +0 -116
- package/__tests__/integration/full-pipeline.test.ts +0 -64
- package/__tests__/integration/graph-report-freshness.test.ts +0 -53
- package/__tests__/integration/incremental-build.test.ts +0 -103
- package/__tests__/mcp-resources/resources.test.ts +0 -256
- package/__tests__/mcp-tools/api-impact.test.ts +0 -188
- package/__tests__/mcp-tools/context.test.ts +0 -130
- package/__tests__/mcp-tools/cypher.test.ts +0 -258
- package/__tests__/mcp-tools/detect-changes.test.ts +0 -114
- package/__tests__/mcp-tools/impact.test.ts +0 -133
- package/__tests__/mcp-tools/rename.test.ts +0 -117
- package/__tests__/mcp-tools/route-map.test.ts +0 -237
- package/__tests__/mcp-tools/shape-check.test.ts +0 -202
- package/__tests__/mcp-tools/tool-map.test.ts +0 -135
- package/__tests__/parsers/c.test.ts +0 -28
- package/__tests__/parsers/cpp.test.ts +0 -28
- package/__tests__/parsers/csharp.test.ts +0 -62
- package/__tests__/parsers/dart.test.ts +0 -28
- package/__tests__/parsers/kotlin.test.ts +0 -28
- package/__tests__/parsers/loader.test.ts +0 -14
- package/__tests__/parsers/php.test.ts +0 -28
- package/__tests__/parsers/python.test.ts +0 -32
- package/__tests__/parsers/ruby.test.ts +0 -33
- package/__tests__/parsers/swift.test.ts +0 -28
- package/__tests__/parsers/typescript.test.ts +0 -45
- package/__tests__/parsers/vue.test.ts +0 -28
- package/__tests__/pipeline/analysis.test.ts +0 -58
- package/__tests__/pipeline/phases/corpus-check.test.ts +0 -26
- package/__tests__/pipeline/phases/evidence.test.ts +0 -41
- package/__tests__/pipeline/phases/field-access.test.ts +0 -22
- package/__tests__/pipeline/phases/leiden.test.ts +0 -72
- package/__tests__/pipeline/phases/markdown.test.ts +0 -84
- package/__tests__/pipeline/phases/middleware-extractor.test.ts +0 -131
- package/__tests__/pipeline/phases/orm.test.ts +0 -379
- package/__tests__/pipeline/phases/processes.test.ts +0 -191
- package/__tests__/pipeline/phases/routes.test.ts +0 -195
- package/__tests__/pipeline/phases/scope-resolution.test.ts +0 -133
- package/__tests__/pipeline/phases/tools.test.ts +0 -161
- package/__tests__/pipeline/phases/variables.test.ts +0 -30
- package/__tests__/pipeline/phases/wildcard-synthesis.test.ts +0 -207
- package/__tests__/pipeline/phases.test.ts +0 -41
- package/__tests__/pipeline/runner.test.ts +0 -28
- package/__tests__/registry/repo-registry.test.ts +0 -127
- package/__tests__/reporting/graph-report.suggest.test.ts +0 -36
- package/__tests__/reporting/graph-report.test.ts +0 -165
- package/__tests__/search/ast-chunker.test.ts +0 -63
- package/__tests__/search/rrf.test.ts +0 -95
- package/__tests__/security/safe-fetch.test.ts +0 -41
- package/__tests__/security/sensitive-files.test.ts +0 -32
- package/__tests__/setup.ts +0 -1
- package/__tests__/skills/platform-skills.test.ts +0 -63
- package/__tests__/staleness/git-staleness.test.ts +0 -107
- package/__tests__/storage/db.test.ts +0 -37
- package/__tests__/storage/evidence-roundtrip.test.ts +0 -89
- package/__tests__/storage/stores.test.ts +0 -165
- package/__tests__/types.test.ts +0 -13
- package/__tests__/validation/extraction-validator.test.ts +0 -48
- package/__tests__/watch/watcher.test.ts +0 -31
- package/__tests__/web/analyze-api.test.ts +0 -66
- package/__tests__/web/api.test.ts +0 -210
- package/__tests__/web/mcp-http.test.ts +0 -67
- package/__tests__/web/react-ui.test.ts +0 -43
- package/__tests__/wiki/gist-publisher.test.ts +0 -66
- package/__tests__/wiki/providers.test.ts +0 -69
- package/__tests__/wiki/wiki-generator.test.ts +0 -260
- package/src/__tests__/analysis/benchmark.test.ts +0 -59
- package/src/__tests__/analysis/cluster-quality.test.ts +0 -106
- package/src/__tests__/analysis/corpus-health.test.ts +0 -33
- package/src/__tests__/analysis/dependency-health.test.ts +0 -105
- package/src/__tests__/analysis/file-classifier.test.ts +0 -50
- package/src/__tests__/analysis/node-similarity.test.ts +0 -81
- package/src/__tests__/cache/augment-cache.test.ts +0 -55
- package/src/__tests__/cli/check-update.test.ts +0 -42
- package/src/__tests__/cli/hooks-install.test.ts +0 -56
- package/src/__tests__/cli/hooks-marker.test.ts +0 -138
- package/src/__tests__/cli/hooks-status.test.ts +0 -42
- package/src/__tests__/export/adjacency-matrix.test.ts +0 -116
- package/src/__tests__/export/csv.test.ts +0 -39
- package/src/__tests__/export/dot.test.ts +0 -86
- package/src/__tests__/export/gexf.test.ts +0 -78
- package/src/__tests__/export/graphml.test.ts +0 -57
- package/src/__tests__/export/mermaid.test.ts +0 -89
- package/src/__tests__/graph/betweenness.test.ts +0 -89
- package/src/__tests__/graph/cycles.test.ts +0 -131
- package/src/__tests__/graph/dead-code.test.ts +0 -174
- package/src/__tests__/graph/dfs.test.ts +0 -62
- package/src/__tests__/graph/diff-summary.test.ts +0 -83
- package/src/__tests__/graph/edge-filter.test.ts +0 -129
- package/src/__tests__/graph/import-chain.test.ts +0 -111
- package/src/__tests__/graph/merge.test.ts +0 -151
- package/src/__tests__/graph/node-search.test.ts +0 -167
- package/src/__tests__/graph/normalize-id.test.ts +0 -102
- package/src/__tests__/graph/pagerank.test.ts +0 -96
- package/src/__tests__/graph/prune.test.ts +0 -110
- package/src/__tests__/graph/regex-search.test.ts +0 -166
- package/src/__tests__/graph/ripple-impact.test.ts +0 -73
- package/src/__tests__/graph/scc.test.ts +0 -85
- package/src/__tests__/graph/statistics.test.ts +0 -219
- package/src/__tests__/graph/subgraph.test.ts +0 -127
- package/src/__tests__/graph/topo-sort.test.ts +0 -110
- package/src/__tests__/graph/wcc.test.ts +0 -101
- package/src/__tests__/groups/grpc-extractor.test.ts +0 -47
- package/src/__tests__/groups/service-boundary.test.ts +0 -86
- package/src/__tests__/groups/topic-extractor.test.ts +0 -43
- package/src/__tests__/ingest/git-clone.test.ts +0 -128
- package/src/__tests__/ingest/query-memory.test.ts +0 -123
- package/src/__tests__/ingest/transcribe.test.ts +0 -58
- package/src/__tests__/ingest/url-ingest.test.ts +0 -48
- package/src/__tests__/mcp-resources/repo-context-resource.test.ts +0 -37
- package/src/__tests__/mcp-resources/repos-resource.test.ts +0 -71
- package/src/__tests__/mcp-resources/wiki-resource.test.ts +0 -52
- package/src/__tests__/mcp-tools/explain.test.ts +0 -46
- package/src/__tests__/mcp-tools/graph-query.test.ts +0 -45
- package/src/__tests__/mcp-tools/group-sync.test.ts +0 -8
- package/src/__tests__/mcp-tools/impact-filtering.test.ts +0 -48
- package/src/__tests__/mcp-tools/impact.risk.test.ts +0 -24
- package/src/__tests__/mcp-tools/list-repos.test.ts +0 -24
- package/src/__tests__/mcp-tools/neighbors.test.ts +0 -48
- package/src/__tests__/mcp-tools/query.test.ts +0 -42
- package/src/__tests__/parsers/language-parsers.test.ts +0 -52
- package/src/__tests__/parsers/named-bindings.test.ts +0 -73
- package/src/__tests__/pipeline/cluster-only.test.ts +0 -33
- package/src/__tests__/pipeline/phases/bridge-adapters/electron-ipc.test.ts +0 -87
- package/src/__tests__/pipeline/phases/bridge-adapters/tauri.test.ts +0 -116
- package/src/__tests__/pipeline/phases/bridge-adapters/wails.test.ts +0 -81
- package/src/__tests__/pipeline/phases/bridge-resolver.test.ts +0 -110
- package/src/__tests__/pipeline/phases/communities.cohesion.test.ts +0 -43
- package/src/__tests__/pipeline/phases/community-split.test.ts +0 -30
- package/src/__tests__/pipeline/phases/framework-detect.test.ts +0 -65
- package/src/__tests__/pipeline/phases/import-resolver.test.ts +0 -64
- package/src/__tests__/pipeline/phases/parse-arrow.test.ts +0 -33
- package/src/__tests__/pipeline/phases/parse-csharp.test.ts +0 -33
- package/src/__tests__/pipeline/phases/scan.monographignore.test.ts +0 -53
- package/src/__tests__/pipeline/phases/scan.negation.test.ts +0 -40
- package/src/__tests__/pipeline/phases/scope-resolution.go.test.ts +0 -34
- package/src/__tests__/pipeline/phases/scope-resolution.java.test.ts +0 -30
- package/src/__tests__/pipeline/phases/scope-resolution.rust.test.ts +0 -31
- package/src/__tests__/pipeline/phases/suggest-questions.test.ts +0 -46
- package/src/__tests__/pipeline/phases/surprises-scoring.test.ts +0 -46
- package/src/__tests__/pipeline/phases/variables-phase.test.ts +0 -78
- package/src/__tests__/pipeline/phases/wildcard-phase.test.ts +0 -99
- package/src/__tests__/pipeline/runner.parallel.test.ts +0 -78
- package/src/__tests__/reporting/graph-report-confidence.test.ts +0 -43
- package/src/__tests__/reporting/graph-report-gaps.test.ts +0 -41
- package/src/__tests__/scope-resolution/call-sites.test.ts +0 -89
- package/src/__tests__/scope-resolution/evidence-weights.test.ts +0 -49
- package/src/__tests__/search/diacritic.test.ts +0 -23
- package/src/__tests__/security/safe-fetch.test.ts +0 -125
- package/src/__tests__/skills/platform-skills.extra.test.ts +0 -36
- package/src/__tests__/web/api.clusters.test.ts +0 -65
- package/src/__tests__/web/api.file.test.ts +0 -44
- package/src/__tests__/web/api.grep.test.ts +0 -47
- package/src/__tests__/web/api.info.test.ts +0 -18
- package/src/__tests__/web/api.jobs.test.ts +0 -47
- package/src/__tests__/web/api.progress.test.ts +0 -25
- package/src/__tests__/web/api.stream.test.ts +0 -35
- package/src/__tests__/wiki/providers-reasoning.test.ts +0 -46
- package/src/__tests__/wiki/wiki-review-mode.test.ts +0 -22
- package/src/analysis/benchmark.ts +0 -132
- package/src/analysis/changed-files.ts +0 -73
- package/src/analysis/changed-workspaces.ts +0 -94
- package/src/analysis/churn-cache.ts +0 -179
- package/src/analysis/churn-trend.ts +0 -57
- package/src/analysis/churn.ts +0 -263
- package/src/analysis/cluster-quality.ts +0 -142
- package/src/analysis/combined.ts +0 -41
- package/src/analysis/corpus-health.ts +0 -41
- package/src/analysis/coverage-gaps.ts +0 -246
- package/src/analysis/dep-classification.ts +0 -167
- package/src/analysis/dependency-health.ts +0 -146
- package/src/analysis/duplicate-exports.ts +0 -110
- package/src/analysis/fallow-suppression.ts +0 -98
- package/src/analysis/feature-flags-config.ts +0 -47
- package/src/analysis/feature-flags.ts +0 -223
- package/src/analysis/file-classifier.ts +0 -87
- package/src/analysis/git-changed-files.ts +0 -62
- package/src/analysis/health-baseline.ts +0 -80
- package/src/analysis/issue-filters.ts +0 -56
- package/src/analysis/list.ts +0 -74
- package/src/analysis/node-similarity.ts +0 -115
- package/src/analysis/private-type-leaks.ts +0 -119
- package/src/analysis/progress.ts +0 -43
- package/src/analysis/project-state.ts +0 -95
- package/src/analysis/regression-config.ts +0 -36
- package/src/analysis/rule-overrides.ts +0 -81
- package/src/analysis/scripts.ts +0 -95
- package/src/analysis/shape-extractor.ts +0 -202
- package/src/analysis/since-duration.ts +0 -42
- package/src/analysis/suppression-context.ts +0 -95
- package/src/analysis/suppressions.ts +0 -80
- package/src/analysis/surprise-scorer.ts +0 -74
- package/src/analysis/targets.ts +0 -237
- package/src/analysis/unused-class-members.ts +0 -79
- package/src/analysis/workspace-filter.ts +0 -89
- package/src/analyze/boundary-analysis.ts +0 -129
- package/src/analyze/predicates/file.ts +0 -86
- package/src/analyze/predicates/import.ts +0 -90
- package/src/analyze/predicates/lifecycle.ts +0 -55
- package/src/analyze/unused-deps.ts +0 -70
- package/src/analyze/unused-exports.ts +0 -145
- package/src/analyze/unused-files.ts +0 -46
- package/src/api/production-override.ts +0 -63
- package/src/api/programmatic.ts +0 -118
- package/src/audit.ts +0 -234
- package/src/cache/augment-cache.ts +0 -63
- package/src/cache/extraction-cache.ts +0 -141
- package/src/check/filtering.ts +0 -78
- package/src/check/index.ts +0 -99
- package/src/check/output.ts +0 -79
- package/src/check/rules.ts +0 -61
- package/src/ci-template.ts +0 -84
- package/src/claude-cli.ts +0 -59
- package/src/cli/ai-context.ts +0 -193
- package/src/cli/augment.ts +0 -114
- package/src/cli/check-update.ts +0 -40
- package/src/cli/doctor.ts +0 -182
- package/src/cli/eval-server.ts +0 -126
- package/src/cli/hooks-install.ts +0 -202
- package/src/cli/setup.ts +0 -197
- package/src/cli/skill-gen.ts +0 -347
- package/src/commands/flags.ts +0 -72
- package/src/config/boundary-config.ts +0 -183
- package/src/config/cli-schema.ts +0 -81
- package/src/config/config-parsing.ts +0 -102
- package/src/config/duplicates-config.ts +0 -62
- package/src/config/external-plugin.ts +0 -77
- package/src/config/health-config.ts +0 -42
- package/src/config/ignore-exports-used-in-file.ts +0 -46
- package/src/config/migration-types.ts +0 -73
- package/src/config/output-format.ts +0 -24
- package/src/config/plugins/builtin.ts +0 -411
- package/src/config/plugins/registry.ts +0 -77
- package/src/config/plugins/types.ts +0 -14
- package/src/config/resolution.ts +0 -102
- package/src/config/rules.ts +0 -70
- package/src/config/schema-gen.ts +0 -115
- package/src/config/types.ts +0 -149
- package/src/config/used-class-members.ts +0 -53
- package/src/config/validate.ts +0 -108
- package/src/config/workspace.ts +0 -137
- package/src/coverage/cloud-client.ts +0 -111
- package/src/coverage/upload-inventory.ts +0 -84
- package/src/coverage/upload-source-maps.ts +0 -97
- package/src/discover/entry-points.ts +0 -51
- package/src/discover/infrastructure-entries.ts +0 -175
- package/src/duplicates/detect/concatenation.ts +0 -37
- package/src/duplicates/detect/extraction.ts +0 -107
- package/src/duplicates/detect/filtering.ts +0 -112
- package/src/duplicates/detect/lcp.ts +0 -27
- package/src/duplicates/detect/ranking.ts +0 -16
- package/src/duplicates/detect/statistics.ts +0 -69
- package/src/duplicates/detect/suffix-array.ts +0 -88
- package/src/duplicates/families.ts +0 -95
- package/src/duplicates/normalize.ts +0 -58
- package/src/duplicates/shingle-filter.ts +0 -37
- package/src/duplicates/token-types.ts +0 -62
- package/src/duplicates/tokenize/index.ts +0 -104
- package/src/error/fallow-error.ts +0 -94
- package/src/error.ts +0 -47
- package/src/export/adjacency-matrix.ts +0 -127
- package/src/export/analysis-json.ts +0 -87
- package/src/export/badge.ts +0 -105
- package/src/export/canvas.ts +0 -42
- package/src/export/codeclimate.ts +0 -201
- package/src/export/compact-health.ts +0 -119
- package/src/export/compact.ts +0 -83
- package/src/export/csv.ts +0 -33
- package/src/export/cypher.ts +0 -33
- package/src/export/dot.ts +0 -52
- package/src/export/gexf.ts +0 -59
- package/src/export/graphml.ts +0 -50
- package/src/export/html.ts +0 -548
- package/src/export/index.ts +0 -9
- package/src/export/json.ts +0 -36
- package/src/export/markdown.ts +0 -290
- package/src/export/mermaid.ts +0 -100
- package/src/export/obsidian.ts +0 -44
- package/src/export/sarif.ts +0 -245
- package/src/export/svg.ts +0 -68
- package/src/fix/deps.ts +0 -70
- package/src/fix/enum-members.ts +0 -103
- package/src/fix/export-surgery.ts +0 -197
- package/src/fix/exports.ts +0 -93
- package/src/fix/orchestrator.ts +0 -67
- package/src/graph/analyzer.ts +0 -69
- package/src/graph/author-analytics.ts +0 -217
- package/src/graph/baseline.ts +0 -432
- package/src/graph/clone-families.ts +0 -132
- package/src/graph/codeowners-extended.ts +0 -114
- package/src/graph/codeowners-gitlab.ts +0 -150
- package/src/graph/codeowners.ts +0 -217
- package/src/graph/complexity.ts +0 -200
- package/src/graph/cross-reference-findings.ts +0 -85
- package/src/graph/cross-reference.ts +0 -139
- package/src/graph/cycle-detection.ts +0 -311
- package/src/graph/cycles.ts +0 -222
- package/src/graph/dead-code.ts +0 -128
- package/src/graph/dependency-closure.ts +0 -126
- package/src/graph/dfs.ts +0 -118
- package/src/graph/diff.ts +0 -92
- package/src/graph/duplication-stats.ts +0 -79
- package/src/graph/edge-filter.ts +0 -117
- package/src/graph/explain.ts +0 -133
- package/src/graph/external-style-usage.ts +0 -81
- package/src/graph/health-score.ts +0 -179
- package/src/graph/hotspots.ts +0 -219
- package/src/graph/import-chain.ts +0 -148
- package/src/graph/loader.ts +0 -44
- package/src/graph/maintainability.ts +0 -156
- package/src/graph/merge.ts +0 -174
- package/src/graph/mirrored-dirs.ts +0 -202
- package/src/graph/narrowing.ts +0 -92
- package/src/graph/node-search.ts +0 -201
- package/src/graph/node-types.ts +0 -67
- package/src/graph/normalize-id.ts +0 -138
- package/src/graph/pagerank.ts +0 -165
- package/src/graph/prune.ts +0 -95
- package/src/graph/re-exports/propagate.ts +0 -95
- package/src/graph/reachability.ts +0 -99
- package/src/graph/regex-search.ts +0 -232
- package/src/graph/regression.ts +0 -199
- package/src/graph/resolve/discover-types.ts +0 -45
- package/src/graph/resolve/dynamic-imports.ts +0 -102
- package/src/graph/resolve/fallbacks.ts +0 -79
- package/src/graph/resolve/index.ts +0 -68
- package/src/graph/resolve/path-info.ts +0 -41
- package/src/graph/resolve/re-exports.ts +0 -14
- package/src/graph/resolve/react-native.ts +0 -27
- package/src/graph/resolve/require-imports.ts +0 -18
- package/src/graph/resolve/specifier.ts +0 -120
- package/src/graph/resolve/static-imports.ts +0 -14
- package/src/graph/resolve/types.ts +0 -108
- package/src/graph/resolve/upgrades.ts +0 -32
- package/src/graph/ripple-impact.ts +0 -131
- package/src/graph/risk-profile.ts +0 -179
- package/src/graph/statistics.ts +0 -165
- package/src/graph/stats.ts +0 -157
- package/src/graph/subgraph.ts +0 -162
- package/src/graph/topo-sort.ts +0 -171
- package/src/graph/wcc.ts +0 -187
- package/src/groups/contract-bridge.ts +0 -103
- package/src/groups/contract-registry.ts +0 -263
- package/src/groups/group-config.ts +0 -108
- package/src/groups/group-search.ts +0 -139
- package/src/groups/group-sync.ts +0 -82
- package/src/groups/grpc-extractor.ts +0 -64
- package/src/groups/service-boundary.ts +0 -119
- package/src/groups/topic-extractor.ts +0 -90
- package/src/health/analysis-counts-snapshot.ts +0 -57
- package/src/health/analysis-counts.ts +0 -70
- package/src/health/complexity-findings.ts +0 -115
- package/src/health/distribution-thresholds.ts +0 -54
- package/src/health/grouping.ts +0 -138
- package/src/health/health-grouping.ts +0 -86
- package/src/health/health-report-types.ts +0 -165
- package/src/health/health-report.ts +0 -81
- package/src/health/health-score.ts +0 -65
- package/src/health/hotspot-utils.ts +0 -55
- package/src/health/hotspots.ts +0 -104
- package/src/health/large-functions.ts +0 -34
- package/src/health/ownership-metrics.ts +0 -61
- package/src/health/ownership-risk.ts +0 -98
- package/src/health/ownership.ts +0 -174
- package/src/health/quality-gate.ts +0 -57
- package/src/health/risk-profile.ts +0 -39
- package/src/health/runtime-coverage-report.ts +0 -101
- package/src/health/runtime-coverage.ts +0 -71
- package/src/health/scores.ts +0 -72
- package/src/health/scoring-types.ts +0 -48
- package/src/health/target-thresholds.ts +0 -92
- package/src/health/target-types.ts +0 -54
- package/src/health/targets.ts +0 -151
- package/src/health/timings.ts +0 -86
- package/src/health/trend-types.ts +0 -57
- package/src/health/trends.ts +0 -86
- package/src/health/vital-signs-compute.ts +0 -108
- package/src/health/vital-signs-snapshot.ts +0 -72
- package/src/health/vital-signs.ts +0 -101
- package/src/index.ts +0 -111
- package/src/ingest/git-clone.ts +0 -246
- package/src/ingest/query-memory.ts +0 -132
- package/src/ingest/transcribe.ts +0 -254
- package/src/ingest/url-ingest.ts +0 -87
- package/src/init/agent-hooks.ts +0 -86
- package/src/init/git-hooks.ts +0 -71
- package/src/init/project-detection.ts +0 -105
- package/src/license/manager.ts +0 -120
- package/src/lsp/code-actions.ts +0 -127
- package/src/lsp/code-lens.ts +0 -56
- package/src/lsp/diagnostics-ext.ts +0 -150
- package/src/lsp/diagnostics-push.ts +0 -103
- package/src/lsp/diagnostics.ts +0 -98
- package/src/lsp/hover.ts +0 -64
- package/src/lsp/server.ts +0 -254
- package/src/mcp/params.ts +0 -201
- package/src/mcp/resources.ts +0 -124
- package/src/mcp/tool-builders.ts +0 -203
- package/src/mcp-resources/communities-resource.ts +0 -72
- package/src/mcp-resources/graph-resource.ts +0 -14
- package/src/mcp-resources/index.ts +0 -9
- package/src/mcp-resources/named-cluster-resource.ts +0 -35
- package/src/mcp-resources/named-process-resource.ts +0 -26
- package/src/mcp-resources/processes-resource.ts +0 -67
- package/src/mcp-resources/repo-context-resource.ts +0 -36
- package/src/mcp-resources/repos-resource.ts +0 -21
- package/src/mcp-resources/schema-resource.ts +0 -46
- package/src/mcp-resources/wiki-resource.ts +0 -23
- package/src/mcp-tools/api-impact.ts +0 -181
- package/src/mcp-tools/context.ts +0 -111
- package/src/mcp-tools/cypher.ts +0 -29
- package/src/mcp-tools/detect-changes.ts +0 -116
- package/src/mcp-tools/explain.ts +0 -65
- package/src/mcp-tools/graph-query.ts +0 -128
- package/src/mcp-tools/group-list.ts +0 -88
- package/src/mcp-tools/group-query.ts +0 -26
- package/src/mcp-tools/group-sync.ts +0 -32
- package/src/mcp-tools/impact.ts +0 -202
- package/src/mcp-tools/index.ts +0 -21
- package/src/mcp-tools/list-repos.ts +0 -38
- package/src/mcp-tools/neighbors.ts +0 -80
- package/src/mcp-tools/query.ts +0 -86
- package/src/mcp-tools/rename.ts +0 -118
- package/src/mcp-tools/route-map.ts +0 -98
- package/src/mcp-tools/serve.ts +0 -41
- package/src/mcp-tools/shape-check.ts +0 -182
- package/src/mcp-tools/staleness.ts +0 -13
- package/src/mcp-tools/tool-map.ts +0 -66
- package/src/mcp-tools/wiki-build.ts +0 -37
- package/src/mcp-tools/wiki.ts +0 -28
- package/src/migrate/jscpd.ts +0 -78
- package/src/migrate/jsonc-gen.ts +0 -38
- package/src/migrate/knip.ts +0 -126
- package/src/migrate/toml-gen.ts +0 -48
- package/src/parsers/c.ts +0 -31
- package/src/parsers/cpp.ts +0 -29
- package/src/parsers/csharp.ts +0 -43
- package/src/parsers/dart.ts +0 -39
- package/src/parsers/extractor.ts +0 -202
- package/src/parsers/go.ts +0 -27
- package/src/parsers/java.ts +0 -27
- package/src/parsers/kotlin.ts +0 -36
- package/src/parsers/language-config.ts +0 -28
- package/src/parsers/language-parsers.ts +0 -120
- package/src/parsers/loader.ts +0 -149
- package/src/parsers/named-bindings.ts +0 -63
- package/src/parsers/php.ts +0 -37
- package/src/parsers/python.ts +0 -26
- package/src/parsers/ruby.ts +0 -39
- package/src/parsers/rust.ts +0 -25
- package/src/parsers/swift.ts +0 -28
- package/src/parsers/typescript.ts +0 -41
- package/src/parsers/vue.ts +0 -79
- package/src/pipeline/cluster-only.ts +0 -64
- package/src/pipeline/effort.ts +0 -50
- package/src/pipeline/orchestrator.ts +0 -384
- package/src/pipeline/phases/boundary.ts +0 -151
- package/src/pipeline/phases/bridge-adapters/electron-ipc.ts +0 -91
- package/src/pipeline/phases/bridge-adapters/registry.ts +0 -14
- package/src/pipeline/phases/bridge-adapters/tauri.ts +0 -103
- package/src/pipeline/phases/bridge-adapters/types.ts +0 -31
- package/src/pipeline/phases/bridge-adapters/wails.ts +0 -33
- package/src/pipeline/phases/bridge-resolver.ts +0 -77
- package/src/pipeline/phases/call-site-extractors.ts +0 -177
- package/src/pipeline/phases/communities.ts +0 -183
- package/src/pipeline/phases/contextual-proximity.ts +0 -88
- package/src/pipeline/phases/cross-file.ts +0 -116
- package/src/pipeline/phases/docs-parse.ts +0 -307
- package/src/pipeline/phases/evidence.ts +0 -9
- package/src/pipeline/phases/field-access.ts +0 -49
- package/src/pipeline/phases/framework-detect.ts +0 -109
- package/src/pipeline/phases/god-nodes.ts +0 -163
- package/src/pipeline/phases/import-resolver.ts +0 -114
- package/src/pipeline/phases/leiden.ts +0 -77
- package/src/pipeline/phases/llm-extract.ts +0 -178
- package/src/pipeline/phases/markdown.ts +0 -121
- package/src/pipeline/phases/middleware-extractor.ts +0 -127
- package/src/pipeline/phases/module-resolution.ts +0 -294
- package/src/pipeline/phases/mro.ts +0 -56
- package/src/pipeline/phases/orm.ts +0 -503
- package/src/pipeline/phases/parse.ts +0 -222
- package/src/pipeline/phases/pdf-parse.ts +0 -133
- package/src/pipeline/phases/processes.ts +0 -249
- package/src/pipeline/phases/re-export-propagation.ts +0 -160
- package/src/pipeline/phases/reachability.ts +0 -156
- package/src/pipeline/phases/routes.ts +0 -350
- package/src/pipeline/phases/scan.ts +0 -133
- package/src/pipeline/phases/scope-resolution.ts +0 -442
- package/src/pipeline/phases/structure.ts +0 -68
- package/src/pipeline/phases/suggest.ts +0 -92
- package/src/pipeline/phases/surprises.ts +0 -83
- package/src/pipeline/phases/tools.ts +0 -180
- package/src/pipeline/phases/variables-phase.ts +0 -37
- package/src/pipeline/phases/variables.ts +0 -67
- package/src/pipeline/phases/wildcard-phase.ts +0 -50
- package/src/pipeline/phases/wildcard-synthesis.ts +0 -214
- package/src/pipeline/progress.ts +0 -58
- package/src/pipeline/runner.ts +0 -88
- package/src/pipeline/types.ts +0 -41
- package/src/query/cypher-parser.ts +0 -450
- package/src/registry/repo-registry.ts +0 -125
- package/src/regression/baseline-deltas.ts +0 -215
- package/src/regression/baseline.ts +0 -76
- package/src/regression/counts.ts +0 -87
- package/src/regression/outcome.ts +0 -78
- package/src/regression/tolerance.ts +0 -35
- package/src/report/attributed-duplication.ts +0 -112
- package/src/report/badge-svg.ts +0 -100
- package/src/report/cross-ref-human.ts +0 -50
- package/src/report/duplication-grouping.ts +0 -74
- package/src/report/grouping.ts +0 -137
- package/src/report/human-check.ts +0 -291
- package/src/report/human-dupes.ts +0 -142
- package/src/report/human-health.ts +0 -195
- package/src/report/human.ts +0 -120
- package/src/report/json-actions.ts +0 -91
- package/src/report/json-builders.ts +0 -70
- package/src/report/json-schema.ts +0 -75
- package/src/report/number-format.ts +0 -91
- package/src/report/output-grouped.ts +0 -102
- package/src/report/pipeline-perf.ts +0 -56
- package/src/report/trace-human.ts +0 -127
- package/src/reporting/graph-report.ts +0 -431
- package/src/results/fallow-results.ts +0 -152
- package/src/results/types.ts +0 -149
- package/src/scope-resolution/evidence-weights.ts +0 -41
- package/src/search/ast-chunker.ts +0 -206
- package/src/search/diacritic.ts +0 -7
- package/src/search/hybrid-query.ts +0 -65
- package/src/search/rrf.ts +0 -51
- package/src/security/safe-fetch.ts +0 -113
- package/src/security/sensitive-files.ts +0 -24
- package/src/skills/platform-skills.ts +0 -233
- package/src/staleness/git-staleness.ts +0 -66
- package/src/storage/db.ts +0 -110
- package/src/storage/edge-store.ts +0 -103
- package/src/storage/file-cache.ts +0 -78
- package/src/storage/fts-store.ts +0 -385
- package/src/storage/node-store.ts +0 -209
- package/src/storage/schema.ts +0 -171
- package/src/storage/suppressions.ts +0 -145
- package/src/storage/unlinked-refs.ts +0 -117
- package/src/types.ts +0 -197
- package/src/validation/extraction-validator.ts +0 -54
- package/src/watch/watcher.ts +0 -160
- package/src/web/analyze-api.ts +0 -146
- package/src/web/api.ts +0 -584
- package/src/web/async-jobs.ts +0 -109
- package/src/web/mcp-http.ts +0 -227
- package/src/web/react-ui.ts +0 -78
- package/src/web/server.ts +0 -90
- package/src/web/ui/index.html +0 -204
- package/src/wiki/gist-publisher.ts +0 -76
- package/src/wiki/prompt-builder.ts +0 -35
- package/src/wiki/providers.ts +0 -134
- package/src/wiki/wiki-generator.ts +0 -223
- package/src/wiki/wiki-store.ts +0 -49
- package/tsconfig.json +0 -11
- package/vitest.config.ts +0 -20
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
import { execSync, spawnSync } from 'child_process';
|
|
2
|
-
import type { MonographDb } from '../storage/db.js';
|
|
3
|
-
|
|
4
|
-
export type ChurnTrend = 'accelerating' | 'stable' | 'declining';
|
|
5
|
-
|
|
6
|
-
export interface AuthorStats {
|
|
7
|
-
author: string;
|
|
8
|
-
commitCount: number;
|
|
9
|
-
filesOwned: number; // files where this author has majority of commits
|
|
10
|
-
recentCommits: number; // commits in last 30 days
|
|
11
|
-
churnTrend: ChurnTrend;
|
|
12
|
-
isBot: boolean;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface AuthorAnalyticsReport {
|
|
16
|
-
authors: AuthorStats[];
|
|
17
|
-
topOwners: AuthorStats[]; // top 5 by filesOwned
|
|
18
|
-
botAuthors: string[];
|
|
19
|
-
unownedFiles: number; // files with no majority owner
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const BOT_PATTERNS = ['[bot]', 'noreply', 'github-actions', 'dependabot', 'renovate'];
|
|
23
|
-
|
|
24
|
-
function isBot(email: string): boolean {
|
|
25
|
-
const lower = email.toLowerCase();
|
|
26
|
-
return BOT_PATTERNS.some(p => lower.includes(p));
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const EMPTY_REPORT: AuthorAnalyticsReport = {
|
|
30
|
-
authors: [],
|
|
31
|
-
topOwners: [],
|
|
32
|
-
botAuthors: [],
|
|
33
|
-
unownedFiles: 0,
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export function computeAuthorAnalytics(repoPath: string, db: MonographDb): AuthorAnalyticsReport {
|
|
37
|
-
// ── Parse git log ──────────────────────────────────────────────────────────
|
|
38
|
-
let logOutput: string;
|
|
39
|
-
try {
|
|
40
|
-
logOutput = execSync('git log --format="%ae|%ad" --date=unix', {
|
|
41
|
-
cwd: repoPath,
|
|
42
|
-
encoding: 'utf-8',
|
|
43
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
44
|
-
});
|
|
45
|
-
} catch {
|
|
46
|
-
return EMPTY_REPORT;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const now = Math.floor(Date.now() / 1000);
|
|
50
|
-
const thirtyDaysAgo = now - 86400 * 30;
|
|
51
|
-
const sixtyDaysAgo = now - 86400 * 60;
|
|
52
|
-
|
|
53
|
-
// commitCount, recentCommits, priorCommits per author
|
|
54
|
-
const commitCount = new Map<string, number>();
|
|
55
|
-
const recentCommits = new Map<string, number>();
|
|
56
|
-
const priorCommits = new Map<string, number>();
|
|
57
|
-
|
|
58
|
-
for (const line of logOutput.split('\n')) {
|
|
59
|
-
const trimmed = line.trim().replace(/^"|"$/g, '');
|
|
60
|
-
if (!trimmed) continue;
|
|
61
|
-
const pipeIdx = trimmed.indexOf('|');
|
|
62
|
-
if (pipeIdx === -1) continue;
|
|
63
|
-
const email = trimmed.slice(0, pipeIdx).trim();
|
|
64
|
-
const tsStr = trimmed.slice(pipeIdx + 1).trim();
|
|
65
|
-
const ts = parseInt(tsStr, 10);
|
|
66
|
-
if (!email || isNaN(ts)) continue;
|
|
67
|
-
|
|
68
|
-
commitCount.set(email, (commitCount.get(email) ?? 0) + 1);
|
|
69
|
-
if (ts > thirtyDaysAgo) {
|
|
70
|
-
recentCommits.set(email, (recentCommits.get(email) ?? 0) + 1);
|
|
71
|
-
} else if (ts > sixtyDaysAgo) {
|
|
72
|
-
priorCommits.set(email, (priorCommits.get(email) ?? 0) + 1);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (commitCount.size === 0) return EMPTY_REPORT;
|
|
77
|
-
|
|
78
|
-
// ── File ownership ─────────────────────────────────────────────────────────
|
|
79
|
-
// Get File nodes with degree > 2 — use JOIN+GROUP BY instead of correlated subquery
|
|
80
|
-
const fileRows = db.prepare(`
|
|
81
|
-
SELECT n.id, n.name, n.file_path
|
|
82
|
-
FROM nodes n
|
|
83
|
-
JOIN (
|
|
84
|
-
SELECT id, COUNT(*) AS deg
|
|
85
|
-
FROM (
|
|
86
|
-
SELECT source_id AS id FROM edges
|
|
87
|
-
UNION ALL
|
|
88
|
-
SELECT target_id AS id FROM edges
|
|
89
|
-
)
|
|
90
|
-
GROUP BY id
|
|
91
|
-
HAVING COUNT(*) > 2
|
|
92
|
-
) deg_tbl ON deg_tbl.id = n.id
|
|
93
|
-
WHERE n.label = 'File'
|
|
94
|
-
AND n.file_path IS NOT NULL
|
|
95
|
-
LIMIT 200
|
|
96
|
-
`).all() as { id: string; name: string; file_path: string }[];
|
|
97
|
-
|
|
98
|
-
// Map: file path → winning author email (majority owner) or null
|
|
99
|
-
const fileOwner = new Map<string, string | null>();
|
|
100
|
-
const filesOwnedByAuthor = new Map<string, number>();
|
|
101
|
-
|
|
102
|
-
for (const file of fileRows) {
|
|
103
|
-
const filePath = file.file_path;
|
|
104
|
-
if (!filePath) { fileOwner.set(file.id, null); continue; }
|
|
105
|
-
|
|
106
|
-
let fileLog: string;
|
|
107
|
-
try {
|
|
108
|
-
const result = spawnSync('git', ['log', '--follow', '--format=%ae', '--', filePath], {
|
|
109
|
-
cwd: repoPath,
|
|
110
|
-
encoding: 'utf-8',
|
|
111
|
-
});
|
|
112
|
-
if (result.status !== 0 || result.error) {
|
|
113
|
-
fileOwner.set(file.id, null);
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
116
|
-
fileLog = result.stdout;
|
|
117
|
-
} catch {
|
|
118
|
-
fileOwner.set(file.id, null);
|
|
119
|
-
continue;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const authorCounts = new Map<string, number>();
|
|
123
|
-
for (const ae of fileLog.split('\n')) {
|
|
124
|
-
const e = ae.trim().replace(/^"|"$/g, '');
|
|
125
|
-
if (!e) continue;
|
|
126
|
-
authorCounts.set(e, (authorCounts.get(e) ?? 0) + 1);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
let totalCommitsOnFile = 0;
|
|
130
|
-
for (const c of authorCounts.values()) totalCommitsOnFile += c;
|
|
131
|
-
|
|
132
|
-
let winner: string | null = null;
|
|
133
|
-
for (const [ae, c] of authorCounts) {
|
|
134
|
-
if (totalCommitsOnFile > 0 && c / totalCommitsOnFile > 0.5) {
|
|
135
|
-
winner = ae;
|
|
136
|
-
break;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
fileOwner.set(file.id, winner);
|
|
140
|
-
if (winner) {
|
|
141
|
-
filesOwnedByAuthor.set(winner, (filesOwnedByAuthor.get(winner) ?? 0) + 1);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// ── Count unowned files ────────────────────────────────────────────────────
|
|
146
|
-
let unownedFiles = 0;
|
|
147
|
-
for (const owner of fileOwner.values()) {
|
|
148
|
-
if (owner === null) unownedFiles++;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// ── Build author stats ─────────────────────────────────────────────────────
|
|
152
|
-
const authors: AuthorStats[] = [];
|
|
153
|
-
const botAuthors: string[] = [];
|
|
154
|
-
|
|
155
|
-
for (const [email, count] of commitCount) {
|
|
156
|
-
const recent = recentCommits.get(email) ?? 0;
|
|
157
|
-
const prior = priorCommits.get(email) ?? 0;
|
|
158
|
-
|
|
159
|
-
let churnTrend: ChurnTrend;
|
|
160
|
-
if (recent > prior * 1.2) churnTrend = 'accelerating';
|
|
161
|
-
else if (recent < prior * 0.8) churnTrend = 'declining';
|
|
162
|
-
else churnTrend = 'stable';
|
|
163
|
-
|
|
164
|
-
const bot = isBot(email);
|
|
165
|
-
if (bot) botAuthors.push(email);
|
|
166
|
-
|
|
167
|
-
authors.push({
|
|
168
|
-
author: email,
|
|
169
|
-
commitCount: count,
|
|
170
|
-
filesOwned: filesOwnedByAuthor.get(email) ?? 0,
|
|
171
|
-
recentCommits: recent,
|
|
172
|
-
churnTrend,
|
|
173
|
-
isBot: bot,
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// Sort by filesOwned desc, then commitCount desc
|
|
178
|
-
authors.sort((a, b) => b.filesOwned - a.filesOwned || b.commitCount - a.commitCount);
|
|
179
|
-
|
|
180
|
-
const topOwners = authors.filter(a => !a.isBot).slice(0, 5);
|
|
181
|
-
|
|
182
|
-
return { authors, topOwners, botAuthors, unownedFiles };
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/** Format AuthorAnalyticsReport as structured text for LLM navigation. */
|
|
186
|
-
export function formatAuthorAnalytics(report: AuthorAnalyticsReport): string {
|
|
187
|
-
if (report.authors.length === 0) {
|
|
188
|
-
return 'Author analytics: no commit history found.';
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const lines: string[] = [
|
|
192
|
-
`Author analytics: ${report.authors.length} contributor(s), ${report.unownedFiles} unowned file(s).`,
|
|
193
|
-
'',
|
|
194
|
-
];
|
|
195
|
-
|
|
196
|
-
if (report.topOwners.length > 0) {
|
|
197
|
-
lines.push('Top file owners (non-bot):');
|
|
198
|
-
for (const a of report.topOwners) {
|
|
199
|
-
const trend = a.churnTrend === 'accelerating' ? ' [↑ accelerating]'
|
|
200
|
-
: a.churnTrend === 'declining' ? ' [↓ declining]' : '';
|
|
201
|
-
lines.push(` ${a.author} files:${a.filesOwned} commits:${a.commitCount} recent30d:${a.recentCommits}${trend}`);
|
|
202
|
-
}
|
|
203
|
-
lines.push('');
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
if (report.botAuthors.length > 0) {
|
|
207
|
-
lines.push(`Bot/automation authors (${report.botAuthors.length}): ${report.botAuthors.join(', ')}`);
|
|
208
|
-
lines.push('');
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
if (report.unownedFiles > 0) {
|
|
212
|
-
lines.push(`Unowned files: ${report.unownedFiles} file(s) have no majority author (> 50% commits).`);
|
|
213
|
-
lines.push('Consider adding CODEOWNERS entries for these files.');
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
return lines.join('\n').trimEnd();
|
|
217
|
-
}
|
package/src/graph/baseline.ts
DELETED
|
@@ -1,432 +0,0 @@
|
|
|
1
|
-
import type Database from 'better-sqlite3';
|
|
2
|
-
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
3
|
-
import { join } from 'path';
|
|
4
|
-
import { createHash } from 'crypto';
|
|
5
|
-
|
|
6
|
-
function fingerprintFinding(type: string, ...parts: string[]): string {
|
|
7
|
-
return createHash('sha256').update([type, ...parts].join('::')).digest('hex').slice(0, 16);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface BaselineFinding {
|
|
11
|
-
/** Stable identifier: e.g. "file:src/foo.ts:export:bar" or "community:12:orphan" */
|
|
12
|
-
key: string;
|
|
13
|
-
type: 'unreachable_export' | 'isolated_node' | 'ambiguous_edge' | 'bridge_node' | 'surprise' | 'god_node' | 'other';
|
|
14
|
-
nodeId: string;
|
|
15
|
-
nodeName: string;
|
|
16
|
-
filePath: string | null;
|
|
17
|
-
startLine: number | null;
|
|
18
|
-
savedAt: string; // ISO timestamp
|
|
19
|
-
/** 16-hex SHA-256 fingerprint for stable deduplication across runs */
|
|
20
|
-
fingerprint?: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface BaselineData {
|
|
24
|
-
version: 1;
|
|
25
|
-
savedAt: string;
|
|
26
|
-
projectPath: string;
|
|
27
|
-
findings: BaselineFinding[];
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface ComparedFinding extends BaselineFinding {
|
|
31
|
-
introduced: boolean; // true = new in this run, not in baseline
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Save the current set of findings as a baseline JSON file.
|
|
36
|
-
* @param baselinePath - path to write (e.g. .monomind/baseline.json)
|
|
37
|
-
* @param findings - current findings to persist
|
|
38
|
-
* @param projectPath - repo path for identification
|
|
39
|
-
*/
|
|
40
|
-
export function saveBaseline(
|
|
41
|
-
baselinePath: string,
|
|
42
|
-
findings: BaselineFinding[],
|
|
43
|
-
projectPath: string,
|
|
44
|
-
): void {
|
|
45
|
-
const data: BaselineData = {
|
|
46
|
-
version: 1,
|
|
47
|
-
savedAt: new Date().toISOString(),
|
|
48
|
-
projectPath,
|
|
49
|
-
findings,
|
|
50
|
-
};
|
|
51
|
-
writeFileSync(baselinePath, JSON.stringify(data, null, 2), 'utf-8');
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Load an existing baseline file.
|
|
56
|
-
*/
|
|
57
|
-
export function loadBaseline(baselinePath: string): BaselineData | null {
|
|
58
|
-
if (!existsSync(baselinePath)) return null;
|
|
59
|
-
try {
|
|
60
|
-
return JSON.parse(readFileSync(baselinePath, 'utf-8')) as BaselineData;
|
|
61
|
-
} catch {
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Compare a list of current findings against a baseline.
|
|
68
|
-
* Returns each finding annotated with introduced:true/false.
|
|
69
|
-
*/
|
|
70
|
-
export function compareWithBaseline(
|
|
71
|
-
currentFindings: BaselineFinding[],
|
|
72
|
-
baseline: BaselineData | null,
|
|
73
|
-
): ComparedFinding[] {
|
|
74
|
-
if (!baseline) {
|
|
75
|
-
// No baseline — all findings are "introduced"
|
|
76
|
-
return currentFindings.map(f => ({ ...f, introduced: true }));
|
|
77
|
-
}
|
|
78
|
-
// Primary: match by fingerprint (for baselines that have it)
|
|
79
|
-
const baselineFingerprints = new Set(
|
|
80
|
-
baseline.findings
|
|
81
|
-
.filter(f => f.fingerprint)
|
|
82
|
-
.map(f => f.fingerprint as string),
|
|
83
|
-
);
|
|
84
|
-
// Fallback: match by key (for old baselines without fingerprint)
|
|
85
|
-
const baselineKeys = new Set(baseline.findings.map(f => f.key));
|
|
86
|
-
return currentFindings.map(f => {
|
|
87
|
-
if (f.fingerprint && baselineFingerprints.size > 0) {
|
|
88
|
-
return { ...f, introduced: !baselineFingerprints.has(f.fingerprint) };
|
|
89
|
-
}
|
|
90
|
-
return { ...f, introduced: !baselineKeys.has(f.key) };
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Extract findings from the database to build a baseline.
|
|
96
|
-
* Collects: isolated nodes (no edges), nodes with only INFERRED edges,
|
|
97
|
-
* god nodes (degree > 50).
|
|
98
|
-
*/
|
|
99
|
-
export function extractFindingsFromDb(
|
|
100
|
-
db: Database.Database,
|
|
101
|
-
projectPath: string,
|
|
102
|
-
): BaselineFinding[] {
|
|
103
|
-
const findings: BaselineFinding[] = [];
|
|
104
|
-
|
|
105
|
-
// Isolated nodes (no incoming or outgoing edges)
|
|
106
|
-
const isolated = db.prepare(`
|
|
107
|
-
SELECT n.id, n.name, n.file_path, n.start_line, n.label
|
|
108
|
-
FROM nodes n
|
|
109
|
-
WHERE NOT EXISTS (SELECT 1 FROM edges e WHERE e.source_id = n.id OR e.target_id = n.id)
|
|
110
|
-
AND n.label IN ('Function', 'Class', 'Method', 'Interface', 'Variable', 'Module', 'File')
|
|
111
|
-
LIMIT 500
|
|
112
|
-
`).all() as { id: string; name: string; file_path: string | null; start_line: number | null; label: string }[];
|
|
113
|
-
|
|
114
|
-
for (const n of isolated) {
|
|
115
|
-
findings.push({
|
|
116
|
-
key: `isolated:${n.file_path ?? n.id}:${n.name}`,
|
|
117
|
-
type: 'isolated_node',
|
|
118
|
-
nodeId: n.id,
|
|
119
|
-
nodeName: n.name,
|
|
120
|
-
filePath: n.file_path,
|
|
121
|
-
startLine: n.start_line ?? null,
|
|
122
|
-
savedAt: new Date().toISOString(),
|
|
123
|
-
fingerprint: fingerprintFinding('isolated_node', n.file_path ?? '', n.id),
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// God nodes (degree > 50)
|
|
128
|
-
const gods = db.prepare(`
|
|
129
|
-
SELECT n.id, n.name, n.file_path, n.start_line, d.deg as degree
|
|
130
|
-
FROM nodes n
|
|
131
|
-
JOIN (
|
|
132
|
-
SELECT node_id, SUM(cnt) AS deg FROM (
|
|
133
|
-
SELECT source_id AS node_id, COUNT(*) AS cnt FROM edges GROUP BY source_id
|
|
134
|
-
UNION ALL
|
|
135
|
-
SELECT target_id AS node_id, COUNT(*) AS cnt FROM edges GROUP BY target_id
|
|
136
|
-
) GROUP BY node_id
|
|
137
|
-
HAVING deg > 50
|
|
138
|
-
ORDER BY deg DESC
|
|
139
|
-
LIMIT 100
|
|
140
|
-
) d ON d.node_id = n.id
|
|
141
|
-
ORDER BY d.deg DESC
|
|
142
|
-
`).all() as { id: string; name: string; file_path: string | null; start_line: number | null; degree: number }[];
|
|
143
|
-
|
|
144
|
-
for (const n of gods) {
|
|
145
|
-
findings.push({
|
|
146
|
-
key: `god_node:${n.file_path ?? n.id}:${n.name}`,
|
|
147
|
-
type: 'god_node',
|
|
148
|
-
nodeId: n.id,
|
|
149
|
-
nodeName: n.name,
|
|
150
|
-
filePath: n.file_path,
|
|
151
|
-
startLine: n.start_line ?? null,
|
|
152
|
-
savedAt: new Date().toISOString(),
|
|
153
|
-
fingerprint: fingerprintFinding('god_node', n.file_path ?? '', n.id),
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// Surprise edges: non-EXTRACTED confidence (cross-community low-confidence edges)
|
|
158
|
-
const surprises = db.prepare(`
|
|
159
|
-
SELECT DISTINCT e.id as edge_id, e.source_id, e.target_id, e.confidence,
|
|
160
|
-
n.name as src_name, n.file_path as src_file, n.start_line as src_line
|
|
161
|
-
FROM edges e
|
|
162
|
-
JOIN nodes n ON n.id = e.source_id
|
|
163
|
-
WHERE e.confidence != 'EXTRACTED'
|
|
164
|
-
LIMIT 200
|
|
165
|
-
`).all() as { edge_id: string; source_id: string; target_id: string; confidence: string; src_name: string; src_file: string | null; src_line: number | null }[];
|
|
166
|
-
|
|
167
|
-
for (const e of surprises) {
|
|
168
|
-
findings.push({
|
|
169
|
-
key: `surprise:${e.source_id}:${e.target_id}`,
|
|
170
|
-
type: 'surprise',
|
|
171
|
-
nodeId: e.source_id,
|
|
172
|
-
nodeName: e.src_name,
|
|
173
|
-
filePath: e.src_file,
|
|
174
|
-
startLine: e.src_line ?? null,
|
|
175
|
-
savedAt: new Date().toISOString(),
|
|
176
|
-
fingerprint: fingerprintFinding('surprise', e.source_id, e.target_id),
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// Bridge nodes: nodes whose edges span 2+ distinct foreign communities.
|
|
181
|
-
// Pre-aggregate cross-community counts per direction to avoid 4-way cross product.
|
|
182
|
-
const bridges = db.prepare(`
|
|
183
|
-
SELECT n.id, n.name, n.file_path, n.start_line
|
|
184
|
-
FROM nodes n
|
|
185
|
-
JOIN (
|
|
186
|
-
SELECT node_id, COUNT(DISTINCT foreign_community) AS cross_cnt FROM (
|
|
187
|
-
SELECT e.source_id AS node_id, n2.community_id AS foreign_community
|
|
188
|
-
FROM edges e
|
|
189
|
-
JOIN nodes n1 ON n1.id = e.source_id AND n1.community_id IS NOT NULL
|
|
190
|
-
JOIN nodes n2 ON n2.id = e.target_id AND n2.community_id IS NOT NULL AND n2.community_id != n1.community_id
|
|
191
|
-
UNION ALL
|
|
192
|
-
SELECT e.target_id AS node_id, n1.community_id AS foreign_community
|
|
193
|
-
FROM edges e
|
|
194
|
-
JOIN nodes n1 ON n1.id = e.source_id AND n1.community_id IS NOT NULL
|
|
195
|
-
JOIN nodes n2 ON n2.id = e.target_id AND n2.community_id IS NOT NULL AND n1.community_id != n2.community_id
|
|
196
|
-
) GROUP BY node_id
|
|
197
|
-
HAVING cross_cnt >= 2
|
|
198
|
-
) b ON b.node_id = n.id
|
|
199
|
-
LIMIT 100
|
|
200
|
-
`).all() as { id: string; name: string; file_path: string | null; start_line: number | null }[];
|
|
201
|
-
|
|
202
|
-
for (const n of bridges) {
|
|
203
|
-
findings.push({
|
|
204
|
-
key: `bridge_node:${n.file_path ?? n.id}:${n.name}`,
|
|
205
|
-
type: 'bridge_node',
|
|
206
|
-
nodeId: n.id,
|
|
207
|
-
nodeName: n.name,
|
|
208
|
-
filePath: n.file_path,
|
|
209
|
-
startLine: n.start_line ?? null,
|
|
210
|
-
savedAt: new Date().toISOString(),
|
|
211
|
-
fingerprint: fingerprintFinding('bridge_node', n.file_path ?? '', n.id),
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Unreachable exports: exported nodes with no incoming edges
|
|
216
|
-
const unreachableExports = db.prepare(`
|
|
217
|
-
SELECT n.id, n.name, n.file_path, n.start_line
|
|
218
|
-
FROM nodes n
|
|
219
|
-
WHERE n.is_exported = 1
|
|
220
|
-
AND n.label IN ('Function', 'Class', 'Method', 'Interface', 'Variable')
|
|
221
|
-
AND NOT EXISTS (SELECT 1 FROM edges e WHERE e.target_id = n.id)
|
|
222
|
-
LIMIT 300
|
|
223
|
-
`).all() as { id: string; name: string; file_path: string | null; start_line: number | null }[];
|
|
224
|
-
|
|
225
|
-
for (const n of unreachableExports) {
|
|
226
|
-
findings.push({
|
|
227
|
-
key: `unreachable_export:${n.file_path ?? n.id}:${n.name}`,
|
|
228
|
-
type: 'unreachable_export',
|
|
229
|
-
nodeId: n.id,
|
|
230
|
-
nodeName: n.name,
|
|
231
|
-
filePath: n.file_path,
|
|
232
|
-
startLine: n.start_line ?? null,
|
|
233
|
-
savedAt: new Date().toISOString(),
|
|
234
|
-
fingerprint: fingerprintFinding('unreachable_export', n.file_path ?? '', n.id),
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// Ambiguous edges: edges with AMBIGUOUS confidence
|
|
239
|
-
const ambiguousEdges = db.prepare(`
|
|
240
|
-
SELECT DISTINCT e.id as edge_id, e.source_id, e.target_id,
|
|
241
|
-
n.name as src_name, n.file_path as src_file, n.start_line as src_line
|
|
242
|
-
FROM edges e
|
|
243
|
-
JOIN nodes n ON n.id = e.source_id
|
|
244
|
-
WHERE e.confidence = 'AMBIGUOUS'
|
|
245
|
-
LIMIT 200
|
|
246
|
-
`).all() as { edge_id: string; source_id: string; target_id: string; src_name: string; src_file: string | null; src_line: number | null }[];
|
|
247
|
-
|
|
248
|
-
for (const e of ambiguousEdges) {
|
|
249
|
-
findings.push({
|
|
250
|
-
key: `ambiguous_edge:${e.source_id}:${e.target_id}`,
|
|
251
|
-
type: 'ambiguous_edge',
|
|
252
|
-
nodeId: e.source_id,
|
|
253
|
-
nodeName: e.src_name,
|
|
254
|
-
filePath: e.src_file,
|
|
255
|
-
startLine: e.src_line ?? null,
|
|
256
|
-
savedAt: new Date().toISOString(),
|
|
257
|
-
fingerprint: fingerprintFinding('ambiguous_edge', e.source_id, e.target_id),
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
return findings;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Default baseline path relative to a project directory.
|
|
266
|
-
* If a name is provided, the file is saved as `baseline-{name}.json`.
|
|
267
|
-
*/
|
|
268
|
-
export function defaultBaselinePath(projectDir: string, name?: string): string {
|
|
269
|
-
const filename = name ? `baseline-${name}.json` : 'baseline.json';
|
|
270
|
-
return join(projectDir, '.monomind', filename);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// ── Vital Signs Trend ─────────────────────────────────────────────────────────
|
|
274
|
-
|
|
275
|
-
export type TrendDirection = 'improving' | 'declining' | 'stable';
|
|
276
|
-
|
|
277
|
-
export interface TrendMetric {
|
|
278
|
-
metric: string;
|
|
279
|
-
previous: number;
|
|
280
|
-
current: number;
|
|
281
|
-
delta: number;
|
|
282
|
-
direction: TrendDirection;
|
|
283
|
-
symbol: '↑' | '↓' | '→';
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
export interface TrendReport {
|
|
287
|
-
metrics: TrendMetric[];
|
|
288
|
-
overallDirection: TrendDirection;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* Extended baseline data with vital-sign counters.
|
|
293
|
-
* These fields are optional so existing baseline files remain compatible.
|
|
294
|
-
*/
|
|
295
|
-
export interface BaselineVitals {
|
|
296
|
-
nodeCount?: number;
|
|
297
|
-
edgeCount?: number;
|
|
298
|
-
communityCount?: number;
|
|
299
|
-
godNodeCount?: number;
|
|
300
|
-
surpriseCount?: number;
|
|
301
|
-
hotspotCount?: number;
|
|
302
|
-
unreachableNodeCount?: number;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* Domain-aware polarity for each metric.
|
|
307
|
-
* true = higher value is better (improving)
|
|
308
|
-
* false = lower value is better (improving)
|
|
309
|
-
*/
|
|
310
|
-
const METRIC_HIGHER_IS_BETTER: Record<string, boolean> = {
|
|
311
|
-
nodeCount: true,
|
|
312
|
-
edgeCount: false, // neutral; treated as stable unless large change
|
|
313
|
-
communityCount: true,
|
|
314
|
-
godNodeCount: false,
|
|
315
|
-
surpriseCount: false,
|
|
316
|
-
hotspotCount: false,
|
|
317
|
-
unreachableNodeCount: false,
|
|
318
|
-
};
|
|
319
|
-
|
|
320
|
-
function trendDirection(
|
|
321
|
-
metric: string,
|
|
322
|
-
delta: number,
|
|
323
|
-
): { direction: TrendDirection; symbol: '↑' | '↓' | '→' } {
|
|
324
|
-
if (delta === 0) return { direction: 'stable', symbol: '→' };
|
|
325
|
-
|
|
326
|
-
// edgeCount is neutral — always stable regardless of direction
|
|
327
|
-
if (metric === 'edgeCount') return { direction: 'stable', symbol: '→' };
|
|
328
|
-
|
|
329
|
-
const higherIsBetter = METRIC_HIGHER_IS_BETTER[metric] ?? true;
|
|
330
|
-
|
|
331
|
-
if (delta > 0) {
|
|
332
|
-
return higherIsBetter
|
|
333
|
-
? { direction: 'improving', symbol: '↑' }
|
|
334
|
-
: { direction: 'declining', symbol: '↑' };
|
|
335
|
-
}
|
|
336
|
-
// delta < 0
|
|
337
|
-
return higherIsBetter
|
|
338
|
-
? { direction: 'declining', symbol: '↓' }
|
|
339
|
-
: { direction: 'improving', symbol: '↓' };
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
/**
|
|
343
|
-
* Compute a trend report by comparing two BaselineData snapshots.
|
|
344
|
-
* Each baseline must carry BaselineVitals fields (nodeCount, edgeCount, …).
|
|
345
|
-
*/
|
|
346
|
-
export function computeTrend(
|
|
347
|
-
before: BaselineData & BaselineVitals,
|
|
348
|
-
after: BaselineData & BaselineVitals,
|
|
349
|
-
): TrendReport {
|
|
350
|
-
const metricKeys: Array<keyof BaselineVitals> = [
|
|
351
|
-
'nodeCount',
|
|
352
|
-
'edgeCount',
|
|
353
|
-
'communityCount',
|
|
354
|
-
'godNodeCount',
|
|
355
|
-
'surpriseCount',
|
|
356
|
-
'hotspotCount',
|
|
357
|
-
'unreachableNodeCount',
|
|
358
|
-
];
|
|
359
|
-
|
|
360
|
-
const metrics: TrendMetric[] = [];
|
|
361
|
-
|
|
362
|
-
for (const key of metricKeys) {
|
|
363
|
-
const prev = before[key] ?? 0;
|
|
364
|
-
const curr = after[key] ?? 0;
|
|
365
|
-
const delta = curr - prev;
|
|
366
|
-
const { direction, symbol } = trendDirection(key, delta);
|
|
367
|
-
metrics.push({ metric: key, previous: prev, current: curr, delta, direction, symbol });
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
// Overall direction: majority vote (improving/declining/stable)
|
|
371
|
-
const counts = { improving: 0, declining: 0, stable: 0 };
|
|
372
|
-
for (const m of metrics) counts[m.direction]++;
|
|
373
|
-
|
|
374
|
-
let overallDirection: TrendDirection = 'stable';
|
|
375
|
-
if (counts.improving > counts.declining && counts.improving > counts.stable) {
|
|
376
|
-
overallDirection = 'improving';
|
|
377
|
-
} else if (counts.declining > counts.improving && counts.declining > counts.stable) {
|
|
378
|
-
overallDirection = 'declining';
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
return { metrics, overallDirection };
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
/** Format a list of ComparedFindings as structured text with file:line hints. */
|
|
385
|
-
export function formatComparedFindings(findings: ComparedFinding[], showAll = false): string {
|
|
386
|
-
if (findings.length === 0) return 'Baseline comparison: no findings.';
|
|
387
|
-
|
|
388
|
-
const newFindings = findings.filter(f => f.introduced);
|
|
389
|
-
const existing = findings.filter(f => !f.introduced);
|
|
390
|
-
|
|
391
|
-
const lines: string[] = [
|
|
392
|
-
`Baseline comparison: ${findings.length} total finding(s) — ${newFindings.length} new, ${existing.length} known.`,
|
|
393
|
-
'',
|
|
394
|
-
];
|
|
395
|
-
|
|
396
|
-
if (newFindings.length > 0) {
|
|
397
|
-
lines.push(`New findings (${newFindings.length}):`);
|
|
398
|
-
for (const f of newFindings) {
|
|
399
|
-
const ref = f.filePath
|
|
400
|
-
? f.startLine != null ? `${f.filePath}:${f.startLine}` : f.filePath
|
|
401
|
-
: f.nodeId;
|
|
402
|
-
lines.push(` [${f.type}] ${f.nodeName} ${ref}`);
|
|
403
|
-
}
|
|
404
|
-
lines.push('');
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
if (showAll && existing.length > 0) {
|
|
408
|
-
lines.push(`Known findings (${existing.length}):`);
|
|
409
|
-
for (const f of existing) {
|
|
410
|
-
const ref = f.filePath
|
|
411
|
-
? f.startLine != null ? `${f.filePath}:${f.startLine}` : f.filePath
|
|
412
|
-
: f.nodeId;
|
|
413
|
-
lines.push(` [${f.type}] ${f.nodeName} ${ref}`);
|
|
414
|
-
}
|
|
415
|
-
lines.push('');
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
return lines.join('\n').trimEnd();
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
/** Format a TrendReport as structured text for LLM consumption. */
|
|
422
|
-
export function formatTrendReport(report: TrendReport): string {
|
|
423
|
-
const lines: string[] = [
|
|
424
|
-
`Graph trend: ${report.overallDirection}`,
|
|
425
|
-
'',
|
|
426
|
-
];
|
|
427
|
-
for (const m of report.metrics) {
|
|
428
|
-
const deltaStr = m.delta > 0 ? `+${m.delta}` : `${m.delta}`;
|
|
429
|
-
lines.push(` ${m.symbol} ${m.metric}: ${m.previous} → ${m.current} (${deltaStr}) [${m.direction}]`);
|
|
430
|
-
}
|
|
431
|
-
return lines.join('\n');
|
|
432
|
-
}
|