ghcralph 0.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/LICENSE +21 -0
- package/README.md +327 -0
- package/bin/ghcralph.js +2 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +92 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/config.d.ts +8 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +118 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/index.d.ts +11 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +11 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.d.ts +15 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +116 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/rollback.d.ts +8 -0
- package/dist/commands/rollback.d.ts.map +1 -0
- package/dist/commands/rollback.js +238 -0
- package/dist/commands/rollback.js.map +1 -0
- package/dist/commands/run.d.ts +28 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +407 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/status.d.ts +8 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +399 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/core/action-executor.d.ts +96 -0
- package/dist/core/action-executor.d.ts.map +1 -0
- package/dist/core/action-executor.js +289 -0
- package/dist/core/action-executor.js.map +1 -0
- package/dist/core/checkpoint-manager.d.ts +94 -0
- package/dist/core/checkpoint-manager.d.ts.map +1 -0
- package/dist/core/checkpoint-manager.js +236 -0
- package/dist/core/checkpoint-manager.js.map +1 -0
- package/dist/core/config-manager.d.ts +62 -0
- package/dist/core/config-manager.d.ts.map +1 -0
- package/dist/core/config-manager.js +184 -0
- package/dist/core/config-manager.js.map +1 -0
- package/dist/core/config-schema.d.ts +74 -0
- package/dist/core/config-schema.d.ts.map +1 -0
- package/dist/core/config-schema.js +84 -0
- package/dist/core/config-schema.js.map +1 -0
- package/dist/core/context-builder.d.ts +116 -0
- package/dist/core/context-builder.d.ts.map +1 -0
- package/dist/core/context-builder.js +388 -0
- package/dist/core/context-builder.js.map +1 -0
- package/dist/core/feedback-builder.d.ts +94 -0
- package/dist/core/feedback-builder.d.ts.map +1 -0
- package/dist/core/feedback-builder.js +226 -0
- package/dist/core/feedback-builder.js.map +1 -0
- package/dist/core/file-safeguard.d.ts +109 -0
- package/dist/core/file-safeguard.d.ts.map +1 -0
- package/dist/core/file-safeguard.js +200 -0
- package/dist/core/file-safeguard.js.map +1 -0
- package/dist/core/git-branch-manager.d.ts +122 -0
- package/dist/core/git-branch-manager.d.ts.map +1 -0
- package/dist/core/git-branch-manager.js +302 -0
- package/dist/core/git-branch-manager.js.map +1 -0
- package/dist/core/github-plan.d.ts +86 -0
- package/dist/core/github-plan.d.ts.map +1 -0
- package/dist/core/github-plan.js +333 -0
- package/dist/core/github-plan.js.map +1 -0
- package/dist/core/index.d.ts +43 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +26 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/local-markdown-plan.d.ts +65 -0
- package/dist/core/local-markdown-plan.d.ts.map +1 -0
- package/dist/core/local-markdown-plan.js +154 -0
- package/dist/core/local-markdown-plan.js.map +1 -0
- package/dist/core/loop-engine.d.ts +133 -0
- package/dist/core/loop-engine.d.ts.map +1 -0
- package/dist/core/loop-engine.js +420 -0
- package/dist/core/loop-engine.js.map +1 -0
- package/dist/core/loop-events.d.ts +48 -0
- package/dist/core/loop-events.d.ts.map +1 -0
- package/dist/core/loop-events.js +24 -0
- package/dist/core/loop-events.js.map +1 -0
- package/dist/core/loop-state.d.ts +51 -0
- package/dist/core/loop-state.d.ts.map +1 -0
- package/dist/core/loop-state.js +48 -0
- package/dist/core/loop-state.js.map +1 -0
- package/dist/core/markdown-parser.d.ts +51 -0
- package/dist/core/markdown-parser.d.ts.map +1 -0
- package/dist/core/markdown-parser.js +122 -0
- package/dist/core/markdown-parser.js.map +1 -0
- package/dist/core/plan-manager.d.ts +61 -0
- package/dist/core/plan-manager.d.ts.map +1 -0
- package/dist/core/plan-manager.js +7 -0
- package/dist/core/plan-manager.js.map +1 -0
- package/dist/core/progress-tracker.d.ts +74 -0
- package/dist/core/progress-tracker.d.ts.map +1 -0
- package/dist/core/progress-tracker.js +198 -0
- package/dist/core/progress-tracker.js.map +1 -0
- package/dist/core/prompt-examples.d.ts +52 -0
- package/dist/core/prompt-examples.d.ts.map +1 -0
- package/dist/core/prompt-examples.js +194 -0
- package/dist/core/prompt-examples.js.map +1 -0
- package/dist/core/response-parser.d.ts +90 -0
- package/dist/core/response-parser.d.ts.map +1 -0
- package/dist/core/response-parser.js +209 -0
- package/dist/core/response-parser.js.map +1 -0
- package/dist/core/verification-hooks.d.ts +103 -0
- package/dist/core/verification-hooks.d.ts.map +1 -0
- package/dist/core/verification-hooks.js +268 -0
- package/dist/core/verification-hooks.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/auth.d.ts +28 -0
- package/dist/integrations/auth.d.ts.map +1 -0
- package/dist/integrations/auth.js +76 -0
- package/dist/integrations/auth.js.map +1 -0
- package/dist/integrations/copilot-agent.d.ts +104 -0
- package/dist/integrations/copilot-agent.d.ts.map +1 -0
- package/dist/integrations/copilot-agent.js +235 -0
- package/dist/integrations/copilot-agent.js.map +1 -0
- package/dist/integrations/index.d.ts +18 -0
- package/dist/integrations/index.d.ts.map +1 -0
- package/dist/integrations/index.js +14 -0
- package/dist/integrations/index.js.map +1 -0
- package/dist/integrations/mcp-tools.d.ts +129 -0
- package/dist/integrations/mcp-tools.d.ts.map +1 -0
- package/dist/integrations/mcp-tools.js +272 -0
- package/dist/integrations/mcp-tools.js.map +1 -0
- package/dist/integrations/tokens.d.ts +45 -0
- package/dist/integrations/tokens.d.ts.map +1 -0
- package/dist/integrations/tokens.js +50 -0
- package/dist/integrations/tokens.js.map +1 -0
- package/dist/types/index.d.ts +53 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +7 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/index.d.ts +23 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +37 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/output.d.ts +59 -0
- package/dist/utils/output.d.ts.map +1 -0
- package/dist/utils/output.js +96 -0
- package/dist/utils/output.js.map +1 -0
- package/dist/utils/paths.d.ts +34 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +67 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/shell.d.ts +26 -0
- package/dist/utils/shell.d.ts.map +1 -0
- package/dist/utils/shell.js +65 -0
- package/dist/utils/shell.js.map +1 -0
- package/dist/utils/validation.d.ts +27 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +43 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +86 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feedback Builder
|
|
3
|
+
*
|
|
4
|
+
* Builds feedback prompts to show the AI the results of its actions.
|
|
5
|
+
* This is a core component of the Ralph pattern - the AI must see
|
|
6
|
+
* actual results (test output, errors, git diff) to iterate effectively.
|
|
7
|
+
*/
|
|
8
|
+
import { exec } from 'node:child_process';
|
|
9
|
+
import { promisify } from 'node:util';
|
|
10
|
+
import { debug } from '../utils/index.js';
|
|
11
|
+
const execAsync = promisify(exec);
|
|
12
|
+
const DEFAULT_CONFIG = {
|
|
13
|
+
cwd: process.cwd(),
|
|
14
|
+
maxOutputLines: 50,
|
|
15
|
+
includeGitDiff: true,
|
|
16
|
+
maxDiffSize: 5000,
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Feedback Builder
|
|
20
|
+
*
|
|
21
|
+
* Creates structured feedback for the AI based on what happened
|
|
22
|
+
* in the previous iteration.
|
|
23
|
+
*/
|
|
24
|
+
export class FeedbackBuilder {
|
|
25
|
+
config;
|
|
26
|
+
constructor(config = {}) {
|
|
27
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build feedback from action execution results
|
|
31
|
+
*/
|
|
32
|
+
buildFromActions(executionResult) {
|
|
33
|
+
const lines = [];
|
|
34
|
+
for (const result of executionResult.results) {
|
|
35
|
+
const icon = result.success ? '✓' : '✗';
|
|
36
|
+
lines.push(`${icon} ${result.message}`);
|
|
37
|
+
// Include output for EXECUTE actions or failures
|
|
38
|
+
if (result.output && (result.action.type === 'EXECUTE' || !result.success)) {
|
|
39
|
+
const outputLines = result.output.split('\n');
|
|
40
|
+
const truncated = outputLines.slice(0, this.config.maxOutputLines);
|
|
41
|
+
if (outputLines.length > this.config.maxOutputLines) {
|
|
42
|
+
truncated.push(`... (${outputLines.length - this.config.maxOutputLines} more lines)`);
|
|
43
|
+
}
|
|
44
|
+
lines.push('```');
|
|
45
|
+
lines.push(...truncated);
|
|
46
|
+
lines.push('```');
|
|
47
|
+
}
|
|
48
|
+
// Include error details for failures
|
|
49
|
+
if (!result.success && result.error) {
|
|
50
|
+
lines.push(` Error: ${result.error}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
type: 'actions',
|
|
55
|
+
title: 'Action Results',
|
|
56
|
+
content: lines.join('\n'),
|
|
57
|
+
success: executionResult.allSucceeded,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Build feedback from verification results
|
|
62
|
+
*/
|
|
63
|
+
buildFromVerification(results) {
|
|
64
|
+
if (results.length === 0) {
|
|
65
|
+
return {
|
|
66
|
+
type: 'verification',
|
|
67
|
+
title: 'Verification',
|
|
68
|
+
content: 'No verification hooks configured.',
|
|
69
|
+
success: true,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
const lines = [];
|
|
73
|
+
let allPassed = true;
|
|
74
|
+
for (const result of results) {
|
|
75
|
+
const icon = result.passed ? '✓' : '✗';
|
|
76
|
+
lines.push(`${icon} ${result.message} (${result.durationMs}ms)`);
|
|
77
|
+
if (!result.passed) {
|
|
78
|
+
allPassed = false;
|
|
79
|
+
// Include failure output
|
|
80
|
+
if (result.output) {
|
|
81
|
+
const outputLines = result.output.split('\n');
|
|
82
|
+
const truncated = outputLines.slice(-this.config.maxOutputLines); // Last N lines for errors
|
|
83
|
+
if (outputLines.length > this.config.maxOutputLines) {
|
|
84
|
+
lines.push(`... (${outputLines.length - this.config.maxOutputLines} lines omitted)`);
|
|
85
|
+
}
|
|
86
|
+
lines.push('```');
|
|
87
|
+
lines.push(...truncated);
|
|
88
|
+
lines.push('```');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
type: 'verification',
|
|
94
|
+
title: 'Verification Results',
|
|
95
|
+
content: lines.join('\n'),
|
|
96
|
+
success: allPassed,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Build feedback from current git diff
|
|
101
|
+
*/
|
|
102
|
+
async buildFromGitDiff() {
|
|
103
|
+
if (!this.config.includeGitDiff) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
const { stdout } = await execAsync('git diff --stat HEAD 2>/dev/null', {
|
|
108
|
+
cwd: this.config.cwd,
|
|
109
|
+
maxBuffer: 100000,
|
|
110
|
+
});
|
|
111
|
+
const diffStat = stdout.trim();
|
|
112
|
+
if (!diffStat) {
|
|
113
|
+
return null; // No changes
|
|
114
|
+
}
|
|
115
|
+
// Get actual diff (limited)
|
|
116
|
+
const { stdout: diffContent } = await execAsync('git diff HEAD 2>/dev/null', {
|
|
117
|
+
cwd: this.config.cwd,
|
|
118
|
+
maxBuffer: this.config.maxDiffSize * 2,
|
|
119
|
+
});
|
|
120
|
+
let content = diffContent.trim();
|
|
121
|
+
if (content.length > this.config.maxDiffSize) {
|
|
122
|
+
content = content.substring(0, this.config.maxDiffSize) + '\n... (diff truncated)';
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
type: 'git-diff',
|
|
126
|
+
title: 'Current Changes',
|
|
127
|
+
content: `\`\`\`diff\n${content}\n\`\`\``,
|
|
128
|
+
success: true,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
debug('Failed to get git diff');
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Build an error feedback section
|
|
138
|
+
*/
|
|
139
|
+
buildError(error) {
|
|
140
|
+
const message = error instanceof Error ? error.message : error;
|
|
141
|
+
return {
|
|
142
|
+
type: 'error',
|
|
143
|
+
title: 'Error',
|
|
144
|
+
content: `An error occurred: ${message}`,
|
|
145
|
+
success: false,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Build a suggestion section
|
|
150
|
+
*/
|
|
151
|
+
buildSuggestion(suggestion) {
|
|
152
|
+
return {
|
|
153
|
+
type: 'suggestion',
|
|
154
|
+
title: 'Suggestion',
|
|
155
|
+
content: suggestion,
|
|
156
|
+
success: true,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Combine sections into complete iteration feedback
|
|
161
|
+
*/
|
|
162
|
+
async buildComplete(actionResult, verificationResults, options = {}) {
|
|
163
|
+
const sections = [];
|
|
164
|
+
// Add action results
|
|
165
|
+
if (actionResult) {
|
|
166
|
+
sections.push(this.buildFromActions(actionResult));
|
|
167
|
+
}
|
|
168
|
+
// Add verification results
|
|
169
|
+
if (verificationResults.length > 0) {
|
|
170
|
+
sections.push(this.buildFromVerification(verificationResults));
|
|
171
|
+
}
|
|
172
|
+
// Add git diff if requested
|
|
173
|
+
if (options.includeGitDiff !== false) {
|
|
174
|
+
const diffSection = await this.buildFromGitDiff();
|
|
175
|
+
if (diffSection) {
|
|
176
|
+
sections.push(diffSection);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// Add suggestion if provided
|
|
180
|
+
if (options.suggestion) {
|
|
181
|
+
sections.push(this.buildSuggestion(options.suggestion));
|
|
182
|
+
}
|
|
183
|
+
// Calculate overall status
|
|
184
|
+
const overallSuccess = sections.every((s) => s.success);
|
|
185
|
+
const verificationPassed = verificationResults.every((r) => r.passed);
|
|
186
|
+
const taskComplete = actionResult?.taskComplete === true && verificationPassed;
|
|
187
|
+
// Format for prompt
|
|
188
|
+
const formatted = this.formatForPrompt(sections, taskComplete);
|
|
189
|
+
return {
|
|
190
|
+
sections,
|
|
191
|
+
overallSuccess,
|
|
192
|
+
taskComplete,
|
|
193
|
+
formatted,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Format feedback sections for inclusion in prompt
|
|
198
|
+
*/
|
|
199
|
+
formatForPrompt(sections, taskComplete) {
|
|
200
|
+
const lines = ['## Feedback from Previous Iteration'];
|
|
201
|
+
if (taskComplete) {
|
|
202
|
+
lines.push('');
|
|
203
|
+
lines.push('✅ **Task verified complete!** All actions succeeded and verification passed.');
|
|
204
|
+
lines.push('');
|
|
205
|
+
}
|
|
206
|
+
for (const section of sections) {
|
|
207
|
+
lines.push('');
|
|
208
|
+
lines.push(`### ${section.title}`);
|
|
209
|
+
lines.push(section.content);
|
|
210
|
+
}
|
|
211
|
+
if (!taskComplete && sections.some((s) => !s.success)) {
|
|
212
|
+
lines.push('');
|
|
213
|
+
lines.push('### Next Steps');
|
|
214
|
+
lines.push('Review the failures above and continue working on the task.');
|
|
215
|
+
lines.push('Use [ACTION:EXECUTE] to investigate issues if needed.');
|
|
216
|
+
}
|
|
217
|
+
return lines.join('\n');
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Create a feedback builder with custom configuration
|
|
222
|
+
*/
|
|
223
|
+
export function createFeedbackBuilder(config) {
|
|
224
|
+
return new FeedbackBuilder(config);
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=feedback-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feedback-builder.js","sourceRoot":"","sources":["../../src/core/feedback-builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Safeguard Manager
|
|
3
|
+
*
|
|
4
|
+
* Protects existing files from accidental deletion while allowing
|
|
5
|
+
* cleanup of agent-created files.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* File safeguard configuration
|
|
9
|
+
*/
|
|
10
|
+
export interface FileSafeguardConfig {
|
|
11
|
+
/** Working directory */
|
|
12
|
+
cwd: string;
|
|
13
|
+
/** Whether to allow deletion of existing files */
|
|
14
|
+
allowDeleteExisting: boolean;
|
|
15
|
+
/** Path to store baseline snapshot */
|
|
16
|
+
baselinePath: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Baseline snapshot data
|
|
20
|
+
*/
|
|
21
|
+
export interface BaselineSnapshot {
|
|
22
|
+
/** When the snapshot was created */
|
|
23
|
+
createdAt: string;
|
|
24
|
+
/** List of files that existed at session start */
|
|
25
|
+
files: string[];
|
|
26
|
+
/** Number of files in the baseline */
|
|
27
|
+
count: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* File operation tracking
|
|
31
|
+
*/
|
|
32
|
+
export interface FileOperations {
|
|
33
|
+
/** Files that existed before session */
|
|
34
|
+
baselineFiles: Set<string>;
|
|
35
|
+
/** Files created during session */
|
|
36
|
+
createdFiles: Set<string>;
|
|
37
|
+
/** Files modified during session */
|
|
38
|
+
modifiedFiles: Set<string>;
|
|
39
|
+
/** Deletion attempts that were blocked */
|
|
40
|
+
blockedDeletions: string[];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* File Safeguard Manager class
|
|
44
|
+
*/
|
|
45
|
+
export declare class FileSafeguardManager {
|
|
46
|
+
private config;
|
|
47
|
+
private operations;
|
|
48
|
+
private initialized;
|
|
49
|
+
constructor(config?: Partial<FileSafeguardConfig>);
|
|
50
|
+
private getNormalizedRelativePath;
|
|
51
|
+
/**
|
|
52
|
+
* Initialize by creating baseline snapshot
|
|
53
|
+
*/
|
|
54
|
+
initialize(): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Create baseline snapshot of existing files
|
|
57
|
+
*/
|
|
58
|
+
private createBaseline;
|
|
59
|
+
/**
|
|
60
|
+
* Load existing baseline from file
|
|
61
|
+
*/
|
|
62
|
+
private loadBaseline;
|
|
63
|
+
/**
|
|
64
|
+
* Check if a file existed before the session
|
|
65
|
+
*/
|
|
66
|
+
isBaselineFile(filePath: string): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Check if a file was created during this session
|
|
69
|
+
*/
|
|
70
|
+
isCreatedFile(filePath: string): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Track a file creation
|
|
73
|
+
*/
|
|
74
|
+
trackFileCreation(filePath: string): void;
|
|
75
|
+
/**
|
|
76
|
+
* Track a file modification
|
|
77
|
+
*/
|
|
78
|
+
trackFileModification(filePath: string): void;
|
|
79
|
+
/**
|
|
80
|
+
* Check if a file can be deleted
|
|
81
|
+
*/
|
|
82
|
+
canDelete(filePath: string): boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Get summary of file operations
|
|
85
|
+
*/
|
|
86
|
+
getSummary(): {
|
|
87
|
+
baselineCount: number;
|
|
88
|
+
createdCount: number;
|
|
89
|
+
modifiedCount: number;
|
|
90
|
+
blockedCount: number;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Get detailed file operation info
|
|
94
|
+
*/
|
|
95
|
+
getDetails(): {
|
|
96
|
+
created: string[];
|
|
97
|
+
modified: string[];
|
|
98
|
+
blockedDeletions: string[];
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Clean up baseline file (call at end of session)
|
|
102
|
+
*/
|
|
103
|
+
cleanup(): Promise<void>;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Create a file safeguard manager
|
|
107
|
+
*/
|
|
108
|
+
export declare function createFileSafeguardManager(config?: Partial<FileSafeguardConfig>): FileSafeguardManager;
|
|
109
|
+
//# sourceMappingURL=file-safeguard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-safeguard.d.ts","sourceRoot":"","sources":["../../src/core/file-safeguard.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,wBAAwB;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,kDAAkD;IAClD,mBAAmB,EAAE,OAAO,CAAC;IAC7B,sCAAsC;IACtC,YAAY,EAAE,MAAM,CAAC;CACtB;AAWD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,wCAAwC;IACxC,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,mCAAmC;IACnC,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC1B,oCAAoC;IACpC,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,0CAA0C;IAC1C,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED;;GAEG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,UAAU,CAAiB;IACnC,OAAO,CAAC,WAAW,CAAkB;gBAEzB,MAAM,GAAE,OAAO,CAAC,mBAAmB,CAAM;IAUrD,OAAO,CAAC,yBAAyB;IAKjC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAoBjC;;OAEG;YACW,cAAc;IA6B5B;;OAEG;YACW,YAAY;IAc1B;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAKzC;;OAEG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAKxC;;OAEG;IACH,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAQzC;;OAEG;IACH,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAK7C;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAwBpC;;OAEG;IACH,UAAU,IAAI;QACZ,aAAa,EAAE,MAAM,CAAC;QACtB,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;QACtB,YAAY,EAAE,MAAM,CAAC;KACtB;IASD;;OAEG;IACH,UAAU,IAAI;QACZ,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,gBAAgB,EAAE,MAAM,EAAE,CAAC;KAC5B;IAQD;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAS/B;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAAG,oBAAoB,CAEtG"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Safeguard Manager
|
|
3
|
+
*
|
|
4
|
+
* Protects existing files from accidental deletion while allowing
|
|
5
|
+
* cleanup of agent-created files.
|
|
6
|
+
*/
|
|
7
|
+
import fs from 'node:fs/promises';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { exec } from 'node:child_process';
|
|
10
|
+
import { promisify } from 'node:util';
|
|
11
|
+
import { debug, warn } from '../utils/index.js';
|
|
12
|
+
const execAsync = promisify(exec);
|
|
13
|
+
/**
|
|
14
|
+
* Default configuration
|
|
15
|
+
*/
|
|
16
|
+
const DEFAULT_CONFIG = {
|
|
17
|
+
cwd: process.cwd(),
|
|
18
|
+
allowDeleteExisting: false,
|
|
19
|
+
baselinePath: '.ghcralph/baseline-files.json',
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* File Safeguard Manager class
|
|
23
|
+
*/
|
|
24
|
+
export class FileSafeguardManager {
|
|
25
|
+
config;
|
|
26
|
+
operations;
|
|
27
|
+
initialized = false;
|
|
28
|
+
constructor(config = {}) {
|
|
29
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
30
|
+
this.operations = {
|
|
31
|
+
baselineFiles: new Set(),
|
|
32
|
+
createdFiles: new Set(),
|
|
33
|
+
modifiedFiles: new Set(),
|
|
34
|
+
blockedDeletions: [],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
getNormalizedRelativePath(filePath) {
|
|
38
|
+
const absolutePath = path.isAbsolute(filePath) ? filePath : path.join(this.config.cwd, filePath);
|
|
39
|
+
return path.relative(this.config.cwd, absolutePath).replace(/\\/g, '/');
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Initialize by creating baseline snapshot
|
|
43
|
+
*/
|
|
44
|
+
async initialize() {
|
|
45
|
+
if (this.initialized)
|
|
46
|
+
return;
|
|
47
|
+
try {
|
|
48
|
+
// Try to load existing baseline
|
|
49
|
+
const loaded = await this.loadBaseline();
|
|
50
|
+
if (loaded) {
|
|
51
|
+
debug('Loaded existing baseline snapshot');
|
|
52
|
+
this.initialized = true;
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
// Create new baseline
|
|
56
|
+
await this.createBaseline();
|
|
57
|
+
this.initialized = true;
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
warn('Failed to initialize file safeguards: ' + (err instanceof Error ? err.message : String(err)));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Create baseline snapshot of existing files
|
|
65
|
+
*/
|
|
66
|
+
async createBaseline() {
|
|
67
|
+
try {
|
|
68
|
+
// Get list of tracked files from git
|
|
69
|
+
const { stdout } = await execAsync('git ls-files', { cwd: this.config.cwd });
|
|
70
|
+
const files = stdout.trim().split('\n').filter(Boolean);
|
|
71
|
+
// Store in memory
|
|
72
|
+
this.operations.baselineFiles = new Set(files);
|
|
73
|
+
// Save to file
|
|
74
|
+
const snapshot = {
|
|
75
|
+
createdAt: new Date().toISOString(),
|
|
76
|
+
files,
|
|
77
|
+
count: files.length,
|
|
78
|
+
};
|
|
79
|
+
const baselinePath = path.join(this.config.cwd, this.config.baselinePath);
|
|
80
|
+
const baselineDir = path.dirname(baselinePath);
|
|
81
|
+
// Ensure directory exists
|
|
82
|
+
await fs.mkdir(baselineDir, { recursive: true });
|
|
83
|
+
await fs.writeFile(baselinePath, JSON.stringify(snapshot, null, 2));
|
|
84
|
+
debug(`Created baseline with ${files.length} files`);
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
debug('Failed to create baseline: ' + (err instanceof Error ? err.message : String(err)));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Load existing baseline from file
|
|
92
|
+
*/
|
|
93
|
+
async loadBaseline() {
|
|
94
|
+
try {
|
|
95
|
+
const baselinePath = path.join(this.config.cwd, this.config.baselinePath);
|
|
96
|
+
const content = await fs.readFile(baselinePath, 'utf-8');
|
|
97
|
+
const snapshot = JSON.parse(content);
|
|
98
|
+
this.operations.baselineFiles = new Set(snapshot.files);
|
|
99
|
+
debug(`Loaded baseline with ${snapshot.count} files from ${snapshot.createdAt}`);
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Check if a file existed before the session
|
|
108
|
+
*/
|
|
109
|
+
isBaselineFile(filePath) {
|
|
110
|
+
const relativePath = this.getNormalizedRelativePath(filePath);
|
|
111
|
+
return this.operations.baselineFiles.has(relativePath);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Check if a file was created during this session
|
|
115
|
+
*/
|
|
116
|
+
isCreatedFile(filePath) {
|
|
117
|
+
const relativePath = this.getNormalizedRelativePath(filePath);
|
|
118
|
+
return this.operations.createdFiles.has(relativePath);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Track a file creation
|
|
122
|
+
*/
|
|
123
|
+
trackFileCreation(filePath) {
|
|
124
|
+
const relativePath = this.getNormalizedRelativePath(filePath);
|
|
125
|
+
if (!this.operations.baselineFiles.has(relativePath)) {
|
|
126
|
+
this.operations.createdFiles.add(relativePath);
|
|
127
|
+
debug(`Tracked file creation: ${relativePath}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Track a file modification
|
|
132
|
+
*/
|
|
133
|
+
trackFileModification(filePath) {
|
|
134
|
+
const relativePath = this.getNormalizedRelativePath(filePath);
|
|
135
|
+
this.operations.modifiedFiles.add(relativePath);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Check if a file can be deleted
|
|
139
|
+
*/
|
|
140
|
+
canDelete(filePath) {
|
|
141
|
+
// Always allow if override is set
|
|
142
|
+
if (this.config.allowDeleteExisting) {
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
const relativePath = this.getNormalizedRelativePath(filePath);
|
|
146
|
+
// Allow deletion of files created during session
|
|
147
|
+
if (this.operations.createdFiles.has(relativePath)) {
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
// Block deletion of baseline files
|
|
151
|
+
if (this.operations.baselineFiles.has(relativePath)) {
|
|
152
|
+
this.operations.blockedDeletions.push(relativePath);
|
|
153
|
+
warn(`Blocked deletion of pre-existing file: ${relativePath}`);
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
// Allow deletion of unknown files (not in baseline, not tracked as created)
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Get summary of file operations
|
|
161
|
+
*/
|
|
162
|
+
getSummary() {
|
|
163
|
+
return {
|
|
164
|
+
baselineCount: this.operations.baselineFiles.size,
|
|
165
|
+
createdCount: this.operations.createdFiles.size,
|
|
166
|
+
modifiedCount: this.operations.modifiedFiles.size,
|
|
167
|
+
blockedCount: this.operations.blockedDeletions.length,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Get detailed file operation info
|
|
172
|
+
*/
|
|
173
|
+
getDetails() {
|
|
174
|
+
return {
|
|
175
|
+
created: Array.from(this.operations.createdFiles),
|
|
176
|
+
modified: Array.from(this.operations.modifiedFiles),
|
|
177
|
+
blockedDeletions: this.operations.blockedDeletions,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Clean up baseline file (call at end of session)
|
|
182
|
+
*/
|
|
183
|
+
async cleanup() {
|
|
184
|
+
try {
|
|
185
|
+
const baselinePath = path.join(this.config.cwd, this.config.baselinePath);
|
|
186
|
+
await fs.unlink(baselinePath);
|
|
187
|
+
debug('Cleaned up baseline file');
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
// Ignore cleanup errors
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Create a file safeguard manager
|
|
196
|
+
*/
|
|
197
|
+
export function createFileSafeguardManager(config) {
|
|
198
|
+
return new FileSafeguardManager(config);
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=file-safeguard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-safeguard.js","sourceRoot":"","sources":["../../src/core/file-safeguard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git Branch Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages git branch isolation for safe Ralph operations
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Git branch manager configuration
|
|
8
|
+
*/
|
|
9
|
+
export interface GitBranchConfig {
|
|
10
|
+
/** Prefix for GitHub Copilot Ralph branches (default: 'ralph/') */
|
|
11
|
+
branchPrefix: string;
|
|
12
|
+
/** Whether to auto-create branches without prompting */
|
|
13
|
+
autoCreate: boolean;
|
|
14
|
+
/** Working directory */
|
|
15
|
+
cwd: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Working directory status
|
|
19
|
+
*/
|
|
20
|
+
export interface WorkingDirStatus {
|
|
21
|
+
/** Whether the working directory is clean */
|
|
22
|
+
isClean: boolean;
|
|
23
|
+
/** Number of modified files */
|
|
24
|
+
modifiedFiles: number;
|
|
25
|
+
/** Number of untracked files */
|
|
26
|
+
untrackedFiles: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Branch info
|
|
30
|
+
*/
|
|
31
|
+
export interface BranchInfo {
|
|
32
|
+
/** Current branch name */
|
|
33
|
+
name: string;
|
|
34
|
+
/** Whether this is a main/master branch */
|
|
35
|
+
isMain: boolean;
|
|
36
|
+
/** Whether this is a Ralph branch */
|
|
37
|
+
isRalphBranch: boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Git Branch Manager class
|
|
41
|
+
*/
|
|
42
|
+
export declare class GitBranchManager {
|
|
43
|
+
private config;
|
|
44
|
+
constructor(config?: Partial<GitBranchConfig>);
|
|
45
|
+
/**
|
|
46
|
+
* Check if we're in a git repository
|
|
47
|
+
*/
|
|
48
|
+
isGitRepository(): Promise<boolean>;
|
|
49
|
+
/**
|
|
50
|
+
* Get current branch information
|
|
51
|
+
*/
|
|
52
|
+
getCurrentBranch(): Promise<BranchInfo>;
|
|
53
|
+
/**
|
|
54
|
+
* Get working directory status
|
|
55
|
+
*/
|
|
56
|
+
getWorkingDirStatus(): Promise<WorkingDirStatus>;
|
|
57
|
+
/**
|
|
58
|
+
* Stash current changes
|
|
59
|
+
*/
|
|
60
|
+
stashChanges(message?: string): Promise<boolean>;
|
|
61
|
+
/**
|
|
62
|
+
* Pop stashed changes
|
|
63
|
+
*/
|
|
64
|
+
popStash(): Promise<boolean>;
|
|
65
|
+
/**
|
|
66
|
+
* Generate a branch name from task info
|
|
67
|
+
*/
|
|
68
|
+
generateBranchName(taskTitle: string, taskId?: string): string;
|
|
69
|
+
/**
|
|
70
|
+
* Create and switch to a new Ralph branch
|
|
71
|
+
*/
|
|
72
|
+
createAndSwitchBranch(branchName: string): Promise<boolean>;
|
|
73
|
+
/**
|
|
74
|
+
* Switch to an existing branch
|
|
75
|
+
*/
|
|
76
|
+
switchBranch(branchName: string): Promise<boolean>;
|
|
77
|
+
/**
|
|
78
|
+
* Check if a branch exists
|
|
79
|
+
*/
|
|
80
|
+
branchExists(branchName: string): Promise<boolean>;
|
|
81
|
+
/**
|
|
82
|
+
* Get the default branch (main/master)
|
|
83
|
+
*/
|
|
84
|
+
getDefaultBranch(): Promise<string>;
|
|
85
|
+
/**
|
|
86
|
+
* Merge a Ralph branch back to the original branch
|
|
87
|
+
*/
|
|
88
|
+
mergeBranch(sourceBranch: string, targetBranch: string): Promise<boolean>;
|
|
89
|
+
/**
|
|
90
|
+
* Delete a branch
|
|
91
|
+
*/
|
|
92
|
+
deleteBranch(branchName: string, force?: boolean): Promise<boolean>;
|
|
93
|
+
/**
|
|
94
|
+
* Get the list of GitHub Copilot Ralph branches
|
|
95
|
+
*/
|
|
96
|
+
listRalphBranches(): Promise<string[]>;
|
|
97
|
+
/**
|
|
98
|
+
* Prepare the branch for a Ralph operation
|
|
99
|
+
* Returns the branch name to use
|
|
100
|
+
*/
|
|
101
|
+
prepareForOperation(taskTitle: string, taskId?: string, options?: {
|
|
102
|
+
branch?: string;
|
|
103
|
+
force?: boolean;
|
|
104
|
+
}): Promise<{
|
|
105
|
+
branchName: string;
|
|
106
|
+
created: boolean;
|
|
107
|
+
originalBranch: string;
|
|
108
|
+
}>;
|
|
109
|
+
/**
|
|
110
|
+
* Get the latest commit hash
|
|
111
|
+
*/
|
|
112
|
+
getLatestCommitHash(): Promise<string | null>;
|
|
113
|
+
/**
|
|
114
|
+
* Get the commit count on current branch
|
|
115
|
+
*/
|
|
116
|
+
getCommitCount(): Promise<number>;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Create a git branch manager with configuration
|
|
120
|
+
*/
|
|
121
|
+
export declare function createGitBranchManager(config?: Partial<GitBranchConfig>): GitBranchManager;
|
|
122
|
+
//# sourceMappingURL=git-branch-manager.d.ts.map
|