rulesync 43.4.2 → 43.5.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 +5 -5
- package/dist/cli/index.js +5 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/{import-ClFasGQ6.cjs → import-CAePeHTT.cjs} +710 -128
- package/dist/{import-BWOC-Tig.js → import-C_XK2L62.js} +711 -129
- package/dist/{import-BWOC-Tig.js.map → import-C_XK2L62.js.map} +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -8378,17 +8378,29 @@ const CodewhalePermissionsOverrideSchema = z.looseObject({
|
|
|
8378
8378
|
rules: z.optional(z.array(CodewhalePermissionRuleSchema))
|
|
8379
8379
|
});
|
|
8380
8380
|
/**
|
|
8381
|
-
* The
|
|
8382
|
-
*
|
|
8381
|
+
* The values VS Code's `chat.permissions.default` setting accepts: the starting
|
|
8382
|
+
* permission level of new Local-harness chat sessions — `default` (Default
|
|
8383
8383
|
* Permissions), `autoApprove` (Bypass Approvals) and `autopilot` (Autopilot).
|
|
8384
8384
|
*
|
|
8385
8385
|
* @see https://code.visualstudio.com/docs/agents/reference/ai-settings
|
|
8386
8386
|
*/
|
|
8387
|
-
const
|
|
8387
|
+
const COPILOT_LOCAL_PERMISSION_LEVELS = [
|
|
8388
8388
|
"default",
|
|
8389
8389
|
"autoApprove",
|
|
8390
8390
|
"autopilot"
|
|
8391
8391
|
];
|
|
8392
|
+
/**
|
|
8393
|
+
* The starting permission level the `copilot.defaultPermissionMode` override
|
|
8394
|
+
* sets for new chat sessions: the {@link COPILOT_LOCAL_PERMISSION_LEVELS}, plus
|
|
8395
|
+
* `assisted` (Assisted permissions, GA for Copilot-harness sessions since VS
|
|
8396
|
+
* Code 1.144 and unavailable to Local sessions). Each value is written to both
|
|
8397
|
+
* `chat.permissions.default` (Local sessions) and the `approvals` / `mode` of
|
|
8398
|
+
* `chat.defaultConfiguration` (Copilot-harness sessions, VS Code 1.144+).
|
|
8399
|
+
*
|
|
8400
|
+
* @see https://code.visualstudio.com/updates/v1_144
|
|
8401
|
+
* @see https://github.com/microsoft/vscode/blob/1.144.0/src/vs/workbench/contrib/chat/browser/chat.shared.contribution.ts
|
|
8402
|
+
*/
|
|
8403
|
+
const COPILOT_DEFAULT_PERMISSION_MODES = [...COPILOT_LOCAL_PERMISSION_LEVELS, "assisted"];
|
|
8392
8404
|
/** `chat.agent.sandbox.enabled`: `"off"` or `"on"`. */
|
|
8393
8405
|
const CopilotSandboxEnabledSchema = z.enum(["off", "on"]);
|
|
8394
8406
|
/** `chat.agent.sandbox.fileSystem.userConfiguredPaths`. */
|
|
@@ -8429,7 +8441,7 @@ const CopilotSandboxSchema = z.strictObject({
|
|
|
8429
8441
|
/**
|
|
8430
8442
|
* Tool-scoped override block for GitHub Copilot in VS Code.
|
|
8431
8443
|
* `defaultPermissionMode` writes the workspace `chat.permissions.default`
|
|
8432
|
-
*
|
|
8444
|
+
* and `chat.defaultConfiguration` settings, and `sandbox` writes the `chat.agent.sandbox.*` settings; neither
|
|
8433
8445
|
* has a canonical category.
|
|
8434
8446
|
*/
|
|
8435
8447
|
const CopilotPermissionsOverrideSchema = z.looseObject({
|
|
@@ -9311,6 +9323,7 @@ const TaktPermissionsOverrideSchema = z.looseObject({
|
|
|
9311
9323
|
})),
|
|
9312
9324
|
workflow_runtime_prepare: z.optional(z.object({ custom_scripts: z.optional(z.boolean()) })),
|
|
9313
9325
|
workflow_command_gates: z.optional(z.object({ custom_scripts: z.optional(z.boolean()) })),
|
|
9326
|
+
workflow_system_commands: z.optional(z.object({ custom_scripts: z.optional(z.boolean()) })),
|
|
9314
9327
|
sync_conflict_resolver: z.optional(z.object({ auto_approve_tools: z.optional(z.boolean()) })),
|
|
9315
9328
|
allow_git_hooks: z.optional(z.boolean()),
|
|
9316
9329
|
allow_git_filters: z.optional(z.boolean())
|
|
@@ -9578,6 +9591,7 @@ const CodexSandboxModeSchema = z.enum([
|
|
|
9578
9591
|
"workspace-write",
|
|
9579
9592
|
"danger-full-access"
|
|
9580
9593
|
]);
|
|
9594
|
+
const CODEX_U32_MAX = 4294967295;
|
|
9581
9595
|
/**
|
|
9582
9596
|
* Codex CLI's reviewer for approval requests. `guardian_subagent` is a legacy
|
|
9583
9597
|
* value Codex still accepts for backward compatibility, so it is included so
|
|
@@ -9646,6 +9660,9 @@ const CodexBasePermissionProfileSchema = z.enum(CODEX_BASE_PERMISSION_PROFILES);
|
|
|
9646
9660
|
* | `guardian_subagent`), or a table for the richer reviewer config.
|
|
9647
9661
|
* Defaults to `auto_review` when neither the override nor the existing
|
|
9648
9662
|
* config sets it.
|
|
9663
|
+
* - `auto_review` — the `[auto_review]` table that configures the reviewer
|
|
9664
|
+
* `approvals_reviewer = "auto_review"` selects (`policy`, `extra_policy`,
|
|
9665
|
+
* `timeout_ms`, …). A loose table, shallow-merged like `apps` / `tui`.
|
|
9649
9666
|
* - `git_write_rules` — whether the managed profile's `:workspace_roots` table
|
|
9650
9667
|
* emits the default `.git` carve-out (`".git/**" = "write"`). Codex's
|
|
9651
9668
|
* `:workspace` baseline makes `.git` read-only, which denies basic git
|
|
@@ -9659,7 +9676,8 @@ const CodexBasePermissionProfileSchema = z.enum(CODEX_BASE_PERMISSION_PROFILES);
|
|
|
9659
9676
|
* The keys written to `config.toml` are an **allowlist**, not verbatim
|
|
9660
9677
|
* passthrough: only `CODEXCLI_OVERRIDE_KEYS`
|
|
9661
9678
|
* (`src/constants/codexcli-paths.ts` — `approval_policy`, `sandbox_mode`,
|
|
9662
|
-
* `sandbox_workspace_write`, `apps`, `approvals_reviewer`
|
|
9679
|
+
* `sandbox_workspace_write`, `apps`, `approvals_reviewer`, `auto_review`,
|
|
9680
|
+
* `tui`) are emitted, and
|
|
9663
9681
|
* `computeCodexcliOverridePatch` skips anything else with a warning.
|
|
9664
9682
|
* `base_permission_profile` and `git_write_rules` are consumed by the profile
|
|
9665
9683
|
* builder rather than written, as described above, and `permission` is the
|
|
@@ -9691,6 +9709,26 @@ const CodexcliPermissionsOverrideSchema = z.looseObject({
|
|
|
9691
9709
|
apps: z.optional(z.looseObject({})),
|
|
9692
9710
|
approvals_reviewer: z.optional(z.union([CodexApprovalsReviewerSchema, z.looseObject({})])),
|
|
9693
9711
|
/**
|
|
9712
|
+
* The `[auto_review]` table of `config.toml`, which configures the reviewer
|
|
9713
|
+
* that `approvals_reviewer = "auto_review"` (Rulesync's default) selects:
|
|
9714
|
+
* `policy` / `extra_policy` (text inserted into the reviewer prompt),
|
|
9715
|
+
* `timeout_ms` (the review budget, Codex 0.165.0+; `0` waits without a
|
|
9716
|
+
* deadline), `circuit_break_action` (`default` | `strict`) and
|
|
9717
|
+
* `conversation_history_max_output_tokens` (a positive token cap). Codex
|
|
9718
|
+
* rejects the whole config file when one of these has the wrong type or is
|
|
9719
|
+
* out of range (`timeout_ms` is a `u32`, the token cap a `NonZeroUsize`), so
|
|
9720
|
+
* they are checked here; every other key passes through verbatim.
|
|
9721
|
+
*
|
|
9722
|
+
* @see https://github.com/openai/codex/blob/rust-v0.166.0/codex-rs/config/src/config_toml.rs (`AutoReviewToml`)
|
|
9723
|
+
*/
|
|
9724
|
+
auto_review: z.optional(z.looseObject({
|
|
9725
|
+
policy: z.optional(z.string()),
|
|
9726
|
+
extra_policy: z.optional(z.string()),
|
|
9727
|
+
timeout_ms: z.optional(z.int().check(z.nonnegative(), z.lte(CODEX_U32_MAX))),
|
|
9728
|
+
circuit_break_action: z.optional(z.enum(["default", "strict"])),
|
|
9729
|
+
conversation_history_max_output_tokens: z.optional(z.int().check(z.positive()))
|
|
9730
|
+
})),
|
|
9731
|
+
/**
|
|
9694
9732
|
* The `[tui]` table of `config.toml` (e.g. `vim_mode_default`, `keymap.*`).
|
|
9695
9733
|
* Not a permission surface, but like `apps` it is a top-level table with no
|
|
9696
9734
|
* canonical category, and Codex adds keys to it faster than an explicit model
|
|
@@ -12297,6 +12335,7 @@ const CODEXCLI_OVERRIDE_KEYS = [
|
|
|
12297
12335
|
"sandbox_workspace_write",
|
|
12298
12336
|
"apps",
|
|
12299
12337
|
"approvals_reviewer",
|
|
12338
|
+
"auto_review",
|
|
12300
12339
|
"tui"
|
|
12301
12340
|
];
|
|
12302
12341
|
// src/constants/takt-paths.ts
|
|
@@ -13719,6 +13758,7 @@ const SHARED_CONFIG_OWNERSHIP = {
|
|
|
13719
13758
|
"workflow_arpeggio",
|
|
13720
13759
|
"workflow_runtime_prepare",
|
|
13721
13760
|
"workflow_command_gates",
|
|
13761
|
+
"workflow_system_commands",
|
|
13722
13762
|
"sync_conflict_resolver",
|
|
13723
13763
|
"allow_git_hooks",
|
|
13724
13764
|
"allow_git_filters"
|
|
@@ -13860,6 +13900,7 @@ const SHARED_CONFIG_OWNERSHIP = {
|
|
|
13860
13900
|
"chat.tools.edits.autoApprove",
|
|
13861
13901
|
"chat.tools.urls.autoApprove",
|
|
13862
13902
|
"chat.permissions.default",
|
|
13903
|
+
"chat.defaultConfiguration",
|
|
13863
13904
|
"chat.agent.sandbox.enabled",
|
|
13864
13905
|
"chat.agent.sandbox.network.allowNetwork",
|
|
13865
13906
|
"chat.agent.sandbox.network.allowLocalNetwork",
|
|
@@ -34101,7 +34142,7 @@ function normalizeAugmentcodeToolList(value) {
|
|
|
34101
34142
|
return tools.length > 0 ? tools : void 0;
|
|
34102
34143
|
}
|
|
34103
34144
|
const AugmentcodeSubagentFrontmatterSchema = z.looseObject({
|
|
34104
|
-
name: z.string(),
|
|
34145
|
+
name: z.optional(z.string()),
|
|
34105
34146
|
description: z.optional(z.string()),
|
|
34106
34147
|
color: z.optional(z.string()),
|
|
34107
34148
|
model: z.optional(z.string()),
|
|
@@ -34160,7 +34201,7 @@ var AugmentcodeSubagent = class AugmentcodeSubagent extends ToolSubagent {
|
|
|
34160
34201
|
outputRoot: ".",
|
|
34161
34202
|
frontmatter: {
|
|
34162
34203
|
targets: ["*"],
|
|
34163
|
-
name,
|
|
34204
|
+
name: name ?? basename(this.getRelativeFilePath(), extname(this.getRelativeFilePath())),
|
|
34164
34205
|
description,
|
|
34165
34206
|
...Object.keys(augmentcodeSection).length > 0 && { augmentcode: augmentcodeSection }
|
|
34166
34207
|
},
|
|
@@ -34226,7 +34267,8 @@ var AugmentcodeSubagent = class AugmentcodeSubagent extends ToolSubagent {
|
|
|
34226
34267
|
const dirPath = relativeDirPath ?? this.getSettablePaths({ global }).relativeDirPath;
|
|
34227
34268
|
const filePath = join(outputRoot, dirPath, relativeFilePath);
|
|
34228
34269
|
const fileContent = await readFileContent(filePath);
|
|
34229
|
-
const { frontmatter, body: content } = parseFrontmatter(fileContent, filePath);
|
|
34270
|
+
const { frontmatter, body: content, hasFrontmatter } = parseFrontmatter(fileContent, filePath);
|
|
34271
|
+
if (!hasFrontmatter) throw new Error(`Missing frontmatter in ${filePath}`);
|
|
34230
34272
|
const result = AugmentcodeSubagentFrontmatterSchema.safeParse(frontmatter);
|
|
34231
34273
|
if (!result.success) throw new Error(`Invalid frontmatter in ${filePath}: ${formatError(result.error)}`);
|
|
34232
34274
|
return new AugmentcodeSubagent({
|
|
@@ -41809,7 +41851,23 @@ function sanitizeOpencodeMcpNamePart(value) {
|
|
|
41809
41851
|
* key that matches nothing.
|
|
41810
41852
|
*/
|
|
41811
41853
|
function opencodeMcpToolPermissionKey(serverName, toolName) {
|
|
41812
|
-
return `${
|
|
41854
|
+
return `${opencodeMcpServerKeyPrefix(serverName)}${toolName.replace(/[^a-zA-Z0-9_\-*?]/g, "_")}`;
|
|
41855
|
+
}
|
|
41856
|
+
/** The sanitized `<server>_` prefix every permission key of the server's tools starts with. */
|
|
41857
|
+
function opencodeMcpServerKeyPrefix(serverName) {
|
|
41858
|
+
return `${sanitizeOpencodeMcpNamePart(serverName)}_`;
|
|
41859
|
+
}
|
|
41860
|
+
/**
|
|
41861
|
+
* Whether `key` is exactly the sanitized `<server>_` prefix of one of
|
|
41862
|
+
* `serverNames` (e.g. `a_b_` for server `a.b` or `a_b`). No tool has an empty
|
|
41863
|
+
* name, so such a key filters nothing of that server, and
|
|
41864
|
+
* {@link findOpencodeMcpToolKeyOwner} gives it no owner. Read as an unlisted
|
|
41865
|
+
* server's filter instead, it would be split at the first `_` into a phantom
|
|
41866
|
+
* server (`a` with tool `b_`), so importers leave it out of the rulesync
|
|
41867
|
+
* config, and the OpenCode family's generate keeps it in the file as it was.
|
|
41868
|
+
*/
|
|
41869
|
+
function isBareOpencodeMcpServerPrefix({ key, serverNames }) {
|
|
41870
|
+
return serverNames.some((serverName) => key === opencodeMcpServerKeyPrefix(serverName));
|
|
41813
41871
|
}
|
|
41814
41872
|
/**
|
|
41815
41873
|
* The server among `serverNames` whose tool a permission key names, with the
|
|
@@ -41823,7 +41881,7 @@ function findOpencodeMcpToolKeyOwner({ key, serverNames, builtinKeys, acceptRawP
|
|
|
41823
41881
|
if (builtinKeys.has(key)) return;
|
|
41824
41882
|
let owner;
|
|
41825
41883
|
for (const serverName of serverNames) {
|
|
41826
|
-
const sanitized =
|
|
41884
|
+
const sanitized = opencodeMcpServerKeyPrefix(serverName);
|
|
41827
41885
|
const prefixes = acceptRawPrefix ? uniq([sanitized, `${serverName}_`]) : [sanitized];
|
|
41828
41886
|
for (const prefix of prefixes) if (key.length > prefix.length && key.startsWith(prefix) && (owner === void 0 || prefix.length > owner.prefix.length)) owner = {
|
|
41829
41887
|
serverName,
|
|
@@ -42284,7 +42342,10 @@ function convertFromKiloFormat(kiloMcp, tools, permission) {
|
|
|
42284
42342
|
const serverNames = Object.keys(kiloMcp);
|
|
42285
42343
|
return {
|
|
42286
42344
|
...Object.fromEntries(Object.entries(kiloMcp).map(([serverName, serverConfig]) => [serverName, kiloServerToRulesync(serverName, serverConfig, splitKiloServerTools(serverName, serverNames, filters))])),
|
|
42287
|
-
...orphanMcpToolFiltersToRulesync(kiloMcp, tools)
|
|
42345
|
+
...orphanMcpToolFiltersToRulesync(kiloMcp, Object.fromEntries(Object.entries(tools ?? {}).filter(([key]) => !findKiloMcpToolKeyOwner(key, serverNames) && !isBareOpencodeMcpServerPrefix({
|
|
42346
|
+
key,
|
|
42347
|
+
serverNames
|
|
42348
|
+
}))))
|
|
42288
42349
|
};
|
|
42289
42350
|
}
|
|
42290
42351
|
/**
|
|
@@ -42802,16 +42863,20 @@ function convertFromOpencodeFormat(opencodeMcp, tools, remoteType) {
|
|
|
42802
42863
|
...orphanMcpToolFiltersToRulesync(opencodeMcp, Object.fromEntries(Object.entries(tools ?? {}).filter(([key]) => !findOpencodeToolOwner({
|
|
42803
42864
|
key,
|
|
42804
42865
|
serverNames
|
|
42866
|
+
}) && !isBareOpencodeMcpServerPrefix({
|
|
42867
|
+
key,
|
|
42868
|
+
serverNames
|
|
42805
42869
|
})))),
|
|
42806
42870
|
...convertOpencodeServers(opencodeMcp, tools, remoteType)
|
|
42807
42871
|
};
|
|
42808
42872
|
}
|
|
42873
|
+
const OPENCODE_MCP_BUILTIN_TOOL_KEYS = /* @__PURE__ */ new Set();
|
|
42809
42874
|
/** Recognize both OpenCode's sanitized names and keys older rulesync versions wrote. */
|
|
42810
42875
|
function findOpencodeToolOwner({ key, serverNames }) {
|
|
42811
42876
|
return findOpencodeMcpToolKeyOwner({
|
|
42812
42877
|
key,
|
|
42813
42878
|
serverNames,
|
|
42814
|
-
builtinKeys:
|
|
42879
|
+
builtinKeys: OPENCODE_MCP_BUILTIN_TOOL_KEYS,
|
|
42815
42880
|
acceptRawPrefix: true
|
|
42816
42881
|
});
|
|
42817
42882
|
}
|
|
@@ -42981,6 +43046,40 @@ function convertToOpencodeFormat(mcpServers, existingMcp, configShape, logger) {
|
|
|
42981
43046
|
tools
|
|
42982
43047
|
};
|
|
42983
43048
|
}
|
|
43049
|
+
/**
|
|
43050
|
+
* Copy each key of `existingTools` that is a bare sanitized `<server>_` prefix
|
|
43051
|
+
* of one of `serverNames` into `tools`, unless a generated filter already
|
|
43052
|
+
* writes the same key or another listed server owns it (`a_b_` is tool `b_` of
|
|
43053
|
+
* server `a` when `a` is listed too). An owned key is the rulesync config's to
|
|
43054
|
+
* write, so carrying it over would keep a filter the user removed. Mutates
|
|
43055
|
+
* `tools` in place.
|
|
43056
|
+
*/
|
|
43057
|
+
function preserveBareOpencodeMcpServerPrefixKeys({ tools, existingTools, serverNames }) {
|
|
43058
|
+
for (const [key, enabled] of Object.entries(existingTools ?? {})) if (!Object.hasOwn(tools, key) && isBareOpencodeMcpServerPrefix({
|
|
43059
|
+
key,
|
|
43060
|
+
serverNames
|
|
43061
|
+
}) && !findOpencodeToolOwner({
|
|
43062
|
+
key,
|
|
43063
|
+
serverNames
|
|
43064
|
+
})) tools[key] = enabled;
|
|
43065
|
+
}
|
|
43066
|
+
/**
|
|
43067
|
+
* When the existing file does not pass the schema, its `tools` map cannot be
|
|
43068
|
+
* read, so a bare `<server>_` key in it is not carried over. Say so rather
|
|
43069
|
+
* than lift the deny it may hold without a word.
|
|
43070
|
+
*/
|
|
43071
|
+
function warnAboutUnreadableBareOpencodeMcpServerPrefixKeys({ existingJson, serverNames, logger }) {
|
|
43072
|
+
const rawTools = isRecord(existingJson) ? existingJson.tools : void 0;
|
|
43073
|
+
if (!isRecord(rawTools)) return;
|
|
43074
|
+
const bareKeys = Object.keys(rawTools).filter((key) => isBareOpencodeMcpServerPrefix({
|
|
43075
|
+
key,
|
|
43076
|
+
serverNames
|
|
43077
|
+
}) && !findOpencodeToolOwner({
|
|
43078
|
+
key,
|
|
43079
|
+
serverNames
|
|
43080
|
+
}));
|
|
43081
|
+
if (bareKeys.length > 0) logger?.warn(`OpenCode MCP: the existing config does not match the expected schema, so the bare server-prefix tool ${bareKeys.length === 1 ? "key" : "keys"} ${bareKeys.map(quoteValueForWarning).join(", ")} ${bareKeys.length === 1 ? "is" : "are"} not kept in "tools".`);
|
|
43082
|
+
}
|
|
42984
43083
|
const OpencodeMcpFeatureOptionsSchema = z.looseObject({ configShape: z.optional(z.enum(["v1", "v2"])) });
|
|
42985
43084
|
var OpencodeMcp = class extends ToolMcp {
|
|
42986
43085
|
/** Directory layout; OpenCode forks (MiMo Code) override it. */
|
|
@@ -43113,6 +43212,16 @@ var OpencodeMcp = class extends ToolMcp {
|
|
|
43113
43212
|
convertedMcp,
|
|
43114
43213
|
mcpServers: transformedServers
|
|
43115
43214
|
});
|
|
43215
|
+
if (existingMcp.success) preserveBareOpencodeMcpServerPrefixKeys({
|
|
43216
|
+
tools: mcpTools,
|
|
43217
|
+
existingTools: existingMcp.data.tools,
|
|
43218
|
+
serverNames: Object.keys(transformedServers)
|
|
43219
|
+
});
|
|
43220
|
+
else warnAboutUnreadableBareOpencodeMcpServerPrefixKeys({
|
|
43221
|
+
existingJson: this.lowerConfig(existingJson),
|
|
43222
|
+
serverNames: Object.keys(transformedServers),
|
|
43223
|
+
logger
|
|
43224
|
+
});
|
|
43116
43225
|
if (this.layout.configVersion === "v2") warnAboutOpencodeV2SseServers({
|
|
43117
43226
|
mcpServers: transformedServers,
|
|
43118
43227
|
convertedMcp,
|
|
@@ -51667,6 +51776,7 @@ var RulesProcessor = class extends FeatureProcessor {
|
|
|
51667
51776
|
factory
|
|
51668
51777
|
});
|
|
51669
51778
|
await this.warnForWarpLegacyRootFile(toolRules);
|
|
51779
|
+
this.warnForAugmentcodePluginRules(toolRules);
|
|
51670
51780
|
await this.warnForInstructionBudget({
|
|
51671
51781
|
toolRules,
|
|
51672
51782
|
meta
|
|
@@ -52058,6 +52168,20 @@ var RulesProcessor = class extends FeatureProcessor {
|
|
|
52058
52168
|
this.logger.warn(`Writing ${stripControlCharacters(rootFileRelativePath)} for ${this.toolTarget} means ${listedNames.join(", ")}${remainingCount > 0 ? ` and ${remainingCount} more` : ""} will no longer be read. Run \`rulesync import --targets ${this.toolTarget}\` first to carry that content into ${RULESYNC_RULES_RELATIVE_DIR_PATH}, or delete ${listedNames.length === 1 ? "it" : "them"} once you have checked the content is already in the root file.`);
|
|
52059
52169
|
}
|
|
52060
52170
|
/**
|
|
52171
|
+
* Auggie 1.x (still a prerelease on npm at the time of writing; the stable
|
|
52172
|
+
* line is 0.36.0) no longer loads `rules/` from plugins: "Rules shipped in
|
|
52173
|
+
* plugins (`rules/` in a plugin)" is listed among the removed features, while
|
|
52174
|
+
* commands, agents, skills, hooks and MCP servers still load. The rule files
|
|
52175
|
+
* are still written, because the stable 0.x CLI reads them, but under 1.x the
|
|
52176
|
+
* bundle silently loses them, so say so.
|
|
52177
|
+
* @see https://docs.augmentcode.com/cli/whats-new
|
|
52178
|
+
* @see https://docs.augmentcode.com/cli/v0/plugins
|
|
52179
|
+
*/
|
|
52180
|
+
warnForAugmentcodePluginRules(toolRules) {
|
|
52181
|
+
if (this.toolTarget !== "augmentcode-plugin" || toolRules.length === 0) return;
|
|
52182
|
+
this.logger.warn(`augmentcode-plugin: plugin rules (rules/*.md) are loaded by Auggie 0.x only; Auggie 1.x no longer reads rules/ from plugins, so these ${toolRules.length} rule file(s) have no effect there. Ship instructions that must reach Auggie 1.x users as a skill, or have them generate the augmentcode target in their project.`);
|
|
52183
|
+
}
|
|
52184
|
+
/**
|
|
52061
52185
|
* Warp still reads a legacy `WARP.md`, and when both `WARP.md` and
|
|
52062
52186
|
* `AGENTS.md` sit in the same directory, `WARP.md` takes priority — so an
|
|
52063
52187
|
* `AGENTS.md` this run writes next to one would never be read. That holds for
|
|
@@ -82300,6 +82424,57 @@ function matchesGlobStep(step, character) {
|
|
|
82300
82424
|
const admitted = step.members.has(character) || step.ranges.some(([low, high]) => code >= low && code <= high);
|
|
82301
82425
|
return step.negated ? !admitted : admitted;
|
|
82302
82426
|
}
|
|
82427
|
+
/**
|
|
82428
|
+
* Whether `value` matches `glob` in full, with `*`, `?` and `[...]` carrying
|
|
82429
|
+
* their usual meaning. The glob comes first, unlike Node's own
|
|
82430
|
+
* `path.matchesGlob(path, pattern)`.
|
|
82431
|
+
*
|
|
82432
|
+
* The glob is walked step by step rather than translated to a regex, because
|
|
82433
|
+
* both sides of a comparison can come from a file a repository carries: `*a*a*a*a*b`
|
|
82434
|
+
* translated to `^.*a.*a.*a.*a.*b$` takes minutes against a forty-character
|
|
82435
|
+
* name, while walking the steps is linear in the name per `*`. Remembering only
|
|
82436
|
+
* the most recent `*` to fall back to is enough — an earlier one can always give
|
|
82437
|
+
* up whatever the later one needed.
|
|
82438
|
+
*/
|
|
82439
|
+
function matchesGlob(glob, value) {
|
|
82440
|
+
return compileGlob(glob)(value);
|
|
82441
|
+
}
|
|
82442
|
+
/**
|
|
82443
|
+
* Parse `glob` once and return a predicate that walks it, for a caller that
|
|
82444
|
+
* tests the same glob against a whole list of names.
|
|
82445
|
+
*/
|
|
82446
|
+
function compileGlob(glob) {
|
|
82447
|
+
const steps = parseGlob(glob);
|
|
82448
|
+
return (value) => matchesParsedGlob(steps, value);
|
|
82449
|
+
}
|
|
82450
|
+
function matchesParsedGlob(steps, value) {
|
|
82451
|
+
const characters = [...value];
|
|
82452
|
+
let stepIndex = 0;
|
|
82453
|
+
let characterIndex = 0;
|
|
82454
|
+
let starStepIndex = -1;
|
|
82455
|
+
let starCharacterIndex = 0;
|
|
82456
|
+
while (characterIndex < characters.length) {
|
|
82457
|
+
const step = steps[stepIndex];
|
|
82458
|
+
if (step?.kind === "star") {
|
|
82459
|
+
starStepIndex = stepIndex;
|
|
82460
|
+
starCharacterIndex = characterIndex;
|
|
82461
|
+
stepIndex += 1;
|
|
82462
|
+
continue;
|
|
82463
|
+
}
|
|
82464
|
+
if (step !== void 0 && matchesGlobStep(step, characters[characterIndex] ?? "")) {
|
|
82465
|
+
stepIndex += 1;
|
|
82466
|
+
characterIndex += 1;
|
|
82467
|
+
continue;
|
|
82468
|
+
}
|
|
82469
|
+
if (starStepIndex < 0) return false;
|
|
82470
|
+
starCharacterIndex += 1;
|
|
82471
|
+
stepIndex = starStepIndex + 1;
|
|
82472
|
+
characterIndex = starCharacterIndex;
|
|
82473
|
+
}
|
|
82474
|
+
let remaining = stepIndex;
|
|
82475
|
+
while (steps[remaining]?.kind === "star") remaining += 1;
|
|
82476
|
+
return remaining === steps.length;
|
|
82477
|
+
}
|
|
82303
82478
|
/** Whether two single-character steps can both match one same character. */
|
|
82304
82479
|
function stepsShareACharacter(left, right) {
|
|
82305
82480
|
if (left.kind === "any" || right.kind === "any") return true;
|
|
@@ -83836,9 +84011,13 @@ const CANONICAL_TO_AUGMENT_TOOL_NAMES = {
|
|
|
83836
84011
|
const AUGMENT_TO_CANONICAL_TOOL_NAMES = Object.fromEntries(Object.entries(CANONICAL_TO_AUGMENT_TOOL_NAMES).map(([k, v]) => [v, k]));
|
|
83837
84012
|
const CURRENT_TO_LEGACY_AUGMENT_TOOL_NAMES = {
|
|
83838
84013
|
terminal: "launch-process",
|
|
84014
|
+
bash: "launch-process",
|
|
84015
|
+
shell: "launch-process",
|
|
83839
84016
|
read: "view",
|
|
83840
84017
|
edit: "str-replace-editor",
|
|
83841
|
-
|
|
84018
|
+
str_replace_editor: "str-replace-editor",
|
|
84019
|
+
write: "save-file",
|
|
84020
|
+
save_file: "save-file"
|
|
83842
84021
|
};
|
|
83843
84022
|
function toAugmentToolName(canonical) {
|
|
83844
84023
|
return lookupOwn({
|
|
@@ -83990,6 +84169,7 @@ function isShellRegexRoundtrippable(regex) {
|
|
|
83990
84169
|
while (i < body.length) {
|
|
83991
84170
|
const ch = body[i];
|
|
83992
84171
|
if (ch === "\\" && i + 1 < body.length) {
|
|
84172
|
+
if (isGlobSpecial(body[i + 1])) return false;
|
|
83993
84173
|
i += 2;
|
|
83994
84174
|
continue;
|
|
83995
84175
|
}
|
|
@@ -84006,6 +84186,37 @@ function isShellRegexRoundtrippable(regex) {
|
|
|
84006
84186
|
}
|
|
84007
84187
|
return true;
|
|
84008
84188
|
}
|
|
84189
|
+
/** Characters a glob reads as syntax (wildcards or the start of a character class). */
|
|
84190
|
+
function isGlobSpecial(ch) {
|
|
84191
|
+
return ch === "*" || ch === "?" || ch === "[";
|
|
84192
|
+
}
|
|
84193
|
+
/**
|
|
84194
|
+
* Whether `shellRegexToGlob` can approximate a `shellInputRegex` without widening it. The lossy
|
|
84195
|
+
* conversion keeps regex quantifiers as characters, and a `*` or `?` left in the glob becomes a
|
|
84196
|
+
* wildcard: `^rm -rf /tmp/a*$` (a run of `a`s) would turn into the glob `rm -rf /tmp/a*`, which
|
|
84197
|
+
* matches `rm -rf /tmp/a /home`. So a regex is unsafe when it has an escaped literal `\*` / `\?` /
|
|
84198
|
+
* `\[` (a `[` would open a character class in targets whose globs support one),
|
|
84199
|
+
* or a bare quantifier `*` / `?` / `+` / `{` that is not part of a `.*` run (which the glob `*`
|
|
84200
|
+
* reproduces faithfully).
|
|
84201
|
+
*/
|
|
84202
|
+
function canApproximateShellRegexWithoutWidening(regex) {
|
|
84203
|
+
let i = 0;
|
|
84204
|
+
while (i < regex.length) {
|
|
84205
|
+
const ch = regex[i];
|
|
84206
|
+
if (ch === "\\" && i + 1 < regex.length) {
|
|
84207
|
+
if (isGlobSpecial(regex[i + 1])) return false;
|
|
84208
|
+
i += 2;
|
|
84209
|
+
continue;
|
|
84210
|
+
}
|
|
84211
|
+
if (ch === "." && regex[i + 1] === "*") {
|
|
84212
|
+
i += 2;
|
|
84213
|
+
continue;
|
|
84214
|
+
}
|
|
84215
|
+
if (ch === "*" || ch === "?" || ch === "+" || ch === "{") return false;
|
|
84216
|
+
i += 1;
|
|
84217
|
+
}
|
|
84218
|
+
return true;
|
|
84219
|
+
}
|
|
84009
84220
|
const MANAGED_AUGMENT_TOOL_NAMES = new Set(Object.values(CANONICAL_TO_AUGMENT_TOOL_NAMES));
|
|
84010
84221
|
var AugmentcodePermissions = class AugmentcodePermissions extends ToolPermissions {
|
|
84011
84222
|
constructor(params) {
|
|
@@ -84442,12 +84653,18 @@ function convertAugmentToRulesyncPermissions({ entries, logger }) {
|
|
|
84442
84653
|
if (legacyToolName === "launch-process" && entry.shellInputRegex) {
|
|
84443
84654
|
const regex = entry.shellInputRegex;
|
|
84444
84655
|
if (isShellRegexRoundtrippable(regex)) pattern = shellRegexToGlob(regex);
|
|
84445
|
-
else
|
|
84446
|
-
|
|
84447
|
-
|
|
84448
|
-
|
|
84449
|
-
|
|
84450
|
-
|
|
84656
|
+
else {
|
|
84657
|
+
if (action !== "deny" && !canApproximateShellRegexWithoutWidening(regex)) {
|
|
84658
|
+
logger?.warn(`AugmentCode permissions: skipping ${action} entry for tool '${entry.toolName}': shellInputRegex '${regex}' uses a quantifier or a literal '*' / '?' that a glob cannot express, and converting it would widen the rule. The entry is not imported.`);
|
|
84659
|
+
continue;
|
|
84660
|
+
}
|
|
84661
|
+
if (action === "deny") {
|
|
84662
|
+
logger?.warn(`AugmentCode permissions: shellInputRegex '${regex}' on tool '${entry.toolName}' is not faithfully roundtrippable to a glob. Importing as the catch-all '*' pattern (fail-closed) so the deny rule cannot be silently narrowed on regenerate.`);
|
|
84663
|
+
pattern = "*";
|
|
84664
|
+
} else {
|
|
84665
|
+
pattern = shellRegexToGlob(regex);
|
|
84666
|
+
logger?.warn(`AugmentCode permissions: shellInputRegex '${regex}' on tool '${entry.toolName}' is not faithfully roundtrippable to a glob. Importing as glob '${pattern}'; the rule may match a different set of inputs after regenerate.`);
|
|
84667
|
+
}
|
|
84451
84668
|
}
|
|
84452
84669
|
} else pattern = "*";
|
|
84453
84670
|
if (isPrototypePollutionKey(pattern)) {
|
|
@@ -85940,15 +86157,19 @@ const CLAUDECODE_ENV_IGNORED_IN_EVERY_FILE = /* @__PURE__ */ new Set([
|
|
|
85940
86157
|
* `env` variables a project or local settings file cannot set, because a
|
|
85941
86158
|
* checked-out repository should not control them: where Claude Code stores its
|
|
85942
86159
|
* own files, what session content it exports, where telemetry goes, how it
|
|
85943
|
-
* starts or syncs, the timers on an unanswered
|
|
85944
|
-
*
|
|
86160
|
+
* starts or syncs, which claude.ai sign-in it uses, the timers on an unanswered
|
|
86161
|
+
* dialog, and whether it processes attachments or expands `@` file mentions,
|
|
86162
|
+
* and the screen reader (`CLAUDE_AX_*`) variables. Claude Code drops them there, so they are skipped at project scope and emitted only under `--global`.
|
|
85945
86163
|
*
|
|
85946
|
-
* Only the names the settings reference lists are covered; its directory
|
|
85947
|
-
* Windows groups are introduced with "such as", so an unlisted member of those
|
|
86164
|
+
* Only the names the settings reference lists are covered; its directory,
|
|
86165
|
+
* Windows and sign-in groups are introduced with "such as", so an unlisted member of those
|
|
85948
86166
|
* families is still written. Windows variable names are case-insensitive, so
|
|
85949
|
-
* that group is matched without regard to case.
|
|
86167
|
+
* that group is matched without regard to case. `ALLUSERSPROFILE`,
|
|
86168
|
+
* `SystemDrive` and the `CommonProgramFiles` family are ignored there since
|
|
86169
|
+
* Claude Code v2.1.285.
|
|
85950
86170
|
*
|
|
85951
86171
|
* @see https://code.claude.com/docs/en/settings-reference#variables-claude-code-ignores-in-env
|
|
86172
|
+
* @see https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md
|
|
85952
86173
|
*/
|
|
85953
86174
|
const CLAUDECODE_ENV_PROJECT_IGNORED_NAMES = /* @__PURE__ */ new Set([
|
|
85954
86175
|
"BETA_TRACING_ENDPOINT",
|
|
@@ -85958,6 +86179,9 @@ const CLAUDECODE_ENV_PROJECT_IGNORED_NAMES = /* @__PURE__ */ new Set([
|
|
|
85958
86179
|
"CLAUDE_CODE_DISABLE_FILE_MENTIONS",
|
|
85959
86180
|
"CLAUDE_CODE_ENABLE_TELEMETRY",
|
|
85960
86181
|
"CLAUDE_CODE_ENHANCED_TELEMETRY_BETA",
|
|
86182
|
+
"CLAUDE_CODE_OAUTH_REFRESH_TOKEN",
|
|
86183
|
+
"CLAUDE_CODE_OAUTH_SCOPES",
|
|
86184
|
+
"CLAUDE_CODE_OAUTH_TOKEN",
|
|
85961
86185
|
"CLAUDE_CODE_PLUGIN_CACHE_DIR",
|
|
85962
86186
|
"CLAUDE_CODE_PLUGIN_SEED_DIR",
|
|
85963
86187
|
"CLAUDE_CODE_PROCESS_WRAPPER",
|
|
@@ -85978,14 +86202,23 @@ const CLAUDECODE_ENV_PROJECT_IGNORED_NAMES = /* @__PURE__ */ new Set([
|
|
|
85978
86202
|
"TMPDIR"
|
|
85979
86203
|
]);
|
|
85980
86204
|
const CLAUDECODE_ENV_PROJECT_IGNORED_WINDOWS_NAMES = /* @__PURE__ */ new Set([
|
|
86205
|
+
"ALLUSERSPROFILE",
|
|
86206
|
+
"COMMONPROGRAMW6432",
|
|
85981
86207
|
"COMSPEC",
|
|
85982
86208
|
"LOCALAPPDATA",
|
|
85983
86209
|
"PATHEXT",
|
|
85984
86210
|
"PROGRAMDATA",
|
|
85985
86211
|
"PROGRAMW6432",
|
|
85986
86212
|
"PSMODULEPATH",
|
|
86213
|
+
"SYSTEMDRIVE",
|
|
85987
86214
|
"SYSTEMROOT"
|
|
85988
86215
|
]);
|
|
86216
|
+
/**
|
|
86217
|
+
* Windows name prefixes matched as whole families: `ProgramFiles*` and
|
|
86218
|
+
* `CommonProgramFiles*`. `ProgramW6432` and `CommonProgramW6432` are exact
|
|
86219
|
+
* names in the set above.
|
|
86220
|
+
*/
|
|
86221
|
+
const CLAUDECODE_ENV_PROJECT_IGNORED_WINDOWS_PREFIXES = ["PROGRAMFILES", "COMMONPROGRAMFILES"];
|
|
85989
86222
|
const CLAUDECODE_ENV_OTLP_IGNORED_SUFFIXES = [
|
|
85990
86223
|
"_ENDPOINT",
|
|
85991
86224
|
"_HEADERS",
|
|
@@ -86030,7 +86263,7 @@ const CLAUDECODE_ENV_PROJECT_HONORED_OFF_VALUES = {
|
|
|
86030
86263
|
function isProjectIgnoredEnvVariable(name, value) {
|
|
86031
86264
|
if (CLAUDECODE_ENV_PROJECT_IGNORED_NAMES.has(name) || name.startsWith("XDG_") || name.startsWith("CLAUDE_AX_")) return true;
|
|
86032
86265
|
const upper = name.toUpperCase();
|
|
86033
|
-
if (CLAUDECODE_ENV_PROJECT_IGNORED_WINDOWS_NAMES.has(upper) || upper.startsWith(
|
|
86266
|
+
if (CLAUDECODE_ENV_PROJECT_IGNORED_WINDOWS_NAMES.has(upper) || CLAUDECODE_ENV_PROJECT_IGNORED_WINDOWS_PREFIXES.some((prefix) => upper.startsWith(prefix))) return true;
|
|
86034
86267
|
if (name.startsWith("OTEL_EXPORTER_OTLP_") && CLAUDECODE_ENV_OTLP_IGNORED_SUFFIXES.some((suffix) => name.endsWith(suffix))) return true;
|
|
86035
86268
|
if (Object.hasOwn(CLAUDECODE_ENV_PROJECT_HONORED_OFF_VALUES, name)) {
|
|
86036
86269
|
const offValues = CLAUDECODE_ENV_PROJECT_HONORED_OFF_VALUES[name];
|
|
@@ -86062,7 +86295,7 @@ function stripIgnoredEnvVariables({ env, global, relativeFilePath, logger }) {
|
|
|
86062
86295
|
kept[name] = value;
|
|
86063
86296
|
}
|
|
86064
86297
|
if (ignoredEverywhere.length > 0) logger?.warn(`Claude Code permissions: Claude Code ignores ${ignoredEverywhere.map((name) => `'env.${name}'`).join(", ")} in every settings file, so ${ignoredEverywhere.length === 1 ? "it is" : "they are"} not written to ${relativeFilePath}. Set ${ignoredEverywhere.length === 1 ? "it" : "them"} in the environment Claude Code starts from instead, and check ${relativeFilePath} for a stale value an earlier generate may have left there.`);
|
|
86065
|
-
if (ignoredAtProjectScope.length > 0) logger?.warn(`Claude Code permissions: ${ignoredAtProjectScope.map((name) => `'env.${name}'`).join(", ")} ${ignoredAtProjectScope.length === 1 ? "is" : "are"} not honored in the project-scoped ${relativeFilePath}, so ${ignoredAtProjectScope.length === 1 ? "it is" : "they are"} not written there — Claude Code ignores variables there that choose where it writes its files, export session content or telemetry, change how it starts or syncs, set dialog timers, turn attachments or file mentions off, or turn Claude in Chrome on (a value that turns telemetry or Chrome off, such as "none" or "0", is still written). Author ${ignoredAtProjectScope.length === 1 ? "it" : "them"} in the global scope instead, and check that file for a stale value an earlier generate may have left there.`);
|
|
86298
|
+
if (ignoredAtProjectScope.length > 0) logger?.warn(`Claude Code permissions: ${ignoredAtProjectScope.map((name) => `'env.${name}'`).join(", ")} ${ignoredAtProjectScope.length === 1 ? "is" : "are"} not honored in the project-scoped ${relativeFilePath}, so ${ignoredAtProjectScope.length === 1 ? "it is" : "they are"} not written there — Claude Code ignores variables there that choose where it writes its files, export session content or telemetry, change how it starts or syncs, set the claude.ai sign-in, set dialog timers, turn attachments or file mentions off, or turn Claude in Chrome on (a value that turns telemetry or Chrome off, such as "none" or "0", is still written). Author ${ignoredAtProjectScope.length === 1 ? "it" : "them"} in the global scope instead, and check that file for a stale value an earlier generate may have left there.`);
|
|
86066
86299
|
return kept;
|
|
86067
86300
|
}
|
|
86068
86301
|
/**
|
|
@@ -86712,7 +86945,7 @@ const CODEBUDDY_RULE_LISTS = [
|
|
|
86712
86945
|
"ask",
|
|
86713
86946
|
"deny"
|
|
86714
86947
|
];
|
|
86715
|
-
const CATCH_ALL_PATTERN$
|
|
86948
|
+
const CATCH_ALL_PATTERN$14 = "*";
|
|
86716
86949
|
const MCP_CATEGORY = "mcp";
|
|
86717
86950
|
const MCP_RULE_PREFIX = "mcp__";
|
|
86718
86951
|
const ALL_MCP_RULE = "mcp__*";
|
|
@@ -86782,7 +87015,7 @@ function categoryOfRule$2(rule) {
|
|
|
86782
87015
|
* and reach the `Bash` rules through `honorAllToolsOnBash`.
|
|
86783
87016
|
*/
|
|
86784
87017
|
function buildCodebuddyRule({ category, pattern, action, logger }) {
|
|
86785
|
-
const catchAll = pattern === CATCH_ALL_PATTERN$
|
|
87018
|
+
const catchAll = pattern === CATCH_ALL_PATTERN$14;
|
|
86786
87019
|
if (category === MCP_CATEGORY) {
|
|
86787
87020
|
if (catchAll && action === "allow") {
|
|
86788
87021
|
logger?.warn(`CodeBuddy permissions: skipping the 'mcp' allow rule '*' — CodeBuddy honors the all-MCP wildcard 'mcp__*' in deny and ask only. Allow servers by name instead (for example 'mcp__github').`);
|
|
@@ -86791,7 +87024,7 @@ function buildCodebuddyRule({ category, pattern, action, logger }) {
|
|
|
86791
87024
|
return catchAll ? ALL_MCP_RULE : `${MCP_RULE_PREFIX}${pattern}`;
|
|
86792
87025
|
}
|
|
86793
87026
|
if (category === "*") {
|
|
86794
|
-
if (catchAll) return CATCH_ALL_PATTERN$
|
|
87027
|
+
if (catchAll) return CATCH_ALL_PATTERN$14;
|
|
86795
87028
|
logger?.warn(`CodeBuddy permissions: skipping the all-tools '*' rule '${pattern}' — CodeBuddy's standalone '*' rule takes no specifier. Write it under the category it is meant for (for example 'bash' or 'read').`);
|
|
86796
87029
|
return null;
|
|
86797
87030
|
}
|
|
@@ -86809,7 +87042,7 @@ function parseCodebuddyRule(rule) {
|
|
|
86809
87042
|
const { specifier } = splitCodebuddyRule(rule);
|
|
86810
87043
|
if (specifier === void 0) return {
|
|
86811
87044
|
category,
|
|
86812
|
-
pattern: CATCH_ALL_PATTERN$
|
|
87045
|
+
pattern: CATCH_ALL_PATTERN$14
|
|
86813
87046
|
};
|
|
86814
87047
|
const trimmed = specifier.trim();
|
|
86815
87048
|
return trimmed === "" ? null : {
|
|
@@ -89135,8 +89368,8 @@ function mapBashActionToDecision(action) {
|
|
|
89135
89368
|
// src/features/permissions/commandcode-permissions.ts
|
|
89136
89369
|
/** Top-level key of `.commandcode/settings.json` that rulesync owns. */
|
|
89137
89370
|
const COMMANDCODE_PERMISSIONS_KEY = "permissions";
|
|
89138
|
-
const CATCH_ALL_PATTERN$
|
|
89139
|
-
const MCP_CANONICAL_PREFIX$
|
|
89371
|
+
const CATCH_ALL_PATTERN$13 = "*";
|
|
89372
|
+
const MCP_CANONICAL_PREFIX$8 = "mcp__";
|
|
89140
89373
|
const COMMANDCODE_ALL_MCP_RULE = "mcp__*";
|
|
89141
89374
|
const CATEGORY_TO_COMMANDCODE_TOOL = {
|
|
89142
89375
|
bash: "Shell",
|
|
@@ -89181,10 +89414,10 @@ const PADDED_SHELL_WILDCARD_REASON = "a pattern narrower than the bare 'Shell' (
|
|
|
89181
89414
|
* restrictions and reach the `Shell` entries through `honorAllToolsOnBash`.
|
|
89182
89415
|
*/
|
|
89183
89416
|
function buildCommandcodeRule(category, pattern) {
|
|
89184
|
-
const catchAll = pattern === CATCH_ALL_PATTERN$
|
|
89185
|
-
if (category.startsWith(MCP_CANONICAL_PREFIX$
|
|
89186
|
-
if (category === "mcp") return catchAll ? COMMANDCODE_ALL_MCP_RULE : `${MCP_CANONICAL_PREFIX$
|
|
89187
|
-
if (category === "*") return catchAll ? CATCH_ALL_PATTERN$
|
|
89417
|
+
const catchAll = pattern === CATCH_ALL_PATTERN$13 || pattern === "";
|
|
89418
|
+
if (category.startsWith(MCP_CANONICAL_PREFIX$8)) return catchAll ? category : `${category}(${pattern})`;
|
|
89419
|
+
if (category === "mcp") return catchAll ? COMMANDCODE_ALL_MCP_RULE : `${MCP_CANONICAL_PREFIX$8}${pattern}`;
|
|
89420
|
+
if (category === "*") return catchAll ? CATCH_ALL_PATTERN$13 : null;
|
|
89188
89421
|
const tool = Object.hasOwn(CATEGORY_TO_COMMANDCODE_TOOL, category) ? CATEGORY_TO_COMMANDCODE_TOOL[category] : void 0;
|
|
89189
89422
|
if (tool === void 0) return null;
|
|
89190
89423
|
return catchAll ? tool : `${tool}(${pattern})`;
|
|
@@ -89220,7 +89453,7 @@ function splitCommandcodeRule(rule) {
|
|
|
89220
89453
|
}
|
|
89221
89454
|
/** Whether a specifier means "no specifier" to Command Code: only `` and `*` do. */
|
|
89222
89455
|
function isCatchAllSpecifier(inner) {
|
|
89223
|
-
return inner === "" || inner === CATCH_ALL_PATTERN$
|
|
89456
|
+
return inner === "" || inner === CATCH_ALL_PATTERN$13;
|
|
89224
89457
|
}
|
|
89225
89458
|
/**
|
|
89226
89459
|
* Read an MCP-shaped rule the way Command Code does (`command-code` 1.54.0,
|
|
@@ -89254,34 +89487,34 @@ function parseMcpCommandcodeRule({ tool, inner }) {
|
|
|
89254
89487
|
if (server.length === 0) return null;
|
|
89255
89488
|
const everyServer = {
|
|
89256
89489
|
category: "mcp",
|
|
89257
|
-
pattern: CATCH_ALL_PATTERN$
|
|
89490
|
+
pattern: CATCH_ALL_PATTERN$13,
|
|
89258
89491
|
notInAllow: true
|
|
89259
89492
|
};
|
|
89260
|
-
if (tool.startsWith(MCP_CANONICAL_PREFIX$
|
|
89261
|
-
if (server === CATCH_ALL_PATTERN$
|
|
89262
|
-
if (server.includes(CATCH_ALL_PATTERN$
|
|
89493
|
+
if (tool.startsWith(MCP_CANONICAL_PREFIX$8)) {
|
|
89494
|
+
if (server === CATCH_ALL_PATTERN$13) return everyServer;
|
|
89495
|
+
if (server.includes(CATCH_ALL_PATTERN$13)) return null;
|
|
89263
89496
|
return {
|
|
89264
|
-
category: rest === "" || rest === CATCH_ALL_PATTERN$
|
|
89265
|
-
pattern: CATCH_ALL_PATTERN$
|
|
89497
|
+
category: rest === "" || rest === CATCH_ALL_PATTERN$13 ? `${MCP_CANONICAL_PREFIX$8}${server}` : `${MCP_CANONICAL_PREFIX$8}${remainder}`,
|
|
89498
|
+
pattern: CATCH_ALL_PATTERN$13,
|
|
89266
89499
|
notInAllow: false
|
|
89267
89500
|
};
|
|
89268
89501
|
}
|
|
89269
|
-
const category = `${MCP_CANONICAL_PREFIX$
|
|
89270
|
-
const namesTool = separator !== -1 && rest.length > 0 && !remainder.includes(CATCH_ALL_PATTERN$
|
|
89502
|
+
const category = `${MCP_CANONICAL_PREFIX$8}${remainder}`;
|
|
89503
|
+
const namesTool = separator !== -1 && rest.length > 0 && !remainder.includes(CATCH_ALL_PATTERN$13);
|
|
89271
89504
|
if (!isCatchAllSpecifier(inner)) return namesTool ? {
|
|
89272
89505
|
category,
|
|
89273
89506
|
pattern: inner,
|
|
89274
89507
|
notInAllow: true
|
|
89275
89508
|
} : null;
|
|
89276
|
-
if (remainder === CATCH_ALL_PATTERN$
|
|
89277
|
-
if (rest === CATCH_ALL_PATTERN$
|
|
89278
|
-
category: `${MCP_CANONICAL_PREFIX$
|
|
89279
|
-
pattern: CATCH_ALL_PATTERN$
|
|
89509
|
+
if (remainder === CATCH_ALL_PATTERN$13) return everyServer;
|
|
89510
|
+
if (rest === CATCH_ALL_PATTERN$13 && !server.includes(CATCH_ALL_PATTERN$13)) return {
|
|
89511
|
+
category: `${MCP_CANONICAL_PREFIX$8}${server}`,
|
|
89512
|
+
pattern: CATCH_ALL_PATTERN$13,
|
|
89280
89513
|
notInAllow: true
|
|
89281
89514
|
};
|
|
89282
89515
|
return namesTool ? {
|
|
89283
89516
|
category,
|
|
89284
|
-
pattern: CATCH_ALL_PATTERN$
|
|
89517
|
+
pattern: CATCH_ALL_PATTERN$13,
|
|
89285
89518
|
notInAllow: false
|
|
89286
89519
|
} : null;
|
|
89287
89520
|
}
|
|
@@ -89305,14 +89538,14 @@ function friendlyToolRule({ category, inner }) {
|
|
|
89305
89538
|
if (category === "bash") {
|
|
89306
89539
|
if (isCatchAllSpecifier(inner)) return {
|
|
89307
89540
|
category,
|
|
89308
|
-
pattern: CATCH_ALL_PATTERN$
|
|
89541
|
+
pattern: CATCH_ALL_PATTERN$13,
|
|
89309
89542
|
notInAllow: false
|
|
89310
89543
|
};
|
|
89311
89544
|
const normalized = inner.trim().replace(/\s+/g, " ");
|
|
89312
89545
|
if (normalized === "" || normalized === ":*") return null;
|
|
89313
89546
|
return isCatchAllSpecifier(normalized) ? {
|
|
89314
89547
|
category,
|
|
89315
|
-
pattern: CATCH_ALL_PATTERN$
|
|
89548
|
+
pattern: CATCH_ALL_PATTERN$13,
|
|
89316
89549
|
notInAllow: true
|
|
89317
89550
|
} : {
|
|
89318
89551
|
category,
|
|
@@ -89322,7 +89555,7 @@ function friendlyToolRule({ category, inner }) {
|
|
|
89322
89555
|
}
|
|
89323
89556
|
if (isCatchAllSpecifier(inner)) return {
|
|
89324
89557
|
category,
|
|
89325
|
-
pattern: CATCH_ALL_PATTERN$
|
|
89558
|
+
pattern: CATCH_ALL_PATTERN$13,
|
|
89326
89559
|
notInAllow: false
|
|
89327
89560
|
};
|
|
89328
89561
|
return isCatchAllSpecifier(inner.trim()) ? null : {
|
|
@@ -89341,13 +89574,13 @@ function friendlyToolRule({ category, inner }) {
|
|
|
89341
89574
|
*/
|
|
89342
89575
|
function parseCommandcodeRule(rule) {
|
|
89343
89576
|
const { tool, inner } = splitCommandcodeRule(rule);
|
|
89344
|
-
if (tool === CATCH_ALL_PATTERN$
|
|
89577
|
+
if (tool === CATCH_ALL_PATTERN$13) return isCatchAllSpecifier(inner) ? {
|
|
89345
89578
|
category: "*",
|
|
89346
|
-
pattern: CATCH_ALL_PATTERN$
|
|
89579
|
+
pattern: CATCH_ALL_PATTERN$13,
|
|
89347
89580
|
notInAllow: true
|
|
89348
89581
|
} : null;
|
|
89349
89582
|
const lowered = tool.toLowerCase();
|
|
89350
|
-
if (lowered.startsWith(MCP_CANONICAL_PREFIX$
|
|
89583
|
+
if (lowered.startsWith(MCP_CANONICAL_PREFIX$8)) return parseMcpCommandcodeRule({
|
|
89351
89584
|
tool,
|
|
89352
89585
|
inner
|
|
89353
89586
|
});
|
|
@@ -89365,12 +89598,12 @@ function parseCommandcodeRule(rule) {
|
|
|
89365
89598
|
*/
|
|
89366
89599
|
function isFoldedMcpToolNameRule({ rule, category }) {
|
|
89367
89600
|
const { tool } = splitCommandcodeRule(rule);
|
|
89368
|
-
return category.startsWith(MCP_CANONICAL_PREFIX$
|
|
89601
|
+
return category.startsWith(MCP_CANONICAL_PREFIX$8) && !tool.startsWith(MCP_CANONICAL_PREFIX$8);
|
|
89369
89602
|
}
|
|
89370
89603
|
/** The `Tool` half of `Tool(specifier)`, when the rule is an exact-prefix MCP rule with a specifier. */
|
|
89371
89604
|
function scopedMcpRuleTool(rule) {
|
|
89372
89605
|
const { tool, inner } = splitCommandcodeRule(rule);
|
|
89373
|
-
return !isCatchAllSpecifier(inner) && tool.startsWith(MCP_CANONICAL_PREFIX$
|
|
89606
|
+
return !isCatchAllSpecifier(inner) && tool.startsWith(MCP_CANONICAL_PREFIX$8) ? tool : null;
|
|
89374
89607
|
}
|
|
89375
89608
|
/**
|
|
89376
89609
|
* The string entries of a Command Code permission list. Command Code reads
|
|
@@ -89413,7 +89646,7 @@ function preservedRules({ existingPermissions, key, managedCategories, written,
|
|
|
89413
89646
|
}).filter((rule) => {
|
|
89414
89647
|
const parsed = parseCommandcodeRule(rule);
|
|
89415
89648
|
if (parsed === null || !managedCategories.has(parsed.category)) return true;
|
|
89416
|
-
const replacement = written.get(`${parsed.category}(${parsed.pattern})`) ?? written.get(`${parsed.category}(${CATCH_ALL_PATTERN$
|
|
89649
|
+
const replacement = written.get(`${parsed.category}(${parsed.pattern})`) ?? written.get(`${parsed.category}(${CATCH_ALL_PATTERN$13})`);
|
|
89417
89650
|
if (key !== "allow" && isStricterAction({
|
|
89418
89651
|
action: key,
|
|
89419
89652
|
existing: replacement
|
|
@@ -89470,7 +89703,7 @@ function buildCommandcodeRuleLists({ config, existingPermissions, logger }) {
|
|
|
89470
89703
|
const ranked = /* @__PURE__ */ new Map();
|
|
89471
89704
|
const managedCategories = /* @__PURE__ */ new Set();
|
|
89472
89705
|
for (const [category, rules] of Object.entries(permission)) {
|
|
89473
|
-
const categoryRule = buildCommandcodeRule(category, CATCH_ALL_PATTERN$
|
|
89706
|
+
const categoryRule = buildCommandcodeRule(category, CATCH_ALL_PATTERN$13);
|
|
89474
89707
|
const managedCategory = categoryRule === null ? null : parseCommandcodeRule(categoryRule);
|
|
89475
89708
|
if (managedCategory !== null) managedCategories.add(managedCategory.category);
|
|
89476
89709
|
for (const [pattern, action] of Object.entries(rules)) {
|
|
@@ -89539,7 +89772,7 @@ function buildCommandcodeRuleLists({ config, existingPermissions, logger }) {
|
|
|
89539
89772
|
function skippedAllowImportMessage({ rule, category }) {
|
|
89540
89773
|
const { tool, inner } = splitCommandcodeRule(rule);
|
|
89541
89774
|
if (category === "bash") return `Command Code reads '${rule}' in "allow" as ${PADDED_SHELL_WILDCARD_REASON}, which rulesync cannot import without widening the grant to every command, so it was not imported.`;
|
|
89542
|
-
if (tool.startsWith(MCP_CANONICAL_PREFIX$
|
|
89775
|
+
if (tool.startsWith(MCP_CANONICAL_PREFIX$8) || isCatchAllSpecifier(inner)) return `Command Code ignores '${rule}' in "allow" (an allow rule must name what it grants), so it was not imported.`;
|
|
89543
89776
|
return `Command Code globs the specifier of '${rule}' in "allow" against the call's arguments, which rulesync cannot import without widening the grant to the whole tool, so it was not imported.`;
|
|
89544
89777
|
}
|
|
89545
89778
|
/**
|
|
@@ -89734,7 +89967,7 @@ function parseCommandcodeSettings({ fileContent, relativePath }) {
|
|
|
89734
89967
|
}
|
|
89735
89968
|
// src/features/permissions/continue-permissions.ts
|
|
89736
89969
|
const CONTINUE_GLOBAL_ONLY_MESSAGE = "Continue permissions are global-only; use --global to sync ~/.continue/permissions.yaml";
|
|
89737
|
-
const CATCH_ALL_PATTERN$
|
|
89970
|
+
const CATCH_ALL_PATTERN$12 = "*";
|
|
89738
89971
|
/**
|
|
89739
89972
|
* A run of `*` (`**`, `***`) is the catch-all spelled another way: Continue
|
|
89740
89973
|
* would match `Tool(**)` against every argument just as the bare tool name
|
|
@@ -89742,7 +89975,7 @@ const CATCH_ALL_PATTERN$11 = "*";
|
|
|
89742
89975
|
* the bare entry instead of being skipped as a pattern-specific rule.
|
|
89743
89976
|
*/
|
|
89744
89977
|
function normalizeCatchAllPattern$1(pattern) {
|
|
89745
|
-
return /^\*+$/.test(pattern) ? CATCH_ALL_PATTERN$
|
|
89978
|
+
return /^\*+$/.test(pattern) ? CATCH_ALL_PATTERN$12 : pattern;
|
|
89746
89979
|
}
|
|
89747
89980
|
const CANONICAL_TO_CONTINUE_TOOL_NAMES = {
|
|
89748
89981
|
bash: "Bash",
|
|
@@ -89786,7 +90019,7 @@ function parseContinuePermissionEntry(entry) {
|
|
|
89786
90019
|
if (toolName === "") return;
|
|
89787
90020
|
return {
|
|
89788
90021
|
toolName,
|
|
89789
|
-
pattern: pattern === "" ? CATCH_ALL_PATTERN$
|
|
90022
|
+
pattern: pattern === "" ? CATCH_ALL_PATTERN$12 : pattern
|
|
89790
90023
|
};
|
|
89791
90024
|
}
|
|
89792
90025
|
/**
|
|
@@ -89951,7 +90184,7 @@ function convertRulesyncToContinuePermissions({ config, logger }) {
|
|
|
89951
90184
|
logger?.warn(`Continue permissions.yaml cannot hold a parenthesis inside a pattern, so the "${action}" rule for "${category}" (pattern ${quoteValueForWarning(pattern)}) was skipped.`);
|
|
89952
90185
|
continue;
|
|
89953
90186
|
}
|
|
89954
|
-
if (toolName === "*" && pattern !== CATCH_ALL_PATTERN$
|
|
90187
|
+
if (toolName === "*" && pattern !== CATCH_ALL_PATTERN$12) {
|
|
89955
90188
|
logger?.warn(`Continue permissions.yaml cannot scope a pattern to every tool, so the "${action}" rule for "*" (pattern ${quoteValueForWarning(pattern)}) was skipped.`);
|
|
89956
90189
|
continue;
|
|
89957
90190
|
}
|
|
@@ -90007,13 +90240,116 @@ const AUTO_APPROVE_KEYS = {
|
|
|
90007
90240
|
webfetch: "chat.tools.urls.autoApprove"
|
|
90008
90241
|
};
|
|
90009
90242
|
/**
|
|
90010
|
-
* The workspace setting holding the starting permission level of new
|
|
90011
|
-
* sessions, authored through the
|
|
90243
|
+
* The workspace setting holding the starting permission level of new Local
|
|
90244
|
+
* (`local` harness) chat sessions, authored through the
|
|
90245
|
+
* `copilot.defaultPermissionMode` override. VS Code 1.144 narrowed it to Local
|
|
90246
|
+
* sessions; the Copilot harness reads {@link DEFAULT_CONFIGURATION_KEY}.
|
|
90012
90247
|
*
|
|
90013
90248
|
* @see https://code.visualstudio.com/docs/agents/reference/ai-settings
|
|
90014
90249
|
*/
|
|
90015
90250
|
const DEFAULT_PERMISSION_MODE_KEY$1 = "chat.permissions.default";
|
|
90016
90251
|
/**
|
|
90252
|
+
* The workspace setting holding the starting `mode` (`interactive` / `plan` /
|
|
90253
|
+
* `autopilot`) and `approvals` (`manual` / `assisted` / `allowAll`) of new
|
|
90254
|
+
* agent sessions such as the Copilot harness, the default since VS Code 1.143.
|
|
90255
|
+
* It shipped in stable VS Code 1.144 as an object setting with
|
|
90256
|
+
* `additionalProperties: false`; older releases ignore it.
|
|
90257
|
+
*
|
|
90258
|
+
* @see https://github.com/microsoft/vscode/blob/1.144.0/src/vs/workbench/contrib/chat/browser/chat.shared.contribution.ts
|
|
90259
|
+
* @see https://github.com/microsoft/vscode/blob/1.144.0/src/vs/workbench/contrib/chat/common/constants.ts
|
|
90260
|
+
*/
|
|
90261
|
+
const DEFAULT_CONFIGURATION_KEY = "chat.defaultConfiguration";
|
|
90262
|
+
/**
|
|
90263
|
+
* What each `copilot.defaultPermissionMode` value writes. `local` goes to
|
|
90264
|
+
* `chat.permissions.default`; `approvals` and `autopilot` go to
|
|
90265
|
+
* `chat.defaultConfiguration`. The Local picker has no Assisted level, so
|
|
90266
|
+
* `assisted` starts Local sessions with Default Permissions — the stricter
|
|
90267
|
+
* fallback. Autopilot is a permission level in the Local picker but a `mode`
|
|
90268
|
+
* in `chat.defaultConfiguration`, where it runs with every tool call approved.
|
|
90269
|
+
*/
|
|
90270
|
+
const DEFAULT_PERMISSION_MODE_MAPPINGS = {
|
|
90271
|
+
default: {
|
|
90272
|
+
local: "default",
|
|
90273
|
+
approvals: "manual",
|
|
90274
|
+
autopilot: false
|
|
90275
|
+
},
|
|
90276
|
+
autoApprove: {
|
|
90277
|
+
local: "autoApprove",
|
|
90278
|
+
approvals: "allowAll",
|
|
90279
|
+
autopilot: false
|
|
90280
|
+
},
|
|
90281
|
+
autopilot: {
|
|
90282
|
+
local: "autopilot",
|
|
90283
|
+
approvals: "allowAll",
|
|
90284
|
+
autopilot: true
|
|
90285
|
+
},
|
|
90286
|
+
assisted: {
|
|
90287
|
+
local: "default",
|
|
90288
|
+
approvals: "assisted",
|
|
90289
|
+
autopilot: false
|
|
90290
|
+
}
|
|
90291
|
+
};
|
|
90292
|
+
/**
|
|
90293
|
+
* The `chat.defaultConfiguration` value for `mode`. Rulesync owns only whether
|
|
90294
|
+
* the mode is Autopilot: authoring Autopilot sets it, and any other value
|
|
90295
|
+
* removes any Autopilot mode in the file (whether an earlier run or a person
|
|
90296
|
+
* wrote it, since the two cannot be told apart), while an `interactive` or
|
|
90297
|
+
* `plan` mode is kept.
|
|
90298
|
+
*/
|
|
90299
|
+
function buildDefaultConfigurationValue({ defaultPermissionMode, existingSettings }) {
|
|
90300
|
+
const { approvals, autopilot } = DEFAULT_PERMISSION_MODE_MAPPINGS[defaultPermissionMode];
|
|
90301
|
+
const existing = existingSettings[DEFAULT_CONFIGURATION_KEY];
|
|
90302
|
+
const value = { ...isPlainObject(existing) ? existing : {} };
|
|
90303
|
+
if (autopilot) value.mode = "autopilot";
|
|
90304
|
+
else if (value.mode === "autopilot") delete value.mode;
|
|
90305
|
+
value.approvals = approvals;
|
|
90306
|
+
return value;
|
|
90307
|
+
}
|
|
90308
|
+
/**
|
|
90309
|
+
* The `copilot.defaultPermissionMode` values from least to most permissive,
|
|
90310
|
+
* used to settle a file whose two keys disagree.
|
|
90311
|
+
*/
|
|
90312
|
+
const DEFAULT_PERMISSION_MODE_RANK = {
|
|
90313
|
+
default: 0,
|
|
90314
|
+
assisted: 1,
|
|
90315
|
+
autoApprove: 2,
|
|
90316
|
+
autopilot: 3
|
|
90317
|
+
};
|
|
90318
|
+
/**
|
|
90319
|
+
* The `copilot.defaultPermissionMode` a `chat.defaultConfiguration` value
|
|
90320
|
+
* stands for. Autopilot is recognized only together with `allowAll`, the pair
|
|
90321
|
+
* Rulesync writes for it: an Autopilot mode with stricter approvals is read
|
|
90322
|
+
* from `approvals` alone, so that regenerating never escalates it to Allow
|
|
90323
|
+
* All. An object without `approvals` is read as `default`, since VS Code then
|
|
90324
|
+
* starts sessions with Manual permissions.
|
|
90325
|
+
*/
|
|
90326
|
+
function readDefaultConfigurationMode(configuration) {
|
|
90327
|
+
if (!isPlainObject(configuration)) return;
|
|
90328
|
+
switch (configuration.approvals) {
|
|
90329
|
+
case void 0:
|
|
90330
|
+
case "manual": return "default";
|
|
90331
|
+
case "assisted": return "assisted";
|
|
90332
|
+
case "allowAll": return configuration.mode === "autopilot" ? "autopilot" : "autoApprove";
|
|
90333
|
+
default: return;
|
|
90334
|
+
}
|
|
90335
|
+
}
|
|
90336
|
+
/**
|
|
90337
|
+
* Read `copilot.defaultPermissionMode` back from the settings. When the two
|
|
90338
|
+
* keys agree — `chat.permissions.default` holds the Local level Rulesync
|
|
90339
|
+
* writes for the `chat.defaultConfiguration` value — the latter is returned,
|
|
90340
|
+
* since only it can say `assisted`. When they disagree, the less permissive of
|
|
90341
|
+
* the two is returned, so regenerating never raises either harness's starting
|
|
90342
|
+
* permissions. Either key alone is read as it stands.
|
|
90343
|
+
*/
|
|
90344
|
+
function readDefaultPermissionMode(settings) {
|
|
90345
|
+
const fromConfiguration = readDefaultConfigurationMode(settings[DEFAULT_CONFIGURATION_KEY]);
|
|
90346
|
+
const localValue = settings[DEFAULT_PERMISSION_MODE_KEY$1];
|
|
90347
|
+
const fromLocal = COPILOT_LOCAL_PERMISSION_LEVELS.find((level) => level === localValue);
|
|
90348
|
+
if (fromConfiguration === void 0 || fromLocal === void 0) return fromConfiguration ?? fromLocal;
|
|
90349
|
+
if (DEFAULT_PERMISSION_MODE_MAPPINGS[fromConfiguration].local === fromLocal) return fromConfiguration;
|
|
90350
|
+
return DEFAULT_PERMISSION_MODE_RANK[fromLocal] < DEFAULT_PERMISSION_MODE_RANK[fromConfiguration] ? fromLocal : fromConfiguration;
|
|
90351
|
+
}
|
|
90352
|
+
/**
|
|
90017
90353
|
* The prefix every Agent Host sandbox setting shares. A `copilot.sandbox` leaf
|
|
90018
90354
|
* at path `a.b` is written to `chat.agent.sandbox.a.b`.
|
|
90019
90355
|
*/
|
|
@@ -90200,9 +90536,6 @@ function readSandboxFromSettings(settings) {
|
|
|
90200
90536
|
}
|
|
90201
90537
|
return Object.keys(sandbox).length > 0 ? sandbox : void 0;
|
|
90202
90538
|
}
|
|
90203
|
-
function isCopilotDefaultPermissionMode(value) {
|
|
90204
|
-
return COPILOT_DEFAULT_PERMISSION_MODES.some((mode) => mode === value);
|
|
90205
|
-
}
|
|
90206
90539
|
function asAutoApproveMap(value) {
|
|
90207
90540
|
if (!isPlainObject(value)) return {};
|
|
90208
90541
|
const result = {};
|
|
@@ -90246,9 +90579,11 @@ function buildAutoApproveValue({ category, rules }) {
|
|
|
90246
90579
|
* `false`. A key whose canonical category is absent entirely
|
|
90247
90580
|
* is left untouched, so authoring only `bash` rules never disturbs a
|
|
90248
90581
|
* hand-written edits or urls map.
|
|
90249
|
-
* The `copilot.defaultPermissionMode` override writes
|
|
90250
|
-
* (
|
|
90251
|
-
*
|
|
90582
|
+
* The `copilot.defaultPermissionMode` override writes both
|
|
90583
|
+
* `chat.permissions.default` (Local sessions) and `chat.defaultConfiguration`
|
|
90584
|
+
* (Copilot-harness sessions, VS Code 1.144+; see
|
|
90585
|
+
* {@link DEFAULT_PERMISSION_MODE_MAPPINGS}); without it both keys are left
|
|
90586
|
+
* untouched. The `copilot.sandbox` override writes the Agent Host sandbox
|
|
90252
90587
|
* settings (`chat.agent.sandbox.*`, see {@link SANDBOX_LEAVES}) per key, and
|
|
90253
90588
|
* warns about every value it writes that loosens the sandbox.
|
|
90254
90589
|
* Only project scope is modeled: VS Code's user-scope settings.json lives at a
|
|
@@ -90299,17 +90634,24 @@ var CopilotPermissions = class CopilotPermissions extends ToolPermissions {
|
|
|
90299
90634
|
rules
|
|
90300
90635
|
});
|
|
90301
90636
|
}
|
|
90637
|
+
const existingSettings = () => parseSharedConfig({
|
|
90638
|
+
format: "jsonc",
|
|
90639
|
+
fileContent: existingContent,
|
|
90640
|
+
filePath
|
|
90641
|
+
});
|
|
90302
90642
|
const defaultPermissionMode = config.copilot?.defaultPermissionMode;
|
|
90303
|
-
if (defaultPermissionMode !== void 0)
|
|
90643
|
+
if (defaultPermissionMode !== void 0) {
|
|
90644
|
+
patch[DEFAULT_PERMISSION_MODE_KEY$1] = DEFAULT_PERMISSION_MODE_MAPPINGS[defaultPermissionMode].local;
|
|
90645
|
+
patch[DEFAULT_CONFIGURATION_KEY] = buildDefaultConfigurationValue({
|
|
90646
|
+
defaultPermissionMode,
|
|
90647
|
+
existingSettings: existingSettings()
|
|
90648
|
+
});
|
|
90649
|
+
}
|
|
90304
90650
|
const sandbox = config.copilot?.sandbox;
|
|
90305
90651
|
if (sandbox !== void 0) {
|
|
90306
90652
|
Object.assign(patch, buildSandboxPatch({
|
|
90307
90653
|
sandbox,
|
|
90308
|
-
existingSettings:
|
|
90309
|
-
format: "jsonc",
|
|
90310
|
-
fileContent: existingContent,
|
|
90311
|
-
filePath
|
|
90312
|
-
})
|
|
90654
|
+
existingSettings: existingSettings()
|
|
90313
90655
|
}));
|
|
90314
90656
|
warnOnTrustAffectingEntries({
|
|
90315
90657
|
toolLabel: COPILOT_TOOL_LABEL,
|
|
@@ -90356,10 +90698,10 @@ var CopilotPermissions = class CopilotPermissions extends ToolPermissions {
|
|
|
90356
90698
|
for (const [pattern, flag] of Object.entries(autoApprove)) rules[pattern] = flag ? "allow" : "deny";
|
|
90357
90699
|
if (Object.keys(rules).length > 0) permission[category] = rules;
|
|
90358
90700
|
}
|
|
90359
|
-
const defaultPermissionMode = settings
|
|
90701
|
+
const defaultPermissionMode = readDefaultPermissionMode(settings);
|
|
90360
90702
|
const sandbox = readSandboxFromSettings(settings);
|
|
90361
90703
|
const copilot = {
|
|
90362
|
-
...
|
|
90704
|
+
...defaultPermissionMode !== void 0 && { defaultPermissionMode },
|
|
90363
90705
|
...sandbox !== void 0 && { sandbox }
|
|
90364
90706
|
};
|
|
90365
90707
|
return this.toRulesyncPermissionsDefault({ fileContent: JSON.stringify({
|
|
@@ -90557,14 +90899,14 @@ var CopilotcliPermissions = class CopilotcliPermissions extends ToolPermissions
|
|
|
90557
90899
|
}
|
|
90558
90900
|
};
|
|
90559
90901
|
// src/features/permissions/crush-permissions.ts
|
|
90560
|
-
const CATCH_ALL_PATTERN$
|
|
90902
|
+
const CATCH_ALL_PATTERN$11 = "*";
|
|
90561
90903
|
/**
|
|
90562
90904
|
* A run of `*` (`**`, `***`) is the catch-all spelled another way: Crush has no
|
|
90563
90905
|
* argument patterns at all, so it is the only pattern a rule can carry and
|
|
90564
90906
|
* still be written.
|
|
90565
90907
|
*/
|
|
90566
90908
|
function normalizeCatchAllPattern(pattern) {
|
|
90567
|
-
return /^\*+$/.test(pattern) ? CATCH_ALL_PATTERN$
|
|
90909
|
+
return /^\*+$/.test(pattern) ? CATCH_ALL_PATTERN$11 : pattern;
|
|
90568
90910
|
}
|
|
90569
90911
|
const CANONICAL_TO_CRUSH_TOOL_NAMES = {
|
|
90570
90912
|
bash: "bash",
|
|
@@ -90576,11 +90918,11 @@ const CANONICAL_TO_CRUSH_TOOL_NAMES = {
|
|
|
90576
90918
|
webfetch: "fetch"
|
|
90577
90919
|
};
|
|
90578
90920
|
const CRUSH_TO_CANONICAL_TOOL_NAMES = Object.fromEntries(Object.entries(CANONICAL_TO_CRUSH_TOOL_NAMES).map(([k, v]) => [v, k]));
|
|
90579
|
-
const MCP_CANONICAL_PREFIX$
|
|
90921
|
+
const MCP_CANONICAL_PREFIX$7 = "mcp__";
|
|
90580
90922
|
const MCP_CRUSH_PREFIX = "mcp_";
|
|
90581
90923
|
function toCrushToolName(canonical) {
|
|
90582
90924
|
if (Object.hasOwn(CANONICAL_TO_CRUSH_TOOL_NAMES, canonical)) return CANONICAL_TO_CRUSH_TOOL_NAMES[canonical] ?? canonical;
|
|
90583
|
-
if (canonical.startsWith(MCP_CANONICAL_PREFIX$
|
|
90925
|
+
if (canonical.startsWith(MCP_CANONICAL_PREFIX$7) && canonical.length > 5) return `${MCP_CRUSH_PREFIX}${canonical.slice(5).replaceAll("__", "_")}`;
|
|
90584
90926
|
return canonical;
|
|
90585
90927
|
}
|
|
90586
90928
|
function toCanonicalToolName$5(crushName) {
|
|
@@ -90754,7 +91096,7 @@ function resolveCategoryAction({ category, toolName, rules, logger }) {
|
|
|
90754
91096
|
for (const [rawPattern, action] of Object.entries(rules)) {
|
|
90755
91097
|
if (isPrototypePollutionKey(rawPattern)) continue;
|
|
90756
91098
|
const pattern = normalizeCatchAllPattern(rawPattern);
|
|
90757
|
-
if (pattern === CATCH_ALL_PATTERN$
|
|
91099
|
+
if (pattern === CATCH_ALL_PATTERN$11) {
|
|
90758
91100
|
catchAllAction = action;
|
|
90759
91101
|
continue;
|
|
90760
91102
|
}
|
|
@@ -90827,11 +91169,11 @@ function convertCrushListsToRulesync({ allowed, disabled }) {
|
|
|
90827
91169
|
};
|
|
90828
91170
|
for (const entry of disabled) {
|
|
90829
91171
|
if (entry === "" || isPrototypePollutionKey(entry)) continue;
|
|
90830
|
-
bucketFor(toCanonicalToolName$5(entry))[CATCH_ALL_PATTERN$
|
|
91172
|
+
bucketFor(toCanonicalToolName$5(entry))[CATCH_ALL_PATTERN$11] = "deny";
|
|
90831
91173
|
}
|
|
90832
91174
|
for (const entry of allowed) {
|
|
90833
91175
|
if (entry === "" || entry.includes(":") || isPrototypePollutionKey(entry)) continue;
|
|
90834
|
-
bucketFor(toCanonicalToolName$5(entry))[CATCH_ALL_PATTERN$
|
|
91176
|
+
bucketFor(toCanonicalToolName$5(entry))[CATCH_ALL_PATTERN$11] ??= "allow";
|
|
90835
91177
|
}
|
|
90836
91178
|
return { permission };
|
|
90837
91179
|
}
|
|
@@ -90877,13 +91219,13 @@ const CURSOR_TYPE_TO_CANONICAL = {
|
|
|
90877
91219
|
WebFetch: "webfetch",
|
|
90878
91220
|
Mcp: "mcp"
|
|
90879
91221
|
};
|
|
90880
|
-
const MCP_CANONICAL_PREFIX$
|
|
91222
|
+
const MCP_CANONICAL_PREFIX$6 = "mcp__";
|
|
90881
91223
|
/**
|
|
90882
91224
|
* Returns true if the canonical category is the per-tool MCP form
|
|
90883
91225
|
* `mcp__<server>__<tool>`.
|
|
90884
91226
|
*/
|
|
90885
91227
|
function isMcpScopedCategory(canonical) {
|
|
90886
|
-
return canonical.startsWith(MCP_CANONICAL_PREFIX$
|
|
91228
|
+
return canonical.startsWith(MCP_CANONICAL_PREFIX$6) && canonical.length > 5;
|
|
90887
91229
|
}
|
|
90888
91230
|
function toCursorType(canonical) {
|
|
90889
91231
|
if (isMcpScopedCategory(canonical)) return "Mcp";
|
|
@@ -90917,7 +91259,7 @@ function toCanonicalCategory$1(cursorType, pattern) {
|
|
|
90917
91259
|
if (match) {
|
|
90918
91260
|
const server = match[1] ?? "*";
|
|
90919
91261
|
const tool = match[2] ?? "*";
|
|
90920
|
-
return `${MCP_CANONICAL_PREFIX$
|
|
91262
|
+
return `${MCP_CANONICAL_PREFIX$6}${server}__${tool}`;
|
|
90921
91263
|
}
|
|
90922
91264
|
return CURSOR_TYPE_TO_CANONICAL[cursorType] ?? cursorType.toLowerCase();
|
|
90923
91265
|
}
|
|
@@ -91179,7 +91521,7 @@ function convertCursorToRulesyncPermissions(params) {
|
|
|
91179
91521
|
const { toolName: type, pattern } = parseToolPatternEntry(entry);
|
|
91180
91522
|
const canonical = toCanonicalCategory$1(type, pattern);
|
|
91181
91523
|
if (!permission[canonical]) permission[canonical] = {};
|
|
91182
|
-
const canonicalPattern = type === "Mcp" && canonical.startsWith(MCP_CANONICAL_PREFIX$
|
|
91524
|
+
const canonicalPattern = type === "Mcp" && canonical.startsWith(MCP_CANONICAL_PREFIX$6) ? "*" : pattern;
|
|
91183
91525
|
permission[canonical][canonicalPattern] = action;
|
|
91184
91526
|
}
|
|
91185
91527
|
};
|
|
@@ -92678,7 +93020,7 @@ function convertFactorydroidToRulesyncPermissions({ allow, deny }) {
|
|
|
92678
93020
|
// src/features/permissions/goose-permissions.ts
|
|
92679
93021
|
const GOOSE_GLOBAL_ONLY_MESSAGE = "Goose permissions are global-only; use --global to sync ~/.config/goose/permission.yaml";
|
|
92680
93022
|
const GOOSE_USER_KEY = "user";
|
|
92681
|
-
const CATCH_ALL_PATTERN$
|
|
93023
|
+
const CATCH_ALL_PATTERN$10 = "*";
|
|
92682
93024
|
const RULESYNC_TO_GOOSE_TOOL_NAME = { bash: "shell" };
|
|
92683
93025
|
const GOOSE_TO_RULESYNC_TOOL_NAMES = {
|
|
92684
93026
|
shell: ["bash"],
|
|
@@ -92827,7 +93169,7 @@ function convertRulesyncToGoosePermissionConfig({ config, logger }) {
|
|
|
92827
93169
|
const assigned = /* @__PURE__ */ new Map();
|
|
92828
93170
|
for (const [category, rules] of Object.entries(honorAllToolsOnBash(config.permission))) {
|
|
92829
93171
|
const toolName = RULESYNC_TO_GOOSE_TOOL_NAME[category] ?? category;
|
|
92830
|
-
for (const [pattern, action] of Object.entries(rules)) if (pattern !== CATCH_ALL_PATTERN$
|
|
93172
|
+
for (const [pattern, action] of Object.entries(rules)) if (pattern !== CATCH_ALL_PATTERN$10) 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.`);
|
|
92831
93173
|
const { action, downgraded } = failSafeCatchAllAction({
|
|
92832
93174
|
rules,
|
|
92833
93175
|
allToolsRules: category === "*" ? void 0 : config.permission["*"]
|
|
@@ -92860,7 +93202,7 @@ function convertGoosePermissionConfigToRulesync(userPermission) {
|
|
|
92860
93202
|
const action = GOOSE_LIST_TO_ACTION[key];
|
|
92861
93203
|
for (const toolName of toolNames) for (const category of GOOSE_TO_RULESYNC_TOOL_NAMES[toolName] ?? [toolName]) {
|
|
92862
93204
|
permission[category] ??= {};
|
|
92863
|
-
permission[category][CATCH_ALL_PATTERN$
|
|
93205
|
+
permission[category][CATCH_ALL_PATTERN$10] = action;
|
|
92864
93206
|
}
|
|
92865
93207
|
}
|
|
92866
93208
|
return { permission };
|
|
@@ -92870,8 +93212,8 @@ const GROKCLI_UI_KEY = "ui";
|
|
|
92870
93212
|
const GROKCLI_PERMISSION_MODE_KEY = "permission_mode";
|
|
92871
93213
|
const GROKCLI_PERMISSION_KEY = "permission";
|
|
92872
93214
|
const GROKCLI_AUTO_PERMISSION_MODE = "auto";
|
|
92873
|
-
const CATCH_ALL_PATTERN$
|
|
92874
|
-
const MCP_CANONICAL_PREFIX$
|
|
93215
|
+
const CATCH_ALL_PATTERN$9 = "*";
|
|
93216
|
+
const MCP_CANONICAL_PREFIX$5 = "mcp__";
|
|
92875
93217
|
const CATEGORY_TO_GROK_TOOL = {
|
|
92876
93218
|
bash: "Bash",
|
|
92877
93219
|
read: "Read",
|
|
@@ -92903,6 +93245,25 @@ const GROK_TOOL_TO_CATEGORY_LOWER = {
|
|
|
92903
93245
|
};
|
|
92904
93246
|
const GROK_MCP_TOOL_ALIASES = /* @__PURE__ */ new Set(["mcp", GROK_MCP_TOOL.toLowerCase()]);
|
|
92905
93247
|
const GROKCLI_PERMISSION_RULES_KEY = "rules";
|
|
93248
|
+
const GROK_PATH_PATTERN_CATEGORIES = /* @__PURE__ */ new Set([
|
|
93249
|
+
"read",
|
|
93250
|
+
"edit",
|
|
93251
|
+
"write",
|
|
93252
|
+
"grep",
|
|
93253
|
+
"glob"
|
|
93254
|
+
]);
|
|
93255
|
+
const CLAUDE_ABSOLUTE_PATH_PREFIX = "//";
|
|
93256
|
+
/**
|
|
93257
|
+
* Rewrite a canonical path pattern into the anchor Grok understands. A
|
|
93258
|
+
* Claude-style `//abs` absolute pattern becomes `/abs`; without this the rule
|
|
93259
|
+
* would match nothing on Grok, so a `deny` or `ask` rule would silently give
|
|
93260
|
+
* no protection. Every other pattern is returned unchanged.
|
|
93261
|
+
*/
|
|
93262
|
+
function toGrokPathPattern(category, pattern) {
|
|
93263
|
+
if (!GROK_PATH_PATTERN_CATEGORIES.has(category)) return pattern;
|
|
93264
|
+
if (!pattern.startsWith(CLAUDE_ABSOLUTE_PATH_PREFIX)) return pattern;
|
|
93265
|
+
return `/${pattern.replace(/^\/+/, "")}`;
|
|
93266
|
+
}
|
|
92906
93267
|
/**
|
|
92907
93268
|
* Build a Grok Claude-style permission entry (e.g. `Bash(git *)`, `Read`,
|
|
92908
93269
|
* `MCPTool(server__tool)`) from a canonical category + pattern. Returns `null`
|
|
@@ -92913,18 +93274,20 @@ const GROKCLI_PERMISSION_RULES_KEY = "rules";
|
|
|
92913
93274
|
* `MCPTool`. For every other tool, a `*` pattern emits the bare tool name and a
|
|
92914
93275
|
* concrete pattern emits `Tool(pattern)`. The all-tools `*` category becomes
|
|
92915
93276
|
* Grok's bare `*` rule for its catch-all pattern only; a narrower pattern
|
|
92916
|
-
* under it has no Grok spelling and returns `null`.
|
|
93277
|
+
* under it has no Grok spelling and returns `null`. A Claude-style `//abs`
|
|
93278
|
+
* path pattern on a file tool is rewritten to Grok's `/abs` (see
|
|
93279
|
+
* `toGrokPathPattern`).
|
|
92917
93280
|
*/
|
|
92918
93281
|
function buildGrokEntry(category, pattern) {
|
|
92919
|
-
if (category === "*") return pattern === CATCH_ALL_PATTERN$
|
|
92920
|
-
if (category.startsWith(MCP_CANONICAL_PREFIX$
|
|
93282
|
+
if (category === "*") return pattern === CATCH_ALL_PATTERN$9 ? GROK_ALL_TOOLS_ENTRY : null;
|
|
93283
|
+
if (category.startsWith(MCP_CANONICAL_PREFIX$5)) {
|
|
92921
93284
|
const remainder = category.slice(5);
|
|
92922
93285
|
return remainder.length > 0 ? `${GROK_MCP_TOOL}(${remainder})` : GROK_MCP_TOOL;
|
|
92923
93286
|
}
|
|
92924
|
-
if (category === "mcp") return pattern === CATCH_ALL_PATTERN$
|
|
93287
|
+
if (category === "mcp") return pattern === CATCH_ALL_PATTERN$9 || pattern === "" ? GROK_MCP_TOOL : `${GROK_MCP_TOOL}(${pattern})`;
|
|
92925
93288
|
const tool = CATEGORY_TO_GROK_TOOL[category];
|
|
92926
93289
|
if (tool === void 0) return null;
|
|
92927
|
-
return pattern === CATCH_ALL_PATTERN$
|
|
93290
|
+
return pattern === CATCH_ALL_PATTERN$9 || pattern === "" ? tool : `${tool}(${toGrokPathPattern(category, pattern)})`;
|
|
92928
93291
|
}
|
|
92929
93292
|
/**
|
|
92930
93293
|
* Parse a Grok Claude-style permission entry back into a canonical category +
|
|
@@ -92946,21 +93309,21 @@ function parseGrokEntry(entry) {
|
|
|
92946
93309
|
}
|
|
92947
93310
|
if (parenIndex === -1 && tool === GROK_ALL_TOOLS_ENTRY) return {
|
|
92948
93311
|
category: "*",
|
|
92949
|
-
pattern: CATCH_ALL_PATTERN$
|
|
93312
|
+
pattern: CATCH_ALL_PATTERN$9
|
|
92950
93313
|
};
|
|
92951
|
-
if (parenIndex === -1 && tool.startsWith(MCP_CANONICAL_PREFIX$
|
|
93314
|
+
if (parenIndex === -1 && tool.startsWith(MCP_CANONICAL_PREFIX$5)) return parseClaudeStyleMcpEntry(tool);
|
|
92952
93315
|
if (tool === GROK_MCP_TOOL) return inner.length > 0 ? {
|
|
92953
|
-
category: `${MCP_CANONICAL_PREFIX$
|
|
92954
|
-
pattern: CATCH_ALL_PATTERN$
|
|
93316
|
+
category: `${MCP_CANONICAL_PREFIX$5}${inner}`,
|
|
93317
|
+
pattern: CATCH_ALL_PATTERN$9
|
|
92955
93318
|
} : {
|
|
92956
93319
|
category: "mcp",
|
|
92957
|
-
pattern: CATCH_ALL_PATTERN$
|
|
93320
|
+
pattern: CATCH_ALL_PATTERN$9
|
|
92958
93321
|
};
|
|
92959
93322
|
const category = GROK_TOOL_TO_CATEGORY[tool];
|
|
92960
93323
|
if (category === void 0) return null;
|
|
92961
93324
|
return {
|
|
92962
93325
|
category,
|
|
92963
|
-
pattern: inner.length > 0 ? inner : CATCH_ALL_PATTERN$
|
|
93326
|
+
pattern: inner.length > 0 ? inner : CATCH_ALL_PATTERN$9
|
|
92964
93327
|
};
|
|
92965
93328
|
}
|
|
92966
93329
|
/**
|
|
@@ -92977,14 +93340,14 @@ function parseGrokEntry(entry) {
|
|
|
92977
93340
|
function parseClaudeStyleMcpEntry(entry) {
|
|
92978
93341
|
const rest = entry.slice(5);
|
|
92979
93342
|
if (rest.length === 0) return null;
|
|
92980
|
-
if (rest === CATCH_ALL_PATTERN$
|
|
93343
|
+
if (rest === CATCH_ALL_PATTERN$9) return {
|
|
92981
93344
|
category: "mcp",
|
|
92982
|
-
pattern: CATCH_ALL_PATTERN$
|
|
93345
|
+
pattern: CATCH_ALL_PATTERN$9
|
|
92983
93346
|
};
|
|
92984
93347
|
const address = rest.includes("__") ? rest : `${rest}__*`;
|
|
92985
93348
|
return {
|
|
92986
|
-
category: `${MCP_CANONICAL_PREFIX$
|
|
92987
|
-
pattern: CATCH_ALL_PATTERN$
|
|
93349
|
+
category: `${MCP_CANONICAL_PREFIX$5}${address}`,
|
|
93350
|
+
pattern: CATCH_ALL_PATTERN$9
|
|
92988
93351
|
};
|
|
92989
93352
|
}
|
|
92990
93353
|
/**
|
|
@@ -93005,20 +93368,20 @@ function parseGrokRule(rule) {
|
|
|
93005
93368
|
if (typeof tool !== "string") return null;
|
|
93006
93369
|
if (pattern !== void 0 && typeof pattern !== "string") return null;
|
|
93007
93370
|
const trimmedPattern = pattern?.trim() ?? "";
|
|
93008
|
-
const resolvedPattern = trimmedPattern.length > 0 ? trimmedPattern : CATCH_ALL_PATTERN$
|
|
93371
|
+
const resolvedPattern = trimmedPattern.length > 0 ? trimmedPattern : CATCH_ALL_PATTERN$9;
|
|
93009
93372
|
const lowerTool = tool.trim().toLowerCase();
|
|
93010
|
-
if (lowerTool === GROK_VERBOSE_ANY_TOOL) return resolvedPattern === CATCH_ALL_PATTERN$
|
|
93373
|
+
if (lowerTool === GROK_VERBOSE_ANY_TOOL) return resolvedPattern === CATCH_ALL_PATTERN$9 ? {
|
|
93011
93374
|
category: "*",
|
|
93012
|
-
pattern: CATCH_ALL_PATTERN$
|
|
93375
|
+
pattern: CATCH_ALL_PATTERN$9,
|
|
93013
93376
|
action
|
|
93014
93377
|
} : null;
|
|
93015
|
-
if (GROK_MCP_TOOL_ALIASES.has(lowerTool)) return resolvedPattern === CATCH_ALL_PATTERN$
|
|
93378
|
+
if (GROK_MCP_TOOL_ALIASES.has(lowerTool)) return resolvedPattern === CATCH_ALL_PATTERN$9 ? {
|
|
93016
93379
|
category: "mcp",
|
|
93017
|
-
pattern: CATCH_ALL_PATTERN$
|
|
93380
|
+
pattern: CATCH_ALL_PATTERN$9,
|
|
93018
93381
|
action
|
|
93019
93382
|
} : {
|
|
93020
|
-
category: `${MCP_CANONICAL_PREFIX$
|
|
93021
|
-
pattern: CATCH_ALL_PATTERN$
|
|
93383
|
+
category: `${MCP_CANONICAL_PREFIX$5}${resolvedPattern}`,
|
|
93384
|
+
pattern: CATCH_ALL_PATTERN$9,
|
|
93022
93385
|
action
|
|
93023
93386
|
};
|
|
93024
93387
|
if (!Object.hasOwn(GROK_TOOL_TO_CATEGORY_LOWER, lowerTool)) return null;
|
|
@@ -93168,7 +93531,7 @@ var GrokcliPermissions = class GrokcliPermissions extends ToolPermissions {
|
|
|
93168
93531
|
throw new Error(`Failed to parse Grok config.toml content in ${join(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`, { cause: error });
|
|
93169
93532
|
}
|
|
93170
93533
|
const fineGrained = parseGrokPermissionArrays(isRecord(parsed[GROKCLI_PERMISSION_KEY]) ? parsed[GROKCLI_PERMISSION_KEY] : {});
|
|
93171
|
-
const rulesyncConfig = fineGrained ? { permission: fineGrained } : { permission: { bash: { [CATCH_ALL_PATTERN$
|
|
93534
|
+
const rulesyncConfig = fineGrained ? { permission: fineGrained } : { permission: { bash: { [CATCH_ALL_PATTERN$9]: legacyModeAction(parsed) } } };
|
|
93172
93535
|
return this.toRulesyncPermissionsDefault({ fileContent: JSON.stringify(rulesyncConfig, null, 2) });
|
|
93173
93536
|
}
|
|
93174
93537
|
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
|
|
@@ -93353,6 +93716,195 @@ function ensureCategory(permission, category) {
|
|
|
93353
93716
|
function removeEmptyCategories(permission) {
|
|
93354
93717
|
for (const [category, rules] of Object.entries(permission)) if (Object.keys(rules).length === 0) delete permission[category];
|
|
93355
93718
|
}
|
|
93719
|
+
/** The prefix Hermes's MCP trust gate keys its persisted "Always" answers with. */
|
|
93720
|
+
const MCP_ALLOWLIST_PREFIX = "mcp:";
|
|
93721
|
+
const MCP_CANONICAL_PREFIX$4 = "mcp__";
|
|
93722
|
+
const CATCH_ALL_PATTERN$8 = "*";
|
|
93723
|
+
/**
|
|
93724
|
+
* Whether a `command_allowlist` entry is an MCP trust-gate grant rather than a
|
|
93725
|
+
* shell-command pattern. Since Hermes Agent v0.22.6, answering **Always** to
|
|
93726
|
+
* the approval prompt of a `trust: untrusted` MCP server appends
|
|
93727
|
+
* `mcp:<server>/<tool>` to `command_allowlist` (`_trust_approval_key` in
|
|
93728
|
+
* `tools/mcp_tool_handlers.py`), and the gate looks the key up by exact set
|
|
93729
|
+
* membership, so no `mcp:` entry is ever a command.
|
|
93730
|
+
*/
|
|
93731
|
+
function isMcpAllowlistEntry(entry) {
|
|
93732
|
+
return entry.startsWith(MCP_ALLOWLIST_PREFIX);
|
|
93733
|
+
}
|
|
93734
|
+
/**
|
|
93735
|
+
* The canonical category (`mcp__<server>__<tool>`) a Hermes `mcp:<server>/<tool>`
|
|
93736
|
+
* grant stands for, or `null` when it has none: a malformed entry, a server
|
|
93737
|
+
* name containing `__` (the canonical name would read back as another server),
|
|
93738
|
+
* or a `*` in either name (Hermes compares the key literally, while a canonical
|
|
93739
|
+
* `*` is a wildcard).
|
|
93740
|
+
*/
|
|
93741
|
+
function mcpAllowlistEntryToCategory(entry) {
|
|
93742
|
+
const parsed = parseMcpAllowlistEntry(entry);
|
|
93743
|
+
if (parsed === null) return null;
|
|
93744
|
+
const { server, tool } = parsed;
|
|
93745
|
+
if (server.includes("__") || server.includes(CATCH_ALL_PATTERN$8)) return null;
|
|
93746
|
+
if (tool.includes(CATCH_ALL_PATTERN$8)) return null;
|
|
93747
|
+
return `${MCP_CANONICAL_PREFIX$4}${server}__${tool}`;
|
|
93748
|
+
}
|
|
93749
|
+
/** The server and tool an `mcp:<server>/<tool>` entry names, or `null` when it is malformed. */
|
|
93750
|
+
function parseMcpAllowlistEntry(entry) {
|
|
93751
|
+
if (!isMcpAllowlistEntry(entry)) return null;
|
|
93752
|
+
const rest = entry.slice(4);
|
|
93753
|
+
const slash = rest.indexOf("/");
|
|
93754
|
+
const server = slash === -1 ? "" : rest.slice(0, slash);
|
|
93755
|
+
const tool = slash === -1 ? "" : rest.slice(slash + 1);
|
|
93756
|
+
return server.length === 0 || tool.length === 0 ? null : {
|
|
93757
|
+
server,
|
|
93758
|
+
tool
|
|
93759
|
+
};
|
|
93760
|
+
}
|
|
93761
|
+
/**
|
|
93762
|
+
* The server and tool a canonical `mcp__<server>__<tool>` category names, or
|
|
93763
|
+
* `null` when it names no single tool (a whole server, a wildcard, or the bare
|
|
93764
|
+
* `mcp` category). Only such a category can become one Hermes grant.
|
|
93765
|
+
*/
|
|
93766
|
+
function parseMcpToolCategory(category) {
|
|
93767
|
+
if (!category.startsWith(MCP_CANONICAL_PREFIX$4)) return null;
|
|
93768
|
+
const remainder = category.slice(5);
|
|
93769
|
+
const separator = remainder.indexOf("__");
|
|
93770
|
+
if (separator <= 0) return null;
|
|
93771
|
+
const server = remainder.slice(0, separator);
|
|
93772
|
+
const tool = remainder.slice(separator + 2);
|
|
93773
|
+
if (tool.length === 0 || server.includes("/") || server.includes(CATCH_ALL_PATTERN$8) || tool.includes(CATCH_ALL_PATTERN$8)) return null;
|
|
93774
|
+
return {
|
|
93775
|
+
server,
|
|
93776
|
+
tool
|
|
93777
|
+
};
|
|
93778
|
+
}
|
|
93779
|
+
function isMcpCategory$1(category) {
|
|
93780
|
+
return category === "mcp" || category.startsWith(MCP_CANONICAL_PREFIX$4);
|
|
93781
|
+
}
|
|
93782
|
+
function isRestricting(action) {
|
|
93783
|
+
return action === "deny" || action === "ask";
|
|
93784
|
+
}
|
|
93785
|
+
/** The first `deny` or `ask` rule of a category, as `<category>: <pattern> (<action>)`. */
|
|
93786
|
+
function firstRestrictingRule(category, rules, covers = () => true) {
|
|
93787
|
+
const found = Object.entries(rules ?? {}).find(([pattern, action]) => isRestricting(action) && covers(pattern));
|
|
93788
|
+
return found ? `${category}: ${found[0]} (${found[1]})` : null;
|
|
93789
|
+
}
|
|
93790
|
+
/**
|
|
93791
|
+
* Whether an MCP name glob (the remainder of an `mcp__...` category, or a
|
|
93792
|
+
* pattern of the bare `mcp` category) covers `server`'s tool `tool`: it names
|
|
93793
|
+
* the tool (`github__delete_repo`, `github__*`, `*__delete_repo`, `*`) or the
|
|
93794
|
+
* whole server (`github`).
|
|
93795
|
+
*/
|
|
93796
|
+
function mcpNameGlobCovers(glob, server, tool) {
|
|
93797
|
+
return glob === `${server}__${tool}` || glob === server || matchesGlob(glob, `${server}__${tool}`) || matchesGlob(glob, server);
|
|
93798
|
+
}
|
|
93799
|
+
/**
|
|
93800
|
+
* The `deny` or `ask` rule that outranks an allow on `server`'s tool `tool`, or
|
|
93801
|
+
* `null` when none does: any one under the all-tools `*` category (a rule there
|
|
93802
|
+
* applies to every tool, so even a narrower pattern restricts some of the
|
|
93803
|
+
* tool's calls), one under the bare `mcp` category whose pattern covers the
|
|
93804
|
+
* tool, or any one in an `mcp__...` category whose name covers the tool — its
|
|
93805
|
+
* own category included, since a deny or ask scoped to some of its calls still
|
|
93806
|
+
* forbids approving all of them. A Hermes grant approves every call of the
|
|
93807
|
+
* tool and Hermes has no ask tier, so such an allow is withheld, the same way
|
|
93808
|
+
* a `bash` allow a stricter rule covers is.
|
|
93809
|
+
*/
|
|
93810
|
+
function findMcpToolRestriction(permission, server, tool) {
|
|
93811
|
+
for (const [category, rules] of Object.entries(permission)) {
|
|
93812
|
+
let found = null;
|
|
93813
|
+
if (category === "*") found = firstRestrictingRule(category, rules);
|
|
93814
|
+
else if (category === "mcp") found = firstRestrictingRule(category, rules, (pattern) => mcpNameGlobCovers(pattern, server, tool));
|
|
93815
|
+
else if (category.startsWith(MCP_CANONICAL_PREFIX$4) && mcpNameGlobCovers(category.slice(5), server, tool)) found = firstRestrictingRule(category, rules);
|
|
93816
|
+
if (found !== null) return found;
|
|
93817
|
+
}
|
|
93818
|
+
return null;
|
|
93819
|
+
}
|
|
93820
|
+
function isMcpToolRestricted(permission, server, tool) {
|
|
93821
|
+
return findMcpToolRestriction(permission, server, tool) !== null;
|
|
93822
|
+
}
|
|
93823
|
+
/**
|
|
93824
|
+
* Translate the canonical MCP `allow` rules into Hermes trust-gate grants: a
|
|
93825
|
+
* `*` allow on `mcp__<server>__<tool>` becomes `mcp:<server>/<tool>`. Every
|
|
93826
|
+
* other MCP allow (a whole server, a wildcard, a narrower pattern) has no
|
|
93827
|
+
* Hermes spelling, and an allow a deny or ask covers is withheld.
|
|
93828
|
+
*/
|
|
93829
|
+
function collectMcpAllowlistEntries(permission) {
|
|
93830
|
+
const entries = [];
|
|
93831
|
+
const withheldCategories = [];
|
|
93832
|
+
const unexpressedRules = [];
|
|
93833
|
+
for (const [category, rules] of Object.entries(permission)) {
|
|
93834
|
+
if (!isMcpCategory$1(category)) continue;
|
|
93835
|
+
const parsed = parseMcpToolCategory(category);
|
|
93836
|
+
for (const pattern of patternsByAction(rules, "allow")) if (parsed === null || pattern !== CATCH_ALL_PATTERN$8) unexpressedRules.push(`${category}: ${pattern}`);
|
|
93837
|
+
else {
|
|
93838
|
+
const restriction = findMcpToolRestriction(permission, parsed.server, parsed.tool);
|
|
93839
|
+
if (restriction === null) entries.push(`${MCP_ALLOWLIST_PREFIX}${parsed.server}/${parsed.tool}`);
|
|
93840
|
+
else withheldCategories.push(`${category} (covered by ${restriction})`);
|
|
93841
|
+
}
|
|
93842
|
+
}
|
|
93843
|
+
return {
|
|
93844
|
+
entries,
|
|
93845
|
+
withheldCategories,
|
|
93846
|
+
unexpressedRules
|
|
93847
|
+
};
|
|
93848
|
+
}
|
|
93849
|
+
function warnAboutUnwrittenMcpAllows({ withheldCategories, unexpressedRules, logger }) {
|
|
93850
|
+
if (withheldCategories.length > 0) warnWithFallback(logger, `Hermes Agent's command_allowlist was not given the MCP allow rule(s) for ${withheldCategories.join(", ")}: a deny or ask rule covers each, a Hermes grant approves every call of the tool, and Hermes has no ask tier.`);
|
|
93851
|
+
if (unexpressedRules.length > 0) warnWithFallback(logger, `Hermes Agent grants MCP tools one at a time (command_allowlist entries 'mcp:<server>/<tool>'), so only a '*' allow on an 'mcp__<server>__<tool>' category can be written; the MCP allow rule(s) ${unexpressedRules.join(", ")} were skipped and survive only in the permissions.rulesync round-trip block.`);
|
|
93852
|
+
}
|
|
93853
|
+
/**
|
|
93854
|
+
* Make the native `mcp:<server>/<tool>` grants authoritative for the canonical
|
|
93855
|
+
* single-tool MCP allows they can speak for. An allow the generator withheld
|
|
93856
|
+
* because a deny or ask covers it was never written, so its absence
|
|
93857
|
+
* is not a retraction and it is kept, as is every MCP allow with no Hermes
|
|
93858
|
+
* spelling. A grant with no canonical spelling stays only in Hermes, where
|
|
93859
|
+
* generation keeps it (see `setFileContent`).
|
|
93860
|
+
*/
|
|
93861
|
+
function reconcileMcpAllowlist({ permission, mcpEntries, logger }) {
|
|
93862
|
+
for (const [category, rules] of Object.entries(permission)) {
|
|
93863
|
+
const parsed = parseMcpToolCategory(category);
|
|
93864
|
+
if (parsed !== null && rules[CATCH_ALL_PATTERN$8] === "allow" && !isMcpToolRestricted(permission, parsed.server, parsed.tool)) delete rules[CATCH_ALL_PATTERN$8];
|
|
93865
|
+
}
|
|
93866
|
+
const keptRestrictions = [];
|
|
93867
|
+
for (const entry of mcpEntries) {
|
|
93868
|
+
const category = mcpAllowlistEntryToCategory(entry);
|
|
93869
|
+
if (category === null) continue;
|
|
93870
|
+
const rules = ensureCategory(permission, category);
|
|
93871
|
+
if (isRestricting(rules[CATCH_ALL_PATTERN$8])) {
|
|
93872
|
+
keptRestrictions.push(entry);
|
|
93873
|
+
continue;
|
|
93874
|
+
}
|
|
93875
|
+
rules[CATCH_ALL_PATTERN$8] = "allow";
|
|
93876
|
+
}
|
|
93877
|
+
if (keptRestrictions.length > 0) warnWithFallback(logger, `Hermes Agent's command_allowlist grants ${keptRestrictions.join(", ")}, but the permissions.rulesync block denies or asks for those MCP tools; the canonical rule was kept and the grant was not imported.`);
|
|
93878
|
+
}
|
|
93879
|
+
/**
|
|
93880
|
+
* The `mcp:` grants in an existing `command_allowlist` that rulesync does not
|
|
93881
|
+
* manage and must keep when it rewrites the list: Hermes appends one whenever
|
|
93882
|
+
* the user answers **Always** on an untrusted MCP server, so dropping it would
|
|
93883
|
+
* silently revoke the grant. A grant is managed — and so retracted with its
|
|
93884
|
+
* canonical rule — when the previous or the new canonical block has a rule
|
|
93885
|
+
* for its `mcp__<server>__<tool>` category, or when the new block restricts
|
|
93886
|
+
* the tool in any way.
|
|
93887
|
+
*/
|
|
93888
|
+
function unmanagedMcpAllowlistEntries({ existing, previousPermission, nextPermission, nextAllowlist }) {
|
|
93889
|
+
return (isStringArray(existing.command_allowlist) ? existing.command_allowlist : []).filter((entry) => {
|
|
93890
|
+
if (!isMcpAllowlistEntry(entry) || nextAllowlist.includes(entry)) return false;
|
|
93891
|
+
const parsed = parseMcpAllowlistEntry(entry);
|
|
93892
|
+
if (parsed !== null && isMcpToolRestricted(nextPermission, parsed.server, parsed.tool)) return false;
|
|
93893
|
+
const category = mcpAllowlistEntryToCategory(entry);
|
|
93894
|
+
return category === null || !Object.hasOwn(previousPermission, category) && !Object.hasOwn(nextPermission, category);
|
|
93895
|
+
});
|
|
93896
|
+
}
|
|
93897
|
+
/** The validated canonical `permission` block of a config's `permissions.rulesync` blob. */
|
|
93898
|
+
function canonicalPermissionOf(config) {
|
|
93899
|
+
const parsed = RulesyncPermissionsFileSchema.safeParse({ permission: provenancePermissionOf(config) });
|
|
93900
|
+
return parsed.success ? parsed.data.permission : {};
|
|
93901
|
+
}
|
|
93902
|
+
/** The canonical `permission` block of a config's `permissions.rulesync` blob, if any. */
|
|
93903
|
+
function provenancePermissionOf(config) {
|
|
93904
|
+
const permissionsRoot = isRecord(config.permissions) ? config.permissions : {};
|
|
93905
|
+
const provenance = isRecord(permissionsRoot.rulesync) ? permissionsRoot.rulesync : {};
|
|
93906
|
+
return isRecord(provenance.permission) ? provenance.permission : {};
|
|
93907
|
+
}
|
|
93356
93908
|
/**
|
|
93357
93909
|
* Make the native `command_allowlist` authoritative for the `bash` allow rules
|
|
93358
93910
|
* it can speak for, and for those only. The allowlist is a list of shell-command
|
|
@@ -93370,8 +93922,9 @@ function reconcileCommandAllowlist({ permission, commandAllowlist }) {
|
|
|
93370
93922
|
writesAllToolsDeny: false
|
|
93371
93923
|
});
|
|
93372
93924
|
const withheld = new Set(shadowedAllowPatterns);
|
|
93925
|
+
const isWithheld = (pattern) => withheld.has(pattern) || isMcpAllowlistEntry(pattern);
|
|
93373
93926
|
const rules = ensureCategory(permission, SHELL_PERMISSION_CATEGORY);
|
|
93374
|
-
for (const [pattern, action] of Object.entries(rules)) if (action === "allow" && !
|
|
93927
|
+
for (const [pattern, action] of Object.entries(rules)) if (action === "allow" && !isWithheld(pattern)) delete rules[pattern];
|
|
93375
93928
|
for (const pattern of commandAllowlist) rules[pattern] = "allow";
|
|
93376
93929
|
}
|
|
93377
93930
|
/**
|
|
@@ -93459,17 +94012,31 @@ var HermesagentPermissions = class HermesagentPermissions extends ToolPermission
|
|
|
93459
94012
|
return true;
|
|
93460
94013
|
}
|
|
93461
94014
|
setFileContent(fileContent) {
|
|
94015
|
+
const patch = parseSharedConfig({
|
|
94016
|
+
format: "yaml",
|
|
94017
|
+
fileContent: this.fileContent
|
|
94018
|
+
});
|
|
94019
|
+
if (isStringArray(patch.command_allowlist)) {
|
|
94020
|
+
const existing = parseSharedConfig({
|
|
94021
|
+
format: "yaml",
|
|
94022
|
+
fileContent
|
|
94023
|
+
});
|
|
94024
|
+
const kept = unmanagedMcpAllowlistEntries({
|
|
94025
|
+
existing,
|
|
94026
|
+
previousPermission: provenancePermissionOf(existing),
|
|
94027
|
+
nextPermission: canonicalPermissionOf(patch),
|
|
94028
|
+
nextAllowlist: patch.command_allowlist
|
|
94029
|
+
});
|
|
94030
|
+
if (kept.length > 0) patch.command_allowlist = [...patch.command_allowlist, ...kept];
|
|
94031
|
+
}
|
|
93462
94032
|
this.fileContent = applySharedConfigPatch({
|
|
93463
94033
|
fileKey: getHermesagentConfigSharedFileKey({ global: this.global }),
|
|
93464
94034
|
feature: "permissions",
|
|
93465
94035
|
existingContent: fileContent,
|
|
93466
|
-
patch
|
|
93467
|
-
format: "yaml",
|
|
93468
|
-
fileContent: this.fileContent
|
|
93469
|
-
})
|
|
94036
|
+
patch
|
|
93470
94037
|
});
|
|
93471
94038
|
}
|
|
93472
|
-
toRulesyncPermissions() {
|
|
94039
|
+
toRulesyncPermissions({ logger } = {}) {
|
|
93473
94040
|
const config = parseSharedConfig({
|
|
93474
94041
|
format: "yaml",
|
|
93475
94042
|
fileContent: this.getFileContent()
|
|
@@ -93481,9 +94048,15 @@ var HermesagentPermissions = class HermesagentPermissions extends ToolPermission
|
|
|
93481
94048
|
}) : rawProvenance);
|
|
93482
94049
|
const provenance = parsedProvenance.success ? parsedProvenance.data : { permission: {} };
|
|
93483
94050
|
const permission = clonePermissionBlock(provenance.permission);
|
|
94051
|
+
const commandAllowlist = isStringArray(config.command_allowlist) ? config.command_allowlist : [];
|
|
93484
94052
|
reconcileCommandAllowlist({
|
|
93485
94053
|
permission,
|
|
93486
|
-
commandAllowlist:
|
|
94054
|
+
commandAllowlist: commandAllowlist.filter((entry) => !isMcpAllowlistEntry(entry))
|
|
94055
|
+
});
|
|
94056
|
+
reconcileMcpAllowlist({
|
|
94057
|
+
permission,
|
|
94058
|
+
mcpEntries: commandAllowlist.filter(isMcpAllowlistEntry),
|
|
94059
|
+
logger
|
|
93487
94060
|
});
|
|
93488
94061
|
const approvals = isRecord(config.approvals) ? config.approvals : {};
|
|
93489
94062
|
reconcileNativeDenies({
|
|
@@ -93541,8 +94114,16 @@ var HermesagentPermissions = class HermesagentPermissions extends ToolPermission
|
|
|
93541
94114
|
logger
|
|
93542
94115
|
});
|
|
93543
94116
|
const webfetchDeny = patternsByAction(permissionBlock[WEBFETCH_PERMISSION_CATEGORY], "deny");
|
|
94117
|
+
const mcpAllows = collectMcpAllowlistEntries(permissionBlock);
|
|
94118
|
+
warnAboutUnwrittenMcpAllows({
|
|
94119
|
+
...mcpAllows,
|
|
94120
|
+
logger
|
|
94121
|
+
});
|
|
94122
|
+
const bashMcpAllows = commandAllowlist.filter(isMcpAllowlistEntry);
|
|
94123
|
+
if (bashMcpAllows.length > 0) warnWithFallback(logger, `Hermes Agent reads 'mcp:' entries in command_allowlist as MCP tool grants, so the bash allow rule(s) ${bashMcpAllows.join(", ")} were skipped; write them as a '*' allow on an 'mcp__<server>__<tool>' category instead.`);
|
|
94124
|
+
const allowlist = [...commandAllowlist.filter((entry) => !isMcpAllowlistEntry(entry)), ...mcpAllows.entries];
|
|
93544
94125
|
let config = {};
|
|
93545
|
-
if (
|
|
94126
|
+
if (allowlist.length > 0) config.command_allowlist = allowlist;
|
|
93546
94127
|
if (bashDeny.length > 0) config.approvals = { deny: bashDeny };
|
|
93547
94128
|
if (webfetchDeny.length > 0) config.security = { website_blocklist: {
|
|
93548
94129
|
enabled: true,
|
|
@@ -100383,6 +100964,7 @@ const TAKT_SECURITY_POLICIES = {
|
|
|
100383
100964
|
],
|
|
100384
100965
|
workflow_runtime_prepare: ["custom_scripts"],
|
|
100385
100966
|
workflow_command_gates: ["custom_scripts"],
|
|
100967
|
+
workflow_system_commands: ["custom_scripts"],
|
|
100386
100968
|
sync_conflict_resolver: ["auto_approve_tools"],
|
|
100387
100969
|
allow_git_hooks: null,
|
|
100388
100970
|
allow_git_filters: null
|
|
@@ -107352,4 +107934,4 @@ async function importChecksCore(params) {
|
|
|
107352
107934
|
}
|
|
107353
107935
|
export { RulesyncPermissions as $, formatError as $n, isSymlink as $t, CODEBUDDY_DIR as A, MAX_FILE_SIZE as An, withFallbackLoggerTarget as At, CLAUDECODE_LOCAL_RULE_FILE_NAME as B, RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH as Bn, assertTreeContainsNoSymlinks as Bt, QWENCODE_LOCAL_RULE_FILE_NAME as C, PACKAGING_TOOL_TARGETS as Cn, getSourceTransport as Ct, FACTORYDROID_SETTINGS_LOCAL_FILE_NAME as D, DEPRECATED_FEATURE_REPLACEMENTS as Dn, WarningCollectingLogger as Dt, FACTORYDROID_DIR as E, ALL_FEATURES_WITH_WILDCARD as En, JsonLogger as Et, groupSpellingsByCaseFoldedIdentity as F, RULESYNC_CONFIG_SCHEMA_URL as Fn, PathOutsideRootError as Ft, toInstructionBudgetFile as G, RULESYNC_PERMISSIONS_SCHEMA_URL as Gn, ensureDir as Gt, CLAUDECODE_SETTINGS_LOCAL_FILE_NAME as H, RULESYNC_MCP_SCHEMA_URL as Hn, checkPathTraversal as Ht, CODEXCLI_BASH_RULES_FILE_NAME as I, RULESYNC_CURATED_RULES_RELATIVE_DIR_PATH as In, applyFileMode as It, RulesyncSubagentFrontmatterSchema as J, RULESYNC_SKILLS_RELATIVE_DIR_PATH as Jn, findFilesByGlobs as Jt, getLocalSkillDirNames as K, RULESYNC_RELATIVE_DIR_PATH as Kn, fileExists as Kt, CODEXCLI_DIR as L, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH as Ln, assertDirectoryIfExists as Lt, AUGMENTCODE_DIR as M, RULESYNC_CHECKS_RELATIVE_DIR_PATH as Mn, withWarnOnceScope as Mt, AUGMENTCODE_SETTINGS_LOCAL_FILE_NAME as N, RULESYNC_COMMANDS_RELATIVE_DIR_PATH as Nn, CLIError as Nt, COMMANDCODE_DIR as O, CURATED_RULES_FEATURE_SUBDIR as On, fallbackLogger as Ot, caseFoldIdentity as P, RULESYNC_CONFIG_RELATIVE_FILE_PATH as Pn, ErrorCodes as Pt, RulesyncRuleFrontmatterSchema as Q, RULESYNC_XDG_CONFIG_HOME_DEFAULT_DIR_NAME as Qn, isFileSystemError as Qt, CLAUDECODE_AGENT_MEMORY_LOCAL_DIR_NAME as R, RULESYNC_HOOKS_RELATIVE_FILE_PATH as Rn, assertNoSymlinkBelowRoot as Rt, QWENCODE_DIR as S, ALL_TOOL_TARGETS_WITH_WILDCARD as Sn, assertTargetsFeaturesExclusive as St, LETTACODE_SETTINGS_LOCAL_FILE_NAME as T, ALL_FEATURES as Tn, ConsoleLogger as Tt, CLAUDECODE_SKILLS_DIR_PATH as U, RULESYNC_NPM_SOURCES_LOCK_RELATIVE_FILE_PATH as Un, createTempDirectory as Ut, CLAUDECODE_MEMORIES_DIR_NAME as V, RULESYNC_MCP_RELATIVE_FILE_PATH as Vn, assertWritablePathInsideRoot as Vt, findProjectInstructionBudgetFindings as W, RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH as Wn, directoryExists as Wt, RulesyncSkillFrontmatterSchema as X, RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH as Xn, getHomeDirectory as Xt, RulesyncSkill as Y, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH as Yn, getFileSizeAndExecutableBit as Yt, RulesyncRule as Z, RULESYNC_USER_CONFIG_DIR_NAME as Zn, isFileNotFoundError as Zt, SubagentsProcessor as _, toPosixPath as _n, resolveEffectiveInputRoots as _t, convertFromTool as a, readFileContent as an, stripControlCharactersKeepingLineFeeds as ar, parseJsonc as at, CommandsProcessor as b, mapWithConcurrency as bn, GITIGNORE_DESTINATION_KEY as bt, parseCommaSeparatedList as c, removeDirectoryStrict as cn, RulesyncCheck as ct, shortenToWidth as d, removeFileWithoutFollowingSymlinks as dn, loadYaml as dt, listDirectoryEntryNames as en, truncateText as er, RulesyncMcp as et, McpProcessor as f, removeTempDirectory as fn, isRecord as ft, RulesProcessor as g, splitPathSegments as gn, mergeInputRootConfigs as gt, ChecksProcessor as h, runWithDirectoryRollback as hn, ConfigResolver as ht, inspectInputRoots as i, posixRelativePathEscapesRoot as in, stripControlCharacters as ir, resolveRulesyncSourceWritePath as it, CODEBUDDY_LOCAL_RULE_FILE_NAME as j, RULESYNC_AIIGNORE_RELATIVE_FILE_PATH as jn, resetRunWarningState as jt, COMMANDCODE_SETTINGS_LOCAL_FILE_NAME as k, FEATURE_SOURCE_TREE_ENTRIES as kn, warnOnConflictingFlags as kt, ELLIPSIS_WIDTH as l, removeFile as ln, RulesyncCheckFrontmatterSchema as lt, HooksProcessor as m, resolvedRelativePath as mn, SKILL_FILE_NAME as mt, formatSourceLoadFailure as n, listSubdirectoryNames as nn, hasEnclosingMarkOutsideKeycap as nr, RulesyncHooks as nt, isPackagingToolTarget as o, readFileContentOrNull as on, stripControlCharactersKeepingLineFeedsAndTabs as or, RulesyncCommand as ot, IgnoreProcessor as p, resolvePath as pn, SHARED_USER_MANAGED_CONFIG_PATHS as pt, RulesyncSubagent as q, RULESYNC_RULES_RELATIVE_DIR_PATH as qn, fileExistsStrict as qt, generate as r, pathEscapesRoot as rn, quoteForLog as rr, getRulesyncSourceCandidates as rt, getProcessorRegistryEntry as s, removeDirectory as sn, stripHiddenCharacters as sr, RulesyncCommandFrontmatterSchema as st, importFromTool as t, listFilePathsRecursively as tn, hasDeceptiveHiddenCharacters as tr, RulesyncIgnore as tt, displayWidthOf as u, removeFileStrict as un, stringifyFrontmatter as ut, SkillsProcessor as v, writeFileBuffer as vn, CONFLICTING_TARGET_PAIRS as vt, LETTACODE_DIR as w, ToolTargetSchema as wn, findControlCharacter as wt, REASONIX_LOCAL_RULE_FILE_NAME as x, ALL_TOOL_TARGETS as xn, SourceEntrySchema as xt, CRUSH_LOCAL_RULE_FILE_NAME as y, writeFileContent as yn, ConfigFileSchema as yt, CLAUDECODE_DIR as z, RULESYNC_IGNORE_RELATIVE_FILE_PATH as zn, assertPathResolvesInsideRoot as zt };
|
|
107354
107936
|
|
|
107355
|
-
//# sourceMappingURL=import-
|
|
107937
|
+
//# sourceMappingURL=import-C_XK2L62.js.map
|