rulesync 18.0.0 → 19.0.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 +3 -3
- package/dist/cli/index.js +3 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/{import-KY5Q7laH.cjs → import-BFhL78qW.cjs} +152 -27
- package/dist/{import-CA3RFpGB.js → import-C-Jsxedt.js} +153 -28
- package/dist/{import-CA3RFpGB.js.map → import-C-Jsxedt.js.map} +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -44111,6 +44111,7 @@ var ClinePermissions = class ClinePermissions extends ToolPermissions {
|
|
|
44111
44111
|
//#region src/features/permissions/codexcli-permissions.ts
|
|
44112
44112
|
const RULESYNC_PROFILE_NAME = "rulesync";
|
|
44113
44113
|
const CODEX_WORKSPACE_ROOTS_KEY = ":workspace_roots";
|
|
44114
|
+
const CODEX_WORKSPACE_ROOT_SUBPATH = ".";
|
|
44114
44115
|
const CODEX_WORKSPACE_BASELINE = ":workspace";
|
|
44115
44116
|
const CODEX_READ_ONLY_BASELINE = ":read-only";
|
|
44116
44117
|
const CODEX_DANGER_FULL_ACCESS_BASELINE = ":danger-full-access";
|
|
@@ -44331,7 +44332,15 @@ function convertRulesyncToCodexProfile({ config, logger }) {
|
|
|
44331
44332
|
workspaceRootFilesystem
|
|
44332
44333
|
});
|
|
44333
44334
|
if (Object.keys(workspaceRootFilesystem).length > 0) {
|
|
44334
|
-
|
|
44335
|
+
const directWorkspaceRootsAccess = filesystem[CODEX_WORKSPACE_ROOTS_KEY];
|
|
44336
|
+
if (isCodexFilesystemAccess(directWorkspaceRootsAccess)) {
|
|
44337
|
+
mergeIntoWorkspaceRootTable({
|
|
44338
|
+
workspaceRootFilesystem,
|
|
44339
|
+
pattern: CODEX_WORKSPACE_ROOT_SUBPATH,
|
|
44340
|
+
access: directWorkspaceRootsAccess
|
|
44341
|
+
});
|
|
44342
|
+
logger?.warn(`"${CODEX_WORKSPACE_ROOTS_KEY}" is set as a direct filesystem access rule in the permissions alongside workspace-relative rules; it is emitted as the "${CODEX_WORKSPACE_ROOT_SUBPATH}" entry of the "${CODEX_WORKSPACE_ROOTS_KEY}" table.`);
|
|
44343
|
+
}
|
|
44335
44344
|
if (Object.keys(workspaceRootFilesystem).some((pattern) => pattern.includes("**"))) filesystem.glob_scan_max_depth = CODEX_GLOB_SCAN_MAX_DEPTH;
|
|
44336
44345
|
filesystem[CODEX_WORKSPACE_ROOTS_KEY] = workspaceRootFilesystem;
|
|
44337
44346
|
}
|
|
@@ -44348,9 +44357,13 @@ function convertRulesyncToCodexProfile({ config, logger }) {
|
|
|
44348
44357
|
};
|
|
44349
44358
|
}
|
|
44350
44359
|
function addCodexFilesystemRules({ categoryRules, filesystem, workspaceRootFilesystem, logger }) {
|
|
44351
|
-
|
|
44360
|
+
const normalizedCategoryRules = normalizeWorkspaceRelativeCategoryRules({
|
|
44352
44361
|
categoryRules,
|
|
44353
44362
|
logger
|
|
44363
|
+
});
|
|
44364
|
+
for (const rule of mergeFilesystemCategoryRules({
|
|
44365
|
+
categoryRules: normalizedCategoryRules,
|
|
44366
|
+
logger
|
|
44354
44367
|
})) {
|
|
44355
44368
|
const access = normalizeCodexFilesystemAccess({
|
|
44356
44369
|
pattern: rule.pattern,
|
|
@@ -44517,9 +44530,59 @@ function addFilesystemRule({ filesystem, workspaceRootFilesystem, pattern, acces
|
|
|
44517
44530
|
filesystem[pattern] = access;
|
|
44518
44531
|
return;
|
|
44519
44532
|
}
|
|
44520
|
-
|
|
44533
|
+
mergeIntoWorkspaceRootTable({
|
|
44534
|
+
workspaceRootFilesystem,
|
|
44535
|
+
pattern,
|
|
44536
|
+
access
|
|
44537
|
+
});
|
|
44538
|
+
}
|
|
44539
|
+
const PERMISSION_ACTION_RESTRICTIVENESS = {
|
|
44540
|
+
deny: 2,
|
|
44541
|
+
ask: 1,
|
|
44542
|
+
allow: 0
|
|
44543
|
+
};
|
|
44544
|
+
function normalizeWorkspaceRelativeCategoryRules({ categoryRules, logger }) {
|
|
44545
|
+
const result = {};
|
|
44546
|
+
for (const category of [
|
|
44547
|
+
"read",
|
|
44548
|
+
"edit",
|
|
44549
|
+
"write"
|
|
44550
|
+
]) {
|
|
44551
|
+
const rules = categoryRules[category];
|
|
44552
|
+
if (rules === void 0) continue;
|
|
44553
|
+
const normalized = {};
|
|
44554
|
+
for (const [pattern, action] of Object.entries(rules)) {
|
|
44555
|
+
const key = pattern.trim() === "" || canBeCodexFilesystemRoot(pattern) ? pattern : toWorkspaceRootSubpath(pattern);
|
|
44556
|
+
if (key === void 0) {
|
|
44557
|
+
logger?.warn(`Skipping Codex CLI ${category} filesystem entry for workspace-relative pattern "${pattern}": Codex rejects a ":workspace_roots" subpath containing a ".." segment or an empty leading segment and would refuse the whole config, so the rule is dropped entirely — even a deny — and the path is NOT protected by the generated profile. Use a normalized relative path instead.`);
|
|
44558
|
+
continue;
|
|
44559
|
+
}
|
|
44560
|
+
const existing = normalized[key];
|
|
44561
|
+
normalized[key] = existing === void 0 || PERMISSION_ACTION_RESTRICTIVENESS[action] > PERMISSION_ACTION_RESTRICTIVENESS[existing] ? action : existing;
|
|
44562
|
+
}
|
|
44563
|
+
result[category] = normalized;
|
|
44564
|
+
}
|
|
44565
|
+
return result;
|
|
44566
|
+
}
|
|
44567
|
+
function toWorkspaceRootSubpath(pattern) {
|
|
44568
|
+
let subpath = pattern;
|
|
44569
|
+
while (subpath.startsWith("./")) subpath = subpath.slice(2);
|
|
44570
|
+
if (subpath === "" || subpath === "**" && subpath !== pattern) return CODEX_WORKSPACE_ROOT_SUBPATH;
|
|
44571
|
+
if (subpath.startsWith("/") || subpath.split(/[\\/]/).some((segment) => segment === "..")) return;
|
|
44572
|
+
return subpath;
|
|
44573
|
+
}
|
|
44574
|
+
function mergeIntoWorkspaceRootTable({ workspaceRootFilesystem, pattern, access }) {
|
|
44575
|
+
const existing = workspaceRootFilesystem[pattern];
|
|
44576
|
+
workspaceRootFilesystem[pattern] = existing === void 0 ? access : moreRestrictiveCodexAccess({
|
|
44577
|
+
a: existing,
|
|
44578
|
+
b: access
|
|
44579
|
+
});
|
|
44521
44580
|
}
|
|
44522
44581
|
function normalizeCodexFilesystemAccess({ pattern, access, writeRestriction, logger }) {
|
|
44582
|
+
if (isWindowsDevicePath(pattern) && !canBeCodexFilesystemRoot(pattern)) {
|
|
44583
|
+
logger?.warn(`Skipping Codex CLI ${access} filesystem entry for Windows device path "${pattern}": Codex cannot express it as a workspace-root entry (it is rejected on Windows and matches nothing elsewhere), so the rule is dropped entirely — even a deny — and the path is NOT protected by the generated profile. Use a plain drive path such as "C:\\..." instead.`);
|
|
44584
|
+
return;
|
|
44585
|
+
}
|
|
44523
44586
|
if ((access === "read" || access === "write") && isWindowsDevicePath(pattern)) {
|
|
44524
44587
|
if (writeRestriction !== void 0) {
|
|
44525
44588
|
logger?.warn(`Codex CLI does not support Windows device paths for read/write access: pattern "${pattern}" will be emitted as "deny" because its write-side ${writeRestriction} restriction cannot be represented as read-only access. Use a plain drive path such as "C:\\..." instead.`);
|
|
@@ -44560,7 +44623,9 @@ function addRulesyncFilesystemRule(permission, pattern, access) {
|
|
|
44560
44623
|
permission.read ??= {};
|
|
44561
44624
|
permission.read[pattern] = "allow";
|
|
44562
44625
|
} else {
|
|
44626
|
+
permission.read ??= {};
|
|
44563
44627
|
permission.edit ??= {};
|
|
44628
|
+
permission.read[pattern] = "allow";
|
|
44564
44629
|
permission.edit[pattern] = "allow";
|
|
44565
44630
|
}
|
|
44566
44631
|
}
|
|
@@ -44696,10 +44761,13 @@ function mapWriteAction(action) {
|
|
|
44696
44761
|
* - A write-side non-allow → `"read"` (readable but not writable — exactly
|
|
44697
44762
|
* what Codex's `"read"` level expresses). An `ask` action is approximated
|
|
44698
44763
|
* this way because Codex has no path-level write approval.
|
|
44699
|
-
* - A write-side-only
|
|
44700
|
-
*
|
|
44701
|
-
* `X/id_rsa`, or `:root`) → `"deny"
|
|
44702
|
-
* path, so emitting `"read"`
|
|
44764
|
+
* - A write-side-only rule (no `read` rule for the same pattern) whose path
|
|
44765
|
+
* is covered by a broader `read` deny/ask rule (e.g. `X/**` covering
|
|
44766
|
+
* `X/id_rsa`, or `:root`) → `"deny"`, for a write-side `allow` too (with a
|
|
44767
|
+
* warning). Codex resolves the most specific path, so emitting `"read"` or
|
|
44768
|
+
* `"write"` there would re-open reads the user denied. Only the most
|
|
44769
|
+
* specific covering read rule counts: a narrower `read: allow` between the
|
|
44770
|
+
* broad deny and the path keeps the path readable.
|
|
44703
44771
|
* - A `read` non-allow on the same pattern → `"deny"` regardless of the
|
|
44704
44772
|
* write side; a contradictory write-side `allow` (unreadable but writable
|
|
44705
44773
|
* is not expressible in Codex) is warned about.
|
|
@@ -44747,10 +44815,11 @@ function mergeFilesystemCategoryRules({ categoryRules, logger }) {
|
|
|
44747
44815
|
}
|
|
44748
44816
|
const writeRestriction = writeAction === "allow" ? void 0 : writeAction;
|
|
44749
44817
|
const readUnspecified = readAction === void 0;
|
|
44750
|
-
if (readUnspecified &&
|
|
44818
|
+
if (readUnspecified && isCoveredByReadRestriction({
|
|
44751
44819
|
pattern,
|
|
44752
44820
|
readRules
|
|
44753
44821
|
})) {
|
|
44822
|
+
if (writeRestriction === void 0) logger?.warn(`Codex CLI cannot express "writable but not readable": pattern "${pattern}" has a write-side allow but is covered by a broader read deny/ask rule. Emitting "deny".`);
|
|
44754
44823
|
merged.push({
|
|
44755
44824
|
pattern,
|
|
44756
44825
|
access: "deny"
|
|
@@ -44767,33 +44836,89 @@ function mergeFilesystemCategoryRules({ categoryRules, logger }) {
|
|
|
44767
44836
|
return merged;
|
|
44768
44837
|
}
|
|
44769
44838
|
function collapseWriteSideRules(categoryRules) {
|
|
44770
|
-
const writeSideRestrictiveness = {
|
|
44771
|
-
deny: 2,
|
|
44772
|
-
ask: 1,
|
|
44773
|
-
allow: 0
|
|
44774
|
-
};
|
|
44775
44839
|
const writeSideRules = {};
|
|
44776
44840
|
for (const category of ["edit", "write"]) for (const [pattern, action] of Object.entries(categoryRules[category] ?? {})) {
|
|
44777
44841
|
const existing = writeSideRules[pattern];
|
|
44778
|
-
if (existing === void 0 ||
|
|
44842
|
+
if (existing === void 0 || PERMISSION_ACTION_RESTRICTIVENESS[action] > PERMISSION_ACTION_RESTRICTIVENESS[existing]) writeSideRules[pattern] = action;
|
|
44779
44843
|
}
|
|
44780
44844
|
return writeSideRules;
|
|
44781
44845
|
}
|
|
44782
44846
|
function isCoveredByReadRestriction({ pattern, readRules }) {
|
|
44783
|
-
const key =
|
|
44784
|
-
|
|
44785
|
-
|
|
44786
|
-
|
|
44787
|
-
|
|
44788
|
-
|
|
44789
|
-
|
|
44790
|
-
|
|
44791
|
-
|
|
44792
|
-
|
|
44793
|
-
|
|
44847
|
+
const key = normalizeCoverageKey(pattern);
|
|
44848
|
+
const isWorkspaceRelative = !canBeCodexFilesystemRoot(pattern);
|
|
44849
|
+
const keyHasDotSegment = hasDotPathSegment(pattern);
|
|
44850
|
+
let best;
|
|
44851
|
+
for (const [readPattern, action] of Object.entries(readRules)) {
|
|
44852
|
+
if (readPattern === pattern) continue;
|
|
44853
|
+
const specificity = coverageSpecificity({
|
|
44854
|
+
readPattern,
|
|
44855
|
+
key,
|
|
44856
|
+
isWorkspaceRelative
|
|
44857
|
+
});
|
|
44858
|
+
if (specificity === void 0) continue;
|
|
44859
|
+
const restrictive = action !== "allow";
|
|
44860
|
+
if (!restrictive && isSkippedCodexGrant(readPattern)) continue;
|
|
44861
|
+
if (!restrictive && (keyHasDotSegment || hasDotPathSegment(readPattern))) continue;
|
|
44862
|
+
if (best === void 0 || specificity > best.specificity || specificity === best.specificity && restrictive) best = {
|
|
44863
|
+
specificity,
|
|
44864
|
+
restrictive
|
|
44865
|
+
};
|
|
44866
|
+
}
|
|
44867
|
+
return best?.restrictive ?? false;
|
|
44868
|
+
}
|
|
44869
|
+
function coverageSpecificity({ readPattern, key, isWorkspaceRelative }) {
|
|
44870
|
+
if (readPattern === ":root" || readPattern === "/**") return 0;
|
|
44871
|
+
if (readPattern === CODEX_WORKSPACE_ROOTS_KEY) return isWorkspaceRelative ? 1 : void 0;
|
|
44872
|
+
if (canBeCodexFilesystemRoot(readPattern) === isWorkspaceRelative) return;
|
|
44873
|
+
const normalized = normalizeCoverageKey(readPattern);
|
|
44874
|
+
if (normalized === "**" || normalized === ".") return isWorkspaceRelative ? 1 : void 0;
|
|
44875
|
+
const withoutTrailingGlob = normalized.endsWith("/**") ? normalized.slice(0, -3) : normalized;
|
|
44876
|
+
if (withoutTrailingGlob.startsWith(":") || hasCodexFilesystemGlob(withoutTrailingGlob)) return;
|
|
44877
|
+
const base = stripTrailingSlash(withoutTrailingGlob);
|
|
44878
|
+
if (base === "") return;
|
|
44879
|
+
return key === base || key.startsWith(base.endsWith("/") ? base : `${base}/`) ? 2 + base.length : void 0;
|
|
44880
|
+
}
|
|
44881
|
+
function normalizeCoverageKey(pattern) {
|
|
44882
|
+
const form = toCoverageForm(pattern);
|
|
44883
|
+
return canBeCodexFilesystemRoot(pattern) && !pattern.startsWith(":") ? resolveDotSegments(form) : form;
|
|
44884
|
+
}
|
|
44885
|
+
function resolveDotSegments(path) {
|
|
44886
|
+
const [anchor = "", ...rest] = path.split("/");
|
|
44887
|
+
const stack = [];
|
|
44888
|
+
for (const segment of rest) {
|
|
44889
|
+
if (segment === ".") continue;
|
|
44890
|
+
if (segment === "..") {
|
|
44891
|
+
if (stack.length > 0 && stack[stack.length - 1] !== "..") stack.pop();
|
|
44892
|
+
else if (anchor === "~") stack.push(segment);
|
|
44893
|
+
continue;
|
|
44894
|
+
}
|
|
44895
|
+
stack.push(segment);
|
|
44896
|
+
}
|
|
44897
|
+
const resolved = [anchor, ...stack].join("/");
|
|
44898
|
+
return resolved === "" ? "/" : stripTrailingSlash(resolved);
|
|
44794
44899
|
}
|
|
44795
|
-
function
|
|
44796
|
-
|
|
44900
|
+
function toCoverageForm(pattern) {
|
|
44901
|
+
let normalized = /^[A-Za-z]:[\\/]/.test(pattern) ? `${pattern.charAt(0).toLowerCase()}${pattern.slice(1).replaceAll("\\", "/")}` : pattern;
|
|
44902
|
+
while (normalized.startsWith("./")) normalized = normalized.slice(2);
|
|
44903
|
+
normalized = stripTrailingSlash(normalized);
|
|
44904
|
+
return normalized === "" && pattern !== "" ? "." : normalized;
|
|
44905
|
+
}
|
|
44906
|
+
function hasDotPathSegment(pattern) {
|
|
44907
|
+
const form = toCoverageForm(pattern);
|
|
44908
|
+
if (form === ".") return false;
|
|
44909
|
+
return form.split(/[\\/]/).some((segment) => segment === "." || segment === "..");
|
|
44910
|
+
}
|
|
44911
|
+
function isSkippedCodexGrant(pattern) {
|
|
44912
|
+
return isWindowsDevicePath(pattern) || hasUnsupportedCodexFilesystemGlob(pattern);
|
|
44913
|
+
}
|
|
44914
|
+
function moreRestrictiveCodexAccess({ a, b }) {
|
|
44915
|
+
const rank = {
|
|
44916
|
+
deny: 0,
|
|
44917
|
+
none: 0,
|
|
44918
|
+
read: 1,
|
|
44919
|
+
write: 2
|
|
44920
|
+
};
|
|
44921
|
+
return rank[a] <= rank[b] ? a : b;
|
|
44797
44922
|
}
|
|
44798
44923
|
function stripTrailingSlash(pattern) {
|
|
44799
44924
|
return pattern.length > 1 && pattern.endsWith("/") ? pattern.slice(0, -1) : pattern;
|
|
@@ -44086,6 +44086,7 @@ var ClinePermissions = class ClinePermissions extends ToolPermissions {
|
|
|
44086
44086
|
//#region src/features/permissions/codexcli-permissions.ts
|
|
44087
44087
|
const RULESYNC_PROFILE_NAME = "rulesync";
|
|
44088
44088
|
const CODEX_WORKSPACE_ROOTS_KEY = ":workspace_roots";
|
|
44089
|
+
const CODEX_WORKSPACE_ROOT_SUBPATH = ".";
|
|
44089
44090
|
const CODEX_WORKSPACE_BASELINE = ":workspace";
|
|
44090
44091
|
const CODEX_READ_ONLY_BASELINE = ":read-only";
|
|
44091
44092
|
const CODEX_DANGER_FULL_ACCESS_BASELINE = ":danger-full-access";
|
|
@@ -44306,7 +44307,15 @@ function convertRulesyncToCodexProfile({ config, logger }) {
|
|
|
44306
44307
|
workspaceRootFilesystem
|
|
44307
44308
|
});
|
|
44308
44309
|
if (Object.keys(workspaceRootFilesystem).length > 0) {
|
|
44309
|
-
|
|
44310
|
+
const directWorkspaceRootsAccess = filesystem[CODEX_WORKSPACE_ROOTS_KEY];
|
|
44311
|
+
if (isCodexFilesystemAccess(directWorkspaceRootsAccess)) {
|
|
44312
|
+
mergeIntoWorkspaceRootTable({
|
|
44313
|
+
workspaceRootFilesystem,
|
|
44314
|
+
pattern: CODEX_WORKSPACE_ROOT_SUBPATH,
|
|
44315
|
+
access: directWorkspaceRootsAccess
|
|
44316
|
+
});
|
|
44317
|
+
logger?.warn(`"${CODEX_WORKSPACE_ROOTS_KEY}" is set as a direct filesystem access rule in the permissions alongside workspace-relative rules; it is emitted as the "${CODEX_WORKSPACE_ROOT_SUBPATH}" entry of the "${CODEX_WORKSPACE_ROOTS_KEY}" table.`);
|
|
44318
|
+
}
|
|
44310
44319
|
if (Object.keys(workspaceRootFilesystem).some((pattern) => pattern.includes("**"))) filesystem.glob_scan_max_depth = CODEX_GLOB_SCAN_MAX_DEPTH;
|
|
44311
44320
|
filesystem[CODEX_WORKSPACE_ROOTS_KEY] = workspaceRootFilesystem;
|
|
44312
44321
|
}
|
|
@@ -44323,9 +44332,13 @@ function convertRulesyncToCodexProfile({ config, logger }) {
|
|
|
44323
44332
|
};
|
|
44324
44333
|
}
|
|
44325
44334
|
function addCodexFilesystemRules({ categoryRules, filesystem, workspaceRootFilesystem, logger }) {
|
|
44326
|
-
|
|
44335
|
+
const normalizedCategoryRules = normalizeWorkspaceRelativeCategoryRules({
|
|
44327
44336
|
categoryRules,
|
|
44328
44337
|
logger
|
|
44338
|
+
});
|
|
44339
|
+
for (const rule of mergeFilesystemCategoryRules({
|
|
44340
|
+
categoryRules: normalizedCategoryRules,
|
|
44341
|
+
logger
|
|
44329
44342
|
})) {
|
|
44330
44343
|
const access = normalizeCodexFilesystemAccess({
|
|
44331
44344
|
pattern: rule.pattern,
|
|
@@ -44492,9 +44505,59 @@ function addFilesystemRule({ filesystem, workspaceRootFilesystem, pattern, acces
|
|
|
44492
44505
|
filesystem[pattern] = access;
|
|
44493
44506
|
return;
|
|
44494
44507
|
}
|
|
44495
|
-
|
|
44508
|
+
mergeIntoWorkspaceRootTable({
|
|
44509
|
+
workspaceRootFilesystem,
|
|
44510
|
+
pattern,
|
|
44511
|
+
access
|
|
44512
|
+
});
|
|
44513
|
+
}
|
|
44514
|
+
const PERMISSION_ACTION_RESTRICTIVENESS = {
|
|
44515
|
+
deny: 2,
|
|
44516
|
+
ask: 1,
|
|
44517
|
+
allow: 0
|
|
44518
|
+
};
|
|
44519
|
+
function normalizeWorkspaceRelativeCategoryRules({ categoryRules, logger }) {
|
|
44520
|
+
const result = {};
|
|
44521
|
+
for (const category of [
|
|
44522
|
+
"read",
|
|
44523
|
+
"edit",
|
|
44524
|
+
"write"
|
|
44525
|
+
]) {
|
|
44526
|
+
const rules = categoryRules[category];
|
|
44527
|
+
if (rules === void 0) continue;
|
|
44528
|
+
const normalized = {};
|
|
44529
|
+
for (const [pattern, action] of Object.entries(rules)) {
|
|
44530
|
+
const key = pattern.trim() === "" || canBeCodexFilesystemRoot(pattern) ? pattern : toWorkspaceRootSubpath(pattern);
|
|
44531
|
+
if (key === void 0) {
|
|
44532
|
+
logger?.warn(`Skipping Codex CLI ${category} filesystem entry for workspace-relative pattern "${pattern}": Codex rejects a ":workspace_roots" subpath containing a ".." segment or an empty leading segment and would refuse the whole config, so the rule is dropped entirely — even a deny — and the path is NOT protected by the generated profile. Use a normalized relative path instead.`);
|
|
44533
|
+
continue;
|
|
44534
|
+
}
|
|
44535
|
+
const existing = normalized[key];
|
|
44536
|
+
normalized[key] = existing === void 0 || PERMISSION_ACTION_RESTRICTIVENESS[action] > PERMISSION_ACTION_RESTRICTIVENESS[existing] ? action : existing;
|
|
44537
|
+
}
|
|
44538
|
+
result[category] = normalized;
|
|
44539
|
+
}
|
|
44540
|
+
return result;
|
|
44541
|
+
}
|
|
44542
|
+
function toWorkspaceRootSubpath(pattern) {
|
|
44543
|
+
let subpath = pattern;
|
|
44544
|
+
while (subpath.startsWith("./")) subpath = subpath.slice(2);
|
|
44545
|
+
if (subpath === "" || subpath === "**" && subpath !== pattern) return CODEX_WORKSPACE_ROOT_SUBPATH;
|
|
44546
|
+
if (subpath.startsWith("/") || subpath.split(/[\\/]/).some((segment) => segment === "..")) return;
|
|
44547
|
+
return subpath;
|
|
44548
|
+
}
|
|
44549
|
+
function mergeIntoWorkspaceRootTable({ workspaceRootFilesystem, pattern, access }) {
|
|
44550
|
+
const existing = workspaceRootFilesystem[pattern];
|
|
44551
|
+
workspaceRootFilesystem[pattern] = existing === void 0 ? access : moreRestrictiveCodexAccess({
|
|
44552
|
+
a: existing,
|
|
44553
|
+
b: access
|
|
44554
|
+
});
|
|
44496
44555
|
}
|
|
44497
44556
|
function normalizeCodexFilesystemAccess({ pattern, access, writeRestriction, logger }) {
|
|
44557
|
+
if (isWindowsDevicePath(pattern) && !canBeCodexFilesystemRoot(pattern)) {
|
|
44558
|
+
logger?.warn(`Skipping Codex CLI ${access} filesystem entry for Windows device path "${pattern}": Codex cannot express it as a workspace-root entry (it is rejected on Windows and matches nothing elsewhere), so the rule is dropped entirely — even a deny — and the path is NOT protected by the generated profile. Use a plain drive path such as "C:\\..." instead.`);
|
|
44559
|
+
return;
|
|
44560
|
+
}
|
|
44498
44561
|
if ((access === "read" || access === "write") && isWindowsDevicePath(pattern)) {
|
|
44499
44562
|
if (writeRestriction !== void 0) {
|
|
44500
44563
|
logger?.warn(`Codex CLI does not support Windows device paths for read/write access: pattern "${pattern}" will be emitted as "deny" because its write-side ${writeRestriction} restriction cannot be represented as read-only access. Use a plain drive path such as "C:\\..." instead.`);
|
|
@@ -44535,7 +44598,9 @@ function addRulesyncFilesystemRule(permission, pattern, access) {
|
|
|
44535
44598
|
permission.read ??= {};
|
|
44536
44599
|
permission.read[pattern] = "allow";
|
|
44537
44600
|
} else {
|
|
44601
|
+
permission.read ??= {};
|
|
44538
44602
|
permission.edit ??= {};
|
|
44603
|
+
permission.read[pattern] = "allow";
|
|
44539
44604
|
permission.edit[pattern] = "allow";
|
|
44540
44605
|
}
|
|
44541
44606
|
}
|
|
@@ -44671,10 +44736,13 @@ function mapWriteAction(action) {
|
|
|
44671
44736
|
* - A write-side non-allow → `"read"` (readable but not writable — exactly
|
|
44672
44737
|
* what Codex's `"read"` level expresses). An `ask` action is approximated
|
|
44673
44738
|
* this way because Codex has no path-level write approval.
|
|
44674
|
-
* - A write-side-only
|
|
44675
|
-
*
|
|
44676
|
-
* `X/id_rsa`, or `:root`) → `"deny"
|
|
44677
|
-
* path, so emitting `"read"`
|
|
44739
|
+
* - A write-side-only rule (no `read` rule for the same pattern) whose path
|
|
44740
|
+
* is covered by a broader `read` deny/ask rule (e.g. `X/**` covering
|
|
44741
|
+
* `X/id_rsa`, or `:root`) → `"deny"`, for a write-side `allow` too (with a
|
|
44742
|
+
* warning). Codex resolves the most specific path, so emitting `"read"` or
|
|
44743
|
+
* `"write"` there would re-open reads the user denied. Only the most
|
|
44744
|
+
* specific covering read rule counts: a narrower `read: allow` between the
|
|
44745
|
+
* broad deny and the path keeps the path readable.
|
|
44678
44746
|
* - A `read` non-allow on the same pattern → `"deny"` regardless of the
|
|
44679
44747
|
* write side; a contradictory write-side `allow` (unreadable but writable
|
|
44680
44748
|
* is not expressible in Codex) is warned about.
|
|
@@ -44722,10 +44790,11 @@ function mergeFilesystemCategoryRules({ categoryRules, logger }) {
|
|
|
44722
44790
|
}
|
|
44723
44791
|
const writeRestriction = writeAction === "allow" ? void 0 : writeAction;
|
|
44724
44792
|
const readUnspecified = readAction === void 0;
|
|
44725
|
-
if (readUnspecified &&
|
|
44793
|
+
if (readUnspecified && isCoveredByReadRestriction({
|
|
44726
44794
|
pattern,
|
|
44727
44795
|
readRules
|
|
44728
44796
|
})) {
|
|
44797
|
+
if (writeRestriction === void 0) logger?.warn(`Codex CLI cannot express "writable but not readable": pattern "${pattern}" has a write-side allow but is covered by a broader read deny/ask rule. Emitting "deny".`);
|
|
44729
44798
|
merged.push({
|
|
44730
44799
|
pattern,
|
|
44731
44800
|
access: "deny"
|
|
@@ -44742,33 +44811,89 @@ function mergeFilesystemCategoryRules({ categoryRules, logger }) {
|
|
|
44742
44811
|
return merged;
|
|
44743
44812
|
}
|
|
44744
44813
|
function collapseWriteSideRules(categoryRules) {
|
|
44745
|
-
const writeSideRestrictiveness = {
|
|
44746
|
-
deny: 2,
|
|
44747
|
-
ask: 1,
|
|
44748
|
-
allow: 0
|
|
44749
|
-
};
|
|
44750
44814
|
const writeSideRules = {};
|
|
44751
44815
|
for (const category of ["edit", "write"]) for (const [pattern, action] of Object.entries(categoryRules[category] ?? {})) {
|
|
44752
44816
|
const existing = writeSideRules[pattern];
|
|
44753
|
-
if (existing === void 0 ||
|
|
44817
|
+
if (existing === void 0 || PERMISSION_ACTION_RESTRICTIVENESS[action] > PERMISSION_ACTION_RESTRICTIVENESS[existing]) writeSideRules[pattern] = action;
|
|
44754
44818
|
}
|
|
44755
44819
|
return writeSideRules;
|
|
44756
44820
|
}
|
|
44757
44821
|
function isCoveredByReadRestriction({ pattern, readRules }) {
|
|
44758
|
-
const key =
|
|
44759
|
-
|
|
44760
|
-
|
|
44761
|
-
|
|
44762
|
-
|
|
44763
|
-
|
|
44764
|
-
|
|
44765
|
-
|
|
44766
|
-
|
|
44767
|
-
|
|
44768
|
-
|
|
44822
|
+
const key = normalizeCoverageKey(pattern);
|
|
44823
|
+
const isWorkspaceRelative = !canBeCodexFilesystemRoot(pattern);
|
|
44824
|
+
const keyHasDotSegment = hasDotPathSegment(pattern);
|
|
44825
|
+
let best;
|
|
44826
|
+
for (const [readPattern, action] of Object.entries(readRules)) {
|
|
44827
|
+
if (readPattern === pattern) continue;
|
|
44828
|
+
const specificity = coverageSpecificity({
|
|
44829
|
+
readPattern,
|
|
44830
|
+
key,
|
|
44831
|
+
isWorkspaceRelative
|
|
44832
|
+
});
|
|
44833
|
+
if (specificity === void 0) continue;
|
|
44834
|
+
const restrictive = action !== "allow";
|
|
44835
|
+
if (!restrictive && isSkippedCodexGrant(readPattern)) continue;
|
|
44836
|
+
if (!restrictive && (keyHasDotSegment || hasDotPathSegment(readPattern))) continue;
|
|
44837
|
+
if (best === void 0 || specificity > best.specificity || specificity === best.specificity && restrictive) best = {
|
|
44838
|
+
specificity,
|
|
44839
|
+
restrictive
|
|
44840
|
+
};
|
|
44841
|
+
}
|
|
44842
|
+
return best?.restrictive ?? false;
|
|
44843
|
+
}
|
|
44844
|
+
function coverageSpecificity({ readPattern, key, isWorkspaceRelative }) {
|
|
44845
|
+
if (readPattern === ":root" || readPattern === "/**") return 0;
|
|
44846
|
+
if (readPattern === CODEX_WORKSPACE_ROOTS_KEY) return isWorkspaceRelative ? 1 : void 0;
|
|
44847
|
+
if (canBeCodexFilesystemRoot(readPattern) === isWorkspaceRelative) return;
|
|
44848
|
+
const normalized = normalizeCoverageKey(readPattern);
|
|
44849
|
+
if (normalized === "**" || normalized === ".") return isWorkspaceRelative ? 1 : void 0;
|
|
44850
|
+
const withoutTrailingGlob = normalized.endsWith("/**") ? normalized.slice(0, -3) : normalized;
|
|
44851
|
+
if (withoutTrailingGlob.startsWith(":") || hasCodexFilesystemGlob(withoutTrailingGlob)) return;
|
|
44852
|
+
const base = stripTrailingSlash(withoutTrailingGlob);
|
|
44853
|
+
if (base === "") return;
|
|
44854
|
+
return key === base || key.startsWith(base.endsWith("/") ? base : `${base}/`) ? 2 + base.length : void 0;
|
|
44855
|
+
}
|
|
44856
|
+
function normalizeCoverageKey(pattern) {
|
|
44857
|
+
const form = toCoverageForm(pattern);
|
|
44858
|
+
return canBeCodexFilesystemRoot(pattern) && !pattern.startsWith(":") ? resolveDotSegments(form) : form;
|
|
44859
|
+
}
|
|
44860
|
+
function resolveDotSegments(path) {
|
|
44861
|
+
const [anchor = "", ...rest] = path.split("/");
|
|
44862
|
+
const stack = [];
|
|
44863
|
+
for (const segment of rest) {
|
|
44864
|
+
if (segment === ".") continue;
|
|
44865
|
+
if (segment === "..") {
|
|
44866
|
+
if (stack.length > 0 && stack[stack.length - 1] !== "..") stack.pop();
|
|
44867
|
+
else if (anchor === "~") stack.push(segment);
|
|
44868
|
+
continue;
|
|
44869
|
+
}
|
|
44870
|
+
stack.push(segment);
|
|
44871
|
+
}
|
|
44872
|
+
const resolved = [anchor, ...stack].join("/");
|
|
44873
|
+
return resolved === "" ? "/" : stripTrailingSlash(resolved);
|
|
44769
44874
|
}
|
|
44770
|
-
function
|
|
44771
|
-
|
|
44875
|
+
function toCoverageForm(pattern) {
|
|
44876
|
+
let normalized = /^[A-Za-z]:[\\/]/.test(pattern) ? `${pattern.charAt(0).toLowerCase()}${pattern.slice(1).replaceAll("\\", "/")}` : pattern;
|
|
44877
|
+
while (normalized.startsWith("./")) normalized = normalized.slice(2);
|
|
44878
|
+
normalized = stripTrailingSlash(normalized);
|
|
44879
|
+
return normalized === "" && pattern !== "" ? "." : normalized;
|
|
44880
|
+
}
|
|
44881
|
+
function hasDotPathSegment(pattern) {
|
|
44882
|
+
const form = toCoverageForm(pattern);
|
|
44883
|
+
if (form === ".") return false;
|
|
44884
|
+
return form.split(/[\\/]/).some((segment) => segment === "." || segment === "..");
|
|
44885
|
+
}
|
|
44886
|
+
function isSkippedCodexGrant(pattern) {
|
|
44887
|
+
return isWindowsDevicePath(pattern) || hasUnsupportedCodexFilesystemGlob(pattern);
|
|
44888
|
+
}
|
|
44889
|
+
function moreRestrictiveCodexAccess({ a, b }) {
|
|
44890
|
+
const rank = {
|
|
44891
|
+
deny: 0,
|
|
44892
|
+
none: 0,
|
|
44893
|
+
read: 1,
|
|
44894
|
+
write: 2
|
|
44895
|
+
};
|
|
44896
|
+
return rank[a] <= rank[b] ? a : b;
|
|
44772
44897
|
}
|
|
44773
44898
|
function stripTrailingSlash(pattern) {
|
|
44774
44899
|
return pattern.length > 1 && pattern.endsWith("/") ? pattern.slice(0, -1) : pattern;
|
|
@@ -82459,4 +82584,4 @@ async function importChecksCore(params) {
|
|
|
82459
82584
|
//#endregion
|
|
82460
82585
|
export { RulesyncCommand as $, toPosixPath as $t, CLAUDECODE_MEMORIES_DIR_NAME as A, RULESYNC_XDG_CONFIG_HOME_DEFAULT_DIR_NAME as An, checkPathTraversal as At, RulesyncSubagent as B, stripControlCharacters as Bn, listDirectoryEntryNames as Bt, COMMANDCODE_DIR as C, RULESYNC_PERMISSIONS_SCHEMA_URL as Cn, withWarnOnceScope as Ct, CODEXCLI_DIR as D, RULESYNC_SOURCES_LOCK_RELATIVE_FILE_PATH as Dn, assertDirectoryIfExists as Dt, CODEXCLI_BASH_RULES_FILE_NAME as E, RULESYNC_SKILLS_RELATIVE_DIR_PATH as En, applyFileMode as Et, caseFoldIdentity as F, formatError as Fn, getFileSize as Ft, RulesyncRuleFrontmatterSchema as G, readFileContentOrNull as Gt, RulesyncSkill as H, stripHiddenCharacters as Hn, listSubdirectoryNames as Ht, groupSpellingsByCaseFoldedIdentity as I, truncateText as In, getHomeDirectory as It, RulesyncIgnore as J, removeFile as Jt, RulesyncPermissions as K, removeDirectory as Kt, AUGMENTCODE_DIR as L, hasDeceptiveHiddenCharacters as Ln, isFileNotFoundError as Lt, CLAUDECODE_SKILLS_DIR_PATH as M, ALL_FEATURES as Mn, directoryExists as Mt, FACTORYDROID_DIR as N, ALL_FEATURES_WITH_WILDCARD as Nn, ensureDir as Nt, CLAUDECODE_DIR as O, RULESYNC_SUBAGENTS_RELATIVE_DIR_PATH as On, assertTreeContainsNoSymlinks as Ot, FACTORYDROID_SETTINGS_LOCAL_FILE_NAME as P, DEPRECATED_FEATURE_REPLACEMENTS as Pn, fileExists as Pt, parseJsonc as Q, runWithDirectoryRollback as Qt, AUGMENTCODE_SETTINGS_LOCAL_FILE_NAME as R, hasEnclosingMarkOutsideKeycap as Rn, isFileSystemError as Rt, QWENCODE_LOCAL_RULE_FILE_NAME as S, RULESYNC_PERMISSIONS_RELATIVE_FILE_PATH as Sn, resetRunWarningState as St, ChecksProcessor as T, RULESYNC_RULES_RELATIVE_DIR_PATH as Tn, ErrorCodes as Tt, RulesyncSkillFrontmatterSchema as U, pathEscapesRoot as Ut, RulesyncSubagentFrontmatterSchema as V, stripControlCharactersKeepingLineFeeds as Vn, listFilePathsRecursively as Vt, RulesyncRule as W, readFileContent as Wt, getRulesyncSourceCandidates as X, removeTempDirectory as Xt, RulesyncHooks as Y, removeFileStrict as Yt, resolveRulesyncSourceWritePath as Z, resolvePath as Zt, IgnoreProcessor as _, RULESYNC_IGNORE_RELATIVE_FILE_PATH as _n, JsonLogger as _t, getProcessorRegistryEntry as a, ToolTargetSchema as an, SHARED_USER_MANAGED_CONFIG_PATHS as at, CommandsProcessor as b, RULESYNC_MCP_SCHEMA_URL as bn, warnOnConflictingFlags as bt, RulesProcessor as c, MAX_FILE_SIZE as cn, mergeInputRootConfigs as ct, CODEBUDDY_DIR as d, RULESYNC_COMMANDS_RELATIVE_DIR_PATH as dn, ConfigFileSchema as dt, writeFileBuffer as en, RulesyncCommandFrontmatterSchema as et, CODEBUDDY_LOCAL_RULE_FILE_NAME as f, RULESYNC_CONFIG_RELATIVE_FILE_PATH as fn, GITIGNORE_DESTINATION_KEY as ft, McpProcessor as g, RULESYNC_HOOKS_RELATIVE_FILE_PATH as gn, ConsoleLogger as gt, shortenToWidth as h, RULESYNC_CURATED_SKILLS_RELATIVE_DIR_PATH as hn, findControlCharacter as ht, inspectInputRoots as i, PACKAGING_TOOL_TARGETS as in, loadYaml as it, CLAUDECODE_SETTINGS_LOCAL_FILE_NAME as j, parseCommaSeparatedList as jn, createTempDirectory as jt, CLAUDECODE_LOCAL_RULE_FILE_NAME as k, RULESYNC_USER_CONFIG_DIR_NAME as kn, assertWritablePathInsideRoot as kt, SubagentsProcessor as l, RULESYNC_AIIGNORE_RELATIVE_FILE_PATH as ln, resolveEffectiveInputRoots as lt, displayWidthOf as m, RULESYNC_CURATED_RULES_RELATIVE_DIR_PATH as mn, assertTargetsFeaturesExclusive as mt, formatSourceLoadFailure as n, ALL_TOOL_TARGETS as nn, RulesyncCheckFrontmatterSchema as nt, convertFromTool as o, CURATED_RULES_FEATURE_SUBDIR as on, SKILL_FILE_NAME as ot, ELLIPSIS_WIDTH as p, RULESYNC_CONFIG_SCHEMA_URL as pn, SourceEntrySchema as pt, RulesyncMcp as q, removeDirectoryStrict as qt, generate as r, ALL_TOOL_TARGETS_WITH_WILDCARD as rn, stringifyFrontmatter as rt, isPackagingToolTarget as s, FEATURE_SOURCE_TREE_ENTRIES as sn, ConfigResolver as st, importFromTool as t, writeFileContent as tn, RulesyncCheck as tt, SkillsProcessor as u, RULESYNC_CHECKS_RELATIVE_DIR_PATH as un, CONFLICTING_TARGET_PAIRS as ut, HooksProcessor as v, RULESYNC_LOCAL_CONFIG_RELATIVE_FILE_PATH as vn, WarningCollectingLogger as vt, COMMANDCODE_SETTINGS_LOCAL_FILE_NAME as w, RULESYNC_RELATIVE_DIR_PATH as wn, CLIError as wt, QWENCODE_DIR as x, RULESYNC_NPM_SOURCES_LOCK_RELATIVE_FILE_PATH as xn, withFallbackLoggerTarget as xt, CRUSH_LOCAL_RULE_FILE_NAME as y, RULESYNC_MCP_RELATIVE_FILE_PATH as yn, fallbackLogger as yt, getLocalSkillDirNames as z, quoteForLog as zn, isSymlink as zt };
|
|
82461
82586
|
|
|
82462
|
-
//# sourceMappingURL=import-
|
|
82587
|
+
//# sourceMappingURL=import-C-Jsxedt.js.map
|