@paths.design/caws-cli 8.0.0 → 8.1.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/dist/budget-derivation.d.ts +74 -0
- package/dist/budget-derivation.d.ts.map +1 -0
- package/dist/cicd-optimizer.d.ts +142 -0
- package/dist/cicd-optimizer.d.ts.map +1 -0
- package/dist/commands/archive.d.ts +51 -0
- package/dist/commands/archive.d.ts.map +1 -0
- package/dist/commands/archive.js +114 -6
- package/dist/commands/burnup.d.ts +6 -0
- package/dist/commands/burnup.d.ts.map +1 -0
- package/dist/commands/burnup.js +109 -10
- package/dist/commands/diagnose.d.ts +52 -0
- package/dist/commands/diagnose.d.ts.map +1 -0
- package/dist/commands/diagnose.js +1 -1
- package/dist/commands/evaluate.d.ts +8 -0
- package/dist/commands/evaluate.d.ts.map +1 -0
- package/dist/commands/init.d.ts +5 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/iterate.d.ts +8 -0
- package/dist/commands/iterate.d.ts.map +1 -0
- package/dist/commands/mode.d.ts +24 -0
- package/dist/commands/mode.d.ts.map +1 -0
- package/dist/commands/mode.js +24 -14
- package/dist/commands/plan.d.ts +49 -0
- package/dist/commands/plan.d.ts.map +1 -0
- package/dist/commands/provenance.d.ts +32 -0
- package/dist/commands/provenance.d.ts.map +1 -0
- package/dist/commands/provenance.js +216 -93
- package/dist/commands/quality-gates.d.ts +6 -0
- package/dist/commands/quality-gates.d.ts.map +1 -0
- package/dist/commands/quality-gates.js +82 -3
- package/dist/commands/quality-monitor.d.ts +17 -0
- package/dist/commands/quality-monitor.d.ts.map +1 -0
- package/dist/commands/specs.d.ts +71 -0
- package/dist/commands/specs.d.ts.map +1 -0
- package/dist/commands/specs.js +184 -6
- package/dist/commands/status.d.ts +44 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +134 -10
- package/dist/commands/templates.d.ts +74 -0
- package/dist/commands/templates.d.ts.map +1 -0
- package/dist/commands/templates.js +2 -2
- package/dist/commands/tool.d.ts +13 -0
- package/dist/commands/tool.d.ts.map +1 -0
- package/dist/commands/troubleshoot.d.ts +8 -0
- package/dist/commands/troubleshoot.d.ts.map +1 -0
- package/dist/commands/tutorial.d.ts +55 -0
- package/dist/commands/tutorial.d.ts.map +1 -0
- package/dist/commands/validate.d.ts +15 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/waivers.d.ts +8 -0
- package/dist/commands/waivers.d.ts.map +1 -0
- package/dist/commands/workflow.d.ts +85 -0
- package/dist/commands/workflow.d.ts.map +1 -0
- package/dist/config/index.d.ts +29 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/modes.d.ts +225 -0
- package/dist/config/modes.d.ts.map +1 -0
- package/dist/constants/spec-types.d.ts +41 -0
- package/dist/constants/spec-types.d.ts.map +1 -0
- package/dist/error-handler.d.ts +164 -0
- package/dist/error-handler.d.ts.map +1 -0
- package/dist/error-handler.js +6 -98
- package/dist/generators/jest-config-generator.js +242 -0
- package/dist/generators/jest-config.d.ts +32 -0
- package/dist/generators/jest-config.d.ts.map +1 -0
- package/dist/generators/working-spec.d.ts +13 -0
- package/dist/generators/working-spec.d.ts.map +1 -0
- package/dist/index-new.d.ts +5 -0
- package/dist/index-new.d.ts.map +1 -0
- package/dist/index-new.js +317 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -7
- package/dist/index.js.backup +4711 -0
- package/dist/minimal-cli.d.ts +3 -0
- package/dist/minimal-cli.d.ts.map +1 -0
- package/dist/minimal-cli.js +3 -1
- package/dist/policy/PolicyManager.d.ts +104 -0
- package/dist/policy/PolicyManager.d.ts.map +1 -0
- package/dist/scaffold/claude-hooks.js +316 -0
- package/dist/scaffold/cursor-hooks.d.ts +7 -0
- package/dist/scaffold/cursor-hooks.d.ts.map +1 -0
- package/dist/scaffold/git-hooks.d.ts +38 -0
- package/dist/scaffold/git-hooks.d.ts.map +1 -0
- package/dist/scaffold/index.d.ts +15 -0
- package/dist/scaffold/index.d.ts.map +1 -0
- package/dist/scaffold/index.js +18 -0
- package/dist/spec/SpecFileManager.d.ts +146 -0
- package/dist/spec/SpecFileManager.d.ts.map +1 -0
- package/dist/templates/.claude/README.md +190 -0
- package/dist/templates/.claude/hooks/audit.sh +96 -0
- package/dist/templates/.claude/hooks/block-dangerous.sh +90 -0
- package/dist/templates/.claude/hooks/naming-check.sh +97 -0
- package/dist/templates/.claude/hooks/quality-check.sh +68 -0
- package/dist/templates/.claude/hooks/scan-secrets.sh +85 -0
- package/dist/templates/.claude/hooks/scope-guard.sh +105 -0
- package/dist/templates/.claude/hooks/validate-spec.sh +76 -0
- package/dist/templates/.claude/settings.json +95 -0
- package/dist/test-analysis.d.ts +182 -0
- package/dist/test-analysis.d.ts.map +1 -0
- package/dist/test-analysis.js +203 -10
- package/dist/tool-interface.d.ts +236 -0
- package/dist/tool-interface.d.ts.map +1 -0
- package/dist/tool-loader.d.ts +77 -0
- package/dist/tool-loader.d.ts.map +1 -0
- package/dist/tool-validator.d.ts +72 -0
- package/dist/tool-validator.d.ts.map +1 -0
- package/dist/utils/async-utils.d.ts +73 -0
- package/dist/utils/async-utils.d.ts.map +1 -0
- package/dist/utils/command-wrapper.d.ts +66 -0
- package/dist/utils/command-wrapper.d.ts.map +1 -0
- package/dist/utils/detection.d.ts +14 -0
- package/dist/utils/detection.d.ts.map +1 -0
- package/dist/utils/error-categories.js +210 -0
- package/dist/utils/finalization.d.ts +17 -0
- package/dist/utils/finalization.d.ts.map +1 -0
- package/dist/utils/git-lock.d.ts +13 -0
- package/dist/utils/git-lock.d.ts.map +1 -0
- package/dist/utils/gitignore-updater.d.ts +39 -0
- package/dist/utils/gitignore-updater.d.ts.map +1 -0
- package/dist/utils/project-analysis.d.ts +34 -0
- package/dist/utils/project-analysis.d.ts.map +1 -0
- package/dist/utils/promise-utils.d.ts +30 -0
- package/dist/utils/promise-utils.d.ts.map +1 -0
- package/dist/utils/quality-gates-utils.js +402 -0
- package/dist/utils/quality-gates.d.ts +49 -0
- package/dist/utils/quality-gates.d.ts.map +1 -0
- package/dist/utils/spec-resolver.d.ts +80 -0
- package/dist/utils/spec-resolver.d.ts.map +1 -0
- package/dist/utils/typescript-detector.d.ts +63 -0
- package/dist/utils/typescript-detector.d.ts.map +1 -0
- package/dist/utils/typescript-detector.js +36 -90
- package/dist/utils/yaml-validation.d.ts +32 -0
- package/dist/utils/yaml-validation.d.ts.map +1 -0
- package/dist/validation/spec-validation.d.ts +43 -0
- package/dist/validation/spec-validation.d.ts.map +1 -0
- package/dist/validation/spec-validation.js +59 -6
- package/dist/waivers-manager.d.ts +167 -0
- package/dist/waivers-manager.d.ts.map +1 -0
- package/package.json +5 -3
- package/templates/.claude/README.md +190 -0
- package/templates/.claude/hooks/audit.sh +96 -0
- package/templates/.claude/hooks/block-dangerous.sh +90 -0
- package/templates/.claude/hooks/naming-check.sh +97 -0
- package/templates/.claude/hooks/quality-check.sh +68 -0
- package/templates/.claude/hooks/scan-secrets.sh +85 -0
- package/templates/.claude/hooks/scope-guard.sh +105 -0
- package/templates/.claude/hooks/validate-spec.sh +76 -0
- package/templates/.claude/settings.json +95 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mode command handler
|
|
3
|
+
* @param {string} action - Action to perform (current, set, compare, recommend)
|
|
4
|
+
* @param {Object} options - Command options
|
|
5
|
+
*/
|
|
6
|
+
export function modeCommand(action: string, options?: any): Promise<any>;
|
|
7
|
+
import { getCurrentMode } from "../config/modes";
|
|
8
|
+
import { setCurrentMode } from "../config/modes";
|
|
9
|
+
/**
|
|
10
|
+
* Display current mode status
|
|
11
|
+
*/
|
|
12
|
+
export function displayCurrentMode(): void;
|
|
13
|
+
/**
|
|
14
|
+
* Display mode details
|
|
15
|
+
* @param {string} mode - Mode to display
|
|
16
|
+
*/
|
|
17
|
+
export function displayModeDetails(mode: string): void;
|
|
18
|
+
/**
|
|
19
|
+
* Interactive mode selection
|
|
20
|
+
* @returns {Promise<string>} Selected mode
|
|
21
|
+
*/
|
|
22
|
+
export function interactiveModeSelection(): Promise<string>;
|
|
23
|
+
export { getCurrentMode, setCurrentMode };
|
|
24
|
+
//# sourceMappingURL=mode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mode.d.ts","sourceRoot":"","sources":["../../src/commands/mode.js"],"names":[],"mappings":"AAuHA;;;;GAIG;AACH,oCAHW,MAAM,+BAgIhB;;;AAvOD;;GAEG;AACH,2CAOC;AAED;;;GAGG;AACH,yCAFW,MAAM,QA+ChB;AAED;;;GAGG;AACH,4CAFa,OAAO,CAAC,MAAM,CAAC,CAkC3B"}
|
package/dist/commands/mode.js
CHANGED
|
@@ -18,13 +18,32 @@ const {
|
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Display current mode status
|
|
21
|
+
* @param {string} currentMode - The current mode to display
|
|
21
22
|
*/
|
|
22
|
-
function displayCurrentMode() {
|
|
23
|
+
function displayCurrentMode(currentMode) {
|
|
24
|
+
const tier = getTier(currentMode);
|
|
25
|
+
|
|
23
26
|
console.log(chalk.bold.cyan('\n🔧 CAWS Current Mode'));
|
|
24
27
|
console.log(chalk.cyan('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
console.log(chalk.
|
|
29
|
+
console.log(chalk.bold(`Active Mode: ${tier.icon} ${tier.color(currentMode)}`));
|
|
30
|
+
console.log(chalk.gray(`Description: ${tier.description}`));
|
|
31
|
+
console.log('');
|
|
32
|
+
|
|
33
|
+
// Quality requirements
|
|
34
|
+
console.log(chalk.bold('Quality Requirements:'));
|
|
35
|
+
console.log(chalk.gray(` Test Coverage: ≥${tier.qualityRequirements.testCoverage}%`));
|
|
36
|
+
console.log(chalk.gray(` Mutation Score: ≥${tier.qualityRequirements.mutationScore}%`));
|
|
37
|
+
console.log(chalk.gray(` Contracts: ${tier.qualityRequirements.contracts}`));
|
|
38
|
+
console.log('');
|
|
39
|
+
|
|
40
|
+
// Risk tiers supported
|
|
41
|
+
console.log(chalk.bold('Supported Risk Tiers:'));
|
|
42
|
+
tier.riskTiers.forEach((riskTier) => {
|
|
43
|
+
const riskColor =
|
|
44
|
+
riskTier === 'T1' ? chalk.red : riskTier === 'T2' ? chalk.yellow : chalk.green;
|
|
45
|
+
console.log(chalk.gray(` ${riskColor(riskTier)}`));
|
|
46
|
+
});
|
|
28
47
|
console.log('');
|
|
29
48
|
}
|
|
30
49
|
|
|
@@ -128,21 +147,12 @@ async function modeCommand(action, options = {}) {
|
|
|
128
147
|
switch (action) {
|
|
129
148
|
case 'current': {
|
|
130
149
|
const currentMode = await getCurrentMode();
|
|
131
|
-
displayCurrentMode();
|
|
132
|
-
|
|
133
|
-
const tier = getTier(currentMode);
|
|
134
|
-
console.log(chalk.bold(`Current Mode: ${tier.icon} ${tier.color(currentMode)}`));
|
|
135
|
-
console.log(chalk.gray(`Description: ${tier.description}`));
|
|
136
|
-
console.log(
|
|
137
|
-
chalk.gray(
|
|
138
|
-
`Quality: ${tier.qualityRequirements.testCoverage}% coverage, ${tier.qualityRequirements.mutationScore}% mutation`
|
|
139
|
-
)
|
|
140
|
-
);
|
|
150
|
+
displayCurrentMode(currentMode);
|
|
141
151
|
|
|
142
152
|
return outputResult({
|
|
143
153
|
command: 'mode current',
|
|
144
154
|
mode: currentMode,
|
|
145
|
-
tier:
|
|
155
|
+
tier: getTier(currentMode),
|
|
146
156
|
});
|
|
147
157
|
}
|
|
148
158
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plan command handler
|
|
3
|
+
* @param {string} action - Action to perform (generate)
|
|
4
|
+
* @param {Object} options - Command options
|
|
5
|
+
*/
|
|
6
|
+
export function planCommand(action: string, options?: any): Promise<any>;
|
|
7
|
+
/**
|
|
8
|
+
* Generate implementation plan from spec
|
|
9
|
+
* @param {Object} spec - Spec data
|
|
10
|
+
* @returns {Object} Generated plan
|
|
11
|
+
*/
|
|
12
|
+
export function generateImplementationPlan(spec: any): any;
|
|
13
|
+
/**
|
|
14
|
+
* Write plan to file
|
|
15
|
+
* @param {Object} plan - Plan data
|
|
16
|
+
* @param {string} outputPath - Output file path
|
|
17
|
+
* @returns {Promise<void>}
|
|
18
|
+
*/
|
|
19
|
+
export function writePlanToFile(plan: any, outputPath: string): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Generate markdown content from plan
|
|
22
|
+
* @param {Object} plan - Plan data
|
|
23
|
+
* @returns {string} Markdown content
|
|
24
|
+
*/
|
|
25
|
+
export function generatePlanMarkdown(plan: any): string;
|
|
26
|
+
/**
|
|
27
|
+
* Display generated plan
|
|
28
|
+
* @param {Object} plan - Plan data
|
|
29
|
+
*/
|
|
30
|
+
export function displayGeneratedPlan(plan: any): void;
|
|
31
|
+
export namespace PLAN_TEMPLATES {
|
|
32
|
+
namespace feature {
|
|
33
|
+
let sections: string[];
|
|
34
|
+
let defaultTasks: string[];
|
|
35
|
+
}
|
|
36
|
+
namespace fix {
|
|
37
|
+
let sections_1: string[];
|
|
38
|
+
export { sections_1 as sections };
|
|
39
|
+
let defaultTasks_1: string[];
|
|
40
|
+
export { defaultTasks_1 as defaultTasks };
|
|
41
|
+
}
|
|
42
|
+
namespace refactor {
|
|
43
|
+
let sections_2: string[];
|
|
44
|
+
export { sections_2 as sections };
|
|
45
|
+
let defaultTasks_2: string[];
|
|
46
|
+
export { defaultTasks_2 as defaultTasks };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=plan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../src/commands/plan.js"],"names":[],"mappings":"AA6XA;;;;GAIG;AACH,oCAHW,MAAM,+BAuDhB;AA1OD;;;;GAIG;AACH,2DA8CC;AAED;;;;;GAKG;AACH,uDAHW,MAAM,GACJ,OAAO,CAAC,IAAI,CAAC,CAQzB;AAED;;;;GAIG;AACH,iDAFa,MAAM,CAiElB;AAED;;;GAGG;AACH,sDAkCC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provenance command handler
|
|
3
|
+
* @param {string} subcommand - The subcommand to execute
|
|
4
|
+
* @param {Object} options - Command options
|
|
5
|
+
*/
|
|
6
|
+
export function provenanceCommand(subcommand: string, options: any): Promise<any>;
|
|
7
|
+
/**
|
|
8
|
+
* Update provenance with new commit information
|
|
9
|
+
* @param {Object} options - Command options
|
|
10
|
+
*/
|
|
11
|
+
export function updateProvenance(options: any): Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* Show current provenance information
|
|
14
|
+
* @param {Object} options - Command options
|
|
15
|
+
*/
|
|
16
|
+
export function showProvenance(options: any): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Verify provenance chain integrity
|
|
19
|
+
* @param {Object} options - Command options
|
|
20
|
+
*/
|
|
21
|
+
export function verifyProvenance(options: any): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Initialize provenance tracking for the project
|
|
24
|
+
* @param {Object} options - Command options
|
|
25
|
+
*/
|
|
26
|
+
export function initProvenance(options: any): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Install git hooks for automatic provenance updates
|
|
29
|
+
* @param {Object} options - Command options
|
|
30
|
+
*/
|
|
31
|
+
export function installHooks(options: any): Promise<void>;
|
|
32
|
+
//# sourceMappingURL=provenance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provenance.d.ts","sourceRoot":"","sources":["../../src/commands/provenance.js"],"names":[],"mappings":"AAYA;;;;GAIG;AACH,8CAHW,MAAM,8BA+BhB;AAED;;;GAGG;AACH,8DA4EC;AAED;;;GAGG;AACH,4DAyEC;AAED;;;GAGG;AACH,8DA8CC;AA6iBD;;;GAGG;AACH,4DAmEC;AAzcD;;;GAGG;AACH,0DAwEC"}
|
|
@@ -4,12 +4,43 @@
|
|
|
4
4
|
* @author @darianrosebrook
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
/* global fetch */
|
|
8
|
+
|
|
7
9
|
const fs = require('fs-extra');
|
|
8
10
|
const path = require('path');
|
|
9
11
|
const crypto = require('crypto');
|
|
10
12
|
const yaml = require('js-yaml');
|
|
13
|
+
const { execSync } = require('child_process');
|
|
11
14
|
const { commandWrapper } = require('../utils/command-wrapper');
|
|
12
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Get quality gates status from saved report
|
|
18
|
+
* @returns {Object} Quality gates status
|
|
19
|
+
*/
|
|
20
|
+
function getQualityGatesStatus() {
|
|
21
|
+
const reportPath = path.join(process.cwd(), '.caws', 'quality-gates-report.json');
|
|
22
|
+
|
|
23
|
+
if (fs.existsSync(reportPath)) {
|
|
24
|
+
try {
|
|
25
|
+
const report = JSON.parse(fs.readFileSync(reportPath, 'utf8'));
|
|
26
|
+
return {
|
|
27
|
+
status: report.passed ? 'passing' : 'failing',
|
|
28
|
+
last_validated: report.timestamp || new Date().toISOString(),
|
|
29
|
+
violations: report.violations || 0,
|
|
30
|
+
gates: report.gates || {}
|
|
31
|
+
};
|
|
32
|
+
} catch (error) {
|
|
33
|
+
// Fall through to default
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
status: 'not_validated',
|
|
39
|
+
last_validated: null,
|
|
40
|
+
violations: null
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
13
44
|
/**
|
|
14
45
|
* Provenance command handler
|
|
15
46
|
* @param {string} subcommand - The subcommand to execute
|
|
@@ -87,12 +118,7 @@ async function updateProvenance(options) {
|
|
|
87
118
|
mode: spec.mode,
|
|
88
119
|
waiver_ids: spec.waiver_ids || [],
|
|
89
120
|
},
|
|
90
|
-
quality_gates:
|
|
91
|
-
// This would be populated by recent validation results
|
|
92
|
-
// For now, we'll mark as unknown
|
|
93
|
-
status: 'unknown',
|
|
94
|
-
last_validated: new Date().toISOString(),
|
|
95
|
-
},
|
|
121
|
+
quality_gates: getQualityGatesStatus(),
|
|
96
122
|
agent: {
|
|
97
123
|
type: detectAgentType(),
|
|
98
124
|
confidence_level: null, // Would be populated by agent actions
|
|
@@ -407,6 +433,67 @@ function analyzeQualityMetrics(aiEntries) {
|
|
|
407
433
|
/**
|
|
408
434
|
* Analyze checkpoint usage patterns
|
|
409
435
|
*/
|
|
436
|
+
/**
|
|
437
|
+
* Calculate actual revert rate from git history
|
|
438
|
+
* Analyzes commits for revert patterns and calculates the percentage
|
|
439
|
+
* @param {number} maxCommits - Maximum number of commits to analyze
|
|
440
|
+
* @returns {number} Revert rate as a decimal (0.0 - 1.0)
|
|
441
|
+
*/
|
|
442
|
+
function calculateRevertRate(maxCommits = 500) {
|
|
443
|
+
try {
|
|
444
|
+
// Get total commit count (limited)
|
|
445
|
+
const logOutput = execSync(`git log --oneline -n ${maxCommits} 2>/dev/null`, {
|
|
446
|
+
encoding: 'utf8',
|
|
447
|
+
cwd: process.cwd(),
|
|
448
|
+
}).trim();
|
|
449
|
+
|
|
450
|
+
if (!logOutput) {
|
|
451
|
+
return 0;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
const totalCommits = logOutput.split('\n').filter(Boolean).length;
|
|
455
|
+
|
|
456
|
+
// Count revert commits (commits with "revert" in the message)
|
|
457
|
+
const revertOutput = execSync(
|
|
458
|
+
`git log --oneline -n ${maxCommits} --grep="[Rr]evert" 2>/dev/null || true`,
|
|
459
|
+
{
|
|
460
|
+
encoding: 'utf8',
|
|
461
|
+
cwd: process.cwd(),
|
|
462
|
+
}
|
|
463
|
+
).trim();
|
|
464
|
+
|
|
465
|
+
const revertCommits = revertOutput ? revertOutput.split('\n').filter(Boolean).length : 0;
|
|
466
|
+
|
|
467
|
+
// Also check for reset/force-push patterns in reflog if available
|
|
468
|
+
let additionalReverts = 0;
|
|
469
|
+
try {
|
|
470
|
+
const reflogOutput = execSync(`git reflog --oneline -n ${maxCommits} 2>/dev/null || true`, {
|
|
471
|
+
encoding: 'utf8',
|
|
472
|
+
cwd: process.cwd(),
|
|
473
|
+
}).trim();
|
|
474
|
+
|
|
475
|
+
if (reflogOutput) {
|
|
476
|
+
const reflogLines = reflogOutput.split('\n').filter(Boolean);
|
|
477
|
+
additionalReverts = reflogLines.filter(
|
|
478
|
+
(line) => line.includes('reset:') || line.includes('checkout:')
|
|
479
|
+
).length;
|
|
480
|
+
// Weight reflog reverts less since they may not be actual code reverts
|
|
481
|
+
additionalReverts = Math.floor(additionalReverts * 0.1);
|
|
482
|
+
}
|
|
483
|
+
} catch {
|
|
484
|
+
// Reflog not available or failed
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
const totalReverts = revertCommits + additionalReverts;
|
|
488
|
+
const revertRate = totalCommits > 0 ? totalReverts / totalCommits : 0;
|
|
489
|
+
|
|
490
|
+
return Math.min(1.0, revertRate); // Cap at 100%
|
|
491
|
+
} catch {
|
|
492
|
+
// Git not available or not a repo
|
|
493
|
+
return 0;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
410
497
|
function analyzeCheckpointUsage(aiEntries) {
|
|
411
498
|
const entriesWithCheckpoints = aiEntries.filter(
|
|
412
499
|
(entry) => entry.checkpoints?.available && entry.checkpoints.checkpoints?.length > 0
|
|
@@ -416,8 +503,8 @@ function analyzeCheckpointUsage(aiEntries) {
|
|
|
416
503
|
.filter((entry) => entry.checkpoints?.available)
|
|
417
504
|
.reduce((sum, entry) => sum + (entry.checkpoints.checkpoints?.length || 0), 0);
|
|
418
505
|
|
|
419
|
-
//
|
|
420
|
-
const revertRate =
|
|
506
|
+
// Calculate actual revert rate from git history
|
|
507
|
+
const revertRate = calculateRevertRate();
|
|
421
508
|
|
|
422
509
|
return {
|
|
423
510
|
entriesWithCheckpoints,
|
|
@@ -753,57 +840,63 @@ function provideAIInsights(contributionPatterns, qualityMetrics, checkpointAnaly
|
|
|
753
840
|
|
|
754
841
|
/**
|
|
755
842
|
* Get Cursor AI code tracking data for a commit
|
|
843
|
+
* Uses Cursor's AI Code Tracking API (Enterprise feature)
|
|
844
|
+
* @see https://cursor.com/docs/account/teams/ai-code-tracking-api
|
|
756
845
|
* @param {string} commitHash - Git commit hash to analyze
|
|
757
846
|
* @returns {Promise<Object>} AI code tracking data
|
|
758
847
|
*/
|
|
759
848
|
async function getCursorTrackingData(commitHash) {
|
|
849
|
+
const apiUrl = process.env.CURSOR_TRACKING_API;
|
|
850
|
+
const apiKey = process.env.CURSOR_API_KEY;
|
|
851
|
+
|
|
852
|
+
if (!apiUrl || !apiKey) {
|
|
853
|
+
return {
|
|
854
|
+
available: false,
|
|
855
|
+
reason: 'Cursor API not configured. Set CURSOR_TRACKING_API and CURSOR_API_KEY environment variables.',
|
|
856
|
+
documentation: 'https://cursor.com/docs/account/teams/ai-code-tracking-api'
|
|
857
|
+
};
|
|
858
|
+
}
|
|
859
|
+
|
|
760
860
|
try {
|
|
761
|
-
//
|
|
762
|
-
|
|
763
|
-
|
|
861
|
+
// Basic auth: base64(apiKey:) - Cursor API uses API key with empty password
|
|
862
|
+
const auth = Buffer.from(`${apiKey}:`).toString('base64');
|
|
863
|
+
|
|
864
|
+
const response = await fetch(`${apiUrl}/analytics/ai-code/commits`, {
|
|
865
|
+
method: 'GET',
|
|
866
|
+
headers: {
|
|
867
|
+
'Authorization': `Basic ${auth}`,
|
|
868
|
+
'Content-Type': 'application/json',
|
|
869
|
+
}
|
|
870
|
+
});
|
|
871
|
+
|
|
872
|
+
if (!response.ok) {
|
|
873
|
+
return {
|
|
874
|
+
available: false,
|
|
875
|
+
reason: `Cursor API error: ${response.status} ${response.statusText}`
|
|
876
|
+
};
|
|
764
877
|
}
|
|
765
878
|
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
879
|
+
const data = await response.json();
|
|
880
|
+
|
|
881
|
+
// Find commit-specific data if available
|
|
882
|
+
const commitData = data.commits?.find(c => c.commit_hash === commitHash) || data;
|
|
883
|
+
|
|
884
|
+
// Transform API response to our internal format
|
|
885
|
+
return {
|
|
769
886
|
available: true,
|
|
770
887
|
commit_hash: commitHash,
|
|
771
|
-
ai_code_breakdown: {
|
|
772
|
-
tab_completions: {
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
files_affected: ['src/utils.js', 'tests/utils.test.js'],
|
|
776
|
-
},
|
|
777
|
-
composer_chat: {
|
|
778
|
-
lines_added: 78,
|
|
779
|
-
percentage: 60,
|
|
780
|
-
files_affected: ['src/new-feature.js', 'src/api.js'],
|
|
781
|
-
checkpoints_created: 3,
|
|
782
|
-
},
|
|
783
|
-
manual_human: {
|
|
784
|
-
lines_added: 5,
|
|
785
|
-
percentage: 5,
|
|
786
|
-
files_affected: ['README.md'],
|
|
787
|
-
},
|
|
888
|
+
ai_code_breakdown: commitData.ai_code_breakdown || {
|
|
889
|
+
tab_completions: { lines_added: 0, percentage: 0, files_affected: [] },
|
|
890
|
+
composer_chat: { lines_added: 0, percentage: 0, files_affected: [], checkpoints_created: 0 },
|
|
891
|
+
manual_human: { lines_added: 0, percentage: 0, files_affected: [] },
|
|
788
892
|
},
|
|
789
|
-
change_groups: [
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
lines_human_edited: 8,
|
|
795
|
-
confidence_score: 0.85,
|
|
796
|
-
timestamp: new Date().toISOString(),
|
|
797
|
-
},
|
|
798
|
-
],
|
|
799
|
-
quality_metrics: {
|
|
800
|
-
ai_code_quality_score: 0.78,
|
|
801
|
-
human_override_rate: 0.12,
|
|
802
|
-
acceptance_rate: 0.94,
|
|
893
|
+
change_groups: commitData.change_groups || [],
|
|
894
|
+
quality_metrics: commitData.quality_metrics || {
|
|
895
|
+
ai_code_quality_score: 0,
|
|
896
|
+
human_override_rate: 0,
|
|
897
|
+
acceptance_rate: 0,
|
|
803
898
|
},
|
|
804
899
|
};
|
|
805
|
-
|
|
806
|
-
return mockTrackingData;
|
|
807
900
|
} catch (error) {
|
|
808
901
|
return {
|
|
809
902
|
available: false,
|
|
@@ -888,62 +981,92 @@ async function initProvenance(options) {
|
|
|
888
981
|
|
|
889
982
|
/**
|
|
890
983
|
* Get Cursor Composer/Chat checkpoint data
|
|
891
|
-
*
|
|
984
|
+
* Reads from local .cursor/ directory since checkpoints are stored locally by Cursor Agent
|
|
985
|
+
* @returns {Promise<Object>} Checkpoint data
|
|
892
986
|
*/
|
|
893
987
|
async function getCursorCheckpoints() {
|
|
988
|
+
const cursorDir = path.join(process.cwd(), '.cursor');
|
|
989
|
+
|
|
990
|
+
if (!fs.existsSync(cursorDir)) {
|
|
991
|
+
return {
|
|
992
|
+
available: false,
|
|
993
|
+
reason: 'No .cursor directory found. Checkpoints are only available when using Cursor IDE.'
|
|
994
|
+
};
|
|
995
|
+
}
|
|
996
|
+
|
|
894
997
|
try {
|
|
895
|
-
//
|
|
896
|
-
|
|
897
|
-
|
|
998
|
+
// Look for checkpoint metadata in .cursor directory
|
|
999
|
+
// Cursor stores checkpoints locally during Composer/Agent sessions
|
|
1000
|
+
const checkpointPatterns = [
|
|
1001
|
+
'.cursor/**/checkpoint*.json',
|
|
1002
|
+
'.cursor/**/checkpoints.json',
|
|
1003
|
+
'.cursor/composer/checkpoints/*.json',
|
|
1004
|
+
'.cursor/agent/checkpoints/*.json',
|
|
1005
|
+
];
|
|
1006
|
+
|
|
1007
|
+
let checkpointFiles = [];
|
|
1008
|
+
for (const pattern of checkpointPatterns) {
|
|
1009
|
+
const glob = require('glob');
|
|
1010
|
+
const matches = glob.sync(pattern, { cwd: process.cwd(), absolute: true });
|
|
1011
|
+
checkpointFiles = checkpointFiles.concat(matches);
|
|
898
1012
|
}
|
|
899
1013
|
|
|
900
|
-
//
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
1014
|
+
// Remove duplicates
|
|
1015
|
+
checkpointFiles = [...new Set(checkpointFiles)];
|
|
1016
|
+
|
|
1017
|
+
if (checkpointFiles.length === 0) {
|
|
1018
|
+
return {
|
|
1019
|
+
available: false,
|
|
1020
|
+
reason: 'No checkpoints found in current session. Checkpoints are created during Cursor Composer/Agent sessions.'
|
|
1021
|
+
};
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
// Parse checkpoint files and aggregate data
|
|
1025
|
+
const checkpoints = [];
|
|
1026
|
+
for (const file of checkpointFiles) {
|
|
1027
|
+
try {
|
|
1028
|
+
const content = await fs.readFile(file, 'utf8');
|
|
1029
|
+
const data = JSON.parse(content);
|
|
1030
|
+
|
|
1031
|
+
// Handle both single checkpoint and array of checkpoints
|
|
1032
|
+
if (Array.isArray(data)) {
|
|
1033
|
+
checkpoints.push(...data);
|
|
1034
|
+
} else if (data.checkpoints) {
|
|
1035
|
+
checkpoints.push(...data.checkpoints);
|
|
1036
|
+
} else if (data.id || data.timestamp) {
|
|
1037
|
+
checkpoints.push(data);
|
|
1038
|
+
}
|
|
1039
|
+
} catch (parseError) {
|
|
1040
|
+
// Skip invalid checkpoint files
|
|
1041
|
+
continue;
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
if (checkpoints.length === 0) {
|
|
1046
|
+
return {
|
|
1047
|
+
available: false,
|
|
1048
|
+
reason: 'No valid checkpoints found in checkpoint files.'
|
|
1049
|
+
};
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
// Sort by timestamp (newest first)
|
|
1053
|
+
checkpoints.sort((a, b) => {
|
|
1054
|
+
const timeA = new Date(a.timestamp || 0).getTime();
|
|
1055
|
+
const timeB = new Date(b.timestamp || 0).getTime();
|
|
1056
|
+
return timeB - timeA;
|
|
1057
|
+
});
|
|
1058
|
+
|
|
1059
|
+
// Mark latest checkpoint as non-revertible
|
|
1060
|
+
if (checkpoints.length > 0) {
|
|
1061
|
+
checkpoints[0].can_revert = false;
|
|
1062
|
+
}
|
|
940
1063
|
|
|
941
|
-
return { available: true, checkpoints
|
|
1064
|
+
return { available: true, checkpoints };
|
|
942
1065
|
} catch (error) {
|
|
943
1066
|
return {
|
|
944
1067
|
available: false,
|
|
945
1068
|
error: error.message,
|
|
946
|
-
reason: 'Failed to
|
|
1069
|
+
reason: 'Failed to read Cursor checkpoint data',
|
|
947
1070
|
};
|
|
948
1071
|
}
|
|
949
1072
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quality-gates.d.ts","sourceRoot":"","sources":["../../src/commands/quality-gates.js"],"names":[],"mappings":"AAqBA;;;GAGG;AACH,iEA8ZC"}
|