propr-cli 0.8.3

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 (64) hide show
  1. package/README.md +549 -0
  2. package/dist/api/agentTank.js +27 -0
  3. package/dist/api/agents.js +201 -0
  4. package/dist/api/client.js +284 -0
  5. package/dist/api/errors.js +145 -0
  6. package/dist/api/implement.js +147 -0
  7. package/dist/api/index.js +26 -0
  8. package/dist/api/logs.js +59 -0
  9. package/dist/api/plans.js +160 -0
  10. package/dist/api/relay.js +73 -0
  11. package/dist/api/repos.js +243 -0
  12. package/dist/api/settings.js +219 -0
  13. package/dist/api/system.js +53 -0
  14. package/dist/api/tasks.js +140 -0
  15. package/dist/api/todos.js +77 -0
  16. package/dist/api/types.js +6 -0
  17. package/dist/assets/.env.example +183 -0
  18. package/dist/assets/env.example.txt +198 -0
  19. package/dist/commands/agentCommands.js +405 -0
  20. package/dist/commands/checkCommands.js +384 -0
  21. package/dist/commands/implementCommands.js +178 -0
  22. package/dist/commands/index.js +22 -0
  23. package/dist/commands/initCommands.js +167 -0
  24. package/dist/commands/initStack.js +193 -0
  25. package/dist/commands/logCommands.js +170 -0
  26. package/dist/commands/planCommands.js +552 -0
  27. package/dist/commands/relayCommands.js +149 -0
  28. package/dist/commands/repoCommands.js +526 -0
  29. package/dist/commands/settingCommands.js +237 -0
  30. package/dist/commands/stackCommands.js +86 -0
  31. package/dist/commands/startCommand.js +36 -0
  32. package/dist/commands/systemCommands.js +221 -0
  33. package/dist/commands/tankCommands.js +55 -0
  34. package/dist/commands/taskCommands.js +554 -0
  35. package/dist/commands/todoCommands.js +620 -0
  36. package/dist/commands/uiDocsCommands.js +69 -0
  37. package/dist/config/ConfigManager.js +360 -0
  38. package/dist/config/index.js +8 -0
  39. package/dist/config/types.js +16 -0
  40. package/dist/index.js +276 -0
  41. package/dist/orchestrator/format.js +31 -0
  42. package/dist/orchestrator/index.js +102 -0
  43. package/dist/orchestrator/manifest.json +16 -0
  44. package/dist/orchestrator/orchestrator.mjs +798 -0
  45. package/dist/orchestrator/types.js +10 -0
  46. package/dist/tui/StartApp.js +175 -0
  47. package/dist/tui/app.js +9 -0
  48. package/dist/tui/render.js +87 -0
  49. package/dist/utils/envFile.js +65 -0
  50. package/dist/utils/index.js +8 -0
  51. package/dist/utils/io.js +186 -0
  52. package/dist/utils/parseState.js +14 -0
  53. package/dist/utils/resolveProject.js +50 -0
  54. package/dist/vendor/shared/demoMode.js +6 -0
  55. package/dist/vendor/shared/events.js +30 -0
  56. package/dist/vendor/shared/githubAuthMode.js +35 -0
  57. package/dist/vendor/shared/index.js +15 -0
  58. package/dist/vendor/shared/labelUtils.js +32 -0
  59. package/dist/vendor/shared/modelDefinitions.js +146 -0
  60. package/dist/vendor/shared/reviewPrompt.js +18 -0
  61. package/dist/vendor/shared/usageTypes.js +13 -0
  62. package/dist/vendor/shared/userWhitelist.js +30 -0
  63. package/dist/vendor/shared/validateRelayUrl.js +21 -0
  64. package/package.json +31 -0
