sdd-full 4.6.1 → 4.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/bin.js +1 -1
  2. package/package.json +1 -1
  3. package/skills/.agents/skills/flutter-add-integration-test/SKILL.md +165 -0
  4. package/skills/.agents/skills/flutter-add-widget-preview/SKILL.md +147 -0
  5. package/skills/.agents/skills/flutter-add-widget-test/SKILL.md +156 -0
  6. package/skills/.agents/skills/flutter-apply-architecture-best-practices/SKILL.md +164 -0
  7. package/skills/.agents/skills/flutter-build-responsive-layout/SKILL.md +141 -0
  8. package/skills/.agents/skills/flutter-fix-layout-issues/SKILL.md +132 -0
  9. package/skills/.agents/skills/flutter-implement-json-serialization/SKILL.md +155 -0
  10. package/skills/.agents/skills/flutter-setup-declarative-routing/SKILL.md +257 -0
  11. package/skills/.agents/skills/flutter-setup-localization/SKILL.md +212 -0
  12. package/skills/.agents/skills/flutter-use-http-package/SKILL.md +177 -0
  13. package/skills/VERSION.md +186 -62
  14. package/skills/design-planning/ai-coding-rules/SKILL.md +5 -13
  15. package/skills/design-planning/design-to-code/SKILL.md +5 -14
  16. package/skills/design-planning/enterprise-spec/SKILL.md +5 -13
  17. package/skills/design-planning/flutter-av/SKILL.md +5 -16
  18. package/skills/design-planning/flutter-map/SKILL.md +5 -14
  19. package/skills/design-planning/function-sdd/SKILL.md +5 -13
  20. package/skills/design-planning/global-overlay-stack-standard/SKILL.md +73 -0
  21. package/skills/design-planning/ui-motion-interaction-standard/SKILL.md +69 -0
  22. package/skills/design-planning/ui-sdd-specialized/SKILL.md +5 -14
  23. package/skills/development-execution/flutter-errors/SKILL.md +5 -15
  24. package/skills/flutter-skills/.github/dependabot.yaml +15 -0
  25. package/skills/flutter-skills/.github/workflows/dart_skills_lint_workflow.yaml +68 -0
  26. package/skills/flutter-skills/.github/workflows/skills_tool.yaml +51 -0
  27. package/skills/flutter-skills/CODE_OF_CONDUCT.md +3 -0
  28. package/skills/flutter-skills/CONTRIBUTING.md +36 -0
  29. package/skills/flutter-skills/LICENSE +26 -0
  30. package/skills/flutter-skills/README.md +50 -0
  31. package/skills/flutter-skills/pubspec.yaml +9 -0
  32. package/skills/flutter-skills/resources/flutter_skills.yaml +434 -0
  33. package/skills/flutter-skills/skills/flutter-add-integration-test/SKILL.md +163 -0
  34. package/skills/flutter-skills/skills/flutter-add-widget-preview/SKILL.md +145 -0
  35. package/skills/flutter-skills/skills/flutter-add-widget-test/SKILL.md +154 -0
  36. package/skills/flutter-skills/skills/flutter-apply-architecture-best-practices/SKILL.md +162 -0
  37. package/skills/flutter-skills/skills/flutter-build-responsive-layout/SKILL.md +139 -0
  38. package/skills/flutter-skills/skills/flutter-fix-layout-issues/SKILL.md +130 -0
  39. package/skills/flutter-skills/skills/flutter-implement-json-serialization/SKILL.md +153 -0
  40. package/skills/flutter-skills/skills/flutter-setup-declarative-routing/SKILL.md +255 -0
  41. package/skills/flutter-skills/skills/flutter-setup-localization/SKILL.md +210 -0
  42. package/skills/flutter-skills/skills/flutter-use-http-package/SKILL.md +175 -0
  43. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/add-dart-lint-validation-rule/SKILL.md +196 -0
  44. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-best-practices/SKILL.md +65 -0
  45. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-checks-migration/SKILL.md +158 -0
  46. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-cli-app-best-practices/SKILL.md +168 -0
  47. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-doc-validation/SKILL.md +87 -0
  48. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-long-lines/SKILL.md +101 -0
  49. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-matcher-best-practices/SKILL.md +136 -0
  50. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-modern-features/SKILL.md +266 -0
  51. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-package-maintenance/SKILL.md +92 -0
  52. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-test-coverage/SKILL.md +92 -0
  53. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-test-coverage/example/lib/src/calculator.dart +7 -0
  54. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-test-coverage/example/pubspec.yaml +8 -0
  55. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-test-coverage/example/test/calculator_test.dart +11 -0
  56. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-test-coverage/scripts/interpret_coverage.dart +95 -0
  57. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-test-coverage/scripts/pubspec.yaml +6 -0
  58. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-test-coverage/scripts/test/interpret_coverage_test.dart +93 -0
  59. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-test-fundamentals/SKILL.md +173 -0
  60. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/definition-of-done/SKILL.md +27 -0
  61. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/flutter_skills_ignore.json +3 -0
  62. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/grill-me/SKILL.md +10 -0
  63. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/ignore.json +3 -0
  64. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/test-driven-development/SKILL.md +371 -0
  65. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/test-driven-development/testing-anti-patterns.md +299 -0
  66. package/skills/flutter-skills/tool/dart_skills_lint/AUTHORS +7 -0
  67. package/skills/flutter-skills/tool/dart_skills_lint/CHANGELOG.md +12 -0
  68. package/skills/flutter-skills/tool/dart_skills_lint/CONTRIBUTING.md +51 -0
  69. package/skills/flutter-skills/tool/dart_skills_lint/LICENSE +27 -0
  70. package/skills/flutter-skills/tool/dart_skills_lint/README.md +203 -0
  71. package/skills/flutter-skills/tool/dart_skills_lint/analysis_options.yaml +296 -0
  72. package/skills/flutter-skills/tool/dart_skills_lint/bench/README.md +23 -0
  73. package/skills/flutter-skills/tool/dart_skills_lint/bench/baseline_throughput.dart +230 -0
  74. package/skills/flutter-skills/tool/dart_skills_lint/bin/cli.dart +10 -0
  75. package/skills/flutter-skills/tool/dart_skills_lint/dart_skills_lint.yaml +14 -0
  76. package/skills/flutter-skills/tool/dart_skills_lint/documentation/feature_design_docs/PRODUCTION_READYNESS.md +48 -0
  77. package/skills/flutter-skills/tool/dart_skills_lint/documentation/feature_design_docs/completion_migration_plan.md +99 -0
  78. package/skills/flutter-skills/tool/dart_skills_lint/documentation/feature_design_docs/legacy_patterns_report.md +110 -0
  79. package/skills/flutter-skills/tool/dart_skills_lint/documentation/feature_design_docs/pub_vs_skill_report.md +56 -0
  80. package/skills/flutter-skills/tool/dart_skills_lint/documentation/knowledge/SPECIFICATION.md +79 -0
  81. package/skills/flutter-skills/tool/dart_skills_lint/documentation/knowledge/architecture_overview.md +64 -0
  82. package/skills/flutter-skills/tool/dart_skills_lint/lib/dart_skills_lint.dart +11 -0
  83. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/config_parser.dart +156 -0
  84. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/entry_point.dart +354 -0
  85. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/fixable_rule.dart +20 -0
  86. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/analysis_severity.dart +15 -0
  87. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/check_type.dart +17 -0
  88. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/ignore_entry.dart +34 -0
  89. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/ignore_entry.g.dart +19 -0
  90. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/skill_context.dart +27 -0
  91. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/skill_rule.dart +27 -0
  92. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/skills_ignores.dart +26 -0
  93. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/skills_ignores.g.dart +24 -0
  94. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/validation_error.dart +31 -0
  95. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rule_registry.dart +79 -0
  96. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rules/absolute_paths_rule.dart +74 -0
  97. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rules/description_length_rule.dart +49 -0
  98. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rules/disallowed_field_rule.dart +61 -0
  99. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rules/name_format_rule.dart +167 -0
  100. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rules/relative_paths_rule.dart +72 -0
  101. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rules/trailing_whitespace_rule.dart +93 -0
  102. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rules/valid_yaml_metadata_rule.dart +74 -0
  103. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/skills_ignores_storage.dart +36 -0
  104. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/validation_session.dart +559 -0
  105. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/validator.dart +238 -0
  106. package/skills/flutter-skills/tool/dart_skills_lint/pubspec.yaml +28 -0
  107. package/skills/flutter-skills/tool/dart_skills_lint/skills/README.md +10 -0
  108. package/skills/flutter-skills/tool/dart_skills_lint/skills/dart-skills-lint-validation/SKILL.md +195 -0
  109. package/skills/flutter-skills/tool/dart_skills_lint/skills-lock.json +75 -0
  110. package/skills/flutter-skills/tool/dart_skills_lint/test/absolute_paths_test.dart +167 -0
  111. package/skills/flutter-skills/tool/dart_skills_lint/test/cli_integration_test.dart +683 -0
  112. package/skills/flutter-skills/tool/dart_skills_lint/test/config_file_test.dart +292 -0
  113. package/skills/flutter-skills/tool/dart_skills_lint/test/custom_rule_test.dart +122 -0
  114. package/skills/flutter-skills/tool/dart_skills_lint/test/directory_structure_test.dart +163 -0
  115. package/skills/flutter-skills/tool/dart_skills_lint/test/field_constraints_test.dart +178 -0
  116. package/skills/flutter-skills/tool/dart_skills_lint/test/fixer_test.dart +172 -0
  117. package/skills/flutter-skills/tool/dart_skills_lint/test/ignore_models_test.dart +63 -0
  118. package/skills/flutter-skills/tool/dart_skills_lint/test/metadata_validation_test.dart +116 -0
  119. package/skills/flutter-skills/tool/dart_skills_lint/test/relative_path_flag_test.dart +70 -0
  120. package/skills/flutter-skills/tool/dart_skills_lint/test/relative_paths_test.dart +172 -0
  121. package/skills/flutter-skills/tool/dart_skills_lint/test/resolve_rules_test.dart +82 -0
  122. package/skills/flutter-skills/tool/dart_skills_lint/test/rule_naming_test.dart +29 -0
  123. package/skills/flutter-skills/tool/dart_skills_lint/test/skills_ignores_storage_test.dart +89 -0
  124. package/skills/flutter-skills/tool/dart_skills_lint/test/test_utils.dart +19 -0
  125. package/skills/flutter-skills/tool/dart_skills_lint/test/trailing_whitespace_test.dart +152 -0
  126. package/skills/flutter-skills/tool/generator/README.md +150 -0
  127. package/skills/flutter-skills/tool/generator/analysis_options.yaml +143 -0
  128. package/skills/flutter-skills/tool/generator/bin/skills.dart +73 -0
  129. package/skills/flutter-skills/tool/generator/lib/src/commands/base_skill_command.dart +87 -0
  130. package/skills/flutter-skills/tool/generator/lib/src/commands/base_yaml_command.dart +83 -0
  131. package/skills/flutter-skills/tool/generator/lib/src/commands/generate_skill_command.dart +92 -0
  132. package/skills/flutter-skills/tool/generator/lib/src/commands/update_readme_command.dart +150 -0
  133. package/skills/flutter-skills/tool/generator/lib/src/commands/update_skill_command.dart +97 -0
  134. package/skills/flutter-skills/tool/generator/lib/src/commands/validate_skill_command.dart +284 -0
  135. package/skills/flutter-skills/tool/generator/lib/src/models/skill_params.dart +41 -0
  136. package/skills/flutter-skills/tool/generator/lib/src/services/gemini_service.dart +310 -0
  137. package/skills/flutter-skills/tool/generator/lib/src/services/markdown_converter.dart +226 -0
  138. package/skills/flutter-skills/tool/generator/lib/src/services/prompts.dart +72 -0
  139. package/skills/flutter-skills/tool/generator/lib/src/services/resource_fetcher_service.dart +84 -0
  140. package/skills/flutter-skills/tool/generator/lib/src/services/skill_instructions.dart +30 -0
  141. package/skills/flutter-skills/tool/generator/pubspec.yaml +32 -0
  142. package/skills/flutter-skills/tool/generator/test/commands/base_skill_command_test.dart +131 -0
  143. package/skills/flutter-skills/tool/generator/test/commands/validate_skills_input_test.dart +263 -0
  144. package/skills/flutter-skills/tool/generator/test/custom_skill_rules/last_modified_rule.dart +32 -0
  145. package/skills/flutter-skills/tool/generator/test/generate_skills_retry_test.dart +105 -0
  146. package/skills/flutter-skills/tool/generator/test/generate_skills_test.dart +519 -0
  147. package/skills/flutter-skills/tool/generator/test/lint_skills_test.dart +34 -0
  148. package/skills/flutter-skills/tool/generator/test/markdown_converter_test.dart +103 -0
  149. package/skills/flutter-skills/tool/generator/test/markdown_table_test.dart +131 -0
  150. package/skills/flutter-skills/tool/generator/test/models/skill_params_test.dart +37 -0
  151. package/skills/flutter-skills/tool/generator/test/services/gemini_service_test.dart +291 -0
  152. package/skills/flutter-skills/tool/generator/test/services/markdown_converter_test.dart +156 -0
  153. package/skills/flutter-skills/tool/generator/test/services/resource_fetcher_service_test.dart +188 -0
  154. package/skills/flutter-skills/tool/generator/test/update_skills_test.dart +241 -0
  155. package/skills/flutter-skills/tool/generator/test/validate_skills_test.dart +728 -0
  156. package/skills/quality-assurance/bdd-acceptance/SKILL.md +5 -14
  157. package/skills/quality-assurance/flutter-test/SKILL.md +5 -16
  158. package/skills/rules/project_rules.md +538 -127
  159. package/skills/special-tools/env-check/SKILL.md +5 -13
  160. package/skills/special-tools/ios-full-auto-debug/SKILL.md +5 -15
  161. package/skills/writing-skills/SKILL.md +654 -0
  162. package/skills/writing-skills/anthropic-best-practices.md +1149 -0
  163. package/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
  164. package/skills/writing-skills/graphviz-conventions.dot +172 -0
  165. package/skills/writing-skills/persuasion-principles.md +187 -0
  166. package/skills/writing-skills/render-graphs.js +168 -0
  167. package/skills/writing-skills/testing-skills-with-subagents.md +384 -0
  168. package/skills/checklist.md +0 -154
  169. package/skills/rules/user_rules.md +0 -263
  170. package/skills//345/256/214/346/225/264/345/274/200/345/217/221/346/265/201/347/250/213/346/211/213/345/206/214.md +0 -454
  171. package/skills//346/212/200/350/203/275/344/275/223/347/263/273/345/256/214/345/226/204/345/273/272/350/256/256.md +0 -308
  172. package/skills//346/212/200/350/203/275/344/275/277/347/224/250/346/214/207/345/215/227.md +0 -309
  173. package/skills//346/212/200/350/203/275/345/206/263/347/255/226/346/240/221.md +0 -338
