playwright-intelligence-engine 2.0.0 → 2.0.2
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/README.md +229 -229
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/core/version.d.ts +3 -3
- package/dist/index.js +81 -24
- package/package.json +76 -76
- package/src/authoring/author.ts +81 -81
- package/src/authoring/generation-contract.ts +283 -283
- package/src/authoring/hybrid-author.ts +115 -115
- package/src/authoring/index.ts +7 -7
- package/src/authoring/llm-author.ts +282 -282
- package/src/authoring/naming/name-plan.ts +28 -28
- package/src/authoring/naming/name-planner.ts +339 -339
- package/src/authoring/naming/naming-linter.ts +292 -292
- package/src/cli/index.ts +1238 -1172
- package/src/collectors/git-diff-collector.ts +190 -190
- package/src/core/version.ts +25 -25
- package/src/diagnostics/diagnostic-report.ts +204 -204
- package/src/diagnostics/failure-classifier.ts +701 -701
- package/src/evaluation/repository-runner.ts +197 -197
- package/src/gate/quality.ts +101 -101
- package/src/generator/architecture-generator.ts +582 -582
- package/src/generator/assertion-quality-gate.ts +88 -88
- package/src/generator/candidate-writer.ts +288 -288
- package/src/generator/test-generator.ts +52 -52
- package/src/index.ts +107 -107
- package/src/intelligence/evidence-bundle.ts +300 -300
- package/src/intelligence/generation-agent.ts +561 -561
- package/src/intelligence/generation-verifier.ts +1115 -1115
- package/src/intelligence/locator-disambiguation-engine.ts +331 -331
- package/src/intelligence/project-intelligence.ts +140 -140
- package/src/intelligence/repository-profile.ts +796 -796
- package/src/intelligence/trace-proposal-workflow.ts +318 -318
- package/src/intelligence/workflow-planner.ts +966 -966
- package/src/mcp/server.ts +970 -970
- package/src/perception/app-model.ts +32 -32
- package/src/perception/crawler.ts +263 -263
- package/src/perception/index.ts +3 -3
- package/src/repair/assertion-hasher.ts +386 -386
- package/src/repair/diff-allowlist.ts +612 -612
- package/src/repair/intent-validator.ts +761 -761
- package/src/repair/repair-planner.ts +467 -467
- package/src/repair/statement-patcher.ts +544 -544
- package/src/reproduce/interactive-workflow-runner.ts +828 -828
- package/src/sandbox/execution-runner.ts +408 -408
- package/src/selector/abstention-policy.ts +175 -175
- package/src/selector/candidate-extractor.ts +343 -343
- package/src/selector/repair-candidate-ranker.ts +92 -92
- package/src/selector/selector-scorer.ts +344 -344
|
@@ -1,190 +1,190 @@
|
|
|
1
|
-
import { execFileSync } from 'child_process';
|
|
2
|
-
import { EvidenceCollector } from './collector-interface.js';
|
|
3
|
-
import { UnifiedEvidenceRecord } from '../evidence/evidence-model.js';
|
|
4
|
-
import { EvidenceRedactor } from '../evidence/evidence-redactor.js';
|
|
5
|
-
|
|
6
|
-
export interface GitDiffInput {
|
|
7
|
-
workspaceRoot: string;
|
|
8
|
-
sinceRef?: string;
|
|
9
|
-
executionId?: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export class GitDiffCollector implements EvidenceCollector<GitDiffInput> {
|
|
13
|
-
public readonly name = 'GitDiffCollector';
|
|
14
|
-
public readonly source = 'git-diff' as const;
|
|
15
|
-
|
|
16
|
-
public async collect(input: GitDiffInput): Promise<UnifiedEvidenceRecord[]> {
|
|
17
|
-
const executionId = input.executionId ?? `exec-${Date.now()}`;
|
|
18
|
-
const timestamp = Date.now();
|
|
19
|
-
const ref = input.sinceRef ?? 'HEAD~1';
|
|
20
|
-
|
|
21
|
-
try {
|
|
22
|
-
// 1. Get recent commits
|
|
23
|
-
const logOutput = execFileSync(
|
|
24
|
-
'git',
|
|
25
|
-
['log', '-n', '5', '--pretty=format:%h|%an|%s'],
|
|
26
|
-
{ cwd: input.workspaceRoot, encoding: 'utf-8', timeout: 5000 }
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
const recentCommits = logOutput
|
|
30
|
-
.split('\n')
|
|
31
|
-
.filter(Boolean)
|
|
32
|
-
.map((line) => {
|
|
33
|
-
const [hash, author, subject] = line.split('|');
|
|
34
|
-
return { hash, author, subject };
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
// 2. Get changed files
|
|
38
|
-
let changedFiles: string[] = [];
|
|
39
|
-
try {
|
|
40
|
-
const filesOutput = execFileSync('git', ['diff', '--name-only', ref, 'HEAD'], {
|
|
41
|
-
cwd: input.workspaceRoot,
|
|
42
|
-
encoding: 'utf-8',
|
|
43
|
-
timeout: 5000,
|
|
44
|
-
});
|
|
45
|
-
changedFiles = filesOutput.split('\n').filter(Boolean);
|
|
46
|
-
} catch {
|
|
47
|
-
// If ref doesn't exist, diff working tree
|
|
48
|
-
const uncommitted = execFileSync('git', ['diff', '--name-only'], {
|
|
49
|
-
cwd: input.workspaceRoot,
|
|
50
|
-
encoding: 'utf-8',
|
|
51
|
-
timeout: 5000,
|
|
52
|
-
});
|
|
53
|
-
changedFiles = uncommitted.split('\n').filter(Boolean);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// 3. Get diff summary with line changes
|
|
57
|
-
let rawDiff = '';
|
|
58
|
-
try {
|
|
59
|
-
rawDiff = execFileSync('git', ['diff', '-U2', ref, 'HEAD'], {
|
|
60
|
-
cwd: input.workspaceRoot,
|
|
61
|
-
encoding: 'utf-8',
|
|
62
|
-
timeout: 5000,
|
|
63
|
-
maxBuffer: 4 * 1024 * 1024,
|
|
64
|
-
});
|
|
65
|
-
} catch {
|
|
66
|
-
rawDiff = execFileSync('git', ['diff', '-U2'], {
|
|
67
|
-
cwd: input.workspaceRoot,
|
|
68
|
-
encoding: 'utf-8',
|
|
69
|
-
timeout: 5000,
|
|
70
|
-
maxBuffer: 4 * 1024 * 1024,
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const { redactedText: cleanDiff } = EvidenceRedactor.redactText(rawDiff);
|
|
75
|
-
|
|
76
|
-
// Extract modified selectors or identifiers in diff
|
|
77
|
-
const modifiedAttributes: string[] = [];
|
|
78
|
-
const attrMatches = cleanDiff.matchAll(/[+-]\s*.*?(id|data-testid|class|name|role|aria-label|placeholder)=["']([^"']+)["']/g);
|
|
79
|
-
for (const m of attrMatches) {
|
|
80
|
-
modifiedAttributes.push(`${m[1]}="${m[2]}"`);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const diffHints = GitDiffCollector.extractDiffHints(cleanDiff, changedFiles);
|
|
84
|
-
|
|
85
|
-
return [
|
|
86
|
-
{
|
|
87
|
-
evidenceId: `git-${timestamp}-${Math.random().toString(36).slice(2, 8)}`,
|
|
88
|
-
executionId,
|
|
89
|
-
source: 'git-diff',
|
|
90
|
-
timestamp,
|
|
91
|
-
evidenceType: 'git-diff',
|
|
92
|
-
payload: {
|
|
93
|
-
sinceRef: ref,
|
|
94
|
-
recentCommits,
|
|
95
|
-
changedFiles,
|
|
96
|
-
modifiedAttributes: Array.from(new Set(modifiedAttributes)),
|
|
97
|
-
diffHints,
|
|
98
|
-
diffSnippet: cleanDiff.slice(0, 10000),
|
|
99
|
-
},
|
|
100
|
-
reliability: 'HIGH',
|
|
101
|
-
provenance: {
|
|
102
|
-
collector: this.name,
|
|
103
|
-
collectedAt: timestamp,
|
|
104
|
-
captureMethod: 'git-cli-diff',
|
|
105
|
-
sourceUri: input.workspaceRoot,
|
|
106
|
-
},
|
|
107
|
-
redactionStatus: { isRedacted: false },
|
|
108
|
-
},
|
|
109
|
-
];
|
|
110
|
-
} catch (err: any) {
|
|
111
|
-
return [
|
|
112
|
-
{
|
|
113
|
-
evidenceId: `git-${timestamp}-${Math.random().toString(36).slice(2, 8)}`,
|
|
114
|
-
executionId,
|
|
115
|
-
source: 'git-diff',
|
|
116
|
-
timestamp,
|
|
117
|
-
evidenceType: 'git-diff',
|
|
118
|
-
payload: {
|
|
119
|
-
error: err?.message || 'Failed to collect git diff',
|
|
120
|
-
changedFiles: [],
|
|
121
|
-
recentCommits: [],
|
|
122
|
-
},
|
|
123
|
-
reliability: 'LOW',
|
|
124
|
-
provenance: {
|
|
125
|
-
collector: this.name,
|
|
126
|
-
collectedAt: timestamp,
|
|
127
|
-
captureMethod: 'git-cli-diff',
|
|
128
|
-
sourceUri: input.workspaceRoot,
|
|
129
|
-
},
|
|
130
|
-
redactionStatus: { isRedacted: false },
|
|
131
|
-
},
|
|
132
|
-
];
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
public static extractDiffHints(cleanDiff: string, changedFiles: string[]): {
|
|
137
|
-
changedRoutes: string[];
|
|
138
|
-
changedSymbols: string[];
|
|
139
|
-
apiEndpoints: string[];
|
|
140
|
-
validationHints: string[];
|
|
141
|
-
existingTestsChanged: string[];
|
|
142
|
-
} {
|
|
143
|
-
const addedOrChangedLines = cleanDiff
|
|
144
|
-
.split(/\r?\n/)
|
|
145
|
-
.filter((line) => (line.startsWith('+') || line.startsWith('-')) && !line.startsWith('+++') && !line.startsWith('---'))
|
|
146
|
-
.join('\n');
|
|
147
|
-
|
|
148
|
-
const changedRoutes = new Set<string>();
|
|
149
|
-
for (const file of changedFiles) {
|
|
150
|
-
const appMatch = file.match(/(?:^|\/)(?:src\/)?app\/(.+?)\/page\.[tj]sx?$/i);
|
|
151
|
-
if (appMatch?.[1]) changedRoutes.add(`/${appMatch[1]}`);
|
|
152
|
-
const pagesMatch = file.match(/(?:^|\/)(?:src\/)?pages\/(.+?)\.[tj]sx?$/i);
|
|
153
|
-
if (pagesMatch?.[1] && !pagesMatch[1].startsWith('api/')) {
|
|
154
|
-
changedRoutes.add(pagesMatch[1] === 'index' ? '/' : `/${pagesMatch[1].replace(/\/index$/, '')}`);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
for (const m of addedOrChangedLines.matchAll(/path\s*[:=]\s*['"](\/[^'"]*)['"]/g)) {
|
|
158
|
-
if (m[1]) changedRoutes.add(m[1]);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
const changedSymbols = new Set<string>();
|
|
162
|
-
for (const m of addedOrChangedLines.matchAll(/(?:function|class|const|export\s+(?:async\s+)?function)\s+([A-Za-z_][A-Za-z0-9_]*)/g)) {
|
|
163
|
-
if (m[1]) changedSymbols.add(m[1]);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const apiEndpoints = new Set<string>();
|
|
167
|
-
for (const m of addedOrChangedLines.matchAll(/['"`](\/api\/[A-Za-z0-9_/?=&{}:-]+)['"`]/g)) {
|
|
168
|
-
if (m[1]) apiEndpoints.add(m[1]);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const validationHints = new Set<string>();
|
|
172
|
-
for (const m of addedOrChangedLines.matchAll(/\.(min|max|email|regex|required)\s*\(([^)]*)\)/g)) {
|
|
173
|
-
validationHints.add(`${m[1]}(${(m[2] ?? '').trim()})`);
|
|
174
|
-
}
|
|
175
|
-
for (const m of addedOrChangedLines.matchAll(/required(?:\s*=\s*\{?true\}?|\b)/g)) {
|
|
176
|
-
validationHints.add(m[0].trim());
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const existingTestsChanged = changedFiles.filter((f) => /\.(?:spec|test)\.[tj]sx?$/i.test(f));
|
|
180
|
-
|
|
181
|
-
return {
|
|
182
|
-
changedRoutes: [...changedRoutes],
|
|
183
|
-
changedSymbols: [...changedSymbols].slice(0, 30),
|
|
184
|
-
apiEndpoints: [...apiEndpoints].slice(0, 20),
|
|
185
|
-
validationHints: [...validationHints].slice(0, 20),
|
|
186
|
-
existingTestsChanged,
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
1
|
+
import { execFileSync } from 'child_process';
|
|
2
|
+
import { EvidenceCollector } from './collector-interface.js';
|
|
3
|
+
import { UnifiedEvidenceRecord } from '../evidence/evidence-model.js';
|
|
4
|
+
import { EvidenceRedactor } from '../evidence/evidence-redactor.js';
|
|
5
|
+
|
|
6
|
+
export interface GitDiffInput {
|
|
7
|
+
workspaceRoot: string;
|
|
8
|
+
sinceRef?: string;
|
|
9
|
+
executionId?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class GitDiffCollector implements EvidenceCollector<GitDiffInput> {
|
|
13
|
+
public readonly name = 'GitDiffCollector';
|
|
14
|
+
public readonly source = 'git-diff' as const;
|
|
15
|
+
|
|
16
|
+
public async collect(input: GitDiffInput): Promise<UnifiedEvidenceRecord[]> {
|
|
17
|
+
const executionId = input.executionId ?? `exec-${Date.now()}`;
|
|
18
|
+
const timestamp = Date.now();
|
|
19
|
+
const ref = input.sinceRef ?? 'HEAD~1';
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
// 1. Get recent commits
|
|
23
|
+
const logOutput = execFileSync(
|
|
24
|
+
'git',
|
|
25
|
+
['log', '-n', '5', '--pretty=format:%h|%an|%s'],
|
|
26
|
+
{ cwd: input.workspaceRoot, encoding: 'utf-8', timeout: 5000 }
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const recentCommits = logOutput
|
|
30
|
+
.split('\n')
|
|
31
|
+
.filter(Boolean)
|
|
32
|
+
.map((line) => {
|
|
33
|
+
const [hash, author, subject] = line.split('|');
|
|
34
|
+
return { hash, author, subject };
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// 2. Get changed files
|
|
38
|
+
let changedFiles: string[] = [];
|
|
39
|
+
try {
|
|
40
|
+
const filesOutput = execFileSync('git', ['diff', '--name-only', ref, 'HEAD'], {
|
|
41
|
+
cwd: input.workspaceRoot,
|
|
42
|
+
encoding: 'utf-8',
|
|
43
|
+
timeout: 5000,
|
|
44
|
+
});
|
|
45
|
+
changedFiles = filesOutput.split('\n').filter(Boolean);
|
|
46
|
+
} catch {
|
|
47
|
+
// If ref doesn't exist, diff working tree
|
|
48
|
+
const uncommitted = execFileSync('git', ['diff', '--name-only'], {
|
|
49
|
+
cwd: input.workspaceRoot,
|
|
50
|
+
encoding: 'utf-8',
|
|
51
|
+
timeout: 5000,
|
|
52
|
+
});
|
|
53
|
+
changedFiles = uncommitted.split('\n').filter(Boolean);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 3. Get diff summary with line changes
|
|
57
|
+
let rawDiff = '';
|
|
58
|
+
try {
|
|
59
|
+
rawDiff = execFileSync('git', ['diff', '-U2', ref, 'HEAD'], {
|
|
60
|
+
cwd: input.workspaceRoot,
|
|
61
|
+
encoding: 'utf-8',
|
|
62
|
+
timeout: 5000,
|
|
63
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
64
|
+
});
|
|
65
|
+
} catch {
|
|
66
|
+
rawDiff = execFileSync('git', ['diff', '-U2'], {
|
|
67
|
+
cwd: input.workspaceRoot,
|
|
68
|
+
encoding: 'utf-8',
|
|
69
|
+
timeout: 5000,
|
|
70
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const { redactedText: cleanDiff } = EvidenceRedactor.redactText(rawDiff);
|
|
75
|
+
|
|
76
|
+
// Extract modified selectors or identifiers in diff
|
|
77
|
+
const modifiedAttributes: string[] = [];
|
|
78
|
+
const attrMatches = cleanDiff.matchAll(/[+-]\s*.*?(id|data-testid|class|name|role|aria-label|placeholder)=["']([^"']+)["']/g);
|
|
79
|
+
for (const m of attrMatches) {
|
|
80
|
+
modifiedAttributes.push(`${m[1]}="${m[2]}"`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const diffHints = GitDiffCollector.extractDiffHints(cleanDiff, changedFiles);
|
|
84
|
+
|
|
85
|
+
return [
|
|
86
|
+
{
|
|
87
|
+
evidenceId: `git-${timestamp}-${Math.random().toString(36).slice(2, 8)}`,
|
|
88
|
+
executionId,
|
|
89
|
+
source: 'git-diff',
|
|
90
|
+
timestamp,
|
|
91
|
+
evidenceType: 'git-diff',
|
|
92
|
+
payload: {
|
|
93
|
+
sinceRef: ref,
|
|
94
|
+
recentCommits,
|
|
95
|
+
changedFiles,
|
|
96
|
+
modifiedAttributes: Array.from(new Set(modifiedAttributes)),
|
|
97
|
+
diffHints,
|
|
98
|
+
diffSnippet: cleanDiff.slice(0, 10000),
|
|
99
|
+
},
|
|
100
|
+
reliability: 'HIGH',
|
|
101
|
+
provenance: {
|
|
102
|
+
collector: this.name,
|
|
103
|
+
collectedAt: timestamp,
|
|
104
|
+
captureMethod: 'git-cli-diff',
|
|
105
|
+
sourceUri: input.workspaceRoot,
|
|
106
|
+
},
|
|
107
|
+
redactionStatus: { isRedacted: false },
|
|
108
|
+
},
|
|
109
|
+
];
|
|
110
|
+
} catch (err: any) {
|
|
111
|
+
return [
|
|
112
|
+
{
|
|
113
|
+
evidenceId: `git-${timestamp}-${Math.random().toString(36).slice(2, 8)}`,
|
|
114
|
+
executionId,
|
|
115
|
+
source: 'git-diff',
|
|
116
|
+
timestamp,
|
|
117
|
+
evidenceType: 'git-diff',
|
|
118
|
+
payload: {
|
|
119
|
+
error: err?.message || 'Failed to collect git diff',
|
|
120
|
+
changedFiles: [],
|
|
121
|
+
recentCommits: [],
|
|
122
|
+
},
|
|
123
|
+
reliability: 'LOW',
|
|
124
|
+
provenance: {
|
|
125
|
+
collector: this.name,
|
|
126
|
+
collectedAt: timestamp,
|
|
127
|
+
captureMethod: 'git-cli-diff',
|
|
128
|
+
sourceUri: input.workspaceRoot,
|
|
129
|
+
},
|
|
130
|
+
redactionStatus: { isRedacted: false },
|
|
131
|
+
},
|
|
132
|
+
];
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
public static extractDiffHints(cleanDiff: string, changedFiles: string[]): {
|
|
137
|
+
changedRoutes: string[];
|
|
138
|
+
changedSymbols: string[];
|
|
139
|
+
apiEndpoints: string[];
|
|
140
|
+
validationHints: string[];
|
|
141
|
+
existingTestsChanged: string[];
|
|
142
|
+
} {
|
|
143
|
+
const addedOrChangedLines = cleanDiff
|
|
144
|
+
.split(/\r?\n/)
|
|
145
|
+
.filter((line) => (line.startsWith('+') || line.startsWith('-')) && !line.startsWith('+++') && !line.startsWith('---'))
|
|
146
|
+
.join('\n');
|
|
147
|
+
|
|
148
|
+
const changedRoutes = new Set<string>();
|
|
149
|
+
for (const file of changedFiles) {
|
|
150
|
+
const appMatch = file.match(/(?:^|\/)(?:src\/)?app\/(.+?)\/page\.[tj]sx?$/i);
|
|
151
|
+
if (appMatch?.[1]) changedRoutes.add(`/${appMatch[1]}`);
|
|
152
|
+
const pagesMatch = file.match(/(?:^|\/)(?:src\/)?pages\/(.+?)\.[tj]sx?$/i);
|
|
153
|
+
if (pagesMatch?.[1] && !pagesMatch[1].startsWith('api/')) {
|
|
154
|
+
changedRoutes.add(pagesMatch[1] === 'index' ? '/' : `/${pagesMatch[1].replace(/\/index$/, '')}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
for (const m of addedOrChangedLines.matchAll(/path\s*[:=]\s*['"](\/[^'"]*)['"]/g)) {
|
|
158
|
+
if (m[1]) changedRoutes.add(m[1]);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const changedSymbols = new Set<string>();
|
|
162
|
+
for (const m of addedOrChangedLines.matchAll(/(?:function|class|const|export\s+(?:async\s+)?function)\s+([A-Za-z_][A-Za-z0-9_]*)/g)) {
|
|
163
|
+
if (m[1]) changedSymbols.add(m[1]);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const apiEndpoints = new Set<string>();
|
|
167
|
+
for (const m of addedOrChangedLines.matchAll(/['"`](\/api\/[A-Za-z0-9_/?=&{}:-]+)['"`]/g)) {
|
|
168
|
+
if (m[1]) apiEndpoints.add(m[1]);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const validationHints = new Set<string>();
|
|
172
|
+
for (const m of addedOrChangedLines.matchAll(/\.(min|max|email|regex|required)\s*\(([^)]*)\)/g)) {
|
|
173
|
+
validationHints.add(`${m[1]}(${(m[2] ?? '').trim()})`);
|
|
174
|
+
}
|
|
175
|
+
for (const m of addedOrChangedLines.matchAll(/required(?:\s*=\s*\{?true\}?|\b)/g)) {
|
|
176
|
+
validationHints.add(m[0].trim());
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const existingTestsChanged = changedFiles.filter((f) => /\.(?:spec|test)\.[tj]sx?$/i.test(f));
|
|
180
|
+
|
|
181
|
+
return {
|
|
182
|
+
changedRoutes: [...changedRoutes],
|
|
183
|
+
changedSymbols: [...changedSymbols].slice(0, 30),
|
|
184
|
+
apiEndpoints: [...apiEndpoints].slice(0, 20),
|
|
185
|
+
validationHints: [...validationHints].slice(0, 20),
|
|
186
|
+
existingTestsChanged,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
package/src/core/version.ts
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import { execFileSync } from 'node:child_process';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Product identity is kept in one place so the CLI, MCP server, and execution
|
|
5
|
-
* proofs cannot silently advertise different versions.
|
|
6
|
-
*/
|
|
7
|
-
export const PACKAGE_VERSION = '2.0.
|
|
8
|
-
export const ENGINE_MILESTONE = '2.0.
|
|
9
|
-
export const PROOF_VERSION = ENGINE_MILESTONE;
|
|
10
|
-
|
|
11
|
-
export interface RuntimeProvenance {
|
|
12
|
-
sourceRevision: string;
|
|
13
|
-
workspaceDirty: boolean;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function getRuntimeProvenance(root = process.cwd()): RuntimeProvenance {
|
|
17
|
-
try {
|
|
18
|
-
const sourceRevision = execFileSync('git', ['rev-parse', 'HEAD'], { cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim() || 'unknown';
|
|
19
|
-
const status = execFileSync('git', ['status', '--porcelain'], { cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
20
|
-
return { sourceRevision, workspaceDirty: status.trim().length > 0 };
|
|
21
|
-
} catch {
|
|
22
|
-
return { sourceRevision: 'unknown', workspaceDirty: false };
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Product identity is kept in one place so the CLI, MCP server, and execution
|
|
5
|
+
* proofs cannot silently advertise different versions.
|
|
6
|
+
*/
|
|
7
|
+
export const PACKAGE_VERSION = '2.0.2';
|
|
8
|
+
export const ENGINE_MILESTONE = '2.0.2';
|
|
9
|
+
export const PROOF_VERSION = ENGINE_MILESTONE;
|
|
10
|
+
|
|
11
|
+
export interface RuntimeProvenance {
|
|
12
|
+
sourceRevision: string;
|
|
13
|
+
workspaceDirty: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function getRuntimeProvenance(root = process.cwd()): RuntimeProvenance {
|
|
17
|
+
try {
|
|
18
|
+
const sourceRevision = execFileSync('git', ['rev-parse', 'HEAD'], { cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim() || 'unknown';
|
|
19
|
+
const status = execFileSync('git', ['status', '--porcelain'], { cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
20
|
+
return { sourceRevision, workspaceDirty: status.trim().length > 0 };
|
|
21
|
+
} catch {
|
|
22
|
+
return { sourceRevision: 'unknown', workspaceDirty: false };
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|