dsh-permission-rules 0.7.4 → 0.7.6

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/lib/index.js CHANGED
@@ -1643,61 +1643,146 @@ function resolveBuiltinRulesPath(custom) {
1643
1643
  * a validated {@link Config} field changeable from cordis.yml; the
1644
1644
  * resolution step validates the numeric bounds and compiles nothing — rule
1645
1645
  * files are external documents resolved per session cwd at load time.
1646
+ *
1647
+ * Since the `0.1.7-alpha` settings contract every field is declared
1648
+ * `.volatile()`, so the Loader hands `apply` a live reference per field
1649
+ * ({@link LiveConfig}) and the settings surface edits them in place. The
1650
+ * numeric bounds live in the SCHEMA (`min`/`max`/`step`) as well as in
1651
+ * {@link resolveConfig}: the config editor resolves the merged config
1652
+ * against this schema before it persists anything, so an out-of-range value
1653
+ * is still refused at write time — the tradeoff the removed
1654
+ * `settings.register(..., { validate })` callback used to carry.
1646
1655
  * @module dsh-permission-rules/config
1647
1656
  */
1648
- /** Schemastery schema: the loader validates and fills defaults before `apply`. */
1657
+ /**
1658
+ * Mark one schema field as a live reference, where the host can.
1659
+ *
1660
+ * `.volatile()` first appeared in `@deepseek-ai/schemastery` 3.18.3, and this
1661
+ * schema is built while the plugin module is evaluated — an unguarded call
1662
+ * would turn every host line the package's peer ranges still advertise
1663
+ * (`0.1.2-rc`, `0.1.5-alpha`, `0.1.6-0`) into a hard mount crash. Probed
1664
+ * instead: on a Schemastery without the method the field stays an ordinary
1665
+ * value, the Loader hands `apply` a plain config ({@link plainConfig} passes
1666
+ * it straight through), and the plugin runs exactly as it did before live
1667
+ * forms existed — only the settings form is unavailable there, which is the
1668
+ * same degradation as a host that composes no settings service at all.
1669
+ * @param schema - the field schema.
1670
+ * @returns the same field schema, live where supported.
1671
+ */
1672
+ function live(schema) {
1673
+ const builder = schema;
1674
+ return typeof builder.volatile === "function" ? builder.volatile() : schema;
1675
+ }
1676
+ /**
1677
+ * Schemastery schema: the loader validates and fills defaults before
1678
+ * `apply`. Every field is live (see {@link live}), so on a `0.1.7-alpha`
1679
+ * host the Loader hands `apply` a reference per field and the settings
1680
+ * surface can edit each one in place. `network` and `builtin` are marked
1681
+ * live as WHOLE objects — Schemastery refuses a volatile inside a volatile,
1682
+ * and the only supported shape is a fixed object path.
1683
+ *
1684
+ * The numeric bounds are declared here (not only in {@link resolveConfig})
1685
+ * because the config editor resolves the merged config against THIS schema
1686
+ * before persisting it: an out-of-range edit is refused at write time
1687
+ * instead of disabling the plugin on the next read.
1688
+ */
1649
1689
  const Config = z.object({
1650
- rulesFile: z.string().default(".dsh/rules.yaml"),
1651
- fallbackPath: z.string(),
1652
- badFilePolicy: z.union(["fail", "ignore-with-warning"]).default("fail"),
1653
- maxRules: z.number().default(256),
1654
- maxCachedWorkspaces: z.number().default(512),
1655
- patternMode: z.union(["glob", "regex"]).default("glob"),
1656
- watch: z.boolean().default(true),
1657
- watchStabilityThresholdMs: z.number().default(200),
1658
- language: z.union([
1690
+ rulesFile: live(z.string().default(".dsh/rules.yaml")),
1691
+ fallbackPath: live(z.string()),
1692
+ badFilePolicy: live(z.union(["fail", "ignore-with-warning"]).default("fail")),
1693
+ maxRules: live(z.number().step(1).min(1).default(256)),
1694
+ maxCachedWorkspaces: live(z.number().step(1).min(1).default(512)),
1695
+ patternMode: live(z.union(["glob", "regex"]).default("glob")),
1696
+ watch: live(z.boolean().default(true)),
1697
+ watchStabilityThresholdMs: live(z.number().step(1).min(0).default(200)),
1698
+ language: live(z.union([
1659
1699
  "en",
1660
1700
  "zh",
1661
1701
  "es",
1662
1702
  "pt",
1663
1703
  "hi"
1664
- ]).default("en"),
1665
- caseInsensitivePaths: z.boolean().default(process.platform === "win32"),
1666
- audit: z.union(["all", "hits"]).default("all"),
1667
- searchUp: z.boolean().default(false),
1668
- maxGlobStars: z.number().default(2),
1669
- enforce: z.boolean().default(true),
1670
- allowUnmarkedAudit: z.boolean().default(false),
1671
- network: z.object({
1704
+ ]).default("en")),
1705
+ caseInsensitivePaths: live(z.boolean().default(process.platform === "win32")),
1706
+ audit: live(z.union(["all", "hits"]).default("all")),
1707
+ searchUp: live(z.boolean().default(false)),
1708
+ maxGlobStars: live(z.number().step(1).min(1).default(2)),
1709
+ enforce: live(z.boolean().default(true)),
1710
+ allowUnmarkedAudit: live(z.boolean().default(false)),
1711
+ network: live(z.object({
1672
1712
  enabled: z.boolean().default(true),
1673
1713
  mode: z.union(["auto", ...NETWORK_MODES]).default("auto"),
1674
1714
  autoFallback: z.union(NETWORK_MODES).default("allow-all"),
1675
1715
  unlisted: z.union(["ask", "deny"]).default("ask"),
1676
1716
  proxyBind: z.string().default("127.0.0.1"),
1677
- proxyPort: z.number().default(0),
1678
- proxyMaxRecent: z.number().default(100),
1717
+ proxyPort: z.number().step(1).min(0).max(65535).default(0),
1718
+ proxyMaxRecent: z.number().step(1).min(1).default(100),
1679
1719
  loopback: z.union(["allow", "policy"]).default("allow"),
1680
1720
  injectEnv: z.boolean().default(true),
1681
1721
  noProxy: z.union(["clear", "preserve"]).default("clear"),
1682
1722
  upstreamProxy: z.string().default("off"),
1683
1723
  allowHostAction: z.boolean().default(true)
1684
- }),
1685
- builtin: z.object({
1724
+ })),
1725
+ builtin: live(z.object({
1686
1726
  enabled: z.boolean().default(true),
1687
1727
  path: z.string()
1688
- })
1728
+ }))
1689
1729
  });
1690
1730
  /**
1731
+ * Whether `value` is the Loader's live config rather than a plain one.
1732
+ * `rulesFile` is the discriminator: it always has a schema default, so the
1733
+ * Loader always materializes its reference, plain or absent.
1734
+ * @param value - a raw or live config.
1735
+ * @returns true when the fields are live references.
1736
+ */
1737
+ function isLiveConfig(value) {
1738
+ return typeof value.rulesFile?.get === "function";
1739
+ }
1740
+ /**
1741
+ * Unwrap the Loader's live references into the plain config
1742
+ * {@link resolveConfig} validates. Reading each reference HERE is what keeps
1743
+ * a caller's config source lazy: call it inside the closure, never at
1744
+ * closure-construction time, or a live edit stops being visible.
1745
+ * @param config - the raw config, or the Loader's live one.
1746
+ * @returns the plain raw config (the input itself when it was already plain).
1747
+ */
1748
+ function plainConfig(config) {
1749
+ if (!isLiveConfig(config)) return config;
1750
+ return {
1751
+ rulesFile: config.rulesFile.get(),
1752
+ fallbackPath: config.fallbackPath.get(),
1753
+ badFilePolicy: config.badFilePolicy.get(),
1754
+ maxRules: config.maxRules.get(),
1755
+ maxCachedWorkspaces: config.maxCachedWorkspaces.get(),
1756
+ patternMode: config.patternMode.get(),
1757
+ watch: config.watch.get(),
1758
+ watchStabilityThresholdMs: config.watchStabilityThresholdMs.get(),
1759
+ language: config.language.get(),
1760
+ caseInsensitivePaths: config.caseInsensitivePaths.get(),
1761
+ audit: config.audit.get(),
1762
+ searchUp: config.searchUp.get(),
1763
+ maxGlobStars: config.maxGlobStars.get(),
1764
+ enforce: config.enforce.get(),
1765
+ allowUnmarkedAudit: config.allowUnmarkedAudit.get(),
1766
+ network: config.network.get(),
1767
+ builtin: config.builtin.get()
1768
+ };
1769
+ }
1770
+ /**
1691
1771
  * Validate raw values and fill explicit defaults. A `maxRules`,
1692
1772
  * `maxCachedWorkspaces`, or `maxGlobStars` that is not a positive safe
1693
1773
  * integer, a non-positive stability window, `searchUp` combined with an
1694
1774
  * absolute `rulesFile`, a value outside a closed enum, or a non-boolean
1695
1775
  * flag throws here — misconfiguration fails loud at mount even when the
1696
1776
  * plugin is mounted without the Schemastery loader.
1697
- * @param config - raw (possibly partial) plugin config.
1777
+ *
1778
+ * Accepts the Loader's live config directly and unwraps it through
1779
+ * {@link plainConfig}, so a caller can keep this call inside its config
1780
+ * source and see every live edit on the next read.
1781
+ * @param input - raw (possibly partial) plugin config, or the Loader's live one.
1698
1782
  * @returns the fully resolved config.
1699
1783
  */
1700
- function resolveConfig(config = {}) {
1784
+ function resolveConfig(input = {}) {
1785
+ const config = plainConfig(input);
1701
1786
  const rulesFile = config.rulesFile ?? ".dsh/rules.yaml";
1702
1787
  const searchUp = config.searchUp ?? false;
1703
1788
  if (searchUp && isAbsolute(rulesFile)) throw new TypeError(`searchUp cannot be combined with an absolute rulesFile (${JSON.stringify(rulesFile)}): parent-directory walking needs a relative file name`);
@@ -2954,33 +3039,32 @@ var PermissionRulesRemoteService = class extends TypertRemoteService {
2954
3039
  };
2955
3040
  //#endregion
2956
3041
  //#region src/settings.ts
2957
- /** The settings namespace this plugin owns (kebab-case, per the provider contract). */
2958
- const SETTINGS_NAMESPACE = "permission-rules";
2959
3042
  /**
2960
- * Register the settings section and bind the runtime's live config
2961
- * source. Runs only where a settings service is composed.
3043
+ * Point the runtime's live config source at the Loader's references and
3044
+ * register this instance's settings-page policy.
2962
3045
  * @param ctx - the plugin context.
2963
- * @param runtime - the runtime whose config source follows the section.
2964
- * @param entry - the composition entry config (the section's `base` layer).
3046
+ * @param runtime - the runtime whose config source follows the references.
3047
+ * @param config - the Loader-delivered live config (references to the entry's values).
2965
3048
  */
2966
- function attachSettingsSection(ctx, runtime, entry) {
3049
+ function attachSettingsSection(ctx, runtime, config) {
2967
3050
  ctx.inject(["settings"], (scope) => {
2968
3051
  const settings = scope.get("settings");
2969
- if (settings === void 0) return;
2970
- const registration = settings.register(SETTINGS_NAMESPACE, Config, {
2971
- base: entry,
2972
- expose: true,
2973
- applies: "live",
2974
- validate: (value) => {
2975
- resolveConfig(value);
2976
- }
2977
- });
2978
- runtime.setConfigSource(() => resolveConfig(registration.get()));
2979
- registration.watch((next, prev) => {
2980
- const nextConfig = resolveConfig(next);
2981
- const prevConfig = resolveConfig(prev);
2982
- if (nextConfig.network.proxyPort !== prevConfig.network.proxyPort || nextConfig.network.proxyBind !== prevConfig.network.proxyBind || nextConfig.network.injectEnv !== prevConfig.network.injectEnv || nextConfig.network.noProxy !== prevConfig.network.noProxy) runtime.onNetworkConfigChanged();
2983
- });
3052
+ if (settings?.configure === void 0) return;
3053
+ scope.effect(() => settings.configure({ auto: false }, ctx.fiber));
3054
+ });
3055
+ runtime.setConfigSource(() => resolveConfig(config));
3056
+ let previous = resolveConfig(config);
3057
+ ctx.on("loader/volatile-update", () => {
3058
+ let next;
3059
+ try {
3060
+ next = resolveConfig(config);
3061
+ } catch (error) {
3062
+ ctx.logger.warn(`permission-rules: live config update is not usable: ${error instanceof Error ? error.message : String(error)}`);
3063
+ return;
3064
+ }
3065
+ const rebind = next.network.proxyPort !== previous.network.proxyPort || next.network.proxyBind !== previous.network.proxyBind || next.network.injectEnv !== previous.network.injectEnv || next.network.noProxy !== previous.network.noProxy;
3066
+ previous = next;
3067
+ if (rebind) runtime.onNetworkConfigChanged();
2984
3068
  });
2985
3069
  }
2986
3070
  //#endregion
@@ -4581,8 +4665,13 @@ var PermissionRulesRuntime = class {
4581
4665
  /**
4582
4666
  * Mount the plugin: resolve config, validate deployment-level rule files,
4583
4667
  * register the pre-execute listener and the `/rules` command.
4668
+ *
4669
+ * The `config` argument is the Loader's LIVE config (every field a
4670
+ * `.volatile()` reference, see {@link LiveConfig}); `resolveConfig` unwraps
4671
+ * it, and the same object is handed to {@link attachSettingsSection} so the
4672
+ * runtime keeps reading the current values instead of a mount-time snapshot.
4584
4673
  * @param ctx - the host context.
4585
- * @param config - raw plugin config.
4674
+ * @param config - the Loader-delivered live plugin config.
4586
4675
  */
4587
4676
  async function apply(ctx, config) {
4588
4677
  const resolved = resolveConfig(config);
@@ -4744,4 +4833,4 @@ const name = "permission-rules";
4744
4833
  /** Consumer — the /rules command handler and the tools/pre-execute waterfall listener consume the injected commands/tools services. */
4745
4834
  const inject = ["commands", "tools"];
4746
4835
  //#endregion
4747
- export { BUILTIN_RULES_FILE, Config, GlobError, NETWORK_MODES, NO_PROXY_ENV_NAMES, NetworkProxy, PATH_CANDIDATE_KEYS, PLATFORMS, PROXY_ENV_NAMES, PermissionRulesRuntime, RULE_ACTIONS, RuleError, SCHEMES, SHIPPED_BUILTIN_RULES, URL_CANDIDATE_KEYS, apply, blockMessage, compileGlob, compilePatternRegex, compileRules, compileRulesChain, compileSourceRules, decideNetworkTarget, decomposeShellCommand, defaultDecision, describeRule, extractPathCandidates, extractUrlCandidates, findUnreachableRules, inject, injectProxyEnv, isIpLiteral, isLoopbackTarget, isMarkedAuditEvent, isShellTool, isUnmarkedHostVersion, matchRules, matchTools, matchWhen, mergeCompiledRules, name, networkModeForSandbox, normalizeHost, normalizeWorkspacePath, parseRulesDocument, parseUrlTarget, readAmbientProxy, redactProxyUrl, resolveBuiltinRulesPath, resolveConfig, targetMatchesNetwork };
4836
+ export { BUILTIN_RULES_FILE, Config, GlobError, NETWORK_MODES, NO_PROXY_ENV_NAMES, NetworkProxy, PATH_CANDIDATE_KEYS, PLATFORMS, PROXY_ENV_NAMES, PermissionRulesRuntime, RULE_ACTIONS, RuleError, SCHEMES, SHIPPED_BUILTIN_RULES, URL_CANDIDATE_KEYS, apply, blockMessage, compileGlob, compilePatternRegex, compileRules, compileRulesChain, compileSourceRules, decideNetworkTarget, decomposeShellCommand, defaultDecision, describeRule, extractPathCandidates, extractUrlCandidates, findUnreachableRules, inject, injectProxyEnv, isIpLiteral, isLoopbackTarget, isMarkedAuditEvent, isShellTool, isUnmarkedHostVersion, matchRules, matchTools, matchWhen, mergeCompiledRules, name, networkModeForSandbox, normalizeHost, normalizeWorkspacePath, parseRulesDocument, parseUrlTarget, plainConfig, readAmbientProxy, redactProxyUrl, resolveBuiltinRulesPath, resolveConfig, targetMatchesNetwork };
@@ -4099,17 +4099,17 @@ function superRefine(fn, params) {
4099
4099
  * @module dsh-permission-rules/wire
4100
4100
  */
4101
4101
  /**
4102
- * Strict wire codec carrying BOTH published and checkout faces: the `schema`
4103
- * field feeds the npm-published 0.1.5-rc.2 line, while `create` feeds the
4104
- * 0.1.6-alpha.2+ line, whose typert-loader requires the factory on every
4105
- * codec and materializes schemas lazily on first use. Built through a
4106
- * variable, so neither typecheck ruler flags the other face's field as excess.
4102
+ * Strict wire codec. `create` is the ONLY schema face the `0.1.7-alpha`
4103
+ * `TypertCodec` declares — it materializes the process-realm schema on first
4104
+ * boundary use — and the typert-loader rejects any codec without it. The
4105
+ * older published lines also carried a literal `schema` field on the codec;
4106
+ * that face is gone from the contract, so carrying it here would be dead
4107
+ * weight (and only the `create` factory is ever consulted at run time).
4107
4108
  */
4108
4109
  function strictWire(typeSymbol, schema) {
4109
4110
  return Object.freeze({
4110
4111
  mode: "strict",
4111
4112
  typeSymbol,
4112
- schema,
4113
4113
  create: () => schema
4114
4114
  });
4115
4115
  }
@@ -46,47 +46,9 @@ export declare const PERMISSION_RULES_REMOTE: Readonly<{
46
46
  }>;
47
47
  readonly parameters: readonly never[];
48
48
  readonly result: Readonly<{
49
- create: () => import("zod").ZodObject<{
50
- enabled: import("zod").ZodBoolean;
51
- mode: import("zod").ZodUnion<readonly [import("zod").ZodLiteral<"deny-all">, import("zod").ZodLiteral<"whitelist">, import("zod").ZodLiteral<"allow-all">]>;
52
- configuredMode: import("zod").ZodUnion<readonly [import("zod").ZodLiteral<"auto">, import("zod").ZodLiteral<"deny-all">, import("zod").ZodLiteral<"whitelist">, import("zod").ZodLiteral<"allow-all">]>;
53
- sandboxMode: import("zod").ZodNullable<import("zod").ZodString>;
54
- proxyPort: import("zod").ZodNumber;
55
- proxyActive: import("zod").ZodBoolean;
56
- denied: import("zod").ZodNumber;
57
- askBlocked: import("zod").ZodNumber;
58
- recent: import("zod").ZodArray<import("zod").ZodObject<{
59
- time: import("zod").ZodNumber;
60
- tool: import("zod").ZodString;
61
- attributed: import("zod").ZodBoolean;
62
- domain: import("zod").ZodString;
63
- scheme: import("zod").ZodUnion<readonly [import("zod").ZodLiteral<"http">, import("zod").ZodLiteral<"https">, import("zod").ZodNull]>;
64
- port: import("zod").ZodNullable<import("zod").ZodNumber>;
65
- action: import("zod").ZodUnion<readonly [import("zod").ZodLiteral<"deny">, import("zod").ZodLiteral<"ask">]>;
66
- mode: import("zod").ZodUnion<readonly [import("zod").ZodLiteral<"deny-all">, import("zod").ZodLiteral<"whitelist">, import("zod").ZodLiteral<"allow-all">]>;
67
- matched: import("zod").ZodBoolean;
68
- source: import("zod").ZodString;
69
- ruleIndex: import("zod").ZodNullable<import("zod").ZodNumber>;
70
- reason: import("zod").ZodNullable<import("zod").ZodString>;
71
- cwd: import("zod").ZodNullable<import("zod").ZodString>;
72
- }, import("zod/v4/core").$strip>>;
73
- sources: import("zod").ZodArray<import("zod").ZodObject<{
74
- path: import("zod").ZodString;
75
- exists: import("zod").ZodBoolean;
76
- cwd: import("zod").ZodNullable<import("zod").ZodString>;
77
- }, import("zod/v4/core").$strip>>;
78
- allowHostAction: import("zod").ZodBoolean;
79
- upstream: import("zod").ZodObject<{
80
- mode: import("zod").ZodUnion<readonly [import("zod").ZodLiteral<"off">, import("zod").ZodLiteral<"inherit">, import("zod").ZodLiteral<"url">]>;
81
- http: import("zod").ZodNullable<import("zod").ZodString>;
82
- https: import("zod").ZodNullable<import("zod").ZodString>;
83
- active: import("zod").ZodBoolean;
84
- chained: import("zod").ZodNumber;
85
- }, import("zod/v4/core").$strip>;
86
- }, import("zod/v4/core").$strip>;
87
49
  mode: "strict";
88
50
  typeSymbol: string;
89
- schema: import("zod").ZodObject<{
51
+ create: () => import("zod").ZodObject<{
90
52
  enabled: import("zod").ZodBoolean;
91
53
  mode: import("zod").ZodUnion<readonly [import("zod").ZodLiteral<"deny-all">, import("zod").ZodLiteral<"whitelist">, import("zod").ZodLiteral<"allow-all">]>;
92
54
  configuredMode: import("zod").ZodUnion<readonly [import("zod").ZodLiteral<"auto">, import("zod").ZodLiteral<"deny-all">, import("zod").ZodLiteral<"whitelist">, import("zod").ZodLiteral<"allow-all">]>;
@@ -143,22 +105,15 @@ export declare const PERMISSION_RULES_REMOTE: Readonly<{
143
105
  wire: string;
144
106
  source: "json";
145
107
  codec: Readonly<{
146
- create: () => import("zod").ZodString;
147
108
  mode: "strict";
148
109
  typeSymbol: string;
149
- schema: import("zod").ZodString;
110
+ create: () => import("zod").ZodString;
150
111
  }>;
151
112
  }>[];
152
113
  readonly result: Readonly<{
153
- create: () => import("zod").ZodObject<{
154
- path: import("zod").ZodString;
155
- exists: import("zod").ZodBoolean;
156
- text: import("zod").ZodString;
157
- error: import("zod").ZodNullable<import("zod").ZodString>;
158
- }, import("zod/v4/core").$strip>;
159
114
  mode: "strict";
160
115
  typeSymbol: string;
161
- schema: import("zod").ZodObject<{
116
+ create: () => import("zod").ZodObject<{
162
117
  path: import("zod").ZodString;
163
118
  exists: import("zod").ZodBoolean;
164
119
  text: import("zod").ZodString;
@@ -183,21 +138,15 @@ export declare const PERMISSION_RULES_REMOTE: Readonly<{
183
138
  wire: string;
184
139
  source: "json";
185
140
  codec: Readonly<{
186
- create: () => import("zod").ZodString;
187
141
  mode: "strict";
188
142
  typeSymbol: string;
189
- schema: import("zod").ZodString;
143
+ create: () => import("zod").ZodString;
190
144
  }>;
191
145
  }>[];
192
146
  readonly result: Readonly<{
193
- create: () => import("zod").ZodObject<{
194
- ok: import("zod").ZodBoolean;
195
- error: import("zod").ZodNullable<import("zod").ZodString>;
196
- reloaded: import("zod").ZodNullable<import("zod").ZodNumber>;
197
- }, import("zod/v4/core").$strip>;
198
147
  mode: "strict";
199
148
  typeSymbol: string;
200
- schema: import("zod").ZodObject<{
149
+ create: () => import("zod").ZodObject<{
201
150
  ok: import("zod").ZodBoolean;
202
151
  error: import("zod").ZodNullable<import("zod").ZodString>;
203
152
  reloaded: import("zod").ZodNullable<import("zod").ZodNumber>;
@@ -218,13 +167,9 @@ export declare const PERMISSION_RULES_REMOTE: Readonly<{
218
167
  }>;
219
168
  readonly parameters: readonly never[];
220
169
  readonly result: Readonly<{
221
- create: () => import("zod").ZodObject<{
222
- ok: import("zod").ZodBoolean;
223
- error: import("zod").ZodNullable<import("zod").ZodString>;
224
- }, import("zod/v4/core").$strip>;
225
170
  mode: "strict";
226
171
  typeSymbol: string;
227
- schema: import("zod").ZodObject<{
172
+ create: () => import("zod").ZodObject<{
228
173
  ok: import("zod").ZodBoolean;
229
174
  error: import("zod").ZodNullable<import("zod").ZodString>;
230
175
  }, import("zod/v4/core").$strip>;
@@ -247,15 +192,9 @@ export declare const PERMISSION_RULES_REMOTE: Readonly<{
247
192
  wire: string;
248
193
  source: "json";
249
194
  codec: Readonly<{
250
- create: () => import("zod").ZodObject<{
251
- host: import("zod").ZodString;
252
- scheme: import("zod").ZodUnion<readonly [import("zod").ZodLiteral<"http">, import("zod").ZodLiteral<"https">, import("zod").ZodNull]>;
253
- port: import("zod").ZodNullable<import("zod").ZodNumber>;
254
- cwd: import("zod").ZodNullable<import("zod").ZodString>;
255
- }, import("zod/v4/core").$strip>;
256
195
  mode: "strict";
257
196
  typeSymbol: string;
258
- schema: import("zod").ZodObject<{
197
+ create: () => import("zod").ZodObject<{
259
198
  host: import("zod").ZodString;
260
199
  scheme: import("zod").ZodUnion<readonly [import("zod").ZodLiteral<"http">, import("zod").ZodLiteral<"https">, import("zod").ZodNull]>;
261
200
  port: import("zod").ZodNullable<import("zod").ZodNumber>;
@@ -264,18 +203,9 @@ export declare const PERMISSION_RULES_REMOTE: Readonly<{
264
203
  }>;
265
204
  }>[];
266
205
  readonly result: Readonly<{
267
- create: () => import("zod").ZodObject<{
268
- ok: import("zod").ZodBoolean;
269
- path: import("zod").ZodNullable<import("zod").ZodString>;
270
- created: import("zod").ZodBoolean;
271
- reloaded: import("zod").ZodNumber;
272
- outcome: import("zod").ZodUnion<readonly [import("zod").ZodLiteral<"allow">, import("zod").ZodLiteral<"deny">, import("zod").ZodLiteral<"ask">, import("zod").ZodNull]>;
273
- alreadyAllowed: import("zod").ZodBoolean;
274
- error: import("zod").ZodNullable<import("zod").ZodString>;
275
- }, import("zod/v4/core").$strip>;
276
206
  mode: "strict";
277
207
  typeSymbol: string;
278
- schema: import("zod").ZodObject<{
208
+ create: () => import("zod").ZodObject<{
279
209
  ok: import("zod").ZodBoolean;
280
210
  path: import("zod").ZodNullable<import("zod").ZodString>;
281
211
  created: import("zod").ZodBoolean;
@@ -1 +1 @@
1
- {"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../../../src/client/remote.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,YAAY,EAA4B,MAAM,kCAAkC,CAAA;AAE9F,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,uBAAuB,EAAE,eAAe,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjJ,OAAO,QAAQ,kCAAkC,CAAC;IAChD,UAAU,qCAAqC;QAC7C,+FAA+F;QAC/F,aAAa,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,uBAAuB,CAAC,CAAC,CAAA;QACnE,+CAA+C;QAC/C,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,CAAA;QACnE,8CAA8C;QAC9C,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,CAAA;QACjF,4CAA4C;QAC5C,MAAM,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC,CAAA;QACtD,4FAA4F;QAC5F,SAAS,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,CAAA;KACjF;IACD,UAAU,eAAe;QACvB,+BAA+B,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,uBAAuB,CAAC,CAAC,CAAA;QACrF,2BAA2B,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,CAAA;QACrF,2BAA2B,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,CAAA;QACnG,wBAAwB,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC,CAAA;QACxE,2BAA2B,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,CAAA;KACnG;IACD,UAAU,wBAAwB;QAChC,eAAe,EAAE,qCAAqC,CAAA;KACvD;CACF;AAED,0EAA0E;AAC1E,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGC,CAAA"}
1
+ {"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../../../src/client/remote.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,YAAY,EAA4B,MAAM,kCAAkC,CAAA;AAE9F,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,uBAAuB,EAAE,eAAe,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjJ,OAAO,QAAQ,kCAAkC,CAAC;IAChD,UAAU,qCAAqC;QAC7C,+FAA+F;QAC/F,aAAa,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,uBAAuB,CAAC,CAAC,CAAA;QACnE,+CAA+C;QAC/C,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,CAAA;QACnE,8CAA8C;QAC9C,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,CAAA;QACjF,4CAA4C;QAC5C,MAAM,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC,CAAA;QACtD,4FAA4F;QAC5F,SAAS,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,CAAA;KACjF;IACD,UAAU,eAAe;QACvB,+BAA+B,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,uBAAuB,CAAC,CAAC,CAAA;QACrF,2BAA2B,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,CAAA;QACrF,2BAA2B,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,CAAA;QACnG,wBAAwB,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC,CAAA;QACxE,2BAA2B,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,CAAA;KACnG;IACD,UAAU,wBAAwB;QAChC,eAAe,EAAE,qCAAqC,CAAA;KACvD;CACF;AAED,0EAA0E;AAC1E,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGC,CAAA"}
@@ -3,6 +3,15 @@
3
3
  * a validated {@link Config} field changeable from cordis.yml; the
4
4
  * resolution step validates the numeric bounds and compiles nothing — rule
5
5
  * files are external documents resolved per session cwd at load time.
6
+ *
7
+ * Since the `0.1.7-alpha` settings contract every field is declared
8
+ * `.volatile()`, so the Loader hands `apply` a live reference per field
9
+ * ({@link LiveConfig}) and the settings surface edits them in place. The
10
+ * numeric bounds live in the SCHEMA (`min`/`max`/`step`) as well as in
11
+ * {@link resolveConfig}: the config editor resolves the merged config
12
+ * against this schema before it persists anything, so an out-of-range value
13
+ * is still refused at write time — the tradeoff the removed
14
+ * `settings.register(..., { validate })` callback used to carry.
6
15
  * @module dsh-permission-rules/config
7
16
  */
8
17
  import z from '@deepseek-ai/schemastery';
@@ -86,8 +95,10 @@ export interface Config {
86
95
  /**
87
96
  * Fallback rule file used when per-cwd discovery finds no rule file.
88
97
  * Absolute, or relative to `process.cwd()`. Unset = an empty rule set.
98
+ * Declared `| undefined` because a live reference to a field the schema
99
+ * gives no default reports an absent value explicitly.
89
100
  */
90
- fallbackPath?: string;
101
+ fallbackPath?: string | undefined;
91
102
  /**
92
103
  * How an unreadable/invalid rule file is handled at load: `'fail'` throws
93
104
  * (the pending tool call errors loudly; HMR reloads keep the previous
@@ -134,9 +145,9 @@ export interface Config {
134
145
  */
135
146
  allowUnmarkedAudit?: boolean;
136
147
  /** Process-level network policy (all optional; defaults inside). */
137
- network?: NetworkConfig;
148
+ network?: NetworkConfig | undefined;
138
149
  /** Built-in high-risk baseline (all optional; defaults inside). */
139
- builtin?: BuiltinConfig;
150
+ builtin?: BuiltinConfig | undefined;
140
151
  }
141
152
  /** Network config after {@link resolveConfig}: every optional field has its explicit default. */
142
153
  export interface ResolvedNetworkConfig {
@@ -179,8 +190,133 @@ export interface ResolvedConfig {
179
190
  readonly network: ResolvedNetworkConfig;
180
191
  readonly builtin: ResolvedBuiltinConfig;
181
192
  }
182
- /** Schemastery schema: the loader validates and fills defaults before `apply`. */
183
- export declare const Config: z<Config>;
193
+ /**
194
+ * Schemastery schema: the loader validates and fills defaults before
195
+ * `apply`. Every field is live (see {@link live}), so on a `0.1.7-alpha`
196
+ * host the Loader hands `apply` a reference per field and the settings
197
+ * surface can edit each one in place. `network` and `builtin` are marked
198
+ * live as WHOLE objects — Schemastery refuses a volatile inside a volatile,
199
+ * and the only supported shape is a fixed object path.
200
+ *
201
+ * The numeric bounds are declared here (not only in {@link resolveConfig})
202
+ * because the config editor resolves the merged config against THIS schema
203
+ * before persisting it: an out-of-range edit is refused at write time
204
+ * instead of disabling the plugin on the next read.
205
+ */
206
+ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
207
+ rulesFile: z<string, string, "volatile-defined">;
208
+ fallbackPath: z<string, string, "volatile">;
209
+ badFilePolicy: z<"fail" | "ignore-with-warning", "fail" | "ignore-with-warning", "volatile-defined">;
210
+ maxRules: z<number, number, "volatile-defined">;
211
+ maxCachedWorkspaces: z<number, number, "volatile-defined">;
212
+ patternMode: z<"glob" | "regex", "glob" | "regex", "volatile-defined">;
213
+ watch: z<boolean, boolean, "volatile-defined">;
214
+ watchStabilityThresholdMs: z<number, number, "volatile-defined">;
215
+ language: z<"en" | "zh" | "es" | "pt" | "hi", "en" | "zh" | "es" | "pt" | "hi", "volatile-defined">;
216
+ caseInsensitivePaths: z<boolean, boolean, "volatile-defined">;
217
+ audit: z<"all" | "hits", "all" | "hits", "volatile-defined">;
218
+ searchUp: z<boolean, boolean, "volatile-defined">;
219
+ maxGlobStars: z<number, number, "volatile-defined">;
220
+ enforce: z<boolean, boolean, "volatile-defined">;
221
+ allowUnmarkedAudit: z<boolean, boolean, "volatile-defined">;
222
+ network: z<NoInfer<Schemastery.ObjectS<NoInfer<{
223
+ enabled: z<boolean, boolean, "defined">;
224
+ mode: z<"deny-all" | "whitelist" | "allow-all" | "auto", "deny-all" | "whitelist" | "allow-all" | "auto", "defined">;
225
+ autoFallback: z<"deny-all" | "whitelist" | "allow-all", "deny-all" | "whitelist" | "allow-all", "defined">;
226
+ unlisted: z<"deny" | "ask", "deny" | "ask", "defined">;
227
+ proxyBind: z<string, string, "defined">;
228
+ proxyPort: z<number, number, "defined">;
229
+ proxyMaxRecent: z<number, number, "defined">;
230
+ loopback: z<"allow" | "policy", "allow" | "policy", "defined">;
231
+ injectEnv: z<boolean, boolean, "defined">;
232
+ noProxy: z<"clear" | "preserve", "clear" | "preserve", "defined">;
233
+ upstreamProxy: z<string, string, "defined">;
234
+ allowHostAction: z<boolean, boolean, "defined">;
235
+ }>>>, NoInfer<Schemastery.ObjectT<NoInfer<{
236
+ enabled: z<boolean, boolean, "defined">;
237
+ mode: z<"deny-all" | "whitelist" | "allow-all" | "auto", "deny-all" | "whitelist" | "allow-all" | "auto", "defined">;
238
+ autoFallback: z<"deny-all" | "whitelist" | "allow-all", "deny-all" | "whitelist" | "allow-all", "defined">;
239
+ unlisted: z<"deny" | "ask", "deny" | "ask", "defined">;
240
+ proxyBind: z<string, string, "defined">;
241
+ proxyPort: z<number, number, "defined">;
242
+ proxyMaxRecent: z<number, number, "defined">;
243
+ loopback: z<"allow" | "policy", "allow" | "policy", "defined">;
244
+ injectEnv: z<boolean, boolean, "defined">;
245
+ noProxy: z<"clear" | "preserve", "clear" | "preserve", "defined">;
246
+ upstreamProxy: z<string, string, "defined">;
247
+ allowHostAction: z<boolean, boolean, "defined">;
248
+ }>>>, "volatile">;
249
+ builtin: z<NoInfer<Schemastery.ObjectS<NoInfer<{
250
+ enabled: z<boolean, boolean, "defined">;
251
+ path: z<string, string, "plain">;
252
+ }>>>, NoInfer<Schemastery.ObjectT<NoInfer<{
253
+ enabled: z<boolean, boolean, "defined">;
254
+ path: z<string, string, "plain">;
255
+ }>>>, "volatile">;
256
+ }>>, Schemastery.ObjectT<NoInfer<{
257
+ rulesFile: z<string, string, "volatile-defined">;
258
+ fallbackPath: z<string, string, "volatile">;
259
+ badFilePolicy: z<"fail" | "ignore-with-warning", "fail" | "ignore-with-warning", "volatile-defined">;
260
+ maxRules: z<number, number, "volatile-defined">;
261
+ maxCachedWorkspaces: z<number, number, "volatile-defined">;
262
+ patternMode: z<"glob" | "regex", "glob" | "regex", "volatile-defined">;
263
+ watch: z<boolean, boolean, "volatile-defined">;
264
+ watchStabilityThresholdMs: z<number, number, "volatile-defined">;
265
+ language: z<"en" | "zh" | "es" | "pt" | "hi", "en" | "zh" | "es" | "pt" | "hi", "volatile-defined">;
266
+ caseInsensitivePaths: z<boolean, boolean, "volatile-defined">;
267
+ audit: z<"all" | "hits", "all" | "hits", "volatile-defined">;
268
+ searchUp: z<boolean, boolean, "volatile-defined">;
269
+ maxGlobStars: z<number, number, "volatile-defined">;
270
+ enforce: z<boolean, boolean, "volatile-defined">;
271
+ allowUnmarkedAudit: z<boolean, boolean, "volatile-defined">;
272
+ network: z<NoInfer<Schemastery.ObjectS<NoInfer<{
273
+ enabled: z<boolean, boolean, "defined">;
274
+ mode: z<"deny-all" | "whitelist" | "allow-all" | "auto", "deny-all" | "whitelist" | "allow-all" | "auto", "defined">;
275
+ autoFallback: z<"deny-all" | "whitelist" | "allow-all", "deny-all" | "whitelist" | "allow-all", "defined">;
276
+ unlisted: z<"deny" | "ask", "deny" | "ask", "defined">;
277
+ proxyBind: z<string, string, "defined">;
278
+ proxyPort: z<number, number, "defined">;
279
+ proxyMaxRecent: z<number, number, "defined">;
280
+ loopback: z<"allow" | "policy", "allow" | "policy", "defined">;
281
+ injectEnv: z<boolean, boolean, "defined">;
282
+ noProxy: z<"clear" | "preserve", "clear" | "preserve", "defined">;
283
+ upstreamProxy: z<string, string, "defined">;
284
+ allowHostAction: z<boolean, boolean, "defined">;
285
+ }>>>, NoInfer<Schemastery.ObjectT<NoInfer<{
286
+ enabled: z<boolean, boolean, "defined">;
287
+ mode: z<"deny-all" | "whitelist" | "allow-all" | "auto", "deny-all" | "whitelist" | "allow-all" | "auto", "defined">;
288
+ autoFallback: z<"deny-all" | "whitelist" | "allow-all", "deny-all" | "whitelist" | "allow-all", "defined">;
289
+ unlisted: z<"deny" | "ask", "deny" | "ask", "defined">;
290
+ proxyBind: z<string, string, "defined">;
291
+ proxyPort: z<number, number, "defined">;
292
+ proxyMaxRecent: z<number, number, "defined">;
293
+ loopback: z<"allow" | "policy", "allow" | "policy", "defined">;
294
+ injectEnv: z<boolean, boolean, "defined">;
295
+ noProxy: z<"clear" | "preserve", "clear" | "preserve", "defined">;
296
+ upstreamProxy: z<string, string, "defined">;
297
+ allowHostAction: z<boolean, boolean, "defined">;
298
+ }>>>, "volatile">;
299
+ builtin: z<NoInfer<Schemastery.ObjectS<NoInfer<{
300
+ enabled: z<boolean, boolean, "defined">;
301
+ path: z<string, string, "plain">;
302
+ }>>>, NoInfer<Schemastery.ObjectT<NoInfer<{
303
+ enabled: z<boolean, boolean, "defined">;
304
+ path: z<string, string, "plain">;
305
+ }>>>, "volatile">;
306
+ }>>, "plain">;
307
+ /** The Loader-delivered config: every field is a live reference to its current value. */
308
+ export type LiveConfig = ReturnType<typeof Config>;
309
+ /** What {@link resolveConfig} accepts: the raw config, or the Loader's live one. */
310
+ export type ConfigInput = Config | LiveConfig;
311
+ /**
312
+ * Unwrap the Loader's live references into the plain config
313
+ * {@link resolveConfig} validates. Reading each reference HERE is what keeps
314
+ * a caller's config source lazy: call it inside the closure, never at
315
+ * closure-construction time, or a live edit stops being visible.
316
+ * @param config - the raw config, or the Loader's live one.
317
+ * @returns the plain raw config (the input itself when it was already plain).
318
+ */
319
+ export declare function plainConfig(config: ConfigInput): Config;
184
320
  /**
185
321
  * Validate raw values and fill explicit defaults. A `maxRules`,
186
322
  * `maxCachedWorkspaces`, or `maxGlobStars` that is not a positive safe
@@ -188,8 +324,12 @@ export declare const Config: z<Config>;
188
324
  * absolute `rulesFile`, a value outside a closed enum, or a non-boolean
189
325
  * flag throws here — misconfiguration fails loud at mount even when the
190
326
  * plugin is mounted without the Schemastery loader.
191
- * @param config - raw (possibly partial) plugin config.
327
+ *
328
+ * Accepts the Loader's live config directly and unwraps it through
329
+ * {@link plainConfig}, so a caller can keep this call inside its config
330
+ * source and see every live edit on the next read.
331
+ * @param input - raw (possibly partial) plugin config, or the Loader's live one.
192
332
  * @returns the fully resolved config.
193
333
  */
194
- export declare function resolveConfig(config?: Config): ResolvedConfig;
334
+ export declare function resolveConfig(input?: ConfigInput): ResolvedConfig;
195
335
  //# sourceMappingURL=config.d.ts.map