@vibetasks/cli 0.4.7 → 0.5.1

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 (2) hide show
  1. package/dist/bin/vibetasks.js +685 -176
  2. package/package.json +3 -3
@@ -11,15 +11,12 @@ import {
11
11
  } from "../chunk-2KRLRG4G.js";
12
12
 
13
13
  // bin/vibetasks.ts
14
- import { Command as Command16 } from "commander";
14
+ import { Command as Command18 } from "commander";
15
15
  import { createRequire } from "module";
16
16
 
17
17
  // src/commands/login.ts
18
18
  import { Command } from "commander";
19
- import inquirer from "inquirer";
20
- import ora2 from "ora";
21
19
  import chalk2 from "chalk";
22
- import { AuthManager as AuthManager2, createSupabaseClient } from "@vibetasks/core";
23
20
 
24
21
  // src/utils/browser-auth.ts
25
22
  import { createServer } from "http";
@@ -363,88 +360,17 @@ async function getAvailablePort(startPort = 3737) {
363
360
  }
364
361
 
365
362
  // src/commands/login.ts
366
- var loginCommand = new Command("login").description("Authenticate with TaskFlow").option("-b, --browser", "Login via browser (recommended)").option("-e, --email <email>", "Email for non-interactive login").option("-p, --password <password>", "Password for non-interactive login").action(async (options) => {
367
- if (options.browser) {
368
- await loginWithBrowser();
369
- return;
370
- }
371
- let email = options.email;
372
- let password = options.password;
373
- if (email && password) {
374
- console.log(chalk2.blue.bold("\nVibeTasks Login\n"));
375
- } else if (!process.stdin.isTTY) {
376
- console.log(chalk2.red("Error: Non-interactive environment requires --email and --password flags"));
377
- console.log(chalk2.gray("\nUsage: vibetasks login --email you@example.com --password yourpassword"));
378
- console.log(chalk2.gray(" Or: vibetasks login --browser (opens browser for OAuth)"));
379
- process.exit(1);
380
- } else {
381
- console.log(chalk2.blue.bold("\nVibeTasks Login\n"));
382
- const answers = await inquirer.prompt([
383
- {
384
- type: "input",
385
- name: "email",
386
- message: "Email:",
387
- validate: (input) => {
388
- if (!input.includes("@")) return "Please enter a valid email address";
389
- return true;
390
- }
391
- },
392
- {
393
- type: "password",
394
- name: "password",
395
- message: "Password:",
396
- mask: "*",
397
- validate: (input) => {
398
- if (input.length < 6) return "Password must be at least 6 characters";
399
- return true;
400
- }
401
- }
402
- ]);
403
- email = answers.email;
404
- password = answers.password;
405
- }
406
- const spinner = ora2("Authenticating...").start();
407
- try {
408
- const authManager = new AuthManager2();
409
- const supabaseUrl = process.env.TASKFLOW_SUPABASE_URL || "https://cbkkztbcoitrfcleghfd.supabase.co";
410
- const supabaseKey = process.env.TASKFLOW_SUPABASE_KEY || process.env.SUPABASE_ANON_KEY || "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImNia2t6dGJjb2l0cmZjbGVnaGZkIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Njc3NTc0MjgsImV4cCI6MjA4MzMzMzQyOH0.G7ILx-nntP0NbxO1gKt5yASb7nt7OmpJ8qtykeGYbQA";
411
- await authManager.setConfig("supabase_url", supabaseUrl);
412
- await authManager.setConfig("supabase_key", supabaseKey);
413
- const supabase = createSupabaseClient({
414
- supabaseUrl,
415
- supabaseKey
416
- });
417
- const { data, error } = await supabase.auth.signInWithPassword({
418
- email,
419
- password
420
- });
421
- if (error) throw error;
422
- if (!data.session) {
423
- throw new Error("Authentication failed - no session returned");
424
- }
425
- await authManager.setAccessToken(data.session.access_token);
426
- await authManager.setRefreshToken(data.session.refresh_token);
427
- const storageMethod = authManager.getStorageMethod();
428
- const storageLocation = storageMethod === "keychain" ? "system keychain" : authManager["configManager"].getConfigPath();
429
- spinner.succeed(chalk2.green("Successfully authenticated!"));
430
- console.log(chalk2.gray(`
431
- Logged in as: ${data.user.email}`));
432
- console.log(chalk2.gray(`Tokens stored in: ${storageLocation}`));
433
- console.log(chalk2.blue.bold("\n\u2728 You can now use TaskFlow CLI commands\n"));
434
- process.exit(0);
435
- } catch (error) {
436
- spinner.fail(chalk2.red("Authentication failed"));
437
- console.error(chalk2.red(`
438
- Error: ${error.message}`));
439
- process.exit(1);
440
- }
363
+ var loginCommand = new Command("login").description("Authenticate with VibeTasks via browser (Google OAuth)").option("-b, --browser", "Login via browser (default)").action(async () => {
364
+ console.log(chalk2.blue.bold("\n\u{1F510} VibeTasks Login\n"));
365
+ console.log(chalk2.gray("Opening browser for Google sign-in...\n"));
366
+ await loginWithBrowser();
441
367
  });
442
368
 
443
369
  // src/commands/add.ts
444
370
  import { Command as Command2 } from "commander";
445
- import ora3 from "ora";
371
+ import ora2 from "ora";
446
372
  import chalk3 from "chalk";
447
- import { AuthManager as AuthManager3, TaskOperations } from "@vibetasks/core";
373
+ import { AuthManager as AuthManager2, TaskOperations } from "@vibetasks/core";
448
374
 
449
375
  // src/utils/date-parser.ts
450
376
  import { addDays, addWeeks, addMonths, format, parse, isValid } from "date-fns";
@@ -485,10 +411,230 @@ function parseDate(dateStr) {
485
411
 
486
412
  // src/commands/add.ts
487
413
  import { detectProject } from "@vibetasks/shared/utils/project-detector";
488
- var addCommand = new Command2("add").description("Add a new task").argument("<title>", "Task title").option("-n, --notes <notes>", "Task notes (markdown supported)").option("-d, --due <date>", 'Due date (YYYY-MM-DD, "today", "tomorrow", "+3d")').option("-p, --priority <level>", "Priority: low, medium, high", "none").option("-t, --tags <tags...>", "Tags (space-separated)").option("--project <name>", "Override auto-detected project").option("-e, --energy <level>", "Energy required: low, medium, high").action(async (title, options) => {
489
- const spinner = ora3("Creating task...").start();
414
+ import { randomUUID as randomUUID2 } from "crypto";
415
+
416
+ // src/utils/session-manager.ts
417
+ import { writeFile, readFile, mkdir } from "fs/promises";
418
+ import { join } from "path";
419
+ import { homedir } from "os";
420
+ import { randomUUID } from "crypto";
421
+ var ADJECTIVES = [
422
+ "swift",
423
+ "calm",
424
+ "bold",
425
+ "warm",
426
+ "cool",
427
+ "bright",
428
+ "dark",
429
+ "quick",
430
+ "slow",
431
+ "wise",
432
+ "keen",
433
+ "soft",
434
+ "loud",
435
+ "deep",
436
+ "high",
437
+ "low"
438
+ ];
439
+ var NOUNS = [
440
+ "fox",
441
+ "owl",
442
+ "bear",
443
+ "wolf",
444
+ "hawk",
445
+ "moon",
446
+ "star",
447
+ "sun",
448
+ "tree",
449
+ "wave",
450
+ "wind",
451
+ "fire",
452
+ "snow",
453
+ "rain",
454
+ "leaf",
455
+ "stone"
456
+ ];
457
+ var SessionManager = class {
458
+ storePath;
459
+ store = null;
460
+ constructor() {
461
+ this.storePath = join(homedir(), ".vibetasks", "sessions.json");
462
+ }
463
+ /**
464
+ * Generate a memorable session ID like "swift-fox-42"
465
+ */
466
+ generateSessionId() {
467
+ const adj = ADJECTIVES[Math.floor(Math.random() * ADJECTIVES.length)];
468
+ const noun = NOUNS[Math.floor(Math.random() * NOUNS.length)];
469
+ const num = Math.floor(Math.random() * 100);
470
+ return `${adj}-${noun}-${num}`;
471
+ }
472
+ /**
473
+ * Load sessions from disk
474
+ */
475
+ async load() {
476
+ if (this.store) return this.store;
477
+ try {
478
+ const data = await readFile(this.storePath, "utf-8");
479
+ this.store = JSON.parse(data);
480
+ return this.store;
481
+ } catch {
482
+ this.store = { sessions: [] };
483
+ return this.store;
484
+ }
485
+ }
486
+ /**
487
+ * Save sessions to disk
488
+ */
489
+ async save() {
490
+ const dir = join(homedir(), ".vibetasks");
491
+ await mkdir(dir, { recursive: true });
492
+ await writeFile(this.storePath, JSON.stringify(this.store, null, 2));
493
+ }
494
+ /**
495
+ * Start a new session
496
+ */
497
+ async startSession(project) {
498
+ const store = await this.load();
499
+ if (store.currentSession) {
500
+ await this.endSession();
501
+ }
502
+ const session = {
503
+ id: this.generateSessionId(),
504
+ fullId: randomUUID(),
505
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
506
+ project,
507
+ actions: []
508
+ };
509
+ store.sessions.push(session);
510
+ store.currentSession = session.id;
511
+ await this.save();
512
+ return session;
513
+ }
514
+ /**
515
+ * Get current session (or start one if none exists)
516
+ */
517
+ async getCurrentSession() {
518
+ const store = await this.load();
519
+ if (!store.currentSession) {
520
+ return null;
521
+ }
522
+ return store.sessions.find((s) => s.id === store.currentSession) || null;
523
+ }
524
+ /**
525
+ * Get or create current session
526
+ */
527
+ async getOrCreateSession(project) {
528
+ const current = await this.getCurrentSession();
529
+ if (current) return current;
530
+ return this.startSession(project);
531
+ }
532
+ /**
533
+ * Log an action in the current session
534
+ */
535
+ async logAction(action) {
536
+ const store = await this.load();
537
+ const session = store.sessions.find((s) => s.id === store.currentSession);
538
+ if (!session) {
539
+ const newSession = await this.startSession();
540
+ newSession.actions.push({
541
+ ...action,
542
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
543
+ });
544
+ } else {
545
+ session.actions.push({
546
+ ...action,
547
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
548
+ });
549
+ }
550
+ await this.save();
551
+ }
552
+ /**
553
+ * End the current session
554
+ */
555
+ async endSession(summary) {
556
+ const store = await this.load();
557
+ const session = store.sessions.find((s) => s.id === store.currentSession);
558
+ if (session) {
559
+ session.endedAt = (/* @__PURE__ */ new Date()).toISOString();
560
+ session.summary = summary;
561
+ store.currentSession = void 0;
562
+ await this.save();
563
+ }
564
+ return session || null;
565
+ }
566
+ /**
567
+ * Get a session by ID (partial match supported)
568
+ */
569
+ async getSession(id) {
570
+ const store = await this.load();
571
+ let session = store.sessions.find((s) => s.id === id);
572
+ if (session) return session;
573
+ session = store.sessions.find((s) => s.id.includes(id) || s.fullId.startsWith(id));
574
+ return session || null;
575
+ }
576
+ /**
577
+ * Get recent sessions
578
+ */
579
+ async getRecentSessions(limit = 10) {
580
+ const store = await this.load();
581
+ return store.sessions.slice(-limit).reverse();
582
+ }
583
+ /**
584
+ * Get session summary for handoff to next AI
585
+ */
586
+ async getSessionHandoff(sessionId) {
587
+ const session = await this.getSession(sessionId);
588
+ if (!session) {
589
+ return `Session "${sessionId}" not found.`;
590
+ }
591
+ const lines = [
592
+ `## Session: ${session.id}`,
593
+ `Started: ${session.startedAt}`,
594
+ session.endedAt ? `Ended: ${session.endedAt}` : `Status: ACTIVE`,
595
+ session.project ? `Project: ${session.project}` : "",
596
+ "",
597
+ `### Actions (${session.actions.length}):`
598
+ ];
599
+ for (const action of session.actions) {
600
+ const time = new Date(action.timestamp).toLocaleTimeString();
601
+ switch (action.type) {
602
+ case "task_created":
603
+ lines.push(`- [${time}] Created task: "${action.taskTitle}" (${action.taskId})`);
604
+ break;
605
+ case "task_completed":
606
+ lines.push(`- [${time}] Completed: "${action.taskTitle}"`);
607
+ break;
608
+ case "task_updated":
609
+ lines.push(`- [${time}] Updated: "${action.taskTitle}"`);
610
+ break;
611
+ case "file_modified":
612
+ lines.push(`- [${time}] Modified: ${action.filePath}`);
613
+ break;
614
+ case "note":
615
+ lines.push(`- [${time}] Note: ${action.description}`);
616
+ break;
617
+ }
618
+ }
619
+ if (session.summary) {
620
+ lines.push("", "### Summary:", session.summary);
621
+ }
622
+ return lines.filter(Boolean).join("\n");
623
+ }
624
+ };
625
+ var sessionManager = null;
626
+ function getSessionManager() {
627
+ if (!sessionManager) {
628
+ sessionManager = new SessionManager();
629
+ }
630
+ return sessionManager;
631
+ }
632
+
633
+ // src/commands/add.ts
634
+ var addCommand = new Command2("add").description("Add a new task").argument("<title>", "Task title").option("-n, --notes <notes>", "Task notes (markdown supported)").option("-d, --due <date>", 'Due date (YYYY-MM-DD, "today", "tomorrow", "+3d")').option("-p, --priority <level>", "Priority: low, medium, high", "none").option("-t, --tags <tags...>", "Tags (space-separated)").option("-s, --subtasks <subtasks...>", "Subtasks (space-separated, use quotes for multi-word)").option("--project <name>", "Override auto-detected project").option("-e, --energy <level>", "Energy required: low, medium, high").action(async (title, options) => {
635
+ const spinner = ora2("Creating task...").start();
490
636
  try {
491
- const authManager = new AuthManager3();
637
+ const authManager = new AuthManager2();
492
638
  const taskOps = await TaskOperations.fromAuthManager(authManager);
493
639
  let projectTag;
494
640
  if (options.project) {
@@ -523,6 +669,11 @@ var addCommand = new Command2("add").description("Add a new task").argument("<ti
523
669
  throw new Error(`Invalid energy level. Must be one of: ${validEnergy.join(", ")}`);
524
670
  }
525
671
  }
672
+ const subtasksJson = options.subtasks?.map((subtaskTitle) => ({
673
+ id: randomUUID2(),
674
+ title: subtaskTitle,
675
+ done: false
676
+ })) || [];
526
677
  const task = await taskOps.createTask({
527
678
  title,
528
679
  notes: options.notes,
@@ -535,7 +686,8 @@ var addCommand = new Command2("add").description("Add a new task").argument("<ti
535
686
  // ai or human
536
687
  status: createdBy === "ai" ? "vibing" : "todo",
537
688
  // AI tasks start vibing
538
- energy_required: options.energy
689
+ energy_required: options.energy,
690
+ subtasks_json: subtasksJson
539
691
  });
540
692
  if (options.tags && options.tags.length > 0) {
541
693
  const tagIds = [];
@@ -546,6 +698,15 @@ var addCommand = new Command2("add").description("Add a new task").argument("<ti
546
698
  await taskOps.linkTaskTags(task.id, tagIds);
547
699
  }
548
700
  spinner.succeed(chalk3.green("Task created!"));
701
+ if (createdBy === "ai") {
702
+ const sessionManager2 = getSessionManager();
703
+ await sessionManager2.logAction({
704
+ type: "task_created",
705
+ description: `Created task: "${title}"`,
706
+ taskId: task.id,
707
+ taskTitle: title
708
+ });
709
+ }
549
710
  console.log();
550
711
  if (projectTag) {
551
712
  console.log(chalk3.gray(`\u{1F4C1} Project: ${chalk3.white(projectTag)}`));
@@ -577,6 +738,12 @@ var addCommand = new Command2("add").description("Add a new task").argument("<ti
577
738
  if (options.tags && options.tags.length > 0) {
578
739
  console.log(chalk3.magenta(`Tags: ${options.tags.join(", ")}`));
579
740
  }
741
+ if (subtasksJson.length > 0) {
742
+ console.log(chalk3.cyan(`Subtasks: ${subtasksJson.length}`));
743
+ subtasksJson.forEach((st, i) => {
744
+ console.log(chalk3.gray(` ${i + 1}. ${st.title}`));
745
+ });
746
+ }
580
747
  console.log();
581
748
  process.exit(0);
582
749
  } catch (error) {
@@ -600,8 +767,82 @@ function isRunningInClaudeCode() {
600
767
  import { Command as Command3 } from "commander";
601
768
  import chalk4 from "chalk";
602
769
  import Table from "cli-table3";
603
- import { AuthManager as AuthManager4, TaskOperations as TaskOperations2 } from "@vibetasks/core";
604
- var listCommand = new Command3("list").description("List tasks").argument("[filter]", "Filter: all, today, upcoming, completed", "all").option("-l, --limit <number>", "Maximum number of tasks to show", "50").option("--project <name>", "Filter by project tag").option("--created-by <source>", "Filter by creator: ai or human").option("--status <status>", "Filter by status: todo, vibing, done").action(async (filter, options) => {
770
+ import { AuthManager as AuthManager3, TaskOperations as TaskOperations2 } from "@vibetasks/core";
771
+
772
+ // src/utils/short-ids.ts
773
+ import { writeFile as writeFile2, readFile as readFile2, mkdir as mkdir2 } from "fs/promises";
774
+ import { join as join2 } from "path";
775
+ import { homedir as homedir2 } from "os";
776
+ var ShortIdManager = class {
777
+ storePath;
778
+ maxIds = 99;
779
+ constructor() {
780
+ this.storePath = join2(homedir2(), ".vibetasks", "short-ids.json");
781
+ }
782
+ /**
783
+ * Save mappings from a list of task IDs
784
+ * Short IDs are assigned 1, 2, 3... based on array order
785
+ */
786
+ async saveMappings(taskIds) {
787
+ const mappings = taskIds.slice(0, this.maxIds).map((fullId, index) => ({
788
+ shortId: index + 1,
789
+ fullId,
790
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
791
+ }));
792
+ const store = {
793
+ mappings,
794
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
795
+ };
796
+ const dir = join2(homedir2(), ".vibetasks");
797
+ await mkdir2(dir, { recursive: true });
798
+ await writeFile2(this.storePath, JSON.stringify(store, null, 2));
799
+ }
800
+ /**
801
+ * Get the full UUID for a short ID
802
+ */
803
+ async getFullId(shortId) {
804
+ try {
805
+ const content = await readFile2(this.storePath, "utf-8");
806
+ const store = JSON.parse(content);
807
+ const mapping = store.mappings.find((m) => m.shortId === shortId);
808
+ return mapping?.fullId || null;
809
+ } catch {
810
+ return null;
811
+ }
812
+ }
813
+ /**
814
+ * Get the short ID for a full UUID (if it exists in current mappings)
815
+ */
816
+ async getShortId(fullId) {
817
+ try {
818
+ const content = await readFile2(this.storePath, "utf-8");
819
+ const store = JSON.parse(content);
820
+ const mapping = store.mappings.find((m) => m.fullId === fullId);
821
+ return mapping?.shortId || null;
822
+ } catch {
823
+ return null;
824
+ }
825
+ }
826
+ /**
827
+ * Resolve an ID that could be either short (1-99) or full UUID
828
+ */
829
+ async resolveId(idOrShortId) {
830
+ const shortId = parseInt(idOrShortId, 10);
831
+ if (!isNaN(shortId) && shortId >= 1 && shortId <= this.maxIds) {
832
+ const fullId = await this.getFullId(shortId);
833
+ if (fullId) {
834
+ return fullId;
835
+ }
836
+ throw new Error(
837
+ `Short ID #${shortId} not found. Run 'vibetasks list --short-ids' first to generate mappings.`
838
+ );
839
+ }
840
+ return idOrShortId;
841
+ }
842
+ };
843
+
844
+ // src/commands/list.ts
845
+ var listCommand = new Command3("list").description("List tasks").argument("[filter]", "Filter: all, today, upcoming, completed", "all").option("-l, --limit <number>", "Maximum number of tasks to show", "50").option("--project <name>", "Filter by project tag").option("--created-by <source>", "Filter by creator: ai or human").option("--status <status>", "Filter by status: todo, vibing, done").option("--short-ids", "Show short numeric IDs (1-99) for easy reference").action(async (filter, options) => {
605
846
  try {
606
847
  const validFilters = ["all", "today", "upcoming", "completed"];
607
848
  if (!validFilters.includes(filter)) {
@@ -609,7 +850,7 @@ var listCommand = new Command3("list").description("List tasks").argument("[filt
609
850
  console.error(chalk4.gray(`Valid filters: ${validFilters.join(", ")}`));
610
851
  process.exit(1);
611
852
  }
612
- const authManager = new AuthManager4();
853
+ const authManager = new AuthManager3();
613
854
  const taskOps = await TaskOperations2.fromAuthManager(authManager);
614
855
  let tasks = await taskOps.getTasks(filter);
615
856
  if (options.project) {
@@ -645,8 +886,18 @@ ${filterMessages[filter] || "No tasks found"}.
645
886
  }
646
887
  const limit = parseInt(options.limit, 10);
647
888
  const displayTasks = tasks.slice(0, limit);
889
+ const shortIdManager = new ShortIdManager();
890
+ if (options.shortIds) {
891
+ await shortIdManager.saveMappings(displayTasks.map((t) => t.id));
892
+ }
648
893
  const table = new Table({
649
- head: [
894
+ head: options.shortIds ? [
895
+ chalk4.cyan("#"),
896
+ chalk4.cyan("Status"),
897
+ chalk4.cyan("Title"),
898
+ chalk4.cyan("Progress"),
899
+ chalk4.cyan("Due")
900
+ ] : [
650
901
  chalk4.cyan("ID"),
651
902
  chalk4.cyan("Status"),
652
903
  chalk4.cyan("Title"),
@@ -654,10 +905,10 @@ ${filterMessages[filter] || "No tasks found"}.
654
905
  chalk4.cyan("Priority"),
655
906
  chalk4.cyan("Due")
656
907
  ],
657
- colWidths: [10, 10, 35, 15, 10, 12],
908
+ colWidths: options.shortIds ? [5, 10, 40, 12, 12] : [10, 10, 35, 15, 10, 12],
658
909
  wordWrap: true
659
910
  });
660
- displayTasks.forEach((task) => {
911
+ displayTasks.forEach((task, index) => {
661
912
  const priorityColors = {
662
913
  high: chalk4.red,
663
914
  medium: chalk4.yellow,
@@ -676,6 +927,7 @@ ${filterMessages[filter] || "No tasks found"}.
676
927
  };
677
928
  const priorityColor = priorityColors[task.priority || "none"];
678
929
  const statusColor = statusColors[task.status || "todo"];
930
+ const shortId = chalk4.yellow.bold(`${index + 1}`);
679
931
  const id = task.id.substring(0, 8);
680
932
  const status = statusColor(`${statusEmojis[task.status || "todo"]} ${task.status || "todo"}`);
681
933
  const title = task.status === "done" ? chalk4.strikethrough(task.title) : task.title;
@@ -683,7 +935,15 @@ ${filterMessages[filter] || "No tasks found"}.
683
935
  const project = task.project_tag ? chalk4.blue(task.project_tag) : chalk4.gray("-");
684
936
  const priority = priorityColor(task.priority || "none");
685
937
  const dueDate = task.due_date ? task.due_date.split("T")[0] : chalk4.gray("-");
686
- table.push([id, status, titleWithAI, project, priority, dueDate]);
938
+ const subtasks = task.subtasks_json || task.subtasks || [];
939
+ const doneCount = subtasks.filter((s) => s.done).length;
940
+ const totalCount = subtasks.length;
941
+ const progress = totalCount > 0 ? chalk4.cyan(`${doneCount}/${totalCount}`) : chalk4.gray("-");
942
+ if (options.shortIds) {
943
+ table.push([shortId, status, titleWithAI, progress, dueDate]);
944
+ } else {
945
+ table.push([id, status, titleWithAI, project, priority, dueDate]);
946
+ }
687
947
  });
688
948
  console.log("\n" + table.toString());
689
949
  const filterLabels = {
@@ -697,6 +957,10 @@ Total: ${tasks.length} ${filterLabels[filter]} task${tasks.length === 1 ? "" : "
697
957
  if (tasks.length > limit) {
698
958
  console.log(chalk4.yellow(`Showing ${limit} of ${tasks.length} tasks. Use --limit to show more.`));
699
959
  }
960
+ if (options.shortIds) {
961
+ console.log(chalk4.gray(`
962
+ Use: vibetasks vibing <#> to start working on a task`));
963
+ }
700
964
  console.log();
701
965
  process.exit(0);
702
966
  } catch (error) {
@@ -714,18 +978,19 @@ Error: ${error.message}
714
978
 
715
979
  // src/commands/done.ts
716
980
  import { Command as Command4 } from "commander";
717
- import ora4 from "ora";
981
+ import ora3 from "ora";
718
982
  import chalk5 from "chalk";
719
- import { AuthManager as AuthManager5, TaskOperations as TaskOperations3 } from "@vibetasks/core";
720
- var doneCommand = new Command4("done").description("Mark a task as complete").argument("<id>", "Task ID (full or first 8 characters)").action(async (id) => {
721
- const spinner = ora4("Completing task...").start();
983
+ 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) => {
985
+ const spinner = ora3("Completing task...").start();
722
986
  try {
723
- const authManager = new AuthManager5();
987
+ const authManager = new AuthManager4();
724
988
  const taskOps = await TaskOperations3.fromAuthManager(authManager);
725
- let taskId = id;
726
- if (id.length < 32) {
989
+ const shortIdManager = new ShortIdManager();
990
+ let taskId = await shortIdManager.resolveId(id);
991
+ if (taskId.length < 32) {
727
992
  const allTasks = await taskOps.getTasks("all");
728
- const matchingTask = allTasks.find((t) => t.id.startsWith(id));
993
+ const matchingTask = allTasks.find((t) => t.id.startsWith(taskId));
729
994
  if (!matchingTask) {
730
995
  spinner.fail(chalk5.red("Task not found"));
731
996
  console.error(chalk5.gray(`
@@ -736,6 +1001,13 @@ No task found with ID starting with: ${id}
736
1001
  taskId = matchingTask.id;
737
1002
  }
738
1003
  const task = await taskOps.completeTask(taskId);
1004
+ const sessionManager2 = getSessionManager();
1005
+ await sessionManager2.logAction({
1006
+ type: "task_completed",
1007
+ description: `Completed: "${task.title}"`,
1008
+ taskId: task.id,
1009
+ taskTitle: task.title
1010
+ });
739
1011
  spinner.succeed(chalk5.green("Task completed!"));
740
1012
  console.log(chalk5.gray(`
741
1013
  \u2713 ${task.title}`));
@@ -759,15 +1031,20 @@ Error: ${error.message}
759
1031
  // src/commands/vibing.ts
760
1032
  import { Command as Command5 } from "commander";
761
1033
  import chalk6 from "chalk";
762
- import ora5 from "ora";
763
- import inquirer2 from "inquirer";
764
- import { AuthManager as AuthManager6, TaskOperations as TaskOperations4 } from "@vibetasks/core";
1034
+ import ora4 from "ora";
1035
+ import inquirer from "inquirer";
1036
+ import { AuthManager as AuthManager5, TaskOperations as TaskOperations4 } from "@vibetasks/core";
765
1037
  var WIP_LIMIT = 3;
766
- var vibingCommand = new Command5("vibing").alias("start").alias("v").description("Start working on a task (move to vibing status)").argument("[task-id]", "Task ID to start vibing on").option("-p, --pick", "Pick from todo tasks interactively").action(async (taskId, options) => {
767
- const spinner = ora5();
1038
+ var vibingCommand = new Command5("vibing").alias("start").alias("v").description("Start working on a task (move to vibing status)").argument("[task-id]", "Task ID or short # (1-99) to start vibing on").option("-p, --pick", "Pick from todo tasks interactively").action(async (taskIdInput, options) => {
1039
+ const spinner = ora4();
768
1040
  try {
769
- const authManager = new AuthManager6();
1041
+ const authManager = new AuthManager5();
770
1042
  const taskOps = await TaskOperations4.fromAuthManager(authManager);
1043
+ const shortIdManager = new ShortIdManager();
1044
+ let taskId;
1045
+ if (taskIdInput) {
1046
+ taskId = await shortIdManager.resolveId(taskIdInput);
1047
+ }
771
1048
  const allTasks = await taskOps.getTasks("all");
772
1049
  const vibingTasks = allTasks.filter((t) => t.status === "vibing" && !t.completed);
773
1050
  if (vibingTasks.length >= WIP_LIMIT) {
@@ -779,7 +1056,7 @@ var vibingCommand = new Command5("vibing").alias("start").alias("v").description
779
1056
  console.log(chalk6.magenta(` ${i + 1}. ${t.title}`));
780
1057
  });
781
1058
  console.log("");
782
- const { proceed } = await inquirer2.prompt([{
1059
+ const { proceed } = await inquirer.prompt([{
783
1060
  type: "confirm",
784
1061
  name: "proceed",
785
1062
  message: "Start another task anyway?",
@@ -796,7 +1073,7 @@ var vibingCommand = new Command5("vibing").alias("start").alias("v").description
796
1073
  console.log(chalk6.yellow('\nNo todo tasks found. Add one with `vibetasks add "task title"`\n'));
797
1074
  process.exit(0);
798
1075
  }
799
- const { selectedTask } = await inquirer2.prompt([{
1076
+ const { selectedTask } = await inquirer.prompt([{
800
1077
  type: "list",
801
1078
  name: "selectedTask",
802
1079
  message: "Pick a task to start:",
@@ -832,10 +1109,10 @@ var vibingCommand = new Command5("vibing").alias("start").alias("v").description
832
1109
  import { Command as Command6 } from "commander";
833
1110
  import chalk7 from "chalk";
834
1111
  import Table2 from "cli-table3";
835
- import { AuthManager as AuthManager7, TaskOperations as TaskOperations5 } from "@vibetasks/core";
1112
+ import { AuthManager as AuthManager6, TaskOperations as TaskOperations5 } from "@vibetasks/core";
836
1113
  var searchCommand = new Command6("search").description("Search tasks by title").argument("<query>", "Search query").option("-l, --limit <number>", "Maximum number of results", "20").action(async (query, options) => {
837
1114
  try {
838
- const authManager = new AuthManager7();
1115
+ const authManager = new AuthManager6();
839
1116
  const taskOps = await TaskOperations5.fromAuthManager(authManager);
840
1117
  const limit = parseInt(options.limit, 10);
841
1118
  const tasks = await taskOps.searchTasks(query, limit);
@@ -890,18 +1167,18 @@ Error: ${error.message}
890
1167
 
891
1168
  // src/commands/update.ts
892
1169
  import { Command as Command7 } from "commander";
893
- import ora6 from "ora";
1170
+ import ora5 from "ora";
894
1171
  import chalk8 from "chalk";
895
- import { AuthManager as AuthManager8, TaskOperations as TaskOperations6 } from "@vibetasks/core";
1172
+ import { AuthManager as AuthManager7, TaskOperations as TaskOperations6 } from "@vibetasks/core";
896
1173
  var updateCommand = new Command7("update").description("Update a task").argument("<id>", "Task ID (full or first 8 characters)").option("-t, --title <title>", "New title").option("-n, --notes <notes>", "New notes").option("-d, --due <date>", "New due date").option("-p, --priority <level>", "New priority: low, medium, high, none").option("-s, --status <status>", "New status: todo, vibing, done").option("--project <name>", "New project tag").option("-e, --energy <level>", "Energy required: low, medium, high").option("-c, --context <notes>", "Update context notes").action(async (id, options) => {
897
1174
  if (!options.title && !options.notes && !options.due && !options.priority && !options.status && !options.project && !options.energy && !options.context) {
898
1175
  console.error(chalk8.red("\nError: No updates specified"));
899
1176
  console.error(chalk8.gray("Provide at least one option: --title, --notes, --due, --priority, --status, --project, --energy, or --context\n"));
900
1177
  process.exit(1);
901
1178
  }
902
- const spinner = ora6("Updating task...").start();
1179
+ const spinner = ora5("Updating task...").start();
903
1180
  try {
904
- const authManager = new AuthManager8();
1181
+ const authManager = new AuthManager7();
905
1182
  const taskOps = await TaskOperations6.fromAuthManager(authManager);
906
1183
  let taskId = id;
907
1184
  if (id.length < 32) {
@@ -965,13 +1242,13 @@ Error: ${error.message}
965
1242
 
966
1243
  // src/commands/delete.ts
967
1244
  import { Command as Command8 } from "commander";
968
- import ora7 from "ora";
1245
+ import ora6 from "ora";
969
1246
  import chalk9 from "chalk";
970
- import inquirer3 from "inquirer";
971
- import { AuthManager as AuthManager9, TaskOperations as TaskOperations7 } from "@vibetasks/core";
1247
+ import inquirer2 from "inquirer";
1248
+ import { AuthManager as AuthManager8, TaskOperations as TaskOperations7 } from "@vibetasks/core";
972
1249
  var deleteCommand = new Command8("delete").description("Delete a task").argument("<id>", "Task ID (full or first 8 characters)").option("-y, --yes", "Skip confirmation").action(async (id, options) => {
973
1250
  try {
974
- const authManager = new AuthManager9();
1251
+ const authManager = new AuthManager8();
975
1252
  const taskOps = await TaskOperations7.fromAuthManager(authManager);
976
1253
  let taskId = id;
977
1254
  let taskTitle = "";
@@ -991,7 +1268,7 @@ var deleteCommand = new Command8("delete").description("Delete a task").argument
991
1268
  taskTitle = task.title;
992
1269
  }
993
1270
  if (!options.yes) {
994
- const answers = await inquirer3.prompt([
1271
+ const answers = await inquirer2.prompt([
995
1272
  {
996
1273
  type: "confirm",
997
1274
  name: "confirm",
@@ -1004,7 +1281,7 @@ var deleteCommand = new Command8("delete").description("Delete a task").argument
1004
1281
  process.exit(0);
1005
1282
  }
1006
1283
  }
1007
- const spinner = ora7("Deleting task...").start();
1284
+ const spinner = ora6("Deleting task...").start();
1008
1285
  await taskOps.deleteTask(taskId);
1009
1286
  spinner.succeed(chalk9.green("Task deleted!"));
1010
1287
  console.log(chalk9.gray(`
@@ -1027,10 +1304,10 @@ var deleteCommand = new Command8("delete").description("Delete a task").argument
1027
1304
  // src/commands/config.ts
1028
1305
  import { Command as Command9 } from "commander";
1029
1306
  import chalk10 from "chalk";
1030
- import { AuthManager as AuthManager10 } from "@vibetasks/core";
1307
+ import { AuthManager as AuthManager9 } from "@vibetasks/core";
1031
1308
  var configCommand = new Command9("config").description("View or set configuration").argument("[key]", "Configuration key").argument("[value]", "Configuration value").action(async (key, value) => {
1032
1309
  try {
1033
- const authManager = new AuthManager10();
1310
+ const authManager = new AuthManager9();
1034
1311
  if (!key) {
1035
1312
  const configManager = authManager["configManager"];
1036
1313
  const config = await configManager.getConfig();
@@ -1087,7 +1364,7 @@ Error: ${error.message}
1087
1364
  // src/commands/hooks.ts
1088
1365
  import { Command as Command10 } from "commander";
1089
1366
  import chalk11 from "chalk";
1090
- import ora8 from "ora";
1367
+ import ora7 from "ora";
1091
1368
  import fs from "fs/promises";
1092
1369
  import path from "path";
1093
1370
  function getVibetasksHooksPath() {
@@ -1097,7 +1374,7 @@ function getVibetasksHooksPath() {
1097
1374
  }
1098
1375
  var hooksCommand = new Command10("hooks").description("Manage hooks integration (git and Claude Code)");
1099
1376
  hooksCommand.command("install").description("Install git hooks in current repository").action(async () => {
1100
- const spinner = ora8("Installing git hooks...").start();
1377
+ const spinner = ora7("Installing git hooks...").start();
1101
1378
  try {
1102
1379
  const gitDir = path.join(process.cwd(), ".git");
1103
1380
  try {
@@ -1159,7 +1436,7 @@ Error: ${error.message}
1159
1436
  }
1160
1437
  });
1161
1438
  hooksCommand.command("claude").description("Generate Claude Code hook configuration for TodoWrite sync").option("--project <path>", "Project path (defaults to current directory)").option("--output", "Output config to stdout instead of installing").action(async (options) => {
1162
- const spinner = ora8("Generating Claude Code hook configuration...").start();
1439
+ const spinner = ora7("Generating Claude Code hook configuration...").start();
1163
1440
  try {
1164
1441
  const projectPath = options.project || process.cwd();
1165
1442
  const hooksPath = getVibetasksHooksPath();
@@ -1261,15 +1538,15 @@ hooksCommand.command("status").description("Show status of installed hooks").act
1261
1538
 
1262
1539
  // src/commands/init.ts
1263
1540
  import { Command as Command11 } from "commander";
1264
- import inquirer4 from "inquirer";
1265
- import ora9 from "ora";
1541
+ import inquirer3 from "inquirer";
1542
+ import ora8 from "ora";
1266
1543
  import chalk12 from "chalk";
1267
- import { AuthManager as AuthManager11 } from "@vibetasks/core";
1544
+ import { AuthManager as AuthManager10 } from "@vibetasks/core";
1268
1545
  import { detectProject as detectProject2 } from "@vibetasks/shared/utils/project-detector";
1269
1546
  var initCommand = new Command11("init").description("Initialize TaskFlow for current project (auto-detect from git)").option("--name <name>", "Manually specify project name").action(async (options) => {
1270
- const spinner = ora9("Detecting project...").start();
1547
+ const spinner = ora8("Detecting project...").start();
1271
1548
  try {
1272
- const authManager = new AuthManager11();
1549
+ const authManager = new AuthManager10();
1273
1550
  const cwd = process.cwd();
1274
1551
  let project;
1275
1552
  if (options.name) {
@@ -1288,7 +1565,7 @@ var initCommand = new Command11("init").description("Initialize TaskFlow for cur
1288
1565
  console.log(chalk12.gray(` Source: ${chalk12.white(project.source)}`));
1289
1566
  console.log(chalk12.gray(` Path: ${chalk12.white(project.path)}
1290
1567
  `));
1291
- const answers = await inquirer4.prompt([
1568
+ const answers = await inquirer3.prompt([
1292
1569
  {
1293
1570
  type: "confirm",
1294
1571
  name: "confirm",
@@ -1325,8 +1602,8 @@ Error: ${error.message}
1325
1602
 
1326
1603
  // src/commands/setup.ts
1327
1604
  import { Command as Command12 } from "commander";
1328
- import inquirer5 from "inquirer";
1329
- import ora10 from "ora";
1605
+ import inquirer4 from "inquirer";
1606
+ import ora9 from "ora";
1330
1607
  import chalk13 from "chalk";
1331
1608
  import fs2 from "fs/promises";
1332
1609
  import path2 from "path";
@@ -1334,7 +1611,7 @@ import os from "os";
1334
1611
  import { createServer as createServer2 } from "http";
1335
1612
  import { exec as exec2 } from "child_process";
1336
1613
  import { promisify as promisify2 } from "util";
1337
- import { AuthManager as AuthManager12, TaskOperations as TaskOperations8, createSupabaseClient as createSupabaseClient2 } from "@vibetasks/core";
1614
+ import { AuthManager as AuthManager11, TaskOperations as TaskOperations8, createSupabaseClient } from "@vibetasks/core";
1338
1615
  import { detectProject as detectProject3 } from "@vibetasks/shared/utils/project-detector";
1339
1616
  var execAsync2 = promisify2(exec2);
1340
1617
  var SUPABASE_URL = "https://cbkkztbcoitrfcleghfd.supabase.co";
@@ -1399,12 +1676,12 @@ function showWelcome() {
1399
1676
  }
1400
1677
  async function checkExistingAuth() {
1401
1678
  try {
1402
- const authManager = new AuthManager12();
1679
+ const authManager = new AuthManager11();
1403
1680
  const token = await authManager.getAccessToken();
1404
1681
  if (!token) return { authenticated: false };
1405
1682
  const supabaseUrl = await authManager.getConfig("supabase_url") || SUPABASE_URL;
1406
1683
  const supabaseKey = await authManager.getConfig("supabase_key") || SUPABASE_ANON_KEY;
1407
- const supabase = createSupabaseClient2({ supabaseUrl, supabaseKey, accessToken: token });
1684
+ const supabase = createSupabaseClient({ supabaseUrl, supabaseKey, accessToken: token });
1408
1685
  const { data: { user } } = await supabase.auth.getUser();
1409
1686
  if (user?.email) {
1410
1687
  return { authenticated: true, email: user.email };
@@ -1443,7 +1720,7 @@ async function runBrowserAuth() {
1443
1720
  return;
1444
1721
  }
1445
1722
  try {
1446
- const authManager = new AuthManager12();
1723
+ const authManager = new AuthManager11();
1447
1724
  await authManager.setAccessToken(accessToken);
1448
1725
  await authManager.setRefreshToken(refreshToken);
1449
1726
  if (supabaseUrl) await authManager.setConfig("supabase_url", supabaseUrl);
@@ -1487,7 +1764,7 @@ async function stepAuthentication() {
1487
1764
  const existing = await checkExistingAuth();
1488
1765
  if (existing.authenticated) {
1489
1766
  console.log(chalk13.green(" \u2713") + chalk13.white(` Already logged in as ${chalk13.cyan(existing.email)}`));
1490
- const { reauth } = await inquirer5.prompt([{
1767
+ const { reauth } = await inquirer4.prompt([{
1491
1768
  type: "confirm",
1492
1769
  name: "reauth",
1493
1770
  message: "Re-authenticate with a different account?",
@@ -1497,7 +1774,7 @@ async function stepAuthentication() {
1497
1774
  return { success: true, email: existing.email, skipped: true };
1498
1775
  }
1499
1776
  }
1500
- const { authMethod } = await inquirer5.prompt([{
1777
+ const { authMethod } = await inquirer4.prompt([{
1501
1778
  type: "list",
1502
1779
  name: "authMethod",
1503
1780
  message: "How would you like to authenticate?",
@@ -1507,7 +1784,7 @@ async function stepAuthentication() {
1507
1784
  ]
1508
1785
  }]);
1509
1786
  if (authMethod === "browser") {
1510
- const spinner = ora10("Opening browser for authentication...").start();
1787
+ const spinner = ora9("Opening browser for authentication...").start();
1511
1788
  spinner.stop();
1512
1789
  console.log(chalk13.gray(" Waiting for browser authentication...\n"));
1513
1790
  const result = await runBrowserAuth();
@@ -1519,7 +1796,7 @@ async function stepAuthentication() {
1519
1796
  }
1520
1797
  return result;
1521
1798
  } else {
1522
- const answers = await inquirer5.prompt([
1799
+ const answers = await inquirer4.prompt([
1523
1800
  {
1524
1801
  type: "input",
1525
1802
  name: "email",
@@ -1534,12 +1811,12 @@ async function stepAuthentication() {
1534
1811
  validate: (input) => input.length >= 6 || "Password must be at least 6 characters"
1535
1812
  }
1536
1813
  ]);
1537
- const spinner = ora10("Authenticating...").start();
1814
+ const spinner = ora9("Authenticating...").start();
1538
1815
  try {
1539
- const authManager = new AuthManager12();
1816
+ const authManager = new AuthManager11();
1540
1817
  await authManager.setConfig("supabase_url", SUPABASE_URL);
1541
1818
  await authManager.setConfig("supabase_key", SUPABASE_ANON_KEY);
1542
- const supabase = createSupabaseClient2({
1819
+ const supabase = createSupabaseClient({
1543
1820
  supabaseUrl: SUPABASE_URL,
1544
1821
  supabaseKey: SUPABASE_ANON_KEY
1545
1822
  });
@@ -1569,7 +1846,7 @@ async function stepClaudeCodeConfig() {
1569
1846
  if (!hasClaudeCode) {
1570
1847
  console.log(chalk13.yellow(" \u26A0") + chalk13.gray(" Claude Code config directory not found"));
1571
1848
  console.log(chalk13.gray(" Run this command again after installing Claude Code"));
1572
- const { createAnyway } = await inquirer5.prompt([{
1849
+ const { createAnyway } = await inquirer4.prompt([{
1573
1850
  type: "confirm",
1574
1851
  name: "createAnyway",
1575
1852
  message: "Create config directory anyway?",
@@ -1579,7 +1856,7 @@ async function stepClaudeCodeConfig() {
1579
1856
  return { success: true, skipped: true };
1580
1857
  }
1581
1858
  }
1582
- const { configure } = await inquirer5.prompt([{
1859
+ const { configure } = await inquirer4.prompt([{
1583
1860
  type: "confirm",
1584
1861
  name: "configure",
1585
1862
  message: "Configure VibeTasks MCP server for Claude Code?",
@@ -1588,7 +1865,7 @@ async function stepClaudeCodeConfig() {
1588
1865
  if (!configure) {
1589
1866
  return { success: true, skipped: true };
1590
1867
  }
1591
- const spinner = ora10("Configuring Claude Code...").start();
1868
+ const spinner = ora9("Configuring Claude Code...").start();
1592
1869
  try {
1593
1870
  const configPath = getClaudeConfigPath();
1594
1871
  const configDir = path2.dirname(configPath);
@@ -1664,7 +1941,7 @@ async function stepClaudeCodeConfig() {
1664
1941
  }
1665
1942
  async function stepProjectInit() {
1666
1943
  console.log(chalk13.bold.blue("\n\u2501\u2501\u2501 Step 3: Project Setup (Optional) \u2501\u2501\u2501\n"));
1667
- const spinner = ora10("Detecting project...").start();
1944
+ const spinner = ora9("Detecting project...").start();
1668
1945
  let project;
1669
1946
  try {
1670
1947
  project = await detectProject3(process.cwd());
@@ -1675,7 +1952,7 @@ async function stepProjectInit() {
1675
1952
  spinner.info(chalk13.gray("No project detected in current directory"));
1676
1953
  return { success: true, skipped: true };
1677
1954
  }
1678
- const { setupProject } = await inquirer5.prompt([{
1955
+ const { setupProject } = await inquirer4.prompt([{
1679
1956
  type: "confirm",
1680
1957
  name: "setupProject",
1681
1958
  message: `Auto-tag tasks created here as "${project.name}"?`,
@@ -1685,7 +1962,7 @@ async function stepProjectInit() {
1685
1962
  return { success: true, skipped: true };
1686
1963
  }
1687
1964
  try {
1688
- const authManager = new AuthManager12();
1965
+ const authManager = new AuthManager11();
1689
1966
  await authManager.setConfig(`project_${process.cwd()}`, project.name);
1690
1967
  console.log(chalk13.green("\n \u2713") + chalk13.white(` Project "${project.name}" configured`));
1691
1968
  return { success: true, projectName: project.name };
@@ -1700,9 +1977,9 @@ async function stepVerify() {
1700
1977
  supabaseConnected: false,
1701
1978
  mcpConfigured: false
1702
1979
  };
1703
- const supabaseSpinner = ora10("Testing Supabase connection...").start();
1980
+ const supabaseSpinner = ora9("Testing Supabase connection...").start();
1704
1981
  try {
1705
- const authManager = new AuthManager12();
1982
+ const authManager = new AuthManager11();
1706
1983
  const taskOps = await TaskOperations8.fromAuthManager(authManager);
1707
1984
  const tasks = await taskOps.getTasks("all");
1708
1985
  result.supabaseConnected = true;
@@ -1712,7 +1989,7 @@ async function stepVerify() {
1712
1989
  supabaseSpinner.fail(chalk13.red("Supabase connection failed"));
1713
1990
  console.log(chalk13.gray(` ${error.message}`));
1714
1991
  }
1715
- const mcpSpinner = ora10("Checking MCP configuration...").start();
1992
+ const mcpSpinner = ora9("Checking MCP configuration...").start();
1716
1993
  try {
1717
1994
  const configPath = getClaudeConfigPath();
1718
1995
  const configContent = await fs2.readFile(configPath, "utf-8");
@@ -1873,7 +2150,7 @@ async function runNonInteractiveSetup() {
1873
2150
  if (authResult.success) {
1874
2151
  console.log(chalk13.gray("\nVerifying connection..."));
1875
2152
  try {
1876
- const authManager = new AuthManager12();
2153
+ const authManager = new AuthManager11();
1877
2154
  const taskOps = await TaskOperations8.fromAuthManager(authManager);
1878
2155
  const tasks = await taskOps.getTasks("all");
1879
2156
  console.log(chalk13.green("\u2713") + ` Connected (${tasks.length} tasks)`);
@@ -1900,7 +2177,7 @@ var setupCommand = new Command12("setup").description("Interactive setup wizard
1900
2177
  process.exit(0);
1901
2178
  }
1902
2179
  showWelcome();
1903
- const { proceed } = await inquirer5.prompt([{
2180
+ const { proceed } = await inquirer4.prompt([{
1904
2181
  type: "confirm",
1905
2182
  name: "proceed",
1906
2183
  message: "Ready to begin setup?",
@@ -1942,9 +2219,9 @@ var setupCommand = new Command12("setup").description("Interactive setup wizard
1942
2219
  // src/commands/watch.ts
1943
2220
  import { Command as Command13 } from "commander";
1944
2221
  import chalk14 from "chalk";
1945
- import ora11 from "ora";
1946
- import inquirer6 from "inquirer";
1947
- import { AuthManager as AuthManager13, TaskOperations as TaskOperations9 } from "@vibetasks/core";
2222
+ import ora10 from "ora";
2223
+ import inquirer5 from "inquirer";
2224
+ import { AuthManager as AuthManager12, TaskOperations as TaskOperations9 } from "@vibetasks/core";
1948
2225
  import { detectProject as detectProject4 } from "@vibetasks/shared/utils/project-detector";
1949
2226
  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) => {
1950
2227
  const interval = parseInt(options.interval || "1000", 10);
@@ -1957,7 +2234,7 @@ var watchCommand = new Command13("watch").description("Monitor clipboard for err
1957
2234
  let authManager;
1958
2235
  let taskOps;
1959
2236
  try {
1960
- authManager = new AuthManager13();
2237
+ authManager = new AuthManager12();
1961
2238
  taskOps = await TaskOperations9.fromAuthManager(authManager);
1962
2239
  } catch (error) {
1963
2240
  if (error.message.includes("Not authenticated")) {
@@ -2002,7 +2279,7 @@ Error: ${error.message}
2002
2279
  recentErrors.add(errorHash);
2003
2280
  return;
2004
2281
  }
2005
- const { action } = await inquirer6.prompt([
2282
+ const { action } = await inquirer5.prompt([
2006
2283
  {
2007
2284
  type: "list",
2008
2285
  name: "action",
@@ -2026,7 +2303,7 @@ Error: ${error.message}
2026
2303
  console.log(error.rawText);
2027
2304
  console.log(chalk14.gray("\u2500".repeat(50)));
2028
2305
  console.log();
2029
- const { afterShow } = await inquirer6.prompt([
2306
+ const { afterShow } = await inquirer5.prompt([
2030
2307
  {
2031
2308
  type: "list",
2032
2309
  name: "afterShow",
@@ -2090,7 +2367,7 @@ Error: ${error.message}
2090
2367
  });
2091
2368
  });
2092
2369
  async function createTaskFromError(error, taskOps, projectTag) {
2093
- const spinner = ora11("Creating task...").start();
2370
+ const spinner = ora10("Creating task...").start();
2094
2371
  try {
2095
2372
  const title = generateTaskTitle(error);
2096
2373
  const task = await taskOps.createTask({
@@ -2197,13 +2474,13 @@ var checkCommand = new Command13("check-clipboard").description("Check clipboard
2197
2474
  // src/commands/archive.ts
2198
2475
  import { Command as Command14 } from "commander";
2199
2476
  import chalk15 from "chalk";
2200
- import ora12 from "ora";
2201
- import inquirer7 from "inquirer";
2202
- import { AuthManager as AuthManager14, TaskOperations as TaskOperations10 } from "@vibetasks/core";
2477
+ import ora11 from "ora";
2478
+ import inquirer6 from "inquirer";
2479
+ import { AuthManager as AuthManager13, TaskOperations as TaskOperations10 } from "@vibetasks/core";
2203
2480
  var archiveCommand = new Command14("archive").description("Archive a task or manage archived tasks").argument("[task-id]", "Task ID to archive (full or first 8 characters)").option("-l, --list", "List all archived tasks").option("-u, --unarchive <id>", "Unarchive a task by ID").option("--pick", "Pick from completed tasks to archive").action(async (taskId, options) => {
2204
- const spinner = ora12();
2481
+ const spinner = ora11();
2205
2482
  try {
2206
- const authManager = new AuthManager14();
2483
+ const authManager = new AuthManager13();
2207
2484
  const taskOps = await TaskOperations10.fromAuthManager(authManager);
2208
2485
  if (options.list) {
2209
2486
  spinner.start("Fetching archived tasks...");
@@ -2255,7 +2532,7 @@ Restored: ${task2.title}`));
2255
2532
  console.log(chalk15.yellow("\nNo completed tasks to archive. Complete some tasks first!\n"));
2256
2533
  process.exit(0);
2257
2534
  }
2258
- const { selectedTask } = await inquirer7.prompt([{
2535
+ const { selectedTask } = await inquirer6.prompt([{
2259
2536
  type: "list",
2260
2537
  name: "selectedTask",
2261
2538
  message: "Pick a completed task to archive:",
@@ -2313,17 +2590,17 @@ Error: ${error.message}
2313
2590
  // src/commands/daemon.ts
2314
2591
  import { Command as Command15 } from "commander";
2315
2592
  import chalk16 from "chalk";
2316
- import ora13 from "ora";
2593
+ import ora12 from "ora";
2317
2594
  import { spawn } from "child_process";
2318
2595
  import path3 from "path";
2319
2596
  import { fileURLToPath } from "url";
2320
- import { AuthManager as AuthManager15, TaskOperations as TaskOperations11 } from "@vibetasks/core";
2597
+ import { AuthManager as AuthManager14, TaskOperations as TaskOperations11 } from "@vibetasks/core";
2321
2598
  var __filename2 = fileURLToPath(import.meta.url);
2322
2599
  var __dirname2 = path3.dirname(__filename2);
2323
2600
  var daemonCommand = new Command15("daemon").description("Manage the VibeTasks error capture daemon").addCommand(createStartCommand()).addCommand(createStopCommand()).addCommand(createStatusCommand()).addCommand(createConfigureCommand()).addCommand(createCaptureCommand());
2324
2601
  function createStartCommand() {
2325
2602
  return new Command15("start").description("Start the error capture daemon").option("-f, --foreground", "Run in foreground (useful for debugging)").option("--no-notify", "Disable startup notification").action(async (options) => {
2326
- const spinner = ora13("Starting VibeTasks daemon...").start();
2603
+ const spinner = ora12("Starting VibeTasks daemon...").start();
2327
2604
  try {
2328
2605
  if (await daemonConfigManager.isDaemonRunning()) {
2329
2606
  spinner.warn(chalk16.yellow("Daemon is already running"));
@@ -2364,7 +2641,7 @@ function createStartCommand() {
2364
2641
  }
2365
2642
  function createStopCommand() {
2366
2643
  return new Command15("stop").description("Stop the error capture daemon").action(async () => {
2367
- const spinner = ora13("Stopping VibeTasks daemon...").start();
2644
+ const spinner = ora12("Stopping VibeTasks daemon...").start();
2368
2645
  try {
2369
2646
  const pid = await daemonConfigManager.getPid();
2370
2647
  if (!pid) {
@@ -2461,7 +2738,7 @@ function createConfigureCommand() {
2461
2738
  }
2462
2739
  function createCaptureCommand() {
2463
2740
  return new Command15("capture").description("Manually capture clipboard and check for errors").option("--create-task", "Create a task from the captured error").option("--raw", "Show raw clipboard content").action(async (options) => {
2464
- const spinner = ora13("Capturing clipboard...").start();
2741
+ const spinner = ora12("Capturing clipboard...").start();
2465
2742
  try {
2466
2743
  const clipboard = await import("clipboardy");
2467
2744
  const content = await clipboard.default.read();
@@ -2673,9 +2950,9 @@ function getCategoryPrefix2(category) {
2673
2950
  return prefixes[category] || "Fix";
2674
2951
  }
2675
2952
  async function createTaskFromError2(error) {
2676
- const spinner = ora13("Creating task from error...").start();
2953
+ const spinner = ora12("Creating task from error...").start();
2677
2954
  try {
2678
- const authManager = new AuthManager15();
2955
+ const authManager = new AuthManager14();
2679
2956
  const taskOps = await TaskOperations11.fromAuthManager(authManager);
2680
2957
  const title = generateTaskTitle2(error);
2681
2958
  const notes = formatErrorForNotes(error);
@@ -2732,10 +3009,240 @@ function getTagColor2(category) {
2732
3009
  return colors[category] || "#FF6B6B";
2733
3010
  }
2734
3011
 
3012
+ // src/commands/next.ts
3013
+ import { Command as Command16 } from "commander";
3014
+ import chalk17 from "chalk";
3015
+ import { AuthManager as AuthManager15, TaskOperations as TaskOperations12 } from "@vibetasks/core";
3016
+ var PRIORITY_ORDER = { high: 0, medium: 1, low: 2, none: 3 };
3017
+ var nextCommand = new Command16("next").description("Show and optionally start the highest priority task").option("-s, --start", "Start vibing on the task immediately").option("--project <name>", "Filter by project tag").action(async (options) => {
3018
+ try {
3019
+ const authManager = new AuthManager15();
3020
+ const taskOps = await TaskOperations12.fromAuthManager(authManager);
3021
+ let tasks = await taskOps.getTasks("all");
3022
+ tasks = tasks.filter((t) => t.status !== "done" && t.status !== "archived" && !t.completed);
3023
+ if (options.project) {
3024
+ tasks = tasks.filter((t) => t.project_tag === options.project);
3025
+ }
3026
+ tasks.sort((a, b) => {
3027
+ const priorityDiff = (PRIORITY_ORDER[a.priority || "none"] || 3) - (PRIORITY_ORDER[b.priority || "none"] || 3);
3028
+ if (priorityDiff !== 0) return priorityDiff;
3029
+ if (a.status === "vibing" && b.status !== "vibing") return -1;
3030
+ if (b.status === "vibing" && a.status !== "vibing") return 1;
3031
+ return (a.position || 0) - (b.position || 0);
3032
+ });
3033
+ if (tasks.length === 0) {
3034
+ console.log(chalk17.gray("\n\u{1F389} No tasks in queue! You're all caught up.\n"));
3035
+ process.exit(0);
3036
+ }
3037
+ const nextTask = tasks[0];
3038
+ if (options.start && nextTask.status !== "vibing") {
3039
+ await taskOps.updateTaskStatus(nextTask.id, "vibing");
3040
+ console.log(chalk17.green(`
3041
+ \u26A1 Started vibing on task!
3042
+ `));
3043
+ }
3044
+ const priorityColors = {
3045
+ high: chalk17.red,
3046
+ medium: chalk17.yellow,
3047
+ low: chalk17.blue,
3048
+ none: chalk17.gray
3049
+ };
3050
+ const priorityEmojis = {
3051
+ high: "\u{1F534}",
3052
+ medium: "\u{1F7E1}",
3053
+ low: "\u{1F535}",
3054
+ none: "\u26AA"
3055
+ };
3056
+ const statusColors = {
3057
+ todo: chalk17.gray,
3058
+ vibing: chalk17.magenta,
3059
+ done: chalk17.green
3060
+ };
3061
+ const priority = nextTask.priority || "none";
3062
+ const priorityColor = priorityColors[priority];
3063
+ const priorityEmoji = priorityEmojis[priority];
3064
+ const statusColor = statusColors[nextTask.status || "todo"];
3065
+ const shortIdManager = new ShortIdManager();
3066
+ await shortIdManager.saveMappings([nextTask.id]);
3067
+ console.log("\n" + chalk17.bold("\u2501".repeat(50)));
3068
+ console.log(chalk17.bold.cyan("\n\u{1F4CD} NEXT UP:\n"));
3069
+ console.log(chalk17.bold.white(` ${nextTask.title}`));
3070
+ console.log();
3071
+ console.log(` ${priorityEmoji} Priority: ${priorityColor(priority.charAt(0).toUpperCase() + priority.slice(1))}`);
3072
+ console.log(` \u{1F4CA} Status: ${statusColor(nextTask.status || "todo")}`);
3073
+ if (nextTask.project_tag) {
3074
+ console.log(` \u{1F4C1} Project: ${chalk17.blue(nextTask.project_tag)}`);
3075
+ }
3076
+ if (nextTask.due_date) {
3077
+ const dueDate = new Date(nextTask.due_date);
3078
+ const today = /* @__PURE__ */ new Date();
3079
+ const isOverdue = dueDate < today;
3080
+ const dateStr = nextTask.due_date.split("T")[0];
3081
+ console.log(` \u{1F4C5} Due: ${isOverdue ? chalk17.red(dateStr + " (OVERDUE)") : chalk17.gray(dateStr)}`);
3082
+ }
3083
+ if (nextTask.context_notes) {
3084
+ console.log(`
3085
+ ${chalk17.blue("\u{1F4AC} Context:")}`);
3086
+ console.log(chalk17.gray(` ${nextTask.context_notes}`));
3087
+ }
3088
+ const subtasks = nextTask.subtasks_json || nextTask.subtasks || [];
3089
+ if (subtasks.length > 0) {
3090
+ const doneCount = subtasks.filter((s) => s.done).length;
3091
+ console.log(`
3092
+ ${chalk17.cyan("\u2713 Subtasks:")} ${doneCount}/${subtasks.length} done`);
3093
+ subtasks.slice(0, 5).forEach((s) => {
3094
+ const icon = s.done ? chalk17.green("\u2713") : chalk17.gray("\u25CB");
3095
+ const text = s.done ? chalk17.strikethrough.gray(s.title) : s.title;
3096
+ console.log(` ${icon} ${text}`);
3097
+ });
3098
+ if (subtasks.length > 5) {
3099
+ console.log(chalk17.gray(` ... and ${subtasks.length - 5} more`));
3100
+ }
3101
+ }
3102
+ console.log("\n" + chalk17.bold("\u2501".repeat(50)));
3103
+ console.log(chalk17.gray("\n Quick actions:"));
3104
+ if (nextTask.status !== "vibing") {
3105
+ console.log(chalk17.gray(` \u2022 ${chalk17.cyan("vibetasks next --start")} - Start vibing on this task`));
3106
+ }
3107
+ console.log(chalk17.gray(` \u2022 ${chalk17.cyan("vibetasks vibing 1")} - Start working (short ID #1)`));
3108
+ console.log(chalk17.gray(` \u2022 ${chalk17.cyan("vibetasks done 1")} - Mark as done`));
3109
+ console.log();
3110
+ process.exit(0);
3111
+ } catch (error) {
3112
+ if (error.message.includes("Not authenticated")) {
3113
+ console.error(chalk17.yellow("\n\u26A0\uFE0F You need to login first"));
3114
+ console.error(chalk17.gray("Run: vibetasks login\n"));
3115
+ } else {
3116
+ console.error(chalk17.red(`
3117
+ Error: ${error.message}
3118
+ `));
3119
+ }
3120
+ process.exit(1);
3121
+ }
3122
+ });
3123
+
3124
+ // src/commands/session.ts
3125
+ import { Command as Command17 } from "commander";
3126
+ import chalk18 from "chalk";
3127
+ import { detectProject as detectProject5 } from "@vibetasks/shared/utils/project-detector";
3128
+ var sessionCommand = new Command17("session").description("Manage AI sessions for crash recovery and handoffs").addCommand(
3129
+ new Command17("start").description("Start a new session").action(async () => {
3130
+ const sessionManager2 = getSessionManager();
3131
+ const project = await detectProject5();
3132
+ const session = await sessionManager2.startSession(project?.name);
3133
+ console.log(chalk18.green("\u2713 Session started"));
3134
+ console.log();
3135
+ console.log(chalk18.cyan("Session ID:"), chalk18.bold(session.id));
3136
+ console.log(chalk18.gray("Full ID:"), session.fullId.slice(0, 8));
3137
+ if (session.project) {
3138
+ console.log(chalk18.gray("Project:"), session.project);
3139
+ }
3140
+ console.log();
3141
+ console.log(chalk18.yellow("Tip:"), "If the AI crashes, tell the next one:");
3142
+ console.log(chalk18.white(` "Continue from session ${session.id}"`));
3143
+ })
3144
+ ).addCommand(
3145
+ new Command17("current").alias("status").description("Show current session status").action(async () => {
3146
+ const sessionManager2 = getSessionManager();
3147
+ const session = await sessionManager2.getCurrentSession();
3148
+ if (!session) {
3149
+ console.log(chalk18.yellow("No active session"));
3150
+ console.log(chalk18.gray("Start one with: vibetasks session start"));
3151
+ return;
3152
+ }
3153
+ console.log(chalk18.cyan("Current Session:"), chalk18.bold(session.id));
3154
+ console.log(chalk18.gray("Started:"), new Date(session.startedAt).toLocaleString());
3155
+ if (session.project) {
3156
+ console.log(chalk18.gray("Project:"), session.project);
3157
+ }
3158
+ console.log(chalk18.gray("Actions:"), session.actions.length);
3159
+ console.log();
3160
+ if (session.actions.length > 0) {
3161
+ console.log(chalk18.cyan("Recent actions:"));
3162
+ const recent = session.actions.slice(-5);
3163
+ for (const action of recent) {
3164
+ const time = new Date(action.timestamp).toLocaleTimeString();
3165
+ const icon = {
3166
+ task_created: "\u2795",
3167
+ task_completed: "\u2713",
3168
+ task_updated: "\u{1F4DD}",
3169
+ file_modified: "\u{1F4C4}",
3170
+ note: "\u{1F4AC}"
3171
+ }[action.type];
3172
+ console.log(chalk18.gray(` ${icon} [${time}]`), action.description);
3173
+ }
3174
+ if (session.actions.length > 5) {
3175
+ console.log(chalk18.gray(` ... and ${session.actions.length - 5} more`));
3176
+ }
3177
+ }
3178
+ })
3179
+ ).addCommand(
3180
+ new Command17("end").description("End the current session").option("-s, --summary <text>", "Add a summary of what was done").action(async (options) => {
3181
+ const sessionManager2 = getSessionManager();
3182
+ const session = await sessionManager2.endSession(options.summary);
3183
+ if (!session) {
3184
+ console.log(chalk18.yellow("No active session to end"));
3185
+ return;
3186
+ }
3187
+ console.log(chalk18.green("\u2713 Session ended:"), chalk18.bold(session.id));
3188
+ console.log(chalk18.gray("Duration:"), formatDuration(session.startedAt, session.endedAt));
3189
+ console.log(chalk18.gray("Actions:"), session.actions.length);
3190
+ if (options.summary) {
3191
+ console.log(chalk18.gray("Summary:"), options.summary);
3192
+ }
3193
+ })
3194
+ ).addCommand(
3195
+ new Command17("list").description("List recent sessions").option("-n, --limit <number>", "Number of sessions to show", "10").action(async (options) => {
3196
+ const sessionManager2 = getSessionManager();
3197
+ const sessions = await sessionManager2.getRecentSessions(parseInt(options.limit));
3198
+ if (sessions.length === 0) {
3199
+ console.log(chalk18.yellow("No sessions found"));
3200
+ return;
3201
+ }
3202
+ console.log(chalk18.cyan("Recent Sessions:"));
3203
+ console.log();
3204
+ for (const session of sessions) {
3205
+ const status = session.endedAt ? chalk18.gray("ended") : chalk18.green("active");
3206
+ const date = new Date(session.startedAt).toLocaleDateString();
3207
+ const actions = session.actions.length;
3208
+ console.log(
3209
+ chalk18.bold(session.id),
3210
+ status,
3211
+ chalk18.gray(`| ${date} | ${actions} actions`),
3212
+ session.project ? chalk18.blue(`[${session.project}]`) : ""
3213
+ );
3214
+ }
3215
+ })
3216
+ ).addCommand(
3217
+ new Command17("show").alias("handoff").description("Show session details for handoff to next AI").argument("<session-id>", "Session ID (partial match supported)").action(async (sessionId) => {
3218
+ const sessionManager2 = getSessionManager();
3219
+ const handoff = await sessionManager2.getSessionHandoff(sessionId);
3220
+ console.log(handoff);
3221
+ })
3222
+ ).addCommand(
3223
+ new Command17("log").description("Log an action or note to the current session").argument("<message>", "Note to log").action(async (message) => {
3224
+ const sessionManager2 = getSessionManager();
3225
+ await sessionManager2.logAction({
3226
+ type: "note",
3227
+ description: message
3228
+ });
3229
+ console.log(chalk18.green("\u2713 Logged to session"));
3230
+ })
3231
+ );
3232
+ function formatDuration(start, end) {
3233
+ const ms = new Date(end).getTime() - new Date(start).getTime();
3234
+ const minutes = Math.floor(ms / 6e4);
3235
+ const hours = Math.floor(minutes / 60);
3236
+ if (hours > 0) {
3237
+ return `${hours}h ${minutes % 60}m`;
3238
+ }
3239
+ return `${minutes}m`;
3240
+ }
3241
+
2735
3242
  // bin/vibetasks.ts
2736
3243
  var require2 = createRequire(import.meta.url);
2737
3244
  var pkg = require2("../../package.json");
2738
- var program = new Command16();
3245
+ var program = new Command18();
2739
3246
  program.name("vibetasks").description("VibeTasks CLI - Fast task management for vibers").version(pkg.version);
2740
3247
  program.addCommand(setupCommand);
2741
3248
  program.addCommand(loginCommand);
@@ -2753,4 +3260,6 @@ program.addCommand(watchCommand);
2753
3260
  program.addCommand(checkCommand);
2754
3261
  program.addCommand(archiveCommand);
2755
3262
  program.addCommand(daemonCommand);
3263
+ program.addCommand(nextCommand);
3264
+ program.addCommand(sessionCommand);
2756
3265
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibetasks/cli",
3
- "version": "0.4.7",
3
+ "version": "0.5.1",
4
4
  "description": "VibeTasks CLI - Lightning-fast task management from your terminal. Works with Claude Code, Cursor, and all AI coding tools.",
5
5
  "author": "Vyas",
6
6
  "license": "MIT",
@@ -45,8 +45,8 @@
45
45
  "typecheck": "tsc --noEmit"
46
46
  },
47
47
  "dependencies": {
48
- "@vibetasks/core": "^0.4.2",
49
- "@vibetasks/shared": "^1.1.3",
48
+ "@vibetasks/core": "^0.5.1",
49
+ "@vibetasks/shared": "^1.2.1",
50
50
  "commander": "^11.1.0",
51
51
  "chalk": "^5.3.0",
52
52
  "ora": "^8.0.1",