@ipation/specbridge 2.3.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/README.md +2 -0
- package/dist/cli.js +334 -283
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +120 -64
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { SourceFile, Project } from 'ts-morph';
|
|
3
3
|
import { Document } from 'yaml';
|
|
4
|
+
import { Logger as Logger$1 } from 'pino';
|
|
4
5
|
import { Application } from 'express';
|
|
5
6
|
export { minimatch } from 'minimatch';
|
|
6
7
|
|
|
@@ -1127,6 +1128,7 @@ declare class VerificationEngine {
|
|
|
1127
1128
|
private astCache;
|
|
1128
1129
|
private resultsCache;
|
|
1129
1130
|
private pluginsLoaded;
|
|
1131
|
+
private logger;
|
|
1130
1132
|
constructor(registry?: Registry);
|
|
1131
1133
|
/**
|
|
1132
1134
|
* Run verification
|
|
@@ -1556,6 +1558,7 @@ interface StoredReport {
|
|
|
1556
1558
|
*/
|
|
1557
1559
|
declare class ReportStorage {
|
|
1558
1560
|
private storageDir;
|
|
1561
|
+
private logger;
|
|
1559
1562
|
constructor(basePath: string);
|
|
1560
1563
|
/**
|
|
1561
1564
|
* Save a compliance report to storage
|
|
@@ -1850,6 +1853,10 @@ declare function matchesAnyPattern(filePath: string, patterns: string[], options
|
|
|
1850
1853
|
cwd?: string;
|
|
1851
1854
|
}): boolean;
|
|
1852
1855
|
|
|
1856
|
+
type Logger = Pick<Logger$1, 'debug' | 'info' | 'warn' | 'error' | 'child'>;
|
|
1857
|
+
declare function getLogger(bindings?: Record<string, unknown>): Logger;
|
|
1858
|
+
declare const logger: Logger;
|
|
1859
|
+
|
|
1853
1860
|
/**
|
|
1854
1861
|
* Analytics engine - Provide insights into compliance trends and decision impact
|
|
1855
1862
|
*/
|
|
@@ -1935,6 +1942,7 @@ declare class DashboardServer {
|
|
|
1935
1942
|
private cacheTimestamp;
|
|
1936
1943
|
private readonly CACHE_TTL;
|
|
1937
1944
|
private refreshInterval;
|
|
1945
|
+
private logger;
|
|
1938
1946
|
constructor(options: DashboardOptions);
|
|
1939
1947
|
/**
|
|
1940
1948
|
* Start the server with background cache refresh
|
|
@@ -2006,4 +2014,4 @@ interface GitHubPrCommentOptions {
|
|
|
2006
2014
|
declare function formatViolationsForGitHub(violations: Violation[], limit?: number): string;
|
|
2007
2015
|
declare function postPrComment(violations: Violation[], options: GitHubPrCommentOptions): Promise<void>;
|
|
2008
2016
|
|
|
2009
|
-
export { type AffectedFile, type AgentContext, AgentContextGenerator, AlreadyInitializedError, AnalyticsEngine, type AnalyticsSummary, type Analyzer, AnalyzerNotFoundError, ApiVerifier, type ApplicableConstraint, type ApplicableDecision, AstCache, AutofixEngine, type AutofixPatch, type AutofixResult, type BuildDependencyGraphOptions, CodeScanner, ComplexityVerifier, type ComplianceReport, ConfigError, type Constraint, type ConstraintCheck, ConstraintCheckSchema, type ConstraintCheckSchema_, type ConstraintException, ConstraintExceptionSchema, type ConstraintExceptionSchema_, ConstraintSchema, type ConstraintSchema_, type ConstraintType, ConstraintTypeSchema, type ConstraintTypeSchema_, type ContextOptions, DashboardServer, type Decision, type DecisionCompliance, type DecisionContent, DecisionContentSchema, type DecisionContentSchema_, type DecisionFilter, type DecisionMetadata, DecisionMetadataSchema, type DecisionMetadataSchema_, type DecisionMetrics, DecisionNotFoundError, DecisionSchema, type DecisionStatus, DecisionStatusSchema, type DecisionStatusSchema_, type DecisionTypeSchema, DecisionValidationError, type DependencyGraph, DependencyVerifier, type DriftAnalysis, ErrorsAnalyzer, ErrorsVerifier, FileSystemError, type GitHubPrCommentOptions, type GlobOptions, type GraphNode, HookError, type ImpactAnalysis, ImportsAnalyzer, ImportsVerifier, InferenceEngine, InferenceError, type InferenceOptions, type InferenceResult, type Insight, type LevelConfig, LinksSchema, type LoadError, type LoadResult, type LoadedDecision, type McpServerOptions, type MigrationStep, NamingAnalyzer, NamingVerifier, NotInitializedError, type OverallDrift, type Pattern, type PatternExample, type PromptTemplate, PropagationEngine, type PropagationOptions, RegexVerifier, Registry, type RegistryConstraintMatch, RegistryError, type RegistryOptions, type ReportOptions, ReportStorage, Reporter, type ReporterResult, type ScanOptions, type ScanResult, type ScannedFile, SecurityVerifier, type Severity, SeveritySchema, type SeveritySchema_, type SpecBridgeConfig, SpecBridgeConfigSchema, type SpecBridgeConfigType, SpecBridgeError, SpecBridgeMcpServer, type StoredReport, StructureAnalyzer, type TextEdit, type TrendAnalysis, type TrendData, type TrendDirection, type VerificationConfig, VerificationConfigSchema, type VerificationConfigSchema_, type VerificationContext, VerificationEngine, VerificationError, type VerificationFrequency, VerificationFrequencySchema, type VerificationFrequencySchema_, type VerificationIssue, type VerificationLevel, type VerificationOptions, type VerificationResult, type VerificationWarning, type Verifier, VerifierNotFoundError, type VerifierPlugin, type VerifierPluginMetadata, type Violation, type ViolationFix, analyzeTrend, buildDependencyGraph, builtinAnalyzers, builtinVerifiers, calculateConfidence, checkDegradation, clearVerifierPool, createDashboardServer, createInferenceEngine, createPattern, createPropagationEngine, createRegistry, createScannerFromConfig, createVerificationEngine, createViolation, defaultConfig, defineVerifierPlugin, detectDrift, ensureDir, extractSnippet, formatConsoleReport, formatContextAsJson, formatContextAsMarkdown, formatContextAsMcp, formatError, formatMarkdownReport, formatValidationErrors, formatViolationsForGitHub, generateContext, generateFormattedContext, generateReport, getAffectedFiles, getAffectingDecisions, getAnalyzer, getAnalyzerIds, getChangedFiles, getConfigPath, getDecisionsDir, getInferredDir, getReportsDir, getSpecBridgeDir, getTransitiveDependencies, getVerifier, getVerifierIds, getVerifiersDir, glob, isConstraintExcepted, isDirectory, loadConfig, loadDecisionFile, loadDecisionsFromDir, matchesAnyPattern, matchesPattern, mergeWithDefaults, normalizePath, parseYaml, parseYamlDocument, pathExists, postPrComment, readFilesInDir, readTextFile, runInference, selectVerifierForConstraint, shouldApplyConstraintToFile, startLspServer, stringifyYaml, templates, updateYamlDocument, validateConfig, validateDecision, validateDecisionFile, writeTextFile };
|
|
2017
|
+
export { type AffectedFile, type AgentContext, AgentContextGenerator, AlreadyInitializedError, AnalyticsEngine, type AnalyticsSummary, type Analyzer, AnalyzerNotFoundError, ApiVerifier, type ApplicableConstraint, type ApplicableDecision, AstCache, AutofixEngine, type AutofixPatch, type AutofixResult, type BuildDependencyGraphOptions, CodeScanner, ComplexityVerifier, type ComplianceReport, ConfigError, type Constraint, type ConstraintCheck, ConstraintCheckSchema, type ConstraintCheckSchema_, type ConstraintException, ConstraintExceptionSchema, type ConstraintExceptionSchema_, ConstraintSchema, type ConstraintSchema_, type ConstraintType, ConstraintTypeSchema, type ConstraintTypeSchema_, type ContextOptions, DashboardServer, type Decision, type DecisionCompliance, type DecisionContent, DecisionContentSchema, type DecisionContentSchema_, type DecisionFilter, type DecisionMetadata, DecisionMetadataSchema, type DecisionMetadataSchema_, type DecisionMetrics, DecisionNotFoundError, DecisionSchema, type DecisionStatus, DecisionStatusSchema, type DecisionStatusSchema_, type DecisionTypeSchema, DecisionValidationError, type DependencyGraph, DependencyVerifier, type DriftAnalysis, ErrorsAnalyzer, ErrorsVerifier, FileSystemError, type GitHubPrCommentOptions, type GlobOptions, type GraphNode, HookError, type ImpactAnalysis, ImportsAnalyzer, ImportsVerifier, InferenceEngine, InferenceError, type InferenceOptions, type InferenceResult, type Insight, type LevelConfig, LinksSchema, type LoadError, type LoadResult, type LoadedDecision, type Logger, type McpServerOptions, type MigrationStep, NamingAnalyzer, NamingVerifier, NotInitializedError, type OverallDrift, type Pattern, type PatternExample, type PromptTemplate, PropagationEngine, type PropagationOptions, RegexVerifier, Registry, type RegistryConstraintMatch, RegistryError, type RegistryOptions, type ReportOptions, ReportStorage, Reporter, type ReporterResult, type ScanOptions, type ScanResult, type ScannedFile, SecurityVerifier, type Severity, SeveritySchema, type SeveritySchema_, type SpecBridgeConfig, SpecBridgeConfigSchema, type SpecBridgeConfigType, SpecBridgeError, SpecBridgeMcpServer, type StoredReport, StructureAnalyzer, type TextEdit, type TrendAnalysis, type TrendData, type TrendDirection, type VerificationConfig, VerificationConfigSchema, type VerificationConfigSchema_, type VerificationContext, VerificationEngine, VerificationError, type VerificationFrequency, VerificationFrequencySchema, type VerificationFrequencySchema_, type VerificationIssue, type VerificationLevel, type VerificationOptions, type VerificationResult, type VerificationWarning, type Verifier, VerifierNotFoundError, type VerifierPlugin, type VerifierPluginMetadata, type Violation, type ViolationFix, analyzeTrend, buildDependencyGraph, builtinAnalyzers, builtinVerifiers, calculateConfidence, checkDegradation, clearVerifierPool, createDashboardServer, createInferenceEngine, createPattern, createPropagationEngine, createRegistry, createScannerFromConfig, createVerificationEngine, createViolation, defaultConfig, defineVerifierPlugin, detectDrift, ensureDir, extractSnippet, formatConsoleReport, formatContextAsJson, formatContextAsMarkdown, formatContextAsMcp, formatError, formatMarkdownReport, formatValidationErrors, formatViolationsForGitHub, generateContext, generateFormattedContext, generateReport, getAffectedFiles, getAffectingDecisions, getAnalyzer, getAnalyzerIds, getChangedFiles, getConfigPath, getDecisionsDir, getInferredDir, getLogger, getReportsDir, getSpecBridgeDir, getTransitiveDependencies, getVerifier, getVerifierIds, getVerifiersDir, glob, isConstraintExcepted, isDirectory, loadConfig, loadDecisionFile, loadDecisionsFromDir, logger, matchesAnyPattern, matchesPattern, mergeWithDefaults, normalizePath, parseYaml, parseYamlDocument, pathExists, postPrComment, readFilesInDir, readTextFile, runInference, selectVerifierForConstraint, shouldApplyConstraintToFile, startLspServer, stringifyYaml, templates, updateYamlDocument, validateConfig, validateDecision, validateDecisionFile, writeTextFile };
|
package/dist/index.js
CHANGED
|
@@ -1582,7 +1582,6 @@ async function runInference(config, options) {
|
|
|
1582
1582
|
|
|
1583
1583
|
// src/verification/engine.ts
|
|
1584
1584
|
import { Project as Project2 } from "ts-morph";
|
|
1585
|
-
import chalk from "chalk";
|
|
1586
1585
|
|
|
1587
1586
|
// src/verification/verifiers/base.ts
|
|
1588
1587
|
function defineVerifierPlugin(plugin) {
|
|
@@ -2150,7 +2149,8 @@ var DependencyVerifier = class {
|
|
|
2150
2149
|
const sccs = tarjanScc(graph);
|
|
2151
2150
|
const current = projectFilePath;
|
|
2152
2151
|
for (const scc of sccs) {
|
|
2153
|
-
const
|
|
2152
|
+
const first = scc[0];
|
|
2153
|
+
const hasSelfLoop = first !== void 0 && scc.length === 1 && (graph.get(first)?.has(first) ?? false);
|
|
2154
2154
|
const isCycle = scc.length > 1 || hasSelfLoop;
|
|
2155
2155
|
if (!isCycle) continue;
|
|
2156
2156
|
if (!scc.includes(current)) continue;
|
|
@@ -2591,10 +2591,36 @@ import { existsSync } from "fs";
|
|
|
2591
2591
|
import { join as join3 } from "path";
|
|
2592
2592
|
import { pathToFileURL } from "url";
|
|
2593
2593
|
import fg2 from "fast-glob";
|
|
2594
|
+
|
|
2595
|
+
// src/utils/logger.ts
|
|
2596
|
+
import pino from "pino";
|
|
2597
|
+
var defaultOptions = {
|
|
2598
|
+
level: process.env.SPECBRIDGE_LOG_LEVEL || "info",
|
|
2599
|
+
timestamp: pino.stdTimeFunctions.isoTime,
|
|
2600
|
+
base: {
|
|
2601
|
+
service: "specbridge"
|
|
2602
|
+
}
|
|
2603
|
+
};
|
|
2604
|
+
var destination = pino.destination({
|
|
2605
|
+
fd: 2,
|
|
2606
|
+
// stderr
|
|
2607
|
+
sync: false
|
|
2608
|
+
});
|
|
2609
|
+
var rootLogger = pino(defaultOptions, destination);
|
|
2610
|
+
function getLogger(bindings) {
|
|
2611
|
+
if (!bindings) {
|
|
2612
|
+
return rootLogger;
|
|
2613
|
+
}
|
|
2614
|
+
return rootLogger.child(bindings);
|
|
2615
|
+
}
|
|
2616
|
+
var logger = getLogger();
|
|
2617
|
+
|
|
2618
|
+
// src/verification/plugins/loader.ts
|
|
2594
2619
|
var PluginLoader = class {
|
|
2595
2620
|
plugins = /* @__PURE__ */ new Map();
|
|
2596
2621
|
loaded = false;
|
|
2597
2622
|
loadErrors = [];
|
|
2623
|
+
logger = getLogger({ module: "verification.plugins.loader" });
|
|
2598
2624
|
/**
|
|
2599
2625
|
* Load all plugins from the specified base path
|
|
2600
2626
|
*
|
|
@@ -2617,15 +2643,15 @@ var PluginLoader = class {
|
|
|
2617
2643
|
} catch (error) {
|
|
2618
2644
|
const message = error instanceof Error ? error.message : String(error);
|
|
2619
2645
|
this.loadErrors.push({ file, error: message });
|
|
2620
|
-
|
|
2646
|
+
this.logger.warn({ file, error: message }, "Failed to load plugin");
|
|
2621
2647
|
}
|
|
2622
2648
|
}
|
|
2623
2649
|
this.loaded = true;
|
|
2624
2650
|
if (this.plugins.size > 0) {
|
|
2625
|
-
|
|
2651
|
+
this.logger.info({ count: this.plugins.size }, "Loaded custom verifier plugins");
|
|
2626
2652
|
}
|
|
2627
2653
|
if (this.loadErrors.length > 0) {
|
|
2628
|
-
|
|
2654
|
+
this.logger.warn({ count: this.loadErrors.length }, "Plugin load failures");
|
|
2629
2655
|
}
|
|
2630
2656
|
}
|
|
2631
2657
|
/**
|
|
@@ -2801,8 +2827,9 @@ var builtinVerifiers = {
|
|
|
2801
2827
|
};
|
|
2802
2828
|
var verifierInstances = /* @__PURE__ */ new Map();
|
|
2803
2829
|
function getVerifier(id) {
|
|
2804
|
-
|
|
2805
|
-
|
|
2830
|
+
const pooled = verifierInstances.get(id);
|
|
2831
|
+
if (pooled) {
|
|
2832
|
+
return pooled;
|
|
2806
2833
|
}
|
|
2807
2834
|
const pluginLoader2 = getPluginLoader();
|
|
2808
2835
|
const customVerifier = pluginLoader2.getVerifier(id);
|
|
@@ -3007,6 +3034,7 @@ var VerificationEngine = class {
|
|
|
3007
3034
|
astCache;
|
|
3008
3035
|
resultsCache;
|
|
3009
3036
|
pluginsLoaded = false;
|
|
3037
|
+
logger = getLogger({ module: "verification.engine" });
|
|
3010
3038
|
constructor(registry) {
|
|
3011
3039
|
this.registry = registry || createRegistry();
|
|
3012
3040
|
this.project = new Project2({
|
|
@@ -3180,13 +3208,12 @@ var VerificationEngine = class {
|
|
|
3180
3208
|
);
|
|
3181
3209
|
if (!verifier) {
|
|
3182
3210
|
const requestedVerifier = constraint.check?.verifier || constraint.verifier || "auto-detected";
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
);
|
|
3211
|
+
this.logger.warn({
|
|
3212
|
+
decisionId: decision.metadata.id,
|
|
3213
|
+
constraintId: constraint.id,
|
|
3214
|
+
requestedVerifier,
|
|
3215
|
+
availableVerifiers: getVerifierIds()
|
|
3216
|
+
}, "No verifier found for constraint");
|
|
3190
3217
|
warnings.push({
|
|
3191
3218
|
type: "missing_verifier",
|
|
3192
3219
|
message: `No verifier found for constraint (requested: ${requestedVerifier})`,
|
|
@@ -3292,17 +3319,14 @@ var VerificationEngine = class {
|
|
|
3292
3319
|
} catch (error) {
|
|
3293
3320
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3294
3321
|
const errorStack = error instanceof Error ? error.stack : void 0;
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
);
|
|
3303
|
-
if (errorStack) {
|
|
3304
|
-
console.error(chalk.dim(errorStack));
|
|
3305
|
-
}
|
|
3322
|
+
this.logger.error({
|
|
3323
|
+
verifierId: verifier.id,
|
|
3324
|
+
filePath,
|
|
3325
|
+
decisionId: decision.metadata.id,
|
|
3326
|
+
constraintId: constraint.id,
|
|
3327
|
+
error: errorMessage,
|
|
3328
|
+
stack: errorStack
|
|
3329
|
+
}, "Verifier execution failed");
|
|
3306
3330
|
errors.push({
|
|
3307
3331
|
type: "verifier_exception",
|
|
3308
3332
|
message: `Verifier '${verifier.id}' failed: ${errorMessage}`,
|
|
@@ -3438,6 +3462,10 @@ var AutofixEngine = class {
|
|
|
3438
3462
|
const edits = [];
|
|
3439
3463
|
for (const violation of fileViolations) {
|
|
3440
3464
|
const fix = violation.autofix;
|
|
3465
|
+
if (!fix) {
|
|
3466
|
+
skippedViolations++;
|
|
3467
|
+
continue;
|
|
3468
|
+
}
|
|
3441
3469
|
if (options.interactive) {
|
|
3442
3470
|
const ok = await confirmFix(`Apply fix: ${fix.description} (${filePath}:${violation.line ?? 1})?`);
|
|
3443
3471
|
if (!ok) {
|
|
@@ -3566,7 +3594,24 @@ var PropagationEngine = class {
|
|
|
3566
3594
|
if (!this.graph) {
|
|
3567
3595
|
await this.initialize(config, options);
|
|
3568
3596
|
}
|
|
3569
|
-
const
|
|
3597
|
+
const graph = this.graph;
|
|
3598
|
+
if (!graph) {
|
|
3599
|
+
return {
|
|
3600
|
+
decision: decisionId,
|
|
3601
|
+
change,
|
|
3602
|
+
affectedFiles: [],
|
|
3603
|
+
estimatedEffort: "low",
|
|
3604
|
+
migrationSteps: [
|
|
3605
|
+
{
|
|
3606
|
+
order: 1,
|
|
3607
|
+
description: "Run verification to confirm all violations resolved",
|
|
3608
|
+
files: [],
|
|
3609
|
+
automated: true
|
|
3610
|
+
}
|
|
3611
|
+
]
|
|
3612
|
+
};
|
|
3613
|
+
}
|
|
3614
|
+
const affectedFilePaths = getAffectedFiles(graph, decisionId);
|
|
3570
3615
|
const verificationEngine = createVerificationEngine(this.registry);
|
|
3571
3616
|
const result = await verificationEngine.verify(config, {
|
|
3572
3617
|
files: affectedFilePaths,
|
|
@@ -3944,54 +3989,54 @@ var Reporter = class {
|
|
|
3944
3989
|
};
|
|
3945
3990
|
|
|
3946
3991
|
// src/reporting/formats/console.ts
|
|
3947
|
-
import
|
|
3992
|
+
import chalk from "chalk";
|
|
3948
3993
|
import { table } from "table";
|
|
3949
3994
|
function formatConsoleReport(report) {
|
|
3950
3995
|
const lines = [];
|
|
3951
3996
|
lines.push("");
|
|
3952
|
-
lines.push(
|
|
3953
|
-
lines.push(
|
|
3954
|
-
lines.push(
|
|
3997
|
+
lines.push(chalk.bold.blue("SpecBridge Compliance Report"));
|
|
3998
|
+
lines.push(chalk.dim(`Generated: ${new Date(report.timestamp).toLocaleString()}`));
|
|
3999
|
+
lines.push(chalk.dim(`Project: ${report.project}`));
|
|
3955
4000
|
lines.push("");
|
|
3956
4001
|
const complianceColor = getComplianceColor(report.summary.compliance);
|
|
3957
|
-
lines.push(
|
|
4002
|
+
lines.push(chalk.bold("Overall Compliance"));
|
|
3958
4003
|
lines.push(` ${complianceColor(formatComplianceBar(report.summary.compliance))} ${complianceColor(`${report.summary.compliance}%`)}`);
|
|
3959
4004
|
lines.push("");
|
|
3960
|
-
lines.push(
|
|
4005
|
+
lines.push(chalk.bold("Summary"));
|
|
3961
4006
|
lines.push(` Decisions: ${report.summary.activeDecisions} active / ${report.summary.totalDecisions} total`);
|
|
3962
4007
|
lines.push(` Constraints: ${report.summary.totalConstraints}`);
|
|
3963
4008
|
lines.push("");
|
|
3964
|
-
lines.push(
|
|
4009
|
+
lines.push(chalk.bold("Violations"));
|
|
3965
4010
|
const { violations } = report.summary;
|
|
3966
4011
|
const violationParts = [];
|
|
3967
4012
|
if (violations.critical > 0) {
|
|
3968
|
-
violationParts.push(
|
|
4013
|
+
violationParts.push(chalk.red(`${violations.critical} critical`));
|
|
3969
4014
|
}
|
|
3970
4015
|
if (violations.high > 0) {
|
|
3971
|
-
violationParts.push(
|
|
4016
|
+
violationParts.push(chalk.yellow(`${violations.high} high`));
|
|
3972
4017
|
}
|
|
3973
4018
|
if (violations.medium > 0) {
|
|
3974
|
-
violationParts.push(
|
|
4019
|
+
violationParts.push(chalk.cyan(`${violations.medium} medium`));
|
|
3975
4020
|
}
|
|
3976
4021
|
if (violations.low > 0) {
|
|
3977
|
-
violationParts.push(
|
|
4022
|
+
violationParts.push(chalk.dim(`${violations.low} low`));
|
|
3978
4023
|
}
|
|
3979
4024
|
if (violationParts.length > 0) {
|
|
3980
4025
|
lines.push(` ${violationParts.join(" | ")}`);
|
|
3981
4026
|
} else {
|
|
3982
|
-
lines.push(
|
|
4027
|
+
lines.push(chalk.green(" No violations"));
|
|
3983
4028
|
}
|
|
3984
4029
|
lines.push("");
|
|
3985
4030
|
if (report.byDecision.length > 0) {
|
|
3986
|
-
lines.push(
|
|
4031
|
+
lines.push(chalk.bold("By Decision"));
|
|
3987
4032
|
lines.push("");
|
|
3988
4033
|
const tableData = [
|
|
3989
4034
|
[
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
4035
|
+
chalk.bold("Decision"),
|
|
4036
|
+
chalk.bold("Status"),
|
|
4037
|
+
chalk.bold("Constraints"),
|
|
4038
|
+
chalk.bold("Violations"),
|
|
4039
|
+
chalk.bold("Compliance")
|
|
3995
4040
|
]
|
|
3996
4041
|
];
|
|
3997
4042
|
for (const dec of report.byDecision) {
|
|
@@ -4001,7 +4046,7 @@ function formatConsoleReport(report) {
|
|
|
4001
4046
|
truncate(dec.title, 40),
|
|
4002
4047
|
statusColor(dec.status),
|
|
4003
4048
|
String(dec.constraints),
|
|
4004
|
-
dec.violations > 0 ?
|
|
4049
|
+
dec.violations > 0 ? chalk.red(String(dec.violations)) : chalk.green("0"),
|
|
4005
4050
|
compColor(`${dec.compliance}%`)
|
|
4006
4051
|
]);
|
|
4007
4052
|
}
|
|
@@ -4035,23 +4080,23 @@ function formatComplianceBar(compliance) {
|
|
|
4035
4080
|
return "\u2588".repeat(filled) + "\u2591".repeat(empty);
|
|
4036
4081
|
}
|
|
4037
4082
|
function getComplianceColor(compliance) {
|
|
4038
|
-
if (compliance >= 90) return
|
|
4039
|
-
if (compliance >= 70) return
|
|
4040
|
-
if (compliance >= 50) return
|
|
4041
|
-
return
|
|
4083
|
+
if (compliance >= 90) return chalk.green;
|
|
4084
|
+
if (compliance >= 70) return chalk.yellow;
|
|
4085
|
+
if (compliance >= 50) return chalk.hex("#FFA500");
|
|
4086
|
+
return chalk.red;
|
|
4042
4087
|
}
|
|
4043
4088
|
function getStatusColor(status) {
|
|
4044
4089
|
switch (status) {
|
|
4045
4090
|
case "active":
|
|
4046
|
-
return
|
|
4091
|
+
return chalk.green;
|
|
4047
4092
|
case "draft":
|
|
4048
|
-
return
|
|
4093
|
+
return chalk.yellow;
|
|
4049
4094
|
case "deprecated":
|
|
4050
|
-
return
|
|
4095
|
+
return chalk.gray;
|
|
4051
4096
|
case "superseded":
|
|
4052
|
-
return
|
|
4097
|
+
return chalk.blue;
|
|
4053
4098
|
default:
|
|
4054
|
-
return
|
|
4099
|
+
return chalk.white;
|
|
4055
4100
|
}
|
|
4056
4101
|
}
|
|
4057
4102
|
function truncate(str, length) {
|
|
@@ -4125,6 +4170,7 @@ function formatProgressBar(percentage) {
|
|
|
4125
4170
|
import { join as join4 } from "path";
|
|
4126
4171
|
var ReportStorage = class {
|
|
4127
4172
|
storageDir;
|
|
4173
|
+
logger = getLogger({ module: "reporting.storage" });
|
|
4128
4174
|
constructor(basePath) {
|
|
4129
4175
|
this.storageDir = join4(getSpecBridgeDir(basePath), "reports", "history");
|
|
4130
4176
|
}
|
|
@@ -4183,7 +4229,7 @@ var ReportStorage = class {
|
|
|
4183
4229
|
const timestamp = file.replace("report-", "").replace(".json", "");
|
|
4184
4230
|
return { timestamp, report };
|
|
4185
4231
|
} catch (error) {
|
|
4186
|
-
|
|
4232
|
+
this.logger.warn({ file, error }, "Failed to load report file");
|
|
4187
4233
|
return null;
|
|
4188
4234
|
}
|
|
4189
4235
|
});
|
|
@@ -4227,7 +4273,7 @@ var ReportStorage = class {
|
|
|
4227
4273
|
const fs = await import("fs/promises");
|
|
4228
4274
|
await fs.unlink(filepath);
|
|
4229
4275
|
} catch (error) {
|
|
4230
|
-
|
|
4276
|
+
this.logger.warn({ file, error }, "Failed to delete old report file");
|
|
4231
4277
|
}
|
|
4232
4278
|
}
|
|
4233
4279
|
return filesToDelete.length;
|
|
@@ -5064,6 +5110,7 @@ var DashboardServer = class {
|
|
|
5064
5110
|
CACHE_TTL = 6e4;
|
|
5065
5111
|
// 1 minute
|
|
5066
5112
|
refreshInterval = null;
|
|
5113
|
+
logger = getLogger({ module: "dashboard.server" });
|
|
5067
5114
|
constructor(options) {
|
|
5068
5115
|
this.cwd = options.cwd;
|
|
5069
5116
|
this.config = options.config;
|
|
@@ -5080,7 +5127,11 @@ var DashboardServer = class {
|
|
|
5080
5127
|
await this.registry.load();
|
|
5081
5128
|
await this.refreshCache();
|
|
5082
5129
|
this.refreshInterval = setInterval(
|
|
5083
|
-
() =>
|
|
5130
|
+
() => {
|
|
5131
|
+
void this.refreshCache().catch((error) => {
|
|
5132
|
+
this.logger.error({ error }, "Background cache refresh failed");
|
|
5133
|
+
});
|
|
5134
|
+
},
|
|
5084
5135
|
this.CACHE_TTL
|
|
5085
5136
|
);
|
|
5086
5137
|
}
|
|
@@ -5103,7 +5154,7 @@ var DashboardServer = class {
|
|
|
5103
5154
|
this.cacheTimestamp = Date.now();
|
|
5104
5155
|
await this.reportStorage.save(report);
|
|
5105
5156
|
} catch (error) {
|
|
5106
|
-
|
|
5157
|
+
this.logger.error({ error }, "Cache refresh failed");
|
|
5107
5158
|
if (!this.cachedReport) {
|
|
5108
5159
|
try {
|
|
5109
5160
|
const stored = await this.reportStorage.loadLatest();
|
|
@@ -5111,7 +5162,7 @@ var DashboardServer = class {
|
|
|
5111
5162
|
this.cachedReport = stored.report;
|
|
5112
5163
|
}
|
|
5113
5164
|
} catch (fallbackError) {
|
|
5114
|
-
|
|
5165
|
+
this.logger.error({ error: fallbackError }, "Failed to load fallback report");
|
|
5115
5166
|
}
|
|
5116
5167
|
}
|
|
5117
5168
|
}
|
|
@@ -5374,7 +5425,7 @@ import { TextDocument } from "vscode-languageserver-textdocument";
|
|
|
5374
5425
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5375
5426
|
import path3 from "path";
|
|
5376
5427
|
import { Project as Project3 } from "ts-morph";
|
|
5377
|
-
import
|
|
5428
|
+
import chalk2 from "chalk";
|
|
5378
5429
|
function severityToDiagnostic(severity) {
|
|
5379
5430
|
switch (severity) {
|
|
5380
5431
|
case "critical":
|
|
@@ -5485,7 +5536,7 @@ var SpecBridgeLspServer = class {
|
|
|
5485
5536
|
if (!await pathExists(getSpecBridgeDir(this.cwd))) {
|
|
5486
5537
|
const err = new NotInitializedError();
|
|
5487
5538
|
this.initError = err.message;
|
|
5488
|
-
if (this.options.verbose) this.connection.console.error(
|
|
5539
|
+
if (this.options.verbose) this.connection.console.error(chalk2.red(this.initError));
|
|
5489
5540
|
return;
|
|
5490
5541
|
}
|
|
5491
5542
|
try {
|
|
@@ -5494,7 +5545,7 @@ var SpecBridgeLspServer = class {
|
|
|
5494
5545
|
await getPluginLoader().loadPlugins(this.cwd);
|
|
5495
5546
|
} catch (error) {
|
|
5496
5547
|
const msg = error instanceof Error ? error.message : String(error);
|
|
5497
|
-
if (this.options.verbose) this.connection.console.error(
|
|
5548
|
+
if (this.options.verbose) this.connection.console.error(chalk2.red(`Plugin load failed: ${msg}`));
|
|
5498
5549
|
}
|
|
5499
5550
|
this.registry = createRegistry({ basePath: this.cwd });
|
|
5500
5551
|
await this.registry.load();
|
|
@@ -5507,11 +5558,11 @@ var SpecBridgeLspServer = class {
|
|
|
5507
5558
|
}
|
|
5508
5559
|
}
|
|
5509
5560
|
if (this.options.verbose) {
|
|
5510
|
-
this.connection.console.log(
|
|
5561
|
+
this.connection.console.log(chalk2.dim(`Loaded ${this.decisions.length} active decision(s)`));
|
|
5511
5562
|
}
|
|
5512
5563
|
} catch (error) {
|
|
5513
5564
|
this.initError = error instanceof Error ? error.message : String(error);
|
|
5514
|
-
if (this.options.verbose) this.connection.console.error(
|
|
5565
|
+
if (this.options.verbose) this.connection.console.error(chalk2.red(this.initError));
|
|
5515
5566
|
}
|
|
5516
5567
|
}
|
|
5517
5568
|
async verifyTextDocument(doc) {
|
|
@@ -5579,6 +5630,9 @@ async function startLspServer(options) {
|
|
|
5579
5630
|
// src/integrations/github.ts
|
|
5580
5631
|
function toMdTable(rows) {
|
|
5581
5632
|
const header = rows[0];
|
|
5633
|
+
if (!header) {
|
|
5634
|
+
return "";
|
|
5635
|
+
}
|
|
5582
5636
|
const body = rows.slice(1);
|
|
5583
5637
|
const sep = header.map(() => "---");
|
|
5584
5638
|
const lines = [
|
|
@@ -5722,6 +5776,7 @@ export {
|
|
|
5722
5776
|
getConfigPath,
|
|
5723
5777
|
getDecisionsDir,
|
|
5724
5778
|
getInferredDir,
|
|
5779
|
+
getLogger,
|
|
5725
5780
|
getReportsDir,
|
|
5726
5781
|
getSpecBridgeDir,
|
|
5727
5782
|
getTransitiveDependencies,
|
|
@@ -5734,6 +5789,7 @@ export {
|
|
|
5734
5789
|
loadConfig,
|
|
5735
5790
|
loadDecisionFile,
|
|
5736
5791
|
loadDecisionsFromDir,
|
|
5792
|
+
logger,
|
|
5737
5793
|
matchesAnyPattern,
|
|
5738
5794
|
matchesPattern,
|
|
5739
5795
|
mergeWithDefaults,
|