@yadsh/dsh-prompt-firewall 0.1.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/lib/config.js ADDED
@@ -0,0 +1,100 @@
1
+ import z from '@deepseek-ai/schemastery';
2
+ import { getPreset } from './presets.js';
3
+ export const DEFAULT_AUDIT_CONFIG = Object.freeze({
4
+ enabled: true,
5
+ logAllowed: false,
6
+ logBlocked: true,
7
+ includePreview: false,
8
+ previewChars: 160,
9
+ historySize: 100,
10
+ highlightNewSections: true,
11
+ });
12
+ export const DEFAULT_METRICS_CONFIG = Object.freeze({
13
+ enabled: true,
14
+ });
15
+ export const DEFAULT_CONFIG = Object.freeze({
16
+ enabled: true,
17
+ mode: 'blocklist',
18
+ blockedSections: Object.freeze([]),
19
+ allowedSections: Object.freeze([]),
20
+ blockedPrefixes: Object.freeze([]),
21
+ allowedPrefixes: Object.freeze([]),
22
+ blockedPatterns: Object.freeze([]),
23
+ allowedPatterns: Object.freeze([]),
24
+ protectedSections: Object.freeze([]),
25
+ protectCoreSections: true,
26
+ unknownPluginPolicy: 'allow',
27
+ audit: DEFAULT_AUDIT_CONFIG,
28
+ metrics: DEFAULT_METRICS_CONFIG,
29
+ });
30
+ const nonEmptyString = z.string().min(1);
31
+ const stringList = z.array(nonEmptyString);
32
+ /** Runtime schema consumed by the Cordis loader. */
33
+ export const ConfigSchema = z.object({
34
+ enabled: z.boolean().default(true),
35
+ // Keep preset-owned fields absent until resolveConfig(). Applying schema
36
+ // defaults here would make `preset: strict` look explicitly overridden.
37
+ mode: z.union(['off', 'audit', 'blocklist', 'allowlist']),
38
+ preset: z.union(['clean', 'strict', 'audit-only']),
39
+ blockedSections: stringList.default([]),
40
+ allowedSections: stringList.default([]),
41
+ blockedPrefixes: stringList.default([]),
42
+ allowedPrefixes: stringList.default([]),
43
+ blockedPatterns: stringList.default([]),
44
+ allowedPatterns: stringList.default([]),
45
+ protectedSections: stringList.default([]),
46
+ protectCoreSections: z.boolean().default(true),
47
+ unknownPluginPolicy: z.union(['allow', 'block']),
48
+ audit: z.object({
49
+ enabled: z.boolean().default(true),
50
+ logAllowed: z.boolean().default(false),
51
+ logBlocked: z.boolean().default(true),
52
+ includePreview: z.boolean().default(false),
53
+ previewChars: z.number().step(1).min(0).default(160),
54
+ historySize: z.number().step(1).min(0).default(100),
55
+ highlightNewSections: z.boolean().default(true),
56
+ }).default(DEFAULT_AUDIT_CONFIG),
57
+ metrics: z.object({
58
+ enabled: z.boolean().default(true),
59
+ }).default(DEFAULT_METRICS_CONFIG),
60
+ });
61
+ function mergeList(preset, configured) {
62
+ const result = [...new Set([...(preset ?? []), ...(configured ?? [])])];
63
+ if (result.some(value => value.length === 0)) {
64
+ throw new TypeError('firewall rules must not contain empty strings');
65
+ }
66
+ return Object.freeze(result);
67
+ }
68
+ export function resolveConfig(config = {}) {
69
+ const preset = getPreset(config.preset);
70
+ const resolved = {
71
+ enabled: config.enabled ?? DEFAULT_CONFIG.enabled,
72
+ mode: (config.mode ?? preset.mode ?? DEFAULT_CONFIG.mode),
73
+ ...(config.preset === undefined ? {} : { preset: config.preset }),
74
+ blockedSections: mergeList(preset.blockedSections, config.blockedSections),
75
+ allowedSections: mergeList(preset.allowedSections, config.allowedSections),
76
+ blockedPrefixes: mergeList(preset.blockedPrefixes, config.blockedPrefixes),
77
+ allowedPrefixes: mergeList(preset.allowedPrefixes, config.allowedPrefixes),
78
+ blockedPatterns: mergeList(preset.blockedPatterns, config.blockedPatterns),
79
+ allowedPatterns: mergeList(preset.allowedPatterns, config.allowedPatterns),
80
+ protectedSections: mergeList(preset.protectedSections, config.protectedSections),
81
+ protectCoreSections: config.protectCoreSections
82
+ ?? preset.protectCoreSections
83
+ ?? DEFAULT_CONFIG.protectCoreSections,
84
+ unknownPluginPolicy: (config.unknownPluginPolicy
85
+ ?? preset.unknownPluginPolicy
86
+ ?? DEFAULT_CONFIG.unknownPluginPolicy),
87
+ audit: Object.freeze({
88
+ ...DEFAULT_AUDIT_CONFIG,
89
+ ...preset.audit,
90
+ ...config.audit,
91
+ }),
92
+ metrics: Object.freeze({
93
+ ...DEFAULT_METRICS_CONFIG,
94
+ ...preset.metrics,
95
+ ...config.metrics,
96
+ }),
97
+ };
98
+ return Object.freeze(resolved);
99
+ }
100
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,88 @@
1
+ import { AuditStore, createAuditResult } from './audit.js';
2
+ import { compileRules, evaluateSection } from './rules.js';
3
+ function errorMessage(error) {
4
+ return error instanceof Error ? error.message : String(error);
5
+ }
6
+ function validateAssembly(assembly) {
7
+ if (!Array.isArray(assembly.sections))
8
+ throw new TypeError('prompt assembly sections must be an array');
9
+ for (const section of assembly.sections) {
10
+ if (typeof section.name !== 'string' || section.name.length === 0) {
11
+ throw new TypeError('prompt section name must be a non-empty string');
12
+ }
13
+ if (typeof section.text !== 'string') {
14
+ throw new TypeError(`prompt section "${section.name}" text must be a string`);
15
+ }
16
+ }
17
+ }
18
+ function logAudit(audit, config, logger) {
19
+ if (logger === undefined || !config.audit.enabled)
20
+ return;
21
+ const safeLog = (level, message) => {
22
+ try {
23
+ logger[level](message);
24
+ }
25
+ catch {
26
+ // Observability failures must not affect prompt policy.
27
+ }
28
+ };
29
+ safeLog('info', `[prompt-firewall] assembled prompt: ${audit.totalSections} sections, `
30
+ + `${audit.charsBefore} chars, ~${audit.estimatedTokensBefore} estimated tokens`);
31
+ for (const section of audit.sections) {
32
+ if (section.decision === 'blocked' && config.audit.logBlocked) {
33
+ safeLog('warn', `[prompt-firewall] BLOCK ${section.name}: ${section.reason}, `
34
+ + `${section.chars} chars, ~${section.estimatedTokens} estimated tokens`
35
+ + (section.preview === undefined ? '' : `, preview=${JSON.stringify(section.preview)}`));
36
+ }
37
+ else if (section.decision !== 'blocked' && config.audit.logAllowed) {
38
+ safeLog('info', `[prompt-firewall] ${section.decision.toUpperCase()} ${section.name}: ${section.reason}, `
39
+ + `${section.chars} chars, ~${section.estimatedTokens} estimated tokens`
40
+ + (section.preview === undefined ? '' : `, preview=${JSON.stringify(section.preview)}`));
41
+ }
42
+ }
43
+ if (audit.blockedSections > 0) {
44
+ safeLog('info', `[prompt-firewall] result: removed ${audit.blockedSections} sections, `
45
+ + `${audit.charsRemoved} chars, ~${audit.estimatedTokensRemoved} estimated tokens`);
46
+ }
47
+ }
48
+ /**
49
+ * Filter an already assembled DSH prompt. Any internal error is contained and
50
+ * returns the exact original object (fail-open).
51
+ */
52
+ export function applyFirewall(assembly, options) {
53
+ try {
54
+ validateAssembly(assembly);
55
+ const { config } = options;
56
+ const rules = options.evaluate === undefined ? compileRules(config) : undefined;
57
+ const evaluator = options.evaluate ?? (section => evaluateSection(section, rules));
58
+ const sections = assembly.sections;
59
+ const complete = sections.some(section => section.complete === true);
60
+ const decisions = sections.map(section => (complete
61
+ ? { action: 'allow', reason: 'complete-prompt-bypass' }
62
+ : evaluator(section)));
63
+ const audit = createAuditResult(sections, decisions, config.audit, complete ? 'complete prompt detected' : undefined);
64
+ if (config.audit.enabled)
65
+ options.auditStore?.record(audit);
66
+ if (config.metrics.enabled)
67
+ options.metrics?.record(audit);
68
+ logAudit(audit, config, options.logger);
69
+ if (!config.enabled || config.mode === 'off' || config.mode === 'audit' || complete)
70
+ return assembly;
71
+ if (!decisions.some(decision => decision.action === 'block'))
72
+ return assembly;
73
+ return {
74
+ ...assembly,
75
+ sections: assembly.sections.filter((_, index) => decisions[index]?.action !== 'block'),
76
+ };
77
+ }
78
+ catch (error) {
79
+ try {
80
+ options.logger?.error(`[prompt-firewall] internal error; allowing original prompt: ${errorMessage(error)}`);
81
+ }
82
+ catch {
83
+ // Logging must never turn fail-open into a request failure.
84
+ }
85
+ return assembly;
86
+ }
87
+ }
88
+ //# sourceMappingURL=firewall.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"firewall.js","sourceRoot":"","sources":["../src/firewall.ts"],"names":[],"mappings":"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"}
package/lib/index.js ADDED
@@ -0,0 +1,166 @@
1
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
2
+ var useValue = arguments.length > 2;
3
+ for (var i = 0; i < initializers.length; i++) {
4
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
5
+ }
6
+ return useValue ? value : void 0;
7
+ };
8
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
9
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
10
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
11
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
12
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
13
+ var _, done = false;
14
+ for (var i = decorators.length - 1; i >= 0; i--) {
15
+ var context = {};
16
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
17
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
18
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
19
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
20
+ if (kind === "accessor") {
21
+ if (result === void 0) continue;
22
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
23
+ if (_ = accept(result.get)) descriptor.get = _;
24
+ if (_ = accept(result.set)) descriptor.set = _;
25
+ if (_ = accept(result.init)) initializers.unshift(_);
26
+ }
27
+ else if (_ = accept(result)) {
28
+ if (kind === "field") initializers.unshift(_);
29
+ else descriptor[key] = _;
30
+ }
31
+ }
32
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
33
+ done = true;
34
+ };
35
+ import { Context } from '@deepseek-ai/cordis';
36
+ import { installSettingsSection, settingsNamespace } from '@deepseek-ai/dsh-settings';
37
+ import { Remote, TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
38
+ import { AuditStore } from './audit.js';
39
+ import { ConfigSchema, resolveConfig } from './config.js';
40
+ import { applyFirewall } from './firewall.js';
41
+ import { FirewallMetrics } from './metrics.js';
42
+ import { compileRules, evaluateSection } from './rules.js';
43
+ export * from './audit.js';
44
+ export * from './config.js';
45
+ export * from './firewall.js';
46
+ export * from './metrics.js';
47
+ export * from './presets.js';
48
+ export * from './rules.js';
49
+ export * from './types.js';
50
+ /** Cordis plugin ID. */
51
+ export const name = 'prompt-firewall';
52
+ export const inject = ['systemPrompt'];
53
+ export const PROMPT_FIREWALL_SETTINGS_NAMESPACE = settingsNamespace('prompt-firewall');
54
+ export const Config = ConfigSchema;
55
+ /** DSH Host plugin, public firewall service, and browser Remote owner. */
56
+ let PromptFirewall = (() => {
57
+ let _classSuper = TypertRemoteService;
58
+ let _instanceExtraInitializers = [];
59
+ let _inspect_decorators;
60
+ let _setSectionPolicy_decorators;
61
+ return class PromptFirewall extends _classSuper {
62
+ static {
63
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
64
+ _inspect_decorators = [Remote('inspect')];
65
+ _setSectionPolicy_decorators = [Remote('setSectionPolicy')];
66
+ __esDecorate(this, null, _inspect_decorators, { kind: "method", name: "inspect", static: false, private: false, access: { has: obj => "inspect" in obj, get: obj => obj.inspect }, metadata: _metadata }, null, _instanceExtraInitializers);
67
+ __esDecorate(this, null, _setSectionPolicy_decorators, { kind: "method", name: "setSectionPolicy", static: false, private: false, access: { has: obj => "setSectionPolicy" in obj, get: obj => obj.setSectionPolicy }, metadata: _metadata }, null, _instanceExtraInitializers);
68
+ if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
69
+ }
70
+ static inject = inject;
71
+ static Config = ConfigSchema;
72
+ entryConfig = __runInitializers(this, _instanceExtraInitializers);
73
+ configSource;
74
+ resolvedConfig;
75
+ compiledRules;
76
+ audits;
77
+ metrics = new FirewallMetrics();
78
+ constructor(ctx, config = {}) {
79
+ super(ctx, 'promptFirewall', { namespace: 'promptFirewall' });
80
+ this.entryConfig = structuredClone(config);
81
+ this.configSource = () => this.entryConfig;
82
+ this.resolvedConfig = resolveConfig(config);
83
+ this.compiledRules = compileRules(this.resolvedConfig);
84
+ this.audits = new AuditStore(this.resolvedConfig.audit.historySize, this.resolvedConfig.audit.highlightNewSections);
85
+ installSettingsSection(ctx, PROMPT_FIREWALL_SETTINGS_NAMESPACE, ConfigSchema, this.entryConfig, {
86
+ setSource: current => { this.configSource = current; },
87
+ onChange: () => { this.reloadRules(); },
88
+ });
89
+ // Cordis has registration order plus `prepend`, not numeric priorities.
90
+ // Prepending makes this wrapper call downstream contributors first and
91
+ // apply policy while their final result unwinds back through this listener.
92
+ ctx.on('system-prompt/assemble', async (_assembly, _context, next) => {
93
+ const result = await next();
94
+ return applyFirewall(result, {
95
+ config: this.resolvedConfig,
96
+ auditStore: this.audits,
97
+ metrics: this.metrics,
98
+ logger: ctx.logger,
99
+ evaluate: section => evaluateSection(section, this.compiledRules),
100
+ });
101
+ }, { prepend: true });
102
+ }
103
+ inspectLast() {
104
+ return this.audits.last();
105
+ }
106
+ inspectHistory() {
107
+ return this.audits.entries();
108
+ }
109
+ getKnownSections() {
110
+ return this.audits.knownSections();
111
+ }
112
+ getMetrics() {
113
+ return this.metrics.snapshot();
114
+ }
115
+ getConfig() {
116
+ return structuredClone(this.resolvedConfig);
117
+ }
118
+ /** Return one consistent, content-safe browser inspector projection. */
119
+ inspect() {
120
+ return {
121
+ config: this.getConfig(),
122
+ last: this.inspectLast(),
123
+ knownSections: this.getKnownSections(),
124
+ metrics: this.getMetrics(),
125
+ };
126
+ }
127
+ evaluateSection(section) {
128
+ return evaluateSection(section, this.compiledRules);
129
+ }
130
+ async setSectionPolicy(name, policy, expectedRevision) {
131
+ if (name.length === 0)
132
+ throw new TypeError('section name must be non-empty');
133
+ const settings = this.ctx.get('settings');
134
+ if (settings === undefined) {
135
+ throw new Error('prompt-firewall settings are unavailable; mount a DSH settings provider');
136
+ }
137
+ const current = this.configSource();
138
+ const without = (values) => ((values ?? []).filter(value => value !== name));
139
+ const allowedSections = without(current.allowedSections);
140
+ const blockedSections = without(current.blockedSections);
141
+ const protectedSections = without(current.protectedSections);
142
+ if (policy === 'allow')
143
+ allowedSections.push(name);
144
+ else if (policy === 'block')
145
+ blockedSections.push(name);
146
+ else if (policy === 'protect')
147
+ protectedSections.push(name);
148
+ await settings.update(PROMPT_FIREWALL_SETTINGS_NAMESPACE, {
149
+ allowedSections,
150
+ blockedSections,
151
+ protectedSections,
152
+ }, expectedRevision);
153
+ // The settings scope has committed synchronously by this point; refresh
154
+ // before the asynchronous watch callback so Remote callers observe their write.
155
+ this.reloadRules();
156
+ }
157
+ reloadRules() {
158
+ this.resolvedConfig = resolveConfig(this.configSource());
159
+ this.compiledRules = compileRules(this.resolvedConfig);
160
+ this.audits.configure(this.resolvedConfig.audit.historySize, this.resolvedConfig.audit.highlightNewSections);
161
+ }
162
+ };
163
+ })();
164
+ export { PromptFirewall };
165
+ export default PromptFirewall;
166
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/lib/metrics.js ADDED
@@ -0,0 +1,38 @@
1
+ export const METRIC_NAMES = Object.freeze({
2
+ requestsTotal: 'dsh_prompt_firewall_requests_total',
3
+ sectionsTotal: 'dsh_prompt_firewall_sections_total',
4
+ sectionsBlockedTotal: 'dsh_prompt_firewall_sections_blocked_total',
5
+ charsRemovedTotal: 'dsh_prompt_firewall_chars_removed_total',
6
+ estimatedTokensRemovedTotal: 'dsh_prompt_firewall_estimated_tokens_removed_total',
7
+ });
8
+ const ZERO_SNAPSHOT = Object.freeze({
9
+ requestsTotal: 0,
10
+ sectionsTotal: 0,
11
+ sectionsBlockedTotal: 0,
12
+ charsRemovedTotal: 0,
13
+ estimatedTokensRemovedTotal: 0,
14
+ });
15
+ /** Backend-neutral, label-free counters suitable for UI or an OTel adapter. */
16
+ export class FirewallMetrics {
17
+ counters = { ...ZERO_SNAPSHOT };
18
+ record(result) {
19
+ this.counters.requestsTotal += 1;
20
+ this.counters.sectionsTotal += result.totalSections;
21
+ this.counters.sectionsBlockedTotal += result.blockedSections;
22
+ this.counters.charsRemovedTotal += result.charsRemoved;
23
+ this.counters.estimatedTokensRemovedTotal += result.estimatedTokensRemoved;
24
+ }
25
+ snapshot() {
26
+ return { ...this.counters };
27
+ }
28
+ namedSnapshot() {
29
+ return Object.freeze({
30
+ [METRIC_NAMES.requestsTotal]: this.counters.requestsTotal,
31
+ [METRIC_NAMES.sectionsTotal]: this.counters.sectionsTotal,
32
+ [METRIC_NAMES.sectionsBlockedTotal]: this.counters.sectionsBlockedTotal,
33
+ [METRIC_NAMES.charsRemovedTotal]: this.counters.charsRemovedTotal,
34
+ [METRIC_NAMES.estimatedTokensRemovedTotal]: this.counters.estimatedTokensRemovedTotal,
35
+ });
36
+ }
37
+ }
38
+ //# sourceMappingURL=metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC;IACxC,aAAa,EAAE,oCAAoC;IACnD,aAAa,EAAE,oCAAoC;IACnD,oBAAoB,EAAE,4CAA4C;IAClE,iBAAiB,EAAE,yCAAyC;IAC5D,2BAA2B,EAAE,oDAAoD;CACzE,CAAC,CAAA;AAIX,MAAM,aAAa,GAA4C,MAAM,CAAC,MAAM,CAAC;IAC3E,aAAa,EAAE,CAAC;IAChB,aAAa,EAAE,CAAC;IAChB,oBAAoB,EAAE,CAAC;IACvB,iBAAiB,EAAE,CAAC;IACpB,2BAA2B,EAAE,CAAC;CAC/B,CAAC,CAAA;AAEF,+EAA+E;AAC/E,MAAM,OAAO,eAAe;IAClB,QAAQ,GAAkC,EAAE,GAAG,aAAa,EAAE,CAAA;IAEtE,MAAM,CAAC,MAAyB;QAC9B,IAAI,CAAC,QAAQ,CAAC,aAAa,IAAI,CAAC,CAAA;QAChC,IAAI,CAAC,QAAQ,CAAC,aAAa,IAAI,MAAM,CAAC,aAAa,CAAA;QACnD,IAAI,CAAC,QAAQ,CAAC,oBAAoB,IAAI,MAAM,CAAC,eAAe,CAAA;QAC5D,IAAI,CAAC,QAAQ,CAAC,iBAAiB,IAAI,MAAM,CAAC,YAAY,CAAA;QACtD,IAAI,CAAC,QAAQ,CAAC,2BAA2B,IAAI,MAAM,CAAC,sBAAsB,CAAA;IAC5E,CAAC;IAED,QAAQ;QACN,OAAO,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAA;IAC7B,CAAC;IAED,aAAa;QACX,OAAO,MAAM,CAAC,MAAM,CAAC;YACnB,CAAC,YAAY,CAAC,aAAa,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,aAAa;YACzD,CAAC,YAAY,CAAC,aAAa,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,aAAa;YACzD,CAAC,YAAY,CAAC,oBAAoB,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,oBAAoB;YACvE,CAAC,YAAY,CAAC,iBAAiB,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,iBAAiB;YACjE,CAAC,YAAY,CAAC,2BAA2B,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,2BAA2B;SACtF,CAAC,CAAA;IACJ,CAAC;CACF"}
package/lib/presets.js ADDED
@@ -0,0 +1,23 @@
1
+ export const CLEAN_BLOCKED_SECTIONS = Object.freeze([
2
+ 'plugin:dsh-liangshen',
3
+ 'plugin:dsh-ssh',
4
+ 'plugin:task-board',
5
+ 'plugin:dsh-desktop-launcher',
6
+ ]);
7
+ export const PRESETS = Object.freeze({
8
+ clean: Object.freeze({
9
+ mode: 'blocklist',
10
+ blockedSections: [...CLEAN_BLOCKED_SECTIONS],
11
+ }),
12
+ strict: Object.freeze({
13
+ mode: 'allowlist',
14
+ unknownPluginPolicy: 'block',
15
+ }),
16
+ 'audit-only': Object.freeze({
17
+ mode: 'audit',
18
+ }),
19
+ });
20
+ export function getPreset(name) {
21
+ return name === undefined ? {} : PRESETS[name];
22
+ }
23
+ //# sourceMappingURL=presets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presets.js","sourceRoot":"","sources":["../src/presets.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC,MAAM,CAAC;IAClD,sBAAsB;IACtB,gBAAgB;IAChB,mBAAmB;IACnB,6BAA6B;CACrB,CAAC,CAAA;AAEX,MAAM,CAAC,MAAM,OAAO,GAAqE,MAAM,CAAC,MAAM,CAAC;IACrG,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC;QACnB,IAAI,EAAE,WAAW;QACjB,eAAe,EAAE,CAAC,GAAG,sBAAsB,CAAC;KAC7C,CAAC;IACF,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC;QACpB,IAAI,EAAE,WAAW;QACjB,mBAAmB,EAAE,OAAO;KAC7B,CAAC;IACF,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC;QAC1B,IAAI,EAAE,OAAO;KACd,CAAC;CACH,CAAC,CAAA;AAEF,MAAM,UAAU,SAAS,CAAC,IAAgC;IACxD,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;AAChD,CAAC"}
package/lib/rules.js ADDED
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Verified against the upstream DSH registry. `harness:` and `deployment:` are
3
+ * emitted by dsh-system-prompt; `tool:` and `tools:` are used for tool guidance.
4
+ * The remaining conservative namespaces are retained for compatible hosts.
5
+ */
6
+ export const CORE_SECTION_PREFIXES = Object.freeze([
7
+ 'harness:',
8
+ 'deployment:',
9
+ 'tool:',
10
+ 'tools:',
11
+ 'runtime:',
12
+ 'system:',
13
+ ]);
14
+ function escapeRegExp(value) {
15
+ return value.replace(/[|\\{}()[\]^$+?.]/g, '\\$&');
16
+ }
17
+ export function globToRegExp(glob) {
18
+ let source = '';
19
+ for (const character of glob) {
20
+ if (character === '*')
21
+ source += '.*';
22
+ else if (character === '?')
23
+ source += '.';
24
+ else
25
+ source += escapeRegExp(character);
26
+ }
27
+ return new RegExp(`^${source}$`, 'u');
28
+ }
29
+ function compilePatterns(patterns) {
30
+ return Object.freeze(patterns.map(source => Object.freeze({
31
+ source,
32
+ expression: globToRegExp(source),
33
+ })));
34
+ }
35
+ export function compileRules(config) {
36
+ return Object.freeze({
37
+ config,
38
+ protectedSections: new Set(config.protectedSections),
39
+ allowedSections: new Set(config.allowedSections),
40
+ blockedSections: new Set(config.blockedSections),
41
+ allowedPrefixes: Object.freeze([...config.allowedPrefixes]),
42
+ blockedPrefixes: Object.freeze([...config.blockedPrefixes]),
43
+ allowedPatterns: compilePatterns(config.allowedPatterns),
44
+ blockedPatterns: compilePatterns(config.blockedPatterns),
45
+ });
46
+ }
47
+ function prefixMatch(name, prefixes) {
48
+ return prefixes.find(prefix => name.startsWith(prefix));
49
+ }
50
+ function patternMatch(name, patterns) {
51
+ return patterns.find(pattern => pattern.expression.test(name))?.source;
52
+ }
53
+ export function evaluateSection(section, rules) {
54
+ const { name } = section;
55
+ if (typeof name !== 'string' || name.length === 0) {
56
+ throw new TypeError('prompt section name must be a non-empty string');
57
+ }
58
+ if (rules.protectedSections.has(name)) {
59
+ return { action: 'protect', reason: 'exact-protect', rule: name };
60
+ }
61
+ if (rules.config.protectCoreSections) {
62
+ const corePrefix = prefixMatch(name, CORE_SECTION_PREFIXES);
63
+ if (corePrefix !== undefined) {
64
+ return { action: 'protect', reason: 'core-protect', rule: corePrefix };
65
+ }
66
+ }
67
+ if (!rules.config.enabled || rules.config.mode === 'off') {
68
+ return { action: 'allow', reason: 'mode-off' };
69
+ }
70
+ if (rules.config.mode === 'audit') {
71
+ return { action: 'allow', reason: 'mode-audit' };
72
+ }
73
+ if (rules.allowedSections.has(name)) {
74
+ return { action: 'allow', reason: 'exact-allow', rule: name };
75
+ }
76
+ if (rules.blockedSections.has(name)) {
77
+ return { action: 'block', reason: 'exact-block', rule: name };
78
+ }
79
+ const allowedPrefix = prefixMatch(name, rules.allowedPrefixes);
80
+ if (allowedPrefix !== undefined) {
81
+ return { action: 'allow', reason: 'prefix-allow', rule: allowedPrefix };
82
+ }
83
+ const blockedPrefix = prefixMatch(name, rules.blockedPrefixes);
84
+ if (blockedPrefix !== undefined) {
85
+ return { action: 'block', reason: 'prefix-block', rule: blockedPrefix };
86
+ }
87
+ const allowedPattern = patternMatch(name, rules.allowedPatterns);
88
+ if (allowedPattern !== undefined) {
89
+ return { action: 'allow', reason: 'pattern-allow', rule: allowedPattern };
90
+ }
91
+ const blockedPattern = patternMatch(name, rules.blockedPatterns);
92
+ if (blockedPattern !== undefined) {
93
+ return { action: 'block', reason: 'pattern-block', rule: blockedPattern };
94
+ }
95
+ if (rules.config.mode === 'allowlist') {
96
+ return { action: 'block', reason: 'allowlist-default' };
97
+ }
98
+ if (rules.config.unknownPluginPolicy === 'block' && name.startsWith('plugin:')) {
99
+ return { action: 'block', reason: 'unknown-plugin-policy' };
100
+ }
101
+ return { action: 'allow', reason: 'blocklist-default' };
102
+ }
103
+ //# sourceMappingURL=rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.js","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ /* Generated by @deepseek-ai/dsh-typert-generator from FaceModel — do not edit. */
2
+
3
+ export declare const TYPERT: unknown