@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.
Files changed (64) hide show
  1. package/.agents/rules/agent.md +66 -0
  2. package/.claude/commands/eha/README.md +3 -0
  3. package/.claude/commands/eha/eha-bootstrap.md +9 -0
  4. package/.claude/commands/eha/eha-discuss.md +9 -0
  5. package/.claude/commands/eha/eha-execute.md +9 -0
  6. package/.claude/commands/eha/eha-parity.md +9 -0
  7. package/.claude/commands/eha/eha-refresh.md +9 -0
  8. package/.claude/commands/eha/eha-verify.md +9 -0
  9. package/.claude/rules/agent-rules.md +64 -0
  10. package/.github/instructions/agent-rules.instructions.md +63 -0
  11. package/.github/instructions/eha-workflows.instructions.md +21 -0
  12. package/LICENSE +21 -0
  13. package/README.md +337 -0
  14. package/bin/eha.js +163 -0
  15. package/docs/eyehateagent-contract.md +475 -0
  16. package/docs/eyehateagent-maintenance.md +103 -0
  17. package/docs/project-docs/changelog.md +287 -0
  18. package/docs/project-docs/foundation/architecture.md +117 -0
  19. package/docs/project-docs/foundation/status.md +32 -0
  20. package/docs/project-docs/foundation/workflow.md +63 -0
  21. package/docs/project-docs/index.md +20 -0
  22. package/docs/project-docs/testing.md +73 -0
  23. package/docs/vibes/project-docs-template/foundation/architecture.md +79 -0
  24. package/docs/vibes/project-docs-template/foundation/changelog.md +53 -0
  25. package/docs/vibes/project-docs-template/foundation/feature-inventory.md +46 -0
  26. package/docs/vibes/project-docs-template/foundation/phases.md +60 -0
  27. package/docs/vibes/project-docs-template/foundation/prd.md +69 -0
  28. package/docs/vibes/project-docs-template/foundation/status.md +57 -0
  29. package/docs/vibes/project-docs-template/foundation/workflow.md +59 -0
  30. package/docs/vibes/project-docs-template/getting-started.md +52 -0
  31. package/docs/vibes/project-docs-template/index.md +66 -0
  32. package/docs/vibes/project-docs-template/operations/ci-cd.md +56 -0
  33. package/docs/vibes/project-docs-template/operations/compliance.md +46 -0
  34. package/docs/vibes/project-docs-template/operations/governance.md +46 -0
  35. package/docs/vibes/project-docs-template/operations/observability.md +53 -0
  36. package/docs/vibes/project-docs-template/operations/production-runbook.md +62 -0
  37. package/docs/vibes/project-docs-template/operations/security.md +49 -0
  38. package/docs/vibes/project-docs-template/technical/api-contract.md +49 -0
  39. package/docs/vibes/project-docs-template/technical/database.md +59 -0
  40. package/docs/vibes/project-docs-template/technical/error-handling.md +54 -0
  41. package/docs/vibes/project-docs-template/technical/internationalization.md +46 -0
  42. package/docs/vibes/project-docs-template/technical/testing.md +57 -0
  43. package/docs/vibes/project-docs-template/technical/ui-ux.md +68 -0
  44. package/docs/vibes/project-docs-template/technical-guidelines/index.md +52 -0
  45. package/docs/vibes/reusable-prompts/00-project-docs-bootstrap.md +59 -0
  46. package/docs/vibes/reusable-prompts/00-project-docs-parity.md +88 -0
  47. package/docs/vibes/reusable-prompts/00-project-docs-refresh.md +81 -0
  48. package/docs/vibes/reusable-prompts/01-sdd-execute.md +34 -0
  49. package/docs/vibes/reusable-prompts/02-sdd-discuss.md +27 -0
  50. package/docs/vibes/skills/analysis/SKILL.md +173 -0
  51. package/docs/vibes/skills/api-design/SKILL.md +199 -0
  52. package/docs/vibes/skills/code-audit/SKILL.md +170 -0
  53. package/docs/vibes/skills/full-verification/SKILL.md +173 -0
  54. package/docs/vibes/skills/parity/SKILL.md +158 -0
  55. package/docs/vibes/skills/project-elevation/SKILL.md +157 -0
  56. package/docs/vibes/skills/test-authoring/SKILL.md +201 -0
  57. package/docs/vibes/skills/test-authoring/references/patterns.md +116 -0
  58. package/docs/vibes/skills/test-authoring/references/test-types.md +52 -0
  59. package/package.json +53 -0
  60. package/src/engine/index.js +22 -0
  61. package/src/engine/install.js +222 -0
  62. package/src/engine/runtime-adapters.js +106 -0
  63. package/src/engine/state.js +109 -0
  64. 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
+ };