sdd-full 4.8.0 → 4.8.2
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.
- package/bin.js +2 -2
- package/index.js +18 -12
- package/package.json +1 -1
- package/skills/README.md +155 -47
- package/skills/design-planning/ai-coding-rules/SKILL.md +13 -5
- package/skills/design-planning/design-to-code/SKILL.md +14 -5
- package/skills/design-planning/enterprise-spec/SKILL.md +13 -5
- package/skills/design-planning/flutter-av/SKILL.md +16 -5
- package/skills/design-planning/flutter-map/SKILL.md +14 -5
- package/skills/design-planning/function-sdd/SKILL.md +13 -5
- package/skills/design-planning/global-overlay-stack-standard/SKILL.md +14 -4
- package/skills/design-planning/ui-motion-interaction-standard/SKILL.md +14 -4
- package/skills/design-planning/ui-sdd-specialized/SKILL.md +14 -5
- package/skills/development-execution/flutter-errors/SKILL.md +15 -5
- package/skills/quality-assurance/bdd-acceptance/SKILL.md +14 -5
- package/skills/quality-assurance/flutter-test/SKILL.md +16 -5
- package/skills/requirement-analysis/sdd/mock_sdd.md +156 -0
- package/skills/rules/project_rules.md +127 -538
- package/skills/rules/user_rules.md +263 -0
- package/skills/special-tools/env-check/SKILL.md +13 -5
- package/skills/special-tools/ios-full-auto-debug/SKILL.md +15 -5
- package/skills/VERSION.md +0 -310
- package/skills/flutter-skills/.github/dependabot.yaml +0 -15
- package/skills/flutter-skills/.github/workflows/dart_skills_lint_workflow.yaml +0 -68
- package/skills/flutter-skills/.github/workflows/skills_tool.yaml +0 -51
- package/skills/flutter-skills/CODE_OF_CONDUCT.md +0 -3
- package/skills/flutter-skills/CONTRIBUTING.md +0 -36
- package/skills/flutter-skills/LICENSE +0 -26
- package/skills/flutter-skills/README.md +0 -50
- package/skills/flutter-skills/pubspec.yaml +0 -9
- package/skills/flutter-skills/resources/flutter_skills.yaml +0 -434
- package/skills/flutter-skills/skills/flutter-add-integration-test/SKILL.md +0 -163
- package/skills/flutter-skills/skills/flutter-add-widget-preview/SKILL.md +0 -145
- package/skills/flutter-skills/skills/flutter-add-widget-test/SKILL.md +0 -154
- package/skills/flutter-skills/skills/flutter-apply-architecture-best-practices/SKILL.md +0 -162
- package/skills/flutter-skills/skills/flutter-build-responsive-layout/SKILL.md +0 -139
- package/skills/flutter-skills/skills/flutter-fix-layout-issues/SKILL.md +0 -130
- package/skills/flutter-skills/skills/flutter-implement-json-serialization/SKILL.md +0 -153
- package/skills/flutter-skills/skills/flutter-setup-declarative-routing/SKILL.md +0 -255
- package/skills/flutter-skills/skills/flutter-setup-localization/SKILL.md +0 -210
- package/skills/flutter-skills/skills/flutter-use-http-package/SKILL.md +0 -175
- package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/add-dart-lint-validation-rule/SKILL.md +0 -196
- package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-best-practices/SKILL.md +0 -65
- package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-checks-migration/SKILL.md +0 -158
- package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-cli-app-best-practices/SKILL.md +0 -168
- package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-doc-validation/SKILL.md +0 -87
- package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-long-lines/SKILL.md +0 -101
- package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-matcher-best-practices/SKILL.md +0 -136
- package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-modern-features/SKILL.md +0 -266
- package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-package-maintenance/SKILL.md +0 -92
- package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-test-coverage/SKILL.md +0 -92
- package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-test-coverage/example/lib/src/calculator.dart +0 -7
- package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-test-coverage/example/pubspec.yaml +0 -8
- package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-test-coverage/example/test/calculator_test.dart +0 -11
- package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-test-coverage/scripts/interpret_coverage.dart +0 -95
- package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-test-coverage/scripts/pubspec.yaml +0 -6
- package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-test-coverage/scripts/test/interpret_coverage_test.dart +0 -93
- package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/dart-test-fundamentals/SKILL.md +0 -173
- package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/definition-of-done/SKILL.md +0 -27
- package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/flutter_skills_ignore.json +0 -3
- package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/grill-me/SKILL.md +0 -10
- package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/ignore.json +0 -3
- package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/test-driven-development/SKILL.md +0 -371
- package/skills/flutter-skills/tool/dart_skills_lint/.agents/skills/test-driven-development/testing-anti-patterns.md +0 -299
- package/skills/flutter-skills/tool/dart_skills_lint/AUTHORS +0 -7
- package/skills/flutter-skills/tool/dart_skills_lint/CHANGELOG.md +0 -12
- package/skills/flutter-skills/tool/dart_skills_lint/CONTRIBUTING.md +0 -51
- package/skills/flutter-skills/tool/dart_skills_lint/LICENSE +0 -27
- package/skills/flutter-skills/tool/dart_skills_lint/README.md +0 -203
- package/skills/flutter-skills/tool/dart_skills_lint/analysis_options.yaml +0 -296
- package/skills/flutter-skills/tool/dart_skills_lint/bench/README.md +0 -23
- package/skills/flutter-skills/tool/dart_skills_lint/bench/baseline_throughput.dart +0 -230
- package/skills/flutter-skills/tool/dart_skills_lint/bin/cli.dart +0 -10
- package/skills/flutter-skills/tool/dart_skills_lint/dart_skills_lint.yaml +0 -14
- package/skills/flutter-skills/tool/dart_skills_lint/documentation/feature_design_docs/PRODUCTION_READYNESS.md +0 -48
- package/skills/flutter-skills/tool/dart_skills_lint/documentation/feature_design_docs/completion_migration_plan.md +0 -99
- package/skills/flutter-skills/tool/dart_skills_lint/documentation/feature_design_docs/legacy_patterns_report.md +0 -110
- package/skills/flutter-skills/tool/dart_skills_lint/documentation/feature_design_docs/pub_vs_skill_report.md +0 -56
- package/skills/flutter-skills/tool/dart_skills_lint/documentation/knowledge/SPECIFICATION.md +0 -79
- package/skills/flutter-skills/tool/dart_skills_lint/documentation/knowledge/architecture_overview.md +0 -64
- package/skills/flutter-skills/tool/dart_skills_lint/lib/dart_skills_lint.dart +0 -11
- package/skills/flutter-skills/tool/dart_skills_lint/lib/src/config_parser.dart +0 -156
- package/skills/flutter-skills/tool/dart_skills_lint/lib/src/entry_point.dart +0 -354
- package/skills/flutter-skills/tool/dart_skills_lint/lib/src/fixable_rule.dart +0 -20
- package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/analysis_severity.dart +0 -15
- package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/check_type.dart +0 -17
- package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/ignore_entry.dart +0 -34
- package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/ignore_entry.g.dart +0 -19
- package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/skill_context.dart +0 -27
- package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/skill_rule.dart +0 -27
- package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/skills_ignores.dart +0 -26
- package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/skills_ignores.g.dart +0 -24
- package/skills/flutter-skills/tool/dart_skills_lint/lib/src/models/validation_error.dart +0 -31
- package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rule_registry.dart +0 -79
- package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rules/absolute_paths_rule.dart +0 -74
- package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rules/description_length_rule.dart +0 -49
- package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rules/disallowed_field_rule.dart +0 -61
- package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rules/name_format_rule.dart +0 -167
- package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rules/relative_paths_rule.dart +0 -72
- package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rules/trailing_whitespace_rule.dart +0 -93
- package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rules/valid_yaml_metadata_rule.dart +0 -74
- package/skills/flutter-skills/tool/dart_skills_lint/lib/src/skills_ignores_storage.dart +0 -36
- package/skills/flutter-skills/tool/dart_skills_lint/lib/src/validation_session.dart +0 -559
- package/skills/flutter-skills/tool/dart_skills_lint/lib/src/validator.dart +0 -238
- package/skills/flutter-skills/tool/dart_skills_lint/pubspec.yaml +0 -28
- package/skills/flutter-skills/tool/dart_skills_lint/skills/README.md +0 -10
- package/skills/flutter-skills/tool/dart_skills_lint/skills/dart-skills-lint-validation/SKILL.md +0 -195
- package/skills/flutter-skills/tool/dart_skills_lint/skills-lock.json +0 -75
- package/skills/flutter-skills/tool/dart_skills_lint/test/absolute_paths_test.dart +0 -167
- package/skills/flutter-skills/tool/dart_skills_lint/test/cli_integration_test.dart +0 -683
- package/skills/flutter-skills/tool/dart_skills_lint/test/config_file_test.dart +0 -292
- package/skills/flutter-skills/tool/dart_skills_lint/test/custom_rule_test.dart +0 -122
- package/skills/flutter-skills/tool/dart_skills_lint/test/directory_structure_test.dart +0 -163
- package/skills/flutter-skills/tool/dart_skills_lint/test/field_constraints_test.dart +0 -178
- package/skills/flutter-skills/tool/dart_skills_lint/test/fixer_test.dart +0 -172
- package/skills/flutter-skills/tool/dart_skills_lint/test/ignore_models_test.dart +0 -63
- package/skills/flutter-skills/tool/dart_skills_lint/test/metadata_validation_test.dart +0 -116
- package/skills/flutter-skills/tool/dart_skills_lint/test/relative_path_flag_test.dart +0 -70
- package/skills/flutter-skills/tool/dart_skills_lint/test/relative_paths_test.dart +0 -172
- package/skills/flutter-skills/tool/dart_skills_lint/test/resolve_rules_test.dart +0 -82
- package/skills/flutter-skills/tool/dart_skills_lint/test/rule_naming_test.dart +0 -29
- package/skills/flutter-skills/tool/dart_skills_lint/test/skills_ignores_storage_test.dart +0 -89
- package/skills/flutter-skills/tool/dart_skills_lint/test/test_utils.dart +0 -19
- package/skills/flutter-skills/tool/dart_skills_lint/test/trailing_whitespace_test.dart +0 -152
- package/skills/flutter-skills/tool/generator/README.md +0 -150
- package/skills/flutter-skills/tool/generator/analysis_options.yaml +0 -143
- package/skills/flutter-skills/tool/generator/bin/skills.dart +0 -73
- package/skills/flutter-skills/tool/generator/lib/src/commands/base_skill_command.dart +0 -87
- package/skills/flutter-skills/tool/generator/lib/src/commands/base_yaml_command.dart +0 -83
- package/skills/flutter-skills/tool/generator/lib/src/commands/generate_skill_command.dart +0 -92
- package/skills/flutter-skills/tool/generator/lib/src/commands/update_readme_command.dart +0 -150
- package/skills/flutter-skills/tool/generator/lib/src/commands/update_skill_command.dart +0 -97
- package/skills/flutter-skills/tool/generator/lib/src/commands/validate_skill_command.dart +0 -284
- package/skills/flutter-skills/tool/generator/lib/src/models/skill_params.dart +0 -41
- package/skills/flutter-skills/tool/generator/lib/src/services/gemini_service.dart +0 -310
- package/skills/flutter-skills/tool/generator/lib/src/services/markdown_converter.dart +0 -226
- package/skills/flutter-skills/tool/generator/lib/src/services/prompts.dart +0 -72
- package/skills/flutter-skills/tool/generator/lib/src/services/resource_fetcher_service.dart +0 -84
- package/skills/flutter-skills/tool/generator/lib/src/services/skill_instructions.dart +0 -30
- package/skills/flutter-skills/tool/generator/pubspec.yaml +0 -32
- package/skills/flutter-skills/tool/generator/test/commands/base_skill_command_test.dart +0 -131
- package/skills/flutter-skills/tool/generator/test/commands/validate_skills_input_test.dart +0 -263
- package/skills/flutter-skills/tool/generator/test/custom_skill_rules/last_modified_rule.dart +0 -32
- package/skills/flutter-skills/tool/generator/test/generate_skills_retry_test.dart +0 -105
- package/skills/flutter-skills/tool/generator/test/generate_skills_test.dart +0 -519
- package/skills/flutter-skills/tool/generator/test/lint_skills_test.dart +0 -34
- package/skills/flutter-skills/tool/generator/test/markdown_converter_test.dart +0 -103
- package/skills/flutter-skills/tool/generator/test/markdown_table_test.dart +0 -131
- package/skills/flutter-skills/tool/generator/test/models/skill_params_test.dart +0 -37
- package/skills/flutter-skills/tool/generator/test/services/gemini_service_test.dart +0 -291
- package/skills/flutter-skills/tool/generator/test/services/markdown_converter_test.dart +0 -156
- package/skills/flutter-skills/tool/generator/test/services/resource_fetcher_service_test.dart +0 -188
- package/skills/flutter-skills/tool/generator/test/update_skills_test.dart +0 -241
- package/skills/flutter-skills/tool/generator/test/validate_skills_test.dart +0 -728
- /package/skills/{.agents → flutter}/skills/flutter-add-integration-test/SKILL.md +0 -0
- /package/skills/{.agents → flutter}/skills/flutter-add-widget-preview/SKILL.md +0 -0
- /package/skills/{.agents → flutter}/skills/flutter-add-widget-test/SKILL.md +0 -0
- /package/skills/{.agents → flutter}/skills/flutter-apply-architecture-best-practices/SKILL.md +0 -0
- /package/skills/{.agents → flutter}/skills/flutter-build-responsive-layout/SKILL.md +0 -0
- /package/skills/{.agents → flutter}/skills/flutter-fix-layout-issues/SKILL.md +0 -0
- /package/skills/{.agents → flutter}/skills/flutter-implement-json-serialization/SKILL.md +0 -0
- /package/skills/{.agents → flutter}/skills/flutter-setup-declarative-routing/SKILL.md +0 -0
- /package/skills/{.agents → flutter}/skills/flutter-setup-localization/SKILL.md +0 -0
- /package/skills/{.agents → flutter}/skills/flutter-use-http-package/SKILL.md +0 -0
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import 'dart:io';
|
|
2
|
-
import 'package:path/path.dart';
|
|
3
|
-
import '../fixable_rule.dart';
|
|
4
|
-
import '../models/analysis_severity.dart';
|
|
5
|
-
import '../models/skill_context.dart';
|
|
6
|
-
import '../models/skill_rule.dart';
|
|
7
|
-
import '../models/validation_error.dart';
|
|
8
|
-
|
|
9
|
-
/// Enforces that links in SKILL.md do not use absolute paths.
|
|
10
|
-
class AbsolutePathsRule extends SkillRule implements FixableRule {
|
|
11
|
-
AbsolutePathsRule({this.severity = defaultSeverity});
|
|
12
|
-
|
|
13
|
-
static const String ruleName = 'check-absolute-paths';
|
|
14
|
-
static const AnalysisSeverity defaultSeverity = AnalysisSeverity.warning;
|
|
15
|
-
|
|
16
|
-
@override
|
|
17
|
-
String get name => ruleName;
|
|
18
|
-
|
|
19
|
-
@override
|
|
20
|
-
final AnalysisSeverity severity;
|
|
21
|
-
|
|
22
|
-
static final _markdownLinkRegex = RegExp(r'\[.*?\]\((.*?)\)');
|
|
23
|
-
static const String _skillFileName = SkillContext.skillFileName;
|
|
24
|
-
|
|
25
|
-
@override
|
|
26
|
-
Future<List<ValidationError>> validate(SkillContext context) async {
|
|
27
|
-
final errors = <ValidationError>[];
|
|
28
|
-
|
|
29
|
-
// Extract content after YAML frontmatter
|
|
30
|
-
final skillStartRegex = RegExp(r'^---\s*\n(.*?)\n---\s*\n', dotAll: true);
|
|
31
|
-
final RegExpMatch? match = skillStartRegex.firstMatch(context.rawContent);
|
|
32
|
-
final String markdownContent = match != null
|
|
33
|
-
? context.rawContent.substring(match.end)
|
|
34
|
-
: context.rawContent;
|
|
35
|
-
|
|
36
|
-
for (final RegExpMatch linkMatch in _markdownLinkRegex.allMatches(markdownContent)) {
|
|
37
|
-
final String path = linkMatch.group(1)!;
|
|
38
|
-
if (isAbsolute(path) || windows.isAbsolute(path)) {
|
|
39
|
-
errors.add(
|
|
40
|
-
ValidationError(
|
|
41
|
-
ruleId: name,
|
|
42
|
-
severity: severity,
|
|
43
|
-
file: _skillFileName,
|
|
44
|
-
message: 'Absolute filepath found in link: $path',
|
|
45
|
-
),
|
|
46
|
-
);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return errors;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
@override
|
|
54
|
-
Future<String> fix(String filePath, String currentContent, Directory directory) async {
|
|
55
|
-
if (filePath != SkillContext.skillFileName) {
|
|
56
|
-
return currentContent;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return currentContent.replaceAllMapped(_markdownLinkRegex, (match) {
|
|
60
|
-
final String path = match.group(1)!;
|
|
61
|
-
if (isAbsolute(path) || windows.isAbsolute(path)) {
|
|
62
|
-
final file = File(path);
|
|
63
|
-
if (file.existsSync()) {
|
|
64
|
-
final String relativePath = relative(path, from: directory.path);
|
|
65
|
-
final String posixRelativePath = relativePath.replaceAll(r'\', '/');
|
|
66
|
-
final String fullMatch = match.group(0)!;
|
|
67
|
-
final int lastParen = fullMatch.lastIndexOf('(');
|
|
68
|
-
return '${fullMatch.substring(0, lastParen + 1)}$posixRelativePath)';
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
return match.group(0)!;
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
}
|
package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rules/description_length_rule.dart
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import 'package:yaml/yaml.dart';
|
|
2
|
-
import '../models/analysis_severity.dart';
|
|
3
|
-
import '../models/skill_context.dart';
|
|
4
|
-
import '../models/skill_rule.dart';
|
|
5
|
-
import '../models/validation_error.dart';
|
|
6
|
-
|
|
7
|
-
/// Enforces that the description field is not too long.
|
|
8
|
-
class DescriptionLengthRule extends SkillRule {
|
|
9
|
-
DescriptionLengthRule({this.severity = defaultSeverity});
|
|
10
|
-
|
|
11
|
-
static const String ruleName = 'description-too-long';
|
|
12
|
-
static const AnalysisSeverity defaultSeverity = AnalysisSeverity.error;
|
|
13
|
-
|
|
14
|
-
@override
|
|
15
|
-
String get name => ruleName;
|
|
16
|
-
|
|
17
|
-
@override
|
|
18
|
-
final AnalysisSeverity severity;
|
|
19
|
-
|
|
20
|
-
static const maxDescriptionLength = 1024;
|
|
21
|
-
static const _skillFileName = 'SKILL.md';
|
|
22
|
-
static const _descriptionFieldUrl = 'https://agentskills.io/specification#description-field';
|
|
23
|
-
|
|
24
|
-
@override
|
|
25
|
-
Future<List<ValidationError>> validate(SkillContext context) async {
|
|
26
|
-
final errors = <ValidationError>[];
|
|
27
|
-
|
|
28
|
-
if (context.parsedYaml == null) {
|
|
29
|
-
return errors;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
final YamlMap yaml = context.parsedYaml!;
|
|
33
|
-
final String description = yaml['description']?.toString() ?? '';
|
|
34
|
-
|
|
35
|
-
if (description.length > maxDescriptionLength) {
|
|
36
|
-
errors.add(
|
|
37
|
-
ValidationError(
|
|
38
|
-
ruleId: name,
|
|
39
|
-
severity: severity,
|
|
40
|
-
file: _skillFileName,
|
|
41
|
-
message:
|
|
42
|
-
'Description field is too long. Maximum $maxDescriptionLength characters (see $_descriptionFieldUrl)',
|
|
43
|
-
),
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return errors;
|
|
48
|
-
}
|
|
49
|
-
}
|
package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rules/disallowed_field_rule.dart
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import 'package:yaml/yaml.dart';
|
|
2
|
-
import '../models/analysis_severity.dart';
|
|
3
|
-
import '../models/skill_context.dart';
|
|
4
|
-
import '../models/skill_rule.dart';
|
|
5
|
-
import '../models/validation_error.dart';
|
|
6
|
-
|
|
7
|
-
/// Enforces that only allowed fields are present in YAML metadata.
|
|
8
|
-
class DisallowedFieldRule extends SkillRule {
|
|
9
|
-
DisallowedFieldRule({this.severity = defaultSeverity});
|
|
10
|
-
|
|
11
|
-
static const String ruleName = 'disallowed-field';
|
|
12
|
-
static const AnalysisSeverity defaultSeverity = AnalysisSeverity.disabled;
|
|
13
|
-
|
|
14
|
-
@override
|
|
15
|
-
String get name => ruleName;
|
|
16
|
-
|
|
17
|
-
@override
|
|
18
|
-
final AnalysisSeverity severity;
|
|
19
|
-
|
|
20
|
-
static const _allowedFields = {
|
|
21
|
-
'name',
|
|
22
|
-
'description',
|
|
23
|
-
'license',
|
|
24
|
-
'allowed-tools',
|
|
25
|
-
'metadata',
|
|
26
|
-
'compatibility',
|
|
27
|
-
'category',
|
|
28
|
-
'tags',
|
|
29
|
-
'version',
|
|
30
|
-
'eval_task',
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
static const _skillFileName = 'SKILL.md';
|
|
34
|
-
static const _metadataUrl = 'https://agentskills.io/specification#frontmatter';
|
|
35
|
-
|
|
36
|
-
@override
|
|
37
|
-
Future<List<ValidationError>> validate(SkillContext context) async {
|
|
38
|
-
final errors = <ValidationError>[];
|
|
39
|
-
|
|
40
|
-
if (context.parsedYaml == null) {
|
|
41
|
-
return errors;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
final YamlMap yaml = context.parsedYaml!;
|
|
45
|
-
for (final Object? key in yaml.keys) {
|
|
46
|
-
final bool isDisallowed = key is! String || !_allowedFields.contains(key);
|
|
47
|
-
if (isDisallowed) {
|
|
48
|
-
errors.add(
|
|
49
|
-
ValidationError(
|
|
50
|
-
ruleId: name,
|
|
51
|
-
severity: severity,
|
|
52
|
-
file: _skillFileName,
|
|
53
|
-
message: 'Disallowed field: $key (see $_metadataUrl)',
|
|
54
|
-
),
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return errors;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import 'dart:io';
|
|
2
|
-
import 'package:meta/meta.dart';
|
|
3
|
-
import 'package:path/path.dart';
|
|
4
|
-
import 'package:yaml/yaml.dart';
|
|
5
|
-
import '../fixable_rule.dart';
|
|
6
|
-
import '../models/analysis_severity.dart';
|
|
7
|
-
import '../models/skill_context.dart';
|
|
8
|
-
import '../models/skill_rule.dart';
|
|
9
|
-
import '../models/validation_error.dart';
|
|
10
|
-
|
|
11
|
-
/// Enforces constraints on the skill name field.
|
|
12
|
-
class NameFormatRule extends SkillRule implements FixableRule {
|
|
13
|
-
NameFormatRule({this.severity = defaultSeverity});
|
|
14
|
-
|
|
15
|
-
static const String ruleName = 'invalid-skill-name';
|
|
16
|
-
static const AnalysisSeverity defaultSeverity = AnalysisSeverity.error;
|
|
17
|
-
|
|
18
|
-
@override
|
|
19
|
-
String get name => ruleName;
|
|
20
|
-
|
|
21
|
-
@override
|
|
22
|
-
final AnalysisSeverity severity;
|
|
23
|
-
|
|
24
|
-
static const maxNameLength = 64;
|
|
25
|
-
static final _validNameRegex = RegExp(r'^[a-z0-9\-]+$');
|
|
26
|
-
static const String _skillFileName = SkillContext.skillFileName;
|
|
27
|
-
static const _nameFieldUrl = 'https://agentskills.io/specification#name-field';
|
|
28
|
-
|
|
29
|
-
@override
|
|
30
|
-
Future<List<ValidationError>> validate(SkillContext context) async {
|
|
31
|
-
final errors = <ValidationError>[];
|
|
32
|
-
|
|
33
|
-
if (context.parsedYaml == null) {
|
|
34
|
-
return errors;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
final YamlMap yaml = context.parsedYaml!;
|
|
38
|
-
final String skillName = getNameNode(yaml)?.value.toString() ?? '';
|
|
39
|
-
|
|
40
|
-
if (skillName.isEmpty) {
|
|
41
|
-
return errors; // Handled by required fields check
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (skillName != skillName.toLowerCase()) {
|
|
45
|
-
errors.add(
|
|
46
|
-
ValidationError(
|
|
47
|
-
ruleId: name,
|
|
48
|
-
severity: severity,
|
|
49
|
-
file: _skillFileName,
|
|
50
|
-
message: 'Skill name must be lowercase: $skillName (see $_nameFieldUrl)',
|
|
51
|
-
),
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (skillName.length > maxNameLength) {
|
|
56
|
-
errors.add(
|
|
57
|
-
ValidationError(
|
|
58
|
-
ruleId: name,
|
|
59
|
-
severity: severity,
|
|
60
|
-
file: _skillFileName,
|
|
61
|
-
message: 'Skill name too long. Maximum $maxNameLength characters (see $_nameFieldUrl)',
|
|
62
|
-
),
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (!_validNameRegex.hasMatch(skillName)) {
|
|
67
|
-
errors.add(
|
|
68
|
-
ValidationError(
|
|
69
|
-
ruleId: name,
|
|
70
|
-
severity: severity,
|
|
71
|
-
file: _skillFileName,
|
|
72
|
-
message:
|
|
73
|
-
'Skill name contains invalid characters. Only lowercase letters, digits, and hyphens allowed (see $_nameFieldUrl)',
|
|
74
|
-
),
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (skillName.startsWith('-') || skillName.endsWith('-')) {
|
|
79
|
-
errors.add(
|
|
80
|
-
ValidationError(
|
|
81
|
-
ruleId: name,
|
|
82
|
-
severity: severity,
|
|
83
|
-
file: _skillFileName,
|
|
84
|
-
message: 'Skill name cannot have leading or trailing hyphens (see $_nameFieldUrl)',
|
|
85
|
-
),
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (skillName.contains('--')) {
|
|
90
|
-
errors.add(
|
|
91
|
-
ValidationError(
|
|
92
|
-
ruleId: name,
|
|
93
|
-
severity: severity,
|
|
94
|
-
file: _skillFileName,
|
|
95
|
-
message: 'Skill name cannot have consecutive hyphens (see $_nameFieldUrl)',
|
|
96
|
-
),
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
final String dirName = basename(context.directory.path);
|
|
101
|
-
if (skillName != dirName) {
|
|
102
|
-
errors.add(
|
|
103
|
-
ValidationError(
|
|
104
|
-
ruleId: name,
|
|
105
|
-
severity: severity,
|
|
106
|
-
file: _skillFileName,
|
|
107
|
-
message:
|
|
108
|
-
'Skill name ($skillName) must exactly match the parent directory name ($dirName) (see $_nameFieldUrl)',
|
|
109
|
-
),
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return errors;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
@override
|
|
117
|
-
Future<String> fix(String filePath, String currentContent, Directory directory) async {
|
|
118
|
-
if (filePath != SkillContext.skillFileName) {
|
|
119
|
-
return currentContent;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
final RegExpMatch? match = SkillContext.skillStartRegex.firstMatch(currentContent);
|
|
123
|
-
if (match == null) {
|
|
124
|
-
return currentContent;
|
|
125
|
-
}
|
|
126
|
-
final String yamlStr = match.group(1)!;
|
|
127
|
-
|
|
128
|
-
final Object? yamlObj;
|
|
129
|
-
try {
|
|
130
|
-
yamlObj = loadYaml(yamlStr);
|
|
131
|
-
} catch (e) {
|
|
132
|
-
return currentContent;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (yamlObj is! YamlMap) {
|
|
136
|
-
return currentContent;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
final YamlMap yaml = yamlObj;
|
|
140
|
-
final YamlNode? nameNode = getNameNode(yaml);
|
|
141
|
-
if (nameNode == null) {
|
|
142
|
-
return currentContent;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
final String dirName = basename(directory.path);
|
|
146
|
-
|
|
147
|
-
final currentName = nameNode.value.toString();
|
|
148
|
-
if (currentName == dirName) {
|
|
149
|
-
return currentContent;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
final int yamlOffset = currentContent.indexOf(yamlStr, match.start);
|
|
153
|
-
|
|
154
|
-
// ignore: specify_nonobvious_local_variable_types
|
|
155
|
-
final span = nameNode.span;
|
|
156
|
-
final String before = currentContent.substring(0, yamlOffset + span.start.offset);
|
|
157
|
-
final String after = currentContent.substring(yamlOffset + span.end.offset);
|
|
158
|
-
|
|
159
|
-
return '$before$dirName$after';
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/// Returns the YAML node for the skill name.
|
|
163
|
-
@visibleForTesting
|
|
164
|
-
static YamlNode? getNameNode(YamlMap yaml) {
|
|
165
|
-
return yaml.nodes['name'];
|
|
166
|
-
}
|
|
167
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import 'dart:io';
|
|
2
|
-
import 'package:path/path.dart';
|
|
3
|
-
import '../models/analysis_severity.dart';
|
|
4
|
-
import '../models/skill_context.dart';
|
|
5
|
-
import '../models/skill_rule.dart';
|
|
6
|
-
import '../models/validation_error.dart';
|
|
7
|
-
|
|
8
|
-
/// Enforces that relative links in SKILL.md point to existing files.
|
|
9
|
-
class RelativePathsRule extends SkillRule {
|
|
10
|
-
RelativePathsRule({this.severity = defaultSeverity});
|
|
11
|
-
|
|
12
|
-
static const String ruleName = 'check-relative-paths';
|
|
13
|
-
static const AnalysisSeverity defaultSeverity = AnalysisSeverity.disabled;
|
|
14
|
-
|
|
15
|
-
@override
|
|
16
|
-
String get name => ruleName;
|
|
17
|
-
|
|
18
|
-
@override
|
|
19
|
-
final AnalysisSeverity severity;
|
|
20
|
-
|
|
21
|
-
static final _markdownLinkRegex = RegExp(r'\[.*?\]\((.*?)\)');
|
|
22
|
-
static const _skillFileName = 'SKILL.md';
|
|
23
|
-
|
|
24
|
-
@override
|
|
25
|
-
Future<List<ValidationError>> validate(SkillContext context) async {
|
|
26
|
-
final errors = <ValidationError>[];
|
|
27
|
-
|
|
28
|
-
// Extract content after YAML frontmatter
|
|
29
|
-
final skillStartRegex = RegExp(r'^---\s*\n(.*?)\n---\s*\n', dotAll: true);
|
|
30
|
-
final RegExpMatch? match = skillStartRegex.firstMatch(context.rawContent);
|
|
31
|
-
final String markdownContent = match != null
|
|
32
|
-
? context.rawContent.substring(match.end)
|
|
33
|
-
: context.rawContent;
|
|
34
|
-
|
|
35
|
-
for (final RegExpMatch linkMatch in _markdownLinkRegex.allMatches(markdownContent)) {
|
|
36
|
-
final String fullPath = linkMatch.group(1)!;
|
|
37
|
-
// Markdown links can have a title after the URL, separated by spaces.
|
|
38
|
-
// e.g. [text](url "title")
|
|
39
|
-
final String path = fullPath.trim().split(RegExp(r'\s+')).first;
|
|
40
|
-
|
|
41
|
-
// Skip absolute paths (handled by AbsolutePathsRule)
|
|
42
|
-
if (isAbsolute(path) || windows.isAbsolute(path)) {
|
|
43
|
-
continue;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
var effectivePath = path;
|
|
47
|
-
try {
|
|
48
|
-
final Uri uri = Uri.parse(path);
|
|
49
|
-
if (uri.hasScheme || path.startsWith('#')) {
|
|
50
|
-
continue; // Ignore web URLs, email links, anchors, etc.
|
|
51
|
-
}
|
|
52
|
-
effectivePath = uri.path;
|
|
53
|
-
} catch (_) {
|
|
54
|
-
// If Uri parsing fails, treat it as a potential filepath.
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
final linkedFile = File(join(context.directory.path, effectivePath));
|
|
58
|
-
if (!linkedFile.existsSync()) {
|
|
59
|
-
errors.add(
|
|
60
|
-
ValidationError(
|
|
61
|
-
ruleId: name,
|
|
62
|
-
severity: severity,
|
|
63
|
-
file: _skillFileName,
|
|
64
|
-
message: 'Linked file does not exist: $path',
|
|
65
|
-
),
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return errors;
|
|
71
|
-
}
|
|
72
|
-
}
|
package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rules/trailing_whitespace_rule.dart
DELETED
|
@@ -1,93 +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:io';
|
|
6
|
-
import 'package:meta/meta.dart';
|
|
7
|
-
|
|
8
|
-
import '../fixable_rule.dart';
|
|
9
|
-
import '../models/analysis_severity.dart';
|
|
10
|
-
import '../models/skill_context.dart';
|
|
11
|
-
import '../models/skill_rule.dart';
|
|
12
|
-
import '../models/validation_error.dart';
|
|
13
|
-
|
|
14
|
-
/// Enforces that lines in SKILL.md do not have trailing whitespace,
|
|
15
|
-
/// except for exactly two spaces which indicate a hard line break.
|
|
16
|
-
class TrailingWhitespaceRule extends SkillRule implements FixableRule {
|
|
17
|
-
TrailingWhitespaceRule({this.severity = defaultSeverity});
|
|
18
|
-
|
|
19
|
-
static const String ruleName = 'check-trailing-whitespace';
|
|
20
|
-
static const AnalysisSeverity defaultSeverity = AnalysisSeverity.disabled;
|
|
21
|
-
static final RegExp _whitespaceRegExp = RegExp(r'([ \t]+)$');
|
|
22
|
-
|
|
23
|
-
@override
|
|
24
|
-
String get name => ruleName;
|
|
25
|
-
|
|
26
|
-
@override
|
|
27
|
-
final AnalysisSeverity severity;
|
|
28
|
-
|
|
29
|
-
@override
|
|
30
|
-
Future<List<ValidationError>> validate(SkillContext context) async {
|
|
31
|
-
final errors = <ValidationError>[];
|
|
32
|
-
final List<String> lines = context.rawContent.split('\n');
|
|
33
|
-
|
|
34
|
-
for (var i = 0; i < lines.length; i++) {
|
|
35
|
-
final String line = lines[i];
|
|
36
|
-
|
|
37
|
-
// Remove carriage return if present (Windows line endings)
|
|
38
|
-
final String trimmedLine = line.endsWith('\r') ? line.substring(0, line.length - 1) : line;
|
|
39
|
-
|
|
40
|
-
final RegExpMatch? match = _whitespaceRegExp.firstMatch(trimmedLine);
|
|
41
|
-
if (match != null) {
|
|
42
|
-
final String whitespace = match.group(1)!;
|
|
43
|
-
String? message;
|
|
44
|
-
|
|
45
|
-
if (whitespace.contains('\t')) {
|
|
46
|
-
message = 'Line ${i + 1} has trailing whitespace containing tabs.';
|
|
47
|
-
} else {
|
|
48
|
-
final int spacesCount = whitespace.length;
|
|
49
|
-
if (spacesCount == 1 || spacesCount >= 3) {
|
|
50
|
-
message =
|
|
51
|
-
'Line ${i + 1} has $spacesCount trailing space(s). Only exactly 2 spaces are allowed for line breaks.';
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (message != null) {
|
|
56
|
-
errors.add(
|
|
57
|
-
ValidationError(ruleId: name, severity: severity, file: 'SKILL.md', message: message),
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return errors;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
@override
|
|
67
|
-
Future<String> fix(String filePath, String currentContent, Directory directory) async {
|
|
68
|
-
if (filePath != 'SKILL.md') {
|
|
69
|
-
return currentContent;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return currentContent.split('\n').map(fixLine).join('\n');
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
@visibleForTesting
|
|
76
|
-
String fixLine(String line) {
|
|
77
|
-
final bool hasCR = line.endsWith('\r');
|
|
78
|
-
final String lineWithoutCR = hasCR ? line.substring(0, line.length - 1) : line;
|
|
79
|
-
|
|
80
|
-
final RegExpMatch? match = _whitespaceRegExp.firstMatch(lineWithoutCR);
|
|
81
|
-
if (match == null) {
|
|
82
|
-
return line;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
final String whitespace = match.group(1)!;
|
|
86
|
-
if (whitespace == ' ') {
|
|
87
|
-
return line; // Keep the 2 space hard line break.
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
final String fixedLine = lineWithoutCR.replaceAll(_whitespaceRegExp, '');
|
|
91
|
-
return hasCR ? '$fixedLine\r' : fixedLine;
|
|
92
|
-
}
|
|
93
|
-
}
|
package/skills/flutter-skills/tool/dart_skills_lint/lib/src/rules/valid_yaml_metadata_rule.dart
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import 'package:yaml/yaml.dart';
|
|
2
|
-
import '../models/analysis_severity.dart';
|
|
3
|
-
import '../models/skill_context.dart';
|
|
4
|
-
import '../models/skill_rule.dart';
|
|
5
|
-
import '../models/validation_error.dart';
|
|
6
|
-
|
|
7
|
-
/// Enforces that SKILL.md has valid YAML frontmatter and required fields.
|
|
8
|
-
class ValidYamlMetadataRule extends SkillRule {
|
|
9
|
-
ValidYamlMetadataRule({this.severity = defaultSeverity});
|
|
10
|
-
|
|
11
|
-
static const String ruleName = 'valid-yaml-metadata';
|
|
12
|
-
static const AnalysisSeverity defaultSeverity = AnalysisSeverity.error;
|
|
13
|
-
|
|
14
|
-
@override
|
|
15
|
-
String get name => ruleName;
|
|
16
|
-
|
|
17
|
-
@override
|
|
18
|
-
final AnalysisSeverity severity;
|
|
19
|
-
|
|
20
|
-
static const _requiredFields = {'name', 'description'};
|
|
21
|
-
static const _skillFileName = 'SKILL.md';
|
|
22
|
-
static const _metadataUrl = 'https://agentskills.io/specification#frontmatter';
|
|
23
|
-
static const maxCompatibilityLength = 500;
|
|
24
|
-
static const _compatibilityFieldUrl = 'https://agentskills.io/specification#compatibility-field';
|
|
25
|
-
|
|
26
|
-
@override
|
|
27
|
-
Future<List<ValidationError>> validate(SkillContext context) async {
|
|
28
|
-
final errors = <ValidationError>[];
|
|
29
|
-
|
|
30
|
-
if (context.parsedYaml == null) {
|
|
31
|
-
errors.add(
|
|
32
|
-
ValidationError(
|
|
33
|
-
ruleId: name,
|
|
34
|
-
severity: severity,
|
|
35
|
-
file: _skillFileName,
|
|
36
|
-
message:
|
|
37
|
-
'Invalid YAML metadata: ${context.yamlParsingError ?? 'Missing or invalid'} (see $_metadataUrl)',
|
|
38
|
-
),
|
|
39
|
-
);
|
|
40
|
-
return errors;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
final YamlMap yaml = context.parsedYaml!;
|
|
44
|
-
for (final String field in _requiredFields) {
|
|
45
|
-
if (!yaml.containsKey(field)) {
|
|
46
|
-
errors.add(
|
|
47
|
-
ValidationError(
|
|
48
|
-
ruleId: name,
|
|
49
|
-
severity: severity,
|
|
50
|
-
file: _skillFileName,
|
|
51
|
-
message: 'Missing required field: $field (see $_metadataUrl)',
|
|
52
|
-
),
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (yaml.containsKey('compatibility')) {
|
|
58
|
-
final String compatibility = yaml['compatibility']?.toString() ?? '';
|
|
59
|
-
if (compatibility.length > maxCompatibilityLength) {
|
|
60
|
-
errors.add(
|
|
61
|
-
ValidationError(
|
|
62
|
-
ruleId: name,
|
|
63
|
-
severity: severity,
|
|
64
|
-
file: _skillFileName,
|
|
65
|
-
message:
|
|
66
|
-
'Compatibility field is too long. Maximum $maxCompatibilityLength characters (see $_compatibilityFieldUrl)',
|
|
67
|
-
),
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return errors;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
@@ -1,36 +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 'models/skills_ignores.dart';
|
|
9
|
-
|
|
10
|
-
/// Service class for reading and writing the `SkillsIgnores` model to/from disk.
|
|
11
|
-
class SkillsIgnoresStorage {
|
|
12
|
-
/// Loads `SkillsIgnores` from the specified path.
|
|
13
|
-
///
|
|
14
|
-
/// Returns an empty `SkillsIgnores` if the file does not exist or fails to parse.
|
|
15
|
-
Future<SkillsIgnores> load(String path) async {
|
|
16
|
-
final file = File(path);
|
|
17
|
-
if (!file.existsSync()) {
|
|
18
|
-
return SkillsIgnores(skills: {});
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
try {
|
|
22
|
-
final String content = await file.readAsString();
|
|
23
|
-
final json = jsonDecode(content) as Map<String, dynamic>;
|
|
24
|
-
return SkillsIgnores.fromJson(json);
|
|
25
|
-
} catch (_) {
|
|
26
|
-
return SkillsIgnores(skills: {});
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/// Saves `SkillsIgnores` to the specified path.
|
|
31
|
-
Future<void> save(String path, SkillsIgnores ignores) async {
|
|
32
|
-
final file = File(path);
|
|
33
|
-
final String jsonString = const JsonEncoder.withIndent(' ').convert(ignores.toJson());
|
|
34
|
-
await file.writeAsString(jsonString);
|
|
35
|
-
}
|
|
36
|
-
}
|