@ciandt-flow/flow-ai-obs 0.16.1 → 1.0.0-beta.149
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -14
- package/dist/cli.js +161 -247
- package/dist/index.js +13 -21
- package/dist/setup.js +14 -14
- package/package.json +1 -4
package/dist/index.js
CHANGED
|
@@ -1,23 +1,15 @@
|
|
|
1
|
-
'use strict';var
|
|
2
|
-
`;try{
|
|
3
|
-
`);}}var
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Run: flow-ai-obs init
|
|
8
|
-
`;return rt().then(n=>{if(n){let r=n.split(/[\r\n]/)[0].replace(/[\x00-\x1F\x7F]/g,"").trim();if(!r)return;let i=r.indexOf("@"),o=r.slice(i+1);if(!(r.length<=254&&G.EMAIL_HEADER_PATTERN.test(r)&&(r.match(/@/g)??[]).length===1&&i>0&&i<r.length-1&&o.includes("."))){a("maybePersistUserEmail",`${t}: email from token failed basic validation \u2014 skipping persist`);return}try{qt({[E.FLOW_USER_EMAIL]:r}),a("maybePersistUserEmail",`${t}: persisted FLOW_USER_EMAIL from OAuth token`);}catch(c){a("maybePersistUserEmail",`${t}: FLOW_USER_EMAIL write failed: ${c.message}`),process.stderr.write(`\u26A0\uFE0F flow-ai-obs: could not persist FLOW_USER_EMAIL to settings.json.
|
|
9
|
-
Run: flow-ai-obs init
|
|
10
|
-
`);}}else process.stderr.write(e);}).catch(n=>{a("maybePersistUserEmail",`${t}: getEmailFromToken failed: ${n.message}`);})}Pt();var Je=[/^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 ze(t){return Je.some(e=>e.test(t))}function qe(t){if(!t)return null;try{let e=t.split(".");if(e.length<2)return null;let n=JSON.parse(Buffer.from(e[1].replace(/-/g,"+").replace(/_/g,"/"),"base64").toString("utf8"));return n.email||n.preferred_username||n.upn||n.sub||null}catch{return null}}function gt(t){if(!t)return null;try{let e=t.split(".");if(e.length<2)return null;let n=JSON.parse(Buffer.from(e[1].replace(/-/g,"+").replace(/_/g,"/"),"base64").toString("utf8")),{clientId:r,clientSecret:i,tenant:o}=n;return !r||!i||!o?null:{clientId:r,clientSecret:i,tenant:o}}catch{return null}}function Et(t){let e;try{e=new URL(t);}catch{throw new Error(`Invalid URL: ${t}`)}let n=process.env[E.FLOW_OBS_ALLOW_HTTP]==="true";if(!n&&e.protocol!=="https:")throw new Error(`URL must use HTTPS: ${t}`);if(e.username||e.password)throw new Error(`URL must not contain embedded credentials: ${t}`);if(!n&&ze(e.hostname))throw new Error(`SSRF: private/loopback host not allowed: ${e.hostname}`);return t}async function Qt(){let t=gt(process.env[E.ANTHROPIC_AUTH_TOKEN]);return t?{user:await rt().catch(()=>null)??t.clientId,tenant:t.tenant}:{user:"",tenant:""}}function Ze(t){if(!t)return null;let e=t.replace(/[\r\n]/g,"").trim();return e?e.length>G.API_KEY_MAX_LENGTH?(a("validateApiKey",`API key exceeds ${G.API_KEY_MAX_LENGTH} chars \u2014 rejected`),null):G.API_KEY_PATTERN.test(e)?e:(a("validateApiKey","API key contains invalid or unsafe characters \u2014 rejected"),null):null}function Qe(){let t=process.env[E.FLOW_API_KEY];return Ze(t)}function tn(){return new Date().toISOString().slice(0,10)}async function en(t){let e=tn(),n=await It();if(n?.lastAuthCheckAt!==e){a("getOrRefreshToken",`daily auth check (last: ${n?.lastAuthCheckAt??"never"})`);let o=nt.MAX_RETRY_ATTEMPTS;for(let s=1;s<=o;s++)try{let c=await K(t);try{await kt({...c,lastAuthCheckAt:e});}catch(p){a("getOrRefreshToken",`saveTokenCache failed (non-fatal): ${p.message}`);}return a("getOrRefreshToken",`daily check passed (attempt ${s}), expires=${c.expiresAt}`),Qe()?Zt()||await Nt("api-key"):await Nt("oauth"),c.accessToken}catch(c){if(c instanceof F){if(c.statusCode!==500)throw a("getOrRefreshToken",`daily check auth error (${c.statusCode}) \u2014 propagating immediately`),c;if(s<o){a("getOrRefreshToken",`daily check 500 error (attempt ${s}/${o}) \u2014 retrying in 1s`),await new Promise(l=>setTimeout(l,nt.RETRY_DELAY_MS));continue}throw a("getOrRefreshToken",`daily check failed after ${o} attempts \u2014 propagating`),c}a("getOrRefreshToken",`daily check network error \u2014 using cache: ${c.message}`);break}}let r=n!=null&&new Date(n.expiresAt)>new Date;if(a("getOrRefreshToken",`cacheValid=${r}`),r)return a("getOrRefreshToken",`using cached token, expires=${n.expiresAt}`),n.accessToken;a("getOrRefreshToken",`token expired \u2014 refreshing via auth-engine (tenant=${t.tenant} clientId=${t.clientId})`);let i=await K(t);try{await kt({...i,lastAuthCheckAt:e});}catch(o){a("getOrRefreshToken",`token cache save failed (non-fatal): ${o.message}`);}return a("getOrRefreshToken",`token refreshed, expires=${i.expiresAt}`),i.accessToken}function nn(t,e){let n=e&&e.accessToken?e.accessToken:"";return {endpoint:t.replace(/\/$/,"")+"/flow-langfuse-gateway/v1/traces",authHeader:`Bearer ${n}`}}function rn(t,e,n){let r=Buffer.from(`${e}:${n}`).toString("base64");return {endpoint:t.replace(/\/$/,"")+"/api/public/otel/v1/traces",authHeader:`Basic ${r}`}}async function z(){let t=[],e=gt(process.env[E.ANTHROPIC_AUTH_TOKEN]);a("resolveCredentials",e?"credentials resolved from ANTHROPIC_AUTH_TOKEN":"ANTHROPIC_AUTH_TOKEN absent or invalid"),e&&a("resolveCredentials",`clientId=${e.clientId}`,`tenant=${e.tenant}`);let n=e?e.tenant:"",r=process.env[E.FLOW_TELEMETRY]==="true",i=process.env[E.LANGFUSE_BASE_URL],o=process.env[E.LANGFUSE_PUBLIC_KEY],s=process.env[E.LANGFUSE_SECRET_KEY];if(r&&i&&o&&s){let m="",_=n;e&&(m=await rt().catch(()=>null)??e.clientId);let g={user:m??"",tenant:_??"",team:"",project:""};t.push({mode:"direct",...rn(Et(i),o,s),...g}),a("resolveCredentials","direct mode active",`user=${g.user}`,`tenant=${g.tenant}`);}if(!e){if(t.length===0){let m=[];return m.authError=false,m}return t}let c;try{c=await en(e);}catch(m){if(a("resolveCredentials",`token refresh failed: ${m.message}`,`(tenant=${e.tenant} clientId=${e.clientId})`),t.length>0)return t.authError=true,t;let _=[];return _.authError=true,_}let p={user:qe(c)??e.clientId,tenant:n,team:"",project:""},T=process.env[E.FLOW_TELEMETRY_GATEWAY]??Y();return t.push({mode:"gateway",...nn(Et(T),{accessToken:c}),...p}),t}function w(t,e){let n=typeof t=="object"?JSON.stringify(t):String(t??"");return n.length>e?n.slice(0,e)+" \u2026[truncated]":n}function _t(t,e=100){return String(t??"").split(`
|
|
11
|
-
`)[0].slice(0,e).trim()}function ot(){return new Promise(t=>{let e="";process.stdin.setEncoding("utf8"),process.stdin.on("data",n=>{e+=n;}),process.stdin.on("end",()=>{try{t(JSON.parse(e));}catch{t({});}});})}function O(t){process.stdout.write(JSON.stringify(t));}var Ut=()=>crypto.randomBytes(16).toString("hex"),$=()=>crypto.randomBytes(8).toString("hex");function U(){return String(BigInt(Date.now())*1000000n)}var dn=/^[0-9a-f-]{1,64}$/i,mn=j.normalize(st.tmpdir())+j.sep;function En(t,e){let n=j.resolve(t);if(!n.startsWith(e))throw new Error(`Path traversal detected: ${t}`);return n}function bt(t){if(!dn.test(t))throw new Error(`Invalid session ID: ${t}`);return En(j.join(st.tmpdir(),`flow-obs-${t}.json`),mn)}function q(t){let e;try{e=bt(t);}catch{return null}if(!h.existsSync(e))return null;try{return JSON.parse(h.readFileSync(e,"utf8"))}catch{return null}}function Z(t,e){h.writeFileSync(bt(t),JSON.stringify(e),{encoding:"utf8",mode:384});}function vt(t){try{h.unlinkSync(bt(t));}catch{}}function se(t){if(!t||!h.existsSync(t))return null;try{let e=h.readFileSync(t,"utf8").trimEnd().split(`
|
|
12
|
-
`);for(let n=e.length-1;n>=0;n--)try{let r=JSON.parse(e[n]);if(r.type==="user"&&r.uuid)return r.uuid}catch{}}catch{}return null}function Ct(t){if(!t||!h.existsSync(t))return null;try{let e=h.readFileSync(t,"utf8").trimEnd().split(`
|
|
13
|
-
`),n=[],r=0,i=0,o;for(let s=e.length-1;s>=0;s--)try{let c=JSON.parse(e[s]);if(c.type==="user")break;if(c.type==="assistant"){!o&&c.message?.model&&(o=c.message.model);let p=(c.message?.content??[]).filter(m=>m.type==="text").map(m=>m.text??"").join("");p&&n.unshift(p);let T=c.message?.usage??{};r+=(T.input_tokens??0)+(T.cache_read_input_tokens??0)+(T.cache_creation_input_tokens??0),i+=T.output_tokens??0;}}catch{}return !n.length&&r===0?null:{text:n.join(`
|
|
1
|
+
'use strict';var b=require('fs'),H=require('os'),V=require('path'),child_process=require('child_process'),crypto=require('crypto'),Ge=require('https'),Ke=require('http');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var b__namespace=/*#__PURE__*/_interopNamespace(b);var H__namespace=/*#__PURE__*/_interopNamespace(H);var V__namespace=/*#__PURE__*/_interopNamespace(V);var Ge__default=/*#__PURE__*/_interopDefault(Ge);var Ke__default=/*#__PURE__*/_interopDefault(Ke);var C=(t,e,n)=>()=>{if(n)throw n[0];try{return t&&(e=t(t=0)),e}catch(r){throw n=[r],r}};function ue(){let t=process.env.FLOW_BASE_URL;return t&&t.trim()?t.trim():ce}function lt(){let t=ue();return {GATEWAY_TRACES:process.env.FLOW_GATEWAY_TRACES_URL||`${t}/flow-langfuse-gateway/v1/traces`,GATEWAY_HEALTH:process.env.FLOW_GATEWAY_HEALTH_URL||`${t}/flow-langfuse-gateway/v1/health`,OTEL_ENDPOINT:process.env.FLOW_OTEL_ENDPOINT_URL||`${t}/otel`}}var ce,an,ct,E,At,A,F,Ot,L,O=C(()=>{"use strict";ce="https://flow.ciandt.com";an=lt(),ct={SCOPE_NAME:"flow-ai-obs",SCOPE_VERSION:"0.1.0"},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_AUTH_TOKEN:"ANTHROPIC_AUTH_TOKEN",FLOW_OBS_DEBUG:"FLOW_TELEMETRY_DEBUG",FLOW_OBS_ALLOW_HTTP:"FLOW_TELEMETRY_ALLOW_HTTP",FLOW_OBS_SKIP_DESKTOP_DETECTION:"FLOW_OBS_SKIP_DESKTOP_DETECTION",FLOW_OBS_SKIP_COPILOT_DETECTION:"FLOW_OBS_SKIP_COPILOT_DETECTION",BUFFER_TTL_DAYS:"FLOW_TELEMETRY_BUFFER_TTL_DAYS",BUFFER_MAX_FILES:"FLOW_TELEMETRY_BUFFER_MAX_FILES",FLOW_USER_EMAIL:"FLOW_USER_EMAIL",FLOW_API_KEY:"FLOW_API_KEY",OTEL_EXPORTER_OTLP_HEADERS:"OTEL_EXPORTER_OTLP_HEADERS",FLOW_BASE_URL:"FLOW_BASE_URL"},At={LOCK_STALE_MS:3e4,CLI:"flow-ai-obs "},A={FILE_PREFIX:"flow-obs-buffer-",DEFAULT_TTL_DAYS:4,MIN_TTL_DAYS:1,MAX_TTL_DAYS:30,DEFAULT_MAX_FILES:50,MIN_MAX_FILES:1,MAX_MAX_FILES:500,REPLAY_BATCH_SIZE:10},F={API_KEY_MAX_LENGTH:1024,API_KEY_PATTERN:/^[A-Za-z0-9_.\-:=+/]+$/,EMAIL_MAX_LENGTH:254,EMAIL_HEADER_PATTERN:/^[\x21-\x7E]+$/},Ot="flow-ai-obs-debug.log",L={TOOL_INPUT:2e4,TOOL_OUTPUT:2e4,TRACE_OUTPUT:2e4,USER_INSTRUCTION:1e4,TRACE_INPUT:5e4,TOOL_BRIEF:60};});function a(...t){if(process.env[E.FLOW_OBS_DEBUG]!=="1")return;let e=`[${new Date().toISOString()}] ${t.join(" ")}
|
|
2
|
+
`;try{b.writeFileSync(me,e,{flag:"a"});}catch(n){process.stderr.write(`[flow-obs debug ERROR] ${n.message}
|
|
3
|
+
`);}}var me,R=C(()=>{"use strict";O();me=V.join(H.tmpdir(),Ot);});function W(t,e){return Ee?n=>`\x1B[${t}m${n}\x1B[${e}m`:n=>n}var Ee,mn,ge,En,_e,gn,_n,Lt=C(()=>{"use strict";Ee=!process.env.NO_COLOR&&process.stdout.isTTY;mn=W("32","39"),ge=W("31","39"),En=W("33","39"),_e=W("36","39"),gn=W("1","22"),_n=W("2","22");});var Rt=C(()=>{"use strict";Lt();});function kt(t={}){let e=t.env??process.env,n=t.platform??process.platform;return !!(e.WSL_DISTRO_NAME&&n==="linux")}function Se(t,e={}){let n=e.env??process.env,r=e.spawnSync??child_process.spawnSync;if(!kt({env:n,platform:e.platform}))return;let i=n[t];if(!i)try{let o=r("cmd.exe",["/c","echo",`%${t}%`],{encoding:"utf8",timeout:5e3}).stdout?.trim();o&&/^[A-Za-z]:\\/.test(o)&&(i=o);}catch(s){a("resolveWslWindowsPath",`cmd.exe ${t} lookup failed: ${s.message}`);}if(i)return i.replace(/^([A-Za-z]):/,(s,o)=>`/mnt/${o.toLowerCase()}`).replace(/\\/g,"/")}function It(){if(process.platform==="linux"&&process.getuid?.()===0&&process.env.SUDO_USER)try{let e=child_process.spawnSync("getent",["passwd",process.env.SUDO_USER],{encoding:"utf8",timeout:5e3}).stdout?.split(":")[5]?.trim();if(e)return {home:e,username:process.env.SUDO_USER}}catch(t){a("getActualUser",`getent passwd lookup failed: ${t.message}`);}return {home:H__namespace.homedir(),username:process.env.SUDO_USER||process.env.USER||H__namespace.userInfo().username}}function ut(){if(kt()){let t=Se("USERPROFILE");return t?V__namespace.join(t,".claude","settings.json"):V__namespace.join(H__namespace.homedir(),".claude","settings.json")}if(process.platform==="win32"){let t=process.env.USERPROFILE||H__namespace.homedir();return V__namespace.join(t,".claude","settings.json")}return V__namespace.join(It().home,".claude","settings.json")}var pt=C(()=>{"use strict";R();Rt();});var Pt=C(()=>{"use strict";pt();});function Te(t){if(z===void 0)try{let n=b__namespace.readFileSync(ut(),"utf8");z=JSON.parse(n).env??null;}catch{z=null;}if(!z)return null;let e=z[t];return typeof e=="string"?e:null}function wt(t){let e=process.env[t];return e!==void 0?e!==""?e:void 0:Te(t)??void 0}var vn,z,bt=C(()=>{"use strict";O();pt();Pt();vn=At.LOCK_STALE_MS;});O();R();bt();var Ae=[/^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 Oe(t){return Ae.some(e=>e.test(t))}function Le(t){let e;try{e=new URL(t);}catch{throw new Error(`Invalid URL: ${t}`)}let n=process.env[E.FLOW_OBS_ALLOW_HTTP]==="true";if(!n&&e.protocol!=="https:")throw new Error(`URL must use HTTPS: ${t}`);if(e.username||e.password)throw new Error(`URL must not contain embedded credentials: ${t}`);if(!n&&Oe(e.hostname))throw new Error(`SSRF: private/loopback host not allowed: ${e.hostname}`);return t}function Re(t){let e=process.env[E.OTEL_EXPORTER_OTLP_HEADERS];if(!e)return null;let n=t.toLowerCase();for(let r of e.split(",")){let i=r.indexOf("=");if(!(i<=0)&&r.slice(0,i).trim().toLowerCase()===n){let s=r.slice(i+1),o=s.search(/[\r\n]/);return (o===-1?s:s.slice(0,o)).trim()||null}}return null}function dt(){let t=wt(E.FLOW_USER_EMAIL);if(t!==void 0){let n=t.replace(/[\r\n]/g,"").trim();if(n)if(n.length>F.EMAIL_MAX_LENGTH)a("resolveUserEmail",`FLOW_USER_EMAIL exceeds ${F.EMAIL_MAX_LENGTH} chars \u2014 skipping`);else if(!F.EMAIL_HEADER_PATTERN.test(n))a("resolveUserEmail","FLOW_USER_EMAIL contains non-printable or control characters \u2014 skipping");else return a("resolveUserEmail","using FLOW_USER_EMAIL override: [REDACTED]"),n}let e=Re("x-flow-user");if(e){let n=e.replace(/[\r\n]/g,"").trim();if(n.length>F.EMAIL_MAX_LENGTH)a("resolveUserEmail",`x-flow-user from OTEL_EXPORTER_OTLP_HEADERS exceeds ${F.EMAIL_MAX_LENGTH} chars \u2014 skipping`);else if(!F.EMAIL_HEADER_PATTERN.test(n))a("resolveUserEmail","x-flow-user from OTEL_EXPORTER_OTLP_HEADERS is empty or contains non-printable characters \u2014 skipping");else return a("resolveUserEmail","using x-flow-user from OTEL_EXPORTER_OTLP_HEADERS: [REDACTED]"),n}try{let n=H__namespace.default.userInfo().username||process.env.USERNAME||process.env.USER||"",r=n.lastIndexOf("\\");if(r!==-1&&(n=n.slice(r+1)),n=n.trim().replace(/[^a-zA-Z0-9._%+\-]/g,"").replace(/^\.+/,""),!n)return a("resolveUserEmail","Could not derive x-flow-user: username is empty. Run: flow-ai-obs init"),null;let i=`${n}@ciandt.com`;return a("resolveUserEmail","derived email: [REDACTED]"),i}catch(n){return a("resolveUserEmail",`Could not derive x-flow-user from OS username: ${n.message}. Run: flow-ai-obs init`),null}}function ye(t,e,n){let r=Buffer.from(`${e}:${n}`).toString("base64");return {endpoint:t.replace(/\/$/,"")+"/api/public/otel/v1/traces",authHeader:`Basic ${r}`}}async function nt(){let t=[],e=process.env[E.FLOW_TELEMETRY]==="true",n=process.env[E.LANGFUSE_BASE_URL],r=process.env[E.LANGFUSE_PUBLIC_KEY],i=process.env[E.LANGFUSE_SECRET_KEY];if(e&&n&&r&&i){let s={user:dt()??"",tenant:"",team:"",project:""};t.push({mode:"direct",...ye(Le(n),r,i),...s}),a("resolveCredentials","direct mode active",`user=${s.user}`);}return t}function y(t,e){let n=typeof t=="object"?JSON.stringify(t):String(t??"");return n.length>e?n.slice(0,e)+" \u2026[truncated]":n}function rt(t,e=100){return String(t??"").split(`
|
|
4
|
+
`)[0].slice(0,e).trim()}function J(){return new Promise(t=>{let e="";process.stdin.setEncoding("utf8"),process.stdin.on("data",n=>{e+=n;}),process.stdin.on("end",()=>{try{t(JSON.parse(e));}catch{t({});}});})}function g(t){process.stdout.write(JSON.stringify(t));}var ft=()=>crypto.randomBytes(16).toString("hex"),D=()=>crypto.randomBytes(8).toString("hex");function w(){return String(BigInt(Date.now())*1000000n)}var Ce=/^[0-9a-f-]{1,64}$/i,Fe=V.normalize(H.tmpdir())+V.sep;function De(t,e){let n=V.resolve(t);if(!n.startsWith(e))throw new Error(`Path traversal detected: ${t}`);return n}function mt(t){if(!Ce.test(t))throw new Error(`Invalid session ID: ${t}`);return De(V.join(H.tmpdir(),`flow-obs-${t}.json`),Fe)}function Y(t){let e;try{e=mt(t);}catch{return null}if(!b.existsSync(e))return null;try{return JSON.parse(b.readFileSync(e,"utf8"))}catch{return null}}function j(t,e){b.writeFileSync(mt(t),JSON.stringify(e),{encoding:"utf8",mode:384});}function Et(t){try{b.unlinkSync(mt(t));}catch{}}function Ft(t){if(!t||!b.existsSync(t))return null;try{let e=b.readFileSync(t,"utf8").trimEnd().split(`
|
|
5
|
+
`);for(let n=e.length-1;n>=0;n--)try{let r=JSON.parse(e[n]);if(r.type==="user"&&r.uuid)return r.uuid}catch{}}catch{}return null}function gt(t){if(!t||!b.existsSync(t))return null;try{let e=b.readFileSync(t,"utf8").trimEnd().split(`
|
|
6
|
+
`),n=[],r=0,i=0,s;for(let o=e.length-1;o>=0;o--)try{let c=JSON.parse(e[o]);if(c.type==="user")break;if(c.type==="assistant"){!s&&c.message?.model&&(s=c.message.model);let f=(c.message?.content??[]).filter(h=>h.type==="text").map(h=>h.text??"").join("");f&&n.unshift(f);let T=c.message?.usage??{};r+=(T.input_tokens??0)+(T.cache_read_input_tokens??0)+(T.cache_creation_input_tokens??0),i+=T.output_tokens??0;}}catch{}return !n.length&&r===0?null:{text:n.join(`
|
|
14
7
|
|
|
15
|
-
`),inputTokens:r,outputTokens:i,model:
|
|
16
|
-
`)[0].match(/^\/([a-z][a-z0-9-]*(?::[a-z][a-z0-9-]*)?)(?:\s.*)?$/i)?.[1]??null}var
|
|
17
|
-
`);
|
|
18
|
-
|
|
19
|
-
${y}
|
|
20
|
-
|
|
21
|
-
`)
|
|
22
|
-
`),process.stdin.on("data",e=>process.stdout.write(e));}}Yn().catch(t=>{process.stderr.write(`[flow-obs] fatal: ${t.message}
|
|
8
|
+
`),inputTokens:r,outputTokens:i,model:s}}catch{}return null}var xe=new Set([".venv","__pycache__",".git","node_modules"]),We=new Set([".pyc",".pyo"]),He=new Set(["SKILL.md",".DS_Store",".gitignore"]);function Mt(t){return t.replace(":","/")}function st(t,e){if(!t)return null;let n=Mt(t),r=[V.join(H.homedir(),".claude","skills",n,"SKILL.md"),V.join(e??"",".claude","skills",n,"SKILL.md")];for(let i of r)if(b.existsSync(i))try{return b.readFileSync(i,"utf8")}catch{}return null}function Bt(t){return t.split(`
|
|
9
|
+
`)[0].match(/^\/([a-z][a-z0-9-]*(?::[a-z][a-z0-9-]*)?)(?:\s.*)?$/i)?.[1]??null}var Ye=new Set(["Read","Write","Edit","MultiEdit","Bash","Glob","Grep","TodoWrite","WebFetch","WebSearch","Agent","Task"]);function xt(t){return !!t.slashSkill||t.toolCalls.some(r=>r.tool==="Skill")?t.toolCalls.some(r=>r.tool==="Skill"&&!r.synthetic||Ye.has(r.tool))?"complete":"prerequisite_required":null}function ot(t,e){if(!t)return null;let n=Mt(t),r=[V.join(H.homedir(),".claude","skills",n),V.join(e??"",".claude","skills",n)],i=null;for(let c of r)if(b.existsSync(V.join(c,"SKILL.md"))){i=c;break}if(!i)return null;let s=[];function o(c,d){for(let f of b.readdirSync(c,{withFileTypes:true})){if(xe.has(f.name)||He.has(f.name)||We.has(V.extname(f.name)))continue;let T=d?`${d}/${f.name}`:f.name;f.isDirectory()?o(V.join(c,f.name),T):s.push(T);}}return o(i,""),s.length>0?s:null}R();async function Wt(t){let e=t.session_id||"unknown",n=t.prompt||"",r=t.cwd||"",i=Ft(t.transcript_path)||ft(),s=Bt(n),o=s?st(s,r):null,c=s?ot(s,r):null;j(e,{traceId:ft(),spanId:D(),startNs:w(),sessionId:e,prompt:n,cwd:r,traceName:i,transcriptPath:t.transcript_path||"",toolCalls:[],spans:[],pendingTool:null,slashSkill:s,skillContent:o,skillArtifacts:c}),a("UserPromptSubmit",`sid=${e}`,`traceName=${i}`,`slashSkill=${s}`),g(t);}R();O();async function Ht(t){let e=t.session_id||"unknown",n=t.tool_name||"unknown",r=t.tool_input||{},i=Y(e);i&&(i.pendingTool={name:n,inputStr:y(r,L.TOOL_INPUT),startNs:w()},j(e,i)),a("PreToolUse",`sid=${e}`,`tool=${n}`,`stateFound=${!!i}`),g(t);}O();var je={name:ct.SCOPE_NAME,version:ct.SCOPE_VERSION},p={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 l(t,e){return e==null||e===""?null:{key:t,value:{stringValue:String(e)}}}function $(...t){return t.filter(e=>e!==null)}function Yt(t,e){return {resourceSpans:[{resource:{attributes:t},scopeSpans:[{scope:je,spans:Array.isArray(e)?e:[e]}]}]}}R();O();R();var jt=V.join(H.tmpdir(),"flow-obs-requests.ndjson");function Gt(t,e,n,r,i){if(process.env[E.FLOW_OBS_DEBUG]!=="1")return;let s=JSON.stringify({ts:new Date().toISOString(),request:{method:"POST",url:t,headers:e,body:JSON.parse(n)},response:{status:r,body:i}});try{b.writeFileSync(jt,s+`
|
|
10
|
+
`,{flag:"a",encoding:"utf8",mode:384}),a("sendTraces:dump",`request appendada em ${jt}`);}catch(o){a("sendTraces:dump",`falha ao salvar: ${o.message}`);}}function Je(t){let e=new URL(t),n=new URL(lt().GATEWAY_HEALTH);return n.hostname=e.hostname,n.port=e.port,n.protocol=e.protocol,n}function Kt(t,e){return new Promise((n,r)=>{let i=t._isSSL?Ge__default.default:Ke__default.default;t.headers=Object.assign({},t.headers,{Connection:"close"});let s=i.request(t,o=>{let c=[];o.on("data",d=>c.push(d)),o.on("end",()=>n({statusCode:o.statusCode??0,body:c.join("")}));});s.setTimeout(1e4,()=>{s.destroy(new Error("Request timeout"));}),s.on("error",o=>r(new Error(`Network error: ${o.message}`))),e&&s.write(e),s.end();})}async function Xt(t,e){let n;try{n=Je(t);}catch{return false}let r=n.protocol==="https:";try{let i={};e&&(i.Authorization=String(e).replace(/[\r\n]/g,""));let s=await Kt({hostname:n.hostname,port:n.port||(r?443:80),path:n.pathname,method:"GET",headers:i,_isSSL:r},null);return a("checkHealth",`url=${n.href} status=${s.statusCode}`),s.statusCode>=200&&s.statusCode<300}catch{return false}}async function it(t,e,n){let r=JSON.stringify(t),i=new URL(e),s=i.protocol==="https:",o=String(n).replace(/[\r\n]/g,""),c={"Content-Type":"application/json",Authorization:o,"Content-Length":Buffer.byteLength(r)};a("sendTraces:request",`POST ${e}`),a("sendTraces:request",`headers=${JSON.stringify({...c,Authorization:o.slice(0,20)+"\u2026"})}`),a("sendTraces:request",`body=${r.slice(0,500)}${r.length>500?"\u2026":""}`);try{let d=await Kt({hostname:i.hostname,port:i.port||(s?443:80),path:i.pathname,method:"POST",headers:c,_isSSL:s},r);return a("sendTraces:response",`status=${d.statusCode}`),Gt(e,c,r,d.statusCode,d.body),d.statusCode}catch(d){return a("sendTraces:error",d.message),Gt(e,c,r,0,d.message),0}}O();R();function qe(){let t=parseInt(process.env[E.BUFFER_TTL_DAYS]??"",10);return (Number.isFinite(t)?Math.max(A.MIN_TTL_DAYS,Math.min(A.MAX_TTL_DAYS,t)):A.DEFAULT_TTL_DAYS)*24*60*60*1e3}function Ze(){let t=parseInt(process.env[E.BUFFER_MAX_FILES]??"",10);return Number.isFinite(t)?Math.max(A.MIN_MAX_FILES,Math.min(A.MAX_MAX_FILES,t)):A.DEFAULT_MAX_FILES}function zt(t){if(/[/\\]/.test(t))throw new Error(`Invalid buffer fileId: ${t}`);return V__namespace.default.join(H__namespace.default.tmpdir(),`${A.FILE_PREFIX}${t}.json`)}function St(){let t=H__namespace.default.tmpdir(),e;try{e=b__namespace.default.readdirSync(t);}catch{return []}return e.filter(n=>n.startsWith(A.FILE_PREFIX)&&n.endsWith(".json")).map(n=>{let r=V__namespace.default.join(t,n),i=0;try{i=b__namespace.default.statSync(r).mtimeMs;}catch{}return {full:r,mtime:i}}).sort((n,r)=>n.mtime-r.mtime).map(n=>n.full)}function q(t){try{let e=Ze(),n=St();if(n.length>=e){let s=n.slice(0,n.length-e+1);for(let o of s)try{b__namespace.default.unlinkSync(o);}catch{}}let r=`${Date.now()}-${Math.random().toString(36).slice(2,8)}`,i={fileId:r,bufferedAt:Date.now(),payload:t};return b__namespace.default.writeFileSync(zt(r),JSON.stringify(i),{encoding:"utf8",mode:384}),a("buffer",`saved fileId=${r}`),r}catch(e){return a("buffer",`saveToBuffer failed: ${e.message}`),null}}function Jt(t){let e=St(),n=t!=null&&t>0?t:e.length,r=[];for(let i of e){if(r.length>=n)break;try{let s=b__namespace.default.readFileSync(i,"utf8"),o=JSON.parse(s);o&&o.fileId&&o.payload&&r.push(o);}catch{a("buffer",`skipping malformed file: ${i}`);}}return r}function qt(t){try{b__namespace.default.unlinkSync(zt(t)),a("buffer",`deleted fileId=${t}`);}catch{}}function Zt(){let t=Date.now()-qe();for(let e of St())try{let{mtimeMs:n}=b__namespace.default.statSync(e);n<t&&(b__namespace.default.unlinkSync(e),a("buffer",`evicted stale: ${V__namespace.default.basename(e)}`));}catch{}}O();async function Qe(t){Zt();let e=Jt(A.REPLAY_BATCH_SIZE);e.length&&(a("replayBufferedTraces",`replaying ${e.length} buffered trace(s)`),await Promise.allSettled(e.map(async n=>{try{let r=await it(n.payload,t.endpoint,t.authHeader);r>=200&&r<300?(qt(n.fileId),a("replayBufferedTraces",`replayed fileId=${n.fileId} status=${r}`)):a("replayBufferedTraces",`replay failed fileId=${n.fileId} status=${r}`);}catch(r){a("replayBufferedTraces",`replay error fileId=${n.fileId}: ${r.message}`);}})));}async function Qt(t){let e=await nt();if(!e.length)return e.authError&&(a("postToLangfuse","auth refresh failed \u2014 buffering trace"),q(t)),0;let n=await Promise.all(e.map(async s=>{if(s.mode!=="gateway")return {creds:s,healthy:true};let o=await Xt(s.endpoint,s.authHeader);return {creds:s,healthy:o}})),r=n.find(s=>s.creds.mode==="gateway"&&s.healthy)?.creds??n.find(s=>s.creds.mode==="direct")?.creds;return r&&await Qe(r),(await Promise.all(n.map(async({creds:s,healthy:o})=>{if(s.mode==="gateway"){if(!o)return a("postToLangfuse","gateway health check failed \u2014 buffering trace"),q(t),0;let d=await it(t,s.endpoint,s.authHeader);return (d===0||d>=500)&&(a("postToLangfuse",`gateway send failed (status ${d}) \u2014 buffering trace`),q(t)),d}let c=await it(t,s.endpoint,s.authHeader);return (c===0||c>=500)&&(a("postToLangfuse",`direct endpoint unavailable (status ${c}) \u2014 buffering trace`),q(t)),c}))).find(s=>s!==0)??0}R();O();var S="[REDACTED]",tn="[REDACTED-EMAIL]",en="[REDACTED-CPF]",nn="[REDACTED-CNPJ]",te="[REDACTED-PHONE]",rn=[{re:/\b(sk-[A-Za-z0-9_\-]{20,})/g,replace:()=>`sk-${S}`},{re:/\b(pk-[A-Za-z0-9_\-]{20,})/g,replace:()=>`pk-${S}`},{re:/\b(Bearer\s+)[A-Za-z0-9\-._~+/]+=*/gi,replace:(t,e)=>`${e}${S}`},{re:/\b(Basic\s+)[A-Za-z0-9+/]+=*/gi,replace:(t,e)=>`${e}${S}`},{re:/(-----BEGIN [A-Z ]+-----)[^-]*(-----END [A-Z ]+-----)/g,replace:(t,e,n)=>`${e}
|
|
11
|
+
${S}
|
|
12
|
+
${n}`},{re:/\b(AKIA[0-9A-Z]{16})\b/g,replace:()=>`AKIA${S}`},{re:/(aws_secret_access_key\s*[=:]\s*)([A-Za-z0-9/+]{40})/gi,replace:(t,e)=>`${e}${S}`},{re:/\b(ghp_[A-Za-z0-9]{36,})/g,replace:()=>`ghp_${S}`},{re:/\b(github_pat_[A-Za-z0-9_]{36,})/gi,replace:()=>`github_pat_${S}`},{re:/\b(eyJ[A-Za-z0-9_\-]+\.eyJ[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+)/g,replace:()=>`eyJ.${S}`},{re:/\b([A-Z0-9_]*(?:SECRET|TOKEN|KEY|PASSWORD|PASSWD|PWD|CREDENTIAL|API)[A-Z0-9_]*\s*=\s*)(['"]?)([^\s'"#\n]+)\2/gi,replace:(t,e,n)=>`${e}${n}${S}${n}`},{re:/([a-z][a-z0-9+\-.]*:\/\/[^:/?#\s]*):([^@\s]+)@/gi,replace:(t,e)=>`${e}:${S}@`},{re:/[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}/g,replace:()=>tn},{re:/\b\d{3}\.\d{3}\.\d{3}-\d{2}\b/g,replace:()=>en},{re:/\b\d{2}\.\d{3}\.\d{3}\/\d{4}-\d{2}\b/g,replace:()=>nn},{re:/\(\d{2}\)\s?\d{4,5}[-\s]?\d{4}/g,replace:()=>te},{re:/\+55[\s-]?\d{2}[\s-]?\d{4,5}[-\s]?\d{4}/g,replace:()=>te}];function U(t){if(t==null)return "";let e=typeof t=="string"?t:JSON.stringify(t);return rn.reduce((n,{re:r,replace:i})=>n.replace(r,i),e)}async function ee(t){let e=t.session_id||"unknown",n=t.tool_name||"unknown",r=t.tool_input||{},i=t.tool_response,s=i!==null&&typeof i=="object"?i.output??JSON.stringify(i):i??"",o=Y(e);if(!o){g(t);return}let c=w(),d=o.pendingTool,f=d?.name===n,T=f?d.startNs:String(BigInt(c)-200000000n),h=f?d.inputStr:y(r,L.TOOL_INPUT),N=h,m=null;if(n==="Skill"){let X=typeof r=="object"&&r!==null?r.skill||r.name||r.skillName||r.commandName||String(Object.values(r)[0]??""):String(r);m=X?String(X).trim():null;let x=m?st(m,o.cwd):null;x&&(N=x,o.skillContent||(o.skillContent=x),o.skillArtifacts||(o.skillArtifacts=ot(m,o.cwd))),m&&!o.slashSkill&&(o.slashSkill=m),a("PostToolUse","Skill tool detected",`skillName=${m}`,`contentFound=${!!x}`);}let k=U(y(s,L.TOOL_OUTPUT)),_=/\b(error|exception|failed|failure|traceback|errno)\b/i.test(k.slice(0,500)),Z=_?"ERROR":"DEFAULT",K=D(),Q=Math.round(Number(BigInt(c)-BigInt(T))/1e6),et={Agent:"AGENT",Task:"AGENT"}[n]??"TOOL",B=n==="Skill"&&m?m:rt(h,60);o.toolCalls.push({tool:n,brief:B,error:_,durationMs:Q});let P=o.spans;P.push({traceId:o.traceId,spanId:K,parentSpanId:o.spanId,name:n,kind:3,startTimeUnixNano:T,endTimeUnixNano:c,attributes:$(l(p.OBS_NAME,n),l(p.OBS_TYPE,et),l(p.OBS_LEVEL,Z),l(p.OBS_INPUT,U(N)),l(p.OBS_OUTPUT,k),l("tool.name",n),l("tool.error",String(_)),n==="Skill"&&m?l("skill.name",m):null,n==="Skill"?l("skill.invocation","slash-command"):null),status:{code:_?2:1}}),o.pendingTool=null,j(e,o),a("PostToolUse",`sid=${e}`,`tool=${n}`,`error=${_}`,`durationMs=${Q}`,`totalSpans=${P.length}`),g(t);}var ne={"claude-opus-5":{input:5,output:25},"claude-sonnet-5":{input:2,output:10},"claude-fable-5":{input:10,output:50},"claude-opus-4-6":{input:5,output:25},"claude-opus-4-5":{input:5,output:25},"claude-sonnet-4-6":{input:3,output:15},"claude-sonnet-4-5":{input:3,output:15},"claude-haiku-4-5":{input:1,output:5},"claude-4-6-opus":{input:5,output:25},"claude-4-6-sonnet":{input:3,output:15},"claude-4-5-opus":{input:5,output:25},"claude-4-5-sonnet":{input:3,output:15},"claude-4-5-haiku":{input:1,output:5},"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 re(t,e,n){let r=Object.keys(ne).find(o=>(t??"").toLowerCase().includes(o));if(!r)return;let i=ne[r],s=(e*i.input+n*i.output)/1e6;return Math.round(s*1e6)/1e6}R();O();async function se(t){let e=t.session_id||"unknown",n=t.stop_reason||"end_turn",r=Y(e);if(!r){g(t);return}r.slashSkill&&!/^[a-z][a-z0-9-]*(?::[a-z][a-z0-9-]*)?$/i.test(r.slashSkill)&&(a("Stop",`sid=${e}`,`slashSkill rejected post-disk: "${r.slashSkill}"`),r.slashSkill=null);let i=w(),s=dt()??"",o=r.toolCalls,c=r.spans;if(r.slashSkill&&!o.some(u=>u.tool==="Skill")){let u=D(),v=r.skillContent?r.skillContent:JSON.stringify({skill:r.slashSkill});o.push({tool:"Skill",brief:r.slashSkill,error:false,durationMs:0,synthetic:true}),c.push({traceId:r.traceId,spanId:u,parentSpanId:r.spanId,name:"Skill",kind:3,startTimeUnixNano:r.startNs,endTimeUnixNano:r.startNs,attributes:$(l(p.OBS_NAME,"Skill"),l(p.OBS_TYPE,"TOOL"),l(p.OBS_LEVEL,"DEFAULT"),l(p.OBS_INPUT,v),l(p.OBS_OUTPUT,"loaded via slash command"),l("tool.name","Skill"),l("tool.error","false"),l("skill.name",r.slashSkill),l("skill.invocation","slash-command")),status:{code:1}}),a("Stop",`slashSkill=${r.slashSkill}`,"synthetic span injected");}let d=t.transcript_path||r.transcriptPath||"",f=gt(d);if(d&&(o.some(u=>u.tool==="Skill"&&!u.synthetic)||!!r.slashSkill)&&!f?.text){await new Promise(v=>setTimeout(v,500));let u=gt(d);u?.text&&(f=u);}a("Stop",`transcriptPath=${d||"(empty)"}`,`assistantOut=${f?`text=${f.text.length}chars`:"null"}`);let h=o.length,N=o.filter(u=>u.error).length,m=U(f?.text?y(f.text,L.TRACE_OUTPUT):h===0?"No tools used":o.map((u,v)=>`${v+1}. ${u.tool}${u.brief?` \u2192 ${u.brief}`:""}${u.error?" [ERROR]":""}`).join(`
|
|
13
|
+
`)),k=f?.inputTokens??0,_=f?.outputTokens??0,Z=o.map((u,v)=>`${v+1}. ${u.tool}${u.brief?` \u2192 ${u.brief}`:""}${u.error?" [ERROR]":""} (${u.durationMs}ms)`),K=!!(r.slashSkill||o.some(u=>u.tool==="Skill")),Q=o.some(u=>u.tool==="Agent");if(!K&&!Q){a("Stop",`sid=${e}`,"skipping trace \u2014 no Skill or Agent calls found"),Et(e),g(t);return}let tt=K?"skill":"agent",et=Math.round(Number(BigInt(i)-BigInt(r.startNs))/1e6),B=f?.model||"",at=re(B,k,_),P=xt(r);P==="prerequisite_required"&&f?.text&&(P="complete"),P==="prerequisite_required"&&(c.push({traceId:r.traceId,spanId:D(),parentSpanId:r.spanId,name:"prerequisite-check",kind:3,startTimeUnixNano:r.startNs,endTimeUnixNano:i,attributes:$(l(p.OBS_NAME,"prerequisite-check"),l(p.OBS_TYPE,"EVENT"),l(p.OBS_LEVEL,"WARNING"),l(p.OBS_OUTPUT,m),l("skill.name",r.slashSkill||void 0),l("execution_status","prerequisite_required")),status:{code:1}}),a("Stop",`sid=${e}`,"prerequisite-check span injected",`skill=${r.slashSkill}`));let X=(()=>{if(!(!K||!r.prompt)){if(r.slashSkill){let u=r.prompt.replace(new RegExp(`^\\/${r.slashSkill}\\s*`,"i"),"").trim();return u?y(U(u),L.USER_INSTRUCTION):void 0}return y(U(r.prompt),L.USER_INSTRUCTION)||void 0}})(),x=JSON.stringify({trace_type:tt,...P!==null&&{execution_status:P},...r.slashSkill?{skill_name:r.slashSkill}:{},...r.skillArtifacts?.length&&{skill_artifacts:r.skillArtifacts},...X!==void 0&&{user_instruction:X},latency_ms:et,...k&&{tokens_input:k},..._&&{tokens_output:_},cost_usd:at,...B?{model:B}:{},toolCount:h,errorCount:N,stopReason:n,sessionId:r.sessionId,tools:Z.length?Z:void 0}),Tt=U(y(r.prompt,L.TRACE_INPUT)),oe=$(l(p.TRACE_NAME,r.traceName),l(p.TRACE_INPUT,Tt),l(p.TRACE_OUTPUT,m),l(p.OBS_INPUT,Tt),l(p.OBS_OUTPUT,m),l(p.TRACE_METADATA,x),l(p.SESSION_ID,r.sessionId),l(p.USER_ID,s),l(p.OBS_TYPE,"GENERATION"),l(p.MODEL,B),k?l(p.INPUT_TOKENS,k):null,_?l(p.OUTPUT_TOKENS,_):null,l("claude.stop_reason",n),l("claude.tool_count",String(h)),l("claude.error_count",String(N)),l("claude.session_id",r.sessionId),l("flow.trace_type",tt),{key:p.TRACE_TAGS,value:{arrayValue:{values:[{stringValue:tt}]}}}),ie={traceId:r.traceId,spanId:r.spanId,name:r.traceName,kind:1,startTimeUnixNano:r.startNs,endTimeUnixNano:i,attributes:oe,status:{code:N>0?2:1}},ae=$(l("service.name",process.env.LANGFUSE_PROJECT_NAME||"claude-code"),l("deployment.environment",process.env.LANGFUSE_ENVIRONMENT||"default")),ht=[...c,ie];a("Stop",`sid=${e}`,`totalTools=${h}`,`errorTools=${N}`,`spans=${ht.length}`,`inputTokens=${k}`,`outputTokens=${_}`,`traceOutput="${rt(m,80)}"`);let le=await Qt(Yt(ae,ht));a("Stop",`POST status=${le}`,`traceId=${r.traceId}`,`latencyMs=${et}`,`costUsd=${at}`),Et(e),g(t);}var M=class{static async userPromptSubmit(){let e=await J(),n;try{n=(await nt()).length>0;}catch{g(e);return}n?await Wt(e):g(e);}static async preToolUse(){let e=await J();await Ht(e);}static async postToolUse(){let e=await J();await ee(e);}static async stop(){let e=await J();await se(e);}};async function sn(){let t=process.argv[2];switch(t){case "UserPromptSubmit":await M.userPromptSubmit();break;case "PreToolUse":await M.preToolUse();break;case "PostToolUse":await M.postToolUse();break;case "Stop":await M.stop();break;default:process.stderr.write(`[flow-obs] unknown event: ${t}
|
|
14
|
+
`),process.stdin.on("data",e=>process.stdout.write(e));}}sn().catch(t=>{process.stderr.write(`[flow-obs] fatal: ${t.message}
|
|
23
15
|
`),process.exit(0);});
|
package/dist/setup.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
'use strict';var
|
|
3
|
-
`;try{
|
|
4
|
-
`);}}var
|
|
5
|
-
`,{encoding:"utf8",mode:384});try{
|
|
6
|
-
`,{encoding:"utf8"}),{status:"configured",settingsPath:t}}catch(r){return {status:"skipped",settingsPath:t,reason:r.message}}}T();
|
|
7
|
-
`)}function
|
|
8
|
-
`)}var
|
|
9
|
-
`;try{if(
|
|
10
|
-
`;try{if(
|
|
11
|
-
`,{encoding:"utf8",mode:384});try{
|
|
2
|
+
'use strict';var a=require('fs'),N=require('os'),c=require('path'),child_process=require('child_process'),me=require('crypto'),Et=require('https');require('readline/promises');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var a__namespace=/*#__PURE__*/_interopNamespace(a);var N__namespace=/*#__PURE__*/_interopNamespace(N);var c__namespace=/*#__PURE__*/_interopNamespace(c);var me__namespace=/*#__PURE__*/_interopNamespace(me);var Et__default=/*#__PURE__*/_interopDefault(Et);var H=Object.defineProperty;var Re=Object.getOwnPropertyDescriptor;var Pe=Object.getOwnPropertyNames;var we=Object.prototype.hasOwnProperty;var L=(e,n,t)=>()=>{if(t)throw t[0];try{return e&&(n=e(e=0)),n}catch(r){throw t=[r],r}};var ve=(e,n)=>()=>{try{return n||e((n={exports:{}}).exports,n),n.exports}catch(t){throw n=0,t}},Ie=(e,n)=>{for(var t in n)H(e,t,{get:n[t],enumerable:true});},Ce=(e,n,t,r)=>{if(n&&typeof n=="object"||typeof n=="function")for(let o of Pe(n))!we.call(e,o)&&o!==t&&H(e,o,{get:()=>n[o],enumerable:!(r=Re(n,o))||r.enumerable});return e};var De=e=>Ce(H({},"__esModule",{value:true}),e);var Q={};Ie(Q,{BUFFER:()=>ke,CLAUDE_DESKTOP:()=>f,COPILOT_OTEL:()=>u,DEBUG_LOG_FILENAME:()=>V,ENV:()=>_,FLOW_URLS:()=>Ue,INSTALLER:()=>M,NATIVE_OTEL:()=>$,OTLP:()=>Fe,STATE_FILE_PREFIX:()=>xe,TRACE_LIMITS:()=>be,VALIDATION:()=>h,getFlowBaseUrl:()=>Z,getFlowUrls:()=>R});function Z(){let e=process.env.FLOW_BASE_URL;return e&&e.trim()?e.trim():Ne}function R(){let e=Z();return {GATEWAY_TRACES:process.env.FLOW_GATEWAY_TRACES_URL||`${e}/flow-langfuse-gateway/v1/traces`,GATEWAY_HEALTH:process.env.FLOW_GATEWAY_HEALTH_URL||`${e}/flow-langfuse-gateway/v1/health`,OTEL_ENDPOINT:process.env.FLOW_OTEL_ENDPOINT_URL||`${e}/otel`}}var Ne,Ue,Fe,$,_,M,ke,h,V,be,f,u,xe,T=L(()=>{"use strict";Ne="https://flow.ciandt.com";Ue=R(),Fe={SCOPE_NAME:"flow-ai-obs",SCOPE_VERSION:"0.1.0"},$={CLAUDE_CODE_ENABLE_TELEMETRY:"1",OTEL_EXPORTER_OTLP_PROTOCOL:"http/json",OTEL_METRICS_EXPORTER:"otlp",OTEL_LOGS_EXPORTER:"otlp",OTEL_LOG_TOOL_DETAILS:"1",OTEL_LOG_USER_PROMPTS:"1"},_={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_AUTH_TOKEN:"ANTHROPIC_AUTH_TOKEN",FLOW_OBS_DEBUG:"FLOW_TELEMETRY_DEBUG",FLOW_OBS_ALLOW_HTTP:"FLOW_TELEMETRY_ALLOW_HTTP",FLOW_OBS_SKIP_DESKTOP_DETECTION:"FLOW_OBS_SKIP_DESKTOP_DETECTION",FLOW_OBS_SKIP_COPILOT_DETECTION:"FLOW_OBS_SKIP_COPILOT_DETECTION",BUFFER_TTL_DAYS:"FLOW_TELEMETRY_BUFFER_TTL_DAYS",BUFFER_MAX_FILES:"FLOW_TELEMETRY_BUFFER_MAX_FILES",FLOW_USER_EMAIL:"FLOW_USER_EMAIL",FLOW_API_KEY:"FLOW_API_KEY",OTEL_EXPORTER_OTLP_HEADERS:"OTEL_EXPORTER_OTLP_HEADERS",FLOW_BASE_URL:"FLOW_BASE_URL"},M={LOCK_STALE_MS:3e4,CLI:"flow-ai-obs "},ke={FILE_PREFIX:"flow-obs-buffer-",DEFAULT_TTL_DAYS:4,MIN_TTL_DAYS:1,MAX_TTL_DAYS:30,DEFAULT_MAX_FILES:50,MIN_MAX_FILES:1,MAX_MAX_FILES:500,REPLAY_BATCH_SIZE:10},h={API_KEY_MAX_LENGTH:1024,API_KEY_PATTERN:/^[A-Za-z0-9_.\-:=+/]+$/,EMAIL_MAX_LENGTH:254,EMAIL_HEADER_PATTERN:/^[\x21-\x7E]+$/},V="flow-ai-obs-debug.log",be={TOOL_INPUT:2e4,TOOL_OUTPUT:2e4,TRACE_OUTPUT:2e4,USER_INSTRUCTION:1e4,TRACE_INPUT:5e4,TOOL_BRIEF:60},f={DIR_3P:"Claude-3p",CONFIG_LIBRARY_DIR:"configLibrary",DESKTOP_CONFIG_FILE:"claude_desktop_config.json",META_FILE:"_meta.json",DEPLOYMENT_MODE:"3p",CONFIG_NAME:"Flow AI Obs",WRAPPER_SCRIPT_UNIX:"otel-headers-helper.sh",WRAPPER_SCRIPT_WIN:"otel-headers-helper.cmd",OTLP_PROTOCOL:"http/json",KEYS:{OTLP_ENDPOINT:"otlpEndpoint",OTLP_PROTOCOL:"otlpProtocol",OTLP_HEADERS_HELPER:"otlpHeadersHelper",OTLP_RESOURCE_ATTRIBUTES:"otlpResourceAttributes"},CUSTOM_PROVIDER_KEY:"custom.provider",CUSTOM_PROVIDER_VALUE:"claude-code-desktop"},u={ENABLED_KEY:"github.copilot.chat.otel.enabled",ENABLED_VALUE:!0,EXPORTER_TYPE_KEY:"github.copilot.chat.otel.exporterType",EXPORTER_TYPE_VALUE:"otlp-http",PROTOCOL_KEY:"github.copilot.chat.otel.protocol",PROTOCOL_VALUE:"http/json",ENDPOINT_KEY:"github.copilot.chat.otel.otlpEndpoint",HEADERS_KEY:"github.copilot.chat.otel.headers",HEADER_API_KEY:"x-flow-api-key",HEADER_USER:"x-flow-user"},xe="flow-obs-";});function l(...e){if(process.env[_.FLOW_OBS_DEBUG]!=="1")return;let n=`[${new Date().toISOString()}] ${e.join(" ")}
|
|
3
|
+
`;try{a.writeFileSync(Ke,n,{flag:"a"});}catch(t){process.stderr.write(`[flow-obs debug ERROR] ${t.message}
|
|
4
|
+
`);}}var Ke,K=L(()=>{"use strict";T();Ke=c.join(N.tmpdir(),V);});function P(e,n){return je?t=>`\x1B[${e}m${t}\x1B[${n}m`:t=>t}var je,Ft,He,kt,$e,bt,xt,ee=L(()=>{"use strict";je=!process.env.NO_COLOR&&process.stdout.isTTY;Ft=P("32","39"),He=P("31","39"),kt=P("33","39"),$e=P("36","39"),bt=P("1","22"),xt=P("2","22");});function B(){return process.platform==="win32"?false:process.getuid?.()===0}var te=L(()=>{"use strict";ee();});function y(e={}){let n=e.env??process.env,t=e.platform??process.platform;return !!(n.WSL_DISTRO_NAME&&t==="linux")}function F(e,n={}){let t=n.env??process.env,r=n.spawnSync??child_process.spawnSync;if(!y({env:t,platform:n.platform}))return;let o=t[e];if(!o)try{let i=r("cmd.exe",["/c","echo",`%${e}%`],{encoding:"utf8",timeout:5e3}).stdout?.trim();i&&/^[A-Za-z]:\\/.test(i)&&(o=i);}catch(s){l("resolveWslWindowsPath",`cmd.exe ${e} lookup failed: ${s.message}`);}if(o)return o.replace(/^([A-Za-z]):/,(s,i)=>`/mnt/${i.toLowerCase()}`).replace(/\\/g,"/")}function S(){if(process.platform==="linux"&&process.getuid?.()===0&&process.env.SUDO_USER)try{let n=child_process.spawnSync("getent",["passwd",process.env.SUDO_USER],{encoding:"utf8",timeout:5e3}).stdout?.split(":")[5]?.trim();if(n)return {home:n,username:process.env.SUDO_USER}}catch(e){l("getActualUser",`getent passwd lookup failed: ${e.message}`);}return {home:N__namespace.homedir(),username:process.env.SUDO_USER||process.env.USER||N__namespace.userInfo().username}}function v(){if(y()){let e=F("USERPROFILE");return e?c__namespace.join(e,".claude","settings.json"):c__namespace.join(N__namespace.homedir(),".claude","settings.json")}if(process.platform==="win32"){let e=process.env.USERPROFILE||N__namespace.homedir();return c__namespace.join(e,".claude","settings.json")}return c__namespace.join(S().home,".claude","settings.json")}var I=L(()=>{"use strict";K();te();});function ie(){if(process.platform==="win32"){let t=process.env.APPDATA||c__namespace.join(N__namespace.homedir(),"AppData","Roaming");return c__namespace.join(t,re,se)}let e=S(),n=process.env.XDG_CONFIG_HOME||c__namespace.join(e.home,".config");return c__namespace.join(n,re,se)}var re,se,ae=L(()=>{"use strict";I();re="flow-ai-obs",se="config.json";});function Be(e){try{let n=a__namespace.statSync(e);Date.now()-n.mtimeMs>Ve&&a__namespace.unlinkSync(e);}catch{}try{a__namespace.writeFileSync(e,String(process.pid),{flag:"wx"});}catch(n){throw n.code==="EEXIST"?new Error("Another install is already in progress. If this is stale, remove: "+e):n}}function Ge(e){try{a__namespace.unlinkSync(e);}catch{}}function Xe(e){let n=[];if(!e.hooks||typeof e.hooks!="object"||Array.isArray(e.hooks))return delete e.hooks,n;let t=e.hooks,r={};for(let[o,s]of Object.entries(t)){if(!Array.isArray(s))continue;let i=s.map(E=>{if(!Array.isArray(E?.hooks))return null;let m=E.hooks.filter(O=>!O.command?.startsWith?.(M.CLI));return m.length>0?{...E,hooks:m}:null}).filter(E=>E!=null);i.length>0&&(r[o]=i,n.push(o));}return Object.keys(r).length>0?e.hooks=r:delete e.hooks,n}function le(e,n){let t=v(),r=t+".lock";a__namespace.mkdirSync(c__namespace.dirname(t),{recursive:true}),Be(r);try{if(a__namespace.existsSync(t)){a__namespace.copyFileSync(t,t+".bkp");try{a__namespace.chmodSync(t+".bkp",384);}catch{}}let o=ie();if(a__namespace.existsSync(o)){let Y=o+".bkp";a__namespace.copyFileSync(o,Y);try{a__namespace.chmodSync(Y,384);}catch{}}let s={};try{s=JSON.parse(a__namespace.readFileSync(t,"utf8"));}catch{}let i=s.env&&typeof s.env=="object"?s.env:{};delete i.OTEL_EXPORTER_OTLP_HEADERS;let{getFlowUrls:E}=(T(),De(Q)),m=E().OTEL_ENDPOINT,O={...$,OTEL_EXPORTER_OTLP_ENDPOINT:e??m};s.env={...i,...O,...n??{}},s.otelHeadersHelper="flow-ai-obs otel-headers";let x=Xe(s);a__namespace.writeFileSync(t,JSON.stringify(s,null,2)+`
|
|
5
|
+
`,{encoding:"utf8",mode:384});try{a__namespace.chmodSync(t,384);}catch{}return C=void 0,{settingsPath:t,preserved:x}}finally{Ge(r);}}function ue(e){if(C===void 0)try{let t=a__namespace.readFileSync(v(),"utf8");C=JSON.parse(t).env??null;}catch{C=null;}if(!C)return null;let n=C[e];return typeof n=="string"?n:null}function pe(e){let n=process.env[e];return n!==void 0?n!==""?n:void 0:ue(e)??void 0}function Je(){let e=ue(_.FLOW_BASE_URL);return e&&e.trim()?e.trim():void 0}function fe(){let e=process.env[_.FLOW_BASE_URL];return e&&e.trim()?e.trim():Je()}var Ve,C,G=L(()=>{"use strict";T();I();ae();Ve=M.LOCK_STALE_MS;});var Oe=ve((dn,dt)=>{dt.exports={name:"@ciandt-flow/flow-ai-obs",version:"1.0.0-beta.149",description:"Claude Code hooks for Langfuse OTLP tracing \u2014 cross-platform",main:"dist/index.js",bin:{"flow-ai-obs":"dist/cli.js","flow-ai-obs-setup":"dist/setup.js"},scripts:{build:"tsup",test:"jest",typecheck:"tsc --noEmit",lint:"eslint src bin scripts",format:'prettier --write "src/**/*.ts" "bin/**/*.ts" "scripts/**/*.ts"',"format:check":'prettier --check "src/**/*.ts" "bin/**/*.ts" "scripts/**/*.ts"',"security-scan":"trufflehog filesystem src/ --fail --no-update --exclude-paths .trufflehogignore",postinstall:`node -e "require('fs').existsSync('dist/setup.js') && require('child_process').execFileSync(process.execPath, ['dist/setup.js'], {stdio:'inherit'})"`,prepare:"lefthook install || echo '[WARNING] lefthook install failed - git hooks not installed'",prepublishOnly:"npm run security-scan && npm run build","release:npm":"changeset publish",changeset:"changeset","version-packages":"changeset version","install:hooks":"node dist/cli.js install",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",regression:"jest --config jest.regression.config.js --forceExit","regression:update":"UPDATE_GOLDEN=1 jest --config jest.regression.config.js --forceExit"},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:!1,dependencies:{},devDependencies:{"@changesets/changelog-github":"^0.6.0","@changesets/cli":"^2.30.0","@types/jest":"^30.0.0","@types/node":"^25.8.0","eslint-config-prettier":"^10.1.5",jest:"^30.4.2",lefthook:"^2.1.10",prettier:"^3.5.3","ts-jest":"^29.4.9",tsup:"^8.5.1",typescript:"^6.0.3","typescript-eslint":"^8.33.0"},engines:{node:">=18.0.0"},overrides:{esbuild:"^0.28.1"},publishConfig:{registry:"https://registry.npmjs.org",access:"public"},repository:{type:"git",url:"git+https://github.com/CI-T-HyperX/flow-codeassistant-observability.git"}};});G();T();T();K();G();function ze(e){let n=process.env[_.OTEL_EXPORTER_OTLP_HEADERS];if(!n)return null;let t=e.toLowerCase();for(let r of n.split(",")){let o=r.indexOf("=");if(!(o<=0)&&r.slice(0,o).trim().toLowerCase()===t){let s=r.slice(o+1),i=s.search(/[\r\n]/);return (i===-1?s:s.slice(0,i)).trim()||null}}return null}function de(){let e=pe(_.FLOW_USER_EMAIL);if(e!==void 0){let t=e.replace(/[\r\n]/g,"").trim();if(t)if(t.length>h.EMAIL_MAX_LENGTH)l("resolveUserEmail",`FLOW_USER_EMAIL exceeds ${h.EMAIL_MAX_LENGTH} chars \u2014 skipping`);else if(!h.EMAIL_HEADER_PATTERN.test(t))l("resolveUserEmail","FLOW_USER_EMAIL contains non-printable or control characters \u2014 skipping");else return l("resolveUserEmail","using FLOW_USER_EMAIL override: [REDACTED]"),t}let n=ze("x-flow-user");if(n){let t=n.replace(/[\r\n]/g,"").trim();if(t.length>h.EMAIL_MAX_LENGTH)l("resolveUserEmail",`x-flow-user from OTEL_EXPORTER_OTLP_HEADERS exceeds ${h.EMAIL_MAX_LENGTH} chars \u2014 skipping`);else if(!h.EMAIL_HEADER_PATTERN.test(t))l("resolveUserEmail","x-flow-user from OTEL_EXPORTER_OTLP_HEADERS is empty or contains non-printable characters \u2014 skipping");else return l("resolveUserEmail","using x-flow-user from OTEL_EXPORTER_OTLP_HEADERS: [REDACTED]"),t}try{let t=N__namespace.default.userInfo().username||process.env.USERNAME||process.env.USER||"",r=t.lastIndexOf("\\");if(r!==-1&&(t=t.slice(r+1)),t=t.trim().replace(/[^a-zA-Z0-9._%+\-]/g,"").replace(/^\.+/,""),!t)return l("resolveUserEmail","Could not derive x-flow-user: username is empty. Run: flow-ai-obs init"),null;let o=`${t}@ciandt.com`;return l("resolveUserEmail","derived email: [REDACTED]"),o}catch(t){return l("resolveUserEmail",`Could not derive x-flow-user from OS username: ${t.message}. Run: flow-ai-obs init`),null}}function A(e){if(!e)return null;let n=e.replace(/[\r\n]/g,"").trim();return n?n.length>h.API_KEY_MAX_LENGTH?(l("validateApiKey",`API key exceeds ${h.API_KEY_MAX_LENGTH} chars \u2014 rejected`),null):h.API_KEY_PATTERN.test(n)?n:(l("validateApiKey","API key contains invalid or unsafe characters \u2014 rejected"),null):null}function D(){let e=process.env[_.FLOW_API_KEY];return A(e)}I();function Ee(){if(y()){let t=F("APPDATA");return t?c__namespace.join(t,"Code","User","settings.json"):null}if(process.platform==="win32"){let t=process.env.APPDATA||c__namespace.join(N__namespace.homedir(),"AppData","Roaming");return c__namespace.join(t,"Code","User","settings.json")}if(process.platform==="darwin")return c__namespace.join(N__namespace.homedir(),"Library","Application Support","Code","User","settings.json");let e=process.platform==="linux"&&process.getuid?.()===0?S().home:process.env.HOME||N__namespace.homedir(),n=process.env.XDG_CONFIG_HOME||c__namespace.join(e,".config");return c__namespace.join(n,"Code","User","settings.json")}function Ze(e){let n=false,t=false,r="";for(let o=0;o<e.length;o++){let s=e[o];if(n){r+=s,t?t=false:s==="\\"?t=true:s==='"'&&(n=false);continue}if(s==='"'){n=true,r+=s;continue}if(s===","){let i=o+1;for(;i<e.length&&/\s/.test(e[i]);)i++;if(i<e.length&&(e[i]==="}"||e[i]==="]"))continue}r+=s;}return r}function Qe(e){if(process.env[_.FLOW_OBS_SKIP_COPILOT_DETECTION])return !!(e&&a__namespace.existsSync(e));if(e&&(a__namespace.existsSync(e)||a__namespace.existsSync(c__namespace.dirname(e))||a__namespace.existsSync(c__namespace.dirname(c__namespace.dirname(e)))))return true;let n=Ee();if(n&&(a__namespace.existsSync(n)||a__namespace.existsSync(c__namespace.dirname(n))||a__namespace.existsSync(c__namespace.dirname(c__namespace.dirname(n))))||process.platform==="darwin"&&["/Applications/Visual Studio Code.app",c__namespace.join(N__namespace.homedir(),"Applications","Visual Studio Code.app")].some(r=>a__namespace.existsSync(r)))return true;if(process.platform==="win32"){let t=process.env.LOCALAPPDATA||c__namespace.join(N__namespace.homedir(),"AppData","Local"),r=process.env.PROGRAMFILES||"C:\\Program Files",o=process.env["PROGRAMFILES(X86)"]||"C:\\Program Files (x86)";if([c__namespace.join(t,"Programs","Microsoft VS Code","Code.exe"),c__namespace.join(r,"Microsoft VS Code","Code.exe"),c__namespace.join(o,"Microsoft VS Code","Code.exe")].some(i=>a__namespace.existsSync(i)))return true}return !!(process.platform==="linux"&&["/usr/bin/code","/usr/share/code","/snap/bin/code"].some(r=>a__namespace.existsSync(r)))}function ge(e,n={}){let t;try{t=n.customSettingsPath||Ee();}catch(r){return {status:"skipped",reason:`VS Code path resolution failed: ${r.message}`}}if(!t)return {status:"skipped",reason:"VS Code path not found"};if(!Qe(t))return {status:"skipped",settingsPath:t,reason:"VS Code is not installed"};try{let r={};if(a__namespace.existsSync(t))try{let W=Ze(a__namespace.readFileSync(t,"utf8"));r=JSON.parse(W);}catch{return {status:"skipped",settingsPath:t,reason:"VS Code settings.json could not be parsed (unsupported JSONC syntax such as comments)"}}let o=e||R().OTEL_ENDPOINT,s=n.apiKey!==void 0?n.apiKey:D(),i=n.userEmail!==void 0?n.userEmail:de(),E=typeof r[u.HEADERS_KEY]=="object"&&r[u.HEADERS_KEY]!==null&&!Array.isArray(r[u.HEADERS_KEY])?r[u.HEADERS_KEY]:{},m={...E};s&&(m[u.HEADER_API_KEY]=s),i&&(m[u.HEADER_USER]=i);let O=Object.keys(m),x=Object.keys(E),Y=O.length===0&&(r[u.HEADERS_KEY]===void 0||x.length===0)||O.length===x.length&&O.every(W=>E[W]===m[W]);if(r[u.ENABLED_KEY]===u.ENABLED_VALUE&&r[u.EXPORTER_TYPE_KEY]===u.EXPORTER_TYPE_VALUE&&r[u.PROTOCOL_KEY]===u.PROTOCOL_VALUE&&r[u.ENDPOINT_KEY]===o&&Y)return {status:"already_configured",settingsPath:t};a__namespace.mkdirSync(c__namespace.dirname(t),{recursive:!0});let z={...r,[u.ENABLED_KEY]:u.ENABLED_VALUE,[u.EXPORTER_TYPE_KEY]:u.EXPORTER_TYPE_VALUE,[u.PROTOCOL_KEY]:u.PROTOCOL_VALUE,[u.ENDPOINT_KEY]:o};return O.length>0&&(z[u.HEADERS_KEY]=m),a__namespace.writeFileSync(t,JSON.stringify(z,null,2)+`
|
|
6
|
+
`,{encoding:"utf8"}),{status:"configured",settingsPath:t}}catch(r){return {status:"skipped",settingsPath:t,reason:r.message}}}T();I();K();function X(){return process.platform==="win32"||y()}function et(e){let n=e.match(/^\/mnt\/([a-z])\/(.*)$/);if(!n)return e;let t=n[1].toUpperCase(),r=n[2].replace(/\//g,"\\");return `${t}:\\${r}`}function _e(){if(y()){let r=F("LOCALAPPDATA");if(r){let o=c__namespace.join(r,f.DIR_3P);return j(o)}}if(process.platform==="win32"){let r=process.env.LOCALAPPDATA||c__namespace.join(N__namespace.homedir(),"AppData","Local"),o=c__namespace.join(r,f.DIR_3P);return j(o)}if(process.platform==="darwin"){let r=c__namespace.join(N__namespace.homedir(),"Library","Application Support",f.DIR_3P);return j(r)}let e=S(),n=process.env.XDG_CONFIG_HOME||c__namespace.join(e.home,".config"),t=c__namespace.join(n,f.DIR_3P);return j(t)}function j(e){return {configDir:e,configLibraryDir:c__namespace.join(e,f.CONFIG_LIBRARY_DIR),desktopConfigPath:c__namespace.join(e,f.DESKTOP_CONFIG_FILE),metaPath:c__namespace.join(e,f.CONFIG_LIBRARY_DIR,f.META_FILE)}}function J(){let e=v(),n=c__namespace.dirname(e),t=X()?f.WRAPPER_SCRIPT_WIN:f.WRAPPER_SCRIPT_UNIX;return c__namespace.join(n,t)}function tt(){if(process.env[_.FLOW_OBS_SKIP_DESKTOP_DETECTION])return false;let e=_e();if(a__namespace.existsSync(e.configDir))return true;if(process.platform==="darwin")return ["/Applications/Claude.app",c__namespace.join(N__namespace.homedir(),"Applications","Claude.app")].some(t=>a__namespace.existsSync(t));if(process.platform==="win32"){let n=process.env.LOCALAPPDATA||c__namespace.join(N__namespace.homedir(),"AppData","Local"),t=process.env.PROGRAMFILES||"C:\\Program Files";return [c__namespace.join(n,"AnthropicClaude","Claude.exe"),c__namespace.join(t,"Claude","Claude.exe")].some(o=>a__namespace.existsSync(o))}if(process.platform==="linux"){let n=S(),t=process.env.XDG_CONFIG_HOME||c__namespace.join(n.home,".config"),r=c__namespace.join(t,"Claude");return a__namespace.existsSync(r)}return false}function nt(e){let n=e??J();try{if(!a__namespace.existsSync(n))return null;let t=a__namespace.readFileSync(n,"utf8"),r=t.match(/^export FLOW_API_KEY=["']?([^"'\r\n]+)["']?$/m);if(r&&r[1])return A(r[1]);let o=t.match(/^set FLOW_API_KEY=([^\r\n]+)$/m);if(o&&o[1])return A(o[1])}catch{}return null}function rt(e,n,t=448){let r=c__namespace.dirname(e);a__namespace.mkdirSync(r,{recursive:true});let o=X(),s=o?420:t,i=true;try{a__namespace.readFileSync(e,"utf8")===n&&(i=!1);}catch{}if(!i){if(!o)try{a__namespace.chmodSync(e,t);}catch{}return {written:false}}if(a__namespace.existsSync(e)&&(a__namespace.copyFileSync(e,e+".bkp"),!o))try{a__namespace.chmodSync(e+".bkp",448);}catch{}if(a__namespace.writeFileSync(e,n,{encoding:"utf8",mode:s}),!o)try{a__namespace.chmodSync(e,t);}catch{}return {written:true}}function st(e){let n=J(),t=e?A(e):null,r=X()?it(t):ot(t);return rt(n,r,!!t?448:493),n}function ot(e){let n=e?A(e):null,t=["#!/usr/bin/env bash","# Auto-generated by flow-ai-obs \u2014 do not edit manually.","# Wrapper script for Claude Desktop otelHeadersHelper.","# Invokes flow-ai-obs otel-headers to produce fresh OTLP headers at runtime.","set -euo pipefail"];return n&&t.push(`export FLOW_API_KEY="${n}"`),t.push("exec flow-ai-obs otel-headers",""),t.join(`
|
|
7
|
+
`)}function it(e){let n=e?A(e):null,t=["@echo off","REM Auto-generated by flow-ai-obs \u2014 do not edit manually.","REM Wrapper script for Claude Desktop otelHeadersHelper.","REM Invokes flow-ai-obs otel-headers to produce fresh OTLP headers at runtime."];return n&&t.push(`set FLOW_API_KEY=${n}`),t.push("flow-ai-obs otel-headers",""),t.join(`\r
|
|
8
|
+
`)}var at=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function ct(e){try{let n=a__namespace.readFileSync(e,"utf8");try{let t=JSON.parse(n);if(t.appliedId&&typeof t.appliedId=="string"&&at.test(t.appliedId))return t.appliedId;t.appliedId&&l("getOrCreateConfigUuid","appliedId is not a valid UUID \u2014 generating new UUID");}catch{l("getOrCreateConfigUuid",`corrupted JSON in ${e} \u2014 generating new UUID`);}}catch(n){n.code!=="ENOENT"&&l("getOrCreateConfigUuid",`read error: ${n.message}`);}return me__namespace.randomUUID()}function lt(e,n){let t=c__namespace.dirname(e);a__namespace.mkdirSync(t,{recursive:true});let r;try{let s=a__namespace.readFileSync(e,"utf8");try{r=JSON.parse(s),(!r.appliedId||typeof r.appliedId!="string")&&(r.appliedId=n),Array.isArray(r.entries)||(r.entries=[]);}catch{l("writeMetaJson",`corrupted JSON in ${e} \u2014 starting fresh`),r={appliedId:n,entries:[]};}}catch(s){s.code!=="ENOENT"&&l("writeMetaJson",`read error: ${s.message}`),r={appliedId:n,entries:[]};}r.entries.some(s=>s.id===n)||r.entries.push({id:n,name:f.CONFIG_NAME});let o=JSON.stringify(r,null,2)+`
|
|
9
|
+
`;try{if(a__namespace.readFileSync(e,"utf8")===o)return}catch{}if(a__namespace.existsSync(e)){a__namespace.copyFileSync(e,e+".bkp");try{a__namespace.chmodSync(e+".bkp",384);}catch{}}a__namespace.writeFileSync(e,o,{encoding:"utf8",mode:384});try{a__namespace.chmodSync(e,384);}catch{}}function ut(e,n,t,r){a__namespace.mkdirSync(e,{recursive:true});let o=c__namespace.resolve(e),s=c__namespace.resolve(e,`${n}.json`);if(!s.startsWith(o+c__namespace.sep))throw new Error(`Security error: invalid config path ${s}`);let i={};try{let m=a__namespace.readFileSync(s,"utf8");try{i=JSON.parse(m);}catch{l("writeConfigLibraryFile",`corrupted JSON in ${s} \u2014 starting fresh`);}}catch(m){m.code!=="ENOENT"&&l("writeConfigLibraryFile",`read error: ${m.message}`);}i[f.KEYS.OTLP_ENDPOINT]=t,i[f.KEYS.OTLP_PROTOCOL]=f.OTLP_PROTOCOL,i[f.KEYS.OTLP_HEADERS_HELPER]=y()?et(r):r,i[f.KEYS.OTLP_RESOURCE_ATTRIBUTES]={[f.CUSTOM_PROVIDER_KEY]:f.CUSTOM_PROVIDER_VALUE};let E=JSON.stringify(i,null,2)+`
|
|
10
|
+
`;try{if(a__namespace.readFileSync(s,"utf8")===E)return s}catch{}if(a__namespace.existsSync(s)){a__namespace.copyFileSync(s,s+".bkp");try{a__namespace.chmodSync(s+".bkp",384);}catch{}}a__namespace.writeFileSync(s,E,{encoding:"utf8",mode:384});try{a__namespace.chmodSync(s,384);}catch{}return s}function pt(e){let n=c__namespace.dirname(e);a__namespace.mkdirSync(n,{recursive:true});let t={};try{let r=a__namespace.readFileSync(e,"utf8");try{t=JSON.parse(r);}catch{l("mergeClaudeDesktopConfig",`corrupted JSON in ${e} \u2014 starting fresh (original backed up to .bkp)`);}}catch(r){r.code!=="ENOENT"&&l("mergeClaudeDesktopConfig",`read error: ${r.message}`);}if(t.deploymentMode!==f.DEPLOYMENT_MODE){if(a__namespace.existsSync(e)){a__namespace.copyFileSync(e,e+".bkp");try{a__namespace.chmodSync(e+".bkp",384);}catch{}}t.deploymentMode=f.DEPLOYMENT_MODE,a__namespace.writeFileSync(e,JSON.stringify(t,null,2)+`
|
|
11
|
+
`,{encoding:"utf8",mode:384});try{a__namespace.chmodSync(e,384);}catch{}}}function he(e,n){if(!tt())return {configured:false};let t=_e(),r=R().OTEL_ENDPOINT,o=D()??nt(J()),s=st(o),i=ct(t.metaPath),E=ut(t.configLibraryDir,i,r,s);return lt(t.metaPath,i),pt(t.desktopConfigPath),{configured:true,configDir:t.configDir,configLibraryPath:E,uuid:i,wrapperScriptPath:s}}var q;function Se(){return q||(q=Oe()),q}var Le=c__namespace.default.join(N__namespace.default.tmpdir(),"flow-obs-update-cache.json"),_t=1440*60*1e3,ht=3e3;function Ot(e,n){let t=s=>{let i=String(s).replace(/^v/,"").match(/^(\d+)\.(\d+)\.(\d+)/);return i?[+i[1],+i[2],+i[3]]:null},r=t(e),o=t(n);return !r||!o?false:o[0]!==r[0]?o[0]>r[0]:o[1]!==r[1]?o[1]>r[1]:o[2]>r[2]}function yt(){try{let e=JSON.parse(a__namespace.default.readFileSync(Le,"utf8"));return typeof e.latestVersion!="string"||Date.now()-e.checkedAt>=_t?null:e}catch{return null}}function St(e,n,t=Date.now()){try{a__namespace.default.writeFileSync(Le,JSON.stringify({latestVersion:e,updatePriority:n??null,checkedAt:t}),{mode:384});}catch{}}function Lt(e){let n=Se().name,t=Et__default.default.get(`https://registry.npmjs.org/${encodeURIComponent(n)}/latest`,{timeout:ht},r=>{if(r.statusCode!==200)return r.resume(),e(new Error(`HTTP ${r.statusCode}`));let o="";r.setEncoding("utf8"),r.on("data",s=>{o+=s;}),r.on("end",()=>{try{let s=JSON.parse(o);if(typeof s.version!="string")throw new Error("no version field");e(null,{version:s.version,updatePriority:typeof s.updatePriority=="string"?s.updatePriority:null});}catch(s){e(s);}});});t.on("error",e),t.on("timeout",()=>{t.destroy(new Error("timeout"));});}function Te(){try{if(yt())return;setImmediate(()=>{Lt((e,n)=>{e||!n||Ot(Se().version,n.version)&&St(n.version,n.updatePriority,0);});});}catch{}}I();var Tt=c__namespace.default.resolve(__dirname,".."),At=process.env.INIT_CWD?c__namespace.default.resolve(process.env.INIT_CWD):null;At===Tt&&process.exit(0);B()&&(process.stderr.write(`
|
|
12
12
|
[flow-ai-obs] \u2717 Do not install with sudo.
|
|
13
13
|
Run without sudo: npm install -g @ciandt-flow/flow-ai-obs
|
|
14
14
|
|
|
15
|
-
`),process.exit(1));function
|
|
16
|
-
[flow-ai-obs]
|
|
17
|
-
|
|
15
|
+
`),process.exit(1));function Rt(){let e=fe();e&&(process.env.FLOW_BASE_URL=e);}async function Pt(){Rt();try{le();}catch{}try{ge();}catch{}try{he();}catch{}D()||process.stderr.write(`
|
|
16
|
+
[flow-ai-obs] FLOW_API_KEY not found or invalid.
|
|
17
|
+
Set FLOW_API_KEY in your environment to enable telemetry.
|
|
18
18
|
|
|
19
|
-
`);}
|
|
19
|
+
`);}Pt().catch(()=>{}).finally(()=>Te());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ciandt-flow/flow-ai-obs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-beta.149",
|
|
4
4
|
"description": "Claude Code hooks for Langfuse OTLP tracing — cross-platform",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -22,9 +22,6 @@
|
|
|
22
22
|
"changeset": "changeset",
|
|
23
23
|
"version-packages": "changeset version",
|
|
24
24
|
"install:hooks": "node dist/cli.js install",
|
|
25
|
-
"auth:login": "node dist/cli.js auth login",
|
|
26
|
-
"auth:logout": "node dist/cli.js auth logout",
|
|
27
|
-
"auth:status": "node dist/cli.js auth status",
|
|
28
25
|
"smoke": "bash scripts/smoke-test.sh",
|
|
29
26
|
"smoke:debug": "bash scripts/smoke-test.sh --debug",
|
|
30
27
|
"smoke:send": "bash scripts/smoke-test.sh --send --allow-http --debug",
|