a24z 1.0.21 → 1.0.23

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/index.js CHANGED
@@ -159,7 +159,7 @@ ${QFD}
159
159
  Try running with %s or get access `,P.cyan("sudo"))+`
160
160
  to the local update config store via
161
161
  `+P.cyan(m$(" sudo chown -R $USER:$(id -gn $USER) %s ",T4));G6.on("exit",()=>{console.error(O7(F,{textAlignment:"center"}))})}}check(){if(!this.config||this.config.get("optOut")||this.#Z)return;if(this.update=this.config.get("update"),this.update)this.update.current=this.#J,this.config.delete("update");if(Date.now()-this.config.get("lastUpdateCheck")<this.#Y)return;V2D(G6.execPath,[CS.join(C2D,"check.js"),JSON.stringify(this.#D)],{detached:!0,stdio:"ignore"}).unref()}async fetchInfo(){let{distTag:D}=this.#D,F=await I$(this._packageName,{version:D});return{latest:F,current:this.#J,type:MS.default(this.#J,F)??D,name:this._packageName}}notify(D){let F=!this._shouldNotifyInNpmScript&&jk;if(!G6.stdout.isTTY||F||!this.update||!NS.default(this.update.latest,this.update.current))return this;D={isGlobal:mk,...D};let Z=D.isGlobal?`npm i -g ${this._packageName}`:`npm i ${this._packageName}`,J="Update available "+P.dim("{currentVersion}")+P.reset(" → ")+P.green("{latestVersion}")+`
