@harness-engineering/cli 1.3.0 → 1.6.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.
- package/dist/agents/personas/architecture-enforcer.yaml +1 -0
- package/dist/agents/personas/code-reviewer.yaml +41 -0
- package/dist/agents/personas/codebase-health-analyst.yaml +27 -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/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-code-review/SKILL.md +10 -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-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-planning/SKILL.md +9 -0
- package/dist/agents/skills/claude-code/harness-pre-commit-review/SKILL.md +6 -0
- package/dist/agents/skills/claude-code/harness-refactoring/SKILL.md +19 -0
- 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-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-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-APYEWOCR.js → chunk-VS4OTOKZ.js} +1393 -350
- 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,139 @@
|
|
|
1
|
+
# Harness Impact Analysis
|
|
2
|
+
|
|
3
|
+
> Graph-based impact analysis. Answers: "if I change X, what breaks?"
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
- Before merging a PR — understand the blast radius of changes
|
|
8
|
+
- When planning a refactoring — know what will be affected
|
|
9
|
+
- When a test fails — trace backwards to find what change caused it
|
|
10
|
+
- When `on_pr` triggers fire
|
|
11
|
+
- NOT for understanding code (use harness-onboarding or harness-code-review)
|
|
12
|
+
- NOT for finding dead code (use cleanup-dead-code)
|
|
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: IDENTIFY — Determine Changed Files
|
|
22
|
+
|
|
23
|
+
1. **From diff**: If a git diff is available, parse it to extract changed file paths.
|
|
24
|
+
2. **From input**: If file paths are provided directly, use those.
|
|
25
|
+
3. **From git**: If neither, use `git diff --name-only HEAD~1` to get recent changes.
|
|
26
|
+
|
|
27
|
+
### Phase 2: ANALYZE — Query Graph for Impact
|
|
28
|
+
|
|
29
|
+
For each changed file:
|
|
30
|
+
|
|
31
|
+
1. **Direct dependents**: Use `get_impact` MCP tool to find all files that import or call the changed file.
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
get_impact(filePath="src/services/auth.ts")
|
|
35
|
+
→ tests: [auth.test.ts, integration.test.ts]
|
|
36
|
+
→ docs: [auth-guide.md]
|
|
37
|
+
→ code: [routes/login.ts, middleware/verify.ts, ...]
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
2. **Transitive dependents**: Use `query_graph` with depth 3 to find indirect consumers.
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
query_graph(rootNodeIds=["file:src/services/auth.ts"], maxDepth=3, includeEdges=["imports", "calls"])
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
3. **Documentation impact**: Use `get_relationships` to find `documents` edges pointing to changed nodes.
|
|
47
|
+
|
|
48
|
+
4. **Test coverage**: Identify test files connected via `imports` edges. Flag changed files with no test coverage.
|
|
49
|
+
|
|
50
|
+
### Phase 3: ASSESS — Risk Assessment and Report
|
|
51
|
+
|
|
52
|
+
1. **Impact score**: Calculate based on:
|
|
53
|
+
- Number of direct dependents (weight: 3x)
|
|
54
|
+
- Number of transitive dependents (weight: 1x)
|
|
55
|
+
- Whether affected code includes entry points (weight: 5x)
|
|
56
|
+
- Whether tests exist for the changed code (no tests = higher risk)
|
|
57
|
+
|
|
58
|
+
2. **Risk tiers**:
|
|
59
|
+
- **Critical** (score > 50): Changes affect entry points or >20 downstream files
|
|
60
|
+
- **High** (score 20-50): Changes affect multiple modules or shared utilities
|
|
61
|
+
- **Medium** (score 5-20): Changes affect a few files within the same module
|
|
62
|
+
- **Low** (score < 5): Changes are isolated with minimal downstream impact
|
|
63
|
+
|
|
64
|
+
3. **Output report**:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
## Impact Analysis Report
|
|
68
|
+
|
|
69
|
+
### Changed Files
|
|
70
|
+
- src/services/auth.ts (modified)
|
|
71
|
+
- src/types/user.ts (modified)
|
|
72
|
+
|
|
73
|
+
### Impact Summary
|
|
74
|
+
- Direct dependents: 8 files
|
|
75
|
+
- Transitive dependents: 23 files
|
|
76
|
+
- Affected tests: 5 files
|
|
77
|
+
- Affected docs: 2 files
|
|
78
|
+
- Risk tier: HIGH
|
|
79
|
+
|
|
80
|
+
### Affected Tests (must run)
|
|
81
|
+
1. tests/services/auth.test.ts (direct)
|
|
82
|
+
2. tests/routes/login.test.ts (transitive)
|
|
83
|
+
3. tests/integration/auth-flow.test.ts (transitive)
|
|
84
|
+
|
|
85
|
+
### Affected Documentation (may need update)
|
|
86
|
+
1. docs/auth-guide.md → documents src/services/auth.ts
|
|
87
|
+
2. docs/api-reference.md → documents src/types/user.ts
|
|
88
|
+
|
|
89
|
+
### Downstream Consumers
|
|
90
|
+
1. src/routes/login.ts — imports auth.ts
|
|
91
|
+
2. src/middleware/verify.ts — imports auth.ts
|
|
92
|
+
3. src/routes/signup.ts — imports user.ts (transitive via auth.ts)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Harness Integration
|
|
96
|
+
|
|
97
|
+
- **`harness scan`** — Must run before this skill to ensure graph is current.
|
|
98
|
+
- **`harness validate`** — Run after acting on findings to verify project health.
|
|
99
|
+
- **Graph tools** — This skill uses `query_graph`, `get_impact`, and `get_relationships` MCP tools.
|
|
100
|
+
|
|
101
|
+
## Success Criteria
|
|
102
|
+
|
|
103
|
+
- Impact report generated with a risk tier (Critical / High / Medium / Low)
|
|
104
|
+
- All affected test files listed with direct vs transitive classification
|
|
105
|
+
- All affected documentation files listed with relationship context
|
|
106
|
+
- Report follows the structured output format
|
|
107
|
+
- All findings are backed by graph query evidence, not heuristics
|
|
108
|
+
|
|
109
|
+
## Examples
|
|
110
|
+
|
|
111
|
+
### Example: Analyzing a Change to auth.ts
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
Input: git diff shows src/services/auth.ts modified
|
|
115
|
+
|
|
116
|
+
1. IDENTIFY — Extract changed file: src/services/auth.ts
|
|
117
|
+
2. ANALYZE — get_impact(filePath="src/services/auth.ts")
|
|
118
|
+
query_graph(rootNodeIds=["file:src/services/auth.ts"], maxDepth=3)
|
|
119
|
+
Results: 8 direct dependents, 23 transitive, 5 tests, 2 docs
|
|
120
|
+
3. ASSESS — Impact score: 34 (High tier)
|
|
121
|
+
- Entry points affected: no
|
|
122
|
+
- Tests exist: yes (5 files)
|
|
123
|
+
|
|
124
|
+
Output:
|
|
125
|
+
Risk tier: HIGH
|
|
126
|
+
Must-run tests: auth.test.ts, login.test.ts, auth-flow.test.ts
|
|
127
|
+
Docs to update: auth-guide.md, api-reference.md
|
|
128
|
+
Downstream consumers: 8 files across 3 modules
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Gates
|
|
132
|
+
|
|
133
|
+
- **No analysis without graph.** If no graph exists at `.harness/graph/`, stop and instruct the user to run `harness scan`.
|
|
134
|
+
- **No risk assessment without data.** Do not guess at impact — use graph queries. If graph data is incomplete, state what is missing.
|
|
135
|
+
|
|
136
|
+
## Escalation
|
|
137
|
+
|
|
138
|
+
- **When graph is stale**: If the graph's last scan timestamp is older than the most recent commit, warn that results may be incomplete and suggest re-scanning.
|
|
139
|
+
- **When impact is critical**: If risk tier is Critical, recommend a thorough code review and full test suite run before merging.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
name: harness-impact-analysis
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
description: Graph-based impact analysis — answers "if I change X, what breaks?"
|
|
4
|
+
cognitive_mode: analytical-reporter
|
|
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-impact-analysis
|
|
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-impact-analysis
|
|
29
|
+
path: string
|
|
30
|
+
type: rigid
|
|
31
|
+
phases:
|
|
32
|
+
- name: identify
|
|
33
|
+
description: Identify changed files from diff or input
|
|
34
|
+
required: true
|
|
35
|
+
- name: analyze
|
|
36
|
+
description: Query graph for impact of each changed file
|
|
37
|
+
required: true
|
|
38
|
+
- name: assess
|
|
39
|
+
description: Rank findings by risk and generate report
|
|
40
|
+
required: true
|
|
41
|
+
state:
|
|
42
|
+
persistent: false
|
|
43
|
+
files: []
|
|
44
|
+
depends_on: []
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Harness Knowledge Mapper
|
|
2
|
+
|
|
3
|
+
> Auto-generate always-current knowledge maps from graph topology. Never stale because it's computed, not authored.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
- When AGENTS.md is outdated or doesn't exist — generate it from the graph
|
|
8
|
+
- After major refactoring — regenerate the knowledge map to reflect new structure
|
|
9
|
+
- On scheduled basis — keep documentation aligned with code
|
|
10
|
+
- When `on_commit` to main triggers fire
|
|
11
|
+
- NOT for validating existing AGENTS.md (use validate-context-engineering)
|
|
12
|
+
- NOT for fixing documentation drift (use align-documentation)
|
|
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: SURVEY — Query Graph for Structure
|
|
22
|
+
|
|
23
|
+
1. **Module hierarchy**: Query for module nodes and their `contains` edges to file nodes.
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
query_graph(rootNodeIds=[all module nodes], includeTypes=["module", "file"], includeEdges=["contains"])
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
2. **Entry points**: Find file nodes with high out-degree but low in-degree (they initiate dependency chains).
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
search_similar(query="main entry point index")
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
3. **Layer structure**: Query for layer nodes if defined.
|
|
36
|
+
|
|
37
|
+
4. **Dependency flow**: For each module, trace outbound `imports` edges to other modules.
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
get_relationships(nodeId=<module>, direction="outbound", depth=1)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Phase 2: GENERATE — Build Knowledge Map
|
|
44
|
+
|
|
45
|
+
Generate markdown sections following AGENTS.md conventions:
|
|
46
|
+
|
|
47
|
+
1. **Repository Structure**: Module hierarchy with brief descriptions derived from file contents and function names.
|
|
48
|
+
|
|
49
|
+
2. **Key Entry Points**: Files identified as entry points with their purpose (inferred from exports and naming).
|
|
50
|
+
|
|
51
|
+
3. **Module Dependencies**: For each module, list what it depends on and what depends on it. Format as a dependency table.
|
|
52
|
+
|
|
53
|
+
4. **API Surface**: Public exports from each module, grouped by type (functions, classes, types).
|
|
54
|
+
|
|
55
|
+
5. **Patterns and Conventions**: Detected patterns from graph structure (e.g., "all services follow Repository pattern", "tests co-located with source").
|
|
56
|
+
|
|
57
|
+
### Phase 3: AUDIT — Identify Coverage Gaps
|
|
58
|
+
|
|
59
|
+
1. **Undocumented modules**: Use `check_docs` to find code nodes without `documents` edges.
|
|
60
|
+
|
|
61
|
+
2. **Missing descriptions**: Modules with no README or doc file.
|
|
62
|
+
|
|
63
|
+
3. **Stale references**: If an existing AGENTS.md exists, compare its file references against the graph to find mentions of files that no longer exist.
|
|
64
|
+
|
|
65
|
+
### Phase 4: OUTPUT — Write Knowledge Map
|
|
66
|
+
|
|
67
|
+
1. **Default**: Write to AGENTS.md in project root.
|
|
68
|
+
2. **Custom path**: Write to specified output path.
|
|
69
|
+
3. **Diff mode**: If AGENTS.md exists, show what changed rather than overwriting.
|
|
70
|
+
|
|
71
|
+
### Output
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
## Generated Knowledge Map
|
|
75
|
+
|
|
76
|
+
### Repository Structure
|
|
77
|
+
- **packages/core/** — Core library: context assembly, entropy detection, constraints, feedback
|
|
78
|
+
- src/context/ — Token budget, filtering, doc coverage, knowledge map validation
|
|
79
|
+
- src/entropy/ — Drift detection, dead code analysis, pattern violations
|
|
80
|
+
- src/constraints/ — Layer validation, circular dependency detection, boundaries
|
|
81
|
+
- src/feedback/ — Self-review, peer review, diff analysis
|
|
82
|
+
|
|
83
|
+
- **packages/graph/** — Knowledge graph: store, query, ingest, search
|
|
84
|
+
- src/store/ — LokiJS-backed graph store, vector store, serialization
|
|
85
|
+
- src/query/ — ContextQL traversal, projection
|
|
86
|
+
- src/ingest/ — Code, git, knowledge, connector ingestion
|
|
87
|
+
- src/search/ — FusionLayer hybrid search
|
|
88
|
+
|
|
89
|
+
### Entry Points
|
|
90
|
+
1. packages/core/src/index.ts — Core library barrel export
|
|
91
|
+
2. packages/graph/src/index.ts — Graph library barrel export
|
|
92
|
+
3. packages/cli/src/index.ts — CLI entry point (Commander.js)
|
|
93
|
+
4. packages/mcp-server/src/server.ts — MCP server registration
|
|
94
|
+
|
|
95
|
+
### Coverage Gaps
|
|
96
|
+
- 3 modules have no documentation
|
|
97
|
+
- 5 files have no test coverage
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Graph Refresh
|
|
101
|
+
|
|
102
|
+
After generating documentation, refresh the graph so new `documents` edges reflect the updated docs:
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
harness scan [path]
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
This ensures subsequent graph queries (impact analysis, drift detection) include the newly generated documentation.
|
|
109
|
+
|
|
110
|
+
## Harness Integration
|
|
111
|
+
|
|
112
|
+
- **`harness scan`** — Must run before this skill to ensure graph is current.
|
|
113
|
+
- **`harness validate`** — Run after acting on findings to verify project health.
|
|
114
|
+
- **Graph tools** — This skill uses `query_graph`, `get_relationships`, and `check_docs` MCP tools.
|
|
115
|
+
|
|
116
|
+
## Success Criteria
|
|
117
|
+
|
|
118
|
+
- Knowledge map generated with all sections (structure, entry points, dependencies, API surface, patterns)
|
|
119
|
+
- Coverage gaps identified (undocumented modules, missing descriptions, stale references)
|
|
120
|
+
- Output written to AGENTS.md (or specified path) in proper markdown format
|
|
121
|
+
- Report follows the structured output format
|
|
122
|
+
- All findings are backed by graph query evidence, not heuristics
|
|
123
|
+
|
|
124
|
+
## Examples
|
|
125
|
+
|
|
126
|
+
### Example: Generating AGENTS.md from Graph
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
Input: No AGENTS.md exists, graph is current after harness scan
|
|
130
|
+
|
|
131
|
+
1. SURVEY — query_graph for module hierarchy: 4 packages found
|
|
132
|
+
search_similar for entry points: 4 identified
|
|
133
|
+
get_relationships for dependency flow per module
|
|
134
|
+
2. GENERATE — Built 5 sections: structure, entry points,
|
|
135
|
+
dependencies, API surface, patterns
|
|
136
|
+
3. AUDIT — check_docs found 3 undocumented modules,
|
|
137
|
+
5 files with no test coverage
|
|
138
|
+
4. OUTPUT — Wrote AGENTS.md to project root (new file)
|
|
139
|
+
|
|
140
|
+
Output:
|
|
141
|
+
AGENTS.md generated (142 lines)
|
|
142
|
+
Coverage gaps: 3 undocumented modules, 5 untested files
|
|
143
|
+
No stale references (fresh generation)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Gates
|
|
147
|
+
|
|
148
|
+
- **No generation without graph.** If no graph exists, stop and instruct to run `harness scan`.
|
|
149
|
+
- **Never overwrite without confirmation.** If AGENTS.md exists, show the diff and ask before replacing.
|
|
150
|
+
|
|
151
|
+
## Escalation
|
|
152
|
+
|
|
153
|
+
- **When >50% of modules are undocumented**: Flag as critical documentation debt.
|
|
154
|
+
- **When graph structure doesn't match directory structure**: The graph may be stale — recommend re-scanning.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
name: harness-knowledge-mapper
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
description: Auto-generate always-current knowledge maps from graph topology
|
|
4
|
+
cognitive_mode: constructive-architect
|
|
5
|
+
triggers:
|
|
6
|
+
- manual
|
|
7
|
+
- on_commit
|
|
8
|
+
- scheduled
|
|
9
|
+
platforms:
|
|
10
|
+
- claude-code
|
|
11
|
+
- gemini-cli
|
|
12
|
+
tools:
|
|
13
|
+
- Bash
|
|
14
|
+
- Read
|
|
15
|
+
- Write
|
|
16
|
+
- Glob
|
|
17
|
+
- Grep
|
|
18
|
+
cli:
|
|
19
|
+
command: harness skill run harness-knowledge-mapper
|
|
20
|
+
args:
|
|
21
|
+
- name: path
|
|
22
|
+
description: Project root path
|
|
23
|
+
required: false
|
|
24
|
+
- name: output
|
|
25
|
+
description: Output file path (default AGENTS.md)
|
|
26
|
+
required: false
|
|
27
|
+
mcp:
|
|
28
|
+
tool: run_skill
|
|
29
|
+
input:
|
|
30
|
+
skill: harness-knowledge-mapper
|
|
31
|
+
path: string
|
|
32
|
+
type: rigid
|
|
33
|
+
phases:
|
|
34
|
+
- name: survey
|
|
35
|
+
description: Query graph for module structure and topology
|
|
36
|
+
required: true
|
|
37
|
+
- name: generate
|
|
38
|
+
description: Generate structured knowledge map from graph data
|
|
39
|
+
required: true
|
|
40
|
+
- name: audit
|
|
41
|
+
description: Identify undocumented modules and coverage gaps
|
|
42
|
+
required: true
|
|
43
|
+
- name: output
|
|
44
|
+
description: Write knowledge map to file
|
|
45
|
+
required: true
|
|
46
|
+
state:
|
|
47
|
+
persistent: false
|
|
48
|
+
files: []
|
|
49
|
+
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
|
+
});
|