Skip to content

Commit bc90433

Browse files
authored
Add pub add format guidance (#278)
1 parent 845c126 commit bc90433

File tree

4 files changed

+105
-20
lines changed

4 files changed

+105
-20
lines changed

pkgs/dart_mcp_server/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* Add an `--exclude-tool` command line flag to exclude tools by name.
1515
* Add the abillity to limit the output of `analyze_files` to a set of paths.
1616
* Stop reporting non-zero exit codes from command line tools as tool errors.
17+
* Add descriptions for pub tools, add support for `pub deps` and `pub outdated`.
1718

1819
# 0.1.0 (Dart SDK 3.9.0)
1920

pkgs/dart_mcp_server/lib/src/mixins/pub.dart

Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -87,21 +87,18 @@ base mixin PubSupport on ToolsSupport, LoggingSupport, RootsTrackingSupport
8787
inputSchema: Schema.object(
8888
properties: {
8989
ParameterNames.command: Schema.string(
90-
title: 'The pub command to run.',
91-
description:
92-
'Currently only ${SupportedPubCommand.listAll} are supported.',
90+
title: 'The pub subcommand to run.',
91+
enumValues: SupportedPubCommand.values
92+
.map<String>((e) => e.name)
93+
.toList(),
94+
description: SupportedPubCommand.commandDescriptions,
9395
),
9496
ParameterNames.packageNames: Schema.list(
9597
title: 'The package names to run the command for.',
9698
description:
9799
'This is required for the '
98100
'${SupportedPubCommand.listAllThatRequirePackageName} commands. ',
99-
items: Schema.string(
100-
title: 'A package to run the command for.',
101-
description:
102-
'When used with "add", prefix with "dev:" to add the package '
103-
'as a dev dependency.',
104-
),
101+
items: Schema.string(title: 'A package to run the command for.'),
105102
),
106103
ParameterNames.roots: rootsSchema(),
107104
},
@@ -112,22 +109,49 @@ base mixin PubSupport on ToolsSupport, LoggingSupport, RootsTrackingSupport
112109

113110
/// The set of supported `dart pub` subcommands.
114111
enum SupportedPubCommand {
115-
// This is supported in a simplified form: `dart pub add <package-name>`.
116-
// TODO(https://github.com/dart-lang/ai/issues/77): add support for adding
117-
// dev dependencies.
118-
add(requiresPackageNames: true),
119-
120-
get,
112+
add(
113+
requiresPackageNames: true,
114+
description: '''Add package dependencies.
115+
- To add a package normally (typical): "pkg_name"
116+
- Git reference: "pkg_name:{git:{url: https://github.com/pkg_name/pkg_name.git, ref: branch, path: subdir}}"
117+
- ref and path are optional.
118+
- From local path: "pkg_name:{path: ../pkg_name}"
119+
- Dev Dependency: "dev:pkg_name"
120+
- Dependency override: "override:pkg_name:1.0.0"
121+
''',
122+
),
123+
124+
deps(description: 'Print the dependency tree of the current package.'),
125+
126+
get(
127+
description: "Fetch the current package's dependencies and install them.",
128+
),
129+
130+
outdated(
131+
description: 'Analyze dependencies to find which ones can be upgraded.',
132+
),
121133

122134
// This is supported in a simplified form: `dart pub remove <package-name>`.
123-
remove(requiresPackageNames: true),
135+
remove(
136+
requiresPackageNames: true,
137+
description: 'Removes specified dependencies from `pubspec.yaml`.',
138+
),
124139

125-
upgrade;
140+
upgrade(
141+
description:
142+
"Upgrade the current package's dependencies to latest versions.",
143+
);
126144

127-
const SupportedPubCommand({this.requiresPackageNames = false});
145+
const SupportedPubCommand({
146+
this.requiresPackageNames = false,
147+
required this.description,
148+
});
128149

129150
final bool requiresPackageNames;
130151

152+
/// The description to use in the subcommand help.
153+
final String description;
154+
131155
static SupportedPubCommand? fromName(String name) {
132156
for (final command in SupportedPubCommand.values) {
133157
if (command.name == name) {
@@ -147,6 +171,22 @@ enum SupportedPubCommand {
147171
);
148172
}
149173

174+
static String get commandDescriptions {
175+
return 'Available subcommands:\n${_getDescriptions(values)}';
176+
}
177+
178+
static String _getDescriptions(Iterable<SupportedPubCommand> commands) {
179+
final buffer = StringBuffer();
180+
for (final command in commands) {
181+
final commandName = command.name;
182+
final description = command.description;
183+
if (description.isNotEmpty) {
184+
buffer.writeln('- `$commandName`: $description');
185+
}
186+
}
187+
return buffer.toString();
188+
}
189+
150190
static String _writeCommandsAsList(List<SupportedPubCommand> commands) {
151191
final buffer = StringBuffer();
152192
for (var i = 0; i < commands.length; i++) {

pkgs/dart_mcp_server/test/tools/analyzer_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ void main() {
309309
],
310310
},
311311
);
312-
final result = await testHarness.callToolWithRetry(request);
312+
final result = await testHarness.callToolWithRetry(request, maxTries: 10);
313313
expect(result.isError, isNot(true));
314314
expect(result.content, hasLength(2));
315315
expect(

pkgs/dart_mcp_server/test/tools/pub_test.dart

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,50 @@ void main() {
160160
]);
161161
});
162162

163+
test('deps', () async {
164+
final request = CallToolRequest(
165+
name: dartPubTool.name,
166+
arguments: {
167+
ParameterNames.command: 'deps',
168+
ParameterNames.roots: [
169+
{ParameterNames.root: testRoot.uri},
170+
],
171+
},
172+
);
173+
final result = await testHarness.callToolWithRetry(request);
174+
175+
// Verify the command was sent to the process manager without error.
176+
expect(result.isError, isNot(true));
177+
expect(testProcessManager.commandsRan, [
178+
equalsCommand((
179+
command: [endsWith(executableName), 'pub', 'deps'],
180+
workingDirectory: testRoot.path,
181+
)),
182+
]);
183+
});
184+
185+
test('outdated', () async {
186+
final request = CallToolRequest(
187+
name: dartPubTool.name,
188+
arguments: {
189+
ParameterNames.command: 'outdated',
190+
ParameterNames.roots: [
191+
{ParameterNames.root: testRoot.uri},
192+
],
193+
},
194+
);
195+
final result = await testHarness.callToolWithRetry(request);
196+
197+
// Verify the command was sent to the process manager without error.
198+
expect(result.isError, isNot(true));
199+
expect(testProcessManager.commandsRan, [
200+
equalsCommand((
201+
command: [endsWith(executableName), 'pub', 'outdated'],
202+
workingDirectory: testRoot.path,
203+
)),
204+
]);
205+
});
206+
163207
test('in a subdir of an a root', () async {
164208
fileSystem.file(p.join(fakeAppPath, 'subdir', 'pubspec.yaml'))
165209
..createSync(recursive: true)
@@ -214,7 +258,7 @@ void main() {
214258

215259
expect(
216260
(result.content.single as TextContent).text,
217-
contains('Unsupported pub command `publish`.'),
261+
contains('String "publish" is not one of the allowed values:'),
218262
);
219263
expect(testProcessManager.commandsRan, isEmpty);
220264
});

0 commit comments

Comments
 (0)