@hasna/todos 0.9.28 → 0.9.30

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
@@ -2253,6 +2253,7 @@ function ensureSchema(db) {
2253
2253
  ensureColumn("tasks", "approved_at", "TEXT");
2254
2254
  ensureColumn("agents", "role", "TEXT DEFAULT 'agent'");
2255
2255
  ensureColumn("agents", "permissions", `TEXT DEFAULT '["*"]'`);
2256
+ ensureColumn("agents", "reports_to", "TEXT");
2256
2257
  ensureColumn("plans", "task_list_id", "TEXT");
2257
2258
  ensureColumn("plans", "agent_id", "TEXT");
2258
2259
  ensureIndex("CREATE INDEX IF NOT EXISTS idx_tasks_plan ON tasks(plan_id)");
@@ -2544,6 +2545,10 @@ var init_database = __esm(() => {
2544
2545
  ALTER TABLE agents ADD COLUMN permissions TEXT DEFAULT '["*"]';
2545
2546
 
2546
2547
  INSERT OR IGNORE INTO _migrations (id) VALUES (10);
2548
+ `,
2549
+ `
2550
+ ALTER TABLE agents ADD COLUMN reports_to TEXT;
2551
+ INSERT OR IGNORE INTO _migrations (id) VALUES (11);
2547
2552
  `
2548
2553
  ];
2549
2554
  });
@@ -3198,7 +3203,18 @@ function updateTask(id, input, db) {
3198
3203
  logTaskChange(id, "update", "assigned_to", task.assigned_to, input.assigned_to, agentId, d);
3199
3204
  if (input.approved_by !== undefined)
3200
3205
  logTaskChange(id, "approve", "approved_by", null, input.approved_by, agentId, d);
3201
- return getTask(id, d);
3206
+ return {
3207
+ ...task,
3208
+ ...Object.fromEntries(Object.entries(input).filter(([, v]) => v !== undefined)),
3209
+ tags: input.tags ?? task.tags,
3210
+ metadata: input.metadata ?? task.metadata,
3211
+ version: task.version + 1,
3212
+ updated_at: now(),
3213
+ completed_at: input.status === "completed" ? now() : task.completed_at,
3214
+ requires_approval: input.requires_approval !== undefined ? input.requires_approval : task.requires_approval,
3215
+ approved_by: input.approved_by ?? task.approved_by,
3216
+ approved_at: input.approved_by ? now() : task.approved_at
3217
+ };
3202
3218
  }
3203
3219
  function deleteTask(id, db) {
3204
3220
  const d = db || getDatabase();
@@ -3220,6 +3236,9 @@ function getBlockingDeps(id, db) {
3220
3236
  }
3221
3237
  function startTask(id, agentId, db) {
3222
3238
  const d = db || getDatabase();
3239
+ const task = getTask(id, d);
3240
+ if (!task)
3241
+ throw new TaskNotFoundError(id);
3223
3242
  const blocking = getBlockingDeps(id, d);
3224
3243
  if (blocking.length > 0) {
3225
3244
  const blockerIds = blocking.map((b) => b.id.slice(0, 8)).join(", ");
@@ -3230,15 +3249,12 @@ function startTask(id, agentId, db) {
3230
3249
  const result = d.run(`UPDATE tasks SET status = 'in_progress', assigned_to = ?, locked_by = ?, locked_at = ?, version = version + 1, updated_at = ?
3231
3250
  WHERE id = ? AND (locked_by IS NULL OR locked_by = ? OR locked_at < ?)`, [agentId, agentId, timestamp, timestamp, id, agentId, cutoff]);
3232
3251
  if (result.changes === 0) {
3233
- const current = getTask(id, d);
3234
- if (!current)
3235
- throw new TaskNotFoundError(id);
3236
- if (current.locked_by && current.locked_by !== agentId && !isLockExpired(current.locked_at)) {
3237
- throw new LockError(id, current.locked_by);
3252
+ if (task.locked_by && task.locked_by !== agentId && !isLockExpired(task.locked_at)) {
3253
+ throw new LockError(id, task.locked_by);
3238
3254
  }
3239
3255
  }
3240
3256
  logTaskChange(id, "start", "status", "pending", "in_progress", agentId, d);
3241
- return getTask(id, d);
3257
+ return { ...task, status: "in_progress", assigned_to: agentId, locked_by: agentId, locked_at: timestamp, version: task.version + 1, updated_at: timestamp };
3242
3258
  }
3243
3259
  function completeTask(id, agentId, db, evidence) {
3244
3260
  const d = db || getDatabase();
@@ -3250,14 +3266,15 @@ function completeTask(id, agentId, db, evidence) {
3250
3266
  }
3251
3267
  checkCompletionGuard(task, agentId || null, d);
3252
3268
  if (evidence) {
3253
- const meta = { ...task.metadata, _evidence: evidence };
3254
- d.run("UPDATE tasks SET metadata = ? WHERE id = ?", [JSON.stringify(meta), id]);
3269
+ const meta2 = { ...task.metadata, _evidence: evidence };
3270
+ d.run("UPDATE tasks SET metadata = ? WHERE id = ?", [JSON.stringify(meta2), id]);
3255
3271
  }
3256
3272
  const timestamp = now();
3257
3273
  d.run(`UPDATE tasks SET status = 'completed', locked_by = NULL, locked_at = NULL, completed_at = ?, version = version + 1, updated_at = ?
3258
3274
  WHERE id = ?`, [timestamp, timestamp, id]);
3259
3275
  logTaskChange(id, "complete", "status", task.status, "completed", agentId || null, d);
3260
- return getTask(id, d);
3276
+ const meta = evidence ? { ...task.metadata, _evidence: evidence } : task.metadata;
3277
+ return { ...task, status: "completed", locked_by: null, locked_at: null, completed_at: timestamp, version: task.version + 1, updated_at: timestamp, metadata: meta };
3261
3278
  }
3262
3279
  function lockTask(id, agentId, db) {
3263
3280
  const d = db || getDatabase();
@@ -3351,6 +3368,8 @@ __export(exports_agents, {
3351
3368
  updateAgent: () => updateAgent,
3352
3369
  registerAgent: () => registerAgent,
3353
3370
  listAgents: () => listAgents,
3371
+ getOrgChart: () => getOrgChart,
3372
+ getDirectReports: () => getDirectReports,
3354
3373
  getAgentByName: () => getAgentByName,
3355
3374
  getAgent: () => getAgent,
3356
3375
  deleteAgent: () => deleteAgent
@@ -3374,13 +3393,14 @@ function registerAgent(input, db) {
3374
3393
  }
3375
3394
  const id = shortUuid();
3376
3395
  const timestamp = now();
3377
- d.run(`INSERT INTO agents (id, name, description, role, permissions, metadata, created_at, last_seen_at)
3378
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [
3396
+ d.run(`INSERT INTO agents (id, name, description, role, permissions, reports_to, metadata, created_at, last_seen_at)
3397
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
3379
3398
  id,
3380
3399
  input.name,
3381
3400
  input.description || null,
3382
3401
  input.role || "agent",
3383
3402
  JSON.stringify(input.permissions || ["*"]),
3403
+ input.reports_to || null,
3384
3404
  JSON.stringify(input.metadata || {}),
3385
3405
  timestamp,
3386
3406
  timestamp
@@ -3428,6 +3448,10 @@ function updateAgent(id, input, db) {
3428
3448
  sets.push("permissions = ?");
3429
3449
  params.push(JSON.stringify(input.permissions));
3430
3450
  }
3451
+ if (input.reports_to !== undefined) {
3452
+ sets.push("reports_to = ?");
3453
+ params.push(input.reports_to);
3454
+ }
3431
3455
  if (input.metadata !== undefined) {
3432
3456
  sets.push("metadata = ?");
3433
3457
  params.push(JSON.stringify(input.metadata));
@@ -3440,6 +3464,25 @@ function deleteAgent(id, db) {
3440
3464
  const d = db || getDatabase();
3441
3465
  return d.run("DELETE FROM agents WHERE id = ?", [id]).changes > 0;
3442
3466
  }
3467
+ function getDirectReports(agentId, db) {
3468
+ const d = db || getDatabase();
3469
+ return d.query("SELECT * FROM agents WHERE reports_to = ? ORDER BY name").all(agentId).map(rowToAgent);
3470
+ }
3471
+ function getOrgChart(db) {
3472
+ const agents = listAgents(db);
3473
+ const byManager = new Map;
3474
+ for (const a of agents) {
3475
+ const key = a.reports_to;
3476
+ if (!byManager.has(key))
3477
+ byManager.set(key, []);
3478
+ byManager.get(key).push(a);
3479
+ }
3480
+ function buildTree(parentId) {
3481
+ const children = byManager.get(parentId) || [];
3482
+ return children.map((a) => ({ agent: a, reports: buildTree(a.id) }));
3483
+ }
3484
+ return buildTree(null);
3485
+ }
3443
3486
  var init_agents = __esm(() => {
3444
3487
  init_database();
3445
3488
  });
@@ -8363,22 +8406,22 @@ var init_mcp = __esm(() => {
8363
8406
  version: "0.9.15"
8364
8407
  });
8365
8408
  server.tool("create_task", "Create a new task", {
8366
- title: exports_external.string().describe("Task title"),
8367
- description: exports_external.string().optional().describe("Task description"),
8368
- project_id: exports_external.string().optional().describe("Project ID"),
8369
- parent_id: exports_external.string().optional().describe("Parent task ID (for subtasks)"),
8370
- priority: exports_external.enum(["low", "medium", "high", "critical"]).optional().describe("Task priority"),
8371
- status: exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"]).optional().describe("Initial status"),
8372
- agent_id: exports_external.string().optional().describe("Creator agent ID"),
8373
- assigned_to: exports_external.string().optional().describe("Assigned agent ID"),
8374
- session_id: exports_external.string().optional().describe("Session ID"),
8375
- working_dir: exports_external.string().optional().describe("Working directory context"),
8376
- plan_id: exports_external.string().optional().describe("Plan ID to assign task to"),
8377
- task_list_id: exports_external.string().optional().describe("Task list ID to assign task to"),
8378
- tags: exports_external.array(exports_external.string()).optional().describe("Task tags"),
8379
- metadata: exports_external.record(exports_external.unknown()).optional().describe("Arbitrary metadata"),
8380
- estimated_minutes: exports_external.number().optional().describe("Estimated time in minutes"),
8381
- requires_approval: exports_external.boolean().optional().describe("Require approval before completion")
8409
+ title: exports_external.string(),
8410
+ description: exports_external.string().optional(),
8411
+ project_id: exports_external.string().optional(),
8412
+ parent_id: exports_external.string().optional(),
8413
+ priority: exports_external.enum(["low", "medium", "high", "critical"]).optional(),
8414
+ status: exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"]).optional(),
8415
+ agent_id: exports_external.string().optional(),
8416
+ assigned_to: exports_external.string().optional(),
8417
+ session_id: exports_external.string().optional(),
8418
+ working_dir: exports_external.string().optional(),
8419
+ plan_id: exports_external.string().optional(),
8420
+ task_list_id: exports_external.string().optional(),
8421
+ tags: exports_external.array(exports_external.string()).optional(),
8422
+ metadata: exports_external.record(exports_external.unknown()).optional(),
8423
+ estimated_minutes: exports_external.number().optional(),
8424
+ requires_approval: exports_external.boolean().optional()
8382
8425
  }, async (params) => {
8383
8426
  try {
8384
8427
  const resolved = { ...params };
@@ -8397,19 +8440,19 @@ var init_mcp = __esm(() => {
8397
8440
  }
8398
8441
  });
8399
8442
  server.tool("list_tasks", "List tasks with optional filters", {
8400
- project_id: exports_external.string().optional().describe("Filter by project"),
8443
+ project_id: exports_external.string().optional(),
8401
8444
  status: exports_external.union([
8402
8445
  exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"]),
8403
8446
  exports_external.array(exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"]))
8404
- ]).optional().describe("Filter by status"),
8447
+ ]).optional(),
8405
8448
  priority: exports_external.union([
8406
8449
  exports_external.enum(["low", "medium", "high", "critical"]),
8407
8450
  exports_external.array(exports_external.enum(["low", "medium", "high", "critical"]))
8408
- ]).optional().describe("Filter by priority"),
8409
- assigned_to: exports_external.string().optional().describe("Filter by assigned agent"),
8410
- tags: exports_external.array(exports_external.string()).optional().describe("Filter by tags (any match)"),
8411
- plan_id: exports_external.string().optional().describe("Filter by plan"),
8412
- task_list_id: exports_external.string().optional().describe("Filter by task list")
8451
+ ]).optional(),
8452
+ assigned_to: exports_external.string().optional(),
8453
+ tags: exports_external.array(exports_external.string()).optional(),
8454
+ plan_id: exports_external.string().optional(),
8455
+ task_list_id: exports_external.string().optional()
8413
8456
  }, async (params) => {
8414
8457
  try {
8415
8458
  const resolved = { ...params };
@@ -8436,7 +8479,7 @@ ${text}` }] };
8436
8479
  }
8437
8480
  });
