@pinta-ai/pinta-copilot 0.3.1 → 0.5.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.
Files changed (45) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/dist/index.js +14 -71
  3. package/dist/index.mjs +15 -0
  4. package/dist/tools/doctor.js +4 -81
  5. package/dist/tools/install-hooks.js +3 -101
  6. package/package.json +17 -2
  7. package/dist/core/config.d.ts +0 -15
  8. package/dist/core/config.js +0 -19
  9. package/dist/core/config.js.map +0 -1
  10. package/dist/core/env-bridge.d.ts +0 -25
  11. package/dist/core/env-bridge.js +0 -43
  12. package/dist/core/env-bridge.js.map +0 -1
  13. package/dist/core/guard.d.ts +0 -14
  14. package/dist/core/guard.js +0 -53
  15. package/dist/core/guard.js.map +0 -1
  16. package/dist/core/otlp.d.ts +0 -55
  17. package/dist/core/otlp.js +0 -184
  18. package/dist/core/otlp.js.map +0 -1
  19. package/dist/core/redact.d.ts +0 -57
  20. package/dist/core/redact.js +0 -149
  21. package/dist/core/redact.js.map +0 -1
  22. package/dist/core/retry-queue.d.ts +0 -26
  23. package/dist/core/retry-queue.js +0 -127
  24. package/dist/core/retry-queue.js.map +0 -1
  25. package/dist/core/surface.d.ts +0 -21
  26. package/dist/core/surface.js +0 -13
  27. package/dist/core/surface.js.map +0 -1
  28. package/dist/core/trace.d.ts +0 -20
  29. package/dist/core/trace.js +0 -80
  30. package/dist/core/trace.js.map +0 -1
  31. package/dist/core/transport.d.ts +0 -18
  32. package/dist/core/transport.js +0 -127
  33. package/dist/core/transport.js.map +0 -1
  34. package/dist/core/types.d.ts +0 -49
  35. package/dist/core/types.js +0 -124
  36. package/dist/core/types.js.map +0 -1
  37. package/dist/env-file.d.ts +0 -4
  38. package/dist/env-file.js +0 -69
  39. package/dist/env-file.js.map +0 -1
  40. package/dist/index.d.ts +0 -1
  41. package/dist/index.js.map +0 -1
  42. package/dist/tools/doctor.d.ts +0 -1
  43. package/dist/tools/doctor.js.map +0 -1
  44. package/dist/tools/install-hooks.d.ts +0 -1
  45. package/dist/tools/install-hooks.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,50 @@
2
2
 
3
3
  All notable changes to pinta-copilot are documented here.
4
4
 
5
+ ## [0.4.0] - 2026-07-12
6
+
7
+ ### Changed
8
+
9
+ - **Shared core extraction.** The duplicated low-level utilities (otlp,
10
+ transport, retry-queue, redact, guard, session trace) now come from the
11
+ private `@pinta-ai/core` package; `src/core/*.ts` keeps only thin bindings
12
+ plus the copilot-specific bits (event flattening, surface detection, the
13
+ `envFilePath` override). Core is a devDependency, bundled into `dist/` by
14
+ esbuild at build time, so npmjs consumers never need private-registry access
15
+ and there is no runtime dependency on it.
16
+ - `@pinta-ai/core` bumped `^0.2.0` → `^0.3.0`. The upgrade is additive; no
17
+ adaptor source change was needed.
18
+
19
+ ### Added
20
+
21
+ - `pinta.client.rtt_ms` / `pinta.client.op` span attributes on guarded spans.
22
+ `buildOtlpPayload` already forwards its `guard` result into core's
23
+ `buildPayload`, and core `0.3.0` derives the client-call timing from the
24
+ `GuardResult.clientRttMs` it now measures. The manager can only time its own
25
+ handler, so `clientRttMs - durationMs` gives it the transport overhead.
26
+
27
+ ### Fixed
28
+
29
+ - `package-lock.json` resolved `@pinta-ai/core` as a local link to
30
+ `../pinta-core` while `package.json` declared a version range. `npm ci` did
31
+ not error on the mismatch — it created a dangling symlink to a dev-machine-only
32
+ path and the build then failed `TS2307: Cannot find module '@pinta-ai/core'`,
33
+ breaking pr-validate, build-dist and publish. The lock now pins core's
34
+ GitHub Packages tarball with its integrity hash.
35
+ - `npm publish` would have failed `ENEEDAUTH`: the committed `.npmrc` pointed
36
+ npmjs auth at `${NPM_TOKEN}`, but no such secret exists, so it expanded to an
37
+ empty token instead of falling through to OIDC trusted publishing. The npmjs
38
+ `_authToken` line is gone and `setup-node`'s `registry-url` is back;
39
+ `NODE_AUTH_TOKEN` is now scoped to the `npm ci` step so it is not sent to
40
+ npmjs during publish.
41
+ - `npm` pinned to `11.18.0` in the publish workflow. `npm@latest` is now 12.x,
42
+ which requires node >=22.22 and aborts the node-20 publish job with
43
+ `EBADENGINE`.
44
+ - `tests/core/guard.test.ts` asserted the core `0.2.0` `GuardResult` shape with
45
+ an exhaustive `toEqual` and broke once `clientRttMs` was added. It now matches
46
+ that field by type, since it is a measured wall-clock rather than a value
47
+ echoed from the response body.
48
+
5
49
  ## [0.2.0] - 2026-06-16
6
50
 
7
51
  ### Changed
