dsh-permission-rules 0.7.21 → 0.7.22

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
@@ -512,44 +512,123 @@ var RuleError = class extends Error {
512
512
  * Parse one rules file body. Unknown document/rule/match fields, invalid
513
513
  * actions, missing reasons, and wrong-shaped collections all throw
514
514
  * {@link RuleError} — a malformed file fails loudly at load, never silently.
515
+ * This is the STRICT shape: editor saves use it so a hand edit is refused
516
+ * with its error instead of being silently dropped. The loader uses
517
+ * {@link parseRulesDocumentIsolated} instead, where one bad rule disables
518
+ * only itself.
515
519
  * @param text - the raw YAML text.
516
520
  * @returns the validated document.
517
521
  */
518
522
  function parseRulesDocument(text) {
523
+ return { rules: parseRulesSection(text).map((raw, index) => parseRuleEntry(raw, index)) };
524
+ }
525
+ /**
526
+ * Parse one rules file body with per-rule isolation (issue #49): a rule
527
+ * whose shape is invalid is skipped and reported in
528
+ * {@link RulesFileDoc.issues}, and every other rule still loads. Document
529
+ * STRUCTURE errors (invalid YAML, an unknown top-level field, a `rules`
530
+ * value that is not a list) are still file-level and throw: they leave no
531
+ * rule list to isolate.
532
+ * @param text - the raw YAML text.
533
+ * @returns the validated document plus the skipped-rule reports.
534
+ */
535
+ function parseRulesDocumentIsolated(text) {
536
+ const rules = [];
537
+ const issues = [];
538
+ parseRulesSection(text).forEach((raw, index) => {
539
+ try {
540
+ rules.push(parseRuleEntry(raw, index));
541
+ } catch (error) {
542
+ issues.push({
543
+ index,
544
+ message: ruleErrorMessage(error)
545
+ });
546
+ }
547
+ });
548
+ return issues.length === 0 ? { rules } : {
549
+ rules,
550
+ issues
551
+ };
552
+ }
553
+ /**
554
+ * Parse the document SHELL: validate the YAML, the top-level mapping, and
555
+ * the `rules` list, returning the raw rule entries. Everything below this
556
+ * level can be isolated per rule.
557
+ */
558
+ function parseRulesSection(text) {
519
559
  const parsed = parseYaml(normalizeLineEndings(text));
520
- if (parsed === null || parsed === void 0) return { rules: [] };
560
+ if (parsed === null || parsed === void 0) return [];
521
561
  const root = asRecord(parsed, "rules document root");
522
562
  const unknownRoot = Object.keys(root).filter((key) => key !== "rules");
523
563
  if (unknownRoot.length > 0) throw new RuleError(`unknown top-level field${unknownRoot.length > 1 ? "s" : ""} ${unknownRoot.map((k) => JSON.stringify(k)).join(", ")} (only "rules" is allowed)`);
524
564
  const rawRules = root["rules"];
525
- if (rawRules === void 0) return { rules: [] };
565
+ if (rawRules === void 0) return [];
526
566
  if (!Array.isArray(rawRules)) throw new RuleError("\"rules\" must be a list");
527
- return { rules: rawRules.map((raw, index) => parseRuleEntry(raw, index)) };
567
+ return rawRules;
568
+ }
569
+ /** One error's message, for an isolated-rule report. */
570
+ function ruleErrorMessage(error) {
571
+ return error instanceof Error ? error.message : String(error);
528
572
  }
529
573
  /**
530
- * Compile a parsed document for the hot path: pattern strings become
531
- * RegExps (invalid globs/regexes throw here, at load), and the rule count
532
- * is capped by `maxRules`.
574
+ * Compile a parsed document for the hot path STRICTLY: pattern strings
575
+ * become RegExps (invalid globs/regexes throw here), and the rule count is
576
+ * capped by `maxRules`. Used by editor saves (and the generated allow-host
577
+ * rule), so a hand edit never has a rule silently dropped. The loader uses
578
+ * {@link compileRulesText} instead.
533
579
  * @param doc - the parsed document.
534
580
  * @param options - pattern mode, caps, and case handling.
535
581
  * @returns the compiled ruleset (every rule attributed to source 0).
536
582
  */
537
583
  function compileRules(doc, options) {
538
584
  if (doc.rules.length > options.maxRules) throw new RuleError(`rule count ${doc.rules.length} exceeds maxRules ${options.maxRules}`);
539
- return mergeCompiledRules([compileSourceRules(doc, options)], options);
585
+ return mergeCompiledRules([doc.rules.map((entry) => compileRule(entry, 0, options))], options);
540
586
  }
541
587
  /**
542
- * Compile one parsed document into per-source compiled rules. The returned
543
- * rules carry source-local `index` values and `sourceIndex` 0 — the
544
- * cacheable unit a runtime can reuse across chains (keyed by source path +
545
- * content hash). The total-count cap is NOT applied here; it bounds the
546
- * merged chain in {@link mergeCompiledRules}.
547
- * @param doc - the parsed document.
588
+ * Compile one parsed document into per-source compiled rules with
589
+ * per-rule isolation (issue #49): a rule whose patterns cannot compile is
590
+ * disabled and reported in {@link CompiledSourceRules.issues}, while every
591
+ * other rule still loads. The returned rules carry source-local `index`
592
+ * values and `sourceIndex` 0 — the cacheable unit a runtime can reuse
593
+ * across chains (keyed by source path + content hash). The total-count cap
594
+ * is NOT applied here; it bounds the merged chain in
595
+ * {@link mergeCompiledRules}.
596
+ * @param doc - the parsed document (isolated or strict).
548
597
  * @param options - compile options.
549
- * @returns the compiled rules of one source.
598
+ * @returns the compiled rules of one source plus the disabled-rule reports.
550
599
  */
551
600
  function compileSourceRules(doc, options) {
552
- return doc.rules.map((entry, index) => compileRule(entry, index, 0, options));
601
+ const rules = [];
602
+ const issues = [...doc.issues ?? []];
603
+ for (const entry of doc.rules) try {
604
+ rules.push(compileRule(entry, 0, options));
605
+ } catch (error) {
606
+ issues.push({
607
+ index: entry.index,
608
+ message: ruleErrorMessage(error)
609
+ });
610
+ }
611
+ issues.sort((left, right) => left.index - right.index);
612
+ return {
613
+ rules,
614
+ issues
615
+ };
616
+ }
617
+ /**
618
+ * Parse and compile one rule-file text with per-rule isolation — the
619
+ * loader-facing entry point for issue #49. A bad rule disables only itself
620
+ * (reported with its 0-based document index); the rest of the file stays
621
+ * active. A file-level failure still throws, so `badFilePolicy` keeps
622
+ * choosing how a whole unreadable/unparseable file is handled.
623
+ * @param text - the raw YAML text.
624
+ * @param options - compile options.
625
+ * @returns the compiled rules plus the disabled-rule reports.
626
+ */
627
+ function compileRulesText(text, options) {
628
+ const doc = parseRulesDocumentIsolated(text);
629
+ const total = doc.rules.length + (doc.issues?.length ?? 0);
630
+ if (total > options.maxRules) throw new RuleError(`rule count ${total} exceeds maxRules ${options.maxRules}`);
631
+ return compileSourceRules(doc, options);
553
632
  }
554
633
  /**
555
634
  * Merge per-source compiled rule lists into one chain, assigning the
@@ -575,11 +654,13 @@ function mergeCompiledRules(sources, options) {
575
654
  };
576
655
  }
577
656
  /**
578
- * Parse and compile an ordered source chain (nearest file first). Rules
579
- * keep per-file order and are evaluated in chain order, so a nearer file
580
- * can override a farther one on first-match semantics; `sourceIndex`
657
+ * Parse and compile an ordered source chain (nearest file first) STRICTLY.
658
+ * Rules keep per-file order and are evaluated in chain order, so a nearer
659
+ * file can override a farther one on first-match semantics; `sourceIndex`
581
660
  * attributes every rule to its file. The TOTAL rule count is capped by
582
- * `maxRules`.
661
+ * `maxRules`. The plugin's loader does not use this helper — it compiles
662
+ * each file through {@link compileRulesText} so one bad rule cannot take
663
+ * the chain down.
583
664
  * @param entries - the rule-file texts, nearest file first.
584
665
  * @param options - compile options.
585
666
  * @returns the merged ruleset and the source paths it references.
@@ -587,12 +668,12 @@ function mergeCompiledRules(sources, options) {
587
668
  function compileRulesChain(entries, options) {
588
669
  const sources = entries.map((entry) => entry.path);
589
670
  return {
590
- ruleset: mergeCompiledRules(entries.map((entry) => compileSourceRules(parseRulesDocument(entry.text), options)), options),
671
+ ruleset: mergeCompiledRules(entries.map((entry) => parseRulesDocument(entry.text).rules.map((rule) => compileRule(rule, 0, options))), options),
591
672
  sources
592
673
  };
593
674
  }
594
675
  /** Compile one parsed rule into its hot-path form. */
595
- function compileRule(entry, index, sourceIndex, options) {
676
+ function compileRule(entry, sourceIndex, options) {
596
677
  const tools = entry.match.tools.map((pattern) => compileToolPattern(pattern, options.maxGlobStars));
597
678
  const agents = entry.match.agents.map((pattern) => compileToolPattern(pattern, options.maxGlobStars));
598
679
  const params = /* @__PURE__ */ new Map();
@@ -602,7 +683,7 @@ function compileRule(entry, index, sourceIndex, options) {
602
683
  for (const [key, patterns] of Object.entries(entry.match.when.env)) env.set(key, patterns.map((pattern) => compileValuePattern(pattern, options.patternMode, options.maxGlobStars)));
603
684
  const argv = entry.match.argv === void 0 ? void 0 : compileArgv(entry.match.argv, options);
604
685
  return {
605
- index,
686
+ index: entry.index,
606
687
  sourceIndex,
607
688
  action: entry.action,
608
689
  reason: entry.reason,
@@ -917,6 +998,7 @@ function parseRuleEntry(raw, index) {
917
998
  const description = record["description"];
918
999
  if (description !== void 0 && (typeof description !== "string" || description.trim().length === 0)) throw new RuleError(`${at}: description must be a non-empty string`);
919
1000
  return {
1001
+ index,
920
1002
  match: parseMatch(record["match"], at),
921
1003
  action,
922
1004
  reason,
@@ -2132,6 +2214,9 @@ const EN = {
2132
2214
  reloaded: (count, source) => `Reloaded ${count} rule(s) from ${source}.`,
2133
2215
  reloadFailed: (error) => `Reload failed: ${error}. The previous rules are still active.`,
2134
2216
  lastReloadWarning: (error) => `Warning: the last reload failed (${error}); the rules listed above are the previous ones.`,
2217
+ degradedRules: (disabled, active) => `Warning: ${disabled} rule(s) could not be loaded and are disabled; the other ${active} rule(s) stay active:`,
2218
+ ruleIssueLine: (source, index, message) => `- ${source.length > 0 ? source : "(unknown file)"}: rule ${index + 1} (disabled): ${message}`,
2219
+ reloadDegraded: (active, source, disabled) => `Reloaded ${active} rule(s) from ${source}; ${disabled} rule(s) are disabled by load errors — fix the entries below and run /rules reload:`,
2135
2220
  dryRunNotice: "Dry-run mode (enforce: false): deny/ask hits are audit-logged only — every call is passed through.",
2136
2221
  unknownArg: (arg) => `Unknown /rules argument "${arg}". ${EN.usage}`,
2137
2222
  usage: "Usage: /rules [list | reload | network | decisions [n] | test <tool> <json-args>]",
@@ -2167,6 +2252,9 @@ const ZH = {
2167
2252
  reloaded: (count, source) => `已重载 ${count} 条规则,来自 ${source}。`,
2168
2253
  reloadFailed: (error) => `重载失败:${error}。之前的规则仍然生效。`,
2169
2254
  lastReloadWarning: (error) => `警告:上次重载失败(${error});以上列出的是之前的规则。`,
2255
+ degradedRules: (disabled, active) => `警告:${disabled} 条规则无法加载,已禁用;其余 ${active} 条仍然生效:`,
2256
+ ruleIssueLine: (source, index, message) => `- ${source.length > 0 ? source : "(未知文件)"}:第 ${index + 1} 条(已禁用):${message}`,
2257
+ reloadDegraded: (active, source, disabled) => `已重载 ${active} 条规则,来自 ${source};另有 ${disabled} 条因加载错误被禁用——请修正下列条目后执行 /rules reload:`,
2170
2258
  dryRunNotice: "干跑模式(enforce: false):deny/ask 命中仅写入审计日志——所有调用照常透传。",
2171
2259
  unknownArg: (arg) => `未知的 /rules 参数 "${arg}"。${ZH.usage}`,
2172
2260
  usage: "用法:/rules [list | reload | network | decisions [n] | test <工具名> <json-参数>]",
@@ -2202,6 +2290,9 @@ const ES = {
2202
2290
  reloaded: (count, source) => `Recargadas ${count} regla(s) desde ${source}.`,
2203
2291
  reloadFailed: (error) => `Error de recarga: ${error}. Las reglas anteriores siguen activas.`,
2204
2292
  lastReloadWarning: (error) => `Aviso: la última recarga falló (${error}); las reglas mostradas son las anteriores.`,
2293
+ degradedRules: (disabled, active) => `Aviso: ${disabled} regla(s) no se pudieron cargar y están deshabilitadas; las otras ${active} siguen activas:`,
2294
+ ruleIssueLine: (source, index, message) => `- ${source.length > 0 ? source : "(archivo desconocido)"}: regla ${index + 1} (deshabilitada): ${message}`,
2295
+ reloadDegraded: (active, source, disabled) => `Recargadas ${active} regla(s) desde ${source}; ${disabled} regla(s) están deshabilitadas por errores de carga — corrige las entradas siguientes y ejecuta /rules reload:`,
2205
2296
  dryRunNotice: "Modo simulación (enforce: false): los aciertos deny/ask solo se registran en auditoría — todas las llamadas pasan.",
2206
2297
  unknownArg: (arg) => `Argumento de /rules desconocido "${arg}". ${ES.usage}`,
2207
2298
  usage: "Uso: /rules [list | reload | network | decisions [n] | test <herramienta> <json-args>]",
@@ -2237,6 +2328,9 @@ const PT = {
2237
2328
  reloaded: (count, source) => `Recarregadas ${count} regra(s) de ${source}.`,
2238
2329
  reloadFailed: (error) => `Falha ao recarregar: ${error}. As regras anteriores continuam ativas.`,
2239
2330
  lastReloadWarning: (error) => `Aviso: a última recarga falhou (${error}); as regras listadas são as anteriores.`,
2331
+ degradedRules: (disabled, active) => `Aviso: ${disabled} regra(s) não puderam ser carregadas e estão desativadas; as outras ${active} continuam ativas:`,
2332
+ ruleIssueLine: (source, index, message) => `- ${source.length > 0 ? source : "(arquivo desconhecido)"}: regra ${index + 1} (desativada): ${message}`,
2333
+ reloadDegraded: (active, source, disabled) => `Recarregadas ${active} regra(s) de ${source}; ${disabled} regra(s) estão desativadas por erros de carregamento — corrija as entradas abaixo e execute /rules reload:`,
2240
2334
  dryRunNotice: "Modo simulação (enforce: false): acertos deny/ask são apenas registrados na auditoria — todas as chamadas passam.",
2241
2335
  unknownArg: (arg) => `Argumento de /rules desconhecido "${arg}". ${PT.usage}`,
2242
2336
  usage: "Uso: /rules [list | reload | network | decisions [n] | test <ferramenta> <json-args>]",
@@ -2272,6 +2366,9 @@ const HI = {
2272
2366
  reloaded: (count, source) => `${count} नियम पुनः लोड किए गए, स्रोत ${source}।`,
2273
2367
  reloadFailed: (error) => `पुनः लोड विफल: ${error}। पिछले नियम अब भी सक्रिय हैं।`,
2274
2368
  lastReloadWarning: (error) => `चेतावनी: अंतिम पुनः लोड विफल रहा (${error}); ऊपर सूचीबद्ध नियम पिछले वाले हैं।`,
2369
+ degradedRules: (disabled, active) => `चेतावनी: ${disabled} नियम लोड नहीं हो सके और अक्षम हैं; शेष ${active} नियम सक्रिय रहते हैं:`,
2370
+ ruleIssueLine: (source, index, message) => `- ${source.length > 0 ? source : "(अज्ञात फ़ाइल)"}: नियम ${index + 1} (अक्षम): ${message}`,
2371
+ reloadDegraded: (active, source, disabled) => `${source} से ${active} नियम पुनः लोड हुए; ${disabled} नियम लोड त्रुटियों से अक्षम हैं — नीचे दी प्रविष्टियाँ ठीक करें और /rules reload चलाएँ:`,
2275
2372
  dryRunNotice: "ड्राई-रन मोड (enforce: false): deny/ask हिट केवल ऑडिट में दर्ज होते हैं — हर कॉल पास हो जाती है।",
2276
2373
  unknownArg: (arg) => `अज्ञात /rules तर्क "${arg}"। ${HI.usage}`,
2277
2374
  usage: "उपयोग: /rules [list | reload | network | decisions [n] | test <टूल> <json-args>]",
@@ -3271,10 +3368,17 @@ var PermissionRulesRuntime = class {
3271
3368
  return [];
3272
3369
  }
3273
3370
  /**
3274
- * Read, parse, and compile the rule-file chain serving `cwd`. Under
3275
- * `badFilePolicy: 'ignore-with-warning'` a bad file degrades to an empty
3276
- * rule set with a warning and keeps its source paths (so a later fix is
3277
- * watched and adopted); under `'fail'` it throws.
3371
+ * Read, parse, and compile the rule-file chain serving `cwd`.
3372
+ *
3373
+ * Per-rule failures (a bad glob/regex, an unknown field or action, a
3374
+ * missing reason) no longer fail the whole load: that rule is disabled,
3375
+ * reported with its 0-based document index and source file, and every
3376
+ * other rule — in that file and in every other file of the chain — stays
3377
+ * active (issue #49). FILE-level failures (unreadable file, invalid YAML,
3378
+ * unknown top-level field, `rules` not a list, or a total over
3379
+ * `maxRules`) still follow `badFilePolicy`: `'ignore-with-warning'`
3380
+ * degrades to an empty rule set with a warning and keeps the source paths
3381
+ * (so a later fix is watched and adopted); `'fail'` throws.
3278
3382
  * @param cwd - the workspace root.
3279
3383
  * @returns the loaded state.
3280
3384
  */
@@ -3289,10 +3393,22 @@ var PermissionRulesRuntime = class {
3289
3393
  }
3290
3394
  };
3291
3395
  try {
3396
+ const compiledSources = [];
3397
+ const issues = [];
3398
+ for (const path of sources) {
3399
+ const source = this.compileSourceFile(path);
3400
+ compiledSources.push([...source.rules]);
3401
+ for (const issue of source.issues) issues.push({
3402
+ source: path,
3403
+ index: issue.index,
3404
+ message: issue.message
3405
+ });
3406
+ }
3292
3407
  return {
3293
3408
  cwd,
3294
3409
  sources,
3295
- compiled: mergeCompiledRules(sources.map((path) => this.compileSourceFile(path)), this.compileOptions())
3410
+ compiled: mergeCompiledRules(compiledSources, this.compileOptions()),
3411
+ ...issues.length === 0 ? {} : { issues }
3296
3412
  };
3297
3413
  } catch (error) {
3298
3414
  const message = error instanceof Error ? error.message : String(error);
@@ -3316,9 +3432,12 @@ var PermissionRulesRuntime = class {
3316
3432
  * file's content hash is unchanged. The cache key is the source path plus
3317
3433
  * the content hash, so the same file read by many workspaces (the
3318
3434
  * built-in baseline and any shared fallback/absolute `rulesFile`) is
3319
- * parsed and compiled ONCE, not once per cwd.
3435
+ * parsed and compiled ONCE, not once per cwd. Per-rule failures are
3436
+ * isolated by {@link compileRulesText}; they are logged here (once per
3437
+ * recompiled content, at `error` under `badFilePolicy: 'fail'` and at
3438
+ * `warn` under `'ignore-with-warning'`) instead of being thrown.
3320
3439
  * @param path - the absolute source path.
3321
- * @returns that source's compiled rules (source-local index, sourceIndex 0).
3440
+ * @returns that source's compiled rules (source-local index, sourceIndex 0) and disabled-rule reports.
3322
3441
  */
3323
3442
  compileSourceFile(path) {
3324
3443
  const text = readFileSync(path, "utf8");
@@ -3327,15 +3446,59 @@ var PermissionRulesRuntime = class {
3327
3446
  if (cached !== void 0 && cached.hash === hash) {
3328
3447
  this.compileCache.delete(path);
3329
3448
  this.compileCache.set(path, cached);
3330
- return cached.rules;
3449
+ return cached;
3331
3450
  }
3332
- const rules = compileSourceRules(parseRulesDocument(text), this.compileOptions());
3451
+ const { rules, issues } = compileRulesText(text, this.compileOptions());
3333
3452
  this.compileCache.set(path, {
3334
3453
  hash,
3335
- rules
3454
+ rules,
3455
+ issues
3336
3456
  });
3337
3457
  this.evictCompileCache();
3338
- return rules;
3458
+ this.reportRuleIssues(path, issues);
3459
+ return {
3460
+ rules,
3461
+ issues
3462
+ };
3463
+ }
3464
+ /**
3465
+ * Report the rules an isolated load disabled. The file still loads, so
3466
+ * this is not a file-level failure: `badFilePolicy: 'fail'` reports each
3467
+ * disabled rule at `error` level and `'ignore-with-warning'` at `warn`,
3468
+ * both naming the file and the 1-based rule position the author can find in
3469
+ * the document (the `RuleIssue.index` itself is 0-based). The same errors stay queryable through `/rules`.
3470
+ * @param path - the rule file the rules came from.
3471
+ * @param issues - the disabled-rule reports for that file.
3472
+ */
3473
+ reportRuleIssues(path, issues) {
3474
+ if (issues.length === 0) return;
3475
+ const log = this.config.badFilePolicy === "fail" ? this.ctx.logger.error.bind(this.ctx.logger) : this.ctx.logger.warn.bind(this.ctx.logger);
3476
+ const shown = issues.slice(0, 5);
3477
+ for (const issue of shown) log(`permission-rules: ${path}: rule ${issue.index + 1} disabled by a load error: ${issue.message}`);
3478
+ if (issues.length > shown.length) log(`permission-rules: ${path}: ${issues.length - shown.length} more rule(s) disabled by load errors (run /rules for the full list)`);
3479
+ }
3480
+ /**
3481
+ * ONE process's startup check: load the chain for `cwd` eagerly and, when
3482
+ * it is degraded, emit a single prominent warning instead of waiting for
3483
+ * the first dangerous tool call. The per-rule errors themselves are logged
3484
+ * by {@link compileSourceFile}; this adds the summary that makes the state
3485
+ * impossible to miss in the host log, and `/rules` stays the
3486
+ * session-visible surface with the detailed list. Never throws: a startup
3487
+ * check must not take the plugin down (issue #49).
3488
+ * @param cwd - the workspace to check (the host cwd at mount, the session cwd on creation).
3489
+ */
3490
+ startupNotice(cwd = process.cwd()) {
3491
+ let loaded;
3492
+ try {
3493
+ loaded = this.load(cwd);
3494
+ } catch (error) {
3495
+ const message = error instanceof Error ? error.message : String(error);
3496
+ this.ctx.logger.error(`permission-rules: STARTUP: cannot load the rule chain for ${cwd}: ${message} — tool calls in this workspace will fail until the file is fixed (run /rules reload after fixing it)`);
3497
+ return;
3498
+ }
3499
+ const issues = loaded.issues ?? [];
3500
+ if (issues.length > 0) this.ctx.logger.error(`permission-rules: STARTUP: ${issues.length} rule(s) could not be loaded and are disabled; ${loaded.compiled.rules.length} rule(s) from ${loaded.sources.join(", ")} stay active. Run /rules for the per-rule errors, then fix the named entries.`);
3501
+ if (loaded.lastError !== void 0) this.ctx.logger.error(`permission-rules: STARTUP: the rule chain for ${cwd} is degraded (${loaded.lastError}); the previous/empty rule set is in effect. Run /rules for details.`);
3339
3502
  }
3340
3503
  /** Bound the compile cache: drop the least-recently-used source beyond the workspace cap (compile results are cheap to rebuild). */
3341
3504
  evictCompileCache() {
@@ -4186,6 +4349,11 @@ var PermissionRulesRuntime = class {
4186
4349
  };
4187
4350
  const rules = reloaded?.compiled.rules ?? [];
4188
4351
  const source = reloaded === void 0 || reloaded.sources.length === 0 ? prose.emptySource : reloaded.sources.join(", ");
4352
+ const issues = reloaded?.issues ?? [];
4353
+ if (issues.length > 0) return {
4354
+ kind: "error",
4355
+ text: [prose.reloadDegraded(rules.length, source, issues.length), ...issues.map((issue) => prose.ruleIssueLine(this.displaySource(issue.source, cwd), issue.index, issue.message))].join("\n")
4356
+ };
4189
4357
  return {
4190
4358
  kind: "success",
4191
4359
  text: prose.reloaded(rules.length, source)
@@ -4233,9 +4401,14 @@ var PermissionRulesRuntime = class {
4233
4401
  };
4234
4402
  }
4235
4403
  const lines = [];
4404
+ const issues = loaded.issues ?? [];
4236
4405
  if (loaded.sources.length === 0) lines.push(prose.noRules(cwd, this.config.fallbackPath !== void 0 ? prose.fallbackMissing : ""));
4237
4406
  else {
4238
4407
  lines.push(prose.rulesHeader(loaded.compiled.rules.length, loaded.sources, cwd));
4408
+ if (issues.length > 0) {
4409
+ lines.push(prose.degradedRules(issues.length, loaded.compiled.rules.length));
4410
+ for (const issue of issues) lines.push(prose.ruleIssueLine(this.displaySource(issue.source, cwd), issue.index, issue.message));
4411
+ }
4239
4412
  const multiSource = loaded.sources.length > 1;
4240
4413
  lines.push(...loaded.compiled.rules.map((rule) => describeRule(rule, DESCRIBE_TOKENS[this.config.language], multiSource ? this.displaySource(loaded.sources[rule.sourceIndex] ?? "", cwd) : void 0)));
4241
4414
  const unreachable = findUnreachableRules(loaded.compiled);
@@ -4245,7 +4418,7 @@ var PermissionRulesRuntime = class {
4245
4418
  if (!this.config.enforce) lines.push(prose.dryRunNotice);
4246
4419
  lines.push(prose.usage);
4247
4420
  return {
4248
- kind: "success",
4421
+ kind: issues.length > 0 || loaded.lastError !== void 0 ? "error" : "success",
4249
4422
  text: lines.join("\n")
4250
4423
  };
4251
4424
  }
@@ -4389,9 +4562,13 @@ var PermissionRulesRuntime = class {
4389
4562
  /**
4390
4563
  * Validate deployment-level file references at mount — the earliest
4391
4564
  * resolvable point. An absolute `rulesFile` or a configured
4392
- * `fallbackPath` must exist and parse; a missing referent fails the mount
4393
- * loudly instead of silently degrading later.
4394
- * @throws when a mandated file is missing or invalid.
4565
+ * `fallbackPath` must exist and parse; a missing referent or a FILE-level
4566
+ * failure fails the mount loudly instead of silently degrading later. A
4567
+ * single bad RULE inside such a file no longer fails the mount (issue
4568
+ * #49): it is disabled, reported, and the rest of the file stays active —
4569
+ * otherwise one typo would take the whole plugin (and its protection)
4570
+ * down before any session exists.
4571
+ * @throws when a mandated file is missing or unparseable as a document.
4395
4572
  */
4396
4573
  validateDeploymentFiles() {
4397
4574
  if (isAbsolute(this.config.rulesFile)) this.loadForValidation(this.config.rulesFile);
@@ -4405,10 +4582,15 @@ var PermissionRulesRuntime = class {
4405
4582
  this.loadForValidation(this.config.builtin.path);
4406
4583
  }
4407
4584
  }
4408
- /** Parse and compile one mandated file, rethrowing as a mount failure. */
4585
+ /**
4586
+ * Parse and compile one mandated file with per-rule isolation, rethrowing
4587
+ * only a FILE-level failure as a mount failure. The disabled-rule reports
4588
+ * are logged here (the mount is the first place they can be seen).
4589
+ * @param filePath - the deployment-level rule file to validate.
4590
+ */
4409
4591
  loadForValidation(filePath) {
4410
4592
  try {
4411
- compileRules(parseRulesDocument(readFileSync(filePath, "utf8")), this.compileOptions());
4593
+ this.compileSourceFile(filePath);
4412
4594
  } catch (error) {
4413
4595
  const message = error instanceof Error ? error.message : String(error);
4414
4596
  throw error instanceof RuleError ? error : new RuleError(`permission-rules: cannot load ${filePath}: ${message}`);
@@ -4691,6 +4873,14 @@ async function apply(ctx, config) {
4691
4873
  input: { hint: "[list | reload | network | decisions [n] | test [--cwd <dir>] [--env K=V] [--agent <sel>] [--platform <name>] <tool> <json-args>]" },
4692
4874
  handler: (invocation) => runtime.command(invocation)
4693
4875
  });
4876
+ runtime.startupNotice();
4877
+ ctx.inject(["sessions"], (scope) => {
4878
+ scope.on("session/created", (session) => {
4879
+ try {
4880
+ runtime.startupNotice(session.header.cwd ?? process.cwd());
4881
+ } catch {}
4882
+ });
4883
+ });
4694
4884
  if (resolved.network.enabled) await runtime.attachNetworkProxy();
4695
4885
  ctx.inject(["systemPrompt"], (scope) => {
4696
4886
  const systemPrompt = scope.get("systemPrompt");
@@ -4849,4 +5039,4 @@ const name = "permission-rules";
4849
5039
  /** Consumer — the /rules command handler and the tools/pre-execute waterfall listener consume the injected commands/tools services. */
4850
5040
  const inject = ["commands", "tools"];
4851
5041
  //#endregion
4852
- 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 };
5042
+ 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, compileRulesText, compileSourceRules, decideNetworkTarget, decomposeShellCommand, defaultDecision, describeRule, extractPathCandidates, extractUrlCandidates, findUnreachableRules, inject, injectProxyEnv, isIpLiteral, isLoopbackTarget, isMarkedAuditEvent, isShellTool, isUnmarkedHostVersion, matchRules, matchTools, matchWhen, mergeCompiledRules, name, networkModeForSandbox, normalizeHost, normalizeWorkspacePath, parseRulesDocument, parseRulesDocumentIsolated, parseUrlTarget, plainConfig, readAmbientProxy, redactProxyUrl, resolveBuiltinRulesPath, resolveConfig, targetMatchesNetwork };
@@ -100,10 +100,15 @@ export interface Config {
100
100
  */
101
101
  fallbackPath?: string | undefined;
102
102
  /**
103
- * How an unreadable/invalid rule file is handled at load: `'fail'` throws
104
- * (the pending tool call errors loudly; HMR reloads keep the previous
105
- * rules and report the error), `'ignore-with-warning'` logs a warning and
106
- * continues with an empty (initial) or previous (reload) rule set.
103
+ * How a FILE-level rule-file failure (unreadable, invalid YAML, unknown
104
+ * top-level field, `rules` not a list, over `maxRules`) is handled at
105
+ * load: `'fail'` throws (the pending tool call errors loudly; HMR reloads
106
+ * keep the previous rules and report the error), `'ignore-with-warning'`
107
+ * logs a warning and continues with an empty (initial) or previous
108
+ * (reload) rule set. A single invalid RULE is isolated either way
109
+ * (issue #49): it is disabled and reported at startup and in `/rules`
110
+ * while every other rule stays active, so the policy can never disappear
111
+ * because of one typo.
107
112
  */
108
113
  badFilePolicy?: BadFilePolicy;
109
114
  /** Hard cap on the number of rules across the effective source chain; a larger chain fails the load. */
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"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"}
@@ -22,6 +22,12 @@ export interface UiProse {
22
22
  reloadFailed: (error: string) => string;
23
23
  /** Warning appended to a listing whose last reload failed. */
24
24
  lastReloadWarning: (error: string) => string;
25
+ /** Warning header of a listing whose chain disabled rule(s) by isolated load errors. */
26
+ degradedRules: (disabled: number, active: number) => string;
27
+ /** One disabled-rule line: source file, 1-based rule number, and the load error. */
28
+ ruleIssueLine: (source: string, index: number, message: string) => string;
29
+ /** `/rules reload` result when valid rules loaded but others were disabled. */
30
+ reloadDegraded: (active: number, source: string, disabled: number) => string;
25
31
  /** Notice appended to a listing when dry-run mode (`enforce: false`) is active. */
26
32
  dryRunNotice: string;
27
33
  /** Rejection of an unknown `/rules` argument. */
@@ -1 +1 @@
1
- {"version":3,"file":"prose.d.ts","sourceRoot":"","sources":["../../src/prose.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,0CAA0C;AAC1C,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAEzD,2EAA2E;AAC3E,MAAM,WAAW,OAAO;IACtB,6EAA6E;IAC7E,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IAC/E,iDAAiD;IACjD,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,MAAM,CAAA;IACtD,oEAAoE;IACpE,eAAe,EAAE,MAAM,CAAA;IACvB,uCAAuC;IACvC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,MAAM,CAAA;IACnD,qCAAqC;IACrC,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;IACvC,8DAA8D;IAC9D,iBAAiB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;IAC5C,mFAAmF;IACnF,YAAY,EAAE,MAAM,CAAA;IACpB,iDAAiD;IACjD,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IACnC,kBAAkB;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,0DAA0D;IAC1D,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;IACzD,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAA;IACnB,4HAA4H;IAC5H,mBAAmB,EAAE,MAAM,CAAA;IAC3B,gDAAgD;IAChD,qBAAqB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IAC9C,qEAAqE;IACrE,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,KAAK,MAAM,CAAA;IAChL,iCAAiC;IACjC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,MAAM,CAAA;IACpF,sCAAsC;IACtC,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;IACrC,6DAA6D;IAC7D,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;IACrC,kDAAkD;IAClD,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;IACzC,kFAAkF;IAClF,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;IACrC,kDAAkD;IAClD,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;IAC1C,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAA;IACjB,qEAAqE;IACrE,kBAAkB,EAAE,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,KAAK,MAAM,CAAA;IAC1D,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAA;IACnB,iFAAiF;IACjF,eAAe,EAAE,MAAM,CAAA;IACvB,8EAA8E;IAC9E,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,KAAK,MAAM,CAAA;IACzI,sCAAsC;IACtC,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,MAAM,CAAA;IAC/D,eAAe,EAAE,CAAC,IAAI,EAAE,KAAK,GAAG,SAAS,GAAG,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,MAAM,CAAA;IACzI,yDAAyD;IACzD,eAAe,EAAE,MAAM,CAAA;IACvB,kCAAkC;IAClC,gBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,KAAK,MAAM,CAAA;CACjP;AAED,mEAAmE;AACnE,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,sDAAsD;IACtD,GAAG,EAAE,MAAM,CAAA;CACZ;AAmOD,8CAA8C;AAC9C,eAAO,MAAM,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAA8C,CAAA;AAEzG,yDAAyD;AACzD,eAAO,MAAM,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,cAAc,CAAC,CAMxE,CAAA"}
1
+ {"version":3,"file":"prose.d.ts","sourceRoot":"","sources":["../../src/prose.ts"],"names":[],"mappings":"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"}