@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.
- package/dist/bin/vibetasks.js +685 -176
- package/package.json +3 -3
package/dist/bin/vibetasks.js
CHANGED
|
@@ -11,15 +11,12 @@ import {
|
|
|
11
11
|
} from "../chunk-2KRLRG4G.js";
|
|
12
12
|
|
|
13
13
|
// bin/vibetasks.ts
|
|
14
|
-
import { Command as
|
|
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
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
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
|
|
371
|
+
import ora2 from "ora";
|
|
446
372
|
import chalk3 from "chalk";
|
|
447
|
-
import { AuthManager as
|
|
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
|
-
|
|
489
|
-
|
|
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
|
|
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
|
|
604
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
981
|
+
import ora3 from "ora";
|
|
718
982
|
import chalk5 from "chalk";
|
|
719
|
-
import { AuthManager as
|
|
720
|
-
var doneCommand = new Command4("done").description("Mark a task as complete").argument("<id>", "Task ID (
|
|
721
|
-
const spinner =
|
|
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
|
|
987
|
+
const authManager = new AuthManager4();
|
|
724
988
|
const taskOps = await TaskOperations3.fromAuthManager(authManager);
|
|
725
|
-
|
|
726
|
-
|
|
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(
|
|
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
|
|
763
|
-
import
|
|
764
|
-
import { AuthManager as
|
|
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 (
|
|
767
|
-
const spinner =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1170
|
+
import ora5 from "ora";
|
|
894
1171
|
import chalk8 from "chalk";
|
|
895
|
-
import { AuthManager as
|
|
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 =
|
|
1179
|
+
const spinner = ora5("Updating task...").start();
|
|
903
1180
|
try {
|
|
904
|
-
const authManager = new
|
|
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
|
|
1245
|
+
import ora6 from "ora";
|
|
969
1246
|
import chalk9 from "chalk";
|
|
970
|
-
import
|
|
971
|
-
import { AuthManager as
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
1265
|
-
import
|
|
1541
|
+
import inquirer3 from "inquirer";
|
|
1542
|
+
import ora8 from "ora";
|
|
1266
1543
|
import chalk12 from "chalk";
|
|
1267
|
-
import { AuthManager as
|
|
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 =
|
|
1547
|
+
const spinner = ora8("Detecting project...").start();
|
|
1271
1548
|
try {
|
|
1272
|
-
const authManager = new
|
|
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
|
|
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
|
|
1329
|
-
import
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
1814
|
+
const spinner = ora9("Authenticating...").start();
|
|
1538
1815
|
try {
|
|
1539
|
-
const authManager = new
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
1980
|
+
const supabaseSpinner = ora9("Testing Supabase connection...").start();
|
|
1704
1981
|
try {
|
|
1705
|
-
const authManager = new
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
1946
|
-
import
|
|
1947
|
-
import { AuthManager as
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
2201
|
-
import
|
|
2202
|
-
import { AuthManager as
|
|
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 =
|
|
2481
|
+
const spinner = ora11();
|
|
2205
2482
|
try {
|
|
2206
|
-
const authManager = new
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
2953
|
+
const spinner = ora12("Creating task from error...").start();
|
|
2677
2954
|
try {
|
|
2678
|
-
const authManager = new
|
|
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
|
|
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.
|
|
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.
|
|
49
|
-
"@vibetasks/shared": "^1.1
|
|
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",
|