rulesync 43.6.1 → 43.6.2
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 +7 -10
- package/dist/cli/index.js +7 -10
- package/dist/cli/index.js.map +1 -1
- package/dist/{import-BzVkMPd5.cjs → import-8kSEsosv.cjs} +561 -311
- package/dist/{import-Safgeb1C.js → import-iLVVcze8.js} +557 -307
- package/dist/{import-Safgeb1C.js.map → import-iLVVcze8.js.map} +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -2269,6 +2269,190 @@ async function removeTempDirectory(tempDir) {
|
|
|
2269
2269
|
});
|
|
2270
2270
|
} catch {}
|
|
2271
2271
|
}
|
|
2272
|
+
// src/utils/prototype-pollution.ts
|
|
2273
|
+
/**
|
|
2274
|
+
* Keys that, if walked into when constructing or merging objects from
|
|
2275
|
+
* untrusted input, can mutate `Object.prototype` (or otherwise the prototype
|
|
2276
|
+
* chain) and propagate state to every other object in the runtime. Any code
|
|
2277
|
+
* that copies arbitrary user-supplied keys into a fresh object — frontmatter
|
|
2278
|
+
* parsing, MCP config conversion, settings round-trip — should skip these.
|
|
2279
|
+
*/
|
|
2280
|
+
const PROTOTYPE_POLLUTION_KEYS = /* @__PURE__ */ new Set([
|
|
2281
|
+
"__proto__",
|
|
2282
|
+
"constructor",
|
|
2283
|
+
"prototype"
|
|
2284
|
+
]);
|
|
2285
|
+
function isPrototypePollutionKey(key) {
|
|
2286
|
+
return PROTOTYPE_POLLUTION_KEYS.has(key);
|
|
2287
|
+
}
|
|
2288
|
+
/**
|
|
2289
|
+
* Returns a shallow copy of a record's own entries with every
|
|
2290
|
+
* prototype-pollution key (`__proto__`, `constructor`, `prototype`) dropped.
|
|
2291
|
+
*
|
|
2292
|
+
* Use when copying a nested, user-supplied string map — an MCP server's `env`
|
|
2293
|
+
* or `headers` table — into freshly generated config. Carrying such a map by
|
|
2294
|
+
* reference, or re-assigning its keys via bracket notation, would let a literal
|
|
2295
|
+
* `__proto__` key ride along (and re-assigning it would mutate the target's
|
|
2296
|
+
* prototype). Walking the entries through this helper severs that path while
|
|
2297
|
+
* preserving every legitimate key.
|
|
2298
|
+
*/
|
|
2299
|
+
function omitPrototypePollutionKeys(record) {
|
|
2300
|
+
const sanitized = {};
|
|
2301
|
+
for (const [key, value] of Object.entries(record)) {
|
|
2302
|
+
if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
|
|
2303
|
+
sanitized[key] = value;
|
|
2304
|
+
}
|
|
2305
|
+
return sanitized;
|
|
2306
|
+
}
|
|
2307
|
+
/**
|
|
2308
|
+
* Like {@link omitPrototypePollutionKeys}, but recursive: every plain object
|
|
2309
|
+
* reachable through the value (directly, or through an array) is copied with
|
|
2310
|
+
* its prototype-pollution keys dropped. Scalars and arrays of scalars come back
|
|
2311
|
+
* as they are.
|
|
2312
|
+
*
|
|
2313
|
+
* Use when passing an unknown, user-supplied value through unchanged — an MCP
|
|
2314
|
+
* server field a tool documents that rulesync does not model — so a
|
|
2315
|
+
* `__proto__` key nested anywhere inside it cannot ride into the generated
|
|
2316
|
+
* config, where the consuming tool may merge the object without the same care.
|
|
2317
|
+
*/
|
|
2318
|
+
function omitPrototypePollutionKeysDeep(value) {
|
|
2319
|
+
if (Array.isArray(value)) return value.map((entry) => omitPrototypePollutionKeysDeep(entry));
|
|
2320
|
+
if (value === null || typeof value !== "object") return value;
|
|
2321
|
+
const sanitized = {};
|
|
2322
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
2323
|
+
if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
|
|
2324
|
+
sanitized[key] = omitPrototypePollutionKeysDeep(entry);
|
|
2325
|
+
}
|
|
2326
|
+
return sanitized;
|
|
2327
|
+
}
|
|
2328
|
+
// src/utils/jsonc.ts
|
|
2329
|
+
/**
|
|
2330
|
+
* Rebuild the parsed value from its own enumerable entries, dropping
|
|
2331
|
+
* prototype-pollution keys (`__proto__`, `constructor`, `prototype`).
|
|
2332
|
+
* `jsonc-parser` assigns keys with plain `obj[key] = value` semantics, so a
|
|
2333
|
+
* literal `__proto__` key would replace the containing object's prototype
|
|
2334
|
+
* instead of becoming an own property; rebuilding gives every object a clean
|
|
2335
|
+
* `Object.prototype` again and severs that path.
|
|
2336
|
+
*/
|
|
2337
|
+
function deepSanitize(value) {
|
|
2338
|
+
if (Array.isArray(value)) return value.map((item) => deepSanitize(item));
|
|
2339
|
+
if (value !== null && typeof value === "object") {
|
|
2340
|
+
const sanitized = {};
|
|
2341
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
2342
|
+
if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
|
|
2343
|
+
sanitized[key] = deepSanitize(entry);
|
|
2344
|
+
}
|
|
2345
|
+
return sanitized;
|
|
2346
|
+
}
|
|
2347
|
+
return value;
|
|
2348
|
+
}
|
|
2349
|
+
/**
|
|
2350
|
+
* Collect the paths of every prototype-pollution key in the document, walking
|
|
2351
|
+
* the syntax tree rather than the parsed value.
|
|
2352
|
+
*
|
|
2353
|
+
* The parsed value cannot answer this question for `__proto__`:
|
|
2354
|
+
* `obj["__proto__"] = "deny"` is discarded by the engine outright, and
|
|
2355
|
+
* `obj["__proto__"] = {...}` replaces the prototype instead of adding an own
|
|
2356
|
+
* property — either way the key is already gone by the time
|
|
2357
|
+
* {@link deepSanitize} could look for it, and only the source text still knows
|
|
2358
|
+
* the user wrote it. `constructor` and `prototype` do become own properties and
|
|
2359
|
+
* could be found in the parsed value, but they are collected here too so all
|
|
2360
|
+
* three keys are answered the same way.
|
|
2361
|
+
*
|
|
2362
|
+
* A pollution key's subtree is not descended into, matching
|
|
2363
|
+
* {@link deepSanitize}, which drops the whole value along with the key.
|
|
2364
|
+
*/
|
|
2365
|
+
function collectPollutionKeyPaths({ node, path, found }) {
|
|
2366
|
+
if (node.type === "array") {
|
|
2367
|
+
for (const [index, child] of (node.children ?? []).entries()) collectPollutionKeyPaths({
|
|
2368
|
+
node: child,
|
|
2369
|
+
path: `${path}[${index}]`,
|
|
2370
|
+
found
|
|
2371
|
+
});
|
|
2372
|
+
return;
|
|
2373
|
+
}
|
|
2374
|
+
if (node.type !== "object") return;
|
|
2375
|
+
for (const property of node.children ?? []) {
|
|
2376
|
+
const [keyNode, valueNode] = property.children ?? [];
|
|
2377
|
+
if (typeof keyNode?.value !== "string") continue;
|
|
2378
|
+
const keyPath = path === "" ? keyNode.value : `${path}.${keyNode.value}`;
|
|
2379
|
+
if (PROTOTYPE_POLLUTION_KEYS.has(keyNode.value)) {
|
|
2380
|
+
found.push(keyPath);
|
|
2381
|
+
continue;
|
|
2382
|
+
}
|
|
2383
|
+
if (valueNode !== void 0) collectPollutionKeyPaths({
|
|
2384
|
+
node: valueNode,
|
|
2385
|
+
path: keyPath,
|
|
2386
|
+
found
|
|
2387
|
+
});
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
/**
|
|
2391
|
+
* Parse a JSONC (JSON with Comments) document strictly.
|
|
2392
|
+
*
|
|
2393
|
+
* Unlike `jsonc-parser`'s bare `parse` (which silently tolerates syntax
|
|
2394
|
+
* errors and returns a best-effort value), this throws on any parse error so
|
|
2395
|
+
* a malformed source file fails loudly instead of generating half-empty tool
|
|
2396
|
+
* configs. Plain JSON is valid JSONC, so this is a drop-in replacement for
|
|
2397
|
+
* `JSON.parse` on files that may contain comments or trailing commas.
|
|
2398
|
+
*/
|
|
2399
|
+
function parseJsonc(content) {
|
|
2400
|
+
return deepSanitize(parseStrict(content));
|
|
2401
|
+
}
|
|
2402
|
+
/**
|
|
2403
|
+
* The strict parse shared by both entry points. Kept separate from the syntax
|
|
2404
|
+
* tree walk so the many callers that never look at `droppedKeys` do not pay
|
|
2405
|
+
* for building a second representation of the document.
|
|
2406
|
+
*/
|
|
2407
|
+
function parseStrict(content) {
|
|
2408
|
+
const errors = [];
|
|
2409
|
+
const result = parse$1(content, errors, {
|
|
2410
|
+
allowTrailingComma: true,
|
|
2411
|
+
disallowComments: false
|
|
2412
|
+
});
|
|
2413
|
+
if (errors.length > 0) {
|
|
2414
|
+
const details = errors.map((e) => `${printParseErrorCode(e.error)} at offset ${e.offset}`).join(", ");
|
|
2415
|
+
throw new SyntaxError(`Failed to parse JSONC content: ${details}`);
|
|
2416
|
+
}
|
|
2417
|
+
return result;
|
|
2418
|
+
}
|
|
2419
|
+
/**
|
|
2420
|
+
* The error a source document should fail with when
|
|
2421
|
+
* {@link parseJsoncReportingDroppedKeys} reports keys the parser removed.
|
|
2422
|
+
*
|
|
2423
|
+
* Shared by every source that reports them, so the three files a user can
|
|
2424
|
+
* author explain the same removal the same way rather than each inventing its
|
|
2425
|
+
* own wording.
|
|
2426
|
+
*/
|
|
2427
|
+
function droppedPollutionKeysError({ sourcePath, droppedKeys }) {
|
|
2428
|
+
return /* @__PURE__ */ new Error(`${JSON.stringify(sourcePath)} uses ${droppedKeys.map((key) => JSON.stringify(key)).join(", ")} as ${droppedKeys.length === 1 ? "a key" : "keys"}. Rulesync removes __proto__, constructor and prototype from every source document it parses, because assigning them would reach the prototype chain instead of the object. They are therefore never written to any tool's config — rename them rather than leaving entries that silently do nothing.`);
|
|
2429
|
+
}
|
|
2430
|
+
/**
|
|
2431
|
+
* The same parse as {@link parseJsonc}, additionally reporting which
|
|
2432
|
+
* prototype-pollution keys were removed, as dotted paths
|
|
2433
|
+
* (`permission.bash.__proto__`).
|
|
2434
|
+
*
|
|
2435
|
+
* The parse itself is identical — the paths only let a caller tell the user
|
|
2436
|
+
* about entries that vanished, which they would otherwise have to notice by
|
|
2437
|
+
* comparing their source file against the generated output.
|
|
2438
|
+
*/
|
|
2439
|
+
function parseJsoncReportingDroppedKeys({ content }) {
|
|
2440
|
+
const result = parseStrict(content);
|
|
2441
|
+
const found = [];
|
|
2442
|
+
const tree = parseTree(content, [], {
|
|
2443
|
+
allowTrailingComma: true,
|
|
2444
|
+
disallowComments: false
|
|
2445
|
+
});
|
|
2446
|
+
if (tree !== void 0) collectPollutionKeyPaths({
|
|
2447
|
+
node: tree,
|
|
2448
|
+
path: "",
|
|
2449
|
+
found
|
|
2450
|
+
});
|
|
2451
|
+
return {
|
|
2452
|
+
value: deepSanitize(result),
|
|
2453
|
+
droppedKeys: [...new Set(found)]
|
|
2454
|
+
};
|
|
2455
|
+
}
|
|
2272
2456
|
// src/types/json-output.ts
|
|
2273
2457
|
/**
|
|
2274
2458
|
* Error codes for CLI errors
|
|
@@ -3558,10 +3742,37 @@ const getDefaults = () => ({
|
|
|
3558
3742
|
inputRoots: void 0,
|
|
3559
3743
|
sources: []
|
|
3560
3744
|
});
|
|
3745
|
+
/**
|
|
3746
|
+
* Parse the content of a config file (`rulesync.jsonc` / `rulesync.local.jsonc`)
|
|
3747
|
+
* through the same strict, sanitizing JSONC parser as every other rulesync
|
|
3748
|
+
* source.
|
|
3749
|
+
*
|
|
3750
|
+
* `jsonc-parser`'s bare `parse` recovers from syntax errors without reporting
|
|
3751
|
+
* them, which let a typo (a missing comma, unquoted keys, trailing garbage)
|
|
3752
|
+
* silently drop keys and run rulesync with a different config than the user
|
|
3753
|
+
* wrote. Prototype-pollution keys are rejected rather than silently removed,
|
|
3754
|
+
* matching the hooks, MCP and permissions sources.
|
|
3755
|
+
*/
|
|
3756
|
+
function parseConfigFileContent({ content, filePath }) {
|
|
3757
|
+
let result;
|
|
3758
|
+
try {
|
|
3759
|
+
result = parseJsoncReportingDroppedKeys({ content });
|
|
3760
|
+
} catch (error) {
|
|
3761
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
3762
|
+
throw new Error(`Failed to parse ${JSON.stringify(filePath)}: ${detail}`, { cause: error });
|
|
3763
|
+
}
|
|
3764
|
+
if (result.droppedKeys.length > 0) throw droppedPollutionKeysError({
|
|
3765
|
+
sourcePath: filePath,
|
|
3766
|
+
droppedKeys: result.droppedKeys
|
|
3767
|
+
});
|
|
3768
|
+
return result.value;
|
|
3769
|
+
}
|
|
3561
3770
|
const loadConfigFromFile = async (filePath) => {
|
|
3562
3771
|
if (!await fileExists(filePath)) return {};
|
|
3563
|
-
const
|
|
3564
|
-
|
|
3772
|
+
const jsonData = parseConfigFileContent({
|
|
3773
|
+
content: await readFileContent(filePath),
|
|
3774
|
+
filePath
|
|
3775
|
+
});
|
|
3565
3776
|
const { $schema: _schema, ...configParams } = ConfigFileSchema.parse(jsonData);
|
|
3566
3777
|
assertTargetsFeaturesExclusive({
|
|
3567
3778
|
targets: configParams.targets,
|
|
@@ -4174,62 +4385,6 @@ function createBoundedWalk({ subject, limits, root }) {
|
|
|
4174
4385
|
leave
|
|
4175
4386
|
};
|
|
4176
4387
|
}
|
|
4177
|
-
// src/utils/prototype-pollution.ts
|
|
4178
|
-
/**
|
|
4179
|
-
* Keys that, if walked into when constructing or merging objects from
|
|
4180
|
-
* untrusted input, can mutate `Object.prototype` (or otherwise the prototype
|
|
4181
|
-
* chain) and propagate state to every other object in the runtime. Any code
|
|
4182
|
-
* that copies arbitrary user-supplied keys into a fresh object — frontmatter
|
|
4183
|
-
* parsing, MCP config conversion, settings round-trip — should skip these.
|
|
4184
|
-
*/
|
|
4185
|
-
const PROTOTYPE_POLLUTION_KEYS = /* @__PURE__ */ new Set([
|
|
4186
|
-
"__proto__",
|
|
4187
|
-
"constructor",
|
|
4188
|
-
"prototype"
|
|
4189
|
-
]);
|
|
4190
|
-
function isPrototypePollutionKey(key) {
|
|
4191
|
-
return PROTOTYPE_POLLUTION_KEYS.has(key);
|
|
4192
|
-
}
|
|
4193
|
-
/**
|
|
4194
|
-
* Returns a shallow copy of a record's own entries with every
|
|
4195
|
-
* prototype-pollution key (`__proto__`, `constructor`, `prototype`) dropped.
|
|
4196
|
-
*
|
|
4197
|
-
* Use when copying a nested, user-supplied string map — an MCP server's `env`
|
|
4198
|
-
* or `headers` table — into freshly generated config. Carrying such a map by
|
|
4199
|
-
* reference, or re-assigning its keys via bracket notation, would let a literal
|
|
4200
|
-
* `__proto__` key ride along (and re-assigning it would mutate the target's
|
|
4201
|
-
* prototype). Walking the entries through this helper severs that path while
|
|
4202
|
-
* preserving every legitimate key.
|
|
4203
|
-
*/
|
|
4204
|
-
function omitPrototypePollutionKeys(record) {
|
|
4205
|
-
const sanitized = {};
|
|
4206
|
-
for (const [key, value] of Object.entries(record)) {
|
|
4207
|
-
if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
|
|
4208
|
-
sanitized[key] = value;
|
|
4209
|
-
}
|
|
4210
|
-
return sanitized;
|
|
4211
|
-
}
|
|
4212
|
-
/**
|
|
4213
|
-
* Like {@link omitPrototypePollutionKeys}, but recursive: every plain object
|
|
4214
|
-
* reachable through the value (directly, or through an array) is copied with
|
|
4215
|
-
* its prototype-pollution keys dropped. Scalars and arrays of scalars come back
|
|
4216
|
-
* as they are.
|
|
4217
|
-
*
|
|
4218
|
-
* Use when passing an unknown, user-supplied value through unchanged — an MCP
|
|
4219
|
-
* server field a tool documents that rulesync does not model — so a
|
|
4220
|
-
* `__proto__` key nested anywhere inside it cannot ride into the generated
|
|
4221
|
-
* config, where the consuming tool may merge the object without the same care.
|
|
4222
|
-
*/
|
|
4223
|
-
function omitPrototypePollutionKeysDeep(value) {
|
|
4224
|
-
if (Array.isArray(value)) return value.map((entry) => omitPrototypePollutionKeysDeep(entry));
|
|
4225
|
-
if (value === null || typeof value !== "object") return value;
|
|
4226
|
-
const sanitized = {};
|
|
4227
|
-
for (const [key, entry] of Object.entries(value)) {
|
|
4228
|
-
if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
|
|
4229
|
-
sanitized[key] = omitPrototypePollutionKeysDeep(entry);
|
|
4230
|
-
}
|
|
4231
|
-
return sanitized;
|
|
4232
|
-
}
|
|
4233
4388
|
// src/utils/type-guards.ts
|
|
4234
4389
|
/**
|
|
4235
4390
|
* Type guard to check if a value is a plain object (Record<string, unknown>).
|
|
@@ -4857,6 +5012,24 @@ function lookupOwn({ record, key }) {
|
|
|
4857
5012
|
return Object.hasOwn(record, key) ? record[key] : void 0;
|
|
4858
5013
|
}
|
|
4859
5014
|
/**
|
|
5015
|
+
* Return the value a map holds under its own `key`, first storing `create()`
|
|
5016
|
+
* there when it has none. A bracket read would find an inherited member for a
|
|
5017
|
+
* key such as `toString`, so an importer bucketing rules by a user-supplied
|
|
5018
|
+
* name would write into an `Object.prototype` function instead of a fresh
|
|
5019
|
+
* bucket.
|
|
5020
|
+
*/
|
|
5021
|
+
function getOrCreateOwn({ record, key, create }) {
|
|
5022
|
+
if (Object.hasOwn(record, key)) return record[key];
|
|
5023
|
+
const created = create();
|
|
5024
|
+
Object.defineProperty(record, key, {
|
|
5025
|
+
value: created,
|
|
5026
|
+
writable: true,
|
|
5027
|
+
enumerable: true,
|
|
5028
|
+
configurable: true
|
|
5029
|
+
});
|
|
5030
|
+
return created;
|
|
5031
|
+
}
|
|
5032
|
+
/**
|
|
4860
5033
|
* Swap the keys and values of a name map, e.g. a canonical-to-tool map into
|
|
4861
5034
|
* the tool-to-canonical map an importer reads. When two keys share a value,
|
|
4862
5035
|
* the later key wins.
|
|
@@ -6391,14 +6564,16 @@ const CANONICAL_TO_GOOSE_EVENT_NAMES = {
|
|
|
6391
6564
|
* Hook events supported by Goose.
|
|
6392
6565
|
*
|
|
6393
6566
|
* Goose adopts the Open Plugins hooks spec: each plugin's `hooks/hooks.json`
|
|
6394
|
-
* maps PascalCase event names to matcher/handler arrays.
|
|
6395
|
-
*
|
|
6396
|
-
*
|
|
6397
|
-
*
|
|
6398
|
-
*
|
|
6399
|
-
*
|
|
6567
|
+
* maps PascalCase event names to matcher/handler arrays.
|
|
6568
|
+
*
|
|
6569
|
+
* Goose's `HookEvent` enum defines these 11 events plus `PreToolUseResult`
|
|
6570
|
+
* (added in v1.48.0), which has no canonical equivalent: it is authored under
|
|
6571
|
+
* the `goose.hooks` override block by its native name, emitted verbatim, and
|
|
6572
|
+
* imported back into that block. Notably the enum has NO
|
|
6573
|
+
* `SubagentStart`/`SubagentStop` arms — emitting them would write keys Goose
|
|
6574
|
+
* silently ignores, so `subagentStart`/`subagentStop` are intentionally
|
|
6400
6575
|
* excluded here and from `CANONICAL_TO_GOOSE_EVENT_NAMES`.
|
|
6401
|
-
* @see https://github.com/aaif-goose/goose/blob/v1.
|
|
6576
|
+
* @see https://github.com/aaif-goose/goose/blob/v1.48.0/crates/goose/src/hooks/mod.rs
|
|
6402
6577
|
* @see https://goose-docs.ai/docs/guides/context-engineering/hooks/
|
|
6403
6578
|
*/
|
|
6404
6579
|
const GOOSE_HOOK_EVENTS = eventsOf(CANONICAL_TO_GOOSE_EVENT_NAMES);
|
|
@@ -6876,134 +7051,6 @@ const GROKCLI_HOOK_EVENTS = eventsOf(CANONICAL_TO_GROKCLI_EVENT_NAMES);
|
|
|
6876
7051
|
* Map Grok CLI PascalCase event names to canonical camelCase.
|
|
6877
7052
|
*/
|
|
6878
7053
|
const GROKCLI_TO_CANONICAL_EVENT_NAMES = invertRecord(CANONICAL_TO_GROKCLI_EVENT_NAMES);
|
|
6879
|
-
// src/utils/jsonc.ts
|
|
6880
|
-
/**
|
|
6881
|
-
* Rebuild the parsed value from its own enumerable entries, dropping
|
|
6882
|
-
* prototype-pollution keys (`__proto__`, `constructor`, `prototype`).
|
|
6883
|
-
* `jsonc-parser` assigns keys with plain `obj[key] = value` semantics, so a
|
|
6884
|
-
* literal `__proto__` key would replace the containing object's prototype
|
|
6885
|
-
* instead of becoming an own property; rebuilding gives every object a clean
|
|
6886
|
-
* `Object.prototype` again and severs that path.
|
|
6887
|
-
*/
|
|
6888
|
-
function deepSanitize(value) {
|
|
6889
|
-
if (Array.isArray(value)) return value.map((item) => deepSanitize(item));
|
|
6890
|
-
if (value !== null && typeof value === "object") {
|
|
6891
|
-
const sanitized = {};
|
|
6892
|
-
for (const [key, entry] of Object.entries(value)) {
|
|
6893
|
-
if (PROTOTYPE_POLLUTION_KEYS.has(key)) continue;
|
|
6894
|
-
sanitized[key] = deepSanitize(entry);
|
|
6895
|
-
}
|
|
6896
|
-
return sanitized;
|
|
6897
|
-
}
|
|
6898
|
-
return value;
|
|
6899
|
-
}
|
|
6900
|
-
/**
|
|
6901
|
-
* Collect the paths of every prototype-pollution key in the document, walking
|
|
6902
|
-
* the syntax tree rather than the parsed value.
|
|
6903
|
-
*
|
|
6904
|
-
* The parsed value cannot answer this question for `__proto__`:
|
|
6905
|
-
* `obj["__proto__"] = "deny"` is discarded by the engine outright, and
|
|
6906
|
-
* `obj["__proto__"] = {...}` replaces the prototype instead of adding an own
|
|
6907
|
-
* property — either way the key is already gone by the time
|
|
6908
|
-
* {@link deepSanitize} could look for it, and only the source text still knows
|
|
6909
|
-
* the user wrote it. `constructor` and `prototype` do become own properties and
|
|
6910
|
-
* could be found in the parsed value, but they are collected here too so all
|
|
6911
|
-
* three keys are answered the same way.
|
|
6912
|
-
*
|
|
6913
|
-
* A pollution key's subtree is not descended into, matching
|
|
6914
|
-
* {@link deepSanitize}, which drops the whole value along with the key.
|
|
6915
|
-
*/
|
|
6916
|
-
function collectPollutionKeyPaths({ node, path, found }) {
|
|
6917
|
-
if (node.type === "array") {
|
|
6918
|
-
for (const [index, child] of (node.children ?? []).entries()) collectPollutionKeyPaths({
|
|
6919
|
-
node: child,
|
|
6920
|
-
path: `${path}[${index}]`,
|
|
6921
|
-
found
|
|
6922
|
-
});
|
|
6923
|
-
return;
|
|
6924
|
-
}
|
|
6925
|
-
if (node.type !== "object") return;
|
|
6926
|
-
for (const property of node.children ?? []) {
|
|
6927
|
-
const [keyNode, valueNode] = property.children ?? [];
|
|
6928
|
-
if (typeof keyNode?.value !== "string") continue;
|
|
6929
|
-
const keyPath = path === "" ? keyNode.value : `${path}.${keyNode.value}`;
|
|
6930
|
-
if (PROTOTYPE_POLLUTION_KEYS.has(keyNode.value)) {
|
|
6931
|
-
found.push(keyPath);
|
|
6932
|
-
continue;
|
|
6933
|
-
}
|
|
6934
|
-
if (valueNode !== void 0) collectPollutionKeyPaths({
|
|
6935
|
-
node: valueNode,
|
|
6936
|
-
path: keyPath,
|
|
6937
|
-
found
|
|
6938
|
-
});
|
|
6939
|
-
}
|
|
6940
|
-
}
|
|
6941
|
-
/**
|
|
6942
|
-
* Parse a JSONC (JSON with Comments) document strictly.
|
|
6943
|
-
*
|
|
6944
|
-
* Unlike `jsonc-parser`'s bare `parse` (which silently tolerates syntax
|
|
6945
|
-
* errors and returns a best-effort value), this throws on any parse error so
|
|
6946
|
-
* a malformed source file fails loudly instead of generating half-empty tool
|
|
6947
|
-
* configs. Plain JSON is valid JSONC, so this is a drop-in replacement for
|
|
6948
|
-
* `JSON.parse` on files that may contain comments or trailing commas.
|
|
6949
|
-
*/
|
|
6950
|
-
function parseJsonc(content) {
|
|
6951
|
-
return deepSanitize(parseStrict(content));
|
|
6952
|
-
}
|
|
6953
|
-
/**
|
|
6954
|
-
* The strict parse shared by both entry points. Kept separate from the syntax
|
|
6955
|
-
* tree walk so the many callers that never look at `droppedKeys` do not pay
|
|
6956
|
-
* for building a second representation of the document.
|
|
6957
|
-
*/
|
|
6958
|
-
function parseStrict(content) {
|
|
6959
|
-
const errors = [];
|
|
6960
|
-
const result = parse$1(content, errors, {
|
|
6961
|
-
allowTrailingComma: true,
|
|
6962
|
-
disallowComments: false
|
|
6963
|
-
});
|
|
6964
|
-
if (errors.length > 0) {
|
|
6965
|
-
const details = errors.map((e) => `${printParseErrorCode(e.error)} at offset ${e.offset}`).join(", ");
|
|
6966
|
-
throw new SyntaxError(`Failed to parse JSONC content: ${details}`);
|
|
6967
|
-
}
|
|
6968
|
-
return result;
|
|
6969
|
-
}
|
|
6970
|
-
/**
|
|
6971
|
-
* The error a source document should fail with when
|
|
6972
|
-
* {@link parseJsoncReportingDroppedKeys} reports keys the parser removed.
|
|
6973
|
-
*
|
|
6974
|
-
* Shared by every source that reports them, so the three files a user can
|
|
6975
|
-
* author explain the same removal the same way rather than each inventing its
|
|
6976
|
-
* own wording.
|
|
6977
|
-
*/
|
|
6978
|
-
function droppedPollutionKeysError({ sourcePath, droppedKeys }) {
|
|
6979
|
-
return /* @__PURE__ */ new Error(`${JSON.stringify(sourcePath)} uses ${droppedKeys.map((key) => JSON.stringify(key)).join(", ")} as ${droppedKeys.length === 1 ? "a key" : "keys"}. Rulesync removes __proto__, constructor and prototype from every source document it parses, because assigning them would reach the prototype chain instead of the object. They are therefore never written to any tool's config — rename them rather than leaving entries that silently do nothing.`);
|
|
6980
|
-
}
|
|
6981
|
-
/**
|
|
6982
|
-
* The same parse as {@link parseJsonc}, additionally reporting which
|
|
6983
|
-
* prototype-pollution keys were removed, as dotted paths
|
|
6984
|
-
* (`permission.bash.__proto__`).
|
|
6985
|
-
*
|
|
6986
|
-
* The parse itself is identical — the paths only let a caller tell the user
|
|
6987
|
-
* about entries that vanished, which they would otherwise have to notice by
|
|
6988
|
-
* comparing their source file against the generated output.
|
|
6989
|
-
*/
|
|
6990
|
-
function parseJsoncReportingDroppedKeys({ content }) {
|
|
6991
|
-
const result = parseStrict(content);
|
|
6992
|
-
const found = [];
|
|
6993
|
-
const tree = parseTree(content, [], {
|
|
6994
|
-
allowTrailingComma: true,
|
|
6995
|
-
disallowComments: false
|
|
6996
|
-
});
|
|
6997
|
-
if (tree !== void 0) collectPollutionKeyPaths({
|
|
6998
|
-
node: tree,
|
|
6999
|
-
path: "",
|
|
7000
|
-
found
|
|
7001
|
-
});
|
|
7002
|
-
return {
|
|
7003
|
-
value: deepSanitize(result),
|
|
7004
|
-
droppedKeys: [...new Set(found)]
|
|
7005
|
-
};
|
|
7006
|
-
}
|
|
7007
7054
|
// src/utils/rulesync-source-path.ts
|
|
7008
7055
|
/**
|
|
7009
7056
|
* No `.rulesync/` source file exists for a feature at any of its candidate
|
|
@@ -19558,9 +19605,6 @@ var KiloCommand = class extends FrontmatterMarkdownToolCommand {
|
|
|
19558
19605
|
static getFrontmatterSchema() {
|
|
19559
19606
|
return KiloCommandFrontmatterSchema;
|
|
19560
19607
|
}
|
|
19561
|
-
getRulesyncOutputRoot() {
|
|
19562
|
-
return process.cwd();
|
|
19563
|
-
}
|
|
19564
19608
|
/**
|
|
19565
19609
|
* Refuse to write a command Kilo reserves (see
|
|
19566
19610
|
* {@link KILO_RESERVED_COMMAND_NAMES}). The name Kilo loads is the file
|
|
@@ -20849,9 +20893,6 @@ var OpenCodeCommand = class extends FrontmatterMarkdownToolCommand {
|
|
|
20849
20893
|
...Object.keys(restFields).length > 0 && { [toolTarget]: restFields }
|
|
20850
20894
|
};
|
|
20851
20895
|
}
|
|
20852
|
-
getRulesyncOutputRoot() {
|
|
20853
|
-
return process.cwd();
|
|
20854
|
-
}
|
|
20855
20896
|
/**
|
|
20856
20897
|
* Imports commands defined inline in `opencode.json` / `opencode.jsonc` (and,
|
|
20857
20898
|
* at project scope, `.opencode/opencode.json(c)`, which OpenCode merges over
|
|
@@ -58608,12 +58649,11 @@ var GooseHooks = class GooseHooks extends ToolHooks {
|
|
|
58608
58649
|
});
|
|
58609
58650
|
}
|
|
58610
58651
|
toRulesyncHooks({ logger } = {}) {
|
|
58611
|
-
const parsed = this.parseFileContentOrThrow({
|
|
58612
|
-
displayName: "Goose",
|
|
58613
|
-
parse: (fileContent) => JSON.parse(fileContent)
|
|
58614
|
-
});
|
|
58615
58652
|
const hooks = toolHooksToCanonical({
|
|
58616
|
-
hooks:
|
|
58653
|
+
hooks: this.parseFileContentOrThrow({
|
|
58654
|
+
displayName: "Goose",
|
|
58655
|
+
parse: (fileContent) => JSON.parse(fileContent)
|
|
58656
|
+
}).hooks,
|
|
58617
58657
|
converterConfig: GOOSE_CONVERTER_CONFIG,
|
|
58618
58658
|
logger
|
|
58619
58659
|
});
|
|
@@ -61880,12 +61920,14 @@ var ReasonixHooks = class ReasonixHooks extends ToolHooks {
|
|
|
61880
61920
|
const paths = ReasonixHooks.getSettablePaths({ global });
|
|
61881
61921
|
const filePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
61882
61922
|
const existingContent = await readFileContentOrNull(filePath) ?? JSON.stringify({}, null, 2);
|
|
61883
|
-
let
|
|
61923
|
+
let parsed;
|
|
61884
61924
|
try {
|
|
61885
|
-
|
|
61925
|
+
parsed = JSON.parse(existingContent);
|
|
61886
61926
|
} catch (error) {
|
|
61887
61927
|
throw new Error(`Failed to parse existing Reasonix settings at ${filePath}: ${formatError(error)}`, { cause: error });
|
|
61888
61928
|
}
|
|
61929
|
+
if (!isPlainObject(parsed)) throw new Error(`Failed to parse existing Reasonix settings at ${filePath}: expected a mapping at the root`);
|
|
61930
|
+
const settings = parsed;
|
|
61889
61931
|
const config = rulesyncHooks.getJson();
|
|
61890
61932
|
const reasonixHooks = canonicalToReasonixHooks({
|
|
61891
61933
|
config,
|
|
@@ -62844,15 +62886,18 @@ function emittedEventsWithHook(params) {
|
|
|
62844
62886
|
}
|
|
62845
62887
|
/**
|
|
62846
62888
|
* The capabilities an adapter built on the shared hooks converter already
|
|
62847
|
-
* declares in its converter config: the events it emits
|
|
62848
|
-
* keeps
|
|
62849
|
-
*
|
|
62889
|
+
* declares in its converter config: the events it emits, the hook types it
|
|
62890
|
+
* keeps, and whether it writes the per-hook `enabled` flag. Reading them from
|
|
62891
|
+
* there keeps the processor's skip and dropped-field warnings in step with
|
|
62892
|
+
* what the converter actually writes.
|
|
62850
62893
|
*/
|
|
62851
62894
|
function converterCapabilities(config) {
|
|
62852
62895
|
if (!config.supportedHookTypes) throw new Error("Hooks converter config must declare its supportedHookTypes");
|
|
62896
|
+
const passesThroughEnabled = (config.booleanPassthroughFields ?? []).some((field) => field.canonical === "enabled");
|
|
62853
62897
|
return {
|
|
62854
62898
|
supportedEvents: config.supportedEvents,
|
|
62855
|
-
supportedHookTypes: [...config.supportedHookTypes]
|
|
62899
|
+
supportedHookTypes: [...config.supportedHookTypes],
|
|
62900
|
+
...passesThroughEnabled ? { supportsPerHookEnabled: true } : {}
|
|
62856
62901
|
};
|
|
62857
62902
|
}
|
|
62858
62903
|
const toolHooksFactories = /* @__PURE__ */ new Map([
|
|
@@ -63474,8 +63519,7 @@ const toolHooksFactories = /* @__PURE__ */ new Map([
|
|
|
63474
63519
|
supportsImport: true
|
|
63475
63520
|
},
|
|
63476
63521
|
...converterCapabilities(ZCODE_CONVERTER_CONFIG),
|
|
63477
|
-
supportsMatcher: true
|
|
63478
|
-
supportsPerHookEnabled: true
|
|
63522
|
+
supportsMatcher: true
|
|
63479
63523
|
}],
|
|
63480
63524
|
["zcode-plugin", {
|
|
63481
63525
|
class: ZcodePluginHooks,
|
|
@@ -63485,10 +63529,12 @@ const toolHooksFactories = /* @__PURE__ */ new Map([
|
|
|
63485
63529
|
supportsImport: true
|
|
63486
63530
|
},
|
|
63487
63531
|
...converterCapabilities(ZCODE_PLUGIN_CONVERTER_CONFIG),
|
|
63488
|
-
supportsMatcher: true
|
|
63489
|
-
supportsPerHookEnabled: true
|
|
63532
|
+
supportsMatcher: true
|
|
63490
63533
|
}]
|
|
63491
63534
|
]);
|
|
63535
|
+
function targetsSupporting(capability) {
|
|
63536
|
+
return [...toolHooksFactories.entries()].filter(([, f]) => f[capability]).map(([t]) => t).join(" / ");
|
|
63537
|
+
}
|
|
63492
63538
|
const hooksProcessorToolTargets = [...toolHooksFactories.entries()].filter(([, f]) => f.meta.supportsProject).map(([t]) => t);
|
|
63493
63539
|
const hooksProcessorToolTargetsGlobal = [...toolHooksFactories.entries()].filter(([, f]) => f.meta.supportsGlobal).map(([t]) => t);
|
|
63494
63540
|
const hooksProcessorToolTargetsImportable = [...toolHooksFactories.entries()].filter(([, f]) => f.meta.supportsProject && f.meta.supportsImport).map(([t]) => t);
|
|
@@ -63649,7 +63695,7 @@ var HooksProcessor = class extends FeatureProcessor {
|
|
|
63649
63695
|
effectiveHooks,
|
|
63650
63696
|
predicate: (def) => def.enabled === false
|
|
63651
63697
|
});
|
|
63652
|
-
if (eventsWithDisabledHooks.length > 0) this.logger.warn(`Emitting "enabled: false" hook(s) as active for ${this.toolTarget} (only the
|
|
63698
|
+
if (eventsWithDisabledHooks.length > 0) this.logger.warn(`Emitting "enabled: false" hook(s) as active for ${this.toolTarget} (only the ${targetsSupporting("supportsPerHookEnabled")} hooks formats support the flag): ${eventsWithDisabledHooks.join(", ")}`);
|
|
63653
63699
|
}
|
|
63654
63700
|
if (!factory.supportsPerHookConfirm) {
|
|
63655
63701
|
const eventsWithConfirmHooks = emittedEventsWithHook({
|
|
@@ -63658,7 +63704,7 @@ var HooksProcessor = class extends FeatureProcessor {
|
|
|
63658
63704
|
effectiveHooks,
|
|
63659
63705
|
predicate: (def) => def.confirm !== void 0
|
|
63660
63706
|
});
|
|
63661
|
-
if (eventsWithConfirmHooks.length > 0) this.logger.warn(`Emitting hook(s) without their "confirm" prompt for ${this.toolTarget} (only the
|
|
63707
|
+
if (eventsWithConfirmHooks.length > 0) this.logger.warn(`Emitting hook(s) without their "confirm" prompt for ${this.toolTarget} (only the ${targetsSupporting("supportsPerHookConfirm")} hooks formats support it): ${eventsWithConfirmHooks.join(", ")}`);
|
|
63662
63708
|
}
|
|
63663
63709
|
}
|
|
63664
63710
|
async convertToolFilesToRulesyncFiles(toolFiles) {
|
|
@@ -64921,12 +64967,7 @@ var ReasonixIgnore = class ReasonixIgnore extends ToolIgnore {
|
|
|
64921
64967
|
}
|
|
64922
64968
|
toRulesyncIgnore() {
|
|
64923
64969
|
const rulesyncPatterns = uniq(this.patterns.map((entry) => readDenyPatternOf(entry)).filter((pattern) => pattern !== null && pattern.length > 0));
|
|
64924
|
-
return
|
|
64925
|
-
outputRoot: this.outputRoot,
|
|
64926
|
-
relativeDirPath: RulesyncIgnore.getSettablePaths().recommended.relativeDirPath,
|
|
64927
|
-
relativeFilePath: RulesyncIgnore.getSettablePaths().recommended.relativeFilePath,
|
|
64928
|
-
fileContent: rulesyncPatterns.join("\n")
|
|
64929
|
-
});
|
|
64970
|
+
return this.toRulesyncIgnoreDefault({ fileContent: rulesyncPatterns.join("\n") });
|
|
64930
64971
|
}
|
|
64931
64972
|
static async fromRulesyncIgnore({ outputRoot = process.cwd(), rulesyncIgnore, global = false, logger }) {
|
|
64932
64973
|
await warnIfReasonixNestedProjectConfigShadowed({
|
|
@@ -78633,11 +78674,17 @@ function convertAmpToRulesync({ disable, permissions }) {
|
|
|
78633
78674
|
const assign = (tool, pattern, action) => {
|
|
78634
78675
|
if (isPrototypePollutionKey(tool)) return;
|
|
78635
78676
|
if (isPrototypePollutionKey(pattern)) return;
|
|
78636
|
-
const bucket =
|
|
78637
|
-
|
|
78677
|
+
const bucket = getOrCreateOwn({
|
|
78678
|
+
record: permission,
|
|
78679
|
+
key: tool,
|
|
78680
|
+
create: () => ({})
|
|
78681
|
+
});
|
|
78638
78682
|
if (isStricterAction({
|
|
78639
78683
|
action,
|
|
78640
|
-
existing
|
|
78684
|
+
existing: lookupOwn({
|
|
78685
|
+
record: bucket,
|
|
78686
|
+
key: pattern
|
|
78687
|
+
})
|
|
78641
78688
|
})) bucket[pattern] = action;
|
|
78642
78689
|
};
|
|
78643
78690
|
for (const tool of disable) assign(tool, "*", "deny");
|
|
@@ -80040,8 +80087,12 @@ function convertAntigravityToRulesyncPermissions({ allow, ask, deny, toCategory,
|
|
|
80040
80087
|
logger,
|
|
80041
80088
|
toolLabel
|
|
80042
80089
|
}) : target;
|
|
80043
|
-
if (
|
|
80044
|
-
|
|
80090
|
+
if (isPrototypePollutionKey(canonical) || isPrototypePollutionKey(pattern)) continue;
|
|
80091
|
+
getOrCreateOwn({
|
|
80092
|
+
record: permission,
|
|
80093
|
+
key: canonical,
|
|
80094
|
+
create: () => ({})
|
|
80095
|
+
})[pattern] = action;
|
|
80045
80096
|
}
|
|
80046
80097
|
};
|
|
80047
80098
|
processEntries(allow, "allow");
|
|
@@ -80109,10 +80160,16 @@ const ANTIGRAVITY_CLI_TO_CANONICAL_TOOL_NAMES = {
|
|
|
80109
80160
|
};
|
|
80110
80161
|
function toAntigravityCliToolName(canonical) {
|
|
80111
80162
|
if (canonical.startsWith("mcp__")) return "mcp";
|
|
80112
|
-
return
|
|
80163
|
+
return lookupOwn({
|
|
80164
|
+
record: CANONICAL_TO_ANTIGRAVITY_CLI_TOOL_NAMES,
|
|
80165
|
+
key: canonical
|
|
80166
|
+
}) ?? canonical;
|
|
80113
80167
|
}
|
|
80114
80168
|
function toCanonicalToolName$9(cliName) {
|
|
80115
|
-
return
|
|
80169
|
+
return lookupOwn({
|
|
80170
|
+
record: ANTIGRAVITY_CLI_TO_CANONICAL_TOOL_NAMES,
|
|
80171
|
+
key: cliName
|
|
80172
|
+
}) ?? cliName;
|
|
80116
80173
|
}
|
|
80117
80174
|
/**
|
|
80118
80175
|
* Permissions generator for the Google Antigravity CLI (`agy`, Antigravity 2.0).
|
|
@@ -80275,10 +80332,16 @@ const IDE_ACTION_TO_CANONICAL = {
|
|
|
80275
80332
|
};
|
|
80276
80333
|
function toIdeAction(canonical) {
|
|
80277
80334
|
if (canonical.startsWith("mcp__")) return "mcp";
|
|
80278
|
-
return
|
|
80335
|
+
return lookupOwn({
|
|
80336
|
+
record: CANONICAL_TO_IDE_ACTION,
|
|
80337
|
+
key: canonical
|
|
80338
|
+
}) ?? canonical;
|
|
80279
80339
|
}
|
|
80280
80340
|
function toCanonicalCategory$2(ideAction) {
|
|
80281
|
-
return
|
|
80341
|
+
return lookupOwn({
|
|
80342
|
+
record: IDE_ACTION_TO_CANONICAL,
|
|
80343
|
+
key: ideAction
|
|
80344
|
+
}) ?? ideAction;
|
|
80282
80345
|
}
|
|
80283
80346
|
/**
|
|
80284
80347
|
* Permissions generator for the Google Antigravity IDE (Antigravity 2.0).
|
|
@@ -81817,10 +81880,16 @@ const CANONICAL_TO_CLAUDE_TOOL_NAMES = {
|
|
|
81817
81880
|
*/
|
|
81818
81881
|
const CLAUDE_TO_CANONICAL_TOOL_NAMES = invertRecord(CANONICAL_TO_CLAUDE_TOOL_NAMES);
|
|
81819
81882
|
function toClaudeToolName(canonical) {
|
|
81820
|
-
return
|
|
81883
|
+
return lookupOwn({
|
|
81884
|
+
record: CANONICAL_TO_CLAUDE_TOOL_NAMES,
|
|
81885
|
+
key: canonical
|
|
81886
|
+
}) ?? canonical;
|
|
81821
81887
|
}
|
|
81822
81888
|
function toCanonicalToolName$7(claudeName) {
|
|
81823
|
-
return
|
|
81889
|
+
return lookupOwn({
|
|
81890
|
+
record: CLAUDE_TO_CANONICAL_TOOL_NAMES,
|
|
81891
|
+
key: claudeName
|
|
81892
|
+
}) ?? claudeName;
|
|
81824
81893
|
}
|
|
81825
81894
|
/**
|
|
81826
81895
|
* Merge `patch` into `base`, recursing into plain objects so a sibling key at
|
|
@@ -82792,7 +82861,10 @@ const CLAUDE_PATH_RULE_ALIASES = {
|
|
|
82792
82861
|
*/
|
|
82793
82862
|
function buildClaudePermissionEntry(toolName, pattern) {
|
|
82794
82863
|
if (pattern === "*") return toolName;
|
|
82795
|
-
return `${
|
|
82864
|
+
return `${lookupOwn({
|
|
82865
|
+
record: CLAUDE_PATH_RULE_ALIASES,
|
|
82866
|
+
key: toolName
|
|
82867
|
+
}) ?? toolName}(${pattern})`;
|
|
82796
82868
|
}
|
|
82797
82869
|
/**
|
|
82798
82870
|
* The Claude tool names the canonical config manages. Deliberately the tool
|
|
@@ -83030,8 +83102,12 @@ function convertClaudeToRulesyncPermissions(params) {
|
|
|
83030
83102
|
for (const entry of entries) {
|
|
83031
83103
|
const { toolName, pattern } = parseToolPatternEntry(entry);
|
|
83032
83104
|
const canonical = toCanonicalToolName$7(toolName);
|
|
83033
|
-
if (
|
|
83034
|
-
|
|
83105
|
+
if (isPrototypePollutionKey(canonical) || isPrototypePollutionKey(pattern)) continue;
|
|
83106
|
+
getOrCreateOwn({
|
|
83107
|
+
record: permission,
|
|
83108
|
+
key: canonical,
|
|
83109
|
+
create: () => ({})
|
|
83110
|
+
})[pattern] = action;
|
|
83035
83111
|
}
|
|
83036
83112
|
};
|
|
83037
83113
|
processEntries(params.allow, "allow");
|
|
@@ -83613,11 +83689,17 @@ var CodebuddyPermissions = class CodebuddyPermissions extends ToolPermissions {
|
|
|
83613
83689
|
for (const action of CODEBUDDY_RULE_LISTS) for (const rule of toStringArray$1(permissions[action])) {
|
|
83614
83690
|
const parsed = parseCodebuddyRule(rule);
|
|
83615
83691
|
if (parsed === null || isPrototypePollutionKey(parsed.category) || isPrototypePollutionKey(parsed.pattern)) continue;
|
|
83616
|
-
const rules =
|
|
83617
|
-
|
|
83692
|
+
const rules = getOrCreateOwn({
|
|
83693
|
+
record: permission,
|
|
83694
|
+
key: parsed.category,
|
|
83695
|
+
create: () => ({})
|
|
83696
|
+
});
|
|
83618
83697
|
if (isStricterAction({
|
|
83619
83698
|
action,
|
|
83620
|
-
existing
|
|
83699
|
+
existing: lookupOwn({
|
|
83700
|
+
record: rules,
|
|
83701
|
+
key: parsed.pattern
|
|
83702
|
+
})
|
|
83621
83703
|
})) rules[parsed.pattern] = action;
|
|
83622
83704
|
}
|
|
83623
83705
|
const codebuddy = liftCodebuddyOverride({
|
|
@@ -84127,7 +84209,10 @@ const CODEWHALE_WRITE_RESTRICTION_TOOLS = ["write_file", "apply_patch"];
|
|
|
84127
84209
|
/** The Codewhale tools a canonical path rule is written for. */
|
|
84128
84210
|
function pathCategoryTools(category, action) {
|
|
84129
84211
|
if (category === "write" && action !== "allow") return CODEWHALE_WRITE_RESTRICTION_TOOLS;
|
|
84130
|
-
return
|
|
84212
|
+
return lookupOwn({
|
|
84213
|
+
record: CODEWHALE_PATH_CATEGORY_TOOLS,
|
|
84214
|
+
key: category
|
|
84215
|
+
}) ?? [];
|
|
84131
84216
|
}
|
|
84132
84217
|
/** The canonical path categories a Codewhale file tool's rule can come from. */
|
|
84133
84218
|
const CODEWHALE_TOOL_TO_PATH_CATEGORIES = {
|
|
@@ -84446,7 +84531,10 @@ function canonicalToCodewhaleRules({ config, preservedRules, logger }) {
|
|
|
84446
84531
|
});
|
|
84447
84532
|
for (const [category, rules] of Object.entries(config.permission)) {
|
|
84448
84533
|
if (category === "bash" || category === "*") continue;
|
|
84449
|
-
if (
|
|
84534
|
+
if (lookupOwn({
|
|
84535
|
+
record: CODEWHALE_PATH_CATEGORY_TOOLS,
|
|
84536
|
+
key: category
|
|
84537
|
+
}) === void 0) {
|
|
84450
84538
|
if (Object.keys(rules).length > 0) logger?.warn(`Codewhale permissions: skipping unsupported category "${category}"; Codewhale evaluates permission rules only for shell commands and file tools.`);
|
|
84451
84539
|
continue;
|
|
84452
84540
|
}
|
|
@@ -84556,7 +84644,10 @@ function toImportCandidates(rule) {
|
|
|
84556
84644
|
}
|
|
84557
84645
|
const pattern = pathRuleToPattern(rule);
|
|
84558
84646
|
if (pattern === null) return [];
|
|
84559
|
-
return (
|
|
84647
|
+
return (lookupOwn({
|
|
84648
|
+
record: CODEWHALE_TOOL_TO_PATH_CATEGORIES,
|
|
84649
|
+
key: rule.tool
|
|
84650
|
+
}) ?? []).map((category) => ({
|
|
84560
84651
|
category,
|
|
84561
84652
|
pattern,
|
|
84562
84653
|
rule
|
|
@@ -86164,10 +86255,17 @@ function parseCommandcodeRuleLists(permissions) {
|
|
|
86164
86255
|
rule,
|
|
86165
86256
|
category
|
|
86166
86257
|
})) fallbackLogger.warn(`Command Code matches '${rule}' in "${action}" against MCP tool names case-insensitively, but the '${category}' rule generated from it matches the server and tool names exactly as written; spell the rule the way the tool is registered if they differ.`);
|
|
86167
|
-
const rules =
|
|
86258
|
+
const rules = getOrCreateOwn({
|
|
86259
|
+
record: permission,
|
|
86260
|
+
key: category,
|
|
86261
|
+
create: () => ({})
|
|
86262
|
+
});
|
|
86168
86263
|
if (isStricterAction({
|
|
86169
86264
|
action,
|
|
86170
|
-
existing:
|
|
86265
|
+
existing: lookupOwn({
|
|
86266
|
+
record: rules,
|
|
86267
|
+
key: pattern
|
|
86268
|
+
})
|
|
86171
86269
|
})) rules[pattern] = action;
|
|
86172
86270
|
}
|
|
86173
86271
|
}
|
|
@@ -86528,9 +86626,12 @@ function convertContinuePermissionsToRulesync(lists) {
|
|
|
86528
86626
|
const parsedEntry = parseContinuePermissionEntry(entry);
|
|
86529
86627
|
if (parsedEntry === void 0) continue;
|
|
86530
86628
|
if (isPrototypePollutionKey(parsedEntry.toolName) || isPrototypePollutionKey(parsedEntry.pattern)) continue;
|
|
86531
|
-
const
|
|
86532
|
-
|
|
86533
|
-
|
|
86629
|
+
const rules = getOrCreateOwn({
|
|
86630
|
+
record: permission,
|
|
86631
|
+
key: toCanonicalToolName$6(parsedEntry.toolName),
|
|
86632
|
+
create: () => ({})
|
|
86633
|
+
});
|
|
86634
|
+
if (!Object.hasOwn(rules, parsedEntry.pattern)) rules[parsedEntry.pattern] = action;
|
|
86534
86635
|
}
|
|
86535
86636
|
}
|
|
86536
86637
|
return { permission };
|
|
@@ -87159,7 +87260,9 @@ var CopilotcliPermissions = class CopilotcliPermissions extends ToolPermissions
|
|
|
87159
87260
|
const settings = this.parseSettings();
|
|
87160
87261
|
const rules = {};
|
|
87161
87262
|
for (const pattern of toUrlList(settings[DENIED_URLS_KEY])) rules[pattern] = "deny";
|
|
87162
|
-
if (this.global)
|
|
87263
|
+
if (this.global) {
|
|
87264
|
+
for (const pattern of toUrlList(settings[ALLOWED_URLS_KEY])) if (!Object.hasOwn(rules, pattern)) rules[pattern] = "allow";
|
|
87265
|
+
}
|
|
87163
87266
|
const permission = Object.keys(rules).length > 0 ? { [WEBFETCH_CATEGORY$1]: rules } : {};
|
|
87164
87267
|
const defaultPermissionMode = this.global ? settings[DEFAULT_PERMISSION_MODE_KEY] : void 0;
|
|
87165
87268
|
return this.toRulesyncPermissionsDefault({ fileContent: JSON.stringify({
|
|
@@ -87506,7 +87609,10 @@ function isMcpScopedCategory(canonical) {
|
|
|
87506
87609
|
}
|
|
87507
87610
|
function toCursorType(canonical) {
|
|
87508
87611
|
if (isMcpScopedCategory(canonical)) return "Mcp";
|
|
87509
|
-
return
|
|
87612
|
+
return lookupOwn({
|
|
87613
|
+
record: CANONICAL_TO_CURSOR_TYPE,
|
|
87614
|
+
key: canonical
|
|
87615
|
+
}) ?? canonical;
|
|
87510
87616
|
}
|
|
87511
87617
|
/**
|
|
87512
87618
|
* For per-tool MCP canonical categories like `mcp__puppeteer__navigate`, the
|
|
@@ -87538,9 +87644,15 @@ function toCanonicalCategory$1(cursorType, pattern) {
|
|
|
87538
87644
|
const tool = match[2] ?? "*";
|
|
87539
87645
|
return `${MCP_CATEGORY_PREFIX}${server}__${tool}`;
|
|
87540
87646
|
}
|
|
87541
|
-
return
|
|
87647
|
+
return lookupOwn({
|
|
87648
|
+
record: CURSOR_TYPE_TO_CANONICAL,
|
|
87649
|
+
key: cursorType
|
|
87650
|
+
}) ?? cursorType.toLowerCase();
|
|
87542
87651
|
}
|
|
87543
|
-
return
|
|
87652
|
+
return lookupOwn({
|
|
87653
|
+
record: CURSOR_TYPE_TO_CANONICAL,
|
|
87654
|
+
key: cursorType
|
|
87655
|
+
}) ?? cursorType.toLowerCase();
|
|
87544
87656
|
}
|
|
87545
87657
|
/**
|
|
87546
87658
|
* Narrow `JSON.parse` output to a plain object before treating it as a Cursor
|
|
@@ -87785,9 +87897,13 @@ function convertCursorToRulesyncPermissions(params) {
|
|
|
87785
87897
|
for (const entry of entries) {
|
|
87786
87898
|
const { toolName: type, pattern } = parseToolPatternEntry(entry);
|
|
87787
87899
|
const canonical = toCanonicalCategory$1(type, pattern);
|
|
87788
|
-
if (!permission[canonical]) permission[canonical] = {};
|
|
87789
87900
|
const canonicalPattern = type === "Mcp" && canonical.startsWith("mcp__") ? "*" : pattern;
|
|
87790
|
-
|
|
87901
|
+
if (isPrototypePollutionKey(canonical) || isPrototypePollutionKey(canonicalPattern)) continue;
|
|
87902
|
+
getOrCreateOwn({
|
|
87903
|
+
record: permission,
|
|
87904
|
+
key: canonical,
|
|
87905
|
+
create: () => ({})
|
|
87906
|
+
})[canonicalPattern] = action;
|
|
87791
87907
|
}
|
|
87792
87908
|
};
|
|
87793
87909
|
processEntries(params.allow, "allow");
|
|
@@ -88714,10 +88830,16 @@ const DEVIN_SCOPE_TO_CANONICAL = {
|
|
|
88714
88830
|
*/
|
|
88715
88831
|
const DEVIN_BARE_ONLY_SCOPES = /* @__PURE__ */ new Set(["web_search"]);
|
|
88716
88832
|
function toDevinScope(canonical) {
|
|
88717
|
-
return
|
|
88833
|
+
return lookupOwn({
|
|
88834
|
+
record: CANONICAL_TO_DEVIN_SCOPE,
|
|
88835
|
+
key: canonical
|
|
88836
|
+
}) ?? canonical;
|
|
88718
88837
|
}
|
|
88719
88838
|
function toCanonicalCategory(devinScope) {
|
|
88720
|
-
return
|
|
88839
|
+
return lookupOwn({
|
|
88840
|
+
record: DEVIN_SCOPE_TO_CANONICAL,
|
|
88841
|
+
key: devinScope
|
|
88842
|
+
}) ?? devinScope;
|
|
88721
88843
|
}
|
|
88722
88844
|
function asDevinRecord(value) {
|
|
88723
88845
|
return isRecord(value) ? { ...value } : {};
|
|
@@ -89069,7 +89191,11 @@ function convertDevinToRulesyncPermissions(params) {
|
|
|
89069
89191
|
const { toolName: scope, pattern } = parseToolPatternEntry(entry);
|
|
89070
89192
|
if (isPrototypePollutionKey(scope) || isPrototypePollutionKey(pattern)) continue;
|
|
89071
89193
|
const canonical = toCanonicalCategory(scope);
|
|
89072
|
-
(
|
|
89194
|
+
getOrCreateOwn({
|
|
89195
|
+
record: permission,
|
|
89196
|
+
key: canonical,
|
|
89197
|
+
create: () => ({})
|
|
89198
|
+
})[pattern] = action;
|
|
89073
89199
|
}
|
|
89074
89200
|
};
|
|
89075
89201
|
processEntries(params.allow, "allow");
|
|
@@ -89375,7 +89501,10 @@ function convertRulesyncToGoosePermissionConfig({ config, logger }) {
|
|
|
89375
89501
|
};
|
|
89376
89502
|
const assigned = /* @__PURE__ */ new Map();
|
|
89377
89503
|
for (const [category, rules] of Object.entries(honorAllToolsOnBash(config.permission))) {
|
|
89378
|
-
const toolName =
|
|
89504
|
+
const toolName = lookupOwn({
|
|
89505
|
+
record: RULESYNC_TO_GOOSE_TOOL_NAME,
|
|
89506
|
+
key: category
|
|
89507
|
+
}) ?? category;
|
|
89379
89508
|
for (const [pattern, action] of Object.entries(rules)) if (pattern !== "*") logger?.warn(`Goose permission.yaml lists whole tool names, so the per-pattern "${action}" rule for "${category}" (pattern "${pattern}") cannot be expressed and was skipped.`);
|
|
89380
89509
|
const { action, downgraded } = failSafeCatchAllAction({
|
|
89381
89510
|
rules,
|
|
@@ -89407,9 +89536,16 @@ function convertGoosePermissionConfigToRulesync(userPermission) {
|
|
|
89407
89536
|
for (const key of GOOSE_PERMISSION_LIST_KEYS) {
|
|
89408
89537
|
const toolNames = isStringArray(userPermission[key]) ? userPermission[key] : [];
|
|
89409
89538
|
const action = GOOSE_LIST_TO_ACTION[key];
|
|
89410
|
-
for (const toolName of toolNames) for (const category of
|
|
89411
|
-
|
|
89412
|
-
|
|
89539
|
+
for (const toolName of toolNames) for (const category of lookupOwn({
|
|
89540
|
+
record: GOOSE_TO_RULESYNC_TOOL_NAMES,
|
|
89541
|
+
key: toolName
|
|
89542
|
+
}) ?? [toolName]) {
|
|
89543
|
+
if (isPrototypePollutionKey(category)) continue;
|
|
89544
|
+
getOrCreateOwn({
|
|
89545
|
+
record: permission,
|
|
89546
|
+
key: category,
|
|
89547
|
+
create: () => ({})
|
|
89548
|
+
})["*"] = action;
|
|
89413
89549
|
}
|
|
89414
89550
|
}
|
|
89415
89551
|
return { permission };
|
|
@@ -89490,7 +89626,10 @@ function buildGrokEntry(category, pattern) {
|
|
|
89490
89626
|
return remainder.length > 0 ? `${GROK_MCP_TOOL}(${remainder})` : GROK_MCP_TOOL;
|
|
89491
89627
|
}
|
|
89492
89628
|
if (category === "mcp") return pattern === "*" || pattern === "" ? GROK_MCP_TOOL : `${GROK_MCP_TOOL}(${pattern})`;
|
|
89493
|
-
const tool =
|
|
89629
|
+
const tool = lookupOwn({
|
|
89630
|
+
record: CATEGORY_TO_GROK_TOOL,
|
|
89631
|
+
key: category
|
|
89632
|
+
});
|
|
89494
89633
|
if (tool === void 0) return null;
|
|
89495
89634
|
return pattern === "*" || pattern === "" ? tool : `${tool}(${toGrokPathPattern(category, pattern)})`;
|
|
89496
89635
|
}
|
|
@@ -89524,7 +89663,10 @@ function parseGrokEntry(entry) {
|
|
|
89524
89663
|
category: "mcp",
|
|
89525
89664
|
pattern: "*"
|
|
89526
89665
|
};
|
|
89527
|
-
const category =
|
|
89666
|
+
const category = lookupOwn({
|
|
89667
|
+
record: GROK_TOOL_TO_CATEGORY,
|
|
89668
|
+
key: tool
|
|
89669
|
+
});
|
|
89528
89670
|
if (category === void 0) return null;
|
|
89529
89671
|
return {
|
|
89530
89672
|
category,
|
|
@@ -89845,11 +89987,17 @@ function parseGrokPermissionArrays(permission) {
|
|
|
89845
89987
|
if ((allow?.length ?? 0) + (deny?.length ?? 0) + (ask?.length ?? 0) + (rules?.length ?? 0) === 0) return null;
|
|
89846
89988
|
const result = {};
|
|
89847
89989
|
const record = ({ category, pattern, action }) => {
|
|
89848
|
-
const bucket =
|
|
89849
|
-
|
|
89990
|
+
const bucket = getOrCreateOwn({
|
|
89991
|
+
record: result,
|
|
89992
|
+
key: category,
|
|
89993
|
+
create: () => ({})
|
|
89994
|
+
});
|
|
89850
89995
|
if (isStricterAction({
|
|
89851
89996
|
action,
|
|
89852
|
-
existing
|
|
89997
|
+
existing: lookupOwn({
|
|
89998
|
+
record: bucket,
|
|
89999
|
+
key: pattern
|
|
90000
|
+
})
|
|
89853
90001
|
})) bucket[pattern] = action;
|
|
89854
90002
|
};
|
|
89855
90003
|
const applyEntries = (entries, action) => {
|
|
@@ -89906,7 +90054,11 @@ function deleteRulesByAction(rules, action) {
|
|
|
89906
90054
|
for (const [pattern, currentAction] of Object.entries(rules)) if (currentAction === action) delete rules[pattern];
|
|
89907
90055
|
}
|
|
89908
90056
|
function ensureCategory(permission, category) {
|
|
89909
|
-
return
|
|
90057
|
+
return getOrCreateOwn({
|
|
90058
|
+
record: permission,
|
|
90059
|
+
key: category,
|
|
90060
|
+
create: () => ({})
|
|
90061
|
+
});
|
|
89910
90062
|
}
|
|
89911
90063
|
function removeEmptyCategories(permission) {
|
|
89912
90064
|
for (const [category, rules] of Object.entries(permission)) if (Object.keys(rules).length === 0) delete permission[category];
|
|
@@ -90549,7 +90701,10 @@ var JuniePermissions = class JuniePermissions extends ToolPermissions {
|
|
|
90549
90701
|
function convertRulesyncToJunieRules({ config, logger, existingRules, overrideSecretFile, overrideRuleDefaults }) {
|
|
90550
90702
|
const ruleLists = {};
|
|
90551
90703
|
for (const [category, patterns] of Object.entries(honorAllToolsOnBash(config.permission))) {
|
|
90552
|
-
const group =
|
|
90704
|
+
const group = lookupOwn({
|
|
90705
|
+
record: CANONICAL_TO_JUNIE_GROUP,
|
|
90706
|
+
key: category
|
|
90707
|
+
});
|
|
90553
90708
|
if (!group) {
|
|
90554
90709
|
if (Object.keys(patterns).length > 0) logger?.warn(`Junie allowlist only models executables/fileEditing/mcpTools/readOutsideProject (canonical bash/edit/write/read/mcp); '${category}' rules cannot be represented and were skipped.`);
|
|
90555
90710
|
continue;
|
|
@@ -90947,7 +91102,10 @@ const CATEGORY_TO_KIMI_CODE_TOOL = {
|
|
|
90947
91102
|
function buildKimiCodePattern(category, pattern) {
|
|
90948
91103
|
if (category.startsWith("mcp__")) return pattern === "*" || pattern === "" ? category : null;
|
|
90949
91104
|
if (category === "mcp") return pattern === "*" || pattern === "" ? "mcp__*" : `mcp__${pattern}`;
|
|
90950
|
-
const tool =
|
|
91105
|
+
const tool = lookupOwn({
|
|
91106
|
+
record: CATEGORY_TO_KIMI_CODE_TOOL,
|
|
91107
|
+
key: category
|
|
91108
|
+
});
|
|
90951
91109
|
if (!tool) return null;
|
|
90952
91110
|
return pattern === "*" || pattern === "" ? tool : `${tool}(${pattern})`;
|
|
90953
91111
|
}
|
|
@@ -91043,7 +91201,10 @@ function canonicalToKimiCodeRules({ config, logger }) {
|
|
|
91043
91201
|
const canonicalRules = [];
|
|
91044
91202
|
const overrideRules = config["kimi-code"]?.rules ?? [];
|
|
91045
91203
|
for (const [category, rules] of Object.entries(config.permission)) {
|
|
91046
|
-
if (!(category === "mcp" || category.startsWith("mcp__") ||
|
|
91204
|
+
if (!(category === "mcp" || category.startsWith("mcp__") || lookupOwn({
|
|
91205
|
+
record: CATEGORY_TO_KIMI_CODE_TOOL,
|
|
91206
|
+
key: category
|
|
91207
|
+
}) !== void 0)) {
|
|
91047
91208
|
if (Object.keys(rules).length > 0) logger?.warn(`Kimi Code permissions: skipping unsupported category "${category}".`);
|
|
91048
91209
|
continue;
|
|
91049
91210
|
}
|
|
@@ -91860,9 +92021,16 @@ var KiroCapabilityPermissions = class KiroCapabilityPermissions extends ToolPerm
|
|
|
91860
92021
|
if (!isImportableRule(rule) || !isRecord(rule) || !isPermissionAction(rule.effect)) continue;
|
|
91861
92022
|
const category = KIRO_CAPABILITY_TO_CANONICAL[rule.capability];
|
|
91862
92023
|
const patterns = rule.match === void 0 ? ["*"] : isStringArray(rule.match) ? rule.match : [];
|
|
91863
|
-
const categoryRules =
|
|
92024
|
+
const categoryRules = getOrCreateOwn({
|
|
92025
|
+
record: permission,
|
|
92026
|
+
key: category,
|
|
92027
|
+
create: () => ({})
|
|
92028
|
+
});
|
|
91864
92029
|
for (const pattern of patterns) {
|
|
91865
|
-
const previous =
|
|
92030
|
+
const previous = lookupOwn({
|
|
92031
|
+
record: categoryRules,
|
|
92032
|
+
key: pattern
|
|
92033
|
+
});
|
|
91866
92034
|
if (isStricterAction({
|
|
91867
92035
|
action: rule.effect,
|
|
91868
92036
|
existing: previous
|
|
@@ -91880,7 +92048,10 @@ var KiroCapabilityPermissions = class KiroCapabilityPermissions extends ToolPerm
|
|
|
91880
92048
|
function buildKiroCapabilityRules({ config, logger }) {
|
|
91881
92049
|
const buckets = /* @__PURE__ */ new Map();
|
|
91882
92050
|
for (const [category, rules] of Object.entries(honorAllToolsOnBash(config.permission))) {
|
|
91883
|
-
const capability =
|
|
92051
|
+
const capability = lookupOwn({
|
|
92052
|
+
record: CANONICAL_TO_KIRO_CAPABILITY,
|
|
92053
|
+
key: category
|
|
92054
|
+
});
|
|
91884
92055
|
if (capability === void 0) {
|
|
91885
92056
|
logger?.warn(`Kiro permissions.yaml has no capability for category: ${category}. Skipping.`);
|
|
91886
92057
|
continue;
|
|
@@ -92040,7 +92211,10 @@ function toLettacodeBashPayload({ pattern, action, logger }) {
|
|
|
92040
92211
|
return prefix === "" ? "" : `${prefix}${PREFIX_SUFFIX}`;
|
|
92041
92212
|
}
|
|
92042
92213
|
function toLettacodeRule({ category, pattern, action, logger }) {
|
|
92043
|
-
const tool =
|
|
92214
|
+
const tool = lookupOwn({
|
|
92215
|
+
record: CATEGORY_TO_LETTACODE_TOOL,
|
|
92216
|
+
key: category
|
|
92217
|
+
});
|
|
92044
92218
|
if (tool === void 0) return null;
|
|
92045
92219
|
const payload = category === "bash" ? toLettacodeBashPayload({
|
|
92046
92220
|
pattern,
|
|
@@ -92195,11 +92369,17 @@ var LettacodePermissions = class LettacodePermissions extends ToolPermissions {
|
|
|
92195
92369
|
for (const [key, action] of Object.entries(LIST_TO_ACTION)) for (const rule of toStringArray$1(permissions[key])) {
|
|
92196
92370
|
const parsed = fromLettacodeRule(rule);
|
|
92197
92371
|
if (parsed === null || isPrototypePollutionKey(parsed.pattern)) continue;
|
|
92198
|
-
const rules =
|
|
92199
|
-
|
|
92372
|
+
const rules = getOrCreateOwn({
|
|
92373
|
+
record: permission,
|
|
92374
|
+
key: parsed.category,
|
|
92375
|
+
create: () => ({})
|
|
92376
|
+
});
|
|
92200
92377
|
if (isStricterAction({
|
|
92201
92378
|
action,
|
|
92202
|
-
existing
|
|
92379
|
+
existing: lookupOwn({
|
|
92380
|
+
record: rules,
|
|
92381
|
+
key: parsed.pattern
|
|
92382
|
+
})
|
|
92203
92383
|
})) rules[parsed.pattern] = action;
|
|
92204
92384
|
}
|
|
92205
92385
|
return this.toRulesyncPermissionsDefault({ fileContent: JSON.stringify({ permission }, null, 2) });
|
|
@@ -92386,7 +92566,13 @@ function getOpencodeMcpServerNames(mcp) {
|
|
|
92386
92566
|
return isRecord(lowered) ? Object.keys(lowered) : [];
|
|
92387
92567
|
}
|
|
92388
92568
|
function toOpencodePermissionKey(canonical) {
|
|
92389
|
-
return
|
|
92569
|
+
return lookupOwn({
|
|
92570
|
+
record: CANONICAL_TO_OPENCODE_PERMISSION_KEYS,
|
|
92571
|
+
key: canonical
|
|
92572
|
+
}) ?? lookupOwn({
|
|
92573
|
+
record: CANONICAL_TO_OPENCODE_FOLDED_PERMISSION_KEYS,
|
|
92574
|
+
key: canonical
|
|
92575
|
+
}) ?? canonical;
|
|
92390
92576
|
}
|
|
92391
92577
|
/**
|
|
92392
92578
|
* Merge two canonical pattern maps that land on the same OpenCode key.
|
|
@@ -92410,7 +92596,10 @@ function mergePatternRules(base, incoming) {
|
|
|
92410
92596
|
return Object.fromEntries(Object.entries(merged).toSorted(([, a], [, b]) => PERMISSION_ACTION_PRIORITY[a] - PERMISSION_ACTION_PRIORITY[b]));
|
|
92411
92597
|
}
|
|
92412
92598
|
function toCanonicalPermissionKey(opencodeKey) {
|
|
92413
|
-
return
|
|
92599
|
+
return lookupOwn({
|
|
92600
|
+
record: OPENCODE_TO_CANONICAL_PERMISSION_KEYS,
|
|
92601
|
+
key: opencodeKey
|
|
92602
|
+
}) ?? opencodeKey;
|
|
92414
92603
|
}
|
|
92415
92604
|
function isSharedPermissionCategory(category) {
|
|
92416
92605
|
return category === "*" || CANONICAL_PERMISSION_CATEGORIES$1.has(category) || category.startsWith("mcp__");
|
|
@@ -93692,7 +93881,14 @@ function importPoolTool({ toolConfig, bucket }) {
|
|
|
93692
93881
|
const denied = isStringArray(toolConfig[POOL_DENY_KEY]) ? toolConfig[POOL_DENY_KEY] : [];
|
|
93693
93882
|
const allowed = isStringArray(toolConfig[POOL_ALLOW_KEY]) ? toolConfig[POOL_ALLOW_KEY] : [];
|
|
93694
93883
|
for (const pattern of denied.filter(isUsablePattern)) bucket[pattern] = "deny";
|
|
93695
|
-
for (const pattern of allowed.filter(isUsablePattern)) bucket[pattern]
|
|
93884
|
+
for (const pattern of allowed.filter(isUsablePattern)) if (!Object.hasOwn(bucket, pattern)) bucket[pattern] = "allow";
|
|
93885
|
+
}
|
|
93886
|
+
/**
|
|
93887
|
+
* Record `allow` for a path no deny has claimed. The check is on own
|
|
93888
|
+
* properties, so a path such as `toString` is not mistaken for a stored rule.
|
|
93889
|
+
*/
|
|
93890
|
+
function allowUnlessSet(bucket, path) {
|
|
93891
|
+
if (!Object.hasOwn(bucket, path)) bucket[path] = "allow";
|
|
93696
93892
|
}
|
|
93697
93893
|
/**
|
|
93698
93894
|
* Convert Pool's `tools` and `paths` blocks back into a rulesync config.
|
|
@@ -93727,8 +93923,8 @@ function convertPoolToRulesync({ tools, paths }) {
|
|
|
93727
93923
|
for (const entry of allowEntries) {
|
|
93728
93924
|
const path = pathOfEntry(entry);
|
|
93729
93925
|
if (path === void 0) continue;
|
|
93730
|
-
bucketFor(READ_CATEGORY)
|
|
93731
|
-
if (isRecord(entry) && entry[POOL_WRITE_KEY] === true) for (const category of WRITE_CATEGORIES) bucketFor(category)
|
|
93926
|
+
allowUnlessSet(bucketFor(READ_CATEGORY), path);
|
|
93927
|
+
if (isRecord(entry) && entry[POOL_WRITE_KEY] === true) for (const category of WRITE_CATEGORIES) allowUnlessSet(bucketFor(category), path);
|
|
93732
93928
|
}
|
|
93733
93929
|
return { permission };
|
|
93734
93930
|
}
|
|
@@ -93857,7 +94053,10 @@ function toQoderRule({ category, pattern, logger }) {
|
|
|
93857
94053
|
logger?.warn(`Qoder permissions: skipping the '${category}' rule '${pattern}' — Qoder matches MCP tools by name only.`);
|
|
93858
94054
|
return null;
|
|
93859
94055
|
}
|
|
93860
|
-
const tool =
|
|
94056
|
+
const tool = lookupOwn({
|
|
94057
|
+
record: CATEGORY_TO_QODER_TOOL,
|
|
94058
|
+
key: category
|
|
94059
|
+
});
|
|
93861
94060
|
if (tool === void 0) return null;
|
|
93862
94061
|
if (pattern === "*") return tool;
|
|
93863
94062
|
return `${QODER_PATH_RULE_ALIASES[tool] ?? tool}(${pattern})`;
|
|
@@ -94143,11 +94342,17 @@ var QoderPermissions = class QoderPermissions extends ToolPermissions {
|
|
|
94143
94342
|
for (const action of ACTIONS) for (const rule of toStringArray$1(permissions[action])) {
|
|
94144
94343
|
const parsed = fromQoderRule(rule);
|
|
94145
94344
|
if (parsed === null || isPrototypePollutionKey(parsed.category) || isPrototypePollutionKey(parsed.pattern)) continue;
|
|
94146
|
-
const rules =
|
|
94147
|
-
|
|
94345
|
+
const rules = getOrCreateOwn({
|
|
94346
|
+
record: permission,
|
|
94347
|
+
key: parsed.category,
|
|
94348
|
+
create: () => ({})
|
|
94349
|
+
});
|
|
94148
94350
|
if (isStricterAction({
|
|
94149
94351
|
action,
|
|
94150
|
-
existing
|
|
94352
|
+
existing: lookupOwn({
|
|
94353
|
+
record: rules,
|
|
94354
|
+
key: parsed.pattern
|
|
94355
|
+
})
|
|
94151
94356
|
})) rules[parsed.pattern] = action;
|
|
94152
94357
|
}
|
|
94153
94358
|
const outputStyle = settings[QODER_OUTPUT_STYLE_KEY];
|
|
@@ -94211,10 +94416,16 @@ const CANONICAL_TO_QWEN_TOOL_NAMES = {
|
|
|
94211
94416
|
};
|
|
94212
94417
|
const QWEN_TO_CANONICAL_TOOL_NAMES = invertRecord(CANONICAL_TO_QWEN_TOOL_NAMES);
|
|
94213
94418
|
function toQwenToolName(canonical) {
|
|
94214
|
-
return
|
|
94419
|
+
return lookupOwn({
|
|
94420
|
+
record: CANONICAL_TO_QWEN_TOOL_NAMES,
|
|
94421
|
+
key: canonical
|
|
94422
|
+
}) ?? canonical;
|
|
94215
94423
|
}
|
|
94216
94424
|
function toCanonicalToolName$3(qwenName) {
|
|
94217
|
-
return
|
|
94425
|
+
return lookupOwn({
|
|
94426
|
+
record: QWEN_TO_CANONICAL_TOOL_NAMES,
|
|
94427
|
+
key: qwenName
|
|
94428
|
+
}) ?? qwenName;
|
|
94218
94429
|
}
|
|
94219
94430
|
function parseQwenPermissionEntry(entry, options = {}) {
|
|
94220
94431
|
const parenIndex = entry.indexOf("(");
|
|
@@ -94830,15 +95041,23 @@ function convertQwenToRulesyncPermissions(params) {
|
|
|
94830
95041
|
if (!parsed.ok) {
|
|
94831
95042
|
if (action === "deny") {
|
|
94832
95043
|
const canonical = toCanonicalToolName$3(parsed.toolName);
|
|
94833
|
-
if (
|
|
94834
|
-
|
|
95044
|
+
if (isPrototypePollutionKey(canonical)) continue;
|
|
95045
|
+
getOrCreateOwn({
|
|
95046
|
+
record: permission,
|
|
95047
|
+
key: canonical,
|
|
95048
|
+
create: () => ({})
|
|
95049
|
+
})["*"] = action;
|
|
94835
95050
|
}
|
|
94836
95051
|
continue;
|
|
94837
95052
|
}
|
|
94838
95053
|
const { toolName, pattern } = parsed;
|
|
94839
95054
|
const canonical = toCanonicalToolName$3(toolName);
|
|
94840
|
-
if (
|
|
94841
|
-
|
|
95055
|
+
if (isPrototypePollutionKey(canonical) || isPrototypePollutionKey(pattern)) continue;
|
|
95056
|
+
getOrCreateOwn({
|
|
95057
|
+
record: permission,
|
|
95058
|
+
key: canonical,
|
|
95059
|
+
create: () => ({})
|
|
95060
|
+
})[pattern] = action;
|
|
94842
95061
|
}
|
|
94843
95062
|
};
|
|
94844
95063
|
processEntries(params.allow, "allow");
|
|
@@ -94902,15 +95121,24 @@ const REASONIX_TO_CANONICAL_TOOL_NAMES = {
|
|
|
94902
95121
|
};
|
|
94903
95122
|
/** Every Reasonix tool name a canonical category owns on generate. */
|
|
94904
95123
|
function reasonixToolNamesOf(canonical) {
|
|
94905
|
-
const legacy =
|
|
95124
|
+
const legacy = lookupOwn({
|
|
95125
|
+
record: CANONICAL_TO_LEGACY_REASONIX_TOOL_NAMES,
|
|
95126
|
+
key: canonical
|
|
95127
|
+
});
|
|
94906
95128
|
const current = toReasonixToolName(canonical);
|
|
94907
95129
|
return legacy === void 0 ? [current] : [current, legacy];
|
|
94908
95130
|
}
|
|
94909
95131
|
function toReasonixToolName(canonical) {
|
|
94910
|
-
return
|
|
95132
|
+
return lookupOwn({
|
|
95133
|
+
record: CANONICAL_TO_REASONIX_TOOL_NAMES,
|
|
95134
|
+
key: canonical
|
|
95135
|
+
}) ?? canonical;
|
|
94911
95136
|
}
|
|
94912
95137
|
function toCanonicalToolName$2(reasonixName) {
|
|
94913
|
-
return
|
|
95138
|
+
return lookupOwn({
|
|
95139
|
+
record: REASONIX_TO_CANONICAL_TOOL_NAMES,
|
|
95140
|
+
key: reasonixName
|
|
95141
|
+
}) ?? reasonixName;
|
|
94914
95142
|
}
|
|
94915
95143
|
/**
|
|
94916
95144
|
* Whether an entry uses the first-class `Tool=<literal>` exact-command form
|
|
@@ -95533,8 +95761,12 @@ function convertReasonixToRulesyncPermissions(params) {
|
|
|
95533
95761
|
for (const entry of entries) {
|
|
95534
95762
|
const { toolName, pattern } = parseToolPatternEntry(entry);
|
|
95535
95763
|
const canonical = toCanonicalToolName$2(toolName);
|
|
95536
|
-
if (
|
|
95537
|
-
|
|
95764
|
+
if (isPrototypePollutionKey(canonical) || isPrototypePollutionKey(pattern)) continue;
|
|
95765
|
+
getOrCreateOwn({
|
|
95766
|
+
record: permission,
|
|
95767
|
+
key: canonical,
|
|
95768
|
+
create: () => ({})
|
|
95769
|
+
})[pattern] = action;
|
|
95538
95770
|
}
|
|
95539
95771
|
};
|
|
95540
95772
|
processEntries(params.allow, "allow");
|
|
@@ -96086,7 +96318,10 @@ function convertRulesyncToRovodevToolPermissions({ config, logger }) {
|
|
|
96086
96318
|
if (bash) toolPermissions.bash = bash;
|
|
96087
96319
|
continue;
|
|
96088
96320
|
}
|
|
96089
|
-
const toolKeys =
|
|
96321
|
+
const toolKeys = lookupOwn({
|
|
96322
|
+
record: CATEGORY_TO_TOOL_KEYS,
|
|
96323
|
+
key: category
|
|
96324
|
+
});
|
|
96090
96325
|
if (!toolKeys) {
|
|
96091
96326
|
logger?.warn(`Rovo Dev permissions have no target for the "${category}" category. Skipping it.`);
|
|
96092
96327
|
markSharedToolKeyRestriction({
|
|
@@ -96234,7 +96469,7 @@ function convertRovodevToolPermissionsToRulesync(toolPermissions) {
|
|
|
96234
96469
|
}
|
|
96235
96470
|
if (isStringArray(toolPermissions.allowedExternalPaths)) for (const path of toolPermissions.allowedExternalPaths) {
|
|
96236
96471
|
permission.read ??= {};
|
|
96237
|
-
permission.read[path]
|
|
96472
|
+
if (!Object.hasOwn(permission.read, path)) permission.read[path] = "allow";
|
|
96238
96473
|
}
|
|
96239
96474
|
return { permission };
|
|
96240
96475
|
}
|
|
@@ -97971,11 +98206,17 @@ var TraePermissions = class TraePermissions extends ToolPermissions {
|
|
|
97971
98206
|
const permission = {};
|
|
97972
98207
|
const put = (category, pattern, action) => {
|
|
97973
98208
|
if (isPrototypePollutionKey(category) || isPrototypePollutionKey(pattern)) return;
|
|
97974
|
-
const rules =
|
|
97975
|
-
|
|
98209
|
+
const rules = getOrCreateOwn({
|
|
98210
|
+
record: permission,
|
|
98211
|
+
key: category,
|
|
98212
|
+
create: () => ({})
|
|
98213
|
+
});
|
|
97976
98214
|
if (isStricterAction({
|
|
97977
98215
|
action,
|
|
97978
|
-
existing
|
|
98216
|
+
existing: lookupOwn({
|
|
98217
|
+
record: rules,
|
|
98218
|
+
key: pattern
|
|
98219
|
+
})
|
|
97979
98220
|
})) rules[pattern] = action;
|
|
97980
98221
|
};
|
|
97981
98222
|
for (const [key, value] of Object.entries(readRecord(customProfiles, COMMAND_RULES_PATH))) {
|
|
@@ -100318,7 +100559,10 @@ function toZedToolName(canonical) {
|
|
|
100318
100559
|
const address = toolParts.length > 0 ? `${server}:${toolParts.join("__")}` : server ?? "";
|
|
100319
100560
|
return `${MCP_ZED_PREFIX}${address}`;
|
|
100320
100561
|
}
|
|
100321
|
-
return
|
|
100562
|
+
return lookupOwn({
|
|
100563
|
+
record: CANONICAL_TO_ZED_TOOL_NAMES,
|
|
100564
|
+
key: canonical
|
|
100565
|
+
}) ?? canonical;
|
|
100322
100566
|
}
|
|
100323
100567
|
function toCanonicalToolName(zedName) {
|
|
100324
100568
|
if (zedName.startsWith(MCP_ZED_PREFIX)) {
|
|
@@ -100326,7 +100570,10 @@ function toCanonicalToolName(zedName) {
|
|
|
100326
100570
|
const address = toolParts.length > 0 ? `${server}__${toolParts.join(":")}` : server ?? "";
|
|
100327
100571
|
return `${MCP_CATEGORY_PREFIX}${address}`;
|
|
100328
100572
|
}
|
|
100329
|
-
return
|
|
100573
|
+
return lookupOwn({
|
|
100574
|
+
record: ZED_TO_CANONICAL_TOOL_NAMES,
|
|
100575
|
+
key: zedName
|
|
100576
|
+
}) ?? zedName;
|
|
100330
100577
|
}
|
|
100331
100578
|
/**
|
|
100332
100579
|
* Zed matches `always_allow`/`always_deny`/`always_confirm` regexes against the
|
|
@@ -100638,7 +100885,10 @@ var ZedPermissions = class ZedPermissions extends ToolPermissions {
|
|
|
100638
100885
|
const globalDefault = parsed.success ? parsed.data.default : void 0;
|
|
100639
100886
|
const permission = {};
|
|
100640
100887
|
const ensure = (category) => {
|
|
100641
|
-
const existing =
|
|
100888
|
+
const existing = lookupOwn({
|
|
100889
|
+
record: permission,
|
|
100890
|
+
key: category
|
|
100891
|
+
});
|
|
100642
100892
|
if (existing) return existing;
|
|
100643
100893
|
const created = {};
|
|
100644
100894
|
permission[category] = created;
|
|
@@ -101265,7 +101515,7 @@ function resolveToolOutputRoot({ outputRoot, toolTarget, global }) {
|
|
|
101265
101515
|
async function convertFromTool(params) {
|
|
101266
101516
|
resetRunWarningState();
|
|
101267
101517
|
const packagingTarget = [params.fromTool, ...params.toTools].find(isPackagingToolTarget);
|
|
101268
|
-
if (packagingTarget) throw new Error(`Plugin packaging target '${packagingTarget}' is not supported by convert. Use import and generate with
|
|
101518
|
+
if (packagingTarget) throw new Error(`Plugin packaging target '${packagingTarget}' is not supported by convert. Use import with the plugin directory as outputRoot (--output-root) and generate with it in outputRoots (--output-roots).`);
|
|
101269
101519
|
const ctx = params;
|
|
101270
101520
|
const [rulesCount, ignoreCount, mcpCount, commandsCount, subagentsCount, skillsCount, hooksCount, permissionsCount, checksCount] = [
|
|
101271
101521
|
await runFeatureConvert(ctx, buildRulesStrategy(ctx)),
|
|
@@ -103745,6 +103995,6 @@ const CHECKS_IMPORT_STRATEGY = {
|
|
|
103745
103995
|
missingLabel: "check files",
|
|
103746
103996
|
createdLabel: "check files"
|
|
103747
103997
|
};
|
|
103748
|
-
export {
|
|
103998
|
+
export { RulesyncMcp as $, RULESYNC_USER_CONFIG_DIR_NAME as $n, isRootDirPath as $t, CODEBUDDY_LOCAL_RULE_FILE_NAME as A, CURATED_RULES_FEATURE_SUBDIR as An, resetRunWarningState as At, CLAUDECODE_MEMORIES_DIR_NAME as B, RULESYNC_HOOKS_RELATIVE_FILE_PATH as Bn, assertTreeContainsNoSymlinks as Bt, LETTACODE_DIR as C, ALL_TOOL_TARGETS as Cn, findControlCharacter as Ct, COMMANDCODE_DIR as D, ALL_FEATURES as Dn, fallbackLogger as Dt, FACTORYDROID_SETTINGS_LOCAL_FILE_NAME as E, ToolTargetSchema as En, WarningCollectingLogger as Et, CODEXCLI_BASH_RULES_FILE_NAME as F, RULESYNC_COMMANDS_RELATIVE_DIR_PATH as Fn, PathOutsideRootError as Ft, getLocalSkillDirNames as G, RULESYNC_NPM_SOURCES_LOCK_RELATIVE_FILE_PATH as Gn, ensureDir as Gt, CLAUDECODE_SKILLS_DIR_PATH as H, RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH as Hn, checkPathTraversal as Ht, CODEXCLI_DIR as I, RULESYNC_CONFIG_RELATIVE_FILE_PATH as In, applyFileMode as It, RulesyncSkill as J, RULESYNC_RELATIVE_DIR_PATH as Jn, findFilesByGlobs as Jt, RulesyncSubagent as K, RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH as Kn, fileExists as Kt, CLAUDECODE_AGENT_MEMORY_LOCAL_DIR_NAME as L, RULESYNC_CONFIG_SCHEMA_URL as Ln, assertDirectoryIfExists as Lt, AUGMENTCODE_SETTINGS_LOCAL_FILE_NAME as M, MAX_FILE_SIZE as Mn, CLIError as Mt, caseFoldIdentity as N, RULESYNC_AIIGNORE_RELATIVE_FILE_PATH as Nn, ErrorCodes as Nt, COMMANDCODE_SETTINGS_LOCAL_FILE_NAME as O, ALL_FEATURES_WITH_WILDCARD as On, warnOnConflictingFlags as Ot, groupSpellingsByCaseFoldedIdentity as P, RULESYNC_CHECKS_RELATIVE_DIR_PATH as Pn, parseJsonc as Pt, RulesyncPermissions as Q, RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH as Qn, isFileSystemError as Qt, CLAUDECODE_DIR as R, RULESYNC_CURATED_RULES_RELATIVE_DIR_PATH as Rn, assertNoSymlinkBelowRoot as Rt, QWENCODE_LOCAL_RULE_FILE_NAME as S, mapWithConcurrency as Sn, getSourceTransport as St, FACTORYDROID_DIR as T, PACKAGING_TOOL_TARGETS as Tn, JsonLogger as Tt, findProjectInstructionBudgetFindings as U, RULESYNC_MCP_RELATIVE_FILE_PATH as Un, createTempDirectory as Ut, CLAUDECODE_SETTINGS_LOCAL_FILE_NAME as V, RULESYNC_IGNORE_RELATIVE_FILE_PATH as Vn, assertWritablePathInsideRoot as Vt, toInstructionBudgetFile as W, RULESYNC_MCP_SCHEMA_URL as Wn, directoryExists as Wt, RulesyncRule as X, RULESYNC_SKILLS_RELATIVE_DIR_PATH as Xn, getHomeDirectory as Xt, RulesyncSkillFrontmatterSchema as Y, RULESYNC_RULES_RELATIVE_DIR_PATH as Yn, getFileSizeAndExecutableBit as Yt, RulesyncRuleFrontmatterSchema as Z, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH as Zn, isFileNotFoundError as Zt, SkillsProcessor as _, runWithDirectoryRollback as _n, CONFLICTING_TARGET_PAIRS as _t, convertFromTool as a, pathEscapesRoot as an, hasEnclosingMarkOutsideKeycap as ar, RulesyncCommandFrontmatterSchema as at, REASONIX_LOCAL_RULE_FILE_NAME as b, writeFileBuffer as bn, SourceEntrySchema as bt, ELLIPSIS_WIDTH as c, readFileContentOrNull as cn, stripControlCharactersKeepingLineFeeds as cr, stringifyFrontmatter as ct, McpProcessor as d, removeFile as dn, SHARED_USER_MANAGED_CONFIG_PATHS as dt, isSymlink as en, RULESYNC_XDG_CONFIG_HOME_DEFAULT_DIR_NAME as er, RulesyncIgnore as et, IgnoreProcessor as f, removeFileStrict as fn, SKILL_FILE_NAME as ft, SubagentsProcessor as g, resolvedRelativePath as gn, resolveEffectiveInputRoots as gt, RulesProcessor as h, resolvePath as hn, parseConfigFileContent as ht, inspectInputRoots as i, normalizePosixDirPath as in, hasDeceptiveHiddenCharacters as ir, RulesyncCommand as it, AUGMENTCODE_DIR as j, FEATURE_SOURCE_TREE_ENTRIES as jn, withWarnOnceScope as jt, CODEBUDDY_DIR as k, DEPRECATED_FEATURE_REPLACEMENTS as kn, withFallbackLoggerTarget as kt, displayWidthOf as l, removeDirectory as ln, stripControlCharactersKeepingLineFeedsAndTabs as lr, loadYaml as lt, ChecksProcessor as m, removeTempDirectory as mn, mergeInputRootConfigs as mt, formatSourceLoadFailure as n, listFilePathsRecursively as nn, formatError as nr, getRulesyncSourceCandidates as nt, getProcessorRegistryEntry as o, posixRelativePathEscapesRoot as on, quoteForLog as or, RulesyncCheck as ot, HooksProcessor as p, removeFileWithoutFollowingSymlinks as pn, ConfigResolver as pt, RulesyncSubagentFrontmatterSchema as q, RULESYNC_PERMISSIONS_SCHEMA_URL as qn, fileExistsStrict as qt, generate as r, listSubdirectoryNames as rn, truncateText as rr, resolveRulesyncSourceWritePath as rt, parseCommaSeparatedList as s, readFileContent as sn, stripControlCharacters as sr, RulesyncCheckFrontmatterSchema as st, importFromTool as t, listDirectoryEntryNames as tn, formatMegabytes as tr, RulesyncHooks as tt, shortenToWidth as u, removeDirectoryStrict as un, stripHiddenCharacters as ur, isRecord as ut, CRUSH_LOCAL_RULE_FILE_NAME as v, splitPathSegments as vn, ConfigFileSchema as vt, LETTACODE_SETTINGS_LOCAL_FILE_NAME as w, ALL_TOOL_TARGETS_WITH_WILDCARD as wn, ConsoleLogger as wt, QWENCODE_DIR as x, writeFileContent as xn, assertTargetsFeaturesExclusive as xt, CommandsProcessor as y, toPosixPath as yn, GITIGNORE_DESTINATION_KEY as yt, CLAUDECODE_LOCAL_RULE_FILE_NAME as z, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH as zn, assertPathResolvesInsideRoot as zt };
|
|
103749
103999
|
|
|
103750
|
-
//# sourceMappingURL=import-
|
|
104000
|
+
//# sourceMappingURL=import-iLVVcze8.js.map
|