8438
8481
  server.tool("get_task", "Get full task details with relations", {
8439
- id: exports_external.string().describe("Task ID (full or partial)")
8482
+ id: exports_external.string()
8440
8483
  }, async ({ id }) => {
8441
8484
  try {
8442
8485
  const resolvedId = resolveId(id);
@@ -8484,17 +8527,17 @@ Parent: ${task.parent.id.slice(0, 8)} | ${task.parent.title}`);
8484
8527
  }
8485
8528
  });
8486
8529
  server.tool("update_task", "Update task fields. Version required for optimistic locking.", {
8487
- id: exports_external.string().describe("Task ID (full or partial)"),
8488
- version: exports_external.number().describe("Current version (for optimistic locking)"),
8489
- title: exports_external.string().optional().describe("New title"),
8490
- description: exports_external.string().optional().describe("New description"),
8491
- status: exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"]).optional().describe("New status"),
8492
- priority: exports_external.enum(["low", "medium", "high", "critical"]).optional().describe("New priority"),
8493
- assigned_to: exports_external.string().optional().describe("Assign to agent"),
8494
- tags: exports_external.array(exports_external.string()).optional().describe("New tags"),
8495
- metadata: exports_external.record(exports_external.unknown()).optional().describe("New metadata"),
8496
- plan_id: exports_external.string().optional().describe("Plan ID to assign task to"),
8497
- task_list_id: exports_external.string().optional().describe("Task list ID")
8530
+ id: exports_external.string(),
8531
+ version: exports_external.number(),
8532
+ title: exports_external.string().optional(),
8533
+ description: exports_external.string().optional(),
8534
+ status: exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"]).optional(),
8535
+ priority: exports_external.enum(["low", "medium", "high", "critical"]).optional(),
8536
+ assigned_to: exports_external.string().optional(),
8537
+ tags: exports_external.array(exports_external.string()).optional(),
8538
+ metadata: exports_external.record(exports_external.unknown()).optional(),
8539
+ plan_id: exports_external.string().optional(),
8540
+ task_list_id: exports_external.string().optional()
8498
8541
  }, async ({ id, ...rest }) => {
8499
8542
  try {
8500
8543
  const resolvedId = resolveId(id);
@@ -8505,7 +8548,7 @@ Parent: ${task.parent.id.slice(0, 8)} | ${task.parent.title}`);
8505
8548
  }
8506
8549
  });
