rulesync 9.7.0 → 9.8.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/README.md +1 -1
- package/dist/cli/index.cjs +2 -2
- package/dist/cli/index.js +2 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/{import-DC9T1JlQ.js → import-Dioh9ca8.js} +455 -109
- package/dist/import-Dioh9ca8.js.map +1 -0
- package/dist/{import-D5f_X4-A.cjs → import-l0o1jVdc.cjs} +464 -118
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/import-DC9T1JlQ.js.map +0 -1
|
@@ -322,7 +322,8 @@ const hooksProcessorToolTargetTuple = [
|
|
|
322
322
|
"junie",
|
|
323
323
|
"vibe",
|
|
324
324
|
"qwencode",
|
|
325
|
-
"reasonix"
|
|
325
|
+
"reasonix",
|
|
326
|
+
"grokcli"
|
|
326
327
|
];
|
|
327
328
|
const permissionsProcessorToolTargetTuple = [
|
|
328
329
|
"amp",
|
|
@@ -6269,10 +6270,13 @@ const CLAUDE_HOOK_EVENTS = [
|
|
|
6269
6270
|
* Hook events supported by Devin Local (native `.devin/` hooks).
|
|
6270
6271
|
*
|
|
6271
6272
|
* Devin Local adopts a Claude-Code-style lifecycle hooks surface. It documents
|
|
6272
|
-
*
|
|
6273
|
-
* `UserPromptSubmit`, `Stop`, `SessionStart`,
|
|
6273
|
+
* eight events: `PreToolUse`, `PostToolUse`, `PermissionRequest`,
|
|
6274
|
+
* `UserPromptSubmit`, `Stop`, `SessionStart`, `SessionEnd`, and
|
|
6275
|
+
* `PostCompaction` (fires after context compaction; added in the Devin CLI
|
|
6276
|
+
* stable changelog — https://docs.devin.ai/cli/changelog/stable). The
|
|
6274
6277
|
* tool/permission events (`PreToolUse`/`PostToolUse`/`PermissionRequest`) carry
|
|
6275
|
-
* a `matcher` (regex against `tool_name`); the session/turn events
|
|
6278
|
+
* a `matcher` (regex against `tool_name`); the session/turn/compaction events
|
|
6279
|
+
* do not.
|
|
6276
6280
|
*
|
|
6277
6281
|
* Hooks live in `.devin/hooks.v1.json` (project, standalone — the hooks object
|
|
6278
6282
|
* is the entire file) or under the `"hooks"` key of `.devin/config.json` /
|
|
@@ -6287,7 +6291,8 @@ const DEVIN_HOOK_EVENTS = [
|
|
|
6287
6291
|
"postToolUse",
|
|
6288
6292
|
"beforeSubmitPrompt",
|
|
6289
6293
|
"stop",
|
|
6290
|
-
"permissionRequest"
|
|
6294
|
+
"permissionRequest",
|
|
6295
|
+
"postCompact"
|
|
6291
6296
|
];
|
|
6292
6297
|
/** Hook events supported by OpenCode. */
|
|
6293
6298
|
const OPENCODE_HOOK_EVENTS = [
|
|
@@ -6481,7 +6486,7 @@ const ANTIGRAVITY_HOOK_EVENTS = [
|
|
|
6481
6486
|
* Hook events supported by AugmentCode (Auggie CLI).
|
|
6482
6487
|
* Auggie mirrors Claude Code's lifecycle hooks but exposes a smaller set:
|
|
6483
6488
|
* PreToolUse / PostToolUse (tool events, matcher-aware) plus the
|
|
6484
|
-
* SessionStart / SessionEnd / Stop session events (no matcher).
|
|
6489
|
+
* SessionStart / SessionEnd / Stop / Notification session events (no matcher).
|
|
6485
6490
|
* @see https://docs.augmentcode.com/cli/hooks
|
|
6486
6491
|
*/
|
|
6487
6492
|
const AUGMENTCODE_HOOK_EVENTS = [
|
|
@@ -6489,7 +6494,8 @@ const AUGMENTCODE_HOOK_EVENTS = [
|
|
|
6489
6494
|
"postToolUse",
|
|
6490
6495
|
"sessionStart",
|
|
6491
6496
|
"sessionEnd",
|
|
6492
|
-
"stop"
|
|
6497
|
+
"stop",
|
|
6498
|
+
"notification"
|
|
6493
6499
|
];
|
|
6494
6500
|
/**
|
|
6495
6501
|
* Hook events supported by Mistral Vibe (mistral-vibe).
|
|
@@ -6541,6 +6547,10 @@ const JUNIE_HOOK_EVENTS = [
|
|
|
6541
6547
|
* The Qwen-specific events
|
|
6542
6548
|
* `TodoCreated`, `TodoCompleted`, and `StopFailure` map to the canonical
|
|
6543
6549
|
* `todoCreated`, `todoCompleted`, and `stopFailure` events respectively.
|
|
6550
|
+
* Qwen's `HookEventName` enum (`packages/core/src/hooks/types.ts`) also documents
|
|
6551
|
+
* `PostToolBatch`, `UserPromptExpansion`, `PermissionDenied`, and
|
|
6552
|
+
* `InstructionsLoaded`, which map to the canonical `postToolBatch`,
|
|
6553
|
+
* `userPromptExpansion`, `permissionDenied`, and `instructionsLoaded` events.
|
|
6544
6554
|
* @see https://github.com/QwenLM/qwen-code/blob/main/docs/users/features/hooks.md
|
|
6545
6555
|
*/
|
|
6546
6556
|
const QWENCODE_HOOK_EVENTS = [
|
|
@@ -6549,7 +6559,9 @@ const QWENCODE_HOOK_EVENTS = [
|
|
|
6549
6559
|
"preToolUse",
|
|
6550
6560
|
"postToolUse",
|
|
6551
6561
|
"postToolUseFailure",
|
|
6562
|
+
"postToolBatch",
|
|
6552
6563
|
"beforeSubmitPrompt",
|
|
6564
|
+
"userPromptExpansion",
|
|
6553
6565
|
"stop",
|
|
6554
6566
|
"stopFailure",
|
|
6555
6567
|
"subagentStart",
|
|
@@ -6557,7 +6569,9 @@ const QWENCODE_HOOK_EVENTS = [
|
|
|
6557
6569
|
"preCompact",
|
|
6558
6570
|
"postCompact",
|
|
6559
6571
|
"permissionRequest",
|
|
6572
|
+
"permissionDenied",
|
|
6560
6573
|
"notification",
|
|
6574
|
+
"instructionsLoaded",
|
|
6561
6575
|
"todoCreated",
|
|
6562
6576
|
"todoCompleted"
|
|
6563
6577
|
];
|
|
@@ -6567,11 +6581,11 @@ const QWENCODE_HOOK_EVENTS = [
|
|
|
6567
6581
|
* Reasonix's `.reasonix/settings.json` (project) / `~/.reasonix/settings.json`
|
|
6568
6582
|
* (global) documents a ten-event surface (`PreToolUse`, `PostToolUse`,
|
|
6569
6583
|
* `UserPromptSubmit`, `Stop`, `PostLLMCall`, `SessionStart`, `SessionEnd`,
|
|
6570
|
-
* `SubagentStop`, `Notification`, `PreCompact`).
|
|
6571
|
-
*
|
|
6584
|
+
* `SubagentStop`, `Notification`, `PreCompact`). All ten have a clean canonical
|
|
6585
|
+
* equivalent and are mapped: `PreToolUse`, `PostToolUse`,
|
|
6572
6586
|
* `UserPromptSubmit` ← `beforeSubmitPrompt`, `Stop`, `SessionStart`,
|
|
6573
|
-
* `SessionEnd`, `SubagentStop`,
|
|
6574
|
-
*
|
|
6587
|
+
* `SessionEnd`, `SubagentStop`, `PostLLMCall` ← `postModelInvocation`,
|
|
6588
|
+
* `Notification` ← `notification`, and `PreCompact` ← `preCompact`.
|
|
6575
6589
|
* `match` (Reasonix's matcher field name) is honored only on
|
|
6576
6590
|
* `PreToolUse`/`PostToolUse`, matching the canonical `matcher` field's
|
|
6577
6591
|
* tool-event scoping used by other adapters.
|
|
@@ -6585,7 +6599,39 @@ const REASONIX_HOOK_EVENTS = [
|
|
|
6585
6599
|
"sessionStart",
|
|
6586
6600
|
"sessionEnd",
|
|
6587
6601
|
"subagentStop",
|
|
6588
|
-
"postModelInvocation"
|
|
6602
|
+
"postModelInvocation",
|
|
6603
|
+
"notification",
|
|
6604
|
+
"preCompact"
|
|
6605
|
+
];
|
|
6606
|
+
/**
|
|
6607
|
+
* Hook events supported by Grok CLI (xAI Grok Build).
|
|
6608
|
+
*
|
|
6609
|
+
* Grok Build documents a Claude-Code-compatible hooks surface with fourteen
|
|
6610
|
+
* PascalCase events, all of which map 1:1 onto an existing canonical arm:
|
|
6611
|
+
* `SessionStart`, `SessionEnd`, `UserPromptSubmit` ← `beforeSubmitPrompt`,
|
|
6612
|
+
* `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `PermissionDenied`,
|
|
6613
|
+
* `Stop`, `StopFailure`, `Notification`, `SubagentStart`, `SubagentStop`,
|
|
6614
|
+
* `PreCompact`, `PostCompact`. A `matcher` (a regex tested against the tool
|
|
6615
|
+
* name) is meaningful only on the tool-name events (`PreToolUse`, `PostToolUse`,
|
|
6616
|
+
* `PostToolUseFailure`, `PermissionDenied`), matching Claude Code's semantics;
|
|
6617
|
+
* the remaining lifecycle events are matcher-less.
|
|
6618
|
+
* @see https://docs.x.ai/build/features/hooks
|
|
6619
|
+
*/
|
|
6620
|
+
const GROKCLI_HOOK_EVENTS = [
|
|
6621
|
+
"sessionStart",
|
|
6622
|
+
"sessionEnd",
|
|
6623
|
+
"beforeSubmitPrompt",
|
|
6624
|
+
"preToolUse",
|
|
6625
|
+
"postToolUse",
|
|
6626
|
+
"postToolUseFailure",
|
|
6627
|
+
"permissionDenied",
|
|
6628
|
+
"stop",
|
|
6629
|
+
"stopFailure",
|
|
6630
|
+
"notification",
|
|
6631
|
+
"subagentStart",
|
|
6632
|
+
"subagentStop",
|
|
6633
|
+
"preCompact",
|
|
6634
|
+
"postCompact"
|
|
6589
6635
|
];
|
|
6590
6636
|
/**
|
|
6591
6637
|
* Hook events supported by Hermes Agent's native Shell Hooks system.
|
|
@@ -6659,6 +6705,7 @@ const HooksConfigSchema = z.looseObject({
|
|
|
6659
6705
|
junie: z.optional(z.looseObject({ hooks: z.optional(hooksRecordSchema) })),
|
|
6660
6706
|
vibe: z.optional(z.looseObject({ hooks: z.optional(hooksRecordSchema) })),
|
|
6661
6707
|
reasonix: z.optional(z.looseObject({ hooks: z.optional(hooksRecordSchema) })),
|
|
6708
|
+
grokcli: z.optional(z.looseObject({ hooks: z.optional(hooksRecordSchema) })),
|
|
6662
6709
|
qwencode: z.optional(z.looseObject({
|
|
6663
6710
|
hooks: z.optional(hooksRecordSchema),
|
|
6664
6711
|
disableAllHooks: z.optional(z.boolean())
|
|
@@ -6717,7 +6764,8 @@ const CANONICAL_TO_DEVIN_EVENT_NAMES = {
|
|
|
6717
6764
|
postToolUse: "PostToolUse",
|
|
6718
6765
|
beforeSubmitPrompt: "UserPromptSubmit",
|
|
6719
6766
|
stop: "Stop",
|
|
6720
|
-
permissionRequest: "PermissionRequest"
|
|
6767
|
+
permissionRequest: "PermissionRequest",
|
|
6768
|
+
postCompact: "PostCompaction"
|
|
6721
6769
|
};
|
|
6722
6770
|
/**
|
|
6723
6771
|
* Map Devin Local PascalCase event names to canonical camelCase.
|
|
@@ -6732,7 +6780,8 @@ const CANONICAL_TO_AUGMENTCODE_EVENT_NAMES = {
|
|
|
6732
6780
|
postToolUse: "PostToolUse",
|
|
6733
6781
|
sessionStart: "SessionStart",
|
|
6734
6782
|
sessionEnd: "SessionEnd",
|
|
6735
|
-
stop: "Stop"
|
|
6783
|
+
stop: "Stop",
|
|
6784
|
+
notification: "Notification"
|
|
6736
6785
|
};
|
|
6737
6786
|
/**
|
|
6738
6787
|
* Map AugmentCode PascalCase event names to canonical camelCase.
|
|
@@ -7002,7 +7051,9 @@ const CANONICAL_TO_QWENCODE_EVENT_NAMES = {
|
|
|
7002
7051
|
preToolUse: "PreToolUse",
|
|
7003
7052
|
postToolUse: "PostToolUse",
|
|
7004
7053
|
postToolUseFailure: "PostToolUseFailure",
|
|
7054
|
+
postToolBatch: "PostToolBatch",
|
|
7005
7055
|
beforeSubmitPrompt: "UserPromptSubmit",
|
|
7056
|
+
userPromptExpansion: "UserPromptExpansion",
|
|
7006
7057
|
stop: "Stop",
|
|
7007
7058
|
subagentStart: "SubagentStart",
|
|
7008
7059
|
subagentStop: "SubagentStop",
|
|
@@ -7010,7 +7061,9 @@ const CANONICAL_TO_QWENCODE_EVENT_NAMES = {
|
|
|
7010
7061
|
preCompact: "PreCompact",
|
|
7011
7062
|
postCompact: "PostCompact",
|
|
7012
7063
|
permissionRequest: "PermissionRequest",
|
|
7064
|
+
permissionDenied: "PermissionDenied",
|
|
7013
7065
|
notification: "Notification",
|
|
7066
|
+
instructionsLoaded: "InstructionsLoaded",
|
|
7014
7067
|
todoCreated: "TodoCreated",
|
|
7015
7068
|
todoCompleted: "TodoCompleted"
|
|
7016
7069
|
};
|
|
@@ -7032,12 +7085,40 @@ const CANONICAL_TO_REASONIX_EVENT_NAMES = {
|
|
|
7032
7085
|
sessionStart: "SessionStart",
|
|
7033
7086
|
sessionEnd: "SessionEnd",
|
|
7034
7087
|
subagentStop: "SubagentStop",
|
|
7035
|
-
postModelInvocation: "PostLLMCall"
|
|
7088
|
+
postModelInvocation: "PostLLMCall",
|
|
7089
|
+
notification: "Notification",
|
|
7090
|
+
preCompact: "PreCompact"
|
|
7036
7091
|
};
|
|
7037
7092
|
/**
|
|
7038
7093
|
* Map Reasonix PascalCase event names to canonical camelCase.
|
|
7039
7094
|
*/
|
|
7040
7095
|
const REASONIX_TO_CANONICAL_EVENT_NAMES = Object.fromEntries(Object.entries(CANONICAL_TO_REASONIX_EVENT_NAMES).map(([k, v]) => [v, k]));
|
|
7096
|
+
/**
|
|
7097
|
+
* Map canonical camelCase event names to Grok CLI PascalCase.
|
|
7098
|
+
* Grok Build reuses the same Claude-style PascalCase event names, so each
|
|
7099
|
+
* canonical arm maps to its PascalCase equivalent.
|
|
7100
|
+
* @see https://docs.x.ai/build/features/hooks
|
|
7101
|
+
*/
|
|
7102
|
+
const CANONICAL_TO_GROKCLI_EVENT_NAMES = {
|
|
7103
|
+
sessionStart: "SessionStart",
|
|
7104
|
+
sessionEnd: "SessionEnd",
|
|
7105
|
+
beforeSubmitPrompt: "UserPromptSubmit",
|
|
7106
|
+
preToolUse: "PreToolUse",
|
|
7107
|
+
postToolUse: "PostToolUse",
|
|
7108
|
+
postToolUseFailure: "PostToolUseFailure",
|
|
7109
|
+
permissionDenied: "PermissionDenied",
|
|
7110
|
+
stop: "Stop",
|
|
7111
|
+
stopFailure: "StopFailure",
|
|
7112
|
+
notification: "Notification",
|
|
7113
|
+
subagentStart: "SubagentStart",
|
|
7114
|
+
subagentStop: "SubagentStop",
|
|
7115
|
+
preCompact: "PreCompact",
|
|
7116
|
+
postCompact: "PostCompact"
|
|
7117
|
+
};
|
|
7118
|
+
/**
|
|
7119
|
+
* Map Grok CLI PascalCase event names to canonical camelCase.
|
|
7120
|
+
*/
|
|
7121
|
+
const GROKCLI_TO_CANONICAL_EVENT_NAMES = Object.fromEntries(Object.entries(CANONICAL_TO_GROKCLI_EVENT_NAMES).map(([k, v]) => [v, k]));
|
|
7041
7122
|
//#endregion
|
|
7042
7123
|
//#region src/features/hooks/tool-hooks-converter.ts
|
|
7043
7124
|
function isToolMatcherEntry(x) {
|
|
@@ -7562,7 +7643,8 @@ const AUGMENTCODE_CONVERTER_CONFIG = {
|
|
|
7562
7643
|
noMatcherEvents: /* @__PURE__ */ new Set([
|
|
7563
7644
|
"sessionStart",
|
|
7564
7645
|
"sessionEnd",
|
|
7565
|
-
"stop"
|
|
7646
|
+
"stop",
|
|
7647
|
+
"notification"
|
|
7566
7648
|
])
|
|
7567
7649
|
};
|
|
7568
7650
|
/**
|
|
@@ -8661,7 +8743,8 @@ const DEVIN_CONVERTER_CONFIG = {
|
|
|
8661
8743
|
"sessionStart",
|
|
8662
8744
|
"sessionEnd",
|
|
8663
8745
|
"stop",
|
|
8664
|
-
"beforeSubmitPrompt"
|
|
8746
|
+
"beforeSubmitPrompt",
|
|
8747
|
+
"postCompact"
|
|
8665
8748
|
])
|
|
8666
8749
|
};
|
|
8667
8750
|
/**
|
|
@@ -8970,6 +9053,167 @@ var GooseHooks = class GooseHooks extends ToolHooks {
|
|
|
8970
9053
|
}
|
|
8971
9054
|
};
|
|
8972
9055
|
//#endregion
|
|
9056
|
+
//#region src/constants/grokcli-paths.ts
|
|
9057
|
+
/**
|
|
9058
|
+
* Grok Build CLI (xAI) configuration-layout conventions.
|
|
9059
|
+
*
|
|
9060
|
+
* Single source of truth for where Grok Build expects its files. Grok Build
|
|
9061
|
+
* stores MCP servers (and other settings) in a `config.toml` under `.grok/`,
|
|
9062
|
+
* with project/global scopes resolved by the directory the CLI runs in
|
|
9063
|
+
* (`./.grok/config.toml` vs `~/.grok/config.toml`).
|
|
9064
|
+
*
|
|
9065
|
+
* Verified against `grok` 0.2.54 (`grok mcp add --help`, `grok mcp add`):
|
|
9066
|
+
* `-s project` writes `./.grok/config.toml`, `-s user` writes
|
|
9067
|
+
* `~/.grok/config.toml`, both as a TOML `[mcp_servers.<name>]` table.
|
|
9068
|
+
* @see https://docs.x.ai/build/overview
|
|
9069
|
+
*/
|
|
9070
|
+
/** Root directory for Grok Build configuration, relative to the scope root. */
|
|
9071
|
+
const GROKCLI_DIR = ".grok";
|
|
9072
|
+
/** MCP servers and other settings live in `config.toml` under `.grok/`. */
|
|
9073
|
+
const GROKCLI_MCP_FILE_NAME = "config.toml";
|
|
9074
|
+
/**
|
|
9075
|
+
* Shared Grok CLI config file (`config.toml`). MCP servers, the `[ui]`
|
|
9076
|
+
* permission mode, and other settings all live here; permissions reuse the same
|
|
9077
|
+
* file name as MCP since Grok consolidates everything into one config.
|
|
9078
|
+
*/
|
|
9079
|
+
const GROKCLI_CONFIG_FILE_NAME = "config.toml";
|
|
9080
|
+
/** Skills directory under `.grok/` (project: `./.grok/skills`, global: `~/.grok/skills`). */
|
|
9081
|
+
const GROKCLI_SKILLS_DIR_PATH = join(GROKCLI_DIR, "skills");
|
|
9082
|
+
/**
|
|
9083
|
+
* Hooks directory under `.grok/`. Grok Build discovers hook config files from
|
|
9084
|
+
* `.grok/hooks/*.json` (project) and `~/.grok/hooks/*.json` (global), each a
|
|
9085
|
+
* standalone JSON file using the Claude-Code-compatible nested `{ hooks: { … } }`
|
|
9086
|
+
* shape. rulesync writes all its hooks into a single `rulesync.json`.
|
|
9087
|
+
* @see https://docs.x.ai/build/features/hooks
|
|
9088
|
+
*/
|
|
9089
|
+
const GROKCLI_HOOKS_DIR_PATH = join(GROKCLI_DIR, "hooks");
|
|
9090
|
+
/** rulesync-managed Grok hooks file under `.grok/hooks/`. */
|
|
9091
|
+
const GROKCLI_HOOKS_FILE_NAME = "rulesync.json";
|
|
9092
|
+
/**
|
|
9093
|
+
* Subagents (agent profiles) directory under `.grok/`. Grok Build discovers
|
|
9094
|
+
* agent definitions from `.grok/agents/*.md` (project) and `~/.grok/agents/*.md`
|
|
9095
|
+
* (global), each a Markdown file with YAML frontmatter (verified via
|
|
9096
|
+
* `grok inspect`; format matches the bundled `~/.grok/bundled/agents/*.md`).
|
|
9097
|
+
*/
|
|
9098
|
+
const GROKCLI_AGENTS_DIR_PATH = join(GROKCLI_DIR, "agents");
|
|
9099
|
+
/**
|
|
9100
|
+
* Instruction file. Grok reads the AGENTS.md instruction-file family natively,
|
|
9101
|
+
* including the user-level `~/.grok/AGENTS.md` for global rules (verified via
|
|
9102
|
+
* `grok inspect`, consistent with the `.grok/` global discovery used by the
|
|
9103
|
+
* MCP/skills/subagents adapters).
|
|
9104
|
+
*/
|
|
9105
|
+
const GROKCLI_RULE_FILE_NAME = "AGENTS.md";
|
|
9106
|
+
//#endregion
|
|
9107
|
+
//#region src/features/hooks/grokcli-hooks.ts
|
|
9108
|
+
const GROKCLI_CONVERTER_CONFIG = {
|
|
9109
|
+
supportedEvents: GROKCLI_HOOK_EVENTS,
|
|
9110
|
+
canonicalToToolEventNames: CANONICAL_TO_GROKCLI_EVENT_NAMES,
|
|
9111
|
+
toolToCanonicalEventNames: GROKCLI_TO_CANONICAL_EVENT_NAMES,
|
|
9112
|
+
projectDirVar: "",
|
|
9113
|
+
supportedHookTypes: /* @__PURE__ */ new Set(["command"]),
|
|
9114
|
+
noMatcherEvents: /* @__PURE__ */ new Set([
|
|
9115
|
+
"sessionStart",
|
|
9116
|
+
"sessionEnd",
|
|
9117
|
+
"beforeSubmitPrompt",
|
|
9118
|
+
"stop",
|
|
9119
|
+
"stopFailure",
|
|
9120
|
+
"notification",
|
|
9121
|
+
"subagentStart",
|
|
9122
|
+
"subagentStop",
|
|
9123
|
+
"preCompact",
|
|
9124
|
+
"postCompact"
|
|
9125
|
+
])
|
|
9126
|
+
};
|
|
9127
|
+
/**
|
|
9128
|
+
* Hooks generator for Grok CLI (xAI Grok Build).
|
|
9129
|
+
*
|
|
9130
|
+
* Grok Build adopts a Claude-Code-compatible lifecycle hooks model: each event
|
|
9131
|
+
* maps to an array of `{ matcher?, hooks: [{ type, command, timeout? }] }`
|
|
9132
|
+
* matcher groups under a top-level `hooks` key. rulesync writes all its hooks
|
|
9133
|
+
* into a single standalone `rulesync.json` file discovered from
|
|
9134
|
+
* `.grok/hooks/*.json` (project) and `~/.grok/hooks/*.json` (global). The file
|
|
9135
|
+
* is dedicated to hooks and owned wholesale by rulesync, so it may be deleted
|
|
9136
|
+
* as an orphan.
|
|
9137
|
+
*
|
|
9138
|
+
* @see https://docs.x.ai/build/features/hooks
|
|
9139
|
+
*/
|
|
9140
|
+
var GrokcliHooks = class GrokcliHooks extends ToolHooks {
|
|
9141
|
+
constructor(params) {
|
|
9142
|
+
super({
|
|
9143
|
+
...params,
|
|
9144
|
+
fileContent: params.fileContent ?? "{}"
|
|
9145
|
+
});
|
|
9146
|
+
}
|
|
9147
|
+
static getSettablePaths(_options = {}) {
|
|
9148
|
+
return {
|
|
9149
|
+
relativeDirPath: GROKCLI_HOOKS_DIR_PATH,
|
|
9150
|
+
relativeFilePath: GROKCLI_HOOKS_FILE_NAME
|
|
9151
|
+
};
|
|
9152
|
+
}
|
|
9153
|
+
static async fromFile({ outputRoot = process.cwd(), validate = true, global = false }) {
|
|
9154
|
+
const paths = GrokcliHooks.getSettablePaths({ global });
|
|
9155
|
+
const fileContent = await readFileContentOrNull(join(outputRoot, paths.relativeDirPath, paths.relativeFilePath)) ?? "{\"hooks\":{}}";
|
|
9156
|
+
return new GrokcliHooks({
|
|
9157
|
+
outputRoot,
|
|
9158
|
+
relativeDirPath: paths.relativeDirPath,
|
|
9159
|
+
relativeFilePath: paths.relativeFilePath,
|
|
9160
|
+
fileContent,
|
|
9161
|
+
validate
|
|
9162
|
+
});
|
|
9163
|
+
}
|
|
9164
|
+
static async fromRulesyncHooks({ outputRoot = process.cwd(), rulesyncHooks, validate = true, global = false, logger }) {
|
|
9165
|
+
const paths = GrokcliHooks.getSettablePaths({ global });
|
|
9166
|
+
const filePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
9167
|
+
const config = rulesyncHooks.getJson();
|
|
9168
|
+
const grokHooks = canonicalToToolHooks({
|
|
9169
|
+
config,
|
|
9170
|
+
toolOverrideHooks: config.grokcli?.hooks,
|
|
9171
|
+
converterConfig: GROKCLI_CONVERTER_CONFIG,
|
|
9172
|
+
logger
|
|
9173
|
+
});
|
|
9174
|
+
await readOrInitializeFileContent(filePath, JSON.stringify({ hooks: {} }, null, 2));
|
|
9175
|
+
const fileContent = JSON.stringify({ hooks: grokHooks }, null, 2);
|
|
9176
|
+
return new GrokcliHooks({
|
|
9177
|
+
outputRoot,
|
|
9178
|
+
relativeDirPath: paths.relativeDirPath,
|
|
9179
|
+
relativeFilePath: paths.relativeFilePath,
|
|
9180
|
+
fileContent,
|
|
9181
|
+
validate
|
|
9182
|
+
});
|
|
9183
|
+
}
|
|
9184
|
+
toRulesyncHooks() {
|
|
9185
|
+
let parsed;
|
|
9186
|
+
try {
|
|
9187
|
+
parsed = JSON.parse(this.getFileContent());
|
|
9188
|
+
} catch (error) {
|
|
9189
|
+
throw new Error(`Failed to parse Grok hooks content in ${join(this.getRelativeDirPath(), this.getRelativeFilePath())}: ${formatError(error)}`, { cause: error });
|
|
9190
|
+
}
|
|
9191
|
+
const hooks = toolHooksToCanonical({
|
|
9192
|
+
hooks: isRecord(parsed) && isRecord(parsed.hooks) ? parsed.hooks : {},
|
|
9193
|
+
converterConfig: GROKCLI_CONVERTER_CONFIG
|
|
9194
|
+
});
|
|
9195
|
+
return this.toRulesyncHooksDefault({ fileContent: JSON.stringify({
|
|
9196
|
+
version: 1,
|
|
9197
|
+
hooks
|
|
9198
|
+
}, null, 2) });
|
|
9199
|
+
}
|
|
9200
|
+
validate() {
|
|
9201
|
+
return {
|
|
9202
|
+
success: true,
|
|
9203
|
+
error: null
|
|
9204
|
+
};
|
|
9205
|
+
}
|
|
9206
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
|
|
9207
|
+
return new GrokcliHooks({
|
|
9208
|
+
outputRoot,
|
|
9209
|
+
relativeDirPath,
|
|
9210
|
+
relativeFilePath,
|
|
9211
|
+
fileContent: JSON.stringify({ hooks: {} }, null, 2),
|
|
9212
|
+
validate: false
|
|
9213
|
+
});
|
|
9214
|
+
}
|
|
9215
|
+
};
|
|
9216
|
+
//#endregion
|
|
8973
9217
|
//#region src/features/hooks/hermesagent-hooks.ts
|
|
8974
9218
|
/**
|
|
8975
9219
|
* Canonical events that map to a Hermes tool-call event (`pre_tool_call` /
|
|
@@ -10176,9 +10420,9 @@ function reasonixHooksToCanonical(hooks) {
|
|
|
10176
10420
|
* Reasonix hooks live in a Claude-Code-style but standalone JSON file —
|
|
10177
10421
|
* `.reasonix/settings.json` (project) or `~/.reasonix/settings.json`
|
|
10178
10422
|
* (global) — separate from the `[permissions]`/`[[plugins]]` TOML config.
|
|
10179
|
-
*
|
|
10423
|
+
* All ten upstream events have a clean canonical equivalent and are mapped:
|
|
10180
10424
|
* PreToolUse/PostToolUse/UserPromptSubmit/Stop plus SessionStart/SessionEnd/
|
|
10181
|
-
* SubagentStop/PostLLMCall (see REASONIX_HOOK_EVENTS).
|
|
10425
|
+
* SubagentStop/PostLLMCall/Notification/PreCompact (see REASONIX_HOOK_EVENTS).
|
|
10182
10426
|
* @see https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/docs/DESKTOP_HOOKS.zh-CN.md
|
|
10183
10427
|
*/
|
|
10184
10428
|
var ReasonixHooks = class ReasonixHooks extends ToolHooks {
|
|
@@ -10766,6 +11010,17 @@ const toolHooksFactories = /* @__PURE__ */ new Map([
|
|
|
10766
11010
|
supportedEvents: REASONIX_HOOK_EVENTS,
|
|
10767
11011
|
supportedHookTypes: ["command"],
|
|
10768
11012
|
supportsMatcher: true
|
|
11013
|
+
}],
|
|
11014
|
+
["grokcli", {
|
|
11015
|
+
class: GrokcliHooks,
|
|
11016
|
+
meta: {
|
|
11017
|
+
supportsProject: true,
|
|
11018
|
+
supportsGlobal: true,
|
|
11019
|
+
supportsImport: true
|
|
11020
|
+
},
|
|
11021
|
+
supportedEvents: GROKCLI_HOOK_EVENTS,
|
|
11022
|
+
supportedHookTypes: ["command"],
|
|
11023
|
+
supportsMatcher: true
|
|
10769
11024
|
}]
|
|
10770
11025
|
]);
|
|
10771
11026
|
const hooksProcessorToolTargets = [...toolHooksFactories.entries()].filter(([, f]) => f.meta.supportsProject).map(([t]) => t);
|
|
@@ -13021,7 +13276,13 @@ var CodexcliMcp = class CodexcliMcp extends ToolMcp {
|
|
|
13021
13276
|
...rest,
|
|
13022
13277
|
validate: false
|
|
13023
13278
|
});
|
|
13024
|
-
|
|
13279
|
+
let toml;
|
|
13280
|
+
try {
|
|
13281
|
+
toml = smolToml.parse(this.fileContent);
|
|
13282
|
+
} catch (error) {
|
|
13283
|
+
throw new Error(`Failed to parse Codex CLI config at ${this.getFilePath()}: ${formatError(error)}`, { cause: error });
|
|
13284
|
+
}
|
|
13285
|
+
this.toml = toml;
|
|
13025
13286
|
if (rest.validate) {
|
|
13026
13287
|
const result = this.validate();
|
|
13027
13288
|
if (!result.success) throw result.error;
|
|
@@ -13057,7 +13318,12 @@ var CodexcliMcp = class CodexcliMcp extends ToolMcp {
|
|
|
13057
13318
|
const paths = this.getSettablePaths({ global });
|
|
13058
13319
|
const configTomlFilePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
13059
13320
|
const configTomlFileContent = await readFileContentOrNull(configTomlFilePath) ?? "";
|
|
13060
|
-
|
|
13321
|
+
let configToml;
|
|
13322
|
+
try {
|
|
13323
|
+
configToml = smolToml.parse(configTomlFileContent || smolToml.stringify({}));
|
|
13324
|
+
} catch (error) {
|
|
13325
|
+
throw new Error(`Failed to parse existing Codex CLI config at ${configTomlFilePath}: ${formatError(error)}`, { cause: error });
|
|
13326
|
+
}
|
|
13061
13327
|
const strippedMcpServers = rulesyncMcp.getMcpServers();
|
|
13062
13328
|
const rawMcpServers = rulesyncMcp.getJson().mcpServers;
|
|
13063
13329
|
const converted = convertToCodexFormat(Object.fromEntries(Object.entries(strippedMcpServers).map(([serverName, serverConfig]) => {
|
|
@@ -14031,47 +14297,6 @@ var GooseMcp = class GooseMcp extends ToolMcp {
|
|
|
14031
14297
|
}
|
|
14032
14298
|
};
|
|
14033
14299
|
//#endregion
|
|
14034
|
-
//#region src/constants/grokcli-paths.ts
|
|
14035
|
-
/**
|
|
14036
|
-
* Grok Build CLI (xAI) configuration-layout conventions.
|
|
14037
|
-
*
|
|
14038
|
-
* Single source of truth for where Grok Build expects its files. Grok Build
|
|
14039
|
-
* stores MCP servers (and other settings) in a `config.toml` under `.grok/`,
|
|
14040
|
-
* with project/global scopes resolved by the directory the CLI runs in
|
|
14041
|
-
* (`./.grok/config.toml` vs `~/.grok/config.toml`).
|
|
14042
|
-
*
|
|
14043
|
-
* Verified against `grok` 0.2.54 (`grok mcp add --help`, `grok mcp add`):
|
|
14044
|
-
* `-s project` writes `./.grok/config.toml`, `-s user` writes
|
|
14045
|
-
* `~/.grok/config.toml`, both as a TOML `[mcp_servers.<name>]` table.
|
|
14046
|
-
* @see https://docs.x.ai/build/overview
|
|
14047
|
-
*/
|
|
14048
|
-
/** Root directory for Grok Build configuration, relative to the scope root. */
|
|
14049
|
-
const GROKCLI_DIR = ".grok";
|
|
14050
|
-
/** MCP servers and other settings live in `config.toml` under `.grok/`. */
|
|
14051
|
-
const GROKCLI_MCP_FILE_NAME = "config.toml";
|
|
14052
|
-
/**
|
|
14053
|
-
* Shared Grok CLI config file (`config.toml`). MCP servers, the `[ui]`
|
|
14054
|
-
* permission mode, and other settings all live here; permissions reuse the same
|
|
14055
|
-
* file name as MCP since Grok consolidates everything into one config.
|
|
14056
|
-
*/
|
|
14057
|
-
const GROKCLI_CONFIG_FILE_NAME = "config.toml";
|
|
14058
|
-
/** Skills directory under `.grok/` (project: `./.grok/skills`, global: `~/.grok/skills`). */
|
|
14059
|
-
const GROKCLI_SKILLS_DIR_PATH = join(GROKCLI_DIR, "skills");
|
|
14060
|
-
/**
|
|
14061
|
-
* Subagents (agent profiles) directory under `.grok/`. Grok Build discovers
|
|
14062
|
-
* agent definitions from `.grok/agents/*.md` (project) and `~/.grok/agents/*.md`
|
|
14063
|
-
* (global), each a Markdown file with YAML frontmatter (verified via
|
|
14064
|
-
* `grok inspect`; format matches the bundled `~/.grok/bundled/agents/*.md`).
|
|
14065
|
-
*/
|
|
14066
|
-
const GROKCLI_AGENTS_DIR_PATH = join(GROKCLI_DIR, "agents");
|
|
14067
|
-
/**
|
|
14068
|
-
* Instruction file. Grok reads the AGENTS.md instruction-file family natively,
|
|
14069
|
-
* including the user-level `~/.grok/AGENTS.md` for global rules (verified via
|
|
14070
|
-
* `grok inspect`, consistent with the `.grok/` global discovery used by the
|
|
14071
|
-
* MCP/skills/subagents adapters).
|
|
14072
|
-
*/
|
|
14073
|
-
const GROKCLI_RULE_FILE_NAME = "AGENTS.md";
|
|
14074
|
-
//#endregion
|
|
14075
14300
|
//#region src/features/mcp/grokcli-mcp.ts
|
|
14076
14301
|
const MAX_REMOVE_EMPTY_ENTRIES_DEPTH = 32;
|
|
14077
14302
|
/**
|
|
@@ -14231,6 +14456,54 @@ function resolveHermesTimeout(config) {
|
|
|
14231
14456
|
if (typeof config.networkTimeout === "number") return config.networkTimeout;
|
|
14232
14457
|
}
|
|
14233
14458
|
/**
|
|
14459
|
+
* Copies the advanced Hermes-recognized per-server fields that have no canonical
|
|
14460
|
+
* alias — `auth` (`oauth` for OAuth 2.1/PKCE), mTLS `client_cert` (string PEM
|
|
14461
|
+
* path, or `[cert, key]`/`[cert, key, password]` list) and `client_key`,
|
|
14462
|
+
* `connect_timeout` (seconds), and `supports_parallel_tool_calls` — verbatim
|
|
14463
|
+
* from `source` to `target`. Field names are identical on both sides (the
|
|
14464
|
+
* canonical `McpServerSchema` is a `looseObject`), so this serves export and
|
|
14465
|
+
* import alike. See the Hermes mcp-config-reference.
|
|
14466
|
+
*/
|
|
14467
|
+
function copyHermesAdvancedFields(source, target) {
|
|
14468
|
+
if (typeof source.auth === "string") target.auth = source.auth;
|
|
14469
|
+
if (typeof source.client_cert === "string" || isStringArray(source.client_cert)) target.client_cert = source.client_cert;
|
|
14470
|
+
if (typeof source.client_key === "string") target.client_key = source.client_key;
|
|
14471
|
+
if (typeof source.connect_timeout === "number") target.connect_timeout = source.connect_timeout;
|
|
14472
|
+
if (typeof source.supports_parallel_tool_calls === "boolean") target.supports_parallel_tool_calls = source.supports_parallel_tool_calls;
|
|
14473
|
+
}
|
|
14474
|
+
/**
|
|
14475
|
+
* Builds Hermes's per-server `tools` block from a canonical server config. The
|
|
14476
|
+
* canonical `enabledTools`/`disabledTools` arrays become `include`/`exclude`,
|
|
14477
|
+
* and the boolean `promptsEnabled`/`resourcesEnabled` toggles become Hermes's
|
|
14478
|
+
* `prompts`/`resources` capability flags. Returns an empty object when the
|
|
14479
|
+
* server has no tool scoping (the caller omits the block in that case).
|
|
14480
|
+
*
|
|
14481
|
+
* Note: `promptsEnabled`/`resourcesEnabled` are canonical top-level keys rather
|
|
14482
|
+
* than a nested canonical `tools` object, because canonical `McpServerSchema.tools`
|
|
14483
|
+
* is reserved as a `string[]` (used by other tools) — reusing it for an object
|
|
14484
|
+
* would fail validation on the next `generate`.
|
|
14485
|
+
*/
|
|
14486
|
+
function buildHermesToolsBlock(config) {
|
|
14487
|
+
const tools = {};
|
|
14488
|
+
if (isStringArray(config.enabledTools)) tools.include = config.enabledTools;
|
|
14489
|
+
if (isStringArray(config.disabledTools)) tools.exclude = config.disabledTools;
|
|
14490
|
+
if (typeof config.promptsEnabled === "boolean") tools.prompts = config.promptsEnabled;
|
|
14491
|
+
if (typeof config.resourcesEnabled === "boolean") tools.resources = config.resourcesEnabled;
|
|
14492
|
+
return tools;
|
|
14493
|
+
}
|
|
14494
|
+
/**
|
|
14495
|
+
* Applies a Hermes per-server `tools` block back onto a canonical server config
|
|
14496
|
+
* (inverse of {@link buildHermesToolsBlock}): `include`/`exclude` become
|
|
14497
|
+
* `enabledTools`/`disabledTools`, and `prompts`/`resources` become the boolean
|
|
14498
|
+
* `promptsEnabled`/`resourcesEnabled` top-level toggles.
|
|
14499
|
+
*/
|
|
14500
|
+
function applyHermesToolsBlock(hermesTools, server) {
|
|
14501
|
+
if (isStringArray(hermesTools.include)) server.enabledTools = hermesTools.include;
|
|
14502
|
+
if (isStringArray(hermesTools.exclude)) server.disabledTools = hermesTools.exclude;
|
|
14503
|
+
if (typeof hermesTools.prompts === "boolean") server.promptsEnabled = hermesTools.prompts;
|
|
14504
|
+
if (typeof hermesTools.resources === "boolean") server.resourcesEnabled = hermesTools.resources;
|
|
14505
|
+
}
|
|
14506
|
+
/**
|
|
14234
14507
|
* Converts a single rulesync canonical MCP server into a Hermes `mcp_servers:` entry.
|
|
14235
14508
|
*
|
|
14236
14509
|
* Hermes is close to the MCP spec but not identical: `command` must be a single
|
|
@@ -14264,9 +14537,8 @@ function convertServerToHermes(config) {
|
|
|
14264
14537
|
if (config.disabled === true) out.enabled = false;
|
|
14265
14538
|
const timeout = resolveHermesTimeout(config);
|
|
14266
14539
|
if (timeout !== void 0) out.timeout = timeout;
|
|
14267
|
-
|
|
14268
|
-
|
|
14269
|
-
if (isStringArray(config.disabledTools)) tools.exclude = config.disabledTools;
|
|
14540
|
+
copyHermesAdvancedFields(config, out);
|
|
14541
|
+
const tools = buildHermesToolsBlock(config);
|
|
14270
14542
|
if (Object.keys(tools).length > 0) out.tools = tools;
|
|
14271
14543
|
return out;
|
|
14272
14544
|
}
|
|
@@ -14309,10 +14581,8 @@ function convertFromHermesFormat(mcpServers) {
|
|
|
14309
14581
|
if (isPlainObject$1(config.headers)) server.headers = omitPrototypePollutionKeys(config.headers);
|
|
14310
14582
|
if (config.enabled === false) server.disabled = true;
|
|
14311
14583
|
if (typeof config.timeout === "number") server.networkTimeout = config.timeout;
|
|
14312
|
-
|
|
14313
|
-
|
|
14314
|
-
if (isStringArray(config.tools.exclude)) server.disabledTools = config.tools.exclude;
|
|
14315
|
-
}
|
|
14584
|
+
copyHermesAdvancedFields(config, server);
|
|
14585
|
+
if (isRecord(config.tools)) applyHermesToolsBlock(config.tools, server);
|
|
14316
14586
|
result[name] = server;
|
|
14317
14587
|
}
|
|
14318
14588
|
return result;
|
|
@@ -16607,18 +16877,27 @@ const CursorPermissionsOverrideSchema = z.looseObject({
|
|
|
16607
16877
|
* Tool-scoped override block for Qwen Code. Qwen's `settings.json` exposes
|
|
16608
16878
|
* autonomy/sandbox controls with no canonical permission category — under
|
|
16609
16879
|
* `tools` (`approvalMode` = plan/default/auto-edit/auto/yolo, `autoAccept`,
|
|
16610
|
-
* `sandbox`, `sandboxImage`, `disabled`) and `security` (`folderTrust`).
|
|
16611
|
-
*
|
|
16612
|
-
*
|
|
16613
|
-
*
|
|
16614
|
-
*
|
|
16880
|
+
* `sandbox`, `sandboxImage`, `disabled`) and `security` (`folderTrust`). It also
|
|
16881
|
+
* exposes `permissions.autoMode` (the Auto Mode classifier config:
|
|
16882
|
+
* `hints.{allow,softDeny,hardDeny}`, `environment`, `classifyAllShell` — see
|
|
16883
|
+
* https://qwenlm.github.io/qwen-code-docs/en/users/features/auto-mode/), which
|
|
16884
|
+
* likewise has no canonical category. Fields placed here are merged into the
|
|
16885
|
+
* matching `settings.json` group and emitted only for Qwen, while the shared
|
|
16886
|
+
* `permission` block continues to drive the `permissions.allow`/`ask`/`deny`
|
|
16887
|
+
* arrays. Kept `looseObject` (verbatim passthrough) so any current or future
|
|
16888
|
+
* `tools`/`security`/`autoMode` key can be authored.
|
|
16615
16889
|
*
|
|
16616
16890
|
* @example
|
|
16617
|
-
* {
|
|
16891
|
+
* {
|
|
16892
|
+
* "tools": { "approvalMode": "auto-edit" },
|
|
16893
|
+
* "security": { "folderTrust": { "enabled": true } },
|
|
16894
|
+
* "autoMode": { "hints": { "allow": ["Running tests"] }, "classifyAllShell": true }
|
|
16895
|
+
* }
|
|
16618
16896
|
*/
|
|
16619
16897
|
const QwencodePermissionsOverrideSchema = z.looseObject({
|
|
16620
16898
|
tools: z.optional(z.looseObject({})),
|
|
16621
|
-
security: z.optional(z.looseObject({}))
|
|
16899
|
+
security: z.optional(z.looseObject({})),
|
|
16900
|
+
autoMode: z.optional(z.looseObject({}))
|
|
16622
16901
|
});
|
|
16623
16902
|
/**
|
|
16624
16903
|
* Tool-scoped override block for Reasonix. Reasonix has security axes orthogonal
|
|
@@ -16645,9 +16924,11 @@ const ReasonixPermissionsOverrideSchema = z.looseObject({
|
|
|
16645
16924
|
* exposes security controls with no canonical per-command allow/ask/deny slot —
|
|
16646
16925
|
* `commandBlocklist` (a hard-block tier that can never be approved, distinct from
|
|
16647
16926
|
* an approvable `deny`), `networkPolicy` (`allowedIps`), `sandbox`
|
|
16648
|
-
* (`enabled`/`mode`/`filesystem`/`network`), `mcpPolicy`,
|
|
16927
|
+
* (`enabled`/`mode`/`filesystem`/`network`), `mcpPolicy`,
|
|
16928
|
+
* `mcpAutonomyOverrides` (per-MCP-tool autonomy levels), `enableDroidShield`,
|
|
16649
16929
|
* and autonomy settings (`sessionDefaultSettings`, `maxAutonomyLevel`,
|
|
16650
|
-
* `interactionMode`). Fields placed here are merged
|
|
16930
|
+
* `subagentAutonomyLevel`, `interactionMode`). Fields placed here are merged
|
|
16931
|
+
* into `settings.json` and
|
|
16651
16932
|
* emitted only for Factory Droid, while the shared `permission` block continues
|
|
16652
16933
|
* to drive `commandAllowlist`/`commandDenylist`. Kept `looseObject` passthrough.
|
|
16653
16934
|
*
|
|
@@ -16840,6 +17121,41 @@ const KiroPermissionsOverrideSchema = z.looseObject({ toolsSettings: z.optional(
|
|
|
16840
17121
|
}))
|
|
16841
17122
|
})) });
|
|
16842
17123
|
/**
|
|
17124
|
+
* Codex CLI's approval-workflow policy. Serialized as a kebab-case string in
|
|
17125
|
+
* `.codex/config.toml`. `on-failure` is a legacy alias for `on-request` that
|
|
17126
|
+
* Codex still accepts, so it is included so existing configs round-trip. The
|
|
17127
|
+
* granular table form (`{ granular = { … } }`) is modeled separately in the
|
|
17128
|
+
* override union.
|
|
17129
|
+
* @see https://learn.chatgpt.com/docs/config-file/config-reference
|
|
17130
|
+
*/
|
|
17131
|
+
const CodexApprovalPolicySchema = z.enum([
|
|
17132
|
+
"untrusted",
|
|
17133
|
+
"on-request",
|
|
17134
|
+
"on-failure",
|
|
17135
|
+
"never"
|
|
17136
|
+
]);
|
|
17137
|
+
/**
|
|
17138
|
+
* Codex CLI's classic sandbox mode. Serialized as a kebab-case string in
|
|
17139
|
+
* `.codex/config.toml`.
|
|
17140
|
+
* @see https://learn.chatgpt.com/docs/config-file/config-reference
|
|
17141
|
+
*/
|
|
17142
|
+
const CodexSandboxModeSchema = z.enum([
|
|
17143
|
+
"read-only",
|
|
17144
|
+
"workspace-write",
|
|
17145
|
+
"danger-full-access"
|
|
17146
|
+
]);
|
|
17147
|
+
/**
|
|
17148
|
+
* Codex CLI's reviewer for approval requests. `guardian_subagent` is a legacy
|
|
17149
|
+
* value Codex still accepts for backward compatibility, so it is included so
|
|
17150
|
+
* existing configs round-trip through the rulesync model.
|
|
17151
|
+
* @see https://learn.chatgpt.com/docs/config-file/config-reference
|
|
17152
|
+
*/
|
|
17153
|
+
const CodexApprovalsReviewerSchema = z.enum([
|
|
17154
|
+
"user",
|
|
17155
|
+
"auto_review",
|
|
17156
|
+
"guardian_subagent"
|
|
17157
|
+
]);
|
|
17158
|
+
/**
|
|
16843
17159
|
* Codex CLI-scoped permission override.
|
|
16844
17160
|
*
|
|
16845
17161
|
* Codex CLI's permission surface is richer than the canonical allow/ask/deny
|
|
@@ -16848,15 +17164,16 @@ const KiroPermissionsOverrideSchema = z.looseObject({ toolsSettings: z.optional(
|
|
|
16848
17164
|
* override whose fields are written verbatim as top-level `.codex/config.toml`
|
|
16849
17165
|
* keys (the override wins per key; existing sibling keys the user set directly
|
|
16850
17166
|
* are preserved):
|
|
16851
|
-
* - `approval_policy` — `untrusted` | `on-request`
|
|
16852
|
-
* `{ granular = { … } }` table (kept verbatim; the granular
|
|
16853
|
-
* required fields that are brittle to model as typed keys).
|
|
17167
|
+
* - `approval_policy` — `untrusted` | `on-request` (legacy alias `on-failure`) |
|
|
17168
|
+
* `never`, or a `{ granular = { … } }` table (kept verbatim; the granular
|
|
17169
|
+
* schema has required fields that are brittle to model as typed keys).
|
|
16854
17170
|
* - `sandbox_mode` — `read-only` | `workspace-write` | `danger-full-access`,
|
|
16855
17171
|
* with the sibling `sandbox_workspace_write` table (`network_access`,
|
|
16856
17172
|
* `writable_roots`, …).
|
|
16857
17173
|
* - `apps` — per-app tool gating (`apps.<id>.tools.<tool>.approval_mode` /
|
|
16858
17174
|
* `.enabled`, `apps.<id>.default_tools_approval_mode`).
|
|
16859
|
-
* - `approvals_reviewer` — the reviewer-approval surface
|
|
17175
|
+
* - `approvals_reviewer` — the reviewer-approval surface (`user` | `auto_review`
|
|
17176
|
+
* | `guardian_subagent`), or a table for the richer reviewer config.
|
|
16860
17177
|
*
|
|
16861
17178
|
* Two surfaces are deliberately NOT authorable here so the override can never
|
|
16862
17179
|
* clobber a feature-owned key: `mcp_servers.*` per-MCP gating is owned by the
|
|
@@ -16874,11 +17191,11 @@ const KiroPermissionsOverrideSchema = z.looseObject({ toolsSettings: z.optional(
|
|
|
16874
17191
|
* "sandbox_workspace_write": { "network_access": true } }
|
|
16875
17192
|
*/
|
|
16876
17193
|
const CodexcliPermissionsOverrideSchema = z.looseObject({
|
|
16877
|
-
approval_policy: z.optional(z.union([
|
|
16878
|
-
sandbox_mode: z.optional(
|
|
17194
|
+
approval_policy: z.optional(z.union([CodexApprovalPolicySchema, z.looseObject({})])),
|
|
17195
|
+
sandbox_mode: z.optional(CodexSandboxModeSchema),
|
|
16879
17196
|
sandbox_workspace_write: z.optional(z.looseObject({})),
|
|
16880
17197
|
apps: z.optional(z.looseObject({})),
|
|
16881
|
-
approvals_reviewer: z.optional(z.union([
|
|
17198
|
+
approvals_reviewer: z.optional(z.union([CodexApprovalsReviewerSchema, z.looseObject({})]))
|
|
16882
17199
|
});
|
|
16883
17200
|
/**
|
|
16884
17201
|
* Permissions configuration.
|
|
@@ -19739,9 +20056,11 @@ const FACTORYDROID_OVERRIDE_KEYS = [
|
|
|
19739
20056
|
"networkPolicy",
|
|
19740
20057
|
"sandbox",
|
|
19741
20058
|
"mcpPolicy",
|
|
20059
|
+
"mcpAutonomyOverrides",
|
|
19742
20060
|
"enableDroidShield",
|
|
19743
20061
|
"sessionDefaultSettings",
|
|
19744
20062
|
"maxAutonomyLevel",
|
|
20063
|
+
"subagentAutonomyLevel",
|
|
19745
20064
|
"interactionMode"
|
|
19746
20065
|
];
|
|
19747
20066
|
/**
|
|
@@ -20099,7 +20418,6 @@ function convertGoosePermissionConfigToRulesync(userPermission) {
|
|
|
20099
20418
|
}
|
|
20100
20419
|
//#endregion
|
|
20101
20420
|
//#region src/features/permissions/grokcli-permissions.ts
|
|
20102
|
-
const GROKCLI_GLOBAL_ONLY_MESSAGE = "Grok CLI permissions are global-only; use --global to sync ~/.grok/config.toml";
|
|
20103
20421
|
const GROKCLI_UI_KEY = "ui";
|
|
20104
20422
|
const GROKCLI_PERMISSION_MODE_KEY = "permission_mode";
|
|
20105
20423
|
const GROKCLI_PERMISSION_KEY = "permission";
|
|
@@ -20201,13 +20519,19 @@ function parseGrokEntry(entry) {
|
|
|
20201
20519
|
* compatibility with older Grok versions: `always-approve` when the config is
|
|
20202
20520
|
* pure-`allow`, otherwise `ask` (conservative — it is never `always-approve`
|
|
20203
20521
|
* while any `deny`/`ask` rule exists, so it never contradicts the fine-grained
|
|
20204
|
-
* arrays).
|
|
20205
|
-
*
|
|
20206
|
-
*
|
|
20207
|
-
*
|
|
20208
|
-
*
|
|
20522
|
+
* arrays). It is a user-level UI setting, so it is only written in global scope
|
|
20523
|
+
* (see below).
|
|
20524
|
+
*
|
|
20525
|
+
* Both scopes are supported: the adapter syncs the project-level
|
|
20526
|
+
* `./.grok/config.toml` (default) and the user-level `~/.grok/config.toml`
|
|
20527
|
+
* (with `--global`). Grok documents that "Project configs are limited to MCP
|
|
20528
|
+
* servers, plugins, and permission rules, not full user configs"
|
|
20529
|
+
* (https://docs.x.ai/build/settings), so the project config carries only the
|
|
20530
|
+
* fine-grained `[permission]` rules; the coarse `[ui] permission_mode` UI toggle
|
|
20531
|
+
* is written in global scope only. The shared config is merged in
|
|
20209
20532
|
* place: rulesync owns the `[permission]` `allow`/`deny`/`ask` entries for the
|
|
20210
|
-
* tools it models and the `[ui] permission_mode` value, while
|
|
20533
|
+
* tools it models and (in global scope) the `[ui] permission_mode` value, while
|
|
20534
|
+
* every other key
|
|
20211
20535
|
* (e.g. `[mcp_servers]`, `[permission] rules`, `[sandbox]`) and any user-authored
|
|
20212
20536
|
* entries for tools rulesync cannot model (e.g. `WebSearch`) are preserved. The
|
|
20213
20537
|
* file is never deleted.
|
|
@@ -20229,7 +20553,6 @@ var GrokcliPermissions = class GrokcliPermissions extends ToolPermissions {
|
|
|
20229
20553
|
};
|
|
20230
20554
|
}
|
|
20231
20555
|
static async fromFile({ outputRoot = process.cwd(), validate = true, global = false }) {
|
|
20232
|
-
if (!global) throw new Error(GROKCLI_GLOBAL_ONLY_MESSAGE);
|
|
20233
20556
|
const paths = GrokcliPermissions.getSettablePaths({ global });
|
|
20234
20557
|
const fileContent = await readFileContentOrNull(join(outputRoot, paths.relativeDirPath, paths.relativeFilePath)) ?? "";
|
|
20235
20558
|
return new GrokcliPermissions({
|
|
@@ -20238,11 +20561,10 @@ var GrokcliPermissions = class GrokcliPermissions extends ToolPermissions {
|
|
|
20238
20561
|
relativeFilePath: paths.relativeFilePath,
|
|
20239
20562
|
fileContent,
|
|
20240
20563
|
validate,
|
|
20241
|
-
global
|
|
20564
|
+
global
|
|
20242
20565
|
});
|
|
20243
20566
|
}
|
|
20244
20567
|
static async fromRulesyncPermissions({ outputRoot = process.cwd(), rulesyncPermissions, logger, global = false }) {
|
|
20245
|
-
if (!global) throw new Error(GROKCLI_GLOBAL_ONLY_MESSAGE);
|
|
20246
20568
|
const paths = GrokcliPermissions.getSettablePaths({ global });
|
|
20247
20569
|
const filePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
20248
20570
|
const existingContent = await readFileContentOrNull(filePath) ?? "";
|
|
@@ -20261,11 +20583,10 @@ var GrokcliPermissions = class GrokcliPermissions extends ToolPermissions {
|
|
|
20261
20583
|
deny: buckets.deny,
|
|
20262
20584
|
ask: buckets.ask
|
|
20263
20585
|
};
|
|
20264
|
-
const
|
|
20265
|
-
const ui = {
|
|
20586
|
+
const uiPatch = global ? { [GROKCLI_UI_KEY]: {
|
|
20266
20587
|
...isRecord(parsed[GROKCLI_UI_KEY]) ? parsed[GROKCLI_UI_KEY] : {},
|
|
20267
|
-
[GROKCLI_PERMISSION_MODE_KEY]:
|
|
20268
|
-
};
|
|
20588
|
+
[GROKCLI_PERMISSION_MODE_KEY]: deriveGrokPermissionMode(config)
|
|
20589
|
+
} } : {};
|
|
20269
20590
|
return new GrokcliPermissions({
|
|
20270
20591
|
outputRoot,
|
|
20271
20592
|
relativeDirPath: paths.relativeDirPath,
|
|
@@ -20276,12 +20597,12 @@ var GrokcliPermissions = class GrokcliPermissions extends ToolPermissions {
|
|
|
20276
20597
|
existingContent,
|
|
20277
20598
|
patch: {
|
|
20278
20599
|
[GROKCLI_PERMISSION_KEY]: permission,
|
|
20279
|
-
|
|
20600
|
+
...uiPatch
|
|
20280
20601
|
},
|
|
20281
20602
|
filePath
|
|
20282
20603
|
}),
|
|
20283
20604
|
validate: true,
|
|
20284
|
-
global
|
|
20605
|
+
global
|
|
20285
20606
|
});
|
|
20286
20607
|
}
|
|
20287
20608
|
toRulesyncPermissions() {
|
|
@@ -20302,14 +20623,14 @@ var GrokcliPermissions = class GrokcliPermissions extends ToolPermissions {
|
|
|
20302
20623
|
error: null
|
|
20303
20624
|
};
|
|
20304
20625
|
}
|
|
20305
|
-
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
|
|
20626
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
|
|
20306
20627
|
return new GrokcliPermissions({
|
|
20307
20628
|
outputRoot,
|
|
20308
20629
|
relativeDirPath,
|
|
20309
20630
|
relativeFilePath,
|
|
20310
20631
|
fileContent: "",
|
|
20311
20632
|
validate: false,
|
|
20312
|
-
global
|
|
20633
|
+
global
|
|
20313
20634
|
});
|
|
20314
20635
|
}
|
|
20315
20636
|
};
|
|
@@ -21224,6 +21545,22 @@ const CANONICAL_PERMISSION_CATEGORIES = /* @__PURE__ */ new Set([
|
|
|
21224
21545
|
"notebookedit",
|
|
21225
21546
|
"agent"
|
|
21226
21547
|
]);
|
|
21548
|
+
/**
|
|
21549
|
+
* Translate between rulesync's canonical permission category names and
|
|
21550
|
+
* OpenCode's native permission keys. OpenCode has no `agent` key — subagent
|
|
21551
|
+
* launches are gated by the `task` key (see the documented key list at
|
|
21552
|
+
* https://opencode.ai/docs/permissions/). Without this translation a canonical
|
|
21553
|
+
* `agent: deny` would be written verbatim into `opencode.json` and silently
|
|
21554
|
+
* ignored by OpenCode. Unknown names pass through unchanged.
|
|
21555
|
+
*/
|
|
21556
|
+
const CANONICAL_TO_OPENCODE_PERMISSION_KEYS = { agent: "task" };
|
|
21557
|
+
const OPENCODE_TO_CANONICAL_PERMISSION_KEYS = Object.fromEntries(Object.entries(CANONICAL_TO_OPENCODE_PERMISSION_KEYS).map(([canonical, opencode]) => [opencode, canonical]));
|
|
21558
|
+
function toOpencodePermissionKey(canonical) {
|
|
21559
|
+
return CANONICAL_TO_OPENCODE_PERMISSION_KEYS[canonical] ?? canonical;
|
|
21560
|
+
}
|
|
21561
|
+
function toCanonicalPermissionKey(opencodeKey) {
|
|
21562
|
+
return OPENCODE_TO_CANONICAL_PERMISSION_KEYS[opencodeKey] ?? opencodeKey;
|
|
21563
|
+
}
|
|
21227
21564
|
function isSharedPermissionCategory(category) {
|
|
21228
21565
|
return category === "*" || CANONICAL_PERMISSION_CATEGORIES.has(category) || category.startsWith("mcp__");
|
|
21229
21566
|
}
|
|
@@ -21290,6 +21627,8 @@ var OpencodePermissions = class OpencodePermissions extends ToolPermissions {
|
|
|
21290
21627
|
}
|
|
21291
21628
|
const rulesyncJson = rulesyncPermissions.getJson();
|
|
21292
21629
|
const overridePermission = rulesyncJson.opencode?.permission ?? {};
|
|
21630
|
+
const sharedPermission = {};
|
|
21631
|
+
for (const [category, value] of Object.entries(rulesyncJson.permission ?? {})) sharedPermission[toOpencodePermissionKey(category)] = value;
|
|
21293
21632
|
return new OpencodePermissions({
|
|
21294
21633
|
outputRoot,
|
|
21295
21634
|
relativeDirPath: basePaths.relativeDirPath,
|
|
@@ -21299,7 +21638,7 @@ var OpencodePermissions = class OpencodePermissions extends ToolPermissions {
|
|
|
21299
21638
|
feature: "permissions",
|
|
21300
21639
|
existingContent: fileContent ?? "",
|
|
21301
21640
|
patch: { permission: {
|
|
21302
|
-
...
|
|
21641
|
+
...sharedPermission,
|
|
21303
21642
|
...overridePermission
|
|
21304
21643
|
} },
|
|
21305
21644
|
filePath: join(jsonDir, relativeFilePath)
|
|
@@ -21315,8 +21654,11 @@ var OpencodePermissions = class OpencodePermissions extends ToolPermissions {
|
|
|
21315
21654
|
}
|
|
21316
21655
|
const shared = {};
|
|
21317
21656
|
const overrideOnly = {};
|
|
21318
|
-
for (const [category, value] of Object.entries(rawPermission))
|
|
21319
|
-
|
|
21657
|
+
for (const [category, value] of Object.entries(rawPermission)) {
|
|
21658
|
+
const canonicalCategory = toCanonicalPermissionKey(category);
|
|
21659
|
+
if (isSharedPermissionCategory(canonicalCategory)) shared[canonicalCategory] = typeof value === "string" ? { "*": value } : value;
|
|
21660
|
+
else overrideOnly[category] = value;
|
|
21661
|
+
}
|
|
21320
21662
|
const json = Object.keys(overrideOnly).length > 0 ? {
|
|
21321
21663
|
permission: shared,
|
|
21322
21664
|
opencode: { permission: overrideOnly }
|
|
@@ -21441,6 +21783,7 @@ const QWEN_OVERRIDE_TOOLS_KEYS = [
|
|
|
21441
21783
|
"disabled"
|
|
21442
21784
|
];
|
|
21443
21785
|
const QWEN_OVERRIDE_SECURITY_KEYS = ["folderTrust"];
|
|
21786
|
+
const QWEN_OVERRIDE_PERMISSIONS_KEYS = ["autoMode"];
|
|
21444
21787
|
function asPlainRecord(value) {
|
|
21445
21788
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
21446
21789
|
}
|
|
@@ -21512,8 +21855,9 @@ var QwencodePermissions = class QwencodePermissions extends ToolPermissions {
|
|
|
21512
21855
|
else delete mergedPermissions.ask;
|
|
21513
21856
|
if (mergedDeny.length > 0) mergedPermissions.deny = mergedDeny;
|
|
21514
21857
|
else delete mergedPermissions.deny;
|
|
21515
|
-
const patch = { permissions: mergedPermissions };
|
|
21516
21858
|
const override = config.qwencode;
|
|
21859
|
+
if (override?.autoMode !== void 0) mergedPermissions.autoMode = override.autoMode;
|
|
21860
|
+
const patch = { permissions: mergedPermissions };
|
|
21517
21861
|
if (override?.tools !== void 0) patch.tools = {
|
|
21518
21862
|
...asPlainRecord(settings.tools),
|
|
21519
21863
|
...asPlainRecord(override.tools)
|
|
@@ -21555,9 +21899,11 @@ var QwencodePermissions = class QwencodePermissions extends ToolPermissions {
|
|
|
21555
21899
|
});
|
|
21556
21900
|
const overrideTools = pickQwenOverrideKeys(settings.tools, QWEN_OVERRIDE_TOOLS_KEYS);
|
|
21557
21901
|
const overrideSecurity = pickQwenOverrideKeys(settings.security, QWEN_OVERRIDE_SECURITY_KEYS);
|
|
21902
|
+
const overridePermissions = pickQwenOverrideKeys(settings.permissions, QWEN_OVERRIDE_PERMISSIONS_KEYS);
|
|
21558
21903
|
const qwencodeOverride = {};
|
|
21559
21904
|
if (Object.keys(overrideTools).length > 0) qwencodeOverride.tools = overrideTools;
|
|
21560
21905
|
if (Object.keys(overrideSecurity).length > 0) qwencodeOverride.security = overrideSecurity;
|
|
21906
|
+
if (overridePermissions.autoMode !== void 0) qwencodeOverride.autoMode = overridePermissions.autoMode;
|
|
21561
21907
|
const result = { ...config };
|
|
21562
21908
|
if (Object.keys(qwencodeOverride).length > 0) result.qwencode = qwencodeOverride;
|
|
21563
21909
|
return this.toRulesyncPermissionsDefault({ fileContent: JSON.stringify(result, null, 2) });
|
|
@@ -23066,7 +23412,7 @@ const toolPermissionsFactories = /* @__PURE__ */ new Map([
|
|
|
23066
23412
|
["grokcli", {
|
|
23067
23413
|
class: GrokcliPermissions,
|
|
23068
23414
|
meta: {
|
|
23069
|
-
supportsProject:
|
|
23415
|
+
supportsProject: true,
|
|
23070
23416
|
supportsGlobal: true,
|
|
23071
23417
|
supportsImport: true
|
|
23072
23418
|
}
|
|
@@ -39591,4 +39937,4 @@ async function importPermissionsCore(params) {
|
|
|
39591
39937
|
//#endregion
|
|
39592
39938
|
export { removeTempDirectory as $, RulesyncCommand as A, checkPathTraversal as B, RulesyncHooks as C, RULESYNC_RULES_RELATIVE_DIR_PATH as Ct, CLAUDECODE_MEMORIES_DIR_NAME as D, formatError as Dt, CLAUDECODE_LOCAL_RULE_FILE_NAME as E, RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH as Et, findControlCharacter as F, findFilesByGlobs as G, directoryExists as H, ConsoleLogger as I, isSymlink as J, getFileSize as K, JsonLogger as L, stringifyFrontmatter as M, loadYaml as N, CLAUDECODE_SETTINGS_LOCAL_FILE_NAME as O, ALL_FEATURES as Ot, ConfigResolver as P, removeFile as Q, CLIError as R, HooksProcessor as S, RULESYNC_RELATIVE_DIR_PATH as St, CLAUDECODE_DIR as T, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH as Tt, ensureDir as U, createTempDirectory as V, fileExists as W, readFileContent as X, listDirectoryFiles as Y, removeDirectory as Z, RulesyncPermissions as _, RULESYNC_MCP_RELATIVE_FILE_PATH as _t, convertFromTool as a, MAX_FILE_SIZE as at, IgnoreProcessor as b, RULESYNC_PERMISSIONS_FILE_NAME as bt, RulesyncRuleFrontmatterSchema as c, RULESYNC_COMMANDS_RELATIVE_DIR_PATH as ct, RulesyncSubagentFrontmatterSchema as d, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH as dt, toPosixPath as et, SkillsProcessor as f, RULESYNC_HOOKS_FILE_NAME as ft, SKILL_FILE_NAME as g, RULESYNC_MCP_FILE_NAME as gt, RulesyncSkillFrontmatterSchema as h, RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH as ht, getProcessorRegistryEntry as i, ToolTargetSchema as it, RulesyncCommandFrontmatterSchema as j, CLAUDECODE_SKILLS_DIR_PATH as k, ALL_FEATURES_WITH_WILDCARD as kt, SubagentsProcessor as l, RULESYNC_CONFIG_RELATIVE_FILE_PATH as lt, RulesyncSkill as m, RULESYNC_IGNORE_RELATIVE_FILE_PATH as mt, checkRulesyncDirExists as n, ALL_TOOL_TARGETS as nt, RulesProcessor as o, RULESYNC_AIIGNORE_FILE_NAME as ot, getLocalSkillDirNames as p, RULESYNC_HOOKS_RELATIVE_FILE_PATH as pt, getHomeDirectory as q, generate as r, ALL_TOOL_TARGETS_WITH_WILDCARD as rt, RulesyncRule as s, RULESYNC_AIIGNORE_RELATIVE_FILE_PATH as st, importFromTool as t, writeFileContent as tt, RulesyncSubagent as u, RULESYNC_CONFIG_SCHEMA_URL as ut, McpProcessor as v, RULESYNC_MCP_SCHEMA_URL as vt, CommandsProcessor as w, RULESYNC_SKILLS_RELATIVE_DIR_PATH as wt, RulesyncIgnore as x, RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH as xt, RulesyncMcp as y, RULESYNC_OVERVIEW_FILE_NAME as yt, ErrorCodes as z };
|
|
39593
39939
|
|
|
39594
|
-
//# sourceMappingURL=import-
|
|
39940
|
+
//# sourceMappingURL=import-Dioh9ca8.js.map
|