hermes-action-bridge 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -0
- package/CONTRIBUTING.md +28 -0
- package/LICENSE +21 -0
- package/README.md +323 -0
- package/dist/adapters/hermes-cli.d.ts +3 -0
- package/dist/adapters/hermes-cli.js +48 -0
- package/dist/adapters/hermes-cli.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +271 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.js +172 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +2 -0
- package/dist/context.js +15 -0
- package/dist/context.js.map +1 -0
- package/dist/doctor.d.ts +18 -0
- package/dist/doctor.js +77 -0
- package/dist/doctor.js.map +1 -0
- package/dist/install/file-edit.d.ts +12 -0
- package/dist/install/file-edit.js +18 -0
- package/dist/install/file-edit.js.map +1 -0
- package/dist/install/install-service.d.ts +26 -0
- package/dist/install/install-service.js +59 -0
- package/dist/install/install-service.js.map +1 -0
- package/dist/install/managed-file.d.ts +9 -0
- package/dist/install/managed-file.js +157 -0
- package/dist/install/managed-file.js.map +1 -0
- package/dist/install/marker-block.d.ts +10 -0
- package/dist/install/marker-block.js +61 -0
- package/dist/install/marker-block.js.map +1 -0
- package/dist/install/mcp-config.d.ts +15 -0
- package/dist/install/mcp-config.js +65 -0
- package/dist/install/mcp-config.js.map +1 -0
- package/dist/install/paths.d.ts +6 -0
- package/dist/install/paths.js +22 -0
- package/dist/install/paths.js.map +1 -0
- package/dist/install/templates.d.ts +16 -0
- package/dist/install/templates.js +86 -0
- package/dist/install/templates.js.map +1 -0
- package/dist/install/types.d.ts +18 -0
- package/dist/install/types.js +2 -0
- package/dist/install/types.js.map +1 -0
- package/dist/mcp-server.d.ts +1 -0
- package/dist/mcp-server.js +69 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/policy.d.ts +9 -0
- package/dist/policy.js +25 -0
- package/dist/policy.js.map +1 -0
- package/dist/prompt.d.ts +2 -0
- package/dist/prompt.js +34 -0
- package/dist/prompt.js.map +1 -0
- package/dist/run.d.ts +2 -0
- package/dist/run.js +27 -0
- package/dist/run.js.map +1 -0
- package/dist/status.d.ts +8 -0
- package/dist/status.js +10 -0
- package/dist/status.js.map +1 -0
- package/dist/types.d.ts +77 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +12 -0
- package/dist/version.js.map +1 -0
- package/docs/ARCHITECTURE.md +105 -0
- package/docs/FUNCTIONAL-TESTS.md +97 -0
- package/examples/claude-code/CLAUDE.md +21 -0
- package/examples/claude-code/SKILL.md +55 -0
- package/examples/codex/AGENTS.md +21 -0
- package/examples/codex/SKILL.md +55 -0
- package/examples/configs/basic.yaml +36 -0
- package/examples/configs/strict.yaml +26 -0
- package/examples/configs/yolo.yaml +19 -0
- package/package.json +59 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { loadConfig } from "./config.js";
|
|
5
|
+
import { buildEffectiveRun } from "./run.js";
|
|
6
|
+
import { runHermesCli } from "./adapters/hermes-cli.js";
|
|
7
|
+
import { checkHermesStatus } from "./status.js";
|
|
8
|
+
import { version } from "./version.js";
|
|
9
|
+
const modeSchema = z.enum(["plan", "draft", "execute", "request-approval"]);
|
|
10
|
+
async function delegate(config, options) {
|
|
11
|
+
const dryRun = options.dryRun ?? false;
|
|
12
|
+
const run = buildEffectiveRun(config, {
|
|
13
|
+
prompt: options.prompt,
|
|
14
|
+
mode: options.mode,
|
|
15
|
+
preset: options.preset,
|
|
16
|
+
contextFiles: options.contextFiles ?? [],
|
|
17
|
+
yolo: options.yolo ?? false,
|
|
18
|
+
dryRun,
|
|
19
|
+
json: false,
|
|
20
|
+
});
|
|
21
|
+
const result = await runHermesCli(config, run, dryRun);
|
|
22
|
+
const sections = [result.stdout, result.stderr].filter((section) => section.trim().length > 0);
|
|
23
|
+
const text = sections.length > 0 ? sections.join("\n") : `Hermes exited with code ${result.exitCode}`;
|
|
24
|
+
const content = [{ type: "text", text }];
|
|
25
|
+
return result.ok ? { content } : { content, isError: true };
|
|
26
|
+
}
|
|
27
|
+
export async function startMcpServer(configPath) {
|
|
28
|
+
const config = loadConfig(process.cwd(), configPath);
|
|
29
|
+
const server = new McpServer({ name: "hermes-action-bridge", version });
|
|
30
|
+
server.registerTool("hermes_run", {
|
|
31
|
+
title: "Delegate a request to Hermes",
|
|
32
|
+
description: "Run Hermes through the configured hermes-action-bridge policy and presets.",
|
|
33
|
+
inputSchema: {
|
|
34
|
+
prompt: z.string().min(1),
|
|
35
|
+
mode: modeSchema.optional(),
|
|
36
|
+
preset: z.string().optional(),
|
|
37
|
+
contextFiles: z.array(z.string()).optional(),
|
|
38
|
+
yolo: z.boolean().optional(),
|
|
39
|
+
dryRun: z.boolean().optional(),
|
|
40
|
+
},
|
|
41
|
+
}, (args) => delegate(config, {
|
|
42
|
+
prompt: args.prompt,
|
|
43
|
+
mode: args.mode,
|
|
44
|
+
preset: args.preset,
|
|
45
|
+
contextFiles: args.contextFiles,
|
|
46
|
+
yolo: args.yolo,
|
|
47
|
+
dryRun: args.dryRun,
|
|
48
|
+
}));
|
|
49
|
+
server.registerTool("hermes_plan", {
|
|
50
|
+
title: "Ask Hermes for a plan",
|
|
51
|
+
description: "Shortcut for hermes_run with mode=plan.",
|
|
52
|
+
inputSchema: { prompt: z.string().min(1), preset: z.string().optional(), contextFiles: z.array(z.string()).optional() },
|
|
53
|
+
}, (args) => delegate(config, {
|
|
54
|
+
prompt: args.prompt,
|
|
55
|
+
mode: "plan",
|
|
56
|
+
preset: args.preset,
|
|
57
|
+
contextFiles: args.contextFiles,
|
|
58
|
+
}));
|
|
59
|
+
server.registerTool("hermes_presets", {
|
|
60
|
+
title: "List presets",
|
|
61
|
+
description: "List configured hermes-action-bridge presets.",
|
|
62
|
+
}, () => ({ content: [{ type: "text", text: JSON.stringify(config.presets, null, 2) }] }));
|
|
63
|
+
server.registerTool("hermes_status", {
|
|
64
|
+
title: "Check Hermes runtime status",
|
|
65
|
+
description: "Check whether the configured Hermes command is available.",
|
|
66
|
+
}, () => ({ content: [{ type: "text", text: JSON.stringify(checkHermesStatus(config), null, 2) }] }));
|
|
67
|
+
await server.connect(new StdioServerTransport());
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=mcp-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"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"}
|
package/dist/policy.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { BridgeMode, PolicyConfig, RiskCategory } from "./types.js";
|
|
2
|
+
export interface PolicyDecision {
|
|
3
|
+
mode: BridgeMode;
|
|
4
|
+
requestedMode: BridgeMode;
|
|
5
|
+
detectedRisks: RiskCategory[];
|
|
6
|
+
approvalRequired: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function detectRisks(text: string): RiskCategory[];
|
|
9
|
+
export declare function applyPolicy(requestedMode: BridgeMode, policy: PolicyConfig, prompt: string, yoloFlag: boolean): PolicyDecision;
|
package/dist/policy.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const riskMatchers = [
|
|
2
|
+
{ risk: "publish_external", pattern: /\b(publish|post|tweet|linkedin|reddit|x\.com|twitter|social)\b/i },
|
|
3
|
+
{ risk: "send_message", pattern: /\b(send|message|dm|discord|telegram|slack|whatsapp|sms)\b/i },
|
|
4
|
+
{ risk: "send_email", pattern: /\b(email|e-mail|gmail|send mail|reply to)\b/i },
|
|
5
|
+
{ risk: "delete", pattern: /\b(delete|remove|destroy|drop|wipe|rm\s+-rf)\b/i },
|
|
6
|
+
{ risk: "payment", pattern: /\b(pay|payment|purchase|buy|subscribe|credit card|checkout)\b/i },
|
|
7
|
+
{ risk: "git_push", pattern: /\b(git push|push to|publish branch|create repo|gh repo create)\b/i },
|
|
8
|
+
{ risk: "credential_change", pattern: /\b(token|secret|api key|credential|password|oauth|keychain)\b/i },
|
|
9
|
+
];
|
|
10
|
+
export function detectRisks(text) {
|
|
11
|
+
const risks = new Set();
|
|
12
|
+
for (const matcher of riskMatchers) {
|
|
13
|
+
if (matcher.pattern.test(text))
|
|
14
|
+
risks.add(matcher.risk);
|
|
15
|
+
}
|
|
16
|
+
return [...risks];
|
|
17
|
+
}
|
|
18
|
+
export function applyPolicy(requestedMode, policy, prompt, yoloFlag) {
|
|
19
|
+
const detectedRisks = detectRisks(prompt);
|
|
20
|
+
const yolo = yoloFlag || policy.yolo;
|
|
21
|
+
const approvalRequired = !yolo && detectedRisks.some((risk) => policy.requireApprovalFor.includes(risk));
|
|
22
|
+
const mode = approvalRequired && requestedMode === "execute" ? "request-approval" : requestedMode;
|
|
23
|
+
return { mode, requestedMode, detectedRisks, approvalRequired };
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAEA,MAAM,YAAY,GAAmD;IACnE,EAAE,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,iEAAiE,EAAE;IACxG,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,4DAA4D,EAAE;IAC/F,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,8CAA8C,EAAE;IAC/E,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,iDAAiD,EAAE;IAC9E,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,gEAAgE,EAAE;IAC9F,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,mEAAmE,EAAE;IAClG,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,gEAAgE,EAAE;CACzG,CAAC;AASF,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAgB,CAAC;IACtC,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE,CAAC;QACnC,IAAI,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,aAAyB,EAAE,MAAoB,EAAE,MAAc,EAAE,QAAiB;IAC5G,MAAM,aAAa,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC;IACrC,MAAM,gBAAgB,GAAG,CAAC,IAAI,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,kBAAkB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IACzG,MAAM,IAAI,GAAG,gBAAgB,IAAI,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,aAAa,CAAC;IAClG,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,CAAC;AAClE,CAAC"}
|
package/dist/prompt.d.ts
ADDED
package/dist/prompt.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export function buildHermesPrompt(run) {
|
|
2
|
+
const contextBlock = run.contextDocuments.length
|
|
3
|
+
? run.contextDocuments
|
|
4
|
+
.map((doc) => `<context path="${escapeAttribute(doc.path)}">\n${doc.content}\n</context>`)
|
|
5
|
+
.join("\n\n")
|
|
6
|
+
: "<context>None provided.</context>";
|
|
7
|
+
return [
|
|
8
|
+
"You are Hermes Agent being called by an external agent through hermes-action-bridge.",
|
|
9
|
+
"",
|
|
10
|
+
`Mode: ${run.mode}`,
|
|
11
|
+
`Requested mode: ${run.requestedMode}`,
|
|
12
|
+
`Preset: ${run.presetName}`,
|
|
13
|
+
`YOLO: ${run.yolo ? "enabled" : "disabled"}`,
|
|
14
|
+
`Detected risks: ${run.detectedRisks.length ? run.detectedRisks.join(", ") : "none"}`,
|
|
15
|
+
"",
|
|
16
|
+
"Policy:",
|
|
17
|
+
"- Follow the user's request using the tools and skills available in this Hermes session.",
|
|
18
|
+
"- If Mode is plan, return a plan only. Do not perform side effects.",
|
|
19
|
+
"- If Mode is draft, produce the requested artifact only. Do not perform external side effects.",
|
|
20
|
+
"- If Mode is request-approval, prepare the action and explicitly ask the human for approval before irreversible external effects.",
|
|
21
|
+
"- If Mode is execute, perform allowed actions, but still obey Hermes' own safety rules and any platform approval prompts.",
|
|
22
|
+
"- Never reveal secrets. Do not print API keys, OAuth tokens, passwords, private keys, or session cookies.",
|
|
23
|
+
"",
|
|
24
|
+
"External agent request:",
|
|
25
|
+
run.prompt,
|
|
26
|
+
"",
|
|
27
|
+
"Context files:",
|
|
28
|
+
contextBlock,
|
|
29
|
+
].join("\n");
|
|
30
|
+
}
|
|
31
|
+
function escapeAttribute(value) {
|
|
32
|
+
return value.replaceAll("&", "&").replaceAll('"', """).replaceAll("<", "<");
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,iBAAiB,CAAC,GAAiB;IACjD,MAAM,YAAY,GAAG,GAAG,CAAC,gBAAgB,CAAC,MAAM;QAC9C,CAAC,CAAC,GAAG,CAAC,gBAAgB;aACjB,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,kBAAkB,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,OAAO,cAAc,CAAC;aACzF,IAAI,CAAC,MAAM,CAAC;QACjB,CAAC,CAAC,mCAAmC,CAAC;IAExC,OAAO;QACL,sFAAsF;QACtF,EAAE;QACF,SAAS,GAAG,CAAC,IAAI,EAAE;QACnB,mBAAmB,GAAG,CAAC,aAAa,EAAE;QACtC,WAAW,GAAG,CAAC,UAAU,EAAE;QAC3B,SAAS,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,EAAE;QAC5C,mBAAmB,GAAG,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE;QACrF,EAAE;QACF,SAAS;QACT,0FAA0F;QAC1F,qEAAqE;QACrE,gGAAgG;QAChG,mIAAmI;QACnI,2HAA2H;QAC3H,2GAA2G;QAC3G,EAAE;QACF,yBAAyB;QACzB,GAAG,CAAC,MAAM;QACV,EAAE;QACF,gBAAgB;QAChB,YAAY;KACb,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,SAAS,eAAe,CAAC,KAAa;IACpC,OAAO,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AAC1F,CAAC"}
|
package/dist/run.d.ts
ADDED
package/dist/run.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { applyPolicy } from "./policy.js";
|
|
2
|
+
import { readContextFiles } from "./context.js";
|
|
3
|
+
export function buildEffectiveRun(config, options) {
|
|
4
|
+
const presetName = options.preset || config.defaults.preset;
|
|
5
|
+
const preset = config.presets[presetName];
|
|
6
|
+
if (!preset)
|
|
7
|
+
throw new Error(`Unknown preset: ${presetName}`);
|
|
8
|
+
const requestedMode = options.mode || config.defaults.mode;
|
|
9
|
+
const yolo = options.yolo || config.policy.yolo;
|
|
10
|
+
const decision = applyPolicy(requestedMode, config.policy, options.prompt, yolo);
|
|
11
|
+
return {
|
|
12
|
+
mode: decision.mode,
|
|
13
|
+
requestedMode: decision.requestedMode,
|
|
14
|
+
presetName,
|
|
15
|
+
preset,
|
|
16
|
+
prompt: options.prompt,
|
|
17
|
+
source: options.source || preset.source || config.defaults.source,
|
|
18
|
+
profile: options.profile || preset.profile || config.defaults.profile,
|
|
19
|
+
provider: options.provider || preset.provider,
|
|
20
|
+
model: options.model || preset.model,
|
|
21
|
+
maxTurns: options.maxTurns || preset.maxTurns || config.defaults.maxTurns,
|
|
22
|
+
yolo,
|
|
23
|
+
detectedRisks: decision.detectedRisks,
|
|
24
|
+
contextDocuments: readContextFiles(options.contextFiles),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=run.js.map
|
package/dist/run.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,UAAU,iBAAiB,CAAC,MAAoB,EAAE,OAAmB;IACzE,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;IAC5D,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC1C,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,UAAU,EAAE,CAAC,CAAC;IAC9D,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;IAC3D,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;IAChD,MAAM,QAAQ,GAAG,WAAW,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAEjF,OAAO;QACL,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,aAAa,EAAE,QAAQ,CAAC,aAAa;QACrC,UAAU;QACV,MAAM;QACN,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM;QACjE,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO;QACrE,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ;QAC7C,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK;QACpC,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ;QACzE,IAAI;QACJ,aAAa,EAAE,QAAQ,CAAC,aAAa;QACrC,gBAAgB,EAAE,gBAAgB,CAAC,OAAO,CAAC,YAAY,CAAC;KACzD,CAAC;AACJ,CAAC"}
|
package/dist/status.d.ts
ADDED
package/dist/status.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
export function checkHermesStatus(config) {
|
|
3
|
+
const result = spawnSync(config.runtime.command, ["--version"], { encoding: "utf8" });
|
|
4
|
+
if (result.error)
|
|
5
|
+
return { command: config.runtime.command, available: false, error: result.error.message };
|
|
6
|
+
if (result.status !== 0)
|
|
7
|
+
return { command: config.runtime.command, available: false, error: result.stderr.trim() || `exit ${result.status}` };
|
|
8
|
+
return { command: config.runtime.command, available: true, version: result.stdout.trim() };
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAU/C,MAAM,UAAU,iBAAiB,CAAC,MAAoB;IACpD,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IACtF,IAAI,MAAM,CAAC,KAAK;QAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;IAC5G,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,QAAQ,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;IAC9I,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;AAC7F,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export declare const modes: readonly ["plan", "draft", "execute", "request-approval"];
|
|
2
|
+
export type BridgeMode = (typeof modes)[number];
|
|
3
|
+
export type RuntimeAdapter = "hermes-cli";
|
|
4
|
+
export interface RuntimeConfig {
|
|
5
|
+
adapter: RuntimeAdapter;
|
|
6
|
+
command: string;
|
|
7
|
+
}
|
|
8
|
+
export interface PresetConfig {
|
|
9
|
+
description?: string | undefined;
|
|
10
|
+
skills: string[];
|
|
11
|
+
toolsets: string[];
|
|
12
|
+
provider?: string | undefined;
|
|
13
|
+
model?: string | undefined;
|
|
14
|
+
profile?: string | undefined;
|
|
15
|
+
maxTurns?: number | undefined;
|
|
16
|
+
source?: string | undefined;
|
|
17
|
+
}
|
|
18
|
+
export interface DefaultsConfig {
|
|
19
|
+
mode: BridgeMode;
|
|
20
|
+
profile?: string | undefined;
|
|
21
|
+
source: string;
|
|
22
|
+
maxTurns: number;
|
|
23
|
+
preset: string;
|
|
24
|
+
}
|
|
25
|
+
export type RiskCategory = "publish_external" | "send_message" | "send_email" | "delete" | "payment" | "git_push" | "credential_change";
|
|
26
|
+
export interface PolicyConfig {
|
|
27
|
+
yolo: boolean;
|
|
28
|
+
requireApprovalFor: RiskCategory[];
|
|
29
|
+
}
|
|
30
|
+
export interface BridgeConfig {
|
|
31
|
+
runtime: RuntimeConfig;
|
|
32
|
+
defaults: DefaultsConfig;
|
|
33
|
+
presets: Record<string, PresetConfig>;
|
|
34
|
+
policy: PolicyConfig;
|
|
35
|
+
}
|
|
36
|
+
export interface RunOptions {
|
|
37
|
+
prompt: string;
|
|
38
|
+
mode?: BridgeMode | undefined;
|
|
39
|
+
preset?: string | undefined;
|
|
40
|
+
contextFiles: string[];
|
|
41
|
+
yolo: boolean;
|
|
42
|
+
dryRun: boolean;
|
|
43
|
+
json: boolean;
|
|
44
|
+
profile?: string | undefined;
|
|
45
|
+
provider?: string | undefined;
|
|
46
|
+
model?: string | undefined;
|
|
47
|
+
maxTurns?: number | undefined;
|
|
48
|
+
source?: string | undefined;
|
|
49
|
+
}
|
|
50
|
+
export interface ContextDocument {
|
|
51
|
+
path: string;
|
|
52
|
+
content: string;
|
|
53
|
+
}
|
|
54
|
+
export interface EffectiveRun {
|
|
55
|
+
mode: BridgeMode;
|
|
56
|
+
requestedMode: BridgeMode;
|
|
57
|
+
presetName: string;
|
|
58
|
+
preset: PresetConfig;
|
|
59
|
+
prompt: string;
|
|
60
|
+
source: string;
|
|
61
|
+
profile?: string | undefined;
|
|
62
|
+
provider?: string | undefined;
|
|
63
|
+
model?: string | undefined;
|
|
64
|
+
maxTurns: number;
|
|
65
|
+
yolo: boolean;
|
|
66
|
+
detectedRisks: RiskCategory[];
|
|
67
|
+
contextDocuments: ContextDocument[];
|
|
68
|
+
}
|
|
69
|
+
export interface AdapterResult {
|
|
70
|
+
ok: boolean;
|
|
71
|
+
exitCode: number;
|
|
72
|
+
stdout: string;
|
|
73
|
+
stderr: string;
|
|
74
|
+
command: string[];
|
|
75
|
+
prompt: string;
|
|
76
|
+
dryRun: boolean;
|
|
77
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,kBAAkB,CAAU,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const version: string;
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
function readVersion() {
|
|
3
|
+
try {
|
|
4
|
+
const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
5
|
+
return pkg.version ?? "0.0.0";
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
return "0.0.0";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export const version = readVersion();
|
|
12
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAMvC,SAAS,WAAW;IAClB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAgB,CAAC;QACzG,OAAO,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
Hermes Action Bridge is deliberately small. It does not try to become another automation platform.
|
|
4
|
+
|
|
5
|
+
Its job is to let an external agent ask Hermes Agent to handle a task, while applying a local, configurable policy layer.
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
Claude Code / Codex / Cursor / CI / shell
|
|
9
|
+
|
|
|
10
|
+
v
|
|
11
|
+
hermes-action CLI or MCP server
|
|
12
|
+
|
|
|
13
|
+
v
|
|
14
|
+
Hermes Agent CLI session
|
|
15
|
+
|
|
|
16
|
+
v
|
|
17
|
+
Hermes skills, tools, browser automation, MCPs, cron jobs, messaging, APIs
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Core modules
|
|
21
|
+
|
|
22
|
+
- `src/cli.ts`: command-line interface.
|
|
23
|
+
- `src/config.ts`: YAML config loading and normalization.
|
|
24
|
+
- `src/policy.ts`: risk detection and mode switching.
|
|
25
|
+
- `src/prompt.ts`: prompt envelope sent to Hermes.
|
|
26
|
+
- `src/context.ts`: context file loading with size guardrails.
|
|
27
|
+
- `src/adapters/hermes-cli.ts`: Hermes CLI adapter.
|
|
28
|
+
- `src/mcp-server.ts`: minimal MCP server.
|
|
29
|
+
- `src/status.ts`: runtime availability check.
|
|
30
|
+
- `src/version.ts`: single source of truth for the package version.
|
|
31
|
+
- `src/doctor.ts`: environment checks for `hermes-action doctor`.
|
|
32
|
+
|
|
33
|
+
## Native skills installer (`src/install/`)
|
|
34
|
+
|
|
35
|
+
The `install` / `uninstall` commands install an open-standard `SKILL.md` for Claude Code (`~/.claude/skills/`) and Codex (`~/.codex/skills/`). The CLI remains the deterministic execution layer; the skill only tells the agent when to delegate.
|
|
36
|
+
|
|
37
|
+
- `src/install/paths.ts`: cross-platform skill and instruction-file paths (injectable home/cwd).
|
|
38
|
+
- `src/install/templates.ts`: single source for the `SKILL.md` body, project hint, and MCP snippets.
|
|
39
|
+
- `src/install/managed-file.ts`: lock-based provenance for skill bundles (classify, atomic write, refuse-unmanaged).
|
|
40
|
+
- `src/install/marker-block.ts`: fail-safe marker block for the optional `CLAUDE.md` / `AGENTS.md` hint.
|
|
41
|
+
- `src/install/file-edit.ts`: shared read-edit-write helper used by the hint and the `.mcp.json` writer.
|
|
42
|
+
- `src/install/mcp-config.ts`: MCP snippets and the Claude Code `.mcp.json` merge/unmerge writer.
|
|
43
|
+
- `src/install/install-service.ts`: per-agent install/uninstall with failure isolation.
|
|
44
|
+
|
|
45
|
+
Defaults are conservative: never modify `CLAUDE.md` / `AGENTS.md` without `--project-hint`, never overwrite a file the installer did not generate, and stay idempotent.
|
|
46
|
+
|
|
47
|
+
## Config precedence
|
|
48
|
+
|
|
49
|
+
The bridge merges config in this order:
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
built-in defaults -> user config -> project config -> CLI flags
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
User config:
|
|
56
|
+
|
|
57
|
+
```text
|
|
58
|
+
~/.config/hermes-action/config.yaml
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Project config:
|
|
62
|
+
|
|
63
|
+
```text
|
|
64
|
+
.hermes-action.yaml
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Modes
|
|
68
|
+
|
|
69
|
+
The bridge does not decide how Hermes completes the task. It only labels the requested behavior:
|
|
70
|
+
|
|
71
|
+
- `plan`: no side effects.
|
|
72
|
+
- `draft`: produce an artifact, no external side effects.
|
|
73
|
+
- `execute`: execute allowed actions.
|
|
74
|
+
- `request-approval`: prepare the action and ask for approval.
|
|
75
|
+
|
|
76
|
+
## Policy
|
|
77
|
+
|
|
78
|
+
Policy is intentionally conservative and transparent.
|
|
79
|
+
|
|
80
|
+
When a prompt contains risky intent and `mode=execute`, the bridge changes the effective mode to `request-approval` unless YOLO is enabled.
|
|
81
|
+
|
|
82
|
+
The detected risks are included in the prompt envelope so Hermes knows why the mode changed.
|
|
83
|
+
|
|
84
|
+
## YOLO
|
|
85
|
+
|
|
86
|
+
YOLO is explicit and local:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
hermes-action run --yolo --mode execute "..."
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
It bypasses the bridge policy only. Hermes Agent still enforces its own rules and any tool/provider/platform approval flow.
|
|
93
|
+
|
|
94
|
+
## MCP design
|
|
95
|
+
|
|
96
|
+
The MCP server exposes a small delegation surface instead of mirroring every Hermes tool.
|
|
97
|
+
|
|
98
|
+
Tools:
|
|
99
|
+
|
|
100
|
+
- `hermes_run`
|
|
101
|
+
- `hermes_plan`
|
|
102
|
+
- `hermes_presets`
|
|
103
|
+
- `hermes_status`
|
|
104
|
+
|
|
105
|
+
This keeps schema drift low and lets Hermes remain the action runtime.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Functional Testing
|
|
2
|
+
|
|
3
|
+
This project has two validation layers.
|
|
4
|
+
|
|
5
|
+
## Automated tests
|
|
6
|
+
|
|
7
|
+
Run:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm run check
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
This executes:
|
|
14
|
+
|
|
15
|
+
- TypeScript build with `tsc`.
|
|
16
|
+
- Vitest unit tests.
|
|
17
|
+
- Functional CLI tests using a fake Hermes executable.
|
|
18
|
+
|
|
19
|
+
The fake Hermes tests verify:
|
|
20
|
+
|
|
21
|
+
- `hermes-action run` calls the configured Hermes command.
|
|
22
|
+
- Skills and toolsets are passed as CLI flags.
|
|
23
|
+
- Risky `execute` requests become `request-approval`.
|
|
24
|
+
- `--yolo` passes through and keeps `execute` mode.
|
|
25
|
+
- The prompt envelope contains mode, preset, YOLO state, detected risks, user request, and context.
|
|
26
|
+
- A failed Hermes run is surfaced through the MCP server as an error result (`isError`).
|
|
27
|
+
|
|
28
|
+
The installer tests verify (with injected home/cwd and temp `HOME`, no real agents required):
|
|
29
|
+
|
|
30
|
+
- `install` / `uninstall` are idempotent and never touch `CLAUDE.md` / `AGENTS.md` by default.
|
|
31
|
+
- `--dry-run` and `--print` write nothing; `--force` replaces a managed skill; a non-managed file is refused.
|
|
32
|
+
- `--project-hint` adds and removes a marker block without losing existing content.
|
|
33
|
+
- `--project` installs a project-local skill without creating the global one.
|
|
34
|
+
- `install mcp --write` merges and `uninstall mcp --write` unmerges the project `.mcp.json`, preserving other servers.
|
|
35
|
+
- `doctor` assembles its checks and JSON report, and `--probe` accepts the sentinel on stdout or stderr.
|
|
36
|
+
- The shipped `examples/*/SKILL.md` match the installer template exactly (no drift).
|
|
37
|
+
|
|
38
|
+
## Live Hermes smoke test
|
|
39
|
+
|
|
40
|
+
Use a safe dry-run first:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm run build
|
|
44
|
+
node dist/cli.js run --dry-run --json "Return the word BRIDGE_OK only."
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Then run a minimal real Hermes call if you intentionally want to spend provider tokens:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
node dist/cli.js run \
|
|
51
|
+
--mode plan \
|
|
52
|
+
--max-turns 2 \
|
|
53
|
+
"Return the word BRIDGE_OK only. Do not use tools."
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Claude Code smoke test
|
|
57
|
+
|
|
58
|
+
After `npm link`, ask Claude Code to run:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
hermes-action run --dry-run --json "Return BRIDGE_OK only."
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Expected result:
|
|
65
|
+
|
|
66
|
+
- The command exits `0`.
|
|
67
|
+
- The JSON output contains a `command` array starting with `hermes chat -Q`.
|
|
68
|
+
- The prompt contains `Mode: plan`.
|
|
69
|
+
|
|
70
|
+
## Codex smoke test
|
|
71
|
+
|
|
72
|
+
After `npm link`, ask Codex to run:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
hermes-action run --dry-run --json "Return BRIDGE_OK only."
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Expected result is the same as Claude Code.
|
|
79
|
+
|
|
80
|
+
## MCP smoke test
|
|
81
|
+
|
|
82
|
+
Configure an MCP client with:
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"mcpServers": {
|
|
87
|
+
"hermes-action": {
|
|
88
|
+
"command": "hermes-action",
|
|
89
|
+
"args": ["mcp"]
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Call `hermes_status` first. It should report whether the configured Hermes command is available.
|
|
96
|
+
|
|
97
|
+
Then call `hermes_run` with `dryRun: true` before making real Hermes calls.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Claude Code: Hermes Action Bridge
|
|
2
|
+
|
|
3
|
+
Install the native skill so Claude Code knows when to delegate real-world actions to Hermes:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
hermes-action install claude-code
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
This writes `~/.claude/skills/hermes-action-bridge/SKILL.md`. Preview the exact content first with:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
hermes-action install claude-code --print
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
To add a small marker-managed hint to this project's `CLAUDE.md` (instead of, or in addition to, the global skill):
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
hermes-action install claude-code --project-hint
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The generated skill is shown in [SKILL.md](SKILL.md). Check your setup with `hermes-action doctor`. Remove everything with `hermes-action uninstall claude-code --project-hint`.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hermes-action-bridge
|
|
3
|
+
description: Delegate external actions, Hermes skills, browser automation, messaging, cron jobs, and integrations to Hermes Agent through hermes-action. Use when a task needs capabilities outside the local coding session.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Hermes Action Bridge
|
|
7
|
+
|
|
8
|
+
Use this skill when a task needs capabilities outside the local coding session:
|
|
9
|
+
Hermes skills or memory, messaging platforms, browser automation, scheduled or
|
|
10
|
+
cron automation, external research, or any platform integration already
|
|
11
|
+
configured in Hermes Agent.
|
|
12
|
+
|
|
13
|
+
Do not reimplement those integrations here. Delegate them to Hermes through the
|
|
14
|
+
`hermes-action` CLI.
|
|
15
|
+
|
|
16
|
+
## When to use
|
|
17
|
+
|
|
18
|
+
- The task requires a Hermes skill, tool, profile, or connected service.
|
|
19
|
+
- The task needs a real-world action that is not local code editing.
|
|
20
|
+
- The task needs research, messaging, browser, or scheduled automation Hermes owns.
|
|
21
|
+
|
|
22
|
+
## Safe default
|
|
23
|
+
|
|
24
|
+
Ask Hermes for a plan first; it has no side effects:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
hermes-action run --mode plan "<describe what Hermes should do>"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## With context
|
|
31
|
+
|
|
32
|
+
Write a concise handoff to a file and pass it explicitly:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
hermes-action run --preset coding --context ./handoff.md "<request>"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## External side effects
|
|
39
|
+
|
|
40
|
+
For public posts, outbound email or messages, deletes, payments, credential
|
|
41
|
+
changes, or git pushes, require human approval:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
hermes-action run --mode request-approval "<request requiring side effects>"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Never use `--yolo` unless the human explicitly asked for trusted local
|
|
48
|
+
execution. It bypasses only the bridge policy, not Hermes' own safety rules.
|
|
49
|
+
|
|
50
|
+
## Verify setup
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
hermes-action status
|
|
54
|
+
hermes-action run --dry-run --json "Return BRIDGE_OK only."
|
|
55
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Codex: Hermes Action Bridge
|
|
2
|
+
|
|
3
|
+
Install the native skill so Codex knows when to delegate real-world actions to Hermes:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
hermes-action install codex
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
This writes `~/.codex/skills/hermes-action-bridge/SKILL.md`. Preview the exact content first with:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
hermes-action install codex --print
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
To add a small marker-managed hint to this project's `AGENTS.md` (instead of, or in addition to, the global skill):
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
hermes-action install codex --project-hint
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The generated skill is shown in [SKILL.md](SKILL.md). Check your setup with `hermes-action doctor`. Remove everything with `hermes-action uninstall codex --project-hint`.
|