@@ -0,0 +1,238 @@
1
+ // Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
2
+ // for details. All rights reserved. Use of this source code is governed by a
3
+ // BSD-style license that can be found in the LICENSE file.
4
+
5
+ import 'dart:io';
6
+
7
+ import 'package:logging/logging.dart';
8
+ import 'package:path/path.dart' as p;
9
+ import 'package:yaml/yaml.dart';
10
+
11
+ import 'models/analysis_severity.dart';
12
+ import 'models/check_type.dart';
13
+ import 'models/skill_context.dart';
14
+ import 'models/skill_rule.dart';
15
+ import 'models/validation_error.dart';
16
+ import 'rule_registry.dart';
17
+
18
+ const _dirStructureUrl = 'https://agentskills.io/specification#directory-structure';
19
+
20
+ final _log = Logger('dart_skills_lint');
21
+
22
+ /// Validates agent skill directories against the Agent Skills specification.
23
+ class Validator {
24
+ Validator({Map<String, AnalysisSeverity>? ruleOverrides, List<SkillRule>? customRules})
25
+ : _customSeverities = ruleOverrides ?? {},
26
+ _rules = _buildRules(ruleOverrides ?? {}, customRules ?? []);
27
+ static const String _skillFileName = SkillContext.skillFileName;
28
+
29
+ /// The name of the special check for missing files or directories.
30
+ static const String pathDoesNotExist = 'path-does-not-exist';
31
+
32
+ /// The name of the special check for inaccessible files.
33
+ static const String skillFileInaccessible = 'skill-file-inaccessible';
34
+
35
+ /// The name of the special check for unexpected errors.
36
+ static const String unexpectedError = 'unexpected-error';
37
+
38
+ final Map<String, AnalysisSeverity> _customSeverities;
39
+ final List<SkillRule> _rules;
40
+
41
+ /// Returns the rules used by this validator.
42
+ List<SkillRule> get rules => _rules;
43
+
44
+ AnalysisSeverity _getSeverity(String name, AnalysisSeverity defaultSeverity) {
45
+ return _customSeverities[name] ?? defaultSeverity;
46
+ }
47
+
48
+ /// Validates a single skill directory.
49
+ ///
50
+ /// Scans the directory for `SKILL.md`, parses its YAML metadata, and validates
51
+ /// constraints like name format and field lengths using registered rules.
52
+ Future<ValidationResult> validate(Directory dir) async {
53
+ final validationErrors = <ValidationError>[];
54
+
55
+ final bool isValidDir = await _checkDirectoryStructure(dir, validationErrors);
56
+ if (!isValidDir) {
57
+ return ValidationResult(validationErrors: validationErrors);
58
+ }
59
+
60
+ final skillMdFile = File(p.join(dir.path, _skillFileName));
61
+ String content;
62
+ try {
63
+ content = await skillMdFile.readAsString();
64
+ } on FileSystemException catch (e) {
65
+ validationErrors.add(
66
+ ValidationError(
67
+ ruleId: skillFileInaccessible,
68
+ file: skillMdFile.path,
69
+ message: 'Failed to read $_skillFileName: $e',
70
+ severity: _getSeverity(skillFileInaccessible, AnalysisSeverity.error),
71
+ ),
72
+ );
73
+ return ValidationResult(validationErrors: validationErrors);
74
+ } catch (e) {
75
+ validationErrors.add(
76
+ ValidationError(
77
+ ruleId: unexpectedError,
78
+ file: skillMdFile.path,
79
+ message: 'Unexpected error reading $_skillFileName: $e',
80
+ severity: _getSeverity(unexpectedError, AnalysisSeverity.error),
81
+ ),
82
+ );
83
+ return ValidationResult(validationErrors: validationErrors);
84
+ }
85
+
86
+ YamlMap? parsedYaml;
87
+ String? yamlParsingError;
88
+ try {
89
+ final RegExpMatch? match = SkillContext.skillStartRegex.firstMatch(content);
90
+ if (match != null) {
91
+ final String yamlStr = match.group(1)!;
92
+ final Object? doc = loadYaml(yamlStr);
93
+ if (doc is YamlMap) {
94
+ parsedYaml = doc;
95
+ } else {
96
+ yamlParsingError = 'YAML frontmatter is not a map';
97
+ }
98
+ } else {
99
+ yamlParsingError = 'Missing YAML metadata in $_skillFileName';
100
+ }
101
+ } catch (e) {
102
+ yamlParsingError = 'Failed to parse YAML: $e';
103
+ }
104
+
105
+ final context = SkillContext(
106
+ directory: dir,
107
+ rawContent: content,
108
+ parsedYaml: parsedYaml,
109
+ yamlParsingError: yamlParsingError,
110
+ );
111
+
112
+ for (final SkillRule rule in _rules) {
113
+ final List<ValidationError> errors = await rule.validate(context);
114
+ for (final error in errors) {
115
+ if (error.severity != rule.severity) {
116
+ _log.warning(
117
+ 'Rule "${rule.name}" used severity ${error.severity} instead of defined ${rule.severity}.',
118
+ );
119
+ }
120
+ }
121
+ validationErrors.addAll(errors);
122
+ }
123
+
124
+ return ValidationResult(validationErrors: validationErrors, context: context);
125
+ }
126
+
127
+ static List<SkillRule> _buildRules(
128
+ Map<String, AnalysisSeverity> customSeverities,
129
+ List<SkillRule> customRules,
130
+ ) {
131
+ final rules = <SkillRule>[];
132
+ final seenNames = <String>{};
133
+
134
+ void addRule(SkillRule rule) {
135
+ if (rule.severity != AnalysisSeverity.disabled) {
136
+ if (seenNames.contains(rule.name)) {
137
+ throw ArgumentError('Duplicate rule name detected: ${rule.name}');
138
+ }
139
+ seenNames.add(rule.name);
140
+ rules.add(rule);
141
+ }
142
+ }
143
+
144
+ for (final CheckType check in RuleRegistry.allChecks) {
145
+ final AnalysisSeverity severity = customSeverities[check.name] ?? check.defaultSeverity;
146
+ final SkillRule? rule = RuleRegistry.createRule(check.name, severity);
147
+ if (rule != null) {
148
+ addRule(rule);
149
+ }
150
+ }
151
+
152
+ customRules.forEach(addRule);
153
+
154
+ return rules;
155
+ }
156
+
157
+ Future<bool> _checkDirectoryStructure(
158
+ Directory dir,
159
+ List<ValidationError> validationErrors,
160
+ ) async {
161
+ final AnalysisSeverity pathDoesNotExistSeverity = _getSeverity(
162
+ pathDoesNotExist,
163
+ AnalysisSeverity.error,
164
+ );
165
+
166
+ if (!dir.existsSync()) {
167
+ if (File(dir.path).existsSync()) {
168
+ validationErrors.add(
169
+ ValidationError(
170
+ ruleId: pathDoesNotExist,
171
+ file: dir.path,
172
+ message: 'Path is not a directory: ${dir.path} (see $_dirStructureUrl)',
173
+ severity: pathDoesNotExistSeverity,
174
+ ),
175
+ );
176
+ } else {
177
+ validationErrors.add(
178
+ ValidationError(
179
+ ruleId: pathDoesNotExist,
180
+ file: dir.path,
181
+ message: 'Directory does not exist: ${dir.path} (see $_dirStructureUrl)',
182
+ severity: pathDoesNotExistSeverity,
183
+ ),
184
+ );
185
+ }
186
+ return false;
187
+ }
188
+
189
+ final skillMdFile = File(p.join(dir.path, _skillFileName));
190
+ if (!skillMdFile.existsSync()) {
191
+ validationErrors.add(
192
+ ValidationError(
193
+ ruleId: pathDoesNotExist,
194
+ file: dir.path,
195
+ message: '$_skillFileName is missing in directory: ${dir.path} (see $_dirStructureUrl)',
196
+ severity: pathDoesNotExistSeverity,
197
+ ),
198
+ );
199
+ return false;
200
+ }
201
+ return true;
202
+ }
203
+ }
204
+
205
+ /// The result of a skill directory validation attempt.
206
+ class ValidationResult {
207
+ ValidationResult({
208
+ this.validationErrors = const [],
209
+ List<String> warnings = const [],
210
+ this.context,
211
+ }) : _manualWarnings = warnings;
212
+
213
+ /// The context used during validation.
214
+ final SkillContext? context;
215
+
216
+ /// Whether the skill directory is valid according to the specification.
217
+ bool get isValid =>
218
+ !validationErrors.any((e) => e.severity == AnalysisSeverity.error && !e.isIgnored);
219
+
220
+ /// A list of structured validation errors found.
221
+ final List<ValidationError> validationErrors;
222
+
223
+ final List<String> _manualWarnings;
224
+
225
+ /// A list of error messages for failing checks (excluding ignored ones).
226
+ List<String> get errors => validationErrors
227
+ .where((e) => e.severity == AnalysisSeverity.error && !e.isIgnored)
228
+ .map((e) => e.message)
229
+ .toList();
230
+
231
+ /// A list of warning messages for suboptimal setups or recommendations.
232
+ List<String> get warnings => [
233
+ ..._manualWarnings,
234
+ ...validationErrors
235
+ .where((e) => e.severity == AnalysisSeverity.warning && !e.isIgnored)
236
+ .map((e) => e.message),
237
+ ];
238
+ }
@@ -0,0 +1,28 @@
1
+ name: dart_skills_lint
2
+ description: A static analysis linter for agent skills.
3
+ version: 0.2.0
4
+ resolution: workspace
5
+ repository: https://github.com/flutter/skills
6
+
7
+ environment:
8
+ sdk: ^3.10.8
9
+
10
+ dependencies:
11
+ args: ^2.4.0
12
+ io: ^1.0.4
13
+ logging: ^1.2.0
14
+ meta: ^1.11.0
15
+ path: ^1.9.1
16
+ yaml: ^3.1.3
17
+ json_annotation: ^4.8.0
18
+
19
+ dev_dependencies:
20
+ lints: ^6.0.0
21
+ test: ^1.24.0
22
+ test_process: ^2.1.1
23
+ json_serializable: ^6.7.0
24
+ build_runner: ^2.4.0
25
+ dart_code_linter: ^4.0.3
26
+
27
+ executables:
28
+ dart_skills_lint: cli
@@ -0,0 +1,10 @@
1
+ # Skills shipped with dart_skills_lint
2
+
3
+ The skills in this directory are shipped with the `dart_skills_lint` package.
4
+ They are intended for users of the package to help them use it effectively.
5
+
6
+ To install these skills into your IDE, you can use the [skills](https://pub.dev/packages/skills) package on pub:
7
+ ```bash
8
+ dart pub global activate skills
9
+ skills get
10
+ ```
@@ -0,0 +1,195 @@
1
+ ---
2
+ name: dart-skills-lint-validation
3
+ description: |-
4
+ Use this skill when you need to validate that AI agent skills meet the specification.
5
+ This includes generic validation of any skills for users that have Dart installed,
6
+ as well as integrating dart_skills_lint into a Dart project as a dev_dependency
7
+ to automate skill validation in tests or CI/CD.
8
+ ---
9
+
10
+ # Validating Skills with dart_skills_lint
11
+
12
+ ## Contents
13
+ - [Usage for Agents (CLI)](#usage-for-agents-cli)
14
+ - [Setup for Dart Developers](#setup-for-dart-developers)
15
+ - [Authoring Custom Rules](#authoring-custom-rules)
16
+ - [Workflow: Validating Skills](#workflow-validating-skills)
17
+ - [Specification Reference](#specification-reference)
18
+
19
+ ## Usage for Agents (CLI)
20
+ Use the `dart_skills_lint` CLI to validate skills. Choose the appropriate workflow based on your environment:
21
+
22
+ ### Scenario A: The package is in your project dependencies
23
+ Use this method if you are working within a project that has `dart_skills_lint` listed in `pubspec.yaml`.
24
+ Run:
25
+ ```bash
26
+ dart run dart_skills_lint -d .agents/skills
27
+ ```
28
+
29
+ ### Scenario B: The package is activated globally
30
+ Use this method if you want to validate skills across multiple projects without adding a dependency to each one.
31
+ Run:
32
+ ```bash
33
+ dart pub global run dart_skills_lint -d .agents/skills
34
+ ```
35
+
36
+ ### Common Flags
37
+ - `-d`, `--skills-directory`: Specifies a root directory containing sub-folders of skills to validate. Can be passed multiple times.
38
+ - `-s`, `--skill`: Specifies an individual skill directory to validate directly. Can be passed multiple times.
39
+ - `-q`, `--quiet`: Hide non-error validation output.
40
+ - `-w`, `--print-warnings`: Enable printing of warning messages.
41
+ - `--fast-fail`: Halt execution immediately on the error.
42
+ - `--ignore-config`: Ignore the YAML configuration file entirely.
43
+
44
+ ## Setup for Dart Developers
45
+ Setup validation in your Dart project:
46
+
47
+ 1. Add `dart_skills_lint` to your `pubspec.yaml` as a `dev_dependency`:
48
+ ```yaml
49
+ dev_dependencies:
50
+ dart_skills_lint: ^0.2.0
51
+ ```
52
+
53
+ 2. Integrate the linter into your automated tests by importing the package and calling `validateSkills`. This ensures your skills are automatically validated whenever you run `dart test`.
54
+
55
+ Example `test/lint_skills_test.dart`:
56
+ ```dart
57
+ import 'dart:async';
58
+ import 'package:dart_skills_lint/dart_skills_lint.dart';
59
+ import 'package:logging/logging.dart';
60
+ import 'package:test/test.dart';
61
+
62
+ void main() {
63
+ test('Run skills linter', () async {
64
+ // Enable logging to see detailed validation errors in test output.
65
+ final Level oldLevel = Logger.root.level;
66
+ Logger.root.level = Level.ALL;
67
+ final StreamSubscription<LogRecord> subscription =
68
+ Logger.root.onRecord.listen((record) => print(record.message));
69
+
70
+ try {
71
+ final isValid = await validateSkills(
72
+ skillDirPaths: ['.agents/skills'],
73
+ resolvedRules: {
74
+ 'check-relative-paths': AnalysisSeverity.error,
75
+ 'check-absolute-paths': AnalysisSeverity.error,
76
+ 'check-trailing-whitespace': AnalysisSeverity.error,
77
+ },
78
+ );
79
+ expect(isValid, isTrue, reason: 'Skills validation failed. See above for details.');
80
+ } finally {
81
+ Logger.root.level = oldLevel;
82
+ await subscription.cancel();
83
+ }
84
+ });
85
+ }
86
+ ```
87
+
88
+ 3. (Optional) Create a configuration file `dart_skills_lint.yaml` in the root of your project to customize rules and directories for the CLI:
89
+ **Note:** If you use `validateSkills` directly in tests, the `dart_skills_lint.yaml` file is ignored by default, and you should pass configuration programmatically if needed.
90
+ ```yaml
91
+ dart_skills_lint:
92
+ rules:
93
+ check-relative-paths: error
94
+ check-absolute-paths: error
95
+ directories:
96
+ - path: ".agents/skills"
97
+ ```
98
+
99
+ ## Initial Integration in a Repository
100
+
101
+ When adding `dart_skills_lint` to a repository for the first time, follow these best practices based on real-world integration:
102
+
103
+ ### 1. Workspace Dependency Management
104
+ If your repository is a workspace with multiple packages:
105
+ - **Isolate the dependency**: Add `dart_skills_lint` to the specific package that handles tooling or tests (e.g., `tool/pubspec.yaml`) rather than the root `pubspec.yaml`, unless it is strictly needed at the root level.
106
+ - **Keep hashes in sync**: If you must add it to multiple `pubspec.yaml` files (e.g., root and a tool package), ensure the `ref` (commit hash) is identical to avoid resolution conflicts.
107
+
108
+ ### 2. Configuration File Location
109
+ - Place `dart_skills_lint.yaml` in the directory from which you plan to run the command (e.g., inside `tool/` if that's where your setup lives).
110
+ - **Update relative paths**: Ensure the `path` entries in the config file are relative to that directory (e.g., `../.agents/skills` if running from `tool/` to target a folder in the repository root).
111
+
112
+ ### 3. Generating a Baseline
113
+ If you are integrating the linter into a repository with existing skills that may have legacy errors or false positives:
114
+ - Use the baseline feature to ignore existing issues and start with a clean run.
115
+ - Run:
116
+ ```bash
117
+ dart run dart_skills_lint:cli --skills-directory=.agents/skills --generate-baseline
118
+ ```
119
+ - This will create a `dart_skills_lint_ignore.json` file.
120
+ - **Note on False Positives**: The linter currently evaluates links inside markdown code blocks. If your skill documentation includes examples with placeholder links or images, they might be flagged as broken. Use the baseline file to ignore these specific false positives.
121
+
122
+ ## Authoring Custom Rules
123
+ To author custom rules, extend the `SkillRule` class and pass them to `validateSkills`.
124
+
125
+ Example:
126
+ ```dart
127
+ import 'package:dart_skills_lint/dart_skills_lint.dart';
128
+
129
+ class MyCustomRule extends SkillRule {
130
+ @override
131
+ final String name = 'my-custom-rule';
132
+
133
+ @override
134
+ final AnalysisSeverity severity = AnalysisSeverity.warning;
135
+
136
+ @override
137
+ Future<List<ValidationError>> validate(SkillContext context) async {
138
+ final errors = <ValidationError>[];
139
+ final yaml = context.parsedYaml;
140
+ if (yaml == null) return errors;
141
+
142
+ if (yaml['metadata']?['deprecated'] == true) {
143
+ errors.add(ValidationError(
144
+ ruleId: name,
145
+ severity: severity,
146
+ file: 'SKILL.md',
147
+ message: 'This skill is marked as deprecated.',
148
+ ));
149
+ }
150
+ return errors;
151
+ }
152
+ }
153
+ ```
154
+
155
+ Use it in your test:
156
+ ```dart
157
+ await validateSkills(
158
+ skillDirPaths: ['.agents/skills'],
159
+ customRules: [MyCustomRule()],
160
+ );
161
+ ```
162
+
163
+ ## Workflow: Validating Skills
164
+ Follow this workflow to validate skills:
165
+
166
+ 1. **Run the validator**: Execute the linter on your skills directory.
167
+ ```bash
168
+ dart run dart_skills_lint -d .agents/skills
169
+ ```
170
+ 2. **Review errors**: Check the output for any errors or warnings.
171
+ 3. **Fix violations**: Edit the `SKILL.md` or directory structure to resolve issues.
172
+ 4. **Verify**: Re-run the validator to ensure all checks pass.
173
+
174
+ ### Task Progress
175
+ - [ ] Run validator
176
+ - [ ] Review errors
177
+ - [ ] Fix violations
178
+ - [ ] Verify clean run
179
+
180
+ ## Specification Reference
181
+ <details>
182
+ <summary>View Skill Specification Constraints</summary>
183
+
184
+ ### Directory and File Structure
185
+ - Mandatory `SKILL.md` file at the root of the skill folder.
186
+ - Directories starting with a dot `.` (e.g., `.dart_tool`) are ignored.
187
+
188
+ ### Metadata (YAML Frontmatter)
189
+ - Required fields: `name` and `description`.
190
+
191
+ ### Field Constraints
192
+ - **Name**: Max 64 characters, lowercase alphanumeric and hyphens only. Must match the parent directory name.
193
+ - **Description**: Max 1024 characters.
194
+ - **Compatibility**: Max 500 characters.
195
+ </details>
@@ -0,0 +1,75 @@
1
+ {
2
+ "version": 1,
3
+ "skills": {
4
+ "dart-best-practices": {
5
+ "source": "kevmoo/dash_skills",
6
+ "sourceType": "github",
7
+ "skillPath": ".agent/skills/dart-best-practices/SKILL.md",
8
+ "computedHash": "1f529bd357368f67621de2c25531f69e16f726ecbe0071aabbf47b6d7b2a16c4"
9
+ },
10
+ "dart-checks-migration": {
11
+ "source": "kevmoo/dash_skills",
12
+ "sourceType": "github",
13
+ "skillPath": ".agent/skills/dart-checks-migration/SKILL.md",
14
+ "computedHash": "15592bf08008e2a37da5d1f4dc6b99dae01ce0db1ec7127f97cdfac3d6bcfb5d"
15
+ },
16
+ "dart-cli-app-best-practices": {
17
+ "source": "kevmoo/dash_skills",
18
+ "sourceType": "github",
19
+ "skillPath": ".agent/skills/dart-cli-app-best-practices/SKILL.md",
20
+ "computedHash": "83487d2341e4b692d180fe6c9fc402706a5707aba227424db016182006cfdf30"
21
+ },
22
+ "dart-doc-validation": {
23
+ "source": "kevmoo/dash_skills",
24
+ "sourceType": "github",
25
+ "skillPath": ".agent/skills/dart-doc-validation/SKILL.md",
26
+ "computedHash": "acc150afe3406de17059f9215fa009ffeb1b7c0815f903c2af303380e90055c4"
27
+ },
28
+ "dart-long-lines": {
29
+ "source": "kevmoo/dash_skills",
30
+ "sourceType": "github",
31
+ "skillPath": ".agent/skills/dart-long-lines/SKILL.md",
32
+ "computedHash": "db6543389e683823446c7ee27fb162f219cc47f209809b9fd79b012bdb944991"
33
+ },
34
+ "dart-matcher-best-practices": {
35
+ "source": "kevmoo/dash_skills",
36
+ "sourceType": "github",
37
+ "skillPath": ".agent/skills/dart-matcher-best-practices/SKILL.md",
38
+ "computedHash": "99a200dca8676e865b97a81abe40e8f9e2b9afdbd0f82845c1e3c8dd7eae007b"
39
+ },
40
+ "dart-modern-features": {
41
+ "source": "kevmoo/dash_skills",
42
+ "sourceType": "github",
43
+ "skillPath": ".agent/skills/dart-modern-features/SKILL.md",
44
+ "computedHash": "3148ee2c96c296593d3cd704d4bd99af25c84237a40c07acad5696328555907a"
45
+ },
46
+ "dart-package-maintenance": {
47
+ "source": "kevmoo/dash_skills",
48
+ "sourceType": "github",
49
+ "skillPath": ".agent/skills/dart-package-maintenance/SKILL.md",
50
+ "computedHash": "92efdb1b873eec4e0bcb61ade541b954eee347c3ddd70c27ba22c982c318d7e6"
51
+ },
52
+ "dart-test-coverage": {
53
+ "source": "kevmoo/dash_skills",
54
+ "sourceType": "github",
55
+ "skillPath": ".agent/skills/dart-test-coverage/SKILL.md",
56
+ "computedHash": "b52e0f0203181a5b6eeb5ea202f7509ab8380c53448411b84e1f84696436dfdb"
57
+ },
58
+ "dart-test-fundamentals": {
59
+ "source": "kevmoo/dash_skills",
60
+ "sourceType": "github",
61
+ "skillPath": ".agent/skills/dart-test-fundamentals/SKILL.md",
62
+ "computedHash": "0d6e877c3575136909afa4f9daa82ed48c713a3052f8e211b2476043b0438bf7"
63
+ },
64
+ "grill-me": {
65
+ "source": "mattpocock/skills",
66
+ "sourceType": "github",
67
+ "computedHash": "784f0dbb7403b0f00324bce9a112f715342777a0daee7bbb7385f9c6f0a170ea"
68
+ },
69
+ "test-driven-development": {
70
+ "source": "obra/superpowers",
71
+ "sourceType": "github",
72
+ "computedHash": "126f1ebf6ccd414f42544f6e83d8cc5adb089e1108eaffb7c400701e37eecd9f"
73
+ }
74
+ }
75
+ }