@aiready/core 0.23.8 → 0.23.9

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/dist/client.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- export { e as AIReadyConfig, h as AcceptancePrediction, A as AnalysisResult, r as AnalysisStatus, B as BusinessMetrics, t as COMMON_FINE_TUNING_OPTIONS, u as CONTEXT_TIER_THRESHOLDS, v as CommonASTNode, i as ComprehensionDifficulty, w as Config, C as CostConfig, D as DEFAULT_TOOL_WEIGHTS, n as ExportInfo, x as FRIENDLY_TOOL_NAMES, y as FileContent, G as GLOBAL_INFRA_OPTIONS, z as GLOBAL_SCAN_OPTIONS, H as GraphData, J as GraphEdge, K as GraphIssueSeverity, O as GraphMetadata, Q as GraphNode, I as Issue, U as IssueType, W as LANGUAGE_EXTENSIONS, l as Language, X as LanguageConfig, L as LanguageParser, Y as Lead, Z as LeadSchema, _ as LeadSource, $ as LeadSourceSchema, a0 as LeadSubmission, a1 as LeadSubmissionSchema, a2 as Location, M as Metrics, f as ModelContextTier, N as NamingConvention, a9 as ParseError, m as ParseResult, aa as ParseStatistics, P as ProductivityImpact, ab as ReadinessRating, ac as RecommendationPriority, ad as SCORING_PROFILES, ae as SIZE_ADJUSTED_THRESHOLDS, S as ScanOptions, af as ScanResult, ag as ScoringConfig, ah as ScoringProfile, ai as ScoringResult, d as Severity, d as SeverityType, ak as SourceLocation, al as SourceRange, a as SpokeOutput, ap as TOOL_NAME_MAP, k as TechnicalValueChain, j as TechnicalValueChainSummary, g as TokenBudget, T as ToolName, c as ToolOptions, ar as ToolOutput, b as ToolScoringOutput, as as UnifiedReport, at as UnifiedReportSchema, au as calculateOverallScore, av as formatScore, aw as formatToolScore, ax as generateHTML, ay as getProjectSizeTier, az as getRating, aA as getRatingDisplay, aB as getRatingSlug, aC as getRatingWithContext, aD as getRecommendedThreshold, aE as getToolWeight, aF as normalizeToolName, aG as parseWeightString } from './client-wk2fgk1q.mjs';
1
+ export { e as AIReadyConfig, h as AcceptancePrediction, A as AnalysisResult, r as AnalysisStatus, B as BusinessMetrics, t as COMMON_FINE_TUNING_OPTIONS, u as CONTEXT_TIER_THRESHOLDS, v as CommonASTNode, i as ComprehensionDifficulty, w as Config, C as CostConfig, D as DEFAULT_TOOL_WEIGHTS, n as ExportInfo, x as FRIENDLY_TOOL_NAMES, y as FileContent, G as GLOBAL_INFRA_OPTIONS, z as GLOBAL_SCAN_OPTIONS, H as GraphData, J as GraphEdge, K as GraphIssueSeverity, O as GraphMetadata, Q as GraphNode, I as Issue, U as IssueType, W as LANGUAGE_EXTENSIONS, l as Language, X as LanguageConfig, L as LanguageParser, Y as Lead, Z as LeadSchema, _ as LeadSource, $ as LeadSourceSchema, a0 as LeadSubmission, a1 as LeadSubmissionSchema, a2 as Location, M as Metrics, f as ModelContextTier, N as NamingConvention, a9 as ParseError, m as ParseResult, aa as ParseStatistics, P as ProductivityImpact, ab as ReadinessRating, ac as RecommendationPriority, ad as SCORING_PROFILES, ae as SIZE_ADJUSTED_THRESHOLDS, S as ScanOptions, af as ScanResult, ag as ScoringConfig, ah as ScoringProfile, ai as ScoringResult, d as Severity, d as SeverityType, ak as SourceLocation, al as SourceRange, a as SpokeOutput, ap as TOOL_NAME_MAP, k as TechnicalValueChain, j as TechnicalValueChainSummary, g as TokenBudget, T as ToolName, c as ToolOptions, ar as ToolOutput, b as ToolScoringOutput, as as UnifiedReport, at as UnifiedReportSchema, au as calculateOverallScore, av as formatScore, aw as formatToolScore, ax as generateHTML, ay as getProjectSizeTier, az as getRating, aA as getRatingDisplay, aB as getRatingSlug, aC as getRatingWithContext, aD as getRecommendedThreshold, aE as getToolWeight, aF as normalizeToolName, aG as parseWeightString } from './client-BEoUYNLp.mjs';
2
2
  import 'zod';
