@pinta-ai/pinta-codex 1.2.4 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.codex-plugin/plugin.json +1 -1
- package/CHANGELOG.md +31 -0
- package/dist/index.js +15 -53
- package/package.json +14 -6
- package/dist/core/config.d.ts +0 -12
- package/dist/core/config.js +0 -125
- package/dist/core/config.js.map +0 -1
- package/dist/core/guard.d.ts +0 -13
- package/dist/core/guard.js +0 -41
- package/dist/core/guard.js.map +0 -1
- package/dist/core/identity.d.ts +0 -1
- package/dist/core/identity.js +0 -3
- package/dist/core/identity.js.map +0 -1
- package/dist/core/otlp.d.ts +0 -59
- package/dist/core/otlp.js +0 -192
- package/dist/core/otlp.js.map +0 -1
- package/dist/core/redact.d.ts +0 -57
- package/dist/core/redact.js +0 -149
- package/dist/core/redact.js.map +0 -1
- package/dist/core/retry-queue.d.ts +0 -26
- package/dist/core/retry-queue.js +0 -127
- package/dist/core/retry-queue.js.map +0 -1
- package/dist/core/trace.d.ts +0 -10
- package/dist/core/trace.js +0 -61
- package/dist/core/trace.js.map +0 -1
- package/dist/core/transport.d.ts +0 -10
- package/dist/core/transport.js +0 -83
- package/dist/core/transport.js.map +0 -1
- package/dist/core/types.d.ts +0 -48
- package/dist/core/types.js +0 -45
- package/dist/core/types.js.map +0 -1
- package/dist/handlers/default.d.ts +0 -6
- package/dist/handlers/default.js +0 -11
- package/dist/handlers/default.js.map +0 -1
- package/dist/handlers/post-tool-use.d.ts +0 -3
- package/dist/handlers/post-tool-use.js +0 -15
- package/dist/handlers/post-tool-use.js.map +0 -1
- package/dist/handlers/pre-tool-use.d.ts +0 -3
- package/dist/handlers/pre-tool-use.js +0 -38
- package/dist/handlers/pre-tool-use.js.map +0 -1
- package/dist/handlers/session.d.ts +0 -3
- package/dist/handlers/session.js +0 -15
- package/dist/handlers/session.js.map +0 -1
- package/dist/handlers/stop.d.ts +0 -3
- package/dist/handlers/stop.js +0 -15
- package/dist/handlers/stop.js.map +0 -1
- package/dist/handlers/user-prompt.d.ts +0 -3
- package/dist/handlers/user-prompt.js +0 -15
- package/dist/handlers/user-prompt.js.map +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to pinta-codex are documented here.
|
|
4
4
|
|
|
5
|
+
## [1.4.0] - 2026-07-12
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- Low-level utilities consolidated into the shared private `@pinta-ai/core`
|
|
10
|
+
package (`^0.3.0`, devDependency). `src/core/*` keeps thin adaptor bindings;
|
|
11
|
+
core is **bundled + minified into `dist/` by esbuild at build time**, so npmjs
|
|
12
|
+
consumers never need private-registry access and `dist/` carries no runtime
|
|
13
|
+
`@pinta-ai/core` dependency.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- `pinta.client.rtt_ms` / `pinta.client.op` span attributes on PreToolUse spans.
|
|
18
|
+
`buildOtlpPayload` already forwards its `guard` result into core's
|
|
19
|
+
`buildPayload`, and core `0.3.0` derives the client-call timing from the
|
|
20
|
+
`GuardResult.clientRttMs` it now measures. The manager can only time its own
|
|
21
|
+
handler, so `clientRttMs - durationMs` gives it the transport overhead.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- `package-lock.json` resolved `@pinta-ai/core` as a `link:` to a local
|
|
26
|
+
`../pinta-core` checkout. `npm ci` created a dangling symlink in CI and the
|
|
27
|
+
build failed with `TS2307: Cannot find module '@pinta-ai/core'`. It is now
|
|
28
|
+
pinned to core's GitHub Packages tarball URL + integrity hash.
|
|
29
|
+
- `publish` workflow: npm pinned to `11.18.0` (npm@latest is 12.x and requires
|
|
30
|
+
node >=22.22, but the job runs node 20).
|
|
31
|
+
- `publish` workflow: restored OIDC trusted publishing. The committed `.npmrc`
|
|
32
|
+
pointed npmjs auth at `${NPM_TOKEN}`, but no such secret exists — it expanded
|
|
33
|
+
to an empty token and would have failed `npm publish` with ENEEDAUTH.
|
|
34
|
+
`NODE_AUTH_TOKEN` is now scoped to the `npm ci` step alone.
|
|
35
|
+
|
|
5
36
|
## [1.2.1] - 2026-04-30
|
|
6
37
|
|
|
7
38
|
### Changed
|
package/dist/index.js
CHANGED
|
@@ -1,53 +1,15 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
async function
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return Buffer.concat(chunks).toString("utf-8");
|
|
17
|
-
}
|
|
18
|
-
async function main() {
|
|
19
|
-
let exitCode = 0;
|
|
20
|
-
try {
|
|
21
|
-
const config = (0, config_js_1.loadConfig)();
|
|
22
|
-
const raw = await readStdin();
|
|
23
|
-
const event = JSON.parse(raw);
|
|
24
|
-
if ((0, types_js_1.isSkippedHook)(event)) {
|
|
25
|
-
exitCode = await (0, default_js_1.handleDefault)(event);
|
|
26
|
-
}
|
|
27
|
-
else if ((0, types_js_1.isPreToolUseEvent)(event)) {
|
|
28
|
-
exitCode = await (0, pre_tool_use_js_1.handlePreToolUse)(event, config);
|
|
29
|
-
}
|
|
30
|
-
else if ((0, types_js_1.isPostToolUseEvent)(event)) {
|
|
31
|
-
exitCode = await (0, post_tool_use_js_1.handlePostToolUse)(event, config);
|
|
32
|
-
}
|
|
33
|
-
else if ((0, types_js_1.isUserPromptSubmitEvent)(event)) {
|
|
34
|
-
exitCode = await (0, user_prompt_js_1.handleUserPrompt)(event, config);
|
|
35
|
-
}
|
|
36
|
-
else if ((0, types_js_1.isSessionEvent)(event)) {
|
|
37
|
-
exitCode = await (0, session_js_1.handleSession)(event, config);
|
|
38
|
-
}
|
|
39
|
-
else if ((0, types_js_1.isStopEvent)(event)) {
|
|
40
|
-
exitCode = await (0, stop_js_1.handleStop)(event, config);
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
exitCode = await (0, default_js_1.handleDefault)(event);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
catch (err) {
|
|
47
|
-
process.stderr.write(`[pinta-codex] error: ${err}\n`);
|
|
48
|
-
exitCode = 0; // top-level catch-all stays fail-open per spec §6
|
|
49
|
-
}
|
|
50
|
-
process.exit(exitCode);
|
|
51
|
-
}
|
|
52
|
-
main();
|
|
53
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
"use strict";var et=Object.create;var re=Object.defineProperty;var tt=Object.getOwnPropertyDescriptor;var rt=Object.getOwnPropertyNames;var nt=Object.getPrototypeOf,ot=Object.prototype.hasOwnProperty;var f=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var st=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of rt(e))!ot.call(t,o)&&o!==r&&re(t,o,{get:()=>e[o],enumerable:!(n=tt(e,o))||n.enumerable});return t};var _=(t,e,r)=>(r=t!=null?et(nt(t)):{},st(e||!t||!t.__esModule?re(r,"default",{value:t,enumerable:!0}):r,t));var C=f(c=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});c.PATTERNS=c.MAX_BYTES=void 0;c.truncate=it;c.collectMatches=ne;c.resolveOverlaps=oe;c.applyMatches=se;c.redact=at;c.MAX_BYTES=102400;function it(t){let e=Buffer.from(t,"utf-8");return e.length<=c.MAX_BYTES?t:`${e.subarray(0,c.MAX_BYTES).toString("utf-8")}\u2026[TRUNCATED:${e.length}]`}c.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 ne(t,e){let r=[];for(let n of c.PATTERNS){if(n.requireContext&&n.requireContext!==e.context)continue;let o=new RegExp(n.regex.source,n.regex.flags),i;for(;(i=o.exec(t))!==null;){let a=n.captureGroup??0,u=i[a];if(u===void 0){i.index===o.lastIndex&&o.lastIndex++;continue}let S=i.index,Je=i.index+i[0].length,te=S+i[0].indexOf(u),Qe=te+u.length;r.push({start:S,end:Je,replaceStart:te,replaceEnd:Qe,type:n.type}),i.index===o.lastIndex&&o.lastIndex++}}return r}function oe(t){let e=[...t].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 e)o.start<n||(r.push(o),n=o.end);return r}function se(t,e){let r=[...e].sort((o,i)=>i.replaceStart-o.replaceStart),n=t;for(let o of r)n=n.slice(0,o.replaceStart)+`[REDACTED:${o.type}]`+n.slice(o.replaceEnd);return n}function at(t,e={}){if(t.length===0)return t;let r=ne(t,e);if(r.length===0)return t;let n=oe(r);return se(t,n)}});var N=f(p=>{"use strict";var ut=p&&p.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(p,"__esModule",{value:!0});p.ulidToTraceId=ue;p.newSpanId=ce;p.snakeCase=pt;p.toOtlpValue=le;p.attrsFromRecord=dt;p.guardAttrs=pe;p.clientAttrs=de;p.buildPayload=ft;p.mergeBatch=_t;var ct=ut(require("crypto")),ie=C(),lt="0123456789ABCDEFGHJKMNPQRSTVWXYZ";function ue(t){if(t.length!==26)throw new Error(`ulidToTraceId: expected 26 chars, got ${t.length}`);let e=0n;for(let n of t){let o=lt.indexOf(n);if(o<0)throw new Error(`ulidToTraceId: invalid Crockford char "${n}"`);e=e<<5n|BigInt(o)}let r=(1n<<128n)-1n;return e&=r,e.toString(16).padStart(32,"0")}function ce(){return ct.default.randomBytes(8).toString("hex")}function pt(t){return t.replace(/([a-z0-9])([A-Z])/g,"$1_$2").replace(/([A-Z])([A-Z][a-z])/g,"$1_$2").toLowerCase()}var ae=new Set;function R(t,e,r){let n=(0,ie.truncate)(e);if((r.skipRedactKeys??ae).has(t))return n;let o=(r.bashContextKeys??ae).has(t)?"bash":void 0;return(0,ie.redact)(n,{context:o})}function le(t,e,r={}){if(e==null)return null;switch(typeof e){case"string":return{stringValue:R(t,e,r)};case"boolean":return{boolValue:e};case"number":return Number.isInteger(e)?{intValue:e}:{doubleValue:e};case"object":try{return{stringValue:R(t,JSON.stringify(e),r)}}catch{return{stringValue:R(t,String(e),r)}}default:return{stringValue:R(t,String(e),r)}}}function dt(t,e,r={}){let n=[];for(let[o,i]of Object.entries(t)){let a=`${e}.${o}`,u=le(a,i,r);u!==null&&n.push({key:a,value:u})}return n}function pe(t){let e=[{key:"pinta.guard.decision",value:{stringValue:t.decision.toLowerCase()}},{key:"pinta.guard.duration_ms",value:{intValue:t.durationMs}}];return t.reason&&e.push({key:"pinta.guard.matched_rule",value:{stringValue:t.reason}}),t.failOpenReason&&e.push({key:"pinta.guard.fail_open_reason",value:{stringValue:t.failOpenReason}}),e}function de(t){return[{key:"pinta.client.rtt_ms",value:Number.isInteger(t.rttMs)?{intValue:t.rttMs}:{doubleValue:t.rttMs}},{key:"pinta.client.op",value:{stringValue:t.op}}]}function ft(t){let e=t.now??Date.now(),r=(BigInt(e)*1000000n).toString(),n=[...t.attributes];t.guard&&n.push(...pe(t.guard));let o=t.clientTiming??(t.guard?.clientRttMs!==void 0?{op:"guard",rttMs:t.guard.clientRttMs}:null);o&&n.push(...de(o));let i={traceId:ue(t.traceId),spanId:ce(),name:t.spanName,kind:t.spanKind??1,startTimeUnixNano:r,endTimeUnixNano:r,attributes:n};return{resourceSpans:[{resource:{attributes:t.resource},scopeSpans:[{scope:t.scope,spans:[i]}]}]}}function _t(t){let e=[];for(let r of t)e.push(...r.resourceSpans);return{resourceSpans:e}}});var _e=f(U=>{"use strict";Object.defineProperty(U,"__esModule",{value:!0});U.evaluateGuard=yt;var mt=1e4,gt="pinta-core";function fe(t,e){return{decision:"ALLOW",reason:null,userMessage:null,durationMs:t,clientRttMs:t,failOpenReason:e}}function ht(t){return new Promise((e,r)=>setTimeout(()=>{let n=new Error("Guard request timed out");n.name="TimeoutError",r(n)},t))}async function yt(t,e,r={}){if(!e||r.disabled)return null;let n=r.timeoutMs??mt,o=Date.now();try{let i=await Promise.race([fetch(e,{method:"POST",headers:{"content-type":"application/json","user-agent":r.userAgent??gt,"x-pinta-relay-token":r.token??""},body:JSON.stringify({input:t})}),ht(n)]);if(i.status!==200)return fe(Date.now()-o,"error");let a=await i.json(),u=Date.now()-o;return{decision:a.decision,reason:a.reason,userMessage:a.userMessage??null,durationMs:a.durationMs??u,clientRttMs:u}}catch(i){let a=i.name==="TimeoutError"?"timeout":"error";return fe(Date.now()-o,a)}}});var B=f(h=>{"use strict";var me=h&&h.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(h,"__esModule",{value:!0});h.MemoryRetryQueue=h.DiskRetryQueue=void 0;var l=me(require("fs")),A=me(require("path")),w=1e3,Pt=50,Et=5,L=class{filePath;lockPath;logPrefix;constructor(e,r){this.filePath=A.default.join(e,"failed-spans.jsonl"),this.lockPath=this.filePath+".lock",this.logPrefix=r}enqueue(e){try{l.default.mkdirSync(A.default.dirname(this.filePath),{recursive:!0});let r=JSON.stringify({savedAt:new Date().toISOString(),payload:e})+`
|
|
2
|
+
`;l.default.appendFileSync(this.filePath,r),this.trim()}catch(r){process.stderr.write(`[${this.logPrefix}] retry-queue enqueue failed: ${r}
|
|
3
|
+
`)}}readAll(){try{let e=l.default.readFileSync(this.filePath,"utf-8"),r=[];for(let n of e.split(`
|
|
4
|
+
`))if(n.trim())try{r.push(JSON.parse(n))}catch{}return r}catch{return[]}}rewrite(e){try{if(e.length===0){l.default.existsSync(this.filePath)&&l.default.unlinkSync(this.filePath);return}l.default.mkdirSync(A.default.dirname(this.filePath),{recursive:!0}),l.default.writeFileSync(this.filePath,e.map(r=>JSON.stringify(r)).join(`
|
|
5
|
+
`)+`
|
|
6
|
+
`)}catch(r){process.stderr.write(`[${this.logPrefix}] retry-queue rewrite failed: ${r}
|
|
7
|
+
`)}}tryAcquireLock(){let e=Date.now();for(l.default.mkdirSync(A.default.dirname(this.lockPath),{recursive:!0});Date.now()-e<Pt;)try{let r=l.default.openSync(this.lockPath,"wx");return l.default.writeSync(r,String(process.pid)),l.default.closeSync(r),!0}catch(r){if(r?.code!=="EEXIST")return process.stderr.write(`[${this.logPrefix}] retry-queue lock open failed: ${r}
|
|
8
|
+
`),!1;try{let i=l.default.statSync(this.lockPath);if(Date.now()-i.mtimeMs>3e4){l.default.unlinkSync(this.lockPath);continue}}catch{}let n=Et,o=Date.now()+n;for(;Date.now()<o;);}return!1}release(){try{l.default.unlinkSync(this.lockPath)}catch{}}trim(){let e=this.readAll();if(e.length<=w)return;let r=e.length-w;process.stderr.write(`[${this.logPrefix}] retry-queue full, dropping ${r} oldest entries
|
|
9
|
+
`),this.rewrite(e.slice(r))}};h.DiskRetryQueue=L;var q=class{entries=[];enqueue(e){this.entries.push(e),this.entries.length>w&&this.entries.splice(0,this.entries.length-w)}drain(){let e=this.entries;return this.entries=[],e}get size(){return this.entries.length}};h.MemoryRetryQueue=q});var Ee=f(m=>{"use strict";Object.defineProperty(m,"__esModule",{value:!0});m.MemoryTransport=m.DiskTransport=void 0;m.parseHeadersEnv=ye;m.envOptionsResolver=Pe;m.postOtlp=x;var ge=B(),he=N(),vt=5e3;function ye(t){if(!t)return{};if(typeof t=="object")return{...t};let e={};for(let r of t.split(",")){let[n,...o]=r.split("=");n&&o.length>0&&(e[n.trim()]=o.join("=").trim())}return e}function Pe(){let t=process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,e=process.env.OTEL_EXPORTER_OTLP_ENDPOINT,r;return t?r=t.replace(/\/+$/,""):e&&(r=e.replace(/\/+$/,"")+"/v1/traces"),r?{endpoint:r,headers:ye(process.env.OTEL_EXPORTER_OTLP_HEADERS)}:null}async function x(t,e,r){let n=new AbortController,o=setTimeout(()=>n.abort(),vt);try{let i=await fetch(e.endpoint,{method:"POST",headers:{"Content-Type":"application/json",...e.headers},body:JSON.stringify(t),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} ${e.endpoint}${u}${a?` body=${a}`:""}
|
|
10
|
+
`),!1}return!0}catch(i){return process.stderr.write(`[${r}] OTLP POST failed: ${i.message??String(i)}
|
|
11
|
+
`),!1}finally{clearTimeout(o)}}var G=class{queue;logPrefix;resolveOptions;constructor(e){this.queue=new ge.DiskRetryQueue(e.pluginData,e.logPrefix),this.logPrefix=e.logPrefix,this.resolveOptions=e.resolveOptions??Pe}async send(e){let r=this.resolveOptions();if(!r)return;await x(e,r,this.logPrefix)||this.queue.enqueue(e)}async flush(){let e=this.resolveOptions();if(e&&this.queue.tryAcquireLock())try{let r=this.queue.readAll();if(r.length===0)return;let n=(0,he.mergeBatch)(r.map(i=>i.payload));await x(n,e,this.logPrefix)&&this.queue.rewrite([])}finally{this.queue.release()}}};m.DiskTransport=G;var V=class{queue=new ge.MemoryRetryQueue;logPrefix;resolveOptions;constructor(e){this.logPrefix=e.logPrefix,this.resolveOptions=e.resolveOptions}async send(e){let r=this.resolveOptions();if(!r)return;await x(e,r,this.logPrefix)||this.queue.enqueue(e)}async flush(){let e=this.resolveOptions();if(!e)return;let r=this.queue.drain();if(r.length===0)return;let n=(0,he.mergeBatch)(r);if(!await x(n,e,this.logPrefix))for(let i of r)this.queue.enqueue(i)}};m.MemoryTransport=V});var Y=f(P=>{"use strict";var K=P&&P.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(P,"__esModule",{value:!0});P.TraceManager=void 0;P.generateUlid=ve;var F=K(require("fs")),Ot=K(require("path")),Tt=K(require("crypto")),X="0123456789ABCDEFGHJKMNPQRSTVWXYZ";function ve(){let t=Date.now(),e="",r=t;for(let i=0;i<10;i++)e=X[r&31]+e,r=Math.floor(r/32);let n=Tt.default.randomBytes(10),o="";for(let i=0;i<10;i++)o+=X[n[i]&31];for(;o.length<16;)o+=X[0];return e+o}var $=class{tracePath;constructor(e){this.tracePath=e}newTrace(){let e=ve();return this.save(e),e}currentTrace(){try{let e=F.default.readFileSync(this.tracePath,"utf-8"),{traceId:r}=JSON.parse(e);if(r)return r}catch{}return this.newTrace()}save(e){F.default.mkdirSync(Ot.default.dirname(this.tracePath),{recursive:!0}),F.default.writeFileSync(this.tracePath,JSON.stringify({traceId:e}))}};P.TraceManager=$});var xe=f(y=>{"use strict";var Oe=y&&y.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(y,"__esModule",{value:!0});y.MemorySessionTraceManager=y.DiskSessionTraceManager=void 0;var H=Oe(require("fs")),St=Oe(require("path")),Te=Y(),Se=200,Z=class{tracePath;maxSessions;constructor(e,r={}){this.tracePath=e,this.maxSessions=r.maxSessions??Se}read(){try{let e=JSON.parse(H.default.readFileSync(this.tracePath,"utf-8"));if(e&&typeof e=="object"&&!("traceId"in e))return e}catch{}return{}}write(e){try{H.default.mkdirSync(St.default.dirname(this.tracePath),{recursive:!0});let r=Object.entries(e),n=r.length>this.maxSessions?Object.fromEntries(r.slice(-this.maxSessions)):e;H.default.writeFileSync(this.tracePath,JSON.stringify(n))}catch{}}newTrace(e){let r=e||"default",n=(0,Te.generateUlid)(),o=this.read();return o[r]=n,this.write(o),n}currentTrace(e){let r=e||"default",n=this.read()[r];return n||this.newTrace(r)}};y.DiskSessionTraceManager=Z;var W=class{map=new Map;maxSessions;constructor(e={}){this.maxSessions=e.maxSessions??Se}newTrace(e){let r=e||"default",n=(0,Te.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(e){let r=e||"default";return this.map.get(r)??this.newTrace(r)}};y.MemorySessionTraceManager=W});var Re=f(E=>{"use strict";var z=E&&E.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(E,"__esModule",{value:!0});E.envFilePath=bt;E.parseEnvFile=be;E.loadEnvFile=Rt;var xt=z(require("node:fs")),kt=z(require("node:os")),ke=z(require("node:path"));function bt(t,e,r){let n=r?process.env[r]:void 0,o=n&&n.length>0?n:ke.default.join(kt.default.homedir(),t);return ke.default.join(o,e)}function be(t){let e={};for(let r of t.split(`
|
|
12
|
+
`)){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&&(e[i]=a)}return e}function Rt(t){let e;try{e=xt.default.readFileSync(t,"utf-8")}catch{return}let r=be(e);for(let[n,o]of Object.entries(r))process.env[n]===void 0&&(process.env[n]=o)}});var T=f(s=>{"use strict";Object.defineProperty(s,"__esModule",{value:!0});s.loadEnvFile=s.parseEnvFile=s.envFilePath=s.MemorySessionTraceManager=s.DiskSessionTraceManager=s.generateUlid=s.TraceManager=s.parseHeadersEnv=s.envOptionsResolver=s.postOtlp=s.MemoryTransport=s.DiskTransport=s.MemoryRetryQueue=s.DiskRetryQueue=s.evaluateGuard=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.truncate=s.redact=void 0;var v=C();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,"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 g=N();Object.defineProperty(s,"ulidToTraceId",{enumerable:!0,get:function(){return g.ulidToTraceId}});Object.defineProperty(s,"newSpanId",{enumerable:!0,get:function(){return g.newSpanId}});Object.defineProperty(s,"snakeCase",{enumerable:!0,get:function(){return g.snakeCase}});Object.defineProperty(s,"toOtlpValue",{enumerable:!0,get:function(){return g.toOtlpValue}});Object.defineProperty(s,"attrsFromRecord",{enumerable:!0,get:function(){return g.attrsFromRecord}});Object.defineProperty(s,"guardAttrs",{enumerable:!0,get:function(){return g.guardAttrs}});Object.defineProperty(s,"clientAttrs",{enumerable:!0,get:function(){return g.clientAttrs}});Object.defineProperty(s,"buildPayload",{enumerable:!0,get:function(){return g.buildPayload}});Object.defineProperty(s,"mergeBatch",{enumerable:!0,get:function(){return g.mergeBatch}});var At=_e();Object.defineProperty(s,"evaluateGuard",{enumerable:!0,get:function(){return At.evaluateGuard}});var Ae=B();Object.defineProperty(s,"DiskRetryQueue",{enumerable:!0,get:function(){return Ae.DiskRetryQueue}});Object.defineProperty(s,"MemoryRetryQueue",{enumerable:!0,get:function(){return Ae.MemoryRetryQueue}});var k=Ee();Object.defineProperty(s,"DiskTransport",{enumerable:!0,get:function(){return k.DiskTransport}});Object.defineProperty(s,"MemoryTransport",{enumerable:!0,get:function(){return k.MemoryTransport}});Object.defineProperty(s,"postOtlp",{enumerable:!0,get:function(){return k.postOtlp}});Object.defineProperty(s,"envOptionsResolver",{enumerable:!0,get:function(){return k.envOptionsResolver}});Object.defineProperty(s,"parseHeadersEnv",{enumerable:!0,get:function(){return k.parseHeadersEnv}});var we=Y();Object.defineProperty(s,"TraceManager",{enumerable:!0,get:function(){return we.TraceManager}});Object.defineProperty(s,"generateUlid",{enumerable:!0,get:function(){return we.generateUlid}});var De=xe();Object.defineProperty(s,"DiskSessionTraceManager",{enumerable:!0,get:function(){return De.DiskSessionTraceManager}});Object.defineProperty(s,"MemorySessionTraceManager",{enumerable:!0,get:function(){return De.MemorySessionTraceManager}});var J=Re();Object.defineProperty(s,"envFilePath",{enumerable:!0,get:function(){return J.envFilePath}});Object.defineProperty(s,"parseEnvFile",{enumerable:!0,get:function(){return J.parseEnvFile}});Object.defineProperty(s,"loadEnvFile",{enumerable:!0,get:function(){return J.loadEnvFile}})});var Q=_(require("node:fs")),Ie=_(require("node:os")),b=_(require("node:path")),Me=_(T());function wt(t){let e={},r;try{r=Q.default.readFileSync(t,"utf-8")}catch{return e}for(let n of r.split(`
|
|
13
|
+
`)){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&&(e[a]=u)}return e}function Dt(t){let e=process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT??t.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT;if(e)return e;let r=process.env.OTEL_EXPORTER_OTLP_ENDPOINT??t.OTEL_EXPORTER_OTLP_ENDPOINT;return r?r.replace(/\/+$/,"")+"/v1/traces":process.env.PINTA_CODEX_ENDPOINT??t.PINTA_CODEX_ENDPOINT??process.env.CLAUDE_PLUGIN_OPTION_ENDPOINT}function It(t){if(process.env.OTEL_EXPORTER_OTLP_HEADERS)return process.env.OTEL_EXPORTER_OTLP_HEADERS;if(t.OTEL_EXPORTER_OTLP_HEADERS)return t.OTEL_EXPORTER_OTLP_HEADERS;if(process.env.PINTA_CODEX_API_KEY)return`x-pinta-relay-token=${process.env.PINTA_CODEX_API_KEY}`;if(t.PINTA_CODEX_API_KEY)return`x-pinta-relay-token=${t.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 je(){let t=process.env.CODEX_PLUGIN_ROOT??process.env.CLAUDE_PLUGIN_ROOT??process.cwd(),e=process.env.CODEX_PLUGIN_DATA??process.env.CLAUDE_PLUGIN_DATA??b.default.join(t,".plugin-data"),r=process.env.CODEX_HOME??b.default.join(Ie.default.homedir(),".codex"),n=b.default.join(r,"pinta-codex.env"),o=Q.default.existsSync(n)?wt(n):{},i=Dt(o),a=It(o);if(a&&!process.env.PINTA_RELAY_TOKEN){let S=a.match(/x-pinta-relay-token=([^,\s]+)/i);S&&(process.env.PINTA_RELAY_TOKEN=S[1])}let u=process.env.PINTA_GUARD_ENDPOINT??o.PINTA_GUARD_ENDPOINT;return{pluginRoot:t,pluginData:e,tracePath:b.default.join(e,"trace.json"),endpoint:i?.replace(/\/+$/,""),headers:(0,Me.parseHeadersEnv)(a??""),guardEndpoint:u}}function Ce(t){return t.hook_event_name==="PreToolUse"}function Ne(t){return t.hook_event_name==="PostToolUse"}function Ue(t){return t.hook_event_name==="UserPromptSubmit"}function Le(t){return t.hook_event_name==="SessionStart"}function qe(t){return t.hook_event_name==="Stop"}var Mt=new Set(["PreToolUse","PostToolUse","SessionStart","UserPromptSubmit","Stop"]);function Be(t){return!Mt.has(t.hook_event_name)}var Ge=_(T()),jt=50,Ct="pinta-codex/1.4.0";async function Ve(t,e){let r=await(0,Ge.evaluateGuard)(t,e,{timeoutMs:jt,token:process.env.PINTA_RELAY_TOKEN??"",disabled:process.env.PINTA_GUARD_DISABLED==="1",userAgent:Ct});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 Fe=_(T()),D=class extends Fe.DiskTransport{constructor(e){super({pluginData:e.pluginData,logPrefix:"pinta-codex",resolveOptions:()=>e.endpoint?{endpoint:e.endpoint,headers:e.headers}:null})}};var Xe=_(T()),I=class extends Xe.TraceManager{constructor(e){super(e.tracePath)}};var j=_(require("os")),O=_(T());var $e="1.4.0",M=null;function Nt(){return M!==null||(M=process.env.CODEX_CLI_VERSION||"unknown"),M}var Ut=new Set(["codex.hook","codex.tool_name","codex.tool_use_id","codex.session_id","codex.transcript_path","codex.cwd","codex.permission_mode"]),Lt=new Set(["codex.tool_input","codex.tool_response"]),qt={skipRedactKeys:Ut,bashContextKeys:Lt};function Bt(t){let e=[];e.push({key:"ingest.type",value:{stringValue:"codex"}}),e.push({key:"codex.hook",value:{stringValue:t.hook_event_name}});let r={};for(let[n,o]of Object.entries(t))n!=="hook_event_name"&&(r[n]=o);return e.push(...(0,O.attrsFromRecord)(r,"codex",qt)),e}function Gt(){return[{key:"service.name",value:{stringValue:"codex"}},{key:"service.version",value:{stringValue:Nt()}},{key:"telemetry.sdk.name",value:{stringValue:"pinta-codex"}},{key:"telemetry.sdk.language",value:{stringValue:"nodejs"}},{key:"telemetry.sdk.version",value:{stringValue:$e}},{key:"process.pid",value:{intValue:process.pid}},{key:"process.owner",value:{stringValue:j.default.userInfo().username}},{key:"host.name",value:{stringValue:j.default.hostname()}},{key:"host.arch",value:{stringValue:j.default.arch()}}]}function Ke(t){return(0,O.buildPayload)({traceId:t.traceId,spanName:`codex.${(0,O.snakeCase)(t.event.hook_event_name)}`,attributes:Bt(t.event),resource:Gt(),scope:{name:"pinta-codex",version:$e},now:t.now,guard:t.guard})}async function d(t,e,r){let n=new D(e);await n.flush();let o=new I(e),i=r.trace==="new"?o.newTrace():o.currentTrace(),a=Ke({event:t,traceId:i,guard:r.guard});await n.send(a)}async function Ye(t,e){let r=typeof t.tool_input=="string"?t.tool_input:JSON.stringify(t.tool_input),n=await Ve({spanId:t.session_id??"unknown",toolName:t.tool_name,toolInput:t.tool_input,rawTextFields:{toolInput:r}},e.guardEndpoint);if(await d(t,e,{trace:"current",guard:n}),n?.decision==="DENY"){let o={hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:n.reason??"guard_deny"}};process.stdout.write(JSON.stringify(o)+`
|
|
14
|
+
`)}return 0}async function He(t,e){return await d(t,e,{trace:"current"}),0}async function Ze(t,e){return await d(t,e,{trace:"new"}),0}async function We(t,e){return await d(t,e,{trace:"current"}),0}async function ze(t,e){return await d(t,e,{trace:"current"}),0}async function ee(t){return 0}async function Vt(){let t=[];for await(let e of process.stdin)t.push(e);return Buffer.concat(t).toString("utf-8")}async function Ft(){let t=0;try{let e=je(),r=await Vt(),n=JSON.parse(r);Be(n)?t=await ee(n):Ce(n)?t=await Ye(n,e):Ne(n)?t=await He(n,e):Ue(n)?t=await Ze(n,e):Le(n)?t=await We(n,e):qe(n)?t=await ze(n,e):t=await ee(n)}catch(e){process.stderr.write(`[pinta-codex] error: ${e}
|
|
15
|
+
`),t=0}process.exit(t)}Ft();
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pinta-ai/pinta-codex",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Generic OTLP forwarder for Codex hook events",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"license": "SEE LICENSE IN ./LICENSE",
|
|
7
7
|
"author": "Pinta AI (https://pinta.sh)",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
|
-
"url": "https://github.com/
|
|
10
|
+
"url": "git+https://github.com/pinta-ai/pinta-codex.git"
|
|
11
11
|
},
|
|
12
|
-
"homepage": "https://github.com/
|
|
12
|
+
"homepage": "https://github.com/pinta-ai/pinta-codex",
|
|
13
13
|
"bugs": {
|
|
14
|
-
"url": "https://github.com/
|
|
14
|
+
"url": "https://github.com/pinta-ai/pinta-codex/issues"
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
17
|
"dist",
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
"CHANGELOG.md"
|
|
24
24
|
],
|
|
25
25
|
"scripts": {
|
|
26
|
-
"
|
|
26
|
+
"bump": "node scripts/bump.mjs",
|
|
27
|
+
"build": "tsc --noEmit && esbuild src/index.ts --bundle --platform=node --format=cjs --target=node18 --minify --outfile=dist/index.js",
|
|
27
28
|
"dev": "tsc --watch",
|
|
28
29
|
"setup": "npx tsx tools/setup.ts",
|
|
29
30
|
"doctor": "npx tsx tools/doctor.ts",
|
|
@@ -33,11 +34,18 @@
|
|
|
33
34
|
"test:otlp": "npx tsx tools/test-otlp.ts",
|
|
34
35
|
"test:redact": "npx tsx tools/test-redact.ts",
|
|
35
36
|
"test": "vitest run",
|
|
36
|
-
"test:watch": "vitest"
|
|
37
|
+
"test:watch": "vitest",
|
|
38
|
+
"prepublishOnly": "npm run build"
|
|
37
39
|
},
|
|
38
40
|
"devDependencies": {
|
|
41
|
+
"@pinta-ai/core": "^0.3.0",
|
|
39
42
|
"@types/node": "^22.0.0",
|
|
43
|
+
"esbuild": "^0.24.0",
|
|
40
44
|
"typescript": "^5.7.0",
|
|
41
45
|
"vitest": "^2.1.0"
|
|
46
|
+
},
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"registry": "https://registry.npmjs.org",
|
|
49
|
+
"access": "public"
|
|
42
50
|
}
|
|
43
51
|
}
|
package/dist/core/config.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export interface PintaCodexConfig {
|
|
2
|
-
pluginRoot: string;
|
|
3
|
-
pluginData: string;
|
|
4
|
-
tracePath: string;
|
|
5
|
-
endpoint?: string;
|
|
6
|
-
headers: Record<string, string>;
|
|
7
|
-
/** Plan 5: manager-local guard endpoint (or undefined → guard skipped). */
|
|
8
|
-
guardEndpoint?: string;
|
|
9
|
-
}
|
|
10
|
-
export declare function loadConfig(): PintaCodexConfig;
|
|
11
|
-
/** Returns true if OTel endpoint is configured (signal to silently disable telemetry). */
|
|
12
|
-
export declare function hasOtlpEndpoint(config: PintaCodexConfig): boolean;
|
package/dist/core/config.js
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.loadConfig = loadConfig;
|
|
7
|
-
exports.hasOtlpEndpoint = hasOtlpEndpoint;
|
|
8
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
|
-
const node_os_1 = __importDefault(require("node:os"));
|
|
10
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
-
function readEnvFile(p) {
|
|
12
|
-
const out = {};
|
|
13
|
-
let content;
|
|
14
|
-
try {
|
|
15
|
-
content = node_fs_1.default.readFileSync(p, "utf-8");
|
|
16
|
-
}
|
|
17
|
-
catch {
|
|
18
|
-
return out;
|
|
19
|
-
}
|
|
20
|
-
for (const raw of content.split("\n")) {
|
|
21
|
-
const line = raw.trim();
|
|
22
|
-
if (!line || line.startsWith("#"))
|
|
23
|
-
continue;
|
|
24
|
-
const idx = line.indexOf("=");
|
|
25
|
-
if (idx < 0)
|
|
26
|
-
continue;
|
|
27
|
-
const key = line.slice(0, idx).trim();
|
|
28
|
-
let value = line.slice(idx + 1).trim();
|
|
29
|
-
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
30
|
-
(value.startsWith("'") && value.endsWith("'"))) {
|
|
31
|
-
value = value.slice(1, -1);
|
|
32
|
-
}
|
|
33
|
-
if (key)
|
|
34
|
-
out[key] = value;
|
|
35
|
-
}
|
|
36
|
-
return out;
|
|
37
|
-
}
|
|
38
|
-
function resolveEndpoint(envFile) {
|
|
39
|
-
// Per OTel spec:
|
|
40
|
-
// OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = full URL (use as-is)
|
|
41
|
-
// OTEL_EXPORTER_OTLP_ENDPOINT = base URL (append /v1/traces)
|
|
42
|
-
// We treat values from manager (and the user-facing parity vars) as full URLs.
|
|
43
|
-
const tracesEndpoint = process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ??
|
|
44
|
-
envFile.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT;
|
|
45
|
-
if (tracesEndpoint)
|
|
46
|
-
return tracesEndpoint;
|
|
47
|
-
const baseEndpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT ??
|
|
48
|
-
envFile.OTEL_EXPORTER_OTLP_ENDPOINT;
|
|
49
|
-
if (baseEndpoint)
|
|
50
|
-
return baseEndpoint.replace(/\/+$/, "") + "/v1/traces";
|
|
51
|
-
return (process.env.PINTA_CODEX_ENDPOINT ?? // legacy (full URL)
|
|
52
|
-
envFile.PINTA_CODEX_ENDPOINT ?? // legacy
|
|
53
|
-
process.env.CLAUDE_PLUGIN_OPTION_ENDPOINT // parity (full URL)
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
function resolveHeaders(envFile) {
|
|
57
|
-
// Primary: OTel-spec, already in `key=val,key=val` format
|
|
58
|
-
if (process.env.OTEL_EXPORTER_OTLP_HEADERS)
|
|
59
|
-
return process.env.OTEL_EXPORTER_OTLP_HEADERS;
|
|
60
|
-
if (envFile.OTEL_EXPORTER_OTLP_HEADERS)
|
|
61
|
-
return envFile.OTEL_EXPORTER_OTLP_HEADERS;
|
|
62
|
-
// Legacy: raw token → wrap as x-pinta-relay-token header
|
|
63
|
-
if (process.env.PINTA_CODEX_API_KEY) {
|
|
64
|
-
return `x-pinta-relay-token=${process.env.PINTA_CODEX_API_KEY}`;
|
|
65
|
-
}
|
|
66
|
-
if (envFile.PINTA_CODEX_API_KEY) {
|
|
67
|
-
return `x-pinta-relay-token=${envFile.PINTA_CODEX_API_KEY}`;
|
|
68
|
-
}
|
|
69
|
-
// Parity: Claude Code-style userConfig env (raw token, same wrap)
|
|
70
|
-
if (process.env.CLAUDE_PLUGIN_OPTION_API_KEY) {
|
|
71
|
-
return `x-pinta-relay-token=${process.env.CLAUDE_PLUGIN_OPTION_API_KEY}`;
|
|
72
|
-
}
|
|
73
|
-
return undefined;
|
|
74
|
-
}
|
|
75
|
-
function parseHeadersString(raw) {
|
|
76
|
-
const out = {};
|
|
77
|
-
if (!raw)
|
|
78
|
-
return out;
|
|
79
|
-
for (const pair of raw.split(",")) {
|
|
80
|
-
const [k, ...rest] = pair.split("=");
|
|
81
|
-
if (k && rest.length > 0)
|
|
82
|
-
out[k.trim()] = rest.join("=").trim();
|
|
83
|
-
}
|
|
84
|
-
return out;
|
|
85
|
-
}
|
|
86
|
-
function loadConfig() {
|
|
87
|
-
const pluginRoot = process.env.CODEX_PLUGIN_ROOT
|
|
88
|
-
?? process.env.CLAUDE_PLUGIN_ROOT
|
|
89
|
-
?? process.cwd();
|
|
90
|
-
const pluginData = process.env.CODEX_PLUGIN_DATA
|
|
91
|
-
?? process.env.CLAUDE_PLUGIN_DATA
|
|
92
|
-
?? node_path_1.default.join(pluginRoot, ".plugin-data");
|
|
93
|
-
const codexHome = process.env.CODEX_HOME ?? node_path_1.default.join(node_os_1.default.homedir(), ".codex");
|
|
94
|
-
const envFilePath = node_path_1.default.join(codexHome, "pinta-codex.env");
|
|
95
|
-
const envFile = node_fs_1.default.existsSync(envFilePath) ? readEnvFile(envFilePath) : {};
|
|
96
|
-
const endpoint = resolveEndpoint(envFile);
|
|
97
|
-
const headersRaw = resolveHeaders(envFile);
|
|
98
|
-
// Plan 5: expose relay token for guard.ts (~/guard/evaluate auth header).
|
|
99
|
-
// Parse x-pinta-relay-token from the resolved OTEL headers string so guard.ts
|
|
100
|
-
// can read it from process.env.PINTA_RELAY_TOKEN (same as pinta-cc pattern).
|
|
101
|
-
if (headersRaw && !process.env.PINTA_RELAY_TOKEN) {
|
|
102
|
-
const tokenMatch = headersRaw.match(/x-pinta-relay-token=([^,\s]+)/i);
|
|
103
|
-
if (tokenMatch) {
|
|
104
|
-
process.env.PINTA_RELAY_TOKEN = tokenMatch[1];
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
// Plan 5 v1.2.4: codex CLI does NOT inject pinta-codex.env into hook
|
|
108
|
-
// subprocess env (unlike Claude Code's settings.json env-prefix). The hook
|
|
109
|
-
// must read PINTA_GUARD_ENDPOINT from envFile too — not just process.env.
|
|
110
|
-
// Same pattern as resolveEndpoint/resolveHeaders above.
|
|
111
|
-
const guardEndpoint = process.env.PINTA_GUARD_ENDPOINT ?? envFile.PINTA_GUARD_ENDPOINT;
|
|
112
|
-
return {
|
|
113
|
-
pluginRoot,
|
|
114
|
-
pluginData,
|
|
115
|
-
tracePath: node_path_1.default.join(pluginData, "trace.json"),
|
|
116
|
-
endpoint: endpoint?.replace(/\/+$/, ""),
|
|
117
|
-
headers: parseHeadersString(headersRaw ?? ""),
|
|
118
|
-
guardEndpoint,
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
/** Returns true if OTel endpoint is configured (signal to silently disable telemetry). */
|
|
122
|
-
function hasOtlpEndpoint(config) {
|
|
123
|
-
return Boolean(config.endpoint);
|
|
124
|
-
}
|
|
125
|
-
//# sourceMappingURL=config.js.map
|
package/dist/core/config.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"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"}
|
package/dist/core/guard.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export interface GuardInput {
|
|
2
|
-
spanId: string;
|
|
3
|
-
toolName?: string;
|
|
4
|
-
toolInput?: unknown;
|
|
5
|
-
rawTextFields?: Record<string, string>;
|
|
6
|
-
}
|
|
7
|
-
export interface GuardResult {
|
|
8
|
-
decision: 'ALLOW' | 'DENY' | 'REVIEW';
|
|
9
|
-
reason: string | null;
|
|
10
|
-
durationMs: number;
|
|
11
|
-
failOpenReason?: 'timeout' | 'refused' | 'error';
|
|
12
|
-
}
|
|
13
|
-
export declare function evaluateGuard(input: GuardInput, endpoint: string | undefined): Promise<GuardResult | null>;
|
package/dist/core/guard.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.evaluateGuard = evaluateGuard;
|
|
4
|
-
const TIMEOUT_MS = 50;
|
|
5
|
-
function sleep(ms) {
|
|
6
|
-
return new Promise((_, reject) => setTimeout(() => {
|
|
7
|
-
const err = new Error('Guard request timed out');
|
|
8
|
-
err.name = 'TimeoutError';
|
|
9
|
-
reject(err);
|
|
10
|
-
}, ms));
|
|
11
|
-
}
|
|
12
|
-
async function evaluateGuard(input, endpoint) {
|
|
13
|
-
if (!endpoint)
|
|
14
|
-
return null;
|
|
15
|
-
if (process.env.PINTA_GUARD_DISABLED === '1')
|
|
16
|
-
return null;
|
|
17
|
-
const start = Date.now();
|
|
18
|
-
try {
|
|
19
|
-
const res = await Promise.race([
|
|
20
|
-
fetch(endpoint, {
|
|
21
|
-
method: 'POST',
|
|
22
|
-
headers: {
|
|
23
|
-
'content-type': 'application/json',
|
|
24
|
-
'x-pinta-relay-token': process.env.PINTA_RELAY_TOKEN ?? '',
|
|
25
|
-
},
|
|
26
|
-
body: JSON.stringify({ input }),
|
|
27
|
-
}),
|
|
28
|
-
sleep(TIMEOUT_MS),
|
|
29
|
-
]);
|
|
30
|
-
if (res.status !== 200) {
|
|
31
|
-
return { decision: 'ALLOW', reason: null, durationMs: Date.now() - start, failOpenReason: 'error' };
|
|
32
|
-
}
|
|
33
|
-
const body = (await res.json());
|
|
34
|
-
return { decision: body.decision, reason: body.reason, durationMs: body.durationMs ?? (Date.now() - start) };
|
|
35
|
-
}
|
|
36
|
-
catch (err) {
|
|
37
|
-
const reason = err.name === 'TimeoutError' ? 'timeout' : 'error';
|
|
38
|
-
return { decision: 'ALLOW', reason: null, durationMs: Date.now() - start, failOpenReason: reason };
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
//# sourceMappingURL=guard.js.map
|
package/dist/core/guard.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"guard.js","sourceRoot":"","sources":["../../src/core/guard.ts"],"names":[],"mappings":";;AA0BA,sCA4BC;AAxCD,MAAM,UAAU,GAAG,EAAE,CAAC;AAEtB,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAC/B,UAAU,CAAC,GAAG,EAAE;QACd,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QACjD,GAAG,CAAC,IAAI,GAAG,cAAc,CAAC;QAC1B,MAAM,CAAC,GAAG,CAAC,CAAC;IACd,CAAC,EAAE,EAAE,CAAC,CACP,CAAC;AACJ,CAAC;AAEM,KAAK,UAAU,aAAa,CACjC,KAAiB,EACjB,QAA4B;IAE5B,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3B,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IAC1D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC;YAC7B,KAAK,CAAC,QAAQ,EAAE;gBACd,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;oBAClC,qBAAqB,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE;iBAC3D;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC;aAChC,CAAC;YACF,KAAK,CAAC,UAAU,CAAC;SAClB,CAAC,CAAC;QACH,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACvB,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC;QACtG,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAsF,CAAC;QACrH,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,EAAE,CAAC;IAC/G,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GAAmC,GAAa,CAAC,IAAI,KAAK,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;QAC3G,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC;IACrG,CAAC;AACH,CAAC"}
|
package/dist/core/identity.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/core/identity.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/core/identity.ts"],"names":[],"mappings":""}
|
package/dist/core/otlp.d.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import type { BaseEvent } from "./types.js";
|
|
2
|
-
import type { GuardResult } from "./guard.js";
|
|
3
|
-
export interface OtlpAttribute {
|
|
4
|
-
key: string;
|
|
5
|
-
value: {
|
|
6
|
-
stringValue: string;
|
|
7
|
-
} | {
|
|
8
|
-
intValue: number;
|
|
9
|
-
} | {
|
|
10
|
-
doubleValue: number;
|
|
11
|
-
} | {
|
|
12
|
-
boolValue: boolean;
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
export interface OtlpSpan {
|
|
16
|
-
traceId: string;
|
|
17
|
-
spanId: string;
|
|
18
|
-
name: string;
|
|
19
|
-
kind: number;
|
|
20
|
-
startTimeUnixNano: string;
|
|
21
|
-
endTimeUnixNano: string;
|
|
22
|
-
attributes: OtlpAttribute[];
|
|
23
|
-
}
|
|
24
|
-
export interface ResourceSpans {
|
|
25
|
-
resource: {
|
|
26
|
-
attributes: OtlpAttribute[];
|
|
27
|
-
};
|
|
28
|
-
scopeSpans: Array<{
|
|
29
|
-
scope: {
|
|
30
|
-
name: string;
|
|
31
|
-
version: string;
|
|
32
|
-
};
|
|
33
|
-
spans: OtlpSpan[];
|
|
34
|
-
}>;
|
|
35
|
-
}
|
|
36
|
-
export interface OtlpPayload {
|
|
37
|
-
resourceSpans: ResourceSpans[];
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Convert a 26-char Crockford ULID into 32 lowercase hex chars (16 bytes)
|
|
41
|
-
* suitable for an OTLP traceId. Decoding is straightforward because each
|
|
42
|
-
* Crockford char carries 5 bits and 26 chars = 130 bits; we keep the low
|
|
43
|
-
* 128 bits (the spec already pads timestamp+randomness into 128 bits).
|
|
44
|
-
*/
|
|
45
|
-
export declare function ulidToTraceId(ulid: string): string;
|
|
46
|
-
/** Generate a fresh 16-hex-char (8-byte) span ID. */
|
|
47
|
-
export declare function newSpanId(): string;
|
|
48
|
-
export declare function buildOtlpPayload(args: {
|
|
49
|
-
event: BaseEvent;
|
|
50
|
-
traceId: string;
|
|
51
|
-
now?: number;
|
|
52
|
-
guard?: GuardResult | null;
|
|
53
|
-
}): OtlpPayload;
|
|
54
|
-
/**
|
|
55
|
-
* Combine multiple per-hook payloads into a single OTLP payload by
|
|
56
|
-
* concatenating their resourceSpans arrays. The Pinta backend's parser
|
|
57
|
-
* iterates over resourceSpans natively.
|
|
58
|
-
*/
|
|
59
|
-
export declare function mergeBatch(payloads: OtlpPayload[]): OtlpPayload;
|