ace-lint 0.25.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.
- checksums.yaml +7 -0
- data/.ace-defaults/lint/config.yml +5 -0
- data/.ace-defaults/lint/kramdown.yml +23 -0
- data/.ace-defaults/lint/markdown.yml +16 -0
- data/.ace-defaults/lint/ruby.yml +67 -0
- data/.ace-defaults/lint/skills.yml +138 -0
- data/.ace-defaults/nav/protocols/wfi-sources/ace-lint.yml +11 -0
- data/CHANGELOG.md +584 -0
- data/LICENSE +21 -0
- data/README.md +40 -0
- data/Rakefile +14 -0
- data/exe/ace-lint +14 -0
- data/handbook/skills/as-lint-fix-issue-from/SKILL.md +34 -0
- data/handbook/skills/as-lint-process-report/SKILL.md +29 -0
- data/handbook/skills/as-lint-run/SKILL.md +27 -0
- data/handbook/workflow-instructions/lint/process-report.wf.md +175 -0
- data/handbook/workflow-instructions/lint/run.wf.md +145 -0
- data/lib/ace/lint/atoms/allowed_tools_validator.rb +100 -0
- data/lib/ace/lint/atoms/base_runner.rb +239 -0
- data/lib/ace/lint/atoms/comment_validator.rb +63 -0
- data/lib/ace/lint/atoms/config_locator.rb +162 -0
- data/lib/ace/lint/atoms/frontmatter_extractor.rb +74 -0
- data/lib/ace/lint/atoms/kramdown_parser.rb +81 -0
- data/lib/ace/lint/atoms/pattern_matcher.rb +96 -0
- data/lib/ace/lint/atoms/rubocop_runner.rb +67 -0
- data/lib/ace/lint/atoms/skill_schema_loader.rb +83 -0
- data/lib/ace/lint/atoms/standardrb_runner.rb +45 -0
- data/lib/ace/lint/atoms/type_detector.rb +121 -0
- data/lib/ace/lint/atoms/validator_registry.rb +113 -0
- data/lib/ace/lint/atoms/yaml_parser.rb +11 -0
- data/lib/ace/lint/atoms/yaml_validator.rb +69 -0
- data/lib/ace/lint/cli/commands/lint.rb +318 -0
- data/lib/ace/lint/cli.rb +25 -0
- data/lib/ace/lint/models/lint_result.rb +87 -0
- data/lib/ace/lint/models/validation_error.rb +31 -0
- data/lib/ace/lint/molecules/frontmatter_validator.rb +131 -0
- data/lib/ace/lint/molecules/group_resolver.rb +122 -0
- data/lib/ace/lint/molecules/kramdown_formatter.rb +66 -0
- data/lib/ace/lint/molecules/markdown_linter.rb +249 -0
- data/lib/ace/lint/molecules/offense_deduplicator.rb +65 -0
- data/lib/ace/lint/molecules/ruby_linter.rb +205 -0
- data/lib/ace/lint/molecules/skill_validator.rb +462 -0
- data/lib/ace/lint/molecules/validator_chain.rb +150 -0
- data/lib/ace/lint/molecules/yaml_linter.rb +53 -0
- data/lib/ace/lint/organisms/lint_doctor.rb +289 -0
- data/lib/ace/lint/organisms/lint_orchestrator.rb +294 -0
- data/lib/ace/lint/organisms/report_generator.rb +213 -0
- data/lib/ace/lint/organisms/result_reporter.rb +130 -0
- data/lib/ace/lint/version.rb +7 -0
- data/lib/ace/lint.rb +141 -0
- metadata +248 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: as-lint-fix-issue-from
|
|
3
|
+
description: Fix linting issues identified in ace-lint report output
|
|
4
|
+
# bundle: wfi://lint/run
|
|
5
|
+
# context: no-fork
|
|
6
|
+
# agent: general-purpose
|
|
7
|
+
user-invocable: true
|
|
8
|
+
allowed-tools:
|
|
9
|
+
- Bash(ace-lint:*)
|
|
10
|
+
- Bash(ace-bundle:*)
|
|
11
|
+
- Bash(ace-git-commit:*)
|
|
12
|
+
- Read
|
|
13
|
+
- Write
|
|
14
|
+
- Edit
|
|
15
|
+
- Grep
|
|
16
|
+
argument-hint: [linter-output-file]
|
|
17
|
+
last_modified: 2026-01-10
|
|
18
|
+
source: ace-lint
|
|
19
|
+
integration:
|
|
20
|
+
targets:
|
|
21
|
+
- claude
|
|
22
|
+
- codex
|
|
23
|
+
- gemini
|
|
24
|
+
- opencode
|
|
25
|
+
- pi
|
|
26
|
+
providers: {}
|
|
27
|
+
skill:
|
|
28
|
+
kind: workflow
|
|
29
|
+
execution:
|
|
30
|
+
workflow: wfi://lint/run
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
Load and run `ace-bundle wfi://lint/run` in the current project, then follow the loaded workflow as the source of truth and execute it end-to-end instead of only summarizing it.
|
|
34
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: as-lint-process-report
|
|
3
|
+
description: Process lint report and create tasks for manual fixes
|
|
4
|
+
# bundle: wfi://lint/process-report
|
|
5
|
+
# context: no-fork
|
|
6
|
+
# agent: general-purpose
|
|
7
|
+
user-invocable: true
|
|
8
|
+
allowed-tools:
|
|
9
|
+
- Bash(ace-lint:*)
|
|
10
|
+
- Bash(ace-bundle:*)
|
|
11
|
+
- Read
|
|
12
|
+
argument-hint: [report-path]
|
|
13
|
+
last_modified: 2026-03-10
|
|
14
|
+
source: ace-lint
|
|
15
|
+
integration:
|
|
16
|
+
targets:
|
|
17
|
+
- claude
|
|
18
|
+
- codex
|
|
19
|
+
- gemini
|
|
20
|
+
- opencode
|
|
21
|
+
- pi
|
|
22
|
+
providers: {}
|
|
23
|
+
skill:
|
|
24
|
+
kind: workflow
|
|
25
|
+
execution:
|
|
26
|
+
workflow: wfi://lint/process-report
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
Load and run `ace-bundle wfi://lint/process-report` in the current project, then follow the loaded workflow as the source of truth and execute it end-to-end instead of only summarizing it.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: as-lint-run
|
|
3
|
+
description: Run ace-lint on project files with optional autofix and report
|
|
4
|
+
# bundle: wfi://lint/run
|
|
5
|
+
# agent: general-purpose
|
|
6
|
+
user-invocable: true
|
|
7
|
+
allowed-tools:
|
|
8
|
+
- Bash(ace-lint:*)
|
|
9
|
+
- Bash(ace-bundle:*)
|
|
10
|
+
- Read
|
|
11
|
+
argument-hint: "[file-pattern] [--fix] [--report]"
|
|
12
|
+
last_modified: 2026-03-10
|
|
13
|
+
source: ace-lint
|
|
14
|
+
integration:
|
|
15
|
+
targets:
|
|
16
|
+
- claude
|
|
17
|
+
- codex
|
|
18
|
+
- gemini
|
|
19
|
+
- opencode
|
|
20
|
+
- pi
|
|
21
|
+
skill:
|
|
22
|
+
kind: workflow
|
|
23
|
+
execution:
|
|
24
|
+
workflow: wfi://lint/run
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
Load and run `ace-bundle wfi://lint/run` in the current project, then follow the loaded workflow as the source of truth and execute it end-to-end instead of only summarizing it.
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
---
|
|
2
|
+
doc-type: workflow
|
|
3
|
+
title: Process Lint Report Workflow
|
|
4
|
+
purpose: lint report processing workflow instruction
|
|
5
|
+
ace-docs:
|
|
6
|
+
last-updated: 2026-03-06
|
|
7
|
+
last-checked: 2026-03-21
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Process Lint Report Workflow
|
|
11
|
+
|
|
12
|
+
## Purpose
|
|
13
|
+
|
|
14
|
+
Parse a lint report file and create structured tasks for issues requiring manual intervention. Groups issues by severity and type, generates fix proposals, and drafts tasks via ace-taskflow.
|
|
15
|
+
|
|
16
|
+
## Prerequisites
|
|
17
|
+
|
|
18
|
+
- Lint report file exists (from `wfi://lint/run --report`)
|
|
19
|
+
- **ace-taskflow is installed and available** - required for task creation commands
|
|
20
|
+
- Understanding of project lint rules
|
|
21
|
+
|
|
22
|
+
## Variables
|
|
23
|
+
|
|
24
|
+
- `$report_path`: Path to lint report JSON file (from argument)
|
|
25
|
+
|
|
26
|
+
## Instructions
|
|
27
|
+
|
|
28
|
+
1. **Locate and read the lint report**:
|
|
29
|
+
|
|
30
|
+
**If report path provided:**
|
|
31
|
+
```bash
|
|
32
|
+
cat "$report_path"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**If no path, find most recent:**
|
|
36
|
+
```bash
|
|
37
|
+
ls -t .ace-lint/reports/*.json | head -1
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
2. **Parse and analyze errors**:
|
|
41
|
+
- Group by severity (error > warning)
|
|
42
|
+
- Group by file (for efficient fixing)
|
|
43
|
+
- Group by rule type (similar fixes together)
|
|
44
|
+
|
|
45
|
+
3. **Generate fix proposals** for each issue:
|
|
46
|
+
|
|
47
|
+
| Rule Type | Fix Approach |
|
|
48
|
+
|-----------|--------------|
|
|
49
|
+
| frontmatter-required | Add missing field with default value |
|
|
50
|
+
| yaml-syntax | Suggest correct syntax structure |
|
|
51
|
+
| markdown-structure | Recommend structural changes |
|
|
52
|
+
| link-broken | Suggest path updates or removal |
|
|
53
|
+
|
|
54
|
+
4. **Prioritize issues**:
|
|
55
|
+
- **P0 (blocking)**: Syntax errors preventing file parsing
|
|
56
|
+
- **P1 (high)**: Missing required metadata
|
|
57
|
+
- **P2 (medium)**: Style/formatting issues
|
|
58
|
+
- **P3 (low)**: Suggestions and improvements
|
|
59
|
+
|
|
60
|
+
5. **Create tasks via ace-taskflow**:
|
|
61
|
+
|
|
62
|
+
**For grouped issues (multiple similar errors):**
|
|
63
|
+
```bash
|
|
64
|
+
ace-idea create --llm-enhance "Fix [N] [rule-type] lint errors in [component]
|
|
65
|
+
|
|
66
|
+
Affected files:
|
|
67
|
+
- file1.md (line 10, 25)
|
|
68
|
+
- file2.md (line 5)
|
|
69
|
+
|
|
70
|
+
Fix approach: [common fix description]"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**For complex single issues:**
|
|
74
|
+
```bash
|
|
75
|
+
ace-idea create --llm-enhance "Fix [rule-type] in [file]
|
|
76
|
+
|
|
77
|
+
Error: [error message]
|
|
78
|
+
Location: [file:line]
|
|
79
|
+
|
|
80
|
+
Suggested fix: [fix proposal]"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
6. **Generate summary report**:
|
|
84
|
+
|
|
85
|
+
```markdown
|
|
86
|
+
# Lint Report Processing Summary
|
|
87
|
+
|
|
88
|
+
## Report: [report_path]
|
|
89
|
+
## Processed: [timestamp]
|
|
90
|
+
|
|
91
|
+
### Issues by Priority
|
|
92
|
+
|
|
93
|
+
| Priority | Count | Status |
|
|
94
|
+
|----------|-------|--------|
|
|
95
|
+
| P0 | N | Task created |
|
|
96
|
+
| P1 | N | Task created |
|
|
97
|
+
| P2 | N | Grouped into M tasks |
|
|
98
|
+
| P3 | N | Logged for later |
|
|
99
|
+
|
|
100
|
+
### Tasks Created
|
|
101
|
+
|
|
102
|
+
1. [Task ID]: [Title] - [N] issues
|
|
103
|
+
2. [Task ID]: [Title] - [N] issues
|
|
104
|
+
|
|
105
|
+
### Issues Deferred (P3)
|
|
106
|
+
|
|
107
|
+
- [issue description] - [file:line]
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Grouping Strategy
|
|
111
|
+
|
|
112
|
+
### Group by File (for small projects)
|
|
113
|
+
- All issues in one file → single task
|
|
114
|
+
- Efficient for focused fixes
|
|
115
|
+
|
|
116
|
+
### Group by Rule Type (for large projects)
|
|
117
|
+
- All `frontmatter-required` errors → one task
|
|
118
|
+
- Efficient for batch fixes with similar patterns
|
|
119
|
+
|
|
120
|
+
### Group by Component (for mono-repos)
|
|
121
|
+
- All issues in `ace-lint/` → one task
|
|
122
|
+
- Respects package boundaries
|
|
123
|
+
|
|
124
|
+
## Fix Proposal Templates
|
|
125
|
+
|
|
126
|
+
### Missing Frontmatter Field
|
|
127
|
+
```markdown
|
|
128
|
+
**Fix:** Add the following to YAML frontmatter:
|
|
129
|
+
\`\`\`yaml
|
|
130
|
+
doc-type: [suggested-type]
|
|
131
|
+
\`\`\`
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### YAML Syntax Error
|
|
135
|
+
```markdown
|
|
136
|
+
**Fix:** Correct YAML syntax at line [N]:
|
|
137
|
+
- Issue: [description]
|
|
138
|
+
- Current: `[problematic line]`
|
|
139
|
+
- Suggested: `[corrected line]`
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Broken Link
|
|
143
|
+
```markdown
|
|
144
|
+
**Fix:** Update link reference:
|
|
145
|
+
- Current: `[broken-path]`
|
|
146
|
+
- Options:
|
|
147
|
+
1. Update to: `[correct-path]` (if file moved)
|
|
148
|
+
2. Remove link (if resource deleted)
|
|
149
|
+
3. Mark as external (if external URL)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Success Criteria
|
|
153
|
+
|
|
154
|
+
- Report successfully parsed
|
|
155
|
+
- Issues grouped logically
|
|
156
|
+
- Fix proposals generated for each issue
|
|
157
|
+
- Tasks created in ace-taskflow
|
|
158
|
+
- Summary report generated
|
|
159
|
+
- No issues lost or duplicated
|
|
160
|
+
|
|
161
|
+
## Response Template
|
|
162
|
+
|
|
163
|
+
**Report Processed:** [report_path]
|
|
164
|
+
**Total Issues:** [N]
|
|
165
|
+
**Tasks Created:** [M]
|
|
166
|
+
**Issues Grouped:** [breakdown by priority]
|
|
167
|
+
**Next Steps:**
|
|
168
|
+
- Run `/as-task-work [task-id]` for each created task
|
|
169
|
+
- Re-run lint after fixes to verify
|
|
170
|
+
|
|
171
|
+
## Error Handling
|
|
172
|
+
|
|
173
|
+
- **Empty report**: Report success, no tasks needed
|
|
174
|
+
- **Invalid JSON**: Report parse error, suggest re-running lint
|
|
175
|
+
- **ace-taskflow unavailable**: Output task drafts as markdown
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
---
|
|
2
|
+
doc-type: workflow
|
|
3
|
+
title: Run Lint Workflow
|
|
4
|
+
purpose: lint workflow instruction
|
|
5
|
+
ace-docs:
|
|
6
|
+
last-updated: 2026-02-23
|
|
7
|
+
last-checked: 2026-03-21
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Run Lint Workflow
|
|
11
|
+
|
|
12
|
+
## Purpose
|
|
13
|
+
|
|
14
|
+
Execute ace-lint on project files with intelligent file selection, optional autofix coordination, and structured report generation for AI-assisted code quality improvement.
|
|
15
|
+
|
|
16
|
+
## Context
|
|
17
|
+
|
|
18
|
+
ace-lint automatically:
|
|
19
|
+
- Detects file types from extensions (.md, .yml, .yaml)
|
|
20
|
+
- Validates markdown frontmatter and structure
|
|
21
|
+
- Checks YAML syntax
|
|
22
|
+
- Reports errors in structured format
|
|
23
|
+
|
|
24
|
+
## Variables
|
|
25
|
+
|
|
26
|
+
- `$file_pattern`: Optional glob pattern or file paths (from argument)
|
|
27
|
+
- `$fix`: Whether to attempt autofixes (from --fix flag)
|
|
28
|
+
- `$report`: Whether to generate JSON report (from --report flag)
|
|
29
|
+
|
|
30
|
+
## Instructions
|
|
31
|
+
|
|
32
|
+
1. **Review embedded repository status** in `<current_repository_status>`:
|
|
33
|
+
- Which files have been modified?
|
|
34
|
+
- What types of files are involved?
|
|
35
|
+
- Is this a targeted lint or full project scan?
|
|
36
|
+
|
|
37
|
+
2. **Select files to lint** based on context:
|
|
38
|
+
- If file pattern provided: Use that pattern
|
|
39
|
+
- If recent changes: Focus on changed files
|
|
40
|
+
- Otherwise: Lint project-wide
|
|
41
|
+
|
|
42
|
+
3. **Execute lint command**:
|
|
43
|
+
|
|
44
|
+
**Basic lint (all markdown/yaml):**
|
|
45
|
+
```bash
|
|
46
|
+
ace-lint "**/*.md" "**/*.yml"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Lint specific files:**
|
|
50
|
+
```bash
|
|
51
|
+
ace-lint path/to/file.md path/to/other.yml
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Lint with glob pattern:**
|
|
55
|
+
```bash
|
|
56
|
+
ace-lint "**/*.md"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Lint changed files only:**
|
|
60
|
+
```bash
|
|
61
|
+
git diff --name-only --diff-filter=AM | grep -E '\.(md|ya?ml)$' | xargs ace-lint
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
4. **Handle results**:
|
|
65
|
+
- **Exit code 0**: All files pass - report success
|
|
66
|
+
- **Exit code 1**: Errors found - analyze and fix or generate report
|
|
67
|
+
- **Exit code 2**: Fatal error - investigate and report
|
|
68
|
+
|
|
69
|
+
5. **If errors found and --fix requested**:
|
|
70
|
+
- Analyze each error type
|
|
71
|
+
- Apply safe autofixes where possible
|
|
72
|
+
- Re-run lint to verify fixes
|
|
73
|
+
- Report remaining manual-fix issues
|
|
74
|
+
|
|
75
|
+
6. **If --report requested**, generate JSON report:
|
|
76
|
+
```bash
|
|
77
|
+
# Create report directory if needed
|
|
78
|
+
mkdir -p .ace-lint/reports
|
|
79
|
+
|
|
80
|
+
# Generate timestamped report
|
|
81
|
+
REPORT_FILE=".ace-lint/reports/lint-$(date +%Y%m%d-%H%M%S).json"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Report structure:
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"timestamp": "2026-01-08T16:30:00Z",
|
|
88
|
+
"files_checked": 42,
|
|
89
|
+
"errors": [
|
|
90
|
+
{
|
|
91
|
+
"file": "path/to/file.md",
|
|
92
|
+
"line": 10,
|
|
93
|
+
"severity": "error",
|
|
94
|
+
"rule": "frontmatter-required",
|
|
95
|
+
"message": "Missing required frontmatter field: doc-type",
|
|
96
|
+
"fix_proposal": "Add 'doc-type: workflow' to frontmatter"
|
|
97
|
+
}
|
|
98
|
+
],
|
|
99
|
+
"summary": {
|
|
100
|
+
"total_errors": 5,
|
|
101
|
+
"by_severity": {"error": 3, "warning": 2},
|
|
102
|
+
"by_rule": {"frontmatter-required": 2, "yaml-syntax": 3}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Options Reference
|
|
108
|
+
|
|
109
|
+
ace-lint CLI options:
|
|
110
|
+
- `--quiet`: Suppress detailed output
|
|
111
|
+
- `--version`: Show version
|
|
112
|
+
- File types auto-detected from extensions
|
|
113
|
+
|
|
114
|
+
## Common Error Patterns
|
|
115
|
+
|
|
116
|
+
### Markdown Issues
|
|
117
|
+
- Missing frontmatter → Add required YAML block
|
|
118
|
+
- Invalid frontmatter syntax → Fix YAML structure
|
|
119
|
+
- Broken internal links → Update path references
|
|
120
|
+
|
|
121
|
+
### YAML Issues
|
|
122
|
+
- Indentation errors → Fix spacing (2 spaces)
|
|
123
|
+
- Missing quotes → Add quotes around special characters
|
|
124
|
+
- Invalid syntax → Check colons, dashes, brackets
|
|
125
|
+
|
|
126
|
+
### Frontmatter Issues
|
|
127
|
+
- Missing required fields → Add doc-type, purpose, etc.
|
|
128
|
+
- Invalid date format → Use YYYY-MM-DD
|
|
129
|
+
- Type mismatches → Ensure correct value types
|
|
130
|
+
|
|
131
|
+
## Success Criteria
|
|
132
|
+
|
|
133
|
+
- All specified files linted
|
|
134
|
+
- Errors clearly reported with file:line format
|
|
135
|
+
- Autofixes applied safely (if requested)
|
|
136
|
+
- JSON report generated (if requested)
|
|
137
|
+
- Clear summary of remaining issues
|
|
138
|
+
|
|
139
|
+
## Response Template
|
|
140
|
+
|
|
141
|
+
**Files Linted:** [count] files
|
|
142
|
+
**Result:** ✓ All pass | ✗ [N] errors found
|
|
143
|
+
**Autofixes Applied:** [count] (if --fix)
|
|
144
|
+
**Report Generated:** [path] (if --report)
|
|
145
|
+
**Manual Fixes Needed:** [list of issues requiring human intervention]
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ace
|
|
4
|
+
module Lint
|
|
5
|
+
module Atoms
|
|
6
|
+
# Validates allowed-tools entries against known tools list
|
|
7
|
+
# Handles both simple tool names and Bash(prefix:*) patterns
|
|
8
|
+
class AllowedToolsValidator
|
|
9
|
+
# Pattern to match Bash(prefix:*) format
|
|
10
|
+
# e.g., "Bash(ace-git:*)", "Bash(npm:*)"
|
|
11
|
+
BASH_PATTERN_REGEX = /\ABash\(([^:]+):\*\)\z/
|
|
12
|
+
|
|
13
|
+
class << self
|
|
14
|
+
# Validate allowed-tools array
|
|
15
|
+
# @param tools [Array<String>, String] Tool entries to validate
|
|
16
|
+
# @param known_tools [Array<String>] List of known tool names
|
|
17
|
+
# @param known_bash_prefixes [Array<String>] List of known Bash command prefixes
|
|
18
|
+
# @return [Array<Hash>] List of validation errors with :tool and :message
|
|
19
|
+
def validate(tools, known_tools:, known_bash_prefixes:)
|
|
20
|
+
errors = []
|
|
21
|
+
|
|
22
|
+
# Handle string format (comma-separated)
|
|
23
|
+
tools_array = normalize_tools(tools)
|
|
24
|
+
|
|
25
|
+
tools_array.each do |tool|
|
|
26
|
+
tool = tool.to_s.strip
|
|
27
|
+
next if tool.empty?
|
|
28
|
+
|
|
29
|
+
error = validate_single_tool(tool, known_tools, known_bash_prefixes)
|
|
30
|
+
errors << error if error
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
errors
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
# Normalize tools to array format
|
|
39
|
+
# @param tools [Array, String, nil] Tools in various formats
|
|
40
|
+
# @return [Array<String>] Normalized array of tool names
|
|
41
|
+
def normalize_tools(tools)
|
|
42
|
+
case tools
|
|
43
|
+
when Array
|
|
44
|
+
tools.flatten
|
|
45
|
+
when String
|
|
46
|
+
# Handle comma-separated string format from workflow files
|
|
47
|
+
tools.split(",").map(&:strip)
|
|
48
|
+
when nil
|
|
49
|
+
[]
|
|
50
|
+
else
|
|
51
|
+
[tools.to_s]
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Validate a single tool entry
|
|
56
|
+
# @param tool [String] Tool name or Bash pattern
|
|
57
|
+
# @param known_tools [Array<String>] Known tool names
|
|
58
|
+
# @param known_bash_prefixes [Array<String>] Known Bash prefixes
|
|
59
|
+
# @return [Hash, nil] Error hash or nil if valid
|
|
60
|
+
def validate_single_tool(tool, known_tools, known_bash_prefixes)
|
|
61
|
+
# Check for Bash(prefix:*) pattern
|
|
62
|
+
if (match = tool.match(BASH_PATTERN_REGEX))
|
|
63
|
+
prefix = match[1]
|
|
64
|
+
return validate_bash_prefix(prefix, known_bash_prefixes)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Check for simple tool name
|
|
68
|
+
validate_tool_name(tool, known_tools)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Validate a Bash prefix
|
|
72
|
+
# @param prefix [String] The Bash command prefix
|
|
73
|
+
# @param known_prefixes [Array<String>] Known prefixes
|
|
74
|
+
# @return [Hash, nil] Error hash or nil if valid
|
|
75
|
+
def validate_bash_prefix(prefix, known_prefixes)
|
|
76
|
+
return nil if known_prefixes.include?(prefix)
|
|
77
|
+
|
|
78
|
+
{
|
|
79
|
+
tool: "Bash(#{prefix}:*)",
|
|
80
|
+
message: "Unknown Bash prefix '#{prefix}'. Known prefixes: #{known_prefixes.first(5).join(", ")}... (#{known_prefixes.size} total)"
|
|
81
|
+
}
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Validate a simple tool name
|
|
85
|
+
# @param tool [String] Tool name
|
|
86
|
+
# @param known_tools [Array<String>] Known tools
|
|
87
|
+
# @return [Hash, nil] Error hash or nil if valid
|
|
88
|
+
def validate_tool_name(tool, known_tools)
|
|
89
|
+
return nil if known_tools.include?(tool)
|
|
90
|
+
|
|
91
|
+
{
|
|
92
|
+
tool: tool,
|
|
93
|
+
message: "Unknown tool '#{tool}'. Known tools: #{known_tools.first(5).join(", ")}... (#{known_tools.size} total)"
|
|
94
|
+
}
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|