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.
Files changed (130) hide show
  1. package/README.md +58 -24
  2. package/dist/add-HGJCLWED.mjs +14 -0
  3. package/dist/add-MRGCS3US.mjs +14 -0
  4. package/dist/chunk-6PYTKGB5.mjs +316 -0
  5. package/dist/chunk-7TG3EAQ2.mjs +20 -0
  6. package/dist/chunk-EKMZZRWI.mjs +521 -0
  7. package/dist/chunk-JON4GCLR.mjs +59 -0
  8. package/dist/chunk-LOR7QBXX.mjs +3683 -0
  9. package/dist/chunk-MNMQC36F.mjs +556 -0
  10. package/dist/chunk-MRKOFVTM.mjs +537 -0
  11. package/dist/chunk-NTWO2LXB.mjs +52 -0
  12. package/dist/chunk-QBXHAXHI.mjs +562 -0
  13. package/dist/chunk-WGHJI3OI.mjs +214 -0
  14. package/dist/cli.mjs +4245 -0
  15. package/dist/create-MG7E7PLQ.mjs +10 -0
  16. package/dist/handle-UG5M2OON.mjs +22 -0
  17. package/dist/multiline-OHSNFCRG.mjs +40 -0
  18. package/dist/project-NT3L4FTB.mjs +28 -0
  19. package/dist/resolver-WSFWKACM.mjs +153 -0
  20. package/dist/sprint-4VHDLGFN.mjs +37 -0
  21. package/dist/wizard-LRELAN2J.mjs +196 -0
  22. package/package.json +19 -28
  23. package/CHANGELOG.md +0 -94
  24. package/bin/ralphctl +0 -13
  25. package/src/ai/executor.ts +0 -973
  26. package/src/ai/lifecycle.ts +0 -45
  27. package/src/ai/parser.ts +0 -40
  28. package/src/ai/permissions.ts +0 -207
  29. package/src/ai/process-manager.ts +0 -248
  30. package/src/ai/prompts/index.ts +0 -89
  31. package/src/ai/rate-limiter.ts +0 -89
  32. package/src/ai/runner.ts +0 -478
  33. package/src/ai/session.ts +0 -319
  34. package/src/ai/task-context.ts +0 -270
  35. package/src/cli-metadata.ts +0 -7
  36. package/src/cli.ts +0 -65
  37. package/src/commands/completion/index.ts +0 -33
  38. package/src/commands/config/config.ts +0 -58
  39. package/src/commands/config/index.ts +0 -33
  40. package/src/commands/dashboard/dashboard.ts +0 -5
  41. package/src/commands/dashboard/index.ts +0 -6
  42. package/src/commands/doctor/doctor.ts +0 -271
  43. package/src/commands/doctor/index.ts +0 -25
  44. package/src/commands/progress/index.ts +0 -25
  45. package/src/commands/progress/log.ts +0 -64
  46. package/src/commands/progress/show.ts +0 -14
  47. package/src/commands/project/add.ts +0 -336
  48. package/src/commands/project/index.ts +0 -104
  49. package/src/commands/project/list.ts +0 -31
  50. package/src/commands/project/remove.ts +0 -43
  51. package/src/commands/project/repo.ts +0 -118
  52. package/src/commands/project/show.ts +0 -49
  53. package/src/commands/sprint/close.ts +0 -180
  54. package/src/commands/sprint/context.ts +0 -109
  55. package/src/commands/sprint/create.ts +0 -60
  56. package/src/commands/sprint/current.ts +0 -75
  57. package/src/commands/sprint/delete.ts +0 -72
  58. package/src/commands/sprint/health.ts +0 -229
  59. package/src/commands/sprint/ideate.ts +0 -496
  60. package/src/commands/sprint/index.ts +0 -226
  61. package/src/commands/sprint/list.ts +0 -86
  62. package/src/commands/sprint/plan-utils.ts +0 -207
  63. package/src/commands/sprint/plan.ts +0 -549
  64. package/src/commands/sprint/refine.ts +0 -359
  65. package/src/commands/sprint/requirements.ts +0 -58
  66. package/src/commands/sprint/show.ts +0 -140
  67. package/src/commands/sprint/start.ts +0 -119
  68. package/src/commands/sprint/switch.ts +0 -20
  69. package/src/commands/task/add.ts +0 -316
  70. package/src/commands/task/import.ts +0 -150
  71. package/src/commands/task/index.ts +0 -123
  72. package/src/commands/task/list.ts +0 -145
  73. package/src/commands/task/next.ts +0 -45
  74. package/src/commands/task/remove.ts +0 -47
  75. package/src/commands/task/reorder.ts +0 -45
  76. package/src/commands/task/show.ts +0 -111
  77. package/src/commands/task/status.ts +0 -99
  78. package/src/commands/ticket/add.ts +0 -265
  79. package/src/commands/ticket/edit.ts +0 -166
  80. package/src/commands/ticket/index.ts +0 -114
  81. package/src/commands/ticket/list.ts +0 -128
  82. package/src/commands/ticket/refine-utils.ts +0 -89
  83. package/src/commands/ticket/refine.ts +0 -268
  84. package/src/commands/ticket/remove.ts +0 -48
  85. package/src/commands/ticket/show.ts +0 -74
  86. package/src/completion/handle.ts +0 -30
  87. package/src/completion/resolver.ts +0 -241
  88. package/src/interactive/dashboard.ts +0 -268
  89. package/src/interactive/escapable.ts +0 -81
  90. package/src/interactive/file-browser.ts +0 -153
  91. package/src/interactive/index.ts +0 -429
  92. package/src/interactive/menu.ts +0 -403
  93. package/src/interactive/selectors.ts +0 -273
  94. package/src/interactive/wizard.ts +0 -221
  95. package/src/providers/claude.ts +0 -53
  96. package/src/providers/copilot.ts +0 -86
  97. package/src/providers/index.ts +0 -43
  98. package/src/providers/types.ts +0 -85
  99. package/src/schemas/index.ts +0 -130
  100. package/src/store/config.ts +0 -74
  101. package/src/store/progress.ts +0 -230
  102. package/src/store/project.ts +0 -276
  103. package/src/store/sprint.ts +0 -229
  104. package/src/store/task.ts +0 -443
  105. package/src/store/ticket.ts +0 -178
  106. package/src/theme/index.ts +0 -215
  107. package/src/theme/ui.ts +0 -872
  108. package/src/utils/detect-scripts.ts +0 -247
  109. package/src/utils/editor-input.ts +0 -41
  110. package/src/utils/editor.ts +0 -37
  111. package/src/utils/exit-codes.ts +0 -27
  112. package/src/utils/file-lock.ts +0 -135
  113. package/src/utils/git.ts +0 -185
  114. package/src/utils/ids.ts +0 -37
  115. package/src/utils/issue-fetch.ts +0 -244
  116. package/src/utils/json-extract.ts +0 -62
  117. package/src/utils/multiline.ts +0 -61
  118. package/src/utils/path-selector.ts +0 -236
  119. package/src/utils/paths.ts +0 -108
  120. package/src/utils/provider.ts +0 -34
  121. package/src/utils/requirements-export.ts +0 -63
  122. package/src/utils/storage.ts +0 -107
  123. package/tsconfig.json +0 -25
  124. /package/{src/ai → dist}/prompts/ideate-auto.md +0 -0
  125. /package/{src/ai → dist}/prompts/ideate.md +0 -0
  126. /package/{src/ai → dist}/prompts/plan-auto.md +0 -0
  127. /package/{src/ai → dist}/prompts/plan-common.md +0 -0
  128. /package/{src/ai → dist}/prompts/plan-interactive.md +0 -0
  129. /package/{src/ai → dist}/prompts/task-execution.md +0 -0
  130. /package/{src/ai → dist}/prompts/ticket-refine.md +0 -0
