@vibetasks/cli 0.5.2 → 0.5.4

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.
@@ -5,13 +5,13 @@ import {
5
5
  detectError,
6
6
  formatErrorForNotes,
7
7
  getErrorSummary
8
- } from "../chunk-PZF4VRDG.js";
8
+ } from "../chunk-S3G6KYGP.js";
9
9
  import {
10
10
  daemonConfigManager
11
11
  } from "../chunk-2KRLRG4G.js";
12
12
 
13
13
  // bin/vibetasks.ts
14
- import { Command as Command18 } from "commander";
14
+ import { Command as Command21 } from "commander";
15
15
  import { createRequire } from "module";
16
16
 
17
17
  // src/commands/login.ts
@@ -877,7 +877,8 @@ var listCommand = new Command3("list").description("List tasks").argument("[filt
877
877
  all: "No active tasks found",
878
878
  today: "No tasks due today",
879
879
  upcoming: "No upcoming tasks",
880
- completed: "No completed tasks"
880
+ completed: "No completed tasks",
881
+ archived: "No archived tasks"
881
882
  };
882
883
  console.log(chalk4.gray(`
883
884
  ${filterMessages[filter] || "No tasks found"}.
@@ -918,12 +919,14 @@ ${filterMessages[filter] || "No tasks found"}.
918
919
  const statusColors = {
919
920
  todo: chalk4.gray,
920
921
  vibing: chalk4.magenta,
921
- done: chalk4.green
922
+ done: chalk4.green,
923
+ archived: chalk4.dim
922
924
  };
923
925
  const statusEmojis = {
924
926
  todo: "\u{1F4CB}",
925
927
  vibing: "\u26A1",
926
- done: "\u2713"
928
+ done: "\u2713",
929
+ archived: "\u{1F4E6}"
927
930
  };
928
931
  const priorityColor = priorityColors[task.priority || "none"];
929
932
  const statusColor = statusColors[task.status || "todo"];
@@ -950,7 +953,8 @@ ${filterMessages[filter] || "No tasks found"}.
950
953
  all: "active",
951
954
  today: "today",
952
955
  upcoming: "upcoming",
953
- completed: "completed"
956
+ completed: "completed",
957
+ archived: "archived"
954
958
  };
955
959
  console.log(chalk4.gray(`
956
960
  Total: ${tasks.length} ${filterLabels[filter]} task${tasks.length === 1 ? "" : "s"}`));
@@ -981,7 +985,7 @@ import { Command as Command4 } from "commander";
981
985
  import ora3 from "ora";
982
986
  import chalk5 from "chalk";
983
987
  import { AuthManager as AuthManager4, TaskOperations as TaskOperations3 } from "@vibetasks/core";
984
- var doneCommand = new Command4("done").description("Mark a task as complete").argument("<id>", "Task ID, short # (1-99), or first 8 characters").action(async (id) => {
988
+ var doneCommand = new Command4("done").description("Mark a task as complete").argument("<id>", "Task ID, short # (1-99), or first 8 characters").option("-n, --notes <notes>", "Completion notes - what was done, any final notes").option("-c, --context <context>", "Context notes (alias for --notes)").action(async (id, options) => {
985
989
  const spinner = ora3("Completing task...").start();
986
990
  try {
987
991
  const authManager = new AuthManager4();
@@ -1000,6 +1004,10 @@ No task found with ID starting with: ${id}
1000
1004
  }
1001
1005
  taskId = matchingTask.id;
1002
1006
  }
1007
+ const contextNotes = options.notes || options.context;
1008
+ if (contextNotes) {
1009
+ await taskOps.updateTask(taskId, { context_notes: contextNotes });
1010
+ }
1003
1011
  const task = await taskOps.completeTask(taskId);
1004
1012
  const sessionManager2 = getSessionManager();
1005
1013
  await sessionManager2.logAction({
@@ -1011,6 +1019,9 @@ No task found with ID starting with: ${id}
1011
1019
  spinner.succeed(chalk5.green("Task completed!"));
1012
1020
  console.log(chalk5.gray(`
1013
1021
  \u2713 ${task.title}`));
1022
+ if (contextNotes) {
1023
+ console.log(chalk5.gray(`Notes: ${contextNotes}`));
1024
+ }
1014
1025
  console.log(chalk5.gray(`Completed at: ${(/* @__PURE__ */ new Date()).toLocaleString()}
1015
1026
  `));
1016
1027
  process.exit(0);
@@ -1614,7 +1625,7 @@ import { promisify as promisify2 } from "util";
1614
1625
  import { AuthManager as AuthManager11, TaskOperations as TaskOperations8, createSupabaseClient } from "@vibetasks/core";
1615
1626
  import { detectProject as detectProject3 } from "@vibetasks/shared/utils/project-detector";
1616
1627
  var execAsync2 = promisify2(exec2);
1617
- var SUPABASE_URL = "https://cbkkztbcoitrfcleghfd.supabase.co";
1628
+ var SUPABASE_URL = "https://ihmayqzxqyednchbezya.supabase.co";
1618
1629
  var SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImNia2t6dGJjb2l0cmZjbGVnaGZkIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Njc3NTc0MjgsImV4cCI6MjA4MzMzMzQyOH0.G7ILx-nntP0NbxO1gKt5yASb7nt7OmpJ8qtykeGYbQA";
1619
1630
  async function openBrowser2(url) {
1620
1631
  const platform = process.platform;
@@ -2035,7 +2046,7 @@ function showCompletion(auth, claude, project, verify) {
2035
2046
  console.log(chalk13.cyan(' "What should I work on next?"'));
2036
2047
  }
2037
2048
  console.log("");
2038
- console.log(chalk13.gray(" Need help? https://github.com/vyasapps/vibetasks"));
2049
+ console.log(chalk13.gray(" Need help? https://github.com/sparktory/vibetasks"));
2039
2050
  console.log("");
2040
2051
  }
2041
2052
  function getSuccessHtml(email) {
@@ -2223,6 +2234,7 @@ import ora10 from "ora";
2223
2234
  import inquirer5 from "inquirer";
2224
2235
  import { AuthManager as AuthManager12, TaskOperations as TaskOperations9 } from "@vibetasks/core";
2225
2236
  import { detectProject as detectProject4 } from "@vibetasks/shared/utils/project-detector";
2237
+ import { generateErrorTaskTitle } from "@vibetasks/shared";
2226
2238
  var watchCommand = new Command13("watch").description("Monitor clipboard for errors and offer to capture them as tasks").option("-i, --interval <ms>", "Polling interval in milliseconds", "1000").option("-a, --auto", "Auto-create tasks without prompting").option("-q, --quiet", "Minimal output (only show errors)").option("--project <name>", "Override auto-detected project").action(async (options) => {
2227
2239
  const interval = parseInt(options.interval || "1000", 10);
2228
2240
  if (!options.quiet) {
@@ -2260,7 +2272,7 @@ Error: ${error.message}
2260
2272
  }
2261
2273
  const recentErrors = /* @__PURE__ */ new Set();
2262
2274
  const handleError = async (error) => {
2263
- const errorHash = `${error.type}:${error.message.substring(0, 50)}`;
2275
+ const errorHash = `${error.error_type || "unknown"}:${(error.message || "").substring(0, 50)}`;
2264
2276
  if (recentErrors.has(errorHash)) {
2265
2277
  return;
2266
2278
  }
@@ -2300,7 +2312,7 @@ Error: ${error.message}
2300
2312
  case "show":
2301
2313
  console.log();
2302
2314
  console.log(chalk14.gray("\u2500".repeat(50)));
2303
- console.log(error.rawText);
2315
+ console.log(error.raw_text);
2304
2316
  console.log(chalk14.gray("\u2500".repeat(50)));
2305
2317
  console.log();
2306
2318
  const { afterShow } = await inquirer5.prompt([
@@ -2369,20 +2381,23 @@ Error: ${error.message}
2369
2381
  async function createTaskFromError(error, taskOps, projectTag) {
2370
2382
  const spinner = ora10("Creating task...").start();
2371
2383
  try {
2372
- const title = generateTaskTitle(error);
2384
+ const title = generateErrorTaskTitle(error);
2385
+ const category = error.category || "general";
2373
2386
  const task = await taskOps.createTask({
2374
2387
  title,
2375
2388
  notes: formatErrorForNotes(error),
2376
2389
  notes_format: "markdown",
2377
- priority: error.category === "typescript" ? "medium" : "high",
2390
+ priority: category === "typescript" ? "medium" : "high",
2378
2391
  project_tag: projectTag,
2379
2392
  created_by: "human",
2380
2393
  // User triggered this
2381
- status: "todo"
2394
+ status: "todo",
2395
+ source_type: "cli",
2396
+ error_context: error
2382
2397
  });
2383
- const tagName = `error-${error.category}`;
2398
+ const tagName = `error-${category}`;
2384
2399
  try {
2385
- const tag = await taskOps.findOrCreateTag(tagName, getTagColor(error.category));
2400
+ const tag = await taskOps.findOrCreateTag(tagName, getTagColor(category));
2386
2401
  await taskOps.linkTaskTags(task.id, [tag.id]);
2387
2402
  } catch {
2388
2403
  }
@@ -2394,41 +2409,6 @@ async function createTaskFromError(error, taskOps, projectTag) {
2394
2409
  console.error(chalk14.red(`Error: ${err.message}`));
2395
2410
  }
2396
2411
  }
2397
- function generateTaskTitle(error) {
2398
- const prefix = getCategoryPrefix(error.category);
2399
- let title = `${prefix} ${error.type}`;
2400
- if (error.message && error.message.length < 60) {
2401
- title += `: ${error.message}`;
2402
- } else if (error.message) {
2403
- const shortMessage = error.message.split(/[.!?\n]/)[0].trim();
2404
- if (shortMessage.length < 60) {
2405
- title += `: ${shortMessage}`;
2406
- }
2407
- }
2408
- if (error.file) {
2409
- const fileName = error.file.split(/[/\\]/).pop();
2410
- if (fileName && title.length + fileName.length < 100) {
2411
- title += ` in ${fileName}`;
2412
- }
2413
- }
2414
- if (title.length > 120) {
2415
- title = title.substring(0, 117) + "...";
2416
- }
2417
- return title;
2418
- }
2419
- function getCategoryPrefix(category) {
2420
- const prefixes = {
2421
- nodejs: "Fix",
2422
- npm: "Resolve npm",
2423
- expo: "Fix Expo",
2424
- "react-native": "Fix RN",
2425
- webpack: "Fix build",
2426
- typescript: "Fix TS",
2427
- python: "Fix Python",
2428
- generic: "Fix"
2429
- };
2430
- return prefixes[category] || "Fix";
2431
- }
2432
2412
  function getTagColor(category) {
2433
2413
  const colors = {
2434
2414
  nodejs: "#68A063",
@@ -2550,11 +2530,12 @@ Restored: ${task2.title}`));
2550
2530
  console.log(chalk15.gray(" or: vibetasks archive --unarchive <id>\n"));
