@vladar107/claudescope 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cli.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire as __cr } from 'node:module';
|
|
3
3
|
const require = __cr(import.meta.url);
|
|
4
|
-
import{spawn as G,spawnSync as I}from"node:child_process";import{existsSync as D,mkdirSync as B,openSync as ue,readFileSync as
|
|
5
|
-
`),Z(f,p),{fetchedAt:s,modelCount:Object.keys(n).length,changed:o,path:p}}var O=fe(he(import.meta.url)),_e=E(O,"server.js"),u=E(a,"daemon.json"),w=E(a,"daemon.log"),P=E(a,"update-check.json"),m="@vladar107/claudescope",we=
|
|
4
|
+
import{spawn as G,spawnSync as I}from"node:child_process";import{existsSync as D,mkdirSync as B,openSync as ue,readFileSync as A,realpathSync as de,rmSync as C,writeFileSync as J}from"node:fs";import{dirname as fe,join as E}from"node:path";import{createInterface as me}from"node:readline/promises";import{parseArgs as ge}from"node:util";import{fileURLToPath as he}from"node:url";import{copyFileSync as ke,existsSync as X,mkdirSync as De}from"node:fs";import{homedir as l}from"node:os";import{dirname as Y,join as i}from"node:path";import{fileURLToPath as q}from"node:url";var R=Y(q(import.meta.url));function T(e,t){return e.find(n=>X(n))??t}var v=Number(process.env.PORT??4317),h=i(R,"..");function _(e){return e==="~"?l():e.startsWith("~/")?i(l(),e.slice(2)):e}var b=_(process.env.CLAUDE_PROJECTS_DIR??i(l(),".claude","projects")),Te=_(process.env.CODEX_SESSIONS_DIR??i(l(),".codex","sessions")),$e=_(process.env.JUNIE_SESSIONS_DIR??i(l(),".junie","sessions")),Me=process.env.OPEN_BROWSER==="1",Ue=Number(process.env.REINDEX_INTERVAL_MS??15e3),a=_(process.env.CLAUDESCOPE_HOME??i(l(),".claudescope")),Fe=process.env.DUCKDB_PATH??i(a,"index.duckdb"),He=T([i(R,"pricing.default.json"),i(h,"pricing.json")],i(h,"pricing.json")),je=process.env.PRICING_PATH??i(a,"pricing.json"),p=process.env.FETCHED_PRICING_PATH??i(a,"pricing.fetched.json"),$=process.env.LITELLM_PRICING_URL??"https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",Ge=Number(process.env.PRICING_REFRESH_INTERVAL_MS??1440*60*1e3),Be=process.env.WEB_DIST_DIR??T([i(R,"web"),i(h,"..","web","dist")],i(h,"..","web","dist")),c="0.5.2";import{mkdirSync as z,readFileSync as Q,renameSync as Z,writeFileSync as ee}from"node:fs";import{dirname as M,join as te}from"node:path";var oe=new Set(["anthropic","openai","gemini","xai","mistral","deepseek"]),ne=new Set(["chat","responses"]),re=1e6,se=1e4,ie=3e4;function y(e){if(typeof e!="number"||!Number.isFinite(e)||e<0)return null;let t=e*re;return t<=se?t:null}function U(e){return e==null?0:y(e)}function ce(e){let t={};if(typeof e!="object"||e===null)return t;for(let[n,r]of Object.entries(e)){if(n==="sample_spec"||n.includes("/")||typeof r!="object"||r===null)continue;let o=r;if(typeof o.litellm_provider!="string"||!oe.has(o.litellm_provider)||typeof o.mode!="string"||!ne.has(o.mode))continue;let s=y(o.input_cost_per_token),d=y(o.output_cost_per_token),f=U(o.cache_creation_input_token_cost),x=U(o.cache_read_input_token_cost);s===null||d===null||f===null||x===null||(t[n]={input:s,output:d,cacheWrite:f,cacheRead:x})}return t}function ae(e){let t=Object.keys(e),n=t.some(o=>o.startsWith("claude")),r=t.some(o=>/^(gpt|o\d|chatgpt|codex)/.test(o));if(!n||!r){let o=[!n&&"anthropic",!r&&"openai"].filter(Boolean).join(", ");throw new Error(`Fetched pricing failed validation: no ${o} model survived mapping (${t.length} model(s) total). LiteLLM schema may have drifted.`)}}function le(e){try{return JSON.parse(Q(e,"utf8"))?.models??{}}catch{return{}}}function pe(e,t){let n=0;for(let[r,o]of Object.entries(e)){let s=t[r];(!s||s.input!==o.input||s.output!==o.output||s.cacheWrite!==o.cacheWrite||s.cacheRead!==o.cacheRead)&&(n+=1)}return n}async function F(){let e=await fetch($,{signal:AbortSignal.timeout(ie)});if(!e.ok)throw new Error(`Pricing fetch failed: ${e.status} ${e.statusText}`);let t=await e.json(),n=ce(t);ae(n);let r=le(p),o=pe(n,r),s=new Date().toISOString(),d={fetchedAt:s,models:n};z(M(p),{recursive:!0});let f=te(M(p),`.pricing.fetched.${process.pid}.tmp`);return ee(f,`${JSON.stringify(d,null,2)}
|
|
5
|
+
`),Z(f,p),{fetchedAt:s,modelCount:Object.keys(n).length,changed:o,path:p}}var O=fe(he(import.meta.url)),_e=E(O,"server.js"),u=E(a,"daemon.json"),w=E(a,"daemon.log"),P=E(a,"update-check.json"),m="@vladar107/claudescope",we=1440*60*1e3;function S(){if(!D(u))return null;try{return JSON.parse(A(u,"utf8"))}catch{return null}}function g(e){try{return process.kill(e,0),!0}catch{return!1}}async function N(e){try{return(await fetch(`http://127.0.0.1:${e}/api/health`,{signal:AbortSignal.timeout(1500)})).ok}catch{return!1}}async function Ee(e,t){let n=Date.now()+t;for(;Date.now()<n;){if(await N(e))return!0;process.stdout.write("."),await new Promise(r=>setTimeout(r,500))}return!1}function L(e){let t=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";try{G(t,[e],{stdio:"ignore",detached:!0,shell:process.platform==="win32"}).unref()}catch{}}async function H(e,t){B(a,{recursive:!0});let n=S();if(n&&g(n.pid)&&await N(n.port)){console.log(`\u2713 claudescope is already running \u2192 ${n.url}`),t&&L(n.url);return}n&&!g(n.pid)&&C(u,{force:!0});let r=`http://localhost:${e}`,o=ue(w,"a"),s=G(process.execPath,[_e],{detached:!0,stdio:["ignore",o,o],env:{...process.env,PORT:String(e),OPEN_BROWSER:"0"}});if(s.unref(),J(u,JSON.stringify({pid:s.pid,port:e,url:r,version:c,startedAt:new Date().toISOString()},null,2)),process.stdout.write("\u203A Starting claudescope"),!await Ee(e,2e4)){console.error(`
|
|
6
6
|
\u2717 Server did not become healthy in time. Inspect: claudescope logs`),process.exitCode=1;return}console.log(`
|
|
7
|
-
\u2713 claudescope running \u2192 ${r}`),console.log(` Sessions: ${b} (read-only)`),t&&L(r),await K(!1)}function k(){let e=S();if(!e||!g(e.pid)){console.log("claudescope is not running."),C(u,{force:!0});return}try{process.kill(e.pid,"SIGTERM")}catch{}C(u,{force:!0}),console.log(`\u2713 Stopped claudescope (pid ${e.pid}).`)}async function Se(){let e=S();e&&g(e.pid)&&await
|
|
7
|
+
\u2713 claudescope running \u2192 ${r}`),console.log(` Sessions: ${b} (read-only)`),t&&L(r),await K(!1)}function k(){let e=S();if(!e||!g(e.pid)){console.log("claudescope is not running."),C(u,{force:!0});return}try{process.kill(e.pid,"SIGTERM")}catch{}C(u,{force:!0}),console.log(`\u2713 Stopped claudescope (pid ${e.pid}).`)}async function Se(){let e=S();e&&g(e.pid)&&await N(e.port)?console.log(`\u25CF running ${e.url} (pid ${e.pid}, v${e.version})`):console.log(`\u25CB stopped (installed v${c})`),await K(!0)}function Re(){let e=S();e&&g(e.pid)?L(e.url):console.log("claudescope is not running. Start it with: claudescope start")}function ve(e){if(!D(w)){console.log("No logs yet.");return}e&&process.platform!=="win32"?I("tail",["-f",w],{stdio:"inherit"}):process.stdout.write(A(w,"utf8"))}async function be(e,t){if(!process.stdin.isTTY)return t;let n=me({input:process.stdin,output:process.stdout});try{let r=(await n.question(`${e} ${t?"[Y/n]":"[y/N]"} `)).trim().toLowerCase();return r?r==="y"||r==="yes":t}finally{n.close()}}function ye(){let e=O;try{e=de(O)}catch{}return e.includes("/nix/store/")?"nix":/[\\/]Cellar[\\/]claudescope[\\/]/.test(e)?"brew":"npm"}async function Pe(e){let t=await W(!0);if(t&&!V(t,c)){console.log(`\u2713 Already on the latest version (v${c}).`);return}let n=ye();if(n==="brew"){console.log("claudescope was installed via Homebrew."),console.log(" Run: brew upgrade vladar107/tap/claudescope");return}if(n==="nix"){console.log("claudescope was installed via Nix."),console.log(" Run: nix profile upgrade claudescope"),console.log(" (flake users: re-run `nix run --refresh github:vladar107/claudescope`)");return}t||console.log("\u26A0 Could not reach the npm registry to confirm the latest version.");let r=t?`v${c} \u2192 v${t}`:`v${c} \u2192 latest`;if(console.log(`\u203A Will run: npm install -g ${m}@latest (${r})`),!e&&!await be("Proceed?",!0)){console.log("Aborted.");return}console.log(`\u203A Updating ${m}\u2026`);let o=process.platform==="win32"?"npm.cmd":"npm";if(I(o,["install","-g",`${m}@latest`],{stdio:"inherit"}).status!==0){console.error(`\u2717 Update failed. If you run via npx, just re-run \`npx ${m}\` to get the latest.`),process.exitCode=1;return}k(),console.log("\u2713 Updated. Restarting\u2026"),I("claudescope",["start"],{stdio:"inherit",shell:process.platform==="win32"})}function V(e,t){let n=e.split(".").map(o=>Number.parseInt(o,10)||0),r=t.split(".").map(o=>Number.parseInt(o,10)||0);for(let o=0;o<3;o++){if((n[o]??0)>(r[o]??0))return!0;if((n[o]??0)<(r[o]??0))return!1}return!1}async function W(e){let t=Date.now();if(!e&&D(P))try{let s=JSON.parse(A(P,"utf8"));if(t-s.lastCheck<we)return s.latest}catch{}let n=`https://registry.npmjs.org/${m.replaceAll("/","%2f")}/latest`,r=await fetch(n,{signal:AbortSignal.timeout(2500)});if(!r.ok)return null;let o=await r.json();return o.version?(B(a,{recursive:!0}),J(P,JSON.stringify({lastCheck:t,latest:o.version})),o.version):null}async function K(e){try{let t=await W(e);t&&V(t,c)&&console.log(`
|
|
8
8
|
\u2B06 Update available: v${c} \u2192 v${t}. Run: claudescope update`)}catch{}}async function Ie(){try{let{modelCount:e,changed:t,path:n}=await F();console.log(`\u2713 Pricing updated: ${e} models (${t} changed) \u2192 ${n}`),console.log(" A running server picks up the new rates automatically (newly indexed events).")}catch(e){console.error(`\u2717 Pricing update failed: ${e instanceof Error?e.message:String(e)}`),console.error(" Existing rates are unchanged."),process.exitCode=1}}function Ce(){console.log(`Usage: claudescope pricing <subcommand>
|
|
9
9
|
|
|
10
10
|
Subcommands:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vladar107/claudescope",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "Local, read-only web app to browse, read, search, and analyze your AI coding-agent transcripts — Claude Code, OpenAI Codex, and JetBrains Junie.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|