@ciandt-flow/flow-ai-obs 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +103 -83
- package/dist/index.js +15 -10
- package/dist/setup.js +41 -37
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -1,97 +1,117 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
'use strict';var c=(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
|
|
2
|
+
'use strict';var c=(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 p=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Se=p((Na,ds)=>{ds.exports={name:"@ciandt-flow/flow-ai-obs",version:"0.3.0",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 J=p((Ia,pt)=>{var ps=!process.env.NO_COLOR&&process.stdout.isTTY;function q(e,t){return ps?n=>`\x1B[${e}m${n}\x1B[${t}m`:n=>n}var fs=q("32","39"),hs=q("31","39"),Ts=q("33","39"),Ss=q("36","39"),Es=q("1","22"),ws=q("2","22");pt.exports={green:fs,red:hs,yellow:Ts,cyan:Ss,bold:Es,dim:ws};});var Re=p((Ca,Et)=>{var _s=c("https"),Tt=c("fs"),gs=c("os"),ms=c("path"),{spawn:ys}=c("child_process"),Ue;function F(){return Ue||(Ue=Se()),Ue}var St=ms.join(gs.tmpdir(),"flow-obs-update-cache.json"),As=1440*60*1e3,Os=3e3;function ve(e,t){let n=o=>{let i=String(o).replace(/^v/,"").match(/^(\d+)\.(\d+)\.(\d+)/);return i?[+i[1],+i[2],+i[3]]:null},s=n(e),r=n(t);return !s||!r?false:r[0]!==s[0]?r[0]>s[0]:r[1]!==s[1]?r[1]>s[1]:r[2]>s[2]}function Ls(){try{let e=JSON.parse(Tt.readFileSync(St,"utf8"));return typeof e.latestVersion!="string"||Date.now()-e.checkedAt>=As?null:e}catch{return null}}function Ns(e,t){try{Tt.writeFileSync(St,JSON.stringify({latestVersion:e,updatePriority:t||null,checkedAt:Date.now()}),{mode:384});}catch{}}function Is(e){let t=F().name,n=_s.get(`https://registry.npmjs.org/${encodeURIComponent(t)}/latest`,{timeout:Os},s=>{if(s.statusCode!==200)return s.resume(),e(new Error(`HTTP ${s.statusCode}`));let r="";s.setEncoding("utf8"),s.on("data",o=>{r+=o;}),s.on("end",()=>{try{let o=JSON.parse(r);if(typeof o.version!="string")throw new Error("no version field");e(null,{version:o.version,updatePriority:typeof o.updatePriority=="string"?o.updatePriority:null});}catch(o){e(o);}});});n.on("error",e),n.on("timeout",()=>{n.destroy(new Error("timeout"));});}function ft(e){let t=F().name,s=` Update available: ${F().version} \u2192 ${e}`,r=` Run: npm install -g ${t}`,o=Math.max(s.length,r.length)+2,i="\u2500".repeat(o);process.stderr.write(`
|
|
3
3
|
\u256D${i}\u256E
|
|
4
|
-
\u2502${s.padEnd(
|
|
5
|
-
\u2502${
|
|
4
|
+
\u2502${s.padEnd(o)}\u2502
|
|
5
|
+
\u2502${r.padEnd(o)}\u2502
|
|
6
6
|
\u2570${i}\u256F
|
|
7
7
|
|
|
8
|
-
`);}function
|
|
8
|
+
`);}function ht(e){let t=F().name;process.stderr.write(`
|
|
9
9
|
[${t}] Critical update detected \u2014 auto-updating to ${e}...
|
|
10
10
|
|
|
11
|
-
`),
|
|
12
|
-
`,"utf8");}finally{
|
|
11
|
+
`),ys("npm",["install","-g",`${t}@${e}`],{detached:true,stdio:"ignore",windowsHide:true}).unref();}function Cs(){try{let e=Ls();if(e){ve(F().version,e.latestVersion)&&(e.updatePriority==="auto"?ht(e.latestVersion):ft(e.latestVersion));return}setImmediate(()=>{Is((t,n)=>{t||!n||(Ns(n.version,n.updatePriority),ve(F().version,n.version)&&(n.updatePriority==="auto"?ht(n.version):ft(n.version)));});});}catch{}}Et.exports={checkForUpdate:Cs,isNewer:ve};});var w=p((ka,_t)=>{var x=process.env.FLOW_BASE_URL||"https://flow.ciandt.com",wt={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`},ks={SERVICE:"flow-plugins-cli",ACCOUNT_CREDS:"credentials",ACCOUNT_TOKEN:"token-cache"},Us="FLOW-nodejs",vs="config.json",Rs={SCOPE_NAME:"flow-ai-obs",SCOPE_VERSION:"0.1.0"},bs={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"},Ps={CLAUDE_CODE_ENABLE_TELEMETRY:"1",OTEL_EXPORTER_OTLP_ENDPOINT:wt.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"},$s={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"},qs={KEYCHAIN_ENABLED:false},Fs={LOCK_STALE_MS:3e4,CONNECTIVITY_MAX_RETRY:3,CONNECTIVITY_RETRY_MS:2e3},xs={UserPromptSubmit:5,PreToolUse:3,PostToolUse:10,Stop:15},Ms={FILE_PREFIX:"flow-obs-buffer-",MAX_AGE_MS:5760*60*1e3,MAX_FILES:50},Ds="flow-ai-obs-debug.log",Bs={TOOL_INPUT:2e4,TOOL_OUTPUT:2e4,TRACE_OUTPUT:2e4,USER_INSTRUCTION:1e4,TRACE_INPUT:5e4,TOOL_BRIEF:60},Hs="flow-obs-";_t.exports={FLOW_BASE_URL:x,FLOW_URLS:wt,VAULT:ks,CONFIG_DIR_NAME:Us,CONFIG_FILE_NAME:vs,OTLP:Rs,LLM_PROXY:bs,NATIVE_OTEL:Ps,ENV:$s,FEATURES:qs,INSTALLER:Fs,HOOK_TIMEOUTS:xs,BUFFER:Ms,DEBUG_LOG_FILENAME:Ds,STATE_FILE_PREFIX:Hs,TRACE_LIMITS:Bs};});var X=p((Ua,mt)=>{var js=c("https"),Gs=c("http"),{FLOW_URLS:Ys}=w(),Ks=/^[a-z0-9][a-z0-9-]{0,62}[a-z0-9]$|^[a-z0-9]$/;function Vs(e){if(!Ks.test(e))throw new Error(`Invalid tenant value: "${e}". Tenant must be lowercase alphanumeric and hyphens (1-64 chars).`)}var gt={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 Ws(e,t){try{let n=JSON.parse(t);if(typeof n.error=="string"&>[n.error])return new Error(gt[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 Js(e){return new Promise((t,n)=>{try{Vs(e.tenant);}catch(d){return n(d)}let s=JSON.stringify({clientSecret:e.clientSecret}),r=new URL(Ys.AUTH_ENGINE),o=r.protocol==="https:",i={hostname:r.hostname,port:r.port||(o?443:80),path:r.pathname+r.search,method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(s),FlowTenant:e.tenant}},u=(o?js:Gs).request(i,d=>{let l=[];d.on("data",h=>l.push(h)),d.on("end",()=>{let h=l.join("");if(d.statusCode>=400)return n(Ws(d.statusCode,h));let S;try{S=JSON.parse(h);}catch{return n(new Error("Invalid response from auth engine"))}let A=S.expires_at??new Date(Date.now()+(S.expires_in??3600)*1e3).toISOString();t({accessToken:S.access_token,expiresAt:A});});});u.on("error",d=>n(new Error(`Network error: ${d.message}`))),u.write(s),u.end();})}mt.exports={getToken:Js};});var we=p((va,Lt)=>{var g=c("fs"),Z=c("path"),yt=c("os"),{FLOW_URLS:Xs,INSTALLER:z,HOOK_TIMEOUTS:Ee,NATIVE_OTEL:zs,LLM_PROXY:Zs}=w(),{getToken:Qs}=X();function Pe(){return process.platform==="win32"?Z.join(process.env.APPDATA||Z.join(yt.homedir(),"AppData","Roaming"),"Claude","settings.json"):Z.join(yt.homedir(),".claude","settings.json")}var er=z.LOCK_STALE_MS;function At(e){try{let t=g.statSync(e);Date.now()-t.mtimeMs>er&&g.unlinkSync(e);}catch{}try{g.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{g.unlinkSync(e);}catch{}}function tr(){let e=Pe(),t=e+".lock";g.mkdirSync(Z.dirname(e),{recursive:true}),At(t);try{g.existsSync(e)&&g.copyFileSync(e,e+".bkp");let n={};try{n=JSON.parse(g.readFileSync(e,"utf8"));}catch{}(!n.env||typeof n.env!="object")&&(n.env={}),Object.assign(n.env,zs),Object.assign(n.env,Zs),n.otelHeadersHelper="flow-ai-obs otel-headers",(!n.hooks||typeof n.hooks!="object")&&(n.hooks={});let s=(r,o)=>({matcher:"",hooks:[{type:"command",command:`flow-ai-obs ${r}`,timeout:o}]});n.hooks.UserPromptSubmit=[s("UserPromptSubmit",Ee.UserPromptSubmit)],n.hooks.PreToolUse=[s("PreToolUse",Ee.PreToolUse)],n.hooks.PostToolUse=[s("PostToolUse",Ee.PostToolUse)],n.hooks.Stop=[s("Stop",Ee.Stop)],g.writeFileSync(e,JSON.stringify(n,null,2)+`
|
|
12
|
+
`,"utf8");}finally{Ot(t);}return e}async function nr(e){let t;try{t=(await Qs(e)).accessToken;}catch{return false}return t?new Promise(n=>{be(`Bearer ${t}`,n,1);}):false}function be(e,t,n){let s=new URL(Xs.GATEWAY_TRACES),r=JSON.stringify({resourceSpans:[],validation_run:true}),o=s.protocol==="https:",i={hostname:s.hostname,port:s.port||(o?443:80),path:s.pathname,method:"POST",headers:{"Content-Type":"application/json",Authorization:e,"Content-Length":Buffer.byteLength(r)}},u=(o?c("https"):c("http")).request(i,d=>{d.resume(),d.statusCode===200||d.statusCode===204?t(true):n<z.CONNECTIVITY_MAX_RETRY?setTimeout(()=>be(e,t,n+1),z.CONNECTIVITY_RETRY_MS):t(false);});u.on("error",()=>{n<z.CONNECTIVITY_MAX_RETRY?setTimeout(()=>be(e,t,n+1),z.CONNECTIVITY_RETRY_MS):t(false);}),u.write(r),u.end();}function sr(e){let t=Pe(),n=t+".lock";g.mkdirSync(Z.dirname(t),{recursive:true}),At(n);try{let s={};try{s=JSON.parse(g.readFileSync(t,"utf8"));}catch{}(!s.env||typeof s.env!="object")&&(s.env={}),Object.assign(s.env,e),g.writeFileSync(t,JSON.stringify(s,null,2)+`
|
|
13
|
+
`,"utf8");}finally{Ot(n);}}Lt.exports={getClaudeSettingsPath:Pe,writeClaudeSettings:tr,addEnvToClaudeSettings:sr,validateConnectivity:nr};});var Ct=p((Ra,It)=>{var ee=c("fs"),M=c("path"),rr=c("os"),{CONFIG_DIR_NAME:$e,CONFIG_FILE_NAME:qe}=w(),Fe={credentials:"credentials","token-cache":"tokenCache"};function Q(){let e=rr.homedir();if(process.platform==="darwin")return M.join(e,"Library","Preferences",$e,qe);if(process.platform==="win32"){let n=process.env.APPDATA||M.join(e,"AppData","Roaming");return M.join(n,$e,qe)}let t=process.env.XDG_CONFIG_HOME||M.join(e,".config");return M.join(t,$e,qe)}function xe(){try{let e=ee.readFileSync(Q(),"utf8");return JSON.parse(e)}catch{return {}}}function Nt(e){let t=Q();ee.mkdirSync(M.dirname(t),{recursive:true}),ee.writeFileSync(t,JSON.stringify(e,null,2),{encoding:"utf8",mode:384});}var Me=class{static isAvailable(){return true}static hasExistingData(){try{if(!ee.existsSync(Q()))return !1;let t=JSON.parse(ee.readFileSync(Q(),"utf8"));return !!(t&&t.credentials)}catch{return false}}async getSecret(t,n){let s=xe(),r=Fe[n]||n,o=s[r];return o?typeof o=="string"?o:JSON.stringify(o):null}async setSecret(t,n,s){let r=xe(),o=Fe[n]||n;if(n==="token-cache")try{r[o]=JSON.parse(s);}catch{r[o]=s;}else r[o]=s;Nt(r);}async deleteSecret(t,n){let s=xe(),r=Fe[n]||n;return r in s?(delete s[r],Nt(s),true):false}getStoragePath(){return `config.json (unencrypted) \u2014 ${Q()}`}};function or(){}It.exports={ScryptFallbackProvider:Me,_resetWarningState:or};});var Ut=p((ba,kt)=>{var{VAULT:te}=w();async function ir(e,t){let n=[te.ACCOUNT_CREDS,te.ACCOUNT_TOKEN];for(let s of n)try{if(await t.getSecret(te.SERVICE,s)!==null)continue;let o=await e.getSecret(te.SERVICE,s);o!==null&&await t.setSecret(te.SERVICE,s,o);}catch{}}kt.exports={migrateFromJsonFallback:ir};});var bt=p((Pa,Rt)=>{var{execFile:ar,exec:cr}=c("child_process"),{promisify:vt}=c("util"),De=vt(ar),ur=vt(cr),Be=class{static async isAvailable(){try{return await ur("command -v security"),!0}catch{return false}}async getSecret(t,n){try{let{stdout:s}=await De("security",["find-generic-password","-w","-a",n,"-s",t]);return s.trim()||null}catch{return null}}async setSecret(t,n,s){await De("security",["add-generic-password","-U","-a",n,"-s",t,"-w",s]);}async deleteSecret(t,n){try{return await De("security",["delete-generic-password","-a",n,"-s",t]),!0}catch{return false}}getStoragePath(){return "macOS Keychain"}};Rt.exports={MacOsKeyVaultProvider:Be};});var Ft=p(($a,qt)=>{var{execFile:lr,exec:dr,spawn:pr}=c("child_process"),{promisify:$t}=c("util"),Pt=$t(lr),fr=$t(dr),He=class{static async isAvailable(){try{return await fr("command -v secret-tool"),!0}catch{return false}}async getSecret(t,n){try{let{stdout:s}=await Pt("secret-tool",["lookup","service",t,"account",n]);return s.trim()||null}catch{return null}}async setSecret(t,n,s){await new Promise((r,o)=>{let i=pr("secret-tool",["store","--label",t,"service",t,"account",n]);i.on("error",o),i.on("close",a=>{a===0?r():o(new Error(`secret-tool exited with code ${a}`));}),i.stdin.write(s),i.stdin.end();});}async deleteSecret(t,n){try{return await Pt("secret-tool",["clear","service",t,"account",n]),!0}catch{return false}}getStoragePath(){return "Linux Secret Service (libsecret)"}};qt.exports={LinuxKeyVaultProvider:He};});var Mt=p((qa,xt)=>{var je=class{static async isAvailable(){try{return await c("keytar").getPassword("__flow_probe__","__flow_probe__"),!0}catch{return false}}async getSecret(t,n){return c("keytar").getPassword(t,n)}async setSecret(t,n,s){await c("keytar").setPassword(t,n,s);}async deleteSecret(t,n){return c("keytar").deletePassword(t,n)}getStoragePath(){return "Windows Credential Manager"}};xt.exports={WindowsKeyVaultProvider:je};});var jt=p((Fa,Ht)=>{async function Bt(){let{ScryptFallbackProvider:e}=Ct();if(e.hasExistingData()){let t=await Dt();if(t){let{migrateFromJsonFallback:n}=Ut(),{VAULT:s}=w();if(await n(new e,t),await t.getSecret(s.SERVICE,s.ACCOUNT_CREDS)!==null)return t}return new e}return await Dt()??new e}async function Dt(){switch(process.platform){case "darwin":{let{MacOsKeyVaultProvider:e}=bt();return await e.isAvailable()?new e:null}case "linux":{let{LinuxKeyVaultProvider:e}=Ft();return await e.isAvailable()?new e:null}case "win32":{let{WindowsKeyVaultProvider:e}=Mt();return await e.isAvailable()?new e:null}default:return null}}var hr=Bt;Ht.exports={createSecretVaultProvider:Bt,createKeyVaultProvider:hr};});var H=p((xa,Yt)=>{var{createSecretVaultProvider:Tr}=jt(),{VAULT:Ye}=w(),D=Ye.SERVICE,Ke=Ye.ACCOUNT_CREDS,Ve=Ye.ACCOUNT_TOKEN,Ge=null;function B(){return Ge||(Ge=Tr()),Ge}async function Gt(){let t=await(await B()).getSecret(D,Ke);if(!t)return null;try{return JSON.parse(t)}catch{return null}}async function Sr(e){if(!e.clientId||!e.clientSecret||!e.tenant)throw new Error("clientId, clientSecret and tenant are required");await(await B()).setSecret(D,Ke,JSON.stringify(e));}async function Er(){let e=await B();await e.deleteSecret(D,Ke),await e.deleteSecret(D,Ve);}async function wr(e){await(await B()).setSecret(D,Ve,JSON.stringify({accessToken:e.accessToken,expiresAt:e.expiresAt}));}async function We(){let t=await(await B()).getSecret(D,Ve);if(!t)return null;try{let n=JSON.parse(t);return {accessToken:n.accessToken,expiresAt:n.expiresAt}}catch{return null}}async function _r(){let e=await We();return e?new Date(e.expiresAt)>new Date:false}async function gr(){let e=await We();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 mr(){let e=await B();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 yr(){let e=await Gt();return !!(e&&e.clientId&&e.clientSecret&&e.tenant)}Yt.exports={getFlowCredentials:Gt,saveFlowCredentials:Sr,clearFlowCredentials:Er,saveTokenCache:wr,getTokenCache:We,isTokenValid:_r,getEmailFromToken:gr,getConfigPath:mr,hasCredentials:yr};});var k=p((Ma,Vt)=>{var{writeFileSync:Ar}=c("fs"),{tmpdir:Or}=c("os"),{join:Lr}=c("path"),{DEBUG_LOG_FILENAME:Nr,ENV:Ir}=w(),Kt=Lr(Or(),Nr);function Cr(...e){if(process.env[Ir.FLOW_OBS_DEBUG]!=="1")return;let t=`[${new Date().toISOString()}] ${e.join(" ")}
|
|
14
|
+
`;try{Ar(Kt,t,{flag:"a"});}catch(n){process.stderr.write(`[flow-obs debug ERROR] ${n.message}
|
|
15
|
+
`);}}Vt.exports={dbg:Cr,DEBUG_LOG:Kt};});var U=p((Da,Jt)=>{var{getFlowCredentials:Je,isTokenValid:kr,getEmailFromToken:ne,getTokenCache:Ur,saveTokenCache:vr}=H(),{getToken:Rr}=X(),{FLOW_BASE_URL:br,ENV:O,FEATURES:Xe}=w(),{dbg:j}=k(),Pr=[/^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 $r(e){return Pr.some(t=>t.test(e))}function _e(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:r,tenant:o}=n;return !s||!r||!o?null:{clientId:s,clientSecret:r,tenant:o}}catch{return null}}function qr(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 ze(e){let t;try{t=new URL(e);}catch{throw new Error(`Invalid URL: ${e}`)}if(!(process.env[O.FLOW_OBS_ALLOW_HTTP]==="true")&&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($r(t.hostname))throw new Error(`SSRF: private/loopback host not allowed: ${t.hostname}`);return e}async function Fr(){let e=_e(process.env[O.ANTHROPIC_AUTH_TOKEN]);if(e)return {user:await ne().catch(()=>null)||e.clientId,tenant:e.tenant};if(Xe.KEYCHAIN_ENABLED)try{let t=await Je();if(!t)return {user:"",tenant:""};let n=await ne()||t.clientId||"",s=t.tenant||"";return {user:n,tenant:s}}catch{return {user:"",tenant:""}}return {user:"",tenant:""}}async function xr(e){if(await kr())return (await Ur()).accessToken;j("getOrRefreshToken","token expired \u2014 refreshing via auth-engine");let t=await Rr(e);return await vr(t),j("getOrRefreshToken",`token refreshed, expires=${t.expiresAt}`),t.accessToken}function Mr(e,t){let n=t&&t.accessToken?t.accessToken:"";return {endpoint:e.replace(/\/$/,"")+"/langfuse/traces",authHeader:`Bearer ${n}`}}function Dr(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 Wt(){let e=[],t=process.env[O.ANTHROPIC_MODEL]||"",n=process.env[O.FLOW_TELEMETRY]==="true",s=process.env[O.LANGFUSE_BASE_URL],r=process.env[O.LANGFUSE_PUBLIC_KEY],o=process.env[O.LANGFUSE_SECRET_KEY];if(n&&s&&r&&o){let l="",h="",S=_e(process.env[O.ANTHROPIC_AUTH_TOKEN]);if(S)l=await ne().catch(()=>null)||S.clientId,h=S.tenant;else if(Xe.KEYCHAIN_ENABLED)try{let N=await Je();N&&(l=await ne()||N.clientId,h=N.tenant);}catch{}let A={user:l||"",tenant:h||"",team:"",project:"",model:t};e.push({mode:"direct",...Dr(ze(s),r,o),...A}),j("resolveCredentials","direct mode active",`user=${A.user}`,`tenant=${A.tenant}`);}let i=_e(process.env[O.ANTHROPIC_AUTH_TOKEN]);if(j("resolveCredentials",i?"credentials resolved from ANTHROPIC_AUTH_TOKEN":"ANTHROPIC_AUTH_TOKEN absent or invalid"),!i&&Xe.KEYCHAIN_ENABLED&&(i=await Je(),i&&j("resolveCredentials","credentials resolved from keychain (FEATURES.KEYCHAIN_ENABLED=true)")),!i){if(e.length===0){let l=[];return l.authError=false,l}return e}let a;try{a=await xr(i);}catch(l){if(j("resolveCredentials",`token refresh failed: ${l.message}`),e.length>0)return e;let h=[];return h.authError=true,h}let u={user:await ne()||i.clientId,tenant:i.tenant,team:"",project:"",model:t},d=process.env[O.FLOW_TELEMETRY_GATEWAY]||br;return e.push({mode:"gateway",...Mr(ze(d),{accessToken:a}),...u}),e}async function Br(){return (await Wt()).length>0}Jt.exports={credentialsAvailable:Br,getIdentityFromToken:Fr,resolveCredentials:Wt,validateUrl:ze,parseCredsFromAnthropicToken:_e,buildAnthropicAuthToken:qr};});var ye=p((Ba,nn)=>{var{getFlowCredentials:Ze,saveFlowCredentials:Xt,clearFlowCredentials:Hr,saveTokenCache:jr,isTokenValid:Gr,getConfigPath:zt,hasCredentials:Yr}=H(),{getToken:Kr}=X(),{buildAnthropicAuthToken:Vr,parseCredsFromAnthropicToken:Zt}=U(),{addEnvToClaudeSettings:Wr}=we(),{ENV:Qe}=w(),{green:me,red:se,yellow:ge,cyan:re,bold:Qt,dim:G}=J(),Jr=/[\x00-\x08\x0B-\x1F\x7F]|\x1b\[[0-9;]*[a-zA-Z]/g;function v(e){return typeof e=="string"?e.replace(Jr,""):e}function oe(e,t={}){return new Promise((n,s)=>{let{masked:r=false,defaultValue:o=""}=t;process.stdout.write(e+o);let i=o;function a(){try{process.stdin.setRawMode(!1);}catch{}}process.once("uncaughtException",a),process.once("unhandledRejection",a);let u=l=>{if(l===""){d(),s(new Error("SIGINT"));return}if(l==="\r"||l===`
|
|
16
|
+
`){d(),process.stdout.write(`
|
|
17
|
+
`),n(i);return}if(l==="\x7F"){i.length>0&&(i=i.slice(0,-1),process.stdout.write("\b \b"));return}l.startsWith("\x1B")||(i+=l,process.stdout.write(r?"*".repeat(l.length):l));};function d(){process.stdin.setRawMode(false),process.stdin.removeListener("data",u),process.removeListener("uncaughtException",a),process.removeListener("unhandledRejection",a);}process.stdin.setRawMode(true),process.stdin.resume(),process.stdin.setEncoding("utf8"),process.stdin.on("data",u);})}async function en(e){try{let t=await Ze();(!t||t.clientId!==e.clientId||t.clientSecret!==e.clientSecret||t.tenant!==e.tenant)&&await Xt(e);}catch{}}async function tn(e){let{accessToken:t,expiresAt:n}=await Kr(e);await Xt(e),await jr({accessToken:t,expiresAt:n});try{let s=Vr(e);Wr({[Qe.ANTHROPIC_AUTH_TOKEN]:s});}catch{}}async function Xr(e){try{return await tn(e),process.stdout.write(me(` \u2713 Setup complete. Tenant: ${v(e.tenant)}
|
|
18
|
+
|
|
19
|
+
`)),0}catch(t){return process.stderr.write(se(` \u2717 Authentication failed: ${v(t.message)}
|
|
20
|
+
`)),1}}async function zr(){try{process.stdout.write(`
|
|
21
|
+
`);let e=(await oe(re(" ? ")+"Client ID: ")).trim(),t=(await oe(re(" ? ")+"Client Secret: ",{masked:!0})).trim(),n=(await oe(re(" ? ")+"Tenant: ")).trim();if(!e||!t||!n)return process.stderr.write(se(` \u2717 All fields are required
|
|
22
|
+
`)),1;try{await tn({clientId:e,clientSecret:t,tenant:n});}catch(s){return process.stderr.write(se(` \u2717 Authentication failed: ${v(s.message)}
|
|
23
|
+
`)),1}return process.stdout.write(me(` \u2713 Setup complete. Tenant: ${v(n)}
|
|
24
|
+
`)),process.stdout.write(` Storage: ${await zt()}
|
|
25
|
+
|
|
26
|
+
`),0}catch(e){if(e.message==="SIGINT")throw e;return process.stderr.write(se(` \u2717 Unexpected error: ${e.message}
|
|
27
|
+
`)),1}}async function Zr(e={}){if(e.clientId&&e.clientSecret&&e.tenant)return Xr({clientId:e.clientId,clientSecret:e.clientSecret,tenant:e.tenant});let t=Zt(process.env[Qe.ANTHROPIC_AUTH_TOKEN]);t&&await en(t);let n=t||await Ze();if(n){process.stdout.write(`
|
|
28
|
+
`),process.stdout.write(Qt(` Already authenticated
|
|
29
|
+
`)),process.stdout.write(G(" Tenant: ")+v(n.tenant)+`
|
|
30
|
+
`),process.stdout.write(G(" Client ID: ")+v(n.clientId)+`
|
|
31
|
+
`),process.stdout.write(`
|
|
32
|
+
`);let s;try{s=await oe(re(" ? ")+"Re-authenticate? (y/N): ");}catch(r){if(r.message==="SIGINT")return process.stdout.write(`
|
|
33
|
+
`),130;throw r}if(s.trim().toLowerCase()!=="y")return process.stdout.write(me(` \u2713 Using existing credentials.
|
|
34
|
+
|
|
35
|
+
`)),0}try{return await zr()}catch(s){if(s.message==="SIGINT")return process.stdout.write(`
|
|
36
|
+
`),130;throw s}}async function Qr(){try{return process.stdout.write(`
|
|
37
|
+
`),(await oe(re(" ? ")+"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 eo(e=false){if(!await Yr())return process.stdout.write(ge(` \u26A0 You are not authenticated
|
|
40
|
+
`)),0;if(!e){let t=await Qr();if(t!==null)return t}try{return await Hr(),process.stdout.write(me(` \u2713 Credentials removed successfully
|
|
41
|
+
`)),0}catch{return process.stderr.write(se(` \u2717 Error removing credentials
|
|
42
|
+
`)),1}}async function to(){let e=Zt(process.env[Qe.ANTHROPIC_AUTH_TOKEN]);e&&await en(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 Gr())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 zt();return process.stdout.write(`
|
|
43
|
+
`+Qt(` Authenticated
|
|
44
|
+
`)),process.stdout.write(G(" Tenant: ")+v(t.tenant)+`
|
|
45
|
+
`),process.stdout.write(G(" Client ID: ")+v(t.clientId)+`
|
|
46
|
+
`),process.stdout.write(G(" Client Secret: ")+n+`
|
|
47
|
+
`),process.stdout.write(G(" Storage: ")+s+`
|
|
48
|
+
|
|
49
|
+
`),0}nn.exports={runLogin:Zr,runLogout:eo,runStatus:to};});var on=p((Ha,rn)=>{var{spawnSync:no}=c("child_process"),{writeClaudeSettings:so}=we(),{NATIVE_OTEL:ro,LLM_PROXY:oo,ENV:io}=w(),{green:ao,red:co,yellow:uo,bold:et,dim:L,cyan:lo}=J(),{runLogin:po}=ye(),{parseCredsFromAnthropicToken:fo}=U(),{getFlowCredentials:ho}=H(),sn={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 To(){let e=process.platform==="win32"?"where":"which";return no(e,["claude"],{encoding:"utf8",timeout:5e3}).status===0}async function So(){if(!To()){let s=process.platform,r=sn[s]||sn.linux;return process.stderr.write(`
|
|
52
|
+
`+co(` \u2717 Claude Code is not installed or not found in PATH.
|
|
53
|
+
|
|
54
|
+
`)+` flow-ai-obs requires Claude Code to function.
|
|
55
|
+
Install it with:
|
|
56
|
+
|
|
57
|
+
`+lo(` ${r}`)+`
|
|
58
|
+
|
|
59
|
+
`),1}let e=!!fo(process.env[io.ANTHROPIC_AUTH_TOKEN]),t=!e&&!!await ho();if(!e&&!t){process.stdout.write(uo(` \u26A0 No credentials found \u2014 authentication required.
|
|
60
|
+
|
|
61
|
+
`));let s=await po();if(s!==0)return s}let n;try{n=so();}catch(s){return process.stderr.write(` \u2717 Failed to write settings: ${s.message}
|
|
13
62
|
`),1}process.stdout.write(`
|
|
14
|
-
`+
|
|
15
|
-
`);for(let[
|
|
63
|
+
`+et(" Flow LLM Proxy configured")+` (model provider)
|
|
64
|
+
`);for(let[s,r]of Object.entries(oo))process.stdout.write(L(` ${s.padEnd(36)}`)+r+`
|
|
65
|
+
`);process.stdout.write(`
|
|
66
|
+
`),process.stdout.write(et(" Native OTEL configured")+` (metrics & logs)
|
|
67
|
+
`);for(let[s,r]of Object.entries(ro))process.stdout.write(L(` ${s.padEnd(36)}`)+r+`
|
|
16
68
|
`);return process.stdout.write(`
|
|
17
|
-
`),process.stdout.write(
|
|
18
|
-
`),process.stdout.write(
|
|
19
|
-
`),process.stdout.write(
|
|
20
|
-
`),process.stdout.write(
|
|
21
|
-
`),process.stdout.write(
|
|
69
|
+
`),process.stdout.write(et(" Hooks registered")+` (Langfuse trace capture)
|
|
70
|
+
`),process.stdout.write(L(" UserPromptSubmit")+` \u2192 flow-ai-obs UserPromptSubmit (timeout: 5s)
|
|
71
|
+
`),process.stdout.write(L(" PreToolUse ")+` \u2192 flow-ai-obs PreToolUse (timeout: 3s)
|
|
72
|
+
`),process.stdout.write(L(" PostToolUse ")+` \u2192 flow-ai-obs PostToolUse (timeout: 10s)
|
|
73
|
+
`),process.stdout.write(L(" Stop ")+` \u2192 flow-ai-obs Stop (timeout: 15s)
|
|
22
74
|
`),process.stdout.write(`
|
|
23
|
-
`),process.stdout.write(
|
|
24
|
-
`),process.stdout.write(
|
|
25
|
-
`),process.stdout.write(
|
|
75
|
+
`),process.stdout.write(L(" Settings: ")+n+`
|
|
76
|
+
`),process.stdout.write(L(" Backup: ")+n+`.bkp
|
|
77
|
+
`),process.stdout.write(L(" OTEL auth: flow-ai-obs otel-headers")+L(` (reads keychain at runtime)
|
|
26
78
|
`)),process.stdout.write(`
|
|
27
|
-
`),
|
|
28
|
-
|
|
29
|
-
`)):process.stdout.write(fr(` \u26A0 Not authenticated \u2014 hooks registered, but trace forwarding is inactive.
|
|
30
|
-
`)+" Run "+hr("flow-ai-obs auth login")+` to activate Langfuse tracing.
|
|
31
|
-
|
|
32
|
-
`),0}Mt.exports={runInstall:Sr};});var Ht=d((Ta,Wt)=>{var{getFlowCredentials:Dt,saveFlowCredentials:Er,clearFlowCredentials:Tr,saveTokenCache:wr,isTokenValid:gr,getConfigPath:Gt,hasCredentials:jt}=x(),{getToken:_r}=K(),{green:Te,red:Q,yellow:Ee,cyan:ee,bold:Vt,dim:M}=W(),mr=/[\x00-\x08\x0B-\x1F\x7F]|\x1b\[[0-9;]*[a-zA-Z]/g;function k(e){return typeof e=="string"?e.replace(mr,""):e}function te(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 p=u=>{if(u===""){l(),s(new Error("SIGINT"));return}if(u==="\r"||u===`
|
|
33
|
-
`){l(),process.stdout.write(`
|
|
34
|
-
`),n(i);return}if(u==="\x7F"){i.length>0&&(i=i.slice(0,-1),process.stdout.write("\b \b"));return}u.startsWith("\x1B")||(i+=u,process.stdout.write(o?"*".repeat(u.length):u));};function l(){process.stdin.setRawMode(false),process.stdin.removeListener("data",p),process.removeListener("uncaughtException",a),process.removeListener("unhandledRejection",a);}process.stdin.setRawMode(true),process.stdin.resume(),process.stdin.setEncoding("utf8"),process.stdin.on("data",p);})}async function Yt(e){let{accessToken:t,expiresAt:n}=await _r(e);await Er(e),await wr({accessToken:t,expiresAt:n});}async function yr(e){try{return await Yt(e),process.stdout.write(Te(` \u2713 Setup complete. Tenant: ${k(e.tenant)}
|
|
35
|
-
|
|
36
|
-
`)),0}catch(t){return process.stderr.write(Q(` \u2717 Authentication failed: ${k(t.message)}
|
|
37
|
-
`)),1}}async function Or(){try{process.stdout.write(`
|
|
38
|
-
`);let e=(await te(ee(" ? ")+"Client ID: ")).trim(),t=(await te(ee(" ? ")+"Client Secret: ",{masked:!0})).trim(),n=(await te(ee(" ? ")+"Tenant: ")).trim();if(!e||!t||!n)return process.stderr.write(Q(` \u2717 All fields are required
|
|
39
|
-
`)),1;try{await Yt({clientId:e,clientSecret:t,tenant:n});}catch(s){return process.stderr.write(Q(` \u2717 Authentication failed: ${k(s.message)}
|
|
40
|
-
`)),1}return process.stdout.write(Te(` \u2713 Setup complete. Tenant: ${k(n)}
|
|
41
|
-
`)),process.stdout.write(` Storage: ${await Gt()}
|
|
42
|
-
|
|
43
|
-
`),0}catch(e){if(e.message==="SIGINT")throw e;return process.stderr.write(Q(` \u2717 Unexpected error: ${e.message}
|
|
44
|
-
`)),1}}async function Lr(e={}){if(e.clientId&&e.clientSecret&&e.tenant)return yr({clientId:e.clientId,clientSecret:e.clientSecret,tenant:e.tenant});if(await jt()){let t=await Dt();process.stdout.write(`
|
|
45
|
-
`),process.stdout.write(Vt(` Already authenticated
|
|
46
|
-
`)),process.stdout.write(M(" Tenant: ")+k(t.tenant)+`
|
|
47
|
-
`),process.stdout.write(M(" Client ID: ")+k(t.clientId)+`
|
|
48
|
-
`),process.stdout.write(`
|
|
49
|
-
`);let n;try{n=await te(ee(" ? ")+"Re-authenticate? (y/N): ");}catch(s){if(s.message==="SIGINT")return process.stdout.write(`
|
|
50
|
-
`),130;throw s}if(n.trim().toLowerCase()!=="y")return process.stdout.write(Te(` \u2713 Using existing credentials.
|
|
79
|
+
`),process.stdout.write(ao(` \u2713 Ready. Native OTEL + Langfuse trace capture active.
|
|
51
80
|
|
|
52
|
-
`)),0}
|
|
53
|
-
`),130;throw t}}async function Ar(){try{return process.stdout.write(`
|
|
54
|
-
`),(await te(ee(" ? ")+"Are you sure? This will remove your local credentials. (y/N): ")).toLowerCase()!=="y"?(process.stdout.write(Ee(` \u26A0 Logout cancelled
|
|
55
|
-
`)),0):null}catch(e){if(e.message==="SIGINT")return process.stdout.write(`
|
|
56
|
-
`),130;throw e}}async function Ir(e=false){if(!await jt())return process.stdout.write(Ee(` \u26A0 You are not authenticated
|
|
57
|
-
`)),0;if(!e){let t=await Ar();if(t!==null)return t}try{return await Tr(),process.stdout.write(Te(` \u2713 Credentials removed successfully
|
|
58
|
-
`)),0}catch{return process.stderr.write(Q(` \u2717 Error removing credentials
|
|
59
|
-
`)),1}}async function kr(){let e=await Dt();if(!e)return process.stdout.write(Ee(" \u26A0 Not authenticated. Run `flow-ai-obs auth login` to set up.\n")),0;if(!await gr())return process.stdout.write(Ee(" \u26A0 Session expired. Run `flow-ai-obs auth login` to re-authenticate.\n")),0;let t=e.clientSecret.length>4?"****...****"+e.clientSecret.slice(-4):"****";return process.stdout.write(`
|
|
60
|
-
`+Vt(` Authenticated
|
|
61
|
-
`)),process.stdout.write(M(" Tenant: ")+k(e.tenant)+`
|
|
62
|
-
`),process.stdout.write(M(" Client ID: ")+k(e.clientId)+`
|
|
63
|
-
`),process.stdout.write(M(" Client Secret: ")+t+`
|
|
64
|
-
`),process.stdout.write(M(" Storage: ")+await Gt()+`
|
|
65
|
-
|
|
66
|
-
`),0}Wt.exports={runLogin:Lr,runLogout:Ir,runStatus:kr};});var Jt=d((wa,Kt)=>{var{getFlowCredentials:Nr}=x(),{getToken:Cr}=K();async function br(){let e;try{e=await Nr();}catch{return process.stderr.write(`[flow-ai-obs otel-headers] Failed to read credentials
|
|
81
|
+
`)),0}rn.exports={runInstall:So};});var cn=p((ja,an)=>{var{getFlowCredentials:Eo}=H(),{getToken:wo}=X();async function _o(){let e;try{e=await Eo();}catch{return process.stderr.write(`[flow-ai-obs otel-headers] Failed to read credentials
|
|
67
82
|
`),1}if(!e)return process.stderr.write(`[flow-ai-obs otel-headers] Not authenticated \u2014 run: flow-ai-obs auth login
|
|
68
|
-
`),1;let t;try{t=(await
|
|
83
|
+
`),1;let t;try{t=(await wo(e)).accessToken;}catch(n){return process.stderr.write(`[flow-ai-obs otel-headers] Token fetch failed: ${n.message}
|
|
69
84
|
`),1}return t?(process.stdout.write(`{"Authorization": "Bearer ${t}"}
|
|
70
85
|
`),0):(process.stderr.write(`[flow-ai-obs otel-headers] Empty token received
|
|
71
|
-
`),1)}
|
|
72
|
-
|
|
73
|
-
`);}
|
|
74
|
-
`);}function
|
|
75
|
-
`);}function
|
|
76
|
-
`);}function
|
|
77
|
-
`)
|
|
78
|
-
`);
|
|
79
|
-
`),
|
|
80
|
-
`);
|
|
81
|
-
`);let
|
|
82
|
-
`),process.env[
|
|
83
|
-
`),
|
|
84
|
-
`)[0].slice(0,t).trim()}function
|
|
85
|
-
`);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
|
|
86
|
-
`),n=[],s=0,
|
|
87
|
-
|
|
88
|
-
`),inputTokens:s,outputTokens:
|
|
86
|
+
`),1)}an.exports={runOtelHeaders:_o};});var fn=p((Ga,pn)=>{var{getFlowCredentials:un,isTokenValid:go,getEmailFromToken:mo,getTokenCache:yo}=H(),{resolveCredentials:Ao,parseCredsFromAnthropicToken:ln}=U(),{getClaudeSettingsPath:Oo}=we(),{ENV:R,NATIVE_OTEL:Lo}=w(),{runLogin:dn}=ye(),No=c("fs");function tt(e){return !e||e.length<=8?"****":e.slice(0,4)+"****...****"+e.slice(-4)}function ie(e){process.stdout.write(` \u2713 ${e}
|
|
87
|
+
`);}function Ae(e){process.stdout.write(` \u26A0 ${e}
|
|
88
|
+
`);}function Oe(e){process.stdout.write(` \u2717 ${e}
|
|
89
|
+
`);}function m(e){process.stdout.write(` ${e}
|
|
90
|
+
`);}function y(){process.stdout.write(`
|
|
91
|
+
`);}async function Io(){y(),process.stdout.write(` flow-claude-observability \u2014 configuration check
|
|
92
|
+
`),y(),process.stdout.write(` Auth
|
|
93
|
+
`);let e=ln(process.env[R.ANTHROPIC_AUTH_TOKEN]),t=e||await un();if(!t){Ae("Not authenticated \u2014 starting setup..."),y();let a=await dn();if(a!==0)return a;if(e=ln(process.env[R.ANTHROPIC_AUTH_TOKEN]),t=e||await un(),!t)return Oe("Authentication failed"),y(),1;y(),process.stdout.write(` Auth
|
|
94
|
+
`);}if(!e&&!await go()){Ae("Session expired \u2014 re-authenticating..."),y();let a=await dn();if(a!==0)return a;y(),process.stdout.write(` Auth
|
|
95
|
+
`);}let n=await mo()||t.clientId;ie("Authenticated"),m(`Tenant: ${t.tenant}`),m(`User: ${n}`),y(),process.stdout.write(` Native OTEL
|
|
96
|
+
`);let s={};try{let a=No.readFileSync(Oo(),"utf8");s=JSON.parse(a).env||{};}catch{}let r=Object.keys(Lo).filter(a=>!s[a]);if(r.length===0?(ie("All OTEL env vars present in settings.json"),m(`Endpoint: ${s.OTEL_EXPORTER_OTLP_ENDPOINT}`)):(Ae(`${r.length} OTEL var(s) missing from settings.json \u2014 native metrics/logs disabled`),r.forEach(a=>Oe(`Missing: ${a}`)),m("Run: flow-ai-obs install (restores missing vars automatically)")),y(),process.stdout.write(` Tracing
|
|
97
|
+
`),process.env[R.FLOW_TELEMETRY]==="true"){ie("FLOW_TELEMETRY=true (direct mode enabled)");let a=[R.LANGFUSE_BASE_URL,R.LANGFUSE_PUBLIC_KEY,R.LANGFUSE_SECRET_KEY].filter(u=>!process.env[u]);a.length>0&&a.forEach(u=>Ae(`Missing: ${u}`));}else m("FLOW_TELEMETRY not set \u2014 direct mode inactive (gateway mode may still be active)");let i=await Ao();if(!i||i.length===0)return i&&i.authError?Oe("Token refresh failed \u2014 gateway mode could not activate"):(Oe("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")),y(),1;for(let a of i)if(a.mode==="gateway"){let u=await yo();ie("Mode: gateway"),m(`Endpoint: ${a.endpoint}`),m(`Token: ${tt(u&&u.accessToken)}`);}else a.mode==="direct"&&(ie("Mode: direct"),m(`Endpoint: ${a.endpoint}`),m(`PK: ${tt(process.env[R.LANGFUSE_PUBLIC_KEY])}`),m(`SK: ${tt(process.env[R.LANGFUSE_SECRET_KEY])}`));return y(),process.stdout.write(` All checks passed \u2014 observability is active.
|
|
98
|
+
`),y(),0}pn.exports={runCheck:Io};});var Y=p((Ya,hn)=>{function Co(e,t){let n=typeof e=="object"?JSON.stringify(e):String(e??"");return n.length>t?n.slice(0,t)+" \u2026[truncated]":n}function ko(e,t=100){return String(e??"").split(`
|
|
99
|
+
`)[0].slice(0,t).trim()}function Uo(){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 vo(e){process.stdout.write(JSON.stringify(e));}hn.exports={truncate:Co,firstLine:ko,readInput:Uo,passthrough:vo};});var ae=p((Ka,Sn)=>{var{randomBytes:Tn}=c("crypto"),Ro=()=>Tn(16).toString("hex"),bo=()=>Tn(8).toString("hex");function Po(){return String(BigInt(Date.now())*1000000n)}Sn.exports={generateTraceId:Ro,generateSpanId:bo,nowNs:Po};});var ce=p((Wa,wn)=>{var{readFileSync:$o,writeFileSync:qo,unlinkSync:Fo,existsSync:xo,realpathSync:Va}=c("fs"),{tmpdir:En}=c("os"),{join:Mo,resolve:Do,normalize:Bo,sep:Ho}=c("path"),jo=/^[0-9a-f-]{1,64}$/i,Go=Bo(En())+Ho;function Yo(e,t){let n=Do(e);if(!n.startsWith(t))throw new Error(`Path traversal detected: ${e}`);return n}function nt(e){if(!jo.test(e))throw new Error(`Invalid session ID: ${e}`);return Yo(Mo(En(),`flow-obs-${e}.json`),Go)}function Ko(e){let t=nt(e);if(!xo(t))return null;try{return JSON.parse($o(t,"utf8"))}catch{return null}}function Vo(e,t){qo(nt(e),JSON.stringify(t),"utf8");}function Wo(e){try{Fo(nt(e));}catch{}}wn.exports={loadState:Ko,saveState:Vo,deleteState:Wo};});var st=p((Ja,mn)=>{var{readFileSync:_n,existsSync:gn}=c("fs");function Jo(e){if(!e||!gn(e))return null;try{let t=_n(e,"utf8").trimEnd().split(`
|
|
100
|
+
`);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 Xo(e){if(!e||!gn(e))return null;try{let t=_n(e,"utf8").trimEnd().split(`
|
|
101
|
+
`),n=[],s=0,r=0,o=!1;for(let i=t.length-1;i>=0;i--)try{let a=JSON.parse(t[i]);if(a.type==="user"){if(o)break;continue}if(a.type==="assistant"){o=!0;let d=(a.message?.content??[]).filter(h=>h.type==="text").map(h=>h.text).join("");d&&n.unshift(d);let l=a.message?.usage??{};s+=(l.input_tokens??0)+(l.cache_read_input_tokens??0)+(l.cache_creation_input_tokens??0),r+=l.output_tokens??0;}}catch{}return !n.length&&s===0?null:{text:n.join(`
|
|
102
|
+
|
|
103
|
+
`),inputTokens:s,outputTokens:r}}catch{}return null}mn.exports={readPromptUuid:Jo,readLastAssistantOutput:Xo};});var Le=p((Xa,Ln)=>{var{readFileSync:zo,existsSync:yn,readdirSync:Zo}=c("fs"),{homedir:An}=c("os"),{join:K,extname:Qo}=c("path"),ei=new Set([".venv","__pycache__",".git","node_modules"]),ti=new Set([".pyc",".pyo"]),ni=new Set(["SKILL.md",".DS_Store",".gitignore"]);function si(e,t){if(!e)return null;let n=[K(An(),".claude","skills",e,"SKILL.md"),K(t||"",".claude","skills",e,"SKILL.md")];for(let s of n)if(yn(s))try{return zo(s,"utf8")}catch{}return null}function ri(e){return e.match(/^\/([a-z][a-z0-9-]*)(?:\s.*)?$/i)?.[1]||null}var On=new Set(["Read","Write","Edit","MultiEdit","Bash","Glob","Grep","TodoWrite","WebFetch","WebSearch","Agent","Task"]);function oi(e){return !!e.slashSkill||e.toolCalls.some(s=>s.tool==="Skill")?e.toolCalls.some(s=>On.has(s.tool))?"complete":"prerequisite_required":null}function ii(e,t){if(!e)return null;let n=[K(An(),".claude","skills",e),K(t||"",".claude","skills",e)],s=null;for(let i of n)if(yn(K(i,"SKILL.md"))){s=i;break}if(!s)return null;let r=[];function o(i,a){for(let u of Zo(i,{withFileTypes:true})){if(ei.has(u.name)||ni.has(u.name)||ti.has(Qo(u.name)))continue;let d=a?`${a}/${u.name}`:u.name;u.isDirectory()?o(K(i,u.name),d):r.push(d);}}return o(s,""),r.length>0?r:null}Ln.exports={readSkillContent:si,readSkillArtifacts:ii,detectSlashSkill:ri,EXECUTION_TOOLS:On,detectExecutionStatus:oi};});var kn=p((za,Cn)=>{var{generateTraceId:Nn,generateSpanId:ai,nowNs:ci}=ae(),{saveState:ui}=ce(),{readPromptUuid:li}=st(),{detectSlashSkill:di,readSkillContent:pi,readSkillArtifacts:fi}=Le(),{passthrough:hi}=Y(),{dbg:In}=k(),{ENV:Ti}=w(),{resolveCredentials:Si}=U();async function Ei(e){let t=e.session_id||"unknown",n=e.prompt||"",s=e.cwd||"";try{(await Si()).authError===!0&&(process.stderr.write(`
|
|
104
|
+
\u26A0 flow-ai-obs: Your Flow credentials have expired.
|
|
105
|
+
Traces will not be captured until you re-authenticate.
|
|
106
|
+
Run: flow-ai-obs auth login
|
|
107
|
+
|
|
108
|
+
`),In("UserPromptSubmit","auth expired \u2014 warning emitted to stderr"));}catch{}let r=li(e.transcript_path)||Nn(),o=di(n),i=o?pi(o,s):null,a=o?fi(o,s):null;ui(t,{traceId:Nn(),spanId:ai(),startNs:ci(),sessionId:t,prompt:n,cwd:s,traceName:r,transcriptPath:e.transcript_path||"",model:process.env[Ti.ANTHROPIC_MODEL]||"",toolCalls:[],spans:[],pendingTool:null,slashSkill:o,skillContent:i,skillArtifacts:a}),In("UserPromptSubmit",`sid=${t}`,`traceName=${r}`,`slashSkill=${o}`),hi(e);}Cn.exports={onUserPromptSubmit:Ei};});var vn=p((Za,Un)=>{var{nowNs:wi}=ae(),{loadState:_i,saveState:gi}=ce(),{truncate:mi,passthrough:yi}=Y(),{dbg:Ai}=k(),{TRACE_LIMITS:Oi}=w();async function Li(e){let t=e.session_id||"unknown",n=e.tool_name||"unknown",s=e.tool_input||{},r=_i(t);r&&(r.pendingTool={name:n,inputStr:mi(s,Oi.TOOL_INPUT),startNs:wi()},gi(t,r)),Ai("PreToolUse",`sid=${t}`,`tool=${n}`,`stateFound=${!!r}`),yi(e);}Un.exports={onPreToolUse:Li};});var Pn=p((Qa,bn)=>{var Ni=c("https"),Ii=c("http"),{FLOW_URLS:Ci}=w();function ki(e){let t=new URL(e),n=new URL(Ci.GATEWAY_HEALTH);return n.hostname=t.hostname,n.port=t.port,n.protocol=t.protocol,n}function Rn(e,t){return new Promise((n,s)=>{let o=(e._isSSL?Ni:Ii).request(e,i=>{let a=[];i.on("data",u=>a.push(u)),i.on("end",()=>n({statusCode:i.statusCode,body:a.join("")}));});o.on("error",i=>s(new Error(`Network error: ${i.message}`))),t&&o.write(t),o.end();})}async function Ui(e){let t;try{t=ki(e);}catch{return false}let n=t.protocol==="https:";try{let s=await Rn({hostname:t.hostname,port:t.port||(n?443:80),path:t.pathname,method:"GET",_isSSL:n},null);return s.statusCode>=200&&s.statusCode<300}catch{return false}}async function vi(e,t,n){let s=JSON.stringify(e),r=new URL(t),o=r.protocol==="https:",i=String(n).replace(/[\r\n]/g,"");try{return (await Rn({hostname:r.hostname,port:r.port||(o?443:80),path:r.pathname,method:"POST",headers:{"Content-Type":"application/json",Authorization:i,"Content-Length":Buffer.byteLength(s)},_isSSL:o},s)).statusCode}catch{return 0}}bn.exports={checkHealth:Ui,sendTraces:vi};});var xn=p((ec,Fn)=>{var b=c("fs"),rt=c("path"),$n=c("os"),{BUFFER:ue}=w(),{dbg:le}=k();function qn(e){if(/[/\\]/.test(e))throw new Error(`Invalid buffer fileId: ${e}`);return rt.join($n.tmpdir(),`${ue.FILE_PREFIX}${e}.json`)}function ot(){let e=$n.tmpdir(),t;try{t=b.readdirSync(e);}catch{return []}return t.filter(n=>n.startsWith(ue.FILE_PREFIX)&&n.endsWith(".json")).map(n=>{let s=rt.join(e,n),r=0;try{r=b.statSync(s).mtimeMs;}catch{}return {full:s,mtime:r}}).sort((n,s)=>n.mtime-s.mtime).map(n=>n.full)}function Ri(e){try{let t=ot();if(t.length>=ue.MAX_FILES){let r=t.slice(0,t.length-ue.MAX_FILES+1);for(let o of r)try{b.unlinkSync(o);}catch{}}let n=`${Date.now()}-${Math.random().toString(36).slice(2,8)}`,s={fileId:n,bufferedAt:Date.now(),payload:e};return b.writeFileSync(qn(n),JSON.stringify(s),"utf8"),le("buffer",`saved fileId=${n}`),n}catch(t){return le("buffer",`saveToBuffer failed: ${t.message}`),null}}function bi(){let e=ot(),t=[];for(let n of e)try{let s=b.readFileSync(n,"utf8"),r=JSON.parse(s);r&&r.fileId&&r.payload&&t.push(r);}catch{le("buffer",`skipping malformed file: ${n}`);}return t}function Pi(e){try{b.unlinkSync(qn(e)),le("buffer",`deleted fileId=${e}`);}catch{}}function $i(){let e=ot(),t=Date.now()-ue.MAX_AGE_MS;for(let n of e)try{let{mtimeMs:s}=b.statSync(n);s<t&&(b.unlinkSync(n),le("buffer",`evicted stale: ${rt.basename(n)}`));}catch{}}Fn.exports={saveToBuffer:Ri,loadBuffer:bi,deleteBuffer:Pi,cleanStaleBuffers:$i};});var it=p((tc,Hn)=>{var{resolveCredentials:qi}=U(),{OTLP:Mn}=w(),{dbg:V}=k(),{checkHealth:Fi,sendTraces:Bn}=Pn(),{saveToBuffer:Dn,loadBuffer:xi,deleteBuffer:Mi,cleanStaleBuffers:Di}=xn(),Bi={name:Mn.SCOPE_NAME,version:Mn.SCOPE_VERSION},Hi={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 ji(e,t){return t==null||t===""?null:{key:e,value:{stringValue:String(t)}}}function Gi(...e){return e.filter(Boolean)}function Yi(e,t){return {resourceSpans:[{resource:{attributes:e},scopeSpans:[{scope:Bi,spans:Array.isArray(t)?t:[t]}]}]}}function Ki(e,t){return new Promise(n=>{let s=JSON.stringify(e),r=new URL(t.endpoint),o=r.protocol==="https:",i=l=>String(l).replace(/[\r\n]/g,""),a={hostname:r.hostname,port:r.port||(o?443:80),path:r.pathname,method:"POST",headers:{"Content-Type":"application/json",Authorization:i(t.authHeader),"Content-Length":Buffer.byteLength(s)}},d=(o?c("https"):c("http")).request(a,l=>{l.resume(),n(l.statusCode);});d.on("error",()=>n(0)),d.write(s),d.end();})}async function Vi(e){Di();let t=xi();if(t.length){V("replayBufferedTraces",`replaying ${t.length} buffered trace(s)`);for(let n of t)try{let s=await Bn(n.payload,e.endpoint,e.authHeader);s>=200&&s<300?(Mi(n.fileId),V("replayBufferedTraces",`replayed fileId=${n.fileId} status=${s}`)):V("replayBufferedTraces",`replay failed fileId=${n.fileId} status=${s}`);}catch(s){V("replayBufferedTraces",`replay error fileId=${n.fileId}: ${s.message}`);}}}async function Wi(e){let t=await qi();return t.length?(await Promise.all(t.map(async s=>s.mode==="gateway"?await Fi(s.endpoint)?(await Vi(s),Bn(e,s.endpoint,s.authHeader)):(V("postToLangfuse","gateway health check failed \u2014 buffering trace"),Dn(e),0):Ki(e,s)))).find(s=>s!==0)||0:(t.authError&&(V("postToLangfuse","auth refresh failed \u2014 buffering trace"),Dn(e)),0)}Hn.exports={LF:Hi,a:ji,attrs:Gi,buildPayload:Yi,postToLangfuse:Wi};});var at=p((nc,jn)=>{var _="[REDACTED]",Ji=[{re:/\b(sk-[A-Za-z0-9_\-]{20,})/g,replace:()=>`sk-${_}`},{re:/\b(pk-[A-Za-z0-9_\-]{20,})/g,replace:()=>`pk-${_}`},{re:/\b(Bearer\s+)[A-Za-z0-9\-._~+/]+=*/gi,replace:(e,t)=>`${t}${_}`},{re:/\b(Basic\s+)[A-Za-z0-9+/]+=*/gi,replace:(e,t)=>`${t}${_}`},{re:/(-----BEGIN [A-Z ]+-----)[^-]*(-----END [A-Z ]+-----)/g,replace:(e,t,n)=>`${t}
|
|
89
109
|
${_}
|
|
90
|
-
${n}`},{re:/\b(AKIA[0-9A-Z]{16})\b/g,replace:()=>`AKIA${_}`},{re:/(aws_secret_access_key\s*[=:]\s*)([A-Za-z0-9/+]{40})/gi,replace:(e,t)=>`${t}${_}`},{re:/\b(ghp_[A-Za-z0-9]{36,})/g,replace:()=>`ghp_${_}`},{re:/\b(github_pat_[A-Za-z0-9_]{36,})/gi,replace:()=>`github_pat_${_}`},{re:/\b(eyJ[A-Za-z0-9_\-]+\.eyJ[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+)/g,replace:()=>`eyJ.${_}`},{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}${_}${n}`},{re:/([a-z][a-z0-9+\-.]*:\/\/[^:/?#\s]*):([^@\s]+)@/gi,replace:(e,t)=>`${t}:${_}@`}];function
|
|
91
|
-
`)),h=a?.inputTokens??0,
|
|
92
|
-
`),process.stdout.write(JSON.stringify(t));}}
|
|
93
|
-
`),process.exit(0);});});var
|
|
94
|
-
`),process.exit(0);}else if(
|
|
110
|
+
${n}`},{re:/\b(AKIA[0-9A-Z]{16})\b/g,replace:()=>`AKIA${_}`},{re:/(aws_secret_access_key\s*[=:]\s*)([A-Za-z0-9/+]{40})/gi,replace:(e,t)=>`${t}${_}`},{re:/\b(ghp_[A-Za-z0-9]{36,})/g,replace:()=>`ghp_${_}`},{re:/\b(github_pat_[A-Za-z0-9_]{36,})/gi,replace:()=>`github_pat_${_}`},{re:/\b(eyJ[A-Za-z0-9_\-]+\.eyJ[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+)/g,replace:()=>`eyJ.${_}`},{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}${_}${n}`},{re:/([a-z][a-z0-9+\-.]*:\/\/[^:/?#\s]*):([^@\s]+)@/gi,replace:(e,t)=>`${t}:${_}@`}];function Xi(e){if(e==null)return "";let t=typeof e=="string"?e:JSON.stringify(e);return Ji.reduce((n,{re:s,replace:r})=>n.replace(s,r),t)}jn.exports={sanitize:Xi,REDACTED:_};});var Xn=p((sc,Jn)=>{var{generateSpanId:zi,nowNs:Zi}=ae(),{loadState:Qi,saveState:ea}=ce(),{LF:de,a:$,attrs:ta}=it(),{truncate:Gn,firstLine:na,passthrough:Yn}=Y(),{readSkillContent:sa,readSkillArtifacts:ra}=Le(),{dbg:Kn}=k(),{TRACE_LIMITS:Vn}=w(),{sanitize:Wn}=at();async function oa(e){let t=e.session_id||"unknown",n=e.tool_name||"unknown",s=e.tool_input||{},r=e.tool_response||"",o=Qi(t);if(!o){Yn(e);return}let i=Zi(),a=o.pendingTool?.name===n,u=a?o.pendingTool.startNs:String(BigInt(i)-200000000n),d=a?o.pendingTool.inputStr:Gn(s,Vn.TOOL_INPUT),l=d;if(n==="Skill"){let P=typeof s=="object"&&s!==null?s.skill||s.name||s.skillName||String(Object.values(s)[0]??""):String(s),C=P?sa(P.trim(),o.cwd):null;C&&(l=C,o.skillContent||(o.skillContent=C),o.slashSkill||(o.slashSkill=P.trim()),o.skillArtifacts||(o.skillArtifacts=ra(P.trim(),o.cwd))),Kn("PostToolUse","Skill tool detected",`skillName=${P}`,`contentFound=${!!C}`);}let h=Wn(Gn(r,Vn.TOOL_OUTPUT)),S=/\b(error|exception|failed|failure|traceback|errno)\b/i.test(h.slice(0,500)),A=S?"ERROR":"DEFAULT",N=zi(),he=Math.round(Number(BigInt(i)-BigInt(u))/1e6),ke={Agent:"AGENT",Task:"AGENT"}[n]??"TOOL";o.toolCalls.push({tool:n,brief:na(d,60),error:S,durationMs:he}),o.spans.push({traceId:o.traceId,spanId:N,parentSpanId:o.spanId,name:n,kind:3,startTimeUnixNano:u,endTimeUnixNano:i,attributes:ta($(de.OBS_NAME,n),$(de.OBS_TYPE,ke),$(de.OBS_LEVEL,A),$(de.OBS_INPUT,Wn(l)),$(de.OBS_OUTPUT,h),$("tool.name",n),$("tool.error",String(S))),status:{code:S?2:1}}),o.pendingTool=null,ea(t,o),Kn("PostToolUse",`sid=${t}`,`tool=${n}`,`error=${S}`,`durationMs=${he}`,`totalSpans=${o.spans.length}`),Yn(e);}Jn.exports={onPostToolUse:oa};});var Zn=p((rc,zn)=>{var ct={"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 ia(e,t,n){let s=Object.keys(ct).find(i=>(e||"").toLowerCase().includes(i));if(!s)return;let r=ct[s],o=(t*r.input+n*r.output)/1e6;return Math.round(o*1e6)/1e6}zn.exports={MODEL_PRICING:ct,calcCostUsd:ia};});var ss=p((oc,ns)=>{var{generateSpanId:Qn,nowNs:aa}=ae(),{loadState:ca,deleteState:es}=ce(),{LF:E,a:f,attrs:Ne,buildPayload:ua,postToLangfuse:la}=it(),{getIdentityFromToken:da}=U(),{calcCostUsd:pa}=Zn(),{readLastAssistantOutput:fa}=st(),{truncate:Ie,firstLine:ha,passthrough:ut}=Y(),{dbg:pe}=k(),{detectExecutionStatus:Ta}=Le(),{sanitize:ts}=at(),{TRACE_LIMITS:Ce}=w();async function Sa(e){let t=e.session_id||"unknown",n=e.stop_reason||"end_turn",s=ca(t);if(!s){ut(e);return}let r=aa(),o=await da();if(s.slashSkill&&!s.toolCalls.some(T=>T.tool==="Skill")){let T=Qn(),W=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:Ne(f(E.OBS_NAME,"Skill"),f(E.OBS_TYPE,"TOOL"),f(E.OBS_LEVEL,"DEFAULT"),f(E.OBS_INPUT,W),f(E.OBS_OUTPUT,"loaded via slash command"),f("tool.name","Skill"),f("tool.error","false"),f("skill.name",s.slashSkill),f("skill.invocation","slash-command")),status:{code:1}}),pe("Stop",`slashSkill=${s.slashSkill}`,"synthetic span injected");}let i=e.transcript_path||s.transcriptPath||"",a=fa(i),u=s.toolCalls.length,d=s.toolCalls.filter(T=>T.error).length,l=ts(a?.text?Ie(a.text,Ce.TRACE_OUTPUT):u===0?"No tools used":s.toolCalls.map((T,W)=>`${W+1}. ${T.tool}${T.brief?` \u2192 ${T.brief}`:""}${T.error?" [ERROR]":""}`).join(`
|
|
111
|
+
`)),h=a?.inputTokens??0,S=a?.outputTokens??0,A=s.toolCalls.map((T,W)=>`${W+1}. ${T.tool}${T.brief?` \u2192 ${T.brief}`:""}${T.error?" [ERROR]":""} (${T.durationMs}ms)`),N=!!(s.slashSkill||s.toolCalls.some(T=>T.tool==="Skill")),he=s.toolCalls.some(T=>T.tool==="Agent");if(!N&&!he){pe("Stop",`sid=${t}`,"skipping trace \u2014 no Skill or Agent calls found"),es(t),ut(e);return}let Te=N?"skill":"agent",ke=Math.round(Number(BigInt(r)-BigInt(s.startNs))/1e6),P=pa(s.model,h,S),C=Ta(s);C==="prerequisite_required"&&(s.spans.push({traceId:s.traceId,spanId:Qn(),parentSpanId:s.spanId,name:"prerequisite-check",kind:3,startTimeUnixNano:s.startNs,endTimeUnixNano:r,attributes:Ne(f(E.OBS_NAME,"prerequisite-check"),f(E.OBS_TYPE,"EVENT"),f(E.OBS_LEVEL,"WARNING"),f(E.OBS_OUTPUT,l),f("skill.name",s.slashSkill||void 0),f("execution_status","prerequisite_required")),status:{code:1}}),pe("Stop",`sid=${t}`,"prerequisite-check span injected",`skill=${s.slashSkill}`));let lt=(()=>{if(!(!N||!s.prompt)){if(s.slashSkill){let T=s.prompt.replace(new RegExp(`^\\/${s.slashSkill}\\s*`,"i"),"").trim();return T?Ie(T,Ce.USER_INSTRUCTION):void 0}return Ie(s.prompt,Ce.USER_INSTRUCTION)||void 0}})(),os=JSON.stringify({trace_type:Te,...C!==null&&{execution_status:C},...s.slashSkill&&{skill_name:s.slashSkill},...s.skillArtifacts?.length&&{skill_artifacts:s.skillArtifacts},...lt!==void 0&&{user_instruction:lt},latency_ms:ke,...h&&{tokens_input:h},...S&&{tokens_output:S},cost_usd:P,...s.model&&{model:s.model},toolCount:u,errorCount:d,stopReason:n,sessionId:s.sessionId,tools:A.length?A:void 0}),is=ts(Ie(s.prompt,Ce.TRACE_INPUT)),as=Ne(f(E.TRACE_NAME,s.traceName),f(E.TRACE_INPUT,is),f(E.TRACE_OUTPUT,l),f(E.TRACE_METADATA,os),f(E.SESSION_ID,s.sessionId),f(E.USER_ID,o.user),f(E.OBS_TYPE,"GENERATION"),f(E.MODEL,s.model),h?f(E.INPUT_TOKENS,h):null,S?f(E.OUTPUT_TOKENS,S):null,f("claude.stop_reason",n),f("claude.tool_count",String(u)),f("claude.error_count",String(d)),f("claude.session_id",s.sessionId),f("flow.trace_type",Te),{key:E.TRACE_TAGS,value:{arrayValue:{values:[{stringValue:Te}]}}}),cs={traceId:s.traceId,spanId:s.spanId,name:s.traceName,kind:1,startTimeUnixNano:s.startNs,endTimeUnixNano:r,attributes:as,status:{code:d>0?2:1}},us=Ne(f("service.name",process.env.LANGFUSE_PROJECT_NAME||"claude-code"),f("deployment.environment",process.env.LANGFUSE_ENVIRONMENT||"default")),dt=[...s.spans||[],cs];pe("Stop",`sid=${t}`,`totalTools=${u}`,`errorTools=${d}`,`spans=${dt.length}`,`inputTokens=${h}`,`outputTokens=${S}`,`traceOutput="${ha(l,80)}"`);let ls=await la(ua(us,dt));pe("Stop",`POST status=${ls}`,`traceId=${s.traceId}`),es(t),ut(e);}ns.exports={onStop:Sa};});var rs=p(()=>{var{credentialsAvailable:Ea}=U(),{readInput:wa}=Y(),{onUserPromptSubmit:_a}=kn(),{onPreToolUse:ga}=vn(),{onPostToolUse:ma}=Xn(),{onStop:ya}=ss();async function Aa(){let e=process.argv[2];if(!await Ea()){let n=[];process.stdin.on("data",s=>n.push(s)),process.stdin.on("end",()=>process.stdout.write(n.join("")));return}let t=await wa();switch(e){case "UserPromptSubmit":await _a(t);break;case "PreToolUse":await ga(t);break;case "PostToolUse":await ma(t);break;case "Stop":await ya(t);break;default:process.stderr.write(`[flow-obs] unknown event: ${e}
|
|
112
|
+
`),process.stdout.write(JSON.stringify(t));}}Aa().catch(e=>{process.stderr.write(`[flow-obs] fatal: ${e.message}
|
|
113
|
+
`),process.exit(0);});});var Oa=new Set(["UserPromptSubmit","PreToolUse","PostToolUse","Stop"]),[,,I,fe]=process.argv;if(I==="--version"||I==="-v"){let{version:e}=Se();process.stdout.write(e+`
|
|
114
|
+
`),process.exit(0);}else if(I==="--help"||I==="-h"){let{bold:e,cyan:t,dim:n}=J(),{version:s}=Se();process.stdout.write(`
|
|
95
115
|
`+e(" flow-ai-obs")+n(" v"+s)+`
|
|
96
116
|
|
|
97
117
|
`),process.stdout.write(t(" install")+n(` Register Claude Code hooks in ~/.claude/settings.json
|
|
@@ -105,11 +125,11 @@ ${n}`},{re:/\b(AKIA[0-9A-Z]{16})\b/g,replace:()=>`AKIA${_}`},{re:/(aws_secret_ac
|
|
|
105
125
|
|
|
106
126
|
`)),process.stdout.write(n(` (Hook events: UserPromptSubmit | PreToolUse | PostToolUse | Stop)
|
|
107
127
|
|
|
108
|
-
`)),process.exit(0);}else if(
|
|
109
|
-
`),process.exit(1);});}else if(
|
|
128
|
+
`)),process.exit(0);}else if(I==="install"){Re().checkForUpdate();let{runInstall:e}=on();e().then(t=>process.exit(t)).catch(t=>{process.stderr.write(`Unexpected error: ${t.message}
|
|
129
|
+
`),process.exit(1);});}else if(I==="auth"){Re().checkForUpdate();let{runLogin:e,runLogout:t,runStatus:n}=ye();(async()=>{let s=0;if(fe==="login"||!fe){let r=process.argv.slice(4),o=i=>{let a=r.indexOf(i);return a!==-1?r[a+1]:void 0};s=await e({clientId:o("--client-id"),clientSecret:o("--client-secret"),tenant:o("--tenant")});}else if(fe==="logout"){let r=process.argv.includes("--force");s=await t(r);}else fe==="status"?s=await n():(process.stderr.write(`Unknown auth subcommand: ${fe}
|
|
110
130
|
`),process.stderr.write(`Usage: flow-ai-obs auth [login|logout|status]
|
|
111
|
-
`),s=1);process.exit(s);})();}else if(
|
|
112
|
-
`),process.exit(1);});}else if(
|
|
131
|
+
`),s=1);process.exit(s);})();}else if(I==="otel-headers"){let{runOtelHeaders:e}=cn();e().then(t=>process.exit(t)).catch(()=>process.exit(1));}else if(I==="check"){let{runCheck:e}=fn();e().then(t=>process.exit(t)).catch(t=>{process.stderr.write(`Unexpected error: ${t.message}
|
|
132
|
+
`),process.exit(1);});}else if(Oa.has(I))rs();else {let{bold:e,cyan:t,dim:n}=J();process.stdout.write(`
|
|
113
133
|
`+e(" flow-ai-obs")+`
|
|
114
134
|
|
|
115
135
|
`),process.stdout.write(t(" install")+n(` Register Claude Code hooks in ~/.claude/settings.json
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
'use strict';var c=(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 f=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var h=f((Zs,kt)=>{var v=process.env.FLOW_BASE_URL||"https://flow.ciandt.com",Nt={AUTH_ENGINE:process.env.FLOW_AUTH_ENGINE_URL||`${v}/auth-engine-api/v2/api-key/token`,GATEWAY_TRACES:process.env.FLOW_GATEWAY_TRACES_URL||`${v}/flow-langfuse-gateway/v1/traces`,GATEWAY_HEALTH:process.env.FLOW_GATEWAY_HEALTH_URL||`${v}/flow-langfuse-gateway/v1/health`,OTEL_ENDPOINT:process.env.FLOW_OTEL_ENDPOINT_URL||`${v}/otel`},Ze={SERVICE:"flow-plugins-cli",ACCOUNT_CREDS:"credentials",ACCOUNT_TOKEN:"token-cache"},Qe="FLOW-nodejs",tn="config.json",en={SCOPE_NAME:"flow-ai-obs",SCOPE_VERSION:"0.1.0"},nn={CLAUDE_CODE_ENABLE_TELEMETRY:"1",OTEL_EXPORTER_OTLP_ENDPOINT:Nt.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"},rn={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",FLOW_OBS_DEBUG:"FLOW_TELEMETRY_DEBUG",FLOW_OBS_ALLOW_HTTP:"FLOW_TELEMETRY_ALLOW_HTTP"},sn={LOCK_STALE_MS:3e4,CONNECTIVITY_MAX_RETRY:3,CONNECTIVITY_RETRY_MS:2e3},on={UserPromptSubmit:5,PreToolUse:3,PostToolUse:10,Stop:15},an={FILE_PREFIX:"flow-obs-buffer-",MAX_AGE_MS:5760*60*1e3,MAX_FILES:50},cn="flow-ai-obs-debug.log",un={TOOL_INPUT:2e4,TOOL_OUTPUT:2e4,TRACE_OUTPUT:2e4,USER_INSTRUCTION:1e4,TRACE_INPUT:5e4,TOOL_BRIEF:60},ln="flow-obs-";kt.exports={FLOW_BASE_URL:v,FLOW_URLS:Nt,VAULT:Ze,CONFIG_DIR_NAME:Qe,CONFIG_FILE_NAME:tn,OTLP:en,NATIVE_OTEL:nn,ENV:rn,INSTALLER:sn,HOOK_TIMEOUTS:on,BUFFER:an,DEBUG_LOG_FILENAME:cn,STATE_FILE_PREFIX:ln,TRACE_LIMITS:un};});var Rt=f((Qs,Ct)=>{var F=c("fs"),N=c("path"),dn=c("os"),{CONFIG_DIR_NAME:tt,CONFIG_FILE_NAME:et}=h(),nt={credentials:"credentials","token-cache":"tokenCache"};function q(){let t=dn.homedir();if(process.platform==="darwin")return N.join(t,"Library","Preferences",tt,et);if(process.platform==="win32"){let r=process.env.APPDATA||N.join(t,"AppData","Roaming");return N.join(r,tt,et)}let e=process.env.XDG_CONFIG_HOME||N.join(t,".config");return N.join(e,tt,et)}function rt(){try{let t=F.readFileSync(q(),"utf8");return JSON.parse(t)}catch{return {}}}function Ut(t){let e=q();F.mkdirSync(N.dirname(e),{recursive:true}),F.writeFileSync(e,JSON.stringify(t,null,2),{encoding:"utf8",mode:384});}var st=class{static isAvailable(){return true}static hasExistingData(){try{if(!F.existsSync(q()))return !1;let e=JSON.parse(F.readFileSync(q(),"utf8"));return !!(e&&e.credentials)}catch{return false}}async getSecret(e,r){let n=rt(),s=nt[r]||r,o=n[s];return o?typeof o=="string"?o:JSON.stringify(o):null}async setSecret(e,r,n){let s=rt(),o=nt[r]||r;if(r==="token-cache")try{s[o]=JSON.parse(n);}catch{s[o]=n;}else s[o]=n;Ut(s);}async deleteSecret(e,r){let n=rt(),s=nt[r]||r;return s in n?(delete n[s],Ut(n),true):false}getStoragePath(){return `config.json (unencrypted) \u2014 ${q()}`}};function pn(){}Ct.exports={ScryptFallbackProvider:st,_resetWarningState:pn};});var $t=f((to,Pt)=>{var{VAULT:x}=h();async function fn(t,e){let r=[x.ACCOUNT_CREDS,x.ACCOUNT_TOKEN];for(let n of r)try{if(await e.getSecret(x.SERVICE,n)!==null)continue;let o=await t.getSecret(x.SERVICE,n);o!==null&&await e.setSecret(x.SERVICE,n,o);}catch{}}Pt.exports={migrateFromJsonFallback:fn};});var qt=f((eo,vt)=>{var{execFile:Sn,exec:_n}=c("child_process"),{promisify:bt}=c("util"),ot=bt(Sn),En=bt(_n),at=class{static async isAvailable(){try{return await En("command -v security"),!0}catch{return false}}async getSecret(e,r){try{let{stdout:n}=await ot("security",["find-generic-password","-w","-a",r,"-s",e]);return n.trim()||null}catch{return null}}async setSecret(e,r,n){await ot("security",["add-generic-password","-U","-a",r,"-s",e,"-w",n]);}async deleteSecret(e,r){try{return await ot("security",["delete-generic-password","-a",r,"-s",e]),!0}catch{return false}}getStoragePath(){return "macOS Keychain"}};vt.exports={MacOsKeyVaultProvider:at};});var Dt=f((no,Bt)=>{var{execFile:Tn,exec:hn,spawn:gn}=c("child_process"),{promisify:xt}=c("util"),Ft=xt(Tn),yn=xt(hn),it=class{static async isAvailable(){try{return await yn("command -v secret-tool"),!0}catch{return false}}async getSecret(e,r){try{let{stdout:n}=await Ft("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 a=gn("secret-tool",["store","--label",e,"service",e,"account",r]);a.on("error",o),a.on("close",u=>{u===0?s():o(new Error(`secret-tool exited with code ${u}`));}),a.stdin.write(n),a.stdin.end();});}async deleteSecret(e,r){try{return await Ft("secret-tool",["clear","service",e,"account",r]),!0}catch{return false}}getStoragePath(){return "Linux Secret Service (libsecret)"}};Bt.exports={LinuxKeyVaultProvider:it};});var Gt=f((ro,Mt)=>{var ct=class{static async isAvailable(){try{return await c("keytar").getPassword("__flow_probe__","__flow_probe__"),!0}catch{return false}}async getSecret(e,r){return c("keytar").getPassword(e,r)}async setSecret(e,r,n){await c("keytar").setPassword(e,r,n);}async deleteSecret(e,r){return c("keytar").deletePassword(e,r)}getStoragePath(){return "Windows Credential Manager"}};Mt.exports={WindowsKeyVaultProvider:ct};});var jt=f((so,Yt)=>{async function Vt(){let{ScryptFallbackProvider:t}=Rt();if(t.hasExistingData()){let e=await Wt();if(e){let{migrateFromJsonFallback:r}=$t(),{VAULT:n}=h();if(await r(new t,e),await e.getSecret(n.SERVICE,n.ACCOUNT_CREDS)!==null)return e}return new t}return await Wt()??new t}async function Wt(){switch(process.platform){case "darwin":{let{MacOsKeyVaultProvider:t}=qt();return await t.isAvailable()?new t:null}case "linux":{let{LinuxKeyVaultProvider:t}=Dt();return await t.isAvailable()?new t:null}case "win32":{let{WindowsKeyVaultProvider:t}=Gt();return await t.isAvailable()?new t:null}default:return null}}var On=Vt;Yt.exports={createSecretVaultProvider:Vt,createKeyVaultProvider:On};});var Kt=f((oo,Jt)=>{var{createSecretVaultProvider:mn}=jt(),{VAULT:lt}=h(),k=lt.SERVICE,dt=lt.ACCOUNT_CREDS,pt=lt.ACCOUNT_TOKEN,ut=null;function U(){return ut||(ut=mn()),ut}async function Ht(){let e=await(await U()).getSecret(k,dt);if(!e)return null;try{return JSON.parse(e)}catch{return null}}async function An(t){if(!t.clientId||!t.clientSecret||!t.tenant)throw new Error("clientId, clientSecret and tenant are required");await(await U()).setSecret(k,dt,JSON.stringify(t));}async function wn(){let t=await U();await t.deleteSecret(k,dt),await t.deleteSecret(k,pt);}async function Ln(t){await(await U()).setSecret(k,pt,JSON.stringify({accessToken:t.accessToken,expiresAt:t.expiresAt}));}async function ft(){let e=await(await U()).getSecret(k,pt);if(!e)return null;try{let r=JSON.parse(e);return {accessToken:r.accessToken,expiresAt:r.expiresAt}}catch{return null}}async function In(){let t=await ft();return t?new Date(t.expiresAt)>new Date:false}async function Nn(){let t=await ft();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 kn(){let t=await U();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 Un(){let t=await Ht();return !!(t&&t.clientId&&t.clientSecret&&t.tenant)}Jt.exports={getFlowCredentials:Ht,saveFlowCredentials:An,clearFlowCredentials:wn,saveTokenCache:Ln,getTokenCache:ft,isTokenValid:In,getEmailFromToken:Nn,getConfigPath:kn,hasCredentials:Un};});var Zt=f((ao,Xt)=>{var Cn=c("https"),Rn=c("http"),{FLOW_URLS:Pn}=h(),$n=/^[a-z0-9][a-z0-9-]{0,62}[a-z0-9]$|^[a-z0-9]$/;function bn(t){if(!$n.test(t))throw new Error(`Invalid tenant value: "${t}". Tenant must be lowercase alphanumeric and hyphens (1-64 chars).`)}var zt={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 vn(t,e){try{let r=JSON.parse(e);if(typeof r.error=="string"&&zt[r.error])return new Error(zt[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 qn(t){return new Promise((e,r)=>{try{bn(t.tenant);}catch(l){return r(l)}let n=JSON.stringify({clientSecret:t.clientSecret}),s=new URL(Pn.AUTH_ENGINE),o=s.protocol==="https:",a={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}},p=(o?Cn:Rn).request(a,l=>{let d=[];l.on("data",S=>d.push(S)),l.on("end",()=>{let S=d.join("");if(l.statusCode>=400)return r(vn(l.statusCode,S));let E;try{E=JSON.parse(S);}catch{return r(new Error("Invalid response from auth engine"))}let y=E.expires_at??new Date(Date.now()+(E.expires_in??3600)*1e3).toISOString();e({accessToken:E.access_token,expiresAt:y});});});p.on("error",l=>r(new Error(`Network error: ${l.message}`))),p.write(n),p.end();})}Xt.exports={getToken:qn};});var m=f((io,te)=>{var{writeFileSync:Fn}=c("fs"),{tmpdir:xn}=c("os"),{join:Bn}=c("path"),{DEBUG_LOG_FILENAME:Dn,ENV:Mn}=h(),Qt=Bn(xn(),Dn);function Gn(...t){if(process.env[Mn.FLOW_OBS_DEBUG]!=="1")return;let e=`[${new Date().toISOString()}] ${t.join(" ")}
|
|
2
|
-
`;try{
|
|
3
|
-
`);}}
|
|
4
|
-
`)[0].slice(0,
|
|
5
|
-
`);for(let r=
|
|
6
|
-
`),r=[],n=0,s=0,o=!1;for(let a=
|
|
1
|
+
'use strict';var c=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,r)=>(typeof require<"u"?require:t)[r]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var _=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var h=_((so,Re)=>{var k=process.env.FLOW_BASE_URL||"https://flow.ciandt.com",Ce={AUTH_ENGINE:process.env.FLOW_AUTH_ENGINE_URL||`${k}/auth-engine-api/v2/api-key/token`,GATEWAY_TRACES:process.env.FLOW_GATEWAY_TRACES_URL||`${k}/flow-langfuse-gateway/v1/traces`,GATEWAY_HEALTH:process.env.FLOW_GATEWAY_HEALTH_URL||`${k}/flow-langfuse-gateway/v1/health`,OTEL_ENDPOINT:process.env.FLOW_OTEL_ENDPOINT_URL||`${k}/otel`},tn={SERVICE:"flow-plugins-cli",ACCOUNT_CREDS:"credentials",ACCOUNT_TOKEN:"token-cache"},nn="FLOW-nodejs",rn="config.json",sn={SCOPE_NAME:"flow-ai-obs",SCOPE_VERSION:"0.1.0"},on={ANTHROPIC_BASE_URL:process.env.FLOW_LLM_PROXY_URL||`${k}/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"},an={CLAUDE_CODE_ENABLE_TELEMETRY:"1",OTEL_EXPORTER_OTLP_ENDPOINT:Ce.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"},cn={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"},ln={KEYCHAIN_ENABLED:false},un={LOCK_STALE_MS:3e4,CONNECTIVITY_MAX_RETRY:3,CONNECTIVITY_RETRY_MS:2e3},dn={UserPromptSubmit:5,PreToolUse:3,PostToolUse:10,Stop:15},pn={FILE_PREFIX:"flow-obs-buffer-",MAX_AGE_MS:5760*60*1e3,MAX_FILES:50},fn="flow-ai-obs-debug.log",_n={TOOL_INPUT:2e4,TOOL_OUTPUT:2e4,TRACE_OUTPUT:2e4,USER_INSTRUCTION:1e4,TRACE_INPUT:5e4,TOOL_BRIEF:60},Sn="flow-obs-";Re.exports={FLOW_BASE_URL:k,FLOW_URLS:Ce,VAULT:tn,CONFIG_DIR_NAME:nn,CONFIG_FILE_NAME:rn,OTLP:sn,LLM_PROXY:on,NATIVE_OTEL:an,ENV:cn,FEATURES:ln,INSTALLER:un,HOOK_TIMEOUTS:dn,BUFFER:pn,DEBUG_LOG_FILENAME:fn,STATE_FILE_PREFIX:Sn,TRACE_LIMITS:_n};});var be=_((oo,Pe)=>{var B=c("fs"),C=c("path"),En=c("os"),{CONFIG_DIR_NAME:ne,CONFIG_FILE_NAME:re}=h(),se={credentials:"credentials","token-cache":"tokenCache"};function q(){let e=En.homedir();if(process.platform==="darwin")return C.join(e,"Library","Preferences",ne,re);if(process.platform==="win32"){let r=process.env.APPDATA||C.join(e,"AppData","Roaming");return C.join(r,ne,re)}let t=process.env.XDG_CONFIG_HOME||C.join(e,".config");return C.join(t,ne,re)}function oe(){try{let e=B.readFileSync(q(),"utf8");return JSON.parse(e)}catch{return {}}}function Ue(e){let t=q();B.mkdirSync(C.dirname(t),{recursive:true}),B.writeFileSync(t,JSON.stringify(e,null,2),{encoding:"utf8",mode:384});}var ae=class{static isAvailable(){return true}static hasExistingData(){try{if(!B.existsSync(q()))return !1;let t=JSON.parse(B.readFileSync(q(),"utf8"));return !!(t&&t.credentials)}catch{return false}}async getSecret(t,r){let n=oe(),s=se[r]||r,o=n[s];return o?typeof o=="string"?o:JSON.stringify(o):null}async setSecret(t,r,n){let s=oe(),o=se[r]||r;if(r==="token-cache")try{s[o]=JSON.parse(n);}catch{s[o]=n;}else s[o]=n;Ue(s);}async deleteSecret(t,r){let n=oe(),s=se[r]||r;return s in n?(delete n[s],Ue(n),true):false}getStoragePath(){return `config.json (unencrypted) \u2014 ${q()}`}};function Tn(){}Pe.exports={ScryptFallbackProvider:ae,_resetWarningState:Tn};});var $e=_((ao,ve)=>{var{VAULT:D}=h();async function hn(e,t){let r=[D.ACCOUNT_CREDS,D.ACCOUNT_TOKEN];for(let n of r)try{if(await t.getSecret(D.SERVICE,n)!==null)continue;let o=await e.getSecret(D.SERVICE,n);o!==null&&await t.setSecret(D.SERVICE,n,o);}catch{}}ve.exports={migrateFromJsonFallback:hn};});var Be=_((io,qe)=>{var{execFile:gn,exec:On}=c("child_process"),{promisify:Fe}=c("util"),ie=Fe(gn),An=Fe(On),ce=class{static async isAvailable(){try{return await An("command -v security"),!0}catch{return false}}async getSecret(t,r){try{let{stdout:n}=await ie("security",["find-generic-password","-w","-a",r,"-s",t]);return n.trim()||null}catch{return null}}async setSecret(t,r,n){await ie("security",["add-generic-password","-U","-a",r,"-s",t,"-w",n]);}async deleteSecret(t,r){try{return await ie("security",["delete-generic-password","-a",r,"-s",t]),!0}catch{return false}}getStoragePath(){return "macOS Keychain"}};qe.exports={MacOsKeyVaultProvider:ce};});var He=_((co,Me)=>{var{execFile:yn,exec:mn,spawn:Ln}=c("child_process"),{promisify:xe}=c("util"),De=xe(yn),wn=xe(mn),le=class{static async isAvailable(){try{return await wn("command -v secret-tool"),!0}catch{return false}}async getSecret(t,r){try{let{stdout:n}=await De("secret-tool",["lookup","service",t,"account",r]);return n.trim()||null}catch{return null}}async setSecret(t,r,n){await new Promise((s,o)=>{let a=Ln("secret-tool",["store","--label",t,"service",t,"account",r]);a.on("error",o),a.on("close",l=>{l===0?s():o(new Error(`secret-tool exited with code ${l}`));}),a.stdin.write(n),a.stdin.end();});}async deleteSecret(t,r){try{return await De("secret-tool",["clear","service",t,"account",r]),!0}catch{return false}}getStoragePath(){return "Linux Secret Service (libsecret)"}};Me.exports={LinuxKeyVaultProvider:le};});var We=_((lo,Ge)=>{var ue=class{static async isAvailable(){try{return await c("keytar").getPassword("__flow_probe__","__flow_probe__"),!0}catch{return false}}async getSecret(t,r){return c("keytar").getPassword(t,r)}async setSecret(t,r,n){await c("keytar").setPassword(t,r,n);}async deleteSecret(t,r){return c("keytar").deletePassword(t,r)}getStoragePath(){return "Windows Credential Manager"}};Ge.exports={WindowsKeyVaultProvider:ue};});var Je=_((uo,Ve)=>{async function Ke(){let{ScryptFallbackProvider:e}=be();if(e.hasExistingData()){let t=await Ye();if(t){let{migrateFromJsonFallback:r}=$e(),{VAULT:n}=h();if(await r(new e,t),await t.getSecret(n.SERVICE,n.ACCOUNT_CREDS)!==null)return t}return new e}return await Ye()??new e}async function Ye(){switch(process.platform){case "darwin":{let{MacOsKeyVaultProvider:e}=Be();return await e.isAvailable()?new e:null}case "linux":{let{LinuxKeyVaultProvider:e}=He();return await e.isAvailable()?new e:null}case "win32":{let{WindowsKeyVaultProvider:e}=We();return await e.isAvailable()?new e:null}default:return null}}var Nn=Ke;Ve.exports={createSecretVaultProvider:Ke,createKeyVaultProvider:Nn};});var Xe=_((po,ze)=>{var{createSecretVaultProvider:In}=Je(),{VAULT:pe}=h(),R=pe.SERVICE,fe=pe.ACCOUNT_CREDS,_e=pe.ACCOUNT_TOKEN,de=null;function U(){return de||(de=In()),de}async function je(){let t=await(await U()).getSecret(R,fe);if(!t)return null;try{return JSON.parse(t)}catch{return null}}async function kn(e){if(!e.clientId||!e.clientSecret||!e.tenant)throw new Error("clientId, clientSecret and tenant are required");await(await U()).setSecret(R,fe,JSON.stringify(e));}async function Cn(){let e=await U();await e.deleteSecret(R,fe),await e.deleteSecret(R,_e);}async function Rn(e){await(await U()).setSecret(R,_e,JSON.stringify({accessToken:e.accessToken,expiresAt:e.expiresAt}));}async function Se(){let t=await(await U()).getSecret(R,_e);if(!t)return null;try{let r=JSON.parse(t);return {accessToken:r.accessToken,expiresAt:r.expiresAt}}catch{return null}}async function Un(){let e=await Se();return e?new Date(e.expiresAt)>new Date:false}async function Pn(){let e=await Se();if(!e||!e.accessToken)return null;try{let t=e.accessToken.split(".");if(t.length<2)return null;let r=JSON.parse(Buffer.from(t[1].replace(/-/g,"+").replace(/_/g,"/"),"base64").toString("utf8"));return r.email||r.preferred_username||r.upn||r.sub||null}catch{return null}}async function bn(){let e=await U();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 vn(){let e=await je();return !!(e&&e.clientId&&e.clientSecret&&e.tenant)}ze.exports={getFlowCredentials:je,saveFlowCredentials:kn,clearFlowCredentials:Cn,saveTokenCache:Rn,getTokenCache:Se,isTokenValid:Un,getEmailFromToken:Pn,getConfigPath:bn,hasCredentials:vn};});var et=_((fo,Qe)=>{var $n=c("https"),Fn=c("http"),{FLOW_URLS:qn}=h(),Bn=/^[a-z0-9][a-z0-9-]{0,62}[a-z0-9]$|^[a-z0-9]$/;function Dn(e){if(!Bn.test(e))throw new Error(`Invalid tenant value: "${e}". Tenant must be lowercase alphanumeric and hyphens (1-64 chars).`)}var Ze={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 xn(e,t){try{let r=JSON.parse(t);if(typeof r.error=="string"&&Ze[r.error])return new Error(Ze[r.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 Mn(e){return new Promise((t,r)=>{try{Dn(e.tenant);}catch(u){return r(u)}let n=JSON.stringify({clientSecret:e.clientSecret}),s=new URL(qn.AUTH_ENGINE),o=s.protocol==="https:",a={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:e.tenant}},p=(o?$n:Fn).request(a,u=>{let d=[];u.on("data",f=>d.push(f)),u.on("end",()=>{let f=d.join("");if(u.statusCode>=400)return r(xn(u.statusCode,f));let E;try{E=JSON.parse(f);}catch{return r(new Error("Invalid response from auth engine"))}let O=E.expires_at??new Date(Date.now()+(E.expires_in??3600)*1e3).toISOString();t({accessToken:E.access_token,expiresAt:O});});});p.on("error",u=>r(new Error(`Network error: ${u.message}`))),p.write(n),p.end();})}Qe.exports={getToken:Mn};});var L=_((_o,nt)=>{var{writeFileSync:Hn}=c("fs"),{tmpdir:Gn}=c("os"),{join:Wn}=c("path"),{DEBUG_LOG_FILENAME:Yn,ENV:Kn}=h(),tt=Wn(Gn(),Yn);function Vn(...e){if(process.env[Kn.FLOW_OBS_DEBUG]!=="1")return;let t=`[${new Date().toISOString()}] ${e.join(" ")}
|
|
2
|
+
`;try{Hn(tt,t,{flag:"a"});}catch(r){process.stderr.write(`[flow-obs debug ERROR] ${r.message}
|
|
3
|
+
`);}}nt.exports={dbg:Vn,DEBUG_LOG:tt};});var M=_((So,st)=>{var{getFlowCredentials:Ee,isTokenValid:Jn,getEmailFromToken:x,getTokenCache:jn,saveTokenCache:zn}=Xe(),{getToken:Xn}=et(),{FLOW_BASE_URL:Zn,ENV:A,FEATURES:Te}=h(),{dbg:P}=L(),Qn=[/^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 er(e){return Qn.some(t=>t.test(e))}function z(e){if(!e)return null;try{let t=e.split(".");if(t.length<2)return null;let r=JSON.parse(Buffer.from(t[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 tr(e){let t=Buffer.from(JSON.stringify({alg:"none",typ:"JWT"})).toString("base64url"),r=Buffer.from(JSON.stringify({clientId:e.clientId,clientSecret:e.clientSecret,tenant:e.tenant})).toString("base64url");return `${t}.${r}.`}function he(e){let t;try{t=new URL(e);}catch{throw new Error(`Invalid URL: ${e}`)}if(!(process.env[A.FLOW_OBS_ALLOW_HTTP]==="true")&&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(er(t.hostname))throw new Error(`SSRF: private/loopback host not allowed: ${t.hostname}`);return e}async function nr(){let e=z(process.env[A.ANTHROPIC_AUTH_TOKEN]);if(e)return {user:await x().catch(()=>null)||e.clientId,tenant:e.tenant};if(Te.KEYCHAIN_ENABLED)try{let t=await Ee();if(!t)return {user:"",tenant:""};let r=await x()||t.clientId||"",n=t.tenant||"";return {user:r,tenant:n}}catch{return {user:"",tenant:""}}return {user:"",tenant:""}}async function rr(e){if(await Jn())return (await jn()).accessToken;P("getOrRefreshToken","token expired \u2014 refreshing via auth-engine");let t=await Xn(e);return await zn(t),P("getOrRefreshToken",`token refreshed, expires=${t.expiresAt}`),t.accessToken}function sr(e,t){let r=t&&t.accessToken?t.accessToken:"";return {endpoint:e.replace(/\/$/,"")+"/langfuse/traces",authHeader:`Bearer ${r}`}}function or(e,t,r){let n=Buffer.from(`${t}:${r}`).toString("base64");return {endpoint:e.replace(/\/$/,"")+"/api/public/otel/v1/traces",authHeader:`Basic ${n}`}}async function rt(){let e=[],t=process.env[A.ANTHROPIC_MODEL]||"",r=process.env[A.FLOW_TELEMETRY]==="true",n=process.env[A.LANGFUSE_BASE_URL],s=process.env[A.LANGFUSE_PUBLIC_KEY],o=process.env[A.LANGFUSE_SECRET_KEY];if(r&&n&&s&&o){let d="",f="",E=z(process.env[A.ANTHROPIC_AUTH_TOKEN]);if(E)d=await x().catch(()=>null)||E.clientId,f=E.tenant;else if(Te.KEYCHAIN_ENABLED)try{let y=await Ee();y&&(d=await x()||y.clientId,f=y.tenant);}catch{}let O={user:d||"",tenant:f||"",team:"",project:"",model:t};e.push({mode:"direct",...or(he(n),s,o),...O}),P("resolveCredentials","direct mode active",`user=${O.user}`,`tenant=${O.tenant}`);}let a=z(process.env[A.ANTHROPIC_AUTH_TOKEN]);if(P("resolveCredentials",a?"credentials resolved from ANTHROPIC_AUTH_TOKEN":"ANTHROPIC_AUTH_TOKEN absent or invalid"),!a&&Te.KEYCHAIN_ENABLED&&(a=await Ee(),a&&P("resolveCredentials","credentials resolved from keychain (FEATURES.KEYCHAIN_ENABLED=true)")),!a){if(e.length===0){let d=[];return d.authError=false,d}return e}let l;try{l=await rr(a);}catch(d){if(P("resolveCredentials",`token refresh failed: ${d.message}`),e.length>0)return e;let f=[];return f.authError=true,f}let p={user:await x()||a.clientId,tenant:a.tenant,team:"",project:"",model:t},u=process.env[A.FLOW_TELEMETRY_GATEWAY]||Zn;return e.push({mode:"gateway",...sr(he(u),{accessToken:l}),...p}),e}async function ar(){return (await rt()).length>0}st.exports={credentialsAvailable:ar,getIdentityFromToken:nr,resolveCredentials:rt,validateUrl:he,parseCredsFromAnthropicToken:z,buildAnthropicAuthToken:tr};});var b=_((Eo,ot)=>{function ir(e,t){let r=typeof e=="object"?JSON.stringify(e):String(e??"");return r.length>t?r.slice(0,t)+" \u2026[truncated]":r}function cr(e,t=100){return String(e??"").split(`
|
|
4
|
+
`)[0].slice(0,t).trim()}function lr(){return new Promise(e=>{let t="";process.stdin.setEncoding("utf8"),process.stdin.on("data",r=>t+=r),process.stdin.on("end",()=>{try{e(JSON.parse(t));}catch{e({});}});})}function ur(e){process.stdout.write(JSON.stringify(e));}ot.exports={truncate:ir,firstLine:cr,readInput:lr,passthrough:ur};});var H=_((To,it)=>{var{randomBytes:at}=c("crypto"),dr=()=>at(16).toString("hex"),pr=()=>at(8).toString("hex");function fr(){return String(BigInt(Date.now())*1000000n)}it.exports={generateTraceId:dr,generateSpanId:pr,nowNs:fr};});var G=_((go,lt)=>{var{readFileSync:_r,writeFileSync:Sr,unlinkSync:Er,existsSync:Tr,realpathSync:ho}=c("fs"),{tmpdir:ct}=c("os"),{join:hr,resolve:gr,normalize:Or,sep:Ar}=c("path"),yr=/^[0-9a-f-]{1,64}$/i,mr=Or(ct())+Ar;function Lr(e,t){let r=gr(e);if(!r.startsWith(t))throw new Error(`Path traversal detected: ${e}`);return r}function ge(e){if(!yr.test(e))throw new Error(`Invalid session ID: ${e}`);return Lr(hr(ct(),`flow-obs-${e}.json`),mr)}function wr(e){let t=ge(e);if(!Tr(t))return null;try{return JSON.parse(_r(t,"utf8"))}catch{return null}}function Nr(e,t){Sr(ge(e),JSON.stringify(t),"utf8");}function Ir(e){try{Er(ge(e));}catch{}}lt.exports={loadState:wr,saveState:Nr,deleteState:Ir};});var Oe=_((Oo,pt)=>{var{readFileSync:ut,existsSync:dt}=c("fs");function kr(e){if(!e||!dt(e))return null;try{let t=ut(e,"utf8").trimEnd().split(`
|
|
5
|
+
`);for(let r=t.length-1;r>=0;r--)try{let n=JSON.parse(t[r]);if(n.type==="user"&&n.uuid)return n.uuid}catch{}}catch{}return null}function Cr(e){if(!e||!dt(e))return null;try{let t=ut(e,"utf8").trimEnd().split(`
|
|
6
|
+
`),r=[],n=0,s=0,o=!1;for(let a=t.length-1;a>=0;a--)try{let l=JSON.parse(t[a]);if(l.type==="user"){if(o)break;continue}if(l.type==="assistant"){o=!0;let u=(l.message?.content??[]).filter(f=>f.type==="text").map(f=>f.text).join("");u&&r.unshift(u);let d=l.message?.usage??{};n+=(d.input_tokens??0)+(d.cache_read_input_tokens??0)+(d.cache_creation_input_tokens??0),s+=d.output_tokens??0;}}catch{}return !r.length&&n===0?null:{text:r.join(`
|
|
7
7
|
|
|
8
|
-
`),inputTokens:n,outputTokens:s}}catch{}return null}
|
|
8
|
+
`),inputTokens:n,outputTokens:s}}catch{}return null}pt.exports={readPromptUuid:kr,readLastAssistantOutput:Cr};});var X=_((Ao,Et)=>{var{readFileSync:Rr,existsSync:ft,readdirSync:Ur}=c("fs"),{homedir:_t}=c("os"),{join:v,extname:Pr}=c("path"),br=new Set([".venv","__pycache__",".git","node_modules"]),vr=new Set([".pyc",".pyo"]),$r=new Set(["SKILL.md",".DS_Store",".gitignore"]);function Fr(e,t){if(!e)return null;let r=[v(_t(),".claude","skills",e,"SKILL.md"),v(t||"",".claude","skills",e,"SKILL.md")];for(let n of r)if(ft(n))try{return Rr(n,"utf8")}catch{}return null}function qr(e){return e.match(/^\/([a-z][a-z0-9-]*)(?:\s.*)?$/i)?.[1]||null}var St=new Set(["Read","Write","Edit","MultiEdit","Bash","Glob","Grep","TodoWrite","WebFetch","WebSearch","Agent","Task"]);function Br(e){return !!e.slashSkill||e.toolCalls.some(n=>n.tool==="Skill")?e.toolCalls.some(n=>St.has(n.tool))?"complete":"prerequisite_required":null}function Dr(e,t){if(!e)return null;let r=[v(_t(),".claude","skills",e),v(t||"",".claude","skills",e)],n=null;for(let a of r)if(ft(v(a,"SKILL.md"))){n=a;break}if(!n)return null;let s=[];function o(a,l){for(let p of Ur(a,{withFileTypes:true})){if(br.has(p.name)||$r.has(p.name)||vr.has(Pr(p.name)))continue;let u=l?`${l}/${p.name}`:p.name;p.isDirectory()?o(v(a,p.name),u):s.push(u);}}return o(n,""),s.length>0?s:null}Et.exports={readSkillContent:Fr,readSkillArtifacts:Dr,detectSlashSkill:qr,EXECUTION_TOOLS:St,detectExecutionStatus:Br};});var Ot=_((yo,gt)=>{var{generateTraceId:Tt,generateSpanId:xr,nowNs:Mr}=H(),{saveState:Hr}=G(),{readPromptUuid:Gr}=Oe(),{detectSlashSkill:Wr,readSkillContent:Yr,readSkillArtifacts:Kr}=X(),{passthrough:Vr}=b(),{dbg:ht}=L(),{ENV:Jr}=h(),{resolveCredentials:jr}=M();async function zr(e){let t=e.session_id||"unknown",r=e.prompt||"",n=e.cwd||"";try{(await jr()).authError===!0&&(process.stderr.write(`
|
|
9
|
+
\u26A0 flow-ai-obs: Your Flow credentials have expired.
|
|
10
|
+
Traces will not be captured until you re-authenticate.
|
|
11
|
+
Run: flow-ai-obs auth login
|
|
12
|
+
|
|
13
|
+
`),ht("UserPromptSubmit","auth expired \u2014 warning emitted to stderr"));}catch{}let s=Gr(e.transcript_path)||Tt(),o=Wr(r),a=o?Yr(o,n):null,l=o?Kr(o,n):null;Hr(t,{traceId:Tt(),spanId:xr(),startNs:Mr(),sessionId:t,prompt:r,cwd:n,traceName:s,transcriptPath:e.transcript_path||"",model:process.env[Jr.ANTHROPIC_MODEL]||"",toolCalls:[],spans:[],pendingTool:null,slashSkill:o,skillContent:a,skillArtifacts:l}),ht("UserPromptSubmit",`sid=${t}`,`traceName=${s}`,`slashSkill=${o}`),Vr(e);}gt.exports={onUserPromptSubmit:zr};});var yt=_((mo,At)=>{var{nowNs:Xr}=H(),{loadState:Zr,saveState:Qr}=G(),{truncate:es,passthrough:ts}=b(),{dbg:ns}=L(),{TRACE_LIMITS:rs}=h();async function ss(e){let t=e.session_id||"unknown",r=e.tool_name||"unknown",n=e.tool_input||{},s=Zr(t);s&&(s.pendingTool={name:r,inputStr:es(n,rs.TOOL_INPUT),startNs:Xr()},Qr(t,s)),ns("PreToolUse",`sid=${t}`,`tool=${r}`,`stateFound=${!!s}`),ts(e);}At.exports={onPreToolUse:ss};});var wt=_((Lo,Lt)=>{var os=c("https"),as=c("http"),{FLOW_URLS:is}=h();function cs(e){let t=new URL(e),r=new URL(is.GATEWAY_HEALTH);return r.hostname=t.hostname,r.port=t.port,r.protocol=t.protocol,r}function mt(e,t){return new Promise((r,n)=>{let o=(e._isSSL?os:as).request(e,a=>{let l=[];a.on("data",p=>l.push(p)),a.on("end",()=>r({statusCode:a.statusCode,body:l.join("")}));});o.on("error",a=>n(new Error(`Network error: ${a.message}`))),t&&o.write(t),o.end();})}async function ls(e){let t;try{t=cs(e);}catch{return false}let r=t.protocol==="https:";try{let n=await mt({hostname:t.hostname,port:t.port||(r?443:80),path:t.pathname,method:"GET",_isSSL:r},null);return n.statusCode>=200&&n.statusCode<300}catch{return false}}async function us(e,t,r){let n=JSON.stringify(e),s=new URL(t),o=s.protocol==="https:",a=String(r).replace(/[\r\n]/g,"");try{return (await mt({hostname:s.hostname,port:s.port||(o?443:80),path:s.pathname,method:"POST",headers:{"Content-Type":"application/json",Authorization:a,"Content-Length":Buffer.byteLength(n)},_isSSL:o},n)).statusCode}catch{return 0}}Lt.exports={checkHealth:ls,sendTraces:us};});var Ct=_((wo,kt)=>{var w=c("fs"),Ae=c("path"),Nt=c("os"),{BUFFER:W}=h(),{dbg:Y}=L();function It(e){if(/[/\\]/.test(e))throw new Error(`Invalid buffer fileId: ${e}`);return Ae.join(Nt.tmpdir(),`${W.FILE_PREFIX}${e}.json`)}function ye(){let e=Nt.tmpdir(),t;try{t=w.readdirSync(e);}catch{return []}return t.filter(r=>r.startsWith(W.FILE_PREFIX)&&r.endsWith(".json")).map(r=>{let n=Ae.join(e,r),s=0;try{s=w.statSync(n).mtimeMs;}catch{}return {full:n,mtime:s}}).sort((r,n)=>r.mtime-n.mtime).map(r=>r.full)}function ds(e){try{let t=ye();if(t.length>=W.MAX_FILES){let s=t.slice(0,t.length-W.MAX_FILES+1);for(let o of s)try{w.unlinkSync(o);}catch{}}let r=`${Date.now()}-${Math.random().toString(36).slice(2,8)}`,n={fileId:r,bufferedAt:Date.now(),payload:e};return w.writeFileSync(It(r),JSON.stringify(n),"utf8"),Y("buffer",`saved fileId=${r}`),r}catch(t){return Y("buffer",`saveToBuffer failed: ${t.message}`),null}}function ps(){let e=ye(),t=[];for(let r of e)try{let n=w.readFileSync(r,"utf8"),s=JSON.parse(n);s&&s.fileId&&s.payload&&t.push(s);}catch{Y("buffer",`skipping malformed file: ${r}`);}return t}function fs(e){try{w.unlinkSync(It(e)),Y("buffer",`deleted fileId=${e}`);}catch{}}function _s(){let e=ye(),t=Date.now()-W.MAX_AGE_MS;for(let r of e)try{let{mtimeMs:n}=w.statSync(r);n<t&&(w.unlinkSync(r),Y("buffer",`evicted stale: ${Ae.basename(r)}`));}catch{}}kt.exports={saveToBuffer:ds,loadBuffer:ps,deleteBuffer:fs,cleanStaleBuffers:_s};});var me=_((No,bt)=>{var{resolveCredentials:Ss}=M(),{OTLP:Rt}=h(),{dbg:$}=L(),{checkHealth:Es,sendTraces:Pt}=wt(),{saveToBuffer:Ut,loadBuffer:Ts,deleteBuffer:hs,cleanStaleBuffers:gs}=Ct(),Os={name:Rt.SCOPE_NAME,version:Rt.SCOPE_VERSION},As={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 ys(e,t){return t==null||t===""?null:{key:e,value:{stringValue:String(t)}}}function ms(...e){return e.filter(Boolean)}function Ls(e,t){return {resourceSpans:[{resource:{attributes:e},scopeSpans:[{scope:Os,spans:Array.isArray(t)?t:[t]}]}]}}function ws(e,t){return new Promise(r=>{let n=JSON.stringify(e),s=new URL(t.endpoint),o=s.protocol==="https:",a=d=>String(d).replace(/[\r\n]/g,""),l={hostname:s.hostname,port:s.port||(o?443:80),path:s.pathname,method:"POST",headers:{"Content-Type":"application/json",Authorization:a(t.authHeader),"Content-Length":Buffer.byteLength(n)}},u=(o?c("https"):c("http")).request(l,d=>{d.resume(),r(d.statusCode);});u.on("error",()=>r(0)),u.write(n),u.end();})}async function Ns(e){gs();let t=Ts();if(t.length){$("replayBufferedTraces",`replaying ${t.length} buffered trace(s)`);for(let r of t)try{let n=await Pt(r.payload,e.endpoint,e.authHeader);n>=200&&n<300?(hs(r.fileId),$("replayBufferedTraces",`replayed fileId=${r.fileId} status=${n}`)):$("replayBufferedTraces",`replay failed fileId=${r.fileId} status=${n}`);}catch(n){$("replayBufferedTraces",`replay error fileId=${r.fileId}: ${n.message}`);}}}async function Is(e){let t=await Ss();return t.length?(await Promise.all(t.map(async n=>n.mode==="gateway"?await Es(n.endpoint)?(await Ns(n),Pt(e,n.endpoint,n.authHeader)):($("postToLangfuse","gateway health check failed \u2014 buffering trace"),Ut(e),0):ws(e,n)))).find(n=>n!==0)||0:(t.authError&&($("postToLangfuse","auth refresh failed \u2014 buffering trace"),Ut(e)),0)}bt.exports={LF:As,a:ys,attrs:ms,buildPayload:Ls,postToLangfuse:Is};});var Le=_((Io,vt)=>{var g="[REDACTED]",ks=[{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,r)=>`${t}
|
|
9
14
|
${g}
|
|
10
|
-
${r}`},{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:(t
|
|
11
|
-
`)),
|
|
12
|
-
`),process.stdout.write(JSON.stringify(
|
|
15
|
+
${r}`},{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,r)=>`${t}${r}${g}${r}`},{re:/([a-z][a-z0-9+\-.]*:\/\/[^:/?#\s]*):([^@\s]+)@/gi,replace:(e,t)=>`${t}:${g}@`}];function Cs(e){if(e==null)return "";let t=typeof e=="string"?e:JSON.stringify(e);return ks.reduce((r,{re:n,replace:s})=>r.replace(n,s),t)}vt.exports={sanitize:Cs,REDACTED:g};});var Mt=_((ko,xt)=>{var{generateSpanId:Rs,nowNs:Us}=H(),{loadState:Ps,saveState:bs}=G(),{LF:K,a:I,attrs:vs}=me(),{truncate:$t,firstLine:$s,passthrough:Ft}=b(),{readSkillContent:Fs,readSkillArtifacts:qs}=X(),{dbg:qt}=L(),{TRACE_LIMITS:Bt}=h(),{sanitize:Dt}=Le();async function Bs(e){let t=e.session_id||"unknown",r=e.tool_name||"unknown",n=e.tool_input||{},s=e.tool_response||"",o=Ps(t);if(!o){Ft(e);return}let a=Us(),l=o.pendingTool?.name===r,p=l?o.pendingTool.startNs:String(BigInt(a)-200000000n),u=l?o.pendingTool.inputStr:$t(n,Bt.TOOL_INPUT),d=u;if(r==="Skill"){let N=typeof n=="object"&&n!==null?n.skill||n.name||n.skillName||String(Object.values(n)[0]??""):String(n),m=N?Fs(N.trim(),o.cwd):null;m&&(d=m,o.skillContent||(o.skillContent=m),o.slashSkill||(o.slashSkill=N.trim()),o.skillArtifacts||(o.skillArtifacts=qs(N.trim(),o.cwd))),qt("PostToolUse","Skill tool detected",`skillName=${N}`,`contentFound=${!!m}`);}let f=Dt($t(s,Bt.TOOL_OUTPUT)),E=/\b(error|exception|failed|failure|traceback|errno)\b/i.test(f.slice(0,500)),O=E?"ERROR":"DEFAULT",y=Rs(),J=Math.round(Number(BigInt(a)-BigInt(p))/1e6),te={Agent:"AGENT",Task:"AGENT"}[r]??"TOOL";o.toolCalls.push({tool:r,brief:$s(u,60),error:E,durationMs:J}),o.spans.push({traceId:o.traceId,spanId:y,parentSpanId:o.spanId,name:r,kind:3,startTimeUnixNano:p,endTimeUnixNano:a,attributes:vs(I(K.OBS_NAME,r),I(K.OBS_TYPE,te),I(K.OBS_LEVEL,O),I(K.OBS_INPUT,Dt(d)),I(K.OBS_OUTPUT,f),I("tool.name",r),I("tool.error",String(E))),status:{code:E?2:1}}),o.pendingTool=null,bs(t,o),qt("PostToolUse",`sid=${t}`,`tool=${r}`,`error=${E}`,`durationMs=${J}`,`totalSpans=${o.spans.length}`),Ft(e);}xt.exports={onPostToolUse:Bs};});var Gt=_((Co,Ht)=>{var we={"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 Ds(e,t,r){let n=Object.keys(we).find(a=>(e||"").toLowerCase().includes(a));if(!n)return;let s=we[n],o=(t*s.input+r*s.output)/1e6;return Math.round(o*1e6)/1e6}Ht.exports={MODEL_PRICING:we,calcCostUsd:Ds};});var Jt=_((Ro,Vt)=>{var{generateSpanId:Wt,nowNs:xs}=H(),{loadState:Ms,deleteState:Yt}=G(),{LF:T,a:i,attrs:Z,buildPayload:Hs,postToLangfuse:Gs}=me(),{getIdentityFromToken:Ws}=M(),{calcCostUsd:Ys}=Gt(),{readLastAssistantOutput:Ks}=Oe(),{truncate:Q,firstLine:Vs,passthrough:Ne}=b(),{dbg:V}=L(),{detectExecutionStatus:Js}=X(),{sanitize:Kt}=Le(),{TRACE_LIMITS:ee}=h();async function js(e){let t=e.session_id||"unknown",r=e.stop_reason||"end_turn",n=Ms(t);if(!n){Ne(e);return}let s=xs(),o=await Ws();if(n.slashSkill&&!n.toolCalls.some(S=>S.tool==="Skill")){let S=Wt(),F=n.skillContent?n.skillContent:JSON.stringify({skill:n.slashSkill});n.toolCalls.push({tool:"Skill",brief:n.slashSkill,error:false,durationMs:0,synthetic:true}),n.spans.push({traceId:n.traceId,spanId:S,parentSpanId:n.spanId,name:"Skill",kind:3,startTimeUnixNano:n.startNs,endTimeUnixNano:n.startNs,attributes:Z(i(T.OBS_NAME,"Skill"),i(T.OBS_TYPE,"TOOL"),i(T.OBS_LEVEL,"DEFAULT"),i(T.OBS_INPUT,F),i(T.OBS_OUTPUT,"loaded via slash command"),i("tool.name","Skill"),i("tool.error","false"),i("skill.name",n.slashSkill),i("skill.invocation","slash-command")),status:{code:1}}),V("Stop",`slashSkill=${n.slashSkill}`,"synthetic span injected");}let a=e.transcript_path||n.transcriptPath||"",l=Ks(a),p=n.toolCalls.length,u=n.toolCalls.filter(S=>S.error).length,d=Kt(l?.text?Q(l.text,ee.TRACE_OUTPUT):p===0?"No tools used":n.toolCalls.map((S,F)=>`${F+1}. ${S.tool}${S.brief?` \u2192 ${S.brief}`:""}${S.error?" [ERROR]":""}`).join(`
|
|
16
|
+
`)),f=l?.inputTokens??0,E=l?.outputTokens??0,O=n.toolCalls.map((S,F)=>`${F+1}. ${S.tool}${S.brief?` \u2192 ${S.brief}`:""}${S.error?" [ERROR]":""} (${S.durationMs}ms)`),y=!!(n.slashSkill||n.toolCalls.some(S=>S.tool==="Skill")),J=n.toolCalls.some(S=>S.tool==="Agent");if(!y&&!J){V("Stop",`sid=${t}`,"skipping trace \u2014 no Skill or Agent calls found"),Yt(t),Ne(e);return}let j=y?"skill":"agent",te=Math.round(Number(BigInt(s)-BigInt(n.startNs))/1e6),N=Ys(n.model,f,E),m=Js(n);m==="prerequisite_required"&&(n.spans.push({traceId:n.traceId,spanId:Wt(),parentSpanId:n.spanId,name:"prerequisite-check",kind:3,startTimeUnixNano:n.startNs,endTimeUnixNano:s,attributes:Z(i(T.OBS_NAME,"prerequisite-check"),i(T.OBS_TYPE,"EVENT"),i(T.OBS_LEVEL,"WARNING"),i(T.OBS_OUTPUT,d),i("skill.name",n.slashSkill||void 0),i("execution_status","prerequisite_required")),status:{code:1}}),V("Stop",`sid=${t}`,"prerequisite-check span injected",`skill=${n.slashSkill}`));let Ie=(()=>{if(!(!y||!n.prompt)){if(n.slashSkill){let S=n.prompt.replace(new RegExp(`^\\/${n.slashSkill}\\s*`,"i"),"").trim();return S?Q(S,ee.USER_INSTRUCTION):void 0}return Q(n.prompt,ee.USER_INSTRUCTION)||void 0}})(),jt=JSON.stringify({trace_type:j,...m!==null&&{execution_status:m},...n.slashSkill&&{skill_name:n.slashSkill},...n.skillArtifacts?.length&&{skill_artifacts:n.skillArtifacts},...Ie!==void 0&&{user_instruction:Ie},latency_ms:te,...f&&{tokens_input:f},...E&&{tokens_output:E},cost_usd:N,...n.model&&{model:n.model},toolCount:p,errorCount:u,stopReason:r,sessionId:n.sessionId,tools:O.length?O:void 0}),zt=Kt(Q(n.prompt,ee.TRACE_INPUT)),Xt=Z(i(T.TRACE_NAME,n.traceName),i(T.TRACE_INPUT,zt),i(T.TRACE_OUTPUT,d),i(T.TRACE_METADATA,jt),i(T.SESSION_ID,n.sessionId),i(T.USER_ID,o.user),i(T.OBS_TYPE,"GENERATION"),i(T.MODEL,n.model),f?i(T.INPUT_TOKENS,f):null,E?i(T.OUTPUT_TOKENS,E):null,i("claude.stop_reason",r),i("claude.tool_count",String(p)),i("claude.error_count",String(u)),i("claude.session_id",n.sessionId),i("flow.trace_type",j),{key:T.TRACE_TAGS,value:{arrayValue:{values:[{stringValue:j}]}}}),Zt={traceId:n.traceId,spanId:n.spanId,name:n.traceName,kind:1,startTimeUnixNano:n.startNs,endTimeUnixNano:s,attributes:Xt,status:{code:u>0?2:1}},Qt=Z(i("service.name",process.env.LANGFUSE_PROJECT_NAME||"claude-code"),i("deployment.environment",process.env.LANGFUSE_ENVIRONMENT||"default")),ke=[...n.spans||[],Zt];V("Stop",`sid=${t}`,`totalTools=${p}`,`errorTools=${u}`,`spans=${ke.length}`,`inputTokens=${f}`,`outputTokens=${E}`,`traceOutput="${Vs(d,80)}"`);let en=await Gs(Hs(Qt,ke));V("Stop",`POST status=${en}`,`traceId=${n.traceId}`),Yt(t),Ne(e);}Vt.exports={onStop:js};});var{credentialsAvailable:zs}=M(),{readInput:Xs}=b(),{onUserPromptSubmit:Zs}=Ot(),{onPreToolUse:Qs}=yt(),{onPostToolUse:eo}=Mt(),{onStop:to}=Jt();async function no(){let e=process.argv[2];if(!await zs()){let r=[];process.stdin.on("data",n=>r.push(n)),process.stdin.on("end",()=>process.stdout.write(r.join("")));return}let t=await Xs();switch(e){case "UserPromptSubmit":await Zs(t);break;case "PreToolUse":await Qs(t);break;case "PostToolUse":await eo(t);break;case "Stop":await to(t);break;default:process.stderr.write(`[flow-obs] unknown event: ${e}
|
|
17
|
+
`),process.stdout.write(JSON.stringify(t));}}no().catch(e=>{process.stderr.write(`[flow-obs] fatal: ${e.message}
|
|
13
18
|
`),process.exit(0);});
|
package/dist/setup.js
CHANGED
|
@@ -1,51 +1,55 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
'use strict';var i=(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 u=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var E=u((sn,Q)=>{var h=process.env.FLOW_BASE_URL||"https://flow.ciandt.com",Z={AUTH_ENGINE:process.env.FLOW_AUTH_ENGINE_URL||`${h}/auth-engine-api/v2/api-key/token`,GATEWAY_TRACES:process.env.FLOW_GATEWAY_TRACES_URL||`${h}/flow-langfuse-gateway/v1/traces`,GATEWAY_HEALTH:process.env.FLOW_GATEWAY_HEALTH_URL||`${h}/flow-langfuse-gateway/v1/health`,OTEL_ENDPOINT:process.env.FLOW_OTEL_ENDPOINT_URL||`${h}/otel`},Me={SERVICE:"flow-plugins-cli",ACCOUNT_CREDS:"credentials",ACCOUNT_TOKEN:"token-cache"},Ge="FLOW-nodejs",Ve="config.json",Ye={SCOPE_NAME:"flow-ai-obs",SCOPE_VERSION:"0.1.0"},We={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"},$e={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",FLOW_OBS_DEBUG:"FLOW_TELEMETRY_DEBUG",FLOW_OBS_ALLOW_HTTP:"FLOW_TELEMETRY_ALLOW_HTTP"},Be={LOCK_STALE_MS:3e4,CONNECTIVITY_MAX_RETRY:3,CONNECTIVITY_RETRY_MS:2e3},je={UserPromptSubmit:5,PreToolUse:3,PostToolUse:10,Stop:15},Je={FILE_PREFIX:"flow-obs-buffer-",MAX_AGE_MS:5760*60*1e3,MAX_FILES:50},Ke="flow-ai-obs-debug.log",He={TOOL_INPUT:2e4,TOOL_OUTPUT:2e4,TRACE_OUTPUT:2e4,USER_INSTRUCTION:1e4,TRACE_INPUT:5e4,TOOL_BRIEF:60},Xe="flow-obs-";Q.exports={FLOW_BASE_URL:h,FLOW_URLS:Z,VAULT:Me,CONFIG_DIR_NAME:Ge,CONFIG_FILE_NAME:Ve,OTLP:Ye,NATIVE_OTEL:We,ENV:$e,INSTALLER:Be,HOOK_TIMEOUTS:je,BUFFER:Je,DEBUG_LOG_FILENAME:Ke,STATE_FILE_PREFIX:Xe,TRACE_LIMITS:He};});var ne=u((on,te)=>{var O=i("fs"),T=i("path"),ze=i("os"),{CONFIG_DIR_NAME:x,CONFIG_FILE_NAME:b}=E(),D={credentials:"credentials","token-cache":"tokenCache"};function L(){let e=ze.homedir();if(process.platform==="darwin")return T.join(e,"Library","Preferences",x,b);if(process.platform==="win32"){let n=process.env.APPDATA||T.join(e,"AppData","Roaming");return T.join(n,x,b)}let t=process.env.XDG_CONFIG_HOME||T.join(e,".config");return T.join(t,x,b)}function q(){try{let e=O.readFileSync(L(),"utf8");return JSON.parse(e)}catch{return {}}}function ee(e){let t=L();O.mkdirSync(T.dirname(t),{recursive:true}),O.writeFileSync(t,JSON.stringify(e,null,2),{encoding:"utf8",mode:384});}var M=class{static isAvailable(){return true}static hasExistingData(){try{if(!O.existsSync(L()))return !1;let t=JSON.parse(O.readFileSync(L(),"utf8"));return !!(t&&t.credentials)}catch{return false}}async getSecret(t,n){let r=q(),s=D[n]||n,o=r[s];return o?typeof o=="string"?o:JSON.stringify(o):null}async setSecret(t,n,r){let s=q(),o=D[n]||n;if(n==="token-cache")try{s[o]=JSON.parse(r);}catch{s[o]=r;}else s[o]=r;ee(s);}async deleteSecret(t,n){let r=q(),s=D[n]||n;return s in r?(delete r[s],ee(r),true):false}getStoragePath(){return `config.json (unencrypted) \u2014 ${L()}`}};function Ze(){}te.exports={ScryptFallbackProvider:M,_resetWarningState:Ze};});var se=u((an,re)=>{var{VAULT:A}=E();async function Qe(e,t){let n=[A.ACCOUNT_CREDS,A.ACCOUNT_TOKEN];for(let r of n)try{if(await t.getSecret(A.SERVICE,r)!==null)continue;let o=await e.getSecret(A.SERVICE,r);o!==null&&await t.setSecret(A.SERVICE,r,o);}catch{}}re.exports={migrateFromJsonFallback:Qe};});var ae=u((cn,ie)=>{var{execFile:et,exec:tt}=i("child_process"),{promisify:oe}=i("util"),G=oe(et),nt=oe(tt),V=class{static async isAvailable(){try{return await nt("command -v security"),!0}catch{return false}}async getSecret(t,n){try{let{stdout:r}=await G("security",["find-generic-password","-w","-a",n,"-s",t]);return r.trim()||null}catch{return null}}async setSecret(t,n,r){await G("security",["add-generic-password","-U","-a",n,"-s",t,"-w",r]);}async deleteSecret(t,n){try{return await G("security",["delete-generic-password","-a",n,"-s",t]),!0}catch{return false}}getStoragePath(){return "macOS Keychain"}};ie.exports={MacOsKeyVaultProvider:V};});var de=u((un,le)=>{var{execFile:rt,exec:st,spawn:ot}=i("child_process"),{promisify:ue}=i("util"),ce=ue(rt),it=ue(st),Y=class{static async isAvailable(){try{return await it("command -v secret-tool"),!0}catch{return false}}async getSecret(t,n){try{let{stdout:r}=await ce("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=ot("secret-tool",["store","--label",t,"service",t,"account",n]);c.on("error",o),c.on("close",w=>{w===0?s():o(new Error(`secret-tool exited with code ${w}`));}),c.stdin.write(r),c.stdin.end();});}async deleteSecret(t,n){try{return await ce("secret-tool",["clear","service",t,"account",n]),!0}catch{return false}}getStoragePath(){return "Linux Secret Service (libsecret)"}};le.exports={LinuxKeyVaultProvider:Y};});var pe=u((ln,we)=>{var W=class{static async isAvailable(){try{return await i("keytar").getPassword("__flow_probe__","__flow_probe__"),!0}catch{return false}}async getSecret(t,n){return i("keytar").getPassword(t,n)}async setSecret(t,n,r){await i("keytar").setPassword(t,n,r);}async deleteSecret(t,n){return i("keytar").deletePassword(t,n)}getStoragePath(){return "Windows Credential Manager"}};we.exports={WindowsKeyVaultProvider:W};});var _e=u((dn,Te)=>{async function Ee(){let{ScryptFallbackProvider:e}=ne();if(e.hasExistingData()){let t=await fe();if(t){let{migrateFromJsonFallback:n}=se(),{VAULT:r}=E();if(await n(new e,t),await t.getSecret(r.SERVICE,r.ACCOUNT_CREDS)!==null)return t}return new e}return await fe()??new e}async function fe(){switch(process.platform){case "darwin":{let{MacOsKeyVaultProvider:e}=ae();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}=pe();return await e.isAvailable()?new e:null}default:return null}}var at=Ee;Te.exports={createSecretVaultProvider:Ee,createKeyVaultProvider:at};});var H=u((wn,ye)=>{var{createSecretVaultProvider:ct}=_e(),{VAULT:B}=E(),_=B.SERVICE,j=B.ACCOUNT_CREDS,J=B.ACCOUNT_TOKEN,$=null;function S(){return $||($=ct()),$}async function Se(){let t=await(await S()).getSecret(_,j);if(!t)return null;try{return JSON.parse(t)}catch{return null}}async function ut(e){if(!e.clientId||!e.clientSecret||!e.tenant)throw new Error("clientId, clientSecret and tenant are required");await(await S()).setSecret(_,j,JSON.stringify(e));}async function lt(){let e=await S();await e.deleteSecret(_,j),await e.deleteSecret(_,J);}async function dt(e){await(await S()).setSecret(_,J,JSON.stringify({accessToken:e.accessToken,expiresAt:e.expiresAt}));}async function K(){let t=await(await S()).getSecret(_,J);if(!t)return null;try{let n=JSON.parse(t);return {accessToken:n.accessToken,expiresAt:n.expiresAt}}catch{return null}}async function wt(){let e=await K();return e?new Date(e.expiresAt)>new Date:false}async function pt(){let e=await K();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 ft(){let e=await S();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 Et(){let e=await Se();return !!(e&&e.clientId&&e.clientSecret&&e.tenant)}ye.exports={getFlowCredentials:Se,saveFlowCredentials:ut,clearFlowCredentials:lt,saveTokenCache:dt,getTokenCache:K,isTokenValid:wt,getEmailFromToken:pt,getConfigPath:ft,hasCredentials:Et};});var X=u((pn,he)=>{var Tt=i("https"),_t=i("http"),{FLOW_URLS:St}=E(),yt=/^[a-z0-9][a-z0-9-]{0,62}[a-z0-9]$|^[a-z0-9]$/;function gt(e){if(!yt.test(e))throw new Error(`Invalid tenant value: "${e}". Tenant must be lowercase alphanumeric and hyphens (1-64 chars).`)}var ge={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 ht(e,t){try{let n=JSON.parse(t);if(typeof n.error=="string"&&ge[n.error])return new Error(ge[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 Lt(e){return new Promise((t,n)=>{try{gt(e.tenant);}catch(a){return n(a)}let r=JSON.stringify({clientSecret:e.clientSecret}),s=new URL(St.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}},d=(o?Tt:_t).request(c,a=>{let l=[];a.on("data",R=>l.push(R)),a.on("end",()=>{let R=l.join("");if(a.statusCode>=400)return n(ht(a.statusCode,R));let v;try{v=JSON.parse(R);}catch{return n(new Error("Invalid response from auth engine"))}let qe=v.expires_at??new Date(Date.now()+(v.expires_in??3600)*1e3).toISOString();t({accessToken:v.access_token,expiresAt:qe});});});d.on("error",a=>n(new Error(`Network error: ${a.message}`))),d.write(r),d.end();})}he.exports={getToken:Lt};});var Oe=u((fn,Le)=>{var Ot=!process.env.NO_COLOR&&process.stdout.isTTY;function y(e,t){return Ot?n=>`\x1B[${e}m${n}\x1B[${t}m`:n=>n}var At=y("32","39"),Ct=y("31","39"),Nt=y("33","39"),It=y("36","39"),mt=y("1","22"),Rt=y("2","22");Le.exports={green:At,red:Ct,yellow:Nt,cyan:It,bold:mt,dim:Rt};});var ve=u((En,Re)=>{var{getFlowCredentials:Ae,saveFlowCredentials:vt,clearFlowCredentials:Ut,saveTokenCache:Pt,isTokenValid:Ft,getConfigPath:Ce,hasCredentials:Ne}=H(),{getToken:kt}=X(),{green:P,red:C,yellow:U,cyan:N,bold:Ie,dim:g}=Oe(),xt=/[\x00-\x08\x0B-\x1F\x7F]|\x1b\[[0-9;]*[a-zA-Z]/g;function f(e){return typeof e=="string"?e.replace(xt,""):e}function I(e,t={}){return new Promise((n,r)=>{let{masked:s=false,defaultValue:o=""}=t;process.stdout.write(e+o);let c=o;function w(){try{process.stdin.setRawMode(!1);}catch{}}process.once("uncaughtException",w),process.once("unhandledRejection",w);let d=l=>{if(l===""){a(),r(new Error("SIGINT"));return}if(l==="\r"||l===`
|
|
3
|
-
|
|
4
|
-
`),
|
|
2
|
+
'use strict';var i=(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 p=l((zn,pe)=>{var h=process.env.FLOW_BASE_URL||"https://flow.ciandt.com",fe={AUTH_ENGINE:process.env.FLOW_AUTH_ENGINE_URL||`${h}/auth-engine-api/v2/api-key/token`,GATEWAY_TRACES:process.env.FLOW_GATEWAY_TRACES_URL||`${h}/flow-langfuse-gateway/v1/traces`,GATEWAY_HEALTH:process.env.FLOW_GATEWAY_HEALTH_URL||`${h}/flow-langfuse-gateway/v1/health`,OTEL_ENDPOINT:process.env.FLOW_OTEL_ENDPOINT_URL||`${h}/otel`},ut={SERVICE:"flow-plugins-cli",ACCOUNT_CREDS:"credentials",ACCOUNT_TOKEN:"token-cache"},lt="FLOW-nodejs",dt="config.json",Tt={SCOPE_NAME:"flow-ai-obs",SCOPE_VERSION:"0.1.0"},Et={ANTHROPIC_BASE_URL:process.env.FLOW_LLM_PROXY_URL||`${h}/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"},ft={CLAUDE_CODE_ENABLE_TELEMETRY:"1",OTEL_EXPORTER_OTLP_ENDPOINT:fe.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"},pt={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"},_t={KEYCHAIN_ENABLED:false},wt={LOCK_STALE_MS:3e4,CONNECTIVITY_MAX_RETRY:3,CONNECTIVITY_RETRY_MS:2e3},St={UserPromptSubmit:5,PreToolUse:3,PostToolUse:10,Stop:15},ht={FILE_PREFIX:"flow-obs-buffer-",MAX_AGE_MS:5760*60*1e3,MAX_FILES:50},At="flow-ai-obs-debug.log",yt={TOOL_INPUT:2e4,TOOL_OUTPUT:2e4,TRACE_OUTPUT:2e4,USER_INSTRUCTION:1e4,TRACE_INPUT:5e4,TOOL_BRIEF:60},Ot="flow-obs-";pe.exports={FLOW_BASE_URL:h,FLOW_URLS:fe,VAULT:ut,CONFIG_DIR_NAME:lt,CONFIG_FILE_NAME:dt,OTLP:Tt,LLM_PROXY:Et,NATIVE_OTEL:ft,ENV:pt,FEATURES:_t,INSTALLER:wt,HOOK_TIMEOUTS:St,BUFFER:ht,DEBUG_LOG_FILENAME:At,STATE_FILE_PREFIX:Ot,TRACE_LIMITS:yt};});var Se=l((Zn,we)=>{var R=i("fs"),A=i("path"),gt=i("os"),{CONFIG_DIR_NAME:B,CONFIG_FILE_NAME:W}=p(),K={credentials:"credentials","token-cache":"tokenCache"};function I(){let e=gt.homedir();if(process.platform==="darwin")return A.join(e,"Library","Preferences",B,W);if(process.platform==="win32"){let n=process.env.APPDATA||A.join(e,"AppData","Roaming");return A.join(n,B,W)}let t=process.env.XDG_CONFIG_HOME||A.join(e,".config");return A.join(t,B,W)}function V(){try{let e=R.readFileSync(I(),"utf8");return JSON.parse(e)}catch{return {}}}function _e(e){let t=I();R.mkdirSync(A.dirname(t),{recursive:true}),R.writeFileSync(t,JSON.stringify(e,null,2),{encoding:"utf8",mode:384});}var j=class{static isAvailable(){return true}static hasExistingData(){try{if(!R.existsSync(I()))return !1;let t=JSON.parse(R.readFileSync(I(),"utf8"));return !!(t&&t.credentials)}catch{return false}}async getSecret(t,n){let r=V(),s=K[n]||n,o=r[s];return o?typeof o=="string"?o:JSON.stringify(o):null}async setSecret(t,n,r){let s=V(),o=K[n]||n;if(n==="token-cache")try{s[o]=JSON.parse(r);}catch{s[o]=r;}else s[o]=r;_e(s);}async deleteSecret(t,n){let r=V(),s=K[n]||n;return s in r?(delete r[s],_e(r),true):false}getStoragePath(){return `config.json (unencrypted) \u2014 ${I()}`}};function Lt(){}we.exports={ScryptFallbackProvider:j,_resetWarningState:Lt};});var Ae=l((Qn,he)=>{var{VAULT:m}=p();async function Nt(e,t){let n=[m.ACCOUNT_CREDS,m.ACCOUNT_TOKEN];for(let r of n)try{if(await t.getSecret(m.SERVICE,r)!==null)continue;let o=await e.getSecret(m.SERVICE,r);o!==null&&await t.setSecret(m.SERVICE,r,o);}catch{}}he.exports={migrateFromJsonFallback:Nt};});var ge=l((er,Oe)=>{var{execFile:Ct,exec:It}=i("child_process"),{promisify:ye}=i("util"),J=ye(Ct),Rt=ye(It),X=class{static async isAvailable(){try{return await Rt("command -v security"),!0}catch{return false}}async getSecret(t,n){try{let{stdout:r}=await J("security",["find-generic-password","-w","-a",n,"-s",t]);return r.trim()||null}catch{return null}}async setSecret(t,n,r){await J("security",["add-generic-password","-U","-a",n,"-s",t,"-w",r]);}async deleteSecret(t,n){try{return await J("security",["delete-generic-password","-a",n,"-s",t]),!0}catch{return false}}getStoragePath(){return "macOS Keychain"}};Oe.exports={MacOsKeyVaultProvider:X};});var Ie=l((tr,Ce)=>{var{execFile:mt,exec:vt,spawn:Ut}=i("child_process"),{promisify:Ne}=i("util"),Le=Ne(mt),Pt=Ne(vt),z=class{static async isAvailable(){try{return await Pt("command -v secret-tool"),!0}catch{return false}}async getSecret(t,n){try{let{stdout:r}=await Le("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=Ut("secret-tool",["store","--label",t,"service",t,"account",n]);c.on("error",o),c.on("close",d=>{d===0?s():o(new Error(`secret-tool exited with code ${d}`));}),c.stdin.write(r),c.stdin.end();});}async deleteSecret(t,n){try{return await Le("secret-tool",["clear","service",t,"account",n]),!0}catch{return false}}getStoragePath(){return "Linux Secret Service (libsecret)"}};Ce.exports={LinuxKeyVaultProvider:z};});var me=l((nr,Re)=>{var Z=class{static async isAvailable(){try{return await i("keytar").getPassword("__flow_probe__","__flow_probe__"),!0}catch{return false}}async getSecret(t,n){return i("keytar").getPassword(t,n)}async setSecret(t,n,r){await i("keytar").setPassword(t,n,r);}async deleteSecret(t,n){return i("keytar").deletePassword(t,n)}getStoragePath(){return "Windows Credential Manager"}};Re.exports={WindowsKeyVaultProvider:Z};});var Fe=l((rr,Pe)=>{async function Ue(){let{ScryptFallbackProvider:e}=Se();if(e.hasExistingData()){let t=await ve();if(t){let{migrateFromJsonFallback:n}=Ae(),{VAULT:r}=p();if(await n(new e,t),await t.getSecret(r.SERVICE,r.ACCOUNT_CREDS)!==null)return t}return new e}return await ve()??new e}async function ve(){switch(process.platform){case "darwin":{let{MacOsKeyVaultProvider:e}=ge();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}=me();return await e.isAvailable()?new e:null}default:return null}}var Ft=Ue;Pe.exports={createSecretVaultProvider:Ue,createKeyVaultProvider:Ft};});var D=l((sr,be)=>{var{createSecretVaultProvider:kt}=Fe(),{VAULT:ee}=p(),y=ee.SERVICE,te=ee.ACCOUNT_CREDS,ne=ee.ACCOUNT_TOKEN,Q=null;function O(){return Q||(Q=kt()),Q}async function ke(){let t=await(await O()).getSecret(y,te);if(!t)return null;try{return JSON.parse(t)}catch{return null}}async function bt(e){if(!e.clientId||!e.clientSecret||!e.tenant)throw new Error("clientId, clientSecret and tenant are required");await(await O()).setSecret(y,te,JSON.stringify(e));}async function Dt(){let e=await O();await e.deleteSecret(y,te),await e.deleteSecret(y,ne);}async function Ht(e){await(await O()).setSecret(y,ne,JSON.stringify({accessToken:e.accessToken,expiresAt:e.expiresAt}));}async function re(){let t=await(await O()).getSecret(y,ne);if(!t)return null;try{let n=JSON.parse(t);return {accessToken:n.accessToken,expiresAt:n.expiresAt}}catch{return null}}async function xt(){let e=await re();return e?new Date(e.expiresAt)>new Date:false}async function Mt(){let e=await re();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 qt(){let e=await O();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 ke();return !!(e&&e.clientId&&e.clientSecret&&e.tenant)}be.exports={getFlowCredentials:ke,saveFlowCredentials:bt,clearFlowCredentials:Dt,saveTokenCache:Ht,getTokenCache:re,isTokenValid:xt,getEmailFromToken:Mt,getConfigPath:qt,hasCredentials:$t};});var H=l((or,He)=>{var Yt=i("https"),Gt=i("http"),{FLOW_URLS:Bt}=p(),Wt=/^[a-z0-9][a-z0-9-]{0,62}[a-z0-9]$|^[a-z0-9]$/;function Kt(e){if(!Wt.test(e))throw new Error(`Invalid tenant value: "${e}". Tenant must be lowercase alphanumeric and hyphens (1-64 chars).`)}var De={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 Vt(e,t){try{let n=JSON.parse(t);if(typeof n.error=="string"&&De[n.error])return new Error(De[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 jt(e){return new Promise((t,n)=>{try{Kt(e.tenant);}catch(u){return n(u)}let r=JSON.stringify({clientSecret:e.clientSecret}),s=new URL(Bt.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}},T=(o?Yt:Gt).request(c,u=>{let a=[];u.on("data",f=>a.push(f)),u.on("end",()=>{let f=a.join("");if(u.statusCode>=400)return n(Vt(u.statusCode,f));let w;try{w=JSON.parse(f);}catch{return n(new Error("Invalid response from auth engine"))}let C=w.expires_at??new Date(Date.now()+(w.expires_in??3600)*1e3).toISOString();t({accessToken:w.access_token,expiresAt:C});});});T.on("error",u=>n(new Error(`Network error: ${u.message}`))),T.write(r),T.end();})}He.exports={getToken:jt};});var qe=l((cr,Me)=>{var{writeFileSync:Jt}=i("fs"),{tmpdir:Xt}=i("os"),{join:zt}=i("path"),{DEBUG_LOG_FILENAME:Zt,ENV:Qt}=p(),xe=zt(Xt(),Zt);function en(...e){if(process.env[Qt.FLOW_OBS_DEBUG]!=="1")return;let t=`[${new Date().toISOString()}] ${e.join(" ")}
|
|
3
|
+
`;try{Jt(xe,t,{flag:"a"});}catch(n){process.stderr.write(`[flow-obs debug ERROR] ${n.message}
|
|
4
|
+
`);}}Me.exports={dbg:en,DEBUG_LOG:xe};});var ie=l((ir,Ye)=>{var{getFlowCredentials:se,isTokenValid:tn,getEmailFromToken:v,getTokenCache:nn,saveTokenCache:rn}=D(),{getToken:sn}=H(),{FLOW_BASE_URL:on,ENV:_,FEATURES:oe}=p(),{dbg:g}=qe(),cn=[/^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 an(e){return cn.some(t=>t.test(e))}function x(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 un(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 ce(e){let t;try{t=new URL(e);}catch{throw new Error(`Invalid URL: ${e}`)}if(!(process.env[_.FLOW_OBS_ALLOW_HTTP]==="true")&&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(an(t.hostname))throw new Error(`SSRF: private/loopback host not allowed: ${t.hostname}`);return e}async function ln(){let e=x(process.env[_.ANTHROPIC_AUTH_TOKEN]);if(e)return {user:await v().catch(()=>null)||e.clientId,tenant:e.tenant};if(oe.KEYCHAIN_ENABLED)try{let t=await se();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 dn(e){if(await tn())return (await nn()).accessToken;g("getOrRefreshToken","token expired \u2014 refreshing via auth-engine");let t=await sn(e);return await rn(t),g("getOrRefreshToken",`token refreshed, expires=${t.expiresAt}`),t.accessToken}function Tn(e,t){let n=t&&t.accessToken?t.accessToken:"";return {endpoint:e.replace(/\/$/,"")+"/langfuse/traces",authHeader:`Bearer ${n}`}}function En(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 $e(){let e=[],t=process.env[_.ANTHROPIC_MODEL]||"",n=process.env[_.FLOW_TELEMETRY]==="true",r=process.env[_.LANGFUSE_BASE_URL],s=process.env[_.LANGFUSE_PUBLIC_KEY],o=process.env[_.LANGFUSE_SECRET_KEY];if(n&&r&&s&&o){let a="",f="",w=x(process.env[_.ANTHROPIC_AUTH_TOKEN]);if(w)a=await v().catch(()=>null)||w.clientId,f=w.tenant;else if(oe.KEYCHAIN_ENABLED)try{let G=await se();G&&(a=await v()||G.clientId,f=G.tenant);}catch{}let C={user:a||"",tenant:f||"",team:"",project:"",model:t};e.push({mode:"direct",...En(ce(r),s,o),...C}),g("resolveCredentials","direct mode active",`user=${C.user}`,`tenant=${C.tenant}`);}let c=x(process.env[_.ANTHROPIC_AUTH_TOKEN]);if(g("resolveCredentials",c?"credentials resolved from ANTHROPIC_AUTH_TOKEN":"ANTHROPIC_AUTH_TOKEN absent or invalid"),!c&&oe.KEYCHAIN_ENABLED&&(c=await se(),c&&g("resolveCredentials","credentials resolved from keychain (FEATURES.KEYCHAIN_ENABLED=true)")),!c){if(e.length===0){let a=[];return a.authError=false,a}return e}let d;try{d=await dn(c);}catch(a){if(g("resolveCredentials",`token refresh failed: ${a.message}`),e.length>0)return e;let f=[];return f.authError=true,f}let T={user:await v()||c.clientId,tenant:c.tenant,team:"",project:"",model:t},u=process.env[_.FLOW_TELEMETRY_GATEWAY]||on;return e.push({mode:"gateway",...Tn(ce(u),{accessToken:d}),...T}),e}async function fn(){return (await $e()).length>0}Ye.exports={credentialsAvailable:fn,getIdentityFromToken:ln,resolveCredentials:$e,validateUrl:ce,parseCredsFromAnthropicToken:x,buildAnthropicAuthToken:un};});var le=l((ar,Ke)=>{var E=i("fs"),P=i("path"),Ge=i("os"),{FLOW_URLS:pn,INSTALLER:U,HOOK_TIMEOUTS:M,NATIVE_OTEL:_n,LLM_PROXY:wn}=p(),{getToken:Sn}=H();function ue(){return process.platform==="win32"?P.join(process.env.APPDATA||P.join(Ge.homedir(),"AppData","Roaming"),"Claude","settings.json"):P.join(Ge.homedir(),".claude","settings.json")}var hn=U.LOCK_STALE_MS;function Be(e){try{let t=E.statSync(e);Date.now()-t.mtimeMs>hn&&E.unlinkSync(e);}catch{}try{E.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 We(e){try{E.unlinkSync(e);}catch{}}function An(){let e=ue(),t=e+".lock";E.mkdirSync(P.dirname(e),{recursive:true}),Be(t);try{E.existsSync(e)&&E.copyFileSync(e,e+".bkp");let n={};try{n=JSON.parse(E.readFileSync(e,"utf8"));}catch{}(!n.env||typeof n.env!="object")&&(n.env={}),Object.assign(n.env,_n),Object.assign(n.env,wn),n.otelHeadersHelper="flow-ai-obs otel-headers",(!n.hooks||typeof n.hooks!="object")&&(n.hooks={});let r=(s,o)=>({matcher:"",hooks:[{type:"command",command:`flow-ai-obs ${s}`,timeout:o}]});n.hooks.UserPromptSubmit=[r("UserPromptSubmit",M.UserPromptSubmit)],n.hooks.PreToolUse=[r("PreToolUse",M.PreToolUse)],n.hooks.PostToolUse=[r("PostToolUse",M.PostToolUse)],n.hooks.Stop=[r("Stop",M.Stop)],E.writeFileSync(e,JSON.stringify(n,null,2)+`
|
|
5
|
+
`,"utf8");}finally{We(t);}return e}async function yn(e){let t;try{t=(await Sn(e)).accessToken;}catch{return false}return t?new Promise(n=>{ae(`Bearer ${t}`,n,1);}):false}function ae(e,t,n){let r=new URL(pn.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)}},T=(o?i("https"):i("http")).request(c,u=>{u.resume(),u.statusCode===200||u.statusCode===204?t(true):n<U.CONNECTIVITY_MAX_RETRY?setTimeout(()=>ae(e,t,n+1),U.CONNECTIVITY_RETRY_MS):t(false);});T.on("error",()=>{n<U.CONNECTIVITY_MAX_RETRY?setTimeout(()=>ae(e,t,n+1),U.CONNECTIVITY_RETRY_MS):t(false);}),T.write(s),T.end();}function On(e){let t=ue(),n=t+".lock";E.mkdirSync(P.dirname(t),{recursive:true}),Be(n);try{let r={};try{r=JSON.parse(E.readFileSync(t,"utf8"));}catch{}(!r.env||typeof r.env!="object")&&(r.env={}),Object.assign(r.env,e),E.writeFileSync(t,JSON.stringify(r,null,2)+`
|
|
6
|
+
`,"utf8");}finally{We(n);}}Ke.exports={getClaudeSettingsPath:ue,writeClaudeSettings:An,addEnvToClaudeSettings:On,validateConnectivity:yn};});var je=l((ur,Ve)=>{var gn=!process.env.NO_COLOR&&process.stdout.isTTY;function L(e,t){return gn?n=>`\x1B[${e}m${n}\x1B[${t}m`:n=>n}var Ln=L("32","39"),Nn=L("31","39"),Cn=L("33","39"),In=L("36","39"),Rn=L("1","22"),mn=L("2","22");Ve.exports={green:Ln,red:Nn,yellow:Cn,cyan:In,bold:Rn,dim:mn};});var nt=l((lr,tt)=>{var{getFlowCredentials:de,saveFlowCredentials:Je,clearFlowCredentials:vn,saveTokenCache:Un,isTokenValid:Pn,getConfigPath:Xe,hasCredentials:Fn}=D(),{getToken:kn}=H(),{buildAnthropicAuthToken:bn,parseCredsFromAnthropicToken:ze}=ie(),{addEnvToClaudeSettings:Dn}=le(),{ENV:Te}=p(),{green:$,red:F,yellow:q,cyan:k,bold:Ze,dim:N}=je(),Hn=/[\x00-\x08\x0B-\x1F\x7F]|\x1b\[[0-9;]*[a-zA-Z]/g;function S(e){return typeof e=="string"?e.replace(Hn,""):e}function b(e,t={}){return new Promise((n,r)=>{let{masked:s=false,defaultValue:o=""}=t;process.stdout.write(e+o);let c=o;function d(){try{process.stdin.setRawMode(!1);}catch{}}process.once("uncaughtException",d),process.once("unhandledRejection",d);let T=a=>{if(a===""){u(),r(new Error("SIGINT"));return}if(a==="\r"||a===`
|
|
7
|
+
`){u(),process.stdout.write(`
|
|
8
|
+
`),n(c);return}if(a==="\x7F"){c.length>0&&(c=c.slice(0,-1),process.stdout.write("\b \b"));return}a.startsWith("\x1B")||(c+=a,process.stdout.write(s?"*".repeat(a.length):a));};function u(){process.stdin.setRawMode(false),process.stdin.removeListener("data",T),process.removeListener("uncaughtException",d),process.removeListener("unhandledRejection",d);}process.stdin.setRawMode(true),process.stdin.resume(),process.stdin.setEncoding("utf8"),process.stdin.on("data",T);})}async function Qe(e){try{let t=await de();(!t||t.clientId!==e.clientId||t.clientSecret!==e.clientSecret||t.tenant!==e.tenant)&&await Je(e);}catch{}}async function et(e){let{accessToken:t,expiresAt:n}=await kn(e);await Je(e),await Un({accessToken:t,expiresAt:n});try{let r=bn(e);Dn({[Te.ANTHROPIC_AUTH_TOKEN]:r});}catch{}}async function xn(e){try{return await et(e),process.stdout.write($(` \u2713 Setup complete. Tenant: ${S(e.tenant)}
|
|
5
9
|
|
|
6
|
-
`)),0}catch(t){return process.stderr.write(
|
|
7
|
-
`)),1}}async function
|
|
8
|
-
`);let e=(await
|
|
9
|
-
`)),1;try{await
|
|
10
|
-
`)),1}return process.stdout.write(
|
|
11
|
-
`)),process.stdout.write(` Storage: ${await
|
|
10
|
+
`)),0}catch(t){return process.stderr.write(F(` \u2717 Authentication failed: ${S(t.message)}
|
|
11
|
+
`)),1}}async function Mn(){try{process.stdout.write(`
|
|
12
|
+
`);let e=(await b(k(" ? ")+"Client ID: ")).trim(),t=(await b(k(" ? ")+"Client Secret: ",{masked:!0})).trim(),n=(await b(k(" ? ")+"Tenant: ")).trim();if(!e||!t||!n)return process.stderr.write(F(` \u2717 All fields are required
|
|
13
|
+
`)),1;try{await et({clientId:e,clientSecret:t,tenant:n});}catch(r){return process.stderr.write(F(` \u2717 Authentication failed: ${S(r.message)}
|
|
14
|
+
`)),1}return process.stdout.write($(` \u2713 Setup complete. Tenant: ${S(n)}
|
|
15
|
+
`)),process.stdout.write(` Storage: ${await Xe()}
|
|
12
16
|
|
|
13
|
-
`),0}catch(e){if(e.message==="SIGINT")throw e;return process.stderr.write(
|
|
14
|
-
`)),1}}async function
|
|
15
|
-
`),process.stdout.write(
|
|
16
|
-
`)),process.stdout.write(
|
|
17
|
-
`),process.stdout.write(
|
|
17
|
+
`),0}catch(e){if(e.message==="SIGINT")throw e;return process.stderr.write(F(` \u2717 Unexpected error: ${e.message}
|
|
18
|
+
`)),1}}async function qn(e={}){if(e.clientId&&e.clientSecret&&e.tenant)return xn({clientId:e.clientId,clientSecret:e.clientSecret,tenant:e.tenant});let t=ze(process.env[Te.ANTHROPIC_AUTH_TOKEN]);t&&await Qe(t);let n=t||await de();if(n){process.stdout.write(`
|
|
19
|
+
`),process.stdout.write(Ze(` Already authenticated
|
|
20
|
+
`)),process.stdout.write(N(" Tenant: ")+S(n.tenant)+`
|
|
21
|
+
`),process.stdout.write(N(" Client ID: ")+S(n.clientId)+`
|
|
18
22
|
`),process.stdout.write(`
|
|
19
|
-
`);let
|
|
20
|
-
`),130;throw
|
|
23
|
+
`);let r;try{r=await b(k(" ? ")+"Re-authenticate? (y/N): ");}catch(s){if(s.message==="SIGINT")return process.stdout.write(`
|
|
24
|
+
`),130;throw s}if(r.trim().toLowerCase()!=="y")return process.stdout.write($(` \u2713 Using existing credentials.
|
|
21
25
|
|
|
22
|
-
`)),0}try{return await
|
|
23
|
-
`),130;throw
|
|
24
|
-
`),(await
|
|
26
|
+
`)),0}try{return await Mn()}catch(r){if(r.message==="SIGINT")return process.stdout.write(`
|
|
27
|
+
`),130;throw r}}async function $n(){try{return process.stdout.write(`
|
|
28
|
+
`),(await b(k(" ? ")+"Are you sure? This will remove your local credentials. (y/N): ")).toLowerCase()!=="y"?(process.stdout.write(q(` \u26A0 Logout cancelled
|
|
25
29
|
`)),0):null}catch(e){if(e.message==="SIGINT")return process.stdout.write(`
|
|
26
|
-
`),130;throw e}}async function
|
|
27
|
-
`)),0;if(!e){let t=await
|
|
28
|
-
`)),0}catch{return process.stderr.write(
|
|
29
|
-
`)),1}}async function
|
|
30
|
-
`+
|
|
31
|
-
`)),process.stdout.write(
|
|
32
|
-
`),process.stdout.write(
|
|
33
|
-
`),process.stdout.write(
|
|
34
|
-
`),process.stdout.write(
|
|
30
|
+
`),130;throw e}}async function Yn(e=false){if(!await Fn())return process.stdout.write(q(` \u26A0 You are not authenticated
|
|
31
|
+
`)),0;if(!e){let t=await $n();if(t!==null)return t}try{return await vn(),process.stdout.write($(` \u2713 Credentials removed successfully
|
|
32
|
+
`)),0}catch{return process.stderr.write(F(` \u2717 Error removing credentials
|
|
33
|
+
`)),1}}async function Gn(){let e=ze(process.env[Te.ANTHROPIC_AUTH_TOKEN]);e&&await Qe(e);let t=e||await de();if(!t)return process.stdout.write(q(" \u26A0 Not authenticated. Run `flow-ai-obs auth login` to set up.\n")),0;if(!e&&!await Pn())return process.stdout.write(q(" \u26A0 Session expired. Run `flow-ai-obs auth login` to re-authenticate.\n")),0;let n=t.clientSecret.length>4?"****...****"+t.clientSecret.slice(-4):"****",r=e?"ANTHROPIC_AUTH_TOKEN (settings.json)":await Xe();return process.stdout.write(`
|
|
34
|
+
`+Ze(` Authenticated
|
|
35
|
+
`)),process.stdout.write(N(" Tenant: ")+S(t.tenant)+`
|
|
36
|
+
`),process.stdout.write(N(" Client ID: ")+S(t.clientId)+`
|
|
37
|
+
`),process.stdout.write(N(" Client Secret: ")+n+`
|
|
38
|
+
`),process.stdout.write(N(" Storage: ")+r+`
|
|
35
39
|
|
|
36
|
-
`),0}
|
|
37
|
-
`,"utf8");}finally{Jt(t);}return e}async function Ht(e){let t;try{t=(await $t(e)).accessToken;}catch{return false}return t?new Promise(n=>{z(`Bearer ${t}`,n,1);}):false}function z(e,t,n){let r=new URL(Yt.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)}},d=(o?i("https"):i("http")).request(c,a=>{a.resume(),a.statusCode===200||a.statusCode===204?t(true):n<m.CONNECTIVITY_MAX_RETRY?setTimeout(()=>z(e,t,n+1),m.CONNECTIVITY_RETRY_MS):t(false);});d.on("error",()=>{n<m.CONNECTIVITY_MAX_RETRY?setTimeout(()=>z(e,t,n+1),m.CONNECTIVITY_RETRY_MS):t(false);}),d.write(s),d.end();}Fe.exports={getClaudeSettingsPath:Pe,writeClaudeSettings:Kt,validateConnectivity:Ht};});var xe=i("path"),{hasCredentials:be,getConfigPath:De,isTokenValid:Xt,getFlowCredentials:zt}=H(),{runLogin:Zt}=ve(),{writeClaudeSettings:Qt,validateConnectivity:en}=ke();function tn(){let e=xe.resolve(__dirname,".."),n=(process.env.INIT_CWD?xe.resolve(process.env.INIT_CWD):null)===e;return !process.stdin.isTTY||n||process.env.CI==="true"||process.env.CI==="1"||process.env.npm_config_yes==="true"||process.env.DEBIAN_FRONTEND==="noninteractive"}async function nn(){if(tn()){await be()&&(console.log(`
|
|
38
|
-
[flow-ai-obs] Already authenticated \u2014 skipping setup wizard.`),console.log(" Run `flow-ai-obs install` to register Claude Code hooks.\n"));return}if(console.log(`
|
|
40
|
+
`),0}tt.exports={runLogin:qn,runLogout:Yn,runStatus:Gn};});var rt=i("path"),{hasCredentials:Bn,getConfigPath:st,isTokenValid:Wn,getFlowCredentials:Ee}=D(),{runLogin:Kn}=nt(),{writeClaudeSettings:ot,addEnvToClaudeSettings:ct,validateConnectivity:Vn}=le(),{buildAnthropicAuthToken:it,parseCredsFromAnthropicToken:at}=ie(),{ENV:Y}=p();function jn(){let e=rt.resolve(__dirname,".."),n=(process.env.INIT_CWD?rt.resolve(process.env.INIT_CWD):null)===e;return !process.stdin.isTTY||n||process.env.CI==="true"||process.env.CI==="1"||process.env.npm_config_yes==="true"||process.env.DEBIAN_FRONTEND==="noninteractive"}async function Jn(){if(jn()){try{ot();}catch{}let n=await Ee();if(n){let r=at(process.env[Y.ANTHROPIC_AUTH_TOKEN]);if(!r||r.clientId!==n.clientId||r.clientSecret!==n.clientSecret||r.tenant!==n.tenant)try{let o=it(n);ct({[Y.ANTHROPIC_AUTH_TOKEN]:o});}catch{}}return}if(console.log(`
|
|
39
41
|
\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`),console.log("\u2551 flow-ai-obs \u2014 setup wizard \u2551"),console.log(`\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
|
|
40
|
-
`),await
|
|
41
|
-
`)
|
|
42
|
-
`);
|
|
42
|
+
`),await Bn()&&await Wn()){console.log(` \u2713 Already authenticated. Config: ${await st()}`),console.log(" Run `flow-ai-obs auth status` to inspect."),console.log(" Run `flow-ai-obs auth login` to re-authenticate.\n");let n=await Ee(),r=at(process.env[Y.ANTHROPIC_AUTH_TOKEN]);if(n&&(!r||r.clientId!==n.clientId||r.clientSecret!==n.clientSecret||r.tenant!==n.tenant))try{let o=it(n);ct({[Y.ANTHROPIC_AUTH_TOKEN]:o}),console.log(` \u2713 ANTHROPIC_AUTH_TOKEN refreshed in settings.json
|
|
43
|
+
`);}catch(o){console.log(` \u26A0 Could not refresh ANTHROPIC_AUTH_TOKEN: ${o.message}
|
|
44
|
+
`);}}else {console.log(` Authenticate with your Flow credentials (clientId / clientSecret / tenant).
|
|
45
|
+
`),console.log(" Credentials will be stored in:"),console.log(` ${await st()}
|
|
46
|
+
`);let n=await Kn();n!==0&&(console.error("\n Setup aborted. Run `flow-ai-obs auth login` to retry.\n"),process.exit(n));}try{let n=ot();console.log(` \u2713 Claude settings updated at ${n}`);}catch(n){console.error(`
|
|
43
47
|
[warn] Could not update Claude settings: ${n.message}`);}console.log(`
|
|
44
|
-
Validating connectivity to Flow OTEL endpoint\u2026`);let e=await
|
|
48
|
+
Validating connectivity to Flow OTEL endpoint\u2026`);let e=await Ee();e||(console.error(`
|
|
45
49
|
[error] Could not read stored credentials.
|
|
46
|
-
`),process.exit(1));let t=await
|
|
50
|
+
`),process.exit(1));let t=await Vn(e);console.log(t?` \u2713 Connectivity validated \u2014 telemetry is active.
|
|
47
51
|
`:` \u26A0 Could not reach the OTEL endpoint. Telemetry will activate once connectivity is restored.
|
|
48
52
|
`),console.log(` [done] Setup complete!
|
|
49
|
-
`);}
|
|
53
|
+
`);}Jn().catch(e=>{console.error(`
|
|
50
54
|
[error] ${e.message}
|
|
51
55
|
`),process.exit(1);});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ciandt-flow/flow-ai-obs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Claude Code hooks for Langfuse OTLP tracing — cross-platform",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"typecheck": "node --check src/**/*.js bin/cli.js",
|
|
14
14
|
"lint": "node --check src/**/*.js bin/cli.js",
|
|
15
15
|
"security-scan": "trufflehog filesystem src/ --fail --no-update --exclude-paths .trufflehogignore",
|
|
16
|
-
"postinstall": "node dist/setup.js",
|
|
16
|
+
"postinstall": "node -e \"require('fs').existsSync('dist/setup.js') && require('child_process').execFileSync(process.execPath, ['dist/setup.js'], {stdio:'inherit'})\"",
|
|
17
17
|
"prepublishOnly": "npm run security-scan && npm run build",
|
|
18
18
|
"release:npm": "changeset publish",
|
|
19
19
|
"changeset": "changeset",
|