@pinta-ai/pinta-cc 1.10.0 → 1.10.2
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/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +78 -0
- package/README.md +107 -5
- package/dist/index.js +29 -20
- package/dist/index.mjs +29 -20
- package/hooks/hooks.json +1 -0
- package/package.json +3 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pinta-cc",
|
|
3
3
|
"description": "Generic OTLP forwarder for Claude Code hook events. Converts hook events into OTLP/HTTP spans and sends them to any OpenTelemetry-compatible collector.",
|
|
4
|
-
"version": "1.10.
|
|
4
|
+
"version": "1.10.2",
|
|
5
5
|
"license": "PolyForm-Noncommercial-1.0.0",
|
|
6
6
|
"userConfig": {
|
|
7
7
|
"endpoint": {
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,84 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to pinta-cc are documented here.
|
|
4
4
|
|
|
5
|
+
## [1.10.2] - 2026-09-30
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Bundle `@pinta-ai/core` `^0.9.2`, preserving ordinary `find -path` and
|
|
10
|
+
`find -print` arguments while retaining mysql-family short-password
|
|
11
|
+
masking (PTA-515). Guard/export ordering is unchanged.
|
|
12
|
+
- Evaluate `PermissionRequest` and emit its native deny decision before local
|
|
13
|
+
telemetry deferral. ALLOW/REVIEW do not grant permission; `PermissionDenied`
|
|
14
|
+
remains observation-only (PTA-583).
|
|
15
|
+
- Register and guard `PostToolBatch` using its original model-facing results,
|
|
16
|
+
including failed calls, and stop denied batches before the next model request.
|
|
17
|
+
Native Claude 2.1.267 ignores a run-stop on `PostToolUseFailure` itself, so
|
|
18
|
+
merely guarding that event would not protect the model (PTA-582).
|
|
19
|
+
- Cover both gates in CJS/ESM process regressions, including REVIEW/disabled,
|
|
20
|
+
one-second completion despite delayed collector ACK, and original-span queueing.
|
|
21
|
+
|
|
22
|
+
### Compatibility
|
|
23
|
+
|
|
24
|
+
- Batch protection requires synchronous `PostToolBatch` registration and a
|
|
25
|
+
guard/Manager projecting `cc.tool_calls` as output. Managed registration must
|
|
26
|
+
be updated alongside the adapter. Hosts without this event remain unsupported
|
|
27
|
+
for failed-result protection; 2.1.267 is verified, not a minimum-version claim.
|
|
28
|
+
- The existing successful-output gate, observation-only failure event, output
|
|
29
|
+
target metadata, bounded retry queue, and guard fail-open behavior remain.
|
|
30
|
+
A batch is a separate native event and can re-evaluate successful output.
|
|
31
|
+
|
|
32
|
+
## [1.10.1] - 2026-09-29
|
|
33
|
+
|
|
34
|
+
### Fixed
|
|
35
|
+
|
|
36
|
+
- Publish the output-enforcement fix above both 1.10.0 and 1.9.1 so semantic
|
|
37
|
+
version selection chooses the fixed adapter.
|
|
38
|
+
|
|
39
|
+
### Compatibility
|
|
40
|
+
|
|
41
|
+
- Version-only forward release of the merged behavior shipped in 1.9.1:
|
|
42
|
+
retains the 1.10.0 timeout declaration, native output denial and deferred
|
|
43
|
+
DENY telemetry. No policy, timeout, dependency or hook behavior changes.
|
|
44
|
+
|
|
45
|
+
## [1.9.1] - 2026-09-29
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
|
|
49
|
+
- Evaluate successful `PostToolUse` output, including native `tool_response`,
|
|
50
|
+
using the original redaction-aware OTLP payload. Previously these events
|
|
51
|
+
emitted telemetry without asking the guard.
|
|
52
|
+
- On an output `DENY`, emit Claude Code's supported `continue: false` stop JSON
|
|
53
|
+
before best-effort local persistence, using a fixed message that asks for a new
|
|
54
|
+
session and never reflects untrusted output or guard messages.
|
|
55
|
+
- Finish both `PreToolUse` and `PostToolUse` DENYs without collector network IO,
|
|
56
|
+
deferring their original spans through the existing `DiskRetryQueue`. Merely
|
|
57
|
+
printing the response before awaiting telemetry was insufficient: a host
|
|
58
|
+
timeout could discard the decision while waiting for a slow collector.
|
|
59
|
+
- Preserve original masked input/output evidence and span identity; attach
|
|
60
|
+
normal guard metadata plus `pinta.guard.target = "tool_output"` for every
|
|
61
|
+
non-null after-tool verdict.
|
|
62
|
+
- Add native-output handler regressions and built CJS/ESM stdin/loopback checks
|
|
63
|
+
to PR validation, including a 1-second hook deadline with a 4-second collector
|
|
64
|
+
ACK, queue failure diagnostics, later-hook flush and non-gating boundaries.
|
|
65
|
+
|
|
66
|
+
### Compatibility
|
|
67
|
+
|
|
68
|
+
- This stops the current run on hosts honoring Claude Code's documented
|
|
69
|
+
synchronous `PostToolUse` stop contract. It does not undo an executed tool,
|
|
70
|
+
strip retained transcript content or make a resumed conversation safe.
|
|
71
|
+
Start a new session after an output denial; no persistent session lock or
|
|
72
|
+
automatic context clearing is introduced.
|
|
73
|
+
- `PreToolUse` permission decisions, permission/lifecycle/internal hooks,
|
|
74
|
+
failed-tool telemetry, ALLOW/REVIEW and existing fail-open behavior remain
|
|
75
|
+
unchanged. No policy thresholds or required guard request fields change.
|
|
76
|
+
- This out-of-order patch retains the already-released `@pinta-ai/core` 0.9.0
|
|
77
|
+
timeout-declaration behavior from 1.10.0.
|
|
78
|
+
- With telemetry enabled, decided-DENY evidence persists in the existing local
|
|
79
|
+
retry queue; backend visibility waits for a later eligible hook to flush it.
|
|
80
|
+
Guard-only/telemetry-disabled mode does not retain new local evidence.
|
|
81
|
+
Existing size/retention limits and disk-failure diagnostics still apply.
|
|
82
|
+
|
|
5
83
|
## [1.10.0] - 2026-09-30
|
|
6
84
|
|
|
7
85
|
### Added
|
package/README.md
CHANGED
|
@@ -4,12 +4,13 @@ Converts Claude Code hook events into OTLP/HTTP spans and forwards them to any O
|
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- **OTLP transport**: converts
|
|
7
|
+
- **OTLP transport**: converts 12 hook event types into OTLP/HTTP `resourceSpans` and sends them via `POST {endpoint}/traces`
|
|
8
8
|
- **Bronze flattening**: every top-level field of a hook event is flattened into `cc.<key>` span attributes
|
|
9
9
|
- **ULID per-turn traceId**: `UserPromptSubmit` starts a new ULID-based trace; all subsequent hooks in the same turn share it
|
|
10
|
-
- **Retry queue**:
|
|
10
|
+
- **Retry queue**: DENY and transport-failure spans are persisted to `.plugin-data/failed-spans.jsonl` (cap 1000) and flushed by a later eligible telemetry hook
|
|
11
11
|
- **Vendor-neutral**: any OTel-compatible collector works. Pinta Manager auto-configures the endpoint and token
|
|
12
12
|
- **Identity at relay**: `member.identity.*` attributes are no longer attached at plugin time. Pinta Manager (or your own pipeline) attaches identity at the forwarding layer
|
|
13
|
+
- **Optional guard enforcement**: denies tool input at `PreToolUse` and `PermissionRequest`; stops denied successful output at `PostToolUse` and model-facing batch results (including failures) at `PostToolBatch`
|
|
13
14
|
|
|
14
15
|
## Channels
|
|
15
16
|
|
|
@@ -81,6 +82,94 @@ The plugin reads OTel env vars directly. `CLAUDE_PLUGIN_OPTION_*` env vars (set
|
|
|
81
82
|
| `CLAUDE_PLUGIN_OPTION_ENDPOINT` | `OTEL_EXPORTER_OTLP_ENDPOINT` |
|
|
82
83
|
| `CLAUDE_PLUGIN_OPTION_API_KEY` | `OTEL_EXPORTER_OTLP_HEADERS=x-pinta-relay-token=<key>` |
|
|
83
84
|
|
|
85
|
+
## Tool-output guard and recovery
|
|
86
|
+
|
|
87
|
+
When `PINTA_GUARD_ENDPOINT` is configured, successful `PostToolUse` and
|
|
88
|
+
`PostToolBatch` events are evaluated through the same guard as `PreToolUse`.
|
|
89
|
+
The adapter first builds the normal redaction-aware OTLP span, including native
|
|
90
|
+
`tool_response` or the batch's `tool_calls` array, and sends
|
|
91
|
+
that original payload to the guard. It attaches the verdict to the same span
|
|
92
|
+
before delivery or local deferral, preserving its `traceId`, `spanId`, input and output evidence.
|
|
93
|
+
Every non-null after-tool verdict adds `pinta.guard.target = "tool_output"`:
|
|
94
|
+
denial concerns the output, not whether the completed tool executed.
|
|
95
|
+
|
|
96
|
+
Roll out telemetry-reader support for output-target verdicts before activating
|
|
97
|
+
this adapter in managed installations. Older readers can interpret every guard
|
|
98
|
+
denial as a prevented tool call rather than a completed tool with denied output.
|
|
99
|
+
The target is retained as original extension metadata.
|
|
100
|
+
|
|
101
|
+
**Failed results require `PostToolBatch`.** In native Claude Code 2.1.267,
|
|
102
|
+
`PostToolUseFailure` receives the error but ignores a parsed `continue: false`;
|
|
103
|
+
the next model request still receives that error. `PostToolBatch` runs before
|
|
104
|
+
the next model call, carries model-facing results for all calls (including
|
|
105
|
+
failed calls), and honors the run-stop response. The adapter therefore keeps
|
|
106
|
+
the failure event observation-only and gates the batch without cross-process
|
|
107
|
+
pending-decision state. A batch is a separate native event and may re-evaluate
|
|
108
|
+
successful results already checked at `PostToolUse`.
|
|
109
|
+
|
|
110
|
+
The plugin registers `PostToolBatch`. Managed/direct installations must also
|
|
111
|
+
register this synchronous hook, and the Manager/guard must project
|
|
112
|
+
`cc.tool_calls[].tool_response` as **output**, not interpret the batch's tool
|
|
113
|
+
inputs as new commands. Updating only the adapter is insufficient. Hosts
|
|
114
|
+
without a working batch hook have no failed-result enforcement guarantee.
|
|
115
|
+
|
|
116
|
+
On an output `DENY`, the hook exits successfully and emits exactly one JSON
|
|
117
|
+
object before best-effort local persistence:
|
|
118
|
+
|
|
119
|
+
```json
|
|
120
|
+
{"continue":false,"stopReason":"Pinta blocked this tool output. Start a new session before continuing."}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
This uses Claude Code's documented
|
|
124
|
+
[`continue: false` / `stopReason` contract](https://code.claude.com/docs/en/hooks#json-output)
|
|
125
|
+
to stop the current run, including when a tool completes during streaming.
|
|
126
|
+
`PostToolUse` exit code 2 only provides stderr feedback, and `decision: "block"`
|
|
127
|
+
alone is not this run-stop contract. The fixed message never copies tool output
|
|
128
|
+
or guard-supplied reasons/messages into the conversation.
|
|
129
|
+
|
|
130
|
+
**Decided DENYs never wait for collector network IO.** `PreToolUse`,
|
|
131
|
+
`PermissionRequest`, `PostToolUse` and `PostToolBatch` write their native
|
|
132
|
+
response, attach the guard metadata,
|
|
133
|
+
persist the original redacted span using the existing `DiskRetryQueue`, and
|
|
134
|
+
return without flushing or sending telemetry. Printing JSON first is not
|
|
135
|
+
sufficient: a host timeout while waiting for a collector can invalidate that
|
|
136
|
+
decision. The queued evidence retains the original input/output and span IDs,
|
|
137
|
+
not replacement warning text.
|
|
138
|
+
|
|
139
|
+
When telemetry is configured, evidence persists locally in
|
|
140
|
+
`${CLAUDE_PLUGIN_DATA}/failed-spans.jsonl` (default:
|
|
141
|
+
`${CLAUDE_PLUGIN_ROOT}/.plugin-data/failed-spans.jsonl`).
|
|
142
|
+
**Backend visibility is delayed** until a later eligible telemetry hook
|
|
143
|
+
successfully flushes the queue, including a hook in a new session. No queue is
|
|
144
|
+
created or appended to in guard-only/telemetry-disabled mode. Local persistence
|
|
145
|
+
uses the existing redaction, payload-size and 1000-entry retention limits.
|
|
146
|
+
Queue write failures, oversized drops and oldest-entry eviction are diagnosed
|
|
147
|
+
on stderr; they do not suppress the response or trigger a network fallback.
|
|
148
|
+
|
|
149
|
+
**Start a new session after an output denial.** The tool already ran: this does
|
|
150
|
+
not undo its effects, remove native results from the retained transcript, or
|
|
151
|
+
make resuming/continuing that conversation safe. There is no automatic clearing
|
|
152
|
+
or persistent session lock.
|
|
153
|
+
|
|
154
|
+
`ALLOW`, `REVIEW`, inactive guarding and existing guard fail-open paths do not
|
|
155
|
+
stop the run. `PermissionRequest` now evaluates the original permission span
|
|
156
|
+
and emits `hookSpecificOutput.decision = {behavior: "deny", message: ...}` on
|
|
157
|
+
DENY. Other decisions emit nothing: they do not automatically approve a
|
|
158
|
+
native permission request. `PermissionDenied`, session, lifecycle and internal
|
|
159
|
+
events keep their existing observation behavior, as does the `PreToolUse`
|
|
160
|
+
permission-denial response.
|
|
161
|
+
|
|
162
|
+
Enforcement requires synchronous hooks and a Claude Code host honoring the
|
|
163
|
+
documented `PostToolUse`/`PostToolBatch` stop contracts. The hook must finish within its host
|
|
164
|
+
timeout: Claude Code [discards timed-out hook output](https://code.claude.com/docs/en/hooks#timeouts).
|
|
165
|
+
Guard evaluation and local storage must still fit that deadline; removing
|
|
166
|
+
collector IO from decided DENYs does not make those operations instantaneous.
|
|
167
|
+
The native batch and permission contracts were verified with Claude Code
|
|
168
|
+
2.1.267 using an isolated HOME, a loopback-only provider, and harmless
|
|
169
|
+
read/failed-command fixtures. This is not a minimum-version claim or proof
|
|
170
|
+
of live policy reachability; that additionally requires the corresponding
|
|
171
|
+
Manager projection, registration and enabled policy.
|
|
172
|
+
|
|
84
173
|
## Span attribute conventions
|
|
85
174
|
|
|
86
175
|
### Resource attributes
|
|
@@ -193,8 +282,8 @@ src/
|
|
|
193
282
|
│ ├── identity.ts # Empty stub (identity attribution moved to relay)
|
|
194
283
|
│ └── redact.ts # Tier-1 redaction + Tier-3 truncation
|
|
195
284
|
└── handlers/
|
|
196
|
-
├── pre-tool-use.ts #
|
|
197
|
-
├── post-tool-use.ts
|
|
285
|
+
├── pre-tool-use.ts # build → guard → permission denial → defer DENY / send otherwise
|
|
286
|
+
├── post-tool-use.ts # success/batch output: build → guard → run stop → defer DENY / send otherwise
|
|
198
287
|
├── user-prompt.ts # flush → newTrace → buildOtlpPayload → send → exit 0
|
|
199
288
|
├── session.ts
|
|
200
289
|
├── subagent.ts
|
|
@@ -218,7 +307,7 @@ Each hook invocation spawns a fresh Node process. One hook = one OTLP span = one
|
|
|
218
307
|
|
|
219
308
|
## Captured events (11)
|
|
220
309
|
|
|
221
|
-
PreToolUse, PostToolUse, PostToolUseFailure, UserPromptSubmit, SessionStart, SessionEnd, PermissionRequest, PermissionDenied, SubagentStart, SubagentStop, Stop
|
|
310
|
+
PreToolUse, PostToolUse, PostToolUseFailure, PostToolBatch, UserPromptSubmit, SessionStart, SessionEnd, PermissionRequest, PermissionDenied, SubagentStart, SubagentStop, Stop
|
|
222
311
|
|
|
223
312
|
## Skipped events (3, exit 0 immediately)
|
|
224
313
|
|
|
@@ -232,11 +321,24 @@ npm run build # tsc → dist/
|
|
|
232
321
|
npm test # vitest run
|
|
233
322
|
npm run smoke:version # built CJS/ESM hooks -> local collector (after build)
|
|
234
323
|
npm run smoke:model # model attribution -> isolated loopback collector
|
|
324
|
+
npm run smoke:guard # output enforcement -> isolated loopback guard + collector
|
|
235
325
|
npm run mock-server # Generic OTLP collector at http://localhost:3000
|
|
236
326
|
```
|
|
237
327
|
|
|
238
328
|
### Local integration test
|
|
239
329
|
|
|
330
|
+
`smoke:guard` exercises both built entrypoints with native `PostToolUse`,
|
|
331
|
+
`PostToolBatch`, `PreToolUse` and `PermissionRequest` stdin payloads and isolated
|
|
332
|
+
HOME/plugin data. It verifies real guard requests,
|
|
333
|
+
fixed/unchanged DENY JSON and zero collector calls with a 1-second hook deadline
|
|
334
|
+
and a 4-second collector ACK delay. Both deny paths retain masked original
|
|
335
|
+
spans in the existing retry queue; later hook processes flush the same IDs and
|
|
336
|
+
evidence. Queue failures are diagnosed without losing the response, and
|
|
337
|
+
guard-only mode never queues evidence. ALLOW/REVIEW/inactive/fail-open behavior,
|
|
338
|
+
collector failure and failed-tool/permission/lifecycle routing remain covered.
|
|
339
|
+
Only loopback fixture endpoints are contacted; no installed hooks or live
|
|
340
|
+
Claude session are modified.
|
|
341
|
+
|
|
240
342
|
`smoke:model` exercises fresh built CJS/ESM hooks with isolated HOME/plugin
|
|
241
343
|
data, no real Claude executable, and no manager/guard calls. Supplied, missing,
|
|
242
344
|
placeholder, correlated, cross-session/subagent, future, partial and oversized
|
package/dist/index.js
CHANGED
|
@@ -1,23 +1,32 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
|
|
3
|
-
`)
|
|
4
|
-
|
|
1
|
+
"use strict";var mn=Object.create;var Le=Object.defineProperty;var hn=Object.getOwnPropertyDescriptor;var gn=Object.getOwnPropertyNames;var _n=Object.getPrototypeOf,yn=Object.prototype.hasOwnProperty;var b=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var vn=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of gn(t))!yn.call(e,o)&&o!==n&&Le(e,o,{get:()=>t[o],enumerable:!(r=hn(t,o))||r.enumerable});return e};var p=(e,t,n)=>(n=e!=null?mn(_n(e)):{},vn(t||!e||!e.__esModule?Le(n,"default",{value:e,enumerable:!0}):n,e));var Ge=b(pe=>{"use strict";Object.defineProperty(pe,"__esModule",{value:!0});pe.mysqlPasswordRanges=An;var En=new Set(["mysql","mysqldump","mysqladmin","mysqlcheck","mysqlimport","mysqlshow","mariadb","mariadb-dump","mariadb-admin","mariadb-check","mariadb-import","mariadb-show"]),Pn=new Set(["sh","bash","dash","zsh","ksh"]),Sn=new Set(["-u","--user","-h","--host","-P","--port","-D","--database","-S","--socket","-e","--execute","--protocol","--default-character-set","--defaults-file","--defaults-extra-file","--login-path","--init-command","--ssl-ca","--ssl-capath","--ssl-cert","--ssl-key","--ssl-cipher"]),W=16;function $e(e,t,n=e.value.length){return{value:e.value.slice(t,n),ranges:e.ranges.slice(t,n)}}function z(e,t,n,r){e.value+=t.value.slice(n,r);for(let o=n;o<r;o++)e.ranges.push(t.ranges[o])}function qe(e){if(e?.literal)return e.value.slice(e.value.lastIndexOf("/")+1).replace(/\.exe$/,"")}function Tn(e){let t=0;for(let n=0;n<=W;n++){for(;/^[A-Za-z_][A-Za-z0-9_]*=/.test(e[t]?.value??"");)t++;let r=qe(e[t]);if(!r)return;if(["!","if","then","elif","else","while","until","do"].includes(r)){t++;continue}let o={env:["-u","--unset","-C","--chdir"],sudo:["-u","--user","-g","--group","-p","--prompt","-D","--chdir","-R","--chroot","-C","--close-from","-T","--command-timeout"],exec:["-a"],nice:["-n","--adjustment"],timeout:["-s","--signal","-k","--kill-after"]},i={env:["-i","--ignore-environment","-0","--null"],sudo:["-n","-E","-H","-S","-b","-k"],command:["-p"],exec:["-c","-l"],nohup:[],nice:[],time:["-p"],timeout:["--foreground","--preserve-status"]};if(!(r in i))return t;for(t++;e[t]?.value.startsWith("-");){let s=e[t++].value;if(s==="--")break;if(!i[r].includes(s)){if((o[r]??[]).includes(s)){if(!e[t++])return;continue}if(!(o[r]??[]).some(a=>a.startsWith("--")?s.startsWith(a+"="):s.startsWith(a)&&s.length>2)&&!(r==="nice"&&/^-\d+$/.test(s)))return}}if(r==="timeout"&&!/^\d+(?:\.\d+)?[smhd]?$/.test(e[t++]?.value??""))return}}function Fe(e,t){let n=1,r="";for(let o=t;o<e.length;o++){let i=e[o];if(i==="\\"&&r!=="'"){o++;continue}if(r){i===r&&(r="");continue}if(i==="'"||i==='"')r=i;else if(i==="(")n++;else if(i===")"&&--n===0)return o}return e.length}function bn(e,t,n,r){let o={value:"",ranges:[],start:t,end:t,literal:!0},i="",s=t;for(;s<e.value.length;){let a=e.value[s];if(!i&&/[\s;|&()<>{}]/.test(a))break;if(a===i){i="",s++;continue}if(!i&&(a==="'"||a==='"')){i=a,s++;continue}if(a==="\\"&&i!=="'"){let c=e.value[s+1];if(c===`
|
|
2
|
+
`){s+=2;continue}if(c&&(!i||/[$`"\\]/.test(c))){z(o,e,s+1,s+2),s+=2;continue}}if(i!=="'"&&e.value.startsWith("$(",s)){let c=Fe(e.value,s+2);e.value[s+2]!=="("&&r<W&&B($e(e,s+2,c),n,r+1),z(o,e,s,Math.min(c+1,e.value.length)),o.literal=!1,s=Math.min(c+1,e.value.length);continue}if(a==="`"&&i!=="'"){let c=s+1;for(;c<e.value.length&&e.value[c]!=="`";)c+=e.value[c]==="\\"?2:1;r<W&&B($e(e,s+1,c),n,r+1),z(o,e,s,Math.min(c+1,e.value.length)),o.literal=!1,s=Math.min(c+1,e.value.length);continue}a==="$"&&i!=="'"&&(o.literal=!1),z(o,e,s,s+1),s++}return o.end=s,o}function On(e,t,n,r){let o=Tn(t);if(o===void 0)return;let i=qe(t[o]);if(Pn.has(i)&&r<W){for(let s=o+1;s<t.length;s++){let a=t[s].value;if(a==="--command"||/^-[a-zA-Z]*c[a-zA-Z]*$/.test(a)){let c=t[s+1];c&&B(c,n,r+1);return}if(!a.startsWith("-")||a==="--")return;(a==="-o"||a==="-O")&&s++}return}if(En.has(i))for(let s=o+1;s<t.length;s++){let a=t[s];if(a.value==="--")return;if(Sn.has(a.value)){s++;continue}a.value.startsWith("-p")&&a.value.length>2&&n.push({start:e.ranges[a.start].start,end:e.ranges[a.end-1].end})}}function B(e,t,n=0){let r=[],o,i=[],s=0,a=()=>{On(e,r,t,n),r=[],o=void 0};for(;s<e.value.length;){let c=e.value[s];if(c===`
|
|
3
|
+
`){a(),s++;for(let l of i.splice(0))for(;s<e.value.length;){let d=e.value.indexOf(`
|
|
4
|
+
`,s),y=d<0?e.value.length:d,v=e.value.slice(s,y);if(s=d<0?y:y+1,(l.stripTabs?v.replace(/^\t+/,""):v)===l.delimiter)break}}else if(/\s/.test(c))s++;else if(c==="#"){let l=e.value.indexOf(`
|
|
5
|
+
`,s);s=l<0?e.value.length:l}else if(e.value.startsWith("((",s))a(),s=Math.min(Fe(e.value,s+1)+1,e.value.length);else if(/[;|&(){}]/.test(c))a(),s++;else if(c==="<"||c===">")r.at(-1)?.end===s&&/^\d+$/.test(r.at(-1).value)&&r.pop(),o=/^(?:<<<|<<-?|>>|<&|>&|[<>])/.exec(e.value.slice(s))?.[0]??c,s+=o.length;else{let l=bn(e,s,t,n);s=l.end,(o==="<<"||o==="<<-")&&i.push({delimiter:l.value,stripTabs:o==="<<-"}),o||r.push(l),o=void 0}}a()}function kn(e,t,n){let r={value:"",ranges:[]};for(let o=t+1;o<n-1;o++){if(e.value[o]!=="\\"){z(r,e,o,o+1);continue}let i=o+(e.value[o+1]==="u"?6:2),s=JSON.parse(`"${e.value.slice(o,i)}"`);r.value+=s;for(let a=0;a<s.length;a++)r.ranges.push({start:e.ranges[o].start,end:e.ranges[i-1].end});o=i-1}return r}function An(e){let t={value:e,ranges:Array.from({length:e.length},(r,o)=>({start:o,end:o+1}))},n=[];if(/^\s*[{[]/.test(e)){let r;try{r=JSON.parse(e)}catch{return B(t,n),n}if(r!==null&&typeof r=="object"){let o=/"(?:[^"\\]|\\.)*"/g,i;for(;i=o.exec(e);){let s=JSON.parse(i[0]);if(s!=="command"&&s!=="cmd"&&s!=="CommandLine")continue;let a=/^\s*:\s*/.exec(e.slice(o.lastIndex));if(!a)continue;let c=o.lastIndex+a[0].length;if(e[c]!=='"')continue;o.lastIndex=c;let l=o.exec(e);l?.index===c&&B(kn(t,c,c+l[0].length),n)}}return n}return B(t,n),n}});var me=b(g=>{"use strict";Object.defineProperty(g,"__esModule",{value:!0});g.PATTERNS=g.MAX_BYTES=void 0;g.truncateTo=Ve;g.truncate=Rn;g.collectMatches=Ye;g.resolveOverlaps=ze;g.applyMatches=Xe;g.redact=Mn;var wn=Ge();g.MAX_BYTES=102400;function Ve(e,t){let n=Buffer.from(e,"utf-8");return n.length<=t?e:`${n.subarray(0,Math.max(0,t)).toString("utf-8")}\u2026[TRUNCATED:${n.length}]`}function Rn(e){return Ve(e,g.MAX_BYTES)}g.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 Ye(e,t){let n=[];for(let r of g.PATTERNS){if(r.requireContext&&r.requireContext!==t.context)continue;if(r.type==="cli_password_short"){for(let{start:s,end:a}of(0,wn.mysqlPasswordRanges)(e))n.push({start:s,end:a,replaceStart:s,replaceEnd:a,type:r.type,replacement:`-p[REDACTED:${r.type}]`});continue}let o=new RegExp(r.regex.source,r.regex.flags),i;for(;(i=o.exec(e))!==null;){let s=r.captureGroup??0,a=i[s];if(a===void 0){i.index===o.lastIndex&&o.lastIndex++;continue}let c=i.index,l=i.index+i[0].length,d=c+i[0].indexOf(a),y=d+a.length;n.push({start:c,end:l,replaceStart:d,replaceEnd:y,type:r.type}),i.index===o.lastIndex&&o.lastIndex++}}return n}function ze(e){let t=[...e].sort((o,i)=>o.start!==i.start?o.start-i.start:i.end-i.start-(o.end-o.start)),n=[],r=-1;for(let o of t)o.start<r||(n.push(o),r=o.end);return n}function Xe(e,t){let n=[...t].sort((o,i)=>i.replaceStart-o.replaceStart),r=e;for(let o of n)r=r.slice(0,o.replaceStart)+(o.replacement??`[REDACTED:${o.type}]`)+r.slice(o.replaceEnd);return r}function Mn(e,t={}){if(e.length===0)return e;let n=Ye(e,t);if(n.length===0)return e;let r=ze(n);return Xe(e,r)}});var ge=b(m=>{"use strict";var Dn=m&&m.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(m,"__esModule",{value:!0});m.MAX_SPAN_BYTES=void 0;m.ulidToTraceId=Je;m.newSpanId=We;m.snakeCase=jn;m.toOtlpValue=Qe;m.attrsFromRecord=In;m.guardAttrs=et;m.clientAttrs=tt;m.enforceSpanBudget=nt;m.buildPayload=Cn;m.attachGuard=rt;m.mergeBatch=Un;var xn=Dn(require("crypto")),he=me(),Nn="0123456789ABCDEFGHJKMNPQRSTVWXYZ";function Je(e){if(e.length!==26)throw new Error(`ulidToTraceId: expected 26 chars, got ${e.length}`);let t=0n;for(let r of e){let o=Nn.indexOf(r);if(o<0)throw new Error(`ulidToTraceId: invalid Crockford char "${r}"`);t=t<<5n|BigInt(o)}let n=(1n<<128n)-1n;return t&=n,t.toString(16).padStart(32,"0")}function We(){return xn.default.randomBytes(8).toString("hex")}function jn(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1_$2").replace(/([A-Z])([A-Z][a-z])/g,"$1_$2").toLowerCase()}var He=new Set;function Q(e,t,n){let r=(0,he.truncate)(t);if((n.skipRedactKeys??He).has(e))return r;let o=(n.bashContextKeys??He).has(e)?"bash":void 0;return(0,he.redact)(r,{context:o})}function Qe(e,t,n={}){if(t==null)return null;switch(typeof t){case"string":return{stringValue:Q(e,t,n)};case"boolean":return{boolValue:t};case"number":return Number.isInteger(t)?{intValue:t}:{doubleValue:t};case"object":try{return{stringValue:Q(e,JSON.stringify(t),n)}}catch{return{stringValue:Q(e,String(t),n)}}default:return{stringValue:Q(e,String(t),n)}}}function In(e,t,n={}){let r=[];for(let[o,i]of Object.entries(e)){let s=`${t}.${o}`,a=Qe(s,i,n);a!==null&&r.push({key:s,value:a})}return r}function et(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 tt(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}}]}m.MAX_SPAN_BYTES=800*1024;function Ke(e){let t=JSON.stringify(e);return t===void 0?0:Buffer.byteLength(t,"utf-8")}var Ze=1024;function nt(e,t=m.MAX_SPAN_BYTES){let n=Ke(e);for(let r=0;r<100&&n>t;r++){let o=null,i=0;for(let c of e.attributes){if(!("stringValue"in c.value))continue;let l=Buffer.byteLength(c.value.stringValue,"utf-8");l>i&&(i=l,o=c.value)}if(o===null||i<=Ze)break;let s=n-t,a=Math.max(Ze,i-s-64);o.stringValue=(0,he.truncateTo)(o.stringValue,a),n=Ke(e)}return e}function Cn(e){let t=e.now??Date.now(),n=(BigInt(t)*1000000n).toString(),r=[...e.attributes],o={traceId:Je(e.traceId),spanId:We(),name:e.spanName,kind:e.spanKind??1,startTimeUnixNano:n,endTimeUnixNano:n,attributes:r};nt(o);let i={resourceSpans:[{resource:{attributes:e.resource},scopeSpans:[{scope:e.scope,spans:[o]}]}]};return rt(i,e.guard,e.clientTiming)}function rt(e,t,n){let r=e.resourceSpans[0]?.scopeSpans[0]?.spans[0];if(!r)return e;t&&r.attributes.push(...et(t));let o=n??(t?.clientRttMs!==void 0?{op:"guard",rttMs:t.clientRttMs}:null);return o&&r.attributes.push(...tt(o)),e}function Un(e){let t=[];for(let n of e)t.push(...n.resourceSpans);return{resourceSpans:t}}});var ot=b(A=>{"use strict";Object.defineProperty(A,"__esModule",{value:!0});A.GUARD_STATUS_REFUSED=A.GUARD_BUDGET_HEADER=void 0;A.evaluateGuard=qn;var Bn=1e4,Ln="pinta-core";A.GUARD_BUDGET_HEADER="x-pinta-guard-budget-ms";function ee(e,t){return{decision:"ALLOW",reason:null,userMessage:null,durationMs:e,clientRttMs:e,failOpenReason:t}}var $n=new Set(["ALLOW","DENY","REVIEW"]);A.GUARD_STATUS_REFUSED=410;async function qn(e,t,n={}){if(!t||n.disabled)return null;let r=n.timeoutMs??Bn,o=Date.now(),i=new AbortController,s=setTimeout(()=>i.abort(),r);try{let a=await fetch(t,{method:"POST",headers:{"content-type":"application/json","user-agent":n.userAgent??Ln,"x-pinta-relay-token":n.token??"",...n.agentType?{"x-pinta-agent-type":n.agentType}:{},...Number.isFinite(r)&&r>0?{[A.GUARD_BUDGET_HEADER]:String(r)}:{}},body:JSON.stringify(e),signal:i.signal});if(a.status===A.GUARD_STATUS_REFUSED)return ee(Date.now()-o,"refused");if(a.status!==200)return ee(Date.now()-o,"error");let c=await a.json(),l=c?.durationMs===void 0||typeof c.durationMs=="number"&&Number.isFinite(c.durationMs);if(!c||!$n.has(c.decision)||!l)return ee(Date.now()-o,"error");let d=Date.now()-o;return{decision:c.decision,reason:c.reason??null,userMessage:c.userMessage??null,durationMs:c.durationMs??d,clientRttMs:d}}catch(a){let c=a.name,l=c==="AbortError"||c==="TimeoutError"?"timeout":"error";return ee(Date.now()-o,l)}finally{clearTimeout(s)}}});var te=b(X=>{"use strict";var Fn=X&&X.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(X,"__esModule",{value:!0});X.atomicWriteFileSync=Gn;var st=Fn(require("fs"));function Gn(e,t){let n=`${e}.${process.pid}.tmp`;st.default.writeFileSync(n,t),st.default.renameSync(n,e)}});var ve=b(R=>{"use strict";var it=R&&R.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(R,"__esModule",{value:!0});R.MemoryRetryQueue=R.DiskRetryQueue=void 0;var _=it(require("fs")),ne=it(require("path")),Vn=te(),re=1e3,Yn=50,zn=5,_e=class{filePath;lockPath;logPrefix;constructor(t,n){this.filePath=ne.default.join(t,"failed-spans.jsonl"),this.lockPath=this.filePath+".lock",this.logPrefix=n}enqueue(t){try{_.default.mkdirSync(ne.default.dirname(this.filePath),{recursive:!0});let n=JSON.stringify({savedAt:new Date().toISOString(),payload:t})+`
|
|
6
|
+
`;_.default.appendFileSync(this.filePath,n),this.trim()}catch(n){process.stderr.write(`[${this.logPrefix}] retry-queue enqueue failed: ${n}
|
|
7
|
+
`)}}readAll(){try{let t=_.default.readFileSync(this.filePath,"utf-8"),n=[];for(let r of t.split(`
|
|
8
|
+
`))if(r.trim())try{let o=JSON.parse(r);Array.isArray(o?.payload?.resourceSpans)&&n.push(o)}catch{}return n}catch{return[]}}rewrite(t){try{if(t.length===0){_.default.existsSync(this.filePath)&&_.default.unlinkSync(this.filePath);return}_.default.mkdirSync(ne.default.dirname(this.filePath),{recursive:!0}),(0,Vn.atomicWriteFileSync)(this.filePath,t.map(n=>JSON.stringify(n)).join(`
|
|
5
9
|
`)+`
|
|
6
10
|
`)}catch(n){process.stderr.write(`[${this.logPrefix}] retry-queue rewrite failed: ${n}
|
|
7
|
-
`)}}tryAcquireLock(){let t=Date.now();try{
|
|
8
|
-
`),!1}for(;Date.now()-t<
|
|
9
|
-
`),!1;try{let i=
|
|
10
|
-
`),this.rewrite(t.slice(n))}};
|
|
11
|
+
`)}}tryAcquireLock(){let t=Date.now();try{_.default.mkdirSync(ne.default.dirname(this.lockPath),{recursive:!0})}catch(n){return process.stderr.write(`[${this.logPrefix}] retry-queue lock mkdir failed: ${n}
|
|
12
|
+
`),!1}for(;Date.now()-t<Yn;)try{let n=_.default.openSync(this.lockPath,"wx");return _.default.writeSync(n,String(process.pid)),_.default.closeSync(n),!0}catch(n){if(n?.code!=="EEXIST")return process.stderr.write(`[${this.logPrefix}] retry-queue lock open failed: ${n}
|
|
13
|
+
`),!1;try{let i=_.default.statSync(this.lockPath);if(Date.now()-i.mtimeMs>3e4){_.default.unlinkSync(this.lockPath);continue}}catch{}let r=zn,o=Date.now()+r;for(;Date.now()<o;);}return!1}release(){try{_.default.unlinkSync(this.lockPath)}catch{}}trim(){let t=this.readAll();if(t.length<=re)return;let n=t.length-re;process.stderr.write(`[${this.logPrefix}] retry-queue full, dropping ${n} oldest entries
|
|
14
|
+
`),this.rewrite(t.slice(n))}};R.DiskRetryQueue=_e;var ye=class{entries=[];enqueue(t){this.entries.push(t),this.entries.length>re&&this.entries.splice(0,this.entries.length-re)}drain(){let t=this.entries;return this.entries=[],t}get size(){return this.entries.length}};R.MemoryRetryQueue=ye});var ft=b(f=>{"use strict";Object.defineProperty(f,"__esModule",{value:!0});f.MemoryTransport=f.DiskTransport=f.MAX_POST_BYTES=void 0;f.parseHeadersEnv=lt;f.envOptionsResolver=dt;f.postOtlp=H;var at=ve(),ut=ge(),Xn=5e3;f.MAX_POST_BYTES=900*1024;function oe(e){let t=JSON.stringify(e);return t===void 0?0:Buffer.byteLength(t,"utf-8")}function ct(e,t,n){let r=[],o=[],i=[],s=0;for(let a of e){let c=t(a);if(c>n){o.push(a);continue}i.length>0&&s+c>n&&(r.push(i),i=[],s=0),i.push(a),s+=c}return i.length>0&&r.push(i),{chunks:r,oversize:o}}function lt(e){if(!e)return{};if(typeof e=="object")return{...e};let t={};for(let n of e.split(",")){let[r,...o]=n.split("=");r&&o.length>0&&(t[r.trim()]=o.join("=").trim())}return t}function dt(){let e=process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,t=process.env.OTEL_EXPORTER_OTLP_ENDPOINT,n;return e?n=e.replace(/\/+$/,""):t&&(n=t.replace(/\/+$/,"")+"/v1/traces"),n?{endpoint:n,headers:lt(process.env.OTEL_EXPORTER_OTLP_HEADERS)}:null}async function H(e,t,n){let r=new AbortController,o=setTimeout(()=>r.abort(),Xn);try{let i=await fetch(t.endpoint,{method:"POST",headers:{"Content-Type":"application/json",...t.headers},body:JSON.stringify(e),signal:r.signal});if(!i.ok){let s="";try{s=(await i.text()).slice(0,200)}catch{}let a=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(`[${n}] OTLP POST ${i.status} ${t.endpoint}${a}${s?` body=${s}`:""}
|
|
11
15
|
`),!1}return!0}catch(i){return process.stderr.write(`[${n}] OTLP POST failed: ${i.message??String(i)}
|
|
12
|
-
`),!1}finally{clearTimeout(o)}}var
|
|
13
|
-
`);let i=[].concat(...r),
|
|
14
|
-
`)}finally{this.queue.release()}}dropIfOversized(t){let n=
|
|
15
|
-
`),!0)}};
|
|
16
|
-
`);return}await
|
|
17
|
-
`);let i=[].concat(...r),
|
|
18
|
-
`)}}};
|
|
19
|
-
`)){let r=n.trim();if(!r||r.startsWith("#"))continue;let o=r.indexOf("=");if(o<0)continue;let i=r.slice(0,o).trim(),
|
|
20
|
-
`)}function
|
|
21
|
-
`)}
|
|
22
|
-
`)}
|
|
23
|
-
`)
|
|
16
|
+
`),!1}finally{clearTimeout(o)}}var Ee=class{queue;logPrefix;resolveOptions;constructor(t){this.queue=new at.DiskRetryQueue(t.pluginData,t.logPrefix),this.logPrefix=t.logPrefix,this.resolveOptions=t.resolveOptions??dt}async send(t){let n=this.resolveOptions();if(!n||this.dropIfOversized(t))return;await H(t,n,this.logPrefix)||this.queue.enqueue(t)}async flush(){let t=this.resolveOptions();if(t&&this.queue.tryAcquireLock())try{let n=this.queue.readAll();if(n.length===0)return;let{chunks:r,oversize:o}=ct(n,a=>oe(a.payload),f.MAX_POST_BYTES);o.length>0&&process.stderr.write(`[${this.logPrefix}] dropping ${o.length} oversized retry ${o.length===1?"entry":"entries"} (each > ${f.MAX_POST_BYTES} bytes \u2014 the backend caps the request body, so they can never be delivered)
|
|
17
|
+
`);let i=[].concat(...r),s=0;for(let a of r){if(!await H((0,ut.mergeBatch)(a.map(l=>l.payload)),t,this.logPrefix))break;s+=a.length}this.queue.rewrite(i.slice(s))}catch(n){process.stderr.write(`[${this.logPrefix}] flush failed: ${n?.message??String(n)}
|
|
18
|
+
`)}finally{this.queue.release()}}dropIfOversized(t){let n=oe(t);return n<=f.MAX_POST_BYTES?!1:(process.stderr.write(`[${this.logPrefix}] dropping oversized span payload (${n} > ${f.MAX_POST_BYTES} bytes) \u2014 undeliverable, not queued
|
|
19
|
+
`),!0)}};f.DiskTransport=Ee;var Pe=class{queue=new at.MemoryRetryQueue;logPrefix;resolveOptions;constructor(t){this.logPrefix=t.logPrefix,this.resolveOptions=t.resolveOptions}async send(t){let n=this.resolveOptions();if(!n)return;if(oe(t)>f.MAX_POST_BYTES){process.stderr.write(`[${this.logPrefix}] dropping oversized span payload (> ${f.MAX_POST_BYTES} bytes) \u2014 undeliverable, not buffered
|
|
20
|
+
`);return}await H(t,n,this.logPrefix)||this.queue.enqueue(t)}async flush(){let t=this.resolveOptions();if(!t)return;let n=this.queue.drain();if(n.length===0)return;let{chunks:r,oversize:o}=ct(n,oe,f.MAX_POST_BYTES);o.length>0&&process.stderr.write(`[${this.logPrefix}] dropping ${o.length} oversized buffered ${o.length===1?"payload":"payloads"} (each > ${f.MAX_POST_BYTES} bytes \u2014 undeliverable)
|
|
21
|
+
`);let i=[].concat(...r),s=0;for(let a of r){if(!await H((0,ut.mergeBatch)(a),t,this.logPrefix))break;s+=a.length}for(let a of i.slice(s))this.queue.enqueue(a)}};f.MemoryTransport=Pe});var Oe=b(N=>{"use strict";var be=N&&N.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(N,"__esModule",{value:!0});N.TraceManager=void 0;N.generateUlid=mt;var pt=be(require("fs")),Hn=be(require("path")),Kn=be(require("crypto")),Zn=te(),Se="0123456789ABCDEFGHJKMNPQRSTVWXYZ";function mt(){let e=Date.now(),t="",n=e;for(let i=0;i<10;i++)t=Se[n&31]+t,n=Math.floor(n/32);let r=Kn.default.randomBytes(10),o="";for(let i=0;i<10;i++)o+=Se[r[i]&31];for(;o.length<16;)o+=Se[0];return t+o}var Te=class{tracePath;constructor(t){this.tracePath=t}newTrace(){let t=mt();return this.save(t),t}currentTrace(){try{let t=pt.default.readFileSync(this.tracePath,"utf-8"),{traceId:n}=JSON.parse(t);if(n)return n}catch{}return this.newTrace()}save(t){try{pt.default.mkdirSync(Hn.default.dirname(this.tracePath),{recursive:!0}),(0,Zn.atomicWriteFileSync)(this.tracePath,JSON.stringify({traceId:t}))}catch(n){process.stderr.write(`[pinta-core] trace persistence failed: ${n}
|
|
22
|
+
`)}}};N.TraceManager=Te});var vt=b(M=>{"use strict";var gt=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 ht=gt(require("fs")),Jn=gt(require("path")),_t=Oe(),Wn=te(),yt=200,ke=class{tracePath;maxSessions;constructor(t,n={}){this.tracePath=t,this.maxSessions=n.maxSessions??yt}read(){try{let t=JSON.parse(ht.default.readFileSync(this.tracePath,"utf-8"));if(t&&typeof t=="object"&&!("traceId"in t))return t}catch{}return{}}write(t){try{ht.default.mkdirSync(Jn.default.dirname(this.tracePath),{recursive:!0});let n=Object.entries(t),r=n.length>this.maxSessions?Object.fromEntries(n.slice(-this.maxSessions)):t;(0,Wn.atomicWriteFileSync)(this.tracePath,JSON.stringify(r))}catch{}}newTrace(t){let n=t||"default",r=(0,_t.generateUlid)(),o=this.read();return o[n]=r,this.write(o),r}currentTrace(t){let n=t||"default",r=this.read()[n];return r||this.newTrace(n)}};M.DiskSessionTraceManager=ke;var Ae=class{map=new Map;maxSessions;constructor(t={}){this.maxSessions=t.maxSessions??yt}newTrace(t){let n=t||"default",r=(0,_t.generateUlid)();if(this.map.set(n,r),this.map.size>this.maxSessions){let o=this.map.keys().next().value;o!==void 0&&this.map.delete(o)}return r}currentTrace(t){let n=t||"default";return this.map.get(n)??this.newTrace(n)}};M.MemorySessionTraceManager=Ae});var St=b(j=>{"use strict";var we=j&&j.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(j,"__esModule",{value:!0});j.envFilePath=tr;j.parseEnvFile=Pt;j.loadEnvFile=nr;var Qn=we(require("node:fs")),er=we(require("node:os")),Et=we(require("node:path"));function tr(e,t,n){let r=n?process.env[n]:void 0,o=r&&r.length>0?r:Et.default.join(er.default.homedir(),e);return Et.default.join(o,t)}function Pt(e){let t={};for(let n of e.split(`
|
|
23
|
+
`)){let r=n.trim();if(!r||r.startsWith("#"))continue;let o=r.indexOf("=");if(o<0)continue;let i=r.slice(0,o).trim(),s=r.slice(o+1).trim();(s.startsWith('"')&&s.endsWith('"')||s.startsWith("'")&&s.endsWith("'"))&&(s=s.slice(1,-1)),i&&(t[i]=s)}return t}function nr(e){let t;try{t=Qn.default.readFileSync(e,"utf-8")}catch{return}let n=Pt(t);for(let[r,o]of Object.entries(n))process.env[r]===void 0&&(process.env[r]=o)}});var O=b(u=>{"use strict";Object.defineProperty(u,"__esModule",{value:!0});u.loadEnvFile=u.parseEnvFile=u.envFilePath=u.MemorySessionTraceManager=u.DiskSessionTraceManager=u.generateUlid=u.TraceManager=u.MAX_POST_BYTES=u.parseHeadersEnv=u.envOptionsResolver=u.postOtlp=u.MemoryTransport=u.DiskTransport=u.MemoryRetryQueue=u.DiskRetryQueue=u.GUARD_BUDGET_HEADER=u.GUARD_STATUS_REFUSED=u.evaluateGuard=u.MAX_SPAN_BYTES=u.enforceSpanBudget=u.mergeBatch=u.attachGuard=u.buildPayload=u.clientAttrs=u.guardAttrs=u.attrsFromRecord=u.toOtlpValue=u.snakeCase=u.newSpanId=u.ulidToTraceId=u.MAX_BYTES=u.PATTERNS=u.applyMatches=u.resolveOverlaps=u.collectMatches=u.truncateTo=u.truncate=u.redact=void 0;var D=me();Object.defineProperty(u,"redact",{enumerable:!0,get:function(){return D.redact}});Object.defineProperty(u,"truncate",{enumerable:!0,get:function(){return D.truncate}});Object.defineProperty(u,"truncateTo",{enumerable:!0,get:function(){return D.truncateTo}});Object.defineProperty(u,"collectMatches",{enumerable:!0,get:function(){return D.collectMatches}});Object.defineProperty(u,"resolveOverlaps",{enumerable:!0,get:function(){return D.resolveOverlaps}});Object.defineProperty(u,"applyMatches",{enumerable:!0,get:function(){return D.applyMatches}});Object.defineProperty(u,"PATTERNS",{enumerable:!0,get:function(){return D.PATTERNS}});Object.defineProperty(u,"MAX_BYTES",{enumerable:!0,get:function(){return D.MAX_BYTES}});var E=ge();Object.defineProperty(u,"ulidToTraceId",{enumerable:!0,get:function(){return E.ulidToTraceId}});Object.defineProperty(u,"newSpanId",{enumerable:!0,get:function(){return E.newSpanId}});Object.defineProperty(u,"snakeCase",{enumerable:!0,get:function(){return E.snakeCase}});Object.defineProperty(u,"toOtlpValue",{enumerable:!0,get:function(){return E.toOtlpValue}});Object.defineProperty(u,"attrsFromRecord",{enumerable:!0,get:function(){return E.attrsFromRecord}});Object.defineProperty(u,"guardAttrs",{enumerable:!0,get:function(){return E.guardAttrs}});Object.defineProperty(u,"clientAttrs",{enumerable:!0,get:function(){return E.clientAttrs}});Object.defineProperty(u,"buildPayload",{enumerable:!0,get:function(){return E.buildPayload}});Object.defineProperty(u,"attachGuard",{enumerable:!0,get:function(){return E.attachGuard}});Object.defineProperty(u,"mergeBatch",{enumerable:!0,get:function(){return E.mergeBatch}});Object.defineProperty(u,"enforceSpanBudget",{enumerable:!0,get:function(){return E.enforceSpanBudget}});Object.defineProperty(u,"MAX_SPAN_BYTES",{enumerable:!0,get:function(){return E.MAX_SPAN_BYTES}});var Re=ot();Object.defineProperty(u,"evaluateGuard",{enumerable:!0,get:function(){return Re.evaluateGuard}});Object.defineProperty(u,"GUARD_STATUS_REFUSED",{enumerable:!0,get:function(){return Re.GUARD_STATUS_REFUSED}});Object.defineProperty(u,"GUARD_BUDGET_HEADER",{enumerable:!0,get:function(){return Re.GUARD_BUDGET_HEADER}});var Tt=ve();Object.defineProperty(u,"DiskRetryQueue",{enumerable:!0,get:function(){return Tt.DiskRetryQueue}});Object.defineProperty(u,"MemoryRetryQueue",{enumerable:!0,get:function(){return Tt.MemoryRetryQueue}});var L=ft();Object.defineProperty(u,"DiskTransport",{enumerable:!0,get:function(){return L.DiskTransport}});Object.defineProperty(u,"MemoryTransport",{enumerable:!0,get:function(){return L.MemoryTransport}});Object.defineProperty(u,"postOtlp",{enumerable:!0,get:function(){return L.postOtlp}});Object.defineProperty(u,"envOptionsResolver",{enumerable:!0,get:function(){return L.envOptionsResolver}});Object.defineProperty(u,"parseHeadersEnv",{enumerable:!0,get:function(){return L.parseHeadersEnv}});Object.defineProperty(u,"MAX_POST_BYTES",{enumerable:!0,get:function(){return L.MAX_POST_BYTES}});var bt=Oe();Object.defineProperty(u,"TraceManager",{enumerable:!0,get:function(){return bt.TraceManager}});Object.defineProperty(u,"generateUlid",{enumerable:!0,get:function(){return bt.generateUlid}});var Ot=vt();Object.defineProperty(u,"DiskSessionTraceManager",{enumerable:!0,get:function(){return Ot.DiskSessionTraceManager}});Object.defineProperty(u,"MemorySessionTraceManager",{enumerable:!0,get:function(){return Ot.MemorySessionTraceManager}});var Me=St();Object.defineProperty(u,"envFilePath",{enumerable:!0,get:function(){return Me.envFilePath}});Object.defineProperty(u,"parseEnvFile",{enumerable:!0,get:function(){return Me.parseEnvFile}});Object.defineProperty(u,"loadEnvFile",{enumerable:!0,get:function(){return Me.loadEnvFile}})});var K=p(O());function rr(){return(0,K.envFilePath)(".claude","pinta-cc.env")}function kt(e=rr()){(0,K.loadEnvFile)(e)}function At(){process.env.CLAUDE_PLUGIN_OPTION_ENDPOINT&&!process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT&&(process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=process.env.CLAUDE_PLUGIN_OPTION_ENDPOINT),process.env.CLAUDE_PLUGIN_OPTION_API_KEY&&!process.env.OTEL_EXPORTER_OTLP_HEADERS&&(process.env.OTEL_EXPORTER_OTLP_HEADERS=`x-pinta-relay-token=${process.env.CLAUDE_PLUGIN_OPTION_API_KEY}`),!process.env.PINTA_RELAY_TOKEN&&process.env.CLAUDE_PLUGIN_OPTION_API_KEY&&(process.env.PINTA_RELAY_TOKEN=process.env.CLAUDE_PLUGIN_OPTION_API_KEY)}var De=p(require("path")),wt=p(O());function Rt(){let e=process.env.CLAUDE_PLUGIN_ROOT||process.cwd(),t=process.env.CLAUDE_PLUGIN_DATA||De.default.join(e,".plugin-data");return{pluginRoot:e,pluginData:t,tracePath:De.default.join(t,"trace.json")}}function se(){return(0,wt.envOptionsResolver)()!==null}function Mt(e){return e.hook_event_name==="PreToolUse"}function Dt(e){return e.hook_event_name==="PostToolUse"||e.hook_event_name==="PostToolUseFailure"}function xt(e){return e.hook_event_name==="PostToolBatch"}function Nt(e){return e.hook_event_name==="UserPromptSubmit"}function jt(e){return e.hook_event_name==="SessionStart"||e.hook_event_name==="SessionEnd"}function It(e){return e.hook_event_name==="SubagentStart"||e.hook_event_name==="SubagentStop"}function Ct(e){return e.hook_event_name==="Stop"}function Ut(e){return e.hook_event_name==="PermissionRequest"||e.hook_event_name==="PermissionDenied"}var or=new Set(["Notification","TaskCreated","TaskCompleted"]);function Bt(e){return or.has(e.hook_event_name)}var nn=p(O());var Lt=p(O()),sr=1e4,ir="pinta-cc/1.10.2";function $(e,t){return(0,Lt.evaluateGuard)(e,t,{timeoutMs:sr,token:process.env.PINTA_RELAY_TOKEN??"",disabled:process.env.PINTA_GUARD_DISABLED==="1",userAgent:ir})}var Z=p(O());var $t=p(O()),ie=class extends $t.DiskTransport{constructor(t){super({pluginData:t.pluginData,logPrefix:"pinta-cc"})}};var qt=p(O()),ae=class extends qt.TraceManager{constructor(t){super(t.tracePath)}};var fe=p(require("os"));var Vt=require("node:child_process"),ue=require("node:crypto"),P=p(require("node:fs")),Yt=p(require("node:os")),h=p(require("node:path")),zt=/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/,ar=/^v?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?)\s+\(Claude Code\)$/m,ur=2e3,cr=24*60*60*1e3,lr=3e4,Ne=8,Xt="claude-version.json",q=new Map;function w(e){return typeof e=="object"&&e!==null&&"code"in e&&typeof e.code=="string"?e.code:"UNKNOWN"}function S(e){process.stderr.write(`[pinta-cc] CLI version: ${e}
|
|
24
|
+
`)}function ce(e){return w(e)==="ENOENT"||w(e)==="ENOTDIR"}function dr(){let e=process.env.CLAUDE_CODE_EXECPATH,t=process.platform==="win32"?["claude.exe","claude.cmd"]:["claude"],n;if(e)n=[e];else{let r=(process.env.PATH??"").split(h.default.delimiter).filter(o=>h.default.isAbsolute(o));try{r.push(h.default.join(Yt.default.homedir(),".local","bin"))}catch(o){S(`native install directory lookup failed (${w(o)})`)}n=r.flatMap(o=>t.map(i=>h.default.join(o,i)))}for(let r of new Set(n))try{let o=P.default.realpathSync(r),i=P.default.statSync(o);if(!i.isFile())continue;return!e&&process.platform!=="win32"&&P.default.accessSync(o,P.default.constants.X_OK),{file:o,fingerprint:(0,ue.createHash)("sha256").update(JSON.stringify([o,i.ino,i.size,i.mtimeMs,i.ctimeMs])).digest("hex")}}catch(o){ce(o)||S(`executable lookup failed (${w(o)})`)}return S(e?"configured executable is unavailable":"no Claude executable found in PATH or ~/.local/bin"),null}function xe(e){let t;try{t=JSON.parse(P.default.readFileSync(e,"utf8"))}catch(n){return ce(n)||S(`package metadata could not be read (${n instanceof SyntaxError?"INVALID_JSON":w(n)})`),null}return typeof t!="object"||t===null||!("name"in t)||!("version"in t)||typeof t.name!="string"||typeof t.version!="string"||!zt.test(t.version)?null:t.name==="@anthropic-ai/claude-code"||t.name.startsWith("@anthropic-ai/claude-code-")?t.version:null}function fr(e){let t=h.default.dirname(e),n=h.default.basename(t)===".bin"&&/^claude(?:\.cmd)?$/i.test(h.default.basename(e));for(let r=0;r<6;r++){let o=xe(h.default.join(t,"package.json"));if(o)return o;if(h.default.basename(e).toLowerCase()==="claude.cmd"&&r===0){let s=xe(h.default.join(t,"node_modules","@anthropic-ai","claude-code","package.json"));if(s)return s}if(n&&h.default.basename(t)==="node_modules"){let s=xe(h.default.join(t,"@anthropic-ai","claude-code","package.json"));if(s)return s}let i=h.default.dirname(t);if(i===t)break;t=i}return null}function pr(e){return typeof e=="object"&&e!==null&&"fingerprint"in e&&typeof e.fingerprint=="string"&&/^[0-9a-f]{64}$/.test(e.fingerprint)&&"version"in e&&(e.version===null||typeof e.version=="string"&&zt.test(e.version))&&"checkedAt"in e&&typeof e.checkedAt=="number"&&Number.isFinite(e.checkedAt)}function Ft(e,t){let n=t-e.checkedAt;return n>=0&&n<(e.version===null?lr:cr)}function mr(e){if(!e)return[];let t=h.default.join(e,Xt);try{if(P.default.statSync(t).size>16384)return S("oversized version cache ignored"),[];let n=JSON.parse(P.default.readFileSync(t,"utf8"));if(Array.isArray(n)&&n.length<=Ne&&n.every(pr))return n;S("invalid version cache ignored")}catch(n){ce(n)||S(`version cache read failed (${n instanceof SyntaxError?"INVALID_JSON":w(n)})`)}return[]}function Gt(e){for(q.delete(e.fingerprint),q.set(e.fingerprint,e);q.size>Ne;){let t=q.keys().next().value;t!==void 0&&q.delete(t)}}function hr(e,t){if(!e)return;let n=h.default.join(e,Xt),r=`${n}.${process.pid}.${(0,ue.randomUUID)()}.tmp`;try{P.default.mkdirSync(e,{recursive:!0,mode:448}),P.default.writeFileSync(r,JSON.stringify(t),{encoding:"utf8",mode:384,flag:"wx"}),P.default.renameSync(r,n)}catch(o){S(`version cache write failed (${w(o)})`)}finally{try{P.default.unlinkSync(r)}catch(o){ce(o)||S(`temporary version cache cleanup failed (${w(o)})`)}}}function gr(e){if(/\.(cmd|bat|ps1)$/i.test(e))return S("command shim has no readable Claude package metadata"),null;let t=(0,Vt.spawnSync)(e,["--version"],{encoding:"utf8",stdio:["ignore","pipe","pipe"],shell:!1,windowsHide:!0,timeout:ur,killSignal:"SIGKILL",maxBuffer:4096});if(t.error||t.status!==0)return S(`version probe failed (${t.error?w(t.error):`exit ${t.status??t.signal}`})`),null;let n=ar.exec(t.stdout.trim())?.[1];return n||(S("version probe did not identify Claude Code"),null)}function Ht(e){let t=dr();if(!t)return"unknown";let n=fr(t.file);if(n)return n;let r=Date.now(),o=mr(e),i=[q.get(t.fingerprint),...o].find(a=>a&&a.fingerprint===t.fingerprint&&Ft(a,r));if(i)return Gt(i),i.version??"unknown";let s={fingerprint:t.fingerprint,version:gr(t.file),checkedAt:Date.now()};return Gt(s),hr(e,[...o.filter(a=>a.fingerprint!==s.fingerprint&&Ft(a,s.checkedAt)),s].slice(-Ne)),s.version??"unknown"}var x=p(require("node:path"));var k=p(require("node:fs")),je=p(require("node:path")),_r=new Set(["","unknown","undefined","null","n/a","none","auto","default"]),yr=256*1024,vr=1024*1024,Er=4096;function I(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)?e:void 0}function Ie(e){let t=I(e),n=t?"id"in t?t.id:t.name:e;if(typeof n!="string")return;let r=n.trim();if(!(r.startsWith("{")||r.startsWith("[")))return r.length<=512&&!/[\u0000-\u001f\u007f]/.test(r)&&!_r.has(r.toLowerCase())?r:void 0}function Kt(e,t){delete e.model,t&&(e.model=t.name,!(t.source==="hook.model"&&e.model_source!==void 0)&&(e.model_source!==void 0&&(e.model_original_source=e.model_source),e.model_source=t.source))}function F(e){return typeof e=="string"&&/^[A-Za-z0-9][A-Za-z0-9_.:-]{0,255}$/.test(e)?e:void 0}function le(e){let t=typeof e=="number"?e:typeof e=="string"&&/^\d{4}-\d{2}-\d{2}T/.test(e)?Date.parse(e):NaN;return Number.isFinite(t)&&t>=0?t:void 0}function Zt(e,t){let n=e.timestamp===void 0?le(t):le(e.timestamp);return n!==void 0&&n<=t?n:void 0}function Jt(e){if(typeof e!="string"||e.length>4096||/[\u0000-\u001f]/.test(e)||!je.default.isAbsolute(e)||je.default.extname(e)!==".jsonl")return;let t;try{t=k.default.openSync(e,k.default.constants.O_RDONLY|k.default.constants.O_NONBLOCK|(k.default.constants.O_NOFOLLOW??0));let n=k.default.fstatSync(t);if(!n.isFile()||!Number.isSafeInteger(n.size)||n.size<=0)return;let r=Buffer.alloc(Math.min(n.size,yr));if(k.default.readSync(t,r,0,r.length,0)!==r.length)return;let o=r.indexOf(10),i;if(o>=0)try{i=I(JSON.parse(r.toString("utf8",0,o)))}catch{}let s=Math.max(0,n.size-vr),a=n.size<=r.length?r:Buffer.alloc(n.size-s);if(a!==r&&k.default.readSync(t,a,0,a.length,s)!==a.length)return;let c=k.default.fstatSync(t);if(c.size<n.size||c.size===n.size&&c.mtimeMs!==n.mtimeMs)return;let l=s>0?a.indexOf(10)+1:0,d=a.lastIndexOf(10);if(s>0&&l===0||d<l)return;let y=[],v=0;for(;d>l&&v<Er;){let J=a.lastIndexOf(10,d-1),Y=Math.max(l,J+1),Ue=a.toString("utf8",Y,d).trim();if(Ue){let Be=I(JSON.parse(Ue));Be&&y.push(Be)}d=Y-1,v++}return y.reverse(),{first:i,rows:y,complete:s===0&&d<0&&a[a.length-1]===10}}catch{return}finally{if(t!==void 0)try{k.default.closeSync(t)}catch{}}}function Wt(e){let t=e[0];return t&&e.every(n=>n?.name===t.name)?t:void 0}var Pr=new Set(["PreToolUse","PostToolUse","PostToolUseFailure","PermissionRequest","PermissionDenied"]);function Sr(e,t){let n=x.default.dirname(e);if(x.default.basename(n)!=="subagents"||x.default.basename(x.default.dirname(n))!==t)return;let r=/^agent-(.+)\.jsonl$/.exec(x.default.basename(e));return F(r?.[1])}function Qt(e,t){let n=Ie(e.model);if(n)return{name:n,source:"hook.model"};try{return Tr(e,t)}catch{return}}function Tr(e,t){if(!Pr.has(e.hook_event_name))return;let n=F(e.session_id),r=F(e.tool_use_id),o=Zt(e,t);if(!n||!r||o===void 0||typeof e.transcript_path!="string")return;let i=Sr(e.transcript_path,n),s=e.agent_id===void 0?i:F(e.agent_id);if(e.agent_id!==void 0&&!s||i!==void 0&&i!==s||!s&&e.agent_type!==void 0||x.default.basename(x.default.dirname(e.transcript_path))==="subagents"&&!i)return;let a=Jt(e.transcript_path);if(!a)return;let c=[];for(let l of a.rows){let d=le(l.timestamp);if(l.type!=="assistant"||l.sessionId!==n||d===void 0||d>o)continue;let y=l.agentId===void 0?void 0:F(l.agentId);if(y!==s||l.agentId!==void 0&&!y||l.isSidechain===!0&&!s)continue;let v=I(l.message);if(!v||v.role!==void 0&&v.role!=="assistant"||!Array.isArray(v.content)||!v.content.some(Y=>I(Y)?.type==="tool_use"&&I(Y)?.id===r))continue;let J=Ie(v.model);c.push(J?{name:J,source:"transcript.assistant.message"}:void 0)}return Wt(c)}var G=p(O()),de;function br(){if(de===void 0)try{de=fe.default.userInfo().username}catch{de=process.env.USER??process.env.LOGNAME??(typeof process.getuid=="function"?String(process.getuid()):"unknown")}return de}var en="1.10.2",Or=new Set(["cc.hook","cc.tool_name","cc.tool_use_id","cc.session_id","cc.transcript_path","cc.cwd","cc.permission_mode"]),kr=new Set(["cc.tool_input","cc.tool_response","cc.tool_calls"]),Ar={skipRedactKeys:Or,bashContextKeys:kr};function wr(e,t){let n=[];n.push({key:"ingest.type",value:{stringValue:"cc"}}),n.push({key:"cc.hook",value:{stringValue:e.hook_event_name}});let r={};for(let[o,i]of Object.entries(e))o!=="hook_event_name"&&(r[o]=i);return Kt(r,Qt(e,t)),n.push(...(0,G.attrsFromRecord)(r,"cc",Ar)),n}function Rr(e){return[{key:"service.name",value:{stringValue:"claude-code"}},{key:"service.version",value:{stringValue:Ht(e)}},{key:"telemetry.sdk.name",value:{stringValue:"pinta-cc"}},{key:"telemetry.sdk.language",value:{stringValue:"nodejs"}},{key:"telemetry.sdk.version",value:{stringValue:en}},{key:"process.pid",value:{intValue:process.pid}},{key:"process.owner",value:{stringValue:br()}},{key:"host.name",value:{stringValue:fe.default.hostname()}},{key:"host.arch",value:{stringValue:fe.default.arch()}}]}function tn(e){let t=e.now??Date.now();return(0,G.buildPayload)({traceId:e.traceId,spanName:`cc.${(0,G.snakeCase)(e.event.hook_event_name)}`,attributes:wr(e.event,t),resource:Rr(e.versionCacheDir),scope:{name:"pinta-cc",version:en},now:t})}function C(e,t,n={}){let r=new ae(t),o=n.traceMode==="new"?r.newTrace():r.currentTrace();return tn({event:e,traceId:o,versionCacheDir:t.pluginData})}async function U(e,t){if(!se())return;let n=new ie(t);await n.flush(),await n.send(e)}function V(e,t){if(!se())return;let n=Buffer.byteLength(JSON.stringify(e),"utf-8");if(n>Z.MAX_POST_BYTES){process.stderr.write(`[pinta-cc] dropping oversized span payload (${n} > ${Z.MAX_POST_BYTES} bytes) \u2014 undeliverable, not queued
|
|
25
|
+
`);return}new Z.DiskRetryQueue(t.pluginData,"pinta-cc").enqueue(e)}async function T(e,t,n={}){se()&&await U(C(e,t,n),t)}async function rn(e,t){let n=C(e,t),r=await $(n,process.env.PINTA_GUARD_ENDPOINT);if(r?.decision==="DENY"){let i={hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:r.userMessage??r.reason??"guard_deny"}};process.stdout.write(JSON.stringify(i)+`
|
|
26
|
+
`)}try{if((0,nn.attachGuard)(n,r),r?.decision==="DENY")return V(n,t),0;await U(n,t)}catch(o){process.stderr.write(`[pinta-cc] telemetry emit failed: ${o}
|
|
27
|
+
`)}return 0}var on=p(O());async function sn(e,t){if(e.hook_event_name==="PostToolUseFailure")return await T(e,t),0;let n=C(e,t),r=await $(n,process.env.PINTA_GUARD_ENDPOINT);r?.decision==="DENY"&&process.stdout.write(JSON.stringify({continue:!1,stopReason:"Pinta blocked this tool output. Start a new session before continuing."})+`
|
|
28
|
+
`);try{if((0,on.attachGuard)(n,r),r&&n.resourceSpans[0].scopeSpans[0].spans[0].attributes.push({key:"pinta.guard.target",value:{stringValue:"tool_output"}}),r?.decision==="DENY")return V(n,t),0;await U(n,t)}catch(o){process.stderr.write(`[pinta-cc] telemetry emit failed: ${o}
|
|
29
|
+
`)}return 0}async function an(e,t){return await T(e,t,{traceMode:"new"}),0}async function un(e,t){return await T(e,t),0}async function cn(e,t){return await T(e,t),0}async function ln(e,t){return await T(e,t),0}var dn=p(O());async function fn(e,t){if(e.hook_event_name==="PermissionDenied")return await T(e,t),0;let n=C(e,t),r=await $(n,process.env.PINTA_GUARD_ENDPOINT);r?.decision==="DENY"&&process.stdout.write(JSON.stringify({hookSpecificOutput:{hookEventName:"PermissionRequest",decision:{behavior:"deny",message:r.userMessage??r.reason??"guard_deny"}}})+`
|
|
30
|
+
`);try{if((0,dn.attachGuard)(n,r),r?.decision==="DENY")return V(n,t),0;await U(n,t)}catch(o){process.stderr.write(`[pinta-cc] telemetry emit failed: ${o}
|
|
31
|
+
`)}return 0}async function Ce(e){return 0}async function Mr(){let e=[];for await(let t of process.stdin)e.push(t);return Buffer.concat(e).toString("utf-8")}async function pn(){At();let e=0;try{let t=Rt(),n=await Mr(),r=JSON.parse(n);Bt(r)?e=await Ce(r):Mt(r)?e=await rn(r,t):Dt(r)||xt(r)?e=await sn(r,t):Nt(r)?e=await an(r,t):jt(r)?e=await un(r,t):It(r)?e=await cn(r,t):Ct(r)?e=await ln(r,t):Ut(r)?e=await fn(r,t):e=await Ce(r)}catch(t){process.stderr.write(`[pinta-cc] error: ${t}
|
|
32
|
+
`),e=0}return e}kt();async function Dr(){let e=await pn();process.exit(e)}Dr();
|
package/dist/index.mjs
CHANGED
|
@@ -1,24 +1,33 @@
|
|
|
1
1
|
import{createRequire as __pintaCreateRequire}from 'node:module';const require=__pintaCreateRequire(import.meta.url);
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
`)
|
|
5
|
-
|
|
2
|
+
var gn=Object.create;var Be=Object.defineProperty;var _n=Object.getOwnPropertyDescriptor;var yn=Object.getOwnPropertyNames;var vn=Object.getPrototypeOf,En=Object.prototype.hasOwnProperty;var v=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,n)=>(typeof require<"u"?require:t)[n]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var T=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Pn=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of yn(t))!En.call(e,o)&&o!==n&&Be(e,o,{get:()=>t[o],enumerable:!(r=_n(t,o))||r.enumerable});return e};var k=(e,t,n)=>(n=e!=null?gn(vn(e)):{},Pn(t||!e||!e.__esModule?Be(n,"default",{value:e,enumerable:!0}):n,e));var qe=T(pe=>{"use strict";Object.defineProperty(pe,"__esModule",{value:!0});pe.mysqlPasswordRanges=Rn;var Sn=new Set(["mysql","mysqldump","mysqladmin","mysqlcheck","mysqlimport","mysqlshow","mariadb","mariadb-dump","mariadb-admin","mariadb-check","mariadb-import","mariadb-show"]),Tn=new Set(["sh","bash","dash","zsh","ksh"]),bn=new Set(["-u","--user","-h","--host","-P","--port","-D","--database","-S","--socket","-e","--execute","--protocol","--default-character-set","--defaults-file","--defaults-extra-file","--login-path","--init-command","--ssl-ca","--ssl-capath","--ssl-cert","--ssl-key","--ssl-cipher"]),ee=16;function Le(e,t,n=e.value.length){return{value:e.value.slice(t,n),ranges:e.ranges.slice(t,n)}}function X(e,t,n,r){e.value+=t.value.slice(n,r);for(let o=n;o<r;o++)e.ranges.push(t.ranges[o])}function $e(e){if(e?.literal)return e.value.slice(e.value.lastIndexOf("/")+1).replace(/\.exe$/,"")}function On(e){let t=0;for(let n=0;n<=ee;n++){for(;/^[A-Za-z_][A-Za-z0-9_]*=/.test(e[t]?.value??"");)t++;let r=$e(e[t]);if(!r)return;if(["!","if","then","elif","else","while","until","do"].includes(r)){t++;continue}let o={env:["-u","--unset","-C","--chdir"],sudo:["-u","--user","-g","--group","-p","--prompt","-D","--chdir","-R","--chroot","-C","--close-from","-T","--command-timeout"],exec:["-a"],nice:["-n","--adjustment"],timeout:["-s","--signal","-k","--kill-after"]},i={env:["-i","--ignore-environment","-0","--null"],sudo:["-n","-E","-H","-S","-b","-k"],command:["-p"],exec:["-c","-l"],nohup:[],nice:[],time:["-p"],timeout:["--foreground","--preserve-status"]};if(!(r in i))return t;for(t++;e[t]?.value.startsWith("-");){let s=e[t++].value;if(s==="--")break;if(!i[r].includes(s)){if((o[r]??[]).includes(s)){if(!e[t++])return;continue}if(!(o[r]??[]).some(a=>a.startsWith("--")?s.startsWith(a+"="):s.startsWith(a)&&s.length>2)&&!(r==="nice"&&/^-\d+$/.test(s)))return}}if(r==="timeout"&&!/^\d+(?:\.\d+)?[smhd]?$/.test(e[t++]?.value??""))return}}function Fe(e,t){let n=1,r="";for(let o=t;o<e.length;o++){let i=e[o];if(i==="\\"&&r!=="'"){o++;continue}if(r){i===r&&(r="");continue}if(i==="'"||i==='"')r=i;else if(i==="(")n++;else if(i===")"&&--n===0)return o}return e.length}function kn(e,t,n,r){let o={value:"",ranges:[],start:t,end:t,literal:!0},i="",s=t;for(;s<e.value.length;){let a=e.value[s];if(!i&&/[\s;|&()<>{}]/.test(a))break;if(a===i){i="",s++;continue}if(!i&&(a==="'"||a==='"')){i=a,s++;continue}if(a==="\\"&&i!=="'"){let u=e.value[s+1];if(u===`
|
|
3
|
+
`){s+=2;continue}if(u&&(!i||/[$`"\\]/.test(u))){X(o,e,s+1,s+2),s+=2;continue}}if(i!=="'"&&e.value.startsWith("$(",s)){let u=Fe(e.value,s+2);e.value[s+2]!=="("&&r<ee&&L(Le(e,s+2,u),n,r+1),X(o,e,s,Math.min(u+1,e.value.length)),o.literal=!1,s=Math.min(u+1,e.value.length);continue}if(a==="`"&&i!=="'"){let u=s+1;for(;u<e.value.length&&e.value[u]!=="`";)u+=e.value[u]==="\\"?2:1;r<ee&&L(Le(e,s+1,u),n,r+1),X(o,e,s,Math.min(u+1,e.value.length)),o.literal=!1,s=Math.min(u+1,e.value.length);continue}a==="$"&&i!=="'"&&(o.literal=!1),X(o,e,s,s+1),s++}return o.end=s,o}function An(e,t,n,r){let o=On(t);if(o===void 0)return;let i=$e(t[o]);if(Tn.has(i)&&r<ee){for(let s=o+1;s<t.length;s++){let a=t[s].value;if(a==="--command"||/^-[a-zA-Z]*c[a-zA-Z]*$/.test(a)){let u=t[s+1];u&&L(u,n,r+1);return}if(!a.startsWith("-")||a==="--")return;(a==="-o"||a==="-O")&&s++}return}if(Sn.has(i))for(let s=o+1;s<t.length;s++){let a=t[s];if(a.value==="--")return;if(bn.has(a.value)){s++;continue}a.value.startsWith("-p")&&a.value.length>2&&n.push({start:e.ranges[a.start].start,end:e.ranges[a.end-1].end})}}function L(e,t,n=0){let r=[],o,i=[],s=0,a=()=>{An(e,r,t,n),r=[],o=void 0};for(;s<e.value.length;){let u=e.value[s];if(u===`
|
|
4
|
+
`){a(),s++;for(let l of i.splice(0))for(;s<e.value.length;){let f=e.value.indexOf(`
|
|
5
|
+
`,s),_=f<0?e.value.length:f,y=e.value.slice(s,_);if(s=f<0?_:_+1,(l.stripTabs?y.replace(/^\t+/,""):y)===l.delimiter)break}}else if(/\s/.test(u))s++;else if(u==="#"){let l=e.value.indexOf(`
|
|
6
|
+
`,s);s=l<0?e.value.length:l}else if(e.value.startsWith("((",s))a(),s=Math.min(Fe(e.value,s+1)+1,e.value.length);else if(/[;|&(){}]/.test(u))a(),s++;else if(u==="<"||u===">")r.at(-1)?.end===s&&/^\d+$/.test(r.at(-1).value)&&r.pop(),o=/^(?:<<<|<<-?|>>|<&|>&|[<>])/.exec(e.value.slice(s))?.[0]??u,s+=o.length;else{let l=kn(e,s,t,n);s=l.end,(o==="<<"||o==="<<-")&&i.push({delimiter:l.value,stripTabs:o==="<<-"}),o||r.push(l),o=void 0}}a()}function wn(e,t,n){let r={value:"",ranges:[]};for(let o=t+1;o<n-1;o++){if(e.value[o]!=="\\"){X(r,e,o,o+1);continue}let i=o+(e.value[o+1]==="u"?6:2),s=JSON.parse(`"${e.value.slice(o,i)}"`);r.value+=s;for(let a=0;a<s.length;a++)r.ranges.push({start:e.ranges[o].start,end:e.ranges[i-1].end});o=i-1}return r}function Rn(e){let t={value:e,ranges:Array.from({length:e.length},(r,o)=>({start:o,end:o+1}))},n=[];if(/^\s*[{[]/.test(e)){let r;try{r=JSON.parse(e)}catch{return L(t,n),n}if(r!==null&&typeof r=="object"){let o=/"(?:[^"\\]|\\.)*"/g,i;for(;i=o.exec(e);){let s=JSON.parse(i[0]);if(s!=="command"&&s!=="cmd"&&s!=="CommandLine")continue;let a=/^\s*:\s*/.exec(e.slice(o.lastIndex));if(!a)continue;let u=o.lastIndex+a[0].length;if(e[u]!=='"')continue;o.lastIndex=u;let l=o.exec(e);l?.index===u&&L(wn(t,u,u+l[0].length),n)}}return n}return L(t,n),n}});var me=T(h=>{"use strict";Object.defineProperty(h,"__esModule",{value:!0});h.PATTERNS=h.MAX_BYTES=void 0;h.truncateTo=Ge;h.truncate=xn;h.collectMatches=Ve;h.resolveOverlaps=ze;h.applyMatches=Ye;h.redact=Mn;var Dn=qe();h.MAX_BYTES=102400;function Ge(e,t){let n=Buffer.from(e,"utf-8");return n.length<=t?e:`${n.subarray(0,Math.max(0,t)).toString("utf-8")}\u2026[TRUNCATED:${n.length}]`}function xn(e){return Ge(e,h.MAX_BYTES)}h.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 Ve(e,t){let n=[];for(let r of h.PATTERNS){if(r.requireContext&&r.requireContext!==t.context)continue;if(r.type==="cli_password_short"){for(let{start:s,end:a}of(0,Dn.mysqlPasswordRanges)(e))n.push({start:s,end:a,replaceStart:s,replaceEnd:a,type:r.type,replacement:`-p[REDACTED:${r.type}]`});continue}let o=new RegExp(r.regex.source,r.regex.flags),i;for(;(i=o.exec(e))!==null;){let s=r.captureGroup??0,a=i[s];if(a===void 0){i.index===o.lastIndex&&o.lastIndex++;continue}let u=i.index,l=i.index+i[0].length,f=u+i[0].indexOf(a),_=f+a.length;n.push({start:u,end:l,replaceStart:f,replaceEnd:_,type:r.type}),i.index===o.lastIndex&&o.lastIndex++}}return n}function ze(e){let t=[...e].sort((o,i)=>o.start!==i.start?o.start-i.start:i.end-i.start-(o.end-o.start)),n=[],r=-1;for(let o of t)o.start<r||(n.push(o),r=o.end);return n}function Ye(e,t){let n=[...t].sort((o,i)=>i.replaceStart-o.replaceStart),r=e;for(let o of n)r=r.slice(0,o.replaceStart)+(o.replacement??`[REDACTED:${o.type}]`)+r.slice(o.replaceEnd);return r}function Mn(e,t={}){if(e.length===0)return e;let n=Ve(e,t);if(n.length===0)return e;let r=ze(n);return Ye(e,r)}});var ge=T(p=>{"use strict";var jn=p&&p.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(p,"__esModule",{value:!0});p.MAX_SPAN_BYTES=void 0;p.ulidToTraceId=He;p.newSpanId=Ze;p.snakeCase=Cn;p.toOtlpValue=Je;p.attrsFromRecord=Un;p.guardAttrs=Qe;p.clientAttrs=et;p.enforceSpanBudget=tt;p.buildPayload=Bn;p.attachGuard=nt;p.mergeBatch=Ln;var Nn=jn(v("crypto")),he=me(),In="0123456789ABCDEFGHJKMNPQRSTVWXYZ";function He(e){if(e.length!==26)throw new Error(`ulidToTraceId: expected 26 chars, got ${e.length}`);let t=0n;for(let r of e){let o=In.indexOf(r);if(o<0)throw new Error(`ulidToTraceId: invalid Crockford char "${r}"`);t=t<<5n|BigInt(o)}let n=(1n<<128n)-1n;return t&=n,t.toString(16).padStart(32,"0")}function Ze(){return Nn.default.randomBytes(8).toString("hex")}function Cn(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1_$2").replace(/([A-Z])([A-Z][a-z])/g,"$1_$2").toLowerCase()}var Xe=new Set;function te(e,t,n){let r=(0,he.truncate)(t);if((n.skipRedactKeys??Xe).has(e))return r;let o=(n.bashContextKeys??Xe).has(e)?"bash":void 0;return(0,he.redact)(r,{context:o})}function Je(e,t,n={}){if(t==null)return null;switch(typeof t){case"string":return{stringValue:te(e,t,n)};case"boolean":return{boolValue:t};case"number":return Number.isInteger(t)?{intValue:t}:{doubleValue:t};case"object":try{return{stringValue:te(e,JSON.stringify(t),n)}}catch{return{stringValue:te(e,String(t),n)}}default:return{stringValue:te(e,String(t),n)}}}function Un(e,t,n={}){let r=[];for(let[o,i]of Object.entries(e)){let s=`${t}.${o}`,a=Je(s,i,n);a!==null&&r.push({key:s,value:a})}return r}function Qe(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 et(e){return[{key:"pinta.client.rtt_ms",value:Number.isInteger(e.rttMs)?{intValue:e.rttMs}:{doubleValue:e.rttMs}},{key:"pinta.client.op",value:{stringValue:e.op}}]}p.MAX_SPAN_BYTES=800*1024;function Ke(e){let t=JSON.stringify(e);return t===void 0?0:Buffer.byteLength(t,"utf-8")}var We=1024;function tt(e,t=p.MAX_SPAN_BYTES){let n=Ke(e);for(let r=0;r<100&&n>t;r++){let o=null,i=0;for(let u of e.attributes){if(!("stringValue"in u.value))continue;let l=Buffer.byteLength(u.value.stringValue,"utf-8");l>i&&(i=l,o=u.value)}if(o===null||i<=We)break;let s=n-t,a=Math.max(We,i-s-64);o.stringValue=(0,he.truncateTo)(o.stringValue,a),n=Ke(e)}return e}function Bn(e){let t=e.now??Date.now(),n=(BigInt(t)*1000000n).toString(),r=[...e.attributes],o={traceId:He(e.traceId),spanId:Ze(),name:e.spanName,kind:e.spanKind??1,startTimeUnixNano:n,endTimeUnixNano:n,attributes:r};tt(o);let i={resourceSpans:[{resource:{attributes:e.resource},scopeSpans:[{scope:e.scope,spans:[o]}]}]};return nt(i,e.guard,e.clientTiming)}function nt(e,t,n){let r=e.resourceSpans[0]?.scopeSpans[0]?.spans[0];if(!r)return e;t&&r.attributes.push(...Qe(t));let o=n??(t?.clientRttMs!==void 0?{op:"guard",rttMs:t.clientRttMs}:null);return o&&r.attributes.push(...et(o)),e}function Ln(e){let t=[];for(let n of e)t.push(...n.resourceSpans);return{resourceSpans:t}}});var rt=T(A=>{"use strict";Object.defineProperty(A,"__esModule",{value:!0});A.GUARD_STATUS_REFUSED=A.GUARD_BUDGET_HEADER=void 0;A.evaluateGuard=Gn;var $n=1e4,Fn="pinta-core";A.GUARD_BUDGET_HEADER="x-pinta-guard-budget-ms";function ne(e,t){return{decision:"ALLOW",reason:null,userMessage:null,durationMs:e,clientRttMs:e,failOpenReason:t}}var qn=new Set(["ALLOW","DENY","REVIEW"]);A.GUARD_STATUS_REFUSED=410;async function Gn(e,t,n={}){if(!t||n.disabled)return null;let r=n.timeoutMs??$n,o=Date.now(),i=new AbortController,s=setTimeout(()=>i.abort(),r);try{let a=await fetch(t,{method:"POST",headers:{"content-type":"application/json","user-agent":n.userAgent??Fn,"x-pinta-relay-token":n.token??"",...n.agentType?{"x-pinta-agent-type":n.agentType}:{},...Number.isFinite(r)&&r>0?{[A.GUARD_BUDGET_HEADER]:String(r)}:{}},body:JSON.stringify(e),signal:i.signal});if(a.status===A.GUARD_STATUS_REFUSED)return ne(Date.now()-o,"refused");if(a.status!==200)return ne(Date.now()-o,"error");let u=await a.json(),l=u?.durationMs===void 0||typeof u.durationMs=="number"&&Number.isFinite(u.durationMs);if(!u||!qn.has(u.decision)||!l)return ne(Date.now()-o,"error");let f=Date.now()-o;return{decision:u.decision,reason:u.reason??null,userMessage:u.userMessage??null,durationMs:u.durationMs??f,clientRttMs:f}}catch(a){let u=a.name,l=u==="AbortError"||u==="TimeoutError"?"timeout":"error";return ne(Date.now()-o,l)}finally{clearTimeout(s)}}});var re=T(K=>{"use strict";var Vn=K&&K.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(K,"__esModule",{value:!0});K.atomicWriteFileSync=zn;var ot=Vn(v("fs"));function zn(e,t){let n=`${e}.${process.pid}.tmp`;ot.default.writeFileSync(n,t),ot.default.renameSync(n,e)}});var ve=T(D=>{"use strict";var st=D&&D.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(D,"__esModule",{value:!0});D.MemoryRetryQueue=D.DiskRetryQueue=void 0;var g=st(v("fs")),oe=st(v("path")),Yn=re(),se=1e3,Xn=50,Kn=5,_e=class{filePath;lockPath;logPrefix;constructor(t,n){this.filePath=oe.default.join(t,"failed-spans.jsonl"),this.lockPath=this.filePath+".lock",this.logPrefix=n}enqueue(t){try{g.default.mkdirSync(oe.default.dirname(this.filePath),{recursive:!0});let n=JSON.stringify({savedAt:new Date().toISOString(),payload:t})+`
|
|
7
|
+
`;g.default.appendFileSync(this.filePath,n),this.trim()}catch(n){process.stderr.write(`[${this.logPrefix}] retry-queue enqueue failed: ${n}
|
|
8
|
+
`)}}readAll(){try{let t=g.default.readFileSync(this.filePath,"utf-8"),n=[];for(let r of t.split(`
|
|
9
|
+
`))if(r.trim())try{let o=JSON.parse(r);Array.isArray(o?.payload?.resourceSpans)&&n.push(o)}catch{}return n}catch{return[]}}rewrite(t){try{if(t.length===0){g.default.existsSync(this.filePath)&&g.default.unlinkSync(this.filePath);return}g.default.mkdirSync(oe.default.dirname(this.filePath),{recursive:!0}),(0,Yn.atomicWriteFileSync)(this.filePath,t.map(n=>JSON.stringify(n)).join(`
|
|
6
10
|
`)+`
|
|
7
11
|
`)}catch(n){process.stderr.write(`[${this.logPrefix}] retry-queue rewrite failed: ${n}
|
|
8
|
-
`)}}tryAcquireLock(){let t=Date.now();try{
|
|
9
|
-
`),!1}for(;Date.now()-t<
|
|
10
|
-
`),!1;try{let i=
|
|
11
|
-
`),this.rewrite(t.slice(n))}};
|
|
12
|
+
`)}}tryAcquireLock(){let t=Date.now();try{g.default.mkdirSync(oe.default.dirname(this.lockPath),{recursive:!0})}catch(n){return process.stderr.write(`[${this.logPrefix}] retry-queue lock mkdir failed: ${n}
|
|
13
|
+
`),!1}for(;Date.now()-t<Xn;)try{let n=g.default.openSync(this.lockPath,"wx");return g.default.writeSync(n,String(process.pid)),g.default.closeSync(n),!0}catch(n){if(n?.code!=="EEXIST")return process.stderr.write(`[${this.logPrefix}] retry-queue lock open failed: ${n}
|
|
14
|
+
`),!1;try{let i=g.default.statSync(this.lockPath);if(Date.now()-i.mtimeMs>3e4){g.default.unlinkSync(this.lockPath);continue}}catch{}let r=Kn,o=Date.now()+r;for(;Date.now()<o;);}return!1}release(){try{g.default.unlinkSync(this.lockPath)}catch{}}trim(){let t=this.readAll();if(t.length<=se)return;let n=t.length-se;process.stderr.write(`[${this.logPrefix}] retry-queue full, dropping ${n} oldest entries
|
|
15
|
+
`),this.rewrite(t.slice(n))}};D.DiskRetryQueue=_e;var ye=class{entries=[];enqueue(t){this.entries.push(t),this.entries.length>se&&this.entries.splice(0,this.entries.length-se)}drain(){let t=this.entries;return this.entries=[],t}get size(){return this.entries.length}};D.MemoryRetryQueue=ye});var ft=T(d=>{"use strict";Object.defineProperty(d,"__esModule",{value:!0});d.MemoryTransport=d.DiskTransport=d.MAX_POST_BYTES=void 0;d.parseHeadersEnv=ut;d.envOptionsResolver=lt;d.postOtlp=W;var it=ve(),at=ge(),Wn=5e3;d.MAX_POST_BYTES=900*1024;function ie(e){let t=JSON.stringify(e);return t===void 0?0:Buffer.byteLength(t,"utf-8")}function ct(e,t,n){let r=[],o=[],i=[],s=0;for(let a of e){let u=t(a);if(u>n){o.push(a);continue}i.length>0&&s+u>n&&(r.push(i),i=[],s=0),i.push(a),s+=u}return i.length>0&&r.push(i),{chunks:r,oversize:o}}function ut(e){if(!e)return{};if(typeof e=="object")return{...e};let t={};for(let n of e.split(",")){let[r,...o]=n.split("=");r&&o.length>0&&(t[r.trim()]=o.join("=").trim())}return t}function lt(){let e=process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,t=process.env.OTEL_EXPORTER_OTLP_ENDPOINT,n;return e?n=e.replace(/\/+$/,""):t&&(n=t.replace(/\/+$/,"")+"/v1/traces"),n?{endpoint:n,headers:ut(process.env.OTEL_EXPORTER_OTLP_HEADERS)}:null}async function W(e,t,n){let r=new AbortController,o=setTimeout(()=>r.abort(),Wn);try{let i=await fetch(t.endpoint,{method:"POST",headers:{"Content-Type":"application/json",...t.headers},body:JSON.stringify(e),signal:r.signal});if(!i.ok){let s="";try{s=(await i.text()).slice(0,200)}catch{}let a=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(`[${n}] OTLP POST ${i.status} ${t.endpoint}${a}${s?` body=${s}`:""}
|
|
12
16
|
`),!1}return!0}catch(i){return process.stderr.write(`[${n}] OTLP POST failed: ${i.message??String(i)}
|
|
13
|
-
`),!1}finally{clearTimeout(o)}}var
|
|
14
|
-
`);let i=[].concat(...r),
|
|
15
|
-
`)}finally{this.queue.release()}}dropIfOversized(t){let n=
|
|
16
|
-
`),!0)}};
|
|
17
|
-
`);return}await
|
|
18
|
-
`);let i=[].concat(...r),
|
|
19
|
-
`)}}};j.TraceManager=
|
|
20
|
-
`)){let r=n.trim();if(!r||r.startsWith("#"))continue;let o=r.indexOf("=");if(o<0)continue;let i=r.slice(0,o).trim(),
|
|
21
|
-
`)}function
|
|
22
|
-
`)}
|
|
23
|
-
`)}
|
|
24
|
-
`)
|
|
17
|
+
`),!1}finally{clearTimeout(o)}}var Ee=class{queue;logPrefix;resolveOptions;constructor(t){this.queue=new it.DiskRetryQueue(t.pluginData,t.logPrefix),this.logPrefix=t.logPrefix,this.resolveOptions=t.resolveOptions??lt}async send(t){let n=this.resolveOptions();if(!n||this.dropIfOversized(t))return;await W(t,n,this.logPrefix)||this.queue.enqueue(t)}async flush(){let t=this.resolveOptions();if(t&&this.queue.tryAcquireLock())try{let n=this.queue.readAll();if(n.length===0)return;let{chunks:r,oversize:o}=ct(n,a=>ie(a.payload),d.MAX_POST_BYTES);o.length>0&&process.stderr.write(`[${this.logPrefix}] dropping ${o.length} oversized retry ${o.length===1?"entry":"entries"} (each > ${d.MAX_POST_BYTES} bytes \u2014 the backend caps the request body, so they can never be delivered)
|
|
18
|
+
`);let i=[].concat(...r),s=0;for(let a of r){if(!await W((0,at.mergeBatch)(a.map(l=>l.payload)),t,this.logPrefix))break;s+=a.length}this.queue.rewrite(i.slice(s))}catch(n){process.stderr.write(`[${this.logPrefix}] flush failed: ${n?.message??String(n)}
|
|
19
|
+
`)}finally{this.queue.release()}}dropIfOversized(t){let n=ie(t);return n<=d.MAX_POST_BYTES?!1:(process.stderr.write(`[${this.logPrefix}] dropping oversized span payload (${n} > ${d.MAX_POST_BYTES} bytes) \u2014 undeliverable, not queued
|
|
20
|
+
`),!0)}};d.DiskTransport=Ee;var Pe=class{queue=new it.MemoryRetryQueue;logPrefix;resolveOptions;constructor(t){this.logPrefix=t.logPrefix,this.resolveOptions=t.resolveOptions}async send(t){let n=this.resolveOptions();if(!n)return;if(ie(t)>d.MAX_POST_BYTES){process.stderr.write(`[${this.logPrefix}] dropping oversized span payload (> ${d.MAX_POST_BYTES} bytes) \u2014 undeliverable, not buffered
|
|
21
|
+
`);return}await W(t,n,this.logPrefix)||this.queue.enqueue(t)}async flush(){let t=this.resolveOptions();if(!t)return;let n=this.queue.drain();if(n.length===0)return;let{chunks:r,oversize:o}=ct(n,ie,d.MAX_POST_BYTES);o.length>0&&process.stderr.write(`[${this.logPrefix}] dropping ${o.length} oversized buffered ${o.length===1?"payload":"payloads"} (each > ${d.MAX_POST_BYTES} bytes \u2014 undeliverable)
|
|
22
|
+
`);let i=[].concat(...r),s=0;for(let a of r){if(!await W((0,at.mergeBatch)(a),t,this.logPrefix))break;s+=a.length}for(let a of i.slice(s))this.queue.enqueue(a)}};d.MemoryTransport=Pe});var Oe=T(j=>{"use strict";var be=j&&j.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(j,"__esModule",{value:!0});j.TraceManager=void 0;j.generateUlid=pt;var dt=be(v("fs")),Hn=be(v("path")),Zn=be(v("crypto")),Jn=re(),Se="0123456789ABCDEFGHJKMNPQRSTVWXYZ";function pt(){let e=Date.now(),t="",n=e;for(let i=0;i<10;i++)t=Se[n&31]+t,n=Math.floor(n/32);let r=Zn.default.randomBytes(10),o="";for(let i=0;i<10;i++)o+=Se[r[i]&31];for(;o.length<16;)o+=Se[0];return t+o}var Te=class{tracePath;constructor(t){this.tracePath=t}newTrace(){let t=pt();return this.save(t),t}currentTrace(){try{let t=dt.default.readFileSync(this.tracePath,"utf-8"),{traceId:n}=JSON.parse(t);if(n)return n}catch{}return this.newTrace()}save(t){try{dt.default.mkdirSync(Hn.default.dirname(this.tracePath),{recursive:!0}),(0,Jn.atomicWriteFileSync)(this.tracePath,JSON.stringify({traceId:t}))}catch(n){process.stderr.write(`[pinta-core] trace persistence failed: ${n}
|
|
23
|
+
`)}}};j.TraceManager=Te});var yt=T(x=>{"use strict";var ht=x&&x.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(x,"__esModule",{value:!0});x.MemorySessionTraceManager=x.DiskSessionTraceManager=void 0;var mt=ht(v("fs")),Qn=ht(v("path")),gt=Oe(),er=re(),_t=200,ke=class{tracePath;maxSessions;constructor(t,n={}){this.tracePath=t,this.maxSessions=n.maxSessions??_t}read(){try{let t=JSON.parse(mt.default.readFileSync(this.tracePath,"utf-8"));if(t&&typeof t=="object"&&!("traceId"in t))return t}catch{}return{}}write(t){try{mt.default.mkdirSync(Qn.default.dirname(this.tracePath),{recursive:!0});let n=Object.entries(t),r=n.length>this.maxSessions?Object.fromEntries(n.slice(-this.maxSessions)):t;(0,er.atomicWriteFileSync)(this.tracePath,JSON.stringify(r))}catch{}}newTrace(t){let n=t||"default",r=(0,gt.generateUlid)(),o=this.read();return o[n]=r,this.write(o),r}currentTrace(t){let n=t||"default",r=this.read()[n];return r||this.newTrace(n)}};x.DiskSessionTraceManager=ke;var Ae=class{map=new Map;maxSessions;constructor(t={}){this.maxSessions=t.maxSessions??_t}newTrace(t){let n=t||"default",r=(0,gt.generateUlid)();if(this.map.set(n,r),this.map.size>this.maxSessions){let o=this.map.keys().next().value;o!==void 0&&this.map.delete(o)}return r}currentTrace(t){let n=t||"default";return this.map.get(n)??this.newTrace(n)}};x.MemorySessionTraceManager=Ae});var Pt=T(N=>{"use strict";var we=N&&N.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(N,"__esModule",{value:!0});N.envFilePath=rr;N.parseEnvFile=Et;N.loadEnvFile=or;var tr=we(v("node:fs")),nr=we(v("node:os")),vt=we(v("node:path"));function rr(e,t,n){let r=n?process.env[n]:void 0,o=r&&r.length>0?r:vt.default.join(nr.default.homedir(),e);return vt.default.join(o,t)}function Et(e){let t={};for(let n of e.split(`
|
|
24
|
+
`)){let r=n.trim();if(!r||r.startsWith("#"))continue;let o=r.indexOf("=");if(o<0)continue;let i=r.slice(0,o).trim(),s=r.slice(o+1).trim();(s.startsWith('"')&&s.endsWith('"')||s.startsWith("'")&&s.endsWith("'"))&&(s=s.slice(1,-1)),i&&(t[i]=s)}return t}function or(e){let t;try{t=tr.default.readFileSync(e,"utf-8")}catch{return}let n=Et(t);for(let[r,o]of Object.entries(n))process.env[r]===void 0&&(process.env[r]=o)}});var b=T(c=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});c.loadEnvFile=c.parseEnvFile=c.envFilePath=c.MemorySessionTraceManager=c.DiskSessionTraceManager=c.generateUlid=c.TraceManager=c.MAX_POST_BYTES=c.parseHeadersEnv=c.envOptionsResolver=c.postOtlp=c.MemoryTransport=c.DiskTransport=c.MemoryRetryQueue=c.DiskRetryQueue=c.GUARD_BUDGET_HEADER=c.GUARD_STATUS_REFUSED=c.evaluateGuard=c.MAX_SPAN_BYTES=c.enforceSpanBudget=c.mergeBatch=c.attachGuard=c.buildPayload=c.clientAttrs=c.guardAttrs=c.attrsFromRecord=c.toOtlpValue=c.snakeCase=c.newSpanId=c.ulidToTraceId=c.MAX_BYTES=c.PATTERNS=c.applyMatches=c.resolveOverlaps=c.collectMatches=c.truncateTo=c.truncate=c.redact=void 0;var M=me();Object.defineProperty(c,"redact",{enumerable:!0,get:function(){return M.redact}});Object.defineProperty(c,"truncate",{enumerable:!0,get:function(){return M.truncate}});Object.defineProperty(c,"truncateTo",{enumerable:!0,get:function(){return M.truncateTo}});Object.defineProperty(c,"collectMatches",{enumerable:!0,get:function(){return M.collectMatches}});Object.defineProperty(c,"resolveOverlaps",{enumerable:!0,get:function(){return M.resolveOverlaps}});Object.defineProperty(c,"applyMatches",{enumerable:!0,get:function(){return M.applyMatches}});Object.defineProperty(c,"PATTERNS",{enumerable:!0,get:function(){return M.PATTERNS}});Object.defineProperty(c,"MAX_BYTES",{enumerable:!0,get:function(){return M.MAX_BYTES}});var E=ge();Object.defineProperty(c,"ulidToTraceId",{enumerable:!0,get:function(){return E.ulidToTraceId}});Object.defineProperty(c,"newSpanId",{enumerable:!0,get:function(){return E.newSpanId}});Object.defineProperty(c,"snakeCase",{enumerable:!0,get:function(){return E.snakeCase}});Object.defineProperty(c,"toOtlpValue",{enumerable:!0,get:function(){return E.toOtlpValue}});Object.defineProperty(c,"attrsFromRecord",{enumerable:!0,get:function(){return E.attrsFromRecord}});Object.defineProperty(c,"guardAttrs",{enumerable:!0,get:function(){return E.guardAttrs}});Object.defineProperty(c,"clientAttrs",{enumerable:!0,get:function(){return E.clientAttrs}});Object.defineProperty(c,"buildPayload",{enumerable:!0,get:function(){return E.buildPayload}});Object.defineProperty(c,"attachGuard",{enumerable:!0,get:function(){return E.attachGuard}});Object.defineProperty(c,"mergeBatch",{enumerable:!0,get:function(){return E.mergeBatch}});Object.defineProperty(c,"enforceSpanBudget",{enumerable:!0,get:function(){return E.enforceSpanBudget}});Object.defineProperty(c,"MAX_SPAN_BYTES",{enumerable:!0,get:function(){return E.MAX_SPAN_BYTES}});var Re=rt();Object.defineProperty(c,"evaluateGuard",{enumerable:!0,get:function(){return Re.evaluateGuard}});Object.defineProperty(c,"GUARD_STATUS_REFUSED",{enumerable:!0,get:function(){return Re.GUARD_STATUS_REFUSED}});Object.defineProperty(c,"GUARD_BUDGET_HEADER",{enumerable:!0,get:function(){return Re.GUARD_BUDGET_HEADER}});var St=ve();Object.defineProperty(c,"DiskRetryQueue",{enumerable:!0,get:function(){return St.DiskRetryQueue}});Object.defineProperty(c,"MemoryRetryQueue",{enumerable:!0,get:function(){return St.MemoryRetryQueue}});var $=ft();Object.defineProperty(c,"DiskTransport",{enumerable:!0,get:function(){return $.DiskTransport}});Object.defineProperty(c,"MemoryTransport",{enumerable:!0,get:function(){return $.MemoryTransport}});Object.defineProperty(c,"postOtlp",{enumerable:!0,get:function(){return $.postOtlp}});Object.defineProperty(c,"envOptionsResolver",{enumerable:!0,get:function(){return $.envOptionsResolver}});Object.defineProperty(c,"parseHeadersEnv",{enumerable:!0,get:function(){return $.parseHeadersEnv}});Object.defineProperty(c,"MAX_POST_BYTES",{enumerable:!0,get:function(){return $.MAX_POST_BYTES}});var Tt=Oe();Object.defineProperty(c,"TraceManager",{enumerable:!0,get:function(){return Tt.TraceManager}});Object.defineProperty(c,"generateUlid",{enumerable:!0,get:function(){return Tt.generateUlid}});var bt=yt();Object.defineProperty(c,"DiskSessionTraceManager",{enumerable:!0,get:function(){return bt.DiskSessionTraceManager}});Object.defineProperty(c,"MemorySessionTraceManager",{enumerable:!0,get:function(){return bt.MemorySessionTraceManager}});var De=Pt();Object.defineProperty(c,"envFilePath",{enumerable:!0,get:function(){return De.envFilePath}});Object.defineProperty(c,"parseEnvFile",{enumerable:!0,get:function(){return De.parseEnvFile}});Object.defineProperty(c,"loadEnvFile",{enumerable:!0,get:function(){return De.loadEnvFile}})});import{realpathSync as Wr}from"node:fs";import{pathToFileURL as Hr}from"node:url";var H=k(b());function sr(){return(0,H.envFilePath)(".claude","pinta-cc.env")}function Ot(e=sr()){(0,H.loadEnvFile)(e)}function kt(){process.env.CLAUDE_PLUGIN_OPTION_ENDPOINT&&!process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT&&(process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=process.env.CLAUDE_PLUGIN_OPTION_ENDPOINT),process.env.CLAUDE_PLUGIN_OPTION_API_KEY&&!process.env.OTEL_EXPORTER_OTLP_HEADERS&&(process.env.OTEL_EXPORTER_OTLP_HEADERS=`x-pinta-relay-token=${process.env.CLAUDE_PLUGIN_OPTION_API_KEY}`),!process.env.PINTA_RELAY_TOKEN&&process.env.CLAUDE_PLUGIN_OPTION_API_KEY&&(process.env.PINTA_RELAY_TOKEN=process.env.CLAUDE_PLUGIN_OPTION_API_KEY)}var wt=k(b());import At from"path";function Rt(){let e=process.env.CLAUDE_PLUGIN_ROOT||process.cwd(),t=process.env.CLAUDE_PLUGIN_DATA||At.join(e,".plugin-data");return{pluginRoot:e,pluginData:t,tracePath:At.join(t,"trace.json")}}function ae(){return(0,wt.envOptionsResolver)()!==null}function Dt(e){return e.hook_event_name==="PreToolUse"}function xt(e){return e.hook_event_name==="PostToolUse"||e.hook_event_name==="PostToolUseFailure"}function Mt(e){return e.hook_event_name==="PostToolBatch"}function jt(e){return e.hook_event_name==="UserPromptSubmit"}function Nt(e){return e.hook_event_name==="SessionStart"||e.hook_event_name==="SessionEnd"}function It(e){return e.hook_event_name==="SubagentStart"||e.hook_event_name==="SubagentStop"}function Ct(e){return e.hook_event_name==="Stop"}function Ut(e){return e.hook_event_name==="PermissionRequest"||e.hook_event_name==="PermissionDenied"}var ir=new Set(["Notification","TaskCreated","TaskCompleted"]);function Bt(e){return ir.has(e.hook_event_name)}var tn=k(b());var Lt=k(b()),ar=1e4,cr="pinta-cc/1.10.2";function F(e,t){return(0,Lt.evaluateGuard)(e,t,{timeoutMs:ar,token:process.env.PINTA_RELAY_TOKEN??"",disabled:process.env.PINTA_GUARD_DISABLED==="1",userAgent:cr})}var Z=k(b());var $t=k(b()),ce=class extends $t.DiskTransport{constructor(t){super({pluginData:t.pluginData,logPrefix:"pinta-cc"})}};var Ft=k(b()),ue=class extends Ft.TraceManager{constructor(t){super(t.tracePath)}};import Ne from"os";import{spawnSync as ur}from"node:child_process";import{createHash as lr,randomUUID as fr}from"node:crypto";import O from"node:fs";import dr from"node:os";import m from"node:path";var Vt=/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/,pr=/^v?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?)\s+\(Claude Code\)$/m,mr=2e3,hr=24*60*60*1e3,gr=3e4,Me=8,zt="claude-version.json",q=new Map;function w(e){return typeof e=="object"&&e!==null&&"code"in e&&typeof e.code=="string"?e.code:"UNKNOWN"}function P(e){process.stderr.write(`[pinta-cc] CLI version: ${e}
|
|
25
|
+
`)}function le(e){return w(e)==="ENOENT"||w(e)==="ENOTDIR"}function _r(){let e=process.env.CLAUDE_CODE_EXECPATH,t=process.platform==="win32"?["claude.exe","claude.cmd"]:["claude"],n;if(e)n=[e];else{let r=(process.env.PATH??"").split(m.delimiter).filter(o=>m.isAbsolute(o));try{r.push(m.join(dr.homedir(),".local","bin"))}catch(o){P(`native install directory lookup failed (${w(o)})`)}n=r.flatMap(o=>t.map(i=>m.join(o,i)))}for(let r of new Set(n))try{let o=O.realpathSync(r),i=O.statSync(o);if(!i.isFile())continue;return!e&&process.platform!=="win32"&&O.accessSync(o,O.constants.X_OK),{file:o,fingerprint:lr("sha256").update(JSON.stringify([o,i.ino,i.size,i.mtimeMs,i.ctimeMs])).digest("hex")}}catch(o){le(o)||P(`executable lookup failed (${w(o)})`)}return P(e?"configured executable is unavailable":"no Claude executable found in PATH or ~/.local/bin"),null}function xe(e){let t;try{t=JSON.parse(O.readFileSync(e,"utf8"))}catch(n){return le(n)||P(`package metadata could not be read (${n instanceof SyntaxError?"INVALID_JSON":w(n)})`),null}return typeof t!="object"||t===null||!("name"in t)||!("version"in t)||typeof t.name!="string"||typeof t.version!="string"||!Vt.test(t.version)?null:t.name==="@anthropic-ai/claude-code"||t.name.startsWith("@anthropic-ai/claude-code-")?t.version:null}function yr(e){let t=m.dirname(e),n=m.basename(t)===".bin"&&/^claude(?:\.cmd)?$/i.test(m.basename(e));for(let r=0;r<6;r++){let o=xe(m.join(t,"package.json"));if(o)return o;if(m.basename(e).toLowerCase()==="claude.cmd"&&r===0){let s=xe(m.join(t,"node_modules","@anthropic-ai","claude-code","package.json"));if(s)return s}if(n&&m.basename(t)==="node_modules"){let s=xe(m.join(t,"@anthropic-ai","claude-code","package.json"));if(s)return s}let i=m.dirname(t);if(i===t)break;t=i}return null}function vr(e){return typeof e=="object"&&e!==null&&"fingerprint"in e&&typeof e.fingerprint=="string"&&/^[0-9a-f]{64}$/.test(e.fingerprint)&&"version"in e&&(e.version===null||typeof e.version=="string"&&Vt.test(e.version))&&"checkedAt"in e&&typeof e.checkedAt=="number"&&Number.isFinite(e.checkedAt)}function qt(e,t){let n=t-e.checkedAt;return n>=0&&n<(e.version===null?gr:hr)}function Er(e){if(!e)return[];let t=m.join(e,zt);try{if(O.statSync(t).size>16384)return P("oversized version cache ignored"),[];let n=JSON.parse(O.readFileSync(t,"utf8"));if(Array.isArray(n)&&n.length<=Me&&n.every(vr))return n;P("invalid version cache ignored")}catch(n){le(n)||P(`version cache read failed (${n instanceof SyntaxError?"INVALID_JSON":w(n)})`)}return[]}function Gt(e){for(q.delete(e.fingerprint),q.set(e.fingerprint,e);q.size>Me;){let t=q.keys().next().value;t!==void 0&&q.delete(t)}}function Pr(e,t){if(!e)return;let n=m.join(e,zt),r=`${n}.${process.pid}.${fr()}.tmp`;try{O.mkdirSync(e,{recursive:!0,mode:448}),O.writeFileSync(r,JSON.stringify(t),{encoding:"utf8",mode:384,flag:"wx"}),O.renameSync(r,n)}catch(o){P(`version cache write failed (${w(o)})`)}finally{try{O.unlinkSync(r)}catch(o){le(o)||P(`temporary version cache cleanup failed (${w(o)})`)}}}function Sr(e){if(/\.(cmd|bat|ps1)$/i.test(e))return P("command shim has no readable Claude package metadata"),null;let t=ur(e,["--version"],{encoding:"utf8",stdio:["ignore","pipe","pipe"],shell:!1,windowsHide:!0,timeout:mr,killSignal:"SIGKILL",maxBuffer:4096});if(t.error||t.status!==0)return P(`version probe failed (${t.error?w(t.error):`exit ${t.status??t.signal}`})`),null;let n=pr.exec(t.stdout.trim())?.[1];return n||(P("version probe did not identify Claude Code"),null)}function Yt(e){let t=_r();if(!t)return"unknown";let n=yr(t.file);if(n)return n;let r=Date.now(),o=Er(e),i=[q.get(t.fingerprint),...o].find(a=>a&&a.fingerprint===t.fingerprint&&qt(a,r));if(i)return Gt(i),i.version??"unknown";let s={fingerprint:t.fingerprint,version:Sr(t.file),checkedAt:Date.now()};return Gt(s),Pr(e,[...o.filter(a=>a.fingerprint!==s.fingerprint&&qt(a,s.checkedAt)),s].slice(-Me)),s.version??"unknown"}import C from"node:path";import R from"node:fs";import Xt from"node:path";var Tr=new Set(["","unknown","undefined","null","n/a","none","auto","default"]),br=256*1024,Or=1024*1024,kr=4096;function I(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)?e:void 0}function je(e){let t=I(e),n=t?"id"in t?t.id:t.name:e;if(typeof n!="string")return;let r=n.trim();if(!(r.startsWith("{")||r.startsWith("[")))return r.length<=512&&!/[\u0000-\u001f\u007f]/.test(r)&&!Tr.has(r.toLowerCase())?r:void 0}function Kt(e,t){delete e.model,t&&(e.model=t.name,!(t.source==="hook.model"&&e.model_source!==void 0)&&(e.model_source!==void 0&&(e.model_original_source=e.model_source),e.model_source=t.source))}function G(e){return typeof e=="string"&&/^[A-Za-z0-9][A-Za-z0-9_.:-]{0,255}$/.test(e)?e:void 0}function fe(e){let t=typeof e=="number"?e:typeof e=="string"&&/^\d{4}-\d{2}-\d{2}T/.test(e)?Date.parse(e):NaN;return Number.isFinite(t)&&t>=0?t:void 0}function Wt(e,t){let n=e.timestamp===void 0?fe(t):fe(e.timestamp);return n!==void 0&&n<=t?n:void 0}function Ht(e){if(typeof e!="string"||e.length>4096||/[\u0000-\u001f]/.test(e)||!Xt.isAbsolute(e)||Xt.extname(e)!==".jsonl")return;let t;try{t=R.openSync(e,R.constants.O_RDONLY|R.constants.O_NONBLOCK|(R.constants.O_NOFOLLOW??0));let n=R.fstatSync(t);if(!n.isFile()||!Number.isSafeInteger(n.size)||n.size<=0)return;let r=Buffer.alloc(Math.min(n.size,br));if(R.readSync(t,r,0,r.length,0)!==r.length)return;let o=r.indexOf(10),i;if(o>=0)try{i=I(JSON.parse(r.toString("utf8",0,o)))}catch{}let s=Math.max(0,n.size-Or),a=n.size<=r.length?r:Buffer.alloc(n.size-s);if(a!==r&&R.readSync(t,a,0,a.length,s)!==a.length)return;let u=R.fstatSync(t);if(u.size<n.size||u.size===n.size&&u.mtimeMs!==n.mtimeMs)return;let l=s>0?a.indexOf(10)+1:0,f=a.lastIndexOf(10);if(s>0&&l===0||f<l)return;let _=[],y=0;for(;f>l&&y<kr;){let Q=a.lastIndexOf(10,f-1),Y=Math.max(l,Q+1),Ce=a.toString("utf8",Y,f).trim();if(Ce){let Ue=I(JSON.parse(Ce));Ue&&_.push(Ue)}f=Y-1,y++}return _.reverse(),{first:i,rows:_,complete:s===0&&f<0&&a[a.length-1]===10}}catch{return}finally{if(t!==void 0)try{R.closeSync(t)}catch{}}}function Zt(e){let t=e[0];return t&&e.every(n=>n?.name===t.name)?t:void 0}var Ar=new Set(["PreToolUse","PostToolUse","PostToolUseFailure","PermissionRequest","PermissionDenied"]);function wr(e,t){let n=C.dirname(e);if(C.basename(n)!=="subagents"||C.basename(C.dirname(n))!==t)return;let r=/^agent-(.+)\.jsonl$/.exec(C.basename(e));return G(r?.[1])}function Jt(e,t){let n=je(e.model);if(n)return{name:n,source:"hook.model"};try{return Rr(e,t)}catch{return}}function Rr(e,t){if(!Ar.has(e.hook_event_name))return;let n=G(e.session_id),r=G(e.tool_use_id),o=Wt(e,t);if(!n||!r||o===void 0||typeof e.transcript_path!="string")return;let i=wr(e.transcript_path,n),s=e.agent_id===void 0?i:G(e.agent_id);if(e.agent_id!==void 0&&!s||i!==void 0&&i!==s||!s&&e.agent_type!==void 0||C.basename(C.dirname(e.transcript_path))==="subagents"&&!i)return;let a=Ht(e.transcript_path);if(!a)return;let u=[];for(let l of a.rows){let f=fe(l.timestamp);if(l.type!=="assistant"||l.sessionId!==n||f===void 0||f>o)continue;let _=l.agentId===void 0?void 0:G(l.agentId);if(_!==s||l.agentId!==void 0&&!_||l.isSidechain===!0&&!s)continue;let y=I(l.message);if(!y||y.role!==void 0&&y.role!=="assistant"||!Array.isArray(y.content)||!y.content.some(Y=>I(Y)?.type==="tool_use"&&I(Y)?.id===r))continue;let Q=je(y.model);u.push(Q?{name:Q,source:"transcript.assistant.message"}:void 0)}return Zt(u)}var V=k(b()),de;function Dr(){if(de===void 0)try{de=Ne.userInfo().username}catch{de=process.env.USER??process.env.LOGNAME??(typeof process.getuid=="function"?String(process.getuid()):"unknown")}return de}var Qt="1.10.2",xr=new Set(["cc.hook","cc.tool_name","cc.tool_use_id","cc.session_id","cc.transcript_path","cc.cwd","cc.permission_mode"]),Mr=new Set(["cc.tool_input","cc.tool_response","cc.tool_calls"]),jr={skipRedactKeys:xr,bashContextKeys:Mr};function Nr(e,t){let n=[];n.push({key:"ingest.type",value:{stringValue:"cc"}}),n.push({key:"cc.hook",value:{stringValue:e.hook_event_name}});let r={};for(let[o,i]of Object.entries(e))o!=="hook_event_name"&&(r[o]=i);return Kt(r,Jt(e,t)),n.push(...(0,V.attrsFromRecord)(r,"cc",jr)),n}function Ir(e){return[{key:"service.name",value:{stringValue:"claude-code"}},{key:"service.version",value:{stringValue:Yt(e)}},{key:"telemetry.sdk.name",value:{stringValue:"pinta-cc"}},{key:"telemetry.sdk.language",value:{stringValue:"nodejs"}},{key:"telemetry.sdk.version",value:{stringValue:Qt}},{key:"process.pid",value:{intValue:process.pid}},{key:"process.owner",value:{stringValue:Dr()}},{key:"host.name",value:{stringValue:Ne.hostname()}},{key:"host.arch",value:{stringValue:Ne.arch()}}]}function en(e){let t=e.now??Date.now();return(0,V.buildPayload)({traceId:e.traceId,spanName:`cc.${(0,V.snakeCase)(e.event.hook_event_name)}`,attributes:Nr(e.event,t),resource:Ir(e.versionCacheDir),scope:{name:"pinta-cc",version:Qt},now:t})}function U(e,t,n={}){let r=new ue(t),o=n.traceMode==="new"?r.newTrace():r.currentTrace();return en({event:e,traceId:o,versionCacheDir:t.pluginData})}async function B(e,t){if(!ae())return;let n=new ce(t);await n.flush(),await n.send(e)}function z(e,t){if(!ae())return;let n=Buffer.byteLength(JSON.stringify(e),"utf-8");if(n>Z.MAX_POST_BYTES){process.stderr.write(`[pinta-cc] dropping oversized span payload (${n} > ${Z.MAX_POST_BYTES} bytes) \u2014 undeliverable, not queued
|
|
26
|
+
`);return}new Z.DiskRetryQueue(t.pluginData,"pinta-cc").enqueue(e)}async function S(e,t,n={}){ae()&&await B(U(e,t,n),t)}async function nn(e,t){let n=U(e,t),r=await F(n,process.env.PINTA_GUARD_ENDPOINT);if(r?.decision==="DENY"){let i={hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:r.userMessage??r.reason??"guard_deny"}};process.stdout.write(JSON.stringify(i)+`
|
|
27
|
+
`)}try{if((0,tn.attachGuard)(n,r),r?.decision==="DENY")return z(n,t),0;await B(n,t)}catch(o){process.stderr.write(`[pinta-cc] telemetry emit failed: ${o}
|
|
28
|
+
`)}return 0}var rn=k(b());async function on(e,t){if(e.hook_event_name==="PostToolUseFailure")return await S(e,t),0;let n=U(e,t),r=await F(n,process.env.PINTA_GUARD_ENDPOINT);r?.decision==="DENY"&&process.stdout.write(JSON.stringify({continue:!1,stopReason:"Pinta blocked this tool output. Start a new session before continuing."})+`
|
|
29
|
+
`);try{if((0,rn.attachGuard)(n,r),r&&n.resourceSpans[0].scopeSpans[0].spans[0].attributes.push({key:"pinta.guard.target",value:{stringValue:"tool_output"}}),r?.decision==="DENY")return z(n,t),0;await B(n,t)}catch(o){process.stderr.write(`[pinta-cc] telemetry emit failed: ${o}
|
|
30
|
+
`)}return 0}async function sn(e,t){return await S(e,t,{traceMode:"new"}),0}async function an(e,t){return await S(e,t),0}async function cn(e,t){return await S(e,t),0}async function un(e,t){return await S(e,t),0}var ln=k(b());async function fn(e,t){if(e.hook_event_name==="PermissionDenied")return await S(e,t),0;let n=U(e,t),r=await F(n,process.env.PINTA_GUARD_ENDPOINT);r?.decision==="DENY"&&process.stdout.write(JSON.stringify({hookSpecificOutput:{hookEventName:"PermissionRequest",decision:{behavior:"deny",message:r.userMessage??r.reason??"guard_deny"}}})+`
|
|
31
|
+
`);try{if((0,ln.attachGuard)(n,r),r?.decision==="DENY")return z(n,t),0;await B(n,t)}catch(o){process.stderr.write(`[pinta-cc] telemetry emit failed: ${o}
|
|
32
|
+
`)}return 0}async function Ie(e){return 0}async function Cr(){let e=[];for await(let t of process.stdin)e.push(t);return Buffer.concat(e).toString("utf-8")}async function dn(){kt();let e=0;try{let t=Rt(),n=await Cr(),r=JSON.parse(n);Bt(r)?e=await Ie(r):Dt(r)?e=await nn(r,t):xt(r)||Mt(r)?e=await on(r,t):jt(r)?e=await sn(r,t):Nt(r)?e=await an(r,t):It(r)?e=await cn(r,t):Ct(r)?e=await un(r,t):Ut(r)?e=await fn(r,t):e=await Ie(r)}catch(t){process.stderr.write(`[pinta-cc] error: ${t}
|
|
33
|
+
`),e=0}return e}import{opendir as Ur,stat as Br}from"node:fs/promises";import{homedir as Lr}from"node:os";import J from"node:path";var $r="pinta-cc",pn="memory";function Fr(){let e=process.env.CLAUDE_CONFIG_DIR;return e&&e.length>0?e:J.join(Lr(),".claude")}function qr(){return J.join(Fr(),"projects")}function Gr(e,t){return J.relative(e,t).split(J.sep).join("/")}function Vr(e){return e.endsWith(".jsonl")?"append-log":"rewritten-doc"}function zr(e){let t=e.split("/");if(t.length<2)return{};let n=t[0],r=t[1];return t.length===2?r.endsWith(".jsonl")?{projectKey:n,sessionId:r.slice(0,-6)}:{projectKey:n}:r===pn?{projectKey:n}:{projectKey:n,sessionId:r}}function Yr(e){return e.endsWith(".jsonl")?"session-log":e.split("/")[1]===pn?"memory":e.endsWith(".json")?"meta":"other"}async function mn(){return[qr()]}async function*hn(e,t){let n;try{n=await Ur(t)}catch{return}try{for await(let r of n){let o=J.join(t,r.name);r.isDirectory()?yield*hn(e,o):r.isFile()&&(yield{absPath:o,relPath:Gr(e,o)})}}catch{return}}async function*Xr(e){let[t]=await mn(),n=e.since?.getTime();for await(let{absPath:r,relPath:o}of hn(t,t)){let i;try{i=await Br(r)}catch{continue}if(n!==void 0&&i.mtime.getTime()<=n)continue;let{projectKey:s,sessionId:a}=zr(o);yield{relPath:o,absPath:r,size:i.size,mtime:i.mtime,sessionId:a,projectKey:s,semantics:Vr(o)}}}var Kr={id:$r,roots:mn,scan:Xr,classify:Yr};Ot();function Zr(){let e=process.argv[1];if(!e)return!1;try{return import.meta.url===Hr(Wr(e)).href}catch{return!1}}async function Jr(){let e=await dn();process.exit(e)}Zr()&&Jr();export{Kr as lifecycle};
|
package/hooks/hooks.json
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"hooks": {
|
|
3
3
|
"PreToolUse": [{ "hooks": [{ "type": "command", "command": "node ${CLAUDE_PLUGIN_ROOT}/dist/index.js" }] }],
|
|
4
4
|
"PostToolUse": [{ "hooks": [{ "type": "command", "command": "node ${CLAUDE_PLUGIN_ROOT}/dist/index.js" }] }],
|
|
5
|
+
"PostToolBatch": [{ "hooks": [{ "type": "command", "command": "node ${CLAUDE_PLUGIN_ROOT}/dist/index.js" }] }],
|
|
5
6
|
"UserPromptSubmit": [{ "hooks": [{ "type": "command", "command": "node ${CLAUDE_PLUGIN_ROOT}/dist/index.js" }] }],
|
|
6
7
|
"SessionStart": [{ "hooks": [{ "type": "command", "command": "node ${CLAUDE_PLUGIN_ROOT}/dist/index.js" }] }],
|
|
7
8
|
"SessionEnd": [{ "hooks": [{ "type": "command", "command": "node ${CLAUDE_PLUGIN_ROOT}/dist/index.js" }] }],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pinta-ai/pinta-cc",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.2",
|
|
4
4
|
"description": "Generic OTLP forwarder for Claude Code hook events",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -38,11 +38,12 @@
|
|
|
38
38
|
"smoke:import": "node scripts/smoke-import.mjs",
|
|
39
39
|
"smoke:version": "node scripts/smoke-version.mjs",
|
|
40
40
|
"smoke:model": "node scripts/smoke-model.mjs",
|
|
41
|
+
"smoke:guard": "node scripts/smoke-guard.mjs",
|
|
41
42
|
"mock-server": "npx tsx tools/mock-server.ts",
|
|
42
43
|
"prepublishOnly": "npm run build"
|
|
43
44
|
},
|
|
44
45
|
"devDependencies": {
|
|
45
|
-
"@pinta-ai/core": "^0.9.
|
|
46
|
+
"@pinta-ai/core": "^0.9.2",
|
|
46
47
|
"@types/node": "^22.0.0",
|
|
47
48
|
"esbuild": "^0.24.0",
|
|
48
49
|
"tsx": "^4.0.0",
|