dsh-permission-rules 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/README.es.md +6 -5
- package/README.hi.md +6 -5
- package/README.md +6 -5
- package/README.pt.md +6 -5
- package/README.zh.md +6 -5
- package/docs/rules-format.en.md +4 -2
- package/docs/rules-format.md +4 -2
- package/lib/index.js +209 -60
- package/lib/types/prose.d.ts +4 -0
- package/lib/types/prose.d.ts.map +1 -1
- package/lib/types/prose.js +20 -15
- package/lib/types/prose.js.map +1 -1
- package/lib/types/rules.d.ts +8 -2
- package/lib/types/rules.d.ts.map +1 -1
- package/lib/types/rules.js +8 -3
- package/lib/types/rules.js.map +1 -1
- package/lib/types/runtime.d.ts +49 -10
- package/lib/types/runtime.d.ts.map +1 -1
- package/lib/types/runtime.js +166 -35
- package/lib/types/runtime.js.map +1 -1
- package/package.json +1 -1
- package/src/prose.ts +24 -15
- package/src/rules.ts +10 -3
- package/src/runtime.ts +171 -34
package/lib/index.js
CHANGED
|
@@ -563,12 +563,16 @@ function isCatchAll(rule) {
|
|
|
563
563
|
/**
|
|
564
564
|
* One-line human summary of a compiled rule, for `/rules` output. The
|
|
565
565
|
* 1-based number, action, match dimensions, and reason render first; a
|
|
566
|
-
* disabled marker, tags, and a truncated description follow.
|
|
566
|
+
* disabled marker, tags, and a truncated description follow. When `source`
|
|
567
|
+
* is provided (multi-file chains), the rule's origin file is attributed on
|
|
568
|
+
* the line.
|
|
567
569
|
* @param rule - the compiled rule.
|
|
568
570
|
* @param tokens - dimension-prefix vocabulary for the configured language.
|
|
571
|
+
* @param source - display path of the rule's source file, when the listing
|
|
572
|
+
* spans several files.
|
|
569
573
|
* @returns a single display line.
|
|
570
574
|
*/
|
|
571
|
-
function describeRule(rule, tokens) {
|
|
575
|
+
function describeRule(rule, tokens, source) {
|
|
572
576
|
const parts = [];
|
|
573
577
|
if (rule.source.match.tools.length > 0) parts.push(`${tokens.tools}:${rule.source.match.tools.join(",")}`);
|
|
574
578
|
if (rule.source.match.agents.length > 0) parts.push(`${tokens.agents}:${rule.source.match.agents.join(",")}`);
|
|
@@ -581,9 +585,10 @@ function describeRule(rule, tokens) {
|
|
|
581
585
|
if (whenParts.length > 0 || platformPart.length > 0) parts.push(`${tokens.when}:${whenParts}${whenParts.length > 0 && platformPart.length > 0 ? " " : ""}${platformPart}`);
|
|
582
586
|
const match = parts.length > 0 ? `[${parts.join(" ")}]` : `[${tokens.allTools}]`;
|
|
583
587
|
const disabled = rule.enabled ? "" : ` (${tokens.disabled})`;
|
|
588
|
+
const sourcePart = source !== void 0 && source.length > 0 ? ` [${tokens.src}:${source}]` : "";
|
|
584
589
|
const description = rule.description !== void 0 ? ` (${truncate(rule.description, DISPLAY_TRUNCATE)})` : "";
|
|
585
590
|
const tags = rule.tags.length > 0 ? ` [${tokens.tags}:${rule.tags.join(",")}]` : "";
|
|
586
|
-
return `${rule.index + 1}. ${rule.action}${disabled} ${match}: ${truncate(rule.reason, DISPLAY_TRUNCATE)}${description}${tags}`;
|
|
591
|
+
return `${rule.index + 1}. ${rule.action}${disabled} ${match}${sourcePart}: ${truncate(rule.reason, DISPLAY_TRUNCATE)}${description}${tags}`;
|
|
587
592
|
}
|
|
588
593
|
/** Cut a display string at `limit` characters, marking truncation with `…`. */
|
|
589
594
|
function truncate(text, limit) {
|
|
@@ -926,7 +931,7 @@ const EN = {
|
|
|
926
931
|
lastReloadWarning: (error) => `Warning: the last reload failed (${error}); the rules listed above are the previous ones.`,
|
|
927
932
|
dryRunNotice: "Dry-run mode (enforce: false): deny/ask hits are audit-logged only — every call is passed through.",
|
|
928
933
|
unknownArg: (arg) => `Unknown /rules argument "${arg}". ${EN.usage}`,
|
|
929
|
-
usage: "Usage: /rules [reload | decisions [n] | test <tool> <json-args>]",
|
|
934
|
+
usage: "Usage: /rules [list | reload | decisions [n] | test <tool> <json-args>]",
|
|
930
935
|
decisionsHeader: (shown, total) => `Last ${shown} of ${total} permission decision(s) for this session:`,
|
|
931
936
|
noDecisions: "No permission decisions recorded in this session yet.",
|
|
932
937
|
invalidDecisionsCount: (arg) => `Invalid decisions count "${arg}": give a positive integer (default 10).`,
|
|
@@ -938,7 +943,8 @@ const EN = {
|
|
|
938
943
|
testBadJson: (text) => `Invalid JSON arguments "${text}": the arguments must parse as JSON.`,
|
|
939
944
|
testUnknownFlag: (flag) => `Unknown /rules test flag "${flag}". ${EN.testUsage}`,
|
|
940
945
|
testBadFlag: (flag) => `Invalid /rules test flag "${flag}": expected a value. ${EN.testUsage}`,
|
|
941
|
-
|
|
946
|
+
testBadPlatform: (value) => `Unknown platform "${value}" in --platform: expected one of aix, android, darwin, freebsd, linux, openbsd, sunos, win32. ${EN.testUsage}`,
|
|
947
|
+
testUsage: "Usage: /rules test [--cwd <dir>] [--env KEY=VALUE]... [--agent <selector>]... [--platform <name>] <tool> <json-args>, e.g. /rules test bash {\"command\":\"git push origin main\"}",
|
|
942
948
|
unreachableWarning: (numbers) => `Warning: rule${numbers.length > 1 ? "s" : ""} ${numbers.join(", ")} ${numbers.length > 1 ? "are" : "is"} unreachable (shadowed by an earlier catch-all rule).`,
|
|
943
949
|
emptySource: "(no rule file — empty rule set)"
|
|
944
950
|
};
|
|
@@ -951,7 +957,7 @@ const ZH = {
|
|
|
951
957
|
lastReloadWarning: (error) => `警告:上次重载失败(${error});以上列出的是之前的规则。`,
|
|
952
958
|
dryRunNotice: "干跑模式(enforce: false):deny/ask 命中仅写入审计日志——所有调用照常透传。",
|
|
953
959
|
unknownArg: (arg) => `未知的 /rules 参数 "${arg}"。${ZH.usage}`,
|
|
954
|
-
usage: "用法:/rules [reload | decisions [n] | test <工具名> <json-参数>]",
|
|
960
|
+
usage: "用法:/rules [list | reload | decisions [n] | test <工具名> <json-参数>]",
|
|
955
961
|
decisionsHeader: (shown, total) => `本会话最近 ${shown}/${total} 条权限裁决:`,
|
|
956
962
|
noDecisions: "本会话还没有记录任何权限裁决。",
|
|
957
963
|
invalidDecisionsCount: (arg) => `无效的裁决条数 "${arg}":请给正整数(默认 10)。`,
|
|
@@ -963,7 +969,8 @@ const ZH = {
|
|
|
963
969
|
testBadJson: (text) => `无效的 JSON 参数 "${text}":参数必须能被解析为 JSON。`,
|
|
964
970
|
testUnknownFlag: (flag) => `未知的 /rules test 标志 "${flag}"。${ZH.testUsage}`,
|
|
965
971
|
testBadFlag: (flag) => `无效的 /rules test 标志 "${flag}":缺少取值。${ZH.testUsage}`,
|
|
966
|
-
|
|
972
|
+
testBadPlatform: (value) => `未知的平台 "${value}"(--platform):应为 aix、android、darwin、freebsd、linux、openbsd、sunos、win32 之一。${ZH.testUsage}`,
|
|
973
|
+
testUsage: "用法:/rules test [--cwd <目录>] [--env 键=值]... [--agent <选择器>]... [--platform <平台名>] <工具名> <json-参数>,例如 /rules test bash {\"command\":\"git push origin main\"}",
|
|
967
974
|
unreachableWarning: (numbers) => `警告:规则 ${numbers.join("、")} 不可达(被前面的通配规则遮蔽)。`,
|
|
968
975
|
emptySource: "(无规则文件——空规则集)"
|
|
969
976
|
};
|
|
@@ -976,7 +983,7 @@ const ES = {
|
|
|
976
983
|
lastReloadWarning: (error) => `Aviso: la última recarga falló (${error}); las reglas mostradas son las anteriores.`,
|
|
977
984
|
dryRunNotice: "Modo simulación (enforce: false): los aciertos deny/ask solo se registran en auditoría — todas las llamadas pasan.",
|
|
978
985
|
unknownArg: (arg) => `Argumento de /rules desconocido "${arg}". ${ES.usage}`,
|
|
979
|
-
usage: "Uso: /rules [reload | decisions [n] | test <herramienta> <json-args>]",
|
|
986
|
+
usage: "Uso: /rules [list | reload | decisions [n] | test <herramienta> <json-args>]",
|
|
980
987
|
decisionsHeader: (shown, total) => `Últimas ${shown} de ${total} decisión(es) de permiso de esta sesión:`,
|
|
981
988
|
noDecisions: "Esta sesión aún no registra decisiones de permiso.",
|
|
982
989
|
invalidDecisionsCount: (arg) => `Cantidad de decisiones inválida "${arg}": indique un entero positivo (por defecto 10).`,
|
|
@@ -988,7 +995,8 @@ const ES = {
|
|
|
988
995
|
testBadJson: (text) => `Argumentos JSON inválidos "${text}": los argumentos deben poderse analizar como JSON.`,
|
|
989
996
|
testUnknownFlag: (flag) => `Bandera de /rules test desconocida "${flag}". ${ES.testUsage}`,
|
|
990
997
|
testBadFlag: (flag) => `Bandera de /rules test inválida "${flag}": falta un valor. ${ES.testUsage}`,
|
|
991
|
-
|
|
998
|
+
testBadPlatform: (value) => `Plataforma desconocida "${value}" en --platform: se esperaba una de aix, android, darwin, freebsd, linux, openbsd, sunos, win32. ${ES.testUsage}`,
|
|
999
|
+
testUsage: "Uso: /rules test [--cwd <dir>] [--env CLAVE=VALOR]... [--agent <selector>]... [--platform <nombre>] <herramienta> <json-args>, p. ej. /rules test bash {\"command\":\"git push origin main\"}",
|
|
992
1000
|
unreachableWarning: (numbers) => `Aviso: ${numbers.length > 1 ? "las reglas" : "la regla"} ${numbers.join(", ")} ${numbers.length > 1 ? "son inalcanzables" : "es inalcanzable"} (tapada por una regla general anterior).`,
|
|
993
1001
|
emptySource: "(sin archivo de reglas — conjunto vacío)"
|
|
994
1002
|
};
|
|
@@ -1001,7 +1009,7 @@ const PT = {
|
|
|
1001
1009
|
lastReloadWarning: (error) => `Aviso: a última recarga falhou (${error}); as regras listadas são as anteriores.`,
|
|
1002
1010
|
dryRunNotice: "Modo simulação (enforce: false): acertos deny/ask são apenas registrados na auditoria — todas as chamadas passam.",
|
|
1003
1011
|
unknownArg: (arg) => `Argumento de /rules desconhecido "${arg}". ${PT.usage}`,
|
|
1004
|
-
usage: "Uso: /rules [reload | decisions [n] | test <ferramenta> <json-args>]",
|
|
1012
|
+
usage: "Uso: /rules [list | reload | decisions [n] | test <ferramenta> <json-args>]",
|
|
1005
1013
|
decisionsHeader: (shown, total) => `Últimas ${shown} de ${total} decisão(ões) de permissão desta sessão:`,
|
|
1006
1014
|
noDecisions: "Esta sessão ainda não registrou decisões de permissão.",
|
|
1007
1015
|
invalidDecisionsCount: (arg) => `Quantidade de decisões inválida "${arg}": informe um inteiro positivo (padrão 10).`,
|
|
@@ -1013,7 +1021,8 @@ const PT = {
|
|
|
1013
1021
|
testBadJson: (text) => `Argumentos JSON inválidos "${text}": os argumentos precisam ser JSON analisável.`,
|
|
1014
1022
|
testUnknownFlag: (flag) => `Sinalizador de /rules test desconhecido "${flag}". ${PT.testUsage}`,
|
|
1015
1023
|
testBadFlag: (flag) => `Sinalizador de /rules test inválido "${flag}": falta um valor. ${PT.testUsage}`,
|
|
1016
|
-
|
|
1024
|
+
testBadPlatform: (value) => `Plataforma desconhecida "${value}" em --platform: esperava-se uma de aix, android, darwin, freebsd, linux, openbsd, sunos, win32. ${PT.testUsage}`,
|
|
1025
|
+
testUsage: "Uso: /rules test [--cwd <dir>] [--env CHAVE=VALOR]... [--agent <seletor>]... [--platform <nome>] <ferramenta> <json-args>, ex.: /rules test bash {\"command\":\"git push origin main\"}",
|
|
1017
1026
|
unreachableWarning: (numbers) => `Aviso: ${numbers.length > 1 ? "as regras" : "a regra"} ${numbers.join(", ")} ${numbers.length > 1 ? "são inalcançáveis" : "é inalcançável"} (encoberta por uma regra geral anterior).`,
|
|
1018
1027
|
emptySource: "(sem arquivo de regras — conjunto vazio)"
|
|
1019
1028
|
};
|
|
@@ -1026,7 +1035,7 @@ const HI = {
|
|
|
1026
1035
|
lastReloadWarning: (error) => `चेतावनी: अंतिम पुनः लोड विफल रहा (${error}); ऊपर सूचीबद्ध नियम पिछले वाले हैं।`,
|
|
1027
1036
|
dryRunNotice: "ड्राई-रन मोड (enforce: false): deny/ask हिट केवल ऑडिट में दर्ज होते हैं — हर कॉल पास हो जाती है।",
|
|
1028
1037
|
unknownArg: (arg) => `अज्ञात /rules तर्क "${arg}"। ${HI.usage}`,
|
|
1029
|
-
usage: "उपयोग: /rules [reload | decisions [n] | test <टूल> <json-args>]",
|
|
1038
|
+
usage: "उपयोग: /rules [list | reload | decisions [n] | test <टूल> <json-args>]",
|
|
1030
1039
|
decisionsHeader: (shown, total) => `इस सत्र के अंतिम ${shown}/${total} अनुमति निर्णय:`,
|
|
1031
1040
|
noDecisions: "इस सत्र में अभी कोई अनुमति निर्णय दर्ज नहीं है।",
|
|
1032
1041
|
invalidDecisionsCount: (arg) => `अमान्य निर्णय-संख्या "${arg}": एक धनात्मक पूर्णांक दें (डिफ़ॉल्ट 10)।`,
|
|
@@ -1038,7 +1047,8 @@ const HI = {
|
|
|
1038
1047
|
testBadJson: (text) => `अमान्य JSON तर्क "${text}": तर्क JSON के रूप में पार्स होने चाहिए।`,
|
|
1039
1048
|
testUnknownFlag: (flag) => `अज्ञात /rules test फ़्लैग "${flag}"। ${HI.testUsage}`,
|
|
1040
1049
|
testBadFlag: (flag) => `अमान्य /rules test फ़्लैग "${flag}": मान गायब है। ${HI.testUsage}`,
|
|
1041
|
-
|
|
1050
|
+
testBadPlatform: (value) => `अज्ञात प्लेटफ़ॉर्म "${value}" (--platform): aix, android, darwin, freebsd, linux, openbsd, sunos, win32 में से एक अपेक्षित। ${HI.testUsage}`,
|
|
1051
|
+
testUsage: "उपयोग: /rules test [--cwd <dir>] [--env KEY=मान]... [--agent <चयनकर्ता>]... [--platform <नाम>] <टूल> <json-args>, जैसे /rules test bash {\"command\":\"git push origin main\"}",
|
|
1042
1052
|
unreachableWarning: (numbers) => `चेतावनी: नियम ${numbers.join(", ")} अप्राप्य हैं (पहले वाले सर्व-मिलान नियम से ढके हुए)।`,
|
|
1043
1053
|
emptySource: "(कोई नियम फ़ाइल नहीं — खाली नियम-समूह)"
|
|
1044
1054
|
};
|
|
@@ -1062,7 +1072,8 @@ const DESCRIBE_TOKENS = {
|
|
|
1062
1072
|
when: "when",
|
|
1063
1073
|
platform: "platform",
|
|
1064
1074
|
disabled: "disabled",
|
|
1065
|
-
tags: "tags"
|
|
1075
|
+
tags: "tags",
|
|
1076
|
+
src: "src"
|
|
1066
1077
|
},
|
|
1067
1078
|
zh: {
|
|
1068
1079
|
allTools: "全部工具",
|
|
@@ -1074,7 +1085,8 @@ const DESCRIBE_TOKENS = {
|
|
|
1074
1085
|
when: "条件",
|
|
1075
1086
|
platform: "平台",
|
|
1076
1087
|
disabled: "已禁用",
|
|
1077
|
-
tags: "标签"
|
|
1088
|
+
tags: "标签",
|
|
1089
|
+
src: "来源"
|
|
1078
1090
|
},
|
|
1079
1091
|
es: {
|
|
1080
1092
|
allTools: "todas las herramientas",
|
|
@@ -1086,7 +1098,8 @@ const DESCRIBE_TOKENS = {
|
|
|
1086
1098
|
when: "cuándo",
|
|
1087
1099
|
platform: "plataforma",
|
|
1088
1100
|
disabled: "deshabilitada",
|
|
1089
|
-
tags: "etiquetas"
|
|
1101
|
+
tags: "etiquetas",
|
|
1102
|
+
src: "origen"
|
|
1090
1103
|
},
|
|
1091
1104
|
pt: {
|
|
1092
1105
|
allTools: "todas as ferramentas",
|
|
@@ -1098,7 +1111,8 @@ const DESCRIBE_TOKENS = {
|
|
|
1098
1111
|
when: "quando",
|
|
1099
1112
|
platform: "plataforma",
|
|
1100
1113
|
disabled: "desativada",
|
|
1101
|
-
tags: "etiquetas"
|
|
1114
|
+
tags: "etiquetas",
|
|
1115
|
+
src: "origem"
|
|
1102
1116
|
},
|
|
1103
1117
|
hi: {
|
|
1104
1118
|
allTools: "सभी टूल",
|
|
@@ -1110,7 +1124,8 @@ const DESCRIBE_TOKENS = {
|
|
|
1110
1124
|
when: "शर्त",
|
|
1111
1125
|
platform: "प्लेटफ़ॉर्म",
|
|
1112
1126
|
disabled: "अक्षम",
|
|
1113
|
-
tags: "टैग"
|
|
1127
|
+
tags: "टैग",
|
|
1128
|
+
src: "स्रोत"
|
|
1114
1129
|
}
|
|
1115
1130
|
};
|
|
1116
1131
|
//#endregion
|
|
@@ -1122,7 +1137,9 @@ const DESCRIBE_TOKENS = {
|
|
|
1122
1137
|
* deny/ask decision (and NEVER short-circuits on allow or passthrough),
|
|
1123
1138
|
* the `permissionRules/decision` audit event, the `/rules` session command
|
|
1124
1139
|
* (`list | reload | decisions [n] | test [flags] <tool> <json>`), and
|
|
1125
|
-
* Chokidar-driven reloads
|
|
1140
|
+
* Chokidar-driven reloads (effective rule files plus candidate watches on
|
|
1141
|
+
* expected-but-absent files, so mid-session creation is adopted). Every
|
|
1142
|
+
* registration is an effect.
|
|
1126
1143
|
* @module dsh-permission-rules/runtime
|
|
1127
1144
|
*/
|
|
1128
1145
|
/**
|
|
@@ -1134,7 +1151,7 @@ var PermissionRulesRuntime = class {
|
|
|
1134
1151
|
config;
|
|
1135
1152
|
/** Loaded (or failed) rules per workspace cwd, least-recently-used first for eviction. */
|
|
1136
1153
|
byCwd = /* @__PURE__ */ new Map();
|
|
1137
|
-
/** Live watchers per rule
|
|
1154
|
+
/** Live watchers per watched path (rule file or candidate ancestor directory), with the cwds each serves. */
|
|
1138
1155
|
watchers = /* @__PURE__ */ new Map();
|
|
1139
1156
|
/** Debounce timers per rule-file path. */
|
|
1140
1157
|
timers = /* @__PURE__ */ new Map();
|
|
@@ -1232,6 +1249,17 @@ var PermissionRulesRuntime = class {
|
|
|
1232
1249
|
}
|
|
1233
1250
|
}
|
|
1234
1251
|
/**
|
|
1252
|
+
* Canonical per-workspace cache key: the resolved root, case-folded on
|
|
1253
|
+
* Windows so differently-spelled paths to the same workspace share one
|
|
1254
|
+
* cache entry and one watcher set instead of doubling both.
|
|
1255
|
+
* @param cwd - the session's absolute workspace root.
|
|
1256
|
+
* @returns the canonical key.
|
|
1257
|
+
*/
|
|
1258
|
+
cacheKey(cwd) {
|
|
1259
|
+
const resolved = resolve(cwd);
|
|
1260
|
+
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
1261
|
+
}
|
|
1262
|
+
/**
|
|
1235
1263
|
* The rules in effect for one cwd, loading on first use. Under
|
|
1236
1264
|
* `badFilePolicy: 'fail'` a bad initial load throws on EVERY use (the
|
|
1237
1265
|
* pending tool call errors loudly) while the watcher keeps observing the
|
|
@@ -1242,23 +1270,24 @@ var PermissionRulesRuntime = class {
|
|
|
1242
1270
|
* @returns the loaded rules.
|
|
1243
1271
|
*/
|
|
1244
1272
|
rulesFor(cwd) {
|
|
1245
|
-
const
|
|
1273
|
+
const key = this.cacheKey(cwd);
|
|
1274
|
+
const existing = this.byCwd.get(key);
|
|
1246
1275
|
if (existing !== void 0) {
|
|
1247
1276
|
if (existing.failed === true) throw new RuleError(existing.lastError ?? `rule load failed for ${cwd}`);
|
|
1248
|
-
this.byCwd.delete(
|
|
1249
|
-
this.byCwd.set(
|
|
1277
|
+
this.byCwd.delete(key);
|
|
1278
|
+
this.byCwd.set(key, existing);
|
|
1250
1279
|
return existing;
|
|
1251
1280
|
}
|
|
1252
|
-
this.evictIfFull(
|
|
1281
|
+
this.evictIfFull(key);
|
|
1253
1282
|
try {
|
|
1254
1283
|
const loaded = this.load(cwd);
|
|
1255
|
-
this.byCwd.set(
|
|
1256
|
-
this.reconcileWatch(
|
|
1284
|
+
this.byCwd.set(key, loaded);
|
|
1285
|
+
this.reconcileWatch(key, loaded.sources);
|
|
1257
1286
|
return loaded;
|
|
1258
1287
|
} catch (error) {
|
|
1259
1288
|
const message = error instanceof Error ? error.message : String(error);
|
|
1260
1289
|
const sources = this.resolveSources(cwd);
|
|
1261
|
-
this.byCwd.set(
|
|
1290
|
+
this.byCwd.set(key, {
|
|
1262
1291
|
cwd,
|
|
1263
1292
|
sources,
|
|
1264
1293
|
compiled: {
|
|
@@ -1268,7 +1297,7 @@ var PermissionRulesRuntime = class {
|
|
|
1268
1297
|
lastError: message,
|
|
1269
1298
|
failed: true
|
|
1270
1299
|
});
|
|
1271
|
-
this.reconcileWatch(
|
|
1300
|
+
this.reconcileWatch(key, sources);
|
|
1272
1301
|
throw error;
|
|
1273
1302
|
}
|
|
1274
1303
|
}
|
|
@@ -1280,29 +1309,34 @@ var PermissionRulesRuntime = class {
|
|
|
1280
1309
|
* @param cwd - the workspace root.
|
|
1281
1310
|
*/
|
|
1282
1311
|
reload(cwd) {
|
|
1283
|
-
const
|
|
1312
|
+
const key = this.cacheKey(cwd);
|
|
1313
|
+
const previous = this.byCwd.get(key);
|
|
1284
1314
|
try {
|
|
1285
1315
|
const loaded = this.load(cwd);
|
|
1286
|
-
this.byCwd.set(
|
|
1287
|
-
this.reconcileWatch(
|
|
1316
|
+
this.byCwd.set(key, loaded);
|
|
1317
|
+
this.reconcileWatch(key, loaded.sources);
|
|
1288
1318
|
this.ctx.logger.info(`permission-rules: reloaded ${loaded.compiled.rules.length} rule(s) from ${loaded.sources.join(", ") || "(empty rule set)"} for ${cwd}`);
|
|
1289
1319
|
} catch (error) {
|
|
1290
1320
|
const message = error instanceof Error ? error.message : String(error);
|
|
1291
1321
|
this.ctx.logger.warn(`permission-rules: reload failed for ${cwd}: ${message} (keeping previous rules)`);
|
|
1292
|
-
if (previous !== void 0) this.byCwd.set(
|
|
1322
|
+
if (previous !== void 0) this.byCwd.set(key, {
|
|
1293
1323
|
...previous,
|
|
1294
1324
|
lastError: message
|
|
1295
1325
|
});
|
|
1296
|
-
else
|
|
1297
|
-
cwd
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1326
|
+
else {
|
|
1327
|
+
const sources = this.resolveSources(cwd);
|
|
1328
|
+
this.byCwd.set(key, {
|
|
1329
|
+
cwd,
|
|
1330
|
+
sources,
|
|
1331
|
+
compiled: {
|
|
1332
|
+
rules: [],
|
|
1333
|
+
caseInsensitivePaths: this.config.caseInsensitivePaths
|
|
1334
|
+
},
|
|
1335
|
+
lastError: message,
|
|
1336
|
+
failed: true
|
|
1337
|
+
});
|
|
1338
|
+
this.reconcileWatch(key, sources);
|
|
1339
|
+
}
|
|
1306
1340
|
}
|
|
1307
1341
|
}
|
|
1308
1342
|
/**
|
|
@@ -1418,7 +1452,7 @@ var PermissionRulesRuntime = class {
|
|
|
1418
1452
|
text: prose.unknownArg(invocation.rawInput.trim())
|
|
1419
1453
|
};
|
|
1420
1454
|
this.reload(cwd);
|
|
1421
|
-
const reloaded = this.byCwd.get(cwd);
|
|
1455
|
+
const reloaded = this.byCwd.get(this.cacheKey(cwd));
|
|
1422
1456
|
if (reloaded?.lastError !== void 0) return {
|
|
1423
1457
|
kind: "error",
|
|
1424
1458
|
text: prose.reloadFailed(reloaded.lastError)
|
|
@@ -1430,6 +1464,10 @@ var PermissionRulesRuntime = class {
|
|
|
1430
1464
|
text: prose.reloaded(rules.length, source)
|
|
1431
1465
|
};
|
|
1432
1466
|
}
|
|
1467
|
+
if (verb === "list" && rest.length > 0) return {
|
|
1468
|
+
kind: "error",
|
|
1469
|
+
text: prose.unknownArg(invocation.rawInput.trim())
|
|
1470
|
+
};
|
|
1433
1471
|
if (verb === "decisions") {
|
|
1434
1472
|
if (rest.length > 1) return {
|
|
1435
1473
|
kind: "error",
|
|
@@ -1447,7 +1485,7 @@ var PermissionRulesRuntime = class {
|
|
|
1447
1485
|
return this.decisionsCommand(invocation, count, prose);
|
|
1448
1486
|
}
|
|
1449
1487
|
if (verb === "test") return this.testCommand(raw, verbRaw ?? "", invocation, cwd, prose);
|
|
1450
|
-
if (verb !== "") return {
|
|
1488
|
+
if (verb !== "" && verb !== "list") return {
|
|
1451
1489
|
kind: "error",
|
|
1452
1490
|
text: prose.unknownArg(invocation.rawInput.trim())
|
|
1453
1491
|
};
|
|
@@ -1464,7 +1502,8 @@ var PermissionRulesRuntime = class {
|
|
|
1464
1502
|
if (loaded.sources.length === 0) lines.push(prose.noRules(cwd, this.config.fallbackPath !== void 0 ? prose.fallbackMissing : ""));
|
|
1465
1503
|
else {
|
|
1466
1504
|
lines.push(prose.rulesHeader(loaded.compiled.rules.length, loaded.sources, cwd));
|
|
1467
|
-
|
|
1505
|
+
const multiSource = loaded.sources.length > 1;
|
|
1506
|
+
lines.push(...loaded.compiled.rules.map((rule) => describeRule(rule, DESCRIBE_TOKENS[this.config.language], multiSource ? this.displaySource(loaded.sources[rule.sourceIndex] ?? "", cwd) : void 0)));
|
|
1468
1507
|
const unreachable = findUnreachableRules(loaded.compiled);
|
|
1469
1508
|
if (unreachable.length > 0) lines.push(prose.unreachableWarning(unreachable.map((index) => index + 1)));
|
|
1470
1509
|
}
|
|
@@ -1480,9 +1519,11 @@ var PermissionRulesRuntime = class {
|
|
|
1480
1519
|
* Execute `/rules test` with optional leading flags: `--cwd <dir>`
|
|
1481
1520
|
* evaluates against that workspace (rule discovery AND path
|
|
1482
1521
|
* normalization), `--env KEY=VALUE` (repeatable) overrides host env for
|
|
1483
|
-
* `when.env` matching,
|
|
1484
|
-
* agent-identity candidates for the `agents` dimension
|
|
1485
|
-
*
|
|
1522
|
+
* `when.env` matching, `--agent <selector>` (repeatable) supplies
|
|
1523
|
+
* agent-identity candidates for the `agents` dimension, and
|
|
1524
|
+
* `--platform <name>` overrides the host platform for `when.platform`.
|
|
1525
|
+
* The JSON argument tail is kept verbatim, so quoted JSON survives
|
|
1526
|
+
* unchanged.
|
|
1486
1527
|
* @param raw - the full raw command input.
|
|
1487
1528
|
* @param verbRaw - the verb as typed.
|
|
1488
1529
|
* @param invocation - the received command invocation (session agent).
|
|
@@ -1495,6 +1536,7 @@ var PermissionRulesRuntime = class {
|
|
|
1495
1536
|
const envOverrides = {};
|
|
1496
1537
|
const agentSelectors = [];
|
|
1497
1538
|
let testCwd;
|
|
1539
|
+
let testPlatform;
|
|
1498
1540
|
let parsed = nextToken(rest);
|
|
1499
1541
|
while (parsed !== void 0 && parsed.token.startsWith("--")) {
|
|
1500
1542
|
const flag = parsed.token;
|
|
@@ -1512,7 +1554,13 @@ var PermissionRulesRuntime = class {
|
|
|
1512
1554
|
};
|
|
1513
1555
|
envOverrides[value.token.slice(0, equals)] = value.token.slice(equals + 1);
|
|
1514
1556
|
} else if (flag === "--agent") agentSelectors.push(value.token);
|
|
1515
|
-
else
|
|
1557
|
+
else if (flag === "--platform") {
|
|
1558
|
+
if (!PLATFORMS.includes(value.token)) return {
|
|
1559
|
+
kind: "error",
|
|
1560
|
+
text: prose.testBadPlatform(value.token)
|
|
1561
|
+
};
|
|
1562
|
+
testPlatform = value.token;
|
|
1563
|
+
} else return {
|
|
1516
1564
|
kind: "error",
|
|
1517
1565
|
text: prose.testUnknownFlag(flag)
|
|
1518
1566
|
};
|
|
@@ -1545,7 +1593,7 @@ var PermissionRulesRuntime = class {
|
|
|
1545
1593
|
};
|
|
1546
1594
|
}
|
|
1547
1595
|
const context = {
|
|
1548
|
-
platform: process.platform,
|
|
1596
|
+
platform: testPlatform ?? process.platform,
|
|
1549
1597
|
env: Object.keys(envOverrides).length === 0 ? process.env : {
|
|
1550
1598
|
...process.env,
|
|
1551
1599
|
...envOverrides
|
|
@@ -1558,6 +1606,12 @@ var PermissionRulesRuntime = class {
|
|
|
1558
1606
|
text: hit === void 0 ? prose.testNoMatch(tool) : prose.testHit(tool, hit.ruleIndex, hit.rule.action, hit.rule.reason)
|
|
1559
1607
|
};
|
|
1560
1608
|
}
|
|
1609
|
+
/** Render one rule-file source for per-rule attribution: workspace-relative when inside the cwd, raw otherwise. */
|
|
1610
|
+
displaySource(source, cwd) {
|
|
1611
|
+
if (source.length === 0) return "";
|
|
1612
|
+
const relative = normalizeWorkspacePath(cwd, source, this.config.caseInsensitivePaths);
|
|
1613
|
+
return relative.length > 0 ? relative : source;
|
|
1614
|
+
}
|
|
1561
1615
|
/** Render the session's `permissionRules/decision` audit trail, newest last. */
|
|
1562
1616
|
decisionsCommand(invocation, count, prose) {
|
|
1563
1617
|
const decisions = invocation.agent.session.events.filter((event) => event.type === "permissionRules/decision");
|
|
@@ -1642,16 +1696,97 @@ var PermissionRulesRuntime = class {
|
|
|
1642
1696
|
* Rebind `cwd` to its current rule-source chain. When a concrete source
|
|
1643
1697
|
* left the chain (deleted file, fallback switch), detach the workspace
|
|
1644
1698
|
* from watchers serving other sources and close the ones left empty, so
|
|
1645
|
-
* long-running hosts cannot accumulate stale watchers.
|
|
1646
|
-
* rule
|
|
1647
|
-
*
|
|
1648
|
-
*
|
|
1699
|
+
* long-running hosts cannot accumulate stale watchers. Expected-but-absent
|
|
1700
|
+
* rule files (the project file when it is not effective, and a configured
|
|
1701
|
+
* fallback that does not exist) are covered by candidate watchers on
|
|
1702
|
+
* their deepest existing ancestor directory, so a file created
|
|
1703
|
+
* mid-session is adopted without a manual `/rules reload`. With
|
|
1704
|
+
* `searchUp`, only the immediate cwd-level candidate is watched —
|
|
1705
|
+
* deeper ancestors are discovered on the next load.
|
|
1649
1706
|
*/
|
|
1650
1707
|
reconcileWatch(cwd, sources) {
|
|
1651
|
-
if (sources.
|
|
1652
|
-
|
|
1708
|
+
for (const [watchedSource, entry] of this.watchers) if (!sources.includes(watchedSource)) {
|
|
1709
|
+
entry.cwds.delete(cwd);
|
|
1710
|
+
entry.candidates?.delete(cwd);
|
|
1711
|
+
}
|
|
1653
1712
|
this.pruneWatchers();
|
|
1654
1713
|
for (const source of sources) this.attachWatch(cwd, source);
|
|
1714
|
+
for (const candidate of this.candidateSources(cwd)) {
|
|
1715
|
+
if (sources.includes(candidate) || existsSync(candidate)) continue;
|
|
1716
|
+
this.attachCandidateWatch(cwd, candidate);
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
/**
|
|
1720
|
+
* The rule-file paths a workspace COULD be served by: the project file
|
|
1721
|
+
* (an absolute `rulesFile`, or `<cwd>/<rulesFile>` — the immediate level
|
|
1722
|
+
* only under `searchUp`) plus the configured fallback.
|
|
1723
|
+
*/
|
|
1724
|
+
candidateSources(cwd) {
|
|
1725
|
+
const candidates = [isAbsolute(this.config.rulesFile) ? this.config.rulesFile : join(cwd, this.config.rulesFile)];
|
|
1726
|
+
const fallback = this.config.fallbackPath;
|
|
1727
|
+
if (fallback !== void 0) candidates.push(isAbsolute(fallback) ? fallback : resolve(fallback));
|
|
1728
|
+
return candidates;
|
|
1729
|
+
}
|
|
1730
|
+
/**
|
|
1731
|
+
* Watch one expected-but-absent rule file through its deepest existing
|
|
1732
|
+
* ancestor directory. Chokidar cannot reliably watch a missing path when
|
|
1733
|
+
* its parent is also missing, but directory watching is dependable; every
|
|
1734
|
+
* relevant event re-checks existence and only triggers a reload once the
|
|
1735
|
+
* candidate actually appeared, so unrelated workspace activity while the
|
|
1736
|
+
* file is absent costs a stat, not a reload.
|
|
1737
|
+
*/
|
|
1738
|
+
attachCandidateWatch(cwd, candidate) {
|
|
1739
|
+
if (!this.config.watch) return;
|
|
1740
|
+
const dir = this.deepestExistingDir(dirname(candidate));
|
|
1741
|
+
const existing = this.watchers.get(dir);
|
|
1742
|
+
if (existing !== void 0) {
|
|
1743
|
+
existing.cwds.add(cwd);
|
|
1744
|
+
existing.candidates?.set(cwd, candidate);
|
|
1745
|
+
return;
|
|
1746
|
+
}
|
|
1747
|
+
const cwds = /* @__PURE__ */ new Set([cwd]);
|
|
1748
|
+
const candidates = /* @__PURE__ */ new Map([[cwd, candidate]]);
|
|
1749
|
+
const watcher = chokidar.watch(dir, {
|
|
1750
|
+
persistent: true,
|
|
1751
|
+
ignoreInitial: true
|
|
1752
|
+
});
|
|
1753
|
+
const onEvent = () => this.scheduleReload(dir);
|
|
1754
|
+
watcher.on("add", onEvent);
|
|
1755
|
+
watcher.on("addDir", onEvent);
|
|
1756
|
+
watcher.on("change", onEvent);
|
|
1757
|
+
watcher.on("unlink", onEvent);
|
|
1758
|
+
watcher.on("unlinkDir", onEvent);
|
|
1759
|
+
watcher.on("error", (error) => {
|
|
1760
|
+
this.ctx.logger.warn(`permission-rules: watcher error on ${dir}: ${String(error)}`);
|
|
1761
|
+
});
|
|
1762
|
+
this.watchers.set(dir, {
|
|
1763
|
+
cwds,
|
|
1764
|
+
candidates,
|
|
1765
|
+
close: () => {
|
|
1766
|
+
watcher.close().catch((error) => {
|
|
1767
|
+
this.ctx.logger.warn(`permission-rules: failed to close watcher on ${dir}: ${String(error)}`);
|
|
1768
|
+
});
|
|
1769
|
+
}
|
|
1770
|
+
});
|
|
1771
|
+
this.ctx.effect(() => () => {
|
|
1772
|
+
this.watchers.get(dir)?.close();
|
|
1773
|
+
this.watchers.delete(dir);
|
|
1774
|
+
const timer = this.timers.get(dir);
|
|
1775
|
+
if (timer !== void 0) {
|
|
1776
|
+
clearTimeout(timer);
|
|
1777
|
+
this.timers.delete(dir);
|
|
1778
|
+
}
|
|
1779
|
+
});
|
|
1780
|
+
}
|
|
1781
|
+
/** The deepest existing ancestor directory of `dir` (candidate watchers target directories, never missing files). */
|
|
1782
|
+
deepestExistingDir(dir) {
|
|
1783
|
+
let current = dir;
|
|
1784
|
+
for (;;) {
|
|
1785
|
+
if (existsSync(current)) return current;
|
|
1786
|
+
const parent = dirname(current);
|
|
1787
|
+
if (parent === current) return current;
|
|
1788
|
+
current = parent;
|
|
1789
|
+
}
|
|
1655
1790
|
}
|
|
1656
1791
|
/** Close and drop watchers whose workspace sets are empty, clearing their debounce timers. */
|
|
1657
1792
|
pruneWatchers() {
|
|
@@ -1678,7 +1813,10 @@ var PermissionRulesRuntime = class {
|
|
|
1678
1813
|
const oldest = this.byCwd.keys().next().value;
|
|
1679
1814
|
if (oldest === void 0) return;
|
|
1680
1815
|
this.byCwd.delete(oldest);
|
|
1681
|
-
for (const entry of this.watchers.values())
|
|
1816
|
+
for (const entry of this.watchers.values()) {
|
|
1817
|
+
entry.cwds.delete(oldest);
|
|
1818
|
+
entry.candidates?.delete(oldest);
|
|
1819
|
+
}
|
|
1682
1820
|
this.pruneWatchers();
|
|
1683
1821
|
}
|
|
1684
1822
|
/** Number of live watchers, for observability and tests. */
|
|
@@ -1689,13 +1827,24 @@ var PermissionRulesRuntime = class {
|
|
|
1689
1827
|
pendingReloadCount() {
|
|
1690
1828
|
return this.timers.size;
|
|
1691
1829
|
}
|
|
1692
|
-
/**
|
|
1830
|
+
/**
|
|
1831
|
+
* Debounce watch events into one reload per stability window. A
|
|
1832
|
+
* candidate (directory) watcher only reloads a cwd once its expected
|
|
1833
|
+
* file actually exists — unrelated events while the file is absent are
|
|
1834
|
+
* dropped before any re-read.
|
|
1835
|
+
*/
|
|
1693
1836
|
scheduleReload(source) {
|
|
1694
1837
|
const existing = this.timers.get(source);
|
|
1695
1838
|
if (existing !== void 0) clearTimeout(existing);
|
|
1696
1839
|
const timer = setTimeout(() => {
|
|
1697
1840
|
this.timers.delete(source);
|
|
1698
|
-
|
|
1841
|
+
const entry = this.watchers.get(source);
|
|
1842
|
+
if (entry === void 0) return;
|
|
1843
|
+
for (const cwd of entry.cwds) {
|
|
1844
|
+
const candidate = entry.candidates?.get(cwd);
|
|
1845
|
+
if (candidate !== void 0 && !existsSync(candidate)) continue;
|
|
1846
|
+
this.reload(cwd);
|
|
1847
|
+
}
|
|
1699
1848
|
}, this.config.watchStabilityThresholdMs);
|
|
1700
1849
|
this.timers.set(source, timer);
|
|
1701
1850
|
}
|
|
@@ -1714,7 +1863,7 @@ function apply(ctx, config) {
|
|
|
1714
1863
|
ctx.commands.register({
|
|
1715
1864
|
name: "rules",
|
|
1716
1865
|
description: "list, reload, audit, or dry-test the active permission rules for this workspace",
|
|
1717
|
-
input: { hint: "[reload | decisions [n] | test [--cwd <dir>] [--env K=V] [--agent <sel>] <tool> <json-args>]" },
|
|
1866
|
+
input: { hint: "[list | reload | decisions [n] | test [--cwd <dir>] [--env K=V] [--agent <sel>] [--platform <name>] <tool> <json-args>]" },
|
|
1718
1867
|
handler: (invocation) => runtime.command(invocation)
|
|
1719
1868
|
});
|
|
1720
1869
|
}
|
package/lib/types/prose.d.ts
CHANGED
|
@@ -46,6 +46,8 @@ export interface UiProse {
|
|
|
46
46
|
testUnknownFlag: (flag: string) => string;
|
|
47
47
|
/** Rejection of a malformed `/rules test` flag (missing value, bad KEY=VALUE). */
|
|
48
48
|
testBadFlag: (flag: string) => string;
|
|
49
|
+
/** Rejection of an unknown `--platform` value. */
|
|
50
|
+
testBadPlatform: (value: string) => string;
|
|
49
51
|
/** Usage hint of `/rules test`. */
|
|
50
52
|
testUsage: string;
|
|
51
53
|
/** Warning naming shadowed (unreachable) rules by 1-based number. */
|
|
@@ -65,6 +67,8 @@ export interface DescribeTokens {
|
|
|
65
67
|
platform: string;
|
|
66
68
|
disabled: string;
|
|
67
69
|
tags: string;
|
|
70
|
+
/** Prefix of the per-rule source-file attribution. */
|
|
71
|
+
src: string;
|
|
68
72
|
}
|
|
69
73
|
/** The localized prose tables by language. */
|
|
70
74
|
export declare const UI_PROSE: Readonly<Record<UiLanguage, UiProse>>;
|
package/lib/types/prose.d.ts.map
CHANGED
|
@@ -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,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,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;CACpB;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,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"prose.d.ts","sourceRoot":"","sources":["../../src/prose.ts"],"names":[],"mappings":"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"}
|