@ttfw/envoi 1.0.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/README.md +238 -0
- package/dist/commands/app.d.ts +2 -0
- package/dist/commands/app.d.ts.map +1 -0
- package/dist/commands/app.js +31 -0
- package/dist/commands/app.js.map +1 -0
- package/dist/commands/autonomy.d.ts +6 -0
- package/dist/commands/autonomy.d.ts.map +1 -0
- package/dist/commands/autonomy.js +89 -0
- package/dist/commands/autonomy.js.map +1 -0
- package/dist/commands/builder.d.ts +13 -0
- package/dist/commands/builder.d.ts.map +1 -0
- package/dist/commands/builder.js +142 -0
- package/dist/commands/builder.js.map +1 -0
- package/dist/commands/idea.d.ts +12 -0
- package/dist/commands/idea.d.ts.map +1 -0
- package/dist/commands/idea.js +79 -0
- package/dist/commands/idea.js.map +1 -0
- package/dist/commands/init.d.ts +18 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +423 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/mode.d.ts +13 -0
- package/dist/commands/mode.d.ts.map +1 -0
- package/dist/commands/mode.js +96 -0
- package/dist/commands/mode.js.map +1 -0
- package/dist/commands/onboard.d.ts +37 -0
- package/dist/commands/onboard.d.ts.map +1 -0
- package/dist/commands/onboard.js +743 -0
- package/dist/commands/onboard.js.map +1 -0
- package/dist/commands/pr-note.d.ts +8 -0
- package/dist/commands/pr-note.d.ts.map +1 -0
- package/dist/commands/pr-note.js +27 -0
- package/dist/commands/pr-note.js.map +1 -0
- package/dist/commands/undo.d.ts +7 -0
- package/dist/commands/undo.d.ts.map +1 -0
- package/dist/commands/undo.js +59 -0
- package/dist/commands/undo.js.map +1 -0
- package/dist/commands/update.d.ts +24 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +248 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/constants/report_codes.d.ts +29 -0
- package/dist/constants/report_codes.d.ts.map +1 -0
- package/dist/constants/report_codes.js +69 -0
- package/dist/constants/report_codes.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +675 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/autonomy.d.ts +16 -0
- package/dist/lib/autonomy.d.ts.map +1 -0
- package/dist/lib/autonomy.js +38 -0
- package/dist/lib/autonomy.js.map +1 -0
- package/dist/lib/blocked.d.ts +87 -0
- package/dist/lib/blocked.d.ts.map +1 -0
- package/dist/lib/blocked.js +134 -0
- package/dist/lib/blocked.js.map +1 -0
- package/dist/lib/branding.d.ts +13 -0
- package/dist/lib/branding.d.ts.map +1 -0
- package/dist/lib/branding.js +19 -0
- package/dist/lib/branding.js.map +1 -0
- package/dist/lib/claude.d.ts +42 -0
- package/dist/lib/claude.d.ts.map +1 -0
- package/dist/lib/claude.js +291 -0
- package/dist/lib/claude.js.map +1 -0
- package/dist/lib/config.d.ts +71 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +410 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/diff.d.ts +150 -0
- package/dist/lib/diff.d.ts.map +1 -0
- package/dist/lib/diff.js +257 -0
- package/dist/lib/diff.js.map +1 -0
- package/dist/lib/doctor.d.ts +67 -0
- package/dist/lib/doctor.d.ts.map +1 -0
- package/dist/lib/doctor.js +211 -0
- package/dist/lib/doctor.js.map +1 -0
- package/dist/lib/fingerprint.d.ts +27 -0
- package/dist/lib/fingerprint.d.ts.map +1 -0
- package/dist/lib/fingerprint.js +116 -0
- package/dist/lib/fingerprint.js.map +1 -0
- package/dist/lib/fs.d.ts +93 -0
- package/dist/lib/fs.d.ts.map +1 -0
- package/dist/lib/fs.js +179 -0
- package/dist/lib/fs.js.map +1 -0
- package/dist/lib/git.d.ts +177 -0
- package/dist/lib/git.d.ts.map +1 -0
- package/dist/lib/git.js +355 -0
- package/dist/lib/git.js.map +1 -0
- package/dist/lib/git_branching.d.ts +84 -0
- package/dist/lib/git_branching.d.ts.map +1 -0
- package/dist/lib/git_branching.js +327 -0
- package/dist/lib/git_branching.js.map +1 -0
- package/dist/lib/gitignore.d.ts +26 -0
- package/dist/lib/gitignore.d.ts.map +1 -0
- package/dist/lib/gitignore.js +119 -0
- package/dist/lib/gitignore.js.map +1 -0
- package/dist/lib/guardrails.d.ts +232 -0
- package/dist/lib/guardrails.d.ts.map +1 -0
- package/dist/lib/guardrails.js +323 -0
- package/dist/lib/guardrails.js.map +1 -0
- package/dist/lib/history.d.ts +110 -0
- package/dist/lib/history.d.ts.map +1 -0
- package/dist/lib/history.js +236 -0
- package/dist/lib/history.js.map +1 -0
- package/dist/lib/index.d.ts +29 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +29 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/json-extract.d.ts +42 -0
- package/dist/lib/json-extract.d.ts.map +1 -0
- package/dist/lib/json-extract.js +201 -0
- package/dist/lib/json-extract.js.map +1 -0
- package/dist/lib/judge.d.ts +237 -0
- package/dist/lib/judge.d.ts.map +1 -0
- package/dist/lib/judge.js +501 -0
- package/dist/lib/judge.js.map +1 -0
- package/dist/lib/lock.d.ts +79 -0
- package/dist/lib/lock.d.ts.map +1 -0
- package/dist/lib/lock.js +254 -0
- package/dist/lib/lock.js.map +1 -0
- package/dist/lib/migration.d.ts +9 -0
- package/dist/lib/migration.d.ts.map +1 -0
- package/dist/lib/migration.js +74 -0
- package/dist/lib/migration.js.map +1 -0
- package/dist/lib/paths.d.ts +18 -0
- package/dist/lib/paths.d.ts.map +1 -0
- package/dist/lib/paths.js +27 -0
- package/dist/lib/paths.js.map +1 -0
- package/dist/lib/preflight.d.ts +33 -0
- package/dist/lib/preflight.d.ts.map +1 -0
- package/dist/lib/preflight.js +177 -0
- package/dist/lib/preflight.js.map +1 -0
- package/dist/lib/prompt_budget.d.ts +18 -0
- package/dist/lib/prompt_budget.d.ts.map +1 -0
- package/dist/lib/prompt_budget.js +36 -0
- package/dist/lib/prompt_budget.js.map +1 -0
- package/dist/lib/report.d.ts +102 -0
- package/dist/lib/report.d.ts.map +1 -0
- package/dist/lib/report.js +347 -0
- package/dist/lib/report.js.map +1 -0
- package/dist/lib/reviewer-flow.d.ts +80 -0
- package/dist/lib/reviewer-flow.d.ts.map +1 -0
- package/dist/lib/reviewer-flow.js +138 -0
- package/dist/lib/reviewer-flow.js.map +1 -0
- package/dist/lib/reviewer.d.ts +53 -0
- package/dist/lib/reviewer.d.ts.map +1 -0
- package/dist/lib/reviewer.js +199 -0
- package/dist/lib/reviewer.js.map +1 -0
- package/dist/lib/risk.d.ts +127 -0
- package/dist/lib/risk.d.ts.map +1 -0
- package/dist/lib/risk.js +192 -0
- package/dist/lib/risk.js.map +1 -0
- package/dist/lib/rollback.d.ts +143 -0
- package/dist/lib/rollback.d.ts.map +1 -0
- package/dist/lib/rollback.js +244 -0
- package/dist/lib/rollback.js.map +1 -0
- package/dist/lib/schema.d.ts +47 -0
- package/dist/lib/schema.d.ts.map +1 -0
- package/dist/lib/schema.js +91 -0
- package/dist/lib/schema.js.map +1 -0
- package/dist/lib/scope.d.ts +89 -0
- package/dist/lib/scope.d.ts.map +1 -0
- package/dist/lib/scope.js +135 -0
- package/dist/lib/scope.js.map +1 -0
- package/dist/lib/self_update.d.ts +13 -0
- package/dist/lib/self_update.d.ts.map +1 -0
- package/dist/lib/self_update.js +172 -0
- package/dist/lib/self_update.js.map +1 -0
- package/dist/lib/state.d.ts +143 -0
- package/dist/lib/state.d.ts.map +1 -0
- package/dist/lib/state.js +258 -0
- package/dist/lib/state.js.map +1 -0
- package/dist/lib/tick.d.ts +310 -0
- package/dist/lib/tick.d.ts.map +1 -0
- package/dist/lib/tick.js +424 -0
- package/dist/lib/tick.js.map +1 -0
- package/dist/lib/transport.d.ts +145 -0
- package/dist/lib/transport.d.ts.map +1 -0
- package/dist/lib/transport.js +237 -0
- package/dist/lib/transport.js.map +1 -0
- package/dist/lib/verdict_labels.d.ts +5 -0
- package/dist/lib/verdict_labels.d.ts.map +1 -0
- package/dist/lib/verdict_labels.js +25 -0
- package/dist/lib/verdict_labels.js.map +1 -0
- package/dist/lib/verify-safety.d.ts +63 -0
- package/dist/lib/verify-safety.d.ts.map +1 -0
- package/dist/lib/verify-safety.js +123 -0
- package/dist/lib/verify-safety.js.map +1 -0
- package/dist/lib/verify.d.ts +139 -0
- package/dist/lib/verify.d.ts.map +1 -0
- package/dist/lib/verify.js +311 -0
- package/dist/lib/verify.js.map +1 -0
- package/dist/lib/workspace_state.d.ts +79 -0
- package/dist/lib/workspace_state.d.ts.map +1 -0
- package/dist/lib/workspace_state.js +283 -0
- package/dist/lib/workspace_state.js.map +1 -0
- package/dist/runner/builder.d.ts +58 -0
- package/dist/runner/builder.d.ts.map +1 -0
- package/dist/runner/builder.js +775 -0
- package/dist/runner/builder.js.map +1 -0
- package/dist/runner/builder_parse.d.ts +37 -0
- package/dist/runner/builder_parse.d.ts.map +1 -0
- package/dist/runner/builder_parse.js +76 -0
- package/dist/runner/builder_parse.js.map +1 -0
- package/dist/runner/index.d.ts +9 -0
- package/dist/runner/index.d.ts.map +1 -0
- package/dist/runner/index.js +7 -0
- package/dist/runner/index.js.map +1 -0
- package/dist/runner/loop.d.ts +51 -0
- package/dist/runner/loop.d.ts.map +1 -0
- package/dist/runner/loop.js +221 -0
- package/dist/runner/loop.js.map +1 -0
- package/dist/runner/orchestrator.d.ts +67 -0
- package/dist/runner/orchestrator.d.ts.map +1 -0
- package/dist/runner/orchestrator.js +376 -0
- package/dist/runner/orchestrator.js.map +1 -0
- package/dist/runner/tick.d.ts +10 -0
- package/dist/runner/tick.d.ts.map +1 -0
- package/dist/runner/tick.js +1639 -0
- package/dist/runner/tick.js.map +1 -0
- package/dist/types/blocked.d.ts +52 -0
- package/dist/types/blocked.d.ts.map +1 -0
- package/dist/types/blocked.js +8 -0
- package/dist/types/blocked.js.map +1 -0
- package/dist/types/builder.d.ts +25 -0
- package/dist/types/builder.d.ts.map +1 -0
- package/dist/types/builder.js +7 -0
- package/dist/types/builder.js.map +1 -0
- package/dist/types/claude.d.ts +86 -0
- package/dist/types/claude.d.ts.map +1 -0
- package/dist/types/claude.js +48 -0
- package/dist/types/claude.js.map +1 -0
- package/dist/types/config.d.ts +384 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +7 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/index.d.ts +18 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +8 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/lock.d.ts +21 -0
- package/dist/types/lock.d.ts.map +1 -0
- package/dist/types/lock.js +8 -0
- package/dist/types/lock.js.map +1 -0
- package/dist/types/preflight.d.ts +49 -0
- package/dist/types/preflight.d.ts.map +1 -0
- package/dist/types/preflight.js +8 -0
- package/dist/types/preflight.js.map +1 -0
- package/dist/types/report.d.ts +161 -0
- package/dist/types/report.d.ts.map +1 -0
- package/dist/types/report.js +8 -0
- package/dist/types/report.js.map +1 -0
- package/dist/types/reviewer.d.ts +66 -0
- package/dist/types/reviewer.d.ts.map +1 -0
- package/dist/types/reviewer.js +5 -0
- package/dist/types/reviewer.js.map +1 -0
- package/dist/types/state.d.ts +124 -0
- package/dist/types/state.d.ts.map +1 -0
- package/dist/types/state.js +20 -0
- package/dist/types/state.js.map +1 -0
- package/dist/types/task.d.ts +117 -0
- package/dist/types/task.d.ts.map +1 -0
- package/dist/types/task.js +7 -0
- package/dist/types/task.js.map +1 -0
- package/dist/types/workspace_state.d.ts +125 -0
- package/dist/types/workspace_state.d.ts.map +1 -0
- package/dist/types/workspace_state.js +10 -0
- package/dist/types/workspace_state.js.map +1 -0
- package/envoi.config.json +191 -0
- package/package.json +52 -0
- package/relais/prompts/.gitkeep +0 -0
- package/relais/prompts/builder.system.txt +13 -0
- package/relais/prompts/builder.user.txt +15 -0
- package/relais/prompts/orchestrator.system.txt +37 -0
- package/relais/prompts/orchestrator.user.txt +34 -0
- package/relais/prompts/reviewer.system.txt +33 -0
- package/relais/prompts/reviewer.user.txt +35 -0
- package/relais/schemas/.gitkeep +0 -0
- package/relais/schemas/builder_result.schema.json +29 -0
- package/relais/schemas/report.schema.json +195 -0
- package/relais/schemas/reviewer_result.schema.json +70 -0
- package/relais/schemas/task.schema.json +155 -0
package/dist/lib/risk.js
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Risk scoring and reviewer trigger logic.
|
|
3
|
+
*
|
|
4
|
+
* Determines when the reviewer should be invoked based on deterministic
|
|
5
|
+
* risk signals: high-risk file paths, diff fraction thresholds, repeated
|
|
6
|
+
* stops, verification failures, and budget warnings.
|
|
7
|
+
*/
|
|
8
|
+
import micromatch from 'micromatch';
|
|
9
|
+
/**
|
|
10
|
+
* Checks if any paths match high-risk glob patterns.
|
|
11
|
+
*
|
|
12
|
+
* Uses micromatch to check paths against high_risk_globs patterns.
|
|
13
|
+
*
|
|
14
|
+
* @param paths - Array of file paths to check
|
|
15
|
+
* @param highRiskGlobs - Array of glob patterns for high-risk files
|
|
16
|
+
* @returns Array of paths that match high-risk patterns
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* const riskyPaths = checkHighRiskGlobs(
|
|
20
|
+
* ['src/auth.ts', 'src/utils.ts'],
|
|
21
|
+
* ['src/auth*.ts', 'src/*secret*']
|
|
22
|
+
* );
|
|
23
|
+
*/
|
|
24
|
+
export function checkHighRiskGlobs(paths, highRiskGlobs) {
|
|
25
|
+
if (highRiskGlobs.length === 0) {
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
// Check if any paths match high-risk globs
|
|
29
|
+
return paths.filter((path) => micromatch.isMatch(path, highRiskGlobs));
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Checks if diff fraction exceeds threshold.
|
|
33
|
+
*
|
|
34
|
+
* Calculates files_touched/max_files_touched or lines_changed/max_lines_changed
|
|
35
|
+
* and checks if either fraction >= threshold.
|
|
36
|
+
*
|
|
37
|
+
* @param analysis - Diff analysis result
|
|
38
|
+
* @param limits - Diff limits from task
|
|
39
|
+
* @param threshold - Fraction threshold (0.0 to 1.0)
|
|
40
|
+
* @returns True if diff fraction >= threshold
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* const analysis = { files_touched: 8, lines_changed: 300, ... };
|
|
44
|
+
* const limits = { max_files_touched: 10, max_lines_changed: 400 };
|
|
45
|
+
* const nearCap = checkDiffFraction(analysis, limits, 0.8);
|
|
46
|
+
*/
|
|
47
|
+
export function checkDiffFraction(analysis, limits, threshold) {
|
|
48
|
+
if (threshold <= 0) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
const lines_changed = analysis.lines_added + analysis.lines_deleted;
|
|
52
|
+
// Calculate fractions
|
|
53
|
+
const filesFraction = limits.max_files_touched > 0
|
|
54
|
+
? analysis.files_touched / limits.max_files_touched
|
|
55
|
+
: 0;
|
|
56
|
+
const linesFraction = limits.max_lines_changed > 0 ? lines_changed / limits.max_lines_changed : 0;
|
|
57
|
+
// Check if either fraction exceeds threshold
|
|
58
|
+
return filesFraction >= threshold || linesFraction >= threshold;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Checks if there are repeated stops within a time window.
|
|
62
|
+
*
|
|
63
|
+
* Counts STOP verdicts in stop_history within the specified window
|
|
64
|
+
* and checks if count >= maxStops.
|
|
65
|
+
*
|
|
66
|
+
* @param stopHistory - Array of stop history entries
|
|
67
|
+
* @param window - Time window in ticks
|
|
68
|
+
* @param maxStops - Maximum number of stops allowed in window
|
|
69
|
+
* @param currentTick - Current tick number
|
|
70
|
+
* @returns True if repeated stops detected
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* const history = [
|
|
74
|
+
* { tick: 5, verdict: 'stop' },
|
|
75
|
+
* { tick: 8, verdict: 'stop' },
|
|
76
|
+
* { tick: 12, verdict: 'stop' }
|
|
77
|
+
* ];
|
|
78
|
+
* const repeated = checkRepeatedStops(history, 10, 2, 12);
|
|
79
|
+
*/
|
|
80
|
+
export function checkRepeatedStops(stopHistory, window, maxStops, currentTick) {
|
|
81
|
+
if (window <= 0 || maxStops <= 0) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
// Filter stops within the window (from currentTick - window to currentTick)
|
|
85
|
+
const windowStart = Math.max(0, currentTick - window);
|
|
86
|
+
const stopsInWindow = stopHistory.filter((entry) => entry.verdict === 'stop' && entry.tick >= windowStart && entry.tick <= currentTick);
|
|
87
|
+
return stopsInWindow.length >= maxStops;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Computes risk flags based on various risk signals.
|
|
91
|
+
*
|
|
92
|
+
* Returns an array of risk flag strings indicating which risk conditions
|
|
93
|
+
* have been triggered.
|
|
94
|
+
*
|
|
95
|
+
* @param params - Parameters for risk computation
|
|
96
|
+
* @param params.analysis - Diff analysis result
|
|
97
|
+
* @param params.limits - Diff limits from task
|
|
98
|
+
* @param params.scope - Task scope configuration
|
|
99
|
+
* @param params.trigger - Reviewer trigger configuration
|
|
100
|
+
* @param params.stopHistory - Array of stop history entries
|
|
101
|
+
* @param params.currentTick - Current tick number
|
|
102
|
+
* @param params.verifyFailed - Whether verification failed
|
|
103
|
+
* @param params.budgetWarning - Whether budget warning threshold reached
|
|
104
|
+
* @returns Array of risk flag strings
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* const flags = computeRiskFlags({
|
|
108
|
+
* analysis,
|
|
109
|
+
* limits,
|
|
110
|
+
* scope,
|
|
111
|
+
* trigger,
|
|
112
|
+
* stopHistory: [],
|
|
113
|
+
* currentTick: 10,
|
|
114
|
+
* verifyFailed: false,
|
|
115
|
+
* budgetWarning: false
|
|
116
|
+
* });
|
|
117
|
+
*/
|
|
118
|
+
export function computeRiskFlags(params) {
|
|
119
|
+
const { analysis, limits, scope, trigger, stopHistory, currentTick, verifyFailed, budgetWarning, } = params;
|
|
120
|
+
const flags = [];
|
|
121
|
+
// Check high-risk paths
|
|
122
|
+
if (trigger.on_high_risk_paths && trigger.high_risk_globs.length > 0) {
|
|
123
|
+
const riskyPaths = checkHighRiskGlobs(analysis.touched_paths, trigger.high_risk_globs);
|
|
124
|
+
if (riskyPaths.length > 0) {
|
|
125
|
+
flags.push('high_risk_path');
|
|
126
|
+
}
|
|
127
|
+
// Also check if allowed_globs overlap with high_risk_globs (pattern-level check)
|
|
128
|
+
// This is mentioned in the PRD as a risk trigger
|
|
129
|
+
const hasOverlap = scope.allowed_globs.some((allowedGlob) => trigger.high_risk_globs.some((riskGlob) => {
|
|
130
|
+
// Check if patterns overlap by testing if they could match similar paths
|
|
131
|
+
// Simple heuristic: check if one pattern could match the other
|
|
132
|
+
try {
|
|
133
|
+
return micromatch.isMatch(allowedGlob, [riskGlob]) ||
|
|
134
|
+
micromatch.isMatch(riskGlob, [allowedGlob]);
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
// If pattern matching fails, skip this comparison
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
}));
|
|
141
|
+
if (hasOverlap && riskyPaths.length === 0) {
|
|
142
|
+
// Pattern overlap detected even if no paths match yet
|
|
143
|
+
flags.push('high_risk_path');
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// Check diff fraction threshold
|
|
147
|
+
if (trigger.diff_fraction_threshold > 0) {
|
|
148
|
+
const nearCap = checkDiffFraction(analysis, limits, trigger.diff_fraction_threshold);
|
|
149
|
+
if (nearCap) {
|
|
150
|
+
flags.push('diff_near_cap');
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Check verification failure
|
|
154
|
+
if (trigger.on_verify_fail && verifyFailed) {
|
|
155
|
+
flags.push('verify_failed');
|
|
156
|
+
}
|
|
157
|
+
// Check repeated stops
|
|
158
|
+
if (trigger.on_repeated_stop &&
|
|
159
|
+
trigger.stop_window_ticks > 0 &&
|
|
160
|
+
trigger.max_stops_in_window > 0) {
|
|
161
|
+
const repeated = checkRepeatedStops(stopHistory, trigger.stop_window_ticks, trigger.max_stops_in_window, currentTick);
|
|
162
|
+
if (repeated) {
|
|
163
|
+
flags.push('repeated_stop');
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// Check budget warning
|
|
167
|
+
if (budgetWarning) {
|
|
168
|
+
flags.push('budget_warning');
|
|
169
|
+
}
|
|
170
|
+
return flags;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Determines if reviewer should be triggered based on risk flags and config.
|
|
174
|
+
*
|
|
175
|
+
* Returns true if reviewer is enabled and any trigger condition is met.
|
|
176
|
+
*
|
|
177
|
+
* @param config - Reviewer configuration
|
|
178
|
+
* @param riskFlags - Array of risk flags from computeRiskFlags
|
|
179
|
+
* @returns True if reviewer should be triggered
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* const shouldTrigger = shouldTriggerReviewer(config, ['high_risk_path', 'diff_near_cap']);
|
|
183
|
+
*/
|
|
184
|
+
export function shouldTriggerReviewer(config, riskFlags) {
|
|
185
|
+
// Reviewer must be enabled
|
|
186
|
+
if (!config.enabled) {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
// At least one risk flag must be present
|
|
190
|
+
return riskFlags.length > 0;
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=risk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"risk.js","sourceRoot":"","sources":["../../src/lib/risk.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rollback utilities to restore repository to base_commit state.
|
|
3
|
+
*
|
|
4
|
+
* Used when Judge detects violations (scope, diff limits, etc.) to reset
|
|
5
|
+
* tracked files and remove only the untracked files that were touched by the builder.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Result of a rollback operation.
|
|
9
|
+
*/
|
|
10
|
+
export interface RollbackResult {
|
|
11
|
+
/**
|
|
12
|
+
* True if rollback completed successfully.
|
|
13
|
+
*/
|
|
14
|
+
success: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Whether git reset succeeded.
|
|
17
|
+
*/
|
|
18
|
+
tracked_reset: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Untracked paths that were removed.
|
|
21
|
+
*/
|
|
22
|
+
paths_removed: string[];
|
|
23
|
+
/**
|
|
24
|
+
* Any errors encountered during rollback.
|
|
25
|
+
*/
|
|
26
|
+
errors: string[];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Result of a rollback operation (new format for STOP code handling).
|
|
30
|
+
*/
|
|
31
|
+
export interface RollbackResultNew {
|
|
32
|
+
/**
|
|
33
|
+
* True if rollback completed successfully.
|
|
34
|
+
*/
|
|
35
|
+
ok: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* The commit SHA that was restored to.
|
|
38
|
+
*/
|
|
39
|
+
restoredCommit: string;
|
|
40
|
+
/**
|
|
41
|
+
* Files that were removed during rollback.
|
|
42
|
+
*/
|
|
43
|
+
removedFiles: string[];
|
|
44
|
+
/**
|
|
45
|
+
* Error message if rollback failed, null otherwise.
|
|
46
|
+
*/
|
|
47
|
+
error: string | null;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Resets tracked files to a specific base commit using git reset --hard.
|
|
51
|
+
*
|
|
52
|
+
* @param baseCommit - The commit SHA to reset to
|
|
53
|
+
* @returns Object indicating success and any errors
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* const result = rollbackTracked('abc123');
|
|
58
|
+
* if (!result.tracked_reset) {
|
|
59
|
+
* console.error('Failed to reset tracked files');
|
|
60
|
+
* }
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export declare function rollbackTracked(baseCommit: string): {
|
|
64
|
+
tracked_reset: boolean;
|
|
65
|
+
errors: string[];
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Removes specific untracked files and directories.
|
|
69
|
+
*
|
|
70
|
+
* Handles errors gracefully (file already removed, permission issues, etc.)
|
|
71
|
+
* and continues removing other paths even if some fail.
|
|
72
|
+
*
|
|
73
|
+
* @param paths - Array of file or directory paths to remove
|
|
74
|
+
* @returns Object with list of successfully removed paths and any errors
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* const result = await removeUntrackedPaths(['temp.txt', 'build/']);
|
|
79
|
+
* console.log(`Removed ${result.paths_removed.length} paths`);
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export declare function removeUntrackedPaths(paths: string[]): Promise<{
|
|
83
|
+
paths_removed: string[];
|
|
84
|
+
errors: string[];
|
|
85
|
+
}>;
|
|
86
|
+
/**
|
|
87
|
+
* Performs a full rollback operation: resets tracked files to base_commit
|
|
88
|
+
* and removes specified untracked paths.
|
|
89
|
+
*
|
|
90
|
+
* @param baseCommit - The commit SHA to reset tracked files to
|
|
91
|
+
* @param untrackedPaths - Array of untracked file/directory paths to remove
|
|
92
|
+
* @returns RollbackResult with complete status of the operation
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```typescript
|
|
96
|
+
* const result = await rollback('abc123', ['temp.txt', 'build/']);
|
|
97
|
+
* if (result.success) {
|
|
98
|
+
* console.log('Rollback completed successfully');
|
|
99
|
+
* }
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export declare function rollback(baseCommit: string, untrackedPaths: string[]): Promise<RollbackResult>;
|
|
103
|
+
/**
|
|
104
|
+
* Resets to base commit and removes untracked files created by builder.
|
|
105
|
+
*
|
|
106
|
+
* This is the synchronous version used for STOP code handling.
|
|
107
|
+
* It resets tracked files to the base commit and removes specified untracked files.
|
|
108
|
+
*
|
|
109
|
+
* @param baseCommit - The commit SHA to reset to
|
|
110
|
+
* @param untrackedToRemove - Optional array of untracked file/directory paths to remove
|
|
111
|
+
* @returns RollbackResultNew with success status and details
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```typescript
|
|
115
|
+
* const result = rollbackToCommit('abc123', ['temp.txt', 'build/']);
|
|
116
|
+
* if (result.ok) {
|
|
117
|
+
* console.log(`Rolled back to ${result.restoredCommit}`);
|
|
118
|
+
* console.log(`Removed ${result.removedFiles.length} files`);
|
|
119
|
+
* } else {
|
|
120
|
+
* console.error(`Rollback failed: ${result.error}`);
|
|
121
|
+
* }
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
export declare function rollbackToCommit(baseCommit: string, untrackedToRemove?: string[]): RollbackResultNew;
|
|
125
|
+
/**
|
|
126
|
+
* Verifies that the git worktree is clean.
|
|
127
|
+
*
|
|
128
|
+
* Uses `git diff --exit-code` to check for uncommitted tracked changes.
|
|
129
|
+
* Also checks that there are no untracked files (via git status --porcelain).
|
|
130
|
+
*
|
|
131
|
+
* @returns true if worktree is clean (no uncommitted changes and no untracked files), false otherwise
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```typescript
|
|
135
|
+
* if (verifyCleanWorktree()) {
|
|
136
|
+
* console.log('Worktree is clean');
|
|
137
|
+
* } else {
|
|
138
|
+
* console.log('Worktree has uncommitted changes');
|
|
139
|
+
* }
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
export declare function verifyCleanWorktree(): boolean;
|
|
143
|
+
//# sourceMappingURL=rollback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rollback.d.ts","sourceRoot":"","sources":["../../src/lib/rollback.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,aAAa,EAAE,OAAO,CAAC;IAEvB;;OAEG;IACH,aAAa,EAAE,MAAM,EAAE,CAAC;IAExB;;OAEG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,EAAE,EAAE,OAAO,CAAC;IAEZ;;OAEG;IACH,cAAc,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,YAAY,EAAE,MAAM,EAAE,CAAC;IAEvB;;OAEG;IACH,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG;IACnD,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAgBA;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IACnE,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC,CAqCD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,QAAQ,CAC5B,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,EAAE,GACvB,OAAO,CAAC,cAAc,CAAC,CAqBzB;AA8CD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,EAClB,iBAAiB,GAAE,MAAM,EAAO,GAC/B,iBAAiB,CAkCnB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAqB7C"}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rollback utilities to restore repository to base_commit state.
|
|
3
|
+
*
|
|
4
|
+
* Used when Judge detects violations (scope, diff limits, etc.) to reset
|
|
5
|
+
* tracked files and remove only the untracked files that were touched by the builder.
|
|
6
|
+
*/
|
|
7
|
+
import { execSync } from 'node:child_process';
|
|
8
|
+
import { unlink, rm } from 'node:fs/promises';
|
|
9
|
+
import { stat } from 'node:fs/promises';
|
|
10
|
+
import { unlinkSync, rmSync, statSync } from 'node:fs';
|
|
11
|
+
/**
|
|
12
|
+
* Resets tracked files to a specific base commit using git reset --hard.
|
|
13
|
+
*
|
|
14
|
+
* @param baseCommit - The commit SHA to reset to
|
|
15
|
+
* @returns Object indicating success and any errors
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const result = rollbackTracked('abc123');
|
|
20
|
+
* if (!result.tracked_reset) {
|
|
21
|
+
* console.error('Failed to reset tracked files');
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export function rollbackTracked(baseCommit) {
|
|
26
|
+
const errors = [];
|
|
27
|
+
try {
|
|
28
|
+
execSync(`git reset --hard ${baseCommit}`, {
|
|
29
|
+
encoding: 'utf-8',
|
|
30
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
31
|
+
});
|
|
32
|
+
return { tracked_reset: true, errors: [] };
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
const errorMsg = `Failed to reset tracked files to ${baseCommit}: ${error instanceof Error ? error.message : String(error)}`;
|
|
36
|
+
errors.push(errorMsg);
|
|
37
|
+
return { tracked_reset: false, errors };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Removes specific untracked files and directories.
|
|
42
|
+
*
|
|
43
|
+
* Handles errors gracefully (file already removed, permission issues, etc.)
|
|
44
|
+
* and continues removing other paths even if some fail.
|
|
45
|
+
*
|
|
46
|
+
* @param paths - Array of file or directory paths to remove
|
|
47
|
+
* @returns Object with list of successfully removed paths and any errors
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const result = await removeUntrackedPaths(['temp.txt', 'build/']);
|
|
52
|
+
* console.log(`Removed ${result.paths_removed.length} paths`);
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export async function removeUntrackedPaths(paths) {
|
|
56
|
+
const paths_removed = [];
|
|
57
|
+
const errors = [];
|
|
58
|
+
for (const path of paths) {
|
|
59
|
+
try {
|
|
60
|
+
// Check if path exists and is a directory
|
|
61
|
+
const stats = await stat(path);
|
|
62
|
+
const isDirectory = stats.isDirectory();
|
|
63
|
+
if (isDirectory) {
|
|
64
|
+
// Use rm with recursive for directories
|
|
65
|
+
await rm(path, { recursive: true, force: true });
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
// Use unlink for files
|
|
69
|
+
await unlink(path);
|
|
70
|
+
}
|
|
71
|
+
paths_removed.push(path);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
// Handle errors gracefully - file may already be removed, permission issues, etc.
|
|
75
|
+
const errorMsg = `Failed to remove ${path}: ${error instanceof Error ? error.message : String(error)}`;
|
|
76
|
+
// Check if it's a "file not found" error (ENOENT) - this is acceptable
|
|
77
|
+
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
|
|
78
|
+
// File/directory doesn't exist - consider it already removed, but don't add to paths_removed
|
|
79
|
+
// since we didn't actually remove it
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
errors.push(errorMsg);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return { paths_removed, errors };
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Performs a full rollback operation: resets tracked files to base_commit
|
|
89
|
+
* and removes specified untracked paths.
|
|
90
|
+
*
|
|
91
|
+
* @param baseCommit - The commit SHA to reset tracked files to
|
|
92
|
+
* @param untrackedPaths - Array of untracked file/directory paths to remove
|
|
93
|
+
* @returns RollbackResult with complete status of the operation
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```typescript
|
|
97
|
+
* const result = await rollback('abc123', ['temp.txt', 'build/']);
|
|
98
|
+
* if (result.success) {
|
|
99
|
+
* console.log('Rollback completed successfully');
|
|
100
|
+
* }
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export async function rollback(baseCommit, untrackedPaths) {
|
|
104
|
+
const errors = [];
|
|
105
|
+
// Step 1: Reset tracked files
|
|
106
|
+
const trackedResult = rollbackTracked(baseCommit);
|
|
107
|
+
errors.push(...trackedResult.errors);
|
|
108
|
+
// Step 2: Remove untracked paths
|
|
109
|
+
const untrackedResult = await removeUntrackedPaths(untrackedPaths);
|
|
110
|
+
errors.push(...untrackedResult.errors);
|
|
111
|
+
// Rollback is considered successful if tracked files were reset
|
|
112
|
+
// (untracked removal errors are less critical)
|
|
113
|
+
const success = trackedResult.tracked_reset && errors.length === 0;
|
|
114
|
+
return {
|
|
115
|
+
success,
|
|
116
|
+
tracked_reset: trackedResult.tracked_reset,
|
|
117
|
+
paths_removed: untrackedResult.paths_removed,
|
|
118
|
+
errors,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Synchronous version of removeUntrackedPaths for use in rollbackToCommit.
|
|
123
|
+
*/
|
|
124
|
+
function removeUntrackedPathsSync(paths) {
|
|
125
|
+
const paths_removed = [];
|
|
126
|
+
const errors = [];
|
|
127
|
+
for (const path of paths) {
|
|
128
|
+
try {
|
|
129
|
+
// Check if path exists and is a directory
|
|
130
|
+
const stats = statSync(path);
|
|
131
|
+
const isDirectory = stats.isDirectory();
|
|
132
|
+
if (isDirectory) {
|
|
133
|
+
// Use rmSync with recursive for directories
|
|
134
|
+
rmSync(path, { recursive: true, force: true });
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
// Use unlinkSync for files
|
|
138
|
+
unlinkSync(path);
|
|
139
|
+
}
|
|
140
|
+
paths_removed.push(path);
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
// Handle errors gracefully - file may already be removed, permission issues, etc.
|
|
144
|
+
const errorMsg = `Failed to remove ${path}: ${error instanceof Error ? error.message : String(error)}`;
|
|
145
|
+
// Check if it's a "file not found" error (ENOENT) - this is acceptable
|
|
146
|
+
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
|
|
147
|
+
// File/directory doesn't exist - consider it already removed
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
errors.push(errorMsg);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return { paths_removed, errors };
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Resets to base commit and removes untracked files created by builder.
|
|
157
|
+
*
|
|
158
|
+
* This is the synchronous version used for STOP code handling.
|
|
159
|
+
* It resets tracked files to the base commit and removes specified untracked files.
|
|
160
|
+
*
|
|
161
|
+
* @param baseCommit - The commit SHA to reset to
|
|
162
|
+
* @param untrackedToRemove - Optional array of untracked file/directory paths to remove
|
|
163
|
+
* @returns RollbackResultNew with success status and details
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* ```typescript
|
|
167
|
+
* const result = rollbackToCommit('abc123', ['temp.txt', 'build/']);
|
|
168
|
+
* if (result.ok) {
|
|
169
|
+
* console.log(`Rolled back to ${result.restoredCommit}`);
|
|
170
|
+
* console.log(`Removed ${result.removedFiles.length} files`);
|
|
171
|
+
* } else {
|
|
172
|
+
* console.error(`Rollback failed: ${result.error}`);
|
|
173
|
+
* }
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
export function rollbackToCommit(baseCommit, untrackedToRemove = []) {
|
|
177
|
+
try {
|
|
178
|
+
// Step 1: Reset tracked files
|
|
179
|
+
execSync(`git reset --hard ${baseCommit}`, {
|
|
180
|
+
encoding: 'utf-8',
|
|
181
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
182
|
+
});
|
|
183
|
+
// Step 2: Remove untracked files
|
|
184
|
+
const untrackedResult = removeUntrackedPathsSync(untrackedToRemove);
|
|
185
|
+
// If there were errors removing untracked files, still consider it successful
|
|
186
|
+
// as long as git reset succeeded (untracked removal errors are less critical)
|
|
187
|
+
const ok = untrackedResult.errors.length === 0;
|
|
188
|
+
const error = untrackedResult.errors.length > 0 ? untrackedResult.errors.join('; ') : null;
|
|
189
|
+
return {
|
|
190
|
+
ok,
|
|
191
|
+
restoredCommit: baseCommit,
|
|
192
|
+
removedFiles: untrackedResult.paths_removed,
|
|
193
|
+
error,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
const errorMsg = `Failed to rollback to ${baseCommit}: ${error instanceof Error ? error.message : String(error)}`;
|
|
198
|
+
return {
|
|
199
|
+
ok: false,
|
|
200
|
+
restoredCommit: baseCommit,
|
|
201
|
+
removedFiles: [],
|
|
202
|
+
error: errorMsg,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Verifies that the git worktree is clean.
|
|
208
|
+
*
|
|
209
|
+
* Uses `git diff --exit-code` to check for uncommitted tracked changes.
|
|
210
|
+
* Also checks that there are no untracked files (via git status --porcelain).
|
|
211
|
+
*
|
|
212
|
+
* @returns true if worktree is clean (no uncommitted changes and no untracked files), false otherwise
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* ```typescript
|
|
216
|
+
* if (verifyCleanWorktree()) {
|
|
217
|
+
* console.log('Worktree is clean');
|
|
218
|
+
* } else {
|
|
219
|
+
* console.log('Worktree has uncommitted changes');
|
|
220
|
+
* }
|
|
221
|
+
* ```
|
|
222
|
+
*/
|
|
223
|
+
export function verifyCleanWorktree() {
|
|
224
|
+
try {
|
|
225
|
+
// Check for uncommitted tracked changes
|
|
226
|
+
execSync('git diff --exit-code', {
|
|
227
|
+
encoding: 'utf-8',
|
|
228
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
229
|
+
});
|
|
230
|
+
// Check for untracked files
|
|
231
|
+
const status = execSync('git status --porcelain', {
|
|
232
|
+
encoding: 'utf-8',
|
|
233
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
234
|
+
});
|
|
235
|
+
// Worktree is clean if status is empty (no uncommitted changes and no untracked files)
|
|
236
|
+
return status.trim() === '';
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
// git diff --exit-code exits with non-zero if there are changes
|
|
240
|
+
// git status might fail in some edge cases
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
//# sourceMappingURL=rollback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rollback.js","sourceRoot":"","sources":["../../src/lib/rollback.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAoDvD;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,eAAe,CAAC,UAAkB;IAIhD,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,IAAI,CAAC;QACH,QAAQ,CAAC,oBAAoB,UAAU,EAAE,EAAE;YACzC,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC,CAAC;QACH,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IAC7C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,QAAQ,GAAG,oCAAoC,UAAU,KAC7D,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CACvD,EAAE,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtB,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAC1C,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,KAAe;IAIxD,MAAM,aAAa,GAAa,EAAE,CAAC;IACnC,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,0CAA0C;YAC1C,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/B,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;YAExC,IAAI,WAAW,EAAE,CAAC;gBAChB,wCAAwC;gBACxC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACnD,CAAC;iBAAM,CAAC;gBACN,uBAAuB;gBACvB,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;YACrB,CAAC;YAED,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,kFAAkF;YAClF,MAAM,QAAQ,GAAG,oBAAoB,IAAI,KACvC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CACvD,EAAE,CAAC;YAEH,uEAAuE;YACvE,IAAI,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACzE,6FAA6F;gBAC7F,qCAAqC;gBACrC,SAAS;YACX,CAAC;YAED,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC;AACnC,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,UAAkB,EAClB,cAAwB;IAExB,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,8BAA8B;IAC9B,MAAM,aAAa,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;IAClD,MAAM,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IAErC,iCAAiC;IACjC,MAAM,eAAe,GAAG,MAAM,oBAAoB,CAAC,cAAc,CAAC,CAAC;IACnE,MAAM,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAEvC,gEAAgE;IAChE,+CAA+C;IAC/C,MAAM,OAAO,GAAG,aAAa,CAAC,aAAa,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC;IAEnE,OAAO;QACL,OAAO;QACP,aAAa,EAAE,aAAa,CAAC,aAAa;QAC1C,aAAa,EAAE,eAAe,CAAC,aAAa;QAC5C,MAAM;KACP,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,wBAAwB,CAAC,KAAe;IAI/C,MAAM,aAAa,GAAa,EAAE,CAAC;IACnC,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,0CAA0C;YAC1C,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC7B,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;YAExC,IAAI,WAAW,EAAE,CAAC;gBAChB,4CAA4C;gBAC5C,MAAM,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACjD,CAAC;iBAAM,CAAC;gBACN,2BAA2B;gBAC3B,UAAU,CAAC,IAAI,CAAC,CAAC;YACnB,CAAC;YAED,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,kFAAkF;YAClF,MAAM,QAAQ,GAAG,oBAAoB,IAAI,KACvC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CACvD,EAAE,CAAC;YAEH,uEAAuE;YACvE,IAAI,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACzE,6DAA6D;gBAC7D,SAAS;YACX,CAAC;YAED,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC;AACnC,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,gBAAgB,CAC9B,UAAkB,EAClB,oBAA8B,EAAE;IAEhC,IAAI,CAAC;QACH,8BAA8B;QAC9B,QAAQ,CAAC,oBAAoB,UAAU,EAAE,EAAE;YACzC,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC,CAAC;QAEH,iCAAiC;QACjC,MAAM,eAAe,GAAG,wBAAwB,CAAC,iBAAiB,CAAC,CAAC;QAEpE,8EAA8E;QAC9E,8EAA8E;QAC9E,MAAM,EAAE,GAAG,eAAe,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC;QAC/C,MAAM,KAAK,GAAG,eAAe,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAE3F,OAAO;YACL,EAAE;YACF,cAAc,EAAE,UAAU;YAC1B,YAAY,EAAE,eAAe,CAAC,aAAa;YAC3C,KAAK;SACN,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,QAAQ,GAAG,yBAAyB,UAAU,KAClD,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CACvD,EAAE,CAAC;QAEH,OAAO;YACL,EAAE,EAAE,KAAK;YACT,cAAc,EAAE,UAAU;YAC1B,YAAY,EAAE,EAAE;YAChB,KAAK,EAAE,QAAQ;SAChB,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,mBAAmB;IACjC,IAAI,CAAC;QACH,wCAAwC;QACxC,QAAQ,CAAC,sBAAsB,EAAE;YAC/B,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC,CAAC;QAEH,4BAA4B;QAC5B,MAAM,MAAM,GAAG,QAAQ,CAAC,wBAAwB,EAAE;YAChD,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC,CAAC;QAEH,uFAAuF;QACvF,OAAO,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,gEAAgE;QAChE,2CAA2C;QAC3C,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON Schema validation utilities using Ajv.
|
|
3
|
+
*
|
|
4
|
+
* Provides functions to load and validate data against JSON schemas.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Raw AJV error object (subset of fields we care about).
|
|
8
|
+
*/
|
|
9
|
+
export interface RawAjvError {
|
|
10
|
+
instancePath: string;
|
|
11
|
+
schemaPath: string;
|
|
12
|
+
keyword: string;
|
|
13
|
+
params: Record<string, unknown>;
|
|
14
|
+
message?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Result of schema validation.
|
|
18
|
+
*/
|
|
19
|
+
export interface ValidationResult<T> {
|
|
20
|
+
/** Whether the data is valid */
|
|
21
|
+
valid: boolean;
|
|
22
|
+
/** Typed data if valid, null otherwise */
|
|
23
|
+
data: T | null;
|
|
24
|
+
/** Validation error messages if invalid */
|
|
25
|
+
errors: string[];
|
|
26
|
+
/** Raw AJV error objects for diagnostics */
|
|
27
|
+
rawErrors?: RawAjvError[];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Loads and parses a JSON schema file.
|
|
31
|
+
*
|
|
32
|
+
* @param schemaPath - Path to the JSON schema file
|
|
33
|
+
* @returns Parsed schema object
|
|
34
|
+
* @throws Error if the schema file cannot be read or parsed
|
|
35
|
+
*/
|
|
36
|
+
export declare function loadSchema(schemaPath: string): Promise<object>;
|
|
37
|
+
/**
|
|
38
|
+
* Validates data against a JSON schema using Ajv.
|
|
39
|
+
*
|
|
40
|
+
* Uses draft-2020-12 schema support and caches compiled schemas for performance.
|
|
41
|
+
*
|
|
42
|
+
* @param data - Data to validate
|
|
43
|
+
* @param schema - JSON schema object
|
|
44
|
+
* @returns ValidationResult with typed data or error messages
|
|
45
|
+
*/
|
|
46
|
+
export declare function validateWithSchema<T>(data: unknown, schema: object): ValidationResult<T>;
|
|
47
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/lib/schema.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC,gCAAgC;IAChC,KAAK,EAAE,OAAO,CAAC;IACf,0CAA0C;IAC1C,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACf,2CAA2C;IAC3C,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,WAAW,EAAE,CAAC;CAC3B;AAKD;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CASpE;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,gBAAgB,CAAC,CAAC,CAAC,CA6DxF"}
|