ralph-wiggum-ui 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/dist/cli/commands/add.d.ts +10 -0
- package/dist/cli/commands/add.d.ts.map +1 -0
- package/dist/cli/commands/add.js +87 -0
- package/dist/cli/commands/add.js.map +1 -0
- package/dist/cli/commands/init.d.ts +5 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +91 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/list.d.ts +9 -0
- package/dist/cli/commands/list.d.ts.map +1 -0
- package/dist/cli/commands/list.js +90 -0
- package/dist/cli/commands/list.js.map +1 -0
- package/dist/cli/commands/run.d.ts +10 -0
- package/dist/cli/commands/run.d.ts.map +1 -0
- package/dist/cli/commands/run.js +200 -0
- package/dist/cli/commands/run.js.map +1 -0
- package/dist/cli/commands/serve.d.ts +10 -0
- package/dist/cli/commands/serve.d.ts.map +1 -0
- package/dist/cli/commands/serve.js +57 -0
- package/dist/cli/commands/serve.js.map +1 -0
- package/dist/cli/commands/status.d.ts +5 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +63 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/index.d.ts +6 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +76 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/lib/config.d.ts +53 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +164 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/index.d.ts +11 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +18 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/logger.d.ts +72 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +159 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/preflight.d.ts +45 -0
- package/dist/lib/preflight.d.ts.map +1 -0
- package/dist/lib/preflight.js +173 -0
- package/dist/lib/preflight.js.map +1 -0
- package/dist/lib/progress.d.ts +41 -0
- package/dist/lib/progress.d.ts.map +1 -0
- package/dist/lib/progress.js +122 -0
- package/dist/lib/progress.js.map +1 -0
- package/dist/lib/tasks.d.ts +77 -0
- package/dist/lib/tasks.d.ts.map +1 -0
- package/dist/lib/tasks.js +259 -0
- package/dist/lib/tasks.js.map +1 -0
- package/dist/lib/templates.d.ts +25 -0
- package/dist/lib/templates.d.ts.map +1 -0
- package/dist/lib/templates.js +86 -0
- package/dist/lib/templates.js.map +1 -0
- package/dist/server/api.d.ts +7 -0
- package/dist/server/api.d.ts.map +1 -0
- package/dist/server/api.js +258 -0
- package/dist/server/api.js.map +1 -0
- package/dist/server/index.d.ts +15 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +59 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/runner.d.ts +15 -0
- package/dist/server/runner.d.ts.map +1 -0
- package/dist/server/runner.js +265 -0
- package/dist/server/runner.js.map +1 -0
- package/dist/types/index.d.ts +129 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +37 -0
- package/dist/types/index.js.map +1 -0
- package/dist/ui/assets/index-DBOjIoHW.js +137 -0
- package/dist/ui/assets/index-mu6cQFl4.css +1 -0
- package/dist/ui/favicon.svg +3 -0
- package/dist/ui/index.html +14 -0
- package/package.json +78 -0
- package/templates/AGENTS.md +48 -0
- package/templates/prompt.md +64 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task (User Story) management for Ralph Wiggum UI
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
5
|
+
import { PRD_FILE } from '../types/index.js';
|
|
6
|
+
import { getRalphFilePath } from './config.js';
|
|
7
|
+
/**
|
|
8
|
+
* Generate a new task ID
|
|
9
|
+
*/
|
|
10
|
+
export function generateTaskId(existingIds) {
|
|
11
|
+
// Find the highest existing number
|
|
12
|
+
const numbers = existingIds
|
|
13
|
+
.map((id) => {
|
|
14
|
+
const match = id.match(/^US-(\d+)$/);
|
|
15
|
+
return match ? parseInt(match[1] ?? '0', 10) : 0;
|
|
16
|
+
})
|
|
17
|
+
.filter((n) => n > 0);
|
|
18
|
+
const nextNumber = numbers.length > 0 ? Math.max(...numbers) + 1 : 1;
|
|
19
|
+
return `US-${String(nextNumber).padStart(3, '0')}`;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Create an empty PRD
|
|
23
|
+
*/
|
|
24
|
+
export function createEmptyPRD(project, branch) {
|
|
25
|
+
return {
|
|
26
|
+
version: '1.0.0',
|
|
27
|
+
project,
|
|
28
|
+
branchName: branch,
|
|
29
|
+
description: '',
|
|
30
|
+
createdAt: new Date().toISOString(),
|
|
31
|
+
userStories: [],
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Load the PRD file
|
|
36
|
+
*/
|
|
37
|
+
export function loadPRD(cwd) {
|
|
38
|
+
const prdPath = getRalphFilePath(cwd, PRD_FILE);
|
|
39
|
+
if (!existsSync(prdPath)) {
|
|
40
|
+
throw new Error(`PRD file not found: ${prdPath}`);
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
const content = readFileSync(prdPath, 'utf-8');
|
|
44
|
+
return JSON.parse(content);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (error instanceof SyntaxError) {
|
|
48
|
+
throw new Error(`Invalid JSON in PRD file: ${prdPath}`);
|
|
49
|
+
}
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Save the PRD file
|
|
55
|
+
*/
|
|
56
|
+
export function savePRD(cwd, prd) {
|
|
57
|
+
const prdPath = getRalphFilePath(cwd, PRD_FILE);
|
|
58
|
+
prd.updatedAt = new Date().toISOString();
|
|
59
|
+
const content = JSON.stringify(prd, null, 2);
|
|
60
|
+
writeFileSync(prdPath, content, 'utf-8');
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Check if PRD file exists
|
|
64
|
+
*/
|
|
65
|
+
export function prdExists(cwd) {
|
|
66
|
+
const prdPath = getRalphFilePath(cwd, PRD_FILE);
|
|
67
|
+
return existsSync(prdPath);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Add a new task to the PRD
|
|
71
|
+
*/
|
|
72
|
+
export function addTask(cwd, task) {
|
|
73
|
+
const prd = loadPRD(cwd);
|
|
74
|
+
const existingIds = prd.userStories.map((s) => s.id);
|
|
75
|
+
const id = generateTaskId(existingIds);
|
|
76
|
+
// Get the next priority (highest + 1)
|
|
77
|
+
const priorities = prd.userStories.map((s) => s.priority);
|
|
78
|
+
const nextPriority = priorities.length > 0 ? Math.max(...priorities) + 1 : 1;
|
|
79
|
+
const newTask = {
|
|
80
|
+
id,
|
|
81
|
+
title: task.title,
|
|
82
|
+
description: task.description,
|
|
83
|
+
acceptanceCriteria: task.acceptanceCriteria,
|
|
84
|
+
priority: nextPriority,
|
|
85
|
+
status: 'pending',
|
|
86
|
+
createdAt: new Date().toISOString(),
|
|
87
|
+
...(task.notes ? { notes: task.notes } : {}),
|
|
88
|
+
};
|
|
89
|
+
prd.userStories.push(newTask);
|
|
90
|
+
savePRD(cwd, prd);
|
|
91
|
+
return newTask;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Update an existing task
|
|
95
|
+
*/
|
|
96
|
+
export function updateTask(cwd, taskId, updates) {
|
|
97
|
+
const prd = loadPRD(cwd);
|
|
98
|
+
const taskIndex = prd.userStories.findIndex((s) => s.id === taskId);
|
|
99
|
+
if (taskIndex === -1) {
|
|
100
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
101
|
+
}
|
|
102
|
+
const task = prd.userStories[taskIndex];
|
|
103
|
+
if (!task) {
|
|
104
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
105
|
+
}
|
|
106
|
+
const updatedTask = {
|
|
107
|
+
...task,
|
|
108
|
+
...updates,
|
|
109
|
+
updatedAt: new Date().toISOString(),
|
|
110
|
+
};
|
|
111
|
+
// If marking as completed, add completedAt
|
|
112
|
+
if (updates.status === 'completed' && task.status !== 'completed') {
|
|
113
|
+
updatedTask.completedAt = new Date().toISOString();
|
|
114
|
+
}
|
|
115
|
+
prd.userStories[taskIndex] = updatedTask;
|
|
116
|
+
savePRD(cwd, prd);
|
|
117
|
+
return updatedTask;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Delete a task
|
|
121
|
+
*/
|
|
122
|
+
export function deleteTask(cwd, taskId) {
|
|
123
|
+
const prd = loadPRD(cwd);
|
|
124
|
+
const taskIndex = prd.userStories.findIndex((s) => s.id === taskId);
|
|
125
|
+
if (taskIndex === -1) {
|
|
126
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
127
|
+
}
|
|
128
|
+
prd.userStories.splice(taskIndex, 1);
|
|
129
|
+
savePRD(cwd, prd);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Get all tasks
|
|
133
|
+
*/
|
|
134
|
+
export function getAllTasks(cwd) {
|
|
135
|
+
const prd = loadPRD(cwd);
|
|
136
|
+
return prd.userStories;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Get tasks by status
|
|
140
|
+
*/
|
|
141
|
+
export function getTasksByStatus(cwd, status) {
|
|
142
|
+
const prd = loadPRD(cwd);
|
|
143
|
+
return prd.userStories.filter((s) => s.status === status);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Get the next pending task (highest priority)
|
|
147
|
+
*/
|
|
148
|
+
export function getNextTask(cwd) {
|
|
149
|
+
const pendingTasks = getTasksByStatus(cwd, 'pending');
|
|
150
|
+
if (pendingTasks.length === 0) {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
// Sort by priority (lower number = higher priority)
|
|
154
|
+
pendingTasks.sort((a, b) => a.priority - b.priority);
|
|
155
|
+
return pendingTasks[0] ?? null;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Get a task by ID
|
|
159
|
+
*/
|
|
160
|
+
export function getTaskById(cwd, taskId) {
|
|
161
|
+
const prd = loadPRD(cwd);
|
|
162
|
+
return prd.userStories.find((s) => s.id === taskId) ?? null;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Reorder tasks (update priorities)
|
|
166
|
+
*/
|
|
167
|
+
export function reorderTasks(cwd, taskIds) {
|
|
168
|
+
const prd = loadPRD(cwd);
|
|
169
|
+
// Update priorities based on the new order
|
|
170
|
+
taskIds.forEach((taskId, index) => {
|
|
171
|
+
const task = prd.userStories.find((s) => s.id === taskId);
|
|
172
|
+
if (task) {
|
|
173
|
+
task.priority = index + 1;
|
|
174
|
+
task.updatedAt = new Date().toISOString();
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
savePRD(cwd, prd);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Get status summary
|
|
181
|
+
*/
|
|
182
|
+
export function getStatusSummary(cwd) {
|
|
183
|
+
if (!prdExists(cwd)) {
|
|
184
|
+
return {
|
|
185
|
+
initialized: false,
|
|
186
|
+
totalTasks: 0,
|
|
187
|
+
completedTasks: 0,
|
|
188
|
+
pendingTasks: 0,
|
|
189
|
+
inProgressTasks: 0,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
const prd = loadPRD(cwd);
|
|
193
|
+
const tasks = prd.userStories;
|
|
194
|
+
const completedTasks = tasks.filter((t) => t.status === 'completed').length;
|
|
195
|
+
const pendingTasks = tasks.filter((t) => t.status === 'pending').length;
|
|
196
|
+
const inProgressTasks = tasks.filter((t) => t.status === 'in_progress').length;
|
|
197
|
+
const nextTask = getNextTask(cwd);
|
|
198
|
+
const response = {
|
|
199
|
+
initialized: true,
|
|
200
|
+
project: prd.project,
|
|
201
|
+
branch: prd.branchName,
|
|
202
|
+
totalTasks: tasks.length,
|
|
203
|
+
completedTasks,
|
|
204
|
+
pendingTasks,
|
|
205
|
+
inProgressTasks,
|
|
206
|
+
};
|
|
207
|
+
if (nextTask) {
|
|
208
|
+
response.nextTask = nextTask;
|
|
209
|
+
}
|
|
210
|
+
return response;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Mark a task as in progress
|
|
214
|
+
*/
|
|
215
|
+
export function markTaskInProgress(cwd, taskId) {
|
|
216
|
+
return updateTask(cwd, taskId, { status: 'in_progress' });
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Mark a task as completed
|
|
220
|
+
*/
|
|
221
|
+
export function markTaskCompleted(cwd, taskId, notes) {
|
|
222
|
+
const updates = {
|
|
223
|
+
status: 'completed',
|
|
224
|
+
};
|
|
225
|
+
if (notes) {
|
|
226
|
+
updates.notes = notes;
|
|
227
|
+
}
|
|
228
|
+
return updateTask(cwd, taskId, updates);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Mark a task as failed
|
|
232
|
+
*/
|
|
233
|
+
export function markTaskFailed(cwd, taskId, error) {
|
|
234
|
+
const updates = {
|
|
235
|
+
status: 'failed',
|
|
236
|
+
};
|
|
237
|
+
if (error) {
|
|
238
|
+
updates.notes = error;
|
|
239
|
+
}
|
|
240
|
+
return updateTask(cwd, taskId, updates);
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Reset a failed task back to pending
|
|
244
|
+
*/
|
|
245
|
+
export function resetTask(cwd, taskId) {
|
|
246
|
+
// Get the current task to clear notes
|
|
247
|
+
const prd = loadPRD(cwd);
|
|
248
|
+
const task = prd.userStories.find((s) => s.id === taskId);
|
|
249
|
+
if (!task) {
|
|
250
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
251
|
+
}
|
|
252
|
+
// Remove notes and set to pending
|
|
253
|
+
delete task.notes;
|
|
254
|
+
task.status = 'pending';
|
|
255
|
+
task.updatedAt = new Date().toISOString();
|
|
256
|
+
savePRD(cwd, prd);
|
|
257
|
+
return task;
|
|
258
|
+
}
|
|
259
|
+
//# sourceMappingURL=tasks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tasks.js","sourceRoot":"","sources":["../../src/lib/tasks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template loading and processing for Ralph Wiggum UI
|
|
3
|
+
*/
|
|
4
|
+
import type { Config } from '../types/index.js';
|
|
5
|
+
/**
|
|
6
|
+
* Load a template file
|
|
7
|
+
*/
|
|
8
|
+
export declare function loadTemplate(templateName: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* Process template variables
|
|
11
|
+
*/
|
|
12
|
+
export declare function processTemplate(template: string, variables: Record<string, string>): string;
|
|
13
|
+
/**
|
|
14
|
+
* Generate the AGENTS.md file from template
|
|
15
|
+
*/
|
|
16
|
+
export declare function generateAgentsFile(config: Config): string;
|
|
17
|
+
/**
|
|
18
|
+
* Generate the prompt.md file from template
|
|
19
|
+
*/
|
|
20
|
+
export declare function generatePromptFile(): string;
|
|
21
|
+
/**
|
|
22
|
+
* Write all template files to the Ralph directory
|
|
23
|
+
*/
|
|
24
|
+
export declare function writeTemplateFiles(cwd: string, config: Config, branch: string): void;
|
|
25
|
+
//# sourceMappingURL=templates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/lib/templates.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AA+BhD;;GAEG;AACH,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAGzD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,MAAM,CASR;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAczD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACb,IAAI,CAmBN"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template loading and processing for Ralph Wiggum UI
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, writeFileSync } from 'fs';
|
|
5
|
+
import { join, dirname } from 'path';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
import { AGENTS_FILE, PROMPT_FILE, PRD_FILE, } from '../types/index.js';
|
|
8
|
+
import { getRalphFilePath } from './config.js';
|
|
9
|
+
import { createEmptyPRD } from './tasks.js';
|
|
10
|
+
import { createProgressFile } from './progress.js';
|
|
11
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
+
const __dirname = dirname(__filename);
|
|
13
|
+
/**
|
|
14
|
+
* Get the path to a template file
|
|
15
|
+
*/
|
|
16
|
+
function getTemplatePath(templateName) {
|
|
17
|
+
// Templates are at the package root in ./templates/
|
|
18
|
+
// From dist/lib/, go up two levels to reach package root
|
|
19
|
+
const rootPath = join(__dirname, '..', '..', 'templates', templateName);
|
|
20
|
+
// In development, templates might be in src/templates
|
|
21
|
+
const srcPath = join(__dirname, '..', 'templates', templateName);
|
|
22
|
+
try {
|
|
23
|
+
readFileSync(rootPath);
|
|
24
|
+
return rootPath;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return srcPath;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Load a template file
|
|
32
|
+
*/
|
|
33
|
+
export function loadTemplate(templateName) {
|
|
34
|
+
const templatePath = getTemplatePath(templateName);
|
|
35
|
+
return readFileSync(templatePath, 'utf-8');
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Process template variables
|
|
39
|
+
*/
|
|
40
|
+
export function processTemplate(template, variables) {
|
|
41
|
+
let result = template;
|
|
42
|
+
for (const [key, value] of Object.entries(variables)) {
|
|
43
|
+
const pattern = new RegExp(`\\{\\{${key}\\}\\}`, 'g');
|
|
44
|
+
result = result.replace(pattern, value);
|
|
45
|
+
}
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Generate the AGENTS.md file from template
|
|
50
|
+
*/
|
|
51
|
+
export function generateAgentsFile(config) {
|
|
52
|
+
const template = loadTemplate('AGENTS.md');
|
|
53
|
+
const variables = {
|
|
54
|
+
INSTALL_COMMAND: 'npm install',
|
|
55
|
+
DEV_COMMAND: 'npm run dev',
|
|
56
|
+
BUILD_COMMAND: config.commands.build || 'npm run build',
|
|
57
|
+
TEST_COMMAND: config.commands.test || 'npm test',
|
|
58
|
+
TYPECHECK_COMMAND: config.commands.typecheck || 'npm run typecheck',
|
|
59
|
+
LINT_COMMAND: config.commands.lint || 'npm run lint',
|
|
60
|
+
SOURCE_DIR: config.sourceDir,
|
|
61
|
+
};
|
|
62
|
+
return processTemplate(template, variables);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Generate the prompt.md file from template
|
|
66
|
+
*/
|
|
67
|
+
export function generatePromptFile() {
|
|
68
|
+
return loadTemplate('prompt.md');
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Write all template files to the Ralph directory
|
|
72
|
+
*/
|
|
73
|
+
export function writeTemplateFiles(cwd, config, branch) {
|
|
74
|
+
// Write AGENTS.md
|
|
75
|
+
const agentsContent = generateAgentsFile(config);
|
|
76
|
+
writeFileSync(getRalphFilePath(cwd, AGENTS_FILE), agentsContent, 'utf-8');
|
|
77
|
+
// Write prompt.md
|
|
78
|
+
const promptContent = generatePromptFile();
|
|
79
|
+
writeFileSync(getRalphFilePath(cwd, PROMPT_FILE), promptContent, 'utf-8');
|
|
80
|
+
// Write empty prd.json
|
|
81
|
+
const prd = createEmptyPRD(config.project, branch);
|
|
82
|
+
writeFileSync(getRalphFilePath(cwd, PRD_FILE), JSON.stringify(prd, null, 2), 'utf-8');
|
|
83
|
+
// Write progress.txt
|
|
84
|
+
createProgressFile(cwd, config.project);
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=templates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/lib/templates.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/server/api.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAejC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGhD,wBAAgB,eAAe,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAiR9D"}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ralph Wiggum UI - REST API Routes
|
|
3
|
+
*/
|
|
4
|
+
import { Router } from 'express';
|
|
5
|
+
import { getAllTasks, getTasksByStatus, getNextTask, addTask, updateTask, deleteTask, reorderTasks, getStatusSummary, loadConfig, getCurrentBranch, listLogFiles, readLogFile, } from '../lib/index.js';
|
|
6
|
+
export function createApiRouter(context) {
|
|
7
|
+
const router = Router();
|
|
8
|
+
const { cwd, taskRunner } = context;
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// Status & Config
|
|
11
|
+
// ============================================================================
|
|
12
|
+
/**
|
|
13
|
+
* GET /api/status
|
|
14
|
+
* Get overall project status
|
|
15
|
+
*/
|
|
16
|
+
router.get('/status', (_req, res) => {
|
|
17
|
+
try {
|
|
18
|
+
const status = getStatusSummary(cwd);
|
|
19
|
+
res.json({ success: true, data: status });
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
23
|
+
res.status(500).json({ success: false, error: message });
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
/**
|
|
27
|
+
* GET /api/config
|
|
28
|
+
* Get current configuration
|
|
29
|
+
*/
|
|
30
|
+
router.get('/config', (_req, res) => {
|
|
31
|
+
try {
|
|
32
|
+
const config = loadConfig(cwd);
|
|
33
|
+
const branch = getCurrentBranch(cwd);
|
|
34
|
+
res.json({ success: true, data: { config, branch } });
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
38
|
+
res.status(500).json({ success: false, error: message });
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
// ============================================================================
|
|
42
|
+
// Tasks CRUD
|
|
43
|
+
// ============================================================================
|
|
44
|
+
/**
|
|
45
|
+
* GET /api/tasks
|
|
46
|
+
* Get all tasks, optionally filtered by status
|
|
47
|
+
*/
|
|
48
|
+
router.get('/tasks', (req, res) => {
|
|
49
|
+
try {
|
|
50
|
+
const status = req.query.status;
|
|
51
|
+
let tasks;
|
|
52
|
+
if (status) {
|
|
53
|
+
tasks = getTasksByStatus(cwd, status);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
tasks = getAllTasks(cwd);
|
|
57
|
+
}
|
|
58
|
+
res.json({ success: true, data: tasks });
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
62
|
+
res.status(500).json({ success: false, error: message });
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
/**
|
|
66
|
+
* GET /api/tasks/next
|
|
67
|
+
* Get the next task to work on
|
|
68
|
+
*/
|
|
69
|
+
router.get('/tasks/next', (_req, res) => {
|
|
70
|
+
try {
|
|
71
|
+
const task = getNextTask(cwd);
|
|
72
|
+
res.json({ success: true, data: task });
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
76
|
+
res.status(500).json({ success: false, error: message });
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
/**
|
|
80
|
+
* POST /api/tasks
|
|
81
|
+
* Create a new task
|
|
82
|
+
*/
|
|
83
|
+
router.post('/tasks', (req, res) => {
|
|
84
|
+
try {
|
|
85
|
+
const { title, description, acceptanceCriteria } = req.body;
|
|
86
|
+
if (!title) {
|
|
87
|
+
res.status(400).json({ success: false, error: 'Title is required' });
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const task = addTask(cwd, {
|
|
91
|
+
title,
|
|
92
|
+
description: description || '',
|
|
93
|
+
acceptanceCriteria: acceptanceCriteria || [],
|
|
94
|
+
});
|
|
95
|
+
// Notify connected clients
|
|
96
|
+
context.io.emit('task_created', task);
|
|
97
|
+
res.json({ success: true, data: task });
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
101
|
+
res.status(500).json({ success: false, error: message });
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
/**
|
|
105
|
+
* PUT /api/tasks/:id
|
|
106
|
+
* Update a task
|
|
107
|
+
*/
|
|
108
|
+
router.put('/tasks/:id', (req, res) => {
|
|
109
|
+
try {
|
|
110
|
+
const { id } = req.params;
|
|
111
|
+
const updates = req.body;
|
|
112
|
+
const task = updateTask(cwd, id, updates);
|
|
113
|
+
// Notify connected clients
|
|
114
|
+
context.io.emit('task_updated', task);
|
|
115
|
+
res.json({ success: true, data: task });
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
119
|
+
res.status(500).json({ success: false, error: message });
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
/**
|
|
123
|
+
* DELETE /api/tasks/:id
|
|
124
|
+
* Delete a task
|
|
125
|
+
*/
|
|
126
|
+
router.delete('/tasks/:id', (req, res) => {
|
|
127
|
+
try {
|
|
128
|
+
const { id } = req.params;
|
|
129
|
+
deleteTask(cwd, id);
|
|
130
|
+
// Notify connected clients
|
|
131
|
+
context.io.emit('task_deleted', { id });
|
|
132
|
+
res.json({ success: true });
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
136
|
+
res.status(500).json({ success: false, error: message });
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
/**
|
|
140
|
+
* POST /api/tasks/reorder
|
|
141
|
+
* Reorder tasks (for drag-and-drop)
|
|
142
|
+
*/
|
|
143
|
+
router.post('/tasks/reorder', (req, res) => {
|
|
144
|
+
try {
|
|
145
|
+
const { taskIds } = req.body;
|
|
146
|
+
if (!Array.isArray(taskIds)) {
|
|
147
|
+
res.status(400).json({ success: false, error: 'taskIds must be an array' });
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
reorderTasks(cwd, taskIds);
|
|
151
|
+
// Notify connected clients
|
|
152
|
+
context.io.emit('tasks_reordered', { taskIds });
|
|
153
|
+
res.json({ success: true });
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
157
|
+
res.status(500).json({ success: false, error: message });
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
// ============================================================================
|
|
161
|
+
// Task Execution
|
|
162
|
+
// ============================================================================
|
|
163
|
+
/**
|
|
164
|
+
* POST /api/run
|
|
165
|
+
* Start running tasks
|
|
166
|
+
*/
|
|
167
|
+
router.post('/run', (req, res) => {
|
|
168
|
+
try {
|
|
169
|
+
const { count, all, stopOnFailure } = req.body;
|
|
170
|
+
if (taskRunner.isRunning()) {
|
|
171
|
+
res.status(400).json({ success: false, error: 'Already running tasks' });
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
let taskCount;
|
|
175
|
+
if (all) {
|
|
176
|
+
taskCount = 'all';
|
|
177
|
+
}
|
|
178
|
+
else if (count && typeof count === 'number') {
|
|
179
|
+
taskCount = count;
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
taskCount = 1;
|
|
183
|
+
}
|
|
184
|
+
taskRunner.start({
|
|
185
|
+
taskCount,
|
|
186
|
+
stopOnFailure: stopOnFailure !== false,
|
|
187
|
+
notifications: true,
|
|
188
|
+
});
|
|
189
|
+
res.json({ success: true, data: taskRunner.getState() });
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
193
|
+
res.status(500).json({ success: false, error: message });
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
/**
|
|
197
|
+
* POST /api/run/stop
|
|
198
|
+
* Stop running tasks
|
|
199
|
+
*/
|
|
200
|
+
router.post('/run/stop', (_req, res) => {
|
|
201
|
+
try {
|
|
202
|
+
taskRunner.stop();
|
|
203
|
+
res.json({ success: true });
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
207
|
+
res.status(500).json({ success: false, error: message });
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
/**
|
|
211
|
+
* GET /api/run/status
|
|
212
|
+
* Get current execution status
|
|
213
|
+
*/
|
|
214
|
+
router.get('/run/status', (_req, res) => {
|
|
215
|
+
try {
|
|
216
|
+
const state = taskRunner.getState();
|
|
217
|
+
res.json({ success: true, data: state });
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
221
|
+
res.status(500).json({ success: false, error: message });
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
// ============================================================================
|
|
225
|
+
// Logs
|
|
226
|
+
// ============================================================================
|
|
227
|
+
/**
|
|
228
|
+
* GET /api/logs
|
|
229
|
+
* List all log files
|
|
230
|
+
*/
|
|
231
|
+
router.get('/logs', (_req, res) => {
|
|
232
|
+
try {
|
|
233
|
+
const logs = listLogFiles(cwd);
|
|
234
|
+
res.json({ success: true, data: logs });
|
|
235
|
+
}
|
|
236
|
+
catch (error) {
|
|
237
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
238
|
+
res.status(500).json({ success: false, error: message });
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
/**
|
|
242
|
+
* GET /api/logs/:filename
|
|
243
|
+
* Read a specific log file
|
|
244
|
+
*/
|
|
245
|
+
router.get('/logs/:filename', (req, res) => {
|
|
246
|
+
try {
|
|
247
|
+
const { filename } = req.params;
|
|
248
|
+
const content = readLogFile(cwd, filename);
|
|
249
|
+
res.json({ success: true, data: { filename, content } });
|
|
250
|
+
}
|
|
251
|
+
catch (error) {
|
|
252
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
253
|
+
res.status(500).json({ success: false, error: message });
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
return router;
|
|
257
|
+
}
|
|
258
|
+
//# sourceMappingURL=api.js.map
|