@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.
Files changed (89) hide show
  1. package/README.md +38 -310
  2. package/bin/eha.js +203 -118
  3. package/docs/templates/project-docs-template/foundation/architecture.md +79 -0
  4. package/docs/templates/project-docs-template/foundation/changelog.md +53 -0
  5. package/docs/templates/project-docs-template/foundation/feature-inventory.md +46 -0
  6. package/docs/templates/project-docs-template/foundation/phases.md +60 -0
  7. package/docs/templates/project-docs-template/foundation/prd.md +69 -0
  8. package/docs/templates/project-docs-template/foundation/status.md +57 -0
  9. package/docs/templates/project-docs-template/foundation/workflow.md +59 -0
  10. package/docs/templates/project-docs-template/getting-started.md +52 -0
  11. package/docs/{vibes → templates}/project-docs-template/index.md +12 -12
  12. package/docs/templates/project-docs-template/operations/ci-cd.md +56 -0
  13. package/docs/templates/project-docs-template/operations/compliance.md +46 -0
  14. package/docs/templates/project-docs-template/operations/governance.md +46 -0
  15. package/docs/templates/project-docs-template/operations/observability.md +53 -0
  16. package/docs/templates/project-docs-template/operations/production-runbook.md +62 -0
  17. package/docs/templates/project-docs-template/operations/security.md +49 -0
  18. package/docs/templates/project-docs-template/technical/api-contract.md +49 -0
  19. package/docs/templates/project-docs-template/technical/database.md +59 -0
  20. package/docs/templates/project-docs-template/technical/error-handling.md +54 -0
  21. package/docs/templates/project-docs-template/technical/internationalization.md +46 -0
  22. package/docs/templates/project-docs-template/technical/testing.md +57 -0
  23. package/docs/templates/project-docs-template/technical/ui-ux.md +68 -0
  24. package/docs/{vibes → templates}/project-docs-template/technical-guidelines/index.md +3 -3
  25. package/docs/{vibes → templates}/reusable-prompts/00-project-docs-bootstrap.md +2 -4
  26. package/docs/{vibes → templates}/reusable-prompts/00-project-docs-parity.md +3 -5
  27. package/docs/{vibes → templates}/reusable-prompts/00-project-docs-refresh.md +2 -4
  28. package/docs/{vibes → templates}/reusable-prompts/02-sdd-discuss.md +2 -2
  29. package/{.agents/rules/agent.md → docs/templates/rules/agent-rules.md} +6 -11
  30. package/docs/templates/skills/architecture/db-schema-design/SKILL.md +14 -0
  31. package/docs/{vibes/skills → templates/skills/auditing}/full-verification/SKILL.md +1 -1
  32. package/docs/{vibes/skills → templates/skills/auditing}/parity/SKILL.md +2 -2
  33. package/docs/templates/skills/engineering/refactor-specialist/SKILL.md +13 -0
  34. package/docs/{vibes/skills → templates/skills/engineering}/test-authoring/SKILL.md +177 -1
  35. package/docs/templates/skills/engineering/ui-ux-implementation/SKILL.md +13 -0
  36. package/docs/templates/skills/operations/ci-cd-authoring/SKILL.md +13 -0
  37. package/docs/templates/skills/operations/observability-setup/SKILL.md +13 -0
  38. package/package.json +4 -6
  39. package/src/engine/index.js +7 -12
  40. package/src/engine/install.js +67 -163
  41. package/src/engine/runtime-adapters.js +263 -50
  42. package/src/engine/skill-registry.js +67 -0
  43. package/src/engine/state.js +29 -7
  44. package/src/engine/workflow-registry.js +14 -23
  45. package/.claude/commands/eha/README.md +0 -3
  46. package/.claude/commands/eha/eha-bootstrap.md +0 -9
  47. package/.claude/commands/eha/eha-discuss.md +0 -9
  48. package/.claude/commands/eha/eha-execute.md +0 -9
  49. package/.claude/commands/eha/eha-parity.md +0 -9
  50. package/.claude/commands/eha/eha-refresh.md +0 -9
  51. package/.claude/commands/eha/eha-verify.md +0 -9
  52. package/.claude/rules/agent-rules.md +0 -64
  53. package/.github/instructions/agent-rules.instructions.md +0 -63
  54. package/.github/instructions/eha-workflows.instructions.md +0 -21
  55. package/docs/eyehateagent-contract.md +0 -475
  56. package/docs/eyehateagent-maintenance.md +0 -103
  57. package/docs/project-docs/changelog.md +0 -299
  58. package/docs/project-docs/foundation/architecture.md +0 -117
  59. package/docs/project-docs/foundation/status.md +0 -32
  60. package/docs/project-docs/foundation/workflow.md +0 -63
  61. package/docs/project-docs/index.md +0 -20
  62. package/docs/project-docs/testing.md +0 -73
  63. package/docs/vibes/project-docs-template/foundation/architecture.md +0 -79
  64. package/docs/vibes/project-docs-template/foundation/changelog.md +0 -53
  65. package/docs/vibes/project-docs-template/foundation/feature-inventory.md +0 -46
  66. package/docs/vibes/project-docs-template/foundation/phases.md +0 -60
  67. package/docs/vibes/project-docs-template/foundation/prd.md +0 -69
  68. package/docs/vibes/project-docs-template/foundation/status.md +0 -57
  69. package/docs/vibes/project-docs-template/foundation/workflow.md +0 -59
  70. package/docs/vibes/project-docs-template/getting-started.md +0 -52
  71. package/docs/vibes/project-docs-template/operations/ci-cd.md +0 -56
  72. package/docs/vibes/project-docs-template/operations/compliance.md +0 -46
  73. package/docs/vibes/project-docs-template/operations/governance.md +0 -46
  74. package/docs/vibes/project-docs-template/operations/observability.md +0 -53
  75. package/docs/vibes/project-docs-template/operations/production-runbook.md +0 -62
  76. package/docs/vibes/project-docs-template/operations/security.md +0 -49
  77. package/docs/vibes/project-docs-template/technical/api-contract.md +0 -49
  78. package/docs/vibes/project-docs-template/technical/database.md +0 -59
  79. package/docs/vibes/project-docs-template/technical/error-handling.md +0 -54
  80. package/docs/vibes/project-docs-template/technical/internationalization.md +0 -46
  81. package/docs/vibes/project-docs-template/technical/testing.md +0 -57
  82. package/docs/vibes/project-docs-template/technical/ui-ux.md +0 -68
  83. package/docs/vibes/skills/project-elevation/SKILL.md +0 -157
  84. package/docs/vibes/skills/test-authoring/references/patterns.md +0 -116
  85. package/docs/vibes/skills/test-authoring/references/test-types.md +0 -52
  86. /package/docs/{vibes → templates}/reusable-prompts/01-sdd-execute.md +0 -0
  87. /package/docs/{vibes/skills → templates/skills/architecture}/api-design/SKILL.md +0 -0
  88. /package/docs/{vibes/skills/analysis → templates/skills/architecture/system-analysis}/SKILL.md +0 -0
  89. /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
