@edictum/core 0.1.0 → 0.2.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/README.md +46 -0
- package/dist/{chunk-IXMXZGJG.mjs → chunk-23XIQZR5.mjs} +1 -1
- package/dist/chunk-23XIQZR5.mjs.map +1 -0
- package/dist/{chunk-CRPQFRYJ.mjs → chunk-2YSBMUK5.mjs} +2 -10
- package/dist/chunk-2YSBMUK5.mjs.map +1 -0
- package/dist/{chunk-X5E2YY35.mjs → chunk-JOBPRXVE.mjs} +44 -110
- package/dist/chunk-JOBPRXVE.mjs.map +1 -0
- package/dist/{dry-run-54PYIM6T.mjs → dry-run-JTRNTZA5.mjs} +3 -3
- package/dist/dry-run-JTRNTZA5.mjs.map +1 -0
- package/dist/index.cjs +413 -224
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -27
- package/dist/index.d.ts +28 -27
- package/dist/index.mjs +370 -118
- package/dist/index.mjs.map +1 -1
- package/dist/runner-JCAQMF6O.mjs +10 -0
- package/package.json +14 -13
- package/dist/chunk-CRPQFRYJ.mjs.map +0 -1
- package/dist/chunk-IXMXZGJG.mjs.map +0 -1
- package/dist/chunk-X5E2YY35.mjs.map +0 -1
- package/dist/dry-run-54PYIM6T.mjs.map +0 -1
- package/dist/runner-ASI4JIW2.mjs +0 -10
- /package/dist/{runner-ASI4JIW2.mjs.map → runner-JCAQMF6O.mjs.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/approval.ts","../src/redaction.ts","../src/audit.ts","../src/contracts.ts","../src/hooks.ts","../src/pipeline.ts","../src/session.ts","../src/runner.ts"],"sourcesContent":["/** Approval protocol for human-in-the-loop tool call authorization. */\n\nimport { randomUUID } from 'node:crypto'\nimport * as readline from 'node:readline'\n\nimport { RedactionPolicy } from './redaction.js'\n\n/** Strip ANSI escape sequences and control characters from terminal output. */\nfunction sanitizeForTerminal(s: string): string {\n return s.replace(/\\x1b\\[[0-9;]*[a-zA-Z]/g, '').replace(/[\\x00-\\x1f\\x7f-\\x9f\\u2028\\u2029]/g, '')\n}\n\n// ---------------------------------------------------------------------------\n// ApprovalStatus\n// ---------------------------------------------------------------------------\n\nexport const ApprovalStatus = {\n PENDING: 'pending',\n APPROVED: 'approved',\n DENIED: 'denied',\n TIMEOUT: 'timeout',\n} as const\n\nexport type ApprovalStatus = (typeof ApprovalStatus)[keyof typeof ApprovalStatus]\n\n// ---------------------------------------------------------------------------\n// ApprovalRequest — frozen data object\n// ---------------------------------------------------------------------------\n\n/** A request for human approval of a tool call. */\nexport interface ApprovalRequest {\n readonly approvalId: string\n readonly toolName: string\n readonly toolArgs: Readonly<Record<string, unknown>>\n readonly message: string\n readonly timeout: number // seconds\n readonly timeoutEffect: string // \"deny\" | \"allow\"\n readonly principal: Readonly<Record<string, unknown>> | null\n readonly metadata: Readonly<Record<string, unknown>>\n readonly createdAt: Date\n}\n\nfunction createApprovalRequest(\n fields: Omit<ApprovalRequest, 'createdAt'> & { createdAt?: Date },\n): ApprovalRequest {\n const request: ApprovalRequest = {\n approvalId: fields.approvalId,\n toolName: fields.toolName,\n toolArgs: Object.freeze({ ...fields.toolArgs }),\n message: fields.message,\n timeout: fields.timeout,\n timeoutEffect: fields.timeoutEffect,\n principal: fields.principal !== null ? Object.freeze({ ...fields.principal }) : null,\n metadata: Object.freeze({ ...fields.metadata }),\n createdAt: fields.createdAt ?? new Date(),\n }\n return Object.freeze(request)\n}\n\n// ---------------------------------------------------------------------------\n// ApprovalDecision — frozen data object\n// ---------------------------------------------------------------------------\n\n/** The result of a human approval decision. */\nexport interface ApprovalDecision {\n readonly approved: boolean\n readonly approver: string | null\n readonly reason: string | null\n readonly status: ApprovalStatus\n readonly timestamp: Date\n}\n\nfunction createApprovalDecision(\n fields: Partial<ApprovalDecision> & { approved: boolean },\n): ApprovalDecision {\n const decision: ApprovalDecision = {\n approved: fields.approved,\n approver: fields.approver ?? null,\n reason: fields.reason ?? null,\n status: fields.status ?? ApprovalStatus.PENDING,\n timestamp: fields.timestamp ?? new Date(),\n }\n return Object.freeze(decision)\n}\n\n// ---------------------------------------------------------------------------\n// ApprovalBackend — protocol\n// ---------------------------------------------------------------------------\n\n/** Protocol for human-in-the-loop approval providers. */\nexport interface ApprovalBackend {\n requestApproval(\n toolName: string,\n toolArgs: Record<string, unknown>,\n message: string,\n options?: {\n timeout?: number\n timeoutEffect?: string\n principal?: Record<string, unknown> | null\n metadata?: Record<string, unknown> | null\n },\n ): Promise<ApprovalRequest>\n\n waitForDecision(approvalId: string, timeout?: number | null): Promise<ApprovalDecision>\n}\n\n// ---------------------------------------------------------------------------\n// LocalApprovalBackend — CLI-based approval for local testing\n// ---------------------------------------------------------------------------\n\n/**\n * CLI-based approval backend for local testing.\n *\n * Prompts on stdout, reads from stdin. Blocks until response or timeout.\n */\nexport class LocalApprovalBackend implements ApprovalBackend {\n private readonly _pending: Map<string, ApprovalRequest> = new Map()\n\n async requestApproval(\n toolName: string,\n toolArgs: Record<string, unknown>,\n message: string,\n options?: {\n timeout?: number\n timeoutEffect?: string\n principal?: Record<string, unknown> | null\n metadata?: Record<string, unknown> | null\n },\n ): Promise<ApprovalRequest> {\n const approvalId = randomUUID()\n const request = createApprovalRequest({\n approvalId,\n toolName,\n toolArgs,\n message,\n timeout: options?.timeout ?? 300,\n timeoutEffect: options?.timeoutEffect ?? 'deny',\n principal: options?.principal ?? null,\n metadata: options?.metadata ?? {},\n })\n this._pending.set(approvalId, request)\n\n const redaction = new RedactionPolicy()\n const safeArgs = redaction.redactArgs(toolArgs)\n process.stdout.write(`[APPROVAL REQUIRED] ${sanitizeForTerminal(message)}\\n`)\n process.stdout.write(` Tool: ${sanitizeForTerminal(toolName)}\\n`)\n process.stdout.write(` Args: ${sanitizeForTerminal(JSON.stringify(safeArgs))}\\n`)\n process.stdout.write(` ID: ${approvalId}\\n`)\n\n return request\n }\n\n async waitForDecision(approvalId: string, timeout?: number | null): Promise<ApprovalDecision> {\n const request = this._pending.get(approvalId)\n const effectiveTimeout = timeout ?? (request ? request.timeout : 300)\n\n try {\n const response = await this._readStdin(approvalId, effectiveTimeout)\n const approved = ['y', 'yes', 'approve'].includes(response.trim().toLowerCase())\n const status = approved ? ApprovalStatus.APPROVED : ApprovalStatus.DENIED\n return createApprovalDecision({\n approved,\n approver: 'local',\n status,\n })\n } catch {\n // Timeout\n const timeoutEffect = request ? request.timeoutEffect : 'deny'\n const approved = timeoutEffect === 'allow'\n return createApprovalDecision({\n approved,\n status: ApprovalStatus.TIMEOUT,\n })\n }\n }\n\n /** Read a single line from stdin with a timeout. */\n private _readStdin(approvalId: string, timeoutSeconds: number): Promise<string> {\n return new Promise<string>((resolve, reject) => {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n })\n\n const timer = setTimeout(() => {\n rl.close()\n reject(new Error('Approval timed out'))\n }, timeoutSeconds * 1000)\n\n rl.question(`Approve? [y/N] (id: ${approvalId}): `, (answer) => {\n clearTimeout(timer)\n rl.close()\n resolve(answer)\n })\n })\n }\n}\n","/** Redaction policy for sensitive data in audit events. */\n\nimport { EdictumConfigError } from './errors.js'\n\n// ---------------------------------------------------------------------------\n// RedactionPolicy\n// ---------------------------------------------------------------------------\n\n/**\n * Redact sensitive data from audit events.\n *\n * Recurses into dicts AND lists. Normalizes keys to lowercase.\n * Caps total payload size. Detects common secret patterns in values.\n */\nexport class RedactionPolicy {\n static readonly DEFAULT_SENSITIVE_KEYS: ReadonlySet<string> = new Set([\n 'password',\n 'secret',\n 'token',\n 'api_key',\n 'apikey',\n 'api-key',\n 'authorization',\n 'auth',\n 'credentials',\n 'private_key',\n 'privatekey',\n 'access_token',\n 'refresh_token',\n 'client_secret',\n 'connection_string',\n 'database_url',\n 'db_password',\n 'ssh_key',\n 'passphrase',\n ])\n\n static readonly BASH_REDACTION_PATTERNS: ReadonlyArray<readonly [string, string]> = [\n [String.raw`(export\\s+\\w*(?:KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL)\\w*=)\\S+`, '$1[REDACTED]'],\n [String.raw`((?:^|\\s)-p\\s*|--password[= ])\\S+`, '$1[REDACTED]'],\n [String.raw`(://\\w+:)\\S+(@)`, '$1[REDACTED]$2'],\n ]\n\n static readonly SECRET_VALUE_PATTERNS: ReadonlyArray<string> = [\n String.raw`^(sk-[a-zA-Z0-9]{20,})`,\n String.raw`^(AKIA[A-Z0-9]{16})`,\n String.raw`^(eyJ[a-zA-Z0-9_-]{20,}\\.)`,\n String.raw`^(ghp_[a-zA-Z0-9]{36})`,\n String.raw`^(xox[bpas]-[a-zA-Z0-9-]{10,})`,\n ]\n\n static readonly MAX_PAYLOAD_SIZE = 32_768\n static readonly MAX_REGEX_INPUT = 10_000\n static readonly MAX_PATTERN_LENGTH = 10_000\n\n private readonly _keys: ReadonlySet<string>\n private readonly _patterns: ReadonlyArray<readonly [string, string]>\n private readonly _compiledPatterns: ReadonlyArray<readonly [RegExp, string]>\n private readonly _compiledSecretPatterns: ReadonlyArray<RegExp>\n private readonly _detectValues: boolean\n\n constructor(\n sensitiveKeys?: ReadonlySet<string> | null,\n customPatterns?: ReadonlyArray<readonly [string, string]> | null,\n detectSecretValues: boolean = true,\n ) {\n const baseKeys = sensitiveKeys\n ? new Set([...RedactionPolicy.DEFAULT_SENSITIVE_KEYS, ...sensitiveKeys])\n : new Set(RedactionPolicy.DEFAULT_SENSITIVE_KEYS)\n this._keys = new Set([...baseKeys].map((k) => k.toLowerCase()))\n if (customPatterns) {\n for (const [pattern] of customPatterns) {\n if (pattern.length > RedactionPolicy.MAX_PATTERN_LENGTH) {\n throw new EdictumConfigError(\n `Custom redaction pattern exceeds ${RedactionPolicy.MAX_PATTERN_LENGTH} characters`,\n )\n }\n }\n }\n this._patterns = [...(customPatterns ?? []), ...RedactionPolicy.BASH_REDACTION_PATTERNS]\n this._compiledPatterns = this._patterns.map(\n ([pattern, replacement]) => [new RegExp(pattern, 'g'), replacement] as const,\n )\n this._compiledSecretPatterns = RedactionPolicy.SECRET_VALUE_PATTERNS.map((p) => new RegExp(p))\n this._detectValues = detectSecretValues\n }\n\n /** Recursively redact sensitive data from tool arguments. */\n redactArgs(args: unknown): unknown {\n if (args !== null && typeof args === 'object' && !Array.isArray(args)) {\n const result: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(args as Record<string, unknown>)) {\n result[key] = this._isSensitiveKey(key) ? '[REDACTED]' : this.redactArgs(value)\n }\n return result\n }\n if (Array.isArray(args)) {\n return args.map((item) => this.redactArgs(item))\n }\n if (typeof args === 'string') {\n if (this._detectValues && this._looksLikeSecret(args)) {\n return '[REDACTED]'\n }\n // Apply bash redaction patterns to catch credentials in shell commands.\n // Gated on _detectValues so detectSecretValues=false suppresses bash\n // patterns in redactArgs. Note: redactBashCommand and redactResult always\n // apply bash patterns regardless of this flag.\n if (this._detectValues) {\n // Cap before running patterns — consistent with redactBashCommand / redactResult.\n const capped =\n args.length > RedactionPolicy.MAX_REGEX_INPUT\n ? args.slice(0, RedactionPolicy.MAX_REGEX_INPUT)\n : args\n let redacted = capped\n for (const [pattern, replacement] of this._compiledPatterns) {\n pattern.lastIndex = 0\n redacted = redacted.replace(pattern, replacement)\n }\n if (redacted.length > 1000) {\n return redacted.slice(0, 997) + '...'\n }\n return redacted\n }\n if (args.length > 1000) {\n return args.slice(0, 997) + '...'\n }\n return args\n }\n return args\n }\n\n /** Check if a key name indicates sensitive data. */\n _isSensitiveKey(key: string): boolean {\n const k = key.toLowerCase()\n if (this._keys.has(k)) return true\n // Normalize camelCase → snake_case for set lookup (e.g. databaseUrl → database_url)\n const normalized = key.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase()\n if (normalized !== k && this._keys.has(normalized)) return true\n // Split on _ , - , and camelCase boundaries (e.g. accessToken → [access, token])\n // to catch both snake_case and camelCase field names common in JS/TS.\n const parts = normalized.split(/[_\\-]/)\n return parts.some(\n (part) =>\n part === 'token' ||\n part === 'key' ||\n part === 'secret' ||\n part === 'password' ||\n part === 'credential',\n )\n }\n\n /** Check if a string value looks like a known secret format. */\n _looksLikeSecret(value: string): boolean {\n const capped =\n value.length > RedactionPolicy.MAX_REGEX_INPUT\n ? value.slice(0, RedactionPolicy.MAX_REGEX_INPUT)\n : value\n for (const regex of this._compiledSecretPatterns) {\n if (regex.test(capped)) {\n return true\n }\n }\n return false\n }\n\n /** Apply redaction patterns to a bash command string. */\n redactBashCommand(command: string): string {\n const capped =\n command.length > RedactionPolicy.MAX_REGEX_INPUT\n ? command.slice(0, RedactionPolicy.MAX_REGEX_INPUT)\n : command\n let result = capped\n for (const [regex, replacement] of this._compiledPatterns) {\n regex.lastIndex = 0\n result = result.replace(regex, replacement)\n }\n return result\n }\n\n /** Apply redaction patterns and truncate a result string. */\n redactResult(result: string, maxLength: number = 500): string {\n const capped =\n result.length > RedactionPolicy.MAX_REGEX_INPUT\n ? result.slice(0, RedactionPolicy.MAX_REGEX_INPUT)\n : result\n let redacted = capped\n for (const [regex, replacement] of this._compiledPatterns) {\n regex.lastIndex = 0\n redacted = redacted.replace(regex, replacement)\n }\n if (redacted.length > maxLength) {\n redacted = redacted.slice(0, maxLength - 3) + '...'\n }\n return redacted\n }\n\n /** Cap total serialized size of audit payload. Returns a new object if truncated. */\n capPayload(data: Record<string, unknown>): Record<string, unknown> {\n const serialized = JSON.stringify(data)\n if (serialized.length > RedactionPolicy.MAX_PAYLOAD_SIZE) {\n const { resultSummary: _rs, toolArgs: _ta, ...rest } = data\n void _rs\n void _ta\n return {\n ...rest,\n _truncated: true,\n toolArgs: { _redacted: 'payload exceeded 32KB' },\n }\n }\n return data\n }\n}\n","/** Structured Event Log with Redaction. */\n\nimport { appendFile } from 'node:fs/promises'\n\nimport { RedactionPolicy } from './redaction.js'\n\n// -- AuditAction --------------------------------------------------------------\n\nexport const AuditAction = {\n CALL_DENIED: 'call_denied',\n CALL_WOULD_DENY: 'call_would_deny',\n CALL_ALLOWED: 'call_allowed',\n CALL_EXECUTED: 'call_executed',\n CALL_FAILED: 'call_failed',\n POSTCONDITION_WARNING: 'postcondition_warning',\n CALL_APPROVAL_REQUESTED: 'call_approval_requested',\n CALL_APPROVAL_GRANTED: 'call_approval_granted',\n CALL_APPROVAL_DENIED: 'call_approval_denied',\n CALL_APPROVAL_TIMEOUT: 'call_approval_timeout',\n} as const\n\nexport type AuditAction = (typeof AuditAction)[keyof typeof AuditAction]\n\n// -- AuditEvent ---------------------------------------------------------------\n\nexport interface AuditEvent {\n schemaVersion: string\n timestamp: Date\n runId: string\n callId: string\n callIndex: number\n parentCallId: string | null\n toolName: string\n toolArgs: Record<string, unknown>\n sideEffect: string\n environment: string\n principal: Record<string, unknown> | null\n action: AuditAction\n decisionSource: string | null\n decisionName: string | null\n reason: string | null\n hooksEvaluated: Record<string, unknown>[]\n contractsEvaluated: Record<string, unknown>[]\n toolSuccess: boolean | null\n postconditionsPassed: boolean | null\n durationMs: number\n error: string | null\n resultSummary: string | null\n sessionAttemptCount: number\n sessionExecutionCount: number\n mode: string\n policyVersion: string | null\n policyError: boolean\n}\n\n/** Factory with defaults matching the Python dataclass. */\nexport function createAuditEvent(f: Partial<AuditEvent> = {}): AuditEvent {\n return {\n schemaVersion: f.schemaVersion ?? '0.3.0',\n timestamp: f.timestamp ?? new Date(),\n runId: f.runId ?? '',\n callId: f.callId ?? '',\n callIndex: f.callIndex ?? 0,\n parentCallId: f.parentCallId ?? null,\n toolName: f.toolName ?? '',\n toolArgs: f.toolArgs ?? {},\n sideEffect: f.sideEffect ?? '',\n environment: f.environment ?? '',\n principal: f.principal ?? null,\n action: f.action ?? AuditAction.CALL_DENIED,\n decisionSource: f.decisionSource ?? null,\n decisionName: f.decisionName ?? null,\n reason: f.reason ?? null,\n hooksEvaluated: f.hooksEvaluated ?? [],\n contractsEvaluated: f.contractsEvaluated ?? [],\n toolSuccess: f.toolSuccess ?? null,\n postconditionsPassed: f.postconditionsPassed ?? null,\n durationMs: f.durationMs ?? 0,\n error: f.error ?? null,\n resultSummary: f.resultSummary ?? null,\n sessionAttemptCount: f.sessionAttemptCount ?? 0,\n sessionExecutionCount: f.sessionExecutionCount ?? 0,\n mode: f.mode ?? 'enforce',\n policyVersion: f.policyVersion ?? null,\n policyError: f.policyError ?? false,\n }\n}\n\n// -- AuditSink ----------------------------------------------------------------\n\nexport interface AuditSink {\n emit(event: AuditEvent): Promise<void>\n}\n\n// -- MarkEvictedError ---------------------------------------------------------\n\n/** Raised when a mark references events evicted from the buffer. */\nexport class MarkEvictedError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'MarkEvictedError'\n }\n}\n\n// -- CompositeSink ------------------------------------------------------------\n\n/** Fan-out sink: emits to all sinks, raises AggregateError on failures. */\nexport class CompositeSink implements AuditSink {\n private readonly _sinks: AuditSink[]\n\n constructor(sinks: AuditSink[]) {\n if (sinks.length === 0) throw new Error('CompositeSink requires at least one sink')\n this._sinks = [...sinks]\n }\n\n get sinks(): AuditSink[] {\n return [...this._sinks]\n }\n\n async emit(event: AuditEvent): Promise<void> {\n const errors: Error[] = []\n for (const sink of this._sinks) {\n try {\n await sink.emit(event)\n } catch (err) {\n errors.push(err instanceof Error ? err : new Error(String(err)))\n }\n }\n if (errors.length > 0) {\n throw new AggregateError(errors, 'CompositeSink: one or more sinks failed')\n }\n }\n}\n\n// -- Shared serialization -----------------------------------------------------\n\nfunction _toPlain(event: AuditEvent): Record<string, unknown> {\n const { timestamp, ...rest } = event\n return { ...rest, timestamp: timestamp.toISOString() }\n}\n\n// -- StdoutAuditSink ----------------------------------------------------------\n\nexport class StdoutAuditSink implements AuditSink {\n private readonly _redaction: RedactionPolicy\n constructor(redaction?: RedactionPolicy | null) {\n this._redaction = redaction ?? new RedactionPolicy()\n }\n async emit(event: AuditEvent): Promise<void> {\n process.stdout.write(JSON.stringify(this._redaction.capPayload(_toPlain(event))) + '\\n')\n }\n}\n\n// -- FileAuditSink ------------------------------------------------------------\n\nexport class FileAuditSink implements AuditSink {\n private readonly _path: string\n private readonly _redaction: RedactionPolicy\n constructor(path: string, redaction?: RedactionPolicy | null) {\n this._path = path\n this._redaction = redaction ?? new RedactionPolicy()\n }\n async emit(event: AuditEvent): Promise<void> {\n const data = this._redaction.capPayload(_toPlain(event))\n await appendFile(this._path, JSON.stringify(data) + '\\n', 'utf-8')\n }\n}\n\n// -- CollectingAuditSink ------------------------------------------------------\n\n/** In-memory ring buffer sink for programmatic inspection. */\nexport class CollectingAuditSink implements AuditSink {\n private _events: AuditEvent[] = []\n private readonly _maxEvents: number\n private _totalEmitted: number = 0\n\n constructor(maxEvents: number = 50_000) {\n if (maxEvents < 1) throw new Error(`max_events must be >= 1, got ${maxEvents}`)\n this._maxEvents = maxEvents\n }\n\n async emit(event: AuditEvent): Promise<void> {\n this._events.push(event)\n this._totalEmitted += 1\n if (this._events.length > this._maxEvents) this._events = this._events.slice(-this._maxEvents)\n }\n\n get events(): AuditEvent[] {\n return [...this._events]\n }\n mark(): number {\n return this._totalEmitted\n }\n\n sinceMark(m: number): AuditEvent[] {\n if (m > this._totalEmitted) {\n throw new Error(`Mark ${m} is ahead of total emitted (${this._totalEmitted})`)\n }\n const evictedCount = this._totalEmitted - this._events.length\n if (m < evictedCount) {\n throw new MarkEvictedError(\n `Mark ${m} references evicted events (buffer starts at ${evictedCount}, max_events=${this._maxEvents})`,\n )\n }\n return [...this._events.slice(m - evictedCount)]\n }\n\n last(): AuditEvent {\n if (this._events.length === 0) throw new Error('No events collected')\n const last = this._events[this._events.length - 1]\n if (!last) throw new Error('No events collected')\n return last\n }\n\n filter(action: AuditAction): AuditEvent[] {\n return this._events.filter((e) => e.action === action)\n }\n\n clear(): void {\n this._events = []\n }\n}\n","/** Pre/Post Conditions — contract types for tool governance. */\n\nimport type { ToolEnvelope } from './envelope.js'\nimport type { Session } from './session.js'\n\n// ---------------------------------------------------------------------------\n// Verdict\n// ---------------------------------------------------------------------------\n\n/** Outcome of a single contract check. */\nexport interface Verdict {\n readonly passed: boolean\n readonly message: string | null\n readonly metadata: Readonly<Record<string, unknown>>\n}\n\n/** Factory methods for Verdict. */\nexport const Verdict = {\n /**\n * Contract passed — tool call is acceptable.\n */\n pass_(): Verdict {\n return Object.freeze({ passed: true, message: null, metadata: Object.freeze({}) })\n },\n\n /**\n * Contract failed with an actionable message (truncated to 500 chars).\n *\n * Make it SPECIFIC and INSTRUCTIVE — the agent uses it to self-correct.\n */\n fail(message: string, metadata: Record<string, unknown> = {}): Verdict {\n const truncated = message.length > 500 ? message.slice(0, 497) + '...' : message\n return Object.freeze({\n passed: false,\n message: truncated,\n metadata: Object.freeze({ ...metadata }),\n })\n },\n}\n\n// ---------------------------------------------------------------------------\n// Contract interfaces — plain objects, not decorators\n// ---------------------------------------------------------------------------\n\n/** Before execution. Safe to deny — tool hasn't run yet. */\nexport interface Precondition {\n readonly contractType?: 'pre'\n readonly tool: string\n readonly check: (envelope: ToolEnvelope) => Verdict | Promise<Verdict>\n readonly when?: ((envelope: ToolEnvelope) => boolean) | null\n}\n\n/**\n * After execution. Observe-and-log.\n *\n * On failure for pure/read: inject context suggesting retry.\n * On failure for write/irreversible: warn only, NO retry coaching.\n */\nexport interface Postcondition {\n readonly contractType: 'post'\n readonly tool: string\n readonly check: (envelope: ToolEnvelope, response: unknown) => Verdict | Promise<Verdict>\n readonly when?: ((envelope: ToolEnvelope) => boolean) | null\n}\n\n/**\n * Cross-turn governance using persisted atomic counters.\n *\n * Session methods are ASYNC. Session contract checks must be async.\n *\n * Example:\n * ```typescript\n * const maxOperations: SessionContract = {\n * check: async (session) => {\n * const count = await session.executionCount();\n * if (count >= 200) {\n * return Verdict.fail(\"Session limit reached.\");\n * }\n * return Verdict.pass_();\n * },\n * };\n * ```\n */\nexport interface SessionContract {\n readonly check: (session: Session) => Verdict | Promise<Verdict>\n}\n","/** Hook interception — before/after tool execution. */\n\nexport const HookResult = {\n ALLOW: 'allow',\n DENY: 'deny',\n} as const\n\nexport type HookResult = (typeof HookResult)[keyof typeof HookResult]\n\nexport interface HookDecision {\n readonly result: HookResult\n readonly reason: string | null\n}\n\nexport const HookDecision = {\n allow(): HookDecision {\n return Object.freeze({ result: HookResult.ALLOW, reason: null })\n },\n\n deny(reason: string): HookDecision {\n const truncated = reason.length > 500 ? reason.slice(0, 497) + '...' : reason\n return Object.freeze({ result: HookResult.DENY, reason: truncated })\n },\n}\n","/**\n * GovernancePipeline -- single source of governance logic.\n *\n * SIZE APPROVAL: This file exceeds 200 lines. It mirrors Python's pipeline.py\n * (485 LOC). PreDecision + PostDecision types + the 5-stage pre/post engine\n * form a single cohesive evaluation flow that would be harder to follow if split.\n */\n\nimport { Verdict } from './contracts.js'\nimport { SideEffect } from './envelope.js'\nimport type { ToolEnvelope } from './envelope.js'\nimport { HookDecision, HookResult } from './hooks.js'\nimport { RedactionPolicy } from './redaction.js'\nimport type { Session } from './session.js'\nimport type { GuardLike } from './internal-contracts.js'\n\n// ---------------------------------------------------------------------------\n// PreDecision\n// ---------------------------------------------------------------------------\n\n/** Result of pre-execution governance evaluation. */\nexport interface PreDecision {\n readonly action: 'allow' | 'deny' | 'pending_approval'\n readonly reason: string | null\n readonly decisionSource: string | null\n readonly decisionName: string | null\n readonly hooksEvaluated: Record<string, unknown>[]\n readonly contractsEvaluated: Record<string, unknown>[]\n readonly observed: boolean\n readonly policyError: boolean\n readonly observeResults: Record<string, unknown>[]\n readonly approvalTimeout: number\n readonly approvalTimeoutEffect: string\n readonly approvalMessage: string | null\n}\n\n/** Create a PreDecision with defaults for omitted fields. */\nexport function createPreDecision(\n partial: Partial<PreDecision> & Pick<PreDecision, 'action'>,\n): PreDecision {\n return {\n action: partial.action,\n reason: partial.reason ?? null,\n decisionSource: partial.decisionSource ?? null,\n decisionName: partial.decisionName ?? null,\n hooksEvaluated: partial.hooksEvaluated ?? [],\n contractsEvaluated: partial.contractsEvaluated ?? [],\n observed: partial.observed ?? false,\n policyError: partial.policyError ?? false,\n observeResults: partial.observeResults ?? [],\n approvalTimeout: partial.approvalTimeout ?? 300,\n approvalTimeoutEffect: partial.approvalTimeoutEffect ?? 'deny',\n approvalMessage: partial.approvalMessage ?? null,\n }\n}\n\n// ---------------------------------------------------------------------------\n// PostDecision\n// ---------------------------------------------------------------------------\n\n/** Result of post-execution governance evaluation. */\nexport interface PostDecision {\n readonly toolSuccess: boolean\n readonly postconditionsPassed: boolean\n readonly warnings: string[]\n readonly contractsEvaluated: Record<string, unknown>[]\n readonly policyError: boolean\n readonly redactedResponse: unknown\n readonly outputSuppressed: boolean\n}\n\n/** Create a PostDecision with defaults for omitted fields. */\nexport function createPostDecision(\n partial: Partial<PostDecision> & Pick<PostDecision, 'toolSuccess'>,\n): PostDecision {\n return {\n toolSuccess: partial.toolSuccess,\n postconditionsPassed: partial.postconditionsPassed ?? true,\n warnings: partial.warnings ?? [],\n contractsEvaluated: partial.contractsEvaluated ?? [],\n policyError: partial.policyError ?? false,\n redactedResponse: partial.redactedResponse ?? null,\n outputSuppressed: partial.outputSuppressed ?? false,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Check if any evaluated contract record has a policy_error in metadata. */\nfunction hasPolicyError(contractsEvaluated: Record<string, unknown>[]): boolean {\n return contractsEvaluated.some((c) => {\n const meta = c['metadata'] as Record<string, unknown> | undefined\n return meta?.['policy_error'] === true\n })\n}\n\n// ---------------------------------------------------------------------------\n// GovernancePipeline\n// ---------------------------------------------------------------------------\n\n/**\n * Orchestrates all governance checks.\n *\n * This is the single source of truth for governance logic.\n * Adapters call preExecute() and postExecute(), then translate\n * the structured results into framework-specific formats.\n */\nexport class GovernancePipeline {\n private readonly _guard: GuardLike\n\n constructor(guard: GuardLike) {\n this._guard = guard\n }\n\n async preExecute(envelope: ToolEnvelope, session: Session): Promise<PreDecision> {\n const hooksEvaluated: Record<string, unknown>[] = []\n const contractsEvaluated: Record<string, unknown>[] = []\n let hasObservedDeny = false\n\n // Pre-fetch session counters in a single batch to reduce HTTP\n // round trips when using ServerBackend. The tool-specific key\n // is included only when a per-tool limit is configured.\n let toolNameForBatch: string | undefined\n if (envelope.toolName in this._guard.limits.maxCallsPerTool) {\n toolNameForBatch = envelope.toolName\n }\n const counters = await session.batchGetCounters({\n includeTool: toolNameForBatch,\n })\n\n // 1. Attempt limit\n const attemptCount = counters['attempts'] ?? 0\n if (attemptCount >= this._guard.limits.maxAttempts) {\n return createPreDecision({\n action: 'deny',\n reason:\n `Attempt limit reached (${this._guard.limits.maxAttempts}). ` +\n 'Agent may be stuck in a retry loop. Stop and reassess.',\n decisionSource: 'attempt_limit',\n decisionName: 'max_attempts',\n hooksEvaluated,\n contractsEvaluated,\n })\n }\n\n // 2. Before hooks (catch exceptions)\n for (const hookReg of this._guard.getHooks('before', envelope)) {\n if (hookReg.when && !hookReg.when(envelope)) {\n continue\n }\n let decision: HookDecision\n try {\n decision = await hookReg.callback(envelope)\n } catch (exc) {\n decision = HookDecision.deny(`Hook error: ${exc}`)\n }\n\n const hookRecord: Record<string, unknown> = {\n name: hookReg.callback.name || 'anonymous',\n result: decision.result,\n reason: decision.reason,\n }\n hooksEvaluated.push(hookRecord)\n\n if (decision.result === HookResult.DENY) {\n return createPreDecision({\n action: 'deny',\n reason: decision.reason,\n decisionSource: 'hook',\n decisionName: hookRecord['name'] as string,\n hooksEvaluated,\n contractsEvaluated,\n policyError: (decision.reason ?? '').includes('Hook error:'),\n })\n }\n }\n\n // 3. Preconditions (catch exceptions)\n for (const contract of this._guard.getPreconditions(envelope)) {\n let verdict: Verdict\n try {\n verdict = await contract.check(envelope)\n } catch (exc) {\n verdict = Verdict.fail(`Precondition error: ${exc}`, {\n policy_error: true,\n })\n }\n\n const contractRecord: Record<string, unknown> = {\n name: contract.name,\n type: 'precondition',\n passed: verdict.passed,\n message: verdict.message,\n }\n if (verdict.metadata && Object.keys(verdict.metadata).length > 0) {\n contractRecord['metadata'] = verdict.metadata\n }\n contractsEvaluated.push(contractRecord)\n\n if (!verdict.passed) {\n // Per-contract observe mode: record but don't deny\n if (contract.mode === 'observe') {\n contractRecord['observed'] = true\n hasObservedDeny = true\n continue\n }\n\n const source = contract.source ?? 'precondition'\n const pe = hasPolicyError(contractsEvaluated)\n\n const effect = contract.effect ?? 'deny'\n if (effect === 'approve') {\n return createPreDecision({\n action: 'pending_approval',\n reason: verdict.message,\n decisionSource: source,\n decisionName: contract.name,\n hooksEvaluated,\n contractsEvaluated,\n policyError: pe,\n approvalTimeout: contract.timeout ?? 300,\n approvalTimeoutEffect: contract.timeoutEffect ?? 'deny',\n approvalMessage: verdict.message,\n })\n }\n\n return createPreDecision({\n action: 'deny',\n reason: verdict.message,\n decisionSource: source,\n decisionName: contract.name,\n hooksEvaluated,\n contractsEvaluated,\n policyError: pe,\n })\n }\n }\n\n // 3.5. Sandbox contracts\n for (const contract of this._guard.getSandboxContracts(envelope)) {\n let verdict: Verdict\n try {\n verdict = await contract.check(envelope)\n } catch (exc) {\n verdict = Verdict.fail(`Sandbox contract error: ${exc}`, {\n policy_error: true,\n })\n }\n\n const contractRecord: Record<string, unknown> = {\n name: contract.name,\n type: 'sandbox',\n passed: verdict.passed,\n message: verdict.message,\n }\n if (verdict.metadata && Object.keys(verdict.metadata).length > 0) {\n contractRecord['metadata'] = verdict.metadata\n }\n contractsEvaluated.push(contractRecord)\n\n if (!verdict.passed) {\n if (contract.mode === 'observe') {\n contractRecord['observed'] = true\n hasObservedDeny = true\n continue\n }\n\n const source = contract.source ?? 'yaml_sandbox'\n const pe = hasPolicyError(contractsEvaluated)\n\n const effect = contract.effect ?? 'deny'\n if (effect === 'approve') {\n return createPreDecision({\n action: 'pending_approval',\n reason: verdict.message,\n decisionSource: source,\n decisionName: contract.name,\n hooksEvaluated,\n contractsEvaluated,\n policyError: pe,\n approvalTimeout: contract.timeout ?? 300,\n approvalTimeoutEffect: contract.timeoutEffect ?? 'deny',\n approvalMessage: verdict.message,\n })\n }\n\n return createPreDecision({\n action: 'deny',\n reason: verdict.message,\n decisionSource: source,\n decisionName: contract.name,\n hooksEvaluated,\n contractsEvaluated,\n policyError: pe,\n })\n }\n }\n\n // 4. Session contracts (catch exceptions)\n for (const contract of this._guard.getSessionContracts()) {\n let verdict: Verdict\n try {\n verdict = await contract.check(session)\n } catch (exc) {\n verdict = Verdict.fail(`Session contract error: ${exc}`, {\n policy_error: true,\n })\n }\n\n const contractRecord: Record<string, unknown> = {\n name: contract.name,\n type: 'session_contract',\n passed: verdict.passed,\n message: verdict.message,\n }\n if (verdict.metadata && Object.keys(verdict.metadata).length > 0) {\n contractRecord['metadata'] = verdict.metadata\n }\n contractsEvaluated.push(contractRecord)\n\n if (!verdict.passed) {\n const source = contract.source ?? 'session_contract'\n const pe = hasPolicyError(contractsEvaluated)\n return createPreDecision({\n action: 'deny',\n reason: verdict.message,\n decisionSource: source,\n decisionName: contract.name,\n hooksEvaluated,\n contractsEvaluated,\n policyError: pe,\n })\n }\n }\n\n // 5. Execution limits (use pre-fetched counters)\n const execCount = counters['execs'] ?? 0\n if (execCount >= this._guard.limits.maxToolCalls) {\n return createPreDecision({\n action: 'deny',\n reason:\n `Execution limit reached (${this._guard.limits.maxToolCalls} calls). ` +\n 'Summarize progress and stop.',\n decisionSource: 'operation_limit',\n decisionName: 'max_tool_calls',\n hooksEvaluated,\n contractsEvaluated,\n })\n }\n\n // Per-tool limits (use pre-fetched counter when available)\n if (envelope.toolName in this._guard.limits.maxCallsPerTool) {\n const toolKey = `tool:${envelope.toolName}`\n const toolCount = counters[toolKey] ?? 0\n const toolLimit = this._guard.limits.maxCallsPerTool[envelope.toolName] ?? 0\n if (toolCount >= toolLimit) {\n return createPreDecision({\n action: 'deny',\n reason: `Per-tool limit: ${envelope.toolName} called ${toolCount} times (limit: ${toolLimit}).`,\n decisionSource: 'operation_limit',\n decisionName: `max_calls_per_tool:${envelope.toolName}`,\n hooksEvaluated,\n contractsEvaluated,\n })\n }\n }\n\n // 6. All checks passed\n const pe = hasPolicyError(contractsEvaluated)\n\n // 7. Observe-mode contract evaluation (never affects the decision)\n const observeResults = await this._evaluateObserveContracts(envelope, session)\n\n return createPreDecision({\n action: 'allow',\n hooksEvaluated,\n contractsEvaluated,\n observed: hasObservedDeny,\n policyError: pe,\n observeResults,\n })\n }\n\n async postExecute(\n envelope: ToolEnvelope,\n toolResponse: unknown,\n toolSuccess: boolean,\n ): Promise<PostDecision> {\n const warnings: string[] = []\n const contractsEvaluated: Record<string, unknown>[] = []\n let redactedResponse: unknown = null\n let outputSuppressed = false\n\n // 1. Postconditions (catch exceptions)\n for (const contract of this._guard.getPostconditions(envelope)) {\n let verdict: Verdict\n try {\n verdict = await contract.check(envelope, toolResponse)\n } catch (exc) {\n verdict = Verdict.fail(`Postcondition error: ${exc}`, {\n policy_error: true,\n })\n }\n\n const contractRecord: Record<string, unknown> = {\n name: contract.name,\n type: 'postcondition',\n passed: verdict.passed,\n message: verdict.message,\n }\n if (verdict.metadata && Object.keys(verdict.metadata).length > 0) {\n contractRecord['metadata'] = verdict.metadata\n }\n contractsEvaluated.push(contractRecord)\n\n if (!verdict.passed) {\n const effect = contract.effect ?? 'warn'\n const contractMode = contract.mode\n const isSafe =\n envelope.sideEffect === SideEffect.PURE || envelope.sideEffect === SideEffect.READ\n\n // Observe mode takes precedence\n if (contractMode === 'observe') {\n contractRecord['observed'] = true\n warnings.push(`\\u26a0\\ufe0f [observe] ${verdict.message}`)\n } else if (effect === 'redact' && isSafe) {\n const patterns = contract.redactPatterns ?? []\n const source = redactedResponse !== null ? redactedResponse : toolResponse\n let text = source != null ? String(source) : ''\n if (patterns.length > 0) {\n for (const pat of patterns) {\n // Python re.sub() replaces ALL occurrences; ensure global flag\n const globalPat = pat.global ? pat : new RegExp(pat.source, pat.flags + 'g')\n text = text.replace(globalPat, '[REDACTED]')\n }\n } else {\n const policy = new RedactionPolicy()\n text = policy.redactResult(text, text.length + 100)\n }\n redactedResponse = text\n warnings.push(`\\u26a0\\ufe0f Content redacted by ${contract.name}.`)\n } else if (effect === 'deny' && isSafe) {\n redactedResponse = `[OUTPUT SUPPRESSED] ${verdict.message}`\n outputSuppressed = true\n warnings.push(`\\u26a0\\ufe0f Output suppressed by ${contract.name}.`)\n } else if ((effect === 'redact' || effect === 'deny') && !isSafe) {\n warnings.push(\n `\\u26a0\\ufe0f ${verdict.message} Tool already executed \\u2014 assess before proceeding.`,\n )\n } else if (isSafe) {\n warnings.push(`\\u26a0\\ufe0f ${verdict.message} Consider retrying.`)\n } else {\n warnings.push(\n `\\u26a0\\ufe0f ${verdict.message} Tool already executed \\u2014 assess before proceeding.`,\n )\n }\n }\n }\n\n // 2. After hooks (catch exceptions)\n for (const hookReg of this._guard.getHooks('after', envelope)) {\n if (hookReg.when && !hookReg.when(envelope)) {\n continue\n }\n try {\n await hookReg.callback(envelope, toolResponse)\n } catch {\n // After hook errors are silently swallowed — they must not affect governance decisions.\n }\n }\n\n // 3. Observe-mode postconditions (from observe_alongside bundles)\n // These never affect the decision — only produce audit findings.\n for (const contract of this._guard.getObservePostconditions(envelope)) {\n let verdict: Verdict\n try {\n verdict = await contract.check(envelope, toolResponse)\n } catch (exc) {\n verdict = Verdict.fail(`Observe-mode postcondition error: ${exc}`, { policy_error: true })\n }\n const record: Record<string, unknown> = {\n name: contract.name,\n type: 'postcondition',\n passed: verdict.passed,\n message: verdict.message,\n observed: true,\n source: contract.source ?? 'yaml_postcondition',\n }\n if (verdict.metadata && Object.keys(verdict.metadata).length > 0) {\n record['metadata'] = verdict.metadata\n }\n contractsEvaluated.push(record)\n if (!verdict.passed) {\n warnings.push(`\\u26a0\\ufe0f [observe] ${verdict.message}`)\n }\n }\n\n // Exclude observe-mode records from the \"real failure\" check —\n // observe-mode failures are logged but should not signal a real failure\n const postconditionsPassed =\n contractsEvaluated.length > 0\n ? contractsEvaluated.every((c) => c['passed'] === true || c['observed'] === true)\n : true\n const pe = hasPolicyError(contractsEvaluated)\n\n return createPostDecision({\n toolSuccess,\n postconditionsPassed,\n warnings,\n contractsEvaluated,\n policyError: pe,\n redactedResponse,\n outputSuppressed,\n })\n }\n\n /**\n * Evaluate observe-mode contracts without affecting the real decision.\n *\n * Observe-mode contracts are identified by mode === \"observe\" on the\n * internal contract. Results are returned as dicts for audit emission\n * but never block calls.\n */\n private async _evaluateObserveContracts(\n envelope: ToolEnvelope,\n session: Session,\n ): Promise<Record<string, unknown>[]> {\n const results: Record<string, unknown>[] = []\n\n // Observe-mode preconditions\n for (const contract of this._guard.getObservePreconditions(envelope)) {\n let verdict: Verdict\n try {\n verdict = await contract.check(envelope)\n } catch (exc) {\n verdict = Verdict.fail(`Observe-mode precondition error: ${exc}`, { policy_error: true })\n }\n\n results.push({\n name: contract.name,\n type: 'precondition',\n passed: verdict.passed,\n message: verdict.message,\n source: contract.source ?? 'yaml_precondition',\n })\n }\n\n // Observe-mode sandbox contracts\n for (const contract of this._guard.getObserveSandboxContracts(envelope)) {\n let verdict: Verdict\n try {\n verdict = await contract.check(envelope)\n } catch (exc) {\n verdict = Verdict.fail(`Observe-mode sandbox error: ${exc}`, { policy_error: true })\n }\n\n results.push({\n name: contract.name,\n type: 'sandbox',\n passed: verdict.passed,\n message: verdict.message,\n source: contract.source ?? 'yaml_sandbox',\n })\n }\n\n // Observe-mode session contracts -- evaluate against the real session\n for (const contract of this._guard.getObserveSessionContracts()) {\n let verdict: Verdict\n try {\n verdict = await contract.check(session)\n } catch (exc) {\n verdict = Verdict.fail(`Observe-mode session contract error: ${exc}`, {\n policy_error: true,\n })\n }\n\n results.push({\n name: contract.name,\n type: 'session_contract',\n passed: verdict.passed,\n message: verdict.message,\n source: contract.source ?? 'yaml_session',\n })\n }\n\n return results\n }\n}\n","/** Session -- atomic counters backed by StorageBackend. */\n\nimport { EdictumConfigError } from './errors.js'\nimport type { StorageBackend } from './storage.js'\n\n// ---------------------------------------------------------------------------\n// BatchGet capability detection\n// ---------------------------------------------------------------------------\n\n/** StorageBackend that also supports batchGet(). */\ninterface BatchCapableBackend extends StorageBackend {\n batchGet(keys: readonly string[]): Promise<Record<string, string | null>>\n}\n\nfunction hasBatchGet(backend: StorageBackend): backend is BatchCapableBackend {\n return 'batchGet' in backend\n}\n\n// ---------------------------------------------------------------------------\n// Input validation\n// ---------------------------------------------------------------------------\n\nconst MAX_ID_LENGTH = 10_000\n\n/**\n * Validate a string used in storage keys: reject empty, control chars.\n * Mirrors _validateToolName logic for any key component.\n */\nfunction _validateStorageKeyComponent(value: string, label: string): void {\n if (!value) {\n throw new EdictumConfigError(`Invalid ${label}: ${JSON.stringify(value)}`)\n }\n if (value.length > MAX_ID_LENGTH) {\n throw new EdictumConfigError(`Invalid ${label}: exceeds ${MAX_ID_LENGTH} characters`)\n }\n for (let i = 0; i < value.length; i++) {\n const code = value.charCodeAt(i)\n if (code < 0x20 || (code >= 0x7f && code <= 0x9f) || code === 0x2028 || code === 0x2029) {\n throw new EdictumConfigError(`Invalid ${label}: ${JSON.stringify(value)}`)\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Session\n// ---------------------------------------------------------------------------\n\n/**\n * Tracks execution state via atomic counters in StorageBackend.\n *\n * All methods are ASYNC because StorageBackend is async.\n *\n * Counter semantics:\n * - attempts: every PreToolUse, including denied (pre-execution)\n * - execs: every PostToolUse (tool actually ran)\n * - tool:{name}: per-tool execution count\n * - consec_fail: resets on success, increments on failure\n */\nexport class Session {\n private readonly _sid: string\n private readonly _backend: StorageBackend\n\n constructor(sessionId: string, backend: StorageBackend) {\n _validateStorageKeyComponent(sessionId, 'session_id')\n this._sid = sessionId\n this._backend = backend\n }\n\n get sessionId(): string {\n return this._sid\n }\n\n /** Increment attempt counter. Called in PreToolUse (before governance). */\n async incrementAttempts(): Promise<number> {\n return await this._backend.increment(`s:${this._sid}:attempts`)\n }\n\n async attemptCount(): Promise<number> {\n return Number((await this._backend.get(`s:${this._sid}:attempts`)) ?? 0)\n }\n\n /** Record a tool execution. Called in PostToolUse. */\n async recordExecution(toolName: string, success: boolean): Promise<void> {\n _validateStorageKeyComponent(toolName, 'tool_name')\n await this._backend.increment(`s:${this._sid}:execs`)\n await this._backend.increment(`s:${this._sid}:tool:${toolName}`)\n\n if (success) {\n await this._backend.delete(`s:${this._sid}:consec_fail`)\n } else {\n await this._backend.increment(`s:${this._sid}:consec_fail`)\n }\n }\n\n async executionCount(): Promise<number> {\n return Number((await this._backend.get(`s:${this._sid}:execs`)) ?? 0)\n }\n\n async toolExecutionCount(tool: string): Promise<number> {\n _validateStorageKeyComponent(tool, 'tool_name')\n return Number((await this._backend.get(`s:${this._sid}:tool:${tool}`)) ?? 0)\n }\n\n async consecutiveFailures(): Promise<number> {\n return Number((await this._backend.get(`s:${this._sid}:consec_fail`)) ?? 0)\n }\n\n /**\n * Pre-fetch multiple session counters in a single backend call.\n *\n * Returns a record with keys: \"attempts\", \"execs\", and optionally\n * \"tool:{name}\" if includeTool is provided.\n *\n * Uses batchGet() on the backend when available (single HTTP round\n * trip for ServerBackend). Falls back to individual get() calls for\n * backends without batchGet support.\n */\n async batchGetCounters(options?: { includeTool?: string }): Promise<Record<string, number>> {\n const keys: string[] = [`s:${this._sid}:attempts`, `s:${this._sid}:execs`]\n const keyLabels: string[] = ['attempts', 'execs']\n\n if (options?.includeTool != null) {\n _validateStorageKeyComponent(options.includeTool, 'tool_name')\n keys.push(`s:${this._sid}:tool:${options.includeTool}`)\n keyLabels.push(`tool:${options.includeTool}`)\n }\n\n let raw: Record<string, string | null>\n\n if (hasBatchGet(this._backend)) {\n raw = await this._backend.batchGet(keys)\n } else {\n raw = {}\n for (const key of keys) {\n raw[key] = await this._backend.get(key)\n }\n }\n\n const result: Record<string, number> = {}\n for (let i = 0; i < keys.length; i++) {\n const label = keyLabels[i] ?? ''\n const key = keys[i] ?? ''\n result[label] = Number(raw[key] ?? 0)\n }\n return result\n }\n}\n","/**\n * Execution logic for Edictum.run() -- governance pipeline with tool execution.\n *\n * Ports Python's _runner.py. Governance pipeline + tool callable execution.\n *\n * SIZE APPROVAL: This file exceeds 200 lines. It mirrors Python's _runner.py\n * (350 LOC). The full run() flow (pre-execute → approval → execute → post-execute\n * → audit) is a single cohesive transaction that would be harder to follow if split.\n */\n\nimport type { Edictum } from './guard.js'\nimport type { AuditAction } from './audit.js'\nimport type { Principal, ToolEnvelope } from './envelope.js'\nimport type { PreDecision } from './pipeline.js'\nimport type { Session } from './session.js'\n\nimport { ApprovalStatus } from './approval.js'\nimport { AuditAction as AA, createAuditEvent } from './audit.js'\nimport { createEnvelope } from './envelope.js'\nimport { EdictumDenied, EdictumToolError } from './errors.js'\nimport { GovernancePipeline } from './pipeline.js'\nimport { Session as SessionClass } from './session.js'\n\n// ---------------------------------------------------------------------------\n// defaultSuccessCheck\n// ---------------------------------------------------------------------------\n\n/**\n * Default heuristic for tool success detection.\n *\n * Matches the heuristic used by all framework adapters:\n * - null/undefined is success\n * - object with is_error truthy is failure\n * - string starting with \"error:\" or \"fatal:\" (case-insensitive) is failure\n * - everything else is success\n */\nexport function defaultSuccessCheck(_toolName: string, result: unknown): boolean {\n if (result == null) {\n return true\n }\n if (typeof result === 'object' && !Array.isArray(result)) {\n const dict = result as Record<string, unknown>\n if (dict['is_error']) {\n return false\n }\n }\n if (typeof result === 'string') {\n const lower = result.slice(0, 7).toLowerCase()\n if (lower.startsWith('error:') || lower.startsWith('fatal:')) {\n return false\n }\n }\n return true\n}\n\n// ---------------------------------------------------------------------------\n// RunOptions\n// ---------------------------------------------------------------------------\n\n/** Options for the run() function beyond the required positional args. */\nexport interface RunOptions {\n readonly sessionId?: string\n readonly environment?: string\n readonly principal?: Principal\n}\n\n// ---------------------------------------------------------------------------\n// _emitRunPreAudit\n// ---------------------------------------------------------------------------\n\nasync function _emitRunPreAudit(\n guard: Edictum,\n envelope: Readonly<ToolEnvelope>,\n session: Session,\n action: AuditAction,\n pre: PreDecision,\n): Promise<void> {\n const event = createAuditEvent({\n action,\n runId: envelope.runId,\n callId: envelope.callId,\n toolName: envelope.toolName,\n toolArgs: guard.redaction.redactArgs(envelope.args) as Record<string, unknown>,\n sideEffect: envelope.sideEffect,\n environment: envelope.environment,\n principal: envelope.principal ? ({ ...envelope.principal } as Record<string, unknown>) : null,\n decisionSource: pre.decisionSource,\n decisionName: pre.decisionName,\n reason: pre.reason,\n hooksEvaluated: pre.hooksEvaluated,\n contractsEvaluated: pre.contractsEvaluated,\n sessionAttemptCount: await session.attemptCount(),\n sessionExecutionCount: await session.executionCount(),\n mode: guard.mode,\n policyVersion: guard.policyVersion,\n policyError: pre.policyError,\n })\n await guard.auditSink.emit(event)\n // TODO: Phase 3 — _emitOtelGovernanceSpan(guard, event)\n}\n\n// ---------------------------------------------------------------------------\n// run\n// ---------------------------------------------------------------------------\n\n/**\n * Framework-agnostic entrypoint for governed tool execution.\n *\n * Creates session, pipeline, envelope. Runs pre-execute governance,\n * handles approval flow, executes the tool, runs post-execute governance,\n * emits audit events, and returns the (potentially redacted) result.\n */\nexport async function run(\n guard: Edictum,\n toolName: string,\n args: Record<string, unknown>,\n toolCallable: (args: Record<string, unknown>) => unknown | Promise<unknown>,\n options?: RunOptions,\n): Promise<unknown> {\n const sessionId = options?.sessionId ?? guard.sessionId\n const session = new SessionClass(sessionId, guard.backend)\n const pipeline = new GovernancePipeline(guard)\n\n // Allow per-call environment override; fall back to guard-level default\n const env = options?.environment ?? guard.environment\n\n // Resolve principal: per-call resolver > static > options\n let principal = options?.principal ?? undefined\n if (principal === undefined) {\n const resolved = guard._resolvePrincipal(toolName, args)\n if (resolved != null) {\n principal = resolved\n }\n }\n\n const envelope = createEnvelope(toolName, args, {\n runId: sessionId,\n environment: env,\n registry: guard.toolRegistry,\n principal: principal ?? null,\n })\n\n // Increment attempts\n await session.incrementAttempts()\n\n // TODO: Phase 3 — start OTel span\n // const span = guard.telemetry.startToolSpan(envelope);\n\n try {\n // TODO: Phase 3 — set policy version on span\n // if (guard.policyVersion) {\n // span.setAttribute(\"edictum.policy_version\", guard.policyVersion);\n // }\n\n // Pre-execute\n const pre = await pipeline.preExecute(envelope, session)\n\n // Handle pending_approval: request approval from backend\n if (pre.action === 'pending_approval') {\n if (guard._approvalBackend == null) {\n // TODO: Phase 3 — span.setError(...)\n throw new EdictumDenied(\n `Approval required but no approval backend configured: ${pre.reason}`,\n pre.decisionSource,\n pre.decisionName,\n )\n }\n\n const principalDict = envelope.principal\n ? ({ ...envelope.principal } as Record<string, unknown>)\n : null\n\n const approvalRequest = await guard._approvalBackend.requestApproval(\n envelope.toolName,\n envelope.args as Record<string, unknown>,\n pre.approvalMessage ?? pre.reason ?? '',\n {\n timeout: pre.approvalTimeout,\n timeoutEffect: pre.approvalTimeoutEffect,\n principal: principalDict,\n },\n )\n\n await _emitRunPreAudit(guard, envelope, session, AA.CALL_APPROVAL_REQUESTED, pre)\n\n const decision = await guard._approvalBackend.waitForDecision(\n approvalRequest.approvalId,\n pre.approvalTimeout,\n )\n\n // Resolve approval: approved, denied, or timeout (with timeout_effect)\n let approved = false\n if (decision.status === ApprovalStatus.TIMEOUT) {\n await _emitRunPreAudit(guard, envelope, session, AA.CALL_APPROVAL_TIMEOUT, pre)\n if (pre.approvalTimeoutEffect === 'allow') {\n approved = true\n }\n } else if (!decision.approved) {\n await _emitRunPreAudit(guard, envelope, session, AA.CALL_APPROVAL_DENIED, pre)\n } else {\n approved = true\n await _emitRunPreAudit(guard, envelope, session, AA.CALL_APPROVAL_GRANTED, pre)\n }\n\n if (approved) {\n // TODO: Phase 3 — guard.telemetry.recordAllowed(envelope)\n if (guard._onAllow) {\n try {\n guard._onAllow(envelope)\n } catch {\n // on_allow callback raised — swallow\n }\n }\n // TODO: Phase 3 — span.setAttribute(\"governance.action\", \"approved\")\n // Skip the normal pre-execution audit/callback logic below —\n // approval-granted path handles its own audit and callbacks.\n } else {\n const denyReason = decision.reason ?? pre.reason ?? ''\n // TODO: Phase 3 — guard.telemetry.recordDenial(envelope, denyReason)\n if (guard._onDeny) {\n try {\n guard._onDeny(envelope, denyReason, pre.decisionName)\n } catch {\n // on_deny callback raised — swallow\n }\n }\n // TODO: Phase 3 — span error attributes\n throw new EdictumDenied(\n decision.reason ?? pre.reason ?? 'denied',\n pre.decisionSource,\n pre.decisionName,\n )\n }\n }\n\n // Determine if this is a real deny or just per-contract observed denials\n const realDeny = pre.action === 'deny' && !pre.observed\n\n // Skip pre-execution audit for approval-granted path (already handled above)\n if (pre.action === 'pending_approval') {\n // Fall through directly to tool execution\n } else if (realDeny) {\n const auditAction = guard.mode === 'observe' ? AA.CALL_WOULD_DENY : AA.CALL_DENIED\n await _emitRunPreAudit(guard, envelope, session, auditAction, pre)\n // TODO: Phase 3 — guard.telemetry.recordDenial(envelope, pre.reason)\n\n if (guard.mode === 'enforce') {\n if (guard._onDeny) {\n try {\n guard._onDeny(envelope, pre.reason ?? '', pre.decisionName)\n } catch {\n // on_deny callback raised — swallow\n }\n }\n // TODO: Phase 3 — span error attributes\n throw new EdictumDenied(pre.reason ?? 'denied', pre.decisionSource, pre.decisionName)\n }\n // observe mode: fall through to execute\n // TODO: Phase 3 — span.setAttribute(\"governance.action\", \"would_deny\")\n } else {\n // Emit CALL_WOULD_DENY for any per-contract observed denials\n for (const cr of pre.contractsEvaluated) {\n if (cr['observed'] && !cr['passed']) {\n const observedEvent = createAuditEvent({\n action: AA.CALL_WOULD_DENY,\n runId: envelope.runId,\n callId: envelope.callId,\n toolName: envelope.toolName,\n toolArgs: guard.redaction.redactArgs(envelope.args) as Record<string, unknown>,\n sideEffect: envelope.sideEffect,\n environment: envelope.environment,\n principal: envelope.principal\n ? ({ ...envelope.principal } as Record<string, unknown>)\n : null,\n decisionSource: 'precondition',\n decisionName: cr['name'] as string,\n reason: cr['message'] as string | null,\n mode: 'observe',\n policyVersion: guard.policyVersion,\n policyError: pre.policyError,\n })\n await guard.auditSink.emit(observedEvent)\n // TODO: Phase 3 — _emitOtelGovernanceSpan(guard, observedEvent)\n }\n }\n\n await _emitRunPreAudit(guard, envelope, session, AA.CALL_ALLOWED, pre)\n // TODO: Phase 3 — guard.telemetry.recordAllowed(envelope)\n if (guard._onAllow) {\n try {\n guard._onAllow(envelope)\n } catch {\n // on_allow callback raised — swallow\n }\n }\n // TODO: Phase 3 — span.setAttribute(\"governance.action\", \"allowed\")\n }\n\n // Emit observe-mode audit events (never affect the real decision)\n for (const sr of pre.observeResults) {\n const observeAction = sr['passed'] ? AA.CALL_ALLOWED : AA.CALL_WOULD_DENY\n const observeEvent = createAuditEvent({\n action: observeAction,\n runId: envelope.runId,\n callId: envelope.callId,\n toolName: envelope.toolName,\n toolArgs: guard.redaction.redactArgs(envelope.args) as Record<string, unknown>,\n sideEffect: envelope.sideEffect,\n environment: envelope.environment,\n principal: envelope.principal\n ? ({ ...envelope.principal } as Record<string, unknown>)\n : null,\n decisionSource: sr['source'] as string | null,\n decisionName: sr['name'] as string | null,\n reason: sr['message'] as string | null,\n mode: 'observe',\n policyVersion: guard.policyVersion,\n })\n await guard.auditSink.emit(observeEvent)\n // TODO: Phase 3 — _emitOtelGovernanceSpan(guard, observeEvent)\n }\n\n // Execute tool\n let result: unknown\n let toolSuccess: boolean\n try {\n // Use the frozen envelope.args snapshot — prevents TOCTOU between\n // governance evaluation and tool execution\n result = toolCallable(envelope.args as Record<string, unknown>)\n // Await if the callable returns a promise\n if (\n result != null &&\n typeof result === 'object' &&\n typeof (result as Promise<unknown>).then === 'function'\n ) {\n result = await (result as Promise<unknown>)\n }\n if (guard._successCheck) {\n toolSuccess = guard._successCheck(toolName, result)\n } else {\n toolSuccess = defaultSuccessCheck(toolName, result)\n }\n } catch (e: unknown) {\n result = String(e)\n toolSuccess = false\n }\n\n // Post-execute\n const post = await pipeline.postExecute(envelope, result, toolSuccess)\n await session.recordExecution(toolName, toolSuccess)\n\n // Emit post-execute audit\n const postAction = toolSuccess ? AA.CALL_EXECUTED : AA.CALL_FAILED\n const postEvent = createAuditEvent({\n action: postAction,\n runId: envelope.runId,\n callId: envelope.callId,\n toolName: envelope.toolName,\n toolArgs: guard.redaction.redactArgs(envelope.args) as Record<string, unknown>,\n sideEffect: envelope.sideEffect,\n environment: envelope.environment,\n principal: envelope.principal ? ({ ...envelope.principal } as Record<string, unknown>) : null,\n toolSuccess,\n postconditionsPassed: post.postconditionsPassed,\n contractsEvaluated: post.contractsEvaluated,\n sessionAttemptCount: await session.attemptCount(),\n sessionExecutionCount: await session.executionCount(),\n mode: guard.mode,\n policyVersion: guard.policyVersion,\n policyError: post.policyError,\n })\n await guard.auditSink.emit(postEvent)\n // TODO: Phase 3 — _emitOtelGovernanceSpan(guard, postEvent)\n\n // TODO: Phase 3 — span tool_success / postconditions_passed attributes\n // TODO: Phase 3 — span OK/error status\n\n if (!toolSuccess) {\n throw new EdictumToolError(String(result))\n }\n\n return post.redactedResponse != null ? post.redactedResponse : result\n } finally {\n // TODO: Phase 3 — span.end()\n }\n}\n"],"mappings":"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","names":["pe"]}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createContractResult,
|
|
3
3
|
createEvaluationResult
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-23XIQZR5.mjs";
|
|
5
5
|
import {
|
|
6
6
|
createEnvelope,
|
|
7
7
|
createPrincipal
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-2YSBMUK5.mjs";
|
|
9
9
|
|
|
10
10
|
// src/dry-run.ts
|
|
11
11
|
function safeTags(metadata) {
|
|
@@ -196,4 +196,4 @@ export {
|
|
|
196
196
|
evaluate,
|
|
197
197
|
evaluateBatch
|
|
198
198
|
};
|
|
199
|
-
//# sourceMappingURL=dry-run-
|
|
199
|
+
//# sourceMappingURL=dry-run-JTRNTZA5.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dry-run.ts"],"sourcesContent":["/**\n * Dry-run evaluation logic for Edictum.evaluate() and evaluateBatch().\n *\n * Ports Python's _dry_run.py. Exhaustive contract evaluation without\n * tool execution. Session contracts are skipped (no session state).\n *\n * SIZE APPROVAL: This file exceeds 200 lines. It mirrors Python's\n * _dry_run.py (205 LOC). evaluate() + evaluateBatch() are a cohesive unit.\n */\n\nimport type { Edictum } from './guard.js'\nimport type { Principal } from './envelope.js'\n\nimport { createEnvelope, createPrincipal } from './envelope.js'\n\n/** Safely extract tags array from verdict metadata. */\nfunction safeTags(metadata: Readonly<Record<string, unknown>> | null | undefined): string[] {\n if (!metadata) return []\n const raw = metadata['tags']\n if (!Array.isArray(raw)) return []\n return raw.filter((t): t is string => typeof t === 'string')\n}\nimport { createContractResult, createEvaluationResult } from './evaluation.js'\nimport type { ContractResult, EvaluationResult } from './evaluation.js'\n\n// ---------------------------------------------------------------------------\n// EvaluateOptions\n// ---------------------------------------------------------------------------\n\n/** Options for the evaluate() function. */\nexport interface EvaluateOptions {\n readonly principal?: Principal\n readonly output?: string\n readonly environment?: string\n}\n\n// ---------------------------------------------------------------------------\n// evaluate\n// ---------------------------------------------------------------------------\n\n/**\n * Dry-run evaluation of a tool call against all matching contracts.\n *\n * Unlike run(), this never executes the tool and evaluates all\n * matching contracts exhaustively (no short-circuit on first deny).\n * Session contracts are skipped (no session state in dry-run).\n */\nexport async function evaluate(\n guard: Edictum,\n toolName: string,\n args: Record<string, unknown>,\n options?: EvaluateOptions,\n): Promise<EvaluationResult> {\n const env = options?.environment ?? guard.environment\n const envelope = createEnvelope(toolName, args, {\n environment: env,\n principal: options?.principal ?? null,\n registry: guard.toolRegistry,\n })\n\n const contracts: ContractResult[] = []\n const denyReasons: string[] = []\n const warnReasons: string[] = []\n\n // Evaluate all matching preconditions (exhaustive, no short-circuit)\n for (const contract of guard.getPreconditions(envelope)) {\n const contractId = contract.name ?? 'unknown'\n let verdict\n try {\n verdict = await contract.check(envelope)\n } catch (exc: unknown) {\n const contractResult = createContractResult({\n contractId,\n contractType: 'precondition',\n passed: false,\n message: `Precondition error: ${exc}`,\n policyError: true,\n })\n contracts.push(contractResult)\n denyReasons.push(contractResult.message ?? '')\n continue\n }\n\n const tags = safeTags(verdict.metadata)\n const isObserved = contract.mode === 'observe' && !verdict.passed\n const pe = verdict.metadata ? ((verdict.metadata['policy_error'] as boolean) ?? false) : false\n\n const contractResult = createContractResult({\n contractId,\n contractType: 'precondition',\n passed: verdict.passed,\n message: verdict.message,\n tags,\n observed: isObserved,\n policyError: pe,\n })\n contracts.push(contractResult)\n\n if (!verdict.passed && !isObserved) {\n denyReasons.push(verdict.message ?? '')\n }\n }\n\n // Evaluate sandbox contracts (exhaustive, no short-circuit)\n for (const contract of guard.getSandboxContracts(envelope)) {\n const contractId = contract.name ?? 'unknown'\n let verdict\n try {\n verdict = await contract.check(envelope)\n } catch (exc: unknown) {\n const contractResult = createContractResult({\n contractId,\n contractType: 'sandbox',\n passed: false,\n message: `Sandbox error: ${exc}`,\n policyError: true,\n })\n contracts.push(contractResult)\n denyReasons.push(contractResult.message ?? '')\n continue\n }\n\n const tags = safeTags(verdict.metadata)\n const isObserved = contract.mode === 'observe' && !verdict.passed\n const pe = verdict.metadata ? ((verdict.metadata['policy_error'] as boolean) ?? false) : false\n\n const contractResult = createContractResult({\n contractId,\n contractType: 'sandbox',\n passed: verdict.passed,\n message: verdict.message,\n tags,\n observed: isObserved,\n policyError: pe,\n })\n contracts.push(contractResult)\n\n if (!verdict.passed && !isObserved) {\n denyReasons.push(verdict.message ?? '')\n }\n }\n\n // Evaluate postconditions only when output is provided\n if (options?.output != null) {\n for (const contract of guard.getPostconditions(envelope)) {\n const contractId = contract.name ?? 'unknown'\n let verdict\n try {\n verdict = await contract.check(envelope, options.output)\n } catch (exc: unknown) {\n const contractResult = createContractResult({\n contractId,\n contractType: 'postcondition',\n passed: false,\n message: `Postcondition error: ${exc}`,\n policyError: true,\n })\n contracts.push(contractResult)\n // Route to correct bucket based on effect — deny-effect errors\n // must produce deny verdict, not warn\n const excEffect = contract.effect ?? 'warn'\n if (excEffect === 'deny') {\n denyReasons.push(contractResult.message ?? '')\n } else {\n warnReasons.push(contractResult.message ?? '')\n }\n continue\n }\n\n const tags = safeTags(verdict.metadata)\n const isObserved = contract.mode === 'observe' && !verdict.passed\n const pe = verdict.metadata ? ((verdict.metadata['policy_error'] as boolean) ?? false) : false\n const effect = contract.effect ?? 'warn'\n\n const contractResult = createContractResult({\n contractId,\n contractType: 'postcondition',\n passed: verdict.passed,\n message: verdict.message,\n tags,\n observed: isObserved,\n effect,\n policyError: pe,\n })\n contracts.push(contractResult)\n\n if (!verdict.passed && !isObserved) {\n if (effect === 'deny') {\n denyReasons.push(verdict.message ?? '')\n } else {\n warnReasons.push(verdict.message ?? '')\n }\n }\n }\n }\n\n // Compute verdict: deny > warn > allow\n let verdictStr: string\n if (denyReasons.length > 0) {\n verdictStr = 'deny'\n } else if (warnReasons.length > 0) {\n verdictStr = 'warn'\n } else {\n verdictStr = 'allow'\n }\n\n return createEvaluationResult({\n verdict: verdictStr,\n toolName,\n contracts,\n denyReasons,\n warnReasons,\n contractsEvaluated: contracts.length,\n policyError: contracts.some((r) => r.policyError),\n })\n}\n\n// ---------------------------------------------------------------------------\n// BatchCall\n// ---------------------------------------------------------------------------\n\n/** A single call in an evaluateBatch() batch. */\nexport interface BatchCall {\n readonly tool: string\n readonly args?: Record<string, unknown>\n readonly principal?: Record<string, unknown>\n readonly output?: string | Record<string, unknown>\n readonly environment?: string\n}\n\n// ---------------------------------------------------------------------------\n// evaluateBatch\n// ---------------------------------------------------------------------------\n\n/**\n * Evaluate a batch of tool calls. Thin wrapper over evaluate().\n */\nexport async function evaluateBatch(\n guard: Edictum,\n calls: BatchCall[],\n): Promise<EvaluationResult[]> {\n const results: EvaluationResult[] = []\n for (const call of calls) {\n const callArgs = call.args ?? {}\n\n // Convert principal dict to Principal object\n let principal: Principal | undefined\n if (call.principal != null && typeof call.principal === 'object') {\n principal = createPrincipal({\n role: (call.principal['role'] as string | undefined) ?? undefined,\n userId: (call.principal['userId'] as string | undefined) ?? undefined,\n ticketRef: (call.principal['ticketRef'] as string | undefined) ?? undefined,\n claims:\n typeof call.principal['claims'] === 'object' &&\n call.principal['claims'] != null &&\n !Array.isArray(call.principal['claims'])\n ? (call.principal['claims'] as Record<string, unknown>)\n : {},\n })\n }\n\n // Normalize output: if object, JSON.stringify\n let output: string | undefined\n if (call.output != null) {\n if (typeof call.output === 'object') {\n try {\n output = JSON.stringify(call.output)\n } catch {\n output = '[unserializable output]'\n }\n } else {\n output = call.output\n }\n }\n\n results.push(\n await evaluate(guard, call.tool, callArgs, {\n principal,\n output,\n environment: call.environment,\n }),\n )\n }\n return results\n}\n"],"mappings":"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","names":["contractResult"]}
|