rulesync 16.3.0 → 16.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.cjs +201 -3
- package/dist/cli/index.js +201 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/{import-Bj5HxY9p.js → import-BwakMyyf.js} +177 -107
- package/dist/import-BwakMyyf.js.map +1 -0
- package/dist/{import-DD-GRmB9.cjs → import-C9wxpZey.cjs} +187 -105
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/package.json +5 -2
- package/dist/import-Bj5HxY9p.js.map +0 -1
|
@@ -2356,6 +2356,7 @@ const PI_HOOK_EVENTS = [
|
|
|
2356
2356
|
"preToolUse",
|
|
2357
2357
|
"postToolUse",
|
|
2358
2358
|
"preModelInvocation",
|
|
2359
|
+
"postModelInvocation",
|
|
2359
2360
|
"beforeSubmitPrompt",
|
|
2360
2361
|
"stop",
|
|
2361
2362
|
"preCompact",
|
|
@@ -3062,6 +3063,7 @@ const CANONICAL_TO_PI_EVENT_NAMES = {
|
|
|
3062
3063
|
preToolUse: "tool_call",
|
|
3063
3064
|
postToolUse: "tool_result",
|
|
3064
3065
|
preModelInvocation: "context",
|
|
3066
|
+
postModelInvocation: "message_end",
|
|
3065
3067
|
beforeSubmitPrompt: "input",
|
|
3066
3068
|
stop: "agent_end",
|
|
3067
3069
|
preCompact: "session_before_compact",
|
|
@@ -6827,24 +6829,14 @@ const SHARED_CONFIG_OWNERSHIP = {
|
|
|
6827
6829
|
},
|
|
6828
6830
|
".devin/config.json": {
|
|
6829
6831
|
format: "json",
|
|
6830
|
-
features: {
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
},
|
|
6835
|
-
permissions: {
|
|
6836
|
-
kind: "replace-owned-keys",
|
|
6837
|
-
ownedKeys: ["permissions"]
|
|
6838
|
-
}
|
|
6839
|
-
}
|
|
6832
|
+
features: { permissions: {
|
|
6833
|
+
kind: "replace-owned-keys",
|
|
6834
|
+
ownedKeys: ["permissions"]
|
|
6835
|
+
} }
|
|
6840
6836
|
},
|
|
6841
6837
|
".config/devin/config.json": {
|
|
6842
6838
|
format: "json",
|
|
6843
6839
|
features: {
|
|
6844
|
-
mcp: {
|
|
6845
|
-
kind: "replace-owned-keys",
|
|
6846
|
-
ownedKeys: ["mcpServers"]
|
|
6847
|
-
},
|
|
6848
6840
|
hooks: {
|
|
6849
6841
|
kind: "replace-owned-keys",
|
|
6850
6842
|
ownedKeys: ["hooks"]
|
|
@@ -9044,6 +9036,7 @@ const DEVIN_GLOBAL_CONFIG_DIR_PATH = join(".config", "devin");
|
|
|
9044
9036
|
const DEVIN_GLOBAL_AGENTS_DIR_PATH = join(DEVIN_GLOBAL_CONFIG_DIR_PATH, "agents");
|
|
9045
9037
|
const DEVIN_GLOBAL_SKILLS_DIR_PATH = join(DEVIN_GLOBAL_CONFIG_DIR_PATH, "skills");
|
|
9046
9038
|
const DEVIN_CONFIG_FILE_NAME = "config.json";
|
|
9039
|
+
const DEVIN_MCP_CONFIG_FILE_NAME = "mcp_config.json";
|
|
9047
9040
|
const DEVIN_HOOKS_V1_FILE_NAME = "hooks.v1.json";
|
|
9048
9041
|
const DEVIN_GLOBAL_AGENTS_FILE_NAME = "AGENTS.md";
|
|
9049
9042
|
const DEVIN_IGNORE_FILE_NAME = ".devinignore";
|
|
@@ -11301,6 +11294,7 @@ const QWENCODE_COMMANDS_DIR_PATH = join(QWENCODE_DIR, "commands");
|
|
|
11301
11294
|
const QWENCODE_AGENTS_DIR_PATH = join(QWENCODE_DIR, "agents");
|
|
11302
11295
|
const QWENCODE_SKILLS_DIR_PATH = join(QWENCODE_DIR, "skills");
|
|
11303
11296
|
const QWENCODE_RULE_FILE_NAME = "QWEN.md";
|
|
11297
|
+
const QWENCODE_LOCAL_RULE_FILE_NAME = "QWEN.local.md";
|
|
11304
11298
|
const QWENCODE_IGNORE_FILE_NAME = ".qwenignore";
|
|
11305
11299
|
const QWENCODE_SETTINGS_FILE_NAME = "settings.json";
|
|
11306
11300
|
//#endregion
|
|
@@ -12047,6 +12041,7 @@ const WARP_SKILLS_DIR_PATH = join(WARP_DIR, "skills");
|
|
|
12047
12041
|
const WARP_LINUX_DIR = join(".config", "warp-terminal");
|
|
12048
12042
|
const WARP_WIN32_DIR = join("AppData", "Local", "warp", "Warp", "config");
|
|
12049
12043
|
const WARP_RULE_FILE_NAME = "AGENTS.md";
|
|
12044
|
+
const WARP_GLOBAL_RULE_DIR = ".agents";
|
|
12050
12045
|
const WARP_MCP_FILE_NAME = ".mcp.json";
|
|
12051
12046
|
const WARP_PERMISSIONS_FILE_NAME = "settings.toml";
|
|
12052
12047
|
const WARP_IGNORE_FILE_NAME = ".warpindexingignore";
|
|
@@ -14782,9 +14777,9 @@ const DEVIN_CONVERTER_CONFIG = {
|
|
|
14782
14777
|
* - Project scope: `.devin/hooks.v1.json`. This is a standalone file whose top
|
|
14783
14778
|
* level IS the event map (no wrapper key).
|
|
14784
14779
|
* - Global scope: `~/.config/devin/config.json` under the `"hooks"` key. This
|
|
14785
|
-
* file is shared with the
|
|
14786
|
-
*
|
|
14787
|
-
* never deleted in global mode.
|
|
14780
|
+
* file is shared with the permissions (`permissions`) feature (MCP moved to
|
|
14781
|
+
* the dedicated mcp_config.json in v3000.3), so reads and writes merge into
|
|
14782
|
+
* the existing JSON and the file is never deleted in global mode.
|
|
14788
14783
|
*
|
|
14789
14784
|
* @see https://docs.devin.ai/cli/extensibility/hooks/overview
|
|
14790
14785
|
*/
|
|
@@ -16396,6 +16391,13 @@ var OpencodeHooks = class OpencodeHooks extends ToolHooks {
|
|
|
16396
16391
|
*/
|
|
16397
16392
|
const PI_TOOL_EVENTS = /* @__PURE__ */ new Set(["tool_call", "tool_result"]);
|
|
16398
16393
|
/**
|
|
16394
|
+
* Pi extension events that fire for every message role (user, assistant,
|
|
16395
|
+
* toolResult). The generated handler gates these on the assistant role so a
|
|
16396
|
+
* `postModelInvocation` hook runs once per finalized model response rather
|
|
16397
|
+
* than for every message in the conversation.
|
|
16398
|
+
*/
|
|
16399
|
+
const PI_ASSISTANT_MESSAGE_EVENTS = /* @__PURE__ */ new Set(["message_end"]);
|
|
16400
|
+
/**
|
|
16399
16401
|
* Validate a hook matcher as a regular expression and return it as a JS
|
|
16400
16402
|
* string-literal (JSON.stringify quoting) safe to embed in generated code.
|
|
16401
16403
|
*/
|
|
@@ -16436,7 +16438,10 @@ function buildSubscriptionLines(handlerGroups) {
|
|
|
16436
16438
|
const lines = [];
|
|
16437
16439
|
for (const [piEvent, handlers] of Object.entries(handlerGroups)) {
|
|
16438
16440
|
const usesToolName = PI_TOOL_EVENTS.has(piEvent) && handlers.some((h) => h.matcher);
|
|
16439
|
-
|
|
16441
|
+
const gatesOnAssistant = PI_ASSISTANT_MESSAGE_EVENTS.has(piEvent);
|
|
16442
|
+
const usesEvent = usesToolName || gatesOnAssistant;
|
|
16443
|
+
lines.push(` pi.on(${JSON.stringify(piEvent)}, async (${usesEvent ? "event" : ""}) => {`);
|
|
16444
|
+
if (gatesOnAssistant) lines.push(` if (event.message.role !== "assistant") return;`);
|
|
16440
16445
|
for (const handler of handlers) {
|
|
16441
16446
|
const embeddedCommand = JSON.stringify(handler.command);
|
|
16442
16447
|
if (usesToolName && handler.matcher) {
|
|
@@ -16571,6 +16576,7 @@ function canonicalDefToQwencodeHook(def) {
|
|
|
16571
16576
|
const type = def.type ?? "command";
|
|
16572
16577
|
const isHttp = type === "http";
|
|
16573
16578
|
const isCommand = type === "command";
|
|
16579
|
+
const isPrompt = type === "prompt";
|
|
16574
16580
|
return {
|
|
16575
16581
|
type,
|
|
16576
16582
|
...compact({
|
|
@@ -16580,6 +16586,8 @@ function canonicalDefToQwencodeHook(def) {
|
|
|
16580
16586
|
name: def.name,
|
|
16581
16587
|
description: def.description,
|
|
16582
16588
|
statusMessage: def.statusMessage,
|
|
16589
|
+
prompt: isPrompt ? def.prompt : void 0,
|
|
16590
|
+
model: isPrompt ? def.model : void 0,
|
|
16583
16591
|
async: isCommand ? def.async : void 0,
|
|
16584
16592
|
env: isCommand ? def.env : void 0,
|
|
16585
16593
|
shell: isCommand ? def.shell : void 0,
|
|
@@ -16598,7 +16606,7 @@ function canonicalDefToQwencodeHook(def) {
|
|
|
16598
16606
|
* is needed here — commands are passed through verbatim and any such variable
|
|
16599
16607
|
* reference stays intact for Qwen Code to expand.
|
|
16600
16608
|
*/
|
|
16601
|
-
function canonicalToQwencodeHooks(config) {
|
|
16609
|
+
function canonicalToQwencodeHooks(config, logger) {
|
|
16602
16610
|
const qwencodeSupported = new Set(QWENCODE_HOOK_EVENTS);
|
|
16603
16611
|
const sharedHooks = {};
|
|
16604
16612
|
for (const [event, defs] of Object.entries(config.hooks)) if (qwencodeSupported.has(event)) sharedHooks[event] = defs;
|
|
@@ -16618,6 +16626,7 @@ function canonicalToQwencodeHooks(config) {
|
|
|
16618
16626
|
const byMatcher = /* @__PURE__ */ new Map();
|
|
16619
16627
|
for (const def of definitions) {
|
|
16620
16628
|
if (!qwencodeSupportedTypes.has(def.type ?? "command")) continue;
|
|
16629
|
+
if (def.type === "prompt" && !def.prompt) logger?.warn(`Qwen Code prompt hook on '${eventName}' has no 'prompt' field; Qwen Code will load it and fail it at runtime.`);
|
|
16621
16630
|
const key = def.matcher ?? "";
|
|
16622
16631
|
const list = byMatcher.get(key);
|
|
16623
16632
|
if (list) list.push(def);
|
|
@@ -16656,7 +16665,9 @@ const QwencodeHookEntrySchema = z.looseObject({
|
|
|
16656
16665
|
shell: z.optional(z.string()),
|
|
16657
16666
|
headers: z.optional(z.record(z.string(), z.string())),
|
|
16658
16667
|
allowedEnvVars: z.optional(z.array(z.string())),
|
|
16659
|
-
once: z.optional(z.boolean())
|
|
16668
|
+
once: z.optional(z.boolean()),
|
|
16669
|
+
prompt: z.optional(z.string()),
|
|
16670
|
+
model: z.optional(z.string())
|
|
16660
16671
|
});
|
|
16661
16672
|
/**
|
|
16662
16673
|
* A matcher group entry in a Qwen Code event array.
|
|
@@ -16671,37 +16682,43 @@ const QwencodeMatcherEntrySchema = z.looseObject({
|
|
|
16671
16682
|
/**
|
|
16672
16683
|
* Convert a single parsed Qwen Code matcher group into canonical hook definitions.
|
|
16673
16684
|
*/
|
|
16685
|
+
function qwencodeHookEntryToCanonical({ hook, sequential, matcher }) {
|
|
16686
|
+
const h = hook;
|
|
16687
|
+
const hookType = h.type === "command" || h.type === "prompt" || h.type === "http" || h.type === "function" ? h.type : "command";
|
|
16688
|
+
const isHttp = hookType === "http";
|
|
16689
|
+
const isCommand = hookType === "command";
|
|
16690
|
+
const isPrompt = hookType === "prompt";
|
|
16691
|
+
const shell = h.shell === "bash" || h.shell === "powershell" ? h.shell : void 0;
|
|
16692
|
+
return {
|
|
16693
|
+
type: hookType,
|
|
16694
|
+
...compact({
|
|
16695
|
+
command: h.command,
|
|
16696
|
+
url: h.url,
|
|
16697
|
+
timeout: h.timeout,
|
|
16698
|
+
name: h.name,
|
|
16699
|
+
description: h.description,
|
|
16700
|
+
statusMessage: h.statusMessage,
|
|
16701
|
+
async: isCommand ? h.async : void 0,
|
|
16702
|
+
env: isCommand ? h.env : void 0,
|
|
16703
|
+
shell: isCommand ? shell : void 0,
|
|
16704
|
+
headers: isHttp ? h.headers : void 0,
|
|
16705
|
+
allowedEnvVars: isHttp ? h.allowedEnvVars : void 0,
|
|
16706
|
+
once: isHttp ? h.once : void 0,
|
|
16707
|
+
prompt: isPrompt ? h.prompt : void 0,
|
|
16708
|
+
model: isPrompt ? h.model : void 0,
|
|
16709
|
+
sequential: sequential ? true : void 0,
|
|
16710
|
+
matcher
|
|
16711
|
+
})
|
|
16712
|
+
};
|
|
16713
|
+
}
|
|
16674
16714
|
function qwencodeMatcherEntryToCanonical(entry) {
|
|
16675
|
-
const defs = [];
|
|
16676
|
-
const hooks = entry.hooks ?? [];
|
|
16677
16715
|
const sequential = entry.sequential === true;
|
|
16678
16716
|
const matcher = entry.matcher !== void 0 && entry.matcher !== null && entry.matcher !== "" ? entry.matcher : void 0;
|
|
16679
|
-
|
|
16680
|
-
|
|
16681
|
-
|
|
16682
|
-
|
|
16683
|
-
|
|
16684
|
-
defs.push({
|
|
16685
|
-
type: hookType,
|
|
16686
|
-
...compact({
|
|
16687
|
-
command: h.command,
|
|
16688
|
-
url: h.url,
|
|
16689
|
-
timeout: h.timeout,
|
|
16690
|
-
name: h.name,
|
|
16691
|
-
description: h.description,
|
|
16692
|
-
statusMessage: h.statusMessage,
|
|
16693
|
-
async: isCommand ? h.async : void 0,
|
|
16694
|
-
env: isCommand ? h.env : void 0,
|
|
16695
|
-
shell: isCommand ? shell : void 0,
|
|
16696
|
-
headers: isHttp ? h.headers : void 0,
|
|
16697
|
-
allowedEnvVars: isHttp ? h.allowedEnvVars : void 0,
|
|
16698
|
-
once: isHttp ? h.once : void 0,
|
|
16699
|
-
sequential: sequential ? true : void 0,
|
|
16700
|
-
matcher
|
|
16701
|
-
})
|
|
16702
|
-
});
|
|
16703
|
-
}
|
|
16704
|
-
return defs;
|
|
16717
|
+
return (entry.hooks ?? []).map((hook) => qwencodeHookEntryToCanonical({
|
|
16718
|
+
hook,
|
|
16719
|
+
sequential,
|
|
16720
|
+
matcher
|
|
16721
|
+
}));
|
|
16705
16722
|
}
|
|
16706
16723
|
/**
|
|
16707
16724
|
* Extract hooks from Qwen Code settings.json into canonical format.
|
|
@@ -16749,12 +16766,12 @@ var QwencodeHooks = class QwencodeHooks extends ToolHooks {
|
|
|
16749
16766
|
validate
|
|
16750
16767
|
});
|
|
16751
16768
|
}
|
|
16752
|
-
static async fromRulesyncHooks({ outputRoot = process.cwd(), rulesyncHooks, validate = true, global = false }) {
|
|
16769
|
+
static async fromRulesyncHooks({ outputRoot = process.cwd(), rulesyncHooks, validate = true, global = false, logger }) {
|
|
16753
16770
|
const paths = QwencodeHooks.getSettablePaths({ global });
|
|
16754
16771
|
const filePath = join(outputRoot, paths.relativeDirPath, paths.relativeFilePath);
|
|
16755
16772
|
const existingContent = await readFileContentOrNull(filePath) ?? JSON.stringify({}, null, 2);
|
|
16756
16773
|
const config = rulesyncHooks.getJson();
|
|
16757
|
-
const patch = { hooks: canonicalToQwencodeHooks(config) };
|
|
16774
|
+
const patch = { hooks: canonicalToQwencodeHooks(config, logger) };
|
|
16758
16775
|
const disableAllHooks = config.qwencode?.disableAllHooks;
|
|
16759
16776
|
if (typeof disableAllHooks === "boolean") patch.disableAllHooks = disableAllHooks;
|
|
16760
16777
|
const fileContent = applySharedConfigPatch({
|
|
@@ -20780,18 +20797,24 @@ var DeepagentsMcp = class DeepagentsMcp extends ToolMcp {
|
|
|
20780
20797
|
/**
|
|
20781
20798
|
* MCP generator for Devin Local (native `.devin/` configuration).
|
|
20782
20799
|
*
|
|
20783
|
-
*
|
|
20784
|
-
*
|
|
20785
|
-
*
|
|
20800
|
+
* Since v3000.3 (the Local 3.6 release), Devin reads MCP servers from a
|
|
20801
|
+
* dedicated `mcpServers`-keyed config file rather than the shared
|
|
20802
|
+
* `config.json`:
|
|
20803
|
+
* - Project scope: `.devin/mcp_config.json`
|
|
20804
|
+
* - Global scope: `~/.config/devin/mcp_config.json`
|
|
20786
20805
|
*
|
|
20787
|
-
*
|
|
20788
|
-
*
|
|
20789
|
-
*
|
|
20790
|
-
*
|
|
20791
|
-
*
|
|
20792
|
-
*
|
|
20806
|
+
* Legacy `mcpServers` entries left in `config.json` are auto-migrated into
|
|
20807
|
+
* the dedicated file on Devin startup, so writing the legacy key would fight
|
|
20808
|
+
* the migration. Import still falls back to the legacy `config.json`
|
|
20809
|
+
* `mcpServers` key when no dedicated file exists, so pre-v3000.3 repos
|
|
20810
|
+
* migrate cleanly. The gitignored `.devin/mcp_config.local.json` override is
|
|
20811
|
+
* the user's personal territory and is never read or written.
|
|
20793
20812
|
*
|
|
20794
|
-
*
|
|
20813
|
+
* Each server is a stdio entry ({ command, args, env }) or a remote entry
|
|
20814
|
+
* ({ serverUrl | url, headers }), and may carry an optional `disabledTools`
|
|
20815
|
+
* array.
|
|
20816
|
+
*
|
|
20817
|
+
* @see https://docs.devin.ai/cli/extensibility/mcp/configuration
|
|
20795
20818
|
*/
|
|
20796
20819
|
var DevinMcp = class DevinMcp extends ToolMcp {
|
|
20797
20820
|
json;
|
|
@@ -20809,31 +20832,27 @@ var DevinMcp = class DevinMcp extends ToolMcp {
|
|
|
20809
20832
|
throw new Error(`Failed to parse Devin MCP config at ${join(relativeDirPath, relativeFilePath)}: ${formatError(error)}`, { cause: error });
|
|
20810
20833
|
}
|
|
20811
20834
|
}
|
|
20812
|
-
/**
|
|
20813
|
-
* config.json may carry the permissions/hooks features' keys, so it is never
|
|
20814
|
-
* deleted; only the managed `mcpServers` key is rewritten.
|
|
20815
|
-
*/
|
|
20816
|
-
isDeletable() {
|
|
20817
|
-
return false;
|
|
20818
|
-
}
|
|
20819
20835
|
static getSettablePaths({ global = false } = {}) {
|
|
20820
20836
|
if (global) return {
|
|
20821
20837
|
relativeDirPath: DEVIN_GLOBAL_CONFIG_DIR_PATH,
|
|
20822
|
-
relativeFilePath:
|
|
20838
|
+
relativeFilePath: DEVIN_MCP_CONFIG_FILE_NAME
|
|
20823
20839
|
};
|
|
20824
20840
|
return {
|
|
20825
20841
|
relativeDirPath: DEVIN_DIR,
|
|
20826
|
-
relativeFilePath:
|
|
20842
|
+
relativeFilePath: DEVIN_MCP_CONFIG_FILE_NAME
|
|
20827
20843
|
};
|
|
20828
20844
|
}
|
|
20829
20845
|
static async fromFile({ outputRoot = process.cwd(), validate = true, global = false }) {
|
|
20830
20846
|
const paths = this.getSettablePaths({ global });
|
|
20831
|
-
|
|
20832
|
-
|
|
20833
|
-
|
|
20834
|
-
|
|
20835
|
-
|
|
20836
|
-
|
|
20847
|
+
let fileContent = await readFileContentOrNull(join(outputRoot, paths.relativeDirPath, paths.relativeFilePath));
|
|
20848
|
+
if (fileContent === null) {
|
|
20849
|
+
const legacyContent = await readFileContentOrNull(join(outputRoot, paths.relativeDirPath, DEVIN_CONFIG_FILE_NAME));
|
|
20850
|
+
if (legacyContent !== null) {
|
|
20851
|
+
const legacyJson = this.parseJsonOrThrow(legacyContent, paths.relativeDirPath, DEVIN_CONFIG_FILE_NAME);
|
|
20852
|
+
fileContent = JSON.stringify({ mcpServers: legacyJson.mcpServers ?? {} }, null, 2);
|
|
20853
|
+
}
|
|
20854
|
+
}
|
|
20855
|
+
const newJson = { mcpServers: this.parseJsonOrThrow(fileContent ?? "{\"mcpServers\":{}}", paths.relativeDirPath, paths.relativeFilePath).mcpServers ?? {} };
|
|
20837
20856
|
return new DevinMcp({
|
|
20838
20857
|
outputRoot,
|
|
20839
20858
|
relativeDirPath: paths.relativeDirPath,
|
|
@@ -20843,21 +20862,21 @@ var DevinMcp = class DevinMcp extends ToolMcp {
|
|
|
20843
20862
|
global
|
|
20844
20863
|
});
|
|
20845
20864
|
}
|
|
20846
|
-
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false }) {
|
|
20865
|
+
static async fromRulesyncMcp({ outputRoot = process.cwd(), rulesyncMcp, validate = true, global = false, logger }) {
|
|
20847
20866
|
const paths = this.getSettablePaths({ global });
|
|
20848
|
-
const
|
|
20849
|
-
|
|
20867
|
+
const existingContent = await readFileContentOrNull(join(outputRoot, paths.relativeDirPath, paths.relativeFilePath));
|
|
20868
|
+
if (existingContent !== null) {
|
|
20869
|
+
const existingJson = this.parseJsonOrThrow(existingContent, paths.relativeDirPath, paths.relativeFilePath);
|
|
20870
|
+
const existingServers = existingJson.mcpServers && typeof existingJson.mcpServers === "object" ? Object.keys(existingJson.mcpServers) : [];
|
|
20871
|
+
const managedServers = new Set(Object.keys(rulesyncMcp.getMcpServers()));
|
|
20872
|
+
const dropped = existingServers.filter((name) => !managedServers.has(name));
|
|
20873
|
+
if (dropped.length > 0) logger?.warn(`Devin MCP servers not managed by rulesync will be removed from ${join(paths.relativeDirPath, paths.relativeFilePath)}: ${dropped.join(", ")}. Run 'rulesync import' first to keep them, or move them to mcp_config.local.json.`);
|
|
20874
|
+
}
|
|
20850
20875
|
return new DevinMcp({
|
|
20851
20876
|
outputRoot,
|
|
20852
20877
|
relativeDirPath: paths.relativeDirPath,
|
|
20853
20878
|
relativeFilePath: paths.relativeFilePath,
|
|
20854
|
-
fileContent:
|
|
20855
|
-
fileKey: sharedConfigFileKey(paths),
|
|
20856
|
-
feature: "mcp",
|
|
20857
|
-
existingContent,
|
|
20858
|
-
patch: { mcpServers: rulesyncMcp.getMcpServers() },
|
|
20859
|
-
filePath
|
|
20860
|
-
}),
|
|
20879
|
+
fileContent: JSON.stringify({ mcpServers: rulesyncMcp.getMcpServers() }, null, 2),
|
|
20861
20880
|
validate,
|
|
20862
20881
|
global
|
|
20863
20882
|
});
|
|
@@ -27575,9 +27594,10 @@ function buildDevinPermissionEntry(scope, pattern) {
|
|
|
27575
27594
|
* - Project scope: `.devin/config.json`
|
|
27576
27595
|
* - Global scope: `~/.config/devin/config.json`
|
|
27577
27596
|
*
|
|
27578
|
-
*
|
|
27579
|
-
*
|
|
27580
|
-
* the file is never deleted; only the managed
|
|
27597
|
+
* In global mode the config file is shared with the hooks (`hooks`) feature
|
|
27598
|
+
* (MCP moved to the dedicated mcp_config.json in v3000.3), so reads and writes
|
|
27599
|
+
* merge into the existing JSON and the file is never deleted; only the managed
|
|
27600
|
+
* `permissions` key is rewritten.
|
|
27581
27601
|
*
|
|
27582
27602
|
* @see https://docs.devin.ai/cli/reference/permissions
|
|
27583
27603
|
*/
|
|
@@ -31451,6 +31471,10 @@ function ensurePermission(permission, category) {
|
|
|
31451
31471
|
const WARP_GLOBAL_ONLY_MESSAGE = "Warp permissions are global-only; use --global to sync Warp's settings.toml";
|
|
31452
31472
|
const ALLOWLIST_KEY = "agent_mode_command_execution_allowlist";
|
|
31453
31473
|
const DENYLIST_KEY = "agent_mode_command_execution_denylist";
|
|
31474
|
+
const EXECUTION_PROFILES_KEY = "execution_profiles";
|
|
31475
|
+
const DEFAULT_PROFILE_KEY = "default";
|
|
31476
|
+
const PROFILE_ALLOWLIST_KEY = "command_allowlist";
|
|
31477
|
+
const PROFILE_DENYLIST_KEY = "command_denylist";
|
|
31454
31478
|
const WARP_OVERRIDE_KEYS = [
|
|
31455
31479
|
"agent_mode_coding_permissions",
|
|
31456
31480
|
"agent_mode_coding_file_read_allowlist",
|
|
@@ -31478,11 +31502,21 @@ function warpSettingsDir() {
|
|
|
31478
31502
|
/**
|
|
31479
31503
|
* Permissions adapter for Warp.
|
|
31480
31504
|
*
|
|
31481
|
-
* Warp gates **shell command** execution through two regex arrays
|
|
31482
|
-
*
|
|
31483
|
-
* - `
|
|
31484
|
-
*
|
|
31485
|
-
*
|
|
31505
|
+
* Warp gates **shell command** execution through two regex arrays in the
|
|
31506
|
+
* global user `settings.toml`. Since file-backed execution profiles went
|
|
31507
|
+
* Stable (2026-07-28) the authoritative surface is the `default` record of the
|
|
31508
|
+
* `[agents.execution_profiles.<id>]` collection:
|
|
31509
|
+
* - `command_allowlist` — commands that auto-execute.
|
|
31510
|
+
* - `command_denylist` — commands that always require permission (the denylist
|
|
31511
|
+
* wins over the allowlist).
|
|
31512
|
+
*
|
|
31513
|
+
* The legacy `[agents.profiles]` keys
|
|
31514
|
+
* (`agent_mode_command_execution_allowlist` / `denylist`) are consumed only
|
|
31515
|
+
* once by Warp's one-shot migration and are ignored afterwards. Both surfaces
|
|
31516
|
+
* are written: the legacy block keeps un-migrated installs and old clients
|
|
31517
|
+
* working, and the `default` execution profile (merged in place, only when the
|
|
31518
|
+
* collection already exists) keeps migrated installs enforcing the lists.
|
|
31519
|
+
* Import prefers the execution profile and falls back to the legacy keys.
|
|
31486
31520
|
*
|
|
31487
31521
|
* This surface is **global only** — there is no project-scoped Warp permissions
|
|
31488
31522
|
* file. rulesync's canonical `permission.bash` patterns map directly (`allow` →
|
|
@@ -31561,6 +31595,18 @@ var WarpPermissions = class WarpPermissions extends ToolPermissions {
|
|
|
31561
31595
|
if (mergedDeny.length > 0) profiles[DENYLIST_KEY] = mergedDeny;
|
|
31562
31596
|
else delete profiles[DENYLIST_KEY];
|
|
31563
31597
|
agents.profiles = profiles;
|
|
31598
|
+
if (isRecord(agents[EXECUTION_PROFILES_KEY])) {
|
|
31599
|
+
const executionProfiles = { ...agents[EXECUTION_PROFILES_KEY] };
|
|
31600
|
+
const defaultProfile = isRecord(executionProfiles[DEFAULT_PROFILE_KEY]) ? { ...executionProfiles[DEFAULT_PROFILE_KEY] } : {};
|
|
31601
|
+
if (mergedAllow.length > 0) defaultProfile[PROFILE_ALLOWLIST_KEY] = mergedAllow;
|
|
31602
|
+
else delete defaultProfile[PROFILE_ALLOWLIST_KEY];
|
|
31603
|
+
if (mergedDeny.length > 0) defaultProfile[PROFILE_DENYLIST_KEY] = mergedDeny;
|
|
31604
|
+
else delete defaultProfile[PROFILE_DENYLIST_KEY];
|
|
31605
|
+
executionProfiles[DEFAULT_PROFILE_KEY] = defaultProfile;
|
|
31606
|
+
agents[EXECUTION_PROFILES_KEY] = executionProfiles;
|
|
31607
|
+
const otherProfileIds = Object.keys(executionProfiles).filter((id) => id !== DEFAULT_PROFILE_KEY);
|
|
31608
|
+
if (mergedDeny.length > 0 && otherProfileIds.length > 0 && logger) logger.warn(`Warp command deny rules were written to the 'default' execution profile only; they are not enforced while another profile (${otherProfileIds.join(", ")}) is active.`);
|
|
31609
|
+
}
|
|
31564
31610
|
settings.agents = agents;
|
|
31565
31611
|
return new WarpPermissions({
|
|
31566
31612
|
outputRoot,
|
|
@@ -31580,9 +31626,11 @@ var WarpPermissions = class WarpPermissions extends ToolPermissions {
|
|
|
31580
31626
|
}
|
|
31581
31627
|
const agents = isRecord(settings.agents) ? settings.agents : {};
|
|
31582
31628
|
const profiles = isRecord(agents.profiles) ? agents.profiles : {};
|
|
31629
|
+
const executionProfiles = isRecord(agents[EXECUTION_PROFILES_KEY]) ? agents[EXECUTION_PROFILES_KEY] : void 0;
|
|
31630
|
+
const defaultProfile = executionProfiles && isRecord(executionProfiles[DEFAULT_PROFILE_KEY]) ? executionProfiles[DEFAULT_PROFILE_KEY] : void 0;
|
|
31583
31631
|
const config = convertWarpToRulesyncPermissions({
|
|
31584
|
-
allow: isStringArray$1(profiles[ALLOWLIST_KEY]) ? profiles[ALLOWLIST_KEY] : [],
|
|
31585
|
-
deny: isStringArray$1(profiles[DENYLIST_KEY]) ? profiles[DENYLIST_KEY] : []
|
|
31632
|
+
allow: defaultProfile ? isStringArray$1(defaultProfile[PROFILE_ALLOWLIST_KEY]) ? defaultProfile[PROFILE_ALLOWLIST_KEY] : [] : isStringArray$1(profiles[ALLOWLIST_KEY]) ? profiles[ALLOWLIST_KEY] : [],
|
|
31633
|
+
deny: defaultProfile ? isStringArray$1(defaultProfile[PROFILE_DENYLIST_KEY]) ? defaultProfile[PROFILE_DENYLIST_KEY] : [] : isStringArray$1(profiles[DENYLIST_KEY]) ? profiles[DENYLIST_KEY] : []
|
|
31586
31634
|
});
|
|
31587
31635
|
const warpOverride = {};
|
|
31588
31636
|
for (const key of WARP_OVERRIDE_KEYS) if (profiles[key] !== void 0) warpOverride[key] = profiles[key];
|
|
@@ -37332,7 +37380,8 @@ const toolSkillFactories = /* @__PURE__ */ new Map([
|
|
|
37332
37380
|
meta: {
|
|
37333
37381
|
supportsProject: true,
|
|
37334
37382
|
supportsSimulated: false,
|
|
37335
|
-
supportsGlobal: true
|
|
37383
|
+
supportsGlobal: true,
|
|
37384
|
+
lenientImport: true
|
|
37336
37385
|
}
|
|
37337
37386
|
}],
|
|
37338
37387
|
["aiassistant", {
|
|
@@ -37769,7 +37818,7 @@ var SkillsProcessor = class extends DirFeatureProcessor {
|
|
|
37769
37818
|
global: this.global
|
|
37770
37819
|
});
|
|
37771
37820
|
} catch (error) {
|
|
37772
|
-
if (!isConfiguredRoot) throw error;
|
|
37821
|
+
if (!isConfiguredRoot && !factory.meta.lenientImport) throw error;
|
|
37773
37822
|
this.logger.warn(`Skipping ${join(relativeDirPath, dirName)}: ${formatError(error)}`);
|
|
37774
37823
|
return null;
|
|
37775
37824
|
}
|
|
@@ -46418,6 +46467,13 @@ var QwencodeRule = class QwencodeRule extends ToolRule {
|
|
|
46418
46467
|
toolTarget: "qwencode"
|
|
46419
46468
|
});
|
|
46420
46469
|
}
|
|
46470
|
+
/**
|
|
46471
|
+
* The personal local context file lives under `.qwen/`, not at the project
|
|
46472
|
+
* root where the settable root path points, so override the deletion glob.
|
|
46473
|
+
*/
|
|
46474
|
+
static getLocalRootDeletionGlob({ outputRoot, fileName }) {
|
|
46475
|
+
return join(outputRoot, QWENCODE_DIR, fileName);
|
|
46476
|
+
}
|
|
46421
46477
|
};
|
|
46422
46478
|
//#endregion
|
|
46423
46479
|
//#region src/features/rules/reasonix-rule.ts
|
|
@@ -47021,14 +47077,18 @@ var WarpRule = class WarpRule extends ToolRule {
|
|
|
47021
47077
|
root: root ?? false
|
|
47022
47078
|
});
|
|
47023
47079
|
}
|
|
47024
|
-
static getSettablePaths(
|
|
47080
|
+
static getSettablePaths({ global = false } = {}) {
|
|
47081
|
+
if (global) return { root: {
|
|
47082
|
+
relativeDirPath: WARP_GLOBAL_RULE_DIR,
|
|
47083
|
+
relativeFilePath: WARP_RULE_FILE_NAME
|
|
47084
|
+
} };
|
|
47025
47085
|
return { root: {
|
|
47026
47086
|
relativeDirPath: ".",
|
|
47027
47087
|
relativeFilePath: WARP_RULE_FILE_NAME
|
|
47028
47088
|
} };
|
|
47029
47089
|
}
|
|
47030
|
-
static async fromFile({ outputRoot = process.cwd(), relativeFilePath: _relativeFilePath, validate = true }) {
|
|
47031
|
-
const { root } = this.getSettablePaths();
|
|
47090
|
+
static async fromFile({ outputRoot = process.cwd(), relativeFilePath: _relativeFilePath, validate = true, global = false }) {
|
|
47091
|
+
const { root } = this.getSettablePaths({ global });
|
|
47032
47092
|
const fileContent = await readFileContent(join(outputRoot, join(root.relativeDirPath, root.relativeFilePath)));
|
|
47033
47093
|
return new WarpRule({
|
|
47034
47094
|
outputRoot,
|
|
@@ -47039,8 +47099,8 @@ var WarpRule = class WarpRule extends ToolRule {
|
|
|
47039
47099
|
root: true
|
|
47040
47100
|
});
|
|
47041
47101
|
}
|
|
47042
|
-
static fromRulesyncRule({ outputRoot = process.cwd(), rulesyncRule, validate = true }) {
|
|
47043
|
-
const { root } = this.getSettablePaths();
|
|
47102
|
+
static fromRulesyncRule({ outputRoot = process.cwd(), rulesyncRule, validate = true, global = false }) {
|
|
47103
|
+
const { root } = this.getSettablePaths({ global });
|
|
47044
47104
|
const isRoot = rulesyncRule.getFrontmatter().root ?? false;
|
|
47045
47105
|
return new WarpRule({
|
|
47046
47106
|
outputRoot,
|
|
@@ -47060,8 +47120,8 @@ var WarpRule = class WarpRule extends ToolRule {
|
|
|
47060
47120
|
error: null
|
|
47061
47121
|
};
|
|
47062
47122
|
}
|
|
47063
|
-
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath }) {
|
|
47064
|
-
const { root } = this.getSettablePaths();
|
|
47123
|
+
static forDeletion({ outputRoot = process.cwd(), relativeDirPath, relativeFilePath, global = false }) {
|
|
47124
|
+
const { root } = this.getSettablePaths({ global });
|
|
47065
47125
|
const isRoot = relativeFilePath === root.relativeFilePath && relativeDirPath === root.relativeDirPath;
|
|
47066
47126
|
return new WarpRule({
|
|
47067
47127
|
outputRoot,
|
|
@@ -47434,6 +47494,8 @@ const toolRuleFactories = /* @__PURE__ */ new Map([
|
|
|
47434
47494
|
extension: "md",
|
|
47435
47495
|
supportsGlobal: true,
|
|
47436
47496
|
ruleDiscoveryMode: "auto",
|
|
47497
|
+
localRootMode: "separate-local-file",
|
|
47498
|
+
localRootFileName: QWENCODE_LOCAL_RULE_FILE_NAME,
|
|
47437
47499
|
additionalConventions: { subagents: { subagentClass: QwencodeSubagent } }
|
|
47438
47500
|
}
|
|
47439
47501
|
}],
|
|
@@ -47498,7 +47560,7 @@ const toolRuleFactories = /* @__PURE__ */ new Map([
|
|
|
47498
47560
|
class: WarpRule,
|
|
47499
47561
|
meta: {
|
|
47500
47562
|
extension: "md",
|
|
47501
|
-
supportsGlobal:
|
|
47563
|
+
supportsGlobal: true,
|
|
47502
47564
|
ruleDiscoveryMode: "toon",
|
|
47503
47565
|
collisionPolicy: "fold"
|
|
47504
47566
|
}
|
|
@@ -47832,6 +47894,14 @@ var RulesProcessor = class extends FeatureProcessor {
|
|
|
47832
47894
|
validate: true,
|
|
47833
47895
|
root: true
|
|
47834
47896
|
});
|
|
47897
|
+
if (factory.class === QwencodeRule) return new QwencodeRule({
|
|
47898
|
+
outputRoot: this.outputRoot,
|
|
47899
|
+
relativeDirPath: QWENCODE_DIR,
|
|
47900
|
+
relativeFilePath: fileName,
|
|
47901
|
+
fileContent: body,
|
|
47902
|
+
validate: true,
|
|
47903
|
+
root: true
|
|
47904
|
+
});
|
|
47835
47905
|
return null;
|
|
47836
47906
|
}
|
|
47837
47907
|
/**
|
|
@@ -49984,6 +50054,6 @@ async function importChecksCore(params) {
|
|
|
49984
50054
|
return writtenCount;
|
|
49985
50055
|
}
|
|
49986
50056
|
//#endregion
|
|
49987
|
-
export {
|
|
50057
|
+
export { JsonLogger as $, RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH as $t, RulesyncRuleFrontmatterSchema as A, PACKAGING_TOOL_TARGETS as At, RulesyncCheck as B, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH as Bt, CODEXCLI_DIR as C, removeTempDirectory as Ct, RulesyncSkill as D, writeFileContent as Dt, RulesyncSubagentFrontmatterSchema as E, toPosixPath as Et, getRulesyncSourceCandidates as F, RULESYNC_CHECKS_RELATIVE_DIR_PATH as Ft, SKILL_FILE_NAME as G, RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH as Gt, stringifyFrontmatter as H, RULESYNC_HOOKS_LEGACY_FILE_NAME as Ht, resolveRulesyncSourceWritePath as I, RULESYNC_COMMANDS_RELATIVE_DIR_PATH as It, ConfigFileSchema as J, RULESYNC_MCP_RELATIVE_FILE_PATH as Jt, ConfigResolver as K, RULESYNC_MCP_FILE_NAME as Kt, parseJsonc as L, RULESYNC_CONFIG_RELATIVE_FILE_PATH as Lt, RulesyncMcp as M, MAX_FILE_SIZE as Mt, RulesyncIgnore as N, RULESYNC_AIIGNORE_FILE_NAME as Nt, RulesyncSkillFrontmatterSchema as O, ALL_TOOL_TARGETS as Ot, RulesyncHooks as P, RULESYNC_AIIGNORE_RELATIVE_FILE_PATH as Pt, ConsoleLogger as Q, RULESYNC_PERMISSIONS_LEGACY_FILE_NAME as Qt, RulesyncCommand as R, RULESYNC_CONFIG_SCHEMA_URL as Rt, CODEXCLI_BASH_RULES_FILE_NAME as S, removeFileStrict as St, RulesyncSubagent as T, runWithDirectoryRollback as Tt, loadYaml as U, RULESYNC_HOOKS_RELATIVE_FILE_PATH as Ut, RulesyncCheckFrontmatterSchema as V, RULESYNC_HOOKS_FILE_NAME as Vt, SHARED_USER_MANAGED_CONFIG_PATHS as W, RULESYNC_IGNORE_RELATIVE_FILE_PATH as Wt, SourceEntrySchema as X, RULESYNC_NPM_SOURCES_LOCK_RELATIVE_FILE_PATH as Xt, GITIGNORE_DESTINATION_KEY as Y, RULESYNC_MCP_SCHEMA_URL as Yt, findControlCharacter as Z, RULESYNC_PERMISSIONS_FILE_NAME as Zt, CLAUDECODE_LOCAL_RULE_FILE_NAME as _, readFileContent as _t, convertFromTool as a, RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH as an, assertTreeContainsNoSymlinks as at, CLAUDECODE_SKILLS_DIR_PATH as b, removeDirectoryStrict as bt, SubagentsProcessor as c, DEPRECATED_FEATURE_REPLACEMENTS as cn, createTempDirectory as ct, IgnoreProcessor as d, fileExists as dt, RULESYNC_PERMISSIONS_SCHEMA_URL as en, fallbackLogger as et, HooksProcessor as f, findFilesByGlobs as ft, CLAUDECODE_DIR as g, listDirectoryFiles as gt, QWENCODE_LOCAL_RULE_FILE_NAME as h, isSymlink as ht, getProcessorRegistryEntry as i, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH as in, assertDirectoryIfExists as it, RulesyncPermissions as j, ToolTargetSchema as jt, RulesyncRule as k, ALL_TOOL_TARGETS_WITH_WILDCARD as kt, SkillsProcessor as l, formatError as ln, directoryExists as lt, QWENCODE_DIR as m, getHomeDirectory as mt, checkRulesyncDirExists as n, RULESYNC_RULES_RELATIVE_DIR_PATH as nn, CLIError as nt, isPackagingToolTarget as o, ALL_FEATURES as on, assertWritablePathInsideRoot as ot, CommandsProcessor as p, getFileSize as pt, CONFLICTING_TARGET_PAIRS as q, RULESYNC_MCP_LEGACY_FILE_NAME as qt, generate as r, RULESYNC_SKILLS_RELATIVE_DIR_PATH as rn, ErrorCodes as rt, RulesProcessor as s, ALL_FEATURES_WITH_WILDCARD as sn, checkPathTraversal as st, importFromTool as t, RULESYNC_RELATIVE_DIR_PATH as tn, warnOnConflictingFlags as tt, McpProcessor as u, ensureDir as ut, CLAUDECODE_MEMORIES_DIR_NAME as v, readFileContentOrNull as vt, getLocalSkillDirNames as w, resolvePath as wt, ChecksProcessor as x, removeFile as xt, CLAUDECODE_SETTINGS_LOCAL_FILE_NAME as y, removeDirectory as yt, RulesyncCommandFrontmatterSchema as z, RULESYNC_CURATED_RULES_RELATIVE_DIR_PATH as zt };
|
|
49988
50058
|
|
|
49989
|
-
//# sourceMappingURL=import-
|
|
50059
|
+
//# sourceMappingURL=import-BwakMyyf.js.map
|