@hasna/todos 0.10.22 → 0.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -2347,6 +2347,15 @@ function ensureSchema(db) {
2347
2347
  ensureColumn("tasks", "assigned_by", "TEXT");
2348
2348
  ensureColumn("tasks", "assigned_from_project", "TEXT");
2349
2349
  ensureColumn("tasks", "started_at", "TEXT");
2350
+ ensureColumn("tasks", "task_type", "TEXT");
2351
+ ensureColumn("tasks", "cost_tokens", "INTEGER DEFAULT 0");
2352
+ ensureColumn("tasks", "cost_usd", "REAL DEFAULT 0");
2353
+ ensureColumn("tasks", "delegated_from", "TEXT");
2354
+ ensureColumn("tasks", "delegation_depth", "INTEGER DEFAULT 0");
2355
+ ensureColumn("tasks", "retry_count", "INTEGER DEFAULT 0");
2356
+ ensureColumn("tasks", "max_retries", "INTEGER DEFAULT 3");
2357
+ ensureColumn("tasks", "retry_after", "TEXT");
2358
+ ensureColumn("tasks", "sla_minutes", "INTEGER");
2350
2359
  ensureColumn("agents", "role", "TEXT DEFAULT 'agent'");
2351
2360
  ensureColumn("agents", "permissions", `TEXT DEFAULT '["*"]'`);
2352
2361
  ensureColumn("agents", "reports_to", "TEXT");
@@ -2960,6 +2969,58 @@ var init_database = __esm(() => {
2960
2969
  `
2961
2970
  ALTER TABLE tasks ADD COLUMN task_type TEXT;
2962
2971
  CREATE INDEX IF NOT EXISTS idx_tasks_task_type ON tasks(task_type);
2972
+ ALTER TABLE tasks ADD COLUMN cost_tokens INTEGER DEFAULT 0;
2973
+ ALTER TABLE tasks ADD COLUMN cost_usd REAL DEFAULT 0;
2974
+ ALTER TABLE tasks ADD COLUMN delegated_from TEXT;
2975
+ ALTER TABLE tasks ADD COLUMN delegation_depth INTEGER DEFAULT 0;
2976
+ ALTER TABLE tasks ADD COLUMN retry_count INTEGER DEFAULT 0;
2977
+ ALTER TABLE tasks ADD COLUMN max_retries INTEGER DEFAULT 3;
2978
+ ALTER TABLE tasks ADD COLUMN retry_after TEXT;
2979
+ ALTER TABLE tasks ADD COLUMN sla_minutes INTEGER;
2980
+
2981
+ CREATE TABLE IF NOT EXISTS task_traces (
2982
+ id TEXT PRIMARY KEY,
2983
+ task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
2984
+ agent_id TEXT,
2985
+ trace_type TEXT NOT NULL CHECK(trace_type IN ('tool_call','llm_call','error','handoff','custom')),
2986
+ name TEXT,
2987
+ input_summary TEXT,
2988
+ output_summary TEXT,
2989
+ duration_ms INTEGER,
2990
+ tokens INTEGER,
2991
+ cost_usd REAL,
2992
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
2993
+ );
2994
+ CREATE INDEX IF NOT EXISTS idx_task_traces_task ON task_traces(task_id);
2995
+ CREATE INDEX IF NOT EXISTS idx_task_traces_agent ON task_traces(agent_id);
2996
+
2997
+ CREATE TABLE IF NOT EXISTS context_snapshots (
2998
+ id TEXT PRIMARY KEY,
2999
+ agent_id TEXT,
3000
+ task_id TEXT REFERENCES tasks(id) ON DELETE SET NULL,
3001
+ project_id TEXT REFERENCES projects(id) ON DELETE SET NULL,
3002
+ snapshot_type TEXT NOT NULL CHECK(snapshot_type IN ('interrupt','complete','handoff','checkpoint')),
3003
+ plan_summary TEXT,
3004
+ files_open TEXT DEFAULT '[]',
3005
+ attempts TEXT DEFAULT '[]',
3006
+ blockers TEXT DEFAULT '[]',
3007
+ next_steps TEXT,
3008
+ metadata TEXT DEFAULT '{}',
3009
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
3010
+ );
3011
+ CREATE INDEX IF NOT EXISTS idx_snapshots_agent ON context_snapshots(agent_id);
3012
+ CREATE INDEX IF NOT EXISTS idx_snapshots_task ON context_snapshots(task_id);
3013
+
3014
+ CREATE TABLE IF NOT EXISTS agent_budgets (
3015
+ agent_id TEXT PRIMARY KEY,
3016
+ max_concurrent INTEGER DEFAULT 5,
3017
+ max_cost_usd REAL,
3018
+ max_task_minutes INTEGER,
3019
+ period_hours INTEGER DEFAULT 24,
3020
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
3021
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
3022
+ );
3023
+
2963
3024
  INSERT OR IGNORE INTO _migrations (id) VALUES (35);
2964
3025
  `
2965
3026
  ];
@@ -3755,12 +3816,14 @@ var exports_tasks = {};
3755
3816
  __export(exports_tasks, {
3756
3817
  updateTask: () => updateTask,
3757
3818
  unlockTask: () => unlockTask,
3819
+ stealTask: () => stealTask,
3758
3820
  startTask: () => startTask,
3759
3821
  setTaskStatus: () => setTaskStatus,
3760
3822
  setTaskPriority: () => setTaskPriority,
3761
3823
  removeDependency: () => removeDependency,
3762
3824
  redistributeStaleTasks: () => redistributeStaleTasks,
3763
3825
  moveTask: () => moveTask,
3826
+ logCost: () => logCost,
3764
3827
  lockTask: () => lockTask,
3765
3828
  listTasks: () => listTasks,
3766
3829
  getTasksChangedSince: () => getTasksChangedSince,
@@ -3783,6 +3846,7 @@ __export(exports_tasks, {
3783
3846
  countTasks: () => countTasks,
3784
3847
  completeTask: () => completeTask,
3785
3848
  cloneTask: () => cloneTask,
3849
+ claimOrSteal: () => claimOrSteal,
3786
3850
  claimNextTask: () => claimNextTask,
3787
3851
  bulkUpdateTasks: () => bulkUpdateTasks,
3788
3852
  bulkCreateTasks: () => bulkCreateTasks,
@@ -4264,6 +4328,20 @@ function completeTask(id, agentId, db, options) {
4264
4328
  if (spawnedFromTemplate) {
4265
4329
  meta._spawned_task = { id: spawnedFromTemplate.id, short_id: spawnedFromTemplate.short_id, title: spawnedFromTemplate.title };
4266
4330
  }
4331
+ const unblockedDeps = d.query(`SELECT DISTINCT t.id, t.short_id, t.title FROM tasks t
4332
+ JOIN task_dependencies td ON td.task_id = t.id
4333
+ WHERE td.depends_on = ? AND t.status = 'pending'
4334
+ AND NOT EXISTS (
4335
+ SELECT 1 FROM task_dependencies td2
4336
+ JOIN tasks dep2 ON dep2.id = td2.depends_on
4337
+ WHERE td2.task_id = t.id AND dep2.status NOT IN ('completed', 'cancelled') AND dep2.id != ?
4338
+ )`).all(id, id);
4339
+ if (unblockedDeps.length > 0) {
4340
+ meta._unblocked = unblockedDeps.map((d2) => ({ id: d2.id, short_id: d2.short_id, title: d2.title }));
4341
+ for (const dep of unblockedDeps) {
4342
+ dispatchWebhook("task.unblocked", { id: dep.id, unblocked_by: id, title: dep.title }, d).catch(() => {});
4343
+ }
4344
+ }
4267
4345
  return { ...task, status: "completed", locked_by: null, locked_at: null, completed_at: timestamp, confidence, version: task.version + 1, updated_at: timestamp, metadata: meta };
4268
4346
  }
4269
4347
  function lockTask(id, agentId, db) {
@@ -4560,24 +4638,36 @@ function failTask(id, agentId, reason, options, db) {
4560
4638
  };
4561
4639
  let retryTask;
4562
4640
  if (options?.retry) {
4563
- let title = task.title;
4564
- if (task.short_id && title.startsWith(task.short_id + ": ")) {
4565
- title = title.slice(task.short_id.length + 2);
4641
+ const retryCount = (task.retry_count || 0) + 1;
4642
+ const maxRetries = task.max_retries || 3;
4643
+ if (retryCount > maxRetries) {
4644
+ d.run("UPDATE tasks SET metadata = ? WHERE id = ?", [
4645
+ JSON.stringify({ ...meta, _retry_exhausted: { retry_count: retryCount - 1, max_retries: maxRetries } }),
4646
+ id
4647
+ ]);
4648
+ } else {
4649
+ const backoffMinutes = Math.pow(5, retryCount - 1);
4650
+ const retryAfter = options.retry_after || new Date(Date.now() + backoffMinutes * 60 * 1000).toISOString();
4651
+ let title = task.title;
4652
+ if (task.short_id && title.startsWith(task.short_id + ": ")) {
4653
+ title = title.slice(task.short_id.length + 2);
4654
+ }
4655
+ retryTask = createTask({
4656
+ title,
4657
+ description: task.description ?? undefined,
4658
+ priority: task.priority,
4659
+ project_id: task.project_id ?? undefined,
4660
+ task_list_id: task.task_list_id ?? undefined,
4661
+ plan_id: task.plan_id ?? undefined,
4662
+ assigned_to: task.assigned_to ?? undefined,
4663
+ tags: task.tags,
4664
+ metadata: { ...task.metadata, _retry: { original_id: task.id, retry_count: retryCount, max_retries: maxRetries, retry_after: retryAfter, failure_reason: reason } },
4665
+ estimated_minutes: task.estimated_minutes ?? undefined,
4666
+ recurrence_rule: task.recurrence_rule ?? undefined,
4667
+ due_at: retryAfter
4668
+ }, d);
4669
+ d.run("UPDATE tasks SET retry_count = ?, max_retries = ?, retry_after = ? WHERE id = ?", [retryCount, maxRetries, retryAfter, retryTask.id]);
4566
4670
  }
4567
- retryTask = createTask({
4568
- title,
4569
- description: task.description ?? undefined,
4570
- priority: task.priority,
4571
- project_id: task.project_id ?? undefined,
4572
- task_list_id: task.task_list_id ?? undefined,
4573
- plan_id: task.plan_id ?? undefined,
4574
- assigned_to: task.assigned_to ?? undefined,
4575
- tags: task.tags,
4576
- metadata: { ...task.metadata, _retry: { original_id: task.id, retry_after: options.retry_after || null, failure_reason: reason } },
4577
- estimated_minutes: task.estimated_minutes ?? undefined,
4578
- recurrence_rule: task.recurrence_rule ?? undefined,
4579
- due_at: options.retry_after || task.due_at || undefined
4580
- }, d);
4581
4671
  }
4582
4672
  return { task: failedTask, retryTask };
4583
4673
  }
@@ -4601,6 +4691,40 @@ function getStaleTasks(staleMinutes = 30, filters, db) {
4601
4691
  const rows = d.query(`SELECT * FROM tasks WHERE ${where} ORDER BY updated_at ASC`).all(...params);
4602
4692
  return rows.map(rowToTask);
4603
4693
  }
4694
+ function logCost(taskId, tokens, usd, db) {
4695
+ const d = db || getDatabase();
4696
+ d.run("UPDATE tasks SET cost_tokens = cost_tokens + ?, cost_usd = cost_usd + ?, updated_at = ? WHERE id = ?", [tokens, usd, now(), taskId]);
4697
+ }
4698
+ function stealTask(agentId, opts, db) {
4699
+ const d = db || getDatabase();
4700
+ const staleMinutes = opts?.stale_minutes ?? 30;
4701
+ const staleTasks = getStaleTasks(staleMinutes, { project_id: opts?.project_id, task_list_id: opts?.task_list_id }, d);
4702
+ if (staleTasks.length === 0)
4703
+ return null;
4704
+ const priorityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
4705
+ staleTasks.sort((a, b) => (priorityOrder[a.priority] ?? 9) - (priorityOrder[b.priority] ?? 9));
4706
+ const target = staleTasks[0];
4707
+ const timestamp = now();
4708
+ d.run(`UPDATE tasks SET assigned_to = ?, locked_by = ?, locked_at = ?, updated_at = ?, version = version + 1 WHERE id = ?`, [agentId, agentId, timestamp, timestamp, target.id]);
4709
+ logTaskChange(target.id, "steal", "assigned_to", target.assigned_to, agentId, agentId, d);
4710
+ dispatchWebhook("task.assigned", { id: target.id, agent_id: agentId, title: target.title, stolen_from: target.assigned_to }, d).catch(() => {});
4711
+ return { ...target, assigned_to: agentId, locked_by: agentId, locked_at: timestamp, updated_at: timestamp, version: target.version + 1 };
4712
+ }
4713
+ function claimOrSteal(agentId, filters, db) {
4714
+ const d = db || getDatabase();
4715
+ const tx = d.transaction(() => {
4716
+ const next = getNextTask(agentId, filters, d);
4717
+ if (next) {
4718
+ const started = startTask(next.id, agentId, d);
4719
+ return { task: started, stolen: false };
4720
+ }
4721
+ const stolen = stealTask(agentId, { stale_minutes: filters?.stale_minutes, project_id: filters?.project_id, task_list_id: filters?.task_list_id }, d);
4722
+ if (stolen)
4723
+ return { task: stolen, stolen: true };
4724
+ return null;
4725
+ });
4726
+ return tx();
4727
+ }
4604
4728
  function getStatus(filters, agentId, options, db) {
4605
4729
  const d = db || getDatabase();
4606
4730
  const pending = countTasks({ ...filters, status: "pending" }, d);
@@ -6199,8 +6323,8 @@ __export(exports_extract, {
6199
6323
  extractFromSource: () => extractFromSource,
6200
6324
  EXTRACT_TAGS: () => EXTRACT_TAGS
6201
6325
  });
6202
- import { readFileSync as readFileSync3, statSync as statSync2 } from "fs";
6203
- import { relative, resolve as resolve2, join as join6 } from "path";
6326
+ import { readFileSync as readFileSync4, statSync as statSync2 } from "fs";
6327
+ import { relative, resolve as resolve2, join as join8 } from "path";
6204
6328
  function tagToPriority(tag) {
6205
6329
  switch (tag) {
6206
6330
  case "BUG":
@@ -6272,9 +6396,9 @@ function extractTodos(options, db) {
6272
6396
  const files = collectFiles(basePath, extensions);
6273
6397
  const allComments = [];
6274
6398
  for (const file of files) {
6275
- const fullPath = statSync2(basePath).isFile() ? basePath : join6(basePath, file);
6399
+ const fullPath = statSync2(basePath).isFile() ? basePath : join8(basePath, file);
6276
6400
  try {
6277
- const source = readFileSync3(fullPath, "utf-8");
6401
+ const source = readFileSync4(fullPath, "utf-8");
6278
6402
  const relPath = statSync2(basePath).isFile() ? relative(resolve2(basePath, ".."), fullPath) : file;
6279
6403
  const comments = extractFromSource(source, relPath, tags);
6280
6404
  allComments.push(...comments);
@@ -10363,6 +10487,219 @@ var init_zod = __esm(() => {
10363
10487
  init_external();
10364
10488
  });
10365
10489
 
10490
+ // src/db/traces.ts
10491
+ var exports_traces = {};
10492
+ __export(exports_traces, {
10493
+ logTrace: () => logTrace,
10494
+ getTraceStats: () => getTraceStats,
10495
+ getTaskTraces: () => getTaskTraces
10496
+ });
10497
+ function logTrace(input, db) {
10498
+ const d = db || getDatabase();
10499
+ const id = uuid();
10500
+ const timestamp = now();
10501
+ d.run(`INSERT INTO task_traces (id, task_id, agent_id, trace_type, name, input_summary, output_summary, duration_ms, tokens, cost_usd, created_at)
10502
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
10503
+ id,
10504
+ input.task_id,
10505
+ input.agent_id || null,
10506
+ input.trace_type,
10507
+ input.name || null,
10508
+ input.input_summary || null,
10509
+ input.output_summary || null,
10510
+ input.duration_ms ?? null,
10511
+ input.tokens ?? null,
10512
+ input.cost_usd ?? null,
10513
+ timestamp
10514
+ ]);
10515
+ return {
10516
+ id,
10517
+ task_id: input.task_id,
10518
+ agent_id: input.agent_id || null,
10519
+ trace_type: input.trace_type,
10520
+ name: input.name || null,
10521
+ input_summary: input.input_summary || null,
10522
+ output_summary: input.output_summary || null,
10523
+ duration_ms: input.duration_ms ?? null,
10524
+ tokens: input.tokens ?? null,
10525
+ cost_usd: input.cost_usd ?? null,
10526
+ created_at: timestamp
10527
+ };
10528
+ }
10529
+ function getTaskTraces(taskId, db) {
10530
+ const d = db || getDatabase();
10531
+ return d.query("SELECT * FROM task_traces WHERE task_id = ? ORDER BY created_at DESC").all(taskId);
10532
+ }
10533
+ function getTraceStats(taskId, db) {
10534
+ const d = db || getDatabase();
10535
+ const row = d.query(`SELECT COUNT(*) as total,
10536
+ SUM(CASE WHEN trace_type = 'tool_call' THEN 1 ELSE 0 END) as tool_calls,
10537
+ SUM(CASE WHEN trace_type = 'llm_call' THEN 1 ELSE 0 END) as llm_calls,
10538
+ SUM(CASE WHEN trace_type = 'error' THEN 1 ELSE 0 END) as errors,
10539
+ COALESCE(SUM(tokens), 0) as total_tokens,
10540
+ COALESCE(SUM(cost_usd), 0) as total_cost_usd,
10541
+ COALESCE(SUM(duration_ms), 0) as total_duration_ms
10542
+ FROM task_traces WHERE task_id = ?`).get(taskId);
10543
+ return row;
10544
+ }
10545
+ var init_traces = __esm(() => {
10546
+ init_database();
10547
+ });
10548
+
10549
+ // src/db/snapshots.ts
10550
+ var exports_snapshots = {};
10551
+ __export(exports_snapshots, {
10552
+ saveSnapshot: () => saveSnapshot,
10553
+ listSnapshots: () => listSnapshots,
10554
+ getLatestSnapshot: () => getLatestSnapshot
10555
+ });
10556
+ function rowToSnapshot(row) {
10557
+ return {
10558
+ ...row,
10559
+ snapshot_type: row.snapshot_type,
10560
+ files_open: JSON.parse(row.files_open || "[]"),
10561
+ attempts: JSON.parse(row.attempts || "[]"),
10562
+ blockers: JSON.parse(row.blockers || "[]"),
10563
+ metadata: JSON.parse(row.metadata || "{}")
10564
+ };
10565
+ }
10566
+ function saveSnapshot(input, db) {
10567
+ const d = db || getDatabase();
10568
+ const id = uuid();
10569
+ const timestamp = now();
10570
+ d.run(`INSERT INTO context_snapshots (id, agent_id, task_id, project_id, snapshot_type, plan_summary, files_open, attempts, blockers, next_steps, metadata, created_at)
10571
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
10572
+ id,
10573
+ input.agent_id || null,
10574
+ input.task_id || null,
10575
+ input.project_id || null,
10576
+ input.snapshot_type,
10577
+ input.plan_summary || null,
10578
+ JSON.stringify(input.files_open || []),
10579
+ JSON.stringify(input.attempts || []),
10580
+ JSON.stringify(input.blockers || []),
10581
+ input.next_steps || null,
10582
+ JSON.stringify(input.metadata || {}),
10583
+ timestamp
10584
+ ]);
10585
+ return {
10586
+ id,
10587
+ agent_id: input.agent_id || null,
10588
+ task_id: input.task_id || null,
10589
+ project_id: input.project_id || null,
10590
+ snapshot_type: input.snapshot_type,
10591
+ plan_summary: input.plan_summary || null,
10592
+ files_open: input.files_open || [],
10593
+ attempts: input.attempts || [],
10594
+ blockers: input.blockers || [],
10595
+ next_steps: input.next_steps || null,
10596
+ metadata: input.metadata || {},
10597
+ created_at: timestamp
10598
+ };
10599
+ }
10600
+ function getLatestSnapshot(agentId, taskId, db) {
10601
+ const d = db || getDatabase();
10602
+ const conditions = [];
10603
+ const params = [];
10604
+ if (agentId) {
10605
+ conditions.push("agent_id = ?");
10606
+ params.push(agentId);
10607
+ }
10608
+ if (taskId) {
10609
+ conditions.push("task_id = ?");
10610
+ params.push(taskId);
10611
+ }
10612
+ if (conditions.length === 0)
10613
+ return null;
10614
+ const where = conditions.join(" AND ");
10615
+ const row = d.query(`SELECT * FROM context_snapshots WHERE ${where} ORDER BY created_at DESC LIMIT 1`).get(...params);
10616
+ return row ? rowToSnapshot(row) : null;
10617
+ }
10618
+ function listSnapshots(opts, db) {
10619
+ const d = db || getDatabase();
10620
+ const conditions = [];
10621
+ const params = [];
10622
+ if (opts.agent_id) {
10623
+ conditions.push("agent_id = ?");
10624
+ params.push(opts.agent_id);
10625
+ }
10626
+ if (opts.task_id) {
10627
+ conditions.push("task_id = ?");
10628
+ params.push(opts.task_id);
10629
+ }
10630
+ if (opts.project_id) {
10631
+ conditions.push("project_id = ?");
10632
+ params.push(opts.project_id);
10633
+ }
10634
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
10635
+ const limit = opts.limit || 20;
10636
+ params.push(limit);
10637
+ return d.query(`SELECT * FROM context_snapshots ${where} ORDER BY created_at DESC LIMIT ?`).all(...params).map(rowToSnapshot);
10638
+ }
10639
+ var init_snapshots = __esm(() => {
10640
+ init_database();
10641
+ });
10642
+
10643
+ // src/db/budgets.ts
10644
+ var exports_budgets = {};
10645
+ __export(exports_budgets, {
10646
+ setBudget: () => setBudget,
10647
+ getBudget: () => getBudget,
10648
+ checkBudget: () => checkBudget
10649
+ });
10650
+ function setBudget(agentId, opts, db) {
10651
+ const d = db || getDatabase();
10652
+ const timestamp = now();
10653
+ d.run(`INSERT INTO agent_budgets (agent_id, max_concurrent, max_cost_usd, max_task_minutes, period_hours, created_at, updated_at)
10654
+ VALUES (?, ?, ?, ?, ?, ?, ?)
10655
+ ON CONFLICT(agent_id) DO UPDATE SET
10656
+ max_concurrent = COALESCE(?, max_concurrent),
10657
+ max_cost_usd = COALESCE(?, max_cost_usd),
10658
+ max_task_minutes = COALESCE(?, max_task_minutes),
10659
+ period_hours = COALESCE(?, period_hours),
10660
+ updated_at = ?`, [
10661
+ agentId,
10662
+ opts.max_concurrent ?? 5,
10663
+ opts.max_cost_usd ?? null,
10664
+ opts.max_task_minutes ?? null,
10665
+ opts.period_hours ?? 24,
10666
+ timestamp,
10667
+ timestamp,
10668
+ opts.max_concurrent ?? null,
10669
+ opts.max_cost_usd ?? null,
10670
+ opts.max_task_minutes ?? null,
10671
+ opts.period_hours ?? null,
10672
+ timestamp
10673
+ ]);
10674
+ return getBudget(agentId, d);
10675
+ }
10676
+ function getBudget(agentId, db) {
10677
+ const d = db || getDatabase();
10678
+ return d.query("SELECT * FROM agent_budgets WHERE agent_id = ?").get(agentId);
10679
+ }
10680
+ function checkBudget(agentId, db) {
10681
+ const d = db || getDatabase();
10682
+ const budget = getBudget(agentId, d);
10683
+ if (!budget)
10684
+ return { allowed: true, current_concurrent: 0, max_concurrent: 999 };
10685
+ const concurrent = countTasks({ status: "in_progress", assigned_to: agentId }, d);
10686
+ if (concurrent >= budget.max_concurrent) {
10687
+ return { allowed: false, reason: `Concurrent limit reached (${concurrent}/${budget.max_concurrent})`, current_concurrent: concurrent, max_concurrent: budget.max_concurrent };
10688
+ }
10689
+ if (budget.max_cost_usd != null) {
10690
+ const periodStart = new Date(Date.now() - budget.period_hours * 60 * 60 * 1000).toISOString();
10691
+ const costRow = d.query("SELECT COALESCE(SUM(cost_usd), 0) as total FROM tasks WHERE (assigned_to = ? OR agent_id = ?) AND updated_at > ?").get(agentId, agentId, periodStart);
10692
+ if (costRow.total >= budget.max_cost_usd) {
10693
+ return { allowed: false, reason: `Cost limit reached ($${costRow.total.toFixed(2)}/$${budget.max_cost_usd.toFixed(2)} in ${budget.period_hours}h)`, current_concurrent: concurrent, max_concurrent: budget.max_concurrent, current_cost_usd: costRow.total, max_cost_usd: budget.max_cost_usd };
10694
+ }
10695
+ }
10696
+ return { allowed: true, current_concurrent: concurrent, max_concurrent: budget.max_concurrent };
10697
+ }
10698
+ var init_budgets = __esm(() => {
10699
+ init_database();
10700
+ init_tasks();
10701
+ });
10702
+
10366
10703
  // src/lib/github.ts
10367
10704
  var exports_github = {};
10368
10705
  __export(exports_github, {
@@ -11462,14 +11799,14 @@ __export(exports_mcp, {
11462
11799
  });
11463
11800
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
11464
11801
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
11465
- import { readFileSync as readFileSync4 } from "fs";
11466
- import { join as join7, dirname as dirname2 } from "path";
11802
+ import { readFileSync as readFileSync5 } from "fs";
11803
+ import { join as join9, dirname as dirname2 } from "path";
11467
11804
  import { fileURLToPath } from "url";
11468
11805
  function getMcpVersion() {
11469
11806
  try {
11470
11807
  const __dir = dirname2(fileURLToPath(import.meta.url));
11471
- const pkgPath = join7(__dir, "..", "package.json");
11472
- return JSON.parse(readFileSync4(pkgPath, "utf-8")).version || "0.0.0";
11808
+ const pkgPath = join9(__dir, "..", "package.json");
11809
+ return JSON.parse(readFileSync5(pkgPath, "utf-8")).version || "0.0.0";
11473
11810
  } catch {
11474
11811
  return "0.0.0";
11475
11812
  }
@@ -11533,7 +11870,23 @@ function formatError(error) {
11533
11870
  return JSON.stringify({ code: CompletionGuardError.code, message: error.reason, suggestion: CompletionGuardError.suggestion, ...retry });
11534
11871
  }
11535
11872
  if (error instanceof Error) {
11536
- return JSON.stringify({ code: "UNKNOWN_ERROR", message: error.message });
11873
+ const msg = error.message;
11874
+ if (msg.includes("UNIQUE constraint failed: projects.path")) {
11875
+ const db = getDatabase();
11876
+ const existing = db.prepare("SELECT id, name FROM projects WHERE path = ?").get(msg.match(/'([^']+)'$/)?.[1] ?? "");
11877
+ return JSON.stringify({ code: "DUPLICATE_PROJECT", message: `Project already exists at this path${existing ? ` (id: ${existing.id}, name: ${existing.name})` : ""}. Use list_projects to find it.`, suggestion: "Use list_projects or get_project to retrieve the existing project." });
11878
+ }
11879
+ if (msg.includes("UNIQUE constraint failed: projects.name")) {
11880
+ return JSON.stringify({ code: "DUPLICATE_PROJECT", message: "A project with this name already exists. Use a different name or list_projects to find the existing one.", suggestion: "Use list_projects to see existing projects." });
11881
+ }
11882
+ if (msg.includes("UNIQUE constraint failed")) {
11883
+ const table = msg.match(/UNIQUE constraint failed: (\w+)\./)?.[1] ?? "unknown";
11884
+ return JSON.stringify({ code: "DUPLICATE_ENTRY", message: `Duplicate entry in ${table}. The record already exists.`, suggestion: `Use the list or get endpoint for ${table} to find the existing record.` });
11885
+ }
11886
+ if (msg.includes("FOREIGN KEY constraint failed")) {
11887
+ return JSON.stringify({ code: "REFERENCE_ERROR", message: "Referenced record does not exist. Check that the ID is correct.", suggestion: "Verify the referenced ID exists before creating this record." });
11888
+ }
11889
+ return JSON.stringify({ code: "UNKNOWN_ERROR", message: msg });
11537
11890
  }
11538
11891
  return JSON.stringify({ code: "UNKNOWN_ERROR", message: String(error) });
11539
11892
  }
@@ -13037,6 +13390,135 @@ Blocked:`);
13037
13390
  }
13038
13391
  });
13039
13392
  }
13393
+ if (shouldRegisterTool("log_cost")) {
13394
+ server.tool("log_cost", "Log token usage and cost to a task. Accumulates \u2014 call after each LLM invocation.", { task_id: exports_external.string(), tokens: exports_external.number().describe("Token count"), usd: exports_external.number().describe("Cost in USD") }, async ({ task_id, tokens, usd }) => {
13395
+ try {
13396
+ const { logCost: logCost2 } = await Promise.resolve().then(() => (init_tasks(), exports_tasks));
13397
+ const resolvedId = resolveId(task_id, "tasks");
13398
+ logCost2(resolvedId, tokens, usd);
13399
+ return { content: [{ type: "text", text: `Logged ${tokens} tokens ($${usd.toFixed(4)}) to ${task_id}` }] };
13400
+ } catch (e) {
13401
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
13402
+ }
13403
+ });
13404
+ }
13405
+ if (shouldRegisterTool("log_trace")) {
13406
+ server.tool("log_trace", "Log a trace entry (tool call, LLM call, error, handoff) to a task for observability.", {
13407
+ task_id: exports_external.string(),
13408
+ agent_id: exports_external.string().optional(),
13409
+ trace_type: exports_external.enum(["tool_call", "llm_call", "error", "handoff", "custom"]),
13410
+ name: exports_external.string().optional(),
13411
+ input_summary: exports_external.string().optional(),
13412
+ output_summary: exports_external.string().optional(),
13413
+ duration_ms: exports_external.number().optional(),
13414
+ tokens: exports_external.number().optional(),
13415
+ cost_usd: exports_external.number().optional()
13416
+ }, async ({ task_id, agent_id, trace_type, name, input_summary, output_summary, duration_ms, tokens, cost_usd }) => {
13417
+ try {
13418
+ const { logTrace: logTrace2 } = await Promise.resolve().then(() => (init_traces(), exports_traces));
13419
+ const resolvedId = resolveId(task_id, "tasks");
13420
+ const trace = logTrace2({ task_id: resolvedId, agent_id, trace_type, name, input_summary, output_summary, duration_ms, tokens, cost_usd });
13421
+ return { content: [{ type: "text", text: `Trace logged: ${trace.id} [${trace_type}] ${name || ""}` }] };
13422
+ } catch (e) {
13423
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
13424
+ }
13425
+ });
13426
+ }
13427
+ if (shouldRegisterTool("get_traces")) {
13428
+ server.tool("get_traces", "Get execution traces for a task \u2014 tool calls, LLM invocations, errors, handoffs.", { task_id: exports_external.string() }, async ({ task_id }) => {
13429
+ try {
13430
+ const { getTaskTraces: getTaskTraces2, getTraceStats: getTraceStats2 } = await Promise.resolve().then(() => (init_traces(), exports_traces));
13431
+ const resolvedId = resolveId(task_id, "tasks");
13432
+ const traces = getTaskTraces2(resolvedId);
13433
+ const stats = getTraceStats2(resolvedId);
13434
+ const lines = [`Traces for ${task_id}: ${stats.total} total (${stats.tool_calls} tools, ${stats.llm_calls} LLM, ${stats.errors} errors) | ${stats.total_tokens} tokens | $${stats.total_cost_usd.toFixed(4)} | ${stats.total_duration_ms}ms`];
13435
+ for (const t of traces.slice(0, 20)) {
13436
+ lines.push(` ${t.created_at} [${t.trace_type}] ${t.name || ""} ${t.tokens ? t.tokens + "tok" : ""} ${t.duration_ms ? t.duration_ms + "ms" : ""}`);
13437
+ }
13438
+ return { content: [{ type: "text", text: lines.join(`
13439
+ `) }] };
13440
+ } catch (e) {
13441
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
13442
+ }
13443
+ });
13444
+ }
13445
+ if (shouldRegisterTool("save_snapshot")) {
13446
+ server.tool("save_snapshot", "Save a structured context snapshot \u2014 what you were working on, what files are open, what was tried, blockers, next steps. Call on session end or before handoff.", {
13447
+ agent_id: exports_external.string().optional(),
13448
+ task_id: exports_external.string().optional(),
13449
+ project_id: exports_external.string().optional(),
13450
+ snapshot_type: exports_external.enum(["interrupt", "complete", "handoff", "checkpoint"]),
13451
+ plan_summary: exports_external.string().optional(),
13452
+ files_open: exports_external.array(exports_external.string()).optional(),
13453
+ attempts: exports_external.array(exports_external.string()).optional(),
13454
+ blockers: exports_external.array(exports_external.string()).optional(),
13455
+ next_steps: exports_external.string().optional()
13456
+ }, async ({ agent_id, task_id, project_id, snapshot_type, plan_summary, files_open, attempts, blockers, next_steps }) => {
13457
+ try {
13458
+ const { saveSnapshot: saveSnapshot2 } = await Promise.resolve().then(() => (init_snapshots(), exports_snapshots));
13459
+ const snap = saveSnapshot2({ agent_id, task_id, project_id, snapshot_type, plan_summary, files_open, attempts, blockers, next_steps });
13460
+ return { content: [{ type: "text", text: `Snapshot saved: ${snap.id} [${snapshot_type}]${plan_summary ? " \u2014 " + plan_summary.slice(0, 80) : ""}` }] };
13461
+ } catch (e) {
13462
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
13463
+ }
13464
+ });
13465
+ }
13466
+ if (shouldRegisterTool("get_snapshot")) {
13467
+ server.tool("get_snapshot", "Get the latest context snapshot for an agent or task \u2014 use to resume work after interruption.", { agent_id: exports_external.string().optional(), task_id: exports_external.string().optional() }, async ({ agent_id, task_id }) => {
13468
+ try {
13469
+ const { getLatestSnapshot: getLatestSnapshot2 } = await Promise.resolve().then(() => (init_snapshots(), exports_snapshots));
13470
+ const snap = getLatestSnapshot2(agent_id, task_id);
13471
+ if (!snap)
13472
+ return { content: [{ type: "text", text: "No snapshot found." }] };
13473
+ const lines = [`Snapshot [${snap.snapshot_type}] from ${snap.created_at}`];
13474
+ if (snap.plan_summary)
13475
+ lines.push(`Plan: ${snap.plan_summary}`);
13476
+ if (snap.files_open.length > 0)
13477
+ lines.push(`Files: ${snap.files_open.join(", ")}`);
13478
+ if (snap.blockers.length > 0)
13479
+ lines.push(`Blockers: ${snap.blockers.join(", ")}`);
13480
+ if (snap.next_steps)
13481
+ lines.push(`Next: ${snap.next_steps}`);
13482
+ if (snap.attempts.length > 0)
13483
+ lines.push(`Attempts: ${snap.attempts.join("; ")}`);
13484
+ return { content: [{ type: "text", text: lines.join(`
13485
+ `) }] };
13486
+ } catch (e) {
13487
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
13488
+ }
13489
+ });
13490
+ }
13491
+ if (shouldRegisterTool("set_budget")) {
13492
+ server.tool("set_budget", "Set execution budget for an agent \u2014 max concurrent tasks, cost limit, time limit per period.", {
13493
+ agent_id: exports_external.string(),
13494
+ max_concurrent: exports_external.number().optional(),
13495
+ max_cost_usd: exports_external.number().optional(),
13496
+ max_task_minutes: exports_external.number().optional(),
13497
+ period_hours: exports_external.number().optional()
13498
+ }, async ({ agent_id, max_concurrent, max_cost_usd, max_task_minutes, period_hours }) => {
13499
+ try {
13500
+ const { setBudget: setBudget2 } = await Promise.resolve().then(() => (init_budgets(), exports_budgets));
13501
+ const budget = setBudget2(agent_id, { max_concurrent, max_cost_usd, max_task_minutes, period_hours });
13502
+ return { content: [{ type: "text", text: `Budget set for ${agent_id}: max ${budget.max_concurrent} concurrent, $${budget.max_cost_usd ?? "\u221E"} cost limit, ${budget.period_hours}h period` }] };
13503
+ } catch (e) {
13504
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
13505
+ }
13506
+ });
13507
+ }
13508
+ if (shouldRegisterTool("check_budget")) {
13509
+ server.tool("check_budget", "Check if an agent is within their execution budget (concurrent tasks, cost, time).", { agent_id: exports_external.string() }, async ({ agent_id }) => {
13510
+ try {
13511
+ const { checkBudget: checkBudget2 } = await Promise.resolve().then(() => (init_budgets(), exports_budgets));
13512
+ const result = checkBudget2(agent_id);
13513
+ if (result.allowed) {
13514
+ return { content: [{ type: "text", text: `Budget OK: ${result.current_concurrent}/${result.max_concurrent} concurrent tasks` }] };
13515
+ }
13516
+ return { content: [{ type: "text", text: `BUDGET EXCEEDED: ${result.reason}` }], isError: true };
13517
+ } catch (e) {
13518
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
13519
+ }
13520
+ });
13521
+ }
13040
13522
  if (shouldRegisterTool("import_github_issue")) {
13041
13523
  server.tool("import_github_issue", "Import a GitHub issue as a task. Requires gh CLI installed and authenticated.", {
13042
13524
  url: exports_external.string().describe("GitHub issue URL (e.g. https://github.com/owner/repo/issues/42)"),
@@ -13747,6 +14229,56 @@ ${formatTaskDetail(task, 300)}` }] };
13747
14229
  }
13748
14230
  });
13749
14231
  }
14232
+ if (shouldRegisterTool("steal_task")) {
14233
+ server.tool("steal_task", "Work-stealing: take the highest-priority stale in_progress task from another agent and reassign it to you.", {
14234
+ agent_id: exports_external.string().describe("Your agent ID"),
14235
+ stale_minutes: exports_external.number().optional().describe("How long a task must be stale before stealing (default: 30)"),
14236
+ project_id: exports_external.string().optional(),
14237
+ task_list_id: exports_external.string().optional()
14238
+ }, async ({ agent_id, stale_minutes, project_id, task_list_id }) => {
14239
+ try {
14240
+ const task = stealTask(agent_id, { stale_minutes, project_id, task_list_id });
14241
+ if (!task)
14242
+ return { content: [{ type: "text", text: "No stale tasks available to steal." }] };
14243
+ return { content: [{ type: "text", text: `Stolen: ${formatTask(task)}
14244
+ Previous owner: ${task.metadata?._stolen_from || "unknown"}` }] };
14245
+ } catch (e) {
14246
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
14247
+ }
14248
+ });
14249
+ }
14250
+ if (shouldRegisterTool("claim_or_steal")) {
14251
+ server.tool("claim_or_steal", "Try to claim a pending task first; if none available, steal from a stale agent. Best single call for getting work.", {
14252
+ agent_id: exports_external.string(),
14253
+ project_id: exports_external.string().optional(),
14254
+ task_list_id: exports_external.string().optional(),
14255
+ plan_id: exports_external.string().optional(),
14256
+ tags: exports_external.array(exports_external.string()).optional(),
14257
+ stale_minutes: exports_external.number().optional().describe("Stale threshold for work-stealing fallback (default: 30)")
14258
+ }, async ({ agent_id, project_id, task_list_id, plan_id, tags, stale_minutes }) => {
14259
+ try {
14260
+ const filters = {};
14261
+ if (project_id)
14262
+ filters.project_id = resolveId(project_id, "projects");
14263
+ if (task_list_id)
14264
+ filters.task_list_id = resolveId(task_list_id, "task_lists");
14265
+ if (plan_id)
14266
+ filters.plan_id = resolveId(plan_id, "plans");
14267
+ if (tags)
14268
+ filters.tags = tags;
14269
+ if (stale_minutes)
14270
+ filters.stale_minutes = stale_minutes;
14271
+ const result = claimOrSteal(agent_id, Object.keys(filters).length > 0 ? filters : undefined);
14272
+ if (!result)
14273
+ return { content: [{ type: "text", text: "No tasks available to claim or steal." }] };
14274
+ const prefix = result.stolen ? "Stolen" : "Claimed";
14275
+ return { content: [{ type: "text", text: `${prefix}: ${formatTask(result.task)}
14276
+ ${formatTaskDetail(result.task, 300)}` }] };
14277
+ } catch (e) {
14278
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
14279
+ }
14280
+ });
14281
+ }
13750
14282
  if (shouldRegisterTool("get_stale_tasks")) {
13751
14283
  server.tool("get_stale_tasks", "Find stale in_progress tasks with no recent activity.", {
13752
14284
  stale_minutes: exports_external.number().optional(),
@@ -15414,27 +15946,27 @@ var exports_serve = {};
15414
15946
  __export(exports_serve, {
15415
15947
  startServer: () => startServer
15416
15948
  });
15417
- import { existsSync as existsSync6 } from "fs";
15418
- import { join as join8, dirname as dirname3, extname, resolve as resolve3, sep } from "path";
15949
+ import { existsSync as existsSync8 } from "fs";
15950
+ import { join as join10, dirname as dirname3, extname, resolve as resolve3, sep } from "path";
15419
15951
  import { fileURLToPath as fileURLToPath2 } from "url";
15420
15952
  function resolveDashboardDir() {
15421
15953
  const candidates = [];
15422
15954
  try {
15423
15955
  const scriptDir = dirname3(fileURLToPath2(import.meta.url));
15424
- candidates.push(join8(scriptDir, "..", "dashboard", "dist"));
15425
- candidates.push(join8(scriptDir, "..", "..", "dashboard", "dist"));
15956
+ candidates.push(join10(scriptDir, "..", "dashboard", "dist"));
15957
+ candidates.push(join10(scriptDir, "..", "..", "dashboard", "dist"));
15426
15958
  } catch {}
15427
15959
  if (process.argv[1]) {
15428
15960
  const mainDir = dirname3(process.argv[1]);
15429
- candidates.push(join8(mainDir, "..", "dashboard", "dist"));
15430
- candidates.push(join8(mainDir, "..", "..", "dashboard", "dist"));
15961
+ candidates.push(join10(mainDir, "..", "dashboard", "dist"));
15962
+ candidates.push(join10(mainDir, "..", "..", "dashboard", "dist"));
15431
15963
  }
15432
- candidates.push(join8(process.cwd(), "dashboard", "dist"));
15964
+ candidates.push(join10(process.cwd(), "dashboard", "dist"));
15433
15965
  for (const candidate of candidates) {
15434
- if (existsSync6(candidate))
15966
+ if (existsSync8(candidate))
15435
15967
  return candidate;
15436
15968
  }
15437
- return join8(process.cwd(), "dashboard", "dist");
15969
+ return join10(process.cwd(), "dashboard", "dist");
15438
15970
  }
15439
15971
  function json(data, status = 200, port) {
15440
15972
  return new Response(JSON.stringify(data), {
@@ -15447,7 +15979,7 @@ function json(data, status = 200, port) {
15447
15979
  });
15448
15980
  }
15449
15981
  function serveStaticFile(filePath) {
15450
- if (!existsSync6(filePath))
15982
+ if (!existsSync8(filePath))
15451
15983
  return null;
15452
15984
  const ext = extname(filePath);
15453
15985
  const contentType = MIME_TYPES[ext] || "application/octet-stream";
@@ -15514,7 +16046,7 @@ data: ${data}
15514
16046
  }
15515
16047
  }
15516
16048
  const dashboardDir = resolveDashboardDir();
15517
- const dashboardExists = existsSync6(dashboardDir);
16049
+ const dashboardExists = existsSync8(dashboardDir);
15518
16050
  if (!dashboardExists) {
15519
16051
  console.error(`
15520
16052
  Dashboard not found at: ${dashboardDir}`);
@@ -16238,7 +16770,7 @@ data: ${JSON.stringify({ type: "connected", agent_id: agentId, timestamp: new Da
16238
16770
  }
16239
16771
  if (dashboardExists && (method === "GET" || method === "HEAD")) {
16240
16772
  if (path !== "/") {
16241
- const filePath = join8(dashboardDir, path);
16773
+ const filePath = join10(dashboardDir, path);
16242
16774
  const resolvedFile = resolve3(filePath);
16243
16775
  const resolvedBase = resolve3(dashboardDir);
16244
16776
  if (!resolvedFile.startsWith(resolvedBase + sep) && resolvedFile !== resolvedBase) {
@@ -16248,7 +16780,7 @@ data: ${JSON.stringify({ type: "connected", agent_id: agentId, timestamp: new Da
16248
16780
  if (res2)
16249
16781
  return res2;
16250
16782
  }
16251
- const indexPath = join8(dashboardDir, "index.html");
16783
+ const indexPath = join10(dashboardDir, "index.html");
16252
16784
  const res = serveStaticFile(indexPath);
16253
16785
  if (res)
16254
16786
  return res;
@@ -17667,15 +18199,318 @@ init_comments();
17667
18199
  init_search();
17668
18200
  init_sync();
17669
18201
  init_config();
17670
- import chalk from "chalk";
18202
+ import chalk2 from "chalk";
17671
18203
  import { execSync as execSync2 } from "child_process";
17672
- import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
17673
- import { basename, dirname as dirname4, join as join9, resolve as resolve4 } from "path";
18204
+ import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
18205
+ import { basename, dirname as dirname4, join as join11, resolve as resolve4 } from "path";
17674
18206
  import { fileURLToPath as fileURLToPath3 } from "url";
18207
+
18208
+ // src/cli/brains.ts
18209
+ import {
18210
+ existsSync as existsSync7,
18211
+ mkdirSync as mkdirSync4,
18212
+ writeFileSync as writeFileSync4,
18213
+ readdirSync as readdirSync3
18214
+ } from "fs";
18215
+ import { homedir as homedir2 } from "os";
18216
+ import { join as join7 } from "path";
18217
+ import chalk from "chalk";
18218
+
18219
+ // src/lib/gatherer.ts
18220
+ init_tasks();
18221
+ var SYSTEM_PROMPT = "You are a task management assistant that creates, updates, and tracks tasks and projects.";
18222
+ function taskToCreateExample(task) {
18223
+ const userMsg = `Create a task: ${task.title}${task.description ? `
18224
+
18225
+ Description: ${task.description}` : ""}`;
18226
+ const taskDetails = {
18227
+ id: task.short_id ?? task.id,
18228
+ title: task.title,
18229
+ description: task.description ?? "",
18230
+ status: task.status,
18231
+ priority: task.priority,
18232
+ tags: task.tags,
18233
+ created_at: task.created_at
18234
+ };
18235
+ return {
18236
+ messages: [
18237
+ { role: "system", content: SYSTEM_PROMPT },
18238
+ { role: "user", content: userMsg },
18239
+ {
18240
+ role: "assistant",
18241
+ content: `Created task: ${JSON.stringify(taskDetails, null, 2)}`
18242
+ }
18243
+ ]
18244
+ };
18245
+ }
18246
+ function taskToStatusUpdateExample(task) {
18247
+ if (!task.completed_at && task.status === "pending")
18248
+ return null;
18249
+ const id = task.short_id ?? task.id;
18250
+ return {
18251
+ messages: [
18252
+ { role: "system", content: SYSTEM_PROMPT },
18253
+ { role: "user", content: `Mark task ${id} as ${task.status}` },
18254
+ {
18255
+ role: "assistant",
18256
+ content: `Task ${id} has been updated to status: ${task.status}. ${task.completed_at ? `Completed at: ${task.completed_at}` : ""}`.trim()
18257
+ }
18258
+ ]
18259
+ };
18260
+ }
18261
+ function taskToSearchExample(tasks, query) {
18262
+ const matched = tasks.filter((t) => t.title.toLowerCase().includes(query.toLowerCase())).slice(0, 5);
18263
+ return {
18264
+ messages: [
18265
+ { role: "system", content: SYSTEM_PROMPT },
18266
+ { role: "user", content: `Search tasks for: "${query}"` },
18267
+ {
18268
+ role: "assistant",
18269
+ content: matched.length > 0 ? `Found ${matched.length} task(s):
18270
+ ${matched.map((t) => `- [${t.short_id ?? t.id}] ${t.title} (${t.status})`).join(`
18271
+ `)}` : `No tasks found matching "${query}".`
18272
+ }
18273
+ ]
18274
+ };
18275
+ }
18276
+ var gatherTrainingData = async (options = {}) => {
18277
+ const allTasks = listTasks({});
18278
+ const filtered = options.since ? allTasks.filter((t) => new Date(t.created_at) >= options.since) : allTasks;
18279
+ const sorted = filtered.slice().sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
18280
+ const fetchSet = options.limit ? sorted.slice(0, options.limit * 2) : sorted;
18281
+ const examples = [];
18282
+ for (const task of fetchSet) {
18283
+ examples.push(taskToCreateExample(task));
18284
+ const statusEx = taskToStatusUpdateExample(task);
18285
+ if (statusEx)
18286
+ examples.push(statusEx);
18287
+ }
18288
+ const searchTerms = ["urgent", "fix", "implement", "create", "update", "review"];
18289
+ for (const term of searchTerms) {
18290
+ examples.push(taskToSearchExample(sorted, term));
18291
+ }
18292
+ const finalExamples = options.limit ? examples.slice(0, options.limit) : examples;
18293
+ return {
18294
+ source: "todos",
18295
+ examples: finalExamples,
18296
+ count: finalExamples.length
18297
+ };
18298
+ };
18299
+
18300
+ // src/lib/model-config.ts
18301
+ import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
18302
+ import { homedir } from "os";
18303
+ import { join as join6 } from "path";
18304
+ var DEFAULT_MODEL = "gpt-4o-mini";
18305
+ var CONFIG_DIR = join6(homedir(), ".todos");
18306
+ var CONFIG_PATH = join6(CONFIG_DIR, "config.json");
18307
+ function readConfig() {
18308
+ if (!existsSync6(CONFIG_PATH))
18309
+ return {};
18310
+ try {
18311
+ const raw = readFileSync3(CONFIG_PATH, "utf-8");
18312
+ return JSON.parse(raw);
18313
+ } catch {
18314
+ return {};
18315
+ }
18316
+ }
18317
+ function writeConfig(config) {
18318
+ if (!existsSync6(CONFIG_DIR)) {
18319
+ mkdirSync3(CONFIG_DIR, { recursive: true });
18320
+ }
18321
+ writeFileSync3(CONFIG_PATH, JSON.stringify(config, null, 2) + `
18322
+ `, "utf-8");
18323
+ }
18324
+ function getActiveModel() {
18325
+ const config = readConfig();
18326
+ return config.activeModel ?? DEFAULT_MODEL;
18327
+ }
18328
+ function setActiveModel(modelId) {
18329
+ const config = readConfig();
18330
+ config.activeModel = modelId;
18331
+ writeConfig(config);
18332
+ }
18333
+ function clearActiveModel() {
18334
+ const config = readConfig();
18335
+ delete config.activeModel;
18336
+ writeConfig(config);
18337
+ }
18338
+
18339
+ // src/cli/brains.ts
18340
+ function printSuccess(msg) {
18341
+ console.log(chalk.green("\u2713 " + msg));
18342
+ }
18343
+ function printError(msg) {
18344
+ console.error(chalk.red("\u2717 " + msg));
18345
+ }
18346
+ function printInfo(msg) {
18347
+ console.log(chalk.cyan("\u2139 " + msg));
18348
+ }
18349
+ function makeBrainsCommand() {
18350
+ const brains = new Command("brains");
18351
+ brains.description("Fine-tuned model training and management (via @hasna/brains)");
18352
+ brains.command("gather").description("Gather training data from tasks and write to JSONL").option("--limit <n>", "Maximum number of examples to gather", parseInt).option("--since <date>", "Only include tasks created since this date (ISO 8601)").option("--output <dir>", "Output directory (default: ~/.todos/training/)").option("--json", "Output result summary as JSON").action(async (opts) => {
18353
+ try {
18354
+ const since = opts.since ? new Date(opts.since) : undefined;
18355
+ if (since && isNaN(since.getTime())) {
18356
+ printError(`Invalid date: ${opts.since}`);
18357
+ process.exit(1);
18358
+ }
18359
+ if (!opts.json) {
18360
+ printInfo("Gathering training data from tasks...");
18361
+ }
18362
+ const result = await gatherTrainingData({
18363
+ limit: opts.limit,
18364
+ since
18365
+ });
18366
+ const outputDir = opts.output ?? join7(homedir2(), ".todos", "training");
18367
+ if (!existsSync7(outputDir)) {
18368
+ mkdirSync4(outputDir, { recursive: true });
18369
+ }
18370
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
18371
+ const outputPath = join7(outputDir, `todos-training-${timestamp}.jsonl`);
18372
+ const jsonl = result.examples.map((ex) => JSON.stringify(ex)).join(`
18373
+ `);
18374
+ writeFileSync4(outputPath, jsonl + `
18375
+ `, "utf-8");
18376
+ if (opts.json) {
18377
+ console.log(JSON.stringify({
18378
+ source: result.source,
18379
+ count: result.count,
18380
+ path: outputPath
18381
+ }));
18382
+ } else {
18383
+ printSuccess(`Gathered ${result.count} training examples from tasks`);
18384
+ console.log(chalk.dim(` Output: ${outputPath}`));
18385
+ }
18386
+ } catch (err) {
18387
+ printError(err instanceof Error ? err.message : String(err));
18388
+ process.exit(1);
18389
+ }
18390
+ });
18391
+ brains.command("train").description("Start a fine-tuning job using gathered task training data").option("--base-model <model>", "Base model to fine-tune", "gpt-4o-mini-2024-07-18").option("--provider <provider>", "Provider (openai|thinker-labs)", "openai").option("--dataset <path>", "Path to JSONL dataset (auto-detects latest if omitted)").option("--name <name>", "Display name for the fine-tuned model").option("--json", "Output result as JSON").action(async (opts) => {
18392
+ try {
18393
+ let datasetPath = opts.dataset;
18394
+ if (!datasetPath) {
18395
+ const trainingDir = join7(homedir2(), ".todos", "training");
18396
+ if (!existsSync7(trainingDir)) {
18397
+ printError("No training data found. Run `todos brains gather` first.");
18398
+ process.exit(1);
18399
+ }
18400
+ const files = readdirSync3(trainingDir).filter((f) => f.endsWith(".jsonl")).sort().reverse();
18401
+ const latestFile = files[0];
18402
+ if (!latestFile) {
18403
+ printError("No JSONL training files found. Run `todos brains gather` first.");
18404
+ process.exit(1);
18405
+ }
18406
+ datasetPath = join7(trainingDir, latestFile);
18407
+ }
18408
+ if (!datasetPath || !existsSync7(datasetPath)) {
18409
+ printError(`Dataset file not found: ${datasetPath ?? "(unresolved)"}`);
18410
+ process.exit(1);
18411
+ }
18412
+ if (!opts.json) {
18413
+ printInfo(`Starting fine-tuning job with dataset: ${datasetPath}`);
18414
+ }
18415
+ let brainsSDK;
18416
+ try {
18417
+ brainsSDK = await import("@hasna/brains");
18418
+ } catch {
18419
+ printError("@hasna/brains is not installed. Run `bun add @hasna/brains` to enable training.");
18420
+ process.exit(1);
18421
+ }
18422
+ const startFinetune = brainsSDK["startFinetune"];
18423
+ if (typeof startFinetune !== "function") {
18424
+ printError("@hasna/brains does not export startFinetune. Please update @hasna/brains.");
18425
+ process.exit(1);
18426
+ }
18427
+ const modelName = opts.name ?? `todos-${new Date().toISOString().slice(0, 10)}`;
18428
+ const jobResult = await startFinetune({
18429
+ provider: opts.provider,
18430
+ baseModel: opts.baseModel,
18431
+ datasetPath,
18432
+ name: modelName
18433
+ });
18434
+ if (opts.json) {
18435
+ console.log(JSON.stringify(jobResult));
18436
+ } else {
18437
+ printSuccess(`Fine-tuning job started: ${String(jobResult["jobId"] ?? "(unknown)")}`);
18438
+ console.log(chalk.dim(` Provider: ${opts.provider}`));
18439
+ console.log(chalk.dim(` Base model: ${opts.baseModel}`));
18440
+ console.log(chalk.dim(` Name: ${modelName}`));
18441
+ if (jobResult["jobId"]) {
18442
+ console.log();
18443
+ printInfo(`Use \`todos brains model set <model-id>\` once training completes.`);
18444
+ }
18445
+ }
18446
+ } catch (err) {
18447
+ printError(err instanceof Error ? err.message : String(err));
18448
+ process.exit(1);
18449
+ }
18450
+ });
18451
+ const modelCmd = brains.command("model").description("Manage the active fine-tuned model");
18452
+ modelCmd.command("get").description("Show the currently active fine-tuned model").option("--json", "Output as JSON").action((opts) => {
18453
+ try {
18454
+ const active = getActiveModel();
18455
+ const isDefault = active === DEFAULT_MODEL;
18456
+ if (opts.json) {
18457
+ console.log(JSON.stringify({ activeModel: active, isDefault }));
18458
+ } else {
18459
+ if (isDefault) {
18460
+ console.log(`Active model: ${chalk.cyan(active)} ${chalk.dim("(default)")}`);
18461
+ } else {
18462
+ console.log(`Active model: ${chalk.green(active)}`);
18463
+ }
18464
+ }
18465
+ } catch (err) {
18466
+ printError(err instanceof Error ? err.message : String(err));
18467
+ process.exit(1);
18468
+ }
18469
+ });
18470
+ modelCmd.command("set <modelId>").description("Set the active fine-tuned model ID").action((modelId) => {
18471
+ try {
18472
+ setActiveModel(modelId);
18473
+ printSuccess(`Active model set to: ${modelId}`);
18474
+ } catch (err) {
18475
+ printError(err instanceof Error ? err.message : String(err));
18476
+ process.exit(1);
18477
+ }
18478
+ });
18479
+ modelCmd.command("clear").description(`Clear the active fine-tuned model (reverts to ${DEFAULT_MODEL})`).action(() => {
18480
+ try {
18481
+ clearActiveModel();
18482
+ printSuccess(`Active model cleared. Using default: ${DEFAULT_MODEL}`);
18483
+ } catch (err) {
18484
+ printError(err instanceof Error ? err.message : String(err));
18485
+ process.exit(1);
18486
+ }
18487
+ });
18488
+ modelCmd.action((opts) => {
18489
+ try {
18490
+ const active = getActiveModel();
18491
+ const isDefault = active === DEFAULT_MODEL;
18492
+ if (opts.json) {
18493
+ console.log(JSON.stringify({ activeModel: active, isDefault }));
18494
+ } else {
18495
+ if (isDefault) {
18496
+ console.log(`Active model: ${chalk.cyan(active)} ${chalk.dim("(default)")}`);
18497
+ } else {
18498
+ console.log(`Active model: ${chalk.green(active)}`);
18499
+ }
18500
+ }
18501
+ } catch (err) {
18502
+ printError(err instanceof Error ? err.message : String(err));
18503
+ process.exit(1);
18504
+ }
18505
+ });
18506
+ return brains;
18507
+ }
18508
+
18509
+ // src/cli/index.tsx
17675
18510
  function getPackageVersion() {
17676
18511
  try {
17677
- const pkgPath = join9(dirname4(fileURLToPath3(import.meta.url)), "..", "..", "package.json");
17678
- return JSON.parse(readFileSync5(pkgPath, "utf-8")).version || "0.0.0";
18512
+ const pkgPath = join11(dirname4(fileURLToPath3(import.meta.url)), "..", "..", "package.json");
18513
+ return JSON.parse(readFileSync6(pkgPath, "utf-8")).version || "0.0.0";
17679
18514
  } catch {
17680
18515
  return "0.0.0";
17681
18516
  }
@@ -17686,7 +18521,7 @@ function handleError(e) {
17686
18521
  if (globalOpts.json) {
17687
18522
  console.log(JSON.stringify({ error: e instanceof Error ? e.message : String(e) }));
17688
18523
  } else {
17689
- console.error(chalk.red(e instanceof Error ? e.message : String(e)));
18524
+ console.error(chalk2.red(e instanceof Error ? e.message : String(e)));
17690
18525
  }
17691
18526
  process.exit(1);
17692
18527
  }
@@ -17696,10 +18531,10 @@ function resolveTaskId(partialId) {
17696
18531
  if (!id) {
17697
18532
  const similar = db.query("SELECT id FROM tasks WHERE id LIKE ? LIMIT 3").all(`%${partialId}%`);
17698
18533
  if (similar.length > 0) {
17699
- console.error(chalk.red(`Could not resolve task ID: ${partialId}`));
17700
- console.error(chalk.dim(`Did you mean: ${similar.map((s) => s.id.slice(0, 8)).join(", ")}?`));
18534
+ console.error(chalk2.red(`Could not resolve task ID: ${partialId}`));
18535
+ console.error(chalk2.dim(`Did you mean: ${similar.map((s) => s.id.slice(0, 8)).join(", ")}?`));
17701
18536
  } else {
17702
- console.error(chalk.red(`Could not resolve task ID: ${partialId}`));
18537
+ console.error(chalk2.red(`Could not resolve task ID: ${partialId}`));
17703
18538
  }
17704
18539
  process.exit(1);
17705
18540
  }
@@ -17733,26 +18568,26 @@ function output(data, jsonMode) {
17733
18568
  }
17734
18569
  }
17735
18570
  var statusColors4 = {
17736
- pending: chalk.yellow,
17737
- in_progress: chalk.blue,
17738
- completed: chalk.green,
17739
- failed: chalk.red,
17740
- cancelled: chalk.gray
18571
+ pending: chalk2.yellow,
18572
+ in_progress: chalk2.blue,
18573
+ completed: chalk2.green,
18574
+ failed: chalk2.red,
18575
+ cancelled: chalk2.gray
17741
18576
  };
17742
18577
  var priorityColors2 = {
17743
- critical: chalk.red.bold,
17744
- high: chalk.red,
17745
- medium: chalk.yellow,
17746
- low: chalk.gray
18578
+ critical: chalk2.red.bold,
18579
+ high: chalk2.red,
18580
+ medium: chalk2.yellow,
18581
+ low: chalk2.gray
17747
18582
  };
17748
18583
  function formatTaskLine(t) {
17749
- const statusFn = statusColors4[t.status] || chalk.white;
17750
- const priorityFn = priorityColors2[t.priority] || chalk.white;
17751
- const lock = t.locked_by ? chalk.magenta(` [locked:${t.locked_by}]`) : "";
17752
- const assigned = t.assigned_to ? chalk.cyan(` -> ${t.assigned_to}`) : "";
17753
- const tags = t.tags.length > 0 ? chalk.dim(` [${t.tags.join(",")}]`) : "";
17754
- const plan = t.plan_id ? chalk.magenta(` [plan:${t.plan_id.slice(0, 8)}]`) : "";
17755
- return `${chalk.dim(t.id.slice(0, 8))} ${statusFn(t.status.padEnd(11))} ${priorityFn(t.priority.padEnd(8))} ${t.title}${assigned}${lock}${tags}${plan}`;
18584
+ const statusFn = statusColors4[t.status] || chalk2.white;
18585
+ const priorityFn = priorityColors2[t.priority] || chalk2.white;
18586
+ const lock = t.locked_by ? chalk2.magenta(` [locked:${t.locked_by}]`) : "";
18587
+ const assigned = t.assigned_to ? chalk2.cyan(` -> ${t.assigned_to}`) : "";
18588
+ const tags = t.tags.length > 0 ? chalk2.dim(` [${t.tags.join(",")}]`) : "";
18589
+ const plan = t.plan_id ? chalk2.magenta(` [plan:${t.plan_id.slice(0, 8)}]`) : "";
18590
+ return `${chalk2.dim(t.id.slice(0, 8))} ${statusFn(t.status.padEnd(11))} ${priorityFn(t.priority.padEnd(8))} ${t.title}${assigned}${lock}${tags}${plan}`;
17756
18591
  }
17757
18592
  program2.name("todos").description("Universal task management for AI coding agents").version(getPackageVersion()).option("--project <path>", "Project path").option("--json", "Output as JSON").option("--agent <name>", "Agent name").option("--session <id>", "Session ID");
17758
18593
  program2.command("add <title>").description("Create a new task").option("-d, --description <text>", "Task description").option("-p, --priority <level>", "Priority: low, medium, high, critical").option("--parent <id>", "Parent task ID").option("-t, --tags <tags>", "Comma-separated tags").option("--tag <tags>", "Comma-separated tags (alias for --tags)").option("--plan <id>", "Assign to a plan").option("--assign <agent>", "Assign to agent").option("--status <status>", "Initial status").option("--list <id>", "Task list ID").option("--task-list <id>", "Task list ID (alias for --list)").option("--estimated <minutes>", "Estimated time in minutes").option("--approval", "Require approval before completion").option("--recurrence <rule>", "Recurrence rule, e.g. 'every day', 'every weekday', 'every 2 weeks'").option("--due <date>", "Due date (ISO string or YYYY-MM-DD)").option("--reason <text>", "Why this task exists").action((title, opts) => {
@@ -17764,7 +18599,7 @@ program2.command("add <title>").description("Create a new task").option("-d, --d
17764
18599
  const db = getDatabase();
17765
18600
  const id = resolvePartialId(db, "task_lists", opts.list);
17766
18601
  if (!id) {
17767
- console.error(chalk.red(`Could not resolve task list ID: ${opts.list}`));
18602
+ console.error(chalk2.red(`Could not resolve task list ID: ${opts.list}`));
17768
18603
  process.exit(1);
17769
18604
  }
17770
18605
  return id;
@@ -17779,7 +18614,7 @@ program2.command("add <title>").description("Create a new task").option("-d, --d
17779
18614
  const db = getDatabase();
17780
18615
  const id = resolvePartialId(db, "plans", opts.plan);
17781
18616
  if (!id) {
17782
- console.error(chalk.red(`Could not resolve plan ID: ${opts.plan}`));
18617
+ console.error(chalk2.red(`Could not resolve plan ID: ${opts.plan}`));
17783
18618
  process.exit(1);
17784
18619
  }
17785
18620
  return id;
@@ -17800,7 +18635,7 @@ program2.command("add <title>").description("Create a new task").option("-d, --d
17800
18635
  if (globalOpts.json) {
17801
18636
  output(task, true);
17802
18637
  } else {
17803
- console.log(chalk.green("Task created:"));
18638
+ console.log(chalk2.green("Task created:"));
17804
18639
  console.log(formatTaskLine(task));
17805
18640
  }
17806
18641
  });
@@ -17816,7 +18651,7 @@ program2.command("list").description("List tasks").option("-s, --status <status>
17816
18651
  const db = getDatabase();
17817
18652
  const listId = resolvePartialId(db, "task_lists", opts.list);
17818
18653
  if (!listId) {
17819
- console.error(chalk.red(`Could not resolve task list ID: ${opts.list}`));
18654
+ console.error(chalk2.red(`Could not resolve task list ID: ${opts.list}`));
17820
18655
  process.exit(1);
17821
18656
  }
17822
18657
  filter["task_list_id"] = listId;
@@ -17838,7 +18673,7 @@ program2.command("list").description("List tasks").option("-s, --status <status>
17838
18673
  if (match) {
17839
18674
  filter["project_id"] = match.id;
17840
18675
  } else {
17841
- console.error(chalk.red(`No project matching: ${opts.projectName}`));
18676
+ console.error(chalk2.red(`No project matching: ${opts.projectName}`));
17842
18677
  process.exit(1);
17843
18678
  }
17844
18679
  }
@@ -17882,7 +18717,7 @@ program2.command("list").description("List tasks").option("-s, --status <status>
17882
18717
  if (fmt === "compact" || fmt === "csv")
17883
18718
  process.stdout.write("");
17884
18719
  else
17885
- console.log(chalk.dim("No tasks found."));
18720
+ console.log(chalk2.dim("No tasks found."));
17886
18721
  return;
17887
18722
  }
17888
18723
  if (fmt === "csv") {
@@ -17909,7 +18744,7 @@ program2.command("list").description("List tasks").option("-s, --status <status>
17909
18744
  }
17910
18745
  return;
17911
18746
  }
17912
- console.log(chalk.bold(`${tasks.length} task(s):
18747
+ console.log(chalk2.bold(`${tasks.length} task(s):
17913
18748
  `));
17914
18749
  for (const t of tasks) {
17915
18750
  console.log(formatTaskLine(t));
@@ -17926,12 +18761,12 @@ program2.command("count").description("Show task count by status").action(() =>
17926
18761
  output(counts, true);
17927
18762
  } else {
17928
18763
  const parts = [
17929
- `total: ${chalk.bold(String(counts.total))}`,
17930
- `pending: ${chalk.yellow(String(counts["pending"] || 0))}`,
17931
- `in_progress: ${chalk.blue(String(counts["in_progress"] || 0))}`,
17932
- `completed: ${chalk.green(String(counts["completed"] || 0))}`,
17933
- `failed: ${chalk.red(String(counts["failed"] || 0))}`,
17934
- `cancelled: ${chalk.gray(String(counts["cancelled"] || 0))}`
18764
+ `total: ${chalk2.bold(String(counts.total))}`,
18765
+ `pending: ${chalk2.yellow(String(counts["pending"] || 0))}`,
18766
+ `in_progress: ${chalk2.blue(String(counts["in_progress"] || 0))}`,
18767
+ `completed: ${chalk2.green(String(counts["completed"] || 0))}`,
18768
+ `failed: ${chalk2.red(String(counts["failed"] || 0))}`,
18769
+ `cancelled: ${chalk2.gray(String(counts["cancelled"] || 0))}`
17935
18770
  ];
17936
18771
  console.log(parts.join(" "));
17937
18772
  }
@@ -17941,83 +18776,83 @@ program2.command("show <id>").description("Show full task details").action((id)
17941
18776
  const resolvedId = resolveTaskId(id);
17942
18777
  const task = getTaskWithRelations(resolvedId);
17943
18778
  if (!task) {
17944
- console.error(chalk.red(`Task not found: ${id}`));
18779
+ console.error(chalk2.red(`Task not found: ${id}`));
17945
18780
  process.exit(1);
17946
18781
  }
17947
18782
  if (globalOpts.json) {
17948
18783
  output(task, true);
17949
18784
  return;
17950
18785
  }
17951
- console.log(chalk.bold(`Task Details:
18786
+ console.log(chalk2.bold(`Task Details:
17952
18787
  `));
17953
- console.log(` ${chalk.dim("ID:")} ${task.id}`);
17954
- console.log(` ${chalk.dim("Title:")} ${task.title}`);
17955
- console.log(` ${chalk.dim("Status:")} ${(statusColors4[task.status] || chalk.white)(task.status)}`);
17956
- console.log(` ${chalk.dim("Priority:")} ${(priorityColors2[task.priority] || chalk.white)(task.priority)}`);
18788
+ console.log(` ${chalk2.dim("ID:")} ${task.id}`);
18789
+ console.log(` ${chalk2.dim("Title:")} ${task.title}`);
18790
+ console.log(` ${chalk2.dim("Status:")} ${(statusColors4[task.status] || chalk2.white)(task.status)}`);
18791
+ console.log(` ${chalk2.dim("Priority:")} ${(priorityColors2[task.priority] || chalk2.white)(task.priority)}`);
17957
18792
  if (task.description)
17958
- console.log(` ${chalk.dim("Desc:")} ${task.description}`);
18793
+ console.log(` ${chalk2.dim("Desc:")} ${task.description}`);
17959
18794
  if (task.assigned_to)
17960
- console.log(` ${chalk.dim("Assigned:")} ${task.assigned_to}`);
18795
+ console.log(` ${chalk2.dim("Assigned:")} ${task.assigned_to}`);
17961
18796
  if (task.agent_id)
17962
- console.log(` ${chalk.dim("Agent:")} ${task.agent_id}`);
18797
+ console.log(` ${chalk2.dim("Agent:")} ${task.agent_id}`);
17963
18798
  if (task.session_id)
17964
- console.log(` ${chalk.dim("Session:")} ${task.session_id}`);
18799
+ console.log(` ${chalk2.dim("Session:")} ${task.session_id}`);
17965
18800
  if (task.locked_by)
17966
- console.log(` ${chalk.dim("Locked:")} ${task.locked_by} (at ${task.locked_at})`);
18801
+ console.log(` ${chalk2.dim("Locked:")} ${task.locked_by} (at ${task.locked_at})`);
17967
18802
  if (task.requires_approval) {
17968
- const approvalStatus = task.approved_by ? chalk.green(`approved by ${task.approved_by}`) : chalk.yellow("pending approval");
17969
- console.log(` ${chalk.dim("Approval:")} ${approvalStatus}`);
18803
+ const approvalStatus = task.approved_by ? chalk2.green(`approved by ${task.approved_by}`) : chalk2.yellow("pending approval");
18804
+ console.log(` ${chalk2.dim("Approval:")} ${approvalStatus}`);
17970
18805
  }
17971
18806
  if (task.estimated_minutes)
17972
- console.log(` ${chalk.dim("Estimate:")} ${task.estimated_minutes} minutes`);
18807
+ console.log(` ${chalk2.dim("Estimate:")} ${task.estimated_minutes} minutes`);
17973
18808
  if (task.project_id)
17974
- console.log(` ${chalk.dim("Project:")} ${task.project_id}`);
18809
+ console.log(` ${chalk2.dim("Project:")} ${task.project_id}`);
17975
18810
  if (task.plan_id)
17976
- console.log(` ${chalk.dim("Plan:")} ${task.plan_id}`);
18811
+ console.log(` ${chalk2.dim("Plan:")} ${task.plan_id}`);
17977
18812
  if (task.working_dir)
17978
- console.log(` ${chalk.dim("WorkDir:")} ${task.working_dir}`);
18813
+ console.log(` ${chalk2.dim("WorkDir:")} ${task.working_dir}`);
17979
18814
  if (task.parent)
17980
- console.log(` ${chalk.dim("Parent:")} ${task.parent.id.slice(0, 8)} | ${task.parent.title}`);
18815
+ console.log(` ${chalk2.dim("Parent:")} ${task.parent.id.slice(0, 8)} | ${task.parent.title}`);
17981
18816
  if (task.tags.length > 0)
17982
- console.log(` ${chalk.dim("Tags:")} ${task.tags.join(", ")}`);
17983
- console.log(` ${chalk.dim("Version:")} ${task.version}`);
17984
- console.log(` ${chalk.dim("Created:")} ${task.created_at}`);
18817
+ console.log(` ${chalk2.dim("Tags:")} ${task.tags.join(", ")}`);
18818
+ console.log(` ${chalk2.dim("Version:")} ${task.version}`);
18819
+ console.log(` ${chalk2.dim("Created:")} ${task.created_at}`);
17985
18820
  if (task.started_at)
17986
- console.log(` ${chalk.dim("Started:")} ${task.started_at}`);
18821
+ console.log(` ${chalk2.dim("Started:")} ${task.started_at}`);
17987
18822
  if (task.completed_at) {
17988
- console.log(` ${chalk.dim("Done:")} ${task.completed_at}`);
18823
+ console.log(` ${chalk2.dim("Done:")} ${task.completed_at}`);
17989
18824
  if (task.started_at) {
17990
18825
  const dur = Math.round((new Date(task.completed_at).getTime() - new Date(task.started_at).getTime()) / 60000);
17991
- console.log(` ${chalk.dim("Duration:")} ${dur}m`);
18826
+ console.log(` ${chalk2.dim("Duration:")} ${dur}m`);
17992
18827
  }
17993
18828
  }
17994
18829
  if (task.subtasks.length > 0) {
17995
- console.log(chalk.bold(`
18830
+ console.log(chalk2.bold(`
17996
18831
  Subtasks (${task.subtasks.length}):`));
17997
18832
  for (const st of task.subtasks) {
17998
18833
  console.log(` ${formatTaskLine(st)}`);
17999
18834
  }
18000
18835
  }
18001
18836
  if (task.dependencies.length > 0) {
18002
- console.log(chalk.bold(`
18837
+ console.log(chalk2.bold(`
18003
18838
  Depends on (${task.dependencies.length}):`));
18004
18839
  for (const dep of task.dependencies) {
18005
18840
  console.log(` ${formatTaskLine(dep)}`);
18006
18841
  }
18007
18842
  }
18008
18843
  if (task.blocked_by.length > 0) {
18009
- console.log(chalk.bold(`
18844
+ console.log(chalk2.bold(`
18010
18845
  Blocks (${task.blocked_by.length}):`));
18011
18846
  for (const b of task.blocked_by) {
18012
18847
  console.log(` ${formatTaskLine(b)}`);
18013
18848
  }
18014
18849
  }
18015
18850
  if (task.comments.length > 0) {
18016
- console.log(chalk.bold(`
18851
+ console.log(chalk2.bold(`
18017
18852
  Comments (${task.comments.length}):`));
18018
18853
  for (const c of task.comments) {
18019
- const agent = c.agent_id ? chalk.cyan(`[${c.agent_id}] `) : "";
18020
- console.log(` ${agent}${chalk.dim(c.created_at)}: ${c.content}`);
18854
+ const agent = c.agent_id ? chalk2.cyan(`[${c.agent_id}] `) : "";
18855
+ console.log(` ${agent}${chalk2.dim(c.created_at)}: ${c.content}`);
18021
18856
  }
18022
18857
  }
18023
18858
  });
@@ -18031,12 +18866,12 @@ program2.command("inspect [id]").description("Full orientation for a task \u2014
18031
18866
  resolvedId = active[0].id;
18032
18867
  }
18033
18868
  if (!resolvedId) {
18034
- console.error(chalk.red("No task ID given and no active task found. Pass an ID or use --agent."));
18869
+ console.error(chalk2.red("No task ID given and no active task found. Pass an ID or use --agent."));
18035
18870
  process.exit(1);
18036
18871
  }
18037
18872
  const task = getTaskWithRelations(resolvedId);
18038
18873
  if (!task) {
18039
- console.error(chalk.red(`Task not found: ${id || resolvedId}`));
18874
+ console.error(chalk2.red(`Task not found: ${id || resolvedId}`));
18040
18875
  process.exit(1);
18041
18876
  }
18042
18877
  if (globalOpts.json) {
@@ -18056,59 +18891,59 @@ program2.command("inspect [id]").description("Full orientation for a task \u2014
18056
18891
  return;
18057
18892
  }
18058
18893
  const sid = task.short_id || task.id.slice(0, 8);
18059
- const statusColor = statusColors4[task.status] || chalk.white;
18060
- const prioColor = priorityColors2[task.priority] || chalk.white;
18061
- console.log(chalk.bold(`
18062
- ${chalk.cyan(sid)} ${statusColor(task.status)} ${prioColor(task.priority)} ${task.title}
18894
+ const statusColor = statusColors4[task.status] || chalk2.white;
18895
+ const prioColor = priorityColors2[task.priority] || chalk2.white;
18896
+ console.log(chalk2.bold(`
18897
+ ${chalk2.cyan(sid)} ${statusColor(task.status)} ${prioColor(task.priority)} ${task.title}
18063
18898
  `));
18064
18899
  if (task.description) {
18065
- console.log(chalk.dim("Description:"));
18900
+ console.log(chalk2.dim("Description:"));
18066
18901
  console.log(` ${task.description}
18067
18902
  `);
18068
18903
  }
18069
18904
  if (task.assigned_to)
18070
- console.log(` ${chalk.dim("Assigned:")} ${task.assigned_to}`);
18905
+ console.log(` ${chalk2.dim("Assigned:")} ${task.assigned_to}`);
18071
18906
  if (task.locked_by)
18072
- console.log(` ${chalk.dim("Locked by:")} ${task.locked_by}`);
18907
+ console.log(` ${chalk2.dim("Locked by:")} ${task.locked_by}`);
18073
18908
  if (task.project_id)
18074
- console.log(` ${chalk.dim("Project:")} ${task.project_id}`);
18909
+ console.log(` ${chalk2.dim("Project:")} ${task.project_id}`);
18075
18910
  if (task.plan_id)
18076
- console.log(` ${chalk.dim("Plan:")} ${task.plan_id}`);
18911
+ console.log(` ${chalk2.dim("Plan:")} ${task.plan_id}`);
18077
18912
  if (task.started_at)
18078
- console.log(` ${chalk.dim("Started:")} ${task.started_at}`);
18913
+ console.log(` ${chalk2.dim("Started:")} ${task.started_at}`);
18079
18914
  if (task.completed_at) {
18080
- console.log(` ${chalk.dim("Completed:")} ${task.completed_at}`);
18915
+ console.log(` ${chalk2.dim("Completed:")} ${task.completed_at}`);
18081
18916
  if (task.started_at) {
18082
18917
  const dur = Math.round((new Date(task.completed_at).getTime() - new Date(task.started_at).getTime()) / 60000);
18083
- console.log(` ${chalk.dim("Duration:")} ${dur}m`);
18918
+ console.log(` ${chalk2.dim("Duration:")} ${dur}m`);
18084
18919
  }
18085
18920
  }
18086
18921
  if (task.estimated_minutes)
18087
- console.log(` ${chalk.dim("Estimate:")} ${task.estimated_minutes}m`);
18922
+ console.log(` ${chalk2.dim("Estimate:")} ${task.estimated_minutes}m`);
18088
18923
  if (task.tags.length > 0)
18089
- console.log(` ${chalk.dim("Tags:")} ${task.tags.join(", ")}`);
18924
+ console.log(` ${chalk2.dim("Tags:")} ${task.tags.join(", ")}`);
18090
18925
  const unfinishedDeps = task.dependencies.filter((d) => d.status !== "completed" && d.status !== "cancelled");
18091
18926
  if (task.dependencies.length > 0) {
18092
- console.log(chalk.bold(`
18927
+ console.log(chalk2.bold(`
18093
18928
  Depends on (${task.dependencies.length}):`));
18094
18929
  for (const dep of task.dependencies) {
18095
18930
  const blocked = dep.status !== "completed" && dep.status !== "cancelled";
18096
- const icon = blocked ? chalk.red("\u2717") : chalk.green("\u2713");
18931
+ const icon = blocked ? chalk2.red("\u2717") : chalk2.green("\u2713");
18097
18932
  console.log(` ${icon} ${formatTaskLine(dep)}`);
18098
18933
  }
18099
18934
  }
18100
18935
  if (unfinishedDeps.length > 0) {
18101
- console.log(chalk.red(`
18936
+ console.log(chalk2.red(`
18102
18937
  BLOCKED by ${unfinishedDeps.length} unfinished dep(s)`));
18103
18938
  }
18104
18939
  if (task.blocked_by.length > 0) {
18105
- console.log(chalk.bold(`
18940
+ console.log(chalk2.bold(`
18106
18941
  Blocks (${task.blocked_by.length}):`));
18107
18942
  for (const b of task.blocked_by)
18108
18943
  console.log(` ${formatTaskLine(b)}`);
18109
18944
  }
18110
18945
  if (task.subtasks.length > 0) {
18111
- console.log(chalk.bold(`
18946
+ console.log(chalk2.bold(`
18112
18947
  Subtasks (${task.subtasks.length}):`));
18113
18948
  for (const st of task.subtasks)
18114
18949
  console.log(` ${formatTaskLine(st)}`);
@@ -18117,36 +18952,36 @@ ${chalk.cyan(sid)} ${statusColor(task.status)} ${prioColor(task.priority)} ${tas
18117
18952
  const { listTaskFiles: listTaskFiles2 } = (init_task_files(), __toCommonJS(exports_task_files));
18118
18953
  const files = listTaskFiles2(task.id);
18119
18954
  if (files.length > 0) {
18120
- console.log(chalk.bold(`
18955
+ console.log(chalk2.bold(`
18121
18956
  Files (${files.length}):`));
18122
18957
  for (const f of files)
18123
- console.log(` ${chalk.dim(f.role || "file")} ${f.path}`);
18958
+ console.log(` ${chalk2.dim(f.role || "file")} ${f.path}`);
18124
18959
  }
18125
18960
  } catch {}
18126
18961
  try {
18127
18962
  const { getTaskCommits: getTaskCommits2 } = (init_task_commits(), __toCommonJS(exports_task_commits));
18128
18963
  const commits = getTaskCommits2(task.id);
18129
18964
  if (commits.length > 0) {
18130
- console.log(chalk.bold(`
18965
+ console.log(chalk2.bold(`
18131
18966
  Commits (${commits.length}):`));
18132
18967
  for (const c of commits)
18133
- console.log(` ${chalk.yellow(c.commit_hash.slice(0, 7))} ${c.message || ""}`);
18968
+ console.log(` ${chalk2.yellow(c.commit_hash.slice(0, 7))} ${c.message || ""}`);
18134
18969
  }
18135
18970
  } catch {}
18136
18971
  if (task.comments.length > 0) {
18137
- console.log(chalk.bold(`
18972
+ console.log(chalk2.bold(`
18138
18973
  Comments (${task.comments.length}):`));
18139
18974
  for (const c of task.comments) {
18140
- const agent = c.agent_id ? chalk.cyan(`[${c.agent_id}] `) : "";
18141
- console.log(` ${agent}${chalk.dim(c.created_at)}: ${c.content}`);
18975
+ const agent = c.agent_id ? chalk2.cyan(`[${c.agent_id}] `) : "";
18976
+ console.log(` ${agent}${chalk2.dim(c.created_at)}: ${c.content}`);
18142
18977
  }
18143
18978
  }
18144
18979
  if (task.checklist && task.checklist.length > 0) {
18145
18980
  const done = task.checklist.filter((c) => c.checked).length;
18146
- console.log(chalk.bold(`
18981
+ console.log(chalk2.bold(`
18147
18982
  Checklist (${done}/${task.checklist.length}):`));
18148
18983
  for (const item of task.checklist) {
18149
- const icon = item.checked ? chalk.green("\u2611") : chalk.dim("\u2610");
18984
+ const icon = item.checked ? chalk2.green("\u2611") : chalk2.dim("\u2610");
18150
18985
  console.log(` ${icon} ${item.text || item.title}`);
18151
18986
  }
18152
18987
  }
@@ -18162,16 +18997,16 @@ program2.command("history <id>").description("Show change history for a task (au
18162
18997
  return;
18163
18998
  }
18164
18999
  if (history.length === 0) {
18165
- console.log(chalk.dim("No history for this task."));
19000
+ console.log(chalk2.dim("No history for this task."));
18166
19001
  return;
18167
19002
  }
18168
- console.log(chalk.bold(`${history.length} change(s):
19003
+ console.log(chalk2.bold(`${history.length} change(s):
18169
19004
  `));
18170
19005
  for (const h of history) {
18171
- const agent = h.agent_id ? chalk.cyan(` by ${h.agent_id}`) : "";
18172
- const field = h.field ? chalk.yellow(` ${h.field}`) : "";
18173
- const change = h.old_value && h.new_value ? ` ${chalk.red(h.old_value)} \u2192 ${chalk.green(h.new_value)}` : h.new_value ? ` \u2192 ${chalk.green(h.new_value)}` : "";
18174
- console.log(` ${chalk.dim(h.created_at)} ${chalk.bold(h.action)}${field}${change}${agent}`);
19006
+ const agent = h.agent_id ? chalk2.cyan(` by ${h.agent_id}`) : "";
19007
+ const field = h.field ? chalk2.yellow(` ${h.field}`) : "";
19008
+ const change = h.old_value && h.new_value ? ` ${chalk2.red(h.old_value)} \u2192 ${chalk2.green(h.new_value)}` : h.new_value ? ` \u2192 ${chalk2.green(h.new_value)}` : "";
19009
+ console.log(` ${chalk2.dim(h.created_at)} ${chalk2.bold(h.action)}${field}${change}${agent}`);
18175
19010
  }
18176
19011
  });
18177
19012
  program2.command("update <id>").description("Update a task").option("--title <text>", "New title").option("-d, --description <text>", "New description").option("-s, --status <status>", "New status").option("-p, --priority <priority>", "New priority").option("--assign <agent>", "Assign to agent").option("--tags <tags>", "New tags (comma-separated)").option("--tag <tags>", "New tags (alias for --tags)").option("--list <id>", "Move to a task list").option("--task-list <id>", "Move to a task list (alias for --list)").option("--estimated <minutes>", "Estimated time in minutes").option("--approval", "Require approval before completion").action((id, opts) => {
@@ -18181,14 +19016,14 @@ program2.command("update <id>").description("Update a task").option("--title <te
18181
19016
  const resolvedId = resolveTaskId(id);
18182
19017
  const current = getTask(resolvedId);
18183
19018
  if (!current) {
18184
- console.error(chalk.red(`Task not found: ${id}`));
19019
+ console.error(chalk2.red(`Task not found: ${id}`));
18185
19020
  process.exit(1);
18186
19021
  }
18187
19022
  const taskListId = opts.list ? (() => {
18188
19023
  const db = getDatabase();
18189
19024
  const resolved = resolvePartialId(db, "task_lists", opts.list);
18190
19025
  if (!resolved) {
18191
- console.error(chalk.red(`Could not resolve task list ID: ${opts.list}`));
19026
+ console.error(chalk2.red(`Could not resolve task list ID: ${opts.list}`));
18192
19027
  process.exit(1);
18193
19028
  }
18194
19029
  return resolved;
@@ -18213,7 +19048,7 @@ program2.command("update <id>").description("Update a task").option("--title <te
18213
19048
  if (globalOpts.json) {
18214
19049
  output(task, true);
18215
19050
  } else {
18216
- console.log(chalk.green("Task updated:"));
19051
+ console.log(chalk2.green("Task updated:"));
18217
19052
  console.log(formatTaskLine(task));
18218
19053
  }
18219
19054
  });
@@ -18233,7 +19068,7 @@ program2.command("done <id>").description("Mark a task as completed").option("--
18233
19068
  if (globalOpts.json) {
18234
19069
  output(task, true);
18235
19070
  } else {
18236
- console.log(chalk.green("Task completed:"));
19071
+ console.log(chalk2.green("Task completed:"));
18237
19072
  console.log(formatTaskLine(task));
18238
19073
  }
18239
19074
  });
@@ -18242,15 +19077,15 @@ program2.command("approve <id>").description("Approve a task that requires appro
18242
19077
  const resolvedId = resolveTaskId(id);
18243
19078
  const task = getTask(resolvedId);
18244
19079
  if (!task) {
18245
- console.error(chalk.red(`Task not found: ${id}`));
19080
+ console.error(chalk2.red(`Task not found: ${id}`));
18246
19081
  process.exit(1);
18247
19082
  }
18248
19083
  if (!task.requires_approval) {
18249
- console.log(chalk.yellow("This task does not require approval."));
19084
+ console.log(chalk2.yellow("This task does not require approval."));
18250
19085
  return;
18251
19086
  }
18252
19087
  if (task.approved_by) {
18253
- console.log(chalk.yellow(`Already approved by ${task.approved_by}.`));
19088
+ console.log(chalk2.yellow(`Already approved by ${task.approved_by}.`));
18254
19089
  return;
18255
19090
  }
18256
19091
  try {
@@ -18258,7 +19093,7 @@ program2.command("approve <id>").description("Approve a task that requires appro
18258
19093
  if (globalOpts.json) {
18259
19094
  output(updated, true);
18260
19095
  } else {
18261
- console.log(chalk.green(`Task approved by ${globalOpts.agent || "cli"}:`));
19096
+ console.log(chalk2.green(`Task approved by ${globalOpts.agent || "cli"}:`));
18262
19097
  console.log(formatTaskLine(updated));
18263
19098
  }
18264
19099
  } catch (e) {
@@ -18278,7 +19113,7 @@ program2.command("start <id>").description("Claim, lock, and start a task").acti
18278
19113
  if (globalOpts.json) {
18279
19114
  output(task, true);
18280
19115
  } else {
18281
- console.log(chalk.green(`Task started by ${agentId}:`));
19116
+ console.log(chalk2.green(`Task started by ${agentId}:`));
18282
19117
  console.log(formatTaskLine(task));
18283
19118
  }
18284
19119
  });
@@ -18295,9 +19130,9 @@ program2.command("lock <id>").description("Acquire exclusive lock on a task").ac
18295
19130
  if (globalOpts.json) {
18296
19131
  output(result, true);
18297
19132
  } else if (result.success) {
18298
- console.log(chalk.green(`Lock acquired by ${agentId}`));
19133
+ console.log(chalk2.green(`Lock acquired by ${agentId}`));
18299
19134
  } else {
18300
- console.error(chalk.red(`Lock failed: ${result.error}`));
19135
+ console.error(chalk2.red(`Lock failed: ${result.error}`));
18301
19136
  process.exit(1);
18302
19137
  }
18303
19138
  });
@@ -18312,7 +19147,7 @@ program2.command("unlock <id>").description("Release lock on a task").action((id
18312
19147
  if (globalOpts.json) {
18313
19148
  output({ success: true }, true);
18314
19149
  } else {
18315
- console.log(chalk.green("Lock released."));
19150
+ console.log(chalk2.green("Lock released."));
18316
19151
  }
18317
19152
  });
18318
19153
  program2.command("delete <id>").description("Delete a task").action((id) => {
@@ -18322,9 +19157,9 @@ program2.command("delete <id>").description("Delete a task").action((id) => {
18322
19157
  if (globalOpts.json) {
18323
19158
  output({ deleted }, true);
18324
19159
  } else if (deleted) {
18325
- console.log(chalk.green("Task deleted."));
19160
+ console.log(chalk2.green("Task deleted."));
18326
19161
  } else {
18327
- console.error(chalk.red("Task not found."));
19162
+ console.error(chalk2.red("Task not found."));
18328
19163
  process.exit(1);
18329
19164
  }
18330
19165
  });
@@ -18335,9 +19170,9 @@ program2.command("remove <id>").description("Remove/delete a task (alias for del
18335
19170
  if (globalOpts.json) {
18336
19171
  output({ deleted }, true);
18337
19172
  } else if (deleted) {
18338
- console.log(chalk.green("Task removed."));
19173
+ console.log(chalk2.green("Task removed."));
18339
19174
  } else {
18340
- console.error(chalk.red("Task not found."));
19175
+ console.error(chalk2.red("Task not found."));
18341
19176
  process.exit(1);
18342
19177
  }
18343
19178
  });
@@ -18357,7 +19192,7 @@ program2.command("bulk <action> <ids...>").description("Bulk operation on multip
18357
19192
  deleteTask(resolvedId);
18358
19193
  results.push({ id: resolvedId, success: true });
18359
19194
  } else {
18360
- console.error(chalk.red(`Unknown action: ${action}. Use: done, start, delete`));
19195
+ console.error(chalk2.red(`Unknown action: ${action}. Use: done, start, delete`));
18361
19196
  process.exit(1);
18362
19197
  }
18363
19198
  } catch (e) {
@@ -18369,9 +19204,9 @@ program2.command("bulk <action> <ids...>").description("Bulk operation on multip
18369
19204
  if (globalOpts.json) {
18370
19205
  output({ results, succeeded, failed }, true);
18371
19206
  } else {
18372
- console.log(chalk.green(`${action}: ${succeeded} succeeded, ${failed} failed`));
19207
+ console.log(chalk2.green(`${action}: ${succeeded} succeeded, ${failed} failed`));
18373
19208
  for (const r of results.filter((r2) => !r2.success)) {
18374
- console.log(chalk.red(` ${r.id}: ${r.error}`));
19209
+ console.log(chalk2.red(` ${r.id}: ${r.error}`));
18375
19210
  }
18376
19211
  }
18377
19212
  });
@@ -18387,8 +19222,8 @@ program2.command("plans").description("List and manage plans").option("--add <na
18387
19222
  if (globalOpts.json) {
18388
19223
  output(plan, true);
18389
19224
  } else {
18390
- console.log(chalk.green("Plan created:"));
18391
- console.log(`${chalk.dim(plan.id.slice(0, 8))} ${chalk.bold(plan.name)} ${chalk.cyan(`[${plan.status}]`)}`);
19225
+ console.log(chalk2.green("Plan created:"));
19226
+ console.log(`${chalk2.dim(plan.id.slice(0, 8))} ${chalk2.bold(plan.name)} ${chalk2.cyan(`[${plan.status}]`)}`);
18392
19227
  }
18393
19228
  return;
18394
19229
  }
@@ -18396,12 +19231,12 @@ program2.command("plans").description("List and manage plans").option("--add <na
18396
19231
  const db = getDatabase();
18397
19232
  const resolvedId = resolvePartialId(db, "plans", opts.show);
18398
19233
  if (!resolvedId) {
18399
- console.error(chalk.red(`Could not resolve plan ID: ${opts.show}`));
19234
+ console.error(chalk2.red(`Could not resolve plan ID: ${opts.show}`));
18400
19235
  process.exit(1);
18401
19236
  }
18402
19237
  const plan = getPlan(resolvedId);
18403
19238
  if (!plan) {
18404
- console.error(chalk.red(`Plan not found: ${opts.show}`));
19239
+ console.error(chalk2.red(`Plan not found: ${opts.show}`));
18405
19240
  process.exit(1);
18406
19241
  }
18407
19242
  const tasks = listTasks({ plan_id: resolvedId });
@@ -18409,24 +19244,24 @@ program2.command("plans").description("List and manage plans").option("--add <na
18409
19244
  output({ plan, tasks }, true);
18410
19245
  return;
18411
19246
  }
18412
- console.log(chalk.bold(`Plan Details:
19247
+ console.log(chalk2.bold(`Plan Details:
18413
19248
  `));
18414
- console.log(` ${chalk.dim("ID:")} ${plan.id}`);
18415
- console.log(` ${chalk.dim("Name:")} ${plan.name}`);
18416
- console.log(` ${chalk.dim("Status:")} ${chalk.cyan(plan.status)}`);
19249
+ console.log(` ${chalk2.dim("ID:")} ${plan.id}`);
19250
+ console.log(` ${chalk2.dim("Name:")} ${plan.name}`);
19251
+ console.log(` ${chalk2.dim("Status:")} ${chalk2.cyan(plan.status)}`);
18417
19252
  if (plan.description)
18418
- console.log(` ${chalk.dim("Desc:")} ${plan.description}`);
19253
+ console.log(` ${chalk2.dim("Desc:")} ${plan.description}`);
18419
19254
  if (plan.project_id)
18420
- console.log(` ${chalk.dim("Project:")} ${plan.project_id}`);
18421
- console.log(` ${chalk.dim("Created:")} ${plan.created_at}`);
19255
+ console.log(` ${chalk2.dim("Project:")} ${plan.project_id}`);
19256
+ console.log(` ${chalk2.dim("Created:")} ${plan.created_at}`);
18422
19257
  if (tasks.length > 0) {
18423
- console.log(chalk.bold(`
19258
+ console.log(chalk2.bold(`
18424
19259
  Tasks (${tasks.length}):`));
18425
19260
  for (const t of tasks) {
18426
19261
  console.log(` ${formatTaskLine(t)}`);
18427
19262
  }
18428
19263
  } else {
18429
- console.log(chalk.dim(`
19264
+ console.log(chalk2.dim(`
18430
19265
  No tasks in this plan.`));
18431
19266
  }
18432
19267
  return;
@@ -18435,16 +19270,16 @@ program2.command("plans").description("List and manage plans").option("--add <na
18435
19270
  const db = getDatabase();
18436
19271
  const resolvedId = resolvePartialId(db, "plans", opts.delete);
18437
19272
  if (!resolvedId) {
18438
- console.error(chalk.red(`Could not resolve plan ID: ${opts.delete}`));
19273
+ console.error(chalk2.red(`Could not resolve plan ID: ${opts.delete}`));
18439
19274
  process.exit(1);
18440
19275
  }
18441
19276
  const deleted = deletePlan(resolvedId);
18442
19277
  if (globalOpts.json) {
18443
19278
  output({ deleted }, true);
18444
19279
  } else if (deleted) {
18445
- console.log(chalk.green("Plan deleted."));
19280
+ console.log(chalk2.green("Plan deleted."));
18446
19281
  } else {
18447
- console.error(chalk.red("Plan not found."));
19282
+ console.error(chalk2.red("Plan not found."));
18448
19283
  process.exit(1);
18449
19284
  }
18450
19285
  return;
@@ -18453,7 +19288,7 @@ program2.command("plans").description("List and manage plans").option("--add <na
18453
19288
  const db = getDatabase();
18454
19289
  const resolvedId = resolvePartialId(db, "plans", opts.complete);
18455
19290
  if (!resolvedId) {
18456
- console.error(chalk.red(`Could not resolve plan ID: ${opts.complete}`));
19291
+ console.error(chalk2.red(`Could not resolve plan ID: ${opts.complete}`));
18457
19292
  process.exit(1);
18458
19293
  }
18459
19294
  try {
@@ -18461,8 +19296,8 @@ program2.command("plans").description("List and manage plans").option("--add <na
18461
19296
  if (globalOpts.json) {
18462
19297
  output(plan, true);
18463
19298
  } else {
18464
- console.log(chalk.green("Plan completed:"));
18465
- console.log(`${chalk.dim(plan.id.slice(0, 8))} ${chalk.bold(plan.name)} ${chalk.cyan(`[${plan.status}]`)}`);
19299
+ console.log(chalk2.green("Plan completed:"));
19300
+ console.log(`${chalk2.dim(plan.id.slice(0, 8))} ${chalk2.bold(plan.name)} ${chalk2.cyan(`[${plan.status}]`)}`);
18466
19301
  }
18467
19302
  } catch (e) {
18468
19303
  handleError(e);
@@ -18475,14 +19310,14 @@ program2.command("plans").description("List and manage plans").option("--add <na
18475
19310
  return;
18476
19311
  }
18477
19312
  if (plans.length === 0) {
18478
- console.log(chalk.dim("No plans found."));
19313
+ console.log(chalk2.dim("No plans found."));
18479
19314
  return;
18480
19315
  }
18481
- console.log(chalk.bold(`${plans.length} plan(s):
19316
+ console.log(chalk2.bold(`${plans.length} plan(s):
18482
19317
  `));
18483
19318
  for (const p of plans) {
18484
- const desc = p.description ? chalk.dim(` - ${p.description}`) : "";
18485
- console.log(`${chalk.dim(p.id.slice(0, 8))} ${chalk.bold(p.name)} ${chalk.cyan(`[${p.status}]`)}${desc}`);
19319
+ const desc = p.description ? chalk2.dim(` - ${p.description}`) : "";
19320
+ console.log(`${chalk2.dim(p.id.slice(0, 8))} ${chalk2.bold(p.name)} ${chalk2.cyan(`[${p.status}]`)}${desc}`);
18486
19321
  }
18487
19322
  });
18488
19323
  program2.command("templates").description("List and manage task templates").option("--add <name>", "Create a template").option("--title <pattern>", "Title pattern (with --add)").option("-d, --description <text>", "Default description").option("-p, --priority <level>", "Default priority").option("-t, --tags <tags>", "Default tags (comma-separated)").option("--delete <id>", "Delete a template").option("--use <id>", "Create a task from a template").action((opts) => {
@@ -18490,7 +19325,7 @@ program2.command("templates").description("List and manage task templates").opti
18490
19325
  const { createTemplate: createTemplate2, listTemplates: listTemplates2, deleteTemplate: deleteTemplate2, taskFromTemplate: taskFromTemplate2 } = (init_templates(), __toCommonJS(exports_templates));
18491
19326
  if (opts.add) {
18492
19327
  if (!opts.title) {
18493
- console.error(chalk.red("--title is required with --add"));
19328
+ console.error(chalk2.red("--title is required with --add"));
18494
19329
  process.exit(1);
18495
19330
  }
18496
19331
  const projectId = autoProject(globalOpts);
@@ -18505,7 +19340,7 @@ program2.command("templates").description("List and manage task templates").opti
18505
19340
  if (globalOpts.json) {
18506
19341
  output(template, true);
18507
19342
  } else {
18508
- console.log(chalk.green(`Template created: ${template.id.slice(0, 8)} | ${template.name} | "${template.title_pattern}"`));
19343
+ console.log(chalk2.green(`Template created: ${template.id.slice(0, 8)} | ${template.name} | "${template.title_pattern}"`));
18509
19344
  }
18510
19345
  return;
18511
19346
  }
@@ -18514,9 +19349,9 @@ program2.command("templates").description("List and manage task templates").opti
18514
19349
  if (globalOpts.json) {
18515
19350
  output({ deleted }, true);
18516
19351
  } else if (deleted) {
18517
- console.log(chalk.green("Template deleted."));
19352
+ console.log(chalk2.green("Template deleted."));
18518
19353
  } else {
18519
- console.error(chalk.red("Template not found."));
19354
+ console.error(chalk2.red("Template not found."));
18520
19355
  process.exit(1);
18521
19356
  }
18522
19357
  return;
@@ -18532,7 +19367,7 @@ program2.command("templates").description("List and manage task templates").opti
18532
19367
  if (globalOpts.json) {
18533
19368
  output(task, true);
18534
19369
  } else {
18535
- console.log(chalk.green("Task created from template:"));
19370
+ console.log(chalk2.green("Task created from template:"));
18536
19371
  console.log(formatTaskLine(task));
18537
19372
  }
18538
19373
  } catch (e) {
@@ -18546,13 +19381,13 @@ program2.command("templates").description("List and manage task templates").opti
18546
19381
  return;
18547
19382
  }
18548
19383
  if (templates.length === 0) {
18549
- console.log(chalk.dim("No templates."));
19384
+ console.log(chalk2.dim("No templates."));
18550
19385
  return;
18551
19386
  }
18552
- console.log(chalk.bold(`${templates.length} template(s):
19387
+ console.log(chalk2.bold(`${templates.length} template(s):
18553
19388
  `));
18554
19389
  for (const t of templates) {
18555
- console.log(` ${chalk.dim(t.id.slice(0, 8))} ${chalk.bold(t.name)} ${chalk.cyan(`"${t.title_pattern}"`)} ${chalk.yellow(t.priority)}`);
19390
+ console.log(` ${chalk2.dim(t.id.slice(0, 8))} ${chalk2.bold(t.name)} ${chalk2.cyan(`"${t.title_pattern}"`)} ${chalk2.yellow(t.priority)}`);
18556
19391
  }
18557
19392
  });
18558
19393
  program2.command("comment <id> <text>").description("Add a comment to a task").action((id, text) => {
@@ -18567,7 +19402,7 @@ program2.command("comment <id> <text>").description("Add a comment to a task").a
18567
19402
  if (globalOpts.json) {
18568
19403
  output(comment, true);
18569
19404
  } else {
18570
- console.log(chalk.green("Comment added."));
19405
+ console.log(chalk2.green("Comment added."));
18571
19406
  }
18572
19407
  });
18573
19408
  program2.command("search <query>").description("Search tasks").option("--status <status>", "Filter by status").option("--priority <p>", "Filter by priority").option("--assigned <agent>", "Filter by assigned agent").option("--since <date>", "Only tasks updated after this date (ISO)").option("--blocked", "Only blocked tasks (incomplete dependencies)").option("--has-deps", "Only tasks with dependencies").action((query, opts) => {
@@ -18592,10 +19427,10 @@ program2.command("search <query>").description("Search tasks").option("--status
18592
19427
  return;
18593
19428
  }
18594
19429
  if (tasks.length === 0) {
18595
- console.log(chalk.dim(`No tasks matching "${query}".`));
19430
+ console.log(chalk2.dim(`No tasks matching "${query}".`));
18596
19431
  return;
18597
19432
  }
18598
- console.log(chalk.bold(`${tasks.length} result(s) for "${query}":
19433
+ console.log(chalk2.bold(`${tasks.length} result(s) for "${query}":
18599
19434
  `));
18600
19435
  for (const t of tasks) {
18601
19436
  console.log(formatTaskLine(t));
@@ -18609,13 +19444,13 @@ program2.command("deps <id>").description("Manage task dependencies").option("--
18609
19444
  try {
18610
19445
  addDependency(resolvedId, depId);
18611
19446
  } catch (e) {
18612
- console.error(chalk.red(e instanceof Error ? e.message : String(e)));
19447
+ console.error(chalk2.red(e instanceof Error ? e.message : String(e)));
18613
19448
  process.exit(1);
18614
19449
  }
18615
19450
  if (globalOpts.json) {
18616
19451
  output({ task_id: resolvedId, depends_on: depId }, true);
18617
19452
  } else {
18618
- console.log(chalk.green("Dependency added."));
19453
+ console.log(chalk2.green("Dependency added."));
18619
19454
  }
18620
19455
  } else if (opts.remove) {
18621
19456
  const depId = resolveTaskId(opts.remove);
@@ -18623,12 +19458,12 @@ program2.command("deps <id>").description("Manage task dependencies").option("--
18623
19458
  if (globalOpts.json) {
18624
19459
  output({ removed }, true);
18625
19460
  } else {
18626
- console.log(removed ? chalk.green("Dependency removed.") : chalk.red("Dependency not found."));
19461
+ console.log(removed ? chalk2.green("Dependency removed.") : chalk2.red("Dependency not found."));
18627
19462
  }
18628
19463
  } else {
18629
19464
  const task = getTaskWithRelations(resolvedId);
18630
19465
  if (!task) {
18631
- console.error(chalk.red("Task not found."));
19466
+ console.error(chalk2.red("Task not found."));
18632
19467
  process.exit(1);
18633
19468
  }
18634
19469
  if (globalOpts.json) {
@@ -18636,19 +19471,19 @@ program2.command("deps <id>").description("Manage task dependencies").option("--
18636
19471
  return;
18637
19472
  }
18638
19473
  if (task.dependencies.length > 0) {
18639
- console.log(chalk.bold("Depends on:"));
19474
+ console.log(chalk2.bold("Depends on:"));
18640
19475
  for (const dep of task.dependencies) {
18641
19476
  console.log(` ${formatTaskLine(dep)}`);
18642
19477
  }
18643
19478
  }
18644
19479
  if (task.blocked_by.length > 0) {
18645
- console.log(chalk.bold("Blocks:"));
19480
+ console.log(chalk2.bold("Blocks:"));
18646
19481
  for (const b of task.blocked_by) {
18647
19482
  console.log(` ${formatTaskLine(b)}`);
18648
19483
  }
18649
19484
  }
18650
19485
  if (task.dependencies.length === 0 && task.blocked_by.length === 0) {
18651
- console.log(chalk.dim("No dependencies."));
19486
+ console.log(chalk2.dim("No dependencies."));
18652
19487
  }
18653
19488
  }
18654
19489
  });
@@ -18670,9 +19505,9 @@ program2.command("projects").description("List and manage projects").option("--a
18670
19505
  if (globalOpts.json) {
18671
19506
  output(project, true);
18672
19507
  } else {
18673
- console.log(chalk.green(`Project registered: ${project.name} (${project.path})`));
19508
+ console.log(chalk2.green(`Project registered: ${project.name} (${project.path})`));
18674
19509
  if (project.task_list_id)
18675
- console.log(chalk.dim(` Task list: ${project.task_list_id}`));
19510
+ console.log(chalk2.dim(` Task list: ${project.task_list_id}`));
18676
19511
  }
18677
19512
  return;
18678
19513
  }
@@ -18682,14 +19517,14 @@ program2.command("projects").description("List and manage projects").option("--a
18682
19517
  return;
18683
19518
  }
18684
19519
  if (projects.length === 0) {
18685
- console.log(chalk.dim("No projects registered."));
19520
+ console.log(chalk2.dim("No projects registered."));
18686
19521
  return;
18687
19522
  }
18688
- console.log(chalk.bold(`${projects.length} project(s):
19523
+ console.log(chalk2.bold(`${projects.length} project(s):
18689
19524
  `));
18690
19525
  for (const p of projects) {
18691
- const taskList = p.task_list_id ? chalk.cyan(` [${p.task_list_id}]`) : "";
18692
- console.log(`${chalk.dim(p.id.slice(0, 8))} ${chalk.bold(p.name)} ${chalk.dim(p.path)}${taskList}${p.description ? ` - ${p.description}` : ""}`);
19526
+ const taskList = p.task_list_id ? chalk2.cyan(` [${p.task_list_id}]`) : "";
19527
+ console.log(`${chalk2.dim(p.id.slice(0, 8))} ${chalk2.bold(p.name)} ${chalk2.dim(p.path)}${taskList}${p.description ? ` - ${p.description}` : ""}`);
18693
19528
  }
18694
19529
  });
18695
19530
  program2.command("extract <path>").description("Extract TODO/FIXME/HACK/BUG/XXX/NOTE comments from source files and create tasks").option("--dry-run", "Show extracted comments without creating tasks").option("--pattern <tags>", "Comma-separated tags to look for (default: TODO,FIXME,HACK,XXX,BUG,NOTE)").option("-t, --tags <tags>", "Extra comma-separated tags to add to created tasks").option("--assign <agent>", "Assign extracted tasks to an agent").option("--list <id>", "Task list ID").option("--ext <extensions>", "Comma-separated file extensions to scan (e.g. ts,py,go)").action((scanPath, opts) => {
@@ -18702,7 +19537,7 @@ program2.command("extract <path>").description("Extract TODO/FIXME/HACK/BUG/XXX/
18702
19537
  const db = getDatabase();
18703
19538
  const id = resolvePartialId(db, "task_lists", opts.list);
18704
19539
  if (!id) {
18705
- console.error(chalk.red(`Could not resolve task list ID: ${opts.list}`));
19540
+ console.error(chalk2.red(`Could not resolve task list ID: ${opts.list}`));
18706
19541
  process.exit(1);
18707
19542
  }
18708
19543
  return id;
@@ -18721,18 +19556,18 @@ program2.command("extract <path>").description("Extract TODO/FIXME/HACK/BUG/XXX/
18721
19556
  if (globalOpts.json) {
18722
19557
  console.log(JSON.stringify(opts.dryRun ? { comments: result.comments } : { tasks_created: result.tasks.length, skipped: result.skipped, comments: result.comments.length }, null, 2));
18723
19558
  } else if (opts.dryRun) {
18724
- console.log(chalk.cyan(`Found ${result.comments.length} comment(s):
19559
+ console.log(chalk2.cyan(`Found ${result.comments.length} comment(s):
18725
19560
  `));
18726
19561
  for (const c of result.comments) {
18727
- console.log(` ${chalk.yellow(`[${c.tag}]`)} ${c.message}`);
18728
- console.log(` ${chalk.gray(`${c.file}:${c.line}`)}`);
19562
+ console.log(` ${chalk2.yellow(`[${c.tag}]`)} ${c.message}`);
19563
+ console.log(` ${chalk2.gray(`${c.file}:${c.line}`)}`);
18729
19564
  }
18730
19565
  } else {
18731
- console.log(chalk.green(`Created ${result.tasks.length} task(s)`));
19566
+ console.log(chalk2.green(`Created ${result.tasks.length} task(s)`));
18732
19567
  if (result.skipped > 0) {
18733
- console.log(chalk.gray(`Skipped ${result.skipped} duplicate(s)`));
19568
+ console.log(chalk2.gray(`Skipped ${result.skipped} duplicate(s)`));
18734
19569
  }
18735
- console.log(chalk.gray(`Total comments found: ${result.comments.length}`));
19570
+ console.log(chalk2.gray(`Total comments found: ${result.comments.length}`));
18736
19571
  for (const t of result.tasks) {
18737
19572
  console.log(formatTaskLine(t));
18738
19573
  }
@@ -18782,7 +19617,7 @@ program2.command("sync").description("Sync tasks with an agent task list (Claude
18782
19617
  const agent = opts.agent || "claude";
18783
19618
  const taskListId = resolveTaskListId2(agent, opts.taskList, project?.task_list_id);
18784
19619
  if (!taskListId) {
18785
- console.error(chalk.red(`Could not detect task list ID for ${agent}. Use --task-list <id> or set appropriate env vars.`));
19620
+ console.error(chalk2.red(`Could not detect task list ID for ${agent}. Use --task-list <id> or set appropriate env vars.`));
18786
19621
  process.exit(1);
18787
19622
  }
18788
19623
  result = syncWithAgent(agent, taskListId, projectId, direction, { prefer });
@@ -18792,14 +19627,14 @@ program2.command("sync").description("Sync tasks with an agent task list (Claude
18792
19627
  return;
18793
19628
  }
18794
19629
  if (result.pulled > 0)
18795
- console.log(chalk.green(`Pulled ${result.pulled} task(s).`));
19630
+ console.log(chalk2.green(`Pulled ${result.pulled} task(s).`));
18796
19631
  if (result.pushed > 0)
18797
- console.log(chalk.green(`Pushed ${result.pushed} task(s).`));
19632
+ console.log(chalk2.green(`Pushed ${result.pushed} task(s).`));
18798
19633
  if (result.pulled === 0 && result.pushed === 0 && result.errors.length === 0) {
18799
- console.log(chalk.dim("Nothing to sync."));
19634
+ console.log(chalk2.dim("Nothing to sync."));
18800
19635
  }
18801
19636
  for (const err of result.errors) {
18802
- console.error(chalk.red(` Error: ${err}`));
19637
+ console.error(chalk2.red(` Error: ${err}`));
18803
19638
  }
18804
19639
  });
18805
19640
  var hooks = program2.command("hooks").description("Manage Claude Code hook integration");
@@ -18810,9 +19645,9 @@ hooks.command("install").description("Install Claude Code hooks for auto-sync").
18810
19645
  if (p)
18811
19646
  todosBin = p;
18812
19647
  } catch {}
18813
- const hooksDir = join9(process.cwd(), ".claude", "hooks");
18814
- if (!existsSync7(hooksDir))
18815
- mkdirSync3(hooksDir, { recursive: true });
19648
+ const hooksDir = join11(process.cwd(), ".claude", "hooks");
19649
+ if (!existsSync9(hooksDir))
19650
+ mkdirSync5(hooksDir, { recursive: true });
18816
19651
  const hookScript = `#!/usr/bin/env bash
18817
19652
  # Auto-generated by: todos hooks install
18818
19653
  # Syncs todos with Claude Code task list on tool use events.
@@ -18836,11 +19671,11 @@ esac
18836
19671
 
18837
19672
  exit 0
18838
19673
  `;
18839
- const hookPath = join9(hooksDir, "todos-sync.sh");
18840
- writeFileSync3(hookPath, hookScript);
19674
+ const hookPath = join11(hooksDir, "todos-sync.sh");
19675
+ writeFileSync5(hookPath, hookScript);
18841
19676
  execSync2(`chmod +x "${hookPath}"`);
18842
- console.log(chalk.green(`Hook script created: ${hookPath}`));
18843
- const settingsPath = join9(process.cwd(), ".claude", "settings.json");
19677
+ console.log(chalk2.green(`Hook script created: ${hookPath}`));
19678
+ const settingsPath = join11(process.cwd(), ".claude", "settings.json");
18844
19679
  const settings = readJsonFile2(settingsPath);
18845
19680
  if (!settings["hooks"]) {
18846
19681
  settings["hooks"] = {};
@@ -18866,8 +19701,8 @@ exit 0
18866
19701
  });
18867
19702
  hooksConfig["PostToolUse"] = filtered;
18868
19703
  writeJsonFile2(settingsPath, settings);
18869
- console.log(chalk.green(`Claude Code hooks configured in: ${settingsPath}`));
18870
- console.log(chalk.dim("Task list ID auto-detected from project."));
19704
+ console.log(chalk2.green(`Claude Code hooks configured in: ${settingsPath}`));
19705
+ console.log(chalk2.dim("Task list ID auto-detected from project."));
18871
19706
  });
18872
19707
  program2.command("mcp").description("Start MCP server (stdio)").option("--register <agent>", "Register MCP server with an agent (claude, codex, gemini, all)").option("--unregister <agent>", "Unregister MCP server from an agent (claude, codex, gemini, all)").option("-g, --global", "Register/unregister globally (user-level) instead of project-level").action(async (opts) => {
18873
19708
  if (opts.register) {
@@ -18887,37 +19722,37 @@ function getMcpBinaryPath() {
18887
19722
  if (p)
18888
19723
  return p;
18889
19724
  } catch {}
18890
- const bunBin = join9(HOME2, ".bun", "bin", "todos-mcp");
18891
- if (existsSync7(bunBin))
19725
+ const bunBin = join11(HOME2, ".bun", "bin", "todos-mcp");
19726
+ if (existsSync9(bunBin))
18892
19727
  return bunBin;
18893
19728
  return "todos-mcp";
18894
19729
  }
18895
19730
  function readJsonFile2(path) {
18896
- if (!existsSync7(path))
19731
+ if (!existsSync9(path))
18897
19732
  return {};
18898
19733
  try {
18899
- return JSON.parse(readFileSync5(path, "utf-8"));
19734
+ return JSON.parse(readFileSync6(path, "utf-8"));
18900
19735
  } catch {
18901
19736
  return {};
18902
19737
  }
18903
19738
  }
18904
19739
  function writeJsonFile2(path, data) {
18905
19740
  const dir = dirname4(path);
18906
- if (!existsSync7(dir))
18907
- mkdirSync3(dir, { recursive: true });
18908
- writeFileSync3(path, JSON.stringify(data, null, 2) + `
19741
+ if (!existsSync9(dir))
19742
+ mkdirSync5(dir, { recursive: true });
19743
+ writeFileSync5(path, JSON.stringify(data, null, 2) + `
18909
19744
  `);
18910
19745
  }
18911
19746
  function readTomlFile(path) {
18912
- if (!existsSync7(path))
19747
+ if (!existsSync9(path))
18913
19748
  return "";
18914
- return readFileSync5(path, "utf-8");
19749
+ return readFileSync6(path, "utf-8");
18915
19750
  }
18916
19751
  function writeTomlFile(path, content) {
18917
19752
  const dir = dirname4(path);
18918
- if (!existsSync7(dir))
18919
- mkdirSync3(dir, { recursive: true });
18920
- writeFileSync3(path, content);
19753
+ if (!existsSync9(dir))
19754
+ mkdirSync5(dir, { recursive: true });
19755
+ writeFileSync5(path, content);
18921
19756
  }
18922
19757
  function registerClaude(binPath, global) {
18923
19758
  const scope = global ? "user" : "project";
@@ -18925,24 +19760,24 @@ function registerClaude(binPath, global) {
18925
19760
  try {
18926
19761
  const { execSync: execSync3 } = __require("child_process");
18927
19762
  execSync3(cmd, { stdio: "pipe" });
18928
- console.log(chalk.green(`Claude Code (${scope}): registered via 'claude mcp add'`));
19763
+ console.log(chalk2.green(`Claude Code (${scope}): registered via 'claude mcp add'`));
18929
19764
  } catch {
18930
- console.log(chalk.yellow(`Claude Code: could not auto-register. Run this command manually:`));
18931
- console.log(chalk.cyan(` ${cmd}`));
19765
+ console.log(chalk2.yellow(`Claude Code: could not auto-register. Run this command manually:`));
19766
+ console.log(chalk2.cyan(` ${cmd}`));
18932
19767
  }
18933
19768
  }
18934
19769
  function unregisterClaude(_global) {
18935
19770
  try {
18936
19771
  const { execSync: execSync3 } = __require("child_process");
18937
19772
  execSync3("claude mcp remove todos", { stdio: "pipe" });
18938
- console.log(chalk.green(`Claude Code: removed todos MCP server`));
19773
+ console.log(chalk2.green(`Claude Code: removed todos MCP server`));
18939
19774
  } catch {
18940
- console.log(chalk.yellow(`Claude Code: could not auto-remove. Run manually:`));
18941
- console.log(chalk.cyan(" claude mcp remove todos"));
19775
+ console.log(chalk2.yellow(`Claude Code: could not auto-remove. Run manually:`));
19776
+ console.log(chalk2.cyan(" claude mcp remove todos"));
18942
19777
  }
18943
19778
  }
18944
19779
  function registerCodex(binPath) {
18945
- const configPath = join9(HOME2, ".codex", "config.toml");
19780
+ const configPath = join11(HOME2, ".codex", "config.toml");
18946
19781
  let content = readTomlFile(configPath);
18947
19782
  content = removeTomlBlock(content, "mcp_servers.todos");
18948
19783
  const block = `
@@ -18953,19 +19788,19 @@ args = []
18953
19788
  content = content.trimEnd() + `
18954
19789
  ` + block;
18955
19790
  writeTomlFile(configPath, content);
18956
- console.log(chalk.green(`Codex CLI: registered in ${configPath}`));
19791
+ console.log(chalk2.green(`Codex CLI: registered in ${configPath}`));
18957
19792
  }
18958
19793
  function unregisterCodex() {
18959
- const configPath = join9(HOME2, ".codex", "config.toml");
19794
+ const configPath = join11(HOME2, ".codex", "config.toml");
18960
19795
  let content = readTomlFile(configPath);
18961
19796
  if (!content.includes("[mcp_servers.todos]")) {
18962
- console.log(chalk.dim(`Codex CLI: todos not found in ${configPath}`));
19797
+ console.log(chalk2.dim(`Codex CLI: todos not found in ${configPath}`));
18963
19798
  return;
18964
19799
  }
18965
19800
  content = removeTomlBlock(content, "mcp_servers.todos");
18966
19801
  writeTomlFile(configPath, content.trimEnd() + `
18967
19802
  `);
18968
- console.log(chalk.green(`Codex CLI: unregistered from ${configPath}`));
19803
+ console.log(chalk2.green(`Codex CLI: unregistered from ${configPath}`));
18969
19804
  }
18970
19805
  function removeTomlBlock(content, blockName) {
18971
19806
  const lines = content.split(`
@@ -18989,7 +19824,7 @@ function removeTomlBlock(content, blockName) {
18989
19824
  `);
18990
19825
  }
18991
19826
  function registerGemini(binPath) {
18992
- const configPath = join9(HOME2, ".gemini", "settings.json");
19827
+ const configPath = join11(HOME2, ".gemini", "settings.json");
18993
19828
  const config = readJsonFile2(configPath);
18994
19829
  if (!config["mcpServers"]) {
18995
19830
  config["mcpServers"] = {};
@@ -19000,19 +19835,19 @@ function registerGemini(binPath) {
19000
19835
  args: []
19001
19836
  };
19002
19837
  writeJsonFile2(configPath, config);
19003
- console.log(chalk.green(`Gemini CLI: registered in ${configPath}`));
19838
+ console.log(chalk2.green(`Gemini CLI: registered in ${configPath}`));
19004
19839
  }
19005
19840
  function unregisterGemini() {
19006
- const configPath = join9(HOME2, ".gemini", "settings.json");
19841
+ const configPath = join11(HOME2, ".gemini", "settings.json");
19007
19842
  const config = readJsonFile2(configPath);
19008
19843
  const servers = config["mcpServers"];
19009
19844
  if (!servers || !("todos" in servers)) {
19010
- console.log(chalk.dim(`Gemini CLI: todos not found in ${configPath}`));
19845
+ console.log(chalk2.dim(`Gemini CLI: todos not found in ${configPath}`));
19011
19846
  return;
19012
19847
  }
19013
19848
  delete servers["todos"];
19014
19849
  writeJsonFile2(configPath, config);
19015
- console.log(chalk.green(`Gemini CLI: unregistered from ${configPath}`));
19850
+ console.log(chalk2.green(`Gemini CLI: unregistered from ${configPath}`));
19016
19851
  }
19017
19852
  function registerMcp(agent, global) {
19018
19853
  const agents = agent === "all" ? ["claude", "codex", "gemini"] : [agent];
@@ -19029,7 +19864,7 @@ function registerMcp(agent, global) {
19029
19864
  registerGemini(binPath);
19030
19865
  break;
19031
19866
  default:
19032
- console.error(chalk.red(`Unknown agent: ${a}. Use: claude, codex, gemini, all`));
19867
+ console.error(chalk2.red(`Unknown agent: ${a}. Use: claude, codex, gemini, all`));
19033
19868
  }
19034
19869
  }
19035
19870
  }
@@ -19047,7 +19882,7 @@ function unregisterMcp(agent, global) {
19047
19882
  unregisterGemini();
19048
19883
  break;
19049
19884
  default:
19050
- console.error(chalk.red(`Unknown agent: ${a}. Use: claude, codex, gemini, all`));
19885
+ console.error(chalk2.red(`Unknown agent: ${a}. Use: claude, codex, gemini, all`));
19051
19886
  }
19052
19887
  }
19053
19888
  }
@@ -19056,7 +19891,7 @@ program2.command("import <url>").description("Import a GitHub issue as a task").
19056
19891
  const { parseGitHubUrl: parseGitHubUrl2, fetchGitHubIssue: fetchGitHubIssue2, issueToTask: issueToTask2 } = (init_github(), __toCommonJS(exports_github));
19057
19892
  const parsed = parseGitHubUrl2(url);
19058
19893
  if (!parsed) {
19059
- console.error(chalk.red("Invalid GitHub issue URL. Expected: https://github.com/owner/repo/issues/123"));
19894
+ console.error(chalk2.red("Invalid GitHub issue URL. Expected: https://github.com/owner/repo/issues/123"));
19060
19895
  process.exit(1);
19061
19896
  }
19062
19897
  try {
@@ -19068,15 +19903,15 @@ program2.command("import <url>").description("Import a GitHub issue as a task").
19068
19903
  output(task, true);
19069
19904
  return;
19070
19905
  }
19071
- console.log(chalk.green(`Imported GH#${issue.number}: ${issue.title}`));
19072
- console.log(` ${chalk.dim("Task ID:")} ${task.short_id || task.id}`);
19073
- console.log(` ${chalk.dim("Labels:")} ${issue.labels.join(", ") || "none"}`);
19074
- console.log(` ${chalk.dim("Priority:")} ${task.priority}`);
19906
+ console.log(chalk2.green(`Imported GH#${issue.number}: ${issue.title}`));
19907
+ console.log(` ${chalk2.dim("Task ID:")} ${task.short_id || task.id}`);
19908
+ console.log(` ${chalk2.dim("Labels:")} ${issue.labels.join(", ") || "none"}`);
19909
+ console.log(` ${chalk2.dim("Priority:")} ${task.priority}`);
19075
19910
  } catch (e) {
19076
19911
  if (e.message?.includes("gh")) {
19077
- console.error(chalk.red("GitHub CLI (gh) not found or not authenticated. Install: https://cli.github.com"));
19912
+ console.error(chalk2.red("GitHub CLI (gh) not found or not authenticated. Install: https://cli.github.com"));
19078
19913
  } else {
19079
- console.error(chalk.red(`Import failed: ${e.message}`));
19914
+ console.error(chalk2.red(`Import failed: ${e.message}`));
19080
19915
  }
19081
19916
  process.exit(1);
19082
19917
  }
@@ -19096,7 +19931,7 @@ program2.command("link-commit <task-id> <sha>").description("Link a git commit t
19096
19931
  output(commit, true);
19097
19932
  return;
19098
19933
  }
19099
- console.log(chalk.green(`Linked commit ${sha.slice(0, 7)} to task ${taskId}`));
19934
+ console.log(chalk2.green(`Linked commit ${sha.slice(0, 7)} to task ${taskId}`));
19100
19935
  });
19101
19936
  var hookCmd = program2.command("hook").description("Manage git hooks for auto-linking commits to tasks");
19102
19937
  hookCmd.command("install").description("Install post-commit hook that auto-links commits to tasks").action(() => {
@@ -19104,28 +19939,28 @@ hookCmd.command("install").description("Install post-commit hook that auto-links
19104
19939
  try {
19105
19940
  const gitDir = execSync3("git rev-parse --git-dir", { encoding: "utf-8" }).trim();
19106
19941
  const hookPath = `${gitDir}/hooks/post-commit`;
19107
- const { existsSync: existsSync8, readFileSync: readFileSync6, writeFileSync: writeFileSync4, chmodSync } = __require("fs");
19942
+ const { existsSync: existsSync10, readFileSync: readFileSync7, writeFileSync: writeFileSync6, chmodSync } = __require("fs");
19108
19943
  const marker = "# todos-auto-link";
19109
- if (existsSync8(hookPath)) {
19110
- const existing = readFileSync6(hookPath, "utf-8");
19944
+ if (existsSync10(hookPath)) {
19945
+ const existing = readFileSync7(hookPath, "utf-8");
19111
19946
  if (existing.includes(marker)) {
19112
- console.log(chalk.yellow("Hook already installed."));
19947
+ console.log(chalk2.yellow("Hook already installed."));
19113
19948
  return;
19114
19949
  }
19115
- writeFileSync4(hookPath, existing + `
19950
+ writeFileSync6(hookPath, existing + `
19116
19951
  ${marker}
19117
19952
  $(dirname "$0")/../../scripts/post-commit-hook.sh
19118
19953
  `);
19119
19954
  } else {
19120
- writeFileSync4(hookPath, `#!/usr/bin/env bash
19955
+ writeFileSync6(hookPath, `#!/usr/bin/env bash
19121
19956
  ${marker}
19122
19957
  $(dirname "$0")/../../scripts/post-commit-hook.sh
19123
19958
  `);
19124
19959
  chmodSync(hookPath, 493);
19125
19960
  }
19126
- console.log(chalk.green("Post-commit hook installed. Commits with task IDs (e.g. OPE-00042) will auto-link."));
19961
+ console.log(chalk2.green("Post-commit hook installed. Commits with task IDs (e.g. OPE-00042) will auto-link."));
19127
19962
  } catch (e) {
19128
- console.error(chalk.red("Not in a git repository or hook install failed."));
19963
+ console.error(chalk2.red("Not in a git repository or hook install failed."));
19129
19964
  process.exit(1);
19130
19965
  }
19131
19966
  });
@@ -19134,15 +19969,15 @@ hookCmd.command("uninstall").description("Remove the todos post-commit hook").ac
19134
19969
  try {
19135
19970
  const gitDir = execSync3("git rev-parse --git-dir", { encoding: "utf-8" }).trim();
19136
19971
  const hookPath = `${gitDir}/hooks/post-commit`;
19137
- const { existsSync: existsSync8, readFileSync: readFileSync6, writeFileSync: writeFileSync4 } = __require("fs");
19972
+ const { existsSync: existsSync10, readFileSync: readFileSync7, writeFileSync: writeFileSync6 } = __require("fs");
19138
19973
  const marker = "# todos-auto-link";
19139
- if (!existsSync8(hookPath)) {
19140
- console.log(chalk.dim("No post-commit hook found."));
19974
+ if (!existsSync10(hookPath)) {
19975
+ console.log(chalk2.dim("No post-commit hook found."));
19141
19976
  return;
19142
19977
  }
19143
- const content = readFileSync6(hookPath, "utf-8");
19978
+ const content = readFileSync7(hookPath, "utf-8");
19144
19979
  if (!content.includes(marker)) {
19145
- console.log(chalk.dim("Hook not managed by todos."));
19980
+ console.log(chalk2.dim("Hook not managed by todos."));
19146
19981
  return;
19147
19982
  }
19148
19983
  const cleaned = content.split(`
@@ -19151,12 +19986,12 @@ hookCmd.command("uninstall").description("Remove the todos post-commit hook").ac
19151
19986
  if (cleaned === "#!/usr/bin/env bash" || cleaned === "") {
19152
19987
  __require("fs").unlinkSync(hookPath);
19153
19988
  } else {
19154
- writeFileSync4(hookPath, cleaned + `
19989
+ writeFileSync6(hookPath, cleaned + `
19155
19990
  `);
19156
19991
  }
19157
- console.log(chalk.green("Post-commit hook removed."));
19992
+ console.log(chalk2.green("Post-commit hook removed."));
19158
19993
  } catch (e) {
19159
- console.error(chalk.red("Not in a git repository or hook removal failed."));
19994
+ console.error(chalk2.red("Not in a git repository or hook removal failed."));
19160
19995
  process.exit(1);
19161
19996
  }
19162
19997
  });
@@ -19165,17 +20000,17 @@ program2.command("init <name>").description("Register an agent and get a short U
19165
20000
  try {
19166
20001
  const result = registerAgent({ name, description: opts.description });
19167
20002
  if (isAgentConflict(result)) {
19168
- console.error(chalk.red("CONFLICT:"), result.message);
20003
+ console.error(chalk2.red("CONFLICT:"), result.message);
19169
20004
  process.exit(1);
19170
20005
  }
19171
20006
  if (globalOpts.json) {
19172
20007
  output(result, true);
19173
20008
  } else {
19174
- console.log(chalk.green("Agent registered:"));
19175
- console.log(` ${chalk.dim("ID:")} ${result.id}`);
19176
- console.log(` ${chalk.dim("Name:")} ${result.name}`);
20009
+ console.log(chalk2.green("Agent registered:"));
20010
+ console.log(` ${chalk2.dim("ID:")} ${result.id}`);
20011
+ console.log(` ${chalk2.dim("Name:")} ${result.name}`);
19177
20012
  console.log(`
19178
- Use ${chalk.cyan(`--agent ${result.id}`)} on future commands.`);
20013
+ Use ${chalk2.cyan(`--agent ${result.id}`)} on future commands.`);
19179
20014
  }
19180
20015
  } catch (e) {
19181
20016
  handleError(e);
@@ -19185,51 +20020,51 @@ program2.command("heartbeat [agent]").description("Update last_seen_at to signal
19185
20020
  const globalOpts = program2.opts();
19186
20021
  const agentId = agent || globalOpts.agent;
19187
20022
  if (!agentId) {
19188
- console.error(chalk.red("Agent ID required. Use --agent or pass as argument."));
20023
+ console.error(chalk2.red("Agent ID required. Use --agent or pass as argument."));
19189
20024
  process.exit(1);
19190
20025
  }
19191
20026
  const { updateAgentActivity: updateAgentActivity2, getAgent: getAgent2 } = (init_agents(), __toCommonJS(exports_agents));
19192
20027
  const a = getAgent2(agentId) || (init_agents(), __toCommonJS(exports_agents)).getAgentByName(agentId);
19193
20028
  if (!a) {
19194
- console.error(chalk.red(`Agent not found: ${agentId}`));
20029
+ console.error(chalk2.red(`Agent not found: ${agentId}`));
19195
20030
  process.exit(1);
19196
20031
  }
19197
20032
  updateAgentActivity2(a.id);
19198
20033
  if (globalOpts.json) {
19199
20034
  console.log(JSON.stringify({ agent_id: a.id, name: a.name, last_seen_at: new Date().toISOString() }));
19200
20035
  } else {
19201
- console.log(chalk.green(`\u2665 ${a.name} (${a.id.slice(0, 8)}) \u2014 heartbeat sent`));
20036
+ console.log(chalk2.green(`\u2665 ${a.name} (${a.id.slice(0, 8)}) \u2014 heartbeat sent`));
19202
20037
  }
19203
20038
  });
19204
20039
  program2.command("release [agent]").description("Release/logout an agent \u2014 clears session binding so the name is immediately available").option("--session-id <id>", "Only release if session ID matches").action((agent, opts) => {
19205
20040
  const globalOpts = program2.opts();
19206
20041
  const agentId = agent || globalOpts.agent;
19207
20042
  if (!agentId) {
19208
- console.error(chalk.red("Agent ID or name required. Use --agent or pass as argument."));
20043
+ console.error(chalk2.red("Agent ID or name required. Use --agent or pass as argument."));
19209
20044
  process.exit(1);
19210
20045
  }
19211
20046
  const { getAgent: getAgent2, getAgentByName: getAgentByName2 } = (init_agents(), __toCommonJS(exports_agents));
19212
20047
  const a = getAgent2(agentId) || getAgentByName2(agentId);
19213
20048
  if (!a) {
19214
- console.error(chalk.red(`Agent not found: ${agentId}`));
20049
+ console.error(chalk2.red(`Agent not found: ${agentId}`));
19215
20050
  process.exit(1);
19216
20051
  }
19217
20052
  const released = releaseAgent(a.id, opts?.sessionId);
19218
20053
  if (!released) {
19219
- console.error(chalk.red("Release denied: session_id does not match agent's current session."));
20054
+ console.error(chalk2.red("Release denied: session_id does not match agent's current session."));
19220
20055
  process.exit(1);
19221
20056
  }
19222
20057
  if (globalOpts.json) {
19223
20058
  console.log(JSON.stringify({ agent_id: a.id, name: a.name, released: true }));
19224
20059
  } else {
19225
- console.log(chalk.green(`\u2713 ${a.name} (${a.id}) released \u2014 name is now available.`));
20060
+ console.log(chalk2.green(`\u2713 ${a.name} (${a.id}) released \u2014 name is now available.`));
19226
20061
  }
19227
20062
  });
19228
20063
  program2.command("focus [project]").description("Focus on a project (or clear focus if no project given)").action((project) => {
19229
20064
  const globalOpts = program2.opts();
19230
20065
  const agentId = globalOpts.agent;
19231
20066
  if (!agentId) {
19232
- console.error(chalk.red("Agent ID required. Use --agent."));
20067
+ console.error(chalk2.red("Agent ID required. Use --agent."));
19233
20068
  process.exit(1);
19234
20069
  }
19235
20070
  const db = getDatabase();
@@ -19238,10 +20073,10 @@ program2.command("focus [project]").description("Focus on a project (or clear fo
19238
20073
  const p = getProjectByPath2(process.cwd(), db) || getProjectByName(project, db);
19239
20074
  const projectId = p?.id || project;
19240
20075
  db.run("UPDATE agents SET active_project_id = ? WHERE id = ? OR name = ?", [projectId, agentId, agentId]);
19241
- console.log(chalk.green(`Focused on: ${p?.name || projectId}`));
20076
+ console.log(chalk2.green(`Focused on: ${p?.name || projectId}`));
19242
20077
  } else {
19243
20078
  db.run("UPDATE agents SET active_project_id = NULL WHERE id = ? OR name = ?", [agentId, agentId]);
19244
- console.log(chalk.dim("Focus cleared."));
20079
+ console.log(chalk2.dim("Focus cleared."));
19245
20080
  }
19246
20081
  });
19247
20082
  program2.command("agents").description("List registered agents").action(() => {
@@ -19253,11 +20088,11 @@ program2.command("agents").description("List registered agents").action(() => {
19253
20088
  return;
19254
20089
  }
19255
20090
  if (agents.length === 0) {
19256
- console.log(chalk.dim("No agents registered. Use 'todos init <name>' to register."));
20091
+ console.log(chalk2.dim("No agents registered. Use 'todos init <name>' to register."));
19257
20092
  return;
19258
20093
  }
19259
20094
  for (const a of agents) {
19260
- console.log(` ${chalk.cyan(a.id)} ${chalk.bold(a.name)} ${chalk.dim(a.last_seen_at)}`);
20095
+ console.log(` ${chalk2.cyan(a.id)} ${chalk2.bold(a.name)} ${chalk2.dim(a.last_seen_at)}`);
19261
20096
  }
19262
20097
  } catch (e) {
19263
20098
  handleError(e);
@@ -19269,7 +20104,7 @@ program2.command("agent-update <name>").alias("agents-update").description("Upda
19269
20104
  const { getAgentByName: findByName, updateAgent: doUpdate } = (init_agents(), __toCommonJS(exports_agents));
19270
20105
  const agent = findByName(name);
19271
20106
  if (!agent) {
19272
- console.error(chalk.red(`Agent not found: ${name}`));
20107
+ console.error(chalk2.red(`Agent not found: ${name}`));
19273
20108
  process.exit(1);
19274
20109
  }
19275
20110
  const updates = {};
@@ -19283,11 +20118,11 @@ program2.command("agent-update <name>").alias("agents-update").description("Upda
19283
20118
  if (globalOpts.json) {
19284
20119
  output(updated, true);
19285
20120
  } else {
19286
- console.log(chalk.green(`Updated agent: ${updated.name} (${updated.id.slice(0, 8)})`));
20121
+ console.log(chalk2.green(`Updated agent: ${updated.name} (${updated.id.slice(0, 8)})`));
19287
20122
  if (updated.description)
19288
- console.log(chalk.dim(` Description: ${updated.description}`));
20123
+ console.log(chalk2.dim(` Description: ${updated.description}`));
19289
20124
  if (updated.role)
19290
- console.log(chalk.dim(` Role: ${updated.role}`));
20125
+ console.log(chalk2.dim(` Role: ${updated.role}`));
19291
20126
  }
19292
20127
  } catch (e) {
19293
20128
  handleError(e);
@@ -19298,7 +20133,7 @@ program2.command("agent <name>").description("Show all info about an agent: task
19298
20133
  const { getAgentByName: findByName } = (init_agents(), __toCommonJS(exports_agents));
19299
20134
  const agent = findByName(name);
19300
20135
  if (!agent) {
19301
- console.error(chalk.red(`Agent not found: ${name}`));
20136
+ console.error(chalk2.red(`Agent not found: ${name}`));
19302
20137
  process.exit(1);
19303
20138
  }
19304
20139
  const byAssigned = listTasks({ assigned_to: agent.name });
@@ -19317,53 +20152,53 @@ program2.command("agent <name>").description("Show all info about an agent: task
19317
20152
  const rate = allTasks.length > 0 ? Math.round(completed.length / allTasks.length * 100) : 0;
19318
20153
  const lastSeenMs = Date.now() - new Date(agent.last_seen_at).getTime();
19319
20154
  const lastSeenMins = Math.floor(lastSeenMs / 60000);
19320
- const lastSeenStr = lastSeenMins < 2 ? chalk.green("just now") : lastSeenMins < 60 ? chalk.yellow(`${lastSeenMins}m ago`) : lastSeenMins < 1440 ? chalk.yellow(`${Math.floor(lastSeenMins / 60)}h ago`) : chalk.dim(`${Math.floor(lastSeenMins / 1440)}d ago`);
20155
+ const lastSeenStr = lastSeenMins < 2 ? chalk2.green("just now") : lastSeenMins < 60 ? chalk2.yellow(`${lastSeenMins}m ago`) : lastSeenMins < 1440 ? chalk2.yellow(`${Math.floor(lastSeenMins / 60)}h ago`) : chalk2.dim(`${Math.floor(lastSeenMins / 1440)}d ago`);
19321
20156
  const isOnline = lastSeenMins < 5;
19322
20157
  if (opts.json || globalOpts.json) {
19323
20158
  console.log(JSON.stringify({ agent, tasks: { pending: pending.length, in_progress: inProgress.length, completed: completed.length, failed: failed.length, total: allTasks.length, completion_rate: rate }, all_tasks: allTasks }, null, 2));
19324
20159
  return;
19325
20160
  }
19326
20161
  console.log(`
19327
- ${isOnline ? chalk.green("\u25CF") : chalk.dim("\u25CB")} ${chalk.bold(agent.name)} ${chalk.dim(`(${agent.id})`)} ${lastSeenStr}`);
20162
+ ${isOnline ? chalk2.green("\u25CF") : chalk2.dim("\u25CB")} ${chalk2.bold(agent.name)} ${chalk2.dim(`(${agent.id})`)} ${lastSeenStr}`);
19328
20163
  if (agent.description)
19329
- console.log(chalk.dim(` ${agent.description}`));
20164
+ console.log(chalk2.dim(` ${agent.description}`));
19330
20165
  if (agent.role)
19331
- console.log(chalk.dim(` Role: ${agent.role}`));
20166
+ console.log(chalk2.dim(` Role: ${agent.role}`));
19332
20167
  console.log();
19333
- console.log(` ${chalk.yellow(String(pending.length))} pending ${chalk.blue(String(inProgress.length))} active ${chalk.green(String(completed.length))} done ${chalk.dim(`${rate}% rate`)}`);
20168
+ console.log(` ${chalk2.yellow(String(pending.length))} pending ${chalk2.blue(String(inProgress.length))} active ${chalk2.green(String(completed.length))} done ${chalk2.dim(`${rate}% rate`)}`);
19334
20169
  console.log();
19335
20170
  if (inProgress.length > 0) {
19336
- console.log(chalk.bold(" In progress:"));
20171
+ console.log(chalk2.bold(" In progress:"));
19337
20172
  for (const t of inProgress) {
19338
20173
  const id = t.short_id || t.id.slice(0, 8);
19339
- const staleFlag = new Date(t.updated_at).getTime() < Date.now() - 30 * 60 * 1000 ? chalk.red(" [stale]") : "";
19340
- console.log(` ${chalk.cyan(id)} ${chalk.yellow(t.priority)} ${t.title}${staleFlag}`);
20174
+ const staleFlag = new Date(t.updated_at).getTime() < Date.now() - 30 * 60 * 1000 ? chalk2.red(" [stale]") : "";
20175
+ console.log(` ${chalk2.cyan(id)} ${chalk2.yellow(t.priority)} ${t.title}${staleFlag}`);
19341
20176
  }
19342
20177
  console.log();
19343
20178
  }
19344
20179
  if (pending.length > 0) {
19345
- console.log(chalk.bold(` Pending (${pending.length}):`));
20180
+ console.log(chalk2.bold(` Pending (${pending.length}):`));
19346
20181
  for (const t of pending.slice(0, 5)) {
19347
20182
  const id = t.short_id || t.id.slice(0, 8);
19348
- const due = t.due_at ? chalk.dim(` due:${t.due_at.slice(0, 10)}`) : "";
19349
- console.log(` ${chalk.dim(id)} ${t.priority.padEnd(8)} ${t.title}${due}`);
20183
+ const due = t.due_at ? chalk2.dim(` due:${t.due_at.slice(0, 10)}`) : "";
20184
+ console.log(` ${chalk2.dim(id)} ${t.priority.padEnd(8)} ${t.title}${due}`);
19350
20185
  }
19351
20186
  if (pending.length > 5)
19352
- console.log(chalk.dim(` ... and ${pending.length - 5} more`));
20187
+ console.log(chalk2.dim(` ... and ${pending.length - 5} more`));
19353
20188
  console.log();
19354
20189
  }
19355
20190
  const recentDone = completed.filter((t) => t.completed_at).sort((a, b) => new Date(b.completed_at).getTime() - new Date(a.completed_at).getTime()).slice(0, 3);
19356
20191
  if (recentDone.length > 0) {
19357
- console.log(chalk.bold(" Recently completed:"));
20192
+ console.log(chalk2.bold(" Recently completed:"));
19358
20193
  for (const t of recentDone) {
19359
20194
  const id = t.short_id || t.id.slice(0, 8);
19360
- const when = t.completed_at ? chalk.dim(new Date(t.completed_at).toLocaleDateString()) : "";
19361
- console.log(` ${chalk.green("\u2713")} ${chalk.dim(id)} ${t.title} ${when}`);
20195
+ const when = t.completed_at ? chalk2.dim(new Date(t.completed_at).toLocaleDateString()) : "";
20196
+ console.log(` ${chalk2.green("\u2713")} ${chalk2.dim(id)} ${t.title} ${when}`);
19362
20197
  }
19363
20198
  console.log();
19364
20199
  }
19365
20200
  if (allTasks.length === 0) {
19366
- console.log(chalk.dim(" No tasks assigned to this agent."));
20201
+ console.log(chalk2.dim(" No tasks assigned to this agent."));
19367
20202
  }
19368
20203
  });
19369
20204
  program2.command("org").description("Show agent org chart \u2014 who reports to who").option("--set <agent=manager>", "Set reporting: 'seneca=julius' or 'seneca=' to clear").action((opts) => {
@@ -19373,14 +20208,14 @@ program2.command("org").description("Show agent org chart \u2014 who reports to
19373
20208
  const [agentName, managerName] = opts.set.split("=");
19374
20209
  const agent = getByName(agentName);
19375
20210
  if (!agent) {
19376
- console.error(chalk.red(`Agent not found: ${agentName}`));
20211
+ console.error(chalk2.red(`Agent not found: ${agentName}`));
19377
20212
  process.exit(1);
19378
20213
  }
19379
20214
  let managerId = null;
19380
20215
  if (managerName) {
19381
20216
  const manager = getByName(managerName);
19382
20217
  if (!manager) {
19383
- console.error(chalk.red(`Manager not found: ${managerName}`));
20218
+ console.error(chalk2.red(`Manager not found: ${managerName}`));
19384
20219
  process.exit(1);
19385
20220
  }
19386
20221
  managerId = manager.id;
@@ -19389,7 +20224,7 @@ program2.command("org").description("Show agent org chart \u2014 who reports to
19389
20224
  if (globalOpts.json) {
19390
20225
  output({ agent: agentName, reports_to: managerName || null }, true);
19391
20226
  } else {
19392
- console.log(chalk.green(managerId ? `${agentName} \u2192 ${managerName}` : `${agentName} \u2192 (top-level)`));
20227
+ console.log(chalk2.green(managerId ? `${agentName} \u2192 ${managerName}` : `${agentName} \u2192 (top-level)`));
19393
20228
  }
19394
20229
  return;
19395
20230
  }
@@ -19399,15 +20234,15 @@ program2.command("org").description("Show agent org chart \u2014 who reports to
19399
20234
  return;
19400
20235
  }
19401
20236
  if (tree.length === 0) {
19402
- console.log(chalk.dim("No agents registered."));
20237
+ console.log(chalk2.dim("No agents registered."));
19403
20238
  return;
19404
20239
  }
19405
20240
  function render2(nodes, indent = 0) {
19406
20241
  for (const n of nodes) {
19407
20242
  const prefix = " ".repeat(indent);
19408
- const title = n.agent.title ? chalk.cyan(` \u2014 ${n.agent.title}`) : "";
19409
- const level = n.agent.level ? chalk.dim(` (${n.agent.level})`) : "";
19410
- console.log(`${prefix}${indent > 0 ? "\u251C\u2500\u2500 " : ""}${chalk.bold(n.agent.name)}${title}${level}`);
20243
+ const title = n.agent.title ? chalk2.cyan(` \u2014 ${n.agent.title}`) : "";
20244
+ const level = n.agent.level ? chalk2.dim(` (${n.agent.level})`) : "";
20245
+ console.log(`${prefix}${indent > 0 ? "\u251C\u2500\u2500 " : ""}${chalk2.bold(n.agent.name)}${title}${level}`);
19411
20246
  render2(n.reports, indent + 1);
19412
20247
  }
19413
20248
  }
@@ -19423,21 +20258,21 @@ program2.command("lists").aliases(["task-lists", "tl"]).description("List and ma
19423
20258
  output(list, true);
19424
20259
  return;
19425
20260
  }
19426
- console.log(chalk.green("Task list created:"));
19427
- console.log(` ${chalk.dim("ID:")} ${list.id.slice(0, 8)}`);
19428
- console.log(` ${chalk.dim("Slug:")} ${list.slug}`);
19429
- console.log(` ${chalk.dim("Name:")} ${list.name}`);
20261
+ console.log(chalk2.green("Task list created:"));
20262
+ console.log(` ${chalk2.dim("ID:")} ${list.id.slice(0, 8)}`);
20263
+ console.log(` ${chalk2.dim("Slug:")} ${list.slug}`);
20264
+ console.log(` ${chalk2.dim("Name:")} ${list.name}`);
19430
20265
  return;
19431
20266
  }
19432
20267
  if (opts.delete) {
19433
20268
  const db = getDatabase();
19434
20269
  const resolved = resolvePartialId(db, "task_lists", opts.delete);
19435
20270
  if (!resolved) {
19436
- console.error(chalk.red("Task list not found"));
20271
+ console.error(chalk2.red("Task list not found"));
19437
20272
  process.exit(1);
19438
20273
  }
19439
20274
  deleteTaskList(resolved);
19440
- console.log(chalk.green("Task list deleted."));
20275
+ console.log(chalk2.green("Task list deleted."));
19441
20276
  return;
19442
20277
  }
19443
20278
  const lists = listTaskLists(projectId);
@@ -19446,11 +20281,11 @@ program2.command("lists").aliases(["task-lists", "tl"]).description("List and ma
19446
20281
  return;
19447
20282
  }
19448
20283
  if (lists.length === 0) {
19449
- console.log(chalk.dim("No task lists. Use 'todos lists --add <name>' to create one."));
20284
+ console.log(chalk2.dim("No task lists. Use 'todos lists --add <name>' to create one."));
19450
20285
  return;
19451
20286
  }
19452
20287
  for (const l of lists) {
19453
- console.log(` ${chalk.dim(l.id.slice(0, 8))} ${chalk.bold(l.name)} ${chalk.dim(`(${l.slug})`)}`);
20288
+ console.log(` ${chalk2.dim(l.id.slice(0, 8))} ${chalk2.bold(l.name)} ${chalk2.dim(`(${l.slug})`)}`);
19454
20289
  }
19455
20290
  } catch (e) {
19456
20291
  handleError(e);
@@ -19461,20 +20296,20 @@ program2.command("upgrade").alias("self-update").description("Update todos to th
19461
20296
  const currentVersion = getPackageVersion();
19462
20297
  const res = await fetch("https://registry.npmjs.org/@hasna/todos/latest");
19463
20298
  if (!res.ok) {
19464
- console.error(chalk.red("Failed to check for updates."));
20299
+ console.error(chalk2.red("Failed to check for updates."));
19465
20300
  process.exit(1);
19466
20301
  }
19467
20302
  const data = await res.json();
19468
20303
  const latestVersion = data.version;
19469
- console.log(` Current: ${chalk.dim(currentVersion)}`);
19470
- console.log(` Latest: ${chalk.green(latestVersion)}`);
20304
+ console.log(` Current: ${chalk2.dim(currentVersion)}`);
20305
+ console.log(` Latest: ${chalk2.green(latestVersion)}`);
19471
20306
  if (currentVersion === latestVersion) {
19472
- console.log(chalk.green(`
20307
+ console.log(chalk2.green(`
19473
20308
  Already up to date!`));
19474
20309
  return;
19475
20310
  }
19476
20311
  if (opts.check) {
19477
- console.log(chalk.yellow(`
20312
+ console.log(chalk2.yellow(`
19478
20313
  Update available: ${currentVersion} \u2192 ${latestVersion}`));
19479
20314
  return;
19480
20315
  }
@@ -19484,10 +20319,10 @@ Update available: ${currentVersion} \u2192 ${latestVersion}`));
19484
20319
  useBun = true;
19485
20320
  } catch {}
19486
20321
  const cmd = useBun ? "bun add -g @hasna/todos@latest" : "npm install -g @hasna/todos@latest";
19487
- console.log(chalk.dim(`
20322
+ console.log(chalk2.dim(`
19488
20323
  Running: ${cmd}`));
19489
20324
  execSync2(cmd, { stdio: "inherit" });
19490
- console.log(chalk.green(`
20325
+ console.log(chalk2.green(`
19491
20326
  Updated to ${latestVersion}!`));
19492
20327
  } catch (e) {
19493
20328
  handleError(e);
@@ -19495,7 +20330,7 @@ Updated to ${latestVersion}!`));
19495
20330
  });
19496
20331
  program2.command("config").description("View or update configuration").option("--get <key>", "Get a config value").option("--set <key=value>", "Set a config value (e.g. completion_guard.enabled=true)").action((opts) => {
19497
20332
  const globalOpts = program2.opts();
19498
- const configPath = join9(process.env["HOME"] || "~", ".todos", "config.json");
20333
+ const configPath = join11(process.env["HOME"] || "~", ".todos", "config.json");
19499
20334
  if (opts.get) {
19500
20335
  const config2 = loadConfig();
19501
20336
  const keys = opts.get.split(".");
@@ -19506,7 +20341,7 @@ program2.command("config").description("View or update configuration").option("-
19506
20341
  if (globalOpts.json) {
19507
20342
  output({ key: opts.get, value }, true);
19508
20343
  } else {
19509
- console.log(value !== undefined ? JSON.stringify(value, null, 2) : chalk.dim("(not set)"));
20344
+ console.log(value !== undefined ? JSON.stringify(value, null, 2) : chalk2.dim("(not set)"));
19510
20345
  }
19511
20346
  return;
19512
20347
  }
@@ -19521,7 +20356,7 @@ program2.command("config").description("View or update configuration").option("-
19521
20356
  }
19522
20357
  let config2 = {};
19523
20358
  try {
19524
- config2 = JSON.parse(readFileSync5(configPath, "utf-8"));
20359
+ config2 = JSON.parse(readFileSync6(configPath, "utf-8"));
19525
20360
  } catch {}
19526
20361
  const keys = key.split(".");
19527
20362
  let obj = config2;
@@ -19532,13 +20367,13 @@ program2.command("config").description("View or update configuration").option("-
19532
20367
  }
19533
20368
  obj[keys[keys.length - 1]] = parsedValue;
19534
20369
  const dir = dirname4(configPath);
19535
- if (!existsSync7(dir))
19536
- mkdirSync3(dir, { recursive: true });
19537
- writeFileSync3(configPath, JSON.stringify(config2, null, 2));
20370
+ if (!existsSync9(dir))
20371
+ mkdirSync5(dir, { recursive: true });
20372
+ writeFileSync5(configPath, JSON.stringify(config2, null, 2));
19538
20373
  if (globalOpts.json) {
19539
20374
  output({ key, value: parsedValue }, true);
19540
20375
  } else {
19541
- console.log(chalk.green(`Set ${key} = ${JSON.stringify(parsedValue)}`));
20376
+ console.log(chalk2.green(`Set ${key} = ${JSON.stringify(parsedValue)}`));
19542
20377
  }
19543
20378
  return;
19544
20379
  }
@@ -19579,25 +20414,25 @@ program2.command("watch").description("Live-updating task list (refreshes every
19579
20414
  counts[t.status] = (counts[t.status] || 0) + 1;
19580
20415
  process.stdout.write("\x1B[2J\x1B[0f");
19581
20416
  const now2 = new Date().toLocaleTimeString();
19582
- console.log(chalk.bold(`todos watch`) + chalk.dim(` \u2014 ${now2} \u2014 refreshing every ${opts.interval}s \u2014 Ctrl+C to stop
20417
+ console.log(chalk2.bold(`todos watch`) + chalk2.dim(` \u2014 ${now2} \u2014 refreshing every ${opts.interval}s \u2014 Ctrl+C to stop
19583
20418
  `));
19584
20419
  const parts = [
19585
- `total: ${chalk.bold(String(all.length))}`,
19586
- `pending: ${chalk.yellow(String(counts["pending"] || 0))}`,
19587
- `in_progress: ${chalk.blue(String(counts["in_progress"] || 0))}`,
19588
- `completed: ${chalk.green(String(counts["completed"] || 0))}`,
19589
- `failed: ${chalk.red(String(counts["failed"] || 0))}`
20420
+ `total: ${chalk2.bold(String(all.length))}`,
20421
+ `pending: ${chalk2.yellow(String(counts["pending"] || 0))}`,
20422
+ `in_progress: ${chalk2.blue(String(counts["in_progress"] || 0))}`,
20423
+ `completed: ${chalk2.green(String(counts["completed"] || 0))}`,
20424
+ `failed: ${chalk2.red(String(counts["failed"] || 0))}`
19590
20425
  ];
19591
20426
  console.log(parts.join(" ") + `
19592
20427
  `);
19593
20428
  if (tasks.length === 0) {
19594
- console.log(chalk.dim("No matching tasks."));
20429
+ console.log(chalk2.dim("No matching tasks."));
19595
20430
  return;
19596
20431
  }
19597
20432
  for (const t of tasks) {
19598
20433
  console.log(formatTaskLine(t));
19599
20434
  }
19600
- console.log(chalk.dim(`
20435
+ console.log(chalk2.dim(`
19601
20436
  ${tasks.length} task(s) shown`));
19602
20437
  }
19603
20438
  render2();
@@ -19617,19 +20452,19 @@ program2.command("stream").description("Subscribe to real-time task events via S
19617
20452
  params.set("events", opts.events);
19618
20453
  const url = `${baseUrl}/api/tasks/stream?${params}`;
19619
20454
  const eventColors = {
19620
- "task.created": chalk.blue,
19621
- "task.started": chalk.cyan,
19622
- "task.completed": chalk.green,
19623
- "task.failed": chalk.red,
19624
- "task.assigned": chalk.yellow,
19625
- "task.status_changed": chalk.magenta
20455
+ "task.created": chalk2.blue,
20456
+ "task.started": chalk2.cyan,
20457
+ "task.completed": chalk2.green,
20458
+ "task.failed": chalk2.red,
20459
+ "task.assigned": chalk2.yellow,
20460
+ "task.status_changed": chalk2.magenta
19626
20461
  };
19627
- console.log(chalk.dim(`Connecting to ${url} \u2014 Ctrl+C to stop
20462
+ console.log(chalk2.dim(`Connecting to ${url} \u2014 Ctrl+C to stop
19628
20463
  `));
19629
20464
  try {
19630
20465
  const resp = await fetch(url);
19631
20466
  if (!resp.ok || !resp.body) {
19632
- console.error(chalk.red(`Failed to connect: ${resp.status}`));
20467
+ console.error(chalk2.red(`Failed to connect: ${resp.status}`));
19633
20468
  process.exit(1);
19634
20469
  }
19635
20470
  const reader = resp.body.getReader();
@@ -19655,11 +20490,11 @@ program2.command("stream").description("Subscribe to real-time task events via S
19655
20490
  if (opts.json) {
19656
20491
  console.log(JSON.stringify({ event: eventName, ...data }));
19657
20492
  } else {
19658
- const colorFn = eventColors[eventName] || chalk.white;
20493
+ const colorFn = eventColors[eventName] || chalk2.white;
19659
20494
  const ts = new Date(data.timestamp || Date.now()).toLocaleTimeString();
19660
20495
  const taskId = data.task_id ? data.task_id.slice(0, 8) : "";
19661
20496
  const agentInfo = data.agent_id ? ` [${data.agent_id}]` : "";
19662
- console.log(`${chalk.dim(ts)} ${colorFn(eventName.padEnd(25))} ${taskId}${agentInfo}`);
20497
+ console.log(`${chalk2.dim(ts)} ${colorFn(eventName.padEnd(25))} ${taskId}${agentInfo}`);
19663
20498
  }
19664
20499
  } catch {}
19665
20500
  eventName = "";
@@ -19667,8 +20502,8 @@ program2.command("stream").description("Subscribe to real-time task events via S
19667
20502
  }
19668
20503
  }
19669
20504
  } catch (e) {
19670
- console.error(chalk.red(`Connection error: ${e instanceof Error ? e.message : e}`));
19671
- console.error(chalk.dim("Is `todos serve` running?"));
20505
+ console.error(chalk2.red(`Connection error: ${e instanceof Error ? e.message : e}`));
20506
+ console.error(chalk2.dim("Is `todos serve` running?"));
19672
20507
  process.exit(1);
19673
20508
  }
19674
20509
  });
@@ -19689,29 +20524,29 @@ program2.command("blame <file>").description("Show which tasks/agents touched a
19689
20524
  output({ file: filePath, task_files: taskFiles, commits: commitRows }, true);
19690
20525
  return;
19691
20526
  }
19692
- console.log(chalk.bold(`
20527
+ console.log(chalk2.bold(`
19693
20528
  Blame: ${filePath}
19694
20529
  `));
19695
20530
  if (taskFiles.length > 0) {
19696
- console.log(chalk.bold("Task File Links:"));
20531
+ console.log(chalk2.bold("Task File Links:"));
19697
20532
  for (const tf of taskFiles) {
19698
20533
  const task = getTask2(tf.task_id, db);
19699
20534
  const title = task ? task.title : "unknown";
19700
20535
  const sid = task?.short_id || tf.task_id.slice(0, 8);
19701
- console.log(` ${chalk.cyan(sid)} ${title} \u2014 ${chalk.dim(tf.role || "file")} ${chalk.dim(tf.updated_at)}`);
20536
+ console.log(` ${chalk2.cyan(sid)} ${title} \u2014 ${chalk2.dim(tf.role || "file")} ${chalk2.dim(tf.updated_at)}`);
19702
20537
  }
19703
20538
  }
19704
20539
  if (commitRows.length > 0) {
19705
- console.log(chalk.bold(`
20540
+ console.log(chalk2.bold(`
19706
20541
  Commit Links (${commitRows.length}):`));
19707
20542
  for (const c of commitRows) {
19708
20543
  const sid = c.short_id || c.task_id.slice(0, 8);
19709
- console.log(` ${chalk.yellow(c.sha?.slice(0, 7) || "?")} ${chalk.cyan(sid)} ${c.title || ""} \u2014 ${chalk.dim(c.author || "")} ${chalk.dim(c.committed_at || "")}`);
20544
+ console.log(` ${chalk2.yellow(c.sha?.slice(0, 7) || "?")} ${chalk2.cyan(sid)} ${c.title || ""} \u2014 ${chalk2.dim(c.author || "")} ${chalk2.dim(c.committed_at || "")}`);
19710
20545
  }
19711
20546
  }
19712
20547
  if (taskFiles.length === 0 && commitRows.length === 0) {
19713
- console.log(chalk.dim("No task or commit links found for this file."));
19714
- console.log(chalk.dim("Use 'todos hook install' to auto-link future commits."));
20548
+ console.log(chalk2.dim("No task or commit links found for this file."));
20549
+ console.log(chalk2.dim("Use 'todos hook install' to auto-link future commits."));
19715
20550
  }
19716
20551
  console.log();
19717
20552
  });
@@ -19730,17 +20565,17 @@ program2.command("next").description("Show the best pending task to work on next
19730
20565
  filters.project_id = opts.project;
19731
20566
  const task = getNextTask(opts.agent, Object.keys(filters).length ? filters : undefined, db);
19732
20567
  if (!task) {
19733
- console.log(chalk.dim("No tasks available."));
20568
+ console.log(chalk2.dim("No tasks available."));
19734
20569
  return;
19735
20570
  }
19736
20571
  if (opts.json) {
19737
20572
  console.log(JSON.stringify(task, null, 2));
19738
20573
  return;
19739
20574
  }
19740
- console.log(chalk.bold("Next task:"));
19741
- console.log(` ${chalk.cyan(task.short_id || task.id.slice(0, 8))} ${chalk.yellow(task.priority)} ${task.title}`);
20575
+ console.log(chalk2.bold("Next task:"));
20576
+ console.log(` ${chalk2.cyan(task.short_id || task.id.slice(0, 8))} ${chalk2.yellow(task.priority)} ${task.title}`);
19742
20577
  if (task.description)
19743
- console.log(chalk.dim(` ${task.description.slice(0, 100)}`));
20578
+ console.log(chalk2.dim(` ${task.description.slice(0, 100)}`));
19744
20579
  });
19745
20580
  program2.command("claim <agent>").description("Atomically claim the best pending task for an agent").option("--project <id>", "Filter to project").option("--json", "Output as JSON").action(async (agent, opts) => {
19746
20581
  const db = getDatabase();
@@ -19749,14 +20584,28 @@ program2.command("claim <agent>").description("Atomically claim the best pending
19749
20584
  filters.project_id = opts.project;
19750
20585
  const task = claimNextTask(agent, Object.keys(filters).length ? filters : undefined, db);
19751
20586
  if (!task) {
19752
- console.log(chalk.dim("No tasks available to claim."));
20587
+ console.log(chalk2.dim("No tasks available to claim."));
19753
20588
  return;
19754
20589
  }
19755
20590
  if (opts.json) {
19756
20591
  console.log(JSON.stringify(task, null, 2));
19757
20592
  return;
19758
20593
  }
19759
- console.log(chalk.green(`Claimed: ${task.short_id || task.id.slice(0, 8)} | ${task.priority} | ${task.title}`));
20594
+ console.log(chalk2.green(`Claimed: ${task.short_id || task.id.slice(0, 8)} | ${task.priority} | ${task.title}`));
20595
+ });
20596
+ program2.command("steal <agent>").description("Work-stealing: take the highest-priority stale task from another agent").option("--stale-minutes <n>", "How long a task must be stale (default: 30)", "30").option("--project <id>", "Filter to project").action((agent, opts) => {
20597
+ const globalOpts = program2.opts();
20598
+ const { stealTask: stealTask2 } = (init_tasks(), __toCommonJS(exports_tasks));
20599
+ const task = stealTask2(agent, { stale_minutes: parseInt(opts.staleMinutes, 10), project_id: opts.project });
20600
+ if (!task) {
20601
+ console.log(chalk2.dim("No stale tasks available to steal."));
20602
+ return;
20603
+ }
20604
+ if (globalOpts.json) {
20605
+ output(task, true);
20606
+ return;
20607
+ }
20608
+ console.log(chalk2.green(`Stolen: ${task.short_id || task.id.slice(0, 8)} | ${task.priority} | ${task.title}`));
19760
20609
  });
19761
20610
  program2.command("status").description("Show full project health snapshot").option("--agent <id>", "Include next task for this agent").option("--project <id>", "Filter to project").option("--json", "Output as JSON").action(async (opts) => {
19762
20611
  const db = getDatabase();
@@ -19768,24 +20617,24 @@ program2.command("status").description("Show full project health snapshot").opti
19768
20617
  console.log(JSON.stringify(s, null, 2));
19769
20618
  return;
19770
20619
  }
19771
- console.log(`Tasks: ${chalk.yellow(s.pending)} pending | ${chalk.blue(s.in_progress)} active | ${chalk.green(s.completed)} done | ${s.total} total`);
20620
+ console.log(`Tasks: ${chalk2.yellow(s.pending)} pending | ${chalk2.blue(s.in_progress)} active | ${chalk2.green(s.completed)} done | ${s.total} total`);
19772
20621
  if (s.stale_count > 0)
19773
- console.log(chalk.red(`\u26A0\uFE0F ${s.stale_count} stale tasks (stuck in_progress)`));
20622
+ console.log(chalk2.red(`\u26A0\uFE0F ${s.stale_count} stale tasks (stuck in_progress)`));
19774
20623
  if (s.overdue_recurring > 0)
19775
- console.log(chalk.yellow(`\uD83D\uDD01 ${s.overdue_recurring} overdue recurring`));
20624
+ console.log(chalk2.yellow(`\uD83D\uDD01 ${s.overdue_recurring} overdue recurring`));
19776
20625
  if (s.active_work.length > 0) {
19777
- console.log(chalk.bold(`
20626
+ console.log(chalk2.bold(`
19778
20627
  Active:`));
19779
20628
  for (const w of s.active_work.slice(0, 5)) {
19780
20629
  const id = w.short_id || w.id.slice(0, 8);
19781
- console.log(` ${chalk.cyan(id)} | ${w.assigned_to || w.locked_by || "?"} | ${w.title}`);
20630
+ console.log(` ${chalk2.cyan(id)} | ${w.assigned_to || w.locked_by || "?"} | ${w.title}`);
19782
20631
  }
19783
20632
  }
19784
20633
  if (s.next_task) {
19785
- console.log(chalk.bold(`
20634
+ console.log(chalk2.bold(`
19786
20635
  Next up:`));
19787
20636
  const t = s.next_task;
19788
- console.log(` ${chalk.cyan(t.short_id || t.id.slice(0, 8))} ${chalk.yellow(t.priority)} ${t.title}`);
20637
+ console.log(` ${chalk2.cyan(t.short_id || t.id.slice(0, 8))} ${chalk2.yellow(t.priority)} ${t.title}`);
19789
20638
  }
19790
20639
  });
19791
20640
  program2.command("recap").description("Show what happened in the last N hours \u2014 completed tasks, new tasks, agent activity, blockers").option("--hours <n>", "Look back N hours (default: 8)", "8").option("--project <id>", "Filter to project").action((opts) => {
@@ -19796,60 +20645,60 @@ program2.command("recap").description("Show what happened in the last N hours \u
19796
20645
  output(recap, true);
19797
20646
  return;
19798
20647
  }
19799
- console.log(chalk.bold(`
20648
+ console.log(chalk2.bold(`
19800
20649
  Recap \u2014 last ${recap.hours} hours (since ${new Date(recap.since).toLocaleString()})
19801
20650
  `));
19802
20651
  if (recap.completed.length > 0) {
19803
- console.log(chalk.green.bold(`Completed (${recap.completed.length}):`));
20652
+ console.log(chalk2.green.bold(`Completed (${recap.completed.length}):`));
19804
20653
  for (const t of recap.completed) {
19805
20654
  const id = t.short_id || t.id.slice(0, 8);
19806
20655
  const dur = t.duration_minutes != null ? ` (${t.duration_minutes}m)` : "";
19807
- console.log(` ${chalk.green("\u2713")} ${chalk.cyan(id)} ${t.title}${dur}${t.assigned_to ? ` \u2014 ${chalk.dim(t.assigned_to)}` : ""}`);
20656
+ console.log(` ${chalk2.green("\u2713")} ${chalk2.cyan(id)} ${t.title}${dur}${t.assigned_to ? ` \u2014 ${chalk2.dim(t.assigned_to)}` : ""}`);
19808
20657
  }
19809
20658
  } else {
19810
- console.log(chalk.dim("No tasks completed in this period."));
20659
+ console.log(chalk2.dim("No tasks completed in this period."));
19811
20660
  }
19812
20661
  if (recap.in_progress.length > 0) {
19813
- console.log(chalk.blue.bold(`
20662
+ console.log(chalk2.blue.bold(`
19814
20663
  In Progress (${recap.in_progress.length}):`));
19815
20664
  for (const t of recap.in_progress) {
19816
20665
  const id = t.short_id || t.id.slice(0, 8);
19817
- console.log(` ${chalk.blue("\u2192")} ${chalk.cyan(id)} ${t.title}${t.assigned_to ? ` \u2014 ${chalk.dim(t.assigned_to)}` : ""}`);
20666
+ console.log(` ${chalk2.blue("\u2192")} ${chalk2.cyan(id)} ${t.title}${t.assigned_to ? ` \u2014 ${chalk2.dim(t.assigned_to)}` : ""}`);
19818
20667
  }
19819
20668
  }
19820
20669
  if (recap.blocked.length > 0) {
19821
- console.log(chalk.red.bold(`
20670
+ console.log(chalk2.red.bold(`
19822
20671
  Blocked (${recap.blocked.length}):`));
19823
20672
  for (const t of recap.blocked) {
19824
20673
  const id = t.short_id || t.id.slice(0, 8);
19825
- console.log(` ${chalk.red("\u2717")} ${chalk.cyan(id)} ${t.title}`);
20674
+ console.log(` ${chalk2.red("\u2717")} ${chalk2.cyan(id)} ${t.title}`);
19826
20675
  }
19827
20676
  }
19828
20677
  if (recap.stale.length > 0) {
19829
- console.log(chalk.yellow.bold(`
20678
+ console.log(chalk2.yellow.bold(`
19830
20679
  Stale (${recap.stale.length}):`));
19831
20680
  for (const t of recap.stale) {
19832
20681
  const id = t.short_id || t.id.slice(0, 8);
19833
20682
  const ago = Math.round((Date.now() - new Date(t.updated_at).getTime()) / 60000);
19834
- console.log(` ${chalk.yellow("!")} ${chalk.cyan(id)} ${t.title} \u2014 last update ${ago}m ago`);
20683
+ console.log(` ${chalk2.yellow("!")} ${chalk2.cyan(id)} ${t.title} \u2014 last update ${ago}m ago`);
19835
20684
  }
19836
20685
  }
19837
20686
  if (recap.created.length > 0) {
19838
- console.log(chalk.dim.bold(`
20687
+ console.log(chalk2.dim.bold(`
19839
20688
  Created (${recap.created.length}):`));
19840
20689
  for (const t of recap.created.slice(0, 10)) {
19841
20690
  const id = t.short_id || t.id.slice(0, 8);
19842
- console.log(` ${chalk.dim("+")} ${chalk.cyan(id)} ${t.title}`);
20691
+ console.log(` ${chalk2.dim("+")} ${chalk2.cyan(id)} ${t.title}`);
19843
20692
  }
19844
20693
  if (recap.created.length > 10)
19845
- console.log(chalk.dim(` ... and ${recap.created.length - 10} more`));
20694
+ console.log(chalk2.dim(` ... and ${recap.created.length - 10} more`));
19846
20695
  }
19847
20696
  if (recap.agents.length > 0) {
19848
- console.log(chalk.bold(`
20697
+ console.log(chalk2.bold(`
19849
20698
  Agents:`));
19850
20699
  for (const a of recap.agents) {
19851
20700
  const seen = Math.round((Date.now() - new Date(a.last_seen_at).getTime()) / 60000);
19852
- console.log(` ${a.name}: ${chalk.green(a.completed_count + " done")} | ${chalk.blue(a.in_progress_count + " active")} | last seen ${seen}m ago`);
20701
+ console.log(` ${a.name}: ${chalk2.green(a.completed_count + " done")} | ${chalk2.blue(a.in_progress_count + " active")} | last seen ${seen}m ago`);
19853
20702
  }
19854
20703
  }
19855
20704
  console.log();
@@ -19864,7 +20713,7 @@ program2.command("standup").description("Generate standup notes \u2014 completed
19864
20713
  output(recap, true);
19865
20714
  return;
19866
20715
  }
19867
- console.log(chalk.bold(`
20716
+ console.log(chalk2.bold(`
19868
20717
  Standup \u2014 since ${sinceDate.toLocaleDateString()}
19869
20718
  `));
19870
20719
  const byAgent = new Map;
@@ -19875,29 +20724,29 @@ Standup \u2014 since ${sinceDate.toLocaleDateString()}
19875
20724
  byAgent.get(agent).push(t);
19876
20725
  }
19877
20726
  if (byAgent.size > 0) {
19878
- console.log(chalk.green.bold("Done:"));
20727
+ console.log(chalk2.green.bold("Done:"));
19879
20728
  for (const [agent, tasks] of byAgent) {
19880
- console.log(` ${chalk.cyan(agent)}:`);
20729
+ console.log(` ${chalk2.cyan(agent)}:`);
19881
20730
  for (const t of tasks) {
19882
20731
  const dur = t.duration_minutes != null ? ` (${t.duration_minutes}m)` : "";
19883
- console.log(` ${chalk.green("\u2713")} ${t.short_id || t.id.slice(0, 8)} ${t.title}${dur}`);
20732
+ console.log(` ${chalk2.green("\u2713")} ${t.short_id || t.id.slice(0, 8)} ${t.title}${dur}`);
19884
20733
  }
19885
20734
  }
19886
20735
  } else {
19887
- console.log(chalk.dim("Nothing completed."));
20736
+ console.log(chalk2.dim("Nothing completed."));
19888
20737
  }
19889
20738
  if (recap.in_progress.length > 0) {
19890
- console.log(chalk.blue.bold(`
20739
+ console.log(chalk2.blue.bold(`
19891
20740
  In Progress:`));
19892
20741
  for (const t of recap.in_progress) {
19893
- console.log(` ${chalk.blue("\u2192")} ${t.short_id || t.id.slice(0, 8)} ${t.title}${t.assigned_to ? ` \u2014 ${chalk.dim(t.assigned_to)}` : ""}`);
20742
+ console.log(` ${chalk2.blue("\u2192")} ${t.short_id || t.id.slice(0, 8)} ${t.title}${t.assigned_to ? ` \u2014 ${chalk2.dim(t.assigned_to)}` : ""}`);
19894
20743
  }
19895
20744
  }
19896
20745
  if (recap.blocked.length > 0) {
19897
- console.log(chalk.red.bold(`
20746
+ console.log(chalk2.red.bold(`
19898
20747
  Blocked:`));
19899
20748
  for (const t of recap.blocked) {
19900
- console.log(` ${chalk.red("\u2717")} ${t.short_id || t.id.slice(0, 8)} ${t.title}`);
20749
+ console.log(` ${chalk2.red("\u2717")} ${t.short_id || t.id.slice(0, 8)} ${t.title}`);
19901
20750
  }
19902
20751
  }
19903
20752
  console.log();
@@ -19906,7 +20755,7 @@ program2.command("fail <id>").description("Mark a task as failed with optional r
19906
20755
  const db = getDatabase();
19907
20756
  const resolvedId = resolvePartialId(db, "tasks", id);
19908
20757
  if (!resolvedId) {
19909
- console.error(chalk.red(`Task not found: ${id}`));
20758
+ console.error(chalk2.red(`Task not found: ${id}`));
19910
20759
  process.exit(1);
19911
20760
  }
19912
20761
  const result = failTask(resolvedId, opts.agent, opts.reason, { retry: opts.retry }, db);
@@ -19914,11 +20763,11 @@ program2.command("fail <id>").description("Mark a task as failed with optional r
19914
20763
  console.log(JSON.stringify(result, null, 2));
19915
20764
  return;
19916
20765
  }
19917
- console.log(chalk.red(`Failed: ${result.task.short_id || result.task.id.slice(0, 8)} | ${result.task.title}`));
20766
+ console.log(chalk2.red(`Failed: ${result.task.short_id || result.task.id.slice(0, 8)} | ${result.task.title}`));
19918
20767
  if (opts.reason)
19919
- console.log(chalk.dim(`Reason: ${opts.reason}`));
20768
+ console.log(chalk2.dim(`Reason: ${opts.reason}`));
19920
20769
  if (result.retryTask)
19921
- console.log(chalk.yellow(`Retry created: ${result.retryTask.short_id || result.retryTask.id.slice(0, 8)} | ${result.retryTask.title}`));
20770
+ console.log(chalk2.yellow(`Retry created: ${result.retryTask.short_id || result.retryTask.id.slice(0, 8)} | ${result.retryTask.title}`));
19922
20771
  });
19923
20772
  program2.command("active").description("Show all currently in-progress tasks").option("--project <id>", "Filter to project").option("--json", "Output as JSON").action(async (opts) => {
19924
20773
  const db = getDatabase();
@@ -19931,14 +20780,14 @@ program2.command("active").description("Show all currently in-progress tasks").o
19931
20780
  return;
19932
20781
  }
19933
20782
  if (work.length === 0) {
19934
- console.log(chalk.dim("No active work."));
20783
+ console.log(chalk2.dim("No active work."));
19935
20784
  return;
19936
20785
  }
19937
- console.log(chalk.bold(`Active work (${work.length}):`));
20786
+ console.log(chalk2.bold(`Active work (${work.length}):`));
19938
20787
  for (const w of work) {
19939
20788
  const id = w.short_id || w.id.slice(0, 8);
19940
20789
  const agent = w.assigned_to || w.locked_by || "unassigned";
19941
- console.log(` ${chalk.cyan(id)} | ${chalk.yellow(w.priority)} | ${agent.padEnd(12)} | ${w.title}`);
20790
+ console.log(` ${chalk2.cyan(id)} | ${chalk2.yellow(w.priority)} | ${agent.padEnd(12)} | ${w.title}`);
19942
20791
  }
19943
20792
  });
19944
20793
  program2.command("stale").description("Find tasks stuck in_progress with no recent activity").option("--minutes <n>", "Stale threshold in minutes", "30").option("--project <id>", "Filter to project").option("--json", "Output as JSON").action(async (opts) => {
@@ -19952,14 +20801,14 @@ program2.command("stale").description("Find tasks stuck in_progress with no rece
19952
20801
  return;
19953
20802
  }
19954
20803
  if (tasks.length === 0) {
19955
- console.log(chalk.dim("No stale tasks."));
20804
+ console.log(chalk2.dim("No stale tasks."));
19956
20805
  return;
19957
20806
  }
19958
- console.log(chalk.bold(`Stale tasks (${tasks.length}):`));
20807
+ console.log(chalk2.bold(`Stale tasks (${tasks.length}):`));
19959
20808
  for (const t of tasks) {
19960
20809
  const id = t.short_id || t.id.slice(0, 8);
19961
20810
  const staleMin = Math.round((Date.now() - new Date(t.updated_at).getTime()) / 60000);
19962
- console.log(` ${chalk.cyan(id)} | ${t.locked_by || t.assigned_to || "?"} | ${t.title} ${chalk.dim(`(${staleMin}min stale)`)}`);
20811
+ console.log(` ${chalk2.cyan(id)} | ${t.locked_by || t.assigned_to || "?"} | ${t.title} ${chalk2.dim(`(${staleMin}min stale)`)}`);
19963
20812
  }
19964
20813
  });
19965
20814
  program2.command("redistribute <agent>").description("Release stale in-progress tasks and claim the best one (work-stealing)").option("--max-age <minutes>", "Stale threshold in minutes", "60").option("--project <id>", "Limit to a specific project").option("--limit <n>", "Max stale tasks to release").option("--json", "Output as JSON").action(async (agent, opts) => {
@@ -19975,17 +20824,17 @@ program2.command("redistribute <agent>").description("Release stale in-progress
19975
20824
  console.log(JSON.stringify(result, null, 2));
19976
20825
  return;
19977
20826
  }
19978
- console.log(chalk.bold(`Released ${result.released.length} stale task(s).`));
20827
+ console.log(chalk2.bold(`Released ${result.released.length} stale task(s).`));
19979
20828
  for (const t of result.released) {
19980
20829
  const id = t.short_id || t.id.slice(0, 8);
19981
- console.log(` ${chalk.yellow("released")} ${chalk.cyan(id)} ${t.title}`);
20830
+ console.log(` ${chalk2.yellow("released")} ${chalk2.cyan(id)} ${t.title}`);
19982
20831
  }
19983
20832
  if (result.claimed) {
19984
20833
  const id = result.claimed.short_id || result.claimed.id.slice(0, 8);
19985
- console.log(chalk.green(`
19986
- Claimed: ${chalk.cyan(id)} ${result.claimed.title}`));
20834
+ console.log(chalk2.green(`
20835
+ Claimed: ${chalk2.cyan(id)} ${result.claimed.title}`));
19987
20836
  } else {
19988
- console.log(chalk.dim(`
20837
+ console.log(chalk2.dim(`
19989
20838
  No task claimed (nothing available).`));
19990
20839
  }
19991
20840
  });
@@ -19995,7 +20844,7 @@ program2.command("assign <id> <agent>").description("Assign a task to an agent")
19995
20844
  const db = getDatabase();
19996
20845
  const task = getTask(resolvedId, db);
19997
20846
  if (!task) {
19998
- console.error(chalk.red(`Task not found: ${id}`));
20847
+ console.error(chalk2.red(`Task not found: ${id}`));
19999
20848
  process.exit(1);
20000
20849
  }
20001
20850
  try {
@@ -20004,7 +20853,7 @@ program2.command("assign <id> <agent>").description("Assign a task to an agent")
20004
20853
  console.log(JSON.stringify(updated));
20005
20854
  return;
20006
20855
  }
20007
- console.log(chalk.green(`Assigned to ${agent}: ${formatTaskLine(updated)}`));
20856
+ console.log(chalk2.green(`Assigned to ${agent}: ${formatTaskLine(updated)}`));
20008
20857
  } catch {
20009
20858
  handleError(new Error("Failed to assign"));
20010
20859
  }
@@ -20015,7 +20864,7 @@ program2.command("unassign <id>").description("Remove task assignment").option("
20015
20864
  const db = getDatabase();
20016
20865
  const task = getTask(resolvedId, db);
20017
20866
  if (!task) {
20018
- console.error(chalk.red(`Task not found: ${id}`));
20867
+ console.error(chalk2.red(`Task not found: ${id}`));
20019
20868
  process.exit(1);
20020
20869
  }
20021
20870
  try {
@@ -20024,7 +20873,7 @@ program2.command("unassign <id>").description("Remove task assignment").option("
20024
20873
  console.log(JSON.stringify(updated));
20025
20874
  return;
20026
20875
  }
20027
- console.log(chalk.green(`Unassigned: ${formatTaskLine(updated)}`));
20876
+ console.log(chalk2.green(`Unassigned: ${formatTaskLine(updated)}`));
20028
20877
  } catch {
20029
20878
  handleError(new Error("Failed to unassign"));
20030
20879
  }
@@ -20035,7 +20884,7 @@ program2.command("tag <id> <tag>").description("Add a tag to a task").option("--
20035
20884
  const db = getDatabase();
20036
20885
  const task = getTask(resolvedId, db);
20037
20886
  if (!task) {
20038
- console.error(chalk.red(`Task not found: ${id}`));
20887
+ console.error(chalk2.red(`Task not found: ${id}`));
20039
20888
  process.exit(1);
20040
20889
  }
20041
20890
  const newTags = [...new Set([...task.tags, tag])];
@@ -20045,7 +20894,7 @@ program2.command("tag <id> <tag>").description("Add a tag to a task").option("--
20045
20894
  console.log(JSON.stringify(updated));
20046
20895
  return;
20047
20896
  }
20048
- console.log(chalk.green(`Tagged [${tag}]: ${formatTaskLine(updated)}`));
20897
+ console.log(chalk2.green(`Tagged [${tag}]: ${formatTaskLine(updated)}`));
20049
20898
  } catch {
20050
20899
  handleError(new Error("Failed to tag"));
20051
20900
  }
@@ -20056,7 +20905,7 @@ program2.command("untag <id> <tag>").description("Remove a tag from a task").opt
20056
20905
  const db = getDatabase();
20057
20906
  const task = getTask(resolvedId, db);
20058
20907
  if (!task) {
20059
- console.error(chalk.red(`Task not found: ${id}`));
20908
+ console.error(chalk2.red(`Task not found: ${id}`));
20060
20909
  process.exit(1);
20061
20910
  }
20062
20911
  const newTags = task.tags.filter((t) => t !== tag);
@@ -20066,7 +20915,7 @@ program2.command("untag <id> <tag>").description("Remove a tag from a task").opt
20066
20915
  console.log(JSON.stringify(updated));
20067
20916
  return;
20068
20917
  }
20069
- console.log(chalk.green(`Untagged [${tag}]: ${formatTaskLine(updated)}`));
20918
+ console.log(chalk2.green(`Untagged [${tag}]: ${formatTaskLine(updated)}`));
20070
20919
  } catch {
20071
20920
  handleError(new Error("Failed to untag"));
20072
20921
  }
@@ -20082,7 +20931,7 @@ program2.command("pin <id>").description("Escalate task to critical priority").o
20082
20931
  console.log(JSON.stringify(updated));
20083
20932
  return;
20084
20933
  }
20085
- console.log(chalk.red(`\uD83D\uDCCC Pinned (critical): ${formatTaskLine(updated)}`));
20934
+ console.log(chalk2.red(`\uD83D\uDCCC Pinned (critical): ${formatTaskLine(updated)}`));
20086
20935
  } catch {
20087
20936
  handleError(new Error("Failed to pin"));
20088
20937
  }
@@ -20169,19 +21018,19 @@ program2.command("doctor").description("Diagnose common task data issues").optio
20169
21018
  console.log(JSON.stringify({ issues, ok: !issues.some((i) => i.severity === "error") }));
20170
21019
  return;
20171
21020
  }
20172
- console.log(chalk.bold(`todos doctor
21021
+ console.log(chalk2.bold(`todos doctor
20173
21022
  `));
20174
21023
  for (const issue of issues) {
20175
- const icon = issue.severity === "error" ? chalk.red("\u2717") : issue.severity === "warn" ? chalk.yellow("\u26A0") : chalk.green("\u2713");
21024
+ const icon = issue.severity === "error" ? chalk2.red("\u2717") : issue.severity === "warn" ? chalk2.yellow("\u26A0") : chalk2.green("\u2713");
20176
21025
  console.log(` ${icon} ${issue.message}`);
20177
21026
  }
20178
21027
  const errors2 = issues.filter((i) => i.severity === "error").length;
20179
21028
  const warns = issues.filter((i) => i.severity === "warn").length;
20180
21029
  if (errors2 === 0 && warns === 0)
20181
- console.log(chalk.green(`
21030
+ console.log(chalk2.green(`
20182
21031
  All clear.`));
20183
21032
  else
20184
- console.log(chalk[errors2 > 0 ? "red" : "yellow"](`
21033
+ console.log(chalk2[errors2 > 0 ? "red" : "yellow"](`
20185
21034
  ${errors2} error(s), ${warns} warning(s). Run with --fix to auto-resolve where possible.`));
20186
21035
  });
20187
21036
  program2.command("health").description("Check todos system health \u2014 database, config, connectivity").option("--json", "Output as JSON").action(async (opts) => {
@@ -20196,7 +21045,7 @@ program2.command("health").description("Check todos system health \u2014 databas
20196
21045
  try {
20197
21046
  size = `${(statSync3(dbPath).size / 1024 / 1024).toFixed(1)} MB`;
20198
21047
  } catch {}
20199
- checks.push({ name: "Database", ok: true, message: `${row.count} tasks \xB7 ${size} \xB7 ${chalk.dim(dbPath)}` });
21048
+ checks.push({ name: "Database", ok: true, message: `${row.count} tasks \xB7 ${size} \xB7 ${chalk2.dim(dbPath)}` });
20200
21049
  } catch (e) {
20201
21050
  checks.push({ name: "Database", ok: false, message: e instanceof Error ? e.message : "Failed" });
20202
21051
  }
@@ -20229,15 +21078,15 @@ program2.command("health").description("Check todos system health \u2014 databas
20229
21078
  console.log(JSON.stringify({ ok, checks }));
20230
21079
  return;
20231
21080
  }
20232
- console.log(chalk.bold(`todos health
21081
+ console.log(chalk2.bold(`todos health
20233
21082
  `));
20234
21083
  for (const c of checks) {
20235
- const icon = c.ok ? chalk.green("\u2713") : chalk.yellow("\u26A0");
21084
+ const icon = c.ok ? chalk2.green("\u2713") : chalk2.yellow("\u26A0");
20236
21085
  console.log(` ${icon} ${c.name.padEnd(14)} ${c.message}`);
20237
21086
  }
20238
21087
  const allOk = checks.every((c) => c.ok);
20239
21088
  console.log(`
20240
- ${allOk ? chalk.green("All checks passed.") : chalk.yellow("Some checks need attention.")}`);
21089
+ ${allOk ? chalk2.green("All checks passed.") : chalk2.yellow("Some checks need attention.")}`);
20241
21090
  });
20242
21091
  program2.command("report").description("Analytics report: task activity, completion rates, agent breakdown").option("--days <n>", "Days to include in report", "7").option("--project <id>", "Filter to project").option("--markdown", "Output as markdown").option("--json", "Output as JSON").action(async (opts) => {
20243
21092
  const globalOpts = program2.opts();
@@ -20286,15 +21135,15 @@ program2.command("report").description("Analytics report: task activity, complet
20286
21135
  if (sparkline)
20287
21136
  lines.push(`| Activity | \`${sparkline}\` |`);
20288
21137
  } else {
20289
- lines.push(chalk.bold(`todos report \u2014 last ${days} day${days !== 1 ? "s" : ""}`));
21138
+ lines.push(chalk2.bold(`todos report \u2014 last ${days} day${days !== 1 ? "s" : ""}`));
20290
21139
  lines.push("");
20291
- lines.push(` Total: ${chalk.bold(String(all.length))} tasks (${chalk.yellow(String(stats.pending))} pending, ${chalk.blue(String(stats.in_progress))} active)`);
20292
- lines.push(` Changed: ${chalk.bold(String(changed.length))} in period`);
20293
- lines.push(` Completed: ${chalk.green(String(completed.length))} (${completionRate}% rate)`);
21140
+ lines.push(` Total: ${chalk2.bold(String(all.length))} tasks (${chalk2.yellow(String(stats.pending))} pending, ${chalk2.blue(String(stats.in_progress))} active)`);
21141
+ lines.push(` Changed: ${chalk2.bold(String(changed.length))} in period`);
21142
+ lines.push(` Completed: ${chalk2.green(String(completed.length))} (${completionRate}% rate)`);
20294
21143
  if (failed.length > 0)
20295
- lines.push(` Failed: ${chalk.red(String(failed.length))}`);
21144
+ lines.push(` Failed: ${chalk2.red(String(failed.length))}`);
20296
21145
  if (sparkline)
20297
- lines.push(` Activity: ${chalk.dim(sparkline)}`);
21146
+ lines.push(` Activity: ${chalk2.dim(sparkline)}`);
20298
21147
  if (Object.keys(byAgent).length > 0) {
20299
21148
  lines.push(` By agent: ${Object.entries(byAgent).map(([a, n]) => `${a}=${n}`).join(" ")}`);
20300
21149
  }
@@ -20318,21 +21167,21 @@ program2.command("today").description("Show task activity from today").option("-
20318
21167
  console.log(JSON.stringify({ date: start.toISOString().slice(0, 10), completed, started, changed: other }));
20319
21168
  return;
20320
21169
  }
20321
- console.log(chalk.bold(`Today \u2014 ${start.toISOString().slice(0, 10)}
21170
+ console.log(chalk2.bold(`Today \u2014 ${start.toISOString().slice(0, 10)}
20322
21171
  `));
20323
21172
  if (completed.length > 0) {
20324
- console.log(chalk.green(` \u2713 Completed (${completed.length}):`));
21173
+ console.log(chalk2.green(` \u2713 Completed (${completed.length}):`));
20325
21174
  for (const t of completed)
20326
- console.log(` ${chalk.cyan(t.short_id || t.id.slice(0, 8))} ${t.title}${t.assigned_to ? chalk.dim(` \u2014 ${t.assigned_to}`) : ""}`);
21175
+ console.log(` ${chalk2.cyan(t.short_id || t.id.slice(0, 8))} ${t.title}${t.assigned_to ? chalk2.dim(` \u2014 ${t.assigned_to}`) : ""}`);
20327
21176
  }
20328
21177
  if (started.length > 0) {
20329
- console.log(chalk.blue(`
21178
+ console.log(chalk2.blue(`
20330
21179
  \u25B6 Started (${started.length}):`));
20331
21180
  for (const t of started)
20332
- console.log(` ${chalk.cyan(t.short_id || t.id.slice(0, 8))} ${t.title}${t.assigned_to ? chalk.dim(` \u2014 ${t.assigned_to}`) : ""}`);
21181
+ console.log(` ${chalk2.cyan(t.short_id || t.id.slice(0, 8))} ${t.title}${t.assigned_to ? chalk2.dim(` \u2014 ${t.assigned_to}`) : ""}`);
20333
21182
  }
20334
21183
  if (completed.length === 0 && started.length === 0)
20335
- console.log(chalk.dim(" No activity today."));
21184
+ console.log(chalk2.dim(" No activity today."));
20336
21185
  });
20337
21186
  program2.command("yesterday").description("Show task activity from yesterday").option("--json", "Output as JSON").action(async (opts) => {
20338
21187
  const globalOpts = program2.opts();
@@ -20351,21 +21200,21 @@ program2.command("yesterday").description("Show task activity from yesterday").o
20351
21200
  console.log(JSON.stringify({ date: start.toISOString().slice(0, 10), completed, started }));
20352
21201
  return;
20353
21202
  }
20354
- console.log(chalk.bold(`Yesterday \u2014 ${start.toISOString().slice(0, 10)}
21203
+ console.log(chalk2.bold(`Yesterday \u2014 ${start.toISOString().slice(0, 10)}
20355
21204
  `));
20356
21205
  if (completed.length > 0) {
20357
- console.log(chalk.green(` \u2713 Completed (${completed.length}):`));
21206
+ console.log(chalk2.green(` \u2713 Completed (${completed.length}):`));
20358
21207
  for (const t of completed)
20359
- console.log(` ${chalk.cyan(t.short_id || t.id.slice(0, 8))} ${t.title}${t.assigned_to ? chalk.dim(` \u2014 ${t.assigned_to}`) : ""}`);
21208
+ console.log(` ${chalk2.cyan(t.short_id || t.id.slice(0, 8))} ${t.title}${t.assigned_to ? chalk2.dim(` \u2014 ${t.assigned_to}`) : ""}`);
20360
21209
  }
20361
21210
  if (started.length > 0) {
20362
- console.log(chalk.blue(`
21211
+ console.log(chalk2.blue(`
20363
21212
  \u25B6 Started (${started.length}):`));
20364
21213
  for (const t of started)
20365
- console.log(` ${chalk.cyan(t.short_id || t.id.slice(0, 8))} ${t.title}`);
21214
+ console.log(` ${chalk2.cyan(t.short_id || t.id.slice(0, 8))} ${t.title}`);
20366
21215
  }
20367
21216
  if (completed.length === 0 && started.length === 0)
20368
- console.log(chalk.dim(" No activity yesterday."));
21217
+ console.log(chalk2.dim(" No activity yesterday."));
20369
21218
  });
20370
21219
  program2.command("mine").description("Show tasks assigned to you, grouped by status").argument("<agent>", "Agent name or ID").option("--json", "Output as JSON").action(async (agent, opts) => {
20371
21220
  const globalOpts = program2.opts();
@@ -20400,23 +21249,23 @@ program2.command("mine").description("Show tasks assigned to you, grouped by sta
20400
21249
  }
20401
21250
  const statusOrder = ["in_progress", "pending", "blocked", "completed", "failed", "cancelled"];
20402
21251
  const statusIcons2 = { in_progress: "\u25B6", pending: "\u25CB", blocked: "\u2298", completed: "\u2713", failed: "\u2717", cancelled: "\u2014" };
20403
- const statusColors5 = { in_progress: chalk.blue, pending: chalk.white, blocked: chalk.red, completed: chalk.green, failed: chalk.red, cancelled: chalk.dim };
20404
- console.log(chalk.bold(`Tasks for ${agent} (${tasks.length} total):
21252
+ const statusColors5 = { in_progress: chalk2.blue, pending: chalk2.white, blocked: chalk2.red, completed: chalk2.green, failed: chalk2.red, cancelled: chalk2.dim };
21253
+ console.log(chalk2.bold(`Tasks for ${agent} (${tasks.length} total):
20405
21254
  `));
20406
21255
  for (const status of statusOrder) {
20407
21256
  const group = groups[status];
20408
21257
  if (!group || group.length === 0)
20409
21258
  continue;
20410
- const color = statusColors5[status] || chalk.white;
21259
+ const color = statusColors5[status] || chalk2.white;
20411
21260
  const icon = statusIcons2[status] || "?";
20412
21261
  console.log(color(` ${icon} ${status.replace("_", " ")} (${group.length}):`));
20413
21262
  for (const t of group) {
20414
- const priority = t.priority === "critical" || t.priority === "high" ? chalk.red(` [${t.priority}]`) : "";
20415
- console.log(` ${chalk.cyan(t.short_id || t.id.slice(0, 8))} ${t.title}${priority}`);
21263
+ const priority = t.priority === "critical" || t.priority === "high" ? chalk2.red(` [${t.priority}]`) : "";
21264
+ console.log(` ${chalk2.cyan(t.short_id || t.id.slice(0, 8))} ${t.title}${priority}`);
20416
21265
  }
20417
21266
  }
20418
21267
  if (tasks.length === 0)
20419
- console.log(chalk.dim(` No tasks assigned to ${agent}.`));
21268
+ console.log(chalk2.dim(` No tasks assigned to ${agent}.`));
20420
21269
  });
20421
21270
  program2.command("blocked").description("Show tasks blocked by incomplete dependencies").option("--json", "Output as JSON").option("--project <id>", "Filter to project").action(async (opts) => {
20422
21271
  const globalOpts = program2.opts();
@@ -20438,15 +21287,15 @@ program2.command("blocked").description("Show tasks blocked by incomplete depend
20438
21287
  return;
20439
21288
  }
20440
21289
  if (blockedTasks.length === 0) {
20441
- console.log(chalk.green(" No blocked tasks!"));
21290
+ console.log(chalk2.green(" No blocked tasks!"));
20442
21291
  return;
20443
21292
  }
20444
- console.log(chalk.bold(`Blocked (${blockedTasks.length}):
21293
+ console.log(chalk2.bold(`Blocked (${blockedTasks.length}):
20445
21294
  `));
20446
21295
  for (const { task, blockers } of blockedTasks) {
20447
- console.log(` ${chalk.cyan(task.short_id || task.id.slice(0, 8))} ${task.title}`);
21296
+ console.log(` ${chalk2.cyan(task.short_id || task.id.slice(0, 8))} ${task.title}`);
20448
21297
  for (const bl of blockers) {
20449
- console.log(` ${chalk.red("\u2298")} ${chalk.dim(bl.short_id || bl.id.slice(0, 8))} ${chalk.dim(bl.title)} ${chalk.yellow(`[${bl.status}]`)}`);
21298
+ console.log(` ${chalk2.red("\u2298")} ${chalk2.dim(bl.short_id || bl.id.slice(0, 8))} ${chalk2.dim(bl.title)} ${chalk2.yellow(`[${bl.status}]`)}`);
20450
21299
  }
20451
21300
  }
20452
21301
  });
@@ -20460,16 +21309,16 @@ program2.command("overdue").description("Show tasks past their due date").option
20460
21309
  return;
20461
21310
  }
20462
21311
  if (tasks.length === 0) {
20463
- console.log(chalk.green(" No overdue tasks!"));
21312
+ console.log(chalk2.green(" No overdue tasks!"));
20464
21313
  return;
20465
21314
  }
20466
- console.log(chalk.bold.red(`Overdue (${tasks.length}):
21315
+ console.log(chalk2.bold.red(`Overdue (${tasks.length}):
20467
21316
  `));
20468
21317
  for (const t of tasks) {
20469
21318
  const dueDate = t.due_at.slice(0, 10);
20470
21319
  const daysOverdue = Math.floor((Date.now() - new Date(t.due_at).getTime()) / 86400000);
20471
- const urgency = daysOverdue > 7 ? chalk.bgRed.white(` ${daysOverdue}d `) : chalk.red(`${daysOverdue}d`);
20472
- console.log(` ${urgency} ${chalk.cyan(t.short_id || t.id.slice(0, 8))} ${t.title}${t.assigned_to ? chalk.dim(` \u2014 ${t.assigned_to}`) : ""} ${chalk.dim(`(due ${dueDate})`)}`);
21320
+ const urgency = daysOverdue > 7 ? chalk2.bgRed.white(` ${daysOverdue}d `) : chalk2.red(`${daysOverdue}d`);
21321
+ console.log(` ${urgency} ${chalk2.cyan(t.short_id || t.id.slice(0, 8))} ${t.title}${t.assigned_to ? chalk2.dim(` \u2014 ${t.assigned_to}`) : ""} ${chalk2.dim(`(due ${dueDate})`)}`);
20473
21322
  }
20474
21323
  });
20475
21324
  program2.command("week").description("Show task activity from the past 7 days").option("--json", "Output as JSON").action(async (opts) => {
@@ -20504,8 +21353,8 @@ program2.command("week").description("Show task activity from the past 7 days").
20504
21353
  }
20505
21354
  const totalCompleted = tasks.filter((t) => t.status === "completed").length;
20506
21355
  const totalStarted = tasks.filter((t) => t.status === "in_progress").length;
20507
- console.log(chalk.bold(`Week \u2014 ${start.toISOString().slice(0, 10)} to ${now2.toISOString().slice(0, 10)}`));
20508
- console.log(chalk.dim(` ${totalCompleted} completed, ${totalStarted} in progress, ${tasks.length} total changes
21356
+ console.log(chalk2.bold(`Week \u2014 ${start.toISOString().slice(0, 10)} to ${now2.toISOString().slice(0, 10)}`));
21357
+ console.log(chalk2.dim(` ${totalCompleted} completed, ${totalStarted} in progress, ${tasks.length} total changes
20509
21358
  `));
20510
21359
  const sortedDays = Object.keys(days).sort().reverse();
20511
21360
  for (const day of sortedDays) {
@@ -20516,14 +21365,14 @@ program2.command("week").description("Show task activity from the past 7 days").
20516
21365
  if (completed.length === 0 && started.length === 0)
20517
21366
  continue;
20518
21367
  const weekday = new Date(day + "T12:00:00").toLocaleDateString("en-US", { weekday: "short" });
20519
- console.log(chalk.bold(` ${weekday} ${day}`));
21368
+ console.log(chalk2.bold(` ${weekday} ${day}`));
20520
21369
  for (const t of completed)
20521
- console.log(` ${chalk.green("\u2713")} ${chalk.cyan(t.short_id || t.id.slice(0, 8))} ${t.title}${t.assigned_to ? chalk.dim(` \u2014 ${t.assigned_to}`) : ""}`);
21370
+ console.log(` ${chalk2.green("\u2713")} ${chalk2.cyan(t.short_id || t.id.slice(0, 8))} ${t.title}${t.assigned_to ? chalk2.dim(` \u2014 ${t.assigned_to}`) : ""}`);
20522
21371
  for (const t of started)
20523
- console.log(` ${chalk.blue("\u25B6")} ${chalk.cyan(t.short_id || t.id.slice(0, 8))} ${t.title}${t.assigned_to ? chalk.dim(` \u2014 ${t.assigned_to}`) : ""}`);
21372
+ console.log(` ${chalk2.blue("\u25B6")} ${chalk2.cyan(t.short_id || t.id.slice(0, 8))} ${t.title}${t.assigned_to ? chalk2.dim(` \u2014 ${t.assigned_to}`) : ""}`);
20524
21373
  }
20525
21374
  if (tasks.length === 0)
20526
- console.log(chalk.dim(" No activity this week."));
21375
+ console.log(chalk2.dim(" No activity this week."));
20527
21376
  });
20528
21377
  program2.command("burndown").description("Show task completion velocity over the past 7 days").option("--days <n>", "Number of days", "7").option("--json", "Output as JSON").action(async (opts) => {
20529
21378
  const globalOpts = program2.opts();
@@ -20551,20 +21400,20 @@ program2.command("burndown").description("Show task completion velocity over the
20551
21400
  }
20552
21401
  const maxVal = Math.max(...dayStats.map((d) => Math.max(d.completed, d.created)), 1);
20553
21402
  const barWidth = 30;
20554
- console.log(chalk.bold("Burndown (last " + numDays + ` days):
21403
+ console.log(chalk2.bold("Burndown (last " + numDays + ` days):
20555
21404
  `));
20556
- console.log(chalk.dim(" Date Done New Failed Chart"));
21405
+ console.log(chalk2.dim(" Date Done New Failed Chart"));
20557
21406
  for (const day of dayStats) {
20558
21407
  const weekday = new Date(day.date + "T12:00:00").toLocaleDateString("en-US", { weekday: "short" });
20559
- const completedBar = chalk.green("\u2588".repeat(Math.round(day.completed / maxVal * barWidth)));
20560
- const createdBar = chalk.blue("\u2591".repeat(Math.round(day.created / maxVal * barWidth)));
20561
- const failed = day.failed > 0 ? chalk.red(String(day.failed).padStart(4)) : chalk.dim(" 0");
20562
- console.log(` ${weekday} ${day.date.slice(5)} ${chalk.green(String(day.completed).padStart(4))} ${chalk.blue(String(day.created).padStart(4))} ${failed} ${completedBar}${createdBar}`);
21408
+ const completedBar = chalk2.green("\u2588".repeat(Math.round(day.completed / maxVal * barWidth)));
21409
+ const createdBar = chalk2.blue("\u2591".repeat(Math.round(day.created / maxVal * barWidth)));
21410
+ const failed = day.failed > 0 ? chalk2.red(String(day.failed).padStart(4)) : chalk2.dim(" 0");
21411
+ console.log(` ${weekday} ${day.date.slice(5)} ${chalk2.green(String(day.completed).padStart(4))} ${chalk2.blue(String(day.created).padStart(4))} ${failed} ${completedBar}${createdBar}`);
20563
21412
  }
20564
21413
  const totalCompleted = dayStats.reduce((s, d) => s + d.completed, 0);
20565
21414
  const totalCreated = dayStats.reduce((s, d) => s + d.created, 0);
20566
21415
  const velocity = (totalCompleted / numDays).toFixed(1);
20567
- console.log(chalk.dim(`
21416
+ console.log(chalk2.dim(`
20568
21417
  Velocity: ${velocity}/day \xB7 ${totalCompleted} done \xB7 ${totalCreated} created`));
20569
21418
  });
20570
21419
  program2.command("log").description("Show recent task activity log (git-log style)").option("--limit <n>", "Number of entries", "30").option("--json", "Output as JSON").action(async (opts) => {
@@ -20577,38 +21426,38 @@ program2.command("log").description("Show recent task activity log (git-log styl
20577
21426
  return;
20578
21427
  }
20579
21428
  if (entries.length === 0) {
20580
- console.log(chalk.dim(" No activity yet."));
21429
+ console.log(chalk2.dim(" No activity yet."));
20581
21430
  return;
20582
21431
  }
20583
21432
  const actionIcons = {
20584
- create: chalk.green("+"),
20585
- start: chalk.blue("\u25B6"),
20586
- complete: chalk.green("\u2713"),
20587
- fail: chalk.red("\u2717"),
20588
- update: chalk.yellow("~"),
20589
- approve: chalk.green("\u2605"),
20590
- lock: chalk.dim("\uD83D\uDD12"),
20591
- unlock: chalk.dim("\uD83D\uDD13")
21433
+ create: chalk2.green("+"),
21434
+ start: chalk2.blue("\u25B6"),
21435
+ complete: chalk2.green("\u2713"),
21436
+ fail: chalk2.red("\u2717"),
21437
+ update: chalk2.yellow("~"),
21438
+ approve: chalk2.green("\u2605"),
21439
+ lock: chalk2.dim("\uD83D\uDD12"),
21440
+ unlock: chalk2.dim("\uD83D\uDD13")
20592
21441
  };
20593
21442
  let lastDate = "";
20594
21443
  for (const e of entries) {
20595
21444
  const date = e.created_at.slice(0, 10);
20596
21445
  const time = e.created_at.slice(11, 16);
20597
21446
  if (date !== lastDate) {
20598
- console.log(chalk.bold(`
21447
+ console.log(chalk2.bold(`
20599
21448
  ${date}`));
20600
21449
  lastDate = date;
20601
21450
  }
20602
- const icon = actionIcons[e.action] || chalk.dim("\xB7");
20603
- const agent = e.agent_id ? chalk.dim(` (${e.agent_id})`) : "";
20604
- const taskRef = chalk.cyan(e.task_id.slice(0, 8));
21451
+ const icon = actionIcons[e.action] || chalk2.dim("\xB7");
21452
+ const agent = e.agent_id ? chalk2.dim(` (${e.agent_id})`) : "";
21453
+ const taskRef = chalk2.cyan(e.task_id.slice(0, 8));
20605
21454
  let detail = "";
20606
21455
  if (e.field && e.old_value && e.new_value) {
20607
- detail = chalk.dim(` ${e.field}: ${e.old_value} \u2192 ${e.new_value}`);
21456
+ detail = chalk2.dim(` ${e.field}: ${e.old_value} \u2192 ${e.new_value}`);
20608
21457
  } else if (e.field && e.new_value) {
20609
- detail = chalk.dim(` ${e.field}: ${e.new_value}`);
21458
+ detail = chalk2.dim(` ${e.field}: ${e.new_value}`);
20610
21459
  }
20611
- console.log(` ${chalk.dim(time)} ${icon} ${e.action.padEnd(8)} ${taskRef}${detail}${agent}`);
21460
+ console.log(` ${chalk2.dim(time)} ${icon} ${e.action.padEnd(8)} ${taskRef}${detail}${agent}`);
20612
21461
  }
20613
21462
  });
20614
21463
  program2.command("ready").description("Show all tasks ready to be claimed (pending, unblocked, unlocked)").option("--json", "Output as JSON").option("--project <id>", "Filter to project").option("--limit <n>", "Max tasks to show", "20").action(async (opts) => {
@@ -20633,15 +21482,15 @@ program2.command("ready").description("Show all tasks ready to be claimed (pendi
20633
21482
  return;
20634
21483
  }
20635
21484
  if (limited.length === 0) {
20636
- console.log(chalk.dim(" No tasks ready to claim."));
21485
+ console.log(chalk2.dim(" No tasks ready to claim."));
20637
21486
  return;
20638
21487
  }
20639
- console.log(chalk.bold(`Ready to claim (${ready.length}${ready.length > limited.length ? `, showing ${limited.length}` : ""}):
21488
+ console.log(chalk2.bold(`Ready to claim (${ready.length}${ready.length > limited.length ? `, showing ${limited.length}` : ""}):
20640
21489
  `));
20641
21490
  for (const t of limited) {
20642
- const pri = t.priority === "critical" ? chalk.bgRed.white(" CRIT ") : t.priority === "high" ? chalk.red("[high]") : t.priority === "medium" ? chalk.yellow("[med]") : "";
20643
- const due = t.due_at ? chalk.dim(` due ${t.due_at.slice(0, 10)}`) : "";
20644
- console.log(` ${chalk.cyan(t.short_id || t.id.slice(0, 8))} ${t.title} ${pri}${due}`);
21491
+ const pri = t.priority === "critical" ? chalk2.bgRed.white(" CRIT ") : t.priority === "high" ? chalk2.red("[high]") : t.priority === "medium" ? chalk2.yellow("[med]") : "";
21492
+ const due = t.due_at ? chalk2.dim(` due ${t.due_at.slice(0, 10)}`) : "";
21493
+ console.log(` ${chalk2.cyan(t.short_id || t.id.slice(0, 8))} ${t.title} ${pri}${due}`);
20645
21494
  }
20646
21495
  });
20647
21496
  program2.command("sprint").description("Sprint dashboard: in-progress, next up, blockers, and overdue").option("--json", "Output as JSON").option("--project <id>", "Filter to project").action(async (opts) => {
@@ -20668,41 +21517,41 @@ program2.command("sprint").description("Sprint dashboard: in-progress, next up,
20668
21517
  console.log(JSON.stringify({ in_progress: inProgress, next_up: nextUp, blocked, overdue }));
20669
21518
  return;
20670
21519
  }
20671
- console.log(chalk.bold(`Sprint Dashboard
21520
+ console.log(chalk2.bold(`Sprint Dashboard
20672
21521
  `));
20673
- console.log(chalk.blue(` \u25B6 In Progress (${inProgress.length}):`));
21522
+ console.log(chalk2.blue(` \u25B6 In Progress (${inProgress.length}):`));
20674
21523
  if (inProgress.length === 0)
20675
- console.log(chalk.dim(" (none)"));
21524
+ console.log(chalk2.dim(" (none)"));
20676
21525
  for (const t of inProgress) {
20677
- const agent = t.assigned_to ? chalk.dim(` \u2014 ${t.assigned_to}`) : "";
20678
- console.log(` ${chalk.cyan(t.short_id || t.id.slice(0, 8))} ${t.title}${agent}`);
21526
+ const agent = t.assigned_to ? chalk2.dim(` \u2014 ${t.assigned_to}`) : "";
21527
+ console.log(` ${chalk2.cyan(t.short_id || t.id.slice(0, 8))} ${t.title}${agent}`);
20679
21528
  }
20680
- console.log(chalk.white(`
21529
+ console.log(chalk2.white(`
20681
21530
  \u25CB Next Up (${nextUp.length}):`));
20682
21531
  if (nextUp.length === 0)
20683
- console.log(chalk.dim(" (none)"));
21532
+ console.log(chalk2.dim(" (none)"));
20684
21533
  for (const t of nextUp) {
20685
- const pri = t.priority === "critical" ? chalk.bgRed.white(" CRIT ") : t.priority === "high" ? chalk.red("[high]") : "";
20686
- console.log(` ${chalk.cyan(t.short_id || t.id.slice(0, 8))} ${t.title} ${pri}`);
21534
+ const pri = t.priority === "critical" ? chalk2.bgRed.white(" CRIT ") : t.priority === "high" ? chalk2.red("[high]") : "";
21535
+ console.log(` ${chalk2.cyan(t.short_id || t.id.slice(0, 8))} ${t.title} ${pri}`);
20687
21536
  }
20688
21537
  if (blocked.length > 0) {
20689
- console.log(chalk.red(`
21538
+ console.log(chalk2.red(`
20690
21539
  \u2298 Blocked (${blocked.length}):`));
20691
21540
  for (const { task, blockers } of blocked) {
20692
- console.log(` ${chalk.cyan(task.short_id || task.id.slice(0, 8))} ${task.title}`);
21541
+ console.log(` ${chalk2.cyan(task.short_id || task.id.slice(0, 8))} ${task.title}`);
20693
21542
  for (const bl of blockers)
20694
- console.log(` ${chalk.dim("\u2190 " + (bl.short_id || bl.id.slice(0, 8)) + " " + bl.title)} ${chalk.yellow(`[${bl.status}]`)}`);
21543
+ console.log(` ${chalk2.dim("\u2190 " + (bl.short_id || bl.id.slice(0, 8)) + " " + bl.title)} ${chalk2.yellow(`[${bl.status}]`)}`);
20695
21544
  }
20696
21545
  }
20697
21546
  if (overdue.length > 0) {
20698
- console.log(chalk.red(`
21547
+ console.log(chalk2.red(`
20699
21548
  \u26A0 Overdue (${overdue.length}):`));
20700
21549
  for (const t of overdue) {
20701
21550
  const daysOver = Math.floor((Date.now() - new Date(t.due_at).getTime()) / 86400000);
20702
- console.log(` ${chalk.red(`${daysOver}d`)} ${chalk.cyan(t.short_id || t.id.slice(0, 8))} ${t.title}`);
21551
+ console.log(` ${chalk2.red(`${daysOver}d`)} ${chalk2.cyan(t.short_id || t.id.slice(0, 8))} ${t.title}`);
20703
21552
  }
20704
21553
  }
20705
- console.log(chalk.dim(`
21554
+ console.log(chalk2.dim(`
20706
21555
  ${inProgress.length} active \xB7 ${pending.length} pending \xB7 ${blocked.length} blocked \xB7 ${overdue.length} overdue`));
20707
21556
  });
20708
21557
  program2.command("handoff").description("Create or view agent session handoffs").option("--create", "Create a new handoff").option("--agent <name>", "Agent name").option("--summary <text>", "Handoff summary").option("--completed <items>", "Comma-separated completed items").option("--in-progress <items>", "Comma-separated in-progress items").option("--blockers <items>", "Comma-separated blockers").option("--next <items>", "Comma-separated next steps").option("--json", "Output as JSON").option("--limit <n>", "Number of handoffs to show", "5").action(async (opts) => {
@@ -20712,7 +21561,7 @@ program2.command("handoff").description("Create or view agent session handoffs")
20712
21561
  const projectId = autoProject(globalOpts) || undefined;
20713
21562
  if (opts.create || opts.summary) {
20714
21563
  if (!opts.summary) {
20715
- console.error(chalk.red(" --summary is required for creating a handoff"));
21564
+ console.error(chalk2.red(" --summary is required for creating a handoff"));
20716
21565
  process.exit(1);
20717
21566
  }
20718
21567
  const handoff = createHandoff2({
@@ -20728,7 +21577,7 @@ program2.command("handoff").description("Create or view agent session handoffs")
20728
21577
  console.log(JSON.stringify(handoff));
20729
21578
  return;
20730
21579
  }
20731
- console.log(chalk.green(` \u2713 Handoff created by ${handoff.agent_id || "unknown"}`));
21580
+ console.log(chalk2.green(` \u2713 Handoff created by ${handoff.agent_id || "unknown"}`));
20732
21581
  return;
20733
21582
  }
20734
21583
  const handoffs = listHandoffs2(projectId, parseInt(opts.limit, 10), db);
@@ -20737,31 +21586,31 @@ program2.command("handoff").description("Create or view agent session handoffs")
20737
21586
  return;
20738
21587
  }
20739
21588
  if (handoffs.length === 0) {
20740
- console.log(chalk.dim(" No handoffs yet."));
21589
+ console.log(chalk2.dim(" No handoffs yet."));
20741
21590
  return;
20742
21591
  }
20743
21592
  for (const h of handoffs) {
20744
21593
  const time = h.created_at.slice(0, 16).replace("T", " ");
20745
- console.log(chalk.bold(`
21594
+ console.log(chalk2.bold(`
20746
21595
  ${time} ${h.agent_id || "unknown"}`));
20747
21596
  console.log(` ${h.summary}`);
20748
21597
  if (h.completed?.length) {
20749
- console.log(chalk.green(` \u2713 Completed:`));
21598
+ console.log(chalk2.green(` \u2713 Completed:`));
20750
21599
  for (const c of h.completed)
20751
21600
  console.log(` - ${c}`);
20752
21601
  }
20753
21602
  if (h.in_progress?.length) {
20754
- console.log(chalk.blue(` \u25B6 In progress:`));
21603
+ console.log(chalk2.blue(` \u25B6 In progress:`));
20755
21604
  for (const c of h.in_progress)
20756
21605
  console.log(` - ${c}`);
20757
21606
  }
20758
21607
  if (h.blockers?.length) {
20759
- console.log(chalk.red(` \u2298 Blockers:`));
21608
+ console.log(chalk2.red(` \u2298 Blockers:`));
20760
21609
  for (const c of h.blockers)
20761
21610
  console.log(` - ${c}`);
20762
21611
  }
20763
21612
  if (h.next_steps?.length) {
20764
- console.log(chalk.cyan(` \u2192 Next steps:`));
21613
+ console.log(chalk2.cyan(` \u2192 Next steps:`));
20765
21614
  for (const c of h.next_steps)
20766
21615
  console.log(` - ${c}`);
20767
21616
  }
@@ -20787,16 +21636,16 @@ program2.command("priorities").description("Show task counts grouped by priority
20787
21636
  console.log(JSON.stringify(counts));
20788
21637
  return;
20789
21638
  }
20790
- console.log(chalk.bold(`Priority Breakdown:
21639
+ console.log(chalk2.bold(`Priority Breakdown:
20791
21640
  `));
20792
- const priColors = { critical: chalk.bgRed.white, high: chalk.red, medium: chalk.yellow, low: chalk.blue, none: chalk.dim };
21641
+ const priColors = { critical: chalk2.bgRed.white, high: chalk2.red, medium: chalk2.yellow, low: chalk2.blue, none: chalk2.dim };
20793
21642
  for (const p of priorities) {
20794
21643
  const c = counts[p];
20795
21644
  if (!c || c.total === 0)
20796
21645
  continue;
20797
- const color = priColors[p] || chalk.white;
20798
- const bar = chalk.green("\u2588".repeat(Math.min(c.completed, 30))) + chalk.blue("\u2591".repeat(Math.min(c.in_progress, 10))) + chalk.dim("\xB7".repeat(Math.min(c.pending, 20)));
20799
- console.log(` ${color(p.padEnd(9))} ${String(c.total).padStart(4)} total ${chalk.green(String(c.completed).padStart(3))} done ${chalk.blue(String(c.in_progress).padStart(3))} active ${chalk.dim(String(c.pending).padStart(3))} pending ${bar}`);
21646
+ const color = priColors[p] || chalk2.white;
21647
+ const bar = chalk2.green("\u2588".repeat(Math.min(c.completed, 30))) + chalk2.blue("\u2591".repeat(Math.min(c.in_progress, 10))) + chalk2.dim("\xB7".repeat(Math.min(c.pending, 20)));
21648
+ console.log(` ${color(p.padEnd(9))} ${String(c.total).padStart(4)} total ${chalk2.green(String(c.completed).padStart(3))} done ${chalk2.blue(String(c.in_progress).padStart(3))} active ${chalk2.dim(String(c.pending).padStart(3))} pending ${bar}`);
20800
21649
  }
20801
21650
  });
20802
21651
  program2.command("context").description("Session start context: status, latest handoff, next task, overdue").option("--agent <name>", "Agent name for handoff lookup").option("--json", "Output as JSON").action(async (opts) => {
@@ -20816,21 +21665,21 @@ program2.command("context").description("Session start context: status, latest h
20816
21665
  console.log(JSON.stringify({ status, next_task: nextTask, overdue_count: overdue.length, latest_handoff: handoff, as_of: new Date().toISOString() }));
20817
21666
  return;
20818
21667
  }
20819
- console.log(chalk.bold(`Session Context
21668
+ console.log(chalk2.bold(`Session Context
20820
21669
  `));
20821
21670
  console.log(` ${status.pending} pending \xB7 ${status.in_progress} active \xB7 ${status.completed} done \xB7 ${status.total} total`);
20822
21671
  if (status.stale_count > 0)
20823
- console.log(chalk.yellow(` \u26A0 ${status.stale_count} stale tasks`));
21672
+ console.log(chalk2.yellow(` \u26A0 ${status.stale_count} stale tasks`));
20824
21673
  if (overdue.length > 0)
20825
- console.log(chalk.red(` \u26A0 ${overdue.length} overdue tasks`));
21674
+ console.log(chalk2.red(` \u26A0 ${overdue.length} overdue tasks`));
20826
21675
  if (nextTask) {
20827
- const pri = nextTask.priority === "critical" || nextTask.priority === "high" ? chalk.red(` [${nextTask.priority}]`) : "";
20828
- console.log(chalk.bold(`
21676
+ const pri = nextTask.priority === "critical" || nextTask.priority === "high" ? chalk2.red(` [${nextTask.priority}]`) : "";
21677
+ console.log(chalk2.bold(`
20829
21678
  Next up:`));
20830
- console.log(` ${chalk.cyan(nextTask.short_id || nextTask.id.slice(0, 8))} ${nextTask.title}${pri}`);
21679
+ console.log(` ${chalk2.cyan(nextTask.short_id || nextTask.id.slice(0, 8))} ${nextTask.title}${pri}`);
20831
21680
  }
20832
21681
  if (handoff) {
20833
- console.log(chalk.bold(`
21682
+ console.log(chalk2.bold(`
20834
21683
  Last handoff (${handoff.agent_id || "unknown"}, ${handoff.created_at.slice(0, 16).replace("T", " ")}):`));
20835
21684
  console.log(` ${handoff.summary}`);
20836
21685
  if (handoff.next_steps?.length) {
@@ -20838,7 +21687,7 @@ program2.command("context").description("Session start context: status, latest h
20838
21687
  console.log(` \u2192 ${s}`);
20839
21688
  }
20840
21689
  }
20841
- console.log(chalk.dim(`
21690
+ console.log(chalk2.dim(`
20842
21691
  as_of: ${new Date().toISOString()}`));
20843
21692
  });
20844
21693
  program2.command("report-failure").description("Create a task from a test/build/typecheck failure and auto-assign it").requiredOption("--error <message>", "Error message or summary").option("--type <type>", "Failure type: test, build, typecheck, runtime, other", "test").option("--file <path>", "File where failure occurred").option("--stack <trace>", "Stack trace or detailed output").option("--title <title>", "Custom task title (auto-generated if omitted)").option("--priority <p>", "Priority: low, medium, high, critical").option("--json", "Output as JSON").action(async (opts) => {
@@ -20877,11 +21726,11 @@ ${opts.stack.slice(0, 1500)}
20877
21726
  console.log(JSON.stringify({ task_id: task.id, short_id: task.short_id, title: task.title, assigned_to: assignResult.agent_name, method: assignResult.method }));
20878
21727
  return;
20879
21728
  }
20880
- console.log(chalk.green(`\u2713 Created task ${task.short_id || task.id.slice(0, 8)}: ${task.title}`));
21729
+ console.log(chalk2.green(`\u2713 Created task ${task.short_id || task.id.slice(0, 8)}: ${task.title}`));
20881
21730
  if (assignResult.agent_name) {
20882
- console.log(chalk.cyan(` Assigned to: ${assignResult.agent_name} (via ${assignResult.method})`));
21731
+ console.log(chalk2.cyan(` Assigned to: ${assignResult.agent_name} (via ${assignResult.method})`));
20883
21732
  if (assignResult.reason)
20884
- console.log(chalk.dim(` Reason: ${assignResult.reason}`));
21733
+ console.log(chalk2.dim(` Reason: ${assignResult.reason}`));
20885
21734
  }
20886
21735
  });
20887
21736
  program2.action(async () => {
@@ -20898,4 +21747,5 @@ program2.action(async () => {
20898
21747
  program2.help();
20899
21748
  }
20900
21749
  });
21750
+ program2.addCommand(makeBrainsCommand());
20901
21751
  program2.parse();