8507
8550
  server.tool("delete_task", "Delete a task permanently", {
8508
- id: exports_external.string().describe("Task ID (full or partial)")
8551
+ id: exports_external.string()
8509
8552
  }, async ({ id }) => {
8510
8553
  try {
8511
8554
  const resolvedId = resolveId(id);
@@ -8521,8 +8564,8 @@ Parent: ${task.parent.id.slice(0, 8)} | ${task.parent.title}`);
8521
8564
  }
8522
8565
  });
8523
8566
  server.tool("start_task", "Claim, lock, and set task status to in_progress.", {
8524
- id: exports_external.string().describe("Task ID (full or partial)"),
8525
- agent_id: exports_external.string().describe("Agent claiming the task")
8567
+ id: exports_external.string(),
8568
+ agent_id: exports_external.string()
8526
8569
  }, async ({ id, agent_id }) => {
8527
8570
  try {
8528
8571
  const resolvedId = resolveId(id);
@@ -8533,8 +8576,8 @@ Parent: ${task.parent.id.slice(0, 8)} | ${task.parent.title}`);
8533
8576
  }
8534
8577
  });
8535
8578
  server.tool("complete_task", "Mark task completed and release lock.", {
8536
- id: exports_external.string().describe("Task ID (full or partial)"),
8537
- agent_id: exports_external.string().optional().describe("Agent completing the task")
8579
+ id: exports_external.string(),
8580
+ agent_id: exports_external.string().optional()
8538
8581
  }, async ({ id, agent_id }) => {
8539
8582
  try {
8540
8583
  const resolvedId = resolveId(id);
@@ -8545,8 +8588,8 @@ Parent: ${task.parent.id.slice(0, 8)} | ${task.parent.title}`);
8545
8588
  }
8546
8589
  });
8547
8590
  server.tool("lock_task", "Acquire exclusive lock on a task", {
8548
- id: exports_external.string().describe("Task ID (full or partial)"),
8549
- agent_id: exports_external.string().describe("Agent acquiring lock")
8591
+ id: exports_external.string(),
8592
+ agent_id: exports_external.string()
8550
8593
  }, async ({ id, agent_id }) => {
8551
8594
  try {
8552
8595
  const resolvedId = resolveId(id);
@@ -8560,8 +8603,8 @@ Parent: ${task.parent.id.slice(0, 8)} | ${task.parent.title}`);
8560
8603
  }
8561
8604
  });
