Prepare 0.4.0 release
This commit is contained in:
parent
69fa044e5b
commit
1bc6a6447d
51 changed files with 225 additions and 67 deletions
26
CHANGELOG.md
26
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
13
packages/infra/CHANGELOG.md
Normal file
13
packages/infra/CHANGELOG.md
Normal file
|
|
@ -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.
|
||||
21
packages/infra/LICENSE
Normal file
21
packages/infra/LICENSE
Normal file
|
|
@ -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.
|
||||
22
packages/infra/README.md
Normal file
22
packages/infra/README.md
Normal file
|
|
@ -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:
|
||||
|
||||
<https://github.com/artificerchris/dew#readme>
|
||||
|
||||
## License
|
||||
|
||||
MIT — see [LICENSE](LICENSE).
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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.')
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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.')
|
||||
|
|
|
|||
|
|
@ -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<void> onInit(
|
||||
|
|
|
|||
|
|
@ -218,9 +218,10 @@ 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.
|
||||
/// Skips the [attachments] directory. Includes [archive].
|
||||
|
|
@ -231,9 +232,10 @@ 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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import 'package:dew_core/dew_core.dart';
|
|||
base class DewMcpServer extends MCPServer with ToolsSupport {
|
||||
DewMcpServer(super.channel, List<McpTool> 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.).',
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ String renderVaultOutput({
|
|||
if (format == 'json') {
|
||||
final payload = <String, dynamic>{
|
||||
'message': message,
|
||||
if (json != null) ...json,
|
||||
...?json,
|
||||
};
|
||||
return const JsonEncoder.withIndent(' ').convert(payload);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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<void> onInit(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ packages:
|
|||
source: hosted
|
||||
version: "4.1.4"
|
||||
dart_mcp:
|
||||
dependency: transitive
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: dart_mcp
|
||||
sha256: "92a2ee1cca577ed54fa4f3d5ae0e80ce2dd61e1892e793bb4f951b30eab9c4b1"
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue