@sallmarta/eye-hate-agent 1.0.2 → 1.0.3
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/README.md +38 -310
- package/bin/eha.js +203 -118
- package/docs/templates/project-docs-template/foundation/architecture.md +79 -0
- package/docs/templates/project-docs-template/foundation/changelog.md +53 -0
- package/docs/templates/project-docs-template/foundation/feature-inventory.md +46 -0
- package/docs/templates/project-docs-template/foundation/phases.md +60 -0
- package/docs/templates/project-docs-template/foundation/prd.md +69 -0
- package/docs/templates/project-docs-template/foundation/status.md +57 -0
- package/docs/templates/project-docs-template/foundation/workflow.md +59 -0
- package/docs/templates/project-docs-template/getting-started.md +52 -0
- package/docs/{vibes → templates}/project-docs-template/index.md +12 -12
- package/docs/templates/project-docs-template/operations/ci-cd.md +56 -0
- package/docs/templates/project-docs-template/operations/compliance.md +46 -0
- package/docs/templates/project-docs-template/operations/governance.md +46 -0
- package/docs/templates/project-docs-template/operations/observability.md +53 -0
- package/docs/templates/project-docs-template/operations/production-runbook.md +62 -0
- package/docs/templates/project-docs-template/operations/security.md +49 -0
- package/docs/templates/project-docs-template/technical/api-contract.md +49 -0
- package/docs/templates/project-docs-template/technical/database.md +59 -0
- package/docs/templates/project-docs-template/technical/error-handling.md +54 -0
- package/docs/templates/project-docs-template/technical/internationalization.md +46 -0
- package/docs/templates/project-docs-template/technical/testing.md +57 -0
- package/docs/templates/project-docs-template/technical/ui-ux.md +68 -0
- package/docs/{vibes → templates}/project-docs-template/technical-guidelines/index.md +3 -3
- package/docs/{vibes → templates}/reusable-prompts/00-project-docs-bootstrap.md +2 -4
- package/docs/{vibes → templates}/reusable-prompts/00-project-docs-parity.md +3 -5
- package/docs/{vibes → templates}/reusable-prompts/00-project-docs-refresh.md +2 -4
- package/docs/{vibes → templates}/reusable-prompts/02-sdd-discuss.md +2 -2
- package/{.agents/rules/agent.md → docs/templates/rules/agent-rules.md} +6 -11
- package/docs/templates/skills/architecture/db-schema-design/SKILL.md +14 -0
- package/docs/{vibes/skills → templates/skills/auditing}/full-verification/SKILL.md +1 -1
- package/docs/{vibes/skills → templates/skills/auditing}/parity/SKILL.md +2 -2
- package/docs/templates/skills/engineering/refactor-specialist/SKILL.md +13 -0
- package/docs/{vibes/skills → templates/skills/engineering}/test-authoring/SKILL.md +177 -1
- package/docs/templates/skills/engineering/ui-ux-implementation/SKILL.md +13 -0
- package/docs/templates/skills/operations/ci-cd-authoring/SKILL.md +13 -0
- package/docs/templates/skills/operations/observability-setup/SKILL.md +13 -0
- package/package.json +4 -6
- package/src/engine/index.js +7 -12
- package/src/engine/install.js +67 -163
- package/src/engine/runtime-adapters.js +263 -50
- package/src/engine/skill-registry.js +67 -0
- package/src/engine/state.js +29 -7
- package/src/engine/workflow-registry.js +14 -23
- package/.claude/commands/eha/README.md +0 -3
- package/.claude/commands/eha/eha-bootstrap.md +0 -9
- package/.claude/commands/eha/eha-discuss.md +0 -9
- package/.claude/commands/eha/eha-execute.md +0 -9
- package/.claude/commands/eha/eha-parity.md +0 -9
- package/.claude/commands/eha/eha-refresh.md +0 -9
- package/.claude/commands/eha/eha-verify.md +0 -9
- package/.claude/rules/agent-rules.md +0 -64
- package/.github/instructions/agent-rules.instructions.md +0 -63
- package/.github/instructions/eha-workflows.instructions.md +0 -21
- package/docs/eyehateagent-contract.md +0 -475
- package/docs/eyehateagent-maintenance.md +0 -103
- package/docs/project-docs/changelog.md +0 -299
- package/docs/project-docs/foundation/architecture.md +0 -117
- package/docs/project-docs/foundation/status.md +0 -32
- package/docs/project-docs/foundation/workflow.md +0 -63
- package/docs/project-docs/index.md +0 -20
- package/docs/project-docs/testing.md +0 -73
- package/docs/vibes/project-docs-template/foundation/architecture.md +0 -79
- package/docs/vibes/project-docs-template/foundation/changelog.md +0 -53
- package/docs/vibes/project-docs-template/foundation/feature-inventory.md +0 -46
- package/docs/vibes/project-docs-template/foundation/phases.md +0 -60
- package/docs/vibes/project-docs-template/foundation/prd.md +0 -69
- package/docs/vibes/project-docs-template/foundation/status.md +0 -57
- package/docs/vibes/project-docs-template/foundation/workflow.md +0 -59
- package/docs/vibes/project-docs-template/getting-started.md +0 -52
- package/docs/vibes/project-docs-template/operations/ci-cd.md +0 -56
- package/docs/vibes/project-docs-template/operations/compliance.md +0 -46
- package/docs/vibes/project-docs-template/operations/governance.md +0 -46
- package/docs/vibes/project-docs-template/operations/observability.md +0 -53
- package/docs/vibes/project-docs-template/operations/production-runbook.md +0 -62
- package/docs/vibes/project-docs-template/operations/security.md +0 -49
- package/docs/vibes/project-docs-template/technical/api-contract.md +0 -49
- package/docs/vibes/project-docs-template/technical/database.md +0 -59
- package/docs/vibes/project-docs-template/technical/error-handling.md +0 -54
- package/docs/vibes/project-docs-template/technical/internationalization.md +0 -46
- package/docs/vibes/project-docs-template/technical/testing.md +0 -57
- package/docs/vibes/project-docs-template/technical/ui-ux.md +0 -68
- package/docs/vibes/skills/project-elevation/SKILL.md +0 -157
- package/docs/vibes/skills/test-authoring/references/patterns.md +0 -116
- package/docs/vibes/skills/test-authoring/references/test-types.md +0 -52
- /package/docs/{vibes → templates}/reusable-prompts/01-sdd-execute.md +0 -0
- /package/docs/{vibes/skills → templates/skills/architecture}/api-design/SKILL.md +0 -0
- /package/docs/{vibes/skills/analysis → templates/skills/architecture/system-analysis}/SKILL.md +0 -0
- /package/docs/{vibes/skills/code-audit → templates/skills/auditing/security-audit}/SKILL.md +0 -0
|
@@ -1,102 +1,315 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs');
|
|
1
4
|
const path = require('node:path');
|
|
2
5
|
|
|
3
|
-
|
|
6
|
+
const { getBundledAssetPath } = require('./state');
|
|
7
|
+
|
|
8
|
+
// Compact EHA rules embedded in every generated command file so the agent
|
|
9
|
+
// has all structural context without needing any external file reference.
|
|
10
|
+
const EHA_COMPACT_RULES = `## EHA Project Doc Rules
|
|
11
|
+
|
|
12
|
+
**4-Layer Taxonomy.** All project docs live under \`docs/project-docs/\`:
|
|
13
|
+
- \`foundation/\` — prd, architecture, workflow, status, phases, changelog, feature-inventory
|
|
14
|
+
- \`operations/\` — ci-cd, production-runbook, governance, compliance, observability, security
|
|
15
|
+
- \`technical/\` — testing, api-contract, database, ui-ux, error-handling, internationalization
|
|
16
|
+
- \`technical-guidelines/\` — domain-specific cross-cutting rules (API, database, logging, etc.)
|
|
17
|
+
|
|
18
|
+
**Legacy/Reference Docs:** Treat folders named \`archive/\`, \`docs-legacy/\`, or \`reference/\` as secondary migration input only, never as authoritative active truth.
|
|
19
|
+
|
|
20
|
+
**Mandatory core docs:** \`index.md\`, \`getting-started.md\`, \`foundation/prd.md\`, \`foundation/architecture.md\`, \`foundation/workflow.md\`, \`foundation/status.md\`, \`foundation/phases.md\`, \`operations/ci-cd.md\`, \`operations/production-runbook.md\`, \`technical/testing.md\`, \`technical/api-contract.md\`, \`technical/database.md\`, \`technical/ui-ux.md\`.
|
|
21
|
+
|
|
22
|
+
**Authority order:** project docs → codebase → agent judgment. When docs conflict, the owning doc wins. When code and docs conflict and authority is unclear, surface the conflict and ask the user — do not guess.
|
|
23
|
+
|
|
24
|
+
**Universal stable headings (every file):** Description, Important, Table of Contents, Scope, Goals, Non Goals.
|
|
25
|
+
|
|
26
|
+
**Key ownership rules:**
|
|
27
|
+
- Vision, personas, requirements → \`foundation/prd.md\`
|
|
28
|
+
- Stack and architecture → \`foundation/architecture.md\`
|
|
29
|
+
- Dev loop and PR process → \`foundation/workflow.md\`
|
|
30
|
+
- Verification commands and quality gates → \`technical/testing.md\`
|
|
31
|
+
- Execution plan and progress → \`foundation/status.md\`
|
|
32
|
+
- Sprint tracking and backlogs → \`foundation/phases.md\`
|
|
33
|
+
- Optional doc inventory → \`index.md\`
|
|
34
|
+
- Domain-specific technical rules → \`technical-guidelines/\` (Create these only for durable cross-cutting rules; avoid placeholders).
|
|
35
|
+
|
|
36
|
+
**SDD rule:** Specifications dictate implementation. Follow a strict 4-step workflow: 1. Update project docs first, 2. Generate tests based on the specs, 3. Generate code to pass the tests, 4. Logically map every code change back to a spec requirement. Refuse to write code for features not in the spec.
|
|
37
|
+
|
|
38
|
+
**Flexible Baselines Principle:** Omit docs the repo doesn't need. Mark unknowns as \`TBD\` or \`Assumption\`. Mark inferred facts as \`Inferred from codebase\` until the user confirms them.`;
|
|
39
|
+
|
|
40
|
+
function loadPromptContent(workflow) {
|
|
41
|
+
const promptPath = getBundledAssetPath(workflow.repoRelativePath);
|
|
42
|
+
const raw = fs.readFileSync(promptPath, 'utf8');
|
|
43
|
+
// Remove the "Read `docs/eyehateagent-contract.md` first." line — the
|
|
44
|
+
// compact rules block replaces that dependency.
|
|
45
|
+
return raw
|
|
46
|
+
.split('\n')
|
|
47
|
+
.filter((line) => !line.includes('docs/eyehateagent-contract.md'))
|
|
48
|
+
.join('\n')
|
|
49
|
+
.replace(/^\n+/, '');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function loadSkillContent(skill) {
|
|
53
|
+
const promptPath = getBundledAssetPath(skill.repoRelativePath);
|
|
54
|
+
const raw = fs.readFileSync(promptPath, 'utf8');
|
|
55
|
+
const parts = raw.split(/^---\r?\n/m);
|
|
56
|
+
let body = parts.length > 2 ? parts.slice(2).join('---\n') : raw;
|
|
57
|
+
return body
|
|
58
|
+
.split('\n')
|
|
59
|
+
.filter((line) => !line.includes('docs/eyehateagent-contract.md'))
|
|
60
|
+
.join('\n')
|
|
61
|
+
.replace(/^\n+/, '');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function loadRuleContent(agentId) {
|
|
65
|
+
const rulePath = getBundledAssetPath(path.join('docs', 'templates', 'rules', 'agent-rules.md'));
|
|
66
|
+
let content = fs.readFileSync(rulePath, 'utf8').replace(/^\n+/, '');
|
|
67
|
+
|
|
68
|
+
if (agentId) {
|
|
69
|
+
const agentsToFilter = ['claude', 'antigravity', 'copilot'].filter(a => a !== agentId.toLowerCase());
|
|
70
|
+
for (const a of agentsToFilter) {
|
|
71
|
+
const regex = new RegExp(`^\\s*-\\s*\\*\\*${a}.*$\\n?`, 'gmi');
|
|
72
|
+
content = content.replace(regex, '');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return content;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function buildClaudeCommandFile(workflow) {
|
|
80
|
+
const promptContent = loadPromptContent(workflow);
|
|
4
81
|
return `---
|
|
5
|
-
description: "
|
|
82
|
+
description: "EHA ${workflow.id} — ${workflow.description}"
|
|
6
83
|
---
|
|
7
84
|
|
|
8
|
-
|
|
85
|
+
${EHA_COMPACT_RULES}
|
|
9
86
|
|
|
10
|
-
|
|
87
|
+
---
|
|
11
88
|
|
|
12
|
-
|
|
13
|
-
`;
|
|
89
|
+
${promptContent}`;
|
|
14
90
|
}
|
|
15
91
|
|
|
16
|
-
function
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
92
|
+
function buildCopilotPromptFile(workflow) {
|
|
93
|
+
const promptContent = loadPromptContent(workflow);
|
|
94
|
+
return `---
|
|
95
|
+
mode: agent
|
|
96
|
+
description: "EHA ${workflow.id} — ${workflow.description}"
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
${EHA_COMPACT_RULES}
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
${promptContent}`;
|
|
104
|
+
}
|
|
23
105
|
|
|
106
|
+
function buildClaudeSkillFile(skill) {
|
|
24
107
|
return `---
|
|
25
|
-
description: "
|
|
108
|
+
description: "EHA skill — ${skill.commandName}"
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
${EHA_COMPACT_RULES}
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
${loadSkillContent(skill)}`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function buildCopilotSkillFile(skill) {
|
|
119
|
+
return `---
|
|
120
|
+
mode: agent
|
|
121
|
+
description: "EHA skill — ${skill.commandName}"
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
${EHA_COMPACT_RULES}
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
${loadSkillContent(skill)}`;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function buildClaudeRuleFile() {
|
|
132
|
+
return `---
|
|
133
|
+
description: "EHA agent rules"
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
${loadRuleContent('claude')}`;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function buildCopilotRuleFile() {
|
|
140
|
+
return `---
|
|
141
|
+
description: "EHA agent rules"
|
|
26
142
|
applyTo: "**"
|
|
27
143
|
---
|
|
28
144
|
|
|
29
|
-
|
|
145
|
+
${loadRuleContent('copilot')}`;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function buildAntigravityCommandFile(workflow) {
|
|
149
|
+
const promptContent = loadPromptContent(workflow);
|
|
150
|
+
return `---
|
|
151
|
+
name: "eha-${workflow.commandName}"
|
|
152
|
+
description: "EHA ${workflow.id} — ${workflow.description}"
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
${EHA_COMPACT_RULES}
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
${promptContent}`;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function buildAntigravitySkillFile(skill) {
|
|
163
|
+
return `---
|
|
164
|
+
name: "eha-${skill.commandName}"
|
|
165
|
+
description: "EHA skill — ${skill.commandName}"
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
${EHA_COMPACT_RULES}
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
${loadSkillContent(skill)}`;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function buildAntigravityRuleFile() {
|
|
176
|
+
return `---
|
|
177
|
+
name: "eha-agent-rules"
|
|
178
|
+
description: "EHA agent rules"
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
${loadRuleContent('antigravity')}`;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function buildCopilotInstructionsFile(workflows) {
|
|
185
|
+
const workflowTable = workflows
|
|
186
|
+
.map((w) => `- \`${w.commandName}\` → \`.github/prompts/eha-${w.commandName}.prompt.md\``)
|
|
187
|
+
.join('\n');
|
|
30
188
|
|
|
31
|
-
|
|
189
|
+
return `---
|
|
190
|
+
description: "EHA workflow routing for GitHub Copilot"
|
|
191
|
+
applyTo: "**"
|
|
192
|
+
---
|
|
32
193
|
|
|
33
|
-
|
|
194
|
+
# EHA Workflows
|
|
34
195
|
|
|
35
|
-
|
|
196
|
+
When a user asks to run an EHA workflow, use the matching prompt file below.
|
|
36
197
|
|
|
37
|
-
|
|
38
|
-
- this install generates repo-local instructions, not slash commands
|
|
39
|
-
- bundled contract path: \`${bundledSources.contractPath}\`
|
|
40
|
-
- generated outputs stay inside the repository for transparency
|
|
41
|
-
`;
|
|
198
|
+
${workflowTable}`;
|
|
42
199
|
}
|
|
43
200
|
|
|
44
201
|
const RUNTIME_ADAPTERS = {
|
|
45
202
|
claude: {
|
|
46
203
|
id: 'claude',
|
|
47
204
|
name: 'Claude',
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
generateFiles(rootDir, workflows, bundledSources) {
|
|
205
|
+
description: 'Generates .claude/commands/eha/ slash command files, .claude/skills/ and .claude/rules/',
|
|
206
|
+
generateFiles(rootDir, workflows, skills) {
|
|
51
207
|
const files = [];
|
|
52
208
|
for (const workflow of workflows) {
|
|
53
209
|
files.push({
|
|
54
210
|
relativePath: path.join('.claude', 'commands', 'eha', `eha-${workflow.commandName}.md`),
|
|
55
|
-
content:
|
|
56
|
-
contractPath: bundledSources.contractPath,
|
|
57
|
-
workflowPath: bundledSources.workflowPaths[workflow.repoRelativePath],
|
|
58
|
-
}),
|
|
211
|
+
content: buildClaudeCommandFile(workflow),
|
|
59
212
|
});
|
|
60
213
|
}
|
|
61
|
-
|
|
62
214
|
files.push({
|
|
63
215
|
relativePath: path.join('.claude', 'commands', 'eha', 'README.md'),
|
|
64
|
-
content:
|
|
65
|
-
'# Generated EHA Claude commands\n\nThese files are generated by `eha install` from the canonical workflow registry.\n',
|
|
216
|
+
content: `# EHA Claude commands\n\nGenerated by \`eha init\`. Use \`/eha-bootstrap\`, \`/eha-refresh\`, \`/eha-parity\`, or \`/eha-discuss\` in Claude.\n`,
|
|
66
217
|
});
|
|
67
|
-
|
|
218
|
+
|
|
219
|
+
for (const skill of skills) {
|
|
220
|
+
files.push({
|
|
221
|
+
relativePath: path.join('.claude', 'skills', `eha-${skill.commandName}.md`),
|
|
222
|
+
content: buildClaudeSkillFile(skill),
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
files.push({
|
|
227
|
+
relativePath: path.join('.claude', 'rules', 'eha-agent-rules.md'),
|
|
228
|
+
content: buildClaudeRuleFile(),
|
|
229
|
+
});
|
|
230
|
+
|
|
68
231
|
return files;
|
|
69
232
|
},
|
|
70
233
|
},
|
|
71
234
|
copilot: {
|
|
72
235
|
id: 'copilot',
|
|
73
236
|
name: 'GitHub Copilot',
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
{
|
|
79
|
-
relativePath: path.join('.github', '
|
|
80
|
-
content:
|
|
81
|
-
}
|
|
82
|
-
|
|
237
|
+
description: 'Generates .github/prompts/ reusable prompt files, skills, and always-on instruction rules',
|
|
238
|
+
generateFiles(rootDir, workflows, skills) {
|
|
239
|
+
const files = [];
|
|
240
|
+
for (const workflow of workflows) {
|
|
241
|
+
files.push({
|
|
242
|
+
relativePath: path.join('.github', 'prompts', `eha-${workflow.commandName}.prompt.md`),
|
|
243
|
+
content: buildCopilotPromptFile(workflow),
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
files.push({
|
|
247
|
+
relativePath: path.join('.github', 'instructions', 'eha-workflows.instructions.md'),
|
|
248
|
+
content: buildCopilotInstructionsFile(workflows),
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
for (const skill of skills) {
|
|
252
|
+
files.push({
|
|
253
|
+
relativePath: path.join('.github', 'prompts', 'skills', `eha-${skill.commandName}.prompt.md`),
|
|
254
|
+
content: buildCopilotSkillFile(skill),
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
files.push({
|
|
259
|
+
relativePath: path.join('.github', 'instructions', 'eha-agent-rules.instructions.md'),
|
|
260
|
+
content: buildCopilotRuleFile(),
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
return files;
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
antigravity: {
|
|
267
|
+
id: 'antigravity',
|
|
268
|
+
name: 'Antigravity',
|
|
269
|
+
description: 'Generates Antigravity-compatible skills in .agents/skills/',
|
|
270
|
+
generateFiles(rootDir, workflows, skills) {
|
|
271
|
+
const files = [];
|
|
272
|
+
for (const workflow of workflows) {
|
|
273
|
+
files.push({
|
|
274
|
+
relativePath: path.join('.agents', 'skills', `eha-${workflow.commandName}`, 'SKILL.md'),
|
|
275
|
+
content: buildAntigravityCommandFile(workflow),
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
files.push({
|
|
279
|
+
relativePath: path.join('.agents', 'commands', 'eha', 'README.md'),
|
|
280
|
+
content: `# EHA Antigravity commands\n\nGenerated by \`eha init\`. Call the generated skills directly.\n`,
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
for (const skill of skills) {
|
|
284
|
+
files.push({
|
|
285
|
+
relativePath: path.join('.agents', 'skills', `eha-${skill.commandName}`, 'SKILL.md'),
|
|
286
|
+
content: buildAntigravitySkillFile(skill),
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
files.push({
|
|
291
|
+
relativePath: path.join('.agents', 'skills', 'eha-agent-rules', 'SKILL.md'),
|
|
292
|
+
content: buildAntigravityRuleFile(),
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
return files;
|
|
83
296
|
},
|
|
84
297
|
},
|
|
85
298
|
};
|
|
86
299
|
|
|
87
|
-
function getRuntimeAdapter(
|
|
88
|
-
const adapter = RUNTIME_ADAPTERS[String(
|
|
300
|
+
function getRuntimeAdapter(agentId) {
|
|
301
|
+
const adapter = RUNTIME_ADAPTERS[String(agentId).trim().toLowerCase()];
|
|
89
302
|
if (!adapter) {
|
|
90
|
-
throw new Error(`Unsupported
|
|
303
|
+
throw new Error(`Unsupported agent: ${agentId}. Choose one of: ${Object.keys(RUNTIME_ADAPTERS).join(', ')}.`);
|
|
91
304
|
}
|
|
92
305
|
return adapter;
|
|
93
306
|
}
|
|
94
307
|
|
|
95
308
|
function listSupportedRuntimes() {
|
|
96
|
-
return Object.values(RUNTIME_ADAPTERS).map((
|
|
97
|
-
id:
|
|
98
|
-
|
|
99
|
-
description:
|
|
309
|
+
return Object.values(RUNTIME_ADAPTERS).map((a) => ({
|
|
310
|
+
id: a.id,
|
|
311
|
+
name: a.name,
|
|
312
|
+
description: a.description,
|
|
100
313
|
}));
|
|
101
314
|
}
|
|
102
315
|
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
const path = require('node:path');
|
|
2
|
+
|
|
3
|
+
const SKILL_DEFINITIONS = {
|
|
4
|
+
'system-analysis': {
|
|
5
|
+
id: 'system-analysis',
|
|
6
|
+
commandName: 'system-analysis',
|
|
7
|
+
repoRelativePath: path.join('docs', 'templates', 'skills', 'architecture', 'system-analysis', 'SKILL.md'),
|
|
8
|
+
},
|
|
9
|
+
'api-design': {
|
|
10
|
+
id: 'api-design',
|
|
11
|
+
commandName: 'api-design',
|
|
12
|
+
repoRelativePath: path.join('docs', 'templates', 'skills', 'architecture', 'api-design', 'SKILL.md'),
|
|
13
|
+
},
|
|
14
|
+
'db-schema-design': {
|
|
15
|
+
id: 'db-schema-design',
|
|
16
|
+
commandName: 'db-schema-design',
|
|
17
|
+
repoRelativePath: path.join('docs', 'templates', 'skills', 'architecture', 'db-schema-design', 'SKILL.md'),
|
|
18
|
+
},
|
|
19
|
+
'test-authoring': {
|
|
20
|
+
id: 'test-authoring',
|
|
21
|
+
commandName: 'test-authoring',
|
|
22
|
+
repoRelativePath: path.join('docs', 'templates', 'skills', 'engineering', 'test-authoring', 'SKILL.md'),
|
|
23
|
+
},
|
|
24
|
+
'ui-ux-implementation': {
|
|
25
|
+
id: 'ui-ux-implementation',
|
|
26
|
+
commandName: 'ui-ux-implementation',
|
|
27
|
+
repoRelativePath: path.join('docs', 'templates', 'skills', 'engineering', 'ui-ux-implementation', 'SKILL.md'),
|
|
28
|
+
},
|
|
29
|
+
'refactor-specialist': {
|
|
30
|
+
id: 'refactor-specialist',
|
|
31
|
+
commandName: 'refactor-specialist',
|
|
32
|
+
repoRelativePath: path.join('docs', 'templates', 'skills', 'engineering', 'refactor-specialist', 'SKILL.md'),
|
|
33
|
+
},
|
|
34
|
+
'security-audit': {
|
|
35
|
+
id: 'security-audit',
|
|
36
|
+
commandName: 'security-audit',
|
|
37
|
+
repoRelativePath: path.join('docs', 'templates', 'skills', 'auditing', 'security-audit', 'SKILL.md'),
|
|
38
|
+
},
|
|
39
|
+
'full-verification': {
|
|
40
|
+
id: 'full-verification',
|
|
41
|
+
commandName: 'full-verification',
|
|
42
|
+
repoRelativePath: path.join('docs', 'templates', 'skills', 'auditing', 'full-verification', 'SKILL.md'),
|
|
43
|
+
},
|
|
44
|
+
'parity': {
|
|
45
|
+
id: 'parity',
|
|
46
|
+
commandName: 'parity',
|
|
47
|
+
repoRelativePath: path.join('docs', 'templates', 'skills', 'auditing', 'parity', 'SKILL.md'),
|
|
48
|
+
},
|
|
49
|
+
'ci-cd-authoring': {
|
|
50
|
+
id: 'ci-cd-authoring',
|
|
51
|
+
commandName: 'ci-cd-authoring',
|
|
52
|
+
repoRelativePath: path.join('docs', 'templates', 'skills', 'operations', 'ci-cd-authoring', 'SKILL.md'),
|
|
53
|
+
},
|
|
54
|
+
'observability-setup': {
|
|
55
|
+
id: 'observability-setup',
|
|
56
|
+
commandName: 'observability-setup',
|
|
57
|
+
repoRelativePath: path.join('docs', 'templates', 'skills', 'operations', 'observability-setup', 'SKILL.md'),
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
function listSkills() {
|
|
62
|
+
return Object.values(SKILL_DEFINITIONS).map((skill) => ({ ...skill }));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
module.exports = {
|
|
66
|
+
listSkills,
|
|
67
|
+
};
|
package/src/engine/state.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
const fs = require('node:fs');
|
|
2
2
|
const path = require('node:path');
|
|
3
3
|
|
|
4
|
-
const
|
|
5
|
-
const
|
|
4
|
+
const ROOT_MARKERS = ['package.json', '.git'];
|
|
5
|
+
const DEFAULT_CONFIG = {
|
|
6
|
+
configVersion: 1,
|
|
7
|
+
agent: null,
|
|
8
|
+
};
|
|
6
9
|
|
|
7
10
|
function ensureDir(dirPath) {
|
|
8
11
|
fs.mkdirSync(dirPath, { recursive: true });
|
|
@@ -62,14 +65,31 @@ function getEnginePaths(rootDir) {
|
|
|
62
65
|
const ehaDir = path.join(rootDir, '.eha');
|
|
63
66
|
return {
|
|
64
67
|
ehaDir,
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
configPath: path.join(ehaDir, 'config.json'),
|
|
69
|
+
manifestPath: path.join(ehaDir, 'manifest.json'),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function normalizeConfig(config) {
|
|
74
|
+
const candidate = config && typeof config === 'object' ? config : {};
|
|
75
|
+
return {
|
|
76
|
+
configVersion: Number.isInteger(candidate.configVersion) ? candidate.configVersion : DEFAULT_CONFIG.configVersion,
|
|
77
|
+
agent: candidate.agent ? String(candidate.agent).trim().toLowerCase() : null,
|
|
70
78
|
};
|
|
71
79
|
}
|
|
72
80
|
|
|
81
|
+
function readConfig(rootDir) {
|
|
82
|
+
const { configPath } = getEnginePaths(rootDir);
|
|
83
|
+
return normalizeConfig(readJsonIfExists(configPath) || DEFAULT_CONFIG);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function writeConfig(rootDir, value) {
|
|
87
|
+
const { configPath } = getEnginePaths(rootDir);
|
|
88
|
+
const normalizedConfig = normalizeConfig(value);
|
|
89
|
+
writeJson(configPath, normalizedConfig);
|
|
90
|
+
return normalizedConfig;
|
|
91
|
+
}
|
|
92
|
+
|
|
73
93
|
function removeFileIfExists(filePath) {
|
|
74
94
|
if (fs.existsSync(filePath)) {
|
|
75
95
|
fs.unlinkSync(filePath);
|
|
@@ -101,9 +121,11 @@ module.exports = {
|
|
|
101
121
|
getBundledAssetPath,
|
|
102
122
|
getEnginePaths,
|
|
103
123
|
getPackageRoot,
|
|
124
|
+
readConfig,
|
|
104
125
|
readJsonIfExists,
|
|
105
126
|
removeEmptyParents,
|
|
106
127
|
removeFileIfExists,
|
|
128
|
+
writeConfig,
|
|
107
129
|
writeJson,
|
|
108
130
|
writeText,
|
|
109
131
|
};
|
|
@@ -4,45 +4,36 @@ const WORKFLOW_DEFINITIONS = {
|
|
|
4
4
|
bootstrap: {
|
|
5
5
|
id: 'bootstrap',
|
|
6
6
|
commandName: 'bootstrap',
|
|
7
|
-
description: '
|
|
8
|
-
repoRelativePath: path.join('docs', '
|
|
7
|
+
description: 'Generate the initial project documentation set',
|
|
8
|
+
repoRelativePath: path.join('docs', 'templates', 'reusable-prompts', '00-project-docs-bootstrap.md'),
|
|
9
9
|
},
|
|
10
10
|
refresh: {
|
|
11
11
|
id: 'refresh',
|
|
12
12
|
commandName: 'refresh',
|
|
13
|
-
description: '
|
|
14
|
-
repoRelativePath: path.join('docs', '
|
|
13
|
+
description: 'Refresh project docs after a change in scope, stack, or behavior',
|
|
14
|
+
repoRelativePath: path.join('docs', 'templates', 'reusable-prompts', '00-project-docs-refresh.md'),
|
|
15
15
|
},
|
|
16
16
|
parity: {
|
|
17
17
|
id: 'parity',
|
|
18
18
|
commandName: 'parity',
|
|
19
|
-
description: '
|
|
20
|
-
repoRelativePath: path.join('docs', '
|
|
19
|
+
description: 'Audit for documentation drift and ownership mismatches',
|
|
20
|
+
repoRelativePath: path.join('docs', 'templates', 'reusable-prompts', '00-project-docs-parity.md'),
|
|
21
21
|
},
|
|
22
22
|
discuss: {
|
|
23
23
|
id: 'discuss',
|
|
24
24
|
commandName: 'discuss',
|
|
25
|
-
description: '
|
|
26
|
-
repoRelativePath: path.join('docs', '
|
|
25
|
+
description: 'Brainstorm and finalize a feature spec before implementation',
|
|
26
|
+
repoRelativePath: path.join('docs', 'templates', 'reusable-prompts', '02-sdd-discuss.md'),
|
|
27
27
|
},
|
|
28
|
-
execute: {
|
|
29
|
-
id: 'execute',
|
|
30
|
-
commandName: 'execute',
|
|
31
|
-
description: '
|
|
32
|
-
repoRelativePath: path.join('docs', '
|
|
33
|
-
},
|
|
34
|
-
verify: {
|
|
35
|
-
id: 'verify',
|
|
36
|
-
commandName: 'verify',
|
|
37
|
-
description: 'Prepare the verification workflow',
|
|
38
|
-
repoRelativePath: path.join('docs', 'vibes', 'reusable-prompts', '00-project-docs-parity.md'),
|
|
39
|
-
capabilityNote: 'A dedicated verify workflow does not exist yet; verify currently routes to the parity workflow.',
|
|
28
|
+
'sdd-execute': {
|
|
29
|
+
id: 'sdd-execute',
|
|
30
|
+
commandName: 'sdd-execute',
|
|
31
|
+
description: 'Translate a project specification into tested, working code',
|
|
32
|
+
repoRelativePath: path.join('docs', 'templates', 'reusable-prompts', '01-sdd-execute.md'),
|
|
40
33
|
},
|
|
41
34
|
};
|
|
42
35
|
|
|
43
|
-
const WORKFLOW_ALIASES = {
|
|
44
|
-
init: 'bootstrap',
|
|
45
|
-
};
|
|
36
|
+
const WORKFLOW_ALIASES = {};
|
|
46
37
|
|
|
47
38
|
function normalizeWorkflowId(input) {
|
|
48
39
|
if (!input) {
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Run the EHA bootstrap workflow"
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Read `docs/eyehateagent-contract.md` first.
|
|
6
|
-
|
|
7
|
-
Execute `docs/vibes/reusable-prompts/00-project-docs-bootstrap.md`.
|
|
8
|
-
|
|
9
|
-
If the user provides additional context, apply it while preserving the workflow's output contract and the owning-doc rules in `docs/project-docs/`.
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Run the EHA discuss workflow"
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Read `docs/eyehateagent-contract.md` first.
|
|
6
|
-
|
|
7
|
-
Execute `docs/vibes/reusable-prompts/02-sdd-discuss.md`.
|
|
8
|
-
|
|
9
|
-
If the user provides additional context, apply it while preserving the workflow's output contract and the owning-doc rules in `docs/project-docs/`.
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Run the EHA execute workflow"
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Read `docs/eyehateagent-contract.md` first.
|
|
6
|
-
|
|
7
|
-
Execute `docs/vibes/reusable-prompts/01-sdd-execute.md`.
|
|
8
|
-
|
|
9
|
-
If the user provides additional context, apply it while preserving the workflow's output contract and the owning-doc rules in `docs/project-docs/`.
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Run the EHA parity workflow"
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Read `docs/eyehateagent-contract.md` first.
|
|
6
|
-
|
|
7
|
-
Execute `docs/vibes/reusable-prompts/00-project-docs-parity.md`.
|
|
8
|
-
|
|
9
|
-
If the user provides additional context, apply it while preserving the workflow's output contract and the owning-doc rules in `docs/project-docs/`.
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Run the EHA refresh workflow"
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Read `docs/eyehateagent-contract.md` first.
|
|
6
|
-
|
|
7
|
-
Execute `docs/vibes/reusable-prompts/00-project-docs-refresh.md`.
|
|
8
|
-
|
|
9
|
-
If the user provides additional context, apply it while preserving the workflow's output contract and the owning-doc rules in `docs/project-docs/`.
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Run the EHA verify workflow"
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Read `docs/eyehateagent-contract.md` first.
|
|
6
|
-
|
|
7
|
-
Execute `docs/vibes/reusable-prompts/00-project-docs-parity.md`.
|
|
8
|
-
|
|
9
|
-
If the user provides additional context, apply it while preserving the workflow's output contract and the owning-doc rules in `docs/project-docs/`.
|