sdd-full 4.8.0 → 4.8.1

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 (163) hide show
  1. package/bin.js +1 -1
  2. package/index.js +18 -12
  3. package/package.json +1 -1
  4. package/skills/VERSION.md +61 -175
  5. package/skills/design-planning/ai-coding-rules/SKILL.md +13 -5
  6. package/skills/design-planning/design-to-code/SKILL.md +14 -5
  7. package/skills/design-planning/enterprise-spec/SKILL.md +13 -5
  8. package/skills/design-planning/flutter-av/SKILL.md +16 -5
  9. package/skills/design-planning/flutter-map/SKILL.md +14 -5
  10. package/skills/design-planning/function-sdd/SKILL.md +13 -5
  11. package/skills/design-planning/global-overlay-stack-standard/SKILL.md +14 -4
  12. package/skills/design-planning/ui-motion-interaction-standard/SKILL.md +14 -4
  13. package/skills/design-planning/ui-sdd-specialized/SKILL.md +14 -5
  14. package/skills/development-execution/flutter-errors/SKILL.md +15 -5
  15. package/skills/quality-assurance/bdd-acceptance/SKILL.md +14 -5
  16. package/skills/quality-assurance/flutter-test/SKILL.md +16 -5
  17. package/skills/requirement-analysis/sdd/mock_sdd.md +156 -0
  18. package/skills/rules/project_rules.md +127 -538
  19. package/skills/rules/user_rules.md +263 -0
  20. package/skills/special-tools/env-check/SKILL.md +13 -5
  21. package/skills/special-tools/ios-full-auto-debug/SKILL.md +15 -5
  22. package/skills/flutter-skills/.github/dependabot.yaml +0 -15
  23. package/skills/flutter-skills/.github/workflows/dart_skills_lint_workflow.yaml +0 -68
  24. package/skills/flutter-skills/.github/workflows/skills_tool.yaml +0 -51
  25. package/skills/flutter-skills/CODE_OF_CONDUCT.md +0 -3
  26. package/skills/flutter-skills/CONTRIBUTING.md +0 -36
  27. package/skills/flutter-skills/LICENSE +0 -26
  28. package/skills/flutter-skills/README.md +0 -50
  29. package/skills/flutter-skills/pubspec.yaml +0 -9
  30. package/skills/flutter-skills/resources/flutter_skills.yaml +0 -434
  31. package/skills/flutter-skills/skills/flutter-add-integration-test/SKILL.md +0 -163
  32. package/skills/flutter-skills/skills/flutter-add-widget-preview/SKILL.md +0 -145
  33. package/skills/flutter-skills/skills/flutter-add-widget-test/SKILL.md +0 -154
  34. package/skills/flutter-skills/skills/flutter-apply-architecture-best-practices/SKILL.md +0 -162
  35. package/skills/flutter-skills/skills/flutter-build-responsive-layout/SKILL.md +0 -139
  36. package/skills/flutter-skills/skills/flutter-fix-layout-issues/SKILL.md +0 -130
  37. package/skills/flutter-skills/skills/flutter-implement-json-serialization/SKILL.md +0 -153
  38. package/skills/flutter-skills/skills/flutter-setup-declarative-routing/SKILL.md +0 -255
  39. package/skills/flutter-skills/skills/flutter-setup-localization/SKILL.md +0 -210
  40. package/skills/flutter-skills/skills/flutter-use-http-package/SKILL.md +0 -175
  41. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/add-dart-lint-validation-rule/SKILL.md +0 -196
  42. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-best-practices/SKILL.md +0 -65
  43. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-checks-migration/SKILL.md +0 -158
  44. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-cli-app-best-practices/SKILL.md +0 -168
  45. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-doc-validation/SKILL.md +0 -87
  46. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-long-lines/SKILL.md +0 -101
  47. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-matcher-best-practices/SKILL.md +0 -136
  48. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-modern-features/SKILL.md +0 -266
  49. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-package-maintenance/SKILL.md +0 -92
  50. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-test-coverage/SKILL.md +0 -92
  51. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-test-coverage/example/lib/src/calculator.dart +0 -7
  52. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-test-coverage/example/pubspec.yaml +0 -8
  53. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-test-coverage/example/test/calculator_test.dart +0 -11
  54. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-test-coverage/scripts/interpret_coverage.dart +0 -95
  55. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-test-coverage/scripts/pubspec.yaml +0 -6
  56. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-test-coverage/scripts/test/interpret_coverage_test.dart +0 -93
  57. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-test-fundamentals/SKILL.md +0 -173
  58. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/definition-of-done/SKILL.md +0 -27
  59. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/flutter_skills_ignore.json +0 -3
  60. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/grill-me/SKILL.md +0 -10
  61. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/ignore.json +0 -3
  62. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/test-driven-development/SKILL.md +0 -371
  63. package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/test-driven-development/testing-anti-patterns.md +0 -299
  64. package/skills/flutter-skills/tool/dart_skills_lint/AUTHORS +0 -7
  65. package/skills/flutter-skills/tool/dart_skills_lint/CHANGELOG.md +0 -12
  66. package/skills/flutter-skills/tool/dart_skills_lint/CONTRIBUTING.md +0 -51
  67. package/skills/flutter-skills/tool/dart_skills_lint/LICENSE +0 -27
  68. package/skills/flutter-skills/tool/dart_skills_lint/README.md +0 -203
  69. package/skills/flutter-skills/tool/dart_skills_lint/analysis_options.yaml +0 -296
  70. package/skills/flutter-skills/tool/dart_skills_lint/bench/README.md +0 -23
  71. package/skills/flutter-skills/tool/dart_skills_lint/bench/baseline_throughput.dart +0 -230
  72. package/skills/flutter-skills/tool/dart_skills_lint/bin/cli.dart +0 -10
  73. package/skills/flutter-skills/tool/dart_skills_lint/dart_skills_lint.yaml +0 -14
  74. package/skills/flutter-skills/tool/dart_skills_lint/documentation/feature_design_docs/PRODUCTION_READYNESS.md +0 -48
  75. package/skills/flutter-skills/tool/dart_skills_lint/documentation/feature_design_docs/completion_migration_plan.md +0 -99
  76. package/skills/flutter-skills/tool/dart_skills_lint/documentation/feature_design_docs/legacy_patterns_report.md +0 -110
  77. package/skills/flutter-skills/tool/dart_skills_lint/documentation/feature_design_docs/pub_vs_skill_report.md +0 -56
  78. package/skills/flutter-skills/tool/dart_skills_lint/documentation/knowledge/SPECIFICATION.md +0 -79
  79. package/skills/flutter-skills/tool/dart_skills_lint/documentation/knowledge/architecture_overview.md +0 -64
  80. package/skills/flutter-skills/tool/dart_skills_lint/lib/dart_skills_lint.dart +0 -11
  81. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/config_parser.dart +0 -156
  82. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/entry_point.dart +0 -354
  83. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/fixable_rule.dart +0 -20
  84. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/analysis_severity.dart +0 -15
  85. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/check_type.dart +0 -17
  86. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/ignore_entry.dart +0 -34
  87. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/ignore_entry.g.dart +0 -19
  88. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/skill_context.dart +0 -27
  89. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/skill_rule.dart +0 -27
  90. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/skills_ignores.dart +0 -26
  91. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/skills_ignores.g.dart +0 -24
  92. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/validation_error.dart +0 -31
  93. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rule_registry.dart +0 -79
  94. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rules/absolute_paths_rule.dart +0 -74
  95. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rules/description_length_rule.dart +0 -49
  96. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rules/disallowed_field_rule.dart +0 -61
  97. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rules/name_format_rule.dart +0 -167
  98. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rules/relative_paths_rule.dart +0 -72
  99. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rules/trailing_whitespace_rule.dart +0 -93
  100. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rules/valid_yaml_metadata_rule.dart +0 -74
  101. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/skills_ignores_storage.dart +0 -36
  102. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/validation_session.dart +0 -559
  103. package/skills/flutter-skills/tool/dart_skills_lint/lib/src/validator.dart +0 -238
  104. package/skills/flutter-skills/tool/dart_skills_lint/pubspec.yaml +0 -28
  105. package/skills/flutter-skills/tool/dart_skills_lint/skills/README.md +0 -10
  106. package/skills/flutter-skills/tool/dart_skills_lint/skills/dart-skills-lint-validation/SKILL.md +0 -195
  107. package/skills/flutter-skills/tool/dart_skills_lint/skills-lock.json +0 -75
  108. package/skills/flutter-skills/tool/dart_skills_lint/test/absolute_paths_test.dart +0 -167
  109. package/skills/flutter-skills/tool/dart_skills_lint/test/cli_integration_test.dart +0 -683
  110. package/skills/flutter-skills/tool/dart_skills_lint/test/config_file_test.dart +0 -292
  111. package/skills/flutter-skills/tool/dart_skills_lint/test/custom_rule_test.dart +0 -122
  112. package/skills/flutter-skills/tool/dart_skills_lint/test/directory_structure_test.dart +0 -163
  113. package/skills/flutter-skills/tool/dart_skills_lint/test/field_constraints_test.dart +0 -178
  114. package/skills/flutter-skills/tool/dart_skills_lint/test/fixer_test.dart +0 -172
  115. package/skills/flutter-skills/tool/dart_skills_lint/test/ignore_models_test.dart +0 -63
  116. package/skills/flutter-skills/tool/dart_skills_lint/test/metadata_validation_test.dart +0 -116
  117. package/skills/flutter-skills/tool/dart_skills_lint/test/relative_path_flag_test.dart +0 -70
  118. package/skills/flutter-skills/tool/dart_skills_lint/test/relative_paths_test.dart +0 -172
  119. package/skills/flutter-skills/tool/dart_skills_lint/test/resolve_rules_test.dart +0 -82
  120. package/skills/flutter-skills/tool/dart_skills_lint/test/rule_naming_test.dart +0 -29
  121. package/skills/flutter-skills/tool/dart_skills_lint/test/skills_ignores_storage_test.dart +0 -89
  122. package/skills/flutter-skills/tool/dart_skills_lint/test/test_utils.dart +0 -19
  123. package/skills/flutter-skills/tool/dart_skills_lint/test/trailing_whitespace_test.dart +0 -152
  124. package/skills/flutter-skills/tool/generator/README.md +0 -150
  125. package/skills/flutter-skills/tool/generator/analysis_options.yaml +0 -143
  126. package/skills/flutter-skills/tool/generator/bin/skills.dart +0 -73
  127. package/skills/flutter-skills/tool/generator/lib/src/commands/base_skill_command.dart +0 -87
  128. package/skills/flutter-skills/tool/generator/lib/src/commands/base_yaml_command.dart +0 -83
  129. package/skills/flutter-skills/tool/generator/lib/src/commands/generate_skill_command.dart +0 -92
  130. package/skills/flutter-skills/tool/generator/lib/src/commands/update_readme_command.dart +0 -150
  131. package/skills/flutter-skills/tool/generator/lib/src/commands/update_skill_command.dart +0 -97
  132. package/skills/flutter-skills/tool/generator/lib/src/commands/validate_skill_command.dart +0 -284
  133. package/skills/flutter-skills/tool/generator/lib/src/models/skill_params.dart +0 -41
  134. package/skills/flutter-skills/tool/generator/lib/src/services/gemini_service.dart +0 -310
  135. package/skills/flutter-skills/tool/generator/lib/src/services/markdown_converter.dart +0 -226
  136. package/skills/flutter-skills/tool/generator/lib/src/services/prompts.dart +0 -72
  137. package/skills/flutter-skills/tool/generator/lib/src/services/resource_fetcher_service.dart +0 -84
  138. package/skills/flutter-skills/tool/generator/lib/src/services/skill_instructions.dart +0 -30
  139. package/skills/flutter-skills/tool/generator/pubspec.yaml +0 -32
  140. package/skills/flutter-skills/tool/generator/test/commands/base_skill_command_test.dart +0 -131
  141. package/skills/flutter-skills/tool/generator/test/commands/validate_skills_input_test.dart +0 -263
  142. package/skills/flutter-skills/tool/generator/test/custom_skill_rules/last_modified_rule.dart +0 -32
  143. package/skills/flutter-skills/tool/generator/test/generate_skills_retry_test.dart +0 -105
  144. package/skills/flutter-skills/tool/generator/test/generate_skills_test.dart +0 -519
  145. package/skills/flutter-skills/tool/generator/test/lint_skills_test.dart +0 -34
  146. package/skills/flutter-skills/tool/generator/test/markdown_converter_test.dart +0 -103
  147. package/skills/flutter-skills/tool/generator/test/markdown_table_test.dart +0 -131
  148. package/skills/flutter-skills/tool/generator/test/models/skill_params_test.dart +0 -37
  149. package/skills/flutter-skills/tool/generator/test/services/gemini_service_test.dart +0 -291
  150. package/skills/flutter-skills/tool/generator/test/services/markdown_converter_test.dart +0 -156
  151. package/skills/flutter-skills/tool/generator/test/services/resource_fetcher_service_test.dart +0 -188
  152. package/skills/flutter-skills/tool/generator/test/update_skills_test.dart +0 -241
  153. package/skills/flutter-skills/tool/generator/test/validate_skills_test.dart +0 -728
  154. /package/skills/{.agents → flutter}/skills/flutter-add-integration-test/SKILL.md +0 -0
  155. /package/skills/{.agents → flutter}/skills/flutter-add-widget-preview/SKILL.md +0 -0
  156. /package/skills/{.agents → flutter}/skills/flutter-add-widget-test/SKILL.md +0 -0
  157. /package/skills/{.agents → flutter}/skills/flutter-apply-architecture-best-practices/SKILL.md +0 -0
  158. /package/skills/{.agents → flutter}/skills/flutter-build-responsive-layout/SKILL.md +0 -0
  159. /package/skills/{.agents → flutter}/skills/flutter-fix-layout-issues/SKILL.md +0 -0
  160. /package/skills/{.agents → flutter}/skills/flutter-implement-json-serialization/SKILL.md +0 -0
  161. /package/skills/{.agents → flutter}/skills/flutter-setup-declarative-routing/SKILL.md +0 -0
  162. /package/skills/{.agents → flutter}/skills/flutter-setup-localization/SKILL.md +0 -0
  163. /package/skills/{.agents → flutter}/skills/flutter-use-http-package/SKILL.md +0 -0
