rulesync 9.3.0 → 9.4.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 +4 -61
- package/dist/cli/index.js +2 -59
- package/dist/cli/index.js.map +1 -1
- package/dist/{import-B7VzSVUK.js → import-BxqZVTKb.js} +930 -375
- package/dist/import-BxqZVTKb.js.map +1 -0
- package/dist/{import-CE3Rx3Wt.cjs → import-DVGMvuhx.cjs} +944 -485
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/import-B7VzSVUK.js.map +0 -1
|
@@ -114,22 +114,22 @@ function formatError(error) {
|
|
|
114
114
|
}
|
|
115
115
|
//#endregion
|
|
116
116
|
//#region src/constants/rulesync-paths.ts
|
|
117
|
-
const { join: join$
|
|
117
|
+
const { join: join$247 } = node_path.posix;
|
|
118
118
|
const RULESYNC_CONFIG_RELATIVE_FILE_PATH = "rulesync.jsonc";
|
|
119
119
|
const RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH = "rulesync.local.jsonc";
|
|
120
120
|
const RULESYNC_RELATIVE_DIR_PATH = ".rulesync";
|
|
121
|
-
const RULESYNC_RULES_RELATIVE_DIR_PATH = join$
|
|
122
|
-
const RULESYNC_COMMANDS_RELATIVE_DIR_PATH = join$
|
|
123
|
-
const RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH = join$
|
|
124
|
-
const RULESYNC_MCP_RELATIVE_FILE_PATH = join$
|
|
125
|
-
const RULESYNC_HOOKS_RELATIVE_FILE_PATH = join$
|
|
126
|
-
const RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH = join$
|
|
121
|
+
const RULESYNC_RULES_RELATIVE_DIR_PATH = join$247(RULESYNC_RELATIVE_DIR_PATH, "rules");
|
|
122
|
+
const RULESYNC_COMMANDS_RELATIVE_DIR_PATH = join$247(RULESYNC_RELATIVE_DIR_PATH, "commands");
|
|
123
|
+
const RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH = join$247(RULESYNC_RELATIVE_DIR_PATH, "subagents");
|
|
124
|
+
const RULESYNC_MCP_RELATIVE_FILE_PATH = join$247(RULESYNC_RELATIVE_DIR_PATH, "mcp.json");
|
|
125
|
+
const RULESYNC_HOOKS_RELATIVE_FILE_PATH = join$247(RULESYNC_RELATIVE_DIR_PATH, "hooks.json");
|
|
126
|
+
const RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH = join$247(RULESYNC_RELATIVE_DIR_PATH, "permissions.json");
|
|
127
127
|
const RULESYNC_AIIGNORE_FILE_NAME = ".aiignore";
|
|
128
|
-
const RULESYNC_AIIGNORE_RELATIVE_FILE_PATH = join$
|
|
128
|
+
const RULESYNC_AIIGNORE_RELATIVE_FILE_PATH = join$247(RULESYNC_RELATIVE_DIR_PATH, ".aiignore");
|
|
129
129
|
const RULESYNC_IGNORE_RELATIVE_FILE_PATH = ".rulesyncignore";
|
|
130
130
|
const RULESYNC_OVERVIEW_FILE_NAME = "overview.md";
|
|
131
|
-
const RULESYNC_SKILLS_RELATIVE_DIR_PATH = join$
|
|
132
|
-
const RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH = join$
|
|
131
|
+
const RULESYNC_SKILLS_RELATIVE_DIR_PATH = join$247(RULESYNC_RELATIVE_DIR_PATH, "skills");
|
|
132
|
+
const RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH = join$247(RULESYNC_SKILLS_RELATIVE_DIR_PATH, ".curated");
|
|
133
133
|
const RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH = "rulesync.lock";
|
|
134
134
|
const RULESYNC_MCP_FILE_NAME = "mcp.json";
|
|
135
135
|
const RULESYNC_HOOKS_FILE_NAME = "hooks.json";
|
|
@@ -3919,6 +3919,297 @@ const OPENCODE_JSON_FILE_NAME = "opencode.json";
|
|
|
3919
3919
|
const OPENCODE_RULE_FILE_NAME = "AGENTS.md";
|
|
3920
3920
|
const OPENCODE_HOOKS_FILE_NAME = "rulesync-hooks.js";
|
|
3921
3921
|
//#endregion
|
|
3922
|
+
//#region src/constants/takt-paths.ts
|
|
3923
|
+
const TAKT_DIR = ".takt";
|
|
3924
|
+
const TAKT_FACETS_SUBDIR = "facets";
|
|
3925
|
+
const TAKT_FACETS_DIR_PATH = (0, node_path.join)(TAKT_DIR, TAKT_FACETS_SUBDIR);
|
|
3926
|
+
const TAKT_RULES_DIR_PATH = (0, node_path.join)(TAKT_FACETS_DIR_PATH, "policies");
|
|
3927
|
+
const TAKT_COMMANDS_DIR_PATH = (0, node_path.join)(TAKT_FACETS_DIR_PATH, "instructions");
|
|
3928
|
+
const TAKT_SKILLS_DIR_PATH = (0, node_path.join)(TAKT_FACETS_DIR_PATH, "knowledge");
|
|
3929
|
+
const TAKT_SUBAGENTS_DIR_PATH = (0, node_path.join)(TAKT_FACETS_DIR_PATH, "personas");
|
|
3930
|
+
const TAKT_OUTPUT_CONTRACTS_DIR_PATH = (0, node_path.join)(TAKT_FACETS_DIR_PATH, "output-contracts");
|
|
3931
|
+
const TAKT_RULE_OVERVIEW_FILE_NAME = "overview.md";
|
|
3932
|
+
/**
|
|
3933
|
+
* Takt's shared config file. Lives at `.takt/config.yaml` (project) and
|
|
3934
|
+
* `~/.takt/config.yaml` (global); it holds the active provider, provider
|
|
3935
|
+
* profiles (including permission modes), and other Takt settings.
|
|
3936
|
+
* @see https://github.com/nrslib/takt/blob/main/docs/configuration.md
|
|
3937
|
+
*/
|
|
3938
|
+
const TAKT_CONFIG_FILE_NAME = "config.yaml";
|
|
3939
|
+
/**
|
|
3940
|
+
* Top-level key in Takt's `config.yaml` holding the workflow MCP transport
|
|
3941
|
+
* allowlist (`stdio` / `sse` / `http` booleans). Takt is default-deny: a
|
|
3942
|
+
* transport must be explicitly enabled here before any workflow-defined MCP
|
|
3943
|
+
* server using it is permitted to run.
|
|
3944
|
+
* @see https://github.com/nrslib/takt/blob/main/docs/configuration.md
|
|
3945
|
+
*/
|
|
3946
|
+
const TAKT_WORKFLOW_MCP_SERVERS_KEY = "workflow_mcp_servers";
|
|
3947
|
+
//#endregion
|
|
3948
|
+
//#region src/utils/prototype-pollution.ts
|
|
3949
|
+
/**
|
|
3950
|
+
* Keys that, if walked into when constructing or merging objects from
|
|
3951
|
+
* untrusted input, can mutate `Object.prototype` (or otherwise the prototype
|
|
3952
|
+
* chain) and propagate state to every other object in the runtime. Any code
|
|
3953
|
+
* that copies arbitrary user-supplied keys into a fresh object — frontmatter
|
|
3954
|
+
* parsing, MCP config conversion, settings round-trip — should skip these.
|
|
3955
|
+
*/
|
|
3956
|
+
const PROTOTYPE_POLLUTION_KEYS = /* @__PURE__ */ new Set([
|
|
3957
|
+
"__proto__",
|
|
3958
|
+
"constructor",
|
|
3959
|
+
"prototype"
|
|
3960
|
+
]);
|
|
3961
|
+
function isPrototypePollutionKey(key) {
|
|
3962
|
+
return PROTOTYPE_POLLUTION_KEYS.has(key);
|
|
3963
|
+
}
|
|
3964
|
+
/**
|
|
3965
|
+
* Returns a shallow copy of a record's own entries with every
|
|
3966
|
+
* prototype-pollution key (`__proto__`, `constructor`, `prototype`) dropped.
|
|
3967
|
+
*
|
|
3968
|
+
* Use when copying a nested, user-supplied string map — an MCP server's `env`
|
|
3969
|
+
* or `headers` table — into freshly generated config. Carrying such a map by
|
|
3970
|
+
* reference, or re-assigning its keys via bracket notation, would let a literal
|
|
3971
|
+
* `__proto__` key ride along (and re-assigning it would mutate the target's
|
|
3972
|
+
* prototype). Walking the entries through this helper severs that path while
|
|
3973
|
+
* preserving every legitimate key.
|
|
3974
|
+
*/
|
|
3975
|
+
function omitPrototypePollutionKeys(record) {
|
|
3976
|
+
const sanitized = {};
|
|
3977
|
+
for (const [key, value] of Object.entries(record)) {
|
|
3978
|
+
if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
|
|
3979
|
+
sanitized[key] = value;
|
|
3980
|
+
}
|
|
3981
|
+
return sanitized;
|
|
3982
|
+
}
|
|
3983
|
+
//#endregion
|
|
3984
|
+
//#region src/features/shared/shared-config-gateway.ts
|
|
3985
|
+
function sanitizeSharedConfigValue(value) {
|
|
3986
|
+
if (Array.isArray(value)) return value.map(sanitizeSharedConfigValue);
|
|
3987
|
+
if (!isPlainObject(value)) return value;
|
|
3988
|
+
const result = {};
|
|
3989
|
+
for (const [key, nested] of Object.entries(omitPrototypePollutionKeys(value))) result[key] = sanitizeSharedConfigValue(nested);
|
|
3990
|
+
return result;
|
|
3991
|
+
}
|
|
3992
|
+
/**
|
|
3993
|
+
* Parse a shared config file into a plain document: an empty/whitespace file
|
|
3994
|
+
* is `{}`, prototype-pollution keys are dropped recursively, and a non-mapping
|
|
3995
|
+
* root follows `invalidRootPolicy`. Syntax errors are wrapped with the file
|
|
3996
|
+
* path when one is given.
|
|
3997
|
+
*/
|
|
3998
|
+
function parseSharedConfig({ format, fileContent, filePath, invalidRootPolicy = "coerce-empty" }) {
|
|
3999
|
+
if (fileContent.trim() === "") return {};
|
|
4000
|
+
const at = filePath === void 0 ? "" : ` at ${filePath}`;
|
|
4001
|
+
let parsed;
|
|
4002
|
+
try {
|
|
4003
|
+
if (format === "yaml") parsed = (0, js_yaml.load)(fileContent);
|
|
4004
|
+
else if (format === "json") parsed = JSON.parse(fileContent);
|
|
4005
|
+
else parsed = (0, jsonc_parser.parse)(fileContent);
|
|
4006
|
+
} catch (error) {
|
|
4007
|
+
throw new Error(`Failed to parse shared config${at}: ${formatError(error)}`, { cause: error });
|
|
4008
|
+
}
|
|
4009
|
+
if (parsed === void 0 || parsed === null) return {};
|
|
4010
|
+
if (!isPlainObject(parsed)) {
|
|
4011
|
+
if (invalidRootPolicy === "error") throw new Error(`Failed to parse shared config${at}: expected a mapping at the root`);
|
|
4012
|
+
return {};
|
|
4013
|
+
}
|
|
4014
|
+
return sanitizeSharedConfigValue(parsed);
|
|
4015
|
+
}
|
|
4016
|
+
/**
|
|
4017
|
+
* Serialize a shared config document. YAML output always ends with exactly one
|
|
4018
|
+
* newline; JSON output matches the 2-space `JSON.stringify` shape the JSON
|
|
4019
|
+
* writers have always emitted (no trailing newline).
|
|
4020
|
+
*/
|
|
4021
|
+
function stringifySharedConfig({ format, document }) {
|
|
4022
|
+
if (format === "yaml") return (0, js_yaml.dump)(document, {
|
|
4023
|
+
noRefs: true,
|
|
4024
|
+
sortKeys: false
|
|
4025
|
+
}).trimEnd() + "\n";
|
|
4026
|
+
return JSON.stringify(document, null, 2);
|
|
4027
|
+
}
|
|
4028
|
+
/**
|
|
4029
|
+
* Shallow merge: every top-level key in `patch` replaces the base key
|
|
4030
|
+
* wholesale; all other base keys are preserved. The policy for a feature that
|
|
4031
|
+
* owns a fixed set of top-level keys.
|
|
4032
|
+
*/
|
|
4033
|
+
function mergeSharedConfigShallow({ base, patch }) {
|
|
4034
|
+
return {
|
|
4035
|
+
...base,
|
|
4036
|
+
...sanitizeSharedConfigValue(patch)
|
|
4037
|
+
};
|
|
4038
|
+
}
|
|
4039
|
+
/**
|
|
4040
|
+
* Deep merge (`patch` wins): nested plain objects are merged key-by-key; every
|
|
4041
|
+
* other value (arrays, scalars) is replaced wholesale. The policy for a
|
|
4042
|
+
* feature whose contribution interleaves with user-authored siblings at any
|
|
4043
|
+
* depth (e.g. permissions overlays onto `approvals`/`security` structures, or
|
|
4044
|
+
* per-provider option tables) — nested sibling keys are preserved by
|
|
4045
|
+
* construction instead of by per-tool re-implementation. Prototype-pollution
|
|
4046
|
+
* keys are dropped.
|
|
4047
|
+
*/
|
|
4048
|
+
function mergeSharedConfigDeep({ base, patch }) {
|
|
4049
|
+
const result = { ...base };
|
|
4050
|
+
for (const [key, patchValue] of Object.entries(patch)) {
|
|
4051
|
+
if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
|
|
4052
|
+
const baseValue = result[key];
|
|
4053
|
+
if (isPlainObject(baseValue) && isPlainObject(patchValue)) result[key] = mergeSharedConfigDeep({
|
|
4054
|
+
base: baseValue,
|
|
4055
|
+
patch: patchValue
|
|
4056
|
+
});
|
|
4057
|
+
else result[key] = sanitizeSharedConfigValue(patchValue);
|
|
4058
|
+
}
|
|
4059
|
+
return result;
|
|
4060
|
+
}
|
|
4061
|
+
const CLAUDE_SETTINGS_SHARED_FILE_KEY = ".claude/settings.json";
|
|
4062
|
+
const HERMES_CONFIG_SHARED_FILE_KEY = ".hermes/config.yaml";
|
|
4063
|
+
const TAKT_CONFIG_SHARED_FILE_KEY = ".takt/config.yaml";
|
|
4064
|
+
/**
|
|
4065
|
+
* Who owns what in each gateway-managed shared config file, and which policy
|
|
4066
|
+
* resolves conflicts. Keys are `dir/file` tokens matching
|
|
4067
|
+
* `deriveSharedFileWriters()`; a test keeps each entry's feature set in
|
|
4068
|
+
* lock-step with the writers derived from the processor registry, so an
|
|
4069
|
+
* undeclared writer fails CI instead of merging by accident.
|
|
4070
|
+
*/
|
|
4071
|
+
const SHARED_CONFIG_OWNERSHIP = {
|
|
4072
|
+
[CLAUDE_SETTINGS_SHARED_FILE_KEY]: {
|
|
4073
|
+
format: "json",
|
|
4074
|
+
features: {
|
|
4075
|
+
ignore: {
|
|
4076
|
+
kind: "custom",
|
|
4077
|
+
policyFunction: "applyIgnoreReadDenies"
|
|
4078
|
+
},
|
|
4079
|
+
hooks: {
|
|
4080
|
+
kind: "replace-owned-keys",
|
|
4081
|
+
ownedKeys: ["hooks"]
|
|
4082
|
+
},
|
|
4083
|
+
permissions: {
|
|
4084
|
+
kind: "custom",
|
|
4085
|
+
policyFunction: "applyPermissions"
|
|
4086
|
+
}
|
|
4087
|
+
}
|
|
4088
|
+
},
|
|
4089
|
+
[HERMES_CONFIG_SHARED_FILE_KEY]: {
|
|
4090
|
+
format: "yaml",
|
|
4091
|
+
features: {
|
|
4092
|
+
subagents: {
|
|
4093
|
+
kind: "replace-owned-keys",
|
|
4094
|
+
ownedKeys: ["plugins"]
|
|
4095
|
+
},
|
|
4096
|
+
mcp: {
|
|
4097
|
+
kind: "replace-owned-keys",
|
|
4098
|
+
ownedKeys: ["mcp_servers"]
|
|
4099
|
+
},
|
|
4100
|
+
hooks: {
|
|
4101
|
+
kind: "replace-owned-keys",
|
|
4102
|
+
ownedKeys: ["hooks"]
|
|
4103
|
+
},
|
|
4104
|
+
permissions: {
|
|
4105
|
+
kind: "deep-merge",
|
|
4106
|
+
replaceKeys: ["permissions"]
|
|
4107
|
+
}
|
|
4108
|
+
}
|
|
4109
|
+
},
|
|
4110
|
+
[TAKT_CONFIG_SHARED_FILE_KEY]: {
|
|
4111
|
+
format: "yaml",
|
|
4112
|
+
invalidRootPolicy: "error",
|
|
4113
|
+
features: {
|
|
4114
|
+
mcp: {
|
|
4115
|
+
kind: "replace-owned-keys",
|
|
4116
|
+
ownedKeys: [TAKT_WORKFLOW_MCP_SERVERS_KEY]
|
|
4117
|
+
},
|
|
4118
|
+
permissions: { kind: "deep-merge" }
|
|
4119
|
+
}
|
|
4120
|
+
}
|
|
4121
|
+
};
|
|
4122
|
+
/**
|
|
4123
|
+
* Execute a feature's declared write to a gateway-managed shared file: parse
|
|
4124
|
+
* the existing content, merge the patch under the feature's declared policy,
|
|
4125
|
+
* and serialize. Throws when the file or feature is undeclared, when a
|
|
4126
|
+
* `replace-owned-keys` patch strays outside its owned keys, or when the
|
|
4127
|
+
* feature's policy is `custom` (those calls go to the named policy function
|
|
4128
|
+
* instead).
|
|
4129
|
+
*/
|
|
4130
|
+
function applySharedConfigPatch({ fileKey, feature, existingContent, patch, filePath }) {
|
|
4131
|
+
const declaration = SHARED_CONFIG_OWNERSHIP[fileKey];
|
|
4132
|
+
if (!declaration) throw new Error(`Shared config file '${fileKey}' has no SHARED_CONFIG_OWNERSHIP declaration; declare its writers and policies before writing it through the gateway.`);
|
|
4133
|
+
const policy = declaration.features[feature];
|
|
4134
|
+
if (!policy) throw new Error(`Feature '${feature}' declares no ownership of '${fileKey}'; add it to SHARED_CONFIG_OWNERSHIP before writing.`);
|
|
4135
|
+
if (policy.kind === "custom") throw new Error(`Feature '${feature}' writes '${fileKey}' through its dedicated policy function '${policy.policyFunction}' in shared-config-gateway.ts, not applySharedConfigPatch.`);
|
|
4136
|
+
const base = parseSharedConfig({
|
|
4137
|
+
format: declaration.format,
|
|
4138
|
+
fileContent: existingContent,
|
|
4139
|
+
filePath,
|
|
4140
|
+
...declaration.invalidRootPolicy !== void 0 && { invalidRootPolicy: declaration.invalidRootPolicy }
|
|
4141
|
+
});
|
|
4142
|
+
if (policy.kind === "replace-owned-keys") {
|
|
4143
|
+
const unowned = Object.keys(patch).filter((key) => !policy.ownedKeys.includes(key));
|
|
4144
|
+
if (unowned.length > 0) throw new Error(`Feature '${feature}' tried to write undeclared keys [${unowned.join(", ")}] to '${fileKey}'; extend its ownedKeys declaration if that ownership is intended.`);
|
|
4145
|
+
return stringifySharedConfig({
|
|
4146
|
+
format: declaration.format,
|
|
4147
|
+
document: mergeSharedConfigShallow({
|
|
4148
|
+
base,
|
|
4149
|
+
patch
|
|
4150
|
+
})
|
|
4151
|
+
});
|
|
4152
|
+
}
|
|
4153
|
+
const merged = mergeSharedConfigDeep({
|
|
4154
|
+
base,
|
|
4155
|
+
patch
|
|
4156
|
+
});
|
|
4157
|
+
for (const key of policy.replaceKeys ?? []) if (patch[key] !== void 0) merged[key] = sanitizeSharedConfigValue(patch[key]);
|
|
4158
|
+
return stringifySharedConfig({
|
|
4159
|
+
format: declaration.format,
|
|
4160
|
+
document: merged
|
|
4161
|
+
});
|
|
4162
|
+
}
|
|
4163
|
+
const READ_TOOL_NAME = "Read";
|
|
4164
|
+
const isReadDenyEntry = (entry) => entry.startsWith(`${READ_TOOL_NAME}(`) && entry.endsWith(")");
|
|
4165
|
+
const buildReadDenyEntry = (pattern) => `${READ_TOOL_NAME}(${pattern})`;
|
|
4166
|
+
const parsePermissionsBlock = (settings) => {
|
|
4167
|
+
const permissions = settings.permissions ?? {};
|
|
4168
|
+
return {
|
|
4169
|
+
allow: permissions.allow ?? [],
|
|
4170
|
+
ask: permissions.ask ?? [],
|
|
4171
|
+
deny: permissions.deny ?? []
|
|
4172
|
+
};
|
|
4173
|
+
};
|
|
4174
|
+
const withPermissions = (settings, next) => {
|
|
4175
|
+
const permissions = { ...settings.permissions };
|
|
4176
|
+
const assign = (key, values) => {
|
|
4177
|
+
if (values.length > 0) permissions[key] = values;
|
|
4178
|
+
else delete permissions[key];
|
|
4179
|
+
};
|
|
4180
|
+
assign("allow", next.allow);
|
|
4181
|
+
assign("ask", next.ask);
|
|
4182
|
+
assign("deny", next.deny);
|
|
4183
|
+
return {
|
|
4184
|
+
...settings,
|
|
4185
|
+
permissions
|
|
4186
|
+
};
|
|
4187
|
+
};
|
|
4188
|
+
const applyIgnoreReadDenies = (params) => {
|
|
4189
|
+
const { settings, readDenies } = params;
|
|
4190
|
+
const current = parsePermissionsBlock(settings);
|
|
4191
|
+
const preservedDeny = current.deny.filter((entry) => !isReadDenyEntry(entry) || readDenies.includes(entry));
|
|
4192
|
+
return withPermissions(settings, {
|
|
4193
|
+
allow: current.allow,
|
|
4194
|
+
ask: current.ask,
|
|
4195
|
+
deny: (0, es_toolkit.uniq)([...preservedDeny, ...readDenies].toSorted())
|
|
4196
|
+
});
|
|
4197
|
+
};
|
|
4198
|
+
const applyPermissions = (params) => {
|
|
4199
|
+
const { settings, managedToolNames, toolNameOf, allow, ask, deny, logger } = params;
|
|
4200
|
+
const current = parsePermissionsBlock(settings);
|
|
4201
|
+
const keepUnmanaged = (entries) => entries.filter((entry) => !managedToolNames.has(toolNameOf(entry)));
|
|
4202
|
+
if (logger && managedToolNames.has(READ_TOOL_NAME)) {
|
|
4203
|
+
const overwrittenReadDenies = current.deny.filter((entry) => toolNameOf(entry) === READ_TOOL_NAME);
|
|
4204
|
+
if (overwrittenReadDenies.length > 0) logger.warn(`Permissions feature manages '${READ_TOOL_NAME}' tool and will overwrite ${overwrittenReadDenies.length} existing ${READ_TOOL_NAME} deny entries. Permissions take precedence.`);
|
|
4205
|
+
}
|
|
4206
|
+
return withPermissions(settings, {
|
|
4207
|
+
allow: (0, es_toolkit.uniq)([...keepUnmanaged(current.allow), ...allow].toSorted()),
|
|
4208
|
+
ask: (0, es_toolkit.uniq)([...keepUnmanaged(current.ask), ...ask].toSorted()),
|
|
4209
|
+
deny: (0, es_toolkit.uniq)([...keepUnmanaged(current.deny), ...deny].toSorted())
|
|
4210
|
+
});
|
|
4211
|
+
};
|
|
4212
|
+
//#endregion
|
|
3922
4213
|
//#region src/features/opencode-config.ts
|
|
3923
4214
|
/**
|
|
3924
4215
|
* Reads and parses the OpenCode config (`opencode.jsonc` preferred, then
|
|
@@ -3943,9 +4234,10 @@ async function readOpencodeConfig({ outputRoot, global = false }) {
|
|
|
3943
4234
|
});
|
|
3944
4235
|
const fileContent = await readFileContentOrNull((0, node_path.join)(configDir, "opencode.jsonc")) ?? await readFileContentOrNull((0, node_path.join)(configDir, "opencode.json"));
|
|
3945
4236
|
if (!fileContent) return {};
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
4237
|
+
return parseSharedConfig({
|
|
4238
|
+
format: "jsonc",
|
|
4239
|
+
fileContent
|
|
4240
|
+
});
|
|
3949
4241
|
}
|
|
3950
4242
|
/**
|
|
3951
4243
|
* Narrows an unknown value to a plain record of entries keyed by name, as used
|
|
@@ -4854,32 +5146,6 @@ var RovodevPromptsManifest = class extends ToolFile {
|
|
|
4854
5146
|
}
|
|
4855
5147
|
};
|
|
4856
5148
|
//#endregion
|
|
4857
|
-
//#region src/constants/takt-paths.ts
|
|
4858
|
-
const TAKT_DIR = ".takt";
|
|
4859
|
-
const TAKT_FACETS_SUBDIR = "facets";
|
|
4860
|
-
const TAKT_FACETS_DIR_PATH = (0, node_path.join)(TAKT_DIR, TAKT_FACETS_SUBDIR);
|
|
4861
|
-
const TAKT_RULES_DIR_PATH = (0, node_path.join)(TAKT_FACETS_DIR_PATH, "policies");
|
|
4862
|
-
const TAKT_COMMANDS_DIR_PATH = (0, node_path.join)(TAKT_FACETS_DIR_PATH, "instructions");
|
|
4863
|
-
const TAKT_SKILLS_DIR_PATH = (0, node_path.join)(TAKT_FACETS_DIR_PATH, "knowledge");
|
|
4864
|
-
const TAKT_SUBAGENTS_DIR_PATH = (0, node_path.join)(TAKT_FACETS_DIR_PATH, "personas");
|
|
4865
|
-
const TAKT_OUTPUT_CONTRACTS_DIR_PATH = (0, node_path.join)(TAKT_FACETS_DIR_PATH, "output-contracts");
|
|
4866
|
-
const TAKT_RULE_OVERVIEW_FILE_NAME = "overview.md";
|
|
4867
|
-
/**
|
|
4868
|
-
* Takt's shared config file. Lives at `.takt/config.yaml` (project) and
|
|
4869
|
-
* `~/.takt/config.yaml` (global); it holds the active provider, provider
|
|
4870
|
-
* profiles (including permission modes), and other Takt settings.
|
|
4871
|
-
* @see https://github.com/nrslib/takt/blob/main/docs/configuration.md
|
|
4872
|
-
*/
|
|
4873
|
-
const TAKT_CONFIG_FILE_NAME = "config.yaml";
|
|
4874
|
-
/**
|
|
4875
|
-
* Top-level key in Takt's `config.yaml` holding the workflow MCP transport
|
|
4876
|
-
* allowlist (`stdio` / `sse` / `http` booleans). Takt is default-deny: a
|
|
4877
|
-
* transport must be explicitly enabled here before any workflow-defined MCP
|
|
4878
|
-
* server using it is permitted to run.
|
|
4879
|
-
* @see https://github.com/nrslib/takt/blob/main/docs/configuration.md
|
|
4880
|
-
*/
|
|
4881
|
-
const TAKT_WORKFLOW_MCP_SERVERS_KEY = "workflow_mcp_servers";
|
|
4882
|
-
//#endregion
|
|
4883
5149
|
//#region src/features/takt-shared.ts
|
|
4884
5150
|
/**
|
|
4885
5151
|
* Shared utilities for all TAKT-* tool file classes.
|
|
@@ -6357,42 +6623,6 @@ const CANONICAL_TO_REASONIX_EVENT_NAMES = {
|
|
|
6357
6623
|
*/
|
|
6358
6624
|
const REASONIX_TO_CANONICAL_EVENT_NAMES = Object.fromEntries(Object.entries(CANONICAL_TO_REASONIX_EVENT_NAMES).map(([k, v]) => [v, k]));
|
|
6359
6625
|
//#endregion
|
|
6360
|
-
//#region src/utils/prototype-pollution.ts
|
|
6361
|
-
/**
|
|
6362
|
-
* Keys that, if walked into when constructing or merging objects from
|
|
6363
|
-
* untrusted input, can mutate `Object.prototype` (or otherwise the prototype
|
|
6364
|
-
* chain) and propagate state to every other object in the runtime. Any code
|
|
6365
|
-
* that copies arbitrary user-supplied keys into a fresh object — frontmatter
|
|
6366
|
-
* parsing, MCP config conversion, settings round-trip — should skip these.
|
|
6367
|
-
*/
|
|
6368
|
-
const PROTOTYPE_POLLUTION_KEYS = /* @__PURE__ */ new Set([
|
|
6369
|
-
"__proto__",
|
|
6370
|
-
"constructor",
|
|
6371
|
-
"prototype"
|
|
6372
|
-
]);
|
|
6373
|
-
function isPrototypePollutionKey(key) {
|
|
6374
|
-
return PROTOTYPE_POLLUTION_KEYS.has(key);
|
|
6375
|
-
}
|
|
6376
|
-
/**
|
|
6377
|
-
* Returns a shallow copy of a record's own entries with every
|
|
6378
|
-
* prototype-pollution key (`__proto__`, `constructor`, `prototype`) dropped.
|
|
6379
|
-
*
|
|
6380
|
-
* Use when copying a nested, user-supplied string map — an MCP server's `env`
|
|
6381
|
-
* or `headers` table — into freshly generated config. Carrying such a map by
|
|
6382
|
-
* reference, or re-assigning its keys via bracket notation, would let a literal
|
|
6383
|
-
* `__proto__` key ride along (and re-assigning it would mutate the target's
|
|
6384
|
-
* prototype). Walking the entries through this helper severs that path while
|
|
6385
|
-
* preserving every legitimate key.
|
|
6386
|
-
*/
|
|
6387
|
-
function omitPrototypePollutionKeys(record) {
|
|
6388
|
-
const sanitized = {};
|
|
6389
|
-
for (const [key, value] of Object.entries(record)) {
|
|
6390
|
-
if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
|
|
6391
|
-
sanitized[key] = value;
|
|
6392
|
-
}
|
|
6393
|
-
return sanitized;
|
|
6394
|
-
}
|
|
6395
|
-
//#endregion
|
|
6396
6626
|
//#region src/features/hooks/tool-hooks-converter.ts
|
|
6397
6627
|
function isToolMatcherEntry(x) {
|
|
6398
6628
|
if (x === null || typeof x !== "object") return false;
|
|
@@ -7051,24 +7281,19 @@ var ClaudecodeHooks = class ClaudecodeHooks extends ToolHooks {
|
|
|
7051
7281
|
const paths = ClaudecodeHooks.getSettablePaths({ global });
|
|
7052
7282
|
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
7053
7283
|
const existingContent = await readOrInitializeFileContent(filePath, JSON.stringify({}, null, 2));
|
|
7054
|
-
let settings;
|
|
7055
|
-
try {
|
|
7056
|
-
settings = JSON.parse(existingContent);
|
|
7057
|
-
} catch (error) {
|
|
7058
|
-
throw new Error(`Failed to parse existing Claude settings at ${filePath}: ${formatError(error)}`, { cause: error });
|
|
7059
|
-
}
|
|
7060
7284
|
const config = rulesyncHooks.getJson();
|
|
7061
|
-
const
|
|
7062
|
-
|
|
7063
|
-
|
|
7064
|
-
|
|
7065
|
-
|
|
7285
|
+
const fileContent = applySharedConfigPatch({
|
|
7286
|
+
fileKey: CLAUDE_SETTINGS_SHARED_FILE_KEY,
|
|
7287
|
+
feature: "hooks",
|
|
7288
|
+
existingContent,
|
|
7289
|
+
patch: { hooks: canonicalToToolHooks({
|
|
7290
|
+
config,
|
|
7291
|
+
toolOverrideHooks: config.claudecode?.hooks,
|
|
7292
|
+
converterConfig: CLAUDE_CONVERTER_CONFIG,
|
|
7293
|
+
logger
|
|
7294
|
+
}) },
|
|
7295
|
+
filePath
|
|
7066
7296
|
});
|
|
7067
|
-
const merged = {
|
|
7068
|
-
...settings,
|
|
7069
|
-
hooks: claudeHooks
|
|
7070
|
-
};
|
|
7071
|
-
const fileContent = JSON.stringify(merged, null, 2);
|
|
7072
7297
|
return new ClaudecodeHooks({
|
|
7073
7298
|
outputRoot,
|
|
7074
7299
|
relativeDirPath: paths.relativeDirPath,
|
|
@@ -8300,55 +8525,6 @@ var GooseHooks = class GooseHooks extends ToolHooks {
|
|
|
8300
8525
|
}
|
|
8301
8526
|
};
|
|
8302
8527
|
//#endregion
|
|
8303
|
-
//#region src/features/hermes-config.ts
|
|
8304
|
-
function sanitizeHermesConfigValue(value) {
|
|
8305
|
-
if (Array.isArray(value)) return value.map(sanitizeHermesConfigValue);
|
|
8306
|
-
if (!isPlainObject(value)) return value;
|
|
8307
|
-
const sanitized = omitPrototypePollutionKeys(value);
|
|
8308
|
-
const result = {};
|
|
8309
|
-
for (const [key, nestedValue] of Object.entries(sanitized)) {
|
|
8310
|
-
if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
|
|
8311
|
-
result[key] = sanitizeHermesConfigValue(nestedValue);
|
|
8312
|
-
}
|
|
8313
|
-
return result;
|
|
8314
|
-
}
|
|
8315
|
-
function parseHermesConfig(fileContent) {
|
|
8316
|
-
if (!fileContent.trim()) return {};
|
|
8317
|
-
const parsed = (0, js_yaml.load)(fileContent);
|
|
8318
|
-
if (isPlainObject(parsed)) return sanitizeHermesConfigValue(parsed);
|
|
8319
|
-
return {};
|
|
8320
|
-
}
|
|
8321
|
-
function stringifyHermesConfig(config) {
|
|
8322
|
-
return (0, js_yaml.dump)(config, {
|
|
8323
|
-
noRefs: true,
|
|
8324
|
-
sortKeys: false
|
|
8325
|
-
}).trimEnd() + "\n";
|
|
8326
|
-
}
|
|
8327
|
-
function mergeHermesConfig(fileContent, patch) {
|
|
8328
|
-
return stringifyHermesConfig({
|
|
8329
|
-
...parseHermesConfig(fileContent),
|
|
8330
|
-
...patch
|
|
8331
|
-
});
|
|
8332
|
-
}
|
|
8333
|
-
/**
|
|
8334
|
-
* Recursively merge `patch` into `base` (patch wins). Nested plain objects are
|
|
8335
|
-
* merged key-by-key; every other value (arrays, scalars) is replaced wholesale.
|
|
8336
|
-
* Used to overlay the Hermes-scoped permission override onto the natively
|
|
8337
|
-
* emitted `approvals`/`security` structures without one clobbering the other
|
|
8338
|
-
* (e.g. `approvals.deny` from canonical deny rules coexisting with an
|
|
8339
|
-
* `approvals.mode` from the override). Prototype-pollution keys are dropped.
|
|
8340
|
-
*/
|
|
8341
|
-
function deepMergeHermesConfig(base, patch) {
|
|
8342
|
-
const result = { ...base };
|
|
8343
|
-
for (const [key, patchValue] of Object.entries(patch)) {
|
|
8344
|
-
if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
|
|
8345
|
-
const baseValue = result[key];
|
|
8346
|
-
if (isPlainObject(baseValue) && isPlainObject(patchValue)) result[key] = deepMergeHermesConfig(baseValue, patchValue);
|
|
8347
|
-
else result[key] = sanitizeHermesConfigValue(patchValue);
|
|
8348
|
-
}
|
|
8349
|
-
return result;
|
|
8350
|
-
}
|
|
8351
|
-
//#endregion
|
|
8352
8528
|
//#region src/features/hooks/hermesagent-hooks.ts
|
|
8353
8529
|
/**
|
|
8354
8530
|
* Canonical events that map to a Hermes tool-call event (`pre_tool_call` /
|
|
@@ -8476,10 +8652,21 @@ var HermesagentHooks = class HermesagentHooks extends ToolHooks {
|
|
|
8476
8652
|
return true;
|
|
8477
8653
|
}
|
|
8478
8654
|
setFileContent(fileContent) {
|
|
8479
|
-
this.fileContent =
|
|
8655
|
+
this.fileContent = applySharedConfigPatch({
|
|
8656
|
+
fileKey: HERMES_CONFIG_SHARED_FILE_KEY,
|
|
8657
|
+
feature: "hooks",
|
|
8658
|
+
existingContent: fileContent,
|
|
8659
|
+
patch: parseSharedConfig({
|
|
8660
|
+
format: "yaml",
|
|
8661
|
+
fileContent: this.fileContent
|
|
8662
|
+
})
|
|
8663
|
+
});
|
|
8480
8664
|
}
|
|
8481
8665
|
toRulesyncHooks() {
|
|
8482
|
-
const hooks = hermesHooksToCanonical(
|
|
8666
|
+
const hooks = hermesHooksToCanonical(parseSharedConfig({
|
|
8667
|
+
format: "yaml",
|
|
8668
|
+
fileContent: this.getFileContent()
|
|
8669
|
+
}).hooks);
|
|
8483
8670
|
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
|
|
8484
8671
|
version: 1,
|
|
8485
8672
|
hooks
|
|
@@ -8489,11 +8676,14 @@ var HermesagentHooks = class HermesagentHooks extends ToolHooks {
|
|
|
8489
8676
|
const config = rulesyncHooks.getJson();
|
|
8490
8677
|
return new HermesagentHooks({
|
|
8491
8678
|
outputRoot,
|
|
8492
|
-
fileContent:
|
|
8493
|
-
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
|
|
8679
|
+
fileContent: stringifySharedConfig({
|
|
8680
|
+
format: "yaml",
|
|
8681
|
+
document: { hooks: canonicalToHermesHooks({
|
|
8682
|
+
config,
|
|
8683
|
+
toolOverrideHooks: config.hermesagent?.hooks,
|
|
8684
|
+
logger
|
|
8685
|
+
}) }
|
|
8686
|
+
})
|
|
8497
8687
|
});
|
|
8498
8688
|
}
|
|
8499
8689
|
};
|
|
@@ -10513,66 +10703,6 @@ var AugmentcodeIgnore = class AugmentcodeIgnore extends ToolIgnore {
|
|
|
10513
10703
|
}
|
|
10514
10704
|
};
|
|
10515
10705
|
//#endregion
|
|
10516
|
-
//#region src/features/claudecode-settings-gateway.ts
|
|
10517
|
-
/**
|
|
10518
|
-
* Single owner of the `.claude/settings.json` `permissions` block, which both
|
|
10519
|
-
* `ignore` (writes `Read(...)` into `permissions.deny`) and `permissions`
|
|
10520
|
-
* (writes the whole `allow`/`ask`/`deny`) read-modify-write. The entry format,
|
|
10521
|
-
* the merge, and the cross-feature ownership rule (permissions' explicit `Read`
|
|
10522
|
-
* rules win over ignore-derived `Read` denies) used to be duplicated across both
|
|
10523
|
-
* feature files; they live here once so each feature just states its intent and
|
|
10524
|
-
* never reasons about the other's existence.
|
|
10525
|
-
*/
|
|
10526
|
-
const READ_TOOL_NAME = "Read";
|
|
10527
|
-
const isReadDenyEntry = (entry) => entry.startsWith(`${READ_TOOL_NAME}(`) && entry.endsWith(")");
|
|
10528
|
-
const buildReadDenyEntry = (pattern) => `${READ_TOOL_NAME}(${pattern})`;
|
|
10529
|
-
const parsePermissionsBlock = (settings) => {
|
|
10530
|
-
const permissions = settings.permissions ?? {};
|
|
10531
|
-
return {
|
|
10532
|
-
allow: permissions.allow ?? [],
|
|
10533
|
-
ask: permissions.ask ?? [],
|
|
10534
|
-
deny: permissions.deny ?? []
|
|
10535
|
-
};
|
|
10536
|
-
};
|
|
10537
|
-
const withPermissions = (settings, next) => {
|
|
10538
|
-
const permissions = { ...settings.permissions };
|
|
10539
|
-
const assign = (key, values) => {
|
|
10540
|
-
if (values.length > 0) permissions[key] = values;
|
|
10541
|
-
else delete permissions[key];
|
|
10542
|
-
};
|
|
10543
|
-
assign("allow", next.allow);
|
|
10544
|
-
assign("ask", next.ask);
|
|
10545
|
-
assign("deny", next.deny);
|
|
10546
|
-
return {
|
|
10547
|
-
...settings,
|
|
10548
|
-
permissions
|
|
10549
|
-
};
|
|
10550
|
-
};
|
|
10551
|
-
const applyIgnoreReadDenies = (params) => {
|
|
10552
|
-
const { settings, readDenies } = params;
|
|
10553
|
-
const current = parsePermissionsBlock(settings);
|
|
10554
|
-
const preservedDeny = current.deny.filter((entry) => !isReadDenyEntry(entry) || readDenies.includes(entry));
|
|
10555
|
-
return withPermissions(settings, {
|
|
10556
|
-
allow: current.allow,
|
|
10557
|
-
ask: current.ask,
|
|
10558
|
-
deny: (0, es_toolkit.uniq)([...preservedDeny, ...readDenies].toSorted())
|
|
10559
|
-
});
|
|
10560
|
-
};
|
|
10561
|
-
const applyPermissions = (params) => {
|
|
10562
|
-
const { settings, managedToolNames, toolNameOf, allow, ask, deny, logger } = params;
|
|
10563
|
-
const current = parsePermissionsBlock(settings);
|
|
10564
|
-
const keepUnmanaged = (entries) => entries.filter((entry) => !managedToolNames.has(toolNameOf(entry)));
|
|
10565
|
-
if (logger && managedToolNames.has(READ_TOOL_NAME)) {
|
|
10566
|
-
const overwrittenReadDenies = current.deny.filter((entry) => toolNameOf(entry) === READ_TOOL_NAME);
|
|
10567
|
-
if (overwrittenReadDenies.length > 0) logger.warn(`Permissions feature manages '${READ_TOOL_NAME}' tool and will overwrite ${overwrittenReadDenies.length} existing ${READ_TOOL_NAME} deny entries. Permissions take precedence.`);
|
|
10568
|
-
}
|
|
10569
|
-
return withPermissions(settings, {
|
|
10570
|
-
allow: (0, es_toolkit.uniq)([...keepUnmanaged(current.allow), ...allow].toSorted()),
|
|
10571
|
-
ask: (0, es_toolkit.uniq)([...keepUnmanaged(current.ask), ...ask].toSorted()),
|
|
10572
|
-
deny: (0, es_toolkit.uniq)([...keepUnmanaged(current.deny), ...deny].toSorted())
|
|
10573
|
-
});
|
|
10574
|
-
};
|
|
10575
|
-
//#endregion
|
|
10576
10706
|
//#region src/features/ignore/claudecode-ignore.ts
|
|
10577
10707
|
const DEFAULT_FILE_MODE = "shared";
|
|
10578
10708
|
/**
|
|
@@ -11995,7 +12125,6 @@ var AntigravityIdeMcp = class extends AntigravityMcp {
|
|
|
11995
12125
|
};
|
|
11996
12126
|
//#endregion
|
|
11997
12127
|
//#region src/features/mcp/augmentcode-mcp.ts
|
|
11998
|
-
const AUGMENTCODE_GLOBAL_ONLY_MESSAGE = "AugmentCode MCP is global-only; use --global to sync ~/.augment/settings.json";
|
|
11999
12128
|
function parseAugmentcodeSettings(fileContent, relativeDirPath, relativeFilePath) {
|
|
12000
12129
|
const configPath = (0, node_path.join)(relativeDirPath, relativeFilePath);
|
|
12001
12130
|
let parsed;
|
|
@@ -12010,13 +12139,15 @@ function parseAugmentcodeSettings(fileContent, relativeDirPath, relativeFilePath
|
|
|
12010
12139
|
/**
|
|
12011
12140
|
* AugmentCode (Auggie CLI) MCP servers.
|
|
12012
12141
|
*
|
|
12013
|
-
* MCP servers are persisted in the shared
|
|
12014
|
-
*
|
|
12015
|
-
*
|
|
12142
|
+
* MCP servers are persisted in the shared settings file `.augment/settings.json`
|
|
12143
|
+
* at either scope: the committed workspace file for team-shared servers (project)
|
|
12144
|
+
* or `~/.augment/settings.json` (global). That same file also holds `hooks` and
|
|
12016
12145
|
* `toolPermissions`, so generation merges the `mcpServers` block into the
|
|
12017
|
-
* existing settings instead of overwriting it, and the file is never deleted.
|
|
12146
|
+
* existing settings instead of overwriting it, and the file is never deleted. On
|
|
12147
|
+
* project-scope import the gitignored `.augment/settings.local.json` overrides
|
|
12148
|
+
* file is overlaid on top (the same layering the hooks/permissions adapters use).
|
|
12018
12149
|
*
|
|
12019
|
-
* @see https://docs.augmentcode.com/cli/
|
|
12150
|
+
* @see https://docs.augmentcode.com/cli/config
|
|
12020
12151
|
*/
|
|
12021
12152
|
var AugmentcodeMcp = class AugmentcodeMcp extends ToolMcp {
|
|
12022
12153
|
json;
|
|
@@ -12038,9 +12169,14 @@ var AugmentcodeMcp = class AugmentcodeMcp extends ToolMcp {
|
|
|
12038
12169
|
};
|
|
12039
12170
|
}
|
|
12040
12171
|
static async fromFile({ outputRoot = process.cwd(), validate = true, global = false }) {
|
|
12041
|
-
if (!global) throw new Error(AUGMENTCODE_GLOBAL_ONLY_MESSAGE);
|
|
12042
12172
|
const paths = this.getSettablePaths({ global });
|
|
12043
|
-
const json = parseAugmentcodeSettings(await
|
|
12173
|
+
const json = parseAugmentcodeSettings(await readAugmentcodeSettingsWithLocalOverlay({
|
|
12174
|
+
outputRoot,
|
|
12175
|
+
relativeDirPath: paths.relativeDirPath,
|
|
12176
|
+
baseFileName: paths.relativeFilePath,
|
|
12177
|
+
baseFallbackContent: "{}",
|
|
12178
|
+
includeLocalOverlay: !global
|
|
12179
|
+
}), paths.relativeDirPath, paths.relativeFilePath);
|
|
12044
12180
|
const newJson = {
|
|
12045
12181
|
...json,
|
|
12046
12182
|
mcpServers: json.mcpServers ?? {}
|
|
@@ -12055,7 +12191,6 @@ var AugmentcodeMcp = class AugmentcodeMcp extends ToolMcp {
|
|
|
12055
12191
|
});
|
|
12056
12192
|
}
|
|
12057
12193
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
12058
|
-
if (!global) throw new Error(AUGMENTCODE_GLOBAL_ONLY_MESSAGE);
|
|
12059
12194
|
const paths = this.getSettablePaths({ global });
|
|
12060
12195
|
const merged = {
|
|
12061
12196
|
...parseAugmentcodeSettings(await readOrInitializeFileContent((0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath), JSON.stringify({}, null, 2)), paths.relativeDirPath, paths.relativeFilePath),
|
|
@@ -13705,7 +13840,10 @@ var HermesagentMcp = class HermesagentMcp extends ToolMcp {
|
|
|
13705
13840
|
config;
|
|
13706
13841
|
constructor(params) {
|
|
13707
13842
|
super(params);
|
|
13708
|
-
this.config = this.fileContent !== void 0 ?
|
|
13843
|
+
this.config = this.fileContent !== void 0 ? parseSharedConfig({
|
|
13844
|
+
format: "yaml",
|
|
13845
|
+
fileContent: this.fileContent
|
|
13846
|
+
}) : {};
|
|
13709
13847
|
}
|
|
13710
13848
|
getConfig() {
|
|
13711
13849
|
return this.config;
|
|
@@ -13714,9 +13852,17 @@ var HermesagentMcp = class HermesagentMcp extends ToolMcp {
|
|
|
13714
13852
|
return true;
|
|
13715
13853
|
}
|
|
13716
13854
|
setFileContent(fileContent) {
|
|
13717
|
-
const merged = mergeHermesMcpServers(
|
|
13855
|
+
const merged = mergeHermesMcpServers(parseSharedConfig({
|
|
13856
|
+
format: "yaml",
|
|
13857
|
+
fileContent
|
|
13858
|
+
}), isRecord(this.config.mcp_servers) ? this.config.mcp_servers : {});
|
|
13718
13859
|
this.config = merged;
|
|
13719
|
-
super.setFileContent(
|
|
13860
|
+
super.setFileContent(applySharedConfigPatch({
|
|
13861
|
+
fileKey: HERMES_CONFIG_SHARED_FILE_KEY,
|
|
13862
|
+
feature: "mcp",
|
|
13863
|
+
existingContent: fileContent,
|
|
13864
|
+
patch: { mcp_servers: merged.mcp_servers }
|
|
13865
|
+
}));
|
|
13720
13866
|
}
|
|
13721
13867
|
isDeletable() {
|
|
13722
13868
|
return false;
|
|
@@ -13743,12 +13889,21 @@ var HermesagentMcp = class HermesagentMcp extends ToolMcp {
|
|
|
13743
13889
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
13744
13890
|
if (!global) throw new Error(HERMESAGENT_GLOBAL_ONLY_MESSAGE);
|
|
13745
13891
|
const paths = this.getSettablePaths({ global });
|
|
13746
|
-
const
|
|
13892
|
+
const fileContent = await readOrInitializeFileContent((0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath), "");
|
|
13893
|
+
const merged = mergeHermesMcpServers(parseSharedConfig({
|
|
13894
|
+
format: "yaml",
|
|
13895
|
+
fileContent
|
|
13896
|
+
}), convertToHermesFormat(rulesyncMcp.getMcpServers()));
|
|
13747
13897
|
return new HermesagentMcp({
|
|
13748
13898
|
outputRoot,
|
|
13749
13899
|
relativeDirPath: paths.relativeDirPath,
|
|
13750
13900
|
relativeFilePath: paths.relativeFilePath,
|
|
13751
|
-
fileContent:
|
|
13901
|
+
fileContent: applySharedConfigPatch({
|
|
13902
|
+
fileKey: HERMES_CONFIG_SHARED_FILE_KEY,
|
|
13903
|
+
feature: "mcp",
|
|
13904
|
+
existingContent: fileContent,
|
|
13905
|
+
patch: { mcp_servers: merged.mcp_servers }
|
|
13906
|
+
}),
|
|
13752
13907
|
validate,
|
|
13753
13908
|
global
|
|
13754
13909
|
});
|
|
@@ -14913,28 +15068,6 @@ var RovodevMcp = class RovodevMcp extends ToolMcp {
|
|
|
14913
15068
|
}
|
|
14914
15069
|
};
|
|
14915
15070
|
//#endregion
|
|
14916
|
-
//#region src/features/shared/takt-config.ts
|
|
14917
|
-
/**
|
|
14918
|
-
* Parse a Takt `config.yaml` into a plain object, treating an empty file as `{}`.
|
|
14919
|
-
*
|
|
14920
|
-
* Shared by the Takt adapters that read-modify-write the same `config.yaml`
|
|
14921
|
-
* (mcp, permissions, ...). Uses `isPlainObject` (not `isRecord`) so class
|
|
14922
|
-
* instances are rejected for prototype-pollution hardening; a YAML mapping
|
|
14923
|
-
* always parses to a plain object.
|
|
14924
|
-
*/
|
|
14925
|
-
function parseTaktConfig(fileContent, relativeDirPath, relativeFilePath) {
|
|
14926
|
-
const configPath = (0, node_path.join)(relativeDirPath, relativeFilePath);
|
|
14927
|
-
let parsed;
|
|
14928
|
-
try {
|
|
14929
|
-
parsed = fileContent.trim() === "" ? {} : (0, js_yaml.load)(fileContent);
|
|
14930
|
-
} catch (error) {
|
|
14931
|
-
throw new Error(`Failed to parse Takt config at ${configPath}: ${formatError(error)}`, { cause: error });
|
|
14932
|
-
}
|
|
14933
|
-
if (parsed === void 0 || parsed === null) return {};
|
|
14934
|
-
if (!isPlainObject(parsed)) throw new Error(`Failed to parse Takt config at ${configPath}: expected a YAML mapping`);
|
|
14935
|
-
return parsed;
|
|
14936
|
-
}
|
|
14937
|
-
//#endregion
|
|
14938
15071
|
//#region src/features/mcp/takt-mcp.ts
|
|
14939
15072
|
/**
|
|
14940
15073
|
* MCP adapter for Takt (`.takt/config.yaml` project / `~/.takt/config.yaml`
|
|
@@ -15000,17 +15133,20 @@ var TaktMcp = class TaktMcp extends ToolMcp {
|
|
|
15000
15133
|
}
|
|
15001
15134
|
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
15002
15135
|
const paths = TaktMcp.getSettablePaths({ global });
|
|
15003
|
-
const
|
|
15136
|
+
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
15137
|
+
const existingContent = await readFileContentOrNull(filePath) ?? "";
|
|
15004
15138
|
const allowlist = deriveTransportAllowlist(rulesyncMcp.getMcpServers());
|
|
15005
|
-
const merged = {
|
|
15006
|
-
...config,
|
|
15007
|
-
[TAKT_WORKFLOW_MCP_SERVERS_KEY]: allowlist
|
|
15008
|
-
};
|
|
15009
15139
|
return new TaktMcp({
|
|
15010
15140
|
outputRoot,
|
|
15011
15141
|
relativeDirPath: paths.relativeDirPath,
|
|
15012
15142
|
relativeFilePath: paths.relativeFilePath,
|
|
15013
|
-
fileContent: (
|
|
15143
|
+
fileContent: applySharedConfigPatch({
|
|
15144
|
+
fileKey: TAKT_CONFIG_SHARED_FILE_KEY,
|
|
15145
|
+
feature: "mcp",
|
|
15146
|
+
existingContent,
|
|
15147
|
+
patch: { [TAKT_WORKFLOW_MCP_SERVERS_KEY]: allowlist },
|
|
15148
|
+
filePath
|
|
15149
|
+
}),
|
|
15014
15150
|
validate,
|
|
15015
15151
|
global
|
|
15016
15152
|
});
|
|
@@ -15455,7 +15591,7 @@ const toolMcpFactories = /* @__PURE__ */ new Map([
|
|
|
15455
15591
|
["augmentcode", {
|
|
15456
15592
|
class: AugmentcodeMcp,
|
|
15457
15593
|
meta: {
|
|
15458
|
-
supportsProject:
|
|
15594
|
+
supportsProject: true,
|
|
15459
15595
|
supportsGlobal: true,
|
|
15460
15596
|
supportsEnabledTools: false,
|
|
15461
15597
|
supportsDisabledTools: false
|
|
@@ -16037,15 +16173,97 @@ const JuniePermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
|
16037
16173
|
defaultBehavior: zod_mini.z.optional(zod_mini.z.string())
|
|
16038
16174
|
});
|
|
16039
16175
|
/**
|
|
16176
|
+
* Tool-scoped override block for Takt. Takt's `config.yaml` carries two
|
|
16177
|
+
* permission surfaces the canonical coarse-mode mapping can't express:
|
|
16178
|
+
* `step_permission_overrides` — a per-workflow-step map (`<step>` →
|
|
16179
|
+
* `readonly`/`edit`/`full`) that lives inside the active provider profile
|
|
16180
|
+
* alongside `default_permission_mode` and layers on top of it at that step; and
|
|
16181
|
+
* `provider_options` — a top-level, per-provider table of sandbox/network knobs
|
|
16182
|
+
* orthogonal to the permission mode (e.g. `codex.network_access`,
|
|
16183
|
+
* `claude.sandbox.allow_unsandboxed_commands`, `opencode.allowed_tools`). Fields
|
|
16184
|
+
* placed here are merged into `config.yaml` and emitted only for Takt, while the
|
|
16185
|
+
* shared `permission` block continues to drive `default_permission_mode`. Kept
|
|
16186
|
+
* `looseObject` (verbatim passthrough); Takt validates its own value sets (e.g.
|
|
16187
|
+
* `provider_options.<p>.base_url` must be loopback). Both project and global
|
|
16188
|
+
* scope are supported.
|
|
16189
|
+
*
|
|
16190
|
+
* Note: Takt's config loader hard-rejects unknown top-level keys, so only keys
|
|
16191
|
+
* Takt actually recognizes belong here. `required_permission_mode` is NOT one —
|
|
16192
|
+
* it is a per-step field of the workflow YAML (not `config.yaml`), so it is out
|
|
16193
|
+
* of scope for this override.
|
|
16194
|
+
*
|
|
16195
|
+
* @example
|
|
16196
|
+
* { "step_permission_overrides": { "ai_review": "readonly" }, "provider_options": { "codex": { "network_access": true } } }
|
|
16197
|
+
*/
|
|
16198
|
+
const TaktPermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
16199
|
+
step_permission_overrides: zod_mini.z.optional(zod_mini.z.record(zod_mini.z.string(), zod_mini.z.string())),
|
|
16200
|
+
provider_options: zod_mini.z.optional(zod_mini.z.looseObject({}))
|
|
16201
|
+
});
|
|
16202
|
+
/**
|
|
16203
|
+
* Tool-scoped override block for Amp. Amp's `amp.permissions` array and sibling
|
|
16204
|
+
* settings carry shapes the canonical per-command allow/ask/deny model can't
|
|
16205
|
+
* express, so they are authored here and merged into the shared Amp settings
|
|
16206
|
+
* file, while the shared `permission` block continues to drive the canonical
|
|
16207
|
+
* `amp.permissions` (allow/ask/reject) + `amp.tools.disable` entries:
|
|
16208
|
+
* - `permissions` — extra `amp.permissions` entries with non-`cmd` matchers
|
|
16209
|
+
* (`path`/`url`/`query`/…), regex/array match values, `context`
|
|
16210
|
+
* (`thread`/`subagent`), `delegate` (+`to`), or `reject` (+`message`). These
|
|
16211
|
+
* are appended AFTER the canonical-generated entries (Amp is first-match-wins,
|
|
16212
|
+
* so generated allow/ask/reject rules take precedence; authored entries act as
|
|
16213
|
+
* later fallbacks), preserving author order.
|
|
16214
|
+
* - `mcpPermissions` — Amp's `amp.mcpPermissions` array (`{ matches, action }`).
|
|
16215
|
+
* - `guardedFiles` — `amp.guardedFiles.allowlist` (globs allowed without
|
|
16216
|
+
* confirmation).
|
|
16217
|
+
* - `dangerouslyAllowAll` — `amp.dangerouslyAllowAll` (disable all confirmation).
|
|
16218
|
+
* Kept `looseObject` (verbatim passthrough). Both project and global scope are
|
|
16219
|
+
* supported.
|
|
16220
|
+
*
|
|
16221
|
+
* @example
|
|
16222
|
+
* { "dangerouslyAllowAll": false, "guardedFiles": { "allowlist": ["docs/**"] },
|
|
16223
|
+
* "permissions": [{ "tool": "Bash", "action": "delegate", "to": "approve.sh" }] }
|
|
16224
|
+
*/
|
|
16225
|
+
const AmpPermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
16226
|
+
permissions: zod_mini.z.optional(zod_mini.z.array(zod_mini.z.looseObject({
|
|
16227
|
+
tool: zod_mini.z.string(),
|
|
16228
|
+
action: zod_mini.z.string()
|
|
16229
|
+
}))),
|
|
16230
|
+
mcpPermissions: zod_mini.z.optional(zod_mini.z.array(zod_mini.z.looseObject({}))),
|
|
16231
|
+
guardedFiles: zod_mini.z.optional(zod_mini.z.looseObject({ allowlist: zod_mini.z.optional(zod_mini.z.array(zod_mini.z.string())) })),
|
|
16232
|
+
dangerouslyAllowAll: zod_mini.z.optional(zod_mini.z.boolean())
|
|
16233
|
+
});
|
|
16234
|
+
/**
|
|
16235
|
+
* Tool-scoped override block for the Google Antigravity CLI. Antigravity's CLI
|
|
16236
|
+
* `settings.json` carries two global autonomy/sandbox knobs outside the
|
|
16237
|
+
* `permissions.allow/ask/deny` arrays rulesync manages: `toolPermission` (the
|
|
16238
|
+
* global autonomy preset — `request-review` (default) / `proceed-in-sandbox` /
|
|
16239
|
+
* `always-proceed` / `strict`) and `enableTerminalSandbox` (a boolean confining
|
|
16240
|
+
* agent-run commands to OS containment). Antigravity applies the allow/deny
|
|
16241
|
+
* lists as per-rule exceptions to the preset at runtime, so rulesync only
|
|
16242
|
+
* authors these keys verbatim — no precedence modeling is needed on our side.
|
|
16243
|
+
* Fields placed here are merged onto the top level of
|
|
16244
|
+
* `~/.gemini/antigravity-cli/settings.json` (global-only) and emitted only for
|
|
16245
|
+
* the CLI. The Antigravity IDE exposes the same concepts through a GUI (no
|
|
16246
|
+
* documented JSON schema), so this override does NOT apply to `antigravity-ide`.
|
|
16247
|
+
* Verified against https://antigravity.google/docs/cli/reference and
|
|
16248
|
+
* https://antigravity.google/docs/cli/sandbox.
|
|
16249
|
+
*
|
|
16250
|
+
* @example
|
|
16251
|
+
* { "toolPermission": "strict", "enableTerminalSandbox": true }
|
|
16252
|
+
*/
|
|
16253
|
+
const AntigravityCliPermissionsOverrideSchema = zod_mini.z.looseObject({
|
|
16254
|
+
toolPermission: zod_mini.z.optional(zod_mini.z.string()),
|
|
16255
|
+
enableTerminalSandbox: zod_mini.z.optional(zod_mini.z.boolean())
|
|
16256
|
+
});
|
|
16257
|
+
/**
|
|
16040
16258
|
* Permissions configuration.
|
|
16041
16259
|
* Keys are tool category names (e.g., "bash", "edit", "read", "webfetch").
|
|
16042
16260
|
* Values are pattern-to-action mappings for that tool category.
|
|
16043
16261
|
*
|
|
16044
16262
|
* The optional `opencode`/`hermes`/`cline`/`kilo`/`claudecode`/`vibe`/`cursor`/
|
|
16045
|
-
* `qwencode`/`reasonix`/`factorydroid`/`warp`/`junie
|
|
16046
|
-
* overrides consumed only by their
|
|
16047
|
-
* `*PermissionsOverrideSchema`); every
|
|
16048
|
-
* block and ignores them.
|
|
16263
|
+
* `qwencode`/`reasonix`/`factorydroid`/`warp`/`junie`/`takt`/`amp`/
|
|
16264
|
+
* `antigravity-cli` keys are tool-scoped overrides consumed only by their
|
|
16265
|
+
* respective translator (see the matching `*PermissionsOverrideSchema`); every
|
|
16266
|
+
* other tool reads the shared `permission` block and ignores them.
|
|
16049
16267
|
*
|
|
16050
16268
|
* @example
|
|
16051
16269
|
* {
|
|
@@ -16066,7 +16284,10 @@ const PermissionsConfigSchema = zod_mini.z.looseObject({
|
|
|
16066
16284
|
reasonix: zod_mini.z.optional(ReasonixPermissionsOverrideSchema),
|
|
16067
16285
|
factorydroid: zod_mini.z.optional(FactorydroidPermissionsOverrideSchema),
|
|
16068
16286
|
warp: zod_mini.z.optional(WarpPermissionsOverrideSchema),
|
|
16069
|
-
junie: zod_mini.z.optional(JuniePermissionsOverrideSchema)
|
|
16287
|
+
junie: zod_mini.z.optional(JuniePermissionsOverrideSchema),
|
|
16288
|
+
takt: zod_mini.z.optional(TaktPermissionsOverrideSchema),
|
|
16289
|
+
amp: zod_mini.z.optional(AmpPermissionsOverrideSchema),
|
|
16290
|
+
"antigravity-cli": zod_mini.z.optional(AntigravityCliPermissionsOverrideSchema)
|
|
16070
16291
|
});
|
|
16071
16292
|
/**
|
|
16072
16293
|
* Full permissions file schema including optional $schema field.
|
|
@@ -16178,6 +16399,39 @@ const AMP_TOOLS_DISABLE_KEY = "amp.tools.disable";
|
|
|
16178
16399
|
* Reference: https://ampcode.com/manual ("amp.permissions").
|
|
16179
16400
|
*/
|
|
16180
16401
|
const AMP_PERMISSIONS_KEY = "amp.permissions";
|
|
16402
|
+
/**
|
|
16403
|
+
* The `amp.guardedFiles.allowlist` array (file globs allowed without
|
|
16404
|
+
* confirmation), `amp.dangerouslyAllowAll` boolean (disable all confirmation),
|
|
16405
|
+
* and `amp.mcpPermissions` array — sibling settings authored through the `amp`
|
|
16406
|
+
* permissions override. Reference: https://ampcode.com/manual.
|
|
16407
|
+
*/
|
|
16408
|
+
const AMP_GUARDED_FILES_ALLOWLIST_KEY = "amp.guardedFiles.allowlist";
|
|
16409
|
+
const AMP_DANGEROUSLY_ALLOW_ALL_KEY = "amp.dangerouslyAllowAll";
|
|
16410
|
+
const AMP_MCP_PERMISSIONS_KEY = "amp.mcpPermissions";
|
|
16411
|
+
/**
|
|
16412
|
+
* The read-only `cmd` string of an entry's `matches`, or `undefined` when the
|
|
16413
|
+
* matcher is absent or uses a non-`cmd` key / non-string value.
|
|
16414
|
+
*/
|
|
16415
|
+
function ampMatchesCmd(entry) {
|
|
16416
|
+
const cmd = entry.matches?.cmd;
|
|
16417
|
+
return typeof cmd === "string" ? cmd : void 0;
|
|
16418
|
+
}
|
|
16419
|
+
/**
|
|
16420
|
+
* Whether an `amp.permissions` entry is fully expressible in the canonical
|
|
16421
|
+
* per-command allow/ask/deny model: a plain `allow`/`ask`/`reject` action with
|
|
16422
|
+
* no `context`/`message`/`to` and a matcher that is either absent or exactly a
|
|
16423
|
+
* single string `cmd`. Everything else (non-`cmd` matchers, regex/array match
|
|
16424
|
+
* values, `delegate`, `reject`+`message`, `context`) is routed to the `amp`
|
|
16425
|
+
* override verbatim instead of being flattened with loss or dropped.
|
|
16426
|
+
*/
|
|
16427
|
+
function isCanonicalAmpEntry(entry) {
|
|
16428
|
+
if (entry.action === "delegate") return false;
|
|
16429
|
+
if (entry.context !== void 0 || entry.message !== void 0 || entry.to !== void 0) return false;
|
|
16430
|
+
const matches = entry.matches;
|
|
16431
|
+
if (matches === void 0) return true;
|
|
16432
|
+
const keys = Object.keys(matches);
|
|
16433
|
+
return keys.length === 0 || keys.length === 1 && typeof matches.cmd === "string";
|
|
16434
|
+
}
|
|
16181
16435
|
function parseAmpSettings(fileContent) {
|
|
16182
16436
|
const errors = [];
|
|
16183
16437
|
const parsed = (0, jsonc_parser.parse)(fileContent || "{}", errors, { allowTrailingComma: true });
|
|
@@ -16193,10 +16447,20 @@ function toDisableList(value) {
|
|
|
16193
16447
|
return value.filter((entry) => typeof entry === "string");
|
|
16194
16448
|
}
|
|
16195
16449
|
/**
|
|
16450
|
+
* Read `amp.guardedFiles.allowlist` (an array of file glob strings) from parsed
|
|
16451
|
+
* settings, returning `undefined` when the key is absent or not an array so the
|
|
16452
|
+
* override omits it.
|
|
16453
|
+
*/
|
|
16454
|
+
function extractAmpGuardedAllowlist(value) {
|
|
16455
|
+
if (!Array.isArray(value)) return void 0;
|
|
16456
|
+
return value.filter((entry) => typeof entry === "string");
|
|
16457
|
+
}
|
|
16458
|
+
/**
|
|
16196
16459
|
* Read an `amp.permissions` array from untrusted parsed settings. Only entries
|
|
16197
|
-
* whose
|
|
16198
|
-
*
|
|
16199
|
-
*
|
|
16460
|
+
* whose `tool`/`action` rulesync understands are retained; every other key —
|
|
16461
|
+
* including the full `matches` object (so non-`cmd` matchers, regex/array
|
|
16462
|
+
* values, `context`, `to`, `message`) — is kept verbatim so it survives a
|
|
16463
|
+
* round-trip.
|
|
16200
16464
|
*/
|
|
16201
16465
|
function toPermissionsList(value) {
|
|
16202
16466
|
if (!Array.isArray(value)) return [];
|
|
@@ -16206,14 +16470,11 @@ function toPermissionsList(value) {
|
|
|
16206
16470
|
const { tool, action } = raw;
|
|
16207
16471
|
if (typeof tool !== "string" || typeof action !== "string") continue;
|
|
16208
16472
|
if (action !== "allow" && action !== "reject" && action !== "ask" && action !== "delegate") continue;
|
|
16209
|
-
const matches = raw.matches;
|
|
16210
|
-
let normalizedMatches;
|
|
16211
|
-
if (isPlainObject(matches) && typeof matches.cmd === "string") normalizedMatches = { cmd: matches.cmd };
|
|
16212
16473
|
entries.push({
|
|
16213
16474
|
...raw,
|
|
16214
16475
|
tool,
|
|
16215
16476
|
action,
|
|
16216
|
-
...
|
|
16477
|
+
...isPlainObject(raw.matches) ? { matches: raw.matches } : {}
|
|
16217
16478
|
});
|
|
16218
16479
|
}
|
|
16219
16480
|
return entries;
|
|
@@ -16238,6 +16499,13 @@ function toPermissionsList(value) {
|
|
|
16238
16499
|
* The settings file is shared with the MCP feature (`amp.mcpServers`), so reads
|
|
16239
16500
|
* and writes merge into the existing JSON rather than overwriting it, and the
|
|
16240
16501
|
* file is never deleted.
|
|
16502
|
+
*
|
|
16503
|
+
* Amp shapes with no canonical category are authored and round-tripped through
|
|
16504
|
+
* the `amp` permissions override (see `AmpPermissionsOverrideSchema`): extra
|
|
16505
|
+
* `amp.permissions` entries with non-`cmd` matchers / `context` / `delegate` /
|
|
16506
|
+
* `reject`+`message` (appended after the generated canonical entries), plus the
|
|
16507
|
+
* sibling `amp.mcpPermissions`, `amp.guardedFiles.allowlist`, and
|
|
16508
|
+
* `amp.dangerouslyAllowAll` settings.
|
|
16241
16509
|
*/
|
|
16242
16510
|
var AmpPermissions = class AmpPermissions extends ToolPermissions {
|
|
16243
16511
|
constructor(params) {
|
|
@@ -16307,15 +16575,25 @@ var AmpPermissions = class AmpPermissions extends ToolPermissions {
|
|
|
16307
16575
|
const jsonDir = (0, node_path.join)(outputRoot, basePaths.relativeDirPath);
|
|
16308
16576
|
const { fileContent, relativeFilePath } = await this.resolveSettingsFile(jsonDir);
|
|
16309
16577
|
const json = fileContent ? parseAmpSettings(fileContent) : {};
|
|
16310
|
-
const
|
|
16311
|
-
const
|
|
16578
|
+
const config = rulesyncPermissions.getJson();
|
|
16579
|
+
const { disable, permissions } = convertRulesyncToAmp(config);
|
|
16580
|
+
const override = config.amp;
|
|
16581
|
+
const authoredExtras = override?.permissions ? toPermissionsList(override.permissions) : [];
|
|
16582
|
+
const preservedDelegates = override?.permissions ? [] : toPermissionsList(json[AMP_PERMISSIONS_KEY]).filter((entry) => entry.action === "delegate");
|
|
16312
16583
|
const newJson = {
|
|
16313
16584
|
...json,
|
|
16314
16585
|
[AMP_TOOLS_DISABLE_KEY]: disable
|
|
16315
16586
|
};
|
|
16316
|
-
const mergedPermissions = [
|
|
16587
|
+
const mergedPermissions = mergeAmpPermissions([
|
|
16588
|
+
...permissions,
|
|
16589
|
+
...authoredExtras,
|
|
16590
|
+
...preservedDelegates
|
|
16591
|
+
]);
|
|
16317
16592
|
if (mergedPermissions.length > 0) newJson[AMP_PERMISSIONS_KEY] = mergedPermissions;
|
|
16318
16593
|
else delete newJson[AMP_PERMISSIONS_KEY];
|
|
16594
|
+
if (override?.guardedFiles?.allowlist !== void 0) newJson[AMP_GUARDED_FILES_ALLOWLIST_KEY] = override.guardedFiles.allowlist;
|
|
16595
|
+
if (override?.dangerouslyAllowAll !== void 0) newJson[AMP_DANGEROUSLY_ALLOW_ALL_KEY] = override.dangerouslyAllowAll;
|
|
16596
|
+
if (override?.mcpPermissions !== void 0) newJson[AMP_MCP_PERMISSIONS_KEY] = override.mcpPermissions;
|
|
16319
16597
|
return new AmpPermissions({
|
|
16320
16598
|
outputRoot,
|
|
16321
16599
|
relativeDirPath: basePaths.relativeDirPath,
|
|
@@ -16326,11 +16604,22 @@ var AmpPermissions = class AmpPermissions extends ToolPermissions {
|
|
|
16326
16604
|
}
|
|
16327
16605
|
toRulesyncPermissions() {
|
|
16328
16606
|
const json = parseAmpSettings(this.getFileContent());
|
|
16607
|
+
const allPermissions = toPermissionsList(json[AMP_PERMISSIONS_KEY]);
|
|
16608
|
+
const canonicalEntries = allPermissions.filter(isCanonicalAmpEntry);
|
|
16609
|
+
const overrideEntries = allPermissions.filter((entry) => !isCanonicalAmpEntry(entry));
|
|
16329
16610
|
const config = convertAmpToRulesync({
|
|
16330
16611
|
disable: toDisableList(json[AMP_TOOLS_DISABLE_KEY]),
|
|
16331
|
-
permissions:
|
|
16332
|
-
});
|
|
16333
|
-
|
|
16612
|
+
permissions: canonicalEntries
|
|
16613
|
+
});
|
|
16614
|
+
const ampOverride = {};
|
|
16615
|
+
if (overrideEntries.length > 0) ampOverride.permissions = overrideEntries;
|
|
16616
|
+
if (Array.isArray(json[AMP_MCP_PERMISSIONS_KEY])) ampOverride.mcpPermissions = json[AMP_MCP_PERMISSIONS_KEY];
|
|
16617
|
+
const allowlist = extractAmpGuardedAllowlist(json[AMP_GUARDED_FILES_ALLOWLIST_KEY]);
|
|
16618
|
+
if (allowlist !== void 0) ampOverride.guardedFiles = { allowlist };
|
|
16619
|
+
if (typeof json[AMP_DANGEROUSLY_ALLOW_ALL_KEY] === "boolean") ampOverride.dangerouslyAllowAll = json[AMP_DANGEROUSLY_ALLOW_ALL_KEY];
|
|
16620
|
+
const result = { ...config };
|
|
16621
|
+
if (Object.keys(ampOverride).length > 0) result.amp = ampOverride;
|
|
16622
|
+
return this.toRulesyncPermissionsDefault({ fileContent: JSON.stringify(result, null, 2) });
|
|
16334
16623
|
}
|
|
16335
16624
|
validate() {
|
|
16336
16625
|
try {
|
|
@@ -16377,6 +16666,37 @@ const ACTION_PRIORITY = {
|
|
|
16377
16666
|
allow: 2
|
|
16378
16667
|
};
|
|
16379
16668
|
/**
|
|
16669
|
+
* Fail-closed action priority for merging the full `amp.permissions` list
|
|
16670
|
+
* (generated + authored/preserved). `reject` leads so no `allow` can shadow it
|
|
16671
|
+
* under first-match-wins; `delegate` (which defers to an external approver, so
|
|
16672
|
+
* it never auto-allows) trails as the final fallback.
|
|
16673
|
+
*/
|
|
16674
|
+
const MERGE_ACTION_PRIORITY = {
|
|
16675
|
+
reject: 0,
|
|
16676
|
+
ask: 1,
|
|
16677
|
+
allow: 2,
|
|
16678
|
+
delegate: 3
|
|
16679
|
+
};
|
|
16680
|
+
/**
|
|
16681
|
+
* Stable fail-closed merge of generated and authored `amp.permissions` entries:
|
|
16682
|
+
* order by {@link MERGE_ACTION_PRIORITY} only, preserving each source's relative
|
|
16683
|
+
* order within an action class. Guarantees an authored `reject` cannot be
|
|
16684
|
+
* shadowed by a generated catch-all `allow`.
|
|
16685
|
+
*/
|
|
16686
|
+
function mergeAmpPermissions(entries) {
|
|
16687
|
+
const decorated = entries.map((entry, index) => ({
|
|
16688
|
+
entry,
|
|
16689
|
+
index
|
|
16690
|
+
}));
|
|
16691
|
+
decorated.sort((a, b) => {
|
|
16692
|
+
const ap = MERGE_ACTION_PRIORITY[a.entry.action] ?? MERGE_ACTION_PRIORITY.allow;
|
|
16693
|
+
const bp = MERGE_ACTION_PRIORITY[b.entry.action] ?? MERGE_ACTION_PRIORITY.allow;
|
|
16694
|
+
if (ap !== bp) return ap - bp;
|
|
16695
|
+
return a.index - b.index;
|
|
16696
|
+
});
|
|
16697
|
+
return decorated.map((d) => d.entry);
|
|
16698
|
+
}
|
|
16699
|
+
/**
|
|
16380
16700
|
* Convert a rulesync permissions config into Amp's two permission surfaces.
|
|
16381
16701
|
*
|
|
16382
16702
|
* For each `(category, pattern, action)` — where the category name IS the Amp
|
|
@@ -16441,14 +16761,14 @@ function sortAmpPermissions(entries) {
|
|
|
16441
16761
|
const ap = ACTION_PRIORITY[a.entry.action] ?? 0;
|
|
16442
16762
|
const bp = ACTION_PRIORITY[b.entry.action] ?? 0;
|
|
16443
16763
|
if (ap !== bp) return ap - bp;
|
|
16444
|
-
const aHasCmd = a.entry
|
|
16445
|
-
const bHasCmd = b.entry
|
|
16764
|
+
const aHasCmd = ampMatchesCmd(a.entry) !== void 0 ? 0 : 1;
|
|
16765
|
+
const bHasCmd = ampMatchesCmd(b.entry) !== void 0 ? 0 : 1;
|
|
16446
16766
|
if (aHasCmd !== bHasCmd) return aHasCmd - bHasCmd;
|
|
16447
16767
|
const at = a.entry.tool;
|
|
16448
16768
|
const bt = b.entry.tool;
|
|
16449
16769
|
if (at !== bt) return at < bt ? -1 : 1;
|
|
16450
|
-
const ac = a.entry
|
|
16451
|
-
const bc = b.entry
|
|
16770
|
+
const ac = ampMatchesCmd(a.entry) ?? "";
|
|
16771
|
+
const bc = ampMatchesCmd(b.entry) ?? "";
|
|
16452
16772
|
if (ac !== bc) return ac < bc ? -1 : 1;
|
|
16453
16773
|
return a.index - b.index;
|
|
16454
16774
|
});
|
|
@@ -16487,7 +16807,7 @@ function convertAmpToRulesync({ disable, permissions }) {
|
|
|
16487
16807
|
for (const tool of disable) assign(tool, "*", "deny");
|
|
16488
16808
|
for (const entry of permissions) {
|
|
16489
16809
|
if (entry.action === "delegate") continue;
|
|
16490
|
-
const pattern = entry
|
|
16810
|
+
const pattern = ampMatchesCmd(entry) ?? "*";
|
|
16491
16811
|
const action = entry.action === "reject" ? "deny" : entry.action === "ask" ? "ask" : "allow";
|
|
16492
16812
|
assign(entry.tool, pattern, action);
|
|
16493
16813
|
}
|
|
@@ -16569,6 +16889,11 @@ function buildPermissionEntry$1(toolName, pattern) {
|
|
|
16569
16889
|
* Permissions are written to the global `~/.gemini/antigravity-cli/settings.json`
|
|
16570
16890
|
* file (global scope only). The file holds other CLI settings besides
|
|
16571
16891
|
* permissions, so it is never deleted.
|
|
16892
|
+
*
|
|
16893
|
+
* Two CLI-only autonomy/sandbox knobs outside the allow/ask/deny arrays —
|
|
16894
|
+
* `toolPermission` (the global autonomy preset) and `enableTerminalSandbox` — are
|
|
16895
|
+
* authored and round-tripped through the `antigravity-cli` permissions override
|
|
16896
|
+
* (see `AntigravityCliPermissionsOverrideSchema`).
|
|
16572
16897
|
*/
|
|
16573
16898
|
var AntigravityCliPermissions = class AntigravityCliPermissions extends ToolPermissions {
|
|
16574
16899
|
constructor(params) {
|
|
@@ -16629,6 +16954,9 @@ var AntigravityCliPermissions = class AntigravityCliPermissions extends ToolPerm
|
|
|
16629
16954
|
...settings,
|
|
16630
16955
|
permissions: mergedPermissions
|
|
16631
16956
|
};
|
|
16957
|
+
const override = config["antigravity-cli"];
|
|
16958
|
+
if (override?.toolPermission !== void 0) merged.toolPermission = override.toolPermission;
|
|
16959
|
+
if (override?.enableTerminalSandbox !== void 0) merged.enableTerminalSandbox = override.enableTerminalSandbox;
|
|
16632
16960
|
const fileContent = JSON.stringify(merged, null, 2);
|
|
16633
16961
|
return new AntigravityCliPermissions({
|
|
16634
16962
|
outputRoot,
|
|
@@ -16652,7 +16980,12 @@ var AntigravityCliPermissions = class AntigravityCliPermissions extends ToolPerm
|
|
|
16652
16980
|
ask: permissions.ask ?? [],
|
|
16653
16981
|
deny: permissions.deny ?? []
|
|
16654
16982
|
});
|
|
16655
|
-
|
|
16983
|
+
const override = {};
|
|
16984
|
+
if (typeof settings.toolPermission === "string") override.toolPermission = settings.toolPermission;
|
|
16985
|
+
if (typeof settings.enableTerminalSandbox === "boolean") override.enableTerminalSandbox = settings.enableTerminalSandbox;
|
|
16986
|
+
const result = { ...config };
|
|
16987
|
+
if (Object.keys(override).length > 0) result["antigravity-cli"] = override;
|
|
16988
|
+
return this.toRulesyncPermissionsDefault({ fileContent: JSON.stringify(result, null, 2) });
|
|
16656
16989
|
}
|
|
16657
16990
|
validate() {
|
|
16658
16991
|
return {
|
|
@@ -19338,14 +19671,21 @@ var HermesagentPermissions = class HermesagentPermissions extends ToolPermission
|
|
|
19338
19671
|
return true;
|
|
19339
19672
|
}
|
|
19340
19673
|
setFileContent(fileContent) {
|
|
19341
|
-
|
|
19342
|
-
|
|
19343
|
-
|
|
19344
|
-
|
|
19345
|
-
|
|
19674
|
+
this.fileContent = applySharedConfigPatch({
|
|
19675
|
+
fileKey: HERMES_CONFIG_SHARED_FILE_KEY,
|
|
19676
|
+
feature: "permissions",
|
|
19677
|
+
existingContent: fileContent,
|
|
19678
|
+
patch: parseSharedConfig({
|
|
19679
|
+
format: "yaml",
|
|
19680
|
+
fileContent: this.fileContent
|
|
19681
|
+
})
|
|
19682
|
+
});
|
|
19346
19683
|
}
|
|
19347
19684
|
toRulesyncPermissions() {
|
|
19348
|
-
const config =
|
|
19685
|
+
const config = parseSharedConfig({
|
|
19686
|
+
format: "yaml",
|
|
19687
|
+
fileContent: this.getFileContent()
|
|
19688
|
+
});
|
|
19349
19689
|
const permissions = config.permissions && typeof config.permissions === "object" ? config.permissions.rulesync : {};
|
|
19350
19690
|
return new RulesyncPermissions({
|
|
19351
19691
|
relativeDirPath: "",
|
|
@@ -19366,11 +19706,17 @@ var HermesagentPermissions = class HermesagentPermissions extends ToolPermission
|
|
|
19366
19706
|
enabled: true,
|
|
19367
19707
|
domains: webfetchDeny
|
|
19368
19708
|
} };
|
|
19369
|
-
if (permissions.hermes && typeof permissions.hermes === "object") config =
|
|
19709
|
+
if (permissions.hermes && typeof permissions.hermes === "object") config = mergeSharedConfigDeep({
|
|
19710
|
+
base: config,
|
|
19711
|
+
patch: permissions.hermes
|
|
19712
|
+
});
|
|
19370
19713
|
config.permissions = { rulesync: permissions };
|
|
19371
19714
|
return new HermesagentPermissions({
|
|
19372
19715
|
outputRoot,
|
|
19373
|
-
fileContent:
|
|
19716
|
+
fileContent: stringifySharedConfig({
|
|
19717
|
+
format: "yaml",
|
|
19718
|
+
document: config
|
|
19719
|
+
})
|
|
19374
19720
|
});
|
|
19375
19721
|
}
|
|
19376
19722
|
};
|
|
@@ -20926,6 +21272,8 @@ function isPermissionAction(value) {
|
|
|
20926
21272
|
const TAKT_PROVIDER_KEY = "provider";
|
|
20927
21273
|
const TAKT_PROVIDER_PROFILES_KEY = "provider_profiles";
|
|
20928
21274
|
const TAKT_DEFAULT_PERMISSION_MODE_KEY = "default_permission_mode";
|
|
21275
|
+
const TAKT_STEP_PERMISSION_OVERRIDES_KEY = "step_permission_overrides";
|
|
21276
|
+
const TAKT_PROVIDER_OPTIONS_KEY = "provider_options";
|
|
20929
21277
|
const TAKT_DEFAULT_PROVIDER = "claude";
|
|
20930
21278
|
const CATCH_ALL_PATTERN = "*";
|
|
20931
21279
|
/**
|
|
@@ -20955,10 +21303,16 @@ const CATCH_ALL_PATTERN = "*";
|
|
|
20955
21303
|
* `bash: { "*": "deny" }`. These round-trip the generate mapping.
|
|
20956
21304
|
*
|
|
20957
21305
|
* Both project and global scope are supported. The shared config is merged in
|
|
20958
|
-
* place:
|
|
20959
|
-
*
|
|
20960
|
-
*
|
|
20961
|
-
*
|
|
21306
|
+
* place: `provider_profiles.<provider>.default_permission_mode` is set from the
|
|
21307
|
+
* derived mode; every other provider profile and all other top-level keys are
|
|
21308
|
+
* preserved. The file is never deleted.
|
|
21309
|
+
*
|
|
21310
|
+
* Two Takt-specific surfaces with no canonical category round-trip through the
|
|
21311
|
+
* `takt` override (see `TaktPermissionsOverrideSchema`):
|
|
21312
|
+
* `step_permission_overrides` (a per-step mode map inside the active provider
|
|
21313
|
+
* profile, layered on top of `default_permission_mode`) and `provider_options`
|
|
21314
|
+
* (a top-level per-provider sandbox/network table). Both are authored on
|
|
21315
|
+
* generate and re-extracted on import.
|
|
20962
21316
|
*/
|
|
20963
21317
|
var TaktPermissions = class TaktPermissions extends ToolPermissions {
|
|
20964
21318
|
constructor(params) {
|
|
@@ -20990,37 +21344,62 @@ var TaktPermissions = class TaktPermissions extends ToolPermissions {
|
|
|
20990
21344
|
}
|
|
20991
21345
|
static async fromRulesyncPermissions({ outputRoot = process.cwd(), rulesyncPermissions, global = false }) {
|
|
20992
21346
|
const paths = TaktPermissions.getSettablePaths({ global });
|
|
20993
|
-
const
|
|
21347
|
+
const filePath = (0, node_path.join)(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
21348
|
+
const existingContent = await readFileContentOrNull(filePath) ?? "";
|
|
21349
|
+
const config = parseSharedConfig({
|
|
21350
|
+
format: "yaml",
|
|
21351
|
+
fileContent: existingContent,
|
|
21352
|
+
filePath,
|
|
21353
|
+
invalidRootPolicy: "error"
|
|
21354
|
+
});
|
|
21355
|
+
const rulesyncJson = rulesyncPermissions.getJson();
|
|
20994
21356
|
const provider = resolveActiveProvider(config);
|
|
20995
|
-
const mode = deriveTaktPermissionMode(
|
|
20996
|
-
const
|
|
20997
|
-
const
|
|
20998
|
-
const
|
|
20999
|
-
|
|
21000
|
-
[TAKT_PROVIDER_PROFILES_KEY]: {
|
|
21001
|
-
|
|
21002
|
-
[
|
|
21003
|
-
|
|
21004
|
-
|
|
21005
|
-
}
|
|
21006
|
-
}
|
|
21357
|
+
const mode = deriveTaktPermissionMode(rulesyncJson);
|
|
21358
|
+
const override = isPlainObject(rulesyncJson.takt) ? rulesyncJson.takt : void 0;
|
|
21359
|
+
const stepOverrides = isPlainObject(override?.[TAKT_STEP_PERMISSION_OVERRIDES_KEY]) ? override[TAKT_STEP_PERMISSION_OVERRIDES_KEY] : void 0;
|
|
21360
|
+
const overrideProviderOptions = isPlainObject(override?.[TAKT_PROVIDER_OPTIONS_KEY]) ? override[TAKT_PROVIDER_OPTIONS_KEY] : void 0;
|
|
21361
|
+
const patch = {
|
|
21362
|
+
[TAKT_PROVIDER_PROFILES_KEY]: { [provider]: {
|
|
21363
|
+
[TAKT_DEFAULT_PERMISSION_MODE_KEY]: mode,
|
|
21364
|
+
...stepOverrides !== void 0 && { [TAKT_STEP_PERMISSION_OVERRIDES_KEY]: stepOverrides }
|
|
21365
|
+
} },
|
|
21366
|
+
...overrideProviderOptions !== void 0 && { [TAKT_PROVIDER_OPTIONS_KEY]: overrideProviderOptions }
|
|
21007
21367
|
};
|
|
21008
21368
|
return new TaktPermissions({
|
|
21009
21369
|
outputRoot,
|
|
21010
21370
|
relativeDirPath: paths.relativeDirPath,
|
|
21011
21371
|
relativeFilePath: paths.relativeFilePath,
|
|
21012
|
-
fileContent: (
|
|
21372
|
+
fileContent: applySharedConfigPatch({
|
|
21373
|
+
fileKey: TAKT_CONFIG_SHARED_FILE_KEY,
|
|
21374
|
+
feature: "permissions",
|
|
21375
|
+
existingContent,
|
|
21376
|
+
patch,
|
|
21377
|
+
filePath
|
|
21378
|
+
}),
|
|
21013
21379
|
validate: true,
|
|
21014
21380
|
global
|
|
21015
21381
|
});
|
|
21016
21382
|
}
|
|
21017
21383
|
toRulesyncPermissions() {
|
|
21018
|
-
const config =
|
|
21384
|
+
const config = parseSharedConfig({
|
|
21385
|
+
format: "yaml",
|
|
21386
|
+
fileContent: this.getFileContent(),
|
|
21387
|
+
filePath: (0, node_path.join)(this.getRelativeDirPath(), this.getRelativeFilePath()),
|
|
21388
|
+
invalidRootPolicy: "error"
|
|
21389
|
+
});
|
|
21019
21390
|
const provider = resolveActiveProvider(config);
|
|
21020
21391
|
const profiles = isPlainObject(config[TAKT_PROVIDER_PROFILES_KEY]) ? config[TAKT_PROVIDER_PROFILES_KEY] : {};
|
|
21021
|
-
const
|
|
21392
|
+
const profile = isPlainObject(profiles[provider]) ? profiles[provider] : {};
|
|
21393
|
+
const mode = profile[TAKT_DEFAULT_PERMISSION_MODE_KEY];
|
|
21022
21394
|
const rulesyncConfig = taktModeToRulesyncConfig(mode);
|
|
21023
|
-
|
|
21395
|
+
const stepOverrides = isPlainObject(profile[TAKT_STEP_PERMISSION_OVERRIDES_KEY]) ? profile[TAKT_STEP_PERMISSION_OVERRIDES_KEY] : void 0;
|
|
21396
|
+
const providerOptions = isPlainObject(config[TAKT_PROVIDER_OPTIONS_KEY]) ? config[TAKT_PROVIDER_OPTIONS_KEY] : void 0;
|
|
21397
|
+
const taktOverride = {};
|
|
21398
|
+
if (stepOverrides && Object.keys(stepOverrides).length > 0) taktOverride[TAKT_STEP_PERMISSION_OVERRIDES_KEY] = stepOverrides;
|
|
21399
|
+
if (providerOptions && Object.keys(providerOptions).length > 0) taktOverride[TAKT_PROVIDER_OPTIONS_KEY] = providerOptions;
|
|
21400
|
+
const result = { ...rulesyncConfig };
|
|
21401
|
+
if (Object.keys(taktOverride).length > 0) result.takt = taktOverride;
|
|
21402
|
+
return this.toRulesyncPermissionsDefault({ fileContent: JSON.stringify(result, null, 2) });
|
|
21024
21403
|
}
|
|
21025
21404
|
validate() {
|
|
21026
21405
|
return {
|
|
@@ -29915,14 +30294,21 @@ def register(ctx):
|
|
|
29915
30294
|
`;
|
|
29916
30295
|
}
|
|
29917
30296
|
function getEnabledPluginConfigContent(currentContent) {
|
|
29918
|
-
const config =
|
|
30297
|
+
const config = parseSharedConfig({
|
|
30298
|
+
format: "yaml",
|
|
30299
|
+
fileContent: currentContent
|
|
30300
|
+
});
|
|
29919
30301
|
const plugins = config.plugins && typeof config.plugins === "object" ? config.plugins : {};
|
|
29920
30302
|
const enabled = Array.isArray(plugins.enabled) ? plugins.enabled : [];
|
|
29921
|
-
|
|
29922
|
-
|
|
29923
|
-
|
|
29924
|
-
|
|
29925
|
-
|
|
30303
|
+
return applySharedConfigPatch({
|
|
30304
|
+
fileKey: HERMES_CONFIG_SHARED_FILE_KEY,
|
|
30305
|
+
feature: "subagents",
|
|
30306
|
+
existingContent: currentContent,
|
|
30307
|
+
patch: { plugins: {
|
|
30308
|
+
...plugins,
|
|
30309
|
+
enabled: Array.from(/* @__PURE__ */ new Set([...enabled, "rulesync-subagents"]))
|
|
30310
|
+
} }
|
|
30311
|
+
});
|
|
29926
30312
|
}
|
|
29927
30313
|
function getSubagentSpec(rulesyncSubagent) {
|
|
29928
30314
|
const json = rulesyncSubagent.getFrontmatter();
|
|
@@ -30008,6 +30394,17 @@ var HermesagentSubagent = class HermesagentSubagent extends ToolSubagent {
|
|
|
30008
30394
|
static getSettablePaths() {
|
|
30009
30395
|
return { relativeDirPath: HERMESAGENT_RULESYNC_SUBAGENTS_DIR_PATH };
|
|
30010
30396
|
}
|
|
30397
|
+
/**
|
|
30398
|
+
* Beyond the subagent spec files, generation also read-modify-writes the
|
|
30399
|
+
* shared `~/.hermes/config.yaml` (enabling the `rulesync-subagents` plugin),
|
|
30400
|
+
* so the write must be declared for the shared-file order derivation.
|
|
30401
|
+
*/
|
|
30402
|
+
static getExtraSharedWritePaths() {
|
|
30403
|
+
return [{
|
|
30404
|
+
relativeDirPath: HERMESAGENT_GLOBAL_DIR,
|
|
30405
|
+
relativeFilePath: (0, node_path.basename)(HERMESAGENT_CONFIG_FILE_PATH)
|
|
30406
|
+
}];
|
|
30407
|
+
}
|
|
30011
30408
|
static getSettablePathsForRulesyncSubagent(rulesyncSubagent) {
|
|
30012
30409
|
return [(0, node_path.join)(HERMESAGENT_RULESYNC_SUBAGENTS_DIR_PATH, `${subagentSlug(rulesyncSubagent.getRelativePathFromCwd())}.json`)];
|
|
30013
30410
|
}
|
|
@@ -31746,7 +32143,9 @@ const RulesyncRuleFrontmatterSchema = zod_mini.z.object({
|
|
|
31746
32143
|
})),
|
|
31747
32144
|
kiro: zod_mini.z.optional(zod_mini.z.looseObject({
|
|
31748
32145
|
inclusion: zod_mini.z.optional(zod_mini.z.string()),
|
|
31749
|
-
fileMatchPattern: zod_mini.z.optional(zod_mini.z.union([zod_mini.z.string(), zod_mini.z.array(zod_mini.z.string())]))
|
|
32146
|
+
fileMatchPattern: zod_mini.z.optional(zod_mini.z.union([zod_mini.z.string(), zod_mini.z.array(zod_mini.z.string())])),
|
|
32147
|
+
name: zod_mini.z.optional(zod_mini.z.string()),
|
|
32148
|
+
description: zod_mini.z.optional(zod_mini.z.string())
|
|
31750
32149
|
})),
|
|
31751
32150
|
takt: zod_mini.z.optional(zod_mini.z.looseObject({
|
|
31752
32151
|
name: zod_mini.z.optional(zod_mini.z.string()),
|
|
@@ -34662,7 +35061,8 @@ function toFileMatchPattern(globs) {
|
|
|
34662
35061
|
*
|
|
34663
35062
|
* Precedence:
|
|
34664
35063
|
* 1. An explicit `kiro.inclusion` block round-trips as-is (with `fileMatchPattern`
|
|
34665
|
-
* taken from the block, or derived from `globs` when omitted for `fileMatch
|
|
35064
|
+
* taken from the block, or derived from `globs` when omitted for `fileMatch`;
|
|
35065
|
+
* and with the companion `name`/`description` carried through for `auto`).
|
|
34666
35066
|
* 2. Otherwise specific (non-wildcard) globs map to `fileMatch`, scoping the rule
|
|
34667
35067
|
* to matching files instead of leaving it implicitly always-on.
|
|
34668
35068
|
* 3. Otherwise the rule stays `always` — represented by omitting the block so the
|
|
@@ -34680,6 +35080,11 @@ function deriveKiroInclusion({ kiro, globs }) {
|
|
|
34680
35080
|
fileMatchPattern
|
|
34681
35081
|
} : { inclusion: "fileMatch" };
|
|
34682
35082
|
}
|
|
35083
|
+
if (kiro.inclusion === "auto") return {
|
|
35084
|
+
inclusion: "auto",
|
|
35085
|
+
...kiro.name !== void 0 ? { name: kiro.name } : {},
|
|
35086
|
+
...kiro.description !== void 0 ? { description: kiro.description } : {}
|
|
35087
|
+
};
|
|
34683
35088
|
return { inclusion: kiro.inclusion };
|
|
34684
35089
|
}
|
|
34685
35090
|
const fileMatchPattern = toFileMatchPattern(specificGlobs);
|
|
@@ -34751,6 +35156,8 @@ var KiroRule = class KiroRule extends ToolRule {
|
|
|
34751
35156
|
const rawPattern = frontmatter.fileMatchPattern;
|
|
34752
35157
|
const fileMatchPattern = Array.isArray(rawPattern) ? rawPattern.filter((p) => typeof p === "string") : typeof rawPattern === "string" ? rawPattern : void 0;
|
|
34753
35158
|
const globs = inclusion === "fileMatch" ? fileMatchPattern === void 0 ? [] : Array.isArray(fileMatchPattern) ? fileMatchPattern : [fileMatchPattern] : [];
|
|
35159
|
+
const name = typeof frontmatter.name === "string" ? frontmatter.name : void 0;
|
|
35160
|
+
const description = typeof frontmatter.description === "string" ? frontmatter.description : void 0;
|
|
34754
35161
|
return new RulesyncRule({
|
|
34755
35162
|
outputRoot: process.cwd(),
|
|
34756
35163
|
relativeDirPath: RulesyncRule.getSettablePaths().recommended.relativeDirPath,
|
|
@@ -34761,7 +35168,9 @@ var KiroRule = class KiroRule extends ToolRule {
|
|
|
34761
35168
|
globs,
|
|
34762
35169
|
kiro: {
|
|
34763
35170
|
inclusion,
|
|
34764
|
-
...fileMatchPattern !== void 0 ? { fileMatchPattern } : {}
|
|
35171
|
+
...fileMatchPattern !== void 0 ? { fileMatchPattern } : {},
|
|
35172
|
+
...inclusion === "auto" && name !== void 0 ? { name } : {},
|
|
35173
|
+
...inclusion === "auto" && description !== void 0 ? { description } : {}
|
|
34765
35174
|
}
|
|
34766
35175
|
},
|
|
34767
35176
|
body
|
|
@@ -36935,6 +37344,197 @@ function buildPermissionsStrategy(ctx) {
|
|
|
36935
37344
|
};
|
|
36936
37345
|
}
|
|
36937
37346
|
//#endregion
|
|
37347
|
+
//#region src/types/processor-registry.ts
|
|
37348
|
+
const PROCESSOR_REGISTRY = [
|
|
37349
|
+
{
|
|
37350
|
+
feature: "rules",
|
|
37351
|
+
processor: RulesProcessor,
|
|
37352
|
+
schema: RulesProcessorToolTargetSchema,
|
|
37353
|
+
factory: toolRuleFactories
|
|
37354
|
+
},
|
|
37355
|
+
{
|
|
37356
|
+
feature: "ignore",
|
|
37357
|
+
processor: IgnoreProcessor,
|
|
37358
|
+
schema: IgnoreProcessorToolTargetSchema,
|
|
37359
|
+
factory: toolIgnoreFactories
|
|
37360
|
+
},
|
|
37361
|
+
{
|
|
37362
|
+
feature: "mcp",
|
|
37363
|
+
processor: McpProcessor,
|
|
37364
|
+
schema: McpProcessorToolTargetSchema,
|
|
37365
|
+
factory: toolMcpFactories
|
|
37366
|
+
},
|
|
37367
|
+
{
|
|
37368
|
+
feature: "commands",
|
|
37369
|
+
processor: CommandsProcessor,
|
|
37370
|
+
schema: CommandsProcessorToolTargetSchema,
|
|
37371
|
+
factory: toolCommandFactories
|
|
37372
|
+
},
|
|
37373
|
+
{
|
|
37374
|
+
feature: "subagents",
|
|
37375
|
+
processor: SubagentsProcessor,
|
|
37376
|
+
schema: SubagentsProcessorToolTargetSchema,
|
|
37377
|
+
factory: toolSubagentFactories
|
|
37378
|
+
},
|
|
37379
|
+
{
|
|
37380
|
+
feature: "skills",
|
|
37381
|
+
processor: SkillsProcessor,
|
|
37382
|
+
schema: SkillsProcessorToolTargetSchema,
|
|
37383
|
+
factory: toolSkillFactories
|
|
37384
|
+
},
|
|
37385
|
+
{
|
|
37386
|
+
feature: "hooks",
|
|
37387
|
+
processor: HooksProcessor,
|
|
37388
|
+
schema: HooksProcessorToolTargetSchema,
|
|
37389
|
+
factory: toolHooksFactories
|
|
37390
|
+
},
|
|
37391
|
+
{
|
|
37392
|
+
feature: "permissions",
|
|
37393
|
+
processor: PermissionsProcessor,
|
|
37394
|
+
schema: PermissionsProcessorToolTargetSchema,
|
|
37395
|
+
factory: toolPermissionsFactories
|
|
37396
|
+
}
|
|
37397
|
+
];
|
|
37398
|
+
const getProcessorRegistryEntry = (feature) => {
|
|
37399
|
+
const entry = PROCESSOR_REGISTRY.find((e) => e.feature === feature);
|
|
37400
|
+
if (!entry) throw new Error(`No processor registered for feature: ${feature}`);
|
|
37401
|
+
return entry;
|
|
37402
|
+
};
|
|
37403
|
+
//#endregion
|
|
37404
|
+
//#region src/lib/shared-file-derive.ts
|
|
37405
|
+
/**
|
|
37406
|
+
* The single declaration of the cross-feature write order for shared
|
|
37407
|
+
* (read-modify-write) config files: when two features write the same on-disk
|
|
37408
|
+
* file, the earlier one writes first and the later one merges on top, so the
|
|
37409
|
+
* later feature's conflict policy decides what survives (e.g. `permissions`
|
|
37410
|
+
* overriding `ignore`-derived `Read(...)` denies in `.claude/settings.json`).
|
|
37411
|
+
* The generation step graph's `dependsOn` edges are derived from this list
|
|
37412
|
+
* plus the registry's `getSettablePaths` declarations — adding a tool or a
|
|
37413
|
+
* shared path never requires touching the graph by hand.
|
|
37414
|
+
*/
|
|
37415
|
+
const SHARED_WRITE_FEATURE_ORDER = [
|
|
37416
|
+
"ignore",
|
|
37417
|
+
"subagents",
|
|
37418
|
+
"mcp",
|
|
37419
|
+
"hooks",
|
|
37420
|
+
"permissions",
|
|
37421
|
+
"rules"
|
|
37422
|
+
];
|
|
37423
|
+
const SHARED_WRITE_FEATURES = new Set(SHARED_WRITE_FEATURE_ORDER);
|
|
37424
|
+
const TARGETS_NOT_DERIVED = /* @__PURE__ */ new Set(["augmentcode-legacy", "claudecode-legacy"]);
|
|
37425
|
+
const sharedFileKey = (path) => {
|
|
37426
|
+
const dir = path.relativeDirPath.replace(/\\/g, "/").replace(/\/$/, "");
|
|
37427
|
+
const file = path.relativeFilePath.replace(/\\/g, "/");
|
|
37428
|
+
return dir === "" || dir === "." ? file : `${dir}/${file}`;
|
|
37429
|
+
};
|
|
37430
|
+
const settablePathsForScope = (cls, global) => {
|
|
37431
|
+
const paths = [];
|
|
37432
|
+
let settable;
|
|
37433
|
+
try {
|
|
37434
|
+
settable = cls.getSettablePaths?.({ global });
|
|
37435
|
+
} catch {
|
|
37436
|
+
return paths;
|
|
37437
|
+
}
|
|
37438
|
+
if (settable?.relativeFilePath) paths.push({
|
|
37439
|
+
relativeDirPath: settable.relativeDirPath ?? ".",
|
|
37440
|
+
relativeFilePath: settable.relativeFilePath
|
|
37441
|
+
});
|
|
37442
|
+
if (settable?.root) {
|
|
37443
|
+
paths.push(settable.root);
|
|
37444
|
+
for (const alt of settable.alternativeRoots ?? []) paths.push(alt);
|
|
37445
|
+
}
|
|
37446
|
+
for (const path of cls.getExtraSharedWritePaths?.({ global }) ?? []) if (path.relativeFilePath) paths.push(path);
|
|
37447
|
+
return paths;
|
|
37448
|
+
};
|
|
37449
|
+
const collectFactoryPaths = (factory) => [...settablePathsForScope(factory.class, false), ...settablePathsForScope(factory.class, true)];
|
|
37450
|
+
/**
|
|
37451
|
+
* Derive, from the processor registry, every on-disk file that two or more
|
|
37452
|
+
* features read-modify-write. Source of truth the generation step graph's
|
|
37453
|
+
* `writesSharedFile` declarations must match.
|
|
37454
|
+
*/
|
|
37455
|
+
const deriveSharedFileWriters = () => {
|
|
37456
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
37457
|
+
const pathByKey = /* @__PURE__ */ new Map();
|
|
37458
|
+
for (const entry of PROCESSOR_REGISTRY) {
|
|
37459
|
+
if (!SHARED_WRITE_FEATURES.has(entry.feature)) continue;
|
|
37460
|
+
const factories = entry.factory;
|
|
37461
|
+
for (const [tool, factory] of factories) {
|
|
37462
|
+
if (TARGETS_NOT_DERIVED.has(tool)) continue;
|
|
37463
|
+
for (const path of collectFactoryPaths(factory)) {
|
|
37464
|
+
const key = sharedFileKey(path);
|
|
37465
|
+
if (!pathByKey.has(key)) pathByKey.set(key, path);
|
|
37466
|
+
let features = byKey.get(key);
|
|
37467
|
+
if (!features) {
|
|
37468
|
+
features = /* @__PURE__ */ new Map();
|
|
37469
|
+
byKey.set(key, features);
|
|
37470
|
+
}
|
|
37471
|
+
let tools = features.get(entry.feature);
|
|
37472
|
+
if (!tools) {
|
|
37473
|
+
tools = /* @__PURE__ */ new Set();
|
|
37474
|
+
features.set(entry.feature, tools);
|
|
37475
|
+
}
|
|
37476
|
+
tools.add(tool);
|
|
37477
|
+
}
|
|
37478
|
+
}
|
|
37479
|
+
}
|
|
37480
|
+
const writers = [];
|
|
37481
|
+
for (const [key, features] of byKey) {
|
|
37482
|
+
if (features.size < 2) continue;
|
|
37483
|
+
const path = pathByKey.get(key);
|
|
37484
|
+
const toolsByFeature = /* @__PURE__ */ new Map();
|
|
37485
|
+
for (const [feature, tools] of features) toolsByFeature.set(feature, [...tools].toSorted());
|
|
37486
|
+
writers.push({
|
|
37487
|
+
key,
|
|
37488
|
+
relativeDirPath: path.relativeDirPath,
|
|
37489
|
+
relativeFilePath: path.relativeFilePath,
|
|
37490
|
+
features: [...features.keys()].toSorted(),
|
|
37491
|
+
toolsByFeature
|
|
37492
|
+
});
|
|
37493
|
+
}
|
|
37494
|
+
return writers.toSorted((a, b) => a.key.localeCompare(b.key));
|
|
37495
|
+
};
|
|
37496
|
+
/**
|
|
37497
|
+
* Derive, per shared-write feature, the shared files it writes and the
|
|
37498
|
+
* `dependsOn` edges that fix a safe write order: for every shared file, each
|
|
37499
|
+
* writer depends on all writers that precede it in
|
|
37500
|
+
* {@link SHARED_WRITE_FEATURE_ORDER}. This is the source the generation step
|
|
37501
|
+
* graph consumes, so registry changes (a new tool, a new settable path)
|
|
37502
|
+
* propagate into the execution order without a hand-maintained declaration.
|
|
37503
|
+
*
|
|
37504
|
+
* @throws Error if a feature writes a shared file but has no position in
|
|
37505
|
+
* `SHARED_WRITE_FEATURE_ORDER` — ordering it is a deliberate decision about
|
|
37506
|
+
* whose merge policy wins, so it must be made explicitly there.
|
|
37507
|
+
*/
|
|
37508
|
+
const deriveSharedWriteSteps = () => {
|
|
37509
|
+
const orderIndex = new Map(SHARED_WRITE_FEATURE_ORDER.map((feature, index) => [feature, index]));
|
|
37510
|
+
const filesByFeature = /* @__PURE__ */ new Map();
|
|
37511
|
+
const depsByFeature = /* @__PURE__ */ new Map();
|
|
37512
|
+
for (const writer of deriveSharedFileWriters()) {
|
|
37513
|
+
for (const feature of writer.features) if (!orderIndex.has(feature)) throw new Error(`Feature '${feature}' writes the shared file '${writer.key}' but has no position in SHARED_WRITE_FEATURE_ORDER. Decide where its writes merge relative to the other features and add it to the order.`);
|
|
37514
|
+
const ordered = [...writer.features].toSorted((a, b) => orderIndex.get(a) - orderIndex.get(b));
|
|
37515
|
+
for (const [position, feature] of ordered.entries()) {
|
|
37516
|
+
let files = filesByFeature.get(feature);
|
|
37517
|
+
if (!files) {
|
|
37518
|
+
files = /* @__PURE__ */ new Set();
|
|
37519
|
+
filesByFeature.set(feature, files);
|
|
37520
|
+
}
|
|
37521
|
+
files.add(writer.key);
|
|
37522
|
+
let deps = depsByFeature.get(feature);
|
|
37523
|
+
if (!deps) {
|
|
37524
|
+
deps = /* @__PURE__ */ new Set();
|
|
37525
|
+
depsByFeature.set(feature, deps);
|
|
37526
|
+
}
|
|
37527
|
+
for (const earlier of ordered.slice(0, position)) deps.add(earlier);
|
|
37528
|
+
}
|
|
37529
|
+
}
|
|
37530
|
+
const steps = /* @__PURE__ */ new Map();
|
|
37531
|
+
for (const [feature, files] of filesByFeature) steps.set(feature, {
|
|
37532
|
+
writesSharedFile: [...files].toSorted(),
|
|
37533
|
+
dependsOn: [...depsByFeature.get(feature) ?? []].toSorted((a, b) => orderIndex.get(a) - orderIndex.get(b))
|
|
37534
|
+
});
|
|
37535
|
+
return steps;
|
|
37536
|
+
};
|
|
37537
|
+
//#endregion
|
|
36938
37538
|
//#region src/lib/generate.ts
|
|
36939
37539
|
async function processFeatureGeneration(params) {
|
|
36940
37540
|
const { config, processor, toolFiles, skipFilePaths } = params;
|
|
@@ -37084,98 +37684,53 @@ function resolveExecutionOrder(steps) {
|
|
|
37084
37684
|
if (ordered.length !== steps.length) throw new Error("Generation steps contain a cyclic 'dependsOn' dependency.");
|
|
37085
37685
|
return ordered;
|
|
37086
37686
|
}
|
|
37687
|
+
const SHARED_WRITE_STEPS = deriveSharedWriteSteps();
|
|
37688
|
+
const sharedWriteMeta = (id) => {
|
|
37689
|
+
const step = SHARED_WRITE_STEPS.get(id);
|
|
37690
|
+
return step ? {
|
|
37691
|
+
writesSharedFile: step.writesSharedFile,
|
|
37692
|
+
dependsOn: step.dependsOn
|
|
37693
|
+
} : {};
|
|
37694
|
+
};
|
|
37087
37695
|
/**
|
|
37088
37696
|
* The static shape of the generation step graph: which steps write which shared
|
|
37089
37697
|
* (read-modify-write) config files, and the `dependsOn` edges that fix a safe order
|
|
37090
|
-
* for those writers.
|
|
37091
|
-
*
|
|
37092
|
-
*
|
|
37093
|
-
*
|
|
37094
|
-
*
|
|
37698
|
+
* for those writers. Both are derived from the processor registry's settable
|
|
37699
|
+
* paths and `SHARED_WRITE_FEATURE_ORDER` (see `shared-file-derive.ts`), so a new
|
|
37700
|
+
* tool or shared path never requires editing this graph. Exported (separately
|
|
37701
|
+
* from the `run` closures, which need a live `config`/`logger`) so
|
|
37702
|
+
* `resolveExecutionOrder`'s ordering guarantee can be tested directly against
|
|
37703
|
+
* the real graph rather than a hand-copied one. Readonly so a consumer can't
|
|
37704
|
+
* mutate this module-level singleton and affect every subsequent `generate()`
|
|
37705
|
+
* call in the process.
|
|
37095
37706
|
*/
|
|
37096
37707
|
const GENERATION_STEP_GRAPH = [
|
|
37097
37708
|
{
|
|
37098
37709
|
id: "ignore",
|
|
37099
|
-
|
|
37710
|
+
...sharedWriteMeta("ignore")
|
|
37100
37711
|
},
|
|
37101
37712
|
{
|
|
37102
37713
|
id: "mcp",
|
|
37103
|
-
|
|
37104
|
-
".amp/settings.json",
|
|
37105
|
-
".augment/settings.json",
|
|
37106
|
-
".codex/config.toml",
|
|
37107
|
-
".config/amp/settings.json",
|
|
37108
|
-
".config/devin/config.json",
|
|
37109
|
-
".config/opencode/opencode.json",
|
|
37110
|
-
".config/zed/settings.json",
|
|
37111
|
-
".devin/config.json",
|
|
37112
|
-
".grok/config.toml",
|
|
37113
|
-
".hermes/config.yaml",
|
|
37114
|
-
".qwen/settings.json",
|
|
37115
|
-
".reasonix/config.toml",
|
|
37116
|
-
".takt/config.yaml",
|
|
37117
|
-
".vibe/config.toml",
|
|
37118
|
-
".zed/settings.json",
|
|
37119
|
-
"kilo.json",
|
|
37120
|
-
"opencode.json",
|
|
37121
|
-
"reasonix.toml"
|
|
37122
|
-
],
|
|
37123
|
-
dependsOn: ["ignore"]
|
|
37714
|
+
...sharedWriteMeta("mcp")
|
|
37124
37715
|
},
|
|
37125
37716
|
{ id: "commands" },
|
|
37126
|
-
{
|
|
37717
|
+
{
|
|
37718
|
+
id: "subagents",
|
|
37719
|
+
...sharedWriteMeta("subagents")
|
|
37720
|
+
},
|
|
37127
37721
|
{ id: "skills" },
|
|
37128
37722
|
{
|
|
37129
37723
|
id: "hooks",
|
|
37130
|
-
|
|
37131
|
-
".augment/settings.json",
|
|
37132
|
-
".claude/settings.json",
|
|
37133
|
-
".codex/config.toml",
|
|
37134
|
-
".config/devin/config.json",
|
|
37135
|
-
".hermes/config.yaml",
|
|
37136
|
-
".kiro/agents/default.json",
|
|
37137
|
-
".qwen/settings.json",
|
|
37138
|
-
".vibe/config.toml"
|
|
37139
|
-
],
|
|
37140
|
-
dependsOn: ["ignore", "mcp"]
|
|
37724
|
+
...sharedWriteMeta("hooks")
|
|
37141
37725
|
},
|
|
37142
37726
|
{
|
|
37143
37727
|
id: "permissions",
|
|
37144
|
-
|
|
37145
|
-
".amp/settings.json",
|
|
37146
|
-
".augment/settings.json",
|
|
37147
|
-
".claude/settings.json",
|
|
37148
|
-
".codex/config.toml",
|
|
37149
|
-
".config/amp/settings.json",
|
|
37150
|
-
".config/devin/config.json",
|
|
37151
|
-
".config/opencode/opencode.json",
|
|
37152
|
-
".config/zed/settings.json",
|
|
37153
|
-
".devin/config.json",
|
|
37154
|
-
".grok/config.toml",
|
|
37155
|
-
".hermes/config.yaml",
|
|
37156
|
-
".kiro/agents/default.json",
|
|
37157
|
-
".qwen/settings.json",
|
|
37158
|
-
".reasonix/config.toml",
|
|
37159
|
-
".takt/config.yaml",
|
|
37160
|
-
".vibe/config.toml",
|
|
37161
|
-
".zed/settings.json",
|
|
37162
|
-
"opencode.json",
|
|
37163
|
-
"reasonix.toml"
|
|
37164
|
-
],
|
|
37165
|
-
dependsOn: [
|
|
37166
|
-
"ignore",
|
|
37167
|
-
"hooks",
|
|
37168
|
-
"mcp"
|
|
37169
|
-
]
|
|
37728
|
+
...sharedWriteMeta("permissions")
|
|
37170
37729
|
},
|
|
37171
37730
|
{
|
|
37172
37731
|
id: "rules",
|
|
37173
|
-
|
|
37174
|
-
dependsOn: [
|
|
37175
|
-
"mcp",
|
|
37176
|
-
"skills",
|
|
37177
|
-
"permissions"
|
|
37178
|
-
]
|
|
37732
|
+
...sharedWriteMeta("rules"),
|
|
37733
|
+
dependsOn: [...sharedWriteMeta("rules").dependsOn ?? [], "skills"]
|
|
37179
37734
|
}
|
|
37180
37735
|
];
|
|
37181
37736
|
/**
|
|
@@ -37933,12 +38488,6 @@ Object.defineProperty(exports, "CommandsProcessor", {
|
|
|
37933
38488
|
return CommandsProcessor;
|
|
37934
38489
|
}
|
|
37935
38490
|
});
|
|
37936
|
-
Object.defineProperty(exports, "CommandsProcessorToolTargetSchema", {
|
|
37937
|
-
enumerable: true,
|
|
37938
|
-
get: function() {
|
|
37939
|
-
return CommandsProcessorToolTargetSchema;
|
|
37940
|
-
}
|
|
37941
|
-
});
|
|
37942
38491
|
Object.defineProperty(exports, "ConfigResolver", {
|
|
37943
38492
|
enumerable: true,
|
|
37944
38493
|
get: function() {
|
|
@@ -37963,24 +38512,12 @@ Object.defineProperty(exports, "HooksProcessor", {
|
|
|
37963
38512
|
return HooksProcessor;
|
|
37964
38513
|
}
|
|
37965
38514
|
});
|
|
37966
|
-
Object.defineProperty(exports, "HooksProcessorToolTargetSchema", {
|
|
37967
|
-
enumerable: true,
|
|
37968
|
-
get: function() {
|
|
37969
|
-
return HooksProcessorToolTargetSchema;
|
|
37970
|
-
}
|
|
37971
|
-
});
|
|
37972
38515
|
Object.defineProperty(exports, "IgnoreProcessor", {
|
|
37973
38516
|
enumerable: true,
|
|
37974
38517
|
get: function() {
|
|
37975
38518
|
return IgnoreProcessor;
|
|
37976
38519
|
}
|
|
37977
38520
|
});
|
|
37978
|
-
Object.defineProperty(exports, "IgnoreProcessorToolTargetSchema", {
|
|
37979
|
-
enumerable: true,
|
|
37980
|
-
get: function() {
|
|
37981
|
-
return IgnoreProcessorToolTargetSchema;
|
|
37982
|
-
}
|
|
37983
|
-
});
|
|
37984
38521
|
Object.defineProperty(exports, "JsonLogger", {
|
|
37985
38522
|
enumerable: true,
|
|
37986
38523
|
get: function() {
|
|
@@ -37999,24 +38536,6 @@ Object.defineProperty(exports, "McpProcessor", {
|
|
|
37999
38536
|
return McpProcessor;
|
|
38000
38537
|
}
|
|
38001
38538
|
});
|
|
38002
|
-
Object.defineProperty(exports, "McpProcessorToolTargetSchema", {
|
|
38003
|
-
enumerable: true,
|
|
38004
|
-
get: function() {
|
|
38005
|
-
return McpProcessorToolTargetSchema;
|
|
38006
|
-
}
|
|
38007
|
-
});
|
|
38008
|
-
Object.defineProperty(exports, "PermissionsProcessor", {
|
|
38009
|
-
enumerable: true,
|
|
38010
|
-
get: function() {
|
|
38011
|
-
return PermissionsProcessor;
|
|
38012
|
-
}
|
|
38013
|
-
});
|
|
38014
|
-
Object.defineProperty(exports, "PermissionsProcessorToolTargetSchema", {
|
|
38015
|
-
enumerable: true,
|
|
38016
|
-
get: function() {
|
|
38017
|
-
return PermissionsProcessorToolTargetSchema;
|
|
38018
|
-
}
|
|
38019
|
-
});
|
|
38020
38539
|
Object.defineProperty(exports, "RULESYNC_AIIGNORE_FILE_NAME", {
|
|
38021
38540
|
enumerable: true,
|
|
38022
38541
|
get: function() {
|
|
@@ -38149,12 +38668,6 @@ Object.defineProperty(exports, "RulesProcessor", {
|
|
|
38149
38668
|
return RulesProcessor;
|
|
38150
38669
|
}
|
|
38151
38670
|
});
|
|
38152
|
-
Object.defineProperty(exports, "RulesProcessorToolTargetSchema", {
|
|
38153
|
-
enumerable: true,
|
|
38154
|
-
get: function() {
|
|
38155
|
-
return RulesProcessorToolTargetSchema;
|
|
38156
|
-
}
|
|
38157
|
-
});
|
|
38158
38671
|
Object.defineProperty(exports, "RulesyncCommand", {
|
|
38159
38672
|
enumerable: true,
|
|
38160
38673
|
get: function() {
|
|
@@ -38239,24 +38752,12 @@ Object.defineProperty(exports, "SkillsProcessor", {
|
|
|
38239
38752
|
return SkillsProcessor;
|
|
38240
38753
|
}
|
|
38241
38754
|
});
|
|
38242
|
-
Object.defineProperty(exports, "SkillsProcessorToolTargetSchema", {
|
|
38243
|
-
enumerable: true,
|
|
38244
|
-
get: function() {
|
|
38245
|
-
return SkillsProcessorToolTargetSchema;
|
|
38246
|
-
}
|
|
38247
|
-
});
|
|
38248
38755
|
Object.defineProperty(exports, "SubagentsProcessor", {
|
|
38249
38756
|
enumerable: true,
|
|
38250
38757
|
get: function() {
|
|
38251
38758
|
return SubagentsProcessor;
|
|
38252
38759
|
}
|
|
38253
38760
|
});
|
|
38254
|
-
Object.defineProperty(exports, "SubagentsProcessorToolTargetSchema", {
|
|
38255
|
-
enumerable: true,
|
|
38256
|
-
get: function() {
|
|
38257
|
-
return SubagentsProcessorToolTargetSchema;
|
|
38258
|
-
}
|
|
38259
|
-
});
|
|
38260
38761
|
Object.defineProperty(exports, "ToolTargetSchema", {
|
|
38261
38762
|
enumerable: true,
|
|
38262
38763
|
get: function() {
|
|
@@ -38353,6 +38854,12 @@ Object.defineProperty(exports, "getLocalSkillDirNames", {
|
|
|
38353
38854
|
return getLocalSkillDirNames;
|
|
38354
38855
|
}
|
|
38355
38856
|
});
|
|
38857
|
+
Object.defineProperty(exports, "getProcessorRegistryEntry", {
|
|
38858
|
+
enumerable: true,
|
|
38859
|
+
get: function() {
|
|
38860
|
+
return getProcessorRegistryEntry;
|
|
38861
|
+
}
|
|
38862
|
+
});
|
|
38356
38863
|
Object.defineProperty(exports, "importFromTool", {
|
|
38357
38864
|
enumerable: true,
|
|
38358
38865
|
get: function() {
|
|
@@ -38407,54 +38914,6 @@ Object.defineProperty(exports, "toPosixPath", {
|
|
|
38407
38914
|
return toPosixPath;
|
|
38408
38915
|
}
|
|
38409
38916
|
});
|
|
38410
|
-
Object.defineProperty(exports, "toolCommandFactories", {
|
|
38411
|
-
enumerable: true,
|
|
38412
|
-
get: function() {
|
|
38413
|
-
return toolCommandFactories;
|
|
38414
|
-
}
|
|
38415
|
-
});
|
|
38416
|
-
Object.defineProperty(exports, "toolHooksFactories", {
|
|
38417
|
-
enumerable: true,
|
|
38418
|
-
get: function() {
|
|
38419
|
-
return toolHooksFactories;
|
|
38420
|
-
}
|
|
38421
|
-
});
|
|
38422
|
-
Object.defineProperty(exports, "toolIgnoreFactories", {
|
|
38423
|
-
enumerable: true,
|
|
38424
|
-
get: function() {
|
|
38425
|
-
return toolIgnoreFactories;
|
|
38426
|
-
}
|
|
38427
|
-
});
|
|
38428
|
-
Object.defineProperty(exports, "toolMcpFactories", {
|
|
38429
|
-
enumerable: true,
|
|
38430
|
-
get: function() {
|
|
38431
|
-
return toolMcpFactories;
|
|
38432
|
-
}
|
|
38433
|
-
});
|
|
38434
|
-
Object.defineProperty(exports, "toolPermissionsFactories", {
|
|
38435
|
-
enumerable: true,
|
|
38436
|
-
get: function() {
|
|
38437
|
-
return toolPermissionsFactories;
|
|
38438
|
-
}
|
|
38439
|
-
});
|
|
38440
|
-
Object.defineProperty(exports, "toolRuleFactories", {
|
|
38441
|
-
enumerable: true,
|
|
38442
|
-
get: function() {
|
|
38443
|
-
return toolRuleFactories;
|
|
38444
|
-
}
|
|
38445
|
-
});
|
|
38446
|
-
Object.defineProperty(exports, "toolSkillFactories", {
|
|
38447
|
-
enumerable: true,
|
|
38448
|
-
get: function() {
|
|
38449
|
-
return toolSkillFactories;
|
|
38450
|
-
}
|
|
38451
|
-
});
|
|
38452
|
-
Object.defineProperty(exports, "toolSubagentFactories", {
|
|
38453
|
-
enumerable: true,
|
|
38454
|
-
get: function() {
|
|
38455
|
-
return toolSubagentFactories;
|
|
38456
|
-
}
|
|
38457
|
-
});
|
|
38458
38917
|
Object.defineProperty(exports, "writeFileContent", {
|
|
38459
38918
|
enumerable: true,
|
|
38460
38919
|
get: function() {
|