package/dist/client.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { e as AIReadyConfig, h as AcceptancePrediction, A as AnalysisResult, r as AnalysisStatus, B as BusinessMetrics, t as COMMON_FINE_TUNING_OPTIONS, u as CONTEXT_TIER_THRESHOLDS, v as CommonASTNode, i as ComprehensionDifficulty, w as Config, C as CostConfig, D as DEFAULT_TOOL_WEIGHTS, n as ExportInfo, x as FRIENDLY_TOOL_NAMES, y as FileContent, G as GLOBAL_INFRA_OPTIONS, z as GLOBAL_SCAN_OPTIONS, H as GraphData, J as GraphEdge, K as GraphIssueSeverity, O as GraphMetadata, Q as GraphNode, I as Issue, U as IssueType, W as LANGUAGE_EXTENSIONS, l as Language, X as LanguageConfig, L as LanguageParser, Y as Lead, Z as LeadSchema, _ as LeadSource, $ as LeadSourceSchema, a0 as LeadSubmission, a1 as LeadSubmissionSchema, a2 as Location, M as Metrics, f as ModelContextTier, N as NamingConvention, a9 as ParseError, m as ParseResult, aa as ParseStatistics, P as ProductivityImpact, ab as ReadinessRating, ac as RecommendationPriority, ad as SCORING_PROFILES, ae as SIZE_ADJUSTED_THRESHOLDS, S as ScanOptions, af as ScanResult, ag as ScoringConfig, ah as ScoringProfile, ai as ScoringResult, d as Severity, d as SeverityType, ak as SourceLocation, al as SourceRange, a as SpokeOutput, ap as TOOL_NAME_MAP, k as TechnicalValueChain, j as TechnicalValueChainSummary, g as TokenBudget, T as ToolName, c as ToolOptions, ar as ToolOutput, b as ToolScoringOutput, as as UnifiedReport, at as UnifiedReportSchema, au as calculateOverallScore, av as formatScore, aw as formatToolScore, ax as generateHTML, ay as getProjectSizeTier, az as getRating, aA as getRatingDisplay, aB as getRatingSlug, aC as getRatingWithContext, aD as getRecommendedThreshold, aE as getToolWeight, aF as normalizeToolName, aG as parseWeightString } from './client-wk2fgk1q.js';
1
+ export { e as AIReadyConfig, h as AcceptancePrediction, A as AnalysisResult, r as AnalysisStatus, B as BusinessMetrics, t as COMMON_FINE_TUNING_OPTIONS, u as CONTEXT_TIER_THRESHOLDS, v as CommonASTNode, i as ComprehensionDifficulty, w as Config, C as CostConfig, D as DEFAULT_TOOL_WEIGHTS, n as ExportInfo, x as FRIENDLY_TOOL_NAMES, y as FileContent, G as GLOBAL_INFRA_OPTIONS, z as GLOBAL_SCAN_OPTIONS, H as GraphData, J as GraphEdge, K as GraphIssueSeverity, O as GraphMetadata, Q as GraphNode, I as Issue, U as IssueType, W as LANGUAGE_EXTENSIONS, l as Language, X as LanguageConfig, L as LanguageParser, Y as Lead, Z as LeadSchema, _ as LeadSource, $ as LeadSourceSchema, a0 as LeadSubmission, a1 as LeadSubmissionSchema, a2 as Location, M as Metrics, f as ModelContextTier, N as NamingConvention, a9 as ParseError, m as ParseResult, aa as ParseStatistics, P as ProductivityImpact, ab as ReadinessRating, ac as RecommendationPriority, ad as SCORING_PROFILES, ae as SIZE_ADJUSTED_THRESHOLDS, S as ScanOptions, af as ScanResult, ag as ScoringConfig, ah as ScoringProfile, ai as ScoringResult, d as Severity, d as SeverityType, ak as SourceLocation, al as SourceRange, a as SpokeOutput, ap as TOOL_NAME_MAP, k as TechnicalValueChain, j as TechnicalValueChainSummary, g as TokenBudget, T as ToolName, c as ToolOptions, ar as ToolOutput, b as ToolScoringOutput, as as UnifiedReport, at as UnifiedReportSchema, au as calculateOverallScore, av as formatScore, aw as formatToolScore, ax as generateHTML, ay as getProjectSizeTier, az as getRating, aA as getRatingDisplay, aB as getRatingSlug, aC as getRatingWithContext, aD as getRecommendedThreshold, aE as getToolWeight, aF as normalizeToolName, aG as parseWeightString } from './client-BEoUYNLp.js';
2
2
  import 'zod';
package/dist/client.js CHANGED
@@ -256,8 +256,16 @@ var AIReadyConfigSchema = import_zod.z.object({
256
256
  profile: import_zod.z.string().optional(),
257
257
  /** Custom weights for tools and metrics */
258
258
  weights: import_zod.z.record(import_zod.z.string(), import_zod.z.number()).optional()
259
+ }).optional(),
260
+ /** Visualizer settings (interactive graph) */
261
+ visualizer: import_zod.z.object({
262
+ groupingDirs: import_zod.z.array(import_zod.z.string()).optional(),
263
+ graph: import_zod.z.object({
264
+ maxNodes: import_zod.z.number().optional(),
265
+ maxEdges: import_zod.z.number().optional()
266
+ }).optional()
259
267
  }).optional()
260
- });
268
+ }).catchall(import_zod.z.any());
261
269
 
262
270
  // src/types/business.ts
263
271
  var import_zod2 = require("zod");
