qa360 2.2.6 → 2.2.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.

Potentially problematic release.


This version of qa360 might be problematic. Click here for more details.

package/CHANGELOG.md CHANGED
@@ -5,6 +5,34 @@ All notable changes to QA360 will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ---
9
+
10
+ ## ⚠️ BROKEN VERSIONS - DO NOT USE
11
+
12
+ | Version | Status | Issue | Fixed In |
13
+ |---------|--------|-------|----------|
14
+ | **2.2.4** | 🔴 BROKEN | Published without CI check (CI was failing) | 2.2.6 |
15
+ | **2.2.5** | 🔴 BROKEN | Published without bundle script - missing `cli/dist/core/` | 2.2.6 |
16
+
17
+ **Use version 2.2.6 or later instead.**
18
+
19
+ ---
20
+
21
+ ## [2.2.6] - 2025-01-18
22
+
23
+ ### Fixed
24
+ - **Critical bundle fix**: Re-ran bundle script correctly before publication
25
+ - `cli/dist/core/` now contains the bundled core engine
26
+ - Imports correctly use `../core/index.js` instead of `qa360-core`
27
+ - Package installation now works correctly
28
+ - **Recovery**: This version fixes the broken 2.2.4 and 2.2.5 releases
29
+
30
+ ### Added
31
+ - **npm Publication Workflow section** in README with mandatory checklist
32
+ - Documented fatal mistakes from 2.2.4 and 2.2.5 to prevent recurrence
33
+
34
+ ---
35
+
8
36
  ## Versioning Convention
9
37
 
10
38
  QA360 uses **Node.js-style versioning** (Major.Minor.Patch).
package/README.md CHANGED
@@ -215,6 +215,85 @@ QA360 Core is developed in structured phases:
215
215
  - **Phase 8**: ✅ TUI & Dashboard (COMPLETE)
216
216
  - **Phase 9**: ⏳ Parallel CI → consolidated proof
217
217
 
218
+ ## 🚢 npm Publication Workflow (CRITICAL)
219
+
220
+ > **⚠️ WARNING: Publishing broken packages damages user trust permanently.**
221
+
222
+ ### Mandatory Pre-Publication Checklist
223
+
224
+ **NEVER skip these steps - versions 2.2.4 and 2.2.5 were broken due to skipping these:**
225
+
226
+ 1. ✅ **CI MUST be green** on both `develop` AND `main`
227
+ 2. ✅ **Run bundle script**: `cd cli && bash scripts/bundle-for-npm.sh`
228
+ 3. ✅ **Test with npm pack**: `npm pack && tar -tzf qa360-*.tgz | grep "cli/dist/core/index.js"`
229
+ 4. ✅ **Test installation**: `cd /tmp && npm install -g ./qa360-*.tgz && qa360 --version`
230
+ 5. ✅ **Get EXPLICIT authorization** from maintainer before publishing
231
+ 6. ✅ **Publish from MAIN branch only** - NEVER from `develop`
232
+
233
+ ### The Fatal Mistakes (DO NOT REPEAT)
234
+
235
+ | Version | Mistake | Result |
236
+ |---------|---------|--------|
237
+ | **2.2.4** | Published without CI check | CI was failing - broken package |
238
+ | **2.2.5** | Published without bundle script | Missing `cli/dist/core/` - completely broken |
239
+ | **2.2.6** | Followed full checklist | ✅ Working package |
240
+
241
+ ### Correct Publication Workflow
242
+
243
+ ```bash
244
+ # 1. Verify CI is green
245
+ gh run list --branch develop --limit 1
246
+ gh run list --branch main --limit 1
247
+
248
+ # 2. Merge develop to main
249
+ git checkout main
250
+ git merge develop --no-ff
251
+ git push origin main
252
+
253
+ # 3. Wait for CI to pass on main
254
+ gh run watch --branch main
255
+
256
+ # 4. CREATE THE BUNDLE (THIS IS CRITICAL)
257
+ cd cli
258
+ bash scripts/bundle-for-npm.sh
259
+ cd ..
260
+
261
+ # 5. Verify bundle was created
262
+ ls -la cli/dist/core/index.js # Must exist
263
+ grep "from '../core/index.js'" cli/dist/commands/ai.js # Must show this, NOT qa360-core
264
+
265
+ # 6. Test the package locally
266
+ npm pack
267
+ tar -tzf qa360-*.tgz | grep "cli/dist/core/index.js" # Must exist
268
+ cd /tmp && npm install -g /path/to/qa360-*.tgz && qa360 --version
269
+
270
+ # 7. ONLY AFTER ALL TESTS PASS: Get authorization, then publish
271
+ npm version patch # or minor/major
272
+ npm publish --access public
273
+ git push origin main --tags
274
+
275
+ # 8. ALWAYS return to develop
276
+ git checkout develop
277
+ ```
278
+
279
+ ### Why the Bundle Script Is Critical
280
+
281
+ The bundle script (`cli/scripts/bundle-for-npm.sh`) does:
282
+ 1. Copies `core/src/*` into `cli/src/core/`
283
+ 2. Changes imports from `'qa360-core'` to `'../core/index.js'`
284
+ 3. Builds TypeScript → `cli/dist/`
285
+ 4. **Result**: `cli/dist/core/` contains the bundled core engine
286
+
287
+ **Without this step**: The CLI imports `'qa360-core'` which doesn't exist in the npm package → **COMPLETELY BROKEN**
288
+
289
+ ### Recovery from Broken Publication
290
+
291
+ If a broken version is published:
292
+ 1. **Fix the issue** on `develop`
293
+ 2. **Follow the FULL checklist** above
294
+ 3. **Publish a patch version** (e.g., 2.2.5 → 2.2.6)
295
+ 4. **Add a warning** in CHANGELOG about broken versions
296
+
218
297
  ## 🛠️ Technology Stack
