dew/packages/kanban/lib/src/commands/list_command.dart
Chris Hendrickson 7b83572f7a Unified command-tool registration via DewToolCommand mixin
- Add DewToolCommand mixin that auto-derives MCP tool JSON Schema from
  ArgParser, eliminating the need to define CLI commands and MCP tools
  separately
- Add schemaFromArgParser() to generate JSON Schema from ArgParser options
- Add CommandRegistry.mcpTools recursive collector for all DewToolCommand
  subcommands
- Refactor all kanban subcommands to use the mixin; switch get/update/delete
  from positional rest args to --id / -i option for schema compatibility
- Promote list to a proper CLI subcommand (was MCP-only before)
- Add search, comment, and config subcommands (CLI + MCP tools)
- Add TicketStore.addComment() for non-destructive comment appending
- Simplify mcp.registerCommands() to take only CommandRegistry
- Simplify CLI entry point (no more KanbanToolProvider/McpToolRegistry)
- Delete stale files: kanban_tool_provider.dart, mcp_tool_provider.dart,
  mcp_tool_registry.dart (superseded by DewToolCommand mixin)
- Add tools/mcp_client.dart debug client for manual MCP server testing
- Update .vscode/mcp.json with correct server config

All 26 tests pass, dart analyze clean.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-23 16:30:43 -04:00

46 lines
1.3 KiB
Dart

import 'package:dew_core/dew_core.dart';
import 'package:path/path.dart' as p;
import '../ticket_store.dart';
class ListCommand extends DewCommand with DewToolCommand {
ListCommand() {
argParser
..addOption('column', abbr: 'c', help: 'Filter to tickets in this column.')
..addOption('type', abbr: 't', help: 'Filter to tickets of this type.');
}
@override
final String name = 'list';
@override
final String description = 'List kanban tickets, optionally filtered by column or type.';
@override
final String toolName = 'kanban_list_tickets';
@override
Future<String> callAsTool(Map<String, dynamic> args) async {
final columnFilter = args['column'] as String?;
final typeFilter = args['type'] as String?;
final context = await ProjectContext.find();
final store = TicketStore(
kanbanDir: p.join(context.root, '.project', 'kanban'),
prefix: context.config.kanban.prefix,
);
var tickets = await store.list();
if (columnFilter != null) {
tickets = tickets.where((t) => t.column == columnFilter).toList();
}
if (typeFilter != null) {
tickets = tickets.where((t) => t.type == typeFilter).toList();
}
if (tickets.isEmpty) return 'No tickets found.';
return tickets
.map((t) => '[${t.id}] (${t.type}) [${t.column}] ${t.title}')
.join('\n');
}
}