8562
8605
  server.tool("unlock_task", "Release exclusive lock on a task", {
8563
- id: exports_external.string().describe("Task ID (full or partial)"),
8564
- agent_id: exports_external.string().optional().describe("Agent releasing lock (omit to force)")
8606
+ id: exports_external.string(),
8607
+ agent_id: exports_external.string().optional()
8565
8608
  }, async ({ id, agent_id }) => {
8566
8609
  try {
8567
8610
  const resolvedId = resolveId(id);
@@ -8572,8 +8615,8 @@ Parent: ${task.parent.id.slice(0, 8)} | ${task.parent.title}`);
8572
8615
  }
8573
8616
  });
8574
8617
  server.tool("add_dependency", "Add a dependency: task_id depends on depends_on.", {
8575
- task_id: exports_external.string().describe("Task that depends on another"),
8576
- depends_on: exports_external.string().describe("Task that must complete first")
8618
+ task_id: exports_external.string(),
8619
+ depends_on: exports_external.string()
8577
8620
  }, async ({ task_id, depends_on }) => {
8578
8621
  try {
8579
8622
  const resolvedTaskId = resolveId(task_id);
@@ -8585,8 +8628,8 @@ Parent: ${task.parent.id.slice(0, 8)} | ${task.parent.title}`);
8585
8628
  }
8586
8629
  });
8587
8630
  server.tool("remove_dependency", "Remove a dependency between tasks", {
8588
- task_id: exports_external.string().describe("Task ID"),
8589
- depends_on: exports_external.string().describe("Dependency to remove")
8631
+ task_id: exports_external.string(),
8632
+ depends_on: exports_external.string()
8590
8633
  }, async ({ task_id, depends_on }) => {
8591
8634
  try {
8592
8635
  const resolvedTaskId = resolveId(task_id);
@@ -8603,10 +8646,10 @@ Parent: ${task.parent.id.slice(0, 8)} | ${task.parent.title}`);
8603
8646
  }
8604
8647
  });
8605
8648
  server.tool("add_comment", "Add a comment/note to a task", {
8606
- task_id: exports_external.string().describe("Task ID (full or partial)"),
8607
- content: exports_external.string().describe("Comment content"),
8608
- agent_id: exports_external.string().optional().describe("Agent adding comment"),
8609
- session_id: exports_external.string().optional().describe("Session ID")
8649
+ task_id: exports_external.string(),
8650
+ content: exports_external.string(),
8651
+ agent_id: exports_external.string().optional(),
8652
+ session_id: exports_external.string().optional()
8610
8653
  }, async ({ task_id, ...rest }) => {
8611
8654
  try {
8612
8655
  const resolvedId = resolveId(task_id);
@@ -8634,10 +8677,10 @@ ${text}` }] };
8634
8677
  }
8635
8678
  });
8636
8679
  server.tool("create_project", "Register a new project", {
8637
- name: exports_external.string().describe("Project name"),
8638
- path: exports_external.string().describe("Absolute path to project"),
8639
- description: exports_external.string().optional().describe("Project description"),
8640
- task_list_id: exports_external.string().optional().describe("Custom task list ID for Claude Code sync (defaults to todos-<slugified-name>)")
8680
+ name: exports_external.string(),
8681
+ path: exports_external.string(),
8682
+ description: exports_external.string().optional(),
8683
+ task_list_id: exports_external.string().optional()
8641
8684
  }, async (params) => {
8642
8685
  try {
8643
8686
  const project = createProject(params);
@@ -8653,12 +8696,12 @@ ${text}` }] };
8653
8696
  }
8654
8697
  });
8655
8698
  server.tool("create_plan", "Create a new plan", {
8656
- name: exports_external.string().describe("Plan name"),
8657
- project_id: exports_external.string().optional().describe("Project ID"),
8658
- description: exports_external.string().optional().describe("Plan description"),
8659
- status: exports_external.enum(["active", "completed", "archived"]).optional().describe("Plan status"),
8660
- task_list_id: exports_external.string().optional().describe("Task list ID"),
8661
- agent_id: exports_external.string().optional().describe("Owner agent ID")
8699
+ name: exports_external.string(),
8700
+ project_id: exports_external.string().optional(),
8701
+ description: exports_external.string().optional(),
8702
+ status: exports_external.enum(["active", "completed", "archived"]).optional(),
8703
+ task_list_id: exports_external.string().optional(),
8704
+ agent_id: exports_external.string().optional()
8662
8705
  }, async (params) => {
8663
8706
  try {
8664
8707
  const resolved = { ...params };
@@ -8678,7 +8721,7 @@ ${text}` }] };
8678
8721
  }
8679
8722
  });
8680
8723
  server.tool("list_plans", "List plans with optional project filter", {
8681
- project_id: exports_external.string().optional().describe("Filter by project")
8724
+ project_id: exports_external.string().optional()
8682
8725
  }, async ({ project_id }) => {
8683
8726
  try {
8684
8727
  const resolvedProjectId = project_id ? resolveId(project_id, "projects") : undefined;
@@ -8698,7 +8741,7 @@ ${text}` }] };
8698
8741
  }
8699
8742
  });
8700
8743
  server.tool("get_plan", "Get plan details", {
8701
- id: exports_external.string().describe("Plan ID (full or partial)")
8744
+ id: exports_external.string()
8702
8745
  }, async ({ id }) => {
8703
8746
  try {
8704
8747
  const resolvedId = resolveId(id, "plans");
@@ -8723,12 +8766,12 @@ ${text}` }] };
8723
8766
  }
8724
8767
  });
8725
8768
  server.tool("update_plan", "Update a plan", {
8726
- id: exports_external.string().describe("Plan ID (full or partial)"),
8727
- name: exports_external.string().optional().describe("New name"),
8728
- description: exports_external.string().optional().describe("New description"),
8729
- status: exports_external.enum(["active", "completed", "archived"]).optional().describe("New status"),
8730
- task_list_id: exports_external.string().optional().describe("Task list ID"),
8731
- agent_id: exports_external.string().optional().describe("Owner agent ID")
8769
+ id: exports_external.string(),
8770
+ name: exports_external.string().optional(),
8771
+ description: exports_external.string().optional(),
8772
+ status: exports_external.enum(["active", "completed", "archived"]).optional(),
8773
+ task_list_id: exports_external.string().optional(),
8774
+ agent_id: exports_external.string().optional()
8732
8775
  }, async ({ id, ...rest }) => {
8733
8776
  try {
8734
8777
  const resolvedId = resolveId(id, "plans");
@@ -8747,7 +8790,7 @@ ${text}` }] };
8747
8790
  }
8748
8791
  });
8749
8792
  server.tool("delete_plan", "Delete a plan", {
8750
- id: exports_external.string().describe("Plan ID (full or partial)")
8793
+ id: exports_external.string()
8751
8794
  }, async ({ id }) => {
8752
8795
  try {
8753
8796
  const resolvedId = resolveId(id, "plans");
@@ -8763,9 +8806,9 @@ ${text}` }] };
8763
8806
  }
8764
8807
  });
8765
8808
  server.tool("search_tasks", "Full-text search across task titles, descriptions, tags.", {
8766
- query: exports_external.string().describe("Search query"),
8767
- project_id: exports_external.string().optional().describe("Limit to project"),
8768
- task_list_id: exports_external.string().optional().describe("Filter by task list")
8809
+ query: exports_external.string(),
8810
+ project_id: exports_external.string().optional(),
8811
+ task_list_id: exports_external.string().optional()
8769
8812
  }, async ({ query, project_id, task_list_id }) => {
8770
8813
  try {
8771
8814
  const resolvedProjectId = project_id ? resolveId(project_id, "projects") : undefined;
@@ -8783,12 +8826,12 @@ ${text}` }] };
8783
8826
  }
8784
8827
  });
8785
8828
  server.tool("sync", "Sync tasks with an agent task list.", {
8786
- task_list_id: exports_external.string().optional().describe("Task list ID (required for Claude)"),
8787
- agent: exports_external.string().optional().describe("Agent/provider name (default: claude)"),
8788
- all_agents: exports_external.boolean().optional().describe("Sync across all configured agents"),
8789
- project_id: exports_external.string().optional().describe("Project ID \u2014 its task_list_id will be used for Claude if task_list_id is not provided"),
8790
- direction: exports_external.enum(["push", "pull", "both"]).optional().describe("Sync direction: push (SQLite->agent), pull (agent->SQLite), or both (default)"),
8791
- prefer: exports_external.enum(["local", "remote"]).optional().describe("Conflict strategy")
8829
+ task_list_id: exports_external.string().optional(),
8830
+ agent: exports_external.string().optional(),
8831
+ all_agents: exports_external.boolean().optional(),
8832
+ project_id: exports_external.string().optional(),
8833
+ direction: exports_external.enum(["push", "pull", "both"]).optional(),
8834
+ prefer: exports_external.enum(["local", "remote"]).optional()
8792
8835
  }, async ({ task_list_id, agent, all_agents, project_id, direction, prefer }) => {
8793
8836
  try {
8794
8837
  const resolvedProjectId = project_id ? resolveId(project_id, "projects") : undefined;
@@ -8831,8 +8874,8 @@ ${text}` }] };
8831
8874
  }
8832
8875
  });
8833
8876
  server.tool("register_agent", "Register an agent (idempotent by name).", {
8834
- name: exports_external.string().describe("Agent name"),
8835
- description: exports_external.string().optional().describe("Agent description")
8877
+ name: exports_external.string(),
8878
+ description: exports_external.string().optional()
8836
8879
  }, async ({ name, description }) => {
8837
8880
  try {
8838
8881
  const agent = registerAgent({ name, description });
@@ -8868,8 +8911,8 @@ ${text}` }] };
8868
8911
  }
8869
8912
  });
8870
8913
  server.tool("get_agent", "Get agent details by ID or name", {
8871
- id: exports_external.string().optional().describe("Agent ID"),
8872
- name: exports_external.string().optional().describe("Agent name")
8914
+ id: exports_external.string().optional(),
8915
+ name: exports_external.string().optional()
8873
8916
  }, async ({ id, name }) => {
8874
8917
  try {
8875
8918
  if (!id && !name) {
@@ -8896,10 +8939,10 @@ ${text}` }] };
8896
8939
  }
8897
8940
  });
8898
8941
  server.tool("create_task_list", "Create a new task list", {
8899
- name: exports_external.string().describe("Task list name"),
8900
- slug: exports_external.string().optional().describe("URL-friendly slug (auto-generated from name if omitted)"),
8901
- project_id: exports_external.string().optional().describe("Project ID to associate with"),
8902
- description: exports_external.string().optional().describe("Task list description")
8942
+ name: exports_external.string(),
8943
+ slug: exports_external.string().optional(),
8944
+ project_id: exports_external.string().optional(),
8945
+ description: exports_external.string().optional()
8903
8946
  }, async (params) => {
8904
8947
  try {
8905
8948
  const resolved = { ...params };
@@ -8922,7 +8965,7 @@ Description: ${list.description}` : ""}`
8922
8965
  }
8923
8966
  });
8924
8967
  server.tool("list_task_lists", "List task lists, optionally filtered by project", {
8925
- project_id: exports_external.string().optional().describe("Filter by project")
8968
+ project_id: exports_external.string().optional()
8926
8969
  }, async ({ project_id }) => {
8927
8970
  try {
8928
8971
  const resolvedProjectId = project_id ? resolveId(project_id, "projects") : undefined;
@@ -8942,7 +8985,7 @@ ${text}` }] };
8942
8985
  }
8943
8986
  });
8944
8987
  server.tool("get_task_list", "Get task list details", {
8945
- id: exports_external.string().describe("Task list ID (full or partial)")
8988
+ id: exports_external.string()
8946
8989
  }, async ({ id }) => {
8947
8990
  try {
8948
8991
  const resolvedId = resolveId(id, "task_lists");
@@ -8970,9 +9013,9 @@ ${text}` }] };
8970
9013
  }
8971
9014
  });
8972
9015
  server.tool("update_task_list", "Update a task list", {
8973
- id: exports_external.string().describe("Task list ID (full or partial)"),
8974
- name: exports_external.string().optional().describe("New name"),
8975
- description: exports_external.string().optional().describe("New description")
9016
+ id: exports_external.string(),
9017
+ name: exports_external.string().optional(),
9018
+ description: exports_external.string().optional()
8976
9019
  }, async ({ id, ...rest }) => {
8977
9020
  try {
8978
9021
  const resolvedId = resolveId(id, "task_lists");
@@ -8991,7 +9034,7 @@ Slug: ${list.slug}`
8991
9034
  }
8992
9035
  });
8993
9036
  server.tool("delete_task_list", "Delete a task list. Tasks lose association but keep data.", {
8994
- id: exports_external.string().describe("Task list ID (full or partial)")
9037
+ id: exports_external.string()
8995
9038
  }, async ({ id }) => {
8996
9039
  try {
8997
9040
  const resolvedId = resolveId(id, "task_lists");
@@ -9007,7 +9050,7 @@ Slug: ${list.slug}`
9007
9050
  }
9008
9051
  });
9009
9052
  server.tool("get_task_history", "Get audit log for a task.", {
9010
- task_id: exports_external.string().describe("Task ID (full or partial)")
9053
+ task_id: exports_external.string()
9011
9054
  }, async ({ task_id }) => {
9012
9055
  try {
9013
9056
  const resolvedId = resolveId(task_id);
@@ -9024,7 +9067,7 @@ ${text}` }] };
9024
9067
  }
9025
9068
  });
9026
9069
  server.tool("get_recent_activity", "Get recent task changes across all tasks.", {
9027
- limit: exports_external.number().optional().describe("Max entries (default 50)")
9070
+ limit: exports_external.number().optional()
9028
9071
  }, async ({ limit }) => {
9029
9072
  try {
9030
9073
  const { getRecentActivity: getRecentActivity2 } = await Promise.resolve().then(() => (init_audit(), exports_audit));
@@ -9040,9 +9083,9 @@ ${text}` }] };
9040
9083
  }
9041
9084
  });
9042
9085
  server.tool("create_webhook", "Register a webhook to receive task change events.", {
9043
- url: exports_external.string().describe("Webhook URL"),
9044
- events: exports_external.array(exports_external.string()).optional().describe("Event types to subscribe to (empty = all)"),
9045
- secret: exports_external.string().optional().describe("HMAC secret for signature verification")
9086
+ url: exports_external.string(),
9087
+ events: exports_external.array(exports_external.string()).optional(),
9088
+ secret: exports_external.string().optional()
9046
9089
  }, async (params) => {
9047
9090
  try {
9048
9091
  const { createWebhook: createWebhook2 } = await Promise.resolve().then(() => (init_webhooks(), exports_webhooks));
@@ -9067,7 +9110,7 @@ ${text}` }] };
9067
9110
  }
9068
9111
  });
9069
9112
  server.tool("delete_webhook", "Delete a webhook", {
9070
- id: exports_external.string().describe("Webhook ID")
9113
+ id: exports_external.string()
9071
9114
  }, async ({ id }) => {
9072
9115
  try {
9073
9116
  const { deleteWebhook: deleteWebhook2 } = await Promise.resolve().then(() => (init_webhooks(), exports_webhooks));
@@ -9078,13 +9121,13 @@ ${text}` }] };
9078
9121
  }
9079
9122
  });
