rulesync 15.0.1 → 15.1.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/dist/cli/index.cjs +14 -4
- package/dist/cli/index.d.cts +1 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +14 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/{import-DRN7goJ_.cjs → import-CVk4I0-A.cjs} +468 -88
- package/dist/{import-BuxzyDyH.js → import-WWoS8Wv4.js} +454 -74
- package/dist/import-WWoS8Wv4.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +4 -0
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +15 -15
- package/dist/import-BuxzyDyH.js.map +0 -1
|
@@ -127,27 +127,27 @@ const isFeatureValueEnabled = (value) => {
|
|
|
127
127
|
};
|
|
128
128
|
//#endregion
|
|
129
129
|
//#region src/constants/rulesync-paths.ts
|
|
130
|
-
const { join: join$
|
|
130
|
+
const { join: join$273 } = node_path.posix;
|
|
131
131
|
const RULESYNC_CONFIG_RELATIVE_FILE_PATH = "rulesync.jsonc";
|
|
132
132
|
const RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH = "rulesync.local.jsonc";
|
|
133
133
|
const RULESYNC_RELATIVE_DIR_PATH = ".rulesync";
|
|
134
|
-
const RULESYNC_RULES_RELATIVE_DIR_PATH = join$
|
|
135
|
-
const RULESYNC_CURATED_RULES_RELATIVE_DIR_PATH = join$
|
|
136
|
-
const RULESYNC_COMMANDS_RELATIVE_DIR_PATH = join$
|
|
137
|
-
const RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH = join$
|
|
138
|
-
const RULESYNC_CHECKS_RELATIVE_DIR_PATH = join$
|
|
139
|
-
const RULESYNC_MCP_RELATIVE_FILE_PATH = join$
|
|
140
|
-
const RULESYNC_HOOKS_RELATIVE_FILE_PATH = join$
|
|
141
|
-
const RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH = join$
|
|
142
|
-
join$
|
|
143
|
-
const RULESYNC_HOOKS_LEGACY_RELATIVE_FILE_PATH = join$
|
|
144
|
-
const RULESYNC_PERMISSIONS_LEGACY_RELATIVE_FILE_PATH = join$
|
|
134
|
+
const RULESYNC_RULES_RELATIVE_DIR_PATH = join$273(RULESYNC_RELATIVE_DIR_PATH, "rules");
|
|
135
|
+
const RULESYNC_CURATED_RULES_RELATIVE_DIR_PATH = join$273(RULESYNC_RULES_RELATIVE_DIR_PATH, ".curated");
|
|
136
|
+
const RULESYNC_COMMANDS_RELATIVE_DIR_PATH = join$273(RULESYNC_RELATIVE_DIR_PATH, "commands");
|
|
137
|
+
const RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH = join$273(RULESYNC_RELATIVE_DIR_PATH, "subagents");
|
|
138
|
+
const RULESYNC_CHECKS_RELATIVE_DIR_PATH = join$273(RULESYNC_RELATIVE_DIR_PATH, "checks");
|
|
139
|
+
const RULESYNC_MCP_RELATIVE_FILE_PATH = join$273(RULESYNC_RELATIVE_DIR_PATH, "mcp.jsonc");
|
|
140
|
+
const RULESYNC_HOOKS_RELATIVE_FILE_PATH = join$273(RULESYNC_RELATIVE_DIR_PATH, "hooks.jsonc");
|
|
141
|
+
const RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH = join$273(RULESYNC_RELATIVE_DIR_PATH, "permissions.jsonc");
|
|
142
|
+
join$273(RULESYNC_RELATIVE_DIR_PATH, "mcp.json");
|
|
143
|
+
const RULESYNC_HOOKS_LEGACY_RELATIVE_FILE_PATH = join$273(RULESYNC_RELATIVE_DIR_PATH, "hooks.json");
|
|
144
|
+
const RULESYNC_PERMISSIONS_LEGACY_RELATIVE_FILE_PATH = join$273(RULESYNC_RELATIVE_DIR_PATH, "permissions.json");
|
|
145
145
|
const RULESYNC_AIIGNORE_FILE_NAME = ".aiignore";
|
|
146
|
-
const RULESYNC_AIIGNORE_RELATIVE_FILE_PATH = join$
|
|
146
|
+
const RULESYNC_AIIGNORE_RELATIVE_FILE_PATH = join$273(RULESYNC_RELATIVE_DIR_PATH, ".aiignore");
|
|
147
147
|
const RULESYNC_IGNORE_RELATIVE_FILE_PATH = ".rulesyncignore";
|
|
148
148
|
const RULESYNC_OVERVIEW_FILE_NAME = "overview.md";
|
|
149
|
-
const RULESYNC_SKILLS_RELATIVE_DIR_PATH = join$
|
|
150
|
-
const RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH = join$
|
|
149
|
+
const RULESYNC_SKILLS_RELATIVE_DIR_PATH = join$273(RULESYNC_RELATIVE_DIR_PATH, "skills");
|
|
150
|
+
const RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH = join$273(RULESYNC_SKILLS_RELATIVE_DIR_PATH, ".curated");
|
|
151
151
|
const RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH = "rulesync.lock";
|
|
152
152
|
const RULESYNC_NPM_SOURCES_LOCK_RELATIVE_FILE_PATH = "rulesync-npm.lock.json";
|
|
153
153
|
const RULESYNC_MCP_FILE_NAME = "mcp.jsonc";
|
|
@@ -2598,15 +2598,14 @@ const KIMI_CODE_TO_CANONICAL_EVENT_NAMES = Object.fromEntries(Object.entries(CAN
|
|
|
2598
2598
|
*
|
|
2599
2599
|
* Hermes validates hook events against a fixed `VALID_HOOKS` set:
|
|
2600
2600
|
* `pre_tool_call`, `post_tool_call`, `pre_llm_call`, `post_llm_call`,
|
|
2601
|
-
* `pre_verify`, `
|
|
2601
|
+
* `pre_verify`, `pre_api_request`, `post_api_request`, `api_request_error`,
|
|
2602
|
+
* `on_session_start`, `on_session_end`, `on_session_finalize`,
|
|
2602
2603
|
* `on_session_reset`, `subagent_start`, `subagent_stop`, `pre_gateway_dispatch`,
|
|
2603
2604
|
* `pre_approval_request`, `post_approval_response`, `transform_tool_result`,
|
|
2604
|
-
* `transform_terminal_output`, `transform_llm_output
|
|
2605
|
-
* clean 1:1 canonical equivalent
|
|
2606
|
-
*
|
|
2607
|
-
* `
|
|
2608
|
-
* `transform_*` result-rewriting hooks) have no canonical rulesync equivalent,
|
|
2609
|
-
* so no canonical event maps to them.
|
|
2605
|
+
* `transform_terminal_output`, `transform_llm_output`, and the three
|
|
2606
|
+
* `kanban_task_*` events. Only the events with a clean 1:1 canonical equivalent
|
|
2607
|
+
* are mapped here. All other native events round-trip through
|
|
2608
|
+
* `hermesagent.hooks`.
|
|
2610
2609
|
* @see https://github.com/NousResearch/hermes-agent/blob/main/website/docs/user-guide/features/hooks.md
|
|
2611
2610
|
*/
|
|
2612
2611
|
const HERMESAGENT_HOOK_EVENTS = [
|
|
@@ -2619,6 +2618,31 @@ const HERMESAGENT_HOOK_EVENTS = [
|
|
|
2619
2618
|
"subagentStart",
|
|
2620
2619
|
"subagentStop"
|
|
2621
2620
|
];
|
|
2621
|
+
const HERMESAGENT_NATIVE_HOOK_EVENTS = [
|
|
2622
|
+
"pre_tool_call",
|
|
2623
|
+
"post_tool_call",
|
|
2624
|
+
"transform_terminal_output",
|
|
2625
|
+
"transform_tool_result",
|
|
2626
|
+
"transform_llm_output",
|
|
2627
|
+
"pre_llm_call",
|
|
2628
|
+
"post_llm_call",
|
|
2629
|
+
"pre_verify",
|
|
2630
|
+
"pre_api_request",
|
|
2631
|
+
"post_api_request",
|
|
2632
|
+
"api_request_error",
|
|
2633
|
+
"on_session_start",
|
|
2634
|
+
"on_session_end",
|
|
2635
|
+
"on_session_finalize",
|
|
2636
|
+
"on_session_reset",
|
|
2637
|
+
"subagent_start",
|
|
2638
|
+
"subagent_stop",
|
|
2639
|
+
"pre_gateway_dispatch",
|
|
2640
|
+
"pre_approval_request",
|
|
2641
|
+
"post_approval_response",
|
|
2642
|
+
"kanban_task_claimed",
|
|
2643
|
+
"kanban_task_completed",
|
|
2644
|
+
"kanban_task_blocked"
|
|
2645
|
+
];
|
|
2622
2646
|
/**
|
|
2623
2647
|
* Map canonical camelCase event names to Hermes Agent's native `VALID_HOOKS`
|
|
2624
2648
|
* snake_case keys under the `hooks:` block of `~/.hermes/config.yaml`.
|
|
@@ -4766,6 +4790,7 @@ const RulesyncSkillFrontmatterSchema = zod_mini.z.looseObject({
|
|
|
4766
4790
|
metadata: zod_mini.z.optional(zod_mini.z.looseObject({})),
|
|
4767
4791
|
"allowed-tools": zod_mini.z.optional(zod_mini.z.union([zod_mini.z.string(), zod_mini.z.array(zod_mini.z.string())]))
|
|
4768
4792
|
})),
|
|
4793
|
+
hermesagent: zod_mini.z.optional(zod_mini.z.looseObject({})),
|
|
4769
4794
|
vibe: zod_mini.z.optional(zod_mini.z.looseObject({
|
|
4770
4795
|
license: zod_mini.z.optional(zod_mini.z.string()),
|
|
4771
4796
|
compatibility: zod_mini.z.optional(zod_mini.z.union([zod_mini.z.string(), zod_mini.z.looseObject({})])),
|
|
@@ -5338,6 +5363,7 @@ const HERMESAGENT_GLOBAL_DIR = ".hermes";
|
|
|
5338
5363
|
/** MCP servers and other settings live in `config.yaml` under `~/.hermes/`. */
|
|
5339
5364
|
const HERMESAGENT_CONFIG_FILE_NAME = "config.yaml";
|
|
5340
5365
|
const HERMESAGENT_CONFIG_FILE_PATH = (0, node_path.join)(HERMESAGENT_GLOBAL_DIR, HERMESAGENT_CONFIG_FILE_NAME);
|
|
5366
|
+
const HERMESAGENT_PROJECT_PLUGINS_ENV_VAR = "HERMES_ENABLE_PROJECT_PLUGINS";
|
|
5341
5367
|
const HERMESAGENT_SKILLS_DIR_PATH = (0, node_path.join)(HERMESAGENT_GLOBAL_DIR, "skills");
|
|
5342
5368
|
const HERMESAGENT_RULESYNC_DIR_PATH = (0, node_path.join)(HERMESAGENT_GLOBAL_DIR, "rulesync");
|
|
5343
5369
|
const HERMESAGENT_RULESYNC_COMMANDS_DIR_PATH = (0, node_path.join)(HERMESAGENT_RULESYNC_DIR_PATH, "commands");
|
|
@@ -8267,7 +8293,12 @@ var AgentsSkillsSkill = class AgentsSkillsSkill extends ToolSkill {
|
|
|
8267
8293
|
};
|
|
8268
8294
|
//#endregion
|
|
8269
8295
|
//#region src/features/skills/hermesagent-skill.ts
|
|
8270
|
-
|
|
8296
|
+
const SHARED_AGENT_SKILL_FIELDS = /* @__PURE__ */ new Set([
|
|
8297
|
+
"license",
|
|
8298
|
+
"compatibility",
|
|
8299
|
+
"allowed-tools"
|
|
8300
|
+
]);
|
|
8301
|
+
var HermesagentSkill = class HermesagentSkill extends AgentsSkillsSkill {
|
|
8271
8302
|
static isTargetedByRulesyncSkill(rulesyncSkill) {
|
|
8272
8303
|
const targets = rulesyncSkill.getFrontmatter().targets;
|
|
8273
8304
|
return targets.includes("*") || targets.includes("agentsskills") || targets.includes("hermesagent");
|
|
@@ -8281,6 +8312,87 @@ var HermesagentSkill = class extends AgentsSkillsSkill {
|
|
|
8281
8312
|
relativeDirPath: HERMESAGENT_SKILLS_DIR_PATH
|
|
8282
8313
|
});
|
|
8283
8314
|
}
|
|
8315
|
+
static fromRulesyncSkill({ outputRoot = process.cwd(), rulesyncSkill, validate = true, global = false }) {
|
|
8316
|
+
const rulesyncFrontmatter = rulesyncSkill.getFrontmatter();
|
|
8317
|
+
const shared = rulesyncFrontmatter.agentsskills ?? {};
|
|
8318
|
+
const hermes = rulesyncFrontmatter.hermesagent ?? {};
|
|
8319
|
+
return new this({
|
|
8320
|
+
outputRoot,
|
|
8321
|
+
relativeDirPath: HERMESAGENT_SKILLS_DIR_PATH,
|
|
8322
|
+
dirName: rulesyncSkill.getDirName(),
|
|
8323
|
+
frontmatter: {
|
|
8324
|
+
...shared,
|
|
8325
|
+
...hermes,
|
|
8326
|
+
name: rulesyncFrontmatter.name,
|
|
8327
|
+
description: rulesyncFrontmatter.description
|
|
8328
|
+
},
|
|
8329
|
+
body: rulesyncSkill.getBody(),
|
|
8330
|
+
otherFiles: rulesyncSkill.getOtherFiles(),
|
|
8331
|
+
validate,
|
|
8332
|
+
global
|
|
8333
|
+
});
|
|
8334
|
+
}
|
|
8335
|
+
toRulesyncSkill() {
|
|
8336
|
+
const frontmatter = this.getFrontmatter();
|
|
8337
|
+
const agentsskills = {
|
|
8338
|
+
...frontmatter.license !== void 0 && { license: frontmatter.license },
|
|
8339
|
+
...frontmatter.compatibility !== void 0 && { compatibility: frontmatter.compatibility },
|
|
8340
|
+
...frontmatter["allowed-tools"] !== void 0 && { "allowed-tools": frontmatter["allowed-tools"] }
|
|
8341
|
+
};
|
|
8342
|
+
const hermesagent = {};
|
|
8343
|
+
for (const [key, value] of Object.entries(frontmatter)) {
|
|
8344
|
+
if (key === "name" || key === "description") continue;
|
|
8345
|
+
if (!SHARED_AGENT_SKILL_FIELDS.has(key)) hermesagent[key] = value;
|
|
8346
|
+
}
|
|
8347
|
+
const rulesyncFrontmatter = {
|
|
8348
|
+
name: frontmatter.name,
|
|
8349
|
+
description: frontmatter.description,
|
|
8350
|
+
targets: ["*"],
|
|
8351
|
+
...Object.keys(agentsskills).length > 0 && { agentsskills },
|
|
8352
|
+
...Object.keys(hermesagent).length > 0 && { hermesagent }
|
|
8353
|
+
};
|
|
8354
|
+
return new RulesyncSkill({
|
|
8355
|
+
outputRoot: this.outputRoot,
|
|
8356
|
+
relativeDirPath: RULESYNC_SKILLS_RELATIVE_DIR_PATH,
|
|
8357
|
+
dirName: this.getDirName(),
|
|
8358
|
+
frontmatter: rulesyncFrontmatter,
|
|
8359
|
+
body: this.getBody(),
|
|
8360
|
+
otherFiles: this.getOtherFiles(),
|
|
8361
|
+
validate: true,
|
|
8362
|
+
global: this.global
|
|
8363
|
+
});
|
|
8364
|
+
}
|
|
8365
|
+
static async fromDir(params) {
|
|
8366
|
+
const loaded = await this.loadSkillDirContent({
|
|
8367
|
+
...params,
|
|
8368
|
+
getSettablePaths: HermesagentSkill.getSettablePaths
|
|
8369
|
+
});
|
|
8370
|
+
return new this({
|
|
8371
|
+
outputRoot: loaded.outputRoot,
|
|
8372
|
+
relativeDirPath: loaded.relativeDirPath,
|
|
8373
|
+
dirName: loaded.dirName,
|
|
8374
|
+
frontmatter: loaded.frontmatter,
|
|
8375
|
+
body: loaded.body,
|
|
8376
|
+
otherFiles: loaded.otherFiles,
|
|
8377
|
+
validate: true,
|
|
8378
|
+
global: loaded.global
|
|
8379
|
+
});
|
|
8380
|
+
}
|
|
8381
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, dirName, global = false }) {
|
|
8382
|
+
return new this({
|
|
8383
|
+
outputRoot,
|
|
8384
|
+
relativeDirPath: relativeDirPath ?? HERMESAGENT_SKILLS_DIR_PATH,
|
|
8385
|
+
dirName,
|
|
8386
|
+
frontmatter: {
|
|
8387
|
+
name: "",
|
|
8388
|
+
description: ""
|
|
8389
|
+
},
|
|
8390
|
+
body: "",
|
|
8391
|
+
otherFiles: [],
|
|
8392
|
+
validate: false,
|
|
8393
|
+
global
|
|
8394
|
+
});
|
|
8395
|
+
}
|
|
8284
8396
|
};
|
|
8285
8397
|
//#endregion
|
|
8286
8398
|
//#region src/features/commands/hermesagent-command.ts
|
|
@@ -8307,7 +8419,7 @@ import json
|
|
|
8307
8419
|
from pathlib import Path
|
|
8308
8420
|
|
|
8309
8421
|
|
|
8310
|
-
COMMANDS_DIR = Path.
|
|
8422
|
+
COMMANDS_DIR = Path(__file__).resolve().parents[2] / "rulesync" / "commands"
|
|
8311
8423
|
|
|
8312
8424
|
|
|
8313
8425
|
def _load_commands():
|
|
@@ -10760,7 +10872,7 @@ function isToolMatcherEntry(x) {
|
|
|
10760
10872
|
/**
|
|
10761
10873
|
* Filter the shared canonical hooks to the supported events and merge tool overrides on top.
|
|
10762
10874
|
*/
|
|
10763
|
-
function buildEffectiveHooks$
|
|
10875
|
+
function buildEffectiveHooks$1({ config, toolOverrideHooks, supportedEvents }) {
|
|
10764
10876
|
const supported = new Set(supportedEvents);
|
|
10765
10877
|
const sharedHooks = {};
|
|
10766
10878
|
for (const [event, defs] of Object.entries(config.hooks)) if (supported.has(event)) sharedHooks[event] = defs;
|
|
@@ -10890,7 +11002,7 @@ function buildToolHooks({ defs, converterConfig }) {
|
|
|
10890
11002
|
* (e.g. beforeSubmitPrompt → UserPromptSubmit).
|
|
10891
11003
|
*/
|
|
10892
11004
|
function canonicalToToolHooks({ config, toolOverrideHooks, converterConfig, logger }) {
|
|
10893
|
-
const effectiveHooks = buildEffectiveHooks$
|
|
11005
|
+
const effectiveHooks = buildEffectiveHooks$1({
|
|
10894
11006
|
config,
|
|
10895
11007
|
toolOverrideHooks,
|
|
10896
11008
|
supportedEvents: converterConfig.supportedEvents
|
|
@@ -12924,20 +13036,9 @@ var GrokcliHooks = class GrokcliHooks extends ToolHooks {
|
|
|
12924
13036
|
* `matcher`.
|
|
12925
13037
|
* @see https://github.com/NousResearch/hermes-agent/blob/main/website/docs/user-guide/features/hooks.md
|
|
12926
13038
|
*/
|
|
12927
|
-
const HERMESAGENT_MATCHER_EVENTS = /* @__PURE__ */ new Set(["
|
|
12928
|
-
|
|
12929
|
-
|
|
12930
|
-
* the `hermesagent`-specific override block on top.
|
|
12931
|
-
*/
|
|
12932
|
-
function buildEffectiveHooks$1(config, toolOverrideHooks) {
|
|
12933
|
-
const supported = new Set(HERMESAGENT_HOOK_EVENTS);
|
|
12934
|
-
const shared = {};
|
|
12935
|
-
for (const [event, defs] of Object.entries(config.hooks)) if (supported.has(event)) shared[event] = defs;
|
|
12936
|
-
return {
|
|
12937
|
-
...shared,
|
|
12938
|
-
...toolOverrideHooks
|
|
12939
|
-
};
|
|
12940
|
-
}
|
|
13039
|
+
const HERMESAGENT_MATCHER_EVENTS = /* @__PURE__ */ new Set(["pre_tool_call", "post_tool_call"]);
|
|
13040
|
+
const HERMESAGENT_CANONICAL_EVENTS = new Set(HERMESAGENT_HOOK_EVENTS);
|
|
13041
|
+
const HERMESAGENT_NATIVE_EVENTS = new Set(HERMESAGENT_NATIVE_HOOK_EVENTS);
|
|
12941
13042
|
/**
|
|
12942
13043
|
* Convert the canonical hooks config into Hermes's native
|
|
12943
13044
|
* `hooks: { <event>: [{ matcher?, command, timeout? }] }` shape.
|
|
@@ -12950,24 +13051,62 @@ function buildEffectiveHooks$1(config, toolOverrideHooks) {
|
|
|
12950
13051
|
* warning, mirroring how other adapters (e.g. AugmentCode) handle
|
|
12951
13052
|
* matcher-less lifecycle events.
|
|
12952
13053
|
*/
|
|
13054
|
+
function definitionsToHermesEntries({ event, sourceEvent = event, definitions, logger }) {
|
|
13055
|
+
const supportsMatcher = HERMESAGENT_MATCHER_EVENTS.has(event);
|
|
13056
|
+
const entries = [];
|
|
13057
|
+
for (const definition of definitions) {
|
|
13058
|
+
if ((definition.type ?? "command") !== "command" || typeof definition.command !== "string" || definition.command === "") continue;
|
|
13059
|
+
const entry = { command: definition.command };
|
|
13060
|
+
if (typeof definition.matcher === "string" && definition.matcher !== "") if (supportsMatcher) entry.matcher = definition.matcher;
|
|
13061
|
+
else logger?.warn(`matcher "${definition.matcher}" on "${sourceEvent}" hook will be ignored — Hermes Agent only supports matchers on pre_tool_call/post_tool_call`);
|
|
13062
|
+
if (typeof definition.timeout === "number") entry.timeout = definition.timeout;
|
|
13063
|
+
entries.push(entry);
|
|
13064
|
+
}
|
|
13065
|
+
return entries;
|
|
13066
|
+
}
|
|
13067
|
+
function setHermesHookEntries({ result, event, sourceEvent, definitions, logger }) {
|
|
13068
|
+
if (PROTOTYPE_POLLUTION_KEYS.has(event)) return;
|
|
13069
|
+
const entries = definitionsToHermesEntries({
|
|
13070
|
+
event,
|
|
13071
|
+
sourceEvent,
|
|
13072
|
+
definitions,
|
|
13073
|
+
logger
|
|
13074
|
+
});
|
|
13075
|
+
if (entries.length > 0) result[event] = entries;
|
|
13076
|
+
}
|
|
12953
13077
|
function canonicalToHermesHooks({ config, toolOverrideHooks, logger }) {
|
|
12954
|
-
const effectiveHooks = buildEffectiveHooks$1(config, toolOverrideHooks);
|
|
12955
13078
|
const result = {};
|
|
12956
|
-
for (const [canonicalEvent,
|
|
13079
|
+
for (const [canonicalEvent, definitions] of Object.entries(config.hooks)) {
|
|
13080
|
+
if (!HERMESAGENT_CANONICAL_EVENTS.has(canonicalEvent)) continue;
|
|
12957
13081
|
const nativeEvent = CANONICAL_TO_HERMESAGENT_EVENT_NAMES[canonicalEvent];
|
|
12958
|
-
if (
|
|
12959
|
-
|
|
12960
|
-
|
|
12961
|
-
|
|
12962
|
-
|
|
12963
|
-
|
|
12964
|
-
|
|
12965
|
-
|
|
12966
|
-
|
|
12967
|
-
|
|
12968
|
-
|
|
12969
|
-
|
|
12970
|
-
|
|
13082
|
+
if (nativeEvent) setHermesHookEntries({
|
|
13083
|
+
result,
|
|
13084
|
+
event: nativeEvent,
|
|
13085
|
+
sourceEvent: canonicalEvent,
|
|
13086
|
+
definitions,
|
|
13087
|
+
logger
|
|
13088
|
+
});
|
|
13089
|
+
}
|
|
13090
|
+
for (const [canonicalEvent, definitions] of Object.entries(toolOverrideHooks ?? {})) {
|
|
13091
|
+
if (!HERMESAGENT_CANONICAL_EVENTS.has(canonicalEvent)) continue;
|
|
13092
|
+
const nativeEvent = CANONICAL_TO_HERMESAGENT_EVENT_NAMES[canonicalEvent];
|
|
13093
|
+
if (nativeEvent) setHermesHookEntries({
|
|
13094
|
+
result,
|
|
13095
|
+
event: nativeEvent,
|
|
13096
|
+
sourceEvent: canonicalEvent,
|
|
13097
|
+
definitions,
|
|
13098
|
+
logger
|
|
13099
|
+
});
|
|
13100
|
+
}
|
|
13101
|
+
for (const [nativeEvent, definitions] of Object.entries(toolOverrideHooks ?? {})) {
|
|
13102
|
+
if (HERMESAGENT_CANONICAL_EVENTS.has(nativeEvent)) continue;
|
|
13103
|
+
if (!HERMESAGENT_NATIVE_EVENTS.has(nativeEvent)) logger?.warn(`Hermes hook event "${nativeEvent}" is not documented by Hermes Agent v0.19.0; preserving it for forward compatibility.`);
|
|
13104
|
+
setHermesHookEntries({
|
|
13105
|
+
result,
|
|
13106
|
+
event: nativeEvent,
|
|
13107
|
+
definitions,
|
|
13108
|
+
logger
|
|
13109
|
+
});
|
|
12971
13110
|
}
|
|
12972
13111
|
return result;
|
|
12973
13112
|
}
|
|
@@ -12975,16 +13114,15 @@ function canonicalToHermesHooks({ config, toolOverrideHooks, logger }) {
|
|
|
12975
13114
|
* Reverse {@link canonicalToHermesHooks}: parse Hermes's native
|
|
12976
13115
|
* `hooks: { <event>: [...] }` map back into a canonical event → definition[]
|
|
12977
13116
|
* record. Native events with no canonical equivalent (`pre_verify`,
|
|
12978
|
-
* `transform_tool_result`, ...)
|
|
12979
|
-
*
|
|
13117
|
+
* `transform_tool_result`, ...) retain their native names so
|
|
13118
|
+
* {@link buildImportedHooksConfig} places them under `hermesagent.hooks`.
|
|
12980
13119
|
*/
|
|
12981
13120
|
function hermesHooksToCanonical(hooks) {
|
|
12982
13121
|
const canonical = {};
|
|
12983
13122
|
if (hooks === null || typeof hooks !== "object" || Array.isArray(hooks)) return canonical;
|
|
12984
13123
|
for (const [nativeEvent, entries] of Object.entries(hooks)) {
|
|
12985
13124
|
if (PROTOTYPE_POLLUTION_KEYS.has(nativeEvent) || !Array.isArray(entries)) continue;
|
|
12986
|
-
const
|
|
12987
|
-
if (!canonicalEvent) continue;
|
|
13125
|
+
const rulesyncEvent = HERMESAGENT_TO_CANONICAL_EVENT_NAMES[nativeEvent] ?? nativeEvent;
|
|
12988
13126
|
const defs = [];
|
|
12989
13127
|
for (const raw of entries) {
|
|
12990
13128
|
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) continue;
|
|
@@ -12994,11 +13132,11 @@ function hermesHooksToCanonical(hooks) {
|
|
|
12994
13132
|
type: "command",
|
|
12995
13133
|
command: entry.command
|
|
12996
13134
|
};
|
|
12997
|
-
if (typeof entry.matcher === "string" && entry.matcher !== "") def.matcher = entry.matcher;
|
|
13135
|
+
if (HERMESAGENT_MATCHER_EVENTS.has(nativeEvent) && typeof entry.matcher === "string" && entry.matcher !== "") def.matcher = entry.matcher;
|
|
12998
13136
|
if (typeof entry.timeout === "number") def.timeout = entry.timeout;
|
|
12999
13137
|
defs.push(def);
|
|
13000
13138
|
}
|
|
13001
|
-
if (defs.length > 0) canonical[
|
|
13139
|
+
if (defs.length > 0) canonical[rulesyncEvent] = defs;
|
|
13002
13140
|
}
|
|
13003
13141
|
return canonical;
|
|
13004
13142
|
}
|
|
@@ -15055,7 +15193,8 @@ const toolHooksFactories = /* @__PURE__ */ new Map([
|
|
|
15055
15193
|
},
|
|
15056
15194
|
supportedEvents: HERMESAGENT_HOOK_EVENTS,
|
|
15057
15195
|
supportedHookTypes: ["command"],
|
|
15058
|
-
supportsMatcher: true
|
|
15196
|
+
supportsMatcher: true,
|
|
15197
|
+
passthroughOverrideEvents: true
|
|
15059
15198
|
}],
|
|
15060
15199
|
["kimi-code", {
|
|
15061
15200
|
class: KimiCodeHooks,
|
|
@@ -18792,12 +18931,51 @@ function resolveHermesTimeout(config) {
|
|
|
18792
18931
|
* canonical `McpServerSchema` is a `looseObject`), so this serves export and
|
|
18793
18932
|
* import alike. See the Hermes mcp-config-reference.
|
|
18794
18933
|
*/
|
|
18934
|
+
function copyHermesOauth(source) {
|
|
18935
|
+
if (!isRecord(source)) return;
|
|
18936
|
+
const oauth = {};
|
|
18937
|
+
for (const key of [
|
|
18938
|
+
"redirect_uri",
|
|
18939
|
+
"redirect_host",
|
|
18940
|
+
"client_id",
|
|
18941
|
+
"client_secret"
|
|
18942
|
+
]) if (typeof source[key] === "string") oauth[key] = source[key];
|
|
18943
|
+
if (typeof source.redirect_port === "number") oauth.redirect_port = source.redirect_port;
|
|
18944
|
+
if (isStringArray$1(source.scopes)) oauth.scopes = source.scopes;
|
|
18945
|
+
return Object.keys(oauth).length > 0 ? oauth : void 0;
|
|
18946
|
+
}
|
|
18795
18947
|
function copyHermesAdvancedFields(source, target) {
|
|
18796
|
-
|
|
18797
|
-
if (typeof source.
|
|
18798
|
-
|
|
18799
|
-
|
|
18800
|
-
|
|
18948
|
+
let copied = false;
|
|
18949
|
+
if (typeof source.auth === "string") {
|
|
18950
|
+
target.auth = source.auth;
|
|
18951
|
+
copied = true;
|
|
18952
|
+
}
|
|
18953
|
+
if (typeof source.client_cert === "string" || isStringArray$1(source.client_cert)) {
|
|
18954
|
+
target.client_cert = source.client_cert;
|
|
18955
|
+
copied = true;
|
|
18956
|
+
}
|
|
18957
|
+
if (typeof source.client_key === "string") {
|
|
18958
|
+
target.client_key = source.client_key;
|
|
18959
|
+
copied = true;
|
|
18960
|
+
}
|
|
18961
|
+
if (typeof source.connect_timeout === "number") {
|
|
18962
|
+
target.connect_timeout = source.connect_timeout;
|
|
18963
|
+
copied = true;
|
|
18964
|
+
}
|
|
18965
|
+
if (typeof source.supports_parallel_tool_calls === "boolean") {
|
|
18966
|
+
target.supports_parallel_tool_calls = source.supports_parallel_tool_calls;
|
|
18967
|
+
copied = true;
|
|
18968
|
+
}
|
|
18969
|
+
const oauth = copyHermesOauth(source.oauth);
|
|
18970
|
+
if (oauth) {
|
|
18971
|
+
target.oauth = oauth;
|
|
18972
|
+
copied = true;
|
|
18973
|
+
}
|
|
18974
|
+
for (const key of ["idle_timeout_seconds", "max_lifetime_seconds"]) if (typeof source[key] === "number") {
|
|
18975
|
+
target[key] = source[key];
|
|
18976
|
+
copied = true;
|
|
18977
|
+
}
|
|
18978
|
+
return copied;
|
|
18801
18979
|
}
|
|
18802
18980
|
/**
|
|
18803
18981
|
* Builds Hermes's per-server `tools` block from a canonical server config. The
|
|
@@ -18899,6 +19077,7 @@ function mergeHermesMcpServers(config, mcpServers) {
|
|
|
18899
19077
|
*/
|
|
18900
19078
|
function convertFromHermesFormat(mcpServers) {
|
|
18901
19079
|
const result = {};
|
|
19080
|
+
const hermesOverrides = {};
|
|
18902
19081
|
for (const [name, config] of Object.entries(mcpServers)) {
|
|
18903
19082
|
if (PROTOTYPE_POLLUTION_KEYS.has(name) || !isRecord(config)) continue;
|
|
18904
19083
|
const server = {};
|
|
@@ -18909,11 +19088,15 @@ function convertFromHermesFormat(mcpServers) {
|
|
|
18909
19088
|
if (isPlainObject$1(config.headers)) server.headers = omitPrototypePollutionKeys(config.headers);
|
|
18910
19089
|
if (config.enabled === false) server.disabled = true;
|
|
18911
19090
|
if (typeof config.timeout === "number") server.networkTimeout = config.timeout;
|
|
18912
|
-
copyHermesAdvancedFields(config, server);
|
|
18913
19091
|
if (isRecord(config.tools)) applyHermesToolsBlock(config.tools, server);
|
|
18914
19092
|
result[name] = server;
|
|
19093
|
+
const hermesServer = { ...server };
|
|
19094
|
+
if (copyHermesAdvancedFields(config, hermesServer)) hermesOverrides[name] = hermesServer;
|
|
18915
19095
|
}
|
|
18916
|
-
return
|
|
19096
|
+
return {
|
|
19097
|
+
mcpServers: result,
|
|
19098
|
+
hermesOverrides
|
|
19099
|
+
};
|
|
18917
19100
|
}
|
|
18918
19101
|
/**
|
|
18919
19102
|
* Hermes Agent MCP servers.
|
|
@@ -18998,8 +19181,11 @@ var HermesagentMcp = class HermesagentMcp extends ToolMcp {
|
|
|
18998
19181
|
});
|
|
18999
19182
|
}
|
|
19000
19183
|
toRulesyncMcp() {
|
|
19001
|
-
const servers = convertFromHermesFormat(isRecord(this.config.mcp_servers) ? this.config.mcp_servers : {});
|
|
19002
|
-
return this.toRulesyncMcpDefault({ fileContent: JSON.stringify({
|
|
19184
|
+
const { mcpServers: servers, hermesOverrides } = convertFromHermesFormat(isRecord(this.config.mcp_servers) ? this.config.mcp_servers : {});
|
|
19185
|
+
return this.toRulesyncMcpDefault({ fileContent: JSON.stringify({
|
|
19186
|
+
mcpServers: servers,
|
|
19187
|
+
...Object.keys(hermesOverrides).length > 0 && { hermesagent: { mcpServers: hermesOverrides } }
|
|
19188
|
+
}, null, 2) });
|
|
19003
19189
|
}
|
|
19004
19190
|
validate() {
|
|
19005
19191
|
return {
|
|
@@ -21009,8 +21195,8 @@ const toolMcpFactories = /* @__PURE__ */ new Map([
|
|
|
21009
21195
|
meta: {
|
|
21010
21196
|
supportsProject: false,
|
|
21011
21197
|
supportsGlobal: true,
|
|
21012
|
-
supportsEnabledTools:
|
|
21013
|
-
supportsDisabledTools:
|
|
21198
|
+
supportsEnabledTools: true,
|
|
21199
|
+
supportsDisabledTools: true
|
|
21014
21200
|
}
|
|
21015
21201
|
}],
|
|
21016
21202
|
["kimi-code", {
|
|
@@ -25024,6 +25210,59 @@ function deriveGrokPermissionMode(config) {
|
|
|
25024
25210
|
function patternsByAction(category, action) {
|
|
25025
25211
|
return Object.entries(category ?? {}).filter(([, value]) => value === action).map(([pattern]) => pattern);
|
|
25026
25212
|
}
|
|
25213
|
+
function clonePermissionBlock(permission) {
|
|
25214
|
+
return Object.fromEntries(Object.entries(permission).map(([category, rules]) => [category, { ...rules }]));
|
|
25215
|
+
}
|
|
25216
|
+
function deleteRulesByAction(rules, action) {
|
|
25217
|
+
for (const [pattern, currentAction] of Object.entries(rules)) if (currentAction === action) delete rules[pattern];
|
|
25218
|
+
}
|
|
25219
|
+
function ensureCategory(permission, category) {
|
|
25220
|
+
return permission[category] ??= {};
|
|
25221
|
+
}
|
|
25222
|
+
function removeEmptyCategories(permission) {
|
|
25223
|
+
for (const [category, rules] of Object.entries(permission)) if (Object.keys(rules).length === 0) delete permission[category];
|
|
25224
|
+
}
|
|
25225
|
+
function reconcileCommandAllowlist({ permission, commandAllowlist }) {
|
|
25226
|
+
const nativeAllows = new Set(commandAllowlist);
|
|
25227
|
+
const existingAllowCategories = /* @__PURE__ */ new Map();
|
|
25228
|
+
for (const [category, rules] of Object.entries(permission)) for (const [pattern, action] of Object.entries(rules)) {
|
|
25229
|
+
if (action !== "allow") continue;
|
|
25230
|
+
existingAllowCategories.set(pattern, category);
|
|
25231
|
+
if (!nativeAllows.has(pattern)) delete rules[pattern];
|
|
25232
|
+
}
|
|
25233
|
+
for (const pattern of nativeAllows) {
|
|
25234
|
+
const existingCategory = existingAllowCategories.get(pattern);
|
|
25235
|
+
if (existingCategory) ensureCategory(permission, existingCategory)[pattern] = "allow";
|
|
25236
|
+
else ensureCategory(permission, "bash")[pattern] = "allow";
|
|
25237
|
+
}
|
|
25238
|
+
}
|
|
25239
|
+
function reconcileNativeDenies({ permission, category, patterns }) {
|
|
25240
|
+
const rules = ensureCategory(permission, category);
|
|
25241
|
+
deleteRulesByAction(rules, "deny");
|
|
25242
|
+
for (const pattern of patterns) rules[pattern] = "deny";
|
|
25243
|
+
}
|
|
25244
|
+
function withoutKey(record, key) {
|
|
25245
|
+
return Object.fromEntries(Object.entries(record).filter(([entryKey]) => entryKey !== key));
|
|
25246
|
+
}
|
|
25247
|
+
function buildHermesOverride(config, provenance) {
|
|
25248
|
+
const base = isRecord(provenance.hermes) ? { ...provenance.hermes } : {};
|
|
25249
|
+
const approvalsOverride = withoutKey(isRecord(config.approvals) ? config.approvals : {}, "deny");
|
|
25250
|
+
if (Object.keys(approvalsOverride).length > 0) base.approvals = approvalsOverride;
|
|
25251
|
+
else delete base.approvals;
|
|
25252
|
+
const security = isRecord(config.security) ? { ...config.security } : {};
|
|
25253
|
+
const blocklist = isRecord(security.website_blocklist) ? { ...security.website_blocklist } : void 0;
|
|
25254
|
+
if (blocklist?.enabled === true) {
|
|
25255
|
+
delete blocklist.domains;
|
|
25256
|
+
delete blocklist.enabled;
|
|
25257
|
+
}
|
|
25258
|
+
if (blocklist && Object.keys(blocklist).length > 0) security.website_blocklist = blocklist;
|
|
25259
|
+
else delete security.website_blocklist;
|
|
25260
|
+
if (Object.keys(security).length > 0) base.security = security;
|
|
25261
|
+
else delete base.security;
|
|
25262
|
+
for (const key of ["skills", "memory"]) if (isRecord(config[key])) base[key] = config[key];
|
|
25263
|
+
else delete base[key];
|
|
25264
|
+
return base;
|
|
25265
|
+
}
|
|
25027
25266
|
var HermesagentPermissions = class HermesagentPermissions extends ToolPermissions {
|
|
25028
25267
|
static getSettablePaths() {
|
|
25029
25268
|
return {
|
|
@@ -25080,12 +25319,40 @@ var HermesagentPermissions = class HermesagentPermissions extends ToolPermission
|
|
|
25080
25319
|
format: "yaml",
|
|
25081
25320
|
fileContent: this.getFileContent()
|
|
25082
25321
|
});
|
|
25083
|
-
const
|
|
25322
|
+
const permissionsRoot = isRecord(config.permissions) ? config.permissions : {};
|
|
25323
|
+
const parsedProvenance = RulesyncPermissionsFileSchema.safeParse(permissionsRoot.rulesync);
|
|
25324
|
+
const provenance = parsedProvenance.success ? parsedProvenance.data : { permission: {} };
|
|
25325
|
+
const permission = clonePermissionBlock(provenance.permission);
|
|
25326
|
+
reconcileCommandAllowlist({
|
|
25327
|
+
permission,
|
|
25328
|
+
commandAllowlist: isStringArray$1(config.command_allowlist) ? config.command_allowlist : []
|
|
25329
|
+
});
|
|
25330
|
+
const approvals = isRecord(config.approvals) ? config.approvals : {};
|
|
25331
|
+
reconcileNativeDenies({
|
|
25332
|
+
permission,
|
|
25333
|
+
category: "bash",
|
|
25334
|
+
patterns: isStringArray$1(approvals.deny) ? approvals.deny : []
|
|
25335
|
+
});
|
|
25336
|
+
const security = isRecord(config.security) ? config.security : {};
|
|
25337
|
+
const websiteBlocklist = isRecord(security.website_blocklist) ? security.website_blocklist : {};
|
|
25338
|
+
reconcileNativeDenies({
|
|
25339
|
+
permission,
|
|
25340
|
+
category: "webfetch",
|
|
25341
|
+
patterns: websiteBlocklist.enabled === true && isStringArray$1(websiteBlocklist.domains) ? websiteBlocklist.domains : []
|
|
25342
|
+
});
|
|
25343
|
+
removeEmptyCategories(permission);
|
|
25344
|
+
const { permission: _permission, hermes: _hermes, ...otherProvenance } = provenance;
|
|
25345
|
+
const hermes = buildHermesOverride(config, provenance);
|
|
25346
|
+
const imported = {
|
|
25347
|
+
...otherProvenance,
|
|
25348
|
+
permission,
|
|
25349
|
+
...Object.keys(hermes).length > 0 && { hermes }
|
|
25350
|
+
};
|
|
25084
25351
|
return new RulesyncPermissions({
|
|
25085
25352
|
outputRoot: this.outputRoot,
|
|
25086
25353
|
relativeDirPath: RULESYNC_RELATIVE_DIR_PATH,
|
|
25087
25354
|
relativeFilePath: RULESYNC_PERMISSIONS_FILE_NAME,
|
|
25088
|
-
fileContent: JSON.stringify(
|
|
25355
|
+
fileContent: JSON.stringify(imported, null, 2)
|
|
25089
25356
|
});
|
|
25090
25357
|
}
|
|
25091
25358
|
static fromRulesyncPermissions({ outputRoot, rulesyncPermissions }) {
|
|
@@ -35828,7 +36095,7 @@ import json
|
|
|
35828
36095
|
from pathlib import Path
|
|
35829
36096
|
|
|
35830
36097
|
|
|
35831
|
-
SUBAGENTS_DIR = Path.
|
|
36098
|
+
SUBAGENTS_DIR = Path(__file__).resolve().parents[2] / "rulesync" / "subagents"
|
|
35832
36099
|
|
|
35833
36100
|
|
|
35834
36101
|
def _load_subagents():
|
|
@@ -35937,12 +36204,12 @@ var HermesagentSubagent = class HermesagentSubagent extends ToolSubagent {
|
|
|
35937
36204
|
validate: false
|
|
35938
36205
|
});
|
|
35939
36206
|
}
|
|
35940
|
-
static async fromFile({ global = false, outputRoot = process.cwd(), relativeFilePath, validate = true }) {
|
|
36207
|
+
static async fromFile({ global = false, outputRoot = process.cwd(), relativeDirPath, relativeFilePath, validate = true }) {
|
|
35941
36208
|
return new HermesagentSubagent({
|
|
35942
|
-
fileContent: await (0, node_fs_promises.readFile)((0, node_path.join)(outputRoot, relativeFilePath), "utf8"),
|
|
36209
|
+
fileContent: await (0, node_fs_promises.readFile)((0, node_path.join)(outputRoot, relativeDirPath ?? HERMESAGENT_RULESYNC_SUBAGENTS_DIR_PATH, relativeFilePath), "utf8"),
|
|
35943
36210
|
global,
|
|
35944
36211
|
outputRoot,
|
|
35945
|
-
relativeDirPath: (0, node_path.dirname)(relativeFilePath),
|
|
36212
|
+
relativeDirPath: relativeDirPath ?? (0, node_path.dirname)(relativeFilePath),
|
|
35946
36213
|
relativeFilePath: (0, node_path.basename)(relativeFilePath),
|
|
35947
36214
|
validate
|
|
35948
36215
|
});
|
|
@@ -35951,7 +36218,7 @@ var HermesagentSubagent = class HermesagentSubagent extends ToolSubagent {
|
|
|
35951
36218
|
const targets = rulesyncSubagent.getFrontmatter().targets;
|
|
35952
36219
|
return !targets || targets.includes("*") || targets.includes("hermesagent");
|
|
35953
36220
|
}
|
|
35954
|
-
static fromRulesyncSubagents({ rulesyncSubagents, outputRoot }) {
|
|
36221
|
+
static fromRulesyncSubagents({ rulesyncSubagents, outputRoot, global = false }) {
|
|
35955
36222
|
return [
|
|
35956
36223
|
...rulesyncSubagents.map((rulesyncSubagent) => HermesagentSubagent.fromRulesyncSubagent({
|
|
35957
36224
|
relativeDirPath: HERMESAGENT_RULESYNC_SUBAGENTS_DIR_PATH,
|
|
@@ -35970,12 +36237,12 @@ var HermesagentSubagent = class HermesagentSubagent extends ToolSubagent {
|
|
|
35970
36237
|
fileContent: "",
|
|
35971
36238
|
outputRoot
|
|
35972
36239
|
}),
|
|
35973
|
-
new HermesagentSubagent({
|
|
36240
|
+
...global ? [new HermesagentSubagent({
|
|
35974
36241
|
relativeDirPath: HERMESAGENT_GLOBAL_DIR,
|
|
35975
36242
|
relativeFilePath: (0, node_path.basename)(HERMESAGENT_CONFIG_FILE_PATH),
|
|
35976
36243
|
fileContent: "",
|
|
35977
36244
|
outputRoot
|
|
35978
|
-
})
|
|
36245
|
+
})] : []
|
|
35979
36246
|
];
|
|
35980
36247
|
}
|
|
35981
36248
|
static fromRulesyncSubagent({ rulesyncSubagent, outputRoot }) {
|
|
@@ -35996,11 +36263,11 @@ var HermesagentSubagent = class HermesagentSubagent extends ToolSubagent {
|
|
|
35996
36263
|
* shared `~/.hermes/config.yaml` (enabling the `rulesync-subagents` plugin),
|
|
35997
36264
|
* so the write must be declared for the shared-file order derivation.
|
|
35998
36265
|
*/
|
|
35999
|
-
static getExtraSharedWritePaths() {
|
|
36000
|
-
return [{
|
|
36266
|
+
static getExtraSharedWritePaths({ global = false } = {}) {
|
|
36267
|
+
return global ? [{
|
|
36001
36268
|
relativeDirPath: HERMESAGENT_GLOBAL_DIR,
|
|
36002
36269
|
relativeFilePath: (0, node_path.basename)(HERMESAGENT_CONFIG_FILE_PATH)
|
|
36003
|
-
}];
|
|
36270
|
+
}] : [];
|
|
36004
36271
|
}
|
|
36005
36272
|
static getSettablePathsForRulesyncSubagent(rulesyncSubagent) {
|
|
36006
36273
|
return [(0, node_path.join)(HERMESAGENT_RULESYNC_SUBAGENTS_DIR_PATH, `${subagentSlug(rulesyncSubagent.getRelativePathFromCwd())}.json`)];
|
|
@@ -36010,13 +36277,13 @@ var HermesagentSubagent = class HermesagentSubagent extends ToolSubagent {
|
|
|
36010
36277
|
const json = JSON.parse(this.getFileContent());
|
|
36011
36278
|
return new RulesyncSubagent({
|
|
36012
36279
|
relativeDirPath: RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH,
|
|
36013
|
-
relativeFilePath:
|
|
36280
|
+
relativeFilePath: `${slug}.md`,
|
|
36014
36281
|
body: json.prompt ?? "",
|
|
36015
36282
|
frontmatter: {
|
|
36016
36283
|
name: json.name ?? slug,
|
|
36017
36284
|
description: json.description
|
|
36018
36285
|
},
|
|
36019
|
-
outputRoot: this.outputRoot
|
|
36286
|
+
outputRoot: this.global ? this.outputRoot : process.cwd()
|
|
36020
36287
|
});
|
|
36021
36288
|
}
|
|
36022
36289
|
validate() {
|
|
@@ -43666,6 +43933,74 @@ function buildChecksStrategy(ctx) {
|
|
|
43666
43933
|
};
|
|
43667
43934
|
}
|
|
43668
43935
|
//#endregion
|
|
43936
|
+
//#region src/features/shared/hermes-project-plugin-activation.ts
|
|
43937
|
+
function mergeEnabledPlugins({ existingContent, filePath, pluginNames }) {
|
|
43938
|
+
const config = parseSharedConfig({
|
|
43939
|
+
format: "yaml",
|
|
43940
|
+
fileContent: existingContent,
|
|
43941
|
+
filePath,
|
|
43942
|
+
invalidRootPolicy: "error"
|
|
43943
|
+
});
|
|
43944
|
+
const plugins = isPlainObject$1(config.plugins) ? config.plugins : {};
|
|
43945
|
+
const disabled = Array.isArray(plugins.disabled) ? plugins.disabled.filter((value) => typeof value === "string") : [];
|
|
43946
|
+
const conflicts = pluginNames.filter((pluginName) => disabled.includes(pluginName));
|
|
43947
|
+
if (conflicts.length > 0) throw new Error(`Cannot activate Hermes project plugin(s) ${conflicts.join(", ")} because ${filePath} explicitly lists them in plugins.disabled. Remove the conflicting entries or exclude those RuleSync features.`);
|
|
43948
|
+
const enabled = Array.isArray(plugins.enabled) ? plugins.enabled : [];
|
|
43949
|
+
return stringifySharedConfig({
|
|
43950
|
+
format: "yaml",
|
|
43951
|
+
document: {
|
|
43952
|
+
...config,
|
|
43953
|
+
plugins: {
|
|
43954
|
+
...plugins,
|
|
43955
|
+
enabled: Array.from(/* @__PURE__ */ new Set([...enabled, ...pluginNames]))
|
|
43956
|
+
}
|
|
43957
|
+
}
|
|
43958
|
+
});
|
|
43959
|
+
}
|
|
43960
|
+
async function writeActivationFile({ filePath, relativePath, expectedContent, dryRun, logger }) {
|
|
43961
|
+
const existingContent = await readFileContentOrNull(filePath);
|
|
43962
|
+
const normalizedExpected = addTrailingNewline(expectedContent);
|
|
43963
|
+
if (fileContentsEquivalent({
|
|
43964
|
+
filePath,
|
|
43965
|
+
expected: normalizedExpected,
|
|
43966
|
+
existing: existingContent
|
|
43967
|
+
})) return false;
|
|
43968
|
+
if (dryRun) logger.info(`[DRY RUN] Would write: ${filePath}`);
|
|
43969
|
+
else await writeFileContent(filePath, normalizedExpected);
|
|
43970
|
+
logger.debug(`Hermes project-plugin activation requires ${relativePath}`);
|
|
43971
|
+
return true;
|
|
43972
|
+
}
|
|
43973
|
+
async function activateHermesProjectPlugins({ pluginNames, dryRun, logger }) {
|
|
43974
|
+
if (pluginNames.length === 0) return {
|
|
43975
|
+
count: 0,
|
|
43976
|
+
paths: [],
|
|
43977
|
+
hasDiff: false
|
|
43978
|
+
};
|
|
43979
|
+
const configuredHermesHome = process.env.HERMES_HOME?.trim();
|
|
43980
|
+
const configRoot = configuredHermesHome ? (0, node_path.resolve)(configuredHermesHome) : getHomeDirectory();
|
|
43981
|
+
const relativeConfigPath = configuredHermesHome ? HERMESAGENT_CONFIG_FILE_NAME : HERMESAGENT_CONFIG_FILE_PATH;
|
|
43982
|
+
const configPath = (0, node_path.join)(configRoot, relativeConfigPath);
|
|
43983
|
+
const expectedConfig = mergeEnabledPlugins({
|
|
43984
|
+
existingContent: await readFileContentOrNull(configPath) ?? "",
|
|
43985
|
+
filePath: configPath,
|
|
43986
|
+
pluginNames
|
|
43987
|
+
});
|
|
43988
|
+
const paths = [];
|
|
43989
|
+
logger.warn(`Hermes project plugins require explicit trust. Run Hermes from this trusted repository with ${HERMESAGENT_PROJECT_PLUGINS_ENV_VAR}=true. RuleSync does not persist this global setting.`);
|
|
43990
|
+
if (await writeActivationFile({
|
|
43991
|
+
filePath: configPath,
|
|
43992
|
+
relativePath: relativeConfigPath,
|
|
43993
|
+
expectedContent: expectedConfig,
|
|
43994
|
+
dryRun,
|
|
43995
|
+
logger
|
|
43996
|
+
})) paths.push(relativeConfigPath);
|
|
43997
|
+
return {
|
|
43998
|
+
count: paths.length,
|
|
43999
|
+
paths,
|
|
44000
|
+
hasDiff: paths.length > 0
|
|
44001
|
+
};
|
|
44002
|
+
}
|
|
44003
|
+
//#endregion
|
|
43669
44004
|
//#region src/types/processor-registry.ts
|
|
43670
44005
|
const PROCESSOR_REGISTRY = [
|
|
43671
44006
|
{
|
|
@@ -44127,6 +44462,41 @@ async function warnSkillSubagentNameCollisions(params) {
|
|
|
44127
44462
|
for (const name of skillNames) if (subagentNames.has(name)) logger.warn(`Skill "${name}" and subagent "${name}" both target '${toolTarget}' and write the same path '${(0, node_path.join)(subagentsDirPath, name)}'; the later generation step overwrites the other's output. Rename one of them or narrow their targets.`);
|
|
44128
44463
|
}
|
|
44129
44464
|
}
|
|
44465
|
+
async function collectHermesProjectPluginNames({ config, resultsById }) {
|
|
44466
|
+
if (config.getGlobal() || !config.getTargets().includes("hermesagent")) return [];
|
|
44467
|
+
const outputRoots = config.getOutputRoots("hermesagent");
|
|
44468
|
+
const enabledFeatures = config.getFeatures("hermesagent");
|
|
44469
|
+
const descriptors = [
|
|
44470
|
+
{
|
|
44471
|
+
feature: "ignore",
|
|
44472
|
+
pluginName: "rulesync-ignore",
|
|
44473
|
+
manifestPath: HERMESAGENT_IGNORE_PLUGIN_MANIFEST_PATH
|
|
44474
|
+
},
|
|
44475
|
+
{
|
|
44476
|
+
feature: "subagents",
|
|
44477
|
+
pluginName: "rulesync-subagents",
|
|
44478
|
+
manifestPath: HERMESAGENT_RULESYNC_SUBAGENTS_PLUGIN_MANIFEST_PATH
|
|
44479
|
+
},
|
|
44480
|
+
{
|
|
44481
|
+
feature: "checks",
|
|
44482
|
+
pluginName: "rulesync-checks",
|
|
44483
|
+
manifestPath: HERMESAGENT_CHECKS_PLUGIN_MANIFEST_PATH
|
|
44484
|
+
}
|
|
44485
|
+
];
|
|
44486
|
+
const pluginNames = [];
|
|
44487
|
+
for (const descriptor of descriptors) {
|
|
44488
|
+
if (!enabledFeatures.includes(descriptor.feature)) continue;
|
|
44489
|
+
const relativeManifestPath = toPosixPath(descriptor.manifestPath);
|
|
44490
|
+
const willWriteManifest = resultsById.get(descriptor.feature)?.paths.some((generatedPath) => toPosixPath(generatedPath) === relativeManifestPath) ?? false;
|
|
44491
|
+
let manifestExists = false;
|
|
44492
|
+
for (const outputRoot of outputRoots) if (await fileExists((0, node_path.join)(outputRoot, descriptor.manifestPath))) {
|
|
44493
|
+
manifestExists = true;
|
|
44494
|
+
break;
|
|
44495
|
+
}
|
|
44496
|
+
if (willWriteManifest || manifestExists) pluginNames.push(descriptor.pluginName);
|
|
44497
|
+
}
|
|
44498
|
+
return pluginNames;
|
|
44499
|
+
}
|
|
44130
44500
|
/**
|
|
44131
44501
|
* Generate configuration files for AI tools.
|
|
44132
44502
|
* @throws Error if generation fails
|
|
@@ -44190,13 +44560,21 @@ async function generate(params) {
|
|
|
44190
44560
|
})));
|
|
44191
44561
|
const resultsById = /* @__PURE__ */ new Map();
|
|
44192
44562
|
for (const step of orderedSteps) resultsById.set(step.id, await step.run());
|
|
44563
|
+
const activationResult = await activateHermesProjectPlugins({
|
|
44564
|
+
pluginNames: await collectHermesProjectPluginNames({
|
|
44565
|
+
config,
|
|
44566
|
+
resultsById
|
|
44567
|
+
}),
|
|
44568
|
+
dryRun: config.isPreviewMode(),
|
|
44569
|
+
logger
|
|
44570
|
+
});
|
|
44193
44571
|
if (!skillsResult) throw new Error("Skills generation step did not run.");
|
|
44194
44572
|
const get = (id) => {
|
|
44195
44573
|
const result = resultsById.get(id);
|
|
44196
44574
|
if (!result) throw new Error(`Missing generation result for step '${id}'.`);
|
|
44197
44575
|
return result;
|
|
44198
44576
|
};
|
|
44199
|
-
const hasDiff = orderedSteps.some((step) => get(step.id).hasDiff);
|
|
44577
|
+
const hasDiff = activationResult.hasDiff || orderedSteps.some((step) => get(step.id).hasDiff);
|
|
44200
44578
|
return {
|
|
44201
44579
|
rulesCount: get("rules").count,
|
|
44202
44580
|
rulesPaths: get("rules").paths,
|
|
@@ -44216,6 +44594,8 @@ async function generate(params) {
|
|
|
44216
44594
|
permissionsPaths: get("permissions").paths,
|
|
44217
44595
|
checksCount: get("checks").count,
|
|
44218
44596
|
checksPaths: get("checks").paths,
|
|
44597
|
+
activationCount: activationResult.count,
|
|
44598
|
+
activationPaths: activationResult.paths,
|
|
44219
44599
|
skills: skillsResult.skills,
|
|
44220
44600
|
hasDiff
|
|
44221
44601
|
};
|