@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 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: "error-hierarchy"
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: "custom-errors-only"
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
- const timeoutPromise = new Promise(
2132
- (resolve) => setTimeout(() => resolve("timeout"), timeout)
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
- const result = await Promise.race([verificationPromise, timeoutPromise]);
2150
- if (result === "timeout") {
2151
- return {
2152
- success: false,
2153
- violations: allViolations,
2154
- checked,
2155
- passed,
2156
- failed,
2157
- skipped: filesToVerify.length - checked,
2158
- duration: timeout
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/specbridge/specbridge)*");
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
  }