219
298
 
220
299
  - **Runtime**: Node.js 18+ with TypeScript 5+
@@ -32,16 +32,28 @@ export class OllamaProvider {
32
32
  }
33
33
  async isAvailable() {
34
34
  try {
35
- // Use timeout with AbortSignal - wrap for compatibility
35
+ // Use a longer timeout (15 seconds) to accommodate slower systems
36
+ // Ollama can take time to respond, especially on first run or with many models
36
37
  const controller = new AbortController();
37
- const timeoutId = setTimeout(() => controller.abort(), 5000);
38
+ const timeoutId = setTimeout(() => controller.abort(), 15000);
38
39
  const response = await fetch(`${this.baseUrl}/api/tags`, {
39
40
  signal: controller.signal,
40
41
  });
41
42
  clearTimeout(timeoutId);
42
43
  return response.ok;
43
44
  }
44
- catch {
45
+ catch (error) {
46
+ // Log the error for debugging (will be visible in verbose mode)
47
+ if (error instanceof Error) {
48
+ if (error.name === 'AbortError') {
49
+ // Timeout - Ollama is slow to respond
50
+ console.debug(`[Ollama] Connection to ${this.baseUrl} timed out after 15s`);
51
+ }
52
+ else {
53
+ // Other error (ECONNREFUSED, ENOTFOUND, etc.)
54
+ console.debug(`[Ollama] Connection error: ${error.message}`);
55
+ }
56
+ }
45
57
  return false;
46
58
  }
47
59
  }
@@ -47,6 +47,7 @@ export declare class PackMigrator {
47
47
  private findSecretInEnv;
48
48
  /**
49
49
  * Sanitize gate name for v2 format
50
+ * Handles both strings and objects (from YAML parsing edge cases)
50
51
  */
51
52
  private sanitizeGateName;
52
53
  /**
@@ -424,8 +424,33 @@ export class PackMigrator {
424
424
  }
425
425
  /**
426
426
  * Sanitize gate name for v2 format
427
+ * Handles both strings and objects (from YAML parsing edge cases)
427
428
  */
428
429
  sanitizeGateName(gate) {
430
+ // Handle edge case where gate might be an object from YAML parsing
431
+ if (typeof gate !== 'string') {
432
+ // If gate is an object, try to extract a name
433
+ if (gate && typeof gate === 'object') {
434
+ // Try common property names
435
+ const possibleName = gate.name || gate.id || gate.gate;
436
+ if (typeof possibleName === 'string') {
437
+ gate = possibleName;
438
+ }
439
+ else {
440
+ // Fallback: stringify the object keys
441
+ const keys = Object.keys(gate);
442
+ if (keys.length === 1) {
443
+ gate = keys[0];
444
+ }
445
+ else {
446
+ throw new Error(`Invalid gate format: expected string, got object with keys: ${keys.join(', ')}`);
447
+ }
448
+ }
449
+ }
450
+ else {
451
+ throw new Error(`Invalid gate format: expected string, got ${typeof gate}`);
452
+ }
453
+ }
429
454
  // Map v1 gate names to v2 conventions
430
455
  const nameMap = {
431
456
  'api_smoke': 'smoke',
package/cli/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qa360",
3
- "version": "2.2.4",
3
+ "version": "2.2.9",
4
4
  "description": "QA360 Proof CLI - Quality as Cryptographic Proof",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qa360",
3
- "version": "2.2.6",
3
+ "version": "2.2.9",
4
4
  "description": "Transform software testing into verifiable, signed, and traceable proofs",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@9.12.2",
@@ -1,101 +0,0 @@
1
- /**
2
- * Coverage Analyzer
3
- *
4
- * Analyzes coverage data to provide insights, trends, and recommendations.
5
- */
6
- import type { FileCoverage, CoverageMetrics, CoverageResult, CoverageTrend, CoverageGap, CoverageComparison, CoverageThreshold, CoverageType, CoverageReport } from './types.js';
7
- /**
8
- * Historical coverage data point
9
- */
10
- interface HistoricalCoverage {
11
- runId: string;
12
- timestamp: number;
13
- metrics: CoverageMetrics;
14
- }
15
- /**
16
- * Coverage Analyzer class
17
- */
18
- export declare class CoverageAnalyzer {
19
- private history;
20
- /**
21
- * Analyze coverage and generate insights
22
- */
23
- analyze(result: CoverageResult, threshold?: CoverageThreshold): CoverageReport;
24
- /**
25
- * Check if coverage meets thresholds
26
- */
27
- checkThresholds(metrics: CoverageMetrics, threshold?: CoverageThreshold): boolean;
28
- /**
29
- * Check if a single file meets thresholds
30
- */
31
- checkFileThresholds(file: FileCoverage, threshold?: CoverageThreshold): boolean;
32
- /**
33
- * Find coverage gaps
34
- */
35
- findGaps(files: Record<string, FileCoverage>, threshold?: CoverageThreshold): CoverageGap[];
36
- /**
37
- * Calculate priority for covering a file
38
- */
39
- private calculatePriority;
40
- /**
41
- * Estimate effort to cover a file
42
- */
43
- private estimateEffort;
44
- /**
45
- * Generate test suggestions for a file
46
- */
47
- private generateSuggestions;
48
- /**
49
- * Group consecutive numbers into ranges
50
- */
51
- private groupConsecutiveNumbers;
52
- /**
53
- * Get top and bottom files by coverage
54
- */
55
- getTopFiles(files: Record<string, FileCoverage>, limit?: number): Array<{
56
- path: string;
57
- coverage: number;
58
- type: 'best' | 'worst';
59
- }>;
60
- /**
61
- * Compare two coverage results
62
- */
63
- compare(baseResult: CoverageResult, compareResult: CoverageResult): CoverageComparison;
64
- /**
65
- * Add historical coverage data
66
- */
67
- addHistory(key: string, data: HistoricalCoverage): void;
68
- /**
69
- * Get coverage trends
70
- */
71
- getTrends(key: string, type?: CoverageType, limit?: number): CoverageTrend[];
72
- /**
73
- * Calculate trend direction
74
- */
75
- getTrendDirection(trends: CoverageTrend[]): 'improving' | 'stable' | 'declining';
76
- /**
77
- * Predict future coverage based on trends
78
- */
79
- predictCoverage(key: string, type: CoverageType | undefined, targetCoverage: number): {
80
- predictedReach: number | null;
81
- projectedCoverage: number;
82
- confidence: 'high' | 'medium' | 'low';
83
- };
84
- /**
85
- * Generate coverage summary text
86
- */
87
- generateSummary(metrics: CoverageMetrics): string;
88
- /**
89
- * Format coverage percentage with color indicator
90
- */
91
- formatCoverage(percentage: number, threshold?: number): string;
92
- /**
93
- * Clear history
94
- */
95
- clearHistory(key?: string): void;
96
- }
97
- /**
98
- * Create a coverage analyzer
99
- */
100
- export declare function createCoverageAnalyzer(): CoverageAnalyzer;
101
- export {};