- function renderClaudeCommand(workflow, sourcePaths) {
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: "Run the EHA ${workflow.id} workflow"
82
+ description: "EHA ${workflow.id} — ${workflow.description}"
6
83
  ---
7
84
 
8
- Read \`${sourcePaths.contractPath}\` first.
85
+ ${EHA_COMPACT_RULES}
9
86
 
10
- Execute \`${sourcePaths.workflowPath}\`.
87
+ ---
11
88
 
12
- If the user provides additional context, apply it while preserving the workflow's output contract and the owning-doc rules in \`docs/project-docs/\`.
13
- `;
89
+ ${promptContent}`;
14
90
  }
15
91
 
16
- function renderCopilotInstructions(workflows, bundledSources) {
17
- const workflowTable = workflows
18
- .map(
19
- (workflow) =>
20
- `- \`${workflow.commandName}\` -> \`${bundledSources.workflowPaths[workflow.repoRelativePath]}\`${workflow.capabilityNote ? ` (${workflow.capabilityNote})` : ''}`,
21
- )
22
- .join('\n');
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: "Generated EHA workflow routing for GitHub Copilot"
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
- # EHA Engine Workflows
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
- When a user asks to run an EHA workflow, prefer the canonical reusable prompt file listed below and preserve its output contract.
189
+ return `---
190
+ description: "EHA workflow routing for GitHub Copilot"
191
+ applyTo: "**"
192
+ ---
32
193
 
33
- ${workflowTable}
194
+ # EHA Workflows
34
195
 
35
- ## Runtime support
196
+ When a user asks to run an EHA workflow, use the matching prompt file below.
36
197
 
37
- - GitHub Copilot support tier is **guided**
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
- supportTier: 'full',
49
- description: 'Repo-local Claude command projection under .claude/commands/eha/',
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: renderClaudeCommand(workflow, {
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
- supportTier: 'guided',
75
- description: 'Repo-local Copilot instruction projection under .github/instructions/',
76
- generateFiles(rootDir, workflows, bundledSources) {
77
- return [
78
- {
79
- relativePath: path.join('.github', 'instructions', 'eha-workflows.instructions.md'),
80
- content: renderCopilotInstructions(workflows, bundledSources),
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(runtimeId) {
88
- const adapter = RUNTIME_ADAPTERS[String(runtimeId).trim().toLowerCase()];
300
+ function getRuntimeAdapter(agentId) {
301
+ const adapter = RUNTIME_ADAPTERS[String(agentId).trim().toLowerCase()];
89
302
  if (!adapter) {
90
- throw new Error(`Unsupported runtime: ${runtimeId}`);
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((runtime) => ({
97
- id: runtime.id,
98
- supportTier: runtime.supportTier,
99
- description: runtime.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
+ };
@@ -1,8 +1,11 @@
1
1
  const fs = require('node:fs');
2
2
  const path = require('node:path');
3
3
 
4
- const CONTRACT_PATH = path.join('docs', 'eyehateagent-contract.md');
5
- const ROOT_MARKERS = [CONTRACT_PATH, 'package.json', '.git'];
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
- stateDir: path.join(ehaDir, 'state'),
66
- generatedDir: path.join(ehaDir, 'generated'),
67
- manifestPath: path.join(ehaDir, 'generated', 'install-manifest.json'),
68
- lastRunPath: path.join(ehaDir, 'state', 'last-run.json'),
69
- lastPromptPath: path.join(ehaDir, 'state', 'last-prompt.md'),
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: 'Prepare the bootstrap workflow for creating project docs',
8
- repoRelativePath: path.join('docs', 'vibes', 'reusable-prompts', '00-project-docs-bootstrap.md'),
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: 'Prepare the refresh workflow for owner-doc updates',
14
- repoRelativePath: path.join('docs', 'vibes', 'reusable-prompts', '00-project-docs-refresh.md'),
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: 'Prepare the parity workflow for ownership and drift checks',
20
- repoRelativePath: path.join('docs', 'vibes', 'reusable-prompts', '00-project-docs-parity.md'),
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: 'Prepare the spec-discussion workflow',
26
- repoRelativePath: path.join('docs', 'vibes', 'reusable-prompts', '02-sdd-discuss.md'),
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: 'Prepare the spec-driven execution workflow',
32
- repoRelativePath: path.join('docs', 'vibes', 'reusable-prompts', '01-sdd-execute.md'),
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,3 +0,0 @@
1
- # Generated EHA Claude commands
2
-
3
- These files are generated by `eha install` from the canonical workflow registry.
@@ -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/`.