@goodandready/dsh-approval-gate 0.1.17 → 0.1.19

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
@@ -3,6 +3,7 @@ import { BandsEngine } from "./bands.js";
3
3
  import { AuditLogger } from "./audit-log.js";
4
4
  import { DeclarativeRulesEngine } from "./rules-loader.js";
5
5
  import { LlmClassifier } from "./classifier.js";
6
+ import { ClassifierLatencyTracker } from "./latency.js";
6
7
  import Schema from "@deepseek-ai/schemastery";
7
8
 
8
9
  if (typeof Schema.prototype?.volatile !== "function") {
@@ -230,6 +231,16 @@ export const Config = Schema.object({
230
231
  classifierTimeoutPolicy: Schema.union(["strict", "permissive"]).default("strict").volatile(),
231
232
  /** Maximum context characters for classifier prompt (#117). */
232
233
  classifierMaxContext: Schema.number().default(1000).volatile(),
234
+ /** Maximum payload bytes for tool arguments (#71). */
235
+ maxPayloadBytes: Schema.number().default(65536).volatile(),
236
+ /** Isolate temporary directories to workspace/.dsh/tmp (#102). */
237
+ isolateTempRoots: Schema.boolean().default(true).volatile(),
238
+ /** Maximum allowed created files per session to prevent overengineering (#89). */
239
+ maxFilesPerSession: Schema.number().default(10).volatile(),
240
+ /** Maximum latency in ms before classifier degrades to deterministic rules (#57). */
241
+ classifierSlaMs: Schema.number().default(2000).volatile(),
242
+ /** Task contract boundary rules (#87). */
243
+ taskContract: Schema.any().volatile(),
233
244
  /** Security engine instance (internal/testing). */
234
245
  engine: Schema.any().hidden(),
235
246
  });
@@ -281,10 +292,21 @@ export function apply(ctx, config) {
281
292
  : null;
282
293
 
283
294
  const engine = (config && config.engine) || cfg.engine || new SecurityEngine({
284
- inspectConfig: { toolName: toolName, fileWriteTools: fileWriteTools, workspaceDir: cfg.workspaceDir || "" },
295
+ inspectConfig: {
296
+ toolName: toolName,
297
+ fileWriteTools: fileWriteTools,
298
+ workspaceDir: cfg.workspaceDir || "",
299
+ maxPayloadBytes: cfg.maxPayloadBytes !== undefined ? cfg.maxPayloadBytes : 65536,
300
+ isolateTempRoots: cfg.isolateTempRoots !== false,
301
+ },
302
+ taskContract: cfg.taskContract || undefined,
303
+ maxFilesPerSession: cfg.maxFilesPerSession !== undefined ? cfg.maxFilesPerSession : 10,
285
304
  bands: new BandsEngine({ toolRegistry: ctx && ctx.tools }),
286
305
  classifier,
287
306
  timeoutPolicy: cfg.classifierTimeoutPolicy || "strict",
307
+ latencyTracker: new ClassifierLatencyTracker({
308
+ slaMs: cfg.classifierSlaMs !== undefined ? cfg.classifierSlaMs : 2000,
309
+ }),
288
310
  defaultVerdict: cfg.defaultVerdict || "allow",
289
311
  dryRun: Boolean(cfg.dryRun || cfg.shadowMode),
290
312
  auditFailClosed: Boolean(cfg.auditFailClosed),
@@ -310,6 +332,8 @@ export function apply(ctx, config) {
310
332
  getCounters: () => engine.getCounters(),
311
333
  resetCounters: () => engine.resetCounters(),
312
334
  getLedgerSummary: (sessionId) => engine.getLedgerSummary(sessionId),
335
+ getLatencyMetrics: () => (engine.getLatencyMetrics ? engine.getLatencyMetrics() : null),
336
+ resetLatencyTracker: () => (engine.resetLatencyTracker ? engine.resetLatencyTracker() : undefined),
313
337
  getSnapshot: () => ({
314
338
  active: true,
315
339
  dryRun: Boolean(cfg.dryRun || cfg.shadowMode),
@@ -320,6 +344,7 @@ export function apply(ctx, config) {
320
344
  rulesCount: engine.declarativeRules ? engine.declarativeRules.count() : 0,
321
345
  cacheStats: engine.cache ? engine.cache.stats() : null,
322
346
  breakerState: engine.breaker ? engine.breaker.getState() : null,
347
+ latencyMetrics: engine.getLatencyMetrics ? engine.getLatencyMetrics() : null,
323
348
  }),
324
349
  };
325
350
  if (ctx && typeof ctx === "object") {
@@ -520,27 +545,11 @@ export {
520
545
  DEFAULT_RETAIN_LINES,
521
546
  auditRotateContent,
522
547
  } from "./audit-log.js";
523
- export {
524
- BlockCounters,
525
- categorizeReason,
526
- } from "./counters.js";
527
- export {
528
- isCriticalOperation,
529
- } from "./engine.js";
530
- export {
531
- parseYaml,
532
- parseScalar,
533
- stripComment,
534
- } from "./yaml-parser.js";
535
- export {
536
- matchConditionValue,
537
- evaluateWhen,
538
- } from "./when-matcher.js";
539
- export {
540
- HotwordsMatcher,
541
- DEFAULT_HOTWORDS,
542
- extractWords,
543
- } from "./hotwords.js";
548
+ export { BlockCounters, categorizeReason } from "./counters.js";
549
+ export { isCriticalOperation } from "./engine.js";
550
+ export { parseYaml, parseScalar, stripComment } from "./yaml-parser.js";
551
+ export { matchConditionValue, evaluateWhen } from "./when-matcher.js";
552
+ export { HotwordsMatcher, DEFAULT_HOTWORDS, extractWords } from "./hotwords.js";
544
553
  export {
545
554
  DeclarativeRulesEngine,
546
555
  BUILTIN_RULES_FILE,
@@ -553,5 +562,16 @@ export {
553
562
  sanitizeClassifierInput,
554
563
  truncateClassifierContext,
555
564
  isLowRiskExecution,
565
+ isShapeRejectError,
566
+ extractJsonPayload,
567
+ ClassifierVerdictSchema,
568
+ validateClassifierResponse,
556
569
  LlmClassifier,
557
570
  } from "./classifier.js";
571
+ export { ContractGuard } from "./contract-guard.js";
572
+ export { OverengineeringGuard, DEFAULT_MAX_FILES_PER_SESSION } from "./overengineering.js";
573
+ export { resolveTempRoot, isGlobalTempPath, checkTempIsolation } from "./paths.js";
574
+ export { computePayloadSize, scanPromptInjection } from "./inspect.js";
575
+ export { RISK_BUCKETS, RISK_TAGS, categorizeRiskBucket, extractRiskTags } from "./risk.js";
576
+ export { ClassifierLatencyTracker, DEFAULT_CLASSIFIER_SLA_MS } from "./latency.js";
577
+