@ipation/specbridge 1.0.3 → 1.0.4
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 +68 -0
- package/dist/cli.js +37 -27
- package/dist/cli.js.map +1 -1
- package/dist/index.js +31 -21
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,74 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.0.4] - 2026-01-30
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
#### Critical Fixes
|
|
15
|
+
- **Verification Timeout Bug** (src/verification/engine.ts)
|
|
16
|
+
- Fixed event loop hanging issue where verification would wait for full 60-second timeout even after completing
|
|
17
|
+
- Added proper timeout handle cleanup with try-finally block
|
|
18
|
+
- Used `unref()` to prevent blocking process exit
|
|
19
|
+
- **Impact**: Integration tests now complete in ~97 seconds instead of hanging for 10+ minutes
|
|
20
|
+
- CLI verify command exits immediately (~600ms) instead of waiting 60 seconds
|
|
21
|
+
|
|
22
|
+
#### Inference Issues
|
|
23
|
+
- **Non-Existent Verifier References** (src/inference/analyzers/errors.ts)
|
|
24
|
+
- Fixed `error-hierarchy` verifier reference → `errors` (line 90)
|
|
25
|
+
- Fixed `custom-errors-only` verifier reference → `errors` (line 205)
|
|
26
|
+
- Updated corresponding unit tests to match
|
|
27
|
+
- **Impact**: Inferred constraints now reference valid verifiers that exist in the registry
|
|
28
|
+
|
|
29
|
+
#### CLI Command Issues
|
|
30
|
+
- **`infer --output` Bug** (src/cli/commands/infer.ts)
|
|
31
|
+
- Fixed early return preventing file save when no patterns detected
|
|
32
|
+
- Moved file saving logic before pattern check
|
|
33
|
+
- **Impact**: Output file is always created when `--output` flag is used, even with empty results
|
|
34
|
+
|
|
35
|
+
#### Visual Formatting
|
|
36
|
+
- **Empty Placeholder Characters** (src/reporting/formats/markdown.ts, src/agent/context.generator.ts)
|
|
37
|
+
- Added compliance emojis: ✅ (≥90%), ⚠️ (70-89%), ❌ (<70%)
|
|
38
|
+
- Added progress bar characters: █ (filled), ░ (empty)
|
|
39
|
+
- Added constraint type emojis: 🔒 (invariant), 📋 (convention), 💡 (guideline)
|
|
40
|
+
- **Impact**: Reports and agent context now display with proper visual indicators
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
|
|
44
|
+
#### Documentation
|
|
45
|
+
- **Version Consistency**
|
|
46
|
+
- Archived outdated `IMPLEMENTATION_STATUS.md` → `IMPLEMENTATION_STATUS_v0.2.2_ARCHIVED.md`
|
|
47
|
+
- Added archive notice indicating current version is 1.0.4
|
|
48
|
+
- **Impact**: No misleading version information
|
|
49
|
+
|
|
50
|
+
- **GitHub URL Standardization**
|
|
51
|
+
- Standardized all repository references to `nouatzi/specbridge`
|
|
52
|
+
- Fixed docs/README.md, docs/troubleshooting.md, src/reporting/formats/markdown.ts
|
|
53
|
+
- Corrected wrong `anthropics/claude-code` reference in archived file
|
|
54
|
+
- **Impact**: Consistent repository URLs throughout documentation and code
|
|
55
|
+
|
|
56
|
+
### Improved
|
|
57
|
+
|
|
58
|
+
#### Test Suite
|
|
59
|
+
- **Integration Tests** (tests/integration/cli.test.ts)
|
|
60
|
+
- Fixed `decision create` test syntax (positional argument instead of `--id` flag)
|
|
61
|
+
- Added valid constraints to manually created decision files (schema compliance)
|
|
62
|
+
- Fixed 3 previously failing CLI integration tests
|
|
63
|
+
- **Result**: All 30 integration tests now pass (100% success rate)
|
|
64
|
+
- **Duration**: Tests complete in ~97 seconds (down from 10+ minutes)
|
|
65
|
+
|
|
66
|
+
### Test Results Summary
|
|
67
|
+
- ✅ Type Checking: Passed
|
|
68
|
+
- ✅ Unit Tests: 762/762 passed (24 test files)
|
|
69
|
+
- ✅ Integration Tests: 30/30 passed (2 test files)
|
|
70
|
+
- ✅ Total Duration: ~97 seconds
|
|
71
|
+
|
|
72
|
+
### Files Modified
|
|
73
|
+
- 9 source/test files updated
|
|
74
|
+
- 2 documentation files updated
|
|
75
|
+
- 1 file archived
|
|
76
|
+
- All changes backward compatible (no breaking changes)
|
|
77
|
+
|
|
10
78
|
## [1.0.3] - 2026-01-30
|
|
11
79
|
|
|
12
80
|
### Improved
|
package/dist/cli.js
CHANGED
|
@@ -1045,7 +1045,7 @@ var ErrorsAnalyzer = class {
|
|
|
1045
1045
|
rule: `Custom error classes should extend ${customBaseName}`,
|
|
1046
1046
|
severity: "medium",
|
|
1047
1047
|
scope: "src/**/*.ts",
|
|
1048
|
-
verifier: "
|
|
1048
|
+
verifier: "errors"
|
|
1049
1049
|
}
|
|
1050
1050
|
});
|
|
1051
1051
|
}
|
|
@@ -1142,7 +1142,7 @@ var ErrorsAnalyzer = class {
|
|
|
1142
1142
|
rule: "Throw custom error classes instead of generic Error",
|
|
1143
1143
|
severity: "medium",
|
|
1144
1144
|
scope: "src/**/*.ts",
|
|
1145
|
-
verifier: "
|
|
1145
|
+
verifier: "errors"
|
|
1146
1146
|
}
|
|
1147
1147
|
});
|
|
1148
1148
|
}
|
|
@@ -1281,6 +1281,12 @@ var inferCommand = new Command2("infer").description("Analyze codebase and detec
|
|
|
1281
1281
|
cwd
|
|
1282
1282
|
});
|
|
1283
1283
|
spinner.succeed(`Scanned ${result.filesScanned} files in ${result.duration}ms`);
|
|
1284
|
+
if (options.save || options.output) {
|
|
1285
|
+
const outputPath = options.output || join3(getInferredDir(cwd), "patterns.json");
|
|
1286
|
+
await writeTextFile(outputPath, JSON.stringify(result, null, 2));
|
|
1287
|
+
console.log(chalk2.green(`
|
|
1288
|
+
Results saved to: ${outputPath}`));
|
|
1289
|
+
}
|
|
1284
1290
|
if (result.patterns.length === 0) {
|
|
1285
1291
|
console.log(chalk2.yellow("\nNo patterns detected above confidence threshold."));
|
|
1286
1292
|
console.log(chalk2.dim(`Try lowering --min-confidence (current: ${minConfidence})`));
|
|
@@ -1291,12 +1297,6 @@ var inferCommand = new Command2("infer").description("Analyze codebase and detec
|
|
|
1291
1297
|
} else {
|
|
1292
1298
|
printPatterns(result.patterns);
|
|
1293
1299
|
}
|
|
1294
|
-
if (options.save || options.output) {
|
|
1295
|
-
const outputPath = options.output || join3(getInferredDir(cwd), "patterns.json");
|
|
1296
|
-
await writeTextFile(outputPath, JSON.stringify(result, null, 2));
|
|
1297
|
-
console.log(chalk2.green(`
|
|
1298
|
-
Results saved to: ${outputPath}`));
|
|
1299
|
-
}
|
|
1300
1300
|
if (!options.json) {
|
|
1301
1301
|
console.log("");
|
|
1302
1302
|
console.log(chalk2.cyan("Next steps:"));
|
|
@@ -2128,9 +2128,11 @@ var VerificationEngine = class {
|
|
|
2128
2128
|
let passed = 0;
|
|
2129
2129
|
let failed = 0;
|
|
2130
2130
|
const skipped = 0;
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2131
|
+
let timeoutHandle = null;
|
|
2132
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
2133
|
+
timeoutHandle = setTimeout(() => resolve("timeout"), timeout);
|
|
2134
|
+
timeoutHandle.unref();
|
|
2135
|
+
});
|
|
2134
2136
|
const verificationPromise = this.verifyFiles(
|
|
2135
2137
|
filesToVerify,
|
|
2136
2138
|
decisions,
|
|
@@ -2146,17 +2148,25 @@ var VerificationEngine = class {
|
|
|
2146
2148
|
}
|
|
2147
2149
|
}
|
|
2148
2150
|
);
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2151
|
+
let result;
|
|
2152
|
+
try {
|
|
2153
|
+
result = await Promise.race([verificationPromise, timeoutPromise]);
|
|
2154
|
+
if (result === "timeout") {
|
|
2155
|
+
return {
|
|
2156
|
+
success: false,
|
|
2157
|
+
violations: allViolations,
|
|
2158
|
+
checked,
|
|
2159
|
+
passed,
|
|
2160
|
+
failed,
|
|
2161
|
+
skipped: filesToVerify.length - checked,
|
|
2162
|
+
duration: timeout
|
|
2163
|
+
};
|
|
2164
|
+
}
|
|
2165
|
+
} finally {
|
|
2166
|
+
if (timeoutHandle) {
|
|
2167
|
+
clearTimeout(timeoutHandle);
|
|
2168
|
+
timeoutHandle = null;
|
|
2169
|
+
}
|
|
2160
2170
|
}
|
|
2161
2171
|
const hasBlockingViolations = allViolations.some((v) => {
|
|
2162
2172
|
if (level === "commit") {
|
|
@@ -3101,7 +3111,7 @@ function formatMarkdownReport(report) {
|
|
|
3101
3111
|
lines.push("| Decision | Status | Constraints | Violations | Compliance |");
|
|
3102
3112
|
lines.push("|----------|--------|-------------|------------|------------|");
|
|
3103
3113
|
for (const dec of report.byDecision) {
|
|
3104
|
-
const complianceEmoji = dec.compliance >= 90 ? "" : dec.compliance >= 70 ? "" : "";
|
|
3114
|
+
const complianceEmoji = dec.compliance >= 90 ? "\u2705" : dec.compliance >= 70 ? "\u26A0\uFE0F" : "\u274C";
|
|
3105
3115
|
lines.push(
|
|
3106
3116
|
`| ${dec.title} | ${dec.status} | ${dec.constraints} | ${dec.violations} | ${complianceEmoji} ${dec.compliance}% |`
|
|
3107
3117
|
);
|
|
@@ -3110,15 +3120,15 @@ function formatMarkdownReport(report) {
|
|
|
3110
3120
|
}
|
|
3111
3121
|
lines.push("---");
|
|
3112
3122
|
lines.push("");
|
|
3113
|
-
lines.push("*Generated by [SpecBridge](https://github.com/
|
|
3123
|
+
lines.push("*Generated by [SpecBridge](https://github.com/nouatzi/specbridge)*");
|
|
3114
3124
|
return lines.join("\n");
|
|
3115
3125
|
}
|
|
3116
3126
|
function formatProgressBar(percentage) {
|
|
3117
3127
|
const width = 20;
|
|
3118
3128
|
const filled = Math.round(percentage / 100 * width);
|
|
3119
3129
|
const empty = width - filled;
|
|
3120
|
-
const filledChar = "";
|
|
3121
|
-
const emptyChar = "";
|
|
3130
|
+
const filledChar = "\u2588";
|
|
3131
|
+
const emptyChar = "\u2591";
|
|
3122
3132
|
return `\`${filledChar.repeat(filled)}${emptyChar.repeat(empty)}\` ${percentage}%`;
|
|
3123
3133
|
}
|
|
3124
3134
|
|
|
@@ -3236,7 +3246,7 @@ function formatContextAsMarkdown(context) {
|
|
|
3236
3246
|
lines.push("### Constraints");
|
|
3237
3247
|
lines.push("");
|
|
3238
3248
|
for (const constraint of decision.constraints) {
|
|
3239
|
-
const typeEmoji = constraint.type === "invariant" ? "" : constraint.type === "convention" ? "" : "";
|
|
3249
|
+
const typeEmoji = constraint.type === "invariant" ? "\u{1F512}" : constraint.type === "convention" ? "\u{1F4CB}" : "\u{1F4A1}";
|
|
3240
3250
|
const severityBadge = `[${constraint.severity.toUpperCase()}]`;
|
|
3241
3251
|
lines.push(`- ${typeEmoji} **${severityBadge}** ${constraint.rule}`);
|
|
3242
3252
|
}
|