1. get shows milestones/labels: GetCommand._format() now shows Milestones:/Labels: lines when non-empty, between Created: and Links: 2. unarchive command: kanban unarchive --id <id> [--column <col>] restores a ticket from archive/ back to a column (default: first configured column); registered as 'kanban_unarchive_ticket' MCP tool (15 tools total) 3. Test isolation: add dart_test.yaml (concurrency: 1) — Directory.current is a process-global OS chdir(); concurrent test files in the same process would race. Now dart test packages/core packages/kanban passes cleanly. 4. update empty multi-option fix: --milestone '' / --label '' with empty strings now filters them out (treats as 'clear to empty') rather than writing spurious empty-string YAML list entries Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
60 lines
1.9 KiB
Dart
60 lines
1.9 KiB
Dart
import 'dart:io';
|
|
|
|
import 'package:dew_core/dew_core.dart';
|
|
import '../kanban_config.dart';
|
|
import 'package:path/path.dart' as p;
|
|
|
|
import '../ticket_store.dart';
|
|
|
|
class UnarchiveCommand extends DewCommand with DewToolCommand {
|
|
UnarchiveCommand() {
|
|
argParser
|
|
..addOption('id', abbr: 'i', mandatory: true, help: 'Ticket ID to unarchive.')
|
|
..addOption(
|
|
'column',
|
|
abbr: 'c',
|
|
help: 'Column to restore to. Defaults to the first configured column.',
|
|
);
|
|
}
|
|
|
|
@override
|
|
final String name = 'unarchive';
|
|
|
|
@override
|
|
final String description = 'Restore an archived ticket to a column.';
|
|
|
|
@override
|
|
final String toolName = 'kanban_unarchive_ticket';
|
|
|
|
@override
|
|
Future<String> callAsTool(Map<String, dynamic> args) async {
|
|
final id = (args['id'] as String).toUpperCase();
|
|
|
|
final context = await ProjectContext.find();
|
|
final config = context.config.kanban;
|
|
final kanbanDir = p.join(context.root, '.project', 'kanban');
|
|
|
|
final store = TicketStore(kanbanDir: kanbanDir, prefix: config.prefix);
|
|
final ticket = await store.findById(id);
|
|
if (ticket == null) throw ArgumentError('Ticket $id not found.');
|
|
if (ticket.column != 'archive') return '$id is not archived.';
|
|
|
|
final columnArg = args['column'] as String?;
|
|
final targetColumn = columnArg ?? config.columns.first.id;
|
|
if (!config.columns.any((c) => c.id == targetColumn)) {
|
|
throw ArgumentError(
|
|
'Unknown column "$targetColumn". '
|
|
'Valid: ${config.columns.map((c) => c.id).join(', ')}',
|
|
);
|
|
}
|
|
|
|
final targetDir = Directory(p.join(kanbanDir, targetColumn));
|
|
await targetDir.create(recursive: true);
|
|
|
|
final srcFile = File(p.join(kanbanDir, 'archive', '$id.md'));
|
|
final dstFile = File(p.join(targetDir.path, '$id.md'));
|
|
await srcFile.rename(dstFile.path);
|
|
|
|
return 'Restored $id to "$targetColumn".';
|
|
}
|
|
}
|