@@ -1,30 +0,0 @@
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
- /// Instructions for authoring Skills.
6
- const String skillInstructions = '''
7
- # Role
8
- Act as an Expert Skill Author. Generate high-performance, well-structured Skill modules (SKILL.md) that follow the "Skill authoring best practices" guide.
9
-
10
- # Authoring Guidelines
11
- 1. **Concise & Expert:** Assume the AI is highly competent. Only provide context the AI doesn't already have. Challenge each paragraph: "Does this justify its token cost?". Avoid explaining basic concepts.
12
- 2. **Imperative Mood:** Write all instructions and best practices using the imperative mood (e.g., "Implement the repository..." rather than "The agent should implement...").
13
- 3. **Single File Constraint:** Do not use external file references (e.g., [other.md](other.md)). Include all necessary content within the SKILL.md file. Use <details> tags to collapse lengthy reference material if it exceeds 500 lines.
14
- 4. **Naming:** Use the gerund form (verb + -ing) for the H1 title.
15
- 5. **Workflows & Feedback Loops:** For complex tasks, implement sequential workflows with "Task Progress" checklists that the agent can copy to track progress. Include feedback loops where the agent must "Run validator -> review errors -> fix" for quality-critical operations.
16
- 6. **Conditional Logic:** Use conditional workflows to guide the agent through decision points (e.g., "If creating NEW content..." vs "If EDITING existing content...").
17
- 7. **Examples:** When output quality depends on style or specific formatting, provide clear input/output pairs or high-fidelity implementation examples.
18
- 8. **Consistent Terminology:** Choose one clear term for concepts (e.g., "API endpoint", "Widget state") and use it throughout.
19
- 9. **Single File Constraint:** Do not use external file references (e.g., [other.md](other.md)). Include all necessary content within the SKILL.md file. Use <details> tags to collapse lengthy reference material if it exceeds 500 lines.
20
-
21
- # Formatting Rules
22
- 1. **No YAML**: DO NOT include any YAML frontmatter in your response. Start immediately with the markdown content (e.g., the H1 title).
23
- 2. **Raw Markdown**: DO NOT wrap the entire output in a markdown code block (e.g., ```markdown ... ```). Return raw markdown text.
24
- 3. **Structure**: When generating or updating a skill module, follow this hierarchy:
25
- - **# [Gerund Form Title]**
26
- - **## Contents**: A table of contents linking to all H2 sections.
27
- - **## [Domain/Topic Sections]**: Organized H2 sections covering concepts and core guidelines.
28
- - **## [Workflow Sections]**: Sequential, checklist-based guides for common tasks.
29
- - **## Examples** (If applicable): Concrete examples demonstrating the preferred implementation.
30
- ''';
@@ -1,32 +0,0 @@
1
- name: skills
2
- description: A command-line application for creating and validating Agent Skills.
3
- version: 0.0.1
4
- resolution: workspace
5
-
6
- environment:
7
- sdk: ^3.10.8
8
-
9
- # Add regular dependencies here.
10
- dependencies:
11
- args: ^2.7.0
12
- file: ^7.0.1
13
- glob: ^2.1.3
14
- google_cloud_ai_generativelanguage_v1beta: ^0.5.2
15
- googleapis_auth: ^2.0.0
16
- html: ^0.15.6
17
- http: ^1.6.0
18
- logging: ^1.3.0
19
- meta: ^1.18.1
20
- path: ^1.9.1
21
- platform: ^3.1.6
22
- retry: ^3.1.2
23
- yaml: ^3.1.2
24
-
25
- dev_dependencies:
26
- build_verify: ^3.1.0
27
- coverage: ^1.15.0
28
- dart_skills_lint:
29
- path: ../dart_skills_lint
30
- lints: ^6.0.0
31
- test: ^1.25.6
32
-
@@ -1,131 +0,0 @@
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:convert';
6
- import 'dart:io';
7
-
8
- import 'package:args/command_runner.dart';
9
- import 'package:http/testing.dart';
10
- import 'package:logging/logging.dart';
11
- import 'package:path/path.dart' as p;
12
- import 'package:skills/src/commands/base_skill_command.dart';
13
- import 'package:skills/src/models/skill_params.dart';
14
- import 'package:skills/src/services/gemini_service.dart';
15
- import 'package:test/test.dart';
16
-
17
- class _TestSkillCommand extends BaseSkillCommand {
18
- _TestSkillCommand({required super.httpClient, super.environment})
19
- : super(logger: Logger('_TestSkillCommand'));
20
-
21
- @override
22
- String get name => 'test-command';
23
-
24
- @override
25
- String get description => 'Description';
26
-
27
- @override
28
- Future<void> runSkill(
29
- SkillParams skill,
30
- GeminiService gemini,
31
- Directory outputDir,
32
- int thinkingBudget, {
33
- Directory? configDir,
34
- }) async {}
35
- }
36
-
37
- void main() {
38
- group('BaseSkillCommand Edge Cases', () {
39
- late CommandRunner<void> runner;
40
- late Directory tempDir;
41
- late MockClient mockClient;
42
- final logs = <String>[];
43
-
44
- setUp(() async {
45
- tempDir = await Directory.systemTemp.createTemp(
46
- 'base_skill_commands_test',
47
- );
48
- mockClient = MockClient((request) async => throw UnimplementedError());
49
- runner = CommandRunner<void>('skills', 'Test runner')
50
- ..addCommand(_TestSkillCommand(httpClient: mockClient));
51
-
52
- Logger.root.level = Level.INFO;
53
- Logger.root.onRecord.listen((record) => logs.add(record.message));
54
- logs.clear();
55
- });
56
-
57
- tearDown(() async {
58
- await tempDir.delete(recursive: true);
59
- logs.clear();
60
- });
61
-
62
- test('logs severe error when configuration file not found', () async {
63
- final path = p.join(tempDir.path, 'missing.yaml');
64
- await IOOverrides.runZoned(() async {
65
- await runner.run(['test-command', path]);
66
- }, getCurrentDirectory: () => tempDir);
67
-
68
- expect(logs, contains('Configuration file not found: $path'));
69
- });
70
-
71
- test('logs warning when no skills match the --skill filter', () async {
72
- final configFile = File(p.join(tempDir.path, 'config.yaml'));
73
- await configFile.writeAsString(
74
- jsonEncode(<Map<String, dynamic>>[
75
- {
76
- 'name': 'existent-skill',
77
- 'description': 'desc',
78
- 'resources': <String>[],
79
- },
80
- ]),
81
- );
82
-
83
- await IOOverrides.runZoned(() async {
84
- await runner.run([
85
- 'test-command',
86
- configFile.path,
87
- '--skill',
88
- 'non-existent',
89
- ]);
90
- }, getCurrentDirectory: () => tempDir);
91
-
92
- expect(logs, contains('No skill found with name: non-existent'));
93
- });
94
-
95
- test('logs warning when configuration file contains no skills', () async {
96
- final configFile = File(p.join(tempDir.path, 'empty.yaml'));
97
- await configFile.writeAsString('[]');
98
-
99
- await IOOverrides.runZoned(() async {
100
- await runner.run(['test-command', configFile.path]);
101
- }, getCurrentDirectory: () => tempDir);
102
-
103
- expect(logs, contains('No skills found in configuration file.'));
104
- });
105
-
106
- test('logs severe error when GEMINI_API_KEY is not set', () async {
107
- final configFile = File(p.join(tempDir.path, 'config.yaml'));
108
- await configFile.writeAsString(
109
- jsonEncode(<Map<String, dynamic>>[
110
- {
111
- 'name': 'existent-skill',
112
- 'description': 'desc',
113
- 'resources': <String>[],
114
- },
115
- ]),
116
- );
117
-
118
- // Override environment parameter to simulate missing api key
119
- runner = CommandRunner(
120
- 'skills',
121
- 'Test runner',
122
- )..addCommand(_TestSkillCommand(httpClient: mockClient, environment: {}));
123
-
124
- await IOOverrides.runZoned(() async {
125
- await runner.run(['test-command', configFile.path]);
126
- }, getCurrentDirectory: () => tempDir);
127
-
128
- expect(logs, contains('GEMINI_API_KEY environment variable not set.'));
129
- });
130
- });
131
- }
@@ -1,263 +0,0 @@
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:convert';
6
- import 'dart:io';
7
-
8
- import 'package:args/command_runner.dart';
9
- import 'package:http/http.dart' as http;
10
- import 'package:http/testing.dart';
11
- import 'package:logging/logging.dart';
12
- import 'package:path/path.dart' as p;
13
- import 'package:skills/src/commands/validate_skill_command.dart';
14
- import 'package:test/test.dart';
15
-
16
- void main() {
17
- group('ValidateSkillCommand Input Validation', () {
18
- late CommandRunner<void> runner;
19
- late Directory tempDir;
20
- late MockClient mockClient;
21
- final logs = <String>[];
22
-
23
- setUp(() async {
24
- tempDir = await Directory.systemTemp.createTemp(
25
- 'validate_skills_input_test',
26
- );
27
- mockClient = MockClient((request) async => http.Response('', 200));
28
-
29
- Logger.root.level = Level.INFO;
30
- Logger.root.onRecord.listen((record) {
31
- logs.add(record.message);
32
- });
33
- logs.clear();
34
- });
35
-
36
- tearDown(() async {
37
- await tempDir.delete(recursive: true);
38
- logs.clear();
39
- });
40
-
41
- Future<void> runValidation(String filename, String content) async {
42
- final configFile = File(p.join(tempDir.path, filename));
43
- await configFile.writeAsString(content);
44
-
45
- runner = CommandRunner<void>('skills', 'Test runner')
46
- ..addCommand(
47
- ValidateSkillCommand(
48
- environment: {'GEMINI_API_KEY': 'test-key'},
49
- outputDir: tempDir,
50
- httpClient: mockClient,
51
- ),
52
- );
53
-
54
- await IOOverrides.runZoned(() async {
55
- await runner.run(['validate-skill', configFile.path]);
56
- }, getCurrentDirectory: () => tempDir);
57
- }
58
-
59
- test('passes when configuration is perfectly valid', () async {
60
- final content = jsonEncode([
61
- {
62
- 'name': 'flutter-test-skill',
63
- 'description': 'A Flutter test skill',
64
- 'resources': ['https://example.com/doc'],
65
- },
66
- ]);
67
-
68
- await runValidation('flutter_skills.yaml', content);
69
- expect(logs, isNot(contains('Configuration validation failed.')));
70
- });
71
-
72
- test('fails when root structure is not a list', () async {
73
- final content = jsonEncode({'name': 'flutter-test-skill'});
74
-
75
- await runValidation('flutter_skills.yaml', content);
76
- expect(
77
- logs,
78
- contains('Invalid configuration: Root must be a YAML list.'),
79
- );
80
- });
81
-
82
- test('fails when configuration list is empty', () async {
83
- final content = jsonEncode([]);
84
-
85
- await runValidation('flutter_skills.yaml', content);
86
- expect(logs, contains('Configuration list must not be empty.'));
87
- });
88
-
89
- test('fails when item is not a map', () async {
90
- final content = jsonEncode(['just-a-string-not-a-map']);
91
-
92
- await runValidation('flutter_skills.yaml', content);
93
- expect(logs, contains('Item 0 is not a Map.'));
94
- expect(logs, contains('Configuration validation failed.'));
95
- });
96
-
97
- test('fails when fields are missing', () async {
98
- final content = jsonEncode([
99
- {'name': 'flutter-skill'},
100
- ]);
101
-
102
- await runValidation('flutter_skills.yaml', content);
103
- expect(
104
- logs,
105
- contains(
106
- 'Skill "flutter-skill" is missing required field "description".',
107
- ),
108
- );
109
- expect(
110
- logs,
111
- contains(
112
- 'Skill "flutter-skill" is missing required field "resources".',
113
- ),
114
- );
115
- expect(logs, contains('Configuration validation failed.'));
116
- });
117
-
118
- test('fails when skill name is not kabob-case', () async {
119
- final content = jsonEncode([
120
- {
121
- 'name': 'flutter_skill_invalid',
122
- 'description': 'A Flutter skill description',
123
- 'resources': ['https://example.com'],
124
- },
125
- ]);
126
-
127
- await runValidation('flutter_skills.yaml', content);
128
- expect(
129
- logs,
130
- contains(
131
- 'Skill name "flutter_skill_invalid" must be kabob-case (e.g. abc-def).',
132
- ),
133
- );
134
- expect(logs, contains('Configuration validation failed.'));
135
- });
136
-
137
- test(
138
- 'fails when flutter_skills.yaml name or description conventions are violated',
139
- () async {
140
- final content = jsonEncode([
141
- {
142
- 'name': 'dart-skill',
143
- 'description': 'A skill description with no framework keyword',
144
- 'resources': ['https://example.com'],
145
- },
146
- ]);
147
-
148
- await runValidation('flutter_skills.yaml', content);
149
- expect(
150
- logs,
151
- contains(
152
- 'Skill name "dart-skill" in flutter_skills.yaml must start with "flutter-".',
153
- ),
154
- );
155
- expect(logs, contains('Configuration validation failed.'));
156
- },
157
- );
158
-
159
- test(
160
- 'fails when dart_skills.yaml name or description conventions are violated',
161
- () async {
162
- final content = jsonEncode([
163
- {
164
- 'name': 'flutter-skill',
165
- 'description': 'A skill description with no language keyword',
166
- 'resources': ['https://example.com'],
167
- },
168
- ]);
169
-
170
- await runValidation('dart_skills.yaml', content);
171
- expect(
172
- logs,
173
- contains(
174
- 'Skill name "flutter-skill" in dart_skills.yaml must start with "dart-".',
175
- ),
176
- );
177
- expect(logs, contains('Configuration validation failed.'));
178
- },
179
- );
180
-
181
- test('fails when resources list is empty', () async {
182
- final content = jsonEncode([
183
- {
184
- 'name': 'flutter-skill',
185
- 'description': 'A Flutter skill description',
186
- 'resources': <dynamic>[],
187
- },
188
- ]);
189
-
190
- await runValidation('flutter_skills.yaml', content);
191
- expect(
192
- logs,
193
- contains('Skill "flutter-skill" field "resources" must not be empty.'),
194
- );
195
- expect(logs, contains('Configuration validation failed.'));
196
- });
197
-
198
- test('fails when resource URL uses insecure HTTP protocol', () async {
199
- final content = jsonEncode([
200
- {
201
- 'name': 'flutter-skill',
202
- 'description': 'A Flutter skill description',
203
- 'resources': ['http://example.com/insecure'],
204
- },
205
- ]);
206
-
207
- await runValidation('flutter_skills.yaml', content);
208
- expect(
209
- logs,
210
- contains(
211
- 'Skill "flutter-skill" resource URL "http://example.com/insecure" must use secure HTTPS.',
212
- ),
213
- );
214
- expect(logs, contains('Configuration validation failed.'));
215
- });
216
-
217
- test('fails when fields have invalid types', () async {
218
- final content1 = jsonEncode([
219
- {
220
- 'name': 12345, // int, should be string
221
- 'description': 'A Flutter skill description',
222
- 'resources': ['https://example.com'],
223
- },
224
- ]);
225
-
226
- await runValidation('flutter_skills.yaml', content1);
227
- expect(logs, contains('Item 0 field "name" must be a string.'));
228
-
229
- logs.clear();
230
- final content2 = jsonEncode([
231
- {
232
- 'name': 'flutter-skill',
233
- 'description': true, // bool, should be string
234
- 'resources': ['https://example.com'],
235
- },
236
- ]);
237
-
238
- await runValidation('flutter_skills.yaml', content2);
239
- expect(
240
- logs,
241
- contains('Skill "flutter-skill" field "description" must be a string.'),
242
- );
243
-
244
- logs.clear();
245
- final content3 = jsonEncode([
246
- {
247
- 'name': 'flutter-skill',
248
- 'description': 'A Flutter skill description',
249
- 'resources': ['https://example.com'],
250
- 'instructions': 999, // int, should be string
251
- },
252
- ]);
253
-
254
- await runValidation('flutter_skills.yaml', content3);
255
- expect(
256
- logs,
257
- contains(
258
- 'Skill "flutter-skill" field "instructions" must be a string.',
259
- ),
260
- );
261
- });
262
- });
263
- }
@@ -1,32 +0,0 @@
1
- import 'package:dart_skills_lint/dart_skills_lint.dart';
2
-
3
- class LastModifiedRule extends SkillRule {
4
- static const _metadataKey = 'metadata';
5
- static const _lastModifiedKey = 'last_modified';
6
-
7
- @override
8
- final String name = 'generator:last-modified';
9
-
10
- @override
11
- final AnalysisSeverity severity = AnalysisSeverity.error;
12
-
13
- @override
14
- Future<List<ValidationError>> validate(SkillContext context) async {
15
- final errors = <ValidationError>[];
16
- final yaml = context.parsedYaml;
17
- if (yaml == null) return errors;
18
-
19
- final Object? metadata = yaml[_metadataKey];
20
- if (metadata is! Map || !metadata.containsKey(_lastModifiedKey)) {
21
- errors.add(
22
- ValidationError(
23
- ruleId: name,
24
- severity: severity,
25
- file: 'SKILL.md',
26
- message: 'Missing field: $_metadataKey.$_lastModifiedKey',
27
- ),
28
- );
29
- }
30
- return errors;
31
- }
32
- }
@@ -1,105 +0,0 @@
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:convert';
6
- import 'dart:io';
7
-
8
- import 'package:args/command_runner.dart';
9
- import 'package:http/http.dart' as http;
10
- import 'package:http/testing.dart';
11
- import 'package:logging/logging.dart';
12
- import 'package:path/path.dart' as p;
13
- import 'package:skills/src/commands/generate_skill_command.dart';
14
- import 'package:test/test.dart';
15
-
16
- void main() {
17
- group('GenerateSkillsCommand Retry Logic', () {
18
- late CommandRunner<void> runner;
19
- late Directory tempDir;
20
- late File inputFile;
21
-
22
- setUp(() async {
23
- tempDir = await Directory.systemTemp.createTemp('skills_retry_test');
24
- inputFile = File(p.join(tempDir.path, 'input.yaml'));
25
- runner = CommandRunner<void>('skills', 'Test runner');
26
- });
27
-
28
- tearDown(() async {
29
- await tempDir.delete(recursive: true);
30
- });
31
-
32
- test('retries failed LLM calls up to 3 times', () async {
33
- const url = 'https://example.com/retry';
34
- inputFile.writeAsStringSync(
35
- jsonEncode([
36
- {
37
- 'name': 'retry_skill',
38
- 'description': 'Retry Description',
39
- 'resources': [url],
40
- },
41
- ]),
42
- );
43
-
44
- var attemptCount = 0;
45
- final logs = <String>[];
46
- final sub = Logger.root.onRecord.listen((record) {
47
- logs.add(record.message);
48
- });
49
- addTearDown(sub.cancel);
50
-
51
- final mockClient = MockClient((request) async {
52
- if (request.url.toString() == url) {
53
- return http.Response('<html>Content</html>', 200);
54
- }
55
-
56
- if (request.url.toString().contains('generativelanguage')) {
57
- attemptCount++;
58
- if (attemptCount < 3) {
59
- throw Exception('Simulated Network Error');
60
- }
61
- return http.Response(
62
- jsonEncode({
63
- 'candidates': [
64
- {
65
- 'content': {
66
- 'parts': [
67
- {'text': '---\nname: skill\n---\nContent'},
68
- ],
69
- },
70
- },
71
- ],
72
- }),
73
- 200,
74
- );
75
- }
76
- return http.Response('Not Found', 404);
77
- });
78
-
79
- final command = GenerateSkillCommand(
80
- environment: {'GEMINI_API_KEY': 'test-key'},
81
- httpClient: mockClient,
82
- outputDir: tempDir,
83
- );
84
- runner.addCommand(command);
85
-
86
- await runner.run(['generate-skill', inputFile.path]);
87
-
88
- expect(
89
- attemptCount,
90
- 3,
91
- reason: 'Should attempt 3 times (1 initial + 2 retries)',
92
- );
93
- expect(
94
- logs,
95
- contains(contains('Retrying Gemini generation')),
96
- reason: 'Should log retry warnings',
97
- );
98
- expect(
99
- logs,
100
- contains(contains('Generated')),
101
- reason: 'Should eventually succeed',
102
- );
103
- });
104
- });
105
- }