ralphctl 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -24
- package/dist/add-HGJCLWED.mjs +14 -0
- package/dist/add-MRGCS3US.mjs +14 -0
- package/dist/chunk-6PYTKGB5.mjs +316 -0
- package/dist/chunk-7TG3EAQ2.mjs +20 -0
- package/dist/chunk-EKMZZRWI.mjs +521 -0
- package/dist/chunk-JON4GCLR.mjs +59 -0
- package/dist/chunk-LOR7QBXX.mjs +3683 -0
- package/dist/chunk-MNMQC36F.mjs +556 -0
- package/dist/chunk-MRKOFVTM.mjs +537 -0
- package/dist/chunk-NTWO2LXB.mjs +52 -0
- package/dist/chunk-QBXHAXHI.mjs +562 -0
- package/dist/chunk-WGHJI3OI.mjs +214 -0
- package/dist/cli.mjs +4245 -0
- package/dist/create-MG7E7PLQ.mjs +10 -0
- package/dist/handle-UG5M2OON.mjs +22 -0
- package/dist/multiline-OHSNFCRG.mjs +40 -0
- package/dist/project-NT3L4FTB.mjs +28 -0
- package/dist/resolver-WSFWKACM.mjs +153 -0
- package/dist/sprint-4VHDLGFN.mjs +37 -0
- package/dist/wizard-LRELAN2J.mjs +196 -0
- package/package.json +19 -28
- package/CHANGELOG.md +0 -94
- package/bin/ralphctl +0 -13
- package/src/ai/executor.ts +0 -973
- package/src/ai/lifecycle.ts +0 -45
- package/src/ai/parser.ts +0 -40
- package/src/ai/permissions.ts +0 -207
- package/src/ai/process-manager.ts +0 -248
- package/src/ai/prompts/index.ts +0 -89
- package/src/ai/rate-limiter.ts +0 -89
- package/src/ai/runner.ts +0 -478
- package/src/ai/session.ts +0 -319
- package/src/ai/task-context.ts +0 -270
- package/src/cli-metadata.ts +0 -7
- package/src/cli.ts +0 -65
- package/src/commands/completion/index.ts +0 -33
- package/src/commands/config/config.ts +0 -58
- package/src/commands/config/index.ts +0 -33
- package/src/commands/dashboard/dashboard.ts +0 -5
- package/src/commands/dashboard/index.ts +0 -6
- package/src/commands/doctor/doctor.ts +0 -271
- package/src/commands/doctor/index.ts +0 -25
- package/src/commands/progress/index.ts +0 -25
- package/src/commands/progress/log.ts +0 -64
- package/src/commands/progress/show.ts +0 -14
- package/src/commands/project/add.ts +0 -336
- package/src/commands/project/index.ts +0 -104
- package/src/commands/project/list.ts +0 -31
- package/src/commands/project/remove.ts +0 -43
- package/src/commands/project/repo.ts +0 -118
- package/src/commands/project/show.ts +0 -49
- package/src/commands/sprint/close.ts +0 -180
- package/src/commands/sprint/context.ts +0 -109
- package/src/commands/sprint/create.ts +0 -60
- package/src/commands/sprint/current.ts +0 -75
- package/src/commands/sprint/delete.ts +0 -72
- package/src/commands/sprint/health.ts +0 -229
- package/src/commands/sprint/ideate.ts +0 -496
- package/src/commands/sprint/index.ts +0 -226
- package/src/commands/sprint/list.ts +0 -86
- package/src/commands/sprint/plan-utils.ts +0 -207
- package/src/commands/sprint/plan.ts +0 -549
- package/src/commands/sprint/refine.ts +0 -359
- package/src/commands/sprint/requirements.ts +0 -58
- package/src/commands/sprint/show.ts +0 -140
- package/src/commands/sprint/start.ts +0 -119
- package/src/commands/sprint/switch.ts +0 -20
- package/src/commands/task/add.ts +0 -316
- package/src/commands/task/import.ts +0 -150
- package/src/commands/task/index.ts +0 -123
- package/src/commands/task/list.ts +0 -145
- package/src/commands/task/next.ts +0 -45
- package/src/commands/task/remove.ts +0 -47
- package/src/commands/task/reorder.ts +0 -45
- package/src/commands/task/show.ts +0 -111
- package/src/commands/task/status.ts +0 -99
- package/src/commands/ticket/add.ts +0 -265
- package/src/commands/ticket/edit.ts +0 -166
- package/src/commands/ticket/index.ts +0 -114
- package/src/commands/ticket/list.ts +0 -128
- package/src/commands/ticket/refine-utils.ts +0 -89
- package/src/commands/ticket/refine.ts +0 -268
- package/src/commands/ticket/remove.ts +0 -48
- package/src/commands/ticket/show.ts +0 -74
- package/src/completion/handle.ts +0 -30
- package/src/completion/resolver.ts +0 -241
- package/src/interactive/dashboard.ts +0 -268
- package/src/interactive/escapable.ts +0 -81
- package/src/interactive/file-browser.ts +0 -153
- package/src/interactive/index.ts +0 -429
- package/src/interactive/menu.ts +0 -403
- package/src/interactive/selectors.ts +0 -273
- package/src/interactive/wizard.ts +0 -221
- package/src/providers/claude.ts +0 -53
- package/src/providers/copilot.ts +0 -86
- package/src/providers/index.ts +0 -43
- package/src/providers/types.ts +0 -85
- package/src/schemas/index.ts +0 -130
- package/src/store/config.ts +0 -74
- package/src/store/progress.ts +0 -230
- package/src/store/project.ts +0 -276
- package/src/store/sprint.ts +0 -229
- package/src/store/task.ts +0 -443
- package/src/store/ticket.ts +0 -178
- package/src/theme/index.ts +0 -215
- package/src/theme/ui.ts +0 -872
- package/src/utils/detect-scripts.ts +0 -247
- package/src/utils/editor-input.ts +0 -41
- package/src/utils/editor.ts +0 -37
- package/src/utils/exit-codes.ts +0 -27
- package/src/utils/file-lock.ts +0 -135
- package/src/utils/git.ts +0 -185
- package/src/utils/ids.ts +0 -37
- package/src/utils/issue-fetch.ts +0 -244
- package/src/utils/json-extract.ts +0 -62
- package/src/utils/multiline.ts +0 -61
- package/src/utils/path-selector.ts +0 -236
- package/src/utils/paths.ts +0 -108
- package/src/utils/provider.ts +0 -34
- package/src/utils/requirements-export.ts +0 -63
- package/src/utils/storage.ts +0 -107
- package/tsconfig.json +0 -25
- /package/{src/ai → dist}/prompts/ideate-auto.md +0 -0
- /package/{src/ai → dist}/prompts/ideate.md +0 -0
- /package/{src/ai → dist}/prompts/plan-auto.md +0 -0
- /package/{src/ai → dist}/prompts/plan-common.md +0 -0
- /package/{src/ai → dist}/prompts/plan-interactive.md +0 -0
- /package/{src/ai → dist}/prompts/task-execution.md +0 -0
- /package/{src/ai → dist}/prompts/ticket-refine.md +0 -0
|
@@ -1,229 +0,0 @@
|
|
|
1
|
-
import { getCurrentSprintOrThrow } from '@src/store/sprint.ts';
|
|
2
|
-
import { getTasks } from '@src/store/task.ts';
|
|
3
|
-
import { colors, getQuoteForContext } from '@src/theme/index.ts';
|
|
4
|
-
import { icons, log, printHeader, progressBar, renderCard, showError } from '@src/theme/ui.ts';
|
|
5
|
-
import type { Sprint, Task } from '@src/schemas/index.ts';
|
|
6
|
-
import { getCurrentBranch } from '@src/utils/git.ts';
|
|
7
|
-
|
|
8
|
-
// ============================================================================
|
|
9
|
-
// Health Check Types
|
|
10
|
-
// ============================================================================
|
|
11
|
-
|
|
12
|
-
interface HealthCheck {
|
|
13
|
-
name: string;
|
|
14
|
-
status: 'pass' | 'warn' | 'fail';
|
|
15
|
-
items: string[];
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// ============================================================================
|
|
19
|
-
// Health Check Runners
|
|
20
|
-
// ============================================================================
|
|
21
|
-
|
|
22
|
-
function checkBlockers(tasks: Task[]): HealthCheck {
|
|
23
|
-
const doneTasks = new Set(tasks.filter((t) => t.status === 'done').map((t) => t.id));
|
|
24
|
-
const allTaskIds = new Set(tasks.map((t) => t.id));
|
|
25
|
-
|
|
26
|
-
const blocked: string[] = [];
|
|
27
|
-
for (const task of tasks) {
|
|
28
|
-
if (task.status === 'done') continue;
|
|
29
|
-
const unresolvedDeps = task.blockedBy.filter((depId) => allTaskIds.has(depId) && !doneTasks.has(depId));
|
|
30
|
-
if (unresolvedDeps.length > 0) {
|
|
31
|
-
blocked.push(`${task.name} ${colors.muted(`(${task.id})`)} blocked by ${unresolvedDeps.join(', ')}`);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return {
|
|
36
|
-
name: 'Blockers',
|
|
37
|
-
status: blocked.length > 0 ? 'fail' : 'pass',
|
|
38
|
-
items: blocked,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function checkStaleTasks(tasks: Task[]): HealthCheck {
|
|
43
|
-
const stale = tasks.filter((t) => t.status === 'in_progress');
|
|
44
|
-
const items = stale.map((t) => `${t.name} ${colors.muted(`(${t.id})`)}`);
|
|
45
|
-
|
|
46
|
-
return {
|
|
47
|
-
name: 'Stale Tasks',
|
|
48
|
-
status: items.length > 0 ? 'warn' : 'pass',
|
|
49
|
-
items,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function checkOrphanedDeps(tasks: Task[]): HealthCheck {
|
|
54
|
-
const allTaskIds = new Set(tasks.map((t) => t.id));
|
|
55
|
-
const orphaned: string[] = [];
|
|
56
|
-
|
|
57
|
-
for (const task of tasks) {
|
|
58
|
-
const missingDeps = task.blockedBy.filter((depId) => !allTaskIds.has(depId));
|
|
59
|
-
if (missingDeps.length > 0) {
|
|
60
|
-
orphaned.push(`${task.name} ${colors.muted(`(${task.id})`)} references missing: ${missingDeps.join(', ')}`);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return {
|
|
65
|
-
name: 'Orphaned Dependencies',
|
|
66
|
-
status: orphaned.length > 0 ? 'fail' : 'pass',
|
|
67
|
-
items: orphaned,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function checkTicketsWithoutTasks(sprint: Sprint, tasks: Task[]): HealthCheck {
|
|
72
|
-
const ticketIdsWithTasks = new Set(tasks.map((t) => t.ticketId).filter(Boolean));
|
|
73
|
-
const orphanedTickets = sprint.tickets.filter((t) => !ticketIdsWithTasks.has(t.id));
|
|
74
|
-
const items = orphanedTickets.map((t) => `${t.title} ${colors.muted(`(${t.id})`)}`);
|
|
75
|
-
|
|
76
|
-
return {
|
|
77
|
-
name: 'Tickets Without Tasks',
|
|
78
|
-
status: items.length > 0 ? 'warn' : 'pass',
|
|
79
|
-
items,
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function checkDuplicateOrders(tasks: Task[]): HealthCheck {
|
|
84
|
-
const orderCounts = new Map<number, string[]>();
|
|
85
|
-
for (const task of tasks) {
|
|
86
|
-
const existing = orderCounts.get(task.order) ?? [];
|
|
87
|
-
existing.push(`${task.name} ${colors.muted(`(${task.id})`)}`);
|
|
88
|
-
orderCounts.set(task.order, existing);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const items: string[] = [];
|
|
92
|
-
for (const [order, taskNames] of orderCounts) {
|
|
93
|
-
if (taskNames.length > 1) {
|
|
94
|
-
items.push(`Order ${String(order)}: ${taskNames.join(', ')}`);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return {
|
|
99
|
-
name: 'Duplicate Task Orders',
|
|
100
|
-
status: items.length > 0 ? 'warn' : 'pass',
|
|
101
|
-
items,
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function checkPendingRequirementsOnActive(sprint: Sprint): HealthCheck {
|
|
106
|
-
if (sprint.status !== 'active') {
|
|
107
|
-
return { name: 'Pending Requirements', status: 'pass', items: [] };
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const pending = sprint.tickets.filter((t) => t.requirementStatus === 'pending');
|
|
111
|
-
const items = pending.map((t) => `${t.title} ${colors.muted(`(${t.id})`)} — refine before planning`);
|
|
112
|
-
|
|
113
|
-
return {
|
|
114
|
-
name: 'Pending Requirements',
|
|
115
|
-
status: items.length > 0 ? 'warn' : 'pass',
|
|
116
|
-
items,
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function checkBranchConsistency(sprint: Sprint, tasks: Task[]): HealthCheck {
|
|
121
|
-
if (!sprint.branch) {
|
|
122
|
-
return { name: 'Branch Consistency', status: 'pass', items: [] };
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const remainingTasks = tasks.filter((t) => t.status !== 'done');
|
|
126
|
-
const uniquePaths = [...new Set(remainingTasks.map((t) => t.projectPath))];
|
|
127
|
-
const items: string[] = [];
|
|
128
|
-
|
|
129
|
-
for (const projectPath of uniquePaths) {
|
|
130
|
-
try {
|
|
131
|
-
const current = getCurrentBranch(projectPath);
|
|
132
|
-
if (current !== sprint.branch) {
|
|
133
|
-
items.push(`${projectPath} — on '${current}', expected '${sprint.branch}'`);
|
|
134
|
-
}
|
|
135
|
-
} catch {
|
|
136
|
-
items.push(`${projectPath} — unable to determine branch`);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return {
|
|
141
|
-
name: 'Branch Consistency',
|
|
142
|
-
status: items.length > 0 ? 'warn' : 'pass',
|
|
143
|
-
items,
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
function checkTasksWithoutSteps(tasks: Task[]): HealthCheck {
|
|
148
|
-
const empty = tasks.filter((t) => t.steps.length === 0);
|
|
149
|
-
const items = empty.map((t) => `${t.name} ${colors.muted(`(${t.id})`)}`);
|
|
150
|
-
|
|
151
|
-
return {
|
|
152
|
-
name: 'Tasks Without Steps',
|
|
153
|
-
status: items.length > 0 ? 'warn' : 'pass',
|
|
154
|
-
items,
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// ============================================================================
|
|
159
|
-
// Card Rendering
|
|
160
|
-
// ============================================================================
|
|
161
|
-
|
|
162
|
-
function renderCheckCard(check: HealthCheck): string {
|
|
163
|
-
const colorFn = check.status === 'pass' ? colors.success : check.status === 'warn' ? colors.warning : colors.error;
|
|
164
|
-
|
|
165
|
-
const statusIcon = check.status === 'pass' ? icons.success : check.status === 'warn' ? icons.warning : icons.error;
|
|
166
|
-
|
|
167
|
-
const lines: string[] = [];
|
|
168
|
-
|
|
169
|
-
if (check.items.length === 0) {
|
|
170
|
-
lines.push(colors.success(`${icons.success} No issues found`));
|
|
171
|
-
} else {
|
|
172
|
-
for (const item of check.items) {
|
|
173
|
-
lines.push(`${colorFn(statusIcon)} ${item}`);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
return renderCard(check.name, lines, { colorFn });
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// ============================================================================
|
|
181
|
-
// Main Command
|
|
182
|
-
// ============================================================================
|
|
183
|
-
|
|
184
|
-
export async function sprintHealthCommand(): Promise<void> {
|
|
185
|
-
let sprint: Sprint;
|
|
186
|
-
try {
|
|
187
|
-
sprint = await getCurrentSprintOrThrow();
|
|
188
|
-
} catch (err) {
|
|
189
|
-
if (err instanceof Error) {
|
|
190
|
-
showError(err.message);
|
|
191
|
-
} else {
|
|
192
|
-
showError('Unknown error');
|
|
193
|
-
}
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const tasks = await getTasks(sprint.id);
|
|
198
|
-
|
|
199
|
-
printHeader(`Sprint Health: ${sprint.name}`, icons.sprint);
|
|
200
|
-
|
|
201
|
-
const checks: HealthCheck[] = [
|
|
202
|
-
checkBlockers(tasks),
|
|
203
|
-
checkStaleTasks(tasks),
|
|
204
|
-
checkOrphanedDeps(tasks),
|
|
205
|
-
checkTicketsWithoutTasks(sprint, tasks),
|
|
206
|
-
checkTasksWithoutSteps(tasks),
|
|
207
|
-
checkDuplicateOrders(tasks),
|
|
208
|
-
checkPendingRequirementsOnActive(sprint),
|
|
209
|
-
checkBranchConsistency(sprint, tasks),
|
|
210
|
-
];
|
|
211
|
-
|
|
212
|
-
for (const check of checks) {
|
|
213
|
-
console.log(renderCheckCard(check));
|
|
214
|
-
log.newline();
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// Health score
|
|
218
|
-
const passing = checks.filter((c) => c.status === 'pass').length;
|
|
219
|
-
const total = checks.length;
|
|
220
|
-
const bar = progressBar(passing, total);
|
|
221
|
-
log.info(`Health Score: ${bar} ${colors.muted(`${String(passing)}/${String(total)} checks passing`)}`);
|
|
222
|
-
|
|
223
|
-
// Ralph quote
|
|
224
|
-
log.newline();
|
|
225
|
-
const category = passing === total ? 'success' : 'error';
|
|
226
|
-
const quote = getQuoteForContext(category);
|
|
227
|
-
console.log(colors.muted(` "${quote}"`));
|
|
228
|
-
log.newline();
|
|
229
|
-
}
|