package/dist/index.js CHANGED
@@ -1,71 +1,14 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- // Load ~/.copilot/pinta-copilot.env BEFORE any other import that may read
4
- // process.env. loadEnvFile only fills in unset keys, so explicit env / hook
5
- // `env` blocks always win (D5).
6
- const env_file_js_1 = require("./env-file.js");
7
- (0, env_file_js_1.loadEnvFile)();
8
- const config_js_1 = require("./core/config.js");
9
- const surface_js_1 = require("./core/surface.js");
10
- const types_js_1 = require("./core/types.js");
11
- const transport_js_1 = require("./core/transport.js");
12
- const trace_js_1 = require("./core/trace.js");
13
- const otlp_js_1 = require("./core/otlp.js");
14
- const guard_js_1 = require("./core/guard.js");
15
- async function readStdin() {
16
- const chunks = [];
17
- for await (const chunk of process.stdin)
18
- chunks.push(chunk);
19
- return Buffer.concat(chunks).toString("utf-8");
20
- }
21
- async function main() {
22
- // ⚠️ CLI preToolUse hooks are FAIL-CLOSED: a non-zero exit / crash / timeout
23
- // DENIES the tool — and a crashing hook bricks the whole agent (report_intent
24
- // / ask_user get blocked too, verified §9.6). Therefore this process MUST
25
- // exit 0 on every path. All work is wrapped; the catch-all stays exit 0.
26
- try {
27
- const config = (0, config_js_1.loadConfig)();
28
- const surface = (0, surface_js_1.detectSurface)();
29
- const raw = await readStdin();
30
- const event = JSON.parse(raw);
31
- const kind = (0, types_js_1.classify)(event);
32
- const sid = (0, types_js_1.sessionId)(event);
33
- const transport = new transport_js_1.Transport(config);
34
- await transport.flush(); // drain retry queue first
35
- const trace = new trace_js_1.TraceManager(config);
36
- // UserPromptSubmit starts a new per-turn trace; everything else reuses it.
37
- const traceId = kind === "UserPromptSubmit" ? trace.newTrace(sid) : trace.currentTrace(sid);
38
- // Guard runs on the two tool-gating events (PreToolUse: all surfaces;
39
- // PermissionRequest: CLI-only). Internal agent tools (report_intent,
40
- // ask_user) are telemetry-only — never guarded (would brick the turn).
41
- const toolNm = (0, types_js_1.toolName)(event);
42
- let guard = null;
43
- if ((0, types_js_1.isGuardEvent)(kind) && !(0, types_js_1.isInternalTool)(toolNm)) {
44
- const ti = (0, types_js_1.toolInput)(event);
45
- guard = await (0, guard_js_1.evaluateGuard)({
46
- spanId: sid ?? "unknown",
47
- toolName: toolNm,
48
- toolInput: ti,
49
- rawTextFields: {
50
- toolInput: typeof ti === "string" ? ti : JSON.stringify(ti ?? null),
51
- },
52
- }, process.env.PINTA_GUARD_ENDPOINT);
53
- }
54
- // Telemetry: one span per event (Bronze flattening, copilot.* prefix).
55
- const payload = (0, otlp_js_1.buildOtlpPayload)({ event, traceId, surface, guard });
56
- await transport.send(payload);
57
- // Enforcement: emit a deny decision in the format the firing event expects.
58
- if (guard?.decision === "DENY") {
59
- const out = (0, types_js_1.formatDeny)(kind, guard.userMessage ?? guard.reason ?? "guard_deny");
60
- if (out)
61
- process.stdout.write(out + "\n");
62
- }
63
- }
64
- catch (err) {
65
- process.stderr.write(`[pinta-copilot] error: ${err}\n`);
66
- // fail-open by design — never block a tool because the adapter crashed.
67
- }
68
- process.exit(0);
69
- }
70
- main();
71
- //# sourceMappingURL=index.js.map
1
+ "use strict";var Qe=Object.create;var se=Object.defineProperty;var We=Object.getOwnPropertyDescriptor;var et=Object.getOwnPropertyNames;var tt=Object.getPrototypeOf,rt=Object.prototype.hasOwnProperty;var f=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var nt=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of et(t))!rt.call(e,o)&&o!==r&&se(e,o,{get:()=>t[o],enumerable:!(n=We(t,o))||n.enumerable});return e};var _=(e,t,r)=>(r=e!=null?Qe(tt(e)):{},nt(t||!e||!e.__esModule?se(r,"default",{value:e,enumerable:!0}):r,e));var G=f(c=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});c.PATTERNS=c.MAX_BYTES=void 0;c.truncate=ot;c.collectMatches=ie;c.resolveOverlaps=ae;c.applyMatches=ue;c.redact=st;c.MAX_BYTES=102400;function ot(e){let t=Buffer.from(e,"utf-8");return t.length<=c.MAX_BYTES?e:`${t.subarray(0,c.MAX_BYTES).toString("utf-8")}\u2026[TRUNCATED:${t.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 ie(e,t){let r=[];for(let n of c.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 R=i.index,I=i.index+i[0].length,h=R+i[0].indexOf(u),U=h+u.length;r.push({start:R,end:I,replaceStart:h,replaceEnd:U,type:n.type}),i.index===o.lastIndex&&o.lastIndex++}}return r}function ae(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 ue(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 st(e,t={}){if(e.length===0)return e;let r=ie(e,t);if(r.length===0)return e;let n=ae(r);return ue(e,n)}});var V=f(p=>{"use strict";var it=p&&p.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(p,"__esModule",{value:!0});p.ulidToTraceId=pe;p.newSpanId=fe;p.snakeCase=ct;p.toOtlpValue=de;p.attrsFromRecord=lt;p.guardAttrs=ge;p.clientAttrs=he;p.buildPayload=pt;p.mergeBatch=ft;var at=it(require("crypto")),ce=G(),ut="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=ut.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 fe(){return at.default.randomBytes(8).toString("hex")}function ct(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1_$2").replace(/([A-Z])([A-Z][a-z])/g,"$1_$2").toLowerCase()}var le=new Set;function x(e,t,r){let n=(0,ce.truncate)(t);if((r.skipRedactKeys??le).has(e))return n;let o=(r.bashContextKeys??le).has(e)?"bash":void 0;return(0,ce.redact)(n,{context:o})}function de(e,t,r={}){if(t==null)return null;switch(typeof t){case"string":return{stringValue:x(e,t,r)};case"boolean":return{boolValue:t};case"number":return Number.isInteger(t)?{intValue:t}:{doubleValue:t};case"object":try{return{stringValue:x(e,JSON.stringify(t),r)}}catch{return{stringValue:x(e,String(t),r)}}default:return{stringValue:x(e,String(t),r)}}}function lt(e,t,r={}){let n=[];for(let[o,i]of Object.entries(e)){let a=`${t}.${o}`,u=de(a,i,r);u!==null&&n.push({key:a,value:u})}return n}function ge(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 he(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}}]}function pt(e){let t=e.now??Date.now(),r=(BigInt(t)*1000000n).toString(),n=[...e.attributes];e.guard&&n.push(...ge(e.guard));let o=e.clientTiming??(e.guard?.clientRttMs!==void 0?{op:"guard",rttMs:e.guard.clientRttMs}:null);o&&n.push(...he(o));let i={traceId:pe(e.traceId),spanId:fe(),name:e.spanName,kind:e.spanKind??1,startTimeUnixNano:r,endTimeUnixNano:r,attributes:n};return{resourceSpans:[{resource:{attributes:e.resource},scopeSpans:[{scope:e.scope,spans:[i]}]}]}}function ft(e){let t=[];for(let r of e)t.push(...r.resourceSpans);return{resourceSpans:t}}});var ye=f($=>{"use strict";Object.defineProperty($,"__esModule",{value:!0});$.evaluateGuard=_t;var dt=1e4,gt="pinta-core";function _e(e,t){return{decision:"ALLOW",reason:null,userMessage:null,durationMs:e,clientRttMs:e,failOpenReason:t}}function ht(e){return new Promise((t,r)=>setTimeout(()=>{let n=new Error("Guard request timed out");n.name="TimeoutError",r(n)},e))}async function _t(e,t,r={}){if(!t||r.disabled)return null;let n=r.timeoutMs??dt,o=Date.now();try{let i=await Promise.race([fetch(t,{method:"POST",headers:{"content-type":"application/json","user-agent":r.userAgent??gt,"x-pinta-relay-token":r.token??""},body:JSON.stringify({input:e})}),ht(n)]);if(i.status!==200)return _e(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 _e(Date.now()-o,a)}}});var Z=f(y=>{"use strict";var me=y&&y.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(y,"__esModule",{value:!0});y.MemoryRetryQueue=y.DiskRetryQueue=void 0;var l=me(require("fs")),M=me(require("path")),N=1e3,yt=50,mt=5,K=class{filePath;lockPath;logPrefix;constructor(t,r){this.filePath=M.default.join(t,"failed-spans.jsonl"),this.lockPath=this.filePath+".lock",this.logPrefix=r}enqueue(t){try{l.default.mkdirSync(M.default.dirname(this.filePath),{recursive:!0});let r=JSON.stringify({savedAt:new Date().toISOString(),payload:t})+`
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 t=l.default.readFileSync(this.filePath,"utf-8"),r=[];for(let n of t.split(`
4
+ `))if(n.trim())try{r.push(JSON.parse(n))}catch{}return r}catch{return[]}}rewrite(t){try{if(t.length===0){l.default.existsSync(this.filePath)&&l.default.unlinkSync(this.filePath);return}l.default.mkdirSync(M.default.dirname(this.filePath),{recursive:!0}),l.default.writeFileSync(this.filePath,t.map(r=>JSON.stringify(r)).join(`
5
+ `)+`
6
+ `)}catch(r){process.stderr.write(`[${this.logPrefix}] retry-queue rewrite failed: ${r}
7
+ `)}}tryAcquireLock(){let t=Date.now();for(l.default.mkdirSync(M.default.dirname(this.lockPath),{recursive:!0});Date.now()-t<yt;)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=mt,o=Date.now()+n;for(;Date.now()<o;);}return!1}release(){try{l.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
9
+ `),this.rewrite(t.slice(r))}};y.DiskRetryQueue=K;var B=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}};y.MemoryRetryQueue=B});var ve=f(d=>{"use strict";Object.defineProperty(d,"__esModule",{value:!0});d.MemoryTransport=d.DiskTransport=void 0;d.parseHeadersEnv=Te;d.envOptionsResolver=Se;d.postOtlp=k;var Pe=Z(),Oe=V(),Pt=5e3;function Te(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 Se(){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:Te(process.env.OTEL_EXPORTER_OTLP_HEADERS)}:null}async function k(e,t,r){let n=new AbortController,o=setTimeout(()=>n.abort(),Pt);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}`:""}
10
+ `),!1}return!0}catch(i){return process.stderr.write(`[${r}] OTLP POST failed: ${i.message??String(i)}
11
+ `),!1}finally{clearTimeout(o)}}var X=class{queue;logPrefix;resolveOptions;constructor(t){this.queue=new Pe.DiskRetryQueue(t.pluginData,t.logPrefix),this.logPrefix=t.logPrefix,this.resolveOptions=t.resolveOptions??Se}async send(t){let r=this.resolveOptions();if(!r)return;await k(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 n=(0,Oe.mergeBatch)(r.map(i=>i.payload));await k(n,t,this.logPrefix)&&this.queue.rewrite([])}finally{this.queue.release()}}};d.DiskTransport=X;var J=class{queue=new Pe.MemoryRetryQueue;logPrefix;resolveOptions;constructor(t){this.logPrefix=t.logPrefix,this.resolveOptions=t.resolveOptions}async send(t){let r=this.resolveOptions();if(!r)return;await k(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 n=(0,Oe.mergeBatch)(r);if(!await k(n,t,this.logPrefix))for(let i of r)this.queue.enqueue(i)}};d.MemoryTransport=J});var W=f(O=>{"use strict";var Q=O&&O.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(O,"__esModule",{value:!0});O.TraceManager=void 0;O.generateUlid=Ee;var Y=Q(require("fs")),Ot=Q(require("path")),Tt=Q(require("crypto")),H="0123456789ABCDEFGHJKMNPQRSTVWXYZ";function Ee(){let e=Date.now(),t="",r=e;for(let i=0;i<10;i++)t=H[r&31]+t,r=Math.floor(r/32);let n=Tt.default.randomBytes(10),o="";for(let i=0;i<10;i++)o+=H[n[i]&31];for(;o.length<16;)o+=H[0];return t+o}var z=class{tracePath;constructor(t){this.tracePath=t}newTrace(){let t=Ee();return this.save(t),t}currentTrace(){try{let t=Y.default.readFileSync(this.tracePath,"utf-8"),{traceId:r}=JSON.parse(t);if(r)return r}catch{}return this.newTrace()}save(t){Y.default.mkdirSync(Ot.default.dirname(this.tracePath),{recursive:!0}),Y.default.writeFileSync(this.tracePath,JSON.stringify({traceId:t}))}};O.TraceManager=z});var Ae=f(m=>{"use strict";var be=m&&m.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(m,"__esModule",{value:!0});m.MemorySessionTraceManager=m.DiskSessionTraceManager=void 0;var ee=be(require("fs")),St=be(require("path")),ke=W(),we=200,te=class{tracePath;maxSessions;constructor(t,r={}){this.tracePath=t,this.maxSessions=r.maxSessions??we}read(){try{let t=JSON.parse(ee.default.readFileSync(this.tracePath,"utf-8"));if(t&&typeof t=="object"&&!("traceId"in t))return t}catch{}return{}}write(t){try{ee.default.mkdirSync(St.default.dirname(this.tracePath),{recursive:!0});let r=Object.entries(t),n=r.length>this.maxSessions?Object.fromEntries(r.slice(-this.maxSessions)):t;ee.default.writeFileSync(this.tracePath,JSON.stringify(n))}catch{}}newTrace(t){let r=t||"default",n=(0,ke.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)}};m.DiskSessionTraceManager=te;var re=class{map=new Map;maxSessions;constructor(t={}){this.maxSessions=t.maxSessions??we}newTrace(t){let r=t||"default",n=(0,ke.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)}};m.MemorySessionTraceManager=re});var xe=f(T=>{"use strict";var ne=T&&T.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(T,"__esModule",{value:!0});T.envFilePath=bt;T.parseEnvFile=Ie;T.loadEnvFile=kt;var vt=ne(require("node:fs")),Et=ne(require("node:os")),Re=ne(require("node:path"));function bt(e,t,r){let n=r?process.env[r]:void 0,o=n&&n.length>0?n:Re.default.join(Et.default.homedir(),e);return Re.default.join(o,t)}function Ie(e){let t={};for(let r of e.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&&(t[i]=a)}return t}function kt(e){let t;try{t=vt.default.readFileSync(e,"utf-8")}catch{return}let r=Ie(t);for(let[n,o]of Object.entries(r))process.env[n]===void 0&&(process.env[n]=o)}});var b=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 S=G();Object.defineProperty(s,"redact",{enumerable:!0,get:function(){return S.redact}});Object.defineProperty(s,"truncate",{enumerable:!0,get:function(){return S.truncate}});Object.defineProperty(s,"collectMatches",{enumerable:!0,get:function(){return S.collectMatches}});Object.defineProperty(s,"resolveOverlaps",{enumerable:!0,get:function(){return S.resolveOverlaps}});Object.defineProperty(s,"applyMatches",{enumerable:!0,get:function(){return S.applyMatches}});Object.defineProperty(s,"PATTERNS",{enumerable:!0,get:function(){return S.PATTERNS}});Object.defineProperty(s,"MAX_BYTES",{enumerable:!0,get:function(){return S.MAX_BYTES}});var g=V();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 wt=ye();Object.defineProperty(s,"evaluateGuard",{enumerable:!0,get:function(){return wt.evaluateGuard}});var Me=Z();Object.defineProperty(s,"DiskRetryQueue",{enumerable:!0,get:function(){return Me.DiskRetryQueue}});Object.defineProperty(s,"MemoryRetryQueue",{enumerable:!0,get:function(){return Me.MemoryRetryQueue}});var w=ve();Object.defineProperty(s,"DiskTransport",{enumerable:!0,get:function(){return w.DiskTransport}});Object.defineProperty(s,"MemoryTransport",{enumerable:!0,get:function(){return w.MemoryTransport}});Object.defineProperty(s,"postOtlp",{enumerable:!0,get:function(){return w.postOtlp}});Object.defineProperty(s,"envOptionsResolver",{enumerable:!0,get:function(){return w.envOptionsResolver}});Object.defineProperty(s,"parseHeadersEnv",{enumerable:!0,get:function(){return w.parseHeadersEnv}});var Ne=W();Object.defineProperty(s,"TraceManager",{enumerable:!0,get:function(){return Ne.TraceManager}});Object.defineProperty(s,"generateUlid",{enumerable:!0,get:function(){return Ne.generateUlid}});var De=Ae();Object.defineProperty(s,"DiskSessionTraceManager",{enumerable:!0,get:function(){return De.DiskSessionTraceManager}});Object.defineProperty(s,"MemorySessionTraceManager",{enumerable:!0,get:function(){return De.MemorySessionTraceManager}});var oe=xe();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 A=_(b());function At(){return(0,A.envFilePath)(".copilot","pinta-copilot.env","COPILOT_HOME")}function je(e=At()){(0,A.loadEnvFile)(e)}var Ce=_(require("os")),D=_(require("path"));function Rt(){return process.env.COPILOT_HOME||D.default.join(Ce.default.homedir(),".copilot")}function qe(){let e=process.env.COPILOT_PLUGIN_DATA||D.default.join(Rt(),"pinta-copilot-data");return{pluginData:e,tracePath:D.default.join(e,"trace.json")}}function Le(e=process.env){return e.COPILOT_AGENT_JOB_ID||e.COPILOT_AGENT_SESSION_ID||e.COPILOT_AGENT_PROMPT?"cloud":e.ELECTRON_RUN_AS_NODE||e.VSCODE_IPC_HOOK||e.VSCODE_PID?"ext":"cli"}function v(e){return typeof e=="string"?e:void 0}function j(e){return v(e.hook_event_name)??v(e.hookEventName)??v(e.hookName)??(process.env.PINTA_COPILOT_EVENT||void 0)}function Fe(e){return v(e.session_id)??v(e.sessionId)}function Ue(e){return v(e.tool_name)??v(e.toolName)}function Ge(e){return e.tool_input??e.toolArgs??e.toolInput}var It={sessionstart:"SessionStart",sessionend:"SessionEnd",userpromptsubmit:"UserPromptSubmit",userpromptsubmitted:"UserPromptSubmit",pretooluse:"PreToolUse",posttooluse:"PostToolUse",posttoolusefailure:"PostToolUseFailure",stop:"Stop",agentstop:"Stop",subagentstart:"SubagentStart",subagentstop:"SubagentStop",precompact:"PreCompact",notification:"Notification",permissionrequest:"PermissionRequest",erroroccurred:"ErrorOccurred"};function Ve(e){let t=j(e);return t?It[t.toLowerCase()]??"Unknown":"Unknown"}function $e(e){return e==="PreToolUse"||e==="PermissionRequest"}var xt=new Set(["report_intent","ask_user"]);function Ke(e){return e!==void 0&&xt.has(e)}function Be(e,t){return e==="PreToolUse"?JSON.stringify({hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:t}}):e==="PermissionRequest"?JSON.stringify({behavior:"deny",message:t}):null}var q=_(b());function Mt(){let e=process.env.COPILOT_PLUGIN_OPTION_ENDPOINT||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:(0,q.parseHeadersEnv)(process.env.COPILOT_PLUGIN_OPTION_HEADERS||process.env.OTEL_EXPORTER_OTLP_HEADERS)}:null}var C=class extends q.DiskTransport{constructor(t){super({pluginData:t.pluginData,logPrefix:"pinta-copilot",resolveOptions:Mt})}};var Ze=_(b()),L=class extends Ze.DiskSessionTraceManager{constructor(t){super(t.tracePath)}};var F=_(require("os")),E=_(b());var Xe="0.5.0";function Nt(){return process.env.COPILOT_CLI_VERSION||"unknown"}var Dt=new Set(["copilot.hook","copilot.tool_name","copilot.toolName","copilot.tool_use_id","copilot.toolUseId","copilot.session_id","copilot.sessionId","copilot.transcript_path","copilot.transcriptPath","copilot.cwd","copilot.permission_mode","copilot.surface","copilot.agent_id","copilot.agent_type","copilot.agent_name","copilot.agent_display_name","copilot.stop_reason","copilot.notification_type"]),jt=new Set(["copilot.tool_input","copilot.toolInput","copilot.tool_response","copilot.tool_result"]),Ct={skipRedactKeys:Dt,bashContextKeys:jt},qt=new Set(["hook_event_name","hookEventName","hookName"]);function Lt(e,t){let r=Object.fromEntries(Object.entries(e).filter(([n])=>!qt.has(n)));return[{key:"ingest.type",value:{stringValue:"copilot"}},{key:"copilot.hook",value:{stringValue:j(e)??"unknown"}},{key:"copilot.surface",value:{stringValue:t}},...(0,E.attrsFromRecord)(r,"copilot",Ct)]}function Ft(){return[{key:"service.name",value:{stringValue:"copilot"}},{key:"service.version",value:{stringValue:Nt()}},{key:"telemetry.sdk.name",value:{stringValue:"pinta-copilot"}},{key:"telemetry.sdk.language",value:{stringValue:"nodejs"}},{key:"telemetry.sdk.version",value:{stringValue:Xe}},{key:"process.pid",value:{intValue:process.pid}},{key:"process.owner",value:{stringValue:F.default.userInfo().username}},{key:"host.name",value:{stringValue:F.default.hostname()}},{key:"host.arch",value:{stringValue:F.default.arch()}}]}function Je(e){return(0,E.buildPayload)({traceId:e.traceId,spanName:`copilot.${(0,E.snakeCase)(j(e.event)??"unknown")}`,attributes:Lt(e.event,e.surface),resource:Ft(),scope:{name:"pinta-copilot",version:Xe},now:e.now,guard:e.guard})}var Ye=_(b());function Ut(){return Number(process.env.PINTA_GUARD_TIMEOUT_MS)||50}var Gt="pinta-copilot/0.5.0";function He(e,t){return(0,Ye.evaluateGuard)(e,t,{timeoutMs:Ut(),token:process.env.PINTA_RELAY_TOKEN??"",disabled:process.env.PINTA_GUARD_DISABLED==="1",userAgent:Gt})}async function Vt(){let e=[];for await(let t of process.stdin)e.push(t);return Buffer.concat(e).toString("utf-8")}async function ze(){try{let e=qe(),t=Le(),r=await Vt(),n=JSON.parse(r),o=Ve(n),i=Fe(n),a=new C(e);await a.flush();let u=new L(e),R=o==="UserPromptSubmit"?u.newTrace(i):u.currentTrace(i),I=Ue(n),h=null;if($e(o)&&!Ke(I)){let P=Ge(n);h=await He({spanId:i??"unknown",toolName:I,toolInput:P,rawTextFields:{toolInput:typeof P=="string"?P:JSON.stringify(P??null)}},process.env.PINTA_GUARD_ENDPOINT)}let U=Je({event:n,traceId:R,surface:t,guard:h});if(await a.send(U),h?.decision==="DENY"){let P=Be(o,h.userMessage??h.reason??"guard_deny");P&&process.stdout.write(P+`
13
+ `)}}catch(e){process.stderr.write(`[pinta-copilot] error: ${e}
14
+ `)}return 0}je();async function $t(){let e=await ze();process.exit(e)}$t();
package/dist/index.mjs ADDED
@@ -0,0 +1,15 @@
1
+ import{createRequire as __pintaCreateRequire}from 'node:module';const require=__pintaCreateRequire(import.meta.url);
2
+ var dt=Object.create;var fe=Object.defineProperty;var mt=Object.getOwnPropertyDescriptor;var gt=Object.getOwnPropertyNames;var ht=Object.getPrototypeOf,yt=Object.prototype.hasOwnProperty;var d=(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 m=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var _t=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of gt(t))!yt.call(e,o)&&o!==r&&fe(e,o,{get:()=>t[o],enumerable:!(n=mt(t,o))||n.enumerable});return e};var I=(e,t,r)=>(r=e!=null?dt(ht(e)):{},_t(t||!e||!e.__esModule?fe(r,"default",{value:e,enumerable:!0}):r,e));var $=m(c=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});c.PATTERNS=c.MAX_BYTES=void 0;c.truncate=Pt;c.collectMatches=de;c.resolveOverlaps=me;c.applyMatches=ge;c.redact=St;c.MAX_BYTES=102400;function Pt(e){let t=Buffer.from(e,"utf-8");return t.length<=c.MAX_BYTES?e:`${t.subarray(0,c.MAX_BYTES).toString("utf-8")}\u2026[TRUNCATED:${t.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 de(e,t){let r=[];for(let n of c.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 p=s.index,b=s.index+s[0].length,y=p+s[0].indexOf(u),U=y+u.length;r.push({start:p,end:b,replaceStart:y,replaceEnd:U,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 ge(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 St(e,t={}){if(e.length===0)return e;let r=de(e,t);if(r.length===0)return e;let n=me(r);return ge(e,n)}});var G=m(f=>{"use strict";var Ot=f&&f.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(f,"__esModule",{value:!0});f.ulidToTraceId=_e;f.newSpanId=Pe;f.snakeCase=Et;f.toOtlpValue=Se;f.attrsFromRecord=wt;f.guardAttrs=Oe;f.clientAttrs=Te;f.buildPayload=bt;f.mergeBatch=kt;var Tt=Ot(d("crypto")),he=$(),vt="0123456789ABCDEFGHJKMNPQRSTVWXYZ";function _e(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 Pe(){return Tt.default.randomBytes(8).toString("hex")}function Et(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1_$2").replace(/([A-Z])([A-Z][a-z])/g,"$1_$2").toLowerCase()}var ye=new Set;function M(e,t,r){let n=(0,he.truncate)(t);if((r.skipRedactKeys??ye).has(e))return n;let o=(r.bashContextKeys??ye).has(e)?"bash":void 0;return(0,he.redact)(n,{context:o})}function Se(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 wt(e,t,r={}){let n=[];for(let[o,s]of Object.entries(e)){let a=`${t}.${o}`,u=Se(a,s,r);u!==null&&n.push({key:a,value:u})}return n}function Oe(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 Te(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}}]}function bt(e){let t=e.now??Date.now(),r=(BigInt(t)*1000000n).toString(),n=[...e.attributes];e.guard&&n.push(...Oe(e.guard));let o=e.clientTiming??(e.guard?.clientRttMs!==void 0?{op:"guard",rttMs:e.guard.clientRttMs}:null);o&&n.push(...Te(o));let s={traceId:_e(e.traceId),spanId:Pe(),name:e.spanName,kind:e.spanKind??1,startTimeUnixNano:r,endTimeUnixNano:r,attributes:n};return{resourceSpans:[{resource:{attributes:e.resource},scopeSpans:[{scope:e.scope,spans:[s]}]}]}}function kt(e){let t=[];for(let r of e)t.push(...r.resourceSpans);return{resourceSpans:t}}});var Ee=m(V=>{"use strict";Object.defineProperty(V,"__esModule",{value:!0});V.evaluateGuard=At;var It=1e4,xt="pinta-core";function ve(e,t){return{decision:"ALLOW",reason:null,userMessage:null,durationMs:e,clientRttMs:e,failOpenReason:t}}function Rt(e){return new Promise((t,r)=>setTimeout(()=>{let n=new Error("Guard request timed out");n.name="TimeoutError",r(n)},e))}async function At(e,t,r={}){if(!t||r.disabled)return null;let n=r.timeoutMs??It,o=Date.now();try{let s=await Promise.race([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})}),Rt(n)]);if(s.status!==200)return ve(Date.now()-o,"error");let a=await s.json(),u=Date.now()-o;return{decision:a.decision,reason:a.reason,userMessage:a.userMessage??null,durationMs:a.durationMs??u,clientRttMs:u}}catch(s){let a=s.name==="TimeoutError"?"timeout":"error";return ve(Date.now()-o,a)}}});var Z=m(_=>{"use strict";var we=_&&_.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(_,"__esModule",{value:!0});_.MemoryRetryQueue=_.DiskRetryQueue=void 0;var l=we(d("fs")),D=we(d("path")),N=1e3,Mt=50,Dt=5,B=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{l.default.mkdirSync(D.default.dirname(this.filePath),{recursive:!0});let r=JSON.stringify({savedAt:new Date().toISOString(),payload:t})+`
3
+ `;l.default.appendFileSync(this.filePath,r),this.trim()}catch(r){process.stderr.write(`[${this.logPrefix}] retry-queue enqueue failed: ${r}
4
+ `)}}readAll(){try{let t=l.default.readFileSync(this.filePath,"utf-8"),r=[];for(let n of t.split(`
5
+ `))if(n.trim())try{r.push(JSON.parse(n))}catch{}return r}catch{return[]}}rewrite(t){try{if(t.length===0){l.default.existsSync(this.filePath)&&l.default.unlinkSync(this.filePath);return}l.default.mkdirSync(D.default.dirname(this.filePath),{recursive:!0}),l.default.writeFileSync(this.filePath,t.map(r=>JSON.stringify(r)).join(`
6
+ `)+`
7
+ `)}catch(r){process.stderr.write(`[${this.logPrefix}] retry-queue rewrite failed: ${r}
8
+ `)}}tryAcquireLock(){let t=Date.now();for(l.default.mkdirSync(D.default.dirname(this.lockPath),{recursive:!0});Date.now()-t<Mt;)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}
9
+ `),!1;try{let s=l.default.statSync(this.lockPath);if(Date.now()-s.mtimeMs>3e4){l.default.unlinkSync(this.lockPath);continue}}catch{}let n=Dt,o=Date.now()+n;for(;Date.now()<o;);}return!1}release(){try{l.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))}};_.DiskRetryQueue=B;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}};_.MemoryRetryQueue=K});var Re=m(g=>{"use strict";Object.defineProperty(g,"__esModule",{value:!0});g.MemoryTransport=g.DiskTransport=void 0;g.parseHeadersEnv=Ie;g.envOptionsResolver=xe;g.postOtlp=x;var be=Z(),ke=G(),Nt=5e3;function Ie(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 xe(){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:Ie(process.env.OTEL_EXPORTER_OTLP_HEADERS)}:null}async function x(e,t,r){let n=new AbortController,o=setTimeout(()=>n.abort(),Nt);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 X=class{queue;logPrefix;resolveOptions;constructor(t){this.queue=new be.DiskRetryQueue(t.pluginData,t.logPrefix),this.logPrefix=t.logPrefix,this.resolveOptions=t.resolveOptions??xe}async send(t){let r=this.resolveOptions();if(!r)return;await x(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 n=(0,ke.mergeBatch)(r.map(s=>s.payload));await x(n,t,this.logPrefix)&&this.queue.rewrite([])}finally{this.queue.release()}}};g.DiskTransport=X;var z=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;await x(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 n=(0,ke.mergeBatch)(r);if(!await x(n,t,this.logPrefix))for(let s of r)this.queue.enqueue(s)}};g.MemoryTransport=z});var W=m(O=>{"use strict";var Q=O&&O.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(O,"__esModule",{value:!0});O.TraceManager=void 0;O.generateUlid=Ae;var H=Q(d("fs")),jt=Q(d("path")),Ct=Q(d("crypto")),J="0123456789ABCDEFGHJKMNPQRSTVWXYZ";function Ae(){let e=Date.now(),t="",r=e;for(let s=0;s<10;s++)t=J[r&31]+t,r=Math.floor(r/32);let n=Ct.default.randomBytes(10),o="";for(let s=0;s<10;s++)o+=J[n[s]&31];for(;o.length<16;)o+=J[0];return t+o}var Y=class{tracePath;constructor(t){this.tracePath=t}newTrace(){let t=Ae();return this.save(t),t}currentTrace(){try{let t=H.default.readFileSync(this.tracePath,"utf-8"),{traceId:r}=JSON.parse(t);if(r)return r}catch{}return this.newTrace()}save(t){H.default.mkdirSync(jt.default.dirname(this.tracePath),{recursive:!0}),H.default.writeFileSync(this.tracePath,JSON.stringify({traceId:t}))}};O.TraceManager=Y});var je=m(P=>{"use strict";var Me=P&&P.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(P,"__esModule",{value:!0});P.MemorySessionTraceManager=P.DiskSessionTraceManager=void 0;var ee=Me(d("fs")),qt=Me(d("path")),De=W(),Ne=200,te=class{tracePath;maxSessions;constructor(t,r={}){this.tracePath=t,this.maxSessions=r.maxSessions??Ne}read(){try{let t=JSON.parse(ee.default.readFileSync(this.tracePath,"utf-8"));if(t&&typeof t=="object"&&!("traceId"in t))return t}catch{}return{}}write(t){try{ee.default.mkdirSync(qt.default.dirname(this.tracePath),{recursive:!0});let r=Object.entries(t),n=r.length>this.maxSessions?Object.fromEntries(r.slice(-this.maxSessions)):t;ee.default.writeFileSync(this.tracePath,JSON.stringify(n))}catch{}}newTrace(t){let r=t||"default",n=(0,De.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)}};P.DiskSessionTraceManager=te;var re=class{map=new Map;maxSessions;constructor(t={}){this.maxSessions=t.maxSessions??Ne}newTrace(t){let r=t||"default",n=(0,De.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)}};P.MemorySessionTraceManager=re});var Fe=m(T=>{"use strict";var ne=T&&T.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(T,"__esModule",{value:!0});T.envFilePath=Ut;T.parseEnvFile=qe;T.loadEnvFile=$t;var Ft=ne(d("node:fs")),Lt=ne(d("node:os")),Ce=ne(d("node:path"));function Ut(e,t,r){let n=r?process.env[r]:void 0,o=n&&n.length>0?n:Ce.default.join(Lt.default.homedir(),e);return Ce.default.join(o,t)}function qe(e){let t={};for(let r of e.split(`
13
+ `)){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 $t(e){let t;try{t=Ft.default.readFileSync(e,"utf-8")}catch{return}let r=qe(t);for(let[n,o]of Object.entries(r))process.env[n]===void 0&&(process.env[n]=o)}});var k=m(i=>{"use strict";Object.defineProperty(i,"__esModule",{value:!0});i.loadEnvFile=i.parseEnvFile=i.envFilePath=i.MemorySessionTraceManager=i.DiskSessionTraceManager=i.generateUlid=i.TraceManager=i.parseHeadersEnv=i.envOptionsResolver=i.postOtlp=i.MemoryTransport=i.DiskTransport=i.MemoryRetryQueue=i.DiskRetryQueue=i.evaluateGuard=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.truncate=i.redact=void 0;var v=$();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,"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 h=G();Object.defineProperty(i,"ulidToTraceId",{enumerable:!0,get:function(){return h.ulidToTraceId}});Object.defineProperty(i,"newSpanId",{enumerable:!0,get:function(){return h.newSpanId}});Object.defineProperty(i,"snakeCase",{enumerable:!0,get:function(){return h.snakeCase}});Object.defineProperty(i,"toOtlpValue",{enumerable:!0,get:function(){return h.toOtlpValue}});Object.defineProperty(i,"attrsFromRecord",{enumerable:!0,get:function(){return h.attrsFromRecord}});Object.defineProperty(i,"guardAttrs",{enumerable:!0,get:function(){return h.guardAttrs}});Object.defineProperty(i,"clientAttrs",{enumerable:!0,get:function(){return h.clientAttrs}});Object.defineProperty(i,"buildPayload",{enumerable:!0,get:function(){return h.buildPayload}});Object.defineProperty(i,"mergeBatch",{enumerable:!0,get:function(){return h.mergeBatch}});var Gt=Ee();Object.defineProperty(i,"evaluateGuard",{enumerable:!0,get:function(){return Gt.evaluateGuard}});var Le=Z();Object.defineProperty(i,"DiskRetryQueue",{enumerable:!0,get:function(){return Le.DiskRetryQueue}});Object.defineProperty(i,"MemoryRetryQueue",{enumerable:!0,get:function(){return Le.MemoryRetryQueue}});var R=Re();Object.defineProperty(i,"DiskTransport",{enumerable:!0,get:function(){return R.DiskTransport}});Object.defineProperty(i,"MemoryTransport",{enumerable:!0,get:function(){return R.MemoryTransport}});Object.defineProperty(i,"postOtlp",{enumerable:!0,get:function(){return R.postOtlp}});Object.defineProperty(i,"envOptionsResolver",{enumerable:!0,get:function(){return R.envOptionsResolver}});Object.defineProperty(i,"parseHeadersEnv",{enumerable:!0,get:function(){return R.parseHeadersEnv}});var Ue=W();Object.defineProperty(i,"TraceManager",{enumerable:!0,get:function(){return Ue.TraceManager}});Object.defineProperty(i,"generateUlid",{enumerable:!0,get:function(){return Ue.generateUlid}});var $e=je();Object.defineProperty(i,"DiskSessionTraceManager",{enumerable:!0,get:function(){return $e.DiskSessionTraceManager}});Object.defineProperty(i,"MemorySessionTraceManager",{enumerable:!0,get:function(){return $e.MemorySessionTraceManager}});var oe=Fe();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 Ir}from"node:fs";import{pathToFileURL as xr}from"node:url";var A=I(k());function Vt(){return(0,A.envFilePath)(".copilot","pinta-copilot.env","COPILOT_HOME")}function Ge(e=Vt()){(0,A.loadEnvFile)(e)}import Bt from"os";import se from"path";function ie(){return process.env.COPILOT_HOME||se.join(Bt.homedir(),".copilot")}function Ve(){let e=process.env.COPILOT_PLUGIN_DATA||se.join(ie(),"pinta-copilot-data");return{pluginData:e,tracePath:se.join(e,"trace.json")}}function Be(e=process.env){return e.COPILOT_AGENT_JOB_ID||e.COPILOT_AGENT_SESSION_ID||e.COPILOT_AGENT_PROMPT?"cloud":e.ELECTRON_RUN_AS_NODE||e.VSCODE_IPC_HOOK||e.VSCODE_PID?"ext":"cli"}function E(e){return typeof e=="string"?e:void 0}function j(e){return E(e.hook_event_name)??E(e.hookEventName)??E(e.hookName)??(process.env.PINTA_COPILOT_EVENT||void 0)}function Ke(e){return E(e.session_id)??E(e.sessionId)}function Ze(e){return E(e.tool_name)??E(e.toolName)}function Xe(e){return e.tool_input??e.toolArgs??e.toolInput}var Kt={sessionstart:"SessionStart",sessionend:"SessionEnd",userpromptsubmit:"UserPromptSubmit",userpromptsubmitted:"UserPromptSubmit",pretooluse:"PreToolUse",posttooluse:"PostToolUse",posttoolusefailure:"PostToolUseFailure",stop:"Stop",agentstop:"Stop",subagentstart:"SubagentStart",subagentstop:"SubagentStop",precompact:"PreCompact",notification:"Notification",permissionrequest:"PermissionRequest",erroroccurred:"ErrorOccurred"};function ze(e){let t=j(e);return t?Kt[t.toLowerCase()]??"Unknown":"Unknown"}function He(e){return e==="PreToolUse"||e==="PermissionRequest"}var Zt=new Set(["report_intent","ask_user"]);function Je(e){return e!==void 0&&Zt.has(e)}function Ye(e,t){return e==="PreToolUse"?JSON.stringify({hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:t}}):e==="PermissionRequest"?JSON.stringify({behavior:"deny",message:t}):null}var q=I(k());function Xt(){let e=process.env.COPILOT_PLUGIN_OPTION_ENDPOINT||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:(0,q.parseHeadersEnv)(process.env.COPILOT_PLUGIN_OPTION_HEADERS||process.env.OTEL_EXPORTER_OTLP_HEADERS)}:null}var C=class extends q.DiskTransport{constructor(t){super({pluginData:t.pluginData,logPrefix:"pinta-copilot",resolveOptions:Xt})}};var Qe=I(k()),F=class extends Qe.DiskSessionTraceManager{constructor(t){super(t.tracePath)}};var w=I(k());import ae from"os";var We="0.5.0";function zt(){return process.env.COPILOT_CLI_VERSION||"unknown"}var Ht=new Set(["copilot.hook","copilot.tool_name","copilot.toolName","copilot.tool_use_id","copilot.toolUseId","copilot.session_id","copilot.sessionId","copilot.transcript_path","copilot.transcriptPath","copilot.cwd","copilot.permission_mode","copilot.surface","copilot.agent_id","copilot.agent_type","copilot.agent_name","copilot.agent_display_name","copilot.stop_reason","copilot.notification_type"]),Jt=new Set(["copilot.tool_input","copilot.toolInput","copilot.tool_response","copilot.tool_result"]),Yt={skipRedactKeys:Ht,bashContextKeys:Jt},Qt=new Set(["hook_event_name","hookEventName","hookName"]);function Wt(e,t){let r=Object.fromEntries(Object.entries(e).filter(([n])=>!Qt.has(n)));return[{key:"ingest.type",value:{stringValue:"copilot"}},{key:"copilot.hook",value:{stringValue:j(e)??"unknown"}},{key:"copilot.surface",value:{stringValue:t}},...(0,w.attrsFromRecord)(r,"copilot",Yt)]}function er(){return[{key:"service.name",value:{stringValue:"copilot"}},{key:"service.version",value:{stringValue:zt()}},{key:"telemetry.sdk.name",value:{stringValue:"pinta-copilot"}},{key:"telemetry.sdk.language",value:{stringValue:"nodejs"}},{key:"telemetry.sdk.version",value:{stringValue:We}},{key:"process.pid",value:{intValue:process.pid}},{key:"process.owner",value:{stringValue:ae.userInfo().username}},{key:"host.name",value:{stringValue:ae.hostname()}},{key:"host.arch",value:{stringValue:ae.arch()}}]}function et(e){return(0,w.buildPayload)({traceId:e.traceId,spanName:`copilot.${(0,w.snakeCase)(j(e.event)??"unknown")}`,attributes:Wt(e.event,e.surface),resource:er(),scope:{name:"pinta-copilot",version:We},now:e.now,guard:e.guard})}var tt=I(k());function tr(){return Number(process.env.PINTA_GUARD_TIMEOUT_MS)||50}var rr="pinta-copilot/0.5.0";function rt(e,t){return(0,tt.evaluateGuard)(e,t,{timeoutMs:tr(),token:process.env.PINTA_RELAY_TOKEN??"",disabled:process.env.PINTA_GUARD_DISABLED==="1",userAgent:rr})}async function nr(){let e=[];for await(let t of process.stdin)e.push(t);return Buffer.concat(e).toString("utf-8")}async function nt(){try{let e=Ve(),t=Be(),r=await nr(),n=JSON.parse(r),o=ze(n),s=Ke(n),a=new C(e);await a.flush();let u=new F(e),p=o==="UserPromptSubmit"?u.newTrace(s):u.currentTrace(s),b=Ze(n),y=null;if(He(o)&&!Je(b)){let S=Xe(n);y=await rt({spanId:s??"unknown",toolName:b,toolInput:S,rawTextFields:{toolInput:typeof S=="string"?S:JSON.stringify(S??null)}},process.env.PINTA_GUARD_ENDPOINT)}let U=et({event:n,traceId:p,surface:t,guard:y});if(await a.send(U),y?.decision==="DENY"){let S=Ye(o,y.userMessage??y.reason??"guard_deny");S&&process.stdout.write(S+`
14
+ `)}}catch(e){process.stderr.write(`[pinta-copilot] error: ${e}
15
+ `)}return 0}import{opendir as gr,stat as hr}from"node:fs/promises";import L from"node:path";import{spawn as st}from"node:child_process";import{copyFile as ue,mkdtemp as or,rm as pn,stat as sr}from"node:fs/promises";import ir from"node:os";import ce from"node:path";var ar=2e3,ur=250,ot=3,le;function cr(){return le||(le=new Promise(e=>{let t=st("sqlite3",["-version"],{stdio:"ignore"});t.once("error",()=>e(!1)),t.once("exit",r=>e(r===0))})),le}function lr(e){return`'${e.replace(/'/g,"''")}'`}async function pr(e,t){let r=`.backup ${lr(t)}`;await new Promise((n,o)=>{let s=st("sqlite3",[e,r],{stdio:["ignore","ignore","pipe"]}),a="";s.stderr?.on("data",u=>{a+=u.toString()}),s.once("error",o),s.once("exit",u=>{u===0?n():o(new Error(`sqlite3 .backup exited ${u}: ${a.trim()}`))})})}async function pe(e){try{return await sr(e)}catch{return}}function it(e,t){return e===void 0||t===void 0?e===void 0&&t===void 0:e.size===t.size&&e.mtimeMs===t.mtimeMs}function at(e){return{wal:`${e}-wal`,shm:`${e}-shm`}}async function fr(e){let{wal:t,shm:r}=at(e),n=[e,t,r],o=Date.now(),s=await Promise.all(n.map(async a=>({path:a,st:await pe(a)})));for(;;){if(Date.now()-o>=ar)return s;await new Promise(p=>setTimeout(p,ur));let a=await Promise.all(n.map(async p=>({path:p,st:await pe(p)})));a.every((p,b)=>it(p.st,s[b].st))||(o=Date.now()),s=a}}async function dr(e,t){let{wal:r,shm:n}=at(e),o=await fr(e);if(await ue(e,t),o.find(u=>u.path===r)?.st!==void 0&&await ue(r,`${t}-wal`),o.find(u=>u.path===n)?.st!==void 0&&await ue(n,`${t}-shm`),!(await Promise.all([e,r,n].map(async u=>({path:u,st:await pe(u)})))).every((u,p)=>it(u.st,o[p].st)))throw new Error(`snapshot: ${e} changed during quiesce-copy (torn-read guard)`)}async function mr(e,t){let r;for(let n=1;n<=ot;n++)try{await dr(e,t);return}catch(o){r=o}throw new Error(`snapshot: quiesce-copy of ${e} failed after ${ot} attempts: ${String(r)}`)}async function ut(e,t={}){let r=t.tmpDirBase??ir.tmpdir(),n=await or(ce.join(r,"pinta-copilot-snapshot-")),o=ce.join(n,ce.basename(e.absPath));if(await cr())try{return await pr(e.absPath,o),o}catch{}return await mr(e.absPath,o),o}var yr="pinta-copilot",ct="events.jsonl",lt="session.db",_r="rewind-snapshots/backups/";function Pr(){return L.join(ie(),"session-state")}function Sr(e,t){return L.relative(e,t).split(L.sep).join("/")}function Or(e){return e.endsWith(".db-wal")||e.endsWith(".db-shm")}function Tr(e){let[t]=e.split("/");return!t||t===e?{}:{sessionId:t}}function vr(e,t){let r=e.split("/").length===2;return r&&t===ct?"append-log":r&&t===lt?"database":"rewritten-doc"}function Er(e){let t=e.split("/"),r=t[t.length-1]??"";return t.length===2&&(r===ct||r===lt)?"session-log":e.includes(_r)?"other":"meta"}async function pt(){return[Pr()]}async function*ft(e,t){let r;try{r=await gr(t)}catch{return}try{for await(let n of r){let o=L.join(t,n.name);n.isDirectory()?yield*ft(e,o):n.isFile()&&(yield{absPath:o,relPath:Sr(e,o)})}}catch{return}}async function*wr(e){let[t]=await pt(),r=e.since?.getTime();for await(let{absPath:n,relPath:o}of ft(t,t)){let s=o.split("/"),a=s[s.length-1]??"";if(Or(a))continue;let u;try{u=await hr(n)}catch{continue}r!==void 0&&u.mtime.getTime()<=r||(yield{relPath:o,absPath:n,size:u.size,mtime:u.mtime,...Tr(o),semantics:vr(o,a)})}}async function br(e){return ut(e)}var kr={id:yr,roots:pt,scan:wr,classify:Er,snapshot:br};Ge();function Rr(){let e=process.argv[1];if(!e)return!1;try{return import.meta.url===xr(Ir(e)).href}catch{return!1}}async function Ar(){let e=await nt();process.exit(e)}Rr()&&Ar();export{kr as lifecycle};
@@ -1,81 +1,4 @@
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
- /**
7
- * doctor — read-only health check for a pinta-copilot install.
8
- *
9
- * node dist/tools/doctor.js (or: npm run doctor)
10
- *
11
- * Verifies the hook file, env file / OTel endpoint, and the built adapter.
12
- * Exits 1 if anything required is missing; 0 if healthy.
13
- */
14
- const node_fs_1 = __importDefault(require("node:fs"));
15
- const node_os_1 = __importDefault(require("node:os"));
16
- const node_path_1 = __importDefault(require("node:path"));
17
- const surface_js_1 = require("../core/surface.js");
18
- function copilotHome() {
19
- return process.env.COPILOT_HOME || node_path_1.default.join(node_os_1.default.homedir(), ".copilot");
20
- }
21
- const checks = [];
22
- function check(required, ok, label, detail) {
23
- checks.push({ ok, label, detail, required });
24
- }
25
- const home = copilotHome();
26
- const hookFile = node_path_1.default.join(home, "hooks", "pinta-copilot.json");
27
- const envFile = node_path_1.default.join(home, "pinta-copilot.env");
28
- const adapter = node_path_1.default.join(node_path_1.default.dirname(node_path_1.default.resolve(process.argv[1])), "..", "index.js");
29
- // 1. adapter built
30
- check(true, node_fs_1.default.existsSync(adapter), "adapter built (dist/index.js)", adapter);
31
- // 2. hook file installed + points at this adapter
32
- let hookOk = false;
33
- let hookDetail = `${hookFile} (missing — run \`npm run install-hooks\`)`;
34
- try {
35
- const j = JSON.parse(node_fs_1.default.readFileSync(hookFile, "utf-8"));
36
- const cmd = j?.hooks?.PreToolUse?.[0]?.command ?? "";
37
- const events = Object.keys(j?.hooks ?? {}).length;
38
- hookOk = cmd.includes("index.js");
39
- hookDetail = `${hookFile} (${events} events)`;
40
- }
41
- catch {
42
- /* missing */
43
- }
44
- check(true, hookOk, "hook file installed", hookDetail);
45
- // 3. env file (optional) + OTel endpoint configured (required for telemetry)
46
- const hasEnvFile = node_fs_1.default.existsSync(envFile);
47
- check(false, hasEnvFile, "env file present", hasEnvFile ? envFile : `${envFile} (none — config may come from process.env)`);
48
- let endpoint = process.env.COPILOT_PLUGIN_OPTION_ENDPOINT ||
49
- process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ||
50
- process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
51
- if (!endpoint && hasEnvFile) {
52
- const m = node_fs_1.default
53
- .readFileSync(envFile, "utf-8")
54
- .match(/(?:COPILOT_PLUGIN_OPTION_ENDPOINT|OTEL_EXPORTER_OTLP_(?:TRACES_)?ENDPOINT)=(.+)/);
55
- if (m)
56
- endpoint = m[1].trim();
57
- }
58
- check(true, Boolean(endpoint), "traces endpoint configured", endpoint || "(unset — spans will be dropped)");
59
- // 4. guard endpoint (optional)
60
- let guardEp = process.env.PINTA_GUARD_ENDPOINT;
61
- if (!guardEp && hasEnvFile) {
62
- const m = node_fs_1.default.readFileSync(envFile, "utf-8").match(/PINTA_GUARD_ENDPOINT=(.+)/);
63
- if (m)
64
- guardEp = m[1].trim();
65
- }
66
- check(false, Boolean(guardEp), "guard endpoint (optional)", guardEp || "(none — telemetry only, no allow/deny)");
67
- // --- report ---
68
- let failed = 0;
69
- for (const c of checks) {
70
- const mark = c.ok ? "✅" : c.required ? "❌" : "⚠️ ";
71
- if (!c.ok && c.required)
72
- failed++;
73
- // eslint-disable-next-line no-console
74
- console.log(`${mark} ${c.label}${c.detail ? ` — ${c.detail}` : ""}`);
75
- }
76
- // eslint-disable-next-line no-console
77
- console.log(`\nsurface (this shell): ${(0, surface_js_1.detectSurface)()}`);
78
- // eslint-disable-next-line no-console
79
- console.log(failed === 0 ? "\nhealthy ✅" : `\n${failed} required check(s) failed ❌`);
80
- process.exit(failed === 0 ? 0 : 1);
81
- //# sourceMappingURL=doctor.js.map
1
+ "use strict";var k=Object.create;var _=Object.defineProperty;var L=Object.getOwnPropertyDescriptor;var C=Object.getOwnPropertyNames;var x=Object.getPrototypeOf,R=Object.prototype.hasOwnProperty;var j=(e,o,n,l)=>{if(o&&typeof o=="object"||typeof o=="function")for(let r of C(o))!R.call(e,r)&&r!==n&&_(e,r,{get:()=>o[r],enumerable:!(l=L(o,r))||l.enumerable});return e};var a=(e,o,n)=>(n=e!=null?k(x(e)):{},j(o||!e||!e.__esModule?_(n,"default",{value:e,enumerable:!0}):n,e));var s=a(require("node:fs")),t=a(require("node:path"));function P(e=process.env){return e.COPILOT_AGENT_JOB_ID||e.COPILOT_AGENT_SESSION_ID||e.COPILOT_AGENT_PROMPT?"cloud":e.ELECTRON_RUN_AS_NODE||e.VSCODE_IPC_HOOK||e.VSCODE_PID?"ext":"cli"}var T=a(require("os")),E=a(require("path"));function m(){return process.env.COPILOT_HOME||E.default.join(T.default.homedir(),".copilot")}var h=[];function c(e,o,n,l){h.push({ok:o,label:n,detail:l,required:e})}function I(e,o){let n=s.default.readFileSync(e,"utf-8").match(o);return n?n[1].trim():void 0}var g=m(),u=t.default.join(g,"hooks","pinta-copilot.json"),i=t.default.join(g,"pinta-copilot.env"),N=t.default.join(t.default.dirname(t.default.resolve(process.argv[1])),"..","index.js");c(!0,s.default.existsSync(N),"adapter built (dist/index.js)",N);var D=!1,S=`${u} (missing \u2014 run \`npm run install-hooks\`)`;try{let e=JSON.parse(s.default.readFileSync(u,"utf-8")),o=e?.hooks?.PreToolUse?.[0]?.command??"",n=Object.keys(e?.hooks??{}).length;D=o.includes("index.js"),S=`${u} (${n} events)`}catch{}c(!0,D,"hook file installed",S);var p=s.default.existsSync(i);c(!1,p,"env file present",p?i:`${i} (none \u2014 config may come from process.env)`);var O=process.env.COPILOT_PLUGIN_OPTION_ENDPOINT||process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT||process.env.OTEL_EXPORTER_OTLP_ENDPOINT;!O&&p&&(O=I(i,/(?:COPILOT_PLUGIN_OPTION_ENDPOINT|OTEL_EXPORTER_OTLP_(?:TRACES_)?ENDPOINT)=(.+)/));c(!0,!!O,"traces endpoint configured",O||"(unset \u2014 spans will be dropped)");var d=process.env.PINTA_GUARD_ENDPOINT;!d&&p&&(d=I(i,/PINTA_GUARD_ENDPOINT=(.+)/));c(!1,!!d,"guard endpoint (optional)",d||"(none \u2014 telemetry only, no allow/deny)");var f=0;for(let e of h){let o=e.ok?"\u2705":e.required?"\u274C":"\u26A0\uFE0F ";!e.ok&&e.required&&f++,console.log(`${o} ${e.label}${e.detail?` \u2014 ${e.detail}`:""}`)}console.log(`
2
+ surface (this shell): ${P()}`);console.log(f===0?`
3
+ healthy \u2705`:`
4
+ ${f} required check(s) failed \u274C`);process.exit(f===0?0:1);
@@ -1,101 +1,3 @@
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
- /**
7
- * install-hooks — write the user-level Copilot hook file that points every
8
- * event at this adapter's `dist/index.js` (D4: direct hook-file install,
9
- * plugin auto-discovery channel unused).
10
- *
11
- * Target: `$COPILOT_HOME/hooks/pinta-copilot.json` (default `~/.copilot/hooks/`).
12
- * One file fires on BOTH the Copilot CLI and the VS Code extension — no VS Code
13
- * setting required (`chat.useClaudeHooks` default works, §9.7). Add the same
14
- * file under a repo's `.github/hooks/` for cloud/repo-scoped runs (out of scope
15
- * for now).
16
- *
17
- * Idempotent: re-running rewrites our file in place. `--uninstall` removes it.
18
- * Absolute paths are baked in at install time because user-level hooks don't
19
- * receive `${COPILOT_PLUGIN_ROOT}` substitution.
20
- *
21
- * Usage:
22
- * node dist/tools/install-hooks.js [--dry-run] [--uninstall]
23
- */
24
- const node_fs_1 = __importDefault(require("node:fs"));
25
- const node_os_1 = __importDefault(require("node:os"));
26
- const node_path_1 = __importDefault(require("node:path"));
27
- const HOOK_FILE = "pinta-copilot.json";
28
- // Every event routes to the single adapter binary; it branches internally
29
- // (telemetry for all; guard deny on PreToolUse + permissionRequest).
30
- const EVENTS = [
31
- "SessionStart",
32
- "SessionEnd",
33
- "UserPromptSubmit",
34
- "PreToolUse",
35
- "PostToolUse",
36
- "PostToolUseFailure",
37
- "Stop",
38
- "SubagentStart",
39
- "SubagentStop",
40
- "PreCompact",
41
- "Notification",
42
- "permissionRequest",
43
- ];
44
- function copilotHome() {
45
- return process.env.COPILOT_HOME || node_path_1.default.join(node_os_1.default.homedir(), ".copilot");
46
- }
47
- function hooksDir() {
48
- return node_path_1.default.join(copilotHome(), "hooks");
49
- }
50
- /** Absolute path to dist/index.js. This script runs as dist/tools/install-hooks.js,
51
- * so resolve relative to the invoked script path (CJS/ESM agnostic). */
52
- function adapterEntry() {
53
- const here = node_path_1.default.dirname(node_path_1.default.resolve(process.argv[1])); // .../dist/tools
54
- return node_path_1.default.join(here, "..", "index.js"); // .../dist/index.js
55
- }
56
- function buildHooksFile() {
57
- const cmd = `${process.execPath} ${adapterEntry()}`;
58
- const hooks = {};
59
- for (const ev of EVENTS) {
60
- // Stamp the registered event name into env as a fail-safe discriminator —
61
- // some payloads (CLI subagentStart) omit any hook-name field entirely.
62
- hooks[ev] = [{ type: "command", command: cmd, env: { PINTA_COPILOT_EVENT: ev } }];
63
- }
64
- return JSON.stringify({
65
- version: 1,
66
- _note: "Managed by @pinta-ai/pinta-copilot install-hooks. Do not edit by hand.",
67
- hooks,
68
- }, null, 2) + "\n";
69
- }
70
- function main() {
71
- const args = process.argv.slice(2);
72
- const dryRun = args.includes("--dry-run");
73
- const uninstall = args.includes("--uninstall");
74
- const target = node_path_1.default.join(hooksDir(), HOOK_FILE);
75
- if (uninstall) {
76
- if (node_fs_1.default.existsSync(target)) {
77
- if (!dryRun)
78
- node_fs_1.default.rmSync(target);
79
- console.log(`${dryRun ? "[dry-run] would remove" : "removed"}: ${target}`);
80
- }
81
- else {
82
- console.log(`nothing to remove: ${target}`);
83
- }
84
- return;
85
- }
86
- const content = buildHooksFile();
87
- if (node_fs_1.default.existsSync(target) && node_fs_1.default.readFileSync(target, "utf-8") === content) {
88
- console.log(`already up to date: ${target}`);
89
- return;
90
- }
91
- if (dryRun) {
92
- console.log(`[dry-run] would write: ${target}\n${content}`);
93
- return;
94
- }
95
- node_fs_1.default.mkdirSync(hooksDir(), { recursive: true });
96
- node_fs_1.default.writeFileSync(target, content);
97
- console.log(`installed: ${target}`);
98
- console.log("→ restart the Copilot CLI / reload the VS Code window to load hooks.");
99
- }
100
- main();
101
- //# sourceMappingURL=install-hooks.js.map
1
+ "use strict";var m=Object.create;var a=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var S=Object.getPrototypeOf,h=Object.prototype.hasOwnProperty;var y=(o,n,e,t)=>{if(n&&typeof n=="object"||typeof n=="function")for(let r of f(n))!h.call(o,r)&&r!==e&&a(o,r,{get:()=>n[r],enumerable:!(t=g(n,r))||t.enumerable});return o};var c=(o,n,e)=>(e=o!=null?m(S(o)):{},y(n||!o||!o.__esModule?a(e,"default",{value:o,enumerable:!0}):e,o));var i=c(require("node:fs")),s=c(require("node:path"));var l=c(require("os")),u=c(require("path"));function p(){return process.env.COPILOT_HOME||u.default.join(l.default.homedir(),".copilot")}var P="pinta-copilot.json",v=["SessionStart","SessionEnd","UserPromptSubmit","PreToolUse","PostToolUse","PostToolUseFailure","Stop","SubagentStart","SubagentStop","PreCompact","Notification","permissionRequest"];function d(){return s.default.join(p(),"hooks")}function C(){let o=s.default.dirname(s.default.resolve(process.argv[1]));return s.default.join(o,"..","index.js")}function O(){let o=`${process.execPath} ${C()}`,n={};for(let e of v)n[e]=[{type:"command",command:o,env:{PINTA_COPILOT_EVENT:e}}];return JSON.stringify({version:1,_note:"Managed by @pinta-ai/pinta-copilot install-hooks. Do not edit by hand.",hooks:n},null,2)+`
2
+ `}function T(){let o=process.argv.slice(2),n=o.includes("--dry-run"),e=o.includes("--uninstall"),t=s.default.join(d(),P);if(e){i.default.existsSync(t)?(n||i.default.rmSync(t),console.log(`${n?"[dry-run] would remove":"removed"}: ${t}`)):console.log(`nothing to remove: ${t}`);return}let r=O();if(i.default.existsSync(t)&&i.default.readFileSync(t,"utf-8")===r){console.log(`already up to date: ${t}`);return}if(n){console.log(`[dry-run] would write: ${t}
3
+ ${r}`);return}i.default.mkdirSync(d(),{recursive:!0}),i.default.writeFileSync(t,r),console.log(`installed: ${t}`),console.log("\u2192 restart the Copilot CLI / reload the VS Code window to load hooks.")}T();
package/package.json CHANGED
@@ -1,8 +1,14 @@
1
1
  {
2
2
  "name": "@pinta-ai/pinta-copilot",
3
- "version": "0.3.1",
3
+ "version": "0.5.0",
4
4
  "description": "Generic OTLP forwarder + guard for GitHub Copilot hook events (CLI + VS Code extension)",
5
5
  "main": "dist/index.js",
6
+ "exports": {
7
+ ".": {
8
+ "import": "./dist/index.mjs",
9
+ "require": "./dist/index.js"
10
+ }
11
+ },
6
12
  "license": "PolyForm-Noncommercial-1.0.0",
7
13
  "files": [
8
14
  "dist",
@@ -20,10 +26,13 @@
20
26
  },
21
27
  "scripts": {
22
28
  "bump": "node scripts/bump.mjs",
23
- "build": "tsc",
29
+ "build": "tsc --noEmit && npm run build:cjs && npm run build:esm",
30
+ "build:cjs": "esbuild src/index.ts src/tools/doctor.ts src/tools/install-hooks.ts --bundle --platform=node --format=cjs --target=node18 --minify --outbase=src --outdir=dist",
31
+ "build:esm": "esbuild src/index.mts --bundle --platform=node --format=esm --target=node18 --minify --banner:js=\"import{createRequire as __pintaCreateRequire}from 'node:module';const require=__pintaCreateRequire(import.meta.url);\" --outfile=dist/index.mjs",
24
32
  "dev": "tsc --watch",
25
33
  "test": "vitest run",
26
34
  "test:watch": "vitest",
35
+ "smoke:import": "node scripts/smoke-import.mjs",
27
36
  "mock-server": "npx tsx tools/mock-server.ts",
28
37
  "install-hooks": "node dist/tools/install-hooks.js",
29
38
  "uninstall-hooks": "node dist/tools/install-hooks.js --uninstall",
@@ -31,9 +40,15 @@
31
40
  "prepublishOnly": "npm run build"
32
41
  },
33
42
  "devDependencies": {
43
+ "@pinta-ai/core": "^0.3.0",
34
44
  "@types/node": "^22.0.0",
45
+ "esbuild": "^0.24.0",
35
46
  "tsx": "^4.0.0",
36
47
  "typescript": "^5.7.0",
37
48
  "vitest": "^2.1.0"
49
+ },
50
+ "publishConfig": {
51
+ "registry": "https://registry.npmjs.org",
52
+ "access": "public"
38
53
  }
39
54
  }
@@ -1,15 +0,0 @@
1
- /**
2
- * Runtime config. Endpoint/headers come from OTEL_EXPORTER_OTLP_* env vars
3
- * (loaded from ~/.copilot/pinta-copilot.env at startup) — not in this struct.
4
- *
5
- * pinta-copilot is installed as a direct hook file (D4), so the data dir
6
- * (trace + retry-queue) must be a STABLE location independent of cwd —
7
- * otherwise the per-turn trace written by UserPromptSubmit can't be read back
8
- * by the following PreToolUse if cwd differs. We anchor it under the Copilot
9
- * home (`$COPILOT_HOME` or `~/.copilot`).
10
- */
11
- export interface PintaConfig {
12
- pluginData: string;
13
- tracePath: string;
14
- }
15
- export declare function loadConfig(): PintaConfig;
@@ -1,19 +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
- const os_1 = __importDefault(require("os"));
8
- const path_1 = __importDefault(require("path"));
9
- function copilotHome() {
10
- return process.env.COPILOT_HOME || path_1.default.join(os_1.default.homedir(), ".copilot");
11
- }
12
- function loadConfig() {
13
- const pluginData = process.env.COPILOT_PLUGIN_DATA || path_1.default.join(copilotHome(), "pinta-copilot-data");
14
- return {
15
- pluginData,
16
- tracePath: path_1.default.join(pluginData, "trace.json"),
17
- };
18
- }
19
- //# sourceMappingURL=config.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":";;;;;AAsBA,gCAOC;AA7BD,4CAAoB;AACpB,gDAAwB;AAiBxB,SAAS,WAAW;IAClB,OAAO,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,cAAI,CAAC,IAAI,CAAC,YAAE,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;AACzE,CAAC;AAED,SAAgB,UAAU;IACxB,MAAM,UAAU,GACd,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,cAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,oBAAoB,CAAC,CAAC;IACpF,OAAO;QACL,UAAU;QACV,SAAS,EAAE,cAAI,CAAC,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC;KAC/C,CAAC;AACJ,CAAC"}
@@ -1,25 +0,0 @@
1
- /**
2
- * Bridge Claude Code's userConfig env vars (CLAUDE_PLUGIN_OPTION_*) to the
3
- * OTel SDK standard env vars (OTEL_EXPORTER_OTLP_*).
4
- *
5
- * Claude Code maps each plugin.json `userConfig.<key>` to a corresponding
6
- * `CLAUDE_PLUGIN_OPTION_<KEY>` env var on hook spawn. We keep the user-
7
- * facing names friendly (`endpoint`, `api_key`) and translate them into the
8
- * canonical OTel env names so transport.ts (and any future OTel SDK adoption)
9
- * can read them via the OTel-spec names.
10
- *
11
- * The user-facing `endpoint` is treated as a *full* OTLP/HTTP traces URL
12
- * (e.g., `http://127.0.0.1:5147/v1/traces`), so we map it to
13
- * `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` (signal-specific full URL per OTel
14
- * spec) rather than `OTEL_EXPORTER_OTLP_ENDPOINT` (which is a base URL the
15
- * SDK appends `/v1/traces` to). This way both the OTel SDK (when used) and
16
- * pinta-cc's hand-written transport agree on the URL without any path
17
- * manipulation downstream.
18
- *
19
- * Pinta Manager auto-injects `CLAUDE_PLUGIN_OPTION_*` via Claude Code's
20
- * settings.json. OSS users fill them in via the `/plugin install` UI.
21
- *
22
- * Existing OTEL_EXPORTER_OTLP_TRACES_ENDPOINT / HEADERS take precedence
23
- * (explicit override).
24
- */
25
- export declare function bridgeUserConfigToOtelEnv(): void;