From 66c1d6055061536521f079089319947cdc5b82a8 Mon Sep 17 00:00:00 2001 From: Dominik Simonik Date: Wed, 21 Oct 2026 14:02:40 +0200 Subject: [PATCH 1/2] chore: run very_good_analysis with no rule overrides Both packages disabled public_member_api_docs. Very Good CLI disables nothing and excludes generated files in the analyzer section instead, so do the same and document the members that were missing a comment. The lint reads a Dart 3.13 primary constructor as an undocumented member, and the class's own doc comment does not satisfy it. The only thing that does is declaring the constructor in the body as `this;` under `/// {@macro name}`. Very Good CLI puts its constructor doc in the same place; it just never needs the bare declaration, because it has no primary constructors. --- AGENTS.md | 5 +++-- packages/plugin_source/analysis_options.yaml | 3 --- .../src/format/plugin_parse_exception.dart | 3 +++ .../lib/src/model/agent_asset.dart | 5 ++++- .../lib/src/model/hook_asset.dart | 8 +++++++- .../lib/src/model/mcp_server.dart | 9 +++++++++ .../lib/src/model/plugin_assets.dart | 3 +++ .../lib/src/model/skill_asset.dart | 3 +++ .../lib/src/parser/claude_plugin_parser.dart | 3 +++ .../lib/src/parser/claude_schemas.dart | 12 +++++++++++ .../plugin_source/lib/src/plugin_ref.dart | 3 +++ .../plugin_source/lib/src/resolution.dart | 13 ++++++++++-- packages/vgv_ai_cli/analysis_options.yaml | 7 ++++--- .../commands/doctor/model/fix_command.dart | 3 +++ .../commands/doctor/model/report_section.dart | 3 +++ .../lib/src/commands/update_command.dart | 5 +++++ .../lib/src/detect/harness_detector.dart | 3 +++ .../lib/src/document/markdown_text.dart | 3 +++ .../src/document/model/normalized_text.dart | 3 +++ .../lib/src/document/model/section_span.dart | 5 ++++- .../lib/src/document/model/toml_region.dart | 3 +++ .../src/document/model/toml_statement.dart | 3 +++ .../lib/src/document/toml_scanner.dart | 3 +++ .../lib/src/document/toml_text.dart | 3 +++ .../lib/src/manifest/manifest_auditor.dart | 3 +++ .../lib/src/manifest/manifest_store.dart | 3 +++ .../lib/src/manifest/model/reversal.dart | 5 ++++- .../src/manifest/model/reverse_decision.dart | 5 ++++- .../lib/src/model/document_codec.dart | 3 +++ packages/vgv_ai_cli/lib/src/model/drift.dart | 3 +++ .../lib/src/model/install_manifest.dart | 12 +++++++++++ .../vgv_ai_cli/lib/src/model/subtraction.dart | 5 ++++- .../src/reconcile/model/applied_change.dart | 5 ++++- .../lib/src/reconcile/model/deep_merge.dart | 5 ++++- .../src/reconcile/model/reconciliation.dart | 5 ++++- .../lib/src/reconcile/model/text_merge.dart | 5 ++++- .../src/reconcile/model/write_decision.dart | 5 ++++- .../lib/src/reconcile/reconciler.dart | 3 +++ .../src/resolve/model/asset_resolution.dart | 20 +++++++++++++++---- .../lib/src/translate/agents_brick.dart | 3 +++ .../lib/src/translate/agents_vars.dart | 3 +++ .../lib/src/translate/harness_translator.dart | 3 +++ .../lib/src/translate/hook_scripts.dart | 8 +++++++- .../src/translate/model/harness_fields.dart | 3 +++ .../src/translate/model/hook_translation.dart | 5 ++++- .../src/translate/model/translation_note.dart | 3 +++ .../src/translate/model/translation_plan.dart | 3 +++ .../translate/model/translation_result.dart | 5 ++++- .../lib/src/translate/translator.dart | 3 +++ .../translators/antigravity_translator.dart | 3 +++ .../translators/claude_translator.dart | 3 +++ .../translators/codex_translator.dart | 3 +++ .../translators/copilot_translator.dart | 3 +++ .../translators/gemini_translator.dart | 3 +++ .../translators/opencode_translator.dart | 3 +++ .../translate/translators/pi_translator.dart | 3 +++ .../translators/skills_translator.dart | 3 +++ packages/vgv_ai_cli/lib/vgv_ai_cli.dart | 4 ++-- 58 files changed, 238 insertions(+), 30 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 974cc0fc..6420f983 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -124,8 +124,9 @@ You should not need to bump the version by hand at all: release-please owns it. ## Code Conventions -- Linting: `very_good_analysis` ^11.0.0, with `public_member_api_docs` disabled. Public classes still carry `/// {@template name}` / `/// {@macro name}` doc comments. -- The codebase uses **Dart 3.13 syntax**. Unnamed constructors are declared with the `new` keyword — `new({required this._logger})`, not `UpdateCommand({...})`. Empty class bodies use a semicolon — `class _MockLogger extends Mock implements Logger;`. +- Linting: `very_good_analysis` ^11.0.0 with no rule overrides, the same as Very Good CLI. Generated files are excluded in the `analyzer` section rather than by turning rules off. +- Every public class carries `/// {@template name}` / `/// {@endtemplate}`, and declares its constructor in the body under `/// {@macro name}` — `this;`, or `this { ... }` when it has one. The declaration is not optional: `public_member_api_docs` reads a primary constructor as an undocumented member, and the class's own doc comment does not satisfy it. +- The codebase uses **Dart 3.13 syntax**. Unnamed constructors are declared with the `new` keyword — `new({required this._logger})`, not `UpdateCommand({...})`. Empty class bodies use a semicolon — `class _MockLogger extends Mock implements Logger;`. That is for private classes such as test doubles; a public class still needs a body to hold the documented constructor above. - Commits and PR titles follow [Conventional Commits](https://www.conventionalcommits.org/). ### Testing diff --git a/packages/plugin_source/analysis_options.yaml b/packages/plugin_source/analysis_options.yaml index ce42cd44..9df80aa4 100644 --- a/packages/plugin_source/analysis_options.yaml +++ b/packages/plugin_source/analysis_options.yaml @@ -1,4 +1 @@ include: package:very_good_analysis/analysis_options.yaml -linter: - rules: - public_member_api_docs: false diff --git a/packages/plugin_source/lib/src/format/plugin_parse_exception.dart b/packages/plugin_source/lib/src/format/plugin_parse_exception.dart index 2359c922..0e7dd7d6 100644 --- a/packages/plugin_source/lib/src/format/plugin_parse_exception.dart +++ b/packages/plugin_source/lib/src/format/plugin_parse_exception.dart @@ -7,6 +7,9 @@ /// {@endtemplate} class const PluginParseException(final String path, final String message) implements Exception { + /// {@macro plugin_parse_exception} + this; + @override String toString() => 'Could not parse $path: $message'; } diff --git a/packages/plugin_source/lib/src/model/agent_asset.dart b/packages/plugin_source/lib/src/model/agent_asset.dart index a086b284..144e1154 100644 --- a/packages/plugin_source/lib/src/model/agent_asset.dart +++ b/packages/plugin_source/lib/src/model/agent_asset.dart @@ -13,4 +13,7 @@ class const AgentAsset({ /// The skills the agent expects to have loaded. required final List skills, -}); +}) { + /// {@macro agent_asset} + this; +} diff --git a/packages/plugin_source/lib/src/model/hook_asset.dart b/packages/plugin_source/lib/src/model/hook_asset.dart index 58f13c9d..ffeadb5d 100644 --- a/packages/plugin_source/lib/src/model/hook_asset.dart +++ b/packages/plugin_source/lib/src/model/hook_asset.dart @@ -14,6 +14,9 @@ class const HookCommand({ required final String command, final int? timeout, }) { + /// {@macro hook_command} + this; + /// Stands in for the plugin's root directory inside [command]. /// /// Parsers rewrite their harness's own placeholder to this one, so @@ -38,4 +41,7 @@ class const HookAsset({ required final Directory pluginRoot, final String? matcher, final String? agent, -}); +}) { + /// {@macro hook_asset} + this; +} diff --git a/packages/plugin_source/lib/src/model/mcp_server.dart b/packages/plugin_source/lib/src/model/mcp_server.dart index a1406fe9..364ef194 100644 --- a/packages/plugin_source/lib/src/model/mcp_server.dart +++ b/packages/plugin_source/lib/src/model/mcp_server.dart @@ -12,6 +12,9 @@ sealed class const MCPServer({ /// The name the plugin declares the server under, unique across plugins. required final String name, }) { + /// {@macro mcp_server} + this; + /// The server as a `.mcp.json` file declares it under its [name], leaving /// out every empty list and map rather than writing it empty. Map toJson(); @@ -32,6 +35,9 @@ final class const LocalMCPServer({ /// Environment variables set for the subprocess. final Map env = const {}, }) extends MCPServer { + /// {@macro local_mcp_server} + this; + @override Map toJson() => { 'command': command, @@ -52,6 +58,9 @@ final class const RemoteMCPServer({ /// Headers sent with each request. final Map headers = const {}, }) extends MCPServer { + /// {@macro remote_mcp_server} + this; + @override Map toJson() => { 'url': url, diff --git a/packages/plugin_source/lib/src/model/plugin_assets.dart b/packages/plugin_source/lib/src/model/plugin_assets.dart index 48443aa8..6b17761a 100644 --- a/packages/plugin_source/lib/src/model/plugin_assets.dart +++ b/packages/plugin_source/lib/src/model/plugin_assets.dart @@ -24,6 +24,9 @@ class const PluginAssets({ /// itself names in its settings. final List plugins = const [], }) { + /// {@macro plugin_assets} + this; + /// Combines what the [plugins] contribute into one [PluginAssets]. /// /// Each skill, agent and MCP server is written to a path or key derived diff --git a/packages/plugin_source/lib/src/model/skill_asset.dart b/packages/plugin_source/lib/src/model/skill_asset.dart index a293f599..63509161 100644 --- a/packages/plugin_source/lib/src/model/skill_asset.dart +++ b/packages/plugin_source/lib/src/model/skill_asset.dart @@ -17,6 +17,9 @@ class const SkillAsset({ required final Map portableFrontmatter, required final Directory directory, }) { + /// {@macro skill_asset} + this; + /// The frontmatter keys every harness understands: the open Agent Skills /// specification's key set. Parsers keep exactly these and drop everything /// else, so a harness-specific key never reaches another harness's skill. diff --git a/packages/plugin_source/lib/src/parser/claude_plugin_parser.dart b/packages/plugin_source/lib/src/parser/claude_plugin_parser.dart index 2d34601d..fd8186fa 100644 --- a/packages/plugin_source/lib/src/parser/claude_plugin_parser.dart +++ b/packages/plugin_source/lib/src/parser/claude_plugin_parser.dart @@ -15,6 +15,9 @@ import 'package:plugin_source/src/parser/plugin_parser.dart'; /// inconsistent shapes the two plugins ship and throws on anything else. /// {@endtemplate} class const ClaudePluginParser() implements PluginParser { + /// {@macro claude_plugin_parser} + this; + @override PluginAssets parse(Directory root) { final agents = _readAgents(root.childDirectory('agents')); diff --git a/packages/plugin_source/lib/src/parser/claude_schemas.dart b/packages/plugin_source/lib/src/parser/claude_schemas.dart index cf73f171..bffe00af 100644 --- a/packages/plugin_source/lib/src/parser/claude_schemas.dart +++ b/packages/plugin_source/lib/src/parser/claude_schemas.dart @@ -21,6 +21,7 @@ extension type PluginManifestJson(Map _json) { 'name': Ack.string().optional(), }).passthrough(); + /// The plugin's name as the manifest declares it, or null when unset. String? get name => _json['name'] as String?; } @@ -53,14 +54,19 @@ extension type McpServerJson(Map _json) { 'env': Ack.map(Ack.string()).optional(), }).passthrough(); + /// The endpoint a remote server is reached at, or null for a local one. String? get url => _json['url'] as String?; + /// Headers sent with each request to [url]. Map get headers => _strings(_json['headers']); + /// The executable a local server launches, or null for a remote one. String? get command => _json['command'] as String?; + /// Arguments passed to [command]. List get args => [...?_json['args'] as List?]; + /// Environment variables set for the subprocess launched by [command]. Map get env => _strings(_json['env']); static Map _strings(Object? block) => @@ -105,8 +111,10 @@ extension type HookRegistrationJson(Map _json) { 'hooks': Ack.list(HookJson._schema), }).passthrough(); + /// Which tools this registration fires for, or null for every tool. String? get matcher => _json['matcher'] as String?; + /// The hooks this registration runs. List get hooks => [ for (final hook in _json['hooks']! as List) HookJson(hook! as Map), @@ -122,10 +130,14 @@ extension type HookJson(Map _json) { 'timeout': Ack.integer().optional(), }).passthrough(); + /// The hook's kind, such as `command`. String? get type => _json['type'] as String?; + /// The shell command this hook runs, or null when it runs nothing + /// translatable. String? get command => _json['command'] as String?; + /// How long the command may run, or null for no limit. int? get timeout => _json['timeout'] as int?; } diff --git a/packages/plugin_source/lib/src/plugin_ref.dart b/packages/plugin_source/lib/src/plugin_ref.dart index 8617b453..f937c68d 100644 --- a/packages/plugin_source/lib/src/plugin_ref.dart +++ b/packages/plugin_source/lib/src/plugin_ref.dart @@ -20,6 +20,9 @@ class const PluginRef({ required final String version, required final String gitRef, }) { + /// {@macro plugin_ref} + this; + @override String toString() => '$name@$version'; } diff --git a/packages/plugin_source/lib/src/resolution.dart b/packages/plugin_source/lib/src/resolution.dart index 9548e1ca..f60ae85e 100644 --- a/packages/plugin_source/lib/src/resolution.dart +++ b/packages/plugin_source/lib/src/resolution.dart @@ -7,13 +7,19 @@ import 'package:file/file.dart'; /// plugin, collapsing a cache miss, a missing tag, an absent git binary and an /// unwritable cache root into one indistinguishable `null`. /// {@endtemplate} -sealed class const PluginResolution(); +sealed class const PluginResolution() { + /// {@macro plugin_resolution} + this; +} /// {@template resolved_plugin} /// The plugin was found on disk at [directory]. /// {@endtemplate} final class const ResolvedPlugin(final Directory directory) - extends PluginResolution; + extends PluginResolution { + /// {@macro resolved_plugin} + this; +} /// {@template unavailable_plugin} /// No source could supply the plugin. @@ -24,6 +30,9 @@ final class const ResolvedPlugin(final Directory directory) /// {@endtemplate} final class const UnavailablePlugin(final List reasons) extends PluginResolution { + /// {@macro unavailable_plugin} + this; + /// {@macro unavailable_plugin} /// /// Convenience for a single source, which has exactly one reason. diff --git a/packages/vgv_ai_cli/analysis_options.yaml b/packages/vgv_ai_cli/analysis_options.yaml index ce42cd44..511661a0 100644 --- a/packages/vgv_ai_cli/analysis_options.yaml +++ b/packages/vgv_ai_cli/analysis_options.yaml @@ -1,4 +1,5 @@ include: package:very_good_analysis/analysis_options.yaml -linter: - rules: - public_member_api_docs: false +analyzer: + exclude: + - "**/*.g.dart" + - "**/version.dart" diff --git a/packages/vgv_ai_cli/lib/src/commands/doctor/model/fix_command.dart b/packages/vgv_ai_cli/lib/src/commands/doctor/model/fix_command.dart index c6bd7753..4e023768 100644 --- a/packages/vgv_ai_cli/lib/src/commands/doctor/model/fix_command.dart +++ b/packages/vgv_ai_cli/lib/src/commands/doctor/model/fix_command.dart @@ -18,6 +18,9 @@ class const FixCommand({ /// harness with `install --plugin`. final Set plugins = const {}, }) { + /// {@macro fix_command} + this; + /// One command that does what every one of [fixes] does, or null when /// there are none, or when they install different plugins and so cannot /// be said in one command. diff --git a/packages/vgv_ai_cli/lib/src/commands/doctor/model/report_section.dart b/packages/vgv_ai_cli/lib/src/commands/doctor/model/report_section.dart index 95741356..eb008b54 100644 --- a/packages/vgv_ai_cli/lib/src/commands/doctor/model/report_section.dart +++ b/packages/vgv_ai_cli/lib/src/commands/doctor/model/report_section.dart @@ -21,6 +21,9 @@ class const ReportSection({ /// fixes them all. final Set? plugins = const {}, }) { + /// {@macro report_section} + this; + /// Whether anything was found that is wrong. bool get hasProblems => findings.any((finding) => finding.isProblem); diff --git a/packages/vgv_ai_cli/lib/src/commands/update_command.dart b/packages/vgv_ai_cli/lib/src/commands/update_command.dart index 0882e674..236d439f 100644 --- a/packages/vgv_ai_cli/lib/src/commands/update_command.dart +++ b/packages/vgv_ai_cli/lib/src/commands/update_command.dart @@ -11,11 +11,16 @@ import 'package:vgv_ai_cli/src/version.dart'; /// {@endtemplate} class UpdateCommand({required final Logger _logger, PubUpdater? pubUpdater}) extends Command { + /// {@macro update_command} + this; + final PubUpdater _pubUpdater = pubUpdater ?? PubUpdater(); @override String get description => 'Update vgv_ai to the latest version.'; + /// The name the CLI registers `update` under, so other code can name it + /// without constructing one. The runner skips its update check for it. static const String commandName = 'update'; @override diff --git a/packages/vgv_ai_cli/lib/src/detect/harness_detector.dart b/packages/vgv_ai_cli/lib/src/detect/harness_detector.dart index efeed1d3..11291936 100644 --- a/packages/vgv_ai_cli/lib/src/detect/harness_detector.dart +++ b/packages/vgv_ai_cli/lib/src/detect/harness_detector.dart @@ -31,6 +31,9 @@ class const HarnessDetector({ final RunProcess _runProcess = Process.run, final Duration _timeout = const Duration(seconds: 5), }) { + /// {@macro harness_detector} + this; + /// Matches the first `x.y.z` in a version banner. static final _versionPattern = RegExp(r'\d+\.\d+\.\d+'); diff --git a/packages/vgv_ai_cli/lib/src/document/markdown_text.dart b/packages/vgv_ai_cli/lib/src/document/markdown_text.dart index 18c2c842..fd77b4d0 100644 --- a/packages/vgv_ai_cli/lib/src/document/markdown_text.dart +++ b/packages/vgv_ai_cli/lib/src/document/markdown_text.dart @@ -18,6 +18,9 @@ class const MarkdownText( /// The file's text, as written. final String source, ) { + /// {@macro markdown_text} + this; + /// Opens the section named [name]. static String sectionStart(String name) => ''; diff --git a/packages/vgv_ai_cli/lib/src/document/model/normalized_text.dart b/packages/vgv_ai_cli/lib/src/document/model/normalized_text.dart index e2695fdc..d63aec2d 100644 --- a/packages/vgv_ai_cli/lib/src/document/model/normalized_text.dart +++ b/packages/vgv_ai_cli/lib/src/document/model/normalized_text.dart @@ -9,6 +9,9 @@ class const NormalizedText({ /// The line ending of the text [text] was normalized from. required final String ending, }) { + /// {@macro normalized_text} + this; + /// {@macro normalized_text} /// /// Normalizes [original], so an edit of it can be turned back into diff --git a/packages/vgv_ai_cli/lib/src/document/model/section_span.dart b/packages/vgv_ai_cli/lib/src/document/model/section_span.dart index 0b2e6279..d567bed2 100644 --- a/packages/vgv_ai_cli/lib/src/document/model/section_span.dart +++ b/packages/vgv_ai_cli/lib/src/document/model/section_span.dart @@ -8,4 +8,7 @@ class const SectionSpan({ /// The offset just past the section's end marker. required final int end, -}); +}) { + /// {@macro section_span} + this; +} diff --git a/packages/vgv_ai_cli/lib/src/document/model/toml_region.dart b/packages/vgv_ai_cli/lib/src/document/model/toml_region.dart index a2753315..07abae2f 100644 --- a/packages/vgv_ai_cli/lib/src/document/model/toml_region.dart +++ b/packages/vgv_ai_cli/lib/src/document/model/toml_region.dart @@ -11,6 +11,9 @@ class const TomlRegion({ /// Every statement after [header] up to the next header. required final List body, }) { + /// {@macro toml_region} + this; + /// The statement that sets [key] in this table, if any. TomlStatement? statementOf(String key) => body.firstWhereOrNull( (s) => s.declares(TomlStatementKind.keyValue, [key]), diff --git a/packages/vgv_ai_cli/lib/src/document/model/toml_statement.dart b/packages/vgv_ai_cli/lib/src/document/model/toml_statement.dart index bb2e1fb5..af2a8399 100644 --- a/packages/vgv_ai_cli/lib/src/document/model/toml_statement.dart +++ b/packages/vgv_ai_cli/lib/src/document/model/toml_statement.dart @@ -41,6 +41,9 @@ class const TomlStatement({ /// inside a value that spans several lines. required final bool hasInnerComment, }) { + /// {@macro toml_statement} + this; + /// Whether the statement opens a table or an array of tables. bool get isHeader => kind == TomlStatementKind.table || kind == TomlStatementKind.arrayTable; diff --git a/packages/vgv_ai_cli/lib/src/document/toml_scanner.dart b/packages/vgv_ai_cli/lib/src/document/toml_scanner.dart index 422b9918..d2312ced 100644 --- a/packages/vgv_ai_cli/lib/src/document/toml_scanner.dart +++ b/packages/vgv_ai_cli/lib/src/document/toml_scanner.dart @@ -6,6 +6,9 @@ import 'package:vgv_ai_cli/src/document/model/model.dart'; /// or array is one statement however many lines it spans. /// {@endtemplate} class TomlScanner(final List lines) { + /// {@macro toml_scanner} + this; + /// The region of [lines] that holds [table], or null when the document /// has no `[table]` header for it. An empty [table] is the document's top /// level. diff --git a/packages/vgv_ai_cli/lib/src/document/toml_text.dart b/packages/vgv_ai_cli/lib/src/document/toml_text.dart index cfcf7c64..53f62297 100644 --- a/packages/vgv_ai_cli/lib/src/document/toml_text.dart +++ b/packages/vgv_ai_cli/lib/src/document/toml_text.dart @@ -18,6 +18,9 @@ class const TomlText( /// Compares what an edit decodes to with what it meant to produce. final DocumentCodec codec = const DocumentCodec(), }) { + /// {@macro toml_text} + this; + /// {@macro toml_text} /// /// [map] encoded as canonical TOML with a trailing newline. diff --git a/packages/vgv_ai_cli/lib/src/manifest/manifest_auditor.dart b/packages/vgv_ai_cli/lib/src/manifest/manifest_auditor.dart index 49da2137..1c87f823 100644 --- a/packages/vgv_ai_cli/lib/src/manifest/manifest_auditor.dart +++ b/packages/vgv_ai_cli/lib/src/manifest/manifest_auditor.dart @@ -18,6 +18,9 @@ class const ManifestAuditor({ /// Decodes and compares what is on disk with what VGV recorded. final DocumentCodec codec = const DocumentCodec(), }) { + /// {@macro manifest_auditor} + this; + /// Checks that what [entry] records is still on disk, as VGV wrote it. /// /// Never writes, and reports a file it cannot read rather than throwing. diff --git a/packages/vgv_ai_cli/lib/src/manifest/manifest_store.dart b/packages/vgv_ai_cli/lib/src/manifest/manifest_store.dart index 81dadcbe..600a2944 100644 --- a/packages/vgv_ai_cli/lib/src/manifest/manifest_store.dart +++ b/packages/vgv_ai_cli/lib/src/manifest/manifest_store.dart @@ -14,6 +14,9 @@ class const ManifestStore( /// The home directory the manifest records, and is kept under. final Directory home, ) { + /// {@macro manifest_store} + this; + /// Why a manifest this version cannot read is left as it is. static const unreadable = 'the manifest was written by a newer version of vgv_ai, so it was ' diff --git a/packages/vgv_ai_cli/lib/src/manifest/model/reversal.dart b/packages/vgv_ai_cli/lib/src/manifest/model/reversal.dart index 0527f3f0..0b50290f 100644 --- a/packages/vgv_ai_cli/lib/src/manifest/model/reversal.dart +++ b/packages/vgv_ai_cli/lib/src/manifest/model/reversal.dart @@ -13,4 +13,7 @@ class const Reversal({ /// longer hold anything of VGV's. On a dry run it records what would /// have been taken back. required final InstallManifest manifest, -}); +}) { + /// {@macro reversal} + this; +} diff --git a/packages/vgv_ai_cli/lib/src/manifest/model/reverse_decision.dart b/packages/vgv_ai_cli/lib/src/manifest/model/reverse_decision.dart index b529afc2..18e61d82 100644 --- a/packages/vgv_ai_cli/lib/src/manifest/model/reverse_decision.dart +++ b/packages/vgv_ai_cli/lib/src/manifest/model/reverse_decision.dart @@ -20,4 +20,7 @@ class const ReverseDecision({ /// Only a file that is still VGV's is deleted through a link, so forcing /// cannot reach a file the user put at the other end. final bool throughLink = true, -}); +}) { + /// {@macro reverse_decision} + this; +} diff --git a/packages/vgv_ai_cli/lib/src/model/document_codec.dart b/packages/vgv_ai_cli/lib/src/model/document_codec.dart index 926dceaf..a977f396 100644 --- a/packages/vgv_ai_cli/lib/src/model/document_codec.dart +++ b/packages/vgv_ai_cli/lib/src/model/document_codec.dart @@ -13,6 +13,9 @@ class const DocumentCodec({ /// Compares decoded documents, and the values inside them, structurally. final DeepCollectionEquality deepEquality = const DeepCollectionEquality(), }) { + /// {@macro document_codec} + this; + /// The keys whose list is an argv: a command and its arguments. static const Set _argvKeys = {'command', 'args'}; diff --git a/packages/vgv_ai_cli/lib/src/model/drift.dart b/packages/vgv_ai_cli/lib/src/model/drift.dart index 480b296f..19c6abac 100644 --- a/packages/vgv_ai_cli/lib/src/model/drift.dart +++ b/packages/vgv_ai_cli/lib/src/model/drift.dart @@ -9,6 +9,9 @@ class const Drift({ /// The key paths, or section names, that hold a different value now. required final List drifted, }) { + /// {@macro drift} + this; + /// Whether nothing is missing and nothing has drifted. bool get isEmpty => missing.isEmpty && drifted.isEmpty; } diff --git a/packages/vgv_ai_cli/lib/src/model/install_manifest.dart b/packages/vgv_ai_cli/lib/src/model/install_manifest.dart index 2ad537cc..985f4c81 100644 --- a/packages/vgv_ai_cli/lib/src/model/install_manifest.dart +++ b/packages/vgv_ai_cli/lib/src/model/install_manifest.dart @@ -18,6 +18,9 @@ sealed class const ManifestEntry({ /// The harness the file configures, or null for the shared skills. required final Harness? owner, }) extends Equatable { + /// {@macro manifest_entry} + this; + /// How [path] was written. ChangeMode get mode; @@ -105,6 +108,9 @@ final class const OwnedFile({ /// The SHA-256 of what VGV last wrote. required final String sha256, }) extends ManifestEntry { + /// {@macro owned_file} + this; + /// {@macro owned_file} /// /// Records [bytes] as what VGV wrote to [path]. @@ -137,6 +143,9 @@ final class const MergedDocument({ /// The part of the document that is VGV's. required final Contribution contribution, }) extends ManifestEntry { + /// {@macro merged_document} + this; + @override ChangeMode get mode => format.mode; @@ -154,6 +163,9 @@ final class const MarkdownSections({ /// Each section's name to the SHA-256 of the body VGV last wrote there. required final Map sections, }) extends ManifestEntry { + /// {@macro markdown_sections} + this; + /// This entry with [body] recorded as what VGV wrote into section [name]. MarkdownSections recording(String name, String body) => MarkdownSections( path: path, diff --git a/packages/vgv_ai_cli/lib/src/model/subtraction.dart b/packages/vgv_ai_cli/lib/src/model/subtraction.dart index aafa8be5..4b767b19 100644 --- a/packages/vgv_ai_cli/lib/src/model/subtraction.dart +++ b/packages/vgv_ai_cli/lib/src/model/subtraction.dart @@ -7,4 +7,7 @@ class const Subtraction({ /// Whether any of what VGV wrote was kept, because the user changed it. required final bool kept, -}); +}) { + /// {@macro subtraction} + this; +} diff --git a/packages/vgv_ai_cli/lib/src/reconcile/model/applied_change.dart b/packages/vgv_ai_cli/lib/src/reconcile/model/applied_change.dart index 36e88522..218a7941 100644 --- a/packages/vgv_ai_cli/lib/src/reconcile/model/applied_change.dart +++ b/packages/vgv_ai_cli/lib/src/reconcile/model/applied_change.dart @@ -43,4 +43,7 @@ class AppliedChange({ /// Why the change [ChangeOutcome.failed], and null otherwise. final String? error, -}); +}) { + /// {@macro applied_change} + this; +} diff --git a/packages/vgv_ai_cli/lib/src/reconcile/model/deep_merge.dart b/packages/vgv_ai_cli/lib/src/reconcile/model/deep_merge.dart index d349d10d..98a143e2 100644 --- a/packages/vgv_ai_cli/lib/src/reconcile/model/deep_merge.dart +++ b/packages/vgv_ai_cli/lib/src/reconcile/model/deep_merge.dart @@ -11,4 +11,7 @@ class const DeepMerge({ /// Whether the merge kept a value the user set in place of VGV's. required final bool declined, -}); +}) { + /// {@macro deep_merge} + this; +} diff --git a/packages/vgv_ai_cli/lib/src/reconcile/model/reconciliation.dart b/packages/vgv_ai_cli/lib/src/reconcile/model/reconciliation.dart index bbf0656a..4f5aa0c3 100644 --- a/packages/vgv_ai_cli/lib/src/reconcile/model/reconciliation.dart +++ b/packages/vgv_ai_cli/lib/src/reconcile/model/reconciliation.dart @@ -12,4 +12,7 @@ class const Reconciliation({ /// The manifest the changes were applied against, updated with what they /// wrote. On a dry run it records what they would have written. required final InstallManifest manifest, -}); +}) { + /// {@macro reconciliation} + this; +} diff --git a/packages/vgv_ai_cli/lib/src/reconcile/model/text_merge.dart b/packages/vgv_ai_cli/lib/src/reconcile/model/text_merge.dart index 6bd06ac9..288e9a8c 100644 --- a/packages/vgv_ai_cli/lib/src/reconcile/model/text_merge.dart +++ b/packages/vgv_ai_cli/lib/src/reconcile/model/text_merge.dart @@ -15,4 +15,7 @@ class const TextMerge({ /// What of [contents] VGV contributed, and null when nothing could be /// parsed. final Contribution? contribution, -}); +}) { + /// {@macro text_merge} + this; +} diff --git a/packages/vgv_ai_cli/lib/src/reconcile/model/write_decision.dart b/packages/vgv_ai_cli/lib/src/reconcile/model/write_decision.dart index b56e739f..d92950da 100644 --- a/packages/vgv_ai_cli/lib/src/reconcile/model/write_decision.dart +++ b/packages/vgv_ai_cli/lib/src/reconcile/model/write_decision.dart @@ -16,4 +16,7 @@ class const WriteDecision({ /// entry as it is, and a [MergedDocument] with an empty contribution drops /// it, since nothing in the file is VGV's. final ManifestEntry? entry, -}); +}) { + /// {@macro write_decision} + this; +} diff --git a/packages/vgv_ai_cli/lib/src/reconcile/reconciler.dart b/packages/vgv_ai_cli/lib/src/reconcile/reconciler.dart index cd4bc0bc..2c977e2d 100644 --- a/packages/vgv_ai_cli/lib/src/reconcile/reconciler.dart +++ b/packages/vgv_ai_cli/lib/src/reconcile/reconciler.dart @@ -18,6 +18,9 @@ class const Reconciler({ /// Decodes and compares what is on disk with what VGV writes. final DocumentCodec codec = const DocumentCodec(), }) { + /// {@macro reconciler} + this; + /// Applies every one of [changes] against [manifest], and returns what /// each did and the manifest updated with what they wrote. /// diff --git a/packages/vgv_ai_cli/lib/src/resolve/model/asset_resolution.dart b/packages/vgv_ai_cli/lib/src/resolve/model/asset_resolution.dart index 285a071d..07c0e697 100644 --- a/packages/vgv_ai_cli/lib/src/resolve/model/asset_resolution.dart +++ b/packages/vgv_ai_cli/lib/src/resolve/model/asset_resolution.dart @@ -3,7 +3,10 @@ import 'package:plugin_source/plugin_source.dart'; /// {@template asset_resolution} /// What resolving and parsing every pinned plugin produced. /// {@endtemplate} -sealed class const AssetResolution(); +sealed class const AssetResolution() { + /// {@macro asset_resolution} + this; +} /// {@template resolved_assets} /// Every plugin resolved and parsed, merged into [assets], which names them. @@ -11,7 +14,10 @@ sealed class const AssetResolution(); final class const ResolvedAssets({ /// What the plugins contribute, merged. required final PluginAssets assets, -}) extends AssetResolution; +}) extends AssetResolution { + /// {@macro resolved_assets} + this; +} /// {@template unavailable_assets} /// No source could supply [plugin], for each of [reasons]. @@ -22,7 +28,10 @@ final class const UnavailableAssets( /// Why, one reason per source tried, in the order they were tried. final List reasons, -) extends AssetResolution; +) extends AssetResolution { + /// {@macro unavailable_assets} + this; +} /// {@template unparseable_assets} /// [plugin] resolved, but could not be parsed because of [error]. @@ -33,4 +42,7 @@ final class const UnparseableAssets( /// Why it could not be parsed. final PluginParseException error, -) extends AssetResolution; +) extends AssetResolution { + /// {@macro unparseable_assets} + this; +} diff --git a/packages/vgv_ai_cli/lib/src/translate/agents_brick.dart b/packages/vgv_ai_cli/lib/src/translate/agents_brick.dart index 465e609c..5f133c6a 100644 --- a/packages/vgv_ai_cli/lib/src/translate/agents_brick.dart +++ b/packages/vgv_ai_cli/lib/src/translate/agents_brick.dart @@ -13,6 +13,9 @@ import 'package:vgv_ai_cli/src/templates/templates.dart'; /// back. The brick has no hooks, so the bundle's files are all it needs. /// {@endtemplate} class const AgentsBrick() { + /// {@macro agents_brick} + this; + /// Renders every file [vars] select, keyed by its path in the brick. Future> render(Map vars) async { final generator = MasonGenerator( diff --git a/packages/vgv_ai_cli/lib/src/translate/agents_vars.dart b/packages/vgv_ai_cli/lib/src/translate/agents_vars.dart index d34422d6..851fa9c7 100644 --- a/packages/vgv_ai_cli/lib/src/translate/agents_vars.dart +++ b/packages/vgv_ai_cli/lib/src/translate/agents_vars.dart @@ -21,6 +21,9 @@ class const AgentsVars({ /// The hooks fragment of each harness that has one. final Map hooks = const {}, }) { + /// {@macro agents_vars} + this; + /// The vars, keyed as the brick reads them. /// /// `agents` and `commands` are left out when empty: the brick loops a file diff --git a/packages/vgv_ai_cli/lib/src/translate/harness_translator.dart b/packages/vgv_ai_cli/lib/src/translate/harness_translator.dart index 1f697863..31aad5ac 100644 --- a/packages/vgv_ai_cli/lib/src/translate/harness_translator.dart +++ b/packages/vgv_ai_cli/lib/src/translate/harness_translator.dart @@ -20,6 +20,9 @@ import 'package:vgv_ai_cli/src/translate/model/model.dart'; /// See `Harness` for every step of adding a harness. /// {@endtemplate} abstract class const HarnessTranslator() { + /// {@macro harness_translator} + this; + /// Which harness this configures. Harness get harness; diff --git a/packages/vgv_ai_cli/lib/src/translate/hook_scripts.dart b/packages/vgv_ai_cli/lib/src/translate/hook_scripts.dart index 5ddf74f0..b8b445e4 100644 --- a/packages/vgv_ai_cli/lib/src/translate/hook_scripts.dart +++ b/packages/vgv_ai_cli/lib/src/translate/hook_scripts.dart @@ -25,6 +25,9 @@ class const HookScripts({ /// What goes below the shebang of a script a hook runs. required final String preamble, }) { + /// {@macro hook_scripts} + this; + /// The folder a Claude Code plugin keeps its hooks in. static const hooksFolder = 'hooks'; @@ -307,7 +310,10 @@ class const HookScripts({ class const HookCopy({ required final List files, required final List notes, -}); +}) { + /// {@macro hook_copy} + this; +} /// One file of a plugin's hooks folder as the copy holds it; [hook] is any /// hook of the plugin, [relative] its path from the plugin root, and diff --git a/packages/vgv_ai_cli/lib/src/translate/model/harness_fields.dart b/packages/vgv_ai_cli/lib/src/translate/model/harness_fields.dart index c6d6f9cd..76f223f8 100644 --- a/packages/vgv_ai_cli/lib/src/translate/model/harness_fields.dart +++ b/packages/vgv_ai_cli/lib/src/translate/model/harness_fields.dart @@ -18,6 +18,9 @@ class const HarnessFields({ /// frontmatter rather than through the shared pointer. final String? instructions, }) extends Equatable { + /// {@macro harness_fields} + this; + /// The fields keyed as the brick reads them, leaving out every null one. Map toMap() => { 'frontmatter': ?frontmatter, diff --git a/packages/vgv_ai_cli/lib/src/translate/model/hook_translation.dart b/packages/vgv_ai_cli/lib/src/translate/model/hook_translation.dart index 0ec2f2af..81e5c8ad 100644 --- a/packages/vgv_ai_cli/lib/src/translate/model/hook_translation.dart +++ b/packages/vgv_ai_cli/lib/src/translate/model/hook_translation.dart @@ -16,4 +16,7 @@ class const HookTranslation({ /// What could not be translated as intended, and what the user must do. final List notes = const [], -}); +}) { + /// {@macro hook_translation} + this; +} diff --git a/packages/vgv_ai_cli/lib/src/translate/model/translation_note.dart b/packages/vgv_ai_cli/lib/src/translate/model/translation_note.dart index b6c7512f..63564962 100644 --- a/packages/vgv_ai_cli/lib/src/translate/model/translation_note.dart +++ b/packages/vgv_ai_cli/lib/src/translate/model/translation_note.dart @@ -13,6 +13,9 @@ class const TranslationNote({ /// Why. required final String reason, }) extends Equatable { + /// {@macro translation_note} + this; + @override List get props => [subject, reason]; diff --git a/packages/vgv_ai_cli/lib/src/translate/model/translation_plan.dart b/packages/vgv_ai_cli/lib/src/translate/model/translation_plan.dart index 3c7fb972..d513905b 100644 --- a/packages/vgv_ai_cli/lib/src/translate/model/translation_plan.dart +++ b/packages/vgv_ai_cli/lib/src/translate/model/translation_plan.dart @@ -12,6 +12,9 @@ class const TranslationPlan({ /// Each selected harness's own result, in reporting order. final Map harnesses = const {}, }) { + /// {@macro translation_plan} + this; + /// Every planned change, the shared ones first. List get changes => [ ...?shared?.changes, diff --git a/packages/vgv_ai_cli/lib/src/translate/model/translation_result.dart b/packages/vgv_ai_cli/lib/src/translate/model/translation_result.dart index 405c9fed..9dff0eab 100644 --- a/packages/vgv_ai_cli/lib/src/translate/model/translation_result.dart +++ b/packages/vgv_ai_cli/lib/src/translate/model/translation_result.dart @@ -13,4 +13,7 @@ class const TranslationResult({ /// Everything this harness could not express. final List notes = const [], -}); +}) { + /// {@macro translation_result} + this; +} diff --git a/packages/vgv_ai_cli/lib/src/translate/translator.dart b/packages/vgv_ai_cli/lib/src/translate/translator.dart index 30fc69d9..a0b8f90c 100644 --- a/packages/vgv_ai_cli/lib/src/translate/translator.dart +++ b/packages/vgv_ai_cli/lib/src/translate/translator.dart @@ -18,6 +18,9 @@ class const Translator({ final AgentsBrick brick = const AgentsBrick(), final SkillsTranslator skills = const SkillsTranslator(), }) { + /// {@macro translator} + this; + /// The changes and notes for each of [selected], plus the shared skills /// when any of them reads them. Future translate({ diff --git a/packages/vgv_ai_cli/lib/src/translate/translators/antigravity_translator.dart b/packages/vgv_ai_cli/lib/src/translate/translators/antigravity_translator.dart index c1218848..e3970e48 100644 --- a/packages/vgv_ai_cli/lib/src/translate/translators/antigravity_translator.dart +++ b/packages/vgv_ai_cli/lib/src/translate/translators/antigravity_translator.dart @@ -20,6 +20,9 @@ import 'package:vgv_ai_cli/src/translate/translate.dart'; /// See https://antigravity.google/docs/plugins/. /// {@endtemplate} class const AntigravityTranslator() extends HarnessTranslator { + /// {@macro antigravity_translator} + this; + /// The plugin everything is installed as. static const plugin = 'vgv'; diff --git a/packages/vgv_ai_cli/lib/src/translate/translators/claude_translator.dart b/packages/vgv_ai_cli/lib/src/translate/translators/claude_translator.dart index 1dae2f81..975b1e84 100644 --- a/packages/vgv_ai_cli/lib/src/translate/translators/claude_translator.dart +++ b/packages/vgv_ai_cli/lib/src/translate/translators/claude_translator.dart @@ -14,6 +14,9 @@ import 'package:vgv_ai_cli/src/translate/translate.dart'; /// does, and the two copies would drift apart on the next plugin release. /// {@endtemplate} class const ClaudeTranslator() extends HarnessTranslator { + /// {@macro claude_translator} + this; + @override Harness get harness => Harness.claude; diff --git a/packages/vgv_ai_cli/lib/src/translate/translators/codex_translator.dart b/packages/vgv_ai_cli/lib/src/translate/translators/codex_translator.dart index 32f6528f..8cca22c7 100644 --- a/packages/vgv_ai_cli/lib/src/translate/translators/codex_translator.dart +++ b/packages/vgv_ai_cli/lib/src/translate/translators/codex_translator.dart @@ -12,6 +12,9 @@ import 'package:vgv_ai_cli/src/translate/translate.dart'; /// Codex reads `~/.agents/skills` natively. Its agents are TOML. /// {@endtemplate} class const CodexTranslator() extends HarnessTranslator { + /// {@macro codex_translator} + this; + @override Harness get harness => Harness.codex; diff --git a/packages/vgv_ai_cli/lib/src/translate/translators/copilot_translator.dart b/packages/vgv_ai_cli/lib/src/translate/translators/copilot_translator.dart index 04315508..aa104195 100644 --- a/packages/vgv_ai_cli/lib/src/translate/translators/copilot_translator.dart +++ b/packages/vgv_ai_cli/lib/src/translate/translators/copilot_translator.dart @@ -13,6 +13,9 @@ import 'package:vgv_ai_cli/src/translate/translate.dart'; /// it needs no commands. /// {@endtemplate} class const CopilotTranslator() extends HarnessTranslator { + /// {@macro copilot_translator} + this; + @override Harness get harness => Harness.copilot; diff --git a/packages/vgv_ai_cli/lib/src/translate/translators/gemini_translator.dart b/packages/vgv_ai_cli/lib/src/translate/translators/gemini_translator.dart index 7f3ab911..0e47506d 100644 --- a/packages/vgv_ai_cli/lib/src/translate/translators/gemini_translator.dart +++ b/packages/vgv_ai_cli/lib/src/translate/translators/gemini_translator.dart @@ -14,6 +14,9 @@ import 'package:vgv_ai_cli/src/translate/translate.dart'; /// argument placeholder. /// {@endtemplate} class const GeminiTranslator() extends HarnessTranslator { + /// {@macro gemini_translator} + this; + /// Gemini's argument placeholder. Codex, OpenCode and Pi all keep Claude's /// `$ARGUMENTS`, so this substitution belongs to Gemini alone. static const _arguments = r'$ARGUMENTS'; diff --git a/packages/vgv_ai_cli/lib/src/translate/translators/opencode_translator.dart b/packages/vgv_ai_cli/lib/src/translate/translators/opencode_translator.dart index 0981110f..09638bf2 100644 --- a/packages/vgv_ai_cli/lib/src/translate/translators/opencode_translator.dart +++ b/packages/vgv_ai_cli/lib/src/translate/translators/opencode_translator.dart @@ -11,6 +11,9 @@ import 'package:vgv_ai_cli/src/translate/translate.dart'; /// `mode: subagent` so it is delegated to rather than driven directly. /// {@endtemplate} class const OpenCodeTranslator() extends HarnessTranslator { + /// {@macro opencode_translator} + this; + @override Harness get harness => Harness.opencode; diff --git a/packages/vgv_ai_cli/lib/src/translate/translators/pi_translator.dart b/packages/vgv_ai_cli/lib/src/translate/translators/pi_translator.dart index cc417c24..b9b2bab9 100644 --- a/packages/vgv_ai_cli/lib/src/translate/translators/pi_translator.dart +++ b/packages/vgv_ai_cli/lib/src/translate/translators/pi_translator.dart @@ -11,6 +11,9 @@ import 'package:vgv_ai_cli/src/translate/translate.dart'; /// written, and nothing that would imitate the rest. /// {@endtemplate} class const PiTranslator() extends HarnessTranslator { + /// {@macro pi_translator} + this; + @override Harness get harness => Harness.pi; diff --git a/packages/vgv_ai_cli/lib/src/translate/translators/skills_translator.dart b/packages/vgv_ai_cli/lib/src/translate/translators/skills_translator.dart index 28293071..fc266b68 100644 --- a/packages/vgv_ai_cli/lib/src/translate/translators/skills_translator.dart +++ b/packages/vgv_ai_cli/lib/src/translate/translators/skills_translator.dart @@ -14,6 +14,9 @@ import 'package:vgv_ai_cli/src/translate/translate.dart'; /// harness. /// {@endtemplate} class const SkillsTranslator() { + /// {@macro skills_translator} + this; + /// Plans every skill under [root], plus the files each one ships alongside /// its `SKILL.md`, owned by [harness] or shared when null. TranslationResult translate({ diff --git a/packages/vgv_ai_cli/lib/vgv_ai_cli.dart b/packages/vgv_ai_cli/lib/vgv_ai_cli.dart index 2571304a..be4644ef 100644 --- a/packages/vgv_ai_cli/lib/vgv_ai_cli.dart +++ b/packages/vgv_ai_cli/lib/vgv_ai_cli.dart @@ -1,8 +1,8 @@ /// vgv_ai_cli, A CLI that configures Very Good AI coding agents and tooling /// /// ```sh -/// # activate vgv_ai_cli -/// dart pub global activate vgv_ai_cli +/// # activate vgv_ai_cli from a checkout of this repository +/// dart pub global activate --source=path /// /// # see usage /// vgv_ai --help From af342b0b574c0d65adf7d2c5163942677c68ed9b Mon Sep 17 00:00:00 2001 From: Dominik Simonik Date: Mon, 26 Oct 2026 14:07:31 +0100 Subject: [PATCH 2/2] docs: install from pub.dev in the library doc --- packages/vgv_ai_cli/lib/vgv_ai_cli.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/vgv_ai_cli/lib/vgv_ai_cli.dart b/packages/vgv_ai_cli/lib/vgv_ai_cli.dart index be4644ef..2571304a 100644 --- a/packages/vgv_ai_cli/lib/vgv_ai_cli.dart +++ b/packages/vgv_ai_cli/lib/vgv_ai_cli.dart @@ -1,8 +1,8 @@ /// vgv_ai_cli, A CLI that configures Very Good AI coding agents and tooling /// /// ```sh -/// # activate vgv_ai_cli from a checkout of this repository -/// dart pub global activate --source=path +/// # activate vgv_ai_cli +/// dart pub global activate vgv_ai_cli /// /// # see usage /// vgv_ai --help