@pinta-ai/pinta-codex 1.6.0 → 1.8.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinta-codex",
3
- "version": "1.6.0",
3
+ "version": "1.8.0",
4
4
  "description": "Generic OTLP forwarder for Codex hook events",
5
5
  "author": {
6
6
  "name": "Pinta AI",
package/CHANGELOG.md CHANGED
@@ -2,6 +2,62 @@
2
2
 
3
3
  All notable changes to pinta-codex are documented here.
4
4
 
5
+ ## [1.8.0] - 2026-09-15
6
+
7
+ ### Added
8
+
9
+ - **PermissionRequest gate.** Codex fires `PermissionRequest` wherever it would
10
+ otherwise prompt the user — including network access, which `PreToolUse` never
11
+ sees. It was unhandled, so that whole class of approval was unguarded.
12
+ Its output envelope is **not** `PreToolUse`'s: the decision is nested as
13
+ `hookSpecificOutput.decision = {behavior, message}` rather than the flat
14
+ `permissionDecision` / `permissionDecisionReason` pair. Sending the flat shape
15
+ parses as a valid envelope carrying no decision, so a deny is dropped with no
16
+ diagnostic. Both shapes are now typed at the point of use.
17
+ - **All 12 hook events handled**, up from 5. Codex 0.154.0 dispatches
18
+ `PreToolUse`, `PermissionRequest`, `PostToolUse`, `PreCompact`, `PostCompact`,
19
+ `SessionStart`, `SessionEnd`, `UserPromptSubmit`, `SubagentStart`,
20
+ `SubagentStop`, `Stop` and `Interrupt`. The seven that were previously
21
+ discarded are now forwarded by a single generic observe handler, and
22
+ `hooks.json` registers all twelve — an event handled in code but absent from
23
+ that template is never dispatched.
24
+ - `tests/core/self-version.test.ts`, which fails when the embedded version
25
+ constants drift from `package.json` (see Fixed).
26
+
27
+ ### Changed
28
+
29
+ - `PreToolUse` and `PermissionRequest` now build their guard request through one
30
+ shared `evaluateToolGate`, so the two gates cannot drift into different
31
+ verdicts for the same action.
32
+ - Fail-open is now stated and tested as deliberate rather than left implicit. A
33
+ guard endpoint that is unreachable or slow allows: an outage in Pinta must not
34
+ stop an engineer from working.
35
+
36
+ ### Fixed
37
+
38
+ - **Version misattribution.** `package.json` was 1.7.0 while `GUARD_UA`,
39
+ `PLUGIN_VERSION` and `.codex-plugin/plugin.json` were all still 1.6.0, so
40
+ every guard call and every OTLP span was attributed to a version that never
41
+ shipped. Confirmed live: the sidecar logged
42
+ `adaptor=pinta-codex ver=1.6.0` from an installation in `.../pinta-codex/1.7.0/`.
43
+ `scripts/bump.mjs` sets all four in lock-step and exists precisely to prevent
44
+ this; it had been bypassed.
45
+ - **`doctor` failed on a healthy install.** Codex renamed the feature flag from
46
+ `codex_hooks` to `hooks`, and the check only recognised the old spelling — so
47
+ a machine configured with `[features] hooks = true`, with hooks firing
48
+ normally, was told its install was broken. Both spellings are now accepted.
49
+ - **`setup` wrote the deprecated flag name.** It now writes canonical
50
+ `hooks = true`, and leaves an existing `codex_hooks = true` alone rather than
51
+ adding a second key for one setting.
52
+ - Measured on codex-cli 0.154.0 with an isolated `CODEX_HOME`: `hooks` is stage
53
+ `stable` and effective `true` with no config at all. Enabling it is now a
54
+ no-op guard for older builds, and an absent key is no longer reported as a
55
+ fault — only an explicit `false` is, since that is a silent kill switch.
56
+ - README corrected throughout: it claimed five events, `PreToolUse`/`PostToolUse`
57
+ were "Bash tool only" (untrue since codex 0.134.0, which extended `PreToolUse`
58
+ to `apply_patch`, MCP calls and every local function tool), and the feature
59
+ flag was given as `features.codex_hooks`.
60
+
5
61
  ## [1.5.1] - 2026-07-20
6
62
 
7
63
  ### Changed
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # pinta-codex
2
2
 
3
- Generic OTLP forwarder for Codex hook events.
3
+ Guard and OTLP forwarder for Codex hook events. Blocks dangerous tool calls
4
+ before they run, and forwards every hook event as a span.
4
5
 
5
6
  > **End-user install guide:** [`docs/installation-guide.md`](./docs/installation-guide.md)
6
7
  > **Differences from pinta-cc:** [`docs/codex-vs-claude-code.md`](./docs/codex-vs-claude-code.md)
@@ -30,15 +31,39 @@ npm run doctor # verify everything green
30
31
 
31
32
  ## What it captures
32
33
 
33
- All five events that Codex's hook system (experimental; requires `features.codex_hooks = true` in `~/.codex/config.toml`) currently emits are handled.
34
+ Codex 0.154.0 dispatches **twelve** hook events. All twelve are handled: two are
35
+ pre-execution gates that can block, and ten are observed and forwarded.
36
+
37
+ Hooks require the `hooks` feature in `~/.codex/config.toml`:
38
+
39
+ ```toml
40
+ [features]
41
+ hooks = true
42
+ ```
43
+
44
+ > `codex_hooks` is the pre-0.13x spelling. Codex still accepts it as a legacy
45
+ > alias, but `hooks` is the canonical name and the one to write.
46
+
47
+ ### Gates — these can deny
34
48
 
35
49
  | Event | Notes |
36
50
  |-------|-------|
37
- | `SessionStart` | health ping + drain retry queue |
38
- | `UserPromptSubmit` | starts a new ULID trace per user turn |
39
- | `PreToolUse` | **Bash tool only** (current Codex limitation) |
40
- | `PostToolUse` | **Bash tool only** (current Codex limitation) |
41
- | `Stop` | final flush |
51
+ | `PreToolUse` | Every local tool, not just Bash — `apply_patch`, MCP calls and all function tools since 0.134.0 |
52
+ | `PermissionRequest` | Fires when Codex would prompt the user, including for network access |
53
+
54
+ Both answer through stdout, and their output envelopes are **not the same
55
+ shape** — see `src/core/types.ts`. A deny must carry a non-empty reason; Codex
56
+ rejects one without it. `PreToolUse` accepts only `deny` (an allow is empty
57
+ stdout).
58
+
59
+ ### Observed — forwarded, never block
60
+
61
+ `PostToolUse`, `PreCompact`, `PostCompact`, `SessionStart`, `SessionEnd`,
62
+ `UserPromptSubmit`, `SubagentStart`, `SubagentStop`, `Stop`, `Interrupt`.
63
+
64
+ `SessionStart` also drains the retry queue; `UserPromptSubmit` starts a new ULID
65
+ trace per user turn; `Stop` performs the final flush. `SessionEnd` is
66
+ send-only — Codex reads no reply from it.
42
67
 
43
68
  Each invocation spawns `node dist/index.js`, maps the event to a single OTLP span, and POSTs it to `{endpoint}/traces`.
44
69
 
@@ -46,7 +71,8 @@ Each invocation spawns `node dist/index.js`, maps the event to a single OTLP spa
46
71
 
47
72
  - OTLP/HTTP JSON transport. Headers are read from `OTEL_EXPORTER_OTLP_HEADERS` (`key=val,key=val` format)
48
73
  - Top-level event fields are flattened into `codex.*` span attributes (Bronze; sibling adaptors use `cc.*`, `mcp.*`)
49
- - **No fail-close** — every hook exits 0 on success (transmission failures are absorbed by the retry queue)
74
+ - **Telemetry never blocks.** Every hook exits 0, and transmission failures are absorbed by the retry queue. A guard decision travels in stdout, so a dropped span cannot deny and a failed POST cannot stall a turn
75
+ - **Fail-open is deliberate.** If the guard endpoint is unreachable or slow, the gates allow. An outage in Pinta must not stop an engineer from working; the guard is a control, not a dependency
50
76
  - Disk-backed retry queue at `.plugin-data/failed-spans.jsonl` (cap 1000). Drained on the next hook invocation
51
77
  - One trace per user turn — based on the `UserPromptSubmit` ULID
52
78
 
@@ -104,7 +130,7 @@ Add the following manually to `~/.codex/config.toml`:
104
130
 
105
131
  ```toml
106
132
  [features]
107
- codex_hooks = true
133
+ hooks = true
108
134
  ```
109
135
 
110
136
  > **Why an install script?** Codex does not yet auto-load hooks from `.codex-plugin/plugin.json`. `install-hooks` substitutes `${CODEX_PLUGIN_ROOT}` in the bundled `hooks.json` template with an absolute path and merges it into the user-level file. Once Codex adds plugin-hook auto-discovery, this step will go away.
@@ -121,7 +147,7 @@ For a complete removal:
121
147
 
122
148
  ```bash
123
149
  rm ~/.codex/pinta-codex.env
124
- # Manually remove the [features] codex_hooks = true line from ~/.codex/config.toml
150
+ # Manually remove the [features] hooks = true line from ~/.codex/config.toml
125
151
  ```
126
152
 
127
153
  ## Local development
@@ -192,10 +218,11 @@ pinta-codex/
192
218
  │ └── codex-vs-claude-code.md # UX differences vs pinta-cc
193
219
  ├── src/
194
220
  │ ├── core/ # OSS-reusable (config, transport, otlp, redact, retry-queue, trace, types, identity stub)
195
- │ ├── handlers/ # per-event handlers
221
+ │ ├── handlers/ # per-event handlers (gates + shared tool-gate + generic observe)
196
222
  │ └── index.ts # stdin → type guard → handler dispatch
197
223
  ├── tests/
198
- │ └── core/ # vitest tests (otlp.test.ts etc.)
224
+ │ ├── core/ # vitest tests (otlp, hook inventory, self-version)
225
+ │ └── handlers/ # gate output-envelope tests
199
226
  ├── tools/
200
227
  │ ├── setup.ts # one-shot interactive installer
201
228
  │ ├── doctor.ts # read-only health check
package/dist/index.js CHANGED
@@ -1,23 +1,26 @@
1
- "use strict";var pt=Object.create;var ae=Object.defineProperty;var dt=Object.getOwnPropertyDescriptor;var ft=Object.getOwnPropertyNames;var _t=Object.getPrototypeOf,ht=Object.prototype.hasOwnProperty;var g=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var gt=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of ft(t))!ht.call(e,o)&&o!==r&&ae(e,o,{get:()=>t[o],enumerable:!(n=dt(t,o))||n.enumerable});return e};var y=(e,t,r)=>(r=e!=null?pt(_t(e)):{},gt(t||!e||!e.__esModule?ae(r,"default",{value:e,enumerable:!0}):r,e));var $=g(d=>{"use strict";Object.defineProperty(d,"__esModule",{value:!0});d.PATTERNS=d.MAX_BYTES=void 0;d.truncateTo=ue;d.truncate=mt;d.collectMatches=ce;d.resolveOverlaps=le;d.applyMatches=pe;d.redact=yt;d.MAX_BYTES=102400;function ue(e,t){let r=Buffer.from(e,"utf-8");return r.length<=t?e:`${r.subarray(0,Math.max(0,t)).toString("utf-8")}\u2026[TRUNCATED:${r.length}]`}function mt(e){return ue(e,d.MAX_BYTES)}d.PATTERNS=[{type:"aws_access_key",regex:/AKIA[0-9A-Z]{16}/g},{type:"aws_secret_key",regex:/(?:aws[_-]?secret(?:[_-]?(?:access)?[_-]?key)?)\s*[:=]\s*["']?([A-Za-z0-9/+=]{40})(?![A-Za-z0-9/+=])/gi,captureGroup:1},{type:"gcp_service_account",regex:/\{[\s\S]{0,200}?"type"\s*:\s*"service_account"[\s\S]*?\}/g},{type:"github_token",regex:/gh[pousr]_[A-Za-z0-9]{36,}/g},{type:"gitlab_token",regex:/glpat-[A-Za-z0-9_-]{20}/g},{type:"slack_token",regex:/xox[abrsp]-[0-9A-Za-z-]{10,}/g},{type:"openai_key",regex:/sk-(?:proj-)?[A-Za-z0-9_-]{40,}/g},{type:"anthropic_key",regex:/sk-ant-[A-Za-z0-9_-]{50,}/g},{type:"stripe_key",regex:/(?:sk|rk|pk)_(?:live|test)_[A-Za-z0-9]{20,}/g},{type:"jwt",regex:/eyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g},{type:"private_key_block",regex:/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g},{type:"bearer_token",regex:/bearer\s+([A-Za-z0-9._~+/=-]{12,})/gi,captureGroup:1},{type:"basic_auth",regex:/basic\s+([A-Za-z0-9+/=]{12,})/gi,captureGroup:1},{type:"db_url_password",regex:/\b(?:postgres|postgresql|mysql|mariadb|mongodb(?:\+srv)?|redis):\/\/[^:\s/]+:([^@\s]+)@/gi,captureGroup:1},{type:"cli_password_flag",regex:/(?:--password|--pass|--pwd)[=\s]([^\s'"]+)/g,captureGroup:1},{type:"cli_password_short",regex:/\s-p([^\s'"]+)/g,captureGroup:1,requireContext:"bash"},{type:"env_var_secret",regex:/^(?:export\s+)?([A-Z][A-Z0-9_]*(?:KEY|SECRET|TOKEN|PASSWORD|PASSWD|PWD|API_KEY)[A-Z0-9_]*)\s*=\s*["']?([^\s"'\n]+)/gm,captureGroup:2}];function ce(e,t){let r=[];for(let n of d.PATTERNS){if(n.requireContext&&n.requireContext!==t.context)continue;let o=new RegExp(n.regex.source,n.regex.flags),i;for(;(i=o.exec(e))!==null;){let a=n.captureGroup??0,u=i[a];if(u===void 0){i.index===o.lastIndex&&o.lastIndex++;continue}let c=i.index,h=i.index+i[0].length,x=c+i[0].indexOf(u),lt=x+u.length;r.push({start:c,end:h,replaceStart:x,replaceEnd:lt,type:n.type}),i.index===o.lastIndex&&o.lastIndex++}}return r}function le(e){let t=[...e].sort((o,i)=>o.start!==i.start?o.start-i.start:i.end-i.start-(o.end-o.start)),r=[],n=-1;for(let o of t)o.start<n||(r.push(o),n=o.end);return r}function pe(e,t){let r=[...t].sort((o,i)=>i.replaceStart-o.replaceStart),n=e;for(let o of r)n=n.slice(0,o.replaceStart)+`[REDACTED:${o.type}]`+n.slice(o.replaceEnd);return n}function yt(e,t={}){if(e.length===0)return e;let r=ce(e,t);if(r.length===0)return e;let n=le(r);return pe(e,n)}});var Y=g(p=>{"use strict";var Pt=p&&p.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(p,"__esModule",{value:!0});p.MAX_SPAN_BYTES=void 0;p.ulidToTraceId=he;p.newSpanId=ge;p.snakeCase=Tt;p.toOtlpValue=me;p.attrsFromRecord=Ot;p.guardAttrs=ye;p.clientAttrs=Pe;p.enforceSpanBudget=Ee;p.buildPayload=St;p.mergeBatch=bt;var Et=Pt(require("crypto")),X=$(),vt="0123456789ABCDEFGHJKMNPQRSTVWXYZ";function he(e){if(e.length!==26)throw new Error(`ulidToTraceId: expected 26 chars, got ${e.length}`);let t=0n;for(let n of e){let o=vt.indexOf(n);if(o<0)throw new Error(`ulidToTraceId: invalid Crockford char "${n}"`);t=t<<5n|BigInt(o)}let r=(1n<<128n)-1n;return t&=r,t.toString(16).padStart(32,"0")}function ge(){return Et.default.randomBytes(8).toString("hex")}function Tt(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1_$2").replace(/([A-Z])([A-Z][a-z])/g,"$1_$2").toLowerCase()}var de=new Set;function M(e,t,r){let n=(0,X.truncate)(t);if((r.skipRedactKeys??de).has(e))return n;let o=(r.bashContextKeys??de).has(e)?"bash":void 0;return(0,X.redact)(n,{context:o})}function me(e,t,r={}){if(t==null)return null;switch(typeof t){case"string":return{stringValue:M(e,t,r)};case"boolean":return{boolValue:t};case"number":return Number.isInteger(t)?{intValue:t}:{doubleValue:t};case"object":try{return{stringValue:M(e,JSON.stringify(t),r)}}catch{return{stringValue:M(e,String(t),r)}}default:return{stringValue:M(e,String(t),r)}}}function Ot(e,t,r={}){let n=[];for(let[o,i]of Object.entries(e)){let a=`${t}.${o}`,u=me(a,i,r);u!==null&&n.push({key:a,value:u})}return n}function ye(e){let t=[{key:"pinta.guard.decision",value:{stringValue:e.decision.toLowerCase()}},{key:"pinta.guard.duration_ms",value:{intValue:e.durationMs}}];return e.reason&&t.push({key:"pinta.guard.matched_rule",value:{stringValue:e.reason}}),e.failOpenReason&&t.push({key:"pinta.guard.fail_open_reason",value:{stringValue:e.failOpenReason}}),t}function Pe(e){return[{key:"pinta.client.rtt_ms",value:Number.isInteger(e.rttMs)?{intValue:e.rttMs}:{doubleValue:e.rttMs}},{key:"pinta.client.op",value:{stringValue:e.op}}]}p.MAX_SPAN_BYTES=800*1024;function fe(e){let t=JSON.stringify(e);return t===void 0?0:Buffer.byteLength(t,"utf-8")}var _e=1024;function Ee(e,t=p.MAX_SPAN_BYTES){let r=fe(e);for(let n=0;n<100&&r>t;n++){let o=null,i=0;for(let c of e.attributes){if(!("stringValue"in c.value))continue;let h=Buffer.byteLength(c.value.stringValue,"utf-8");h>i&&(i=h,o=c.value)}if(o===null||i<=_e)break;let a=r-t,u=Math.max(_e,i-a-64);o.stringValue=(0,X.truncateTo)(o.stringValue,u),r=fe(e)}return e}function St(e){let t=e.now??Date.now(),r=(BigInt(t)*1000000n).toString(),n=[...e.attributes];e.guard&&n.push(...ye(e.guard));let o=e.clientTiming??(e.guard?.clientRttMs!==void 0?{op:"guard",rttMs:e.guard.clientRttMs}:null);o&&n.push(...Pe(o));let i={traceId:he(e.traceId),spanId:ge(),name:e.spanName,kind:e.spanKind??1,startTimeUnixNano:r,endTimeUnixNano:r,attributes:n};return Ee(i),{resourceSpans:[{resource:{attributes:e.resource},scopeSpans:[{scope:e.scope,spans:[i]}]}]}}function bt(e){let t=[];for(let r of e)t.push(...r.resourceSpans);return{resourceSpans:t}}});var ve=g(V=>{"use strict";Object.defineProperty(V,"__esModule",{value:!0});V.evaluateGuard=wt;var kt=1e4,xt="pinta-core";function G(e,t){return{decision:"ALLOW",reason:null,userMessage:null,durationMs:e,clientRttMs:e,failOpenReason:t}}var At=new Set(["ALLOW","DENY","REVIEW"]);async function wt(e,t,r={}){if(!t||r.disabled)return null;let n=r.timeoutMs??kt,o=Date.now(),i=new AbortController,a=setTimeout(()=>i.abort(),n);try{let u=await fetch(t,{method:"POST",headers:{"content-type":"application/json","user-agent":r.userAgent??xt,"x-pinta-relay-token":r.token??""},body:JSON.stringify({input:e}),signal:i.signal});if(u.status!==200)return G(Date.now()-o,"error");let c=await u.json(),h=c?.durationMs===void 0||typeof c.durationMs=="number"&&Number.isFinite(c.durationMs);if(!c||!At.has(c.decision)||!h)return G(Date.now()-o,"error");let x=Date.now()-o;return{decision:c.decision,reason:c.reason??null,userMessage:c.userMessage??null,durationMs:c.durationMs??x,clientRttMs:x}}catch(u){let c=u.name,h=c==="AbortError"||c==="TimeoutError"?"timeout":"error";return G(Date.now()-o,h)}finally{clearTimeout(a)}}});var D=g(A=>{"use strict";var Rt=A&&A.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(A,"__esModule",{value:!0});A.atomicWriteFileSync=Mt;var Te=Rt(require("fs"));function Mt(e,t){let r=`${e}.${process.pid}.tmp`;Te.default.writeFileSync(r,t),Te.default.renameSync(r,e)}});var z=g(P=>{"use strict";var Oe=P&&P.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(P,"__esModule",{value:!0});P.MemoryRetryQueue=P.DiskRetryQueue=void 0;var f=Oe(require("fs")),I=Oe(require("path")),Dt=D(),N=1e3,It=50,Nt=5,F=class{filePath;lockPath;logPrefix;constructor(t,r){this.filePath=I.default.join(t,"failed-spans.jsonl"),this.lockPath=this.filePath+".lock",this.logPrefix=r}enqueue(t){try{f.default.mkdirSync(I.default.dirname(this.filePath),{recursive:!0});let r=JSON.stringify({savedAt:new Date().toISOString(),payload:t})+`
2
- `;f.default.appendFileSync(this.filePath,r),this.trim()}catch(r){process.stderr.write(`[${this.logPrefix}] retry-queue enqueue failed: ${r}
3
- `)}}readAll(){try{let t=f.default.readFileSync(this.filePath,"utf-8"),r=[];for(let n of t.split(`
4
- `))if(n.trim())try{let o=JSON.parse(n);Array.isArray(o?.payload?.resourceSpans)&&r.push(o)}catch{}return r}catch{return[]}}rewrite(t){try{if(t.length===0){f.default.existsSync(this.filePath)&&f.default.unlinkSync(this.filePath);return}f.default.mkdirSync(I.default.dirname(this.filePath),{recursive:!0}),(0,Dt.atomicWriteFileSync)(this.filePath,t.map(r=>JSON.stringify(r)).join(`
1
+ "use strict";var Et=Object.create;var le=Object.defineProperty;var vt=Object.getOwnPropertyDescriptor;var Ot=Object.getOwnPropertyNames;var St=Object.getPrototypeOf,Tt=Object.prototype.hasOwnProperty;var y=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var bt=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of Ot(t))!Tt.call(e,o)&&o!==r&&le(e,o,{get:()=>t[o],enumerable:!(n=vt(t,o))||n.enumerable});return e};var _=(e,t,r)=>(r=e!=null?Et(St(e)):{},bt(t||!e||!e.__esModule?le(r,"default",{value:e,enumerable:!0}):r,e));var Y=y(p=>{"use strict";Object.defineProperty(p,"__esModule",{value:!0});p.PATTERNS=p.MAX_BYTES=void 0;p.truncateTo=de;p.truncate=xt;p.collectMatches=pe;p.resolveOverlaps=fe;p.applyMatches=me;p.redact=kt;p.MAX_BYTES=102400;function de(e,t){let r=Buffer.from(e,"utf-8");return r.length<=t?e:`${r.subarray(0,Math.max(0,t)).toString("utf-8")}\u2026[TRUNCATED:${r.length}]`}function xt(e){return de(e,p.MAX_BYTES)}p.PATTERNS=[{type:"aws_access_key",regex:/AKIA[0-9A-Z]{16}/g},{type:"aws_secret_key",regex:/(?:aws[_-]?secret(?:[_-]?(?:access)?[_-]?key)?)\s*[:=]\s*["']?([A-Za-z0-9/+=]{40})(?![A-Za-z0-9/+=])/gi,captureGroup:1},{type:"gcp_service_account",regex:/\{[\s\S]{0,200}?"type"\s*:\s*"service_account"[\s\S]*?\}/g},{type:"github_token",regex:/gh[pousr]_[A-Za-z0-9]{36,}/g},{type:"gitlab_token",regex:/glpat-[A-Za-z0-9_-]{20}/g},{type:"slack_token",regex:/xox[abrsp]-[0-9A-Za-z-]{10,}/g},{type:"openai_key",regex:/sk-(?:proj-)?[A-Za-z0-9_-]{40,}/g},{type:"anthropic_key",regex:/sk-ant-[A-Za-z0-9_-]{50,}/g},{type:"stripe_key",regex:/(?:sk|rk|pk)_(?:live|test)_[A-Za-z0-9]{20,}/g},{type:"jwt",regex:/eyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g},{type:"private_key_block",regex:/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g},{type:"bearer_token",regex:/bearer\s+([A-Za-z0-9._~+/=-]{12,})/gi,captureGroup:1},{type:"basic_auth",regex:/basic\s+([A-Za-z0-9+/=]{12,})/gi,captureGroup:1},{type:"db_url_password",regex:/\b(?:postgres|postgresql|mysql|mariadb|mongodb(?:\+srv)?|redis):\/\/[^:\s/]+:([^@\s]+)@/gi,captureGroup:1},{type:"cli_password_flag",regex:/(?:--password|--pass|--pwd)[=\s]([^\s'"]+)/g,captureGroup:1},{type:"cli_password_short",regex:/\s-p([^\s'"]+)/g,captureGroup:1,requireContext:"bash"},{type:"env_var_secret",regex:/^(?:export\s+)?([A-Z][A-Z0-9_]*(?:KEY|SECRET|TOKEN|PASSWORD|PASSWD|PWD|API_KEY)[A-Z0-9_]*)\s*=\s*["']?([^\s"'\n]+)/gm,captureGroup:2}];function pe(e,t){let r=[];for(let n of p.PATTERNS){if(n.requireContext&&n.requireContext!==t.context)continue;let o=new RegExp(n.regex.source,n.regex.flags),s;for(;(s=o.exec(e))!==null;){let a=n.captureGroup??0,u=s[a];if(u===void 0){s.index===o.lastIndex&&o.lastIndex++;continue}let c=s.index,h=s.index+s[0].length,k=c+s[0].indexOf(u),Pt=k+u.length;r.push({start:c,end:h,replaceStart:k,replaceEnd:Pt,type:n.type}),s.index===o.lastIndex&&o.lastIndex++}}return r}function fe(e){let t=[...e].sort((o,s)=>o.start!==s.start?o.start-s.start:s.end-s.start-(o.end-o.start)),r=[],n=-1;for(let o of t)o.start<n||(r.push(o),n=o.end);return r}function me(e,t){let r=[...t].sort((o,s)=>s.replaceStart-o.replaceStart),n=e;for(let o of r)n=n.slice(0,o.replaceStart)+`[REDACTED:${o.type}]`+n.slice(o.replaceEnd);return n}function kt(e,t={}){if(e.length===0)return e;let r=pe(e,t);if(r.length===0)return e;let n=fe(r);return me(e,n)}});var F=y(d=>{"use strict";var At=d&&d.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(d,"__esModule",{value:!0});d.MAX_SPAN_BYTES=void 0;d.ulidToTraceId=ye;d.newSpanId=Pe;d.snakeCase=Mt;d.toOtlpValue=Ee;d.attrsFromRecord=Ct;d.guardAttrs=ve;d.clientAttrs=Oe;d.enforceSpanBudget=Se;d.buildPayload=Nt;d.mergeBatch=jt;var Rt=At(require("crypto")),V=Y(),wt="0123456789ABCDEFGHJKMNPQRSTVWXYZ";function ye(e){if(e.length!==26)throw new Error(`ulidToTraceId: expected 26 chars, got ${e.length}`);let t=0n;for(let n of e){let o=wt.indexOf(n);if(o<0)throw new Error(`ulidToTraceId: invalid Crockford char "${n}"`);t=t<<5n|BigInt(o)}let r=(1n<<128n)-1n;return t&=r,t.toString(16).padStart(32,"0")}function Pe(){return Rt.default.randomBytes(8).toString("hex")}function Mt(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1_$2").replace(/([A-Z])([A-Z][a-z])/g,"$1_$2").toLowerCase()}var _e=new Set;function N(e,t,r){let n=(0,V.truncate)(t);if((r.skipRedactKeys??_e).has(e))return n;let o=(r.bashContextKeys??_e).has(e)?"bash":void 0;return(0,V.redact)(n,{context:o})}function Ee(e,t,r={}){if(t==null)return null;switch(typeof t){case"string":return{stringValue:N(e,t,r)};case"boolean":return{boolValue:t};case"number":return Number.isInteger(t)?{intValue:t}:{doubleValue:t};case"object":try{return{stringValue:N(e,JSON.stringify(t),r)}}catch{return{stringValue:N(e,String(t),r)}}default:return{stringValue:N(e,String(t),r)}}}function Ct(e,t,r={}){let n=[];for(let[o,s]of Object.entries(e)){let a=`${t}.${o}`,u=Ee(a,s,r);u!==null&&n.push({key:a,value:u})}return n}function ve(e){let t=[{key:"pinta.guard.decision",value:{stringValue:e.decision.toLowerCase()}},{key:"pinta.guard.duration_ms",value:{intValue:e.durationMs}}];return e.reason&&t.push({key:"pinta.guard.matched_rule",value:{stringValue:e.reason}}),e.failOpenReason&&t.push({key:"pinta.guard.fail_open_reason",value:{stringValue:e.failOpenReason}}),t}function Oe(e){return[{key:"pinta.client.rtt_ms",value:Number.isInteger(e.rttMs)?{intValue:e.rttMs}:{doubleValue:e.rttMs}},{key:"pinta.client.op",value:{stringValue:e.op}}]}d.MAX_SPAN_BYTES=800*1024;function ge(e){let t=JSON.stringify(e);return t===void 0?0:Buffer.byteLength(t,"utf-8")}var he=1024;function Se(e,t=d.MAX_SPAN_BYTES){let r=ge(e);for(let n=0;n<100&&r>t;n++){let o=null,s=0;for(let c of e.attributes){if(!("stringValue"in c.value))continue;let h=Buffer.byteLength(c.value.stringValue,"utf-8");h>s&&(s=h,o=c.value)}if(o===null||s<=he)break;let a=r-t,u=Math.max(he,s-a-64);o.stringValue=(0,V.truncateTo)(o.stringValue,u),r=ge(e)}return e}function Nt(e){let t=e.now??Date.now(),r=(BigInt(t)*1000000n).toString(),n=[...e.attributes];e.guard&&n.push(...ve(e.guard));let o=e.clientTiming??(e.guard?.clientRttMs!==void 0?{op:"guard",rttMs:e.guard.clientRttMs}:null);o&&n.push(...Oe(o));let s={traceId:ye(e.traceId),spanId:Pe(),name:e.spanName,kind:e.spanKind??1,startTimeUnixNano:r,endTimeUnixNano:r,attributes:n};return Se(s),{resourceSpans:[{resource:{attributes:e.resource},scopeSpans:[{scope:e.scope,spans:[s]}]}]}}function jt(e){let t=[];for(let r of e)t.push(...r.resourceSpans);return{resourceSpans:t}}});var Te=y(H=>{"use strict";Object.defineProperty(H,"__esModule",{value:!0});H.evaluateGuard=qt;var Dt=1e4,It="pinta-core";function K(e,t){return{decision:"ALLOW",reason:null,userMessage:null,durationMs:e,clientRttMs:e,failOpenReason:t}}var Bt=new Set(["ALLOW","DENY","REVIEW"]);async function qt(e,t,r={}){if(!t||r.disabled)return null;let n=r.timeoutMs??Dt,o=Date.now(),s=new AbortController,a=setTimeout(()=>s.abort(),n);try{let u=await fetch(t,{method:"POST",headers:{"content-type":"application/json","user-agent":r.userAgent??It,"x-pinta-relay-token":r.token??""},body:JSON.stringify({input:e}),signal:s.signal});if(u.status!==200)return K(Date.now()-o,"error");let c=await u.json(),h=c?.durationMs===void 0||typeof c.durationMs=="number"&&Number.isFinite(c.durationMs);if(!c||!Bt.has(c.decision)||!h)return K(Date.now()-o,"error");let k=Date.now()-o;return{decision:c.decision,reason:c.reason??null,userMessage:c.userMessage??null,durationMs:c.durationMs??k,clientRttMs:k}}catch(u){let c=u.name,h=c==="AbortError"||c==="TimeoutError"?"timeout":"error";return K(Date.now()-o,h)}finally{clearTimeout(a)}}});var j=y(A=>{"use strict";var Ut=A&&A.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(A,"__esModule",{value:!0});A.atomicWriteFileSync=Lt;var be=Ut(require("fs"));function Lt(e,t){let r=`${e}.${process.pid}.tmp`;be.default.writeFileSync(r,t),be.default.renameSync(r,e)}});var Z=y(P=>{"use strict";var xe=P&&P.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(P,"__esModule",{value:!0});P.MemoryRetryQueue=P.DiskRetryQueue=void 0;var m=xe(require("fs")),D=xe(require("path")),$t=j(),I=1e3,Gt=50,Xt=5,z=class{filePath;lockPath;logPrefix;constructor(t,r){this.filePath=D.default.join(t,"failed-spans.jsonl"),this.lockPath=this.filePath+".lock",this.logPrefix=r}enqueue(t){try{m.default.mkdirSync(D.default.dirname(this.filePath),{recursive:!0});let r=JSON.stringify({savedAt:new Date().toISOString(),payload:t})+`
2
+ `;m.default.appendFileSync(this.filePath,r),this.trim()}catch(r){process.stderr.write(`[${this.logPrefix}] retry-queue enqueue failed: ${r}
3
+ `)}}readAll(){try{let t=m.default.readFileSync(this.filePath,"utf-8"),r=[];for(let n of t.split(`
4
+ `))if(n.trim())try{let o=JSON.parse(n);Array.isArray(o?.payload?.resourceSpans)&&r.push(o)}catch{}return r}catch{return[]}}rewrite(t){try{if(t.length===0){m.default.existsSync(this.filePath)&&m.default.unlinkSync(this.filePath);return}m.default.mkdirSync(D.default.dirname(this.filePath),{recursive:!0}),(0,$t.atomicWriteFileSync)(this.filePath,t.map(r=>JSON.stringify(r)).join(`
5
5
  `)+`
6
6
  `)}catch(r){process.stderr.write(`[${this.logPrefix}] retry-queue rewrite failed: ${r}
7
- `)}}tryAcquireLock(){let t=Date.now();try{f.default.mkdirSync(I.default.dirname(this.lockPath),{recursive:!0})}catch(r){return process.stderr.write(`[${this.logPrefix}] retry-queue lock mkdir failed: ${r}
8
- `),!1}for(;Date.now()-t<It;)try{let r=f.default.openSync(this.lockPath,"wx");return f.default.writeSync(r,String(process.pid)),f.default.closeSync(r),!0}catch(r){if(r?.code!=="EEXIST")return process.stderr.write(`[${this.logPrefix}] retry-queue lock open failed: ${r}
9
- `),!1;try{let i=f.default.statSync(this.lockPath);if(Date.now()-i.mtimeMs>3e4){f.default.unlinkSync(this.lockPath);continue}}catch{}let n=Nt,o=Date.now()+n;for(;Date.now()<o;);}return!1}release(){try{f.default.unlinkSync(this.lockPath)}catch{}}trim(){let t=this.readAll();if(t.length<=N)return;let r=t.length-N;process.stderr.write(`[${this.logPrefix}] retry-queue full, dropping ${r} oldest entries
10
- `),this.rewrite(t.slice(r))}};P.DiskRetryQueue=F;var K=class{entries=[];enqueue(t){this.entries.push(t),this.entries.length>N&&this.entries.splice(0,this.entries.length-N)}drain(){let t=this.entries;return this.entries=[],t}get size(){return this.entries.length}};P.MemoryRetryQueue=K});var we=g(l=>{"use strict";Object.defineProperty(l,"__esModule",{value:!0});l.MemoryTransport=l.DiskTransport=l.MAX_POST_BYTES=void 0;l.parseHeadersEnv=xe;l.envOptionsResolver=Ae;l.postOtlp=w;var Se=z(),be=Y(),jt=5e3;l.MAX_POST_BYTES=900*1024;function j(e){let t=JSON.stringify(e);return t===void 0?0:Buffer.byteLength(t,"utf-8")}function ke(e,t,r){let n=[],o=[],i=[],a=0;for(let u of e){let c=t(u);if(c>r){o.push(u);continue}i.length>0&&a+c>r&&(n.push(i),i=[],a=0),i.push(u),a+=c}return i.length>0&&n.push(i),{chunks:n,oversize:o}}function xe(e){if(!e)return{};if(typeof e=="object")return{...e};let t={};for(let r of e.split(",")){let[n,...o]=r.split("=");n&&o.length>0&&(t[n.trim()]=o.join("=").trim())}return t}function Ae(){let e=process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,t=process.env.OTEL_EXPORTER_OTLP_ENDPOINT,r;return e?r=e.replace(/\/+$/,""):t&&(r=t.replace(/\/+$/,"")+"/v1/traces"),r?{endpoint:r,headers:xe(process.env.OTEL_EXPORTER_OTLP_HEADERS)}:null}async function w(e,t,r){let n=new AbortController,o=setTimeout(()=>n.abort(),jt);try{let i=await fetch(t.endpoint,{method:"POST",headers:{"Content-Type":"application/json",...t.headers},body:JSON.stringify(e),signal:n.signal});if(!i.ok){let a="";try{a=(await i.text()).slice(0,200)}catch{}let u=i.status===401||i.status===403?" \u2014 check OTEL_EXPORTER_OTLP_HEADERS (relay token)":i.status===404?" \u2014 check OTEL_EXPORTER_OTLP_TRACES_ENDPOINT path":i.status>=500?" \u2014 collector may be down":"";return process.stderr.write(`[${r}] OTLP POST ${i.status} ${t.endpoint}${u}${a?` body=${a}`:""}
11
- `),!1}return!0}catch(i){return process.stderr.write(`[${r}] OTLP POST failed: ${i.message??String(i)}
12
- `),!1}finally{clearTimeout(o)}}var H=class{queue;logPrefix;resolveOptions;constructor(t){this.queue=new Se.DiskRetryQueue(t.pluginData,t.logPrefix),this.logPrefix=t.logPrefix,this.resolveOptions=t.resolveOptions??Ae}async send(t){let r=this.resolveOptions();if(!r||this.dropIfOversized(t))return;await w(t,r,this.logPrefix)||this.queue.enqueue(t)}async flush(){let t=this.resolveOptions();if(t&&this.queue.tryAcquireLock())try{let r=this.queue.readAll();if(r.length===0)return;let{chunks:n,oversize:o}=ke(r,u=>j(u.payload),l.MAX_POST_BYTES);o.length>0&&process.stderr.write(`[${this.logPrefix}] dropping ${o.length} oversized retry ${o.length===1?"entry":"entries"} (each > ${l.MAX_POST_BYTES} bytes \u2014 the backend caps the request body, so they can never be delivered)
13
- `);let i=[].concat(...n),a=0;for(let u of n){if(!await w((0,be.mergeBatch)(u.map(h=>h.payload)),t,this.logPrefix))break;a+=u.length}this.queue.rewrite(i.slice(a))}catch(r){process.stderr.write(`[${this.logPrefix}] flush failed: ${r?.message??String(r)}
14
- `)}finally{this.queue.release()}}dropIfOversized(t){let r=j(t);return r<=l.MAX_POST_BYTES?!1:(process.stderr.write(`[${this.logPrefix}] dropping oversized span payload (${r} > ${l.MAX_POST_BYTES} bytes) \u2014 undeliverable, not queued
15
- `),!0)}};l.DiskTransport=H;var W=class{queue=new Se.MemoryRetryQueue;logPrefix;resolveOptions;constructor(t){this.logPrefix=t.logPrefix,this.resolveOptions=t.resolveOptions}async send(t){let r=this.resolveOptions();if(!r)return;if(j(t)>l.MAX_POST_BYTES){process.stderr.write(`[${this.logPrefix}] dropping oversized span payload (> ${l.MAX_POST_BYTES} bytes) \u2014 undeliverable, not buffered
16
- `);return}await w(t,r,this.logPrefix)||this.queue.enqueue(t)}async flush(){let t=this.resolveOptions();if(!t)return;let r=this.queue.drain();if(r.length===0)return;let{chunks:n,oversize:o}=ke(r,j,l.MAX_POST_BYTES);o.length>0&&process.stderr.write(`[${this.logPrefix}] dropping ${o.length} oversized buffered ${o.length===1?"payload":"payloads"} (each > ${l.MAX_POST_BYTES} bytes \u2014 undeliverable)
17
- `);let i=[].concat(...n),a=0;for(let u of n){if(!await w((0,be.mergeBatch)(u),t,this.logPrefix))break;a+=u.length}for(let u of i.slice(a))this.queue.enqueue(u)}};l.MemoryTransport=W});var ee=g(T=>{"use strict";var Q=T&&T.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(T,"__esModule",{value:!0});T.TraceManager=void 0;T.generateUlid=Me;var Re=Q(require("fs")),Ct=Q(require("path")),Bt=Q(require("crypto")),Ut=D(),Z="0123456789ABCDEFGHJKMNPQRSTVWXYZ";function Me(){let e=Date.now(),t="",r=e;for(let i=0;i<10;i++)t=Z[r&31]+t,r=Math.floor(r/32);let n=Bt.default.randomBytes(10),o="";for(let i=0;i<10;i++)o+=Z[n[i]&31];for(;o.length<16;)o+=Z[0];return t+o}var J=class{tracePath;constructor(t){this.tracePath=t}newTrace(){let t=Me();return this.save(t),t}currentTrace(){try{let t=Re.default.readFileSync(this.tracePath,"utf-8"),{traceId:r}=JSON.parse(t);if(r)return r}catch{}return this.newTrace()}save(t){try{Re.default.mkdirSync(Ct.default.dirname(this.tracePath),{recursive:!0}),(0,Ut.atomicWriteFileSync)(this.tracePath,JSON.stringify({traceId:t}))}catch(r){process.stderr.write(`[pinta-core] trace persistence failed: ${r}
18
- `)}}};T.TraceManager=J});var Ce=g(E=>{"use strict";var Ie=E&&E.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(E,"__esModule",{value:!0});E.MemorySessionTraceManager=E.DiskSessionTraceManager=void 0;var De=Ie(require("fs")),Lt=Ie(require("path")),Ne=ee(),qt=D(),je=200,te=class{tracePath;maxSessions;constructor(t,r={}){this.tracePath=t,this.maxSessions=r.maxSessions??je}read(){try{let t=JSON.parse(De.default.readFileSync(this.tracePath,"utf-8"));if(t&&typeof t=="object"&&!("traceId"in t))return t}catch{}return{}}write(t){try{De.default.mkdirSync(Lt.default.dirname(this.tracePath),{recursive:!0});let r=Object.entries(t),n=r.length>this.maxSessions?Object.fromEntries(r.slice(-this.maxSessions)):t;(0,qt.atomicWriteFileSync)(this.tracePath,JSON.stringify(n))}catch{}}newTrace(t){let r=t||"default",n=(0,Ne.generateUlid)(),o=this.read();return o[r]=n,this.write(o),n}currentTrace(t){let r=t||"default",n=this.read()[r];return n||this.newTrace(r)}};E.DiskSessionTraceManager=te;var re=class{map=new Map;maxSessions;constructor(t={}){this.maxSessions=t.maxSessions??je}newTrace(t){let r=t||"default",n=(0,Ne.generateUlid)();if(this.map.set(r,n),this.map.size>this.maxSessions){let o=this.map.keys().next().value;o!==void 0&&this.map.delete(o)}return n}currentTrace(t){let r=t||"default";return this.map.get(r)??this.newTrace(r)}};E.MemorySessionTraceManager=re});var Le=g(O=>{"use strict";var ne=O&&O.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(O,"__esModule",{value:!0});O.envFilePath=Yt;O.parseEnvFile=Ue;O.loadEnvFile=Gt;var $t=ne(require("node:fs")),Xt=ne(require("node:os")),Be=ne(require("node:path"));function Yt(e,t,r){let n=r?process.env[r]:void 0,o=n&&n.length>0?n:Be.default.join(Xt.default.homedir(),e);return Be.default.join(o,t)}function Ue(e){let t={};for(let r of e.split(`
19
- `)){let n=r.trim();if(!n||n.startsWith("#"))continue;let o=n.indexOf("=");if(o<0)continue;let i=n.slice(0,o).trim(),a=n.slice(o+1).trim();(a.startsWith('"')&&a.endsWith('"')||a.startsWith("'")&&a.endsWith("'"))&&(a=a.slice(1,-1)),i&&(t[i]=a)}return t}function Gt(e){let t;try{t=$t.default.readFileSync(e,"utf-8")}catch{return}let r=Ue(t);for(let[n,o]of Object.entries(r))process.env[n]===void 0&&(process.env[n]=o)}});var k=g(s=>{"use strict";Object.defineProperty(s,"__esModule",{value:!0});s.loadEnvFile=s.parseEnvFile=s.envFilePath=s.MemorySessionTraceManager=s.DiskSessionTraceManager=s.generateUlid=s.TraceManager=s.MAX_POST_BYTES=s.parseHeadersEnv=s.envOptionsResolver=s.postOtlp=s.MemoryTransport=s.DiskTransport=s.MemoryRetryQueue=s.DiskRetryQueue=s.evaluateGuard=s.MAX_SPAN_BYTES=s.enforceSpanBudget=s.mergeBatch=s.buildPayload=s.clientAttrs=s.guardAttrs=s.attrsFromRecord=s.toOtlpValue=s.snakeCase=s.newSpanId=s.ulidToTraceId=s.MAX_BYTES=s.PATTERNS=s.applyMatches=s.resolveOverlaps=s.collectMatches=s.truncateTo=s.truncate=s.redact=void 0;var v=$();Object.defineProperty(s,"redact",{enumerable:!0,get:function(){return v.redact}});Object.defineProperty(s,"truncate",{enumerable:!0,get:function(){return v.truncate}});Object.defineProperty(s,"truncateTo",{enumerable:!0,get:function(){return v.truncateTo}});Object.defineProperty(s,"collectMatches",{enumerable:!0,get:function(){return v.collectMatches}});Object.defineProperty(s,"resolveOverlaps",{enumerable:!0,get:function(){return v.resolveOverlaps}});Object.defineProperty(s,"applyMatches",{enumerable:!0,get:function(){return v.applyMatches}});Object.defineProperty(s,"PATTERNS",{enumerable:!0,get:function(){return v.PATTERNS}});Object.defineProperty(s,"MAX_BYTES",{enumerable:!0,get:function(){return v.MAX_BYTES}});var _=Y();Object.defineProperty(s,"ulidToTraceId",{enumerable:!0,get:function(){return _.ulidToTraceId}});Object.defineProperty(s,"newSpanId",{enumerable:!0,get:function(){return _.newSpanId}});Object.defineProperty(s,"snakeCase",{enumerable:!0,get:function(){return _.snakeCase}});Object.defineProperty(s,"toOtlpValue",{enumerable:!0,get:function(){return _.toOtlpValue}});Object.defineProperty(s,"attrsFromRecord",{enumerable:!0,get:function(){return _.attrsFromRecord}});Object.defineProperty(s,"guardAttrs",{enumerable:!0,get:function(){return _.guardAttrs}});Object.defineProperty(s,"clientAttrs",{enumerable:!0,get:function(){return _.clientAttrs}});Object.defineProperty(s,"buildPayload",{enumerable:!0,get:function(){return _.buildPayload}});Object.defineProperty(s,"mergeBatch",{enumerable:!0,get:function(){return _.mergeBatch}});Object.defineProperty(s,"enforceSpanBudget",{enumerable:!0,get:function(){return _.enforceSpanBudget}});Object.defineProperty(s,"MAX_SPAN_BYTES",{enumerable:!0,get:function(){return _.MAX_SPAN_BYTES}});var Vt=ve();Object.defineProperty(s,"evaluateGuard",{enumerable:!0,get:function(){return Vt.evaluateGuard}});var qe=z();Object.defineProperty(s,"DiskRetryQueue",{enumerable:!0,get:function(){return qe.DiskRetryQueue}});Object.defineProperty(s,"MemoryRetryQueue",{enumerable:!0,get:function(){return qe.MemoryRetryQueue}});var b=we();Object.defineProperty(s,"DiskTransport",{enumerable:!0,get:function(){return b.DiskTransport}});Object.defineProperty(s,"MemoryTransport",{enumerable:!0,get:function(){return b.MemoryTransport}});Object.defineProperty(s,"postOtlp",{enumerable:!0,get:function(){return b.postOtlp}});Object.defineProperty(s,"envOptionsResolver",{enumerable:!0,get:function(){return b.envOptionsResolver}});Object.defineProperty(s,"parseHeadersEnv",{enumerable:!0,get:function(){return b.parseHeadersEnv}});Object.defineProperty(s,"MAX_POST_BYTES",{enumerable:!0,get:function(){return b.MAX_POST_BYTES}});var $e=ee();Object.defineProperty(s,"TraceManager",{enumerable:!0,get:function(){return $e.TraceManager}});Object.defineProperty(s,"generateUlid",{enumerable:!0,get:function(){return $e.generateUlid}});var Xe=Ce();Object.defineProperty(s,"DiskSessionTraceManager",{enumerable:!0,get:function(){return Xe.DiskSessionTraceManager}});Object.defineProperty(s,"MemorySessionTraceManager",{enumerable:!0,get:function(){return Xe.MemorySessionTraceManager}});var oe=Le();Object.defineProperty(s,"envFilePath",{enumerable:!0,get:function(){return oe.envFilePath}});Object.defineProperty(s,"parseEnvFile",{enumerable:!0,get:function(){return oe.parseEnvFile}});Object.defineProperty(s,"loadEnvFile",{enumerable:!0,get:function(){return oe.loadEnvFile}})});var se=y(require("node:fs")),Ye=y(require("node:os")),R=y(require("node:path")),Ge=y(k());function Ft(e){let t={},r;try{r=se.default.readFileSync(e,"utf-8")}catch{return t}for(let n of r.split(`
20
- `)){let o=n.trim();if(!o||o.startsWith("#"))continue;let i=o.indexOf("=");if(i<0)continue;let a=o.slice(0,i).trim(),u=o.slice(i+1).trim();(u.startsWith('"')&&u.endsWith('"')||u.startsWith("'")&&u.endsWith("'"))&&(u=u.slice(1,-1)),a&&(t[a]=u)}return t}function Kt(e){let t=process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT??e.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT;if(t)return t;let r=process.env.OTEL_EXPORTER_OTLP_ENDPOINT??e.OTEL_EXPORTER_OTLP_ENDPOINT;return r?r.replace(/\/+$/,"")+"/v1/traces":process.env.PINTA_CODEX_ENDPOINT??e.PINTA_CODEX_ENDPOINT??process.env.CLAUDE_PLUGIN_OPTION_ENDPOINT}function zt(e){if(process.env.OTEL_EXPORTER_OTLP_HEADERS)return process.env.OTEL_EXPORTER_OTLP_HEADERS;if(e.OTEL_EXPORTER_OTLP_HEADERS)return e.OTEL_EXPORTER_OTLP_HEADERS;if(process.env.PINTA_CODEX_API_KEY)return`x-pinta-relay-token=${process.env.PINTA_CODEX_API_KEY}`;if(e.PINTA_CODEX_API_KEY)return`x-pinta-relay-token=${e.PINTA_CODEX_API_KEY}`;if(process.env.CLAUDE_PLUGIN_OPTION_API_KEY)return`x-pinta-relay-token=${process.env.CLAUDE_PLUGIN_OPTION_API_KEY}`}function Ve(){let e=process.env.CODEX_PLUGIN_ROOT??process.env.CLAUDE_PLUGIN_ROOT??process.cwd(),t=process.env.CODEX_PLUGIN_DATA??process.env.CLAUDE_PLUGIN_DATA??R.default.join(e,".plugin-data"),r=process.env.CODEX_HOME??R.default.join(Ye.default.homedir(),".codex"),n=R.default.join(r,"pinta-codex.env"),o=se.default.existsSync(n)?Ft(n):{},i=Kt(o),a=zt(o);if(a&&!process.env.PINTA_RELAY_TOKEN){let c=a.match(/x-pinta-relay-token=([^,\s]+)/i);c&&(process.env.PINTA_RELAY_TOKEN=c[1])}let u=process.env.PINTA_GUARD_ENDPOINT??o.PINTA_GUARD_ENDPOINT;return{pluginRoot:e,pluginData:t,tracePath:R.default.join(t,"trace.json"),endpoint:i?.replace(/\/+$/,""),headers:(0,Ge.parseHeadersEnv)(a??""),guardEndpoint:u}}function Fe(e){return e.hook_event_name==="PreToolUse"}function Ke(e){return e.hook_event_name==="PostToolUse"}function ze(e){return e.hook_event_name==="UserPromptSubmit"}function He(e){return e.hook_event_name==="SessionStart"}function We(e){return e.hook_event_name==="Stop"}var Ht=new Set(["PreToolUse","PostToolUse","SessionStart","UserPromptSubmit","Stop"]);function Ze(e){return!Ht.has(e.hook_event_name)}var Je=y(k()),Wt=50,Zt="pinta-codex/1.6.0";async function Qe(e,t){let r=await(0,Je.evaluateGuard)(e,t,{timeoutMs:Wt,token:process.env.PINTA_RELAY_TOKEN??"",disabled:process.env.PINTA_GUARD_DISABLED==="1",userAgent:Zt});if(r===null)return null;let n={decision:r.decision,reason:r.reason,durationMs:r.durationMs,clientRttMs:r.clientRttMs};return r.failOpenReason!==void 0&&(n.failOpenReason=r.failOpenReason),n}var et=y(k()),C=class extends et.DiskTransport{constructor(t){super({pluginData:t.pluginData,logPrefix:"pinta-codex",resolveOptions:()=>t.endpoint?{endpoint:t.endpoint,headers:t.headers}:null})}};var tt=y(k()),B=class extends tt.TraceManager{constructor(t){super(t.tracePath)}};var q=y(require("os")),S=y(k()),U;function Jt(){if(U===void 0)try{U=q.default.userInfo().username}catch{U=process.env.USER??process.env.LOGNAME??(typeof process.getuid=="function"?String(process.getuid()):"unknown")}return U}var rt="1.6.0",L=null;function Qt(){return L!==null||(L=process.env.CODEX_CLI_VERSION||"unknown"),L}var er=new Set(["codex.hook","codex.tool_name","codex.tool_use_id","codex.session_id","codex.transcript_path","codex.cwd","codex.permission_mode"]),tr=new Set(["codex.tool_input","codex.tool_response"]),rr={skipRedactKeys:er,bashContextKeys:tr};function nr(e){let t=[];t.push({key:"ingest.type",value:{stringValue:"codex"}}),t.push({key:"codex.hook",value:{stringValue:e.hook_event_name}});let r={};for(let[n,o]of Object.entries(e))n!=="hook_event_name"&&(r[n]=o);return t.push(...(0,S.attrsFromRecord)(r,"codex",rr)),t}function or(){return[{key:"service.name",value:{stringValue:"codex"}},{key:"service.version",value:{stringValue:Qt()}},{key:"telemetry.sdk.name",value:{stringValue:"pinta-codex"}},{key:"telemetry.sdk.language",value:{stringValue:"nodejs"}},{key:"telemetry.sdk.version",value:{stringValue:rt}},{key:"process.pid",value:{intValue:process.pid}},{key:"process.owner",value:{stringValue:Jt()}},{key:"host.name",value:{stringValue:q.default.hostname()}},{key:"host.arch",value:{stringValue:q.default.arch()}}]}function nt(e){return(0,S.buildPayload)({traceId:e.traceId,spanName:`codex.${(0,S.snakeCase)(e.event.hook_event_name)}`,attributes:nr(e.event),resource:or(),scope:{name:"pinta-codex",version:rt},now:e.now,guard:e.guard})}async function m(e,t,r){let n=new C(t);await n.flush();let o=new B(t),i=r.trace==="new"?o.newTrace():o.currentTrace(),a=nt({event:e,traceId:i,guard:r.guard});await n.send(a)}async function ot(e,t){let r=typeof e.tool_input=="string"?e.tool_input:JSON.stringify(e.tool_input),n=await Qe({spanId:e.session_id??"unknown",toolName:e.tool_name,method:e.hook_event_name,cwd:e.cwd,toolInput:e.tool_input,rawTextFields:{toolInput:r}},t.guardEndpoint);if(n?.decision==="DENY"){let o={hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:n.reason??"guard_deny"}};process.stdout.write(JSON.stringify(o)+`
21
- `)}try{await m(e,t,{trace:"current",guard:n})}catch(o){process.stderr.write(`[pinta-codex] telemetry emit failed: ${o}
22
- `)}return 0}async function st(e,t){return await m(e,t,{trace:"current"}),0}async function it(e,t){return await m(e,t,{trace:"new"}),0}async function at(e,t){return await m(e,t,{trace:"current"}),0}async function ut(e,t){return await m(e,t,{trace:"current"}),0}async function ie(e){return 0}async function sr(){let e=[];for await(let t of process.stdin)e.push(t);return Buffer.concat(e).toString("utf-8")}async function ct(){let e=0;try{let t=Ve(),r=await sr(),n=JSON.parse(r);Ze(n)?e=await ie(n):Fe(n)?e=await ot(n,t):Ke(n)?e=await st(n,t):ze(n)?e=await it(n,t):He(n)?e=await at(n,t):We(n)?e=await ut(n,t):e=await ie(n)}catch(t){process.stderr.write(`[pinta-codex] error: ${t}
23
- `),e=0}return e}async function ir(){let e=await ct();process.exit(e)}ir();
7
+ `)}}tryAcquireLock(){let t=Date.now();try{m.default.mkdirSync(D.default.dirname(this.lockPath),{recursive:!0})}catch(r){return process.stderr.write(`[${this.logPrefix}] retry-queue lock mkdir failed: ${r}
8
+ `),!1}for(;Date.now()-t<Gt;)try{let r=m.default.openSync(this.lockPath,"wx");return m.default.writeSync(r,String(process.pid)),m.default.closeSync(r),!0}catch(r){if(r?.code!=="EEXIST")return process.stderr.write(`[${this.logPrefix}] retry-queue lock open failed: ${r}
9
+ `),!1;try{let s=m.default.statSync(this.lockPath);if(Date.now()-s.mtimeMs>3e4){m.default.unlinkSync(this.lockPath);continue}}catch{}let n=Xt,o=Date.now()+n;for(;Date.now()<o;);}return!1}release(){try{m.default.unlinkSync(this.lockPath)}catch{}}trim(){let t=this.readAll();if(t.length<=I)return;let r=t.length-I;process.stderr.write(`[${this.logPrefix}] retry-queue full, dropping ${r} oldest entries
10
+ `),this.rewrite(t.slice(r))}};P.DiskRetryQueue=z;var W=class{entries=[];enqueue(t){this.entries.push(t),this.entries.length>I&&this.entries.splice(0,this.entries.length-I)}drain(){let t=this.entries;return this.entries=[],t}get size(){return this.entries.length}};P.MemoryRetryQueue=W});var Ce=y(l=>{"use strict";Object.defineProperty(l,"__esModule",{value:!0});l.MemoryTransport=l.DiskTransport=l.MAX_POST_BYTES=void 0;l.parseHeadersEnv=we;l.envOptionsResolver=Me;l.postOtlp=R;var ke=Z(),Ae=F(),Yt=5e3;l.MAX_POST_BYTES=900*1024;function B(e){let t=JSON.stringify(e);return t===void 0?0:Buffer.byteLength(t,"utf-8")}function Re(e,t,r){let n=[],o=[],s=[],a=0;for(let u of e){let c=t(u);if(c>r){o.push(u);continue}s.length>0&&a+c>r&&(n.push(s),s=[],a=0),s.push(u),a+=c}return s.length>0&&n.push(s),{chunks:n,oversize:o}}function we(e){if(!e)return{};if(typeof e=="object")return{...e};let t={};for(let r of e.split(",")){let[n,...o]=r.split("=");n&&o.length>0&&(t[n.trim()]=o.join("=").trim())}return t}function Me(){let e=process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,t=process.env.OTEL_EXPORTER_OTLP_ENDPOINT,r;return e?r=e.replace(/\/+$/,""):t&&(r=t.replace(/\/+$/,"")+"/v1/traces"),r?{endpoint:r,headers:we(process.env.OTEL_EXPORTER_OTLP_HEADERS)}:null}async function R(e,t,r){let n=new AbortController,o=setTimeout(()=>n.abort(),Yt);try{let s=await fetch(t.endpoint,{method:"POST",headers:{"Content-Type":"application/json",...t.headers},body:JSON.stringify(e),signal:n.signal});if(!s.ok){let a="";try{a=(await s.text()).slice(0,200)}catch{}let u=s.status===401||s.status===403?" \u2014 check OTEL_EXPORTER_OTLP_HEADERS (relay token)":s.status===404?" \u2014 check OTEL_EXPORTER_OTLP_TRACES_ENDPOINT path":s.status>=500?" \u2014 collector may be down":"";return process.stderr.write(`[${r}] OTLP POST ${s.status} ${t.endpoint}${u}${a?` body=${a}`:""}
11
+ `),!1}return!0}catch(s){return process.stderr.write(`[${r}] OTLP POST failed: ${s.message??String(s)}
12
+ `),!1}finally{clearTimeout(o)}}var J=class{queue;logPrefix;resolveOptions;constructor(t){this.queue=new ke.DiskRetryQueue(t.pluginData,t.logPrefix),this.logPrefix=t.logPrefix,this.resolveOptions=t.resolveOptions??Me}async send(t){let r=this.resolveOptions();if(!r||this.dropIfOversized(t))return;await R(t,r,this.logPrefix)||this.queue.enqueue(t)}async flush(){let t=this.resolveOptions();if(t&&this.queue.tryAcquireLock())try{let r=this.queue.readAll();if(r.length===0)return;let{chunks:n,oversize:o}=Re(r,u=>B(u.payload),l.MAX_POST_BYTES);o.length>0&&process.stderr.write(`[${this.logPrefix}] dropping ${o.length} oversized retry ${o.length===1?"entry":"entries"} (each > ${l.MAX_POST_BYTES} bytes \u2014 the backend caps the request body, so they can never be delivered)
13
+ `);let s=[].concat(...n),a=0;for(let u of n){if(!await R((0,Ae.mergeBatch)(u.map(h=>h.payload)),t,this.logPrefix))break;a+=u.length}this.queue.rewrite(s.slice(a))}catch(r){process.stderr.write(`[${this.logPrefix}] flush failed: ${r?.message??String(r)}
14
+ `)}finally{this.queue.release()}}dropIfOversized(t){let r=B(t);return r<=l.MAX_POST_BYTES?!1:(process.stderr.write(`[${this.logPrefix}] dropping oversized span payload (${r} > ${l.MAX_POST_BYTES} bytes) \u2014 undeliverable, not queued
15
+ `),!0)}};l.DiskTransport=J;var Q=class{queue=new ke.MemoryRetryQueue;logPrefix;resolveOptions;constructor(t){this.logPrefix=t.logPrefix,this.resolveOptions=t.resolveOptions}async send(t){let r=this.resolveOptions();if(!r)return;if(B(t)>l.MAX_POST_BYTES){process.stderr.write(`[${this.logPrefix}] dropping oversized span payload (> ${l.MAX_POST_BYTES} bytes) \u2014 undeliverable, not buffered
16
+ `);return}await R(t,r,this.logPrefix)||this.queue.enqueue(t)}async flush(){let t=this.resolveOptions();if(!t)return;let r=this.queue.drain();if(r.length===0)return;let{chunks:n,oversize:o}=Re(r,B,l.MAX_POST_BYTES);o.length>0&&process.stderr.write(`[${this.logPrefix}] dropping ${o.length} oversized buffered ${o.length===1?"payload":"payloads"} (each > ${l.MAX_POST_BYTES} bytes \u2014 undeliverable)
17
+ `);let s=[].concat(...n),a=0;for(let u of n){if(!await R((0,Ae.mergeBatch)(u),t,this.logPrefix))break;a+=u.length}for(let u of s.slice(a))this.queue.enqueue(u)}};l.MemoryTransport=Q});var ne=y(O=>{"use strict";var re=O&&O.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(O,"__esModule",{value:!0});O.TraceManager=void 0;O.generateUlid=je;var Ne=re(require("fs")),Vt=re(require("path")),Ft=re(require("crypto")),Kt=j(),ee="0123456789ABCDEFGHJKMNPQRSTVWXYZ";function je(){let e=Date.now(),t="",r=e;for(let s=0;s<10;s++)t=ee[r&31]+t,r=Math.floor(r/32);let n=Ft.default.randomBytes(10),o="";for(let s=0;s<10;s++)o+=ee[n[s]&31];for(;o.length<16;)o+=ee[0];return t+o}var te=class{tracePath;constructor(t){this.tracePath=t}newTrace(){let t=je();return this.save(t),t}currentTrace(){try{let t=Ne.default.readFileSync(this.tracePath,"utf-8"),{traceId:r}=JSON.parse(t);if(r)return r}catch{}return this.newTrace()}save(t){try{Ne.default.mkdirSync(Vt.default.dirname(this.tracePath),{recursive:!0}),(0,Kt.atomicWriteFileSync)(this.tracePath,JSON.stringify({traceId:t}))}catch(r){process.stderr.write(`[pinta-core] trace persistence failed: ${r}
18
+ `)}}};O.TraceManager=te});var Ue=y(E=>{"use strict";var Ie=E&&E.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(E,"__esModule",{value:!0});E.MemorySessionTraceManager=E.DiskSessionTraceManager=void 0;var De=Ie(require("fs")),Ht=Ie(require("path")),Be=ne(),zt=j(),qe=200,oe=class{tracePath;maxSessions;constructor(t,r={}){this.tracePath=t,this.maxSessions=r.maxSessions??qe}read(){try{let t=JSON.parse(De.default.readFileSync(this.tracePath,"utf-8"));if(t&&typeof t=="object"&&!("traceId"in t))return t}catch{}return{}}write(t){try{De.default.mkdirSync(Ht.default.dirname(this.tracePath),{recursive:!0});let r=Object.entries(t),n=r.length>this.maxSessions?Object.fromEntries(r.slice(-this.maxSessions)):t;(0,zt.atomicWriteFileSync)(this.tracePath,JSON.stringify(n))}catch{}}newTrace(t){let r=t||"default",n=(0,Be.generateUlid)(),o=this.read();return o[r]=n,this.write(o),n}currentTrace(t){let r=t||"default",n=this.read()[r];return n||this.newTrace(r)}};E.DiskSessionTraceManager=oe;var se=class{map=new Map;maxSessions;constructor(t={}){this.maxSessions=t.maxSessions??qe}newTrace(t){let r=t||"default",n=(0,Be.generateUlid)();if(this.map.set(r,n),this.map.size>this.maxSessions){let o=this.map.keys().next().value;o!==void 0&&this.map.delete(o)}return n}currentTrace(t){let r=t||"default";return this.map.get(r)??this.newTrace(r)}};E.MemorySessionTraceManager=se});var Ge=y(S=>{"use strict";var ie=S&&S.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(S,"__esModule",{value:!0});S.envFilePath=Jt;S.parseEnvFile=$e;S.loadEnvFile=Qt;var Wt=ie(require("node:fs")),Zt=ie(require("node:os")),Le=ie(require("node:path"));function Jt(e,t,r){let n=r?process.env[r]:void 0,o=n&&n.length>0?n:Le.default.join(Zt.default.homedir(),e);return Le.default.join(o,t)}function $e(e){let t={};for(let r of e.split(`
19
+ `)){let n=r.trim();if(!n||n.startsWith("#"))continue;let o=n.indexOf("=");if(o<0)continue;let s=n.slice(0,o).trim(),a=n.slice(o+1).trim();(a.startsWith('"')&&a.endsWith('"')||a.startsWith("'")&&a.endsWith("'"))&&(a=a.slice(1,-1)),s&&(t[s]=a)}return t}function Qt(e){let t;try{t=Wt.default.readFileSync(e,"utf-8")}catch{return}let r=$e(t);for(let[n,o]of Object.entries(r))process.env[n]===void 0&&(process.env[n]=o)}});var x=y(i=>{"use strict";Object.defineProperty(i,"__esModule",{value:!0});i.loadEnvFile=i.parseEnvFile=i.envFilePath=i.MemorySessionTraceManager=i.DiskSessionTraceManager=i.generateUlid=i.TraceManager=i.MAX_POST_BYTES=i.parseHeadersEnv=i.envOptionsResolver=i.postOtlp=i.MemoryTransport=i.DiskTransport=i.MemoryRetryQueue=i.DiskRetryQueue=i.evaluateGuard=i.MAX_SPAN_BYTES=i.enforceSpanBudget=i.mergeBatch=i.buildPayload=i.clientAttrs=i.guardAttrs=i.attrsFromRecord=i.toOtlpValue=i.snakeCase=i.newSpanId=i.ulidToTraceId=i.MAX_BYTES=i.PATTERNS=i.applyMatches=i.resolveOverlaps=i.collectMatches=i.truncateTo=i.truncate=i.redact=void 0;var v=Y();Object.defineProperty(i,"redact",{enumerable:!0,get:function(){return v.redact}});Object.defineProperty(i,"truncate",{enumerable:!0,get:function(){return v.truncate}});Object.defineProperty(i,"truncateTo",{enumerable:!0,get:function(){return v.truncateTo}});Object.defineProperty(i,"collectMatches",{enumerable:!0,get:function(){return v.collectMatches}});Object.defineProperty(i,"resolveOverlaps",{enumerable:!0,get:function(){return v.resolveOverlaps}});Object.defineProperty(i,"applyMatches",{enumerable:!0,get:function(){return v.applyMatches}});Object.defineProperty(i,"PATTERNS",{enumerable:!0,get:function(){return v.PATTERNS}});Object.defineProperty(i,"MAX_BYTES",{enumerable:!0,get:function(){return v.MAX_BYTES}});var g=F();Object.defineProperty(i,"ulidToTraceId",{enumerable:!0,get:function(){return g.ulidToTraceId}});Object.defineProperty(i,"newSpanId",{enumerable:!0,get:function(){return g.newSpanId}});Object.defineProperty(i,"snakeCase",{enumerable:!0,get:function(){return g.snakeCase}});Object.defineProperty(i,"toOtlpValue",{enumerable:!0,get:function(){return g.toOtlpValue}});Object.defineProperty(i,"attrsFromRecord",{enumerable:!0,get:function(){return g.attrsFromRecord}});Object.defineProperty(i,"guardAttrs",{enumerable:!0,get:function(){return g.guardAttrs}});Object.defineProperty(i,"clientAttrs",{enumerable:!0,get:function(){return g.clientAttrs}});Object.defineProperty(i,"buildPayload",{enumerable:!0,get:function(){return g.buildPayload}});Object.defineProperty(i,"mergeBatch",{enumerable:!0,get:function(){return g.mergeBatch}});Object.defineProperty(i,"enforceSpanBudget",{enumerable:!0,get:function(){return g.enforceSpanBudget}});Object.defineProperty(i,"MAX_SPAN_BYTES",{enumerable:!0,get:function(){return g.MAX_SPAN_BYTES}});var er=Te();Object.defineProperty(i,"evaluateGuard",{enumerable:!0,get:function(){return er.evaluateGuard}});var Xe=Z();Object.defineProperty(i,"DiskRetryQueue",{enumerable:!0,get:function(){return Xe.DiskRetryQueue}});Object.defineProperty(i,"MemoryRetryQueue",{enumerable:!0,get:function(){return Xe.MemoryRetryQueue}});var b=Ce();Object.defineProperty(i,"DiskTransport",{enumerable:!0,get:function(){return b.DiskTransport}});Object.defineProperty(i,"MemoryTransport",{enumerable:!0,get:function(){return b.MemoryTransport}});Object.defineProperty(i,"postOtlp",{enumerable:!0,get:function(){return b.postOtlp}});Object.defineProperty(i,"envOptionsResolver",{enumerable:!0,get:function(){return b.envOptionsResolver}});Object.defineProperty(i,"parseHeadersEnv",{enumerable:!0,get:function(){return b.parseHeadersEnv}});Object.defineProperty(i,"MAX_POST_BYTES",{enumerable:!0,get:function(){return b.MAX_POST_BYTES}});var Ye=ne();Object.defineProperty(i,"TraceManager",{enumerable:!0,get:function(){return Ye.TraceManager}});Object.defineProperty(i,"generateUlid",{enumerable:!0,get:function(){return Ye.generateUlid}});var Ve=Ue();Object.defineProperty(i,"DiskSessionTraceManager",{enumerable:!0,get:function(){return Ve.DiskSessionTraceManager}});Object.defineProperty(i,"MemorySessionTraceManager",{enumerable:!0,get:function(){return Ve.MemorySessionTraceManager}});var ae=Ge();Object.defineProperty(i,"envFilePath",{enumerable:!0,get:function(){return ae.envFilePath}});Object.defineProperty(i,"parseEnvFile",{enumerable:!0,get:function(){return ae.parseEnvFile}});Object.defineProperty(i,"loadEnvFile",{enumerable:!0,get:function(){return ae.loadEnvFile}})});var ue=_(require("node:fs")),Fe=_(require("node:os")),w=_(require("node:path")),Ke=_(x());function tr(e){let t={},r;try{r=ue.default.readFileSync(e,"utf-8")}catch{return t}for(let n of r.split(`
20
+ `)){let o=n.trim();if(!o||o.startsWith("#"))continue;let s=o.indexOf("=");if(s<0)continue;let a=o.slice(0,s).trim(),u=o.slice(s+1).trim();(u.startsWith('"')&&u.endsWith('"')||u.startsWith("'")&&u.endsWith("'"))&&(u=u.slice(1,-1)),a&&(t[a]=u)}return t}function rr(e){let t=process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT??e.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT;if(t)return t;let r=process.env.OTEL_EXPORTER_OTLP_ENDPOINT??e.OTEL_EXPORTER_OTLP_ENDPOINT;return r?r.replace(/\/+$/,"")+"/v1/traces":process.env.PINTA_CODEX_ENDPOINT??e.PINTA_CODEX_ENDPOINT??process.env.CLAUDE_PLUGIN_OPTION_ENDPOINT}function nr(e){if(process.env.OTEL_EXPORTER_OTLP_HEADERS)return process.env.OTEL_EXPORTER_OTLP_HEADERS;if(e.OTEL_EXPORTER_OTLP_HEADERS)return e.OTEL_EXPORTER_OTLP_HEADERS;if(process.env.PINTA_CODEX_API_KEY)return`x-pinta-relay-token=${process.env.PINTA_CODEX_API_KEY}`;if(e.PINTA_CODEX_API_KEY)return`x-pinta-relay-token=${e.PINTA_CODEX_API_KEY}`;if(process.env.CLAUDE_PLUGIN_OPTION_API_KEY)return`x-pinta-relay-token=${process.env.CLAUDE_PLUGIN_OPTION_API_KEY}`}function He(){let e=process.env.CODEX_PLUGIN_ROOT??process.env.CLAUDE_PLUGIN_ROOT??process.cwd(),t=process.env.CODEX_PLUGIN_DATA??process.env.CLAUDE_PLUGIN_DATA??w.default.join(e,".plugin-data"),r=process.env.CODEX_HOME??w.default.join(Fe.default.homedir(),".codex"),n=w.default.join(r,"pinta-codex.env"),o=ue.default.existsSync(n)?tr(n):{},s=rr(o),a=nr(o);if(a&&!process.env.PINTA_RELAY_TOKEN){let c=a.match(/x-pinta-relay-token=([^,\s]+)/i);c&&(process.env.PINTA_RELAY_TOKEN=c[1])}let u=process.env.PINTA_GUARD_ENDPOINT??o.PINTA_GUARD_ENDPOINT;return{pluginRoot:e,pluginData:t,tracePath:w.default.join(t,"trace.json"),endpoint:s?.replace(/\/+$/,""),headers:(0,Ke.parseHeadersEnv)(a??""),guardEndpoint:u}}function ze(e){return e.hook_event_name==="PreToolUse"}function We(e){return e.hook_event_name==="PermissionRequest"}function Ze(e){return e.hook_event_name==="PostToolUse"}function Je(e){return e.hook_event_name==="UserPromptSubmit"}function Qe(e){return e.hook_event_name==="SessionStart"}function et(e){return e.hook_event_name==="Stop"}var or=["PreToolUse","PermissionRequest"],sr=["PostToolUse","PreCompact","PostCompact","SessionStart","SessionEnd","UserPromptSubmit","SubagentStart","SubagentStop","Stop","Interrupt"],ir=new Set([...or,...sr]);function tt(e){return!ir.has(e.hook_event_name)}var rt=_(x()),q=class extends rt.DiskTransport{constructor(t){super({pluginData:t.pluginData,logPrefix:"pinta-codex",resolveOptions:()=>t.endpoint?{endpoint:t.endpoint,headers:t.headers}:null})}};var nt=_(x()),U=class extends nt.TraceManager{constructor(t){super(t.tracePath)}};var M=_(require("fs")),$=_(require("os")),st=_(require("path")),T=_(x()),L;function ar(){if(L===void 0)try{L=$.default.userInfo().username}catch{L=process.env.USER??process.env.LOGNAME??(typeof process.getuid=="function"?String(process.getuid()):"unknown")}return L}var it="1.8.0",ce;function C(e){return typeof e=="string"&&e.trim()!==""?e.trim():void 0}var ot=256*1024;function ur(e){if(!e)return;let t;try{t=M.default.openSync(e,"r");let r=Buffer.allocUnsafe(ot),n=M.default.readSync(t,r,0,ot,0),o=r.toString("utf8",0,n),s=o.indexOf(`
21
+ `);if(s<0)return;let a=JSON.parse(o.slice(0,s));return a?.type!=="session_meta"?void 0:C(a.payload?.cli_version)}catch{return}finally{if(t!==void 0)try{M.default.closeSync(t)}catch{}}}function cr(){let e=C(process.env.CODEX_MANAGED_PACKAGE_ROOT);if(e)try{let t=JSON.parse(M.default.readFileSync(st.default.join(e,"package.json"),"utf8"));return C(t.version)}catch{return}}function lr(e){return ce===void 0&&(ce=ur(C(e?.transcript_path))??cr()??C(process.env.CODEX_CLI_VERSION)??null),ce??void 0}var dr=new Set(["codex.hook","codex.tool_name","codex.tool_use_id","codex.session_id","codex.transcript_path","codex.cwd","codex.permission_mode"]),pr=new Set(["codex.tool_input","codex.tool_response"]),fr={skipRedactKeys:dr,bashContextKeys:pr};function mr(e){let t=[];t.push({key:"ingest.type",value:{stringValue:"codex"}}),t.push({key:"codex.hook",value:{stringValue:e.hook_event_name}});let r={};for(let[n,o]of Object.entries(e))n!=="hook_event_name"&&(r[n]=o);return t.push(...(0,T.attrsFromRecord)(r,"codex",fr)),t}function _r(e){let t=lr(e);return[{key:"service.name",value:{stringValue:"codex"}},...t?[{key:"service.version",value:{stringValue:t}}]:[],{key:"telemetry.sdk.name",value:{stringValue:"pinta-codex"}},{key:"telemetry.sdk.language",value:{stringValue:"nodejs"}},{key:"telemetry.sdk.version",value:{stringValue:it}},{key:"process.pid",value:{intValue:process.pid}},{key:"process.owner",value:{stringValue:ar()}},{key:"host.name",value:{stringValue:$.default.hostname()}},{key:"host.arch",value:{stringValue:$.default.arch()}}]}function at(e){return(0,T.buildPayload)({traceId:e.traceId,spanName:`codex.${(0,T.snakeCase)(e.event.hook_event_name)}`,attributes:mr(e.event),resource:_r(e.event),scope:{name:"pinta-codex",version:it},now:e.now,guard:e.guard})}async function f(e,t,r){let n=new q(t);await n.flush();let o=new U(t),s=r.trace==="new"?o.newTrace():o.currentTrace(),a=at({event:e,traceId:s,guard:r.guard});await n.send(a)}var ut=_(x()),gr=50,hr="pinta-codex/1.8.0";async function ct(e,t){let r=await(0,ut.evaluateGuard)(e,t,{timeoutMs:gr,token:process.env.PINTA_RELAY_TOKEN??"",disabled:process.env.PINTA_GUARD_DISABLED==="1",userAgent:hr});if(r===null)return null;let n={decision:r.decision,reason:r.reason,durationMs:r.durationMs,clientRttMs:r.clientRttMs};return r.failOpenReason!==void 0&&(n.failOpenReason=r.failOpenReason),n}async function G(e,t){let r=typeof e.tool_input=="string"?e.tool_input:JSON.stringify(e.tool_input);return ct({spanId:e.session_id??"unknown",toolName:e.tool_name,method:e.hook_event_name,cwd:e.cwd,toolInput:e.tool_input,rawTextFields:{toolInput:r}},t.guardEndpoint)}function X(e){let t=e?.reason;return typeof t=="string"&&t.trim().length>0?t:"guard_deny"}async function lt(e,t){let r=await G(e,t);if(r?.decision==="DENY"){let n={hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:X(r)}};process.stdout.write(JSON.stringify(n)+`
22
+ `)}try{await f(e,t,{trace:"current",guard:r})}catch(n){process.stderr.write(`[pinta-codex] telemetry emit failed: ${n}
23
+ `)}return 0}async function dt(e,t){let r=await G(e,t);if(r?.decision==="DENY"){let n={hookSpecificOutput:{hookEventName:"PermissionRequest",decision:{behavior:"deny",message:X(r)}}};process.stdout.write(JSON.stringify(n)+`
24
+ `)}try{await f(e,t,{trace:"current",guard:r})}catch(n){process.stderr.write(`[pinta-codex] telemetry emit failed: ${n}
25
+ `)}return 0}async function pt(e,t){return await f(e,t,{trace:"current"}),0}async function ft(e,t){return await f(e,t,{trace:"new"}),0}async function mt(e,t){return await f(e,t,{trace:"current"}),0}async function _t(e,t){return await f(e,t,{trace:"current"}),0}async function gt(e,t){return await f(e,t,{trace:"current"}),0}async function ht(e){return 0}async function yr(){let e=[];for await(let t of process.stdin)e.push(t);return Buffer.concat(e).toString("utf-8")}async function yt(){let e=0;try{let t=He(),r=await yr(),n=JSON.parse(r);tt(n)?e=await ht(n):ze(n)?e=await lt(n,t):We(n)?e=await dt(n,t):Ze(n)?e=await pt(n,t):Je(n)?e=await ft(n,t):Qe(n)?e=await mt(n,t):et(n)?e=await _t(n,t):e=await gt(n,t)}catch(t){process.stderr.write(`[pinta-codex] error: ${t}
26
+ `),e=0}return e}async function Pr(){let e=await yt();process.exit(e)}Pr();
package/dist/index.mjs CHANGED
@@ -1,24 +1,27 @@
1
1
  import{createRequire as __pintaCreateRequire}from 'node:module';const require=__pintaCreateRequire(import.meta.url);
2
- var mt=Object.create;var ue=Object.defineProperty;var ht=Object.getOwnPropertyDescriptor;var gt=Object.getOwnPropertyNames;var yt=Object.getPrototypeOf,Pt=Object.prototype.hasOwnProperty;var _=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,r)=>(typeof require<"u"?require:t)[r]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var g=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Et=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of gt(t))!Pt.call(e,o)&&o!==r&&ue(e,o,{get:()=>t[o],enumerable:!(n=ht(t,o))||n.enumerable});return e};var x=(e,t,r)=>(r=e!=null?mt(yt(e)):{},Et(t||!e||!e.__esModule?ue(r,"default",{value:e,enumerable:!0}):r,e));var $=g(d=>{"use strict";Object.defineProperty(d,"__esModule",{value:!0});d.PATTERNS=d.MAX_BYTES=void 0;d.truncateTo=ce;d.truncate=Tt;d.collectMatches=le;d.resolveOverlaps=pe;d.applyMatches=de;d.redact=vt;d.MAX_BYTES=102400;function ce(e,t){let r=Buffer.from(e,"utf-8");return r.length<=t?e:`${r.subarray(0,Math.max(0,t)).toString("utf-8")}\u2026[TRUNCATED:${r.length}]`}function Tt(e){return ce(e,d.MAX_BYTES)}d.PATTERNS=[{type:"aws_access_key",regex:/AKIA[0-9A-Z]{16}/g},{type:"aws_secret_key",regex:/(?:aws[_-]?secret(?:[_-]?(?:access)?[_-]?key)?)\s*[:=]\s*["']?([A-Za-z0-9/+=]{40})(?![A-Za-z0-9/+=])/gi,captureGroup:1},{type:"gcp_service_account",regex:/\{[\s\S]{0,200}?"type"\s*:\s*"service_account"[\s\S]*?\}/g},{type:"github_token",regex:/gh[pousr]_[A-Za-z0-9]{36,}/g},{type:"gitlab_token",regex:/glpat-[A-Za-z0-9_-]{20}/g},{type:"slack_token",regex:/xox[abrsp]-[0-9A-Za-z-]{10,}/g},{type:"openai_key",regex:/sk-(?:proj-)?[A-Za-z0-9_-]{40,}/g},{type:"anthropic_key",regex:/sk-ant-[A-Za-z0-9_-]{50,}/g},{type:"stripe_key",regex:/(?:sk|rk|pk)_(?:live|test)_[A-Za-z0-9]{20,}/g},{type:"jwt",regex:/eyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g},{type:"private_key_block",regex:/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g},{type:"bearer_token",regex:/bearer\s+([A-Za-z0-9._~+/=-]{12,})/gi,captureGroup:1},{type:"basic_auth",regex:/basic\s+([A-Za-z0-9+/=]{12,})/gi,captureGroup:1},{type:"db_url_password",regex:/\b(?:postgres|postgresql|mysql|mariadb|mongodb(?:\+srv)?|redis):\/\/[^:\s/]+:([^@\s]+)@/gi,captureGroup:1},{type:"cli_password_flag",regex:/(?:--password|--pass|--pwd)[=\s]([^\s'"]+)/g,captureGroup:1},{type:"cli_password_short",regex:/\s-p([^\s'"]+)/g,captureGroup:1,requireContext:"bash"},{type:"env_var_secret",regex:/^(?:export\s+)?([A-Z][A-Z0-9_]*(?:KEY|SECRET|TOKEN|PASSWORD|PASSWD|PWD|API_KEY)[A-Z0-9_]*)\s*=\s*["']?([^\s"'\n]+)/gm,captureGroup:2}];function le(e,t){let r=[];for(let n of d.PATTERNS){if(n.requireContext&&n.requireContext!==t.context)continue;let o=new RegExp(n.regex.source,n.regex.flags),s;for(;(s=o.exec(e))!==null;){let a=n.captureGroup??0,u=s[a];if(u===void 0){s.index===o.lastIndex&&o.lastIndex++;continue}let c=s.index,h=s.index+s[0].length,A=c+s[0].indexOf(u),_t=A+u.length;r.push({start:c,end:h,replaceStart:A,replaceEnd:_t,type:n.type}),s.index===o.lastIndex&&o.lastIndex++}}return r}function pe(e){let t=[...e].sort((o,s)=>o.start!==s.start?o.start-s.start:s.end-s.start-(o.end-o.start)),r=[],n=-1;for(let o of t)o.start<n||(r.push(o),n=o.end);return r}function de(e,t){let r=[...t].sort((o,s)=>s.replaceStart-o.replaceStart),n=e;for(let o of r)n=n.slice(0,o.replaceStart)+`[REDACTED:${o.type}]`+n.slice(o.replaceEnd);return n}function vt(e,t={}){if(e.length===0)return e;let r=le(e,t);if(r.length===0)return e;let n=pe(r);return de(e,n)}});var F=g(p=>{"use strict";var Ot=p&&p.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(p,"__esModule",{value:!0});p.MAX_SPAN_BYTES=void 0;p.ulidToTraceId=he;p.newSpanId=ge;p.snakeCase=xt;p.toOtlpValue=ye;p.attrsFromRecord=kt;p.guardAttrs=Pe;p.clientAttrs=Ee;p.enforceSpanBudget=Te;p.buildPayload=At;p.mergeBatch=wt;var St=Ot(_("crypto")),X=$(),bt="0123456789ABCDEFGHJKMNPQRSTVWXYZ";function he(e){if(e.length!==26)throw new Error(`ulidToTraceId: expected 26 chars, got ${e.length}`);let t=0n;for(let n of e){let o=bt.indexOf(n);if(o<0)throw new Error(`ulidToTraceId: invalid Crockford char "${n}"`);t=t<<5n|BigInt(o)}let r=(1n<<128n)-1n;return t&=r,t.toString(16).padStart(32,"0")}function ge(){return St.default.randomBytes(8).toString("hex")}function xt(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1_$2").replace(/([A-Z])([A-Z][a-z])/g,"$1_$2").toLowerCase()}var fe=new Set;function M(e,t,r){let n=(0,X.truncate)(t);if((r.skipRedactKeys??fe).has(e))return n;let o=(r.bashContextKeys??fe).has(e)?"bash":void 0;return(0,X.redact)(n,{context:o})}function ye(e,t,r={}){if(t==null)return null;switch(typeof t){case"string":return{stringValue:M(e,t,r)};case"boolean":return{boolValue:t};case"number":return Number.isInteger(t)?{intValue:t}:{doubleValue:t};case"object":try{return{stringValue:M(e,JSON.stringify(t),r)}}catch{return{stringValue:M(e,String(t),r)}}default:return{stringValue:M(e,String(t),r)}}}function kt(e,t,r={}){let n=[];for(let[o,s]of Object.entries(e)){let a=`${t}.${o}`,u=ye(a,s,r);u!==null&&n.push({key:a,value:u})}return n}function Pe(e){let t=[{key:"pinta.guard.decision",value:{stringValue:e.decision.toLowerCase()}},{key:"pinta.guard.duration_ms",value:{intValue:e.durationMs}}];return e.reason&&t.push({key:"pinta.guard.matched_rule",value:{stringValue:e.reason}}),e.failOpenReason&&t.push({key:"pinta.guard.fail_open_reason",value:{stringValue:e.failOpenReason}}),t}function Ee(e){return[{key:"pinta.client.rtt_ms",value:Number.isInteger(e.rttMs)?{intValue:e.rttMs}:{doubleValue:e.rttMs}},{key:"pinta.client.op",value:{stringValue:e.op}}]}p.MAX_SPAN_BYTES=800*1024;function _e(e){let t=JSON.stringify(e);return t===void 0?0:Buffer.byteLength(t,"utf-8")}var me=1024;function Te(e,t=p.MAX_SPAN_BYTES){let r=_e(e);for(let n=0;n<100&&r>t;n++){let o=null,s=0;for(let c of e.attributes){if(!("stringValue"in c.value))continue;let h=Buffer.byteLength(c.value.stringValue,"utf-8");h>s&&(s=h,o=c.value)}if(o===null||s<=me)break;let a=r-t,u=Math.max(me,s-a-64);o.stringValue=(0,X.truncateTo)(o.stringValue,u),r=_e(e)}return e}function At(e){let t=e.now??Date.now(),r=(BigInt(t)*1000000n).toString(),n=[...e.attributes];e.guard&&n.push(...Pe(e.guard));let o=e.clientTiming??(e.guard?.clientRttMs!==void 0?{op:"guard",rttMs:e.guard.clientRttMs}:null);o&&n.push(...Ee(o));let s={traceId:he(e.traceId),spanId:ge(),name:e.spanName,kind:e.spanKind??1,startTimeUnixNano:r,endTimeUnixNano:r,attributes:n};return Te(s),{resourceSpans:[{resource:{attributes:e.resource},scopeSpans:[{scope:e.scope,spans:[s]}]}]}}function wt(e){let t=[];for(let r of e)t.push(...r.resourceSpans);return{resourceSpans:t}}});var ve=g(G=>{"use strict";Object.defineProperty(G,"__esModule",{value:!0});G.evaluateGuard=It;var Rt=1e4,Mt="pinta-core";function Y(e,t){return{decision:"ALLOW",reason:null,userMessage:null,durationMs:e,clientRttMs:e,failOpenReason:t}}var Dt=new Set(["ALLOW","DENY","REVIEW"]);async function It(e,t,r={}){if(!t||r.disabled)return null;let n=r.timeoutMs??Rt,o=Date.now(),s=new AbortController,a=setTimeout(()=>s.abort(),n);try{let u=await fetch(t,{method:"POST",headers:{"content-type":"application/json","user-agent":r.userAgent??Mt,"x-pinta-relay-token":r.token??""},body:JSON.stringify({input:e}),signal:s.signal});if(u.status!==200)return Y(Date.now()-o,"error");let c=await u.json(),h=c?.durationMs===void 0||typeof c.durationMs=="number"&&Number.isFinite(c.durationMs);if(!c||!Dt.has(c.decision)||!h)return Y(Date.now()-o,"error");let A=Date.now()-o;return{decision:c.decision,reason:c.reason??null,userMessage:c.userMessage??null,durationMs:c.durationMs??A,clientRttMs:A}}catch(u){let c=u.name,h=c==="AbortError"||c==="TimeoutError"?"timeout":"error";return Y(Date.now()-o,h)}finally{clearTimeout(a)}}});var D=g(w=>{"use strict";var jt=w&&w.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(w,"__esModule",{value:!0});w.atomicWriteFileSync=Nt;var Oe=jt(_("fs"));function Nt(e,t){let r=`${e}.${process.pid}.tmp`;Oe.default.writeFileSync(r,t),Oe.default.renameSync(r,e)}});var z=g(P=>{"use strict";var Se=P&&P.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(P,"__esModule",{value:!0});P.MemoryRetryQueue=P.DiskRetryQueue=void 0;var f=Se(_("fs")),I=Se(_("path")),Ct=D(),j=1e3,Bt=50,Lt=5,V=class{filePath;lockPath;logPrefix;constructor(t,r){this.filePath=I.default.join(t,"failed-spans.jsonl"),this.lockPath=this.filePath+".lock",this.logPrefix=r}enqueue(t){try{f.default.mkdirSync(I.default.dirname(this.filePath),{recursive:!0});let r=JSON.stringify({savedAt:new Date().toISOString(),payload:t})+`
3
- `;f.default.appendFileSync(this.filePath,r),this.trim()}catch(r){process.stderr.write(`[${this.logPrefix}] retry-queue enqueue failed: ${r}
4
- `)}}readAll(){try{let t=f.default.readFileSync(this.filePath,"utf-8"),r=[];for(let n of t.split(`
5
- `))if(n.trim())try{let o=JSON.parse(n);Array.isArray(o?.payload?.resourceSpans)&&r.push(o)}catch{}return r}catch{return[]}}rewrite(t){try{if(t.length===0){f.default.existsSync(this.filePath)&&f.default.unlinkSync(this.filePath);return}f.default.mkdirSync(I.default.dirname(this.filePath),{recursive:!0}),(0,Ct.atomicWriteFileSync)(this.filePath,t.map(r=>JSON.stringify(r)).join(`
2
+ var Ot=Object.create;var pe=Object.defineProperty;var St=Object.getOwnPropertyDescriptor;var bt=Object.getOwnPropertyNames;var xt=Object.getPrototypeOf,kt=Object.prototype.hasOwnProperty;var _=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,r)=>(typeof require<"u"?require:t)[r]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var y=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var At=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of bt(t))!kt.call(e,o)&&o!==r&&pe(e,o,{get:()=>t[o],enumerable:!(n=St(t,o))||n.enumerable});return e};var x=(e,t,r)=>(r=e!=null?Ot(xt(e)):{},At(t||!e||!e.__esModule?pe(r,"default",{value:e,enumerable:!0}):r,e));var X=y(d=>{"use strict";Object.defineProperty(d,"__esModule",{value:!0});d.PATTERNS=d.MAX_BYTES=void 0;d.truncateTo=de;d.truncate=Rt;d.collectMatches=fe;d.resolveOverlaps=me;d.applyMatches=_e;d.redact=wt;d.MAX_BYTES=102400;function de(e,t){let r=Buffer.from(e,"utf-8");return r.length<=t?e:`${r.subarray(0,Math.max(0,t)).toString("utf-8")}\u2026[TRUNCATED:${r.length}]`}function Rt(e){return de(e,d.MAX_BYTES)}d.PATTERNS=[{type:"aws_access_key",regex:/AKIA[0-9A-Z]{16}/g},{type:"aws_secret_key",regex:/(?:aws[_-]?secret(?:[_-]?(?:access)?[_-]?key)?)\s*[:=]\s*["']?([A-Za-z0-9/+=]{40})(?![A-Za-z0-9/+=])/gi,captureGroup:1},{type:"gcp_service_account",regex:/\{[\s\S]{0,200}?"type"\s*:\s*"service_account"[\s\S]*?\}/g},{type:"github_token",regex:/gh[pousr]_[A-Za-z0-9]{36,}/g},{type:"gitlab_token",regex:/glpat-[A-Za-z0-9_-]{20}/g},{type:"slack_token",regex:/xox[abrsp]-[0-9A-Za-z-]{10,}/g},{type:"openai_key",regex:/sk-(?:proj-)?[A-Za-z0-9_-]{40,}/g},{type:"anthropic_key",regex:/sk-ant-[A-Za-z0-9_-]{50,}/g},{type:"stripe_key",regex:/(?:sk|rk|pk)_(?:live|test)_[A-Za-z0-9]{20,}/g},{type:"jwt",regex:/eyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g},{type:"private_key_block",regex:/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g},{type:"bearer_token",regex:/bearer\s+([A-Za-z0-9._~+/=-]{12,})/gi,captureGroup:1},{type:"basic_auth",regex:/basic\s+([A-Za-z0-9+/=]{12,})/gi,captureGroup:1},{type:"db_url_password",regex:/\b(?:postgres|postgresql|mysql|mariadb|mongodb(?:\+srv)?|redis):\/\/[^:\s/]+:([^@\s]+)@/gi,captureGroup:1},{type:"cli_password_flag",regex:/(?:--password|--pass|--pwd)[=\s]([^\s'"]+)/g,captureGroup:1},{type:"cli_password_short",regex:/\s-p([^\s'"]+)/g,captureGroup:1,requireContext:"bash"},{type:"env_var_secret",regex:/^(?:export\s+)?([A-Z][A-Z0-9_]*(?:KEY|SECRET|TOKEN|PASSWORD|PASSWD|PWD|API_KEY)[A-Z0-9_]*)\s*=\s*["']?([^\s"'\n]+)/gm,captureGroup:2}];function fe(e,t){let r=[];for(let n of d.PATTERNS){if(n.requireContext&&n.requireContext!==t.context)continue;let o=new RegExp(n.regex.source,n.regex.flags),s;for(;(s=o.exec(e))!==null;){let a=n.captureGroup??0,u=s[a];if(u===void 0){s.index===o.lastIndex&&o.lastIndex++;continue}let c=s.index,h=s.index+s[0].length,A=c+s[0].indexOf(u),Tt=A+u.length;r.push({start:c,end:h,replaceStart:A,replaceEnd:Tt,type:n.type}),s.index===o.lastIndex&&o.lastIndex++}}return r}function me(e){let t=[...e].sort((o,s)=>o.start!==s.start?o.start-s.start:s.end-s.start-(o.end-o.start)),r=[],n=-1;for(let o of t)o.start<n||(r.push(o),n=o.end);return r}function _e(e,t){let r=[...t].sort((o,s)=>s.replaceStart-o.replaceStart),n=e;for(let o of r)n=n.slice(0,o.replaceStart)+`[REDACTED:${o.type}]`+n.slice(o.replaceEnd);return n}function wt(e,t={}){if(e.length===0)return e;let r=fe(e,t);if(r.length===0)return e;let n=me(r);return _e(e,n)}});var V=y(p=>{"use strict";var Mt=p&&p.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(p,"__esModule",{value:!0});p.MAX_SPAN_BYTES=void 0;p.ulidToTraceId=Pe;p.newSpanId=Ee;p.snakeCase=It;p.toOtlpValue=ve;p.attrsFromRecord=Dt;p.guardAttrs=Te;p.clientAttrs=Oe;p.enforceSpanBudget=Se;p.buildPayload=Nt;p.mergeBatch=Bt;var Ct=Mt(_("crypto")),Y=X(),jt="0123456789ABCDEFGHJKMNPQRSTVWXYZ";function Pe(e){if(e.length!==26)throw new Error(`ulidToTraceId: expected 26 chars, got ${e.length}`);let t=0n;for(let n of e){let o=jt.indexOf(n);if(o<0)throw new Error(`ulidToTraceId: invalid Crockford char "${n}"`);t=t<<5n|BigInt(o)}let r=(1n<<128n)-1n;return t&=r,t.toString(16).padStart(32,"0")}function Ee(){return Ct.default.randomBytes(8).toString("hex")}function It(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1_$2").replace(/([A-Z])([A-Z][a-z])/g,"$1_$2").toLowerCase()}var ge=new Set;function C(e,t,r){let n=(0,Y.truncate)(t);if((r.skipRedactKeys??ge).has(e))return n;let o=(r.bashContextKeys??ge).has(e)?"bash":void 0;return(0,Y.redact)(n,{context:o})}function ve(e,t,r={}){if(t==null)return null;switch(typeof t){case"string":return{stringValue:C(e,t,r)};case"boolean":return{boolValue:t};case"number":return Number.isInteger(t)?{intValue:t}:{doubleValue:t};case"object":try{return{stringValue:C(e,JSON.stringify(t),r)}}catch{return{stringValue:C(e,String(t),r)}}default:return{stringValue:C(e,String(t),r)}}}function Dt(e,t,r={}){let n=[];for(let[o,s]of Object.entries(e)){let a=`${t}.${o}`,u=ve(a,s,r);u!==null&&n.push({key:a,value:u})}return n}function Te(e){let t=[{key:"pinta.guard.decision",value:{stringValue:e.decision.toLowerCase()}},{key:"pinta.guard.duration_ms",value:{intValue:e.durationMs}}];return e.reason&&t.push({key:"pinta.guard.matched_rule",value:{stringValue:e.reason}}),e.failOpenReason&&t.push({key:"pinta.guard.fail_open_reason",value:{stringValue:e.failOpenReason}}),t}function Oe(e){return[{key:"pinta.client.rtt_ms",value:Number.isInteger(e.rttMs)?{intValue:e.rttMs}:{doubleValue:e.rttMs}},{key:"pinta.client.op",value:{stringValue:e.op}}]}p.MAX_SPAN_BYTES=800*1024;function he(e){let t=JSON.stringify(e);return t===void 0?0:Buffer.byteLength(t,"utf-8")}var ye=1024;function Se(e,t=p.MAX_SPAN_BYTES){let r=he(e);for(let n=0;n<100&&r>t;n++){let o=null,s=0;for(let c of e.attributes){if(!("stringValue"in c.value))continue;let h=Buffer.byteLength(c.value.stringValue,"utf-8");h>s&&(s=h,o=c.value)}if(o===null||s<=ye)break;let a=r-t,u=Math.max(ye,s-a-64);o.stringValue=(0,Y.truncateTo)(o.stringValue,u),r=he(e)}return e}function Nt(e){let t=e.now??Date.now(),r=(BigInt(t)*1000000n).toString(),n=[...e.attributes];e.guard&&n.push(...Te(e.guard));let o=e.clientTiming??(e.guard?.clientRttMs!==void 0?{op:"guard",rttMs:e.guard.clientRttMs}:null);o&&n.push(...Oe(o));let s={traceId:Pe(e.traceId),spanId:Ee(),name:e.spanName,kind:e.spanKind??1,startTimeUnixNano:r,endTimeUnixNano:r,attributes:n};return Se(s),{resourceSpans:[{resource:{attributes:e.resource},scopeSpans:[{scope:e.scope,spans:[s]}]}]}}function Bt(e){let t=[];for(let r of e)t.push(...r.resourceSpans);return{resourceSpans:t}}});var be=y(z=>{"use strict";Object.defineProperty(z,"__esModule",{value:!0});z.evaluateGuard=$t;var qt=1e4,Lt="pinta-core";function K(e,t){return{decision:"ALLOW",reason:null,userMessage:null,durationMs:e,clientRttMs:e,failOpenReason:t}}var Ut=new Set(["ALLOW","DENY","REVIEW"]);async function $t(e,t,r={}){if(!t||r.disabled)return null;let n=r.timeoutMs??qt,o=Date.now(),s=new AbortController,a=setTimeout(()=>s.abort(),n);try{let u=await fetch(t,{method:"POST",headers:{"content-type":"application/json","user-agent":r.userAgent??Lt,"x-pinta-relay-token":r.token??""},body:JSON.stringify({input:e}),signal:s.signal});if(u.status!==200)return K(Date.now()-o,"error");let c=await u.json(),h=c?.durationMs===void 0||typeof c.durationMs=="number"&&Number.isFinite(c.durationMs);if(!c||!Ut.has(c.decision)||!h)return K(Date.now()-o,"error");let A=Date.now()-o;return{decision:c.decision,reason:c.reason??null,userMessage:c.userMessage??null,durationMs:c.durationMs??A,clientRttMs:A}}catch(u){let c=u.name,h=c==="AbortError"||c==="TimeoutError"?"timeout":"error";return K(Date.now()-o,h)}finally{clearTimeout(a)}}});var j=y(R=>{"use strict";var Ft=R&&R.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(R,"__esModule",{value:!0});R.atomicWriteFileSync=Gt;var xe=Ft(_("fs"));function Gt(e,t){let r=`${e}.${process.pid}.tmp`;xe.default.writeFileSync(r,t),xe.default.renameSync(r,e)}});var Z=y(P=>{"use strict";var ke=P&&P.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(P,"__esModule",{value:!0});P.MemoryRetryQueue=P.DiskRetryQueue=void 0;var m=ke(_("fs")),I=ke(_("path")),Xt=j(),D=1e3,Yt=50,Vt=5,H=class{filePath;lockPath;logPrefix;constructor(t,r){this.filePath=I.default.join(t,"failed-spans.jsonl"),this.lockPath=this.filePath+".lock",this.logPrefix=r}enqueue(t){try{m.default.mkdirSync(I.default.dirname(this.filePath),{recursive:!0});let r=JSON.stringify({savedAt:new Date().toISOString(),payload:t})+`
3
+ `;m.default.appendFileSync(this.filePath,r),this.trim()}catch(r){process.stderr.write(`[${this.logPrefix}] retry-queue enqueue failed: ${r}
4
+ `)}}readAll(){try{let t=m.default.readFileSync(this.filePath,"utf-8"),r=[];for(let n of t.split(`
5
+ `))if(n.trim())try{let o=JSON.parse(n);Array.isArray(o?.payload?.resourceSpans)&&r.push(o)}catch{}return r}catch{return[]}}rewrite(t){try{if(t.length===0){m.default.existsSync(this.filePath)&&m.default.unlinkSync(this.filePath);return}m.default.mkdirSync(I.default.dirname(this.filePath),{recursive:!0}),(0,Xt.atomicWriteFileSync)(this.filePath,t.map(r=>JSON.stringify(r)).join(`
6
6
  `)+`
7
7
  `)}catch(r){process.stderr.write(`[${this.logPrefix}] retry-queue rewrite failed: ${r}
8
- `)}}tryAcquireLock(){let t=Date.now();try{f.default.mkdirSync(I.default.dirname(this.lockPath),{recursive:!0})}catch(r){return process.stderr.write(`[${this.logPrefix}] retry-queue lock mkdir failed: ${r}
9
- `),!1}for(;Date.now()-t<Bt;)try{let r=f.default.openSync(this.lockPath,"wx");return f.default.writeSync(r,String(process.pid)),f.default.closeSync(r),!0}catch(r){if(r?.code!=="EEXIST")return process.stderr.write(`[${this.logPrefix}] retry-queue lock open failed: ${r}
10
- `),!1;try{let s=f.default.statSync(this.lockPath);if(Date.now()-s.mtimeMs>3e4){f.default.unlinkSync(this.lockPath);continue}}catch{}let n=Lt,o=Date.now()+n;for(;Date.now()<o;);}return!1}release(){try{f.default.unlinkSync(this.lockPath)}catch{}}trim(){let t=this.readAll();if(t.length<=j)return;let r=t.length-j;process.stderr.write(`[${this.logPrefix}] retry-queue full, dropping ${r} oldest entries
11
- `),this.rewrite(t.slice(r))}};P.DiskRetryQueue=V;var K=class{entries=[];enqueue(t){this.entries.push(t),this.entries.length>j&&this.entries.splice(0,this.entries.length-j)}drain(){let t=this.entries;return this.entries=[],t}get size(){return this.entries.length}};P.MemoryRetryQueue=K});var Re=g(l=>{"use strict";Object.defineProperty(l,"__esModule",{value:!0});l.MemoryTransport=l.DiskTransport=l.MAX_POST_BYTES=void 0;l.parseHeadersEnv=Ae;l.envOptionsResolver=we;l.postOtlp=R;var be=z(),xe=F(),Ut=5e3;l.MAX_POST_BYTES=900*1024;function N(e){let t=JSON.stringify(e);return t===void 0?0:Buffer.byteLength(t,"utf-8")}function ke(e,t,r){let n=[],o=[],s=[],a=0;for(let u of e){let c=t(u);if(c>r){o.push(u);continue}s.length>0&&a+c>r&&(n.push(s),s=[],a=0),s.push(u),a+=c}return s.length>0&&n.push(s),{chunks:n,oversize:o}}function Ae(e){if(!e)return{};if(typeof e=="object")return{...e};let t={};for(let r of e.split(",")){let[n,...o]=r.split("=");n&&o.length>0&&(t[n.trim()]=o.join("=").trim())}return t}function we(){let e=process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,t=process.env.OTEL_EXPORTER_OTLP_ENDPOINT,r;return e?r=e.replace(/\/+$/,""):t&&(r=t.replace(/\/+$/,"")+"/v1/traces"),r?{endpoint:r,headers:Ae(process.env.OTEL_EXPORTER_OTLP_HEADERS)}:null}async function R(e,t,r){let n=new AbortController,o=setTimeout(()=>n.abort(),Ut);try{let s=await fetch(t.endpoint,{method:"POST",headers:{"Content-Type":"application/json",...t.headers},body:JSON.stringify(e),signal:n.signal});if(!s.ok){let a="";try{a=(await s.text()).slice(0,200)}catch{}let u=s.status===401||s.status===403?" \u2014 check OTEL_EXPORTER_OTLP_HEADERS (relay token)":s.status===404?" \u2014 check OTEL_EXPORTER_OTLP_TRACES_ENDPOINT path":s.status>=500?" \u2014 collector may be down":"";return process.stderr.write(`[${r}] OTLP POST ${s.status} ${t.endpoint}${u}${a?` body=${a}`:""}
8
+ `)}}tryAcquireLock(){let t=Date.now();try{m.default.mkdirSync(I.default.dirname(this.lockPath),{recursive:!0})}catch(r){return process.stderr.write(`[${this.logPrefix}] retry-queue lock mkdir failed: ${r}
9
+ `),!1}for(;Date.now()-t<Yt;)try{let r=m.default.openSync(this.lockPath,"wx");return m.default.writeSync(r,String(process.pid)),m.default.closeSync(r),!0}catch(r){if(r?.code!=="EEXIST")return process.stderr.write(`[${this.logPrefix}] retry-queue lock open failed: ${r}
10
+ `),!1;try{let s=m.default.statSync(this.lockPath);if(Date.now()-s.mtimeMs>3e4){m.default.unlinkSync(this.lockPath);continue}}catch{}let n=Vt,o=Date.now()+n;for(;Date.now()<o;);}return!1}release(){try{m.default.unlinkSync(this.lockPath)}catch{}}trim(){let t=this.readAll();if(t.length<=D)return;let r=t.length-D;process.stderr.write(`[${this.logPrefix}] retry-queue full, dropping ${r} oldest entries
11
+ `),this.rewrite(t.slice(r))}};P.DiskRetryQueue=H;var W=class{entries=[];enqueue(t){this.entries.push(t),this.entries.length>D&&this.entries.splice(0,this.entries.length-D)}drain(){let t=this.entries;return this.entries=[],t}get size(){return this.entries.length}};P.MemoryRetryQueue=W});var je=y(l=>{"use strict";Object.defineProperty(l,"__esModule",{value:!0});l.MemoryTransport=l.DiskTransport=l.MAX_POST_BYTES=void 0;l.parseHeadersEnv=Me;l.envOptionsResolver=Ce;l.postOtlp=w;var Ae=Z(),Re=V(),Kt=5e3;l.MAX_POST_BYTES=900*1024;function N(e){let t=JSON.stringify(e);return t===void 0?0:Buffer.byteLength(t,"utf-8")}function we(e,t,r){let n=[],o=[],s=[],a=0;for(let u of e){let c=t(u);if(c>r){o.push(u);continue}s.length>0&&a+c>r&&(n.push(s),s=[],a=0),s.push(u),a+=c}return s.length>0&&n.push(s),{chunks:n,oversize:o}}function Me(e){if(!e)return{};if(typeof e=="object")return{...e};let t={};for(let r of e.split(",")){let[n,...o]=r.split("=");n&&o.length>0&&(t[n.trim()]=o.join("=").trim())}return t}function Ce(){let e=process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,t=process.env.OTEL_EXPORTER_OTLP_ENDPOINT,r;return e?r=e.replace(/\/+$/,""):t&&(r=t.replace(/\/+$/,"")+"/v1/traces"),r?{endpoint:r,headers:Me(process.env.OTEL_EXPORTER_OTLP_HEADERS)}:null}async function w(e,t,r){let n=new AbortController,o=setTimeout(()=>n.abort(),Kt);try{let s=await fetch(t.endpoint,{method:"POST",headers:{"Content-Type":"application/json",...t.headers},body:JSON.stringify(e),signal:n.signal});if(!s.ok){let a="";try{a=(await s.text()).slice(0,200)}catch{}let u=s.status===401||s.status===403?" \u2014 check OTEL_EXPORTER_OTLP_HEADERS (relay token)":s.status===404?" \u2014 check OTEL_EXPORTER_OTLP_TRACES_ENDPOINT path":s.status>=500?" \u2014 collector may be down":"";return process.stderr.write(`[${r}] OTLP POST ${s.status} ${t.endpoint}${u}${a?` body=${a}`:""}
12
12
  `),!1}return!0}catch(s){return process.stderr.write(`[${r}] OTLP POST failed: ${s.message??String(s)}
13
- `),!1}finally{clearTimeout(o)}}var W=class{queue;logPrefix;resolveOptions;constructor(t){this.queue=new be.DiskRetryQueue(t.pluginData,t.logPrefix),this.logPrefix=t.logPrefix,this.resolveOptions=t.resolveOptions??we}async send(t){let r=this.resolveOptions();if(!r||this.dropIfOversized(t))return;await R(t,r,this.logPrefix)||this.queue.enqueue(t)}async flush(){let t=this.resolveOptions();if(t&&this.queue.tryAcquireLock())try{let r=this.queue.readAll();if(r.length===0)return;let{chunks:n,oversize:o}=ke(r,u=>N(u.payload),l.MAX_POST_BYTES);o.length>0&&process.stderr.write(`[${this.logPrefix}] dropping ${o.length} oversized retry ${o.length===1?"entry":"entries"} (each > ${l.MAX_POST_BYTES} bytes \u2014 the backend caps the request body, so they can never be delivered)
14
- `);let s=[].concat(...n),a=0;for(let u of n){if(!await R((0,xe.mergeBatch)(u.map(h=>h.payload)),t,this.logPrefix))break;a+=u.length}this.queue.rewrite(s.slice(a))}catch(r){process.stderr.write(`[${this.logPrefix}] flush failed: ${r?.message??String(r)}
13
+ `),!1}finally{clearTimeout(o)}}var J=class{queue;logPrefix;resolveOptions;constructor(t){this.queue=new Ae.DiskRetryQueue(t.pluginData,t.logPrefix),this.logPrefix=t.logPrefix,this.resolveOptions=t.resolveOptions??Ce}async send(t){let r=this.resolveOptions();if(!r||this.dropIfOversized(t))return;await w(t,r,this.logPrefix)||this.queue.enqueue(t)}async flush(){let t=this.resolveOptions();if(t&&this.queue.tryAcquireLock())try{let r=this.queue.readAll();if(r.length===0)return;let{chunks:n,oversize:o}=we(r,u=>N(u.payload),l.MAX_POST_BYTES);o.length>0&&process.stderr.write(`[${this.logPrefix}] dropping ${o.length} oversized retry ${o.length===1?"entry":"entries"} (each > ${l.MAX_POST_BYTES} bytes \u2014 the backend caps the request body, so they can never be delivered)
14
+ `);let s=[].concat(...n),a=0;for(let u of n){if(!await w((0,Re.mergeBatch)(u.map(h=>h.payload)),t,this.logPrefix))break;a+=u.length}this.queue.rewrite(s.slice(a))}catch(r){process.stderr.write(`[${this.logPrefix}] flush failed: ${r?.message??String(r)}
15
15
  `)}finally{this.queue.release()}}dropIfOversized(t){let r=N(t);return r<=l.MAX_POST_BYTES?!1:(process.stderr.write(`[${this.logPrefix}] dropping oversized span payload (${r} > ${l.MAX_POST_BYTES} bytes) \u2014 undeliverable, not queued
16
- `),!0)}};l.DiskTransport=W;var H=class{queue=new be.MemoryRetryQueue;logPrefix;resolveOptions;constructor(t){this.logPrefix=t.logPrefix,this.resolveOptions=t.resolveOptions}async send(t){let r=this.resolveOptions();if(!r)return;if(N(t)>l.MAX_POST_BYTES){process.stderr.write(`[${this.logPrefix}] dropping oversized span payload (> ${l.MAX_POST_BYTES} bytes) \u2014 undeliverable, not buffered
17
- `);return}await R(t,r,this.logPrefix)||this.queue.enqueue(t)}async flush(){let t=this.resolveOptions();if(!t)return;let r=this.queue.drain();if(r.length===0)return;let{chunks:n,oversize:o}=ke(r,N,l.MAX_POST_BYTES);o.length>0&&process.stderr.write(`[${this.logPrefix}] dropping ${o.length} oversized buffered ${o.length===1?"payload":"payloads"} (each > ${l.MAX_POST_BYTES} bytes \u2014 undeliverable)
18
- `);let s=[].concat(...n),a=0;for(let u of n){if(!await R((0,xe.mergeBatch)(u),t,this.logPrefix))break;a+=u.length}for(let u of s.slice(a))this.queue.enqueue(u)}};l.MemoryTransport=H});var ee=g(v=>{"use strict";var Q=v&&v.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(v,"__esModule",{value:!0});v.TraceManager=void 0;v.generateUlid=De;var Me=Q(_("fs")),qt=Q(_("path")),$t=Q(_("crypto")),Xt=D(),Z="0123456789ABCDEFGHJKMNPQRSTVWXYZ";function De(){let e=Date.now(),t="",r=e;for(let s=0;s<10;s++)t=Z[r&31]+t,r=Math.floor(r/32);let n=$t.default.randomBytes(10),o="";for(let s=0;s<10;s++)o+=Z[n[s]&31];for(;o.length<16;)o+=Z[0];return t+o}var J=class{tracePath;constructor(t){this.tracePath=t}newTrace(){let t=De();return this.save(t),t}currentTrace(){try{let t=Me.default.readFileSync(this.tracePath,"utf-8"),{traceId:r}=JSON.parse(t);if(r)return r}catch{}return this.newTrace()}save(t){try{Me.default.mkdirSync(qt.default.dirname(this.tracePath),{recursive:!0}),(0,Xt.atomicWriteFileSync)(this.tracePath,JSON.stringify({traceId:t}))}catch(r){process.stderr.write(`[pinta-core] trace persistence failed: ${r}
19
- `)}}};v.TraceManager=J});var Be=g(E=>{"use strict";var je=E&&E.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(E,"__esModule",{value:!0});E.MemorySessionTraceManager=E.DiskSessionTraceManager=void 0;var Ie=je(_("fs")),Ft=je(_("path")),Ne=ee(),Yt=D(),Ce=200,te=class{tracePath;maxSessions;constructor(t,r={}){this.tracePath=t,this.maxSessions=r.maxSessions??Ce}read(){try{let t=JSON.parse(Ie.default.readFileSync(this.tracePath,"utf-8"));if(t&&typeof t=="object"&&!("traceId"in t))return t}catch{}return{}}write(t){try{Ie.default.mkdirSync(Ft.default.dirname(this.tracePath),{recursive:!0});let r=Object.entries(t),n=r.length>this.maxSessions?Object.fromEntries(r.slice(-this.maxSessions)):t;(0,Yt.atomicWriteFileSync)(this.tracePath,JSON.stringify(n))}catch{}}newTrace(t){let r=t||"default",n=(0,Ne.generateUlid)(),o=this.read();return o[r]=n,this.write(o),n}currentTrace(t){let r=t||"default",n=this.read()[r];return n||this.newTrace(r)}};E.DiskSessionTraceManager=te;var re=class{map=new Map;maxSessions;constructor(t={}){this.maxSessions=t.maxSessions??Ce}newTrace(t){let r=t||"default",n=(0,Ne.generateUlid)();if(this.map.set(r,n),this.map.size>this.maxSessions){let o=this.map.keys().next().value;o!==void 0&&this.map.delete(o)}return n}currentTrace(t){let r=t||"default";return this.map.get(r)??this.newTrace(r)}};E.MemorySessionTraceManager=re});var qe=g(O=>{"use strict";var ne=O&&O.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(O,"__esModule",{value:!0});O.envFilePath=Kt;O.parseEnvFile=Ue;O.loadEnvFile=zt;var Gt=ne(_("node:fs")),Vt=ne(_("node:os")),Le=ne(_("node:path"));function Kt(e,t,r){let n=r?process.env[r]:void 0,o=n&&n.length>0?n:Le.default.join(Vt.default.homedir(),e);return Le.default.join(o,t)}function Ue(e){let t={};for(let r of e.split(`
20
- `)){let n=r.trim();if(!n||n.startsWith("#"))continue;let o=n.indexOf("=");if(o<0)continue;let s=n.slice(0,o).trim(),a=n.slice(o+1).trim();(a.startsWith('"')&&a.endsWith('"')||a.startsWith("'")&&a.endsWith("'"))&&(a=a.slice(1,-1)),s&&(t[s]=a)}return t}function zt(e){let t;try{t=Gt.default.readFileSync(e,"utf-8")}catch{return}let r=Ue(t);for(let[n,o]of Object.entries(r))process.env[n]===void 0&&(process.env[n]=o)}});var S=g(i=>{"use strict";Object.defineProperty(i,"__esModule",{value:!0});i.loadEnvFile=i.parseEnvFile=i.envFilePath=i.MemorySessionTraceManager=i.DiskSessionTraceManager=i.generateUlid=i.TraceManager=i.MAX_POST_BYTES=i.parseHeadersEnv=i.envOptionsResolver=i.postOtlp=i.MemoryTransport=i.DiskTransport=i.MemoryRetryQueue=i.DiskRetryQueue=i.evaluateGuard=i.MAX_SPAN_BYTES=i.enforceSpanBudget=i.mergeBatch=i.buildPayload=i.clientAttrs=i.guardAttrs=i.attrsFromRecord=i.toOtlpValue=i.snakeCase=i.newSpanId=i.ulidToTraceId=i.MAX_BYTES=i.PATTERNS=i.applyMatches=i.resolveOverlaps=i.collectMatches=i.truncateTo=i.truncate=i.redact=void 0;var T=$();Object.defineProperty(i,"redact",{enumerable:!0,get:function(){return T.redact}});Object.defineProperty(i,"truncate",{enumerable:!0,get:function(){return T.truncate}});Object.defineProperty(i,"truncateTo",{enumerable:!0,get:function(){return T.truncateTo}});Object.defineProperty(i,"collectMatches",{enumerable:!0,get:function(){return T.collectMatches}});Object.defineProperty(i,"resolveOverlaps",{enumerable:!0,get:function(){return T.resolveOverlaps}});Object.defineProperty(i,"applyMatches",{enumerable:!0,get:function(){return T.applyMatches}});Object.defineProperty(i,"PATTERNS",{enumerable:!0,get:function(){return T.PATTERNS}});Object.defineProperty(i,"MAX_BYTES",{enumerable:!0,get:function(){return T.MAX_BYTES}});var m=F();Object.defineProperty(i,"ulidToTraceId",{enumerable:!0,get:function(){return m.ulidToTraceId}});Object.defineProperty(i,"newSpanId",{enumerable:!0,get:function(){return m.newSpanId}});Object.defineProperty(i,"snakeCase",{enumerable:!0,get:function(){return m.snakeCase}});Object.defineProperty(i,"toOtlpValue",{enumerable:!0,get:function(){return m.toOtlpValue}});Object.defineProperty(i,"attrsFromRecord",{enumerable:!0,get:function(){return m.attrsFromRecord}});Object.defineProperty(i,"guardAttrs",{enumerable:!0,get:function(){return m.guardAttrs}});Object.defineProperty(i,"clientAttrs",{enumerable:!0,get:function(){return m.clientAttrs}});Object.defineProperty(i,"buildPayload",{enumerable:!0,get:function(){return m.buildPayload}});Object.defineProperty(i,"mergeBatch",{enumerable:!0,get:function(){return m.mergeBatch}});Object.defineProperty(i,"enforceSpanBudget",{enumerable:!0,get:function(){return m.enforceSpanBudget}});Object.defineProperty(i,"MAX_SPAN_BYTES",{enumerable:!0,get:function(){return m.MAX_SPAN_BYTES}});var Wt=ve();Object.defineProperty(i,"evaluateGuard",{enumerable:!0,get:function(){return Wt.evaluateGuard}});var $e=z();Object.defineProperty(i,"DiskRetryQueue",{enumerable:!0,get:function(){return $e.DiskRetryQueue}});Object.defineProperty(i,"MemoryRetryQueue",{enumerable:!0,get:function(){return $e.MemoryRetryQueue}});var k=Re();Object.defineProperty(i,"DiskTransport",{enumerable:!0,get:function(){return k.DiskTransport}});Object.defineProperty(i,"MemoryTransport",{enumerable:!0,get:function(){return k.MemoryTransport}});Object.defineProperty(i,"postOtlp",{enumerable:!0,get:function(){return k.postOtlp}});Object.defineProperty(i,"envOptionsResolver",{enumerable:!0,get:function(){return k.envOptionsResolver}});Object.defineProperty(i,"parseHeadersEnv",{enumerable:!0,get:function(){return k.parseHeadersEnv}});Object.defineProperty(i,"MAX_POST_BYTES",{enumerable:!0,get:function(){return k.MAX_POST_BYTES}});var Xe=ee();Object.defineProperty(i,"TraceManager",{enumerable:!0,get:function(){return Xe.TraceManager}});Object.defineProperty(i,"generateUlid",{enumerable:!0,get:function(){return Xe.generateUlid}});var Fe=Be();Object.defineProperty(i,"DiskSessionTraceManager",{enumerable:!0,get:function(){return Fe.DiskSessionTraceManager}});Object.defineProperty(i,"MemorySessionTraceManager",{enumerable:!0,get:function(){return Fe.MemorySessionTraceManager}});var oe=qe();Object.defineProperty(i,"envFilePath",{enumerable:!0,get:function(){return oe.envFilePath}});Object.defineProperty(i,"parseEnvFile",{enumerable:!0,get:function(){return oe.parseEnvFile}});Object.defineProperty(i,"loadEnvFile",{enumerable:!0,get:function(){return oe.loadEnvFile}})});import{realpathSync as vr}from"node:fs";import{pathToFileURL as Or}from"node:url";var Ge=x(S());import Ye from"node:fs";import Ht from"node:os";import C from"node:path";function Zt(e){let t={},r;try{r=Ye.readFileSync(e,"utf-8")}catch{return t}for(let n of r.split(`
21
- `)){let o=n.trim();if(!o||o.startsWith("#"))continue;let s=o.indexOf("=");if(s<0)continue;let a=o.slice(0,s).trim(),u=o.slice(s+1).trim();(u.startsWith('"')&&u.endsWith('"')||u.startsWith("'")&&u.endsWith("'"))&&(u=u.slice(1,-1)),a&&(t[a]=u)}return t}function Jt(e){let t=process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT??e.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT;if(t)return t;let r=process.env.OTEL_EXPORTER_OTLP_ENDPOINT??e.OTEL_EXPORTER_OTLP_ENDPOINT;return r?r.replace(/\/+$/,"")+"/v1/traces":process.env.PINTA_CODEX_ENDPOINT??e.PINTA_CODEX_ENDPOINT??process.env.CLAUDE_PLUGIN_OPTION_ENDPOINT}function Qt(e){if(process.env.OTEL_EXPORTER_OTLP_HEADERS)return process.env.OTEL_EXPORTER_OTLP_HEADERS;if(e.OTEL_EXPORTER_OTLP_HEADERS)return e.OTEL_EXPORTER_OTLP_HEADERS;if(process.env.PINTA_CODEX_API_KEY)return`x-pinta-relay-token=${process.env.PINTA_CODEX_API_KEY}`;if(e.PINTA_CODEX_API_KEY)return`x-pinta-relay-token=${e.PINTA_CODEX_API_KEY}`;if(process.env.CLAUDE_PLUGIN_OPTION_API_KEY)return`x-pinta-relay-token=${process.env.CLAUDE_PLUGIN_OPTION_API_KEY}`}function Ve(){let e=process.env.CODEX_PLUGIN_ROOT??process.env.CLAUDE_PLUGIN_ROOT??process.cwd(),t=process.env.CODEX_PLUGIN_DATA??process.env.CLAUDE_PLUGIN_DATA??C.join(e,".plugin-data"),r=process.env.CODEX_HOME??C.join(Ht.homedir(),".codex"),n=C.join(r,"pinta-codex.env"),o=Ye.existsSync(n)?Zt(n):{},s=Jt(o),a=Qt(o);if(a&&!process.env.PINTA_RELAY_TOKEN){let c=a.match(/x-pinta-relay-token=([^,\s]+)/i);c&&(process.env.PINTA_RELAY_TOKEN=c[1])}let u=process.env.PINTA_GUARD_ENDPOINT??o.PINTA_GUARD_ENDPOINT;return{pluginRoot:e,pluginData:t,tracePath:C.join(t,"trace.json"),endpoint:s?.replace(/\/+$/,""),headers:(0,Ge.parseHeadersEnv)(a??""),guardEndpoint:u}}function Ke(e){return e.hook_event_name==="PreToolUse"}function ze(e){return e.hook_event_name==="PostToolUse"}function We(e){return e.hook_event_name==="UserPromptSubmit"}function He(e){return e.hook_event_name==="SessionStart"}function Ze(e){return e.hook_event_name==="Stop"}var er=new Set(["PreToolUse","PostToolUse","SessionStart","UserPromptSubmit","Stop"]);function Je(e){return!er.has(e.hook_event_name)}var Qe=x(S()),tr=50,rr="pinta-codex/1.6.0";async function et(e,t){let r=await(0,Qe.evaluateGuard)(e,t,{timeoutMs:tr,token:process.env.PINTA_RELAY_TOKEN??"",disabled:process.env.PINTA_GUARD_DISABLED==="1",userAgent:rr});if(r===null)return null;let n={decision:r.decision,reason:r.reason,durationMs:r.durationMs,clientRttMs:r.clientRttMs};return r.failOpenReason!==void 0&&(n.failOpenReason=r.failOpenReason),n}var tt=x(S()),B=class extends tt.DiskTransport{constructor(t){super({pluginData:t.pluginData,logPrefix:"pinta-codex",resolveOptions:()=>t.endpoint?{endpoint:t.endpoint,headers:t.headers}:null})}};var rt=x(S()),L=class extends rt.TraceManager{constructor(t){super(t.tracePath)}};var b=x(S());import se from"os";var U;function nr(){if(U===void 0)try{U=se.userInfo().username}catch{U=process.env.USER??process.env.LOGNAME??(typeof process.getuid=="function"?String(process.getuid()):"unknown")}return U}var nt="1.6.0",q=null;function or(){return q!==null||(q=process.env.CODEX_CLI_VERSION||"unknown"),q}var sr=new Set(["codex.hook","codex.tool_name","codex.tool_use_id","codex.session_id","codex.transcript_path","codex.cwd","codex.permission_mode"]),ir=new Set(["codex.tool_input","codex.tool_response"]),ar={skipRedactKeys:sr,bashContextKeys:ir};function ur(e){let t=[];t.push({key:"ingest.type",value:{stringValue:"codex"}}),t.push({key:"codex.hook",value:{stringValue:e.hook_event_name}});let r={};for(let[n,o]of Object.entries(e))n!=="hook_event_name"&&(r[n]=o);return t.push(...(0,b.attrsFromRecord)(r,"codex",ar)),t}function cr(){return[{key:"service.name",value:{stringValue:"codex"}},{key:"service.version",value:{stringValue:or()}},{key:"telemetry.sdk.name",value:{stringValue:"pinta-codex"}},{key:"telemetry.sdk.language",value:{stringValue:"nodejs"}},{key:"telemetry.sdk.version",value:{stringValue:nt}},{key:"process.pid",value:{intValue:process.pid}},{key:"process.owner",value:{stringValue:nr()}},{key:"host.name",value:{stringValue:se.hostname()}},{key:"host.arch",value:{stringValue:se.arch()}}]}function ot(e){return(0,b.buildPayload)({traceId:e.traceId,spanName:`codex.${(0,b.snakeCase)(e.event.hook_event_name)}`,attributes:ur(e.event),resource:cr(),scope:{name:"pinta-codex",version:nt},now:e.now,guard:e.guard})}async function y(e,t,r){let n=new B(t);await n.flush();let o=new L(t),s=r.trace==="new"?o.newTrace():o.currentTrace(),a=ot({event:e,traceId:s,guard:r.guard});await n.send(a)}async function st(e,t){let r=typeof e.tool_input=="string"?e.tool_input:JSON.stringify(e.tool_input),n=await et({spanId:e.session_id??"unknown",toolName:e.tool_name,method:e.hook_event_name,cwd:e.cwd,toolInput:e.tool_input,rawTextFields:{toolInput:r}},t.guardEndpoint);if(n?.decision==="DENY"){let o={hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:n.reason??"guard_deny"}};process.stdout.write(JSON.stringify(o)+`
22
- `)}try{await y(e,t,{trace:"current",guard:n})}catch(o){process.stderr.write(`[pinta-codex] telemetry emit failed: ${o}
23
- `)}return 0}async function it(e,t){return await y(e,t,{trace:"current"}),0}async function at(e,t){return await y(e,t,{trace:"new"}),0}async function ut(e,t){return await y(e,t,{trace:"current"}),0}async function ct(e,t){return await y(e,t,{trace:"current"}),0}async function ie(e){return 0}async function lr(){let e=[];for await(let t of process.stdin)e.push(t);return Buffer.concat(e).toString("utf-8")}async function lt(){let e=0;try{let t=Ve(),r=await lr(),n=JSON.parse(r);Je(n)?e=await ie(n):Ke(n)?e=await st(n,t):ze(n)?e=await it(n,t):We(n)?e=await at(n,t):He(n)?e=await ut(n,t):Ze(n)?e=await ct(n,t):e=await ie(n)}catch(t){process.stderr.write(`[pinta-codex] error: ${t}
24
- `),e=0}return e}var pt=x(S());import{opendir as pr,stat as dr}from"node:fs/promises";import ae from"node:path";var fr="pinta-codex",_r=/^rollout-.+-([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})\.jsonl$/;function mr(){return(0,pt.envFilePath)(".codex","sessions","CODEX_HOME")}function hr(e,t){return ae.relative(e,t).split(ae.sep).join("/")}function gr(e){return e.endsWith(".jsonl")?"append-log":"rewritten-doc"}function yr(e){return e.endsWith(".jsonl")?"session-log":"other"}function Pr(e){let t=e.slice(e.lastIndexOf("/")+1);return _r.exec(t)?.[1]}async function dt(){return[mr()]}async function*ft(e,t){let r;try{r=await pr(t)}catch{return}try{for await(let n of r){let o=ae.join(t,n.name);n.isDirectory()?yield*ft(e,o):n.isFile()&&(yield{absPath:o,relPath:hr(e,o)})}}catch{return}}async function*Er(e){let[t]=await dt(),r=e.since?.getTime();for await(let{absPath:n,relPath:o}of ft(t,t)){let s;try{s=await dr(n)}catch{continue}r!==void 0&&s.mtime.getTime()<=r||(yield{relPath:o,absPath:n,size:s.size,mtime:s.mtime,sessionId:Pr(o),semantics:gr(o)})}}var Tr={id:fr,roots:dt,scan:Er,classify:yr};function Sr(){let e=process.argv[1];if(!e)return!1;try{return import.meta.url===Or(vr(e)).href}catch{return!1}}async function br(){let e=await lt();process.exit(e)}Sr()&&br();export{Tr as lifecycle};
16
+ `),!0)}};l.DiskTransport=J;var Q=class{queue=new Ae.MemoryRetryQueue;logPrefix;resolveOptions;constructor(t){this.logPrefix=t.logPrefix,this.resolveOptions=t.resolveOptions}async send(t){let r=this.resolveOptions();if(!r)return;if(N(t)>l.MAX_POST_BYTES){process.stderr.write(`[${this.logPrefix}] dropping oversized span payload (> ${l.MAX_POST_BYTES} bytes) \u2014 undeliverable, not buffered
17
+ `);return}await w(t,r,this.logPrefix)||this.queue.enqueue(t)}async flush(){let t=this.resolveOptions();if(!t)return;let r=this.queue.drain();if(r.length===0)return;let{chunks:n,oversize:o}=we(r,N,l.MAX_POST_BYTES);o.length>0&&process.stderr.write(`[${this.logPrefix}] dropping ${o.length} oversized buffered ${o.length===1?"payload":"payloads"} (each > ${l.MAX_POST_BYTES} bytes \u2014 undeliverable)
18
+ `);let s=[].concat(...n),a=0;for(let u of n){if(!await w((0,Re.mergeBatch)(u),t,this.logPrefix))break;a+=u.length}for(let u of s.slice(a))this.queue.enqueue(u)}};l.MemoryTransport=Q});var ne=y(T=>{"use strict";var re=T&&T.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(T,"__esModule",{value:!0});T.TraceManager=void 0;T.generateUlid=De;var Ie=re(_("fs")),zt=re(_("path")),Ht=re(_("crypto")),Wt=j(),ee="0123456789ABCDEFGHJKMNPQRSTVWXYZ";function De(){let e=Date.now(),t="",r=e;for(let s=0;s<10;s++)t=ee[r&31]+t,r=Math.floor(r/32);let n=Ht.default.randomBytes(10),o="";for(let s=0;s<10;s++)o+=ee[n[s]&31];for(;o.length<16;)o+=ee[0];return t+o}var te=class{tracePath;constructor(t){this.tracePath=t}newTrace(){let t=De();return this.save(t),t}currentTrace(){try{let t=Ie.default.readFileSync(this.tracePath,"utf-8"),{traceId:r}=JSON.parse(t);if(r)return r}catch{}return this.newTrace()}save(t){try{Ie.default.mkdirSync(zt.default.dirname(this.tracePath),{recursive:!0}),(0,Wt.atomicWriteFileSync)(this.tracePath,JSON.stringify({traceId:t}))}catch(r){process.stderr.write(`[pinta-core] trace persistence failed: ${r}
19
+ `)}}};T.TraceManager=te});var Ue=y(E=>{"use strict";var Be=E&&E.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(E,"__esModule",{value:!0});E.MemorySessionTraceManager=E.DiskSessionTraceManager=void 0;var Ne=Be(_("fs")),Zt=Be(_("path")),qe=ne(),Jt=j(),Le=200,oe=class{tracePath;maxSessions;constructor(t,r={}){this.tracePath=t,this.maxSessions=r.maxSessions??Le}read(){try{let t=JSON.parse(Ne.default.readFileSync(this.tracePath,"utf-8"));if(t&&typeof t=="object"&&!("traceId"in t))return t}catch{}return{}}write(t){try{Ne.default.mkdirSync(Zt.default.dirname(this.tracePath),{recursive:!0});let r=Object.entries(t),n=r.length>this.maxSessions?Object.fromEntries(r.slice(-this.maxSessions)):t;(0,Jt.atomicWriteFileSync)(this.tracePath,JSON.stringify(n))}catch{}}newTrace(t){let r=t||"default",n=(0,qe.generateUlid)(),o=this.read();return o[r]=n,this.write(o),n}currentTrace(t){let r=t||"default",n=this.read()[r];return n||this.newTrace(r)}};E.DiskSessionTraceManager=oe;var se=class{map=new Map;maxSessions;constructor(t={}){this.maxSessions=t.maxSessions??Le}newTrace(t){let r=t||"default",n=(0,qe.generateUlid)();if(this.map.set(r,n),this.map.size>this.maxSessions){let o=this.map.keys().next().value;o!==void 0&&this.map.delete(o)}return n}currentTrace(t){let r=t||"default";return this.map.get(r)??this.newTrace(r)}};E.MemorySessionTraceManager=se});var Ge=y(O=>{"use strict";var ie=O&&O.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(O,"__esModule",{value:!0});O.envFilePath=tr;O.parseEnvFile=Fe;O.loadEnvFile=rr;var Qt=ie(_("node:fs")),er=ie(_("node:os")),$e=ie(_("node:path"));function tr(e,t,r){let n=r?process.env[r]:void 0,o=n&&n.length>0?n:$e.default.join(er.default.homedir(),e);return $e.default.join(o,t)}function Fe(e){let t={};for(let r of e.split(`
20
+ `)){let n=r.trim();if(!n||n.startsWith("#"))continue;let o=n.indexOf("=");if(o<0)continue;let s=n.slice(0,o).trim(),a=n.slice(o+1).trim();(a.startsWith('"')&&a.endsWith('"')||a.startsWith("'")&&a.endsWith("'"))&&(a=a.slice(1,-1)),s&&(t[s]=a)}return t}function rr(e){let t;try{t=Qt.default.readFileSync(e,"utf-8")}catch{return}let r=Fe(t);for(let[n,o]of Object.entries(r))process.env[n]===void 0&&(process.env[n]=o)}});var S=y(i=>{"use strict";Object.defineProperty(i,"__esModule",{value:!0});i.loadEnvFile=i.parseEnvFile=i.envFilePath=i.MemorySessionTraceManager=i.DiskSessionTraceManager=i.generateUlid=i.TraceManager=i.MAX_POST_BYTES=i.parseHeadersEnv=i.envOptionsResolver=i.postOtlp=i.MemoryTransport=i.DiskTransport=i.MemoryRetryQueue=i.DiskRetryQueue=i.evaluateGuard=i.MAX_SPAN_BYTES=i.enforceSpanBudget=i.mergeBatch=i.buildPayload=i.clientAttrs=i.guardAttrs=i.attrsFromRecord=i.toOtlpValue=i.snakeCase=i.newSpanId=i.ulidToTraceId=i.MAX_BYTES=i.PATTERNS=i.applyMatches=i.resolveOverlaps=i.collectMatches=i.truncateTo=i.truncate=i.redact=void 0;var v=X();Object.defineProperty(i,"redact",{enumerable:!0,get:function(){return v.redact}});Object.defineProperty(i,"truncate",{enumerable:!0,get:function(){return v.truncate}});Object.defineProperty(i,"truncateTo",{enumerable:!0,get:function(){return v.truncateTo}});Object.defineProperty(i,"collectMatches",{enumerable:!0,get:function(){return v.collectMatches}});Object.defineProperty(i,"resolveOverlaps",{enumerable:!0,get:function(){return v.resolveOverlaps}});Object.defineProperty(i,"applyMatches",{enumerable:!0,get:function(){return v.applyMatches}});Object.defineProperty(i,"PATTERNS",{enumerable:!0,get:function(){return v.PATTERNS}});Object.defineProperty(i,"MAX_BYTES",{enumerable:!0,get:function(){return v.MAX_BYTES}});var g=V();Object.defineProperty(i,"ulidToTraceId",{enumerable:!0,get:function(){return g.ulidToTraceId}});Object.defineProperty(i,"newSpanId",{enumerable:!0,get:function(){return g.newSpanId}});Object.defineProperty(i,"snakeCase",{enumerable:!0,get:function(){return g.snakeCase}});Object.defineProperty(i,"toOtlpValue",{enumerable:!0,get:function(){return g.toOtlpValue}});Object.defineProperty(i,"attrsFromRecord",{enumerable:!0,get:function(){return g.attrsFromRecord}});Object.defineProperty(i,"guardAttrs",{enumerable:!0,get:function(){return g.guardAttrs}});Object.defineProperty(i,"clientAttrs",{enumerable:!0,get:function(){return g.clientAttrs}});Object.defineProperty(i,"buildPayload",{enumerable:!0,get:function(){return g.buildPayload}});Object.defineProperty(i,"mergeBatch",{enumerable:!0,get:function(){return g.mergeBatch}});Object.defineProperty(i,"enforceSpanBudget",{enumerable:!0,get:function(){return g.enforceSpanBudget}});Object.defineProperty(i,"MAX_SPAN_BYTES",{enumerable:!0,get:function(){return g.MAX_SPAN_BYTES}});var nr=be();Object.defineProperty(i,"evaluateGuard",{enumerable:!0,get:function(){return nr.evaluateGuard}});var Xe=Z();Object.defineProperty(i,"DiskRetryQueue",{enumerable:!0,get:function(){return Xe.DiskRetryQueue}});Object.defineProperty(i,"MemoryRetryQueue",{enumerable:!0,get:function(){return Xe.MemoryRetryQueue}});var k=je();Object.defineProperty(i,"DiskTransport",{enumerable:!0,get:function(){return k.DiskTransport}});Object.defineProperty(i,"MemoryTransport",{enumerable:!0,get:function(){return k.MemoryTransport}});Object.defineProperty(i,"postOtlp",{enumerable:!0,get:function(){return k.postOtlp}});Object.defineProperty(i,"envOptionsResolver",{enumerable:!0,get:function(){return k.envOptionsResolver}});Object.defineProperty(i,"parseHeadersEnv",{enumerable:!0,get:function(){return k.parseHeadersEnv}});Object.defineProperty(i,"MAX_POST_BYTES",{enumerable:!0,get:function(){return k.MAX_POST_BYTES}});var Ye=ne();Object.defineProperty(i,"TraceManager",{enumerable:!0,get:function(){return Ye.TraceManager}});Object.defineProperty(i,"generateUlid",{enumerable:!0,get:function(){return Ye.generateUlid}});var Ve=Ue();Object.defineProperty(i,"DiskSessionTraceManager",{enumerable:!0,get:function(){return Ve.DiskSessionTraceManager}});Object.defineProperty(i,"MemorySessionTraceManager",{enumerable:!0,get:function(){return Ve.MemorySessionTraceManager}});var ae=Ge();Object.defineProperty(i,"envFilePath",{enumerable:!0,get:function(){return ae.envFilePath}});Object.defineProperty(i,"parseEnvFile",{enumerable:!0,get:function(){return ae.parseEnvFile}});Object.defineProperty(i,"loadEnvFile",{enumerable:!0,get:function(){return ae.loadEnvFile}})});import{realpathSync as Dr}from"node:fs";import{pathToFileURL as Nr}from"node:url";var ze=x(S());import Ke from"node:fs";import or from"node:os";import B from"node:path";function sr(e){let t={},r;try{r=Ke.readFileSync(e,"utf-8")}catch{return t}for(let n of r.split(`
21
+ `)){let o=n.trim();if(!o||o.startsWith("#"))continue;let s=o.indexOf("=");if(s<0)continue;let a=o.slice(0,s).trim(),u=o.slice(s+1).trim();(u.startsWith('"')&&u.endsWith('"')||u.startsWith("'")&&u.endsWith("'"))&&(u=u.slice(1,-1)),a&&(t[a]=u)}return t}function ir(e){let t=process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT??e.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT;if(t)return t;let r=process.env.OTEL_EXPORTER_OTLP_ENDPOINT??e.OTEL_EXPORTER_OTLP_ENDPOINT;return r?r.replace(/\/+$/,"")+"/v1/traces":process.env.PINTA_CODEX_ENDPOINT??e.PINTA_CODEX_ENDPOINT??process.env.CLAUDE_PLUGIN_OPTION_ENDPOINT}function ar(e){if(process.env.OTEL_EXPORTER_OTLP_HEADERS)return process.env.OTEL_EXPORTER_OTLP_HEADERS;if(e.OTEL_EXPORTER_OTLP_HEADERS)return e.OTEL_EXPORTER_OTLP_HEADERS;if(process.env.PINTA_CODEX_API_KEY)return`x-pinta-relay-token=${process.env.PINTA_CODEX_API_KEY}`;if(e.PINTA_CODEX_API_KEY)return`x-pinta-relay-token=${e.PINTA_CODEX_API_KEY}`;if(process.env.CLAUDE_PLUGIN_OPTION_API_KEY)return`x-pinta-relay-token=${process.env.CLAUDE_PLUGIN_OPTION_API_KEY}`}function He(){let e=process.env.CODEX_PLUGIN_ROOT??process.env.CLAUDE_PLUGIN_ROOT??process.cwd(),t=process.env.CODEX_PLUGIN_DATA??process.env.CLAUDE_PLUGIN_DATA??B.join(e,".plugin-data"),r=process.env.CODEX_HOME??B.join(or.homedir(),".codex"),n=B.join(r,"pinta-codex.env"),o=Ke.existsSync(n)?sr(n):{},s=ir(o),a=ar(o);if(a&&!process.env.PINTA_RELAY_TOKEN){let c=a.match(/x-pinta-relay-token=([^,\s]+)/i);c&&(process.env.PINTA_RELAY_TOKEN=c[1])}let u=process.env.PINTA_GUARD_ENDPOINT??o.PINTA_GUARD_ENDPOINT;return{pluginRoot:e,pluginData:t,tracePath:B.join(t,"trace.json"),endpoint:s?.replace(/\/+$/,""),headers:(0,ze.parseHeadersEnv)(a??""),guardEndpoint:u}}function We(e){return e.hook_event_name==="PreToolUse"}function Ze(e){return e.hook_event_name==="PermissionRequest"}function Je(e){return e.hook_event_name==="PostToolUse"}function Qe(e){return e.hook_event_name==="UserPromptSubmit"}function et(e){return e.hook_event_name==="SessionStart"}function tt(e){return e.hook_event_name==="Stop"}var ur=["PreToolUse","PermissionRequest"],cr=["PostToolUse","PreCompact","PostCompact","SessionStart","SessionEnd","UserPromptSubmit","SubagentStart","SubagentStop","Stop","Interrupt"],lr=new Set([...ur,...cr]);function rt(e){return!lr.has(e.hook_event_name)}var nt=x(S()),q=class extends nt.DiskTransport{constructor(t){super({pluginData:t.pluginData,logPrefix:"pinta-codex",resolveOptions:()=>t.endpoint?{endpoint:t.endpoint,headers:t.headers}:null})}};var ot=x(S()),L=class extends ot.TraceManager{constructor(t){super(t.tracePath)}};var b=x(S());import $ from"fs";import ce from"os";import pr from"path";var U;function dr(){if(U===void 0)try{U=ce.userInfo().username}catch{U=process.env.USER??process.env.LOGNAME??(typeof process.getuid=="function"?String(process.getuid()):"unknown")}return U}var it="1.8.0",ue;function M(e){return typeof e=="string"&&e.trim()!==""?e.trim():void 0}var st=256*1024;function fr(e){if(!e)return;let t;try{t=$.openSync(e,"r");let r=Buffer.allocUnsafe(st),n=$.readSync(t,r,0,st,0),o=r.toString("utf8",0,n),s=o.indexOf(`
22
+ `);if(s<0)return;let a=JSON.parse(o.slice(0,s));return a?.type!=="session_meta"?void 0:M(a.payload?.cli_version)}catch{return}finally{if(t!==void 0)try{$.closeSync(t)}catch{}}}function mr(){let e=M(process.env.CODEX_MANAGED_PACKAGE_ROOT);if(e)try{let t=JSON.parse($.readFileSync(pr.join(e,"package.json"),"utf8"));return M(t.version)}catch{return}}function _r(e){return ue===void 0&&(ue=fr(M(e?.transcript_path))??mr()??M(process.env.CODEX_CLI_VERSION)??null),ue??void 0}var gr=new Set(["codex.hook","codex.tool_name","codex.tool_use_id","codex.session_id","codex.transcript_path","codex.cwd","codex.permission_mode"]),hr=new Set(["codex.tool_input","codex.tool_response"]),yr={skipRedactKeys:gr,bashContextKeys:hr};function Pr(e){let t=[];t.push({key:"ingest.type",value:{stringValue:"codex"}}),t.push({key:"codex.hook",value:{stringValue:e.hook_event_name}});let r={};for(let[n,o]of Object.entries(e))n!=="hook_event_name"&&(r[n]=o);return t.push(...(0,b.attrsFromRecord)(r,"codex",yr)),t}function Er(e){let t=_r(e);return[{key:"service.name",value:{stringValue:"codex"}},...t?[{key:"service.version",value:{stringValue:t}}]:[],{key:"telemetry.sdk.name",value:{stringValue:"pinta-codex"}},{key:"telemetry.sdk.language",value:{stringValue:"nodejs"}},{key:"telemetry.sdk.version",value:{stringValue:it}},{key:"process.pid",value:{intValue:process.pid}},{key:"process.owner",value:{stringValue:dr()}},{key:"host.name",value:{stringValue:ce.hostname()}},{key:"host.arch",value:{stringValue:ce.arch()}}]}function at(e){return(0,b.buildPayload)({traceId:e.traceId,spanName:`codex.${(0,b.snakeCase)(e.event.hook_event_name)}`,attributes:Pr(e.event),resource:Er(e.event),scope:{name:"pinta-codex",version:it},now:e.now,guard:e.guard})}async function f(e,t,r){let n=new q(t);await n.flush();let o=new L(t),s=r.trace==="new"?o.newTrace():o.currentTrace(),a=at({event:e,traceId:s,guard:r.guard});await n.send(a)}var ut=x(S()),vr=50,Tr="pinta-codex/1.8.0";async function ct(e,t){let r=await(0,ut.evaluateGuard)(e,t,{timeoutMs:vr,token:process.env.PINTA_RELAY_TOKEN??"",disabled:process.env.PINTA_GUARD_DISABLED==="1",userAgent:Tr});if(r===null)return null;let n={decision:r.decision,reason:r.reason,durationMs:r.durationMs,clientRttMs:r.clientRttMs};return r.failOpenReason!==void 0&&(n.failOpenReason=r.failOpenReason),n}async function F(e,t){let r=typeof e.tool_input=="string"?e.tool_input:JSON.stringify(e.tool_input);return ct({spanId:e.session_id??"unknown",toolName:e.tool_name,method:e.hook_event_name,cwd:e.cwd,toolInput:e.tool_input,rawTextFields:{toolInput:r}},t.guardEndpoint)}function G(e){let t=e?.reason;return typeof t=="string"&&t.trim().length>0?t:"guard_deny"}async function lt(e,t){let r=await F(e,t);if(r?.decision==="DENY"){let n={hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:G(r)}};process.stdout.write(JSON.stringify(n)+`
23
+ `)}try{await f(e,t,{trace:"current",guard:r})}catch(n){process.stderr.write(`[pinta-codex] telemetry emit failed: ${n}
24
+ `)}return 0}async function pt(e,t){let r=await F(e,t);if(r?.decision==="DENY"){let n={hookSpecificOutput:{hookEventName:"PermissionRequest",decision:{behavior:"deny",message:G(r)}}};process.stdout.write(JSON.stringify(n)+`
25
+ `)}try{await f(e,t,{trace:"current",guard:r})}catch(n){process.stderr.write(`[pinta-codex] telemetry emit failed: ${n}
26
+ `)}return 0}async function dt(e,t){return await f(e,t,{trace:"current"}),0}async function ft(e,t){return await f(e,t,{trace:"new"}),0}async function mt(e,t){return await f(e,t,{trace:"current"}),0}async function _t(e,t){return await f(e,t,{trace:"current"}),0}async function gt(e,t){return await f(e,t,{trace:"current"}),0}async function ht(e){return 0}async function Or(){let e=[];for await(let t of process.stdin)e.push(t);return Buffer.concat(e).toString("utf-8")}async function yt(){let e=0;try{let t=He(),r=await Or(),n=JSON.parse(r);rt(n)?e=await ht(n):We(n)?e=await lt(n,t):Ze(n)?e=await pt(n,t):Je(n)?e=await dt(n,t):Qe(n)?e=await ft(n,t):et(n)?e=await mt(n,t):tt(n)?e=await _t(n,t):e=await gt(n,t)}catch(t){process.stderr.write(`[pinta-codex] error: ${t}
27
+ `),e=0}return e}var Pt=x(S());import{opendir as Sr,stat as br}from"node:fs/promises";import le from"node:path";var xr="pinta-codex",kr=/^rollout-.+-([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})\.jsonl$/;function Ar(){return(0,Pt.envFilePath)(".codex","sessions","CODEX_HOME")}function Rr(e,t){return le.relative(e,t).split(le.sep).join("/")}function wr(e){return e.endsWith(".jsonl")?"append-log":"rewritten-doc"}function Mr(e){return e.endsWith(".jsonl")?"session-log":"other"}function Cr(e){let t=e.slice(e.lastIndexOf("/")+1);return kr.exec(t)?.[1]}async function Et(){return[Ar()]}async function*vt(e,t){let r;try{r=await Sr(t)}catch{return}try{for await(let n of r){let o=le.join(t,n.name);n.isDirectory()?yield*vt(e,o):n.isFile()&&(yield{absPath:o,relPath:Rr(e,o)})}}catch{return}}async function*jr(e){let[t]=await Et(),r=e.since?.getTime();for await(let{absPath:n,relPath:o}of vt(t,t)){let s;try{s=await br(n)}catch{continue}r!==void 0&&s.mtime.getTime()<=r||(yield{relPath:o,absPath:n,size:s.size,mtime:s.mtime,sessionId:Cr(o),semantics:wr(o)})}}var Ir={id:xr,roots:Et,scan:jr,classify:Mr};function Br(){let e=process.argv[1];if(!e)return!1;try{return import.meta.url===Nr(Dr(e)).href}catch{return!1}}async function qr(){let e=await yt();process.exit(e)}Br()&&qr();export{Ir as lifecycle};
package/hooks.json CHANGED
@@ -1,5 +1,55 @@
1
1
  {
2
2
  "hooks": {
3
+ "PreToolUse": [
4
+ {
5
+ "hooks": [
6
+ {
7
+ "type": "command",
8
+ "command": "node ${CODEX_PLUGIN_ROOT}/dist/index.js"
9
+ }
10
+ ]
11
+ }
12
+ ],
13
+ "PermissionRequest": [
14
+ {
15
+ "hooks": [
16
+ {
17
+ "type": "command",
18
+ "command": "node ${CODEX_PLUGIN_ROOT}/dist/index.js"
19
+ }
20
+ ]
21
+ }
22
+ ],
23
+ "PostToolUse": [
24
+ {
25
+ "hooks": [
26
+ {
27
+ "type": "command",
28
+ "command": "node ${CODEX_PLUGIN_ROOT}/dist/index.js"
29
+ }
30
+ ]
31
+ }
32
+ ],
33
+ "PreCompact": [
34
+ {
35
+ "hooks": [
36
+ {
37
+ "type": "command",
38
+ "command": "node ${CODEX_PLUGIN_ROOT}/dist/index.js"
39
+ }
40
+ ]
41
+ }
42
+ ],
43
+ "PostCompact": [
44
+ {
45
+ "hooks": [
46
+ {
47
+ "type": "command",
48
+ "command": "node ${CODEX_PLUGIN_ROOT}/dist/index.js"
49
+ }
50
+ ]
51
+ }
52
+ ],
3
53
  "SessionStart": [
4
54
  {
5
55
  "hooks": [
@@ -10,6 +60,16 @@
10
60
  ]
11
61
  }
12
62
  ],
63
+ "SessionEnd": [
64
+ {
65
+ "hooks": [
66
+ {
67
+ "type": "command",
68
+ "command": "node ${CODEX_PLUGIN_ROOT}/dist/index.js"
69
+ }
70
+ ]
71
+ }
72
+ ],
13
73
  "UserPromptSubmit": [
14
74
  {
15
75
  "hooks": [
@@ -20,7 +80,7 @@
20
80
  ]
21
81
  }
22
82
  ],
23
- "PreToolUse": [
83
+ "SubagentStart": [
24
84
  {
25
85
  "hooks": [
26
86
  {
@@ -30,7 +90,7 @@
30
90
  ]
31
91
  }
32
92
  ],
33
- "PostToolUse": [
93
+ "SubagentStop": [
34
94
  {
35
95
  "hooks": [
36
96
  {
@@ -49,6 +109,16 @@
49
109
  }
50
110
  ]
51
111
  }
112
+ ],
113
+ "Interrupt": [
114
+ {
115
+ "hooks": [
116
+ {
117
+ "type": "command",
118
+ "command": "node ${CODEX_PLUGIN_ROOT}/dist/index.js"
119
+ }
120
+ ]
121
+ }
52
122
  ]
53
123
  }
54
124
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pinta-ai/pinta-codex",
3
- "version": "1.6.0",
3
+ "version": "1.8.0",
4
4
  "description": "Generic OTLP forwarder for Codex hook events",
5
5
  "main": "dist/index.js",
6
6
  "exports": {
package/tools/_lib.ts CHANGED
@@ -152,18 +152,34 @@ export function migrateLegacyEnvKeys(p: string): string[] {
152
152
  return renamed;
153
153
  }
154
154
 
155
- // --- TOML: minimal, targeted `[features].codex_hooks = true` toggle ---
155
+ // --- TOML: minimal, targeted `[features].hooks = true` toggle ---
156
156
 
157
157
  /**
158
- * Ensure `[features] codex_hooks = true` is set in the TOML source.
159
- * Preserves unrelated content; only touches the features section.
158
+ * Ensure the hooks feature is enabled in the TOML source.
159
+ *
160
+ * `hooks` is the canonical name and the one written. `codex_hooks` was the
161
+ * pre-0.13x spelling; codex still maps it through `features/src/legacy.rs`, so
162
+ * an existing `codex_hooks = true` is honoured and left alone rather than
163
+ * "upgraded" — rewriting a key the user did not ask us to touch is the kind of
164
+ * edit that loses a config, and both spellings produce the same state.
165
+ *
166
+ * Measured on codex-cli 0.154.0 with an isolated `CODEX_HOME`
167
+ * (`codex features list`):
168
+ *
169
+ * codex_hooks = true → hooks stable true
170
+ * hooks = true → hooks stable true
171
+ * (absent) → hooks stable true
172
+ *
173
+ * The third row is why nothing here is load-bearing any more: the feature
174
+ * reached `stable` and is on by default. Writing it stays as a no-op guard for
175
+ * older codex builds and for a config that explicitly set it `false`.
160
176
  *
161
177
  * Handles:
162
178
  * - no file / empty file → append section
163
179
  * - no [features] section → append section
164
- * - [features] present, key missing → insert key
165
- * - key present with different value → replace value
166
- * - key already true → no change
180
+ * - [features] present, either key already true → no change
181
+ * - `hooks` present with a different value → replace value
182
+ * - neither key present → insert `hooks = true`
167
183
  */
168
184
  export function ensureCodexHooksEnabled(content: string): {
169
185
  next: string;
@@ -175,7 +191,7 @@ export function ensureCodexHooksEnabled(content: string): {
175
191
  const sep = content.length === 0 || content.endsWith("\n") ? "" : "\n";
176
192
  const suffix = content.length === 0 ? "" : "\n";
177
193
  return {
178
- next: content + sep + suffix + "[features]\ncodex_hooks = true\n",
194
+ next: content + sep + suffix + "[features]\nhooks = true\n",
179
195
  changed: true,
180
196
  };
181
197
  }
@@ -186,11 +202,16 @@ export function ensureCodexHooksEnabled(content: string): {
186
202
  const sectionEnd = nextSection ? sectionStart + nextSection.index! : content.length;
187
203
  const body = content.slice(sectionStart, sectionEnd);
188
204
 
189
- const keyRe = /^(\s*)codex_hooks\s*=\s*(true|false|"[^"]*"|'[^']*')\s*$/m;
205
+ // An enabled legacy key is an enabled feature. Adding `hooks = true` beside
206
+ // it would leave two keys for one setting, which is how a later `disable`
207
+ // turns off the half the user can see and none of the half that matters.
208
+ if (LEGACY_HOOKS_TRUE_RE.test(body)) return { next: content, changed: false };
209
+
210
+ const keyRe = /^(\s*)hooks\s*=\s*(true|false|"[^"]*"|'[^']*')\s*$/m;
190
211
  const keyMatch = body.match(keyRe);
191
212
  if (keyMatch) {
192
213
  if (keyMatch[2] === "true") return { next: content, changed: false };
193
- const replaced = body.replace(keyRe, `${keyMatch[1] ?? ""}codex_hooks = true`);
214
+ const replaced = body.replace(keyRe, `${keyMatch[1] ?? ""}hooks = true`);
194
215
  return {
195
216
  next: content.slice(0, sectionStart) + replaced + content.slice(sectionEnd),
196
217
  changed: true,
@@ -198,13 +219,28 @@ export function ensureCodexHooksEnabled(content: string): {
198
219
  }
199
220
 
200
221
  const sep = body.length === 0 || body.endsWith("\n") ? "" : "\n";
201
- const insert = `${sep}codex_hooks = true\n`;
222
+ const insert = `${sep}hooks = true\n`;
202
223
  return {
203
224
  next: content.slice(0, sectionStart) + body + insert + content.slice(sectionEnd),
204
225
  changed: true,
205
226
  };
206
227
  }
207
228
 
229
+ const LEGACY_HOOKS_TRUE_RE = /^\s*codex_hooks\s*=\s*(true|"true"|'true')\s*$/m;
230
+
231
+ /**
232
+ * True when the config explicitly enables hooks under either spelling.
233
+ *
234
+ * Reading only `codex_hooks` made this answer `false` for
235
+ * `[features] hooks = true` — the canonical, working configuration — so
236
+ * `doctor` reported "not enabled" and exited 1 on machines whose hooks were
237
+ * firing normally. A health check that fails on a healthy install is worse
238
+ * than no check: it sends people to edit the one file that was already right.
239
+ *
240
+ * `false` no longer means hooks are off. The feature is `stable` and default-on
241
+ * (see `ensureCodexHooksEnabled`), so callers must treat absence as unremarkable
242
+ * rather than as a fault.
243
+ */
208
244
  export function isCodexHooksEnabled(content: string): boolean {
209
245
  const sectionHeader = /^\[features\]\s*$/m;
210
246
  const match = content.match(sectionHeader);
@@ -214,8 +250,20 @@ export function isCodexHooksEnabled(content: string): boolean {
214
250
  const nextSection = rest.match(/\n\[[^\]]+\]\s*$/m);
215
251
  const sectionEnd = nextSection ? sectionStart + nextSection.index! : content.length;
216
252
  const body = content.slice(sectionStart, sectionEnd);
217
- const keyRe = /^\s*codex_hooks\s*=\s*(true|"true"|'true')\s*$/m;
218
- return keyRe.test(body);
253
+ return /^\s*hooks\s*=\s*(true|"true"|'true')\s*$/m.test(body) || LEGACY_HOOKS_TRUE_RE.test(body);
254
+ }
255
+
256
+ /** True when the config explicitly turns hooks off under either spelling. */
257
+ export function isCodexHooksDisabled(content: string): boolean {
258
+ const sectionHeader = /^\[features\]\s*$/m;
259
+ const match = content.match(sectionHeader);
260
+ if (!match) return false;
261
+ const sectionStart = match.index! + match[0].length;
262
+ const rest = content.slice(sectionStart);
263
+ const nextSection = rest.match(/\n\[[^\]]+\]\s*$/m);
264
+ const sectionEnd = nextSection ? sectionStart + nextSection.index! : content.length;
265
+ const body = content.slice(sectionStart, sectionEnd);
266
+ return /^\s*(?:codex_)?hooks\s*=\s*(false|"false"|'false')\s*$/m.test(body);
219
267
  }
220
268
 
221
269
  // --- hooks.json merge ---
package/tools/doctor.ts CHANGED
@@ -16,6 +16,7 @@ import {
16
16
  PLUGIN_ENTRY,
17
17
  PLUGIN_ROOT,
18
18
  countRegisteredEvents,
19
+ isCodexHooksDisabled,
19
20
  isCodexHooksEnabled,
20
21
  readEnvFile,
21
22
  readJson,
@@ -92,26 +93,43 @@ function checkEnv(): { endpoint?: string; headers?: string } {
92
93
  return { endpoint, headers };
93
94
  }
94
95
 
96
+ /**
97
+ * The hooks feature, which is no longer something an install has to turn on.
98
+ *
99
+ * Measured on codex-cli 0.154.0 with an isolated `CODEX_HOME`: `hooks` lists as
100
+ * `stable` and effective `true` with nothing in `config.toml` at all. So an
101
+ * absent key means "default", not "broken", and failing on it sent people to
102
+ * edit a file that was already correct.
103
+ *
104
+ * An explicit `false` is the one state worth failing on, because that is a
105
+ * kill switch: every hook stops dispatching and nothing else reports it.
106
+ */
95
107
  function checkCodexHooksFlag(): void {
96
108
  let content = "";
97
109
  try {
98
110
  content = fs.readFileSync(CODEX_CONFIG_PATH, "utf-8");
99
111
  } catch {
100
- fail(
101
- "codex_hooks flag",
112
+ // Not an error either. codex creates this file on first run, and hooks are
113
+ // on by default whether or not it exists yet.
114
+ warn(
115
+ "hooks feature",
102
116
  `${CODEX_CONFIG_PATH} not found`,
103
- "Run 'npm run setup' to create it.",
117
+ "Hooks default to on; run 'npm run setup' if Codex has never been started.",
104
118
  );
105
119
  return;
106
120
  }
107
- if (isCodexHooksEnabled(content)) {
108
- pass("codex_hooks flag", "[features].codex_hooks = true");
109
- } else {
121
+ if (isCodexHooksDisabled(content)) {
110
122
  fail(
111
- "codex_hooks flag",
112
- "not enabled in config.toml",
113
- "Add [features] codex_hooks = true, or run 'npm run setup'.",
123
+ "hooks feature",
124
+ "[features] hooks = false — every hook is disabled",
125
+ "Set hooks = true in config.toml, or run 'npm run setup'.",
114
126
  );
127
+ return;
128
+ }
129
+ if (isCodexHooksEnabled(content)) {
130
+ pass("hooks feature", "[features] hooks = true");
131
+ } else {
132
+ pass("hooks feature", "default (stable, on)");
115
133
  }
116
134
  }
117
135
 
package/tools/setup.ts CHANGED
@@ -7,7 +7,7 @@
7
7
  * 1. Builds dist/ (runs tsc if dist/index.js missing or --rebuild)
8
8
  * 2. Prompts for OTLP endpoint & headers (migrates legacy keys if present)
9
9
  * 3. Writes them to ~/.codex/pinta-codex.env
10
- * 4. Enables `codex_hooks = true` in ~/.codex/config.toml (idempotent)
10
+ * 4. Enables `hooks = true` in ~/.codex/config.toml (idempotent; no-op on modern codex)
11
11
  * 5. Merges this plugin's hooks into ~/.codex/hooks.json with absolute paths
12
12
  * 6. Prints a summary of what to run next
13
13
  *
@@ -122,7 +122,7 @@ async function stepEnv(ask: AskFn): Promise<{ endpoint: string; headers: string
122
122
  }
123
123
 
124
124
  async function stepConfigToml(): Promise<void> {
125
- heading("3. Enable codex_hooks feature");
125
+ heading("3. Enable hooks feature");
126
126
  let current = "";
127
127
  try {
128
128
  current = fs.readFileSync(CODEX_CONFIG_PATH, "utf-8");
@@ -131,7 +131,7 @@ async function stepConfigToml(): Promise<void> {
131
131
  }
132
132
  const { next, changed } = ensureCodexHooksEnabled(current);
133
133
  if (!changed) {
134
- ok(`codex_hooks already enabled in ${CODEX_CONFIG_PATH}`);
134
+ ok(`hooks feature already enabled in ${CODEX_CONFIG_PATH}`);
135
135
  return;
136
136
  }
137
137
  fs.mkdirSync(CODEX_HOME, { recursive: true });