@@ -0,0 +1,554 @@
1
+ /**
2
+ * Task Management Commands
3
+ *
4
+ * CLI commands for managing tasks using the ProPR backend.
5
+ * Provides the `task` command group with `list`, `get`, `stop`, `delete`, and `revert` subcommands.
6
+ */
7
+ import { Command } from "commander";
8
+ import { createConfigManager } from "../config/index.js";
9
+ import { printOutput } from "../utils/index.js";
10
+ import { listTasks, stopTask, deleteTask, revertTask, getTaskStatus, } from "../api/index.js";
11
+ /**
12
+ * Formats a task status for display.
13
+ */
14
+ function formatStatus(status) {
15
+ const statusMap = {
16
+ pending: "Pending",
17
+ queued: "Queued",
18
+ processing: "Processing",
19
+ claude_execution: "Executing",
20
+ post_processing: "Post-processing",
21
+ completed: "Completed",
22
+ failed: "Failed",
23
+ cancelled: "Cancelled",
24
+ };
25
+ return statusMap[status?.toLowerCase()] || status;
26
+ }
27
+ /**
28
+ * Formats a date string for display.
29
+ */
30
+ function formatDate(dateStr) {
31
+ if (!dateStr)
32
+ return "-";
33
+ const date = new Date(dateStr);
34
+ return date.toLocaleString();
35
+ }
36
+ /**
37
+ * Truncates a string to a maximum length.
38
+ */
39
+ function truncate(str, maxLen) {
40
+ if (!str)
41
+ return "";
42
+ if (str.length <= maxLen)
43
+ return str;
44
+ return str.substring(0, maxLen - 3) + "...";
45
+ }
46
+ /**
47
+ * Displays a table of tasks with clean formatting.
48
+ */
49
+ function displayTasksTable(tasks) {
50
+ const idWidth = Math.max("ID".length, ...tasks.map((t) => t.id.length));
51
+ const repoWidth = Math.max("Repository".length, ...tasks.map((t) => truncate(t.repository, 25).length));
52
+ const issueWidth = Math.max("Issue".length, ...tasks.map((t) => String(t.issueNumber || "-").length));
53
+ const statusWidth = Math.max("Status".length, ...tasks.map((t) => formatStatus(t.status).length));
54
+ const titleWidth = Math.max("Title".length, ...tasks.map((t) => truncate(t.title, 30).length));
55
+ const header = [
56
+ "ID".padEnd(idWidth),
57
+ "Repository".padEnd(repoWidth),
58
+ "Issue".padEnd(issueWidth),
59
+ "Status".padEnd(statusWidth),
60
+ "Title".padEnd(titleWidth),
61
+ ].join(" ");
62
+ console.log(header);
63
+ console.log("-".repeat(header.length));
64
+ for (const task of tasks) {
65
+ const row = [
66
+ task.id.padEnd(idWidth),
67
+ truncate(task.repository, 25).padEnd(repoWidth),
68
+ String(task.issueNumber || "-").padEnd(issueWidth),
69
+ formatStatus(task.status).padEnd(statusWidth),
70
+ truncate(task.title, 30).padEnd(titleWidth),
71
+ ].join(" ");
72
+ console.log(row);
73
+ }
74
+ }
75
+ /**
76
+ * Displays detailed task information from TaskStatus.
77
+ */
78
+ function displayTaskDetails(status) {
79
+ console.log("");
80
+ console.log("=".repeat(60));
81
+ console.log("Task Details");
82
+ console.log("=".repeat(60));
83
+ console.log("");
84
+ console.log(`ID: ${status.taskId}`);
85
+ console.log(`Status: ${formatStatus(status.currentState)}`);
86
+ if (status.taskInfo) {
87
+ const info = status.taskInfo;
88
+ console.log(`Repository: ${info.repoOwner}/${info.repoName}`);
89
+ console.log(`Type: ${info.type}`);
90
+ console.log(`Number: #${info.number}`);
91
+ if (info.title) {
92
+ console.log(`Title: ${info.title}`);
93
+ }
94
+ if (info.subtitle) {
95
+ console.log(`Subtitle: ${info.subtitle}`);
96
+ }
97
+ if (info.modelName) {
98
+ console.log(`Model: ${info.modelName}`);
99
+ }
100
+ if (info.correlationId) {
101
+ console.log(`Correlation: ${info.correlationId}`);
102
+ }
103
+ if (info.issueNumber && info.issueNumber !== info.number) {
104
+ console.log(`Linked Issue: #${info.issueNumber}`);
105
+ }
106
+ }
107
+ if (status.prNumber) {
108
+ console.log(`PR Number: #${status.prNumber}`);
109
+ }
110
+ if (status.prUrl) {
111
+ console.log(`PR URL: ${status.prUrl}`);
112
+ }
113
+ if (status.isFailed && status.failureReason) {
114
+ console.log("");
115
+ console.log("Failure Reason:");
116
+ console.log("-".repeat(40));
117
+ console.log(status.failureReason);
118
+ }
119
+ if (status.history && status.history.length > 0) {
120
+ console.log("");
121
+ console.log("History:");
122
+ console.log("-".repeat(40));
123
+ for (const entry of status.history) {
124
+ const timestamp = new Date(entry.timestamp).toLocaleString();
125
+ let line = `[${timestamp}] ${formatStatus(entry.state)}`;
126
+ if (entry.message) {
127
+ line += ` - ${entry.message}`;
128
+ }
129
+ if (entry.reason) {
130
+ line += ` (${entry.reason})`;
131
+ }
132
+ console.log(line);
133
+ if (entry.metadata) {
134
+ if (entry.metadata.model) {
135
+ console.log(` Model: ${entry.metadata.model}`);
136
+ }
137
+ if (entry.metadata.duration !== undefined) {
138
+ console.log(` Duration: ${entry.metadata.duration}ms`);
139
+ }
140
+ if (entry.metadata.tokenUsage) {
141
+ const usage = entry.metadata.tokenUsage;
142
+ const parts = [];
143
+ if (usage.input_tokens)
144
+ parts.push(`input: ${usage.input_tokens}`);
145
+ if (usage.output_tokens)
146
+ parts.push(`output: ${usage.output_tokens}`);
147
+ if (parts.length > 0) {
148
+ console.log(` Tokens: ${parts.join(", ")}`);
149
+ }
150
+ }
151
+ }
152
+ }
153
+ }
154
+ console.log("");
155
+ console.log("=".repeat(60));
156
+ console.log("");
157
+ console.log("Full JSON:");
158
+ console.log("-".repeat(40));
159
+ console.log(JSON.stringify(status, null, 2));
160
+ }
161
+ /**
162
+ * Prompts the user for confirmation.
163
+ */
164
+ async function confirm(message) {
165
+ const readline = await import("readline");
166
+ const rl = readline.createInterface({
167
+ input: process.stdin,
168
+ output: process.stdout,
169
+ });
170
+ return new Promise((resolve) => {
171
+ rl.question(`${message} (y/N): `, (answer) => {
172
+ rl.close();
173
+ resolve(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
174
+ });
175
+ });
176
+ }
177
+ /**
178
+ * Creates the `task` command group.
179
+ */
180
+ export function createTaskCommand() {
181
+ const task = new Command("task")
182
+ .description("Manage implementation tasks")
183
+ .addHelpText("after", `
184
+ Examples:
185
+ $ propr task list # List all tasks
186
+ $ propr task list -s processing # Filter by status
187
+ $ propr task get abc123 # View task details
188
+ $ propr task stop abc123 # Stop a running task
189
+ $ propr task delete abc123 # Delete a task
190
+ $ propr task revert myorg/myrepo 123 abc 456 # Revert a commit
191
+ `);
192
+ // task list
193
+ task
194
+ .command("list")
195
+ .description("List tasks with optional filtering by project, status, or search term")
196
+ .option("-p, --project <project>", "Filter by project (owner/repo)")
197
+ .option("-s, --status <status>", "Filter by status (pending, queued, processing, completed, failed, cancelled, or all)", "all")
198
+ .option("-l, --limit <limit>", "Maximum number of tasks to show", "50")
199
+ .option("--search <term>", "Search tasks by term")
200
+ .option("-j, --json", "Output as JSON for programmatic use")
201
+ .addHelpText("after", `
202
+ Status Values:
203
+ pending Task waiting to be queued
204
+ queued Task in queue waiting for worker
205
+ processing Task being executed
206
+ completed Task finished successfully
207
+ failed Task failed with error
208
+ cancelled Task was cancelled
209
+ all Show all tasks (default)
210
+
211
+ Examples:
212
+ $ propr task list # List all tasks
213
+ $ propr task list -p myorg/myrepo # Filter by project
214
+ $ propr task list -s processing # Filter by status
215
+ $ propr task list --search "auth" -l 100 # Search with limit
216
+ $ propr task list --json # JSON output
217
+ `)
218
+ .action(async (options) => {
219
+ try {
220
+ const listOptions = {};
221
+ if (options.status && options.status !== "all") {
222
+ listOptions.status = options.status.toLowerCase();
223
+ }
224
+ if (options.project) {
225
+ listOptions.repository = options.project;
226
+ }
227
+ const limit = parseInt(options.limit, 10);
228
+ if (!isNaN(limit) && limit > 0) {
229
+ listOptions.limit = limit;
230
+ }
231
+ if (options.search) {
232
+ listOptions.search = options.search;
233
+ }
234
+ const result = await listTasks(listOptions);
235
+ if (printOutput(result, options.json ?? false)) {
236
+ return;
237
+ }
238
+ console.log("Fetching tasks...");
239
+ if (result.tasks.length === 0) {
240
+ console.log("");
241
+ console.log("No tasks found.");
242
+ if (options.project) {
243
+ console.log(`Project filter: ${options.project}`);
244
+ }
245
+ if (options.status !== "all") {
246
+ console.log(`Status filter: ${options.status}`);
247
+ }
248
+ return;
249
+ }
250
+ console.log("");
251
+ displayTasksTable(result.tasks);
252
+ console.log("");
253
+ console.log(`Showing ${result.tasks.length} of ${result.total} task(s)`);
254
+ if (result.tasks.length < result.total) {
255
+ console.log(`Use --limit to show more (currently showing ${result.limit})`);
256
+ }
257
+ }
258
+ catch (error) {
259
+ const errorMessage = error.message;
260
+ if (errorMessage.includes("401") ||
261
+ errorMessage.includes("unauthorized")) {
262
+ console.error("Error: Unauthorized. Please run 'propr login' first.");
263
+ }
264
+ else {
265
+ console.error(`Error listing tasks: ${errorMessage}`);
266
+ }
267
+ process.exit(1);
268
+ }
269
+ });
270
+ // task get
271
+ task
272
+ .command("get <task-id>")
273
+ .description("Get detailed information about a specific task including history and metadata")
274
+ .option("-j, --json", "Output as JSON for programmatic use")
275
+ .addHelpText("after", `
276
+ Argument:
277
+ task-id The unique identifier of the task
278
+
279
+ Examples:
280
+ $ propr task get abc123-task-id
281
+ $ propr task get abc123-task-id --json
282
+ `)
283
+ .action(async (taskId, options) => {
284
+ try {
285
+ const status = await getTaskStatus(taskId);
286
+ if (printOutput(status, options.json ?? false)) {
287
+ return;
288
+ }
289
+ console.log(`Fetching task ${taskId}...`);
290
+ displayTaskDetails(status);
291
+ }
292
+ catch (error) {
293
+ const errorMessage = error.message;
294
+ if (errorMessage.includes("404") || errorMessage.includes("not found")) {
295
+ console.error(`Error: Task not found: ${taskId}`);
296
+ }
297
+ else if (errorMessage.includes("401") ||
298
+ errorMessage.includes("unauthorized")) {
299
+ console.error("Error: Unauthorized. Please run 'propr login' first.");
300
+ }
301
+ else if (errorMessage.includes("403") ||
302
+ errorMessage.includes("forbidden")) {
303
+ console.error("Error: Access denied. You do not have permission to view this task.");
304
+ }
305
+ else {
306
+ console.error(`Error fetching task: ${errorMessage}`);
307
+ }
308
+ process.exit(1);
309
+ }
310
+ });
311
+ // task stop
312
+ task
313
+ .command("stop <task-id>")
314
+ .description("Stop a running task (only works for active tasks)")
315
+ .addHelpText("after", `
316
+ Argument:
317
+ task-id The unique identifier of the task to stop
318
+
319
+ Note:
320
+ This command only works for tasks in active states (pending, queued, processing).
321
+ Tasks in terminal states (completed, failed, cancelled) cannot be stopped.
322
+
323
+ Example:
324
+ $ propr task stop abc123-task-id
325
+ `)
326
+ .action(async (taskId) => {
327
+ try {
328
+ let currentStatus;
329
+ try {
330
+ const status = await getTaskStatus(taskId);
331
+ currentStatus = status.currentState;
332
+ const terminalStates = ["completed", "failed", "cancelled"];
333
+ if (terminalStates.includes(currentStatus.toLowerCase())) {
334
+ console.log(`Task is already in "${formatStatus(currentStatus)}" state.`);
335
+ console.log("No action needed.");
336
+ return;
337
+ }
338
+ console.log(`Current status: ${formatStatus(currentStatus)}`);
339
+ }
340
+ catch {
341
+ // If we can't fetch the status, continue with stop attempt
342
+ }
343
+ console.log(`Stopping task ${taskId}...`);
344
+ const result = await stopTask(taskId);
345
+ if (result.success) {
346
+ console.log(result.message || "Task stopped successfully.");
347
+ }
348
+ else {
349
+ console.error(`Failed to stop task: ${result.message}`);
350
+ process.exit(1);
351
+ }
352
+ }
353
+ catch (error) {
354
+ const errorMessage = error.message;
355
+ if (errorMessage.includes("404") || errorMessage.includes("not found")) {
356
+ console.error(`Error: Task not found: ${taskId}`);
357
+ }
358
+ else if (errorMessage.includes("400")) {
359
+ console.error("Error: Task cannot be stopped in its current state.");
360
+ }
361
+ else if (errorMessage.includes("401") ||
362
+ errorMessage.includes("unauthorized")) {
363
+ console.error("Error: Unauthorized. Please run 'propr login' first.");
364
+ }
365
+ else if (errorMessage.includes("403") ||
366
+ errorMessage.includes("forbidden")) {
367
+ console.error("Error: Access denied. You do not have permission to stop this task.");
368
+ }
369
+ else {
370
+ console.error(`Error stopping task: ${errorMessage}`);
371
+ }
372
+ process.exit(1);
373
+ }
374
+ });
375
+ // task delete
376
+ task
377
+ .command("delete <task-id>")
378
+ .description("Delete a task from the system permanently")
379
+ .option("-f, --force", "Force deletion even for active tasks")
380
+ .addHelpText("after", `
381
+ Argument:
382
+ task-id The unique identifier of the task to delete
383
+
384
+ Note:
385
+ Active tasks require --force flag to delete.
386
+ Consider using 'propr task stop' first for running tasks.
387
+
388
+ Examples:
389
+ $ propr task delete abc123-task-id # With confirmation
390
+ $ propr task delete abc123-task-id --force # Force delete active task
391
+ `)
392
+ .action(async (taskId, options) => {
393
+ try {
394
+ let taskInfo = taskId;
395
+ let currentStatus;
396
+ try {
397
+ const status = await getTaskStatus(taskId);
398
+ currentStatus = status.currentState;
399
+ if (status.taskInfo) {
400
+ const info = status.taskInfo;
401
+ taskInfo = `${info.repoOwner}/${info.repoName}#${info.number}`;
402
+ if (info.title) {
403
+ taskInfo += ` - ${info.title}`;
404
+ }
405
+ }
406
+ console.log(`Task: ${taskInfo}`);
407
+ console.log(`Status: ${formatStatus(currentStatus)}`);
408
+ console.log("");
409
+ const activeStates = [
410
+ "pending",
411
+ "queued",
412
+ "processing",
413
+ "claude_execution",
414
+ "post_processing",
415
+ ];
416
+ if (activeStates.includes(currentStatus.toLowerCase())) {
417
+ if (!options.force) {
418
+ console.log("Warning: This task is currently active. Use --force to delete anyway.");
419
+ console.log("Alternatively, stop the task first with 'propr task stop'.");
420
+ console.log("");
421
+ }
422
+ }
423
+ }
424
+ catch {
425
+ console.log(`Task ID: ${taskId}`);
426
+ console.log("");
427
+ }
428
+ if (!options.force) {
429
+ const confirmed = await confirm("Are you sure you want to delete this task?");
430
+ if (!confirmed) {
431
+ console.log("Deletion cancelled.");
432
+ return;
433
+ }
434
+ }
435
+ console.log(`Deleting task ${taskId}...`);
436
+ await deleteTask(taskId, options.force || false);
437
+ console.log("Task deleted successfully.");
438
+ }
439
+ catch (error) {
440
+ const errorMessage = error.message;
441
+ if (errorMessage.includes("404") || errorMessage.includes("not found")) {
442
+ console.error(`Error: Task not found: ${taskId}`);
443
+ }
444
+ else if (errorMessage.includes("400")) {
445
+ console.error("Error: Cannot delete task in active state. Stop the task first or use --force.");
446
+ }
447
+ else if (errorMessage.includes("401") ||
448
+ errorMessage.includes("unauthorized")) {
449
+ console.error("Error: Unauthorized. Please run 'propr login' first.");
450
+ }
451
+ else if (errorMessage.includes("403") ||
452
+ errorMessage.includes("forbidden")) {
453
+ console.error("Error: Access denied. You do not have permission to delete this task.");
454
+ }
455
+ else {
456
+ console.error(`Error deleting task: ${errorMessage}`);
457
+ }
458
+ process.exit(1);
459
+ }
460
+ });
461
+ // task revert
462
+ task
463
+ .command("revert <repo> <pr> <commit> <commentId>")
464
+ .description("Revert changes from a specific commit in a pull request")
465
+ .option("-o, --owner <owner>", "Repository owner (required if repo is not in owner/repo format)")
466
+ .addHelpText("after", `
467
+ Arguments:
468
+ repo Repository name (owner/repo format) or just repo name with -o flag
469
+ pr Pull request number
470
+ commit Commit hash to revert
471
+ commentId ID of the comment that triggered the revert
472
+
473
+ Examples:
474
+ $ propr task revert myorg/myrepo 123 abc123def 456789
475
+ $ propr task revert myrepo 123 abc123def 456789 -o myorg
476
+ `)
477
+ .action(async (repo, pr, commit, commentId, options) => {
478
+ try {
479
+ let owner = options.owner;
480
+ let repoName = repo;
481
+ if (repo.includes("/")) {
482
+ const parts = repo.split("/");
483
+ if (parts.length === 2) {
484
+ owner = owner || parts[0];
485
+ repoName = parts[1];
486
+ }
487
+ }
488
+ if (!owner) {
489
+ const configManager = await createConfigManager();
490
+ const defaultProject = configManager.getDefaultProject();
491
+ if (defaultProject && defaultProject.includes("/")) {
492
+ owner = defaultProject.split("/")[0];
493
+ }
494
+ }
495
+ if (!owner) {
496
+ console.error("Error: Owner must be provided via --owner flag, in repo argument as owner/repo, or in propr config");
497
+ process.exit(1);
498
+ }
499
+ const prNumber = parseInt(pr, 10);
500
+ const commentIdNum = parseInt(commentId, 10);
501
+ if (isNaN(prNumber) || prNumber <= 0) {
502
+ console.error("Error: PR number must be a positive integer");
503
+ process.exit(1);
504
+ }
505
+ if (isNaN(commentIdNum) || commentIdNum <= 0) {
506
+ console.error("Error: Comment ID must be a positive integer");
507
+ process.exit(1);
508
+ }
509
+ if (!commit || commit.trim().length === 0) {
510
+ console.error("Error: Commit hash is required");
511
+ process.exit(1);
512
+ }
513
+ console.log(`Reverting commit ${commit} from PR #${pr} in ${owner}/${repoName}...`);
514
+ const result = await revertTask(owner, repoName, prNumber, commit, commentIdNum);
515
+ if (result.success) {
516
+ console.log("");
517
+ console.log("Revert task queued successfully!");
518
+ console.log(`Job ID: ${result.jobId}`);
519
+ console.log(`Correlation ID: ${result.correlationId}`);
520
+ console.log(`Message: ${result.message}`);
521
+ console.log("");
522
+ console.log("You can check the status of this task with:");
523
+ console.log(` propr task list -p ${owner}/${repoName}`);
524
+ }
525
+ else {
526
+ console.error(`Failed to queue revert task: ${result.message}`);
527
+ process.exit(1);
528
+ }
529
+ }
530
+ catch (error) {
531
+ const errorMessage = error.message;
532
+ if (errorMessage.includes("401") ||
533
+ errorMessage.includes("unauthorized")) {
534
+ console.error("Error: Unauthorized. Please run 'propr login' first.");
535
+ }
536
+ else if (errorMessage.includes("403") ||
537
+ errorMessage.includes("forbidden")) {
538
+ console.error("Error: Access denied. You do not have permission to revert this PR.");
539
+ }
540
+ else if (errorMessage.includes("404") ||
541
+ errorMessage.includes("not found")) {
542
+ console.error("Error: Repository, PR, or commit not found.");
543
+ }
544
+ else if (errorMessage.includes("400")) {
545
+ console.error("Error: Invalid parameters provided.");
546
+ }
547
+ else {
548
+ console.error(`Error reverting task: ${errorMessage}`);
549
+ }
550
+ process.exit(1);
551
+ }
552
+ });
553
+ return task;
554
+ }