@minions-tasks/cli 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +190 -1
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -34,7 +34,7 @@ function findType(slug) {
34
34
  program
35
35
  .name('tasks')
36
36
  .description('Task and work management across agents, humans, and workflows')
37
- .version('0.3.0');
37
+ .version('0.4.0');
38
38
  // ─── info ──────────────────────────────────────────────────
39
39
  program
40
40
  .command('info')
@@ -328,4 +328,193 @@ program
328
328
  console.log(`\n ${chalk.bold('Total:')} ${total} Minion(s)`);
329
329
  console.log(` ${chalk.dim(`Store: ${STORE_DIR}`)}\n`);
330
330
  });
331
+ // ─── blocked ───────────────────────────────────────────────
332
+ program
333
+ .command('blocked')
334
+ .description('List all tasks with status "blocked" and their dependencies')
335
+ .action(() => {
336
+ ensureStore();
337
+ const taskDir = join(STORE_DIR, 'task');
338
+ const depDir = join(STORE_DIR, 'task-dependency');
339
+ if (!existsSync(taskDir)) {
340
+ console.log(chalk.dim('\n No tasks found.\n'));
341
+ return;
342
+ }
343
+ const tasks = readdirSync(taskDir).filter(f => f.endsWith('.json'))
344
+ .map(f => JSON.parse(readFileSync(join(taskDir, f), 'utf-8')))
345
+ .filter(t => t.fields?.status === 'blocked');
346
+ if (tasks.length === 0) {
347
+ console.log(chalk.green('\n ✔ No blocked tasks.\n'));
348
+ return;
349
+ }
350
+ const deps = existsSync(depDir)
351
+ ? readdirSync(depDir).filter(f => f.endsWith('.json')).map(f => JSON.parse(readFileSync(join(depDir, f), 'utf-8')))
352
+ : [];
353
+ console.log(chalk.bold(`\n 🚫 ${tasks.length} blocked task(s):\n`));
354
+ for (const t of tasks) {
355
+ console.log(` ✅ ${chalk.bold(t.fields.title || '(untitled)')}`);
356
+ console.log(` ${chalk.dim(t.id)}`);
357
+ const taskDeps = deps.filter(d => d.fields?.taskId === t.id);
358
+ if (taskDeps.length > 0) {
359
+ for (const d of taskDeps) {
360
+ console.log(` ${chalk.red('→')} blocked by ${chalk.dim(d.fields.dependsOnTaskId)} (${d.fields.type})`);
361
+ }
362
+ }
363
+ else {
364
+ console.log(` ${chalk.dim('No dependency records found')}`);
365
+ }
366
+ console.log('');
367
+ }
368
+ });
369
+ // ─── search ────────────────────────────────────────────────
370
+ program
371
+ .command('search <query>')
372
+ .description('Search Minions by title, name, or label')
373
+ .option('-t, --type <type>', 'Filter by MinionType slug')
374
+ .option('--status <status>', 'Filter by status')
375
+ .option('--json', 'Output as JSON')
376
+ .action((query, opts) => {
377
+ ensureStore();
378
+ const slugs = opts.type ? [opts.type] : customTypes.map(t => t.slug);
379
+ const results = [];
380
+ const q = query.toLowerCase();
381
+ for (const slug of slugs) {
382
+ const dir = join(STORE_DIR, slug);
383
+ if (!existsSync(dir))
384
+ continue;
385
+ const files = readdirSync(dir).filter(f => f.endsWith('.json'));
386
+ for (const file of files) {
387
+ const minion = JSON.parse(readFileSync(join(dir, file), 'utf-8'));
388
+ const title = (minion.fields?.title || minion.fields?.name || minion.fields?.label || '').toLowerCase();
389
+ const desc = (minion.fields?.description || minion.fields?.body || '').toLowerCase();
390
+ if (title.includes(q) || desc.includes(q)) {
391
+ if (opts.status && minion.fields?.status !== opts.status)
392
+ continue;
393
+ results.push(minion);
394
+ }
395
+ }
396
+ }
397
+ if (opts.json) {
398
+ console.log(JSON.stringify(results, null, 2));
399
+ return;
400
+ }
401
+ if (results.length === 0) {
402
+ console.log(chalk.dim(`\n No results for "${query}".\n`));
403
+ return;
404
+ }
405
+ console.log(chalk.bold(`\n ${results.length} result(s) for "${query}":\n`));
406
+ for (const m of results) {
407
+ const type = customTypes.find(t => t.slug === m.type);
408
+ const icon = type?.icon || '?';
409
+ const title = m.fields?.title || m.fields?.name || m.fields?.label || chalk.dim('(untitled)');
410
+ const status = m.fields?.status ? chalk.dim(`[${m.fields.status}]`) : '';
411
+ console.log(` ${icon} ${chalk.bold(title)} ${status}`);
412
+ console.log(` ${chalk.dim(m.id)} ${chalk.dim(m.type)}`);
413
+ }
414
+ console.log('');
415
+ });
416
+ // ─── complete ──────────────────────────────────────────────
417
+ program
418
+ .command('complete <id>')
419
+ .description('Mark a task as done and create a task-outcome')
420
+ .option('-r, --result <result>', 'Outcome result: success, partial, or failed', 'success')
421
+ .option('--summary <summary>', 'Summary of what was accomplished')
422
+ .option('--lessons <lessons>', 'Lessons learned for the agent learning loop')
423
+ .action((id, opts) => {
424
+ ensureStore();
425
+ const filePath = join(STORE_DIR, 'task', `${id}.json`);
426
+ if (!existsSync(filePath)) {
427
+ console.error(chalk.red(`\n Task not found: ${id}\n`));
428
+ process.exit(1);
429
+ }
430
+ const task = JSON.parse(readFileSync(filePath, 'utf-8'));
431
+ task.fields.status = 'done';
432
+ task.fields.completedAt = new Date().toISOString();
433
+ task.updatedAt = new Date().toISOString();
434
+ writeFileSync(filePath, JSON.stringify(task, null, 2));
435
+ // Create task-outcome
436
+ const outcome = {
437
+ id: randomUUID(),
438
+ type: 'task-outcome',
439
+ typeName: 'Task outcome',
440
+ fields: {
441
+ taskId: id,
442
+ result: opts.result,
443
+ summary: opts.summary || '',
444
+ artifactIds: '',
445
+ lessons: opts.lessons || '',
446
+ },
447
+ createdAt: new Date().toISOString(),
448
+ updatedAt: new Date().toISOString(),
449
+ };
450
+ const outcomeDir = getTypeDir('task-outcome');
451
+ writeFileSync(join(outcomeDir, `${outcome.id}.json`), JSON.stringify(outcome, null, 2));
452
+ console.log(chalk.green(`\n ✔ Completed ✅ ${task.fields.title || 'Task'}`));
453
+ console.log(` ${chalk.dim('Result:')} ${opts.result}`);
454
+ console.log(` ${chalk.dim('Outcome:')} ${outcome.id}\n`);
455
+ });
456
+ // ─── assign ────────────────────────────────────────────────
457
+ program
458
+ .command('assign <taskId> <assigneeId>')
459
+ .description('Assign a task to a person or agent')
460
+ .option('--type <type>', 'Assignee type: human or agent', 'agent')
461
+ .option('--role <role>', 'Role: owner, collaborator, reviewer, observer', 'owner')
462
+ .action((taskId, assigneeId, opts) => {
463
+ ensureStore();
464
+ const taskPath = join(STORE_DIR, 'task', `${taskId}.json`);
465
+ if (!existsSync(taskPath)) {
466
+ console.error(chalk.red(`\n Task not found: ${taskId}\n`));
467
+ process.exit(1);
468
+ }
469
+ const assignment = {
470
+ id: randomUUID(),
471
+ type: 'task-assignment',
472
+ typeName: 'Task assignment',
473
+ fields: {
474
+ taskId,
475
+ assigneeId,
476
+ assigneeType: opts.type,
477
+ assignedAt: new Date().toISOString(),
478
+ assignedBy: 'cli',
479
+ role: opts.role,
480
+ },
481
+ createdAt: new Date().toISOString(),
482
+ updatedAt: new Date().toISOString(),
483
+ };
484
+ const dir = getTypeDir('task-assignment');
485
+ writeFileSync(join(dir, `${assignment.id}.json`), JSON.stringify(assignment, null, 2));
486
+ console.log(chalk.green(`\n ✔ Assigned task to ${assigneeId}`));
487
+ console.log(` ${chalk.dim('Task:')} ${taskId}`);
488
+ console.log(` ${chalk.dim('Type:')} ${opts.type}`);
489
+ console.log(` ${chalk.dim('Role:')} ${opts.role}`);
490
+ console.log(` ${chalk.dim('Assignment:')} ${assignment.id}\n`);
491
+ });
492
+ // ─── comment ───────────────────────────────────────────────
493
+ program
494
+ .command('comment <taskId> <body>')
495
+ .description('Add a comment to a task')
496
+ .option('--author <id>', 'Author ID', 'cli')
497
+ .option('--type <type>', 'Author type: human or agent', 'agent')
498
+ .action((taskId, body, opts) => {
499
+ ensureStore();
500
+ const comment = {
501
+ id: randomUUID(),
502
+ type: 'task-comment',
503
+ typeName: 'Task comment',
504
+ fields: {
505
+ taskId,
506
+ authorId: opts.author,
507
+ authorType: opts.type,
508
+ body,
509
+ createdAt: new Date().toISOString(),
510
+ resolvedAt: '',
511
+ },
512
+ createdAt: new Date().toISOString(),
513
+ updatedAt: new Date().toISOString(),
514
+ };
515
+ const dir = getTypeDir('task-comment');
516
+ writeFileSync(join(dir, `${comment.id}.json`), JSON.stringify(comment, null, 2));
517
+ console.log(chalk.green(`\n ✔ Comment added to task ${taskId}`));
518
+ console.log(` ${chalk.dim('ID:')} ${comment.id}\n`);
519
+ });
331
520
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@minions-tasks/cli",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "CLI for minions-tasks — Task and work management across agents, humans, and workflows",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -28,7 +28,7 @@
28
28
  "commander": "^14.0.3",
29
29
  "inquirer": "^13.2.5",
30
30
  "minions-sdk": "^0.2.2",
31
- "@minions-tasks/sdk": "0.3.0"
31
+ "@minions-tasks/sdk": "0.4.0"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@types/node": "^25.3.0",