2551
2531
  process.exit(1);
2552
2532
  }
2533
+ const validTaskId = taskId;
2553
2534
  spinner.start("Archiving task...");
2554
- let targetId = taskId;
2555
- if (taskId.length < 32) {
2535
+ let targetId = validTaskId;
2536
+ if (validTaskId.length < 32) {
2556
2537
  const allTasks = await taskOps.getTasks("all", true);
2557
- const matchingTask = allTasks.find((t) => t.id.startsWith(taskId));
2538
+ const matchingTask = allTasks.find((t) => t.id.startsWith(validTaskId));
2558
2539
  if (!matchingTask) {
2559
2540
  spinner.fail(chalk15.red("Task not found"));
2560
2541
  console.error(chalk15.gray(`
@@ -2595,6 +2576,7 @@ import { spawn } from "child_process";
2595
2576
  import path3 from "path";
2596
2577
  import { fileURLToPath } from "url";
2597
2578
  import { AuthManager as AuthManager14, TaskOperations as TaskOperations11 } from "@vibetasks/core";
2579
+ import { generateErrorTaskTitle as generateErrorTaskTitle2 } from "@vibetasks/shared";
2598
2580
  var __filename2 = fileURLToPath(import.meta.url);
2599
2581
  var __dirname2 = path3.dirname(__filename2);
2600
2582
  var daemonCommand = new Command15("daemon").description("Manage the VibeTasks error capture daemon").addCommand(createStartCommand()).addCommand(createStopCommand()).addCommand(createStatusCommand()).addCommand(createConfigureCommand()).addCommand(createCaptureCommand());
@@ -2763,21 +2745,21 @@ function createCaptureCommand() {
2763
2745
  process.exit(0);
2764
2746
  }
2765
2747
  console.log(chalk16.red.bold("\nError Detected!\n"));
2766
- console.log(chalk16.cyan("Type: ") + chalk16.white(error.type));
2767
- console.log(chalk16.cyan("Category: ") + chalk16.white(error.category));
2768
- console.log(chalk16.cyan("Message: ") + chalk16.white(error.message));
2769
- if (error.file) {
2770
- console.log(chalk16.cyan("File: ") + chalk16.white(error.file));
2771
- if (error.line) {
2772
- console.log(chalk16.cyan("Line: ") + chalk16.white(error.line.toString()) + (error.column ? chalk16.gray(`:${error.column}`) : ""));
2748
+ console.log(chalk16.cyan("Type: ") + chalk16.white(error.error_type || "Unknown"));
2749
+ console.log(chalk16.cyan("Category: ") + chalk16.white(error.category || "general"));
2750
+ console.log(chalk16.cyan("Message: ") + chalk16.white(error.message || ""));
2751
+ if (error.file_path) {
2752
+ console.log(chalk16.cyan("File: ") + chalk16.white(error.file_path));
2753
+ if (error.line_number) {
2754
+ console.log(chalk16.cyan("Line: ") + chalk16.white(error.line_number.toString()) + (error.column ? chalk16.gray(`:${error.column}`) : ""));
2773
2755
  }
2774
2756
  }
2775
2757
  if (error.suggestion) {
2776
2758
  console.log(chalk16.green("\nSuggestion: ") + chalk16.white(error.suggestion));
2777
2759
  }
2778
- if (error.stack) {
2760
+ if (error.stack_trace) {
2779
2761
  console.log(chalk16.cyan("\nStack Trace (first 5 lines):"));
2780
- const stackLines = error.stack.split("\n").slice(0, 5);
2762
+ const stackLines = error.stack_trace.split("\n").slice(0, 5);
2781
2763
  stackLines.forEach((line) => {
2782
2764
  console.log(chalk16.gray(" " + line));
2783
2765
  });
@@ -2914,59 +2896,27 @@ async function showNotification(title, message, type = "info", duration) {
2914
2896
  console.log(chalk16.blue(`[Notification] ${title}: ${message}`));
2915
2897
  }
2916
2898
  }
2917
- function generateTaskTitle2(error) {
2918
- const prefix = getCategoryPrefix2(error.category);
2919
- let title = `${prefix} ${error.type}`;
2920
- if (error.message && error.message.length < 60) {
2921
- title += `: ${error.message}`;
2922
- } else if (error.message) {
2923
- const shortMessage = error.message.split(/[.!?\n]/)[0].trim();
2924
- if (shortMessage.length < 60) {
2925
- title += `: ${shortMessage}`;
2926
- }
2927
- }
2928
- if (error.file) {
2929
- const fileName = error.file.split(/[/\\]/).pop();
2930
- if (fileName && title.length + fileName.length < 100) {
2931
- title += ` in ${fileName}`;
2932
- }
2933
- }
2934
- if (title.length > 120) {
2935
- title = title.substring(0, 117) + "...";
2936
- }
2937
- return title;
2938
- }
2939
- function getCategoryPrefix2(category) {
2940
- const prefixes = {
2941
- nodejs: "Fix",
2942
- npm: "Resolve npm",
2943
- expo: "Fix Expo",
2944
- "react-native": "Fix RN",
2945
- webpack: "Fix build",
2946
- typescript: "Fix TS",
2947
- python: "Fix Python",
2948
- generic: "Fix"
2949
- };
2950
- return prefixes[category] || "Fix";
2951
- }
2952
2899
  async function createTaskFromError2(error) {
2953
2900
  const spinner = ora12("Creating task from error...").start();
2954
2901
  try {
2955
2902
  const authManager = new AuthManager14();
2956
2903
  const taskOps = await TaskOperations11.fromAuthManager(authManager);
2957
- const title = generateTaskTitle2(error);
2904
+ const title = generateErrorTaskTitle2(error);
2958
2905
  const notes = formatErrorForNotes(error);
2906
+ const category = error.category || "general";
2959
2907
  const task = await taskOps.createTask({
2960
2908
  title,
2961
2909
  notes,
2962
2910
  notes_format: "markdown",
2963
- priority: error.category === "typescript" ? "medium" : "high",
2911
+ priority: category === "typescript" ? "medium" : "high",
2964
2912
  created_by: "ai",
2965
- status: "todo"
2913
+ status: "todo",
2914
+ source_type: "cli",
2915
+ error_context: error
2966
2916
  });
2967
- const tagName = `error-${error.category}`;
2917
+ const tagName = `error-${category}`;
2968
2918
  try {
2969
- const tag = await taskOps.findOrCreateTag(tagName, getTagColor2(error.category));
2919
+ const tag = await taskOps.findOrCreateTag(tagName, getTagColor2(category));
2970
2920
  await taskOps.linkTaskTags(task.id, [tag.id]);
2971
2921
  } catch {
2972
2922
  }
@@ -3036,7 +2986,7 @@ var nextCommand = new Command16("next").description("Show and optionally start t
3036
2986
  }
3037
2987
  const nextTask = tasks[0];
3038
2988
  if (options.start && nextTask.status !== "vibing") {
3039
- await taskOps.updateTaskStatus(nextTask.id, "vibing");
2989
+ await taskOps.updateTask(nextTask.id, { status: "vibing" });
3040
2990
  console.log(chalk17.green(`
3041
2991
  \u26A1 Started vibing on task!
3042
2992
  `));
@@ -3239,10 +3189,584 @@ function formatDuration(start, end) {
3239
3189
  return `${minutes}m`;
3240
3190
  }
3241
3191
 
3192
+ // src/commands/subtask.ts
3193
+ import { Command as Command18 } from "commander";
3194
+ import ora13 from "ora";
3195
+ import chalk19 from "chalk";
3196
+ import { AuthManager as AuthManager16, TaskOperations as TaskOperations13 } from "@vibetasks/core";
3197
+ function parseIndices(args) {
3198
+ const indices = /* @__PURE__ */ new Set();
3199
+ for (const arg of args) {
3200
+ const parts = arg.split(",");
3201
+ for (const part of parts) {
3202
+ const trimmed = part.trim();
3203
+ if (trimmed.includes("-")) {
3204
+ const [startStr, endStr] = trimmed.split("-");
3205
+ const start = parseInt(startStr, 10);
3206
+ const end = parseInt(endStr, 10);
3207
+ if (!isNaN(start) && !isNaN(end) && start <= end) {
3208
+ for (let i = start; i <= end; i++) {
3209
+ indices.add(i);
3210
+ }
3211
+ }
3212
+ } else {
3213
+ const num = parseInt(trimmed, 10);
3214
+ if (!isNaN(num)) {
3215
+ indices.add(num);
3216
+ }
3217
+ }
3218
+ }
3219
+ }
3220
+ return Array.from(indices).sort((a, b) => a - b);
3221
+ }
3222
+ function findSubtasksByTitle(subtasks, searchTerms) {
3223
+ const indices = [];
3224
+ for (const term of searchTerms) {
3225
+ const lowerTerm = term.toLowerCase();
3226
+ subtasks.forEach((subtask, index) => {
3227
+ if (subtask.title.toLowerCase().includes(lowerTerm)) {
3228
+ indices.push(index + 1);
3229
+ }
3230
+ });
3231
+ }
3232
+ return [...new Set(indices)].sort((a, b) => a - b);
3233
+ }
3234
+ var subtaskCommand = new Command18("subtask").description("Manage subtasks within a task");
3235
+ subtaskCommand.command("list").description("List subtasks for a task").argument("<task-id>", "Task ID, short # (1-99), or first 8 characters").action(async (taskIdArg) => {
3236
+ const spinner = ora13("Loading subtasks...").start();
3237
+ try {
3238
+ const authManager = new AuthManager16();
3239
+ const taskOps = await TaskOperations13.fromAuthManager(authManager);
3240
+ const shortIdManager = new ShortIdManager();
3241
+ let taskId = await shortIdManager.resolveId(taskIdArg);
3242
+ if (taskId.length < 32) {
3243
+ const allTasks = await taskOps.getTasks("all");
3244
+ const matchingTask = allTasks.find((t) => t.id.startsWith(taskId));
3245
+ if (!matchingTask) {
3246
+ spinner.fail(chalk19.red("Task not found"));
3247
+ console.error(chalk19.gray(`
3248
+ No task found with ID: ${taskIdArg}
3249
+ `));
3250
+ process.exit(1);
3251
+ }
3252
+ taskId = matchingTask.id;
3253
+ }
3254
+ const task = await taskOps.getTask(taskId);
3255
+ const subtasks = task.subtasks_json || [];
3256
+ spinner.stop();
3257
+ console.log();
3258
+ console.log(chalk19.white.bold(task.title));
3259
+ console.log(chalk19.gray(`ID: ${task.id.substring(0, 8)}`));
3260
+ console.log();
3261
+ if (subtasks.length === 0) {
3262
+ console.log(chalk19.gray(" No subtasks"));
3263
+ } else {
3264
+ const doneCount = subtasks.filter((s) => s.done).length;
3265
+ console.log(chalk19.gray(`Subtasks: ${doneCount}/${subtasks.length} completed`));
3266
+ console.log();
3267
+ subtasks.forEach((subtask, index) => {
3268
+ const checkbox = subtask.done ? chalk19.green("[x]") : chalk19.gray("[ ]");
3269
+ const title = subtask.done ? chalk19.strikethrough.gray(subtask.title) : chalk19.white(subtask.title);
3270
+ console.log(` ${chalk19.cyan(String(index + 1).padStart(2, " "))}. ${checkbox} ${title}`);
3271
+ });
3272
+ }
3273
+ console.log();
3274
+ process.exit(0);
3275
+ } catch (error) {
3276
+ spinner.fail(chalk19.red("Failed to load subtasks"));
3277
+ console.error(chalk19.red(`
3278
+ Error: ${error.message}
3279
+ `));
3280
+ process.exit(1);
3281
+ }
3282
+ });
3283
+ subtaskCommand.command("done").description("Mark subtasks as complete").argument("<task-id>", "Task ID, short # (1-99), or first 8 characters").argument("<indices...>", 'Subtask indices (1-based): "1 2 3", "1-5", "1,3,5", or partial title match').action(async (taskIdArg, indicesArgs) => {
3284
+ const spinner = ora13("Updating subtasks...").start();
3285
+ try {
3286
+ const authManager = new AuthManager16();
3287
+ const taskOps = await TaskOperations13.fromAuthManager(authManager);
3288
+ const shortIdManager = new ShortIdManager();
3289
+ let taskId = await shortIdManager.resolveId(taskIdArg);
3290
+ if (taskId.length < 32) {
3291
+ const allTasks = await taskOps.getTasks("all");
3292
+ const matchingTask = allTasks.find((t) => t.id.startsWith(taskId));
3293
+ if (!matchingTask) {
3294
+ spinner.fail(chalk19.red("Task not found"));
3295
+ console.error(chalk19.gray(`
3296
+ No task found with ID: ${taskIdArg}
3297
+ `));
3298
+ process.exit(1);
3299
+ }
3300
+ taskId = matchingTask.id;
3301
+ }
3302
+ const task = await taskOps.getTask(taskId);
3303
+ const subtasks = [...task.subtasks_json || []];
3304
+ if (subtasks.length === 0) {
3305
+ spinner.fail(chalk19.yellow("No subtasks to update"));
3306
+ process.exit(1);
3307
+ }
3308
+ let indices = parseIndices(indicesArgs);
3309
+ if (indices.length === 0) {
3310
+ indices = findSubtasksByTitle(subtasks, indicesArgs);
3311
+ }
3312
+ if (indices.length === 0) {
3313
+ spinner.fail(chalk19.yellow("No matching subtasks found"));
3314
+ console.error(chalk19.gray("\nProvide indices (1, 2, 3) or partial title matches.\n"));
3315
+ process.exit(1);
3316
+ }
3317
+ const outOfRange = indices.filter((i) => i < 1 || i > subtasks.length);
3318
+ if (outOfRange.length > 0) {
3319
+ spinner.fail(chalk19.red(`Invalid indices: ${outOfRange.join(", ")}`));
3320
+ console.error(chalk19.gray(`
3321
+ Valid range: 1-${subtasks.length}
3322
+ `));
3323
+ process.exit(1);
3324
+ }
3325
+ const updated = [];
3326
+ for (const idx of indices) {
3327
+ if (!subtasks[idx - 1].done) {
3328
+ subtasks[idx - 1].done = true;
3329
+ updated.push(subtasks[idx - 1].title);
3330
+ }
3331
+ }
3332
+ if (updated.length === 0) {
3333
+ spinner.succeed(chalk19.yellow("All specified subtasks were already done"));
3334
+ process.exit(0);
3335
+ }
3336
+ await taskOps.updateTask(taskId, { subtasks_json: subtasks });
3337
+ const doneCount = subtasks.filter((s) => s.done).length;
3338
+ spinner.succeed(chalk19.green(`Marked ${updated.length} subtask(s) as done`));
3339
+ console.log();
3340
+ updated.forEach((title) => {
3341
+ console.log(chalk19.green(` \u2713 ${title}`));
3342
+ });
3343
+ console.log();
3344
+ console.log(chalk19.gray(`Progress: ${doneCount}/${subtasks.length} completed`));
3345
+ if (doneCount === subtasks.length) {
3346
+ console.log();
3347
+ console.log(chalk19.cyan(`All subtasks complete! Run: vibetasks done ${taskId.substring(0, 8)}`));
3348
+ }
3349
+ console.log();
3350
+ process.exit(0);
3351
+ } catch (error) {
3352
+ spinner.fail(chalk19.red("Failed to update subtasks"));
3353
+ console.error(chalk19.red(`
3354
+ Error: ${error.message}
3355
+ `));
3356
+ process.exit(1);
3357
+ }
3358
+ });
3359
+ subtaskCommand.command("undo").description("Mark subtasks as incomplete").argument("<task-id>", "Task ID, short # (1-99), or first 8 characters").argument("<indices...>", 'Subtask indices (1-based): "1 2 3", "1-5", "1,3,5", or partial title match').action(async (taskIdArg, indicesArgs) => {
3360
+ const spinner = ora13("Updating subtasks...").start();
3361
+ try {
3362
+ const authManager = new AuthManager16();
3363
+ const taskOps = await TaskOperations13.fromAuthManager(authManager);
3364
+ const shortIdManager = new ShortIdManager();
3365
+ let taskId = await shortIdManager.resolveId(taskIdArg);
3366
+ if (taskId.length < 32) {
3367
+ const allTasks = await taskOps.getTasks("all");
3368
+ const matchingTask = allTasks.find((t) => t.id.startsWith(taskId));
3369
+ if (!matchingTask) {
3370
+ spinner.fail(chalk19.red("Task not found"));
3371
+ console.error(chalk19.gray(`
3372
+ No task found with ID: ${taskIdArg}
3373
+ `));
3374
+ process.exit(1);
3375
+ }
3376
+ taskId = matchingTask.id;
3377
+ }
3378
+ const task = await taskOps.getTask(taskId);
3379
+ const subtasks = [...task.subtasks_json || []];
3380
+ if (subtasks.length === 0) {
3381
+ spinner.fail(chalk19.yellow("No subtasks to update"));
3382
+ process.exit(1);
3383
+ }
3384
+ let indices = parseIndices(indicesArgs);
3385
+ if (indices.length === 0) {
3386
+ indices = findSubtasksByTitle(subtasks, indicesArgs);
3387
+ }
3388
+ if (indices.length === 0) {
3389
+ spinner.fail(chalk19.yellow("No matching subtasks found"));
3390
+ console.error(chalk19.gray("\nProvide indices (1, 2, 3) or partial title matches.\n"));
3391
+ process.exit(1);
3392
+ }
3393
+ const outOfRange = indices.filter((i) => i < 1 || i > subtasks.length);
3394
+ if (outOfRange.length > 0) {
3395
+ spinner.fail(chalk19.red(`Invalid indices: ${outOfRange.join(", ")}`));
3396
+ console.error(chalk19.gray(`
3397
+ Valid range: 1-${subtasks.length}
3398
+ `));
3399
+ process.exit(1);
3400
+ }
3401
+ const updated = [];
3402
+ for (const idx of indices) {
3403
+ if (subtasks[idx - 1].done) {
3404
+ subtasks[idx - 1].done = false;
3405
+ updated.push(subtasks[idx - 1].title);
3406
+ }
3407
+ }
3408
+ if (updated.length === 0) {
3409
+ spinner.succeed(chalk19.yellow("All specified subtasks were already incomplete"));
3410
+ process.exit(0);
3411
+ }
3412
+ await taskOps.updateTask(taskId, { subtasks_json: subtasks });
3413
+ const doneCount = subtasks.filter((s) => s.done).length;
3414
+ spinner.succeed(chalk19.yellow(`Marked ${updated.length} subtask(s) as incomplete`));
3415
+ console.log();
3416
+ updated.forEach((title) => {
3417
+ console.log(chalk19.yellow(` \u25CB ${title}`));
3418
+ });
3419
+ console.log();
3420
+ console.log(chalk19.gray(`Progress: ${doneCount}/${subtasks.length} completed`));
3421
+ console.log();
3422
+ process.exit(0);
3423
+ } catch (error) {
3424
+ spinner.fail(chalk19.red("Failed to update subtasks"));
3425
+ console.error(chalk19.red(`
3426
+ Error: ${error.message}
3427
+ `));
3428
+ process.exit(1);
3429
+ }
3430
+ });
3431
+
3432
+ // src/commands/error.ts
3433
+ import { Command as Command19 } from "commander";
3434
+ import chalk20 from "chalk";
3435
+ import ora14 from "ora";
3436
+ import { AuthManager as AuthManager17, TaskOperations as TaskOperations14 } from "@vibetasks/core";
3437
+ import {
3438
+ parseError,
3439
+ generateErrorTaskTitle as generateErrorTaskTitle3,
3440
+ detectProjectFromError
3441
+ } from "@vibetasks/shared";
3442
+ function formatErrorNotes(error) {
3443
+ const lines = [];
3444
+ lines.push("## Error Details");
3445
+ lines.push("");
3446
+ if (error.error_type) {
3447
+ lines.push(`**Type:** ${error.error_type}`);
3448
+ }
3449
+ if (error.category) {
3450
+ lines.push(`**Category:** ${error.category}`);
3451
+ }
3452
+ if (error.message) {
3453
+ lines.push(`**Message:** ${error.message}`);
3454
+ }
3455
+ if (error.file_path) {
3456
+ lines.push(`**File:** \`${error.file_path}\``);
3457
+ if (error.line_number) {
3458
+ lines.push(`**Line:** ${error.line_number}${error.column ? `:${error.column}` : ""}`);
3459
+ }
3460
+ }
3461
+ if (error.suggestion) {
3462
+ lines.push("");
3463
+ lines.push("### Suggestion");
3464
+ lines.push(error.suggestion);
3465
+ }
3466
+ if (error.stack_trace) {
3467
+ lines.push("");
3468
+ lines.push("### Stack Trace");
3469
+ lines.push("```");
3470
+ lines.push(error.stack_trace);
3471
+ lines.push("```");
3472
+ }
3473
+ lines.push("");
3474
+ lines.push("### Raw Error");
3475
+ lines.push("```");
3476
+ const rawLines = error.raw_text.split("\n");
3477
+ if (rawLines.length > 30) {
3478
+ lines.push(rawLines.slice(0, 30).join("\n"));
3479
+ lines.push(`... (${rawLines.length - 30} more lines)`);
3480
+ } else {
3481
+ lines.push(error.raw_text);
3482
+ }
3483
+ lines.push("```");
3484
+ return lines.join("\n");
3485
+ }
3486
+ async function readStdin() {
3487
+ if (process.stdin.isTTY) {
3488
+ return null;
3489
+ }
3490
+ return new Promise((resolve) => {
3491
+ let data = "";
3492
+ process.stdin.setEncoding("utf8");
3493
+ process.stdin.on("readable", () => {
3494
+ let chunk;
3495
+ while ((chunk = process.stdin.read()) !== null) {
3496
+ data += chunk;
3497
+ }
3498
+ });
3499
+ process.stdin.on("end", () => {
3500
+ resolve(data || null);
3501
+ });
3502
+ setTimeout(() => {
3503
+ if (!data) resolve(null);
3504
+ }, 100);
3505
+ });
3506
+ }
3507
+ var errorCommand = new Command19("error").description("Capture an error and create a high-priority task").argument("[error-text]", "Error message/stack trace (or pipe from stdin)").option("-p, --project <project>", "Project name").option("--clipboard", "Read error from clipboard").action(async (errorTextArg, options) => {
3508
+ const spinner = ora14();
3509
+ try {
3510
+ let errorText = errorTextArg;
3511
+ if (!errorText) {
3512
+ const stdinData = await readStdin();
3513
+ if (stdinData) {
3514
+ errorText = stdinData;
3515
+ }
3516
+ }
3517
+ if (!errorText && options.clipboard) {
3518
+ try {
3519
+ const clipboardy = await import("clipboardy");
3520
+ errorText = await clipboardy.default.read();
3521
+ } catch {
3522
+ console.log(chalk20.yellow("Clipboard not available in this environment"));
3523
+ }
3524
+ }
3525
+ if (!errorText || !errorText.trim()) {
3526
+ console.log(chalk20.yellow("\nUsage:"));
3527
+ console.log(chalk20.gray(' vibetasks error "TypeError: Cannot read..."'));
3528
+ console.log(chalk20.gray(" npm run build 2>&1 | vibetasks error"));
3529
+ console.log(chalk20.gray(" vibetasks error --clipboard"));
3530
+ console.log("");
3531
+ process.exit(1);
3532
+ }
3533
+ spinner.start("Creating error task...");
3534
+ const authManager = new AuthManager17();
3535
+ const taskOps = await TaskOperations14.fromAuthManager(authManager);
3536
+ const errorContext = parseError(errorText, "terminal");
3537
+ const title = errorContext ? generateErrorTaskTitle3(errorContext) : `Error: ${errorText.split("\n")[0].slice(0, 80)}`;
3538
+ const detectedProject = errorContext ? detectProjectFromError(errorContext) : void 0;
3539
+ const projectTag = options.project || detectedProject;
3540
+ const notes = errorContext ? formatErrorNotes(errorContext) : `\`\`\`
3541
+ ${errorText}
3542
+ \`\`\``;
3543
+ const task = await taskOps.createTask({
3544
+ title,
3545
+ notes,
3546
+ priority: "high",
3547
+ status: "todo",
3548
+ project_tag: projectTag,
3549
+ created_by: "human",
3550
+ source_type: "cli",
3551
+ error_context: errorContext || void 0
3552
+ });
3553
+ spinner.succeed(chalk20.green("Error captured!"));
3554
+ console.log("");
3555
+ console.log(chalk20.white(` ${title}`));
3556
+ if (projectTag) {
3557
+ console.log(chalk20.blue(` Project: ${projectTag}`));
3558
+ }
3559
+ console.log(chalk20.gray(` ID: ${task.id.slice(0, 8)}`));
3560
+ console.log(chalk20.gray(` Priority: high`));
3561
+ console.log("");
3562
+ console.log(chalk20.gray("View your tasks: vibetasks list"));
3563
+ } catch (error) {
3564
+ spinner.fail(chalk20.red("Failed to capture error"));
3565
+ console.error(chalk20.gray(error.message));
3566
+ process.exit(1);
3567
+ }
3568
+ });
3569
+
3570
+ // src/commands/inbox.ts
3571
+ import { Command as Command20 } from "commander";
3572
+ import chalk21 from "chalk";
3573
+ import Table3 from "cli-table3";
3574
+ import { AuthManager as AuthManager18, TaskOperations as TaskOperations15 } from "@vibetasks/core";
3575
+ var sourceDisplay = {
3576
+ sentry: { label: "Sentry", color: chalk21.red },
3577
+ ci: { label: "CI", color: chalk21.yellow },
3578
+ github_bug: { label: "GitHub Bug", color: chalk21.magenta },
3579
+ github_feedback: { label: "GitHub", color: chalk21.magenta },
3580
+ email_bug: { label: "Email Bug", color: chalk21.blue },
3581
+ email_feedback: { label: "Email", color: chalk21.blue },
3582
+ slack_bug: { label: "Slack Bug", color: chalk21.cyan },
3583
+ slack_feedback: { label: "Slack", color: chalk21.cyan },
3584
+ manual: { label: "Manual", color: chalk21.gray }
3585
+ };
3586
+ function getSourceType(task) {
3587
+ if (task.source_type) return task.source_type;
3588
+ if (task.sentry_issue_id) return "sentry";
3589
+ if (task.github_issue_id) return task.title?.toLowerCase().includes("bug") ? "github_bug" : "github_feedback";
3590
+ if (task.email_message_id) return task.title?.toLowerCase().includes("bug") ? "email_bug" : "email_feedback";
3591
+ if (task.slack_message_id) return task.title?.toLowerCase().includes("bug") ? "slack_bug" : "slack_feedback";
3592
+ if (task.tags?.some((t) => t.name === "ci")) return "ci";
3593
+ return "manual";
3594
+ }
3595
+ function formatSource(sourceType) {
3596
+ const config = sourceDisplay[sourceType] || sourceDisplay.manual;
3597
+ return config.color(config.label);
3598
+ }
3599
+ var inboxCommand = new Command20("inbox").description("View inbox items from all sources (Sentry, GitHub, Email, Slack, CI)").option("-s, --source <source>", "Filter by source: sentry, ci, github, email, slack, errors, feedback").option("-p, --priority <priority>", "Filter by priority: high, medium, low").option("-a, --all", "Include acknowledged items").option("-l, --limit <number>", "Maximum items to show", "20").action(async (options) => {
3600
+ try {
3601
+ const authManager = new AuthManager18();
3602
+ const taskOps = await TaskOperations15.fromAuthManager(authManager);
3603
+ let sourceTypes;
3604
+ if (options.source) {
3605
+ switch (options.source.toLowerCase()) {
3606
+ case "sentry":
3607
+ sourceTypes = ["sentry"];
3608
+ break;
3609
+ case "ci":
3610
+ sourceTypes = ["ci"];
3611
+ break;
3612
+ case "github":
3613
+ sourceTypes = ["github_bug", "github_feedback"];
3614
+ break;
3615
+ case "email":
3616
+ sourceTypes = ["email_bug", "email_feedback"];
3617
+ break;
3618
+ case "slack":
3619
+ sourceTypes = ["slack_bug", "slack_feedback"];
3620
+ break;
3621
+ case "errors":
3622
+ sourceTypes = ["sentry", "ci"];
3623
+ break;
3624
+ case "feedback":
3625
+ sourceTypes = ["github_bug", "github_feedback", "email_bug", "email_feedback", "slack_bug", "slack_feedback"];
3626
+ break;
3627
+ default:
3628
+ console.error(chalk21.red(`Invalid source: ${options.source}`));
3629
+ console.error(chalk21.gray("Valid sources: sentry, ci, github, email, slack, errors, feedback"));
3630
+ process.exit(1);
3631
+ }
3632
+ }
3633
+ let priority;
3634
+ if (options.priority) {
3635
+ if (!["high", "medium", "low"].includes(options.priority)) {
3636
+ console.error(chalk21.red(`Invalid priority: ${options.priority}`));
3637
+ console.error(chalk21.gray("Valid priorities: high, medium, low"));
3638
+ process.exit(1);
3639
+ }
3640
+ priority = options.priority;
3641
+ }
3642
+ const limit = parseInt(options.limit, 10);
3643
+ const inboxItems = await taskOps.getInboxItems({
3644
+ source_type: sourceTypes,
3645
+ priority,
3646
+ unacknowledged_only: !options.all,
3647
+ limit
3648
+ });
3649
+ if (inboxItems.length === 0) {
3650
+ console.log(chalk21.green("\nInbox is empty! No items need attention.\n"));
3651
+ process.exit(0);
3652
+ }
3653
+ const table = new Table3({
3654
+ head: [
3655
+ chalk21.cyan("ID"),
3656
+ chalk21.cyan("Source"),
3657
+ chalk21.cyan("Title"),
3658
+ chalk21.cyan("Priority"),
3659
+ chalk21.cyan("Status")
3660
+ ],
3661
+ colWidths: [10, 14, 40, 10, 10],
3662
+ wordWrap: true
3663
+ });
3664
+ const priorityColors = {
3665
+ high: chalk21.red,
3666
+ medium: chalk21.yellow,
3667
+ low: chalk21.blue,
3668
+ none: chalk21.gray
3669
+ };
3670
+ const statusColors = {
3671
+ todo: chalk21.gray,
3672
+ vibing: chalk21.magenta,
3673
+ done: chalk21.green,
3674
+ archived: chalk21.dim
3675
+ };
3676
+ inboxItems.forEach((item) => {
3677
+ const sourceType = getSourceType(item);
3678
+ const priorityColor = priorityColors[item.priority || "none"];
3679
+ const statusColor = statusColors[item.status || "todo"];
3680
+ const ack = item.context_notes?.includes("[AI_ACKNOWLEDGED]") ? chalk21.dim(" (ack)") : "";
3681
+ table.push([
3682
+ item.id.substring(0, 8),
3683
+ formatSource(sourceType),
3684
+ item.title + ack,
3685
+ priorityColor(item.priority || "none"),
3686
+ statusColor(item.status || "todo")
3687
+ ]);
3688
+ });
3689
+ console.log("\n" + chalk21.bold("Inbox Items") + "\n");
3690
+ console.log(table.toString());
3691
+ console.log(chalk21.gray(`
3692
+ Showing ${inboxItems.length} items${options.all ? " (including acknowledged)" : ""}`));
3693
+ console.log(chalk21.gray("Use: vibetasks inbox stats for a summary"));
3694
+ console.log();
3695
+ process.exit(0);
3696
+ } catch (error) {
3697
+ if (error.message.includes("Not authenticated")) {
3698
+ console.error(chalk21.yellow("\nYou need to login first"));
3699
+ console.error(chalk21.gray("Run: vibetasks login\n"));
3700
+ } else {
3701
+ console.error(chalk21.red(`
3702
+ Error: ${error.message}
3703
+ `));
3704
+ }
3705
+ process.exit(1);
3706
+ }
3707
+ });
3708
+ var inboxStatsCommand = new Command20("stats").description("Show inbox statistics").action(async () => {
3709
+ try {
3710
+ const authManager = new AuthManager18();
3711
+ const taskOps = await TaskOperations15.fromAuthManager(authManager);
3712
+ const stats = await taskOps.getInboxStats();
3713
+ console.log("\n" + chalk21.bold("Inbox Statistics") + "\n");
3714
+ console.log(chalk21.white(`Total items: ${stats.total}`));
3715
+ console.log(chalk21.white(`Unacknowledged: ${stats.unacknowledged}`));
3716
+ console.log();
3717
+ console.log(chalk21.cyan("By Source:"));
3718
+ const sources = Object.entries(stats.by_source).filter(([_, count]) => count > 0);
3719
+ if (sources.length === 0) {
3720
+ console.log(chalk21.gray(" No items from any source"));
3721
+ } else {
3722
+ for (const [source, count] of sources) {
3723
+ const config = sourceDisplay[source] || sourceDisplay.manual;
3724
+ console.log(` ${config.color(config.label)}: ${count}`);
3725
+ }
3726
+ }
3727
+ console.log();
3728
+ console.log(chalk21.cyan("By Priority:"));
3729
+ const priorities = Object.entries(stats.by_priority).filter(([_, count]) => count > 0);
3730
+ if (priorities.length === 0) {
3731
+ console.log(chalk21.gray(" No prioritized items"));
3732
+ } else {
3733
+ const priorityColors = {
3734
+ high: chalk21.red,
3735
+ medium: chalk21.yellow,
3736
+ low: chalk21.blue,
3737
+ none: chalk21.gray
3738
+ };
3739
+ for (const [priority, count] of priorities) {
3740
+ const color = priorityColors[priority] || chalk21.gray;
3741
+ console.log(` ${color(priority)}: ${count}`);
3742
+ }
3743
+ }
3744
+ console.log();
3745
+ if (stats.needs_attention) {
3746
+ console.log(chalk21.yellow("Needs attention! Use: vibetasks inbox"));
3747
+ } else {
3748
+ console.log(chalk21.green("Inbox is under control!"));
3749
+ }
3750
+ console.log();
3751
+ process.exit(0);
3752
+ } catch (error) {
3753
+ if (error.message.includes("Not authenticated")) {
3754
+ console.error(chalk21.yellow("\nYou need to login first"));
3755
+ console.error(chalk21.gray("Run: vibetasks login\n"));
3756
+ } else {
3757
+ console.error(chalk21.red(`
3758
+ Error: ${error.message}
3759
+ `));
3760
+ }
3761
+ process.exit(1);
3762
+ }
3763
+ });
3764
+ inboxCommand.addCommand(inboxStatsCommand);
3765
+
3242
3766
  // bin/vibetasks.ts
3243
3767
  var require2 = createRequire(import.meta.url);
3244
3768
  var pkg = require2("../../package.json");
3245
- var program = new Command18();
3769
+ var program = new Command21();
3246
3770
  program.name("vibetasks").description("VibeTasks CLI - Fast task management for vibers").version(pkg.version);
3247
3771
  program.addCommand(setupCommand);
3248
3772
  program.addCommand(loginCommand);
@@ -3262,4 +3786,7 @@ program.addCommand(archiveCommand);
3262
3786
  program.addCommand(daemonCommand);
3263
3787
  program.addCommand(nextCommand);
3264
3788
  program.addCommand(sessionCommand);
3789
+ program.addCommand(subtaskCommand);
3790
+ program.addCommand(errorCommand);
3791
+ program.addCommand(inboxCommand);
3265
3792
  program.parse();