package/dist/client.mjs CHANGED
@@ -36,7 +36,7 @@ import {
36
36
  getToolWeight,
37
37
  normalizeToolName,
38
38
  parseWeightString
39
- } from "./chunk-TJXR2CHZ.mjs";
39
+ } from "./chunk-CGOS2J6T.mjs";
40
40
  export {
41
41
  AnalysisStatus,
42
42
  COMMON_FINE_TUNING_OPTIONS,
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { T as ToolName, S as ScanOptions, a as SpokeOutput, b as ToolScoringOutput, c as ToolOptions, d as Severity, A as AnalysisResult, E as ExportWithImports, F as FileImport, e as AIReadyConfig, I as Issue, M as Metrics, f as ModelContextTier, C as CostConfig, g as TokenBudget, P as ProductivityImpact, h as AcceptancePrediction, i as ComprehensionDifficulty, j as TechnicalValueChainSummary, k as TechnicalValueChain, L as LanguageParser, l as Language, m as ParseResult, N as NamingConvention, n as ExportInfo } from './client-wk2fgk1q.mjs';
2
- export { o as AIReadyConfigSchema, p as ASTNode, q as AnalysisResultSchema, r as AnalysisStatus, s as AnalysisStatusSchema, B as BusinessMetrics, t as COMMON_FINE_TUNING_OPTIONS, u as CONTEXT_TIER_THRESHOLDS, v as CommonASTNode, w as Config, D as DEFAULT_TOOL_WEIGHTS, x as FRIENDLY_TOOL_NAMES, y as FileContent, G as GLOBAL_INFRA_OPTIONS, z as GLOBAL_SCAN_OPTIONS, H as GraphData, J as GraphEdge, K as GraphIssueSeverity, O as GraphMetadata, Q as GraphNode, R as IssueSchema, U as IssueType, V as IssueTypeSchema, W as LANGUAGE_EXTENSIONS, X as LanguageConfig, Y as Lead, Z as LeadSchema, _ as LeadSource, $ as LeadSourceSchema, a0 as LeadSubmission, a1 as LeadSubmissionSchema, a2 as Location, a3 as LocationSchema, a4 as ManagedAccount, a5 as ManagedAccountSchema, a6 as MetricsSchema, a7 as ModelTier, a8 as ModelTierSchema, a9 as ParseError, aa as ParseStatistics, ab as ReadinessRating, ac as RecommendationPriority, ad as SCORING_PROFILES, ae as SIZE_ADJUSTED_THRESHOLDS, af as ScanResult, ag as ScoringConfig, ah as ScoringProfile, ai as ScoringResult, aj as SeveritySchema, ak as SourceLocation, al as SourceRange, am as SpokeOutputSchema, an as SpokeSummary, ao as SpokeSummarySchema, ap as TOOL_NAME_MAP, aq as ToolNameSchema, ar as ToolOutput, as as UnifiedReport, at as UnifiedReportSchema, au as calculateOverallScore, av as formatScore, aw as formatToolScore, ax as generateHTML, ay as getProjectSizeTier, az as getRating, aA as getRatingDisplay, aB as getRatingSlug, aC as getRatingWithContext, aD as getRecommendedThreshold, aE as getToolWeight, aF as normalizeToolName, aG as parseWeightString } from './client-wk2fgk1q.mjs';
1
+ import { T as ToolName, S as ScanOptions, a as SpokeOutput, b as ToolScoringOutput, c as ToolOptions, d as Severity, A as AnalysisResult, E as ExportWithImports, F as FileImport, e as AIReadyConfig, I as Issue, M as Metrics, f as ModelContextTier, C as CostConfig, g as TokenBudget, P as ProductivityImpact, h as AcceptancePrediction, i as ComprehensionDifficulty, j as TechnicalValueChainSummary, k as TechnicalValueChain, L as LanguageParser, l as Language, m as ParseResult, N as NamingConvention, n as ExportInfo } from './client-BEoUYNLp.mjs';
2
+ export { o as AIReadyConfigSchema, p as ASTNode, q as AnalysisResultSchema, r as AnalysisStatus, s as AnalysisStatusSchema, B as BusinessMetrics, t as COMMON_FINE_TUNING_OPTIONS, u as CONTEXT_TIER_THRESHOLDS, v as CommonASTNode, w as Config, D as DEFAULT_TOOL_WEIGHTS, x as FRIENDLY_TOOL_NAMES, y as FileContent, G as GLOBAL_INFRA_OPTIONS, z as GLOBAL_SCAN_OPTIONS, H as GraphData, J as GraphEdge, K as GraphIssueSeverity, O as GraphMetadata, Q as GraphNode, R as IssueSchema, U as IssueType, V as IssueTypeSchema, W as LANGUAGE_EXTENSIONS, X as LanguageConfig, Y as Lead, Z as LeadSchema, _ as LeadSource, $ as LeadSourceSchema, a0 as LeadSubmission, a1 as LeadSubmissionSchema, a2 as Location, a3 as LocationSchema, a4 as ManagedAccount, a5 as ManagedAccountSchema, a6 as MetricsSchema, a7 as ModelTier, a8 as ModelTierSchema, a9 as ParseError, aa as ParseStatistics, ab as ReadinessRating, ac as RecommendationPriority, ad as SCORING_PROFILES, ae as SIZE_ADJUSTED_THRESHOLDS, af as ScanResult, ag as ScoringConfig, ah as ScoringProfile, ai as ScoringResult, aj as SeveritySchema, ak as SourceLocation, al as SourceRange, am as SpokeOutputSchema, an as SpokeSummary, ao as SpokeSummarySchema, ap as TOOL_NAME_MAP, aq as ToolNameSchema, ar as ToolOutput, as as UnifiedReport, at as UnifiedReportSchema, au as calculateOverallScore, av as formatScore, aw as formatToolScore, ax as generateHTML, ay as getProjectSizeTier, az as getRating, aA as getRatingDisplay, aB as getRatingSlug, aC as getRatingWithContext, aD as getRecommendedThreshold, aE as getToolWeight, aF as normalizeToolName, aG as parseWeightString } from './client-BEoUYNLp.mjs';
3
3
  import { z } from 'zod';
4
4
  import * as Parser from 'web-tree-sitter';
5
5
 
@@ -1316,8 +1316,14 @@ declare function calculateAgentGrounding(params: {
1316
1316
  * Testability Index Metrics.
1317
1317
  * Measures how verifiable AI-generated changes are based on local testing infrastructure.
1318
1318
  *
1319
- * @lastUpdated 2026-03-18
1319
+ * @lastUpdated 2026-03-19
1320
1320
  */
1321
+ interface FileTestability {
1322
+ filePath: string;
1323
+ score: number;
1324
+ purityScore: number;
1325
+ isEntryPoint: boolean;
1326
+ }
1321
1327
  interface TestabilityIndex {
1322
1328
  score: number;
1323
1329
  rating: 'excellent' | 'good' | 'moderate' | 'poor' | 'unverifiable';
@@ -1330,6 +1336,10 @@ interface TestabilityIndex {
1330
1336
  };
1331
1337
  aiChangeSafetyRating: 'safe' | 'moderate-risk' | 'high-risk' | 'blind-risk';
1332
1338
  recommendations: string[];
1339
+ /** Per-file testability metrics */
1340
+ fileMetrics?: FileTestability[];
1341
+ /** Score based only on library code (excluding CLI entry points) */
1342
+ libraryScore?: number;
1333
1343
  }
1334
1344
  /**
1335
1345
  * Calculate the Testability Index for a project.
@@ -1345,6 +1355,7 @@ interface TestabilityIndex {
1345
1355
  * @param params.totalInterfaces - Total number of interfaces analyzed.
1346
1356
  * @param params.externalStateMutations - Count of nodes that mutate external state.
1347
1357
  * @param params.hasTestFramework - Whether a testing framework (e.g., Vitest) is detected.
1358
+ * @param params.fileDetails - Optional per-file data for detailed analysis.
1348
1359
  * @returns Comprehensive TestabilityIndex analysis.
1349
1360
  */
1350
1361
  declare function calculateTestabilityIndex(params: {
@@ -1358,6 +1369,11 @@ declare function calculateTestabilityIndex(params: {
1358
1369
  totalInterfaces: number;
1359
1370
  externalStateMutations: number;
1360
1371
  hasTestFramework: boolean;
1372
+ fileDetails?: Array<{
1373
+ filePath: string;
1374
+ pureFunctions: number;
1375
+ totalFunctions: number;
1376
+ }>;
1361
1377
  }): TestabilityIndex;
1362
1378
 
1363
1379
  /**
@@ -1638,4 +1654,4 @@ declare function severityToAnnotationLevel(severity: string): 'error' | 'warning
1638
1654
  */
1639
1655
  declare function emitIssuesAsAnnotations(issues: any[]): void;
1640
1656
 
1641
- export { AIReadyConfig, AcceptancePrediction, type AgentGroundingScore, type AiSignalClarity, type AiSignalClaritySignal, AnalysisResult, type CLIOptions, CSharpParser, type ChangeAmplificationScore, type CognitiveLoad, ComprehensionDifficulty, type ConceptCohesion, CostConfig, DEFAULT_COST_CONFIG, DEFAULT_EXCLUDE, type DependencyHealthScore, type DocDriftRisk, ExportInfo, ExportWithImports, FileImport, type FileWithDomain, GoParser, Issue, JavaParser, type KnowledgeConcentrationRisk, Language, LanguageParser, type LoadFactor, MODEL_PRICING_PRESETS, Metrics, ModelContextTier, type ModelPricingPreset, NamingConvention, ParseResult, ParserFactory, type PatternEntropy, ProductivityImpact, type ProviderFactoryConfig, PythonParser, SEVERITY_TIME_ESTIMATES, ScanOptions, type ScoreHistoryEntry, type ScoreTrend, type SemanticDistance, Severity, Severity as SeverityType, SpokeOutput, type TechnicalDebtInterest, TechnicalValueChain, TechnicalValueChainSummary, type TestabilityIndex, TokenBudget, ToolName, ToolOptions, type ToolProvider, ToolRegistry, ToolScoringOutput, TypeScriptParser, VAGUE_FILE_NAMES, buildSimpleProviderScore, buildSpokeOutput, calculateAgentGrounding, calculateAiSignalClarity, calculateBusinessROI, calculateChangeAmplification, calculateCognitiveLoad, calculateComprehensionDifficulty, calculateConceptCohesion, calculateDebtInterest, calculateDependencyHealth, calculateDocDrift, calculateExtendedFutureProofScore, calculateFutureProofScore, calculateImportSimilarity, calculateKnowledgeConcentration, calculateMonthlyCost, calculatePatternEntropy, calculateProductivityImpact, calculateSemanticDistance, calculateTechnicalValueChain, calculateTestabilityIndex, calculateTokenBudget, clearHistory, createProvider, emitAnnotation, emitIssuesAsAnnotations, emitProgress, estimateCostFromBudget, estimateTokens, exportHistory, findLatestReport, findLatestScanReport, formatAcceptanceRate, formatCost, formatHours, generateValueChain, getElapsedTime, getFileCommitTimestamps, getFileExtension, getHistorySummary, getLineRangeLastModifiedCached, getModelPreset, getParser, getRepoMetadata, getSafetyIcon, getScoreBar, getSeverityBadge, getSeverityColor, getSeverityEnum, getSeverityLevel, getSeverityValue, getSupportedLanguages, getWasmPath, groupIssuesByFile, handleCLIError, handleJSONOutput, initTreeSitter, initializeParsers, isFileSupported, isSourceFile, loadConfig, loadMergedConfig, loadScoreHistory, mergeConfigWithDefaults, normalizeAnalysisResult, normalizeIssue, normalizeMetrics, normalizeSpokeOutput, parseFileExports, predictAcceptanceRate, readFileContent, resolveOutputPath, saveScoreEntry, scanEntries, scanFiles, setupParser, severityToAnnotationLevel, validateSpokeOutput, validateWithSchema };
1657
+ export { AIReadyConfig, AcceptancePrediction, type AgentGroundingScore, type AiSignalClarity, type AiSignalClaritySignal, AnalysisResult, type CLIOptions, CSharpParser, type ChangeAmplificationScore, type CognitiveLoad, ComprehensionDifficulty, type ConceptCohesion, CostConfig, DEFAULT_COST_CONFIG, DEFAULT_EXCLUDE, type DependencyHealthScore, type DocDriftRisk, ExportInfo, ExportWithImports, FileImport, type FileTestability, type FileWithDomain, GoParser, Issue, JavaParser, type KnowledgeConcentrationRisk, Language, LanguageParser, type LoadFactor, MODEL_PRICING_PRESETS, Metrics, ModelContextTier, type ModelPricingPreset, NamingConvention, ParseResult, ParserFactory, type PatternEntropy, ProductivityImpact, type ProviderFactoryConfig, PythonParser, SEVERITY_TIME_ESTIMATES, ScanOptions, type ScoreHistoryEntry, type ScoreTrend, type SemanticDistance, Severity, Severity as SeverityType, SpokeOutput, type TechnicalDebtInterest, TechnicalValueChain, TechnicalValueChainSummary, type TestabilityIndex, TokenBudget, ToolName, ToolOptions, type ToolProvider, ToolRegistry, ToolScoringOutput, TypeScriptParser, VAGUE_FILE_NAMES, buildSimpleProviderScore, buildSpokeOutput, calculateAgentGrounding, calculateAiSignalClarity, calculateBusinessROI, calculateChangeAmplification, calculateCognitiveLoad, calculateComprehensionDifficulty, calculateConceptCohesion, calculateDebtInterest, calculateDependencyHealth, calculateDocDrift, calculateExtendedFutureProofScore, calculateFutureProofScore, calculateImportSimilarity, calculateKnowledgeConcentration, calculateMonthlyCost, calculatePatternEntropy, calculateProductivityImpact, calculateSemanticDistance, calculateTechnicalValueChain, calculateTestabilityIndex, calculateTokenBudget, clearHistory, createProvider, emitAnnotation, emitIssuesAsAnnotations, emitProgress, estimateCostFromBudget, estimateTokens, exportHistory, findLatestReport, findLatestScanReport, formatAcceptanceRate, formatCost, formatHours, generateValueChain, getElapsedTime, getFileCommitTimestamps, getFileExtension, getHistorySummary, getLineRangeLastModifiedCached, getModelPreset, getParser, getRepoMetadata, getSafetyIcon, getScoreBar, getSeverityBadge, getSeverityColor, getSeverityEnum, getSeverityLevel, getSeverityValue, getSupportedLanguages, getWasmPath, groupIssuesByFile, handleCLIError, handleJSONOutput, initTreeSitter, initializeParsers, isFileSupported, isSourceFile, loadConfig, loadMergedConfig, loadScoreHistory, mergeConfigWithDefaults, normalizeAnalysisResult, normalizeIssue, normalizeMetrics, normalizeSpokeOutput, parseFileExports, predictAcceptanceRate, readFileContent, resolveOutputPath, saveScoreEntry, scanEntries, scanFiles, setupParser, severityToAnnotationLevel, validateSpokeOutput, validateWithSchema };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { T as ToolName, S as ScanOptions, a as SpokeOutput, b as ToolScoringOutput, c as ToolOptions, d as Severity, A as AnalysisResult, E as ExportWithImports, F as FileImport, e as AIReadyConfig, I as Issue, M as Metrics, f as ModelContextTier, C as CostConfig, g as TokenBudget, P as ProductivityImpact, h as AcceptancePrediction, i as ComprehensionDifficulty, j as TechnicalValueChainSummary, k as TechnicalValueChain, L as LanguageParser, l as Language, m as ParseResult, N as NamingConvention, n as ExportInfo } from './client-wk2fgk1q.js';
2
- export { o as AIReadyConfigSchema, p as ASTNode, q as AnalysisResultSchema, r as AnalysisStatus, s as AnalysisStatusSchema, B as BusinessMetrics, t as COMMON_FINE_TUNING_OPTIONS, u as CONTEXT_TIER_THRESHOLDS, v as CommonASTNode, w as Config, D as DEFAULT_TOOL_WEIGHTS, x as FRIENDLY_TOOL_NAMES, y as FileContent, G as GLOBAL_INFRA_OPTIONS, z as GLOBAL_SCAN_OPTIONS, H as GraphData, J as GraphEdge, K as GraphIssueSeverity, O as GraphMetadata, Q as GraphNode, R as IssueSchema, U as IssueType, V as IssueTypeSchema, W as LANGUAGE_EXTENSIONS, X as LanguageConfig, Y as Lead, Z as LeadSchema, _ as LeadSource, $ as LeadSourceSchema, a0 as LeadSubmission, a1 as LeadSubmissionSchema, a2 as Location, a3 as LocationSchema, a4 as ManagedAccount, a5 as ManagedAccountSchema, a6 as MetricsSchema, a7 as ModelTier, a8 as ModelTierSchema, a9 as ParseError, aa as ParseStatistics, ab as ReadinessRating, ac as RecommendationPriority, ad as SCORING_PROFILES, ae as SIZE_ADJUSTED_THRESHOLDS, af as ScanResult, ag as ScoringConfig, ah as ScoringProfile, ai as ScoringResult, aj as SeveritySchema, ak as SourceLocation, al as SourceRange, am as SpokeOutputSchema, an as SpokeSummary, ao as SpokeSummarySchema, ap as TOOL_NAME_MAP, aq as ToolNameSchema, ar as ToolOutput, as as UnifiedReport, at as UnifiedReportSchema, au as calculateOverallScore, av as formatScore, aw as formatToolScore, ax as generateHTML, ay as getProjectSizeTier, az as getRating, aA as getRatingDisplay, aB as getRatingSlug, aC as getRatingWithContext, aD as getRecommendedThreshold, aE as getToolWeight, aF as normalizeToolName, aG as parseWeightString } from './client-wk2fgk1q.js';
1
+ import { T as ToolName, S as ScanOptions, a as SpokeOutput, b as ToolScoringOutput, c as ToolOptions, d as Severity, A as AnalysisResult, E as ExportWithImports, F as FileImport, e as AIReadyConfig, I as Issue, M as Metrics, f as ModelContextTier, C as CostConfig, g as TokenBudget, P as ProductivityImpact, h as AcceptancePrediction, i as ComprehensionDifficulty, j as TechnicalValueChainSummary, k as TechnicalValueChain, L as LanguageParser, l as Language, m as ParseResult, N as NamingConvention, n as ExportInfo } from './client-BEoUYNLp.js';
2
+ export { o as AIReadyConfigSchema, p as ASTNode, q as AnalysisResultSchema, r as AnalysisStatus, s as AnalysisStatusSchema, B as BusinessMetrics, t as COMMON_FINE_TUNING_OPTIONS, u as CONTEXT_TIER_THRESHOLDS, v as CommonASTNode, w as Config, D as DEFAULT_TOOL_WEIGHTS, x as FRIENDLY_TOOL_NAMES, y as FileContent, G as GLOBAL_INFRA_OPTIONS, z as GLOBAL_SCAN_OPTIONS, H as GraphData, J as GraphEdge, K as GraphIssueSeverity, O as GraphMetadata, Q as GraphNode, R as IssueSchema, U as IssueType, V as IssueTypeSchema, W as LANGUAGE_EXTENSIONS, X as LanguageConfig, Y as Lead, Z as LeadSchema, _ as LeadSource, $ as LeadSourceSchema, a0 as LeadSubmission, a1 as LeadSubmissionSchema, a2 as Location, a3 as LocationSchema, a4 as ManagedAccount, a5 as ManagedAccountSchema, a6 as MetricsSchema, a7 as ModelTier, a8 as ModelTierSchema, a9 as ParseError, aa as ParseStatistics, ab as ReadinessRating, ac as RecommendationPriority, ad as SCORING_PROFILES, ae as SIZE_ADJUSTED_THRESHOLDS, af as ScanResult, ag as ScoringConfig, ah as ScoringProfile, ai as ScoringResult, aj as SeveritySchema, ak as SourceLocation, al as SourceRange, am as SpokeOutputSchema, an as SpokeSummary, ao as SpokeSummarySchema, ap as TOOL_NAME_MAP, aq as ToolNameSchema, ar as ToolOutput, as as UnifiedReport, at as UnifiedReportSchema, au as calculateOverallScore, av as formatScore, aw as formatToolScore, ax as generateHTML, ay as getProjectSizeTier, az as getRating, aA as getRatingDisplay, aB as getRatingSlug, aC as getRatingWithContext, aD as getRecommendedThreshold, aE as getToolWeight, aF as normalizeToolName, aG as parseWeightString } from './client-BEoUYNLp.js';
3
3
  import { z } from 'zod';
4
4
  import * as Parser from 'web-tree-sitter';
5
5
 
@@ -1316,8 +1316,14 @@ declare function calculateAgentGrounding(params: {
1316
1316
  * Testability Index Metrics.
1317
1317
  * Measures how verifiable AI-generated changes are based on local testing infrastructure.
1318
1318
  *
1319
- * @lastUpdated 2026-03-18
1319
+ * @lastUpdated 2026-03-19
1320
1320
  */
1321
+ interface FileTestability {
1322
+ filePath: string;
1323
+ score: number;
1324
+ purityScore: number;
1325
+ isEntryPoint: boolean;
1326
+ }
1321
1327
  interface TestabilityIndex {
1322
1328
  score: number;
1323
1329
  rating: 'excellent' | 'good' | 'moderate' | 'poor' | 'unverifiable';
@@ -1330,6 +1336,10 @@ interface TestabilityIndex {
1330
1336
  };
1331
1337
  aiChangeSafetyRating: 'safe' | 'moderate-risk' | 'high-risk' | 'blind-risk';
1332
1338
  recommendations: string[];
1339
+ /** Per-file testability metrics */
1340
+ fileMetrics?: FileTestability[];
1341
+ /** Score based only on library code (excluding CLI entry points) */
1342
+ libraryScore?: number;
1333
1343
  }
1334
1344
  /**
1335
1345
  * Calculate the Testability Index for a project.
@@ -1345,6 +1355,7 @@ interface TestabilityIndex {
1345
1355
  * @param params.totalInterfaces - Total number of interfaces analyzed.
1346
1356
  * @param params.externalStateMutations - Count of nodes that mutate external state.
1347
1357
  * @param params.hasTestFramework - Whether a testing framework (e.g., Vitest) is detected.
1358
+ * @param params.fileDetails - Optional per-file data for detailed analysis.
1348
1359
  * @returns Comprehensive TestabilityIndex analysis.
1349
1360
  */
1350
1361
  declare function calculateTestabilityIndex(params: {
@@ -1358,6 +1369,11 @@ declare function calculateTestabilityIndex(params: {
1358
1369
  totalInterfaces: number;
1359
1370
  externalStateMutations: number;
1360
1371
  hasTestFramework: boolean;
1372
+ fileDetails?: Array<{
1373
+ filePath: string;
1374
+ pureFunctions: number;
1375
+ totalFunctions: number;
1376
+ }>;
1361
1377
  }): TestabilityIndex;
1362
1378
 
1363
1379
  /**
@@ -1638,4 +1654,4 @@ declare function severityToAnnotationLevel(severity: string): 'error' | 'warning
1638
1654
  */
1639
1655
  declare function emitIssuesAsAnnotations(issues: any[]): void;
1640
1656
 
1641
- export { AIReadyConfig, AcceptancePrediction, type AgentGroundingScore, type AiSignalClarity, type AiSignalClaritySignal, AnalysisResult, type CLIOptions, CSharpParser, type ChangeAmplificationScore, type CognitiveLoad, ComprehensionDifficulty, type ConceptCohesion, CostConfig, DEFAULT_COST_CONFIG, DEFAULT_EXCLUDE, type DependencyHealthScore, type DocDriftRisk, ExportInfo, ExportWithImports, FileImport, type FileWithDomain, GoParser, Issue, JavaParser, type KnowledgeConcentrationRisk, Language, LanguageParser, type LoadFactor, MODEL_PRICING_PRESETS, Metrics, ModelContextTier, type ModelPricingPreset, NamingConvention, ParseResult, ParserFactory, type PatternEntropy, ProductivityImpact, type ProviderFactoryConfig, PythonParser, SEVERITY_TIME_ESTIMATES, ScanOptions, type ScoreHistoryEntry, type ScoreTrend, type SemanticDistance, Severity, Severity as SeverityType, SpokeOutput, type TechnicalDebtInterest, TechnicalValueChain, TechnicalValueChainSummary, type TestabilityIndex, TokenBudget, ToolName, ToolOptions, type ToolProvider, ToolRegistry, ToolScoringOutput, TypeScriptParser, VAGUE_FILE_NAMES, buildSimpleProviderScore, buildSpokeOutput, calculateAgentGrounding, calculateAiSignalClarity, calculateBusinessROI, calculateChangeAmplification, calculateCognitiveLoad, calculateComprehensionDifficulty, calculateConceptCohesion, calculateDebtInterest, calculateDependencyHealth, calculateDocDrift, calculateExtendedFutureProofScore, calculateFutureProofScore, calculateImportSimilarity, calculateKnowledgeConcentration, calculateMonthlyCost, calculatePatternEntropy, calculateProductivityImpact, calculateSemanticDistance, calculateTechnicalValueChain, calculateTestabilityIndex, calculateTokenBudget, clearHistory, createProvider, emitAnnotation, emitIssuesAsAnnotations, emitProgress, estimateCostFromBudget, estimateTokens, exportHistory, findLatestReport, findLatestScanReport, formatAcceptanceRate, formatCost, formatHours, generateValueChain, getElapsedTime, getFileCommitTimestamps, getFileExtension, getHistorySummary, getLineRangeLastModifiedCached, getModelPreset, getParser, getRepoMetadata, getSafetyIcon, getScoreBar, getSeverityBadge, getSeverityColor, getSeverityEnum, getSeverityLevel, getSeverityValue, getSupportedLanguages, getWasmPath, groupIssuesByFile, handleCLIError, handleJSONOutput, initTreeSitter, initializeParsers, isFileSupported, isSourceFile, loadConfig, loadMergedConfig, loadScoreHistory, mergeConfigWithDefaults, normalizeAnalysisResult, normalizeIssue, normalizeMetrics, normalizeSpokeOutput, parseFileExports, predictAcceptanceRate, readFileContent, resolveOutputPath, saveScoreEntry, scanEntries, scanFiles, setupParser, severityToAnnotationLevel, validateSpokeOutput, validateWithSchema };
1657
+ export { AIReadyConfig, AcceptancePrediction, type AgentGroundingScore, type AiSignalClarity, type AiSignalClaritySignal, AnalysisResult, type CLIOptions, CSharpParser, type ChangeAmplificationScore, type CognitiveLoad, ComprehensionDifficulty, type ConceptCohesion, CostConfig, DEFAULT_COST_CONFIG, DEFAULT_EXCLUDE, type DependencyHealthScore, type DocDriftRisk, ExportInfo, ExportWithImports, FileImport, type FileTestability, type FileWithDomain, GoParser, Issue, JavaParser, type KnowledgeConcentrationRisk, Language, LanguageParser, type LoadFactor, MODEL_PRICING_PRESETS, Metrics, ModelContextTier, type ModelPricingPreset, NamingConvention, ParseResult, ParserFactory, type PatternEntropy, ProductivityImpact, type ProviderFactoryConfig, PythonParser, SEVERITY_TIME_ESTIMATES, ScanOptions, type ScoreHistoryEntry, type ScoreTrend, type SemanticDistance, Severity, Severity as SeverityType, SpokeOutput, type TechnicalDebtInterest, TechnicalValueChain, TechnicalValueChainSummary, type TestabilityIndex, TokenBudget, ToolName, ToolOptions, type ToolProvider, ToolRegistry, ToolScoringOutput, TypeScriptParser, VAGUE_FILE_NAMES, buildSimpleProviderScore, buildSpokeOutput, calculateAgentGrounding, calculateAiSignalClarity, calculateBusinessROI, calculateChangeAmplification, calculateCognitiveLoad, calculateComprehensionDifficulty, calculateConceptCohesion, calculateDebtInterest, calculateDependencyHealth, calculateDocDrift, calculateExtendedFutureProofScore, calculateFutureProofScore, calculateImportSimilarity, calculateKnowledgeConcentration, calculateMonthlyCost, calculatePatternEntropy, calculateProductivityImpact, calculateSemanticDistance, calculateTechnicalValueChain, calculateTestabilityIndex, calculateTokenBudget, clearHistory, createProvider, emitAnnotation, emitIssuesAsAnnotations, emitProgress, estimateCostFromBudget, estimateTokens, exportHistory, findLatestReport, findLatestScanReport, formatAcceptanceRate, formatCost, formatHours, generateValueChain, getElapsedTime, getFileCommitTimestamps, getFileExtension, getHistorySummary, getLineRangeLastModifiedCached, getModelPreset, getParser, getRepoMetadata, getSafetyIcon, getScoreBar, getSeverityBadge, getSeverityColor, getSeverityEnum, getSeverityLevel, getSeverityValue, getSupportedLanguages, getWasmPath, groupIssuesByFile, handleCLIError, handleJSONOutput, initTreeSitter, initializeParsers, isFileSupported, isSourceFile, loadConfig, loadMergedConfig, loadScoreHistory, mergeConfigWithDefaults, normalizeAnalysisResult, normalizeIssue, normalizeMetrics, normalizeSpokeOutput, parseFileExports, predictAcceptanceRate, readFileContent, resolveOutputPath, saveScoreEntry, scanEntries, scanFiles, setupParser, severityToAnnotationLevel, validateSpokeOutput, validateWithSchema };
package/dist/index.js CHANGED
@@ -372,8 +372,16 @@ var AIReadyConfigSchema = import_zod.z.object({
372
372
  profile: import_zod.z.string().optional(),
373
373
  /** Custom weights for tools and metrics */
374
374
  weights: import_zod.z.record(import_zod.z.string(), import_zod.z.number()).optional()
375
+ }).optional(),
376
+ /** Visualizer settings (interactive graph) */
377
+ visualizer: import_zod.z.object({
378
+ groupingDirs: import_zod.z.array(import_zod.z.string()).optional(),
379
+ graph: import_zod.z.object({
380
+ maxNodes: import_zod.z.number().optional(),
381
+ maxEdges: import_zod.z.number().optional()
382
+ }).optional()
375
383
  }).optional()
376
- });
384
+ }).catchall(import_zod.z.any());
377
385
 
378
386
  // src/types/business.ts
379
387
  var import_zod2 = require("zod");
@@ -4682,6 +4690,40 @@ function calculateAgentGrounding(params) {
4682
4690
  }
4683
4691
 
4684
4692
  // src/metrics/testability-index.ts
4693
+ function isLikelyEntryPoint(filePath) {
4694
+ const basename = filePath.split("/").pop() || "";
4695
+ const lowerBasename = basename.toLowerCase();
4696
+ const entryPointPatterns = [
4697
+ "cli",
4698
+ "main",
4699
+ "bin",
4700
+ "index",
4701
+ // often used as entry point
4702
+ "run",
4703
+ "serve",
4704
+ "start",
4705
+ "boot",
4706
+ "init"
4707
+ ];
4708
+ const nameWithoutExt = lowerBasename.replace(
4709
+ /\.(ts|js|tsx|jsx|mjs|cjs)$/,
4710
+ ""
4711
+ );
4712
+ if (entryPointPatterns.some(
4713
+ (p) => nameWithoutExt === p || nameWithoutExt.endsWith(`-${p}`) || nameWithoutExt.startsWith(`${p}-`)
4714
+ )) {
4715
+ return true;
4716
+ }
4717
+ const cliDirPatterns = ["/bin/", "/cli/", "/cmd/", "/commands/"];
4718
+ if (cliDirPatterns.some((p) => filePath.includes(p))) {
4719
+ return true;
4720
+ }
4721
+ return false;
4722
+ }
4723
+ function calculateFilePurityScore(pureFunctions, totalFunctions) {
4724
+ if (totalFunctions === 0) return 100;
4725
+ return Math.round(pureFunctions / totalFunctions * 100);
4726
+ }
4685
4727
  function calculateTestabilityIndex(params) {
4686
4728
  const {
4687
4729
  testFiles,
@@ -4693,7 +4735,8 @@ function calculateTestabilityIndex(params) {
4693
4735
  bloatedInterfaces,
4694
4736
  totalInterfaces,
4695
4737
  externalStateMutations,
4696
- hasTestFramework
4738
+ hasTestFramework,
4739
+ fileDetails
4697
4740
  } = params;
4698
4741
  const rawCoverageRatio = sourceFiles > 0 ? testFiles / sourceFiles : 0;
4699
4742
  const testCoverageRatio = Math.min(100, Math.round(rawCoverageRatio * 100));
@@ -4719,7 +4762,39 @@ function calculateTestabilityIndex(params) {
4719
4762
  )
4720
4763
  );
4721
4764
  const frameworkWeight = hasTestFramework ? 1 : 0.8;
4722
- const rawScore = (testCoverageRatio * 0.3 + purityScore * 0.25 + dependencyInjectionScore * 0.2 + interfaceFocusScore * 0.1 + observabilityScore * 0.15) * frameworkWeight;
4765
+ let fileMetrics;
4766
+ let libraryPureFunctions = pureFunctions;
4767
+ let libraryTotalFunctions = totalFunctions;
4768
+ let entryPointCount = 0;
4769
+ if (fileDetails && fileDetails.length > 0) {
4770
+ fileMetrics = fileDetails.map((file) => {
4771
+ const isEntryPoint = isLikelyEntryPoint(file.filePath);
4772
+ const purityScore2 = calculateFilePurityScore(
4773
+ file.pureFunctions,
4774
+ file.totalFunctions
4775
+ );
4776
+ if (isEntryPoint) {
4777
+ entryPointCount++;
4778
+ libraryPureFunctions -= file.pureFunctions;
4779
+ libraryTotalFunctions -= file.totalFunctions;
4780
+ }
4781
+ return {
4782
+ filePath: file.filePath,
4783
+ score: purityScore2,
4784
+ // Simplified - just purity for file-level
4785
+ purityScore: purityScore2,
4786
+ isEntryPoint
4787
+ };
4788
+ });
4789
+ }
4790
+ const libraryPurityScore = Math.max(
4791
+ 0,
4792
+ Math.round(
4793
+ (libraryTotalFunctions > 0 ? libraryPureFunctions / libraryTotalFunctions : 0.7) * 100
4794
+ )
4795
+ );
4796
+ const effectivePurityScore = fileDetails && fileDetails.length > 0 ? libraryPurityScore : purityScore;
4797
+ const rawScore = (testCoverageRatio * 0.3 + effectivePurityScore * 0.25 + dependencyInjectionScore * 0.2 + interfaceFocusScore * 0.1 + observabilityScore * 0.15) * frameworkWeight;
4723
4798
  const score = Math.max(0, Math.min(100, Math.round(rawScore)));
4724
4799
  let rating;
4725
4800
  if (score >= 85) rating = "excellent";
@@ -4744,9 +4819,9 @@ function calculateTestabilityIndex(params) {
4744
4819
  `Add ~${neededTests} test files to reach 30% coverage ratio \u2014 minimum for safe AI assistance`
4745
4820
  );
4746
4821
  }
4747
- if (purityScore < 50)
4822
+ if (effectivePurityScore < 50)
4748
4823
  recommendations.push(
4749
- "Extract pure functions from side-effectful code \u2014 pure functions are trivially AI-testable"
4824
+ entryPointCount > 0 ? `Extract pure functions from library code (${entryPointCount} entry point files excluded) \u2014 pure functions are trivially AI-testable` : "Extract pure functions from side-effectful code \u2014 pure functions are trivially AI-testable"
4750
4825
  );
4751
4826
  if (dependencyInjectionScore < 50 && totalClasses > 0)
4752
4827
  recommendations.push(
@@ -4761,13 +4836,15 @@ function calculateTestabilityIndex(params) {
4761
4836
  rating,
4762
4837
  dimensions: {
4763
4838
  testCoverageRatio,
4764
- purityScore,
4839
+ purityScore: effectivePurityScore,
4765
4840
  dependencyInjectionScore,
4766
4841
  interfaceFocusScore,
4767
4842
  observabilityScore
4768
4843
  },
4769
4844
  aiChangeSafetyRating,
4770
- recommendations
4845
+ recommendations,
4846
+ fileMetrics,
4847
+ libraryScore: Math.max(0, fileMetrics ? libraryPurityScore : purityScore)
4771
4848
  };
4772
4849
  }
4773
4850
 
package/dist/index.mjs CHANGED
@@ -50,7 +50,7 @@ import {
50
50
  getToolWeight,
51
51
  normalizeToolName,
52
52
  parseWeightString
53
- } from "./chunk-TJXR2CHZ.mjs";
53
+ } from "./chunk-CGOS2J6T.mjs";
54
54
 
55
55
  // src/utils/normalization.ts
56
56
  function normalizeIssue(raw) {
@@ -3818,6 +3818,40 @@ function calculateAgentGrounding(params) {
3818
3818
  }
3819
3819
 
3820
3820
  // src/metrics/testability-index.ts
3821
+ function isLikelyEntryPoint(filePath) {
3822
+ const basename = filePath.split("/").pop() || "";
3823
+ const lowerBasename = basename.toLowerCase();
3824
+ const entryPointPatterns = [
3825
+ "cli",
3826
+ "main",
3827
+ "bin",
3828
+ "index",
3829
+ // often used as entry point
3830
+ "run",
3831
+ "serve",
3832
+ "start",
3833
+ "boot",
3834
+ "init"
3835
+ ];
3836
+ const nameWithoutExt = lowerBasename.replace(
3837
+ /\.(ts|js|tsx|jsx|mjs|cjs)$/,
3838
+ ""
3839
+ );
3840
+ if (entryPointPatterns.some(
3841
+ (p) => nameWithoutExt === p || nameWithoutExt.endsWith(`-${p}`) || nameWithoutExt.startsWith(`${p}-`)
3842
+ )) {
3843
+ return true;
3844
+ }
3845
+ const cliDirPatterns = ["/bin/", "/cli/", "/cmd/", "/commands/"];
3846
+ if (cliDirPatterns.some((p) => filePath.includes(p))) {
3847
+ return true;
3848
+ }
3849
+ return false;
3850
+ }
3851
+ function calculateFilePurityScore(pureFunctions, totalFunctions) {
3852
+ if (totalFunctions === 0) return 100;
3853
+ return Math.round(pureFunctions / totalFunctions * 100);
3854
+ }
3821
3855
  function calculateTestabilityIndex(params) {
3822
3856
  const {
3823
3857
  testFiles,
@@ -3829,7 +3863,8 @@ function calculateTestabilityIndex(params) {
3829
3863
  bloatedInterfaces,
3830
3864
  totalInterfaces,
3831
3865
  externalStateMutations,
3832
- hasTestFramework
3866
+ hasTestFramework,
3867
+ fileDetails
3833
3868
  } = params;
3834
3869
  const rawCoverageRatio = sourceFiles > 0 ? testFiles / sourceFiles : 0;
3835
3870
  const testCoverageRatio = Math.min(100, Math.round(rawCoverageRatio * 100));
@@ -3855,7 +3890,39 @@ function calculateTestabilityIndex(params) {
3855
3890
  )
3856
3891
  );
3857
3892
  const frameworkWeight = hasTestFramework ? 1 : 0.8;
3858
- const rawScore = (testCoverageRatio * 0.3 + purityScore * 0.25 + dependencyInjectionScore * 0.2 + interfaceFocusScore * 0.1 + observabilityScore * 0.15) * frameworkWeight;
3893
+ let fileMetrics;
3894
+ let libraryPureFunctions = pureFunctions;
3895
+ let libraryTotalFunctions = totalFunctions;
3896
+ let entryPointCount = 0;
3897
+ if (fileDetails && fileDetails.length > 0) {
3898
+ fileMetrics = fileDetails.map((file) => {
3899
+ const isEntryPoint = isLikelyEntryPoint(file.filePath);
3900
+ const purityScore2 = calculateFilePurityScore(
3901
+ file.pureFunctions,
3902
+ file.totalFunctions
3903
+ );
3904
+ if (isEntryPoint) {
3905
+ entryPointCount++;
3906
+ libraryPureFunctions -= file.pureFunctions;
3907
+ libraryTotalFunctions -= file.totalFunctions;
3908
+ }
3909
+ return {
3910
+ filePath: file.filePath,
3911
+ score: purityScore2,
3912
+ // Simplified - just purity for file-level
3913
+ purityScore: purityScore2,
3914
+ isEntryPoint
3915
+ };
3916
+ });
3917
+ }
3918
+ const libraryPurityScore = Math.max(
3919
+ 0,
3920
+ Math.round(
3921
+ (libraryTotalFunctions > 0 ? libraryPureFunctions / libraryTotalFunctions : 0.7) * 100
3922
+ )
3923
+ );
3924
+ const effectivePurityScore = fileDetails && fileDetails.length > 0 ? libraryPurityScore : purityScore;
3925
+ const rawScore = (testCoverageRatio * 0.3 + effectivePurityScore * 0.25 + dependencyInjectionScore * 0.2 + interfaceFocusScore * 0.1 + observabilityScore * 0.15) * frameworkWeight;
3859
3926
  const score = Math.max(0, Math.min(100, Math.round(rawScore)));
3860
3927
  let rating;
3861
3928
  if (score >= 85) rating = "excellent";
@@ -3880,9 +3947,9 @@ function calculateTestabilityIndex(params) {
3880
3947
  `Add ~${neededTests} test files to reach 30% coverage ratio \u2014 minimum for safe AI assistance`
3881
3948
  );
3882
3949
  }
3883
- if (purityScore < 50)
3950
+ if (effectivePurityScore < 50)
3884
3951
  recommendations.push(
3885
- "Extract pure functions from side-effectful code \u2014 pure functions are trivially AI-testable"
3952
+ entryPointCount > 0 ? `Extract pure functions from library code (${entryPointCount} entry point files excluded) \u2014 pure functions are trivially AI-testable` : "Extract pure functions from side-effectful code \u2014 pure functions are trivially AI-testable"
3886
3953
  );
3887
3954
  if (dependencyInjectionScore < 50 && totalClasses > 0)
3888
3955
  recommendations.push(
@@ -3897,13 +3964,15 @@ function calculateTestabilityIndex(params) {
3897
3964
  rating,
3898
3965
  dimensions: {
3899
3966
  testCoverageRatio,
3900
- purityScore,
3967
+ purityScore: effectivePurityScore,
3901
3968
  dependencyInjectionScore,
3902
3969
  interfaceFocusScore,
3903
3970
  observabilityScore
3904
3971
  },
3905
3972
  aiChangeSafetyRating,
3906
- recommendations
3973
+ recommendations,
3974
+ fileMetrics,
3975
+ libraryScore: Math.max(0, fileMetrics ? libraryPurityScore : purityScore)
3907
3976
  };
3908
3977
  }
3909
3978
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiready/core",
3
- "version": "0.23.8",
3
+ "version": "0.23.9",
4
4
  "description": "Shared utilities for AIReady analysis tools",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",