@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.
- package/dist/index.js +190 -1
- 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.
|
|
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
|
+
"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.
|
|
31
|
+
"@minions-tasks/sdk": "0.4.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/node": "^25.3.0",
|