From 1bc6a6447d3a2bc9982ea1f54a3263a28ec8067c Mon Sep 17 00:00:00 2001 From: Chris Hendrickson Date: Tue, 5 May 2026 01:42:08 -0400 Subject: [PATCH] Prepare 0.4.0 release --- CHANGELOG.md | 26 +++++++++++++++- README.md | 5 +++- docs/features/mcp.md | 30 +++++++++++++++++-- docs/index.md | 4 ++- packages/cli/CHANGELOG.md | 8 +++++ packages/cli/pubspec.yaml | 12 ++++---- packages/core/CHANGELOG.md | 8 +++++ packages/core/pubspec.yaml | 2 +- packages/infra/CHANGELOG.md | 13 ++++++++ packages/infra/LICENSE | 21 +++++++++++++ packages/infra/README.md | 22 ++++++++++++++ packages/infra/pubspec.yaml | 5 ++-- packages/kanban/CHANGELOG.md | 7 +++++ .../lib/src/commands/add_comment_command.dart | 2 +- .../lib/src/commands/archive_command.dart | 2 +- .../lib/src/commands/board_command.dart | 2 +- .../lib/src/commands/create_command.dart | 2 +- .../lib/src/commands/delete_command.dart | 2 +- .../kanban/lib/src/commands/get_command.dart | 2 +- .../lib/src/commands/get_config_command.dart | 2 +- .../kanban/lib/src/commands/link_command.dart | 5 ++-- .../kanban/lib/src/commands/list_command.dart | 2 +- .../kanban/lib/src/commands/move_command.dart | 2 +- .../lib/src/commands/search_command.dart | 2 +- .../lib/src/commands/stats_command.dart | 2 +- .../kanban/lib/src/commands/tui_command.dart | 20 ++++++++----- .../lib/src/commands/unarchive_command.dart | 2 +- .../lib/src/commands/unlink_command.dart | 2 +- .../lib/src/commands/update_command.dart | 2 +- packages/kanban/lib/src/kanban_init_hook.dart | 2 +- packages/kanban/lib/src/ticket_store.dart | 9 ++++-- packages/kanban/pubspec.yaml | 4 +-- packages/mcp/CHANGELOG.md | 8 +++++ packages/mcp/README.md | 3 +- packages/mcp/lib/src/dew_mcp_server.dart | 2 +- packages/mcp/pubspec.yaml | 6 ++-- packages/vault/CHANGELOG.md | 9 ++++++ packages/vault/lib/src/command_output.dart | 2 +- .../lib/src/commands/delete_command.dart | 2 +- .../lib/src/commands/generate_command.dart | 2 +- .../vault/lib/src/commands/get_command.dart | 2 +- .../vault/lib/src/commands/init_command.dart | 2 +- .../vault/lib/src/commands/list_command.dart | 2 +- .../lib/src/commands/rename_command.dart | 2 +- .../lib/src/commands/rotate_command.dart | 2 +- .../vault/lib/src/commands/set_command.dart | 2 +- .../lib/src/commands/update_command.dart | 2 +- packages/vault/lib/src/vault_init_hook.dart | 2 +- packages/vault/pubspec.yaml | 4 +-- pubspec.lock | 2 +- pubspec.yaml | 5 ++-- 51 files changed, 225 insertions(+), 67 deletions(-) create mode 100644 packages/infra/CHANGELOG.md create mode 100644 packages/infra/LICENSE create mode 100644 packages/infra/README.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 10763f8..94d9923 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.4.0] - 2026-05-05 + +### Added in 0.4.0 + +- Added `dew infra` for project infrastructure service discovery, validation, + configuration payloads, initialization payloads, lifecycle control, status, + logs, and cleanup. +- Added Podman Quadlet runtime support with a runtime boundary for future + container backends. +- Added manifest, configure, and init JSON Schema handling for infrastructure + services. +- Added sample infrastructure services for PostgreSQL 18, Valkey, RustFS, + Keycloak, pods, networks, volumes, and local image builds. +- Exposed every `dew infra` CLI path through Dew MCP tools, including + path-specific configure/init tools. + +### Changed in 0.4.0 + +- Extended MCP tool discovery so commands can provide extra path-specific tools + beyond one tool per subcommand. +- Raised package versions to `0.4.0` for the infra release. +- Cleaned existing analyzer info findings in kanban and vault ahead of release. + ## [0.1.0] - 2026-04-25 ### Added @@ -86,5 +109,6 @@ Full set of kanban subcommands, each also registered as an MCP tool automaticall - `ProjectDirs` with injectable filesystem abstraction (`package:file`) for testable path resolution. -[Unreleased]: https://github.com/artificerchris/dew/compare/v0.1.0...HEAD +[Unreleased]: https://github.com/artificerchris/dew/compare/v0.4.0...HEAD +[0.4.0]: https://github.com/artificerchris/dew/compare/v0.3.0...v0.4.0 [0.1.0]: https://github.com/artificerchris/dew/releases/tag/v0.1.0 diff --git a/README.md b/README.md index 8dfe91b..c757b2b 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,10 @@ The TUI auto-refreshes when ticket files change on disk, so it stays in sync whe ### MCP Server -`dew mcp serve` starts an MCP-compliant stdio server that exposes every kanban command as an MCP tool. AI agents (GitHub Copilot, Claude, etc.) can create tickets, move cards, search, and comment — using the exact same logic as the CLI. No separate tool definitions needed: every command that mixes in `DewToolCommand` is registered automatically. See the [MCP documentation](./docs/features/mcp.md). +`dew mcp serve` starts an MCP-compliant stdio server that exposes Dew commands +as MCP tools. AI agents (GitHub Copilot, Claude, etc.) can create tickets, move +cards, search, comment, and manage project infrastructure through the same logic +as the CLI. See the [MCP documentation](./docs/features/mcp.md). ## Installation diff --git a/docs/features/mcp.md b/docs/features/mcp.md index 2e1e114..17a4e11 100644 --- a/docs/features/mcp.md +++ b/docs/features/mcp.md @@ -6,9 +6,10 @@ The Dew Model Context Protocol (MCP) Server is a feature that allows AI agents t The MCP feature is split across two packages to keep concerns separate: -- **`packages/core`** defines the `DewToolCommand` mixin. Any command that mixes it in is automatically - registered as an MCP tool — the mixin derives the tool's JSON Schema directly from the command's own - `ArgParser`, so tools and CLI commands share a single definition. +- **`packages/core`** defines the `DewToolCommand` mixin and `McpToolProvider` + interface. Commands that mix in `DewToolCommand` are automatically registered + as MCP tools, and commands that implement `McpToolProvider` can expose extra + path-specific tools. - **`packages/mcp`** implements the actual server. It reads the list of tools from `CommandRegistry` and serves them over stdio using the [dart\_mcp](https://pub.dev/packages/dart_mcp) package. Only the `cli` package depends on `packages/mcp`; feature packages like `kanban` remain decoupled from the transport layer. @@ -74,6 +75,29 @@ The following tools are registered by the `kanban` package: | `kanban_link_tickets` | Link two tickets with a typed relationship (bidirectional) | | `kanban_unlink_tickets` | Remove a link between two tickets (both sides) | +The following tools are registered by the `infra` package: + +| Tool | Description | +| ---------------------------- | ------------------------------------------------ | +| `infra_list_services` | List infrastructure services | +| `infra_show_service` | Show manifest and runtime details | +| `infra_validate_services` | Validate one service or all services | +| `infra_configure_service` | CLI-default configure path placeholder | +| `infra_configure_schema` | Show the configure JSON Schema | +| `infra_configure_show` | Show the active configure payload | +| `infra_configure_apply` | Apply configure payload values | +| `infra_init_service` | CLI-default init path placeholder | +| `infra_init_schema` | Show the init JSON Schema | +| `infra_init_run` | Write an initialization payload | +| `infra_install_service` | Install service Quadlets | +| `infra_uninstall_service` | Uninstall service Quadlets | +| `infra_up_service` | Install, reload, and start services | +| `infra_down_service` | Stop services | +| `infra_restart_service` | Restart services | +| `infra_status_service` | Show service runtime status | +| `infra_logs` | Read service logs | +| `infra_delete_service` | Delete declared runtime artifacts | + ### Link types `kanban_link_tickets` requires a `--type` argument. The inverse is written automatically on the target ticket. diff --git a/docs/index.md b/docs/index.md index ed7a140..176f793 100644 --- a/docs/index.md +++ b/docs/index.md @@ -26,7 +26,9 @@ Dew is structured as a Dart workspace with the following packages: ### How commands become MCP tools -Every CLI command that mixes in `DewToolCommand` is automatically registered as an MCP tool — no separate registration needed. The mixin derives the JSON Schema for the tool's input from the command's own `ArgParser`, so argument definitions are written exactly once. +Every CLI command that mixes in `DewToolCommand` is automatically registered as +an MCP tool. Commands that need more granular tool paths can also implement +`McpToolProvider` to expose additional tools. ```text ArgParser definition diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index c9fa684..fd61251 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 0.4.0 — 2026-05-05 + +Infra release. + +- Added the `dew infra` command group to the CLI. +- Registered the infra package alongside kanban, MCP, and vault packages. +- Updated CLI dependencies for the `0.4.0` package set. + ## 0.1.0 — 2026-04-25 Initial release. diff --git a/packages/cli/pubspec.yaml b/packages/cli/pubspec.yaml index 6eb47d1..c57a305 100644 --- a/packages/cli/pubspec.yaml +++ b/packages/cli/pubspec.yaml @@ -1,6 +1,6 @@ name: dew description: Command-line interface for the Dew project management tool. -version: 0.1.0 +version: 0.4.0 repository: https://github.com/artificerchris/dew issue_tracker: https://github.com/artificerchris/dew/issues resolution: workspace @@ -10,11 +10,11 @@ environment: dependencies: args: ^2.7.0 - dew_core: ^0.1.0 - dew_infra: ^0.1.0 - dew_kanban: ^0.1.0 - dew_vault: ^0.3.0 - dew_mcp: ^0.1.0 + dew_core: ^0.4.0 + dew_infra: ^0.4.0 + dew_kanban: ^0.4.0 + dew_vault: ^0.4.0 + dew_mcp: ^0.4.0 dev_dependencies: lints: ^6.0.0 diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index e0fe8f6..388d1be 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 0.4.0 — 2026-05-05 + +Infra and MCP provider release. + +- Extended `CommandRegistry.mcpTools` to collect extra tools from + `McpToolProvider` command classes. +- Kept `InitCommand` analyzer-clean with the Dart SDK `3.12` lint set. + ## 0.1.0 — 2026-04-25 Initial release. diff --git a/packages/core/pubspec.yaml b/packages/core/pubspec.yaml index 652cf73..6f537ac 100644 --- a/packages/core/pubspec.yaml +++ b/packages/core/pubspec.yaml @@ -1,6 +1,6 @@ name: dew_core description: Core shared types, interfaces, and configuration for the Dew project management tool. -version: 0.1.0 +version: 0.4.0 repository: https://github.com/artificerchris/dew issue_tracker: https://github.com/artificerchris/dew/issues resolution: workspace diff --git a/packages/infra/CHANGELOG.md b/packages/infra/CHANGELOG.md new file mode 100644 index 0000000..e80bb91 --- /dev/null +++ b/packages/infra/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog + +## 0.4.0 — 2026-05-05 + +Initial public release. + +- Added infrastructure service discovery from `.project/infrastructure/services`. +- Added YAML service manifests with support for multiple Podman Quadlet files. +- Added manifest validation, JSON Schema validation, configuration payloads, and + initialization payloads. +- Added Podman Quadlet install, uninstall, up, down, restart, status, logs, and + delete operations behind a container runtime boundary. +- Added MCP tools for every `dew infra` CLI path. diff --git a/packages/infra/LICENSE b/packages/infra/LICENSE new file mode 100644 index 0000000..f64f1b0 --- /dev/null +++ b/packages/infra/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Chris Gebhardt + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/infra/README.md b/packages/infra/README.md new file mode 100644 index 0000000..3ed9d57 --- /dev/null +++ b/packages/infra/README.md @@ -0,0 +1,22 @@ +# dew_infra + +Infrastructure service management for the Dew CLI. + +`dew_infra` discovers service manifests under `.project/infrastructure`, +validates referenced Quadlet files and JSON Schemas, and manages Podman +Quadlets through systemd. It is designed around a runtime boundary so Dew can +support additional container runtimes in later releases. + +Most users should install the `dew` CLI package instead: + +```sh +dart pub global activate dew +``` + +See the main Dew documentation for the `dew infra` command reference: + + + +## License + +MIT — see [LICENSE](LICENSE). diff --git a/packages/infra/pubspec.yaml b/packages/infra/pubspec.yaml index 871fb06..dd7234d 100644 --- a/packages/infra/pubspec.yaml +++ b/packages/infra/pubspec.yaml @@ -1,7 +1,6 @@ name: dew_infra description: Infrastructure service management package for the Dew CLI. -publish_to: none -version: 0.1.0 +version: 0.4.0 repository: https://github.com/artificerchris/dew issue_tracker: https://github.com/artificerchris/dew/issues resolution: workspace @@ -11,7 +10,7 @@ environment: dependencies: args: ^2.7.0 - dew_core: ^0.1.0 + dew_core: ^0.4.0 file: ^7.0.1 json_schema: ^5.2.2 path: ^1.9.0 diff --git a/packages/kanban/CHANGELOG.md b/packages/kanban/CHANGELOG.md index 11fda1c..b6a6860 100644 --- a/packages/kanban/CHANGELOG.md +++ b/packages/kanban/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 0.4.0 — 2026-05-05 + +Release alignment for the `0.4.0` Dew package set. + +- Updated the `dew_core` dependency constraint for the infra release. +- Applied analyzer fixes for current Dart lint recommendations. + ## 0.1.0 — 2026-04-25 Initial release. diff --git a/packages/kanban/lib/src/commands/add_comment_command.dart b/packages/kanban/lib/src/commands/add_comment_command.dart index 3acf6ab..dbec547 100644 --- a/packages/kanban/lib/src/commands/add_comment_command.dart +++ b/packages/kanban/lib/src/commands/add_comment_command.dart @@ -8,7 +8,7 @@ import '../ticket_store.dart'; class AddCommentCommand extends DewCommand with DewToolCommand { final FileSystem _fs; - AddCommentCommand({FileSystem fs = const LocalFileSystem()}) : _fs = fs { + AddCommentCommand({this._fs = const LocalFileSystem()}) { argParser ..addOption( 'id', diff --git a/packages/kanban/lib/src/commands/archive_command.dart b/packages/kanban/lib/src/commands/archive_command.dart index 9cef477..b81537e 100644 --- a/packages/kanban/lib/src/commands/archive_command.dart +++ b/packages/kanban/lib/src/commands/archive_command.dart @@ -9,7 +9,7 @@ import '../ticket_store.dart'; class ArchiveCommand extends DewCommand with DewToolCommand { final FileSystem _fs; - ArchiveCommand({FileSystem fs = const LocalFileSystem()}) : _fs = fs { + ArchiveCommand({this._fs = const LocalFileSystem()}) { argParser.addOption( 'id', abbr: 'i', diff --git a/packages/kanban/lib/src/commands/board_command.dart b/packages/kanban/lib/src/commands/board_command.dart index e8bfcf3..81555e1 100644 --- a/packages/kanban/lib/src/commands/board_command.dart +++ b/packages/kanban/lib/src/commands/board_command.dart @@ -9,7 +9,7 @@ import '../ticket_store.dart'; class BoardCommand extends DewCommand with DewToolCommand { final FileSystem _fs; - BoardCommand({FileSystem fs = const LocalFileSystem()}) : _fs = fs { + BoardCommand({this._fs = const LocalFileSystem()}) { argParser ..addOption('type', abbr: 't', help: 'Filter tickets to this type.') ..addOption('label', help: 'Filter tickets to this label.') diff --git a/packages/kanban/lib/src/commands/create_command.dart b/packages/kanban/lib/src/commands/create_command.dart index a2c4ffb..4439a6c 100644 --- a/packages/kanban/lib/src/commands/create_command.dart +++ b/packages/kanban/lib/src/commands/create_command.dart @@ -8,7 +8,7 @@ import '../ticket_store.dart'; class CreateCommand extends DewCommand with DewToolCommand { final FileSystem _fs; - CreateCommand({FileSystem fs = const LocalFileSystem()}) : _fs = fs { + CreateCommand({this._fs = const LocalFileSystem()}) { argParser ..addOption('title', abbr: 't', mandatory: true, help: 'Ticket title.') ..addOption( diff --git a/packages/kanban/lib/src/commands/delete_command.dart b/packages/kanban/lib/src/commands/delete_command.dart index ecd5215..2387468 100644 --- a/packages/kanban/lib/src/commands/delete_command.dart +++ b/packages/kanban/lib/src/commands/delete_command.dart @@ -8,7 +8,7 @@ import '../ticket_store.dart'; class DeleteCommand extends DewCommand with DewToolCommand { final FileSystem _fs; - DeleteCommand({FileSystem fs = const LocalFileSystem()}) : _fs = fs { + DeleteCommand({this._fs = const LocalFileSystem()}) { argParser.addOption( 'id', abbr: 'i', diff --git a/packages/kanban/lib/src/commands/get_command.dart b/packages/kanban/lib/src/commands/get_command.dart index 93019e9..3600b81 100644 --- a/packages/kanban/lib/src/commands/get_command.dart +++ b/packages/kanban/lib/src/commands/get_command.dart @@ -9,7 +9,7 @@ import '../ticket_store.dart'; class GetCommand extends DewCommand with DewToolCommand { final FileSystem _fs; - GetCommand({FileSystem fs = const LocalFileSystem()}) : _fs = fs { + GetCommand({this._fs = const LocalFileSystem()}) { argParser.addOption( 'id', abbr: 'i', diff --git a/packages/kanban/lib/src/commands/get_config_command.dart b/packages/kanban/lib/src/commands/get_config_command.dart index bfad086..321a1d6 100644 --- a/packages/kanban/lib/src/commands/get_config_command.dart +++ b/packages/kanban/lib/src/commands/get_config_command.dart @@ -6,7 +6,7 @@ import '../kanban_config.dart'; class GetConfigCommand extends DewCommand with DewToolCommand { final FileSystem _fs; - GetConfigCommand({FileSystem fs = const LocalFileSystem()}) : _fs = fs; + GetConfigCommand({this._fs = const LocalFileSystem()}); @override final String name = 'config'; diff --git a/packages/kanban/lib/src/commands/link_command.dart b/packages/kanban/lib/src/commands/link_command.dart index aeb4635..54a1779 100644 --- a/packages/kanban/lib/src/commands/link_command.dart +++ b/packages/kanban/lib/src/commands/link_command.dart @@ -9,7 +9,7 @@ import '../ticket_store.dart'; class LinkCommand extends DewCommand with DewToolCommand { final FileSystem _fs; - LinkCommand({FileSystem fs = const LocalFileSystem()}) : _fs = fs { + LinkCommand({this._fs = const LocalFileSystem()}) { argParser ..addOption('id', abbr: 'i', mandatory: true, help: 'Source ticket ID.') ..addOption( @@ -44,8 +44,9 @@ class LinkCommand extends DewCommand with DewToolCommand { final targetId = '${args['target']}'.toUpperCase(); final type = '${args['type']}'; - if (id == targetId) + if (id == targetId) { throw ArgumentError('A ticket cannot be linked to itself.'); + } final context = await ProjectContext.find(fs: _fs); final store = TicketStore( diff --git a/packages/kanban/lib/src/commands/list_command.dart b/packages/kanban/lib/src/commands/list_command.dart index b8fc102..c9e52c5 100644 --- a/packages/kanban/lib/src/commands/list_command.dart +++ b/packages/kanban/lib/src/commands/list_command.dart @@ -9,7 +9,7 @@ import '../ticket_store.dart'; class ListCommand extends DewCommand with DewToolCommand { final FileSystem _fs; - ListCommand({FileSystem fs = const LocalFileSystem()}) : _fs = fs { + ListCommand({this._fs = const LocalFileSystem()}) { argParser ..addOption( 'column', diff --git a/packages/kanban/lib/src/commands/move_command.dart b/packages/kanban/lib/src/commands/move_command.dart index 2bbd7ce..1708b2f 100644 --- a/packages/kanban/lib/src/commands/move_command.dart +++ b/packages/kanban/lib/src/commands/move_command.dart @@ -8,7 +8,7 @@ import '../ticket_store.dart'; class MoveCommand extends DewCommand with DewToolCommand { final FileSystem _fs; - MoveCommand({FileSystem fs = const LocalFileSystem()}) : _fs = fs { + MoveCommand({this._fs = const LocalFileSystem()}) { argParser ..addOption('id', abbr: 'i', mandatory: true, help: 'Ticket ID.') ..addOption( diff --git a/packages/kanban/lib/src/commands/search_command.dart b/packages/kanban/lib/src/commands/search_command.dart index 6bb16a2..7932022 100644 --- a/packages/kanban/lib/src/commands/search_command.dart +++ b/packages/kanban/lib/src/commands/search_command.dart @@ -8,7 +8,7 @@ import '../ticket_store.dart'; class SearchCommand extends DewCommand with DewToolCommand { final FileSystem _fs; - SearchCommand({FileSystem fs = const LocalFileSystem()}) : _fs = fs { + SearchCommand({this._fs = const LocalFileSystem()}) { argParser ..addOption( 'query', diff --git a/packages/kanban/lib/src/commands/stats_command.dart b/packages/kanban/lib/src/commands/stats_command.dart index 3cd45d8..dbbb637 100644 --- a/packages/kanban/lib/src/commands/stats_command.dart +++ b/packages/kanban/lib/src/commands/stats_command.dart @@ -8,7 +8,7 @@ import '../ticket_store.dart'; class StatsCommand extends DewCommand with DewToolCommand { final FileSystem _fs; - StatsCommand({FileSystem fs = const LocalFileSystem()}) : _fs = fs; + StatsCommand({this._fs = const LocalFileSystem()}); @override final String name = 'stats'; diff --git a/packages/kanban/lib/src/commands/tui_command.dart b/packages/kanban/lib/src/commands/tui_command.dart index 6602fe3..f9fcd6a 100644 --- a/packages/kanban/lib/src/commands/tui_command.dart +++ b/packages/kanban/lib/src/commands/tui_command.dart @@ -214,7 +214,7 @@ class _Cell { class TuiCommand extends DewCommand { final FileSystem _fs; - TuiCommand({FileSystem fs = const LocalFileSystem()}) : _fs = fs; + TuiCommand({this._fs = const LocalFileSystem()}); @override final String name = 'tui'; @@ -410,8 +410,9 @@ class TuiCommand extends DewCommand { case ControlCharacter.arrowLeft: if (p.relationIdx > 0) p.relationIdx--; case ControlCharacter.arrowRight: - if (p.relationIdx < _linkRelations.length - 1) + if (p.relationIdx < _linkRelations.length - 1) { p.relationIdx++; + } case ControlCharacter.enter: try { await store.linkTickets( @@ -444,12 +445,14 @@ class TuiCommand extends DewCommand { p.input = p.input.substring(0, p.input.length - 1); } case ControlCharacter.arrowLeft: - if (p.kind == _PromptKind.newTitle && p.typeIdx > 0) + if (p.kind == _PromptKind.newTitle && p.typeIdx > 0) { p.typeIdx--; + } case ControlCharacter.arrowRight: if (p.kind == _PromptKind.newTitle && - p.typeIdx < config.ticketTypes.length - 1) + p.typeIdx < config.ticketTypes.length - 1) { p.typeIdx++; + } case ControlCharacter.enter: final trimmed = p.input.trim(); if (p.kind == _PromptKind.linkId) { @@ -712,8 +715,9 @@ class TuiCommand extends DewCommand { case _EditorField.labels: if (es.itemCursor < es.labels.length - 1) es.itemCursor++; case _EditorField.milestones: - if (es.itemCursor < es.milestones.length - 1) + if (es.itemCursor < es.milestones.length - 1) { es.itemCursor++; + } default: break; } @@ -1386,10 +1390,12 @@ class TuiCommand extends DewCommand { kv('Type', ticket.type); kv('Column', ticket.column); kv('Created', _fmtDate(ticket.created)); - if (ticket.milestones.isNotEmpty) + if (ticket.milestones.isNotEmpty) { kv('Milestones', ticket.milestones.join(', ')); - if (ticket.labels.isNotEmpty) + } + if (ticket.labels.isNotEmpty) { kv('Labels', ticket.labels.map((l) => '#$l').join(' ')); + } if (ticket.links.isNotEmpty) { for (final link in ticket.links) { kv(link.type, link.targetId); diff --git a/packages/kanban/lib/src/commands/unarchive_command.dart b/packages/kanban/lib/src/commands/unarchive_command.dart index f30a0f8..4bd1519 100644 --- a/packages/kanban/lib/src/commands/unarchive_command.dart +++ b/packages/kanban/lib/src/commands/unarchive_command.dart @@ -9,7 +9,7 @@ import '../ticket_store.dart'; class UnarchiveCommand extends DewCommand with DewToolCommand { final FileSystem _fs; - UnarchiveCommand({FileSystem fs = const LocalFileSystem()}) : _fs = fs { + UnarchiveCommand({this._fs = const LocalFileSystem()}) { argParser ..addOption( 'id', diff --git a/packages/kanban/lib/src/commands/unlink_command.dart b/packages/kanban/lib/src/commands/unlink_command.dart index c41d301..68ac7f3 100644 --- a/packages/kanban/lib/src/commands/unlink_command.dart +++ b/packages/kanban/lib/src/commands/unlink_command.dart @@ -8,7 +8,7 @@ import '../ticket_store.dart'; class UnlinkCommand extends DewCommand with DewToolCommand { final FileSystem _fs; - UnlinkCommand({FileSystem fs = const LocalFileSystem()}) : _fs = fs { + UnlinkCommand({this._fs = const LocalFileSystem()}) { argParser ..addOption('id', abbr: 'i', mandatory: true, help: 'Source ticket ID.') ..addOption( diff --git a/packages/kanban/lib/src/commands/update_command.dart b/packages/kanban/lib/src/commands/update_command.dart index 918ef75..fbe4667 100644 --- a/packages/kanban/lib/src/commands/update_command.dart +++ b/packages/kanban/lib/src/commands/update_command.dart @@ -8,7 +8,7 @@ import '../ticket_store.dart'; class UpdateCommand extends DewCommand with DewToolCommand { final FileSystem _fs; - UpdateCommand({FileSystem fs = const LocalFileSystem()}) : _fs = fs { + UpdateCommand({this._fs = const LocalFileSystem()}) { argParser ..addOption('id', abbr: 'i', mandatory: true, help: 'Ticket ID.') ..addOption('title', abbr: 't', help: 'New title.') diff --git a/packages/kanban/lib/src/kanban_init_hook.dart b/packages/kanban/lib/src/kanban_init_hook.dart index f5df996..42c41d8 100644 --- a/packages/kanban/lib/src/kanban_init_hook.dart +++ b/packages/kanban/lib/src/kanban_init_hook.dart @@ -8,7 +8,7 @@ import 'kanban_config.dart'; class KanbanInitHook implements DewInitHook { final FileSystem _fs; - KanbanInitHook({FileSystem fs = const LocalFileSystem()}) : _fs = fs; + KanbanInitHook({this._fs = const LocalFileSystem()}); @override Future onInit( diff --git a/packages/kanban/lib/src/ticket_store.dart b/packages/kanban/lib/src/ticket_store.dart index a384965..ceb08a5 100644 --- a/packages/kanban/lib/src/ticket_store.dart +++ b/packages/kanban/lib/src/ticket_store.dart @@ -218,8 +218,9 @@ class TicketStore { await found.file.delete(); // Clean up per-ticket attachment directory if present. final attachmentsDir = fs.directory(p.join(kanbanDir, 'attachments', id)); - if (await attachmentsDir.exists()) + if (await attachmentsDir.exists()) { await attachmentsDir.delete(recursive: true); + } } /// Searches all column subdirectories (one level deep) for a ticket file. @@ -231,8 +232,9 @@ class TicketStore { if (entity is! Directory) continue; if (p.basename(entity.path) == 'attachments') continue; final file = fs.file(p.join(entity.path, '$id.md')); - if (await file.exists()) + if (await file.exists()) { return (file: file, column: p.basename(entity.path)); + } } return null; } @@ -243,8 +245,9 @@ class TicketStore { final pattern = RegExp(r'^' + RegExp.escape(prefix) + r'-(\d+)\.md$'); var max = 0; await for (final entity in dir.list()) { - if (entity is! Directory || p.basename(entity.path) == 'attachments') + if (entity is! Directory || p.basename(entity.path) == 'attachments') { continue; + } await for (final file in entity.list()) { final match = pattern.firstMatch(p.basename(file.path)); if (match != null) { diff --git a/packages/kanban/pubspec.yaml b/packages/kanban/pubspec.yaml index 182ae2c..045b2d8 100644 --- a/packages/kanban/pubspec.yaml +++ b/packages/kanban/pubspec.yaml @@ -1,6 +1,6 @@ name: dew_kanban description: Kanban board feature for the Dew project management tool. Implements McpToolProvider to expose board tools to the MCP server. -version: 0.1.0 +version: 0.4.0 repository: https://github.com/artificerchris/dew issue_tracker: https://github.com/artificerchris/dew/issues resolution: workspace @@ -10,7 +10,7 @@ environment: # Add regular dependencies here. dependencies: - dew_core: ^0.1.0 + dew_core: ^0.4.0 dart_console: ^4.1.2 file: ^7.0.1 path: ^1.9.0 diff --git a/packages/mcp/CHANGELOG.md b/packages/mcp/CHANGELOG.md index fbbbfd5..2c7a4a3 100644 --- a/packages/mcp/CHANGELOG.md +++ b/packages/mcp/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 0.4.0 — 2026-05-05 + +Infra MCP tool release. + +- Published with `dew_core` `0.4.0`, which allows commands to expose + path-specific MCP tools through `McpToolProvider`. +- Updated test coverage for provider-supplied MCP tools. + ## 0.1.0 — 2026-04-25 Initial release. diff --git a/packages/mcp/README.md b/packages/mcp/README.md index f3425f3..0e53bd8 100644 --- a/packages/mcp/README.md +++ b/packages/mcp/README.md @@ -2,7 +2,8 @@ MCP (Model Context Protocol) server package for the [Dew](https://github.com/artificerchris/dew) project management tool. -Exposes all Dew kanban operations as MCP tools so AI assistants (GitHub Copilot, Claude, etc.) can manage your kanban board directly. +Exposes Dew operations as MCP tools so AI assistants (GitHub Copilot, Claude, +etc.) can manage your kanban board and project infrastructure directly. ## Usage diff --git a/packages/mcp/lib/src/dew_mcp_server.dart b/packages/mcp/lib/src/dew_mcp_server.dart index 72b3114..af559fe 100644 --- a/packages/mcp/lib/src/dew_mcp_server.dart +++ b/packages/mcp/lib/src/dew_mcp_server.dart @@ -5,7 +5,7 @@ import 'package:dew_core/dew_core.dart'; base class DewMcpServer extends MCPServer with ToolsSupport { DewMcpServer(super.channel, List tools) : super.fromStreamChannel( - implementation: Implementation(name: 'dew', version: '1.0.0'), + implementation: Implementation(name: 'dew', version: '0.4.0'), instructions: 'Tools for managing a Dew project (kanban tickets, etc.).', ) { diff --git a/packages/mcp/pubspec.yaml b/packages/mcp/pubspec.yaml index 645a810..4d1c591 100644 --- a/packages/mcp/pubspec.yaml +++ b/packages/mcp/pubspec.yaml @@ -1,6 +1,6 @@ name: dew_mcp description: MCP server for the Dew project management tool. Collects and serves tools registered by feature packages via the McpToolProvider interface. -version: 0.1.0 +version: 0.4.0 repository: https://github.com/artificerchris/dew issue_tracker: https://github.com/artificerchris/dew/issues resolution: workspace @@ -10,11 +10,11 @@ environment: # Add regular dependencies here. dependencies: - dew_core: ^0.1.0 + dew_core: ^0.4.0 dart_mcp: ^0.5.0 yaml: ^3.1.0 dev_dependencies: lints: ^6.0.0 test: ^1.25.6 - dew_kanban: ^0.1.0 + dew_kanban: ^0.4.0 diff --git a/packages/vault/CHANGELOG.md b/packages/vault/CHANGELOG.md index 396a6d2..9cb60e8 100644 --- a/packages/vault/CHANGELOG.md +++ b/packages/vault/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 0.4.0 — 2026-05-05 + +Release alignment for the `0.4.0` Dew package set. + +- Updated the `dew_core` dependency constraint for the infra release. +- Published vault with the SDK floor and config path fixes from the development + branch. +- Applied analyzer fixes for current Dart lint recommendations. + ## 0.3.0 — 2026-05-03 Implemented vault command behavior end-to-end and completed release-readiness features. diff --git a/packages/vault/lib/src/command_output.dart b/packages/vault/lib/src/command_output.dart index 144ee6d..9e9b9fa 100644 --- a/packages/vault/lib/src/command_output.dart +++ b/packages/vault/lib/src/command_output.dart @@ -12,7 +12,7 @@ String renderVaultOutput({ if (format == 'json') { final payload = { 'message': message, - if (json != null) ...json, + ...?json, }; return const JsonEncoder.withIndent(' ').convert(payload); } diff --git a/packages/vault/lib/src/commands/delete_command.dart b/packages/vault/lib/src/commands/delete_command.dart index 2966a11..647f0b5 100644 --- a/packages/vault/lib/src/commands/delete_command.dart +++ b/packages/vault/lib/src/commands/delete_command.dart @@ -9,7 +9,7 @@ import '../command_output.dart'; class DeleteCommand extends DewCommand with DewToolCommand { final FileSystem _fs; - DeleteCommand({FileSystem fs = const LocalFileSystem()}) : _fs = fs { + DeleteCommand({this._fs = const LocalFileSystem()}) { argParser ..addOption( 'name', diff --git a/packages/vault/lib/src/commands/generate_command.dart b/packages/vault/lib/src/commands/generate_command.dart index 0ec33cb..b5efc7f 100644 --- a/packages/vault/lib/src/commands/generate_command.dart +++ b/packages/vault/lib/src/commands/generate_command.dart @@ -9,7 +9,7 @@ import '../vault_generators.dart'; class GenerateCommand extends DewCommand with DewToolCommand { final FileSystem _fs; - GenerateCommand({FileSystem fs = const LocalFileSystem()}) : _fs = fs { + GenerateCommand({this._fs = const LocalFileSystem()}) { argParser ..addOption( 'generator', diff --git a/packages/vault/lib/src/commands/get_command.dart b/packages/vault/lib/src/commands/get_command.dart index c518b2c..33d4d98 100644 --- a/packages/vault/lib/src/commands/get_command.dart +++ b/packages/vault/lib/src/commands/get_command.dart @@ -9,7 +9,7 @@ import '../vault_store.dart'; class GetCommand extends DewCommand with DewToolCommand { final FileSystem _fs; - GetCommand({FileSystem fs = const LocalFileSystem()}) : _fs = fs { + GetCommand({this._fs = const LocalFileSystem()}) { argParser ..addOption('name', abbr: 'n', mandatory: true, help: 'Secret name.') ..addOption( diff --git a/packages/vault/lib/src/commands/init_command.dart b/packages/vault/lib/src/commands/init_command.dart index a2d9da9..fac7901 100644 --- a/packages/vault/lib/src/commands/init_command.dart +++ b/packages/vault/lib/src/commands/init_command.dart @@ -8,7 +8,7 @@ import '../command_output.dart'; class VaultInitCommand extends DewCommand with DewToolCommand { final FileSystem _fs; - VaultInitCommand({FileSystem fs = const LocalFileSystem()}) : _fs = fs { + VaultInitCommand({this._fs = const LocalFileSystem()}) { argParser ..addOption( 'password-file', diff --git a/packages/vault/lib/src/commands/list_command.dart b/packages/vault/lib/src/commands/list_command.dart index 0b6c181..6512486 100644 --- a/packages/vault/lib/src/commands/list_command.dart +++ b/packages/vault/lib/src/commands/list_command.dart @@ -9,7 +9,7 @@ import '../command_output.dart'; class ListCommand extends DewCommand with DewToolCommand { final FileSystem _fs; - ListCommand({FileSystem fs = const LocalFileSystem()}) : _fs = fs { + ListCommand({this._fs = const LocalFileSystem()}) { argParser.addOption( 'format', defaultsTo: 'default', diff --git a/packages/vault/lib/src/commands/rename_command.dart b/packages/vault/lib/src/commands/rename_command.dart index bcaae78..32c4b3e 100644 --- a/packages/vault/lib/src/commands/rename_command.dart +++ b/packages/vault/lib/src/commands/rename_command.dart @@ -9,7 +9,7 @@ import '../vault_store.dart'; class RenameCommand extends DewCommand with DewToolCommand { final FileSystem _fs; - RenameCommand({FileSystem fs = const LocalFileSystem()}) : _fs = fs { + RenameCommand({this._fs = const LocalFileSystem()}) { argParser ..addOption( 'from', diff --git a/packages/vault/lib/src/commands/rotate_command.dart b/packages/vault/lib/src/commands/rotate_command.dart index ecb9879..1be356e 100644 --- a/packages/vault/lib/src/commands/rotate_command.dart +++ b/packages/vault/lib/src/commands/rotate_command.dart @@ -10,7 +10,7 @@ import '../vault_store.dart'; class RotateCommand extends DewCommand with DewToolCommand { final FileSystem _fs; - RotateCommand({FileSystem fs = const LocalFileSystem()}) : _fs = fs { + RotateCommand({this._fs = const LocalFileSystem()}) { argParser ..addOption('name', help: 'Secret name to rotate; omit to rotate vault password.') ..addOption( diff --git a/packages/vault/lib/src/commands/set_command.dart b/packages/vault/lib/src/commands/set_command.dart index 863b5c8..03d9256 100644 --- a/packages/vault/lib/src/commands/set_command.dart +++ b/packages/vault/lib/src/commands/set_command.dart @@ -9,7 +9,7 @@ import '../vault_store.dart'; class SetCommand extends DewCommand with DewToolCommand { final FileSystem _fs; - SetCommand({FileSystem fs = const LocalFileSystem()}) : _fs = fs { + SetCommand({this._fs = const LocalFileSystem()}) { argParser ..addOption( 'name', diff --git a/packages/vault/lib/src/commands/update_command.dart b/packages/vault/lib/src/commands/update_command.dart index 5e2232b..16b775e 100644 --- a/packages/vault/lib/src/commands/update_command.dart +++ b/packages/vault/lib/src/commands/update_command.dart @@ -9,7 +9,7 @@ import '../command_output.dart'; class UpdateCommand extends DewCommand with DewToolCommand { final FileSystem _fs; - UpdateCommand({FileSystem fs = const LocalFileSystem()}) : _fs = fs { + UpdateCommand({this._fs = const LocalFileSystem()}) { argParser ..addOption( 'name', diff --git a/packages/vault/lib/src/vault_init_hook.dart b/packages/vault/lib/src/vault_init_hook.dart index 902803f..a39fa8b 100644 --- a/packages/vault/lib/src/vault_init_hook.dart +++ b/packages/vault/lib/src/vault_init_hook.dart @@ -6,7 +6,7 @@ import 'package:path/path.dart' as p; class VaultInitHook implements DewInitHook { final FileSystem _fs; - VaultInitHook({FileSystem fs = const LocalFileSystem()}) : _fs = fs; + VaultInitHook({this._fs = const LocalFileSystem()}); @override Future onInit( diff --git a/packages/vault/pubspec.yaml b/packages/vault/pubspec.yaml index d1adfb7..0f16e8e 100644 --- a/packages/vault/pubspec.yaml +++ b/packages/vault/pubspec.yaml @@ -1,6 +1,6 @@ name: dew_vault description: Vault feature package for the Dew project management tool. -version: 0.3.0 +version: 0.4.0 repository: https://github.com/artificerchris/dew issue_tracker: https://github.com/artificerchris/dew/issues resolution: workspace @@ -9,7 +9,7 @@ environment: sdk: ^3.12.0 dependencies: - dew_core: ^0.1.0 + dew_core: ^0.4.0 file: ^7.0.1 pointycastle: ^4.0.0 path: ^1.9.0 diff --git a/pubspec.lock b/pubspec.lock index 1e9b462..c6522bf 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -154,7 +154,7 @@ packages: source: hosted version: "4.1.4" dart_mcp: - dependency: transitive + dependency: "direct dev" description: name: dart_mcp sha256: "92a2ee1cca577ed54fa4f3d5ae0e80ce2dd61e1892e793bb4f951b30eab9c4b1" diff --git a/pubspec.yaml b/pubspec.yaml index 3a4d994..a27e520 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: dew_workspace description: A Dart workspace for the dew project management tool. -version: 0.1.0 +version: 0.4.0 repository: https://github.com/artificerchris/dew publish_to: none @@ -15,11 +15,10 @@ workspace: - packages/vault dev_dependencies: + dart_mcp: ^0.5.0 file: ^7.0.1 lints: ^6.0.0 melos: ^7.0.0 - - melos: scripts: analyze: