@ciandt-flow/flow-ai-obs 0.4.1 → 0.5.0-beta.211

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/README.md CHANGED
@@ -149,6 +149,109 @@ If the gateway is temporarily unavailable, traces are buffered in `/tmp` and rep
149
149
 
150
150
  ---
151
151
 
152
+ ## Development Environment (Docker)
153
+
154
+ A containerized sandbox is available so any team member can develop and test the SDK without touching their local Claude Code installation.
155
+
156
+ ### How it works
157
+
158
+ The container mounts three key paths:
159
+
160
+ | Container path | Source | Purpose |
161
+ |---|---|---|
162
+ | `/sdk` | Project root | SDK source, live-reloaded |
163
+ | `/root/.claude` | `.docker-claude/` | Claude Code config inside the container |
164
+ | `/project/sandbox` | `sandbox/` | Shared workspace for projects |
165
+
166
+ The `sandbox/` folder is committed to the repo and shared across the team. Place or clone any projects there to access them inside the container at `/project/sandbox` — no host path configuration needed regardless of where each developer stores their projects.
167
+
168
+ ### The `.docker-claude/` folder
169
+
170
+ This folder is the Claude Code home directory (`~/.claude`) inside the container. It contains:
171
+
172
+ - **`settings.json.example`** — template for the Claude Code configuration. Copy and fill in before starting the container.
173
+ - **`settings.json`** — your actual config (gitignored). Persists sessions, history, and skills across container restarts.
174
+ - Runtime data (sessions, cache, history) is stored here and persists between container restarts via volume mount.
175
+
176
+ ### First-time setup
177
+
178
+ ```bash
179
+ # 1. Copy the settings template
180
+ cp .docker-claude/settings.json.example .docker-claude/settings.json
181
+
182
+ # 2. Edit settings.json and replace <FLOW_TOKEN> with your actual Flow token
183
+
184
+ # 3. Build the Docker image
185
+ make dev-build
186
+ ```
187
+
188
+ ### Starting the sandbox
189
+
190
+ ```bash
191
+ # Open Claude Code in the sandbox (creates container if not running)
192
+ make dev
193
+
194
+ # Open a bash shell instead
195
+ make dev-shell
196
+ ```
197
+
198
+ Both commands reuse a running container if one already exists, or start a new one automatically.
199
+
200
+ ### All `make` commands
201
+
202
+ | Command | Description |
203
+ |---|---|
204
+ | `make dev` | Start Claude Code inside the sandbox container |
205
+ | `make dev-shell` | Open a bash shell inside the sandbox container |
206
+ | `make dev-build` | Build the Docker image |
207
+ | `make dev-reinstall` | Reinstall `flow-ai-obs` from source inside a running container |
208
+ | `make dev-logs` | Tail the debug log (`/tmp/flow-ai-obs-debug.log`) |
209
+ | `make dev-gh-setup` | Set up GitHub CLI authentication inside the container |
210
+ | `make dev-requests-open` | Copy captured OTLP requests to host and open in VS Code |
211
+ | `make dev-requests-clear` | Clear captured OTLP requests inside the container |
212
+ | `make clean` | Remove `node_modules` and `dist` |
213
+ | `make clean-all` | Full cleanup: Docker image, volumes, and all `.docker-claude` runtime data |
214
+
215
+ ### Status bar
216
+
217
+ When running Claude Code inside the container, the status bar displays:
218
+
219
+ ```
220
+ ◆ SANDBOX ENVIRONMENT ◆ (/project/sandbox/your-project)
221
+ ```
222
+
223
+ This makes it immediately clear you are operating in the sandbox, not your local environment.
224
+
225
+ ---
226
+
227
+ ## Contributing
228
+
229
+ ### Stack
230
+
231
+ TypeScript (CommonJS output via `tsup`), Node.js >= 18, Jest for tests.
232
+
233
+ ### Commands
234
+
235
+ ```bash
236
+ npm run build # compile TypeScript → dist/
237
+ npm test # run Jest test suite
238
+ npm run typecheck # type-check without emitting
239
+ npm run lint # ESLint
240
+ npm run format # Prettier
241
+ npm run smoke # smoke test — simulates 4 hook events via stdin
242
+ npm run security-scan # trufflehog secret scan (required before publish)
243
+ ```
244
+
245
+ ### Before opening a PR
246
+
247
+ All three must pass:
248
+
249
+ ```bash
250
+ npm test
251
+ npm run smoke
252
+ npm run security-scan
253
+ ```
254
+
152
255
  ---
153
256
 
154
257
  ## License
package/dist/cli.js CHANGED
@@ -1,168 +1,170 @@
1
1
  #!/usr/bin/env node
2
- 'use strict';var u=(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 l=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Se=l((Ba,fs)=>{fs.exports={name:"@ciandt-flow/flow-ai-obs",version:"0.4.1",description:"Claude Code hooks for Langfuse OTLP tracing \u2014 cross-platform",main:"dist/index.js",bin:{"flow-ai-obs":"dist/cli.js","flow-ai-obs-setup":"dist/setup.js"},scripts:{build:"tsup",test:"node --test src/**/*.test.js",typecheck:"node --check src/**/*.js bin/cli.js",lint:"node --check src/**/*.js bin/cli.js","security-scan":"trufflehog filesystem src/ --fail --no-update --exclude-paths .trufflehogignore",postinstall:`node -e "require('fs').existsSync('dist/setup.js') && require('child_process').execFileSync(process.execPath, ['dist/setup.js'], {stdio:'inherit'})"`,prepublishOnly:"npm run security-scan && npm run build","release:npm":"changeset publish",changeset:"changeset","version-packages":"changeset version","install:hooks":"node bin/cli.js install","auth:login":"node bin/cli.js auth login","auth:logout":"node bin/cli.js auth logout","auth:status":"node bin/cli.js auth status",smoke:"bash scripts/smoke-test.sh","smoke:debug":"bash scripts/smoke-test.sh --debug","smoke:send":"bash scripts/smoke-test.sh --send --allow-http --debug"},files:["dist/","README.md","LICENSE.md"],keywords:["claude-code","langfuse","observability","otlp","hooks","flow","ciandt"],author:"CI&T Flow Team",license:"SEE LICENSE IN LICENSE.md",private:false,dependencies:{keytar:"7.9.0"},devDependencies:{"@changesets/changelog-github":"^0.6.0","@changesets/cli":"^2.30.0",tsup:"^8.5.1",typescript:"^6.0.3"},engines:{node:">=18.0.0"},publishConfig:{registry:"https://registry.npmjs.org",access:"public"},repository:{type:"git",url:"git+https://github.com/CI-T-HyperX/flow-codeassistant-observability.git"}};});var B=l((Ha,ft)=>{var hs=!process.env.NO_COLOR&&process.stdout.isTTY;function D(e,t){return hs?n=>`\x1B[${e}m${n}\x1B[${t}m`:n=>n}var Ts=D("32","39"),Ss=D("31","39"),Es=D("33","39"),ws=D("36","39"),_s=D("1","22"),gs=D("2","22");ft.exports={green:Ts,red:Ss,yellow:Es,cyan:ws,bold:_s,dim:gs};});var Ee=l((Ya,wt)=>{var ys=u("https"),St=u("fs"),ms=u("os"),As=u("path"),{spawn:Ls}=u("child_process"),ve;function H(){return ve||(ve=Se()),ve}var Et=As.join(ms.tmpdir(),"flow-obs-update-cache.json"),Os=1440*60*1e3,Is=3e3;function be(e,t){let n=r=>{let i=String(r).replace(/^v/,"").match(/^(\d+)\.(\d+)\.(\d+)/);return i?[+i[1],+i[2],+i[3]]:null},s=n(e),o=n(t);return !s||!o?false:o[0]!==s[0]?o[0]>s[0]:o[1]!==s[1]?o[1]>s[1]:o[2]>s[2]}function Ns(){try{let e=JSON.parse(St.readFileSync(Et,"utf8"));return typeof e.latestVersion!="string"||Date.now()-e.checkedAt>=Os?null:e}catch{return null}}function ks(e,t){try{St.writeFileSync(Et,JSON.stringify({latestVersion:e,updatePriority:t||null,checkedAt:Date.now()}),{mode:384});}catch{}}function Cs(e){let t=H().name,n=ys.get(`https://registry.npmjs.org/${encodeURIComponent(t)}/latest`,{timeout:Is},s=>{if(s.statusCode!==200)return s.resume(),e(new Error(`HTTP ${s.statusCode}`));let o="";s.setEncoding("utf8"),s.on("data",r=>{o+=r;}),s.on("end",()=>{try{let r=JSON.parse(o);if(typeof r.version!="string")throw new Error("no version field");e(null,{version:r.version,updatePriority:typeof r.updatePriority=="string"?r.updatePriority:null});}catch(r){e(r);}});});n.on("error",e),n.on("timeout",()=>{n.destroy(new Error("timeout"));});}function ht(e){let t=H().name,s=` Update available: ${H().version} \u2192 ${e}`,o=` Run: npm install -g ${t}`,r=Math.max(s.length,o.length)+2,i="\u2500".repeat(r);process.stderr.write(`
2
+ 'use strict';var kn=require('https'),w=require('fs'),ue=require('os'),pt=require('path'),child_process=require('child_process'),Mn=require('http'),util=require('util'),crypto=require('crypto');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var kn__namespace=/*#__PURE__*/_interopNamespace(kn);var w__namespace=/*#__PURE__*/_interopNamespace(w);var ue__namespace=/*#__PURE__*/_interopNamespace(ue);var pt__namespace=/*#__PURE__*/_interopNamespace(pt);var Mn__namespace=/*#__PURE__*/_interopNamespace(Mn);var oe=Object.defineProperty;var hn=Object.getOwnPropertyDescriptor;var Sn=Object.getOwnPropertyNames;var En=Object.prototype.hasOwnProperty;var Dt=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(e,r)=>(typeof require<"u"?require:e)[r]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')});var p=(t,e)=>()=>(t&&(e=t(t=0)),e);var wn=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports),U=(t,e)=>{for(var r in e)oe(t,r,{get:e[r],enumerable:true});},Tn=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of Sn(e))!En.call(t,s)&&s!==r&&oe(t,s,{get:()=>e[s],enumerable:!(n=hn(e,s))||n.enumerable});return t};var N=t=>Tn(oe({},"__esModule",{value:true}),t);var Bt=wn((eo,yn)=>{yn.exports={name:"@ciandt-flow/flow-ai-obs",version:"0.5.0-beta.211",description:"Claude Code hooks for Langfuse OTLP tracing \u2014 cross-platform",main:"dist/index.js",bin:{"flow-ai-obs":"dist/cli.js","flow-ai-obs-setup":"dist/setup.js"},scripts:{build:"tsup",test:"jest",typecheck:"tsc --noEmit",lint:"eslint src bin scripts",format:'prettier --write "src/**/*.ts" "bin/**/*.ts" "scripts/**/*.ts"',"format:check":'prettier --check "src/**/*.ts" "bin/**/*.ts" "scripts/**/*.ts"',"security-scan":"trufflehog filesystem src/ --fail --no-update --exclude-paths .trufflehogignore",postinstall:`node -e "require('fs').existsSync('dist/setup.js') && require('child_process').execFileSync(process.execPath, ['dist/setup.js'], {stdio:'inherit'})"`,prepublishOnly:"npm run security-scan && npm run build","release:npm":"changeset publish",changeset:"changeset","version-packages":"changeset version","install:hooks":"node dist/cli.js install","auth:login":"node dist/cli.js auth login","auth:logout":"node dist/cli.js auth logout","auth:status":"node dist/cli.js auth status",smoke:"bash scripts/smoke-test.sh","smoke:debug":"bash scripts/smoke-test.sh --debug","smoke:send":"bash scripts/smoke-test.sh --send --allow-http --debug"},files:["dist/","README.md","LICENSE.md"],keywords:["claude-code","langfuse","observability","otlp","hooks","flow","ciandt"],author:"CI&T Flow Team",license:"SEE LICENSE IN LICENSE.md",private:false,dependencies:{keytar:"7.9.0"},devDependencies:{"@changesets/changelog-github":"^0.6.0","@changesets/cli":"^2.30.0","@types/jest":"^30.0.0","@types/node":"^25.8.0",jest:"^30.4.2","ts-jest":"^29.4.9",tsup:"^8.5.1","eslint-config-prettier":"^10.1.5",prettier:"^3.5.3",typescript:"^6.0.3","typescript-eslint":"^8.33.0"},engines:{node:">=18.0.0"},publishConfig:{registry:"https://registry.npmjs.org",access:"public"},repository:{type:"git",url:"git+https://github.com/CI-T-HyperX/flow-codeassistant-observability.git"}};});var ie={};U(ie,{bold:()=>H,cyan:()=>B,dim:()=>E,green:()=>P,red:()=>D,yellow:()=>L});function it(t,e){return _n?r=>`\x1B[${t}m${r}\x1B[${e}m`:r=>r}var _n,P,D,L,B,H,E,at=p(()=>{_n=!process.env.NO_COLOR&&process.stdout.isTTY;P=it("32","39"),D=it("31","39"),L=it("33","39"),B=it("36","39"),H=it("1","22"),E=it("2","22");});var Ht={};U(Ht,{checkForUpdate:()=>Rn,isNewer:()=>ce});function ct(){return ae||(ae=Bt()),ae}function ce(t,e){let r=o=>{let i=String(o).replace(/^v/,"").match(/^(\d+)\.(\d+)\.(\d+)/);return i?[+i[1],+i[2],+i[3]]:null},n=r(t),s=r(e);return !n||!s?false:s[0]!==n[0]?s[0]>n[0]:s[1]!==n[1]?s[1]>n[1]:s[2]>n[2]}function vn(){try{let t=JSON.parse(w__namespace.default.readFileSync(Ve,"utf8"));return typeof t.latestVersion!="string"||Date.now()-t.checkedAt>=bn?null:t}catch{return null}}function Nn(t,e){try{w__namespace.default.writeFileSync(Ve,JSON.stringify({latestVersion:t,updatePriority:e??null,checkedAt:Date.now()}),{mode:384});}catch{}}function Pn(t){let e=ct().name,r=kn__namespace.default.get(`https://registry.npmjs.org/${encodeURIComponent(e)}/latest`,{timeout:In},n=>{if(n.statusCode!==200)return n.resume(),t(new Error(`HTTP ${n.statusCode}`));let s="";n.setEncoding("utf8"),n.on("data",o=>{s+=o;}),n.on("end",()=>{try{let o=JSON.parse(s);if(typeof o.version!="string")throw new Error("no version field");t(null,{version:o.version,updatePriority:typeof o.updatePriority=="string"?o.updatePriority:null});}catch(o){t(o);}});});r.on("error",t),r.on("timeout",()=>{r.destroy(new Error("timeout"));});}function Be(t){let e=ct().name,n=` Update available: ${ct().version} \u2192 ${t}`,s=` Run: npm install -g ${e}`,o=Math.max(n.length,s.length)+2,i="\u2500".repeat(o);process.stderr.write(`
3
3
  \u256D${i}\u256E
4
- \u2502${s.padEnd(r)}\u2502
5
- \u2502${o.padEnd(r)}\u2502
4
+ \u2502${n.padEnd(o)}\u2502
5
+ \u2502${s.padEnd(o)}\u2502
6
6
  \u2570${i}\u256F
7
7
 
8
- `);}function Tt(e){let t=H().name;process.stderr.write(`
9
- [${t}] Critical update detected \u2014 auto-updating to ${e}...
10
-
11
- `),Ls("npm",["install","-g",`${t}@${e}`],{detached:true,stdio:"ignore",windowsHide:true}).unref();}function vs(){try{let e=Ns();if(e){be(H().version,e.latestVersion)&&(e.updatePriority==="auto"?Tt(e.latestVersion):ht(e.latestVersion));return}setImmediate(()=>{Cs((t,n)=>{t||!n||(ks(n.version,n.updatePriority),be(H().version,n.version)&&(n.updatePriority==="auto"?Tt(n.version):ht(n.version)));});});}catch{}}wt.exports={checkForUpdate:vs,isNewer:be};});var w=l((ja,gt)=>{var Y=process.env.FLOW_BASE_URL||"https://flow.ciandt.com",_t={AUTH_ENGINE:process.env.FLOW_AUTH_ENGINE_URL||`${Y}/auth-engine-api/v2/api-key/token`,GATEWAY_TRACES:process.env.FLOW_GATEWAY_TRACES_URL||`${Y}/flow-langfuse-gateway/v1/traces`,GATEWAY_HEALTH:process.env.FLOW_GATEWAY_HEALTH_URL||`${Y}/flow-langfuse-gateway/v1/health`,OTEL_ENDPOINT:process.env.FLOW_OTEL_ENDPOINT_URL||`${Y}/otel`},bs={SERVICE:"flow-plugins-cli",ACCOUNT_CREDS:"credentials",ACCOUNT_TOKEN:"token-cache"},Us="FLOW-nodejs",Rs="config.json",Ps={SCOPE_NAME:"flow-ai-obs",SCOPE_VERSION:"0.1.0"},Fs={ANTHROPIC_BASE_URL:process.env.FLOW_LLM_PROXY_URL||`${Y}/flow-llm-proxy/`,ANTHROPIC_MODEL:process.env.FLOW_LLM_PROXY_MODEL||"anthropic.claude-4-6-sonnet",ANTHROPIC_SMALL_FAST_MODEL:process.env.FLOW_LLM_PROXY_SMALL_MODEL||"anthropic.claude-4-6-sonnet",CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS:"1"},$s={CLAUDE_CODE_ENABLE_TELEMETRY:"1",OTEL_EXPORTER_OTLP_ENDPOINT:_t.OTEL_ENDPOINT,OTEL_EXPORTER_OTLP_PROTOCOL:"http/json",OTEL_METRICS_EXPORTER:"otlp",OTEL_LOGS_EXPORTER:"otlp",OTEL_LOG_TOOL_DETAILS:"1",OTEL_LOG_USER_PROMPTS:"1"},qs={FLOW_TELEMETRY:"FLOW_TELEMETRY",FLOW_TELEMETRY_GATEWAY:"FLOW_TELEMETRY_GATEWAY_URL",LANGFUSE_BASE_URL:"LANGFUSE_BASE_URL",LANGFUSE_PUBLIC_KEY:"LANGFUSE_PUBLIC_KEY",LANGFUSE_SECRET_KEY:"LANGFUSE_SECRET_KEY",ANTHROPIC_MODEL:"ANTHROPIC_MODEL",ANTHROPIC_AUTH_TOKEN:"ANTHROPIC_AUTH_TOKEN",FLOW_OBS_DEBUG:"FLOW_TELEMETRY_DEBUG",FLOW_OBS_ALLOW_HTTP:"FLOW_TELEMETRY_ALLOW_HTTP",BUFFER_TTL_DAYS:"FLOW_TELEMETRY_BUFFER_TTL_DAYS",BUFFER_MAX_FILES:"FLOW_TELEMETRY_BUFFER_MAX_FILES"},xs={KEYCHAIN_ENABLED:false},Ms={LOCK_STALE_MS:3e4,CONNECTIVITY_MAX_RETRY:3,CONNECTIVITY_RETRY_MS:2e3},Ds={UserPromptSubmit:5,PreToolUse:3,PostToolUse:10,Stop:15},Bs={FILE_PREFIX:"flow-obs-buffer-",DEFAULT_TTL_DAYS:4,MIN_TTL_DAYS:1,MAX_TTL_DAYS:30,DEFAULT_MAX_FILES:50,MIN_MAX_FILES:1,MAX_MAX_FILES:500,REPLAY_BATCH_SIZE:10},Hs="flow-ai-obs-debug.log",Ys={TOOL_INPUT:2e4,TOOL_OUTPUT:2e4,TRACE_OUTPUT:2e4,USER_INSTRUCTION:1e4,TRACE_INPUT:5e4,TOOL_BRIEF:60},js="flow-obs-";gt.exports={FLOW_BASE_URL:Y,FLOW_URLS:_t,VAULT:bs,CONFIG_DIR_NAME:Us,CONFIG_FILE_NAME:Rs,OTLP:Ps,LLM_PROXY:Fs,NATIVE_OTEL:$s,ENV:qs,FEATURES:xs,INSTALLER:Ms,HOOK_TIMEOUTS:Ds,BUFFER:Bs,DEBUG_LOG_FILENAME:Hs,STATE_FILE_PREFIX:js,TRACE_LIMITS:Ys};});var Q=l((Ga,mt)=>{var Gs=u("https"),Ks=u("http"),{FLOW_URLS:Ws}=w(),Vs=/^[a-z0-9][a-z0-9-]{0,62}[a-z0-9]$|^[a-z0-9]$/;function Js(e){if(!Vs.test(e))throw new Error(`Invalid tenant value: "${e}". Tenant must be lowercase alphanumeric and hyphens (1-64 chars).`)}var yt={INVALID_CLIENT_SECRET:"Invalid Client Secret \u2014 check the value and try again",INVALID_CLIENT_ID:"Invalid Client ID \u2014 check the value and try again",INVALID_TENANT:"Invalid Tenant \u2014 check the value and try again",TENANT_NOT_FOUND:"Tenant not found \u2014 verify the tenant identifier"};function Xs(e,t){try{let n=JSON.parse(t);if(typeof n.error=="string"&&yt[n.error])return new Error(yt[n.error])}catch{}return e===401||e===403||e===500?new Error("Invalid credentials"):e>=400&&e<500?new Error("Authentication request was rejected"):new Error("Authentication service unavailable, please try again later")}function zs(e){return new Promise((t,n)=>{try{Js(e.tenant);}catch(p){return n(p)}let s=JSON.stringify({clientSecret:e.clientSecret}),o=new URL(Ws.AUTH_ENGINE),r=o.protocol==="https:",i={hostname:o.hostname,port:o.port||(r?443:80),path:o.pathname+o.search,method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(s),FlowTenant:e.tenant}},c=(r?Gs:Ks).request(i,p=>{let h=[];p.on("data",S=>h.push(S)),p.on("end",()=>{let S=h.join("");if(p.statusCode>=400)return n(Xs(p.statusCode,S));let f;try{f=JSON.parse(S);}catch{return n(new Error("Invalid response from auth engine"))}let y=f.expires_at??new Date(Date.now()+(f.expires_in??3600)*1e3).toISOString();t({accessToken:f.access_token,expiresAt:y});});});c.on("error",p=>n(new Error(`Network error: ${p.message}`))),c.write(s),c.end();})}mt.exports={getToken:zs};});var ne=l((Ka,It)=>{var _=u("fs"),te=u("path"),At=u("os"),{FLOW_URLS:Zs,INSTALLER:ee,HOOK_TIMEOUTS:Qs,NATIVE_OTEL:er,LLM_PROXY:tr}=w(),{getToken:nr}=Q();function Re(){return process.platform==="win32"?te.join(process.env.APPDATA||te.join(At.homedir(),"AppData","Roaming"),"Claude","settings.json"):te.join(At.homedir(),".claude","settings.json")}var sr=ee.LOCK_STALE_MS;function Lt(e){try{let t=_.statSync(e);Date.now()-t.mtimeMs>sr&&_.unlinkSync(e);}catch{}try{_.writeFileSync(e,String(process.pid),{flag:"wx"});}catch(t){throw t.code==="EEXIST"?new Error("Another install is already in progress. If this is stale, remove: "+e):t}}function Ot(e){try{_.unlinkSync(e);}catch{}}function rr(e,t){let s=(Array.isArray(e)?e:[]).map(o=>{if(!Array.isArray(o?.hooks))return null;let r=o.hooks.filter(i=>!i.command?.startsWith?.("flow-ai-obs "));return r.length>0?{...o,hooks:r}:null}).filter(o=>o!=null);return [t,...s]}function or(){let e=Re(),t=e+".lock";_.mkdirSync(te.dirname(e),{recursive:true});let n=[];Lt(t);try{if(_.existsSync(e)){_.copyFileSync(e,e+".bkp");try{_.chmodSync(e+".bkp",384);}catch{}}let s={};try{s=JSON.parse(_.readFileSync(e,"utf8"));}catch{}(!s.env||typeof s.env!="object")&&(s.env={}),Object.assign(s.env,er),Object.assign(s.env,tr),s.otelHeadersHelper="flow-ai-obs otel-headers",(!s.hooks||typeof s.hooks!="object"||Array.isArray(s.hooks))&&(s.hooks={});let o=(i,a)=>({matcher:"",hooks:[{type:"command",command:`flow-ai-obs ${i}`,timeout:a}]}),r=["UserPromptSubmit","PreToolUse","PostToolUse","Stop"];for(let i of r){let a=rr(s.hooks[i],o(i,Qs[i]));a.length>1&&n.push(i),s.hooks[i]=a;}_.writeFileSync(e,JSON.stringify(s,null,2)+`
12
- `,{encoding:"utf8",mode:384});try{_.chmodSync(e,384);}catch{}}finally{Ot(t);}return {settingsPath:e,preserved:n}}async function ir(e){let t;try{t=(await nr(e)).accessToken;}catch{return false}return t?new Promise(n=>{Ue(`Bearer ${t}`,n,1);}):false}function Ue(e,t,n){let s=new URL(Zs.GATEWAY_TRACES),o=JSON.stringify({resourceSpans:[],validation_run:true}),r=s.protocol==="https:",i={hostname:s.hostname,port:s.port||(r?443:80),path:s.pathname,method:"POST",headers:{"Content-Type":"application/json",Authorization:e,"Content-Length":Buffer.byteLength(o)}},c=(r?u("https"):u("http")).request(i,p=>{p.resume(),p.statusCode===200||p.statusCode===204?t(true):n<ee.CONNECTIVITY_MAX_RETRY?setTimeout(()=>Ue(e,t,n+1),ee.CONNECTIVITY_RETRY_MS):t(false);});c.on("error",()=>{n<ee.CONNECTIVITY_MAX_RETRY?setTimeout(()=>Ue(e,t,n+1),ee.CONNECTIVITY_RETRY_MS):t(false);}),c.write(o),c.end();}function ar(e){let t=Re(),n=t+".lock";_.mkdirSync(te.dirname(t),{recursive:true}),Lt(n);try{let s={};try{s=JSON.parse(_.readFileSync(t,"utf8"));}catch{}(!s.env||typeof s.env!="object")&&(s.env={}),Object.assign(s.env,e),_.writeFileSync(t,JSON.stringify(s,null,2)+`
13
- `,{encoding:"utf8",mode:384});try{_.chmodSync(t,384);}catch{}}finally{Ot(n);}}It.exports={getClaudeSettingsPath:Re,writeClaudeSettings:or,addEnvToClaudeSettings:ar,validateConnectivity:ir};});var Ct=l((Wa,kt)=>{var re=u("fs"),j=u("path"),cr=u("os"),{CONFIG_DIR_NAME:Pe,CONFIG_FILE_NAME:Fe}=w(),$e={credentials:"credentials","token-cache":"tokenCache"};function se(){let e=cr.homedir();if(process.platform==="darwin")return j.join(e,"Library","Preferences",Pe,Fe);if(process.platform==="win32"){let n=process.env.APPDATA||j.join(e,"AppData","Roaming");return j.join(n,Pe,Fe)}let t=process.env.XDG_CONFIG_HOME||j.join(e,".config");return j.join(t,Pe,Fe)}function qe(){try{let e=re.readFileSync(se(),"utf8");return JSON.parse(e)}catch{return {}}}function Nt(e){let t=se();re.mkdirSync(j.dirname(t),{recursive:true}),re.writeFileSync(t,JSON.stringify(e,null,2),{encoding:"utf8",mode:384});}var we=class{static isAvailable(){return true}static hasExistingData(){try{if(!re.existsSync(se()))return !1;let t=JSON.parse(re.readFileSync(se(),"utf8"));return !!(t&&t.credentials)}catch{return false}}async getSecret(t,n){let s=qe(),o=$e[n]||n,r=s[o];return r?typeof r=="string"?r:JSON.stringify(r):null}async setSecret(t,n,s){let o=qe(),r=$e[n]||n;if(n==="token-cache")try{o[r]=JSON.parse(s);}catch{o[r]=s;}else o[r]=s;Nt(o);}async deleteSecret(t,n){let s=qe(),o=$e[n]||n;return o in s?(delete s[o],Nt(s),true):false}getStoragePath(){return `config.json (unencrypted) \u2014 ${se()}`}};function ur(){}var lr=we;kt.exports={JsonFallbackProvider:we,ScryptFallbackProvider:lr,_resetWarningState:ur};});var bt=l((Va,vt)=>{var{execFile:dr}=u("child_process"),{promisify:pr}=u("util"),{accessSync:fr,constants:hr}=u("fs"),xe=pr(dr),Me=class{static async isAvailable(){try{return fr("/usr/bin/security",hr.X_OK),!0}catch{return false}}async getSecret(t,n){try{let{stdout:s}=await xe("security",["find-generic-password","-w","-a",n,"-s",t]);return s.trim()||null}catch{return null}}async setSecret(t,n,s){await xe("security",["add-generic-password","-U","-a",n,"-s",t,"-w",s]);}async deleteSecret(t,n){try{return await xe("security",["delete-generic-password","-a",n,"-s",t]),!0}catch{return false}}getStoragePath(){return "macOS Keychain"}};vt.exports={MacOsKeyVaultProvider:Me};});var Pt=l((Ja,Rt)=>{var{execFile:Tr,spawn:Sr}=u("child_process"),{promisify:Er}=u("util"),{accessSync:wr,constants:_r}=u("fs"),Ut=Er(Tr),De=class{static async isAvailable(){let t=["/usr/bin/secret-tool","/bin/secret-tool","/usr/local/bin/secret-tool"];for(let n of t)try{return wr(n,_r.X_OK),!0}catch{}return false}async getSecret(t,n){try{let{stdout:s}=await Ut("secret-tool",["lookup","service",t,"account",n]);return s.trim()||null}catch{return null}}async setSecret(t,n,s){await new Promise((o,r)=>{let i=Sr("secret-tool",["store","--label",t,"service",t,"account",n]);i.on("error",r),i.on("close",a=>{a===0?o():r(new Error(`secret-tool exited with code ${a}`));}),i.stdin.write(s),i.stdin.end();});}async deleteSecret(t,n){try{return await Ut("secret-tool",["clear","service",t,"account",n]),!0}catch{return false}}getStoragePath(){return "Linux Secret Service (libsecret)"}};Rt.exports={LinuxKeyVaultProvider:De};});var $t=l((Xa,Ft)=>{var Be=class{static async isAvailable(){try{return await u("keytar").getPassword("__flow_probe__","__flow_probe__"),!0}catch{return false}}async getSecret(t,n){return u("keytar").getPassword(t,n)}async setSecret(t,n,s){await u("keytar").setPassword(t,n,s);}async deleteSecret(t,n){return u("keytar").deletePassword(t,n)}getStoragePath(){return "Windows Credential Manager"}};Ft.exports={WindowsKeyVaultProvider:Be};});var Mt=l((za,xt)=>{async function qt(){let{JsonFallbackProvider:e}=Ct();return await gr()??new e}async function gr(){switch(process.platform){case "darwin":{let{MacOsKeyVaultProvider:e}=bt();return await e.isAvailable()?new e:null}case "linux":{let{LinuxKeyVaultProvider:e}=Pt();return await e.isAvailable()?new e:null}case "win32":{let{WindowsKeyVaultProvider:e}=$t();return await e.isAvailable()?new e:null}default:return null}}var yr=qt;xt.exports={createSecretVaultProvider:qt,createKeyVaultProvider:yr};});var W=l((Za,Bt)=>{var{createSecretVaultProvider:mr}=Mt(),{VAULT:Ye}=w(),G=Ye.SERVICE,je=Ye.ACCOUNT_CREDS,Ge=Ye.ACCOUNT_TOKEN,He=null;function K(){return He||(He=mr()),He}async function Dt(){let t=await(await K()).getSecret(G,je);if(!t)return null;try{return JSON.parse(t)}catch{return null}}async function Ar(e){if(!e.clientId||!e.clientSecret||!e.tenant)throw new Error("clientId, clientSecret and tenant are required");await(await K()).setSecret(G,je,JSON.stringify(e));}async function Lr(){let e=await K();await e.deleteSecret(G,je),await e.deleteSecret(G,Ge);}async function Or(e){await(await K()).setSecret(G,Ge,JSON.stringify({accessToken:e.accessToken,expiresAt:e.expiresAt}));}async function Ke(){let t=await(await K()).getSecret(G,Ge);if(!t)return null;try{let n=JSON.parse(t);return {accessToken:n.accessToken,expiresAt:n.expiresAt}}catch{return null}}async function Ir(){let e=await Ke();return e?new Date(e.expiresAt)>new Date:false}async function Nr(){let e=await Ke();if(!e||!e.accessToken)return null;try{let t=e.accessToken.split(".");if(t.length<2)return null;let n=JSON.parse(Buffer.from(t[1].replace(/-/g,"+").replace(/_/g,"/"),"base64").toString("utf8"));return n.email||n.preferred_username||n.upn||n.sub||null}catch{return null}}async function kr(){let e=await K();if(typeof e.getStoragePath=="function")return e.getStoragePath();let t=process.platform;return t==="darwin"?"macOS Keychain":t==="win32"?"Windows Credential Manager":"Linux Secret Service (libsecret)"}async function Cr(){let e=await Dt();return !!(e&&e.clientId&&e.clientSecret&&e.tenant)}Bt.exports={getFlowCredentials:Dt,saveFlowCredentials:Ar,clearFlowCredentials:Lr,saveTokenCache:Or,getTokenCache:Ke,isTokenValid:Ir,getEmailFromToken:Nr,getConfigPath:kr,hasCredentials:Cr};});var v=l((Qa,Yt)=>{var{writeFileSync:vr}=u("fs"),{tmpdir:br}=u("os"),{join:Ur}=u("path"),{DEBUG_LOG_FILENAME:Rr,ENV:Pr}=w(),Ht=Ur(br(),Rr);function Fr(...e){if(process.env[Pr.FLOW_OBS_DEBUG]!=="1")return;let t=`[${new Date().toISOString()}] ${e.join(" ")}
14
- `;try{vr(Ht,t,{flag:"a"});}catch(n){process.stderr.write(`[flow-obs debug ERROR] ${n.message}
15
- `);}}Yt.exports={dbg:Fr,DEBUG_LOG:Ht};});var x=l((ec,Gt)=>{var{getFlowCredentials:We,isTokenValid:$r,getEmailFromToken:_e,getTokenCache:qr,saveTokenCache:xr}=W(),{getToken:Mr}=Q(),{FLOW_BASE_URL:Dr,ENV:N,FEATURES:Ve}=w(),{dbg:q}=v(),Br=[/^localhost\.?$/i,/^127\./,/^10\./,/^172\.(1[6-9]|2\d|3[01])\./,/^192\.168\./,/^169\.254\./,/^0\.0\.0\.0$/,/^::1$/,/^\[::1\]$/,/^\[::ffff:/i,/^\[f[cd]/i,/^\[fe80:/i,/^metadata\.google\.internal\.?$/i,/^metadata\.azure\.internal\.?$/i,/(?:^|\.)localtest\.me\.?$/i,/(?:^|\.)lvh\.me\.?$/i,/(?:^|\.)vcap\.me\.?$/i];function Hr(e){return Br.some(t=>t.test(e))}function Yr(e){if(!e)return null;try{let t=e.split(".");if(t.length<2)return null;let n=JSON.parse(Buffer.from(t[1].replace(/-/g,"+").replace(/_/g,"/"),"base64").toString("utf8"));return n.email||n.preferred_username||n.upn||n.sub||null}catch{return null}}function Xe(e){if(!e)return null;try{let t=e.split(".");if(t.length<2)return null;let n=JSON.parse(Buffer.from(t[1].replace(/-/g,"+").replace(/_/g,"/"),"base64").toString("utf8")),{clientId:s,clientSecret:o,tenant:r}=n;return !s||!o||!r?null:{clientId:s,clientSecret:o,tenant:r}}catch{return null}}function jr(e){let t=Buffer.from(JSON.stringify({alg:"none",typ:"JWT"})).toString("base64url"),n=Buffer.from(JSON.stringify({clientId:e.clientId,clientSecret:e.clientSecret,tenant:e.tenant})).toString("base64url");return `${t}.${n}.`}function Je(e){let t;try{t=new URL(e);}catch{throw new Error(`Invalid URL: ${e}`)}let n=process.env[N.FLOW_OBS_ALLOW_HTTP]==="true";if(!n&&t.protocol!=="https:")throw new Error(`URL must use HTTPS: ${e}`);if(t.username||t.password)throw new Error(`URL must not contain embedded credentials: ${e}`);if(!n&&Hr(t.hostname))throw new Error(`SSRF: private/loopback host not allowed: ${t.hostname}`);return e}async function Gr(){let e=Xe(process.env[N.ANTHROPIC_AUTH_TOKEN]);if(e)return {user:await _e().catch(()=>null)||e.clientId,tenant:e.tenant};if(Ve.KEYCHAIN_ENABLED)try{let t=await We();if(!t)return {user:"",tenant:""};let n=await _e()||t.clientId||"",s=t.tenant||"";return {user:n,tenant:s}}catch{return {user:"",tenant:""}}return {user:"",tenant:""}}async function Kr(e){if(await $r())return (await qr()).accessToken;q("getOrRefreshToken","token expired \u2014 refreshing via auth-engine");let t=await Mr(e);try{await xr(t);}catch(n){q("getOrRefreshToken",`token cache save failed (non-fatal): ${n.message}`);}return q("getOrRefreshToken",`token refreshed, expires=${t.expiresAt}`),t.accessToken}function Wr(e,t){let n=t&&t.accessToken?t.accessToken:"";return {endpoint:e.replace(/\/$/,"")+"/flow-langfuse-gateway/v1/traces",authHeader:`Bearer ${n}`}}function Vr(e,t,n){let s=Buffer.from(`${t}:${n}`).toString("base64");return {endpoint:e.replace(/\/$/,"")+"/api/public/otel/v1/traces",authHeader:`Basic ${s}`}}async function jt(){let e=[],t=process.env[N.ANTHROPIC_MODEL]||"",n=Xe(process.env[N.ANTHROPIC_AUTH_TOKEN]);q("resolveCredentials",n?"credentials resolved from ANTHROPIC_AUTH_TOKEN":"ANTHROPIC_AUTH_TOKEN absent or invalid"),!n&&Ve.KEYCHAIN_ENABLED&&(n=await We(),n&&q("resolveCredentials","credentials resolved from keychain (FEATURES.KEYCHAIN_ENABLED=true)"));let s=n?n.tenant:"",o=process.env[N.FLOW_TELEMETRY]==="true",r=process.env[N.LANGFUSE_BASE_URL],i=process.env[N.LANGFUSE_PUBLIC_KEY],a=process.env[N.LANGFUSE_SECRET_KEY];if(o&&r&&i&&a){let f="",y=s;if(n)f=await _e().catch(()=>null)||n.clientId;else if(Ve.KEYCHAIN_ENABLED)try{let k=await We();k&&(f=await _e()||k.clientId,y=k.tenant);}catch{}let I={user:f||"",tenant:y||"",team:"",project:"",model:t};e.push({mode:"direct",...Vr(Je(r),i,a),...I}),q("resolveCredentials","direct mode active",`user=${I.user}`,`tenant=${I.tenant}`);}if(!n){if(e.length===0){let f=[];return f.authError=false,f}return e}let c=null;try{c=await Kr(n);}catch(f){if(q("resolveCredentials",`token refresh failed: ${f.message}`),e.length>0)return e;let y=[];return y.authError=true,y}let h={user:Yr(c)||n.clientId,tenant:s,team:"",project:"",model:t},S=process.env[N.FLOW_TELEMETRY_GATEWAY]||Dr;return e.push({mode:"gateway",...Wr(Je(S),{accessToken:c}),...h}),e}async function Jr(){return (await jt()).length>0}Gt.exports={credentialsAvailable:Jr,getIdentityFromToken:Gr,resolveCredentials:jt,validateUrl:Je,parseCredsFromAnthropicToken:Xe,buildAnthropicAuthToken:jr};});var ce=l((tc,Zt)=>{var{getFlowCredentials:ze,saveFlowCredentials:Kt,clearFlowCredentials:Xr,saveTokenCache:zr,isTokenValid:Zr,getConfigPath:Wt,hasCredentials:Qr}=W(),{getToken:eo}=Q(),{buildAnthropicAuthToken:to,parseCredsFromAnthropicToken:Vt}=x(),{addEnvToClaudeSettings:no}=ne(),{ENV:Ze}=w(),{green:ye,red:oe,yellow:ge,cyan:ie,bold:Jt,dim:V}=B(),so=/[\x00-\x08\x0B-\x1F\x7F]|\x1b\[[0-9;]*[a-zA-Z]/g;function b(e){return typeof e=="string"?e.replace(so,""):e}function ae(e,t={}){return new Promise((n,s)=>{let{masked:o=false,defaultValue:r=""}=t;process.stdout.write(e+r);let i=r;function a(){try{process.stdin.setRawMode(!1);}catch{}}process.once("uncaughtException",a),process.once("unhandledRejection",a);let c=h=>{if(h===""){p(),s(new Error("SIGINT"));return}if(h==="\r"||h===`
16
- `){p(),process.stdout.write(`
17
- `),n(i);return}if(h==="\x7F"){i.length>0&&(i=i.slice(0,-1),process.stdout.write("\b \b"));return}h.startsWith("\x1B")||(i+=h,process.stdout.write(o?"*".repeat(h.length):h));};function p(){process.stdin.setRawMode(false),process.stdin.removeListener("data",c),process.removeListener("uncaughtException",a),process.removeListener("unhandledRejection",a);}process.stdin.setRawMode(true),process.stdin.resume(),process.stdin.setEncoding("utf8"),process.stdin.on("data",c);})}async function Xt(e){try{let t=await ze();(!t||t.clientId!==e.clientId||t.clientSecret!==e.clientSecret||t.tenant!==e.tenant)&&await Kt(e);}catch{}}async function zt(e){let{accessToken:t,expiresAt:n}=await eo(e);await Kt(e),await zr({accessToken:t,expiresAt:n});try{let s=to(e);no({[Ze.ANTHROPIC_AUTH_TOKEN]:s});}catch{}}async function ro(e){try{return await zt(e),process.stdout.write(ye(` \u2713 Setup complete. Tenant: ${b(e.tenant)}
18
-
19
- `)),0}catch(t){return process.stderr.write(oe(` \u2717 Authentication failed: ${b(t.message)}
20
- `)),1}}async function oo(){try{process.stdout.write(`
21
- `);let e=(await ae(ie(" ? ")+"Client ID: ")).trim(),t=(await ae(ie(" ? ")+"Client Secret: ",{masked:!0})).trim(),n=(await ae(ie(" ? ")+"Tenant: ")).trim();if(!e||!t||!n)return process.stderr.write(oe(` \u2717 All fields are required
22
- `)),1;try{await zt({clientId:e,clientSecret:t,tenant:n});}catch(s){return process.stderr.write(oe(` \u2717 Authentication failed: ${b(s.message)}
23
- `)),1}return process.stdout.write(ye(` \u2713 Setup complete. Tenant: ${b(n)}
24
- `)),process.stdout.write(` Storage: ${await Wt()}
25
-
26
- `),0}catch(e){if(e.message==="SIGINT")throw e;return process.stderr.write(oe(` \u2717 Unexpected error: ${e.message}
27
- `)),1}}async function io(e={}){if(e.clientId&&e.clientSecret&&e.tenant)return ro({clientId:e.clientId,clientSecret:e.clientSecret,tenant:e.tenant});let t=Vt(process.env[Ze.ANTHROPIC_AUTH_TOKEN]);t&&await Xt(t);let n=t||await ze();if(n){process.stdout.write(`
28
- `),process.stdout.write(Jt(` Already authenticated
29
- `)),process.stdout.write(V(" Tenant: ")+b(n.tenant)+`
30
- `),process.stdout.write(V(" Client ID: ")+b(n.clientId)+`
8
+ `);}function He(t){let e=ct().name;process.stderr.write(`
9
+ [${e}] Critical update detected \u2014 auto-updating to ${t}...
10
+
11
+ `),child_process.spawn("npm",["install","-g",`${e}@${t}`],{detached:true,stdio:"ignore",windowsHide:true}).unref();}function Rn(){try{let t=vn();if(t){ce(ct().version,t.latestVersion)&&(t.updatePriority==="auto"?He(t.latestVersion):Be(t.latestVersion));return}setImmediate(()=>{Pn((e,r)=>{e||!r||(Nn(r.version,r.updatePriority),ce(ct().version,r.version)&&(r.updatePriority==="auto"?He(r.version):Be(r.version)));});});}catch{}}var ae,Ve,bn,In,jt=p(()=>{Ve=pt__namespace.default.join(ue__namespace.default.tmpdir(),"flow-obs-update-cache.json"),bn=1440*60*1e3,In=3e3;});var X,z,Vt,Yt,Gt,le,Lt,lt,f,Kt,ut,Ye,R,Ge,F,T=p(()=>{X=process.env.FLOW_BASE_URL||"https://flow.ciandt.com",z={AUTH_ENGINE:process.env.FLOW_AUTH_ENGINE_URL||`${X}/auth-engine-api/v2/api-key/token`,GATEWAY_TRACES:process.env.FLOW_GATEWAY_TRACES_URL||`${X}/flow-langfuse-gateway/v1/traces`,GATEWAY_HEALTH:process.env.FLOW_GATEWAY_HEALTH_URL||`${X}/flow-langfuse-gateway/v1/health`,OTEL_ENDPOINT:process.env.FLOW_OTEL_ENDPOINT_URL||`${X}/otel`},Vt={SERVICE:"flow-plugins-cli",ACCOUNT_CREDS:"credentials",ACCOUNT_TOKEN:"token-cache"},Yt="FLOW-nodejs",Gt="config.json",le={SCOPE_NAME:"flow-ai-obs",SCOPE_VERSION:"0.1.0"},Lt={ANTHROPIC_BASE_URL:process.env.FLOW_LLM_PROXY_URL??`${X}/flow-llm-proxy/`,ANTHROPIC_MODEL:process.env.FLOW_LLM_PROXY_MODEL??"anthropic.claude-4-6-sonnet",ANTHROPIC_SMALL_FAST_MODEL:process.env.FLOW_LLM_PROXY_SMALL_MODEL??"anthropic.claude-4-6-sonnet",CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS:"1"},lt={CLAUDE_CODE_ENABLE_TELEMETRY:"1",OTEL_EXPORTER_OTLP_ENDPOINT:z.OTEL_ENDPOINT,OTEL_EXPORTER_OTLP_PROTOCOL:"http/json",OTEL_METRICS_EXPORTER:"otlp",OTEL_LOGS_EXPORTER:"otlp",OTEL_LOG_TOOL_DETAILS:"1",OTEL_LOG_USER_PROMPTS:"1"},f={FLOW_TELEMETRY:"FLOW_TELEMETRY",FLOW_TELEMETRY_GATEWAY:"FLOW_TELEMETRY_GATEWAY_URL",LANGFUSE_BASE_URL:"LANGFUSE_BASE_URL",LANGFUSE_PUBLIC_KEY:"LANGFUSE_PUBLIC_KEY",LANGFUSE_SECRET_KEY:"LANGFUSE_SECRET_KEY",ANTHROPIC_MODEL:"ANTHROPIC_MODEL",ANTHROPIC_AUTH_TOKEN:"ANTHROPIC_AUTH_TOKEN",FLOW_OBS_DEBUG:"FLOW_TELEMETRY_DEBUG",FLOW_OBS_ALLOW_HTTP:"FLOW_TELEMETRY_ALLOW_HTTP",BUFFER_TTL_DAYS:"FLOW_TELEMETRY_BUFFER_TTL_DAYS",BUFFER_MAX_FILES:"FLOW_TELEMETRY_BUFFER_MAX_FILES"},Kt={KEYCHAIN_ENABLED:false},ut={LOCK_STALE_MS:3e4,CONNECTIVITY_MAX_RETRY:3,CONNECTIVITY_RETRY_MS:2e3},Ye={UserPromptSubmit:5,PreToolUse:3,PostToolUse:10,Stop:15},R={FILE_PREFIX:"flow-obs-buffer-",DEFAULT_TTL_DAYS:4,MIN_TTL_DAYS:1,MAX_TTL_DAYS:30,DEFAULT_MAX_FILES:50,MIN_MAX_FILES:1,MAX_MAX_FILES:500,REPLAY_BATCH_SIZE:10},Ge="flow-ai-obs-debug.log",F={TOOL_INPUT:2e4,TOOL_OUTPUT:2e4,TRACE_OUTPUT:2e4,USER_INSTRUCTION:1e4,TRACE_INPUT:5e4,TOOL_BRIEF:60};});function l(...t){if(process.env[f.FLOW_OBS_DEBUG]!=="1")return;let e=`[${new Date().toISOString()}] ${t.join(" ")}
12
+ `;try{w.writeFileSync($n,e,{flag:"a"});}catch(r){process.stderr.write(`[flow-obs debug ERROR] ${r.message}
13
+ `);}}var $n,$=p(()=>{T();$n=pt.join(ue.tmpdir(),Ge);});function Bn(t){if(!Dn.test(t))throw new Error(`Invalid tenant value: "${t}". Tenant must be lowercase alphanumeric and hyphens (1-64 chars).`)}function Hn(t,e){let r=e.length>400?e.slice(0,400)+"\u2026":e;l("toAuthError",`status=${t} body=${r}`);try{let n=JSON.parse(e);if(typeof n.error=="string"&&(l("toAuthError",`api_error_code=${n.error}`+(n.message?` api_message=${n.message}`:"")),Ke[n.error]))return new Error(Ke[n.error])}catch{}return t===401||t===403||t===500?new Error("Invalid credentials"):t>=400&&t<500?new Error("Authentication request was rejected"):new Error("Authentication service unavailable, please try again later")}function V(t){return new Promise((e,r)=>{try{Bn(t.tenant);}catch(u){return r(u)}let n=JSON.stringify({clientSecret:t.clientSecret}),s=new URL(z.AUTH_ENGINE),o=s.protocol==="https:",i={hostname:s.hostname,port:s.port||(o?443:80),path:s.pathname+s.search,method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(n),FlowTenant:t.tenant}};l("getToken",`requesting token tenant=${t.tenant} host=${i.hostname} path=${i.path}`);let c=(o?kn__namespace.default:Mn__namespace.default).request(i,u=>{let S=[];u.on("data",A=>S.push(A)),u.on("end",()=>{let A=S.join("");if((u.statusCode??0)>=400)return r(Hn(u.statusCode??0,A));let m;try{m=JSON.parse(A);}catch{return r(new Error("Invalid response from auth engine"))}let k=m.expires_at??new Date(Date.now()+(m.expires_in??3600)*1e3).toISOString();e({accessToken:m.access_token??"",expiresAt:k});});});c.on("error",u=>r(new Error(`Network error: ${u.message}`))),c.write(n),c.end();})}var Dn,Ke,bt=p(()=>{T();$();Dn=/^[a-z0-9][a-z0-9-]{0,62}[a-z0-9]$|^[a-z0-9]$/;Ke={INVALID_CLIENT_SECRET:"Invalid Client Secret \u2014 check the value and try again",INVALID_CLIENT_ID:"Invalid Client ID \u2014 check the value and try again",INVALID_TENANT:"Invalid Tenant \u2014 check the value and try again",TENANT_NOT_FOUND:"Tenant not found \u2014 verify the tenant identifier"};});function dt(){return process.platform==="win32"?pt__namespace.join(process.env.APPDATA||pt__namespace.join(ue__namespace.homedir(),"AppData","Roaming"),"Claude","settings.json"):pt__namespace.join(ue__namespace.homedir(),".claude","settings.json")}function We(t){try{let e=w__namespace.statSync(t);Date.now()-e.mtimeMs>Yn&&w__namespace.unlinkSync(t);}catch{}try{w__namespace.writeFileSync(t,String(process.pid),{flag:"wx"});}catch(e){throw e.code==="EEXIST"?new Error("Another install is already in progress. If this is stale, remove: "+t):e}}function qe(t){try{w__namespace.unlinkSync(t);}catch{}}function Gn(t,e){let n=(Array.isArray(t)?t:[]).map(s=>{if(!Array.isArray(s?.hooks))return null;let o=s.hooks.filter(i=>!i.command?.startsWith?.("flow-ai-obs "));return o.length>0?{...s,hooks:o}:null}).filter(s=>s!=null);return [e,...n]}function Je(){let t=dt(),e=t+".lock",r=[];w__namespace.mkdirSync(pt__namespace.dirname(t),{recursive:true}),We(e);try{if(w__namespace.existsSync(t)){w__namespace.copyFileSync(t,t+".bkp");try{w__namespace.chmodSync(t+".bkp",384);}catch{}}let n={};try{n=JSON.parse(w__namespace.readFileSync(t,"utf8"));}catch{}let s=n.env&&typeof n.env=="object"?n.env:{};n.env={...lt,...Lt,...s},n.otelHeadersHelper="flow-ai-obs otel-headers",(!n.hooks||typeof n.hooks!="object"||Array.isArray(n.hooks))&&(n.hooks={});let o=(c,u)=>({matcher:"",hooks:[{type:"command",command:`flow-ai-obs ${c}`,timeout:u}]}),i=["UserPromptSubmit","PreToolUse","PostToolUse","Stop"],a=n.hooks;for(let c of i){let u=Gn(a[c],o(c,Ye[c]));u.length>1&&r.push(c),a[c]=u;}w__namespace.writeFileSync(t,JSON.stringify(n,null,2)+`
14
+ `,{encoding:"utf8",mode:384});try{w__namespace.chmodSync(t,384);}catch{}}finally{qe(e);}return {settingsPath:t,preserved:r}}async function Xe(t){let e;try{e=(await V(t)).accessToken;}catch{return false}return e?new Promise(r=>{de(`Bearer ${e}`,r,1);}):false}function de(t,e,r){let n=new URL(z.GATEWAY_TRACES),s=JSON.stringify({resourceSpans:[],validation_run:true}),o=n.protocol==="https:",i={hostname:n.hostname,port:n.port||(o?443:80),path:n.pathname,method:"POST",headers:{"Content-Type":"application/json",Authorization:t,"Content-Length":Buffer.byteLength(s)}},c=(o?kn__namespace:Mn__namespace).request(i,u=>{u.resume(),u.statusCode===200||u.statusCode===204?e(true):r<ut.CONNECTIVITY_MAX_RETRY?setTimeout(()=>de(t,e,r+1),ut.CONNECTIVITY_RETRY_MS):e(false);});c.on("error",()=>{r<ut.CONNECTIVITY_MAX_RETRY?setTimeout(()=>de(t,e,r+1),ut.CONNECTIVITY_RETRY_MS):e(false);}),c.write(s),c.end();}function Wt(t){let e=dt(),r=e+".lock";w__namespace.mkdirSync(pt__namespace.dirname(e),{recursive:true}),We(r);try{let n={};try{n=JSON.parse(w__namespace.readFileSync(e,"utf8"));}catch{}(!n.env||typeof n.env!="object")&&(n.env={}),Object.assign(n.env,t),w__namespace.writeFileSync(e,JSON.stringify(n,null,2)+`
15
+ `,{encoding:"utf8",mode:384});try{w__namespace.chmodSync(e,384);}catch{}}finally{qe(r);}}var Yn,It=p(()=>{T();bt();Yn=ut.LOCK_STALE_MS;});function vt(){let t=ue__namespace.default.homedir();if(process.platform==="darwin")return pt__namespace.default.join(t,"Library","Preferences",Yt,Gt);if(process.platform==="win32"){let r=process.env.APPDATA??pt__namespace.default.join(t,"AppData","Roaming");return pt__namespace.default.join(r,Yt,Gt)}let e=process.env.XDG_CONFIG_HOME??pt__namespace.default.join(t,".config");return pt__namespace.default.join(e,Yt,Gt)}function fe(){try{let t=w__namespace.default.readFileSync(vt(),"utf8");return JSON.parse(t)}catch{return {}}}function ze(t){let e=vt();w__namespace.default.mkdirSync(pt__namespace.default.dirname(e),{recursive:true}),w__namespace.default.writeFileSync(e,JSON.stringify(t,null,2),{encoding:"utf8",mode:384});}var pe,qt,Ze=p(()=>{T();pe={credentials:"credentials","token-cache":"tokenCache"};qt=class{static isAvailable(){return true}static hasExistingData(){try{if(!w__namespace.default.existsSync(vt()))return !1;let e=JSON.parse(w__namespace.default.readFileSync(vt(),"utf8"));return !!(e&&e.credentials)}catch{return false}}async getSecret(e,r){let n=fe(),s=pe[r]??r,o=n[s];return o?typeof o=="string"?o:JSON.stringify(o):null}async setSecret(e,r,n){let s=fe(),o=pe[r]??r;if(r==="token-cache")try{s[o]=JSON.parse(n);}catch{s[o]=n;}else s[o]=n;ze(s);}async deleteSecret(e,r){let n=fe(),s=pe[r]??r;return s in n?(delete n[s],ze(n),true):false}getStoragePath(){return `config.json (unencrypted) \u2014 ${vt()}`}};});var Qe={};U(Qe,{MacOsKeyVaultProvider:()=>ge});var me,ge,tr=p(()=>{me=util.promisify(child_process.execFile),ge=class{static async isAvailable(){try{return w.accessSync("/usr/bin/security",w.constants.X_OK),!0}catch{return false}}async getSecret(e,r){try{let{stdout:n}=await me("security",["find-generic-password","-w","-a",r,"-s",e]);return n.trim()||null}catch{return null}}async setSecret(e,r,n){await me("security",["add-generic-password","-U","-a",r,"-s",e,"-w",n]);}async deleteSecret(e,r){try{return await me("security",["delete-generic-password","-a",r,"-s",e]),!0}catch{return false}}getStoragePath(){return "macOS Keychain"}};});var rr={};U(rr,{LinuxKeyVaultProvider:()=>he});var er,he,nr=p(()=>{er=util.promisify(child_process.execFile),he=class{static async isAvailable(){let e=["/usr/bin/secret-tool","/bin/secret-tool","/usr/local/bin/secret-tool"];for(let r of e)try{return w.accessSync(r,w.constants.X_OK),!0}catch{}return false}async getSecret(e,r){try{let{stdout:n}=await er("secret-tool",["lookup","service",e,"account",r]);return n.trim()||null}catch{return null}}async setSecret(e,r,n){await new Promise((s,o)=>{let i=child_process.spawn("secret-tool",["store","--label",e,"service",e,"account",r]);i.on("error",o),i.on("close",a=>{a===0?s():o(new Error(`secret-tool exited with code ${a}`));}),i.stdin.write(n),i.stdin.end();});}async deleteSecret(e,r){try{return await er("secret-tool",["clear","service",e,"account",r]),!0}catch{return false}}getStoragePath(){return "Linux Secret Service (libsecret)"}};});var sr={};U(sr,{WindowsKeyVaultProvider:()=>Se});var Se,or=p(()=>{Se=class{static async isAvailable(){try{return await Dt("keytar").getPassword("__flow_probe__","__flow_probe__"),!0}catch{return false}}async getSecret(e,r){return Dt("keytar").getPassword(e,r)}async setSecret(e,r,n){await Dt("keytar").setPassword(e,r,n);}async deleteSecret(e,r){return Dt("keytar").deletePassword(e,r)}getStoragePath(){return "Windows Credential Manager"}};});async function ir(){return await rs()??new qt}async function rs(){switch(process.platform){case "darwin":{let{MacOsKeyVaultProvider:t}=await Promise.resolve().then(()=>(tr(),Qe));return await t.isAvailable()?new t:null}case "linux":{let{LinuxKeyVaultProvider:t}=await Promise.resolve().then(()=>(nr(),rr));return await t.isAvailable()?new t:null}case "win32":{let{WindowsKeyVaultProvider:t}=await Promise.resolve().then(()=>(or(),sr));return await t.isAvailable()?new t:null}default:return null}}var ar=p(()=>{Ze();});function mt(){return Ee||(Ee=ir()),Ee}async function _(){let e=await(await mt()).getSecret(ft,we);if(!e)return null;try{return JSON.parse(e)}catch{return null}}async function ye(t){if(!t.clientId||!t.clientSecret||!t.tenant)throw new Error("clientId, clientSecret and tenant are required");await(await mt()).setSecret(ft,we,JSON.stringify(t));}async function cr(){let t=await mt();await t.deleteSecret(ft,we),await t.deleteSecret(ft,Te);}async function Jt(t){await(await mt()).setSecret(ft,Te,JSON.stringify({accessToken:t.accessToken,expiresAt:t.expiresAt}));}async function gt(){let e=await(await mt()).getSecret(ft,Te);if(!e)return null;try{let r=JSON.parse(e);return {accessToken:r.accessToken,expiresAt:r.expiresAt}}catch{return null}}async function ht(){let t=await gt();return t?new Date(t.expiresAt)>new Date:false}async function Q(){let t=await gt();if(!t||!t.accessToken)return null;try{let e=t.accessToken.split(".");if(e.length<2)return null;let r=JSON.parse(Buffer.from(e[1].replace(/-/g,"+").replace(/_/g,"/"),"base64").toString("utf8"));return r.email??r.preferred_username??r.upn??r.sub??null}catch{return null}}async function _e(){let t=await mt();if(typeof t.getStoragePath=="function")return t.getStoragePath();let e=process.platform;return e==="darwin"?"macOS Keychain":e==="win32"?"Windows Credential Manager":"Linux Secret Service (libsecret)"}async function lr(){let t=await _();return !!(t&&t.clientId&&t.clientSecret&&t.tenant)}var ft,we,Te,Ee,St=p(()=>{ar();T();ft=Vt.SERVICE,we=Vt.ACCOUNT_CREDS,Te=Vt.ACCOUNT_TOKEN,Ee=null;});function ss(t){return ns.some(e=>e.test(t))}function os(t){if(!t)return null;try{let e=t.split(".");if(e.length<2)return null;let r=JSON.parse(Buffer.from(e[1].replace(/-/g,"+").replace(/_/g,"/"),"base64").toString("utf8"));return r.email||r.preferred_username||r.upn||r.sub||null}catch{return null}}function Y(t){if(!t)return null;try{let e=t.split(".");if(e.length<2)return null;let r=JSON.parse(Buffer.from(e[1].replace(/-/g,"+").replace(/_/g,"/"),"base64").toString("utf8")),{clientId:n,clientSecret:s,tenant:o}=r;return !n||!s||!o?null:{clientId:n,clientSecret:s,tenant:o}}catch{return null}}function dr(t){let e=Buffer.from(JSON.stringify({alg:"none",typ:"JWT"})).toString("base64url"),r=Buffer.from(JSON.stringify({clientId:t.clientId,clientSecret:t.clientSecret,tenant:t.tenant})).toString("base64url");return `${e}.${r}.`}function ur(t){let e;try{e=new URL(t);}catch{throw new Error(`Invalid URL: ${t}`)}let r=process.env[f.FLOW_OBS_ALLOW_HTTP]==="true";if(!r&&e.protocol!=="https:")throw new Error(`URL must use HTTPS: ${t}`);if(e.username||e.password)throw new Error(`URL must not contain embedded credentials: ${t}`);if(!r&&ss(e.hostname))throw new Error(`SSRF: private/loopback host not allowed: ${e.hostname}`);return t}async function pr(){let t=Y(process.env[f.ANTHROPIC_AUTH_TOKEN]);if(t)return {user:await Q().catch(()=>null)??t.clientId,tenant:t.tenant};if(Kt.KEYCHAIN_ENABLED)try{let e=await _();if(!e)return {user:"",tenant:""};let r=await Q()??e.clientId??"",n=e.tenant??"";return {user:r,tenant:n}}catch{return {user:"",tenant:""}}return {user:"",tenant:""}}async function is(t){if(await ht()){let r=await gt();return l("getOrRefreshToken",`using cached token, expires=${r.expiresAt}`),r.accessToken}l("getOrRefreshToken",`token expired \u2014 refreshing via auth-engine (tenant=${t.tenant} clientId=${t.clientId})`);let e=await V(t);try{await Jt(e);}catch(r){l("getOrRefreshToken",`token cache save failed (non-fatal): ${r.message}`);}return l("getOrRefreshToken",`token refreshed, expires=${e.expiresAt}`),e.accessToken}function as(t,e){let r=e&&e.accessToken?e.accessToken:"";return {endpoint:t.replace(/\/$/,"")+"/flow-langfuse-gateway/v1/traces",authHeader:`Bearer ${r}`}}function cs(t,e,r){let n=Buffer.from(`${e}:${r}`).toString("base64");return {endpoint:t.replace(/\/$/,"")+"/api/public/otel/v1/traces",authHeader:`Basic ${n}`}}async function tt(){let t=[],e=process.env[f.ANTHROPIC_MODEL]??"",r=Y(process.env[f.ANTHROPIC_AUTH_TOKEN]);l("resolveCredentials",r?"credentials resolved from ANTHROPIC_AUTH_TOKEN":"ANTHROPIC_AUTH_TOKEN absent or invalid"),!r&&Kt.KEYCHAIN_ENABLED&&(r=await _(),r&&l("resolveCredentials","credentials resolved from keychain (FEATURES.KEYCHAIN_ENABLED=true)"));let n=r?r.tenant:"",s=process.env[f.FLOW_TELEMETRY]==="true",o=process.env[f.LANGFUSE_BASE_URL],i=process.env[f.LANGFUSE_PUBLIC_KEY],a=process.env[f.LANGFUSE_SECRET_KEY];if(s&&o&&i&&a){let m="",k=n;if(r)m=await Q().catch(()=>null)??r.clientId;else if(Kt.KEYCHAIN_ENABLED)try{let O=await _();O&&(m=await Q()??O.clientId,k=O.tenant);}catch{}let y={user:m??"",tenant:k??"",team:"",project:"",model:e};t.push({mode:"direct",...cs(ur(o),i,a),...y}),l("resolveCredentials","direct mode active",`user=${y.user}`,`tenant=${y.tenant}`);}if(!r){if(t.length===0){let m=[];return m.authError=false,m}return t}let c;try{c=await is(r);}catch(m){if(l("resolveCredentials",`token refresh failed: ${m.message}`,`(tenant=${r.tenant} clientId=${r.clientId})`),t.length>0)return t;let k=[];return k.authError=true,k}let S={user:os(c)??r.clientId,tenant:n,team:"",project:"",model:e},A=process.env[f.FLOW_TELEMETRY_GATEWAY]??X;return t.push({mode:"gateway",...as(ur(A),{accessToken:c}),...S}),t}async function fr(){return (await tt()).length>0}var ns,et=p(()=>{St();bt();T();$();ns=[/^localhost\.?$/i,/^127\./,/^10\./,/^172\.(1[6-9]|2\d|3[01])\./,/^192\.168\./,/^169\.254\./,/^0\.0\.0\.0$/,/^::1$/,/^\[::1\]$/,/^\[::ffff:/i,/^\[f[cd]/i,/^\[fe80:/i,/^metadata\.google\.internal\.?$/i,/^metadata\.azure\.internal\.?$/i,/(?:^|\.)localtest\.me\.?$/i,/(?:^|\.)lvh\.me\.?$/i,/(?:^|\.)vcap\.me\.?$/i];});var hr={};U(hr,{runLogin:()=>K,runLogout:()=>fs,runStatus:()=>ms});function G(t){return typeof t=="string"?t.replace(ls,""):t}function Pt(t,e={}){return new Promise((r,n)=>{let{masked:s=false,defaultValue:o=""}=e;process.stdout.write(t+o);let i=o;function a(){try{process.stdin.setRawMode(!1);}catch{}}process.once("uncaughtException",a),process.once("unhandledRejection",a);let c=S=>{if(S===""){u(),n(new Error("SIGINT"));return}if(S==="\r"||S===`
16
+ `){u(),process.stdout.write(`
17
+ `),r(i);return}if(S==="\x7F"){i.length>0&&(i=i.slice(0,-1),process.stdout.write("\b \b"));return}S.startsWith("\x1B")||(i+=S,process.stdout.write(s?"*".repeat(S.length):S));};function u(){process.stdin.setRawMode(false),process.stdin.removeListener("data",c),process.removeListener("uncaughtException",a),process.removeListener("unhandledRejection",a);}process.stdin.setRawMode(true),process.stdin.resume(),process.stdin.setEncoding("utf8"),process.stdin.on("data",c);})}async function mr(t){try{let e=await _();(!e||e.clientId!==t.clientId||e.clientSecret!==t.clientSecret||e.tenant!==t.tenant)&&await ye(t);}catch{}}async function gr(t){let{accessToken:e,expiresAt:r}=await V(t);await ye(t),await Jt({accessToken:e,expiresAt:r});try{let n=dr(t);Wt({[f.ANTHROPIC_AUTH_TOKEN]:n});}catch{}}async function us(t){try{return await gr(t),process.stdout.write(P(` \u2713 Setup complete. Tenant: ${G(t.tenant)}
18
+
19
+ `)),0}catch(e){return process.stderr.write(D(` \u2717 Authentication failed: ${G(e.message)}
20
+ `)),1}}async function ds(){try{process.stdout.write(`
21
+ `);let t=(await Pt(B(" ? ")+"Client ID: ")).trim(),e=(await Pt(B(" ? ")+"Client Secret: ",{masked:!0})).trim(),r=(await Pt(B(" ? ")+"Tenant: ")).trim();if(!t||!e||!r)return process.stderr.write(D(` \u2717 All fields are required
22
+ `)),1;try{await gr({clientId:t,clientSecret:e,tenant:r});}catch(n){return process.stderr.write(D(` \u2717 Authentication failed: ${G(n.message)}
23
+ `)),1}return process.stdout.write(P(` \u2713 Setup complete. Tenant: ${G(r)}
24
+ `)),process.stdout.write(` Storage: ${await _e()}
25
+
26
+ `),0}catch(t){if(t.message==="SIGINT")throw t;return process.stderr.write(D(` \u2717 Unexpected error: ${t.message}
27
+ `)),1}}async function K(t={}){if(t.clientId&&t.clientSecret&&t.tenant)return us({clientId:t.clientId,clientSecret:t.clientSecret,tenant:t.tenant});let e=Y(process.env[f.ANTHROPIC_AUTH_TOKEN]);e&&await mr(e);let r=e||await _();if(r){process.stdout.write(`
28
+ `),process.stdout.write(H(` Already authenticated
29
+ `)),process.stdout.write(E(" Tenant: ")+G(r.tenant)+`
30
+ `),process.stdout.write(E(" Client ID: ")+G(r.clientId)+`
31
31
  `),process.stdout.write(`
32
- `);let s;try{s=await ae(ie(" ? ")+"Re-authenticate? (y/N): ");}catch(o){if(o.message==="SIGINT")return process.stdout.write(`
33
- `),130;throw o}if(s.trim().toLowerCase()!=="y")return process.stdout.write(ye(` \u2713 Using existing credentials.
34
-
35
- `)),0}try{return await oo()}catch(s){if(s.message==="SIGINT")return process.stdout.write(`
36
- `),130;throw s}}async function ao(){try{return process.stdout.write(`
37
- `),(await ae(ie(" ? ")+"Are you sure? This will remove your local credentials. (y/N): ")).toLowerCase()!=="y"?(process.stdout.write(ge(` \u26A0 Logout cancelled
38
- `)),0):null}catch(e){if(e.message==="SIGINT")return process.stdout.write(`
39
- `),130;throw e}}async function co(e=false){if(!await Qr())return process.stdout.write(ge(` \u26A0 You are not authenticated
40
- `)),0;if(!e){let t=await ao();if(t!==null)return t}try{return await Xr(),process.stdout.write(ye(` \u2713 Credentials removed successfully
41
- `)),0}catch{return process.stderr.write(oe(` \u2717 Error removing credentials
42
- `)),1}}async function uo(){let e=Vt(process.env[Ze.ANTHROPIC_AUTH_TOKEN]);e&&await Xt(e);let t=e||await ze();if(!t)return process.stdout.write(ge(" \u26A0 Not authenticated. Run `flow-ai-obs auth login` to set up.\n")),0;if(!e&&!await Zr())return process.stdout.write(ge(" \u26A0 Session expired. Run `flow-ai-obs auth login` to re-authenticate.\n")),0;let n=t.clientSecret.length>4?"****...****"+t.clientSecret.slice(-4):"****",s=e?"ANTHROPIC_AUTH_TOKEN (settings.json)":await Wt();return process.stdout.write(`
43
- `+Jt(` Authenticated
44
- `)),process.stdout.write(V(" Tenant: ")+b(t.tenant)+`
45
- `),process.stdout.write(V(" Client ID: ")+b(t.clientId)+`
46
- `),process.stdout.write(V(" Client Secret: ")+n+`
47
- `),process.stdout.write(V(" Storage: ")+s+`
48
-
49
- `),0}Zt.exports={runLogin:io,runLogout:co,runStatus:uo};});var et=l((nc,sn)=>{var lo=u("fs"),Qe=u("path"),Qt=u("os"),{spawnSync:po}=u("child_process"),{writeClaudeSettings:fo}=ne(),{NATIVE_OTEL:ho,ENV:To}=w(),{green:So,red:Eo,yellow:en,bold:tn,dim:L,cyan:wo}=B(),{runLogin:_o}=ce(),nn={darwin:`npm install -g @anthropic-ai/claude-code
50
- or visit: https://claude.ai/download`,linux:"npm install -g @anthropic-ai/claude-code",win32:`npm install -g @anthropic-ai/claude-code
51
- or visit: https://claude.ai/download`};function go(){let e=process.platform==="win32"?"where":"which";return po(e,["claude"],{encoding:"utf8",timeout:5e3}).status===0}function yo(){return process.platform==="win32"?Qe.join(process.env.APPDATA||Qe.join(Qt.homedir(),"AppData","Roaming"),"Claude","settings.json"):Qe.join(Qt.homedir(),".claude","settings.json")}function mo(){try{let e=lo.readFileSync(yo(),"utf8"),t=JSON.parse(e);return !!(t.env&&t.env[To.ANTHROPIC_AUTH_TOKEN])}catch{return false}}async function Ao(){if(!go()){let n=nn[process.platform]||nn.linux;return process.stderr.write(`
52
- `+Eo(` \u2717 Claude Code is not installed or not found in PATH.
32
+ `);let n;try{n=await Pt(B(" ? ")+"Re-authenticate? (y/N): ");}catch(s){if(s.message==="SIGINT")return process.stdout.write(`
33
+ `),130;throw s}if(n.trim().toLowerCase()!=="y")return process.stdout.write(P(` \u2713 Using existing credentials.
34
+
35
+ `)),0}try{return await ds()}catch(n){if(n.message==="SIGINT")return process.stdout.write(`
36
+ `),130;throw n}}async function ps(){try{return process.stdout.write(`
37
+ `),(await Pt(B(" ? ")+"Are you sure? This will remove your local credentials. (y/N): ")).toLowerCase()!=="y"?(process.stdout.write(L(` \u26A0 Logout cancelled
38
+ `)),0):null}catch(t){if(t.message==="SIGINT")return process.stdout.write(`
39
+ `),130;throw t}}async function fs(t=false){if(!await lr())return process.stdout.write(L(` \u26A0 You are not authenticated
40
+ `)),0;if(!t){let e=await ps();if(e!==null)return e}try{return await cr(),process.stdout.write(P(` \u2713 Credentials removed successfully
41
+ `)),0}catch{return process.stderr.write(D(` \u2717 Error removing credentials
42
+ `)),1}}async function ms(){let t=Y(process.env[f.ANTHROPIC_AUTH_TOKEN]);t&&await mr(t);let e=t||await _();if(!e)return process.stdout.write(L(" \u26A0 Not authenticated. Run `flow-ai-obs auth login` to set up.\n")),0;if(!t&&!await ht())return process.stdout.write(L(" \u26A0 Session expired. Run `flow-ai-obs auth login` to re-authenticate.\n")),0;let r=e.clientSecret.length>4?"****...****"+e.clientSecret.slice(-4):"****",n=t?"ANTHROPIC_AUTH_TOKEN (settings.json)":await _e();return process.stdout.write(`
43
+ `+H(` Authenticated
44
+ `)),process.stdout.write(E(" Tenant: ")+G(e.tenant)+`
45
+ `),process.stdout.write(E(" Client ID: ")+G(e.clientId)+`
46
+ `),process.stdout.write(E(" Client Secret: ")+r+`
47
+ `),process.stdout.write(E(" Storage: ")+n+`
48
+
49
+ `),0}var ls,Rt=p(()=>{St();bt();et();It();T();at();ls=/[\x00-\x08\x0B-\x1F\x7F]|\x1b\[[0-9;]*[a-zA-Z]/g;});var wr={};U(wr,{runInstall:()=>Ae});function hs(){let t=process.platform==="win32"?"where":"which";return child_process.spawnSync(t,["claude"],{encoding:"utf8",timeout:5e3}).status===0}function Ss(){return process.platform==="win32"?pt__namespace.join(process.env.APPDATA||pt__namespace.join(ue__namespace.homedir(),"AppData","Roaming"),"Claude","settings.json"):pt__namespace.join(ue__namespace.homedir(),".claude","settings.json")}function Es(){try{let t=w__namespace.readFileSync(Ss(),"utf8"),e=JSON.parse(t);return !!(e.env&&e.env[f.ANTHROPIC_AUTH_TOKEN])}catch{return false}}async function Ae(){if(!hs()){let r=Sr[process.platform]||Sr.linux;return process.stderr.write(`
50
+ `+D(` \u2717 Claude Code is not installed or not found in PATH.
53
51
 
54
52
  `)+` flow-ai-obs requires Claude Code to function.
55
53
  Install it with:
56
54
 
57
- `+wo(` ${n}`)+`
55
+ `+B(` ${r}`)+`
58
56
 
59
- `),1}if(!mo()){process.stdout.write(en(` \u26A0 No credentials found in settings.json \u2014 authentication required.
57
+ `),1}if(!Es()){process.stdout.write(L(` \u26A0 No credentials found in settings.json \u2014 authentication required.
60
58
 
61
- `));let n=await _o();if(n!==0)return n}let e,t;try{({settingsPath:e,preserved:t}=fo());}catch(n){return process.stderr.write(` \u2717 Failed to write settings: ${n.message}
59
+ `));let r=await K();if(r!==0)return r}let t,e;try{({settingsPath:t,preserved:e}=Je());}catch(r){return process.stderr.write(` \u2717 Failed to write settings: ${r.message}
62
60
  `),1}process.stdout.write(`
63
- `+tn(" Native OTEL configured")+` (metrics & logs)
64
- `);for(let[n,s]of Object.entries(ho))process.stdout.write(L(` ${n.padEnd(36)}`)+s+`
61
+ `+H(" Native OTEL configured")+` (metrics & logs)
62
+ `);for(let[r,n]of Object.entries(lt))process.stdout.write(E(` ${r.padEnd(36)}`)+n+`
65
63
  `);return process.stdout.write(`
66
- `),process.stdout.write(tn(" Hooks registered")+` (Langfuse trace capture)
67
- `),process.stdout.write(L(" UserPromptSubmit")+` \u2192 flow-ai-obs UserPromptSubmit (timeout: 5s)
68
- `),process.stdout.write(L(" PreToolUse ")+` \u2192 flow-ai-obs PreToolUse (timeout: 3s)
69
- `),process.stdout.write(L(" PostToolUse ")+` \u2192 flow-ai-obs PostToolUse (timeout: 10s)
70
- `),process.stdout.write(L(" Stop ")+` \u2192 flow-ai-obs Stop (timeout: 15s)
71
- `),t.length>0&&(process.stdout.write(`
72
- `),process.stdout.write(en(` \u26A0 Third-party hooks detected and preserved on: ${t.join(", ")}
73
- `)),process.stdout.write(L(` flow-ai-obs was prepended \u2014 it executes first.
64
+ `),process.stdout.write(H(" Hooks registered")+` (Langfuse trace capture)
65
+ `),process.stdout.write(E(" UserPromptSubmit")+` \u2192 flow-ai-obs UserPromptSubmit (timeout: 5s)
66
+ `),process.stdout.write(E(" PreToolUse ")+` \u2192 flow-ai-obs PreToolUse (timeout: 3s)
67
+ `),process.stdout.write(E(" PostToolUse ")+` \u2192 flow-ai-obs PostToolUse (timeout: 10s)
68
+ `),process.stdout.write(E(" Stop ")+` \u2192 flow-ai-obs Stop (timeout: 15s)
69
+ `),e.length>0&&(process.stdout.write(`
70
+ `),process.stdout.write(L(` \u26A0 Third-party hooks detected and preserved on: ${e.join(", ")}
71
+ `)),process.stdout.write(E(` flow-ai-obs was prepended \u2014 it executes first.
74
72
  `))),process.stdout.write(`
75
- `),process.stdout.write(L(" Settings: ")+e+`
76
- `),process.stdout.write(L(" Backup: ")+e+`.bkp
77
- `),process.stdout.write(L(" OTEL auth: flow-ai-obs otel-headers")+L(` (reads keychain at runtime)
73
+ `),process.stdout.write(E(" Settings: ")+t+`
74
+ `),process.stdout.write(E(" Backup: ")+t+`.bkp
75
+ `),process.stdout.write(E(" OTEL auth: flow-ai-obs otel-headers")+E(` (reads keychain at runtime)
78
76
  `)),process.stdout.write(`
79
- `),process.stdout.write(So(` \u2713 Ready. Native OTEL + Langfuse trace capture active.
80
- `)),process.stdout.write(L(" Run `flow-ai-obs setup` to also configure the Flow LLM Proxy.\n\n")),0}sn.exports={runInstall:Ao};});var ln=l((sc,un)=>{var{LLM_PROXY:rn}=w(),{green:on,yellow:an,bold:Lo,dim:cn}=B(),{runLogin:Oo}=ce(),{runInstall:Io}=et(),{addEnvToClaudeSettings:No,validateConnectivity:ko,getClaudeSettingsPath:Co}=ne(),{getFlowCredentials:vo}=W();async function bo(e={}){process.stdout.write(`
77
+ `),process.stdout.write(P(` \u2713 Ready. Native OTEL + Langfuse trace capture active.
78
+ `)),process.stdout.write(E(" Run `flow-ai-obs setup` to also configure the Flow LLM Proxy.\n\n")),0}var Sr,Oe=p(()=>{It();T();at();Rt();Sr={darwin:`npm install -g @anthropic-ai/claude-code
79
+ or visit: https://claude.ai/download`,linux:"npm install -g @anthropic-ai/claude-code",win32:`npm install -g @anthropic-ai/claude-code
80
+ or visit: https://claude.ai/download`};});var Tr={};U(Tr,{runSetup:()=>ws});async function ws(t={}){process.stdout.write(`
81
81
  \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
82
82
  `),process.stdout.write(`\u2551 flow-ai-obs \u2014 setup \u2551
83
83
  `),process.stdout.write(`\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
84
84
 
85
- `);let t=await Oo(e);if(t!==0)return process.stderr.write(`
85
+ `);let e=await K(t);if(e!==0)return process.stderr.write(`
86
86
  Setup aborted. Run \`flow-ai-obs auth login\` to retry.
87
87
 
88
- `),t;process.stdout.write(`
89
- `);let n=await Io();if(n!==0)return n;try{No(rn);}catch(o){process.stderr.write(` \u26A0 Could not write LLM Proxy config: ${o.message}
90
- `);}process.stdout.write(Lo(" Flow LLM Proxy configured")+` (model provider)
91
- `);for(let[o,r]of Object.entries(rn))process.stdout.write(cn(` ${o.padEnd(36)}`)+r+`
88
+ `),e;process.stdout.write(`
89
+ `);let r=await Ae();if(r!==0)return r;try{Wt(Lt);}catch(s){process.stderr.write(` \u26A0 Could not write LLM Proxy config: ${s.message}
90
+ `);}process.stdout.write(H(" Flow LLM Proxy configured")+` (model provider)
91
+ `);for(let[s,o]of Object.entries(Lt))process.stdout.write(E(` ${s.padEnd(36)}`)+o+`
92
92
  `);process.stdout.write(`
93
93
  `),process.stdout.write(` Validating connectivity to Flow OTEL endpoint\u2026
94
- `);let s=await vo();return s?await ko(s)?process.stdout.write(on(` \u2713 Connectivity validated \u2014 telemetry is active.
94
+ `);let n=await _();return n?await Xe(n)?process.stdout.write(P(` \u2713 Connectivity validated \u2014 telemetry is active.
95
95
 
96
- `)):process.stdout.write(an(` \u26A0 Could not reach the OTEL endpoint. Telemetry will activate once connectivity is restored.
96
+ `)):process.stdout.write(L(` \u26A0 Could not reach the OTEL endpoint. Telemetry will activate once connectivity is restored.
97
97
 
98
- `)):process.stdout.write(an(` \u26A0 Could not read stored credentials \u2014 skipping connectivity check.
98
+ `)):process.stdout.write(L(` \u26A0 Could not read stored credentials \u2014 skipping connectivity check.
99
99
 
100
- `)),process.stdout.write(on(` \u2713 Setup complete!
101
- `)),process.stdout.write(cn(` Settings: ${Co()}
100
+ `)),process.stdout.write(P(` \u2713 Setup complete!
101
+ `)),process.stdout.write(E(` Settings: ${dt()}
102
102
 
103
- `)),0}un.exports={runSetup:bo};});var pn=l((rc,dn)=>{var{getFlowCredentials:Uo}=W(),{getToken:Ro}=Q();async function Po(){let e;try{e=await Uo();}catch{return process.stderr.write(`[flow-ai-obs otel-headers] Failed to read credentials
104
- `),1}if(!e)return process.stderr.write(`[flow-ai-obs otel-headers] Not authenticated \u2014 run: flow-ai-obs auth login
105
- `),1;let t;try{t=(await Ro(e)).accessToken;}catch(n){return process.stderr.write(`[flow-ai-obs otel-headers] Token fetch failed: ${n.message}
106
- `),1}return t?(process.stdout.write(`{"Authorization": "Bearer ${t}"}
103
+ `)),0}var yr=p(()=>{T();at();Rt();Oe();It();St();});var _r={};U(_r,{runOtelHeaders:()=>Ts});async function Ts(){let t;try{t=await _();}catch{return process.stderr.write(`[flow-ai-obs otel-headers] Failed to read credentials
104
+ `),1}if(!t)return process.stderr.write(`[flow-ai-obs otel-headers] Not authenticated \u2014 run: flow-ai-obs auth login
105
+ `),1;let e;try{e=(await V(t)).accessToken;}catch(r){return process.stderr.write(`[flow-ai-obs otel-headers] Token fetch failed: ${r.message}
106
+ `),1}return e?(process.stdout.write(`{"Authorization": "Bearer ${e}"}
107
107
  `),0):(process.stderr.write(`[flow-ai-obs otel-headers] Empty token received
108
- `),1)}dn.exports={runOtelHeaders:Po};});var En=l((oc,Sn)=>{var{getFlowCredentials:fn,isTokenValid:Fo,getEmailFromToken:$o,getTokenCache:qo}=W(),{resolveCredentials:xo,parseCredsFromAnthropicToken:hn}=x(),{getClaudeSettingsPath:Mo}=ne(),{ENV:U,NATIVE_OTEL:Do}=w(),{runLogin:Tn}=ce(),Bo=u("fs");function tt(e){return !e||e.length<=8?"****":e.slice(0,4)+"****...****"+e.slice(-4)}function ue(e){process.stdout.write(` \u2713 ${e}
109
- `);}function me(e){process.stdout.write(` \u26A0 ${e}
110
- `);}function Ae(e){process.stdout.write(` \u2717 ${e}
111
- `);}function m(e){process.stdout.write(` ${e}
112
- `);}function A(){process.stdout.write(`
113
- `);}async function Ho(){A(),process.stdout.write(` flow-claude-observability \u2014 configuration check
114
- `),A(),process.stdout.write(` Auth
115
- `);let e=hn(process.env[U.ANTHROPIC_AUTH_TOKEN]),t=e||await fn();if(!t){me("Not authenticated \u2014 starting setup..."),A();let a=await Tn();if(a!==0)return a;if(e=hn(process.env[U.ANTHROPIC_AUTH_TOKEN]),t=e||await fn(),!t)return Ae("Authentication failed"),A(),1;A(),process.stdout.write(` Auth
116
- `);}if(!e&&!await Fo()){me("Session expired \u2014 re-authenticating..."),A();let a=await Tn();if(a!==0)return a;A(),process.stdout.write(` Auth
117
- `);}let n=await $o()||t.clientId;ue("Authenticated"),m(`Tenant: ${t.tenant}`),m(`User: ${n}`),A(),process.stdout.write(` Native OTEL
118
- `);let s={};try{let a=Bo.readFileSync(Mo(),"utf8");s=JSON.parse(a).env||{};}catch{}let o=Object.keys(Do).filter(a=>!s[a]);if(o.length===0?(ue("All OTEL env vars present in settings.json"),m(`Endpoint: ${s.OTEL_EXPORTER_OTLP_ENDPOINT}`)):(me(`${o.length} OTEL var(s) missing from settings.json \u2014 native metrics/logs disabled`),o.forEach(a=>Ae(`Missing: ${a}`)),m("Run: flow-ai-obs install (restores missing vars automatically)")),A(),process.stdout.write(` Tracing
119
- `),process.env[U.FLOW_TELEMETRY]==="true"){ue("FLOW_TELEMETRY=true (direct mode enabled)");let a=[U.LANGFUSE_BASE_URL,U.LANGFUSE_PUBLIC_KEY,U.LANGFUSE_SECRET_KEY].filter(c=>!process.env[c]);a.length>0&&a.forEach(c=>me(`Missing: ${c}`));}else m("FLOW_TELEMETRY not set \u2014 direct mode inactive (gateway mode may still be active)");let i=await xo();if(!i||i.length===0)return i&&i.authError?Ae("Token refresh failed \u2014 gateway mode could not activate"):(Ae("No active destinations \u2014 no traces will be sent"),m("For direct mode: set FLOW_TELEMETRY=true + LANGFUSE_BASE_URL + LANGFUSE_PUBLIC_KEY + LANGFUSE_SECRET_KEY"),m("For gateway mode: run flow-claude-observability auth login")),A(),1;for(let a of i)if(a.mode==="gateway"){let c=await qo();ue("Mode: gateway"),m(`Endpoint: ${a.endpoint}`),m(`Token: ${tt(c&&c.accessToken)}`);}else a.mode==="direct"&&(ue("Mode: direct"),m(`Endpoint: ${a.endpoint}`),m(`PK: ${tt(process.env[U.LANGFUSE_PUBLIC_KEY])}`),m(`SK: ${tt(process.env[U.LANGFUSE_SECRET_KEY])}`));return A(),process.stdout.write(` All checks passed \u2014 observability is active.
120
- `),A(),0}Sn.exports={runCheck:Ho};});var J=l((ic,wn)=>{function Yo(e,t){let n=typeof e=="object"?JSON.stringify(e):String(e??"");return n.length>t?n.slice(0,t)+" \u2026[truncated]":n}function jo(e,t=100){return String(e??"").split(`
121
- `)[0].slice(0,t).trim()}function Go(){return new Promise(e=>{let t="";process.stdin.setEncoding("utf8"),process.stdin.on("data",n=>t+=n),process.stdin.on("end",()=>{try{e(JSON.parse(t));}catch{e({});}});})}function Ko(e){process.stdout.write(JSON.stringify(e));}wn.exports={truncate:Yo,firstLine:jo,readInput:Go,passthrough:Ko};});var le=l((ac,gn)=>{var{randomBytes:_n}=u("crypto"),Wo=()=>_n(16).toString("hex"),Vo=()=>_n(8).toString("hex");function Jo(){return String(BigInt(Date.now())*1000000n)}gn.exports={generateTraceId:Wo,generateSpanId:Vo,nowNs:Jo};});var de=l((uc,mn)=>{var{readFileSync:Xo,writeFileSync:zo,unlinkSync:Zo,existsSync:Qo,realpathSync:cc}=u("fs"),{tmpdir:yn}=u("os"),{join:ei,resolve:ti,normalize:ni,sep:si}=u("path"),ri=/^[0-9a-f-]{1,64}$/i,oi=ni(yn())+si;function ii(e,t){let n=ti(e);if(!n.startsWith(t))throw new Error(`Path traversal detected: ${e}`);return n}function nt(e){if(!ri.test(e))throw new Error(`Invalid session ID: ${e}`);return ii(ei(yn(),`flow-obs-${e}.json`),oi)}function ai(e){let t=nt(e);if(!Qo(t))return null;try{return JSON.parse(Xo(t,"utf8"))}catch{return null}}function ci(e,t){zo(nt(e),JSON.stringify(t),{encoding:"utf8",mode:384});}function ui(e){try{Zo(nt(e));}catch{}}mn.exports={loadState:ai,saveState:ci,deleteState:ui};});var st=l((lc,On)=>{var{readFileSync:An,existsSync:Ln}=u("fs");function li(e){if(!e||!Ln(e))return null;try{let t=An(e,"utf8").trimEnd().split(`
122
- `);for(let n=t.length-1;n>=0;n--)try{let s=JSON.parse(t[n]);if(s.type==="user"&&s.uuid)return s.uuid}catch{}}catch{}return null}function di(e){if(!e||!Ln(e))return null;try{let t=An(e,"utf8").trimEnd().split(`
123
- `),n=[],s=0,o=0,r=!1;for(let i=t.length-1;i>=0;i--)try{let a=JSON.parse(t[i]);if(a.type==="user"){if(r)break;continue}if(a.type==="assistant"){r=!0;let p=(a.message?.content??[]).filter(S=>S.type==="text").map(S=>S.text).join("");p&&n.unshift(p);let h=a.message?.usage??{};s+=(h.input_tokens??0)+(h.cache_read_input_tokens??0)+(h.cache_creation_input_tokens??0),o+=h.output_tokens??0;}}catch{}return !n.length&&s===0?null:{text:n.join(`
124
-
125
- `),inputTokens:s,outputTokens:o}}catch{}return null}On.exports={readPromptUuid:li,readLastAssistantOutput:di};});var Le=l((dc,Cn)=>{var{readFileSync:pi,existsSync:In,readdirSync:fi}=u("fs"),{homedir:Nn}=u("os"),{join:X,extname:hi}=u("path"),Ti=new Set([".venv","__pycache__",".git","node_modules"]),Si=new Set([".pyc",".pyo"]),Ei=new Set(["SKILL.md",".DS_Store",".gitignore"]);function wi(e,t){if(!e)return null;let n=[X(Nn(),".claude","skills",e,"SKILL.md"),X(t||"",".claude","skills",e,"SKILL.md")];for(let s of n)if(In(s))try{return pi(s,"utf8")}catch{}return null}function _i(e){return e.match(/^\/([a-z][a-z0-9-]*)(?:\s.*)?$/i)?.[1]||null}var kn=new Set(["Read","Write","Edit","MultiEdit","Bash","Glob","Grep","TodoWrite","WebFetch","WebSearch","Agent","Task"]);function gi(e){return !!e.slashSkill||e.toolCalls.some(s=>s.tool==="Skill")?e.toolCalls.some(s=>kn.has(s.tool))?"complete":"prerequisite_required":null}function yi(e,t){if(!e)return null;let n=[X(Nn(),".claude","skills",e),X(t||"",".claude","skills",e)],s=null;for(let i of n)if(In(X(i,"SKILL.md"))){s=i;break}if(!s)return null;let o=[];function r(i,a){for(let c of fi(i,{withFileTypes:true})){if(Ti.has(c.name)||Ei.has(c.name)||Si.has(hi(c.name)))continue;let p=a?`${a}/${c.name}`:c.name;c.isDirectory()?r(X(i,c.name),p):o.push(p);}}return r(s,""),o.length>0?o:null}Cn.exports={readSkillContent:wi,readSkillArtifacts:yi,detectSlashSkill:_i,EXECUTION_TOOLS:kn,detectExecutionStatus:gi};});var Rn=l((pc,Un)=>{var{generateTraceId:vn,generateSpanId:mi,nowNs:Ai}=le(),{saveState:Li}=de(),{readPromptUuid:Oi}=st(),{detectSlashSkill:Ii,readSkillContent:Ni,readSkillArtifacts:ki}=Le(),{passthrough:Ci}=J(),{dbg:bn}=v(),{ENV:vi}=w(),{resolveCredentials:bi}=x();async function Ui(e){let t=e.session_id||"unknown",n=e.prompt||"",s=e.cwd||"";try{(await bi()).authError===!0&&(process.stderr.write(`
108
+ `),1)}var kr=p(()=>{St();bt();});var Or={};U(Or,{runCheck:()=>ys});function Le(t){return !t||t.length<=8?"****":t.slice(0,4)+"****...****"+t.slice(-4)}function Ct(t){process.stdout.write(` \u2713 ${t}
109
+ `);}function zt(t){process.stdout.write(` \u26A0 ${t}
110
+ `);}function Zt(t){process.stdout.write(` \u2717 ${t}
111
+ `);}function b(t){process.stdout.write(` ${t}
112
+ `);}function I(){process.stdout.write(`
113
+ `);}async function ys(){I(),process.stdout.write(` flow-claude-observability \u2014 configuration check
114
+ `),I(),process.stdout.write(` Auth
115
+ `);let t=Y(process.env[f.ANTHROPIC_AUTH_TOKEN]),e=t||await _();if(!e){zt("Not authenticated \u2014 starting setup..."),I();let a=await K();if(a!==0)return a;if(t=Y(process.env[f.ANTHROPIC_AUTH_TOKEN]),e=t||await _(),!e)return Zt("Authentication failed"),I(),1;I(),process.stdout.write(` Auth
116
+ `);}if(!t&&!await ht()){zt("Session expired \u2014 re-authenticating..."),I();let a=await K();if(a!==0)return a;I(),process.stdout.write(` Auth
117
+ `);}let r=await Q()||e.clientId;Ct("Authenticated"),b(`Tenant: ${e.tenant}`),b(`User: ${r}`),I(),process.stdout.write(` Native OTEL
118
+ `);let n={};try{let a=w__namespace.readFileSync(dt(),"utf8");n=JSON.parse(a).env||{};}catch{}let s=Object.keys(lt).filter(a=>!n[a]);if(s.length===0?(Ct("All OTEL env vars present in settings.json"),b(`Endpoint: ${n.OTEL_EXPORTER_OTLP_ENDPOINT}`)):(zt(`${s.length} OTEL var(s) missing from settings.json \u2014 native metrics/logs disabled`),s.forEach(a=>Zt(`Missing: ${a}`)),b("Run: flow-ai-obs install (restores missing vars automatically)")),I(),process.stdout.write(` Tracing
119
+ `),process.env[f.FLOW_TELEMETRY]==="true"){Ct("FLOW_TELEMETRY=true (direct mode enabled)");let a=[f.LANGFUSE_BASE_URL,f.LANGFUSE_PUBLIC_KEY,f.LANGFUSE_SECRET_KEY].filter(c=>!process.env[c]);a.length>0&&a.forEach(c=>zt(`Missing: ${c}`));}else b("FLOW_TELEMETRY not set \u2014 direct mode inactive (gateway mode may still be active)");let i=await tt();if(!i||i.length===0)return i&&i.authError?Zt("Token refresh failed \u2014 gateway mode could not activate"):(Zt("No active destinations \u2014 no traces will be sent"),b("For direct mode: set FLOW_TELEMETRY=true + LANGFUSE_BASE_URL + LANGFUSE_PUBLIC_KEY + LANGFUSE_SECRET_KEY"),b("For gateway mode: run flow-claude-observability auth login")),I(),1;for(let a of i)if(a.mode==="gateway"){let c=await gt();Ct("Mode: gateway"),b(`Endpoint: ${a.endpoint}`),b(`Token: ${Le(c?.accessToken)}`);}else a.mode==="direct"&&(Ct("Mode: direct"),b(`Endpoint: ${a.endpoint}`),b(`PK: ${Le(process.env[f.LANGFUSE_PUBLIC_KEY])}`),b(`SK: ${Le(process.env[f.LANGFUSE_SECRET_KEY])}`));return I(),process.stdout.write(` All checks passed \u2014 observability is active.
120
+ `),I(),0}var Lr=p(()=>{St();et();It();T();Rt();});function x(t,e){let r=typeof t=="object"?JSON.stringify(t):String(t??"");return r.length>e?r.slice(0,e)+" \u2026[truncated]":r}function Qt(t,e=100){return String(t??"").split(`
121
+ `)[0].slice(0,e).trim()}function br(){return new Promise(t=>{let e="";process.stdin.setEncoding("utf8"),process.stdin.on("data",r=>{e+=r;}),process.stdin.on("end",()=>{try{t(JSON.parse(e));}catch{t({});}});})}function C(t){process.stdout.write(JSON.stringify(t));}var Et=p(()=>{});function W(){return String(BigInt(Date.now())*1000000n)}var be,rt,Ut=p(()=>{be=()=>crypto.randomBytes(16).toString("hex"),rt=()=>crypto.randomBytes(8).toString("hex");});function Rs(t,e){let r=pt.resolve(t);if(!r.startsWith(e))throw new Error(`Path traversal detected: ${t}`);return r}function Ie(t){if(!Ns.test(t))throw new Error(`Invalid session ID: ${t}`);return Rs(pt.join(ue.tmpdir(),`flow-obs-${t}.json`),Ps)}function wt(t){let e=Ie(t);if(!w.existsSync(e))return null;try{return JSON.parse(w.readFileSync(e,"utf8"))}catch{return null}}function Tt(t,e){w.writeFileSync(Ie(t),JSON.stringify(e),{encoding:"utf8",mode:384});}function ve(t){try{w.unlinkSync(Ie(t));}catch{}}var Ns,Ps,Ft=p(()=>{Ns=/^[0-9a-f-]{1,64}$/i,Ps=pt.normalize(ue.tmpdir())+pt.sep;});function Rr(t){if(!t||!w.existsSync(t))return null;try{let e=w.readFileSync(t,"utf8").trimEnd().split(`
122
+ `);for(let r=e.length-1;r>=0;r--)try{let n=JSON.parse(e[r]);if(n.type==="user"&&n.uuid)return n.uuid}catch{}}catch{}return null}function Ne(t){if(!t||!w.existsSync(t))return null;try{let e=w.readFileSync(t,"utf8").trimEnd().split(`
123
+ `),r=[],n=0,s=0;for(let o=e.length-1;o>=0;o--)try{let i=JSON.parse(e[o]);if(i.type==="user")break;if(i.type==="assistant"){let c=(i.message?.content??[]).filter(S=>S.type==="text").map(S=>S.text??"").join("");c&&r.unshift(c);let u=i.message?.usage??{};n+=(u.input_tokens??0)+(u.cache_read_input_tokens??0)+(u.cache_creation_input_tokens??0),s+=u.output_tokens??0;}}catch{}return !r.length&&n===0?null:{text:r.join(`
124
+
125
+ `),inputTokens:n,outputTokens:s}}catch{}return null}var Pe=p(()=>{});function Fr(t){return t.replace(":","/")}function te(t,e){if(!t)return null;let r=Fr(t),n=[pt.join(ue.homedir(),".claude","skills",r,"SKILL.md"),pt.join(e??"",".claude","skills",r,"SKILL.md")];for(let s of n)if(w.existsSync(s))try{return w.readFileSync(s,"utf8")}catch{}return null}function $r(t){return t.split(`
126
+ `)[0].match(/^\/([a-z][a-z0-9-]*(?::[a-z][a-z0-9-]*)?)(?:\s.*)?$/i)?.[1]??null}function xr(t){return !!t.slashSkill||t.toolCalls.some(n=>n.tool==="Skill")?t.toolCalls.some(n=>n.tool==="Skill"&&!n.synthetic||Ds.has(n.tool))?"complete":"prerequisite_required":null}function ee(t,e){if(!t)return null;let r=Fr(t),n=[pt.join(ue.homedir(),".claude","skills",r),pt.join(e??"",".claude","skills",r)],s=null;for(let a of n)if(w.existsSync(pt.join(a,"SKILL.md"))){s=a;break}if(!s)return null;let o=[];function i(a,c){for(let u of w.readdirSync(a,{withFileTypes:true})){if($s.has(u.name)||Ms.has(u.name)||xs.has(pt.extname(u.name)))continue;let S=c?`${c}/${u.name}`:u.name;u.isDirectory()?i(pt.join(a,u.name),S):o.push(S);}}return i(s,""),o.length>0?o:null}var $s,xs,Ms,Ds,re=p(()=>{$s=new Set([".venv","__pycache__",".git","node_modules"]),xs=new Set([".pyc",".pyo"]),Ms=new Set(["SKILL.md",".DS_Store",".gitignore"]);Ds=new Set(["Read","Write","Edit","MultiEdit","Bash","Glob","Grep","TodoWrite","WebFetch","WebSearch","Agent","Task"]);});async function Mr(t){let e=t.session_id||"unknown",r=t.prompt||"",n=t.cwd||"";try{(await tt()).authError===!0&&(process.stderr.write(`
126
127
  \u26A0 flow-ai-obs: Your Flow credentials have expired.
127
128
  Traces will not be captured until you re-authenticate.
128
129
  Run: flow-ai-obs auth login
129
130
 
130
- `),bn("UserPromptSubmit","auth expired \u2014 warning emitted to stderr"));}catch{}let o=Oi(e.transcript_path)||vn(),r=Ii(n),i=r?Ni(r,s):null,a=r?ki(r,s):null;Li(t,{traceId:vn(),spanId:mi(),startNs:Ai(),sessionId:t,prompt:n,cwd:s,traceName:o,transcriptPath:e.transcript_path||"",model:process.env[vi.ANTHROPIC_MODEL]||"",toolCalls:[],spans:[],pendingTool:null,slashSkill:r,skillContent:i,skillArtifacts:a}),bn("UserPromptSubmit",`sid=${t}`,`traceName=${o}`,`slashSkill=${r}`),Ci(e);}Un.exports={onUserPromptSubmit:Ui};});var Fn=l((fc,Pn)=>{var{nowNs:Ri}=le(),{loadState:Pi,saveState:Fi}=de(),{truncate:$i,passthrough:qi}=J(),{dbg:xi}=v(),{TRACE_LIMITS:Mi}=w();async function Di(e){let t=e.session_id||"unknown",n=e.tool_name||"unknown",s=e.tool_input||{},o=Pi(t);o&&(o.pendingTool={name:n,inputStr:$i(s,Mi.TOOL_INPUT),startNs:Ri()},Fi(t,o)),xi("PreToolUse",`sid=${t}`,`tool=${n}`,`stateFound=${!!o}`),qi(e);}Pn.exports={onPreToolUse:Di};});var qn=l((hc,$n)=>{var{FLOW_URLS:Bi}=w();function Hi(e){let t=new URL(e),n=new URL(Bi.GATEWAY_HEALTH);return n.hostname=t.hostname,n.port=t.port,n.protocol=t.protocol,n}async function Yi(e,t){let n;try{n=Hi(e);}catch{return false}let s={};t&&(s.Authorization=String(t).replace(/[\r\n]/g,""));try{let o=await fetch(n.toString(),{method:"GET",headers:s,signal:AbortSignal.timeout(1e4)});return o.status>=200&&o.status<300}catch{return false}}async function ji(e,t,n){let s=String(n).replace(/[\r\n]/g,"");try{return (await fetch(t,{method:"POST",headers:{"Content-Type":"application/json",Authorization:s},body:JSON.stringify(e),signal:AbortSignal.timeout(1e4)})).status}catch{return 0}}$n.exports={checkHealth:Yi,sendTraces:ji};});var Hn=l((Tc,Bn)=>{var P=u("fs"),rt=u("path"),xn=u("os"),{BUFFER:R,ENV:Mn}=w(),{dbg:pe}=v();function Gi(){let e=parseInt(process.env[Mn.BUFFER_TTL_DAYS],10);return (Number.isFinite(e)?Math.max(R.MIN_TTL_DAYS,Math.min(R.MAX_TTL_DAYS,e)):R.DEFAULT_TTL_DAYS)*24*60*60*1e3}function Ki(){let e=parseInt(process.env[Mn.BUFFER_MAX_FILES],10);return Number.isFinite(e)?Math.max(R.MIN_MAX_FILES,Math.min(R.MAX_MAX_FILES,e)):R.DEFAULT_MAX_FILES}function Dn(e){if(/[/\\]/.test(e))throw new Error(`Invalid buffer fileId: ${e}`);return rt.join(xn.tmpdir(),`${R.FILE_PREFIX}${e}.json`)}function ot(){let e=xn.tmpdir(),t;try{t=P.readdirSync(e);}catch{return []}return t.filter(n=>n.startsWith(R.FILE_PREFIX)&&n.endsWith(".json")).map(n=>{let s=rt.join(e,n),o=0;try{o=P.statSync(s).mtimeMs;}catch{}return {full:s,mtime:o}}).sort((n,s)=>n.mtime-s.mtime).map(n=>n.full)}function Wi(e){try{let t=Ki(),n=ot();if(n.length>=t){let r=n.slice(0,n.length-t+1);for(let i of r)try{P.unlinkSync(i);}catch{}}let s=`${Date.now()}-${Math.random().toString(36).slice(2,8)}`,o={fileId:s,bufferedAt:Date.now(),payload:e};return P.writeFileSync(Dn(s),JSON.stringify(o),{encoding:"utf8",mode:384}),pe("buffer",`saved fileId=${s}`),s}catch(t){return pe("buffer",`saveToBuffer failed: ${t.message}`),null}}function Vi(e){let t=ot(),n=e!=null&&e>0?e:t.length,s=[];for(let o of t){if(s.length>=n)break;try{let r=P.readFileSync(o,"utf8"),i=JSON.parse(r);i&&i.fileId&&i.payload&&s.push(i);}catch{pe("buffer",`skipping malformed file: ${o}`);}}return s}function Ji(e){try{P.unlinkSync(Dn(e)),pe("buffer",`deleted fileId=${e}`);}catch{}}function Xi(){let e=Date.now()-Gi();for(let t of ot())try{let{mtimeMs:n}=P.statSync(t);n<e&&(P.unlinkSync(t),pe("buffer",`evicted stale: ${rt.basename(t)}`));}catch{}}Bn.exports={saveToBuffer:Wi,loadBuffer:Vi,deleteBuffer:Ji,cleanStaleBuffers:Xi};});var at=l((Sc,jn)=>{var{resolveCredentials:zi}=x(),{OTLP:Yn,BUFFER:Zi}=w(),{dbg:F}=v(),{checkHealth:Qi,sendTraces:it}=qn(),{saveToBuffer:Oe,loadBuffer:ea,deleteBuffer:ta,cleanStaleBuffers:na}=Hn(),sa={name:Yn.SCOPE_NAME,version:Yn.SCOPE_VERSION},ra={TRACE_NAME:"langfuse.trace.name",TRACE_INPUT:"langfuse.trace.input",TRACE_OUTPUT:"langfuse.trace.output",TRACE_METADATA:"langfuse.trace.metadata",TRACE_TAGS:"langfuse.trace.tags",USER_ID:"langfuse.user.id",SESSION_ID:"langfuse.session.id",OBS_NAME:"langfuse.observation.name",OBS_INPUT:"langfuse.observation.input",OBS_OUTPUT:"langfuse.observation.output",OBS_LEVEL:"langfuse.observation.level",OBS_TYPE:"langfuse.observation.type",MODEL:"gen_ai.request.model",INPUT_TOKENS:"gen_ai.usage.input_tokens",OUTPUT_TOKENS:"gen_ai.usage.output_tokens"};function oa(e,t){return t==null||t===""?null:{key:e,value:{stringValue:String(t)}}}function ia(...e){return e.filter(Boolean)}function aa(e,t){return {resourceSpans:[{resource:{attributes:e},scopeSpans:[{scope:sa,spans:Array.isArray(t)?t:[t]}]}]}}async function ca(e){na();let t=ea(Zi.REPLAY_BATCH_SIZE);t.length&&(F("replayBufferedTraces",`replaying ${t.length} buffered trace(s)`),await Promise.allSettled(t.map(async n=>{try{let s=await it(n.payload,e.endpoint,e.authHeader);s>=200&&s<300?(ta(n.fileId),F("replayBufferedTraces",`replayed fileId=${n.fileId} status=${s}`)):F("replayBufferedTraces",`replay failed fileId=${n.fileId} status=${s}`);}catch(s){F("replayBufferedTraces",`replay error fileId=${n.fileId}: ${s.message}`);}})));}async function ua(e){let t=await zi();if(!t.length)return t.authError&&(F("postToLangfuse","auth refresh failed \u2014 buffering trace"),Oe(e)),0;let n=await Promise.all(t.map(async r=>{if(r.mode!=="gateway")return {creds:r,healthy:true};let i=await Qi(r.endpoint,r.authHeader);return {creds:r,healthy:i}})),s=n.find(r=>r.creds.mode==="gateway"&&r.healthy)?.creds??n.find(r=>r.creds.mode==="direct")?.creds;return s&&await ca(s),(await Promise.all(n.map(async({creds:r,healthy:i})=>{if(r.mode==="gateway"){if(!i)return F("postToLangfuse","gateway health check failed \u2014 buffering trace"),Oe(e),0;let c=await it(e,r.endpoint,r.authHeader);return (c===0||c>=500)&&(F("postToLangfuse",`gateway send failed (status ${c}) \u2014 buffering trace`),Oe(e)),c}let a=await it(e,r.endpoint,r.authHeader);return (a===0||a>=500)&&(F("postToLangfuse",`direct endpoint unavailable (status ${a}) \u2014 buffering trace`),Oe(e)),a}))).find(r=>r!==0)||0}jn.exports={LF:ra,a:oa,attrs:ia,buildPayload:aa,postToLangfuse:ua};});var ct=l((Ec,Gn)=>{var g="[REDACTED]",la=[{re:/\b(sk-[A-Za-z0-9_\-]{20,})/g,replace:()=>`sk-${g}`},{re:/\b(pk-[A-Za-z0-9_\-]{20,})/g,replace:()=>`pk-${g}`},{re:/\b(Bearer\s+)[A-Za-z0-9\-._~+/]+=*/gi,replace:(e,t)=>`${t}${g}`},{re:/\b(Basic\s+)[A-Za-z0-9+/]+=*/gi,replace:(e,t)=>`${t}${g}`},{re:/(-----BEGIN [A-Z ]+-----)[^-]*(-----END [A-Z ]+-----)/g,replace:(e,t,n)=>`${t}
131
- ${g}
132
- ${n}`},{re:/\b(AKIA[0-9A-Z]{16})\b/g,replace:()=>`AKIA${g}`},{re:/(aws_secret_access_key\s*[=:]\s*)([A-Za-z0-9/+]{40})/gi,replace:(e,t)=>`${t}${g}`},{re:/\b(ghp_[A-Za-z0-9]{36,})/g,replace:()=>`ghp_${g}`},{re:/\b(github_pat_[A-Za-z0-9_]{36,})/gi,replace:()=>`github_pat_${g}`},{re:/\b(eyJ[A-Za-z0-9_\-]+\.eyJ[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+)/g,replace:()=>`eyJ.${g}`},{re:/\b([A-Z0-9_]*(?:SECRET|TOKEN|KEY|PASSWORD|PASSWD|PWD|CREDENTIAL|API)[A-Z0-9_]*\s*=\s*)(['"]?)([^\s'"#\n]+)\2/gi,replace:(e,t,n)=>`${t}${n}${g}${n}`},{re:/([a-z][a-z0-9+\-.]*:\/\/[^:/?#\s]*):([^@\s]+)@/gi,replace:(e,t)=>`${t}:${g}@`}];function da(e){if(e==null)return "";let t=typeof e=="string"?e:JSON.stringify(e);return la.reduce((n,{re:s,replace:o})=>n.replace(s,o),t)}Gn.exports={sanitize:da,REDACTED:g};});var Zn=l((wc,zn)=>{var{generateSpanId:pa,nowNs:fa}=le(),{loadState:ha,saveState:Ta}=de(),{LF:fe,a:M,attrs:Sa}=at(),{truncate:Kn,firstLine:Ea,passthrough:Wn}=J(),{readSkillContent:wa,readSkillArtifacts:_a}=Le(),{dbg:Vn}=v(),{TRACE_LIMITS:Jn}=w(),{sanitize:Xn}=ct();async function ga(e){let t=e.session_id||"unknown",n=e.tool_name||"unknown",s=e.tool_input||{},o=e.tool_response||"",r=ha(t);if(!r){Wn(e);return}let i=fa(),a=r.pendingTool?.name===n,c=a?r.pendingTool.startNs:String(BigInt(i)-200000000n),p=a?r.pendingTool.inputStr:Kn(s,Jn.TOOL_INPUT),h=p;if(n==="Skill"){let $=typeof s=="object"&&s!==null?s.skill||s.name||s.skillName||String(Object.values(s)[0]??""):String(s),C=$?wa($.trim(),r.cwd):null;C&&(h=C,r.skillContent||(r.skillContent=C),r.slashSkill||(r.slashSkill=$.trim()),r.skillArtifacts||(r.skillArtifacts=_a($.trim(),r.cwd))),Vn("PostToolUse","Skill tool detected",`skillName=${$}`,`contentFound=${!!C}`);}let S=Xn(Kn(o,Jn.TOOL_OUTPUT)),f=/\b(error|exception|failed|failure|traceback|errno)\b/i.test(S.slice(0,500)),y=f?"ERROR":"DEFAULT",I=pa(),k=Math.round(Number(BigInt(i)-BigInt(c))/1e6),Ce={Agent:"AGENT",Task:"AGENT"}[n]??"TOOL";r.toolCalls.push({tool:n,brief:Ea(p,60),error:f,durationMs:k}),r.spans.push({traceId:r.traceId,spanId:I,parentSpanId:r.spanId,name:n,kind:3,startTimeUnixNano:c,endTimeUnixNano:i,attributes:Sa(M(fe.OBS_NAME,n),M(fe.OBS_TYPE,Ce),M(fe.OBS_LEVEL,y),M(fe.OBS_INPUT,Xn(h)),M(fe.OBS_OUTPUT,S),M("tool.name",n),M("tool.error",String(f))),status:{code:f?2:1}}),r.pendingTool=null,Ta(t,r),Vn("PostToolUse",`sid=${t}`,`tool=${n}`,`error=${f}`,`durationMs=${k}`,`totalSpans=${r.spans.length}`),Wn(e);}zn.exports={onPostToolUse:ga};});var es=l((_c,Qn)=>{var ut={"claude-opus-4-6":{input:15,output:75},"claude-opus-4-5":{input:15,output:75},"claude-sonnet-4-6":{input:3,output:15},"claude-sonnet-4-5":{input:3,output:15},"claude-haiku-4-5":{input:.8,output:4},"claude-4-6-opus":{input:15,output:75},"claude-4-6-sonnet":{input:3,output:15},"claude-4-5-opus":{input:15,output:75},"claude-4-5-sonnet":{input:3,output:15},"claude-4-5-haiku":{input:.8,output:4},"claude-3-5-sonnet-20241022":{input:3,output:15},"claude-3-5-haiku-20241022":{input:.8,output:4},"claude-3-opus-20240229":{input:15,output:75}};function ya(e,t,n){let s=Object.keys(ut).find(i=>(e||"").toLowerCase().includes(i));if(!s)return;let o=ut[s],r=(t*o.input+n*o.output)/1e6;return Math.round(r*1e6)/1e6}Qn.exports={MODEL_PRICING:ut,calcCostUsd:ya};});var os=l((gc,rs)=>{var{generateSpanId:ts,nowNs:ma}=le(),{loadState:Aa,deleteState:ns}=de(),{LF:E,a:d,attrs:Ie,buildPayload:La,postToLangfuse:Oa}=at(),{getIdentityFromToken:Ia}=x(),{calcCostUsd:Na}=es(),{readLastAssistantOutput:ka}=st(),{truncate:Ne,firstLine:Ca,passthrough:lt}=J(),{dbg:z}=v(),{detectExecutionStatus:va}=Le(),{sanitize:ss}=ct(),{TRACE_LIMITS:ke}=w();async function ba(e){let t=e.session_id||"unknown",n=e.stop_reason||"end_turn",s=Aa(t);if(!s){lt(e);return}s.slashSkill&&!/^[a-z][a-z0-9-]*$/i.test(s.slashSkill)&&(z("Stop",`sid=${t}`,`slashSkill rejected post-disk: "${s.slashSkill}"`),s.slashSkill=null);let o=ma(),r=await Ia();if(s.slashSkill&&!s.toolCalls.some(T=>T.tool==="Skill")){let T=ts(),Z=s.skillContent?s.skillContent:JSON.stringify({skill:s.slashSkill});s.toolCalls.push({tool:"Skill",brief:s.slashSkill,error:false,durationMs:0,synthetic:true}),s.spans.push({traceId:s.traceId,spanId:T,parentSpanId:s.spanId,name:"Skill",kind:3,startTimeUnixNano:s.startNs,endTimeUnixNano:s.startNs,attributes:Ie(d(E.OBS_NAME,"Skill"),d(E.OBS_TYPE,"TOOL"),d(E.OBS_LEVEL,"DEFAULT"),d(E.OBS_INPUT,Z),d(E.OBS_OUTPUT,"loaded via slash command"),d("tool.name","Skill"),d("tool.error","false"),d("skill.name",s.slashSkill),d("skill.invocation","slash-command")),status:{code:1}}),z("Stop",`slashSkill=${s.slashSkill}`,"synthetic span injected");}let i=e.transcript_path||s.transcriptPath||"",a=ka(i),c=s.toolCalls.length,p=s.toolCalls.filter(T=>T.error).length,h=ss(a?.text?Ne(a.text,ke.TRACE_OUTPUT):c===0?"No tools used":s.toolCalls.map((T,Z)=>`${Z+1}. ${T.tool}${T.brief?` \u2192 ${T.brief}`:""}${T.error?" [ERROR]":""}`).join(`
133
- `)),S=a?.inputTokens??0,f=a?.outputTokens??0,y=s.toolCalls.map((T,Z)=>`${Z+1}. ${T.tool}${T.brief?` \u2192 ${T.brief}`:""}${T.error?" [ERROR]":""} (${T.durationMs}ms)`),I=!!(s.slashSkill||s.toolCalls.some(T=>T.tool==="Skill")),k=s.toolCalls.some(T=>T.tool==="Agent");if(!I&&!k){z("Stop",`sid=${t}`,"skipping trace \u2014 no Skill or Agent calls found"),ns(t),lt(e);return}let Te=I?"skill":"agent",Ce=Math.round(Number(BigInt(o)-BigInt(s.startNs))/1e6),$=Na(s.model,S,f),C=va(s);C==="prerequisite_required"&&(s.spans.push({traceId:s.traceId,spanId:ts(),parentSpanId:s.spanId,name:"prerequisite-check",kind:3,startTimeUnixNano:s.startNs,endTimeUnixNano:o,attributes:Ie(d(E.OBS_NAME,"prerequisite-check"),d(E.OBS_TYPE,"EVENT"),d(E.OBS_LEVEL,"WARNING"),d(E.OBS_OUTPUT,h),d("skill.name",s.slashSkill||void 0),d("execution_status","prerequisite_required")),status:{code:1}}),z("Stop",`sid=${t}`,"prerequisite-check span injected",`skill=${s.slashSkill}`));let dt=(()=>{if(!(!I||!s.prompt)){if(s.slashSkill){let T=s.prompt.replace(new RegExp(`^\\/${s.slashSkill}\\s*`,"i"),"").trim();return T?Ne(T,ke.USER_INSTRUCTION):void 0}return Ne(s.prompt,ke.USER_INSTRUCTION)||void 0}})(),as=JSON.stringify({trace_type:Te,...C!==null&&{execution_status:C},...s.slashSkill&&{skill_name:s.slashSkill},...s.skillArtifacts?.length&&{skill_artifacts:s.skillArtifacts},...dt!==void 0&&{user_instruction:dt},latency_ms:Ce,...S&&{tokens_input:S},...f&&{tokens_output:f},cost_usd:$,...s.model&&{model:s.model},toolCount:c,errorCount:p,stopReason:n,sessionId:s.sessionId,tools:y.length?y:void 0}),cs=ss(Ne(s.prompt,ke.TRACE_INPUT)),us=Ie(d(E.TRACE_NAME,s.traceName),d(E.TRACE_INPUT,cs),d(E.TRACE_OUTPUT,h),d(E.TRACE_METADATA,as),d(E.SESSION_ID,s.sessionId),d(E.USER_ID,r.user),d(E.OBS_TYPE,"GENERATION"),d(E.MODEL,s.model),S?d(E.INPUT_TOKENS,S):null,f?d(E.OUTPUT_TOKENS,f):null,d("claude.stop_reason",n),d("claude.tool_count",String(c)),d("claude.error_count",String(p)),d("claude.session_id",s.sessionId),d("flow.trace_type",Te),{key:E.TRACE_TAGS,value:{arrayValue:{values:[{stringValue:Te}]}}}),ls={traceId:s.traceId,spanId:s.spanId,name:s.traceName,kind:1,startTimeUnixNano:s.startNs,endTimeUnixNano:o,attributes:us,status:{code:p>0?2:1}},ds=Ie(d("service.name",process.env.LANGFUSE_PROJECT_NAME||"claude-code"),d("deployment.environment",process.env.LANGFUSE_ENVIRONMENT||"default")),pt=[...s.spans||[],ls];z("Stop",`sid=${t}`,`totalTools=${c}`,`errorTools=${p}`,`spans=${pt.length}`,`inputTokens=${S}`,`outputTokens=${f}`,`traceOutput="${Ca(h,80)}"`);let ps=await Oa(La(ds,pt));z("Stop",`POST status=${ps}`,`traceId=${s.traceId}`),ns(t),lt(e);}rs.exports={onStop:ba};});var is=l(()=>{var{credentialsAvailable:Ua}=x(),{readInput:Ra}=J(),{onUserPromptSubmit:Pa}=Rn(),{onPreToolUse:Fa}=Fn(),{onPostToolUse:$a}=Zn(),{onStop:qa}=os();async function xa(){let e=process.argv[2];if(!await Ua()){let n=[];process.stdin.on("data",s=>n.push(s)),process.stdin.on("end",()=>process.stdout.write(n.join("")));return}let t=await Ra();switch(e){case "UserPromptSubmit":await Pa(t);break;case "PreToolUse":await Fa(t);break;case "PostToolUse":await $a(t);break;case "Stop":await qa(t);break;default:process.stderr.write(`[flow-obs] unknown event: ${e}
134
- `),process.stdout.write(JSON.stringify(t));}}xa().catch(e=>{process.stderr.write(`[flow-obs] fatal: ${e.message}
135
- `),process.exit(0);});});var Ma=new Set(["UserPromptSubmit","PreToolUse","PostToolUse","Stop"]),[,,O,he]=process.argv;if(O==="--version"||O==="-v"){let{version:e}=Se();process.stdout.write(e+`
136
- `),process.exit(0);}else if(O==="--help"||O==="-h"){let{bold:e,cyan:t,dim:n}=B(),{version:s}=Se();process.stdout.write(`
137
- `+e(" flow-ai-obs")+n(" v"+s)+`
138
-
139
- `),process.stdout.write(t(" install")+n(` Auth (if needed) + hooks + native OTEL
140
- `)),process.stdout.write(t(" setup")+n(` Full Flow wizard: auth + hooks + OTEL + LLM proxy + connectivity
141
- `)),process.stdout.write(t(" auth login")+n(` Authenticate with Flow (clientId / clientSecret / tenant)
142
- `)),process.stdout.write(t(" auth logout")+n(` Remove credentials
143
- `)),process.stdout.write(t(" auth status")+n(` Show current auth status
144
- `)),process.stdout.write(t(" check")+n(` Validate full observability setup
145
-
146
- `)),process.stdout.write(n(` Flags: --version, -v Show version
147
- `)),process.stdout.write(n(` --help, -h Show this help
148
-
149
- `)),process.stdout.write(n(` (Hook events: UserPromptSubmit | PreToolUse | PostToolUse | Stop)
150
-
151
- `)),process.exit(0);}else if(O==="install"){Ee().checkForUpdate();let{runInstall:e}=et();e().then(t=>process.exit(t)).catch(t=>{process.stderr.write(`Unexpected error: ${t.message}
152
- `),process.exit(1);});}else if(O==="setup"){Ee().checkForUpdate();let{runSetup:e}=ln(),t=process.argv.slice(3),n=s=>{let o=t.indexOf(s);return o!==-1?t[o+1]:void 0};e({clientId:n("--client-id"),clientSecret:n("--client-secret"),tenant:n("--tenant")}).then(s=>process.exit(s)).catch(s=>{process.stderr.write(`Unexpected error: ${s.message}
153
- `),process.exit(1);});}else if(O==="auth"){Ee().checkForUpdate();let{runLogin:e,runLogout:t,runStatus:n}=ce();(async()=>{let s=0;if(he==="login"||!he){let o=process.argv.slice(4),r=i=>{let a=o.indexOf(i);return a!==-1?o[a+1]:void 0};s=await e({clientId:r("--client-id"),clientSecret:r("--client-secret"),tenant:r("--tenant")});}else if(he==="logout"){let o=process.argv.includes("--force");s=await t(o);}else he==="status"?s=await n():(process.stderr.write(`Unknown auth subcommand: ${he}
131
+ `),l("UserPromptSubmit","auth expired \u2014 warning emitted to stderr"));}catch{}let s=Rr(t.transcript_path)||be(),o=$r(r),i=o?te(o,n):null,a=o?ee(o,n):null;Tt(e,{traceId:be(),spanId:rt(),startNs:W(),sessionId:e,prompt:r,cwd:n,traceName:s,transcriptPath:t.transcript_path||"",model:process.env[f.ANTHROPIC_MODEL]||"",toolCalls:[],spans:[],pendingTool:null,slashSkill:o,skillContent:i,skillArtifacts:a}),l("UserPromptSubmit",`sid=${e}`,`traceName=${s}`,`slashSkill=${o}`),C(t);}var Dr=p(()=>{Ut();Ft();Pe();re();Et();$();T();et();});async function Br(t){let e=t.session_id||"unknown",r=t.tool_name||"unknown",n=t.tool_input||{},s=wt(e);s&&(s.pendingTool={name:r,inputStr:x(n,F.TOOL_INPUT),startNs:W()},Tt(e,s)),l("PreToolUse",`sid=${e}`,`tool=${r}`,`stateFound=${!!s}`),C(t);}var Hr=p(()=>{Ut();Ft();Et();$();T();});function d(t,e){return e==null||e===""?null:{key:t,value:{stringValue:String(e)}}}function nt(...t){return t.filter(e=>e!==null)}function jr(t,e){return {resourceSpans:[{resource:{attributes:t},scopeSpans:[{scope:Bs,spans:Array.isArray(e)?e:[e]}]}]}}var Bs,h,Vr=p(()=>{T();Bs={name:le.SCOPE_NAME,version:le.SCOPE_VERSION},h={TRACE_NAME:"langfuse.trace.name",TRACE_INPUT:"langfuse.trace.input",TRACE_OUTPUT:"langfuse.trace.output",TRACE_METADATA:"langfuse.trace.metadata",TRACE_TAGS:"langfuse.trace.tags",USER_ID:"langfuse.user.id",SESSION_ID:"langfuse.session.id",OBS_NAME:"langfuse.observation.name",OBS_INPUT:"langfuse.observation.input",OBS_OUTPUT:"langfuse.observation.output",OBS_LEVEL:"langfuse.observation.level",OBS_TYPE:"langfuse.observation.type",MODEL:"gen_ai.request.model",INPUT_TOKENS:"gen_ai.usage.input_tokens",OUTPUT_TOKENS:"gen_ai.usage.output_tokens"};});function Gr(t,e,r,n,s){if(process.env[f.FLOW_OBS_DEBUG]!=="1")return;let o=JSON.stringify({ts:new Date().toISOString(),request:{method:"POST",url:t,headers:e,body:JSON.parse(r)},response:{status:n,body:s}});try{w.writeFileSync(Yr,o+`
132
+ `,{flag:"a",encoding:"utf8",mode:384}),l("sendTraces:dump",`request appendada em ${Yr}`);}catch(i){l("sendTraces:dump",`falha ao salvar: ${i.message}`);}}function Ks(t){let e=new URL(t),r=new URL(z.GATEWAY_HEALTH);return r.hostname=e.hostname,r.port=e.port,r.protocol=e.protocol,r}function Kr(t,e){return new Promise((r,n)=>{let s=t._isSSL?kn__namespace.default:Mn__namespace.default;t.headers=Object.assign({},t.headers,{Connection:"close"});let o=s.request(t,i=>{let a=[];i.on("data",c=>a.push(c)),i.on("end",()=>r({statusCode:i.statusCode??0,body:a.join("")}));});o.setTimeout(1e4,()=>{o.destroy(new Error("Request timeout"));}),o.on("error",i=>n(new Error(`Network error: ${i.message}`))),e&&o.write(e),o.end();})}async function Wr(t,e){let r;try{r=Ks(t);}catch{return false}let n=r.protocol==="https:";try{let s={};e&&(s.Authorization=String(e).replace(/[\r\n]/g,""));let o=await Kr({hostname:r.hostname,port:r.port||(n?443:80),path:r.pathname,method:"GET",headers:s,_isSSL:n},null);return l("checkHealth",`url=${r.href} status=${o.statusCode}`),o.statusCode>=200&&o.statusCode<300}catch{return false}}async function ne(t,e,r){let n=JSON.stringify(t),s=new URL(e),o=s.protocol==="https:",i=String(r).replace(/[\r\n]/g,""),a={"Content-Type":"application/json",Authorization:i,"Content-Length":Buffer.byteLength(n)};l("sendTraces:request",`POST ${e}`),l("sendTraces:request",`headers=${JSON.stringify({...a,Authorization:i.slice(0,20)+"\u2026"})}`),l("sendTraces:request",`body=${n.slice(0,500)}${n.length>500?"\u2026":""}`);try{let c=await Kr({hostname:s.hostname,port:s.port||(o?443:80),path:s.pathname,method:"POST",headers:a,_isSSL:o},n);return l("sendTraces:response",`status=${c.statusCode}`),Gr(e,a,n,c.statusCode,c.body),c.statusCode}catch(c){return l("sendTraces:error",c.message),Gr(e,a,n,0,c.message),0}}var Yr,qr=p(()=>{T();$();Yr=pt.join(ue.tmpdir(),"flow-obs-requests.ndjson");});function Ws(){let t=parseInt(process.env[f.BUFFER_TTL_DAYS]??"",10);return (Number.isFinite(t)?Math.max(R.MIN_TTL_DAYS,Math.min(R.MAX_TTL_DAYS,t)):R.DEFAULT_TTL_DAYS)*24*60*60*1e3}function qs(){let t=parseInt(process.env[f.BUFFER_MAX_FILES]??"",10);return Number.isFinite(t)?Math.max(R.MIN_MAX_FILES,Math.min(R.MAX_MAX_FILES,t)):R.DEFAULT_MAX_FILES}function Xr(t){if(/[/\\]/.test(t))throw new Error(`Invalid buffer fileId: ${t}`);return pt__namespace.default.join(ue__namespace.default.tmpdir(),`${R.FILE_PREFIX}${t}.json`)}function Ce(){let t=ue__namespace.default.tmpdir(),e;try{e=w__namespace.default.readdirSync(t);}catch{return []}return e.filter(r=>r.startsWith(R.FILE_PREFIX)&&r.endsWith(".json")).map(r=>{let n=pt__namespace.default.join(t,r),s=0;try{s=w__namespace.default.statSync(n).mtimeMs;}catch{}return {full:n,mtime:s}}).sort((r,n)=>r.mtime-n.mtime).map(r=>r.full)}function $t(t){try{let e=qs(),r=Ce();if(r.length>=e){let o=r.slice(0,r.length-e+1);for(let i of o)try{w__namespace.default.unlinkSync(i);}catch{}}let n=`${Date.now()}-${Math.random().toString(36).slice(2,8)}`,s={fileId:n,bufferedAt:Date.now(),payload:t};return w__namespace.default.writeFileSync(Xr(n),JSON.stringify(s),{encoding:"utf8",mode:384}),l("buffer",`saved fileId=${n}`),n}catch(e){return l("buffer",`saveToBuffer failed: ${e.message}`),null}}function zr(t){let e=Ce(),r=t!=null&&t>0?t:e.length,n=[];for(let s of e){if(n.length>=r)break;try{let o=w__namespace.default.readFileSync(s,"utf8"),i=JSON.parse(o);i&&i.fileId&&i.payload&&n.push(i);}catch{l("buffer",`skipping malformed file: ${s}`);}}return n}function Zr(t){try{w__namespace.default.unlinkSync(Xr(t)),l("buffer",`deleted fileId=${t}`);}catch{}}function Qr(){let t=Date.now()-Ws();for(let e of Ce())try{let{mtimeMs:r}=w__namespace.default.statSync(e);r<t&&(w__namespace.default.unlinkSync(e),l("buffer",`evicted stale: ${pt__namespace.default.basename(e)}`));}catch{}}var tn=p(()=>{T();$();});async function Js(t){Qr();let e=zr(R.REPLAY_BATCH_SIZE);e.length&&(l("replayBufferedTraces",`replaying ${e.length} buffered trace(s)`),await Promise.allSettled(e.map(async r=>{try{let n=await ne(r.payload,t.endpoint,t.authHeader);n>=200&&n<300?(Zr(r.fileId),l("replayBufferedTraces",`replayed fileId=${r.fileId} status=${n}`)):l("replayBufferedTraces",`replay failed fileId=${r.fileId} status=${n}`);}catch(n){l("replayBufferedTraces",`replay error fileId=${r.fileId}: ${n.message}`);}})));}async function en(t){let e=await tt();if(!e.length)return e.authError&&(l("postToLangfuse","auth refresh failed \u2014 buffering trace"),$t(t)),0;let r=await Promise.all(e.map(async o=>{if(o.mode!=="gateway")return {creds:o,healthy:true};let i=await Wr(o.endpoint,o.authHeader);return {creds:o,healthy:i}})),n=r.find(o=>o.creds.mode==="gateway"&&o.healthy)?.creds??r.find(o=>o.creds.mode==="direct")?.creds;return n&&await Js(n),(await Promise.all(r.map(async({creds:o,healthy:i})=>{if(o.mode==="gateway"){if(!i)return l("postToLangfuse","gateway health check failed \u2014 buffering trace"),$t(t),0;let c=await ne(t,o.endpoint,o.authHeader);return (c===0||c>=500)&&(l("postToLangfuse",`gateway send failed (status ${c}) \u2014 buffering trace`),$t(t)),c}let a=await ne(t,o.endpoint,o.authHeader);return (a===0||a>=500)&&(l("postToLangfuse",`direct endpoint unavailable (status ${a}) \u2014 buffering trace`),$t(t)),a}))).find(o=>o!==0)??0}var rn=p(()=>{et();$();qr();tn();T();});var Ue=p(()=>{Vr();rn();});function _t(t){if(t==null)return "";let e=typeof t=="string"?t:JSON.stringify(t);return Xs.reduce((r,{re:n,replace:s})=>r.replace(n,s),e)}var v,Xs,Fe=p(()=>{v="[REDACTED]",Xs=[{re:/\b(sk-[A-Za-z0-9_\-]{20,})/g,replace:()=>`sk-${v}`},{re:/\b(pk-[A-Za-z0-9_\-]{20,})/g,replace:()=>`pk-${v}`},{re:/\b(Bearer\s+)[A-Za-z0-9\-._~+/]+=*/gi,replace:(t,e)=>`${e}${v}`},{re:/\b(Basic\s+)[A-Za-z0-9+/]+=*/gi,replace:(t,e)=>`${e}${v}`},{re:/(-----BEGIN [A-Z ]+-----)[^-]*(-----END [A-Z ]+-----)/g,replace:(t,e,r)=>`${e}
133
+ ${v}
134
+ ${r}`},{re:/\b(AKIA[0-9A-Z]{16})\b/g,replace:()=>`AKIA${v}`},{re:/(aws_secret_access_key\s*[=:]\s*)([A-Za-z0-9/+]{40})/gi,replace:(t,e)=>`${e}${v}`},{re:/\b(ghp_[A-Za-z0-9]{36,})/g,replace:()=>`ghp_${v}`},{re:/\b(github_pat_[A-Za-z0-9_]{36,})/gi,replace:()=>`github_pat_${v}`},{re:/\b(eyJ[A-Za-z0-9_\-]+\.eyJ[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+)/g,replace:()=>`eyJ.${v}`},{re:/\b([A-Z0-9_]*(?:SECRET|TOKEN|KEY|PASSWORD|PASSWD|PWD|CREDENTIAL|API)[A-Z0-9_]*\s*=\s*)(['"]?)([^\s'"#\n]+)\2/gi,replace:(t,e,r)=>`${e}${r}${v}${r}`},{re:/([a-z][a-z0-9+\-.]*:\/\/[^:/?#\s]*):([^@\s]+)@/gi,replace:(t,e)=>`${e}:${v}@`}];});async function nn(t){let e=t.session_id||"unknown",r=t.tool_name||"unknown",n=t.tool_input||{},s=t.tool_response||"",o=wt(e);if(!o){C(t);return}let i=W(),a=o.pendingTool,c=a?.name===r,u=c?a.startNs:String(BigInt(i)-200000000n),S=c?a.inputStr:x(n,F.TOOL_INPUT),A=S,m=null;if(r==="Skill"){let Ot=typeof n=="object"&&n!==null?n.skill||n.name||n.skillName||n.commandName||String(Object.values(n)[0]??""):String(n);m=Ot?String(Ot).trim():null;let ot=m?te(m,o.cwd):null;ot&&(A=ot,o.skillContent||(o.skillContent=ot),o.skillArtifacts||(o.skillArtifacts=ee(m,o.cwd))),m&&!o.slashSkill&&(o.slashSkill=m),l("PostToolUse","Skill tool detected",`skillName=${m}`,`contentFound=${!!ot}`);}let k=_t(x(s,F.TOOL_OUTPUT)),y=/\b(error|exception|failed|failure|traceback|errno)\b/i.test(k.slice(0,500)),O=y?"ERROR":"DEFAULT",Mt=rt(),st=Math.round(Number(BigInt(i)-BigInt(u))/1e6),At={Agent:"AGENT",Task:"AGENT"}[r]??"TOOL",se=r==="Skill"&&m?m:Qt(S,60);o.toolCalls.push({tool:r,brief:se,error:y,durationMs:st});let j=o.spans;j.push({traceId:o.traceId,spanId:Mt,parentSpanId:o.spanId,name:r,kind:3,startTimeUnixNano:u,endTimeUnixNano:i,attributes:nt(d(h.OBS_NAME,r),d(h.OBS_TYPE,At),d(h.OBS_LEVEL,O),d(h.OBS_INPUT,_t(A)),d(h.OBS_OUTPUT,k),d("tool.name",r),d("tool.error",String(y)),r==="Skill"&&m?d("skill.name",m):null,r==="Skill"?d("skill.invocation","slash-command"):null),status:{code:y?2:1}}),o.pendingTool=null,Tt(e,o),l("PostToolUse",`sid=${e}`,`tool=${r}`,`error=${y}`,`durationMs=${st}`,`totalSpans=${j.length}`),C(t);}var sn=p(()=>{Ut();Ft();Ue();Et();re();$();T();Fe();});function an(t,e,r){let n=Object.keys(on).find(i=>(t??"").toLowerCase().includes(i));if(!n)return;let s=on[n],o=(e*s.input+r*s.output)/1e6;return Math.round(o*1e6)/1e6}var on,cn=p(()=>{on={"claude-opus-4-6":{input:15,output:75},"claude-opus-4-5":{input:15,output:75},"claude-sonnet-4-6":{input:3,output:15},"claude-sonnet-4-5":{input:3,output:15},"claude-haiku-4-5":{input:.8,output:4},"claude-4-6-opus":{input:15,output:75},"claude-4-6-sonnet":{input:3,output:15},"claude-4-5-opus":{input:15,output:75},"claude-4-5-sonnet":{input:3,output:15},"claude-4-5-haiku":{input:.8,output:4},"claude-3-5-sonnet-20241022":{input:3,output:15},"claude-3-5-haiku-20241022":{input:.8,output:4},"claude-3-opus-20240229":{input:15,output:75}};});async function ln(t){let e=t.session_id||"unknown",r=t.stop_reason||"end_turn",n=wt(e);if(!n){C(t);return}n.slashSkill&&!/^[a-z][a-z0-9-]*(?::[a-z][a-z0-9-]*)?$/i.test(n.slashSkill)&&(l("Stop",`sid=${e}`,`slashSkill rejected post-disk: "${n.slashSkill}"`),n.slashSkill=null);let s=W(),o=await pr(),i=n.toolCalls,a=n.spans;if(n.slashSkill&&!i.some(g=>g.tool==="Skill")){let g=rt(),J=n.skillContent?n.skillContent:JSON.stringify({skill:n.slashSkill});i.push({tool:"Skill",brief:n.slashSkill,error:false,durationMs:0,synthetic:true}),a.push({traceId:n.traceId,spanId:g,parentSpanId:n.spanId,name:"Skill",kind:3,startTimeUnixNano:n.startNs,endTimeUnixNano:n.startNs,attributes:nt(d(h.OBS_NAME,"Skill"),d(h.OBS_TYPE,"TOOL"),d(h.OBS_LEVEL,"DEFAULT"),d(h.OBS_INPUT,J),d(h.OBS_OUTPUT,"loaded via slash command"),d("tool.name","Skill"),d("tool.error","false"),d("skill.name",n.slashSkill),d("skill.invocation","slash-command")),status:{code:1}}),l("Stop",`slashSkill=${n.slashSkill}`,"synthetic span injected");}let c=t.transcript_path||n.transcriptPath||"",u=Ne(c);if(c&&(i.some(g=>g.tool==="Skill"&&!g.synthetic)||!!n.slashSkill)&&!u?.text){await new Promise(J=>setTimeout(J,500));let g=Ne(c);g?.text&&(u=g);}l("Stop",`transcriptPath=${c||"(empty)"}`,`assistantOut=${u?`text=${u.text.length}chars`:"null"}`);let A=i.length,m=i.filter(g=>g.error).length,k=_t(u?.text?x(u.text,F.TRACE_OUTPUT):A===0?"No tools used":i.map((g,J)=>`${J+1}. ${g.tool}${g.brief?` \u2192 ${g.brief}`:""}${g.error?" [ERROR]":""}`).join(`
135
+ `)),y=u?.inputTokens??0,O=u?.outputTokens??0,Mt=i.map((g,J)=>`${J+1}. ${g.tool}${g.brief?` \u2192 ${g.brief}`:""}${g.error?" [ERROR]":""} (${g.durationMs}ms)`),st=!!(n.slashSkill||i.some(g=>g.tool==="Skill")),$e=i.some(g=>g.tool==="Agent");if(!st&&!$e){l("Stop",`sid=${e}`,"skipping trace \u2014 no Skill or Agent calls found"),ve(e),C(t);return}let At=st?"skill":"agent",se=Math.round(Number(BigInt(s)-BigInt(n.startNs))/1e6),xe=an(n.model,y,O),j=xr(n);j==="prerequisite_required"&&u?.text&&(j="complete"),j==="prerequisite_required"&&(a.push({traceId:n.traceId,spanId:rt(),parentSpanId:n.spanId,name:"prerequisite-check",kind:3,startTimeUnixNano:n.startNs,endTimeUnixNano:s,attributes:nt(d(h.OBS_NAME,"prerequisite-check"),d(h.OBS_TYPE,"EVENT"),d(h.OBS_LEVEL,"WARNING"),d(h.OBS_OUTPUT,k),d("skill.name",n.slashSkill||void 0),d("execution_status","prerequisite_required")),status:{code:1}}),l("Stop",`sid=${e}`,"prerequisite-check span injected",`skill=${n.slashSkill}`));let Ot=(()=>{if(!(!st||!n.prompt)){if(n.slashSkill){let g=n.prompt.replace(new RegExp(`^\\/${n.slashSkill}\\s*`,"i"),"").trim();return g?x(g,F.USER_INSTRUCTION):void 0}return x(n.prompt,F.USER_INSTRUCTION)||void 0}})(),ot=JSON.stringify({trace_type:At,...j!==null&&{execution_status:j},...n.slashSkill?{skill_name:n.slashSkill}:{},...n.skillArtifacts?.length&&{skill_artifacts:n.skillArtifacts},...Ot!==void 0&&{user_instruction:Ot},latency_ms:se,...y&&{tokens_input:y},...O&&{tokens_output:O},cost_usd:xe,...n.model?{model:n.model}:{},toolCount:A,errorCount:m,stopReason:r,sessionId:n.sessionId,tools:Mt.length?Mt:void 0}),Me=_t(x(n.prompt,F.TRACE_INPUT)),pn=nt(d(h.TRACE_NAME,n.traceName),d(h.TRACE_INPUT,Me),d(h.TRACE_OUTPUT,k),d(h.OBS_INPUT,Me),d(h.OBS_OUTPUT,k),d(h.TRACE_METADATA,ot),d(h.SESSION_ID,n.sessionId),d(h.USER_ID,o.user),d(h.OBS_TYPE,"GENERATION"),d(h.MODEL,n.model),y?d(h.INPUT_TOKENS,y):null,O?d(h.OUTPUT_TOKENS,O):null,d("claude.stop_reason",r),d("claude.tool_count",String(A)),d("claude.error_count",String(m)),d("claude.session_id",n.sessionId),d("flow.trace_type",At),{key:h.TRACE_TAGS,value:{arrayValue:{values:[{stringValue:At}]}}}),fn={traceId:n.traceId,spanId:n.spanId,name:n.traceName,kind:1,startTimeUnixNano:n.startNs,endTimeUnixNano:s,attributes:pn,status:{code:m>0?2:1}},mn=nt(d("service.name",process.env.LANGFUSE_PROJECT_NAME||"claude-code"),d("deployment.environment",process.env.LANGFUSE_ENVIRONMENT||"default")),De=[...a,fn];l("Stop",`sid=${e}`,`totalTools=${A}`,`errorTools=${m}`,`spans=${De.length}`,`inputTokens=${y}`,`outputTokens=${O}`,`traceOutput="${Qt(k,80)}"`);let gn=await en(jr(mn,De));l("Stop",`POST status=${gn}`,`traceId=${n.traceId}`),ve(e),C(t);}var un=p(()=>{Ut();Ft();Ue();et();cn();Pe();Et();$();re();Fe();T();});async function zs(){let t=process.argv[2];if(!await fr()){let r=[];process.stdin.on("data",n=>r.push(n)),process.stdin.on("end",()=>process.stdout.write(r.join("")));return}let e=await br();switch(t){case "UserPromptSubmit":await Mr(e);break;case "PreToolUse":await Br(e);break;case "PostToolUse":await nn(e);break;case "Stop":await ln(e);break;default:process.stderr.write(`[flow-obs] unknown event: ${t}
136
+ `),process.stdout.write(JSON.stringify(e));}}var dn=p(()=>{et();Et();Dr();Hr();sn();un();zs().catch(t=>{process.stderr.write(`[flow-obs] fatal: ${t.message}
137
+ `),process.exit(0);});});var Qs=new Set(["UserPromptSubmit","PreToolUse","PostToolUse","Stop"]),[,,M,xt]=process.argv;function kt(t,e){let r=t.indexOf(e);return r!==-1?t[r+1]:void 0}if(M==="--version"||M==="-v"){let{version:t}=Bt();process.stdout.write(t+`
138
+ `),process.exit(0);}else if(M==="--help"||M==="-h"){let{bold:t,cyan:e,dim:r}=(at(),N(ie)),{version:n}=Bt();process.stdout.write(`
139
+ `+t(" flow-ai-obs")+r(" v"+n)+`
140
+
141
+ `),process.stdout.write(e(" install")+r(` Auth (if needed) + hooks + native OTEL
142
+ `)),process.stdout.write(e(" setup")+r(` Full Flow wizard: auth + hooks + OTEL + LLM proxy + connectivity
143
+ `)),process.stdout.write(e(" auth login")+r(` Authenticate with Flow (clientId / clientSecret / tenant)
144
+ `)),process.stdout.write(e(" auth logout")+r(` Remove credentials
145
+ `)),process.stdout.write(e(" auth status")+r(` Show current auth status
146
+ `)),process.stdout.write(e(" check")+r(` Validate full observability setup
147
+
148
+ `)),process.stdout.write(r(` Flags: --version, -v Show version
149
+ `)),process.stdout.write(r(` --help, -h Show this help
150
+
151
+ `)),process.stdout.write(r(` (Hook events: UserPromptSubmit | PreToolUse | PostToolUse | Stop)
152
+
153
+ `)),process.exit(0);}else if(M==="install"){(jt(),N(Ht)).checkForUpdate();let{runInstall:t}=(Oe(),N(wr));t().then(e=>process.exit(e)).catch(e=>{process.stderr.write(`Unexpected error: ${e.message}
154
+ `),process.exit(1);});}else if(M==="setup"){(jt(),N(Ht)).checkForUpdate();let{runSetup:t}=(yr(),N(Tr)),e=process.argv.slice(3);t({clientId:kt(e,"--client-id"),clientSecret:kt(e,"--client-secret"),tenant:kt(e,"--tenant")}).then(r=>process.exit(r)).catch(r=>{process.stderr.write(`Unexpected error: ${r.message}
155
+ `),process.exit(1);});}else if(M==="auth"){(jt(),N(Ht)).checkForUpdate();let{runLogin:t,runLogout:e,runStatus:r}=(Rt(),N(hr));(async()=>{let n=0;if(xt==="login"||!xt){let s=process.argv.slice(4);n=await t({clientId:kt(s,"--client-id"),clientSecret:kt(s,"--client-secret"),tenant:kt(s,"--tenant")});}else if(xt==="logout"){let s=process.argv.includes("--force");n=await e(s);}else xt==="status"?n=await r():(process.stderr.write(`Unknown auth subcommand: ${xt}
154
156
  `),process.stderr.write(`Usage: flow-ai-obs auth [login|logout|status]
155
- `),s=1);process.exit(s);})();}else if(O==="otel-headers"){let{runOtelHeaders:e}=pn();e().then(t=>process.exit(t)).catch(()=>process.exit(1));}else if(O==="check"){let{runCheck:e}=En();e().then(t=>process.exit(t)).catch(t=>{process.stderr.write(`Unexpected error: ${t.message}
156
- `),process.exit(1);});}else if(Ma.has(O))is();else {let{bold:e,cyan:t,dim:n}=B();process.stdout.write(`
157
- `+e(" flow-ai-obs")+`
158
-
159
- `),process.stdout.write(t(" install")+n(` Auth (if needed) + hooks + native OTEL
160
- `)),process.stdout.write(t(" setup")+n(` Full Flow wizard: auth + hooks + OTEL + LLM proxy + connectivity
161
- `)),process.stdout.write(t(" auth login")+n(` Authenticate with Flow (clientId / clientSecret / tenant)
162
- `)),process.stdout.write(t(" auth logout")+n(` Remove credentials
163
- `)),process.stdout.write(t(" auth status")+n(` Show current auth status
164
- `)),process.stdout.write(t(" check")+n(` Validate full observability setup
165
-
166
- `)),process.stdout.write(n(` (Hook events: UserPromptSubmit | PreToolUse | PostToolUse | Stop)
157
+ `),n=1);process.exit(n);})();}else if(M==="otel-headers"){let{runOtelHeaders:t}=(kr(),N(_r));t().then(e=>process.exit(e)).catch(()=>process.exit(1));}else if(M==="check"){let{runCheck:t}=(Lr(),N(Or));t().then(e=>process.exit(e)).catch(e=>{process.stderr.write(`Unexpected error: ${e.message}
158
+ `),process.exit(1);});}else if(Qs.has(M))dn();else {let{bold:t,cyan:e,dim:r}=(at(),N(ie));process.stdout.write(`
159
+ `+t(" flow-ai-obs")+`
160
+
161
+ `),process.stdout.write(e(" install")+r(` Auth (if needed) + hooks + native OTEL
162
+ `)),process.stdout.write(e(" setup")+r(` Full Flow wizard: auth + hooks + OTEL + LLM proxy + connectivity
163
+ `)),process.stdout.write(e(" auth login")+r(` Authenticate with Flow (clientId / clientSecret / tenant)
164
+ `)),process.stdout.write(e(" auth logout")+r(` Remove credentials
165
+ `)),process.stdout.write(e(" auth status")+r(` Show current auth status
166
+ `)),process.stdout.write(e(" check")+r(` Validate full observability setup
167
+
168
+ `)),process.stdout.write(r(` (Hook events: UserPromptSubmit | PreToolUse | PostToolUse | Stop)
167
169
 
168
170
  `)),process.exit(0);}
package/dist/index.js CHANGED
@@ -1,18 +1,20 @@
1
- 'use strict';var u=(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 f=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var h=f((no,Ce)=>{var P=process.env.FLOW_BASE_URL||"https://flow.ciandt.com",Ue={AUTH_ENGINE:process.env.FLOW_AUTH_ENGINE_URL||`${P}/auth-engine-api/v2/api-key/token`,GATEWAY_TRACES:process.env.FLOW_GATEWAY_TRACES_URL||`${P}/flow-langfuse-gateway/v1/traces`,GATEWAY_HEALTH:process.env.FLOW_GATEWAY_HEALTH_URL||`${P}/flow-langfuse-gateway/v1/health`,OTEL_ENDPOINT:process.env.FLOW_OTEL_ENDPOINT_URL||`${P}/otel`},Xt={SERVICE:"flow-plugins-cli",ACCOUNT_CREDS:"credentials",ACCOUNT_TOKEN:"token-cache"},jt="FLOW-nodejs",zt="config.json",Zt={SCOPE_NAME:"flow-ai-obs",SCOPE_VERSION:"0.1.0"},Qt={ANTHROPIC_BASE_URL:process.env.FLOW_LLM_PROXY_URL||`${P}/flow-llm-proxy/`,ANTHROPIC_MODEL:process.env.FLOW_LLM_PROXY_MODEL||"anthropic.claude-4-6-sonnet",ANTHROPIC_SMALL_FAST_MODEL:process.env.FLOW_LLM_PROXY_SMALL_MODEL||"anthropic.claude-4-6-sonnet",CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS:"1"},en={CLAUDE_CODE_ENABLE_TELEMETRY:"1",OTEL_EXPORTER_OTLP_ENDPOINT:Ue.OTEL_ENDPOINT,OTEL_EXPORTER_OTLP_PROTOCOL:"http/json",OTEL_METRICS_EXPORTER:"otlp",OTEL_LOGS_EXPORTER:"otlp",OTEL_LOG_TOOL_DETAILS:"1",OTEL_LOG_USER_PROMPTS:"1"},tn={FLOW_TELEMETRY:"FLOW_TELEMETRY",FLOW_TELEMETRY_GATEWAY:"FLOW_TELEMETRY_GATEWAY_URL",LANGFUSE_BASE_URL:"LANGFUSE_BASE_URL",LANGFUSE_PUBLIC_KEY:"LANGFUSE_PUBLIC_KEY",LANGFUSE_SECRET_KEY:"LANGFUSE_SECRET_KEY",ANTHROPIC_MODEL:"ANTHROPIC_MODEL",ANTHROPIC_AUTH_TOKEN:"ANTHROPIC_AUTH_TOKEN",FLOW_OBS_DEBUG:"FLOW_TELEMETRY_DEBUG",FLOW_OBS_ALLOW_HTTP:"FLOW_TELEMETRY_ALLOW_HTTP",BUFFER_TTL_DAYS:"FLOW_TELEMETRY_BUFFER_TTL_DAYS",BUFFER_MAX_FILES:"FLOW_TELEMETRY_BUFFER_MAX_FILES"},nn={KEYCHAIN_ENABLED:false},rn={LOCK_STALE_MS:3e4,CONNECTIVITY_MAX_RETRY:3,CONNECTIVITY_RETRY_MS:2e3},sn={UserPromptSubmit:5,PreToolUse:3,PostToolUse:10,Stop:15},on={FILE_PREFIX:"flow-obs-buffer-",DEFAULT_TTL_DAYS:4,MIN_TTL_DAYS:1,MAX_TTL_DAYS:30,DEFAULT_MAX_FILES:50,MIN_MAX_FILES:1,MAX_MAX_FILES:500,REPLAY_BATCH_SIZE:10},an="flow-ai-obs-debug.log",cn={TOOL_INPUT:2e4,TOOL_OUTPUT:2e4,TRACE_OUTPUT:2e4,USER_INSTRUCTION:1e4,TRACE_INPUT:5e4,TOOL_BRIEF:60},ln="flow-obs-";Ce.exports={FLOW_BASE_URL:P,FLOW_URLS:Ue,VAULT:Xt,CONFIG_DIR_NAME:jt,CONFIG_FILE_NAME:zt,OTLP:Zt,LLM_PROXY:Qt,NATIVE_OTEL:en,ENV:tn,FEATURES:nn,INSTALLER:rn,HOOK_TIMEOUTS:sn,BUFFER:on,DEBUG_LOG_FILENAME:an,STATE_FILE_PREFIX:ln,TRACE_LIMITS:cn};});var Fe=f((ro,be)=>{var x=u("fs"),b=u("path"),un=u("os"),{CONFIG_DIR_NAME:ne,CONFIG_FILE_NAME:re}=h(),se={credentials:"credentials","token-cache":"tokenCache"};function B(){let e=un.homedir();if(process.platform==="darwin")return b.join(e,"Library","Preferences",ne,re);if(process.platform==="win32"){let n=process.env.APPDATA||b.join(e,"AppData","Roaming");return b.join(n,ne,re)}let t=process.env.XDG_CONFIG_HOME||b.join(e,".config");return b.join(t,ne,re)}function oe(){try{let e=x.readFileSync(B(),"utf8");return JSON.parse(e)}catch{return {}}}function Pe(e){let t=B();x.mkdirSync(b.dirname(t),{recursive:true}),x.writeFileSync(t,JSON.stringify(e,null,2),{encoding:"utf8",mode:384});}var V=class{static isAvailable(){return true}static hasExistingData(){try{if(!x.existsSync(B()))return !1;let t=JSON.parse(x.readFileSync(B(),"utf8"));return !!(t&&t.credentials)}catch{return false}}async getSecret(t,n){let r=oe(),o=se[n]||n,s=r[o];return s?typeof s=="string"?s:JSON.stringify(s):null}async setSecret(t,n,r){let o=oe(),s=se[n]||n;if(n==="token-cache")try{o[s]=JSON.parse(r);}catch{o[s]=r;}else o[s]=r;Pe(o);}async deleteSecret(t,n){let r=oe(),o=se[n]||n;return o in r?(delete r[o],Pe(r),true):false}getStoragePath(){return `config.json (unencrypted) \u2014 ${B()}`}};function dn(){}var fn=V;be.exports={JsonFallbackProvider:V,ScryptFallbackProvider:fn,_resetWarningState:dn};});var $e=f((so,ve)=>{var{execFile:pn}=u("child_process"),{promisify:_n}=u("util"),{accessSync:Sn,constants:En}=u("fs"),ae=_n(pn),ie=class{static async isAvailable(){try{return Sn("/usr/bin/security",En.X_OK),!0}catch{return false}}async getSecret(t,n){try{let{stdout:r}=await ae("security",["find-generic-password","-w","-a",n,"-s",t]);return r.trim()||null}catch{return null}}async setSecret(t,n,r){await ae("security",["add-generic-password","-U","-a",n,"-s",t,"-w",r]);}async deleteSecret(t,n){try{return await ae("security",["delete-generic-password","-a",n,"-s",t]),!0}catch{return false}}getStoragePath(){return "macOS Keychain"}};ve.exports={MacOsKeyVaultProvider:ie};});var De=f((oo,qe)=>{var{execFile:Tn,spawn:hn}=u("child_process"),{promisify:An}=u("util"),{accessSync:gn,constants:On}=u("fs"),Me=An(Tn),ce=class{static async isAvailable(){let t=["/usr/bin/secret-tool","/bin/secret-tool","/usr/local/bin/secret-tool"];for(let n of t)try{return gn(n,On.X_OK),!0}catch{}return false}async getSecret(t,n){try{let{stdout:r}=await Me("secret-tool",["lookup","service",t,"account",n]);return r.trim()||null}catch{return null}}async setSecret(t,n,r){await new Promise((o,s)=>{let a=hn("secret-tool",["store","--label",t,"service",t,"account",n]);a.on("error",s),a.on("close",l=>{l===0?o():s(new Error(`secret-tool exited with code ${l}`));}),a.stdin.write(r),a.stdin.end();});}async deleteSecret(t,n){try{return await Me("secret-tool",["clear","service",t,"account",n]),!0}catch{return false}}getStoragePath(){return "Linux Secret Service (libsecret)"}};qe.exports={LinuxKeyVaultProvider:ce};});var xe=f((ao,Be)=>{var le=class{static async isAvailable(){try{return await u("keytar").getPassword("__flow_probe__","__flow_probe__"),!0}catch{return false}}async getSecret(t,n){return u("keytar").getPassword(t,n)}async setSecret(t,n,r){await u("keytar").setPassword(t,n,r);}async deleteSecret(t,n){return u("keytar").deletePassword(t,n)}getStoragePath(){return "Windows Credential Manager"}};Be.exports={WindowsKeyVaultProvider:le};});var We=f((io,He)=>{async function Ye(){let{JsonFallbackProvider:e}=Fe();return await Ln()??new e}async function Ln(){switch(process.platform){case "darwin":{let{MacOsKeyVaultProvider:e}=$e();return await e.isAvailable()?new e:null}case "linux":{let{LinuxKeyVaultProvider:e}=De();return await e.isAvailable()?new e:null}case "win32":{let{WindowsKeyVaultProvider:e}=xe();return await e.isAvailable()?new e:null}default:return null}}var yn=Ye;He.exports={createSecretVaultProvider:Ye,createKeyVaultProvider:yn};});var Je=f((co,Ke)=>{var{createSecretVaultProvider:mn}=We(),{VAULT:de}=h(),F=de.SERVICE,fe=de.ACCOUNT_CREDS,pe=de.ACCOUNT_TOKEN,ue=null;function v(){return ue||(ue=mn()),ue}async function Ge(){let t=await(await v()).getSecret(F,fe);if(!t)return null;try{return JSON.parse(t)}catch{return null}}async function In(e){if(!e.clientId||!e.clientSecret||!e.tenant)throw new Error("clientId, clientSecret and tenant are required");await(await v()).setSecret(F,fe,JSON.stringify(e));}async function Nn(){let e=await v();await e.deleteSecret(F,fe),await e.deleteSecret(F,pe);}async function wn(e){await(await v()).setSecret(F,pe,JSON.stringify({accessToken:e.accessToken,expiresAt:e.expiresAt}));}async function _e(){let t=await(await v()).getSecret(F,pe);if(!t)return null;try{let n=JSON.parse(t);return {accessToken:n.accessToken,expiresAt:n.expiresAt}}catch{return null}}async function kn(){let e=await _e();return e?new Date(e.expiresAt)>new Date:false}async function Rn(){let e=await _e();if(!e||!e.accessToken)return null;try{let t=e.accessToken.split(".");if(t.length<2)return null;let n=JSON.parse(Buffer.from(t[1].replace(/-/g,"+").replace(/_/g,"/"),"base64").toString("utf8"));return n.email||n.preferred_username||n.upn||n.sub||null}catch{return null}}async function Un(){let e=await v();if(typeof e.getStoragePath=="function")return e.getStoragePath();let t=process.platform;return t==="darwin"?"macOS Keychain":t==="win32"?"Windows Credential Manager":"Linux Secret Service (libsecret)"}async function Cn(){let e=await Ge();return !!(e&&e.clientId&&e.clientSecret&&e.tenant)}Ke.exports={getFlowCredentials:Ge,saveFlowCredentials:In,clearFlowCredentials:Nn,saveTokenCache:wn,getTokenCache:_e,isTokenValid:kn,getEmailFromToken:Rn,getConfigPath:Un,hasCredentials:Cn};});var je=f((lo,Xe)=>{var Pn=u("https"),bn=u("http"),{FLOW_URLS:Fn}=h(),vn=/^[a-z0-9][a-z0-9-]{0,62}[a-z0-9]$|^[a-z0-9]$/;function $n(e){if(!vn.test(e))throw new Error(`Invalid tenant value: "${e}". Tenant must be lowercase alphanumeric and hyphens (1-64 chars).`)}var Ve={INVALID_CLIENT_SECRET:"Invalid Client Secret \u2014 check the value and try again",INVALID_CLIENT_ID:"Invalid Client ID \u2014 check the value and try again",INVALID_TENANT:"Invalid Tenant \u2014 check the value and try again",TENANT_NOT_FOUND:"Tenant not found \u2014 verify the tenant identifier"};function Mn(e,t){try{let n=JSON.parse(t);if(typeof n.error=="string"&&Ve[n.error])return new Error(Ve[n.error])}catch{}return e===401||e===403||e===500?new Error("Invalid credentials"):e>=400&&e<500?new Error("Authentication request was rejected"):new Error("Authentication service unavailable, please try again later")}function qn(e){return new Promise((t,n)=>{try{$n(e.tenant);}catch(p){return n(p)}let r=JSON.stringify({clientSecret:e.clientSecret}),o=new URL(Fn.AUTH_ENGINE),s=o.protocol==="https:",a={hostname:o.hostname,port:o.port||(s?443:80),path:o.pathname+o.search,method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(r),FlowTenant:e.tenant}},c=(s?Pn:bn).request(a,p=>{let T=[];p.on("data",S=>T.push(S)),p.on("end",()=>{let S=T.join("");if(p.statusCode>=400)return n(Mn(p.statusCode,S));let d;try{d=JSON.parse(S);}catch{return n(new Error("Invalid response from auth engine"))}let g=d.expires_at??new Date(Date.now()+(d.expires_in??3600)*1e3).toISOString();t({accessToken:d.access_token,expiresAt:g});});});c.on("error",p=>n(new Error(`Network error: ${p.message}`))),c.write(r),c.end();})}Xe.exports={getToken:qn};});var I=f((uo,Ze)=>{var{writeFileSync:Dn}=u("fs"),{tmpdir:Bn}=u("os"),{join:xn}=u("path"),{DEBUG_LOG_FILENAME:Yn,ENV:Hn}=h(),ze=xn(Bn(),Yn);function Wn(...e){if(process.env[Hn.FLOW_OBS_DEBUG]!=="1")return;let t=`[${new Date().toISOString()}] ${e.join(" ")}
2
- `;try{Dn(ze,t,{flag:"a"});}catch(n){process.stderr.write(`[flow-obs debug ERROR] ${n.message}
3
- `);}}Ze.exports={dbg:Wn,DEBUG_LOG:ze};});var Y=f((fo,et)=>{var{getFlowCredentials:Se,isTokenValid:Gn,getEmailFromToken:X,getTokenCache:Kn,saveTokenCache:Jn}=Je(),{getToken:Vn}=je(),{FLOW_BASE_URL:Xn,ENV:L,FEATURES:Ee}=h(),{dbg:U}=I(),jn=[/^localhost\.?$/i,/^127\./,/^10\./,/^172\.(1[6-9]|2\d|3[01])\./,/^192\.168\./,/^169\.254\./,/^0\.0\.0\.0$/,/^::1$/,/^\[::1\]$/,/^\[::ffff:/i,/^\[f[cd]/i,/^\[fe80:/i,/^metadata\.google\.internal\.?$/i,/^metadata\.azure\.internal\.?$/i,/(?:^|\.)localtest\.me\.?$/i,/(?:^|\.)lvh\.me\.?$/i,/(?:^|\.)vcap\.me\.?$/i];function zn(e){return jn.some(t=>t.test(e))}function Zn(e){if(!e)return null;try{let t=e.split(".");if(t.length<2)return null;let n=JSON.parse(Buffer.from(t[1].replace(/-/g,"+").replace(/_/g,"/"),"base64").toString("utf8"));return n.email||n.preferred_username||n.upn||n.sub||null}catch{return null}}function he(e){if(!e)return null;try{let t=e.split(".");if(t.length<2)return null;let n=JSON.parse(Buffer.from(t[1].replace(/-/g,"+").replace(/_/g,"/"),"base64").toString("utf8")),{clientId:r,clientSecret:o,tenant:s}=n;return !r||!o||!s?null:{clientId:r,clientSecret:o,tenant:s}}catch{return null}}function Qn(e){let t=Buffer.from(JSON.stringify({alg:"none",typ:"JWT"})).toString("base64url"),n=Buffer.from(JSON.stringify({clientId:e.clientId,clientSecret:e.clientSecret,tenant:e.tenant})).toString("base64url");return `${t}.${n}.`}function Te(e){let t;try{t=new URL(e);}catch{throw new Error(`Invalid URL: ${e}`)}let n=process.env[L.FLOW_OBS_ALLOW_HTTP]==="true";if(!n&&t.protocol!=="https:")throw new Error(`URL must use HTTPS: ${e}`);if(t.username||t.password)throw new Error(`URL must not contain embedded credentials: ${e}`);if(!n&&zn(t.hostname))throw new Error(`SSRF: private/loopback host not allowed: ${t.hostname}`);return e}async function er(){let e=he(process.env[L.ANTHROPIC_AUTH_TOKEN]);if(e)return {user:await X().catch(()=>null)||e.clientId,tenant:e.tenant};if(Ee.KEYCHAIN_ENABLED)try{let t=await Se();if(!t)return {user:"",tenant:""};let n=await X()||t.clientId||"",r=t.tenant||"";return {user:n,tenant:r}}catch{return {user:"",tenant:""}}return {user:"",tenant:""}}async function tr(e){if(await Gn())return (await Kn()).accessToken;U("getOrRefreshToken","token expired \u2014 refreshing via auth-engine");let t=await Vn(e);try{await Jn(t);}catch(n){U("getOrRefreshToken",`token cache save failed (non-fatal): ${n.message}`);}return U("getOrRefreshToken",`token refreshed, expires=${t.expiresAt}`),t.accessToken}function nr(e,t){let n=t&&t.accessToken?t.accessToken:"";return {endpoint:e.replace(/\/$/,"")+"/flow-langfuse-gateway/v1/traces",authHeader:`Bearer ${n}`}}function rr(e,t,n){let r=Buffer.from(`${t}:${n}`).toString("base64");return {endpoint:e.replace(/\/$/,"")+"/api/public/otel/v1/traces",authHeader:`Basic ${r}`}}async function Qe(){let e=[],t=process.env[L.ANTHROPIC_MODEL]||"",n=he(process.env[L.ANTHROPIC_AUTH_TOKEN]);U("resolveCredentials",n?"credentials resolved from ANTHROPIC_AUTH_TOKEN":"ANTHROPIC_AUTH_TOKEN absent or invalid"),!n&&Ee.KEYCHAIN_ENABLED&&(n=await Se(),n&&U("resolveCredentials","credentials resolved from keychain (FEATURES.KEYCHAIN_ENABLED=true)"));let r=n?n.tenant:"",o=process.env[L.FLOW_TELEMETRY]==="true",s=process.env[L.LANGFUSE_BASE_URL],a=process.env[L.LANGFUSE_PUBLIC_KEY],l=process.env[L.LANGFUSE_SECRET_KEY];if(o&&s&&a&&l){let d="",g=r;if(n)d=await X().catch(()=>null)||n.clientId;else if(Ee.KEYCHAIN_ENABLED)try{let y=await Se();y&&(d=await X()||y.clientId,g=y.tenant);}catch{}let O={user:d||"",tenant:g||"",team:"",project:"",model:t};e.push({mode:"direct",...rr(Te(s),a,l),...O}),U("resolveCredentials","direct mode active",`user=${O.user}`,`tenant=${O.tenant}`);}if(!n){if(e.length===0){let d=[];return d.authError=false,d}return e}let c=null;try{c=await tr(n);}catch(d){if(U("resolveCredentials",`token refresh failed: ${d.message}`),e.length>0)return e;let g=[];return g.authError=true,g}let T={user:Zn(c)||n.clientId,tenant:r,team:"",project:"",model:t},S=process.env[L.FLOW_TELEMETRY_GATEWAY]||Xn;return e.push({mode:"gateway",...nr(Te(S),{accessToken:c}),...T}),e}async function sr(){return (await Qe()).length>0}et.exports={credentialsAvailable:sr,getIdentityFromToken:er,resolveCredentials:Qe,validateUrl:Te,parseCredsFromAnthropicToken:he,buildAnthropicAuthToken:Qn};});var $=f((po,tt)=>{function or(e,t){let n=typeof e=="object"?JSON.stringify(e):String(e??"");return n.length>t?n.slice(0,t)+" \u2026[truncated]":n}function ar(e,t=100){return String(e??"").split(`
4
- `)[0].slice(0,t).trim()}function ir(){return new Promise(e=>{let t="";process.stdin.setEncoding("utf8"),process.stdin.on("data",n=>t+=n),process.stdin.on("end",()=>{try{e(JSON.parse(t));}catch{e({});}});})}function cr(e){process.stdout.write(JSON.stringify(e));}tt.exports={truncate:or,firstLine:ar,readInput:ir,passthrough:cr};});var H=f((_o,rt)=>{var{randomBytes:nt}=u("crypto"),lr=()=>nt(16).toString("hex"),ur=()=>nt(8).toString("hex");function dr(){return String(BigInt(Date.now())*1000000n)}rt.exports={generateTraceId:lr,generateSpanId:ur,nowNs:dr};});var W=f((Eo,ot)=>{var{readFileSync:fr,writeFileSync:pr,unlinkSync:_r,existsSync:Sr,realpathSync:So}=u("fs"),{tmpdir:st}=u("os"),{join:Er,resolve:Tr,normalize:hr,sep:Ar}=u("path"),gr=/^[0-9a-f-]{1,64}$/i,Or=hr(st())+Ar;function Lr(e,t){let n=Tr(e);if(!n.startsWith(t))throw new Error(`Path traversal detected: ${e}`);return n}function Ae(e){if(!gr.test(e))throw new Error(`Invalid session ID: ${e}`);return Lr(Er(st(),`flow-obs-${e}.json`),Or)}function yr(e){let t=Ae(e);if(!Sr(t))return null;try{return JSON.parse(fr(t,"utf8"))}catch{return null}}function mr(e,t){pr(Ae(e),JSON.stringify(t),{encoding:"utf8",mode:384});}function Ir(e){try{_r(Ae(e));}catch{}}ot.exports={loadState:yr,saveState:mr,deleteState:Ir};});var ge=f((To,ct)=>{var{readFileSync:at,existsSync:it}=u("fs");function Nr(e){if(!e||!it(e))return null;try{let t=at(e,"utf8").trimEnd().split(`
5
- `);for(let n=t.length-1;n>=0;n--)try{let r=JSON.parse(t[n]);if(r.type==="user"&&r.uuid)return r.uuid}catch{}}catch{}return null}function wr(e){if(!e||!it(e))return null;try{let t=at(e,"utf8").trimEnd().split(`
6
- `),n=[],r=0,o=0,s=!1;for(let a=t.length-1;a>=0;a--)try{let l=JSON.parse(t[a]);if(l.type==="user"){if(s)break;continue}if(l.type==="assistant"){s=!0;let p=(l.message?.content??[]).filter(S=>S.type==="text").map(S=>S.text).join("");p&&n.unshift(p);let T=l.message?.usage??{};r+=(T.input_tokens??0)+(T.cache_read_input_tokens??0)+(T.cache_creation_input_tokens??0),o+=T.output_tokens??0;}}catch{}return !n.length&&r===0?null:{text:n.join(`
1
+ 'use strict';var child_process=require('child_process'),util=require('util'),N=require('fs'),$=require('path'),fe=require('os'),We=require('https'),Ge=require('http'),crypto=require('crypto');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var N__default=/*#__PURE__*/_interopDefault(N);var $__default=/*#__PURE__*/_interopDefault($);var fe__default=/*#__PURE__*/_interopDefault(fe);var We__default=/*#__PURE__*/_interopDefault(We);var Ge__default=/*#__PURE__*/_interopDefault(Ge);var Ie=Object.defineProperty;var q=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(e,n)=>(typeof require<"u"?require:e)[n]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')});var ct=(t,e)=>()=>(t&&(e=t(t=0)),e);var lt=(t,e)=>{for(var n in e)Ie(t,n,{get:e[n],enumerable:true});};var Ut={};lt(Ut,{MacOsKeyVaultProvider:()=>mt});var ft,mt,vt=ct(()=>{ft=util.promisify(child_process.execFile),mt=class{static async isAvailable(){try{return N.accessSync("/usr/bin/security",N.constants.X_OK),!0}catch{return false}}async getSecret(e,n){try{let{stdout:r}=await ft("security",["find-generic-password","-w","-a",n,"-s",e]);return r.trim()||null}catch{return null}}async setSecret(e,n,r){await ft("security",["add-generic-password","-U","-a",n,"-s",e,"-w",r]);}async deleteSecret(e,n){try{return await ft("security",["delete-generic-password","-a",n,"-s",e]),!0}catch{return false}}getStoragePath(){return "macOS Keychain"}};});var $t={};lt($t,{LinuxKeyVaultProvider:()=>gt});var Ct,gt,Ft=ct(()=>{Ct=util.promisify(child_process.execFile),gt=class{static async isAvailable(){let e=["/usr/bin/secret-tool","/bin/secret-tool","/usr/local/bin/secret-tool"];for(let n of e)try{return N.accessSync(n,N.constants.X_OK),!0}catch{}return false}async getSecret(e,n){try{let{stdout:r}=await Ct("secret-tool",["lookup","service",e,"account",n]);return r.trim()||null}catch{return null}}async setSecret(e,n,r){await new Promise((o,s)=>{let i=child_process.spawn("secret-tool",["store","--label",e,"service",e,"account",n]);i.on("error",s),i.on("close",u=>{u===0?o():s(new Error(`secret-tool exited with code ${u}`));}),i.stdin.write(r),i.stdin.end();});}async deleteSecret(e,n){try{return await Ct("secret-tool",["clear","service",e,"account",n]),!0}catch{return false}}getStoragePath(){return "Linux Secret Service (libsecret)"}};});var Bt={};lt(Bt,{WindowsKeyVaultProvider:()=>_t});var _t,Dt=ct(()=>{_t=class{static async isAvailable(){try{return await q("keytar").getPassword("__flow_probe__","__flow_probe__"),!0}catch{return false}}async getSecret(e,n){return q("keytar").getPassword(e,n)}async setSecret(e,n,r){await q("keytar").setPassword(e,n,r);}async deleteSecret(e,n){return q("keytar").deletePassword(e,n)}getStoragePath(){return "Windows Credential Manager"}};});var P=process.env.FLOW_BASE_URL||"https://flow.ciandt.com",Y={AUTH_ENGINE:process.env.FLOW_AUTH_ENGINE_URL||`${P}/auth-engine-api/v2/api-key/token`,GATEWAY_TRACES:process.env.FLOW_GATEWAY_TRACES_URL||`${P}/flow-langfuse-gateway/v1/traces`,GATEWAY_HEALTH:process.env.FLOW_GATEWAY_HEALTH_URL||`${P}/flow-langfuse-gateway/v1/health`,OTEL_ENDPOINT:process.env.FLOW_OTEL_ENDPOINT_URL||`${P}/otel`},X={SERVICE:"flow-plugins-cli",ACCOUNT_TOKEN:"token-cache"},z="FLOW-nodejs",Z="config.json",ut={SCOPE_NAME:"flow-ai-obs",SCOPE_VERSION:"0.1.0"};({ANTHROPIC_BASE_URL:process.env.FLOW_LLM_PROXY_URL??`${P}/flow-llm-proxy/`,ANTHROPIC_MODEL:process.env.FLOW_LLM_PROXY_MODEL??"anthropic.claude-4-6-sonnet",ANTHROPIC_SMALL_FAST_MODEL:process.env.FLOW_LLM_PROXY_SMALL_MODEL??"anthropic.claude-4-6-sonnet"});var g={FLOW_TELEMETRY:"FLOW_TELEMETRY",FLOW_TELEMETRY_GATEWAY:"FLOW_TELEMETRY_GATEWAY_URL",LANGFUSE_BASE_URL:"LANGFUSE_BASE_URL",LANGFUSE_PUBLIC_KEY:"LANGFUSE_PUBLIC_KEY",LANGFUSE_SECRET_KEY:"LANGFUSE_SECRET_KEY",ANTHROPIC_MODEL:"ANTHROPIC_MODEL",ANTHROPIC_AUTH_TOKEN:"ANTHROPIC_AUTH_TOKEN",FLOW_OBS_DEBUG:"FLOW_TELEMETRY_DEBUG",FLOW_OBS_ALLOW_HTTP:"FLOW_TELEMETRY_ALLOW_HTTP",BUFFER_TTL_DAYS:"FLOW_TELEMETRY_BUFFER_TTL_DAYS",BUFFER_MAX_FILES:"FLOW_TELEMETRY_BUFFER_MAX_FILES"};var A={FILE_PREFIX:"flow-obs-buffer-",DEFAULT_TTL_DAYS:4,MIN_TTL_DAYS:1,MAX_TTL_DAYS:30,DEFAULT_MAX_FILES:50,MIN_MAX_FILES:1,MAX_MAX_FILES:500,REPLAY_BATCH_SIZE:10},Pt="flow-ai-obs-debug.log",k={TOOL_INPUT:2e4,TOOL_OUTPUT:2e4,TRACE_OUTPUT:2e4,USER_INSTRUCTION:1e4,TRACE_INPUT:5e4};var pt={credentials:"credentials","token-cache":"tokenCache"};function V(){let t=fe__default.default.homedir();if(process.platform==="darwin")return $__default.default.join(t,"Library","Preferences",z,Z);if(process.platform==="win32"){let n=process.env.APPDATA??$__default.default.join(t,"AppData","Roaming");return $__default.default.join(n,z,Z)}let e=process.env.XDG_CONFIG_HOME??$__default.default.join(t,".config");return $__default.default.join(e,z,Z)}function dt(){try{let t=N__default.default.readFileSync(V(),"utf8");return JSON.parse(t)}catch{return {}}}function bt(t){let e=V();N__default.default.mkdirSync($__default.default.dirname(e),{recursive:true}),N__default.default.writeFileSync(e,JSON.stringify(t,null,2),{encoding:"utf8",mode:384});}var tt=class{static isAvailable(){return true}static hasExistingData(){try{if(!N__default.default.existsSync(V()))return !1;let e=JSON.parse(N__default.default.readFileSync(V(),"utf8"));return !!(e&&e.credentials)}catch{return false}}async getSecret(e,n){let r=dt(),o=pt[n]??n,s=r[o];return s?typeof s=="string"?s:JSON.stringify(s):null}async setSecret(e,n,r){let o=dt(),s=pt[n]??n;if(n==="token-cache")try{o[s]=JSON.parse(r);}catch{o[s]=r;}else o[s]=r;bt(o);}async deleteSecret(e,n){let r=dt(),o=pt[n]??n;return o in r?(delete r[o],bt(r),true):false}getStoragePath(){return `config.json (unencrypted) \u2014 ${V()}`}};async function xt(){return await De()??new tt}async function De(){switch(process.platform){case "darwin":{let{MacOsKeyVaultProvider:t}=await Promise.resolve().then(()=>(vt(),Ut));return await t.isAvailable()?new t:null}case "linux":{let{LinuxKeyVaultProvider:t}=await Promise.resolve().then(()=>(Ft(),$t));return await t.isAvailable()?new t:null}case "win32":{let{WindowsKeyVaultProvider:t}=await Promise.resolve().then(()=>(Dt(),Bt));return await t.isAvailable()?new t:null}default:return null}}var Et=X.SERVICE,Mt=X.ACCOUNT_TOKEN,St=null;function Tt(){return St||(St=xt()),St}async function Ht(t){await(await Tt()).setSecret(Et,Mt,JSON.stringify({accessToken:t.accessToken,expiresAt:t.expiresAt}));}async function nt(){let e=await(await Tt()).getSecret(Et,Mt);if(!e)return null;try{let n=JSON.parse(e);return {accessToken:n.accessToken,expiresAt:n.expiresAt}}catch{return null}}async function Yt(){let t=await nt();return t?new Date(t.expiresAt)>new Date:false}async function G(){let t=await nt();if(!t||!t.accessToken)return null;try{let e=t.accessToken.split(".");if(e.length<2)return null;let n=JSON.parse(Buffer.from(e[1].replace(/-/g,"+").replace(/_/g,"/"),"base64").toString("utf8"));return n.email??n.preferred_username??n.upn??n.sub??null}catch{return null}}var Ve=$.join(fe.tmpdir(),Pt);function a(...t){if(process.env[g.FLOW_OBS_DEBUG]!=="1")return;let e=`[${new Date().toISOString()}] ${t.join(" ")}
2
+ `;try{N.writeFileSync(Ve,e,{flag:"a"});}catch(n){process.stderr.write(`[flow-obs debug ERROR] ${n.message}
3
+ `);}}var Ke=/^[a-z0-9][a-z0-9-]{0,62}[a-z0-9]$|^[a-z0-9]$/;function je(t){if(!Ke.test(t))throw new Error(`Invalid tenant value: "${t}". Tenant must be lowercase alphanumeric and hyphens (1-64 chars).`)}var Vt={INVALID_CLIENT_SECRET:"Invalid Client Secret \u2014 check the value and try again",INVALID_CLIENT_ID:"Invalid Client ID \u2014 check the value and try again",INVALID_TENANT:"Invalid Tenant \u2014 check the value and try again",TENANT_NOT_FOUND:"Tenant not found \u2014 verify the tenant identifier"};function Je(t,e){let n=e.length>400?e.slice(0,400)+"\u2026":e;a("toAuthError",`status=${t} body=${n}`);try{let r=JSON.parse(e);if(typeof r.error=="string"&&(a("toAuthError",`api_error_code=${r.error}`+(r.message?` api_message=${r.message}`:"")),Vt[r.error]))return new Error(Vt[r.error])}catch{}return t===401||t===403||t===500?new Error("Invalid credentials"):t>=400&&t<500?new Error("Authentication request was rejected"):new Error("Authentication service unavailable, please try again later")}function Wt(t){return new Promise((e,n)=>{try{je(t.tenant);}catch(p){return n(p)}let r=JSON.stringify({clientSecret:t.clientSecret}),o=new URL(Y.AUTH_ENGINE),s=o.protocol==="https:",i={hostname:o.hostname,port:o.port||(s?443:80),path:o.pathname+o.search,method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(r),FlowTenant:t.tenant}};a("getToken",`requesting token tenant=${t.tenant} host=${i.hostname} path=${i.path}`);let l=(s?We__default.default:Ge__default.default).request(i,p=>{let S=[];p.on("data",T=>S.push(T)),p.on("end",()=>{let T=S.join("");if((p.statusCode??0)>=400)return n(Je(p.statusCode??0,T));let d;try{d=JSON.parse(T);}catch{return n(new Error("Invalid response from auth engine"))}let E=d.expires_at??new Date(Date.now()+(d.expires_in??3600)*1e3).toISOString();e({accessToken:d.access_token??"",expiresAt:E});});});l.on("error",p=>n(new Error(`Network error: ${p.message}`))),l.write(r),l.end();})}var qe=[/^localhost\.?$/i,/^127\./,/^10\./,/^172\.(1[6-9]|2\d|3[01])\./,/^192\.168\./,/^169\.254\./,/^0\.0\.0\.0$/,/^::1$/,/^\[::1\]$/,/^\[::ffff:/i,/^\[f[cd]/i,/^\[fe80:/i,/^metadata\.google\.internal\.?$/i,/^metadata\.azure\.internal\.?$/i,/(?:^|\.)localtest\.me\.?$/i,/(?:^|\.)lvh\.me\.?$/i,/(?:^|\.)vcap\.me\.?$/i];function Xe(t){return qe.some(e=>e.test(t))}function ze(t){if(!t)return null;try{let e=t.split(".");if(e.length<2)return null;let n=JSON.parse(Buffer.from(e[1].replace(/-/g,"+").replace(/_/g,"/"),"base64").toString("utf8"));return n.email||n.preferred_username||n.upn||n.sub||null}catch{return null}}function Kt(t){if(!t)return null;try{let e=t.split(".");if(e.length<2)return null;let n=JSON.parse(Buffer.from(e[1].replace(/-/g,"+").replace(/_/g,"/"),"base64").toString("utf8")),{clientId:r,clientSecret:o,tenant:s}=n;return !r||!o||!s?null:{clientId:r,clientSecret:o,tenant:s}}catch{return null}}function Gt(t){let e;try{e=new URL(t);}catch{throw new Error(`Invalid URL: ${t}`)}let n=process.env[g.FLOW_OBS_ALLOW_HTTP]==="true";if(!n&&e.protocol!=="https:")throw new Error(`URL must use HTTPS: ${t}`);if(e.username||e.password)throw new Error(`URL must not contain embedded credentials: ${t}`);if(!n&&Xe(e.hostname))throw new Error(`SSRF: private/loopback host not allowed: ${e.hostname}`);return t}async function jt(){let t=Kt(process.env[g.ANTHROPIC_AUTH_TOKEN]);if(t)return {user:await G().catch(()=>null)??t.clientId,tenant:t.tenant};return {user:"",tenant:""}}async function Ze(t){if(await Yt()){let n=await nt();return a("getOrRefreshToken",`using cached token, expires=${n.expiresAt}`),n.accessToken}a("getOrRefreshToken",`token expired \u2014 refreshing via auth-engine (tenant=${t.tenant} clientId=${t.clientId})`);let e=await Wt(t);try{await Ht(e);}catch(n){a("getOrRefreshToken",`token cache save failed (non-fatal): ${n.message}`);}return a("getOrRefreshToken",`token refreshed, expires=${e.expiresAt}`),e.accessToken}function Qe(t,e){let n=e&&e.accessToken?e.accessToken:"";return {endpoint:t.replace(/\/$/,"")+"/flow-langfuse-gateway/v1/traces",authHeader:`Bearer ${n}`}}function tn(t,e,n){let r=Buffer.from(`${e}:${n}`).toString("base64");return {endpoint:t.replace(/\/$/,"")+"/api/public/otel/v1/traces",authHeader:`Basic ${r}`}}async function K(){let t=[],e=process.env[g.ANTHROPIC_MODEL]??"",n=Kt(process.env[g.ANTHROPIC_AUTH_TOKEN]);a("resolveCredentials",n?"credentials resolved from ANTHROPIC_AUTH_TOKEN":"ANTHROPIC_AUTH_TOKEN absent or invalid");let r=n?n.tenant:"",o=process.env[g.FLOW_TELEMETRY]==="true",s=process.env[g.LANGFUSE_BASE_URL],i=process.env[g.LANGFUSE_PUBLIC_KEY],u=process.env[g.LANGFUSE_SECRET_KEY];if(o&&s&&i&&u){let d="",E=r;if(n)d=await G().catch(()=>null)??n.clientId;let _={user:d??"",tenant:E??"",team:"",project:"",model:e};t.push({mode:"direct",...tn(Gt(s),i,u),..._}),a("resolveCredentials","direct mode active",`user=${_.user}`,`tenant=${_.tenant}`);}if(!n){if(t.length===0){let d=[];return d.authError=false,d}return t}let l;try{l=await Ze(n);}catch(d){if(a("resolveCredentials",`token refresh failed: ${d.message}`,`(tenant=${n.tenant} clientId=${n.clientId})`),t.length>0)return t;let E=[];return E.authError=true,E}let S={user:ze(l)??n.clientId,tenant:r,team:"",project:"",model:e},T=process.env[g.FLOW_TELEMETRY_GATEWAY]??P;return t.push({mode:"gateway",...Qe(Gt(T),{accessToken:l}),...S}),t}async function Jt(){return (await K()).length>0}function w(t,e){let n=typeof t=="object"?JSON.stringify(t):String(t??"");return n.length>e?n.slice(0,e)+" \u2026[truncated]":n}function rt(t,e=100){return String(t??"").split(`
4
+ `)[0].slice(0,e).trim()}function qt(){return new Promise(t=>{let e="";process.stdin.setEncoding("utf8"),process.stdin.on("data",n=>{e+=n;}),process.stdin.on("end",()=>{try{t(JSON.parse(e));}catch{t({});}});})}function O(t){process.stdout.write(JSON.stringify(t));}var ht=()=>crypto.randomBytes(16).toString("hex"),b=()=>crypto.randomBytes(8).toString("hex");function I(){return String(BigInt(Date.now())*1000000n)}var un=/^[0-9a-f-]{1,64}$/i,pn=$.normalize(fe.tmpdir())+$.sep;function dn(t,e){let n=$.resolve(t);if(!n.startsWith(e))throw new Error(`Path traversal detected: ${t}`);return n}function yt(t){if(!un.test(t))throw new Error(`Invalid session ID: ${t}`);return dn($.join(fe.tmpdir(),`flow-obs-${t}.json`),pn)}function F(t){let e=yt(t);if(!N.existsSync(e))return null;try{return JSON.parse(N.readFileSync(e,"utf8"))}catch{return null}}function B(t,e){N.writeFileSync(yt(t),JSON.stringify(e),{encoding:"utf8",mode:384});}function At(t){try{N.unlinkSync(yt(t));}catch{}}function te(t){if(!t||!N.existsSync(t))return null;try{let e=N.readFileSync(t,"utf8").trimEnd().split(`
5
+ `);for(let n=e.length-1;n>=0;n--)try{let r=JSON.parse(e[n]);if(r.type==="user"&&r.uuid)return r.uuid}catch{}}catch{}return null}function Ot(t){if(!t||!N.existsSync(t))return null;try{let e=N.readFileSync(t,"utf8").trimEnd().split(`
6
+ `),n=[],r=0,o=0;for(let s=e.length-1;s>=0;s--)try{let i=JSON.parse(e[s]);if(i.type==="user")break;if(i.type==="assistant"){let l=(i.message?.content??[]).filter(S=>S.type==="text").map(S=>S.text??"").join("");l&&n.unshift(l);let p=i.message?.usage??{};r+=(p.input_tokens??0)+(p.cache_read_input_tokens??0)+(p.cache_creation_input_tokens??0),o+=p.output_tokens??0;}}catch{}return !n.length&&r===0?null:{text:n.join(`
7
7
 
8
- `),inputTokens:r,outputTokens:o}}catch{}return null}ct.exports={readPromptUuid:Nr,readLastAssistantOutput:wr};});var j=f((ho,ft)=>{var{readFileSync:kr,existsSync:lt,readdirSync:Rr}=u("fs"),{homedir:ut}=u("os"),{join:M,extname:Ur}=u("path"),Cr=new Set([".venv","__pycache__",".git","node_modules"]),Pr=new Set([".pyc",".pyo"]),br=new Set(["SKILL.md",".DS_Store",".gitignore"]);function Fr(e,t){if(!e)return null;let n=[M(ut(),".claude","skills",e,"SKILL.md"),M(t||"",".claude","skills",e,"SKILL.md")];for(let r of n)if(lt(r))try{return kr(r,"utf8")}catch{}return null}function vr(e){return e.match(/^\/([a-z][a-z0-9-]*)(?:\s.*)?$/i)?.[1]||null}var dt=new Set(["Read","Write","Edit","MultiEdit","Bash","Glob","Grep","TodoWrite","WebFetch","WebSearch","Agent","Task"]);function $r(e){return !!e.slashSkill||e.toolCalls.some(r=>r.tool==="Skill")?e.toolCalls.some(r=>dt.has(r.tool))?"complete":"prerequisite_required":null}function Mr(e,t){if(!e)return null;let n=[M(ut(),".claude","skills",e),M(t||"",".claude","skills",e)],r=null;for(let a of n)if(lt(M(a,"SKILL.md"))){r=a;break}if(!r)return null;let o=[];function s(a,l){for(let c of Rr(a,{withFileTypes:true})){if(Cr.has(c.name)||br.has(c.name)||Pr.has(Ur(c.name)))continue;let p=l?`${l}/${c.name}`:c.name;c.isDirectory()?s(M(a,c.name),p):o.push(p);}}return s(r,""),o.length>0?o:null}ft.exports={readSkillContent:Fr,readSkillArtifacts:Mr,detectSlashSkill:vr,EXECUTION_TOOLS:dt,detectExecutionStatus:$r};});var Et=f((Ao,St)=>{var{generateTraceId:pt,generateSpanId:qr,nowNs:Dr}=H(),{saveState:Br}=W(),{readPromptUuid:xr}=ge(),{detectSlashSkill:Yr,readSkillContent:Hr,readSkillArtifacts:Wr}=j(),{passthrough:Gr}=$(),{dbg:_t}=I(),{ENV:Kr}=h(),{resolveCredentials:Jr}=Y();async function Vr(e){let t=e.session_id||"unknown",n=e.prompt||"",r=e.cwd||"";try{(await Jr()).authError===!0&&(process.stderr.write(`
8
+ `),inputTokens:r,outputTokens:o}}catch{}return null}var _n=new Set([".venv","__pycache__",".git","node_modules"]),Sn=new Set([".pyc",".pyo"]),En=new Set(["SKILL.md",".DS_Store",".gitignore"]);function re(t){return t.replace(":","/")}function st(t,e){if(!t)return null;let n=re(t),r=[$.join(fe.homedir(),".claude","skills",n,"SKILL.md"),$.join(e??"",".claude","skills",n,"SKILL.md")];for(let o of r)if(N.existsSync(o))try{return N.readFileSync(o,"utf8")}catch{}return null}function se(t){return t.split(`
9
+ `)[0].match(/^\/([a-z][a-z0-9-]*(?::[a-z][a-z0-9-]*)?)(?:\s.*)?$/i)?.[1]??null}var Tn=new Set(["Read","Write","Edit","MultiEdit","Bash","Glob","Grep","TodoWrite","WebFetch","WebSearch","Agent","Task"]);function oe(t){return !!t.slashSkill||t.toolCalls.some(r=>r.tool==="Skill")?t.toolCalls.some(r=>r.tool==="Skill"&&!r.synthetic||Tn.has(r.tool))?"complete":"prerequisite_required":null}function ot(t,e){if(!t)return null;let n=re(t),r=[$.join(fe.homedir(),".claude","skills",n),$.join(e??"",".claude","skills",n)],o=null;for(let u of r)if(N.existsSync($.join(u,"SKILL.md"))){o=u;break}if(!o)return null;let s=[];function i(u,l){for(let p of N.readdirSync(u,{withFileTypes:true})){if(_n.has(p.name)||En.has(p.name)||Sn.has($.extname(p.name)))continue;let S=l?`${l}/${p.name}`:p.name;p.isDirectory()?i($.join(u,p.name),S):s.push(S);}}return i(o,""),s.length>0?s:null}async function ie(t){let e=t.session_id||"unknown",n=t.prompt||"",r=t.cwd||"";try{(await K()).authError===!0&&(process.stderr.write(`
9
10
  \u26A0 flow-ai-obs: Your Flow credentials have expired.
10
11
  Traces will not be captured until you re-authenticate.
11
12
  Run: flow-ai-obs auth login
12
13
 
13
- `),_t("UserPromptSubmit","auth expired \u2014 warning emitted to stderr"));}catch{}let o=xr(e.transcript_path)||pt(),s=Yr(n),a=s?Hr(s,r):null,l=s?Wr(s,r):null;Br(t,{traceId:pt(),spanId:qr(),startNs:Dr(),sessionId:t,prompt:n,cwd:r,traceName:o,transcriptPath:e.transcript_path||"",model:process.env[Kr.ANTHROPIC_MODEL]||"",toolCalls:[],spans:[],pendingTool:null,slashSkill:s,skillContent:a,skillArtifacts:l}),_t("UserPromptSubmit",`sid=${t}`,`traceName=${o}`,`slashSkill=${s}`),Gr(e);}St.exports={onUserPromptSubmit:Vr};});var ht=f((go,Tt)=>{var{nowNs:Xr}=H(),{loadState:jr,saveState:zr}=W(),{truncate:Zr,passthrough:Qr}=$(),{dbg:es}=I(),{TRACE_LIMITS:ts}=h();async function ns(e){let t=e.session_id||"unknown",n=e.tool_name||"unknown",r=e.tool_input||{},o=jr(t);o&&(o.pendingTool={name:n,inputStr:Zr(r,ts.TOOL_INPUT),startNs:Xr()},zr(t,o)),es("PreToolUse",`sid=${t}`,`tool=${n}`,`stateFound=${!!o}`),Qr(e);}Tt.exports={onPreToolUse:ns};});var gt=f((Oo,At)=>{var{FLOW_URLS:rs}=h();function ss(e){let t=new URL(e),n=new URL(rs.GATEWAY_HEALTH);return n.hostname=t.hostname,n.port=t.port,n.protocol=t.protocol,n}async function os(e,t){let n;try{n=ss(e);}catch{return false}let r={};t&&(r.Authorization=String(t).replace(/[\r\n]/g,""));try{let o=await fetch(n.toString(),{method:"GET",headers:r,signal:AbortSignal.timeout(1e4)});return o.status>=200&&o.status<300}catch{return false}}async function as(e,t,n){let r=String(n).replace(/[\r\n]/g,"");try{return (await fetch(t,{method:"POST",headers:{"Content-Type":"application/json",Authorization:r},body:JSON.stringify(e),signal:AbortSignal.timeout(1e4)})).status}catch{return 0}}At.exports={checkHealth:os,sendTraces:as};});var It=f((Lo,mt)=>{var w=u("fs"),Oe=u("path"),Ot=u("os"),{BUFFER:N,ENV:Lt}=h(),{dbg:G}=I();function is(){let e=parseInt(process.env[Lt.BUFFER_TTL_DAYS],10);return (Number.isFinite(e)?Math.max(N.MIN_TTL_DAYS,Math.min(N.MAX_TTL_DAYS,e)):N.DEFAULT_TTL_DAYS)*24*60*60*1e3}function cs(){let e=parseInt(process.env[Lt.BUFFER_MAX_FILES],10);return Number.isFinite(e)?Math.max(N.MIN_MAX_FILES,Math.min(N.MAX_MAX_FILES,e)):N.DEFAULT_MAX_FILES}function yt(e){if(/[/\\]/.test(e))throw new Error(`Invalid buffer fileId: ${e}`);return Oe.join(Ot.tmpdir(),`${N.FILE_PREFIX}${e}.json`)}function Le(){let e=Ot.tmpdir(),t;try{t=w.readdirSync(e);}catch{return []}return t.filter(n=>n.startsWith(N.FILE_PREFIX)&&n.endsWith(".json")).map(n=>{let r=Oe.join(e,n),o=0;try{o=w.statSync(r).mtimeMs;}catch{}return {full:r,mtime:o}}).sort((n,r)=>n.mtime-r.mtime).map(n=>n.full)}function ls(e){try{let t=cs(),n=Le();if(n.length>=t){let s=n.slice(0,n.length-t+1);for(let a of s)try{w.unlinkSync(a);}catch{}}let r=`${Date.now()}-${Math.random().toString(36).slice(2,8)}`,o={fileId:r,bufferedAt:Date.now(),payload:e};return w.writeFileSync(yt(r),JSON.stringify(o),{encoding:"utf8",mode:384}),G("buffer",`saved fileId=${r}`),r}catch(t){return G("buffer",`saveToBuffer failed: ${t.message}`),null}}function us(e){let t=Le(),n=e!=null&&e>0?e:t.length,r=[];for(let o of t){if(r.length>=n)break;try{let s=w.readFileSync(o,"utf8"),a=JSON.parse(s);a&&a.fileId&&a.payload&&r.push(a);}catch{G("buffer",`skipping malformed file: ${o}`);}}return r}function ds(e){try{w.unlinkSync(yt(e)),G("buffer",`deleted fileId=${e}`);}catch{}}function fs(){let e=Date.now()-is();for(let t of Le())try{let{mtimeMs:n}=w.statSync(t);n<e&&(w.unlinkSync(t),G("buffer",`evicted stale: ${Oe.basename(t)}`));}catch{}}mt.exports={saveToBuffer:ls,loadBuffer:us,deleteBuffer:ds,cleanStaleBuffers:fs};});var me=f((yo,wt)=>{var{resolveCredentials:ps}=Y(),{OTLP:Nt,BUFFER:_s}=h(),{dbg:k}=I(),{checkHealth:Ss,sendTraces:ye}=gt(),{saveToBuffer:z,loadBuffer:Es,deleteBuffer:Ts,cleanStaleBuffers:hs}=It(),As={name:Nt.SCOPE_NAME,version:Nt.SCOPE_VERSION},gs={TRACE_NAME:"langfuse.trace.name",TRACE_INPUT:"langfuse.trace.input",TRACE_OUTPUT:"langfuse.trace.output",TRACE_METADATA:"langfuse.trace.metadata",TRACE_TAGS:"langfuse.trace.tags",USER_ID:"langfuse.user.id",SESSION_ID:"langfuse.session.id",OBS_NAME:"langfuse.observation.name",OBS_INPUT:"langfuse.observation.input",OBS_OUTPUT:"langfuse.observation.output",OBS_LEVEL:"langfuse.observation.level",OBS_TYPE:"langfuse.observation.type",MODEL:"gen_ai.request.model",INPUT_TOKENS:"gen_ai.usage.input_tokens",OUTPUT_TOKENS:"gen_ai.usage.output_tokens"};function Os(e,t){return t==null||t===""?null:{key:e,value:{stringValue:String(t)}}}function Ls(...e){return e.filter(Boolean)}function ys(e,t){return {resourceSpans:[{resource:{attributes:e},scopeSpans:[{scope:As,spans:Array.isArray(t)?t:[t]}]}]}}async function ms(e){hs();let t=Es(_s.REPLAY_BATCH_SIZE);t.length&&(k("replayBufferedTraces",`replaying ${t.length} buffered trace(s)`),await Promise.allSettled(t.map(async n=>{try{let r=await ye(n.payload,e.endpoint,e.authHeader);r>=200&&r<300?(Ts(n.fileId),k("replayBufferedTraces",`replayed fileId=${n.fileId} status=${r}`)):k("replayBufferedTraces",`replay failed fileId=${n.fileId} status=${r}`);}catch(r){k("replayBufferedTraces",`replay error fileId=${n.fileId}: ${r.message}`);}})));}async function Is(e){let t=await ps();if(!t.length)return t.authError&&(k("postToLangfuse","auth refresh failed \u2014 buffering trace"),z(e)),0;let n=await Promise.all(t.map(async s=>{if(s.mode!=="gateway")return {creds:s,healthy:true};let a=await Ss(s.endpoint,s.authHeader);return {creds:s,healthy:a}})),r=n.find(s=>s.creds.mode==="gateway"&&s.healthy)?.creds??n.find(s=>s.creds.mode==="direct")?.creds;return r&&await ms(r),(await Promise.all(n.map(async({creds:s,healthy:a})=>{if(s.mode==="gateway"){if(!a)return k("postToLangfuse","gateway health check failed \u2014 buffering trace"),z(e),0;let c=await ye(e,s.endpoint,s.authHeader);return (c===0||c>=500)&&(k("postToLangfuse",`gateway send failed (status ${c}) \u2014 buffering trace`),z(e)),c}let l=await ye(e,s.endpoint,s.authHeader);return (l===0||l>=500)&&(k("postToLangfuse",`direct endpoint unavailable (status ${l}) \u2014 buffering trace`),z(e)),l}))).find(s=>s!==0)||0}wt.exports={LF:gs,a:Os,attrs:Ls,buildPayload:ys,postToLangfuse:Is};});var Ie=f((mo,kt)=>{var A="[REDACTED]",Ns=[{re:/\b(sk-[A-Za-z0-9_\-]{20,})/g,replace:()=>`sk-${A}`},{re:/\b(pk-[A-Za-z0-9_\-]{20,})/g,replace:()=>`pk-${A}`},{re:/\b(Bearer\s+)[A-Za-z0-9\-._~+/]+=*/gi,replace:(e,t)=>`${t}${A}`},{re:/\b(Basic\s+)[A-Za-z0-9+/]+=*/gi,replace:(e,t)=>`${t}${A}`},{re:/(-----BEGIN [A-Z ]+-----)[^-]*(-----END [A-Z ]+-----)/g,replace:(e,t,n)=>`${t}
14
- ${A}
15
- ${n}`},{re:/\b(AKIA[0-9A-Z]{16})\b/g,replace:()=>`AKIA${A}`},{re:/(aws_secret_access_key\s*[=:]\s*)([A-Za-z0-9/+]{40})/gi,replace:(e,t)=>`${t}${A}`},{re:/\b(ghp_[A-Za-z0-9]{36,})/g,replace:()=>`ghp_${A}`},{re:/\b(github_pat_[A-Za-z0-9_]{36,})/gi,replace:()=>`github_pat_${A}`},{re:/\b(eyJ[A-Za-z0-9_\-]+\.eyJ[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+)/g,replace:()=>`eyJ.${A}`},{re:/\b([A-Z0-9_]*(?:SECRET|TOKEN|KEY|PASSWORD|PASSWD|PWD|CREDENTIAL|API)[A-Z0-9_]*\s*=\s*)(['"]?)([^\s'"#\n]+)\2/gi,replace:(e,t,n)=>`${t}${n}${A}${n}`},{re:/([a-z][a-z0-9+\-.]*:\/\/[^:/?#\s]*):([^@\s]+)@/gi,replace:(e,t)=>`${t}:${A}@`}];function ws(e){if(e==null)return "";let t=typeof e=="string"?e:JSON.stringify(e);return Ns.reduce((n,{re:r,replace:o})=>n.replace(r,o),t)}kt.exports={sanitize:ws,REDACTED:A};});var vt=f((Io,Ft)=>{var{generateSpanId:ks,nowNs:Rs}=H(),{loadState:Us,saveState:Cs}=W(),{LF:K,a:C,attrs:Ps}=me(),{truncate:Rt,firstLine:bs,passthrough:Ut}=$(),{readSkillContent:Fs,readSkillArtifacts:vs}=j(),{dbg:Ct}=I(),{TRACE_LIMITS:Pt}=h(),{sanitize:bt}=Ie();async function $s(e){let t=e.session_id||"unknown",n=e.tool_name||"unknown",r=e.tool_input||{},o=e.tool_response||"",s=Us(t);if(!s){Ut(e);return}let a=Rs(),l=s.pendingTool?.name===n,c=l?s.pendingTool.startNs:String(BigInt(a)-200000000n),p=l?s.pendingTool.inputStr:Rt(r,Pt.TOOL_INPUT),T=p;if(n==="Skill"){let R=typeof r=="object"&&r!==null?r.skill||r.name||r.skillName||String(Object.values(r)[0]??""):String(r),m=R?Fs(R.trim(),s.cwd):null;m&&(T=m,s.skillContent||(s.skillContent=m),s.slashSkill||(s.slashSkill=R.trim()),s.skillArtifacts||(s.skillArtifacts=vs(R.trim(),s.cwd))),Ct("PostToolUse","Skill tool detected",`skillName=${R}`,`contentFound=${!!m}`);}let S=bt(Rt(o,Pt.TOOL_OUTPUT)),d=/\b(error|exception|failed|failure|traceback|errno)\b/i.test(S.slice(0,500)),g=d?"ERROR":"DEFAULT",O=ks(),y=Math.round(Number(BigInt(a)-BigInt(c))/1e6),te={Agent:"AGENT",Task:"AGENT"}[n]??"TOOL";s.toolCalls.push({tool:n,brief:bs(p,60),error:d,durationMs:y}),s.spans.push({traceId:s.traceId,spanId:O,parentSpanId:s.spanId,name:n,kind:3,startTimeUnixNano:c,endTimeUnixNano:a,attributes:Ps(C(K.OBS_NAME,n),C(K.OBS_TYPE,te),C(K.OBS_LEVEL,g),C(K.OBS_INPUT,bt(T)),C(K.OBS_OUTPUT,S),C("tool.name",n),C("tool.error",String(d))),status:{code:d?2:1}}),s.pendingTool=null,Cs(t,s),Ct("PostToolUse",`sid=${t}`,`tool=${n}`,`error=${d}`,`durationMs=${y}`,`totalSpans=${s.spans.length}`),Ut(e);}Ft.exports={onPostToolUse:$s};});var Mt=f((No,$t)=>{var Ne={"claude-opus-4-6":{input:15,output:75},"claude-opus-4-5":{input:15,output:75},"claude-sonnet-4-6":{input:3,output:15},"claude-sonnet-4-5":{input:3,output:15},"claude-haiku-4-5":{input:.8,output:4},"claude-4-6-opus":{input:15,output:75},"claude-4-6-sonnet":{input:3,output:15},"claude-4-5-opus":{input:15,output:75},"claude-4-5-sonnet":{input:3,output:15},"claude-4-5-haiku":{input:.8,output:4},"claude-3-5-sonnet-20241022":{input:3,output:15},"claude-3-5-haiku-20241022":{input:.8,output:4},"claude-3-opus-20240229":{input:15,output:75}};function Ms(e,t,n){let r=Object.keys(Ne).find(a=>(e||"").toLowerCase().includes(a));if(!r)return;let o=Ne[r],s=(t*o.input+n*o.output)/1e6;return Math.round(s*1e6)/1e6}$t.exports={MODEL_PRICING:Ne,calcCostUsd:Ms};});var Yt=f((wo,xt)=>{var{generateSpanId:qt,nowNs:qs}=H(),{loadState:Ds,deleteState:Dt}=W(),{LF:E,a:i,attrs:Z,buildPayload:Bs,postToLangfuse:xs}=me(),{getIdentityFromToken:Ys}=Y(),{calcCostUsd:Hs}=Mt(),{readLastAssistantOutput:Ws}=ge(),{truncate:Q,firstLine:Gs,passthrough:we}=$(),{dbg:q}=I(),{detectExecutionStatus:Ks}=j(),{sanitize:Bt}=Ie(),{TRACE_LIMITS:ee}=h();async function Js(e){let t=e.session_id||"unknown",n=e.stop_reason||"end_turn",r=Ds(t);if(!r){we(e);return}r.slashSkill&&!/^[a-z][a-z0-9-]*$/i.test(r.slashSkill)&&(q("Stop",`sid=${t}`,`slashSkill rejected post-disk: "${r.slashSkill}"`),r.slashSkill=null);let o=qs(),s=await Ys();if(r.slashSkill&&!r.toolCalls.some(_=>_.tool==="Skill")){let _=qt(),D=r.skillContent?r.skillContent:JSON.stringify({skill:r.slashSkill});r.toolCalls.push({tool:"Skill",brief:r.slashSkill,error:false,durationMs:0,synthetic:true}),r.spans.push({traceId:r.traceId,spanId:_,parentSpanId:r.spanId,name:"Skill",kind:3,startTimeUnixNano:r.startNs,endTimeUnixNano:r.startNs,attributes:Z(i(E.OBS_NAME,"Skill"),i(E.OBS_TYPE,"TOOL"),i(E.OBS_LEVEL,"DEFAULT"),i(E.OBS_INPUT,D),i(E.OBS_OUTPUT,"loaded via slash command"),i("tool.name","Skill"),i("tool.error","false"),i("skill.name",r.slashSkill),i("skill.invocation","slash-command")),status:{code:1}}),q("Stop",`slashSkill=${r.slashSkill}`,"synthetic span injected");}let a=e.transcript_path||r.transcriptPath||"",l=Ws(a),c=r.toolCalls.length,p=r.toolCalls.filter(_=>_.error).length,T=Bt(l?.text?Q(l.text,ee.TRACE_OUTPUT):c===0?"No tools used":r.toolCalls.map((_,D)=>`${D+1}. ${_.tool}${_.brief?` \u2192 ${_.brief}`:""}${_.error?" [ERROR]":""}`).join(`
16
- `)),S=l?.inputTokens??0,d=l?.outputTokens??0,g=r.toolCalls.map((_,D)=>`${D+1}. ${_.tool}${_.brief?` \u2192 ${_.brief}`:""}${_.error?" [ERROR]":""} (${_.durationMs}ms)`),O=!!(r.slashSkill||r.toolCalls.some(_=>_.tool==="Skill")),y=r.toolCalls.some(_=>_.tool==="Agent");if(!O&&!y){q("Stop",`sid=${t}`,"skipping trace \u2014 no Skill or Agent calls found"),Dt(t),we(e);return}let J=O?"skill":"agent",te=Math.round(Number(BigInt(o)-BigInt(r.startNs))/1e6),R=Hs(r.model,S,d),m=Ks(r);m==="prerequisite_required"&&(r.spans.push({traceId:r.traceId,spanId:qt(),parentSpanId:r.spanId,name:"prerequisite-check",kind:3,startTimeUnixNano:r.startNs,endTimeUnixNano:o,attributes:Z(i(E.OBS_NAME,"prerequisite-check"),i(E.OBS_TYPE,"EVENT"),i(E.OBS_LEVEL,"WARNING"),i(E.OBS_OUTPUT,T),i("skill.name",r.slashSkill||void 0),i("execution_status","prerequisite_required")),status:{code:1}}),q("Stop",`sid=${t}`,"prerequisite-check span injected",`skill=${r.slashSkill}`));let ke=(()=>{if(!(!O||!r.prompt)){if(r.slashSkill){let _=r.prompt.replace(new RegExp(`^\\/${r.slashSkill}\\s*`,"i"),"").trim();return _?Q(_,ee.USER_INSTRUCTION):void 0}return Q(r.prompt,ee.USER_INSTRUCTION)||void 0}})(),Ht=JSON.stringify({trace_type:J,...m!==null&&{execution_status:m},...r.slashSkill&&{skill_name:r.slashSkill},...r.skillArtifacts?.length&&{skill_artifacts:r.skillArtifacts},...ke!==void 0&&{user_instruction:ke},latency_ms:te,...S&&{tokens_input:S},...d&&{tokens_output:d},cost_usd:R,...r.model&&{model:r.model},toolCount:c,errorCount:p,stopReason:n,sessionId:r.sessionId,tools:g.length?g:void 0}),Wt=Bt(Q(r.prompt,ee.TRACE_INPUT)),Gt=Z(i(E.TRACE_NAME,r.traceName),i(E.TRACE_INPUT,Wt),i(E.TRACE_OUTPUT,T),i(E.TRACE_METADATA,Ht),i(E.SESSION_ID,r.sessionId),i(E.USER_ID,s.user),i(E.OBS_TYPE,"GENERATION"),i(E.MODEL,r.model),S?i(E.INPUT_TOKENS,S):null,d?i(E.OUTPUT_TOKENS,d):null,i("claude.stop_reason",n),i("claude.tool_count",String(c)),i("claude.error_count",String(p)),i("claude.session_id",r.sessionId),i("flow.trace_type",J),{key:E.TRACE_TAGS,value:{arrayValue:{values:[{stringValue:J}]}}}),Kt={traceId:r.traceId,spanId:r.spanId,name:r.traceName,kind:1,startTimeUnixNano:r.startNs,endTimeUnixNano:o,attributes:Gt,status:{code:p>0?2:1}},Jt=Z(i("service.name",process.env.LANGFUSE_PROJECT_NAME||"claude-code"),i("deployment.environment",process.env.LANGFUSE_ENVIRONMENT||"default")),Re=[...r.spans||[],Kt];q("Stop",`sid=${t}`,`totalTools=${c}`,`errorTools=${p}`,`spans=${Re.length}`,`inputTokens=${S}`,`outputTokens=${d}`,`traceOutput="${Gs(T,80)}"`);let Vt=await xs(Bs(Jt,Re));q("Stop",`POST status=${Vt}`,`traceId=${r.traceId}`),Dt(t),we(e);}xt.exports={onStop:Js};});var{credentialsAvailable:Vs}=Y(),{readInput:Xs}=$(),{onUserPromptSubmit:js}=Et(),{onPreToolUse:zs}=ht(),{onPostToolUse:Zs}=vt(),{onStop:Qs}=Yt();async function eo(){let e=process.argv[2];if(!await Vs()){let n=[];process.stdin.on("data",r=>n.push(r)),process.stdin.on("end",()=>process.stdout.write(n.join("")));return}let t=await Xs();switch(e){case "UserPromptSubmit":await js(t);break;case "PreToolUse":await zs(t);break;case "PostToolUse":await Zs(t);break;case "Stop":await Qs(t);break;default:process.stderr.write(`[flow-obs] unknown event: ${e}
17
- `),process.stdout.write(JSON.stringify(t));}}eo().catch(e=>{process.stderr.write(`[flow-obs] fatal: ${e.message}
14
+ `),a("UserPromptSubmit","auth expired \u2014 warning emitted to stderr"));}catch{}let o=te(t.transcript_path)||ht(),s=se(n),i=s?st(s,r):null,u=s?ot(s,r):null;B(e,{traceId:ht(),spanId:b(),startNs:I(),sessionId:e,prompt:n,cwd:r,traceName:o,transcriptPath:t.transcript_path||"",model:process.env[g.ANTHROPIC_MODEL]||"",toolCalls:[],spans:[],pendingTool:null,slashSkill:s,skillContent:i,skillArtifacts:u}),a("UserPromptSubmit",`sid=${e}`,`traceName=${o}`,`slashSkill=${s}`),O(t);}async function ae(t){let e=t.session_id||"unknown",n=t.tool_name||"unknown",r=t.tool_input||{},o=F(e);o&&(o.pendingTool={name:n,inputStr:w(r,k.TOOL_INPUT),startNs:I()},B(e,o)),a("PreToolUse",`sid=${e}`,`tool=${n}`,`stateFound=${!!o}`),O(t);}var hn={name:ut.SCOPE_NAME,version:ut.SCOPE_VERSION},m={TRACE_NAME:"langfuse.trace.name",TRACE_INPUT:"langfuse.trace.input",TRACE_OUTPUT:"langfuse.trace.output",TRACE_METADATA:"langfuse.trace.metadata",TRACE_TAGS:"langfuse.trace.tags",USER_ID:"langfuse.user.id",SESSION_ID:"langfuse.session.id",OBS_NAME:"langfuse.observation.name",OBS_INPUT:"langfuse.observation.input",OBS_OUTPUT:"langfuse.observation.output",OBS_LEVEL:"langfuse.observation.level",OBS_TYPE:"langfuse.observation.type",MODEL:"gen_ai.request.model",INPUT_TOKENS:"gen_ai.usage.input_tokens",OUTPUT_TOKENS:"gen_ai.usage.output_tokens"};function c(t,e){return e==null||e===""?null:{key:t,value:{stringValue:String(e)}}}function U(...t){return t.filter(e=>e!==null)}function ce(t,e){return {resourceSpans:[{resource:{attributes:t},scopeSpans:[{scope:hn,spans:Array.isArray(e)?e:[e]}]}]}}var le=$.join(fe.tmpdir(),"flow-obs-requests.ndjson");function ue(t,e,n,r,o){if(process.env[g.FLOW_OBS_DEBUG]!=="1")return;let s=JSON.stringify({ts:new Date().toISOString(),request:{method:"POST",url:t,headers:e,body:JSON.parse(n)},response:{status:r,body:o}});try{N.writeFileSync(le,s+`
15
+ `,{flag:"a",encoding:"utf8",mode:384}),a("sendTraces:dump",`request appendada em ${le}`);}catch(i){a("sendTraces:dump",`falha ao salvar: ${i.message}`);}}function Ln(t){let e=new URL(t),n=new URL(Y.GATEWAY_HEALTH);return n.hostname=e.hostname,n.port=e.port,n.protocol=e.protocol,n}function pe(t,e){return new Promise((n,r)=>{let o=t._isSSL?We__default.default:Ge__default.default;t.headers=Object.assign({},t.headers,{Connection:"close"});let s=o.request(t,i=>{let u=[];i.on("data",l=>u.push(l)),i.on("end",()=>n({statusCode:i.statusCode??0,body:u.join("")}));});s.setTimeout(1e4,()=>{s.destroy(new Error("Request timeout"));}),s.on("error",i=>r(new Error(`Network error: ${i.message}`))),e&&s.write(e),s.end();})}async function de(t,e){let n;try{n=Ln(t);}catch{return false}let r=n.protocol==="https:";try{let o={};e&&(o.Authorization=String(e).replace(/[\r\n]/g,""));let s=await pe({hostname:n.hostname,port:n.port||(r?443:80),path:n.pathname,method:"GET",headers:o,_isSSL:r},null);return a("checkHealth",`url=${n.href} status=${s.statusCode}`),s.statusCode>=200&&s.statusCode<300}catch{return false}}async function it(t,e,n){let r=JSON.stringify(t),o=new URL(e),s=o.protocol==="https:",i=String(n).replace(/[\r\n]/g,""),u={"Content-Type":"application/json",Authorization:i,"Content-Length":Buffer.byteLength(r)};a("sendTraces:request",`POST ${e}`),a("sendTraces:request",`headers=${JSON.stringify({...u,Authorization:i.slice(0,20)+"\u2026"})}`),a("sendTraces:request",`body=${r.slice(0,500)}${r.length>500?"\u2026":""}`);try{let l=await pe({hostname:o.hostname,port:o.port||(s?443:80),path:o.pathname,method:"POST",headers:u,_isSSL:s},r);return a("sendTraces:response",`status=${l.statusCode}`),ue(e,u,r,l.statusCode,l.body),l.statusCode}catch(l){return a("sendTraces:error",l.message),ue(e,u,r,0,l.message),0}}function In(){let t=parseInt(process.env[g.BUFFER_TTL_DAYS]??"",10);return (Number.isFinite(t)?Math.max(A.MIN_TTL_DAYS,Math.min(A.MAX_TTL_DAYS,t)):A.DEFAULT_TTL_DAYS)*24*60*60*1e3}function Nn(){let t=parseInt(process.env[g.BUFFER_MAX_FILES]??"",10);return Number.isFinite(t)?Math.max(A.MIN_MAX_FILES,Math.min(A.MAX_MAX_FILES,t)):A.DEFAULT_MAX_FILES}function me(t){if(/[/\\]/.test(t))throw new Error(`Invalid buffer fileId: ${t}`);return $__default.default.join(fe__default.default.tmpdir(),`${A.FILE_PREFIX}${t}.json`)}function wt(){let t=fe__default.default.tmpdir(),e;try{e=N__default.default.readdirSync(t);}catch{return []}return e.filter(n=>n.startsWith(A.FILE_PREFIX)&&n.endsWith(".json")).map(n=>{let r=$__default.default.join(t,n),o=0;try{o=N__default.default.statSync(r).mtimeMs;}catch{}return {full:r,mtime:o}}).sort((n,r)=>n.mtime-r.mtime).map(n=>n.full)}function j(t){try{let e=Nn(),n=wt();if(n.length>=e){let s=n.slice(0,n.length-e+1);for(let i of s)try{N__default.default.unlinkSync(i);}catch{}}let r=`${Date.now()}-${Math.random().toString(36).slice(2,8)}`,o={fileId:r,bufferedAt:Date.now(),payload:t};return N__default.default.writeFileSync(me(r),JSON.stringify(o),{encoding:"utf8",mode:384}),a("buffer",`saved fileId=${r}`),r}catch(e){return a("buffer",`saveToBuffer failed: ${e.message}`),null}}function ge(t){let e=wt(),n=t,r=[];for(let o of e){if(r.length>=n)break;try{let s=N__default.default.readFileSync(o,"utf8"),i=JSON.parse(s);i&&i.fileId&&i.payload&&r.push(i);}catch{a("buffer",`skipping malformed file: ${o}`);}}return r}function _e(t){try{N__default.default.unlinkSync(me(t)),a("buffer",`deleted fileId=${t}`);}catch{}}function Se(){let t=Date.now()-In();for(let e of wt())try{let{mtimeMs:n}=N__default.default.statSync(e);n<t&&(N__default.default.unlinkSync(e),a("buffer",`evicted stale: ${$__default.default.basename(e)}`));}catch{}}async function Rn(t){Se();let e=ge(A.REPLAY_BATCH_SIZE);e.length&&(a("replayBufferedTraces",`replaying ${e.length} buffered trace(s)`),await Promise.allSettled(e.map(async n=>{try{let r=await it(n.payload,t.endpoint,t.authHeader);r>=200&&r<300?(_e(n.fileId),a("replayBufferedTraces",`replayed fileId=${n.fileId} status=${r}`)):a("replayBufferedTraces",`replay failed fileId=${n.fileId} status=${r}`);}catch(r){a("replayBufferedTraces",`replay error fileId=${n.fileId}: ${r.message}`);}})));}async function Ee(t){let e=await K();if(!e.length)return e.authError&&(a("postToLangfuse","auth refresh failed \u2014 buffering trace"),j(t)),0;let n=await Promise.all(e.map(async s=>{if(s.mode!=="gateway")return {creds:s,healthy:true};let i=await de(s.endpoint,s.authHeader);return {creds:s,healthy:i}})),r=n.find(s=>s.creds.mode==="gateway"&&s.healthy)?.creds??n.find(s=>s.creds.mode==="direct")?.creds;return r&&await Rn(r),(await Promise.all(n.map(async({creds:s,healthy:i})=>{if(s.mode==="gateway"){if(!i)return a("postToLangfuse","gateway health check failed \u2014 buffering trace"),j(t),0;let l=await it(t,s.endpoint,s.authHeader);return (l===0||l>=500)&&(a("postToLangfuse",`gateway send failed (status ${l}) \u2014 buffering trace`),j(t)),l}let u=await it(t,s.endpoint,s.authHeader);return (u===0||u>=500)&&(a("postToLangfuse",`direct endpoint unavailable (status ${u}) \u2014 buffering trace`),j(t)),u}))).find(s=>s!==0)??0}var y="[REDACTED]",Pn=[{re:/\b(sk-[A-Za-z0-9_\-]{20,})/g,replace:()=>`sk-${y}`},{re:/\b(pk-[A-Za-z0-9_\-]{20,})/g,replace:()=>`pk-${y}`},{re:/\b(Bearer\s+)[A-Za-z0-9\-._~+/]+=*/gi,replace:(t,e)=>`${e}${y}`},{re:/\b(Basic\s+)[A-Za-z0-9+/]+=*/gi,replace:(t,e)=>`${e}${y}`},{re:/(-----BEGIN [A-Z ]+-----)[^-]*(-----END [A-Z ]+-----)/g,replace:(t,e,n)=>`${e}
16
+ ${y}
17
+ ${n}`},{re:/\b(AKIA[0-9A-Z]{16})\b/g,replace:()=>`AKIA${y}`},{re:/(aws_secret_access_key\s*[=:]\s*)([A-Za-z0-9/+]{40})/gi,replace:(t,e)=>`${e}${y}`},{re:/\b(ghp_[A-Za-z0-9]{36,})/g,replace:()=>`ghp_${y}`},{re:/\b(github_pat_[A-Za-z0-9_]{36,})/gi,replace:()=>`github_pat_${y}`},{re:/\b(eyJ[A-Za-z0-9_\-]+\.eyJ[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+)/g,replace:()=>`eyJ.${y}`},{re:/\b([A-Z0-9_]*(?:SECRET|TOKEN|KEY|PASSWORD|PASSWD|PWD|CREDENTIAL|API)[A-Z0-9_]*\s*=\s*)(['"]?)([^\s'"#\n]+)\2/gi,replace:(t,e,n)=>`${e}${n}${y}${n}`},{re:/([a-z][a-z0-9+\-.]*:\/\/[^:/?#\s]*):([^@\s]+)@/gi,replace:(t,e)=>`${e}:${y}@`}];function x(t){if(t==null)return "";let e=typeof t=="string"?t:JSON.stringify(t);return Pn.reduce((n,{re:r,replace:o})=>n.replace(r,o),e)}async function Te(t){let e=t.session_id||"unknown",n=t.tool_name||"unknown",r=t.tool_input||{},o=t.tool_response||"",s=F(e);if(!s){O(t);return}let i=I(),u=s.pendingTool,l=u?.name===n,p=l?u.startNs:String(BigInt(i)-200000000n),S=l?u.inputStr:w(r,k.TOOL_INPUT),T=S,d=null;if(n==="Skill"){let H=typeof r=="object"&&r!==null?r.skill||r.name||r.skillName||r.commandName||String(Object.values(r)[0]??""):String(r);d=H?String(H).trim():null;let C=d?st(d,s.cwd):null;C&&(T=C,s.skillContent||(s.skillContent=C),s.skillArtifacts||(s.skillArtifacts=ot(d,s.cwd))),d&&!s.slashSkill&&(s.slashSkill=d),a("PostToolUse","Skill tool detected",`skillName=${d}`,`contentFound=${!!C}`);}let E=x(w(o,k.TOOL_OUTPUT)),_=/\b(error|exception|failed|failure|traceback|errno)\b/i.test(E.slice(0,500)),h=_?"ERROR":"DEFAULT",J=b(),v=Math.round(Number(BigInt(i)-BigInt(p))/1e6),M={Agent:"AGENT",Task:"AGENT"}[n]??"TOOL",at=n==="Skill"&&d?d:rt(S,60);s.toolCalls.push({tool:n,brief:at,error:_,durationMs:v});let L=s.spans;L.push({traceId:s.traceId,spanId:J,parentSpanId:s.spanId,name:n,kind:3,startTimeUnixNano:p,endTimeUnixNano:i,attributes:U(c(m.OBS_NAME,n),c(m.OBS_TYPE,M),c(m.OBS_LEVEL,h),c(m.OBS_INPUT,x(T)),c(m.OBS_OUTPUT,E),c("tool.name",n),c("tool.error",String(_)),n==="Skill"&&d?c("skill.name",d):null,n==="Skill"?c("skill.invocation","slash-command"):null),status:{code:_?2:1}}),s.pendingTool=null,B(e,s),a("PostToolUse",`sid=${e}`,`tool=${n}`,`error=${_}`,`durationMs=${v}`,`totalSpans=${L.length}`),O(t);}var he={"claude-opus-4-6":{input:15,output:75},"claude-opus-4-5":{input:15,output:75},"claude-sonnet-4-6":{input:3,output:15},"claude-sonnet-4-5":{input:3,output:15},"claude-haiku-4-5":{input:.8,output:4},"claude-4-6-opus":{input:15,output:75},"claude-4-6-sonnet":{input:3,output:15},"claude-4-5-opus":{input:15,output:75},"claude-4-5-sonnet":{input:3,output:15},"claude-4-5-haiku":{input:.8,output:4},"claude-3-5-sonnet-20241022":{input:3,output:15},"claude-3-5-haiku-20241022":{input:.8,output:4},"claude-3-opus-20240229":{input:15,output:75}};function ye(t,e,n){let r=Object.keys(he).find(i=>(t??"").toLowerCase().includes(i));if(!r)return;let o=he[r],s=(e*o.input+n*o.output)/1e6;return Math.round(s*1e6)/1e6}async function Ae(t){let e=t.session_id||"unknown",n=t.stop_reason||"end_turn",r=F(e);if(!r){O(t);return}r.slashSkill&&!/^[a-z][a-z0-9-]*(?::[a-z][a-z0-9-]*)?$/i.test(r.slashSkill)&&(a("Stop",`sid=${e}`,`slashSkill rejected post-disk: "${r.slashSkill}"`),r.slashSkill=null);let o=I(),s=await jt(),i=r.toolCalls,u=r.spans;if(r.slashSkill&&!i.some(f=>f.tool==="Skill")){let f=b(),R=r.skillContent?r.skillContent:JSON.stringify({skill:r.slashSkill});i.push({tool:"Skill",brief:r.slashSkill,error:false,durationMs:0,synthetic:true}),u.push({traceId:r.traceId,spanId:f,parentSpanId:r.spanId,name:"Skill",kind:3,startTimeUnixNano:r.startNs,endTimeUnixNano:r.startNs,attributes:U(c(m.OBS_NAME,"Skill"),c(m.OBS_TYPE,"TOOL"),c(m.OBS_LEVEL,"DEFAULT"),c(m.OBS_INPUT,R),c(m.OBS_OUTPUT,"loaded via slash command"),c("tool.name","Skill"),c("tool.error","false"),c("skill.name",r.slashSkill),c("skill.invocation","slash-command")),status:{code:1}}),a("Stop",`slashSkill=${r.slashSkill}`,"synthetic span injected");}let l=t.transcript_path||r.transcriptPath||"",p=Ot(l);if(l&&(i.some(f=>f.tool==="Skill"&&!f.synthetic)||!!r.slashSkill)&&!p?.text){await new Promise(R=>setTimeout(R,500));let f=Ot(l);f?.text&&(p=f);}a("Stop",`transcriptPath=${l||"(empty)"}`,`assistantOut=${p?`text=${p.text.length}chars`:"null"}`);let T=i.length,d=i.filter(f=>f.error).length,E=x(p?.text?w(p.text,k.TRACE_OUTPUT):T===0?"No tools used":i.map((f,R)=>`${R+1}. ${f.tool}${f.brief?` \u2192 ${f.brief}`:""}${f.error?" [ERROR]":""}`).join(`
18
+ `)),_=p?.inputTokens??0,h=p?.outputTokens??0,J=i.map((f,R)=>`${R+1}. ${f.tool}${f.brief?` \u2192 ${f.brief}`:""}${f.error?" [ERROR]":""} (${f.durationMs}ms)`),v=!!(r.slashSkill||i.some(f=>f.tool==="Skill")),Lt=i.some(f=>f.tool==="Agent");if(!v&&!Lt){a("Stop",`sid=${e}`,"skipping trace \u2014 no Skill or Agent calls found"),At(e),O(t);return}let M=v?"skill":"agent",at=Math.round(Number(BigInt(o)-BigInt(r.startNs))/1e6),It=ye(r.model,_,h),L=oe(r);L==="prerequisite_required"&&p?.text&&(L="complete"),L==="prerequisite_required"&&(u.push({traceId:r.traceId,spanId:b(),parentSpanId:r.spanId,name:"prerequisite-check",kind:3,startTimeUnixNano:r.startNs,endTimeUnixNano:o,attributes:U(c(m.OBS_NAME,"prerequisite-check"),c(m.OBS_TYPE,"EVENT"),c(m.OBS_LEVEL,"WARNING"),c(m.OBS_OUTPUT,E),c("skill.name",r.slashSkill||void 0),c("execution_status","prerequisite_required")),status:{code:1}}),a("Stop",`sid=${e}`,"prerequisite-check span injected",`skill=${r.slashSkill}`));let H=(()=>{if(!(!v||!r.prompt)){if(r.slashSkill){let f=r.prompt.replace(new RegExp(`^\\/${r.slashSkill}\\s*`,"i"),"").trim();return f?w(f,k.USER_INSTRUCTION):void 0}return w(r.prompt,k.USER_INSTRUCTION)||void 0}})(),C=JSON.stringify({trace_type:M,...L!==null&&{execution_status:L},...r.slashSkill?{skill_name:r.slashSkill}:{},...r.skillArtifacts?.length&&{skill_artifacts:r.skillArtifacts},...H!==void 0&&{user_instruction:H},latency_ms:at,..._&&{tokens_input:_},...h&&{tokens_output:h},cost_usd:It,...r.model?{model:r.model}:{},toolCount:T,errorCount:d,stopReason:n,sessionId:r.sessionId,tools:J.length?J:void 0}),Nt=x(w(r.prompt,k.TRACE_INPUT)),Oe=U(c(m.TRACE_NAME,r.traceName),c(m.TRACE_INPUT,Nt),c(m.TRACE_OUTPUT,E),c(m.OBS_INPUT,Nt),c(m.OBS_OUTPUT,E),c(m.TRACE_METADATA,C),c(m.SESSION_ID,r.sessionId),c(m.USER_ID,s.user),c(m.OBS_TYPE,"GENERATION"),c(m.MODEL,r.model),_?c(m.INPUT_TOKENS,_):null,h?c(m.OUTPUT_TOKENS,h):null,c("claude.stop_reason",n),c("claude.tool_count",String(T)),c("claude.error_count",String(d)),c("claude.session_id",r.sessionId),c("flow.trace_type",M),{key:m.TRACE_TAGS,value:{arrayValue:{values:[{stringValue:M}]}}}),ke={traceId:r.traceId,spanId:r.spanId,name:r.traceName,kind:1,startTimeUnixNano:r.startNs,endTimeUnixNano:o,attributes:Oe,status:{code:d>0?2:1}},we=U(c("service.name",process.env.LANGFUSE_PROJECT_NAME||"claude-code"),c("deployment.environment",process.env.LANGFUSE_ENVIRONMENT||"default")),Rt=[...u,ke];a("Stop",`sid=${e}`,`totalTools=${T}`,`errorTools=${d}`,`spans=${Rt.length}`,`inputTokens=${_}`,`outputTokens=${h}`,`traceOutput="${rt(E,80)}"`);let Le=await Ee(ce(we,Rt));a("Stop",`POST status=${Le}`,`traceId=${r.traceId}`),At(e),O(t);}async function bn(){let t=process.argv[2];if(!await Jt()){let n=[];process.stdin.on("data",r=>n.push(r)),process.stdin.on("end",()=>process.stdout.write(n.join("")));return}let e=await qt();switch(t){case "UserPromptSubmit":await ie(e);break;case "PreToolUse":await ae(e);break;case "PostToolUse":await Te(e);break;case "Stop":await Ae(e);break;default:process.stderr.write(`[flow-obs] unknown event: ${t}
19
+ `),process.stdout.write(JSON.stringify(e));}}bn().catch(t=>{process.stderr.write(`[flow-obs] fatal: ${t.message}
18
20
  `),process.exit(0);});
package/dist/setup.js CHANGED
@@ -1,10 +1,8 @@
1
1
  #!/usr/bin/env node
2
- 'use strict';var a=(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 d=T((on,ee)=>{var O=process.env.FLOW_BASE_URL||"https://flow.ciandt.com",Q={AUTH_ENGINE:process.env.FLOW_AUTH_ENGINE_URL||`${O}/auth-engine-api/v2/api-key/token`,GATEWAY_TRACES:process.env.FLOW_GATEWAY_TRACES_URL||`${O}/flow-langfuse-gateway/v1/traces`,GATEWAY_HEALTH:process.env.FLOW_GATEWAY_HEALTH_URL||`${O}/flow-langfuse-gateway/v1/health`,OTEL_ENDPOINT:process.env.FLOW_OTEL_ENDPOINT_URL||`${O}/otel`},Fe={SERVICE:"flow-plugins-cli",ACCOUNT_CREDS:"credentials",ACCOUNT_TOKEN:"token-cache"},Ue="FLOW-nodejs",Pe="config.json",ke={SCOPE_NAME:"flow-ai-obs",SCOPE_VERSION:"0.1.0"},be={ANTHROPIC_BASE_URL:process.env.FLOW_LLM_PROXY_URL||`${O}/flow-llm-proxy/`,ANTHROPIC_MODEL:process.env.FLOW_LLM_PROXY_MODEL||"anthropic.claude-4-6-sonnet",ANTHROPIC_SMALL_FAST_MODEL:process.env.FLOW_LLM_PROXY_SMALL_MODEL||"anthropic.claude-4-6-sonnet",CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS:"1"},De={CLAUDE_CODE_ENABLE_TELEMETRY:"1",OTEL_EXPORTER_OTLP_ENDPOINT:Q.OTEL_ENDPOINT,OTEL_EXPORTER_OTLP_PROTOCOL:"http/json",OTEL_METRICS_EXPORTER:"otlp",OTEL_LOGS_EXPORTER:"otlp",OTEL_LOG_TOOL_DETAILS:"1",OTEL_LOG_USER_PROMPTS:"1"},Me={FLOW_TELEMETRY:"FLOW_TELEMETRY",FLOW_TELEMETRY_GATEWAY:"FLOW_TELEMETRY_GATEWAY_URL",LANGFUSE_BASE_URL:"LANGFUSE_BASE_URL",LANGFUSE_PUBLIC_KEY:"LANGFUSE_PUBLIC_KEY",LANGFUSE_SECRET_KEY:"LANGFUSE_SECRET_KEY",ANTHROPIC_MODEL:"ANTHROPIC_MODEL",ANTHROPIC_AUTH_TOKEN:"ANTHROPIC_AUTH_TOKEN",FLOW_OBS_DEBUG:"FLOW_TELEMETRY_DEBUG",FLOW_OBS_ALLOW_HTTP:"FLOW_TELEMETRY_ALLOW_HTTP",BUFFER_TTL_DAYS:"FLOW_TELEMETRY_BUFFER_TTL_DAYS",BUFFER_MAX_FILES:"FLOW_TELEMETRY_BUFFER_MAX_FILES"},Ye={KEYCHAIN_ENABLED:false},He={LOCK_STALE_MS:3e4,CONNECTIVITY_MAX_RETRY:3,CONNECTIVITY_RETRY_MS:2e3},qe={UserPromptSubmit:5,PreToolUse:3,PostToolUse:10,Stop:15},Be={FILE_PREFIX:"flow-obs-buffer-",DEFAULT_TTL_DAYS:4,MIN_TTL_DAYS:1,MAX_TTL_DAYS:30,DEFAULT_MAX_FILES:50,MIN_MAX_FILES:1,MAX_MAX_FILES:500,REPLAY_BATCH_SIZE:10},We="flow-ai-obs-debug.log",$e={TOOL_INPUT:2e4,TOOL_OUTPUT:2e4,TRACE_OUTPUT:2e4,USER_INSTRUCTION:1e4,TRACE_INPUT:5e4,TOOL_BRIEF:60},Ge="flow-obs-";ee.exports={FLOW_BASE_URL:O,FLOW_URLS:Q,VAULT:Fe,CONFIG_DIR_NAME:Ue,CONFIG_FILE_NAME:Pe,OTLP:ke,LLM_PROXY:be,NATIVE_OTEL:De,ENV:Me,FEATURES:Ye,INSTALLER:He,HOOK_TIMEOUTS:qe,BUFFER:Be,DEBUG_LOG_FILENAME:We,STATE_FILE_PREFIX:Ge,TRACE_LIMITS:$e};});var re=T((an,ne)=>{var g=a("fs"),L=a("path"),xe=a("os"),{CONFIG_DIR_NAME:U,CONFIG_FILE_NAME:P}=d(),k={credentials:"credentials","token-cache":"tokenCache"};function w(){let e=xe.homedir();if(process.platform==="darwin")return L.join(e,"Library","Preferences",U,P);if(process.platform==="win32"){let n=process.env.APPDATA||L.join(e,"AppData","Roaming");return L.join(n,U,P)}let t=process.env.XDG_CONFIG_HOME||L.join(e,".config");return L.join(t,U,P)}function b(){try{let e=g.readFileSync(w(),"utf8");return JSON.parse(e)}catch{return {}}}function te(e){let t=w();g.mkdirSync(L.dirname(t),{recursive:true}),g.writeFileSync(t,JSON.stringify(e,null,2),{encoding:"utf8",mode:384});}var C=class{static isAvailable(){return true}static hasExistingData(){try{if(!g.existsSync(w()))return !1;let t=JSON.parse(g.readFileSync(w(),"utf8"));return !!(t&&t.credentials)}catch{return false}}async getSecret(t,n){let r=b(),s=k[n]||n,o=r[s];return o?typeof o=="string"?o:JSON.stringify(o):null}async setSecret(t,n,r){let s=b(),o=k[n]||n;if(n==="token-cache")try{s[o]=JSON.parse(r);}catch{s[o]=r;}else s[o]=r;te(s);}async deleteSecret(t,n){let r=b(),s=k[n]||n;return s in r?(delete r[s],te(r),true):false}getStoragePath(){return `config.json (unencrypted) \u2014 ${w()}`}};function Ke(){}var Ve=C;ne.exports={JsonFallbackProvider:C,ScryptFallbackProvider:Ve,_resetWarningState:Ke};});var oe=T((cn,se)=>{var{execFile:Xe}=a("child_process"),{promisify:je}=a("util"),{accessSync:Je,constants:ze}=a("fs"),D=je(Xe),M=class{static async isAvailable(){try{return Je("/usr/bin/security",ze.X_OK),!0}catch{return false}}async getSecret(t,n){try{let{stdout:r}=await D("security",["find-generic-password","-w","-a",n,"-s",t]);return r.trim()||null}catch{return null}}async setSecret(t,n,r){await D("security",["add-generic-password","-U","-a",n,"-s",t,"-w",r]);}async deleteSecret(t,n){try{return await D("security",["delete-generic-password","-a",n,"-s",t]),!0}catch{return false}}getStoragePath(){return "macOS Keychain"}};se.exports={MacOsKeyVaultProvider:M};});var ie=T((ln,ce)=>{var{execFile:Ze,spawn:Qe}=a("child_process"),{promisify:et}=a("util"),{accessSync:tt,constants:nt}=a("fs"),ae=et(Ze),Y=class{static async isAvailable(){let t=["/usr/bin/secret-tool","/bin/secret-tool","/usr/local/bin/secret-tool"];for(let n of t)try{return tt(n,nt.X_OK),!0}catch{}return false}async getSecret(t,n){try{let{stdout:r}=await ae("secret-tool",["lookup","service",t,"account",n]);return r.trim()||null}catch{return null}}async setSecret(t,n,r){await new Promise((s,o)=>{let c=Qe("secret-tool",["store","--label",t,"service",t,"account",n]);c.on("error",o),c.on("close",E=>{E===0?s():o(new Error(`secret-tool exited with code ${E}`));}),c.stdin.write(r),c.stdin.end();});}async deleteSecret(t,n){try{return await ae("secret-tool",["clear","service",t,"account",n]),!0}catch{return false}}getStoragePath(){return "Linux Secret Service (libsecret)"}};ce.exports={LinuxKeyVaultProvider:Y};});var ue=T((un,le)=>{var H=class{static async isAvailable(){try{return await a("keytar").getPassword("__flow_probe__","__flow_probe__"),!0}catch{return false}}async getSecret(t,n){return a("keytar").getPassword(t,n)}async setSecret(t,n,r){await a("keytar").setPassword(t,n,r);}async deleteSecret(t,n){return a("keytar").deletePassword(t,n)}getStoragePath(){return "Windows Credential Manager"}};le.exports={WindowsKeyVaultProvider:H};});var Te=T((En,_e)=>{async function Ee(){let{JsonFallbackProvider:e}=re();return await rt()??new e}async function rt(){switch(process.platform){case "darwin":{let{MacOsKeyVaultProvider:e}=oe();return await e.isAvailable()?new e:null}case "linux":{let{LinuxKeyVaultProvider:e}=ie();return await e.isAvailable()?new e:null}case "win32":{let{WindowsKeyVaultProvider:e}=ue();return await e.isAvailable()?new e:null}default:return null}}var st=Ee;_e.exports={createSecretVaultProvider:Ee,createKeyVaultProvider:st};});var x=T((_n,de)=>{var{createSecretVaultProvider:ot}=Te(),{VAULT:B}=d(),h=B.SERVICE,W=B.ACCOUNT_CREDS,$=B.ACCOUNT_TOKEN,q=null;function y(){return q||(q=ot()),q}async function fe(){let t=await(await y()).getSecret(h,W);if(!t)return null;try{return JSON.parse(t)}catch{return null}}async function at(e){if(!e.clientId||!e.clientSecret||!e.tenant)throw new Error("clientId, clientSecret and tenant are required");await(await y()).setSecret(h,W,JSON.stringify(e));}async function ct(){let e=await y();await e.deleteSecret(h,W),await e.deleteSecret(h,$);}async function it(e){await(await y()).setSecret(h,$,JSON.stringify({accessToken:e.accessToken,expiresAt:e.expiresAt}));}async function G(){let t=await(await y()).getSecret(h,$);if(!t)return null;try{let n=JSON.parse(t);return {accessToken:n.accessToken,expiresAt:n.expiresAt}}catch{return null}}async function lt(){let e=await G();return e?new Date(e.expiresAt)>new Date:false}async function ut(){let e=await G();if(!e||!e.accessToken)return null;try{let t=e.accessToken.split(".");if(t.length<2)return null;let n=JSON.parse(Buffer.from(t[1].replace(/-/g,"+").replace(/_/g,"/"),"base64").toString("utf8"));return n.email||n.preferred_username||n.upn||n.sub||null}catch{return null}}async function Et(){let e=await y();if(typeof e.getStoragePath=="function")return e.getStoragePath();let t=process.platform;return t==="darwin"?"macOS Keychain":t==="win32"?"Windows Credential Manager":"Linux Secret Service (libsecret)"}async function _t(){let e=await fe();return !!(e&&e.clientId&&e.clientSecret&&e.tenant)}de.exports={getFlowCredentials:fe,saveFlowCredentials:at,clearFlowCredentials:ct,saveTokenCache:it,getTokenCache:G,isTokenValid:lt,getEmailFromToken:ut,getConfigPath:Et,hasCredentials:_t};});var K=T((Tn,Se)=>{var Tt=a("https"),ft=a("http"),{FLOW_URLS:dt}=d(),pt=/^[a-z0-9][a-z0-9-]{0,62}[a-z0-9]$|^[a-z0-9]$/;function St(e){if(!pt.test(e))throw new Error(`Invalid tenant value: "${e}". Tenant must be lowercase alphanumeric and hyphens (1-64 chars).`)}var pe={INVALID_CLIENT_SECRET:"Invalid Client Secret \u2014 check the value and try again",INVALID_CLIENT_ID:"Invalid Client ID \u2014 check the value and try again",INVALID_TENANT:"Invalid Tenant \u2014 check the value and try again",TENANT_NOT_FOUND:"Tenant not found \u2014 verify the tenant identifier"};function At(e,t){try{let n=JSON.parse(t);if(typeof n.error=="string"&&pe[n.error])return new Error(pe[n.error])}catch{}return e===401||e===403||e===500?new Error("Invalid credentials"):e>=400&&e<500?new Error("Authentication request was rejected"):new Error("Authentication service unavailable, please try again later")}function Ot(e){return new Promise((t,n)=>{try{St(e.tenant);}catch(l){return n(l)}let r=JSON.stringify({clientSecret:e.clientSecret}),s=new URL(dt.AUTH_ENGINE),o=s.protocol==="https:",c={hostname:s.hostname,port:s.port||(o?443:80),path:s.pathname+s.search,method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(r),FlowTenant:e.tenant}},_=(o?Tt:ft).request(c,l=>{let I=[];l.on("data",A=>I.push(A)),l.on("end",()=>{let A=I.join("");if(l.statusCode>=400)return n(At(l.statusCode,A));let u;try{u=JSON.parse(A);}catch{return n(new Error("Invalid response from auth engine"))}let p=u.expires_at??new Date(Date.now()+(u.expires_in??3600)*1e3).toISOString();t({accessToken:u.access_token,expiresAt:p});});});_.on("error",l=>n(new Error(`Network error: ${l.message}`))),_.write(r),_.end();})}Se.exports={getToken:Ot};});var ye=T((fn,he)=>{var i=a("fs"),R=a("path"),Ae=a("os"),{FLOW_URLS:Lt,INSTALLER:N,HOOK_TIMEOUTS:ht,NATIVE_OTEL:yt,LLM_PROXY:wt}=d(),{getToken:gt}=K();function X(){return process.platform==="win32"?R.join(process.env.APPDATA||R.join(Ae.homedir(),"AppData","Roaming"),"Claude","settings.json"):R.join(Ae.homedir(),".claude","settings.json")}var Nt=N.LOCK_STALE_MS;function Oe(e){try{let t=i.statSync(e);Date.now()-t.mtimeMs>Nt&&i.unlinkSync(e);}catch{}try{i.writeFileSync(e,String(process.pid),{flag:"wx"});}catch(t){throw t.code==="EEXIST"?new Error("Another install is already in progress. If this is stale, remove: "+e):t}}function Le(e){try{i.unlinkSync(e);}catch{}}function Rt(e,t){let r=(Array.isArray(e)?e:[]).map(s=>{if(!Array.isArray(s?.hooks))return null;let o=s.hooks.filter(c=>!c.command?.startsWith?.("flow-ai-obs "));return o.length>0?{...s,hooks:o}:null}).filter(s=>s!=null);return [t,...r]}function It(){let e=X(),t=e+".lock";i.mkdirSync(R.dirname(e),{recursive:true});let n=[];Oe(t);try{if(i.existsSync(e)){i.copyFileSync(e,e+".bkp");try{i.chmodSync(e+".bkp",384);}catch{}}let r={};try{r=JSON.parse(i.readFileSync(e,"utf8"));}catch{}(!r.env||typeof r.env!="object")&&(r.env={}),Object.assign(r.env,yt),Object.assign(r.env,wt),r.otelHeadersHelper="flow-ai-obs otel-headers",(!r.hooks||typeof r.hooks!="object"||Array.isArray(r.hooks))&&(r.hooks={});let s=(c,E)=>({matcher:"",hooks:[{type:"command",command:`flow-ai-obs ${c}`,timeout:E}]}),o=["UserPromptSubmit","PreToolUse","PostToolUse","Stop"];for(let c of o){let E=Rt(r.hooks[c],s(c,ht[c]));E.length>1&&n.push(c),r.hooks[c]=E;}i.writeFileSync(e,JSON.stringify(r,null,2)+`
3
- `,{encoding:"utf8",mode:384});try{i.chmodSync(e,384);}catch{}}finally{Le(t);}return {settingsPath:e,preserved:n}}async function Ct(e){let t;try{t=(await gt(e)).accessToken;}catch{return false}return t?new Promise(n=>{V(`Bearer ${t}`,n,1);}):false}function V(e,t,n){let r=new URL(Lt.GATEWAY_TRACES),s=JSON.stringify({resourceSpans:[],validation_run:true}),o=r.protocol==="https:",c={hostname:r.hostname,port:r.port||(o?443:80),path:r.pathname,method:"POST",headers:{"Content-Type":"application/json",Authorization:e,"Content-Length":Buffer.byteLength(s)}},_=(o?a("https"):a("http")).request(c,l=>{l.resume(),l.statusCode===200||l.statusCode===204?t(true):n<N.CONNECTIVITY_MAX_RETRY?setTimeout(()=>V(e,t,n+1),N.CONNECTIVITY_RETRY_MS):t(false);});_.on("error",()=>{n<N.CONNECTIVITY_MAX_RETRY?setTimeout(()=>V(e,t,n+1),N.CONNECTIVITY_RETRY_MS):t(false);}),_.write(s),_.end();}function vt(e){let t=X(),n=t+".lock";i.mkdirSync(R.dirname(t),{recursive:true}),Oe(n);try{let r={};try{r=JSON.parse(i.readFileSync(t,"utf8"));}catch{}(!r.env||typeof r.env!="object")&&(r.env={}),Object.assign(r.env,e),i.writeFileSync(t,JSON.stringify(r,null,2)+`
4
- `,{encoding:"utf8",mode:384});try{i.chmodSync(t,384);}catch{}}finally{Le(n);}}he.exports={getClaudeSettingsPath:X,writeClaudeSettings:It,addEnvToClaudeSettings:vt,validateConnectivity:Ct};});var Ne=T((dn,ge)=>{var{writeFileSync:mt}=a("fs"),{tmpdir:Ft}=a("os"),{join:Ut}=a("path"),{DEBUG_LOG_FILENAME:Pt,ENV:kt}=d(),we=Ut(Ft(),Pt);function bt(...e){if(process.env[kt.FLOW_OBS_DEBUG]!=="1")return;let t=`[${new Date().toISOString()}] ${e.join(" ")}
5
- `;try{mt(we,t,{flag:"a"});}catch(n){process.stderr.write(`[flow-obs debug ERROR] ${n.message}
6
- `);}}ge.exports={dbg:bt,DEBUG_LOG:we};});var Ce=T((pn,Ie)=>{var{getFlowCredentials:j,isTokenValid:Dt,getEmailFromToken:v,getTokenCache:Mt,saveTokenCache:Yt}=x(),{getToken:Ht}=K(),{FLOW_BASE_URL:qt,ENV:f,FEATURES:J}=d(),{dbg:S}=Ne(),Bt=[/^localhost\.?$/i,/^127\./,/^10\./,/^172\.(1[6-9]|2\d|3[01])\./,/^192\.168\./,/^169\.254\./,/^0\.0\.0\.0$/,/^::1$/,/^\[::1\]$/,/^\[::ffff:/i,/^\[f[cd]/i,/^\[fe80:/i,/^metadata\.google\.internal\.?$/i,/^metadata\.azure\.internal\.?$/i,/(?:^|\.)localtest\.me\.?$/i,/(?:^|\.)lvh\.me\.?$/i,/(?:^|\.)vcap\.me\.?$/i];function Wt(e){return Bt.some(t=>t.test(e))}function $t(e){if(!e)return null;try{let t=e.split(".");if(t.length<2)return null;let n=JSON.parse(Buffer.from(t[1].replace(/-/g,"+").replace(/_/g,"/"),"base64").toString("utf8"));return n.email||n.preferred_username||n.upn||n.sub||null}catch{return null}}function Z(e){if(!e)return null;try{let t=e.split(".");if(t.length<2)return null;let n=JSON.parse(Buffer.from(t[1].replace(/-/g,"+").replace(/_/g,"/"),"base64").toString("utf8")),{clientId:r,clientSecret:s,tenant:o}=n;return !r||!s||!o?null:{clientId:r,clientSecret:s,tenant:o}}catch{return null}}function Gt(e){let t=Buffer.from(JSON.stringify({alg:"none",typ:"JWT"})).toString("base64url"),n=Buffer.from(JSON.stringify({clientId:e.clientId,clientSecret:e.clientSecret,tenant:e.tenant})).toString("base64url");return `${t}.${n}.`}function z(e){let t;try{t=new URL(e);}catch{throw new Error(`Invalid URL: ${e}`)}let n=process.env[f.FLOW_OBS_ALLOW_HTTP]==="true";if(!n&&t.protocol!=="https:")throw new Error(`URL must use HTTPS: ${e}`);if(t.username||t.password)throw new Error(`URL must not contain embedded credentials: ${e}`);if(!n&&Wt(t.hostname))throw new Error(`SSRF: private/loopback host not allowed: ${t.hostname}`);return e}async function xt(){let e=Z(process.env[f.ANTHROPIC_AUTH_TOKEN]);if(e)return {user:await v().catch(()=>null)||e.clientId,tenant:e.tenant};if(J.KEYCHAIN_ENABLED)try{let t=await j();if(!t)return {user:"",tenant:""};let n=await v()||t.clientId||"",r=t.tenant||"";return {user:n,tenant:r}}catch{return {user:"",tenant:""}}return {user:"",tenant:""}}async function Kt(e){if(await Dt())return (await Mt()).accessToken;S("getOrRefreshToken","token expired \u2014 refreshing via auth-engine");let t=await Ht(e);try{await Yt(t);}catch(n){S("getOrRefreshToken",`token cache save failed (non-fatal): ${n.message}`);}return S("getOrRefreshToken",`token refreshed, expires=${t.expiresAt}`),t.accessToken}function Vt(e,t){let n=t&&t.accessToken?t.accessToken:"";return {endpoint:e.replace(/\/$/,"")+"/flow-langfuse-gateway/v1/traces",authHeader:`Bearer ${n}`}}function Xt(e,t,n){let r=Buffer.from(`${t}:${n}`).toString("base64");return {endpoint:e.replace(/\/$/,"")+"/api/public/otel/v1/traces",authHeader:`Basic ${r}`}}async function Re(){let e=[],t=process.env[f.ANTHROPIC_MODEL]||"",n=Z(process.env[f.ANTHROPIC_AUTH_TOKEN]);S("resolveCredentials",n?"credentials resolved from ANTHROPIC_AUTH_TOKEN":"ANTHROPIC_AUTH_TOKEN absent or invalid"),!n&&J.KEYCHAIN_ENABLED&&(n=await j(),n&&S("resolveCredentials","credentials resolved from keychain (FEATURES.KEYCHAIN_ENABLED=true)"));let r=n?n.tenant:"",s=process.env[f.FLOW_TELEMETRY]==="true",o=process.env[f.LANGFUSE_BASE_URL],c=process.env[f.LANGFUSE_PUBLIC_KEY],E=process.env[f.LANGFUSE_SECRET_KEY];if(s&&o&&c&&E){let u="",p=r;if(n)u=await v().catch(()=>null)||n.clientId;else if(J.KEYCHAIN_ENABLED)try{let F=await j();F&&(u=await v()||F.clientId,p=F.tenant);}catch{}let m={user:u||"",tenant:p||"",team:"",project:"",model:t};e.push({mode:"direct",...Xt(z(o),c,E),...m}),S("resolveCredentials","direct mode active",`user=${m.user}`,`tenant=${m.tenant}`);}if(!n){if(e.length===0){let u=[];return u.authError=false,u}return e}let _=null;try{_=await Kt(n);}catch(u){if(S("resolveCredentials",`token refresh failed: ${u.message}`),e.length>0)return e;let p=[];return p.authError=true,p}let I={user:$t(_)||n.clientId,tenant:r,team:"",project:"",model:t},A=process.env[f.FLOW_TELEMETRY_GATEWAY]||qt;return e.push({mode:"gateway",...Vt(z(A),{accessToken:_}),...I}),e}async function jt(){return (await Re()).length>0}Ie.exports={credentialsAvailable:jt,getIdentityFromToken:xt,resolveCredentials:Re,validateUrl:z,parseCredsFromAnthropicToken:Z,buildAnthropicAuthToken:Gt};});var me=a("path"),{getFlowCredentials:Jt}=x(),{writeClaudeSettings:zt,addEnvToClaudeSettings:Zt}=ye(),{buildAnthropicAuthToken:Qt,parseCredsFromAnthropicToken:en}=Ce(),{ENV:ve}=d(),tn=me.resolve(__dirname,".."),nn=process.env.INIT_CWD?me.resolve(process.env.INIT_CWD):null;nn===tn&&process.exit(0);async function rn(){try{zt();}catch{}let e=await Jt();if(!e){process.stderr.write(`
2
+ 'use strict';var child_process=require('child_process'),util=require('util'),s=require('fs'),p=require('path'),F=require('os');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var s__namespace=/*#__PURE__*/_interopNamespace(s);var p__namespace=/*#__PURE__*/_interopNamespace(p);var F__namespace=/*#__PURE__*/_interopNamespace(F);var re=Object.defineProperty;var T=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(e,r)=>(typeof require<"u"?require:e)[r]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')});var A=(t,e)=>()=>(t&&(e=t(t=0)),e);var O=(t,e)=>{for(var r in e)re(t,r,{get:e[r],enumerable:true});};var $={};O($,{MacOsKeyVaultProvider:()=>N});var v,N,G=A(()=>{v=util.promisify(child_process.execFile),N=class{static async isAvailable(){try{return s.accessSync("/usr/bin/security",s.constants.X_OK),!0}catch{return false}}async getSecret(e,r){try{let{stdout:n}=await v("security",["find-generic-password","-w","-a",r,"-s",e]);return n.trim()||null}catch{return null}}async setSecret(e,r,n){await v("security",["add-generic-password","-U","-a",r,"-s",e,"-w",n]);}async deleteSecret(e,r){try{return await v("security",["delete-generic-password","-a",r,"-s",e]),!0}catch{return false}}getStoragePath(){return "macOS Keychain"}};});var V={};O(V,{LinuxKeyVaultProvider:()=>I});var W,I,B=A(()=>{W=util.promisify(child_process.execFile),I=class{static async isAvailable(){let e=["/usr/bin/secret-tool","/bin/secret-tool","/usr/local/bin/secret-tool"];for(let r of e)try{return s.accessSync(r,s.constants.X_OK),!0}catch{}return false}async getSecret(e,r){try{let{stdout:n}=await W("secret-tool",["lookup","service",e,"account",r]);return n.trim()||null}catch{return null}}async setSecret(e,r,n){await new Promise((o,i)=>{let a=child_process.spawn("secret-tool",["store","--label",e,"service",e,"account",r]);a.on("error",i),a.on("close",f=>{f===0?o():i(new Error(`secret-tool exited with code ${f}`));}),a.stdin.write(n),a.stdin.end();});}async deleteSecret(e,r){try{return await W("secret-tool",["clear","service",e,"account",r]),!0}catch{return false}}getStoragePath(){return "Linux Secret Service (libsecret)"}};});var x={};O(x,{WindowsKeyVaultProvider:()=>P});var P,K=A(()=>{P=class{static async isAvailable(){try{return await T("keytar").getPassword("__flow_probe__","__flow_probe__"),!0}catch{return false}}async getSecret(e,r){return T("keytar").getPassword(e,r)}async setSecret(e,r,n){await T("keytar").setPassword(e,r,n);}async deleteSecret(e,r){return T("keytar").deletePassword(e,r)}getStoragePath(){return "Windows Credential Manager"}};});var u=process.env.FLOW_BASE_URL||"https://flow.ciandt.com",L={AUTH_ENGINE:process.env.FLOW_AUTH_ENGINE_URL||`${u}/auth-engine-api/v2/api-key/token`,GATEWAY_TRACES:process.env.FLOW_GATEWAY_TRACES_URL||`${u}/flow-langfuse-gateway/v1/traces`,GATEWAY_HEALTH:process.env.FLOW_GATEWAY_HEALTH_URL||`${u}/flow-langfuse-gateway/v1/health`,OTEL_ENDPOINT:process.env.FLOW_OTEL_ENDPOINT_URL||`${u}/otel`},g={SERVICE:"flow-plugins-cli",ACCOUNT_CREDS:"credentials"},y="FLOW-nodejs",S="config.json";var U={ANTHROPIC_BASE_URL:process.env.FLOW_LLM_PROXY_URL??`${u}/flow-llm-proxy/`,ANTHROPIC_MODEL:process.env.FLOW_LLM_PROXY_MODEL??"anthropic.claude-4-6-sonnet",ANTHROPIC_SMALL_FAST_MODEL:process.env.FLOW_LLM_PROXY_SMALL_MODEL??"anthropic.claude-4-6-sonnet",CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS:"1"},b={CLAUDE_CODE_ENABLE_TELEMETRY:"1",OTEL_EXPORTER_OTLP_ENDPOINT:L.OTEL_ENDPOINT,OTEL_EXPORTER_OTLP_PROTOCOL:"http/json",OTEL_METRICS_EXPORTER:"otlp",OTEL_LOGS_EXPORTER:"otlp",OTEL_LOG_TOOL_DETAILS:"1",OTEL_LOG_USER_PROMPTS:"1"},d={FLOW_TELEMETRY:"FLOW_TELEMETRY",FLOW_TELEMETRY_GATEWAY:"FLOW_TELEMETRY_GATEWAY_URL",LANGFUSE_BASE_URL:"LANGFUSE_BASE_URL",LANGFUSE_PUBLIC_KEY:"LANGFUSE_PUBLIC_KEY",LANGFUSE_SECRET_KEY:"LANGFUSE_SECRET_KEY",ANTHROPIC_MODEL:"ANTHROPIC_MODEL",ANTHROPIC_AUTH_TOKEN:"ANTHROPIC_AUTH_TOKEN",FLOW_OBS_DEBUG:"FLOW_TELEMETRY_DEBUG",FLOW_OBS_ALLOW_HTTP:"FLOW_TELEMETRY_ALLOW_HTTP",BUFFER_TTL_DAYS:"FLOW_TELEMETRY_BUFFER_TTL_DAYS",BUFFER_MAX_FILES:"FLOW_TELEMETRY_BUFFER_MAX_FILES"};var D={LOCK_STALE_MS:3e4},H={UserPromptSubmit:5,PreToolUse:3,PostToolUse:10,Stop:15};var M="flow-ai-obs-debug.log";var w={credentials:"credentials","token-cache":"tokenCache"};function E(){let t=F__namespace.default.homedir();if(process.platform==="darwin")return p__namespace.default.join(t,"Library","Preferences",y,S);if(process.platform==="win32"){let r=process.env.APPDATA??p__namespace.default.join(t,"AppData","Roaming");return p__namespace.default.join(r,y,S)}let e=process.env.XDG_CONFIG_HOME??p__namespace.default.join(t,".config");return p__namespace.default.join(e,y,S)}function R(){try{let t=s__namespace.default.readFileSync(E(),"utf8");return JSON.parse(t)}catch{return {}}}function Y(t){let e=E();s__namespace.default.mkdirSync(p__namespace.default.dirname(e),{recursive:true}),s__namespace.default.writeFileSync(e,JSON.stringify(t,null,2),{encoding:"utf8",mode:384});}var h=class{static isAvailable(){return true}static hasExistingData(){try{if(!s__namespace.default.existsSync(E()))return !1;let e=JSON.parse(s__namespace.default.readFileSync(E(),"utf8"));return !!(e&&e.credentials)}catch{return false}}async getSecret(e,r){let n=R(),o=w[r]??r,i=n[o];return i?typeof i=="string"?i:JSON.stringify(i):null}async setSecret(e,r,n){let o=R(),i=w[r]??r;if(r==="token-cache")try{o[i]=JSON.parse(n);}catch{o[i]=n;}else o[i]=n;Y(o);}async deleteSecret(e,r){let n=R(),o=w[r]??r;return o in n?(delete n[o],Y(n),true):false}getStoragePath(){return `config.json (unencrypted) \u2014 ${E()}`}};async function X(){return await de()??new h}async function de(){switch(process.platform){case "darwin":{let{MacOsKeyVaultProvider:t}=await Promise.resolve().then(()=>(G(),$));return await t.isAvailable()?new t:null}case "linux":{let{LinuxKeyVaultProvider:t}=await Promise.resolve().then(()=>(B(),V));return await t.isAvailable()?new t:null}case "win32":{let{WindowsKeyVaultProvider:t}=await Promise.resolve().then(()=>(K(),x));return await t.isAvailable()?new t:null}default:return null}}var Ee=g.SERVICE,_e=g.ACCOUNT_CREDS,k=null;function me(){return k||(k=X()),k}async function C(){let e=await(await me()).getSecret(Ee,_e);if(!e)return null;try{return JSON.parse(e)}catch{return null}}p.join(F.tmpdir(),M);function j(){return process.platform==="win32"?p__namespace.join(process.env.APPDATA||p__namespace.join(F__namespace.homedir(),"AppData","Roaming"),"Claude","settings.json"):p__namespace.join(F__namespace.homedir(),".claude","settings.json")}var he=D.LOCK_STALE_MS;function J(t){try{let e=s__namespace.statSync(t);Date.now()-e.mtimeMs>he&&s__namespace.unlinkSync(t);}catch{}try{s__namespace.writeFileSync(t,String(process.pid),{flag:"wx"});}catch(e){throw e.code==="EEXIST"?new Error("Another install is already in progress. If this is stale, remove: "+t):e}}function q(t){try{s__namespace.unlinkSync(t);}catch{}}function Ae(t,e){let n=(Array.isArray(t)?t:[]).map(o=>{if(!Array.isArray(o?.hooks))return null;let i=o.hooks.filter(a=>!a.command?.startsWith?.("flow-ai-obs "));return i.length>0?{...o,hooks:i}:null}).filter(o=>o!=null);return [e,...n]}function z(){let t=j(),e=t+".lock",r=[];s__namespace.mkdirSync(p__namespace.dirname(t),{recursive:true}),J(e);try{if(s__namespace.existsSync(t)){s__namespace.copyFileSync(t,t+".bkp");try{s__namespace.chmodSync(t+".bkp",384);}catch{}}let n={};try{n=JSON.parse(s__namespace.readFileSync(t,"utf8"));}catch{}let o=n.env&&typeof n.env=="object"?n.env:{};n.env={...b,...U,...o},n.otelHeadersHelper="flow-ai-obs otel-headers",(!n.hooks||typeof n.hooks!="object"||Array.isArray(n.hooks))&&(n.hooks={});let i=(c,m)=>({matcher:"",hooks:[{type:"command",command:`flow-ai-obs ${c}`,timeout:m}]}),a=["UserPromptSubmit","PreToolUse","PostToolUse","Stop"],f=n.hooks;for(let c of a){let m=Ae(f[c],i(c,H[c]));m.length>1&&r.push(c),f[c]=m;}s__namespace.writeFileSync(t,JSON.stringify(n,null,2)+`
3
+ `,{encoding:"utf8",mode:384});try{s__namespace.chmodSync(t,384);}catch{}}finally{q(e);}return {settingsPath:t,preserved:r}}function Z(t){let e=j(),r=e+".lock";s__namespace.mkdirSync(p__namespace.dirname(e),{recursive:true}),J(r);try{let n={};try{n=JSON.parse(s__namespace.readFileSync(e,"utf8"));}catch{}(!n.env||typeof n.env!="object")&&(n.env={}),Object.assign(n.env,t),s__namespace.writeFileSync(e,JSON.stringify(n,null,2)+`
4
+ `,{encoding:"utf8",mode:384});try{s__namespace.chmodSync(e,384);}catch{}}finally{q(r);}}function Q(t){if(!t)return null;try{let e=t.split(".");if(e.length<2)return null;let r=JSON.parse(Buffer.from(e[1].replace(/-/g,"+").replace(/_/g,"/"),"base64").toString("utf8")),{clientId:n,clientSecret:o,tenant:i}=r;return !n||!o||!i?null:{clientId:n,clientSecret:o,tenant:i}}catch{return null}}function ee(t){let e=Buffer.from(JSON.stringify({alg:"none",typ:"JWT"})).toString("base64url"),r=Buffer.from(JSON.stringify({clientId:t.clientId,clientSecret:t.clientSecret,tenant:t.tenant})).toString("base64url");return `${e}.${r}.`}var Oe=p__namespace.default.resolve(__dirname,".."),Le=process.env.INIT_CWD?p__namespace.default.resolve(process.env.INIT_CWD):null;Le===Oe&&process.exit(0);async function we(){try{z();}catch{}let t=await C();if(!t){process.stderr.write(`
7
5
  [flow-ai-obs] No credentials found.
8
6
  Run \`flow-ai-obs auth login\` to authenticate and enable telemetry.
9
7
 
10
- `);return}let t=en(process.env[ve.ANTHROPIC_AUTH_TOKEN]);if(!t||t.clientId!==e.clientId||t.clientSecret!==e.clientSecret||t.tenant!==e.tenant)try{let r=Qt(e);Zt({[ve.ANTHROPIC_AUTH_TOKEN]:r});}catch{}}rn().catch(()=>{});
8
+ `);return}let e=Q(process.env[d.ANTHROPIC_AUTH_TOKEN]);if(!e||e.clientId!==t.clientId||e.clientSecret!==t.clientSecret||e.tenant!==t.tenant)try{let n=ee(t);Z({[d.ANTHROPIC_AUTH_TOKEN]:n});}catch{}}we().catch(()=>{});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ciandt-flow/flow-ai-obs",
3
- "version": "0.4.1",
3
+ "version": "0.5.0-beta.211",
4
4
  "description": "Claude Code hooks for Langfuse OTLP tracing — cross-platform",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -9,19 +9,21 @@
9
9
  },
10
10
  "scripts": {
11
11
  "build": "tsup",
12
- "test": "node --test src/**/*.test.js",
13
- "typecheck": "node --check src/**/*.js bin/cli.js",
14
- "lint": "node --check src/**/*.js bin/cli.js",
12
+ "test": "jest",
13
+ "typecheck": "tsc --noEmit",
14
+ "lint": "eslint src bin scripts",
15
+ "format": "prettier --write \"src/**/*.ts\" \"bin/**/*.ts\" \"scripts/**/*.ts\"",
16
+ "format:check": "prettier --check \"src/**/*.ts\" \"bin/**/*.ts\" \"scripts/**/*.ts\"",
15
17
  "security-scan": "trufflehog filesystem src/ --fail --no-update --exclude-paths .trufflehogignore",
16
18
  "postinstall": "node -e \"require('fs').existsSync('dist/setup.js') && require('child_process').execFileSync(process.execPath, ['dist/setup.js'], {stdio:'inherit'})\"",
17
19
  "prepublishOnly": "npm run security-scan && npm run build",
18
20
  "release:npm": "changeset publish",
19
21
  "changeset": "changeset",
20
22
  "version-packages": "changeset version",
21
- "install:hooks": "node bin/cli.js install",
22
- "auth:login": "node bin/cli.js auth login",
23
- "auth:logout": "node bin/cli.js auth logout",
24
- "auth:status": "node bin/cli.js auth status",
23
+ "install:hooks": "node dist/cli.js install",
24
+ "auth:login": "node dist/cli.js auth login",
25
+ "auth:logout": "node dist/cli.js auth logout",
26
+ "auth:status": "node dist/cli.js auth status",
25
27
  "smoke": "bash scripts/smoke-test.sh",
26
28
  "smoke:debug": "bash scripts/smoke-test.sh --debug",
27
29
  "smoke:send": "bash scripts/smoke-test.sh --send --allow-http --debug"
@@ -49,8 +51,15 @@
49
51
  "devDependencies": {
50
52
  "@changesets/changelog-github": "^0.6.0",
51
53
  "@changesets/cli": "^2.30.0",
54
+ "@types/jest": "^30.0.0",
55
+ "@types/node": "^25.8.0",
56
+ "jest": "^30.4.2",
57
+ "ts-jest": "^29.4.9",
52
58
  "tsup": "^8.5.1",
53
- "typescript": "^6.0.3"
59
+ "eslint-config-prettier": "^10.1.5",
60
+ "prettier": "^3.5.3",
61
+ "typescript": "^6.0.3",
62
+ "typescript-eslint": "^8.33.0"
54
63
  },
55
64
  "engines": {
56
65
  "node": ">=18.0.0"
@@ -63,4 +72,4 @@
63
72
  "type": "git",
64
73
  "url": "git+https://github.com/CI-T-HyperX/flow-codeassistant-observability.git"
65
74
  }
66
- }
75
+ }