rulesync 10.0.0 → 11.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.
@@ -17454,7 +17454,11 @@ const CodexApprovalPolicySchema = zod_mini.z.enum([
17454
17454
  ]);
17455
17455
  /**
17456
17456
  * Codex CLI's classic sandbox mode. Serialized as a kebab-case string in
17457
- * `.codex/config.toml`.
17457
+ * `.codex/config.toml`. Deprecated in favor of permission profiles
17458
+ * (`base_permission_profile`): Codex prioritizes these legacy sandbox keys
17459
+ * over permission profiles when both are present, so authoring one disables
17460
+ * the managed `[permissions.rulesync]` profile. Kept so existing configs
17461
+ * round-trip.
17458
17462
  * @see https://learn.chatgpt.com/docs/config-file/config-reference
17459
17463
  */
17460
17464
  const CodexSandboxModeSchema = zod_mini.z.enum([
@@ -17474,6 +17478,18 @@ const CodexApprovalsReviewerSchema = zod_mini.z.enum([
17474
17478
  "guardian_subagent"
17475
17479
  ]);
17476
17480
  /**
17481
+ * Codex CLI's built-in permission profiles that the managed
17482
+ * `[permissions.rulesync]` profile may extend. Codex ships three built-in
17483
+ * profiles (`:read-only`, `:workspace`, `:danger-full-access`; the leading
17484
+ * colon is reserved for built-ins), but `extends` rejects
17485
+ * `:danger-full-access` at config load time, so only the two extendable
17486
+ * baselines are accepted here. The value list is exported so the Codex CLI
17487
+ * translator derives its import-side baseline check from the same source.
17488
+ * @see https://learn.chatgpt.com/docs/permissions
17489
+ */
17490
+ const CODEX_BASE_PERMISSION_PROFILES = [":read-only", ":workspace"];
17491
+ const CodexBasePermissionProfileSchema = zod_mini.z.enum(CODEX_BASE_PERMISSION_PROFILES);
17492
+ /**
17477
17493
  * Codex CLI-scoped permission override.
17478
17494
  *
17479
17495
  * Codex CLI's permission surface is richer than the canonical allow/ask/deny
@@ -17482,16 +17498,29 @@ const CodexApprovalsReviewerSchema = zod_mini.z.enum([
17482
17498
  * override whose fields are written verbatim as top-level `.codex/config.toml`
17483
17499
  * keys (the override wins per key; existing sibling keys the user set directly
17484
17500
  * are preserved):
17501
+ * - `base_permission_profile` — the built-in profile the managed
17502
+ * `[permissions.rulesync]` profile extends (`:read-only` | `:workspace`).
17503
+ * Unlike the other keys it is not a top-level config key: it is emitted as
17504
+ * the profile's `extends` value. Defaults to `:workspace` when unspecified.
17485
17505
  * - `approval_policy` — `untrusted` | `on-request` (legacy alias `on-failure`) |
17486
17506
  * `never`, or a `{ granular = { … } }` table (kept verbatim; the granular
17487
17507
  * schema has required fields that are brittle to model as typed keys).
17488
- * - `sandbox_mode` `read-only` | `workspace-write` | `danger-full-access`,
17489
- * with the sibling `sandbox_workspace_write` table (`network_access`,
17490
- * `writable_roots`, …).
17508
+ * Defaults to `on-request` when neither the override nor the existing
17509
+ * config sets it.
17510
+ * - `sandbox_mode` — **deprecated.** `read-only` | `workspace-write` |
17511
+ * `danger-full-access`, with the sibling `sandbox_workspace_write` table
17512
+ * (`network_access`, `writable_roots`, …). Codex has superseded the classic
17513
+ * sandbox system with permission profiles and prioritizes these legacy keys
17514
+ * over profiles when both are present, so setting them disables the managed
17515
+ * `[permissions.rulesync]` profile. Use `base_permission_profile` and the
17516
+ * shared `permission` block instead. Still accepted so existing configs
17517
+ * round-trip.
17491
17518
  * - `apps` — per-app tool gating (`apps.<id>.tools.<tool>.approval_mode` /
17492
17519
  * `.enabled`, `apps.<id>.default_tools_approval_mode`).
17493
17520
  * - `approvals_reviewer` — the reviewer-approval surface (`user` | `auto_review`
17494
17521
  * | `guardian_subagent`), or a table for the richer reviewer config.
17522
+ * Defaults to `auto_review` when neither the override nor the existing
17523
+ * config sets it.
17495
17524
  *
17496
17525
  * Two surfaces are deliberately NOT authorable here so the override can never
17497
17526
  * clobber a feature-owned key: `mcp_servers.*` per-MCP gating is owned by the
@@ -17510,8 +17539,11 @@ const CodexApprovalsReviewerSchema = zod_mini.z.enum([
17510
17539
  */
17511
17540
  const CodexcliPermissionsOverrideSchema = zod_mini.z.looseObject({
17512
17541
  permission: zod_mini.z.optional(ToolScopedPermissionSchema),
17542
+ base_permission_profile: zod_mini.z.optional(CodexBasePermissionProfileSchema),
17513
17543
  approval_policy: zod_mini.z.optional(zod_mini.z.union([CodexApprovalPolicySchema, zod_mini.z.looseObject({})])),
17544
+ /** @deprecated Superseded by `base_permission_profile` (permission profiles). */
17514
17545
  sandbox_mode: zod_mini.z.optional(CodexSandboxModeSchema),
17546
+ /** @deprecated Superseded by `base_permission_profile` (permission profiles). */
17515
17547
  sandbox_workspace_write: zod_mini.z.optional(zod_mini.z.looseObject({})),
17516
17548
  apps: zod_mini.z.optional(zod_mini.z.looseObject({})),
17517
17549
  approvals_reviewer: zod_mini.z.optional(zod_mini.z.union([CodexApprovalsReviewerSchema, zod_mini.z.looseObject({})]))
@@ -19483,13 +19515,10 @@ var ClinePermissions = class ClinePermissions extends ToolPermissions {
19483
19515
  const RULESYNC_PROFILE_NAME = "rulesync";
19484
19516
  const CODEX_WORKSPACE_ROOTS_KEY = ":workspace_roots";
19485
19517
  const CODEX_WORKSPACE_BASELINE = ":workspace";
19518
+ const CODEX_EXTENDABLE_BASELINES = new Set(CODEX_BASE_PERMISSION_PROFILES);
19519
+ const CODEX_DEFAULT_APPROVAL_POLICY = "on-request";
19520
+ const CODEX_DEFAULT_APPROVALS_REVIEWER = "auto_review";
19486
19521
  const CODEX_GLOB_SCAN_MAX_DEPTH = 8;
19487
- const WORKSPACE_WIDE_WRITE_PATTERNS = /* @__PURE__ */ new Set([
19488
- ".",
19489
- "./",
19490
- "**",
19491
- "./**"
19492
- ]);
19493
19522
  const CODEX_MINIMAL_KEY = ":minimal";
19494
19523
  const GLOBAL_WILDCARD_DOMAIN = "*";
19495
19524
  var CodexcliPermissions = class CodexcliPermissions extends ToolPermissions {
@@ -19579,6 +19608,7 @@ var CodexcliPermissions = class CodexcliPermissions extends ToolPermissions {
19579
19608
  domainsHadUnknown
19580
19609
  });
19581
19610
  const override = extractCodexcliOverride(table);
19611
+ if (typeof profile?.extends === "string" && CODEX_EXTENDABLE_BASELINES.has(profile.extends)) override.base_permission_profile = profile.extends;
19582
19612
  const result = Object.keys(override).length > 0 ? {
19583
19613
  ...config,
19584
19614
  codexcli: override
@@ -19661,14 +19691,14 @@ function convertRulesyncToCodexProfile({ config, logger }) {
19661
19691
  if (Object.keys(workspaceRootFilesystem).some((pattern) => pattern.includes("**"))) filesystem.glob_scan_max_depth = CODEX_GLOB_SCAN_MAX_DEPTH;
19662
19692
  filesystem[CODEX_WORKSPACE_ROOTS_KEY] = workspaceRootFilesystem;
19663
19693
  }
19664
- const hasWorkspaceWideWrite = Object.entries(workspaceRootFilesystem).some(([pattern, access]) => access === "write" && WORKSPACE_WIDE_WRITE_PATTERNS.has(pattern));
19694
+ const basePermissionProfile = config.codexcli?.base_permission_profile ?? CODEX_WORKSPACE_BASELINE;
19665
19695
  const hasAllowDomain = Object.values(domains).some((action) => action === "allow");
19666
19696
  const network = Object.keys(domains).length > 0 ? {
19667
19697
  ...hasAllowDomain ? { enabled: true } : {},
19668
19698
  domains
19669
19699
  } : void 0;
19670
19700
  return {
19671
- ...hasWorkspaceWideWrite ? { extends: CODEX_WORKSPACE_BASELINE } : {},
19701
+ extends: basePermissionProfile,
19672
19702
  filesystem,
19673
19703
  ...network ? { network } : {}
19674
19704
  };
@@ -19687,10 +19717,6 @@ function convertCodexProfileToRulesync({ profile, domainsHadUnknown }) {
19687
19717
  if (isCodexFilesystemRuleTable(access)) for (const [nestedPattern, nestedAccess] of Object.entries(access)) addRulesyncFilesystemRule(permission, nestedPattern, nestedAccess);
19688
19718
  }
19689
19719
  }
19690
- if (profile?.extends === CODEX_WORKSPACE_BASELINE) {
19691
- permission.edit ??= {};
19692
- permission.edit["."] ??= "allow";
19693
- }
19694
19720
  if (profile?.network && profile.network.enabled !== false) {
19695
19721
  const networkEnabled = profile.network.enabled === true;
19696
19722
  const importedEntries = (profile.network.domains ? Object.entries(profile.network.domains) : []).filter(([, value]) => value === "deny" || networkEnabled);
@@ -19729,7 +19755,7 @@ function toCodexProfile(value) {
19729
19755
  };
19730
19756
  }
19731
19757
  function warnAboutPreservedProfileState({ existingProfile, newProfile, existingDomainsHadUnknown, logger }) {
19732
- if (existingProfile?.extends !== void 0 && existingProfile.extends !== newProfile.extends) logger?.warn(`Existing "extends" value "${existingProfile.extends}" will be replaced by Rulesync-managed "${newProfile.extends ?? "(none)"}".`);
19758
+ if (existingProfile !== void 0 && existingProfile.extends !== newProfile.extends) logger?.warn(`Existing "extends" value "${existingProfile.extends ?? "(none)"}" will be replaced by Rulesync-managed "${newProfile.extends ?? "(none)"}".`);
19733
19759
  if (existingProfile?.network?.unix_sockets !== void 0) logger?.warn(`Preserving existing "network.unix_sockets" from config. Review these entries manually as they may grant broad system access.`);
19734
19760
  if (existingProfile?.network?.mode !== void 0) logger?.warn(`Preserving existing "network.mode" from config. Review this value manually as it may grant broader network access than the Rulesync-managed domain rules.`);
19735
19761
  if (existingDomainsHadUnknown) logger?.warn(`Existing "network.domains" contained unrecognized values. These entries were skipped and will not be imported.`);
@@ -19823,20 +19849,26 @@ function isPlainObject(value) {
19823
19849
  }
19824
19850
  function computeCodexcliOverridePatch({ existing, override, logger }) {
19825
19851
  const patch = {};
19826
- if (!override) return patch;
19827
19852
  const allowed = new Set(CODEXCLI_OVERRIDE_KEYS);
19828
- for (const [key, value] of Object.entries(override)) {
19853
+ for (const [key, value] of Object.entries(override ?? {})) {
19854
+ if (key === "base_permission_profile") continue;
19829
19855
  if (!allowed.has(key)) {
19830
19856
  logger?.warn(`Codex CLI permission override key "${key}" is not managed and was skipped. "permissions"/"default_permissions" are owned by the canonical permission model and "mcp_servers" gating by the MCP feature.`);
19831
19857
  continue;
19832
19858
  }
19833
19859
  if (value === void 0) continue;
19860
+ if (key === "sandbox_mode" || key === "sandbox_workspace_write") logger?.warn(`Codex CLI permission override key "${key}" is deprecated. Codex prioritizes the legacy sandbox settings over permission profiles when both are present, so it disables the generated "${RULESYNC_PROFILE_NAME}" permissions profile. Use "base_permission_profile" and the shared "permission" block instead.`);
19834
19861
  const existingValue = existing[key];
19835
19862
  patch[key] = isPlainObject(existingValue) && isPlainObject(value) ? {
19836
19863
  ...existingValue,
19837
19864
  ...value
19838
19865
  } : value;
19839
19866
  }
19867
+ const defaults = {
19868
+ approval_policy: CODEX_DEFAULT_APPROVAL_POLICY,
19869
+ approvals_reviewer: CODEX_DEFAULT_APPROVALS_REVIEWER
19870
+ };
19871
+ for (const [key, value] of Object.entries(defaults)) if (patch[key] === void 0 && existing[key] === void 0) patch[key] = value;
19840
19872
  return patch;
19841
19873
  }
19842
19874
  function extractCodexcliOverride(table) {
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_import = require("./import-Dcj5HiOE.cjs");
2
+ const require_import = require("./import-ESr9cSFw.cjs");
3
3
  //#region src/index.ts
4
4
  async function generate(options = {}) {
5
5
  const { silent = true, verbose = false, ...rest } = options;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { F as ConfigResolver, L as ConsoleLogger, Nt as ALL_FEATURES, a as convertFromTool$1, n as checkRulesyncDirExists, r as generate$1, rt as ALL_TOOL_TARGETS, t as importFromTool$1 } from "./import-B02AyWkQ.js";
1
+ import { F as ConfigResolver, L as ConsoleLogger, Nt as ALL_FEATURES, a as convertFromTool$1, n as checkRulesyncDirExists, r as generate$1, rt as ALL_TOOL_TARGETS, t as importFromTool$1 } from "./import-AKytnIKl.js";
2
2
  //#region src/index.ts
3
3
  async function generate(options = {}) {
4
4
  const { silent = true, verbose = false, ...rest } = options;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rulesync",
3
- "version": "10.0.0",
3
+ "version": "11.0.0",
4
4
  "description": "Unified AI rules management CLI tool that generates configuration files for various AI development tools",
5
5
  "keywords": [
6
6
  "ai",