162
- Run `+P.cyan("{updateCommand}")+" to update",Y=D.message||J;D.boxenOptions??={padding:1,margin:1,textAlignment:"center",borderColor:"yellow",borderStyle:"round"};let X=O7(g$(Y,{packageName:this._packageName,currentVersion:this.update.current,latestVersion:this.update.latest,updateCommand:Z}),D.boxenOptions);if(D.defer===!1)console.error(X);else G6.on("exit",()=>{console.error(X)});return this}}function b$(D){let F=new P7(D);return F.check(),F}var O3=d(Ax(),1);var Lx={name:"a24z",version:"1.0.21",description:"AI Agent Observability CLI - Monitor and analyze your AI tool performance",main:"dist/index.js",bin:{a24z:"./bin/a24z.js"},type:"module",files:["bin/","dist/","README.md"],scripts:{build:"NODE_ENV=production bun run build.ts","build:dev":"NODE_ENV=development bun run build.ts",prepublishOnly:"bun run build","perf:test":"node scripts/perf-test.js"},keywords:["claude","ai","observability","monitoring","cli","tools","analytics","performance"],author:"a24z",homepage:"https://a24z.ai",dependencies:{"@iarna/toml":"^2.2.5",chalk:"^5.3.0",commander:"^11.1.0",inquirer:"^9.2.12",open:"^9.1.0",ora:"^7.0.1","update-notifier":"^7.3.1"},devDependencies:{"@repo/types":"workspace:*","@types/bun":"latest","@types/iarna__toml":"^2.0.5","@types/inquirer":"^9.0.7","@types/node":"^20.10.0","@types/update-notifier":"^6.0.8",typescript:"^5.3.2"},engines:{node:">=16.0.0"}};function NZD(){return{apiUrl:"https://api.a24z.ai",authUrl:"https://app.a24z.ai",clientId:"client_01K4ZPKT6DNRF3FZFVHXZVWVJ8"}}var AZD=MZD(import.meta.url),LZD=pD.dirname(AZD),p7=pD.join(P3.homedir(),".a24z"),z0=pD.join(p7,"settings.json"),Ox=pD.join(P3.homedir(),".claude"),j8=pD.join(Ox,"settings.json"),RZD=pD.join(P3.homedir(),".gemini"),k8=pD.join(RZD,"settings.json"),TZD=pD.join(P3.homedir(),".codex"),S8=pD.join(TZD,"config.toml"),b7=pD.join(Ox,"a24z-config.json"),Tx=["claude-code","gemini-cli","codex"];function d7(D){let F=D.toLowerCase().trim();if(!Tx.includes(F))throw Error(`Unsupported tool: '${D}'. Supported tools: ${Tx.join(", ")}`);return F}function Ix(D,F=500){if(typeof D!=="string")throw Error("Input must be a string");return D.trim().substring(0,F)}class Px{config;constructor(){this.config=this.loadConfig()}loadConfig(){let D=NZD(),F={apiUrl:D.apiUrl,authUrl:D.authUrl,clientId:D.clientId,accessToken:null,refreshToken:null,apiKey:null,installedAt:null,tools:[]};try{if(XD.existsSync(z0)){let Z=XD.readFileSync(z0,"utf8").trim();if(!Z){console.warn(P.yellow("⚠️ Settings file is empty, using defaults"));try{XD.unlinkSync(z0)}catch($){}return F}let J=JSON.parse(Z),Y=!1;if(J.tool&&typeof J.tool==="string")J.tools=[J.tool],delete J.tool,Y=!0;if(!Array.isArray(J.tools))J.tools=[],Y=!0;let X={...F,...J};if(Y)try{XD.writeFileSync(z0,JSON.stringify(X,null,2)),console.log(P.green('✅ Migrated configuration from "tool" to "tools" array'))}catch($){console.warn(P.yellow("Warning: Could not save migrated configuration"))}return X}if(XD.existsSync(b7)){let Z=XD.readFileSync(b7,"utf8").trim();if(!Z){console.warn(P.yellow("⚠️ Legacy settings file is empty, using defaults"));try{XD.unlinkSync(b7)}catch(X){}return F}let J=JSON.parse(Z);if(J.tool&&typeof J.tool==="string")J.tools=[J.tool],delete J.tool;let Y={...F,...J};XD.mkdirSync(p7,{recursive:!0}),XD.writeFileSync(z0,JSON.stringify(Y,null,2));try{XD.unlinkSync(b7)}catch(X){}return console.log(P.green("✅ Migrated configuration to ~/.a24z/settings.json")),Y}}catch(Z){if(Z instanceof SyntaxError){console.warn(P.yellow("⚠️ Settings file is corrupted, using defaults"));try{if(XD.existsSync(z0))XD.unlinkSync(z0)}catch(J){}}else console.error(P.red("Error loading configuration:"),Z)}if(!XD.existsSync(z0))try{XD.mkdirSync(p7,{recursive:!0}),XD.writeFileSync(z0,JSON.stringify(F,null,2)),console.log(P.green("✅ Initialized configuration at ~/.a24z/settings.json"))}catch(Z){console.warn(P.yellow("⚠️ Could not create settings file, using defaults"))}return F}saveConfig(){try{XD.mkdirSync(p7,{recursive:!0}),XD.writeFileSync(z0,JSON.stringify(this.config,null,2))}catch(D){console.error(P.red("Error saving configuration:"),D)}}getInstalledTools(){try{if(XD.existsSync(z0)){let D=XD.readFileSync(z0,"utf8").trim();if(!D)return[];let F=JSON.parse(D);if(F.tool&&typeof F.tool==="string"&&!F.tools)return[F.tool];return Array.isArray(F.tools)?F.tools:[]}}catch(D){}return[]}async install(D,F={}){let Z;try{Z=d7(D)}catch(Y){console.error(P.red("❌ Error:"),Y instanceof Error?Y.message:Y),process.exit(1)}if(F.apiUrl)try{if(F.apiUrl=Ix(F.apiUrl,500),!new URL(F.apiUrl).protocol.startsWith("http"))throw Error("API URL must use HTTP or HTTPS protocol")}catch(Y){console.error(P.red("❌ Error: Invalid API URL:"),Y instanceof Error?Y.message:Y),process.exit(1)}if(F.authUrl)try{if(F.authUrl=Ix(F.authUrl,500),!new URL(F.authUrl).protocol.startsWith("http"))throw Error("Auth URL must use HTTP or HTTPS protocol")}catch(Y){console.error(P.red("❌ Error: Invalid Auth URL:"),Y instanceof Error?Y.message:Y),process.exit(1)}let J=O6(`Installing A24Z hooks for ${Z}...`).start();try{if(F.apiUrl)this.config.apiUrl=F.apiUrl;if(F.authUrl)this.config.authUrl=F.authUrl;if(Z==="claude-code")this.updateClaudeSettings();else if(Z==="gemini-cli")this.updateGeminiSettings();else if(Z==="codex")this.updateCodexSettings();if(!this.config.tools.includes(Z))this.config.tools.push(Z);this.config.installedAt=new Date().toISOString(),this.saveConfig(),J.succeed(`A24Z hooks installed successfully for ${Z}!`),console.log(P.green("✅ Installation Complete!")),console.log(P.cyan("\uD83D\uDCCB Next steps:")),console.log(P.white(" 1. Login to associate logs with your organization:"),P.yellow("a24z login")),console.log(P.white(" 2. Check installation status:"),P.yellow("a24z status")),console.log(P.white(` 3. Begin using ${D} - sessions will be automatically monitored`)),console.log(P.cyan("\uD83D\uDD27 Configuration:")),console.log(P.white(` • Tool: ${D}`));let Y=j8;if(Z==="gemini-cli")Y=k8;else if(Z==="codex")Y=S8;console.log(P.white(` • Settings file: ${Y}`)),console.log(P.white(` • API URL: ${this.config.apiUrl}`)),console.log(P.white(` • Auth URL: ${this.config.authUrl}`))}catch(Y){J.fail("Installation failed"),console.error(P.red("❌ Error:"),Y),process.exit(1)}}updateClaudeSettings(){let D={};if(XD.existsSync(j8))try{D=JSON.parse(XD.readFileSync(j8,"utf8"))}catch(X){console.warn(P.yellow("Warning: Could not parse existing settings.json, creating new one"))}if(typeof D.hooks!=="object"||D.hooks===null)D.hooks={};let F="a24z hook claude-code",Z=["SessionStart","SessionEnd"];for(let X of Z)this.addOrUpdateHook(D,X,F);if(!D.env||typeof D.env!=="object")D.env={};let J=this.config.apiKey||this.config.accessToken||"",Y=J?`Authorization=Bearer ${J}`:"";D.env={...D.env,CLAUDE_CODE_ENABLE_TELEMETRY:"1",OTEL_METRICS_EXPORTER:"otlp",OTEL_LOGS_EXPORTER:"otlp",OTEL_EXPORTER_OTLP_PROTOCOL:"http/json",OTEL_EXPORTER_OTLP_ENDPOINT:this.config.apiUrl,OTEL_EXPORTER_OTLP_HEADERS:Y,OTEL_METRIC_EXPORT_INTERVAL:"10000",OTEL_LOGS_EXPORT_INTERVAL:"5000"},XD.mkdirSync(pD.dirname(j8),{recursive:!0}),XD.writeFileSync(j8,JSON.stringify(D,null,2))}addOrUpdateHook(D,F,Z){if(!D.hooks)D.hooks={};let J=D.hooks[F],Y={matcher:"*",hooks:[{type:"command",command:Z}]};if(!Array.isArray(J)){D.hooks[F]=[Y];return}if(!J.some(($)=>$.hooks.some((Q)=>typeof Q.command==="string"&&Q.command.includes("a24z hook claude-code"))))J.push(Y)}updateGeminiSettings(){let D={};if(XD.existsSync(k8))try{D=JSON.parse(XD.readFileSync(k8,"utf8"))}catch(F){console.warn(P.yellow("Warning: Could not parse existing Gemini settings.json, creating new one"))}D.telemetry={enabled:!0,target:"local",otlpEndpoint:this.config.apiUrl,otlpProtocol:"http",logPrompts:!0,useCollector:!0,...D.telemetry},XD.mkdirSync(pD.dirname(k8),{recursive:!0}),XD.writeFileSync(k8,JSON.stringify(D,null,2))}updateCodexSettings(){let D={};if(XD.existsSync(S8))try{let Y=XD.readFileSync(S8,"utf8");D=O3.default.parse(Y)}catch(Y){console.warn(P.yellow("Warning: Could not parse existing Codex config.toml, creating new one"))}let F=this.config.apiKey,Z={};if(F)Z.authorization=`Bearer ${F}`,Z["x-otlp-api-key"]=`${F}`;D.otel={...D.otel,environment:"production",exporter:{"otlp-http":{endpoint:`${this.config.apiUrl}/v1/logs`,protocol:"http/json",headers:Z}},log_user_prompt:!0},XD.mkdirSync(pD.dirname(S8),{recursive:!0});let J=O3.default.stringify(D);XD.writeFileSync(S8,J)}async setApiKey(D){console.log(P.blue("\uD83D\uDD11 Configuring API key..."));try{if(!D||D.trim().length===0)throw Error("API key cannot be empty");this.config.apiKey=D.trim(),this.saveConfig();let F=this.config.tools;if(F.length>0){for(let Z of F)if(Z==="claude-code")this.updateClaudeSettings();else if(Z==="gemini-cli")this.updateGeminiSettings();else if(Z==="codex")this.updateCodexSettings()}if(console.log(P.green("✅ API key configured successfully!")),console.log(P.white("\uD83D\uDD27 Configuration saved to:"),P.cyan(z0)),F.length>0)console.log(P.white(`\uD83D\uDCDD Updated settings for: ${F.join(", ")}`));console.log(P.green("Your sessions will now be authenticated with this API key."))}catch(F){console.error(P.red("❌ Failed to configure API key:"),F),process.exit(1)}}async login(){console.log(P.blue("\uD83D\uDD10 Logging in to A24Z Observability..."));try{if(process.env.WORKOS_CLIENT_ID&&process.env.WORKOS_CLIENT_ID!==this.config.clientId)this.config.clientId=process.env.WORKOS_CLIENT_ID,this.saveConfig();let D=await fetch(`${this.config.authUrl}/api/auth/device`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({client_id:this.config.clientId})});if(!D.ok)throw Error(`Authentication request failed: ${D.status}`);let F=await D.json(),{device_code:Z,user_code:J,verification_uri:Y,verification_uri_complete:X,expires_in:$,interval:Q}=F.data;if(console.log(P.green("\uD83D\uDCF1 Complete authentication in your browser:")),console.log(P.cyan(` Go to: ${Y}`)),console.log(P.yellow(` Enter code: ${J}`)),X)console.log(P.gray(` Or visit: ${X}`));console.log(P.white(` Code expires in ${Math.floor($/60)} minutes`));let{openBrowser:G}=await dR.prompt([{type:"confirm",name:"openBrowser",message:"Open browser automatically?",default:!0}]);if(G)await AO(X||Y);let q=O6("Waiting for authentication...").start(),K=await this.pollForTokens(Z,Q,$);q.succeed("Authentication successful!"),this.config.accessToken=K.access_token,this.config.refreshToken=K.refresh_token||null,this.saveConfig(),console.log(P.blue("\uD83D\uDD11 Creating API key for CLI authentication..."));try{let B=await this.createApiKeyForCLI(K.access_token);if(B&&B.apiKey)this.config.apiKey=B.apiKey,this.saveConfig(),console.log(P.green("✅ API key created successfully"))}catch(B){console.log(P.yellow("⚠️ Could not create API key, will use access token instead")),console.log(P.gray(` (${B instanceof Error?B.message:"Unknown error"})`))}let E=this.config.tools;if(E.length>0){for(let B of E)if(B==="claude-code")this.updateClaudeSettings();else if(B==="gemini-cli")this.updateGeminiSettings();else if(B==="codex")this.updateCodexSettings()}if(console.log(P.green("✅ Login successful!")),K.user?.email)console.log(P.white("\uD83D\uDC64 User:"),P.cyan(K.user.email));console.log(P.green("Your sessions will now be associated with your organization."))}catch(D){console.error(P.red("❌ Login failed:"),D),console.log(P.yellow("Make sure the A24Z service is available and try again.")),process.exit(1)}}async createApiKeyForCLI(D){try{let F=await fetch(`${this.config.apiUrl}/api/v1/api-keys`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${D}`}});if(!F.ok){let Z=await F.text().catch(()=>"");throw Error(`API key creation failed: ${F.status} ${Z}`)}return await F.json()}catch(F){throw Error(`Failed to create API key: ${F instanceof Error?F.message:String(F)}`)}}async pollForTokens(D,F,Z){let J=Date.now(),Y=Z*1000,X=F;while(Date.now()-J<Y){try{let $=await fetch(`${this.config.authUrl}/api/auth/device/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({device_code:D,client_id:this.config.clientId})});if(!$.ok){let G="unknown_error",q=$.status;try{G=(await $.json()).error||G}catch{}if(q===428&&G==="authorization_pending"){await new Promise((K)=>setTimeout(K,X*1000));continue}if(q===429&&G==="slow_down"){X+=5,await new Promise((K)=>setTimeout(K,X*1000));continue}if(q===403&&G==="access_denied")throw Error("User denied authorization");if(q===400&&G==="expired_token")throw Error("Device code expired");if(q>=500){await new Promise((K)=>setTimeout(K,X*1000));continue}throw Error(`Token request failed: ${q} ${G}`)}let Q=await $.json();if(Q.success)return Q.data}catch($){if($.name==="TypeError"&&$.message.includes("fetch")){await new Promise((Q)=>setTimeout(Q,X*1000));continue}throw $}await new Promise(($)=>setTimeout($,X*1000))}throw Error("Authentication timeout")}async uninstall(D){let F;try{F=d7(D)}catch(J){console.error(P.red("❌ Error:"),J instanceof Error?J.message:J),process.exit(1)}let Z=O6(`Uninstalling a24z hooks for ${F}...`).start();try{if(F==="claude-code"&&XD.existsSync(j8))try{let J=JSON.parse(XD.readFileSync(j8,"utf8"));if(J&&typeof J==="object"&&typeof J.hooks==="object"&&J.hooks!==null){let Y=["SessionStart","SessionEnd"];for(let X of Y){let $=J.hooks[X];if(Array.isArray($)){for(let G of $)if(Array.isArray(G.hooks))G.hooks=G.hooks.filter((q)=>{if(typeof q.command!=="string")return!0;return!q.command.includes("a24z hook claude-code")});let Q=$.filter((G)=>Array.isArray(G.hooks)&&G.hooks.length>0);if(Q.length>0)J.hooks[X]=Q;else delete J.hooks[X]}}}XD.writeFileSync(j8,JSON.stringify(J,null,2))}catch(J){console.warn(P.yellow("Warning: Could not update Claude settings.json"))}if(F==="codex"&&XD.existsSync(S8))try{let J=XD.readFileSync(S8,"utf8"),Y=O3.default.parse(J);if(Y.otel)Y.otel.exporter="none";let X=O3.default.stringify(Y);XD.writeFileSync(S8,X)}catch(J){console.warn(P.yellow("Warning: Could not update Codex config.toml"))}if(F==="gemini-cli"&&XD.existsSync(k8))try{let J=JSON.parse(XD.readFileSync(k8,"utf8"));if(J.telemetry)J.telemetry.enabled=!1,delete J.telemetry.otlpEndpoint;XD.writeFileSync(k8,JSON.stringify(J,null,2))}catch(J){console.warn(P.yellow("Warning: Could not update Gemini settings.json"))}if(this.config.tools=this.config.tools.filter((J)=>J!==F),this.config.tools.length===0){if(XD.existsSync(z0))XD.unlinkSync(z0)}else this.saveConfig();if(Z.succeed(`a24z hooks uninstalled successfully for ${D}!`),console.log(P.green(`${D} will no longer send observability data.`)),this.config.tools.length>0)console.log(P.white(`Still installed: ${this.config.tools.join(", ")}`))}catch(J){Z.fail("Uninstallation failed"),console.error(P.red("❌ Error:"),J),process.exit(1)}}async status(){console.log(P.blue("\uD83D\uDCCA A24Z Observability Status"));let D=this.getInstalledTools();if(console.log(P.white("\uD83D\uDD27 Installation Status:")),D.length>0)console.log(` • Session monitoring: ${P.green("✅ Configured")}`),console.log(` • Installed tools: ${P.cyan(D.join(", "))}`);else console.log(` • Session monitoring: ${P.yellow("⚠️ Not configured")}`),console.log(P.gray(' Run "a24z install <tool>" to get started'));if(console.log(P.white("\uD83D\uDD10 Authentication Status:")),console.log(` • Logged in: ${this.config.accessToken?P.green("✅ Yes"):P.red("❌ No")}`),this.config.apiKey)console.log(` • API Key: ${P.green("✅ Configured")}`)}async hook(D="claude-code"){let F;try{F=d7(D)}catch(J){process.exit(1)}let Z=async()=>new Promise((J)=>{let Y="";process.stdin.setEncoding("utf8"),process.stdin.on("data",(X)=>{Y+=X}),process.stdin.on("end",()=>J(Y)),setTimeout(()=>J(Y),5000)});try{let J=await Z();if(this.config.accessToken&&this.isTokenExpired(this.config.accessToken))await this.refreshToken();if(!this.config.apiKey&&!this.config.accessToken)console.error('❌ No valid authentication credentials available. Please run "a24z login" to authenticate or configure an API key.'),process.exit(1);let Y=`${this.config.apiUrl}/api/v1/${F}/hooks`,X=this.config.apiKey||this.config.accessToken||"",$=new AbortController,Q=setTimeout(()=>$.abort(),200);try{await fetch(Y,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${X}`},body:JSON.stringify(J),signal:$.signal})}catch(G){}finally{clearTimeout(Q)}process.exit(0)}catch(J){process.exit(1)}}async seed(D="claude-code",F={}){let Z;try{Z=d7(D)}catch(Q){console.error(P.red("❌ Error:"),Q instanceof Error?Q.message:Q),process.exit(1)}let J=typeof F.root==="string"&&F.root.length>0?F.root:pD.join(P3.homedir(),".claude","projects"),Y=typeof F.concurrency==="number"&&F.concurrency>0?F.concurrency:5,X=F.dryRun===!0;if(this.config.accessToken&&this.isTokenExpired(this.config.accessToken))await this.refreshToken();if(!this.config.apiKey&&!this.config.accessToken){console.error(P.red("❌ Not authenticated. Run 'a24z login' first or configure an API key.")),process.exit(1);return}let $=O6(`Scanning transcripts in ${J} ...`).start();try{let Q=await this.collectTranscriptFiles(J);if($.succeed(`Found ${Q.length} transcript file(s).`),X){for(let M of Q)console.log(P.gray(`DRY RUN: ${M}`));console.log(P.green("✅ Dry run complete."));return}console.log(P.white(`\uD83D\uDCE4 Sending ${Q.length} transcript(s) to API (concurrency ${Y})...`));let G=0,q=0,K=`${this.config.apiUrl}/api/v1/${Z}/hooks`,E=0,B=Q.length,H=async()=>{while(!0){let M=E;if(M>=B)return;E++;let A=Q[M],R=this.deriveSessionIdFromPath(A);if(!R){q++,console.warn(P.yellow(`⚠️ Skipping (cannot derive session id): ${A}`));continue}let x=await this.extractCwdFromTranscript(A)||this.decodeCwdFromPath(A)||process.cwd(),_={hook_event_name:"SessionEnd",session_id:R,transcript_path:A,cwd:x,reason:"seed"},u=this.config.apiKey||this.config.accessToken||"",s=new AbortController,e=setTimeout(()=>s.abort(),15000);try{let i=await fetch(K,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${u}`},body:JSON.stringify(_),signal:s.signal});if(!i.ok){q++;let TD=await i.text().catch(()=>"");console.error(P.red(`❌ Failed (${i.status}): ${A}`),TD?P.gray(TD):"")}else G++,console.log(P.green(`✅ Sent: ${A}`))}catch(i){q++,console.error(P.red(`❌ Error sending ${A}:`),i)}finally{clearTimeout(e)}}},C=[];for(let M=0;M<Y;M++)C.push(H());if(await Promise.all(C),console.log(P.white(`
162
+ Run `+P.cyan("{updateCommand}")+" to update",Y=D.message||J;D.boxenOptions??={padding:1,margin:1,textAlignment:"center",borderColor:"yellow",borderStyle:"round"};let X=O7(g$(Y,{packageName:this._packageName,currentVersion:this.update.current,latestVersion:this.update.latest,updateCommand:Z}),D.boxenOptions);if(D.defer===!1)console.error(X);else G6.on("exit",()=>{console.error(X)});return this}}function b$(D){let F=new P7(D);return F.check(),F}var O3=d(Ax(),1);var Lx={name:"a24z",version:"1.0.23",description:"AI Agent Observability CLI - Monitor and analyze your AI tool performance",main:"dist/index.js",bin:{a24z:"./bin/a24z.js"},type:"module",files:["bin/","dist/","README.md"],scripts:{build:"NODE_ENV=production bun run build.ts","build:dev":"NODE_ENV=development bun run build.ts",prepublishOnly:"bun run build","perf:test":"node scripts/perf-test.js"},keywords:["claude","ai","observability","monitoring","cli","tools","analytics","performance"],author:"a24z",homepage:"https://a24z.ai",dependencies:{},devDependencies:{"@iarna/toml":"^2.2.5","@repo/types":"workspace:*","@types/bun":"latest","@types/iarna__toml":"^2.0.5","@types/inquirer":"^9.0.7","@types/node":"^20.10.0","@types/update-notifier":"^6.0.8",chalk:"^5.3.0",commander:"^11.1.0",inquirer:"^9.2.12",open:"^9.1.0",ora:"^7.0.1",typescript:"^5.3.2","update-notifier":"^7.3.1"},engines:{node:">=16.0.0"}};function NZD(){return{apiUrl:"https://api.a24z.ai",authUrl:"https://app.a24z.ai",clientId:"client_01K4ZPKT6DNRF3FZFVHXZVWVJ8"}}var AZD=MZD(import.meta.url),LZD=pD.dirname(AZD),p7=pD.join(P3.homedir(),".a24z"),z0=pD.join(p7,"settings.json"),Ox=pD.join(P3.homedir(),".claude"),j8=pD.join(Ox,"settings.json"),RZD=pD.join(P3.homedir(),".gemini"),k8=pD.join(RZD,"settings.json"),TZD=pD.join(P3.homedir(),".codex"),S8=pD.join(TZD,"config.toml"),b7=pD.join(Ox,"a24z-config.json"),Tx=["claude-code","gemini-cli","codex"];function d7(D){let F=D.toLowerCase().trim();if(!Tx.includes(F))throw Error(`Unsupported tool: '${D}'. Supported tools: ${Tx.join(", ")}`);return F}function Ix(D,F=500){if(typeof D!=="string")throw Error("Input must be a string");return D.trim().substring(0,F)}class Px{config;constructor(){this.config=this.loadConfig()}loadConfig(){let D=NZD(),F={apiUrl:D.apiUrl,authUrl:D.authUrl,clientId:D.clientId,accessToken:null,refreshToken:null,apiKey:null,installedAt:null,tools:[]};try{if(XD.existsSync(z0)){let Z=XD.readFileSync(z0,"utf8").trim();if(!Z){console.warn(P.yellow("⚠️ Settings file is empty, using defaults"));try{XD.unlinkSync(z0)}catch($){}return F}let J=JSON.parse(Z),Y=!1;if(J.tool&&typeof J.tool==="string")J.tools=[J.tool],delete J.tool,Y=!0;if(!Array.isArray(J.tools))J.tools=[],Y=!0;let X={...F,...J};if(Y)try{XD.writeFileSync(z0,JSON.stringify(X,null,2)),console.log(P.green('✅ Migrated configuration from "tool" to "tools" array'))}catch($){console.warn(P.yellow("Warning: Could not save migrated configuration"))}return X}if(XD.existsSync(b7)){let Z=XD.readFileSync(b7,"utf8").trim();if(!Z){console.warn(P.yellow("⚠️ Legacy settings file is empty, using defaults"));try{XD.unlinkSync(b7)}catch(X){}return F}let J=JSON.parse(Z);if(J.tool&&typeof J.tool==="string")J.tools=[J.tool],delete J.tool;let Y={...F,...J};XD.mkdirSync(p7,{recursive:!0}),XD.writeFileSync(z0,JSON.stringify(Y,null,2));try{XD.unlinkSync(b7)}catch(X){}return console.log(P.green("✅ Migrated configuration to ~/.a24z/settings.json")),Y}}catch(Z){if(Z instanceof SyntaxError){console.warn(P.yellow("⚠️ Settings file is corrupted, using defaults"));try{if(XD.existsSync(z0))XD.unlinkSync(z0)}catch(J){}}else console.error(P.red("Error loading configuration:"),Z)}if(!XD.existsSync(z0))try{XD.mkdirSync(p7,{recursive:!0}),XD.writeFileSync(z0,JSON.stringify(F,null,2)),console.log(P.green("✅ Initialized configuration at ~/.a24z/settings.json"))}catch(Z){console.warn(P.yellow("⚠️ Could not create settings file, using defaults"))}return F}saveConfig(){try{XD.mkdirSync(p7,{recursive:!0}),XD.writeFileSync(z0,JSON.stringify(this.config,null,2))}catch(D){console.error(P.red("Error saving configuration:"),D)}}getInstalledTools(){try{if(XD.existsSync(z0)){let D=XD.readFileSync(z0,"utf8").trim();if(!D)return[];let F=JSON.parse(D);if(F.tool&&typeof F.tool==="string"&&!F.tools)return[F.tool];return Array.isArray(F.tools)?F.tools:[]}}catch(D){}return[]}async install(D,F={}){let Z;try{Z=d7(D)}catch(Y){console.error(P.red("❌ Error:"),Y instanceof Error?Y.message:Y),process.exit(1)}if(F.apiUrl)try{if(F.apiUrl=Ix(F.apiUrl,500),!new URL(F.apiUrl).protocol.startsWith("http"))throw Error("API URL must use HTTP or HTTPS protocol")}catch(Y){console.error(P.red("❌ Error: Invalid API URL:"),Y instanceof Error?Y.message:Y),process.exit(1)}if(F.authUrl)try{if(F.authUrl=Ix(F.authUrl,500),!new URL(F.authUrl).protocol.startsWith("http"))throw Error("Auth URL must use HTTP or HTTPS protocol")}catch(Y){console.error(P.red("❌ Error: Invalid Auth URL:"),Y instanceof Error?Y.message:Y),process.exit(1)}let J=O6(`Installing A24Z hooks for ${Z}...`).start();try{if(F.apiUrl)this.config.apiUrl=F.apiUrl;if(F.authUrl)this.config.authUrl=F.authUrl;if(Z==="claude-code")this.updateClaudeSettings();else if(Z==="gemini-cli")this.updateGeminiSettings();else if(Z==="codex")this.updateCodexSettings();if(!this.config.tools.includes(Z))this.config.tools.push(Z);this.config.installedAt=new Date().toISOString(),this.saveConfig(),J.succeed(`A24Z hooks installed successfully for ${Z}!`),console.log(P.green("✅ Installation Complete!")),console.log(P.cyan("\uD83D\uDCCB Next steps:")),console.log(P.white(" 1. Login to associate logs with your organization:"),P.yellow("a24z login")),console.log(P.white(" 2. Check installation status:"),P.yellow("a24z status")),console.log(P.white(` 3. Begin using ${D} - sessions will be automatically monitored`)),console.log(P.cyan("\uD83D\uDD27 Configuration:")),console.log(P.white(` • Tool: ${D}`));let Y=j8;if(Z==="gemini-cli")Y=k8;else if(Z==="codex")Y=S8;console.log(P.white(` • Settings file: ${Y}`)),console.log(P.white(` • API URL: ${this.config.apiUrl}`)),console.log(P.white(` • Auth URL: ${this.config.authUrl}`))}catch(Y){J.fail("Installation failed"),console.error(P.red("❌ Error:"),Y),process.exit(1)}}updateClaudeSettings(){let D={};if(XD.existsSync(j8))try{D=JSON.parse(XD.readFileSync(j8,"utf8"))}catch(X){console.warn(P.yellow("Warning: Could not parse existing settings.json, creating new one"))}if(typeof D.hooks!=="object"||D.hooks===null)D.hooks={};let F="a24z hook claude-code",Z=["SessionStart","SessionEnd"];for(let X of Z)this.addOrUpdateHook(D,X,F);if(!D.env||typeof D.env!=="object")D.env={};let J=this.config.apiKey||this.config.accessToken||"",Y=J?`Authorization=Bearer ${J}`:"";D.env={...D.env,CLAUDE_CODE_ENABLE_TELEMETRY:"1",OTEL_METRICS_EXPORTER:"otlp",OTEL_LOGS_EXPORTER:"otlp",OTEL_EXPORTER_OTLP_PROTOCOL:"http/json",OTEL_EXPORTER_OTLP_ENDPOINT:this.config.apiUrl,OTEL_EXPORTER_OTLP_HEADERS:Y,OTEL_METRIC_EXPORT_INTERVAL:"10000",OTEL_LOGS_EXPORT_INTERVAL:"5000"},XD.mkdirSync(pD.dirname(j8),{recursive:!0}),XD.writeFileSync(j8,JSON.stringify(D,null,2))}addOrUpdateHook(D,F,Z){if(!D.hooks)D.hooks={};let J=D.hooks[F],Y={matcher:"*",hooks:[{type:"command",command:Z}]};if(!Array.isArray(J)){D.hooks[F]=[Y];return}if(!J.some(($)=>$.hooks.some((Q)=>typeof Q.command==="string"&&Q.command.includes("a24z hook claude-code"))))J.push(Y)}updateGeminiSettings(){let D={};if(XD.existsSync(k8))try{D=JSON.parse(XD.readFileSync(k8,"utf8"))}catch(F){console.warn(P.yellow("Warning: Could not parse existing Gemini settings.json, creating new one"))}D.telemetry={enabled:!0,target:"local",otlpEndpoint:this.config.apiUrl,otlpProtocol:"http",logPrompts:!0,useCollector:!0,...D.telemetry},XD.mkdirSync(pD.dirname(k8),{recursive:!0}),XD.writeFileSync(k8,JSON.stringify(D,null,2))}updateCodexSettings(){let D={};if(XD.existsSync(S8))try{let Y=XD.readFileSync(S8,"utf8");D=O3.default.parse(Y)}catch(Y){console.warn(P.yellow("Warning: Could not parse existing Codex config.toml, creating new one"))}let F=this.config.apiKey,Z={};if(F)Z.authorization=`Bearer ${F}`,Z["x-otlp-api-key"]=`${F}`;D.otel={...D.otel,environment:"production",exporter:{"otlp-http":{endpoint:`${this.config.apiUrl}/v1/logs`,protocol:"http/json",headers:Z}},log_user_prompt:!0},XD.mkdirSync(pD.dirname(S8),{recursive:!0});let J=O3.default.stringify(D);XD.writeFileSync(S8,J)}async setApiKey(D){console.log(P.blue("\uD83D\uDD11 Configuring API key..."));try{if(!D||D.trim().length===0)throw Error("API key cannot be empty");this.config.apiKey=D.trim(),this.saveConfig();let F=this.config.tools;if(F.length>0){for(let Z of F)if(Z==="claude-code")this.updateClaudeSettings();else if(Z==="gemini-cli")this.updateGeminiSettings();else if(Z==="codex")this.updateCodexSettings()}if(console.log(P.green("✅ API key configured successfully!")),console.log(P.white("\uD83D\uDD27 Configuration saved to:"),P.cyan(z0)),F.length>0)console.log(P.white(`\uD83D\uDCDD Updated settings for: ${F.join(", ")}`));console.log(P.green("Your sessions will now be authenticated with this API key."))}catch(F){console.error(P.red("❌ Failed to configure API key:"),F),process.exit(1)}}async login(){console.log(P.blue("\uD83D\uDD10 Logging in to A24Z Observability..."));try{if(process.env.WORKOS_CLIENT_ID&&process.env.WORKOS_CLIENT_ID!==this.config.clientId)this.config.clientId=process.env.WORKOS_CLIENT_ID,this.saveConfig();let D=await fetch(`${this.config.authUrl}/api/auth/device`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({client_id:this.config.clientId})});if(!D.ok)throw Error(`Authentication request failed: ${D.status}`);let F=await D.json(),{device_code:Z,user_code:J,verification_uri:Y,verification_uri_complete:X,expires_in:$,interval:Q}=F.data;if(console.log(P.green("\uD83D\uDCF1 Complete authentication in your browser:")),console.log(P.cyan(` Go to: ${Y}`)),console.log(P.yellow(` Enter code: ${J}`)),X)console.log(P.gray(` Or visit: ${X}`));console.log(P.white(` Code expires in ${Math.floor($/60)} minutes`));let{openBrowser:G}=await dR.prompt([{type:"confirm",name:"openBrowser",message:"Open browser automatically?",default:!0}]);if(G)await AO(X||Y);let q=O6("Waiting for authentication...").start(),K=await this.pollForTokens(Z,Q,$);q.succeed("Authentication successful!"),this.config.accessToken=K.access_token,this.config.refreshToken=K.refresh_token||null,this.saveConfig(),console.log(P.blue("\uD83D\uDD11 Creating API key for CLI authentication..."));try{let B=await this.createApiKeyForCLI(K.access_token);if(B&&B.apiKey)this.config.apiKey=B.apiKey,this.saveConfig(),console.log(P.green("✅ API key created successfully"))}catch(B){console.log(P.yellow("⚠️ Could not create API key, will use access token instead")),console.log(P.gray(` (${B instanceof Error?B.message:"Unknown error"})`))}let E=this.config.tools;if(E.length>0){for(let B of E)if(B==="claude-code")this.updateClaudeSettings();else if(B==="gemini-cli")this.updateGeminiSettings();else if(B==="codex")this.updateCodexSettings()}if(console.log(P.green("✅ Login successful!")),K.user?.email)console.log(P.white("\uD83D\uDC64 User:"),P.cyan(K.user.email));console.log(P.green("Your sessions will now be associated with your organization."))}catch(D){console.error(P.red("❌ Login failed:"),D),console.log(P.yellow("Make sure the A24Z service is available and try again.")),process.exit(1)}}async createApiKeyForCLI(D){try{let F=await fetch(`${this.config.apiUrl}/api/v1/api-keys`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${D}`}});if(!F.ok){let Z=await F.text().catch(()=>"");throw Error(`API key creation failed: ${F.status} ${Z}`)}return await F.json()}catch(F){throw Error(`Failed to create API key: ${F instanceof Error?F.message:String(F)}`)}}async pollForTokens(D,F,Z){let J=Date.now(),Y=Z*1000,X=F;while(Date.now()-J<Y){try{let $=await fetch(`${this.config.authUrl}/api/auth/device/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({device_code:D,client_id:this.config.clientId})});if(!$.ok){let G="unknown_error",q=$.status;try{G=(await $.json()).error||G}catch{}if(q===428&&G==="authorization_pending"){await new Promise((K)=>setTimeout(K,X*1000));continue}if(q===429&&G==="slow_down"){X+=5,await new Promise((K)=>setTimeout(K,X*1000));continue}if(q===403&&G==="access_denied")throw Error("User denied authorization");if(q===400&&G==="expired_token")throw Error("Device code expired");if(q>=500){await new Promise((K)=>setTimeout(K,X*1000));continue}throw Error(`Token request failed: ${q} ${G}`)}let Q=await $.json();if(Q.success)return Q.data}catch($){if($.name==="TypeError"&&$.message.includes("fetch")){await new Promise((Q)=>setTimeout(Q,X*1000));continue}throw $}await new Promise(($)=>setTimeout($,X*1000))}throw Error("Authentication timeout")}async uninstall(D){let F;try{F=d7(D)}catch(J){console.error(P.red("❌ Error:"),J instanceof Error?J.message:J),process.exit(1)}let Z=O6(`Uninstalling a24z hooks for ${F}...`).start();try{if(F==="claude-code"&&XD.existsSync(j8))try{let J=JSON.parse(XD.readFileSync(j8,"utf8"));if(J&&typeof J==="object"&&typeof J.hooks==="object"&&J.hooks!==null){let Y=["SessionStart","SessionEnd"];for(let X of Y){let $=J.hooks[X];if(Array.isArray($)){for(let G of $)if(Array.isArray(G.hooks))G.hooks=G.hooks.filter((q)=>{if(typeof q.command!=="string")return!0;return!q.command.includes("a24z hook claude-code")});let Q=$.filter((G)=>Array.isArray(G.hooks)&&G.hooks.length>0);if(Q.length>0)J.hooks[X]=Q;else delete J.hooks[X]}}}XD.writeFileSync(j8,JSON.stringify(J,null,2))}catch(J){console.warn(P.yellow("Warning: Could not update Claude settings.json"))}if(F==="codex"&&XD.existsSync(S8))try{let J=XD.readFileSync(S8,"utf8"),Y=O3.default.parse(J);if(Y.otel)Y.otel.exporter="none";let X=O3.default.stringify(Y);XD.writeFileSync(S8,X)}catch(J){console.warn(P.yellow("Warning: Could not update Codex config.toml"))}if(F==="gemini-cli"&&XD.existsSync(k8))try{let J=JSON.parse(XD.readFileSync(k8,"utf8"));if(J.telemetry)J.telemetry.enabled=!1,delete J.telemetry.otlpEndpoint;XD.writeFileSync(k8,JSON.stringify(J,null,2))}catch(J){console.warn(P.yellow("Warning: Could not update Gemini settings.json"))}if(this.config.tools=this.config.tools.filter((J)=>J!==F),this.config.tools.length===0){if(XD.existsSync(z0))XD.unlinkSync(z0)}else this.saveConfig();if(Z.succeed(`a24z hooks uninstalled successfully for ${D}!`),console.log(P.green(`${D} will no longer send observability data.`)),this.config.tools.length>0)console.log(P.white(`Still installed: ${this.config.tools.join(", ")}`))}catch(J){Z.fail("Uninstallation failed"),console.error(P.red("❌ Error:"),J),process.exit(1)}}async status(){console.log(P.blue("\uD83D\uDCCA A24Z Observability Status"));let D=this.getInstalledTools();if(console.log(P.white("\uD83D\uDD27 Installation Status:")),D.length>0)console.log(` • Session monitoring: ${P.green("✅ Configured")}`),console.log(` • Installed tools: ${P.cyan(D.join(", "))}`);else console.log(` • Session monitoring: ${P.yellow("⚠️ Not configured")}`),console.log(P.gray(' Run "a24z install <tool>" to get started'));if(console.log(P.white("\uD83D\uDD10 Authentication Status:")),console.log(` • Logged in: ${this.config.accessToken?P.green("✅ Yes"):P.red("❌ No")}`),this.config.apiKey)console.log(` • API Key: ${P.green("✅ Configured")}`)}async hook(D="claude-code"){let F;try{F=d7(D)}catch(J){process.exit(1)}let Z=async()=>new Promise((J)=>{let Y="";process.stdin.setEncoding("utf8"),process.stdin.on("data",(X)=>{Y+=X}),process.stdin.on("end",()=>J(Y)),setTimeout(()=>J(Y),5000)});try{let J=await Z();if(this.config.accessToken&&this.isTokenExpired(this.config.accessToken))await this.refreshToken();if(!this.config.apiKey&&!this.config.accessToken)console.error('❌ No valid authentication credentials available. Please run "a24z login" to authenticate or configure an API key.'),process.exit(1);let Y=`${this.config.apiUrl}/api/v1/${F}/hooks`,X=this.config.apiKey||this.config.accessToken||"",$=new AbortController,Q=setTimeout(()=>$.abort(),200);try{await fetch(Y,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${X}`},body:JSON.stringify(J),signal:$.signal})}catch(G){}finally{clearTimeout(Q)}process.exit(0)}catch(J){process.exit(1)}}async seed(D="claude-code",F={}){let Z;try{Z=d7(D)}catch(Q){console.error(P.red("❌ Error:"),Q instanceof Error?Q.message:Q),process.exit(1)}let J=typeof F.root==="string"&&F.root.length>0?F.root:pD.join(P3.homedir(),".claude","projects"),Y=typeof F.concurrency==="number"&&F.concurrency>0?F.concurrency:5,X=F.dryRun===!0;if(this.config.accessToken&&this.isTokenExpired(this.config.accessToken))await this.refreshToken();if(!this.config.apiKey&&!this.config.accessToken){console.error(P.red("❌ Not authenticated. Run 'a24z login' first or configure an API key.")),process.exit(1);return}let $=O6(`Scanning transcripts in ${J} ...`).start();try{let Q=await this.collectTranscriptFiles(J);if($.succeed(`Found ${Q.length} transcript file(s).`),X){for(let M of Q)console.log(P.gray(`DRY RUN: ${M}`));console.log(P.green("✅ Dry run complete."));return}console.log(P.white(`\uD83D\uDCE4 Sending ${Q.length} transcript(s) to API (concurrency ${Y})...`));let G=0,q=0,K=`${this.config.apiUrl}/api/v1/${Z}/hooks`,E=0,B=Q.length,H=async()=>{while(!0){let M=E;if(M>=B)return;E++;let A=Q[M],R=this.deriveSessionIdFromPath(A);if(!R){q++,console.warn(P.yellow(`⚠️ Skipping (cannot derive session id): ${A}`));continue}let x=await this.extractCwdFromTranscript(A)||this.decodeCwdFromPath(A)||process.cwd(),_={hook_event_name:"SessionEnd",session_id:R,transcript_path:A,cwd:x,reason:"seed"},u=this.config.apiKey||this.config.accessToken||"",s=new AbortController,e=setTimeout(()=>s.abort(),15000);try{let i=await fetch(K,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${u}`},body:JSON.stringify(_),signal:s.signal});if(!i.ok){q++;let TD=await i.text().catch(()=>"");console.error(P.red(`❌ Failed (${i.status}): ${A}`),TD?P.gray(TD):"")}else G++,console.log(P.green(`✅ Sent: ${A}`))}catch(i){q++,console.error(P.red(`❌ Error sending ${A}:`),i)}finally{clearTimeout(e)}}},C=[];for(let M=0;M<Y;M++)C.push(H());if(await Promise.all(C),console.log(P.white(`
163
163
  \uD83D\uDCC8 Seed summary:`)),console.log(` • Total: ${B}`),console.log(P.green(` • Sent: ${G}`)),console.log(P.red(` • Failed: ${q}`)),q>0)process.exitCode=1}catch(Q){$.fail("Failed to scan or send transcripts"),console.error(P.red("❌ Error:"),Q),process.exit(1)}}async collectTranscriptFiles(D){let F=[],Z=async(J)=>{let Y=[];try{Y=await Rx.readdir(J,{withFileTypes:!0})}catch{return}for(let X of Y){let $=pD.join(J,X.name);if(X.isDirectory())await Z($);else if(X.isFile()&&X.name.toLowerCase().endsWith(".jsonl"))F.push($)}};return await Z(D),F.sort()}deriveSessionIdFromPath(D){let F=pD.basename(D),Z=F.toLowerCase().lastIndexOf(".jsonl");if(Z<=0)return null;let J=F.substring(0,Z);return J.length>0?J:null}async extractCwdFromTranscript(D){try{let Z=(await Rx.readFile(D,"utf8")).split(`
164
164
  `).filter((J)=>J.trim().length>0).slice(0,100);for(let J of Z)try{let Y=JSON.parse(J),X=Y&&typeof Y.cwd==="string"?Y.cwd:null;if(X&&X.length>0)return X}catch{}}catch{}return null}decodeCwdFromPath(D){try{let F=pD.basename(pD.dirname(D));if(!F||F.length===0)return null;if(F.startsWith("-"))return`/${F.slice(1).split("-").join("/")}`;return null}catch{return null}}isTokenExpired(D){try{let F=D.split(".");if(F.length!==3)return!0;let J=JSON.parse(atob(F[1])).exp*1000,X=Date.now()+300000;return J<X}catch(F){return!0}}async refreshToken(){if(!this.config.refreshToken){this.config.accessToken=null,this.saveConfig();return}try{let D=await fetch(`${this.config.authUrl}/api/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.accessToken}`},body:JSON.stringify({refresh_token:this.config.refreshToken})});if(!D.ok){this.config.accessToken=null,this.config.refreshToken=null,this.saveConfig();return}let F=await D.json();if(F.success&&F.data.access_token)this.config.accessToken=F.data.access_token,this.config.refreshToken=F.data.refresh_token||this.config.refreshToken,this.saveConfig();else throw Error("Invalid token refresh response")}catch(D){this.config.accessToken=null,this.config.refreshToken=null,this.saveConfig()}}}var L1=new xQ,V6=new Px;if(process.argv[2]!=="hook")b$({pkg:Lx}).notify();function wx(){try{let D=pD.resolve(LZD,"..","package.json"),F=XD.readFileSync(D,"utf8"),Z=JSON.parse(F);if(typeof Z.version==="string"&&Z.version.length>0)return Z.version}catch{}return"0.0.0"}function jx(){return`
165
165
  ░▒▓██████▓▒░░▒▓███████▓▒░░▒▓█▓▒░░▒▓█▓▒░▒▓████████▓▒░
@@ -172,4 +172,4 @@ Run `+P.cyan("{updateCommand}")+" to update",Y=D.message||J;D.boxenOptions??={pa
172
172
  `}L1.name("a24z").description(`${jx()}
173
173
  Monitor and analyze your Coding Agents`).version(wx()).showHelpAfterError().showSuggestionAfterError(!0);L1.command("version").description("Show version information with logo").action(()=>{console.log(jx()),console.log(P.cyan(`A24Z Observability CLI v${wx()}`)),console.log("")});L1.command("install <tool>").description("Install A24Z observability hooks for a specific tool").option("--api-url <url>","Set the a24z api url for log ingestion").option("--auth-url <url>","Set the a24z auth url for authentication").action(async(D,F)=>{await V6.install(D,{apiUrl:F.apiUrl,authUrl:F.authUrl})});L1.command("login").description("Authenticate with A24Z").action(async()=>{await V6.login()});L1.command("status").description("Show current installation and authentication status").action(async()=>{await V6.status()});L1.command("uninstall <tool>").description("Remove A24Z observability hooks for a specific tool").action(async(D)=>{await V6.uninstall(D)});L1.command("hook <tool>").description("Internal: process a hook payload from stdin and send to A24Z").action(async(D)=>{await V6.hook(D)});L1.command("seed-transcripts").description("Scan Claude transcript directory and send synthetic SessionEnd hooks to ingest all transcripts").option("--tool <tool>","Tool name to use (default: claude-code)").option("--root <dir>","Root directory to scan (default: ~/.claude/projects)").option("--concurrency <n>","Number of parallel requests (default: 5)").option("--dry-run","List files without sending").action(async(D)=>{let F=typeof D.tool==="string"&&D.tool.length>0?D.tool:"claude-code",Z=typeof D.root==="string"&&D.root.length>0?D.root:void 0,J=D.concurrency?Number(D.concurrency):void 0,Y=D.dryRun===!0;await V6.seed(F,{root:Z,concurrency:J,dryRun:Y})});L1.command("set-api-key <apiKey>").description("Configure an API key for authentication (alternative to login)").action(async(D)=>{await V6.setApiKey(D)});L1.parse();
174
174
 
175
- //# debugId=F3F961D5ABE8BBB864756E2164756E21
175
+ //# debugId=9ACBCDE1A62BB8D964756E2164756E21