mirror of
https://github.com/JuliusBrussee/caveman.git
synced 2026-08-11 13:21:09 +02:00
feat(install): add Hermes Agent support
Adds Hermes Agent as a supported provider with native skill installation. Hermes Agent uses SKILL.md format (same as upstream), so the installer copies all 7 caveman skills directly to ~/.hermes/skills/productivity/. Closes #45914 (related)
This commit is contained in:
+64
-5
@@ -228,7 +228,8 @@ const PROVIDERS = [
|
||||
// CLI agents — require the binary. The `||dir:~/.foo` fallbacks were the
|
||||
// main source of false positives (warp, kiro, junie etc. leave config dirs
|
||||
// behind on uninstall).
|
||||
{ id: 'aider-desk', label: 'Aider Desk', mech: 'npx skills add (aider-desk)', detect: 'command:aider', profile: 'aider-desk' },
|
||||
{ id: 'hermes', label: 'Hermes Agent', mech: 'npx skills add (hermes)', detect: 'command:hermes', profile: 'hermes' },
|
||||
{ id: 'aider-desk', label: 'Aider Desk', mech: 'npx skills add (aider-desk)', detect: 'command:aider', profile: 'aider-desk' },
|
||||
{ id: 'amp', label: 'Sourcegraph Amp', mech: 'npx skills add (amp)', detect: 'command:amp', profile: 'amp' },
|
||||
{ id: 'bob', label: 'IBM Bob', mech: 'npx skills add (bob)', detect: 'command:bob', profile: 'bob' },
|
||||
{ id: 'crush', label: 'Crush', mech: 'npx skills add (crush)', detect: 'command:crush', profile: 'crush' },
|
||||
@@ -560,6 +561,63 @@ function installViaSkills(ctx, prov) {
|
||||
process.stdout.write('\n');
|
||||
}
|
||||
|
||||
// ── hermes native install ──────────────────────────────────────────────────
|
||||
// Drops the caveman skills into ~/.hermes/skills/productivity/ (or HERMES_HOME if set).
|
||||
const HERMES_SKILL_DIRS = ['caveman', 'caveman-commit', 'caveman-review', 'caveman-help', 'caveman-stats', 'caveman-compress', 'cavecrew'];
|
||||
|
||||
function hermesConfigDir() {
|
||||
// Hermes uses ~/.hermes by default, or HERMES_HOME env var.
|
||||
if (process.env.HERMES_HOME) return path.join(process.env.HERMES_HOME, 'skills');
|
||||
return path.join(os.homedir(), '.hermes', 'skills');
|
||||
}
|
||||
|
||||
function installHermes(ctx) {
|
||||
const { say, note, warn, opts, repoRoot, results } = ctx;
|
||||
results.detected++;
|
||||
say('→ Hermes Agent detected');
|
||||
|
||||
if (!repoRoot) {
|
||||
warn(' Hermes native install requires a local clone of the caveman repo.');
|
||||
note(' Re-run from a clone: git clone https://github.com/' + REPO + ' && cd caveman && node bin/install.js --only hermes');
|
||||
results.failed.push(['hermes', 'native install requires local repo clone']);
|
||||
process.stdout.write('\n');
|
||||
return;
|
||||
}
|
||||
|
||||
const skillsRoot = path.join(hermesConfigDir(), 'productivity');
|
||||
|
||||
if (opts.dryRun) {
|
||||
note(` would mkdir ${skillsRoot}/`);
|
||||
note(` would copy ${HERMES_SKILL_DIRS.length} skill dirs into ${skillsRoot}/`);
|
||||
results.installed.push('hermes');
|
||||
process.stdout.write('\n');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
fs.mkdirSync(skillsRoot, { recursive: true });
|
||||
|
||||
for (const skillDir of HERMES_SKILL_DIRS) {
|
||||
const srcDir = path.join(repoRoot, 'skills', skillDir);
|
||||
const destDir = path.join(skillsRoot, skillDir);
|
||||
if (fs.existsSync(srcDir)) {
|
||||
// Remove existing to ensure clean copy
|
||||
if (fs.existsSync(destDir)) fs.rmSync(destDir, { recursive: true, force: true });
|
||||
copyDirRecursive(srcDir, destDir);
|
||||
note(` copied ${skillDir} → ${destDir}`);
|
||||
} else {
|
||||
warn(` skill dir not found: ${srcDir}`);
|
||||
}
|
||||
}
|
||||
|
||||
results.installed.push('hermes');
|
||||
} catch (err) {
|
||||
results.failed.push(['hermes', 'copy failed: ' + err.message]);
|
||||
}
|
||||
|
||||
process.stdout.write('\n');
|
||||
}
|
||||
|
||||
// ── opencode native install ───────────────────────────────────────────────
|
||||
// Drops the in-repo plugin (src/plugins/opencode/) plus skills, agents,
|
||||
// commands, and an AGENTS.md ruleset into ~/.config/opencode/. Patches
|
||||
@@ -1340,10 +1398,11 @@ async function main() {
|
||||
// missing without --force).
|
||||
if (!explicit(prov.id) && !detectMatch(prov.detect)) continue;
|
||||
if (prov.id === 'claude') { await installClaude(ctx); continue; }
|
||||
if (prov.id === 'gemini') { installGemini(ctx); continue; }
|
||||
if (prov.id === 'opencode') { installOpencode(ctx); continue; }
|
||||
if (prov.id === 'openclaw') { installOpenclaw(ctx); continue; }
|
||||
if (prov.profile) { installViaSkills(ctx, prov); continue; }
|
||||
if (prov.id === 'gemini') { installGemini(ctx); continue; }
|
||||
if (prov.id === 'opencode') { installOpencode(ctx); continue; }
|
||||
if (prov.id === 'openclaw') { installOpenclaw(ctx); continue; }
|
||||
if (prov.id === 'hermes') { installHermes(ctx); continue; }
|
||||
if (prov.profile) { installViaSkills(ctx, prov); continue; }
|
||||
}
|
||||
|
||||
// Auto-detect fallback if nothing matched
|
||||
|
||||
Reference in New Issue
Block a user