@sallmarta/eye-hate-agent 1.0.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/.agents/rules/agent.md +66 -0
- package/.claude/commands/eha/README.md +3 -0
- package/.claude/commands/eha/eha-bootstrap.md +9 -0
- package/.claude/commands/eha/eha-discuss.md +9 -0
- package/.claude/commands/eha/eha-execute.md +9 -0
- package/.claude/commands/eha/eha-parity.md +9 -0
- package/.claude/commands/eha/eha-refresh.md +9 -0
- package/.claude/commands/eha/eha-verify.md +9 -0
- package/.claude/rules/agent-rules.md +64 -0
- package/.github/instructions/agent-rules.instructions.md +63 -0
- package/.github/instructions/eha-workflows.instructions.md +21 -0
- package/LICENSE +21 -0
- package/README.md +337 -0
- package/bin/eha.js +163 -0
- package/docs/eyehateagent-contract.md +475 -0
- package/docs/eyehateagent-maintenance.md +103 -0
- package/docs/project-docs/changelog.md +287 -0
- package/docs/project-docs/foundation/architecture.md +117 -0
- package/docs/project-docs/foundation/status.md +32 -0
- package/docs/project-docs/foundation/workflow.md +63 -0
- package/docs/project-docs/index.md +20 -0
- package/docs/project-docs/testing.md +73 -0
- package/docs/vibes/project-docs-template/foundation/architecture.md +79 -0
- package/docs/vibes/project-docs-template/foundation/changelog.md +53 -0
- package/docs/vibes/project-docs-template/foundation/feature-inventory.md +46 -0
- package/docs/vibes/project-docs-template/foundation/phases.md +60 -0
- package/docs/vibes/project-docs-template/foundation/prd.md +69 -0
- package/docs/vibes/project-docs-template/foundation/status.md +57 -0
- package/docs/vibes/project-docs-template/foundation/workflow.md +59 -0
- package/docs/vibes/project-docs-template/getting-started.md +52 -0
- package/docs/vibes/project-docs-template/index.md +66 -0
- package/docs/vibes/project-docs-template/operations/ci-cd.md +56 -0
- package/docs/vibes/project-docs-template/operations/compliance.md +46 -0
- package/docs/vibes/project-docs-template/operations/governance.md +46 -0
- package/docs/vibes/project-docs-template/operations/observability.md +53 -0
- package/docs/vibes/project-docs-template/operations/production-runbook.md +62 -0
- package/docs/vibes/project-docs-template/operations/security.md +49 -0
- package/docs/vibes/project-docs-template/technical/api-contract.md +49 -0
- package/docs/vibes/project-docs-template/technical/database.md +59 -0
- package/docs/vibes/project-docs-template/technical/error-handling.md +54 -0
- package/docs/vibes/project-docs-template/technical/internationalization.md +46 -0
- package/docs/vibes/project-docs-template/technical/testing.md +57 -0
- package/docs/vibes/project-docs-template/technical/ui-ux.md +68 -0
- package/docs/vibes/project-docs-template/technical-guidelines/index.md +52 -0
- package/docs/vibes/reusable-prompts/00-project-docs-bootstrap.md +59 -0
- package/docs/vibes/reusable-prompts/00-project-docs-parity.md +88 -0
- package/docs/vibes/reusable-prompts/00-project-docs-refresh.md +81 -0
- package/docs/vibes/reusable-prompts/01-sdd-execute.md +34 -0
- package/docs/vibes/reusable-prompts/02-sdd-discuss.md +27 -0
- package/docs/vibes/skills/analysis/SKILL.md +173 -0
- package/docs/vibes/skills/api-design/SKILL.md +199 -0
- package/docs/vibes/skills/code-audit/SKILL.md +170 -0
- package/docs/vibes/skills/full-verification/SKILL.md +173 -0
- package/docs/vibes/skills/parity/SKILL.md +158 -0
- package/docs/vibes/skills/project-elevation/SKILL.md +157 -0
- package/docs/vibes/skills/test-authoring/SKILL.md +201 -0
- package/docs/vibes/skills/test-authoring/references/patterns.md +116 -0
- package/docs/vibes/skills/test-authoring/references/test-types.md +52 -0
- package/package.json +53 -0
- package/src/engine/index.js +22 -0
- package/src/engine/install.js +222 -0
- package/src/engine/runtime-adapters.js +106 -0
- package/src/engine/state.js +109 -0
- package/src/engine/workflow-registry.js +75 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test-authoring
|
|
3
|
+
description: "Project-aware expert-role verification strategy and test authoring that reads project docs to choose the right frameworks, commands, layers, and templates. Use when deciding test scope, validating regressions, choosing verification strategy, and writing or reviewing tests across any stack."
|
|
4
|
+
argument-hint: "Describe the behavior, bug, feature, boundary, or artifact to test"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Test Authoring — Project-Aware
|
|
8
|
+
|
|
9
|
+
Produces an **expert, project-aware verification strategy and test implementation plan** by reading the repository's documentation contract first, then selecting the correct test types, commands, and conventions for the current stack.
|
|
10
|
+
|
|
11
|
+
This skill is intentionally **not tied to any single stack or framework**. The stack-specific truth should come from project docs.
|
|
12
|
+
|
|
13
|
+
This skill is **verification-strategy-first**. Its primary job is to choose the right verification boundary, check type, commands, and assertions; writing the test code is downstream of that decision when implementation is actually needed.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Required Project Inputs
|
|
18
|
+
|
|
19
|
+
Read the relevant docs before proposing or writing tests.
|
|
20
|
+
|
|
21
|
+
| Document | Why it matters |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
|
|
24
|
+
| `docs/project-docs/technical/testing.md` | Primary source for verification policy, commands, quality gates, and fallback rules |
|
|
25
|
+
| `docs/project-docs/foundation/architecture.md` | Explains runtime boundaries, architecture pattern, integrations, storage, and enforcement rules |
|
|
26
|
+
| `docs/project-docs/foundation/status.md` | Reveals current implementation state, risks, and which workstream the change belongs to |
|
|
27
|
+
| Relevant feature docs under `docs/project-docs/` or `docs/project-docs/technical-guidelines/` | Provide domain-specific behavior, API contracts, or user-flow expectations |
|
|
28
|
+
| Existing test files in the repo | Show naming, folder structure, harness setup, and local conventions |
|
|
29
|
+
|
|
30
|
+
If one of the required docs is missing and the task depends on it, surface that explicitly and create or update the doc instead of guessing.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## When To Use
|
|
35
|
+
|
|
36
|
+
| Trigger | Example request |
|
|
37
|
+
| --- | --- |
|
|
38
|
+
| Change verification | "Choose the right verification for this repository-layer change" |
|
|
39
|
+
| API contract update | "What tests should cover this API contract update?" |
|
|
40
|
+
| Migration or persistence change | "Write a test plan for this migration change" |
|
|
41
|
+
| Documentation-only repo change | "How should I validate a reusable prompt or platform instruction surface update?" |
|
|
42
|
+
|
|
43
|
+
Use `full-verification` instead when the user wants a broad verification entry point that may need to choose between code review, docs consistency, contract review, health assessment, or executable testing.
|
|
44
|
+
|
|
45
|
+
Use `code-audit` instead when the main question is whether the implementation is correct.
|
|
46
|
+
|
|
47
|
+
Use `analysis` instead when the task is explaining a failure or comparing technical options rather than deciding how to verify them.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Procedure
|
|
52
|
+
|
|
53
|
+
### Step 1 — Identify the verification target
|
|
54
|
+
|
|
55
|
+
Determine what changed:
|
|
56
|
+
|
|
57
|
+
- deterministic logic or transformation behavior
|
|
58
|
+
- interface, contract, or boundary behavior
|
|
59
|
+
- state, storage, migration, or lifecycle behavior
|
|
60
|
+
- internal coordination or module interaction behavior
|
|
61
|
+
- external dependency or integration behavior
|
|
62
|
+
- interactive, operator, or consumer-facing flow
|
|
63
|
+
- background, scheduled, evented, or staged processing
|
|
64
|
+
- documentation, reusable prompt, or rule behavior
|
|
65
|
+
|
|
66
|
+
### Step 2 — Read the project-specific verification rules
|
|
67
|
+
|
|
68
|
+
Use `testing.md` as the first stop.
|
|
69
|
+
|
|
70
|
+
Extract:
|
|
71
|
+
|
|
72
|
+
- which checks are required
|
|
73
|
+
- which commands are available
|
|
74
|
+
- which test layers exist
|
|
75
|
+
- which checks are blocking vs advisory
|
|
76
|
+
- what to do when the repo has no executable validation yet
|
|
77
|
+
|
|
78
|
+
### Step 3 — Choose the narrowest useful check
|
|
79
|
+
|
|
80
|
+
Prefer the smallest check that can disconfirm the current assumption.
|
|
81
|
+
|
|
82
|
+
Order of preference:
|
|
83
|
+
|
|
84
|
+
1. targeted unit or component test
|
|
85
|
+
2. boundary or contract test
|
|
86
|
+
3. integration test
|
|
87
|
+
4. build or analysis check
|
|
88
|
+
5. documentation or consistency review when no executable check exists
|
|
89
|
+
|
|
90
|
+
If the user asked to write tests, still make this decision first before drafting any implementation.
|
|
91
|
+
|
|
92
|
+
### Step 4 — Match the check to the architecture boundary
|
|
93
|
+
|
|
94
|
+
Use `architecture.md` to decide whether the test should sit at:
|
|
95
|
+
|
|
96
|
+
- domain or business-logic boundary
|
|
97
|
+
- interface or contract boundary
|
|
98
|
+
- adapter or integration boundary
|
|
99
|
+
- persistence boundary
|
|
100
|
+
- presentation or user-flow boundary
|
|
101
|
+
|
|
102
|
+
Do not test below or above the intended boundary without a reason.
|
|
103
|
+
|
|
104
|
+
### Step 5 — Follow repository conventions
|
|
105
|
+
|
|
106
|
+
Use existing project patterns for:
|
|
107
|
+
|
|
108
|
+
- file naming
|
|
109
|
+
- directory structure
|
|
110
|
+
- fixtures, samples, or test artifacts
|
|
111
|
+
- mocks, stubs, fakes, simulators, or other doubles
|
|
112
|
+
- harness or environment setup
|
|
113
|
+
- boundary-specific fixtures or sample data
|
|
114
|
+
- dependency setup, replacement, or override patterns
|
|
115
|
+
|
|
116
|
+
If the repo does not define a convention yet, propose one briefly and keep it minimal.
|
|
117
|
+
|
|
118
|
+
### Step 6 — Execute the documented checks
|
|
119
|
+
|
|
120
|
+
Run the exact commands from `testing.md` when they exist.
|
|
121
|
+
|
|
122
|
+
If the repo is documentation-only or otherwise lacks executable checks:
|
|
123
|
+
|
|
124
|
+
- perform the strongest structural review available
|
|
125
|
+
- state the limitation clearly
|
|
126
|
+
- recommend the missing verification doc or command only if it materially blocks quality
|
|
127
|
+
|
|
128
|
+
### Step 7 — Report what was actually covered
|
|
129
|
+
|
|
130
|
+
Separate:
|
|
131
|
+
|
|
132
|
+
- what was verified
|
|
133
|
+
- what was not verified
|
|
134
|
+
- what still depends on manual review or future automation
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
### Check Selection Matrix
|
|
139
|
+
|
|
140
|
+
| Scenario | Preferred check type | Read first |
|
|
141
|
+
| --- | --- | --- |
|
|
142
|
+
| Pure function, mapper, validator, parser | Unit | `testing.md`, `architecture.md` |
|
|
143
|
+
| Internal coordination, service, or module behavior | Unit or component | `testing.md`, `architecture.md`, feature docs |
|
|
144
|
+
| State transition, migration, or persistence rule | Persistence / migration test | `testing.md`, `architecture.md`, data-model docs |
|
|
145
|
+
| Interface, handler, adapter, or contract boundary | Contract or integration test | `testing.md`, API / integration docs |
|
|
146
|
+
| Interactive or end-user-visible flow | UI or end-to-end test | `testing.md`, app-flow / UI docs |
|
|
147
|
+
| Asynchronous, scheduled, staged, or event-driven processing | Integration or component test | `testing.md`, `architecture.md`, workflow docs |
|
|
148
|
+
| Rule, skill, reusable prompt, or documentation change | Consistency review or structural validation | `docs/eyehateagent-contract.md`, `testing.md` |
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Output Contract
|
|
153
|
+
|
|
154
|
+
When using this skill, the output should include:
|
|
155
|
+
|
|
156
|
+
1. the recommended verification boundary
|
|
157
|
+
2. the specific check type to use
|
|
158
|
+
3. the project docs consulted
|
|
159
|
+
4. whether new or changed tests are actually needed
|
|
160
|
+
5. the command(s) to run, or the reason no executable command exists
|
|
161
|
+
6. the expected assertions or behaviors to verify
|
|
162
|
+
7. any residual risks or uncovered paths
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Quality Checks
|
|
167
|
+
|
|
168
|
+
- Choose the narrowest check that can falsify the current assumption
|
|
169
|
+
- Do not recommend commands before checking `testing.md`
|
|
170
|
+
- Keep the verification boundary aligned with `architecture.md`
|
|
171
|
+
- Separate what was verified from what still depends on manual review or future automation
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Anti-Patterns
|
|
176
|
+
|
|
177
|
+
- Hardcoding one framework's tools into the skill text when that belongs in `testing.md`
|
|
178
|
+
- Writing an end-to-end test when a narrow unit or contract test would falsify the same assumption
|
|
179
|
+
- Jumping straight to writing test code before choosing the verification boundary and check type
|
|
180
|
+
- Recommending commands without first checking `testing.md`
|
|
181
|
+
- Guessing naming conventions instead of checking the repo
|
|
182
|
+
- Treating documentation-only repositories as if they must already have executable tests
|
|
183
|
+
- Confusing architecture examples with mandatory implementation details
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Natural Prompt Shapes
|
|
188
|
+
|
|
189
|
+
- "What is the right way to verify this change?"
|
|
190
|
+
- "Which tests should we add for this API or bug fix?"
|
|
191
|
+
- "Use the correct testing approach for this stack and tell me what to run."
|
|
192
|
+
- "Do we actually need new tests here, and if so at what boundary?"
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Example Requests
|
|
197
|
+
|
|
198
|
+
- "Choose the right verification for this repository-layer change"
|
|
199
|
+
- "What tests should cover this API contract update?"
|
|
200
|
+
- "Write a test plan for this migration change"
|
|
201
|
+
- "This repo has no code yet — how should I validate a reusable prompt or platform instruction surface update?"
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Test Patterns Reference — Project-Aware
|
|
2
|
+
|
|
3
|
+
Quick reference for common test-pattern shapes. Use these as **structural examples**, then adapt them using the repository's `testing.md`, `architecture.md`, and local conventions.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Pattern A: Narrow Unit Or Component Test
|
|
8
|
+
|
|
9
|
+
Use when you want the fastest check at a clear boundary.
|
|
10
|
+
|
|
11
|
+
### Pattern A Skeleton
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
Arrange inputs and collaborators
|
|
15
|
+
Act on one function, method, or component boundary
|
|
16
|
+
Assert on the returned value, state change, or emitted effect
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Pattern A Good Fit
|
|
20
|
+
|
|
21
|
+
- pure functions
|
|
22
|
+
- mappers or transformers
|
|
23
|
+
- validators
|
|
24
|
+
- repository or service methods with mocked dependencies
|
|
25
|
+
- small boundary-level business logic
|
|
26
|
+
|
|
27
|
+
### Pattern A Checklist
|
|
28
|
+
|
|
29
|
+
- isolate one behavior
|
|
30
|
+
- keep collaborators fake or mocked when helpful
|
|
31
|
+
- assert on outcomes, not internal implementation noise
|
|
32
|
+
- name tests by observable behavior
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Pattern B: Persistence Or Contract Test
|
|
37
|
+
|
|
38
|
+
Use when you need confidence in schema, queries, serialization, or boundary compatibility.
|
|
39
|
+
|
|
40
|
+
### Pattern B Skeleton
|
|
41
|
+
|
|
42
|
+
```text
|
|
43
|
+
Set up an isolated persistence or contract environment
|
|
44
|
+
Insert or send representative inputs
|
|
45
|
+
Read back or decode the resulting output
|
|
46
|
+
Assert on correctness, constraints, and error cases
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Pattern B Good Fit
|
|
50
|
+
|
|
51
|
+
- database queries
|
|
52
|
+
- repository persistence rules
|
|
53
|
+
- schema evolution
|
|
54
|
+
- migration behavior
|
|
55
|
+
- request / response or message serialization
|
|
56
|
+
- interface compatibility checks
|
|
57
|
+
|
|
58
|
+
### Pattern B Checklist
|
|
59
|
+
|
|
60
|
+
- include one happy path
|
|
61
|
+
- include one invalid or edge case
|
|
62
|
+
- assert on durable outcomes, not just returned status
|
|
63
|
+
- use representative fixtures where that improves clarity
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Pattern C: Flow Or Interaction Test
|
|
68
|
+
|
|
69
|
+
Use when the value lies in verifying a user, operator, or system flow instead of an isolated unit.
|
|
70
|
+
|
|
71
|
+
### Pattern C Skeleton
|
|
72
|
+
|
|
73
|
+
```text
|
|
74
|
+
Start from a realistic entry point
|
|
75
|
+
Drive the interaction or workflow
|
|
76
|
+
Wait for the expected state transition
|
|
77
|
+
Assert on visible output, routed behavior, or side effects
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Pattern C Good Fit
|
|
81
|
+
|
|
82
|
+
- UI interactions
|
|
83
|
+
- endpoint-to-service flow
|
|
84
|
+
- command or job workflows
|
|
85
|
+
- integration boundaries
|
|
86
|
+
- navigation or routing flows
|
|
87
|
+
|
|
88
|
+
### Pattern C Checklist
|
|
89
|
+
|
|
90
|
+
- keep the flow focused on one meaningful outcome
|
|
91
|
+
- mock or isolate irrelevant external dependencies when possible
|
|
92
|
+
- assert on the behavior the caller or user experiences
|
|
93
|
+
- avoid testing multiple unrelated journeys in one case
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Common Assertions To Prefer
|
|
98
|
+
|
|
99
|
+
- returned values or result envelopes
|
|
100
|
+
- persisted state
|
|
101
|
+
- emitted events or messages
|
|
102
|
+
- visible UI state
|
|
103
|
+
- boundary calls that materially define behavior
|
|
104
|
+
- error category and recovery path
|
|
105
|
+
|
|
106
|
+
Prefer observable behavior over internal implementation details.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Common Anti-Patterns
|
|
111
|
+
|
|
112
|
+
- testing too many branches in one test
|
|
113
|
+
- asserting on private implementation details
|
|
114
|
+
- using full integration tests when a narrow unit or contract test would falsify the same assumption
|
|
115
|
+
- naming tests after implementation rather than behavior
|
|
116
|
+
- copying framework-specific scaffolds without checking `testing.md`
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Test Type Decision Table — Project-Aware
|
|
2
|
+
|
|
3
|
+
Use this table to choose the smallest verification type that matches the actual boundary being changed. Confirm the final choice against the repository's `testing.md`.
|
|
4
|
+
|
|
5
|
+
| Scenario | Preferred check type | Why |
|
|
6
|
+
| --- | --- | --- |
|
|
7
|
+
| Pure function, mapper, validator, parser | Unit | Fastest falsifiable check with minimal setup |
|
|
8
|
+
| Internal service or repository rule | Unit or component | Verifies business behavior without unnecessary system setup |
|
|
9
|
+
| Persistence query, migration, or schema rule | Persistence / migration test | Verifies durable state and compatibility at the right boundary |
|
|
10
|
+
| Request, handler, controller, or public API contract | Contract or integration test | Verifies visible boundary behavior and schema expectations |
|
|
11
|
+
| UI or operator interaction flow | Flow / interaction test | Verifies user-visible behavior rather than isolated internals |
|
|
12
|
+
| Async job, workflow, or queue behavior | Component or integration test | Verifies sequencing, retry, and side-effect behavior |
|
|
13
|
+
| Documentation, reusable prompt, or platform instruction surfaces change | Structural consistency review | Executable tests may not exist; consistency becomes the real boundary |
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Test Type Summary
|
|
18
|
+
|
|
19
|
+
| Type | Best for | Typical cost | Isolation |
|
|
20
|
+
| --- | --- | --- | --- |
|
|
21
|
+
| Unit | Pure logic and narrow behavior | Lowest | Highest |
|
|
22
|
+
| Component | One internal boundary with collaborators | Low to medium | High |
|
|
23
|
+
| Persistence / contract | Durable state or schema behavior | Low to medium | Medium to high |
|
|
24
|
+
| Flow / interaction | User or system-visible path | Medium | Medium |
|
|
25
|
+
| Integration | Real dependency or end-to-end boundary | Highest | Lowest |
|
|
26
|
+
| Consistency review | Docs, reusable prompts, platform instruction surfaces, and template systems | Low | High |
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Selection Rules
|
|
31
|
+
|
|
32
|
+
1. Prefer the narrowest check that can prove the change is correct.
|
|
33
|
+
2. Escalate to broader tests only when the boundary truly requires it.
|
|
34
|
+
3. Use project docs to choose commands, harnesses, and file placement.
|
|
35
|
+
4. When no executable validation exists, make the structural review explicit rather than pretending the repo is fully testable.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Naming Guidance
|
|
40
|
+
|
|
41
|
+
Prefer behavior-driven names such as:
|
|
42
|
+
|
|
43
|
+
- `returns empty result when no records match`
|
|
44
|
+
- `rejects invalid payload when required field is missing`
|
|
45
|
+
- `shows retry state after dependency timeout`
|
|
46
|
+
- `persists latest progress after successful update`
|
|
47
|
+
|
|
48
|
+
Avoid placeholder names such as:
|
|
49
|
+
|
|
50
|
+
- `test1`
|
|
51
|
+
- `happy path`
|
|
52
|
+
- `error case`
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sallmarta/eye-hate-agent",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Template-and-engine toolkit for AI-agent-assisted project workflows.",
|
|
5
|
+
"directories": {
|
|
6
|
+
"doc": "docs"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin",
|
|
10
|
+
"src",
|
|
11
|
+
"docs",
|
|
12
|
+
".claude",
|
|
13
|
+
".github",
|
|
14
|
+
".agents",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"test": "node --test"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"ai-agent",
|
|
22
|
+
"agent-workflow",
|
|
23
|
+
"cli",
|
|
24
|
+
"claude",
|
|
25
|
+
"copilot",
|
|
26
|
+
"project-docs",
|
|
27
|
+
"prompt-engineering",
|
|
28
|
+
"template"
|
|
29
|
+
],
|
|
30
|
+
"author": "SallMarta",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/SallMarta/eye-hate-agent.git"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://github.com/SallMarta/eye-hate-agent#readme",
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/SallMarta/eye-hate-agent/issues"
|
|
39
|
+
},
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=18"
|
|
45
|
+
},
|
|
46
|
+
"bin": {
|
|
47
|
+
"eha": "./bin/eha.js"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"commander": "^12.0.0",
|
|
51
|
+
"chalk": "^4.1.2"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const { getWorkflow, listWorkflows } = require('./workflow-registry');
|
|
2
|
+
const { findRepoRoot } = require('./state');
|
|
3
|
+
const { listSupportedRuntimes } = require('./runtime-adapters');
|
|
4
|
+
const {
|
|
5
|
+
DEFAULT_RUNTIME_IDS,
|
|
6
|
+
doctor,
|
|
7
|
+
installRuntimes,
|
|
8
|
+
prepareWorkflowRun,
|
|
9
|
+
uninstallRuntimes,
|
|
10
|
+
} = require('./install');
|
|
11
|
+
|
|
12
|
+
module.exports = {
|
|
13
|
+
DEFAULT_RUNTIME_IDS,
|
|
14
|
+
doctor,
|
|
15
|
+
findRepoRoot,
|
|
16
|
+
getWorkflow,
|
|
17
|
+
installRuntimes,
|
|
18
|
+
listSupportedRuntimes,
|
|
19
|
+
listWorkflows,
|
|
20
|
+
prepareWorkflowRun,
|
|
21
|
+
uninstallRuntimes,
|
|
22
|
+
};
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
const fs = require('node:fs');
|
|
2
|
+
const path = require('node:path');
|
|
3
|
+
|
|
4
|
+
const { listWorkflows, getWorkflow } = require('./workflow-registry');
|
|
5
|
+
const { getRuntimeAdapter, listSupportedRuntimes } = require('./runtime-adapters');
|
|
6
|
+
const {
|
|
7
|
+
ensureDir,
|
|
8
|
+
getBundledAssetPath,
|
|
9
|
+
getEnginePaths,
|
|
10
|
+
readJsonIfExists,
|
|
11
|
+
removeEmptyParents,
|
|
12
|
+
removeFileIfExists,
|
|
13
|
+
writeJson,
|
|
14
|
+
writeText,
|
|
15
|
+
} = require('./state');
|
|
16
|
+
|
|
17
|
+
const DEFAULT_RUNTIME_IDS = ['claude', 'copilot'];
|
|
18
|
+
const BUNDLED_CONTRACT_PATH = path.join('docs', 'eyehateagent-contract.md');
|
|
19
|
+
|
|
20
|
+
function resolveRuntimeIds(runtimes) {
|
|
21
|
+
const runtimeIds = runtimes && runtimes.length > 0 ? runtimes : DEFAULT_RUNTIME_IDS;
|
|
22
|
+
return [...new Set(runtimeIds.map((runtime) => String(runtime).trim().toLowerCase()).filter(Boolean))];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function readManifest(manifestPath) {
|
|
26
|
+
return (
|
|
27
|
+
readJsonIfExists(manifestPath) || {
|
|
28
|
+
generatedOutputsInsideRepo: true,
|
|
29
|
+
manifestVersion: 1,
|
|
30
|
+
runtimes: {},
|
|
31
|
+
}
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function buildManifestSummary(runtimeId, adapter, files) {
|
|
36
|
+
return {
|
|
37
|
+
files: files.map((file) => file.relativePath),
|
|
38
|
+
supportTier: adapter.supportTier,
|
|
39
|
+
updatedAt: new Date().toISOString(),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function getGeneratedSourceRelativePath(repoRelativePath) {
|
|
44
|
+
return path.join('.eha', 'generated', 'sources', repoRelativePath);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function materializeBundledSources(rootDir, workflows) {
|
|
48
|
+
const repoRelativePaths = new Set([BUNDLED_CONTRACT_PATH]);
|
|
49
|
+
for (const workflow of workflows) {
|
|
50
|
+
repoRelativePaths.add(workflow.repoRelativePath);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const generatedSourcePaths = {};
|
|
54
|
+
|
|
55
|
+
for (const repoRelativePath of repoRelativePaths) {
|
|
56
|
+
const sourcePath = getBundledAssetPath(repoRelativePath);
|
|
57
|
+
const targetRelativePath = getGeneratedSourceRelativePath(repoRelativePath);
|
|
58
|
+
const targetPath = path.join(rootDir, targetRelativePath);
|
|
59
|
+
writeText(targetPath, fs.readFileSync(sourcePath, 'utf8'));
|
|
60
|
+
generatedSourcePaths[repoRelativePath] = targetRelativePath;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
contractPath: generatedSourcePaths[BUNDLED_CONTRACT_PATH],
|
|
65
|
+
workflowPaths: generatedSourcePaths,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function installRuntimes({ rootDir, runtimes }) {
|
|
70
|
+
const runtimeIds = resolveRuntimeIds(runtimes);
|
|
71
|
+
const enginePaths = getEnginePaths(rootDir);
|
|
72
|
+
const manifest = readManifest(enginePaths.manifestPath);
|
|
73
|
+
const workflows = listWorkflows();
|
|
74
|
+
const bundledSources = materializeBundledSources(rootDir, workflows);
|
|
75
|
+
const runtimeSummaries = [];
|
|
76
|
+
|
|
77
|
+
for (const runtimeId of runtimeIds) {
|
|
78
|
+
const adapter = getRuntimeAdapter(runtimeId);
|
|
79
|
+
const files = adapter.generateFiles(rootDir, workflows, bundledSources);
|
|
80
|
+
|
|
81
|
+
for (const file of files) {
|
|
82
|
+
const absolutePath = path.join(rootDir, file.relativePath);
|
|
83
|
+
ensureDir(path.dirname(absolutePath));
|
|
84
|
+
writeText(absolutePath, file.content);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
manifest.runtimes[runtimeId] = buildManifestSummary(runtimeId, adapter, files);
|
|
88
|
+
runtimeSummaries.push({
|
|
89
|
+
id: runtimeId,
|
|
90
|
+
supportTier: adapter.supportTier,
|
|
91
|
+
fileCount: files.length,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
writeJson(enginePaths.manifestPath, manifest);
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
rootDir,
|
|
99
|
+
runtimes: runtimeIds,
|
|
100
|
+
manifestPath: enginePaths.manifestPath,
|
|
101
|
+
runtimeSummaries,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function uninstallRuntimes({ rootDir, runtimes }) {
|
|
106
|
+
const enginePaths = getEnginePaths(rootDir);
|
|
107
|
+
const manifest = readManifest(enginePaths.manifestPath);
|
|
108
|
+
const runtimeIds = resolveRuntimeIds(runtimes);
|
|
109
|
+
const runtimeSummaries = [];
|
|
110
|
+
|
|
111
|
+
for (const runtimeId of runtimeIds) {
|
|
112
|
+
const manifestEntry = manifest.runtimes[runtimeId];
|
|
113
|
+
if (!manifestEntry) {
|
|
114
|
+
runtimeSummaries.push({ id: runtimeId, supportTier: 'unknown', fileCount: 0 });
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
for (const relativePath of manifestEntry.files) {
|
|
119
|
+
const absolutePath = path.join(rootDir, relativePath);
|
|
120
|
+
removeFileIfExists(absolutePath);
|
|
121
|
+
removeEmptyParents(path.dirname(absolutePath), rootDir);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
runtimeSummaries.push({
|
|
125
|
+
id: runtimeId,
|
|
126
|
+
supportTier: manifestEntry.supportTier,
|
|
127
|
+
fileCount: manifestEntry.files.length,
|
|
128
|
+
});
|
|
129
|
+
delete manifest.runtimes[runtimeId];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (Object.keys(manifest.runtimes).length === 0) {
|
|
133
|
+
removeFileIfExists(enginePaths.manifestPath);
|
|
134
|
+
removeEmptyParents(path.dirname(enginePaths.manifestPath), rootDir);
|
|
135
|
+
} else {
|
|
136
|
+
writeJson(enginePaths.manifestPath, manifest);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
rootDir,
|
|
141
|
+
runtimes: runtimeIds,
|
|
142
|
+
manifestPath: enginePaths.manifestPath,
|
|
143
|
+
runtimeSummaries,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function buildPromptContent(workflow, sourcePaths, contextText, invokedAs) {
|
|
148
|
+
const commandLabel = invokedAs || workflow.commandName;
|
|
149
|
+
|
|
150
|
+
let content = `# EHA Workflow Dispatch\n\n`;
|
|
151
|
+
content += `Read \`${sourcePaths.contractPath}\` first.\n\n`;
|
|
152
|
+
content += `Execute \`${sourcePaths.workflowPath}\`.\n\n`;
|
|
153
|
+
content += `Requested via CLI command: \`${commandLabel}\`\n`;
|
|
154
|
+
|
|
155
|
+
if (workflow.capabilityNote) {
|
|
156
|
+
content += `\n> Note: ${workflow.capabilityNote}\n`;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (contextText) {
|
|
160
|
+
content += `\n## Additional CLI Context\n\n${contextText}\n`;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return content;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function prepareWorkflowRun({ rootDir, workflowId, contextText = '', invokedAs = null }) {
|
|
167
|
+
const workflow = getWorkflow(workflowId);
|
|
168
|
+
const enginePaths = getEnginePaths(rootDir);
|
|
169
|
+
const bundledSources = materializeBundledSources(rootDir, [workflow]);
|
|
170
|
+
const promptContent = buildPromptContent(
|
|
171
|
+
workflow,
|
|
172
|
+
{
|
|
173
|
+
contractPath: bundledSources.contractPath,
|
|
174
|
+
workflowPath: bundledSources.workflowPaths[workflow.repoRelativePath],
|
|
175
|
+
},
|
|
176
|
+
contextText,
|
|
177
|
+
invokedAs,
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
writeText(enginePaths.lastPromptPath, promptContent);
|
|
181
|
+
writeJson(enginePaths.lastRunPath, {
|
|
182
|
+
workflowId: workflow.id,
|
|
183
|
+
invokedAs: invokedAs || workflow.commandName,
|
|
184
|
+
promptPath: path.relative(rootDir, enginePaths.lastPromptPath),
|
|
185
|
+
sourceWorkflowPath: workflow.repoRelativePath,
|
|
186
|
+
contextText,
|
|
187
|
+
updatedAt: new Date().toISOString(),
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
workflow,
|
|
192
|
+
promptContent,
|
|
193
|
+
promptPath: path.relative(rootDir, enginePaths.lastPromptPath),
|
|
194
|
+
contextText,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function doctor({ rootDir }) {
|
|
199
|
+
const enginePaths = getEnginePaths(rootDir);
|
|
200
|
+
const manifest = readManifest(enginePaths.manifestPath);
|
|
201
|
+
const installedRuntimes = Object.entries(manifest.runtimes).map(([id, entry]) => ({
|
|
202
|
+
id,
|
|
203
|
+
supportTier: entry.supportTier,
|
|
204
|
+
fileCount: entry.files.length,
|
|
205
|
+
}));
|
|
206
|
+
|
|
207
|
+
return {
|
|
208
|
+
rootDir,
|
|
209
|
+
generatedOutputsInsideRepo: true,
|
|
210
|
+
paths: enginePaths,
|
|
211
|
+
supportedRuntimes: listSupportedRuntimes(),
|
|
212
|
+
installedRuntimes,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
module.exports = {
|
|
217
|
+
DEFAULT_RUNTIME_IDS,
|
|
218
|
+
doctor,
|
|
219
|
+
installRuntimes,
|
|
220
|
+
prepareWorkflowRun,
|
|
221
|
+
uninstallRuntimes,
|
|
222
|
+
};
|