9080
9123
  server.tool("create_template", "Create a reusable task template.", {
9081
- name: exports_external.string().describe("Template name"),
9082
- title_pattern: exports_external.string().describe("Title pattern for tasks created from this template"),
9083
- description: exports_external.string().optional().describe("Default description"),
9084
- priority: exports_external.enum(["low", "medium", "high", "critical"]).optional().describe("Default priority"),
9085
- tags: exports_external.array(exports_external.string()).optional().describe("Default tags"),
9086
- project_id: exports_external.string().optional().describe("Default project"),
9087
- plan_id: exports_external.string().optional().describe("Default plan")
9124
+ name: exports_external.string(),
9125
+ title_pattern: exports_external.string(),
9126
+ description: exports_external.string().optional(),
9127
+ priority: exports_external.enum(["low", "medium", "high", "critical"]).optional(),
9128
+ tags: exports_external.array(exports_external.string()).optional(),
9129
+ project_id: exports_external.string().optional(),
9130
+ plan_id: exports_external.string().optional()
9088
9131
  }, async (params) => {
9089
9132
  try {
9090
9133
  const { createTemplate: createTemplate2 } = await Promise.resolve().then(() => (init_templates(), exports_templates));
@@ -9109,12 +9152,12 @@ ${text}` }] };
9109
9152
  }
9110
9153
  });
9111
9154
  server.tool("create_task_from_template", "Create a task from a template with optional overrides.", {
9112
- template_id: exports_external.string().describe("Template ID"),
9113
- title: exports_external.string().optional().describe("Override title"),
9114
- description: exports_external.string().optional().describe("Override description"),
9115
- priority: exports_external.enum(["low", "medium", "high", "critical"]).optional().describe("Override priority"),
9116
- assigned_to: exports_external.string().optional().describe("Assign to agent"),
9117
- project_id: exports_external.string().optional().describe("Override project")
9155
+ template_id: exports_external.string(),
9156
+ title: exports_external.string().optional(),
9157
+ description: exports_external.string().optional(),
9158
+ priority: exports_external.enum(["low", "medium", "high", "critical"]).optional(),
9159
+ assigned_to: exports_external.string().optional(),
9160
+ project_id: exports_external.string().optional()
9118
9161
  }, async (params) => {
9119
9162
  try {
9120
9163
  const { taskFromTemplate: taskFromTemplate2 } = await Promise.resolve().then(() => (init_templates(), exports_templates));
@@ -9132,7 +9175,7 @@ ${task.id.slice(0, 8)} | ${task.priority} | ${task.title}` }] };
9132
9175
  return { content: [{ type: "text", text: formatError(e) }], isError: true };
9133
9176
  }
9134
9177
  });
9135
- server.tool("delete_template", "Delete a task template", { id: exports_external.string().describe("Template ID") }, async ({ id }) => {
9178
+ server.tool("delete_template", "Delete a task template", { id: exports_external.string() }, async ({ id }) => {
9136
9179
  try {
9137
9180
  const { deleteTemplate: deleteTemplate2 } = await Promise.resolve().then(() => (init_templates(), exports_templates));
9138
9181
  const deleted = deleteTemplate2(id);
@@ -9142,8 +9185,8 @@ ${task.id.slice(0, 8)} | ${task.priority} | ${task.title}` }] };
9142
9185
  }
9143
9186
  });
9144
9187
  server.tool("approve_task", "Approve a task that requires approval.", {
9145
- id: exports_external.string().describe("Task ID (full or partial)"),
9146
- agent_id: exports_external.string().optional().describe("Agent approving the task")
9188
+ id: exports_external.string(),
9189
+ agent_id: exports_external.string().optional()
9147
9190
  }, async ({ id, agent_id }) => {
9148
9191
  try {
9149
9192
  const resolvedId = resolveId(id);
@@ -9161,7 +9204,7 @@ ${task.id.slice(0, 8)} | ${task.priority} | ${task.title}` }] };
9161
9204
  }
9162
9205
  });
9163
9206
  server.tool("get_my_tasks", "Get assigned tasks and stats for an agent.", {
9164
- agent_name: exports_external.string().describe("Your agent name")
9207
+ agent_name: exports_external.string()
9165
9208
  }, async ({ agent_name }) => {
9166
9209
  try {
9167
9210
  const agent = registerAgent({ name: agent_name });
@@ -9193,7 +9236,51 @@ In Progress:`);
9193
9236
  return { content: [{ type: "text", text: formatError(e) }], isError: true };
9194
9237
  }
9195
9238
  });
9196
- server.tool("search_tools", "List tool names matching a query.", { query: exports_external.string().optional().describe("Keyword to filter tools") }, async ({ query }) => {
9239
+ server.tool("get_org_chart", "Get agent org chart \u2014 who reports to who.", {}, async () => {
9240
+ try {
9241
+ let render = function(nodes, indent = 0) {
9242
+ return nodes.map((n) => {
9243
+ const prefix = " ".repeat(indent);
9244
+ const role = n.agent.role ? ` (${n.agent.role})` : "";
9245
+ const line = `${prefix}${n.agent.name}${role} [${n.agent.id}]`;
9246
+ const children = n.reports.length > 0 ? `
9247
+ ` + render(n.reports, indent + 1) : "";
9248
+ return line + children;
9249
+ }).join(`
9250
+ `);
9251
+ };
9252
+ const { getOrgChart: getOrgChart2 } = await Promise.resolve().then(() => (init_agents(), exports_agents));
9253
+ const tree = getOrgChart2();
9254
+ const text = tree.length > 0 ? render(tree) : "No agents registered.";
9255
+ return { content: [{ type: "text", text }] };
9256
+ } catch (e) {
9257
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
9258
+ }
9259
+ });
9260
+ server.tool("set_reports_to", "Set who an agent reports to in the org chart.", {
9261
+ agent_name: exports_external.string(),
9262
+ manager_name: exports_external.string().optional()
9263
+ }, async ({ agent_name, manager_name }) => {
9264
+ try {
9265
+ const agent = getAgentByName(agent_name);
9266
+ if (!agent)
9267
+ return { content: [{ type: "text", text: `Agent not found: ${agent_name}` }], isError: true };
9268
+ let managerId = null;
9269
+ if (manager_name) {
9270
+ const manager = getAgentByName(manager_name);
9271
+ if (!manager)
9272
+ return { content: [{ type: "text", text: `Manager not found: ${manager_name}` }], isError: true };
9273
+ managerId = manager.id;
9274
+ }
9275
+ const { updateAgent: updateAgent2 } = await Promise.resolve().then(() => (init_agents(), exports_agents));
9276
+ updateAgent2(agent.id, { reports_to: managerId });
9277
+ const result = managerId ? `${agent_name} now reports to ${manager_name}` : `${agent_name} reports to no one (top-level)`;
9278
+ return { content: [{ type: "text", text: result }] };
9279
+ } catch (e) {
9280
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
9281
+ }
9282
+ });
9283
+ server.tool("search_tools", "List tool names matching a query.", { query: exports_external.string().optional() }, async ({ query }) => {
9197
9284
  const all = [
9198
9285
  "create_task",
9199
9286
  "list_tasks",
@@ -9242,7 +9329,7 @@ In Progress:`);
9242
9329
  const matches = q ? all.filter((n) => n.includes(q)) : all;
9243
9330
  return { content: [{ type: "text", text: matches.join(", ") }] };
9244
9331
  });
