@visiq/claude-cowork-harness 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 VisIQ Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,87 @@
1
+ # @visiq/claude-cowork-harness
2
+
3
+ VisIQ governance for **Claude Cowork** — the agent surface in the Claude desktop app.
4
+
5
+ Cowork is built on Claude Code, but it runs a session in one of two places, and the
6
+ difference decides what governance is even possible. This package covers both, and
7
+ labels each honestly.
8
+
9
+ | Surface | Where it runs | What VisIQ does | How |
10
+ |---|---|---|---|
11
+ | **Host-local** | The desktop app spawns its own `claude` natively on your machine | **Enforcement** — action + retrieval governance, `deny` blocks the tool call before it runs | Claude Code hooks (`SessionStart`, `PreToolUse`, `PostToolUse`) |
12
+ | **VM sandbox** | The session runs in the app's Linux guest | **Monitoring** — every tool call, its arguments, and the model, reported to the platform | Tailing the host-side per-session audit stream |
13
+
14
+ > **The sandbox surface cannot be enforced.** A sandboxed session's config dir lives
15
+ > inside the guest and carries no `settings.json`, so no host hook can fire for it.
16
+ > The audit stream this package tails is written *after* a tool has already run.
17
+ > Nothing in this package reports a block on that surface, and `status` says so.
18
+
19
+ ## Install
20
+
21
+ ```bash
22
+ npm install -g @visiq/claude-cowork-harness
23
+
24
+ # 1. Host-local enforcement (writes ~/.claude/settings.json)
25
+ visiq-claude-cowork install
26
+
27
+ # 2. Credentials — shared with @visiq/claude-code-harness
28
+ visiq-claude-code configure --api-key <key> --agent-id <id>
29
+
30
+ # 3. Sandbox monitoring (optional, long-running)
31
+ visiq-claude-cowork monitor
32
+ ```
33
+
34
+ Restart the Claude desktop app after installing. Then:
35
+
36
+ ```bash
37
+ visiq-claude-cowork status
38
+ ```
39
+
40
+ ```
41
+ [VisIQ] Claude Cowork harness 0.1.0 — status
42
+ credentials: resolved
43
+ agent id: agent_01H…
44
+ hooks: installed — /Users/you/.claude/settings.json
45
+ Claude Cowork (host-local): ENFORCED (PreToolUse deny blocks)
46
+ Claude Cowork (VM sandbox): monitor-only — 3 session(s), 5 audit log(s)
47
+ ```
48
+
49
+ ## Commands
50
+
51
+ | Command | Purpose |
52
+ |---|---|
53
+ | `install [--settings <path>] [--command <cmd>]` | Wire the governance hooks (host-local enforcement) |
54
+ | `uninstall [--settings <path>]` | Remove them, leaving your own hooks untouched |
55
+ | `status` | What is installed, detected, and actually covered |
56
+ | `monitor [--once] [--interval <ms>]` | Tail the sandbox audit stream (monitor-only) |
57
+
58
+ ## Why `install` wires the Claude Code dispatcher
59
+
60
+ Host-local Cowork sessions read the **same** `~/.claude/settings.json` as the Claude
61
+ Code CLI, so this package installs the shared `visiq-claude-code-hook` dispatcher
62
+ rather than a second one. Two dispatchers over one file would double-evaluate every
63
+ tool call and the two installers would fight over the same JSON. If you already run
64
+ `@visiq/claude-code-harness`, your host-local Cowork sessions are **already governed** —
65
+ this package adds the Cowork surface labelling and the sandbox monitor.
66
+
67
+ ## Fail posture
68
+
69
+ Agent-side, this harness **fails open** by default (owner decision 2026-07-15): if
70
+ VisIQ itself cannot answer — no credentials, endpoint unreachable, no bundle — the
71
+ agent keeps working and the failure is reported loudly. A policy `deny` always blocks.
72
+ Opt into strict fail-closed with `VISIQ_FAIL_MODE=closed`.
73
+
74
+ The monitor is fail-open by construction: sessions are created and deleted under it
75
+ constantly, so a vanished directory, a truncated write, or a corrupt line is skipped,
76
+ counted, and reported — never fatal.
77
+
78
+ ## What is captured
79
+
80
+ From the sandbox audit stream, per tool call: tool name (including fully-qualified
81
+ `mcp__*` tools), tool arguments, model, session/tool-call ids, sub-agent parentage, and
82
+ the observation timestamp. Each observation is stamped with the surface it came from
83
+ and `mode: "monitor"`.
84
+
85
+ ## License
86
+
87
+ See [LICENSE](./LICENSE).
@@ -0,0 +1,6 @@
1
+ var Sn="CLAUDE_CODE_HOST_PLATFORM",In=["/Claude/claude-code/","\\Claude\\claude-code\\","/Claude.app/"],En=/^\/sessions\/[^/]+\/mnt\/\.claude(\/|$)/;function Cn(e){if(e.configDir&&En.test(e.configDir))return!0;let t=e.env?.[Sn];return typeof t=="string"&&t.length>0}function xn(e){return(e.processPaths??[]).some(t=>In.some(n=>t.includes(n)))}function Tn(e){return(e.processPaths??[]).some(t=>/(^|[/\\])claude(\.exe)?$/.test(t))}function No(e){return Cn(e)?"cowork_vm":xn(e)?"cowork_desktop":Tn(e)?"claude_code_cli":"unknown"}function Oo(e){return e==="claude_code_cli"||e==="cowork_desktop"}function Ro(e){return e==="cowork_desktop"||e==="cowork_vm"}function $o(e){switch(e){case"claude_code_cli":return"Claude Code CLI";case"cowork_desktop":return"Claude Cowork (host-local)";case"cowork_vm":return"Claude Cowork (VM sandbox)";default:return"unknown"}}function Do(e=process,t=[]){let n=[...t];e.argv?.[1]&&n.push(e.argv[1]),e.execPath&&n.push(e.execPath);let r=e.env??{},i=r.CLAUDE_CONFIG_DIR;return{processPaths:n,env:r,platform:e.platform,...i&&i.length>0?{configDir:i}:{}}}var we="local-agent-mode-sessions",Lo="claude-code-sessions";function Nn(e){let{homeDir:t,platform:n,env:r={}}=e;if(n==="darwin")return`${t}/Library/Application Support/Claude`;if(n==="win32"){let a=r.APPDATA;return a?`${a}\\Claude`:`${t}\\AppData\\Roaming\\Claude`}let i=r.XDG_CONFIG_HOME;return i?`${i}/Claude`:`${t}/.config/Claude`}function On(e,t,...n){let r=e==="win32"?"\\":"/";return[t,...n].join(r)}function Po(e){return On(e.platform,Nn(e),we)}function Ae(e){let t=e.split(/[/\\]+/).filter(o=>o.length>0),n=t.lastIndexOf(we);if(n===-1||t.length<n+4)return null;let[r,i,a]=t.slice(n+1,n+4);return Rn(a)?{accountId:r,orgId:i,sessionKey:a}:null}function Rn(e){return/^local_[0-9a-fA-F-]{8,}$/.test(e)}function $n(e){return/^audit\d*\.jsonl$/.test(e)}function Dn(e){let t=/^audit(\d*)\.jsonl$/.exec(e);return t?t[1]?Number.parseInt(t[1],10):0:null}function ke(e){return e.filter($n).map(t=>({name:t,idx:Dn(t)??0})).sort((t,n)=>n.idx-t.idx).map(t=>t.name)}var jo=8388608;function Se(e){let t=[],n=0,r=!1,i=e.lastIndexOf(`
2
+ `),a,o;i===-1?(a="",o=e):(a=e.slice(0,i),o=e.slice(i+1)),Buffer.byteLength(o,"utf8")>8388608&&(o="",r=!0);for(let s of a.split(`
3
+ `)){let l=s.trim();if(l.length!==0)try{t.push(JSON.parse(l))}catch{n+=1}}return{records:t,remainder:o,skipped:n,truncated:r}}function w(e){return typeof e=="string"&&e.length>0?e:void 0}function W(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:null}function Mn(e){let t=W(e);if(!t)return[];let n=w(t.type),r=w(t.session_id)??"",i=w(t.uuid)??"",a=w(t._audit_timestamp);if(n==="result")return[{kind:"session_result",uuid:i,sessionId:r,timestamp:a}];if(n!=="assistant"&&n!=="user")return[];let o=W(t.message),s=o?.content;if(!Array.isArray(s))return[];let l=w(o?.model),c=w(t.parent_tool_use_id),u=[];for(let h of s){let f=W(h);if(!f)continue;let m=w(f.type);if(n==="assistant"&&m==="tool_use"){let g=w(f.name),_=w(f.id);if(!g||!_)continue;u.push({kind:"tool_call",uuid:i,sessionId:r,toolUseId:_,toolName:g,toolInput:f.input,model:l,parentToolUseId:c,timestamp:a})}else if(n==="user"&&m==="tool_result"){let g=w(f.tool_use_id);if(!g)continue;u.push({kind:"tool_result",uuid:i,sessionId:r,toolUseId:g,isError:f.is_error===!0,timestamp:a})}}return u}function Ie(e){return e.flatMap(t=>Mn(t))}function H(e){return e.kind==="session_result"?`result:${e.sessionId}:${e.uuid}`:`${e.kind}:${e.sessionId}:${e.uuid}:${e.toolUseId}`}var Ee=5e3;function M(){return{cursors:{},seen:[]}}function Ce(e,t,n,r){let i=e.cursors[t];if(!i)return{offset:0,remainder:"",restarted:!1};let a=r!==void 0&&i.identity!==void 0&&i.identity!==r;return n<i.offset||a?{offset:0,remainder:"",restarted:!0}:{offset:i.offset,remainder:i.remainder,restarted:!1}}function xe(e,t,n){let r=Se(n.carriedRemainder+n.chunk),i=Ie(r.records),a=new Set(e.seen),o=[],s=0;for(let u of i){let h=H(u);if(a.has(h)){s+=1;continue}a.add(h),o.push(u)}let l=[...e.seen,...o.map(H)];return{state:{cursors:{...e.cursors,[t]:{offset:n.startOffset+n.bytesRead,remainder:r.remainder,...n.identity!==void 0?{identity:n.identity}:{}}},seen:Te(l)},events:o,duplicates:s,skipped:r.skipped,truncated:r.truncated}}function Te(e){return e.length<=Ee?[...e]:e.slice(e.length-Ee)}function Ne(e){if(!e||typeof e!="object"||Array.isArray(e))return M();let t=e,n={},r=t.cursors;if(r&&typeof r=="object"&&!Array.isArray(r))for(let[a,o]of Object.entries(r)){if(!o||typeof o!="object")continue;let s=o,l=typeof s.offset=="number"&&s.offset>=0?s.offset:0,c=typeof s.remainder=="string"?s.remainder:"",u=typeof s.identity=="string"?s.identity:void 0;n[a]={offset:l,remainder:c,...u?{identity:u}:{}}}let i=Array.isArray(t.seen)?t.seen.filter(a=>typeof a=="string"):[];return{cursors:n,seen:Te(i)}}var Oe="visiq-claude-code-hook";var Re="WebFetch|WebSearch|Read|Grep|Glob|LSP|NotebookRead|ListMcpResourcesTool|ReadMcpResourceTool|mcp__.*",Ln=[{event:"SessionStart",matcher:""},{event:"PreToolUse",matcher:"*"},{event:"PostToolUse",matcher:Re}];function L(e,t){return!!e.hooks?.some(n=>typeof n.command=="string"&&(n.command.includes("visiq-claude-code")||t!==void 0&&n.command===t))}function Pn(e,t){return{matcher:e,hooks:[{type:"command",command:t,timeout:30}]}}function Fn(e,t=Oe){let n={...e},r={...n.hooks??{}};for(let{event:i,matcher:a}of Ln){let o=(Array.isArray(r[i])?r[i]:[]).filter(s=>!L(s,t));r[i]=[...o,Pn(a,t)]}return n.hooks=r,n}function jn(e,t){let n={...e};if(!n.hooks)return n;let r={};for(let[i,a]of Object.entries(n.hooks)){let o=(Array.isArray(a)?a:[]).filter(s=>!L(s,t));o.length>0&&(r[i]=o)}return n.hooks=r,n}function Bn(e){let{hooks:t}=e;return t?Object.values(t).some(n=>(Array.isArray(n)?n:[]).some(r=>L(r))):!1}import{readFile as Za}from"node:fs/promises";import{homedir as dn}from"node:os";import{join as le,isAbsolute as Ja,resolve as Qa}from"node:path";import{mkdir as io,readFile as ao,writeFile as oo,stat as Es}from"node:fs/promises";import{createHash as so}from"node:crypto";import{join as hn}from"node:path";import{z as d}from"zod";import*as A from"node:os";import{randomUUID as Ho}from"node:crypto";var E=1,$e="X-VisIQ-SDK",De="X-VisIQ-Dialect",Me="unknown";function C(e,t=1){return{[$e]:e&&e.length>0?e:Me,[De]:String(t)}}var Le="interceptor_source",Un=d.enum(["enforce","audit","off"]),zn=d.enum(["closed","open"]),Pe=d.enum(["enforce","monitor","off"]),qn=d.object({apiKey:d.string().min(1,"apiKey is required"),agentId:d.string().min(1,"agentId is required"),endpoint:d.string().url().optional(),mode:Un.optional(),timeoutMs:d.number().int().positive().optional(),hitlTimeoutMs:d.number().int().positive().optional(),failBehavior:zn.optional()}),Vo=d.object({agent_id:d.string().min(1),target_app:d.string().min(1),action:d.string().min(1),context:d.record(d.unknown()).optional(),session_id:d.string().min(1).max(255).optional(),action_schema_id:d.string().min(1).max(128).optional(),telemetry:d.record(d.unknown()).optional()}),Gn=d.object({field:d.string().optional(),pattern:d.string().optional(),replacement:d.string().optional(),mode:d.enum(["full","partial","email"]).optional(),keepFirst:d.number().optional(),keepLast:d.number().optional(),maskChar:d.string().optional()}),Vn=d.object({decision_id:d.string().min(1),decision:d.enum(["permit","deny","approval_required","mask"]),reason:d.string().optional(),rule_code:d.string().nullable().optional(),enforced:d.boolean().optional(),agent_mode:Pe.optional(),arg_redaction_rules:d.array(Gn).optional(),plane:d.string().nullable().optional(),operation:d.string().nullable().optional(),is_retrieval:d.boolean().optional(),metadata:d.record(d.unknown()).optional()}),Wn=d.object({field:d.string().min(1),operator:d.enum(["equals","in","not_equals","not_in","glob","gt","lt","gte","lte","contains","not_contains"]),value:d.union([d.string(),d.number(),d.array(d.string())])}),Hn=d.object({id:d.string().min(1),rule_code:d.string().default(""),name:d.string().min(1),description:d.string().nullable().default(null),effect:d.enum(["allow","deny","hitl","mask"]),resource_type:d.string().min(1),rego_source:d.string().default(""),target_app:d.string().nullable().default(null),action_pattern:d.string().nullable().default(null),conditions:d.array(Wn).default([]),priority:d.number().int().default(0)}),Kn=d.object({version:d.string().min(1),agent_mode:Pe.optional(),rules:d.array(Hn),no_coverage:d.object({no_coverage_defaults:d.record(d.string()),autopilot_enabled:d.boolean(),enduser_hitl_enabled:d.boolean(),hitl_timeout_seconds:d.number()}).optional()}),Yn=2e3,Zn=e=>new RegExp("^\\p{White_Space}*$","u").test(e)||e.trim().length===0;function Jn(e){let t=e.rules.filter(n=>Zn(n.rego_source)).map(n=>n.id);return t.length>0&&console.warn(`[VISIQ] ${t.length} bundle rule(s) carry an EMPTY rego body and will be evaluated as an UNCONDITIONAL PERMIT credited to their own rule id: ${t.join(", ")}. If any of these is meant to deny, it is not denying. Fix the rule body at the control plane; the SDK cannot tell an intentional stub from a dropped column.`),t}var Fe=class{config;originalFetch;constructor(e,t){this.config=e,this.originalFetch=t}versionHeaders(){return C(this.config.sdkVersion,this.config.sdkDialect)}async evaluate(e){let t=new AbortController,n=setTimeout(()=>t.abort(),this.config.timeoutMs),r;try{r=await this.originalFetch(`${this.config.endpoint}/allow/evaluate`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`,...this.versionHeaders()},body:JSON.stringify(e),signal:t.signal})}finally{clearTimeout(n)}if(!r.ok)throw new Error(`ALLOW evaluate request failed: HTTP ${r.status} ${r.statusText}`);let i=await r.json();return Vn.parse(i)}async fetchBundle(){let e=this.config.agentId?`?agent_id=${encodeURIComponent(this.config.agentId)}`:"",t=`${this.config.endpoint}/allow/rules/bundle${e}`,n=new AbortController,r=setTimeout(()=>n.abort(),this.config.timeoutMs),i;try{i=await this.originalFetch(t,{method:"GET",headers:{Authorization:`Bearer ${this.config.apiKey}`,Accept:"application/json",...this.versionHeaders()},signal:n.signal})}finally{clearTimeout(r)}if(!i.ok)throw new Error(`ALLOW rules/bundle fetch failed: HTTP ${i.status} ${i.statusText}`);let a=await i.json(),o=Kn.parse(a);return Jn(o),o}async sendTelemetry(e){if(e.length===0)return;let t=`${this.config.endpoint}/allow/telemetry`,n=await this.originalFetch(t,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`,...this.versionHeaders()},body:JSON.stringify({decisions:e})});if(!n.ok)throw new Error(`ALLOW telemetry delivery failed: HTTP ${n.status} ${n.statusText}`)}async sendCognition(e,t){if(t.length===0)return;let n=`${this.config.endpoint}/allow/cognition`,r=await this.originalFetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`,...this.versionHeaders()},body:JSON.stringify({...e?{session:e}:{},beats:t})});if(!r.ok)throw new Error(`ALLOW cognition delivery failed: HTTP ${r.status} ${r.statusText}`)}async reportExecutionResult(e,t,n){let r=`${this.config.endpoint}/allow/execution-events`;try{let i=await this.originalFetch(r,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`,...this.versionHeaders()},body:JSON.stringify({decision_id:e,result:t,details:n})});i.ok||console.warn(`[ALLOW] Execution result report failed: HTTP ${i.status}`)}catch(i){console.warn("[ALLOW] Execution result report failed:",i)}}async registerEnvironment(e){if(!this.config.agentId)return;let t=`${this.config.endpoint}/allow/agents/register`;try{let n=await this.originalFetch(t,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`,...this.versionHeaders()},body:JSON.stringify({agent_id:this.config.agentId,os:e.os,hostname:e.hostname,ip:e.ip,username:e.username,...this.config.harnessKind?{kind:this.config.harnessKind}:{},...e.agent_type?{agent_type:e.agent_type}:{},...e.model?{model:e.model}:{},...e.systemPrompt?{system_prompt:e.systemPrompt}:{},...e.toolSchemas&&e.toolSchemas.length>0?{tool_schemas:e.toolSchemas}:{}})});n.ok||console.warn(`[ALLOW] Agent registration failed: HTTP ${n.status} ${n.statusText}`)}catch(n){console.warn("[ALLOW] Agent registration failed:",n)}}async reportToolSurface(e){if(!this.config.agentId||e.length===0)return;let t=`${this.config.endpoint}/allow/agents/tools`;try{let n=await this.originalFetch(t,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`,...this.versionHeaders()},body:JSON.stringify({agent_id:this.config.agentId,tools:e})});n.ok||console.warn(`[ALLOW] Tool-surface report failed: HTTP ${n.status} ${n.statusText}`)}catch(n){console.warn("[ALLOW] Tool-surface report failed:",n)}}async waitForApproval(e){if(!e)throw new Error("waitForApproval: decisionId must be a non-empty string");let t=Date.now()+this.config.hitlTimeoutMs;for(;Date.now()<t;){let n=new AbortController,r=setTimeout(()=>n.abort(),this.config.timeoutMs),i;try{i=await this.originalFetch(`${this.config.endpoint}/v1/allow/decisions/${encodeURIComponent(e)}`,{method:"GET",headers:{Authorization:`Bearer ${this.config.apiKey}`,...this.versionHeaders()},signal:n.signal})}finally{clearTimeout(r)}if(!i.ok)throw new Error(`ALLOW decisions poll failed: HTTP ${i.status} ${i.statusText}`);let a=await i.json();if(typeof a!="object"||a===null)throw new Error("ALLOW decisions poll returned unexpected non-object response");let o=a,s=o.hitl_result;if(s==="approved")return{decision_id:e,decision:"permit",reason:"Approved by human reviewer"};if(s==="rejected")return{decision_id:e,decision:"deny",reason:typeof o.reason=="string"?o.reason:"Rejected by human reviewer"};if(s==="timeout"||s==="expired")return{decision_id:e,decision:"deny",reason:"HITL approval timed out"};await Qn(Yn)}return{decision_id:e,decision:"deny",reason:"HITL approval timed out"}}};function Qn(e){return new Promise(t=>setTimeout(t,e))}function K(){let e={};try{let t=`${A.platform()} ${A.release()}`.trim();t&&(e.os=t)}catch{}try{let t=A.hostname();t&&(e.hostname=t)}catch{}try{let{username:t}=A.userInfo();t&&(e.username=t)}catch{}try{let t=Xn();t&&(e.ip=t)}catch{}return e}function Xn(){let e=A.networkInterfaces();for(let t of Object.keys(e))for(let n of e[t]??[])if((n.family==="IPv4"||n.family===4)&&!n.internal&&n.address)return n.address}import{z as p}from"zod";import{createHash as er}from"crypto";import{createHash as Nr}from"crypto";var je=new Map;function Be(e){return e.map(t=>t.trim()).filter(t=>t.length>0&&t!=="true")}function Y(e){let t=er("sha256").update(e).digest("hex"),n=je.get(t);if(n)return n;let r=new Map,i=[],a=e.split(`
4
+ `).map(l=>tr(l)).filter(l=>l.trim().length>0),o=0;for(;o<a.length;){let l=a[o].trim();if(l.startsWith("package ")||l.startsWith("import ")){o++;continue}let c=l.match(/^default\s+(\w+)\s*:?=\s*(.+)$/);if(c){let f=c[1],m=c[2].trim();r.set(f,T(m)),o++;continue}let u=l.match(/^(\w+)\s*:?=\s*(.+?)(?:\s+if)?\s*\{(.*)$/);if(u){let f=u[1],m=u[2].trim(),g=u[3].trim(),_=[];if(g&&g!=="}"){let I=g.endsWith("}")?g.slice(0,-1).trim():g;I&&_.push(I),g.endsWith("}")||(o++,o=P(a,o,_))}else g==="}"||(o++,o=P(a,o,_));let b=Ue(_);i.push({variable:f,value:T(m),conditions:b,rawConditions:Be(_)}),o++;continue}let h=l.match(/^(\w+)(?:\s+if)?\s*\{(.*)$/);if(h){let f=h[1],m=h[2].trim(),g=[];if(m&&m!=="}"){let b=m.endsWith("}")?m.slice(0,-1).trim():m;b&&g.push(b),m.endsWith("}")||(o++,o=P(a,o,g))}else m==="}"||(o++,o=P(a,o,g));let _=Ue(g);i.push({variable:f,value:"true",conditions:_,rawConditions:Be(g)}),o++;continue}o++}let s={defaults:r,rules:i};return je.set(t,s),s}function tr(e){let t=!1,n="";for(let r=0;r<e.length;r++){let i=e[r];if(t)i===n&&e[r-1]!=="\\"&&(t=!1);else if(i==='"'||i==="'")t=!0,n=i;else if(i==="#")return e.slice(0,r)}return e}function P(e,t,n){let r=1,i=t;for(;i<e.length&&r>0;){let a=e[i].trim();for(let o of a)o==="{"&&r++,o==="}"&&r--;if(r>0)n.push(a),i++;else{let o=a.slice(0,a.lastIndexOf("}")).trim();return o&&n.push(o),i}}return i}function T(e){return e.startsWith('"')&&e.endsWith('"')||e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function nr(e){return e.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\/g,"\\")}function Ue(e){let t=[];for(let n of e){let r=n.split(";").map(i=>i.trim()).filter(i=>i.length>0);for(let i of r){let a=lr(i);a&&t.push(a)}}return t}var Z=/"(?:[^"\\]|\\.)*"|-?\d+(?:\.\d+)?|true|false/,rr=new RegExp(`^(${Z.source})\\s+in\\s+((?:input|data)[^\\s]*)$`),ir=new RegExp(`^(${Z.source})\\s*==\\s*((?:input|data)\\S*)$`),ar=/^([^\s=!]+)\s*==\s*(.+)$/,or=/^([^\s=!]+)\s*!=\s*(.+)$/,Jo=new RegExp(`^(?:${Z.source})$`);var sr=/^regex\.match\(\s*("(?:[^"\\]|\\.)*")\s*,\s*((?:input|data)[^\s)]*)\s*\)$/;function lr(e){let t=!1,n=e.trim();if(n.startsWith("not ")&&(t=!0,n=n.slice(4).trim()),n==="true"||n==="false")return{type:"literal_bool",negated:t,field:"",value:n==="true"};if(n.includes("[_]"))return{type:"truthy",negated:!1,field:j,value:e.trim()};let r=n.match(/^count\(([^)]+)\)\s*(>=|<=|>|<)\s*(\d+)$/);if(r)return{type:"count_gt",negated:t,field:r[1].trim(),operator:r[2],value:parseInt(r[3],10)};let i=n.match(/^startswith\(([^,]+),\s*"([^"]*)"\)$/);if(i)return{type:"startswith",negated:t,field:i[1].trim(),value:i[2]};let a=n.match(/^endswith\(([^,]+),\s*"([^"]*)"\)$/);if(a)return{type:"endswith",negated:t,field:a[1].trim(),value:a[2]};let o=n.match(/^contains\(([^,]+),\s*"([^"]*)"\)$/);if(o)return{type:"contains",negated:t,field:o[1].trim(),value:o[2]};let s=n.match(sr);if(s)return{type:"regex_match",negated:t,field:s[2].trim(),value:nr(s[1])};let l=n.match(rr);if(l)return{type:"array_includes",negated:t,field:l[2].trim(),value:Ke(l[1])};let c=n.match(/^([^\s]+)\s+in\s+(\[.*\])$/);if(c){let _=pr(c[2]);if(_!==null)return{type:"in_set",negated:t,field:c[1].trim(),values:_}}let u=n.match(/^([^\s=!<>]+)\s*(>=|<=|>|<)\s*(-?\d+(?:\.\d+)?)$/);if(u)return{type:"comparison",negated:t,field:u[1].trim(),operator:u[2],value:parseFloat(u[3])};let h=n.match(ir);if(h)return{type:"equality",negated:t,field:h[2].trim(),value:T(h[1].trim())};let f=n.match(ar);if(f)return{type:"equality",negated:t,field:f[1].trim(),value:T(f[2].trim())};let m=n.match(or);if(m)return{type:"inequality",negated:t,field:m[1].trim(),value:T(m[2].trim())};let g=n.match(/^(input(?:\.[a-zA-Z0-9_]+|\["[^"]+"\]|\['[^']+'\])+)$/);return g?{type:"truthy",negated:t,field:g[1].trim()}:{type:"truthy",negated:!1,field:j,value:e.trim()}}var j="__unrecognized_condition_forces_deny__";var cr=/[A-Za-z_][A-Za-z0-9_.]*\s*\(/;function He(e){let t=[];for(let n of e.rules)for(let r of n.conditions)typeof r.field=="string"&&r.field!==j&&cr.test(r.field)&&t.push(r.field);return t}var ur=["input.normalized.","input.normalized["];function dr(e){let t=new Set;for(let n of e.rules)for(let r of n.conditions){let{field:i}=r;typeof i!="string"||i===j||ur.some(a=>i.startsWith(a))&&t.add(i)}return[...t].sort()}function Ke(e){let t=e.trim();return t==="true"?!0:t==="false"?!1:/^-?\d+(?:\.\d+)?$/.test(t)?parseFloat(t):t.startsWith('"')&&t.endsWith('"')||t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1):t}function pr(e){let t=e.trim().replace(/^\[/,"").replace(/\]$/,"").trim();if(t.length===0)return[];let n=[],r="",i=!1,a="";for(let s=0;s<t.length;s++){let l=t[s];i?(r+=l,l===a&&t[s-1]!=="\\"&&(i=!1)):l==='"'||l==="'"?(r+=l,i=!0,a=l):l===","?(n.push(r.trim()),r=""):r+=l}if(i)return null;r.trim().length>0&&n.push(r.trim());let o=[];for(let s of n){let l=s.startsWith('"')&&s.endsWith('"')&&s.length>=2||s.startsWith("'")&&s.endsWith("'")&&s.length>=2,c=/^-?\d+(?:\.\d+)?$/.test(s);if(!l&&!c&&!(s==="true"||s==="false"))return null;o.push(Ke(s))}return o}var Qo=new RegExp("^\\p{White_Space}*$","u");var fr=["tier1","tier2","tier3"];function Ye(e){return typeof e=="string"&&fr.includes(e)}var mr=["read_only","transactional","data_processor","external_comms","code_exec","privileged"],hr=["internal","customer_facing","experimental","third_party"],Ze=[...mr,...hr];function gr(e){return typeof e=="string"&&Ze.includes(e)}function Je(e){let t=new Set;for(let n of e)gr(n)&&t.add(n);return Ze.filter(n=>t.has(n))}var Qe=["read_only","record_create","record_update","record_delete","data_export","data_share","data_subject_request","consent_change","funds_transfer","funds_disbursement","payroll_run","trade_execution","ledger_mutation","credit_decision","decision_adverse","account_restriction","account_closure","card_management","purchase_commitment","vendor_management","deal_management","pricing_change","contract_execution","legal_hold","regulatory_filing","personnel_action","employment_termination","compensation_change","campaign_send","content_publish","inventory_adjustment","order_fulfillment","account_servicing","credential_reset","access_grant","permission_change","credential_management","auth_policy_change","security_config_change","logging_change","alert_management","code_change","infrastructure_provision","deployment_change","communication_send","other"],_r=["version_control","payments","crm","communication","cloud_infra","identity","data_warehouse","ticketing","hr","finance_erp","storage","database","other"],yr=["production","staging","development","test"],br=["security","engineering","finance","legal","compliance","hr","sales","marketing","support","operations","executive"];function vr(e){if(typeof e!="string"&&typeof e!="number")return null;let t=String(e).trim().replace(/([a-z0-9])([A-Z])/g,"$1_$2").toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_+|_+$/g,"");return t.length>0?t:null}var ze={github:"version_control",gitlab:"version_control",bitbucket:"version_control",stripe:"payments",adyen:"payments",braintree:"payments",paypal:"payments",square:"payments",salesforce:"crm",hubspot:"crm",pipedrive:"crm",slack:"communication",teams:"communication",twilio:"communication",sendgrid:"communication",mailgun:"communication",gmail:"communication",outlook:"communication",zoom:"communication",aws:"cloud_infra",gcp:"cloud_infra",azure:"cloud_infra",okta:"identity",auth0:"identity",entra:"identity",onelogin:"identity",duo:"identity",snowflake:"data_warehouse",bigquery:"data_warehouse",databricks:"data_warehouse",redshift:"data_warehouse",jira:"ticketing",zendesk:"ticketing",servicenow:"ticketing",freshdesk:"ticketing",linear:"ticketing",workday:"hr",bamboohr:"hr",gusto:"hr",netsuite:"finance_erp",quickbooks:"finance_erp",sap:"finance_erp",xero:"finance_erp",s3:"storage",gcs:"storage",dropbox:"storage",box:"storage",postgres:"database",postgresql:"database",mysql:"database",mongodb:"database",redis:"database"};function wr(e){let t=vr(e);return t===null?"other":ze[t]??ze[t.replace(/_/g,"")]??"other"}function Xe(e,t){let n={...e};if(t.targetApp!==void 0&&t.targetApp!==null){let r=n.context&&typeof n.context=="object"&&!Array.isArray(n.context)?{...n.context}:{};r.app_category===void 0&&(r.app_category=wr(t.targetApp)),n.context=r}return n}var qe=["pii","phi","pci","financial","biometric","genetic","location","communications","children","credentials","special_category_gdpr"],Ar=["read","write","delete","share","export","decide","execute"],Ge=["none","low","medium","high","critical"],kr=["public","internal","confidential","restricted","credentials","api_key","private_key","password","secret","token","pan","full_pan","card_number","track_data","cvv","cvc","ssn","tax_id","national_id","passport","drivers_license","identity_document","document_number","kyc_document","bank_account","account_number","routing_number","iban","account_balance","customer_financial","credit_score","net_worth","income","financial_profile","employee_pii","payroll","compensation","material_nonpublic","pre_release_earnings","mnpi","attorney_client","legal_hold","privileged","special_category_gdpr","gdpr_special_category","biometric","ethnicity","political_opinion","health_special","religion"],Sr={action_class:Qe,operation:Ar,"context/app_category":_r,"context/environment":yr,"context/actor_function":br,"read/classification":kr,"read/data_categories":qe,"read/data_sensitivity":Ge,"write/data_categories":qe,"write/data_sensitivity":Ge};function et(e){if(e===null||typeof e!="object")return[];let t=e,n=new Set,r=(i,a,o)=>{let s=Array.isArray(a)?a:[a];for(let l of s)typeof l!="string"||l.length===0||o.includes(l)||n.add(`${i}=${l}`)};for(let[i,a]of Object.entries(Sr)){Object.prototype.hasOwnProperty.call(t,i)&&r(i,t[i],a);let o=i.indexOf("/");if(o===-1)continue;let s=t[i.slice(0,o)];if(s!==null&&typeof s=="object"&&!Array.isArray(s)){let l=i.slice(o+1),c=s;Object.prototype.hasOwnProperty.call(c,l)&&r(i,c[l],a)}}return[...n].sort()}var Ve=64,Ir=64,N={retrieved_data_categories:[],retrieved_classifications:[],taint:[],action_classes:[],action_counts:{},denied_count:0,inhibited_count:0,event_count:0,target_apps:[]};function tt(){return{retrieved_data_categories:[],retrieved_classifications:[],taint:[],action_classes:[],action_counts:{},denied_count:0,inhibited_count:0,event_count:0,target_apps:[]}}var Er=new Set(["deny","approval_required","escalate"]);function x(e,t){if(t.length===0)return[...e];let n=new Set(e);for(let i of t)n.add(i);let r=[...n].sort();return r.length>Ve?r.slice(0,Ve):r}function We(e){return e?e.filter(t=>typeof t=="string"&&t.length>0):[]}function F(e){return typeof e=="string"&&e.length>0?e:null}function nt(e,t){let n=We(t.data_categories),r=F(t.classification),i=We(t.taint),a=F(t.action_class),o=a&&Qe.includes(a)?a:null,s=F(t.target_app),l=F(t.decision),c={...e.action_counts};if(o)if(o in c)c[o]=(c[o]??0)+1;else if(Object.keys(c).length<Ir)c[o]=1;else{let u=Object.keys(c).sort(),h=u[u.length-1];h!==void 0&&o<h&&(delete c[h],c[o]=1)}return{retrieved_data_categories:x(e.retrieved_data_categories,n),retrieved_classifications:x(e.retrieved_classifications,r?[r]:[]),taint:x(e.taint,i),action_classes:x(e.action_classes,o?[o]:[]),action_counts:c,denied_count:e.denied_count+(l==="deny"?1:0),inhibited_count:e.inhibited_count+(l&&Er.has(l)?1:0),event_count:e.event_count+1,target_apps:x(e.target_apps,s?[s]:[])}}var rt="generic",it=[{id:"finance_accounting",name:"Finance & Accounting",icon:"Landmark",description:"Payments, invoicing, ledgers, transactions, refunds, financial reporting, SOX/AML/KYC controls."},{id:"hr",name:"Human Resources",icon:"Users",description:"Employee records, payroll, hiring/recruiting, benefits, personnel actions and PII of staff."},{id:"engineering",name:"Engineering",icon:"Code",description:"Source code, build/deploy pipelines, infrastructure changes, production systems and developer tooling."},{id:"it_security",name:"IT & Security",icon:"ShieldCheck",description:"Credentials, secrets, access control, configuration, threat/exfiltration prevention and security operations."},{id:"legal",name:"Legal",icon:"Scale",description:"Contracts, NDAs, litigation, counsel communications and legal-hold material."},{id:"privacy_compliance",name:"Privacy & Compliance",icon:"BadgeCheck",description:"GDPR/CCPA/HIPAA, consent, data-subject rights, special-category data and regulatory data handling."},{id:"sales",name:"Sales",icon:"TrendingUp",description:"CRM, leads, deals, quotes, pipeline and customer commercial relationships."},{id:"marketing",name:"Marketing",icon:"Megaphone",description:"Campaigns, content, brand, social channels and prospect/audience data."},{id:"operations",name:"Operations",icon:"Cog",description:"Business operations, logistics, internal workflows, vendor/ops tooling and process automation."},{id:"customer_support",name:"Customer Support",icon:"LifeBuoy",description:"Support tickets, customer communications, account servicing and help-desk actions."},{id:"procurement",name:"Procurement",icon:"ShoppingCart",description:"Purchasing, supplier management, purchase orders, sourcing and spend approvals."},{id:rt,name:"Generic",icon:"Shapes",description:"Catch-all for cross-cutting rules or rules that do not fit a specific function. Assign when no specific function clearly applies."}],Cr=it.map(e=>e.id),Xo=new Map(it.map(e=>[e.id,e])),es=new Set(Cr);function at(e){return Array.isArray(e)&&e.length>0?[...e]:[rt]}var xr=/^[a-z][a-z0-9_]*$/;function ot(e){if(!Array.isArray(e))return[];let t=[],n=new Set;for(let r of e)typeof r=="string"&&xr.test(r)&&!n.has(r)&&(n.add(r),t.push(r));return t}var Tr=["narrow","moderate","broad","unbounded","unknown"];function st(e){return typeof e=="string"&&Tr.includes(e)}function lt(e){return e==="open"||e==="closed"?e:null}var Or=["tool_name","function","name","action"];function B(e,t,n){if(Array.isArray(e)){if(e.length===0){n.push([`${t}[]`,void 0]);return}for(let r of e)B(r,`${t}[]`,n);return}if(e!==null&&typeof e=="object"){let r=Object.entries(e);if(r.length===0){t&&n.push([t,void 0]);return}for(let[i,a]of r)B(a,t?`${t}.${i}`:i,n);return}t&&n.push([t,e])}function Rr(e){let t=[];return B(e,"",t),[...new Set(t.map(([n])=>n))].sort()}function $r(e){let t=e.slice(e.lastIndexOf(".")+1);return t.endsWith("[]")?t.slice(0,-2):t}function Dr(e){if(typeof e!="string"&&typeof e!="number")return null;let t=String(e).trim().toLowerCase();return t.length>0?t:null}function Mr(e,t={}){if(t.discriminatorField===null)return null;let n=[];B(e,"",n);let r=t.discriminatorField?[t.discriminatorField]:t.discriminatorFields??Or;for(let i of r){let a=null;for(let[o,s]of n){if($r(o)!==i)continue;let l=Dr(s);l!==null&&(a===null||o<a.path)&&(a={path:o,value:l})}if(a)return a.value}return null}function ct(e,t={}){let n=Nr("sha256").update(Rr(e).join(",")).digest("hex").slice(0,16),r=Mr(e,t);return r!==null?`${n}:${r}`:n}var Lr=["action","retrieval","delegation"];function Pr(e){return typeof e=="string"&&Lr.includes(e)}var Fr=new Set(["rules"]);function ut(e){if(typeof e.id!="string"||typeof e.vendor_id!="string")return null;let t=typeof e.origin_table=="string"?e.origin_table:"";if(!Fr.has(t))return null;let n=Array.isArray(e.applies_to)?e.applies_to.filter(Pr):[];return n.length===0?null:{id:e.id,originTable:t,vendorId:e.vendor_id,name:typeof e.name=="string"?e.name:"",description:typeof e.description=="string"?e.description:null,regoSource:typeof e.rego_source=="string"?e.rego_source:null,priority:typeof e.priority=="number"?e.priority:0,enabled:e.enabled===!0,appliesTo:n,targetApp:typeof e.target_app=="string"?e.target_app:null,actionPattern:typeof e.action_pattern=="string"?e.action_pattern:null,trustTier:typeof e.trust_tier=="string"?e.trust_tier:null,surface:typeof e.surface=="string"?e.surface:null,principalExclusions:Array.isArray(e.principal_exclusions)?e.principal_exclusions.filter(r=>typeof r=="string"):null,bypassActive:e.bypass_active===!0,bypassReason:typeof e.bypass_reason=="string"?e.bypass_reason:null,bypassExpiresAt:typeof e.bypass_expires_at=="string"?e.bypass_expires_at:null,redactionSpec:e.redaction_spec??null,failClosedOnEmptySpec:e.fail_closed_on_empty_spec===!0,hitlFallback:e.hitl_fallback==="mask"?"mask":"deny",ruleCode:typeof e.rule_code=="string"?e.rule_code:null}}function dt(e){let t={retrieval:new Set,action:new Set,delegation:new Set};for(let n of e){if(!n.enabled||n.bypassActive)continue;let r=n.regoSource;if(typeof r!="string"||r.length===0)continue;let i;try{i=Y(r)}catch{continue}let a=dr(i);if(a.length!==0)for(let o of n.appliesTo){let s=t[o];if(s)for(let l of a)s.add(`${n.id}: ${l}`)}}return{retrieval:[...t.retrieval].sort(),action:[...t.action].sort(),delegation:[...t.delegation].sort()}}import{z as q}from"zod";var jr=/[^\u0000-\u007F]/,xt=new RegExp("^\\p{Nd}$","u"),Br=new RegExp("^\\p{Pd}$","u"),Ur=/^[\p{Zs}\p{Zl}\p{Zp}]$/u,zr=/^[\p{Default_Ignorable_Code_Point}\p{Cf}]$/u,qr=new Map([[8722,"-"],[8259,"-"],[8231,"-"]]),Tt="<invisible>",pt=new Map;function Gr(e){let t=String.fromCodePoint(e).normalize("NFKC");if(t.length===1&&t>="0"&&t<="9")return t;let n=e;for(let i=0;i<256&&n>0&&xt.test(String.fromCodePoint(n-1));i++)n--;let r=(e-n)%10;return String.fromCharCode(48+r)}function Vr(e){if(e<128)return null;let t=pt.get(e);if(t!==void 0)return t;let n=(()=>{if(e>=65281&&e<=65374)return String.fromCharCode(e-65248);let r=String.fromCodePoint(e);return xt.test(r)?Gr(e):Br.test(r)||qr.has(e)?"-":Ur.test(r)?" ":zr.test(r)?Tt:null})();return pt.set(e,n),n}function Wr(e){if(typeof e!="string"||e.length===0||!jr.test(e))return[];let t=ft(e,"as-separator");if(t===null)return[];let n=ft(e,"as-nothing");return n===null||n.text===t.text?[t]:[t,n]}function ft(e,t){let n=[],r=[],i=!1;for(let a=0;a<e.length;){let o=e.codePointAt(a),s=o>65535?2:1,l=Vr(o);if(l===null){for(let c=0;c<s;c++)n.push(e[a+c]),r.push(a+c);a+=s;continue}if(i=!0,l===Tt){t==="as-separator"&&(n.push(" "),r.push(a)),a+=s;continue}n.push(l),r.push(a),a+=s}return i?(r.push(e.length),{label:t,text:n.join(""),offsets:Int32Array.from(r)}):null}var Nt="[REDACTED]",ee=[{name:"private_key",re:/-----BEGIN (?:[A-Z]+ )?PRIVATE KEY-----[\s\S]*?-----END (?:[A-Z]+ )?PRIVATE KEY-----/g},{name:"jwt",re:/\beyJ[A-Za-z0-9_-]{6,}\.[A-Za-z0-9_-]{6,}\.[A-Za-z0-9_-]{6,}\b/g},{name:"aws_access_key",re:/\b(?:AKIA|ASIA|AGPA|AIDA|AROA|ANPA|ANVA|AIPA)[0-9A-Z]{16}\b/g},{name:"github_token",re:/\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36}\b|\bgithub_pat_[A-Za-z0-9_]{22,}\b/g},{name:"slack_token",re:/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g},{name:"stripe_secret",re:/\b(?:sk|rk)_live_[A-Za-z0-9]{16,}\b/g},{name:"google_api_key",re:/\bAIza[0-9A-Za-z_-]{35}\b/g},{name:"llm_api_key",re:/\bsk-(?:ant-|proj-)?[A-Za-z0-9_-]{20,}\b/g},{name:"bearer_token",re:/\bBearer\s+[A-Za-z0-9._~+/=-]{20,}/g},{name:"connection_string",re:/\b(?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis|amqps?):\/\/[^\s/@:]+:[^\s/@:]+@[^\s'"]+/g},{name:"us_ein",re:/\b\d{2}-\d{7}\b/g},{name:"ssn",re:/\b\d{3}[- ]\d{2}[- ]\d{4}\b/g},{name:"email",re:/(?<![A-Za-z0-9._%+-])[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g},{name:"in_pan_tax",re:/\b[A-Z]{3}[ABCFGHJLPTE][A-Z]\d{4}[A-Z]\b/g},{name:"swift_bic",re:/\b[A-Z]{6}[A-Z0-9]{2}(?:[A-Z0-9]{3})?\b/g},{name:"date_of_birth",re:/\b(?:\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])|(?:0[1-9]|[12]\d|3[01])[/.](?:0[1-9]|1[0-2])[/.]\d{4}|(?:0[1-9]|1[0-2])\/(?:0[1-9]|[12]\d|3[01])\/\d{4})\b/g},{name:"us_phone",re:/\b(?:\+?1[ .-]?)?\(?\d{3}\)?[ .-]?\d{3}[ .-]?\d{4}\b/g},{name:"ipv4",re:/\b(?:(?:25[0-5]|2[0-4]\d|1?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|1?\d?\d)\b/g},{name:"mac_address",re:/\b(?:[0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}\b/g}],rs=ee.map(({name:e,re:t})=>({name:e,source:t.source})),Hr="(?:(?<![A-Za-z0-9])(?=[A-Za-z0-9])|(?<=[A-Za-z0-9])(?![A-Za-z0-9]))";function Kr(e){return Ot(e,Hr)}function Ot(e,t){let n="",r=!1;for(let i=0;i<e.length;i++){let a=e[i];if(a==="\\"){if(!r&&e[i+1]==="b"){n+=t,i++;continue}n+=a+(e[i+1]??""),i++;continue}a==="["?r=!0:a==="]"&&(r=!1),n+=a}return n}function Rt(e){return new RegExp(Kr(e.source),e.flags)}var Yr="(?:\\b|_)";function Zr(e){return Ot(e,Yr)}var Jr=/^\(\?<!\[((?:[^\]\\]|\\.)*)\]\)/;function Qr(e){let t=Jr.exec(e);return t?`(?:^|[^${t[1]}])${e.slice(t[0].length)}`:e}function Q(e){if(!/^\d+$/.test(e))return!1;let t=0,n=!1;for(let r=e.length-1;r>=0;r--){let i=e.charCodeAt(r)-48;n&&(i*=2,i>9&&(i-=9)),t+=i,n=!n}return t%10===0}function Xr(e){let t=e.replace(/\s/g,"").toUpperCase();if(!/^[A-Z]{2}\d{2}[A-Z0-9]{10,30}$/.test(t))return!1;let n=t.slice(4)+t.slice(0,4),r=0;for(let i=0;i<n.length;i++){let a=n[i],o=a>="A"&&a<="Z"?String(a.charCodeAt(0)-55):a;for(let s=0;s<o.length;s++)r=(r*10+(o.charCodeAt(s)-48))%97}return r===1}function ei(e){if(!/^\d{9}$/.test(e))return!1;let t=[3,7,1,3,7,1,3,7,1],n=0;for(let r=0;r<9;r++)n+=(e.charCodeAt(r)-48)*t[r];return n%10===0}var ti=[[0,1,2,3,4,5,6,7,8,9],[1,2,3,4,0,6,7,8,9,5],[2,3,4,0,1,7,8,9,5,6],[3,4,0,1,2,8,9,5,6,7],[4,0,1,2,3,9,5,6,7,8],[5,9,8,7,6,0,4,3,2,1],[6,5,9,8,7,1,0,4,3,2],[7,6,5,9,8,2,1,0,4,3],[8,7,6,5,9,3,2,1,0,4],[9,8,7,6,5,4,3,2,1,0]],ni=[[0,1,2,3,4,5,6,7,8,9],[1,5,7,6,2,8,3,0,9,4],[5,8,0,3,7,9,6,1,4,2],[8,9,1,6,0,4,3,5,2,7],[9,4,5,3,1,2,6,8,7,0],[4,2,8,6,5,7,3,9,0,1],[2,7,9,3,8,0,6,4,1,5],[7,0,4,6,9,1,3,2,5,8]];function ri(e){if(!/^\d+$/.test(e))return!1;let t=0,n=e.split("").reverse();for(let r=0;r<n.length;r++)t=ti[t][ni[r%8][n[r].charCodeAt(0)-48]];return t===0}function ii(e){if(!/^\d{11}$/.test(e)||/^(\d)\1{10}$/.test(e))return!1;let t=n=>{let r=0;for(let a=0;a<n;a++)r+=(e.charCodeAt(a)-48)*(n+1-a);let i=r*10%11;return i===10?0:i};return t(9)===e.charCodeAt(9)-48&&t(10)===e.charCodeAt(10)-48}function ai(e){if(!/^\d{10}$/.test(e))return!1;let t=0;for(let i=0;i<9;i++)t+=(e.charCodeAt(i)-48)*(10-i);let n=11-t%11,r=n===11?0:n;return r!==10&&r===e.charCodeAt(9)-48}var oi=[1,4,3,7,5,8,6,9,10];function si(e){if(!/^\d{8,9}$/.test(e))return!1;let t=0;for(let n=0;n<e.length;n++)t+=(e.charCodeAt(n)-48)*oi[n];return t%11===0}var li="TRWAGMYFPDXBNJZSQVHLCKE";function ci(e){let t=e.replace(/[\s.-]/g,"").toUpperCase(),n=/^([XYZ]?)(\d{7,8})([A-Z])$/.exec(t);if(!n)return!1;let[,r,i,a]=n;if(r===""&&i.length!==8||r!==""&&i.length!==7)return!1;let o=r===""?i:String("XYZ".indexOf(r))+i;return li[Number(o)%23]===a}var ui=new Set(["BG","GB","NK","KN","TN","NT","ZZ"]);function di(e){let t=e.replace(/[\s-]/g,"").toUpperCase();return/^[ABCEGHJ-PRSTW-Z][ABCEGHJ-NPRSTW-Z]\d{6}[A-D]$/.test(t)?!ui.has(t.slice(0,2)):!1}var te=[{name:"pan",re:/\d(?:[ -]?\d){12,18}/g,normalize:e=>e.replace(/[ -]/g,""),validate:e=>e.length>=13&&e.length<=19&&Q(e)},{name:"iban",re:/\b[A-Z]{2}\d{2}(?:[ ]?[A-Z0-9]){10,30}\b/g,normalize:e=>e.replace(/\s/g,"").toUpperCase(),validate:Xr},{name:"aba_routing",re:/\b\d{9}\b/g,normalize:e=>e,validate:ei},{name:"uk_nino",re:/\b[A-Za-z]{2} ?\d{2} ?\d{2} ?\d{2} ?[A-Da-d]\b/g,normalize:e=>e.replace(/\s/g,"").toUpperCase(),validate:(e,t)=>t!==void 0&&t===t.toLowerCase()?!1:di(e)},{name:"in_aadhaar",re:/\b[2-9]\d{3}[ -]?\d{4}[ -]?\d{4}\b/g,normalize:e=>e.replace(/[\s-]/g,""),validate:e=>e.length===12&&ri(e)},{name:"br_cpf",re:/\b\d{3}\.?\d{3}\.?\d{3}-?\d{2}\b/g,normalize:e=>e.replace(/[.-]/g,""),validate:ii},{name:"es_dni_nie",re:/\b(?:[XYZxyz]-?)?(?:\d{7,8}|\d{1,2}[. ]\d{3}[. ]\d{3})[ -]?[A-Za-z]\b/g,normalize:e=>e.replace(/[\s.-]/g,"").toUpperCase(),validate:ci},{name:"ca_sin",re:/\b\d{3}[ -]?\d{3}[ -]?\d{3}\b/g,normalize:e=>e.replace(/[\s-]/g,""),validate:e=>e.length===9&&Q(e)},{name:"uk_nhs_number",re:/\b\d{3}[ -]?\d{3}[ -]?\d{4}\b/g,normalize:e=>e.replace(/[\s-]/g,""),validate:ai},{name:"au_tfn",re:/\b\d{3}[ -]?\d{3}[ -]?\d{2,3}\b/g,normalize:e=>e.replace(/[\s-]/g,""),validate:si}],pi=Object.fromEntries([...ee,...te].map(e=>[e.name,e.re.source])),y=pi,is=te.map(e=>e.name),$t=ee.map(({name:e,re:t})=>({name:e,re:Rt(t)})),Dt=te.map(e=>({...e,re:Rt(e.re)})),as=[...$t,...Dt].map(({name:e,re:t})=>({name:String(e),source:t.source})),ne=["private_key","jwt","aws_access_key","github_token","slack_token","stripe_secret","google_api_key","llm_api_key","bearer_token","connection_string","pan","iban","aba_routing","us_ein","swift_bic","ssn","uk_nino","in_aadhaar","in_pan_tax","br_cpf","es_dni_nie","ca_sin","uk_nhs_number","au_tfn","email","us_phone","date_of_birth","ipv4","mac_address"],fi={private_key:{id:"private_key",label:"Private keys (PEM)",description:"PEM-encoded private keys (RSA / EC / EdDSA / OpenSSH).",category:"secret",example:`-----BEGIN PRIVATE KEY-----
5
+ MIIEv\u2026
6
+ -----END PRIVATE KEY-----`,template:{pattern:y.private_key,mode:"full"},defaultEnabled:!0},jwt:{id:"jwt",label:"JWT / bearer tokens",description:"JSON Web Tokens (base64url header.payload.signature).",category:"secret",example:"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.dBjftJeZ4CVP",template:{pattern:y.jwt,mode:"full"},defaultEnabled:!0},aws_access_key:{id:"aws_access_key",label:"AWS access key IDs",description:"AWS access / identity key ids (AKIA / ASIA / AROA \u2026).",category:"secret",example:"AKIAIOSFODNN7EXAMPLE",template:{pattern:y.aws_access_key,mode:"full"},defaultEnabled:!0},github_token:{id:"github_token",label:"GitHub tokens",description:"GitHub personal / OAuth tokens (classic ghp_\u2026 + fine-grained).",category:"secret",example:"ghp_0123456789abcdef0123456789abcdef0123",template:{pattern:y.github_token,mode:"full"},defaultEnabled:!0},slack_token:{id:"slack_token",label:"Slack tokens",description:"Slack bot / user / app tokens (xoxb- / xoxp- \u2026).",category:"secret",example:"xoxb-1234567890-abcdefghijkl",template:{pattern:y.slack_token,mode:"full"},defaultEnabled:!0},stripe_secret:{id:"stripe_secret",label:"Stripe secret keys",description:"Stripe live secret / restricted keys (sk_live_ / rk_live_).",category:"secret",example:"sk_live_0123456789abcdefABCDEF",template:{pattern:y.stripe_secret,mode:"full"},defaultEnabled:!0},google_api_key:{id:"google_api_key",label:"Google API keys",description:"Google API keys (AIza\u2026).",category:"secret",example:"AIzaSyA1234567890abcdefghijklmnopqrstuv",template:{pattern:y.google_api_key,mode:"full"},defaultEnabled:!0},llm_api_key:{id:"llm_api_key",label:"LLM provider API keys",description:"OpenAI / Anthropic secret keys (sk-\u2026, sk-proj-\u2026, sk-ant-\u2026).",category:"secret",example:"sk-ant-api03-AbCdEf0123456789AbCdEf01",template:{pattern:y.llm_api_key,mode:"full"},defaultEnabled:!0},bearer_token:{id:"bearer_token",label:"Authorization bearer tokens",description:"Credentials following an HTTP `Authorization: Bearer \u2026` header.",category:"secret",example:"Bearer abcdef0123456789abcdef0123456789",template:{pattern:y.bearer_token,mode:"full"},defaultEnabled:!0},connection_string:{id:"connection_string",label:"Connection strings (with password)",description:"Database / broker DSNs carrying an inline password (scheme://user:pass@host).",category:"secret",example:"postgres://app:s3cr3t@db.internal:5432/main",template:{pattern:y.connection_string,mode:"full"},defaultEnabled:!0},pan:{id:"pan",label:"Payment card numbers (PAN)",description:"Luhn-valid 13\u201319 digit primary account numbers (PCI-DSS). Collision rate: MEASURED 9.8% of benign 16-digit runs \u2014 Luhn leaves ~1 in 10. Default-ON because PCI-DSS makes masking mandatory; note in_aadhaar sits at the same rate and is often proposed for removal on that basis.",category:"financial",example:"4242 4242 4242 4242",template:{pattern:y.pan,mode:"partial",keepLast:4,templateOnly:{reason:"A rego rule cannot run Luhn, so the rule masks EVERY 13-19 digit run (grouped or not) \u2014 the floor's regex without the checksum that makes it precise. ~9 in 10 of those are not card numbers.",examples:["4242 4242 4242 4243","4242424242424241"],measuredOverMaskRate:.531}},defaultEnabled:!0},iban:{id:"iban",label:"IBAN bank account numbers",description:"ISO 13616 IBANs (mod-97 validated); keeps the last 4 visible. Collision rate: MEASURED 1.0% \u2014 mod-97 leaves ~1 in 97, the most precise detector on this floor alongside br_cpf.",category:"financial",example:"DE89 3704 0044 0532 0130 00",template:{pattern:y.iban,mode:"partial",keepLast:4,templateOnly:{reason:"A rego rule cannot run mod-97, so the rule masks EVERY IBAN-SHAPED token (2 letters, 2 digits, 10-30 alphanumerics) \u2014 and mod-97 is what makes this the most precise detector on the floor, so almost all of those are not IBANs.",examples:["DE89 3704 0044 0532 0130 01","GB00 NWBK 6016 1331 9268 19"],measuredOverMaskRate:.934}},defaultEnabled:!0},aba_routing:{id:"aba_routing",label:"ABA routing numbers",description:"US bank routing-transit numbers (9-digit, checksum-validated). DEFAULT-OFF (9-digit false-positive surface).",category:"financial",example:"021000021",template:{pattern:y.aba_routing,mode:"full",templateOnly:{reason:"A rego rule cannot run the weighted 3-7-1 mod-10, so the rule masks EVERY bare 9-digit run \u2014 which is why this detector is default-OFF on the floor and why its rule form is broader still.",examples:["021000022","123456789"],measuredOverMaskRate:.899}},defaultEnabled:!1},us_ein:{id:"us_ein",label:"US Employer ID (EIN)",description:"US tax Employer Identification Numbers (XX-XXXXXXX). Collision rate: MEASURED 100% \u2014 no checksum, so every 2-then-7 dashed digit run matches. Same trade as ssn: the punctuated shape is rare in benign traffic, not precise.",category:"financial",example:"12-3456789",template:{pattern:y.us_ein,mode:"full"},defaultEnabled:!0},swift_bic:{id:"swift_bic",label:"SWIFT / BIC codes",description:"Bank SWIFT/BIC codes (8 or 11 chars). DEFAULT-OFF (matches uppercase tokens).",category:"financial",example:"DEUTDEFF500",template:{pattern:y.swift_bic,mode:"full"},defaultEnabled:!1},ssn:{id:"ssn",label:"US Social Security numbers",description:"Dashed / spaced US SSNs (e.g. 123-45-6789). Collision rate: MEASURED 100% \u2014 there is NO checksum, so every dashed 3-2-4 digit run matches. Default-ON regardless, because that punctuated shape is essentially absent from benign agent traffic; if your traffic carries 3-2-4 dashed reference codes, opt out.",category:"pii",example:"123-45-6789",template:{pattern:y.ssn,mode:"partial",keepLast:4},defaultEnabled:!0},uk_nino:{id:"uk_nino",label:"UK National Insurance numbers",description:"UK NINOs (e.g. AB 12 34 56 C). DEFAULT-OFF \u2014 NO CHECKSUM. Precision comes only from the issued alphabet and the never-issued administrative prefixes (BG, GB, NK, KN, TN, NT, ZZ), so roughly half of tokens already shaped 2-letters/6-digits/[A-D] validate. All-lowercase candidates are rejected (git short SHAs), but that does NOT exclude uppercase business identifiers \u2014 serial, part, batch, PO, coupon and asset tags share the shape exactly and were measured being masked. Opt in when UK NINOs are expected in your traffic.",category:"pii",example:"AB 12 34 56 C",template:{pattern:"\\b(?:[A-CEGHJ-PR-TW-Z][A-CEGHJ-NPR-TW-Za-ceghj-npr-tw-z]\\s?\\d{2}\\s?\\d{2}\\s?\\d{2}\\s?[A-Da-d]|[A-CEGHJ-PR-TW-Za-ceghj-pr-tw-z][A-CEGHJ-NPR-TW-Z]\\s?\\d{2}\\s?\\d{2}\\s?\\d{2}\\s?[A-Da-d]|[A-CEGHJ-PR-TW-Za-ceghj-pr-tw-z][A-CEGHJ-NPR-TW-Za-ceghj-npr-tw-z]\\s?\\d{2}\\s?\\d{2}\\s?\\d{2}\\s?[A-D])\\b",mode:"full",templateOnly:{reason:"uk_nino has no checksum, but the floor still rejects the seven NEVER-ISSUED administrative prefixes (BG GB NK KN TN NT ZZ). A rego rule cannot express that exclusion without enumerating hundreds of letter pairs (RE2 has no lookahead), so the rule masks those too.",examples:["NK 12 34 56 A","ZZ 12 34 56 C"],measuredOverMaskRate:.019}},defaultEnabled:!1},in_aadhaar:{id:"in_aadhaar",label:"Aadhaar numbers (India)",description:"12-digit UIDAI Aadhaar numbers, Verhoeff-checksum validated and constrained to the issued 2-9 leading digit. Keeps the last 4 visible. Collision rate: MEASURED 10.0% of benign 12-digit ids starting 2-9 (order/transaction numbers) \u2014 Verhoeff leaves ~1 in 10. Comparable to the long-shipped pan (10.0%) and well behind iban (1.0%); it stays default-ON because the two US identifiers this floor has always shipped, ssn and us_ein, collide at 100%.",category:"pii",example:"2345 6789 0124",template:{pattern:"\\b[2-9]\\d{3}(?:[ -]\\d{4}[ -]?\\d{4}|\\d{4}[ -]\\d{4})\\b",mode:"partial",keepLast:4,floorOnly:{reason:"The floor accepts the entirely UNPUNCTUATED 12-digit form because Verhoeff gates it (~1 in 10 survive). A rego rule cannot run Verhoeff, so a bare \\d{12} in a rule would mask every 12-digit order id and E.164 Indian mobile number in the tenant. The rule requires at least one printed separator \u2014 every half-punctuated form is covered; only the bare digit run stays floor-only.",examples:["234567890124","id=234567890124"]},templateOnly:{reason:"A rego rule cannot run the Verhoeff checksum, so the rule masks EVERY 4-4-4 grouping that starts 2-9 \u2014 including the ~9 in 10 that are not Aadhaar numbers at all.",examples:["2345 6789 0125","2345-6789-0123"],measuredOverMaskRate:.903}},defaultEnabled:!0},in_pan_tax:{id:"in_pan_tax",label:"India PAN (tax ID)",description:"India Permanent Account Number \u2014 the income-tax id (ABCPE1234F), NOT a payment-card PAN. NO CHECKSUM: the only discriminator is the holder-type letter in position 4, which removes just 15 of 26 possibilities in one position, so roughly 4 in 10 uniform 5-letter/4-digit/1-letter tokens validate. DEFAULT-OFF for that reason \u2014 an uppercase SKU or part number of the same shape is masked, and nothing in the value distinguishes it.",category:"financial",example:"ABCPE1234F",template:{pattern:y.in_pan_tax,mode:"full"},defaultEnabled:!1},br_cpf:{id:"br_cpf",label:"CPF numbers (Brazil)",description:"Brazilian CPF, closed by TWO independent mod-11 check digits. Collision rate: MEASURED 1.0% of benign 11-digit runs (~1-in-100) \u2014 the most precise detector on this floor, alongside iban. Repdigits are rejected. Keeps the last 2 visible.",category:"pii",example:"123.456.789-09",template:{pattern:"\\b\\d{3}(?:\\.\\d{3}\\.?\\d{3}-?\\d{2}|\\d{3}(?:\\.\\d{3}-?\\d{2}|\\d{3}-\\d{2}))\\b",mode:"partial",keepLast:2,floorOnly:{reason:"The floor accepts the entirely bare 11-digit form because TWO mod-11 check digits gate it (~1 in 100 survive). A rego rule cannot run mod-11, so a bare \\d{11} in a rule would mask every 11-digit identifier in the tenant. The rule requires at least one printed separator; the bare form stays floor-only.",examples:["11144477735","ref 11144477735","12345678909"]},templateOnly:{reason:"A rego rule cannot run the two mod-11 check digits, so the rule masks EVERY punctuated 3-3-3-2 digit grouping \u2014 including the ~99 in 100 that are not CPFs.",examples:["123.456.789-10","111.444.777-34"],measuredOverMaskRate:.995}},defaultEnabled:!0},es_dni_nie:{id:"es_dni_nie",label:"DNI / NIE numbers (Spain)",description:"Spanish national ID (8 digits + letter) and foreigner ID (X/Y/Z + 7 digits + letter), validated by the mod-23 check letter. Collision rate: MEASURED 4.0% of benign 8-digit-plus-letter tokens (invoice/order numbers with a suffix letter) \u2014 mod-23 leaves ~1 in 23. More precise than in_aadhaar (10.0%) and pan (10.0%); behind br_cpf (1.0%) and iban (1.0%).",category:"pii",example:"12345678Z",template:{pattern:y.es_dni_nie,mode:"full",templateOnly:{reason:"A rego rule cannot run the mod-23 check letter, so the rule masks EVERY 7-8 digit run followed by a letter \u2014 invoice and order numbers with a suffix letter included. mod-23 admits ~1 in 23; the rule admits all of them. Re-measured 0.973 \u2192 0.981 when the floor learned the printed forms (dotted DNI, hyphenated NIE): the rule now also matches those written forms, and ~22 in 23 of them are not DNI/NIEs. The FLOOR's own rate is unchanged \u2014 mod-23, not punctuation, gates it.",examples:["12345678A","X1234567H"],measuredOverMaskRate:.976}},defaultEnabled:!0},ca_sin:{id:"ca_sin",label:"SIN numbers (Canada)",description:"Canadian Social Insurance Numbers (9-digit, Luhn-validated). DEFAULT-OFF \u2014 identical shape to an ABA routing number and to any 9-digit id, with only a mod-10 pass to separate them.",category:"pii",example:"046 454 286",template:{pattern:"\\b\\d{3}(?:[- ]\\d{3}[- ]?\\d{3}|\\d{3}[- ]\\d{3})\\b",mode:"partial",keepLast:3,floorOnly:{reason:"The floor accepts the entirely bare 9-digit form because Luhn gates it. A rego rule cannot run Luhn, and a bare \\d{9} in a rule is also every ABA routing number and every 9-digit identifier, so the rule requires at least one printed separator in the 3-3-3 grouping.",examples:["046454286"]},templateOnly:{reason:"A rego rule cannot run Luhn, so the rule masks EVERY printed 3-3-3 digit grouping \u2014 including the ~9 in 10 that are not SINs.",examples:["046 454 287","123 456 789"],measuredOverMaskRate:.914}},defaultEnabled:!1},uk_nhs_number:{id:"uk_nhs_number",label:"NHS numbers (UK)",description:"UK NHS patient numbers (10-digit, weighted mod-11). DEFAULT-OFF \u2014 a 10-digit run is also every North American phone number.",category:"pii",example:"943 476 5919",template:{pattern:"\\b\\d{3}(?:[- ]\\d{3}[- ]?\\d{4}|\\d{3}[- ]\\d{4})\\b",mode:"full",floorOnly:{reason:"The floor accepts the entirely bare 10-digit form because the weighted mod-11 gates it. A rego rule cannot run mod-11, and a bare \\d{10} in a rule is also every North American phone number, so the rule requires at least one printed separator in the 3-3-4 grouping.",examples:["9434765919"]},templateOnly:{reason:"A rego rule cannot run the weighted mod-11, so the rule masks EVERY printed 3-3-4 digit grouping \u2014 every North American phone number included \u2014 not just the ~1 in 10 that are NHS numbers.",examples:["943 476 5910","123 456 7890"],measuredOverMaskRate:.899}},defaultEnabled:!1},au_tfn:{id:"au_tfn",label:"Tax File Numbers (Australia)",description:"Australian TFNs (8-9 digit, weighted mod-11). DEFAULT-OFF \u2014 collides with essentially every 8-9 digit identifier.",category:"financial",example:"123 456 782",template:{pattern:"\\b\\d{3}(?:[- ]\\d{3}[- ]?\\d{2,3}|\\d{3}[- ]\\d{2,3})\\b",mode:"full",floorOnly:{reason:"The floor accepts the entirely bare 8-9 digit form because the weighted mod-11 gates it. A rego rule cannot run mod-11, and a bare \\d{8,9} in a rule collides with essentially every identifier of that length, so the rule requires at least one printed separator. BOTH lengths are in the gap: a TFN may be 8 digits (`12345679`) or 9 (`123456782`), and the 8-digit branch went undeclared while the parity sweep derived its population from the 9-digit example alone.",examples:["12345679","123456782"]},templateOnly:{reason:"A rego rule cannot run the weighted mod-11, so the rule masks EVERY printed 3-3-2/3-3-3 digit grouping \u2014 including the ~9 in 10 that are not TFNs.",examples:["123 456 783","123 456 78"],measuredOverMaskRate:.912}},defaultEnabled:!1},date_of_birth:{id:"date_of_birth",label:"Dates of birth",description:"Dates in the common written formats. DEFAULT-OFF and heavily over-masking by nature \u2014 a DOB is indistinguishable from any other date (created_at, invoice, release). Offered because DOB is a GDPR/HIPAA identifier some regulated tenants must mask regardless.",category:"pii",example:"1985-04-12",template:{pattern:y.date_of_birth,mode:"full"},defaultEnabled:!1},email:{id:"email",label:"Email addresses",description:"Email addresses (the mailbox is masked, the domain kept). Collision rate: MEASURED 100% of well-formed addresses \u2014 that is BY DESIGN, not a defect: an email address is structurally unambiguous, so matching every one is correct rather than over-matching.",category:"pii",example:"alice@acme.com",template:{pattern:y.email,mode:"email"},defaultEnabled:!0},us_phone:{id:"us_phone",label:"US phone numbers",description:"US phone numbers in common formats. DEFAULT-OFF (10-digit false-positive surface).",category:"pii",example:"(415) 555-0132",template:{pattern:y.us_phone,mode:"partial",keepLast:4},defaultEnabled:!1},ipv4:{id:"ipv4",label:"IPv4 addresses",description:"Dotted-quad IPv4 addresses. DEFAULT-OFF (common + usually benign).",category:"identifier",example:"203.0.113.42",template:{pattern:y.ipv4,mode:"full"},defaultEnabled:!1},mac_address:{id:"mac_address",label:"MAC addresses",description:"Hardware MAC addresses. DEFAULT-OFF.",category:"identifier",example:"3c:22:fb:1a:2b:3c",template:{pattern:y.mac_address,mode:"full"},defaultEnabled:!1}},re=Object.freeze(Object.fromEntries(ne.map(e=>{let t=fi[e];return[e,{...t,template:{...t.template,pattern:Qr(Zr(t.template.pattern))}}]})));var os=new Set(ne.filter(e=>!re[e].defaultEnabled));function mi(e,t){let n=new Set;for(let r of ne)(re[r].defaultEnabled?!e?.has(r):t?.has(r))||n.add(r);return n}function U(e,t,n,r){if(typeof e!="string"||e.length===0)return e;let i=ie(t),a=e;for(let{name:o,re:s}of $t){let l=o;n.has(l)||(a=a.replace(s,c=>(r?.(l),i(c))))}for(let{name:o,re:s,normalize:l,validate:c}of Dt)n.has(o)||(a=Ii(a,s,l,c,t,o,r));return a}function ie(e){return typeof e=="function"?e:()=>e}var mt=e=>"\0".repeat(e.length);function hi(e,t,n,r){if(typeof e!="string"||e.length===0)return e;let i=Wr(e);if(i.length===0)return U(e,t,n,r);let a=new Set,o=f=>{a.add(f)},s=U(e,mt,n,o),l=!0,c=new Array(e.length).fill(!1);for(let f=0;f<e.length;f++)c[f]=s[f]==="\0"&&e[f]!=="\0";for(let f of i){let m=U(f.text,mt,n,o);for(let g=0;g<f.text.length;g++)if(!(m[g]!=="\0"||f.text[g]==="\0"))for(let _=f.offsets[g];_<f.offsets[g+1];_++)c[_]||(c[_]=!0,l=!1)}if(l)return U(e,t,n,r);for(let f of a)r?.(f);let u="",h=0;for(;h<e.length;){if(!c[h]){u+=e[h],h++;continue}let f=h;for(;h<e.length&&c[h];)h++;u+=ie(t)(e.slice(f,h))}return u}function R(e){return e===void 0||!/[A-Za-z0-9]/.test(e)}var ht=new Map;function gi(e){let t=ht.get(e.source);return t===void 0&&(t=new RegExp(`^(?:${e.source})$`),ht.set(e.source,t)),t}var _i=4096,yi=64,gt=null;function bi(e){return gt!==null?gt:_i+e.length*yi}var Mt=!1,v={spanCalls:0,spanMisses:0,cutCalls:0,cutMisses:0,budgetExhausted:0,maxMissesInAPass:0},Lt={spanBudget:0,depthCap:0};function vi(e){return{stride:e.length+1,chosen:new Map,cuts:new Map,budget:bi(e),exhausted:!1}}function Pt(e,t,n,r,i,a,o){v.spanCalls++;let s=t*o.stride+n.length,l=Mt?void 0:o.chosen.get(s);if(l!==void 0)return l;if(o.budget<=0)return o.exhausted=!0,null;o.budget--,v.spanMisses++;let c=wi(e,t,n,r,i,a,o);return o.chosen.set(s,c),c}function wi(e,t,n,r,i,a,o){let s=gi(r),l=[];for(let u=n.length-1;u>=1;u--)if(R(n[u])){let h=n.slice(0,u);s.test(h)&&l.push(h)}let c=R(e[t+n.length])?[n,...l]:[...l,n];for(let u of c)if(a(i(u),u)&&!ki(e,t,u,r,i,a,o))return u;return null}var _t=new Map;function Ai(e){let t=_t.get(e.source);return t===void 0&&(t=new RegExp(e.source,"y"),_t.set(e.source,t)),t}function ki(e,t,n,r,i,a,o){v.cutCalls++;let s=t*o.stride+n.length,l=Mt?void 0:o.cuts.get(s);if(l!==void 0)return l;if(o.budget<=0)return o.exhausted=!0,!0;o.budget--,v.cutMisses++;let c=Si(e,t,n,r,i,a,o);return o.cuts.set(s,c),c}function Si(e,t,n,r,i,a,o){let s=t+n.length,l=Ai(r);for(let c=1;c<n.length;c++){if(R(n[c])||!R(n[c-1]))continue;let u=t+c;l.lastIndex=u;let h=l.exec(e);if(h===null||h[0].length===0)continue;let f=Pt(e,u,h[0],r,i,a,o);if(f!==null&&u+f.length>s&&R(e[u+f.length]))return!0}return!1}function Ii(e,t,n,r,i,a,o){let s=ie(i);t.lastIndex=0;let l="",c=0,u=vi(e),h=v.spanMisses+v.cutMisses,f;for(;(f=t.exec(e))!==null;){let m=f[0],g=f.index;if(m.length===0){t.lastIndex=g+1;continue}let _;try{_=Pt(e,g,m,t,n,r,u)}catch(b){if(b instanceof RangeError&&/call stack/i.test(b.message))u.exhausted=!0,_=null;else throw b}if(u.exhausted)return v.budgetExhausted++,Lt.spanBudget++,yt(h),l+e.slice(c,g)+s(e.slice(g));if(_!==null)o?.(a),l+=e.slice(c,g)+s(_),c=g+_.length,t.lastIndex=c;else{let b=m.slice(1).search(/[^A-Za-z0-9]/);t.lastIndex=b===-1?g+m.length:g+1+b+1}if(t.lastIndex>e.length)break}return yt(h),l+e.slice(c)}function yt(e){let t=v.spanMisses+v.cutMisses-e;t>v.maxMissesInAPass&&(v.maxMissesInAPass=t)}function Ft(e,t=Nt,n,r){return Ci(e,t,mi(n,r))}var Ei=256;function Ci(e,t,n){let r=new Set,i=!n.has("pan"),a=s=>{r.add(s)},o=(s,l)=>{if(l>Ei)return Lt.depthCap++,t;if(typeof s=="string")return hi(s,t,n,a);if(typeof s=="number"&&Number.isInteger(s)&&s>0){if(!i)return s;let c=String(s);return c.length>=13&&c.length<=19&&Q(c)?(r.add("pan"),t):s}if(Array.isArray(s))return s.map(c=>o(c,l+1));if(s!==null&&typeof s=="object"){let c=s,u={};for(let h of Object.keys(c))u[h]=o(c[h],l+1);return u}return s};return{value:o(e,0),detectors:[...r].sort()}}function jt(e,t=Nt){return Ft(e,t).value}var xi=/[\u00AD\u200B-\u200F\u202A-\u202E\u2060\u2066-\u2069\uFEFF]/g,Bt=Object.freeze({\u0430:"a",\u0435:"e",\u043E:"o",\u0440:"p",\u0441:"c",\u0443:"y",\u0445:"x",\u0456:"i",\u0455:"s",\u043A:"k",\u043C:"m",\u0442:"t",\u043D:"h",\u0432:"b",\u0433:"r",\u03BF:"o",\u03B1:"a",\u03C1:"p",\u03B9:"i",\u03C4:"t",\u03B5:"e",\u03BA:"k",\u03BD:"v",\u03C5:"u",\u03B7:"n",\u0131:"i","\u04CF":"l",\u0578:"n"}),Ti=new RegExp(`[${Object.keys(Bt).join("")}]`,"gu"),Ni=Object.freeze({4:"a","@":"a",3:"e",1:"i","!":"i",0:"o",5:"s",$:"s",7:"t",9:"g","(":"c",8:"b"}),Ut="\u2801\u2803\u2809\u2819\u2811\u280B\u281B\u2813\u280A\u281A\u2805\u2807\u280D\u281D\u2815\u280F\u281F\u2817\u280E\u281E\u2825\u2827\u283A\u282D\u283D\u2835",Oi=Object.freeze(Object.fromEntries([...Ut].map((e,t)=>[e,String.fromCharCode(97+t)]))),Ri=new RegExp(`[${Ut}\u2800]`,"g"),zt=/[⠀-⣿]/;function $i(e){let t="";for(let n of e){let r=n.codePointAt(0);r!==void 0&&(r>=917536&&r<=917630?t+=String.fromCodePoint(r-917504):r>=917504&&r<=917631||(t+=n))}return t}function Di(e){return e.replace(xi,"")}function qt(e){return e.replace(Ti,t=>Bt[t]??t)}function Mi(e){return e.replace(/[4@31!05$79(8]/g,t=>Ni[t]??t)}function Li(e){return e.replace(/[a-zA-Z]/g,t=>{let n=t<="Z"?65:97;return String.fromCharCode((t.charCodeAt(0)-n+13)%26+n)})}function Pi(e){return zt.test(e)?e.replace(Ri,t=>t==="\u2800"?" ":Oi[t]??t):e}function bt(e){let t;try{t=$i(e)}catch{t=e}try{t=t.normalize("NFKC")}catch{}return t=Di(t),t=qt(t),t}var Fi=/^[A-Za-z0-9+/]{16,}={0,2}$/,ji=/^(?:[0-9a-fA-F]{2}\s*){8,}$/,vt=/[A-Za-z0-9+/]{20,}={0,2}/g;function X(e){if(e.length===0)return 0;let t=0;for(let n=0;n<e.length;n++){let r=e.charCodeAt(n);(r===9||r===10||r===13||r>=32&&r<=126||r>=160&&r!==65533)&&t++}return t/e.length}var Gt=new TextDecoder("utf-8",{fatal:!1});function Vt(e){let t;try{t=atob(e)}catch{return[]}let n=new Uint8Array(t.length);for(let i=0;i<t.length;i++)n[i]=t.charCodeAt(i)&255;let r=Gt.decode(n);return t===r?[t]:[r,t]}function Bi(e){let t=e.replace(/\s+/g,"");if(t.length===0||t.length%2!==0)return[];let n=new Uint8Array(t.length/2);for(let a=0;a<n.length;a++){let o=Number.parseInt(t.slice(a*2,a*2+2),16);if(Number.isNaN(o))return[];n[a]=o}let r="";for(let a=0;a<n.length;a++)r+=String.fromCharCode(n[a]);let i=Gt.decode(n);return r===i?[r]:[i,r]}function wt(e){let t=e.trim(),n=[];if(ji.test(t))for(let r of Bi(t))n.push({decoded:r,textiness:X(r)});if(Fi.test(t)&&t.length%4===0)for(let r of Vt(t))n.push({decoded:r,textiness:X(r)});return n}function At(e,t){let n=[],r;for(vt.lastIndex=0;(r=vt.exec(e))!==null&&n.length<t;){let i=r[0];if(i.length%4===0)for(let a of Vt(i))n.push({decoded:a,textiness:X(a)})}return n}var Ui=Object.freeze({maxDepth:3,byteCap:262144,maxNodes:256,maxBlobsPerNode:8});function Wt(e,t=Ui){if(typeof e!="string"||e.length===0)return{views:[],anyDecoded:!1,truncated:!1,nodes:0,maxDepthSeen:0};let{maxDepth:n,byteCap:r,maxNodes:i,maxBlobsPerNode:a}=t,o=new Set,s=m=>{m.length>0&&m.length<=r&&o.add(m)},l=!1,c=!1,u=0,h=0,f=[{s:e,depth:0}];for(;f.length>0;){if(u>=i){c=!0;break}let m=f.pop();if(m===void 0)break;let{s:g,depth:_}=m;if(g.length>r){c=!0;continue}u++,_>h&&(h=_);let b=bt(g);s(b);let I=Mi(b);if(I!==b&&s(I),s(Li(b)),zt.test(g)&&s(Pi(b)),_>=n){let k=bt(g);(wt(k).length>0||At(k,a).length>0)&&(c=!0);continue}let kn=[...wt(b),...At(b,a)];for(let k of kn){if(l=!0,k.decoded.length>r){c=!0;continue}k.textiness>=.85&&k.decoded!==b?f.push({s:k.decoded,depth:_+1}):s(k.decoded)}}return{views:[...o],anyDecoded:l,truncated:c,nodes:u,maxDepthSeen:h}}var Ht=["hidden_text_carrier","injected_turn_boundary","mixed_script_token","nested_encoding_payload"],zi=Object.freeze(["hidden_text_carrier","injected_turn_boundary","mixed_script_token"]),qi=8,Gi=new Set([173,8203,8204,8205,8206,8207,8288,65279,8234,8235,8236,8237,8238,8294,8295,8296,8297]),kt=e=>e!==void 0&&(e>=65&&e<=90||e>=97&&e<=122);function Vi(e){let t=[...e].map(r=>r.codePointAt(0)),n=0;for(let r=0;r<t.length;r++){let i=t[r];if(i>=917504&&i<=917631||Gi.has(i)&&kt(t[r-1])&&kt(t[r+1])&&(n++,n>=qi))return!0}return!1}var Wi=/^[ \t]*(?:system|assistant|developer|user)[ \t]*:/i;function Hi(e){let t=e.split(/\r?\n/),n=!1;for(let r of t){if(Wi.test(r)){if(n)return!0;continue}r.trim().length>0&&(n=!0)}return!1}var Ki=[{name:"latin",lo:65,hi:591},{name:"greek",lo:880,hi:1023},{name:"cyrillic",lo:1024,hi:1279}];function Yi(e){for(let t of Ki)if(e>=t.lo&&e<=t.hi)return t.name;return null}function Zi(e){for(let t of e.split(/\s+/)){if(t.length<4)continue;let n=0,r=0,i=!0;for(let a of t){let o=Yi(a.codePointAt(0));if(o===null){i=!1;break}o==="latin"?n++:qt(a)!==a&&r++}if(i&&n>0&&r>0)return!0}return!1}var St=Object.freeze({signals:[],contributes:!1});function Ji(e){if(typeof e!="string"||e.length===0)return{...St,signals:[]};let t=new Set;try{Vi(e)&&t.add("hidden_text_carrier"),Hi(e)&&t.add("injected_turn_boundary"),Zi(e)&&t.add("mixed_script_token");let{anyDecoded:n,maxDepthSeen:r,truncated:i}=Wt(e);n&&(r>=2||i)&&t.add("nested_encoding_payload")}catch{return{...St,signals:[]}}return{signals:[...Ht.filter(n=>t.has(n))],contributes:zi.some(n=>t.has(n))}}var z=[{name:"override_instructions",re:/\bignore (?:all |the )?(?:previous|above|prior) (?:instructions|prompts?)\b/i},{name:"disregard_instructions",re:/\bdisregard (?:the )?(?:above|previous|system)\b/i},{name:"role_tag",re:/<\/?(system|assistant|instructions|host_context)\b/i},{name:"privilege_override",re:/\b(grant|escalate|elevate) (admin|root|all|full) (access|privileges?)\b/i},{name:"tool_smuggle",re:/```[\s\S]*?(tool_call|function_call)/i}];function It(e){return typeof e!="string"||e.length===0?[]:z.filter(({re:t})=>t.test(e)).map(({name:t})=>t)}function Qi(e){if(typeof e!="string"||e.length===0)return[];let t=new Set(It(e)),{views:n}=Wt(e);for(let r of n)for(let i of It(r))t.add(i);return z.filter(r=>t.has(r.name)).map(r=>r.name)}function Xi(e){let t=new Set,n=new Set,r=!1,i=a=>{if(a!=null){if(typeof a=="string"){for(let s of Qi(a))t.add(s);let o=Ji(a);for(let s of o.signals)n.add(s);o.contributes&&(r=!0);return}if(Array.isArray(a)){for(let o of a)i(o);return}if(typeof a=="object")for(let o of Object.values(a))i(o)}};return i(e),{matched:t.size>0||r,signatures:z.filter(a=>t.has(a.name)).map(a=>a.name),structural:Ht.filter(a=>n.has(a))}}function ea(e){return Xi(e).matched}var ss=z.map(e=>e.name);var ta=new Set(["untrusted","external","public","public_internet","external_third_party","web"]);var na="i:injection";function Kt(e){let t=new Set;if(e.content!==void 0&&e.content!==null){let{detectors:i}=Ft(e.content);for(let a of i){let o=re[a]?.category;o&&t.add(`c:${o}`)}ea(e.content)&&t.add(na)}let n=e.resourceMetadata??{},r=n.source_trust;return(n.untrusted_source===!0||typeof r=="string"&&ta.has(r.toLowerCase()))&&t.add("i:untrusted"),[...t].sort()}var J="(?:system\\s+prompt|initial\\s+(?:instructions|prompt)|system\\s+(?:instructions|message)|hidden\\s+(?:instructions|prompt)|your\\s+(?:system\\s+prompt|initial\\s+instructions|instructions|prompt)|the\\s+prompt\\s+(?:above|you\\s+were\\s+given))",ls=[{name:"reveal_prompt",re:new RegExp(`\\b(?:reveal|show|print|repeat|output|echo|display|expose|dump|leak|reprint|divulge|disclose)\\b[\\s\\S]{0,40}?\\b${J}\\b`,"i")},{name:"what_is_prompt",re:new RegExp(`\\bwhat\\s+(?:is|are|were)\\b[\\s\\S]{0,20}?\\b${J}\\b`,"i")},{name:"tell_me_prompt",re:new RegExp(`\\b(?:tell|give|send|show)\\s+me\\b[\\s\\S]{0,30}?\\b${J}\\b`,"i")},{name:"repeat_above",re:/\b(?:repeat|print|output|echo|reproduce)\b[\s\S]{0,20}?\b(?:everything|all\s+(?:the\s+)?(?:text|words))\b[\s\S]{0,12}?\b(?:above|before|preceding|verbatim|word\s+for\s+word)\b/i}],Et="(?:instructions?|prompts?|rules?|directives?|guidelines?|constraints?|guardrails?)",ra=`(?:(?:all\\s+|any\\s+|the\\s+|these\\s+|those\\s+)*(?:previous|prior|preceding|earlier|above|foregoing|initial|original|system|developer)\\s+${Et}|your\\s+(?:(?:system|initial|original|previous|prior|current)\\s+)?(?:${Et}|programming|training))`,ia="(?:(?:all|any|every|the|of|and|now|please|completely|entirely|totally|immediately)\\s+){0,3}",Ct="(?:\\b(?:unrestricted|unfiltered|uncensored|unbounded|unlimited|unchained|jailbroken|lawless|amoral)\\b|\\b(?:DAN|STAN|DUDE|AIM)\\b|\\bno\\s+(?:longer\\s+)?(?:restrictions?|limits?|rules?|guidelines?|filters?|boundaries|constraints?)\\b(?!\\s+(?:on|over|regarding|upon|for)\\b)|\\bwithout\\s+(?:any\\s+)?(?:restrictions?|limits?|rules?|guidelines?|filters?|constraints?|censorship)\\b|\\b(?:free|freed|released)\\s+from\\s+(?:your\\s+)?(?:restrictions?|limits?|rules?|guidelines?|guardrails?|programming|constraints?)\\b|\\b(?:can|will|are\\s+able\\s+to)\\s+(?:do|say)\\s+anything\\b|\\bignore\\s+(?:all\\s+)?(?:your\\s+)?(?:previous\\s+|prior\\s+|system\\s+)?(?:instructions?|rules?|guidelines?)\\b)",aa="(?:ignore|disregard|forget|override|overrule|bypass|obey|comply\\s+with|follow\\s+(?:only|my|these))",cs=[{name:"override_instructions",re:new RegExp(`\\b(?:ignore|disregard|forget|discard|override|overrule|bypass|delete|erase)\\s+${ia}${ra}\\b`,"i")},{name:"forget_everything_prior",re:/\b(?:forget|ignore|disregard|erase|discard)\s+(?:about\s+|all\s+|any\s+)?(?:everything|anything)\b[\s\S]{0,24}?\b(?:above|before|previously|prior|earlier|you\s+(?:were|have\s+been)\s+(?:told|instructed|given|programmed))\b/i},{name:"persona_reassignment_jailbreak",re:new RegExp(`\\byou\\s+are\\s+now\\s+(?:(?:a|an|the)\\s+)?[\\s\\S]{0,48}?${Ct}`,"i")},{name:"constraint_release",re:/\byou\s+are\s+no\s+longer\s+(?:bound|restricted|limited|constrained|obligated|governed|subject\s+to|required\s+to)\b/i},{name:"from_now_on_reassignment",re:new RegExp(`\\bfrom\\s+now\\s+on\\s*,?\\s+you\\s+(?:are|will|must|shall|have|can)\\s+(?:${aa}\\b|[\\s\\S]{0,40}?${Ct})`,"i")},{name:"new_instructions_header",re:/^\s*(?:[#*>-]+\s*)?(?:new|real|actual|true|secret|hidden|override)\s+(?:system\s+)?(?:instructions?|prompts?|directives?)\s*:/im}];var us=Object.freeze({"\u2019":"'",\u02BC:"'","\uFF07":"'","\u02B9":"'","\u2032":"'"});var S=e=>`[^.!?;\\n]{0,${e}}?`,oa=["\\bi\\s+(?:can'?t|cannot|can\\s+not|won'?t|will\\s+not)\\b","\\bi(?:'m|\\s+am)\\s+(?:not\\s+able\\s+to|unable\\s+to|not\\s+going\\s+to|not\\s+permitted\\s+to|not\\s+allowed\\s+to)\\b"].join("|"),Yt="(?:help|assist|provide|create|generate|produce|write|compose|draft|comply|fulfil|fulfill|share|disclose|reveal|perform|execute|run|send|transmit|publish|export|approve|grant|carry\\s+out|do\\s+that|do\\s+this|do\\s+so|go\\s+ahead)",ds=Object.freeze([{id:"capability_denial",class:"strong",re:new RegExp([`(?:${oa})\\s${S(40)}\\b${Yt}\\b`,"\\b(?:that|this|it)(?:'s|\\s+is)\\s+not\\s+something\\s+i\\s+(?:can|could|am\\s+able\\s+to|'m\\s+able\\s+to)\\b",`\\b(?:falls|sits|is)\\s+outside\\s+(?:of\\s+)?(?:what|the\\s+(?:scope|range|bounds))\\b${S(40)}\\bi\\s+(?:can|am|'m)\\b`,"\\bnot\\s+something\\s+i(?:'m|\\s+am)\\s+(?:able|willing|permitted|allowed)\\s+to\\b"].join("|"),"i")},{id:"explicit_decline",class:"strong",re:new RegExp(["\\bi\\s+(?:must|have\\s+to|need\\s+to|will\\s+have\\s+to|am\\s+going\\s+to|'m\\s+going\\s+to)\\s+(?:respectfully\\s+)?decline\\b","\\bi(?:'m|\\s+am)\\s+not\\s+(?:comfortable|willing|prepared)\\b","\\bi(?:'ll|\\s+will)\\s+(?:have\\s+to\\s+)?pass\\s+on\\b","\\bi\\s+(?:must|have\\s+to)\\s+refuse\\b"].join("|"),"i")},{id:"policy_citation",class:"strong",re:new RegExp([`\\b(?:against|contrary\\s+to|prohibited\\s+by|forbidden\\s+by|in\\s+violation\\s+of|violates)\\s${S(24)}\\b(?:polic(?:y|ies)|guidelines?|terms\\s+of\\s+(?:use|service)|rules\\s+of\\s+engagement|code\\s+of\\s+conduct)\\b`,`\\b(?:my|our|the|company|organi[sz]ation'?s?)\\s+(?:polic(?:y|ies)|guidelines?)\\s${S(24)}\\b(?:do(?:es)?\\s+not\\s+(?:allow|permit)|prohibit|forbid|prevent)\\b`,`\\bnot\\s+(?:permitted|allowed|authori[sz]ed)\\s+(?:under|by)\\s${S(24)}\\b(?:polic(?:y|ies)|guidelines?)\\b`].join("|"),"i")},{id:"guardrail_selfreference",class:"strong",re:new RegExp(["\\bi(?:'ve|\\s+have)\\s+been\\s+(?:instructed|configured|told|trained)\\s+not\\s+to\\b","\\bi(?:'m|\\s+am)\\s+(?:designed|configured|programmed|built|set\\s+up)\\s+not\\s+to\\b",`\\bmy\\s+(?:safety\\s+)?(?:instructions|configuration|guardrails?|constraints|training)\\s${S(24)}\\b(?:prevent|prohibit|forbid|do(?:es)?\\s+not\\s+(?:allow|permit)|preclude)\\b`,"\\b(?:outside|beyond)\\s+(?:my|the)\\s+(?:permitted|authori[sz]ed|configured|approved)\\s+(?:scope|remit|capabilities|actions|operations)\\b"].join("|"),"i")},{id:"ethical_objection",class:"strong",re:new RegExp(["\\b(?:that|this|doing\\s+(?:so|that)|what\\s+you(?:'re|\\s+are)\\s+asking|the\\s+request|such\\s+a\\s+request)\\s+(?:would\\s+be|is|are)\\s+(?:clearly\\s+|both\\s+|potentially\\s+)?(?:illegal|unethical|unlawful|harmful|fraudulent)\\b","\\bi\\s+(?:do\\s+not|don'?t)\\s+condone\\b","\\b(?:goes|would\\s+go|runs)\\s+against\\s+my\\s+(?:principles|values|ethics)\\b","\\bi\\s+(?:can'?t|cannot|won'?t)\\s+in\\s+good\\s+conscience\\b"].join("|"),"i")},{id:"apology_marker",class:"weak",re:new RegExp("\\b(?:i(?:'m|\\s+am)\\s+(?:really\\s+|very\\s+|terribly\\s+|so\\s+)?sorry|i\\s+apologi[sz]e|my\\s+apologies)\\b","i")}]),ps=Object.freeze([/```/,/\b(?:here(?:'s|\s+is|\s+are)|below\s+(?:is|are|you(?:'ll|\s+will)\s+find)|the\s+following\s+(?:is|are))\b/i,new RegExp(`\\b(?:but|however|instead|although|that\\s+said)\\b${S(60)}\\b(?:i\\s+(?:can|could)(?!'t)\\s${S(30)}\\b${Yt}\\b|i(?:'d|\\s+would)\\s+be\\s+happy\\s+to\\b|i(?:'m|\\s+am)\\s+able\\s+to\\b)`,"i"),/\bwhat\s+i\s+can\s+do\s+(?:instead|is|for\s+you)\b/i]);var O=e=>`[^.!?;\\n]{0,${e}}?`,fs=Object.freeze([{id:"vulnerability_scanning",objectPatterns:[/\b(?:vulnerability|vuln|security)\s+(?:scan|scans|scanning|assessment|audit|test|testing)\b/i,/\bpen(?:etration)?[\s-]?test(?:ing)?\b/i,/\bport\s+scan(?:ning)?\b/i,/\b(?:exploit|nmap|metasploit|nessus|burp\s+suite)\b/i,/\bCVE-\d{4}-\d{4,7}\b/i],purposeFunctions:["it_security","engineering"],purposePatterns:[/\b(?:security|vulnerability|incident\s+respon\w{0,4}|threat|soc|red\s+team|phishing|malware)\b/i]},{id:"credential_access",objectPatterns:[/\b(?:credential|password|passphrase|api\s+key|access\s+key|secret|token|private\s+key|ssh\s+key)s?\b/i,/\b(?:vault|secrets?\s+manager|keychain|keystore)\b/i,/\bservice\s+account\s+key\b/i],purposeFunctions:["it_security","engineering"],purposePatterns:[/\b(?:security|identity|iam|credential|secrets?\s+manage\w{0,4}|vault|platform|devops)\b/i]},{id:"financial_transaction",objectPatterns:[/\b(?:wire\s+transfer|bank\s+transfer|payout|disbursement|chargeback)\b/i,new RegExp(`\\b(?:approve|issue|initiate|process|release)\\s${O(20)}\\b(?:payment|refund|invoice|transfer|purchase\\s+order)s?\\b`,"i"),new RegExp(`\\b(?:move|transfer)\\s${O(20)}\\b(?:funds|money)\\b`,"i")],purposeFunctions:["finance_accounting","procurement"],purposePatterns:[/\b(?:finance|financial|accounting|invoice|invoicing|payment|payments|billing|refund|refunds|treasury|procurement|spend|purchasing|fraud|kyc)\b/i]},{id:"personnel_data",objectPatterns:[/\b(?:employee|personnel|payroll|hr|staff)\s+(?:record|records|data|file|files|information|details)\b/i,/\b(?:salary|salaries|compensation|performance\s+review|termination\s+letter)s?\b/i,/\b(?:home\s+address|social\s+security\s+number|national\s+insurance\s+number)e?s?\b/i],purposeFunctions:["hr","privacy_compliance"],purposePatterns:[/\b(?:hr|human\s+resources|people\s+ops|payroll|benefits|recruit\w{0,4}|onboarding|privacy|dsar|consent)\b/i]},{id:"regulated_advice",objectPatterns:[/\b(?:legal|medical|tax|investment|financial)\s+advice\b/i,/\bpractis\w{0,3}\s+law\b/i,/\b(?:diagnose|diagnosis|prescribe|prescription)\b/i,/\b(?:binding|enforceable)\s+(?:opinion|interpretation)\b/i],purposeFunctions:["legal","privacy_compliance"],purposePatterns:[/\b(?:legal|compliance|counsel|contract|contracts|litigation|nda|privacy|regulator\w{0,2}|audit\w{0,3})\b/i]},{id:"data_export",objectPatterns:[new RegExp(`\\b(?:export|download|dump|extract|exfiltrat\\w{0,3}|bulk\\s+copy)\\b\\s${O(30)}\\b(?:data|database|dataset|records?|table|tables|customer\\s+list|contact\\s+list|report)\\b`,"i"),/\b(?:full|entire|whole)\s+(?:database|dataset|customer\s+table)\b/i],purposeFunctions:["operations","engineering","privacy_compliance"],purposePatterns:[/\b(?:data\s+(?:pipeline|engineering|platform)|etl|export|reporting|analytics|operations|document\s+extract\w{0,3}|forecast\w{0,3})\b/i]},{id:"code_execution",objectPatterns:[new RegExp(`\\b(?:run|execute|invoke)\\s${O(24)}\\b(?:script|scripts|command|commands|shell|code|binary|query|migration)\\b`,"i"),/\b(?:shell|root|sudo|admin)\s+(?:access|command|session)\b/i,/\bagainst\s+(?:the\s+)?production\s+(?:system|server|database|environment)s?\b/i],purposeFunctions:["engineering","it_security"],purposePatterns:[/\b(?:engineering|developer|devops|platform|release|deploy\w{0,4}|build|pipeline|sandbox|test\s+data|change\s+window)\b/i]},{id:"external_communication",objectPatterns:[new RegExp(`\\b(?:send|post|publish|email|tweet|message|broadcast)\\b\\s${O(30)}\\b(?:external|customer|customers|public|press|social\\s+media|third[\\s-]party|prospect|prospects)\\b`,"i"),/\b(?:cold\s+outreach|marketing\s+blast|phishing\s+email|press\s+release)\b/i],purposeFunctions:["marketing","sales","customer_support"],purposePatterns:[/\b(?:marketing|campaign|outreach|email\s+assistant|support|customer|sales|lead|leads|communication|communications)\b/i]}]);var Zt=e=>e!==void 0&&e.length>5120?e.slice(0,5120):e;function la(e){let t={...e};return t.content?.text!==void 0&&(t.content={...t.content,text:Zt(t.content.text)}),t.spawn?.prompt!==void 0&&(t.spawn={...t.spawn,prompt:Zt(t.spawn.prompt)}),t}function ca(e,t=process.env){if(typeof e=="number"&&Number.isFinite(e)&&e>0)return e;let n=t.ALLOW_TIMEOUT_MS;if(n!==void 0){let r=Number.parseInt(n,10);if(Number.isFinite(r)&&r>0)return r}return 5e3}var ua=1440*60*1e3,da="VISIQ_BUNDLE_GRACE_TTL_MS",pa="VISIQ_BUNDLE_CACHE_DISABLED",fa="VISIQ_CACHE_DIR",ma=q.object({graceTtlMs:q.number().int().nonnegative().optional(),disabled:q.boolean().optional(),cacheDir:q.string().min(1).optional()}).strict();function ha(e){return e==null?{}:ma.parse(e)}function ga(e,t=process.env){if(typeof e=="number"&&Number.isInteger(e)&&e>=0)return e;let n=t[da];if(n!==void 0){let r=Number(n);if(Number.isInteger(r)&&r>=0)return r}return ua}function _a(e,t=process.env){if(typeof e=="boolean")return e;let n=(t[pa]??"").trim().toLowerCase();return n==="1"||n==="true"||n==="yes"}var Jt;function ya(){if(Jt!==void 0)return Jt;try{return typeof process<"u"&&!!process.versions&&!!process.versions.node}catch{return!1}}function ba(e){return JSON.stringify(oe(e))}function oe(e){if(Array.isArray(e))return e.map(oe);if(e!==null&&typeof e=="object"){let t=e,n={};for(let r of Object.keys(t).sort())n[r]=oe(t[r]);return n}return e}function va(e,t,n){let r=n-e.fetchedAt;return r<0?!1:r<=t}function wa(e){if(e!==null&&typeof e=="object"&&typeof e.fetchedAt=="number"&&typeof e.contentHash=="string"&&"body"in e){let t=e;return{fetchedAt:t.fetchedAt,version:typeof t.version=="string"?t.version:null,contentHash:t.contentHash,body:t.body}}return null}async function an(){if(!ya())return null;try{let[e,t,n,r]=await Promise.all([import("node:fs/promises"),import("node:path"),import("node:os"),import("node:crypto")]);return{fs:e,path:t,os:n,crypto:r}}catch{return null}}function on(e,t){return e.createHash("sha256").update(ba(t)).digest("hex")}function Aa(e,t){let n=t.cacheDir?.trim();if(n)return n;let r=process.env[fa]?.trim();if(r)return r;let i=process.env.XDG_CACHE_HOME?.trim();if(i)return e.path.join(i,"visiq");let a="";try{a=e.os.homedir()}catch{a=""}return a?e.path.join(a,".cache","visiq"):e.path.join(e.os.tmpdir(),"visiq-cache")}function ka(e,t){return e.crypto.createHash("sha256").update(`${t.endpoint}\0${t.agentId}\0${t.apiKey}`).digest("hex")}function sn(e,t,n){return e.path.join(Aa(e,n),"bundles",`${ka(e,t)}.json`)}async function Sa(e,t,n,r={}){let i=await an();if(i)try{let a=sn(i,e,r),o=i.path.dirname(a);await i.fs.mkdir(o,{recursive:!0,mode:448});let s={fetchedAt:r.now??Date.now(),version:n,contentHash:on(i.crypto,t),body:t},l=`${a}.tmp-${process.pid}-${i.crypto.randomBytes(6).toString("hex")}`;await i.fs.writeFile(l,JSON.stringify(s),{mode:384});try{await i.fs.rename(l,a)}catch(c){throw await i.fs.rm(l,{force:!0}).catch(()=>{}),c}}catch{}}async function Ia(e,t={}){let n=await an();if(!n)return null;try{let r=await n.fs.readFile(sn(n,e,t),"utf-8"),i=wa(JSON.parse(r));return!i||on(n.crypto,i.body)!==i.contentHash?null:i}catch{return null}}var $;async function Ea(){if($!==void 0)return $;try{let e=await import("@visiq/core-wasm"),t=e.evaluate??e.default?.evaluate;$=typeof t=="function"?t:null}catch{$=null}return $}function Ca(e){let t=[];for(let n of e){if(typeof n!="object"||n===null)continue;let r=n,i=r.rego_source;if(typeof i!="string"||i.length===0)continue;let a;try{a=Y(i)}catch{continue}let o=typeof r.id=="string"?r.id:"<rule>";for(let s of He(a))t.push(`${o}: ${s}`)}return t}function xa(e){return dt(e)}function Ta(e){return e==null||typeof e!="object"?!0:Object.keys(e).length===0}var Na=5e3,Oa=600*1e3,Ra=1e4,$a=25,Qt=1e3,Da=5e3,Ma=100,Xt=2e3,La=10,Pa=512,Fa=1800*1e3,ja=.7,Ba="monitor",Ua="Agent has been shut down by an operator \u2014 all actions are blocked (G001)",en="Rules bundle requires a newer SDK wire-contract dialect than this SDK supports \u2014 refusing the bundle and blocking all actions (fail-closed, G001). Upgrade the VisIQ SDK.",za="open";function tn(e){if(typeof e!="string")return;let t=e.trim().toLowerCase();return t==="open"||t==="closed"?t:void 0}function qa(e,t){return Kt({content:e,resourceMetadata:t})}var Ga=p.object({operations:p.array(p.enum(["retrieval","action","delegation"])).min(1,"at least one operation is required"),agentId:p.string().min(1,"agentId is required"),sessionId:p.string().min(1).max(255).optional(),toolName:p.string().optional(),toolArgs:p.record(p.unknown()).optional(),targetResource:p.string().optional(),resourceType:p.string().optional(),resourceMetadata:p.record(p.unknown()).optional(),normalized:p.record(p.unknown()).optional(),query:p.string().optional(),contentPreview:p.string().optional(),telemetry:p.record(p.unknown()).optional(),context:p.record(p.unknown()).optional(),mcpServer:p.string().min(1).max(255).optional()}),Va=p.object({version:p.string().min(1),dialect_version:p.number().int().optional(),min_dialect:p.number().int().optional(),shutdown:p.boolean().optional(),agent_mode:p.enum(["enforce","monitor","off"]).optional(),cognition_capture:p.boolean().optional(),agent_mode_by_operation:p.object({action:p.string().optional(),retrieval:p.string().optional(),delegation:p.string().optional()}).partial().optional(),agent_attributes:p.object({trust_tier:p.string().nullable().optional(),categories:p.array(p.string()).optional(),business_function:p.string().nullable().optional(),business_functions:p.array(p.string()).nullable().optional(),blast_radius_tier:p.string().nullable().optional(),no_coverage:p.string().nullable().optional(),fail_mode:p.string().nullable().optional()}).optional(),rules:p.array(p.record(p.unknown())),action_schemas:p.array(p.object({id:p.string(),plane:p.string().optional(),field_mappings:p.array(p.record(p.unknown())).optional(),derived_fields:p.array(p.record(p.unknown())).optional(),action_class:p.string().nullable().optional(),action_class_confidence:p.number().optional()})).optional(),no_coverage:p.object({no_coverage_defaults:p.record(p.string()),autopilot_enabled:p.boolean(),enduser_hitl_enabled:p.boolean(),hitl_timeout_seconds:p.number().optional()}).optional()});function Wa(e){let t=e.trust_tier??null,n=[];Array.isArray(e.business_functions)&&e.business_functions.length>0?n=e.business_functions:typeof e.business_function=="string"&&e.business_function!==""&&(n=[e.business_function]);let r=at(ot(n));return{trust_tier:Ye(t)?t:null,categories:Je(e.categories??[]),business_functions:r,business_function:r[0]??null,blast_radius_tier:typeof e.blast_radius_tier=="string"&&st(e.blast_radius_tier)?e.blast_radius_tier:null}}function Ha(e){if(!e)return null;let t={};for(let n of["action","retrieval","delegation"]){let r=e[n];(r==="enforce"||r==="monitor"||r==="off")&&(t[n]=r)}return Object.keys(t).length>0?t:null}function Ka(e){return e==="permit"?"permit":e==="mask"||e==="redact"?"mask":e==="approval_required"||e==="escalate"?"approval_required":"deny"}var se=new Set,nn=!1;async function rn(e){let t=[];for(let n of se){if(n.pendingTelemetryCount()>0&&!n.hasBackend()){console.warn(`[UnifiedRuntime] exiting with ${n.pendingTelemetryCount()} un-sent decision(s) and no backend \u2014 telemetry lost.`);continue}let r=n.flush();e&&t.push(r)}t.length>0&&await Promise.allSettled(t)}function Ya(){if(!nn&&!(typeof process>"u"||typeof process.once!="function")){nn=!0,process.once("beforeExit",()=>{rn(!1)});for(let e of["SIGINT","SIGTERM"])process.once(e,()=>{(async()=>{try{await rn(!0)}finally{process.kill(process.pid,e)}})()})}}var ln=class{client;originalFetch;resolvedApiKey;resolvedEndpoint;resolvedAgentId;harnessKind;sdkVersion;sdkDialect;rules=[];agentAttributes=null;agentNoCoverage=null;sessions=new Map;noCoverage=null;bundleVersion=null;bundleEtag=null;bundleLoaded=!1;bundleFetchInProgress=!1;initialBundlePromise=null;refreshTimer=null;cacheIdentity;bundleCacheDisabled;bundleGraceTtlMs;bundleCacheDirOverride;diskFallbackServed=!1;agentMode=Ba;agentModeByOperation=null;rawBundle=null;normalizedRefs={retrieval:[],action:[],delegation:[]};warnedNormalizedAbsent=!1;warnedNormalizedDrift=!1;lastNormalizedWarnRearmMs=0;agentModeConfirmed=!1;operatorShutdown=!1;bundleApplyFailed=!1;dialectRefused=!1;failMode=tn(typeof process<"u"?process.env?.VISIQ_FAIL_MODE:void 0)??za;governedFailMode=null;telemetryBuffer=[];telemetryTimer=null;cognitionBuffer=[];cognitionTimer=null;cognitionEnabled=process.env.VISIQ_COGNITION_CAPTURE==="1";envRegistered=!1;registerPromise=null;lastToolSurfaceSig=null;lastCloneCaptureSig=null;toolDescriptions=new Map;constructor(e,t,n,r,i,a,o,s){let l=e??process.env.VISIQ_API_KEY??process.env.ALLOW_API_KEY??process.env.VISIQ_ALLOW_API_KEY,c=t??process.env.VISIQ_ENDPOINT??process.env.ALLOW_ENDPOINT,u=n??process.env.VISIQ_AGENT_ID??process.env.ALLOW_AGENT_ID??"";this.resolvedApiKey=l,this.resolvedEndpoint=c,this.resolvedAgentId=u,this.harnessKind=r,this.sdkVersion=a,this.sdkDialect=o,this.originalFetch=globalThis.fetch.bind(globalThis);let h=ha(s);if(this.bundleCacheDisabled=_a(h.disabled),this.bundleGraceTtlMs=ga(h.graceTtlMs),this.bundleCacheDirOverride=h.cacheDir,this.cacheIdentity=l&&c&&!this.bundleCacheDisabled?{endpoint:c,agentId:u,apiKey:l}:null,l&&c){let f={apiKey:l,agentId:u,endpoint:c,mode:"enforce",timeoutMs:ca(i),hitlTimeoutMs:12e4,failBehavior:"closed",...r?{harnessKind:r}:{},...a!==void 0?{sdkVersion:a}:{},...o!==void 0?{sdkDialect:o}:{}};this.client=new Fe(f,this.originalFetch),this.initialBundlePromise=this.initialBundleLoad(),this.refreshTimer=setInterval(()=>{this.fetchBundleBackground()},Na),ae(this.refreshTimer),this.telemetryTimer=setInterval(()=>{this.flushTelemetry()},Ra),ae(this.telemetryTimer),this.cognitionTimer=setInterval(()=>{this.flushCognition()},Da),ae(this.cognitionTimer),se.add(this),Ya()}else this.client=null}async evaluate(e){let t=Ga.parse(e),n=Date.now();if(this.operatorShutdown){let m=this.denyAll(t,Ua);return this.applyAgentMode(m,"enforce",t,n)}if(this.dialectRefused){if(this.failMode==="open")return this.failOpen(t,en,n);let m=this.denyAll(t,en);return this.applyAgentMode(m,"enforce",t,n)}if(t.operations.every(m=>this.modeFor(m)==="off"))return this.offDecision(t);if(!this.bundleLoaded){let m;if(this.agentModeConfirmed?m=this.agentMode:this.bundleApplyFailed?m="enforce":m="monitor",m==="enforce"&&this.failMode==="open")return this.failOpen(t,"no unified bundle loaded and no local rules",n);let g=this.denyAll(t,"No unified bundle loaded and no local rules \u2014 fail-closed (G001)");return this.applyAgentMode(g,m,t,n)}let r=this.readSession(t.sessionId),i=await Ea();if(!i||!this.rawBundle){if(this.failMode==="open")return this.failOpen(t,"governance core (@visiq/core-wasm) unavailable",n);throw new Error("governance core (@visiq/core-wasm) unavailable \u2014 failing closed (G001)")}let a=t.operations.includes("action")||t.operations.includes("delegation")?Xe(t.normalized??{},{targetApp:t.targetResource??t.toolName??""}):t.normalized,o=this.buildActionSchemaEvent(t),s=t.mcpServer?{...a??{},mcp_server:t.mcpServer}:a,l={...t,normalized:s,session:r,at:Date.now(),action_schema_id:o.id,action_schema_raw:o.canonical},c={...this.rawBundle,agent_mode:this.agentMode,...this.agentModeByOperation?{agent_mode_by_operation:this.agentModeByOperation}:{}},u;try{u=i(l,c)}catch(m){if(this.failMode==="open")return this.failOpen(t,`governance core evaluation threw: ${m instanceof Error?m.message:String(m)}`,n);throw m}let h=[...new Set(t.operations.flatMap(m=>this.normalizedRefs[m]??[]))].sort();h.length>0&&Ta(t.normalized)&&(u.normalizedColdStart=h,this.warnedNormalizedAbsent||(this.warnedNormalizedAbsent=!0,console.warn(`[UNIFIED] no normalized event supplied, but ${h.length} loaded rule condition(s) on this event's operation(s) read input.normalized.* \u2014 those conditions resolve to undefined here, so a deny carrying one does not fire. (Builtin-derived paths such as context/app_category ARE still populated in-core, so this is a dependency report, not a proof that every listed condition was the decider.) Cold start / no action-schema mapping yet. Affected: ${h.slice(0,5).join("; ")}${h.length>5?`; +${h.length-5} more`:""}`)));let f=et(t.normalized);return f.length>0&&(u.normalizedDrift=f,this.warnedNormalizedDrift||(this.warnedNormalizedDrift=!0,console.warn(`[UNIFIED] normalized event carries ${f.length} value(s) outside the canonical vocabulary \u2014 a builder-authored rule can only select in-vocab values, so these cannot match one, so a rule keyed on the canonical value does not fire here. Check the harness classifier's casing/spelling. Affected: ${f.slice(0,5).join("; ")}${f.length>5?`; +${f.length-5} more`:""}`))),this.foldSession(t,u.enforced?u.decision:"permit"),u.enforced&&u.action.decision==="approval_required"&&await this.registerHitl(t,u),this.bufferTelemetry(t,u,Date.now()-n,u.enforced),u}modeFor(e){return this.agentModeByOperation?.[e]??this.agentMode}readSession(e){if(!e)return N;let t=this.sessions.get(e);return t?Date.now()-t.touchedAt>Fa?(this.sessions.delete(e),N):t.state:N}foldActionClass(e){let t=e.normalized?.action_class;if(typeof t=="string"&&t.length>0)return t;let n=this.rawBundle?.action_schemas;if(!Array.isArray(n))return;let{id:r}=this.buildActionSchemaEvent(e),i=n.find(s=>s?.id===r);if(!i)return;let a=i.action_class,o=typeof i.action_class_confidence=="number"?i.action_class_confidence:0;if(typeof a=="string"&&a.length>0&&o>=ja)return a}foldSession(e,t){let{sessionId:n}=e;if(!n)return;let r=this.readSession(n),i=e.resourceMetadata??{},a=e.operations.includes("retrieval"),o=e.operations.includes("action")||e.operations.includes("delegation"),s=nt(r===N?tt():r,{data_categories:a&&Array.isArray(i.data_categories)?i.data_categories:void 0,classification:a?i.classification:void 0,taint:a?qa(e.contentPreview,i):void 0,action_class:o?this.foldActionClass(e):void 0,target_app:o?e.targetResource??e.toolName:void 0,decision:t});if(this.sessions.delete(n),this.sessions.set(n,{state:s,touchedAt:Date.now()}),this.sessions.size>Pa){let l=this.sessions.keys().next().value;l!==void 0&&this.sessions.delete(l)}}applyAgentMode(e,t,n,r){let i=Date.now()-r;if(t==="enforce"){let o={...e,enforced:!0,agentMode:"enforce"};return this.bufferTelemetry(n,o,i,!0),o}let a={...e,allowed:!0,enforced:!1,agentMode:"monitor"};return this.bufferTelemetry(n,a,i,!1),a}setFailMode(e){this.failMode=e}getFailMode(){return this.failMode}getGovernedFailMode(){return this.governedFailMode}failOpen(e,t,n){let r=`fail-open: ${t} \u2014 proceeding UNGOVERNED (set VISIQ_FAIL_MODE=closed to block instead)`;console.error(`[VisIQ] FAIL-OPEN: ${t} \u2014 proceeding UNGOVERNED. Set VISIQ_FAIL_MODE=closed to block instead.`);let i=e.operations.includes("action")||e.operations.includes("delegation"),a=e.operations.includes("retrieval"),o={decision:"permit",allowed:!0,reason:r,ruleId:null,ruleCode:null,enforced:!1,agentMode:this.agentMode,action:i?{decision:"permit",allowed:!0}:{decision:null,allowed:!0},retrieval:a?{action:"allow"}:{action:null},failOpen:!0};return this.bufferTelemetry(e,o,Date.now()-n,!1,!0),o}reportFailOpen(e,t){try{let n={operations:["action"],agentId:this.resolvedAgentId,...t?.toolName?{toolName:t.toolName}:{},...t?.sessionId?{sessionId:t.sessionId}:{}},r={decision:"permit",allowed:!0,reason:`fail-open: ${e} \u2014 proceeding UNGOVERNED (set VISIQ_FAIL_MODE=closed to block instead)`,ruleId:null,ruleCode:null,enforced:!1,agentMode:this.agentMode,action:{decision:"permit",allowed:!0},retrieval:{action:null},failOpen:!0};this.bufferTelemetry(n,r,0,!1,!0)}catch{}}offDecision(e){let t=e.operations.includes("action")||e.operations.includes("delegation"),n=e.operations.includes("retrieval");return{decision:"permit",allowed:!0,reason:"agent_mode=off \u2014 evaluation bypassed",ruleId:null,ruleCode:null,enforced:!1,agentMode:"off",action:t?{decision:"permit",allowed:!0}:{decision:null,allowed:!0},retrieval:n?{action:"allow"}:{action:null}}}denyAll(e,t){let n=e.operations.includes("action")||e.operations.includes("delegation"),r=e.operations.includes("retrieval");return{decision:"deny",allowed:!1,reason:t,ruleId:null,ruleCode:null,enforced:!0,agentMode:"enforce",action:n?{decision:"deny",allowed:!1}:{decision:null,allowed:!0},retrieval:r?{action:"deny"}:{action:null}}}async registerHitl(e,t){if(this.client)try{let n={agent_id:e.agentId,target_app:e.targetResource??e.toolName??"",action:e.toolName??"",context:e.toolName?{[e.toolName]:e.toolArgs??{}}:{},action_schema_id:this.buildActionSchemaEvent(e).id,...e.sessionId?{session_id:e.sessionId}:{},...e.telemetry?{telemetry:e.telemetry}:{}},r=await this.client.evaluate(n);r.decision_id&&(t.action.decisionId=r.decision_id)}catch(n){console.warn("[UNIFIED] HITL registration failed \u2014 staying fail-closed (G001):",n)}}applyBundle(e){this.bundleApplyFailed=!0;let t=Va.parse(e);this.bundleApplyFailed=!1;let n=this.sdkDialect??1;if(t.min_dialect!==void 0&&t.min_dialect>n){this.dialectRefused=!0,this.bundleApplyFailed=!0,console.warn(`[UNIFIED] rules bundle requires dialect ${t.min_dialect} but this SDK speaks ${n} \u2014 refusing the bundle and failing closed (deny-all, G001). Upgrade the VisIQ SDK.`);return}let r=Ca(t.rules);if(r.length>0){this.dialectRefused=!0,this.bundleApplyFailed=!0,console.warn(`[UNIFIED] rules bundle contains rego_source using a builtin the engine cannot evaluate (would silently never match \u2192 fail open): ${r.join("; ")}. Refusing the bundle and failing closed (G001). Recompile the rule without case-folding wrappers like upper()/lower().`);return}this.dialectRefused=!1,!(this.bundleLoaded&&t.version===this.bundleVersion)&&(this.rules=t.rules.map(i=>ut(i)).filter(i=>i!==null),this.agentAttributes=t.agent_attributes?Wa(t.agent_attributes):null,this.agentNoCoverage=lt(t.agent_attributes?.no_coverage),this.governedFailMode=tn(t.agent_attributes?.fail_mode)??null,this.bundleVersion=t.version,this.bundleLoaded=!0,this.noCoverage=t.no_coverage?{no_coverage_defaults:t.no_coverage.no_coverage_defaults,autopilot_enabled:t.no_coverage.autopilot_enabled,enduser_hitl_enabled:t.no_coverage.enduser_hitl_enabled}:null,t.agent_mode!==void 0&&(this.agentMode=t.agent_mode,this.agentModeConfirmed=!0),this.agentModeByOperation=Ha(t.agent_mode_by_operation),process.env.VISIQ_COGNITION_CAPTURE==="1"?this.cognitionEnabled=!0:typeof t.cognition_capture=="boolean"&&(this.cognitionEnabled=t.cognition_capture),this.operatorShutdown=t.shutdown===!0,this.normalizedRefs=xa(this.rules),this.warnedNormalizedAbsent=!1,this.warnedNormalizedDrift=!1,this.lastNormalizedWarnRearmMs=Date.now(),this.rawBundle=e)}async awaitBundleReady(e=5e3){if(!this.initialBundlePromise||this.bundleLoaded)return;let t,n=new Promise(r=>{t=setTimeout(r,e)});try{await Promise.race([this.initialBundlePromise,n])}catch{}finally{t&&clearTimeout(t)}}async fetchBundleBackground(){if(!(this.bundleFetchInProgress||!this.resolvedEndpoint||!this.resolvedApiKey)){this.bundleFetchInProgress=!0;try{let e=this.resolvedAgentId?`?agent_id=${encodeURIComponent(this.resolvedAgentId)}`:"",t={Authorization:`Bearer ${this.resolvedApiKey}`,Accept:"application/json",...C(this.sdkVersion,this.sdkDialect)};this.bundleEtag&&(t["If-None-Match"]=this.bundleEtag);let n=await this.originalFetch(`${this.resolvedEndpoint}/rules/bundle${e}`,{method:"GET",headers:t});if(n.status===304){let o=Date.now();o-this.lastNormalizedWarnRearmMs>=Oa&&(this.lastNormalizedWarnRearmMs=o,this.warnedNormalizedAbsent=!1,this.warnedNormalizedDrift=!1);return}if(!n.ok)throw new Error(`unified bundle fetch failed: HTTP ${n.status}`);let r=n.headers.get("ETag"),i=await n.json();this.applyBundle(i);let a=this.bundleLoaded&&!this.dialectRefused&&!this.bundleApplyFailed;r&&a?this.bundleEtag=r:a||(this.bundleEtag=null),a&&await this.persistBundleToDisk(i)}catch(e){this.bundleLoaded?console.warn("[UNIFIED] Bundle refresh failed (using cached rules):",e):console.warn("[UNIFIED] Initial bundle fetch failed (fail-closed until loaded):",e)}finally{this.bundleFetchInProgress=!1}}}async initialBundleLoad(){await this.fetchBundleBackground(),this.bundleLoaded||await this.tryLoadFromDiskCache()}async tryLoadFromDiskCache(){if(this.bundleLoaded||this.bundleCacheDisabled||!this.cacheIdentity||this.dialectRefused)return;let e;try{e=await Ia(this.cacheIdentity,{...this.bundleCacheDirOverride?{cacheDir:this.bundleCacheDirOverride}:{}})}catch{return}if(!e)return;let t=Date.now();if(va(e,this.bundleGraceTtlMs,t)){try{this.applyBundle(e.body)}catch{return}if(this.bundleLoaded&&!this.dialectRefused&&!this.diskFallbackServed){this.diskFallbackServed=!0;let n=Math.max(0,Math.round((t-e.fetchedAt)/1e3)),r=Math.round(this.bundleGraceTtlMs/1e3);console.warn(`[UnifiedRuntime] serving cached rules bundle (age ${n}s) \u2014 control plane unreachable on cold start; will keep retrying and fail closed once the cache exceeds the ${r}s grace window.`)}}}async persistBundleToDisk(e){this.bundleCacheDisabled||!this.cacheIdentity||await Sa(this.cacheIdentity,e,this.bundleVersion,{...this.bundleCacheDirOverride?{cacheDir:this.bundleCacheDirOverride}:{}})}hasRules(){return this.bundleLoaded&&this.rules.length>0}hasClient(){return this.client!==null}getEndpoint(){return this.resolvedEndpoint}getApiKey(){return this.resolvedApiKey}getBundleVersion(){return this.bundleVersion}isBundleLoaded(){return this.bundleLoaded}getAgentMode(){return this.agentMode}getAgentAttributes(){return this.agentAttributes}getSessionState(e){return this.readSession(e)}registerEnvironment(e){!this.client||this.envRegistered||!this.resolvedAgentId||(this.envRegistered=!0,this.registerPromise=this.client.registerEnvironment(e))}registerHostEnvironment(e,t){this.registerEnvironment({...K(),...e?{agent_type:e}:{},...t?.model?{model:t.model}:{},...t?.systemPrompt?{systemPrompt:t.systemPrompt}:{},...t?.toolSchemas&&t.toolSchemas.length>0?{toolSchemas:t.toolSchemas}:{}})}reportToolSurface(e){if(!this.client||!this.resolvedAgentId||e.length===0)return;let t=JSON.stringify([...e].map(n=>({n:n.name,d:n.description??"",s:n.input_schema??null})).sort((n,r)=>n.n.localeCompare(r.n)));for(let n of e)n.description&&this.toolDescriptions.set(n.name,n.description);t!==this.lastToolSurfaceSig&&(this.lastToolSurfaceSig=t,this.client.reportToolSurface(e))}captureCloneMetadata(e){if(!this.client||!this.resolvedAgentId||!(e.model||e.systemPrompt||(e.toolSchemas?.length??0)>0))return;let t=JSON.stringify({m:e.model??"",s:e.systemPrompt??"",t:e.toolSchemas??[]});t!==this.lastCloneCaptureSig&&(this.lastCloneCaptureSig=t,this.client.registerEnvironment({...K(),...e.agentType?{agent_type:e.agentType}:{},...e.model?{model:e.model}:{},...e.systemPrompt?{systemPrompt:e.systemPrompt}:{},...e.toolSchemas&&e.toolSchemas.length>0?{toolSchemas:e.toolSchemas}:{}}))}buildActionSchemaEvent(e){let t=e.toolName?this.toolDescriptions.get(e.toolName):void 0,n={agent_id:e.agentId,operations:e.operations,...e.toolName?{tool_name:e.toolName}:{},...e.targetResource?{target_resource:e.targetResource}:{},...e.resourceType?{resource_type:e.resourceType}:{},...e.toolArgs?{tool_args:e.toolArgs}:{},...t?{tool_description:t}:{}},r=ct(n),i={...n};return e.toolArgs&&(i.tool_args=jt(e.toolArgs)),{canonical:n,id:r,rawEventForWire:i}}bufferTelemetry(e,t,n,r,i=!1){let a=this.buildActionSchemaEvent(e);this.telemetryBuffer.push({decision_id:crypto.randomUUID(),agent_id:e.agentId,target_app:e.targetResource??e.toolName??"",action:e.toolName??e.operations.join("+"),...e.sessionId?{session_id:e.sessionId}:{},decision:r?Ka(t.decision):"permit",reason:t.reason,evaluated_at:new Date().toISOString(),rule_id:t.ruleId,rule_code:t.ruleCode,enforced:r,agent_mode:this.agentMode,latency_ms:n,evaluation_mode:"local",raw_event:a.rawEventForWire,action_schema_id:a.id,...this.harnessKind||e.context||i||t.normalizedColdStart||t.normalizedDrift?{context:{...this.harnessKind?{[Le]:this.harnessKind}:{},...e.context??{},...i?{fail_open:!0}:{},...t.normalizedColdStart?{normalized_cold_start:!0,normalized_inert_conditions:t.normalizedColdStart.length}:{},...t.normalizedDrift?{normalized_drift:!0,normalized_drift_values:t.normalizedDrift.length,normalized_drift_fields:t.normalizedDrift.slice(0,La)}:{}}}:{}}),this.enforceTelemetryCap(),this.telemetryBuffer.length>=$a&&this.flushTelemetry()}pendingTelemetryCount(){return this.telemetryBuffer.length}hasBackend(){return this.client!==null}async flushTelemetry(){if(this.telemetryBuffer.length===0||!this.client)return;let e=this.telemetryBuffer.splice(0);try{await this.client.sendTelemetry(e)}catch(t){console.error("[UnifiedRuntime] telemetry flush failed (non-fatal):",t)}}enforceTelemetryCap(){let e=this.telemetryBuffer.length-Qt;e>0&&(this.telemetryBuffer.splice(0,e),console.warn(`[UnifiedRuntime] telemetry buffer full \u2014 dropped ${e} oldest entries (cap ${Qt})`))}isCognitionEnabled(){return this.cognitionEnabled}emitCognition(e){!this.cognitionEnabled||!this.client||(this.cognitionBuffer.push(la(e)),this.enforceCognitionCap(),this.cognitionBuffer.length>=Ma&&this.flushCognition())}async flushCognition(){if(this.cognitionBuffer.length===0||!this.client)return;let e=this.cognitionBuffer.splice(0);try{await this.client.sendCognition(void 0,e)}catch(t){console.error("[UnifiedRuntime] cognition flush failed (non-fatal):",t)}}enforceCognitionCap(){let e=this.cognitionBuffer.length-Xt;e>0&&(this.cognitionBuffer.splice(0,e),console.warn(`[UnifiedRuntime] cognition buffer full \u2014 dropped ${e} oldest beats (cap ${Xt})`))}async flush(){if(this.registerPromise)try{await this.registerPromise}catch{}await this.flushTelemetry(),await this.flushCognition()}async shutdown(){await this.flush(),this.dispose(),se.delete(this)}dispose(){this.refreshTimer&&(clearInterval(this.refreshTimer),this.refreshTimer=null),this.telemetryTimer&&(clearInterval(this.telemetryTimer),this.telemetryTimer=null),this.cognitionTimer&&(clearInterval(this.cognitionTimer),this.cognitionTimer=null),this.flushTelemetry(),this.flushCognition()}};function ae(e){e&&typeof e=="object"&&"unref"in e&&e.unref()}var Xa="https://api.visiqlabs.com",eo="@visiq/claude-code-harness",ce="open";function ue(e){if(typeof e!="string")return;let t=e.trim().toLowerCase();return t==="open"||t==="closed"?t:void 0}function D(){let e=process.env.VISIQ_HOME;return e&&e.trim().length>0?e:le(dn(),".visiq","claude-code")}function pn(){return le(D(),"config.json")}function to(e){return e==="~"||e.startsWith("~/")?le(dn(),e.slice(1).replace(/^\//,"")):e}async function no(e){try{let t=Ja(e)?e:Qa(e),n=await Za(t,"utf-8");return JSON.parse(n)}catch{return null}}function G(e,...t){for(let n of t){let r=e[n];if(typeof r=="string"&&r.length>0)return r}}function cn(e){if(!e||typeof e!="object")return{};let t=e,n={},r=G(t,"apiKey","api_key"),i=G(t,"agentId","agent_id"),a=G(t,"baseUrl","base_url"),o=ue(G(t,"failMode","fail_mode"));return r&&(n.apiKey=r),i&&(n.agentId=i),a&&(n.baseUrl=a),o&&(n.failMode=o),n}async function un(e){if(!e)return{};let t=await no(to(e));if(!t||typeof t!="object")return{};let n=t,r=n.plugins?.entries,i=r&&typeof r=="object"?r[eo]:void 0;return i&&typeof i=="object"&&i.config?cn(i.config):cn(n)}function fn(e=process.env){let t={};e.VISIQ_API_KEY&&(t.apiKey=e.VISIQ_API_KEY),e.VISIQ_AGENT_ID&&(t.agentId=e.VISIQ_AGENT_ID),e.VISIQ_BASE_URL?t.baseUrl=e.VISIQ_BASE_URL:e.VISIQ_ENDPOINT&&(t.baseUrl=e.VISIQ_ENDPOINT);let n=ue(e.VISIQ_FAIL_MODE);return n&&(t.failMode=n),t}function mn(e,t,n){let r={...e,...t,...n};if(!r.apiKey||!r.agentId)return null;let i={apiKey:r.apiKey,agentId:r.agentId,failMode:r.failMode??ce};return i.baseUrl=r.baseUrl||Xa,i}async function ro(){let e=fn(),t=await un(process.env.VISIQ_CONFIG_PATH),n=await un(pn()),r={...n,...t,...e};return{config:mn(n,t,e),failMode:r.failMode??ce}}var de="0.1.10",pe=3e4,lo=4e3;function gn(e){return e.replace(/[^a-zA-Z0-9._-]/g,"_").slice(0,200)||"default"}function co(e){let t=so("sha1").update(e).digest("hex").slice(0,10);return`${gn(e)}-${t}`}function fe(e,t,n){return n-e.fetchedAt<t}function _n(e){return hn(D(),"bundles",`${co(e)}.json`)}async function me(e){try{let t=await ao(_n(e),"utf-8"),n=JSON.parse(t);return n&&typeof n.fetchedAt=="number"&&"body"in n?n:null}catch{return null}}async function he(e,t,n){try{let r=_n(e);await io(hn(D(),"bundles"),{recursive:!0});let i={fetchedAt:Date.now(),version:n,body:t};await oo(r,JSON.stringify(i),{mode:384})}catch{}}async function ge(e,t,n){try{let r=`${e.replace(/\/+$/,"")}/rules/bundle?agent_id=${encodeURIComponent(n)}`,i=await fetch(r,{method:"GET",headers:{Authorization:`Bearer ${t}`,Accept:"application/json",...C(de,E)},signal:AbortSignal.timeout(lo)});if(!i.ok)return null;let a=i.headers.get("etag");return{body:await i.json(),version:a}}catch{return null}}import{appendFile as Ps,mkdir as Fs}from"node:fs/promises";import{join as Bs}from"node:path";var fo=new Set(["WebFetch","WebSearch","Read","Grep","Glob","LSP","NotebookRead","ListMcpResourcesTool","ReadMcpResourceTool"]),mo=/(^|_)(search|fetch|read|list|get|query|retrieve|lookup|find|describe|download|export|dump)(_|$)/i;function yn(e){if(typeof e!="string"||!e.startsWith("mcp__"))return typeof e=="string"?e:"";let t=e.lastIndexOf("__");return t>=0?e.slice(t+2):e}function bn(e){return typeof e!="string"?!1:fo.has(e)?!0:e.startsWith("mcp__")?mo.test(yn(e)):!1}function ye(e){return bn(e)?["retrieval","action"]:["action"]}var ho=["query","q","url","prompt","pattern","file_path","path"];function be(e){if(!e||typeof e!="object")return;let t=e,n=[];for(let r of ho){let i=t[r];typeof i=="string"&&i.length>0&&n.push(i)}return n.length>0?n.join(" "):void 0}var vn="cli_harness";function go(e){let t=new ln(e.apiKey,e.baseUrl,e.agentId,vn,void 0,de,E);return t.setFailMode(e.failMode),t}function ve(e){let t={operations:e.operations,agentId:e.agentId,toolName:e.toolName,toolArgs:e.toolInput,resourceType:"tool_result",resourceMetadata:{toolName:e.toolName,...e.toolUseId?{toolCallId:e.toolUseId}:{},...e.sessionId?{sessionId:e.sessionId}:{},...e.cwd?{cwd:e.cwd}:{}}};return e.query&&(t.query=e.query),e.context&&(t.context=e.context),t}async function _o(e,t,n=pe){let{agentId:r}=t,i=await me(r);if(i&&fe(i,n,Date.now())&&_e(e,i.body))return!0;let a=e.getEndpoint();if(a){let o=await ge(a,t.apiKey,r);if(o&&_e(e,o.body))return await he(r,o.body,o.version),!0}if(i&&_e(e,i.body))return!0;try{await e.awaitBundleReady(2500)}catch{}return e.isBundleLoaded()}function _e(e,t){try{return e.applyBundle(t),!0}catch{return!1}}async function yo(e){try{await e.flush()}catch{}try{e.dispose()}catch{}}var bo="visiq_surface";function vo(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:e===void 0?{}:{value:e}}function wn(e){let{call:t,agentId:n,surface:r,session:i}=e,a=ye(t.toolName),o=vo(t.toolInput),s=be(t.toolInput),l={[bo]:r,cowork:{mode:"monitor",sessionKey:i?.sessionKey,accountId:i?.accountId,orgId:i?.orgId,model:t.model,parentToolUseId:t.parentToolUseId,observedAt:t.timestamp}};return{event:ve({operations:a,agentId:n,toolName:t.toolName,toolInput:o,sessionId:t.sessionId,toolUseId:t.toolUseId,...s?{query:s}:{},context:l}),operations:a,enforceable:!1}}import{open as wo,readdir as Ao,readFile as ko,stat as An,writeFile as So,mkdir as Io}from"node:fs/promises";import{dirname as Eo}from"node:path";var Co=4*1024*1024;function V(e,t){let n=e.includes("\\")&&!e.includes("/")?"\\":"/";return`${e}${e.endsWith(n)?"":n}${t}`}async function xo(e,t){let n=[];for(let r of await e.readdir(t)){let i=V(t,r);for(let a of await e.readdir(i)){let o=V(i,a);for(let s of await e.readdir(o)){let l=V(o,s),c=Ae(l);if(c)for(let u of ke(await e.readdir(l)))n.push({path:V(l,u),session:c})}}}return n}async function vl(e){let t=e.surface??"cowork_vm",{state:n}=e,r=new Set,i=[],a={logsScanned:0,eventsSeen:0,duplicates:0,corruptLines:0,restarts:0,truncatedLines:0};for(let s of await xo(e.fs,e.root)){let l=await e.fs.size(s.path);if(l===null)continue;a.logsScanned+=1;let c=await e.fs.identity?.(s.path),u=Ce(n,s.path,l,c);if(u.restarted&&(a.restarts+=1),l<=u.offset){n={...n,cursors:{...n.cursors,[s.path]:{offset:u.offset,remainder:u.remainder,...c===void 0?{}:{identity:c}}}},r.add(s.path);continue}let{text:h,bytes:f}=await e.fs.read(s.path,u.offset,Math.min(l-u.offset,e.maxReadBytes??Co));if(f<=0)continue;let m=xe(n,s.path,{startOffset:u.offset,bytesRead:f,carriedRemainder:u.remainder,chunk:h,identity:c});r.add(s.path),{state:n}=m,a.duplicates+=m.duplicates,a.corruptLines+=m.skipped,a.truncatedLines+=m.truncated?1:0;for(let g of m.events)a.eventsSeen+=1,g.kind==="tool_call"&&i.push(wn({call:g,agentId:e.agentId,surface:t,session:s.session}))}let o={};for(let s of r){let l=n.cursors[s];l&&(o[s]=l)}return n={...n,cursors:o},{state:n,observations:i,stats:a}}async function wl(e,t){let n=await e.readFile(t);if(n===null)return M();try{return Ne(JSON.parse(n))}catch{return M()}}async function Al(e,t,n){try{await e.writeFile(t,JSON.stringify(n))}catch{}}function To(e){let t=e.lastIndexOf(10);return t===-1?e.length:t+1}function kl(){return{async readdir(e){try{return await Ao(e)}catch{return[]}},async size(e){try{let t=await An(e);return t.isFile()?t.size:null}catch{return null}},async identity(e){try{let t=await An(e);return`${t.dev}:${t.ino}`}catch{return}},async read(e,t,n){if(n<=0)return{text:"",bytes:0};let r;try{r=await wo(e,"r");let i=Buffer.alloc(n),{bytesRead:a}=await r.read(i,0,n,t),o=To(i.subarray(0,a));return{text:i.subarray(0,o).toString("utf8"),bytes:o}}catch{return{text:"",bytes:0}}finally{await r?.close().catch(()=>{})}},async readFile(e){try{return await ko(e,"utf8")}catch{return null}},async writeFile(e,t){await Io(Eo(e),{recursive:!0}),await So(e,t,"utf8")}}}var Il="0.1.0";export{Sn as a,No as b,Oo as c,Ro as d,$o as e,Do as f,we as g,Lo as h,Nn as i,Po as j,Ae as k,Rn as l,$n as m,Dn as n,ke as o,jo as p,Se as q,Mn as r,Ie as s,H as t,Ee as u,M as v,Ce as w,xe as x,Te as y,Ne as z,Oe as A,Fn as B,jn as C,Bn as D,ro as E,go as F,_o as G,yo as H,bo as I,vo as J,wn as K,Co as L,xo as M,vl as N,wl as O,Al as P,To as Q,kl as R,Il as S};
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+ import{A as $,B as I,C,D as P,E as w,F as R,G as O,H as V,M as x,N,O as M,P as Q,R as h,S as q,b as S,c as f,e as g,f as y,j as p}from"../chunk-75KSV3E4.js";import{homedir as m,platform as H}from"node:os";import{dirname as A,join as v}from"node:path";import{readFile as _,writeFile as D,mkdir as U}from"node:fs/promises";import{existsSync as G}from"node:fs";import{parseArgs as J}from"node:util";function L(){let n=process.env.VISIQ_HOME,e=n&&n.trim().length>0?n:v(m(),".visiq","claude-cowork");return v(e,"monitor-state.json")}function b(n){let e=n.settings;return typeof e=="string"&&e.length>0?e:v(m(),".claude","settings.json")}async function k(n){if(!G(n))return{};try{let e=JSON.parse(await _(n,"utf-8"));return e&&typeof e=="object"?e:{}}catch{return{}}}async function T(n,e){await U(A(n),{recursive:!0}),await D(n,`${JSON.stringify(e,null,2)}
3
+ `,"utf-8")}async function K(n){let e=b(n),s=typeof n.command=="string"?n.command:$;return await T(e,I(await k(e),s)),process.stdout.write(`[VisIQ] Installed Claude Cowork governance hooks \u2192 ${e}
4
+ Covers HOST-LOCAL Cowork sessions (pre-execution enforcement).
5
+ VM-sandboxed sessions are NOT hook-reachable \u2014 run \`visiq-claude-cowork monitor\`
6
+ for monitor-only coverage of those.
7
+ Next: \`visiq-claude-code configure\` (shared credentials), then restart Claude.
8
+ `),0}async function z(n){let e=b(n),s=typeof n.command=="string"?n.command:void 0;return await T(e,C(await k(e),s)),process.stdout.write(`[VisIQ] Removed Claude Cowork governance hooks from ${e}
9
+ `),0}function E(n,e){let s=` ${g(n)}:`;return f(n)?`${s} ${e.installed?"ENFORCED (PreToolUse deny blocks)":"not covered \u2014 run `visiq-claude-cowork install`"}`:`${s} monitor-only \u2014 ${e.sessions} session(s), ${e.logs} audit log(s)`}async function B(n){let e=h(),{config:s}=await w(),o=b(n),i=P(await k(o)),d=p({homeDir:m(),platform:H(),env:process.env}),u=await x(e,d),a=new Set(u.map(l=>l.session.sessionKey)),c={installed:i,sessions:a.size,logs:u.length},r=S(y()),t=[`[VisIQ] Claude Cowork harness ${q} \u2014 status`,` this process: ${g(r)}${f(r)?"":" (cannot enforce)"}`,` credentials: ${s?"resolved":"MISSING (run `visiq-claude-code configure`)"}`,` agent id: ${s?.agentId??"\u2014"}`,` hooks: ${i?"installed":"not installed"} \u2014 ${o}`,E("cowork_desktop",c),E("cowork_vm",c),` session tree: ${d}`,` monitor state: ${L()}`];return process.stdout.write(`${t.join(`
10
+ `)}
11
+ `),s?0:1}async function W(n){let{config:e}=await w();if(!e)return process.stderr.write("[VisIQ] monitor needs credentials \u2014 run `visiq-claude-code configure` first.\n"),1;let s=h(),o=p({homeDir:m(),platform:H(),env:process.env}),i=L(),d=n.once===!0,u=Math.max(1e3,Number.parseInt(String(n.interval??"15000"),10)||15e3);process.stdout.write(`[VisIQ] Monitoring Claude Cowork sandbox sessions (monitor-only; hooks cover host-local).
12
+ tree: ${o}
13
+ `);let a=!1,c=()=>{a=!0};process.on("SIGINT",c),process.on("SIGTERM",c);do{let r=await M(s,i);try{let t=await N({fs:s,root:o,agentId:e.agentId,state:r});if({state:r}=t,t.observations.length>0){let l=R(e);try{await O(l,e);for(let j of t.observations)await l.evaluate(j.event)}finally{await V(l)}}await Q(s,i,r),process.stdout.write(`[VisIQ] scanned ${t.stats.logsScanned} log(s): ${t.observations.length} new tool call(s), ${t.stats.duplicates} duplicate(s), ${t.stats.corruptLines} corrupt line(s)
14
+ `)}catch(t){process.stderr.write(`[VisIQ] monitor pass failed (continuing): ${t instanceof Error?t.message:String(t)}
15
+ `)}if(d||a)break;await new Promise(t=>{setTimeout(t,u)})}while(!a);return 0}function F(){process.stdout.write(`Usage: visiq-claude-cowork <install|uninstall|status|monitor> [flags]
16
+
17
+ install [--settings <path>] [--command <cmd>] host-local enforcement
18
+ uninstall [--settings <path>]
19
+ status what is covered, and how
20
+ monitor [--once] [--interval <ms>] sandbox monitor-only coverage
21
+
22
+ Credentials are shared with @visiq/claude-code-harness:
23
+ visiq-claude-code configure --api-key <key> --agent-id <id>
24
+ `)}async function X(){let{positionals:n,values:e}=J({args:process.argv.slice(2),options:{settings:{type:"string"},command:{type:"string"},once:{type:"boolean"},interval:{type:"string"}},strict:!1,allowPositionals:!0}),s=e,o=0;switch(n[0]){case"install":o=await K(s);break;case"uninstall":o=await z(s);break;case"status":o=await B(s);break;case"monitor":o=await W(s);break;case"help":case void 0:F();break;default:process.stderr.write(`[VisIQ] Unknown command: ${n[0]}
25
+ `),F(),o=1}process.exit(o)}X().catch(n=>{process.stderr.write(`[VisIQ] ${n instanceof Error?n.message:String(n)}
26
+ `),process.exit(1)});export{L as monitorStatePath};
@@ -0,0 +1,553 @@
1
+ /**
2
+ * Which Claude surface is this process governing?
3
+ *
4
+ * Claude Cowork is built on Claude Code, so a governed session can be running in
5
+ * one of three places — and they are NOT interchangeable for governance:
6
+ *
7
+ * claude_code_cli The standalone `claude` CLI on the user's PATH. Hooks fire;
8
+ * pre-execution deny works. Covered by @visiq/claude-code-harness.
9
+ * cowork_desktop The Claude desktop app's HOST-LOCAL agent. The app spawns its
10
+ * own bundled `claude` natively, and that process reads the SAME
11
+ * `~/.claude/settings.json` — so our hooks fire and a PreToolUse
12
+ * deny hard-blocks the call. Same mechanism, different product
13
+ * surface, and the customer needs them told apart.
14
+ * cowork_vm A Cowork session inside the app's Linux sandbox VM. The guest
15
+ * gets its own per-session config dir (`mnt/.claude`, under a
16
+ * per-session root) which carries NO settings.json,
17
+ * which carries NO settings.json, so host hooks can never fire
18
+ * here. This surface is covered monitor-only, off the host-side
19
+ * audit stream (see audit-stream.ts) — never claim enforcement.
20
+ *
21
+ * Classification is a PURE function of injected facts so every branch is unit
22
+ * testable without a Claude install; `surfaceFactsFromProcess` is the only impure
23
+ * part and it merely snapshots `process`.
24
+ */
25
+ /** The Claude surface a governed session is executing on. */
26
+ export type ClaudeSurface = "claude_code_cli" | "cowork_desktop" | "cowork_vm" | "unknown";
27
+ /**
28
+ * Env var the desktop app sets ONLY on the VM CLI runner, carrying the HOST's
29
+ * platform (so guest code can reason about the host it is sandboxed from). Its
30
+ * presence is the single most reliable in-guest signal.
31
+ */
32
+ export declare const HOST_PLATFORM_ENV = "CLAUDE_CODE_HOST_PLATFORM";
33
+ /** Facts a surface decision is made from. All optional so partial probes work. */
34
+ export interface SurfaceFacts {
35
+ /**
36
+ * Absolute executable paths for the process and (ideally) its ancestors,
37
+ * nearest-first. A hook subprocess should include its PARENT `claude` binary —
38
+ * `process.execPath` alone is just `node`.
39
+ */
40
+ processPaths?: readonly string[];
41
+ env?: Readonly<Record<string, string | undefined>>;
42
+ /** The Claude config dir in effect for this session, when known. */
43
+ configDir?: string | undefined;
44
+ /** The platform this code is actually running on (`process.platform`). */
45
+ platform?: string | undefined;
46
+ }
47
+ /**
48
+ * Classify the surface. Order is deliberate and load-bearing:
49
+ *
50
+ * 1. GUEST first — inside the sandbox the binary is also called `claude` and
51
+ * also sits under a `claude-code`-ish path, so a later check would misread
52
+ * it as desktop/CLI and over-claim enforcement on a surface that has none.
53
+ * 2. DESKTOP next — its bundled path contains `claude-code`, which the generic
54
+ * CLI test would otherwise swallow.
55
+ * 3. CLI last — the residual "some `claude` binary" case.
56
+ */
57
+ export declare function classifySurface(facts: SurfaceFacts): ClaudeSurface;
58
+ /** Is this surface one where a PreToolUse deny actually stops the tool call? */
59
+ export declare function surfaceSupportsEnforcement(surface: ClaudeSurface): boolean;
60
+ /** Is this surface a Claude Cowork surface (as opposed to the bare CLI)? */
61
+ export declare function isCoworkSurface(surface: ClaudeSurface): boolean;
62
+ /**
63
+ * Human-readable label for CLI output and telemetry. Kept beside the type so a
64
+ * new surface cannot be added without a label.
65
+ */
66
+ export declare function surfaceLabel(surface: ClaudeSurface): string;
67
+ /** Snapshot the ambient process into SurfaceFacts. The only impure part. */
68
+ export declare function surfaceFactsFromProcess(proc?: {
69
+ execPath?: string;
70
+ argv?: readonly string[];
71
+ env?: NodeJS.ProcessEnv;
72
+ platform?: string;
73
+ }, extraPaths?: readonly string[]): SurfaceFacts;
74
+ /**
75
+ * Pure model of Claude Cowork's on-disk session layout.
76
+ *
77
+ * Cowork keeps per-session state on the HOST even when the agent itself runs in
78
+ * the sandbox VM — which is precisely why the VM surface is observable at all:
79
+ *
80
+ * <appSupport>/Claude/local-agent-mode-sessions/
81
+ * <accountId>/<orgId>/
82
+ * cowork_settings.json
83
+ * local_<uuid>.json ← session state/transcript
84
+ * local_<uuid>/
85
+ * audit.jsonl ← the ACTIVE stream (see audit-stream.ts)
86
+ * audit1.jsonl ← rotated, logrotate-style: HIGHER N is OLDER
87
+ * .claude/ ← mirror of the guest's per-session config dir
88
+ * outputs/ uploads/
89
+ *
90
+ * `local-agent-mode-sessions` is the on-disk name; "local agent mode" is what
91
+ * Cowork was called before it was renamed, and the directory name never followed.
92
+ * Do not "fix" it.
93
+ *
94
+ * Everything here is a pure path/string computation so the layout contract is
95
+ * unit-tested without needing a Claude install on the runner.
96
+ */
97
+ /** Directory name Cowork uses for its per-session state (pre-rename spelling). */
98
+ export declare const COWORK_SESSIONS_DIRNAME = "local-agent-mode-sessions";
99
+ /** Directory name the desktop app uses for host-local Claude Code sessions. */
100
+ export declare const DESKTOP_SESSIONS_DIRNAME = "claude-code-sessions";
101
+ /** A parsed Cowork session directory. */
102
+ export interface CoworkSessionRef {
103
+ accountId: string;
104
+ orgId: string;
105
+ /** The `local_<uuid>` directory name, used as the stable session key. */
106
+ sessionKey: string;
107
+ }
108
+ /**
109
+ * Root of the Claude desktop app's support directory, per platform.
110
+ *
111
+ * macOS is the surface we verified end-to-end. The Windows/Linux forms follow
112
+ * the same convention the desktop app uses for `claude_desktop_config.json`
113
+ * (mirrored from the discovery agent's own path table) — they are the documented
114
+ * Electron conventions, not guesses, but only macOS is empirically confirmed.
115
+ */
116
+ export declare function claudeSupportDir(opts: {
117
+ homeDir: string;
118
+ platform: string;
119
+ env?: Readonly<Record<string, string | undefined>>;
120
+ }): string;
121
+ /** Directory holding every Cowork session's host-side state. */
122
+ export declare function coworkSessionsRoot(opts: {
123
+ homeDir: string;
124
+ platform: string;
125
+ env?: Readonly<Record<string, string | undefined>>;
126
+ }): string;
127
+ /**
128
+ * Parse a path that may be (or sit under) a Cowork session directory.
129
+ * Returns null when the path does not match the `<account>/<org>/local_<uuid>`
130
+ * shape — callers MUST treat null as "not a Cowork session", never as an error.
131
+ */
132
+ export declare function parseSessionDir(path: string): CoworkSessionRef | null;
133
+ /** Is this directory name a Cowork session key (`local_<uuid>`)? */
134
+ export declare function isSessionKey(name: string): boolean;
135
+ /** Is this file name one of a session's audit logs? */
136
+ export declare function isAuditLogName(name: string): boolean;
137
+ /**
138
+ * Rotation index for an audit log name. `audit.jsonl` is index 0 and each
139
+ * rotation pushes the previous content out to the next integer — the logrotate
140
+ * convention, so a HIGHER index is OLDER and DESCENDING index is chronological.
141
+ *
142
+ * MEASURED, not assumed. An earlier version of this module asserted the opposite
143
+ * ("ASCENDING index is chronological") from two mtimes alone, and mtime is the one
144
+ * signal that lies here — rotation rewrites the archived file, so audit1.jsonl
145
+ * carried the NEWER mtime while holding the OLDER records. Read against the real
146
+ * 7,944-record session this module cites:
147
+ *
148
+ * audit1.jsonl 2026-02-08T16:56:28.378Z → 2026-02-09T00:56:28.416Z
149
+ * audit.jsonl 2026-02-09T00:56:32.573Z → 2026-02-16T17:51:46.190Z
150
+ *
151
+ * audit1 ends 4.157s BEFORE audit.jsonl begins. Returns null for a non-audit name.
152
+ */
153
+ export declare function auditLogIndex(name: string): number | null;
154
+ /**
155
+ * Order audit log names oldest→newest and drop anything that isn't one. Reading
156
+ * them in this order is what makes a resumed tail reconstruct the session in the
157
+ * sequence it actually happened.
158
+ *
159
+ * DESCENDING by index, because a higher rotation number is OLDER (see
160
+ * {@link auditLogIndex}). Sorting the other way replays a rotated session
161
+ * backwards — which is what this function did until the chronology was measured
162
+ * against a real rotated session rather than inferred from mtimes.
163
+ */
164
+ export declare function orderAuditLogs(names: readonly string[]): string[];
165
+ /**
166
+ * Pure parsing + normalization of Cowork's per-session `audit.jsonl`.
167
+ *
168
+ * This is the ONLY governance seam that survives the sandbox boundary: a Cowork
169
+ * session running in the VM still writes a full NDJSON audit stream to the host,
170
+ * carrying the model, every tool call with its inputs (built-in AND `mcp__*`),
171
+ * every tool result, and natural-language tool summaries.
172
+ *
173
+ * It is written AFTER the fact, so what it supports is MONITORING — never
174
+ * pre-execution enforcement. Nothing in this module may be used to claim a block.
175
+ *
176
+ * Record shapes (observed on a real 7,944-record session):
177
+ * {"type":"assistant","message":{"model":…,"content":[{"type":"tool_use","id","name","input"}|{"type":"text"…}]},
178
+ * "parent_tool_use_id":…,"session_id":…,"uuid":…,"_audit_timestamp":…}
179
+ * {"type":"user","message":{"content":[{"type":"tool_result","tool_use_id",…,"is_error"?}]},…}
180
+ * {"type":"tool_use_summary","summary":…,"preceding_tool_use_ids":[…],…}
181
+ * {"type":"result"|"system",…}
182
+ *
183
+ * Everything here is total: malformed JSON, unexpected shapes and truncated
184
+ * writes yield fewer events, never a throw. A monitor that crashes on a partial
185
+ * line is worse than one that skips it.
186
+ */
187
+ /** A tool call the agent issued. The governance-relevant event. */
188
+ export interface CoworkToolCallEvent {
189
+ kind: "tool_call";
190
+ uuid: string;
191
+ sessionId: string;
192
+ toolUseId: string;
193
+ toolName: string;
194
+ toolInput: unknown;
195
+ model?: string | undefined;
196
+ /** Set when the call came from a sub-agent rather than the root loop. */
197
+ parentToolUseId?: string | undefined;
198
+ timestamp?: string | undefined;
199
+ }
200
+ /** The result that came back for a tool call. */
201
+ export interface CoworkToolResultEvent {
202
+ kind: "tool_result";
203
+ uuid: string;
204
+ sessionId: string;
205
+ toolUseId: string;
206
+ isError: boolean;
207
+ timestamp?: string | undefined;
208
+ }
209
+ /** A turn/session terminated. */
210
+ export interface CoworkResultEvent {
211
+ kind: "session_result";
212
+ uuid: string;
213
+ sessionId: string;
214
+ timestamp?: string | undefined;
215
+ }
216
+ export type CoworkAuditEvent = CoworkToolCallEvent | CoworkToolResultEvent | CoworkResultEvent;
217
+ /**
218
+ * Hard ceiling on a single buffered line. A live `audit.jsonl` is appended to
219
+ * while we read it, so a partial trailing line is NORMAL and gets carried to the
220
+ * next chunk — but a corrupt/never-terminated line must not grow the buffer
221
+ * without bound. Past this we drop the partial and resync at the next newline.
222
+ */
223
+ export declare const MAX_BUFFERED_LINE_BYTES: number;
224
+ /** Result of feeding one chunk of a tailed file to the parser. */
225
+ export interface NdjsonChunkResult {
226
+ /** Successfully parsed records, in file order. */
227
+ records: unknown[];
228
+ /** Trailing partial line to prepend to the next chunk. */
229
+ remainder: string;
230
+ /** Lines that were present but unparseable (corrupt JSON). Observability only. */
231
+ skipped: number;
232
+ /** True when an over-long partial line was dropped to bound memory. */
233
+ truncated: boolean;
234
+ }
235
+ /**
236
+ * Split a chunk into whole NDJSON records, carrying any trailing partial line.
237
+ * Callers pass the previous `remainder` prepended to the new bytes.
238
+ */
239
+ export declare function parseNdjsonChunk(chunk: string): NdjsonChunkResult;
240
+ /**
241
+ * Normalize ONE audit record into zero or more governance events.
242
+ *
243
+ * An `assistant` record can carry several `tool_use` blocks in one message, so
244
+ * this returns an array — collapsing them to the first would silently drop
245
+ * parallel tool calls, which is exactly the traffic worth governing.
246
+ */
247
+ export declare function normalizeAuditRecord(raw: unknown): CoworkAuditEvent[];
248
+ /** Normalize a batch of records, preserving order. */
249
+ export declare function normalizeAuditRecords(records: readonly unknown[]): CoworkAuditEvent[];
250
+ /**
251
+ * Stable dedupe key. A resumed tail can legitimately re-read bytes it already
252
+ * processed (rotation, an offset reset, a re-scan), and re-reporting the same
253
+ * tool call would inflate every count the customer sees.
254
+ *
255
+ * `uuid` alone is NOT enough: one assistant record holds several tool_use blocks
256
+ * that share it, so the tool-use id is what separates them.
257
+ */
258
+ export declare function auditEventKey(event: CoworkAuditEvent): string;
259
+ /** Per-file read position plus any partial trailing line. */
260
+ export interface TailCursor {
261
+ offset: number;
262
+ remainder: string;
263
+ /**
264
+ * Opaque file-identity token (inode+device, when the platform supplies one).
265
+ * A cursor is only resumable against the SAME file it was recorded on.
266
+ */
267
+ identity?: string;
268
+ }
269
+ /** Persisted monitor state. */
270
+ export interface MonitorState {
271
+ /** Cursor per absolute audit-log path. */
272
+ cursors: Record<string, TailCursor>;
273
+ /** Recently reported event keys, most-recent last. Bounded by MAX_SEEN_KEYS. */
274
+ seen: string[];
275
+ }
276
+ /**
277
+ * How many event keys to retain for duplicate suppression.
278
+ *
279
+ * HONEST BOUND, corrected: an earlier version of this comment claimed the window
280
+ * was "sized well above a single read batch so a rotation-induced re-read is fully
281
+ * covered". That is FALSE — one pass reads up to `MAX_READ_BYTES` (4 MiB), and a
282
+ * 4 MiB batch of compact tool_use records is well over 5000 events, so a re-read of
283
+ * a large batch CAN age keys out of this window and re-report the oldest of them.
284
+ *
285
+ * The window is a bounded best-effort de-duplicator, not a guarantee: it fully
286
+ * covers the common case (an incremental tail re-reading a recent chunk) and
287
+ * degrades to some duplicate observations on a full re-read of a very large log.
288
+ * Duplicates are the safe direction — a monitor that double-reports is wrong about
289
+ * counts; one that suppresses unboundedly is wrong about coverage.
290
+ */
291
+ export declare const MAX_SEEN_KEYS = 5000;
292
+ /** A fresh, empty monitor state. */
293
+ export declare function emptyState(): MonitorState;
294
+ /**
295
+ * Where should the next read of `path` start?
296
+ *
297
+ * TWO restart conditions, and the second was missing:
298
+ *
299
+ * 1. The file SHRANK below the recorded offset — those bytes no longer exist, so
300
+ * anything but a restart skips content.
301
+ * 2. The file IDENTITY changed — a rotation that reuses the same NAME produces a
302
+ * different inode. Size alone cannot see this: rotate to a file that is the
303
+ * same size or larger and the old cursor resumes mid-way into an unrelated
304
+ * file, silently skipping everything before the stale offset. That is the
305
+ * classic rotation case and it was neither handled nor listed among this
306
+ * module's documented failure modes.
307
+ *
308
+ * `remainder` is dropped on either restart: it belonged to the old file, and
309
+ * prepending it would corrupt the first line of the new one. Identity is optional
310
+ * so a filesystem port that cannot supply one degrades to shrink-detection only
311
+ * rather than restarting on every pass.
312
+ */
313
+ export declare function planRead(state: MonitorState, path: string, size: number, identity?: string | undefined): {
314
+ offset: number;
315
+ remainder: string;
316
+ restarted: boolean;
317
+ };
318
+ /** Outcome of folding one read into the state. */
319
+ export interface AdvanceResult {
320
+ state: MonitorState;
321
+ /** Events not previously reported, in file order. */
322
+ events: CoworkAuditEvent[];
323
+ /** Events suppressed because their key was already seen. */
324
+ duplicates: number;
325
+ /** Corrupt lines skipped in this chunk. */
326
+ skipped: number;
327
+ /** True when an over-long partial line was DROPPED to bound memory. */
328
+ truncated: boolean;
329
+ }
330
+ /**
331
+ * Fold one read of `path` into the state: parse, normalize, drop duplicates and
332
+ * advance the cursor. Pure — the caller owns all I/O.
333
+ *
334
+ * `bytesRead` is the byte length actually consumed from disk (which is NOT
335
+ * `chunk.length` once a carried remainder is prepended, and not the character
336
+ * count for multi-byte UTF-8) so the caller passes it explicitly rather than
337
+ * letting this module guess and drift the offset.
338
+ */
339
+ export declare function advance(state: MonitorState, path: string, opts: {
340
+ startOffset: number;
341
+ bytesRead: number;
342
+ carriedRemainder: string;
343
+ chunk: string;
344
+ identity?: string | undefined;
345
+ }): AdvanceResult;
346
+ /** Keep only the most recent MAX_SEEN_KEYS entries. */
347
+ export declare function pruneSeen(keys: readonly string[]): string[];
348
+ /**
349
+ * Parse a persisted state file. Total: a corrupt/absent state file yields a
350
+ * fresh state rather than an error, because a monitor that refuses to start
351
+ * because its bookkeeping is damaged is strictly worse than one that re-reads.
352
+ */
353
+ export declare function parseState(raw: unknown): MonitorState;
354
+ export type UnifiedOperation = "retrieval" | "action" | "delegation";
355
+ export interface UnifiedEvaluateEvent {
356
+ /** Which facets this event participates in (≥1). */
357
+ operations: UnifiedOperation[];
358
+ agentId: string;
359
+ /**
360
+ * Opaque session key for SEQUENCE-AWARE rules (`input.session.*`): events
361
+ * sharing a sessionId accumulate trajectory evidence in-process, so a rule
362
+ * can gate the CURRENT event on what the agent already retrieved/attempted
363
+ * earlier in the same session. Harnesses thread their native session id
364
+ * (LangChain run session, Claude Code hook session_id, OpenClaw sessionKey).
365
+ * Absent ⇒ no accumulation; session conditions see a fresh-empty state.
366
+ */
367
+ sessionId?: string;
368
+ /** Tool/action name — drives the action + delegation legs. */
369
+ toolName?: string;
370
+ toolArgs?: Record<string, unknown>;
371
+ /** Target app/resource the action acts on (defaults to toolName). */
372
+ targetResource?: string;
373
+ /** Retrieval resource type (the retrieval leg). */
374
+ resourceType?: string;
375
+ resourceMetadata?: Record<string, unknown>;
376
+ query?: string;
377
+ /**
378
+ * Nested normalized event (`{ action_class, write: {...}, ... }`) for
379
+ * `input.normalized.*` rule conditions — supplied by harnesses that classify
380
+ * locally from cached action-schema mappings. Absent ⇒ conditions on
381
+ * normalized fields don't match (cold-start parity with an unmapped schema).
382
+ */
383
+ normalized?: Record<string, unknown>;
384
+ /** A snippet of the retrieved/produced content (reserved; not yet evaluated). */
385
+ contentPreview?: string;
386
+ telemetry?: Record<string, unknown>;
387
+ /**
388
+ * Caller-supplied structured context to PERSIST on the telemetry row
389
+ * (`allow_audit_log.context`), merged alongside the interceptor source. This is
390
+ * how an autonomous capture seam attaches a `delegation` object (a recognized
391
+ * sub-agent spawn: `{ delegation: { is_delegated, parent_agent_id, target_agent,
392
+ * source, spawn } }`) without any new endpoint or column — the delegation sink
393
+ * (`fetchAgentDelegations`) already reads `context->'delegation'`. Never used for
394
+ * the decision itself; display/graph data only.
395
+ */
396
+ context?: Record<string, unknown>;
397
+ /**
398
+ * Surface P: the MCP SERVER this call is attributed to (the tool's origin
399
+ * server). When tagged, it is threaded to `input.normalized.mcp_server` so a
400
+ * synthetic MCP-block deny rule the bundle ships fires IN-PROCESS through the one
401
+ * Rust core before the tool runs. (It is deliberately NOT keyed on `input.context`:
402
+ * the core rebuilds `input.context` as {toolName: toolArgs} on the action leg, so a
403
+ * context-keyed rule would be silently hollow through the real SDK path.)
404
+ * Optional — v1 bites only on TAGGED calls;
405
+ * automatic tool→server attribution across frameworks is the operator-deferred
406
+ * apex. Absent ⇒ the MCP-server plane simply doesn't fire for this event.
407
+ */
408
+ mcpServer?: string;
409
+ }
410
+ /** Governance facets to evaluate for a given tool. */
411
+ export type Operation = "action" | "retrieval" | "delegation";
412
+ /** Context key carrying which Claude surface produced an event. */
413
+ export declare const SURFACE_CONTEXT_KEY = "visiq_surface";
414
+ /** A tool call observed after the fact. Never a gate. */
415
+ export interface CoworkObservation {
416
+ /** The engine event to evaluate/report. */
417
+ event: UnifiedEvaluateEvent;
418
+ /** Operations this call was tagged with. */
419
+ operations: Operation[];
420
+ /**
421
+ * Always false. Present as a value (not a comment) so a caller cannot treat an
422
+ * audit-derived event as a pre-execution decision without ignoring the type.
423
+ */
424
+ enforceable: false;
425
+ }
426
+ /** Coerce arbitrary audit JSON into the record shape the engine expects. */
427
+ export declare function toolArgsOf(input: unknown): Record<string, unknown>;
428
+ /**
429
+ * Build the observation for one audited tool call.
430
+ *
431
+ * `session` is optional because a caller may know the audit file's path (and so
432
+ * the account/org) or may be replaying a bare stream; the observation is valid
433
+ * either way and simply carries less provenance.
434
+ */
435
+ export declare function buildCoworkObservation(opts: {
436
+ call: CoworkToolCallEvent;
437
+ agentId: string;
438
+ surface: ClaudeSurface;
439
+ session?: CoworkSessionRef | undefined;
440
+ }): CoworkObservation;
441
+ /** Bytes to consume from any one file per pass. Excess is picked up next pass. */
442
+ export declare const MAX_READ_BYTES: number;
443
+ /** Filesystem port. Every method resolves to a benign value on failure. */
444
+ export interface MonitorFs {
445
+ /** Directory entries, or [] when unreadable/absent. */
446
+ readdir(path: string): Promise<string[]>;
447
+ /** File size in bytes, or null when unreadable/absent. */
448
+ size(path: string): Promise<number | null>;
449
+ /**
450
+ * Opaque file-identity token (inode+device). OPTIONAL: a port that cannot supply
451
+ * one degrades planRead to shrink-detection only, rather than restarting always.
452
+ */
453
+ identity?(path: string): Promise<string | undefined>;
454
+ /** Read up to `length` bytes from `offset`. Returns text + bytes consumed. */
455
+ read(path: string, offset: number, length: number): Promise<{
456
+ text: string;
457
+ bytes: number;
458
+ }>;
459
+ readFile(path: string): Promise<string | null>;
460
+ writeFile(path: string, data: string): Promise<void>;
461
+ }
462
+ /** An audit log discovered under the Cowork session tree. */
463
+ export interface DiscoveredLog {
464
+ path: string;
465
+ session: CoworkSessionRef;
466
+ }
467
+ /**
468
+ * Walk root → account → org → `local_<uuid>` → the session's `audit*.jsonl` logs.
469
+ * (Written out rather than as a glob: a `*` immediately followed by a slash
470
+ * would close this very comment.)
471
+ *
472
+ * The walk is depth-bounded on purpose: the layout is known and fixed, so a
473
+ * generic recursive crawl would only add a way to wander into a session's
474
+ * `outputs/` tree (which can hold arbitrary user files) for no benefit.
475
+ */
476
+ export declare function discoverAuditLogs(fs: MonitorFs, root: string): Promise<DiscoveredLog[]>;
477
+ /** What one scan pass produced. */
478
+ export interface ScanResult {
479
+ state: MonitorState;
480
+ observations: CoworkObservation[];
481
+ stats: {
482
+ logsScanned: number;
483
+ eventsSeen: number;
484
+ duplicates: number;
485
+ corruptLines: number;
486
+ restarts: number;
487
+ /**
488
+ * Over-long lines DROPPED to bound memory. Previously produced by the parser
489
+ * and consumed by nothing — so discarding up to 8 MiB of governance records
490
+ * was invisible while the far milder `corruptLines` was reported.
491
+ */
492
+ truncatedLines: number;
493
+ };
494
+ }
495
+ /**
496
+ * Run one pass over every discovered audit log, folding new bytes into `state`.
497
+ * Logs are processed in discovery order (oldest rotation first) so a session
498
+ * replays in the order it happened.
499
+ */
500
+ export declare function scanOnce(opts: {
501
+ fs: MonitorFs;
502
+ root: string;
503
+ agentId: string;
504
+ state: MonitorState;
505
+ surface?: ClaudeSurface;
506
+ /**
507
+ * Bytes to consume per file per pass. Injectable ONLY so a test can force reads
508
+ * to land mid-record: with the 4 MiB default no realistic fixture ever crosses a
509
+ * read boundary, so the scanOnce-level consequence of a misaligned read is
510
+ * otherwise untestable — and a test that claimed to prove it was passing
511
+ * vacuously because this parameter did not exist and the option was silently
512
+ * swallowed.
513
+ */
514
+ maxReadBytes?: number;
515
+ }): Promise<ScanResult>;
516
+ /** Load persisted state, tolerating absence and corruption. */
517
+ export declare function loadState(fs: MonitorFs, path: string): Promise<MonitorState>;
518
+ /** Persist state. Best-effort: a failed write costs a re-read, not correctness. */
519
+ export declare function saveState(fs: MonitorFs, path: string, state: MonitorState): Promise<void>;
520
+ /**
521
+ * How many bytes of a freshly-read window may safely be consumed.
522
+ *
523
+ * A fixed-size read can land in the MIDDLE of a multi-byte UTF-8 character.
524
+ * Decoding that window yields a replacement char, which corrupts the JSON of
525
+ * that record (it gets counted as a corrupt line and the tool call is LOST), and
526
+ * because the cursor advances by the full window the next read starts
527
+ * mid-character too. So we consume only up to and including the last newline —
528
+ * a newline is always a single byte and always a record boundary, so the
529
+ * consumed prefix is guaranteed to decode cleanly. The unconsumed tail is simply
530
+ * re-read next pass.
531
+ *
532
+ * Progress guarantee: a window with NO newline (a single record larger than the
533
+ * read size) would otherwise stall forever, so it is consumed whole; the line
534
+ * carry in `advance` reassembles it and MAX_BUFFERED_LINE_BYTES bounds it.
535
+ */
536
+ export declare function alignToRecordBoundary(buffer: Buffer): number;
537
+ /** The real filesystem, with every error folded into a benign value. */
538
+ export declare function nodeFs(): MonitorFs;
539
+ /**
540
+ * This package's published version — the value sent as the `X-VisIQ-SDK-Version`
541
+ * control-plane header.
542
+ *
543
+ * A hand-maintained mirror rather than a JSON import for the same reason as
544
+ * @visiq/claude-code-harness's: a static import of the sibling package.json
545
+ * fails `tsc` under this package's `rootDir: "./src"`.
546
+ *
547
+ * KEEP IN SYNC WITH package.json `version` — guarded by ./__tests__/version.test.ts
548
+ * (package-relative on purpose: a bare `__tests__/…` path reads as a monorepo leak to
549
+ * the publish-bundle validator, because this JSDoc ships inside the published .d.ts).
550
+ */
551
+ export declare const HARNESS_VERSION = "0.1.0";
552
+
553
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ import{I as T,J as w,K as F,L as x,M as D,N as L,O as M,P as g,Q as I,R as K,S as b,a as e,b as o,c as t,d as r,e as s,f as a,g as S,h as n,i as p,j as u,k as i,l as d,m as E,n as c,o as l,p as y,q as R,r as f,s as A,t as C,u as _,v as m,w as N,x as O,y as v,z as k}from"./chunk-75KSV3E4.js";export{S as COWORK_SESSIONS_DIRNAME,n as DESKTOP_SESSIONS_DIRNAME,b as HARNESS_VERSION,e as HOST_PLATFORM_ENV,y as MAX_BUFFERED_LINE_BYTES,x as MAX_READ_BYTES,_ as MAX_SEEN_KEYS,T as SURFACE_CONTEXT_KEY,O as advance,I as alignToRecordBoundary,C as auditEventKey,c as auditLogIndex,F as buildCoworkObservation,o as classifySurface,p as claudeSupportDir,u as coworkSessionsRoot,D as discoverAuditLogs,m as emptyState,E as isAuditLogName,r as isCoworkSurface,d as isSessionKey,M as loadState,K as nodeFs,f as normalizeAuditRecord,A as normalizeAuditRecords,l as orderAuditLogs,R as parseNdjsonChunk,i as parseSessionDir,k as parseState,N as planRead,v as pruneSeen,g as saveState,L as scanOnce,a as surfaceFactsFromProcess,s as surfaceLabel,t as surfaceSupportsEnforcement,w as toolArgsOf};
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@visiq/claude-cowork-harness",
3
+ "version": "0.1.0",
4
+ "description": "VisIQ agent-governance harness for Claude Cowork (the Claude desktop agent) — pre-execution enforcement on host-local sessions via Claude Code hooks, plus audit-stream monitoring for VM-sandboxed sessions the hooks cannot reach.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "bin": {
9
+ "visiq-claude-cowork": "./dist/cli/main.js"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ }
16
+ },
17
+ "dependencies": {
18
+ "zod": "^3.23.8",
19
+ "@visiq/core-wasm": "^0.1.3"
20
+ },
21
+ "engines": {
22
+ "node": ">=20"
23
+ },
24
+ "license": "MIT",
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/VISIQ-LABS/xy.git",
31
+ "directory": "packages/visiq-claude-cowork-harness"
32
+ },
33
+ "homepage": "https://docs.visiqlabs.com",
34
+ "keywords": [
35
+ "visiq",
36
+ "claude-cowork",
37
+ "cowork",
38
+ "claude",
39
+ "anthropic",
40
+ "hooks",
41
+ "ai-governance",
42
+ "agent-governance",
43
+ "action-governance",
44
+ "retrieval-governance",
45
+ "audit-trail"
46
+ ],
47
+ "files": [
48
+ "dist",
49
+ "README.md",
50
+ "LICENSE"
51
+ ],
52
+ "peerDependencies": {
53
+ "@langchain/core": ">=0.3.0",
54
+ "llamaindex": ">=0.11.0"
55
+ },
56
+ "peerDependenciesMeta": {
57
+ "@langchain/core": {
58
+ "optional": true
59
+ },
60
+ "llamaindex": {
61
+ "optional": true
62
+ }
63
+ }
64
+ }