@@ -1,58 +0,0 @@
1
- import { AiProviderSchema } from '@src/schemas/index.ts';
2
- import { getAiProvider, getEditor, setAiProvider, setEditor } from '@src/store/config.ts';
3
- import { field, icons, log, printHeader, showError, showSuccess } from '@src/theme/ui.ts';
4
-
5
- export async function configSetCommand(args: string[]): Promise<void> {
6
- if (args.length < 2) {
7
- showError('Usage: ralphctl config set <key> <value>');
8
- log.dim('Available keys: provider, editor');
9
- log.newline();
10
- return;
11
- }
12
-
13
- const [key, value] = args;
14
-
15
- if (key === 'provider') {
16
- const parsed = AiProviderSchema.safeParse(value);
17
- if (!parsed.success) {
18
- showError(`Invalid provider: ${value ?? '(empty)'}`);
19
- log.dim('Valid providers: claude, copilot');
20
- log.newline();
21
- return;
22
- }
23
-
24
- await setAiProvider(parsed.data);
25
- showSuccess(`AI provider set to: ${parsed.data}`);
26
- log.newline();
27
- return;
28
- }
29
-
30
- if (key === 'editor') {
31
- const trimmed = value?.trim();
32
- if (!trimmed) {
33
- showError('Editor command cannot be empty');
34
- log.dim('Examples: "subl -w", "code --wait", "vim", "nano"');
35
- log.newline();
36
- return;
37
- }
38
-
39
- await setEditor(trimmed);
40
- showSuccess(`Editor set to: ${trimmed}`);
41
- log.newline();
42
- return;
43
- }
44
-
45
- showError(`Unknown config key: ${key ?? '(empty)'}`);
46
- log.dim('Available keys: provider, editor');
47
- log.newline();
48
- }
49
-
50
- export async function configShowCommand(): Promise<void> {
51
- const provider = await getAiProvider();
52
- const editorCmd = await getEditor();
53
-
54
- printHeader('Configuration', icons.info);
55
- console.log(field('AI Provider', provider ?? '(not set — will prompt on first use)'));
56
- console.log(field('Editor', editorCmd ?? '(not set — will prompt on first use)'));
57
- log.newline();
58
- }
@@ -1,33 +0,0 @@
1
- import type { Command } from 'commander';
2
- import { configSetCommand, configShowCommand } from '@src/commands/config/config.ts';
3
-
4
- export function registerConfigCommands(program: Command): void {
5
- const config = program.command('config').description('Manage configuration');
6
-
7
- config.addHelpText(
8
- 'after',
9
- `
10
- Examples:
11
- $ ralphctl config show # Show current configuration
12
- $ ralphctl config set provider claude # Use Claude Code
13
- $ ralphctl config set provider copilot # Use GitHub Copilot
14
- $ ralphctl config set editor "subl -w" # Use Sublime Text for multiline input
15
- $ ralphctl config set editor "code --wait" # Use VS Code for multiline input
16
- $ ralphctl config set editor vim # Use Vim for multiline input
17
- `
18
- );
19
-
20
- config
21
- .command('show')
22
- .description('Show current configuration')
23
- .action(async () => {
24
- await configShowCommand();
25
- });
26
-
27
- config
28
- .command('set <key> <value>')
29
- .description('Set a configuration value')
30
- .action(async (key: string, value: string) => {
31
- await configSetCommand([key, value]);
32
- });
33
- }
@@ -1,5 +0,0 @@
1
- import { showDashboard } from '@src/interactive/dashboard.ts';
2
-
3
- export async function dashboardCommand(): Promise<void> {
4
- await showDashboard();
5
- }
@@ -1,6 +0,0 @@
1
- import type { Command } from 'commander';
2
- import { dashboardCommand } from '@src/commands/dashboard/dashboard.ts';
3
-
4
- export function registerDashboardCommands(program: Command): void {
5
- program.command('status').description('Show current sprint overview').action(dashboardCommand);
6
- }
@@ -1,271 +0,0 @@
1
- import { access, constants } from 'node:fs/promises';
2
- import { join } from 'node:path';
3
- import { spawnSync } from 'node:child_process';
4
- import { getConfig } from '@src/store/config.ts';
5
- import { listProjects } from '@src/store/project.ts';
6
- import { SprintSchema } from '@src/schemas/index.ts';
7
- import { getDataDir, getSprintFilePath } from '@src/utils/paths.ts';
8
- import { validateProjectPath } from '@src/utils/paths.ts';
9
- import { fileExists, readValidatedJson } from '@src/utils/storage.ts';
10
- import { colors, getQuoteForContext } from '@src/theme/index.ts';
11
- import { icons, log, printHeader } from '@src/theme/ui.ts';
12
- import { EXIT_ERROR } from '@src/utils/exit-codes.ts';
13
- import { isGlabAvailable } from '@src/utils/git.ts';
14
-
15
- const REQUIRED_NODE_MAJOR = 24;
16
-
17
- export interface CheckResult {
18
- name: string;
19
- status: 'pass' | 'warn' | 'fail' | 'skip';
20
- detail?: string;
21
- }
22
-
23
- /**
24
- * Check Node.js version >= 24.0.0
25
- */
26
- export function checkNodeVersion(): CheckResult {
27
- const version = process.version; // e.g., "v24.1.0"
28
- const match = /^v(\d+)/.exec(version);
29
- const major = match ? Number(match[1]) : 0;
30
-
31
- if (major >= REQUIRED_NODE_MAJOR) {
32
- return { name: 'Node.js version', status: 'pass', detail: version };
33
- }
34
- return {
35
- name: 'Node.js version',
36
- status: 'fail',
37
- detail: `${version} (requires >= ${String(REQUIRED_NODE_MAJOR)}.0.0)`,
38
- };
39
- }
40
-
41
- /**
42
- * Check git is installed
43
- */
44
- export function checkGitInstalled(): CheckResult {
45
- const result = spawnSync('git', ['--version'], {
46
- encoding: 'utf-8',
47
- stdio: ['ignore', 'pipe', 'pipe'],
48
- });
49
-
50
- if (result.status === 0) {
51
- const version = result.stdout.trim();
52
- return { name: 'Git installed', status: 'pass', detail: version };
53
- }
54
- return { name: 'Git installed', status: 'fail', detail: 'git not found in PATH' };
55
- }
56
-
57
- /**
58
- * Check git identity (user.name and user.email)
59
- */
60
- export function checkGitIdentity(): CheckResult {
61
- const nameResult = spawnSync('git', ['config', 'user.name'], {
62
- encoding: 'utf-8',
63
- stdio: ['ignore', 'pipe', 'pipe'],
64
- });
65
- const emailResult = spawnSync('git', ['config', 'user.email'], {
66
- encoding: 'utf-8',
67
- stdio: ['ignore', 'pipe', 'pipe'],
68
- });
69
-
70
- const name = nameResult.status === 0 ? nameResult.stdout.trim() : '';
71
- const email = emailResult.status === 0 ? emailResult.stdout.trim() : '';
72
-
73
- if (name && email) {
74
- return { name: 'Git identity', status: 'pass', detail: `${name} <${email}>` };
75
- }
76
-
77
- const missing: string[] = [];
78
- if (!name) missing.push('user.name');
79
- if (!email) missing.push('user.email');
80
- return { name: 'Git identity', status: 'warn', detail: `missing: ${missing.join(', ')}` };
81
- }
82
-
83
- /**
84
- * Check AI provider binary is on PATH
85
- */
86
- export async function checkAiProvider(): Promise<CheckResult> {
87
- const config = await getConfig();
88
- const provider = config.aiProvider;
89
-
90
- if (!provider) {
91
- return { name: 'AI provider binary', status: 'skip', detail: 'not configured' };
92
- }
93
-
94
- const binary = provider === 'claude' ? 'claude' : 'copilot';
95
- const result = spawnSync('which', [binary], {
96
- encoding: 'utf-8',
97
- stdio: ['ignore', 'pipe', 'pipe'],
98
- });
99
-
100
- if (result.status === 0) {
101
- return { name: 'AI provider binary', status: 'pass', detail: `${binary} found` };
102
- }
103
- return {
104
- name: 'AI provider binary',
105
- status: 'fail',
106
- detail: `${binary} not found in PATH (provider: ${provider})`,
107
- };
108
- }
109
-
110
- /**
111
- * Check glab CLI availability (informational — for GitLab issue enrichment)
112
- */
113
- export function checkGlabInstalled(): CheckResult {
114
- if (isGlabAvailable()) {
115
- return { name: 'GitLab CLI (glab)', status: 'pass', detail: 'installed' };
116
- }
117
- return {
118
- name: 'GitLab CLI (glab)',
119
- status: 'skip',
120
- detail: 'not installed (optional — needed for GitLab issue enrichment)',
121
- };
122
- }
123
-
124
- /**
125
- * Check data directory exists and is writable
126
- */
127
- export async function checkDataDirectory(): Promise<CheckResult> {
128
- const dataDir = getDataDir();
129
-
130
- try {
131
- await access(dataDir, constants.R_OK | constants.W_OK);
132
- return { name: 'Data directory', status: 'pass', detail: dataDir };
133
- } catch {
134
- return { name: 'Data directory', status: 'fail', detail: `${dataDir} not accessible or writable` };
135
- }
136
- }
137
-
138
- /**
139
- * Check project paths exist and are git repos
140
- */
141
- export async function checkProjectPaths(): Promise<CheckResult> {
142
- const projects = await listProjects();
143
-
144
- if (projects.length === 0) {
145
- return { name: 'Project paths', status: 'skip', detail: 'no projects registered' };
146
- }
147
-
148
- const issues: string[] = [];
149
-
150
- for (const project of projects) {
151
- for (const repo of project.repositories) {
152
- const validation = await validateProjectPath(repo.path);
153
- if (validation !== true) {
154
- issues.push(`${project.name}/${repo.name}: ${validation}`);
155
- continue;
156
- }
157
-
158
- const gitDir = join(repo.path, '.git');
159
- if (!(await fileExists(gitDir))) {
160
- issues.push(`${project.name}/${repo.name}: not a git repository`);
161
- }
162
- }
163
- }
164
-
165
- if (issues.length === 0) {
166
- const repoCount = projects.reduce((sum, p) => sum + p.repositories.length, 0);
167
- return {
168
- name: 'Project paths',
169
- status: 'pass',
170
- detail: `${String(repoCount)} repo${repoCount !== 1 ? 's' : ''} verified`,
171
- };
172
- }
173
-
174
- return { name: 'Project paths', status: 'fail', detail: issues.join('; ') };
175
- }
176
-
177
- /**
178
- * Check current sprint validity
179
- */
180
- export async function checkCurrentSprint(): Promise<CheckResult> {
181
- const config = await getConfig();
182
- const sprintId = config.currentSprint;
183
-
184
- if (!sprintId) {
185
- return { name: 'Current sprint', status: 'skip', detail: 'no current sprint set' };
186
- }
187
-
188
- const sprintPath = getSprintFilePath(sprintId);
189
- if (!(await fileExists(sprintPath))) {
190
- return { name: 'Current sprint', status: 'fail', detail: `sprint file missing: ${sprintId}` };
191
- }
192
-
193
- try {
194
- const sprint = await readValidatedJson(sprintPath, SprintSchema);
195
- return { name: 'Current sprint', status: 'pass', detail: `${sprint.name} (${sprint.status})` };
196
- } catch (err) {
197
- const message = err instanceof Error ? err.message : String(err);
198
- return { name: 'Current sprint', status: 'fail', detail: `invalid sprint data: ${message}` };
199
- }
200
- }
201
-
202
- /**
203
- * Run all doctor checks and print results.
204
- */
205
- export async function doctorCommand(): Promise<void> {
206
- printHeader('System Health Check', icons.info);
207
-
208
- const results: CheckResult[] = [];
209
-
210
- // Synchronous checks
211
- results.push(checkNodeVersion());
212
- results.push(checkGitInstalled());
213
- results.push(checkGitIdentity());
214
- results.push(checkGlabInstalled());
215
-
216
- // Async checks (independent — run in parallel)
217
- const asyncResults = await Promise.all([
218
- checkAiProvider(),
219
- checkDataDirectory(),
220
- checkProjectPaths(),
221
- checkCurrentSprint(),
222
- ]);
223
- results.push(...asyncResults);
224
-
225
- // Print results
226
- for (const result of results) {
227
- if (result.status === 'pass') {
228
- log.success(`${result.name}${result.detail ? colors.muted(` — ${result.detail}`) : ''}`);
229
- } else if (result.status === 'warn') {
230
- log.warn(`${result.name}${result.detail ? colors.muted(` — ${result.detail}`) : ''}`);
231
- } else if (result.status === 'fail') {
232
- log.error(result.name);
233
- if (result.detail) {
234
- log.dim(` ${result.detail}`);
235
- }
236
- } else {
237
- log.raw(
238
- `${icons.bullet} ${colors.muted(result.name)} ${colors.muted('—')} ${colors.muted(result.detail ?? 'skipped')}`
239
- );
240
- }
241
- }
242
-
243
- // Summary
244
- log.newline();
245
- const passed = results.filter((r) => r.status === 'pass').length;
246
- const warned = results.filter((r) => r.status === 'warn').length;
247
- const failed = results.filter((r) => r.status === 'fail').length;
248
- const total = results.filter((r) => r.status !== 'skip').length;
249
-
250
- if (failed === 0 && warned === 0) {
251
- log.success(`All checks passed (${String(passed)}/${String(total)})`);
252
- log.newline();
253
- const quote = getQuoteForContext('success');
254
- log.dim(`"${quote}"`);
255
- } else if (failed === 0) {
256
- log.success(
257
- `${String(passed)}/${String(total)} checks passed, ${String(warned)} warning${warned !== 1 ? 's' : ''}`
258
- );
259
- log.newline();
260
- const quote = getQuoteForContext('success');
261
- log.dim(`"${quote}"`);
262
- } else {
263
- log.error(`${String(passed)}/${String(total)} checks passed, ${String(failed)} failed`);
264
- log.newline();
265
- const quote = getQuoteForContext('error');
266
- log.dim(`"${quote}"`);
267
- process.exitCode = EXIT_ERROR;
268
- }
269
-
270
- log.newline();
271
- }
@@ -1,25 +0,0 @@
1
- import type { Command } from 'commander';
2
- import { doctorCommand } from '@src/commands/doctor/doctor.ts';
3
-
4
- export function registerDoctorCommands(program: Command): void {
5
- program
6
- .command('doctor')
7
- .description('Check environment health and diagnose setup issues')
8
- .addHelpText(
9
- 'after',
10
- `
11
- Examples:
12
- $ ralphctl doctor # Run all health checks
13
-
14
- Checks performed:
15
- - Node.js version (>= 24)
16
- - Git installation and identity
17
- - AI provider binary (claude or copilot)
18
- - Data directory accessibility
19
- - Project repository paths
20
- - Current sprint validity`
21
- )
22
- .action(async () => {
23
- await doctorCommand();
24
- });
25
- }
@@ -1,25 +0,0 @@
1
- import type { Command } from 'commander';
2
- import { progressLogCommand } from '@src/commands/progress/log.ts';
3
- import { progressShowCommand } from '@src/commands/progress/show.ts';
4
-
5
- export function registerProgressCommands(program: Command): void {
6
- const progress = program.command('progress').description('Log and view progress');
7
-
8
- progress.addHelpText(
9
- 'after',
10
- `
11
- Examples:
12
- $ ralphctl progress log "Completed auth flow"
13
- $ ralphctl progress show
14
- `
15
- );
16
-
17
- progress
18
- .command('log [message]')
19
- .description('Append to progress log (opens editor if no message)')
20
- .action(async (message?: string) => {
21
- await progressLogCommand(message ? [message] : []);
22
- });
23
-
24
- progress.command('show').description('Display progress log').action(progressShowCommand);
25
- }
@@ -1,64 +0,0 @@
1
- import { log, showError, showNextStep, showSuccess } from '@src/theme/ui.ts';
2
- import { logProgress } from '@src/store/progress.ts';
3
- import {
4
- assertSprintStatus,
5
- getSprint,
6
- NoCurrentSprintError,
7
- resolveSprintId,
8
- SprintStatusError,
9
- } from '@src/store/sprint.ts';
10
- import { editorInput } from '@src/utils/editor-input.ts';
11
-
12
- export async function progressLogCommand(args: string[]): Promise<void> {
13
- // FAIL FAST: Check sprint status before collecting any input
14
- try {
15
- const sprintId = await resolveSprintId();
16
- const sprint = await getSprint(sprintId);
17
- assertSprintStatus(sprint, ['active'], 'log progress');
18
- } catch (err) {
19
- if (err instanceof SprintStatusError) {
20
- const mainError = err.message.split('\n')[0] ?? err.message;
21
- showError(mainError);
22
- showNextStep('ralphctl sprint start', 'activate the sprint');
23
- log.newline();
24
- return;
25
- }
26
- if (err instanceof NoCurrentSprintError) {
27
- showError('No current sprint set.');
28
- showNextStep('ralphctl sprint create', 'create a new sprint');
29
- log.newline();
30
- return;
31
- }
32
- throw err;
33
- }
34
-
35
- // Validation passed - now collect input
36
- let message = args.join(' ').trim();
37
-
38
- if (!message) {
39
- message = await editorInput({
40
- message: 'Progress message:',
41
- });
42
- message = message.trim();
43
- }
44
-
45
- if (!message) {
46
- showError('No message provided.');
47
- log.newline();
48
- return;
49
- }
50
-
51
- try {
52
- await logProgress(message);
53
- showSuccess('Progress logged.');
54
- log.newline();
55
- } catch (err) {
56
- if (err instanceof SprintStatusError) {
57
- // Fallback handler (shouldn't reach here due to early check)
58
- showError(err.message);
59
- log.newline();
60
- } else {
61
- throw err;
62
- }
63
- }
64
- }
@@ -1,14 +0,0 @@
1
- import { getProgress } from '@src/store/progress.ts';
2
- import { printHeader, showEmpty } from '@src/theme/ui.ts';
3
-
4
- export async function progressShowCommand(): Promise<void> {
5
- const content = await getProgress();
6
-
7
- if (!content.trim()) {
8
- showEmpty('progress entries', 'Log with: ralphctl progress log');
9
- return;
10
- }
11
-
12
- printHeader('Progress Log');
13
- console.log(content);
14
- }