9245
- server.tool("describe_tools", "Get descriptions for specific tools by name.", { names: exports_external.array(exports_external.string()).describe("Tool names from search_tools") }, async ({ names }) => {
9332
+ server.tool("describe_tools", "Get descriptions for specific tools by name.", { names: exports_external.array(exports_external.string()) }, async ({ names }) => {
9246
9333
  const descriptions = {
9247
9334
  create_task: "Create a task. Params: title(req), description, priority, project_id, plan_id, tags, assigned_to, estimated_minutes, requires_approval",
9248
9335
  list_tasks: "List tasks. Params: status, priority, project_id, plan_id, assigned_to, tags, limit",
@@ -9644,6 +9731,16 @@ Dashboard not found at: ${dashboardDir}`);
9644
9731
  return json({ error: e instanceof Error ? e.message : "Failed to claim" }, 500, port);
9645
9732
  }
9646
9733
  }
9734
+ if (path === "/api/org" && method === "GET") {
9735
+ const { getOrgChart: getOrgChart2 } = await Promise.resolve().then(() => (init_agents(), exports_agents));
9736
+ return json(getOrgChart2(), 200, port);
9737
+ }
9738
+ const teamMatch = path.match(/^\/api\/agents\/([^/]+)\/team$/);
9739
+ if (teamMatch && method === "GET") {
9740
+ const agentId = decodeURIComponent(teamMatch[1]);
9741
+ const { getDirectReports: getDirectReports2 } = await Promise.resolve().then(() => (init_agents(), exports_agents));
9742
+ return json(getDirectReports2(agentId), 200, port);
9743
+ }
9647
9744
  if (path === "/api/agents" && method === "GET") {
9648
9745
  return json(listAgents(), 200, port);
9649
9746
  }
@@ -12182,6 +12279,52 @@ program2.command("agents").description("List registered agents").action(() => {
12182
12279
  handleError(e);
12183
12280
  }
12184
12281
  });
12282
+ 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) => {
12283
+ const globalOpts = program2.opts();
12284
+ const { getOrgChart: getOrgChart2, getAgentByName: getByName, updateAgent: update } = (init_agents(), __toCommonJS(exports_agents));
12285
+ if (opts.set) {
12286
+ const [agentName, managerName] = opts.set.split("=");
12287
+ const agent = getByName(agentName);
12288
+ if (!agent) {
12289
+ console.error(chalk.red(`Agent not found: ${agentName}`));
12290
+ process.exit(1);
12291
+ }
12292
+ let managerId = null;
12293
+ if (managerName) {
12294
+ const manager = getByName(managerName);
12295
+ if (!manager) {
12296
+ console.error(chalk.red(`Manager not found: ${managerName}`));
12297
+ process.exit(1);
12298
+ }
12299
+ managerId = manager.id;
12300
+ }
12301
+ update(agent.id, { reports_to: managerId });
12302
+ if (globalOpts.json) {
12303
+ output({ agent: agentName, reports_to: managerName || null }, true);
12304
+ } else {
12305
+ console.log(chalk.green(managerId ? `${agentName} \u2192 ${managerName}` : `${agentName} \u2192 (top-level)`));
12306
+ }
12307
+ return;
12308
+ }
12309
+ const tree = getOrgChart2();
12310
+ if (globalOpts.json) {
12311
+ output(tree, true);
12312
+ return;
12313
+ }
12314
+ if (tree.length === 0) {
12315
+ console.log(chalk.dim("No agents registered."));
12316
+ return;
12317
+ }
12318
+ function render2(nodes, indent = 0) {
12319
+ for (const n of nodes) {
12320
+ const prefix = " ".repeat(indent);
12321
+ const role = n.agent.role ? chalk.dim(` (${n.agent.role})`) : "";
12322
+ console.log(`${prefix}${indent > 0 ? "\u251C\u2500\u2500 " : ""}${chalk.bold(n.agent.name)}${role} ${chalk.dim(n.agent.id)}`);
12323
+ render2(n.reports, indent + 1);
12324
+ }
12325
+ }
12326
+ render2(tree);
12327
+ });
12185
12328
  program2.command("lists").aliases(["task-lists", "tl"]).description("List and manage task lists").option("--add <name>", "Create a task list").option("--slug <slug>", "Custom slug (with --add)").option("-d, --description <text>", "Description (with --add)").option("--delete <id>", "Delete a task list").action((opts) => {
12186
12329
  try {
12187
12330
  const globalOpts = program2.opts();