@harness-engineering/cli 1.4.0 → 1.6.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.
- package/dist/agents/personas/architecture-enforcer.yaml +1 -0
- package/dist/agents/personas/code-reviewer.yaml +43 -0
- package/dist/agents/personas/codebase-health-analyst.yaml +32 -0
- package/dist/agents/personas/documentation-maintainer.yaml +2 -0
- package/dist/agents/personas/entropy-cleaner.yaml +3 -0
- package/dist/agents/personas/graph-maintainer.yaml +27 -0
- package/dist/agents/personas/parallel-coordinator.yaml +29 -0
- package/dist/agents/personas/performance-guardian.yaml +26 -0
- package/dist/agents/personas/security-reviewer.yaml +35 -0
- package/dist/agents/personas/task-executor.yaml +41 -0
- package/dist/agents/skills/README.md +8 -0
- package/dist/agents/skills/claude-code/add-harness-component/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/align-documentation/SKILL.md +19 -0
- package/dist/agents/skills/claude-code/cleanup-dead-code/SKILL.md +19 -0
- package/dist/agents/skills/claude-code/detect-doc-drift/SKILL.md +8 -0
- package/dist/agents/skills/claude-code/enforce-architecture/SKILL.md +9 -0
- package/dist/agents/skills/claude-code/harness-architecture-advisor/SKILL.md +9 -0
- package/dist/agents/skills/claude-code/harness-autopilot/SKILL.md +494 -0
- package/dist/agents/skills/claude-code/harness-autopilot/skill.yaml +52 -0
- package/dist/agents/skills/claude-code/harness-code-review/SKILL.md +25 -0
- package/dist/agents/skills/claude-code/harness-debugging/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-dependency-health/SKILL.md +150 -0
- package/dist/agents/skills/claude-code/harness-dependency-health/skill.yaml +41 -0
- package/dist/agents/skills/claude-code/harness-execution/SKILL.md +19 -0
- package/dist/agents/skills/claude-code/harness-hotspot-detector/SKILL.md +135 -0
- package/dist/agents/skills/claude-code/harness-hotspot-detector/skill.yaml +44 -0
- package/dist/agents/skills/claude-code/harness-impact-analysis/SKILL.md +139 -0
- package/dist/agents/skills/claude-code/harness-impact-analysis/skill.yaml +44 -0
- package/dist/agents/skills/claude-code/harness-integrity/SKILL.md +20 -6
- package/dist/agents/skills/claude-code/harness-knowledge-mapper/SKILL.md +154 -0
- package/dist/agents/skills/claude-code/harness-knowledge-mapper/skill.yaml +49 -0
- package/dist/agents/skills/claude-code/harness-onboarding/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-parallel-agents/SKILL.md +9 -0
- package/dist/agents/skills/claude-code/harness-perf/SKILL.md +231 -0
- package/dist/agents/skills/claude-code/harness-perf/skill.yaml +47 -0
- package/dist/agents/skills/claude-code/harness-perf-tdd/SKILL.md +236 -0
- package/dist/agents/skills/claude-code/harness-perf-tdd/skill.yaml +47 -0
- package/dist/agents/skills/claude-code/harness-planning/SKILL.md +9 -0
- package/dist/agents/skills/claude-code/harness-pre-commit-review/SKILL.md +33 -2
- package/dist/agents/skills/claude-code/harness-refactoring/SKILL.md +19 -0
- package/dist/agents/skills/claude-code/harness-release-readiness/SKILL.md +657 -0
- package/dist/agents/skills/claude-code/harness-release-readiness/skill.yaml +57 -0
- package/dist/agents/skills/claude-code/harness-security-review/SKILL.md +206 -0
- package/dist/agents/skills/claude-code/harness-security-review/skill.yaml +50 -0
- package/dist/agents/skills/claude-code/harness-security-scan/SKILL.md +102 -0
- package/dist/agents/skills/claude-code/harness-security-scan/skill.yaml +41 -0
- package/dist/agents/skills/claude-code/harness-state-management/SKILL.md +22 -8
- package/dist/agents/skills/claude-code/harness-tdd/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/harness-test-advisor/SKILL.md +131 -0
- package/dist/agents/skills/claude-code/harness-test-advisor/skill.yaml +44 -0
- package/dist/agents/skills/claude-code/initialize-harness-project/SKILL.md +10 -0
- package/dist/agents/skills/claude-code/validate-context-engineering/SKILL.md +9 -0
- package/dist/agents/skills/gemini-cli/harness-autopilot/SKILL.md +494 -0
- package/dist/agents/skills/gemini-cli/harness-autopilot/skill.yaml +52 -0
- package/dist/agents/skills/gemini-cli/harness-dependency-health/SKILL.md +150 -0
- package/dist/agents/skills/gemini-cli/harness-dependency-health/skill.yaml +41 -0
- package/dist/agents/skills/gemini-cli/harness-hotspot-detector/SKILL.md +135 -0
- package/dist/agents/skills/gemini-cli/harness-hotspot-detector/skill.yaml +44 -0
- package/dist/agents/skills/gemini-cli/harness-impact-analysis/SKILL.md +139 -0
- package/dist/agents/skills/gemini-cli/harness-impact-analysis/skill.yaml +44 -0
- package/dist/agents/skills/gemini-cli/harness-knowledge-mapper/SKILL.md +154 -0
- package/dist/agents/skills/gemini-cli/harness-knowledge-mapper/skill.yaml +49 -0
- package/dist/agents/skills/gemini-cli/harness-perf/SKILL.md +231 -0
- package/dist/agents/skills/gemini-cli/harness-perf/skill.yaml +47 -0
- package/dist/agents/skills/gemini-cli/harness-perf-tdd/SKILL.md +236 -0
- package/dist/agents/skills/gemini-cli/harness-perf-tdd/skill.yaml +47 -0
- package/dist/agents/skills/gemini-cli/harness-release-readiness/SKILL.md +657 -0
- package/dist/agents/skills/gemini-cli/harness-release-readiness/skill.yaml +57 -0
- package/dist/agents/skills/gemini-cli/harness-security-review/skill.yaml +50 -0
- package/dist/agents/skills/gemini-cli/harness-security-scan/SKILL.md +102 -0
- package/dist/agents/skills/gemini-cli/harness-security-scan/skill.yaml +41 -0
- package/dist/agents/skills/gemini-cli/harness-test-advisor/SKILL.md +131 -0
- package/dist/agents/skills/gemini-cli/harness-test-advisor/skill.yaml +44 -0
- package/dist/agents/skills/tests/platform-parity.test.ts +131 -0
- package/dist/agents/skills/tests/schema.ts +2 -0
- package/dist/bin/harness.js +2 -2
- package/dist/{chunk-EFZOLZFB.js → chunk-ACMDUQJG.js} +4 -2
- package/dist/{chunk-C3J2HW4Y.js → chunk-O6NEKDYP.js} +2002 -487
- package/dist/{create-skill-4GKJZB5R.js → create-skill-NZDLMMR6.js} +1 -1
- package/dist/index.d.ts +265 -143
- package/dist/index.js +30 -4
- package/package.json +3 -2
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
name: harness-release-readiness
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
description: Audit npm release readiness, run maintenance checks, offer auto-fixes, track progress across sessions
|
|
4
|
+
cognitive_mode: meticulous-verifier
|
|
5
|
+
triggers:
|
|
6
|
+
- manual
|
|
7
|
+
- on_milestone
|
|
8
|
+
platforms:
|
|
9
|
+
- claude-code
|
|
10
|
+
- gemini-cli
|
|
11
|
+
tools:
|
|
12
|
+
- Bash
|
|
13
|
+
- Read
|
|
14
|
+
- Write
|
|
15
|
+
- Edit
|
|
16
|
+
- Glob
|
|
17
|
+
- Grep
|
|
18
|
+
cli:
|
|
19
|
+
command: harness skill run harness-release-readiness
|
|
20
|
+
args:
|
|
21
|
+
- name: path
|
|
22
|
+
description: Project root path
|
|
23
|
+
required: false
|
|
24
|
+
- name: comprehensive
|
|
25
|
+
description: Run comprehensive checks (API docs, examples, dep health, git hygiene)
|
|
26
|
+
type: boolean
|
|
27
|
+
required: false
|
|
28
|
+
mcp:
|
|
29
|
+
tool: run_skill
|
|
30
|
+
input:
|
|
31
|
+
skill: harness-release-readiness
|
|
32
|
+
path: string
|
|
33
|
+
type: rigid
|
|
34
|
+
phases:
|
|
35
|
+
- name: audit
|
|
36
|
+
description: Run release-specific checks (packaging, docs, repo hygiene, CI/CD)
|
|
37
|
+
required: true
|
|
38
|
+
- name: maintain
|
|
39
|
+
description: Dispatch maintenance skills in parallel and collect results
|
|
40
|
+
required: true
|
|
41
|
+
- name: fix
|
|
42
|
+
description: Offer auto-remediation for fixable findings
|
|
43
|
+
required: true
|
|
44
|
+
- name: report
|
|
45
|
+
description: Generate report and persist state for session resumption
|
|
46
|
+
required: true
|
|
47
|
+
state:
|
|
48
|
+
persistent: true
|
|
49
|
+
files:
|
|
50
|
+
- .harness/release-readiness.json
|
|
51
|
+
depends_on:
|
|
52
|
+
- detect-doc-drift
|
|
53
|
+
- cleanup-dead-code
|
|
54
|
+
- align-documentation
|
|
55
|
+
- enforce-architecture
|
|
56
|
+
- harness-diagnostics
|
|
57
|
+
- harness-parallel-agents
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: harness-security-review
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
description: Deep security audit with OWASP baseline and stack-adaptive analysis
|
|
4
|
+
cognitive_mode: meticulous-implementer
|
|
5
|
+
triggers:
|
|
6
|
+
- manual
|
|
7
|
+
- on_pr
|
|
8
|
+
platforms:
|
|
9
|
+
- claude-code
|
|
10
|
+
- gemini-cli
|
|
11
|
+
tools:
|
|
12
|
+
- Bash
|
|
13
|
+
- Read
|
|
14
|
+
- Write
|
|
15
|
+
- Edit
|
|
16
|
+
- Glob
|
|
17
|
+
- Grep
|
|
18
|
+
cli:
|
|
19
|
+
command: harness skill run harness-security-review
|
|
20
|
+
args:
|
|
21
|
+
- name: path
|
|
22
|
+
description: Project root path
|
|
23
|
+
required: false
|
|
24
|
+
- name: deep
|
|
25
|
+
description: Enable threat modeling phase
|
|
26
|
+
required: false
|
|
27
|
+
mcp:
|
|
28
|
+
tool: run_skill
|
|
29
|
+
input:
|
|
30
|
+
skill: harness-security-review
|
|
31
|
+
path: string
|
|
32
|
+
type: rigid
|
|
33
|
+
phases:
|
|
34
|
+
- name: scan
|
|
35
|
+
description: Run mechanical security scanner
|
|
36
|
+
required: true
|
|
37
|
+
- name: review
|
|
38
|
+
description: AI-powered security review (OWASP + stack-adaptive)
|
|
39
|
+
required: true
|
|
40
|
+
- name: threat-model
|
|
41
|
+
description: Lightweight threat model from codebase graph
|
|
42
|
+
required: false
|
|
43
|
+
- name: report
|
|
44
|
+
description: Generate findings report with remediation guidance
|
|
45
|
+
required: true
|
|
46
|
+
state:
|
|
47
|
+
persistent: false
|
|
48
|
+
files: []
|
|
49
|
+
depends_on:
|
|
50
|
+
- harness-code-review
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Harness Security Scan
|
|
2
|
+
|
|
3
|
+
> Lightweight mechanical security scan. Fast triage, not deep review.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
- As part of the codebase-health-analyst sweep
|
|
8
|
+
- For quick security triage on a project or changed files
|
|
9
|
+
- On scheduled cron runs for continuous security coverage
|
|
10
|
+
- NOT for deep security review (use harness-security-review)
|
|
11
|
+
- NOT for threat modeling (use harness-security-review --deep)
|
|
12
|
+
|
|
13
|
+
## Process
|
|
14
|
+
|
|
15
|
+
### Phase 1: SCAN — Run Mechanical Scanner
|
|
16
|
+
|
|
17
|
+
1. **Resolve project root.** Use provided path or cwd.
|
|
18
|
+
|
|
19
|
+
2. **Load security config.** Read `harness.config.json` and extract `security`
|
|
20
|
+
section. Fall back to defaults if absent.
|
|
21
|
+
|
|
22
|
+
3. **Determine file scope.**
|
|
23
|
+
- If `--changed-only` or triggered by PR: run `git diff --name-only HEAD~1`
|
|
24
|
+
to get changed files. Filter to source files only (exclude node_modules,
|
|
25
|
+
dist, test files per config).
|
|
26
|
+
- Otherwise: scan all source files in the project.
|
|
27
|
+
|
|
28
|
+
4. **Run SecurityScanner.** Call `SecurityScanner.scanFiles()` from
|
|
29
|
+
`@harness-engineering/core`.
|
|
30
|
+
|
|
31
|
+
5. **Filter by severity threshold.** Remove findings below the configured
|
|
32
|
+
threshold:
|
|
33
|
+
- `error`: only errors
|
|
34
|
+
- `warning`: errors and warnings (default)
|
|
35
|
+
- `info`: all findings
|
|
36
|
+
|
|
37
|
+
6. **Output report.** Present findings grouped by severity:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
Security Scan: [PASS/FAIL]
|
|
41
|
+
Scanned: N files, M rules applied
|
|
42
|
+
Errors: N | Warnings: N | Info: N
|
|
43
|
+
|
|
44
|
+
[List findings with rule ID, file:line, severity, message, remediation]
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Gates
|
|
48
|
+
|
|
49
|
+
- **Error-severity findings are blocking.** Report is FAIL if any error-severity
|
|
50
|
+
finding exists after filtering.
|
|
51
|
+
- **No AI review.** This skill is mechanical only. Do not perform OWASP analysis
|
|
52
|
+
or threat modeling.
|
|
53
|
+
|
|
54
|
+
## Harness Integration
|
|
55
|
+
|
|
56
|
+
- **`harness check-security`** — CLI command that invokes this skill's scanner.
|
|
57
|
+
- **`SecurityScanner`** — Core class from `@harness-engineering/core` that executes the rule engine.
|
|
58
|
+
- **`harness.config.json`** — Security section configures severity threshold and file exclusions.
|
|
59
|
+
- **codebase-health-analyst persona** — Invokes this skill as part of its sweep.
|
|
60
|
+
|
|
61
|
+
## Escalation
|
|
62
|
+
|
|
63
|
+
- **When error-severity findings are disputed:** The scanner is mechanical — it may flag false positives. If a finding is a false positive, add a `// harness-ignore SEC-XXX` comment on the line and document the rationale. Do not suppress without explanation.
|
|
64
|
+
- **When the scanner misses a known vulnerability:** This skill runs pattern-based rules only. For semantic analysis (taint tracking, control flow), use `/harness:security-review` instead.
|
|
65
|
+
- **When scan is too slow on large codebases:** Use `--changed-only` to scope to recently changed files. Full scans can run on a scheduled cron instead.
|
|
66
|
+
|
|
67
|
+
## Success Criteria
|
|
68
|
+
|
|
69
|
+
- Scanner ran and produced findings (or confirmed clean)
|
|
70
|
+
- Findings are filtered by the configured severity threshold
|
|
71
|
+
- Report follows the structured format
|
|
72
|
+
- Exit code reflects pass/fail status
|
|
73
|
+
|
|
74
|
+
## Examples
|
|
75
|
+
|
|
76
|
+
### Example: Clean Scan
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
Security Scan: PASS
|
|
80
|
+
Scanned: 42 files, 12 rules applied
|
|
81
|
+
Errors: 0 | Warnings: 0 | Info: 0
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Example: Findings Detected
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
Security Scan: FAIL
|
|
88
|
+
Scanned: 42 files, 12 rules applied
|
|
89
|
+
Errors: 1 | Warnings: 2 | Info: 0
|
|
90
|
+
|
|
91
|
+
[SEC-SECRET-001] src/config.ts:15 (error)
|
|
92
|
+
Hardcoded API key detected: `const API_KEY = "sk-..."`
|
|
93
|
+
Remediation: Move to environment variable, use dotenv or secrets manager.
|
|
94
|
+
|
|
95
|
+
[SEC-NET-001] src/cors.ts:5 (warning)
|
|
96
|
+
CORS wildcard origin: `origin: "*"`
|
|
97
|
+
Remediation: Restrict to specific allowed origins.
|
|
98
|
+
|
|
99
|
+
[SEC-CRYPTO-001] src/auth.ts:22 (warning)
|
|
100
|
+
Weak hash algorithm: `crypto.createHash("md5")`
|
|
101
|
+
Remediation: Use SHA-256 or stronger.
|
|
102
|
+
```
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: harness-security-scan
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
description: Lightweight mechanical security scan for health checks
|
|
4
|
+
cognitive_mode: meticulous-implementer
|
|
5
|
+
triggers:
|
|
6
|
+
- manual
|
|
7
|
+
- scheduled
|
|
8
|
+
platforms:
|
|
9
|
+
- claude-code
|
|
10
|
+
- gemini-cli
|
|
11
|
+
tools:
|
|
12
|
+
- Bash
|
|
13
|
+
- Read
|
|
14
|
+
- Glob
|
|
15
|
+
- Grep
|
|
16
|
+
cli:
|
|
17
|
+
command: harness skill run harness-security-scan
|
|
18
|
+
args:
|
|
19
|
+
- name: path
|
|
20
|
+
description: Project root path
|
|
21
|
+
required: false
|
|
22
|
+
- name: severity
|
|
23
|
+
description: Minimum severity threshold (error, warning, info)
|
|
24
|
+
required: false
|
|
25
|
+
- name: changed-only
|
|
26
|
+
description: Only scan git-changed files
|
|
27
|
+
required: false
|
|
28
|
+
mcp:
|
|
29
|
+
tool: run_skill
|
|
30
|
+
input:
|
|
31
|
+
skill: harness-security-scan
|
|
32
|
+
path: string
|
|
33
|
+
type: rigid
|
|
34
|
+
phases:
|
|
35
|
+
- name: scan
|
|
36
|
+
description: Run SecurityScanner and filter by severity threshold
|
|
37
|
+
required: true
|
|
38
|
+
state:
|
|
39
|
+
persistent: false
|
|
40
|
+
files: []
|
|
41
|
+
depends_on: []
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Harness Test Advisor
|
|
2
|
+
|
|
3
|
+
> Graph-based test selection. Answers: "I changed these files — what tests should I run?"
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
- Before pushing code — run only the tests that matter
|
|
8
|
+
- In CI — optimize test suite execution order
|
|
9
|
+
- When a test fails — understand which changes could have caused it
|
|
10
|
+
- When `on_pr` triggers fire
|
|
11
|
+
- NOT for writing tests (use harness-tdd)
|
|
12
|
+
- NOT for test quality analysis (out of scope)
|
|
13
|
+
|
|
14
|
+
## Prerequisites
|
|
15
|
+
|
|
16
|
+
A knowledge graph must exist at `.harness/graph/`. Run `harness scan` if no graph is available.
|
|
17
|
+
If the graph exists but code has changed since the last scan, re-run `harness scan` first — stale graph data leads to inaccurate results.
|
|
18
|
+
|
|
19
|
+
## Process
|
|
20
|
+
|
|
21
|
+
### Phase 1: PARSE — Identify Changed Files
|
|
22
|
+
|
|
23
|
+
1. **From diff**: Parse `git diff --name-only` to get changed file paths.
|
|
24
|
+
2. **From input**: Accept comma-separated file paths.
|
|
25
|
+
3. **Filter**: Only consider `.ts`, `.tsx`, `.js`, `.jsx` files (skip docs, config).
|
|
26
|
+
|
|
27
|
+
### Phase 2: DISCOVER — Find Related Tests via Graph
|
|
28
|
+
|
|
29
|
+
For each changed file, use graph traversal to find test files:
|
|
30
|
+
|
|
31
|
+
1. **Direct test coverage**: Use `get_impact` to find test files that import the changed file.
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
get_impact(filePath="src/services/auth.ts")
|
|
35
|
+
→ tests: ["tests/services/auth.test.ts", "tests/integration/auth-flow.test.ts"]
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
2. **Transitive test coverage**: Use `query_graph` with depth 2 to find tests that import files that import the changed file.
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
query_graph(rootNodeIds=["file:src/services/auth.ts"], maxDepth=2, includeEdges=["imports"], bidirectional=true)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
3. **Co-change tests**: Check `co_changes_with` edges for test files that historically change alongside the modified files.
|
|
45
|
+
|
|
46
|
+
### Phase 3: PRIORITIZE — Rank and Generate Commands
|
|
47
|
+
|
|
48
|
+
Organize tests into three tiers:
|
|
49
|
+
|
|
50
|
+
**Tier 1 — Must Run** (direct coverage):
|
|
51
|
+
Tests that directly import or test the changed files. These are most likely to catch regressions.
|
|
52
|
+
|
|
53
|
+
**Tier 2 — Should Run** (transitive coverage):
|
|
54
|
+
Tests that cover code one hop away from the changed files. These catch indirect breakage.
|
|
55
|
+
|
|
56
|
+
**Tier 3 — Could Run** (related):
|
|
57
|
+
Tests in the same module or that co-change with the modified files. Lower probability of failure but worth running if time permits.
|
|
58
|
+
|
|
59
|
+
### Output
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
## Test Advisor Report
|
|
63
|
+
|
|
64
|
+
### Changed Files
|
|
65
|
+
- src/services/auth.ts (modified)
|
|
66
|
+
- src/types/user.ts (modified)
|
|
67
|
+
|
|
68
|
+
### Tier 1 — Must Run (direct coverage)
|
|
69
|
+
1. tests/services/auth.test.ts — imports auth.ts
|
|
70
|
+
2. tests/types/user.test.ts — imports user.ts
|
|
71
|
+
|
|
72
|
+
### Tier 2 — Should Run (transitive)
|
|
73
|
+
3. tests/routes/login.test.ts — imports routes/login.ts → imports auth.ts
|
|
74
|
+
4. tests/middleware/verify.test.ts — imports middleware/verify.ts → imports auth.ts
|
|
75
|
+
|
|
76
|
+
### Tier 3 — Could Run (related)
|
|
77
|
+
5. tests/integration/auth-flow.test.ts — same module, co-changes with auth.ts
|
|
78
|
+
|
|
79
|
+
### Quick Run Command
|
|
80
|
+
npx vitest run tests/services/auth.test.ts tests/types/user.test.ts tests/routes/login.test.ts tests/middleware/verify.test.ts
|
|
81
|
+
|
|
82
|
+
### Full Run Command (all tiers)
|
|
83
|
+
npx vitest run tests/services/auth.test.ts tests/types/user.test.ts tests/routes/login.test.ts tests/middleware/verify.test.ts tests/integration/auth-flow.test.ts
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Harness Integration
|
|
87
|
+
|
|
88
|
+
- **`harness scan`** — Must run before this skill to ensure graph is current.
|
|
89
|
+
- **`harness validate`** — Run after acting on findings to verify project health.
|
|
90
|
+
- **Graph tools** — This skill uses `query_graph`, `get_impact`, and `get_relationships` MCP tools.
|
|
91
|
+
|
|
92
|
+
## Success Criteria
|
|
93
|
+
|
|
94
|
+
- Tests prioritized into 3 tiers (Must Run, Should Run, Could Run)
|
|
95
|
+
- Executable run commands generated for quick and full test runs
|
|
96
|
+
- Coverage gaps flagged for changed files with no test coverage
|
|
97
|
+
- Report follows the structured output format
|
|
98
|
+
- All findings are backed by graph query evidence, not heuristics
|
|
99
|
+
|
|
100
|
+
## Examples
|
|
101
|
+
|
|
102
|
+
### Example: Selecting Tests for a Services Change
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
Input: git diff shows src/services/auth.ts and src/types/user.ts modified
|
|
106
|
+
|
|
107
|
+
1. PARSE — 2 changed files identified (both .ts)
|
|
108
|
+
2. DISCOVER — get_impact(filePath="src/services/auth.ts")
|
|
109
|
+
query_graph with depth 2 for transitive tests
|
|
110
|
+
Tier 1: auth.test.ts, user.test.ts (direct imports)
|
|
111
|
+
Tier 2: login.test.ts, verify.test.ts (one hop away)
|
|
112
|
+
Tier 3: auth-flow.test.ts (co-change history)
|
|
113
|
+
3. PRIORITIZE — 5 tests across 3 tiers
|
|
114
|
+
|
|
115
|
+
Output:
|
|
116
|
+
Tier 1 (must run): 2 tests
|
|
117
|
+
Tier 2 (should run): 2 tests
|
|
118
|
+
Tier 3 (could run): 1 test
|
|
119
|
+
Quick command: npx vitest run auth.test.ts user.test.ts login.test.ts verify.test.ts
|
|
120
|
+
Coverage gaps: none
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Gates
|
|
124
|
+
|
|
125
|
+
- **No advice without graph.** If no graph exists, fall back to: "Run all tests in the same directory as changed files."
|
|
126
|
+
- **Always include Tier 1.** Direct test coverage is non-negotiable — always recommend running these.
|
|
127
|
+
|
|
128
|
+
## Escalation
|
|
129
|
+
|
|
130
|
+
- **When changed file has no test coverage**: Flag as a gap: "No tests found for src/services/auth.ts — consider adding tests before merging."
|
|
131
|
+
- **When Tier 1 has >20 tests**: The changed file may be a hub. Suggest running Tier 1 in parallel or splitting the file.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
name: harness-test-advisor
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
description: Graph-based test selection — answers "what tests should I run?"
|
|
4
|
+
cognitive_mode: advisory-guide
|
|
5
|
+
triggers:
|
|
6
|
+
- manual
|
|
7
|
+
- on_pr
|
|
8
|
+
platforms:
|
|
9
|
+
- claude-code
|
|
10
|
+
- gemini-cli
|
|
11
|
+
tools:
|
|
12
|
+
- Bash
|
|
13
|
+
- Read
|
|
14
|
+
- Glob
|
|
15
|
+
- Grep
|
|
16
|
+
cli:
|
|
17
|
+
command: harness skill run harness-test-advisor
|
|
18
|
+
args:
|
|
19
|
+
- name: path
|
|
20
|
+
description: Project root path
|
|
21
|
+
required: false
|
|
22
|
+
- name: files
|
|
23
|
+
description: Comma-separated list of changed files
|
|
24
|
+
required: false
|
|
25
|
+
mcp:
|
|
26
|
+
tool: run_skill
|
|
27
|
+
input:
|
|
28
|
+
skill: harness-test-advisor
|
|
29
|
+
path: string
|
|
30
|
+
type: flexible
|
|
31
|
+
phases:
|
|
32
|
+
- name: parse
|
|
33
|
+
description: Identify changed files from diff or input
|
|
34
|
+
required: true
|
|
35
|
+
- name: discover
|
|
36
|
+
description: Find related tests via graph traversal
|
|
37
|
+
required: true
|
|
38
|
+
- name: prioritize
|
|
39
|
+
description: Rank tests by relevance and generate commands
|
|
40
|
+
required: true
|
|
41
|
+
state:
|
|
42
|
+
persistent: false
|
|
43
|
+
files: []
|
|
44
|
+
depends_on: []
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// agents/skills/tests/platform-parity.test.ts
|
|
2
|
+
//
|
|
3
|
+
// Ensures all AI platform variations (claude-code, gemini-cli) of skills
|
|
4
|
+
// exist and are in sync. Every skill must be present in every platform
|
|
5
|
+
// directory with identical SKILL.md and skill.yaml files.
|
|
6
|
+
|
|
7
|
+
import { describe, it, expect } from 'vitest';
|
|
8
|
+
import { glob } from 'glob';
|
|
9
|
+
import { readFileSync, existsSync } from 'fs';
|
|
10
|
+
import { resolve, dirname } from 'path';
|
|
11
|
+
import { fileURLToPath } from 'url';
|
|
12
|
+
import { ALLOWED_PLATFORMS } from './schema';
|
|
13
|
+
|
|
14
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const SKILLS_DIR = resolve(__dirname, '..');
|
|
16
|
+
|
|
17
|
+
// Discover all platform directories
|
|
18
|
+
const platforms = ALLOWED_PLATFORMS.filter((p) => existsSync(resolve(SKILLS_DIR, p)));
|
|
19
|
+
|
|
20
|
+
// Files that must exist and be identical in every platform
|
|
21
|
+
const SKILL_FILES = ['SKILL.md', 'skill.yaml'];
|
|
22
|
+
|
|
23
|
+
// Collect all skill names across all platforms
|
|
24
|
+
function getAllSkillNames(): Map<string, Set<string>> {
|
|
25
|
+
const skillsByPlatform = new Map<string, Set<string>>();
|
|
26
|
+
|
|
27
|
+
for (const platform of platforms) {
|
|
28
|
+
const dirs = glob.sync('*/', {
|
|
29
|
+
cwd: resolve(SKILLS_DIR, platform),
|
|
30
|
+
ignore: ['node_modules/'],
|
|
31
|
+
});
|
|
32
|
+
const names = new Set(
|
|
33
|
+
dirs
|
|
34
|
+
.map((d) => d.replace(/\/$/, ''))
|
|
35
|
+
.filter((name) => {
|
|
36
|
+
// Only include directories that have at least one skill file
|
|
37
|
+
return SKILL_FILES.some((f) => existsSync(resolve(SKILLS_DIR, platform, name, f)));
|
|
38
|
+
})
|
|
39
|
+
);
|
|
40
|
+
skillsByPlatform.set(platform, names);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return skillsByPlatform;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
describe('platform parity', () => {
|
|
47
|
+
if (platforms.length < 2) {
|
|
48
|
+
it.skip('fewer than 2 platform directories found', () => {});
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const skillsByPlatform = getAllSkillNames();
|
|
53
|
+
|
|
54
|
+
// Get the union of all skill names across platforms
|
|
55
|
+
const allSkillNames = new Set<string>();
|
|
56
|
+
for (const names of skillsByPlatform.values()) {
|
|
57
|
+
for (const name of names) {
|
|
58
|
+
allSkillNames.add(name);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (allSkillNames.size === 0) {
|
|
63
|
+
it.skip('no skills found in any platform', () => {});
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
describe('every skill exists in all platforms', () => {
|
|
68
|
+
const cases = Array.from(allSkillNames)
|
|
69
|
+
.sort()
|
|
70
|
+
.flatMap((skill) => platforms.map((platform) => ({ skill, platform })));
|
|
71
|
+
|
|
72
|
+
it.each(cases)('$skill exists in $platform', ({ skill, platform }) => {
|
|
73
|
+
const skillDir = resolve(SKILLS_DIR, platform, skill);
|
|
74
|
+
expect(
|
|
75
|
+
existsSync(skillDir),
|
|
76
|
+
`Skill "${skill}" is missing from platform "${platform}". ` +
|
|
77
|
+
`It exists in: ${platforms.filter((p) => skillsByPlatform.get(p)?.has(skill)).join(', ')}`
|
|
78
|
+
).toBe(true);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe('skill files are identical across platforms', () => {
|
|
83
|
+
// Use the first platform as the reference
|
|
84
|
+
const [referencePlatform, ...otherPlatforms] = platforms;
|
|
85
|
+
|
|
86
|
+
const cases = Array.from(allSkillNames)
|
|
87
|
+
.sort()
|
|
88
|
+
.flatMap((skill) =>
|
|
89
|
+
SKILL_FILES.flatMap((file) => otherPlatforms.map((platform) => ({ skill, file, platform })))
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
it.each(cases)(
|
|
93
|
+
'$skill/$file is identical in $platform vs ' + platforms[0],
|
|
94
|
+
({ skill, file, platform }) => {
|
|
95
|
+
const refPath = resolve(SKILLS_DIR, referencePlatform!, skill, file);
|
|
96
|
+
const otherPath = resolve(SKILLS_DIR, platform, skill, file);
|
|
97
|
+
|
|
98
|
+
if (!existsSync(refPath) || !existsSync(otherPath)) {
|
|
99
|
+
// Missing file is caught by the existence test above
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const refContent = readFileSync(refPath, 'utf-8');
|
|
104
|
+
const otherContent = readFileSync(otherPath, 'utf-8');
|
|
105
|
+
|
|
106
|
+
expect(
|
|
107
|
+
otherContent,
|
|
108
|
+
`${skill}/${file} differs between ${referencePlatform} and ${platform}. ` +
|
|
109
|
+
`Run: cp agents/skills/${referencePlatform}/${skill}/${file} agents/skills/${platform}/${skill}/${file}`
|
|
110
|
+
).toBe(refContent);
|
|
111
|
+
}
|
|
112
|
+
);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
describe('platform skill counts match', () => {
|
|
116
|
+
it('all platforms have the same number of skills', () => {
|
|
117
|
+
const counts = platforms.map((p) => ({
|
|
118
|
+
platform: p,
|
|
119
|
+
count: skillsByPlatform.get(p)?.size ?? 0,
|
|
120
|
+
}));
|
|
121
|
+
|
|
122
|
+
const first = counts[0]!;
|
|
123
|
+
for (const { platform, count } of counts.slice(1)) {
|
|
124
|
+
expect(
|
|
125
|
+
count,
|
|
126
|
+
`Platform "${platform}" has ${count} skills but "${first.platform}" has ${first.count}`
|
|
127
|
+
).toBe(first.count);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
});
|
package/dist/bin/harness.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
createProgram
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-O6NEKDYP.js";
|
|
5
5
|
import "../chunk-3U5VZYR7.js";
|
|
6
6
|
import {
|
|
7
7
|
handleError
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-ACMDUQJG.js";
|
|
9
9
|
|
|
10
10
|
// src/bin/harness.ts
|
|
11
11
|
async function main() {
|
|
@@ -37,7 +37,9 @@ var ALLOWED_TRIGGERS = [
|
|
|
37
37
|
"on_bug_fix",
|
|
38
38
|
"on_refactor",
|
|
39
39
|
"on_project_init",
|
|
40
|
-
"on_review"
|
|
40
|
+
"on_review",
|
|
41
|
+
"on_milestone",
|
|
42
|
+
"on_task_complete"
|
|
41
43
|
];
|
|
42
44
|
var ALLOWED_PLATFORMS = ["claude-code", "gemini-cli"];
|
|
43
45
|
var ALLOWED_COGNITIVE_MODES = [
|
|
@@ -115,7 +117,7 @@ function buildSkillYaml(opts) {
|
|
|
115
117
|
description: opts.description,
|
|
116
118
|
cognitive_mode: opts.cognitiveMode ?? "constructive-architect",
|
|
117
119
|
triggers: ["manual"],
|
|
118
|
-
platforms: ["claude-code"],
|
|
120
|
+
platforms: ["claude-code", "gemini-cli"],
|
|
119
121
|
tools: ["Read", "Grep", "Glob", "Edit", "Write", "Bash"],
|
|
120
122
|
type: "flexible",
|
|
121
123
|
state: {
|