@clauderecallhq/cli 0.61.6 → 0.63.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /* Claude Recall (proprietary). See LICENSE for terms. */
3
- var Su=Object.defineProperty;var N=(e,t)=>()=>(e&&(t=e(e=0)),t);var Ee=(e,t)=>{for(var s in t)Su(e,s,{get:t[s],enumerable:!0})};import{homedir as co}from"node:os";import{join as Ot,basename as yu}from"node:path";import{existsSync as lo,mkdirSync as Tu,chmodSync as wu,readdirSync as ao,statSync as Ru}from"node:fs";function P(){lo(R)||Tu(R,{recursive:!0,mode:448}),process.platform!=="win32"&&wu(R,448)}function on(e){return e.replace(/^-/,"/").replace(/-/g,"/")}function uo(e){let t=on(e);return yu(t)||t}function po(){if(!lo(rn))return[];let e=[],t=ao(rn,{withFileTypes:!0}).filter(s=>s.isDirectory()).map(s=>s.name);for(let s of t){let n=Ot(rn,s),r=ao(n,{withFileTypes:!0});for(let o of r){if(!o.isFile()||!o.name.endsWith(".jsonl"))continue;let i=Ot(n,o.name),a=Ru(i);e.push({sessionFile:i,encodedProject:s,mtime:a.mtimeMs,size:a.size})}}return e}var rn,R,te,j=N(()=>{"use strict";rn=Ot(co(),".claude","projects"),R=process.env.RECALL_HOME?process.env.RECALL_HOME:Ot(co(),".recall"),te=Ot(R,"db.sqlite")});function go(e){let t=e.prepare("PRAGMA table_info(sessions)").all(),s=new Set(t.map(f=>f.name)),n=[["total_input_tokens","INTEGER"],["total_output_tokens","INTEGER"],["total_cache_create_tokens","INTEGER"],["total_cache_read_tokens","INTEGER"],["primary_model","TEXT"],["auto_title","TEXT"],["auto_title_source","TEXT"],["auto_title_generated_at","INTEGER"],["auto_title_history","TEXT"],["verification_status","TEXT"],["verification_computed_at","INTEGER"],["title_quality","TEXT"],["title_quality_computed_at","INTEGER"]];for(let[f,g]of n)s.has(f)||e.exec(`ALTER TABLE sessions ADD COLUMN ${f} ${g}`);let r=e.prepare("PRAGMA table_info(collection_sessions)").all(),o=new Set(r.map(f=>f.name)),i=[["source","TEXT NOT NULL DEFAULT 'manual'"],["rule_id","TEXT"]];for(let[f,g]of i)o.has(f)||e.exec(`ALTER TABLE collection_sessions ADD COLUMN ${f} ${g}`);let a=e.prepare("PRAGMA table_info(session_notes)").all(),l=new Set(a.map(f=>f.name)),c=[["auto_synopsis","TEXT"],["auto_synopsis_generated_at","INTEGER"],["auto_synopsis_history","TEXT"]];for(let[f,g]of c)l.has(f)||e.exec(`ALTER TABLE session_notes ADD COLUMN ${f} ${g}`);let u=e.prepare("PRAGMA table_info(threads)").all();new Set(u.map(f=>f.name)).has("folder_id")||(e.exec("ALTER TABLE threads ADD COLUMN folder_id TEXT REFERENCES thread_folders(id) ON DELETE SET NULL"),e.exec("CREATE INDEX IF NOT EXISTS idx_threads_folder ON threads(folder_id)"));let p=e.prepare("PRAGMA table_info(thread_folders)").all(),m=new Set(p.map(f=>f.name));m.has("project_scope")||(e.exec("ALTER TABLE thread_folders ADD COLUMN project_scope TEXT"),e.exec("CREATE INDEX IF NOT EXISTS idx_thread_folders_project ON thread_folders(project_scope)")),m.has("sort_order")||e.exec("ALTER TABLE thread_folders ADD COLUMN sort_order INTEGER NOT NULL DEFAULT 0"),e.exec(`
3
+ var Ju=Object.defineProperty;var C=(e,t)=>()=>(e&&(t=e(e=0)),t);var Se=(e,t)=>{for(var s in t)Ju(e,s,{get:t[s],enumerable:!0})};import{homedir as To}from"node:os";import{join as Mt,basename as Gu}from"node:path";import{existsSync as wo,mkdirSync as zu,chmodSync as Yu,readdirSync as yo,statSync as Ku}from"node:fs";function P(){wo(R)||zu(R,{recursive:!0,mode:448}),process.platform!=="win32"&&Yu(R,448)}function _n(e){return e.replace(/^-/,"/").replace(/-/g,"/")}function Ro(e){let t=_n(e);return Gu(t)||t}function xo(){if(!wo(fn))return[];let e=[],t=yo(fn,{withFileTypes:!0}).filter(s=>s.isDirectory()).map(s=>s.name);for(let s of t){let n=Mt(fn,s),r=yo(n,{withFileTypes:!0});for(let o of r){if(!o.isFile()||!o.name.endsWith(".jsonl"))continue;let i=Mt(n,o.name),a=Ku(i);e.push({sessionFile:i,encodedProject:s,mtime:a.mtimeMs,size:a.size})}}return e}var fn,R,te,j=C(()=>{"use strict";fn=Mt(To(),".claude","projects"),R=process.env.RECALL_HOME?process.env.RECALL_HOME:Mt(To(),".recall"),te=Mt(R,"db.sqlite")});function No(e){let t=e.prepare("PRAGMA table_info(sessions)").all(),s=new Set(t.map(f=>f.name)),n=[["total_input_tokens","INTEGER"],["total_output_tokens","INTEGER"],["total_cache_create_tokens","INTEGER"],["total_cache_read_tokens","INTEGER"],["primary_model","TEXT"],["auto_title","TEXT"],["auto_title_source","TEXT"],["auto_title_generated_at","INTEGER"],["auto_title_history","TEXT"],["verification_status","TEXT"],["verification_computed_at","INTEGER"],["title_quality","TEXT"],["title_quality_computed_at","INTEGER"]];for(let[f,g]of n)s.has(f)||e.exec(`ALTER TABLE sessions ADD COLUMN ${f} ${g}`);let r=e.prepare("PRAGMA table_info(collection_sessions)").all(),o=new Set(r.map(f=>f.name)),i=[["source","TEXT NOT NULL DEFAULT 'manual'"],["rule_id","TEXT"]];for(let[f,g]of i)o.has(f)||e.exec(`ALTER TABLE collection_sessions ADD COLUMN ${f} ${g}`);let a=e.prepare("PRAGMA table_info(session_notes)").all(),l=new Set(a.map(f=>f.name)),c=[["auto_synopsis","TEXT"],["auto_synopsis_generated_at","INTEGER"],["auto_synopsis_history","TEXT"]];for(let[f,g]of c)l.has(f)||e.exec(`ALTER TABLE session_notes ADD COLUMN ${f} ${g}`);let u=e.prepare("PRAGMA table_info(threads)").all();new Set(u.map(f=>f.name)).has("folder_id")||(e.exec("ALTER TABLE threads ADD COLUMN folder_id TEXT REFERENCES thread_folders(id) ON DELETE SET NULL"),e.exec("CREATE INDEX IF NOT EXISTS idx_threads_folder ON threads(folder_id)"));let m=e.prepare("PRAGMA table_info(thread_folders)").all(),p=new Set(m.map(f=>f.name));p.has("project_scope")||(e.exec("ALTER TABLE thread_folders ADD COLUMN project_scope TEXT"),e.exec("CREATE INDEX IF NOT EXISTS idx_thread_folders_project ON thread_folders(project_scope)")),p.has("sort_order")||e.exec("ALTER TABLE thread_folders ADD COLUMN sort_order INTEGER NOT NULL DEFAULT 0"),e.exec(`
4
4
  CREATE TABLE IF NOT EXISTS message_embeddings (
5
5
  message_uuid TEXT PRIMARY KEY REFERENCES messages(uuid) ON DELETE CASCADE,
6
6
  session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
@@ -12,7 +12,7 @@ var Su=Object.defineProperty;var N=(e,t)=>()=>(e&&(t=e(e=0)),t);var Ee=(e,t)=>{f
12
12
  );
13
13
  CREATE INDEX IF NOT EXISTS idx_message_embeddings_session ON message_embeddings(session_id);
14
14
  CREATE INDEX IF NOT EXISTS idx_message_embeddings_generated ON message_embeddings(generated_at DESC);
15
- `)}var mo,fo=N(()=>{"use strict";mo=`
15
+ `)}var ko,Co=C(()=>{"use strict";ko=`
16
16
  PRAGMA journal_mode = WAL;
17
17
  PRAGMA synchronous = NORMAL;
18
18
  PRAGMA foreign_keys = ON;
@@ -618,33 +618,33 @@ CREATE INDEX IF NOT EXISTS idx_synth_results_target
618
618
  ON bug_synthesis_results(scope, target_id, created_at DESC);
619
619
  CREATE INDEX IF NOT EXISTS idx_synth_results_created
620
620
  ON bug_synthesis_results(created_at DESC);
621
- `});import xu from"better-sqlite3";import*as _o from"sqlite-vec";function _(){if(ae)return ae;P(),ae=new xu(te),_o.load(ae),ae.pragma("cache_size = -64000"),ae.pragma("mmap_size = 268435456"),ae.pragma("temp_store = MEMORY"),ae.pragma("busy_timeout = 5000"),ae.pragma("journal_size_limit = 67108864"),ae.pragma("wal_autocheckpoint = 1000"),ae.exec(mo),go(ae);try{ae.exec("PRAGMA optimize")}catch{}return ae}var ae,T=N(()=>{"use strict";j();fo();ae=null});import ke from"chalk";import{formatDistanceToNowStrict as Iu,parseISO as vu}from"date-fns";function Y(e,t){if(!e)return"";let s=e.replace(/\s+/g," ").trim();return s.length<=t?s:s.slice(0,t-1)+"\u2026"}function W(e){if(!e)return"";try{return Iu(vu(e),{addSuffix:!0})}catch{return""}}function H(e){return e.slice(0,8)}function bo(e,t){if(!t)return e;let s=t.split(/\s+/).filter(r=>r.length>1).map(r=>r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));if(s.length===0)return e;let n=new RegExp(`(${s.join("|")})`,"gi");return e.replace(n,r=>ke.bgYellow.black(r))}var d,M=N(()=>{"use strict";d={dim:ke.gray,bold:ke.bold,project:ke.cyan,user:ke.blue,assistant:ke.green,tool:ke.magenta,warn:ke.yellow,err:ke.red,ok:ke.green,accent:ke.hex("#f97316")}});import{existsSync as Fo,readFileSync as Op,writeFileSync as Ap,unlinkSync as Ip}from"node:fs";import{join as vp}from"node:path";function vt(){if(!Fo(ut))return null;try{let e=Op(ut,"utf8"),t=JSON.parse(e);return typeof t.license_jwt!="string"||t.license_jwt.length===0?null:t}catch{return null}}function Uo(e){P(),Ap(ut,JSON.stringify(e,null,2)+`
622
- `,{mode:384})}function Bo(){Fo(ut)&&Ip(ut)}var ut,Mt=N(()=>{"use strict";j();ut=vp(R,"license.json")});var Ho,hn,Wo,Xo,Jo=N(()=>{"use strict";Ho=`-----BEGIN PUBLIC KEY-----
621
+ `});import qu from"better-sqlite3";import*as Lo from"sqlite-vec";function _(){if(ae)return ae;P(),ae=new qu(te),Lo.load(ae),ae.pragma("cache_size = -64000"),ae.pragma("mmap_size = 268435456"),ae.pragma("temp_store = MEMORY"),ae.pragma("busy_timeout = 5000"),ae.pragma("journal_size_limit = 67108864"),ae.pragma("wal_autocheckpoint = 1000"),ae.exec(ko),No(ae);try{ae.exec("PRAGMA optimize")}catch{}return ae}var ae,T=C(()=>{"use strict";j();Co();ae=null});import Ne from"chalk";import{formatDistanceToNowStrict as nm,parseISO as rm}from"date-fns";function Y(e,t){if(!e)return"";let s=e.replace(/\s+/g," ").trim();return s.length<=t?s:s.slice(0,t-1)+"\u2026"}function W(e){if(!e)return"";try{return nm(rm(e),{addSuffix:!0})}catch{return""}}function H(e){return e.slice(0,8)}function Io(e,t){if(!t)return e;let s=t.split(/\s+/).filter(r=>r.length>1).map(r=>r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));if(s.length===0)return e;let n=new RegExp(`(${s.join("|")})`,"gi");return e.replace(n,r=>Ne.bgYellow.black(r))}var d,I=C(()=>{"use strict";d={dim:Ne.gray,bold:Ne.bold,project:Ne.cyan,user:Ne.blue,assistant:Ne.green,tool:Ne.magenta,warn:Ne.yellow,err:Ne.red,ok:Ne.green,accent:Ne.hex("#f97316")}});import{existsSync as Zo,readFileSync as tp,writeFileSync as sp,unlinkSync as np}from"node:fs";import{join as rp}from"node:path";function jt(){if(!Zo(mt))return null;try{let e=tp(mt,"utf8"),t=JSON.parse(e);return typeof t.license_jwt!="string"||t.license_jwt.length===0?null:t}catch{return null}}function Qo(e){P(),sp(mt,JSON.stringify(e,null,2)+`
622
+ `,{mode:384})}function ei(){Zo(mt)&&np(mt)}var mt,Pt=C(()=>{"use strict";j();mt=rp(R,"license.json")});var ti,Nn,si,ni,ri=C(()=>{"use strict";ti=`-----BEGIN PUBLIC KEY-----
623
623
  MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZysO2FffTLdyxQnTmnt78/ayvqz9
624
624
  kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
625
625
  -----END PUBLIC KEY-----
626
- `,hn="ES256",Wo="clauderecall.com",Xo="clauderecall-cli"});import{jwtVerify as Mp,importSPKI as Dp}from"jose";async function $p(){return rs||(rs=await Dp(Ho,hn),rs)}async function os(e){try{let t=await $p(),{payload:s}=await Mp(e,t,{issuer:Wo,audience:Xo,algorithms:[hn]});return{valid:!0,claims:s}}catch(t){return{valid:!1,reason:t instanceof Error?t.message:"verification failed"}}}var rs,En=N(()=>{"use strict";Jo();rs=null});import{createHash as jp}from"node:crypto";import{hostname as Pp,userInfo as Fp,platform as Up,arch as Bp}from"node:os";function is(){let e="unknown";try{e=Fp().username}catch{}let t=[Pp(),e,Up(),Bp()];return jp("sha256").update(t.join("\0")).digest("hex")}var bn=N(()=>{"use strict"});function as(){let e=process.env.RECALL_API_BASE;if(e&&e.length>0){let t=e.replace(/\/$/,""),s;try{s=new URL(t)}catch{throw new Error(`RECALL_API_BASE is not a valid URL: ${t}`)}let n=s.hostname==="127.0.0.1"||s.hostname==="localhost"||s.hostname==="::1";if(s.protocol==="https:"||s.protocol==="http:"&&n)return t;throw new Error(`RECALL_API_BASE must be HTTPS, or HTTP with loopback hostname. Got: ${t}`)}return"https://clauderecall.com"}var Sn=N(()=>{"use strict"});import{existsSync as Hp,readFileSync as Wp,writeFileSync as Xp}from"node:fs";import{join as Jp}from"node:path";function cs(){if(!Hp(yn))return null;try{let e=JSON.parse(Wp(yn,"utf8"));return typeof e.license_key!="string"||typeof e.last_checked_at!="string"||typeof e.revoked!="boolean"?null:e}catch{return null}}function Kp(e){P(),Xp(yn,JSON.stringify(e,null,2)+`
627
- `,{mode:384})}async function qp(e,t){let s=null,n=null;try{s=new AbortController,n=setTimeout(()=>s?.abort(),Yp);let r=await fetch(t,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({license_key:e}),signal:s.signal});if(!r.ok)return null;let o=await r.json();return typeof o?.revoked!="boolean"?null:o}catch{return null}finally{n&&clearTimeout(n)}}async function Go(e,t={}){let s=cs(),n=t.apiUrl??`${as()}/api/license/check`,r=s?.license_key===e,o=!s||!r||Date.now()-new Date(s.last_checked_at).getTime()>=Gp;if(!t.force&&!o)return s;let i=await qp(e,n);if(!i)return r?s:null;let a={license_key:e,last_checked_at:new Date().toISOString(),revoked:i.revoked,reason:i.reason??null};return Kp(a),a}function zo(e){let t=cs();return!t||t.license_key!==e?null:t.revoked?{revoked:!0,reason:t.reason?`license revoked: ${t.reason}`:"license revoked by issuer"}:Date.now()-new Date(t.last_checked_at).getTime()>zp?{revoked:!0,reason:"license has not been validated with the server in 30+ days. Reconnect to the internet and run `recall license check`"}:null}var yn,Gp,zp,Yp,Tn=N(()=>{"use strict";j();Sn();yn=Jp(R,"license-check.json"),Gp=1440*60*1e3,zp=720*60*60*1e3,Yp=1e4});function Zp(e=Date.now()){return e<wn}function Ko(e=Date.now()){return Zp(e)?`(one-time purchase, $${Vp} through May 2026 Founder pricing, $${Yo} from June, lifetime updates either way)`:`(one-time purchase, $${Yo}, lifetime updates)`}var wn,Vp,Yo,Rn=N(()=>{"use strict";wn=Date.UTC(2026,5,1,7,0,0),Vp="29.69",Yo="49.69"});function Cn(e){let t=e.now??Date.now(),s=e.status.expires_at??null,n=s?new Date(s).getTime():null,r=n!==null&&n-t<Qp;if(e.status.tier==="pro"&&r&&n!==null){let o=Math.max(0,Math.floor((n-t)/36e5));if(o<=24)return{kind:"trial-near-expiry",message:`Your Pro trial ends in ${o} hours. Lock in Founder pricing ($29.69 lifetime, ends May 31): ${xn}`}}if(e.status.tier==="free"&&r&&n!==null&&n<t&&Math.floor((t-n)/36e5)<720)return{kind:"trial-expired",message:`Your Pro trial ended. Your data is intact; only Pro features are gated. Founder pricing ($29.69 lifetime, ends May 31): ${xn}`};if(e.status.tier==="free"){let o=wn-t;if(o>0&&o<=3*kn){let i=Math.max(1,Math.ceil(o/kn));return{kind:"founder-near-deadline",message:`Founder pricing ($29.69 lifetime) ends in ${i} day${i===1?"":"s"}. After May 31, lifetime is $49.69: ${xn}`}}}return null}var xn,kn,Qp,qo=N(()=>{"use strict";Rn();xn="https://clauderecall.com/pricing",kn=1440*60*1e3,Qp=60*kn});var Ln={};Ee(Ln,{getLicenseStatus:()=>be,isPro:()=>tm,performRevocationCheck:()=>Nn,printTrialBannerIfAny:()=>sm,requireProOrExit:()=>Ce});async function be(){let e=vt();if(!e)return{tier:"free"};let t=await os(e.license_jwt);if(!t.valid||!t.claims)return{tier:"free",invalid_reason:t.reason};if(t.claims.machine_fp&&t.claims.machine_fp!==is())return{tier:"free",invalid_reason:"machine fingerprint mismatch \u2014 re-activate on this device"};let s=zo(e.license_key);return s?.revoked?{tier:"free",invalid_reason:s.reason}:em(e,t.claims)}async function Nn(e){let t=vt();if(!t)return{ran:!1,revoked:!1,reason:null,last_checked_at:null};let s=await Go(t.license_key,{force:e?.force??!1});return s?{ran:!0,revoked:s.revoked,reason:s.reason,last_checked_at:s.last_checked_at}:{ran:!0,revoked:!1,reason:null,last_checked_at:null}}function em(e,t){let s=t.test_mode===!0&&process.env.NODE_ENV==="production";return{tier:s?"free":"pro",key_short:e.key_short,customer_email:e.customer_email,activated_at:e.activated_at,test_mode:e.test_mode,...s?{test_mode_blocked:!0}:{},expires_at:typeof t.exp=="number"?new Date(t.exp*1e3).toISOString():null}}async function tm(){return(await be()).tier==="pro"}async function Ce(e){let t=await be();if(t.tier==="pro")return;let s=Cn({status:t});s&&process.stderr.write(`
626
+ `,Nn="ES256",si="clauderecall.com",ni="clauderecall-cli"});import{jwtVerify as op,importSPKI as ip}from"jose";async function ap(){return cs||(cs=await ip(ti,Nn),cs)}async function ls(e){try{let t=await ap(),{payload:s}=await op(e,t,{issuer:si,audience:ni,algorithms:[Nn]});return{valid:!0,claims:s}}catch(t){return{valid:!1,reason:t instanceof Error?t.message:"verification failed"}}}var cs,Cn=C(()=>{"use strict";ri();cs=null});import{createHash as cp}from"node:crypto";import{hostname as lp,userInfo as dp,platform as up,arch as mp}from"node:os";function ds(){let e="unknown";try{e=dp().username}catch{}let t=[lp(),e,up(),mp()];return cp("sha256").update(t.join("\0")).digest("hex")}var Ln=C(()=>{"use strict"});function Rt(){let e=process.env.RECALL_API_BASE;if(e&&e.length>0){let t=e.replace(/\/$/,""),s;try{s=new URL(t)}catch{throw new Error(`RECALL_API_BASE is not a valid URL: ${t}`)}let n=s.hostname==="127.0.0.1"||s.hostname==="localhost"||s.hostname==="::1";if(s.protocol==="https:"||s.protocol==="http:"&&n)return t;throw new Error(`RECALL_API_BASE must be HTTPS, or HTTP with loopback hostname. Got: ${t}`)}return"https://clauderecall.com"}var us=C(()=>{"use strict"});import{existsSync as pp,readFileSync as gp,writeFileSync as fp}from"node:fs";import{join as _p}from"node:path";function ms(){if(!pp(On))return null;try{let e=JSON.parse(gp(On,"utf8"));return typeof e.license_key!="string"||typeof e.last_checked_at!="string"||typeof e.revoked!="boolean"?null:e}catch{return null}}function Sp(e){P(),fp(On,JSON.stringify(e,null,2)+`
627
+ `,{mode:384})}async function yp(e,t){let s=null,n=null;try{s=new AbortController,n=setTimeout(()=>s?.abort(),bp);let r=await fetch(t,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({license_key:e}),signal:s.signal});if(!r.ok)return null;let o=await r.json();return typeof o?.revoked!="boolean"?null:o}catch{return null}finally{n&&clearTimeout(n)}}async function oi(e,t={}){let s=ms(),n=t.apiUrl??`${Rt()}/api/license/check`,r=s?.license_key===e,o=!s||!r||Date.now()-new Date(s.last_checked_at).getTime()>=hp;if(!t.force&&!o)return s;let i=await yp(e,n);if(!i)return r?s:null;let a={license_key:e,last_checked_at:new Date().toISOString(),revoked:i.revoked,reason:i.reason??null};return Sp(a),a}function ii(e){let t=ms();return!t||t.license_key!==e?null:t.revoked?{revoked:!0,reason:t.reason?`license revoked: ${t.reason}`:"license revoked by issuer"}:Date.now()-new Date(t.last_checked_at).getTime()>Ep?{revoked:!0,reason:"license has not been validated with the server in 30+ days. Reconnect to the internet and run `recall license check`"}:null}var On,hp,Ep,bp,An=C(()=>{"use strict";j();us();On=_p(R,"license-check.json"),hp=1440*60*1e3,Ep=720*60*60*1e3,bp=1e4});function wp(e=Date.now()){return e<In}function ci(e=Date.now()){return wp(e)?`(one-time purchase, $${Tp} through May 2026 Founder pricing, $${ai} from June, lifetime updates either way)`:`(one-time purchase, $${ai}, lifetime updates)`}var In,Tp,ai,vn=C(()=>{"use strict";In=Date.UTC(2026,5,1,7,0,0),Tp="29.69",ai="49.69"});function $n(e){let t=e.now??Date.now(),s=e.status.expires_at??null,n=s?new Date(s).getTime():null,r=n!==null&&n-t<Rp;if(e.status.tier==="pro"&&r&&n!==null){let o=Math.max(0,Math.floor((n-t)/36e5));if(o<=24)return{kind:"trial-near-expiry",message:`Your Pro trial ends in ${o} hours. Lock in Founder pricing ($29.69 lifetime, ends May 31): ${Mn}`}}if(e.status.tier==="free"&&r&&n!==null&&n<t&&Math.floor((t-n)/36e5)<720)return{kind:"trial-expired",message:`Your Pro trial ended. Your data is intact; only Pro features are gated. Founder pricing ($29.69 lifetime, ends May 31): ${Mn}`};if(e.status.tier==="free"){let o=In-t;if(o>0&&o<=3*Dn){let i=Math.max(1,Math.ceil(o/Dn));return{kind:"founder-near-deadline",message:`Founder pricing ($29.69 lifetime) ends in ${i} day${i===1?"":"s"}. After May 31, lifetime is $49.69: ${Mn}`}}}return null}var Mn,Dn,Rp,li=C(()=>{"use strict";vn();Mn="https://clauderecall.com/pricing",Dn=1440*60*1e3,Rp=60*Dn});var ps={};Se(ps,{getLicenseStatus:()=>ye,isPro:()=>kp,performRevocationCheck:()=>jn,printTrialBannerIfAny:()=>Np,requireProOrExit:()=>Ce});async function ye(){let e=jt();if(!e)return{tier:"free"};let t=await ls(e.license_jwt);if(!t.valid||!t.claims)return{tier:"free",invalid_reason:t.reason};if(t.claims.machine_fp&&t.claims.machine_fp!==ds())return{tier:"free",invalid_reason:"machine fingerprint mismatch \u2014 re-activate on this device"};let s=ii(e.license_key);return s?.revoked?{tier:"free",invalid_reason:s.reason}:xp(e,t.claims)}async function jn(e){let t=jt();if(!t)return{ran:!1,revoked:!1,reason:null,last_checked_at:null};let s=await oi(t.license_key,{force:e?.force??!1});return s?{ran:!0,revoked:s.revoked,reason:s.reason,last_checked_at:s.last_checked_at}:{ran:!0,revoked:!1,reason:null,last_checked_at:null}}function xp(e,t){let s=t.test_mode===!0&&process.env.NODE_ENV==="production";return{tier:s?"free":"pro",key_short:e.key_short,customer_email:e.customer_email,activated_at:e.activated_at,test_mode:e.test_mode,...s?{test_mode_blocked:!0}:{},expires_at:typeof t.exp=="number"?new Date(t.exp*1e3).toISOString():null}}async function kp(){return(await ye()).tier==="pro"}async function Ce(e){let t=await ye();if(t.tier==="pro")return;let s=$n({status:t});s&&process.stderr.write(`
628
628
  ${s.message}
629
629
  `),process.stderr.write(`
630
630
  ${e} is a Pro feature.
631
631
 
632
632
  Buy a license at https://clauderecall.com/pricing
633
- ${Ko()}.
633
+ ${ci()}.
634
634
  Then run: recall activate <license-key>
635
635
 
636
636
  `),t.invalid_reason&&process.stderr.write(`(stored license is invalid: ${t.invalid_reason})
637
637
 
638
- `),process.exit(1)}async function sm(){let e=await be(),t=Cn({status:e});return t?(process.stderr.write(`
638
+ `),process.exit(1)}async function Np(){let e=await ye(),t=$n({status:e});return t?(process.stderr.write(`
639
639
  ${t.message}
640
640
 
641
- `),!0):!1}var Se=N(()=>{"use strict";Mt();En();bn();Tn();Rn();qo()});import{writeFileSync as m0,readFileSync as rm,existsSync as om}from"node:fs";import{join as im}from"node:path";function Zo(){if(!om(ls))return null;try{return rm(ls,"utf8").trim()}catch{return null}}var ls,On=N(()=>{"use strict";j();ls=im(R,"daemon.token")});import{existsSync as Qo,readFileSync as am,writeFileSync as E0,unlinkSync as cm}from"node:fs";import{join as In}from"node:path";function dm(){if(!Qo(An))return null;try{let e=JSON.parse(am(An,"utf8"));return typeof e.pid!="number"||typeof e.port!="number"?null:e}catch{return null}}function vn(){for(let e of[An,lm,ls])if(Qo(e))try{cm(e)}catch{}}function um(e){try{return process.kill(e,0),!0}catch{return!1}}function q(){let e=dm();return e?um(e.pid)?e:(vn(),null):null}var An,lm,ds,He=N(()=>{"use strict";j();On();An=In(R,"daemon.pid"),lm=In(R,"daemon.port"),ds=In(R,"daemon.log")});import{writeFileSync as qm}from"node:fs";import{join as Vm}from"node:path";function Pn(e){try{let t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return[]}function vi(e){return _().prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(e)?.alias??null}function Qm(){return _().prepare("SELECT session_id, alias, updated_at, previous_aliases FROM session_aliases").all().map(t=>({session_id:t.session_id,alias:t.alias,updated_at:t.updated_at,previous_aliases:Pn(t.previous_aliases)}))}function fs(e,t){let s=t.trim();if(!s)throw new Error("alias must be non-empty");let n=_(),r=new Date().toISOString(),o=n.prepare("SELECT alias, previous_aliases FROM session_aliases WHERE session_id = ?").get(e),i=[];return o&&(i=Pn(o.previous_aliases),o.alias!==s&&i.push({alias:o.alias,replaced_at:r})),n.prepare(`INSERT INTO session_aliases (session_id, alias, updated_at, previous_aliases)
641
+ `),!0):!1}var fe=C(()=>{"use strict";Pt();Cn();Ln();An();vn();li()});import{writeFileSync as V0,readFileSync as Lp,existsSync as Op}from"node:fs";import{join as Ap}from"node:path";function ui(){if(!Op(gs))return null;try{return Lp(gs,"utf8").trim()}catch{return null}}var gs,Pn=C(()=>{"use strict";j();gs=Ap(R,"daemon.token")});import{existsSync as mi,readFileSync as Ip,writeFileSync as sR,unlinkSync as vp}from"node:fs";import{join as Un}from"node:path";function Dp(){if(!mi(Fn))return null;try{let e=JSON.parse(Ip(Fn,"utf8"));return typeof e.pid!="number"||typeof e.port!="number"?null:e}catch{return null}}function Bn(){for(let e of[Fn,Mp,gs])if(mi(e))try{vp(e)}catch{}}function $p(e){try{return process.kill(e,0),!0}catch{return!1}}function q(){let e=Dp();return e?$p(e.pid)?e:(Bn(),null):null}var Fn,Mp,fs,We=C(()=>{"use strict";j();Pn();Fn=Un(R,"daemon.pid"),Mp=Un(R,"daemon.port"),fs=Un(R,"daemon.log")});import{writeFileSync as yg}from"node:fs";import{join as Tg}from"node:path";function Gn(e){try{let t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return[]}function Gi(e){return _().prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(e)?.alias??null}function Rg(){return _().prepare("SELECT session_id, alias, updated_at, previous_aliases FROM session_aliases").all().map(t=>({session_id:t.session_id,alias:t.alias,updated_at:t.updated_at,previous_aliases:Gn(t.previous_aliases)}))}function Ss(e,t){let s=t.trim();if(!s)throw new Error("alias must be non-empty");let n=_(),r=new Date().toISOString(),o=n.prepare("SELECT alias, previous_aliases FROM session_aliases WHERE session_id = ?").get(e),i=[];return o&&(i=Gn(o.previous_aliases),o.alias!==s&&i.push({alias:o.alias,replaced_at:r})),n.prepare(`INSERT INTO session_aliases (session_id, alias, updated_at, previous_aliases)
642
642
  VALUES (?, ?, ?, ?)
643
643
  ON CONFLICT(session_id) DO UPDATE SET
644
644
  alias = excluded.alias,
645
645
  updated_at = excluded.updated_at,
646
- previous_aliases = excluded.previous_aliases`).run(e,s,r,JSON.stringify(i)),Di(),{session_id:e,alias:s,updated_at:r,previous_aliases:i}}function Mi(e){let t=_(),s=new Date().toISOString(),n=t.prepare("SELECT alias, previous_aliases FROM session_aliases WHERE session_id = ?").get(e);if(!n)return;let r=Pn(n.previous_aliases);r.push({alias:n.alias,replaced_at:s}),t.prepare(`UPDATE session_aliases SET alias = '', updated_at = ?, previous_aliases = ?
647
- WHERE session_id = ?`).run(s,JSON.stringify(r),e),Di()}function Di(){try{P();let e=Qm(),t={schema:"claude-recall.aliases.v1",backed_up_at:new Date().toISOString(),aliases:e};qm(Zm,JSON.stringify(t,null,2))}catch(e){console.error("[aliases] backup failed:",e)}}var Zm,Dt=N(()=>{"use strict";T();j();Zm=Vm(R,"aliases.json")});import{writeFileSync as Rg}from"node:fs";import{join as xg}from"node:path";function Cg(e){return e.trim().toLowerCase().replace(/^#+/,"").replace(/[\s/\\]+/g,"-").replace(/[^a-z0-9\-._]/g,"").slice(0,40)}function Gi(e,t){let s=Cg(t);if(!s)throw new Error("tag must contain at least one alphanumeric character");let n=_(),r=new Date().toISOString();return n.prepare("SELECT 1 FROM session_tags WHERE session_id = ? AND tag = ?").get(e,s)?{tag:s,added:!1}:(n.transaction(()=>{n.prepare("INSERT INTO session_tags (session_id, tag, created_at) VALUES (?, ?, ?)").run(e,s,r),n.prepare("INSERT INTO tag_events (session_id, tag, action, at) VALUES (?, ?, 'add', ?)").run(e,s,r)})(),Ng(),{tag:s,added:!0})}function zi(e){return _().prepare("SELECT tag FROM session_tags WHERE session_id = ? ORDER BY tag").all(e).map(t=>t.tag)}function Ng(){try{P();let e=_(),t=e.prepare("SELECT session_id, tag, created_at FROM session_tags ORDER BY session_id, tag").all(),s=e.prepare("SELECT id, session_id, tag, action, at FROM tag_events ORDER BY at ASC, id ASC").all(),n={schema:"claude-recall.tags.v1",backed_up_at:new Date().toISOString(),current:t,events:s};Rg(kg,JSON.stringify(n,null,2))}catch(e){console.error("[tags] backup failed:",e)}}var kg,Un=N(()=>{"use strict";T();j();kg=xg(R,"tags.json")});function Lg(e,t){let s=e.filter(o=>o.content_text&&o.content_text.trim().length>0);if(s.length<=t)return s;let n=new Set;n.add(0),n.add(s.length-1);let r=(s.length-2)/Math.max(1,t-2);for(let o=1;o<t-1;o++)n.add(Math.floor(o*r));return Array.from(n).sort((o,i)=>o-i).slice(0,t).map(o=>s[o])}function Yi(e){let t=_(),s={limit:e.limit??500},n=e.sessionIds&&e.sessionIds.length>0,r=n?"1=1":"s.message_count > 2";if(n){let i=e.sessionIds.map((a,l)=>`@sid_${l}`).join(", ");r+=` AND s.id IN (${i})`,e.sessionIds.forEach((a,l)=>{s[`sid_${l}`]=a})}return e.untaggedOnly&&(r+=" AND NOT EXISTS (SELECT 1 FROM session_tags st WHERE st.session_id = s.id)"),e.project&&(r+=" AND p.name = @project",s.project=e.project),e.collectionId&&(r+=" AND s.id IN (SELECT session_id FROM collection_sessions WHERE collection_id = @col)",s.col=e.collectionId),t.prepare(`SELECT s.id, p.name AS project, s.git_branch,
646
+ previous_aliases = excluded.previous_aliases`).run(e,s,r,JSON.stringify(i)),Yi(),{session_id:e,alias:s,updated_at:r,previous_aliases:i}}function zi(e){let t=_(),s=new Date().toISOString(),n=t.prepare("SELECT alias, previous_aliases FROM session_aliases WHERE session_id = ?").get(e);if(!n)return;let r=Gn(n.previous_aliases);r.push({alias:n.alias,replaced_at:s}),t.prepare(`UPDATE session_aliases SET alias = '', updated_at = ?, previous_aliases = ?
647
+ WHERE session_id = ?`).run(s,JSON.stringify(r),e),Yi()}function Yi(){try{P();let e=Rg(),t={schema:"claude-recall.aliases.v1",backed_up_at:new Date().toISOString(),aliases:e};yg(wg,JSON.stringify(t,null,2))}catch(e){console.error("[aliases] backup failed:",e)}}var wg,Ft=C(()=>{"use strict";T();j();wg=Tg(R,"aliases.json")});import{writeFileSync as Kg}from"node:fs";import{join as qg}from"node:path";function Zg(e){return e.trim().toLowerCase().replace(/^#+/,"").replace(/[\s/\\]+/g,"-").replace(/[^a-z0-9\-._]/g,"").slice(0,40)}function oa(e,t){let s=Zg(t);if(!s)throw new Error("tag must contain at least one alphanumeric character");let n=_(),r=new Date().toISOString();return n.prepare("SELECT 1 FROM session_tags WHERE session_id = ? AND tag = ?").get(e,s)?{tag:s,added:!1}:(n.transaction(()=>{n.prepare("INSERT INTO session_tags (session_id, tag, created_at) VALUES (?, ?, ?)").run(e,s,r),n.prepare("INSERT INTO tag_events (session_id, tag, action, at) VALUES (?, ?, 'add', ?)").run(e,s,r)})(),Qg(),{tag:s,added:!0})}function ia(e){return _().prepare("SELECT tag FROM session_tags WHERE session_id = ? ORDER BY tag").all(e).map(t=>t.tag)}function Qg(){try{P();let e=_(),t=e.prepare("SELECT session_id, tag, created_at FROM session_tags ORDER BY session_id, tag").all(),s=e.prepare("SELECT id, session_id, tag, action, at FROM tag_events ORDER BY at ASC, id ASC").all(),n={schema:"claude-recall.tags.v1",backed_up_at:new Date().toISOString(),current:t,events:s};Kg(Vg,JSON.stringify(n,null,2))}catch(e){console.error("[tags] backup failed:",e)}}var Vg,Yn=C(()=>{"use strict";T();j();Vg=qg(R,"tags.json")});function ef(e,t){let s=e.filter(o=>o.content_text&&o.content_text.trim().length>0);if(s.length<=t)return s;let n=new Set;n.add(0),n.add(s.length-1);let r=(s.length-2)/Math.max(1,t-2);for(let o=1;o<t-1;o++)n.add(Math.floor(o*r));return Array.from(n).sort((o,i)=>o-i).slice(0,t).map(o=>s[o])}function aa(e){let t=_(),s={limit:e.limit??500},n=e.sessionIds&&e.sessionIds.length>0,r=n?"1=1":"s.message_count > 2";if(n){let i=e.sessionIds.map((a,l)=>`@sid_${l}`).join(", ");r+=` AND s.id IN (${i})`,e.sessionIds.forEach((a,l)=>{s[`sid_${l}`]=a})}return e.untaggedOnly&&(r+=" AND NOT EXISTS (SELECT 1 FROM session_tags st WHERE st.session_id = s.id)"),e.project&&(r+=" AND p.name = @project",s.project=e.project),e.collectionId&&(r+=" AND s.id IN (SELECT session_id FROM collection_sessions WHERE collection_id = @col)",s.col=e.collectionId),t.prepare(`SELECT s.id, p.name AS project, s.git_branch,
648
648
  NULLIF(sa.alias, '') AS alias,
649
649
  COALESCE(s.first_user_message, '') AS first_user_message
650
650
  FROM sessions s
@@ -654,17 +654,17 @@ ${t.message}
654
654
  ORDER BY COALESCE(s.started_at, '') DESC
655
655
  LIMIT @limit`).all(s).map(i=>{let a=t.prepare(`SELECT role, COALESCE(content_text, '') AS content_text
656
656
  FROM messages WHERE session_id = ?
657
- ORDER BY COALESCE(timestamp, ''), rowid`).all(i.id),c=Lg(a,5).map(u=>`${u.role}: ${u.content_text.slice(0,400)}`).join(`
657
+ ORDER BY COALESCE(timestamp, ''), rowid`).all(i.id),c=ef(a,5).map(u=>`${u.role}: ${u.content_text.slice(0,400)}`).join(`
658
658
  ---
659
- `);return{id:i.id,project:i.project,git_branch:i.git_branch,alias:i.alias,first_user_message:i.first_user_message,message_sample:c,current_tags:zi(i.id)}})}var Ki=N(()=>{"use strict";T();Un()});import{z as Te}from"zod";function qi(e){let t=e.minTags??2,s=e.maxTags??4,n=e.untaggedOnly??!e.sessionId,r=["Auto-tag my Claude Recall sessions using the MCP tools available to you.","","1. Call `list_tags` first to see which tags I already use (prefer those for consistency over inventing new ones).","2. Call `list_sessions_to_tag` with these filters:"],o=[];return e.sessionId?(o.push("limit: 1"),r.push(` ${o.join(", ")}`),r.push(` Then match the session id ${e.sessionId} from the returned list.`)):(n&&o.push("untaggedOnly: true"),e.project&&o.push(`project: "${e.project}"`),e.collectionId&&o.push(`collectionId: "${e.collectionId}"`),o.push(`limit: ${e.limit??100}`),r.push(` ${o.join(", ")}`)),r.push(""),r.push(`3. For each session returned, look at the alias, first user message, git branch, and sampled messages. Pick ${t}-${s} concise, lowercase, hyphen-separated tags describing:`),r.push(" - domain/subsystem (auth, db, frontend, billing, etc.)"),r.push(" - kind of work (bugfix, feature, refactor, research)"),r.push(" - prominent tools or libraries if relevant"),r.push(""),r.push("4. Call `apply_tags` once per session to write the tags."),r.push(""),r.push("Work through EVERY session returned \u2014 do not stop partway. When done, reply with a short summary of how many sessions were tagged. Do not ask clarifying questions; just do the work."),r.join(`
660
- `)}var wx,Rx,xx,kx,Vi=N(()=>{"use strict";wx={project:Te.string().optional().describe("Exact project name match (optional)."),collectionId:Te.string().optional().describe("Restrict to sessions in this collection (optional)."),sessionId:Te.string().optional().describe("Full session UUID to tag just one session (optional)."),untaggedOnly:Te.boolean().optional().describe("Skip sessions that already have any tag (default: true)."),limit:Te.number().int().min(1).max(500).optional().describe("Max sessions to process (default: 100)."),minTags:Te.number().int().min(1).max(10).optional().describe("Minimum tags per session (default: 2)."),maxTags:Te.number().int().min(1).max(10).optional().describe("Maximum tags per session (default: 4).")};Rx={sessionId:Te.string().describe("Session UUID (or 8+-char prefix) to summarize."),mode:Te.enum(["brief","detailed"]).optional().describe("brief = 3-5 bullets; detailed = paragraph + bullets. Default: brief.")},xx={sessionId:Te.string().describe("Session UUID (or 8+-char prefix) to extract decisions from.")},kx={sessionId:Te.string().describe("Session UUID (or 8+-char prefix) to find similar sessions to."),limit:Te.number().int().min(1).max(20).optional().describe("How many similar sessions to surface (default: 5).")}});function Zi(e,t){let s=Og.get(e);if(!(!s||s.size===0))for(let n of s)try{n(t)}catch{}}var Og,Qi=N(()=>{"use strict";Og=new Map});var Bn={};Ee(Bn,{buildScanPrompt:()=>ea,isClaudeCliAvailable:()=>ce,runClaudeCliScan:()=>Ug,spawnClaudePrompt:()=>pt});import{execFileSync as Ag,execSync as Ig,spawn as vg}from"node:child_process";function Dg(){if(jt)return jt;try{jt=Ig("which claude",{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim()}catch{jt="claude"}return jt}function ce(){try{return Ag("command",["-v","claude"],{stdio:"ignore"}),!0}catch{return!1}}function ea(e){return qi({project:e.project,collectionId:e.collectionId,sessionId:e.sessionIds&&e.sessionIds.length===1?e.sessionIds[0]:void 0,untaggedOnly:e.untaggedOnly,limit:e.limit})}function $g(e,t){let s=t.get(e);return s||e.slice(0,8)}function jg(e){try{return Yi(e).map(s=>({id:s.id,label:s.alias&&s.alias.trim().length>0?s.alias:s.first_user_message&&s.first_user_message.trim().length>0?s.first_user_message.slice(0,60):s.id.slice(0,8)}))}catch{return[]}}function Pg(e){let{scanId:t,total:s,labelTable:n}=e,r=new Set;return o=>{let i=o.trim();if(!i.startsWith("{"))return;let a;try{a=JSON.parse(i)}catch{return}if(!a||typeof a!="object")return;let l=a;if(!(l.type!=="assistant"||!l.message?.content))for(let c of l.message.content){if(c?.type!=="tool_use"||c.name!=="mcp__recall__apply_tags")continue;let u=c.input,p=typeof u?.sessionId=="string"?u.sessionId:null;!p||r.has(p)||(r.add(p),Zi(t,{type:"progress",current:r.size,total:s,sessionId:p,sessionLabel:$g(p,n)}))}}}function Fg(e){let t="";return s=>{t+=s.toString("utf8");let n=t.indexOf(`
659
+ `);return{id:i.id,project:i.project,git_branch:i.git_branch,alias:i.alias,first_user_message:i.first_user_message,message_sample:c,current_tags:ia(i.id)}})}var ca=C(()=>{"use strict";T();Yn()});import{z as we}from"zod";function la(e){let t=e.minTags??2,s=e.maxTags??4,n=e.untaggedOnly??!e.sessionId,r=["Auto-tag my Claude Recall sessions using the MCP tools available to you.","","1. Call `list_tags` first to see which tags I already use (prefer those for consistency over inventing new ones).","2. Call `list_sessions_to_tag` with these filters:"],o=[];return e.sessionId?(o.push("limit: 1"),r.push(` ${o.join(", ")}`),r.push(` Then match the session id ${e.sessionId} from the returned list.`)):(n&&o.push("untaggedOnly: true"),e.project&&o.push(`project: "${e.project}"`),e.collectionId&&o.push(`collectionId: "${e.collectionId}"`),o.push(`limit: ${e.limit??100}`),r.push(` ${o.join(", ")}`)),r.push(""),r.push(`3. For each session returned, look at the alias, first user message, git branch, and sampled messages. Pick ${t}-${s} concise, lowercase, hyphen-separated tags describing:`),r.push(" - domain/subsystem (auth, db, frontend, billing, etc.)"),r.push(" - kind of work (bugfix, feature, refactor, research)"),r.push(" - prominent tools or libraries if relevant"),r.push(""),r.push("4. Call `apply_tags` once per session to write the tags."),r.push(""),r.push("Work through EVERY session returned \u2014 do not stop partway. When done, reply with a short summary of how many sessions were tagged. Do not ask clarifying questions; just do the work."),r.join(`
660
+ `)}var ak,ck,lk,dk,da=C(()=>{"use strict";ak={project:we.string().optional().describe("Exact project name match (optional)."),collectionId:we.string().optional().describe("Restrict to sessions in this collection (optional)."),sessionId:we.string().optional().describe("Full session UUID to tag just one session (optional)."),untaggedOnly:we.boolean().optional().describe("Skip sessions that already have any tag (default: true)."),limit:we.number().int().min(1).max(500).optional().describe("Max sessions to process (default: 100)."),minTags:we.number().int().min(1).max(10).optional().describe("Minimum tags per session (default: 2)."),maxTags:we.number().int().min(1).max(10).optional().describe("Maximum tags per session (default: 4).")};ck={sessionId:we.string().describe("Session UUID (or 8+-char prefix) to summarize."),mode:we.enum(["brief","detailed"]).optional().describe("brief = 3-5 bullets; detailed = paragraph + bullets. Default: brief.")},lk={sessionId:we.string().describe("Session UUID (or 8+-char prefix) to extract decisions from.")},dk={sessionId:we.string().describe("Session UUID (or 8+-char prefix) to find similar sessions to."),limit:we.number().int().min(1).max(20).optional().describe("How many similar sessions to surface (default: 5).")}});function ua(e,t){let s=tf.get(e);if(!(!s||s.size===0))for(let n of s)try{n(t)}catch{}}var tf,ma=C(()=>{"use strict";tf=new Map});var Kn={};Se(Kn,{buildScanPrompt:()=>pa,isClaudeCliAvailable:()=>ce,runClaudeCliScan:()=>mf,spawnClaudePrompt:()=>pt});import{execFileSync as sf,execSync as nf,spawn as rf}from"node:child_process";function af(){if(Bt)return Bt;try{Bt=nf("which claude",{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim()}catch{Bt="claude"}return Bt}function ce(){try{return sf("command",["-v","claude"],{stdio:"ignore"}),!0}catch{return!1}}function pa(e){return la({project:e.project,collectionId:e.collectionId,sessionId:e.sessionIds&&e.sessionIds.length===1?e.sessionIds[0]:void 0,untaggedOnly:e.untaggedOnly,limit:e.limit})}function cf(e,t){let s=t.get(e);return s||e.slice(0,8)}function lf(e){try{return aa(e).map(s=>({id:s.id,label:s.alias&&s.alias.trim().length>0?s.alias:s.first_user_message&&s.first_user_message.trim().length>0?s.first_user_message.slice(0,60):s.id.slice(0,8)}))}catch{return[]}}function df(e){let{scanId:t,total:s,labelTable:n}=e,r=new Set;return o=>{let i=o.trim();if(!i.startsWith("{"))return;let a;try{a=JSON.parse(i)}catch{return}if(!a||typeof a!="object")return;let l=a;if(!(l.type!=="assistant"||!l.message?.content))for(let c of l.message.content){if(c?.type!=="tool_use"||c.name!=="mcp__recall__apply_tags")continue;let u=c.input,m=typeof u?.sessionId=="string"?u.sessionId:null;!m||r.has(m)||(r.add(m),ua(t,{type:"progress",current:r.size,total:s,sessionId:m,sessionLabel:cf(m,n)}))}}}function uf(e){let t="";return s=>{t+=s.toString("utf8");let n=t.indexOf(`
661
661
  `);for(;n!==-1;){let r=t.slice(0,n);t=t.slice(n+1),r.length>0&&e(r),n=t.indexOf(`
662
- `)}}}async function Ug(e,t={},s){let n=!!t.scanId,r=n?jg(e):[],o=new Map(r.map(l=>[l.id,l.label])),i=r.length,a;return n&&t.scanId&&(a=Pg({scanId:t.scanId,total:i,labelTable:o})),ta({prompt:ea(e),allowedTools:Mg.split(","),opts:t,onProgress:s,onStdoutLine:a,outputFormat:n?"stream-json":"json"})}async function pt(e,t,s={},n){return ta({prompt:e,allowedTools:t,opts:s,onProgress:n,outputFormat:"json"})}function ta(e){let{prompt:t,allowedTools:s,opts:n,onProgress:r,onStdoutLine:o,outputFormat:i}=e,a=["-p",t,"--output-format",i,"--allowedTools",s.join(","),"--permission-mode","bypassPermissions"];return i==="stream-json"&&a.push("--verbose"),n.model&&a.push("--model",n.model),new Promise(l=>{let c=vg(Dg(),a,{stdio:["ignore","pipe","pipe"]}),u=[],p=[],m=o?Fg(o):void 0;c.stdout.on("data",g=>{u.push(g),m&&m(g)}),c.stderr.on("data",g=>{if(p.push(g),r){let h=g.toString("utf8").trim();h&&r(h)}});let f=setTimeout(()=>{c.kill("SIGKILL")},1800*1e3);c.on("close",g=>{clearTimeout(f),l({success:g===0,stdout:Buffer.concat(u).toString("utf8"),stderr:Buffer.concat(p).toString("utf8"),exitCode:g})}),c.on("error",g=>{clearTimeout(f),l({success:!1,stdout:"",stderr:String(g),exitCode:null})})})}var Mg,jt,Xe=N(()=>{"use strict";Ki();Vi();Qi();Mg=["mcp__recall__list_tags","mcp__recall__list_sessions_to_tag","mcp__recall__apply_tags"].join(",")});var ia={};Ee(ia,{downloadModel:()=>Jn,getModelDir:()=>ys,isModelInstalled:()=>mt,uninstallModel:()=>Gn});import{existsSync as Xn,mkdirSync as ra,rmSync as Wn,createWriteStream as of,statSync as af}from"node:fs";import{join as Ss}from"node:path";import{createHash as cf}from"node:crypto";import{readFile as lf}from"node:fs/promises";function ys(){return Ss(R,"models","BAAI","bge-base-en-v1.5")}function mt(){let e=ys();return oa.every(t=>Xn(Ss(e,t.path)))}async function Jn(e){let t=ys();ra(t,{recursive:!0}),ra(Ss(t,"onnx"),{recursive:!0});for(let s of oa){let n=Ss(t,s.path),r=df+s.path,o=0;Xn(n)&&(o=af(n).size);let i={};o>0&&(i.Range=`bytes=${o}-`);let a=await fetch(r,{headers:i});if(!a.ok&&a.status!==206)throw new Error(`Failed to download ${s.path}: HTTP ${a.status}`);let l=a.headers.get("content-length"),c=l?o+Number(l):0,u=a.body;if(!u)throw new Error(`No response body for ${s.path}`);let p=of(n,{flags:o>0?"a":"w"}),m=u.getReader(),f=o;for(;;){let{done:E,value:b}=await m.read();if(E)break;p.write(Buffer.from(b)),f+=b.byteLength,e?.(s.path,f,c)}if(p.end(),await new Promise((E,b)=>{p.on("finish",E),p.on("error",b)}),s.sha256==="TODO_PLACEHOLDER")throw Wn(n),new Error(`Refusing to install: SHA-256 not pinned for ${s.path}. Update model-download.ts.`);let g=await lf(n);if(cf("sha256").update(g).digest("hex")!==s.sha256)throw Wn(n),new Error(`SHA-256 mismatch for ${s.path}`)}}function Gn(){let e=ys();Xn(e)&&Wn(e,{recursive:!0,force:!0})}var df,oa,Ts=N(()=>{"use strict";j();df="https://huggingface.co/BAAI/bge-base-en-v1.5/resolve/main/",oa=[{path:"config.json",sha256:"bc00af31a4a31b74040d73370aa83b62da34c90b75eb77bfa7db039d90abd591"},{path:"tokenizer.json",sha256:"d241a60d5e8f04cc1b2b3e9ef7a4921b27bf526d9f6050ab90f9267a1f9e5c66"},{path:"tokenizer_config.json",sha256:"9261e7d79b44c8195c1cada2b453e55b00aeb81e907a6664974b4d7776172ab3"},{path:"onnx/model.onnx",sha256:"9bc579acdba21c253c62a9bf866891355a63ffa3442b52c8a37d75b2ccb91848"}]});var Yn={};Ee(Yn,{EmbedderUnavailableError:()=>Ft,embed:()=>gt,embedQuery:()=>zn,getEmbedderStatus:()=>Je,loadEmbedder:()=>Ke,unloadEmbedder:()=>gf});import{join as ca}from"node:path";function mf(){return ca(R,"models","bge-base-en-v1.5")}async function Ke(){if(ws&&Pt)return;let e;try{e=await import("@huggingface/transformers")}catch(n){throw new Ft(n)}let{pipeline:t,env:s}=e;s.localModelPath=ca(R,"models"),s.allowRemoteModels=!1;try{Pt=await t("feature-extraction",la,{local_files_only:!0,cache_dir:mf()}),ws=!0}catch(n){throw n instanceof Error&&/Cannot find module|onnxruntime_binding/.test(n.message)?new Ft(n):n}}function Je(){return{loaded:ws,modelId:la,dim:uf}}async function gt(e){if(!Pt)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");let t=[];for(let s=0;s<e.length;s+=aa){let n=e.slice(s,s+aa),o=(await Pt(n,{pooling:"cls",normalize:!0})).tolist();for(let i=0;i<n.length;i++){let a=o[i],l=Array.isArray(a[0])?a[0]:a;t.push(new Float32Array(l))}}return t}async function zn(e){let t=pf+e,[s]=await gt([t]);return s}function gf(){Pt=null,ws=!1}var la,uf,aa,pf,Pt,ws,Ft,qe=N(()=>{"use strict";j();la="BAAI/bge-base-en-v1.5",uf=768,aa=16,pf="Represent this sentence for searching relevant passages: ",Pt=null,ws=!1;Ft=class extends Error{cause;constructor(t){let s=t instanceof Error?t.message:String(t);super(["Semantic search is unavailable on this platform.","",`Reason: ${s}`,"",`Platform: ${process.platform}/${process.arch}, Node ${process.version}`,"","Claude Recall supports macOS (arm64/x64), Linux (x64/arm64), and Windows (x64).","Core CLI features (search, list, context, daemon) work everywhere.","Only `recall semantic *` requires the on-device embedder.","","See: https://clauderecall.com/docs (Supported platforms) \u2014 or file an issue at","https://gitlab.com/clauderecallhq/clauderecallhq/-/issues with the platform line above."].join(`
663
- `)),this.name="EmbedderUnavailableError",this.cause=t}}});import{writeFileSync as xa,readFileSync as Bk,existsSync as ka,mkdirSync as Ca,readdirSync as Hk}from"node:fs";import{join as ks}from"node:path";function r_(){P(),ka(tr)||Ca(tr,{recursive:!0})}function o_(){P(),ka(sr)||Ca(sr,{recursive:!0})}function Na(e){try{return JSON.parse(e)}catch{return e}}function nr(e){return{id:e.id,source_session_id:e.source_session_id,target_session_id:e.target_session_id,link_type:e.link_type,confidence:e.confidence,source:e.source,evidence:Na(e.evidence),approved:e.approved===1,created_at:e.created_at,updated_at:e.updated_at}}function rr(e){return{id:e.id,source_session_id:e.source_session_id,target_session_id:e.target_session_id,link_type:e.link_type,confidence:e.confidence,evidence:Na(e.evidence),status:e.status,inferred_by:e.inferred_by,created_at:e.created_at,decided_at:e.decided_at}}function i_(e){if(!Number.isFinite(e)||e<0||e>1)throw new Error("confidence must be a number in [0, 1]")}function La(e){if(!Qf.has(e))throw new Error(`invalid link_type: ${e}`)}function Oa(e){if(!s_.has(e))throw new Error(`invalid inferred_by: ${e}`)}function a_(e,t){if(!e||!t)throw new Error("source_session_id and target_session_id are required");if(e===t)throw new Error("a session cannot link to itself")}function c_(e={}){let t=_(),s=[],n=[];e.sourceSessionId&&(s.push("source_session_id = ?"),n.push(e.sourceSessionId)),e.targetSessionId&&(s.push("target_session_id = ?"),n.push(e.targetSessionId)),e.linkType&&(La(e.linkType),s.push("link_type = ?"),n.push(e.linkType)),e.approvedOnly&&s.push("approved = 1");let r=s.length?`WHERE ${s.join(" AND ")}`:"",o=Math.max(1,Math.min(5e3,e.limit??1e3));return t.prepare(`SELECT * FROM session_links ${r}
662
+ `)}}}async function mf(e,t={},s){let n=!!t.scanId,r=n?lf(e):[],o=new Map(r.map(l=>[l.id,l.label])),i=r.length,a;return n&&t.scanId&&(a=df({scanId:t.scanId,total:i,labelTable:o})),ga({prompt:pa(e),allowedTools:of.split(","),opts:t,onProgress:s,onStdoutLine:a,outputFormat:n?"stream-json":"json"})}async function pt(e,t,s={},n){return ga({prompt:e,allowedTools:t,opts:s,onProgress:n,outputFormat:"json"})}function ga(e){let{prompt:t,allowedTools:s,opts:n,onProgress:r,onStdoutLine:o,outputFormat:i}=e,a=["-p",t,"--output-format",i,"--allowedTools",s.join(","),"--permission-mode","bypassPermissions"];return i==="stream-json"&&a.push("--verbose"),n.model&&a.push("--model",n.model),new Promise(l=>{let c=rf(af(),a,{stdio:["ignore","pipe","pipe"]}),u=[],m=[],p=o?uf(o):void 0;c.stdout.on("data",g=>{u.push(g),p&&p(g)}),c.stderr.on("data",g=>{if(m.push(g),r){let h=g.toString("utf8").trim();h&&r(h)}});let f=setTimeout(()=>{c.kill("SIGKILL")},1800*1e3);c.on("close",g=>{clearTimeout(f),l({success:g===0,stdout:Buffer.concat(u).toString("utf8"),stderr:Buffer.concat(m).toString("utf8"),exitCode:g})}),c.on("error",g=>{clearTimeout(f),l({success:!1,stdout:"",stderr:String(g),exitCode:null})})})}var of,Bt,Je=C(()=>{"use strict";ca();da();ma();of=["mcp__recall__list_tags","mcp__recall__list_sessions_to_tag","mcp__recall__apply_tags"].join(",")});var ba={};Se(ba,{downloadModel:()=>Qn,getModelDir:()=>ks,isModelInstalled:()=>gt,uninstallModel:()=>er});import{existsSync as Zn,mkdirSync as ha,rmSync as Vn,createWriteStream as Af,statSync as If}from"node:fs";import{join as xs}from"node:path";import{createHash as vf}from"node:crypto";import{readFile as Mf}from"node:fs/promises";function ks(){return xs(R,"models","BAAI","bge-base-en-v1.5")}function gt(){let e=ks();return Ea.every(t=>Zn(xs(e,t.path)))}async function Qn(e){let t=ks();ha(t,{recursive:!0}),ha(xs(t,"onnx"),{recursive:!0});for(let s of Ea){let n=xs(t,s.path),r=Df+s.path,o=0;Zn(n)&&(o=If(n).size);let i={};o>0&&(i.Range=`bytes=${o}-`);let a=await fetch(r,{headers:i});if(!a.ok&&a.status!==206)throw new Error(`Failed to download ${s.path}: HTTP ${a.status}`);let l=a.headers.get("content-length"),c=l?o+Number(l):0,u=a.body;if(!u)throw new Error(`No response body for ${s.path}`);let m=Af(n,{flags:o>0?"a":"w"}),p=u.getReader(),f=o;for(;;){let{done:E,value:b}=await p.read();if(E)break;m.write(Buffer.from(b)),f+=b.byteLength,e?.(s.path,f,c)}if(m.end(),await new Promise((E,b)=>{m.on("finish",E),m.on("error",b)}),s.sha256==="TODO_PLACEHOLDER")throw Vn(n),new Error(`Refusing to install: SHA-256 not pinned for ${s.path}. Update model-download.ts.`);let g=await Mf(n);if(vf("sha256").update(g).digest("hex")!==s.sha256)throw Vn(n),new Error(`SHA-256 mismatch for ${s.path}`)}}function er(){let e=ks();Zn(e)&&Vn(e,{recursive:!0,force:!0})}var Df,Ea,Ns=C(()=>{"use strict";j();Df="https://huggingface.co/BAAI/bge-base-en-v1.5/resolve/main/",Ea=[{path:"config.json",sha256:"bc00af31a4a31b74040d73370aa83b62da34c90b75eb77bfa7db039d90abd591"},{path:"tokenizer.json",sha256:"d241a60d5e8f04cc1b2b3e9ef7a4921b27bf526d9f6050ab90f9267a1f9e5c66"},{path:"tokenizer_config.json",sha256:"9261e7d79b44c8195c1cada2b453e55b00aeb81e907a6664974b4d7776172ab3"},{path:"onnx/model.onnx",sha256:"9bc579acdba21c253c62a9bf866891355a63ffa3442b52c8a37d75b2ccb91848"}]});var sr={};Se(sr,{EmbedderUnavailableError:()=>Wt,embed:()=>ft,embedQuery:()=>tr,getEmbedderStatus:()=>Ge,loadEmbedder:()=>qe,unloadEmbedder:()=>Ff});import{join as ya}from"node:path";function Pf(){return ya(R,"models","bge-base-en-v1.5")}async function qe(){if(Cs&&Ht)return;let e;try{e=await import("@huggingface/transformers")}catch(n){throw new Wt(n)}let{pipeline:t,env:s}=e;s.localModelPath=ya(R,"models"),s.allowRemoteModels=!1;try{Ht=await t("feature-extraction",Ta,{local_files_only:!0,cache_dir:Pf()}),Cs=!0}catch(n){throw n instanceof Error&&/Cannot find module|onnxruntime_binding/.test(n.message)?new Wt(n):n}}function Ge(){return{loaded:Cs,modelId:Ta,dim:$f}}async function ft(e){if(!Ht)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");let t=[];for(let s=0;s<e.length;s+=Sa){let n=e.slice(s,s+Sa),o=(await Ht(n,{pooling:"cls",normalize:!0})).tolist();for(let i=0;i<n.length;i++){let a=o[i],l=Array.isArray(a[0])?a[0]:a;t.push(new Float32Array(l))}}return t}async function tr(e){let t=jf+e,[s]=await ft([t]);return s}function Ff(){Ht=null,Cs=!1}var Ta,$f,Sa,jf,Ht,Cs,Wt,Ve=C(()=>{"use strict";j();Ta="BAAI/bge-base-en-v1.5",$f=768,Sa=16,jf="Represent this sentence for searching relevant passages: ",Ht=null,Cs=!1;Wt=class extends Error{cause;constructor(t){let s=t instanceof Error?t.message:String(t);super(["Semantic search is unavailable on this platform.","",`Reason: ${s}`,"",`Platform: ${process.platform}/${process.arch}, Node ${process.version}`,"","Claude Recall supports macOS (arm64/x64), Linux (x64/arm64), and Windows (x64).","Core CLI features (search, list, context, daemon) work everywhere.","Only `recall semantic *` requires the on-device embedder.","","See: https://clauderecall.com/docs (Supported platforms) \u2014 or file an issue at","https://gitlab.com/clauderecallhq/clauderecallhq/-/issues with the platform line above."].join(`
663
+ `)),this.name="EmbedderUnavailableError",this.cause=t}}});import{writeFileSync as Pa,readFileSync as xN,existsSync as Fa,mkdirSync as Ua,readdirSync as kN}from"node:fs";import{join as As}from"node:path";function L_(){P(),Fa(lr)||Ua(lr,{recursive:!0})}function O_(){P(),Fa(dr)||Ua(dr,{recursive:!0})}function Ba(e){try{return JSON.parse(e)}catch{return e}}function ur(e){return{id:e.id,source_session_id:e.source_session_id,target_session_id:e.target_session_id,link_type:e.link_type,confidence:e.confidence,source:e.source,evidence:Ba(e.evidence),approved:e.approved===1,created_at:e.created_at,updated_at:e.updated_at}}function mr(e){return{id:e.id,source_session_id:e.source_session_id,target_session_id:e.target_session_id,link_type:e.link_type,confidence:e.confidence,evidence:Ba(e.evidence),status:e.status,inferred_by:e.inferred_by,created_at:e.created_at,decided_at:e.decided_at}}function A_(e){if(!Number.isFinite(e)||e<0||e>1)throw new Error("confidence must be a number in [0, 1]")}function Ha(e){if(!R_.has(e))throw new Error(`invalid link_type: ${e}`)}function Wa(e){if(!N_.has(e))throw new Error(`invalid inferred_by: ${e}`)}function I_(e,t){if(!e||!t)throw new Error("source_session_id and target_session_id are required");if(e===t)throw new Error("a session cannot link to itself")}function v_(e={}){let t=_(),s=[],n=[];e.sourceSessionId&&(s.push("source_session_id = ?"),n.push(e.sourceSessionId)),e.targetSessionId&&(s.push("target_session_id = ?"),n.push(e.targetSessionId)),e.linkType&&(Ha(e.linkType),s.push("link_type = ?"),n.push(e.linkType)),e.approvedOnly&&s.push("approved = 1");let r=s.length?`WHERE ${s.join(" AND ")}`:"",o=Math.max(1,Math.min(5e3,e.limit??1e3));return t.prepare(`SELECT * FROM session_links ${r}
664
664
  ORDER BY confidence DESC, updated_at DESC
665
- LIMIT ?`).all(...n,o).map(nr)}function or(e){return _().prepare(`SELECT * FROM session_links
665
+ LIMIT ?`).all(...n,o).map(ur)}function pr(e){return _().prepare(`SELECT * FROM session_links
666
666
  WHERE source_session_id = ? OR target_session_id = ?
667
- ORDER BY confidence DESC, updated_at DESC`).all(e,e).map(nr)}function Ze(e){a_(e.source_session_id,e.target_session_id),La(e.link_type),i_(e.confidence),Oa(e.inferred_by);let t=_(),s=new Date().toISOString(),n=JSON.stringify(e.evidence??null);t.prepare(`INSERT INTO session_link_suggestions
667
+ ORDER BY confidence DESC, updated_at DESC`).all(e,e).map(ur)}function Qe(e){I_(e.source_session_id,e.target_session_id),Ha(e.link_type),A_(e.confidence),Wa(e.inferred_by);let t=_(),s=new Date().toISOString(),n=JSON.stringify(e.evidence??null);t.prepare(`INSERT INTO session_link_suggestions
668
668
  (source_session_id, target_session_id, link_type,
669
669
  confidence, evidence, status, inferred_by,
670
670
  created_at, decided_at)
@@ -684,9 +684,9 @@ ${t.message}
684
684
  WHERE source_session_id = ?
685
685
  AND target_session_id = ?
686
686
  AND link_type = ?
687
- AND inferred_by = ?`).get(e.source_session_id,e.target_session_id,e.link_type,e.inferred_by);if(!r)throw new Error("createSuggestion succeeded but read-back failed");return Ia(),rr(r)}function Cs(e={}){let t=_(),s=[],n=[];if(e.status){if(!t_.has(e.status))throw new Error(`invalid status: ${e.status}`);s.push("status = ?"),n.push(e.status)}e.sourceSessionId&&(s.push("source_session_id = ?"),n.push(e.sourceSessionId)),e.targetSessionId&&(s.push("target_session_id = ?"),n.push(e.targetSessionId)),e.inferredBy&&(Oa(e.inferredBy),s.push("inferred_by = ?"),n.push(e.inferredBy));let r=s.length?`WHERE ${s.join(" AND ")}`:"",o=Math.max(1,Math.min(5e3,e.limit??1e3));return t.prepare(`SELECT * FROM session_link_suggestions ${r}
687
+ AND inferred_by = ?`).get(e.source_session_id,e.target_session_id,e.link_type,e.inferred_by);if(!r)throw new Error("createSuggestion succeeded but read-back failed");return Ja(),mr(r)}function Is(e={}){let t=_(),s=[],n=[];if(e.status){if(!k_.has(e.status))throw new Error(`invalid status: ${e.status}`);s.push("status = ?"),n.push(e.status)}e.sourceSessionId&&(s.push("source_session_id = ?"),n.push(e.sourceSessionId)),e.targetSessionId&&(s.push("target_session_id = ?"),n.push(e.targetSessionId)),e.inferredBy&&(Wa(e.inferredBy),s.push("inferred_by = ?"),n.push(e.inferredBy));let r=s.length?`WHERE ${s.join(" AND ")}`:"",o=Math.max(1,Math.min(5e3,e.limit??1e3));return t.prepare(`SELECT * FROM session_link_suggestions ${r}
688
688
  ORDER BY confidence DESC, created_at DESC
689
- LIMIT ?`).all(...n,o).map(rr)}function Aa(e,t,s={}){if(t!=="approved"&&t!=="rejected")throw new Error(`invalid decision: ${t}`);let n=s.source??"manual";if(!e_.has(n))throw new Error(`invalid source: ${n}`);let r=_(),o=r.prepare("SELECT * FROM session_link_suggestions WHERE id = ?").get(e);if(!o)throw new Error(`suggestion ${e} not found`);if(o.status!=="pending")throw new Error(`suggestion ${e} already decided as ${o.status}`);let i=new Date().toISOString(),a;r.transaction(()=>{r.prepare(`UPDATE session_link_suggestions
689
+ LIMIT ?`).all(...n,o).map(mr)}function Xa(e,t,s={}){if(t!=="approved"&&t!=="rejected")throw new Error(`invalid decision: ${t}`);let n=s.source??"manual";if(!x_.has(n))throw new Error(`invalid source: ${n}`);let r=_(),o=r.prepare("SELECT * FROM session_link_suggestions WHERE id = ?").get(e);if(!o)throw new Error(`suggestion ${e} not found`);if(o.status!=="pending")throw new Error(`suggestion ${e} already decided as ${o.status}`);let i=new Date().toISOString(),a;r.transaction(()=>{r.prepare(`UPDATE session_link_suggestions
690
690
  SET status = ?, decided_at = ?
691
691
  WHERE id = ?`).run(t,i,e),t==="approved"&&(r.prepare(`INSERT INTO session_links
692
692
  (source_session_id, target_session_id, link_type,
@@ -701,7 +701,7 @@ ${t.message}
701
701
  updated_at = excluded.updated_at`).run(o.source_session_id,o.target_session_id,o.link_type,o.confidence,n,o.evidence,i,i),a=r.prepare(`SELECT * FROM session_links
702
702
  WHERE source_session_id = ?
703
703
  AND target_session_id = ?
704
- AND link_type = ?`).get(o.source_session_id,o.target_session_id,o.link_type))})(),Ia(),t==="approved"&&l_(o.source_session_id);let l=r.prepare("SELECT * FROM session_link_suggestions WHERE id = ?").get(e);return{suggestion:rr(l),link:a?nr(a):null}}function l_(e){try{r_();let t=c_({sourceSessionId:e}),s=ks(tr,`${e}.json`);if(t.length===0)return;let n={schema:"claude-recall.session-links.v1",source_session_id:e,backed_up_at:new Date().toISOString(),links:t};xa(s,JSON.stringify(n,null,2))}catch(t){console.error("[session-links] backup failed:",t)}}function Ia(){try{o_();let e=Cs({limit:5e3}),t={schema:"claude-recall.session-link-suggestions.v1",backed_up_at:new Date().toISOString(),suggestions:e};xa(n_,JSON.stringify(t,null,2))}catch(e){console.error("[session-links] suggestions backup failed:",e)}}var Qf,e_,t_,s_,tr,sr,n_,Wt=N(()=>{"use strict";T();j();Qf=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),e_=new Set(["regex","llm","embedding","manual","auto","citation","git","terminal-registry"]),t_=new Set(["pending","approved","rejected"]),s_=new Set(["L1","L2","L3","L4","user"]),tr=ks(R,"links"),sr=ks(R,"suggestions"),n_=ks(sr,"index.json")});function Is(e){return e?Math.ceil(e.length/4):0}function nc(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/Ch);return Math.max(Nh,t)}function rc(e,t){if(!e||!t)return 0;let s=Date.parse(e),n=Date.parse(t);return!Number.isFinite(s)||!Number.isFinite(n)?0:Math.abs(n-s)/(1e3*60*60*24)}function oc(e){return _().prepare(`SELECT s.id,
704
+ AND link_type = ?`).get(o.source_session_id,o.target_session_id,o.link_type))})(),Ja(),t==="approved"&&M_(o.source_session_id);let l=r.prepare("SELECT * FROM session_link_suggestions WHERE id = ?").get(e);return{suggestion:mr(l),link:a?ur(a):null}}function M_(e){try{L_();let t=v_({sourceSessionId:e}),s=As(lr,`${e}.json`);if(t.length===0)return;let n={schema:"claude-recall.session-links.v1",source_session_id:e,backed_up_at:new Date().toISOString(),links:t};Pa(s,JSON.stringify(n,null,2))}catch(t){console.error("[session-links] backup failed:",t)}}function Ja(){try{O_();let e=Is({limit:5e3}),t={schema:"claude-recall.session-link-suggestions.v1",backed_up_at:new Date().toISOString(),suggestions:e};Pa(C_,JSON.stringify(t,null,2))}catch(e){console.error("[session-links] suggestions backup failed:",e)}}var R_,x_,k_,N_,lr,dr,C_,zt=C(()=>{"use strict";T();j();R_=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),x_=new Set(["regex","llm","embedding","manual","auto","citation","git","terminal-registry"]),k_=new Set(["pending","approved","rejected"]),N_=new Set(["L1","L2","L3","L4","user"]),lr=As(R,"links"),dr=As(R,"suggestions"),C_=As(dr,"index.json")});function js(e){return e?Math.ceil(e.length/4):0}function _c(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/Zh);return Math.max(Qh,t)}function hc(e,t){if(!e||!t)return 0;let s=Date.parse(e),n=Date.parse(t);return!Number.isFinite(s)||!Number.isFinite(n)?0:Math.abs(n-s)/(1e3*60*60*24)}function Ec(e){return _().prepare(`SELECT s.id,
705
705
  NULLIF(sa.alias, '') AS alias,
706
706
  s.auto_title,
707
707
  s.auto_title_source,
@@ -712,37 +712,37 @@ ${t.message}
712
712
  FROM sessions s
713
713
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
714
714
  LEFT JOIN projects p ON p.id = s.project_id
715
- WHERE s.id = ?`).get(e)??null}function ic(e){let s=_().prepare("SELECT summary FROM session_semantic WHERE session_id = ?").get(e);if(!s||!s.summary)return null;let n=s.summary.trim();return n.length>0?n:null}function ac(e){let t=e.alias?.trim(),s=e.auto_title?.trim(),n=e.first_user_message?.trim();return s&&e.auto_title_source==="agent"?s:t||s||(n?n.slice(0,80):e.id.slice(0,8))}function Oh(e){let s=_().prepare(`SELECT id, auto_title, started_at
715
+ WHERE s.id = ?`).get(e)??null}function bc(e){let s=_().prepare("SELECT summary FROM session_semantic WHERE session_id = ?").get(e);if(!s||!s.summary)return null;let n=s.summary.trim();return n.length>0?n:null}function Sc(e){let t=e.alias?.trim(),s=e.auto_title?.trim(),n=e.first_user_message?.trim();return s&&e.auto_title_source==="agent"?s:t||s||(n?n.slice(0,80):e.id.slice(0,8))}function tE(e){let s=_().prepare(`SELECT id, auto_title, started_at
716
716
  FROM sessions
717
717
  WHERE project_id = ?
718
- ORDER BY COALESCE(started_at, ''), id`).all(e),n=new Set,r=new Set,o=[];for(let m of s){if(!m.auto_title||!m.auto_title.startsWith("/")){o.push({id:m.id,brand:null,skill:null});continue}let f=m.auto_title.split(" \xB7 "),g=f[0].trim(),h=f.length>1?f.slice(1).join(" \xB7 ").trim():null;o.push({id:m.id,brand:h||null,skill:g||null}),h&&n.add(h),g&&r.add(g)}let i=[...n].sort(),a=new Map;i.forEach((m,f)=>a.set(m,f));let l=[...r].sort(),c=new Map;l.forEach((m,f)=>c.set(m,f));let u=new Map,p=new Map;for(let m of o){if(!m.brand||!m.skill)continue;let f=a.get(m.brand),g=c.get(m.skill);if(f===void 0||g===void 0)continue;let h=`${f}.${g}`,E=(u.get(h)??0)+1;u.set(h,E),p.set(m.id,`${f}.${g}.${E}`)}return{byId:p}}function Ah(e){return{table:e!==null?Oh(e):null,originProjectId:e,cache:new Map}}function vs(e,t){let s=e.cache.get(t);if(s)return s;let n=oc(t);if(!n)return null;let r=e.table&&n.project_id===e.originProjectId?e.table.byId.get(t)??null:null,o={session_id:n.id,title:ac(n),decimal:r,summary:ic(n.id),project:n.project,started_at:n.started_at};return e.cache.set(t,o),o}function Ih(e,t){let n=_().prepare(`SELECT DISTINCT te.parent_session_id AS pid
718
+ ORDER BY COALESCE(started_at, ''), id`).all(e),n=new Set,r=new Set,o=[];for(let p of s){if(!p.auto_title||!p.auto_title.startsWith("/")){o.push({id:p.id,brand:null,skill:null});continue}let f=p.auto_title.split(" \xB7 "),g=f[0].trim(),h=f.length>1?f.slice(1).join(" \xB7 ").trim():null;o.push({id:p.id,brand:h||null,skill:g||null}),h&&n.add(h),g&&r.add(g)}let i=[...n].sort(),a=new Map;i.forEach((p,f)=>a.set(p,f));let l=[...r].sort(),c=new Map;l.forEach((p,f)=>c.set(p,f));let u=new Map,m=new Map;for(let p of o){if(!p.brand||!p.skill)continue;let f=a.get(p.brand),g=c.get(p.skill);if(f===void 0||g===void 0)continue;let h=`${f}.${g}`,E=(u.get(h)??0)+1;u.set(h,E),m.set(p.id,`${f}.${g}.${E}`)}return{byId:m}}function sE(e){return{table:e!==null?tE(e):null,originProjectId:e,cache:new Map}}function Ps(e,t){let s=e.cache.get(t);if(s)return s;let n=Ec(t);if(!n)return null;let r=e.table&&n.project_id===e.originProjectId?e.table.byId.get(t)??null:null,o={session_id:n.id,title:Sc(n),decimal:r,summary:bc(n.id),project:n.project,started_at:n.started_at};return e.cache.set(t,o),o}function nE(e,t){let n=_().prepare(`SELECT DISTINCT te.parent_session_id AS pid
719
719
  FROM thread_edges te
720
720
  WHERE te.session_id = ?
721
- AND te.parent_session_id IS NOT NULL`).all(t),r=[];for(let o of n){if(!o.pid)continue;let i=vs(e,o.pid);i&&r.push(i)}return r}function vh(e,t){let n=_().prepare(`SELECT DISTINCT te.session_id AS sid
721
+ AND te.parent_session_id IS NOT NULL`).all(t),r=[];for(let o of n){if(!o.pid)continue;let i=Ps(e,o.pid);i&&r.push(i)}return r}function rE(e,t){let n=_().prepare(`SELECT DISTINCT te.session_id AS sid
722
722
  FROM thread_edges te
723
- WHERE te.parent_session_id = ?`).all(t),r=[];for(let o of n){if(!o.sid)continue;let i=vs(e,o.sid);i&&r.push(i)}return r}function cc(e){let t=Lh[e.linkType]??.5,s=Tt(e.confidence),n=t*s,r=nc(e.daysApart),o=e.embeddingCosine??.5,i=Tt(e.pagerank);if(e.scoring==="pagerank")return Tt(i);if(e.scoring==="embedding-rerank")return e.embeddingCosine===null?Tt(n):Tt(o);let a=.35*n+.2*r+.2*o+.25*i;return Tt(a)}function Tt(e){return!Number.isFinite(e)||e<0?0:e>1?1:e}function Mh(e,t,s,n,r){let o=new Map;function i(a,l){if(a===l)return;let c=o.get(a);c||(c=new Set,o.set(a,c)),c.add(l)}for(let a of t)i(a.source_session_id,a.target_session_id),i(a.target_session_id,a.source_session_id);for(let a of s)i(e,a.session_id);for(let a of s)i(a.session_id,e);for(let a of n)i(e,a.session_id);for(let a of n)i(a.session_id,e);if(r>1){let a=new Set([e]),l=new Set([e]);for(let c=1;c<r;c++){let u=new Set;for(let p of a){let m=o.get(p);if(m)for(let f of m){if(l.has(f))continue;let g=or(f).filter(h=>h.approved);for(let h of g)i(h.source_session_id,h.target_session_id),i(h.target_session_id,h.source_session_id);l.add(f),u.add(f)}}if(u.size===0)break;for(let p of u)a.add(p)}}return{edges:o}}function Dh(e,t={}){let s=t.iterations??12,n=t.damping??.85,r=Array.from(e.edges.keys());if(r.length===0)return new Map;let o=1/r.length,i=new Map(r.map(c=>[c,o]));for(let c=0;c<s;c++){let u=new Map(r.map(p=>[p,(1-n)/r.length]));for(let p of r){let m=e.edges.get(p);if(!m||m.size===0)continue;let f=(i.get(p)??0)/m.size;for(let g of m)u.set(g,(u.get(g)??0)+n*f)}i=u}let a=0;for(let c of i.values())c>a&&(a=c);if(a<=0)return i;let l=new Map;for(let[c,u]of i)l.set(c,u/a);return l}function dc(e,t){let s=e.replace(/\s+/g," ").trim();return s.length<=t?s:`${s.slice(0,t-1).trimEnd()}\u2026`}function $h(e){let t=e.decimal?`${e.decimal} `:"",s=e.session_id.slice(0,8),n="evidence"in e&&e.evidence?` \u2014 ${e.evidence}`:"",r=`- ${t}${e.title} (${s})${n}`;if(e.summary){let o=dc(e.summary,lc);return`${r}
724
- ${o}`}return r}function jh(e,t,s){let n=[],r=[],o=0,i=e.decimal?`${e.decimal}: `:"",a=`# Neighborhood for ${e.session_id} (${i}${e.title})`;if(n.push(a),o+=Is(a),e.summary){let l=dc(e.summary,lc*4);n.push(l),o+=Is(l)}n.push("");for(let l of t){if(l.refs.length===0)continue;let c=`## ${l.heading}`,u=Is(c),p=[],m=0;for(let f of l.refs){let g=$h(f),h=Is(g);if(o+u+m+h>s){r.push({session_id:f.session_id,title:f.title,decimal:f.decimal,summary:f.summary,project:f.project,started_at:f.started_at});continue}p.push(g),m+=h}if(p.length>0){n.push(c);for(let f of p)n.push(f);n.push(""),o+=u+m}}for(;n.length>0&&n[n.length-1]==="";)n.pop();return{bundle:n.join(`
723
+ WHERE te.parent_session_id = ?`).all(t),r=[];for(let o of n){if(!o.sid)continue;let i=Ps(e,o.sid);i&&r.push(i)}return r}function yc(e){let t=eE[e.linkType]??.5,s=xt(e.confidence),n=t*s,r=_c(e.daysApart),o=e.embeddingCosine??.5,i=xt(e.pagerank);if(e.scoring==="pagerank")return xt(i);if(e.scoring==="embedding-rerank")return e.embeddingCosine===null?xt(n):xt(o);let a=.35*n+.2*r+.2*o+.25*i;return xt(a)}function xt(e){return!Number.isFinite(e)||e<0?0:e>1?1:e}function oE(e,t,s,n,r){let o=new Map;function i(a,l){if(a===l)return;let c=o.get(a);c||(c=new Set,o.set(a,c)),c.add(l)}for(let a of t)i(a.source_session_id,a.target_session_id),i(a.target_session_id,a.source_session_id);for(let a of s)i(e,a.session_id);for(let a of s)i(a.session_id,e);for(let a of n)i(e,a.session_id);for(let a of n)i(a.session_id,e);if(r>1){let a=new Set([e]),l=new Set([e]);for(let c=1;c<r;c++){let u=new Set;for(let m of a){let p=o.get(m);if(p)for(let f of p){if(l.has(f))continue;let g=pr(f).filter(h=>h.approved);for(let h of g)i(h.source_session_id,h.target_session_id),i(h.target_session_id,h.source_session_id);l.add(f),u.add(f)}}if(u.size===0)break;for(let m of u)a.add(m)}}return{edges:o}}function iE(e,t={}){let s=t.iterations??12,n=t.damping??.85,r=Array.from(e.edges.keys());if(r.length===0)return new Map;let o=1/r.length,i=new Map(r.map(c=>[c,o]));for(let c=0;c<s;c++){let u=new Map(r.map(m=>[m,(1-n)/r.length]));for(let m of r){let p=e.edges.get(m);if(!p||p.size===0)continue;let f=(i.get(m)??0)/p.size;for(let g of p)u.set(g,(u.get(g)??0)+n*f)}i=u}let a=0;for(let c of i.values())c>a&&(a=c);if(a<=0)return i;let l=new Map;for(let[c,u]of i)l.set(c,u/a);return l}function wc(e,t){let s=e.replace(/\s+/g," ").trim();return s.length<=t?s:`${s.slice(0,t-1).trimEnd()}\u2026`}function aE(e){let t=e.decimal?`${e.decimal} `:"",s=e.session_id.slice(0,8),n="evidence"in e&&e.evidence?` \u2014 ${e.evidence}`:"",r=`- ${t}${e.title} (${s})${n}`;if(e.summary){let o=wc(e.summary,Tc);return`${r}
724
+ ${o}`}return r}function cE(e,t,s){let n=[],r=[],o=0,i=e.decimal?`${e.decimal}: `:"",a=`# Neighborhood for ${e.session_id} (${i}${e.title})`;if(n.push(a),o+=js(a),e.summary){let l=wc(e.summary,Tc*4);n.push(l),o+=js(l)}n.push("");for(let l of t){if(l.refs.length===0)continue;let c=`## ${l.heading}`,u=js(c),m=[],p=0;for(let f of l.refs){let g=aE(f),h=js(g);if(o+u+p+h>s){r.push({session_id:f.session_id,title:f.title,decimal:f.decimal,summary:f.summary,project:f.project,started_at:f.started_at});continue}m.push(g),p+=h}if(m.length>0){n.push(c);for(let f of m)n.push(f);n.push(""),o+=u+p}}for(;n.length>0&&n[n.length-1]==="";)n.pop();return{bundle:n.join(`
725
725
  `)+`
726
- `,budgetUsed:o,truncated:r}}function Ph(e,t,s,n,r,o){let i=[];for(let a of s){if(n&&!n.has(a.link_type))continue;let l=null;if(a.source_session_id===t.session_id?l=a.target_session_id:a.target_session_id===t.session_id&&(l=a.source_session_id),!l)continue;let c=vs(e,l);if(!c)continue;let u=rc(t.started_at,c.started_at),p=cc({confidence:a.confidence,linkType:a.link_type,daysApart:u,embeddingCosine:null,pagerank:o.get(l)??0,scoring:r});i.push({...c,score:p,evidence:`(suggestion, ${a.inferred_by}) confidence=${a.confidence.toFixed(2)} ${Math.round(u)}d apart`,link_type:a.link_type})}return i}function Ms(e,t={}){let s=Math.max(100,Math.floor(t.budget??xh)),n=t.scoring??"hybrid",r=Math.max(1,Math.min(5,t.maxDepth??kh)),o=t.includeWikiLinks??!0,i=t.includeSuggestions??!1,a=t.edgeTypes?new Set(t.edgeTypes):null,l=oc(e);if(!l)throw new Error(`session not found: ${e}`);let c=Ah(l.project_id),u={session_id:l.id,title:ac(l),decimal:c.table?.byId.get(l.id)??null,summary:ic(l.id),project:l.project,started_at:l.started_at};c.cache.set(l.id,u);let p=Ih(c,e),m=vh(c,e),f=or(e).filter(I=>I.approved).filter(I=>!a||a.has(I.link_type)).filter(I=>o||I.link_type!=="wiki_link"),g=Mh(e,f,p,m,r),h=Dh(g),E=[],b=[],S=[],C=[];for(let I of f){let ee=I.source_session_id===e?I.target_session_id:I.source_session_id,B=vs(c,ee);if(!B)continue;let y=rc(u.started_at,B.started_at),U=cc({confidence:I.confidence,linkType:I.link_type,daysApart:y,embeddingCosine:null,pagerank:h.get(ee)??0,scoring:n}),v=nc(y),K=`${I.link_type} confidence=${I.confidence.toFixed(2)} recency=${v.toFixed(2)} (${Math.round(y)}d apart)`,Ue={...B,score:U,evidence:K,link_type:I.link_type};I.link_type==="citation"?E.push(Ue):I.link_type==="similar"?b.push(Ue):I.link_type==="wiki_link"?C.push(Ue):S.push(Ue)}if(i){let I=Cs({sourceSessionId:e,status:"pending",limit:100}),ee=Cs({targetSessionId:e,status:"pending",limit:100}),B=[...I,...ee],y=new Set,U=B.filter(K=>y.has(K.id)?!1:(y.add(K.id),!0)),v=Ph(c,u,U,a,n,h);for(let K of v)K.link_type==="citation"?E.push(K):K.link_type==="similar"?b.push(K):K.link_type==="wiki_link"?C.push(K):S.push(K)}let x=(I,ee)=>ee.score-I.score;E.sort(x),b.sort(x),S.sort(x),C.sort(x);let Q=jh(u,[{heading:"Parents",refs:p},{heading:"Children",refs:m},{heading:"Citations (approved)",refs:E},{heading:"Similar sessions",refs:b},{heading:"Cousins (skill track + temporal)",refs:S},{heading:"Wiki links (manual)",refs:C}],s);return{origin:u,parents:p,children:m,citations:E,similar:b,cousins:S,wikiLinks:C,bundle:Q.bundle,budgetUsed:Q.budgetUsed,budgetRemaining:Math.max(0,s-Q.budgetUsed),truncated:Q.truncated}}var xh,kh,Ch,Nh,Lh,lc,mr=N(()=>{"use strict";T();Wt();xh=4e3,kh=2,Ch=30,Nh=.2,Lh={citation:1,wiki_link:.9,similar:.7,skill_track:.5,bug_pattern:.4,temporal_proximity:.3};lc=240});var nl={};Ee(nl,{computeAllHealthScores:()=>Lr,computeHealthScore:()=>Cr,computeHealthScoreByName:()=>Nr});function Jt(e){return Math.max(0,Math.min(1,e))}function Cr(e){let t=_(),s=t.prepare("SELECT id, name FROM projects WHERE id = ?").get(e);if(!s)return null;let n=t.prepare(`SELECT COUNT(*) AS cnt,
726
+ `,budgetUsed:o,truncated:r}}function lE(e,t,s,n,r,o){let i=[];for(let a of s){if(n&&!n.has(a.link_type))continue;let l=null;if(a.source_session_id===t.session_id?l=a.target_session_id:a.target_session_id===t.session_id&&(l=a.source_session_id),!l)continue;let c=Ps(e,l);if(!c)continue;let u=hc(t.started_at,c.started_at),m=yc({confidence:a.confidence,linkType:a.link_type,daysApart:u,embeddingCosine:null,pagerank:o.get(l)??0,scoring:r});i.push({...c,score:m,evidence:`(suggestion, ${a.inferred_by}) confidence=${a.confidence.toFixed(2)} ${Math.round(u)}d apart`,link_type:a.link_type})}return i}function Fs(e,t={}){let s=Math.max(100,Math.floor(t.budget??qh)),n=t.scoring??"hybrid",r=Math.max(1,Math.min(5,t.maxDepth??Vh)),o=t.includeWikiLinks??!0,i=t.includeSuggestions??!1,a=t.edgeTypes?new Set(t.edgeTypes):null,l=Ec(e);if(!l)throw new Error(`session not found: ${e}`);let c=sE(l.project_id),u={session_id:l.id,title:Sc(l),decimal:c.table?.byId.get(l.id)??null,summary:bc(l.id),project:l.project,started_at:l.started_at};c.cache.set(l.id,u);let m=nE(c,e),p=rE(c,e),f=pr(e).filter(v=>v.approved).filter(v=>!a||a.has(v.link_type)).filter(v=>o||v.link_type!=="wiki_link"),g=oE(e,f,m,p,r),h=iE(g),E=[],b=[],S=[],N=[];for(let v of f){let ee=v.source_session_id===e?v.target_session_id:v.source_session_id,B=Ps(c,ee);if(!B)continue;let y=hc(u.started_at,B.started_at),U=yc({confidence:v.confidence,linkType:v.link_type,daysApart:y,embeddingCosine:null,pagerank:h.get(ee)??0,scoring:n}),M=_c(y),K=`${v.link_type} confidence=${v.confidence.toFixed(2)} recency=${M.toFixed(2)} (${Math.round(y)}d apart)`,Be={...B,score:U,evidence:K,link_type:v.link_type};v.link_type==="citation"?E.push(Be):v.link_type==="similar"?b.push(Be):v.link_type==="wiki_link"?N.push(Be):S.push(Be)}if(i){let v=Is({sourceSessionId:e,status:"pending",limit:100}),ee=Is({targetSessionId:e,status:"pending",limit:100}),B=[...v,...ee],y=new Set,U=B.filter(K=>y.has(K.id)?!1:(y.add(K.id),!0)),M=lE(c,u,U,a,n,h);for(let K of M)K.link_type==="citation"?E.push(K):K.link_type==="similar"?b.push(K):K.link_type==="wiki_link"?N.push(K):S.push(K)}let x=(v,ee)=>ee.score-v.score;E.sort(x),b.sort(x),S.sort(x),N.sort(x);let Q=cE(u,[{heading:"Parents",refs:m},{heading:"Children",refs:p},{heading:"Citations (approved)",refs:E},{heading:"Similar sessions",refs:b},{heading:"Cousins (skill track + temporal)",refs:S},{heading:"Wiki links (manual)",refs:N}],s);return{origin:u,parents:m,children:p,citations:E,similar:b,cousins:S,wikiLinks:N,bundle:Q.bundle,budgetUsed:Q.budgetUsed,budgetRemaining:Math.max(0,s-Q.budgetUsed),truncated:Q.truncated}}var qh,Vh,Zh,Qh,eE,Tc,yr=C(()=>{"use strict";T();zt();qh=4e3,Vh=2,Zh=30,Qh=.2,eE={citation:1,wiki_link:.9,similar:.7,skill_track:.5,bug_pattern:.4,temporal_proximity:.3};Tc=240});var _l={};Se(_l,{computeAllHealthScores:()=>jr,computeHealthScore:()=>Dr,computeHealthScoreByName:()=>$r});function Kt(e){return Math.max(0,Math.min(1,e))}function Dr(e){let t=_(),s=t.prepare("SELECT id, name FROM projects WHERE id = ?").get(e);if(!s)return null;let n=t.prepare(`SELECT COUNT(*) AS cnt,
727
727
  MAX(started_at) AS latest
728
- FROM sessions WHERE project_id = ?`).get(e),r=n.cnt;if(r===0)return{projectId:e,projectName:s.name,score:0,breakdown:{sessionCount:{raw:0,score:0,weight:.2},recency:{daysSinceLastSession:1/0,score:0,weight:.25},fragmentation:{avgMessages:0,score:0,weight:.15},searchCoverage:{ratio:0,score:0,weight:.2},tagCoverage:{ratio:0,score:0,weight:.2}}};let o=Jt(r/10),i=n.latest?(Date.now()-new Date(n.latest).getTime())/(1e3*60*60*24):90,a=Jt(1-i/90),c=t.prepare(`SELECT AVG(message_count) AS avg_msgs
729
- FROM sessions WHERE project_id = ?`).get(e).avg_msgs??0,u=Jt((c-2)/3),p=t.prepare(`SELECT COUNT(*) AS total,
728
+ FROM sessions WHERE project_id = ?`).get(e),r=n.cnt;if(r===0)return{projectId:e,projectName:s.name,score:0,breakdown:{sessionCount:{raw:0,score:0,weight:.2},recency:{daysSinceLastSession:1/0,score:0,weight:.25},fragmentation:{avgMessages:0,score:0,weight:.15},searchCoverage:{ratio:0,score:0,weight:.2},tagCoverage:{ratio:0,score:0,weight:.2}}};let o=Kt(r/10),i=n.latest?(Date.now()-new Date(n.latest).getTime())/(1e3*60*60*24):90,a=Kt(1-i/90),c=t.prepare(`SELECT AVG(message_count) AS avg_msgs
729
+ FROM sessions WHERE project_id = ?`).get(e).avg_msgs??0,u=Kt((c-2)/3),m=t.prepare(`SELECT COUNT(*) AS total,
730
730
  SUM(CASE WHEN m.content_text IS NOT NULL AND m.content_text != '' THEN 1 ELSE 0 END) AS covered
731
731
  FROM messages m
732
732
  JOIN sessions s ON s.id = m.session_id
733
- WHERE s.project_id = ?`).get(e),m=p.total>0?p.covered/p.total:.5,f=Jt(m),g=t.prepare(`SELECT COUNT(DISTINCT s.id) AS total,
733
+ WHERE s.project_id = ?`).get(e),p=m.total>0?m.covered/m.total:.5,f=Kt(p),g=t.prepare(`SELECT COUNT(DISTINCT s.id) AS total,
734
734
  COUNT(DISTINCT st.session_id) AS tagged
735
735
  FROM sessions s
736
736
  LEFT JOIN session_tags st ON st.session_id = s.id
737
- WHERE s.project_id = ?`).get(e),h=g.total>0?g.tagged/g.total:0,E=Jt(h),b=Math.round((o*.2+a*.25+u*.15+f*.2+E*.2)*100);return{projectId:e,projectName:s.name,score:b,breakdown:{sessionCount:{raw:r,score:o,weight:.2},recency:{daysSinceLastSession:Math.round(i),score:a,weight:.25},fragmentation:{avgMessages:Math.round(c*10)/10,score:u,weight:.15},searchCoverage:{ratio:Math.round(m*100)/100,score:f,weight:.2},tagCoverage:{ratio:Math.round(h*100)/100,score:E,weight:.2}}}}function Nr(e){let s=_().prepare("SELECT id FROM projects WHERE name = ?").get(e);return s?Cr(s.id):null}function Lr(){let t=_().prepare("SELECT id FROM projects ORDER BY name").all(),s=[];for(let n of t){let r=Cr(n.id);r&&s.push(r)}return s}var Or=N(()=>{"use strict";T()});function sd(e,t){return{type:"svg",props:{width:e,height:e,viewBox:"0 0 64 64",style:{display:"flex"},children:[{type:"line",props:{x1:14,y1:16,x2:46,y2:16,stroke:t,strokeWidth:3,strokeLinecap:"round"}},{type:"line",props:{x1:14,y1:24,x2:38,y2:24,stroke:t,strokeWidth:3,strokeLinecap:"round"}},{type:"line",props:{x1:10,y1:32,x2:54,y2:32,stroke:bt,strokeWidth:5,strokeLinecap:"round"}},{type:"line",props:{x1:14,y1:40,x2:42,y2:40,stroke:t,strokeWidth:3,strokeLinecap:"round"}},{type:"line",props:{x1:14,y1:48,x2:36,y2:48,stroke:t,strokeWidth:3,strokeLinecap:"round"}}]}}}function tt(e,t){return{type:"div",props:{style:{display:"flex",alignItems:"center",justifyContent:"space-between",width:"100%"},children:[{type:"div",props:{style:{display:"flex",alignItems:"center",gap:"18px"},children:[sd(72,e.markStroke),{type:"span",props:{style:{fontSize:"36px",fontWeight:700,color:e.wordmarkFg,letterSpacing:"-0.01em"},children:"Claude Recall"}}]}},{type:"span",props:{style:{fontSize:"17px",color:e.wordmarkFg,opacity:.6,textTransform:"uppercase",letterSpacing:"0.18em",fontWeight:600},children:t}}]}}}function st(e){return{type:"div",props:{style:{display:"flex",alignItems:"center",justifyContent:"space-between",width:"100%"},children:[{type:"div",props:{style:{display:"flex",alignItems:"center",gap:"14px"},children:[sd(52,e.markStroke),{type:"span",props:{style:{fontSize:"24px",fontWeight:700,color:e.wordmarkFg},children:"clauderecall.com"}}]}},{type:"span",props:{style:{fontSize:"20px",color:e.wordmarkFg,opacity:.7,fontWeight:500},children:"local memory for Claude Code"}}]}}}function MS(e){return e>=1e9?`${(e/1e9).toFixed(2).replace(/\.?0+$/,"")}B`:e>=1e6?`${(e/1e6).toFixed(2).replace(/\.?0+$/,"")}M`:e>=1e3?`${(e/1e3).toFixed(1).replace(/\.0$/,"")}k`:String(e)}function DS(e){return e.toLocaleString("en-US")}function nt(e){return e<1e3?String(e):`${MS(e)} (${DS(e)})`}function rt(e){return new Date(e).toLocaleDateString("en-US",{month:"long",day:"numeric",year:"numeric"})}var bt,zt=N(()=>{"use strict";bt="#f97316"});var rd={};Ee(rd,{render:()=>PS});function Ws(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:Yt,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:Xs,textTransform:"uppercase",letterSpacing:"0.16em"},children:t}}]}}}function PS(e){let s=[rt(e.sessionDate)];e.durationLabel&&s.push(e.durationLabel);let n=s.join(" \xB7 "),r=e.costDollars??"$\u2014",o=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${nt(e.cachedTokens)} cached`:null,i=[tt(nd,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:Yt,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"20px",color:Xs},children:n}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",padding:"32px 0"},children:[{type:"span",props:{style:{fontSize:"180px",fontWeight:700,color:bt,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:r}},{type:"span",props:{style:{marginTop:"16px",fontSize:"16px",color:Xs,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:600},children:"session cost"}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:jS}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[Ws(String(e.messageCount),"msgs"),Ws(String(e.filesReferenced),"files"),Ws(String(e.toolCallCount),"tools"),Ws(e.model??"\u2014","model")]}}];return o&&i.push({type:"div",props:{style:{fontSize:"14px",color:Xs,fontFamily:"JetBrains Mono",opacity:.7},children:o}}),e.verdict&&i.push({type:"div",props:{style:{display:"flex",fontSize:"24px",fontStyle:"italic",color:Yt,borderLeft:`3px solid ${bt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),i.push({type:"div",props:{style:{display:"flex",flex:1}}}),i.push(st(nd)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:$S,padding:"64px 72px",fontFamily:"Inter",gap:"28px"},children:i}}}var $S,Yt,Xs,jS,nd,od=N(()=>{"use strict";zt();$S="#1a1b1e",Yt="#e7e9ee",Xs="#8b9098",jS="#2a2c33",nd={markStroke:Yt,wordmarkFg:Yt}});var ad={};Ee(ad,{render:()=>BS});function Js(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:Kt,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:Gs,fontFamily:"JetBrains Mono",textTransform:"lowercase"},children:`// ${t}`}}]}}}function BS(e){let t=[rt(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),s=e.costDollars??"$\u2014",n=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`# ${nt(e.cachedTokens)} tokens cache-replayed (free)`:null,r=[tt(id,"recall.cli/share"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"6px"},children:[{type:"div",props:{style:{fontSize:"18px",color:Pr,fontFamily:"JetBrains Mono"},children:"$ recall share --session"}},{type:"div",props:{style:{fontSize:"40px",fontWeight:700,color:Kt,lineHeight:1.15,wordBreak:"break-word",fontFamily:"JetBrains Mono"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"18px",color:Gs,fontFamily:"JetBrains Mono"},children:t}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"flex-start",padding:"12px 0"},children:[{type:"span",props:{style:{fontSize:"20px",color:Gs,fontFamily:"JetBrains Mono"},children:"> total_cost:"}},{type:"span",props:{style:{fontSize:"180px",fontWeight:700,color:Pr,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:s}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:US}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[Js(String(e.messageCount),"msgs"),Js(String(e.filesReferenced),"files"),Js(String(e.toolCallCount),"tools"),Js(e.model??"\u2014","model")]}}];return n&&r.push({type:"div",props:{style:{fontSize:"14px",color:Gs,fontFamily:"JetBrains Mono",opacity:.7},children:n}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"22px",color:Kt,fontFamily:"JetBrains Mono",borderLeft:`3px solid ${Pr}`,paddingLeft:"20px",marginTop:"8px"},children:`// ${e.verdict}`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(st(id)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:FS,padding:"64px 72px",fontFamily:"Inter",gap:"28px"},children:r}}}var FS,Kt,Gs,US,Pr,id,cd=N(()=>{"use strict";zt();FS="#0d0d0f",Kt="#e1e7ee",Gs="#6b7480",US="#1f2229",Pr="#7ee787",id={markStroke:Kt,wordmarkFg:Kt}});var dd={};Ee(dd,{render:()=>WS});function zs(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:St,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:Ys,textTransform:"uppercase",letterSpacing:"0.16em",fontWeight:600},children:t}}]}}}function WS(e){let t=[rt(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),s=e.costDollars??"$\u2014",n=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${nt(e.cachedTokens)} cached`:null,r=[tt(ld,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:St,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"20px",color:Ys},children:t}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",padding:"32px 0"},children:[{type:"span",props:{style:{fontSize:"180px",fontWeight:700,color:St,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:s}},{type:"span",props:{style:{marginTop:"16px",fontSize:"16px",color:Ys,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:600},children:"session cost"}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:HS}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[zs(String(e.messageCount),"msgs"),zs(String(e.filesReferenced),"files"),zs(String(e.toolCallCount),"tools"),zs(e.model??"\u2014","model")]}}];return n&&r.push({type:"div",props:{style:{fontSize:"14px",color:Ys,fontFamily:"JetBrains Mono",opacity:.85},children:n}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"24px",fontStyle:"italic",color:St,borderLeft:`3px solid ${St}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(st(ld)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundImage:"linear-gradient(135deg, #b1370f 0%, #f97316 55%, #fbbf24 100%)",padding:"64px 72px",fontFamily:"Inter",gap:"28px"},children:r}}}var St,Ys,HS,ld,ud=N(()=>{"use strict";zt();St="#ffffff",Ys="rgba(255,255,255,0.7)",HS="rgba(255,255,255,0.18)",ld={markStroke:St,wordmarkFg:St}});var md={};Ee(md,{render:()=>YS});function Ks(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:800,color:xt,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:qt,textTransform:"uppercase",letterSpacing:"0.16em",fontWeight:600},children:t}}]}}}function zS(e){let t=e.reduce((s,n)=>s+n.value,0)||1;return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{display:"flex",width:"100%",height:"10px",borderRadius:"5px",backgroundColor:GS,overflow:"hidden"},children:e.map(s=>({type:"div",props:{style:{display:"flex",width:`${s.value/t*100}%`,height:"100%",backgroundColor:s.color}}}))}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",fontSize:"12px",color:qt,fontWeight:600,textTransform:"uppercase",letterSpacing:"0.14em"},children:e.map(s=>({type:"span",props:{style:{display:"flex"},children:`${s.label} \xB7 ${s.value}`}}))}}]}}}function YS(e){let t=[rt(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),s=e.costDollars??"$\u2014",n=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${nt(e.cachedTokens)} cached`:null,r=[tt(pd,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"40px",fontWeight:700,color:xt,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"18px",color:qt},children:t}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"flex-start",padding:"8px 0"},children:[{type:"span",props:{style:{fontSize:"14px",color:qt,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:700},children:"session cost"}},{type:"span",props:{style:{fontSize:"180px",fontWeight:800,color:xt,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:s}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:JS}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[Ks(String(e.messageCount),"msgs"),Ks(String(e.filesReferenced),"files"),Ks(String(e.toolCallCount),"tools"),Ks(e.model??"\u2014","model")]}},zS([{value:e.messageCount,color:bt,label:"msgs"},{value:e.filesReferenced,color:"#0a0a0a",label:"files"},{value:e.toolCallCount,color:"#5a6068",label:"tools"}])];return n&&r.push({type:"div",props:{style:{fontSize:"14px",color:qt,fontFamily:"JetBrains Mono",opacity:.85},children:n}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"22px",fontStyle:"italic",color:xt,borderLeft:`3px solid ${bt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(st(pd)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:XS,padding:"64px 72px",fontFamily:"Inter",gap:"24px"},children:r}}}var XS,xt,qt,JS,GS,pd,gd=N(()=>{"use strict";zt();XS="#f6f7f9",xt="#0a0a0a",qt="#5a6068",JS="#e3e6eb",GS="#dde1e7",pd={markStroke:xt,wordmarkFg:xt}});var fd={};Ee(fd,{render:()=>VS});function Fr(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"8px",flex:1},children:[{type:"div",props:{style:{fontSize:"52px",fontWeight:700,color:qs},children:t}},{type:"div",props:{style:{fontSize:"16px",color:Ct,textTransform:"uppercase",letterSpacing:"2px"},children:e}}]}}}function Ur(e,t){return{type:"div",props:{style:{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"16px 24px",backgroundColor:Br,borderRadius:"12px"},children:[{type:"span",props:{style:{fontSize:"18px",color:Ct},children:e}},{type:"span",props:{style:{fontSize:"20px",fontWeight:700,color:qs},children:t}}]}}}function VS(e){let t=Math.round(e.healthScore),s=[{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"16px",color:Ct,textTransform:"uppercase",letterSpacing:"6px"},children:"YOUR MONTH IN CODE"}},{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:qs},children:e.month}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"12px",backgroundColor:Br,borderRadius:"16px",padding:"28px",border:`1px solid ${kt}40`},children:[{type:"div",props:{style:{fontSize:"16px",color:qS,textTransform:"uppercase",letterSpacing:"2px"},children:"You are a"}},{type:"div",props:{style:{fontSize:"36px",fontWeight:700,color:kt},children:e.archetype}}]}},{type:"div",props:{style:{display:"flex",gap:"16px",width:"100%"},children:[Fr("Recalls",String(e.totalRecalls)),Fr("Tokens piped",e.totalTokensPiped>999999?`${(e.totalTokensPiped/1e6).toFixed(1)}M`:e.totalTokensPiped.toLocaleString()),Fr("Sessions",String(e.sessionsIndexed))]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px",width:"100%"},children:[{type:"div",props:{style:{fontSize:"14px",color:Ct,textTransform:"uppercase",letterSpacing:"2px",marginBottom:"4px"},children:"Highlights"}},Ur("Most recalled",e.mostRecalledSession),Ur("Biggest recall",`${e.biggestRecallTokens.toLocaleString()} tokens`),Ur("Peak hours",e.mostActiveHours)]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"12px"},children:[{type:"div",props:{style:{width:"100px",height:"100px",borderRadius:"50%",border:`6px solid ${kt}`,display:"flex",alignItems:"center",justifyContent:"center"},children:{type:"span",props:{style:{fontSize:"32px",fontWeight:700,color:kt},children:`${t}`}}}},{type:"div",props:{style:{fontSize:"14px",color:Ct,textTransform:"uppercase",letterSpacing:"2px"},children:"Memory health"}}]}}];return e.verdict&&s.push({type:"div",props:{style:{backgroundColor:Br,borderLeft:`3px solid ${kt}`,borderRadius:"8px",padding:"20px 24px",fontSize:"20px",color:qs,fontStyle:"italic"},children:`"${e.verdict}"`}}),s.push({type:"div",props:{style:{display:"flex",alignItems:"center",justifyContent:"center",gap:"12px",marginTop:"auto"},children:[{type:"span",props:{style:{fontSize:"22px",fontWeight:700,color:kt},children:"Claude Recall"}},{type:"span",props:{style:{fontSize:"18px",color:Ct},children:"clauderecall.com"}}]}}),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:KS,padding:"72px 64px",fontFamily:"Inter",gap:"36px"},children:s}}}var KS,Br,qs,Ct,kt,qS,_d=N(()=>{"use strict";KS="#0b0c0f",Br="#15171c",qs="#e7e9ee",Ct="#8b9098",kt="#f97316",qS="#fb923c"});var Gr,Od,G,w,Z,ve,Ad,Id,vd,Md,zr,Yr,ot=N(()=>{"use strict";Gr=[String.raw` ___ _ _ _ _ ___ ___ ___ ___ ___ _ _ _ `,String.raw` / __| | /_\ | | | | \| __| | _ \ __/ __| /_\ | | | | `,String.raw`| (__| |__ / _ \| |_| | |) | _| | / _| (__ / _ \| |__| |__ `,String.raw` \___|____/_/ \_\\___/|___/|___| |_|_\___\___/_/ \_\____|____|`],Od=Gr[0]?.length??64,G="#f97316",w="#8b9098",Z="#10b981",ve="#f59e0b",Ad="#60a5fa",Id="#34d399",vd="#c084fc",Md="CLAUDE RECALL",zr=100,Yr=30});import{useEffect as Ny,useState as Ly}from"react";import{Box as Dd,Text as ue}from"ink";import{createRequire as Oy}from"node:module";import{existsSync as Ay}from"node:fs";import{jsx as re,jsxs as jd}from"react/jsx-runtime";function $d({cols:e}){let[t,s]=Ly(My);Ny(()=>{let r=!1,o=q(),i=0,a=0;if(Ay(te))try{let c=_().prepare(`SELECT
737
+ WHERE s.project_id = ?`).get(e),h=g.total>0?g.tagged/g.total:0,E=Kt(h),b=Math.round((o*.2+a*.25+u*.15+f*.2+E*.2)*100);return{projectId:e,projectName:s.name,score:b,breakdown:{sessionCount:{raw:r,score:o,weight:.2},recency:{daysSinceLastSession:Math.round(i),score:a,weight:.25},fragmentation:{avgMessages:Math.round(c*10)/10,score:u,weight:.15},searchCoverage:{ratio:Math.round(p*100)/100,score:f,weight:.2},tagCoverage:{ratio:Math.round(h*100)/100,score:E,weight:.2}}}}function $r(e){let s=_().prepare("SELECT id FROM projects WHERE name = ?").get(e);return s?Dr(s.id):null}function jr(){let t=_().prepare("SELECT id FROM projects ORDER BY name").all(),s=[];for(let n of t){let r=Dr(n.id);r&&s.push(r)}return s}var Pr=C(()=>{"use strict";T()});function Nd(e,t){return{type:"svg",props:{width:e,height:e,viewBox:"0 0 64 64",style:{display:"flex"},children:[{type:"line",props:{x1:14,y1:16,x2:46,y2:16,stroke:t,strokeWidth:3,strokeLinecap:"round"}},{type:"line",props:{x1:14,y1:24,x2:38,y2:24,stroke:t,strokeWidth:3,strokeLinecap:"round"}},{type:"line",props:{x1:10,y1:32,x2:54,y2:32,stroke:yt,strokeWidth:5,strokeLinecap:"round"}},{type:"line",props:{x1:14,y1:40,x2:42,y2:40,stroke:t,strokeWidth:3,strokeLinecap:"round"}},{type:"line",props:{x1:14,y1:48,x2:36,y2:48,stroke:t,strokeWidth:3,strokeLinecap:"round"}}]}}}function st(e,t){return{type:"div",props:{style:{display:"flex",alignItems:"center",justifyContent:"space-between",width:"100%"},children:[{type:"div",props:{style:{display:"flex",alignItems:"center",gap:"18px"},children:[Nd(72,e.markStroke),{type:"span",props:{style:{fontSize:"36px",fontWeight:700,color:e.wordmarkFg,letterSpacing:"-0.01em"},children:"Claude Recall"}}]}},{type:"span",props:{style:{fontSize:"17px",color:e.wordmarkFg,opacity:.6,textTransform:"uppercase",letterSpacing:"0.18em",fontWeight:600},children:t}}]}}}function nt(e){return{type:"div",props:{style:{display:"flex",alignItems:"center",justifyContent:"space-between",width:"100%"},children:[{type:"div",props:{style:{display:"flex",alignItems:"center",gap:"14px"},children:[Nd(52,e.markStroke),{type:"span",props:{style:{fontSize:"24px",fontWeight:700,color:e.wordmarkFg},children:"clauderecall.com"}}]}},{type:"span",props:{style:{fontSize:"20px",color:e.wordmarkFg,opacity:.7,fontWeight:500},children:"local memory for Claude Code"}}]}}}function by(e){return e>=1e9?`${(e/1e9).toFixed(2).replace(/\.?0+$/,"")}B`:e>=1e6?`${(e/1e6).toFixed(2).replace(/\.?0+$/,"")}M`:e>=1e3?`${(e/1e3).toFixed(1).replace(/\.0$/,"")}k`:String(e)}function Sy(e){return e.toLocaleString("en-US")}function rt(e){return e<1e3?String(e):`${by(e)} (${Sy(e)})`}function ot(e){return new Date(e).toLocaleDateString("en-US",{month:"long",day:"numeric",year:"numeric"})}var yt,Vt=C(()=>{"use strict";yt="#f97316"});var Ld={};Se(Ld,{render:()=>wy});function Zs(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:Zt,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:Qs,textTransform:"uppercase",letterSpacing:"0.16em"},children:t}}]}}}function wy(e){let s=[ot(e.sessionDate)];e.durationLabel&&s.push(e.durationLabel);let n=s.join(" \xB7 "),r=e.costDollars??"$\u2014",o=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${rt(e.cachedTokens)} cached`:null,i=[st(Cd,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:Zt,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"20px",color:Qs},children:n}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",padding:"32px 0"},children:[{type:"span",props:{style:{fontSize:"180px",fontWeight:700,color:yt,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:r}},{type:"span",props:{style:{marginTop:"16px",fontSize:"16px",color:Qs,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:600},children:"session cost"}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:Ty}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[Zs(String(e.messageCount),"msgs"),Zs(String(e.filesReferenced),"files"),Zs(String(e.toolCallCount),"tools"),Zs(e.model??"\u2014","model")]}}];return o&&i.push({type:"div",props:{style:{fontSize:"14px",color:Qs,fontFamily:"JetBrains Mono",opacity:.7},children:o}}),e.verdict&&i.push({type:"div",props:{style:{display:"flex",fontSize:"24px",fontStyle:"italic",color:Zt,borderLeft:`3px solid ${yt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),i.push({type:"div",props:{style:{display:"flex",flex:1}}}),i.push(nt(Cd)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:yy,padding:"64px 72px",fontFamily:"Inter",gap:"28px"},children:i}}}var yy,Zt,Qs,Ty,Cd,Od=C(()=>{"use strict";Vt();yy="#1a1b1e",Zt="#e7e9ee",Qs="#8b9098",Ty="#2a2c33",Cd={markStroke:Zt,wordmarkFg:Zt}});var Id={};Se(Id,{render:()=>ky});function en(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:Qt,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:tn,fontFamily:"JetBrains Mono",textTransform:"lowercase"},children:`// ${t}`}}]}}}function ky(e){let t=[ot(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),s=e.costDollars??"$\u2014",n=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`# ${rt(e.cachedTokens)} tokens cache-replayed (free)`:null,r=[st(Ad,"recall.cli/share"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"6px"},children:[{type:"div",props:{style:{fontSize:"18px",color:qr,fontFamily:"JetBrains Mono"},children:"$ recall share --session"}},{type:"div",props:{style:{fontSize:"40px",fontWeight:700,color:Qt,lineHeight:1.15,wordBreak:"break-word",fontFamily:"JetBrains Mono"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"18px",color:tn,fontFamily:"JetBrains Mono"},children:t}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"flex-start",padding:"12px 0"},children:[{type:"span",props:{style:{fontSize:"20px",color:tn,fontFamily:"JetBrains Mono"},children:"> total_cost:"}},{type:"span",props:{style:{fontSize:"180px",fontWeight:700,color:qr,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:s}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:xy}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[en(String(e.messageCount),"msgs"),en(String(e.filesReferenced),"files"),en(String(e.toolCallCount),"tools"),en(e.model??"\u2014","model")]}}];return n&&r.push({type:"div",props:{style:{fontSize:"14px",color:tn,fontFamily:"JetBrains Mono",opacity:.7},children:n}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"22px",color:Qt,fontFamily:"JetBrains Mono",borderLeft:`3px solid ${qr}`,paddingLeft:"20px",marginTop:"8px"},children:`// ${e.verdict}`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(nt(Ad)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:Ry,padding:"64px 72px",fontFamily:"Inter",gap:"28px"},children:r}}}var Ry,Qt,tn,xy,qr,Ad,vd=C(()=>{"use strict";Vt();Ry="#0d0d0f",Qt="#e1e7ee",tn="#6b7480",xy="#1f2229",qr="#7ee787",Ad={markStroke:Qt,wordmarkFg:Qt}});var Dd={};Se(Dd,{render:()=>Cy});function sn(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:Tt,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:nn,textTransform:"uppercase",letterSpacing:"0.16em",fontWeight:600},children:t}}]}}}function Cy(e){let t=[ot(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),s=e.costDollars??"$\u2014",n=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${rt(e.cachedTokens)} cached`:null,r=[st(Md,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:Tt,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"20px",color:nn},children:t}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",padding:"32px 0"},children:[{type:"span",props:{style:{fontSize:"180px",fontWeight:700,color:Tt,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:s}},{type:"span",props:{style:{marginTop:"16px",fontSize:"16px",color:nn,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:600},children:"session cost"}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:Ny}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[sn(String(e.messageCount),"msgs"),sn(String(e.filesReferenced),"files"),sn(String(e.toolCallCount),"tools"),sn(e.model??"\u2014","model")]}}];return n&&r.push({type:"div",props:{style:{fontSize:"14px",color:nn,fontFamily:"JetBrains Mono",opacity:.85},children:n}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"24px",fontStyle:"italic",color:Tt,borderLeft:`3px solid ${Tt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(nt(Md)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundImage:"linear-gradient(135deg, #b1370f 0%, #f97316 55%, #fbbf24 100%)",padding:"64px 72px",fontFamily:"Inter",gap:"28px"},children:r}}}var Tt,nn,Ny,Md,$d=C(()=>{"use strict";Vt();Tt="#ffffff",nn="rgba(255,255,255,0.7)",Ny="rgba(255,255,255,0.18)",Md={markStroke:Tt,wordmarkFg:Tt}});var Pd={};Se(Pd,{render:()=>vy});function rn(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:800,color:Lt,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:es,textTransform:"uppercase",letterSpacing:"0.16em",fontWeight:600},children:t}}]}}}function Iy(e){let t=e.reduce((s,n)=>s+n.value,0)||1;return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{display:"flex",width:"100%",height:"10px",borderRadius:"5px",backgroundColor:Ay,overflow:"hidden"},children:e.map(s=>({type:"div",props:{style:{display:"flex",width:`${s.value/t*100}%`,height:"100%",backgroundColor:s.color}}}))}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",fontSize:"12px",color:es,fontWeight:600,textTransform:"uppercase",letterSpacing:"0.14em"},children:e.map(s=>({type:"span",props:{style:{display:"flex"},children:`${s.label} \xB7 ${s.value}`}}))}}]}}}function vy(e){let t=[ot(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),s=e.costDollars??"$\u2014",n=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${rt(e.cachedTokens)} cached`:null,r=[st(jd,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"40px",fontWeight:700,color:Lt,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"18px",color:es},children:t}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"flex-start",padding:"8px 0"},children:[{type:"span",props:{style:{fontSize:"14px",color:es,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:700},children:"session cost"}},{type:"span",props:{style:{fontSize:"180px",fontWeight:800,color:Lt,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:s}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:Oy}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[rn(String(e.messageCount),"msgs"),rn(String(e.filesReferenced),"files"),rn(String(e.toolCallCount),"tools"),rn(e.model??"\u2014","model")]}},Iy([{value:e.messageCount,color:yt,label:"msgs"},{value:e.filesReferenced,color:"#0a0a0a",label:"files"},{value:e.toolCallCount,color:"#5a6068",label:"tools"}])];return n&&r.push({type:"div",props:{style:{fontSize:"14px",color:es,fontFamily:"JetBrains Mono",opacity:.85},children:n}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"22px",fontStyle:"italic",color:Lt,borderLeft:`3px solid ${yt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(nt(jd)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:Ly,padding:"64px 72px",fontFamily:"Inter",gap:"24px"},children:r}}}var Ly,Lt,es,Oy,Ay,jd,Fd=C(()=>{"use strict";Vt();Ly="#f6f7f9",Lt="#0a0a0a",es="#5a6068",Oy="#e3e6eb",Ay="#dde1e7",jd={markStroke:Lt,wordmarkFg:Lt}});var Ud={};Se(Ud,{render:()=>$y});function Vr(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"8px",flex:1},children:[{type:"div",props:{style:{fontSize:"52px",fontWeight:700,color:on},children:t}},{type:"div",props:{style:{fontSize:"16px",color:At,textTransform:"uppercase",letterSpacing:"2px"},children:e}}]}}}function Zr(e,t){return{type:"div",props:{style:{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"16px 24px",backgroundColor:Qr,borderRadius:"12px"},children:[{type:"span",props:{style:{fontSize:"18px",color:At},children:e}},{type:"span",props:{style:{fontSize:"20px",fontWeight:700,color:on},children:t}}]}}}function $y(e){let t=Math.round(e.healthScore),s=[{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"16px",color:At,textTransform:"uppercase",letterSpacing:"6px"},children:"YOUR MONTH IN CODE"}},{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:on},children:e.month}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"12px",backgroundColor:Qr,borderRadius:"16px",padding:"28px",border:`1px solid ${Ot}40`},children:[{type:"div",props:{style:{fontSize:"16px",color:Dy,textTransform:"uppercase",letterSpacing:"2px"},children:"You are a"}},{type:"div",props:{style:{fontSize:"36px",fontWeight:700,color:Ot},children:e.archetype}}]}},{type:"div",props:{style:{display:"flex",gap:"16px",width:"100%"},children:[Vr("Recalls",String(e.totalRecalls)),Vr("Tokens piped",e.totalTokensPiped>999999?`${(e.totalTokensPiped/1e6).toFixed(1)}M`:e.totalTokensPiped.toLocaleString()),Vr("Sessions",String(e.sessionsIndexed))]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px",width:"100%"},children:[{type:"div",props:{style:{fontSize:"14px",color:At,textTransform:"uppercase",letterSpacing:"2px",marginBottom:"4px"},children:"Highlights"}},Zr("Most recalled",e.mostRecalledSession),Zr("Biggest recall",`${e.biggestRecallTokens.toLocaleString()} tokens`),Zr("Peak hours",e.mostActiveHours)]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"12px"},children:[{type:"div",props:{style:{width:"100px",height:"100px",borderRadius:"50%",border:`6px solid ${Ot}`,display:"flex",alignItems:"center",justifyContent:"center"},children:{type:"span",props:{style:{fontSize:"32px",fontWeight:700,color:Ot},children:`${t}`}}}},{type:"div",props:{style:{fontSize:"14px",color:At,textTransform:"uppercase",letterSpacing:"2px"},children:"Memory health"}}]}}];return e.verdict&&s.push({type:"div",props:{style:{backgroundColor:Qr,borderLeft:`3px solid ${Ot}`,borderRadius:"8px",padding:"20px 24px",fontSize:"20px",color:on,fontStyle:"italic"},children:`"${e.verdict}"`}}),s.push({type:"div",props:{style:{display:"flex",alignItems:"center",justifyContent:"center",gap:"12px",marginTop:"auto"},children:[{type:"span",props:{style:{fontSize:"22px",fontWeight:700,color:Ot},children:"Claude Recall"}},{type:"span",props:{style:{fontSize:"18px",color:At},children:"clauderecall.com"}}]}}),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:My,padding:"72px 64px",fontFamily:"Inter",gap:"36px"},children:s}}}var My,Qr,on,At,Ot,Dy,Bd=C(()=>{"use strict";My="#0b0c0f",Qr="#15171c",on="#e7e9ee",At="#8b9098",Ot="#f97316",Dy="#fb923c"});var ro,tu,G,w,Z,Me,su,nu,ru,ou,oo,io,it=C(()=>{"use strict";ro=[String.raw` ___ _ _ _ _ ___ ___ ___ ___ ___ _ _ _ `,String.raw` / __| | /_\ | | | | \| __| | _ \ __/ __| /_\ | | | | `,String.raw`| (__| |__ / _ \| |_| | |) | _| | / _| (__ / _ \| |__| |__ `,String.raw` \___|____/_/ \_\\___/|___/|___| |_|_\___\___/_/ \_\____|____|`],tu=ro[0]?.length??64,G="#f97316",w="#8b9098",Z="#10b981",Me="#f59e0b",su="#60a5fa",nu="#34d399",ru="#c084fc",ou="CLAUDE RECALL",oo=100,io=30});import{useEffect as pT,useState as gT}from"react";import{Box as iu,Text as me}from"ink";import{createRequire as fT}from"node:module";import{existsSync as _T}from"node:fs";import{jsx as re,jsxs as cu}from"react/jsx-runtime";function au({cols:e}){let[t,s]=gT(bT);pT(()=>{let r=!1,o=q(),i=0,a=0;if(_T(te))try{let c=_().prepare(`SELECT
738
738
  (SELECT COUNT(*) FROM sessions) AS sessions,
739
- (SELECT COUNT(*) FROM projects) AS projects`).get();i=c.sessions,a=c.projects}catch{}return s(l=>({...l,daemon:o,sessions:i,projects:a})),be().then(l=>{r||s(c=>({...c,tier:l.tier}))}).catch(()=>{}),()=>{r=!0}},[]);let n=e>=Od+2;return jd(Dd,{flexDirection:"column",children:[n?Gr.map((r,o)=>re(ue,{color:G,bold:!0,children:r},o)):re(ue,{color:G,bold:!0,children:Md}),re(Dy,{state:t})]})}function Dy({state:e}){let t=re(ue,{color:w,children:" \xB7 "});return jd(Dd,{children:[re(ue,{color:w,children:"v"}),re(ue,{color:G,children:vy}),t,re(ue,{color:w,children:"daemon: "}),e.daemon?re(ue,{color:Z,children:`running 127.0.0.1:${e.daemon.port}`}):re(ue,{color:ve,children:"stopped"}),t,re(ue,{color:w,children:"sessions: "}),re(ue,{color:G,children:e.sessions}),e.projects>0?re(ue,{color:w,children:` across ${e.projects} ${e.projects===1?"project":"projects"}`}):null,t,re(ue,{color:w,children:"license: "}),e.tier==="pro"?re(ue,{color:Z,children:"Pro"}):re(ue,{color:w,children:"Free"})]})}var Iy,vy,My,Pd=N(()=>{"use strict";He();j();T();Se();ot();Iy=Oy(import.meta.url),vy=Iy("../../../package.json").version,My={daemon:null,sessions:0,projects:0,tier:"free"}});import{Box as ze,Text as oe}from"ink";import{jsx as z,jsxs as Qs}from"react/jsx-runtime";function jy(e,t,s){if(t<=s)return{start:0,end:t};let n=e-Math.floor(s/2);return n<0&&(n=0),n+s>t&&(n=t-s),{start:n,end:n+s}}function it(e,t){if(t<=0)return"";let s=e.replace(/\s+/g," ").trim();return s.length<=t?s:s.slice(0,Math.max(0,t-1))+"\u2026"}function Fd({sessions:e,total:t,selected:s,width:n,height:r,loading:o,dbExists:i,filter:a,sortMode:l,groupByProject:c}){let u=Math.max(20,n-2),f=Math.max(1,r-1-1-2),g=jy(s,e.length,f),h=e.slice(g.start,g.end);if(!i)return Qs(ze,{flexDirection:"column",width:n,height:r,borderStyle:"round",borderColor:w,children:[z(oe,{color:G,bold:!0,children:" Sessions "}),z(ze,{paddingX:1,paddingY:1,children:z(oe,{color:w,wrap:"wrap",children:"No sessions indexed yet. Quit (q) and run `recall index` first."})})]});let S=[$y[l],c?"grouped":""].filter(Boolean).join(" \xB7 "),C=o?" Sessions \xB7 loading\u2026 ":a?` Sessions \xB7 ${e.length} of ${t} match "${it(a,18)}" \xB7 ${S} `:` Sessions \xB7 ${e.length} of ${t} \xB7 ${S} `,x=null;return c&&g.start>0&&(x=e[g.start-1]?.project_name??null),Qs(ze,{flexDirection:"column",width:n,height:r,borderStyle:"round",borderColor:w,children:[z(ze,{width:u+2,paddingLeft:1,children:z(oe,{color:G,bold:!0,children:it(C,u)})}),z(ze,{flexDirection:"column",flexGrow:1,paddingX:1,children:h.length===0?z(oe,{color:w,children:a?"no matches.":"no sessions."}):h.flatMap((L,Q)=>{let I=g.start+Q,ee=I===s,B=[];return c&&L.project_name!==x&&(B.push(z(Fy,{project:L.project_name,width:u},`hdr-${L.project_name}-${I}`)),x=L.project_name),B.push(z(Py,{session:L,width:u,isSelected:ee,indented:c},L.id)),B})}),z(ze,{width:u+2,paddingLeft:1,children:z(oe,{color:w,children:e.length>0?it(` ${s+1} / ${e.length}${g.end<e.length?" \xB7 scroll for more":""} `,u):""})})]})}function Py({session:e,width:t,isSelected:s,indented:n}){let r=W(e.started_at)||"",o=n?" ":"",i=s?"\u258C ":" ";if(n){let f=e.alias||e.auto_title||e.first_user_message||"(no title)",g=Math.min(14,Math.max(6,Math.floor(t*.25))),h=Math.max(10,t-i.length-o.length-g-1),E=it(f,h),b=it(r,g),S=Math.max(1,t-i.length-o.length-E.length-b.length);return Qs(ze,{children:[z(oe,{children:o}),z(oe,{color:s?G:w,bold:s,children:i}),z(oe,{color:s?G:"#fefce8",bold:s,children:E}),z(oe,{children:" ".repeat(S)}),z(oe,{color:w,children:b})]})}let a=e.project_name||"?",l=Math.min(28,Math.floor(t*.7)),c=Math.min(14,t-l-i.length-1),u=it(a,l),p=it(r,c),m=Math.max(1,t-i.length-u.length-p.length);return Qs(ze,{children:[z(oe,{color:s?G:w,bold:s,children:i}),z(oe,{color:s?G:"#67e8f9",bold:s,children:u}),z(oe,{children:" ".repeat(m)}),z(oe,{color:w,children:p})]})}function Fy({project:e,width:t}){return z(ze,{children:z(oe,{color:"#67e8f9",bold:!0,children:it(`\u25BE ${e}`,t)})})}var $y,Ud=N(()=>{"use strict";M();ot();$y={recent:"recent",longest:"longest",busiest:"busiest project"}});import{useEffect as Uy,useState as Kr}from"react";function Bd(e,t,s){let n=s?"":"AND is_sidechain = 0";return e.prepare(`SELECT uuid, role, type, timestamp, content_text
739
+ (SELECT COUNT(*) FROM projects) AS projects`).get();i=c.sessions,a=c.projects}catch{}return s(l=>({...l,daemon:o,sessions:i,projects:a})),ye().then(l=>{r||s(c=>({...c,tier:l.tier}))}).catch(()=>{}),()=>{r=!0}},[]);let n=e>=tu+2;return cu(iu,{flexDirection:"column",children:[n?ro.map((r,o)=>re(me,{color:G,bold:!0,children:r},o)):re(me,{color:G,bold:!0,children:ou}),re(ST,{state:t})]})}function ST({state:e}){let t=re(me,{color:w,children:" \xB7 "});return cu(iu,{children:[re(me,{color:w,children:"v"}),re(me,{color:G,children:ET}),t,re(me,{color:w,children:"daemon: "}),e.daemon?re(me,{color:Z,children:`running 127.0.0.1:${e.daemon.port}`}):re(me,{color:Me,children:"stopped"}),t,re(me,{color:w,children:"sessions: "}),re(me,{color:G,children:e.sessions}),e.projects>0?re(me,{color:w,children:` across ${e.projects} ${e.projects===1?"project":"projects"}`}):null,t,re(me,{color:w,children:"license: "}),e.tier==="pro"?re(me,{color:Z,children:"Pro"}):re(me,{color:w,children:"Free"})]})}var hT,ET,bT,lu=C(()=>{"use strict";We();j();T();fe();it();hT=fT(import.meta.url),ET=hT("../../../package.json").version,bT={daemon:null,sessions:0,projects:0,tier:"free"}});import{Box as Ye,Text as oe}from"ink";import{jsx as z,jsxs as ln}from"react/jsx-runtime";function TT(e,t,s){if(t<=s)return{start:0,end:t};let n=e-Math.floor(s/2);return n<0&&(n=0),n+s>t&&(n=t-s),{start:n,end:n+s}}function at(e,t){if(t<=0)return"";let s=e.replace(/\s+/g," ").trim();return s.length<=t?s:s.slice(0,Math.max(0,t-1))+"\u2026"}function du({sessions:e,total:t,selected:s,width:n,height:r,loading:o,dbExists:i,filter:a,sortMode:l,groupByProject:c}){let u=Math.max(20,n-2),f=Math.max(1,r-1-1-2),g=TT(s,e.length,f),h=e.slice(g.start,g.end);if(!i)return ln(Ye,{flexDirection:"column",width:n,height:r,borderStyle:"round",borderColor:w,children:[z(oe,{color:G,bold:!0,children:" Sessions "}),z(Ye,{paddingX:1,paddingY:1,children:z(oe,{color:w,wrap:"wrap",children:"No sessions indexed yet. Quit (q) and run `recall index` first."})})]});let S=[yT[l],c?"grouped":""].filter(Boolean).join(" \xB7 "),N=o?" Sessions \xB7 loading\u2026 ":a?` Sessions \xB7 ${e.length} of ${t} match "${at(a,18)}" \xB7 ${S} `:` Sessions \xB7 ${e.length} of ${t} \xB7 ${S} `,x=null;return c&&g.start>0&&(x=e[g.start-1]?.project_name??null),ln(Ye,{flexDirection:"column",width:n,height:r,borderStyle:"round",borderColor:w,children:[z(Ye,{width:u+2,paddingLeft:1,children:z(oe,{color:G,bold:!0,children:at(N,u)})}),z(Ye,{flexDirection:"column",flexGrow:1,paddingX:1,children:h.length===0?z(oe,{color:w,children:a?"no matches.":"no sessions."}):h.flatMap((L,Q)=>{let v=g.start+Q,ee=v===s,B=[];return c&&L.project_name!==x&&(B.push(z(RT,{project:L.project_name,width:u},`hdr-${L.project_name}-${v}`)),x=L.project_name),B.push(z(wT,{session:L,width:u,isSelected:ee,indented:c},L.id)),B})}),z(Ye,{width:u+2,paddingLeft:1,children:z(oe,{color:w,children:e.length>0?at(` ${s+1} / ${e.length}${g.end<e.length?" \xB7 scroll for more":""} `,u):""})})]})}function wT({session:e,width:t,isSelected:s,indented:n}){let r=W(e.started_at)||"",o=n?" ":"",i=s?"\u258C ":" ";if(n){let f=e.alias||e.auto_title||e.first_user_message||"(no title)",g=Math.min(14,Math.max(6,Math.floor(t*.25))),h=Math.max(10,t-i.length-o.length-g-1),E=at(f,h),b=at(r,g),S=Math.max(1,t-i.length-o.length-E.length-b.length);return ln(Ye,{children:[z(oe,{children:o}),z(oe,{color:s?G:w,bold:s,children:i}),z(oe,{color:s?G:"#fefce8",bold:s,children:E}),z(oe,{children:" ".repeat(S)}),z(oe,{color:w,children:b})]})}let a=e.project_name||"?",l=Math.min(28,Math.floor(t*.7)),c=Math.min(14,t-l-i.length-1),u=at(a,l),m=at(r,c),p=Math.max(1,t-i.length-u.length-m.length);return ln(Ye,{children:[z(oe,{color:s?G:w,bold:s,children:i}),z(oe,{color:s?G:"#67e8f9",bold:s,children:u}),z(oe,{children:" ".repeat(p)}),z(oe,{color:w,children:m})]})}function RT({project:e,width:t}){return z(Ye,{children:z(oe,{color:"#67e8f9",bold:!0,children:at(`\u25BE ${e}`,t)})})}var yT,uu=C(()=>{"use strict";I();it();yT={recent:"recent",longest:"longest",busiest:"busiest project"}});import{useEffect as xT,useState as ao}from"react";function mu(e,t,s){let n=s?"":"AND is_sidechain = 0";return e.prepare(`SELECT uuid, role, type, timestamp, content_text
740
740
  FROM messages
741
741
  WHERE session_id = @id
742
742
  ${n}
743
743
  ORDER BY timestamp DESC
744
- LIMIT @limit`).all({id:t,limit:By})}function Hd(e){let[t,s]=Kr([]),[n,r]=Kr(!1),[o,i]=Kr(!1);return Uy(()=>{if(!e){s([]),i(!1);return}r(!0);try{let a=_(),l=Bd(a,e,!1),c=!1;l.length===0&&(l=Bd(a,e,!0),c=l.length>0),s([...l].reverse()),i(c)}catch{s([]),i(!1)}finally{r(!1)}},[e]),{messages:t,loading:n,fallbackToSidechain:o}}var By,Wd=N(()=>{"use strict";T();By=6});import{Box as Me,Text as Pe}from"ink";import{Fragment as Jy,jsx as V,jsxs as Lt}from"react/jsx-runtime";function Hy(e){let t=(e.role??"").toLowerCase();return t==="user"?{label:"user",color:Ad}:t==="assistant"?{label:"asst",color:Id}:t==="tool"?{label:"tool",color:vd}:t==="system"?{label:"sys ",color:w}:e.type==="summary"?{label:"sum ",color:w}:{label:"----",color:w}}function Wy(e,t){return e?e.replace(/\s+/g," ").trim().slice(0,t+1).replace(/.{1}$/,s=>e.length>t?"\u2026":s):"(empty)"}function Xd({session:e,width:t,height:s}){let n=e?.id??null,{messages:r,loading:o,fallbackToSidechain:i}=Hd(n),a=Math.max(20,t-2),c=Math.max(4,s-2-2),u=Math.max(2,Math.floor(c/Math.max(1,r.length)));return e?Lt(Me,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:w,children:[Lt(Me,{paddingX:1,flexDirection:"column",children:[V(Me,{width:a,children:V(Pe,{color:G,bold:!0,wrap:"truncate-end",children:e.alias||e.auto_title||e.first_user_message||"(no title)"})}),V(Me,{width:a,children:V(Pe,{color:w,wrap:"truncate-end",children:`${e.id.slice(0,8)} \xB7 ${e.message_count} msgs \xB7 ${W(e.started_at)}`})})]}),V(Me,{flexDirection:"column",paddingX:1,flexGrow:1,children:o?V(Pe,{color:w,children:"loading messages\u2026"}):r.length===0?V(Pe,{color:w,children:"no messages indexed for this session."}):Lt(Jy,{children:[i?V(Pe,{color:w,children:"(showing sidechain / subagent messages)"}):null,r.map(p=>V(Xy,{message:p,width:a,perMessageLines:u},p.uuid))]})})]}):Lt(Me,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:w,children:[V(Me,{paddingX:1,children:V(Pe,{color:G,bold:!0,children:"Preview"})}),V(Me,{paddingX:1,paddingY:1,children:V(Pe,{color:w,children:"Select a session on the left to preview."})})]})}function Xy({message:e,width:t,perMessageLines:s}){let n=Hy(e),r=Math.max(1,s-1),o=Math.max(20,t-2),i=r*o,a=Wy(e.content_text,i);return Lt(Me,{flexDirection:"column",marginBottom:0,children:[Lt(Me,{children:[V(Pe,{color:n.color,bold:!0,children:n.label}),V(Pe,{color:w,children:` ${e.timestamp?W(e.timestamp):""}`})]}),V(Me,{width:t,children:V(Pe,{wrap:"truncate-end",children:a})})]})}var Jd=N(()=>{"use strict";M();Wd();ot()});import{useMemo as Gy}from"react";import{Box as De,Text as at}from"ink";import{jsx as pe,jsxs as Vt}from"react/jsx-runtime";function zy(e,t){try{return{ok:!0,result:Ms(e,{budget:t})}}catch(s){return{ok:!1,error:s instanceof Error?s.message:String(s)}}}function Gd({session:e,width:t,height:s,budget:n}){let r=Gy(()=>e?zy(e.id,n):null,[e?.id,n]),o=Math.max(20,t-2),a=Math.max(4,s-2-2);if(!e)return Vt(De,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:w,children:[pe(De,{paddingX:1,children:pe(at,{color:G,bold:!0,children:"Neighborhood"})}),pe(De,{paddingX:1,paddingY:1,children:pe(at,{color:w,children:"Select a session and press `n` to assemble its neighborhood."})})]});if(!r)return null;if(!r.ok)return Vt(De,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:ve,children:[pe(De,{paddingX:1,children:pe(at,{color:ve,bold:!0,children:"Neighborhood error"})}),pe(De,{paddingX:1,paddingY:1,children:pe(at,{color:ve,children:r.error})})]});let{result:l}=r,c=l.bundle.replace(/\n+$/,"").split(`
745
- `),u=c.slice(0,Math.max(1,a-1)),p=c.length-u.length;return Vt(De,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:Z,children:[Vt(De,{paddingX:1,flexDirection:"column",children:[pe(De,{width:o,children:pe(at,{color:Z,bold:!0,wrap:"truncate-end",children:"Neighborhood"})}),pe(De,{width:o,children:pe(at,{color:w,wrap:"truncate-end",children:`budget=${n} used=${l.budgetUsed} remaining=${l.budgetRemaining} truncated=${l.truncated.length}`})})]}),Vt(De,{flexDirection:"column",paddingX:1,flexGrow:1,children:[u.map((m,f)=>pe(at,{wrap:"truncate-end",children:m||" "},f)),p>0?pe(at,{color:w,children:`\u2026 ${p} more line${p===1?"":"s"} (resize the terminal or use \`recall neighborhood ${e.id.slice(0,8)}\` for the full bundle)`}):null]})]})}var zd=N(()=>{"use strict";mr();ot()});import{useEffect as Yy,useState as Yd}from"react";import{Box as Zt,Text as ct}from"ink";import qr from"ink-text-input";import{jsx as _e,jsxs as Vr}from"react/jsx-runtime";function Kd({mode:e,query:t,onQueryChange:s,onSearchSubmit:n,onAliasSubmit:r,onTagSubmit:o,aliasInitial:i,toast:a}){let[l,c]=Yd(""),[u,p]=Yd("");return Yy(()=>{e==="alias"&&c(i),e==="tag"&&p("")},[e,i]),a&&e==="normal"?_e(Zt,{children:_e(ct,{color:ve,children:`\u25B6 ${a}`})}):e==="search"?Vr(Zt,{children:[_e(ct,{color:G,bold:!0,children:"/ "}),_e(qr,{value:t,onChange:s,onSubmit:n,placeholder:"filter sessions by project, alias, or opening message..."}),_e(ct,{color:w,children:" esc clear \xB7 enter confirm"})]}):e==="alias"?Vr(Zt,{children:[_e(ct,{color:Z,bold:!0,children:"alias \u203A "}),_e(qr,{value:l,onChange:c,onSubmit:m=>r(m),placeholder:"terminal-tab name for this session"}),_e(ct,{color:w,children:" esc cancel \xB7 enter save"})]}):e==="tag"?Vr(Zt,{children:[_e(ct,{color:Z,bold:!0,children:"tag \u203A "}),_e(qr,{value:u,onChange:p,onSubmit:m=>o(m),placeholder:"add a tag to this session"}),_e(ct,{color:w,children:" esc cancel \xB7 enter save"})]}):_e(Zt,{children:_e(ct,{color:w,children:"\u2191\u2193 nav \xB7 / filter \xB7 enter view \xB7 a alias \xB7 t tag \xB7 s sort \xB7 g group \xB7 n bundle \xB7 o browser \xB7 ? help \xB7 q quit"})})}var qd=N(()=>{"use strict";ot()});import{Box as me,Text as F}from"ink";import{jsx as D,jsxs as he}from"react/jsx-runtime";function Vd({width:e,height:t}){return he(me,{flexDirection:"column",width:e,height:t,borderStyle:"round",borderColor:G,paddingX:2,paddingY:1,children:[he(me,{children:[D(F,{color:G,bold:!0,children:"Claude Recall TUI \u2014 Help"}),D(F,{color:w,children:" \xB7 press ? or esc to close"})]}),he(me,{marginTop:1,flexDirection:"column",children:[D(F,{color:Z,bold:!0,children:"Navigation"}),Ky.map(s=>D(Zr,{row:s},s.key))]}),he(me,{marginTop:1,flexDirection:"column",children:[D(F,{color:Z,bold:!0,children:"Actions on the selected session"}),qy.map(s=>D(Zr,{row:s},s.key))]}),he(me,{marginTop:1,flexDirection:"column",children:[D(F,{color:Z,bold:!0,children:"Right-pane views"}),Vy.map(s=>D(Zr,{row:s},s.key))]}),he(me,{marginTop:1,flexDirection:"column",children:[D(F,{color:Z,bold:!0,children:"What is Neighborhood?"}),D(F,{color:w,wrap:"wrap",children:"Neighborhood assembles a ranked, token-budgeted bundle of context around the selected session: its parent and child sessions, citations (sessions it referenced), similar sessions (by embedding), and any related bug-pattern matches. Press `n` in the TUI to preview it on the right."})]}),he(me,{marginTop:1,flexDirection:"column",children:[D(F,{color:Z,bold:!0,children:"Maintenance & diagnostics"}),D(F,{color:w,wrap:"wrap",children:"Two commands cover everything. Quit the TUI with `q` first, then:"}),he(me,{marginTop:1,children:[D(F,{color:w,children:" \u2022 "}),D(F,{children:"recall doctor"})]}),D(F,{color:w,wrap:"wrap",children:" Health report: DB size, WAL, FTS fragmentation, integrity, disk free."}),D(F,{color:w,wrap:"wrap",children:" Run this first if anything feels slow or wrong. Add --json for machine output."}),he(me,{marginTop:1,children:[D(F,{color:w,children:" \u2022 "}),D(F,{children:"recall optimize"})]}),D(F,{color:w,wrap:"wrap",children:" Maintenance: WAL truncate + FTS5 merge + planner stats. Safe while daemon is running."}),D(F,{color:w,wrap:"wrap",children:" Add --vacuum (with daemon stopped) to also reclaim disk pages from deleted rows."})]}),he(me,{marginTop:1,flexDirection:"column",children:[D(F,{color:Z,bold:!0,children:"How to pipe a session into Claude"}),D(F,{color:w,wrap:"wrap",children:"Two recipes. Both work in any shell \u2014 exit this TUI with `q` first, then run them."}),he(me,{marginTop:1,children:[D(F,{color:w,children:" 1. "}),D(F,{children:"recall context <id> | claude"})]}),D(F,{color:w,wrap:"wrap",children:" Pipes one session's full transcript as markdown into a fresh `claude` chat."}),D(F,{color:w,wrap:"wrap",children:" Use when you want to continue exactly where one session left off."}),he(me,{marginTop:1,children:[D(F,{color:w,children:" 2. "}),D(F,{children:"recall neighborhood <id> | claude"})]}),D(F,{color:w,wrap:"wrap",children:" Pipes the bundle (parents + children + citations + similar + bug matches)."}),D(F,{color:w,wrap:"wrap",children:" Use when you want broader context, not just one transcript."})]})]})}function Zr({row:e}){return he(me,{children:[D(me,{width:16,children:D(F,{color:G,children:e.key})}),D(F,{color:w,wrap:"truncate-end",children:e.description})]})}var Ky,qy,Vy,Zd=N(()=>{"use strict";ot();Ky=[{key:"\u2191 / k",description:"move selection up"},{key:"\u2193 / j",description:"move selection down"},{key:"PgUp / PgDn",description:"jump 10 sessions"},{key:"/",description:"filter by project, alias, or first user message"},{key:"g",description:"toggle project-grouped view"},{key:"s",description:"cycle sort order: recent \u2192 longest \u2192 most-active"}],qy=[{key:"enter",description:"open the full transcript (`recall show <id>`) and exit the TUI"},{key:"a",description:"set or update the alias for the selected session"},{key:"t",description:"add a tag to the selected session"},{key:"o",description:"open the selected session in your browser (daemon required)"}],Vy=[{key:"n",description:"toggle the right pane between Preview and Neighborhood"},{key:"?",description:"open this help screen"},{key:"esc",description:"dismiss filter or this help screen"},{key:"q / Ctrl-C",description:"quit the TUI"}]});import{useEffect as Zy,useMemo as Qy,useState as en}from"react";import{existsSync as eT}from"node:fs";function Qd(e){let[t,s]=en([]),[n,r]=en(!0),[o,i]=en(null),[a,l]=en(!0);return Zy(()=>{if(!eT(te)){l(!1),r(!1);return}try{let p=_().prepare(`SELECT s.id, p.name AS project_name, s.started_at,
744
+ LIMIT @limit`).all({id:t,limit:kT})}function pu(e){let[t,s]=ao([]),[n,r]=ao(!1),[o,i]=ao(!1);return xT(()=>{if(!e){s([]),i(!1);return}r(!0);try{let a=_(),l=mu(a,e,!1),c=!1;l.length===0&&(l=mu(a,e,!0),c=l.length>0),s([...l].reverse()),i(c)}catch{s([]),i(!1)}finally{r(!1)}},[e]),{messages:t,loading:n,fallbackToSidechain:o}}var kT,gu=C(()=>{"use strict";T();kT=6});import{Box as De,Text as Fe}from"ink";import{Fragment as OT,jsx as V,jsxs as vt}from"react/jsx-runtime";function NT(e){let t=(e.role??"").toLowerCase();return t==="user"?{label:"user",color:su}:t==="assistant"?{label:"asst",color:nu}:t==="tool"?{label:"tool",color:ru}:t==="system"?{label:"sys ",color:w}:e.type==="summary"?{label:"sum ",color:w}:{label:"----",color:w}}function CT(e,t){return e?e.replace(/\s+/g," ").trim().slice(0,t+1).replace(/.{1}$/,s=>e.length>t?"\u2026":s):"(empty)"}function fu({session:e,width:t,height:s}){let n=e?.id??null,{messages:r,loading:o,fallbackToSidechain:i}=pu(n),a=Math.max(20,t-2),c=Math.max(4,s-2-2),u=Math.max(2,Math.floor(c/Math.max(1,r.length)));return e?vt(De,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:w,children:[vt(De,{paddingX:1,flexDirection:"column",children:[V(De,{width:a,children:V(Fe,{color:G,bold:!0,wrap:"truncate-end",children:e.alias||e.auto_title||e.first_user_message||"(no title)"})}),V(De,{width:a,children:V(Fe,{color:w,wrap:"truncate-end",children:`${e.id.slice(0,8)} \xB7 ${e.message_count} msgs \xB7 ${W(e.started_at)}`})})]}),V(De,{flexDirection:"column",paddingX:1,flexGrow:1,children:o?V(Fe,{color:w,children:"loading messages\u2026"}):r.length===0?V(Fe,{color:w,children:"no messages indexed for this session."}):vt(OT,{children:[i?V(Fe,{color:w,children:"(showing sidechain / subagent messages)"}):null,r.map(m=>V(LT,{message:m,width:a,perMessageLines:u},m.uuid))]})})]}):vt(De,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:w,children:[V(De,{paddingX:1,children:V(Fe,{color:G,bold:!0,children:"Preview"})}),V(De,{paddingX:1,paddingY:1,children:V(Fe,{color:w,children:"Select a session on the left to preview."})})]})}function LT({message:e,width:t,perMessageLines:s}){let n=NT(e),r=Math.max(1,s-1),o=Math.max(20,t-2),i=r*o,a=CT(e.content_text,i);return vt(De,{flexDirection:"column",marginBottom:0,children:[vt(De,{children:[V(Fe,{color:n.color,bold:!0,children:n.label}),V(Fe,{color:w,children:` ${e.timestamp?W(e.timestamp):""}`})]}),V(De,{width:t,children:V(Fe,{wrap:"truncate-end",children:a})})]})}var _u=C(()=>{"use strict";I();gu();it()});import{useMemo as AT}from"react";import{Box as $e,Text as ct}from"ink";import{jsx as pe,jsxs as ts}from"react/jsx-runtime";function IT(e,t){try{return{ok:!0,result:Fs(e,{budget:t})}}catch(s){return{ok:!1,error:s instanceof Error?s.message:String(s)}}}function hu({session:e,width:t,height:s,budget:n}){let r=AT(()=>e?IT(e.id,n):null,[e?.id,n]),o=Math.max(20,t-2),a=Math.max(4,s-2-2);if(!e)return ts($e,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:w,children:[pe($e,{paddingX:1,children:pe(ct,{color:G,bold:!0,children:"Neighborhood"})}),pe($e,{paddingX:1,paddingY:1,children:pe(ct,{color:w,children:"Select a session and press `n` to assemble its neighborhood."})})]});if(!r)return null;if(!r.ok)return ts($e,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:Me,children:[pe($e,{paddingX:1,children:pe(ct,{color:Me,bold:!0,children:"Neighborhood error"})}),pe($e,{paddingX:1,paddingY:1,children:pe(ct,{color:Me,children:r.error})})]});let{result:l}=r,c=l.bundle.replace(/\n+$/,"").split(`
745
+ `),u=c.slice(0,Math.max(1,a-1)),m=c.length-u.length;return ts($e,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:Z,children:[ts($e,{paddingX:1,flexDirection:"column",children:[pe($e,{width:o,children:pe(ct,{color:Z,bold:!0,wrap:"truncate-end",children:"Neighborhood"})}),pe($e,{width:o,children:pe(ct,{color:w,wrap:"truncate-end",children:`budget=${n} used=${l.budgetUsed} remaining=${l.budgetRemaining} truncated=${l.truncated.length}`})})]}),ts($e,{flexDirection:"column",paddingX:1,flexGrow:1,children:[u.map((p,f)=>pe(ct,{wrap:"truncate-end",children:p||" "},f)),m>0?pe(ct,{color:w,children:`\u2026 ${m} more line${m===1?"":"s"} (resize the terminal or use \`recall neighborhood ${e.id.slice(0,8)}\` for the full bundle)`}):null]})]})}var Eu=C(()=>{"use strict";yr();it()});import{useEffect as vT,useState as bu}from"react";import{Box as ss,Text as lt}from"ink";import co from"ink-text-input";import{jsx as Ee,jsxs as lo}from"react/jsx-runtime";function Su({mode:e,query:t,onQueryChange:s,onSearchSubmit:n,onAliasSubmit:r,onTagSubmit:o,aliasInitial:i,toast:a}){let[l,c]=bu(""),[u,m]=bu("");return vT(()=>{e==="alias"&&c(i),e==="tag"&&m("")},[e,i]),a&&e==="normal"?Ee(ss,{children:Ee(lt,{color:Me,children:`\u25B6 ${a}`})}):e==="search"?lo(ss,{children:[Ee(lt,{color:G,bold:!0,children:"/ "}),Ee(co,{value:t,onChange:s,onSubmit:n,placeholder:"filter sessions by project, alias, or opening message..."}),Ee(lt,{color:w,children:" esc clear \xB7 enter confirm"})]}):e==="alias"?lo(ss,{children:[Ee(lt,{color:Z,bold:!0,children:"alias \u203A "}),Ee(co,{value:l,onChange:c,onSubmit:p=>r(p),placeholder:"terminal-tab name for this session"}),Ee(lt,{color:w,children:" esc cancel \xB7 enter save"})]}):e==="tag"?lo(ss,{children:[Ee(lt,{color:Z,bold:!0,children:"tag \u203A "}),Ee(co,{value:u,onChange:m,onSubmit:p=>o(p),placeholder:"add a tag to this session"}),Ee(lt,{color:w,children:" esc cancel \xB7 enter save"})]}):Ee(ss,{children:Ee(lt,{color:w,children:"\u2191\u2193 nav \xB7 / filter \xB7 enter view \xB7 a alias \xB7 t tag \xB7 s sort \xB7 g group \xB7 n bundle \xB7 o browser \xB7 ? help \xB7 q quit"})})}var yu=C(()=>{"use strict";it()});import{Box as ge,Text as F}from"ink";import{jsx as D,jsxs as be}from"react/jsx-runtime";function Tu({width:e,height:t}){return be(ge,{flexDirection:"column",width:e,height:t,borderStyle:"round",borderColor:G,paddingX:2,paddingY:1,children:[be(ge,{children:[D(F,{color:G,bold:!0,children:"Claude Recall TUI \u2014 Help"}),D(F,{color:w,children:" \xB7 press ? or esc to close"})]}),be(ge,{marginTop:1,flexDirection:"column",children:[D(F,{color:Z,bold:!0,children:"Navigation"}),MT.map(s=>D(uo,{row:s},s.key))]}),be(ge,{marginTop:1,flexDirection:"column",children:[D(F,{color:Z,bold:!0,children:"Actions on the selected session"}),DT.map(s=>D(uo,{row:s},s.key))]}),be(ge,{marginTop:1,flexDirection:"column",children:[D(F,{color:Z,bold:!0,children:"Right-pane views"}),$T.map(s=>D(uo,{row:s},s.key))]}),be(ge,{marginTop:1,flexDirection:"column",children:[D(F,{color:Z,bold:!0,children:"What is Neighborhood?"}),D(F,{color:w,wrap:"wrap",children:"Neighborhood assembles a ranked, token-budgeted bundle of context around the selected session: its parent and child sessions, citations (sessions it referenced), similar sessions (by embedding), and any related bug-pattern matches. Press `n` in the TUI to preview it on the right."})]}),be(ge,{marginTop:1,flexDirection:"column",children:[D(F,{color:Z,bold:!0,children:"Maintenance & diagnostics"}),D(F,{color:w,wrap:"wrap",children:"Two commands cover everything. Quit the TUI with `q` first, then:"}),be(ge,{marginTop:1,children:[D(F,{color:w,children:" \u2022 "}),D(F,{children:"recall doctor"})]}),D(F,{color:w,wrap:"wrap",children:" Health report: DB size, WAL, FTS fragmentation, integrity, disk free."}),D(F,{color:w,wrap:"wrap",children:" Run this first if anything feels slow or wrong. Add --json for machine output."}),be(ge,{marginTop:1,children:[D(F,{color:w,children:" \u2022 "}),D(F,{children:"recall optimize"})]}),D(F,{color:w,wrap:"wrap",children:" Maintenance: WAL truncate + FTS5 merge + planner stats. Safe while daemon is running."}),D(F,{color:w,wrap:"wrap",children:" Add --vacuum (with daemon stopped) to also reclaim disk pages from deleted rows."})]}),be(ge,{marginTop:1,flexDirection:"column",children:[D(F,{color:Z,bold:!0,children:"How to pipe a session into Claude"}),D(F,{color:w,wrap:"wrap",children:"Two recipes. Both work in any shell \u2014 exit this TUI with `q` first, then run them."}),be(ge,{marginTop:1,children:[D(F,{color:w,children:" 1. "}),D(F,{children:"recall context <id> | claude"})]}),D(F,{color:w,wrap:"wrap",children:" Pipes one session's full transcript as markdown into a fresh `claude` chat."}),D(F,{color:w,wrap:"wrap",children:" Use when you want to continue exactly where one session left off."}),be(ge,{marginTop:1,children:[D(F,{color:w,children:" 2. "}),D(F,{children:"recall neighborhood <id> | claude"})]}),D(F,{color:w,wrap:"wrap",children:" Pipes the bundle (parents + children + citations + similar + bug matches)."}),D(F,{color:w,wrap:"wrap",children:" Use when you want broader context, not just one transcript."})]})]})}function uo({row:e}){return be(ge,{children:[D(ge,{width:16,children:D(F,{color:G,children:e.key})}),D(F,{color:w,wrap:"truncate-end",children:e.description})]})}var MT,DT,$T,wu=C(()=>{"use strict";it();MT=[{key:"\u2191 / k",description:"move selection up"},{key:"\u2193 / j",description:"move selection down"},{key:"PgUp / PgDn",description:"jump 10 sessions"},{key:"/",description:"filter by project, alias, or first user message"},{key:"g",description:"toggle project-grouped view"},{key:"s",description:"cycle sort order: recent \u2192 longest \u2192 most-active"}],DT=[{key:"enter",description:"open the full transcript (`recall show <id>`) and exit the TUI"},{key:"a",description:"set or update the alias for the selected session"},{key:"t",description:"add a tag to the selected session"},{key:"o",description:"open the selected session in your browser (daemon required)"}],$T=[{key:"n",description:"toggle the right pane between Preview and Neighborhood"},{key:"?",description:"open this help screen"},{key:"esc",description:"dismiss filter or this help screen"},{key:"q / Ctrl-C",description:"quit the TUI"}]});import{useEffect as jT,useMemo as PT,useState as dn}from"react";import{existsSync as FT}from"node:fs";function Ru(e){let[t,s]=dn([]),[n,r]=dn(!0),[o,i]=dn(null),[a,l]=dn(!0);return jT(()=>{if(!FT(te)){l(!1),r(!1);return}try{let m=_().prepare(`SELECT s.id, p.name AS project_name, s.started_at,
746
746
  s.message_count, s.first_user_message,
747
747
  NULLIF(sa.alias, '') AS alias,
748
748
  s.auto_title
@@ -754,23 +754,23 @@ ${t.message}
754
754
  AND COALESCE(s.auto_title, '') NOT LIKE '[output-index]%'
755
755
  AND COALESCE(s.auto_title, '') NOT LIKE '[skill]%'
756
756
  ORDER BY COALESCE(s.started_at, '') DESC
757
- LIMIT @limit`).all({limit:tT});s(p)}catch(u){i(u instanceof Error?u.message:String(u))}finally{r(!1)}},[]),{sessions:Qy(()=>{let u=e.trim().toLowerCase();return u?t.filter(p=>{let m=p.project_name?.toLowerCase()??"",f=p.first_user_message?.toLowerCase()??"";return m.includes(u)||f.includes(u)}):t},[t,e]),total:t.length,loading:n,error:o,dbExists:a}}var tT,eu=N(()=>{"use strict";T();j();tT=200});import{useEffect as Qr,useMemo as sT,useState as Fe}from"react";import{Box as lt,Text as tn,useApp as nT,useInput as rT}from"ink";import{spawn as oT}from"node:child_process";import{platform as sn}from"node:os";import{jsx as ie,jsxs as to}from"react/jsx-runtime";function su(){return{cols:process.stdout.columns??100,rows:process.stdout.rows??30}}function dT(e){let t=sn()==="darwin"?"open":sn()==="win32"?"start":"xdg-open",s=sn()==="win32"?["",e]:[e];oT(t,s,{detached:!0,stdio:"ignore",shell:sn()==="win32"}).unref()}function nu({onShowSession:e}){let{exit:t}=nT(),s=su(),[n,r]=Fe(s.cols),[o,i]=Fe(s.rows),[a,l]=Fe(0),[c,u]=Fe(""),[p,m]=Fe("normal"),[f,g]=Fe(null),[h,E]=Fe("preview"),[b,S]=Fe("recent"),[C,x]=Fe(!1),[L,Q]=Fe(!1),{sessions:I,total:ee,loading:B,error:y,dbExists:U}=Qd(c),v=sT(()=>{if(I.length===0)return I;let $=new Map;if(b==="busiest"||C)for(let O of I)$.set(O.project_name,($.get(O.project_name)??0)+1);let X=[...I];if(b==="longest"?X.sort((O,J)=>(J.message_count??0)-(O.message_count??0)):b==="busiest"&&X.sort((O,J)=>{let Re=$.get(O.project_name)??0,xe=$.get(J.project_name)??0;return xe!==Re?xe-Re:(J.started_at??"").localeCompare(O.started_at??"")}),C){let O=new Map;for(let xe of X){let Be=O.get(xe.project_name);Be||(Be=[],O.set(xe.project_name,Be)),Be.push(xe)}let J=Array.from(O.keys()).sort((xe,Be)=>{if(b==="busiest"){let oo=$.get(xe)??0,io=$.get(Be)??0;if(io!==oo)return io-oo}return xe.localeCompare(Be)}),Re=[];for(let xe of J)for(let Be of O.get(xe)??[])Re.push(Be);return Re}return X},[I,b,C]);Qr(()=>{let $=()=>{let X=su();r(X.cols),i(X.rows)};return process.stdout.on("resize",$),()=>{process.stdout.off("resize",$)}},[]),Qr(()=>{if(v.length===0){a!==0&&l(0);return}a>=v.length&&l(v.length-1)},[v.length,a]),Qr(()=>{if(!f)return;let $=setTimeout(()=>g(null),2500);return()=>clearTimeout($)},[f]),rT(($,X)=>{if(p==="search"){X.escape&&(m("normal"),u(""));return}if(p==="alias"||p==="tag"){X.escape&&m("normal");return}if(L){($==="?"||X.escape||$==="q")&&Q(!1);return}if($==="q"||X.ctrl&&$==="c"){t();return}if($==="?"){Q(!0);return}if(!(v.length===0&&$!=="/")){if(X.upArrow||$==="k"){l(O=>Math.max(0,O-1));return}if(X.downArrow||$==="j"){l(O=>Math.min(v.length-1,O+1));return}if(X.pageUp){l(O=>Math.max(0,O-10));return}if(X.pageDown){l(O=>Math.min(v.length-1,O+10));return}if(X.return){let O=v[a];O&&(e(O.id),t());return}if($==="o"){let O=v[a];if(!O)return;let J=q();if(!J){g("start the daemon first (`recall start`)");return}let Re=`http://127.0.0.1:${J.port}/sessions/${O.id}`;dT(Re),g(`opened ${Re}`);return}if($==="n"){E(J=>J==="neighborhood"?"preview":"neighborhood");let O=v[a];O&&g(h==="neighborhood"?"preview view":`neighborhood for ${O.id.slice(0,8)}`);return}if($==="/"){m("search");return}if($==="a"){v[a]&&m("alias");return}if($==="t"){v[a]&&m("tag");return}if($==="s"){S(O=>{let J=eo.indexOf(O),Re=eo[(J+1)%eo.length];return g(`sort: ${uT[Re]}`),Re});return}if($==="g"){x(O=>(g(O?"flat view":"grouped by project"),!O));return}}});function K($){m("normal");let X=v[a];if(!X)return;let O=$.trim();if(!O){g("alias unchanged (empty input)");return}try{fs(X.id,O),g(`alias set: ${O}`)}catch(J){g(`alias failed: ${J instanceof Error?J.message:"unknown"}`)}}function Ue($){m("normal");let X=v[a];if(!X)return;let O=$.trim();if(!O){g("tag unchanged (empty input)");return}try{let J=Gi(X.id,O);g(J.added?`tag added: ${J.tag}`:`tag exists: ${J.tag}`)}catch(J){g(`tag failed: ${J instanceof Error?J.message:"unknown"}`)}}if(n<zr||o<Yr)return to(lt,{flexDirection:"column",padding:1,children:[ie(tn,{color:ve,children:"Terminal too small."}),ie(tn,{color:w,children:`Resize to at least ${zr} cols x ${Yr} rows. Current: ${n} x ${o}.`}),ie(tn,{color:w,children:"Press q to quit."})]});let $e=Math.max(10,o-lT-tu),dt=Math.max(36,Math.floor(n*.4)),ro=n-dt-1,nn=v[a]??null;return to(lt,{flexDirection:"column",width:n,height:o,children:[ie($d,{cols:n}),ie(lt,{height:1}),y?ie(lt,{paddingX:1,children:ie(tn,{color:ve,children:`Error loading sessions: ${y}`})}):L?ie(lt,{height:$e,children:ie(Vd,{width:n,height:$e})}):to(lt,{flexDirection:"row",height:$e,children:[ie(Fd,{sessions:v,total:ee,selected:a,width:dt,height:$e,loading:B,dbExists:U,filter:c,sortMode:b,groupByProject:C}),ie(lt,{width:1,height:$e}),h==="neighborhood"?ie(Gd,{session:nn,width:ro,height:$e,budget:4e3}):ie(Xd,{session:nn,width:ro,height:$e})]}),ie(lt,{height:tu,width:n,paddingX:1,children:ie(Kd,{mode:p,query:c,onQueryChange:u,onSearchSubmit:()=>m("normal"),onAliasSubmit:K,onTagSubmit:Ue,aliasInitial:nn?.alias??"",toast:f})})]})}var iT,aT,cT,tu,lT,eo,uT,ru=N(()=>{"use strict";Pd();Ud();Jd();zd();qd();Zd();eu();He();Dt();Un();ot();iT=4,aT=1,cT=1,tu=1,lT=iT+aT+cT,eo=["recent","longest","busiest"];uT={recent:"most recent first",longest:"longest sessions first",busiest:"busiest project first"}});import{render as pT}from"ink";import{jsx as mT}from"react/jsx-runtime";async function ou(){let e={showSessionId:null};return await pT(mT(nu,{onShowSession:n=>{e.showSessionId=n}})).waitUntilExit(),e}var iu=N(()=>{"use strict";ru()});var au={};Ee(au,{runTui:()=>fT});import{spawn as gT}from"node:child_process";async function fT(){if(!process.stdin.isTTY||!process.stdout.isTTY){console.error("recall tui requires an interactive terminal. Run it directly (no pipes)."),process.exitCode=1;return}let e=await ou();if(!e.showSessionId)return;let t=process.argv[1];t&&await new Promise(s=>{let n=gT(process.execPath,[t,"show",e.showSessionId],{stdio:"inherit"});n.on("exit",()=>s()),n.on("error",()=>s())})}var cu=N(()=>{"use strict";iu()});var lu={};Ee(lu,{findSimilarSessions:()=>hT,vectorSearch:()=>_T});async function _T(e,t=50){let s=await zn(e),n=_(),r=Buffer.from(s.buffer,s.byteOffset,s.byteLength);return n.prepare(`SELECT v.rowid, v.distance, cm.session_id, cm.text, cm.message_uuids
757
+ LIMIT @limit`).all({limit:UT});s(m)}catch(u){i(u instanceof Error?u.message:String(u))}finally{r(!1)}},[]),{sessions:PT(()=>{let u=e.trim().toLowerCase();return u?t.filter(m=>{let p=m.project_name?.toLowerCase()??"",f=m.first_user_message?.toLowerCase()??"";return p.includes(u)||f.includes(u)}):t},[t,e]),total:t.length,loading:n,error:o,dbExists:a}}var UT,xu=C(()=>{"use strict";T();j();UT=200});import{useEffect as mo,useMemo as BT,useState as Ue}from"react";import{Box as dt,Text as un,useApp as HT,useInput as WT}from"ink";import{spawn as XT}from"node:child_process";import{platform as mn}from"node:os";import{jsx as ie,jsxs as go}from"react/jsx-runtime";function Nu(){return{cols:process.stdout.columns??100,rows:process.stdout.rows??30}}function KT(e){let t=mn()==="darwin"?"open":mn()==="win32"?"start":"xdg-open",s=mn()==="win32"?["",e]:[e];XT(t,s,{detached:!0,stdio:"ignore",shell:mn()==="win32"}).unref()}function Cu({onShowSession:e}){let{exit:t}=HT(),s=Nu(),[n,r]=Ue(s.cols),[o,i]=Ue(s.rows),[a,l]=Ue(0),[c,u]=Ue(""),[m,p]=Ue("normal"),[f,g]=Ue(null),[h,E]=Ue("preview"),[b,S]=Ue("recent"),[N,x]=Ue(!1),[L,Q]=Ue(!1),{sessions:v,total:ee,loading:B,error:y,dbExists:U}=Ru(c),M=BT(()=>{if(v.length===0)return v;let $=new Map;if(b==="busiest"||N)for(let O of v)$.set(O.project_name,($.get(O.project_name)??0)+1);let X=[...v];if(b==="longest"?X.sort((O,J)=>(J.message_count??0)-(O.message_count??0)):b==="busiest"&&X.sort((O,J)=>{let xe=$.get(O.project_name)??0,ke=$.get(J.project_name)??0;return ke!==xe?ke-xe:(J.started_at??"").localeCompare(O.started_at??"")}),N){let O=new Map;for(let ke of X){let He=O.get(ke.project_name);He||(He=[],O.set(ke.project_name,He)),He.push(ke)}let J=Array.from(O.keys()).sort((ke,He)=>{if(b==="busiest"){let bo=$.get(ke)??0,So=$.get(He)??0;if(So!==bo)return So-bo}return ke.localeCompare(He)}),xe=[];for(let ke of J)for(let He of O.get(ke)??[])xe.push(He);return xe}return X},[v,b,N]);mo(()=>{let $=()=>{let X=Nu();r(X.cols),i(X.rows)};return process.stdout.on("resize",$),()=>{process.stdout.off("resize",$)}},[]),mo(()=>{if(M.length===0){a!==0&&l(0);return}a>=M.length&&l(M.length-1)},[M.length,a]),mo(()=>{if(!f)return;let $=setTimeout(()=>g(null),2500);return()=>clearTimeout($)},[f]),WT(($,X)=>{if(m==="search"){X.escape&&(p("normal"),u(""));return}if(m==="alias"||m==="tag"){X.escape&&p("normal");return}if(L){($==="?"||X.escape||$==="q")&&Q(!1);return}if($==="q"||X.ctrl&&$==="c"){t();return}if($==="?"){Q(!0);return}if(!(M.length===0&&$!=="/")){if(X.upArrow||$==="k"){l(O=>Math.max(0,O-1));return}if(X.downArrow||$==="j"){l(O=>Math.min(M.length-1,O+1));return}if(X.pageUp){l(O=>Math.max(0,O-10));return}if(X.pageDown){l(O=>Math.min(M.length-1,O+10));return}if(X.return){let O=M[a];O&&(e(O.id),t());return}if($==="o"){let O=M[a];if(!O)return;let J=q();if(!J){g("start the daemon first (`recall start`)");return}let xe=`http://127.0.0.1:${J.port}/sessions/${O.id}`;KT(xe),g(`opened ${xe}`);return}if($==="n"){E(J=>J==="neighborhood"?"preview":"neighborhood");let O=M[a];O&&g(h==="neighborhood"?"preview view":`neighborhood for ${O.id.slice(0,8)}`);return}if($==="/"){p("search");return}if($==="a"){M[a]&&p("alias");return}if($==="t"){M[a]&&p("tag");return}if($==="s"){S(O=>{let J=po.indexOf(O),xe=po[(J+1)%po.length];return g(`sort: ${qT[xe]}`),xe});return}if($==="g"){x(O=>(g(O?"flat view":"grouped by project"),!O));return}}});function K($){p("normal");let X=M[a];if(!X)return;let O=$.trim();if(!O){g("alias unchanged (empty input)");return}try{Ss(X.id,O),g(`alias set: ${O}`)}catch(J){g(`alias failed: ${J instanceof Error?J.message:"unknown"}`)}}function Be($){p("normal");let X=M[a];if(!X)return;let O=$.trim();if(!O){g("tag unchanged (empty input)");return}try{let J=oa(X.id,O);g(J.added?`tag added: ${J.tag}`:`tag exists: ${J.tag}`)}catch(J){g(`tag failed: ${J instanceof Error?J.message:"unknown"}`)}}if(n<oo||o<io)return go(dt,{flexDirection:"column",padding:1,children:[ie(un,{color:Me,children:"Terminal too small."}),ie(un,{color:w,children:`Resize to at least ${oo} cols x ${io} rows. Current: ${n} x ${o}.`}),ie(un,{color:w,children:"Press q to quit."})]});let je=Math.max(10,o-YT-ku),ut=Math.max(36,Math.floor(n*.4)),Eo=n-ut-1,gn=M[a]??null;return go(dt,{flexDirection:"column",width:n,height:o,children:[ie(au,{cols:n}),ie(dt,{height:1}),y?ie(dt,{paddingX:1,children:ie(un,{color:Me,children:`Error loading sessions: ${y}`})}):L?ie(dt,{height:je,children:ie(Tu,{width:n,height:je})}):go(dt,{flexDirection:"row",height:je,children:[ie(du,{sessions:M,total:ee,selected:a,width:ut,height:je,loading:B,dbExists:U,filter:c,sortMode:b,groupByProject:N}),ie(dt,{width:1,height:je}),h==="neighborhood"?ie(hu,{session:gn,width:Eo,height:je,budget:4e3}):ie(fu,{session:gn,width:Eo,height:je})]}),ie(dt,{height:ku,width:n,paddingX:1,children:ie(Su,{mode:m,query:c,onQueryChange:u,onSearchSubmit:()=>p("normal"),onAliasSubmit:K,onTagSubmit:Be,aliasInitial:gn?.alias??"",toast:f})})]})}var JT,GT,zT,ku,YT,po,qT,Lu=C(()=>{"use strict";lu();uu();_u();Eu();yu();wu();xu();We();Ft();Yn();it();JT=4,GT=1,zT=1,ku=1,YT=JT+GT+zT,po=["recent","longest","busiest"];qT={recent:"most recent first",longest:"longest sessions first",busiest:"busiest project first"}});import{render as VT}from"ink";import{jsx as ZT}from"react/jsx-runtime";async function Ou(){let e={showSessionId:null};return await VT(ZT(Cu,{onShowSession:n=>{e.showSessionId=n}})).waitUntilExit(),e}var Au=C(()=>{"use strict";Lu()});var Iu={};Se(Iu,{runTui:()=>ew});import{spawn as QT}from"node:child_process";async function ew(){if(!process.stdin.isTTY||!process.stdout.isTTY){console.error("recall tui requires an interactive terminal. Run it directly (no pipes)."),process.exitCode=1;return}let e=await Ou();if(!e.showSessionId)return;let t=process.argv[1];t&&await new Promise(s=>{let n=QT(process.execPath,[t,"show",e.showSessionId],{stdio:"inherit"});n.on("exit",()=>s()),n.on("error",()=>s())})}var vu=C(()=>{"use strict";Au()});var Mu={};Se(Mu,{findSimilarSessions:()=>sw,vectorSearch:()=>tw});async function tw(e,t=50){let s=await tr(e),n=_(),r=Buffer.from(s.buffer,s.byteOffset,s.byteLength);return n.prepare(`SELECT v.rowid, v.distance, cm.session_id, cm.text, cm.message_uuids
758
758
  FROM vec_chunks v JOIN chunk_meta cm ON cm.rowid = v.rowid
759
- WHERE v.embedding MATCH ? AND k = ? ORDER BY v.distance`).all(r,t).map(i=>({sessionId:i.session_id,chunkRowid:i.rowid,distance:i.distance,text:i.text,messageUuids:JSON.parse(i.message_uuids)}))}async function hT(e,t=10,s=.65){let n=_(),r=n.prepare("SELECT rowid FROM chunk_meta WHERE session_id = ? ORDER BY rowid LIMIT 1").get(e);if(!r)return[];let o=n.prepare("SELECT embedding FROM vec_chunks WHERE rowid = ?").get(r.rowid);if(!o)return[];let i=n.prepare(`SELECT v.rowid, v.distance, cm.session_id FROM vec_chunks v JOIN chunk_meta cm ON cm.rowid = v.rowid
760
- WHERE v.embedding MATCH ? AND k = ? ORDER BY v.distance`).all(o.embedding,t*5),a=new Map;for(let c of i){if(c.session_id===e)continue;let u=a.get(c.session_id);(u===void 0||c.distance<u)&&a.set(c.session_id,c.distance)}let l=[];for(let[c,u]of a){let p=1-u;p>=s&&l.push({sessionId:c,similarity:p})}return l.sort((c,u)=>u.similarity-c.similarity),l.slice(0,t)}var du=N(()=>{"use strict";T();qe()});import{createRequire as ET}from"module";import{Command as bT}from"commander";T();j();import{basename as lp}from"node:path";import{createReadStream as ku}from"node:fs";import{createInterface as Cu}from"node:readline";function es(e){return typeof e=="number"&&Number.isFinite(e)?e:0}function ln(e){let t=e?.usage;if(!t||typeof t!="object")return null;let s={inputTokens:es(t.input_tokens),outputTokens:es(t.output_tokens),cacheCreateTokens:es(t.cache_creation_input_tokens),cacheReadTokens:es(t.cache_read_input_tokens)};return s.inputTokens===0&&s.outputTokens===0&&s.cacheCreateTokens===0&&s.cacheReadTokens===0?null:s}var Nu=/\x1B\[[0-9;]*[a-zA-Z]/g;function an(e){return e.replace(Nu,"")}var cn=12e3;function ho(e,t){if(e.length<=cn)return e;let s=e.slice(0,cn),n=e.length-cn;return`${s}
759
+ WHERE v.embedding MATCH ? AND k = ? ORDER BY v.distance`).all(r,t).map(i=>({sessionId:i.session_id,chunkRowid:i.rowid,distance:i.distance,text:i.text,messageUuids:JSON.parse(i.message_uuids)}))}async function sw(e,t=10,s=.65){let n=_(),r=n.prepare("SELECT rowid FROM chunk_meta WHERE session_id = ? ORDER BY rowid LIMIT 1").get(e);if(!r)return[];let o=n.prepare("SELECT embedding FROM vec_chunks WHERE rowid = ?").get(r.rowid);if(!o)return[];let i=n.prepare(`SELECT v.rowid, v.distance, cm.session_id FROM vec_chunks v JOIN chunk_meta cm ON cm.rowid = v.rowid
760
+ WHERE v.embedding MATCH ? AND k = ? ORDER BY v.distance`).all(o.embedding,t*5),a=new Map;for(let c of i){if(c.session_id===e)continue;let u=a.get(c.session_id);(u===void 0||c.distance<u)&&a.set(c.session_id,c.distance)}let l=[];for(let[c,u]of a){let m=1-u;m>=s&&l.push({sessionId:c,similarity:m})}return l.sort((c,u)=>u.similarity-c.similarity),l.slice(0,t)}var Du=C(()=>{"use strict";T();Ve()});import{createRequire as nw}from"module";import{Command as rw}from"commander";T();j();import{basename as Mm}from"node:path";import{createReadStream as Vu}from"node:fs";import{createInterface as Zu}from"node:readline";function rs(e){return typeof e=="number"&&Number.isFinite(e)?e:0}function bn(e){let t=e?.usage;if(!t||typeof t!="object")return null;let s={inputTokens:rs(t.input_tokens),outputTokens:rs(t.output_tokens),cacheCreateTokens:rs(t.cache_creation_input_tokens),cacheReadTokens:rs(t.cache_read_input_tokens)};return s.inputTokens===0&&s.outputTokens===0&&s.cacheCreateTokens===0&&s.cacheReadTokens===0?null:s}var Qu=/\x1B\[[0-9;]*[a-zA-Z]/g;function hn(e){return e.replace(Qu,"")}var En=12e3;function Oo(e,t){if(e.length<=En)return e;let s=e.slice(0,En),n=e.length-En;return`${s}
761
761
 
762
- \u27E8\u2026 ${n.toLocaleString()} more chars in ${t}; see raw JSONL for full content \u27E9`}function Lu(e){try{return JSON.stringify(e,null,2)}catch{return String(e)}}function Ou(e){if(typeof e.content=="string")return e.content;if(Array.isArray(e.content)){let t=[];for(let s of e.content)if(s&&typeof s=="object"){let n=s;n.type==="text"&&typeof n.text=="string"?t.push(n.text):n.type==="image"&&t.push("[image]")}return t.join(`
763
- `)}return""}function Au(e){if(!e)return{text:"",toolNames:[]};if(typeof e.content=="string")return{text:an(e.content),toolNames:[]};if(!Array.isArray(e.content))return{text:"",toolNames:[]};let t=[],s=[];for(let n of e.content)if(!(!n||typeof n!="object")){if(n.type==="text"&&typeof n.text=="string"){t.push(an(n.text));continue}if(n.type==="tool_use"&&typeof n.name=="string"){s.push(n.name);let r=n.input!=null?Lu(n.input):"",o=ho(r,"tool input");t.push(`\u26A1 **Tool call \xB7 \`${n.name}\`**
762
+ \u27E8\u2026 ${n.toLocaleString()} more chars in ${t}; see raw JSONL for full content \u27E9`}function em(e){try{return JSON.stringify(e,null,2)}catch{return String(e)}}function tm(e){if(typeof e.content=="string")return e.content;if(Array.isArray(e.content)){let t=[];for(let s of e.content)if(s&&typeof s=="object"){let n=s;n.type==="text"&&typeof n.text=="string"?t.push(n.text):n.type==="image"&&t.push("[image]")}return t.join(`
763
+ `)}return""}function sm(e){if(!e)return{text:"",toolNames:[]};if(typeof e.content=="string")return{text:hn(e.content),toolNames:[]};if(!Array.isArray(e.content))return{text:"",toolNames:[]};let t=[],s=[];for(let n of e.content)if(!(!n||typeof n!="object")){if(n.type==="text"&&typeof n.text=="string"){t.push(hn(n.text));continue}if(n.type==="tool_use"&&typeof n.name=="string"){s.push(n.name);let r=n.input!=null?em(n.input):"",o=Oo(r,"tool input");t.push(`\u26A1 **Tool call \xB7 \`${n.name}\`**
764
764
 
765
765
  \`\`\`json
766
766
  ${o}
767
- \`\`\``);continue}if(n.type==="tool_result"){let r=an(Ou(n));if(r){let o=ho(r,"tool result");t.push(`**Tool result**
767
+ \`\`\``);continue}if(n.type==="tool_result"){let r=hn(tm(n));if(r){let o=Oo(r,"tool result");t.push(`**Tool result**
768
768
 
769
769
  \`\`\`
770
770
  ${o}
771
771
  \`\`\``)}else t.push("_(tool result was empty or image-only)_");continue}if(n.type==="image"){t.push("_(image)_");continue}t.push(`_(unknown block: ${n.type})_`)}return{text:t.join(`
772
772
 
773
- `),toolNames:s}}async function*Eo(e){let t=ku(e,{encoding:"utf8"}),s=Cu({input:t,crlfDelay:1/0});for await(let n of s){if(!n.trim())continue;let r;try{r=JSON.parse(n)}catch{continue}if(!r.uuid||!r.sessionId)continue;let{text:o,toolNames:i}=Au(r.message);yield{uuid:r.uuid,parentUuid:r.parentUuid??null,sessionId:r.sessionId,type:r.type??"unknown",role:r.message?.role??null,timestamp:r.timestamp??null,isSidechain:r.isSidechain===!0,cwd:r.cwd??null,gitBranch:r.gitBranch??null,version:r.version??null,contentText:o,toolNames:i,raw:n,usage:ln(r.message),model:r.message?.model??null}}}M();var So=[{name:"Anthropic API key",regex:/sk-ant-[a-zA-Z0-9_\-]{40,}/g,severity:"high"},{name:"OpenAI API key",regex:/sk-(?:proj-)?[a-zA-Z0-9]{32,}/g,severity:"high"},{name:"AWS access key ID",regex:/AKIA[0-9A-Z]{16}/g,severity:"high"},{name:"GitHub PAT",regex:/gh[pousr]_[A-Za-z0-9]{20,}/g,severity:"high"},{name:"Stripe live/test key",regex:/(?:sk|rk|pk)_(?:live|test)_[a-zA-Z0-9]{24,}/g,severity:"high"},{name:"Slack token",regex:/xox[abprs]-[A-Za-z0-9\-]{10,}/g,severity:"high"},{name:"Google API key",regex:/AIza[0-9A-Za-z_\-]{35}/g,severity:"high"},{name:"Private key block",regex:/-----BEGIN (?:RSA |DSA |EC |OPENSSH |ENCRYPTED )?PRIVATE KEY-----/g,severity:"high"},{name:"Apify token",regex:/apify_api_[A-Za-z0-9]{20,}/g,severity:"high"},{name:"Notion integration",regex:/(?:secret_|ntn_)[A-Za-z0-9]{40,}/g,severity:"high"},{name:"Vercel token",regex:/vercel_[A-Za-z0-9]{24,}/g,severity:"high"},{name:"Supabase service key",regex:/sbp_[A-Za-z0-9]{40,}/g,severity:"high"},{name:"SendGrid key",regex:/SG\.[A-Za-z0-9_\-]{20,}\.[A-Za-z0-9_\-]{20,}/g,severity:"high"},{name:"Mailgun key",regex:/key-[a-f0-9]{32}/g,severity:"high"},{name:"Twilio SID",regex:/AC[a-f0-9]{32}/g,severity:"high"},{name:"Discord bot token",regex:/[MN][A-Za-z\d]{23}\.[\w-]{6}\.[\w-]{27,38}/g,severity:"high"},{name:"npm token",regex:/npm_[A-Za-z0-9]{36}/g,severity:"high"},{name:"HuggingFace token",regex:/hf_[A-Za-z0-9]{30,}/g,severity:"high"},{name:"Replicate token",regex:/r8_[A-Za-z0-9]{32,}/g,severity:"high"},{name:"Figma token",regex:/figd_[A-Za-z0-9_\-]{30,}/g,severity:"high"},{name:"Linear key",regex:/lin_api_[A-Za-z0-9]{30,}/g,severity:"high"},{name:"DigitalOcean token",regex:/dop_v1_[a-f0-9]{64}/g,severity:"high"},{name:"Generic provider token",regex:/\b[a-z][a-z0-9]{2,20}_(?:api|pat|token|sk|pk|key|auth)_(?=[A-Za-z0-9_\-]*\d)[A-Za-z0-9_\-]{20,}\b/g,severity:"high"},{name:"Bearer token",regex:/\b[Bb]earer\s+[A-Za-z0-9_\-\.=]{24,}\b/g,severity:"medium"},{name:"Slack webhook URL",regex:/https:\/\/hooks\.slack\.com\/services\/T[A-Z0-9]+\/B[A-Z0-9]+\/[A-Za-z0-9]{20,}/g,severity:"high"},{name:"Discord webhook URL",regex:/https:\/\/(?:ptb\.|canary\.)?discord(?:app)?\.com\/api\/webhooks\/\d+\/[A-Za-z0-9_\-]{40,}/g,severity:"high"},{name:"Teams webhook URL",regex:/https:\/\/[a-zA-Z0-9.\-]+\.webhook\.office\.com\/webhookb2\/[A-Za-z0-9@_\-\/]{30,}/g,severity:"high"},{name:"Secret near keyword",regex:/\b(?:webhook[_\s\-]?secret|signing[_\s\-]?secret|webhook[_\s\-]?signing[_\s\-]?secret|api[_\s\-]?secret|client[_\s\-]?secret|private[_\s\-]?key|access[_\s\-]?token|auth[_\s\-]?token|api[_\s\-]?key)\b[\s\S]{0,200}?\b(?:[a-fA-F0-9]{32,}|[A-Za-z0-9+/_\-]{20,}(?:\.[A-Za-z0-9+/_\-]{10,}){1,2}|[A-Za-z0-9+/_\-]{40,}={0,2})\b/gi,severity:"high"},{name:"JWT",regex:/eyJ[a-zA-Z0-9_\-]{10,}\.[a-zA-Z0-9_\-]{10,}\.[a-zA-Z0-9_\-]{10,}/g,severity:"medium"},{name:"URL with password",regex:/https?:\/\/[^:\s/@]+:[^@\s]{6,}@[^\s/]+/g,severity:"high"},{name:"Password assignment",regex:/(?<![A-Za-z])(?:password|passwd|pwd|secret|token|api[_\-]?key|access[_\-]?key|auth[_\-]?token|webhook[_\-]?secret|client[_\-]?secret|private[_\-]?key)\b\s*[:=]\s*["']?[A-Za-z0-9_\-+/=]{16,}/gi,severity:"high"}];function yo(e){if(e.length<=8)return e.slice(0,2)+"\u2022".repeat(Math.max(0,e.length-4))+e.slice(-2);let t=e.slice(0,Math.min(6,Math.floor(e.length/3))),s=e.slice(-Math.min(4,Math.floor(e.length/4)));return`${t}${"\u2022".repeat(Math.max(3,e.length-t.length-s.length))}${s}`}function At(e){if(!e)return[];let t=new Set,s=[];for(let n of So){n.regex.lastIndex=0;for(let r of e.matchAll(n.regex)){let o=r[0],i=`${n.name}::${To(o)}`;t.has(i)||(t.add(i),s.push({pattern:n.name,maskedPreview:yo(o),offset:r.index??0,severity:n.severity}))}}return s}function To(e){let t=5381;for(let s=0;s<e.length;s++)t=(t<<5)+t+e.charCodeAt(s)|0;return(t>>>0).toString(36)}function Ye(e){if(!e)return{redacted:e,count:0};let t=e,s=0,n=new Set;for(let r of So)r.regex.lastIndex=0,t=t.replace(r.regex,o=>{let i=`${r.name}::${To(o)}`;return n.has(i)||(n.add(i),s+=1),`[REDACTED ${r.name}: ${yo(o)}]`});return{redacted:t,count:s}}function wo(e,t,s){e.prepare("DELETE FROM message_usage WHERE session_id = ?").run(t);let n=e.prepare(`
773
+ `),toolNames:s}}async function*Ao(e){let t=Vu(e,{encoding:"utf8"}),s=Zu({input:t,crlfDelay:1/0});for await(let n of s){if(!n.trim())continue;let r;try{r=JSON.parse(n)}catch{continue}if(!r.uuid||!r.sessionId)continue;let{text:o,toolNames:i}=sm(r.message);yield{uuid:r.uuid,parentUuid:r.parentUuid??null,sessionId:r.sessionId,type:r.type??"unknown",role:r.message?.role??null,timestamp:r.timestamp??null,isSidechain:r.isSidechain===!0,cwd:r.cwd??null,gitBranch:r.gitBranch??null,version:r.version??null,contentText:o,toolNames:i,raw:n,usage:bn(r.message),model:r.message?.model??null}}}I();var vo=[{name:"Anthropic API key",regex:/sk-ant-[a-zA-Z0-9_\-]{40,}/g,severity:"high"},{name:"OpenAI API key",regex:/sk-(?:proj-)?[a-zA-Z0-9]{32,}/g,severity:"high"},{name:"AWS access key ID",regex:/AKIA[0-9A-Z]{16}/g,severity:"high"},{name:"GitHub PAT",regex:/gh[pousr]_[A-Za-z0-9]{20,}/g,severity:"high"},{name:"Stripe live/test key",regex:/(?:sk|rk|pk)_(?:live|test)_[a-zA-Z0-9]{24,}/g,severity:"high"},{name:"Slack token",regex:/xox[abprs]-[A-Za-z0-9\-]{10,}/g,severity:"high"},{name:"Google API key",regex:/AIza[0-9A-Za-z_\-]{35}/g,severity:"high"},{name:"Private key block",regex:/-----BEGIN (?:RSA |DSA |EC |OPENSSH |ENCRYPTED )?PRIVATE KEY-----/g,severity:"high"},{name:"Apify token",regex:/apify_api_[A-Za-z0-9]{20,}/g,severity:"high"},{name:"Notion integration",regex:/(?:secret_|ntn_)[A-Za-z0-9]{40,}/g,severity:"high"},{name:"Vercel token",regex:/vercel_[A-Za-z0-9]{24,}/g,severity:"high"},{name:"Supabase service key",regex:/sbp_[A-Za-z0-9]{40,}/g,severity:"high"},{name:"SendGrid key",regex:/SG\.[A-Za-z0-9_\-]{20,}\.[A-Za-z0-9_\-]{20,}/g,severity:"high"},{name:"Mailgun key",regex:/key-[a-f0-9]{32}/g,severity:"high"},{name:"Twilio SID",regex:/AC[a-f0-9]{32}/g,severity:"high"},{name:"Discord bot token",regex:/[MN][A-Za-z\d]{23}\.[\w-]{6}\.[\w-]{27,38}/g,severity:"high"},{name:"npm token",regex:/npm_[A-Za-z0-9]{36}/g,severity:"high"},{name:"HuggingFace token",regex:/hf_[A-Za-z0-9]{30,}/g,severity:"high"},{name:"Replicate token",regex:/r8_[A-Za-z0-9]{32,}/g,severity:"high"},{name:"Figma token",regex:/figd_[A-Za-z0-9_\-]{30,}/g,severity:"high"},{name:"Linear key",regex:/lin_api_[A-Za-z0-9]{30,}/g,severity:"high"},{name:"DigitalOcean token",regex:/dop_v1_[a-f0-9]{64}/g,severity:"high"},{name:"Generic provider token",regex:/\b[a-z][a-z0-9]{2,20}_(?:api|pat|token|sk|pk|key|auth)_(?=[A-Za-z0-9_\-]*\d)[A-Za-z0-9_\-]{20,}\b/g,severity:"high"},{name:"Bearer token",regex:/\b[Bb]earer\s+[A-Za-z0-9_\-\.=]{24,}\b/g,severity:"medium"},{name:"Slack webhook URL",regex:/https:\/\/hooks\.slack\.com\/services\/T[A-Z0-9]+\/B[A-Z0-9]+\/[A-Za-z0-9]{20,}/g,severity:"high"},{name:"Discord webhook URL",regex:/https:\/\/(?:ptb\.|canary\.)?discord(?:app)?\.com\/api\/webhooks\/\d+\/[A-Za-z0-9_\-]{40,}/g,severity:"high"},{name:"Teams webhook URL",regex:/https:\/\/[a-zA-Z0-9.\-]+\.webhook\.office\.com\/webhookb2\/[A-Za-z0-9@_\-\/]{30,}/g,severity:"high"},{name:"Secret near keyword",regex:/\b(?:webhook[_\s\-]?secret|signing[_\s\-]?secret|webhook[_\s\-]?signing[_\s\-]?secret|api[_\s\-]?secret|client[_\s\-]?secret|private[_\s\-]?key|access[_\s\-]?token|auth[_\s\-]?token|api[_\s\-]?key)\b[\s\S]{0,200}?\b(?:[a-fA-F0-9]{32,}|[A-Za-z0-9+/_\-]{20,}(?:\.[A-Za-z0-9+/_\-]{10,}){1,2}|[A-Za-z0-9+/_\-]{40,}={0,2})\b/gi,severity:"high"},{name:"JWT",regex:/eyJ[a-zA-Z0-9_\-]{10,}\.[a-zA-Z0-9_\-]{10,}\.[a-zA-Z0-9_\-]{10,}/g,severity:"medium"},{name:"URL with password",regex:/https?:\/\/[^:\s/@]+:[^@\s]{6,}@[^\s/]+/g,severity:"high"},{name:"Password assignment",regex:/(?<![A-Za-z])(?:password|passwd|pwd|secret|token|api[_\-]?key|access[_\-]?key|auth[_\-]?token|webhook[_\-]?secret|client[_\-]?secret|private[_\-]?key)\b\s*[:=]\s*["']?[A-Za-z0-9_\-+/=]{16,}/gi,severity:"high"}];function Mo(e){if(e.length<=8)return e.slice(0,2)+"\u2022".repeat(Math.max(0,e.length-4))+e.slice(-2);let t=e.slice(0,Math.min(6,Math.floor(e.length/3))),s=e.slice(-Math.min(4,Math.floor(e.length/4)));return`${t}${"\u2022".repeat(Math.max(3,e.length-t.length-s.length))}${s}`}function Dt(e){if(!e)return[];let t=new Set,s=[];for(let n of vo){n.regex.lastIndex=0;for(let r of e.matchAll(n.regex)){let o=r[0],i=`${n.name}::${Do(o)}`;t.has(i)||(t.add(i),s.push({pattern:n.name,maskedPreview:Mo(o),offset:r.index??0,severity:n.severity}))}}return s}function Do(e){let t=5381;for(let s=0;s<e.length;s++)t=(t<<5)+t+e.charCodeAt(s)|0;return(t>>>0).toString(36)}function Ke(e){if(!e)return{redacted:e,count:0};let t=e,s=0,n=new Set;for(let r of vo)r.regex.lastIndex=0,t=t.replace(r.regex,o=>{let i=`${r.name}::${Do(o)}`;return n.has(i)||(n.add(i),s+=1),`[REDACTED ${r.name}: ${Mo(o)}]`});return{redacted:t,count:s}}function $o(e,t,s){e.prepare("DELETE FROM message_usage WHERE session_id = ?").run(t);let n=e.prepare(`
774
774
  INSERT INTO message_usage (
775
775
  message_uuid, session_id, model,
776
776
  input_tokens, output_tokens, cache_create_tokens, cache_read_tokens,
@@ -787,7 +787,7 @@ ${o}
787
787
  cache_create_tokens = excluded.cache_create_tokens,
788
788
  cache_read_tokens = excluded.cache_read_tokens,
789
789
  timestamp = excluded.timestamp
790
- `);for(let r of s)r.usage&&r.role==="assistant"&&n.run({uuid:r.uuid,session_id:t,model:r.model,input:r.usage.inputTokens,output:r.usage.outputTokens,cc:r.usage.cacheCreateTokens,cr:r.usage.cacheReadTokens,ts:r.timestamp})}function ts(e,t){let s=e.prepare(`SELECT
790
+ `);for(let r of s)r.usage&&r.role==="assistant"&&n.run({uuid:r.uuid,session_id:t,model:r.model,input:r.usage.inputTokens,output:r.usage.outputTokens,cc:r.usage.cacheCreateTokens,cr:r.usage.cacheReadTokens,ts:r.timestamp})}function os(e,t){let s=e.prepare(`SELECT
791
791
  COALESCE(SUM(input_tokens), 0) AS input_tokens,
792
792
  COALESCE(SUM(output_tokens), 0) AS output_tokens,
793
793
  COALESCE(SUM(cache_create_tokens), 0) AS cache_create_tokens,
@@ -802,17 +802,17 @@ ${o}
802
802
  total_cache_create_tokens = @cc,
803
803
  total_cache_read_tokens = @cr,
804
804
  primary_model = @model
805
- WHERE id = @id`).run({id:t,input:s.input_tokens,output:s.output_tokens,cc:s.cache_create_tokens,cr:s.cache_read_tokens,model:n?.model??null})}T();j();import{writeFileSync as Pu,mkdirSync as Fu,existsSync as Uu}from"node:fs";import{join as ko}from"node:path";T();var Mu=[/^You will receive a sample of user messages from a Claude Cod/i,/^You will receive the first \d+ user messages from a Claude/i,/^Base directory for this skill:/i,/^You are Claude Code in a fresh terminal/i,/^You are extracting a structured Output Index from a Claude/i];var Du=[/^Score this person'?s relevance/i,/^You are a [^\n.]{1,60}co-pilot/i,/^Return ONLY valid JSON/i],$u=[/^Draft (a|an|marketing) [a-z]/i,/^Read the file at /i,/^Read this and then begin/i,/^read this and then begin/i],ju=20;function Ro(e){if(e.auto_title_source==="agent"&&e.auto_title)return"agent";if(e.has_alias)return"manual_alias";if(e.auto_title&&e.auto_title.includes(" \xB7 "))return"fixed_v0.16.1";if(!e.auto_title||e.auto_title.length<ju)return"low_signal";for(let t of Mu)if(t.test(e.auto_title))return"recursive_meta";for(let t of Du)if(t.test(e.auto_title))return"programmatic";for(let t of $u)if(t.test(e.auto_title))return"template_pending";return"clean"}function dn(e){if(!e)return"";let t=e.split("|")[0];return t=t.replace(/\s*\([^)]*\)\s*$/,""),t=t.replace(/\s+/g," ").trim(),t}var pn=ko(R,"titles"),Bu=80,Hu=60,Wu=100;function Xu(e){if(!e)return[];try{let t=JSON.parse(e);if(Array.isArray(t))return t.filter(s=>!!s&&typeof s=="object"&&typeof s.title=="string"&&typeof s.replaced_at=="string")}catch{}return[]}function Co(e){if(!e)return null;let t=e;if(t=t.replace(/```[\s\S]*?```/g," "),t=t.replace(/`[^`]+`/g," "),t=t.replace(/https?:\/\/\S+/g,"[url]"),t=t.replace(/\s+/g," ").trim(),!t)return null;let s=Ju(t,e);if(s)return s;let n=t.match(/^[^.!?\n]{8,}?[.!?]/)?.[0]?.trim();return(n&&n.length<=Bu?n:t.slice(0,Hu)).trim()||null}function Ju(e,t){let s=e.match(/^\/([A-Za-z0-9][A-Za-z0-9_-]*)\s+([\s\S]*)$/);if(s){let n=`/${s[1]}`,r=t.replace(/^\s*\/[A-Za-z0-9][A-Za-z0-9_-]*\s+/,""),o=mn(r);return o?It(`${n} \xB7 ${o}`):n}for(let n of Gu){if(!e.match(n.match))continue;let o=n.prefix,i=n.extract?n.extract(e,t):mn(t);return i?n.completeFromExtract?It(i):It(`${o} \xB7 ${i}`):o}for(let n of Ku){if(!e.match(n.match))continue;let o=n.extract?n.extract(e,t):ss(t);return o?n.completeFromExtract?It(o):It(`${n.prefix} \xB7 ${o}`):n.prefix}return null}var Gu=[{match:/^Draft (?:a|an) brand brief\b/i,prefix:"Draft brand brief"},{match:/^Draft (?:a|an) sales brief\b/i,prefix:"Draft sales brief"},{match:/^Draft (?:a|an) leave-behind\b/i,prefix:"Draft leave-behind"},{match:/^Draft (?:a|an) audio identity brief\b/i,prefix:"Draft audio identity brief"},{match:/^Draft marketing ideas\b/i,prefix:"Draft marketing ideas"},{match:/^Draft (?:a|an) ([a-z]{3,30}(?:\s+[a-z]{3,30}){0,2})\b/i,prefix:"Draft",extract:(e,t)=>{let n=e.match(/^Draft (?:a|an) ([a-z]{3,30}(?:\s+[a-z]{3,30}){0,2})\b/i)?.[1]?.trim(),r=mn(t);return n&&r?`${n} \xB7 ${r}`:n||r}},{match:/^Read the file at /i,prefix:"Read",extract:e=>{let s=e.match(/^Read the file at\s+([^\s]+)/i)?.[1];return s?s.split("/").filter(Boolean).slice(-2).join("/")||s:null}},{match:/^(?:read|inspect) this and then begin\b/i,prefix:"Begin from preamble",completeFromExtract:!0,extract:(e,t)=>Yu(t)},{match:/^Base directory for this skill:/i,prefix:"[skill]",completeFromExtract:!0,extract:(e,t)=>{let s=t.match(/\.claude\/skills\/([^/\s]+)/);return s?.[1]?`[skill] ${s[1]}`:null}},{match:/^You are extracting a structured Output Index/i,prefix:"[output-index]",completeFromExtract:!0,extract:(e,t)=>zu(t)},{match:/^You will receive a sample of user messages from a Claude Code session:/i,prefix:"[meta]",completeFromExtract:!0,extract:(e,t)=>xo(t,"[meta] auto-title (full-arc)")},{match:/^You will receive the first \d+ user messages from a Claude Code session/i,prefix:"[meta]",completeFromExtract:!0,extract:(e,t)=>xo(t,"[meta] auto-title (initial)")},{match:/^You are implementing v\d+\.\d+/i,prefix:"Implementing",completeFromExtract:!0,extract:e=>{let t=e.match(/^You are implementing (v\d+\.\d+\w*)\s*(?:\(([^)]+)\))?/i);if(!t)return null;let s=t[1],n=t[2]?.trim();return n?`Implementing ${s} \xB7 ${n}`:`Implementing ${s}`}}];function zu(e){if(!e)return"[output-index] extractor";let t=e.match(/^Session:\s*([0-9a-f]{8})\b/im),s=e.match(/^Opening prompt:\s*([^\n]{1,140})/im),n=t?.[1]?.trim(),r=s?.[1]?.trim().replace(/\s+/g," "),o=r&&r.length>70?r.slice(0,67)+"\u2026":r;return n&&o?`[output-index] \xB7 ${n} \xB7 ${o}`:n?`[output-index] \xB7 ${n}`:o?`[output-index] \xB7 ${o}`:"[output-index] extractor"}function xo(e,t){if(!e)return t;let s=e.indexOf("Messages:");if(s===-1)return t;let n=e.slice(s+9),r=/^\s*\d+\.\s*([^\n]+)/gm;for(let o of n.matchAll(r)){let i=o[1]?.trim()??"";if(!i)continue;let a=i.replace(/^<[^>]+>[\s\S]*?<\/[^>]+>\s*/g,"").replace(/^\[Pasted text[^\]]*\]\s*/i,"").trim();if(!a||/^<local-command-/.test(a))continue;let l=a.length>60?a.slice(0,57)+"\u2026":a;return`${t} \xB7 ${l}`}return t}function Yu(e){if(!e)return null;let t=e.match(/([\/\w.\-]+\.(?:md|markdown|txt|json|yaml|yml|toml|ts|tsx|js|jsx|py|sql))(?=[\s,;:)\]"'`]|$)/i);if(!t)return null;let s=t[1].split("/").filter(Boolean);return(s[s.length-1]??"").replace(/\.[^.]+$/,"")||null}var Ku=[{match:/^Score this person'?s relevance/i,prefix:"Score relevance",extract:(e,t)=>ss(t)},{match:/^You are a [^\n.]{1,60}co-pilot/i,prefix:"co-pilot",completeFromExtract:!0,extract:(e,t)=>{let n=e.match(/^You are a ([^\n.]{1,60}?)co-pilot/i)?.[1]?.trim(),r=n?`${n} co-pilot`:"co-pilot",o=ss(t);return o?`${r} \xB7 ${o}`:r}},{match:/^Return ONLY valid JSON/i,prefix:"JSON-only",extract:(e,t)=>ss(t)}];function ss(e){let t=/^\s*(Name|Company|Prospect|Author|Brand|Client)\s*:\s*([^\n]+)/gim,s;for(;(s=t.exec(e))!==null;){let n=s[2].trim();if(!n||/^(null|none|n\/a|—|-)$/i.test(n))continue;let r=n.replace(/\s+/g," ");return dn(r)||r}return null}function It(e){return e.slice(0,Wu).trim()}var qu=[/^deep research$/i,/^reference(?: spec)?$/i,/^canonical spec/i,/^product context/i,/^services?(?: overview)?$/i,/^overview$/i,/^(?:introduction|template|instructions|context)$/i],Vu=[/^(?:brand|brand brief|brand summary)$/i,/^(?:known facts?|facts)$/i,/^(?:client|prospect|customer|account)$/i,/^(?:topic|subject|brief|task)$/i,/^(?:about|for|re)$/i];function un(e){let t=e.trim();return t.length<3?!0:qu.some(s=>s.test(t))}function Zu(e){let t=e.trim().replace(/\s*\([^)]*\)\s*$/,"").trim();return Vu.some(s=>s.test(t))}function mn(e){let t=Qu(e);return t===null?null:dn(t)||t}function Qu(e){if(/^\s*Skill smoke test\b/i.test(e))return"smoke test";let t=/(^|\n)#{1,3}\s+([^\n]+?)\s+(?:—|–|-|:)\s+([^\n]{2,80})/g,s,n=[];for(;(s=t.exec(e))!==null;){let l=s[2].trim(),c=s[3].trim().replace(/\s+/g," ");if(!un(c)){if(Zu(l))return c;n.push(c)}}if(n.length>0)return n[0];let r=e.match(/\b(?:Topic|Subject|Brand|About|Client|For|Re)\s*:\s*([^\n]{2,80})/i);if(r?.[1]&&!un(r[1]))return r[1].trim().replace(/\s+/g," ");let o=/===\s*([^=\n]{2,120}?)\s*===/g;for(;(s=o.exec(e))!==null;){let l=s[1].trim().replace(/\.(md|txt|json)$/i,""),c=l.replace(/\s*\([^)]*\)\s*$/,"").trim();if(c&&!un(c)&&!/product context|reference/i.test(l))return c}let i=e.replace(/^Context for this run[^:]*:\s*/i,"");if(i!==e){let l=i.split(`
805
+ WHERE id = @id`).run({id:t,input:s.input_tokens,output:s.output_tokens,cc:s.cache_create_tokens,cr:s.cache_read_tokens,model:n?.model??null})}T();j();import{writeFileSync as lm,mkdirSync as dm,existsSync as um}from"node:fs";import{join as Fo}from"node:path";T();var om=[/^You will receive a sample of user messages from a Claude Cod/i,/^You will receive the first \d+ user messages from a Claude/i,/^Base directory for this skill:/i,/^You are Claude Code in a fresh terminal/i,/^You are extracting a structured Output Index from a Claude/i];var im=[/^Score this person'?s relevance/i,/^You are a [^\n.]{1,60}co-pilot/i,/^Return ONLY valid JSON/i],am=[/^Draft (a|an|marketing) [a-z]/i,/^Read the file at /i,/^Read this and then begin/i,/^read this and then begin/i],cm=20;function jo(e){if(e.auto_title_source==="agent"&&e.auto_title)return"agent";if(e.has_alias)return"manual_alias";if(e.auto_title&&e.auto_title.includes(" \xB7 "))return"fixed_v0.16.1";if(!e.auto_title||e.auto_title.length<cm)return"low_signal";for(let t of om)if(t.test(e.auto_title))return"recursive_meta";for(let t of im)if(t.test(e.auto_title))return"programmatic";for(let t of am)if(t.test(e.auto_title))return"template_pending";return"clean"}function Sn(e){if(!e)return"";let t=e.split("|")[0];return t=t.replace(/\s*\([^)]*\)\s*$/,""),t=t.replace(/\s+/g," ").trim(),t}var Tn=Fo(R,"titles"),mm=80,pm=60,gm=100;function fm(e){if(!e)return[];try{let t=JSON.parse(e);if(Array.isArray(t))return t.filter(s=>!!s&&typeof s=="object"&&typeof s.title=="string"&&typeof s.replaced_at=="string")}catch{}return[]}function Uo(e){if(!e)return null;let t=e;if(t=t.replace(/```[\s\S]*?```/g," "),t=t.replace(/`[^`]+`/g," "),t=t.replace(/https?:\/\/\S+/g,"[url]"),t=t.replace(/\s+/g," ").trim(),!t)return null;let s=_m(t,e);if(s)return s;let n=t.match(/^[^.!?\n]{8,}?[.!?]/)?.[0]?.trim();return(n&&n.length<=mm?n:t.slice(0,pm)).trim()||null}function _m(e,t){let s=e.match(/^\/([A-Za-z0-9][A-Za-z0-9_-]*)\s+([\s\S]*)$/);if(s){let n=`/${s[1]}`,r=t.replace(/^\s*\/[A-Za-z0-9][A-Za-z0-9_-]*\s+/,""),o=wn(r);return o?$t(`${n} \xB7 ${o}`):n}for(let n of hm){if(!e.match(n.match))continue;let o=n.prefix,i=n.extract?n.extract(e,t):wn(t);return i?n.completeFromExtract?$t(i):$t(`${o} \xB7 ${i}`):o}for(let n of Sm){if(!e.match(n.match))continue;let o=n.extract?n.extract(e,t):is(t);return o?n.completeFromExtract?$t(o):$t(`${n.prefix} \xB7 ${o}`):n.prefix}return null}var hm=[{match:/^Draft (?:a|an) brand brief\b/i,prefix:"Draft brand brief"},{match:/^Draft (?:a|an) sales brief\b/i,prefix:"Draft sales brief"},{match:/^Draft (?:a|an) leave-behind\b/i,prefix:"Draft leave-behind"},{match:/^Draft (?:a|an) audio identity brief\b/i,prefix:"Draft audio identity brief"},{match:/^Draft marketing ideas\b/i,prefix:"Draft marketing ideas"},{match:/^Draft (?:a|an) ([a-z]{3,30}(?:\s+[a-z]{3,30}){0,2})\b/i,prefix:"Draft",extract:(e,t)=>{let n=e.match(/^Draft (?:a|an) ([a-z]{3,30}(?:\s+[a-z]{3,30}){0,2})\b/i)?.[1]?.trim(),r=wn(t);return n&&r?`${n} \xB7 ${r}`:n||r}},{match:/^Read the file at /i,prefix:"Read",extract:e=>{let s=e.match(/^Read the file at\s+([^\s]+)/i)?.[1];return s?s.split("/").filter(Boolean).slice(-2).join("/")||s:null}},{match:/^(?:read|inspect) this and then begin\b/i,prefix:"Begin from preamble",completeFromExtract:!0,extract:(e,t)=>bm(t)},{match:/^Base directory for this skill:/i,prefix:"[skill]",completeFromExtract:!0,extract:(e,t)=>{let s=t.match(/\.claude\/skills\/([^/\s]+)/);return s?.[1]?`[skill] ${s[1]}`:null}},{match:/^You are extracting a structured Output Index/i,prefix:"[output-index]",completeFromExtract:!0,extract:(e,t)=>Em(t)},{match:/^You will receive a sample of user messages from a Claude Code session:/i,prefix:"[meta]",completeFromExtract:!0,extract:(e,t)=>Po(t,"[meta] auto-title (full-arc)")},{match:/^You will receive the first \d+ user messages from a Claude Code session/i,prefix:"[meta]",completeFromExtract:!0,extract:(e,t)=>Po(t,"[meta] auto-title (initial)")},{match:/^You are implementing v\d+\.\d+/i,prefix:"Implementing",completeFromExtract:!0,extract:e=>{let t=e.match(/^You are implementing (v\d+\.\d+\w*)\s*(?:\(([^)]+)\))?/i);if(!t)return null;let s=t[1],n=t[2]?.trim();return n?`Implementing ${s} \xB7 ${n}`:`Implementing ${s}`}}];function Em(e){if(!e)return"[output-index] extractor";let t=e.match(/^Session:\s*([0-9a-f]{8})\b/im),s=e.match(/^Opening prompt:\s*([^\n]{1,140})/im),n=t?.[1]?.trim(),r=s?.[1]?.trim().replace(/\s+/g," "),o=r&&r.length>70?r.slice(0,67)+"\u2026":r;return n&&o?`[output-index] \xB7 ${n} \xB7 ${o}`:n?`[output-index] \xB7 ${n}`:o?`[output-index] \xB7 ${o}`:"[output-index] extractor"}function Po(e,t){if(!e)return t;let s=e.indexOf("Messages:");if(s===-1)return t;let n=e.slice(s+9),r=/^\s*\d+\.\s*([^\n]+)/gm;for(let o of n.matchAll(r)){let i=o[1]?.trim()??"";if(!i)continue;let a=i.replace(/^<[^>]+>[\s\S]*?<\/[^>]+>\s*/g,"").replace(/^\[Pasted text[^\]]*\]\s*/i,"").trim();if(!a||/^<local-command-/.test(a))continue;let l=a.length>60?a.slice(0,57)+"\u2026":a;return`${t} \xB7 ${l}`}return t}function bm(e){if(!e)return null;let t=e.match(/([\/\w.\-]+\.(?:md|markdown|txt|json|yaml|yml|toml|ts|tsx|js|jsx|py|sql))(?=[\s,;:)\]"'`]|$)/i);if(!t)return null;let s=t[1].split("/").filter(Boolean);return(s[s.length-1]??"").replace(/\.[^.]+$/,"")||null}var Sm=[{match:/^Score this person'?s relevance/i,prefix:"Score relevance",extract:(e,t)=>is(t)},{match:/^You are a [^\n.]{1,60}co-pilot/i,prefix:"co-pilot",completeFromExtract:!0,extract:(e,t)=>{let n=e.match(/^You are a ([^\n.]{1,60}?)co-pilot/i)?.[1]?.trim(),r=n?`${n} co-pilot`:"co-pilot",o=is(t);return o?`${r} \xB7 ${o}`:r}},{match:/^Return ONLY valid JSON/i,prefix:"JSON-only",extract:(e,t)=>is(t)}];function is(e){let t=/^\s*(Name|Company|Prospect|Author|Brand|Client)\s*:\s*([^\n]+)/gim,s;for(;(s=t.exec(e))!==null;){let n=s[2].trim();if(!n||/^(null|none|n\/a|—|-)$/i.test(n))continue;let r=n.replace(/\s+/g," ");return Sn(r)||r}return null}function $t(e){return e.slice(0,gm).trim()}var ym=[/^deep research$/i,/^reference(?: spec)?$/i,/^canonical spec/i,/^product context/i,/^services?(?: overview)?$/i,/^overview$/i,/^(?:introduction|template|instructions|context)$/i],Tm=[/^(?:brand|brand brief|brand summary)$/i,/^(?:known facts?|facts)$/i,/^(?:client|prospect|customer|account)$/i,/^(?:topic|subject|brief|task)$/i,/^(?:about|for|re)$/i];function yn(e){let t=e.trim();return t.length<3?!0:ym.some(s=>s.test(t))}function wm(e){let t=e.trim().replace(/\s*\([^)]*\)\s*$/,"").trim();return Tm.some(s=>s.test(t))}function wn(e){let t=Rm(e);return t===null?null:Sn(t)||t}function Rm(e){if(/^\s*Skill smoke test\b/i.test(e))return"smoke test";let t=/(^|\n)#{1,3}\s+([^\n]+?)\s+(?:—|–|-|:)\s+([^\n]{2,80})/g,s,n=[];for(;(s=t.exec(e))!==null;){let l=s[2].trim(),c=s[3].trim().replace(/\s+/g," ");if(!yn(c)){if(wm(l))return c;n.push(c)}}if(n.length>0)return n[0];let r=e.match(/\b(?:Topic|Subject|Brand|About|Client|For|Re)\s*:\s*([^\n]{2,80})/i);if(r?.[1]&&!yn(r[1]))return r[1].trim().replace(/\s+/g," ");let o=/===\s*([^=\n]{2,120}?)\s*===/g;for(;(s=o.exec(e))!==null;){let l=s[1].trim().replace(/\.(md|txt|json)$/i,""),c=l.replace(/\s*\([^)]*\)\s*$/,"").trim();if(c&&!yn(c)&&!/product context|reference/i.test(l))return c}let i=e.replace(/^Context for this run[^:]*:\s*/i,"");if(i!==e){let l=i.split(`
806
806
  `).map(c=>c.trim()).find(c=>c.length>=4);if(l)return l.slice(0,60)}let a=e.split(`
807
- `).map(l=>l.trim()).find(l=>l.length>=4);return a?a.slice(0,60):null}function No(e,t,s){let n=t.trim();if(!n)return;let r=_(),o=r.prepare(`SELECT auto_title, auto_title_source, auto_title_generated_at, auto_title_history
808
- FROM sessions WHERE id = ?`).get(e);if(!o||s==="heuristic"&&o.auto_title_source==="agent"&&o.auto_title||o.auto_title===n&&o.auto_title_source===s)return;let i=Xu(o.auto_title_history),a=new Date().toISOString();o.auto_title&&o.auto_title_source&&i.push({title:o.auto_title,source:o.auto_title_source,replaced_at:a}),r.prepare(`UPDATE sessions
807
+ `).map(l=>l.trim()).find(l=>l.length>=4);return a?a.slice(0,60):null}function Bo(e,t,s){let n=t.trim();if(!n)return;let r=_(),o=r.prepare(`SELECT auto_title, auto_title_source, auto_title_generated_at, auto_title_history
808
+ FROM sessions WHERE id = ?`).get(e);if(!o||s==="heuristic"&&o.auto_title_source==="agent"&&o.auto_title||o.auto_title===n&&o.auto_title_source===s)return;let i=fm(o.auto_title_history),a=new Date().toISOString();o.auto_title&&o.auto_title_source&&i.push({title:o.auto_title,source:o.auto_title_source,replaced_at:a}),r.prepare(`UPDATE sessions
809
809
  SET auto_title = ?,
810
810
  auto_title_source = ?,
811
811
  auto_title_generated_at = ?,
812
812
  auto_title_history = ?
813
- WHERE id = ?`).run(n,s,Date.now(),JSON.stringify(i),e),tp(e,n,s,a)}function ep(){P(),Uu(pn)||Fu(pn,{recursive:!0})}function tp(e,t,s,n){try{ep();let r=ko(pn,`${e}.txt`),o=`# Claude Recall auto-title \xB7 session ${e} \xB7 source ${s} \xB7 updated ${n}
814
- `;Pu(r,o+t+`
815
- `)}catch(r){console.error("[autoTitle] mirror write failed:",r)}}import{existsSync as sp,mkdirSync as rw,readFileSync as np,writeFileSync as ow}from"node:fs";import{homedir as rp}from"node:os";import{join as Lo}from"node:path";import{z as gn}from"zod";function op(){return process.env.RECALL_HOME??Lo(rp(),".recall")}function ip(){return Lo(op(),"config.json")}var ap=gn.object({heuristicEnabled:gn.boolean().default(!0),agentEnabled:gn.boolean().default(!1)}),fn={heuristicEnabled:!0,agentEnabled:!1};function cp(){let e=ip();if(!sp(e))return{};try{return JSON.parse(np(e,"utf8"))}catch(t){return console.error("[auto-title-config] failed to parse config.json, using defaults:",t),{}}}function Oo(){let e=cp().autoTitle;if(!e)return{...fn};let t=ap.safeParse({...fn,...e});return t.success?t.data:{...fn}}var dp=[/^<local-command-caveat>/,/^<command-name>/,/^<command-message>/,/^<system-reminder>/,/^<user-prompt-submit-hook>/,/^Caveat: The messages below were generated/i];function up(e){let t=e.trim();return t?dp.some(s=>s.test(t)):!0}function pp(e){let t=e;return t=t.replace(/^(?:<[^>]+>[\s\S]*?<\/[^>]+>\s*)+/,"").trim(),t=t.replace(/^<command-[^>]+>[^<]*<\/command-[^>]+>\s*/gm,"").trim(),!t||up(t)?null:t}function mp(e,t,s){let n=on(t),r=s??n,o=s?lp(s)||s:uo(t),i=e.prepare("SELECT id, decoded_path FROM projects WHERE encoded_path = ?").get(t);if(i)return s&&i.decoded_path!==s&&e.prepare("UPDATE projects SET decoded_path = ?, name = ? WHERE id = ?").run(s,o,i.id),i.id;let a=e.prepare("INSERT INTO projects (encoded_path, decoded_path, name) VALUES (?, ?, ?)").run(t,r,o);return Number(a.lastInsertRowid)}async function gp(e,t,s){let n=e.prepare("SELECT id, file_mtime FROM sessions WHERE file_path = ? LIMIT 1").get(t.sessionFile);if(!s&&n&&n.file_mtime>=t.mtime)return{inserted:!1,sessionCount:0,messageCount:0};let r=new Map,o=null;for await(let g of Eo(t.sessionFile)){let h=r.get(g.sessionId);if(h||(h={sessionId:g.sessionId,entries:[],earliestTimestamp:null,latestTimestamp:null,firstUserMessage:null,userCount:0,assistantCount:0,cwd:null,gitBranch:null,version:null},r.set(g.sessionId,h)),h.entries.push(g),g.timestamp&&((!h.earliestTimestamp||g.timestamp<h.earliestTimestamp)&&(h.earliestTimestamp=g.timestamp),(!h.latestTimestamp||g.timestamp>h.latestTimestamp)&&(h.latestTimestamp=g.timestamp)),g.role==="user"&&!g.isSidechain){if(h.userCount+=1,!h.firstUserMessage&&g.contentText){let E=pp(g.contentText);E&&(h.firstUserMessage=Y(Ye(E).redacted,200))}}else g.role==="assistant"&&!g.isSidechain&&(h.assistantCount+=1);!h.cwd&&g.cwd&&(h.cwd=g.cwd),!h.gitBranch&&g.gitBranch&&(h.gitBranch=g.gitBranch),!h.version&&g.version&&(h.version=g.version),!o&&g.cwd&&(o=g.cwd)}let i=mp(e,t.encodedProject,o),a=new Date().toISOString(),l=e.prepare(`
813
+ WHERE id = ?`).run(n,s,Date.now(),JSON.stringify(i),e),km(e,n,s,a)}function xm(){P(),um(Tn)||dm(Tn,{recursive:!0})}function km(e,t,s,n){try{xm();let r=Fo(Tn,`${e}.txt`),o=`# Claude Recall auto-title \xB7 session ${e} \xB7 source ${s} \xB7 updated ${n}
814
+ `;lm(r,o+t+`
815
+ `)}catch(r){console.error("[autoTitle] mirror write failed:",r)}}import{existsSync as Nm,mkdirSync as Hw,readFileSync as Cm,writeFileSync as Ww}from"node:fs";import{homedir as Lm}from"node:os";import{join as Ho}from"node:path";import{z as Rn}from"zod";function Om(){return process.env.RECALL_HOME??Ho(Lm(),".recall")}function Am(){return Ho(Om(),"config.json")}var Im=Rn.object({heuristicEnabled:Rn.boolean().default(!0),agentEnabled:Rn.boolean().default(!1)}),xn={heuristicEnabled:!0,agentEnabled:!1};function vm(){let e=Am();if(!Nm(e))return{};try{return JSON.parse(Cm(e,"utf8"))}catch(t){return console.error("[auto-title-config] failed to parse config.json, using defaults:",t),{}}}function Wo(){let e=vm().autoTitle;if(!e)return{...xn};let t=Im.safeParse({...xn,...e});return t.success?t.data:{...xn}}var Dm=[/^<local-command-caveat>/,/^<command-name>/,/^<command-message>/,/^<system-reminder>/,/^<user-prompt-submit-hook>/,/^Caveat: The messages below were generated/i];function $m(e){let t=e.trim();return t?Dm.some(s=>s.test(t)):!0}function jm(e){let t=e;return t=t.replace(/^(?:<[^>]+>[\s\S]*?<\/[^>]+>\s*)+/,"").trim(),t=t.replace(/^<command-[^>]+>[^<]*<\/command-[^>]+>\s*/gm,"").trim(),!t||$m(t)?null:t}function Pm(e,t,s){let n=_n(t),r=s??n,o=s?Mm(s)||s:Ro(t),i=e.prepare("SELECT id, decoded_path FROM projects WHERE encoded_path = ?").get(t);if(i)return s&&i.decoded_path!==s&&e.prepare("UPDATE projects SET decoded_path = ?, name = ? WHERE id = ?").run(s,o,i.id),i.id;let a=e.prepare("INSERT INTO projects (encoded_path, decoded_path, name) VALUES (?, ?, ?)").run(t,r,o);return Number(a.lastInsertRowid)}async function Fm(e,t,s){let n=e.prepare("SELECT id, file_mtime FROM sessions WHERE file_path = ? LIMIT 1").get(t.sessionFile);if(!s&&n&&n.file_mtime>=t.mtime)return{inserted:!1,sessionCount:0,messageCount:0};let r=new Map,o=null;for await(let g of Ao(t.sessionFile)){let h=r.get(g.sessionId);if(h||(h={sessionId:g.sessionId,entries:[],earliestTimestamp:null,latestTimestamp:null,firstUserMessage:null,userCount:0,assistantCount:0,cwd:null,gitBranch:null,version:null},r.set(g.sessionId,h)),h.entries.push(g),g.timestamp&&((!h.earliestTimestamp||g.timestamp<h.earliestTimestamp)&&(h.earliestTimestamp=g.timestamp),(!h.latestTimestamp||g.timestamp>h.latestTimestamp)&&(h.latestTimestamp=g.timestamp)),g.role==="user"&&!g.isSidechain){if(h.userCount+=1,!h.firstUserMessage&&g.contentText){let E=jm(g.contentText);E&&(h.firstUserMessage=Y(Ke(E).redacted,200))}}else g.role==="assistant"&&!g.isSidechain&&(h.assistantCount+=1);!h.cwd&&g.cwd&&(h.cwd=g.cwd),!h.gitBranch&&g.gitBranch&&(h.gitBranch=g.gitBranch),!h.version&&g.version&&(h.version=g.version),!o&&g.cwd&&(o=g.cwd)}let i=Pm(e,t.encodedProject,o),a=new Date().toISOString(),l=e.prepare(`
816
816
  INSERT INTO sessions (
817
817
  id, project_id, file_path, file_mtime,
818
818
  started_at, ended_at, message_count,
@@ -847,30 +847,30 @@ ${o}
847
847
  @is_sidechain, @content_text, @tool_names, @raw_json
848
848
  )
849
849
  ON CONFLICT(uuid) DO NOTHING
850
- `),u=e.prepare("DELETE FROM messages WHERE session_id = ?"),p=0,m=0;if(e.transaction(()=>{for(let g of r.values()){l.run({id:g.sessionId,project_id:i,file_path:t.sessionFile,file_mtime:t.mtime,started_at:g.earliestTimestamp,ended_at:g.latestTimestamp,message_count:g.entries.length,user_message_count:g.userCount,assistant_message_count:g.assistantCount,first_user_message:g.firstUserMessage,cwd:g.cwd,git_branch:g.gitBranch,version:g.version,indexed_at:a}),u.run(g.sessionId);for(let h of g.entries){let{redacted:E}=Ye(h.contentText),{redacted:b}=Ye(h.raw);c.run({uuid:h.uuid,session_id:h.sessionId,parent_uuid:h.parentUuid,type:h.type,role:h.role,timestamp:h.timestamp,is_sidechain:h.isSidechain?1:0,content_text:E,tool_names:h.toolNames.join(","),raw_json:b}),m+=1}wo(e,g.sessionId,g.entries),ts(e,g.sessionId),p+=1}})(),Oo().heuristicEnabled)for(let g of r.values()){let h=Co(g.firstUserMessage);h&&No(g.sessionId,h,"heuristic")}return{inserted:!0,sessionCount:p,messageCount:m}}async function Ao(e){let t=_(),s=po();console.log(d.dim(`Scanning ${s.length} JSONL session files under ~/.claude/projects/`));let n=0,r=0,o=0,i=0,a=Date.now();for(let c of s)try{let u=await gp(t,c,e.force??!1);u.inserted?(n+=1,o+=u.sessionCount,i+=u.messageCount,e.verbose&&console.log(d.dim(` + ${c.sessionFile.split("/").slice(-2).join("/")} (${u.messageCount} msgs)`))):r+=1}catch(u){console.error(d.err(` ! failed: ${c.sessionFile}`),u)}let l=((Date.now()-a)/1e3).toFixed(1);console.log(""),console.log(`${d.ok("indexed")}: ${d.bold(String(n))} files, ${d.bold(String(o))} sessions, ${d.bold(String(i))} messages ${d.dim(`in ${l}s`)}`),r>0&&console.log(d.dim(`skipped: ${r} unchanged files (use --force to reindex)`))}T();M();import fp from"cli-table3";function Io(e){let t=_(),n={limit:Math.max(1,Math.min(500,parseInt(e.limit??"30",10)||30))},r="1=1";e.project&&(r+=" AND (p.name LIKE @proj OR p.decoded_path LIKE @proj OR p.encoded_path LIKE @proj)",n.proj=`%${e.project}%`),e.all||(r+=" AND s.message_count > 2");let o=t.prepare(`SELECT s.id, p.name AS project_name, s.started_at,
850
+ `),u=e.prepare("DELETE FROM messages WHERE session_id = ?"),m=0,p=0;if(e.transaction(()=>{for(let g of r.values()){l.run({id:g.sessionId,project_id:i,file_path:t.sessionFile,file_mtime:t.mtime,started_at:g.earliestTimestamp,ended_at:g.latestTimestamp,message_count:g.entries.length,user_message_count:g.userCount,assistant_message_count:g.assistantCount,first_user_message:g.firstUserMessage,cwd:g.cwd,git_branch:g.gitBranch,version:g.version,indexed_at:a}),u.run(g.sessionId);for(let h of g.entries){let{redacted:E}=Ke(h.contentText),{redacted:b}=Ke(h.raw);c.run({uuid:h.uuid,session_id:h.sessionId,parent_uuid:h.parentUuid,type:h.type,role:h.role,timestamp:h.timestamp,is_sidechain:h.isSidechain?1:0,content_text:E,tool_names:h.toolNames.join(","),raw_json:b}),p+=1}$o(e,g.sessionId,g.entries),os(e,g.sessionId),m+=1}})(),Wo().heuristicEnabled)for(let g of r.values()){let h=Uo(g.firstUserMessage);h&&Bo(g.sessionId,h,"heuristic")}return{inserted:!0,sessionCount:m,messageCount:p}}async function Xo(e){let t=_(),s=xo();console.log(d.dim(`Scanning ${s.length} JSONL session files under ~/.claude/projects/`));let n=0,r=0,o=0,i=0,a=Date.now();for(let c of s)try{let u=await Fm(t,c,e.force??!1);u.inserted?(n+=1,o+=u.sessionCount,i+=u.messageCount,e.verbose&&console.log(d.dim(` + ${c.sessionFile.split("/").slice(-2).join("/")} (${u.messageCount} msgs)`))):r+=1}catch(u){console.error(d.err(` ! failed: ${c.sessionFile}`),u)}let l=((Date.now()-a)/1e3).toFixed(1);console.log(""),console.log(`${d.ok("indexed")}: ${d.bold(String(n))} files, ${d.bold(String(o))} sessions, ${d.bold(String(i))} messages ${d.dim(`in ${l}s`)}`),r>0&&console.log(d.dim(`skipped: ${r} unchanged files (use --force to reindex)`))}T();I();import Um from"cli-table3";function Jo(e){let t=_(),n={limit:Math.max(1,Math.min(500,parseInt(e.limit??"30",10)||30))},r="1=1";e.project&&(r+=" AND (p.name LIKE @proj OR p.decoded_path LIKE @proj OR p.encoded_path LIKE @proj)",n.proj=`%${e.project}%`),e.all||(r+=" AND s.message_count > 2");let o=t.prepare(`SELECT s.id, p.name AS project_name, s.started_at,
851
851
  s.message_count, s.first_user_message, s.git_branch
852
852
  FROM sessions s
853
853
  JOIN projects p ON p.id = s.project_id
854
854
  WHERE ${r}
855
855
  ORDER BY COALESCE(s.started_at, '') DESC
856
- LIMIT @limit`).all(n);if(o.length===0){console.log(d.dim("no sessions found. run `recall index` first."));return}let i=new fp({head:[d.bold("id"),d.bold("project"),d.bold("when"),d.bold("msgs"),d.bold("opening prompt")],colWidths:[10,22,14,6,70],wordWrap:!0,style:{head:[],border:["grey"]}});for(let a of o)i.push([d.accent(H(a.id)),d.project(Y(a.project_name,20)),d.dim(W(a.started_at)),String(a.message_count),Y(a.first_user_message,200)]);console.log(i.toString()),console.log(d.dim(`showing ${o.length} session${o.length===1?"":"s"}. use \`recall show <id>\` to view one.`))}T();M();import{spawn as xp}from"node:child_process";import{readFileSync as _p,writeFileSync as hp,mkdirSync as Ep,chmodSync as bp}from"node:fs";import{join as vo}from"node:path";import{homedir as Mo}from"node:os";function Do(){return vo(Mo(),".recall","config.json")}function $o(){try{return JSON.parse(_p(Do(),"utf-8"))}catch{return{}}}function Sp(e){let t=Do();Ep(vo(Mo(),".recall"),{recursive:!0}),hp(t,JSON.stringify(e,null,2)+`
857
- `,"utf-8"),bp(t,384)}function ns(){let t=$o().verification;return typeof t=="object"&&t!==null&&"enabled"in t?!!t.enabled:!1}function _n(e){let t=$o();t.verification={...typeof t.verification=="object"&&t.verification!==null?t.verification:{},enabled:e},Sp(t)}T();var yp=[/\btask\s+complete/i,/\bdone\b/i,/\bfinished\b/i,/\bimplemented\b/i,/\bcompleted\b/i,/\bshipped\b/i,/\ball\s+(?:tests?\s+)?pass/i,/\bsuccessfully\b/i],Tp=1440*60*1e3;function wp(e){let t=_(),s=t.prepare(`SELECT content_text, tool_names FROM messages
856
+ LIMIT @limit`).all(n);if(o.length===0){console.log(d.dim("no sessions found. run `recall index` first."));return}let i=new Um({head:[d.bold("id"),d.bold("project"),d.bold("when"),d.bold("msgs"),d.bold("opening prompt")],colWidths:[10,22,14,6,70],wordWrap:!0,style:{head:[],border:["grey"]}});for(let a of o)i.push([d.accent(H(a.id)),d.project(Y(a.project_name,20)),d.dim(W(a.started_at)),String(a.message_count),Y(a.first_user_message,200)]);console.log(i.toString()),console.log(d.dim(`showing ${o.length} session${o.length===1?"":"s"}. use \`recall show <id>\` to view one.`))}T();I();import{spawn as qm}from"node:child_process";import{readFileSync as Bm,writeFileSync as Hm,mkdirSync as Wm,chmodSync as Xm}from"node:fs";import{join as Go}from"node:path";import{homedir as zo}from"node:os";function Yo(){return Go(zo(),".recall","config.json")}function Ko(){try{return JSON.parse(Bm(Yo(),"utf-8"))}catch{return{}}}function Jm(e){let t=Yo();Wm(Go(zo(),".recall"),{recursive:!0}),Hm(t,JSON.stringify(e,null,2)+`
857
+ `,"utf-8"),Xm(t,384)}function as(){let t=Ko().verification;return typeof t=="object"&&t!==null&&"enabled"in t?!!t.enabled:!1}function kn(e){let t=Ko();t.verification={...typeof t.verification=="object"&&t.verification!==null?t.verification:{},enabled:e},Jm(t)}T();var Gm=[/\btask\s+complete/i,/\bdone\b/i,/\bfinished\b/i,/\bimplemented\b/i,/\bcompleted\b/i,/\bshipped\b/i,/\ball\s+(?:tests?\s+)?pass/i,/\bsuccessfully\b/i],zm=1440*60*1e3;function Ym(e){let t=_(),s=t.prepare(`SELECT content_text, tool_names FROM messages
858
858
  WHERE session_id = ? AND role = 'assistant'
859
- ORDER BY timestamp DESC LIMIT 5`).all(e),n=!1;for(let l of s)if(l.content_text&&yp.some(c=>c.test(l.content_text))){n=!0;break}let r=t.prepare(`SELECT content_text, tool_names FROM messages
860
- WHERE session_id = ?`).all(e),o={fileWrites:!1,testRuns:!1,commits:!1,buildSuccess:!1};for(let l of r){let c=l.tool_names??"",u=l.content_text??"";/\bWrite\b|\bEdit\b/.test(c)&&(o.fileWrites=!0),/\b(?:jest|pytest|vitest|mocha|test|spec)\b/i.test(u)&&/pass|ok|✓/i.test(u)&&(o.testRuns=!0),/\bgit\s+commit\b/i.test(u)&&(o.commits=!0),(/\bbuild\s+(?:succeeded|success|passed)\b/i.test(u)||/tsc.*(?:0 errors|no errors)/i.test(u))&&(o.buildSuccess=!0)}return n?{status:[o.fileWrites,o.testRuns,o.commits,o.buildSuccess].filter(Boolean).length>=2?"verified":"unverified",evidence:o,claimFound:n}:{status:"neutral",evidence:o,claimFound:n}}function Rp(e){let t=wp(e);return _().prepare("UPDATE sessions SET verification_status = ?, verification_computed_at = ? WHERE id = ?").run(t.status,Date.now(),e),t}function jo(e){let s=_().prepare("SELECT verification_status, verification_computed_at FROM sessions WHERE id = ?").get(e);if(s?.verification_status&&s.verification_computed_at&&Date.now()-s.verification_computed_at<Tp){let n={fileWrites:!1,testRuns:!1,commits:!1,buildSuccess:!1};return{status:s.verification_status,evidence:n,claimFound:s.verification_status!=="neutral"}}return Rp(e)}function kp(e,t){if(t.length>=32)return e.prepare("SELECT id FROM sessions WHERE id = ?").get(t)?.id??null;let s=e.prepare("SELECT id FROM sessions WHERE id LIKE ? LIMIT 2").all(t+"%");return s.length===1?s[0].id:(s.length===0||console.error(d.err(`ambiguous id prefix "${t}". be more specific.`)),null)}function Cp(e,t){let s=_(),n=s.prepare(`SELECT s.id, p.name AS project_name, p.decoded_path,
859
+ ORDER BY timestamp DESC LIMIT 5`).all(e),n=!1;for(let l of s)if(l.content_text&&Gm.some(c=>c.test(l.content_text))){n=!0;break}let r=t.prepare(`SELECT content_text, tool_names FROM messages
860
+ WHERE session_id = ?`).all(e),o={fileWrites:!1,testRuns:!1,commits:!1,buildSuccess:!1};for(let l of r){let c=l.tool_names??"",u=l.content_text??"";/\bWrite\b|\bEdit\b/.test(c)&&(o.fileWrites=!0),/\b(?:jest|pytest|vitest|mocha|test|spec)\b/i.test(u)&&/pass|ok|✓/i.test(u)&&(o.testRuns=!0),/\bgit\s+commit\b/i.test(u)&&(o.commits=!0),(/\bbuild\s+(?:succeeded|success|passed)\b/i.test(u)||/tsc.*(?:0 errors|no errors)/i.test(u))&&(o.buildSuccess=!0)}return n?{status:[o.fileWrites,o.testRuns,o.commits,o.buildSuccess].filter(Boolean).length>=2?"verified":"unverified",evidence:o,claimFound:n}:{status:"neutral",evidence:o,claimFound:n}}function Km(e){let t=Ym(e);return _().prepare("UPDATE sessions SET verification_status = ?, verification_computed_at = ? WHERE id = ?").run(t.status,Date.now(),e),t}function qo(e){let s=_().prepare("SELECT verification_status, verification_computed_at FROM sessions WHERE id = ?").get(e);if(s?.verification_status&&s.verification_computed_at&&Date.now()-s.verification_computed_at<zm){let n={fileWrites:!1,testRuns:!1,commits:!1,buildSuccess:!1};return{status:s.verification_status,evidence:n,claimFound:s.verification_status!=="neutral"}}return Km(e)}function Vm(e,t){if(t.length>=32)return e.prepare("SELECT id FROM sessions WHERE id = ?").get(t)?.id??null;let s=e.prepare("SELECT id FROM sessions WHERE id LIKE ? LIMIT 2").all(t+"%");return s.length===1?s[0].id:(s.length===0||console.error(d.err(`ambiguous id prefix "${t}". be more specific.`)),null)}function Zm(e,t){let s=_(),n=s.prepare(`SELECT s.id, p.name AS project_name, p.decoded_path,
861
861
  s.started_at, s.ended_at, s.message_count,
862
862
  s.git_branch, s.version, s.cwd
863
863
  FROM sessions s
864
864
  JOIN projects p ON p.id = s.project_id
865
- WHERE s.id = ?`).get(e);if(!n)return null;let r=[],o=d.dim("\u2500".repeat(78));if(r.push(""),r.push(d.bold(d.project(n.project_name))+d.dim(` ${n.decoded_path}`)),r.push(d.dim(`session ${n.id} \xB7 ${n.message_count} msgs \xB7 ${W(n.started_at)}`+(n.git_branch?` \xB7 branch: ${n.git_branch}`:""))),ns()){let l=jo(e);l.status==="verified"?r.push(d.ok("\u2713 verified")):l.status==="unverified"&&r.push(d.warn("\u26A0 unverified"))}r.push(o);let i=t.limit?Math.max(1,parseInt(t.limit,10)||9999):9999,a=s.prepare(`SELECT uuid, type, role, timestamp, is_sidechain, content_text, tool_names, raw_json
865
+ WHERE s.id = ?`).get(e);if(!n)return null;let r=[],o=d.dim("\u2500".repeat(78));if(r.push(""),r.push(d.bold(d.project(n.project_name))+d.dim(` ${n.decoded_path}`)),r.push(d.dim(`session ${n.id} \xB7 ${n.message_count} msgs \xB7 ${W(n.started_at)}`+(n.git_branch?` \xB7 branch: ${n.git_branch}`:""))),as()){let l=qo(e);l.status==="verified"?r.push(d.ok("\u2713 verified")):l.status==="unverified"&&r.push(d.warn("\u26A0 unverified"))}r.push(o);let i=t.limit?Math.max(1,parseInt(t.limit,10)||9999):9999,a=s.prepare(`SELECT uuid, type, role, timestamp, is_sidechain, content_text, tool_names, raw_json
866
866
  FROM messages
867
867
  WHERE session_id = ?
868
868
  ORDER BY COALESCE(timestamp, ''), rowid
869
- LIMIT ?`).all(e,i);for(let l of a){if(t.raw){r.push(l.raw_json);continue}let c=l.is_sidechain===1?d.dim(" [subagent]"):"",u=l.role==="user"?d.user("\u25B8 user"):l.role==="assistant"?d.assistant("\u25B8 assistant"):d.dim(`\u25B8 ${l.type}`);if(r.push(`${u}${c} ${d.dim(l.timestamp??"")}`),l.tool_names&&l.tool_names.length>0&&r.push(d.tool(` tools: ${l.tool_names}`)),l.content_text&&l.content_text.trim()){let p=l.content_text.trim().split(`
870
- `).map(m=>" "+m).join(`
871
- `);r.push(p)}r.push("")}return r.push(o),r.push(d.dim(`end of session ${n.id}`)),r.join(`
872
- `)}function Np(e,t){if(!t||!process.stdout.isTTY)return!1;let s=process.stdout.rows||24;return e.split(`
873
- `).length>s}function Lp(e){let t=xp("less",["-R","-F","-X"],{stdio:["pipe","inherit","inherit"]});t.stdin.on("error",()=>{}),t.stdin.write(e),t.stdin.end(),t.on("exit",()=>process.exit(0))}function Po(e,t){let s=_(),n=kp(s,e);if(!n){e.length>=32&&console.error(d.err(`session not found: ${e}`)),process.exitCode=1;return}let r=Cp(n,t);if(r===null){console.error(d.err(`session metadata missing for ${n}`)),process.exitCode=1;return}let o=t.pager!==!1;Np(r,o)?Lp(r):console.log(r)}T();M();Se();function nm(e){let t=e.split(/\s+/).filter(Boolean).map(s=>s.replace(/"/g,"")).filter(s=>s.length>0);return t.length===0?"":t.map(s=>`"${s}"`).join(" ")}async function Vo(e,t){await Ce("Full-text search");let s=_(),n=nm(e);if(!n){console.log(d.dim("empty query"));return}let r=Math.max(1,Math.min(200,parseInt(t.limit??"20",10)||20)),o={q:n,limit:r},i="";t.project&&(i=" AND (p.name LIKE @proj OR p.decoded_path LIKE @proj) ",o.proj=`%${t.project}%`);let a=s.prepare(`SELECT m.session_id AS session_id,
869
+ LIMIT ?`).all(e,i);for(let l of a){if(t.raw){r.push(l.raw_json);continue}let c=l.is_sidechain===1?d.dim(" [subagent]"):"",u=l.role==="user"?d.user("\u25B8 user"):l.role==="assistant"?d.assistant("\u25B8 assistant"):d.dim(`\u25B8 ${l.type}`);if(r.push(`${u}${c} ${d.dim(l.timestamp??"")}`),l.tool_names&&l.tool_names.length>0&&r.push(d.tool(` tools: ${l.tool_names}`)),l.content_text&&l.content_text.trim()){let m=l.content_text.trim().split(`
870
+ `).map(p=>" "+p).join(`
871
+ `);r.push(m)}r.push("")}return r.push(o),r.push(d.dim(`end of session ${n.id}`)),r.join(`
872
+ `)}function Qm(e,t){if(!t||!process.stdout.isTTY)return!1;let s=process.stdout.rows||24;return e.split(`
873
+ `).length>s}function ep(e){let t=qm("less",["-R","-F","-X"],{stdio:["pipe","inherit","inherit"]});t.stdin.on("error",()=>{}),t.stdin.write(e),t.stdin.end(),t.on("exit",()=>process.exit(0))}function Vo(e,t){let s=_(),n=Vm(s,e);if(!n){e.length>=32&&console.error(d.err(`session not found: ${e}`)),process.exitCode=1;return}let r=Zm(n,t);if(r===null){console.error(d.err(`session metadata missing for ${n}`)),process.exitCode=1;return}let o=t.pager!==!1;Qm(r,o)?ep(r):console.log(r)}T();I();fe();function Cp(e){let t=e.split(/\s+/).filter(Boolean).map(s=>s.replace(/"/g,"")).filter(s=>s.length>0);return t.length===0?"":t.map(s=>`"${s}"`).join(" ")}async function di(e,t){await Ce("Full-text search");let s=_(),n=Cp(e);if(!n){console.log(d.dim("empty query"));return}let r=Math.max(1,Math.min(200,parseInt(t.limit??"20",10)||20)),o={q:n,limit:r},i="";t.project&&(i=" AND (p.name LIKE @proj OR p.decoded_path LIKE @proj) ",o.proj=`%${t.project}%`);let a=s.prepare(`SELECT m.session_id AS session_id,
874
874
  p.name AS project_name,
875
875
  s.started_at AS started_at,
876
876
  snippet(messages_fts, 0, '<<', '>>', '\u2026', 16) AS snippet,
@@ -883,13 +883,13 @@ ${o}
883
883
  WHERE messages_fts MATCH @q
884
884
  ${i}
885
885
  ORDER BY bm25(messages_fts)
886
- LIMIT @limit`).all(o);if(a.length===0){console.log(d.dim(`no matches for "${e}"`));return}console.log(d.dim(`${a.length} match${a.length===1?"":"es"} for "${e}"`)),console.log("");for(let l of a){let c=l.snippet.replace(/<<([\s\S]*?)>>/g,(p,m)=>bo(m,m).replace(/\n/g," ")).replace(/\n/g," "),u=l.role==="user"?d.user("user"):l.role==="assistant"?d.assistant("asst"):d.dim("----");console.log(`${d.accent(H(l.session_id))} ${d.project(Y(l.project_name,20))} ${d.dim(W(l.started_at))} ${u}`),console.log(` ${Y(c,200)}`),console.log("")}console.log(d.dim("`recall show <id>` to read any session."))}T();j();He();M();import{statSync as pm,existsSync as mm}from"node:fs";function ei(){if(console.log(""),console.log(d.bold("Claude Recall status")),console.log(d.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),!mm(te)){console.log(d.dim(" no database yet. run `recall index`."));return}let t=_().prepare(`SELECT
886
+ LIMIT @limit`).all(o);if(a.length===0){console.log(d.dim(`no matches for "${e}"`));return}console.log(d.dim(`${a.length} match${a.length===1?"":"es"} for "${e}"`)),console.log("");for(let l of a){let c=l.snippet.replace(/<<([\s\S]*?)>>/g,(m,p)=>Io(p,p).replace(/\n/g," ")).replace(/\n/g," "),u=l.role==="user"?d.user("user"):l.role==="assistant"?d.assistant("asst"):d.dim("----");console.log(`${d.accent(H(l.session_id))} ${d.project(Y(l.project_name,20))} ${d.dim(W(l.started_at))} ${u}`),console.log(` ${Y(c,200)}`),console.log("")}console.log(d.dim("`recall show <id>` to read any session."))}T();j();We();I();import{statSync as jp,existsSync as Pp}from"node:fs";function pi(){if(console.log(""),console.log(d.bold("Claude Recall status")),console.log(d.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),!Pp(te)){console.log(d.dim(" no database yet. run `recall index`."));return}let t=_().prepare(`SELECT
887
887
  (SELECT COUNT(*) FROM projects) AS projects,
888
888
  (SELECT COUNT(*) FROM sessions) AS sessions,
889
889
  (SELECT COUNT(*) FROM messages) AS messages,
890
890
  (SELECT MIN(started_at) FROM sessions WHERE started_at IS NOT NULL) AS earliest,
891
891
  (SELECT MAX(started_at) FROM sessions WHERE started_at IS NOT NULL) AS latest,
892
- (SELECT MAX(indexed_at) FROM sessions) AS last_indexed`).get(),n=(pm(te).size/1024/1024).toFixed(1);console.log(` db path ${d.dim(te)}`),console.log(` db size ${d.accent(n+" MB")}`),console.log(` projects ${d.accent(String(t.projects))}`),console.log(` sessions ${d.accent(String(t.sessions))}`),console.log(` messages ${d.accent(String(t.messages))}`),console.log(` earliest ${d.dim(t.earliest??"n/a")}`),console.log(` latest ${d.dim(t.latest??"n/a")} ${d.dim(W(t.latest))}`),console.log(` last index ${d.dim(t.last_indexed??"never")}`),console.log("");let r=q();r?(console.log(` daemon ${d.ok("running")} pid ${r.pid} \xB7 http://127.0.0.1:${r.port}`),console.log(` started ${d.dim(r.startedAt)} ${d.dim(W(r.startedAt))}`)):console.log(` daemon ${d.dim("stopped")} (run \`recall start\` or \`recall open\`)`),console.log("")}T();M();import gm from"cli-table3";function ti(){let t=_().prepare(`SELECT p.name,
892
+ (SELECT MAX(indexed_at) FROM sessions) AS last_indexed`).get(),n=(jp(te).size/1024/1024).toFixed(1);console.log(` db path ${d.dim(te)}`),console.log(` db size ${d.accent(n+" MB")}`),console.log(` projects ${d.accent(String(t.projects))}`),console.log(` sessions ${d.accent(String(t.sessions))}`),console.log(` messages ${d.accent(String(t.messages))}`),console.log(` earliest ${d.dim(t.earliest??"n/a")}`),console.log(` latest ${d.dim(t.latest??"n/a")} ${d.dim(W(t.latest))}`),console.log(` last index ${d.dim(t.last_indexed??"never")}`),console.log("");let r=q();r?(console.log(` daemon ${d.ok("running")} pid ${r.pid} \xB7 http://127.0.0.1:${r.port}`),console.log(` started ${d.dim(r.startedAt)} ${d.dim(W(r.startedAt))}`)):console.log(` daemon ${d.dim("stopped")} (run \`recall start\` or \`recall open\`)`),console.log("")}T();I();import Fp from"cli-table3";function gi(){let t=_().prepare(`SELECT p.name,
893
893
  p.decoded_path,
894
894
  COUNT(s.id) AS session_count,
895
895
  COALESCE(SUM(s.message_count), 0) AS message_count,
@@ -897,10 +897,10 @@ ${o}
897
897
  FROM projects p
898
898
  LEFT JOIN sessions s ON s.project_id = p.id
899
899
  GROUP BY p.id
900
- ORDER BY MAX(COALESCE(s.started_at, '')) DESC`).all();if(t.length===0){console.log(d.dim("no projects indexed yet."));return}let s=new gm({head:[d.bold("project"),d.bold("sessions"),d.bold("msgs"),d.bold("latest"),d.bold("path")],style:{head:[],border:["grey"]}});for(let n of t)s.push([d.project(Y(n.name,30)),String(n.session_count),String(n.message_count),d.dim(W(n.latest)),d.dim(Y(n.decoded_path,50))]);console.log(s.toString())}He();He();j();M();import{spawn as hm}from"node:child_process";import{openSync as Em}from"node:fs";import{join as bm}from"node:path";import{existsSync as fm}from"node:fs";import{dirname as si}from"node:path";import{fileURLToPath as _m}from"node:url";var us=null;function ye(){if(us)return us;let e=si(_m(import.meta.url));for(;!fm(`${e}/package.json`);){let t=si(e);if(t===e)throw new Error(`package.json not found walking up from ${import.meta.url}`);e=t}return us=e,us}function Sm(){return bm(ye(),"dist","daemon","entrypoint.js")}async function ps(){let e=q();if(e){console.log(`${d.ok("already running")} pid ${e.pid} \xB7 http://127.0.0.1:${e.port}`);return}P();let t=Em(ds,"a"),s=Sm();hm(process.execPath,[s],{detached:!0,stdio:["ignore",t,t],env:{...process.env}}).unref();let r=Date.now();for(;Date.now()-r<5e3;){await new Promise(i=>setTimeout(i,150));let o=q();if(o){console.log(`${d.ok("daemon started")} pid ${o.pid} \xB7 http://127.0.0.1:${o.port}`),console.log(d.dim(`logs: ${ds}`));return}}console.error(d.err("daemon did not come up within 5s \u2014 check the log file")),console.error(d.dim(` ${ds}`)),process.exitCode=1}He();M();async function ni(){let e=q();if(!e){console.log(d.dim("no daemon running.")),vn();return}try{process.kill(e.pid,"SIGTERM")}catch(s){console.error(d.err(`failed to signal pid ${e.pid}: ${s.message}`)),process.exitCode=1;return}let t=Date.now();for(;Date.now()-t<5e3;)if(await new Promise(s=>setTimeout(s,100)),!q()){console.log(d.ok(`stopped daemon pid ${e.pid}`));return}console.error(d.err(`pid ${e.pid} did not exit within 5s \u2014 you may need to kill it manually`)),process.exitCode=1}He();import{spawn as ym}from"node:child_process";import{platform as ms}from"node:os";M();function Tm(e){let t=ms()==="darwin"?"open":ms()==="win32"?"start":"xdg-open",s=ms()==="win32"?["",e]:[e];ym(t,s,{detached:!0,stdio:"ignore",shell:ms()==="win32"}).unref()}async function ri(){let e=q();if(!e&&(console.log(d.dim("daemon not running \u2014 starting it\u2026")),await ps(),e=q(),!e)){console.error(d.err("could not start the daemon. run `recall start` manually and check logs.")),process.exitCode=1;return}let t=`http://127.0.0.1:${e.port}`;console.log(`${d.ok("opening")} ${t}`),Tm(t)}T();var wm=/<(local-command-caveat|local-command-stdout|command-name|command-message|command-args|system-reminder|user-prompt-submit-hook|task-notification)[\s\S]*?<\/\1>/gi,Rm=/⚡ \*\*Tool call · `[^`]+`\*\*\s*\n+```json\n[\s\S]*?\n```/g,xm=/\*\*Tool result\*\*\s*\n+```\n[\s\S]*?\n```/g;function km(e){return e.replace(wm,"").trim()}function Cm(e){let t=e.replace(Rm,"[tool call]");return t=t.replace(xm,"[tool result]"),t=t.replace(/_\(unknown block: thinking\)_/g,""),t=t.replace(/(?:\[tool call\]|\[tool result\])(?:\s*(?:\[tool call\]|\[tool result\]))+/g,"[tool activity]"),t=t.replace(/\n{3,}/g,`
900
+ ORDER BY MAX(COALESCE(s.started_at, '')) DESC`).all();if(t.length===0){console.log(d.dim("no projects indexed yet."));return}let s=new Fp({head:[d.bold("project"),d.bold("sessions"),d.bold("msgs"),d.bold("latest"),d.bold("path")],style:{head:[],border:["grey"]}});for(let n of t)s.push([d.project(Y(n.name,30)),String(n.session_count),String(n.message_count),d.dim(W(n.latest)),d.dim(Y(n.decoded_path,50))]);console.log(s.toString())}We();We();j();I();import{spawn as Hp}from"node:child_process";import{openSync as Wp}from"node:fs";import{join as Xp}from"node:path";import{existsSync as Up}from"node:fs";import{dirname as fi}from"node:path";import{fileURLToPath as Bp}from"node:url";var _s=null;function Te(){if(_s)return _s;let e=fi(Bp(import.meta.url));for(;!Up(`${e}/package.json`);){let t=fi(e);if(t===e)throw new Error(`package.json not found walking up from ${import.meta.url}`);e=t}return _s=e,_s}function Jp(){return Xp(Te(),"dist","daemon","entrypoint.js")}async function hs(){let e=q();if(e){console.log(`${d.ok("already running")} pid ${e.pid} \xB7 http://127.0.0.1:${e.port}`);return}P();let t=Wp(fs,"a"),s=Jp();Hp(process.execPath,[s],{detached:!0,stdio:["ignore",t,t],env:{...process.env}}).unref();let r=Date.now();for(;Date.now()-r<5e3;){await new Promise(i=>setTimeout(i,150));let o=q();if(o){console.log(`${d.ok("daemon started")} pid ${o.pid} \xB7 http://127.0.0.1:${o.port}`),console.log(d.dim(`logs: ${fs}`));return}}console.error(d.err("daemon did not come up within 5s \u2014 check the log file")),console.error(d.dim(` ${fs}`)),process.exitCode=1}We();I();async function _i(){let e=q();if(!e){console.log(d.dim("no daemon running.")),Bn();return}try{process.kill(e.pid,"SIGTERM")}catch(s){console.error(d.err(`failed to signal pid ${e.pid}: ${s.message}`)),process.exitCode=1;return}let t=Date.now();for(;Date.now()-t<5e3;)if(await new Promise(s=>setTimeout(s,100)),!q()){console.log(d.ok(`stopped daemon pid ${e.pid}`));return}console.error(d.err(`pid ${e.pid} did not exit within 5s \u2014 you may need to kill it manually`)),process.exitCode=1}We();import{spawn as Gp}from"node:child_process";import{platform as Es}from"node:os";I();function zp(e){let t=Es()==="darwin"?"open":Es()==="win32"?"start":"xdg-open",s=Es()==="win32"?["",e]:[e];Gp(t,s,{detached:!0,stdio:"ignore",shell:Es()==="win32"}).unref()}async function hi(){let e=q();if(!e&&(console.log(d.dim("daemon not running \u2014 starting it\u2026")),await hs(),e=q(),!e)){console.error(d.err("could not start the daemon. run `recall start` manually and check logs.")),process.exitCode=1;return}let t=`http://127.0.0.1:${e.port}`;console.log(`${d.ok("opening")} ${t}`),zp(t)}T();var Yp=/<(local-command-caveat|local-command-stdout|command-name|command-message|command-args|system-reminder|user-prompt-submit-hook|task-notification)[\s\S]*?<\/\1>/gi,Kp=/⚡ \*\*Tool call · `[^`]+`\*\*\s*\n+```json\n[\s\S]*?\n```/g,qp=/\*\*Tool result\*\*\s*\n+```\n[\s\S]*?\n```/g;function Vp(e){return e.replace(Yp,"").trim()}function Zp(e){let t=e.replace(Kp,"[tool call]");return t=t.replace(qp,"[tool result]"),t=t.replace(/_\(unknown block: thinking\)_/g,""),t=t.replace(/(?:\[tool call\]|\[tool result\])(?:\s*(?:\[tool call\]|\[tool result\]))+/g,"[tool activity]"),t=t.replace(/\n{3,}/g,`
901
901
 
902
- `),t.trim()}function Nm(e){return e.role??e.type??"message"}function oi(e,t,s={}){let n=s.mode??"condensed",r=s.includeSidechain===!0,o=s.since?Date.parse(s.since):0,i=t.filter(u=>!(!r&&u.is_sidechain===1||o&&u.timestamp&&Date.parse(u.timestamp)<o)),a=[];s.prelude&&(a.push(s.prelude.trim()),a.push("")),a.push(`# Claude Recall, past session context (${n})`),a.push(""),a.push(`- **Project**: ${e.project_name}`),e.decoded_path&&a.push(`- **Path**: \`${e.decoded_path}\``),a.push(`- **Session ID**: \`${e.id}\``),e.started_at&&a.push(`- **Started**: ${e.started_at}`),e.ended_at&&a.push(`- **Ended**: ${e.ended_at}`),e.git_branch&&a.push(`- **Branch**: \`${e.git_branch}\``),a.push(`- **Messages**: ${i.length}`),a.push(""),a.push("> This is a transcript of a previous Claude Code session, included for context. Refer back to it when the user asks about past decisions, code written, or problems debugged in this work."),a.push(""),a.push("---"),a.push("");let l=0,c=0;for(let u of i){let p=u.content_text??"",m=km(p);n==="condensed"&&(m=Cm(m));let f=m.length>0,g=!!u.tool_names&&u.tool_names.length>0;if(!f&&!g){c+=1;continue}let h=Nm(u),E=u.timestamp?` \`${u.timestamp}\``:"";a.push(`## ${h}${E}`),a.push(""),g&&n==="condensed"&&(a.push(`_tools used: ${u.tool_names}_`),a.push("")),f&&(a.push(m),a.push("")),l+=1}return a.push("---"),a.push(""),a.push(`_${l} messages included_`+(c?`, ${c} empty skipped`:"")+(r?"":", subagent/sidechain hidden")+"."),a.join(`
903
- `)}T();j();import{randomUUID as ii}from"node:crypto";import{writeFileSync as ai,readFileSync as rR,existsSync as Lm,mkdirSync as Om}from"node:fs";import{join as Mn}from"node:path";var gs=Mn(R,"threads"),Am=Mn(gs,"index.json");function ci(){P(),Lm(gs)||Om(gs,{recursive:!0})}function li(e,t,s){return{id:e.id,name:e.name,summary:e.summary,created_at:e.created_at,closed_at:e.closed_at,archived:e.archived===1,session_count:t.session_count,origin_count:t.origin_count,project:s?.project??null,project_count:s?.project_count??0,folder_id:e.folder_id??null}}function di(e){let t=new Map;if(e.length===0)return t;let s=_(),n=e.map(()=>"?").join(","),r=s.prepare(`SELECT te.thread_id AS thread_id,
902
+ `),t.trim()}function Qp(e){return e.role??e.type??"message"}function Ei(e,t,s={}){let n=s.mode??"condensed",r=s.includeSidechain===!0,o=s.since?Date.parse(s.since):0,i=t.filter(u=>!(!r&&u.is_sidechain===1||o&&u.timestamp&&Date.parse(u.timestamp)<o)),a=[];s.prelude&&(a.push(s.prelude.trim()),a.push("")),a.push(`# Claude Recall, past session context (${n})`),a.push(""),a.push(`- **Project**: ${e.project_name}`),e.decoded_path&&a.push(`- **Path**: \`${e.decoded_path}\``),a.push(`- **Session ID**: \`${e.id}\``),e.started_at&&a.push(`- **Started**: ${e.started_at}`),e.ended_at&&a.push(`- **Ended**: ${e.ended_at}`),e.git_branch&&a.push(`- **Branch**: \`${e.git_branch}\``),a.push(`- **Messages**: ${i.length}`),a.push(""),a.push("> This is a transcript of a previous Claude Code session, included for context. Refer back to it when the user asks about past decisions, code written, or problems debugged in this work."),a.push(""),a.push("---"),a.push("");let l=0,c=0;for(let u of i){let m=u.content_text??"",p=Vp(m);n==="condensed"&&(p=Zp(p));let f=p.length>0,g=!!u.tool_names&&u.tool_names.length>0;if(!f&&!g){c+=1;continue}let h=Qp(u),E=u.timestamp?` \`${u.timestamp}\``:"";a.push(`## ${h}${E}`),a.push(""),g&&n==="condensed"&&(a.push(`_tools used: ${u.tool_names}_`),a.push("")),f&&(a.push(p),a.push("")),l+=1}return a.push("---"),a.push(""),a.push(`_${l} messages included_`+(c?`, ${c} empty skipped`:"")+(r?"":", subagent/sidechain hidden")+"."),a.join(`
903
+ `)}T();j();import{randomUUID as bi}from"node:crypto";import{writeFileSync as Si,readFileSync as HR,existsSync as eg,mkdirSync as tg}from"node:fs";import{join as Hn}from"node:path";var bs=Hn(R,"threads"),sg=Hn(bs,"index.json");function yi(){P(),eg(bs)||tg(bs,{recursive:!0})}function Ti(e,t,s){return{id:e.id,name:e.name,summary:e.summary,created_at:e.created_at,closed_at:e.closed_at,archived:e.archived===1,session_count:t.session_count,origin_count:t.origin_count,project:s?.project??null,project_count:s?.project_count??0,folder_id:e.folder_id??null}}function wi(e){let t=new Map;if(e.length===0)return t;let s=_(),n=e.map(()=>"?").join(","),r=s.prepare(`SELECT te.thread_id AS thread_id,
904
904
  p.name AS project,
905
905
  COUNT(*) AS n,
906
906
  SUM(CASE WHEN te.role = 'origin' THEN 1 ELSE 0 END) AS origin_n
@@ -908,7 +908,7 @@ ${o}
908
908
  LEFT JOIN sessions s ON s.id = te.session_id
909
909
  LEFT JOIN projects p ON p.id = s.project_id
910
910
  WHERE te.thread_id IN (${n})
911
- GROUP BY te.thread_id, p.name`).all(...e),o=new Map;for(let i of r){let a=o.get(i.thread_id);a||(a=[],o.set(i.thread_id,a)),a.push(i)}for(let[i,a]of o){let l=a.filter(p=>p.project!==null),c=l.length,u=null;l.length>0&&(u=[...l].sort((m,f)=>f.n-m.n||f.origin_n-m.origin_n||(m.project??"").localeCompare(f.project??""))[0].project),t.set(i,{project:u,project_count:c})}return t}function ui(e){let t=e.auto_title_source;return{thread_id:e.thread_id,session_id:e.session_id,parent_session_id:e.parent_session_id,role:e.role,confidence:e.confidence,source:e.source,added_at:e.added_at,alias:e.alias,auto_title:e.auto_title,auto_title_source:t==="agent"||t==="heuristic"?t:null,alias_source:e.alias?"manual":null,first_user_message:e.first_user_message,project:e.project}}function pi(e){let s=_().prepare(`SELECT NULLIF(sa.alias, '') AS alias,
911
+ GROUP BY te.thread_id, p.name`).all(...e),o=new Map;for(let i of r){let a=o.get(i.thread_id);a||(a=[],o.set(i.thread_id,a)),a.push(i)}for(let[i,a]of o){let l=a.filter(m=>m.project!==null),c=l.length,u=null;l.length>0&&(u=[...l].sort((p,f)=>f.n-p.n||f.origin_n-p.origin_n||(p.project??"").localeCompare(f.project??""))[0].project),t.set(i,{project:u,project_count:c})}return t}function Ri(e){let t=e.auto_title_source;return{thread_id:e.thread_id,session_id:e.session_id,parent_session_id:e.parent_session_id,role:e.role,confidence:e.confidence,source:e.source,added_at:e.added_at,alias:e.alias,auto_title:e.auto_title,auto_title_source:t==="agent"||t==="heuristic"?t:null,alias_source:e.alias?"manual":null,first_user_message:e.first_user_message,project:e.project}}function xi(e){let s=_().prepare(`SELECT NULLIF(sa.alias, '') AS alias,
912
912
  s.auto_title AS auto_title,
913
913
  s.auto_title_source AS auto_title_source,
914
914
  s.first_user_message AS first_user_message,
@@ -916,11 +916,11 @@ ${o}
916
916
  FROM (SELECT ? AS sid) q
917
917
  LEFT JOIN sessions s ON s.id = q.sid
918
918
  LEFT JOIN session_aliases sa ON sa.session_id = q.sid
919
- LEFT JOIN projects p ON p.id = s.project_id`).get(e),n=s?.auto_title_source??null;return{alias:s?.alias??null,auto_title:s?.auto_title??null,auto_title_source:n==="agent"||n==="heuristic"?n:null,first_user_message:s?.first_user_message??null,project:s?.project??null}}function mi(e){let s=_().prepare(`SELECT
919
+ LEFT JOIN projects p ON p.id = s.project_id`).get(e),n=s?.auto_title_source??null;return{alias:s?.alias??null,auto_title:s?.auto_title??null,auto_title_source:n==="agent"||n==="heuristic"?n:null,first_user_message:s?.first_user_message??null,project:s?.project??null}}function ki(e){let s=_().prepare(`SELECT
920
920
  COUNT(*) AS session_count,
921
921
  SUM(CASE WHEN role = 'origin' THEN 1 ELSE 0 END) AS origin_count
922
- FROM thread_edges WHERE thread_id = ?`).get(e);return{session_count:s?.session_count??0,origin_count:s?.origin_count??0}}function Ne(e){let t=Le(e);t&&(ci(),ai(Mn(gs,`${e}.json`),JSON.stringify(t,null,2)),gi())}function gi(){ci();let e=Dn({includeArchived:!0});ai(Am,JSON.stringify({threads:e},null,2))}function fi(e){let t=e.name.trim();if(!t)throw new Error("thread name cannot be empty");let s=_(),n=ii(),r=new Date().toISOString();s.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, ?, ?)").run(n,t,e.summary?.trim()||null,r),e.originSessionId&&s.prepare(`INSERT INTO thread_edges (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
923
- VALUES (?, ?, NULL, 'origin', 1.0, 'manual', ?)`).run(n,e.originSessionId,r),Ne(n);let o=Le(n);if(!o)throw new Error("thread creation succeeded but read-back failed");return o}function Dn(e={}){let t=_(),s=e.includeArchived?"":"WHERE archived = 0",n=t.prepare(`SELECT * FROM threads ${s} ORDER BY created_at DESC`).all(),r=di(n.map(o=>o.id));return n.map(o=>li(o,mi(o.id),r.get(o.id)))}function Le(e){let t=_(),s=t.prepare("SELECT * FROM threads WHERE id = ?").get(e);if(!s)return null;let n=t.prepare(`SELECT e.*,
922
+ FROM thread_edges WHERE thread_id = ?`).get(e);return{session_count:s?.session_count??0,origin_count:s?.origin_count??0}}function Le(e){let t=Oe(e);t&&(yi(),Si(Hn(bs,`${e}.json`),JSON.stringify(t,null,2)),Ni())}function Ni(){yi();let e=Wn({includeArchived:!0});Si(sg,JSON.stringify({threads:e},null,2))}function Ci(e){let t=e.name.trim();if(!t)throw new Error("thread name cannot be empty");let s=_(),n=bi(),r=new Date().toISOString();s.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, ?, ?)").run(n,t,e.summary?.trim()||null,r),e.originSessionId&&s.prepare(`INSERT INTO thread_edges (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
923
+ VALUES (?, ?, NULL, 'origin', 1.0, 'manual', ?)`).run(n,e.originSessionId,r),Le(n);let o=Oe(n);if(!o)throw new Error("thread creation succeeded but read-back failed");return o}function Wn(e={}){let t=_(),s=e.includeArchived?"":"WHERE archived = 0",n=t.prepare(`SELECT * FROM threads ${s} ORDER BY created_at DESC`).all(),r=wi(n.map(o=>o.id));return n.map(o=>Ti(o,ki(o.id),r.get(o.id)))}function Oe(e){let t=_(),s=t.prepare("SELECT * FROM threads WHERE id = ?").get(e);if(!s)return null;let n=t.prepare(`SELECT e.*,
924
924
  NULLIF(sa.alias, '') AS alias,
925
925
  s.auto_title AS auto_title,
926
926
  s.auto_title_source AS auto_title_source,
@@ -931,7 +931,7 @@ ${o}
931
931
  LEFT JOIN session_aliases sa ON sa.session_id = e.session_id
932
932
  LEFT JOIN projects p ON p.id = s.project_id
933
933
  WHERE e.thread_id = ?
934
- ORDER BY e.added_at ASC`).all(e).map(ui),r=di([e]).get(e);return{...li(s,mi(s.id),r),edges:n}}function _i(e){let t=_();if(!t.prepare("SELECT * FROM threads WHERE id = ?").get(e.threadId))throw new Error(`thread ${e.threadId} not found`);let n=new Date().toISOString(),r=e.parentSessionId??null,o=e.role??(r?"child":"origin"),i=e.confidence??1,a=e.source??"manual";if(i<0||i>1)throw new Error("confidence must be 0..1");t.prepare(`INSERT INTO thread_edges
934
+ ORDER BY e.added_at ASC`).all(e).map(Ri),r=wi([e]).get(e);return{...Ti(s,ki(s.id),r),edges:n}}function Li(e){let t=_();if(!t.prepare("SELECT * FROM threads WHERE id = ?").get(e.threadId))throw new Error(`thread ${e.threadId} not found`);let n=new Date().toISOString(),r=e.parentSessionId??null,o=e.role??(r?"child":"origin"),i=e.confidence??1,a=e.source??"manual";if(i<0||i>1)throw new Error("confidence must be 0..1");t.prepare(`INSERT INTO thread_edges
935
935
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
936
936
  VALUES (?, ?, ?, ?, ?, ?, ?)
937
937
  ON CONFLICT(thread_id, session_id) DO UPDATE SET
@@ -939,57 +939,57 @@ ${o}
939
939
  role = excluded.role,
940
940
  confidence = excluded.confidence,
941
941
  source = excluded.source,
942
- added_at = excluded.added_at`).run(e.threadId,e.sessionId,r,o,i,a,n),Ne(e.threadId);let l=pi(e.sessionId);return{thread_id:e.threadId,session_id:e.sessionId,parent_session_id:r,role:o,confidence:i,source:a,added_at:n,alias:l.alias,auto_title:l.auto_title,auto_title_source:l.auto_title_source,alias_source:l.alias?"manual":null,first_user_message:l.first_user_message,project:l.project}}function hi(e,t){let n=_().prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e,t);return n.changes>0&&Ne(e),{removed:n.changes}}function Ei(e,t,s){let n=_(),r=n.prepare("SELECT * FROM thread_edges WHERE thread_id = ? AND session_id = ?").get(e,t);if(!r)throw new Error("edge not found; add the session first");if(s!==null){if(s===t)throw new Error("cycle detected: session cannot be its own parent");let a=n.prepare("SELECT parent_session_id FROM thread_edges WHERE thread_id = ? AND session_id = ?"),l=s,c=new Set;for(;l!==null;){if(l===t)throw new Error(`cycle detected: setting parent of ${t} to ${s} would create a loop`);if(c.has(l))break;c.add(l),l=a.get(e,l)?.parent_session_id??null}}let o=s?"child":"origin";n.prepare(`UPDATE thread_edges
942
+ added_at = excluded.added_at`).run(e.threadId,e.sessionId,r,o,i,a,n),Le(e.threadId);let l=xi(e.sessionId);return{thread_id:e.threadId,session_id:e.sessionId,parent_session_id:r,role:o,confidence:i,source:a,added_at:n,alias:l.alias,auto_title:l.auto_title,auto_title_source:l.auto_title_source,alias_source:l.alias?"manual":null,first_user_message:l.first_user_message,project:l.project}}function Oi(e,t){let n=_().prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e,t);return n.changes>0&&Le(e),{removed:n.changes}}function Ai(e,t,s){let n=_(),r=n.prepare("SELECT * FROM thread_edges WHERE thread_id = ? AND session_id = ?").get(e,t);if(!r)throw new Error("edge not found; add the session first");if(s!==null){if(s===t)throw new Error("cycle detected: session cannot be its own parent");let a=n.prepare("SELECT parent_session_id FROM thread_edges WHERE thread_id = ? AND session_id = ?"),l=s,c=new Set;for(;l!==null;){if(l===t)throw new Error(`cycle detected: setting parent of ${t} to ${s} would create a loop`);if(c.has(l))break;c.add(l),l=a.get(e,l)?.parent_session_id??null}}let o=s?"child":"origin";n.prepare(`UPDATE thread_edges
943
943
  SET parent_session_id = ?, role = ?, added_at = ?
944
- WHERE thread_id = ? AND session_id = ?`).run(s,o,new Date().toISOString(),e,t),Ne(e);let i=pi(t);return ui({...r,parent_session_id:s,role:o,added_at:new Date().toISOString(),alias:i.alias,auto_title:i.auto_title,auto_title_source:i.auto_title_source,first_user_message:i.first_user_message,project:i.project})}function bi(e,t){let s=t.trim();if(!s)throw new Error("name cannot be empty");_().prepare("UPDATE threads SET name = ? WHERE id = ?").run(s,e),Ne(e);let r=Le(e);if(!r)throw new Error(`thread ${e} not found`);return r}function Si(e){_().prepare("UPDATE threads SET closed_at = ? WHERE id = ?").run(new Date().toISOString(),e),Ne(e);let s=Le(e);if(!s)throw new Error(`thread ${e} not found`);return s}function yi(e){_().prepare("UPDATE threads SET closed_at = NULL WHERE id = ?").run(e),Ne(e);let s=Le(e);if(!s)throw new Error(`thread ${e} not found`);return s}function Ti(e){_().prepare("UPDATE threads SET archived = 1 WHERE id = ?").run(e),Ne(e);let s=Le(e);if(!s)throw new Error(`thread ${e} not found`);return s}function wi(e,t){if(e===t)throw new Error("cannot merge a thread into itself");let s=_(),n=new Date().toISOString();s.transaction(()=>{let o=s.prepare("SELECT * FROM thread_edges WHERE thread_id = ?").all(e);for(let i of o)s.prepare(`INSERT INTO thread_edges
944
+ WHERE thread_id = ? AND session_id = ?`).run(s,o,new Date().toISOString(),e,t),Le(e);let i=xi(t);return Ri({...r,parent_session_id:s,role:o,added_at:new Date().toISOString(),alias:i.alias,auto_title:i.auto_title,auto_title_source:i.auto_title_source,first_user_message:i.first_user_message,project:i.project})}function Ii(e,t){let s=t.trim();if(!s)throw new Error("name cannot be empty");_().prepare("UPDATE threads SET name = ? WHERE id = ?").run(s,e),Le(e);let r=Oe(e);if(!r)throw new Error(`thread ${e} not found`);return r}function vi(e){_().prepare("UPDATE threads SET closed_at = ? WHERE id = ?").run(new Date().toISOString(),e),Le(e);let s=Oe(e);if(!s)throw new Error(`thread ${e} not found`);return s}function Mi(e){_().prepare("UPDATE threads SET closed_at = NULL WHERE id = ?").run(e),Le(e);let s=Oe(e);if(!s)throw new Error(`thread ${e} not found`);return s}function Di(e){_().prepare("UPDATE threads SET archived = 1 WHERE id = ?").run(e),Le(e);let s=Oe(e);if(!s)throw new Error(`thread ${e} not found`);return s}function $i(e,t){if(e===t)throw new Error("cannot merge a thread into itself");let s=_(),n=new Date().toISOString();s.transaction(()=>{let o=s.prepare("SELECT * FROM thread_edges WHERE thread_id = ?").all(e);for(let i of o)s.prepare(`INSERT INTO thread_edges
945
945
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
946
946
  VALUES (?, ?, ?, ?, ?, ?, ?)
947
947
  ON CONFLICT(thread_id, session_id) DO UPDATE SET
948
948
  parent_session_id = COALESCE(thread_edges.parent_session_id, excluded.parent_session_id),
949
949
  role = CASE WHEN thread_edges.role = 'origin' OR excluded.role = 'origin' THEN 'origin' ELSE 'child' END,
950
950
  confidence = MAX(thread_edges.confidence, excluded.confidence),
951
- source = thread_edges.source`).run(t,i.session_id,i.parent_session_id,i.role,i.confidence,i.source,n);s.prepare("DELETE FROM threads WHERE id = ?").run(e)})(),Ne(t),gi();let r=Le(t);if(!r)throw new Error("merge destination disappeared");return r}function Ri(e){if(e.sessionIds.length===0)throw new Error("no sessions to split off");let t=_(),s=new Date().toISOString(),n=ii();t.transaction(()=>{t.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, NULL, ?)").run(n,e.newThreadName.trim(),s);for(let o of e.sessionIds){let i=t.prepare("SELECT * FROM thread_edges WHERE thread_id = ? AND session_id = ?").get(e.threadId,o);i&&(t.prepare(`INSERT INTO thread_edges
951
+ source = thread_edges.source`).run(t,i.session_id,i.parent_session_id,i.role,i.confidence,i.source,n);s.prepare("DELETE FROM threads WHERE id = ?").run(e)})(),Le(t),Ni();let r=Oe(t);if(!r)throw new Error("merge destination disappeared");return r}function ji(e){if(e.sessionIds.length===0)throw new Error("no sessions to split off");let t=_(),s=new Date().toISOString(),n=bi();t.transaction(()=>{t.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, NULL, ?)").run(n,e.newThreadName.trim(),s);for(let o of e.sessionIds){let i=t.prepare("SELECT * FROM thread_edges WHERE thread_id = ? AND session_id = ?").get(e.threadId,o);i&&(t.prepare(`INSERT INTO thread_edges
952
952
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
953
- VALUES (?, ?, ?, ?, ?, ?, ?)`).run(n,o,i.parent_session_id,i.role,i.confidence,i.source,s),t.prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e.threadId,o))}})(),Ne(e.threadId),Ne(n);let r=Le(n);if(!r)throw new Error("split destination disappeared");return r}function xi(e){let t=Le(e);if(!t)return[];let s=t.edges.filter(r=>r.role==="origin").map(r=>r.session_id),n=t.edges.filter(r=>r.role==="child").map(r=>r.session_id);return[...s,...n]}M();Se();T();j();import{writeFileSync as Im}from"node:fs";import{join as vm}from"node:path";var Mm=vm(R,"recall-events.json");function $n(e,t,s,n="cli"){_().prepare(`
953
+ VALUES (?, ?, ?, ?, ?, ?, ?)`).run(n,o,i.parent_session_id,i.role,i.confidence,i.source,s),t.prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e.threadId,o))}})(),Le(e.threadId),Le(n);let r=Oe(n);if(!r)throw new Error("split destination disappeared");return r}function Pi(e){let t=Oe(e);if(!t)return[];let s=t.edges.filter(r=>r.role==="origin").map(r=>r.session_id),n=t.edges.filter(r=>r.role==="child").map(r=>r.session_id);return[...s,...n]}I();fe();T();j();import{writeFileSync as ng}from"node:fs";import{join as rg}from"node:path";var og=rg(R,"recall-events.json");function Xn(e,t,s,n="cli"){_().prepare(`
954
954
  INSERT INTO recall_events (session_id, recalled_at, token_count, mode, caller)
955
955
  VALUES (?, datetime('now'), ?, ?, ?)
956
- `).run(e,t,s,n),Dm()}function Dm(){P();let t=_().prepare("SELECT id, session_id, recalled_at, token_count, mode, caller FROM recall_events ORDER BY recalled_at DESC").all();Im(Mm,JSON.stringify(t,null,2)+`
957
- `,"utf-8")}function $m(e,t){if(t.length>=32)return e.prepare("SELECT id FROM sessions WHERE id = ?").get(t)?.id??null;let s=e.prepare("SELECT id FROM sessions WHERE id LIKE ? LIMIT 2").all(t+"%");return s.length===1?s[0].id:(s.length===0||process.stderr.write(`ambiguous id prefix "${t}". be more specific.
958
- `),null)}function jm(e){if(!e)return null;let t=e.match(/^(\d+)\s*(s|m|h|d)$/i);if(t){let n=parseInt(t[1],10),r=t[2].toLowerCase(),o=r==="s"?1e3:r==="m"?6e4:r==="h"?36e5:864e5;return new Date(Date.now()-n*o).toISOString()}if(/^\d{4}-\d{2}-\d{2}$/.test(e))return`${e}T00:00:00.000Z`;let s=Date.parse(e);return Number.isNaN(s)?null:new Date(s).toISOString()}function Pm(e,t){if(t.length>=32)return e.prepare("SELECT id FROM threads WHERE id = ?").get(t)?.id??null;let s=e.prepare("SELECT id, name FROM threads WHERE id LIKE ? ORDER BY created_at DESC").all(t+"%");if(s.length===1)return s[0].id;if(s.length===0)return null;process.stderr.write(`ambiguous thread prefix "${t}" \u2014 candidates:
956
+ `).run(e,t,s,n),ig()}function ig(){P();let t=_().prepare("SELECT id, session_id, recalled_at, token_count, mode, caller FROM recall_events ORDER BY recalled_at DESC").all();ng(og,JSON.stringify(t,null,2)+`
957
+ `,"utf-8")}function ag(e,t){if(t.length>=32)return e.prepare("SELECT id FROM sessions WHERE id = ?").get(t)?.id??null;let s=e.prepare("SELECT id FROM sessions WHERE id LIKE ? LIMIT 2").all(t+"%");return s.length===1?s[0].id:(s.length===0||process.stderr.write(`ambiguous id prefix "${t}". be more specific.
958
+ `),null)}function cg(e){if(!e)return null;let t=e.match(/^(\d+)\s*(s|m|h|d)$/i);if(t){let n=parseInt(t[1],10),r=t[2].toLowerCase(),o=r==="s"?1e3:r==="m"?6e4:r==="h"?36e5:864e5;return new Date(Date.now()-n*o).toISOString()}if(/^\d{4}-\d{2}-\d{2}$/.test(e))return`${e}T00:00:00.000Z`;let s=Date.parse(e);return Number.isNaN(s)?null:new Date(s).toISOString()}function lg(e,t){if(t.length>=32)return e.prepare("SELECT id FROM threads WHERE id = ?").get(t)?.id??null;let s=e.prepare("SELECT id, name FROM threads WHERE id LIKE ? ORDER BY created_at DESC").all(t+"%");if(s.length===1)return s[0].id;if(s.length===0)return null;process.stderr.write(`ambiguous thread prefix "${t}" \u2014 candidates:
959
959
  `);for(let n of s)process.stderr.write(` ${H(n.id)} ${n.name}
960
- `);return null}function ki(e,t,s){let n=e.prepare(`SELECT s.id, p.name AS project_name, p.decoded_path,
960
+ `);return null}function Fi(e,t,s){let n=e.prepare(`SELECT s.id, p.name AS project_name, p.decoded_path,
961
961
  s.started_at, s.ended_at, s.message_count, s.git_branch
962
962
  FROM sessions s JOIN projects p ON p.id = s.project_id
963
963
  WHERE s.id = ?`).get(t);if(!n)return process.stderr.write(`session metadata missing for ${t}
964
964
  `),null;let r=e.prepare(`SELECT uuid, type, role, timestamp, is_sidechain, content_text, tool_names
965
965
  FROM messages
966
966
  WHERE session_id = ?
967
- ORDER BY COALESCE(timestamp, ''), rowid`).all(t),o=s.full?"full":"condensed";return oi(n,r,{mode:o,includeSidechain:s.subagents===!0,prelude:s.prelude??null,since:jm(s.since)})}async function Ci(e,t){await Ce("Context re-injection");let s=_();if(e.startsWith("thread:")){let i=e.slice(7).trim();if(!i){process.stderr.write(`thread: target requires an id or prefix
968
- `),process.exitCode=1;return}let a=Pm(s,i);if(!a){process.stderr.write(`thread not found: ${i}
969
- `),process.exitCode=1;return}let l=xi(a);if(l.length===0){process.stderr.write(`thread ${i} has no linked sessions
970
- `),process.exitCode=1;return}for(let c=0;c<l.length;c+=1){let u=l[c],p=ki(s,u,{...t,prelude:c===0?t.prelude:void 0});if(p===null){process.exitCode=1;continue}c>0&&process.stdout.write(`
967
+ ORDER BY COALESCE(timestamp, ''), rowid`).all(t),o=s.full?"full":"condensed";return Ei(n,r,{mode:o,includeSidechain:s.subagents===!0,prelude:s.prelude??null,since:cg(s.since)})}async function Ui(e,t){await Ce("Context re-injection");let s=_();if(e.startsWith("thread:")){let i=e.slice(7).trim();if(!i){process.stderr.write(`thread: target requires an id or prefix
968
+ `),process.exitCode=1;return}let a=lg(s,i);if(!a){process.stderr.write(`thread not found: ${i}
969
+ `),process.exitCode=1;return}let l=Pi(a);if(l.length===0){process.stderr.write(`thread ${i} has no linked sessions
970
+ `),process.exitCode=1;return}for(let c=0;c<l.length;c+=1){let u=l[c],m=Fi(s,u,{...t,prelude:c===0?t.prelude:void 0});if(m===null){process.exitCode=1;continue}c>0&&process.stdout.write(`
971
971
  ---
972
972
 
973
- `),process.stdout.write(p),p.endsWith(`
973
+ `),process.stdout.write(m),m.endsWith(`
974
974
  `)||process.stdout.write(`
975
- `),$n(u,Math.ceil(p.length/4),"thread","cli")}return}let n=$m(s,e);if(!n){e.length>=32&&process.stderr.write(`session not found: ${e}
976
- `),process.exitCode=1;return}let r=ki(s,n,t);if(r===null){process.exitCode=1;return}process.stdout.write(r),r.endsWith(`
975
+ `),Xn(u,Math.ceil(m.length/4),"thread","cli")}return}let n=ag(s,e);if(!n){e.length>=32&&process.stderr.write(`session not found: ${e}
976
+ `),process.exitCode=1;return}let r=Fi(s,n,t);if(r===null){process.exitCode=1;return}process.stdout.write(r),r.endsWith(`
977
977
  `)||process.stdout.write(`
978
- `);let o=t.since?"since":t.full?"full":"condensed";$n(n,Math.ceil(r.length/4),o,"cli"),process.stderr.isTTY&&process.stderr.write(`\x1B[2mShare this recall? \u2192 recall share\x1B[0m
979
- `)}Se();import{join as Fm}from"node:path";import{spawn as Um}from"node:child_process";async function Ni(e={}){await Ce("MCP server");let t=Fm(ye(),"dist","mcp-server.js"),s={...process.env};e.allowWrites&&(s.RECALL_MCP_ALLOW_WRITES="1");let n=Um(process.execPath,[t],{stdio:"inherit",env:s});return new Promise((r,o)=>{n.on("error",o),n.on("exit",(i,a)=>{if(a){process.kill(process.pid,a);return}process.exitCode=i??0,r()})})}T();import{execSync as jn}from"node:child_process";import{randomUUID as Bm}from"node:crypto";import Hm from"node:readline/promises";M();async function Li(e){if(e.list){Wm();return}if(e.purge){Xm(e.purge);return}let t=await Jm();t||(process.stderr.write(d.err(`clipboard empty / nothing on stdin
980
- `)),process.exit(1));let s=At(t);if(s.length>0&&!e.force){process.stderr.write(d.warn(`\u26A0 detected ${s.length} possible secret${s.length===1?"":"s"} in content:
978
+ `);let o=t.since?"since":t.full?"full":"condensed";Xn(n,Math.ceil(r.length/4),o,"cli"),process.stderr.isTTY&&process.stderr.write(`\x1B[2mShare this recall? \u2192 recall share\x1B[0m
979
+ `)}fe();import{join as dg}from"node:path";import{spawn as ug}from"node:child_process";async function Bi(e={}){await Ce("MCP server");let t=dg(Te(),"dist","mcp-server.js"),s={...process.env};e.allowWrites&&(s.RECALL_MCP_ALLOW_WRITES="1");let n=ug(process.execPath,[t],{stdio:"inherit",env:s});return new Promise((r,o)=>{n.on("error",o),n.on("exit",(i,a)=>{if(a){process.kill(process.pid,a);return}process.exitCode=i??0,r()})})}T();import{execSync as Jn}from"node:child_process";import{randomUUID as mg}from"node:crypto";import pg from"node:readline/promises";I();async function Hi(e){if(e.list){gg();return}if(e.purge){fg(e.purge);return}let t=await _g();t||(process.stderr.write(d.err(`clipboard empty / nothing on stdin
980
+ `)),process.exit(1));let s=Dt(t);if(s.length>0&&!e.force){process.stderr.write(d.warn(`\u26A0 detected ${s.length} possible secret${s.length===1?"":"s"} in content:
981
981
  `));for(let a of s.slice(0,8))process.stderr.write(` ${d.err(a.pattern)} ${d.dim("\u2192")} ${a.maskedPreview}
982
982
  `);s.length>8&&process.stderr.write(d.dim(` \u2026 ${s.length-8} more
983
983
  `)),e.dryRun&&(process.stderr.write(d.dim(`
984
984
  (dry run \u2014 nothing archived)
985
985
  `)),process.exit(1)),!process.stdin.isTTY&&!process.stderr.isTTY&&(process.stderr.write(d.err(`refusing to archive secret content in non-interactive mode. use --force to override.
986
- `)),e.pipe&&process.stdout.write(t),process.exit(1));let o=Hm.createInterface({input:process.stdin,output:process.stderr}),i=await o.question(d.accent("archive anyway? [y/N] "));o.close(),i.trim().toLowerCase()!=="y"&&(process.stderr.write(d.dim(`cancelled \u2014 nothing archived.
986
+ `)),e.pipe&&process.stdout.write(t),process.exit(1));let o=pg.createInterface({input:process.stdin,output:process.stderr}),i=await o.question(d.accent("archive anyway? [y/N] "));o.close(),i.trim().toLowerCase()!=="y"&&(process.stderr.write(d.dim(`cancelled \u2014 nothing archived.
987
987
  `)),e.pipe&&process.stdout.write(t),process.exit(0))}e.dryRun&&(process.stderr.write(d.dim(`(dry run \u2014 would archive ${t.length.toLocaleString()} chars)
988
- `)),e.pipe&&process.stdout.write(t),process.exit(0));let n=Bm(),r=new Date().toISOString();_().prepare(`INSERT INTO paste_archives (id, created_at, content, size_bytes, source, label)
988
+ `)),e.pipe&&process.stdout.write(t),process.exit(0));let n=mg(),r=new Date().toISOString();_().prepare(`INSERT INTO paste_archives (id, created_at, content, size_bytes, source, label)
989
989
  VALUES (?, ?, ?, ?, ?, ?)`).run(n,r,t,Buffer.byteLength(t,"utf8"),e.pipe?"cli-piped":"cli",e.label??null),process.stderr.write(d.ok(`\u2713 archived ${t.length.toLocaleString()} chars as ${n.slice(0,8)}
990
990
  `)),e.label&&process.stderr.write(d.dim(` label: ${e.label}
991
991
  `)),process.stderr.write(d.dim(` purge any time with: recall paste --purge ${n.slice(0,8)}
992
- `)),e.pipe&&process.stdout.write(t)}function Wm(){let e=_().prepare(`SELECT id, created_at, size_bytes, source, label,
992
+ `)),e.pipe&&process.stdout.write(t)}function gg(){let e=_().prepare(`SELECT id, created_at, size_bytes, source, label,
993
993
  substr(replace(replace(content, char(10), '\u21B5'), char(13), ''), 1, 80) AS preview
994
994
  FROM paste_archives
995
995
  ORDER BY created_at DESC
@@ -1001,16 +1001,16 @@ ${d.bold(`${e.length} archived paste${e.length===1?"":"s"}`)}
1001
1001
  show full content: recall paste --show <id>
1002
1002
  `)+d.dim(`purge one (permanent): recall paste --purge <id>
1003
1003
 
1004
- `))}function Xm(e){e.length<8&&(process.stderr.write(d.err(`provide at least 8 characters of the paste id to purge.
1004
+ `))}function fg(e){e.length<8&&(process.stderr.write(d.err(`provide at least 8 characters of the paste id to purge.
1005
1005
  `)),process.exit(1));let t=_(),s=t.prepare("SELECT id FROM paste_archives WHERE id = ? OR id LIKE ? LIMIT 2").all(e,`${e}%`);s.length===0&&(process.stderr.write(d.err(`no paste matches ${e}
1006
1006
  `)),process.exit(1)),s.length>1&&(process.stderr.write(d.err(`prefix ${e} is ambiguous. be more specific.
1007
1007
  `)),process.exit(1)),t.prepare("DELETE FROM paste_archives WHERE id = ?").run(s[0].id),process.stderr.write(d.ok(`\u2713 purged ${s[0].id.slice(0,8)} \u2014 content permanently destroyed
1008
- `))}async function Jm(){if(!process.stdin.isTTY)return await Gm();try{return jn("pbpaste",{encoding:"utf8",maxBuffer:16*1024*1024})}catch{}try{return jn("xclip -o -selection clipboard",{encoding:"utf8",maxBuffer:16*1024*1024})}catch{}try{return jn("powershell.exe -command Get-Clipboard",{encoding:"utf8",maxBuffer:16*1024*1024})}catch{}throw new Error("Could not read clipboard. On macOS pbpaste should be built in; on Linux install xclip; on Windows pipe into this command instead.")}async function Gm(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(t));return Buffer.concat(e).toString("utf8")}T();M();async function Oi(e){let t=_(),s=new Map,n=0,r=0,o=0,i=new Set,a=t.prepare(`SELECT uuid, session_id, content_text, raw_json
1008
+ `))}async function _g(){if(!process.stdin.isTTY)return await hg();try{return Jn("pbpaste",{encoding:"utf8",maxBuffer:16*1024*1024})}catch{}try{return Jn("xclip -o -selection clipboard",{encoding:"utf8",maxBuffer:16*1024*1024})}catch{}try{return Jn("powershell.exe -command Get-Clipboard",{encoding:"utf8",maxBuffer:16*1024*1024})}catch{}throw new Error("Could not read clipboard. On macOS pbpaste should be built in; on Linux install xclip; on Windows pipe into this command instead.")}async function hg(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(t));return Buffer.concat(e).toString("utf8")}T();I();async function Wi(e){let t=_(),s=new Map,n=0,r=0,o=0,i=new Set,a=t.prepare(`SELECT uuid, session_id, content_text, raw_json
1009
1009
  FROM messages
1010
- WHERE content_text IS NOT NULL`).all(),l=t.prepare("UPDATE messages SET content_text = ?, raw_json = ? WHERE uuid = ?"),c=(g,h)=>{let E=At(g);if(E.length===0)return!1;for(let b of E){let S=s.get(b.pattern)??{pattern:b.pattern,severity:b.severity,hits:0,sessions:new Set};S.hits+=1,S.sessions.add(h),s.set(b.pattern,S)}return!0};process.stdout.write(d.dim(`Scanning ${a.length.toLocaleString()} messages\u2026
1010
+ WHERE content_text IS NOT NULL`).all(),l=t.prepare("UPDATE messages SET content_text = ?, raw_json = ? WHERE uuid = ?"),c=(g,h)=>{let E=Dt(g);if(E.length===0)return!1;for(let b of E){let S=s.get(b.pattern)??{pattern:b.pattern,severity:b.severity,hits:0,sessions:new Set};S.hits+=1,S.sessions.add(h),s.set(b.pattern,S)}return!0};process.stdout.write(d.dim(`Scanning ${a.length.toLocaleString()} messages\u2026
1011
1011
  `));for(let g of a)if(n+=1,(c(g.content_text??"",g.session_id)||c(g.raw_json??"",g.session_id))&&(r+=1,i.add(g.session_id),e.verbose&&process.stderr.write(d.dim(` hit in session ${g.session_id.slice(0,8)} message ${g.uuid.slice(0,8)}
1012
- `)),e.redact)){let E=Ye(g.content_text??"").redacted,b=g.raw_json?Ye(g.raw_json).redacted:null;l.run(E,b,g.uuid),o+=1}let u=t.prepare(`SELECT id, first_user_message FROM sessions
1013
- WHERE first_user_message IS NOT NULL`).all(),p=t.prepare("UPDATE sessions SET first_user_message = ? WHERE id = ?"),m=0;for(let g of u)At(g.first_user_message).length>0&&(i.add(g.id),e.redact&&(p.run(Ye(g.first_user_message).redacted,g.id),m+=1));if(process.stdout.write(`
1012
+ `)),e.redact)){let E=Ke(g.content_text??"").redacted,b=g.raw_json?Ke(g.raw_json).redacted:null;l.run(E,b,g.uuid),o+=1}let u=t.prepare(`SELECT id, first_user_message FROM sessions
1013
+ WHERE first_user_message IS NOT NULL`).all(),m=t.prepare("UPDATE sessions SET first_user_message = ? WHERE id = ?"),p=0;for(let g of u)Dt(g.first_user_message).length>0&&(i.add(g.id),e.redact&&(m.run(Ke(g.first_user_message).redacted,g.id),p+=1));if(process.stdout.write(`
1014
1014
  `),s.size===0){process.stdout.write(d.ok(`\u2713 clean \u2014 no secrets detected across ${n.toLocaleString()} messages.
1015
1015
  `));return}let f=[...s.values()].sort((g,h)=>h.hits-g.hits);process.stdout.write(d.warn(`\u26A0 ${r.toLocaleString()} message${r===1?"":"s"} across ${i.size.toLocaleString()} session${i.size===1?"":"s"} contain detected secrets.
1016
1016
 
@@ -1018,23 +1018,23 @@ show full content: recall paste --show <id>
1018
1018
  `)),process.stdout.write(d.dim(` \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1019
1019
  `));for(let g of f){let h=g.severity==="high"?d.err("\u25CF"):d.warn("\u25CF");process.stdout.write(` ${h} ${g.pattern.padEnd(30)} ${String(g.hits).padStart(5)} ${String(g.sessions.size).padStart(4)}
1020
1020
  `)}process.stdout.write(`
1021
- `),e.redact?(process.stdout.write(d.ok(`\u2713 redacted in place: ${o.toLocaleString()} messages, ${m.toLocaleString()} session previews.
1021
+ `),e.redact?(process.stdout.write(d.ok(`\u2713 redacted in place: ${o.toLocaleString()} messages, ${p.toLocaleString()} session previews.
1022
1022
  `)),process.stdout.write(d.dim(` (The source JSONL files at ~/.claude/projects/ were not modified.)
1023
- `))):process.stdout.write(d.dim(" Rerun with --redact to scrub these in place, or run `recall index --force`.\n"))}T();M();import{basename as zm}from"node:path";async function Ii(e){let t=_(),s=await Ym(t,e.project);if(!s){console.error(d.err(`No project found${e.project?` matching "${e.project}"`:" for current cwd"}. Run \`recall projects\` to list available projects.`)),process.exitCode=1;return}let n=t.prepare(`SELECT s.id,
1023
+ `))):process.stdout.write(d.dim(" Rerun with --redact to scrub these in place, or run `recall index --force`.\n"))}T();I();import{basename as Eg}from"node:path";async function Ji(e){let t=_(),s=await bg(t,e.project);if(!s){console.error(d.err(`No project found${e.project?` matching "${e.project}"`:" for current cwd"}. Run \`recall projects\` to list available projects.`)),process.exitCode=1;return}let n=t.prepare(`SELECT s.id,
1024
1024
  s.auto_title,
1025
1025
  s.auto_title_source,
1026
1026
  CASE WHEN sa.session_id IS NOT NULL THEN 1 ELSE 0 END AS has_alias
1027
1027
  FROM sessions s
1028
1028
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1029
1029
  WHERE s.project_id = ?
1030
- ORDER BY s.started_at`).all(s.id);if(n.length===0){console.error(d.warn(`Project "${s.name}" has 0 sessions.`));return}let r={clean:0,"fixed_v0.16.1":0,agent:0,manual_alias:0,template_pending:0,programmatic:0,recursive_meta:0,low_signal:0},o=[];for(let u of n){let p={auto_title:u.auto_title,auto_title_source:u.auto_title_source??null,has_alias:u.has_alias===1},m=Ro(p);r[m]+=1,o.push({id:u.id,quality:m})}if(!e.dryRun){let u=t.prepare(`UPDATE sessions
1030
+ ORDER BY s.started_at`).all(s.id);if(n.length===0){console.error(d.warn(`Project "${s.name}" has 0 sessions.`));return}let r={clean:0,"fixed_v0.16.1":0,agent:0,manual_alias:0,template_pending:0,programmatic:0,recursive_meta:0,low_signal:0},o=[];for(let u of n){let m={auto_title:u.auto_title,auto_title_source:u.auto_title_source??null,has_alias:u.has_alias===1},p=jo(m);r[p]+=1,o.push({id:u.id,quality:p})}if(!e.dryRun){let u=t.prepare(`UPDATE sessions
1031
1031
  SET title_quality = ?,
1032
1032
  title_quality_computed_at = ?
1033
- WHERE id = ?`),p=Date.now();t.transaction(f=>{for(let g of f)u.run(g.quality,p,g.id)})(o)}if(e.json){console.log(JSON.stringify({project:s.name,project_id:s.id,total_sessions:n.length,dry_run:!!e.dryRun,counts:r},null,2));return}let i=n.length;console.log(""),console.log(d.project(`Title quality audit \u2014 project ${d.bold(s.name)}`)),s.decoded_path&&console.log(d.dim(` ${s.decoded_path}`)),console.log(d.dim(` ${i} sessions${e.dryRun?" (DRY RUN \u2014 no DB writes)":""}`)),console.log("");let a=["clean","fixed_v0.16.1","agent","manual_alias","template_pending","programmatic","recursive_meta","low_signal"],l=Math.max(...a.map(u=>u.length));for(let u of a){let p=r[u];if(p===0)continue;let m=(p/i*100).toFixed(1).padStart(5),f=Km(p,i);console.log(` ${u.padEnd(l)} ${d.bold(String(p).padStart(5))} ${m}% ${f}`)}console.log("");let c=r.template_pending+r.programmatic+r.recursive_meta+r.low_signal;if(c>0){let u=(c/i*100).toFixed(1);console.log(d.dim(` ${c} sessions (${u}%) eligible for cleanup phases L1/L3/L4.`))}else console.log(d.ok(" No cleanup-eligible sessions remain in this project. \u2713"));console.log("")}async function Ym(e,t){if(t){let o=e.prepare("SELECT id, name, decoded_path FROM projects WHERE name = ?").get(t);if(o)return o;let i=e.prepare("SELECT id, name, decoded_path FROM projects WHERE name LIKE ? ORDER BY name LIMIT 1").get(`%${t}%`);return i||null}let s=process.cwd(),n=e.prepare("SELECT id, name, decoded_path FROM projects WHERE decoded_path = ?").get(s);if(n)return n;let r=e.prepare("SELECT id, name, decoded_path FROM projects WHERE name = ? LIMIT 1").get(zm(s));return r||null}var Ai=28;function Km(e,t){let s=Math.round(e/t*Ai);return d.dim("\u2588".repeat(s)+"\xB7".repeat(Ai-s))}Dt();M();T();T();Dt();import{readFileSync as eg,existsSync as Fn,statSync as tg,readdirSync as sg}from"node:fs";import{join as _s}from"node:path";import{homedir as ng}from"node:os";import rg from"better-sqlite3";var $t=["vscode","cursor","windsurf"],og={vscode:"Code",cursor:"Cursor",windsurf:"Windsurf"};var ig=.7,ag=300*1e3;function cg(e){let t=e?.homeDir??ng(),s=e?.sources??$t,n=[];for(let r of s){let o=_s(t,"Library","Application Support",og[r],"User","workspaceStorage");Fn(o)&&n.push({source:r,root:o})}return n}function lg(e,t){let s=_s(e,"workspace.json"),n=_s(e,"state.vscdb");if(!Fn(s)||!Fn(n))return[];let r;try{let l=JSON.parse(eg(s,"utf8"));if(!l.folder||!l.folder.startsWith("file://"))return[];r=decodeURIComponent(l.folder.replace(/^file:\/\//,""))}catch{return[]}let o;try{o=tg(n).mtime.toISOString()}catch{return[]}let i;try{i=new rg(n,{readonly:!0,fileMustExist:!0})}catch{return[]}let a=[];try{let l=i.prepare("SELECT value FROM ItemTable WHERE key = 'terminal.integrated.bufferState' LIMIT 1").get(),c={};if(l?.value)try{c=JSON.parse(l.value)}catch{}let u=c.state??[];if(u.length===0)a.push({workspace_path:r,workspace_storage_dir:e,tab_name:null,cwd_hint:null,last_seen_at:o,source:t});else for(let p of u){let m=p.shellLaunchConfig??{},f=typeof m.name=="string"?m.name.trim():"";a.push({workspace_path:r,workspace_storage_dir:e,tab_name:f||null,cwd_hint:typeof m.cwd=="string"?m.cwd:null,last_seen_at:o,source:t})}}finally{i.close()}return a}function dg(e,t){let s=[],n=0;if(e.cwd&&t.workspace_path){let r=e.cwd,o=t.workspace_path;(r===o||r.startsWith(o+"/")||o.startsWith(r+"/"))&&(n+=.5,s.push("cwd_prefix"))}if(e.started_at&&t.last_seen_at){let r=Date.parse(e.started_at),o=Date.parse(t.last_seen_at);Number.isFinite(r)&&Number.isFinite(o)&&Math.abs(r-o)<=ag&&(n+=.4,s.push("time_window"))}return e.cwd&&t.cwd_hint&&e.cwd===t.cwd_hint&&(n+=.1,s.push("cwd_exact")),t.tab_name&&(n+=.2,s.push("has_name")),n>1&&(n=1),{score:n,matchedOn:s}}var ug=new Set(["zsh","bash","fish","sh","dash","ksh","tcsh","csh","pwsh","powershell","cmd","nu","node","deno","bun","python","python3","ruby","ts-node","tsx","go","cargo","java","php","irb","pry","iex","task","tasks","terminal","copilot","cascade","composer","claude","claude code"]);function pg(e){return ug.has(e.trim().toLowerCase())}function mg(e){let t=e.tab_name?.trim();return!t||pg(t)?null:t}function $i(e){let t=e?.minScore??ig,s=e?.limit,n=_(),r=e?.projectId?" AND s.project_id = ?":"",o=e?.projectId?[e.projectId]:[],i=n.prepare(`SELECT s.id, p.decoded_path AS cwd, s.started_at
1033
+ WHERE id = ?`),m=Date.now();t.transaction(f=>{for(let g of f)u.run(g.quality,m,g.id)})(o)}if(e.json){console.log(JSON.stringify({project:s.name,project_id:s.id,total_sessions:n.length,dry_run:!!e.dryRun,counts:r},null,2));return}let i=n.length;console.log(""),console.log(d.project(`Title quality audit \u2014 project ${d.bold(s.name)}`)),s.decoded_path&&console.log(d.dim(` ${s.decoded_path}`)),console.log(d.dim(` ${i} sessions${e.dryRun?" (DRY RUN \u2014 no DB writes)":""}`)),console.log("");let a=["clean","fixed_v0.16.1","agent","manual_alias","template_pending","programmatic","recursive_meta","low_signal"],l=Math.max(...a.map(u=>u.length));for(let u of a){let m=r[u];if(m===0)continue;let p=(m/i*100).toFixed(1).padStart(5),f=Sg(m,i);console.log(` ${u.padEnd(l)} ${d.bold(String(m).padStart(5))} ${p}% ${f}`)}console.log("");let c=r.template_pending+r.programmatic+r.recursive_meta+r.low_signal;if(c>0){let u=(c/i*100).toFixed(1);console.log(d.dim(` ${c} sessions (${u}%) eligible for cleanup phases L1/L3/L4.`))}else console.log(d.ok(" No cleanup-eligible sessions remain in this project. \u2713"));console.log("")}async function bg(e,t){if(t){let o=e.prepare("SELECT id, name, decoded_path FROM projects WHERE name = ?").get(t);if(o)return o;let i=e.prepare("SELECT id, name, decoded_path FROM projects WHERE name LIKE ? ORDER BY name LIMIT 1").get(`%${t}%`);return i||null}let s=process.cwd(),n=e.prepare("SELECT id, name, decoded_path FROM projects WHERE decoded_path = ?").get(s);if(n)return n;let r=e.prepare("SELECT id, name, decoded_path FROM projects WHERE name = ? LIMIT 1").get(Eg(s));return r||null}var Xi=28;function Sg(e,t){let s=Math.round(e/t*Xi);return d.dim("\u2588".repeat(s)+"\xB7".repeat(Xi-s))}Ft();I();T();T();Ft();import{readFileSync as xg,existsSync as zn,statSync as kg,readdirSync as Ng}from"node:fs";import{join as ys}from"node:path";import{homedir as Cg}from"node:os";import Lg from"better-sqlite3";var Ut=["vscode","cursor","windsurf"],Og={vscode:"Code",cursor:"Cursor",windsurf:"Windsurf"};var Ag=.7,Ig=300*1e3;function vg(e){let t=e?.homeDir??Cg(),s=e?.sources??Ut,n=[];for(let r of s){let o=ys(t,"Library","Application Support",Og[r],"User","workspaceStorage");zn(o)&&n.push({source:r,root:o})}return n}function Mg(e,t){let s=ys(e,"workspace.json"),n=ys(e,"state.vscdb");if(!zn(s)||!zn(n))return[];let r;try{let l=JSON.parse(xg(s,"utf8"));if(!l.folder||!l.folder.startsWith("file://"))return[];r=decodeURIComponent(l.folder.replace(/^file:\/\//,""))}catch{return[]}let o;try{o=kg(n).mtime.toISOString()}catch{return[]}let i;try{i=new Lg(n,{readonly:!0,fileMustExist:!0})}catch{return[]}let a=[];try{let l=i.prepare("SELECT value FROM ItemTable WHERE key = 'terminal.integrated.bufferState' LIMIT 1").get(),c={};if(l?.value)try{c=JSON.parse(l.value)}catch{}let u=c.state??[];if(u.length===0)a.push({workspace_path:r,workspace_storage_dir:e,tab_name:null,cwd_hint:null,last_seen_at:o,source:t});else for(let m of u){let p=m.shellLaunchConfig??{},f=typeof p.name=="string"?p.name.trim():"";a.push({workspace_path:r,workspace_storage_dir:e,tab_name:f||null,cwd_hint:typeof p.cwd=="string"?p.cwd:null,last_seen_at:o,source:t})}}finally{i.close()}return a}function Dg(e,t){let s=[],n=0;if(e.cwd&&t.workspace_path){let r=e.cwd,o=t.workspace_path;(r===o||r.startsWith(o+"/")||o.startsWith(r+"/"))&&(n+=.5,s.push("cwd_prefix"))}if(e.started_at&&t.last_seen_at){let r=Date.parse(e.started_at),o=Date.parse(t.last_seen_at);Number.isFinite(r)&&Number.isFinite(o)&&Math.abs(r-o)<=Ig&&(n+=.4,s.push("time_window"))}return e.cwd&&t.cwd_hint&&e.cwd===t.cwd_hint&&(n+=.1,s.push("cwd_exact")),t.tab_name&&(n+=.2,s.push("has_name")),n>1&&(n=1),{score:n,matchedOn:s}}var $g=new Set(["zsh","bash","fish","sh","dash","ksh","tcsh","csh","pwsh","powershell","cmd","nu","node","deno","bun","python","python3","ruby","ts-node","tsx","go","cargo","java","php","irb","pry","iex","task","tasks","terminal","copilot","cascade","composer","claude","claude code"]);function jg(e){return $g.has(e.trim().toLowerCase())}function Pg(e){let t=e.tab_name?.trim();return!t||jg(t)?null:t}function Ki(e){let t=e?.minScore??Ag,s=e?.limit,n=_(),r=e?.projectId?" AND s.project_id = ?":"",o=e?.projectId?[e.projectId]:[],i=n.prepare(`SELECT s.id, p.decoded_path AS cwd, s.started_at
1034
1034
  FROM sessions s
1035
1035
  JOIN projects p ON p.id = s.project_id
1036
1036
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1037
- WHERE (sa.alias IS NULL OR sa.alias = '')${r}`).all(...o),a=e?.sources??$t,l=cg({sources:a,homeDir:e?.homeDir}),c=[];for(let{source:p,root:m}of l){let f;try{f=sg(m)}catch{continue}for(let g of f){let h=_s(m,g);c.push(...lg(h,p))}}if(c.length===0)return[];let u=[];for(let p of i){let m=null;for(let g of c){let{score:h,matchedOn:E}=dg(p,g);h<t||(!m||h>m.score)&&(m={entry:g,score:h,matched:E})}if(!m)continue;let f=mg(m.entry);f&&u.push({session_id:p.id,proposed_alias:f,score:m.score,evidence:{source:m.entry.source,workspace_path:m.entry.workspace_path,workspace_storage_dir:m.entry.workspace_storage_dir,tab_name:m.entry.tab_name,cwd_hint:m.entry.cwd_hint,last_seen_at:m.entry.last_seen_at,matched_on:m.matched}})}return u.sort((p,m)=>m.score-p.score||p.session_id.localeCompare(m.session_id)),typeof s=="number"&&s>=0&&u.length>s?u.slice(0,s):u}function ji(e){let t=[],s=[];for(let n of e){let r=vi(n.session_id);if(r&&r.trim()!==""){s.push(n);continue}t.push(n)}return{applicable:t,skipped:s}}import{basename as gg}from"node:path";async function Fi(e){let t=_g(e.source);if(!t){console.error(d.err("Invalid --source. Allowed: vscode | cursor | windsurf | all (default).")),process.exitCode=1;return}let s=hg(e.minScore,.7);if(s===null||s<0||s>1){console.error(d.err("Invalid --min-score. Must be a number in [0, 1].")),process.exitCode=1;return}let n=e.limit?parseInt(e.limit,10):void 0;if(n!==void 0&&(!Number.isFinite(n)||n<0)){console.error(d.err("Invalid --limit. Must be a non-negative integer.")),process.exitCode=1;return}let r=e.project?Eg(e.project):void 0;if(e.project&&r===null){console.error(d.err(`No project found matching "${e.project}". Run \`recall projects\`.`)),process.exitCode=1;return}let o=$i({projectId:r??void 0,sources:t,minScore:s,limit:n}),{applicable:i,skipped:a}=ji(o);if(e.apply){let l=0;for(let c of i)try{fs(c.session_id,c.proposed_alias),l+=1}catch(u){console.error(d.err(`apply failed for ${c.session_id.slice(0,8)}: ${u.message}`))}if(e.json){console.log(JSON.stringify({mode:"apply",sources:t,min_score:s,project_id:r??null,applied:l,skipped:a.length,proposals:i.map(Pi)},null,2));return}console.log(""),console.log(d.ok(`Applied ${l} alias backfill${l===1?"":"s"}`+(a.length?` \xB7 skipped ${a.length} (alias appeared since proposal)`:""))),console.log("");return}if(e.json){console.log(JSON.stringify({mode:"dry-run",sources:t,min_score:s,project_id:r??null,proposals:i.map(Pi),skipped_due_to_existing_alias:a.length},null,2));return}fg(i,t,s,a.length)}function fg(e,t,s,n){if(console.log(""),console.log(d.project(`recall import-vscode-state \xB7 sources=${t.join("+")} min-score=${s.toFixed(2)} \xB7 DRY RUN`)),console.log(d.dim(" Pass --apply to write proposals via setAlias().")),console.log(""),e.length===0){console.log(d.warn(" No proposals \u2014 either no matching workspaces or every candidate session already has an alias.")),n>0&&console.log(d.dim(` ${n} sessions were skipped because they already have aliases.`)),console.log("");return}for(let r of e){let o=d.bold(r.session_id.slice(0,8)),i=d.bold(r.score.toFixed(2)),a=d.dim(`[${r.evidence.source}]`),l=r.evidence.matched_on.join("+");console.log(` ${o} score=${i} ${a} matched=${l}`),console.log(` proposed alias: ${d.bold(r.proposed_alias)}`),console.log(` workspace: ${d.dim(Y(r.evidence.workspace_path,70))}`),r.evidence.tab_name&&console.log(` tab name: ${r.evidence.tab_name}`),r.evidence.cwd_hint&&console.log(` cwd hint: ${d.dim(Y(r.evidence.cwd_hint,70))}`),console.log(` last seen: ${d.dim(r.evidence.last_seen_at)}`),console.log("")}console.log(d.dim(` ${e.length} proposal${e.length===1?"":"s"}`+(n>0?` \xB7 ${n} skipped (existing alias)`:"")+" \xB7 pass --apply to write via setAlias()")),console.log("")}function Pi(e){return e}function _g(e){if(!e||e==="all")return $t;let t=e.split(",").map(n=>n.trim().toLowerCase()).filter(Boolean),s=[];for(let n of t)if($t.includes(n))s.push(n);else return null;return s.length>0?s:null}function hg(e,t){if(e===void 0)return t;let s=Number.parseFloat(e);return Number.isFinite(s)?s:null}function Eg(e){let t=_(),s=t.prepare("SELECT id FROM projects WHERE name = ? LIMIT 1").get(e);if(s)return s.id;let n=t.prepare("SELECT id FROM projects WHERE name LIKE ? ORDER BY name LIMIT 1").get(`%${e}%`);if(n)return n.id;let r=gg(e);if(r&&r!==e){let o=t.prepare("SELECT id FROM projects WHERE name = ? LIMIT 1").get(r);if(o)return o.id}return null}import{existsSync as Ui,mkdirSync as bg,readFileSync as Sg,writeFileSync as yg}from"node:fs";import{homedir as Tg}from"node:os";import{join as Bi}from"node:path";import{z as We}from"zod";function Hi(){return process.env.RECALL_HOME??Bi(Tg(),".recall")}function wg(){let e=Hi();Ui(e)||bg(e,{recursive:!0})}function Wi(){return Bi(Hi(),"config.json")}var Xi=We.object({enabled:We.boolean().default(!1),model:We.string().optional(),ratePerMinute:We.number().int().min(1).max(600).default(30),lastProcessedSessionId:We.string().nullable().default(null),backfillPaused:We.boolean().default(!1),autoExtractEnabled:We.boolean().default(!1),autoExtractIntervalMinutes:We.number().int().min(5).max(720).default(60),autoExtractBatchSize:We.number().int().min(1).max(20).default(1)}),hs={enabled:!1,ratePerMinute:30,lastProcessedSessionId:null,backfillPaused:!1,autoExtractEnabled:!1,autoExtractIntervalMinutes:60,autoExtractBatchSize:1};function Ji(){let e=Wi();if(!Ui(e))return{};try{return JSON.parse(Sg(e,"utf8"))}catch(t){return console.error("[semantic-config] failed to parse config.json, using defaults:",t),{}}}function Oe(){let e=Ji().semantic;if(!e)return{...hs};let t=Xi.safeParse({...hs,...e});return t.success?t.data:{...hs}}function je(e){wg();let t=Ji(),s=Xi.parse({...hs,...t.semantic??{},...e}),n={...t,semantic:s};return yg(Wi(),JSON.stringify(n,null,2)),s}T();Xe();import{existsSync as Bg,mkdirSync as Hg,writeFileSync as Wg}from"node:fs";import{homedir as Xg}from"node:os";import{join as Hn}from"node:path";var Jg=1,Gg=12e3,zg=3,Yg=[];function Kg(){return process.env.RECALL_HOME??Hn(Xg(),".recall")}function sa(){return Hn(Kg(),"semantic")}function qg(){let e=sa();Bg(e)||Hg(e,{recursive:!0})}function Vg(e){let t=_(),s=t.prepare(`SELECT s.id, s.message_count, s.first_user_message,
1037
+ WHERE (sa.alias IS NULL OR sa.alias = '')${r}`).all(...o),a=e?.sources??Ut,l=vg({sources:a,homeDir:e?.homeDir}),c=[];for(let{source:m,root:p}of l){let f;try{f=Ng(p)}catch{continue}for(let g of f){let h=ys(p,g);c.push(...Mg(h,m))}}if(c.length===0)return[];let u=[];for(let m of i){let p=null;for(let g of c){let{score:h,matchedOn:E}=Dg(m,g);h<t||(!p||h>p.score)&&(p={entry:g,score:h,matched:E})}if(!p)continue;let f=Pg(p.entry);f&&u.push({session_id:m.id,proposed_alias:f,score:p.score,evidence:{source:p.entry.source,workspace_path:p.entry.workspace_path,workspace_storage_dir:p.entry.workspace_storage_dir,tab_name:p.entry.tab_name,cwd_hint:p.entry.cwd_hint,last_seen_at:p.entry.last_seen_at,matched_on:p.matched}})}return u.sort((m,p)=>p.score-m.score||m.session_id.localeCompare(p.session_id)),typeof s=="number"&&s>=0&&u.length>s?u.slice(0,s):u}function qi(e){let t=[],s=[];for(let n of e){let r=Gi(n.session_id);if(r&&r.trim()!==""){s.push(n);continue}t.push(n)}return{applicable:t,skipped:s}}import{basename as Fg}from"node:path";async function Zi(e){let t=Bg(e.source);if(!t){console.error(d.err("Invalid --source. Allowed: vscode | cursor | windsurf | all (default).")),process.exitCode=1;return}let s=Hg(e.minScore,.7);if(s===null||s<0||s>1){console.error(d.err("Invalid --min-score. Must be a number in [0, 1].")),process.exitCode=1;return}let n=e.limit?parseInt(e.limit,10):void 0;if(n!==void 0&&(!Number.isFinite(n)||n<0)){console.error(d.err("Invalid --limit. Must be a non-negative integer.")),process.exitCode=1;return}let r=e.project?Wg(e.project):void 0;if(e.project&&r===null){console.error(d.err(`No project found matching "${e.project}". Run \`recall projects\`.`)),process.exitCode=1;return}let o=Ki({projectId:r??void 0,sources:t,minScore:s,limit:n}),{applicable:i,skipped:a}=qi(o);if(e.apply){let l=0;for(let c of i)try{Ss(c.session_id,c.proposed_alias),l+=1}catch(u){console.error(d.err(`apply failed for ${c.session_id.slice(0,8)}: ${u.message}`))}if(e.json){console.log(JSON.stringify({mode:"apply",sources:t,min_score:s,project_id:r??null,applied:l,skipped:a.length,proposals:i.map(Vi)},null,2));return}console.log(""),console.log(d.ok(`Applied ${l} alias backfill${l===1?"":"s"}`+(a.length?` \xB7 skipped ${a.length} (alias appeared since proposal)`:""))),console.log("");return}if(e.json){console.log(JSON.stringify({mode:"dry-run",sources:t,min_score:s,project_id:r??null,proposals:i.map(Vi),skipped_due_to_existing_alias:a.length},null,2));return}Ug(i,t,s,a.length)}function Ug(e,t,s,n){if(console.log(""),console.log(d.project(`recall import-vscode-state \xB7 sources=${t.join("+")} min-score=${s.toFixed(2)} \xB7 DRY RUN`)),console.log(d.dim(" Pass --apply to write proposals via setAlias().")),console.log(""),e.length===0){console.log(d.warn(" No proposals \u2014 either no matching workspaces or every candidate session already has an alias.")),n>0&&console.log(d.dim(` ${n} sessions were skipped because they already have aliases.`)),console.log("");return}for(let r of e){let o=d.bold(r.session_id.slice(0,8)),i=d.bold(r.score.toFixed(2)),a=d.dim(`[${r.evidence.source}]`),l=r.evidence.matched_on.join("+");console.log(` ${o} score=${i} ${a} matched=${l}`),console.log(` proposed alias: ${d.bold(r.proposed_alias)}`),console.log(` workspace: ${d.dim(Y(r.evidence.workspace_path,70))}`),r.evidence.tab_name&&console.log(` tab name: ${r.evidence.tab_name}`),r.evidence.cwd_hint&&console.log(` cwd hint: ${d.dim(Y(r.evidence.cwd_hint,70))}`),console.log(` last seen: ${d.dim(r.evidence.last_seen_at)}`),console.log("")}console.log(d.dim(` ${e.length} proposal${e.length===1?"":"s"}`+(n>0?` \xB7 ${n} skipped (existing alias)`:"")+" \xB7 pass --apply to write via setAlias()")),console.log("")}function Vi(e){return e}function Bg(e){if(!e||e==="all")return Ut;let t=e.split(",").map(n=>n.trim().toLowerCase()).filter(Boolean),s=[];for(let n of t)if(Ut.includes(n))s.push(n);else return null;return s.length>0?s:null}function Hg(e,t){if(e===void 0)return t;let s=Number.parseFloat(e);return Number.isFinite(s)?s:null}function Wg(e){let t=_(),s=t.prepare("SELECT id FROM projects WHERE name = ? LIMIT 1").get(e);if(s)return s.id;let n=t.prepare("SELECT id FROM projects WHERE name LIKE ? ORDER BY name LIMIT 1").get(`%${e}%`);if(n)return n.id;let r=Fg(e);if(r&&r!==e){let o=t.prepare("SELECT id FROM projects WHERE name = ? LIMIT 1").get(r);if(o)return o.id}return null}import{existsSync as Qi,mkdirSync as Xg,readFileSync as Jg,writeFileSync as Gg}from"node:fs";import{homedir as zg}from"node:os";import{join as ea}from"node:path";import{z as Xe}from"zod";function ta(){return process.env.RECALL_HOME??ea(zg(),".recall")}function Yg(){let e=ta();Qi(e)||Xg(e,{recursive:!0})}function sa(){return ea(ta(),"config.json")}var na=Xe.object({enabled:Xe.boolean().default(!1),model:Xe.string().optional(),ratePerMinute:Xe.number().int().min(1).max(600).default(30),lastProcessedSessionId:Xe.string().nullable().default(null),backfillPaused:Xe.boolean().default(!1),autoExtractEnabled:Xe.boolean().default(!1),autoExtractIntervalMinutes:Xe.number().int().min(5).max(720).default(60),autoExtractBatchSize:Xe.number().int().min(1).max(20).default(1)}),Ts={enabled:!1,ratePerMinute:30,lastProcessedSessionId:null,backfillPaused:!1,autoExtractEnabled:!1,autoExtractIntervalMinutes:60,autoExtractBatchSize:1};function ra(){let e=sa();if(!Qi(e))return{};try{return JSON.parse(Jg(e,"utf8"))}catch(t){return console.error("[semantic-config] failed to parse config.json, using defaults:",t),{}}}function Ae(){let e=ra().semantic;if(!e)return{...Ts};let t=na.safeParse({...Ts,...e});return t.success?t.data:{...Ts}}function Pe(e){Yg();let t=ra(),s=na.parse({...Ts,...t.semantic??{},...e}),n={...t,semantic:s};return Gg(sa(),JSON.stringify(n,null,2)),s}T();Je();import{existsSync as pf,mkdirSync as gf,writeFileSync as ff}from"node:fs";import{homedir as _f}from"node:os";import{join as qn}from"node:path";var hf=1,Ef=12e3,bf=3,Sf=[];function yf(){return process.env.RECALL_HOME??qn(_f(),".recall")}function fa(){return qn(yf(),"semantic")}function Tf(){let e=fa();pf(e)||gf(e,{recursive:!0})}function wf(e){let t=_(),s=t.prepare(`SELECT s.id, s.message_count, s.first_user_message,
1038
1038
  p.name AS project,
1039
1039
  NULLIF(sa.alias, '') AS alias
1040
1040
  FROM sessions s
@@ -1043,10 +1043,10 @@ show full content: recall paste --show <id>
1043
1043
  WHERE s.id = ?`).get(e);if(!s)return null;let n=t.prepare(`SELECT role, content_text
1044
1044
  FROM messages
1045
1045
  WHERE session_id = ? AND is_sidechain = 0
1046
- ORDER BY COALESCE(timestamp, ''), rowid`).all(e),r=[],o=0;for(let i of n){if(!i.content_text)continue;let a=i.role??"system",l=i.content_text.replace(/```[\s\S]*?```/g,"[code]").replace(/<[^>]+>[\s\S]*?<\/[^>]+>/g,"").trim();if(!l)continue;let c=l.length>1500?l.slice(0,1500)+"\u2026":l,u=`${a}: ${c}`;if(o+u.length>Gg)break;r.push(u),o+=u.length}return{id:s.id,alias:s.alias,project:s.project,firstUserMessage:s.first_user_message,excerpt:r.join(`
1046
+ ORDER BY COALESCE(timestamp, ''), rowid`).all(e),r=[],o=0;for(let i of n){if(!i.content_text)continue;let a=i.role??"system",l=i.content_text.replace(/```[\s\S]*?```/g,"[code]").replace(/<[^>]+>[\s\S]*?<\/[^>]+>/g,"").trim();if(!l)continue;let c=l.length>1500?l.slice(0,1500)+"\u2026":l,u=`${a}: ${c}`;if(o+u.length>Ef)break;r.push(u),o+=u.length}return{id:s.id,alias:s.alias,project:s.project,firstUserMessage:s.first_user_message,excerpt:r.join(`
1047
1047
 
1048
- `),messageCount:s.message_count}}function Zg(e){return["You are summarizing a Claude Code session for a local semantic-search index. The summary will be stored as plain text and matched against future natural-language queries.","",`Session: ${e.alias??e.id}`,`Project: ${e.project}`,e.firstUserMessage?`Opening prompt: ${e.firstUserMessage}`:"","","Transcript excerpt (truncated):","---",e.excerpt,"---","","Output a single JSON object on one line, with no Markdown fences and no commentary:",'{"summary": "<3 sentences describing what the user was trying to do, what was built or debugged, and the outcome>", "keywords": ["<concept>", "<technology>", "<problem>", ...]}',"","Constraints:","- summary: 3 sentences, plain prose, no bullet points",'- keywords: 10\u201315 lowercase tokens, multi-word entries hyphenated (e.g. "memory-leak"); no duplicates; no generic words like "code" or "session"',"- Output JSON only. Do not echo this prompt."].filter(Boolean).join(`
1049
- `)}function Qg(e){let t=e.trim();try{let o=JSON.parse(t);typeof o.result=="string"&&(t=o.result.trim())}catch{}t=t.replace(/^```(?:json)?\s*/i,"").replace(/```\s*$/i,"").trim();let s=t.indexOf("{"),n=t.lastIndexOf("}");if(s===-1||n===-1||n<=s)return null;let r=t.slice(s,n+1);try{let o=JSON.parse(r),i=typeof o.summary=="string"?o.summary.trim():"",l=(Array.isArray(o.keywords)?o.keywords:[]).filter(c=>typeof c=="string").map(c=>c.trim().toLowerCase()).filter(c=>c.length>0&&c.length<64);return!i||l.length===0?null:{summary:i,keywords:Array.from(new Set(l)).slice(0,20)}}catch{return null}}function ef(e){let t=_(),s=e.keywords.join(",");t.prepare(`INSERT INTO session_semantic
1048
+ `),messageCount:s.message_count}}function Rf(e){return["You are summarizing a Claude Code session for a local semantic-search index. The summary will be stored as plain text and matched against future natural-language queries.","",`Session: ${e.alias??e.id}`,`Project: ${e.project}`,e.firstUserMessage?`Opening prompt: ${e.firstUserMessage}`:"","","Transcript excerpt (truncated):","---",e.excerpt,"---","","Output a single JSON object on one line, with no Markdown fences and no commentary:",'{"summary": "<3 sentences describing what the user was trying to do, what was built or debugged, and the outcome>", "keywords": ["<concept>", "<technology>", "<problem>", ...]}',"","Constraints:","- summary: 3 sentences, plain prose, no bullet points",'- keywords: 10\u201315 lowercase tokens, multi-word entries hyphenated (e.g. "memory-leak"); no duplicates; no generic words like "code" or "session"',"- Output JSON only. Do not echo this prompt."].filter(Boolean).join(`
1049
+ `)}function xf(e){let t=e.trim();try{let o=JSON.parse(t);typeof o.result=="string"&&(t=o.result.trim())}catch{}t=t.replace(/^```(?:json)?\s*/i,"").replace(/```\s*$/i,"").trim();let s=t.indexOf("{"),n=t.lastIndexOf("}");if(s===-1||n===-1||n<=s)return null;let r=t.slice(s,n+1);try{let o=JSON.parse(r),i=typeof o.summary=="string"?o.summary.trim():"",l=(Array.isArray(o.keywords)?o.keywords:[]).filter(c=>typeof c=="string").map(c=>c.trim().toLowerCase()).filter(c=>c.length>0&&c.length<64);return!i||l.length===0?null:{summary:i,keywords:Array.from(new Set(l)).slice(0,20)}}catch{return null}}function kf(e){let t=_(),s=e.keywords.join(",");t.prepare(`INSERT INTO session_semantic
1050
1050
  (session_id, summary, keywords, model, source_message_count, generated_at)
1051
1051
  VALUES (@session_id, @summary, @keywords, @model, @source_message_count, @generated_at)
1052
1052
  ON CONFLICT(session_id) DO UPDATE SET
@@ -1054,19 +1054,19 @@ show full content: recall paste --show <id>
1054
1054
  keywords = excluded.keywords,
1055
1055
  model = excluded.model,
1056
1056
  source_message_count = excluded.source_message_count,
1057
- generated_at = excluded.generated_at`).run({session_id:e.sessionId,summary:e.summary,keywords:s,model:e.model,source_message_count:e.sourceMessageCount,generated_at:e.generatedAt}),qg();let n=Hn(sa(),`${e.sessionId}.json`);Wg(n,JSON.stringify({version:Jg,session_id:e.sessionId,summary:e.summary,keywords:e.keywords,model:e.model,source_message_count:e.sourceMessageCount,generated_at:e.generatedAt},null,2))}var Es=null;function tf(){let t=Oe().ratePerMinute,s=t/6e4;return(!Es||Es.capacity!==t)&&(Es={tokens:t,capacity:t,refillPerMs:s,lastRefill:Date.now()}),Es}function sf(e){let t=Date.now(),s=t-e.lastRefill;s>0&&(e.tokens=Math.min(e.capacity,e.tokens+s*e.refillPerMs),e.lastRefill=t)}async function nf(e){for(;;){if(e?.aborted)throw new Error("aborted");let t=tf();if(sf(t),t.tokens>=1){t.tokens-=1;return}let s=1-t.tokens,n=Math.max(50,Math.ceil(s/t.refillPerMs));await new Promise(r=>setTimeout(r,Math.min(n,5e3)))}}async function rf(e,t={}){let s=Oe();if(!s.enabled)return{sessionId:e,ok:!1,reason:"disabled"};if(!ce())return{sessionId:e,ok:!1,reason:"claude-cli-missing"};let n=Vg(e);if(!n)return{sessionId:e,ok:!1,reason:"session-not-found"};if(n.messageCount<zg)return{sessionId:e,ok:!1,reason:"too-short"};if(!n.excerpt.trim())return{sessionId:e,ok:!1,reason:"empty-excerpt"};await nf(t.signal);let r=Zg(n),o=await pt(r,Yg,{model:s.model});if(!o.success)return{sessionId:e,ok:!1,reason:`claude-cli-exit-${o.exitCode??"null"}`,model:s.model??null};let i=Qg(o.stdout);return i?(ef({sessionId:n.id,summary:i.summary,keywords:i.keywords,model:s.model??null,sourceMessageCount:n.messageCount,generatedAt:new Date().toISOString()}),{sessionId:e,ok:!0,model:s.model??null}):{sessionId:e,ok:!1,reason:"parse-failed",model:s.model??null}}async function bs(e={}){let t=Oe();if(!t.enabled)return{total:0,processed:0,ok:0,failed:0,currentSessionId:null};let s=_(),r={limit:e.limit??1e3},o="s.message_count >= 3";e.force||(o+=" AND ss.session_id IS NULL"),typeof e.projectId=="number"&&(o+=" AND s.project_id = @projectId",r.projectId=e.projectId),t.lastProcessedSessionId&&e.force;let i=s.prepare(`SELECT s.id
1057
+ generated_at = excluded.generated_at`).run({session_id:e.sessionId,summary:e.summary,keywords:s,model:e.model,source_message_count:e.sourceMessageCount,generated_at:e.generatedAt}),Tf();let n=qn(fa(),`${e.sessionId}.json`);ff(n,JSON.stringify({version:hf,session_id:e.sessionId,summary:e.summary,keywords:e.keywords,model:e.model,source_message_count:e.sourceMessageCount,generated_at:e.generatedAt},null,2))}var ws=null;function Nf(){let t=Ae().ratePerMinute,s=t/6e4;return(!ws||ws.capacity!==t)&&(ws={tokens:t,capacity:t,refillPerMs:s,lastRefill:Date.now()}),ws}function Cf(e){let t=Date.now(),s=t-e.lastRefill;s>0&&(e.tokens=Math.min(e.capacity,e.tokens+s*e.refillPerMs),e.lastRefill=t)}async function Lf(e){for(;;){if(e?.aborted)throw new Error("aborted");let t=Nf();if(Cf(t),t.tokens>=1){t.tokens-=1;return}let s=1-t.tokens,n=Math.max(50,Math.ceil(s/t.refillPerMs));await new Promise(r=>setTimeout(r,Math.min(n,5e3)))}}async function Of(e,t={}){let s=Ae();if(!s.enabled)return{sessionId:e,ok:!1,reason:"disabled"};if(!ce())return{sessionId:e,ok:!1,reason:"claude-cli-missing"};let n=wf(e);if(!n)return{sessionId:e,ok:!1,reason:"session-not-found"};if(n.messageCount<bf)return{sessionId:e,ok:!1,reason:"too-short"};if(!n.excerpt.trim())return{sessionId:e,ok:!1,reason:"empty-excerpt"};await Lf(t.signal);let r=Rf(n),o=await pt(r,Sf,{model:s.model});if(!o.success)return{sessionId:e,ok:!1,reason:`claude-cli-exit-${o.exitCode??"null"}`,model:s.model??null};let i=xf(o.stdout);return i?(kf({sessionId:n.id,summary:i.summary,keywords:i.keywords,model:s.model??null,sourceMessageCount:n.messageCount,generatedAt:new Date().toISOString()}),{sessionId:e,ok:!0,model:s.model??null}):{sessionId:e,ok:!1,reason:"parse-failed",model:s.model??null}}async function Rs(e={}){let t=Ae();if(!t.enabled)return{total:0,processed:0,ok:0,failed:0,currentSessionId:null};let s=_(),r={limit:e.limit??1e3},o="s.message_count >= 3";e.force||(o+=" AND ss.session_id IS NULL"),typeof e.projectId=="number"&&(o+=" AND s.project_id = @projectId",r.projectId=e.projectId),t.lastProcessedSessionId&&e.force;let i=s.prepare(`SELECT s.id
1058
1058
  FROM sessions s
1059
1059
  LEFT JOIN session_semantic ss ON ss.session_id = s.id
1060
1060
  WHERE ${o}
1061
1061
  ORDER BY COALESCE(s.started_at, '') ASC, s.id ASC
1062
- LIMIT @limit`).all(r),a={total:i.length,processed:0,ok:0,failed:0,currentSessionId:null};e.onProgress?.(a);for(let{id:l}of i){if(e.signal?.aborted||Oe().backfillPaused)break;a.currentSessionId=l,e.onProgress?.({...a});try{(await rf(l,{signal:e.signal})).ok?a.ok+=1:a.failed+=1}catch(u){a.failed+=1,console.error("[semantic.backfill] failed for",l,u)}a.processed+=1,je({lastProcessedSessionId:l}),e.onProgress?.({...a})}return a.currentSessionId=null,e.onProgress?.({...a}),a}function na(){let e=Oe(),t=_(),s=t.prepare("SELECT COUNT(*) AS n FROM sessions WHERE message_count >= 3").get().n,n=t.prepare("SELECT COUNT(*) AS n FROM session_semantic").get().n;return{enabled:e.enabled,claudeCliAvailable:ce(),ratePerMinute:e.ratePerMinute,model:e.model??null,totalSessions:s,processedSessions:n,pendingSessions:Math.max(0,s-n),lastProcessedSessionId:e.lastProcessedSessionId,backfillPaused:e.backfillPaused}}Xe();Ts();qe();T();qe();T();function da(e){return e.replace(/```json[\s\S]*?```/g,"[tool-call]").replace(/\{[\s\S]{200,}?\}/g,"[json-object]")}function ff(e){let t=[],o=0;for(;o<e.length;){let i=[],a=0;for(;i.length<5&&o<e.length;){let c=e[o],u=da(c.content_text??"");if(a+u.length>2e3&&i.length>=3)break;i.push(c),a+=u.length,o++}if(i.length===0)break;let l=i.map(c=>{let u=c.role??"system",p=da(c.content_text??"");return`[${u}] ${p}`}).join(`
1063
-
1064
- `);t.push({messageUuids:i.map(c=>c.uuid),text:l}),o<e.length&&i.length>=3&&(o=Math.max(o-1,o-1))}return t}function Kn(e){let s=_().prepare("SELECT uuid, role, content_text FROM messages WHERE session_id = ? AND is_sidechain = 0 AND content_text IS NOT NULL ORDER BY rowid").all(e);return ff(s)}var _f=!1,hf=null;function Ef(){return _().prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}function ua(){return{running:_f,queueDepth:Ef(),lastProcessedAt:hf}}T();Se();async function pa(e,t){let s=(e??"status").toLowerCase();if(s==="on"||s==="enable"){if(!ce()){console.error("claude CLI not found on PATH. Install Claude Code first, then re-run."),process.exitCode=1;return}let l={enabled:!0};t.rate&&(l.ratePerMinute=Number(t.rate)),t.model&&(l.model=t.model);let c=je(l);console.log("Semantic search: ENABLED"),console.log(` Rate: ${c.ratePerMinute}/min`),c.model&&console.log(` Model: ${c.model}`),console.log(""),console.log("Disclosure: enabling semantic search sends condensed session"),console.log("summaries to Claude via your local `claude` CLI using your existing"),console.log("plan. New sessions are summarized on close. Run `recall semantic backfill`"),console.log("to summarize the existing archive.");return}if(s==="off"||s==="disable"){je({enabled:!1}),console.log("Semantic search: DISABLED"),console.log("Existing summaries are kept in the database; the pipeline will not run.");return}if(s==="pause"){je({backfillPaused:!0}),console.log("Backfill paused. Resume with `recall semantic resume`.");return}if(s==="resume"){je({backfillPaused:!1}),console.log("Backfill resumed.");return}if(s==="backfill"){let l=Oe();if(!l.enabled){console.error("Semantic search is disabled. Run `recall semantic on` first."),process.exitCode=1;return}l.backfillPaused&&je({backfillPaused:!1});let c=t.limit?Math.max(1,Number(t.limit)):1e3,u=!!t.force;console.log(`Backfilling up to ${c} sessions${u?" (force)":""}\u2026`);let p=Date.now(),m=0,f=await bs({limit:c,force:u,onProgress:h=>{if(h.processed===m)return;m=h.processed;let E=h.total>0?` (${Math.round(h.processed/h.total*100)}%)`:"";process.stdout.write(`\r ${h.processed}/${h.total}${E} ok=${h.ok} failed=${h.failed} `)}});process.stdout.write(`
1065
- `);let g=((Date.now()-p)/1e3).toFixed(1);console.log(`Done in ${g}s \u2014 processed=${f.processed} ok=${f.ok} failed=${f.failed}`);return}if(s==="install"){if(mt()){console.log("Model already installed.");return}console.log("Downloading bge-base-en-v1.5 (~110MB)..."),await Jn((l,c,u)=>{let p=u>0?Math.round(c/u*100):0;process.stdout.write(`\r ${l}: ${p}% `)}),process.stdout.write(`
1066
- `),console.log("Model installed. Loading embedder...");try{await Ke(),console.log("Done. Vector search is now active.")}catch(l){console.log("Model files installed."),console.log(` Embedder load skipped: ${l instanceof Error?l.message.split(`
1067
- `)[0]:String(l)}`),console.log(" Vector features remain available; runtime load happens on first use.")}return}if(s==="uninstall"){Gn(),console.log("Model removed. Vector search will fall back to keyword search.");return}if(s==="auto-extract"){let l=t._autoExtractAction;if(l==="on"||l==="enable"){let c=je({autoExtractEnabled:!0});console.log("Auto-extract: ENABLED"),console.log(` Cadence: 1 batch every ${c.autoExtractIntervalMinutes} minutes`),console.log(` Batch size: ${c.autoExtractBatchSize} session(s) per tick`),console.log(" Honors your 5-hour Claude plan window \u2014 at 60min/1, that is"),console.log(" ~5 extractions per window, leaving 95%+ of the rate budget free."),console.log(" The daemon will start nibbling through un-extracted sessions on"),console.log(" the next tick (within 15 minutes). Status: `recall semantic status`.");return}if(l==="off"||l==="disable"){je({autoExtractEnabled:!1}),console.log("Auto-extract: DISABLED. The daemon will stop running extract-outputs.");return}console.error("Usage: recall semantic auto-extract <on|off>"),process.exitCode=1;return}if(s==="reindex"){if(await Ce("Vector reindex"),!Je().loaded){if(!mt()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}await Ke()}let l=_(),c=l.prepare("SELECT id FROM sessions WHERE message_count >= 3").all();console.log(`Reindexing ${c.length} sessions...`);let u=0;for(let{id:p}of c){let m=Kn(p);if(m.length===0){u++;continue}let f=m.map(b=>b.text),g=await gt(f);l.prepare("DELETE FROM vec_chunks WHERE rowid IN (SELECT rowid FROM chunk_meta WHERE session_id = ?)").run(p),l.prepare("DELETE FROM chunk_meta WHERE session_id = ?").run(p);let h=l.prepare(`INSERT INTO chunk_meta(session_id, message_uuids, text, embedding_model_id, embedding_dim, stale, generated_at)
1068
- VALUES (?, ?, ?, 'bge-base-en-v1.5', 768, 0, datetime('now'))`),E=l.prepare("INSERT INTO vec_chunks(rowid, embedding) VALUES (?, ?)");for(let b=0;b<m.length;b++){let S=h.run(p,JSON.stringify(m[b].messageUuids),m[b].text),C=Buffer.from(g[b].buffer,g[b].byteOffset,g[b].byteLength);E.run(S.lastInsertRowid,C)}u++,u%10===0&&process.stdout.write(`\r ${u}/${c.length} `)}process.stdout.write(`
1069
- `),console.log(`Reindexed ${u} sessions.`);return}let n=na();console.log(`Semantic search: ${n.enabled?"ENABLED":"disabled"}`),console.log(` claude CLI: ${n.claudeCliAvailable?"available":"NOT FOUND"}`),console.log(` Rate: ${n.ratePerMinute}/min`),console.log(` Model: ${n.model??"claude default"}`),console.log(` Sessions: ${n.processedSessions}/${n.totalSessions} summarized`),console.log(` Pending: ${n.pendingSessions}`),n.lastProcessedSessionId&&console.log(` Cursor: ${n.lastProcessedSessionId}`),n.backfillPaused&&console.log(" Backfill: PAUSED (run `recall semantic resume`)");let r=mt(),o=Je(),i=ua(),a=Oe();console.log(""),console.log("Vector tier (Pro):"),console.log(` Model: ${r?"installed":"not installed"}`),console.log(` Embedder: ${o.loaded?"loaded":"not loaded"} (${o.modelId}, ${o.dim}d)`),console.log(` Worker: ${i.running?"running":"stopped"} (queue: ${i.queueDepth})`),console.log(""),console.log("Auto-extract:"),console.log(` Enabled: ${a.autoExtractEnabled?"YES":"no"}`),a.autoExtractEnabled?console.log(` Cadence: 1 batch every ${a.autoExtractIntervalMinutes} min \xD7 ${a.autoExtractBatchSize} session(s)`):console.log(" Run `recall semantic auto-extract on` to populate Patterns / Galaxy automatically."),process.env.RECALL_RRF_K&&console.log(` RRF k: ${process.env.RECALL_RRF_K}`)}T();T();T();qe();var Ve=400,Rs=768,bf="bge-base-en-v1.5";function Sf(e){return Buffer.from(e.buffer,e.byteOffset,e.byteLength)}function yf(e){if(!e.message_uuid)throw new Error("message_uuid is required");if(!e.session_id)throw new Error("session_id is required");if(!(e.embedding instanceof Float32Array))throw new Error("embedding must be a Float32Array");if(e.embedding.length!==Rs)throw new Error(`embedding dim mismatch: got ${e.embedding.length}, expected ${Rs}`);let t=e.embedding_model_id??bf,s=new Date().toISOString();return _().prepare(`INSERT INTO message_embeddings
1062
+ LIMIT @limit`).all(r),a={total:i.length,processed:0,ok:0,failed:0,currentSessionId:null};e.onProgress?.(a);for(let{id:l}of i){if(e.signal?.aborted||Ae().backfillPaused)break;a.currentSessionId=l,e.onProgress?.({...a});try{(await Of(l,{signal:e.signal})).ok?a.ok+=1:a.failed+=1}catch(u){a.failed+=1,console.error("[semantic.backfill] failed for",l,u)}a.processed+=1,Pe({lastProcessedSessionId:l}),e.onProgress?.({...a})}return a.currentSessionId=null,e.onProgress?.({...a}),a}function _a(){let e=Ae(),t=_(),s=t.prepare("SELECT COUNT(*) AS n FROM sessions WHERE message_count >= 3").get().n,n=t.prepare("SELECT COUNT(*) AS n FROM session_semantic").get().n;return{enabled:e.enabled,claudeCliAvailable:ce(),ratePerMinute:e.ratePerMinute,model:e.model??null,totalSessions:s,processedSessions:n,pendingSessions:Math.max(0,s-n),lastProcessedSessionId:e.lastProcessedSessionId,backfillPaused:e.backfillPaused}}Je();Ns();Ve();T();Ve();T();function wa(e){return e.replace(/```json[\s\S]*?```/g,"[tool-call]").replace(/\{[\s\S]{200,}?\}/g,"[json-object]")}function Uf(e){let t=[],o=0;for(;o<e.length;){let i=[],a=0;for(;i.length<5&&o<e.length;){let c=e[o],u=wa(c.content_text??"");if(a+u.length>2e3&&i.length>=3)break;i.push(c),a+=u.length,o++}if(i.length===0)break;let l=i.map(c=>{let u=c.role??"system",m=wa(c.content_text??"");return`[${u}] ${m}`}).join(`
1063
+
1064
+ `);t.push({messageUuids:i.map(c=>c.uuid),text:l}),o<e.length&&i.length>=3&&(o=Math.max(o-1,o-1))}return t}function nr(e){let s=_().prepare("SELECT uuid, role, content_text FROM messages WHERE session_id = ? AND is_sidechain = 0 AND content_text IS NOT NULL ORDER BY rowid").all(e);return Uf(s)}var Bf=!1,Hf=null;function Wf(){return _().prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}function Ra(){return{running:Bf,queueDepth:Wf(),lastProcessedAt:Hf}}T();fe();async function xa(e,t){let s=(e??"status").toLowerCase();if(s==="on"||s==="enable"){if(!ce()){console.error("claude CLI not found on PATH. Install Claude Code first, then re-run."),process.exitCode=1;return}let l={enabled:!0};t.rate&&(l.ratePerMinute=Number(t.rate)),t.model&&(l.model=t.model);let c=Pe(l);console.log("Semantic search: ENABLED"),console.log(` Rate: ${c.ratePerMinute}/min`),c.model&&console.log(` Model: ${c.model}`),console.log(""),console.log("Disclosure: enabling semantic search sends condensed session"),console.log("summaries to Claude via your local `claude` CLI using your existing"),console.log("plan. New sessions are summarized on close. Run `recall semantic backfill`"),console.log("to summarize the existing archive.");return}if(s==="off"||s==="disable"){Pe({enabled:!1}),console.log("Semantic search: DISABLED"),console.log("Existing summaries are kept in the database; the pipeline will not run.");return}if(s==="pause"){Pe({backfillPaused:!0}),console.log("Backfill paused. Resume with `recall semantic resume`.");return}if(s==="resume"){Pe({backfillPaused:!1}),console.log("Backfill resumed.");return}if(s==="backfill"){let l=Ae();if(!l.enabled){console.error("Semantic search is disabled. Run `recall semantic on` first."),process.exitCode=1;return}l.backfillPaused&&Pe({backfillPaused:!1});let c=t.limit?Math.max(1,Number(t.limit)):1e3,u=!!t.force;console.log(`Backfilling up to ${c} sessions${u?" (force)":""}\u2026`);let m=Date.now(),p=0,f=await Rs({limit:c,force:u,onProgress:h=>{if(h.processed===p)return;p=h.processed;let E=h.total>0?` (${Math.round(h.processed/h.total*100)}%)`:"";process.stdout.write(`\r ${h.processed}/${h.total}${E} ok=${h.ok} failed=${h.failed} `)}});process.stdout.write(`
1065
+ `);let g=((Date.now()-m)/1e3).toFixed(1);console.log(`Done in ${g}s \u2014 processed=${f.processed} ok=${f.ok} failed=${f.failed}`);return}if(s==="install"){if(gt()){console.log("Model already installed.");return}console.log("Downloading bge-base-en-v1.5 (~110MB)..."),await Qn((l,c,u)=>{let m=u>0?Math.round(c/u*100):0;process.stdout.write(`\r ${l}: ${m}% `)}),process.stdout.write(`
1066
+ `),console.log("Model installed. Loading embedder...");try{await qe(),console.log("Done. Vector search is now active.")}catch(l){console.log("Model files installed."),console.log(` Embedder load skipped: ${l instanceof Error?l.message.split(`
1067
+ `)[0]:String(l)}`),console.log(" Vector features remain available; runtime load happens on first use.")}return}if(s==="uninstall"){er(),console.log("Model removed. Vector search will fall back to keyword search.");return}if(s==="auto-extract"){let l=t._autoExtractAction;if(l==="on"||l==="enable"){let c=Pe({autoExtractEnabled:!0});console.log("Auto-extract: ENABLED"),console.log(` Cadence: 1 batch every ${c.autoExtractIntervalMinutes} minutes`),console.log(` Batch size: ${c.autoExtractBatchSize} session(s) per tick`),console.log(" Honors your 5-hour Claude plan window \u2014 at 60min/1, that is"),console.log(" ~5 extractions per window, leaving 95%+ of the rate budget free."),console.log(" The daemon will start nibbling through un-extracted sessions on"),console.log(" the next tick (within 15 minutes). Status: `recall semantic status`.");return}if(l==="off"||l==="disable"){Pe({autoExtractEnabled:!1}),console.log("Auto-extract: DISABLED. The daemon will stop running extract-outputs.");return}console.error("Usage: recall semantic auto-extract <on|off>"),process.exitCode=1;return}if(s==="reindex"){if(await Ce("Vector reindex"),!Ge().loaded){if(!gt()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}await qe()}let l=_(),c=l.prepare("SELECT id FROM sessions WHERE message_count >= 3").all();console.log(`Reindexing ${c.length} sessions...`);let u=0;for(let{id:m}of c){let p=nr(m);if(p.length===0){u++;continue}let f=p.map(b=>b.text),g=await ft(f);l.prepare("DELETE FROM vec_chunks WHERE rowid IN (SELECT rowid FROM chunk_meta WHERE session_id = ?)").run(m),l.prepare("DELETE FROM chunk_meta WHERE session_id = ?").run(m);let h=l.prepare(`INSERT INTO chunk_meta(session_id, message_uuids, text, embedding_model_id, embedding_dim, stale, generated_at)
1068
+ VALUES (?, ?, ?, 'bge-base-en-v1.5', 768, 0, datetime('now'))`),E=l.prepare("INSERT INTO vec_chunks(rowid, embedding) VALUES (?, ?)");for(let b=0;b<p.length;b++){let S=h.run(m,JSON.stringify(p[b].messageUuids),p[b].text),N=Buffer.from(g[b].buffer,g[b].byteOffset,g[b].byteLength);E.run(S.lastInsertRowid,N)}u++,u%10===0&&process.stdout.write(`\r ${u}/${c.length} `)}process.stdout.write(`
1069
+ `),console.log(`Reindexed ${u} sessions.`);return}let n=_a();console.log(`Semantic search: ${n.enabled?"ENABLED":"disabled"}`),console.log(` claude CLI: ${n.claudeCliAvailable?"available":"NOT FOUND"}`),console.log(` Rate: ${n.ratePerMinute}/min`),console.log(` Model: ${n.model??"claude default"}`),console.log(` Sessions: ${n.processedSessions}/${n.totalSessions} summarized`),console.log(` Pending: ${n.pendingSessions}`),n.lastProcessedSessionId&&console.log(` Cursor: ${n.lastProcessedSessionId}`),n.backfillPaused&&console.log(" Backfill: PAUSED (run `recall semantic resume`)");let r=gt(),o=Ge(),i=Ra(),a=Ae();console.log(""),console.log("Vector tier (Pro):"),console.log(` Model: ${r?"installed":"not installed"}`),console.log(` Embedder: ${o.loaded?"loaded":"not loaded"} (${o.modelId}, ${o.dim}d)`),console.log(` Worker: ${i.running?"running":"stopped"} (queue: ${i.queueDepth})`),console.log(""),console.log("Auto-extract:"),console.log(` Enabled: ${a.autoExtractEnabled?"YES":"no"}`),a.autoExtractEnabled?console.log(` Cadence: 1 batch every ${a.autoExtractIntervalMinutes} min \xD7 ${a.autoExtractBatchSize} session(s)`):console.log(" Run `recall semantic auto-extract on` to populate Patterns / Galaxy automatically."),process.env.RECALL_RRF_K&&console.log(` RRF k: ${process.env.RECALL_RRF_K}`)}T();T();T();Ve();var Ze=400,Ls=768,Xf="bge-base-en-v1.5";function Jf(e){return Buffer.from(e.buffer,e.byteOffset,e.byteLength)}function Gf(e){if(!e.message_uuid)throw new Error("message_uuid is required");if(!e.session_id)throw new Error("session_id is required");if(!(e.embedding instanceof Float32Array))throw new Error("embedding must be a Float32Array");if(e.embedding.length!==Ls)throw new Error(`embedding dim mismatch: got ${e.embedding.length}, expected ${Ls}`);let t=e.embedding_model_id??Xf,s=new Date().toISOString();return _().prepare(`INSERT INTO message_embeddings
1070
1070
  (message_uuid, session_id, embedding,
1071
1071
  embedding_model_id, embedding_dim, text_length, generated_at)
1072
1072
  VALUES (?, ?, ?, ?, ?, ?, ?)
@@ -1076,7 +1076,7 @@ show full content: recall paste --show <id>
1076
1076
  embedding_model_id = excluded.embedding_model_id,
1077
1077
  embedding_dim = excluded.embedding_dim,
1078
1078
  text_length = excluded.text_length,
1079
- generated_at = excluded.generated_at`).run(e.message_uuid,e.session_id,Sf(e.embedding),t,Rs,e.text_length,s),{message_uuid:e.message_uuid,session_id:e.session_id,embedding_model_id:t,embedding_dim:Rs,text_length:e.text_length,generated_at:s}}function Tf(e,t={}){let s=_(),n=t.force?`m.session_id = ? AND m.is_sidechain = 0
1079
+ generated_at = excluded.generated_at`).run(e.message_uuid,e.session_id,Jf(e.embedding),t,Ls,e.text_length,s),{message_uuid:e.message_uuid,session_id:e.session_id,embedding_model_id:t,embedding_dim:Ls,text_length:e.text_length,generated_at:s}}function zf(e,t={}){let s=_(),n=t.force?`m.session_id = ? AND m.is_sidechain = 0
1080
1080
  AND m.content_text IS NOT NULL
1081
1081
  AND length(m.content_text) > ?`:`m.session_id = ? AND m.is_sidechain = 0
1082
1082
  AND m.content_text IS NOT NULL
@@ -1086,7 +1086,7 @@ show full content: recall paste --show <id>
1086
1086
  LEFT JOIN message_embeddings me ON me.message_uuid = m.uuid
1087
1087
  WHERE ${n}
1088
1088
  ORDER BY m.timestamp ASC, m.rowid ASC
1089
- LIMIT ?`).all(e,Ve,r)}var ma=null;async function wf(){return ma||(Je().loaded||await Ke(),gt)}async function Rf(e,t={}){let s={embedded:0,skipped:0,failed:0,failures:[]},n=Tf(e,{limit:t.limit,force:t.force});if(n.length===0)return s;let r=await wf(),o=n.map(a=>a.content_text),i;try{if(t.signal?.aborted)return s;i=await r(o)}catch(a){return s.failed=n.length,s.failures=n.map(l=>({uuid:l.uuid,error:a instanceof Error?a.message:String(a)})),s}if(i.length!==n.length)return s.failed=n.length,s.failures=n.map(a=>({uuid:a.uuid,error:`embedder returned ${i.length} vectors for ${n.length} inputs`})),s;for(let a=0;a<n.length&&!t.signal?.aborted;a++)try{yf({message_uuid:n[a].uuid,session_id:n[a].session_id,embedding:i[a],text_length:o[a].length}),s.embedded+=1}catch(l){s.failed+=1,s.failures.push({uuid:n[a].uuid,error:l instanceof Error?l.message:String(l)})}return s.skipped=0,s}async function ga(e={}){let t=_(),s=[],n="s.message_count >= 1";typeof e.projectId=="number"&&(n+=" AND s.project_id = ?",s.push(e.projectId));let r=t.prepare(`SELECT DISTINCT s.id AS id
1089
+ LIMIT ?`).all(e,Ze,r)}var ka=null;async function Yf(){return ka||(Ge().loaded||await qe(),ft)}async function Kf(e,t={}){let s={embedded:0,skipped:0,failed:0,failures:[]},n=zf(e,{limit:t.limit,force:t.force});if(n.length===0)return s;let r=await Yf(),o=n.map(a=>a.content_text),i;try{if(t.signal?.aborted)return s;i=await r(o)}catch(a){return s.failed=n.length,s.failures=n.map(l=>({uuid:l.uuid,error:a instanceof Error?a.message:String(a)})),s}if(i.length!==n.length)return s.failed=n.length,s.failures=n.map(a=>({uuid:a.uuid,error:`embedder returned ${i.length} vectors for ${n.length} inputs`})),s;for(let a=0;a<n.length&&!t.signal?.aborted;a++)try{Gf({message_uuid:n[a].uuid,session_id:n[a].session_id,embedding:i[a],text_length:o[a].length}),s.embedded+=1}catch(l){s.failed+=1,s.failures.push({uuid:n[a].uuid,error:l instanceof Error?l.message:String(l)})}return s.skipped=0,s}async function Na(e={}){let t=_(),s=[],n="s.message_count >= 1";typeof e.projectId=="number"&&(n+=" AND s.project_id = ?",s.push(e.projectId));let r=t.prepare(`SELECT DISTINCT s.id AS id
1090
1090
  FROM sessions s
1091
1091
  JOIN messages m ON m.session_id = s.id
1092
1092
  LEFT JOIN message_embeddings me ON me.message_uuid = m.uuid
@@ -1096,7 +1096,7 @@ show full content: recall paste --show <id>
1096
1096
  AND length(m.content_text) > ?
1097
1097
  AND me.message_uuid IS NULL
1098
1098
  ORDER BY s.started_at ASC
1099
- LIMIT ?`).all(...s,Ve,e.limitSessions??1e3),o={total_sessions:r.length,processed_sessions:0,embedded_messages:0,failed_messages:0,current_session_id:null};e.onProgress?.({...o});for(let{id:i}of r){if(e.signal?.aborted)break;o.current_session_id=i,e.onProgress?.({...o});let a=await Rf(i,{limit:e.limitMessagesPerSession,signal:e.signal});o.embedded_messages+=a.embedded,o.failed_messages+=a.failed,o.processed_sessions+=1,e.onProgress?.({...o})}return o.current_session_id=null,e.onProgress?.({...o}),o}function xs(e,t){return t===0?0:Math.round(e/t*1e3)/10}function ge(e){return _().prepare("SELECT id, name FROM projects WHERE name = ? LIMIT 1").get(e)??null}function fa(e={}){let t=_(),s=null;if(typeof e.projectId=="number"){let S=t.prepare("SELECT id, name FROM projects WHERE id = ?").get(e.projectId);S&&(s=S)}else e.projectName&&(s=ge(e.projectName));let n=s?" WHERE s.project_id = ?":"",r=s?[s.id]:[],o=t.prepare(`SELECT
1099
+ LIMIT ?`).all(...s,Ze,e.limitSessions??1e3),o={total_sessions:r.length,processed_sessions:0,embedded_messages:0,failed_messages:0,current_session_id:null};e.onProgress?.({...o});for(let{id:i}of r){if(e.signal?.aborted)break;o.current_session_id=i,e.onProgress?.({...o});let a=await Kf(i,{limit:e.limitMessagesPerSession,signal:e.signal});o.embedded_messages+=a.embedded,o.failed_messages+=a.failed,o.processed_sessions+=1,e.onProgress?.({...o})}return o.current_session_id=null,e.onProgress?.({...o}),o}function Os(e,t){return t===0?0:Math.round(e/t*1e3)/10}function _e(e){return _().prepare("SELECT id, name FROM projects WHERE name = ? LIMIT 1").get(e)??null}function Ca(e={}){let t=_(),s=null;if(typeof e.projectId=="number"){let S=t.prepare("SELECT id, name FROM projects WHERE id = ?").get(e.projectId);S&&(s=S)}else e.projectName&&(s=_e(e.projectName));let n=s?" WHERE s.project_id = ?":"",r=s?[s.id]:[],o=t.prepare(`SELECT
1100
1100
  COUNT(*) AS total,
1101
1101
  SUM(CASE WHEN ss.session_id IS NOT NULL THEN 1 ELSE 0 END) AS with_semantic,
1102
1102
  SUM(CASE WHEN cm_count.session_id IS NOT NULL THEN 1 ELSE 0 END) AS with_chunks,
@@ -1109,23 +1109,23 @@ show full content: recall paste --show <id>
1109
1109
  LEFT JOIN (
1110
1110
  SELECT DISTINCT session_id FROM message_embeddings
1111
1111
  ) me_count ON me_count.session_id = s.id
1112
- ${n}`).get(...r),i=o.total??0,a=o.with_semantic??0,l=o.with_chunks??0,c=o.with_msg_emb??0,u=s?" JOIN sessions s ON s.id = m.session_id WHERE s.project_id = ?":"",p=t.prepare(`SELECT
1112
+ ${n}`).get(...r),i=o.total??0,a=o.with_semantic??0,l=o.with_chunks??0,c=o.with_msg_emb??0,u=s?" JOIN sessions s ON s.id = m.session_id WHERE s.project_id = ?":"",m=t.prepare(`SELECT
1113
1113
  COUNT(*) AS total,
1114
1114
  SUM(CASE
1115
1115
  WHEN m.is_sidechain = 0
1116
1116
  AND m.content_text IS NOT NULL
1117
- AND length(m.content_text) > ${Ve}
1117
+ AND length(m.content_text) > ${Ze}
1118
1118
  THEN 1 ELSE 0 END) AS eligible
1119
1119
  FROM messages m
1120
- ${u}`).get(...r),m=s?" JOIN sessions s ON s.id = me.session_id WHERE s.project_id = ?":"",f=t.prepare(`SELECT COUNT(*) AS embedded
1120
+ ${u}`).get(...r),p=s?" JOIN sessions s ON s.id = me.session_id WHERE s.project_id = ?":"",f=t.prepare(`SELECT COUNT(*) AS embedded
1121
1121
  FROM message_embeddings me
1122
- ${m}`).get(...r),g=s?" JOIN sessions s ON s.id = cm.session_id WHERE s.project_id = ?":"",h=t.prepare(`SELECT COUNT(*) AS n
1122
+ ${p}`).get(...r),g=s?" JOIN sessions s ON s.id = cm.session_id WHERE s.project_id = ?":"",h=t.prepare(`SELECT COUNT(*) AS n
1123
1123
  FROM chunk_meta cm
1124
1124
  ${g}`).get(...r),E=s?" JOIN sessions s ON s.id = cq.session_id WHERE s.project_id = ?":"",b=t.prepare(`SELECT COUNT(*) AS n
1125
1125
  FROM chunk_queue cq
1126
- ${E}`).get(...r);return{project:s,sessions:{total:i,with_semantic:a,with_semantic_pct:xs(a,i),with_chunks:l,with_chunks_pct:xs(l,i),with_message_embeddings:c,with_message_embeddings_pct:xs(c,i)},messages:{total:p.total??0,eligible:p.eligible??0,embedded:f.embedded,embedded_pct:xs(f.embedded,p.eligible??0),threshold_chars:Ve},chunks:{chunk_meta_rows:h.n,chunk_queue_pending:b.n},generated_at:new Date().toISOString()}}function _a(e){let s=e.sessions.with_semantic_pct,n=e.sessions.total-e.sessions.with_semantic,r=e.sessions.total>0&&s>=95,o=r?`${s}% session_semantic coverage (${e.sessions.with_semantic} of ${e.sessions.total})`:e.sessions.total===0?"no sessions in scope":`${s}% session_semantic coverage (need \u226595%); ${n} sessions missing summaries`;return{passes:r,required_pct:95,actual_pct:s,missing_sessions:n,reason:o}}Se();Ts();qe();async function ha(e,t){let s=(e??"audit").toLowerCase();if(s==="audit")return xf(t);if(s==="backfill-summaries")return Cf(t);if(s==="backfill-messages")return Nf(t);console.error(`Unknown embeddings action: ${e}. Supported: audit | backfill-summaries | backfill-messages`),process.exitCode=1}function qn(e){if(!e)return null;let t=ge(e);return t||"not-found"}async function xf(e){let t=qn(e.project);if(t==="not-found"){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let s=fa({projectId:t?t.id:void 0}),n=_a(s);if(e.json){console.log(JSON.stringify({report:s,verdict:n},null,2));return}kf(s,n),n.passes||(process.exitCode=1)}function kf(e,t){let s=e.project?`project "${e.project.name}"`:"all projects";console.log(`Embeddings coverage \u2014 ${s}`),console.log(""),console.log(` Sessions: ${e.sessions.total} total`),console.log(` session_semantic: ${e.sessions.with_semantic}/${e.sessions.total} (${e.sessions.with_semantic_pct}%)`),console.log(` chunk_meta (any): ${e.sessions.with_chunks}/${e.sessions.total} (${e.sessions.with_chunks_pct}%)`),console.log(` message_embeddings: ${e.sessions.with_message_embeddings}/${e.sessions.total} (${e.sessions.with_message_embeddings_pct}%)`),console.log(""),console.log(` Messages: ${e.messages.total} total`),console.log(` eligible (>${e.messages.threshold_chars} chars): ${e.messages.eligible}`),console.log(` embedded: ${e.messages.embedded}${e.messages.eligible>0?` (${e.messages.embedded_pct}% of eligible)`:""}`),console.log(""),console.log(" Chunks (Pro tier):"),console.log(` chunk_meta rows: ${e.chunks.chunk_meta_rows}`),console.log(` chunk_queue pending: ${e.chunks.chunk_queue_pending}`),e.chunks.chunk_queue_pending>1e3&&e.chunks.chunk_meta_rows===0&&(console.log(""),console.log(" \u26A0 chunk_queue is backed up but no chunks have been processed."),console.log(" Activate Pro and run `recall semantic install` to drain the queue.")),console.log(""),t.passes?console.log(` \u2705 Acceptance: ${t.reason}`):(console.log(` \u274C Acceptance: ${t.reason}`),console.log(` Run \`recall embeddings backfill-summaries${e.project?` --project ${e.project.name}`:""}\` to close the gap.`))}async function Cf(e){if(!Oe().enabled){console.error("Semantic search is disabled. Run `recall semantic on` first."),process.exitCode=1;return}let s=qn(e.project);if(s==="not-found"){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let n=e.limit?Math.max(1,Number(e.limit)):1e3,r=s?`project "${s.name}"`:"all projects";console.log(`Backfilling session_semantic \u2014 ${r} \u2014 up to ${n} sessions\u2026`);let o=Date.now(),i=0,a=await bs({limit:n,projectId:s?s.id:void 0,onProgress:c=>{if(e.json||c.processed===i)return;i=c.processed;let u=c.total>0?` (${Math.round(c.processed/c.total*100)}%)`:"";process.stdout.write(`\r ${c.processed}/${c.total}${u} ok=${c.ok} failed=${c.failed} `)}});e.json||process.stdout.write(`
1127
- `);let l=((Date.now()-o)/1e3).toFixed(1);e.json?console.log(JSON.stringify({...a,elapsed_seconds:Number(l)},null,2)):console.log(`Done in ${l}s \u2014 processed=${a.processed} ok=${a.ok} failed=${a.failed}`)}async function Nf(e){if(await Ce("Per-message embeddings"),!mt()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}Je().loaded||await Ke();let t=qn(e.project);if(t==="not-found"){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let s=e.limit?Math.max(1,Number(e.limit)):200,n=t?`project "${t.name}"`:"all projects";console.log(`Embedding messages > ${Ve} chars \u2014 ${n} \u2014 up to ${s} sessions\u2026`);let r=Date.now(),o=0,i=await ga({projectId:t?t.id:void 0,limitSessions:s,onProgress:m=>{if(e.json||m.processed_sessions===o)return;o=m.processed_sessions;let f=m.total_sessions>0?` (${Math.round(m.processed_sessions/m.total_sessions*100)}%)`:"";process.stdout.write(`\r ${m.processed_sessions}/${m.total_sessions} sessions${f} embedded=${m.embedded_messages} failed=${m.failed_messages} `)}});e.json||process.stdout.write(`
1128
- `);let a=((Date.now()-r)/1e3).toFixed(1);e.json?console.log(JSON.stringify({...i,elapsed_seconds:Number(a)},null,2)):console.log(`Done in ${a}s \u2014 sessions=${i.processed_sessions}/${i.total_sessions} embedded=${i.embedded_messages} failed=${i.failed_messages}`);let l=_(),c=t?" AND s.project_id = ?":"",u=t?[t.id]:[],p=l.prepare(`SELECT COUNT(DISTINCT s.id) AS n
1126
+ ${E}`).get(...r);return{project:s,sessions:{total:i,with_semantic:a,with_semantic_pct:Os(a,i),with_chunks:l,with_chunks_pct:Os(l,i),with_message_embeddings:c,with_message_embeddings_pct:Os(c,i)},messages:{total:m.total??0,eligible:m.eligible??0,embedded:f.embedded,embedded_pct:Os(f.embedded,m.eligible??0),threshold_chars:Ze},chunks:{chunk_meta_rows:h.n,chunk_queue_pending:b.n},generated_at:new Date().toISOString()}}function La(e){let s=e.sessions.with_semantic_pct,n=e.sessions.total-e.sessions.with_semantic,r=e.sessions.total>0&&s>=95,o=r?`${s}% session_semantic coverage (${e.sessions.with_semantic} of ${e.sessions.total})`:e.sessions.total===0?"no sessions in scope":`${s}% session_semantic coverage (need \u226595%); ${n} sessions missing summaries`;return{passes:r,required_pct:95,actual_pct:s,missing_sessions:n,reason:o}}fe();Ns();Ve();async function Oa(e,t){let s=(e??"audit").toLowerCase();if(s==="audit")return qf(t);if(s==="backfill-summaries")return Zf(t);if(s==="backfill-messages")return Qf(t);console.error(`Unknown embeddings action: ${e}. Supported: audit | backfill-summaries | backfill-messages`),process.exitCode=1}function rr(e){if(!e)return null;let t=_e(e);return t||"not-found"}async function qf(e){let t=rr(e.project);if(t==="not-found"){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let s=Ca({projectId:t?t.id:void 0}),n=La(s);if(e.json){console.log(JSON.stringify({report:s,verdict:n},null,2));return}Vf(s,n),n.passes||(process.exitCode=1)}function Vf(e,t){let s=e.project?`project "${e.project.name}"`:"all projects";console.log(`Embeddings coverage \u2014 ${s}`),console.log(""),console.log(` Sessions: ${e.sessions.total} total`),console.log(` session_semantic: ${e.sessions.with_semantic}/${e.sessions.total} (${e.sessions.with_semantic_pct}%)`),console.log(` chunk_meta (any): ${e.sessions.with_chunks}/${e.sessions.total} (${e.sessions.with_chunks_pct}%)`),console.log(` message_embeddings: ${e.sessions.with_message_embeddings}/${e.sessions.total} (${e.sessions.with_message_embeddings_pct}%)`),console.log(""),console.log(` Messages: ${e.messages.total} total`),console.log(` eligible (>${e.messages.threshold_chars} chars): ${e.messages.eligible}`),console.log(` embedded: ${e.messages.embedded}${e.messages.eligible>0?` (${e.messages.embedded_pct}% of eligible)`:""}`),console.log(""),console.log(" Chunks (Pro tier):"),console.log(` chunk_meta rows: ${e.chunks.chunk_meta_rows}`),console.log(` chunk_queue pending: ${e.chunks.chunk_queue_pending}`),e.chunks.chunk_queue_pending>1e3&&e.chunks.chunk_meta_rows===0&&(console.log(""),console.log(" \u26A0 chunk_queue is backed up but no chunks have been processed."),console.log(" Activate Pro and run `recall semantic install` to drain the queue.")),console.log(""),t.passes?console.log(` \u2705 Acceptance: ${t.reason}`):(console.log(` \u274C Acceptance: ${t.reason}`),console.log(` Run \`recall embeddings backfill-summaries${e.project?` --project ${e.project.name}`:""}\` to close the gap.`))}async function Zf(e){if(!Ae().enabled){console.error("Semantic search is disabled. Run `recall semantic on` first."),process.exitCode=1;return}let s=rr(e.project);if(s==="not-found"){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let n=e.limit?Math.max(1,Number(e.limit)):1e3,r=s?`project "${s.name}"`:"all projects";console.log(`Backfilling session_semantic \u2014 ${r} \u2014 up to ${n} sessions\u2026`);let o=Date.now(),i=0,a=await Rs({limit:n,projectId:s?s.id:void 0,onProgress:c=>{if(e.json||c.processed===i)return;i=c.processed;let u=c.total>0?` (${Math.round(c.processed/c.total*100)}%)`:"";process.stdout.write(`\r ${c.processed}/${c.total}${u} ok=${c.ok} failed=${c.failed} `)}});e.json||process.stdout.write(`
1127
+ `);let l=((Date.now()-o)/1e3).toFixed(1);e.json?console.log(JSON.stringify({...a,elapsed_seconds:Number(l)},null,2)):console.log(`Done in ${l}s \u2014 processed=${a.processed} ok=${a.ok} failed=${a.failed}`)}async function Qf(e){if(await Ce("Per-message embeddings"),!gt()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}Ge().loaded||await qe();let t=rr(e.project);if(t==="not-found"){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let s=e.limit?Math.max(1,Number(e.limit)):200,n=t?`project "${t.name}"`:"all projects";console.log(`Embedding messages > ${Ze} chars \u2014 ${n} \u2014 up to ${s} sessions\u2026`);let r=Date.now(),o=0,i=await Na({projectId:t?t.id:void 0,limitSessions:s,onProgress:p=>{if(e.json||p.processed_sessions===o)return;o=p.processed_sessions;let f=p.total_sessions>0?` (${Math.round(p.processed_sessions/p.total_sessions*100)}%)`:"";process.stdout.write(`\r ${p.processed_sessions}/${p.total_sessions} sessions${f} embedded=${p.embedded_messages} failed=${p.failed_messages} `)}});e.json||process.stdout.write(`
1128
+ `);let a=((Date.now()-r)/1e3).toFixed(1);e.json?console.log(JSON.stringify({...i,elapsed_seconds:Number(a)},null,2)):console.log(`Done in ${a}s \u2014 sessions=${i.processed_sessions}/${i.total_sessions} embedded=${i.embedded_messages} failed=${i.failed_messages}`);let l=_(),c=t?" AND s.project_id = ?":"",u=t?[t.id]:[],m=l.prepare(`SELECT COUNT(DISTINCT s.id) AS n
1129
1129
  FROM sessions s
1130
1130
  JOIN messages m ON m.session_id = s.id
1131
1131
  LEFT JOIN message_embeddings me ON me.message_uuid = m.uuid
@@ -1133,7 +1133,7 @@ show full content: recall paste --show <id>
1133
1133
  AND m.content_text IS NOT NULL
1134
1134
  AND length(m.content_text) > ?
1135
1135
  AND me.message_uuid IS NULL
1136
- ${c}`).get(Ve,...u);p.n>0&&console.log(` ${p.n} session(s) still have unembedded eligible messages. Re-run to continue.`)}T();Xe();import{createHash as Df}from"node:crypto";T();j();import{writeFileSync as Lf,readFileSync as xk,existsSync as Of,mkdirSync as Af,readdirSync as kk}from"node:fs";import{join as Ea}from"node:path";var Vn=Ea(R,"output-index");function If(){P(),Of(Vn)||Af(Vn,{recursive:!0})}function Ut(e){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}function vf(e){if(!e)return null;try{return JSON.parse(e)}catch{return e}}function ba(e){return{session_id:e.session_id,files_written:Ut(e.files_written),brands_mentioned:Ut(e.brands_mentioned),terms_introduced:Ut(e.terms_introduced),plan_ids_referenced:Ut(e.plan_ids_referenced),bug_signatures:Ut(e.bug_signatures),raw_extraction:vf(e.raw_extraction),extracted_at:e.extracted_at,extractor_version:e.extractor_version}}function Sa(e){if(!e.session_id)throw new Error("session_id is required");let t=_(),s=new Date().toISOString(),n=JSON.stringify(e.files_written??[]),r=JSON.stringify(e.brands_mentioned??[]),o=JSON.stringify(e.terms_introduced??[]),i=JSON.stringify(e.plan_ids_referenced??[]),a=JSON.stringify(e.bug_signatures??[]),l=e.raw_extraction===void 0?null:JSON.stringify(e.raw_extraction),c=Math.max(1,Math.floor(e.extractor_version??1));t.prepare(`INSERT INTO session_output_index
1136
+ ${c}`).get(Ze,...u);m.n>0&&console.log(` ${m.n} session(s) still have unembedded eligible messages. Re-run to continue.`)}T();Je();import{createHash as i_}from"node:crypto";T();j();import{writeFileSync as e_,readFileSync as lN,existsSync as t_,mkdirSync as s_,readdirSync as dN}from"node:fs";import{join as Aa}from"node:path";var or=Aa(R,"output-index");function n_(){P(),t_(or)||s_(or,{recursive:!0})}function Xt(e){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}function r_(e){if(!e)return null;try{return JSON.parse(e)}catch{return e}}function Ia(e){return{session_id:e.session_id,files_written:Xt(e.files_written),brands_mentioned:Xt(e.brands_mentioned),terms_introduced:Xt(e.terms_introduced),plan_ids_referenced:Xt(e.plan_ids_referenced),bug_signatures:Xt(e.bug_signatures),raw_extraction:r_(e.raw_extraction),extracted_at:e.extracted_at,extractor_version:e.extractor_version}}function va(e){if(!e.session_id)throw new Error("session_id is required");let t=_(),s=new Date().toISOString(),n=JSON.stringify(e.files_written??[]),r=JSON.stringify(e.brands_mentioned??[]),o=JSON.stringify(e.terms_introduced??[]),i=JSON.stringify(e.plan_ids_referenced??[]),a=JSON.stringify(e.bug_signatures??[]),l=e.raw_extraction===void 0?null:JSON.stringify(e.raw_extraction),c=Math.max(1,Math.floor(e.extractor_version??1));t.prepare(`INSERT INTO session_output_index
1137
1137
  (session_id, files_written, brands_mentioned, terms_introduced,
1138
1138
  plan_ids_referenced, bug_signatures, raw_extraction,
1139
1139
  extracted_at, extractor_version)
@@ -1146,7 +1146,7 @@ show full content: recall paste --show <id>
1146
1146
  bug_signatures = excluded.bug_signatures,
1147
1147
  raw_extraction = excluded.raw_extraction,
1148
1148
  extracted_at = excluded.extracted_at,
1149
- extractor_version = excluded.extractor_version`).run(e.session_id,n,r,o,i,a,l,s,c);let u=t.prepare("SELECT * FROM session_output_index WHERE session_id = ?").get(e.session_id);if(!u)throw new Error("setOutputIndex succeeded but read-back failed");let p=ba(u);return Mf(e.session_id),p}function Bt(e){let s=_().prepare("SELECT * FROM session_output_index WHERE session_id = ?").get(e);return s?ba(s):null}function Mf(e){try{If();let t=Bt(e);if(!t)return;let s=Ea(Vn,`${e}.json`),n={schema:"claude-recall.session-output-index.v1",backed_up_at:new Date().toISOString(),...t};Lf(s,JSON.stringify(n,null,2))}catch(t){console.error("[output-index] backup failed:",t)}}var Ht=1,er="claude-haiku-4-5-20251001",$f=3,jf=32e3,ya=2e3,Pf=30,Ff=30,Uf=30,Bf=30;function Hf(e){let s=_().prepare(`SELECT s.id,
1149
+ extractor_version = excluded.extractor_version`).run(e.session_id,n,r,o,i,a,l,s,c);let u=t.prepare("SELECT * FROM session_output_index WHERE session_id = ?").get(e.session_id);if(!u)throw new Error("setOutputIndex succeeded but read-back failed");let m=Ia(u);return o_(e.session_id),m}function Jt(e){let s=_().prepare("SELECT * FROM session_output_index WHERE session_id = ?").get(e);return s?Ia(s):null}function o_(e){try{n_();let t=Jt(e);if(!t)return;let s=Aa(or,`${e}.json`),n={schema:"claude-recall.session-output-index.v1",backed_up_at:new Date().toISOString(),...t};e_(s,JSON.stringify(n,null,2))}catch(t){console.error("[output-index] backup failed:",t)}}var Gt=1,cr="claude-haiku-4-5-20251001",a_=3,c_=32e3,Ma=2e3,l_=30,d_=30,u_=30,m_=30;function p_(e){let s=_().prepare(`SELECT s.id,
1150
1150
  NULLIF(sa.alias, '') AS alias,
1151
1151
  s.auto_title,
1152
1152
  s.auto_title_source,
@@ -1157,15 +1157,15 @@ show full content: recall paste --show <id>
1157
1157
  FROM sessions s
1158
1158
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1159
1159
  LEFT JOIN projects p ON p.id = s.project_id
1160
- WHERE s.id = ?`).get(e);return s?{...s,alias_source:s.alias?"manual":null}:null}function Ta(e,t={}){if(e.message_count<$f)return{eligible:!1,reason:"too-short"};let s=e.title_quality;if(s==="programmatic"||s==="recursive_meta")return{eligible:!1,reason:"low-signal-title"};if(e.auto_title_source==="agent"&&!e.alias)return{eligible:!1,reason:"agent-titled-no-override"};if(!t.force){let n=Bt(e.id);if(n&&n.extractor_version>=Ht)return{eligible:!1,reason:"already-extracted"}}return{eligible:!0}}function Wf(e){let t=Hf(e);if(!t)return null;let n=_().prepare(`SELECT role, content_text
1160
+ WHERE s.id = ?`).get(e);return s?{...s,alias_source:s.alias?"manual":null}:null}function Da(e,t={}){if(e.message_count<a_)return{eligible:!1,reason:"too-short"};let s=e.title_quality;if(s==="programmatic"||s==="recursive_meta")return{eligible:!1,reason:"low-signal-title"};if(e.auto_title_source==="agent"&&!e.alias)return{eligible:!1,reason:"agent-titled-no-override"};if(!t.force){let n=Jt(e.id);if(n&&n.extractor_version>=Gt)return{eligible:!1,reason:"already-extracted"}}return{eligible:!0}}function g_(e){let t=p_(e);if(!t)return null;let n=_().prepare(`SELECT role, content_text
1161
1161
  FROM messages
1162
1162
  WHERE session_id = ?
1163
1163
  AND is_sidechain = 0
1164
1164
  AND content_text IS NOT NULL
1165
- ORDER BY COALESCE(timestamp, ''), rowid`).all(e),r=[],o=0;for(let i of n){let a=i.role??"system",l=i.content_text.trim();if(!l)continue;let c=l.length>ya?l.slice(0,ya)+"\u2026":l,u=`${a}: ${c}`;if(o+u.length>jf)break;r.push(u),o+=u.length}return{meta:t,excerpt:r.join(`
1165
+ ORDER BY COALESCE(timestamp, ''), rowid`).all(e),r=[],o=0;for(let i of n){let a=i.role??"system",l=i.content_text.trim();if(!l)continue;let c=l.length>Ma?l.slice(0,Ma)+"\u2026":l,u=`${a}: ${c}`;if(o+u.length>c_)break;r.push(u),o+=u.length}return{meta:t,excerpt:r.join(`
1166
1166
 
1167
- `)}}function Xf(e){let{meta:t}=e;return["You are extracting a structured Output Index from a Claude Code session for a local knowledge graph.","","Read the transcript and produce a single JSON object with EXACTLY these fields. Output JSON only \u2014 no Markdown fences, no commentary, no explanation.","","Fields (every field MUST appear; use [] for empty):","- files_written: array of strings. Relative or absolute file paths the assistant created, edited, or extensively discussed (Write/Edit tool calls or paths quoted verbatim).",'- brands_mentioned: array of strings. Distinct proper-noun company / product / brand names mentioned. Examples of valid: "Glaser Group", "Apollo", "TikTok", "Cloudflare R2". NOT generic terms like "the company" or "users".','- terms_introduced: array of objects { "term": "<lowercase phrase>", "freq": <int> }. Distinctive multi-word noun phrases the session introduced or extensively discussed. Skip generic words. Cap at 30 entries.','- plan_ids_referenced: array of strings. Planning identifiers like "v0.18.A", "Phase D", "L3", "MASTER-PLAN-cognitive-graph". Empty array if none.','- bug_signatures: array of objects { "error_type": "<class or null>", "snippet": "<first line of the error>", "file": "<path or null>" }. Errors actually encountered in the session (not hypothetical). The error_type is the exception class (e.g. "TypeError", "ReferenceError") or null if unspecified.',"","Hard constraints:","- Do NOT fabricate. If a field has no concrete content from the transcript, output an empty array.","- Output JSON ONLY. No backticks, no markdown, no preamble.","- terms_introduced \u2264 30 entries; brands_mentioned \u2264 30 distinct entries; plan_ids_referenced \u2264 30; bug_signatures \u2264 30.","",`Session: ${t.alias??t.id.slice(0,8)}`,`Project: ${t.project??"unknown"}`,t.first_user_message?`Opening prompt: ${t.first_user_message.slice(0,500)}`:"","","Transcript excerpt (may be truncated):","---",e.excerpt,"---"].filter(Boolean).join(`
1168
- `)}function Jf(e){return Array.isArray(e)&&e.every(t=>typeof t=="string")}function Zn(e,t,s=!1){if(!Array.isArray(e))return[];let n=new Set,r=[];for(let o of e){if(typeof o!="string")continue;let i=s?o.trim().toLowerCase():o.trim();if(!(!i||i.length>256)&&!n.has(i)&&(n.add(i),r.push(i),r.length>=t))break}return r}function Gf(e,t){if(!Array.isArray(e))return[];let s=new Set,n=[];for(let r of e){if(!r||typeof r!="object")continue;let o=r.term,i=r.freq;if(typeof o!="string")continue;let a=o.trim().toLowerCase();if(!a||a.length>128||s.has(a))continue;s.add(a);let l=typeof i=="number"&&Number.isFinite(i)&&i>0?Math.floor(i):1;if(n.push({term:a,frequency:l}),n.length>=t)break}return n}function zf(e,t){if(!Array.isArray(e))return[];let s=[];for(let n of e){if(!n||typeof n!="object")continue;let r=n.error_type,o=n.snippet,i=n.file,a=typeof r=="string"&&r.trim().length>0?r.trim().slice(0,64):"unknown",l=typeof o=="string"?o.trim().replace(/\s+/g," ").slice(0,256):"";if(!l)continue;let c=typeof i=="string"&&i.trim().length>0?i.trim().slice(0,256):null,u=Df("sha256").update(`${a}::${l}`).digest("hex").slice(0,12);if(s.push({error_type:a,message_hash:u,snippet:l,file:c}),s.length>=t)break}return s}function Yf(e){let t=e.trim();try{let m=JSON.parse(t);typeof m.result=="string"&&(t=m.result.trim())}catch{}t=t.replace(/^```(?:json)?\s*/i,"").replace(/```\s*$/i,"").trim();let s=t.indexOf("{"),n=t.lastIndexOf("}");if(s===-1||n===-1||n<=s)return null;let r=t.slice(s,n+1),o;try{o=JSON.parse(r)}catch{return null}let i=Zn(o.files_written,200),a=Zn(o.brands_mentioned,Ff),l=Gf(o.terms_introduced,Pf),c=Zn(o.plan_ids_referenced,Uf),u=zf(o.bug_signatures,Bf);return i.length===0&&a.length===0&&l.length===0&&c.length===0&&u.length===0&&!Jf(o.files_written)?null:{files_written:i,brands_mentioned:a,terms_introduced:l,plan_ids_referenced:c,bug_signatures:u}}var Qn=null;async function Kf(e,t){return Qn?Qn(e,t):pt(e,[],{model:t})}async function qf(e,t={}){if(t.signal?.aborted)return{session_id:e,ok:!1,failed:"aborted"};let s=Wf(e);if(!s)return{session_id:e,ok:!1,skipped:"session-not-found"};let n=Ta(s.meta,{force:t.force});if(!n.eligible)return{session_id:e,ok:!1,skipped:n.reason};if(!Qn&&!ce())return{session_id:e,ok:!1,failed:"claude-cli-missing"};let r=Xf(s),o=t.model??er,i=await Kf(r,o);if(!i.success)return{session_id:e,ok:!1,failed:"claude-cli-error",exit_code:i.exitCode};let a=Yf(i.stdout);if(!a)return{session_id:e,ok:!1,failed:"parse-failed",exit_code:i.exitCode};let l=Vf(i.stdout),c=Sa({session_id:e,files_written:a.files_written,brands_mentioned:a.brands_mentioned,terms_introduced:a.terms_introduced,plan_ids_referenced:a.plan_ids_referenced,bug_signatures:a.bug_signatures,raw_extraction:{model:o,usage:l,raw_response_excerpt:i.stdout.slice(0,4e3)},extractor_version:Ht});return{session_id:e,ok:!0,index:c,usage:l}}function Vf(e){try{let t=JSON.parse(e.trim());if(t&&typeof t=="object"&&t.usage){let s=t.usage,n={};return typeof s.input_tokens=="number"&&(n.input_tokens=s.input_tokens),typeof s.output_tokens=="number"&&(n.output_tokens=s.output_tokens),n}}catch{}return null}function Zf(e={}){let t=_(),s=[],n=[];typeof e.projectId=="number"&&(s.push("s.project_id = ?"),n.push(e.projectId));let r=Math.max(1,Math.min(1e4,e.limit??1e3)),o=s.length?`WHERE ${s.join(" AND ")}`:"",i=t.prepare(`SELECT s.id,
1167
+ `)}}function f_(e){let{meta:t}=e;return["You are extracting a structured Output Index from a Claude Code session for a local knowledge graph.","","Read the transcript and produce a single JSON object with EXACTLY these fields. Output JSON only \u2014 no Markdown fences, no commentary, no explanation.","","Fields (every field MUST appear; use [] for empty):","- files_written: array of strings. Relative or absolute file paths the assistant created, edited, or extensively discussed (Write/Edit tool calls or paths quoted verbatim).",'- brands_mentioned: array of strings. Distinct proper-noun company / product / brand names mentioned. Examples of valid: "Glaser Group", "Apollo", "TikTok", "Cloudflare R2". NOT generic terms like "the company" or "users".','- terms_introduced: array of objects { "term": "<lowercase phrase>", "freq": <int> }. Distinctive multi-word noun phrases the session introduced or extensively discussed. Skip generic words. Cap at 30 entries.','- plan_ids_referenced: array of strings. Planning identifiers like "v0.18.A", "Phase D", "L3", "MASTER-PLAN-cognitive-graph". Empty array if none.','- bug_signatures: array of objects { "error_type": "<class or null>", "snippet": "<first line of the error>", "file": "<path or null>" }. Errors actually encountered in the session (not hypothetical). The error_type is the exception class (e.g. "TypeError", "ReferenceError") or null if unspecified.',"","Hard constraints:","- Do NOT fabricate. If a field has no concrete content from the transcript, output an empty array.","- Output JSON ONLY. No backticks, no markdown, no preamble.","- terms_introduced \u2264 30 entries; brands_mentioned \u2264 30 distinct entries; plan_ids_referenced \u2264 30; bug_signatures \u2264 30.","",`Session: ${t.alias??t.id.slice(0,8)}`,`Project: ${t.project??"unknown"}`,t.first_user_message?`Opening prompt: ${t.first_user_message.slice(0,500)}`:"","","Transcript excerpt (may be truncated):","---",e.excerpt,"---"].filter(Boolean).join(`
1168
+ `)}function __(e){return Array.isArray(e)&&e.every(t=>typeof t=="string")}function ir(e,t,s=!1){if(!Array.isArray(e))return[];let n=new Set,r=[];for(let o of e){if(typeof o!="string")continue;let i=s?o.trim().toLowerCase():o.trim();if(!(!i||i.length>256)&&!n.has(i)&&(n.add(i),r.push(i),r.length>=t))break}return r}function h_(e,t){if(!Array.isArray(e))return[];let s=new Set,n=[];for(let r of e){if(!r||typeof r!="object")continue;let o=r.term,i=r.freq;if(typeof o!="string")continue;let a=o.trim().toLowerCase();if(!a||a.length>128||s.has(a))continue;s.add(a);let l=typeof i=="number"&&Number.isFinite(i)&&i>0?Math.floor(i):1;if(n.push({term:a,frequency:l}),n.length>=t)break}return n}function E_(e,t){if(!Array.isArray(e))return[];let s=[];for(let n of e){if(!n||typeof n!="object")continue;let r=n.error_type,o=n.snippet,i=n.file,a=typeof r=="string"&&r.trim().length>0?r.trim().slice(0,64):"unknown",l=typeof o=="string"?o.trim().replace(/\s+/g," ").slice(0,256):"";if(!l)continue;let c=typeof i=="string"&&i.trim().length>0?i.trim().slice(0,256):null,u=i_("sha256").update(`${a}::${l}`).digest("hex").slice(0,12);if(s.push({error_type:a,message_hash:u,snippet:l,file:c}),s.length>=t)break}return s}function b_(e){let t=e.trim();try{let p=JSON.parse(t);typeof p.result=="string"&&(t=p.result.trim())}catch{}t=t.replace(/^```(?:json)?\s*/i,"").replace(/```\s*$/i,"").trim();let s=t.indexOf("{"),n=t.lastIndexOf("}");if(s===-1||n===-1||n<=s)return null;let r=t.slice(s,n+1),o;try{o=JSON.parse(r)}catch{return null}let i=ir(o.files_written,200),a=ir(o.brands_mentioned,d_),l=h_(o.terms_introduced,l_),c=ir(o.plan_ids_referenced,u_),u=E_(o.bug_signatures,m_);return i.length===0&&a.length===0&&l.length===0&&c.length===0&&u.length===0&&!__(o.files_written)?null:{files_written:i,brands_mentioned:a,terms_introduced:l,plan_ids_referenced:c,bug_signatures:u}}var ar=null;async function S_(e,t){return ar?ar(e,t):pt(e,[],{model:t})}async function y_(e,t={}){if(t.signal?.aborted)return{session_id:e,ok:!1,failed:"aborted"};let s=g_(e);if(!s)return{session_id:e,ok:!1,skipped:"session-not-found"};let n=Da(s.meta,{force:t.force});if(!n.eligible)return{session_id:e,ok:!1,skipped:n.reason};if(!ar&&!ce())return{session_id:e,ok:!1,failed:"claude-cli-missing"};let r=f_(s),o=t.model??cr,i=await S_(r,o);if(!i.success)return{session_id:e,ok:!1,failed:"claude-cli-error",exit_code:i.exitCode};let a=b_(i.stdout);if(!a)return{session_id:e,ok:!1,failed:"parse-failed",exit_code:i.exitCode};let l=T_(i.stdout),c=va({session_id:e,files_written:a.files_written,brands_mentioned:a.brands_mentioned,terms_introduced:a.terms_introduced,plan_ids_referenced:a.plan_ids_referenced,bug_signatures:a.bug_signatures,raw_extraction:{model:o,usage:l,raw_response_excerpt:i.stdout.slice(0,4e3)},extractor_version:Gt});return{session_id:e,ok:!0,index:c,usage:l}}function T_(e){try{let t=JSON.parse(e.trim());if(t&&typeof t=="object"&&t.usage){let s=t.usage,n={};return typeof s.input_tokens=="number"&&(n.input_tokens=s.input_tokens),typeof s.output_tokens=="number"&&(n.output_tokens=s.output_tokens),n}}catch{}return null}function w_(e={}){let t=_(),s=[],n=[];typeof e.projectId=="number"&&(s.push("s.project_id = ?"),n.push(e.projectId));let r=Math.max(1,Math.min(1e4,e.limit??1e3)),o=s.length?`WHERE ${s.join(" AND ")}`:"",i=t.prepare(`SELECT s.id,
1169
1169
  NULLIF(sa.alias, '') AS alias,
1170
1170
  s.auto_title,
1171
1171
  s.auto_title_source,
@@ -1177,13 +1177,13 @@ show full content: recall paste --show <id>
1177
1177
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1178
1178
  LEFT JOIN projects p ON p.id = s.project_id
1179
1179
  ${o}
1180
- ORDER BY COALESCE(s.started_at, ''), s.id`).all(...n),a=[],l=new Map;for(let c of i){let u={...c,alias_source:c.alias?"manual":null},p=Ta(u,{force:e.force});if(!p.eligible){let m=p.reason??"session-not-found";l.set(m,(l.get(m)??0)+1);continue}if(a.push(u),a.length>=r)break}return{eligible:a,skipped:l}}async function wa(e={}){let t=Zf({projectId:e.projectId,limit:e.limit,force:e.force}),s={total:t.eligible.length,processed:0,ok:0,failed:0,skipped:0,current_session_id:null,total_input_tokens:0,total_output_tokens:0};for(let r of t.skipped.values())s.skipped+=r;e.onProgress?.({...s});let n=[];for(let r of t.eligible){if(e.signal?.aborted)break;s.current_session_id=r.id,e.onProgress?.({...s});let o=await qf(r.id,{model:e.model,force:e.force,signal:e.signal});n.push(o),e.onResult?.(o),o.ok?s.ok+=1:o.skipped?s.skipped+=1:s.failed+=1,o.usage?.input_tokens&&(s.total_input_tokens+=o.usage.input_tokens),o.usage?.output_tokens&&(s.total_output_tokens+=o.usage.output_tokens),s.processed+=1,e.onProgress?.({...s})}return s.current_session_id=null,e.onProgress?.({...s}),{progress:s,results:n}}Xe();async function Ra(e){if(!e.project){console.error("--project <name> is required."),process.exitCode=1;return}let t=ge(e.project);if(!t){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}if(!ce()){console.error("claude CLI not found on PATH. Install Claude Code first, then re-run."),process.exitCode=1;return}let s=e.limit?Math.max(1,Number(e.limit)):200,n=e.model??er;e.json||console.log(`Extracting Output Index \u2014 project "${t.name}" \u2014 extractor v${Ht} \u2014 model ${n} \u2014 up to ${s} sessions\u2026`);let r=Date.now(),o=-1,{progress:i,results:a}=await wa({projectId:t.id,limit:s,force:e.force,model:n,onProgress:u=>{if(e.json||u.processed===o)return;o=u.processed;let p=u.total>0?` (${Math.round(u.processed/u.total*100)}%)`:"";process.stdout.write(`\r ${u.processed}/${u.total}${p} ok=${u.ok} failed=${u.failed} skipped=${u.skipped} in=${u.total_input_tokens} out=${u.total_output_tokens} `)}});e.json||process.stdout.write(`
1181
- `);let l=Number(((Date.now()-r)/1e3).toFixed(1)),c=i.total>0?Math.round(i.ok/i.total*1e3)/10:0;if(e.json){let u=a.filter(p=>!p.ok&&p.failed).map(p=>({session_id:p.session_id,failed:p.failed,exit_code:p.exit_code??null}));console.log(JSON.stringify({project:t.name,extractor_version:Ht,model:n,progress:i,acceptance_pct:c,failures:u.slice(0,20),elapsed_seconds:l},null,2))}else console.log(`Done in ${l}s \u2014 ok=${i.ok}/${i.total} (${c}%) failed=${i.failed} skipped=${i.skipped}`),console.log(`Token spend: input=${i.total_input_tokens} output=${i.total_output_tokens}`),i.total>0&&c<90?(console.log(` \u26A0 Phase D acceptance bar is 90% non-empty Output Index; actual ${c}%. Inspect failures and re-run.`),process.exitCode=1):i.total===0&&console.log(" \u24D8 No eligible sessions (all sessions were skipped or already extracted).")}T();Wt();var Ls={citation:"same-project",similar:"same-project",skill_track:"same-project",bug_pattern:"cross-project",wiki_link:"cross-project",temporal_proximity:"same-project"},d_=2,u_=.25,p_=5,m_=60,g_=25;function Ns(e){return e.trim().toLowerCase()}function f_(e){let t=new Set;for(let s of e.files_written)t.add(`file:${Ns(s)}`);for(let s of e.brands_mentioned)t.add(`brand:${Ns(s)}`);for(let s of e.terms_introduced)t.add(`term:${Ns(s)}`);for(let s of e.plan_ids_referenced)t.add(`plan:${Ns(s)}`);return t}function __(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/m_);return Math.max(.2,t)}function h_(e,t){if(!e||!t)return 0;let s=Date.parse(e),n=Date.parse(t);return!Number.isFinite(s)||!Number.isFinite(n)?0:Math.abs(n-s)/(1e3*60*60*24)}function E_(e){let t=Bt(e);return t?{session_id:t.session_id,files_written:t.files_written,brands_mentioned:t.brands_mentioned,terms_introduced:t.terms_introduced.map(s=>s.term),plan_ids_referenced:t.plan_ids_referenced}:null}function b_(e){return _().prepare(`SELECT s.id AS id, s.project_id AS project_id, s.started_at AS started_at
1180
+ ORDER BY COALESCE(s.started_at, ''), s.id`).all(...n),a=[],l=new Map;for(let c of i){let u={...c,alias_source:c.alias?"manual":null},m=Da(u,{force:e.force});if(!m.eligible){let p=m.reason??"session-not-found";l.set(p,(l.get(p)??0)+1);continue}if(a.push(u),a.length>=r)break}return{eligible:a,skipped:l}}async function $a(e={}){let t=w_({projectId:e.projectId,limit:e.limit,force:e.force}),s={total:t.eligible.length,processed:0,ok:0,failed:0,skipped:0,current_session_id:null,total_input_tokens:0,total_output_tokens:0};for(let r of t.skipped.values())s.skipped+=r;e.onProgress?.({...s});let n=[];for(let r of t.eligible){if(e.signal?.aborted)break;s.current_session_id=r.id,e.onProgress?.({...s});let o=await y_(r.id,{model:e.model,force:e.force,signal:e.signal});n.push(o),e.onResult?.(o),o.ok?s.ok+=1:o.skipped?s.skipped+=1:s.failed+=1,o.usage?.input_tokens&&(s.total_input_tokens+=o.usage.input_tokens),o.usage?.output_tokens&&(s.total_output_tokens+=o.usage.output_tokens),s.processed+=1,e.onProgress?.({...s})}return s.current_session_id=null,e.onProgress?.({...s}),{progress:s,results:n}}Je();async function ja(e){if(!e.project){console.error("--project <name> is required."),process.exitCode=1;return}let t=_e(e.project);if(!t){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}if(!ce()){console.error("claude CLI not found on PATH. Install Claude Code first, then re-run."),process.exitCode=1;return}let s=e.limit?Math.max(1,Number(e.limit)):200,n=e.model??cr;e.json||console.log(`Extracting Output Index \u2014 project "${t.name}" \u2014 extractor v${Gt} \u2014 model ${n} \u2014 up to ${s} sessions\u2026`);let r=Date.now(),o=-1,{progress:i,results:a}=await $a({projectId:t.id,limit:s,force:e.force,model:n,onProgress:u=>{if(e.json||u.processed===o)return;o=u.processed;let m=u.total>0?` (${Math.round(u.processed/u.total*100)}%)`:"";process.stdout.write(`\r ${u.processed}/${u.total}${m} ok=${u.ok} failed=${u.failed} skipped=${u.skipped} in=${u.total_input_tokens} out=${u.total_output_tokens} `)}});e.json||process.stdout.write(`
1181
+ `);let l=Number(((Date.now()-r)/1e3).toFixed(1)),c=i.total>0?Math.round(i.ok/i.total*1e3)/10:0;if(e.json){let u=a.filter(m=>!m.ok&&m.failed).map(m=>({session_id:m.session_id,failed:m.failed,exit_code:m.exit_code??null}));console.log(JSON.stringify({project:t.name,extractor_version:Gt,model:n,progress:i,acceptance_pct:c,failures:u.slice(0,20),elapsed_seconds:l},null,2))}else console.log(`Done in ${l}s \u2014 ok=${i.ok}/${i.total} (${c}%) failed=${i.failed} skipped=${i.skipped}`),console.log(`Token spend: input=${i.total_input_tokens} output=${i.total_output_tokens}`),i.total>0&&c<90?(console.log(` \u26A0 Phase D acceptance bar is 90% non-empty Output Index; actual ${c}%. Inspect failures and re-run.`),process.exitCode=1):i.total===0&&console.log(" \u24D8 No eligible sessions (all sessions were skipped or already extracted).")}T();zt();var Ms={citation:"same-project",similar:"same-project",skill_track:"same-project",bug_pattern:"cross-project",wiki_link:"cross-project",temporal_proximity:"same-project"},D_=2,$_=.25,j_=5,P_=60,F_=25;function vs(e){return e.trim().toLowerCase()}function U_(e){let t=new Set;for(let s of e.files_written)t.add(`file:${vs(s)}`);for(let s of e.brands_mentioned)t.add(`brand:${vs(s)}`);for(let s of e.terms_introduced)t.add(`term:${vs(s)}`);for(let s of e.plan_ids_referenced)t.add(`plan:${vs(s)}`);return t}function B_(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/P_);return Math.max(.2,t)}function H_(e,t){if(!e||!t)return 0;let s=Date.parse(e),n=Date.parse(t);return!Number.isFinite(s)||!Number.isFinite(n)?0:Math.abs(n-s)/(1e3*60*60*24)}function W_(e){let t=Jt(e);return t?{session_id:t.session_id,files_written:t.files_written,brands_mentioned:t.brands_mentioned,terms_introduced:t.terms_introduced.map(s=>s.term),plan_ids_referenced:t.plan_ids_referenced}:null}function X_(e){return _().prepare(`SELECT s.id AS id, s.project_id AS project_id, s.started_at AS started_at
1182
1182
  FROM sessions s
1183
1183
  JOIN session_output_index oi ON oi.session_id = s.id
1184
1184
  WHERE s.project_id = ?
1185
- ORDER BY COALESCE(s.started_at, ''), s.id`).all(e)}function S_(e,t){let s=new Map,n=new Map,r=new Map;for(let o of e){r.set(o.id,o.started_at);let i=t.get(o.id);if(!i)continue;let a=f_(i);if(a.size!==0){n.set(o.id,a);for(let l of a){let c=s.get(l);c?c.push(o.id):s.set(l,[o.id])}}}return{posting:s,vocab:n,startedAt:r}}function y_(e,t){let s=t.vocab.get(e),n=t.startedAt.get(e)??null;if(!s||!n)return[];let r=new Map;for(let i of s){let a=t.posting.get(i);if(a)for(let l of a){if(l===e)continue;let c=t.startedAt.get(l);if(!c||c>=n)continue;let u=r.get(l);u?u.push(i):r.set(l,[i])}}let o=[];for(let[i,a]of r){let l=a.length;if(l<d_)continue;let c=t.startedAt.get(i)??null,u=h_(n,c),p=__(u),m=Math.min(1,l/p_*p);if(m<u_)continue;let f=a.slice(0,12);o.push({target_session_id:i,matched_terms:f,overlap:l,days_apart:Math.round(u*10)/10,recency:Math.round(p*1e3)/1e3,confidence:Math.round(m*1e3)/1e3})}return o.sort((i,a)=>a.confidence-i.confidence),o.slice(0,g_)}async function va(e){if(Ls.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project \u2014 refusing to run inference");let t=b_(e.projectId),s=new Map;for(let i of t){let a=E_(i.id);a&&s.set(i.id,a)}let n=S_(t,s),r={total_sessions:t.length,processed_sessions:0,suggestions_created:0,suggestions_skipped_existing:0,current_session_id:null};e.onProgress?.({...r});let o=[];for(let i of t){if(e.signal?.aborted)break;r.current_session_id=i.id,e.onProgress?.({...r});let a=y_(i.id,n);for(let l of a)try{let c=Ze({source_session_id:i.id,target_session_id:l.target_session_id,link_type:"citation",confidence:l.confidence,evidence:{matched_terms:l.matched_terms,overlap_count:l.overlap,recency:l.recency,days_apart:l.days_apart},inferred_by:"L2"});o.push(c.id),r.suggestions_created+=1}catch(c){console.error("[citation-inference] createSuggestion failed:",c)}r.processed_sessions+=1,e.onProgress?.({...r})}return r.current_session_id=null,e.onProgress?.({...r}),{progress:r,suggestion_ids:o}}async function Ma(e){if(!e.project){console.error("--project <name> is required."),process.exitCode=1;return}let t=ge(e.project);if(!t){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}e.json||console.log(`Inferring citation suggestions \u2014 project "${t.name}"\u2026`);let s=Date.now(),n=-1,r=await va({projectId:t.id,onProgress:i=>{if(e.json||i.processed_sessions===n)return;n=i.processed_sessions;let a=i.total_sessions>0?` (${Math.round(i.processed_sessions/i.total_sessions*100)}%)`:"";process.stdout.write(`\r ${i.processed_sessions}/${i.total_sessions} sessions${a} suggestions=${i.suggestions_created} `)}});e.json||process.stdout.write(`
1186
- `);let o=Number(((Date.now()-s)/1e3).toFixed(1));e.json?console.log(JSON.stringify({project:t.name,progress:r.progress,suggestion_count:r.suggestion_ids.length,sample_suggestion_ids:r.suggestion_ids.slice(0,25),elapsed_seconds:o},null,2)):(console.log(`Done in ${o}s \u2014 sessions=${r.progress.processed_sessions}/${r.progress.total_sessions} suggestions=${r.progress.suggestions_created}`),r.progress.total_sessions===0?console.log(` \u24D8 No sessions had a populated Output Index. Run \`recall extract-outputs --project ${t.name}\` first.`):r.progress.suggestions_created===0?console.log(" \u24D8 No suggestions met the confidence threshold. This is expected on small corpora; the Output Index needs more shared vocabulary across sessions for citations to surface."):console.log(" Review the queue at GET /api/links/suggestions?status=pending (Phase F UI ships the queue review)."))}import{existsSync as D_,readFileSync as $_}from"node:fs";import{join as j_}from"node:path";T();Wt();var T_=/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/gi,w_=[/\bv\d+\.\d+(?:\.[A-Za-z]+)?\b/g,/\bPhase\s+[A-Ha-h]\b/g,/\bL\d+\b/g,/MASTER-PLAN-[A-Za-z-]+/g],R_=.95,x_=.85,k_=.7,ir=50,C_=50;function N_(e){if(!e)return[];let t=new Set,s=[],n=e.match(T_);if(!n)return s;for(let r of n){let o=r.toLowerCase();if(!t.has(o)&&(t.add(o),s.push(o),s.length>=ir))break}return s}function L_(e){if(!e)return[];let t=new Set,s=[];for(let n of w_){n.lastIndex=0;let r=e.match(n);if(r){for(let o of r){let i=o.trim().toLowerCase().replace(/\s+/g," ");if(!(!i||i.length>64)&&!t.has(i)&&(t.add(i),s.push(i),s.length>=ir))break}if(s.length>=ir)break}}return s}function ar(e){let t=_();return typeof e=="number"?t.prepare("SELECT id, project_id FROM sessions WHERE project_id = ?").all(e):t.prepare("SELECT id, project_id FROM sessions").all()}function Da(e){let t=_();return typeof e=="number"?t.prepare(`SELECT m.uuid AS message_uuid, m.session_id, m.content_text,
1185
+ ORDER BY COALESCE(s.started_at, ''), s.id`).all(e)}function J_(e,t){let s=new Map,n=new Map,r=new Map;for(let o of e){r.set(o.id,o.started_at);let i=t.get(o.id);if(!i)continue;let a=U_(i);if(a.size!==0){n.set(o.id,a);for(let l of a){let c=s.get(l);c?c.push(o.id):s.set(l,[o.id])}}}return{posting:s,vocab:n,startedAt:r}}function G_(e,t){let s=t.vocab.get(e),n=t.startedAt.get(e)??null;if(!s||!n)return[];let r=new Map;for(let i of s){let a=t.posting.get(i);if(a)for(let l of a){if(l===e)continue;let c=t.startedAt.get(l);if(!c||c>=n)continue;let u=r.get(l);u?u.push(i):r.set(l,[i])}}let o=[];for(let[i,a]of r){let l=a.length;if(l<D_)continue;let c=t.startedAt.get(i)??null,u=H_(n,c),m=B_(u),p=Math.min(1,l/j_*m);if(p<$_)continue;let f=a.slice(0,12);o.push({target_session_id:i,matched_terms:f,overlap:l,days_apart:Math.round(u*10)/10,recency:Math.round(m*1e3)/1e3,confidence:Math.round(p*1e3)/1e3})}return o.sort((i,a)=>a.confidence-i.confidence),o.slice(0,F_)}async function Ga(e){if(Ms.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project \u2014 refusing to run inference");let t=X_(e.projectId),s=new Map;for(let i of t){let a=W_(i.id);a&&s.set(i.id,a)}let n=J_(t,s),r={total_sessions:t.length,processed_sessions:0,suggestions_created:0,suggestions_skipped_existing:0,current_session_id:null};e.onProgress?.({...r});let o=[];for(let i of t){if(e.signal?.aborted)break;r.current_session_id=i.id,e.onProgress?.({...r});let a=G_(i.id,n);for(let l of a)try{let c=Qe({source_session_id:i.id,target_session_id:l.target_session_id,link_type:"citation",confidence:l.confidence,evidence:{matched_terms:l.matched_terms,overlap_count:l.overlap,recency:l.recency,days_apart:l.days_apart},inferred_by:"L2"});o.push(c.id),r.suggestions_created+=1}catch(c){console.error("[citation-inference] createSuggestion failed:",c)}r.processed_sessions+=1,e.onProgress?.({...r})}return r.current_session_id=null,e.onProgress?.({...r}),{progress:r,suggestion_ids:o}}async function za(e){if(!e.project){console.error("--project <name> is required."),process.exitCode=1;return}let t=_e(e.project);if(!t){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}e.json||console.log(`Inferring citation suggestions \u2014 project "${t.name}"\u2026`);let s=Date.now(),n=-1,r=await Ga({projectId:t.id,onProgress:i=>{if(e.json||i.processed_sessions===n)return;n=i.processed_sessions;let a=i.total_sessions>0?` (${Math.round(i.processed_sessions/i.total_sessions*100)}%)`:"";process.stdout.write(`\r ${i.processed_sessions}/${i.total_sessions} sessions${a} suggestions=${i.suggestions_created} `)}});e.json||process.stdout.write(`
1186
+ `);let o=Number(((Date.now()-s)/1e3).toFixed(1));e.json?console.log(JSON.stringify({project:t.name,progress:r.progress,suggestion_count:r.suggestion_ids.length,sample_suggestion_ids:r.suggestion_ids.slice(0,25),elapsed_seconds:o},null,2)):(console.log(`Done in ${o}s \u2014 sessions=${r.progress.processed_sessions}/${r.progress.total_sessions} suggestions=${r.progress.suggestions_created}`),r.progress.total_sessions===0?console.log(` \u24D8 No sessions had a populated Output Index. Run \`recall extract-outputs --project ${t.name}\` first.`):r.progress.suggestions_created===0?console.log(" \u24D8 No suggestions met the confidence threshold. This is expected on small corpora; the Output Index needs more shared vocabulary across sessions for citations to surface."):console.log(" Review the queue at GET /api/links/suggestions?status=pending (Phase F UI ships the queue review)."))}import{existsSync as ih,readFileSync as ah}from"node:fs";import{join as ch}from"node:path";T();zt();var z_=/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/gi,Y_=[/\bv\d+\.\d+(?:\.[A-Za-z]+)?\b/g,/\bPhase\s+[A-Ha-h]\b/g,/\bL\d+\b/g,/MASTER-PLAN-[A-Za-z-]+/g],K_=.95,q_=.85,V_=.7,gr=50,Z_=50;function Q_(e){if(!e)return[];let t=new Set,s=[],n=e.match(z_);if(!n)return s;for(let r of n){let o=r.toLowerCase();if(!t.has(o)&&(t.add(o),s.push(o),s.length>=gr))break}return s}function eh(e){if(!e)return[];let t=new Set,s=[];for(let n of Y_){n.lastIndex=0;let r=e.match(n);if(r){for(let o of r){let i=o.trim().toLowerCase().replace(/\s+/g," ");if(!(!i||i.length>64)&&!t.has(i)&&(t.add(i),s.push(i),s.length>=gr))break}if(s.length>=gr)break}}return s}function fr(e){let t=_();return typeof e=="number"?t.prepare("SELECT id, project_id FROM sessions WHERE project_id = ?").all(e):t.prepare("SELECT id, project_id FROM sessions").all()}function Ya(e){let t=_();return typeof e=="number"?t.prepare(`SELECT m.uuid AS message_uuid, m.session_id, m.content_text,
1187
1187
  s.project_id
1188
1188
  FROM messages m
1189
1189
  JOIN sessions s ON s.id = m.session_id
@@ -1196,12 +1196,12 @@ show full content: recall paste --show <id>
1196
1196
  JOIN sessions s ON s.id = m.session_id
1197
1197
  WHERE m.is_sidechain = 0
1198
1198
  AND m.content_text IS NOT NULL
1199
- AND length(m.content_text) > 0`).all()}function O_(e){let t=_(),s=typeof e=="number"?"WHERE s.project_id = ?":"",n=typeof e=="number"?[e]:[];return t.prepare(`SELECT oi.session_id AS session_id,
1199
+ AND length(m.content_text) > 0`).all()}function th(e){let t=_(),s=typeof e=="number"?"WHERE s.project_id = ?":"",n=typeof e=="number"?[e]:[];return t.prepare(`SELECT oi.session_id AS session_id,
1200
1200
  s.project_id AS project_id,
1201
1201
  oi.plan_ids_referenced AS plan_ids_json
1202
1202
  FROM session_output_index oi
1203
1203
  JOIN sessions s ON s.id = oi.session_id
1204
- ${s}`).all(...n)}function A_(e){if(!e)return[];try{let t=JSON.parse(e);if(Array.isArray(t))return t.filter(s=>typeof s=="string")}catch{}return[]}function I_(e={}){if(Ls.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project");let t=ar(e.projectId),s=new Set(t.map(o=>o.id)),n=new Map;for(let o of t)n.set(o.id,o.project_id);let r=0;for(let o of Da(e.projectId)){if(e.signal?.aborted)break;let i=N_(o.content_text);if(i.length===0)continue;let a=n.get(o.session_id);if(a!==void 0)for(let l of i){if(l===o.session_id)continue;let c=n.get(l);if(!(c===void 0&&!s.has(l))&&!(c!==void 0&&a!==void 0&&c!==a))try{Ze({source_session_id:o.session_id,target_session_id:l,link_type:"citation",confidence:R_,evidence:{matched_uuid:l,source_message_uuid:o.message_uuid,scanner:"uuid-ref"},inferred_by:"L1"}),r+=1}catch{}}}return{created:r}}function v_(e={}){let t=O_(e.projectId);if(t.length===0)return{created:0};let s=new Map;for(let a of t){let l=A_(a.plan_ids_json);for(let c of l){let u=c.trim().toLowerCase();if(!u)continue;let p=s.get(u);p?p.push({id:a.session_id,project_id:a.project_id}):s.set(u,[{id:a.session_id,project_id:a.project_id}])}}if(s.size===0)return{created:0};let n=ar(e.projectId),r=new Map;for(let a of n)r.set(a.id,a.project_id);let o=0,i=new Map;for(let a of Da(e.projectId)){if(e.signal?.aborted)break;let l=L_(a.content_text);if(l.length===0)continue;let c=r.get(a.session_id);if(c!==void 0)for(let u of l){let p=s.get(u);if(p)for(let m of p){if(m.id===a.session_id||m.project_id!==c)continue;let f=i.get(a.session_id);f||(f=new Map,i.set(a.session_id,f));let g=f.get(m.id);g||(g=new Set,f.set(m.id,g)),g.add(u)}}}for(let[a,l]of i)for(let[c,u]of l)try{Ze({source_session_id:a,target_session_id:c,link_type:"citation",confidence:x_,evidence:{matched_plan_ids:Array.from(u).slice(0,12),scanner:"plan-ref"},inferred_by:"L1"}),o+=1}catch{}return{created:o}}function M_(e){if(Ls.skill_track!=="same-project")throw new Error("skill_track policy unexpectedly not same-project");if(!e.registry||!Array.isArray(e.registry.terminals))return{created:0};let t=ar(e.projectId),s=new Map,n=new Map;if(t.length>0){let i=_(),a=t.map(u=>u.id),l=a.map(()=>"?").join(","),c=i.prepare(`SELECT id, started_at FROM sessions WHERE id IN (${l})`).all(...a);for(let u of c)n.set(u.id,u.started_at)}for(let i of t)s.set(i.id,i.project_id);let r=new Map;for(let i of e.registry.terminals){let a=e.registry.sessions_by_pid[String(i.shell_pid)]??[];if(a.length===0)continue;let l=`${i.cwd??"<no-cwd>"}::${i.tab_name}`,c=r.get(l);c||(c=new Set,r.set(l,c));for(let u of a)c.add(u)}let o=0;for(let[,i]of r){if(i.size<2)continue;let a=new Map;for(let l of i){let c=s.get(l);if(c===void 0||typeof e.projectId=="number"&&c!==e.projectId)continue;let u=a.get(c);u||(u=[],a.set(c,u)),u.push(l)}for(let[,l]of a){if(l.length<2)continue;l.sort((u,p)=>{let m=n.get(u)??"",f=n.get(p)??"";return m<f?-1:m>f?1:u<p?-1:1});let c=0;for(let u=1;u<l.length&&!e.signal?.aborted;u++)for(let p=0;p<u&&!(c>=C_);p++)try{Ze({source_session_id:l[u],target_session_id:l[p],link_type:"skill_track",confidence:k_,evidence:{shared_tab_signature:!0,bucket_size:l.length,scanner:"tab-carry"},inferred_by:"L1"}),o+=1,c+=1}catch{}}}return{created:o}}function $a(e={}){let t=I_(e);if(e.signal?.aborted)return{uuid_refs_created:t.created,plan_refs_created:0,tab_carry_created:0,total:t.created};let s=v_(e);if(e.signal?.aborted)return{uuid_refs_created:t.created,plan_refs_created:s.created,tab_carry_created:0,total:t.created+s.created};let n=e.registry?M_({projectId:e.projectId,signal:e.signal,registry:e.registry}):{created:0};return{uuid_refs_created:t.created,plan_refs_created:s.created,tab_carry_created:n.created,total:t.created+s.created+n.created}}j();function P_(){let e=j_(R,"terminals.json");if(D_(e))try{let t=$_(e,"utf8"),s=JSON.parse(t);if(!Array.isArray(s.terminals))return;let n=s.terminals.filter(o=>typeof o.shell_pid=="number"&&typeof o.tab_name=="string").map(o=>({shell_pid:o.shell_pid,tab_name:o.tab_name,cwd:o.cwd??null})),r=s.sessions_by_pid??{};return{terminals:n,sessions_by_pid:r}}catch{return}}async function ja(e){let t=null;if(e.project&&(t=ge(e.project),!t)){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let s=P_(),n=t?`project "${t.name}"`:"all projects";e.json||console.log(`L1 deterministic inference \u2014 ${n} \u2014 `+(s?`(tab registry has ${s.terminals.length} entries)`:"(no tab registry; tab-carry scanner skipped)"));let r=Date.now(),o=$a({projectId:t?.id,registry:s}),i=Number(((Date.now()-r)/1e3).toFixed(2));e.json?console.log(JSON.stringify({project:t?.name??null,...o,elapsed_seconds:i},null,2)):(console.log(`Done in ${i}s \u2014 uuid_refs=${o.uuid_refs_created} plan_refs=${o.plan_refs_created} tab_carry=${o.tab_carry_created} (total=${o.total})`),o.total===0?console.log(" \u24D8 Zero new suggestions. This is expected when L1 has already run against this corpus or when the project has no inter-session references. (Tombstones from prior reject decisions also keep re-runs idempotent.)"):console.log(" Review the queue at GET /api/links/suggestions?status=pending (or the web UI at #view=suggestions)."))}T();Xe();Wt();function cr(e){if(!e||e.length===0)return 0;let t=1,s=0;for(let n of e){if(!Number.isFinite(n))continue;let r=Math.max(0,Math.min(1,n));if(t*=1-r,s+=1,t<=1e-9)return 1}return s===0?0:Math.round((1-t)*1e4)/1e4}var dr="claude-haiku-4-5-20251001",Os=.4,ur=.95,Pa=30,Fa=240,F_=new Set(["CITATION","SIMILAR","SKILL_TRACK","UNRELATED"]),U_={CITATION:"citation",SIMILAR:"similar",SKILL_TRACK:"skill_track"};function Ha(e){return _().prepare(`SELECT s.id,
1204
+ ${s}`).all(...n)}function sh(e){if(!e)return[];try{let t=JSON.parse(e);if(Array.isArray(t))return t.filter(s=>typeof s=="string")}catch{}return[]}function nh(e={}){if(Ms.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project");let t=fr(e.projectId),s=new Set(t.map(o=>o.id)),n=new Map;for(let o of t)n.set(o.id,o.project_id);let r=0;for(let o of Ya(e.projectId)){if(e.signal?.aborted)break;let i=Q_(o.content_text);if(i.length===0)continue;let a=n.get(o.session_id);if(a!==void 0)for(let l of i){if(l===o.session_id)continue;let c=n.get(l);if(!(c===void 0&&!s.has(l))&&!(c!==void 0&&a!==void 0&&c!==a))try{Qe({source_session_id:o.session_id,target_session_id:l,link_type:"citation",confidence:K_,evidence:{matched_uuid:l,source_message_uuid:o.message_uuid,scanner:"uuid-ref"},inferred_by:"L1"}),r+=1}catch{}}}return{created:r}}function rh(e={}){let t=th(e.projectId);if(t.length===0)return{created:0};let s=new Map;for(let a of t){let l=sh(a.plan_ids_json);for(let c of l){let u=c.trim().toLowerCase();if(!u)continue;let m=s.get(u);m?m.push({id:a.session_id,project_id:a.project_id}):s.set(u,[{id:a.session_id,project_id:a.project_id}])}}if(s.size===0)return{created:0};let n=fr(e.projectId),r=new Map;for(let a of n)r.set(a.id,a.project_id);let o=0,i=new Map;for(let a of Ya(e.projectId)){if(e.signal?.aborted)break;let l=eh(a.content_text);if(l.length===0)continue;let c=r.get(a.session_id);if(c!==void 0)for(let u of l){let m=s.get(u);if(m)for(let p of m){if(p.id===a.session_id||p.project_id!==c)continue;let f=i.get(a.session_id);f||(f=new Map,i.set(a.session_id,f));let g=f.get(p.id);g||(g=new Set,f.set(p.id,g)),g.add(u)}}}for(let[a,l]of i)for(let[c,u]of l)try{Qe({source_session_id:a,target_session_id:c,link_type:"citation",confidence:q_,evidence:{matched_plan_ids:Array.from(u).slice(0,12),scanner:"plan-ref"},inferred_by:"L1"}),o+=1}catch{}return{created:o}}function oh(e){if(Ms.skill_track!=="same-project")throw new Error("skill_track policy unexpectedly not same-project");if(!e.registry||!Array.isArray(e.registry.terminals))return{created:0};let t=fr(e.projectId),s=new Map,n=new Map;if(t.length>0){let i=_(),a=t.map(u=>u.id),l=a.map(()=>"?").join(","),c=i.prepare(`SELECT id, started_at FROM sessions WHERE id IN (${l})`).all(...a);for(let u of c)n.set(u.id,u.started_at)}for(let i of t)s.set(i.id,i.project_id);let r=new Map;for(let i of e.registry.terminals){let a=e.registry.sessions_by_pid[String(i.shell_pid)]??[];if(a.length===0)continue;let l=`${i.cwd??"<no-cwd>"}::${i.tab_name}`,c=r.get(l);c||(c=new Set,r.set(l,c));for(let u of a)c.add(u)}let o=0;for(let[,i]of r){if(i.size<2)continue;let a=new Map;for(let l of i){let c=s.get(l);if(c===void 0||typeof e.projectId=="number"&&c!==e.projectId)continue;let u=a.get(c);u||(u=[],a.set(c,u)),u.push(l)}for(let[,l]of a){if(l.length<2)continue;l.sort((u,m)=>{let p=n.get(u)??"",f=n.get(m)??"";return p<f?-1:p>f?1:u<m?-1:1});let c=0;for(let u=1;u<l.length&&!e.signal?.aborted;u++)for(let m=0;m<u&&!(c>=Z_);m++)try{Qe({source_session_id:l[u],target_session_id:l[m],link_type:"skill_track",confidence:V_,evidence:{shared_tab_signature:!0,bucket_size:l.length,scanner:"tab-carry"},inferred_by:"L1"}),o+=1,c+=1}catch{}}}return{created:o}}function Ka(e={}){let t=nh(e);if(e.signal?.aborted)return{uuid_refs_created:t.created,plan_refs_created:0,tab_carry_created:0,total:t.created};let s=rh(e);if(e.signal?.aborted)return{uuid_refs_created:t.created,plan_refs_created:s.created,tab_carry_created:0,total:t.created+s.created};let n=e.registry?oh({projectId:e.projectId,signal:e.signal,registry:e.registry}):{created:0};return{uuid_refs_created:t.created,plan_refs_created:s.created,tab_carry_created:n.created,total:t.created+s.created+n.created}}j();function lh(){let e=ch(R,"terminals.json");if(ih(e))try{let t=ah(e,"utf8"),s=JSON.parse(t);if(!Array.isArray(s.terminals))return;let n=s.terminals.filter(o=>typeof o.shell_pid=="number"&&typeof o.tab_name=="string").map(o=>({shell_pid:o.shell_pid,tab_name:o.tab_name,cwd:o.cwd??null})),r=s.sessions_by_pid??{};return{terminals:n,sessions_by_pid:r}}catch{return}}async function qa(e){let t=null;if(e.project&&(t=_e(e.project),!t)){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let s=lh(),n=t?`project "${t.name}"`:"all projects";e.json||console.log(`L1 deterministic inference \u2014 ${n} \u2014 `+(s?`(tab registry has ${s.terminals.length} entries)`:"(no tab registry; tab-carry scanner skipped)"));let r=Date.now(),o=Ka({projectId:t?.id,registry:s}),i=Number(((Date.now()-r)/1e3).toFixed(2));e.json?console.log(JSON.stringify({project:t?.name??null,...o,elapsed_seconds:i},null,2)):(console.log(`Done in ${i}s \u2014 uuid_refs=${o.uuid_refs_created} plan_refs=${o.plan_refs_created} tab_carry=${o.tab_carry_created} (total=${o.total})`),o.total===0?console.log(" \u24D8 Zero new suggestions. This is expected when L1 has already run against this corpus or when the project has no inter-session references. (Tombstones from prior reject decisions also keep re-runs idempotent.)"):console.log(" Review the queue at GET /api/links/suggestions?status=pending (or the web UI at #view=suggestions)."))}T();Je();zt();function _r(e){if(!e||e.length===0)return 0;let t=1,s=0;for(let n of e){if(!Number.isFinite(n))continue;let r=Math.max(0,Math.min(1,n));if(t*=1-r,s+=1,t<=1e-9)return 1}return s===0?0:Math.round((1-t)*1e4)/1e4}var Er="claude-haiku-4-5-20251001",Ds=.4,br=.95,Va=30,Za=240,dh=new Set(["CITATION","SIMILAR","SKILL_TRACK","UNRELATED"]),uh={CITATION:"citation",SIMILAR:"similar",SKILL_TRACK:"skill_track"};function tc(e){return _().prepare(`SELECT s.id,
1205
1205
  s.source_session_id,
1206
1206
  s.target_session_id,
1207
1207
  s.link_type,
@@ -1211,7 +1211,7 @@ show full content: recall paste --show <id>
1211
1211
  FROM session_link_suggestions s
1212
1212
  JOIN sessions src ON src.id = s.source_session_id
1213
1213
  WHERE s.status = 'pending'
1214
- AND src.project_id = ?`).all(e)}function B_(e){if(e.length===0)return new Map;let t=_(),s=e.map(()=>"?").join(","),n=t.prepare(`SELECT s.id,
1214
+ AND src.project_id = ?`).all(e)}function mh(e){if(e.length===0)return new Map;let t=_(),s=e.map(()=>"?").join(","),n=t.prepare(`SELECT s.id,
1215
1215
  NULLIF(sa.alias, '') AS alias,
1216
1216
  s.auto_title,
1217
1217
  s.first_user_message,
@@ -1220,18 +1220,18 @@ show full content: recall paste --show <id>
1220
1220
  FROM sessions s
1221
1221
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1222
1222
  LEFT JOIN projects p ON p.id = s.project_id
1223
- WHERE s.id IN (${s})`).all(...e),r=new Map;for(let o of n)r.set(o.id,o);return r}function Ua(e,t){if(!e)return t.slice(0,8);let s=e.first_user_message?e.first_user_message.slice(0,80):null;return e.alias??e.auto_title??s??t.slice(0,8)}function Ba(e){try{return JSON.parse(e)}catch{return e}}function H_(e){let t=e.minConfidence??Os,s=Math.max(1,Math.min(500,e.limit??100)),n=Ha(e.projectId);if(n.length===0)return[];let r=new Map,o=new Map;for(let c of n){let u=`${c.source_session_id}|${c.target_session_id}|${c.link_type}`,p=o.get(u);p||(p={source_session_id:c.source_session_id,target_session_id:c.target_session_id,link_type:c.link_type,layers:[]},o.set(u,p));let m=p.layers.find(f=>f.inferred_by===c.inferred_by);m?(m.suggestion_ids.push(c.id),c.confidence>m.confidence&&(m.confidence=c.confidence,m.evidence=Ba(c.evidence))):p.layers.push({inferred_by:c.inferred_by,link_type:c.link_type,confidence:c.confidence,evidence:Ba(c.evidence),suggestion_ids:[c.id]})}let i=new Set;for(let c of o.values())i.add(c.source_session_id),i.add(c.target_session_id);let a=B_(Array.from(i)),l=[];for(let c of o.values()){let u=cr(c.layers.map(f=>f.confidence));if(u<t)continue;let p=a.get(c.source_session_id),m=a.get(c.target_session_id);l.push({source_session_id:c.source_session_id,target_session_id:c.target_session_id,primary_link_type:c.link_type,combined_confidence:u,layers:c.layers,source_title:Ua(p,c.source_session_id),target_title:Ua(m,c.target_session_id),source_project:p?.project??null})}return l.sort((c,u)=>u.combined_confidence-c.combined_confidence),l.slice(0,s)}function W_(e){let t;try{t=JSON.stringify(e)}catch{t=String(e)}return t.length>Fa&&(t=t.slice(0,Fa)+"\u2026"),t}function X_(e){let t=["You are classifying candidate session-pair relationships for a developer knowledge graph.","","Categories:","- CITATION: the source session explicitly references content/decisions from the target (a previous session).","- SIMILAR: same subject matter, but neither cites the other directly.","- SKILL_TRACK: same person doing the same kind of work \u2014 same skill, different tasks.","- UNRELATED: shared evidence is coincidental; no real relationship.","","Use UNRELATED with low confidence when evidence is weak or contradictory.","Output a SINGLE JSON object on one line, no markdown fences, no commentary:",'{"classifications":[{"i":0,"label":"CITATION","conf":0.85,"why":"<<=25 words>"},...]}',"",`Pairs (${e.length}):`];return e.forEach((s,n)=>{t.push(""),t.push(`[${n}] B="${(s.source_title??"").slice(0,80)}" [${s.source_session_id.slice(0,8)}] -> A="${(s.target_title??"").slice(0,80)}" [${s.target_session_id.slice(0,8)}]`),t.push(` primary_type: ${s.primary_link_type}`),t.push(` combined_conf: ${s.combined_confidence.toFixed(3)}`);for(let r of s.layers)t.push(` ${r.inferred_by} ${r.link_type} conf=${r.confidence.toFixed(2)} ev=${W_(r.evidence)}`)}),t.join(`
1224
- `)}var lr=null;async function J_(e,t){return lr?lr(e,t):pt(e,[],{model:t})}function G_(e){try{let t=JSON.parse(e.trim());return{input_tokens:t?.usage?.input_tokens??0,output_tokens:t?.usage?.output_tokens??0}}catch{return{input_tokens:0,output_tokens:0}}}function z_(e){let t=e.trim();try{let i=JSON.parse(t);typeof i.result=="string"&&(t=i.result.trim())}catch{}t=t.replace(/^```(?:json)?\s*/i,"").replace(/```\s*$/i,"").trim();let s=t.indexOf("{"),n=t.lastIndexOf("}");if(s===-1||n===-1||n<=s)return null;let r;try{r=JSON.parse(t.slice(s,n+1))}catch{return null}if(!Array.isArray(r.classifications))return null;let o=[];for(let i of r.classifications){if(!i||typeof i!="object")continue;let a=i,l=typeof a.i=="number"?a.i:typeof a.pair_index=="number"?a.pair_index:NaN;if(!Number.isInteger(l)||l<0)continue;let c=typeof a.label=="string"?a.label.toUpperCase():"";if(!F_.has(c))continue;let u=typeof a.conf=="number"?a.conf:typeof a.confidence=="number"?a.confidence:NaN;if(!Number.isFinite(u))continue;let p=Math.max(0,Math.min(1,u)),m=typeof a.why=="string"?a.why.trim().slice(0,200):typeof a.reason=="string"?a.reason.trim().slice(0,200):"";o.push({pair_index:l,label:c,confidence:p,reason:m})}return o}async function Wa(e){let t={candidates_total:0,candidates_after_filter:0,classified:0,suggestions_created:0,links_promoted:0,total_input_tokens:0,total_output_tokens:0,failures:[]};if(!lr&&!ce())return t.failures.push({batch_index:-1,error:"claude CLI not available on PATH"}),t;let s=H_({projectId:e.projectId,minConfidence:e.minConfidence??Os,limit:e.limit??100});t.candidates_after_filter=s.length;let n=Ha(e.projectId),r=new Set;for(let a of n)r.add(`${a.source_session_id}|${a.target_session_id}|${a.link_type}`);if(t.candidates_total=r.size,s.length===0)return t;let o=e.model??dr,i=e.autoPromoteThreshold??ur;for(let a=0,l=0;a<s.length&&!e.signal?.aborted;a+=Pa,l+=1){let c=s.slice(a,a+Pa);e.onBatchStart?.({batch:l,pairs:c.length});let u=X_(c),p=await J_(u,o);if(!p.success){t.failures.push({batch_index:l,error:`claude CLI exited ${p.exitCode}: ${p.stderr.slice(0,200)}`});continue}let m=z_(p.stdout);if(!m){t.failures.push({batch_index:l,error:"parse-failed"});continue}let f=G_(p.stdout);t.total_input_tokens+=f.input_tokens,t.total_output_tokens+=f.output_tokens;for(let g of m){if(g.pair_index>=c.length)continue;let h=c[g.pair_index];if(t.classified+=1,g.label==="UNRELATED")continue;let E=U_[g.label];if(E)try{let b=Ze({source_session_id:h.source_session_id,target_session_id:h.target_session_id,link_type:E,confidence:g.confidence,evidence:{l4_label:g.label,l4_reason:g.reason,primary_type_l1_l2_l3:h.primary_link_type,combined_pre_l4:h.combined_confidence,scanner:"l4-llm",model:o},inferred_by:"L4"});if(t.suggestions_created+=1,e.autoPromote){let S=h.layers.map(x=>x.confidence);if(S.push(g.confidence),cr(S)>=i)try{Aa(b.id,"approved",{source:"auto"}),t.links_promoted+=1}catch{}}}catch{}}}return t}Xe();var Y_=1e3;function K_(e){let t=e.minConf?Math.max(0,Math.min(1,Number(e.minConf))):Os,s=e.autoPromoteThreshold!==void 0?Math.max(0,Math.min(1,Number(e.autoPromoteThreshold))):ur,n=e.limit?Math.max(1,Number(e.limit)):Y_,r=e.model??dr,o=!!e.autoPromote||e.autoPromoteThreshold!==void 0;return{minConfidence:t,autoPromoteThreshold:s,limit:n,model:r,autoPromote:o}}async function Xa(e){if(!e.project){console.error("--project <name> is required."),process.exitCode=1;return}let t=ge(e.project);if(!t){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}if(!ce()){console.error("claude CLI not found on PATH. Install Claude Code first, then re-run."),process.exitCode=1;return}let{minConfidence:s,autoPromoteThreshold:n,limit:r,model:o,autoPromote:i}=K_(e);e.json||console.log(`L4 inference \u2014 project "${t.name}" \u2014 model ${o} \u2014 pre-filter conf \u2265 ${s} \u2014 limit ${r} \u2014 auto-promote ${i?`ON (\u2265 ${n})`:"OFF"}`);let a=Date.now(),l=await Wa({projectId:t.id,minConfidence:s,limit:r,autoPromote:i,autoPromoteThreshold:n,model:o,onBatchStart:u=>{e.json||process.stdout.write(`\r batch ${u.batch} (${u.pairs} pairs)\u2026 `)}});e.json||process.stdout.write(`
1225
- `);let c=Number(((Date.now()-a)/1e3).toFixed(1));if(e.json)console.log(JSON.stringify({project:t.name,model:o,pre_filter_threshold:s,auto_promote:i,auto_promote_threshold:i?n:null,...l,elapsed_seconds:c},null,2));else{if(console.log(`Done in ${c}s \u2014 pairs=${l.candidates_after_filter}/${l.candidates_total} classified=${l.classified} suggestions=${l.suggestions_created} promoted=${l.links_promoted} failures=${l.failures.length}`),console.log(`Token spend: input=${l.total_input_tokens} output=${l.total_output_tokens}`),l.failures.length>0)for(let u of l.failures.slice(0,3))console.log(` \u26A0 batch ${u.batch_index}: ${u.error}`);l.suggestions_created>0?console.log(" Review the new L4 suggestions at #view=suggestions (filter by inferred_by=L4)."):l.candidates_after_filter===0&&console.log(` \u24D8 No pairs cleared the pre-filter (combined conf \u2265 ${s}). Lower --min-conf to widen the batch, or run more L1/L2/L3 inference first.`)}}T();import{createHash as nh}from"node:crypto";T();j();import{writeFileSync as q_,readFileSync as yC,existsSync as V_,mkdirSync as Z_,readdirSync as TC,unlinkSync as wC}from"node:fs";import{join as Ja}from"node:path";import{randomUUID as Q_}from"node:crypto";var pr=Ja(R,"bug-patterns");function eh(){P(),V_(pr)||Z_(pr,{recursive:!0})}function As(e){return{id:e.id,signature_hash:e.signature_hash,example_message:e.example_message,occurrence_count:e.occurrence_count,first_seen_at:e.first_seen_at,last_seen_at:e.last_seen_at,resolved_in_session_id:e.resolved_in_session_id,fix_summary:e.fix_summary}}function th(e){return{cluster_id:e.cluster_id,session_id:e.session_id,matched_at:e.matched_at}}function Ga(e){if(!e.signature_hash)throw new Error("signature_hash is required");if(!e.example_message)throw new Error("example_message is required");if(!Array.isArray(e.member_session_ids)||e.member_session_ids.length===0)throw new Error("at least one member_session_id is required");let t=_(),s=new Date().toISOString(),n=e.id??Q_(),r=e.first_seen_at??s,o=e.last_seen_at??s,i=Array.from(new Set(e.member_session_ids));t.transaction(()=>{t.prepare(`INSERT INTO bug_pattern_clusters
1223
+ WHERE s.id IN (${s})`).all(...e),r=new Map;for(let o of n)r.set(o.id,o);return r}function Qa(e,t){if(!e)return t.slice(0,8);let s=e.first_user_message?e.first_user_message.slice(0,80):null;return e.alias??e.auto_title??s??t.slice(0,8)}function ec(e){try{return JSON.parse(e)}catch{return e}}function ph(e){let t=e.minConfidence??Ds,s=Math.max(1,Math.min(500,e.limit??100)),n=tc(e.projectId);if(n.length===0)return[];let r=new Map,o=new Map;for(let c of n){let u=`${c.source_session_id}|${c.target_session_id}|${c.link_type}`,m=o.get(u);m||(m={source_session_id:c.source_session_id,target_session_id:c.target_session_id,link_type:c.link_type,layers:[]},o.set(u,m));let p=m.layers.find(f=>f.inferred_by===c.inferred_by);p?(p.suggestion_ids.push(c.id),c.confidence>p.confidence&&(p.confidence=c.confidence,p.evidence=ec(c.evidence))):m.layers.push({inferred_by:c.inferred_by,link_type:c.link_type,confidence:c.confidence,evidence:ec(c.evidence),suggestion_ids:[c.id]})}let i=new Set;for(let c of o.values())i.add(c.source_session_id),i.add(c.target_session_id);let a=mh(Array.from(i)),l=[];for(let c of o.values()){let u=_r(c.layers.map(f=>f.confidence));if(u<t)continue;let m=a.get(c.source_session_id),p=a.get(c.target_session_id);l.push({source_session_id:c.source_session_id,target_session_id:c.target_session_id,primary_link_type:c.link_type,combined_confidence:u,layers:c.layers,source_title:Qa(m,c.source_session_id),target_title:Qa(p,c.target_session_id),source_project:m?.project??null})}return l.sort((c,u)=>u.combined_confidence-c.combined_confidence),l.slice(0,s)}function gh(e){let t;try{t=JSON.stringify(e)}catch{t=String(e)}return t.length>Za&&(t=t.slice(0,Za)+"\u2026"),t}function fh(e){let t=["You are classifying candidate session-pair relationships for a developer knowledge graph.","","Categories:","- CITATION: the source session explicitly references content/decisions from the target (a previous session).","- SIMILAR: same subject matter, but neither cites the other directly.","- SKILL_TRACK: same person doing the same kind of work \u2014 same skill, different tasks.","- UNRELATED: shared evidence is coincidental; no real relationship.","","Use UNRELATED with low confidence when evidence is weak or contradictory.","Output a SINGLE JSON object on one line, no markdown fences, no commentary:",'{"classifications":[{"i":0,"label":"CITATION","conf":0.85,"why":"<<=25 words>"},...]}',"",`Pairs (${e.length}):`];return e.forEach((s,n)=>{t.push(""),t.push(`[${n}] B="${(s.source_title??"").slice(0,80)}" [${s.source_session_id.slice(0,8)}] -> A="${(s.target_title??"").slice(0,80)}" [${s.target_session_id.slice(0,8)}]`),t.push(` primary_type: ${s.primary_link_type}`),t.push(` combined_conf: ${s.combined_confidence.toFixed(3)}`);for(let r of s.layers)t.push(` ${r.inferred_by} ${r.link_type} conf=${r.confidence.toFixed(2)} ev=${gh(r.evidence)}`)}),t.join(`
1224
+ `)}var hr=null;async function _h(e,t){return hr?hr(e,t):pt(e,[],{model:t})}function hh(e){try{let t=JSON.parse(e.trim());return{input_tokens:t?.usage?.input_tokens??0,output_tokens:t?.usage?.output_tokens??0}}catch{return{input_tokens:0,output_tokens:0}}}function Eh(e){let t=e.trim();try{let i=JSON.parse(t);typeof i.result=="string"&&(t=i.result.trim())}catch{}t=t.replace(/^```(?:json)?\s*/i,"").replace(/```\s*$/i,"").trim();let s=t.indexOf("{"),n=t.lastIndexOf("}");if(s===-1||n===-1||n<=s)return null;let r;try{r=JSON.parse(t.slice(s,n+1))}catch{return null}if(!Array.isArray(r.classifications))return null;let o=[];for(let i of r.classifications){if(!i||typeof i!="object")continue;let a=i,l=typeof a.i=="number"?a.i:typeof a.pair_index=="number"?a.pair_index:NaN;if(!Number.isInteger(l)||l<0)continue;let c=typeof a.label=="string"?a.label.toUpperCase():"";if(!dh.has(c))continue;let u=typeof a.conf=="number"?a.conf:typeof a.confidence=="number"?a.confidence:NaN;if(!Number.isFinite(u))continue;let m=Math.max(0,Math.min(1,u)),p=typeof a.why=="string"?a.why.trim().slice(0,200):typeof a.reason=="string"?a.reason.trim().slice(0,200):"";o.push({pair_index:l,label:c,confidence:m,reason:p})}return o}async function sc(e){let t={candidates_total:0,candidates_after_filter:0,classified:0,suggestions_created:0,links_promoted:0,total_input_tokens:0,total_output_tokens:0,failures:[]};if(!hr&&!ce())return t.failures.push({batch_index:-1,error:"claude CLI not available on PATH"}),t;let s=ph({projectId:e.projectId,minConfidence:e.minConfidence??Ds,limit:e.limit??100});t.candidates_after_filter=s.length;let n=tc(e.projectId),r=new Set;for(let a of n)r.add(`${a.source_session_id}|${a.target_session_id}|${a.link_type}`);if(t.candidates_total=r.size,s.length===0)return t;let o=e.model??Er,i=e.autoPromoteThreshold??br;for(let a=0,l=0;a<s.length&&!e.signal?.aborted;a+=Va,l+=1){let c=s.slice(a,a+Va);e.onBatchStart?.({batch:l,pairs:c.length});let u=fh(c),m=await _h(u,o);if(!m.success){t.failures.push({batch_index:l,error:`claude CLI exited ${m.exitCode}: ${m.stderr.slice(0,200)}`});continue}let p=Eh(m.stdout);if(!p){t.failures.push({batch_index:l,error:"parse-failed"});continue}let f=hh(m.stdout);t.total_input_tokens+=f.input_tokens,t.total_output_tokens+=f.output_tokens;for(let g of p){if(g.pair_index>=c.length)continue;let h=c[g.pair_index];if(t.classified+=1,g.label==="UNRELATED")continue;let E=uh[g.label];if(E)try{let b=Qe({source_session_id:h.source_session_id,target_session_id:h.target_session_id,link_type:E,confidence:g.confidence,evidence:{l4_label:g.label,l4_reason:g.reason,primary_type_l1_l2_l3:h.primary_link_type,combined_pre_l4:h.combined_confidence,scanner:"l4-llm",model:o},inferred_by:"L4"});if(t.suggestions_created+=1,e.autoPromote){let S=h.layers.map(x=>x.confidence);if(S.push(g.confidence),_r(S)>=i)try{Xa(b.id,"approved",{source:"auto"}),t.links_promoted+=1}catch{}}}catch{}}}return t}Je();var bh=1e3;function Sh(e){let t=e.minConf?Math.max(0,Math.min(1,Number(e.minConf))):Ds,s=e.autoPromoteThreshold!==void 0?Math.max(0,Math.min(1,Number(e.autoPromoteThreshold))):br,n=e.limit?Math.max(1,Number(e.limit)):bh,r=e.model??Er,o=!!e.autoPromote||e.autoPromoteThreshold!==void 0;return{minConfidence:t,autoPromoteThreshold:s,limit:n,model:r,autoPromote:o}}async function nc(e){if(!e.project){console.error("--project <name> is required."),process.exitCode=1;return}let t=_e(e.project);if(!t){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}if(!ce()){console.error("claude CLI not found on PATH. Install Claude Code first, then re-run."),process.exitCode=1;return}let{minConfidence:s,autoPromoteThreshold:n,limit:r,model:o,autoPromote:i}=Sh(e);e.json||console.log(`L4 inference \u2014 project "${t.name}" \u2014 model ${o} \u2014 pre-filter conf \u2265 ${s} \u2014 limit ${r} \u2014 auto-promote ${i?`ON (\u2265 ${n})`:"OFF"}`);let a=Date.now(),l=await sc({projectId:t.id,minConfidence:s,limit:r,autoPromote:i,autoPromoteThreshold:n,model:o,onBatchStart:u=>{e.json||process.stdout.write(`\r batch ${u.batch} (${u.pairs} pairs)\u2026 `)}});e.json||process.stdout.write(`
1225
+ `);let c=Number(((Date.now()-a)/1e3).toFixed(1));if(e.json)console.log(JSON.stringify({project:t.name,model:o,pre_filter_threshold:s,auto_promote:i,auto_promote_threshold:i?n:null,...l,elapsed_seconds:c},null,2));else{if(console.log(`Done in ${c}s \u2014 pairs=${l.candidates_after_filter}/${l.candidates_total} classified=${l.classified} suggestions=${l.suggestions_created} promoted=${l.links_promoted} failures=${l.failures.length}`),console.log(`Token spend: input=${l.total_input_tokens} output=${l.total_output_tokens}`),l.failures.length>0)for(let u of l.failures.slice(0,3))console.log(` \u26A0 batch ${u.batch_index}: ${u.error}`);l.suggestions_created>0?console.log(" Review the new L4 suggestions at #view=suggestions (filter by inferred_by=L4)."):l.candidates_after_filter===0&&console.log(` \u24D8 No pairs cleared the pre-filter (combined conf \u2265 ${s}). Lower --min-conf to widen the batch, or run more L1/L2/L3 inference first.`)}}T();import{createHash as Ch}from"node:crypto";T();j();import{writeFileSync as yh,readFileSync as oC,existsSync as Th,mkdirSync as wh,readdirSync as iC,unlinkSync as aC}from"node:fs";import{join as rc}from"node:path";import{randomUUID as Rh}from"node:crypto";var Sr=rc(R,"bug-patterns");function xh(){P(),Th(Sr)||wh(Sr,{recursive:!0})}function $s(e){return{id:e.id,signature_hash:e.signature_hash,example_message:e.example_message,occurrence_count:e.occurrence_count,first_seen_at:e.first_seen_at,last_seen_at:e.last_seen_at,resolved_in_session_id:e.resolved_in_session_id,fix_summary:e.fix_summary}}function kh(e){return{cluster_id:e.cluster_id,session_id:e.session_id,matched_at:e.matched_at}}function oc(e){if(!e.signature_hash)throw new Error("signature_hash is required");if(!e.example_message)throw new Error("example_message is required");if(!Array.isArray(e.member_session_ids)||e.member_session_ids.length===0)throw new Error("at least one member_session_id is required");let t=_(),s=new Date().toISOString(),n=e.id??Rh(),r=e.first_seen_at??s,o=e.last_seen_at??s,i=Array.from(new Set(e.member_session_ids));t.transaction(()=>{t.prepare(`INSERT INTO bug_pattern_clusters
1226
1226
  (id, signature_hash, example_message, occurrence_count,
1227
1227
  first_seen_at, last_seen_at, resolved_in_session_id, fix_summary)
1228
1228
  VALUES (?, ?, ?, ?, ?, ?, NULL, NULL)`).run(n,e.signature_hash,e.example_message,i.length,r,o);let l=t.prepare(`INSERT INTO bug_pattern_members (cluster_id, session_id, matched_at)
1229
1229
  VALUES (?, ?, ?)
1230
- ON CONFLICT(cluster_id, session_id) DO NOTHING`);for(let c of i)l.run(n,c,s)})();let a=za(n);if(!a)throw new Error("createCluster succeeded but read-back failed");return qa(n),a}function za(e){let t=_(),s=t.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);if(!s)return null;let n=t.prepare("SELECT * FROM bug_pattern_members WHERE cluster_id = ? ORDER BY matched_at ASC, session_id ASC").all(e);return{cluster:As(s),members:n.map(th)}}function Ya(e,t){if(!e)throw new Error("clusterId is required");if(!Array.isArray(t)||t.length===0)throw new Error("sessionIds must be a non-empty array");let s=_();if(!s.prepare("SELECT 1 FROM bug_pattern_clusters WHERE id = ?").get(e))throw new Error(`cluster ${e} not found`);let r=new Date().toISOString(),o=0;s.transaction(()=>{let a=s.prepare(`INSERT INTO bug_pattern_members (cluster_id, session_id, matched_at)
1230
+ ON CONFLICT(cluster_id, session_id) DO NOTHING`);for(let c of i)l.run(n,c,s)})();let a=ic(n);if(!a)throw new Error("createCluster succeeded but read-back failed");return lc(n),a}function ic(e){let t=_(),s=t.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);if(!s)return null;let n=t.prepare("SELECT * FROM bug_pattern_members WHERE cluster_id = ? ORDER BY matched_at ASC, session_id ASC").all(e);return{cluster:$s(s),members:n.map(kh)}}function ac(e,t){if(!e)throw new Error("clusterId is required");if(!Array.isArray(t)||t.length===0)throw new Error("sessionIds must be a non-empty array");let s=_();if(!s.prepare("SELECT 1 FROM bug_pattern_clusters WHERE id = ?").get(e))throw new Error(`cluster ${e} not found`);let r=new Date().toISOString(),o=0;s.transaction(()=>{let a=s.prepare(`INSERT INTO bug_pattern_members (cluster_id, session_id, matched_at)
1231
1231
  VALUES (?, ?, ?)
1232
1232
  ON CONFLICT(cluster_id, session_id) DO NOTHING`);for(let l of Array.from(new Set(t)))a.run(e,l,r).changes>0&&(o+=1);if(o>0){let l=s.prepare("SELECT COUNT(*) AS n FROM bug_pattern_members WHERE cluster_id = ?").get(e).n;s.prepare(`UPDATE bug_pattern_clusters
1233
1233
  SET occurrence_count = ?, last_seen_at = ?
1234
- WHERE id = ?`).run(l,r,e)}})(),o>0&&qa(e);let i=s.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);return{cluster:As(i),added:o}}function sh(e){let t=e.first_user_message?e.first_user_message.slice(0,80):null,s=e.alias??e.auto_title??t??e.session_id.slice(0,8);return{cluster_id:e.cluster_id,session_id:e.session_id,matched_at:e.matched_at,title:s,alias:e.alias,auto_title:e.auto_title,project:e.project,started_at:e.started_at}}function Ka(e){let t=_(),s=t.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);if(!s)return null;let n=t.prepare(`SELECT m.cluster_id, m.session_id, m.matched_at,
1234
+ WHERE id = ?`).run(l,r,e)}})(),o>0&&lc(e);let i=s.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);return{cluster:$s(i),added:o}}function Nh(e){let t=e.first_user_message?e.first_user_message.slice(0,80):null,s=e.alias??e.auto_title??t??e.session_id.slice(0,8);return{cluster_id:e.cluster_id,session_id:e.session_id,matched_at:e.matched_at,title:s,alias:e.alias,auto_title:e.auto_title,project:e.project,started_at:e.started_at}}function cc(e){let t=_(),s=t.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);if(!s)return null;let n=t.prepare(`SELECT m.cluster_id, m.session_id, m.matched_at,
1235
1235
  NULLIF(sa.alias, '') AS alias,
1236
1236
  s.auto_title,
1237
1237
  s.first_user_message,
@@ -1242,37 +1242,37 @@ show full content: recall paste --show <id>
1242
1242
  LEFT JOIN session_aliases sa ON sa.session_id = m.session_id
1243
1243
  LEFT JOIN projects p ON p.id = s.project_id
1244
1244
  WHERE m.cluster_id = ?
1245
- ORDER BY COALESCE(s.started_at, ''), m.matched_at, m.session_id`).all(e);return{cluster:As(s),members:n.map(sh)}}function qa(e){try{eh();let t=za(e);if(!t)return;let s=Ja(pr,`${e}.json`),n={schema:"claude-recall.bug-pattern-cluster.v1",cluster:t.cluster,members:t.members,backed_up_at:new Date().toISOString()};q_(s,JSON.stringify(n,null,2))}catch(t){console.error("[bug-patterns] backup failed:",t)}}function Va(e){return e?_().prepare(`SELECT * FROM bug_pattern_clusters
1245
+ ORDER BY COALESCE(s.started_at, ''), m.matched_at, m.session_id`).all(e);return{cluster:$s(s),members:n.map(Nh)}}function lc(e){try{xh();let t=ic(e);if(!t)return;let s=rc(Sr,`${e}.json`),n={schema:"claude-recall.bug-pattern-cluster.v1",cluster:t.cluster,members:t.members,backed_up_at:new Date().toISOString()};yh(s,JSON.stringify(n,null,2))}catch(t){console.error("[bug-patterns] backup failed:",t)}}function dc(e){return e?_().prepare(`SELECT * FROM bug_pattern_clusters
1246
1246
  WHERE signature_hash = ?
1247
- ORDER BY last_seen_at DESC, id ASC`).all(e).map(As):[]}function Za(e){if(!e)return new Set;let s=_().prepare(`SELECT DISTINCT m.session_id
1247
+ ORDER BY last_seen_at DESC, id ASC`).all(e).map($s):[]}function uc(e){if(!e)return new Set;let s=_().prepare(`SELECT DISTINCT m.session_id
1248
1248
  FROM bug_pattern_members m
1249
1249
  JOIN bug_pattern_clusters c ON c.id = m.cluster_id
1250
- WHERE c.signature_hash = ?`).all(e);return new Set(s.map(n=>n.session_id))}var rh=/\b0x[0-9a-fA-F]+\b/g,oh=/\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\b/g,ih=/\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z?\b/g,ah=/:\d+:\d+/g,ch=/\bline\s+\d+\b/gi,lh=/\bcolumn\s+\d+\b/gi,dh=/\b(?:pid|PID|process(?:\s+id)?)\s*[:=]?\s*\d+\b/gi,uh=/\b(?:port|:)\s*[:=]?\s*\d{2,5}\b/gi,ph=/\b\d{4,}\b/g,mh=/(['"`])[^'"`\n]{1,128}\1/g;function gh(e){if(!e)return"";let t=String(e);return t=t.replace(rh,"<hex>"),t=t.replace(oh,"<uuid>"),t=t.replace(ih,"<ts>"),t=t.replace(ah,":<line>:<col>"),t=t.replace(ch,"line <n>"),t=t.replace(lh,"column <n>"),t=t.replace(dh,"pid <n>"),t=t.replace(uh,"port <n>"),t=t.replace(ph,"<num>"),t=t.replace(mh,"<arg>"),t=t.replace(/\s+/g," ").trim(),t.toLowerCase()}function fh(e){let t=(e.error_type??"unknown").toLowerCase().trim(),s=gh(e.snippet??e.message_hash??""),n=`${t}|${s}`;return nh("sha256").update(n).digest("hex").slice(0,16)}function _h(e){let t=_(),s=["oi.bug_signatures IS NOT NULL"],n=[];e&&(s.push("p.name = ?"),n.push(e));let r=`WHERE ${s.join(" AND ")}`,o=t.prepare(`SELECT oi.session_id AS session_id,
1250
+ WHERE c.signature_hash = ?`).all(e);return new Set(s.map(n=>n.session_id))}var Lh=/\b0x[0-9a-fA-F]+\b/g,Oh=/\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\b/g,Ah=/\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z?\b/g,Ih=/:\d+:\d+/g,vh=/\bline\s+\d+\b/gi,Mh=/\bcolumn\s+\d+\b/gi,Dh=/\b(?:pid|PID|process(?:\s+id)?)\s*[:=]?\s*\d+\b/gi,$h=/\b(?:port|:)\s*[:=]?\s*\d{2,5}\b/gi,jh=/\b\d{4,}\b/g,Ph=/(['"`])[^'"`\n]{1,128}\1/g;function Fh(e){if(!e)return"";let t=String(e);return t=t.replace(Lh,"<hex>"),t=t.replace(Oh,"<uuid>"),t=t.replace(Ah,"<ts>"),t=t.replace(Ih,":<line>:<col>"),t=t.replace(vh,"line <n>"),t=t.replace(Mh,"column <n>"),t=t.replace(Dh,"pid <n>"),t=t.replace($h,"port <n>"),t=t.replace(jh,"<num>"),t=t.replace(Ph,"<arg>"),t=t.replace(/\s+/g," ").trim(),t.toLowerCase()}function Uh(e){let t=(e.error_type??"unknown").toLowerCase().trim(),s=Fh(e.snippet??e.message_hash??""),n=`${t}|${s}`;return Ch("sha256").update(n).digest("hex").slice(0,16)}function Bh(e){let t=_(),s=["oi.bug_signatures IS NOT NULL"],n=[];e&&(s.push("p.name = ?"),n.push(e));let r=`WHERE ${s.join(" AND ")}`,o=t.prepare(`SELECT oi.session_id AS session_id,
1251
1251
  p.name AS project,
1252
1252
  s.started_at AS started_at,
1253
1253
  oi.bug_signatures AS bug_signatures
1254
1254
  FROM session_output_index oi
1255
1255
  LEFT JOIN sessions s ON s.id = oi.session_id
1256
1256
  LEFT JOIN projects p ON p.id = s.project_id
1257
- ${r}`).all(...n),i=[];for(let a of o){if(!a.bug_signatures)continue;let l=[];try{let c=JSON.parse(a.bug_signatures);Array.isArray(c)&&(l=c)}catch{continue}for(let c of l){if(!c||typeof c!="object"||!(c.snippet??"").trim())continue;let p=fh(c);i.push({session_id:a.session_id,project:a.project,started_at:a.started_at,signature:c,fingerprint:p})}}return i}function hh(e){let t=new Map;for(let n of e){let r=t.get(n.fingerprint);r||(r=[],t.set(n.fingerprint,r)),r.push(n)}let s=[];for(let[n,r]of t){let o=new Set,i=[];for(let u of r)o.has(u.session_id)||(o.add(u.session_id),i.push(u));let a=[...i].sort((u,p)=>{let m=u.started_at??"",f=p.started_at??"";return m&&f?m<f?-1:m>f?1:0:m?-1:f?1:0}),l=a.find(u=>u.started_at),c=[...a].reverse().find(u=>u.started_at);s.push({fingerprint:n,example_message:i[0].signature.snippet??i[0].signature.message_hash??"",members:i,first_seen_at:l?.started_at??new Date().toISOString(),last_seen_at:c?.started_at??new Date().toISOString()})}return s}function Eh(e,t){if(e.length!==t.length)return 0;let s=0,n=0,r=0;for(let i=0;i<e.length;i++)s+=e[i]*t[i],n+=e[i]*e[i],r+=t[i]*t[i];let o=Math.sqrt(n)*Math.sqrt(r);return o>0?s/o:0}function bh(e){let{records:t,vectors:s,epsilon:n,minPts:r}=e,o=t.length;if(o===0)return[];let i=[];for(let u=0;u<o;u++){let p=[];for(let m=0;m<o;m++){if(u===m)continue;1-Eh(s[u],s[m])<=n&&p.push(m)}i.push(p)}let a=new Array(o).fill(!1),l=new Array(o).fill(-1),c=[];for(let u=0;u<o;u++){if(a[u])continue;a[u]=!0;let p=i[u];if(p.length<r)continue;let m=c.length;c.push({members:[t[u]]}),l[u]=m;let f=[...p];for(;f.length>0;){let g=f.shift();if(!a[g]&&(a[g]=!0,i[g].length>=r))for(let h of i[g])(!a[h]||l[h]===-1)&&f.push(h);l[g]===-1&&(l[g]=m,c[m].members.push(t[g]))}}return c}async function Sh(e,t,s,n){if(e.length===0)return[];let r=e.map(l=>{let c=l.signature.snippet??l.signature.message_hash??"";return`${l.signature.error_type??""}: ${c}`.trim()}),o=await t(r);if(o.length!==e.length)throw new Error(`embedder returned ${o.length} vectors for ${e.length} inputs`);let i=bh({records:e,vectors:o,epsilon:s,minPts:n}),a=[];for(let l of i){if(l.members.length===0)continue;let c=new Set,u=[];for(let E of l.members)c.has(E.session_id)||(c.add(E.session_id),u.push(E));if(u.length===0)continue;let m=`sem:${[...u.map(E=>E.fingerprint)].sort()[0]}`,f=[...u].sort((E,b)=>{let S=E.started_at??"",C=b.started_at??"";return S<C?-1:S>C?1:0}),g=f.find(E=>E.started_at),h=[...f].reverse().find(E=>E.started_at);a.push({fingerprint:m,example_message:u[0].signature.snippet??u[0].signature.message_hash??"",members:u,first_seen_at:g?.started_at??new Date().toISOString(),last_seen_at:h?.started_at??new Date().toISOString()})}return a}function Qa(e,t){let s={clusters_created:0,clusters_merged:0,members_added:0,cluster_ids:[]};for(let n of e){if(n.members.length<t)continue;let r=Va(n.fingerprint),o=Za(n.fingerprint),i=n.members.map(c=>c.session_id).filter(c=>!o.has(c));if(r.length===0){let c=Ga({signature_hash:n.fingerprint,example_message:n.example_message.slice(0,256),member_session_ids:n.members.map(u=>u.session_id),first_seen_at:n.first_seen_at,last_seen_at:n.last_seen_at});s.clusters_created+=1,s.members_added+=c.members.length,s.cluster_ids.push(c.cluster.id);continue}if(i.length===0){s.cluster_ids.push(r[0].id);continue}let a=r[0],l=Ya(a.id,i);l.added>0&&(s.clusters_merged+=1,s.members_added+=l.added),s.cluster_ids.push(a.id)}return s}async function ec(e={}){let t=Math.max(2,Math.floor(e.minClusterSize??3)),s=Math.max(1,Math.min(5e3,Math.floor(e.limit??1e3))),n=e.semanticEpsilon??.15,r=Math.max(1,Math.floor(e.semanticMinPts??1)),o=_h(e.project),i=new Set(o.map(S=>S.session_id)),a=hh(o),l=[],c=!1;if(e.semantic){let S=e.embedder??null;if(!S)try{S=await wh()}catch(C){let L=(C instanceof Error?C.message:String(C)).split(`
1257
+ ${r}`).all(...n),i=[];for(let a of o){if(!a.bug_signatures)continue;let l=[];try{let c=JSON.parse(a.bug_signatures);Array.isArray(c)&&(l=c)}catch{continue}for(let c of l){if(!c||typeof c!="object"||!(c.snippet??"").trim())continue;let m=Uh(c);i.push({session_id:a.session_id,project:a.project,started_at:a.started_at,signature:c,fingerprint:m})}}return i}function Hh(e){let t=new Map;for(let n of e){let r=t.get(n.fingerprint);r||(r=[],t.set(n.fingerprint,r)),r.push(n)}let s=[];for(let[n,r]of t){let o=new Set,i=[];for(let u of r)o.has(u.session_id)||(o.add(u.session_id),i.push(u));let a=[...i].sort((u,m)=>{let p=u.started_at??"",f=m.started_at??"";return p&&f?p<f?-1:p>f?1:0:p?-1:f?1:0}),l=a.find(u=>u.started_at),c=[...a].reverse().find(u=>u.started_at);s.push({fingerprint:n,example_message:i[0].signature.snippet??i[0].signature.message_hash??"",members:i,first_seen_at:l?.started_at??new Date().toISOString(),last_seen_at:c?.started_at??new Date().toISOString()})}return s}function Wh(e,t){if(e.length!==t.length)return 0;let s=0,n=0,r=0;for(let i=0;i<e.length;i++)s+=e[i]*t[i],n+=e[i]*e[i],r+=t[i]*t[i];let o=Math.sqrt(n)*Math.sqrt(r);return o>0?s/o:0}function Xh(e){let{records:t,vectors:s,epsilon:n,minPts:r}=e,o=t.length;if(o===0)return[];let i=[];for(let u=0;u<o;u++){let m=[];for(let p=0;p<o;p++){if(u===p)continue;1-Wh(s[u],s[p])<=n&&m.push(p)}i.push(m)}let a=new Array(o).fill(!1),l=new Array(o).fill(-1),c=[];for(let u=0;u<o;u++){if(a[u])continue;a[u]=!0;let m=i[u];if(m.length<r)continue;let p=c.length;c.push({members:[t[u]]}),l[u]=p;let f=[...m];for(;f.length>0;){let g=f.shift();if(!a[g]&&(a[g]=!0,i[g].length>=r))for(let h of i[g])(!a[h]||l[h]===-1)&&f.push(h);l[g]===-1&&(l[g]=p,c[p].members.push(t[g]))}}return c}async function Jh(e,t,s,n){if(e.length===0)return[];let r=e.map(l=>{let c=l.signature.snippet??l.signature.message_hash??"";return`${l.signature.error_type??""}: ${c}`.trim()}),o=await t(r);if(o.length!==e.length)throw new Error(`embedder returned ${o.length} vectors for ${e.length} inputs`);let i=Xh({records:e,vectors:o,epsilon:s,minPts:n}),a=[];for(let l of i){if(l.members.length===0)continue;let c=new Set,u=[];for(let E of l.members)c.has(E.session_id)||(c.add(E.session_id),u.push(E));if(u.length===0)continue;let p=`sem:${[...u.map(E=>E.fingerprint)].sort()[0]}`,f=[...u].sort((E,b)=>{let S=E.started_at??"",N=b.started_at??"";return S<N?-1:S>N?1:0}),g=f.find(E=>E.started_at),h=[...f].reverse().find(E=>E.started_at);a.push({fingerprint:p,example_message:u[0].signature.snippet??u[0].signature.message_hash??"",members:u,first_seen_at:g?.started_at??new Date().toISOString(),last_seen_at:h?.started_at??new Date().toISOString()})}return a}function mc(e,t){let s={clusters_created:0,clusters_merged:0,members_added:0,cluster_ids:[]};for(let n of e){if(n.members.length<t)continue;let r=dc(n.fingerprint),o=uc(n.fingerprint),i=n.members.map(c=>c.session_id).filter(c=>!o.has(c));if(r.length===0){let c=oc({signature_hash:n.fingerprint,example_message:n.example_message.slice(0,256),member_session_ids:n.members.map(u=>u.session_id),first_seen_at:n.first_seen_at,last_seen_at:n.last_seen_at});s.clusters_created+=1,s.members_added+=c.members.length,s.cluster_ids.push(c.cluster.id);continue}if(i.length===0){s.cluster_ids.push(r[0].id);continue}let a=r[0],l=ac(a.id,i);l.added>0&&(s.clusters_merged+=1,s.members_added+=l.added),s.cluster_ids.push(a.id)}return s}async function pc(e={}){let t=Math.max(2,Math.floor(e.minClusterSize??3)),s=Math.max(1,Math.min(5e3,Math.floor(e.limit??1e3))),n=e.semanticEpsilon??.15,r=Math.max(1,Math.floor(e.semanticMinPts??1)),o=Bh(e.project),i=new Set(o.map(S=>S.session_id)),a=Hh(o),l=[],c=!1;if(e.semantic){let S=e.embedder??null;if(!S)try{S=await Yh()}catch(N){let L=(N instanceof Error?N.message:String(N)).split(`
1258
1258
  `)[0];console.warn(`[bug-pattern] --semantic requested but the embedder is unavailable: ${L}
1259
- Falling back to exact-match-only clustering. Run \`recall semantic install\` to enable the semantic pass.`),c=!0}if(S){let C=[];for(let x of a)x.members.length===1&&C.push(x.members[0]);C.length>=2&&(l=await Sh(C,S,n,r))}}let u=a.filter(S=>S.members.length>=t),p=l.filter(S=>S.members.length>=t),m=Qa(u,t),f=Qa(p,t),g=[...m.cluster_ids,...f.cluster_ids],h=Array.from(new Set(g)),E=[];if(h.length>0){let S=_(),C=h.map(()=>"?").join(","),x=S.prepare(`SELECT * FROM bug_pattern_clusters
1260
- WHERE id IN (${C})
1259
+ Falling back to exact-match-only clustering. Run \`recall semantic install\` to enable the semantic pass.`),c=!0}if(S){let N=[];for(let x of a)x.members.length===1&&N.push(x.members[0]);N.length>=2&&(l=await Jh(N,S,n,r))}}let u=a.filter(S=>S.members.length>=t),m=l.filter(S=>S.members.length>=t),p=mc(u,t),f=mc(m,t),g=[...p.cluster_ids,...f.cluster_ids],h=Array.from(new Set(g)),E=[];if(h.length>0){let S=_(),N=h.map(()=>"?").join(","),x=S.prepare(`SELECT * FROM bug_pattern_clusters
1260
+ WHERE id IN (${N})
1261
1261
  ORDER BY occurrence_count DESC, last_seen_at DESC
1262
- LIMIT ?`).all(...h,s);for(let L of x)E.push({id:L.id,signature_hash:L.signature_hash,example_message:L.example_message,occurrence_count:L.occurrence_count,first_seen_at:L.first_seen_at,last_seen_at:L.last_seen_at,resolved_in_session_id:L.resolved_in_session_id,fix_summary:L.fix_summary})}return{progress:{total_sessions:i.size,total_signatures:o.length,exact_match_groups:u.length,semantic_groups:p.length,clusters_created:m.clusters_created+f.clusters_created,clusters_merged:m.clusters_merged+f.clusters_merged,members_added:m.members_added+f.members_added,semantic_skipped:c},clusters:E}}var yh=async()=>{let{embed:e,loadEmbedder:t,getEmbedderStatus:s}=await Promise.resolve().then(()=>(qe(),Yn));return s().loaded||await t(),e},Th=yh;async function wh(){return Th()}function Rh(e,t){let s=Ka(e);if(!s)return null;let n=s.cluster,r=s.members.slice(0,t).map(o=>({session_id:o.session_id,title:o.title,project:o.project,started_at:o.started_at}));return{id:n.id,signature_hash:n.signature_hash,example_message:n.example_message,occurrence_count:n.occurrence_count,first_seen_at:n.first_seen_at,last_seen_at:n.last_seen_at,status:n.resolved_in_session_id?"resolved":"open",resolved_in_session_id:n.resolved_in_session_id,sample_members:r}}async function tc(e){let t=e.minClusterSize?Math.max(2,Math.floor(Number(e.minClusterSize))):3;if(!Number.isFinite(t)){console.error("--min-cluster-size must be a positive number"),process.exitCode=1;return}let s=e.limit?Math.max(1,Math.floor(Number(e.limit))):100;if(!Number.isFinite(s)){console.error("--limit must be a positive number"),process.exitCode=1;return}let n;if(e.project){let c=ge(e.project);if(!c){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}n=c.name}if(!e.json){let c=n?`project "${n}"`:"all projects",u=e.semantic?"exact + semantic":"exact";console.log(`Inferring bug patterns \u2014 ${c}, min-cluster-size=${t}, ${u} passes\u2026`)}let r={project:n,minClusterSize:t,semantic:!!e.semantic,limit:s},o=Date.now(),i;try{i=await ec(r)}catch(c){console.error(c instanceof Error?c.message:String(c)),process.exitCode=1;return}let a=Number(((Date.now()-o)/1e3).toFixed(1)),l=[];for(let c of i.clusters.slice(0,s)){let u=Rh(c.id,3);u&&l.push(u)}if(e.json){console.log(JSON.stringify({project:n??null,progress:i.progress,elapsed_seconds:a,clusters:l},null,2));return}if(console.log(`Done in ${a}s \u2014 sessions=${i.progress.total_sessions} signatures=${i.progress.total_signatures} clusters: created=${i.progress.clusters_created} merged=${i.progress.clusters_merged} members_added=${i.progress.members_added}`),i.progress.semantic_skipped&&console.log(" \u24D8 semantic pass skipped \u2014 embedder unavailable. Run `recall semantic install` to enable."),l.length===0){i.progress.total_signatures===0?console.log(" \u24D8 No bug signatures in the corpus yet. Run `recall extract-outputs --project <name>` first to populate session_output_index."):console.log(` \u24D8 No clusters at min-cluster-size=${t}. Try \`--semantic\` to merge near-duplicate snippets, or lower \`--min-cluster-size 2\` to surface pairs.`);return}console.log(`
1263
- Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u2713 resolved":"open",p=c.example_message.slice(0,80);console.log(`
1262
+ LIMIT ?`).all(...h,s);for(let L of x)E.push({id:L.id,signature_hash:L.signature_hash,example_message:L.example_message,occurrence_count:L.occurrence_count,first_seen_at:L.first_seen_at,last_seen_at:L.last_seen_at,resolved_in_session_id:L.resolved_in_session_id,fix_summary:L.fix_summary})}return{progress:{total_sessions:i.size,total_signatures:o.length,exact_match_groups:u.length,semantic_groups:m.length,clusters_created:p.clusters_created+f.clusters_created,clusters_merged:p.clusters_merged+f.clusters_merged,members_added:p.members_added+f.members_added,semantic_skipped:c},clusters:E}}var Gh=async()=>{let{embed:e,loadEmbedder:t,getEmbedderStatus:s}=await Promise.resolve().then(()=>(Ve(),sr));return s().loaded||await t(),e},zh=Gh;async function Yh(){return zh()}function Kh(e,t){let s=cc(e);if(!s)return null;let n=s.cluster,r=s.members.slice(0,t).map(o=>({session_id:o.session_id,title:o.title,project:o.project,started_at:o.started_at}));return{id:n.id,signature_hash:n.signature_hash,example_message:n.example_message,occurrence_count:n.occurrence_count,first_seen_at:n.first_seen_at,last_seen_at:n.last_seen_at,status:n.resolved_in_session_id?"resolved":"open",resolved_in_session_id:n.resolved_in_session_id,sample_members:r}}async function gc(e){let t=e.minClusterSize?Math.max(2,Math.floor(Number(e.minClusterSize))):3;if(!Number.isFinite(t)){console.error("--min-cluster-size must be a positive number"),process.exitCode=1;return}let s=e.limit?Math.max(1,Math.floor(Number(e.limit))):100;if(!Number.isFinite(s)){console.error("--limit must be a positive number"),process.exitCode=1;return}let n;if(e.project){let c=_e(e.project);if(!c){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}n=c.name}if(!e.json){let c=n?`project "${n}"`:"all projects",u=e.semantic?"exact + semantic":"exact";console.log(`Inferring bug patterns \u2014 ${c}, min-cluster-size=${t}, ${u} passes\u2026`)}let r={project:n,minClusterSize:t,semantic:!!e.semantic,limit:s},o=Date.now(),i;try{i=await pc(r)}catch(c){console.error(c instanceof Error?c.message:String(c)),process.exitCode=1;return}let a=Number(((Date.now()-o)/1e3).toFixed(1)),l=[];for(let c of i.clusters.slice(0,s)){let u=Kh(c.id,3);u&&l.push(u)}if(e.json){console.log(JSON.stringify({project:n??null,progress:i.progress,elapsed_seconds:a,clusters:l},null,2));return}if(console.log(`Done in ${a}s \u2014 sessions=${i.progress.total_sessions} signatures=${i.progress.total_signatures} clusters: created=${i.progress.clusters_created} merged=${i.progress.clusters_merged} members_added=${i.progress.members_added}`),i.progress.semantic_skipped&&console.log(" \u24D8 semantic pass skipped \u2014 embedder unavailable. Run `recall semantic install` to enable."),l.length===0){i.progress.total_signatures===0?console.log(" \u24D8 No bug signatures in the corpus yet. Run `recall extract-outputs --project <name>` first to populate session_output_index."):console.log(` \u24D8 No clusters at min-cluster-size=${t}. Try \`--semantic\` to merge near-duplicate snippets, or lower \`--min-cluster-size 2\` to surface pairs.`);return}console.log(`
1263
+ Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u2713 resolved":"open",m=c.example_message.slice(0,80);console.log(`
1264
1264
  [${u}] occurs=${c.occurrence_count} hash=${c.signature_hash.slice(0,8)}
1265
- ${p}
1266
- first=${c.first_seen_at} last=${c.last_seen_at}`);for(let m of c.sample_members){let f=m.project?`[${m.project}] `:"";console.log(` \u2022 ${f}${m.title} (${m.session_id.slice(0,8)})`)}}console.log("\n Review at /graph/patterns in the web UI, or `recall neighborhood <session-id>` for an agent-facing bundle.")}T();import{z as BC}from"zod";T();function sc(e){let t=e.trim();if(t.length<4)return null;let s=_();if(t.length>=32)return s.prepare("SELECT id FROM sessions WHERE id = ?").get(t)?.id??null;let n=s.prepare("SELECT id FROM sessions WHERE id LIKE ? LIMIT 2").all(`${t}%`);return n.length===1?n[0].id:null}mr();var uc=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),pc=new Set(["pagerank","embedding-rerank","hybrid"]);function Fh(e){if(!e)return;let t=e.split(",").map(s=>s.trim()).filter(Boolean);for(let s of t)if(!uc.has(s))throw new Error(`invalid --edge-types value: '${s}'. Valid: ${Array.from(uc).join(", ")}`);return t}function Uh(e){if(!e)return"hybrid";if(!pc.has(e))throw new Error(`invalid --scoring value: '${e}'. Valid: ${Array.from(pc).join(", ")}`);return e}async function mc(e,t){let s=sc(e);if(!s){console.error(`session not found or prefix ambiguous: ${e}`),process.exitCode=1;return}let n,r;try{n=Uh(t.scoring),r=Fh(t.edgeTypes)}catch(l){console.error(l instanceof Error?l.message:String(l)),process.exitCode=1;return}let o=t.budget?Math.max(100,Number(t.budget)):4e3;if(!Number.isFinite(o)){console.error("--budget must be a positive number"),process.exitCode=1;return}let i=t.maxDepth?Math.max(1,Number(t.maxDepth)):2;if(!Number.isFinite(i)){console.error("--max-depth must be a positive number"),process.exitCode=1;return}let a;try{a=Ms(s,{budget:o,maxDepth:i,scoring:n,edgeTypes:r,includeWikiLinks:t.wikiLinks!==!1,includeSuggestions:!!t.includeSuggestions})}catch(l){console.error(l instanceof Error?l.message:String(l)),process.exitCode=1;return}if(t.json){process.stdout.write(JSON.stringify(a,null,2)+`
1265
+ ${m}
1266
+ first=${c.first_seen_at} last=${c.last_seen_at}`);for(let p of c.sample_members){let f=p.project?`[${p.project}] `:"";console.log(` \u2022 ${f}${p.title} (${p.session_id.slice(0,8)})`)}}console.log("\n Review at /graph/patterns in the web UI, or `recall neighborhood <session-id>` for an agent-facing bundle.")}T();import{z as xC}from"zod";T();function fc(e){let t=e.trim();if(t.length<4)return null;let s=_();if(t.length>=32)return s.prepare("SELECT id FROM sessions WHERE id = ?").get(t)?.id??null;let n=s.prepare("SELECT id FROM sessions WHERE id LIKE ? LIMIT 2").all(`${t}%`);return n.length===1?n[0].id:null}yr();var Rc=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),xc=new Set(["pagerank","embedding-rerank","hybrid"]);function dE(e){if(!e)return;let t=e.split(",").map(s=>s.trim()).filter(Boolean);for(let s of t)if(!Rc.has(s))throw new Error(`invalid --edge-types value: '${s}'. Valid: ${Array.from(Rc).join(", ")}`);return t}function uE(e){if(!e)return"hybrid";if(!xc.has(e))throw new Error(`invalid --scoring value: '${e}'. Valid: ${Array.from(xc).join(", ")}`);return e}async function kc(e,t){let s=fc(e);if(!s){console.error(`session not found or prefix ambiguous: ${e}`),process.exitCode=1;return}let n,r;try{n=uE(t.scoring),r=dE(t.edgeTypes)}catch(l){console.error(l instanceof Error?l.message:String(l)),process.exitCode=1;return}let o=t.budget?Math.max(100,Number(t.budget)):4e3;if(!Number.isFinite(o)){console.error("--budget must be a positive number"),process.exitCode=1;return}let i=t.maxDepth?Math.max(1,Number(t.maxDepth)):2;if(!Number.isFinite(i)){console.error("--max-depth must be a positive number"),process.exitCode=1;return}let a;try{a=Fs(s,{budget:o,maxDepth:i,scoring:n,edgeTypes:r,includeWikiLinks:t.wikiLinks!==!1,includeSuggestions:!!t.includeSuggestions})}catch(l){console.error(l instanceof Error?l.message:String(l)),process.exitCode=1;return}if(t.json){process.stdout.write(JSON.stringify(a,null,2)+`
1267
1267
  `);return}process.stdout.write(a.bundle),a.truncated.length>0&&console.error(`
1268
- [truncated ${a.truncated.length} refs to fit ${o}-token budget; ${a.budgetUsed} used / ${a.budgetRemaining} remaining]`)}T();M();var Bh=[[/opus[-_ ]?4[-_. ]?7/i,{label:"Opus 4.7",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/opus[-_ ]?4[-_. ]?6/i,{label:"Opus 4.6",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/sonnet[-_ ]?4[-_. ]?6/i,{label:"Sonnet 4.6",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/sonnet[-_ ]?4[-_. ]?5/i,{label:"Sonnet 4.5",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/haiku[-_ ]?4[-_. ]?5/i,{label:"Haiku 4.5",inputCentsPerMtok:100,outputCentsPerMtok:500,cacheCreateCentsPerMtok:125,cacheReadCentsPerMtok:10}],[/opus[-_ ]?4(?!.*[5-9])/i,{label:"Opus 4",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/sonnet[-_ ]?4(?!.*[5-9])/i,{label:"Sonnet 4",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/3[-_. ]?7[-_ ]?sonnet|sonnet[-_ ]?3[-_. ]?7/i,{label:"Sonnet 3.7",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/3[-_. ]?5[-_ ]?sonnet|sonnet[-_ ]?3[-_. ]?5/i,{label:"Sonnet 3.5",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/3[-_. ]?5[-_ ]?haiku|haiku[-_ ]?3[-_. ]?5/i,{label:"Haiku 3.5",inputCentsPerMtok:80,outputCentsPerMtok:400,cacheCreateCentsPerMtok:100,cacheReadCentsPerMtok:8}],[/3[-_ ]?opus|opus[-_ ]?3/i,{label:"Opus 3",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/3[-_ ]?haiku|haiku(?!.*3[-_. ]?5)/i,{label:"Haiku 3",inputCentsPerMtok:25,outputCentsPerMtok:125,cacheCreateCentsPerMtok:30,cacheReadCentsPerMtok:3}],[/opus/i,{label:"Opus",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/sonnet/i,{label:"Sonnet",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/haiku/i,{label:"Haiku",inputCentsPerMtok:100,outputCentsPerMtok:500,cacheCreateCentsPerMtok:125,cacheReadCentsPerMtok:10}]],gc={label:"unknown",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30};function Qe(e){if(!e)return gc;for(let[t,s]of Bh)if(t.test(e))return s;return gc}function Ae(e,t){if(e.byModel&&Object.keys(e.byModel).length>0){let i={input:0,output:0,cacheCreate:0,cacheRead:0},a=0;for(let[c,u]of Object.entries(e.byModel)){let p=Qe(c);i.input+=u.inputTokens/1e6*p.inputCentsPerMtok,i.output+=u.outputTokens/1e6*p.outputCentsPerMtok,i.cacheCreate+=u.cacheCreateTokens/1e6*p.cacheCreateCentsPerMtok,i.cacheRead+=u.cacheReadTokens/1e6*p.cacheReadCentsPerMtok,a+=u.inputTokens+u.outputTokens+u.cacheCreateTokens+u.cacheReadTokens}let l=i.input+i.output+i.cacheCreate+i.cacheRead;return{cents:l,dollars:l/100,totalTokens:a,parts:i}}let s=Qe(t),n={input:e.inputTokens/1e6*s.inputCentsPerMtok,output:e.outputTokens/1e6*s.outputCentsPerMtok,cacheCreate:e.cacheCreateTokens/1e6*s.cacheCreateCentsPerMtok,cacheRead:e.cacheReadTokens/1e6*s.cacheReadCentsPerMtok},r=n.input+n.output+n.cacheCreate+n.cacheRead,o=e.inputTokens+e.outputTokens+e.cacheCreateTokens+e.cacheReadTokens;return{cents:r,dollars:r/100,totalTokens:o,parts:n}}function se(e){let t=e/100;return t===0?"$0.00":t<.01?"<$0.01":t<1?`$${t.toFixed(2)}`:t<100?`$${t.toFixed(2)}`:t<1e4?`$${t.toFixed(0)}`:`$${(t/1e3).toFixed(1)}k`}function le(e){return!Number.isFinite(e)||e<0?"0":e<1e3?String(Math.round(e)):e<1e6?`${(e/1e3).toFixed(1)}k`:e<1e9?`${(e/1e6).toFixed(2)}M`:e<1e12?`${(e/1e9).toFixed(2)}B`:`${(e/1e12).toFixed(2)}T`}T();T();var Hh=500,Ds=new Set;function fc(){return Ds.size}function Wh(){return`
1268
+ [truncated ${a.truncated.length} refs to fit ${o}-token budget; ${a.budgetUsed} used / ${a.budgetRemaining} remaining]`)}T();I();var mE=[[/opus[-_ ]?4[-_. ]?7/i,{label:"Opus 4.7",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/opus[-_ ]?4[-_. ]?6/i,{label:"Opus 4.6",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/sonnet[-_ ]?4[-_. ]?6/i,{label:"Sonnet 4.6",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/sonnet[-_ ]?4[-_. ]?5/i,{label:"Sonnet 4.5",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/haiku[-_ ]?4[-_. ]?5/i,{label:"Haiku 4.5",inputCentsPerMtok:100,outputCentsPerMtok:500,cacheCreateCentsPerMtok:125,cacheReadCentsPerMtok:10}],[/opus[-_ ]?4(?!.*[5-9])/i,{label:"Opus 4",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/sonnet[-_ ]?4(?!.*[5-9])/i,{label:"Sonnet 4",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/3[-_. ]?7[-_ ]?sonnet|sonnet[-_ ]?3[-_. ]?7/i,{label:"Sonnet 3.7",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/3[-_. ]?5[-_ ]?sonnet|sonnet[-_ ]?3[-_. ]?5/i,{label:"Sonnet 3.5",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/3[-_. ]?5[-_ ]?haiku|haiku[-_ ]?3[-_. ]?5/i,{label:"Haiku 3.5",inputCentsPerMtok:80,outputCentsPerMtok:400,cacheCreateCentsPerMtok:100,cacheReadCentsPerMtok:8}],[/3[-_ ]?opus|opus[-_ ]?3/i,{label:"Opus 3",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/3[-_ ]?haiku|haiku(?!.*3[-_. ]?5)/i,{label:"Haiku 3",inputCentsPerMtok:25,outputCentsPerMtok:125,cacheCreateCentsPerMtok:30,cacheReadCentsPerMtok:3}],[/opus/i,{label:"Opus",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/sonnet/i,{label:"Sonnet",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/haiku/i,{label:"Haiku",inputCentsPerMtok:100,outputCentsPerMtok:500,cacheCreateCentsPerMtok:125,cacheReadCentsPerMtok:10}]],Nc={label:"unknown",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30};function et(e){if(!e)return Nc;for(let[t,s]of mE)if(t.test(e))return s;return Nc}function Ie(e,t){if(e.byModel&&Object.keys(e.byModel).length>0){let i={input:0,output:0,cacheCreate:0,cacheRead:0},a=0;for(let[c,u]of Object.entries(e.byModel)){let m=et(c);i.input+=u.inputTokens/1e6*m.inputCentsPerMtok,i.output+=u.outputTokens/1e6*m.outputCentsPerMtok,i.cacheCreate+=u.cacheCreateTokens/1e6*m.cacheCreateCentsPerMtok,i.cacheRead+=u.cacheReadTokens/1e6*m.cacheReadCentsPerMtok,a+=u.inputTokens+u.outputTokens+u.cacheCreateTokens+u.cacheReadTokens}let l=i.input+i.output+i.cacheCreate+i.cacheRead;return{cents:l,dollars:l/100,totalTokens:a,parts:i}}let s=et(t),n={input:e.inputTokens/1e6*s.inputCentsPerMtok,output:e.outputTokens/1e6*s.outputCentsPerMtok,cacheCreate:e.cacheCreateTokens/1e6*s.cacheCreateCentsPerMtok,cacheRead:e.cacheReadTokens/1e6*s.cacheReadCentsPerMtok},r=n.input+n.output+n.cacheCreate+n.cacheRead,o=e.inputTokens+e.outputTokens+e.cacheCreateTokens+e.cacheReadTokens;return{cents:r,dollars:r/100,totalTokens:o,parts:n}}function se(e){let t=e/100;return t===0?"$0.00":t<.01?"<$0.01":t<1?`$${t.toFixed(2)}`:t<100?`$${t.toFixed(2)}`:t<1e4?`$${t.toFixed(0)}`:`$${(t/1e3).toFixed(1)}k`}function le(e){return!Number.isFinite(e)||e<0?"0":e<1e3?String(Math.round(e)):e<1e6?`${(e/1e3).toFixed(1)}k`:e<1e9?`${(e/1e6).toFixed(2)}M`:e<1e12?`${(e/1e9).toFixed(2)}B`:`${(e/1e12).toFixed(2)}T`}T();T();var pE=500,Us=new Set;function Cc(){return Us.size}function gE(){return`
1269
1269
  SELECT m.uuid, m.session_id, m.timestamp, m.raw_json
1270
1270
  FROM messages m
1271
1271
  LEFT JOIN message_usage mu ON mu.message_uuid = m.uuid
1272
1272
  WHERE m.role = 'assistant' AND mu.message_uuid IS NULL
1273
1273
  AND m.uuid NOT IN (SELECT value FROM json_each(?))
1274
1274
  LIMIT ?
1275
- `}function Xh(e,t){let s=t.limit??Number.MAX_SAFE_INTEGER,n=Math.max(1,t.chunkSize??Hh),r=e.prepare(Wh()),o=e.prepare(`
1275
+ `}function fE(e,t){let s=t.limit??Number.MAX_SAFE_INTEGER,n=Math.max(1,t.chunkSize??pE),r=e.prepare(gE()),o=e.prepare(`
1276
1276
  INSERT INTO message_usage (
1277
1277
  message_uuid, session_id, model,
1278
1278
  input_tokens, output_tokens, cache_create_tokens, cache_read_tokens,
@@ -1282,7 +1282,7 @@ Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u271
1282
1282
  @input, @output, @cc, @cr, @ts
1283
1283
  )
1284
1284
  ON CONFLICT(message_uuid) DO NOTHING
1285
- `),i=0,a=0,l=new Set;for(;i<s;){let c=Math.min(n,s-i),u=JSON.stringify([...Ds]),p=r.all(u,c);if(p.length===0)break;let m=new Set;if(e.transaction(()=>{for(let g of p){let h;try{h=JSON.parse(g.raw_json)}catch{Ds.add(g.uuid);continue}let E=ln(h.message);if(!E){Ds.add(g.uuid);continue}o.run({uuid:g.uuid,session_id:g.session_id,model:h.message?.model??null,input:E.inputTokens,output:E.outputTokens,cc:E.cacheCreateTokens,cr:E.cacheReadTokens,ts:g.timestamp}),a+=1,m.add(g.session_id)}for(let g of m)ts(e,g),l.add(g)})(),i+=p.length,t.onProgress?.({scanned:i,inserted:a,sessionsTouched:l.size,done:p.length<c}),p.length<c)break}return{scanned:i,inserted:a,sessionsTouched:l.size,done:!0}}function _c(e={}){return Xh(_(),e)}function gr(e){let t=new Map;for(let n of e){let r=n.model??null,o=t.get(r)??{inputTokens:0,outputTokens:0,cacheCreateTokens:0,cacheReadTokens:0,messageCount:0};o.inputTokens+=n.input_tokens,o.outputTokens+=n.output_tokens,o.cacheCreateTokens+=n.cache_create_tokens,o.cacheReadTokens+=n.cache_read_tokens,o.messageCount+=n.n,t.set(r,o)}let s=[];for(let[n,r]of t.entries()){let o=Ae({inputTokens:r.inputTokens,outputTokens:r.outputTokens,cacheCreateTokens:r.cacheCreateTokens,cacheReadTokens:r.cacheReadTokens},n);s.push({model:n,modelLabel:Qe(n).label,inputTokens:r.inputTokens,outputTokens:r.outputTokens,cacheCreateTokens:r.cacheCreateTokens,cacheReadTokens:r.cacheReadTokens,messageCount:r.messageCount,cost:o})}return s.sort((n,r)=>r.cost.cents-n.cost.cents)}function fr(e){let t={};for(let s of e)t[s.model??"__unknown__"]={inputTokens:s.inputTokens,outputTokens:s.outputTokens,cacheCreateTokens:s.cacheCreateTokens,cacheReadTokens:s.cacheReadTokens};return{byModel:t}}function hc(e){let t=_(),s=t.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
1285
+ `),i=0,a=0,l=new Set;for(;i<s;){let c=Math.min(n,s-i),u=JSON.stringify([...Us]),m=r.all(u,c);if(m.length===0)break;let p=new Set;if(e.transaction(()=>{for(let g of m){let h;try{h=JSON.parse(g.raw_json)}catch{Us.add(g.uuid);continue}let E=bn(h.message);if(!E){Us.add(g.uuid);continue}o.run({uuid:g.uuid,session_id:g.session_id,model:h.message?.model??null,input:E.inputTokens,output:E.outputTokens,cc:E.cacheCreateTokens,cr:E.cacheReadTokens,ts:g.timestamp}),a+=1,p.add(g.session_id)}for(let g of p)os(e,g),l.add(g)})(),i+=m.length,t.onProgress?.({scanned:i,inserted:a,sessionsTouched:l.size,done:m.length<c}),m.length<c)break}return{scanned:i,inserted:a,sessionsTouched:l.size,done:!0}}function Lc(e={}){return fE(_(),e)}function Tr(e){let t=new Map;for(let n of e){let r=n.model??null,o=t.get(r)??{inputTokens:0,outputTokens:0,cacheCreateTokens:0,cacheReadTokens:0,messageCount:0};o.inputTokens+=n.input_tokens,o.outputTokens+=n.output_tokens,o.cacheCreateTokens+=n.cache_create_tokens,o.cacheReadTokens+=n.cache_read_tokens,o.messageCount+=n.n,t.set(r,o)}let s=[];for(let[n,r]of t.entries()){let o=Ie({inputTokens:r.inputTokens,outputTokens:r.outputTokens,cacheCreateTokens:r.cacheCreateTokens,cacheReadTokens:r.cacheReadTokens},n);s.push({model:n,modelLabel:et(n).label,inputTokens:r.inputTokens,outputTokens:r.outputTokens,cacheCreateTokens:r.cacheCreateTokens,cacheReadTokens:r.cacheReadTokens,messageCount:r.messageCount,cost:o})}return s.sort((n,r)=>r.cost.cents-n.cost.cents)}function wr(e){let t={};for(let s of e)t[s.model??"__unknown__"]={inputTokens:s.inputTokens,outputTokens:s.outputTokens,cacheCreateTokens:s.cacheCreateTokens,cacheReadTokens:s.cacheReadTokens};return{byModel:t}}function Oc(e){let t=_(),s=t.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
1286
1286
  s.message_count,
1287
1287
  s.total_input_tokens, s.total_output_tokens,
1288
1288
  s.total_cache_create_tokens, s.total_cache_read_tokens,
@@ -1297,7 +1297,7 @@ Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u271
1297
1297
  COUNT(*) AS n
1298
1298
  FROM message_usage
1299
1299
  WHERE session_id = ?
1300
- GROUP BY model`).all(e),r=gr(n),o=s.total_input_tokens??0,i=s.total_output_tokens??0,a=s.total_cache_create_tokens??0,l=s.total_cache_read_tokens??0,c=Ae({inputTokens:o,outputTokens:i,cacheCreateTokens:a,cacheReadTokens:l,...fr(r)},s.primary_model);return{sessionId:s.id,project:s.project,startedAt:s.started_at,endedAt:s.ended_at,messageCount:s.message_count,primaryModel:s.primary_model,primaryModelLabel:Qe(s.primary_model).label,inputTokens:o,outputTokens:i,cacheCreateTokens:a,cacheReadTokens:l,totalTokens:c.totalTokens,cost:c,byModel:r,display:{dollars:se(c.cents),tokens:le(c.totalTokens),model:Qe(s.primary_model).label}}}function Ec(e){let t=_(),s=t.prepare("SELECT id, name FROM projects WHERE name = ?").get(e);if(!s)return null;let n=t.prepare(`SELECT mu.model,
1300
+ GROUP BY model`).all(e),r=Tr(n),o=s.total_input_tokens??0,i=s.total_output_tokens??0,a=s.total_cache_create_tokens??0,l=s.total_cache_read_tokens??0,c=Ie({inputTokens:o,outputTokens:i,cacheCreateTokens:a,cacheReadTokens:l,...wr(r)},s.primary_model);return{sessionId:s.id,project:s.project,startedAt:s.started_at,endedAt:s.ended_at,messageCount:s.message_count,primaryModel:s.primary_model,primaryModelLabel:et(s.primary_model).label,inputTokens:o,outputTokens:i,cacheCreateTokens:a,cacheReadTokens:l,totalTokens:c.totalTokens,cost:c,byModel:r,display:{dollars:se(c.cents),tokens:le(c.totalTokens),model:et(s.primary_model).label}}}function Ac(e){let t=_(),s=t.prepare("SELECT id, name FROM projects WHERE name = ?").get(e);if(!s)return null;let n=t.prepare(`SELECT mu.model,
1301
1301
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
1302
1302
  COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
1303
1303
  COALESCE(SUM(mu.cache_create_tokens), 0) AS cache_create_tokens,
@@ -1306,12 +1306,12 @@ Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u271
1306
1306
  FROM message_usage mu
1307
1307
  JOIN sessions s ON s.id = mu.session_id
1308
1308
  WHERE s.project_id = ?
1309
- GROUP BY mu.model`).all(s.id),r=gr(n),o=t.prepare(`SELECT COALESCE(SUM(total_input_tokens), 0) AS input_tokens,
1309
+ GROUP BY mu.model`).all(s.id),r=Tr(n),o=t.prepare(`SELECT COALESCE(SUM(total_input_tokens), 0) AS input_tokens,
1310
1310
  COALESCE(SUM(total_output_tokens), 0) AS output_tokens,
1311
1311
  COALESCE(SUM(total_cache_create_tokens), 0) AS cache_create_tokens,
1312
1312
  COALESCE(SUM(total_cache_read_tokens), 0) AS cache_read_tokens,
1313
1313
  COUNT(*) AS session_count
1314
- FROM sessions WHERE project_id = ?`).get(s.id),i=Ae({inputTokens:o.input_tokens,outputTokens:o.output_tokens,cacheCreateTokens:o.cache_create_tokens,cacheReadTokens:o.cache_read_tokens,...fr(r)},null),l=t.prepare(`SELECT s.id, sa.alias, s.started_at,
1314
+ FROM sessions WHERE project_id = ?`).get(s.id),i=Ie({inputTokens:o.input_tokens,outputTokens:o.output_tokens,cacheCreateTokens:o.cache_create_tokens,cacheReadTokens:o.cache_read_tokens,...wr(r)},null),l=t.prepare(`SELECT s.id, sa.alias, s.started_at,
1315
1315
  s.total_input_tokens, s.total_output_tokens,
1316
1316
  s.total_cache_create_tokens, s.total_cache_read_tokens,
1317
1317
  s.primary_model
@@ -1322,7 +1322,7 @@ Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u271
1322
1322
  + COALESCE(s.total_output_tokens,0)
1323
1323
  + COALESCE(s.total_cache_create_tokens,0)
1324
1324
  + COALESCE(s.total_cache_read_tokens,0)) DESC
1325
- LIMIT 10`).all(s.id).map(c=>{let u=Ae({inputTokens:c.total_input_tokens??0,outputTokens:c.total_output_tokens??0,cacheCreateTokens:c.total_cache_create_tokens??0,cacheReadTokens:c.total_cache_read_tokens??0},c.primary_model);return{sessionId:c.id,alias:c.alias,startedAt:c.started_at,totalTokens:u.totalTokens,cost:u}});return{project:s.name,sessionCount:o.session_count,inputTokens:o.input_tokens,outputTokens:o.output_tokens,cacheCreateTokens:o.cache_create_tokens,cacheReadTokens:o.cache_read_tokens,totalTokens:i.totalTokens,cost:i,byModel:r,topSessions:l,display:{dollars:se(i.cents),tokens:le(i.totalTokens)}}}function bc(e="all"){let t=_(),s=e==="7d"?new Date(Date.now()-7*864e5).toISOString():e==="30d"?new Date(Date.now()-30*864e5).toISOString():null,n=s?"WHERE mu.timestamp >= @since OR (mu.timestamp IS NULL AND s.started_at >= @since)":"",r=s?"WHERE m.timestamp >= @since OR (m.timestamp IS NULL AND s2.started_at >= @since)":"",o=s?{since:s}:{},i=y=>s?t.prepare(y).get(o):t.prepare(y).get(),a=y=>s?t.prepare(y).all(o):t.prepare(y).all(),l=a(`SELECT mu.model,
1325
+ LIMIT 10`).all(s.id).map(c=>{let u=Ie({inputTokens:c.total_input_tokens??0,outputTokens:c.total_output_tokens??0,cacheCreateTokens:c.total_cache_create_tokens??0,cacheReadTokens:c.total_cache_read_tokens??0},c.primary_model);return{sessionId:c.id,alias:c.alias,startedAt:c.started_at,totalTokens:u.totalTokens,cost:u}});return{project:s.name,sessionCount:o.session_count,inputTokens:o.input_tokens,outputTokens:o.output_tokens,cacheCreateTokens:o.cache_create_tokens,cacheReadTokens:o.cache_read_tokens,totalTokens:i.totalTokens,cost:i,byModel:r,topSessions:l,display:{dollars:se(i.cents),tokens:le(i.totalTokens)}}}function Ic(e="all"){let t=_(),s=e==="7d"?new Date(Date.now()-7*864e5).toISOString():e==="30d"?new Date(Date.now()-30*864e5).toISOString():null,n=s?"WHERE mu.timestamp >= @since OR (mu.timestamp IS NULL AND s.started_at >= @since)":"",r=s?"WHERE m.timestamp >= @since OR (m.timestamp IS NULL AND s2.started_at >= @since)":"",o=s?{since:s}:{},i=y=>s?t.prepare(y).get(o):t.prepare(y).get(),a=y=>s?t.prepare(y).all(o):t.prepare(y).all(),l=a(`SELECT mu.model,
1326
1326
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
1327
1327
  COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
1328
1328
  COALESCE(SUM(mu.cache_create_tokens), 0) AS cache_create_tokens,
@@ -1331,7 +1331,7 @@ Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u271
1331
1331
  FROM message_usage mu
1332
1332
  JOIN sessions s ON s.id = mu.session_id
1333
1333
  ${n}
1334
- GROUP BY mu.model`),c=gr(l),u=0,p=0,m=0,f=0;for(let y of c)u+=y.inputTokens,p+=y.outputTokens,m+=y.cacheCreateTokens,f+=y.cacheReadTokens;let g=Ae({inputTokens:u,outputTokens:p,cacheCreateTokens:m,cacheReadTokens:f,...fr(c)},null),h=s?i(`SELECT
1334
+ GROUP BY mu.model`),c=Tr(l),u=0,m=0,p=0,f=0;for(let y of c)u+=y.inputTokens,m+=y.outputTokens,p+=y.cacheCreateTokens,f+=y.cacheReadTokens;let g=Ie({inputTokens:u,outputTokens:m,cacheCreateTokens:p,cacheReadTokens:f,...wr(c)},null),h=s?i(`SELECT
1335
1335
  (SELECT COUNT(DISTINCT m.session_id)
1336
1336
  FROM messages m
1337
1337
  JOIN sessions s2 ON s2.id = m.session_id
@@ -1355,7 +1355,7 @@ Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u271
1355
1355
  JOIN sessions s ON s.id = mu.session_id
1356
1356
  ${n}
1357
1357
  GROUP BY day, mu.model
1358
- ORDER BY day ASC`),b=new Map;for(let y of E){if(!y.day)continue;let U=Ae({inputTokens:y.input_tokens,outputTokens:y.output_tokens,cacheCreateTokens:y.cache_create_tokens,cacheReadTokens:y.cache_read_tokens},y.model),v=b.get(y.day)??{tokens:0,cents:0};v.tokens+=U.totalTokens,v.cents+=U.cents,b.set(y.day,v)}let S=[...b.entries()].map(([y,U])=>({day:y,tokens:U.tokens,cents:U.cents})).sort((y,U)=>y.day.localeCompare(U.day)),x=a(`SELECT s.id, p.name AS project, sa.alias, s.started_at,
1358
+ ORDER BY day ASC`),b=new Map;for(let y of E){if(!y.day)continue;let U=Ie({inputTokens:y.input_tokens,outputTokens:y.output_tokens,cacheCreateTokens:y.cache_create_tokens,cacheReadTokens:y.cache_read_tokens},y.model),M=b.get(y.day)??{tokens:0,cents:0};M.tokens+=U.totalTokens,M.cents+=U.cents,b.set(y.day,M)}let S=[...b.entries()].map(([y,U])=>({day:y,tokens:U.tokens,cents:U.cents})).sort((y,U)=>y.day.localeCompare(U.day)),x=a(`SELECT s.id, p.name AS project, sa.alias, s.started_at,
1359
1359
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
1360
1360
  COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
1361
1361
  COALESCE(SUM(mu.cache_create_tokens), 0) AS cache_create_tokens,
@@ -1371,7 +1371,7 @@ Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u271
1371
1371
  + COALESCE(SUM(mu.output_tokens),0)
1372
1372
  + COALESCE(SUM(mu.cache_create_tokens),0)
1373
1373
  + COALESCE(SUM(mu.cache_read_tokens),0)) DESC
1374
- LIMIT 10`).map(y=>{let U=Ae({inputTokens:y.input_tokens,outputTokens:y.output_tokens,cacheCreateTokens:y.cache_create_tokens,cacheReadTokens:y.cache_read_tokens},y.primary_model);return{sessionId:y.id,project:y.project,alias:y.alias,startedAt:y.started_at,totalTokens:U.totalTokens,cost:U}}),L=a(`SELECT p.id AS project_id,
1374
+ LIMIT 10`).map(y=>{let U=Ie({inputTokens:y.input_tokens,outputTokens:y.output_tokens,cacheCreateTokens:y.cache_create_tokens,cacheReadTokens:y.cache_read_tokens},y.primary_model);return{sessionId:y.id,project:y.project,alias:y.alias,startedAt:y.started_at,totalTokens:U.totalTokens,cost:U}}),L=a(`SELECT p.id AS project_id,
1375
1375
  p.name AS project,
1376
1376
  mu.model,
1377
1377
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
@@ -1383,16 +1383,16 @@ Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u271
1383
1383
  JOIN sessions s ON s.id = mu.session_id
1384
1384
  LEFT JOIN projects p ON p.id = s.project_id
1385
1385
  ${n}
1386
- GROUP BY p.id, mu.model`),Q=new Map;for(let y of L){let U=y.project_id??"__none__",v=Q.get(U);v||(v={project:y.project??"(no project)",sessionIds:new Set,sessionsApprox:0,byModel:{}},Q.set(U,v)),y.sessions>v.sessionsApprox&&(v.sessionsApprox=y.sessions),v.byModel[y.model??"__unknown__"]={inputTokens:y.input_tokens,outputTokens:y.output_tokens,cacheCreateTokens:y.cache_create_tokens,cacheReadTokens:y.cache_read_tokens}}let I=[...Q.values()].map(y=>{let U=0,v=0,K=0,Ue=0;for(let dt of Object.values(y.byModel))U+=dt.inputTokens,v+=dt.outputTokens,K+=dt.cacheCreateTokens,Ue+=dt.cacheReadTokens;let $e=Ae({inputTokens:U,outputTokens:v,cacheCreateTokens:K,cacheReadTokens:Ue,byModel:y.byModel},null);return{project:y.project,sessions:y.sessionsApprox,totalTokens:$e.totalTokens,cost:$e}});I.sort((y,U)=>U.totalTokens-y.totalTokens);let ee=I.slice(0,20),B=t.prepare(`SELECT
1386
+ GROUP BY p.id, mu.model`),Q=new Map;for(let y of L){let U=y.project_id??"__none__",M=Q.get(U);M||(M={project:y.project??"(no project)",sessionIds:new Set,sessionsApprox:0,byModel:{}},Q.set(U,M)),y.sessions>M.sessionsApprox&&(M.sessionsApprox=y.sessions),M.byModel[y.model??"__unknown__"]={inputTokens:y.input_tokens,outputTokens:y.output_tokens,cacheCreateTokens:y.cache_create_tokens,cacheReadTokens:y.cache_read_tokens}}let v=[...Q.values()].map(y=>{let U=0,M=0,K=0,Be=0;for(let ut of Object.values(y.byModel))U+=ut.inputTokens,M+=ut.outputTokens,K+=ut.cacheCreateTokens,Be+=ut.cacheReadTokens;let je=Ie({inputTokens:U,outputTokens:M,cacheCreateTokens:K,cacheReadTokens:Be,byModel:y.byModel},null);return{project:y.project,sessions:y.sessionsApprox,totalTokens:je.totalTokens,cost:je}});v.sort((y,U)=>U.totalTokens-y.totalTokens);let ee=v.slice(0,20),B=t.prepare(`SELECT
1387
1387
  (SELECT COUNT(*) FROM messages WHERE role='assistant') AS assistant_messages,
1388
- (SELECT COUNT(*) FROM message_usage) AS messages_with_usage`).get();return{range:e,totalSessions:h.total_sessions,sessionsWithUsage:h.sessions_with_usage,inputTokens:u,outputTokens:p,cacheCreateTokens:m,cacheReadTokens:f,totalTokens:g.totalTokens,cost:g,daily:S,byModel:c,topSessions:x,topRepos:ee,backfill:{assistantMessages:B.assistant_messages,messagesWithUsage:B.messages_with_usage,pending:Math.max(0,B.assistant_messages-B.messages_with_usage),unrecoverable:Math.min(fc(),Math.max(0,B.assistant_messages-B.messages_with_usage))},display:{dollars:se(g.cents),tokens:le(g.totalTokens)}}}var Ge=e=>e.toLocaleString();function Jh(e){return _().prepare("SELECT id FROM sessions WHERE id = ? OR id LIKE ? LIMIT 1").get(e,`${e}%`)?.id??null}async function Sc(e,t){if(t.backfill){let r=t.limit?Math.max(1,Number(t.limit)):void 0;console.log(d.dim("backfilling per-message usage from raw_json\u2026"));let o=_c({limit:r});if(console.log(`${d.ok("backfill done")}: scanned ${d.bold(String(o.scanned))}, inserted ${d.bold(String(o.inserted))}, rolled-up ${d.bold(String(o.sessionsTouched))} sessions`),!e&&!t.project)return}if(e){let r=Jh(e);if(!r){console.error(d.err(`no session matches '${e}'`)),process.exit(1);return}let o=hc(r);if(!o){console.error(d.err("session has no usage data yet \u2014 try --backfill")),process.exit(1);return}if(t.json){console.log(JSON.stringify(o,null,2));return}if(console.log(""),console.log(d.bold("session cost")),console.log(d.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` id ${d.dim(o.sessionId)}`),console.log(` project ${d.accent(o.project??"\u2014")}`),console.log(` started ${d.dim(o.startedAt??"n/a")}`),console.log(` messages ${d.accent(Ge(o.messageCount))}`),console.log(` model ${d.accent(o.primaryModelLabel)} ${d.dim(o.primaryModel??"")}`),console.log(""),console.log(` input ${Ge(o.inputTokens).padStart(12)}`),console.log(` output ${Ge(o.outputTokens).padStart(12)}`),console.log(` cache write ${Ge(o.cacheCreateTokens).padStart(12)}`),console.log(` cache read ${Ge(o.cacheReadTokens).padStart(12)}`),console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),console.log(` total tokens ${d.bold(Ge(o.totalTokens).padStart(12))}`),console.log(` estimated cost ${d.accent(se(o.cost.cents).padStart(12))}`),o.byModel.length>1){console.log(""),console.log(d.dim(" by model:"));for(let i of o.byModel)console.log(` ${i.modelLabel.padEnd(14)} ${le(i.inputTokens+i.outputTokens+i.cacheCreateTokens+i.cacheReadTokens).padStart(10)} ${d.accent(se(i.cost.cents).padStart(10))}`)}console.log("");return}if(t.project){let r=Ec(t.project);if(!r){console.error(d.err(`project '${t.project}' not found`)),process.exit(1);return}if(t.json){console.log(JSON.stringify(r,null,2));return}if(console.log(""),console.log(d.bold(`project \xB7 ${r.project}`)),console.log(d.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` sessions ${d.accent(Ge(r.sessionCount))}`),console.log(` total tokens ${d.accent(le(r.totalTokens).padStart(12))}`),console.log(` estimated cost ${d.accent(se(r.cost.cents).padStart(12))}`),r.byModel.length>0){console.log(""),console.log(d.dim(" by model:"));for(let o of r.byModel)console.log(` ${o.modelLabel.padEnd(14)} ${le(o.inputTokens+o.outputTokens+o.cacheCreateTokens+o.cacheReadTokens).padStart(10)} ${d.accent(se(o.cost.cents).padStart(10))}`)}if(r.topSessions.length>0){console.log(""),console.log(d.dim(" top sessions:"));for(let o of r.topSessions){let i=o.alias??o.sessionId.slice(0,8);console.log(` ${i.padEnd(22)} ${le(o.totalTokens).padStart(10)} ${d.accent(se(o.cost.cents).padStart(10))}`)}}console.log("");return}let s=t.days==="7"?"7d":t.days==="30"?"30d":"all",n=bc(s);if(t.json){console.log(JSON.stringify(n,null,2));return}if(console.log(""),console.log(d.bold(`overview \xB7 ${s}`)),console.log(d.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` sessions ${d.accent(Ge(n.totalSessions))} ${d.dim(`(${n.sessionsWithUsage} w/ usage)`)}`),console.log(` total tokens ${d.accent(le(n.totalTokens).padStart(12))}`),console.log(` estimated cost ${d.accent(se(n.cost.cents).padStart(12))}`),n.backfill.pending>0&&console.log(d.dim(` (${Ge(n.backfill.pending)} assistant messages pending \u2014 run \`recall stats --backfill\`)`)),n.byModel.length>0){console.log(""),console.log(d.dim(" by model:"));for(let r of n.byModel)console.log(` ${r.modelLabel.padEnd(14)} ${le(r.inputTokens+r.outputTokens+r.cacheCreateTokens+r.cacheReadTokens).padStart(10)} ${d.accent(se(r.cost.cents).padStart(10))}`)}if(n.topSessions.length>0){console.log(""),console.log(d.dim(" top sessions:"));for(let r of n.topSessions){let o=r.alias??r.sessionId.slice(0,8);console.log(` ${o.padEnd(22)} ${(r.project??"").slice(0,20).padEnd(22)} ${le(r.totalTokens).padStart(10)} ${d.accent(se(r.cost.cents).padStart(10))}`)}}console.log("")}M();T();T();import{execFile as Gh}from"node:child_process";import{promisify as zh}from"node:util";import{stat as Yh}from"node:fs/promises";var yc=zh(Gh),Tc=1e4,Kh="%H%x09%aI%x09%s";async function qh(e){try{let{stdout:t}=await yc("git",["rev-parse","--is-inside-work-tree"],{cwd:e,timeout:Tc});return t.trim()==="true"}catch{return!1}}async function Vh(e,t,s){let n=["--no-pager","log","--all","--no-color","--since",t,"--until",s,`--pretty=format:${Kh}`],{stdout:r}=await yc("git",n,{cwd:e,timeout:Tc,maxBuffer:8*1024*1024}),o=[],i=new Set;for(let a of r.split(`
1389
- `)){if(!a)continue;let[l,c,...u]=a.split(" ");!l||i.has(l)||(i.add(l),o.push({commit_sha:l,committed_at:c??null,subject:u.join(" ")||null}))}return o}function Zh(e){return _().prepare(`SELECT id, cwd, started_at, ended_at
1390
- FROM sessions WHERE id = ?`).get(e)??null}function Qh(e,t,s){if(s.length===0)return 0;let n=_(),r=new Date().toISOString(),o=n.prepare(`INSERT OR IGNORE INTO session_commits
1388
+ (SELECT COUNT(*) FROM message_usage) AS messages_with_usage`).get();return{range:e,totalSessions:h.total_sessions,sessionsWithUsage:h.sessions_with_usage,inputTokens:u,outputTokens:m,cacheCreateTokens:p,cacheReadTokens:f,totalTokens:g.totalTokens,cost:g,daily:S,byModel:c,topSessions:x,topRepos:ee,backfill:{assistantMessages:B.assistant_messages,messagesWithUsage:B.messages_with_usage,pending:Math.max(0,B.assistant_messages-B.messages_with_usage),unrecoverable:Math.min(Cc(),Math.max(0,B.assistant_messages-B.messages_with_usage))},display:{dollars:se(g.cents),tokens:le(g.totalTokens)}}}var ze=e=>e.toLocaleString();function _E(e){return _().prepare("SELECT id FROM sessions WHERE id = ? OR id LIKE ? LIMIT 1").get(e,`${e}%`)?.id??null}async function vc(e,t){if(t.backfill){let r=t.limit?Math.max(1,Number(t.limit)):void 0;console.log(d.dim("backfilling per-message usage from raw_json\u2026"));let o=Lc({limit:r});if(console.log(`${d.ok("backfill done")}: scanned ${d.bold(String(o.scanned))}, inserted ${d.bold(String(o.inserted))}, rolled-up ${d.bold(String(o.sessionsTouched))} sessions`),!e&&!t.project)return}if(e){let r=_E(e);if(!r){console.error(d.err(`no session matches '${e}'`)),process.exit(1);return}let o=Oc(r);if(!o){console.error(d.err("session has no usage data yet \u2014 try --backfill")),process.exit(1);return}if(t.json){console.log(JSON.stringify(o,null,2));return}if(console.log(""),console.log(d.bold("session cost")),console.log(d.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` id ${d.dim(o.sessionId)}`),console.log(` project ${d.accent(o.project??"\u2014")}`),console.log(` started ${d.dim(o.startedAt??"n/a")}`),console.log(` messages ${d.accent(ze(o.messageCount))}`),console.log(` model ${d.accent(o.primaryModelLabel)} ${d.dim(o.primaryModel??"")}`),console.log(""),console.log(` input ${ze(o.inputTokens).padStart(12)}`),console.log(` output ${ze(o.outputTokens).padStart(12)}`),console.log(` cache write ${ze(o.cacheCreateTokens).padStart(12)}`),console.log(` cache read ${ze(o.cacheReadTokens).padStart(12)}`),console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),console.log(` total tokens ${d.bold(ze(o.totalTokens).padStart(12))}`),console.log(` estimated cost ${d.accent(se(o.cost.cents).padStart(12))}`),o.byModel.length>1){console.log(""),console.log(d.dim(" by model:"));for(let i of o.byModel)console.log(` ${i.modelLabel.padEnd(14)} ${le(i.inputTokens+i.outputTokens+i.cacheCreateTokens+i.cacheReadTokens).padStart(10)} ${d.accent(se(i.cost.cents).padStart(10))}`)}console.log("");return}if(t.project){let r=Ac(t.project);if(!r){console.error(d.err(`project '${t.project}' not found`)),process.exit(1);return}if(t.json){console.log(JSON.stringify(r,null,2));return}if(console.log(""),console.log(d.bold(`project \xB7 ${r.project}`)),console.log(d.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` sessions ${d.accent(ze(r.sessionCount))}`),console.log(` total tokens ${d.accent(le(r.totalTokens).padStart(12))}`),console.log(` estimated cost ${d.accent(se(r.cost.cents).padStart(12))}`),r.byModel.length>0){console.log(""),console.log(d.dim(" by model:"));for(let o of r.byModel)console.log(` ${o.modelLabel.padEnd(14)} ${le(o.inputTokens+o.outputTokens+o.cacheCreateTokens+o.cacheReadTokens).padStart(10)} ${d.accent(se(o.cost.cents).padStart(10))}`)}if(r.topSessions.length>0){console.log(""),console.log(d.dim(" top sessions:"));for(let o of r.topSessions){let i=o.alias??o.sessionId.slice(0,8);console.log(` ${i.padEnd(22)} ${le(o.totalTokens).padStart(10)} ${d.accent(se(o.cost.cents).padStart(10))}`)}}console.log("");return}let s=t.days==="7"?"7d":t.days==="30"?"30d":"all",n=Ic(s);if(t.json){console.log(JSON.stringify(n,null,2));return}if(console.log(""),console.log(d.bold(`overview \xB7 ${s}`)),console.log(d.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` sessions ${d.accent(ze(n.totalSessions))} ${d.dim(`(${n.sessionsWithUsage} w/ usage)`)}`),console.log(` total tokens ${d.accent(le(n.totalTokens).padStart(12))}`),console.log(` estimated cost ${d.accent(se(n.cost.cents).padStart(12))}`),n.backfill.pending>0&&console.log(d.dim(` (${ze(n.backfill.pending)} assistant messages pending \u2014 run \`recall stats --backfill\`)`)),n.byModel.length>0){console.log(""),console.log(d.dim(" by model:"));for(let r of n.byModel)console.log(` ${r.modelLabel.padEnd(14)} ${le(r.inputTokens+r.outputTokens+r.cacheCreateTokens+r.cacheReadTokens).padStart(10)} ${d.accent(se(r.cost.cents).padStart(10))}`)}if(n.topSessions.length>0){console.log(""),console.log(d.dim(" top sessions:"));for(let r of n.topSessions){let o=r.alias??r.sessionId.slice(0,8);console.log(` ${o.padEnd(22)} ${(r.project??"").slice(0,20).padEnd(22)} ${le(r.totalTokens).padStart(10)} ${d.accent(se(r.cost.cents).padStart(10))}`)}}console.log("")}I();T();T();import{execFile as hE}from"node:child_process";import{promisify as EE}from"node:util";import{stat as bE}from"node:fs/promises";var Mc=EE(hE),Dc=1e4,SE="%H%x09%aI%x09%s";async function yE(e){try{let{stdout:t}=await Mc("git",["rev-parse","--is-inside-work-tree"],{cwd:e,timeout:Dc});return t.trim()==="true"}catch{return!1}}async function TE(e,t,s){let n=["--no-pager","log","--all","--no-color","--since",t,"--until",s,`--pretty=format:${SE}`],{stdout:r}=await Mc("git",n,{cwd:e,timeout:Dc,maxBuffer:8*1024*1024}),o=[],i=new Set;for(let a of r.split(`
1389
+ `)){if(!a)continue;let[l,c,...u]=a.split(" ");!l||i.has(l)||(i.add(l),o.push({commit_sha:l,committed_at:c??null,subject:u.join(" ")||null}))}return o}function wE(e){return _().prepare(`SELECT id, cwd, started_at, ended_at
1390
+ FROM sessions WHERE id = ?`).get(e)??null}function RE(e,t,s){if(s.length===0)return 0;let n=_(),r=new Date().toISOString(),o=n.prepare(`INSERT OR IGNORE INTO session_commits
1391
1391
  (session_id, commit_sha, committed_at, subject, cwd_snapshot, correlated_at)
1392
- VALUES (?, ?, ?, ?, ?, ?)`),i=0;return n.transaction(l=>{for(let c of l)o.run(e,c.commit_sha,c.committed_at,c.subject,t,r).changes>0&&(i+=1)})(s),i}async function _r(e){let t=Zh(e);if(!t)return{sessionId:e,status:"error",commitsFound:0,commitsInserted:0,error:"session not found"};if(!t.cwd)return{sessionId:e,status:"no-cwd",commitsFound:0,commitsInserted:0};if(!t.started_at||!t.ended_at)return{sessionId:e,status:"no-window",commitsFound:0,commitsInserted:0};let s=t.started_at,n=t.ended_at===t.started_at?new Date(Date.parse(t.ended_at)+1e3).toISOString():t.ended_at;try{if(!(await Yh(t.cwd)).isDirectory())return{sessionId:e,status:"cwd-missing",commitsFound:0,commitsInserted:0}}catch{return{sessionId:e,status:"cwd-missing",commitsFound:0,commitsInserted:0}}if(!await qh(t.cwd))return{sessionId:e,status:"not-a-repo",commitsFound:0,commitsInserted:0};try{let o=await Vh(t.cwd,s,n),i=Qh(e,t.cwd,o);return{sessionId:e,status:"ok",commitsFound:o.length,commitsInserted:i}}catch(o){return{sessionId:e,status:"error",commitsFound:0,commitsInserted:0,error:o.message}}}async function wc(e={}){let t=_(),s=Math.max(1,Math.min(1e5,e.limit??1e4)),n=t.prepare(`SELECT id FROM sessions
1392
+ VALUES (?, ?, ?, ?, ?, ?)`),i=0;return n.transaction(l=>{for(let c of l)o.run(e,c.commit_sha,c.committed_at,c.subject,t,r).changes>0&&(i+=1)})(s),i}async function Rr(e){let t=wE(e);if(!t)return{sessionId:e,status:"error",commitsFound:0,commitsInserted:0,error:"session not found"};if(!t.cwd)return{sessionId:e,status:"no-cwd",commitsFound:0,commitsInserted:0};if(!t.started_at||!t.ended_at)return{sessionId:e,status:"no-window",commitsFound:0,commitsInserted:0};let s=t.started_at,n=t.ended_at===t.started_at?new Date(Date.parse(t.ended_at)+1e3).toISOString():t.ended_at;try{if(!(await bE(t.cwd)).isDirectory())return{sessionId:e,status:"cwd-missing",commitsFound:0,commitsInserted:0}}catch{return{sessionId:e,status:"cwd-missing",commitsFound:0,commitsInserted:0}}if(!await yE(t.cwd))return{sessionId:e,status:"not-a-repo",commitsFound:0,commitsInserted:0};try{let o=await TE(t.cwd,s,n),i=RE(e,t.cwd,o);return{sessionId:e,status:"ok",commitsFound:o.length,commitsInserted:i}}catch(o){return{sessionId:e,status:"error",commitsFound:0,commitsInserted:0,error:o.message}}}async function $c(e={}){let t=_(),s=Math.max(1,Math.min(1e5,e.limit??1e4)),n=t.prepare(`SELECT id FROM sessions
1393
1393
  WHERE cwd IS NOT NULL AND started_at IS NOT NULL AND ended_at IS NOT NULL
1394
1394
  ORDER BY COALESCE(ended_at, started_at) DESC
1395
- LIMIT ?`).all(s),r={total:n.length,ok:0,skipped:0,errors:0,commitsInserted:0,results:[]},o=0;for(let i of n){let a=await _r(i.id);r.results.push(a),a.status==="ok"?(r.ok+=1,r.commitsInserted+=a.commitsInserted):a.status==="error"?r.errors+=1:r.skipped+=1,o+=1,e.onProgress?.(o,n.length)}return r}function $s(e){let t=_(),s=e.trim();if(!/^[0-9a-fA-F]{4,40}$/.test(s))return[];let n=`${s.toLowerCase()}%`;return t.prepare(`SELECT sc.session_id AS sessionId,
1395
+ LIMIT ?`).all(s),r={total:n.length,ok:0,skipped:0,errors:0,commitsInserted:0,results:[]},o=0;for(let i of n){let a=await Rr(i.id);r.results.push(a),a.status==="ok"?(r.ok+=1,r.commitsInserted+=a.commitsInserted):a.status==="error"?r.errors+=1:r.skipped+=1,o+=1,e.onProgress?.(o,n.length)}return r}function Bs(e){let t=_(),s=e.trim();if(!/^[0-9a-fA-F]{4,40}$/.test(s))return[];let n=`${s.toLowerCase()}%`;return t.prepare(`SELECT sc.session_id AS sessionId,
1396
1396
  NULLIF(sa.alias, '') AS alias,
1397
1397
  p.name AS project,
1398
1398
  s.started_at AS startedAt,
@@ -1406,65 +1406,65 @@ Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u271
1406
1406
  LEFT JOIN session_aliases sa ON sa.session_id = sc.session_id
1407
1407
  WHERE lower(sc.commit_sha) = lower(?)
1408
1408
  OR lower(sc.commit_sha) LIKE ?
1409
- ORDER BY COALESCE(sc.committed_at, s.started_at, '') DESC`).all(s,n)}function eE(e){return _().prepare("SELECT id FROM sessions WHERE id = ? OR id LIKE ? LIMIT 1").get(e,`${e}%`)?.id??null}function tE(e){let t=e.sessionId.slice(0,8);switch(e.status){case"ok":console.log(`${d.ok("\u2713")} ${d.dim(t)} ${d.bold(String(e.commitsFound))} commits (${e.commitsInserted} new)`);break;case"no-cwd":console.log(`${d.dim("\xB7")} ${d.dim(t)} no cwd recorded \u2014 skipped`);break;case"not-a-repo":console.log(`${d.dim("\xB7")} ${d.dim(t)} cwd is not a git worktree \u2014 skipped`);break;case"cwd-missing":console.log(`${d.dim("\xB7")} ${d.dim(t)} cwd no longer exists on disk \u2014 skipped`);break;case"no-window":console.log(`${d.dim("\xB7")} ${d.dim(t)} session has no time window yet \u2014 skipped`);break;case"error":console.log(`${d.err("\u2717")} ${d.dim(t)} ${e.error??"unknown error"}`);break}}async function Rc(e,t){if(e){let r=eE(e);if(!r){console.error(d.err(`no session matches '${e}'`)),process.exit(1);return}let o=await _r(r);if(t.json){console.log(JSON.stringify(o,null,2));return}tE(o);return}let s=t.limit?Math.max(1,Number(t.limit)):void 0;console.log(d.dim(`correlating sessions to git commits (limit ${s??"default"})\u2026`));let n=await wc({limit:s,onProgress:(r,o)=>{(r%25===0||r===o)&&process.stderr.write(`\r${d.dim(` ${r}/${o}`)}`)}});if(process.stderr.write(`
1410
- `),t.json){console.log(JSON.stringify(n,null,2));return}console.log(""),console.log(`${d.ok("correlated")}: ${d.bold(String(n.ok))} sessions \xB7 ${d.bold(String(n.commitsInserted))} new commits`),console.log(d.dim(` skipped ${n.skipped} (no cwd / non-repo / cwd missing), errors ${n.errors}`)),console.log("")}M();T();Dt();import{existsSync as Sr,readFileSync as yr}from"node:fs";j();import{existsSync as sE,readFileSync as nE,writeFileSync as rE}from"node:fs";import{join as oE}from"node:path";import{z as de}from"zod";var hr=oE(R,"terminals.json"),xc=1440*60*1e3,iE=3e4,aE=6e4,cE=de.object({shell_pid:de.number(),tab_name:de.string(),cwd:de.string().nullable().optional(),opened_at:de.string(),last_seen_at:de.string()}),lE=de.object({schema:de.string().optional(),saved_at:de.string().optional(),terminals:de.array(cE).max(500).default([]),sessions_by_pid:de.record(de.string(),de.array(de.string()).max(50)).optional().default({})}),Cc=/^[⠀-⣿✳\s]+/,Nc=/^\d+(\.\d+){1,3}$/;function kc(e){let t=e.trim();return!!(!t||Cc.test(t)||Nc.test(t))}function dE(e){let t=e.trim();if(!t||Nc.test(t))return null;let s=t.replace(Cc,"").trim();return s.length>0?s:null}function Er(e,t){if(!kc(e))return e;let s=dE(e);return s||(t&&!kc(t)?t:e)}function uE(e){let t=e.now-e.withinMs,s=e.pending.filter(n=>{let r=Date.parse(n.started_at);return Number.isFinite(r)&&r>=t});if(s.length===0)return{kind:"none"};if(e.shellPid!=null){let n=s.find(r=>r.shell_pid===e.shellPid);if(n)return{kind:"pid-match",entry:n}}if(e.cwd){let n=e.cwd.replace(/\/+$/,""),r=s.filter(o=>o.cwd&&o.cwd.replace(/\/+$/,"")===n);if(r.length===1)return{kind:"singleton-cwd",entry:r[0]};if(r.length>=2)return{kind:"ambiguous",candidates:r}}return{kind:"none"}}var br=class{entries=new Map;origins=new Map;sessionsByPid=new Map;pendingClaudeStarts=[];deferredLinks=new Map;pidOwnership=new Map;loaded=!1;ensureLoaded(){if(!this.loaded&&(this.loaded=!0,!!sE(hr)))try{let t=nE(hr,"utf8"),s=JSON.parse(t),n=lE.safeParse(s);if(!n.success){console.warn("[terminal-registry] terminals.json failed validation, starting with empty registry:",n.error.issues);return}let r=n.data;for(let o of r.terminals)this.entries.set(o.shell_pid,{shell_pid:o.shell_pid,tab_name:o.tab_name,cwd:o.cwd??null,opened_at:o.opened_at,last_seen_at:o.last_seen_at});for(let[o,i]of Object.entries(r.sessions_by_pid??{})){let a=Number(o);if(!Number.isFinite(a))continue;let l=new Set;for(let c of i)c.length>0&&l.add(c);l.size>0&&this.sessionsByPid.set(a,l)}this.gc()}catch{}}save(){try{P();let t={schema:"claude-recall.terminals.v1",saved_at:new Date().toISOString(),terminals:Array.from(this.entries.values()),sessions_by_pid:Object.fromEntries(Array.from(this.sessionsByPid.entries()).map(([s,n])=>[String(s),Array.from(n)]))};rE(hr,JSON.stringify(t,null,2))}catch{}}upsert(t){this.ensureLoaded();let s=new Date().toISOString(),n=this.entries.get(t.shell_pid),r=Er(t.tab_name,n?.tab_name),o=n?.opened_at??t.opened_at,i={...t,tab_name:r,opened_at:o,last_seen_at:s};return this.entries.set(t.shell_pid,i),this.gc(),this.save(),i}rename(t,s){this.ensureLoaded();let n=this.entries.get(t);if(!n)return null;let r=Er(s,n.tab_name),o={...n,tab_name:r,last_seen_at:new Date().toISOString()};return this.entries.set(t,o),this.save(),o}remove(t){this.ensureLoaded();let s=this.entries.delete(t),n=this.sessionsByPid.delete(t);return this.outputTails.delete(t),this.pidOwnership.delete(t),(s||n)&&this.save(),s}claimPidOwnership(t,s,n=Date.now()){if(this.ensureLoaded(),!s)return"anonymous";let r=this.pidOwnership.get(t);return r?r.instance_id===s?(r.last_claim_at=n,"refreshed"):n-r.last_claim_at>aE?(this.pidOwnership.set(t,{instance_id:s,last_claim_at:n}),"claimed"):"rejected":(this.pidOwnership.set(t,{instance_id:s,last_claim_at:n}),"claimed")}pidOwnershipSnapshot(){return this.ensureLoaded(),Array.from(this.pidOwnership.entries()).map(([t,s])=>({shell_pid:t,instance_id:s.instance_id,last_claim_at:s.last_claim_at}))}sync(t){this.ensureLoaded();let s=new Date().toISOString(),n=0,r=0;for(let o of t){let i=this.entries.get(o.shell_pid),a=Er(o.tab_name,i?.tab_name),l=i?.opened_at??o.opened_at;this.entries.set(o.shell_pid,{...o,tab_name:a,opened_at:l,last_seen_at:s}),i?(i.tab_name!==a||i.cwd!==o.cwd)&&r++:n++}return this.gc(),this.save(),{added:n,updated:r,removed:0}}get(t){return this.ensureLoaded(),this.entries.get(t)??null}all(){return this.ensureLoaded(),this.gc(),Array.from(this.entries.values())}size(){return this.ensureLoaded(),this.entries.size}linkSession(t,s){this.ensureLoaded();let n=this.sessionsByPid.get(s);n||(n=new Set,this.sessionsByPid.set(s,n)),n.has(t)||(n.add(t),this.save())}sessionsFor(t){return this.ensureLoaded(),Array.from(this.sessionsByPid.get(t)??[])}isSessionAutoLinked(t){this.ensureLoaded();for(let s of this.sessionsByPid.values())if(s.has(t))return!0;return!1}unlinkSession(t){this.ensureLoaded();let s=!1;for(let[n,r]of this.sessionsByPid)r.delete(t)&&(s=!0,r.size===0&&this.sessionsByPid.delete(n));return s&&this.save(),s}pushPending(t){this.ensureLoaded(),this.gcPending(),this.pendingClaudeStarts.push({...t})}takePendingMatched(t){this.ensureLoaded(),this.gcPending();let s=uE({pending:this.pendingClaudeStarts,shellPid:t.shellPid,cwd:t.cwd,withinMs:t.withinMs,now:Date.now()});if(s.kind==="pid-match"||s.kind==="singleton-cwd"){let n=this.pendingClaudeStarts.indexOf(s.entry);n>=0&&this.pendingClaudeStarts.splice(n,1)}return s}pendingSize(){return this.ensureLoaded(),this.gcPending(),this.pendingClaudeStarts.length}deferSessionLink(t,s,n,r){this.ensureLoaded(),this.gcDeferredLinks(),this.deferredLinks.set(t,{parent_shell_pid:s,queued_at:Date.now(),cwd:n,git_branch:r})}allDeferredLinks(){return this.ensureLoaded(),this.gcDeferredLinks(),Array.from(this.deferredLinks.entries()).map(([t,s])=>({session_id:t,...s}))}resolveDeferredLink(t){return this.deferredLinks.delete(t)}deferredLinkSize(){return this.ensureLoaded(),this.gcDeferredLinks(),this.deferredLinks.size}gcDeferredLinks(){let t=Date.now()-9e4;for(let[s,n]of this.deferredLinks)n.queued_at<t&&this.deferredLinks.delete(s)}gcPending(){let t=Date.now()-iE;this.pendingClaudeStarts.length!==0&&(this.pendingClaudeStarts=this.pendingClaudeStarts.filter(s=>{let n=Date.parse(s.started_at);return Number.isFinite(n)&&n>=t}))}outputTails=new Map;setOutputTail(t,s,n){this.ensureLoaded(),this.outputTails.set(t,{text:s,captured_at:n})}getOutputTail(t){return this.ensureLoaded(),this.outputTails.get(t)??null}allOutputTails(){return this.ensureLoaded(),new Map(this.outputTails)}removeOutputTail(t){return this.outputTails.delete(t)}setOrigin(t,s){this.ensureLoaded(),this.origins.set(t,s),this.gcOrigins()}getOrigin(t){return this.ensureLoaded(),this.origins.get(t)??null}removeOrigin(t){return this.ensureLoaded(),this.origins.delete(t)}allOrigins(){return this.ensureLoaded(),this.gcOrigins(),new Map(this.origins)}originSize(){return this.ensureLoaded(),this.origins.size}gc(){let t=Date.now()-xc;for(let[s,n]of this.entries){let r=Date.parse(n.last_seen_at);!Number.isNaN(r)&&r<t&&this.entries.delete(s)}}gcOrigins(){let t=Date.now()-xc;for(let[s,n]of this.origins)n.detectedAt<t&&this.origins.delete(s)}reapStaleLinks(t=10080*60*1e3){this.ensureLoaded();let n=Date.now()-t,r=0,o=0;for(let[i,a]of this.sessionsByPid){let l=this.entries.get(i);if(l){let c=Date.parse(l.last_seen_at);if(Number.isFinite(c)&&c>=n)continue}o+=a.size,this.sessionsByPid.delete(i),l&&(this.entries.delete(i),r++)}return(r||o)&&this.save(),{pruned_pids:r,pruned_sessions:o}}gcDeadPids(){this.ensureLoaded();let t=0,s=0;for(let n of[...this.entries.keys()]){let r=!0;try{process.kill(n,0)}catch(i){i.code==="ESRCH"&&(r=!1)}if(r)continue;this.entries.delete(n),t++;let o=this.sessionsByPid.get(n);o&&(s+=o.size,this.sessionsByPid.delete(n)),this.outputTails.delete(n),this.pidOwnership.delete(n)}return(t||s)&&this.save(),{pruned_pids:t,pruned_sessions:s}}},Lc=new br;On();function Oc(e){let t=Zo(),s={...e};return t&&(s["x-recall-token"]=t),s}async function ft(e,t){let s=t?.headers??{};return fetch(e,{...t,headers:Oc(s)})}async function et(e,t,s,n){let r=s!==void 0?{"content-type":"application/json",...n}:{...n};return fetch(t,{method:e,headers:Oc(r),body:s!==void 0?JSON.stringify(s):void 0})}j();function mE(){let e=`${R}/daemon.port`;if(!Sr(e))return null;try{let t=yr(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function gE(e,t){try{return(await et("POST",`http://127.0.0.1:${e}/api/sessions/${encodeURIComponent(t)}/relink`,{clear:!0})).ok}catch{return!1}}function fE(e,t){let s=_(),n=t?" AND p.name = ?":"",r=t?[t]:[],o=s.prepare(`SELECT s.id, p.name AS project_name, s.cwd, s.started_at, sa.alias
1409
+ ORDER BY COALESCE(sc.committed_at, s.started_at, '') DESC`).all(s,n)}function xE(e){return _().prepare("SELECT id FROM sessions WHERE id = ? OR id LIKE ? LIMIT 1").get(e,`${e}%`)?.id??null}function kE(e){let t=e.sessionId.slice(0,8);switch(e.status){case"ok":console.log(`${d.ok("\u2713")} ${d.dim(t)} ${d.bold(String(e.commitsFound))} commits (${e.commitsInserted} new)`);break;case"no-cwd":console.log(`${d.dim("\xB7")} ${d.dim(t)} no cwd recorded \u2014 skipped`);break;case"not-a-repo":console.log(`${d.dim("\xB7")} ${d.dim(t)} cwd is not a git worktree \u2014 skipped`);break;case"cwd-missing":console.log(`${d.dim("\xB7")} ${d.dim(t)} cwd no longer exists on disk \u2014 skipped`);break;case"no-window":console.log(`${d.dim("\xB7")} ${d.dim(t)} session has no time window yet \u2014 skipped`);break;case"error":console.log(`${d.err("\u2717")} ${d.dim(t)} ${e.error??"unknown error"}`);break}}async function jc(e,t){if(e){let r=xE(e);if(!r){console.error(d.err(`no session matches '${e}'`)),process.exit(1);return}let o=await Rr(r);if(t.json){console.log(JSON.stringify(o,null,2));return}kE(o);return}let s=t.limit?Math.max(1,Number(t.limit)):void 0;console.log(d.dim(`correlating sessions to git commits (limit ${s??"default"})\u2026`));let n=await $c({limit:s,onProgress:(r,o)=>{(r%25===0||r===o)&&process.stderr.write(`\r${d.dim(` ${r}/${o}`)}`)}});if(process.stderr.write(`
1410
+ `),t.json){console.log(JSON.stringify(n,null,2));return}console.log(""),console.log(`${d.ok("correlated")}: ${d.bold(String(n.ok))} sessions \xB7 ${d.bold(String(n.commitsInserted))} new commits`),console.log(d.dim(` skipped ${n.skipped} (no cwd / non-repo / cwd missing), errors ${n.errors}`)),console.log("")}I();T();Ft();import{existsSync as Cr,readFileSync as Lr}from"node:fs";j();import{existsSync as NE,readFileSync as CE,writeFileSync as LE}from"node:fs";import{join as OE}from"node:path";import{z as de}from"zod";var xr=OE(R,"terminals.json"),Pc=1440*60*1e3,AE=3e4,IE=6e4,vE=de.object({shell_pid:de.number(),tab_name:de.string(),cwd:de.string().nullable().optional(),opened_at:de.string(),last_seen_at:de.string()}),ME=de.object({schema:de.string().optional(),saved_at:de.string().optional(),terminals:de.array(vE).max(500).default([]),sessions_by_pid:de.record(de.string(),de.array(de.string()).max(50)).optional().default({})}),Uc=/^[⠀-⣿✳\s]+/,Bc=/^\d+(\.\d+){1,3}$/;function Fc(e){let t=e.trim();return!!(!t||Uc.test(t)||Bc.test(t))}function DE(e){let t=e.trim();if(!t||Bc.test(t))return null;let s=t.replace(Uc,"").trim();return s.length>0?s:null}function kr(e,t){if(!Fc(e))return e;let s=DE(e);return s||(t&&!Fc(t)?t:e)}function $E(e){let t=e.now-e.withinMs,s=e.pending.filter(n=>{let r=Date.parse(n.started_at);return Number.isFinite(r)&&r>=t});if(s.length===0)return{kind:"none"};if(e.shellPid!=null){let n=s.find(r=>r.shell_pid===e.shellPid);if(n)return{kind:"pid-match",entry:n}}if(e.cwd){let n=e.cwd.replace(/\/+$/,""),r=s.filter(o=>o.cwd&&o.cwd.replace(/\/+$/,"")===n);if(r.length===1)return{kind:"singleton-cwd",entry:r[0]};if(r.length>=2)return{kind:"ambiguous",candidates:r}}return{kind:"none"}}var Nr=class{entries=new Map;origins=new Map;sessionsByPid=new Map;pendingClaudeStarts=[];deferredLinks=new Map;pidOwnership=new Map;loaded=!1;ensureLoaded(){if(!this.loaded&&(this.loaded=!0,!!NE(xr)))try{let t=CE(xr,"utf8"),s=JSON.parse(t),n=ME.safeParse(s);if(!n.success){console.warn("[terminal-registry] terminals.json failed validation, starting with empty registry:",n.error.issues);return}let r=n.data;for(let o of r.terminals)this.entries.set(o.shell_pid,{shell_pid:o.shell_pid,tab_name:o.tab_name,cwd:o.cwd??null,opened_at:o.opened_at,last_seen_at:o.last_seen_at});for(let[o,i]of Object.entries(r.sessions_by_pid??{})){let a=Number(o);if(!Number.isFinite(a))continue;let l=new Set;for(let c of i)c.length>0&&l.add(c);l.size>0&&this.sessionsByPid.set(a,l)}this.gc()}catch{}}save(){try{P();let t={schema:"claude-recall.terminals.v1",saved_at:new Date().toISOString(),terminals:Array.from(this.entries.values()),sessions_by_pid:Object.fromEntries(Array.from(this.sessionsByPid.entries()).map(([s,n])=>[String(s),Array.from(n)]))};LE(xr,JSON.stringify(t,null,2))}catch{}}upsert(t){this.ensureLoaded();let s=new Date().toISOString(),n=this.entries.get(t.shell_pid),r=kr(t.tab_name,n?.tab_name),o=n?.opened_at??t.opened_at,i={...t,tab_name:r,opened_at:o,last_seen_at:s};return this.entries.set(t.shell_pid,i),this.gc(),this.save(),i}rename(t,s){this.ensureLoaded();let n=this.entries.get(t);if(!n)return null;let r=kr(s,n.tab_name),o={...n,tab_name:r,last_seen_at:new Date().toISOString()};return this.entries.set(t,o),this.save(),o}remove(t){this.ensureLoaded();let s=this.entries.delete(t),n=this.sessionsByPid.delete(t);return this.outputTails.delete(t),this.pidOwnership.delete(t),(s||n)&&this.save(),s}claimPidOwnership(t,s,n=Date.now()){if(this.ensureLoaded(),!s)return"anonymous";let r=this.pidOwnership.get(t);return r?r.instance_id===s?(r.last_claim_at=n,"refreshed"):n-r.last_claim_at>IE?(this.pidOwnership.set(t,{instance_id:s,last_claim_at:n}),"claimed"):"rejected":(this.pidOwnership.set(t,{instance_id:s,last_claim_at:n}),"claimed")}pidOwnershipSnapshot(){return this.ensureLoaded(),Array.from(this.pidOwnership.entries()).map(([t,s])=>({shell_pid:t,instance_id:s.instance_id,last_claim_at:s.last_claim_at}))}sync(t){this.ensureLoaded();let s=new Date().toISOString(),n=0,r=0;for(let o of t){let i=this.entries.get(o.shell_pid),a=kr(o.tab_name,i?.tab_name),l=i?.opened_at??o.opened_at;this.entries.set(o.shell_pid,{...o,tab_name:a,opened_at:l,last_seen_at:s}),i?(i.tab_name!==a||i.cwd!==o.cwd)&&r++:n++}return this.gc(),this.save(),{added:n,updated:r,removed:0}}get(t){return this.ensureLoaded(),this.entries.get(t)??null}all(){return this.ensureLoaded(),this.gc(),Array.from(this.entries.values())}size(){return this.ensureLoaded(),this.entries.size}linkSession(t,s){this.ensureLoaded();let n=this.sessionsByPid.get(s);n||(n=new Set,this.sessionsByPid.set(s,n)),n.has(t)||(n.add(t),this.save())}sessionsFor(t){return this.ensureLoaded(),Array.from(this.sessionsByPid.get(t)??[])}isSessionAutoLinked(t){this.ensureLoaded();for(let s of this.sessionsByPid.values())if(s.has(t))return!0;return!1}unlinkSession(t){this.ensureLoaded();let s=!1;for(let[n,r]of this.sessionsByPid)r.delete(t)&&(s=!0,r.size===0&&this.sessionsByPid.delete(n));return s&&this.save(),s}pushPending(t){this.ensureLoaded(),this.gcPending(),this.pendingClaudeStarts.push({...t})}takePendingMatched(t){this.ensureLoaded(),this.gcPending();let s=$E({pending:this.pendingClaudeStarts,shellPid:t.shellPid,cwd:t.cwd,withinMs:t.withinMs,now:Date.now()});if(s.kind==="pid-match"||s.kind==="singleton-cwd"){let n=this.pendingClaudeStarts.indexOf(s.entry);n>=0&&this.pendingClaudeStarts.splice(n,1)}return s}pendingSize(){return this.ensureLoaded(),this.gcPending(),this.pendingClaudeStarts.length}deferSessionLink(t,s,n,r){this.ensureLoaded(),this.gcDeferredLinks(),this.deferredLinks.set(t,{parent_shell_pid:s,queued_at:Date.now(),cwd:n,git_branch:r})}allDeferredLinks(){return this.ensureLoaded(),this.gcDeferredLinks(),Array.from(this.deferredLinks.entries()).map(([t,s])=>({session_id:t,...s}))}resolveDeferredLink(t){return this.deferredLinks.delete(t)}deferredLinkSize(){return this.ensureLoaded(),this.gcDeferredLinks(),this.deferredLinks.size}gcDeferredLinks(){let t=Date.now()-9e4;for(let[s,n]of this.deferredLinks)n.queued_at<t&&this.deferredLinks.delete(s)}gcPending(){let t=Date.now()-AE;this.pendingClaudeStarts.length!==0&&(this.pendingClaudeStarts=this.pendingClaudeStarts.filter(s=>{let n=Date.parse(s.started_at);return Number.isFinite(n)&&n>=t}))}outputTails=new Map;setOutputTail(t,s,n){this.ensureLoaded(),this.outputTails.set(t,{text:s,captured_at:n})}getOutputTail(t){return this.ensureLoaded(),this.outputTails.get(t)??null}allOutputTails(){return this.ensureLoaded(),new Map(this.outputTails)}removeOutputTail(t){return this.outputTails.delete(t)}setOrigin(t,s){this.ensureLoaded(),this.origins.set(t,s),this.gcOrigins()}getOrigin(t){return this.ensureLoaded(),this.origins.get(t)??null}removeOrigin(t){return this.ensureLoaded(),this.origins.delete(t)}allOrigins(){return this.ensureLoaded(),this.gcOrigins(),new Map(this.origins)}originSize(){return this.ensureLoaded(),this.origins.size}gc(){let t=Date.now()-Pc;for(let[s,n]of this.entries){let r=Date.parse(n.last_seen_at);!Number.isNaN(r)&&r<t&&this.entries.delete(s)}}gcOrigins(){let t=Date.now()-Pc;for(let[s,n]of this.origins)n.detectedAt<t&&this.origins.delete(s)}reapStaleLinks(t=10080*60*1e3){this.ensureLoaded();let n=Date.now()-t,r=0,o=0;for(let[i,a]of this.sessionsByPid){let l=this.entries.get(i);if(l){let c=Date.parse(l.last_seen_at);if(Number.isFinite(c)&&c>=n)continue}o+=a.size,this.sessionsByPid.delete(i),l&&(this.entries.delete(i),r++)}return(r||o)&&this.save(),{pruned_pids:r,pruned_sessions:o}}gcDeadPids(){this.ensureLoaded();let t=0,s=0;for(let n of[...this.entries.keys()]){let r=!0;try{process.kill(n,0)}catch(i){i.code==="ESRCH"&&(r=!1)}if(r)continue;this.entries.delete(n),t++;let o=this.sessionsByPid.get(n);o&&(s+=o.size,this.sessionsByPid.delete(n)),this.outputTails.delete(n),this.pidOwnership.delete(n)}return(t||s)&&this.save(),{pruned_pids:t,pruned_sessions:s}}},Hc=new Nr;Pn();function Wc(e){let t=ui(),s={...e};return t&&(s["x-recall-token"]=t),s}async function _t(e,t){let s=t?.headers??{};return fetch(e,{...t,headers:Wc(s)})}async function tt(e,t,s,n){let r=s!==void 0?{"content-type":"application/json",...n}:{...n};return fetch(t,{method:e,headers:Wc(r),body:s!==void 0?JSON.stringify(s):void 0})}j();function PE(){let e=`${R}/daemon.port`;if(!Cr(e))return null;try{let t=Lr(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function FE(e,t){try{return(await tt("POST",`http://127.0.0.1:${e}/api/sessions/${encodeURIComponent(t)}/relink`,{clear:!0})).ok}catch{return!1}}function UE(e,t){let s=_(),n=t?" AND p.name = ?":"",r=t?[t]:[],o=s.prepare(`SELECT s.id, p.name AS project_name, s.cwd, s.started_at, sa.alias
1411
1411
  FROM sessions s
1412
1412
  JOIN projects p ON p.id = s.project_id
1413
1413
  JOIN session_aliases sa ON sa.session_id = s.id
1414
1414
  WHERE s.cwd IS NOT NULL
1415
1415
  AND s.started_at IS NOT NULL
1416
1416
  AND sa.alias IS NOT NULL
1417
- AND sa.alias <> ''${n}`).all(...r),i=new Map;for(let c of o){let u=c.cwd.replace(/\/+$/,""),p=i.get(u);p||(p=[],i.set(u,p)),p.push(c)}let a=e*1e3,l=new Map;for(let[c,u]of i){let p=new Map;for(let m of u){let f=p.get(m.alias);f||(f=[],p.set(m.alias,f)),f.push(m)}for(let m of p.values())if(!(m.length<2))for(let f of m){let g=new Set;for(let h of m)h.id!==f.id&&g.add(h.id);l.set(f.id,{row:f,cwdKey:c,reason:"duplicate-alias",siblingIds:g})}}for(let[c,u]of i){if(u.length<2)continue;u.sort((f,g)=>Date.parse(f.started_at)-Date.parse(g.started_at));let p=[],m=()=>{if(p.length>=2)for(let f of p){if(l.has(f.id))continue;let g=new Set;for(let h of p)h.id!==f.id&&g.add(h.id);l.set(f.id,{row:f,cwdKey:c,reason:"cwd-collision",siblingIds:g})}p=[]};for(let f of u){if(p.length===0){p.push(f);continue}let g=p[p.length-1];Date.parse(f.started_at)-Date.parse(g.started_at)<=a||m(),p.push(f)}m()}return Array.from(l.values()).map(c=>({session_id:c.row.id,project_name:c.row.project_name,cwd:c.cwdKey,started_at:c.row.started_at,alias:c.row.alias,sibling_ids:Array.from(c.siblingIds),reason:c.reason}))}function _E(e){let t=[];try{let s=`${R}/terminals.json`;if(!Sr(s))return t;let n=JSON.parse(yr(s,"utf8")),r=n.sessions_by_pid??{},o=new Map;for(let a of n.terminals??[])o.set(a.shell_pid,a);let i=_();for(let[a,l]of Object.entries(r)){let c=Number(a);if(!Number.isFinite(c))continue;let u=o.get(c)??null;for(let p of l){let m=i.prepare(`SELECT s.id, p.name AS project_name, s.cwd, s.started_at,
1417
+ AND sa.alias <> ''${n}`).all(...r),i=new Map;for(let c of o){let u=c.cwd.replace(/\/+$/,""),m=i.get(u);m||(m=[],i.set(u,m)),m.push(c)}let a=e*1e3,l=new Map;for(let[c,u]of i){let m=new Map;for(let p of u){let f=m.get(p.alias);f||(f=[],m.set(p.alias,f)),f.push(p)}for(let p of m.values())if(!(p.length<2))for(let f of p){let g=new Set;for(let h of p)h.id!==f.id&&g.add(h.id);l.set(f.id,{row:f,cwdKey:c,reason:"duplicate-alias",siblingIds:g})}}for(let[c,u]of i){if(u.length<2)continue;u.sort((f,g)=>Date.parse(f.started_at)-Date.parse(g.started_at));let m=[],p=()=>{if(m.length>=2)for(let f of m){if(l.has(f.id))continue;let g=new Set;for(let h of m)h.id!==f.id&&g.add(h.id);l.set(f.id,{row:f,cwdKey:c,reason:"cwd-collision",siblingIds:g})}m=[]};for(let f of u){if(m.length===0){m.push(f);continue}let g=m[m.length-1];Date.parse(f.started_at)-Date.parse(g.started_at)<=a||p(),m.push(f)}p()}return Array.from(l.values()).map(c=>({session_id:c.row.id,project_name:c.row.project_name,cwd:c.cwdKey,started_at:c.row.started_at,alias:c.row.alias,sibling_ids:Array.from(c.siblingIds),reason:c.reason}))}function BE(e){let t=[];try{let s=`${R}/terminals.json`;if(!Cr(s))return t;let n=JSON.parse(Lr(s,"utf8")),r=n.sessions_by_pid??{},o=new Map;for(let a of n.terminals??[])o.set(a.shell_pid,a);let i=_();for(let[a,l]of Object.entries(r)){let c=Number(a);if(!Number.isFinite(c))continue;let u=o.get(c)??null;for(let m of l){let p=i.prepare(`SELECT s.id, p.name AS project_name, s.cwd, s.started_at,
1418
1418
  NULLIF(sa.alias, '') AS alias
1419
1419
  FROM sessions s
1420
1420
  JOIN projects p ON p.id = s.project_id
1421
1421
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1422
- WHERE s.id = ?`).get(p);m&&(m.alias||e&&m.project_name!==e||t.push({session_id:m.id,project_name:m.project_name,cwd:(m.cwd??"").replace(/\/+$/,""),started_at:m.started_at??"",alias:"",sibling_ids:[],reason:"orphan-link",stale_terminal:u}))}}}catch{}return t}function hE(e){let t=[],s=`${R}/terminals.json`;if(!Sr(s))return t;let n;try{n=JSON.parse(yr(s,"utf8"))}catch{return t}let r=new Map;for(let c of n.terminals??[]){if(!c.tab_name)continue;let u=r.get(c.tab_name);u||(u=[],r.set(c.tab_name,u)),u.push(c)}if(r.size===0)return t;let o=_(),i=e?" AND p.name = ?":"",a=e?[e]:[],l=o.prepare(`SELECT s.id, p.name AS project_name, s.cwd, s.started_at, sa.alias
1422
+ WHERE s.id = ?`).get(m);p&&(p.alias||e&&p.project_name!==e||t.push({session_id:p.id,project_name:p.project_name,cwd:(p.cwd??"").replace(/\/+$/,""),started_at:p.started_at??"",alias:"",sibling_ids:[],reason:"orphan-link",stale_terminal:u}))}}}catch{}return t}function HE(e){let t=[],s=`${R}/terminals.json`;if(!Cr(s))return t;let n;try{n=JSON.parse(Lr(s,"utf8"))}catch{return t}let r=new Map;for(let c of n.terminals??[]){if(!c.tab_name)continue;let u=r.get(c.tab_name);u||(u=[],r.set(c.tab_name,u)),u.push(c)}if(r.size===0)return t;let o=_(),i=e?" AND p.name = ?":"",a=e?[e]:[],l=o.prepare(`SELECT s.id, p.name AS project_name, s.cwd, s.started_at, sa.alias
1423
1423
  FROM sessions s
1424
1424
  JOIN projects p ON p.id = s.project_id
1425
1425
  JOIN session_aliases sa ON sa.session_id = s.id
1426
1426
  WHERE s.started_at IS NOT NULL
1427
1427
  AND sa.alias IS NOT NULL
1428
- AND sa.alias <> ''${i}`).all(...a);for(let c of l){let u=r.get(c.alias);if(!u||u.length===0)continue;let p=Date.parse(c.started_at);if(!Number.isFinite(p))continue;let m=!1,f=null,g=1/0;for(let h of u){let E=Date.parse(h.opened_at);if(Number.isFinite(E)){if(E-p<=6e4){m=!0;break}E<g&&(g=E,f=h)}}m||!f||t.push({session_id:c.id,project_name:c.project_name,cwd:c.cwd.replace(/\/+$/,""),started_at:c.started_at,alias:c.alias,sibling_ids:[],reason:"temporal-anomaly",postdating_terminal:f})}return t}function EE(e){if(e.length===0){console.log(d.ok("No suspicious correlations found."));return}console.log(d.warn(`Found ${e.length} session${e.length===1?"":"s"} with likely-bad correlator aliases:`)),console.log();let t=new Map;for(let s of e){let n=t.get(s.cwd);n||(n=[],t.set(s.cwd,n)),n.push(s)}for(let[s,n]of t){console.log(d.dim(` cwd: ${s}`)),n.sort((r,o)=>Date.parse(r.started_at)-Date.parse(o.started_at));for(let r of n){let o=r.reason==="duplicate-alias"?d.err("[dup-alias]"):r.reason==="orphan-link"?d.warn("[orphan-link]"):r.reason==="temporal-anomaly"?d.err("[temporal]"):d.warn("[cwd-collision]"),i=r.reason==="orphan-link"&&r.stale_terminal?`${d.dim("still pointing at pid")} ${r.stale_terminal.shell_pid} ${d.dim("=")} ${d.bold(`"${r.stale_terminal.tab_name}"`)}`:r.reason==="temporal-anomaly"&&r.postdating_terminal?`${d.bold(`"${r.alias}"`)} ${d.dim("\u2190 terminal opened")} ${r.postdating_terminal.opened_at.replace("T"," ").slice(0,19)} ${d.dim("(after session)")}`:d.bold(`"${r.alias}"`);console.log(` ${o} ${d.dim(r.session_id.slice(0,8))} ${d.dim(r.started_at.replace("T"," ").slice(0,19))} \u2192 ${i}`)}console.log()}}async function Ac(e){let t=e.window?Math.max(5,Math.min(600,Number(e.window)||60)):60,s=e.project?.trim()||void 0,n=fE(t,s),r=_E(s),o=hE(s),i=new Set,a=[];for(let p of[...n,...r,...o])i.has(p.session_id)||(i.add(p.session_id),a.push(p));if(e.json){console.log(JSON.stringify({window_sec:t,suspects:a},null,2));return}if(EE(a),!e.fix){a.length>0&&console.log(d.dim("Re-run with --fix to clear these aliases. Heuristic titles will display instead, and you can manually relink via the UI's \u{1F517} picker."));return}let l=mE(),c=0,u=0;for(let p of a){if(l){await gE(l,p.session_id)?c++:(u++,console.error(d.err(`failed to clear ${p.session_id.slice(0,8)} via daemon`)));continue}try{Mi(p.session_id),Lc.unlinkSession(p.session_id),c++}catch(m){u++,console.error(d.err(`failed to clear ${p.session_id.slice(0,8)}: ${m.message}`))}}console.log(d.ok(`Cleared ${c} suspect alias${c===1?"":"es"}.`)),u>0&&console.log(d.warn(`${u} clears failed; see errors above.`)),l||console.log(d.dim("Daemon was not running, so changes were applied directly to state files.")),console.log(d.dim("Open an affected session in the UI and use the \u{1F517} picker to pin the correct terminal."))}M();T();j();import{existsSync as Mc,readFileSync as bE,statSync as Dc,statfsSync as SE}from"node:fs";import{join as $c}from"node:path";import*as jc from"node:http";var yE=["VS Code","VS Code Insiders","Cursor","Windsurf","Warp","iTerm","Terminal","WezTerm","Windows Terminal","Kitty","Alacritty"],TE=new RegExp(`^(${yE.map(e=>e.replace(/ /g,"\\s")).join("|")})\\s\xB7\\s`);function wE(e){let t=[];for(let s of e)if(s.alias){if(TE.test(s.alias)){t.push({session_id:s.session_id,alias:s.alias,violation:"fabricated-origin-label",cwd:s.cwd});continue}if(s.cwd){let n=s.cwd.replace(/\/+$/,"").split("/").pop();n&&s.alias.startsWith(`${n} \xB7 `)&&t.push({session_id:s.session_id,alias:s.alias,violation:"fabricated-cwd-branch",cwd:s.cwd})}}return t}var Pc=5*6e4,Tr=24,Fc=.5;function RE(){let e=$c(R,"daemon.port");if(!Mc(e))return null;try{let t=bE(e,"utf8").trim();if(t.startsWith("{")){let n=JSON.parse(t);return typeof n.port=="number"?n.port:null}let s=Number.parseInt(t,10);return Number.isFinite(s)&&s>0&&s<65536?s:null}catch{return null}}function xE(e,t,s=1500){return new Promise(n=>{let r=jc.request({host:"127.0.0.1",port:e,path:t,method:"GET",timeout:s,headers:{host:"127.0.0.1","user-agent":"recall-doctor"}},o=>{let i=[];o.on("data",a=>i.push(Buffer.isBuffer(a)?a:Buffer.from(a))),o.on("end",()=>{if(!o.statusCode||o.statusCode<200||o.statusCode>=300){n(null);return}try{n(JSON.parse(Buffer.concat(i).toString("utf8")))}catch{n(null)}})});r.on("error",()=>n(null)),r.on("timeout",()=>{r.destroy(),n(null)}),r.end()})}function kE(){let e=$c(R,"terminals.json");if(!Mc(e))return{exists:!1,mtimeMs:null,ageSeconds:null};try{let t=Dc(e),s=Math.floor((Date.now()-t.mtimeMs)/1e3);return{exists:!0,mtimeMs:t.mtimeMs,ageSeconds:s}}catch{return{exists:!1,mtimeMs:null,ageSeconds:null}}}function CE(){let e=new Date(Date.now()-Tr*36e5).toISOString();try{let t=_().prepare(`SELECT
1428
+ AND sa.alias <> ''${i}`).all(...a);for(let c of l){let u=r.get(c.alias);if(!u||u.length===0)continue;let m=Date.parse(c.started_at);if(!Number.isFinite(m))continue;let p=!1,f=null,g=1/0;for(let h of u){let E=Date.parse(h.opened_at);if(Number.isFinite(E)){if(E-m<=6e4){p=!0;break}E<g&&(g=E,f=h)}}p||!f||t.push({session_id:c.id,project_name:c.project_name,cwd:c.cwd.replace(/\/+$/,""),started_at:c.started_at,alias:c.alias,sibling_ids:[],reason:"temporal-anomaly",postdating_terminal:f})}return t}function WE(e){if(e.length===0){console.log(d.ok("No suspicious correlations found."));return}console.log(d.warn(`Found ${e.length} session${e.length===1?"":"s"} with likely-bad correlator aliases:`)),console.log();let t=new Map;for(let s of e){let n=t.get(s.cwd);n||(n=[],t.set(s.cwd,n)),n.push(s)}for(let[s,n]of t){console.log(d.dim(` cwd: ${s}`)),n.sort((r,o)=>Date.parse(r.started_at)-Date.parse(o.started_at));for(let r of n){let o=r.reason==="duplicate-alias"?d.err("[dup-alias]"):r.reason==="orphan-link"?d.warn("[orphan-link]"):r.reason==="temporal-anomaly"?d.err("[temporal]"):d.warn("[cwd-collision]"),i=r.reason==="orphan-link"&&r.stale_terminal?`${d.dim("still pointing at pid")} ${r.stale_terminal.shell_pid} ${d.dim("=")} ${d.bold(`"${r.stale_terminal.tab_name}"`)}`:r.reason==="temporal-anomaly"&&r.postdating_terminal?`${d.bold(`"${r.alias}"`)} ${d.dim("\u2190 terminal opened")} ${r.postdating_terminal.opened_at.replace("T"," ").slice(0,19)} ${d.dim("(after session)")}`:d.bold(`"${r.alias}"`);console.log(` ${o} ${d.dim(r.session_id.slice(0,8))} ${d.dim(r.started_at.replace("T"," ").slice(0,19))} \u2192 ${i}`)}console.log()}}async function Xc(e){let t=e.window?Math.max(5,Math.min(600,Number(e.window)||60)):60,s=e.project?.trim()||void 0,n=UE(t,s),r=BE(s),o=HE(s),i=new Set,a=[];for(let m of[...n,...r,...o])i.has(m.session_id)||(i.add(m.session_id),a.push(m));if(e.json){console.log(JSON.stringify({window_sec:t,suspects:a},null,2));return}if(WE(a),!e.fix){a.length>0&&console.log(d.dim("Re-run with --fix to clear these aliases. Heuristic titles will display instead, and you can manually relink via the UI's \u{1F517} picker."));return}let l=PE(),c=0,u=0;for(let m of a){if(l){await FE(l,m.session_id)?c++:(u++,console.error(d.err(`failed to clear ${m.session_id.slice(0,8)} via daemon`)));continue}try{zi(m.session_id),Hc.unlinkSession(m.session_id),c++}catch(p){u++,console.error(d.err(`failed to clear ${m.session_id.slice(0,8)}: ${p.message}`))}}console.log(d.ok(`Cleared ${c} suspect alias${c===1?"":"es"}.`)),u>0&&console.log(d.warn(`${u} clears failed; see errors above.`)),l||console.log(d.dim("Daemon was not running, so changes were applied directly to state files.")),console.log(d.dim("Open an affected session in the UI and use the \u{1F517} picker to pin the correct terminal."))}I();T();j();import{existsSync as zc,readFileSync as XE,statSync as Yc,statfsSync as JE}from"node:fs";import{join as Kc}from"node:path";import*as qc from"node:http";var GE=["VS Code","VS Code Insiders","Cursor","Windsurf","Warp","iTerm","Terminal","WezTerm","Windows Terminal","Kitty","Alacritty"],zE=new RegExp(`^(${GE.map(e=>e.replace(/ /g,"\\s")).join("|")})\\s\xB7\\s`);function YE(e){let t=[];for(let s of e)if(s.alias){if(zE.test(s.alias)){t.push({session_id:s.session_id,alias:s.alias,violation:"fabricated-origin-label",cwd:s.cwd});continue}if(s.cwd){let n=s.cwd.replace(/\/+$/,"").split("/").pop();n&&s.alias.startsWith(`${n} \xB7 `)&&t.push({session_id:s.session_id,alias:s.alias,violation:"fabricated-cwd-branch",cwd:s.cwd})}}return t}var Vc=5*6e4,Or=24,Zc=.5;function KE(){let e=Kc(R,"daemon.port");if(!zc(e))return null;try{let t=XE(e,"utf8").trim();if(t.startsWith("{")){let n=JSON.parse(t);return typeof n.port=="number"?n.port:null}let s=Number.parseInt(t,10);return Number.isFinite(s)&&s>0&&s<65536?s:null}catch{return null}}function qE(e,t,s=1500){return new Promise(n=>{let r=qc.request({host:"127.0.0.1",port:e,path:t,method:"GET",timeout:s,headers:{host:"127.0.0.1","user-agent":"recall-doctor"}},o=>{let i=[];o.on("data",a=>i.push(Buffer.isBuffer(a)?a:Buffer.from(a))),o.on("end",()=>{if(!o.statusCode||o.statusCode<200||o.statusCode>=300){n(null);return}try{n(JSON.parse(Buffer.concat(i).toString("utf8")))}catch{n(null)}})});r.on("error",()=>n(null)),r.on("timeout",()=>{r.destroy(),n(null)}),r.end()})}function VE(){let e=Kc(R,"terminals.json");if(!zc(e))return{exists:!1,mtimeMs:null,ageSeconds:null};try{let t=Yc(e),s=Math.floor((Date.now()-t.mtimeMs)/1e3);return{exists:!0,mtimeMs:t.mtimeMs,ageSeconds:s}}catch{return{exists:!1,mtimeMs:null,ageSeconds:null}}}function ZE(){let e=new Date(Date.now()-Or*36e5).toISOString();try{let t=_().prepare(`SELECT
1429
1429
  COUNT(*) AS total,
1430
1430
  SUM(CASE WHEN sa.alias IS NULL OR sa.alias = '' THEN 1 ELSE 0 END) AS without_alias,
1431
1431
  SUM(CASE WHEN (sa.alias IS NULL OR sa.alias = '')
1432
1432
  AND s.auto_title_source = 'heuristic' THEN 1 ELSE 0 END) AS heuristic_only
1433
1433
  FROM sessions s
1434
1434
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1435
- WHERE s.started_at >= ?`).get(e),s=t.total??0,n=t.without_alias??0,r=t.heuristic_only??0,o=s>0?r/s:0;return{total:s,withoutAlias:n,heuristicOnly:r,fractionHeuristic:o}}catch{return{total:0,withoutAlias:0,heuristicOnly:0,fractionHeuristic:0}}}async function NE(){let e=RE(),t=kE(),s=CE(),n=!1,r=null,o=null,i=null,a=null;if(e){let u=await xE(e,"/api/health");u&&(n=!0,r=typeof u.uptimeSeconds=="number"?u.uptimeSeconds:null,o=typeof u.version=="string"?u.version:null,i=typeof u.pipeline?.silentTerminalRejections=="number"?u.pipeline.silentTerminalRejections:null,a=u.pipeline?.lastTerminalSyncAt??null)}let l=[];if(n||l.push("Daemon not reachable on 127.0.0.1 \u2014 start it with `recall start` before further diagnosis."),i!==null&&i>0&&l.push(`Daemon rejected ${i.toLocaleString()} /api/terminal/* request(s) without a valid X-Recall-Token. The editor extension is outdated relative to this daemon \u2014 tab names are not flowing through. Reinstall: \`code --install-extension extensions/vscode/clauderecall-vscode-*.vsix\`, then reload the extension host (Cmd/Ctrl+Shift+P \u2192 "Developer: Restart Extension Host").`),n&&r!==null&&r>30)if(!a)l.push(`Daemon has been running ${Math.round(r/60)} min but has not yet seen a single successful /api/terminal/sync. Either no editor extension is installed/active, or every attempt is being rejected (see counter above).`);else{let u=Date.now()-Date.parse(a);Number.isFinite(u)&&u>Pc&&l.push(`Last successful /api/terminal/sync was ${Math.round(u/6e4)} min ago \u2014 extension may have crashed, been disabled, or is failing auth. Run \`recall doctor\` again after restarting the extension host.`)}return!n&&t.exists&&t.ageSeconds!==null&&t.ageSeconds>24*3600&&l.push(`~/.recall/terminals.json is ${Math.round(t.ageSeconds/3600)}h old \u2014 pipeline has not produced fresh data recently. Likely root cause is the same as the rejection counter would show; start the daemon and re-run.`),s.total>=3&&s.fractionHeuristic>=Fc&&l.push(`${s.heuristicOnly}/${s.total} sessions in the last ${Tr}h (${Math.round(s.fractionHeuristic*100)}%) fell back to the heuristic first-message title. A healthy pipeline rate is < 20%. Either the extension is not syncing tab names, or the correlator cannot disambiguate. Reinstall the extension and verify the rejection counter drops to 0.`),{state:n?l.length>0?"degraded":"ok":"down",flags:l,daemon:{running:n,port:e,uptimeSeconds:r,version:o},runtime:{silentTerminalRejections:i,lastTerminalSyncAt:a},terminalsJson:t,recentSessions:s}}function _t(e){return e<1024?`${e} B`:e<1024**2?`${(e/1024).toFixed(1)} KB`:e<1024**3?`${(e/1024**2).toFixed(1)} MB`:`${(e/1024**3).toFixed(2)} GB`}function Ic(e){try{return Dc(e).size}catch{return 0}}function vc(e){try{return _().prepare(`SELECT COUNT(*) AS n FROM ${e}_data WHERE block = 1`).get().n}catch{return 0}}function LE(){let e=_(),t=e.pragma("page_size",{simple:!0})||4096,s=e.pragma("page_count",{simple:!0})||0,n=e.pragma("freelist_count",{simple:!0})||0,r="ok";try{let h=e.pragma("quick_check").map(E=>E.quick_check);r=h.length===1&&h[0]==="ok"?"ok":h.join("; ")}catch(g){r=`check failed: ${g.message}`}let o=Ic(te),i=Ic(`${te}-wal`),a=0,l=0;try{let g=SE(R);a=Number(g.bavail)*Number(g.bsize),l=Number(g.blocks)*Number(g.bsize)}catch{}let c=e.prepare(`SELECT
1435
+ WHERE s.started_at >= ?`).get(e),s=t.total??0,n=t.without_alias??0,r=t.heuristic_only??0,o=s>0?r/s:0;return{total:s,withoutAlias:n,heuristicOnly:r,fractionHeuristic:o}}catch{return{total:0,withoutAlias:0,heuristicOnly:0,fractionHeuristic:0}}}async function QE(){let e=KE(),t=VE(),s=ZE(),n=!1,r=null,o=null,i=null,a=null;if(e){let u=await qE(e,"/api/health");u&&(n=!0,r=typeof u.uptimeSeconds=="number"?u.uptimeSeconds:null,o=typeof u.version=="string"?u.version:null,i=typeof u.pipeline?.silentTerminalRejections=="number"?u.pipeline.silentTerminalRejections:null,a=u.pipeline?.lastTerminalSyncAt??null)}let l=[];if(n||l.push("Daemon not reachable on 127.0.0.1 \u2014 start it with `recall start` before further diagnosis."),i!==null&&i>0&&l.push(`Daemon rejected ${i.toLocaleString()} /api/terminal/* request(s) without a valid X-Recall-Token. The editor extension is outdated relative to this daemon \u2014 tab names are not flowing through. Reinstall: \`code --install-extension extensions/vscode/clauderecall-vscode-*.vsix\`, then reload the extension host (Cmd/Ctrl+Shift+P \u2192 "Developer: Restart Extension Host").`),n&&r!==null&&r>30)if(!a)l.push(`Daemon has been running ${Math.round(r/60)} min but has not yet seen a single successful /api/terminal/sync. Either no editor extension is installed/active, or every attempt is being rejected (see counter above).`);else{let u=Date.now()-Date.parse(a);Number.isFinite(u)&&u>Vc&&l.push(`Last successful /api/terminal/sync was ${Math.round(u/6e4)} min ago \u2014 extension may have crashed, been disabled, or is failing auth. Run \`recall doctor\` again after restarting the extension host.`)}return!n&&t.exists&&t.ageSeconds!==null&&t.ageSeconds>24*3600&&l.push(`~/.recall/terminals.json is ${Math.round(t.ageSeconds/3600)}h old \u2014 pipeline has not produced fresh data recently. Likely root cause is the same as the rejection counter would show; start the daemon and re-run.`),s.total>=3&&s.fractionHeuristic>=Zc&&l.push(`${s.heuristicOnly}/${s.total} sessions in the last ${Or}h (${Math.round(s.fractionHeuristic*100)}%) fell back to the heuristic first-message title. A healthy pipeline rate is < 20%. Either the extension is not syncing tab names, or the correlator cannot disambiguate. Reinstall the extension and verify the rejection counter drops to 0.`),{state:n?l.length>0?"degraded":"ok":"down",flags:l,daemon:{running:n,port:e,uptimeSeconds:r,version:o},runtime:{silentTerminalRejections:i,lastTerminalSyncAt:a},terminalsJson:t,recentSessions:s}}function ht(e){return e<1024?`${e} B`:e<1024**2?`${(e/1024).toFixed(1)} KB`:e<1024**3?`${(e/1024**2).toFixed(1)} MB`:`${(e/1024**3).toFixed(2)} GB`}function Jc(e){try{return Yc(e).size}catch{return 0}}function Gc(e){try{return _().prepare(`SELECT COUNT(*) AS n FROM ${e}_data WHERE block = 1`).get().n}catch{return 0}}function eb(){let e=_(),t=e.pragma("page_size",{simple:!0})||4096,s=e.pragma("page_count",{simple:!0})||0,n=e.pragma("freelist_count",{simple:!0})||0,r="ok";try{let h=e.pragma("quick_check").map(E=>E.quick_check);r=h.length===1&&h[0]==="ok"?"ok":h.join("; ")}catch(g){r=`check failed: ${g.message}`}let o=Jc(te),i=Jc(`${te}-wal`),a=0,l=0;try{let g=JE(R);a=Number(g.bavail)*Number(g.bsize),l=Number(g.blocks)*Number(g.bsize)}catch{}let c=e.prepare(`SELECT
1436
1436
  (SELECT COUNT(*) FROM projects) AS projects,
1437
1437
  (SELECT COUNT(*) FROM sessions) AS sessions,
1438
1438
  (SELECT COUNT(*) FROM messages) AS messages,
1439
- (SELECT COUNT(*) FROM message_usage) AS message_usage`).get(),u=0;try{u=e.prepare("SELECT COUNT(*) AS n FROM vec_chunks").get().n}catch{}let p=[];a>0&&a<1*1024**3&&p.push(`Disk free is ${_t(a)} \u2014 heavy operations (synthesis, extract-outputs, vector ingest) may fail.`),i>50*1024**2&&p.push(`WAL is ${_t(i)} \u2014 run \`recall optimize\` to truncate it.`),n>s*.2&&s>1e3&&p.push(`${n.toLocaleString()} free pages (${(n/s*100).toFixed(0)}% of file) \u2014 \`recall optimize --vacuum\` will reclaim them.`);let m=vc("messages_fts"),f=vc("sessions_fts");return m>16&&p.push(`messages_fts has ${m} segments \u2014 \`recall optimize\` will merge them.`),{db:{sizeBytes:o,walSizeBytes:i,pageCount:s,pageSize:t,freelistCount:n,freelistBytes:n*t,integrity:r},disk:{freeBytes:a,totalBytes:l},fts:{messages:{fragments:m},sessions:{fragments:f}},vectors:{rows:u},rows:{projects:c.projects,sessions:c.sessions,messages:c.messages,messageUsage:c.message_usage},warnings:p}}async function Uc(e={}){let t=_().prepare(`SELECT sa.session_id AS session_id, sa.alias AS alias, s.cwd AS cwd
1439
+ (SELECT COUNT(*) FROM message_usage) AS message_usage`).get(),u=0;try{u=e.prepare("SELECT COUNT(*) AS n FROM vec_chunks").get().n}catch{}let m=[];a>0&&a<1*1024**3&&m.push(`Disk free is ${ht(a)} \u2014 heavy operations (synthesis, extract-outputs, vector ingest) may fail.`),i>50*1024**2&&m.push(`WAL is ${ht(i)} \u2014 run \`recall optimize\` to truncate it.`),n>s*.2&&s>1e3&&m.push(`${n.toLocaleString()} free pages (${(n/s*100).toFixed(0)}% of file) \u2014 \`recall optimize --vacuum\` will reclaim them.`);let p=Gc("messages_fts"),f=Gc("sessions_fts");return p>16&&m.push(`messages_fts has ${p} segments \u2014 \`recall optimize\` will merge them.`),{db:{sizeBytes:o,walSizeBytes:i,pageCount:s,pageSize:t,freelistCount:n,freelistBytes:n*t,integrity:r},disk:{freeBytes:a,totalBytes:l},fts:{messages:{fragments:p},sessions:{fragments:f}},vectors:{rows:u},rows:{projects:c.projects,sessions:c.sessions,messages:c.messages,messageUsage:c.message_usage},warnings:m}}async function Qc(e={}){let t=_().prepare(`SELECT sa.session_id AS session_id, sa.alias AS alias, s.cwd AS cwd
1440
1440
  FROM session_aliases sa
1441
1441
  LEFT JOIN sessions s ON s.id = sa.session_id
1442
- WHERE sa.alias IS NOT NULL AND sa.alias != ''`).all(),s=wE(t),n=LE(),r=await NE();if(e.json){process.stdout.write(JSON.stringify({scanned:t.length,violations:s.length,items:s,health:n,pipeline:r},null,2)),process.stdout.write(`
1443
- `);let a=r.state==="degraded";return s.length===0&&n.db.integrity==="ok"&&!a?0:1}if(console.log(d.dim("\u2014 System health \u2014")),console.log(` Database ${_t(n.db.sizeBytes)} (${n.rows.messages.toLocaleString()} messages across ${n.rows.sessions.toLocaleString()} sessions, ${n.rows.projects.toLocaleString()} projects)`),console.log(` WAL ${_t(n.db.walSizeBytes)} (capped at 64 MB; truncated on clean shutdown)`),console.log(` Free pages ${n.db.freelistCount.toLocaleString()} (${_t(n.db.freelistBytes)} reclaimable via VACUUM)`),console.log(` FTS segments messages=${n.fts.messages.fragments}, sessions=${n.fts.sessions.fragments} (lower is faster \u2014 \`recall optimize\` merges them)`),console.log(` Vector rows ${n.vectors.rows.toLocaleString()}`),n.disk.totalBytes>0){let a=n.disk.freeBytes/n.disk.totalBytes*100;console.log(` Disk free ${_t(n.disk.freeBytes)} of ${_t(n.disk.totalBytes)} (${a.toFixed(1)}%)`)}if(console.log(` Integrity ${n.db.integrity==="ok"?d.ok("ok"):d.err(n.db.integrity)}`),n.warnings.length>0){console.log("");for(let a of n.warnings)console.log(` ${d.warn("!")} ${a}`)}if(console.log(""),console.log(d.dim("\u2014 Pipeline health (tab-name \u2192 session alias) \u2014")),r.daemon.running?console.log(` Daemon ${d.ok("running")} (port ${r.daemon.port}, version ${r.daemon.version??"?"}, up ${r.daemon.uptimeSeconds!==null?Math.round(r.daemon.uptimeSeconds/60)+" min":"?"})`):console.log(` Daemon ${d.warn("not reachable")}`),r.runtime.silentTerminalRejections!==null){let a=r.runtime.silentTerminalRejections;console.log(` Auth rejections ${a===0?d.ok("0"):d.err(a.toLocaleString())} (extension /api/terminal/* requests denied without a valid X-Recall-Token)`)}if(r.runtime.lastTerminalSyncAt!==null){let a=Date.now()-Date.parse(r.runtime.lastTerminalSyncAt),l=Number.isFinite(a)?Math.round(a/6e4):null,c=l!==null&&a>Pc;console.log(` Last ext sync ${c?d.warn(`${l} min ago`):d.ok(l===0?"just now":`${l} min ago`)} (most recent successful POST /api/terminal/sync)`)}else r.daemon.running&&console.log(` Last ext sync ${d.warn("never")} (no extension has called /api/terminal/sync since the daemon started)`);if(r.terminalsJson.exists&&r.terminalsJson.ageSeconds!==null){let a=Math.round(r.terminalsJson.ageSeconds/3600),l=r.terminalsJson.ageSeconds>24*3600;console.log(` terminals.json ${l?d.warn(`${a}h old`):d.ok(`${a}h old`)} (persisted registry mtime \u2014 fresh means extensions are connecting)`)}let o=r.recentSessions;if(o.total>0){let a=Math.round(o.fractionHeuristic*100),l=o.fractionHeuristic>=Fc&&o.total>=3;console.log(` Recent titles ${l?d.err(`${a}% heuristic`):d.ok(`${a}% heuristic`)} (${o.heuristicOnly}/${o.total} sessions in last ${Tr}h fell back to first-message title)`)}if(r.flags.length>0){console.log("");for(let a of r.flags)console.log(` ${d.warn("!")} ${a}`)}if(console.log(""),console.log(d.dim("\u2014 Tab-name invariant \u2014")),s.length===0)return console.log(d.ok(` \u2713 holds across ${t.length.toLocaleString()} aliased session${t.length===1?"":"s"}`)),console.log(d.dim(" No fabricated origin labels (`VS Code \xB7 cwd \xB7 branch`) found. No deprecated cwd-branch synthesis found.")),n.db.integrity==="ok"?0:1;console.log(d.err(`\u2717 ${s.length} invariant violation${s.length===1?"":"s"} found across ${t.length.toLocaleString()} aliased sessions`)),console.log("");let i=new Map;for(let a of s){let l=i.get(a.violation)??[];l.push(a),i.set(a.violation,l)}for(let[a,l]of i){console.log(d.warn(` ${a} (${l.length})`));for(let c of l.slice(0,10))console.log(` ${c.session_id.slice(0,8)} ${d.dim("\u2192")} ${JSON.stringify(c.alias)}`);l.length>10&&console.log(d.dim(` \u2026 and ${l.length-10} more (rerun with --json for the full list)`)),console.log("")}return console.log(d.dim('Remediation: `recall name <id-prefix> ""` clears a bad alias so the heuristic title takes over,\nor `recall name <id-prefix> "<actual tab name>"` sets it to the real value.')),1}M();T();j();import{existsSync as OE,readFileSync as AE}from"node:fs";import{join as IE}from"node:path";function vE(){let e=IE(R,"daemon.pid");if(!OE(e))return!1;try{let t=parseInt(AE(e,"utf-8").trim(),10);return!Number.isFinite(t)||t<=0?!1:(process.kill(t,0),!0)}catch{return!1}}async function Xt(e,t){let s=Date.now();try{return t(),{step:e,ok:!0,durationMs:Date.now()-s}}catch(n){return{step:e,ok:!1,durationMs:Date.now()-s,error:n.message}}}async function Bc(e={}){let t=_(),s=[];if(e.vacuum&&vE())return e.json?(process.stdout.write(JSON.stringify({ok:!1,error:"daemon-running",message:"VACUUM requires the daemon to be stopped. Run `recall stop`, then re-run with --vacuum."},null,2)+`
1444
- `),2):(console.error(d.err("\u2717 VACUUM requires the daemon to be stopped. Run `recall stop` first, then re-run with --vacuum.")),2);s.push(await Xt("wal_checkpoint(TRUNCATE)",()=>{t.pragma("wal_checkpoint(TRUNCATE)")})),s.push(await Xt("messages_fts optimize",()=>{t.exec("INSERT INTO messages_fts(messages_fts) VALUES('optimize');")})),s.push(await Xt("sessions_fts optimize",()=>{t.exec("INSERT INTO sessions_fts(sessions_fts) VALUES('optimize');")})),s.push(await Xt("PRAGMA optimize",()=>{t.exec("PRAGMA optimize")})),e.vacuum&&s.push(await Xt("VACUUM",()=>{t.exec("VACUUM")}));let n=s.filter(r=>!r.ok);if(e.json)return process.stdout.write(JSON.stringify({ok:n.length===0,steps:s,vacuum:!!e.vacuum},null,2)+`
1445
- `),n.length===0?0:1;for(let r of s){let o=r.ok?d.ok("\u2713"):d.err("\u2717"),i=`${r.durationMs} ms`;console.log(` ${o} ${r.step.padEnd(28)} ${d.dim(i)}`),r.error&&console.log(` ${d.err(r.error)}`)}return n.length===0?(console.log(""),console.log(d.ok("All maintenance passes completed.")),e.vacuum||console.log(d.dim(" Run `recall optimize --vacuum` (with the daemon stopped) to reclaim disk pages from deleted rows.")),0):(console.log(""),console.log(d.warn(`${n.length} step(s) failed \u2014 review the errors above.`)),1)}M();T();j();import{existsSync as ME,readFileSync as DE}from"node:fs";function $E(){let e=`${R}/daemon.port`;if(!ME(e))return null;try{let t=DE(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}function jE(e){let t=_();if(e.length>=32){let n=t.prepare("SELECT id FROM sessions WHERE id = ?").get(e);return n?n.id:(process.stderr.write(`session not found: ${e}
1442
+ WHERE sa.alias IS NOT NULL AND sa.alias != ''`).all(),s=YE(t),n=eb(),r=await QE();if(e.json){process.stdout.write(JSON.stringify({scanned:t.length,violations:s.length,items:s,health:n,pipeline:r},null,2)),process.stdout.write(`
1443
+ `);let a=r.state==="degraded";return s.length===0&&n.db.integrity==="ok"&&!a?0:1}if(console.log(d.dim("\u2014 System health \u2014")),console.log(` Database ${ht(n.db.sizeBytes)} (${n.rows.messages.toLocaleString()} messages across ${n.rows.sessions.toLocaleString()} sessions, ${n.rows.projects.toLocaleString()} projects)`),console.log(` WAL ${ht(n.db.walSizeBytes)} (capped at 64 MB; truncated on clean shutdown)`),console.log(` Free pages ${n.db.freelistCount.toLocaleString()} (${ht(n.db.freelistBytes)} reclaimable via VACUUM)`),console.log(` FTS segments messages=${n.fts.messages.fragments}, sessions=${n.fts.sessions.fragments} (lower is faster \u2014 \`recall optimize\` merges them)`),console.log(` Vector rows ${n.vectors.rows.toLocaleString()}`),n.disk.totalBytes>0){let a=n.disk.freeBytes/n.disk.totalBytes*100;console.log(` Disk free ${ht(n.disk.freeBytes)} of ${ht(n.disk.totalBytes)} (${a.toFixed(1)}%)`)}if(console.log(` Integrity ${n.db.integrity==="ok"?d.ok("ok"):d.err(n.db.integrity)}`),n.warnings.length>0){console.log("");for(let a of n.warnings)console.log(` ${d.warn("!")} ${a}`)}if(console.log(""),console.log(d.dim("\u2014 Pipeline health (tab-name \u2192 session alias) \u2014")),r.daemon.running?console.log(` Daemon ${d.ok("running")} (port ${r.daemon.port}, version ${r.daemon.version??"?"}, up ${r.daemon.uptimeSeconds!==null?Math.round(r.daemon.uptimeSeconds/60)+" min":"?"})`):console.log(` Daemon ${d.warn("not reachable")}`),r.runtime.silentTerminalRejections!==null){let a=r.runtime.silentTerminalRejections;console.log(` Auth rejections ${a===0?d.ok("0"):d.err(a.toLocaleString())} (extension /api/terminal/* requests denied without a valid X-Recall-Token)`)}if(r.runtime.lastTerminalSyncAt!==null){let a=Date.now()-Date.parse(r.runtime.lastTerminalSyncAt),l=Number.isFinite(a)?Math.round(a/6e4):null,c=l!==null&&a>Vc;console.log(` Last ext sync ${c?d.warn(`${l} min ago`):d.ok(l===0?"just now":`${l} min ago`)} (most recent successful POST /api/terminal/sync)`)}else r.daemon.running&&console.log(` Last ext sync ${d.warn("never")} (no extension has called /api/terminal/sync since the daemon started)`);if(r.terminalsJson.exists&&r.terminalsJson.ageSeconds!==null){let a=Math.round(r.terminalsJson.ageSeconds/3600),l=r.terminalsJson.ageSeconds>24*3600;console.log(` terminals.json ${l?d.warn(`${a}h old`):d.ok(`${a}h old`)} (persisted registry mtime \u2014 fresh means extensions are connecting)`)}let o=r.recentSessions;if(o.total>0){let a=Math.round(o.fractionHeuristic*100),l=o.fractionHeuristic>=Zc&&o.total>=3;console.log(` Recent titles ${l?d.err(`${a}% heuristic`):d.ok(`${a}% heuristic`)} (${o.heuristicOnly}/${o.total} sessions in last ${Or}h fell back to first-message title)`)}if(r.flags.length>0){console.log("");for(let a of r.flags)console.log(` ${d.warn("!")} ${a}`)}if(console.log(""),console.log(d.dim("\u2014 Tab-name invariant \u2014")),s.length===0)return console.log(d.ok(` \u2713 holds across ${t.length.toLocaleString()} aliased session${t.length===1?"":"s"}`)),console.log(d.dim(" No fabricated origin labels (`VS Code \xB7 cwd \xB7 branch`) found. No deprecated cwd-branch synthesis found.")),n.db.integrity==="ok"?0:1;console.log(d.err(`\u2717 ${s.length} invariant violation${s.length===1?"":"s"} found across ${t.length.toLocaleString()} aliased sessions`)),console.log("");let i=new Map;for(let a of s){let l=i.get(a.violation)??[];l.push(a),i.set(a.violation,l)}for(let[a,l]of i){console.log(d.warn(` ${a} (${l.length})`));for(let c of l.slice(0,10))console.log(` ${c.session_id.slice(0,8)} ${d.dim("\u2192")} ${JSON.stringify(c.alias)}`);l.length>10&&console.log(d.dim(` \u2026 and ${l.length-10} more (rerun with --json for the full list)`)),console.log("")}return console.log(d.dim('Remediation: `recall name <id-prefix> ""` clears a bad alias so the heuristic title takes over,\nor `recall name <id-prefix> "<actual tab name>"` sets it to the real value.')),1}I();T();j();import{existsSync as tb,readFileSync as sb}from"node:fs";import{join as nb}from"node:path";function rb(){let e=nb(R,"daemon.pid");if(!tb(e))return!1;try{let t=parseInt(sb(e,"utf-8").trim(),10);return!Number.isFinite(t)||t<=0?!1:(process.kill(t,0),!0)}catch{return!1}}async function Yt(e,t){let s=Date.now();try{return t(),{step:e,ok:!0,durationMs:Date.now()-s}}catch(n){return{step:e,ok:!1,durationMs:Date.now()-s,error:n.message}}}async function el(e={}){let t=_(),s=[];if(e.vacuum&&rb())return e.json?(process.stdout.write(JSON.stringify({ok:!1,error:"daemon-running",message:"VACUUM requires the daemon to be stopped. Run `recall stop`, then re-run with --vacuum."},null,2)+`
1444
+ `),2):(console.error(d.err("\u2717 VACUUM requires the daemon to be stopped. Run `recall stop` first, then re-run with --vacuum.")),2);s.push(await Yt("wal_checkpoint(TRUNCATE)",()=>{t.pragma("wal_checkpoint(TRUNCATE)")})),s.push(await Yt("messages_fts optimize",()=>{t.exec("INSERT INTO messages_fts(messages_fts) VALUES('optimize');")})),s.push(await Yt("sessions_fts optimize",()=>{t.exec("INSERT INTO sessions_fts(sessions_fts) VALUES('optimize');")})),s.push(await Yt("PRAGMA optimize",()=>{t.exec("PRAGMA optimize")})),e.vacuum&&s.push(await Yt("VACUUM",()=>{t.exec("VACUUM")}));let n=s.filter(r=>!r.ok);if(e.json)return process.stdout.write(JSON.stringify({ok:n.length===0,steps:s,vacuum:!!e.vacuum},null,2)+`
1445
+ `),n.length===0?0:1;for(let r of s){let o=r.ok?d.ok("\u2713"):d.err("\u2717"),i=`${r.durationMs} ms`;console.log(` ${o} ${r.step.padEnd(28)} ${d.dim(i)}`),r.error&&console.log(` ${d.err(r.error)}`)}return n.length===0?(console.log(""),console.log(d.ok("All maintenance passes completed.")),e.vacuum||console.log(d.dim(" Run `recall optimize --vacuum` (with the daemon stopped) to reclaim disk pages from deleted rows.")),0):(console.log(""),console.log(d.warn(`${n.length} step(s) failed \u2014 review the errors above.`)),1)}I();T();j();import{existsSync as ob,readFileSync as ib}from"node:fs";function ab(){let e=`${R}/daemon.port`;if(!ob(e))return null;try{let t=ib(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}function cb(e){let t=_();if(e.length>=32){let n=t.prepare("SELECT id FROM sessions WHERE id = ?").get(e);return n?n.id:(process.stderr.write(`session not found: ${e}
1446
1446
  `),null)}let s=t.prepare("SELECT id FROM sessions WHERE id LIKE ? LIMIT 2").all(e+"%");return s.length===1?s[0].id:s.length===0?(process.stderr.write(`no session matches prefix "${e}"
1447
1447
  `),null):(process.stderr.write(`ambiguous session prefix "${e}". be more specific.
1448
- `),null)}async function Hc(e,t,s){let n=jE(e);if(!n){process.exitCode=1;return}let r=t.trim();if(!r){process.stderr.write(`name cannot be empty
1449
- `),process.exitCode=1;return}let o=$E();if(!o){process.stderr.write("daemon is not running. start it with `recall start` so the alias write is durable.\n"),process.exitCode=1;return}let i;try{i=await et("PUT",`http://127.0.0.1:${o}/api/sessions/${encodeURIComponent(n)}/alias`,{alias:r,pin:s.pin===!0})}catch(l){process.stderr.write(`failed to reach daemon at 127.0.0.1:${o}: ${l.message}
1448
+ `),null)}async function tl(e,t,s){let n=cb(e);if(!n){process.exitCode=1;return}let r=t.trim();if(!r){process.stderr.write(`name cannot be empty
1449
+ `),process.exitCode=1;return}let o=ab();if(!o){process.stderr.write("daemon is not running. start it with `recall start` so the alias write is durable.\n"),process.exitCode=1;return}let i;try{i=await tt("PUT",`http://127.0.0.1:${o}/api/sessions/${encodeURIComponent(n)}/alias`,{alias:r,pin:s.pin===!0})}catch(l){process.stderr.write(`failed to reach daemon at 127.0.0.1:${o}: ${l.message}
1450
1450
  `),process.exitCode=1;return}if(!i.ok){let l="";try{l=await i.text()}catch{}process.stderr.write(`daemon rejected alias write (HTTP ${i.status}): ${l}
1451
- `),process.exitCode=1;return}let a={session_id:n,alias:r};if(s.json){console.log(JSON.stringify(a));return}console.log(`${d.ok("renamed")} ${d.dim(n.slice(0,8))} \u2192 ${d.bold(`"${r}"`)}`)}M();T();var Jc=90;async function PE(){try{let e=`${process.env.HOME}/.recall/daemon.port`,t=await import("node:fs");if(!t.existsSync(e))return null;let s=t.readFileSync(e,"utf8").trim(),n=await ft(`http://127.0.0.1:${s}/api/terminal/registry`);return n.ok?await n.json():null}catch{return null}}function FE(){let e=Date.now()/1e3-Jc;return _().prepare(`SELECT s.id, s.cwd, s.file_mtime, NULLIF(sa.alias, '') AS alias
1451
+ `),process.exitCode=1;return}let a={session_id:n,alias:r};if(s.json){console.log(JSON.stringify(a));return}console.log(`${d.ok("renamed")} ${d.dim(n.slice(0,8))} \u2192 ${d.bold(`"${r}"`)}`)}I();T();var rl=90;async function lb(){try{let e=`${process.env.HOME}/.recall/daemon.port`,t=await import("node:fs");if(!t.existsSync(e))return null;let s=t.readFileSync(e,"utf8").trim(),n=await _t(`http://127.0.0.1:${s}/api/terminal/registry`);return n.ok?await n.json():null}catch{return null}}function db(){let e=Date.now()/1e3-rl;return _().prepare(`SELECT s.id, s.cwd, s.file_mtime, NULLIF(sa.alias, '') AS alias
1452
1452
  FROM sessions s
1453
1453
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1454
1454
  WHERE s.cwd IS NOT NULL AND s.file_mtime > ?
1455
- ORDER BY s.cwd, s.file_mtime DESC`).all(e)}var UE=new Set(["zsh","bash","fish","sh","dash","ksh","tcsh","csh","pwsh","powershell","cmd","nu"]);function Wc(e){let t=e.trim().toLowerCase().replace(/^[-/]+/,"").replace(/^.*\//,"").replace(/\s*\(\d+\)\s*$/,"").trim();return!t||UE.has(t)}var BE=/^[⠀-⣿✳\s]+/,HE=/^\d+(\.\d+){1,3}$/;function Xc(e){let t=e.trim();return!!(!t||BE.test(t)||HE.test(t))}async function Gc(e){let t=await PE(),s=FE();if(e.json){console.log(JSON.stringify({registry:t,active:s},null,2));return}if(console.log(),console.log(d.bold("TERMINAL REGISTRY")),console.log(d.dim("(what the daemon thinks each VS Code terminal is named)")),console.log(),!t){console.log(d.err(" Could not reach daemon. Is recall start running?"));return}let n=new Map;for(let o of t.terminals){let i=o.cwd??"(no cwd)",a=n.get(i);a||(a=[],n.set(i,a)),a.push(o)}for(let[o,i]of n){console.log(d.dim(` cwd: ${o}`));for(let a of i){let l=Wc(a.tab_name),c=Xc(a.tab_name),p=!l&&!c?d.ok("[usable]"):l?d.warn("[generic-shell]"):d.warn("[claude-auto]");console.log(` ${p} pid ${a.shell_pid} ${d.bold(`"${a.tab_name}"`)}`)}console.log()}if(console.log(d.bold(`ACTIVE SESSIONS (mtime within last ${Jc}s)`)),console.log(d.dim("(sessions whose JSONL is being actively written)")),console.log(),s.length===0){console.log(d.dim(" (none)")),console.log();return}let r=new Map;for(let o of s){let i=r.get(o.cwd);i||(i=[],r.set(o.cwd,i)),i.push(o)}for(let[o,i]of r){console.log(d.dim(` cwd: ${o}`));for(let a of i)console.log(` ${d.dim(a.id.slice(0,8))} ${d.bold(a.alias??"(no alias)")} ${d.dim(`mtime ${new Date(a.file_mtime*1e3).toISOString().slice(11,19)}`)}`);console.log()}console.log(d.bold("LAYER 5 SWEEP DECISIONS")),console.log(d.dim("(what the live correlator would do for each cwd right now)")),console.log();for(let[o,i]of r){let l=(n.get(o)??[]).filter(c=>!Wc(c.tab_name)&&!Xc(c.tab_name));l.length===0?console.log(` ${d.warn("skip")} ${d.dim(o)} ${d.dim("\u2014 no usable terminal name (all generic or claude-auto)")}`):l.length>1?console.log(` ${d.warn("refuse")} ${d.dim(o)} ${d.dim(`\u2014 ${l.length} usable terminals, ambiguous`)}`):i.length>1?console.log(` ${d.warn("refuse")} ${d.dim(o)} ${d.dim(`\u2014 ${i.length} active sessions, ambiguous`)}`):console.log(` ${d.ok("link")} ${d.dim(o)} ${d.dim("\u2192")} ${d.dim(i[0].id.slice(0,8))} ${d.dim("=")} ${d.bold(`"${l[0].tab_name}"`)}`)}console.log()}M();T();j();import{existsSync as WE,readFileSync as XE}from"node:fs";function JE(){let e=`${R}/daemon.port`;if(!WE(e))return null;try{let t=XE(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function GE(e){try{let t=await ft(`http://127.0.0.1:${e}/api/terminal/registry`);return t.ok?(await t.json()).terminals??[]:[]}catch{return[]}}async function zE(e,t,s){try{return(await et("POST",`http://127.0.0.1:${e}/api/sessions/${encodeURIComponent(t)}/relink`,{shell_pid:s})).ok}catch{return!1}}function YE(e){try{let t=JSON.parse(e);if(!Array.isArray(t))return null;for(let s=t.length-1;s>=0;s--){let n=t[s];if(n&&typeof n.alias=="string"&&n.alias!=="")return n.alias}return null}catch{return null}}function KE(e){let t=new Map;for(let i of e){if(!i.cwd)continue;let a=i.cwd.replace(/\/+$/,""),l=t.get(a);l||(l=new Map,t.set(a,l)),l.set(i.tab_name,i.shell_pid)}let s=new Map;for(let i of e){if(!i.cwd)continue;let l=`${i.cwd.replace(/\/+$/,"")}::${i.tab_name}`,c=s.get(l);c||(c=new Set,s.set(l,c)),c.add(String(i.shell_pid))}let r=_().prepare(`SELECT sa.session_id, s.cwd, sa.previous_aliases
1455
+ ORDER BY s.cwd, s.file_mtime DESC`).all(e)}var ub=new Set(["zsh","bash","fish","sh","dash","ksh","tcsh","csh","pwsh","powershell","cmd","nu"]);function sl(e){let t=e.trim().toLowerCase().replace(/^[-/]+/,"").replace(/^.*\//,"").replace(/\s*\(\d+\)\s*$/,"").trim();return!t||ub.has(t)}var mb=/^[⠀-⣿✳\s]+/,pb=/^\d+(\.\d+){1,3}$/;function nl(e){let t=e.trim();return!!(!t||mb.test(t)||pb.test(t))}async function ol(e){let t=await lb(),s=db();if(e.json){console.log(JSON.stringify({registry:t,active:s},null,2));return}if(console.log(),console.log(d.bold("TERMINAL REGISTRY")),console.log(d.dim("(what the daemon thinks each VS Code terminal is named)")),console.log(),!t){console.log(d.err(" Could not reach daemon. Is recall start running?"));return}let n=new Map;for(let o of t.terminals){let i=o.cwd??"(no cwd)",a=n.get(i);a||(a=[],n.set(i,a)),a.push(o)}for(let[o,i]of n){console.log(d.dim(` cwd: ${o}`));for(let a of i){let l=sl(a.tab_name),c=nl(a.tab_name),m=!l&&!c?d.ok("[usable]"):l?d.warn("[generic-shell]"):d.warn("[claude-auto]");console.log(` ${m} pid ${a.shell_pid} ${d.bold(`"${a.tab_name}"`)}`)}console.log()}if(console.log(d.bold(`ACTIVE SESSIONS (mtime within last ${rl}s)`)),console.log(d.dim("(sessions whose JSONL is being actively written)")),console.log(),s.length===0){console.log(d.dim(" (none)")),console.log();return}let r=new Map;for(let o of s){let i=r.get(o.cwd);i||(i=[],r.set(o.cwd,i)),i.push(o)}for(let[o,i]of r){console.log(d.dim(` cwd: ${o}`));for(let a of i)console.log(` ${d.dim(a.id.slice(0,8))} ${d.bold(a.alias??"(no alias)")} ${d.dim(`mtime ${new Date(a.file_mtime*1e3).toISOString().slice(11,19)}`)}`);console.log()}console.log(d.bold("LAYER 5 SWEEP DECISIONS")),console.log(d.dim("(what the live correlator would do for each cwd right now)")),console.log();for(let[o,i]of r){let l=(n.get(o)??[]).filter(c=>!sl(c.tab_name)&&!nl(c.tab_name));l.length===0?console.log(` ${d.warn("skip")} ${d.dim(o)} ${d.dim("\u2014 no usable terminal name (all generic or claude-auto)")}`):l.length>1?console.log(` ${d.warn("refuse")} ${d.dim(o)} ${d.dim(`\u2014 ${l.length} usable terminals, ambiguous`)}`):i.length>1?console.log(` ${d.warn("refuse")} ${d.dim(o)} ${d.dim(`\u2014 ${i.length} active sessions, ambiguous`)}`):console.log(` ${d.ok("link")} ${d.dim(o)} ${d.dim("\u2192")} ${d.dim(i[0].id.slice(0,8))} ${d.dim("=")} ${d.bold(`"${l[0].tab_name}"`)}`)}console.log()}I();T();j();import{existsSync as gb,readFileSync as fb}from"node:fs";function _b(){let e=`${R}/daemon.port`;if(!gb(e))return null;try{let t=fb(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function hb(e){try{let t=await _t(`http://127.0.0.1:${e}/api/terminal/registry`);return t.ok?(await t.json()).terminals??[]:[]}catch{return[]}}async function Eb(e,t,s){try{return(await tt("POST",`http://127.0.0.1:${e}/api/sessions/${encodeURIComponent(t)}/relink`,{shell_pid:s})).ok}catch{return!1}}function bb(e){try{let t=JSON.parse(e);if(!Array.isArray(t))return null;for(let s=t.length-1;s>=0;s--){let n=t[s];if(n&&typeof n.alias=="string"&&n.alias!=="")return n.alias}return null}catch{return null}}function Sb(e){let t=new Map;for(let i of e){if(!i.cwd)continue;let a=i.cwd.replace(/\/+$/,""),l=t.get(a);l||(l=new Map,t.set(a,l)),l.set(i.tab_name,i.shell_pid)}let s=new Map;for(let i of e){if(!i.cwd)continue;let l=`${i.cwd.replace(/\/+$/,"")}::${i.tab_name}`,c=s.get(l);c||(c=new Set,s.set(l,c)),c.add(String(i.shell_pid))}let r=_().prepare(`SELECT sa.session_id, s.cwd, sa.previous_aliases
1456
1456
  FROM session_aliases sa
1457
1457
  JOIN sessions s ON s.id = sa.session_id
1458
- WHERE sa.alias = '' AND sa.previous_aliases != '[]' AND s.cwd IS NOT NULL`).all(),o=[];for(let i of r){let a=YE(i.previous_aliases);if(!a)continue;let l=i.cwd.replace(/\/+$/,""),u=t.get(l)?.get(a);if(!u)continue;let p=s.get(`${l}::${a}`);p&&p.size>1||o.push({session_id:i.session_id,cwd:l,alias_to_restore:a,matching_pid:u})}return o}async function zc(e){let t=JE();t||(console.error(d.err("Daemon is not running. Run `recall start` first.")),process.exit(1));let s=await GE(t);s.length===0&&(console.error(d.err("Registry is empty. Open VS Code with the extension to populate it.")),process.exit(1));let n=KE(s);if(e.json){console.log(JSON.stringify({candidates:n},null,2));return}if(n.length===0){console.log(d.dim("No restorable sessions found.")),console.log(d.dim("A session is restorable when its previous alias still matches a currently-open terminal in the same cwd, with no name collisions."));return}console.log(d.bold(`Found ${n.length} session${n.length===1?"":"s"} that can be cleanly restored:`)),console.log();let r=new Map;for(let a of n){let l=r.get(a.cwd);l||(l=[],r.set(a.cwd,l)),l.push(a)}for(let[a,l]of r){console.log(d.dim(` cwd: ${a}`));for(let c of l)console.log(` ${d.dim(c.session_id.slice(0,8))} ${d.dim("\u2192 pid")} ${c.matching_pid} ${d.dim("=")} ${d.bold(`"${c.alias_to_restore}"`)}`);console.log()}if(!e.apply){console.log(d.dim("Re-run with --apply to restore these aliases."));return}let o=0,i=0;for(let a of n)await zE(t,a.session_id,a.matching_pid)?o++:(i++,console.error(d.err(`failed to restore ${a.session_id.slice(0,8)}`)));console.log(d.ok(`Restored ${o} alias${o===1?"":"es"}.${i>0?` ${i} failed.`:""}`)),console.log(d.dim("Sessions whose previous alias did not cleanly match a current terminal still need manual relink via the \u{1F517} picker."))}M();async function Yc(e,t){let s=e.trim();if(!/^[0-9a-fA-F]{4,40}$/.test(s)){console.error(d.err(`not a valid commit SHA: '${e}'`)),process.exit(1);return}let n=$s(s);if(t.json){console.log(JSON.stringify(n,null,2));return}if(n.length===0){console.log(""),console.log(d.dim(`no correlated sessions for ${s}`)),console.log(d.dim(" (if you haven't yet, run `recall correlate` to backfill)")),console.log("");return}console.log(""),console.log(`${d.bold("commit")} ${d.accent(n[0].commitSha.slice(0,12))} ${d.dim(n[0].committedAt??"")}`),n[0].subject&&console.log(` ${n[0].subject}`),console.log(""),console.log(d.dim(`authored during ${n.length} session${n.length===1?"":"s"}:`));for(let r of n){let o=r.alias??r.sessionId.slice(0,8);console.log(` ${d.accent(o.padEnd(24))} ${d.dim((r.project??"").slice(0,24).padEnd(26))} ${d.dim(r.startedAt??"")}`),console.log(` ${d.dim(`recall show ${r.sessionId}`)}`)}console.log("")}M();T();import{execFile as qE}from"node:child_process";import{promisify as VE}from"node:util";import{stat as ZE}from"node:fs/promises";var QE=VE(qE),eb=60,tb=7,sb=7,nb=5e3;function rb(){let e=_(),t=s=>{try{return!!e.prepare(s).get()}catch{return!1}};return{semantic:t("SELECT 1 FROM session_semantic LIMIT 1"),cost:t(`SELECT 1 FROM sessions
1458
+ WHERE sa.alias = '' AND sa.previous_aliases != '[]' AND s.cwd IS NOT NULL`).all(),o=[];for(let i of r){let a=bb(i.previous_aliases);if(!a)continue;let l=i.cwd.replace(/\/+$/,""),u=t.get(l)?.get(a);if(!u)continue;let m=s.get(`${l}::${a}`);m&&m.size>1||o.push({session_id:i.session_id,cwd:l,alias_to_restore:a,matching_pid:u})}return o}async function il(e){let t=_b();t||(console.error(d.err("Daemon is not running. Run `recall start` first.")),process.exit(1));let s=await hb(t);s.length===0&&(console.error(d.err("Registry is empty. Open VS Code with the extension to populate it.")),process.exit(1));let n=Sb(s);if(e.json){console.log(JSON.stringify({candidates:n},null,2));return}if(n.length===0){console.log(d.dim("No restorable sessions found.")),console.log(d.dim("A session is restorable when its previous alias still matches a currently-open terminal in the same cwd, with no name collisions."));return}console.log(d.bold(`Found ${n.length} session${n.length===1?"":"s"} that can be cleanly restored:`)),console.log();let r=new Map;for(let a of n){let l=r.get(a.cwd);l||(l=[],r.set(a.cwd,l)),l.push(a)}for(let[a,l]of r){console.log(d.dim(` cwd: ${a}`));for(let c of l)console.log(` ${d.dim(c.session_id.slice(0,8))} ${d.dim("\u2192 pid")} ${c.matching_pid} ${d.dim("=")} ${d.bold(`"${c.alias_to_restore}"`)}`);console.log()}if(!e.apply){console.log(d.dim("Re-run with --apply to restore these aliases."));return}let o=0,i=0;for(let a of n)await Eb(t,a.session_id,a.matching_pid)?o++:(i++,console.error(d.err(`failed to restore ${a.session_id.slice(0,8)}`)));console.log(d.ok(`Restored ${o} alias${o===1?"":"es"}.${i>0?` ${i} failed.`:""}`)),console.log(d.dim("Sessions whose previous alias did not cleanly match a current terminal still need manual relink via the \u{1F517} picker."))}I();async function al(e,t){let s=e.trim();if(!/^[0-9a-fA-F]{4,40}$/.test(s)){console.error(d.err(`not a valid commit SHA: '${e}'`)),process.exit(1);return}let n=Bs(s);if(t.json){console.log(JSON.stringify(n,null,2));return}if(n.length===0){console.log(""),console.log(d.dim(`no correlated sessions for ${s}`)),console.log(d.dim(" (if you haven't yet, run `recall correlate` to backfill)")),console.log("");return}console.log(""),console.log(`${d.bold("commit")} ${d.accent(n[0].commitSha.slice(0,12))} ${d.dim(n[0].committedAt??"")}`),n[0].subject&&console.log(` ${n[0].subject}`),console.log(""),console.log(d.dim(`authored during ${n.length} session${n.length===1?"":"s"}:`));for(let r of n){let o=r.alias??r.sessionId.slice(0,8);console.log(` ${d.accent(o.padEnd(24))} ${d.dim((r.project??"").slice(0,24).padEnd(26))} ${d.dim(r.startedAt??"")}`),console.log(` ${d.dim(`recall show ${r.sessionId}`)}`)}console.log("")}I();T();import{execFile as yb}from"node:child_process";import{promisify as Tb}from"node:util";import{stat as wb}from"node:fs/promises";var Rb=Tb(yb),xb=60,kb=7,Nb=7,Cb=5e3;function Lb(){let e=_(),t=s=>{try{return!!e.prepare(s).get()}catch{return!1}};return{semantic:t("SELECT 1 FROM session_semantic LIMIT 1"),cost:t(`SELECT 1 FROM sessions
1459
1459
  WHERE (COALESCE(total_input_tokens,0)
1460
1460
  + COALESCE(total_output_tokens,0)
1461
1461
  + COALESCE(total_cache_create_tokens,0)
1462
1462
  + COALESCE(total_cache_read_tokens,0)) > 0
1463
- LIMIT 1`),git:t("SELECT 1 FROM session_commits LIMIT 1")}}function wr(e){if(!e)return[];let t=new Set,s=[];for(let n of e.split(",")){let r=n.trim().toLowerCase();!r||t.has(r)||(t.add(r),s.push(r))}return s}function Kc(e){return{sessionId:e.session_id,project:e.project,alias:e.alias,startedAt:e.started_at,endedAt:e.ended_at,firstUserMessage:e.first_user_message}}function ob(){let e=_(),t=e.prepare(`SELECT ss.keywords
1463
+ LIMIT 1`),git:t("SELECT 1 FROM session_commits LIMIT 1")}}function Ar(e){if(!e)return[];let t=new Set,s=[];for(let n of e.split(",")){let r=n.trim().toLowerCase();!r||t.has(r)||(t.add(r),s.push(r))}return s}function cl(e){return{sessionId:e.session_id,project:e.project,alias:e.alias,startedAt:e.started_at,endedAt:e.ended_at,firstUserMessage:e.first_user_message}}function Ob(){let e=_(),t=e.prepare(`SELECT ss.keywords
1464
1464
  FROM session_semantic ss
1465
1465
  JOIN sessions s ON s.id = ss.session_id
1466
1466
  WHERE s.started_at IS NOT NULL
1467
- AND julianday('now') - julianday(s.started_at) <= @windowDays`).all({windowDays:tb});if(t.length===0)return null;let s=new Set;for(let o of t)for(let i of wr(o.keywords))s.add(i);if(s.size===0)return null;let n=e.prepare(`SELECT ss.session_id AS session_id,
1467
+ AND julianday('now') - julianday(s.started_at) <= @windowDays`).all({windowDays:kb});if(t.length===0)return null;let s=new Set;for(let o of t)for(let i of Ar(o.keywords))s.add(i);if(s.size===0)return null;let n=e.prepare(`SELECT ss.session_id AS session_id,
1468
1468
  ss.summary AS summary,
1469
1469
  ss.keywords AS keywords,
1470
1470
  p.name AS project,
@@ -1480,7 +1480,7 @@ Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u271
1480
1480
  WHERE s.started_at IS NOT NULL
1481
1481
  AND s.message_count > 2
1482
1482
  AND julianday('now') - julianday(s.started_at) >= @ageDays
1483
- ORDER BY s.started_at ASC`).all({ageDays:eb});if(n.length===0)return null;let r=null;for(let o of n){let a=wr(o.keywords).filter(l=>s.has(l));a.length!==0&&(!r||a.length>r.overlap.length)&&(r={row:o,overlap:a})}return r?{...Kc(r.row),summary:r.row.summary,keywords:wr(r.row.keywords),matchedKeywords:r.overlap,daysAgo:Math.max(0,Math.round(r.row.days_old))}:null}function ib(){let t=_().prepare(`SELECT s.id AS session_id,
1483
+ ORDER BY s.started_at ASC`).all({ageDays:xb});if(n.length===0)return null;let r=null;for(let o of n){let a=Ar(o.keywords).filter(l=>s.has(l));a.length!==0&&(!r||a.length>r.overlap.length)&&(r={row:o,overlap:a})}return r?{...cl(r.row),summary:r.row.summary,keywords:Ar(r.row.keywords),matchedKeywords:r.overlap,daysAgo:Math.max(0,Math.round(r.row.days_old))}:null}function Ab(){let t=_().prepare(`SELECT s.id AS session_id,
1484
1484
  p.name AS project,
1485
1485
  NULLIF(sa.alias, '') AS alias,
1486
1486
  s.started_at AS started_at,
@@ -1499,94 +1499,117 @@ Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u271
1499
1499
  AND (COALESCE(s.total_input_tokens, 0)
1500
1500
  + COALESCE(s.total_output_tokens, 0)
1501
1501
  + COALESCE(s.total_cache_create_tokens, 0)
1502
- + COALESCE(s.total_cache_read_tokens, 0)) > 0`).all({windowDays:sb});if(t.length===0)return null;let s=null;for(let n of t){let r=Ae({inputTokens:n.input_tokens,outputTokens:n.output_tokens,cacheCreateTokens:n.cache_create_tokens,cacheReadTokens:n.cache_read_tokens},n.primary_model);r.cents<=0||(!s||r.cents>s.cents)&&(s={row:n,cents:r.cents,totalTokens:r.totalTokens})}return s?{...Kc(s.row),totalTokens:s.totalTokens,costCents:s.cents,costDisplay:se(s.cents),tokensDisplay:le(s.totalTokens),primaryModel:s.row.primary_model,primaryModelLabel:Qe(s.row.primary_model).label}:null}async function ab(e){try{if(!(await ZE(e)).isDirectory())return null}catch{return null}try{let{stdout:t}=await QE("git",["rev-parse","HEAD"],{cwd:e,timeout:nb}),s=t.trim();return/^[0-9a-f]{40}$/.test(s)?s:null}catch{return null}}async function cb(){let e=_(),t=e.prepare(`SELECT s.id AS id, s.cwd AS cwd
1502
+ + COALESCE(s.total_cache_read_tokens, 0)) > 0`).all({windowDays:Nb});if(t.length===0)return null;let s=null;for(let n of t){let r=Ie({inputTokens:n.input_tokens,outputTokens:n.output_tokens,cacheCreateTokens:n.cache_create_tokens,cacheReadTokens:n.cache_read_tokens},n.primary_model);r.cents<=0||(!s||r.cents>s.cents)&&(s={row:n,cents:r.cents,totalTokens:r.totalTokens})}return s?{...cl(s.row),totalTokens:s.totalTokens,costCents:s.cents,costDisplay:se(s.cents),tokensDisplay:le(s.totalTokens),primaryModel:s.row.primary_model,primaryModelLabel:et(s.row.primary_model).label}:null}async function Ib(e){try{if(!(await wb(e)).isDirectory())return null}catch{return null}try{let{stdout:t}=await Rb("git",["rev-parse","HEAD"],{cwd:e,timeout:Cb}),s=t.trim();return/^[0-9a-f]{40}$/.test(s)?s:null}catch{return null}}async function vb(){let e=_(),t=e.prepare(`SELECT s.id AS id, s.cwd AS cwd
1503
1503
  FROM sessions s
1504
1504
  WHERE s.cwd IS NOT NULL AND s.started_at IS NOT NULL
1505
1505
  ORDER BY COALESCE(s.ended_at, s.started_at, '') DESC
1506
- LIMIT 1`).get();if(!t?.cwd)return null;let s=await ab(t.cwd);if(!s)return null;let n=$s(s);if(n.length===0)return null;let r=n[0],o=e.prepare(`SELECT s.first_user_message AS first_user_message, s.ended_at AS ended_at
1506
+ LIMIT 1`).get();if(!t?.cwd)return null;let s=await Ib(t.cwd);if(!s)return null;let n=Bs(s);if(n.length===0)return null;let r=n[0],o=e.prepare(`SELECT s.first_user_message AS first_user_message, s.ended_at AS ended_at
1507
1507
  FROM sessions s
1508
- WHERE s.id = ?`).get(r.sessionId);return{sessionId:r.sessionId,project:r.project,alias:r.alias,startedAt:r.startedAt,endedAt:o?.ended_at??r.endedAt,firstUserMessage:o?.first_user_message??null,commitSha:r.commitSha,shortSha:r.commitSha.slice(0,7),subject:r.subject,committedAt:r.committedAt,cwd:t.cwd}}async function qc(){let e=rb(),t=e.semantic?Promise.resolve().then(()=>{try{return ob()}catch(a){return console.error("[discover.rediscovered]",a),null}}):Promise.resolve(null),s=e.cost?Promise.resolve().then(()=>{try{return ib()}catch(a){return console.error("[discover.expensive]",a),null}}):Promise.resolve(null),n=e.git?cb().catch(a=>(console.error("[discover.authored]",a),null)):Promise.resolve(null),[r,o,i]=await Promise.all([t,s,n]);return{rediscovered:r,expensive:o,authored:i,availability:e,generatedAt:new Date().toISOString()}}function xr(e,t=60){if(!e)return"";let s=e.replace(/\s+/g," ").trim();return s.length<=t?s:s.slice(0,t-1)+"\u2026"}function Rr(e){return e.alias??(e.firstUserMessage?xr(e.firstUserMessage,60):null)??e.sessionId.slice(0,8)}function lb(e){let t=e.rediscovered||e.expensive||e.authored;if(console.log(""),console.log(d.bold("today \xB7 for you")),console.log(d.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),!t){let s=[];e.availability.semantic||s.push("v0.11 semantic (`recall semantic on`)"),e.availability.cost||s.push("v0.10a cost (`recall stats --backfill`)"),e.availability.git||s.push("v0.10b git (`recall correlate`)"),console.log(d.dim(" no picks today.")),s.length>0?console.log(d.dim(" enable: "+s.join(", "))):console.log(d.dim(" data sources are live but nothing matched \u2014 try again tomorrow.")),console.log("");return}if(e.rediscovered){let s=e.rediscovered;console.log(""),console.log(` ${d.tool("\u2726 rediscovered")} ${d.dim(`(${s.daysAgo}d ago)`)}`),console.log(` ${d.bold(Rr(s))} ${d.dim(s.project?`\xB7 ${s.project}`:"")}`),console.log(` ${d.dim(s.sessionId.slice(0,8))}`),s.matchedKeywords.length>0&&console.log(" "+d.dim("matched: ")+s.matchedKeywords.slice(0,6).map(n=>d.tool(`#${n}`)).join(" ")),s.summary&&console.log(" "+d.dim(xr(s.summary,100)))}if(e.expensive){let s=e.expensive;console.log(""),console.log(` ${d.accent("$ most expensive \xB7 7d")} ${d.bold(s.costDisplay)} ${d.dim(`(${s.tokensDisplay} \xB7 ${s.primaryModelLabel})`)}`),console.log(` ${d.bold(Rr(s))} ${d.dim(s.project?`\xB7 ${s.project}`:"")}`),console.log(` ${d.dim(s.sessionId.slice(0,8))} ${d.dim(s.startedAt?W(s.startedAt):"")}`)}if(e.authored){let s=e.authored;console.log(""),console.log(` ${d.ok("\u2387 authored current HEAD")} ${d.bold(s.shortSha)} ${d.dim(s.committedAt?`(${W(s.committedAt)})`:"")}`),console.log(` ${d.bold(Rr(s))} ${d.dim(s.project?`\xB7 ${s.project}`:"")}`),s.subject&&console.log(` ${d.dim(xr(s.subject,80))}`),console.log(` ${d.dim(s.sessionId.slice(0,8))} ${d.dim("cwd: "+s.cwd)}`)}console.log("")}async function Vc(e){let t=await qc();if(e.json){console.log(JSON.stringify(t,null,2));return}lb(t)}M();import{spawnSync as tl}from"node:child_process";import{readdirSync as db}from"node:fs";import{join as ub,resolve as pb}from"node:path";var kr=["code","cursor","code-insiders","windsurf"],Zc=[{id:"code",label:"VS Code"},{id:"cursor",label:"Cursor"},{id:"code-insiders",label:"VS Code Insiders"},{id:"windsurf",label:"Windsurf"}],mb="https://marketplace.visualstudio.com/items?itemName=clauderecallhq.clauderecall-vscode";function gb(){return ub(ye(),"extensions","vscode")}function fb(){let e=gb(),t;try{t=db(e)}catch{return null}let s=t.filter(n=>/^(clauderecall|claude-recall)-vscode-.*\.vsix$/i.test(n));return s.length===0?null:(s.sort((n,r)=>r.localeCompare(n,void 0,{numeric:!0})),pb(e,s[0]))}function Qc(e){let t=tl(e,["--version"],{stdio:"ignore",shell:process.platform==="win32"});return t.error?!1:t.status===0}function _b(e,t){let s=tl(e,["--install-extension",t],{stdio:"pipe",encoding:"utf8",shell:process.platform==="win32"});return s.error?{ok:!1,message:s.error.message}:s.status!==0?{ok:!1,message:(s.stderr??"").trim()||`exit code ${s.status??"null"}`}:{ok:!0,message:""}}function el(){process.stderr.write(d.err(`no bundled .vsix found at extensions/vscode/(clauderecall|claude-recall)-vscode-*.vsix
1508
+ WHERE s.id = ?`).get(r.sessionId);return{sessionId:r.sessionId,project:r.project,alias:r.alias,startedAt:r.startedAt,endedAt:o?.ended_at??r.endedAt,firstUserMessage:o?.first_user_message??null,commitSha:r.commitSha,shortSha:r.commitSha.slice(0,7),subject:r.subject,committedAt:r.committedAt,cwd:t.cwd}}async function ll(){let e=Lb(),t=e.semantic?Promise.resolve().then(()=>{try{return Ob()}catch(a){return console.error("[discover.rediscovered]",a),null}}):Promise.resolve(null),s=e.cost?Promise.resolve().then(()=>{try{return Ab()}catch(a){return console.error("[discover.expensive]",a),null}}):Promise.resolve(null),n=e.git?vb().catch(a=>(console.error("[discover.authored]",a),null)):Promise.resolve(null),[r,o,i]=await Promise.all([t,s,n]);return{rediscovered:r,expensive:o,authored:i,availability:e,generatedAt:new Date().toISOString()}}function vr(e,t=60){if(!e)return"";let s=e.replace(/\s+/g," ").trim();return s.length<=t?s:s.slice(0,t-1)+"\u2026"}function Ir(e){return e.alias??(e.firstUserMessage?vr(e.firstUserMessage,60):null)??e.sessionId.slice(0,8)}function Mb(e){let t=e.rediscovered||e.expensive||e.authored;if(console.log(""),console.log(d.bold("today \xB7 for you")),console.log(d.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),!t){let s=[];e.availability.semantic||s.push("v0.11 semantic (`recall semantic on`)"),e.availability.cost||s.push("v0.10a cost (`recall stats --backfill`)"),e.availability.git||s.push("v0.10b git (`recall correlate`)"),console.log(d.dim(" no picks today.")),s.length>0?console.log(d.dim(" enable: "+s.join(", "))):console.log(d.dim(" data sources are live but nothing matched \u2014 try again tomorrow.")),console.log("");return}if(e.rediscovered){let s=e.rediscovered;console.log(""),console.log(` ${d.tool("\u2726 rediscovered")} ${d.dim(`(${s.daysAgo}d ago)`)}`),console.log(` ${d.bold(Ir(s))} ${d.dim(s.project?`\xB7 ${s.project}`:"")}`),console.log(` ${d.dim(s.sessionId.slice(0,8))}`),s.matchedKeywords.length>0&&console.log(" "+d.dim("matched: ")+s.matchedKeywords.slice(0,6).map(n=>d.tool(`#${n}`)).join(" ")),s.summary&&console.log(" "+d.dim(vr(s.summary,100)))}if(e.expensive){let s=e.expensive;console.log(""),console.log(` ${d.accent("$ most expensive \xB7 7d")} ${d.bold(s.costDisplay)} ${d.dim(`(${s.tokensDisplay} \xB7 ${s.primaryModelLabel})`)}`),console.log(` ${d.bold(Ir(s))} ${d.dim(s.project?`\xB7 ${s.project}`:"")}`),console.log(` ${d.dim(s.sessionId.slice(0,8))} ${d.dim(s.startedAt?W(s.startedAt):"")}`)}if(e.authored){let s=e.authored;console.log(""),console.log(` ${d.ok("\u2387 authored current HEAD")} ${d.bold(s.shortSha)} ${d.dim(s.committedAt?`(${W(s.committedAt)})`:"")}`),console.log(` ${d.bold(Ir(s))} ${d.dim(s.project?`\xB7 ${s.project}`:"")}`),s.subject&&console.log(` ${d.dim(vr(s.subject,80))}`),console.log(` ${d.dim(s.sessionId.slice(0,8))} ${d.dim("cwd: "+s.cwd)}`)}console.log("")}async function dl(e){let t=await ll();if(e.json){console.log(JSON.stringify(t,null,2));return}Mb(t)}I();import{spawnSync as gl}from"node:child_process";import{readdirSync as Db}from"node:fs";import{join as $b,resolve as jb}from"node:path";var Mr=["code","cursor","code-insiders","windsurf"],ul=[{id:"code",label:"VS Code"},{id:"cursor",label:"Cursor"},{id:"code-insiders",label:"VS Code Insiders"},{id:"windsurf",label:"Windsurf"}],Pb="https://marketplace.visualstudio.com/items?itemName=clauderecallhq.clauderecall-vscode";function Fb(){return $b(Te(),"extensions","vscode")}function Ub(){let e=Fb(),t;try{t=Db(e)}catch{return null}let s=t.filter(n=>/^(clauderecall|claude-recall)-vscode-.*\.vsix$/i.test(n));return s.length===0?null:(s.sort((n,r)=>r.localeCompare(n,void 0,{numeric:!0})),jb(e,s[0]))}function ml(e){let t=gl(e,["--version"],{stdio:"ignore",shell:process.platform==="win32"});return t.error?!1:t.status===0}function Bb(e,t){let s=gl(e,["--install-extension",t],{stdio:"pipe",encoding:"utf8",shell:process.platform==="win32"});return s.error?{ok:!1,message:s.error.message}:s.status!==0?{ok:!1,message:(s.stderr??"").trim()||`exit code ${s.status??"null"}`}:{ok:!0,message:""}}function pl(){process.stderr.write(d.err(`no bundled .vsix found at extensions/vscode/(clauderecall|claude-recall)-vscode-*.vsix
1509
1509
  `)),process.stderr.write(d.dim(`see PUBLISHING.md for how to build the extension, or run:
1510
1510
  `)),process.stderr.write(d.dim(` (cd extensions/vscode && npm install && npm run build && npm run package)
1511
- `))}function hb(e){return kr.includes(e)}async function sl(e){if(e.editor!==void 0&&!hb(e.editor)){process.stderr.write(d.err(`unknown --editor target: ${e.editor}
1512
- `)),process.stderr.write(d.dim(`valid values: ${kr.join(", ")}
1513
- `)),process.exitCode=1;return}let t=fb();if(e.printPath){if(!t){el(),process.exitCode=1;return}process.stdout.write(t+`
1514
- `);return}if(!t){el(),process.exitCode=1;return}let s;if(e.editor){let r=e.editor;if(!Qc(r)){process.stderr.write(d.err(`editor CLI not found on PATH: ${r}
1511
+ `))}function Hb(e){return Mr.includes(e)}async function fl(e){if(e.editor!==void 0&&!Hb(e.editor)){process.stderr.write(d.err(`unknown --editor target: ${e.editor}
1512
+ `)),process.stderr.write(d.dim(`valid values: ${Mr.join(", ")}
1513
+ `)),process.exitCode=1;return}let t=Ub();if(e.printPath){if(!t){pl(),process.exitCode=1;return}process.stdout.write(t+`
1514
+ `);return}if(!t){pl(),process.exitCode=1;return}let s;if(e.editor){let r=e.editor;if(!ml(r)){process.stderr.write(d.err(`editor CLI not found on PATH: ${r}
1515
1515
  `)),process.stderr.write(d.dim(`install the editor shell integration, or omit --editor to install into every detected editor.
1516
1516
  `)),process.stderr.write(d.dim(`see PUBLISHING.md for manual install instructions.
1517
- `)),process.exitCode=1;return}s=[Zc.find(i=>i.id===r)??{id:r,label:r}]}else s=Zc.filter(r=>Qc(r.id));if(s.length===0){process.stderr.write(d.err(`no supported editor CLI detected on PATH.
1518
- `)),process.stderr.write(d.dim(`looked for: ${kr.join(", ")}.
1517
+ `)),process.exitCode=1;return}s=[ul.find(i=>i.id===r)??{id:r,label:r}]}else s=ul.filter(r=>ml(r.id));if(s.length===0){process.stderr.write(d.err(`no supported editor CLI detected on PATH.
1518
+ `)),process.stderr.write(d.dim(`looked for: ${Mr.join(", ")}.
1519
1519
  `)),process.stderr.write(d.dim(`install the editor shell integration and try again.
1520
1520
  `)),process.stderr.write(d.dim(`see PUBLISHING.md for manual install instructions.
1521
1521
  `)),process.exitCode=1;return}process.stderr.write(d.dim(`bundled .vsix: ${t}
1522
1522
 
1523
- `));let n=!1;for(let r of s){let{ok:o,message:i}=_b(r.id,t);o?process.stderr.write(d.ok(`\u2713 installed into ${r.label} (${r.id})
1523
+ `));let n=!1;for(let r of s){let{ok:o,message:i}=Bb(r.id,t);o?process.stderr.write(d.ok(`\u2713 installed into ${r.label} (${r.id})
1524
1524
  `)):(n=!0,process.stderr.write(d.err(`\u2717 ${r.label} (${r.id}): ${i}
1525
1525
  `)))}process.stderr.write(`
1526
1526
  `),process.stderr.write(d.bold(`next steps:
1527
1527
  `)),process.stderr.write(` 1. reload the editor window: Cmd/Ctrl+Shift+P then pick "Developer: Reload Window"
1528
1528
  `),process.stderr.write(` 2. enable the extension: open settings and set "claude-recall.autoAlias" to true
1529
1529
  `),process.stderr.write(`
1530
- `),process.stderr.write(d.dim(`marketplace install: ${mb}
1531
- `)),n&&(process.exitCode=1)}Or();M();function Ar(e){return e>=70?d.ok:e>=40?d.warn:d.err}function rl(e,t=20){let s=Math.round(e/100*t);return"\u2588".repeat(s)+"\u2591".repeat(t-s)}function Eb(e){let t=Ar(e.score);process.stdout.write(`
1530
+ `),process.stderr.write(d.dim(`marketplace install: ${Pb}
1531
+ `)),n&&(process.exitCode=1)}Pr();I();function Fr(e){return e>=70?d.ok:e>=40?d.warn:d.err}function hl(e,t=20){let s=Math.round(e/100*t);return"\u2588".repeat(s)+"\u2591".repeat(t-s)}function Wb(e){let t=Fr(e.score);process.stdout.write(`
1532
1532
  ${d.bold(e.projectName)} ${t(String(e.score)+"/100")}
1533
- `);let s=e.breakdown,n=[["Sessions",s.sessionCount.score*100,`${s.sessionCount.raw} sessions`],["Recency",s.recency.score*100,`${s.recency.daysSinceLastSession}d ago`],["Depth",s.fragmentation.score*100,`avg ${s.fragmentation.avgMessages} msgs`],["Search",s.searchCoverage.score*100,`${Math.round(s.searchCoverage.ratio*100)}% covered`],["Tags",s.tagCoverage.score*100,`${Math.round(s.tagCoverage.ratio*100)}% tagged`]];for(let[r,o,i]of n){let a=Ar(o);process.stdout.write(` ${r.padEnd(10)} ${a(rl(o,16))} ${String(Math.round(o)).padStart(3)}% ${d.dim(i)}
1534
- `)}}function ol(e,t){if(e){let r=Nr(e);if(!r){process.stderr.write(d.err(`project "${e}" not found
1533
+ `);let s=e.breakdown,n=[["Sessions",s.sessionCount.score*100,`${s.sessionCount.raw} sessions`],["Recency",s.recency.score*100,`${s.recency.daysSinceLastSession}d ago`],["Depth",s.fragmentation.score*100,`avg ${s.fragmentation.avgMessages} msgs`],["Search",s.searchCoverage.score*100,`${Math.round(s.searchCoverage.ratio*100)}% covered`],["Tags",s.tagCoverage.score*100,`${Math.round(s.tagCoverage.ratio*100)}% tagged`]];for(let[r,o,i]of n){let a=Fr(o);process.stdout.write(` ${r.padEnd(10)} ${a(hl(o,16))} ${String(Math.round(o)).padStart(3)}% ${d.dim(i)}
1534
+ `)}}function El(e,t){if(e){let r=$r(e);if(!r){process.stderr.write(d.err(`project "${e}" not found
1535
1535
  `)),process.exitCode=1;return}if(t.json){process.stdout.write(JSON.stringify(r,null,2)+`
1536
- `);return}Eb(r);return}let s=Lr();if(s.length===0){process.stdout.write("No projects found. Run `recall index` first.\n");return}if(t.json){process.stdout.write(JSON.stringify(s,null,2)+`
1536
+ `);return}Wb(r);return}let s=jr();if(s.length===0){process.stdout.write("No projects found. Run `recall index` first.\n");return}if(t.json){process.stdout.write(JSON.stringify(s,null,2)+`
1537
1537
  `);return}let n=[...s].sort((r,o)=>r.score-o.score);process.stdout.write(d.bold("Memory Health Scores")+` (worst first)
1538
1538
 
1539
- `);for(let r of n){let o=Ar(r.score);process.stdout.write(` ${o(rl(r.score,12))} ${String(r.score).padStart(3)}/100 ${r.projectName}
1539
+ `);for(let r of n){let o=Fr(r.score);process.stdout.write(` ${o(hl(r.score,12))} ${String(r.score).padStart(3)}/100 ${r.projectName}
1540
1540
  `)}process.stdout.write(`
1541
- `)}M();function il(e){if(e==="on"){_n(!0),process.stdout.write(d.ok("Verification badges enabled.")+`
1542
- `);return}if(e==="off"){_n(!1),process.stdout.write(`Verification badges disabled.
1543
- `);return}let t=ns();process.stdout.write(`Verification badges: ${t?d.ok("ON"):"OFF"}
1541
+ `)}I();function bl(e){if(e==="on"){kn(!0),process.stdout.write(d.ok("Verification badges enabled.")+`
1542
+ `);return}if(e==="off"){kn(!1),process.stdout.write(`Verification badges disabled.
1543
+ `);return}let t=as();process.stdout.write(`Verification badges: ${t?d.ok("ON"):"OFF"}
1544
1544
  `),process.stdout.write(`
1545
1545
  Toggle with: recall verify on | off
1546
- `)}M();Sn();En();Mt();bn();import{hostname as Hb}from"node:os";import{randomBytes as Wb}from"node:crypto";He();Se();j();T();import{existsSync as bb}from"node:fs";import Sb from"node:readline";import{createRequire as yb}from"node:module";import{Chalk as Tb}from"chalk";var wb=yb(import.meta.url),Rb=wb(`${ye()}/package.json`).version,dl="#f97316",xb="#8b9098",kb="#10b981",Cb="#f59e0b",wt=new Tb({level:process.env.NO_COLOR?0:3}),fe=wt.hex(dl),ne=wt.hex(dl).bold,A=wt.hex(xb),ht=wt.hex(kb),js=wt.hex(Cb),ul=wt.bold,pl=[" \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557","\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D","\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557 ","\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D ","\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557"," \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D","\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557 ","\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 ","\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 ","\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 ","\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557","\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D"],Nb=pl[0]?.length??49,al="Never lose a Claude Code session again.",Lb="CLAUDE RECALL";function Ob(){if(!bb(te))return{sessions:0,projects:0};try{let t=_().prepare(`SELECT
1546
+ `)}I();us();Cn();Pt();Ln();import{hostname as pS}from"node:os";import{randomBytes as gS}from"node:crypto";We();fe();j();T();import{existsSync as Xb}from"node:fs";import Jb from"node:readline";import{createRequire as Gb}from"node:module";import{Chalk as zb}from"chalk";var Yb=Gb(import.meta.url),Kb=Yb(`${Te()}/package.json`).version,wl="#f97316",qb="#8b9098",Vb="#10b981",Zb="#f59e0b",kt=new zb({level:process.env.NO_COLOR?0:3}),he=kt.hex(wl),ne=kt.hex(wl).bold,A=kt.hex(qb),Et=kt.hex(Vb),Hs=kt.hex(Zb),Rl=kt.bold,xl=[" \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557","\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D","\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557 ","\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D ","\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557"," \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D","\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557 ","\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 ","\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 ","\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 ","\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557","\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D"],Qb=xl[0]?.length??49,Sl="Never lose a Claude Code session again.",eS="CLAUDE RECALL";function tS(){if(!Xb(te))return{sessions:0,projects:0};try{let t=_().prepare(`SELECT
1547
1547
  (SELECT COUNT(*) FROM sessions) AS sessions,
1548
- (SELECT COUNT(*) FROM projects) AS projects`).get();return{sessions:t.sessions,projects:t.projects}}catch{return{sessions:0,projects:0}}}function Ab(){let e=process.stdout.columns;return typeof e!="number"||e<=0?!1:e<Nb+2}function ml(){if(Ab()){console.log(`${ne(Lb)} ${A("\xB7")} ${A(al)}`);return}for(let e of pl)console.log(ne(e));console.log(A(al))}async function Ib(){return{daemon:q(),counts:Ob(),license:await be()}}function vb(e){let t=[];if(t.push(` ${A("Version:")} ${fe(`v${Rb}`)} ${A("\xB7 CLI \xB7 @clauderecallhq/cli")}`),e.daemon){let s=`http://127.0.0.1:${e.daemon.port}`;t.push(` ${A("Daemon:")} ${ht("running")} on ${s} ${A(`(pid ${e.daemon.pid})`)}`)}else t.push(` ${A("Daemon:")} ${js("stopped")}`);if(e.counts.sessions===0)t.push(` ${A("Sessions:")} ${js("none indexed yet")}`);else{let s=e.counts.projects===1?"project":"projects";t.push(` ${A("Sessions:")} ${fe(String(e.counts.sessions))} indexed across ${fe(String(e.counts.projects))} ${s}`)}return e.license.tier==="pro"?t.push(` ${A("License:")} ${ht("Pro")}`):t.push(` ${A("License:")} Free`),t}function Mb(e){let t=fe(">");if(e.counts.sessions===0)return`${t} Run ${ne("recall index")} to scan ~/.claude/projects/`;if(!e.daemon)return`${t} Run ${ne("recall start")} to launch the local daemon`;if(e.license.tier==="free")return`${t} Run ${ne("recall upgrade")} to unlock Pro features`;let s=`http://127.0.0.1:${e.daemon.port}`;return`${t} Open ${fe(s)} in your browser ${A("\xB7")} or run ${ne("recall --help")} for all commands`}var Ps=[{title:"Setup",commands:[{name:"index",description:"Scan your Claude sessions and build the searchable database"},{name:"status",description:"Database size, session counts, and daemon state"},{name:"projects",description:"List every project with how many sessions are in each"},{name:"install-extension",description:"Install the VS Code / Cursor / Windsurf extension"},{name:"doctor",description:"Health check: DB size, WAL, FTS fragmentation, integrity, disk space, alias invariant"},{name:"optimize",description:"Maintenance: WAL checkpoint, FTS5 merge, planner stats. Add --vacuum to reclaim free pages"}]},{title:"Browse",commands:[{name:"tui",description:"Browse and search sessions in an interactive terminal UI"},{name:"list",description:"List your sessions, newest first"},{name:"show <id>",description:"Print a full session transcript"},{name:"search <query>",description:"Full-text search across every message"},{name:"similar <id>",description:"Find sessions about the same topic (Pro)"},{name:"semantic [action]",description:'Manage semantic search (defaults to "status")'},{name:"name <id> <name>",description:"Rename a session (or its terminal tab)"}]},{title:"Pipe to Claude",commands:[{name:"context <id>",description:"Pipe a past session as markdown into a fresh `claude` chat"},{name:"neighborhood <id>",description:"Bundle a session with its parents, children, and citations for richer context"}]},{title:"Threads",commands:[{name:"threads sync",description:"Capture sessions running in this repo right now into a thread"},{name:"threads sync --preflight",description:"Preview what `threads sync` would do without writing"},{name:"threads scan",description:"Auto-detect parent-child links across past sessions"},{name:"threads list",description:"List threads, newest first"},{name:"threads show <id>",description:"Show a thread's header and session tree"},{name:"threads new <name>",description:"Create a new thread"},{name:"threads link <id>",description:"Link a session into a thread"},{name:"threads unlink <id>",description:"Remove a session from a thread"},{name:"threads set-parent <id>",description:"Change a session's parent within a thread"},{name:"threads rename <id>",description:"Rename a thread"},{name:"threads close <id>",description:"Mark a thread as closed"},{name:"threads reopen <id>",description:"Reopen a closed thread"},{name:"threads archive <id>",description:"Archive a thread"},{name:"threads merge <id>",description:"Merge one thread into another"},{name:"threads split <id>",description:"Split sessions out into a new thread"}]},{title:"Inference",commands:[{name:"infer outputs",description:"Extract code, file, and error references from sessions in one project"},{name:"infer citations",description:"Find sessions that cite the same files or errors"},{name:"infer l1",description:"Fast deterministic link inference. No LLM cost"},{name:"infer links",description:"LLM-powered link classification (Pro). Optional --auto-promote"},{name:"infer bug-patterns",description:"Cluster sessions that hit the same bug"},{name:"embeddings [action]",description:'Audit embedding coverage (defaults to "audit")'}]},{title:"Analytics",commands:[{name:"stats [id]",description:"Token + dollar usage. No args = overview, pass a session for details"},{name:"health [project]",description:"Score how well-organized each project's sessions are"},{name:"digest",description:"Today's rediscovery picks and standouts"},{name:"correlate [id]",description:"Link sessions to the git commits they wrote"},{name:"blame <sha>",description:"Find which session(s) wrote the code in a commit"}]},{title:"Daemon",commands:[{name:"start",description:"Start the background daemon (live tab tracking + web UI)"},{name:"stop",description:"Stop the background daemon"},{name:"open",description:"Open the local web UI in your browser"}]},{title:"Sharing",commands:[{name:"share [id]",description:"Save a session as a shareable PNG card"},{name:"wrapped [month]",description:"Save a monthly recap as a PNG card"}]},{title:"Diagnostics",commands:[{name:"correlator audit",description:"Find sessions with bad terminal-name aliases (--fix to clear)"},{name:"correlator debug",description:"Show how the daemon is matching open terminals to sessions"},{name:"correlator restore",description:"Restore aliases that `correlator audit --fix` cleared"},{name:"titles [action]",description:'Audit session titles in the current project (defaults to "audit")'},{name:"import-vscode-state",description:"Backfill missing tab names from your editor's workspace state"},{name:"audit-secrets",description:"Scan the database for leaked secrets"}]},{title:"Integrations",commands:[{name:"mcp",description:"Expose Recall as an MCP server (for Claude Desktop / Claude Code)"},{name:"paste",description:"Save clipboard content (or stdin) into Recall"}]},{title:"Pro & License",commands:[{name:"upgrade",description:"Open the Pro pricing page"},{name:"activate <key>",description:"Activate your Pro license (run once after purchase)"},{name:"license [action]",description:"Show the current license. Use `license deactivate` to remove it"},{name:"verify [action]",description:'Toggle verification badges in the UI (defaults to "status")'}]},{title:"Feedback",commands:[{name:"feedback",description:"Send a 1-5 rating to the team. Pass --score for non-interactive use"}]}],Db=Ps.reduce((e,t)=>e+t.commands.length,0),$b=new Set([...Ps.flatMap(e=>e.commands.map(t=>t.name.split(/\s+/)[0])),"thread","correlator-audit","correlator-debug","correlator-restore","extract-outputs","infer-citations","infer-l1","infer-links","infer-bug-patterns"]);function cl(){let e=Ps.flatMap(s=>s.commands.map(n=>`recall ${n.name}`)),t=Math.max(...e.map(s=>s.length));console.log(),console.log(`${ul("COMMANDS")} ${A(`\xB7 ${Db} total \xB7 q to quit \xB7 recall --help for full details`)}`),console.log(` ${A("All commands run as subcommands of")} ${ne("recall")}${A(". There is no separate")} ${fe("threads")}${A(",")} ${fe("thread")}${A(", or")} ${fe("titles")} ${A("binary.")}`);for(let s of Ps){console.log(),console.log(` ${ne(s.title.toUpperCase())}`);for(let n of s.commands){let r=`recall ${n.name}`.padEnd(t," ");console.log(` ${fe(r)} ${A(n.description)}`)}}console.log()}function jb(){return!!process.stdin.isTTY&&!!process.stdout.isTTY}async function Pb(){if(!jb())return;let e=Sb.createInterface({input:process.stdin,output:process.stdout}),t=`${A("Type")} ${ne("/")} ${A("for commands, or press")} ${ne("Enter")} ${A("to exit")} ${fe("\u203A")} `;return new Promise(s=>{let n=()=>{e.question(t,r=>{let o=r.trim();if(o==="/"||o==="/help"||o==="help"||o==="?"){cl(),n();return}if(o===""||o==="q"||o==="quit"||o==="exit"){e.close();return}let i=o.startsWith("/")?o.slice(1).trimStart():o,a=i.toLowerCase();if((a==="recall"||a.startsWith("recall "))&&(i=i.slice(6).trimStart()),i===""){cl(),n();return}let l=(i.split(/\s+/)[0]??"").toLowerCase();$b.has(l)?console.log(` ${A("Run")} ${ne(`recall ${i}`)} ${A("in your shell to invoke that command.")}`):console.log(` ${A(`No command matches "${o}". Type`)} ${ne("/")} ${A("to browse, or")} ${ne("recall --help")} ${A("for the full list.")}`),n()})};e.on("close",()=>{console.log(),s()}),n()})}async function gl(){let e=await Ib();console.log(),ml(),console.log();for(let t of vb(e))console.log(t);console.log(),console.log(Mb(e)),console.log(),await Pb()}var Fb=[{name:"Unlimited search",detail:"full history, no caps"},{name:"Context for Claude",detail:"recall past sessions on demand"},{name:"MCP integration",detail:"native tool access from any client"},{name:"Semantic search",detail:"find by meaning, not just keywords"},{name:"Advanced UI",detail:"tags, aliases, notes, exports"}];function Ub(){return process.env.NO_COLOR||process.env.CI||process.env.RECALL_NO_ANIMATION?!1:!!process.stdout.isTTY}function Ir(e){return new Promise(t=>setTimeout(t,e))}function Bb(e){let s=(e.split("@")[0]??"").split(/[._+\-]/)[0]??"";return s?s.charAt(0).toUpperCase()+s.slice(1).toLowerCase():""}function ll(){process.stdout.write("\r\x1B[2K")}async function fl(e){let t=Ub();console.log(),ml(),console.log(),t&&(process.stdout.write(` ${A("Verifying license...")}`),await Ir(260),ll()),console.log(` ${ht("\u2713")} ${A("License verified")}`),console.log(` ${ht("\u2713")} ${A("Tier:")} ${ne("Pro")} ${A("\xB7 Lifetime")}`),console.log(` ${ht("\u2713")} ${A("Key:")} ${fe(e.key_short)}`),console.log(` ${ht("\u2713")} ${A("Email:")} ${e.email}`),e.test_mode&&console.log(` ${js("!")} ${js("Test mode:")} this license was issued in test mode.`),console.log(),console.log(` ${ul("Unlocking Pro features")}`),console.log();for(let r of Fb)t&&(process.stdout.write(` ${A("\xB7")} ${A(r.name)}`),await Ir(110),ll()),console.log(` ${ht("\u2713")} ${r.name} ${A(r.detail)}`);t&&await Ir(160),console.log();let s=Bb(e.email),n=s?`Welcome aboard, ${s}.`:"Welcome aboard.";console.log(` ${ne(n)}`),console.log(` ${A("Run")} ${fe("recall")} ${A("to open the dashboard, or")} ${fe("recall help")} ${A("for the command list.")}`),console.log()}async function _l(e){let t=e.trim();t.length<8&&(console.error(d.warn("License key looks too short. Paste the full key from your purchase email.")),process.exit(1));let s=`${Hb()}-${Wb(4).toString("hex")}`,n=`${as()}/api/license/activate`,r;try{r=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({license_key:t,instance_name:s,machine_fingerprint:is()})})}catch(a){let l=a instanceof Error?a.message:"unknown error";console.error(d.warn(`Could not reach activation server at ${n}: ${l}`)),console.error(d.dim("If you are offline, try again when you have a connection.")),process.exit(1)}let o;try{o=await r.json()}catch{console.error(d.warn(`Activation server returned invalid JSON (status ${r.status}).`)),process.exit(1)}if(r.status!==200||!o.license_jwt){let a=o.error??`activation failed (status ${r.status})`;console.error(d.warn(`Activation refused: ${a}`)),process.exit(1)}let i=await os(o.license_jwt);(!i.valid||!i.claims)&&(console.error(d.warn(`Server returned a JWT that fails local verification: ${i.reason??"unknown"}`)),console.error(d.dim("This usually means the CLI is older than the server, or the public key was rotated.")),process.exit(1)),Uo({license_jwt:o.license_jwt,license_key:t,key_short:o.key_short??i.claims.key_short,customer_email:o.customer_email??i.claims.email,activated_at:new Date().toISOString(),tier:"pro",test_mode:!!i.claims.test_mode}),await fl({...i.claims,key_short:o.key_short??i.claims.key_short,email:o.customer_email??i.claims.email})}M();import{spawn as Xb}from"node:child_process";import{platform as Fs}from"node:os";var hl="https://clauderecall.com/pricing";function Jb(e){let t=Fs()==="darwin"?"open":Fs()==="win32"?"start":"xdg-open",s=Fs()==="win32"?["",e]:[e];Xb(t,s,{detached:!0,stdio:"ignore",shell:Fs()==="win32"}).unref()}async function El(){let{getLicenseStatus:e}=await Promise.resolve().then(()=>(Se(),Ln)),t=await e();if(t.tier==="pro"){console.log(),console.log(d.bold("Already on Pro.")),console.log(` ${d.dim("Key:")} ${t.key_short}`),console.log(` ${d.dim("Email:")} ${t.customer_email}`),console.log();return}console.log(),console.log(`${d.ok("Opening")} ${hl}`),console.log(d.dim("After purchase, run: recall activate <license-key>")),console.log(),Jb(hl)}M();Se();Mt();Tn();async function bl(){let e=await be();if(console.log(),e.tier==="free"){console.log(d.bold("Tier: Free")),console.log(d.dim("Free includes: index, list, show, projects, status, the daemon, and the basic web UI.")),e.invalid_reason&&(console.log(),console.log(d.warn(`Stored license is invalid: ${e.invalid_reason}`))),console.log(),console.log("Buy Pro at https://clauderecall.com/pricing"),console.log("Then run: recall activate <license-key>"),console.log();return}console.log(d.bold("Tier: Pro")),console.log(` ${d.dim("Key:")} ${e.key_short}`),console.log(` ${d.dim("Email:")} ${e.customer_email}`),console.log(` ${d.dim("Activated:")} ${e.activated_at}`),e.expires_at&&console.log(` ${d.dim("Expires:")} ${e.expires_at}`),e.test_mode&&console.log(` ${d.warn("Test mode:")} this license was issued in test mode.`);let t=cs();t&&console.log(` ${d.dim("Last server check:")} ${t.last_checked_at}`),console.log()}async function Sl(){let e=await Nn({force:!0});if(console.log(),!e.ran){console.log(d.warn("No license stored on this machine.")),console.log(d.dim("Run `recall activate <license-key>` first.")),console.log();return}if(!e.last_checked_at){console.log(d.warn("Could not reach the license server.")),console.log(d.dim("Network error. Try again when you have a connection.")),console.log();return}if(e.revoked){console.log(d.warn("License is revoked.")),e.reason&&console.log(` ${d.dim("Reason:")} ${e.reason}`),console.log(` ${d.dim("Checked:")} ${e.last_checked_at}`),console.log();return}console.log(d.ok("License is valid.")),console.log(` ${d.dim("Checked:")} ${e.last_checked_at}`),console.log()}function yl(){Bo(),console.log(),console.log("License removed from this machine."),console.log(d.dim(`(${ut})`)),console.log()}T();M();import Gb from"cli-table3";function Ie(e){let t=_();if(e.length>=32){let n=t.prepare("SELECT id FROM threads WHERE id = ?").get(e);return n?n.id:(process.stderr.write(`thread not found: ${e}
1548
+ (SELECT COUNT(*) FROM projects) AS projects`).get();return{sessions:t.sessions,projects:t.projects}}catch{return{sessions:0,projects:0}}}function sS(){let e=process.stdout.columns;return typeof e!="number"||e<=0?!1:e<Qb+2}function kl(){if(sS()){console.log(`${ne(eS)} ${A("\xB7")} ${A(Sl)}`);return}for(let e of xl)console.log(ne(e));console.log(A(Sl))}async function nS(){return{daemon:q(),counts:tS(),license:await ye()}}function rS(e){let t=[];if(t.push(` ${A("Version:")} ${he(`v${Kb}`)} ${A("\xB7 CLI \xB7 @clauderecallhq/cli")}`),e.daemon){let s=`http://127.0.0.1:${e.daemon.port}`;t.push(` ${A("Daemon:")} ${Et("running")} on ${s} ${A(`(pid ${e.daemon.pid})`)}`)}else t.push(` ${A("Daemon:")} ${Hs("stopped")}`);if(e.counts.sessions===0)t.push(` ${A("Sessions:")} ${Hs("none indexed yet")}`);else{let s=e.counts.projects===1?"project":"projects";t.push(` ${A("Sessions:")} ${he(String(e.counts.sessions))} indexed across ${he(String(e.counts.projects))} ${s}`)}return e.license.tier==="pro"?t.push(` ${A("License:")} ${Et("Pro")}`):t.push(` ${A("License:")} Free`),t}function oS(e){let t=he(">");if(e.counts.sessions===0)return`${t} Run ${ne("recall index")} to scan ~/.claude/projects/`;if(!e.daemon)return`${t} Run ${ne("recall start")} to launch the local daemon`;if(e.license.tier==="free")return`${t} Run ${ne("recall upgrade")} to unlock Pro features`;let s=`http://127.0.0.1:${e.daemon.port}`;return`${t} Open ${he(s)} in your browser ${A("\xB7")} or run ${ne("recall --help")} for all commands`}var Ws=[{title:"Setup",commands:[{name:"index",description:"Scan your Claude sessions and build the searchable database"},{name:"status",description:"Database size, session counts, and daemon state"},{name:"projects",description:"List every project with how many sessions are in each"},{name:"install-extension",description:"Install the VS Code / Cursor / Windsurf extension"},{name:"doctor",description:"Health check: DB size, WAL, FTS fragmentation, integrity, disk space, alias invariant"},{name:"optimize",description:"Maintenance: WAL checkpoint, FTS5 merge, planner stats. Add --vacuum to reclaim free pages"}]},{title:"Browse",commands:[{name:"tui",description:"Browse and search sessions in an interactive terminal UI"},{name:"list",description:"List your sessions, newest first"},{name:"show <id>",description:"Print a full session transcript"},{name:"search <query>",description:"Full-text search across every message"},{name:"similar <id>",description:"Find sessions about the same topic (Pro)"},{name:"semantic [action]",description:'Manage semantic search (defaults to "status")'},{name:"name <id> <name>",description:"Rename a session (or its terminal tab)"}]},{title:"Pipe to Claude",commands:[{name:"context <id>",description:"Pipe a past session as markdown into a fresh `claude` chat"},{name:"neighborhood <id>",description:"Bundle a session with its parents, children, and citations for richer context"}]},{title:"Threads",commands:[{name:"threads sync",description:"Capture sessions running in this repo right now into a thread"},{name:"threads sync --preflight",description:"Preview what `threads sync` would do without writing"},{name:"threads scan",description:"Auto-detect parent-child links across past sessions"},{name:"threads list",description:"List threads, newest first"},{name:"threads show <id>",description:"Show a thread's header and session tree"},{name:"threads new <name>",description:"Create a new thread"},{name:"threads link <id>",description:"Link a session into a thread"},{name:"threads unlink <id>",description:"Remove a session from a thread"},{name:"threads set-parent <id>",description:"Change a session's parent within a thread"},{name:"threads rename <id>",description:"Rename a thread"},{name:"threads close <id>",description:"Mark a thread as closed"},{name:"threads reopen <id>",description:"Reopen a closed thread"},{name:"threads archive <id>",description:"Archive a thread"},{name:"threads merge <id>",description:"Merge one thread into another"},{name:"threads split <id>",description:"Split sessions out into a new thread"}]},{title:"Inference",commands:[{name:"infer outputs",description:"Extract code, file, and error references from sessions in one project"},{name:"infer citations",description:"Find sessions that cite the same files or errors"},{name:"infer l1",description:"Fast deterministic link inference. No LLM cost"},{name:"infer links",description:"LLM-powered link classification (Pro). Optional --auto-promote"},{name:"infer bug-patterns",description:"Cluster sessions that hit the same bug"},{name:"embeddings [action]",description:'Audit embedding coverage (defaults to "audit")'}]},{title:"Analytics",commands:[{name:"stats [id]",description:"Token + dollar usage. No args = overview, pass a session for details"},{name:"health [project]",description:"Score how well-organized each project's sessions are"},{name:"digest",description:"Today's rediscovery picks and standouts"},{name:"correlate [id]",description:"Link sessions to the git commits they wrote"},{name:"blame <sha>",description:"Find which session(s) wrote the code in a commit"}]},{title:"Daemon",commands:[{name:"start",description:"Start the background daemon (live tab tracking + web UI)"},{name:"stop",description:"Stop the background daemon"},{name:"open",description:"Open the local web UI in your browser"}]},{title:"Sharing",commands:[{name:"share [id]",description:"Save a session as a shareable PNG card"},{name:"wrapped [month]",description:"Save a monthly recap as a PNG card"}]},{title:"Diagnostics",commands:[{name:"correlator audit",description:"Find sessions with bad terminal-name aliases (--fix to clear)"},{name:"correlator debug",description:"Show how the daemon is matching open terminals to sessions"},{name:"correlator restore",description:"Restore aliases that `correlator audit --fix` cleared"},{name:"titles [action]",description:'Audit session titles in the current project (defaults to "audit")'},{name:"import-vscode-state",description:"Backfill missing tab names from your editor's workspace state"},{name:"audit-secrets",description:"Scan the database for leaked secrets"}]},{title:"Integrations",commands:[{name:"mcp",description:"Expose Recall as an MCP server (for Claude Desktop / Claude Code)"},{name:"paste",description:"Save clipboard content (or stdin) into Recall"}]},{title:"Pro & License",commands:[{name:"upgrade",description:"Open the Pro pricing page"},{name:"activate <key>",description:"Activate your Pro license (run once after purchase)"},{name:"license [action]",description:"Show the current license. Use `license deactivate` to remove it"},{name:"verify [action]",description:'Toggle verification badges in the UI (defaults to "status")'}]},{title:"Feedback",commands:[{name:"feedback",description:"Send a 1-5 rating to the team. Pass --score for non-interactive use"}]}],iS=Ws.reduce((e,t)=>e+t.commands.length,0),aS=new Set([...Ws.flatMap(e=>e.commands.map(t=>t.name.split(/\s+/)[0])),"thread","correlator-audit","correlator-debug","correlator-restore","extract-outputs","infer-citations","infer-l1","infer-links","infer-bug-patterns"]);function yl(){let e=Ws.flatMap(s=>s.commands.map(n=>`recall ${n.name}`)),t=Math.max(...e.map(s=>s.length));console.log(),console.log(`${Rl("COMMANDS")} ${A(`\xB7 ${iS} total \xB7 q to quit \xB7 recall --help for full details`)}`),console.log(` ${A("All commands run as subcommands of")} ${ne("recall")}${A(". There is no separate")} ${he("threads")}${A(",")} ${he("thread")}${A(", or")} ${he("titles")} ${A("binary.")}`);for(let s of Ws){console.log(),console.log(` ${ne(s.title.toUpperCase())}`);for(let n of s.commands){let r=`recall ${n.name}`.padEnd(t," ");console.log(` ${he(r)} ${A(n.description)}`)}}console.log()}function cS(){return!!process.stdin.isTTY&&!!process.stdout.isTTY}async function lS(){if(!cS())return;let e=Jb.createInterface({input:process.stdin,output:process.stdout}),t=`${A("Type")} ${ne("/")} ${A("for commands, or press")} ${ne("Enter")} ${A("to exit")} ${he("\u203A")} `;return new Promise(s=>{let n=()=>{e.question(t,r=>{let o=r.trim();if(o==="/"||o==="/help"||o==="help"||o==="?"){yl(),n();return}if(o===""||o==="q"||o==="quit"||o==="exit"){e.close();return}let i=o.startsWith("/")?o.slice(1).trimStart():o,a=i.toLowerCase();if((a==="recall"||a.startsWith("recall "))&&(i=i.slice(6).trimStart()),i===""){yl(),n();return}let l=(i.split(/\s+/)[0]??"").toLowerCase();aS.has(l)?console.log(` ${A("Run")} ${ne(`recall ${i}`)} ${A("in your shell to invoke that command.")}`):console.log(` ${A(`No command matches "${o}". Type`)} ${ne("/")} ${A("to browse, or")} ${ne("recall --help")} ${A("for the full list.")}`),n()})};e.on("close",()=>{console.log(),s()}),n()})}async function Nl(){let e=await nS();console.log(),kl(),console.log();for(let t of rS(e))console.log(t);console.log(),console.log(oS(e)),console.log(),await lS()}var dS=[{name:"Unlimited search",detail:"full history, no caps"},{name:"Context for Claude",detail:"recall past sessions on demand"},{name:"MCP integration",detail:"native tool access from any client"},{name:"Semantic search",detail:"find by meaning, not just keywords"},{name:"Advanced UI",detail:"tags, aliases, notes, exports"}];function uS(){return process.env.NO_COLOR||process.env.CI||process.env.RECALL_NO_ANIMATION?!1:!!process.stdout.isTTY}function Ur(e){return new Promise(t=>setTimeout(t,e))}function mS(e){let s=(e.split("@")[0]??"").split(/[._+\-]/)[0]??"";return s?s.charAt(0).toUpperCase()+s.slice(1).toLowerCase():""}function Tl(){process.stdout.write("\r\x1B[2K")}async function Cl(e){let t=uS();console.log(),kl(),console.log(),t&&(process.stdout.write(` ${A("Verifying license...")}`),await Ur(260),Tl()),console.log(` ${Et("\u2713")} ${A("License verified")}`),console.log(` ${Et("\u2713")} ${A("Tier:")} ${ne("Pro")} ${A("\xB7 Lifetime")}`),console.log(` ${Et("\u2713")} ${A("Key:")} ${he(e.key_short)}`),console.log(` ${Et("\u2713")} ${A("Email:")} ${e.email}`),e.test_mode&&console.log(` ${Hs("!")} ${Hs("Test mode:")} this license was issued in test mode.`),console.log(),console.log(` ${Rl("Unlocking Pro features")}`),console.log();for(let r of dS)t&&(process.stdout.write(` ${A("\xB7")} ${A(r.name)}`),await Ur(110),Tl()),console.log(` ${Et("\u2713")} ${r.name} ${A(r.detail)}`);t&&await Ur(160),console.log();let s=mS(e.email),n=s?`Welcome aboard, ${s}.`:"Welcome aboard.";console.log(` ${ne(n)}`),console.log(` ${A("Run")} ${he("recall")} ${A("to open the dashboard, or")} ${he("recall help")} ${A("for the command list.")}`),console.log()}async function Ll(e){let t=e.trim();t.length<8&&(console.error(d.warn("License key looks too short. Paste the full key from your purchase email.")),process.exit(1));let s=`${pS()}-${gS(4).toString("hex")}`,n=`${Rt()}/api/license/activate`,r;try{r=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({license_key:t,instance_name:s,machine_fingerprint:ds()})})}catch(a){let l=a instanceof Error?a.message:"unknown error";console.error(d.warn(`Could not reach activation server at ${n}: ${l}`)),console.error(d.dim("If you are offline, try again when you have a connection.")),process.exit(1)}let o;try{o=await r.json()}catch{console.error(d.warn(`Activation server returned invalid JSON (status ${r.status}).`)),process.exit(1)}if(r.status!==200||!o.license_jwt){let a=o.error??`activation failed (status ${r.status})`;console.error(d.warn(`Activation refused: ${a}`)),process.exit(1)}let i=await ls(o.license_jwt);(!i.valid||!i.claims)&&(console.error(d.warn(`Server returned a JWT that fails local verification: ${i.reason??"unknown"}`)),console.error(d.dim("This usually means the CLI is older than the server, or the public key was rotated.")),process.exit(1)),Qo({license_jwt:o.license_jwt,license_key:t,key_short:o.key_short??i.claims.key_short,customer_email:o.customer_email??i.claims.email,activated_at:new Date().toISOString(),tier:"pro",test_mode:!!i.claims.test_mode}),await Cl({...i.claims,key_short:o.key_short??i.claims.key_short,email:o.customer_email??i.claims.email})}I();import{spawn as fS}from"node:child_process";import{platform as Xs}from"node:os";var Ol="https://clauderecall.com/pricing";function _S(e){let t=Xs()==="darwin"?"open":Xs()==="win32"?"start":"xdg-open",s=Xs()==="win32"?["",e]:[e];fS(t,s,{detached:!0,stdio:"ignore",shell:Xs()==="win32"}).unref()}async function Al(){let{getLicenseStatus:e}=await Promise.resolve().then(()=>(fe(),ps)),t=await e();if(t.tier==="pro"){console.log(),console.log(d.bold("Already on Pro.")),console.log(` ${d.dim("Key:")} ${t.key_short}`),console.log(` ${d.dim("Email:")} ${t.customer_email}`),console.log();return}console.log(),console.log(`${d.ok("Opening")} ${Ol}`),console.log(d.dim("After purchase, run: recall activate <license-key>")),console.log(),_S(Ol)}I();import{spawn as hS}from"node:child_process";import{platform as Js}from"node:os";var Il="https://clauderecall.com/pricing?trial=1&utm_source=cli&utm_medium=recall_trial";function ES(e){let t=Js()==="darwin"?"open":Js()==="win32"?"start":"xdg-open",s=Js()==="win32"?["",e]:[e];hS(t,s,{detached:!0,stdio:"ignore",shell:Js()==="win32"}).unref()}async function vl(){let{getLicenseStatus:e}=await Promise.resolve().then(()=>(fe(),ps)),t=await e();if(t.tier==="pro"){console.log(),console.log(d.bold("You are already on Pro.")),console.log(` ${d.dim("Key:")} ${t.key_short}`),console.log(` ${d.dim("Email:")} ${t.customer_email}`),console.log();return}console.log(),console.log(`${d.ok("Opening")} ${Il}`),console.log(d.dim("Enter your email to get a 7-day Pro trial link. No card.")),console.log(d.dim("After you click the verification email, run: recall activate <key>")),console.log(),ES(Il)}I();import{createRequire as xS}from"module";us();import{existsSync as Ml,mkdirSync as bS,readFileSync as SS,writeFileSync as yS}from"node:fs";import{homedir as TS}from"node:os";import{join as Dl}from"node:path";import{randomBytes as wS}from"node:crypto";var Hr=Dl(TS(),".recall"),zs=Dl(Hr,"telemetry.json"),Br={decided_at:null,decision:null,last_ping_month:null,nonce_month:null,nonce:null,last_error:null};function bt(){if(!Ml(zs))return{...Br};try{let e=SS(zs,"utf8"),t=JSON.parse(e);return{...Br,...t}}catch{return{...Br}}}function Gs(e){Ml(Hr)||bS(Hr,{recursive:!0}),yS(zs,JSON.stringify(e,null,2)+`
1549
+ `,{mode:384})}function $l(){return zs}function Wr(e=new Date){let t=e.getUTCFullYear(),s=String(e.getUTCMonth()+1).padStart(2,"0");return`${t}-${s}`}function jl(e,t){return e.nonce&&e.nonce_month===t?e:{...e,nonce:wS(16).toString("hex"),nonce_month:t}}function RS(e,t){return!t.nonce||!t.nonce_month?null:{event:"install",version:e,platform:process.platform,arch:process.arch,month:t.nonce_month,nonce:t.nonce}}async function Pl(e){let t=bt();if(t.decision!=="on")return{status:t.decision==="off"?"opted-out":"no-decision"};let s=Wr();if(t.last_ping_month===s)return{status:"already-this-month"};t=jl(t,s);let n=RS(e,t);if(!n)return{status:"error",detail:"no nonce"};try{let r=await fetch(`${Rt()}/api/install-ping`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n),signal:AbortSignal.timeout(5e3)});if(!r.ok){let i=`http ${r.status}`;return Gs({...t,last_error:`${new Date().toISOString()} ${i}`}),{status:"error",detail:i}}let o=await r.json().catch(()=>({}));return Gs({...t,last_ping_month:s,last_error:null}),{status:o.deduped?"deduped":"sent"}}catch(r){let o=r instanceof Error?r.message:"unknown";return Gs({...t,last_error:`${new Date().toISOString()} ${o}`}),{status:"error",detail:o}}}function Nt(e){let s={...bt(),decision:e,decided_at:new Date().toISOString(),last_error:null,...e==="off"?{nonce:null,nonce_month:null,last_ping_month:null}:{}};return Gs(s),s}function Ys(e){let t=jl(bt(),Wr());return{event:"install",version:e,platform:process.platform,arch:process.arch,month:t.nonce_month??Wr(),nonce:t.nonce??"0".repeat(32)}}var kS=xS(import.meta.url),NS=kS("../package.json").version;async function Xr(){let e=bt();console.log(),console.log(d.bold("Telemetry \u2014 anonymous install ping")),console.log(` ${d.dim("decision:")} ${e.decision??"not yet decided"}`),console.log(` ${d.dim("decided at:")} ${e.decided_at??"\u2014"}`),console.log(` ${d.dim("last ping:")} ${e.last_ping_month??"\u2014"}`),console.log(` ${d.dim("state file:")} ${$l()}`),e.last_error&&console.log(` ${d.warn("last error:")} ${e.last_error}`),console.log(),console.log(d.dim("Next-ping payload preview (only sent if decision = on):")),console.log(d.dim(JSON.stringify(Ys(NS),null,2))),console.log(),console.log(d.dim("Toggle with `recall telemetry on` / `recall telemetry off`.")),console.log(d.dim("Full disclosure: https://clauderecall.com/telemetry")),console.log()}async function Fl(){Nt("on"),console.log(),console.log(d.ok("Telemetry: opted in.")),console.log(d.dim("One anonymous ping per machine per month. No PII. Source: docs/specs/v0.16-install-ping.md")),console.log(d.dim("Reverse with `recall telemetry off`.")),console.log()}async function Ul(){Nt("off"),console.log(),console.log(d.ok("Telemetry: opted out.")),console.log(d.dim("No further pings will be sent. Existing nonce deleted.")),console.log()}async function Bl(){await Xr()}import{createInterface as CS}from"node:readline/promises";import{stdin as Hl,stdout as ue}from"node:process";var LS=new Set(["telemetry","trial","upgrade","activate","license","help","version"]);function OS(e){return!(process.env.CI==="true"||process.env.RECALL_QUIET_INSTALL==="1"||process.env.RECALL_DISABLE_TELEMETRY_PROMPT==="1"||!Hl.isTTY||!ue.isTTY||e&&LS.has(e)||bt().decision!==null)}async function Wl(e,t){if(!OS(e))return;let s=Ys(t);ue.write(`
1550
+ `),ue.write(` Claude Recall \u2014 anonymous install ping?
1551
+
1552
+ `),ue.write(` npm download counts mix real installs with bots and scanners.
1553
+ `),ue.write(` We have no way to tell them apart without your help.
1554
+
1555
+ `),ue.write(` If you say yes, we send ONE message, ONE time per month:
1556
+
1557
+ `),ue.write(` ${JSON.stringify(s)}
1558
+
1559
+ `),ue.write(` Never sent: email, IP, fingerprint, file paths, file content,
1560
+ `),ue.write(` session content, license key. Reverse any time with:
1561
+ `),ue.write(` recall telemetry off
1562
+
1563
+ `),ue.write(` Full disclosure: https://clauderecall.com/telemetry
1564
+
1565
+ `);let n=CS({input:Hl,output:ue}),r;try{r=(await n.question(" Send the install ping? [y/N]: ")).trim().toLowerCase()}finally{n.close()}r==="y"||r==="yes"?(Nt("on"),ue.write(`
1566
+ Opted in. Reverse any time with \`recall telemetry off\`.
1567
+
1568
+ `)):(Nt("off"),ue.write(`
1569
+ Opted out. No pings will be sent. Reverse with \`recall telemetry on\`.
1570
+
1571
+ `))}I();fe();Pt();An();async function Xl(){let e=await ye();if(console.log(),e.tier==="free"){console.log(d.bold("Tier: Free")),console.log(d.dim("Free includes: index, list, show, projects, status, the daemon, and the basic web UI.")),e.invalid_reason&&(console.log(),console.log(d.warn(`Stored license is invalid: ${e.invalid_reason}`))),console.log(),console.log("Buy Pro at https://clauderecall.com/pricing"),console.log("Then run: recall activate <license-key>"),console.log();return}console.log(d.bold("Tier: Pro")),console.log(` ${d.dim("Key:")} ${e.key_short}`),console.log(` ${d.dim("Email:")} ${e.customer_email}`),console.log(` ${d.dim("Activated:")} ${e.activated_at}`),e.expires_at&&console.log(` ${d.dim("Expires:")} ${e.expires_at}`),e.test_mode&&console.log(` ${d.warn("Test mode:")} this license was issued in test mode.`);let t=ms();t&&console.log(` ${d.dim("Last server check:")} ${t.last_checked_at}`),console.log()}async function Jl(){let e=await jn({force:!0});if(console.log(),!e.ran){console.log(d.warn("No license stored on this machine.")),console.log(d.dim("Run `recall activate <license-key>` first.")),console.log();return}if(!e.last_checked_at){console.log(d.warn("Could not reach the license server.")),console.log(d.dim("Network error. Try again when you have a connection.")),console.log();return}if(e.revoked){console.log(d.warn("License is revoked.")),e.reason&&console.log(` ${d.dim("Reason:")} ${e.reason}`),console.log(` ${d.dim("Checked:")} ${e.last_checked_at}`),console.log();return}console.log(d.ok("License is valid.")),console.log(` ${d.dim("Checked:")} ${e.last_checked_at}`),console.log()}function Gl(){ei(),console.log(),console.log("License removed from this machine."),console.log(d.dim(`(${mt})`)),console.log()}T();I();import AS from"cli-table3";function ve(e){let t=_();if(e.length>=32){let n=t.prepare("SELECT id FROM threads WHERE id = ?").get(e);return n?n.id:(process.stderr.write(`thread not found: ${e}
1549
1572
  `),null)}let s=t.prepare("SELECT id, name FROM threads WHERE id LIKE ? ORDER BY created_at DESC").all(e+"%");if(s.length===1)return s[0].id;if(s.length===0)return process.stderr.write(`no thread matches prefix "${e}"
1550
1573
  `),null;process.stderr.write(`ambiguous thread prefix "${e}" \u2014 candidates:
1551
1574
  `);for(let n of s)process.stderr.write(` ${H(n.id)} ${n.name}
1552
- `);return null}function Et(e){let t=_();if(e.length>=32){let n=t.prepare("SELECT id FROM sessions WHERE id = ?").get(e);return n?n.id:(process.stderr.write(`session not found: ${e}
1575
+ `);return null}function St(e){let t=_();if(e.length>=32){let n=t.prepare("SELECT id FROM sessions WHERE id = ?").get(e);return n?n.id:(process.stderr.write(`session not found: ${e}
1553
1576
  `),null)}let s=t.prepare("SELECT id FROM sessions WHERE id LIKE ? LIMIT 2").all(e+"%");return s.length===1?s[0].id:s.length===0?(process.stderr.write(`no session matches prefix "${e}"
1554
1577
  `),null):(process.stderr.write(`ambiguous session prefix "${e}". be more specific.
1555
- `),null)}function zb(e){let t=new Map;if(e.length===0)return t;let s=e.map(()=>"?").join(","),r=_().prepare(`SELECT s.id,
1578
+ `),null)}function IS(e){let t=new Map;if(e.length===0)return t;let s=e.map(()=>"?").join(","),r=_().prepare(`SELECT s.id,
1556
1579
  s.first_user_message,
1557
1580
  p.name AS project_name,
1558
1581
  a.alias AS alias
1559
1582
  FROM sessions s
1560
1583
  LEFT JOIN projects p ON p.id = s.project_id
1561
1584
  LEFT JOIN session_aliases a ON a.session_id = s.id
1562
- WHERE s.id IN (${s})`).all(...e);for(let o of r)t.set(o.id,o);return t}function Tl(e,t){let s=t.get(e),n=d.accent(H(e));if(!s)return`${n} ${d.dim("(unindexed)")}`;let r=s.alias??s.first_user_message??"",o=s.project_name?d.project(`[${s.project_name}] `):"";return`${n} ${o}${Y(r,80)}`}function vr(e){return e.archived?"archived":e.closed_at?"closed":"open"}function Rt(e){let t=vr(e);process.stderr.write(d.ok(`\u2713 ${e.name} ${d.dim(`(${H(e.id)})`)} [${t}]
1563
- `))}function we(e,t,s){if(e){process.stdout.write(JSON.stringify(t,null,2)+`
1564
- `);return}s()}function wl(e){let t=Dn({includeArchived:e.archived===!0});we(e.json===!0,t,()=>{if(t.length===0){console.log(d.dim("no threads. create one with `recall thread new <name>`."));return}let s=new Gb({head:[d.bold("id"),d.bold("name"),d.bold("sessions"),d.bold("origins"),d.bold("status"),d.bold("created")],colWidths:[10,40,10,9,10,16],wordWrap:!0,style:{head:[],border:["grey"]}});for(let n of t)s.push([d.accent(H(n.id)),Y(n.name,38),String(n.session_count),String(n.origin_count),vr(n),d.dim(W(n.created_at))]);console.log(s.toString()),console.log(d.dim(`${t.length} thread${t.length===1?"":"s"}.`+(e.archived?"":" add --archived to include archived.")))})}function Yb(e,t){let s=new Set(e.edges.map(a=>a.session_id)),n=new Map,r=[];for(let a of e.edges){let l=a.parent_session_id;if(a.role==="origin"||!l||!s.has(l)){r.push(a);continue}let c=n.get(l)??[];c.push(a),n.set(l,c)}let o=new Set,i=(a,l,c,u)=>{if(o.has(a.session_id))return;o.add(a.session_id);let p=u?"":c?"\u2514\u2500 ":"\u251C\u2500 ",m=a.role==="origin"?d.warn("[origin] "):"";process.stdout.write(`${l}${p}${m}${Tl(a.session_id,t)}
1565
- `);let f=n.get(a.session_id)??[],g=u?"":l+(c?" ":"\u2502 ");f.forEach((h,E)=>{i(h,g,E===f.length-1,!1)})};r.forEach((a,l)=>i(a,"",l===r.length-1,!0));for(let a of e.edges)o.has(a.session_id)||process.stdout.write(`${d.warn("? ")}${Tl(a.session_id,t)}
1566
- `)}function Rl(e,t){let s=Ie(e);if(!s){process.exitCode=1;return}let n=Le(s);if(!n){process.stderr.write(`thread not found: ${e}
1567
- `),process.exitCode=1;return}let r=zb(n.edges.map(o=>o.session_id));we(t.json===!0,n,()=>{let o=vr(n);if(console.log(d.bold(n.name)),console.log(d.dim(`id ${H(n.id)} \xB7 ${o} \xB7 ${n.session_count} session${n.session_count===1?"":"s"} \xB7 ${n.origin_count} origin${n.origin_count===1?"":"s"} \xB7 created ${W(n.created_at)}`)),n.summary&&console.log(n.summary),console.log(),n.edges.length===0){console.log(d.dim("(no sessions linked \u2014 use `recall thread link ...`)"));return}Yb(n,r)})}function xl(e,t){let s;if(t.origin){let r=Et(t.origin);if(!r){process.exitCode=1;return}s=r}let n=fi({name:e,summary:t.summary??null,originSessionId:s});we(t.json===!0,n,()=>{Rt(n),process.stderr.write(d.dim(`id ${n.id}
1585
+ WHERE s.id IN (${s})`).all(...e);for(let o of r)t.set(o.id,o);return t}function zl(e,t){let s=t.get(e),n=d.accent(H(e));if(!s)return`${n} ${d.dim("(unindexed)")}`;let r=s.alias??s.first_user_message??"",o=s.project_name?d.project(`[${s.project_name}] `):"";return`${n} ${o}${Y(r,80)}`}function Jr(e){return e.archived?"archived":e.closed_at?"closed":"open"}function Ct(e){let t=Jr(e);process.stderr.write(d.ok(`\u2713 ${e.name} ${d.dim(`(${H(e.id)})`)} [${t}]
1586
+ `))}function Re(e,t,s){if(e){process.stdout.write(JSON.stringify(t,null,2)+`
1587
+ `);return}s()}function Yl(e){let t=Wn({includeArchived:e.archived===!0});Re(e.json===!0,t,()=>{if(t.length===0){console.log(d.dim("no threads. create one with `recall thread new <name>`."));return}let s=new AS({head:[d.bold("id"),d.bold("name"),d.bold("sessions"),d.bold("origins"),d.bold("status"),d.bold("created")],colWidths:[10,40,10,9,10,16],wordWrap:!0,style:{head:[],border:["grey"]}});for(let n of t)s.push([d.accent(H(n.id)),Y(n.name,38),String(n.session_count),String(n.origin_count),Jr(n),d.dim(W(n.created_at))]);console.log(s.toString()),console.log(d.dim(`${t.length} thread${t.length===1?"":"s"}.`+(e.archived?"":" add --archived to include archived.")))})}function vS(e,t){let s=new Set(e.edges.map(a=>a.session_id)),n=new Map,r=[];for(let a of e.edges){let l=a.parent_session_id;if(a.role==="origin"||!l||!s.has(l)){r.push(a);continue}let c=n.get(l)??[];c.push(a),n.set(l,c)}let o=new Set,i=(a,l,c,u)=>{if(o.has(a.session_id))return;o.add(a.session_id);let m=u?"":c?"\u2514\u2500 ":"\u251C\u2500 ",p=a.role==="origin"?d.warn("[origin] "):"";process.stdout.write(`${l}${m}${p}${zl(a.session_id,t)}
1588
+ `);let f=n.get(a.session_id)??[],g=u?"":l+(c?" ":"\u2502 ");f.forEach((h,E)=>{i(h,g,E===f.length-1,!1)})};r.forEach((a,l)=>i(a,"",l===r.length-1,!0));for(let a of e.edges)o.has(a.session_id)||process.stdout.write(`${d.warn("? ")}${zl(a.session_id,t)}
1589
+ `)}function Kl(e,t){let s=ve(e);if(!s){process.exitCode=1;return}let n=Oe(s);if(!n){process.stderr.write(`thread not found: ${e}
1590
+ `),process.exitCode=1;return}let r=IS(n.edges.map(o=>o.session_id));Re(t.json===!0,n,()=>{let o=Jr(n);if(console.log(d.bold(n.name)),console.log(d.dim(`id ${H(n.id)} \xB7 ${o} \xB7 ${n.session_count} session${n.session_count===1?"":"s"} \xB7 ${n.origin_count} origin${n.origin_count===1?"":"s"} \xB7 created ${W(n.created_at)}`)),n.summary&&console.log(n.summary),console.log(),n.edges.length===0){console.log(d.dim("(no sessions linked \u2014 use `recall thread link ...`)"));return}vS(n,r)})}function ql(e,t){let s;if(t.origin){let r=St(t.origin);if(!r){process.exitCode=1;return}s=r}let n=Ci({name:e,summary:t.summary??null,originSessionId:s});Re(t.json===!0,n,()=>{Ct(n),process.stderr.write(d.dim(`id ${n.id}
1568
1591
  `)),s&&process.stderr.write(d.dim(`origin: ${H(s)}
1569
- `))})}function kl(e,t){let s=Ie(t.thread);if(!s){process.exitCode=1;return}let n=Et(e);if(!n){process.exitCode=1;return}let r=null;if(t.parent){let a=Et(t.parent);if(!a){process.exitCode=1;return}r=a}let o=t.role??(r?"child":"origin"),i=_i({threadId:s,sessionId:n,parentSessionId:r,role:o});we(t.json===!0,i,()=>{process.stderr.write(d.ok(`\u2713 linked ${H(n)} \u2192 ${H(s)} [${o}]
1570
- `))})}function Cl(e,t){let s=Ie(t.thread);if(!s){process.exitCode=1;return}let n=Et(e);if(!n){process.exitCode=1;return}let r=hi(s,n);we(t.json===!0,r,()=>{if(r.removed===0){process.stderr.write(d.warn(`(no edge existed for ${H(n)} in ${H(s)})
1592
+ `))})}function Vl(e,t){let s=ve(t.thread);if(!s){process.exitCode=1;return}let n=St(e);if(!n){process.exitCode=1;return}let r=null;if(t.parent){let a=St(t.parent);if(!a){process.exitCode=1;return}r=a}let o=t.role??(r?"child":"origin"),i=Li({threadId:s,sessionId:n,parentSessionId:r,role:o});Re(t.json===!0,i,()=>{process.stderr.write(d.ok(`\u2713 linked ${H(n)} \u2192 ${H(s)} [${o}]
1593
+ `))})}function Zl(e,t){let s=ve(t.thread);if(!s){process.exitCode=1;return}let n=St(e);if(!n){process.exitCode=1;return}let r=Oi(s,n);Re(t.json===!0,r,()=>{if(r.removed===0){process.stderr.write(d.warn(`(no edge existed for ${H(n)} in ${H(s)})
1571
1594
  `));return}process.stderr.write(d.ok(`\u2713 unlinked ${H(n)} from ${H(s)}
1572
- `))})}function Nl(e,t){let s=Ie(t.thread);if(!s){process.exitCode=1;return}let n=Et(e);if(!n){process.exitCode=1;return}let r=null;if(t.parent&&t.parent.toLowerCase()!=="none"){let i=Et(t.parent);if(!i){process.exitCode=1;return}r=i}let o=Ei(s,n,r);we(t.json===!0,o,()=>{process.stderr.write(d.ok(`\u2713 ${H(n)} in ${H(s)} \u2192 `+(r?`child of ${H(r)}`:"origin")+`
1573
- `))})}function Ll(e,t,s){let n=Ie(e);if(!n){process.exitCode=1;return}let r=bi(n,t);we(s.json===!0,r,()=>Rt(r))}function Ol(e,t){let s=Ie(e);if(!s){process.exitCode=1;return}let n=Si(s);we(t.json===!0,n,()=>Rt(n))}function Al(e,t){let s=Ie(e);if(!s){process.exitCode=1;return}let n=yi(s);we(t.json===!0,n,()=>Rt(n))}function Il(e,t){let s=Ie(e);if(!s){process.exitCode=1;return}let n=Ti(s);we(t.json===!0,n,()=>Rt(n))}function vl(e,t){let s=Ie(e);if(!s){process.exitCode=1;return}let n=Ie(t.into);if(!n){process.exitCode=1;return}if(s===n){process.stderr.write(d.err(`cannot merge a thread into itself
1574
- `)),process.exitCode=1;return}let r=wi(s,n);we(t.json===!0,r,()=>{process.stderr.write(d.ok(`\u2713 merged ${H(s)} \u2192 ${H(n)} (${r.session_count} sessions)
1575
- `))})}function Ml(e,t){let s=Ie(e);if(!s){process.exitCode=1;return}let n=t.sessions.split(",").map(i=>i.trim()).filter(Boolean);if(n.length===0){process.stderr.write(d.err(`--sessions must be a non-empty comma-separated list
1576
- `)),process.exitCode=1;return}let r=[];for(let i of n){let a=Et(i);if(!a){process.exitCode=1;return}r.push(a)}let o=Ri({threadId:s,sessionIds:r,newThreadName:t.name});we(t.json===!0,o,()=>{Rt(o),process.stderr.write(d.dim(`split off ${r.length} session${r.length===1?"":"s"} from ${H(s)}
1577
- `))})}T();M();import{randomUUID as hS}from"node:crypto";import{readFileSync as Kb,statSync as qb}from"node:fs";var Vb=200*1024*1024,Dr=.7,$r=.5,jl=$r,Zb=[{maxGapMs:3600*1e3,weight:.7,label:"<1h gap"},{maxGapMs:14400*1e3,weight:.4,label:"<4h gap"},{maxGapMs:1440*60*1e3,weight:.2,label:"<24h gap"}],Qb=["let's commit","lets commit","now commit","inspect the diff","inspect this diff","review the diff","review this diff","diff of all changes","diff of changes","based on what we just did","based on the things done","based on all the things","continue from","continuing from","pick up where","next step","now fix","now lets","now let's","from the previous session","from our last session","from the last session"];function Dl(e){if(!e)return null;if(e.startsWith("/")){let s=e.split(" \xB7 ");if(s.length>1)return s[1].trim().toLowerCase()}let t=e.split(" \xB7 ");return t.length>1?t[t.length-1].trim().toLowerCase():null}function eS(e,t){let s=t-e;if(s<0)return{weight:0,label:null};for(let n of Zb)if(s<=n.maxGapMs)return{weight:n.weight,label:n.label};return{weight:0,label:null}}function tS(e){if(e.length===0)return{weight:0,matched:null,matchedIndex:-1};let t=[.4,.35,.3,.25,.2,.15,.1],s=Math.min(e.length,t.length);for(let n=0;n<s;n++){let r=e[n];if(!r)continue;let o=r.toLowerCase();for(let i of Qb)if(o.includes(i))return{weight:t[n],matched:i,matchedIndex:n}}return{weight:0,matched:null,matchedIndex:-1}}function Mr(e,t){if(!e||!t||e.length!==t.length)return 0;let s=0;for(let n=0;n<e.length;n++)s+=e[n]*t[n];return s<-1?-1:s>1?1:s}function sS(e,t){if(e.length===0||t.length===0)return 0;let s=0;for(let n of e)for(let r of t){let o=Mr(n,r);o>s&&(s=o)}return s}function nS(e,t){let s=Mr(e.mean_embedding,t.mean_embedding),n=Mr(e.tail_pool,t.head_pool),r=sS(e.sample_chunks,t.sample_chunks),o=0,i=null;if(s>o&&(o=s,i="mean"),n>o&&(o=n,i="asymmetric"),r>o&&(o=r,i="max_pool"),o<.65)return{weight:0,cosine:o,mode:null};if(o>=.85)return{weight:.3,cosine:o,mode:i};let a=(o-.65)/.2*.3;return{weight:Math.round(a*100)/100,cosine:o,mode:i}}function rS(e,t){return e.cluster_id===null||t.cluster_id===null?{weight:0,same:!1}:e.cluster_id!==t.cluster_id?{weight:0,same:!1}:{weight:.05,same:!0}}function oS(e,t){if(e.size===0||t.size===0)return{weight:0,count:0};let s=0;for(let r of t)e.has(r)&&s++;return s===0?{weight:0,count:0}:{weight:Math.min(.4,s*.1),count:s}}function iS(e,t){let s=Dl(e),n=Dl(t);return s&&n&&s===n?{weight:.1,brand:s}:{weight:0,brand:null}}function $l(e){return e.replace(/\s+/g," ").trim().toLowerCase()}function aS(e,t){let s=0,n=null,r=!1;if(e.authored_paths.size>0){let o=t.recent_user_messages.slice(0,3).join(`
1578
- `).toLowerCase();for(let i of e.authored_paths){let a=i.toLowerCase();if(t.touched_files.has(i)||o.includes(a)){s+=.5,n=i;break}}}if(e.authored_content.length>0&&t.recent_user_messages[0]){let o=$l(t.recent_user_messages[0]);if(o.length>=200)for(let i of e.authored_content){let a=$l(i);if(a.length<200)continue;let l=Math.min(a.length,240),c=a.slice(0,l);if(o.includes(c)){s+=.4,r=!0;break}}}return{weight:Math.min(.6,s),pathMatch:n,contentMatch:r}}function cS(e,t,s=jl){if(t.started_at_ms<=e.started_at_ms)return null;let n=e.ended_at_ms??e.started_at_ms;if(t.started_at_ms<n)return null;let r=eS(n,t.started_at_ms),o=t.recent_user_messages.length>0?t.recent_user_messages:t.first_user_message?[t.first_user_message]:[],i=tS(o),a=oS(e.touched_files,t.touched_files),l=iS(e.auto_title,t.auto_title),c=nS(e,t),u=rS(e,t),p=aS(e,t),m=r.weight+i.weight+a.weight+l.weight+c.weight+u.weight+p.weight;if(m<s)return null;let f=[];if(r.label&&f.push(`temporal ${r.label} (+${r.weight})`),i.matched){let g=i.matchedIndex===0?"opening message":`message #${i.matchedIndex+1}`;f.push(`continuation phrase "${i.matched}" in ${g} (+${i.weight})`)}if(a.count>0&&f.push(`${a.count} file${a.count===1?"":"s"} overlap (+${a.weight.toFixed(1)})`),l.brand&&f.push(`shared brand "${l.brand}" (+${l.weight})`),c.weight>0&&c.mode&&f.push(`semantic ${c.mode==="asymmetric"?"tail\u2192head":c.mode==="max_pool"?"best-chunk":"mean"} ${c.cosine.toFixed(2)} (+${c.weight.toFixed(2)})`),u.same&&f.push(`same cluster (+${u.weight})`),p.weight>0){let g=[];p.pathMatch&&g.push(`opened authored path "${p.pathMatch.split("/").pop()}"`),p.contentMatch&&g.push("verbatim-paste of authored content"),f.push(`doc-authorship: ${g.join(" + ")} (+${p.weight.toFixed(2)})`)}return{parent_id:e.id,child_id:t.id,confidence:Math.min(1,m),signals:{temporal:r.weight,continuation:i.weight,file_overlap:a.weight,same_brand:l.weight,semantic:c.weight,cluster:u.weight,doc_authorship:p.weight},reasons:f}}function Pl(e,t=jl){let s=[];for(let n=0;n<e.length;n++){let r=e[n],o=null;for(let i=0;i<n;i++){let a=e[i],l=cS(a,r,t);l&&(!o||l.confidence>o.confidence)&&(o=l)}o&&s.push(o)}return s}function Fl(e,t){let s=new Map,n=a=>{let l=a;for(;s.get(l)!==l;)l=s.get(l);let c=a;for(;s.get(c)!==l;){let u=s.get(c);s.set(c,l),c=u}return l},r=(a,l)=>{let c=n(a),u=n(l);c!==u&&s.set(c,u)};for(let a of e)s.has(a.parent_id)||s.set(a.parent_id,a.parent_id),s.has(a.child_id)||s.set(a.child_id,a.child_id),r(a.parent_id,a.child_id);let o=new Map;for(let a of s.keys()){let l=n(a),c=o.get(l);c||(c=[],o.set(l,c)),c.push(a)}let i=new Map;for(let a of t)i.set(a.id,a.started_at_ms);return Array.from(o.values()).map(a=>(a.sort((l,c)=>(i.get(l)??0)-(i.get(c)??0)),{rootId:a[0],sessionIds:a}))}function Ul(e,t={}){let s=t.maxUserMessages??5,n=t.userMessageMaxLen??2e3,r=new Set,o=[],i=new Set,a=[],l;try{if(qb(e).size>Vb)return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a};l=Kb(e,"utf8")}catch{return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a}}let c=0;for(;c<l.length;){let u=l.indexOf(`
1579
- `,c),p=u===-1?l.length:u,m=l.slice(c,p);if(c=u===-1?l.length:u+1,!m.trim())continue;let f;try{f=JSON.parse(m)}catch{continue}let g=f;if(g.type==="user"&&g.message?.role==="user"&&typeof g.message.content=="string"&&o.length<s){let E=g.message.content.trim();E&&o.push(E.length>n?E.slice(0,n):E)}let h=g.message?.content;if(Array.isArray(h))for(let E of h){if(!E||typeof E!="object")continue;let b=E;if(b.type!=="tool_use")continue;let S=b.input??{},C=typeof S.file_path=="string"?S.file_path:null;if(C){let x=Us(C);x&&r.add(x)}if((b.name==="Write"||b.name==="Edit"||b.name==="MultiEdit")&&C){let x=Us(C);x&&i.add(x);let L=typeof S.content=="string"?S.content:typeof S.new_string=="string"?S.new_string:null;L&&L.length>=200&&a.push(L.length>4096?L.slice(0,4096):L)}if(b.name==="Bash"&&typeof S.command=="string")for(let x of S.command.matchAll(/(?:^|[\s'"`(=])((?:\.\.?\/|\/|src\/|test\/|docs\/|site\/)[A-Za-z0-9_./-]+)/g)){let L=Us(x[1]);L&&r.add(L)}if((b.name==="Glob"||b.name==="Grep")&&typeof S.pattern=="string"){let x=Us(S.pattern);x&&!x.includes("*")&&r.add(x)}}}return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a}}function Us(e){let t=e.trim().replace(/^['"]|['"]$/g,"");return!t||t.length<4||/[<>|;&\$`]/.test(t)?null:t}T();var Bl=10,Hl=20;function lS(e){if(!e)return!1;let t=e.split(`
1580
- `);if(t.length<4)return!1;let s=0,n=0;for(let r of t)/^\s*\d{1,5}\t/.test(r)?s++:/^\s*\/[A-Za-z0-9_./-]+/.test(r.trim())&&n++;return s/t.length>.7||n/t.length>.5}function dS(e){let t=e.byteLength/4;if(!Number.isInteger(t)||t<=0)return null;let s=new Float32Array(t),n=new Float32Array(e.buffer,e.byteOffset,t);return s.set(n),s}function Wl(e){let t=0;for(let n=0;n<e.length;n++)t+=e[n]*e[n];if(t<=0)return!1;let s=1/Math.sqrt(t);for(let n=0;n<e.length;n++)e[n]*=s;return!0}function jr(e){if(e.length===0)return null;let t=e[0].length,s=new Float32Array(t);for(let n of e)if(n.length===t)for(let r=0;r<t;r++)s[r]+=n[r];for(let n=0;n<t;n++)s[n]/=e.length;return Wl(s)?s:null}function Xl(e){let t=new Map;if(e.length===0)return t;let s=_(),n=e.map(()=>"?").join(","),r=[];try{r=s.prepare(`SELECT cm.rowid AS rowid, cm.session_id AS session_id,
1595
+ `))})}function Ql(e,t){let s=ve(t.thread);if(!s){process.exitCode=1;return}let n=St(e);if(!n){process.exitCode=1;return}let r=null;if(t.parent&&t.parent.toLowerCase()!=="none"){let i=St(t.parent);if(!i){process.exitCode=1;return}r=i}let o=Ai(s,n,r);Re(t.json===!0,o,()=>{process.stderr.write(d.ok(`\u2713 ${H(n)} in ${H(s)} \u2192 `+(r?`child of ${H(r)}`:"origin")+`
1596
+ `))})}function ed(e,t,s){let n=ve(e);if(!n){process.exitCode=1;return}let r=Ii(n,t);Re(s.json===!0,r,()=>Ct(r))}function td(e,t){let s=ve(e);if(!s){process.exitCode=1;return}let n=vi(s);Re(t.json===!0,n,()=>Ct(n))}function sd(e,t){let s=ve(e);if(!s){process.exitCode=1;return}let n=Mi(s);Re(t.json===!0,n,()=>Ct(n))}function nd(e,t){let s=ve(e);if(!s){process.exitCode=1;return}let n=Di(s);Re(t.json===!0,n,()=>Ct(n))}function rd(e,t){let s=ve(e);if(!s){process.exitCode=1;return}let n=ve(t.into);if(!n){process.exitCode=1;return}if(s===n){process.stderr.write(d.err(`cannot merge a thread into itself
1597
+ `)),process.exitCode=1;return}let r=$i(s,n);Re(t.json===!0,r,()=>{process.stderr.write(d.ok(`\u2713 merged ${H(s)} \u2192 ${H(n)} (${r.session_count} sessions)
1598
+ `))})}function od(e,t){let s=ve(e);if(!s){process.exitCode=1;return}let n=t.sessions.split(",").map(i=>i.trim()).filter(Boolean);if(n.length===0){process.stderr.write(d.err(`--sessions must be a non-empty comma-separated list
1599
+ `)),process.exitCode=1;return}let r=[];for(let i of n){let a=St(i);if(!a){process.exitCode=1;return}r.push(a)}let o=ji({threadId:s,sessionIds:r,newThreadName:t.name});Re(t.json===!0,o,()=>{Ct(o),process.stderr.write(d.dim(`split off ${r.length} session${r.length===1?"":"s"} from ${H(s)}
1600
+ `))})}T();I();import{randomUUID as sy}from"node:crypto";import{readFileSync as MS,statSync as DS}from"node:fs";var $S=200*1024*1024,zr=.7,Yr=.5,cd=Yr,jS=[{maxGapMs:3600*1e3,weight:.7,label:"<1h gap"},{maxGapMs:14400*1e3,weight:.4,label:"<4h gap"},{maxGapMs:1440*60*1e3,weight:.2,label:"<24h gap"}],PS=["let's commit","lets commit","now commit","inspect the diff","inspect this diff","review the diff","review this diff","diff of all changes","diff of changes","based on what we just did","based on the things done","based on all the things","continue from","continuing from","pick up where","next step","now fix","now lets","now let's","from the previous session","from our last session","from the last session"];function id(e){if(!e)return null;if(e.startsWith("/")){let s=e.split(" \xB7 ");if(s.length>1)return s[1].trim().toLowerCase()}let t=e.split(" \xB7 ");return t.length>1?t[t.length-1].trim().toLowerCase():null}function FS(e,t){let s=t-e;if(s<0)return{weight:0,label:null};for(let n of jS)if(s<=n.maxGapMs)return{weight:n.weight,label:n.label};return{weight:0,label:null}}function US(e){if(e.length===0)return{weight:0,matched:null,matchedIndex:-1};let t=[.4,.35,.3,.25,.2,.15,.1],s=Math.min(e.length,t.length);for(let n=0;n<s;n++){let r=e[n];if(!r)continue;let o=r.toLowerCase();for(let i of PS)if(o.includes(i))return{weight:t[n],matched:i,matchedIndex:n}}return{weight:0,matched:null,matchedIndex:-1}}function Gr(e,t){if(!e||!t||e.length!==t.length)return 0;let s=0;for(let n=0;n<e.length;n++)s+=e[n]*t[n];return s<-1?-1:s>1?1:s}function BS(e,t){if(e.length===0||t.length===0)return 0;let s=0;for(let n of e)for(let r of t){let o=Gr(n,r);o>s&&(s=o)}return s}function HS(e,t){let s=Gr(e.mean_embedding,t.mean_embedding),n=Gr(e.tail_pool,t.head_pool),r=BS(e.sample_chunks,t.sample_chunks),o=0,i=null;if(s>o&&(o=s,i="mean"),n>o&&(o=n,i="asymmetric"),r>o&&(o=r,i="max_pool"),o<.65)return{weight:0,cosine:o,mode:null};if(o>=.85)return{weight:.3,cosine:o,mode:i};let a=(o-.65)/.2*.3;return{weight:Math.round(a*100)/100,cosine:o,mode:i}}function WS(e,t){return e.cluster_id===null||t.cluster_id===null?{weight:0,same:!1}:e.cluster_id!==t.cluster_id?{weight:0,same:!1}:{weight:.05,same:!0}}function XS(e,t){if(e.size===0||t.size===0)return{weight:0,count:0};let s=0;for(let r of t)e.has(r)&&s++;return s===0?{weight:0,count:0}:{weight:Math.min(.4,s*.1),count:s}}function JS(e,t){let s=id(e),n=id(t);return s&&n&&s===n?{weight:.1,brand:s}:{weight:0,brand:null}}function ad(e){return e.replace(/\s+/g," ").trim().toLowerCase()}function GS(e,t){let s=0,n=null,r=!1;if(e.authored_paths.size>0){let o=t.recent_user_messages.slice(0,3).join(`
1601
+ `).toLowerCase();for(let i of e.authored_paths){let a=i.toLowerCase();if(t.touched_files.has(i)||o.includes(a)){s+=.5,n=i;break}}}if(e.authored_content.length>0&&t.recent_user_messages[0]){let o=ad(t.recent_user_messages[0]);if(o.length>=200)for(let i of e.authored_content){let a=ad(i);if(a.length<200)continue;let l=Math.min(a.length,240),c=a.slice(0,l);if(o.includes(c)){s+=.4,r=!0;break}}}return{weight:Math.min(.6,s),pathMatch:n,contentMatch:r}}function zS(e,t,s=cd){if(t.started_at_ms<=e.started_at_ms)return null;let n=e.ended_at_ms??e.started_at_ms;if(t.started_at_ms<n)return null;let r=FS(n,t.started_at_ms),o=t.recent_user_messages.length>0?t.recent_user_messages:t.first_user_message?[t.first_user_message]:[],i=US(o),a=XS(e.touched_files,t.touched_files),l=JS(e.auto_title,t.auto_title),c=HS(e,t),u=WS(e,t),m=GS(e,t),p=r.weight+i.weight+a.weight+l.weight+c.weight+u.weight+m.weight;if(p<s)return null;let f=[];if(r.label&&f.push(`temporal ${r.label} (+${r.weight})`),i.matched){let g=i.matchedIndex===0?"opening message":`message #${i.matchedIndex+1}`;f.push(`continuation phrase "${i.matched}" in ${g} (+${i.weight})`)}if(a.count>0&&f.push(`${a.count} file${a.count===1?"":"s"} overlap (+${a.weight.toFixed(1)})`),l.brand&&f.push(`shared brand "${l.brand}" (+${l.weight})`),c.weight>0&&c.mode&&f.push(`semantic ${c.mode==="asymmetric"?"tail\u2192head":c.mode==="max_pool"?"best-chunk":"mean"} ${c.cosine.toFixed(2)} (+${c.weight.toFixed(2)})`),u.same&&f.push(`same cluster (+${u.weight})`),m.weight>0){let g=[];m.pathMatch&&g.push(`opened authored path "${m.pathMatch.split("/").pop()}"`),m.contentMatch&&g.push("verbatim-paste of authored content"),f.push(`doc-authorship: ${g.join(" + ")} (+${m.weight.toFixed(2)})`)}return{parent_id:e.id,child_id:t.id,confidence:Math.min(1,p),signals:{temporal:r.weight,continuation:i.weight,file_overlap:a.weight,same_brand:l.weight,semantic:c.weight,cluster:u.weight,doc_authorship:m.weight},reasons:f}}function ld(e,t=cd){let s=[];for(let n=0;n<e.length;n++){let r=e[n],o=null;for(let i=0;i<n;i++){let a=e[i],l=zS(a,r,t);l&&(!o||l.confidence>o.confidence)&&(o=l)}o&&s.push(o)}return s}function dd(e,t){let s=new Map,n=a=>{let l=a;for(;s.get(l)!==l;)l=s.get(l);let c=a;for(;s.get(c)!==l;){let u=s.get(c);s.set(c,l),c=u}return l},r=(a,l)=>{let c=n(a),u=n(l);c!==u&&s.set(c,u)};for(let a of e)s.has(a.parent_id)||s.set(a.parent_id,a.parent_id),s.has(a.child_id)||s.set(a.child_id,a.child_id),r(a.parent_id,a.child_id);let o=new Map;for(let a of s.keys()){let l=n(a),c=o.get(l);c||(c=[],o.set(l,c)),c.push(a)}let i=new Map;for(let a of t)i.set(a.id,a.started_at_ms);return Array.from(o.values()).map(a=>(a.sort((l,c)=>(i.get(l)??0)-(i.get(c)??0)),{rootId:a[0],sessionIds:a}))}function ud(e,t={}){let s=t.maxUserMessages??5,n=t.userMessageMaxLen??2e3,r=new Set,o=[],i=new Set,a=[],l;try{if(DS(e).size>$S)return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a};l=MS(e,"utf8")}catch{return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a}}let c=0;for(;c<l.length;){let u=l.indexOf(`
1602
+ `,c),m=u===-1?l.length:u,p=l.slice(c,m);if(c=u===-1?l.length:u+1,!p.trim())continue;let f;try{f=JSON.parse(p)}catch{continue}let g=f;if(g.type==="user"&&g.message?.role==="user"&&typeof g.message.content=="string"&&o.length<s){let E=g.message.content.trim();E&&o.push(E.length>n?E.slice(0,n):E)}let h=g.message?.content;if(Array.isArray(h))for(let E of h){if(!E||typeof E!="object")continue;let b=E;if(b.type!=="tool_use")continue;let S=b.input??{},N=typeof S.file_path=="string"?S.file_path:null;if(N){let x=Ks(N);x&&r.add(x)}if((b.name==="Write"||b.name==="Edit"||b.name==="MultiEdit")&&N){let x=Ks(N);x&&i.add(x);let L=typeof S.content=="string"?S.content:typeof S.new_string=="string"?S.new_string:null;L&&L.length>=200&&a.push(L.length>4096?L.slice(0,4096):L)}if(b.name==="Bash"&&typeof S.command=="string")for(let x of S.command.matchAll(/(?:^|[\s'"`(=])((?:\.\.?\/|\/|src\/|test\/|docs\/|site\/)[A-Za-z0-9_./-]+)/g)){let L=Ks(x[1]);L&&r.add(L)}if((b.name==="Glob"||b.name==="Grep")&&typeof S.pattern=="string"){let x=Ks(S.pattern);x&&!x.includes("*")&&r.add(x)}}}return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a}}function Ks(e){let t=e.trim().replace(/^['"]|['"]$/g,"");return!t||t.length<4||/[<>|;&\$`]/.test(t)?null:t}T();var md=10,pd=20;function YS(e){if(!e)return!1;let t=e.split(`
1603
+ `);if(t.length<4)return!1;let s=0,n=0;for(let r of t)/^\s*\d{1,5}\t/.test(r)?s++:/^\s*\/[A-Za-z0-9_./-]+/.test(r.trim())&&n++;return s/t.length>.7||n/t.length>.5}function KS(e){let t=e.byteLength/4;if(!Number.isInteger(t)||t<=0)return null;let s=new Float32Array(t),n=new Float32Array(e.buffer,e.byteOffset,t);return s.set(n),s}function gd(e){let t=0;for(let n=0;n<e.length;n++)t+=e[n]*e[n];if(t<=0)return!1;let s=1/Math.sqrt(t);for(let n=0;n<e.length;n++)e[n]*=s;return!0}function Kr(e){if(e.length===0)return null;let t=e[0].length,s=new Float32Array(t);for(let n of e)if(n.length===t)for(let r=0;r<t;r++)s[r]+=n[r];for(let n=0;n<t;n++)s[n]/=e.length;return gd(s)?s:null}function fd(e){let t=new Map;if(e.length===0)return t;let s=_(),n=e.map(()=>"?").join(","),r=[];try{r=s.prepare(`SELECT cm.rowid AS rowid, cm.session_id AS session_id,
1581
1604
  cm.text AS text, v.embedding AS embedding
1582
1605
  FROM chunk_meta cm
1583
1606
  JOIN vec_chunks v ON v.rowid = cm.rowid
1584
1607
  WHERE cm.stale = 0
1585
1608
  AND cm.session_id IN (${n})
1586
- ORDER BY cm.session_id, cm.rowid ASC`).all(...e)}catch{return t}if(r.length===0)return t;let o=new Map;for(let i of r){let a=o.get(i.session_id);a||(a=[],o.set(i.session_id,a)),a.push(i)}for(let[i,a]of o){let l=a.filter(x=>!lS(x.text)),c=l.length>0?l:a,u=[];for(let x of c){let L=dS(x.embedding);L&&Wl(L)&&u.push(L)}if(u.length===0)continue;let p=Math.min(Bl,u.length),m=Math.max(0,u.length-Bl),f=u.slice(0,p),g=u.slice(m),h=jr(f),E=jr(g),b=jr(u),S=new Map;for(let x=0;x<f.length&&S.size<Hl;x++)S.set(x,f[x]);for(let x=0;x<g.length&&S.size<Hl;x++)S.set(m+x,g[x]);let C=Array.from(S.values());t.set(i,{session_id:i,full_mean:b,head_pool:h,tail_pool:E,sample_chunks:C})}return t}function uS(e,t){if(e.length!==t.length)return 0;let s=0;for(let n=0;n<e.length;n++)s+=e[n]*t[n];return s<-1?-1:s>1?1:s}function Jl(e,t=.8){let s=new Map,n=[],r=[];for(let[c,u]of e)u.full_mean&&(n.push(c),r.push(u.full_mean));if(n.length===0)return s;let o=new Int32Array(n.length);for(let c=0;c<o.length;c++)o[c]=c;let i=c=>{let u=c;for(;o[u]!==u;)u=o[u];let p=c;for(;o[p]!==u;){let m=o[p];o[p]=u,p=m}return u},a=(c,u)=>{let p=i(c),m=i(u);p!==m&&(o[p]=m)};for(let c=0;c<n.length;c++)for(let u=c+1;u<n.length;u++)uS(r[c],r[u])>=t&&a(c,u);let l=new Map;for(let c=0;c<n.length;c++){let u=i(c),p=l.get(u);p===void 0&&(p=l.size,l.set(u,p)),s.set(n[c],p)}return s}var Gt={lo:.4,hi:.7},Bs="claude-haiku-4-5-20251001",Gl=50;var pS={same_workflow:.15,unrelated:-.2,unsure:0};function zl(e,t,s=Gt){if(s.lo>s.hi)throw new Error(`borderline band invalid: lo=${s.lo} > hi=${s.hi}`);let n=[];for(let r of e){if(r.confidence<s.lo||r.confidence>s.hi)continue;let o=t.get(r.parent_id),i=t.get(r.child_id);!o||!i||n.push({parent:o,child:i,step1:r})}return n.sort((r,o)=>r.child.started_at_ms-o.child.started_at_ms),n}function mS(e,t){let s=e.replace(/\s+/g," ").trim();return s.length>t?s.slice(0,t-1)+"\u2026":s}function gS(e,t){if(e===null)return"unknown";let s=t-e;if(s<0)return"overlap";let n=Math.round(s/6e4);if(n<60)return`${n}m`;let r=Math.round(s/36e5);return r<24?`${r}h`:`${Math.round(s/864e5)}d`}function fS(e){let s=e.parent.recent_user_messages,n=e.child.recent_user_messages,r=s.slice(0,3),o=s.length>3?s.slice(-3):[],i=n.slice(0,3),a=c=>c.length===0?" (none captured)":c.map(u=>` - ${mS(u,500)}`).join(`
1587
- `),l=gS(e.parent.ended_at_ms??e.parent.started_at_ms,e.child.started_at_ms);return["You are evaluating whether two Claude Code sessions belong to the same continuous workflow.","","A deterministic scorer rated this pair in the borderline band. Its signals:",e.step1.reasons.length===0?" (no signals fired strongly)":e.step1.reasons.map(c=>` - ${c}`).join(`
1609
+ ORDER BY cm.session_id, cm.rowid ASC`).all(...e)}catch{return t}if(r.length===0)return t;let o=new Map;for(let i of r){let a=o.get(i.session_id);a||(a=[],o.set(i.session_id,a)),a.push(i)}for(let[i,a]of o){let l=a.filter(x=>!YS(x.text)),c=l.length>0?l:a,u=[];for(let x of c){let L=KS(x.embedding);L&&gd(L)&&u.push(L)}if(u.length===0)continue;let m=Math.min(md,u.length),p=Math.max(0,u.length-md),f=u.slice(0,m),g=u.slice(p),h=Kr(f),E=Kr(g),b=Kr(u),S=new Map;for(let x=0;x<f.length&&S.size<pd;x++)S.set(x,f[x]);for(let x=0;x<g.length&&S.size<pd;x++)S.set(p+x,g[x]);let N=Array.from(S.values());t.set(i,{session_id:i,full_mean:b,head_pool:h,tail_pool:E,sample_chunks:N})}return t}function qS(e,t){if(e.length!==t.length)return 0;let s=0;for(let n=0;n<e.length;n++)s+=e[n]*t[n];return s<-1?-1:s>1?1:s}function _d(e,t=.8){let s=new Map,n=[],r=[];for(let[c,u]of e)u.full_mean&&(n.push(c),r.push(u.full_mean));if(n.length===0)return s;let o=new Int32Array(n.length);for(let c=0;c<o.length;c++)o[c]=c;let i=c=>{let u=c;for(;o[u]!==u;)u=o[u];let m=c;for(;o[m]!==u;){let p=o[m];o[m]=u,m=p}return u},a=(c,u)=>{let m=i(c),p=i(u);m!==p&&(o[m]=p)};for(let c=0;c<n.length;c++)for(let u=c+1;u<n.length;u++)qS(r[c],r[u])>=t&&a(c,u);let l=new Map;for(let c=0;c<n.length;c++){let u=i(c),m=l.get(u);m===void 0&&(m=l.size,l.set(u,m)),s.set(n[c],m)}return s}var qt={lo:.4,hi:.7},qs="claude-haiku-4-5-20251001",hd=50;var VS={same_workflow:.15,unrelated:-.2,unsure:0};function Ed(e,t,s=qt){if(s.lo>s.hi)throw new Error(`borderline band invalid: lo=${s.lo} > hi=${s.hi}`);let n=[];for(let r of e){if(r.confidence<s.lo||r.confidence>s.hi)continue;let o=t.get(r.parent_id),i=t.get(r.child_id);!o||!i||n.push({parent:o,child:i,step1:r})}return n.sort((r,o)=>r.child.started_at_ms-o.child.started_at_ms),n}function ZS(e,t){let s=e.replace(/\s+/g," ").trim();return s.length>t?s.slice(0,t-1)+"\u2026":s}function QS(e,t){if(e===null)return"unknown";let s=t-e;if(s<0)return"overlap";let n=Math.round(s/6e4);if(n<60)return`${n}m`;let r=Math.round(s/36e5);return r<24?`${r}h`:`${Math.round(s/864e5)}d`}function ey(e){let s=e.parent.recent_user_messages,n=e.child.recent_user_messages,r=s.slice(0,3),o=s.length>3?s.slice(-3):[],i=n.slice(0,3),a=c=>c.length===0?" (none captured)":c.map(u=>` - ${ZS(u,500)}`).join(`
1610
+ `),l=QS(e.parent.ended_at_ms??e.parent.started_at_ms,e.child.started_at_ms);return["You are evaluating whether two Claude Code sessions belong to the same continuous workflow.","","A deterministic scorer rated this pair in the borderline band. Its signals:",e.step1.reasons.length===0?" (no signals fired strongly)":e.step1.reasons.map(c=>` - ${c}`).join(`
1588
1611
  `),` step1_confidence: ${e.step1.confidence.toFixed(2)}`,"","PARENT SESSION","First user messages:",a(r),"Last user messages:",a(o),"",`CHILD SESSION (gap from parent: ${l})`,"First user messages:",a(i),"","Reply with EXACTLY one JSON object on a single line, no prose, no markdown:",'{"verdict":"same_workflow"|"unrelated"|"unsure","reason":"<one short sentence>"}',"","Guidance:",'- "same_workflow" = the child is clearly continuing what the parent was doing.','- "unrelated" = different problem, different files, different intent.','- "unsure" = could go either way; do not force a verdict.'].join(`
1589
- `)}function _S(e){if(!e)return null;let t=e.trim();if(!t)return null;let s=t;try{let l=JSON.parse(t);typeof l.result=="string"&&(s=l.result.trim())}catch{}let n=s.match(/\{[\s\S]*\}/);if(!n)return null;let r;try{r=JSON.parse(n[0])}catch{return null}if(!r||typeof r!="object")return null;let o=r,i=typeof o.verdict=="string"?o.verdict.toLowerCase():"";if(i!=="same_workflow"&&i!=="unrelated"&&i!=="unsure")return null;let a=typeof o.reason=="string"&&o.reason.trim()?o.reason.trim():"";return{verdict:i,reason:a,delta:pS[i]}}async function Yl(e,t={}){if(t.signal?.aborted)return null;let s=t.model??Bs,n=fS(e),r=t.spawn;if(!r)try{let i=await Promise.resolve().then(()=>(Xe(),Bn));if(!i.isClaudeCliAvailable())return null;r=(a,l)=>i.spawnClaudePrompt(a,[],l)}catch{return null}let o;try{o=await Promise.race([r(n,{model:s}),new Promise(i=>{t.signal&&t.signal.addEventListener("abort",()=>i({success:!1,stdout:""}),{once:!0})})])}catch{return null}return!o.success||!o.stdout?null:_S(o.stdout)}function Kl(e){let t=[];for(let s of e.proposals){let n=`${s.parent_id}::${s.child_id}`,r=e.rescored.get(n);if(!r){t.push(s);continue}let o=Math.max(0,Math.min(1,s.confidence+r.delta));if(o<e.applyThreshold)continue;let i=`LLM: ${r.verdict}${r.reason?` \u2014 ${r.reason}`:""} (${r.delta>=0?"+":""}${r.delta.toFixed(2)})`;t.push({...s,confidence:o,reasons:[...s.reasons,i]})}return t}function ql(e){return`${e.parent_id}::${e.child_id}`}async function ES(e){if(e.signal?.aborted)return null;let t,s;try{({spawnClaudePrompt:t,isClaudeCliAvailable:s}=await Promise.resolve().then(()=>(Xe(),Bn)))}catch{return null}if(!s())return null;let n=[];for(let o of e.sessionIds){let i=e.rowById.get(o);if(!i)continue;let a=i.alias||i.auto_title||(i.first_user_message?i.first_user_message.slice(0,120).replace(/\n/g," "):"(no title)");n.push(`- ${a}`)}let r=`Below is a chronological list of related Claude Code sessions that form one continuous workflow. Generate a single short descriptive name for the workflow as a whole. Requirements:
1612
+ `)}function ty(e){if(!e)return null;let t=e.trim();if(!t)return null;let s=t;try{let l=JSON.parse(t);typeof l.result=="string"&&(s=l.result.trim())}catch{}let n=s.match(/\{[\s\S]*\}/);if(!n)return null;let r;try{r=JSON.parse(n[0])}catch{return null}if(!r||typeof r!="object")return null;let o=r,i=typeof o.verdict=="string"?o.verdict.toLowerCase():"";if(i!=="same_workflow"&&i!=="unrelated"&&i!=="unsure")return null;let a=typeof o.reason=="string"&&o.reason.trim()?o.reason.trim():"";return{verdict:i,reason:a,delta:VS[i]}}async function bd(e,t={}){if(t.signal?.aborted)return null;let s=t.model??qs,n=ey(e),r=t.spawn;if(!r)try{let i=await Promise.resolve().then(()=>(Je(),Kn));if(!i.isClaudeCliAvailable())return null;r=(a,l)=>i.spawnClaudePrompt(a,[],l)}catch{return null}let o;try{o=await Promise.race([r(n,{model:s}),new Promise(i=>{t.signal&&t.signal.addEventListener("abort",()=>i({success:!1,stdout:""}),{once:!0})})])}catch{return null}return!o.success||!o.stdout?null:ty(o.stdout)}function Sd(e){let t=[];for(let s of e.proposals){let n=`${s.parent_id}::${s.child_id}`,r=e.rescored.get(n);if(!r){t.push(s);continue}let o=Math.max(0,Math.min(1,s.confidence+r.delta));if(o<e.applyThreshold)continue;let i=`LLM: ${r.verdict}${r.reason?` \u2014 ${r.reason}`:""} (${r.delta>=0?"+":""}${r.delta.toFixed(2)})`;t.push({...s,confidence:o,reasons:[...s.reasons,i]})}return t}function yd(e){return`${e.parent_id}::${e.child_id}`}async function ny(e){if(e.signal?.aborted)return null;let t,s;try{({spawnClaudePrompt:t,isClaudeCliAvailable:s}=await Promise.resolve().then(()=>(Je(),Kn)))}catch{return null}if(!s())return null;let n=[];for(let o of e.sessionIds){let i=e.rowById.get(o);if(!i)continue;let a=i.alias||i.auto_title||(i.first_user_message?i.first_user_message.slice(0,120).replace(/\n/g," "):"(no title)");n.push(`- ${a}`)}let r=`Below is a chronological list of related Claude Code sessions that form one continuous workflow. Generate a single short descriptive name for the workflow as a whole. Requirements:
1590
1613
  - 4 to 8 words
1591
1614
  - Title-case, no trailing punctuation
1592
1615
  - Capture the WORKFLOW (e.g., "Update Remotion deps + lint cleanup"), not any one session
@@ -1597,7 +1620,7 @@ Sessions:
1597
1620
  `+n.join(`
1598
1621
  `)+`
1599
1622
 
1600
- Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model:e.model}:{}),i=null,a=new Promise(p=>{e.signal&&(i=()=>p(null),e.signal.addEventListener("abort",i,{once:!0}))}),l=await Promise.race([o,a]);if(i&&e.signal&&e.signal.removeEventListener("abort",i),!l||!l.success)return null;let c=l.stdout.trim();if(!c)return null;let u;try{let p=JSON.parse(c);u=typeof p.result=="string"?p.result:c}catch{u=c}return u=u.trim().replace(/^["'`]+|["'`]+$/g,"").replace(/[.!?]+$/g,"").trim(),u?u.length>80?u.slice(0,77)+"...":u:null}catch{return null}}function bS(e){let t=new Map;for(let o of e){let i=t.get(o.project);i||(i=[],t.set(o.project,i)),i.push(o)}let s=e.map(o=>o.id),n=new Map;try{n=Xl(s)}catch{n=new Map}let r=new Map;for(let[o,i]of t){let a=new Map;for(let u of i){let p=n.get(u.id);p&&a.set(u.id,p)}let l=Jl(a,.8),c=[];for(let u of i){let p=yS(u,n,l);p&&c.push(p)}r.set(o,c)}return{byProject:t,scannablesByProject:r}}function SS(e){let t=_(),s={},n="1=1 AND s.message_count > 2";return n+=" AND COALESCE(s.auto_title, '') NOT LIKE '[meta]%' AND COALESCE(s.auto_title, '') NOT LIKE '[output-index]%' AND COALESCE(s.auto_title, '') NOT LIKE '[skill]%'",e.project&&(n+=" AND p.name = @project",s.project=e.project),t.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
1623
+ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model:e.model}:{}),i=null,a=new Promise(m=>{e.signal&&(i=()=>m(null),e.signal.addEventListener("abort",i,{once:!0}))}),l=await Promise.race([o,a]);if(i&&e.signal&&e.signal.removeEventListener("abort",i),!l||!l.success)return null;let c=l.stdout.trim();if(!c)return null;let u;try{let m=JSON.parse(c);u=typeof m.result=="string"?m.result:c}catch{u=c}return u=u.trim().replace(/^["'`]+|["'`]+$/g,"").replace(/[.!?]+$/g,"").trim(),u?u.length>80?u.slice(0,77)+"...":u:null}catch{return null}}function ry(e){let t=new Map;for(let o of e){let i=t.get(o.project);i||(i=[],t.set(o.project,i)),i.push(o)}let s=e.map(o=>o.id),n=new Map;try{n=fd(s)}catch{n=new Map}let r=new Map;for(let[o,i]of t){let a=new Map;for(let u of i){let m=n.get(u.id);m&&a.set(u.id,m)}let l=_d(a,.8),c=[];for(let u of i){let m=iy(u,n,l);m&&c.push(m)}r.set(o,c)}return{byProject:t,scannablesByProject:r}}function oy(e){let t=_(),s={},n="1=1 AND s.message_count > 2";return n+=" AND COALESCE(s.auto_title, '') NOT LIKE '[meta]%' AND COALESCE(s.auto_title, '') NOT LIKE '[output-index]%' AND COALESCE(s.auto_title, '') NOT LIKE '[skill]%'",e.project&&(n+=" AND p.name = @project",s.project=e.project),t.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
1601
1624
  s.first_user_message, s.auto_title,
1602
1625
  NULLIF(sa.alias, '') AS alias,
1603
1626
  s.file_path
@@ -1605,38 +1628,38 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1605
1628
  JOIN projects p ON p.id = s.project_id
1606
1629
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1607
1630
  WHERE ${n}
1608
- ORDER BY p.name ASC, s.started_at ASC`).all(s)}function yS(e,t,s){if(!e.started_at)return null;let n=Date.parse(e.started_at);if(!Number.isFinite(n))return null;let r=e.ended_at?Date.parse(e.ended_at):null,o=Ul(e.file_path,{maxUserMessages:7}),i=t?.get(e.id);return{id:e.id,started_at_ms:n,ended_at_ms:Number.isFinite(r)?r:null,first_user_message:e.first_user_message,recent_user_messages:o.recent_user_messages,auto_title:e.auto_title,touched_files:o.touched_files,mean_embedding:i?.full_mean??null,head_pool:i?.head_pool??null,tail_pool:i?.tail_pool??null,sample_chunks:i?.sample_chunks??[],cluster_id:s?.get(e.id)??null,authored_paths:o.authored_paths,authored_content:o.authored_content}}function Hs(e){let t=e.id.slice(0,8),s=e.alias||e.auto_title||(e.first_user_message?e.first_user_message.slice(0,50):"(no title)");return`${t} ${s}`}function Vl(e){if(!e)return"?";let t=new Date(e);if(Number.isNaN(t.getTime()))return"?";let s=n=>String(n).padStart(2,"0");return`${t.getFullYear()}-${s(t.getMonth()+1)}-${s(t.getDate())} ${s(t.getHours())}:${s(t.getMinutes())}`}function Zl(e){let t=e.alias||e.auto_title||(e.first_user_message?e.first_user_message.slice(0,60).replace(/\n/g," ").trim():`thread from ${e.id.slice(0,8)}`);return t.length>80?t.slice(0,77)+"...":t}async function TS(e){if(!e.rescore.enabled)return{proposals:e.proposals,ran:!1,considered:0,promoted:0,demoted:0,unsure:0,failed:0,capped:!1};let t=e.rescore.band??Gt,s=e.rescore.cap??Gl,n=e.rescore.model??Bs,r=new Map(e.scannables.map(m=>[m.id,m])),o=zl(e.proposals,r,t);if(o.length===0)return{proposals:e.proposals,ran:!0,considered:0,promoted:0,demoted:0,unsure:0,failed:0,capped:!1};if(o.length>s)return{proposals:e.proposals,ran:!1,considered:o.length,promoted:0,demoted:0,unsure:0,failed:0,capped:!0};let i=new Map,a=0,l=0,c=0,u=0;for(let m=0;m<o.length&&!e.signal?.aborted;m++){let f=o[m],g=await Yl(f,{model:n,signal:e.signal});g?(i.set(ql(f.step1),g),g.verdict==="same_workflow"?a++:g.verdict==="unrelated"?l++:c++):u++,e.onProgress?.({phase:"rescoring",current:m+1,total:o.length,verdict:g?.verdict??"failed"})}return{proposals:Kl({proposals:e.proposals,rescored:i,applyThreshold:e.applyThreshold}),ran:!0,considered:o.length,promoted:a,demoted:l,unsure:c,failed:u,capped:!1}}async function wS(e){let t=_(),s=new Map(e.rows.map(c=>[c.id,c])),n=Fl(e.edges,e.scannables),r=new Date().toISOString(),o=[],i=new Map,a=0;for(let c of n){if(a++,e.signal?.aborted)break;let u=s.get(c.rootId),p=Zl(u);if(!e.llmNames){i.set(c.rootId,p),e.onProgress?.({phase:"naming",current:a,total:n.length,thread_name:p});continue}let f=await ES({rootRow:u,sessionIds:c.sessionIds,rowById:s,signal:e.signal,model:e.model})??p;i.set(c.rootId,f),e.onProgress?.({phase:"naming",current:a,total:n.length,thread_name:f})}return t.transaction(()=>{for(let c of n){if(!i.has(c.rootId))continue;let u=s.get(c.rootId),p=`auto-scan-${hS()}`,m=i.get(c.rootId)??Zl(u),f=`Auto-detected workflow chain (${c.sessionIds.length} sessions). Source: auto-scan-v1.`;t.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, ?, ?)").run(p,m,f,r),t.prepare(`INSERT INTO thread_edges
1631
+ ORDER BY p.name ASC, s.started_at ASC`).all(s)}function iy(e,t,s){if(!e.started_at)return null;let n=Date.parse(e.started_at);if(!Number.isFinite(n))return null;let r=e.ended_at?Date.parse(e.ended_at):null,o=ud(e.file_path,{maxUserMessages:7}),i=t?.get(e.id);return{id:e.id,started_at_ms:n,ended_at_ms:Number.isFinite(r)?r:null,first_user_message:e.first_user_message,recent_user_messages:o.recent_user_messages,auto_title:e.auto_title,touched_files:o.touched_files,mean_embedding:i?.full_mean??null,head_pool:i?.head_pool??null,tail_pool:i?.tail_pool??null,sample_chunks:i?.sample_chunks??[],cluster_id:s?.get(e.id)??null,authored_paths:o.authored_paths,authored_content:o.authored_content}}function Vs(e){let t=e.id.slice(0,8),s=e.alias||e.auto_title||(e.first_user_message?e.first_user_message.slice(0,50):"(no title)");return`${t} ${s}`}function Td(e){if(!e)return"?";let t=new Date(e);if(Number.isNaN(t.getTime()))return"?";let s=n=>String(n).padStart(2,"0");return`${t.getFullYear()}-${s(t.getMonth()+1)}-${s(t.getDate())} ${s(t.getHours())}:${s(t.getMinutes())}`}function wd(e){let t=e.alias||e.auto_title||(e.first_user_message?e.first_user_message.slice(0,60).replace(/\n/g," ").trim():`thread from ${e.id.slice(0,8)}`);return t.length>80?t.slice(0,77)+"...":t}async function ay(e){if(!e.rescore.enabled)return{proposals:e.proposals,ran:!1,considered:0,promoted:0,demoted:0,unsure:0,failed:0,capped:!1};let t=e.rescore.band??qt,s=e.rescore.cap??hd,n=e.rescore.model??qs,r=new Map(e.scannables.map(p=>[p.id,p])),o=Ed(e.proposals,r,t);if(o.length===0)return{proposals:e.proposals,ran:!0,considered:0,promoted:0,demoted:0,unsure:0,failed:0,capped:!1};if(o.length>s)return{proposals:e.proposals,ran:!1,considered:o.length,promoted:0,demoted:0,unsure:0,failed:0,capped:!0};let i=new Map,a=0,l=0,c=0,u=0;for(let p=0;p<o.length&&!e.signal?.aborted;p++){let f=o[p],g=await bd(f,{model:n,signal:e.signal});g?(i.set(yd(f.step1),g),g.verdict==="same_workflow"?a++:g.verdict==="unrelated"?l++:c++):u++,e.onProgress?.({phase:"rescoring",current:p+1,total:o.length,verdict:g?.verdict??"failed"})}return{proposals:Sd({proposals:e.proposals,rescored:i,applyThreshold:e.applyThreshold}),ran:!0,considered:o.length,promoted:a,demoted:l,unsure:c,failed:u,capped:!1}}async function cy(e){let t=_(),s=new Map(e.rows.map(c=>[c.id,c])),n=dd(e.edges,e.scannables),r=new Date().toISOString(),o=[],i=new Map,a=0;for(let c of n){if(a++,e.signal?.aborted)break;let u=s.get(c.rootId),m=wd(u);if(!e.llmNames){i.set(c.rootId,m),e.onProgress?.({phase:"naming",current:a,total:n.length,thread_name:m});continue}let f=await ny({rootRow:u,sessionIds:c.sessionIds,rowById:s,signal:e.signal,model:e.model})??m;i.set(c.rootId,f),e.onProgress?.({phase:"naming",current:a,total:n.length,thread_name:f})}return t.transaction(()=>{for(let c of n){if(!i.has(c.rootId))continue;let u=s.get(c.rootId),m=`auto-scan-${sy()}`,p=i.get(c.rootId)??wd(u),f=`Auto-detected workflow chain (${c.sessionIds.length} sessions). Source: auto-scan-v1.`;t.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, ?, ?)").run(m,p,f,r),t.prepare(`INSERT INTO thread_edges
1609
1632
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
1610
- VALUES (?, ?, NULL, 'origin', 1.0, 'auto-scan-v1', ?)`).run(p,c.rootId,r);let g=new Map;for(let h of e.edges)c.sessionIds.includes(h.child_id)&&g.set(h.child_id,h);for(let h of c.sessionIds){if(h===c.rootId)continue;let E=g.get(h);E&&t.prepare(`INSERT INTO thread_edges
1633
+ VALUES (?, ?, NULL, 'origin', 1.0, 'auto-scan-v1', ?)`).run(m,c.rootId,r);let g=new Map;for(let h of e.edges)c.sessionIds.includes(h.child_id)&&g.set(h.child_id,h);for(let h of c.sessionIds){if(h===c.rootId)continue;let E=g.get(h);E&&t.prepare(`INSERT INTO thread_edges
1611
1634
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
1612
- VALUES (?, ?, ?, 'child', ?, 'auto-scan-v1', ?)`).run(p,h,E.parent_id,E.confidence,r)}o.push({thread_id:p,name:m,session_count:c.sessionIds.length})}})(),{project:e.project,threads:o}}async function Ql(e){let t=!!e.apply,s=e.confidenceMin?Number(e.confidenceMin):t?Dr:$r;if(!Number.isFinite(s)||s<0||s>1){console.error(d.err("--confidence-min must be a number in [0, 1]")),process.exitCode=1;return}let n=!!e.llmRescore,r={lo:e.rescoreBandLo?Number(e.rescoreBandLo):Gt.lo,hi:e.rescoreBandHi?Number(e.rescoreBandHi):Gt.hi};if(n&&(!Number.isFinite(r.lo)||!Number.isFinite(r.hi)||r.lo<0||r.hi>1||r.lo>r.hi)){console.error(d.err("--rescore-band-lo/hi must satisfy 0 \u2264 lo \u2264 hi \u2264 1")),process.exitCode=1;return}let o=e.rescoreModel??Bs,i=SS({project:e.project});if(i.length===0){console.log(d.dim("no sessions matched"));return}let{byProject:a,scannablesByProject:l}=bS(i),c=n?Math.min(s,r.lo):s,u=new Map,p=0;for(let[f]of a){let g=l.get(f)??[],h=Pl(g,c);if(n&&h.length>0){let E=await TS({proposals:h,scannables:g,applyThreshold:s,rescore:{enabled:!0,band:r,model:o}});h=E.proposals,E.capped?(console.error(d.err(`[${f}] borderline pairs exceeded cap (${E.considered}); skipped LLM rescore. Tighten the band or scan a smaller project.`)),h=h.filter(b=>b.confidence>=s)):n?E.failed===E.considered&&E.considered>0&&(h=h.filter(b=>b.confidence>=s)):h=h.filter(b=>b.confidence>=s)}else n&&(h=h.filter(E=>E.confidence>=s));u.set(f,{proposals:h,scannables:g}),p+=h.length}if(t){if(p===0){console.log(d.dim("no edges above threshold; nothing to apply"));return}let f={threads_created:0,edges_written:0,per_project:[]},g=!e.noLlmNames;for(let[h,{proposals:E,scannables:b}]of u){if(E.length===0)continue;let S=await wS({project:h,rows:a.get(h),edges:E,scannables:b,llmNames:g});f.per_project.push(S),f.threads_created+=S.threads.length,f.edges_written+=E.length+S.threads.length}if(e.json){console.log(JSON.stringify({mode:"apply",threshold:s,...f},null,2));return}console.log(d.ok(`Applied ${f.threads_created} thread${f.threads_created===1?"":"s"} with ${f.edges_written} edges total (threshold ${s}).`));for(let h of f.per_project){console.log(` ${d.bold(h.project)}`);for(let E of h.threads)console.log(` ${d.dim(E.thread_id.slice(0,16)+"\u2026")} ${E.name} ${d.dim(`(${E.session_count} sessions)`)}`)}console.log(),console.log(d.dim("Rollback: sqlite3 ~/.recall/db.sqlite \\")),console.log(d.dim(` "DELETE FROM thread_edges WHERE source='auto-scan-v1';`)),console.log(d.dim(` DELETE FROM threads WHERE id LIKE 'auto-scan-%';"`));return}if(e.json){let f=[];for(let[g,{proposals:h}]of u){let E=new Map(a.get(g).map(b=>[b.id,b]));for(let b of h)f.push({project:g,parent_id:b.parent_id,parent_label:Hs(E.get(b.parent_id)),child_id:b.child_id,child_label:Hs(E.get(b.child_id)),confidence:b.confidence,signals:b.signals,reasons:b.reasons})}console.log(JSON.stringify({mode:"dry-run",threshold:s,total:p,edges:f},null,2));return}console.log(d.dim(`recall thread scan \xB7 ${a.size} project${a.size===1?"":"s"} \xB7 DRY RUN \xB7 threshold ${s}`)),console.log(d.dim(" Algorithm: temporal + continuation phrase + file overlap + same brand.")),console.log();for(let[f,g]of a){let{proposals:h}=u.get(f),E=new Map(g.map(S=>[S.id,S]));if(console.log(d.bold(f)),console.log(d.dim(` ${g.length} eligible session${g.length===1?"":"s"}; ${h.length} parent-child edge${h.length===1?"":"s"} proposed.`)),h.length===0){console.log(d.dim(" (no edges above threshold \u2014 all sessions are origins)")),console.log();continue}let b=[...h].sort((S,C)=>{let x=E.get(S.child_id),L=E.get(C.child_id);return(x.started_at??"").localeCompare(L.started_at??"")});for(let S of b){let C=E.get(S.parent_id),x=E.get(S.child_id),L=S.confidence.toFixed(2);console.log(` ${d.dim(Vl(C.started_at).padEnd(16))} ${d.bold("PARENT")} ${Hs(C)}`),console.log(` ${d.dim(Vl(x.started_at).padEnd(16))} ${d.bold(" \u2514\u2500 child")} ${Hs(x)} ${d.dim(`[conf ${L}]`)}`),console.log(` ${" ".repeat(28)}${d.dim(S.reasons.join(" \xB7 "))}`),console.log()}}let m=Array.from(a.entries()).reduce((f,[g,h])=>f+(h.length-(u.get(g)?.proposals.length??0)),0);console.log(`${p} edge${p===1?"":"s"} proposed across ${a.size} project${a.size===1?"":"s"}; ${m} origin session${m===1?"":"s"} (no proposed parent).`),console.log(d.dim(` This is a DRY RUN. To write: rerun with --apply (default threshold ${Dr}).`))}M();j();import{existsSync as RS,readFileSync as xS}from"node:fs";function kS(){let e=`${R}/daemon.port`;if(!RS(e))return null;try{let t=xS(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function CS(e){try{return(await ft(`http://127.0.0.1:${e}/api/health`,{signal:AbortSignal.timeout(1e4)})).ok}catch{return!1}}async function NS(e){let t=await ft(`http://127.0.0.1:${e}/api/projects`);if(!t.ok)throw new Error(`failed to list projects: HTTP ${t.status}`);return await t.json()}function LS(e,t){let s=t.replace(/\/+$/,""),n=null,r=-1;for(let o of e){if(!o.decoded_path)continue;let i=o.decoded_path.replace(/\/+$/,"");(s===i||s.startsWith(i+"/"))&&i.length>r&&(n=o,r=i.length)}return n}function OS(e,t){let s=e.find(r=>r.name===t);if(s)return s;let n=e.filter(r=>r.name.toLowerCase().includes(t.toLowerCase()));return n.length===1?n[0]:null}function ed(e){return e.alias||e.auto_title||(e.first_user_message?Y(e.first_user_message,60):"(no title)")}function AS(e){if(!e)return"?";let t=new Date(e);if(Number.isNaN(t.getTime()))return"?";let s=n=>String(n).padStart(2,"0");return`${t.getFullYear()}-${s(t.getMonth()+1)}-${s(t.getDate())} ${s(t.getHours())}:${s(t.getMinutes())}`}function IS(e,t){let s=t==="preflight"?d.dim(`recall threads sync \xB7 ${e.project.name} \xB7 PREFLIGHT (no writes)`):d.dim(`recall threads sync \xB7 ${e.project.name}`);if(console.log(s),console.log(),e.thread.exists?console.log(` ${d.bold("Thread")} ${e.thread.name} ${d.dim(`(reusing, ${e.thread.existing_session_count} existing session${e.thread.existing_session_count===1?"":"s"})`)}`):console.log(` ${d.bold("Thread")} ${e.thread.name} ${d.ok("(new)")}`),console.log(),e.candidates.length===0){if(console.log(d.dim(" No active sessions in the rolling window.")),e.warnings.length>0)for(let c of e.warnings)console.log(d.warn(` \u26A0 ${c}`));return}let n=new Map;for(let c of e.proposed_edges)n.set(c.child_id,c);let r=new Map;for(let c of e.preserved_manual_edges)r.set(c.session_id,c.parent_session_id);let o=new Set(e.candidates.map(c=>c.session_id)),i=e.proposed_additions.length,a=e.candidates.length-i;console.log(` ${d.bold("Candidates")} ${e.candidates.length} active session${e.candidates.length===1?"":"s"} ${d.dim(`(${i} new \xB7 ${a} keep)`)}`);let l=String(e.candidates.length).length;for(let c=0;c<e.candidates.length;c++){let u=e.candidates[c],m=e.proposed_additions.some(S=>S.session_id===u.session_id)?d.ok("NEW "):d.dim("keep"),f=n.get(u.session_id)??(r.has(u.session_id)&&r.get(u.session_id)!==null,null),g=f&&o.has(f.parent_id)?" \u2514\u2500 ":" ",h=AS(u.started_at),E=d.dim(`${String(c+1).padStart(l," ")}.`);console.log(` ${E} ${m} ${d.dim(h.padEnd(16))} ${g}${d.dim(u.session_id.slice(0,8))} ${ed(u)}`);let b=" ".repeat(l+2);if(f&&o.has(f.parent_id)){let S=f.confidence.toFixed(2),C=ed(e.candidates.find(x=>x.session_id===f.parent_id));console.log(` ${b}${" ".repeat(28)} parent ${d.dim(f.parent_id.slice(0,8))} (${C}) ${d.dim(`[conf ${S}]`)}`),console.log(` ${b}${" ".repeat(28)} ${d.dim(f.reasons.join(" \xB7 "))}`)}if(r.has(u.session_id)){let S=r.get(u.session_id);S&&console.log(` ${b}${" ".repeat(28)} ${d.bold("manual parent preserved")} ${d.dim(S.slice(0,8))}`)}}if(e.preserved_manual_edges.length>0&&(console.log(),console.log(d.dim(` ${e.preserved_manual_edges.length} manual edge${e.preserved_manual_edges.length===1?"":"s"} will be preserved.`))),e.warnings.length>0){console.log();for(let c of e.warnings)console.log(d.warn(` \u26A0 ${c}`))}}function vS(e){console.log(),console.log(d.ok(`Added ${e.added} session${e.added===1?"":"s"}, set ${e.edges_set} parent edge${e.edges_set===1?"":"s"}, preserved ${e.preserved_manual} manual edge${e.preserved_manual===1?"":"s"}.`)),console.log(d.dim(` thread_id: ${e.thread_id}`))}async function td(e){let t=kS();if(!t){console.error(d.err("Daemon is not running. Start it with `recall start`, then re-run this command.")),process.exitCode=1;return}if(!await CS(t)){console.error(d.err(`Daemon on port ${t} is not responding. Try \`recall stop && recall start\`.`)),process.exitCode=1;return}let n;try{n=await NS(t)}catch(c){console.error(d.err(c.message)),process.exitCode=1;return}let r;if(e.project){if(r=OS(n,e.project),!r){console.error(d.err(`No project matching "${e.project}". Run \`recall projects\` to list known projects.`)),process.exitCode=1;return}}else{let c=process.cwd();if(r=LS(n,c),!r){console.error(d.err(`Current directory (${c}) does not match any known project. Pass --project <name> or cd into a project root.`)),process.exitCode=1;return}}let o=e.windowHours?Number(e.windowHours):void 0;if(o!==void 0&&(!Number.isFinite(o)||o<=0)){console.error(d.err("--window-hours must be a positive number")),process.exitCode=1;return}let i=e.preflight?"preflight":"apply",a={project_id:r.id,mode:i};o!==void 0&&(a.window_hours=o);let l;try{let c=await et("POST",`http://127.0.0.1:${t}/api/threads/sync-active`,a);if(!c.ok){let u=await c.text().catch(()=>"");throw new Error(`HTTP ${c.status}: ${u.slice(0,200)}`)}l=await c.json()}catch(c){console.error(d.err(`Sync failed: ${c.message}`)),process.exitCode=1;return}if(e.json){console.log(JSON.stringify({mode:i,...l},null,2));return}IS(l.plan,i),i==="apply"&&l.result?vS(l.result):i==="preflight"&&(console.log(),console.log(d.dim(" This is a PREFLIGHT. To write: re-run without --preflight.")))}T();import{writeFileSync as sy,existsSync as ny,mkdirSync as ry}from"node:fs";import{join as Sd}from"node:path";import{homedir as oy}from"node:os";import{execSync as Nt}from"node:child_process";import ZS from"satori";import QS from"sharp";import{readFileSync as Hr}from"node:fs";import{join as Vs}from"node:path";var Wr=Vs(ye(),"dist","share","fonts"),hd=!1,Ed=[];function ey(){return hd||(Ed=[{name:"Inter",data:Hr(Vs(Wr,"Inter-Regular.woff")),weight:400,style:"normal"},{name:"Inter",data:Hr(Vs(Wr,"Inter-Bold.woff")),weight:700,style:"normal"},{name:"JetBrains Mono",data:Hr(Vs(Wr,"JetBrainsMono-Regular.woff")),weight:400,style:"normal"}],hd=!0),Ed}async function ty(e){switch(e){case"A":return await Promise.resolve().then(()=>(od(),rd));case"B":return await Promise.resolve().then(()=>(cd(),ad));case"C":return await Promise.resolve().then(()=>(ud(),dd));case"D":return await Promise.resolve().then(()=>(gd(),md));case"E":return await Promise.resolve().then(()=>(_d(),fd))}}async function Zs(e,t){let n=(await ty(e)).render(t),i=await ZS(n,{width:1080,height:e==="E"?1920:1350,fonts:ey()});return await QS(Buffer.from(i)).png({quality:90}).toBuffer()}function bd(e,t){let s=new URLSearchParams({v:"1",s:t,t:e.sessionTitle,d:e.sessionDate.slice(0,10),tk:String(e.tokenCount),m:String(e.messageCount)});return typeof e.inputTokens=="number"&&s.set("i",String(e.inputTokens)),typeof e.outputTokens=="number"&&s.set("o",String(e.outputTokens)),e.verdict&&s.set("q",e.verdict),`https://clauderecall.com/card?${s.toString()}`}function iy(e,t){if(t.length>=32)return e.prepare("SELECT id FROM sessions WHERE id = ?").get(t)?.id??null;let s=e.prepare("SELECT session_id FROM session_aliases WHERE alias = ?").get(t);if(s)return s.session_id;let n=e.prepare("SELECT id FROM sessions WHERE id LIKE ? LIMIT 2").all(t+"%");return n.length===1?n[0].id:(n.length===0||process.stderr.write(`ambiguous id prefix "${t}". be more specific.
1613
- `),null)}function ay(e){return e.prepare("SELECT session_id FROM recall_events ORDER BY recalled_at DESC LIMIT 1").get()?.session_id??null}function cy(e,t){let s=e.prepare(`
1635
+ VALUES (?, ?, ?, 'child', ?, 'auto-scan-v1', ?)`).run(m,h,E.parent_id,E.confidence,r)}o.push({thread_id:m,name:p,session_count:c.sessionIds.length})}})(),{project:e.project,threads:o}}async function Rd(e){let t=!!e.apply,s=e.confidenceMin?Number(e.confidenceMin):t?zr:Yr;if(!Number.isFinite(s)||s<0||s>1){console.error(d.err("--confidence-min must be a number in [0, 1]")),process.exitCode=1;return}let n=!!e.llmRescore,r={lo:e.rescoreBandLo?Number(e.rescoreBandLo):qt.lo,hi:e.rescoreBandHi?Number(e.rescoreBandHi):qt.hi};if(n&&(!Number.isFinite(r.lo)||!Number.isFinite(r.hi)||r.lo<0||r.hi>1||r.lo>r.hi)){console.error(d.err("--rescore-band-lo/hi must satisfy 0 \u2264 lo \u2264 hi \u2264 1")),process.exitCode=1;return}let o=e.rescoreModel??qs,i=oy({project:e.project});if(i.length===0){console.log(d.dim("no sessions matched"));return}let{byProject:a,scannablesByProject:l}=ry(i),c=n?Math.min(s,r.lo):s,u=new Map,m=0;for(let[f]of a){let g=l.get(f)??[],h=ld(g,c);if(n&&h.length>0){let E=await ay({proposals:h,scannables:g,applyThreshold:s,rescore:{enabled:!0,band:r,model:o}});h=E.proposals,E.capped?(console.error(d.err(`[${f}] borderline pairs exceeded cap (${E.considered}); skipped LLM rescore. Tighten the band or scan a smaller project.`)),h=h.filter(b=>b.confidence>=s)):n?E.failed===E.considered&&E.considered>0&&(h=h.filter(b=>b.confidence>=s)):h=h.filter(b=>b.confidence>=s)}else n&&(h=h.filter(E=>E.confidence>=s));u.set(f,{proposals:h,scannables:g}),m+=h.length}if(t){if(m===0){console.log(d.dim("no edges above threshold; nothing to apply"));return}let f={threads_created:0,edges_written:0,per_project:[]},g=!e.noLlmNames;for(let[h,{proposals:E,scannables:b}]of u){if(E.length===0)continue;let S=await cy({project:h,rows:a.get(h),edges:E,scannables:b,llmNames:g});f.per_project.push(S),f.threads_created+=S.threads.length,f.edges_written+=E.length+S.threads.length}if(e.json){console.log(JSON.stringify({mode:"apply",threshold:s,...f},null,2));return}console.log(d.ok(`Applied ${f.threads_created} thread${f.threads_created===1?"":"s"} with ${f.edges_written} edges total (threshold ${s}).`));for(let h of f.per_project){console.log(` ${d.bold(h.project)}`);for(let E of h.threads)console.log(` ${d.dim(E.thread_id.slice(0,16)+"\u2026")} ${E.name} ${d.dim(`(${E.session_count} sessions)`)}`)}console.log(),console.log(d.dim("Rollback: sqlite3 ~/.recall/db.sqlite \\")),console.log(d.dim(` "DELETE FROM thread_edges WHERE source='auto-scan-v1';`)),console.log(d.dim(` DELETE FROM threads WHERE id LIKE 'auto-scan-%';"`));return}if(e.json){let f=[];for(let[g,{proposals:h}]of u){let E=new Map(a.get(g).map(b=>[b.id,b]));for(let b of h)f.push({project:g,parent_id:b.parent_id,parent_label:Vs(E.get(b.parent_id)),child_id:b.child_id,child_label:Vs(E.get(b.child_id)),confidence:b.confidence,signals:b.signals,reasons:b.reasons})}console.log(JSON.stringify({mode:"dry-run",threshold:s,total:m,edges:f},null,2));return}console.log(d.dim(`recall thread scan \xB7 ${a.size} project${a.size===1?"":"s"} \xB7 DRY RUN \xB7 threshold ${s}`)),console.log(d.dim(" Algorithm: temporal + continuation phrase + file overlap + same brand.")),console.log();for(let[f,g]of a){let{proposals:h}=u.get(f),E=new Map(g.map(S=>[S.id,S]));if(console.log(d.bold(f)),console.log(d.dim(` ${g.length} eligible session${g.length===1?"":"s"}; ${h.length} parent-child edge${h.length===1?"":"s"} proposed.`)),h.length===0){console.log(d.dim(" (no edges above threshold \u2014 all sessions are origins)")),console.log();continue}let b=[...h].sort((S,N)=>{let x=E.get(S.child_id),L=E.get(N.child_id);return(x.started_at??"").localeCompare(L.started_at??"")});for(let S of b){let N=E.get(S.parent_id),x=E.get(S.child_id),L=S.confidence.toFixed(2);console.log(` ${d.dim(Td(N.started_at).padEnd(16))} ${d.bold("PARENT")} ${Vs(N)}`),console.log(` ${d.dim(Td(x.started_at).padEnd(16))} ${d.bold(" \u2514\u2500 child")} ${Vs(x)} ${d.dim(`[conf ${L}]`)}`),console.log(` ${" ".repeat(28)}${d.dim(S.reasons.join(" \xB7 "))}`),console.log()}}let p=Array.from(a.entries()).reduce((f,[g,h])=>f+(h.length-(u.get(g)?.proposals.length??0)),0);console.log(`${m} edge${m===1?"":"s"} proposed across ${a.size} project${a.size===1?"":"s"}; ${p} origin session${p===1?"":"s"} (no proposed parent).`),console.log(d.dim(` This is a DRY RUN. To write: rerun with --apply (default threshold ${zr}).`))}I();j();import{existsSync as ly,readFileSync as dy}from"node:fs";function uy(){let e=`${R}/daemon.port`;if(!ly(e))return null;try{let t=dy(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function my(e){try{return(await _t(`http://127.0.0.1:${e}/api/health`,{signal:AbortSignal.timeout(1e4)})).ok}catch{return!1}}async function py(e){let t=await _t(`http://127.0.0.1:${e}/api/projects`);if(!t.ok)throw new Error(`failed to list projects: HTTP ${t.status}`);return await t.json()}function gy(e,t){let s=t.replace(/\/+$/,""),n=null,r=-1;for(let o of e){if(!o.decoded_path)continue;let i=o.decoded_path.replace(/\/+$/,"");(s===i||s.startsWith(i+"/"))&&i.length>r&&(n=o,r=i.length)}return n}function fy(e,t){let s=e.find(r=>r.name===t);if(s)return s;let n=e.filter(r=>r.name.toLowerCase().includes(t.toLowerCase()));return n.length===1?n[0]:null}function xd(e){return e.alias||e.auto_title||(e.first_user_message?Y(e.first_user_message,60):"(no title)")}function _y(e){if(!e)return"?";let t=new Date(e);if(Number.isNaN(t.getTime()))return"?";let s=n=>String(n).padStart(2,"0");return`${t.getFullYear()}-${s(t.getMonth()+1)}-${s(t.getDate())} ${s(t.getHours())}:${s(t.getMinutes())}`}function hy(e,t){let s=t==="preflight"?d.dim(`recall threads sync \xB7 ${e.project.name} \xB7 PREFLIGHT (no writes)`):d.dim(`recall threads sync \xB7 ${e.project.name}`);if(console.log(s),console.log(),e.thread.exists?console.log(` ${d.bold("Thread")} ${e.thread.name} ${d.dim(`(reusing, ${e.thread.existing_session_count} existing session${e.thread.existing_session_count===1?"":"s"})`)}`):console.log(` ${d.bold("Thread")} ${e.thread.name} ${d.ok("(new)")}`),console.log(),e.candidates.length===0){if(console.log(d.dim(" No active sessions in the rolling window.")),e.warnings.length>0)for(let c of e.warnings)console.log(d.warn(` \u26A0 ${c}`));return}let n=new Map;for(let c of e.proposed_edges)n.set(c.child_id,c);let r=new Map;for(let c of e.preserved_manual_edges)r.set(c.session_id,c.parent_session_id);let o=new Set(e.candidates.map(c=>c.session_id)),i=e.proposed_additions.length,a=e.candidates.length-i;console.log(` ${d.bold("Candidates")} ${e.candidates.length} active session${e.candidates.length===1?"":"s"} ${d.dim(`(${i} new \xB7 ${a} keep)`)}`);let l=String(e.candidates.length).length;for(let c=0;c<e.candidates.length;c++){let u=e.candidates[c],p=e.proposed_additions.some(S=>S.session_id===u.session_id)?d.ok("NEW "):d.dim("keep"),f=n.get(u.session_id)??(r.has(u.session_id)&&r.get(u.session_id)!==null,null),g=f&&o.has(f.parent_id)?" \u2514\u2500 ":" ",h=_y(u.started_at),E=d.dim(`${String(c+1).padStart(l," ")}.`);console.log(` ${E} ${p} ${d.dim(h.padEnd(16))} ${g}${d.dim(u.session_id.slice(0,8))} ${xd(u)}`);let b=" ".repeat(l+2);if(f&&o.has(f.parent_id)){let S=f.confidence.toFixed(2),N=xd(e.candidates.find(x=>x.session_id===f.parent_id));console.log(` ${b}${" ".repeat(28)} parent ${d.dim(f.parent_id.slice(0,8))} (${N}) ${d.dim(`[conf ${S}]`)}`),console.log(` ${b}${" ".repeat(28)} ${d.dim(f.reasons.join(" \xB7 "))}`)}if(r.has(u.session_id)){let S=r.get(u.session_id);S&&console.log(` ${b}${" ".repeat(28)} ${d.bold("manual parent preserved")} ${d.dim(S.slice(0,8))}`)}}if(e.preserved_manual_edges.length>0&&(console.log(),console.log(d.dim(` ${e.preserved_manual_edges.length} manual edge${e.preserved_manual_edges.length===1?"":"s"} will be preserved.`))),e.warnings.length>0){console.log();for(let c of e.warnings)console.log(d.warn(` \u26A0 ${c}`))}}function Ey(e){console.log(),console.log(d.ok(`Added ${e.added} session${e.added===1?"":"s"}, set ${e.edges_set} parent edge${e.edges_set===1?"":"s"}, preserved ${e.preserved_manual} manual edge${e.preserved_manual===1?"":"s"}.`)),console.log(d.dim(` thread_id: ${e.thread_id}`))}async function kd(e){let t=uy();if(!t){console.error(d.err("Daemon is not running. Start it with `recall start`, then re-run this command.")),process.exitCode=1;return}if(!await my(t)){console.error(d.err(`Daemon on port ${t} is not responding. Try \`recall stop && recall start\`.`)),process.exitCode=1;return}let n;try{n=await py(t)}catch(c){console.error(d.err(c.message)),process.exitCode=1;return}let r;if(e.project){if(r=fy(n,e.project),!r){console.error(d.err(`No project matching "${e.project}". Run \`recall projects\` to list known projects.`)),process.exitCode=1;return}}else{let c=process.cwd();if(r=gy(n,c),!r){console.error(d.err(`Current directory (${c}) does not match any known project. Pass --project <name> or cd into a project root.`)),process.exitCode=1;return}}let o=e.windowHours?Number(e.windowHours):void 0;if(o!==void 0&&(!Number.isFinite(o)||o<=0)){console.error(d.err("--window-hours must be a positive number")),process.exitCode=1;return}let i=e.preflight?"preflight":"apply",a={project_id:r.id,mode:i};o!==void 0&&(a.window_hours=o);let l;try{let c=await tt("POST",`http://127.0.0.1:${t}/api/threads/sync-active`,a);if(!c.ok){let u=await c.text().catch(()=>"");throw new Error(`HTTP ${c.status}: ${u.slice(0,200)}`)}l=await c.json()}catch(c){console.error(d.err(`Sync failed: ${c.message}`)),process.exitCode=1;return}if(e.json){console.log(JSON.stringify({mode:i,...l},null,2));return}hy(l.plan,i),i==="apply"&&l.result?Ey(l.result):i==="preflight"&&(console.log(),console.log(d.dim(" This is a PREFLIGHT. To write: re-run without --preflight.")))}T();import{writeFileSync as By,existsSync as Hy,mkdirSync as Wy}from"node:fs";import{join as Jd}from"node:path";import{homedir as Xy}from"node:os";import{execSync as It}from"node:child_process";import jy from"satori";import Py from"sharp";import{readFileSync as eo}from"node:fs";import{join as an}from"node:path";var to=an(Te(),"dist","share","fonts"),Hd=!1,Wd=[];function Fy(){return Hd||(Wd=[{name:"Inter",data:eo(an(to,"Inter-Regular.woff")),weight:400,style:"normal"},{name:"Inter",data:eo(an(to,"Inter-Bold.woff")),weight:700,style:"normal"},{name:"JetBrains Mono",data:eo(an(to,"JetBrainsMono-Regular.woff")),weight:400,style:"normal"}],Hd=!0),Wd}async function Uy(e){switch(e){case"A":return await Promise.resolve().then(()=>(Od(),Ld));case"B":return await Promise.resolve().then(()=>(vd(),Id));case"C":return await Promise.resolve().then(()=>($d(),Dd));case"D":return await Promise.resolve().then(()=>(Fd(),Pd));case"E":return await Promise.resolve().then(()=>(Bd(),Ud))}}async function cn(e,t){let n=(await Uy(e)).render(t),i=await jy(n,{width:1080,height:e==="E"?1920:1350,fonts:Fy()});return await Py(Buffer.from(i)).png({quality:90}).toBuffer()}function Xd(e,t){let s=new URLSearchParams({v:"1",s:t,t:e.sessionTitle,d:e.sessionDate.slice(0,10),tk:String(e.tokenCount),m:String(e.messageCount)});return typeof e.inputTokens=="number"&&s.set("i",String(e.inputTokens)),typeof e.outputTokens=="number"&&s.set("o",String(e.outputTokens)),e.verdict&&s.set("q",e.verdict),`https://clauderecall.com/card?${s.toString()}`}function Jy(e,t){if(t.length>=32)return e.prepare("SELECT id FROM sessions WHERE id = ?").get(t)?.id??null;let s=e.prepare("SELECT session_id FROM session_aliases WHERE alias = ?").get(t);if(s)return s.session_id;let n=e.prepare("SELECT id FROM sessions WHERE id LIKE ? LIMIT 2").all(t+"%");return n.length===1?n[0].id:(n.length===0||process.stderr.write(`ambiguous id prefix "${t}". be more specific.
1636
+ `),null)}function Gy(e){return e.prepare("SELECT session_id FROM recall_events ORDER BY recalled_at DESC LIMIT 1").get()?.session_id??null}function zy(e,t){let s=e.prepare(`
1614
1637
  SELECT s.id, s.started_at, s.message_count, s.first_user_message, s.auto_title,
1615
1638
  s.total_input_tokens, s.total_output_tokens
1616
1639
  FROM sessions s WHERE s.id = ?
1617
1640
  `).get(t);if(!s)return null;let r=e.prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(t)?.alias||s.auto_title||s.first_user_message?.slice(0,80)||s.id.slice(0,8),o=e.prepare(`
1618
1641
  SELECT tool_names, raw_json FROM messages
1619
1642
  WHERE session_id = ? AND tool_names IS NOT NULL AND tool_names != ''
1620
- `).all(t),i=o.length,a=new Set;for(let u of o){if(!/Read|Write|Edit/.test(u.tool_names))continue;let p=u.raw_json.match(/"(?:file_path|path)":\s*"([^"]+)"/g);if(p)for(let m of p){let f=m.match(/":\s*"([^"]+)"/);f&&a.add(f[1])}}let l=s.total_input_tokens??0,c=s.total_output_tokens??0;return{sessionTitle:r,sessionDate:s.started_at??new Date().toISOString(),recallDate:new Date().toISOString(),tokenCount:l+c,inputTokens:l,outputTokens:c,messageCount:s.message_count,filesReferenced:a.size,toolCallCount:i,verdict:""}}function ly(e){process.platform==="darwin"?Nt(`osascript -e 'set the clipboard to (read (POSIX file "${e}") as \xABclass PNGf\xBB)'`):process.platform==="linux"&&Nt(`xclip -selection clipboard -t image/png -i "${e}"`)}function dy(e){try{process.platform==="darwin"?Nt(`open "${e}"`):process.platform==="linux"?Nt(`xdg-open "${e}"`):process.platform==="win32"&&Nt(`start "" "${e}"`)}catch{}}async function yd(e,t){let s=_(),n;if(e){if(n=iy(s,e),!n){process.stderr.write(`session not found: ${e}
1621
- `),process.exitCode=1;return}}else if(n=ay(s),!n){process.stderr.write("No recalled sessions yet. Run `recall context <id>` first, then `recall share`.\n"),process.exitCode=1;return}let r=cy(s,n);if(!r){process.stderr.write(`failed to load metadata for session ${n}
1622
- `),process.exitCode=1;return}let o=t.style&&["A","B","C","D"].includes(t.style.toUpperCase())?t.style.toUpperCase():"A";t.verdict&&(r.verdict=t.verdict);let i=await Zs(o,r),a=n.slice(0,8),l=t.out??Sd(oy(),"Downloads");ny(l)||ry(l,{recursive:!0});let c=Sd(l,`recall-card-${a}.png`);if(sy(c,i),process.stderr.write(`Card saved to ${c}
1623
- `),t.clipboard&&(ly(c),process.stderr.write(`Copied PNG to clipboard.
1624
- `)),t.link){let u=bd(r,o);process.stdout.write(u+`
1625
- `),process.platform==="darwin"&&(Nt("pbcopy",{input:u}),process.stderr.write(`Link copied to clipboard.
1626
- `))}t.open!==!1&&dy(c)}T();import{createInterface as uy}from"node:readline";import{writeFileSync as py,existsSync as my,mkdirSync as gy}from"node:fs";import{join as wd}from"node:path";import{homedir as fy}from"node:os";function Td(e){return e.recallCount>=15&&e.uniqueSessionsRecalled>=10?"Context Architect":e.nightSessionRatio>.5?"Night Owl":e.sessionCount>30&&e.avgMessageCount<50?"Rapid Shipper":e.sessionCount<15&&e.avgMessageCount>200?"Deep Diver":e.debugTagRatio>.4?"Debugger":"Power User"}var yt=["january","february","march","april","may","june","july","august","september","october","november","december"],_y=["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"];function hy(e){let t=new Date;if(!e){let i=t.getFullYear(),a=t.getMonth();return{start:`${i}-${String(a+1).padStart(2,"0")}-01`,end:a===11?`${i+1}-01-01`:`${i}-${String(a+2).padStart(2,"0")}-01`,label:`${yt[a][0].toUpperCase()}${yt[a].slice(1)} ${i}`}}let s=e.match(/^(\d{4})-(\d{2})$/);if(s){let i=parseInt(s[1],10),a=parseInt(s[2],10)-1;return a<0||a>11?null:{start:`${i}-${String(a+1).padStart(2,"0")}-01`,end:a===11?`${i+1}-01-01`:`${i}-${String(a+2).padStart(2,"0")}-01`,label:`${yt[a][0].toUpperCase()}${yt[a].slice(1)} ${i}`}}let n=yt.indexOf(e.toLowerCase()),r=n===-1?_y.indexOf(e.toLowerCase()):-1,o=n!==-1?n:r;if(o!==-1){let i=t.getFullYear();return{start:`${i}-${String(o+1).padStart(2,"0")}-01`,end:o===11?`${i+1}-01-01`:`${i}-${String(o+2).padStart(2,"0")}-01`,label:`${yt[o][0].toUpperCase()}${yt[o].slice(1)} ${i}`}}return null}function Ey(e){if(e.length===0)return"N/A";let t=r=>r===0?"12am":r<12?`${r}am`:r===12?"12pm":`${r-12}pm`,s=Math.min(...e),n=Math.max(...e);return`${t(s)}-${t(n+1>23?0:n+1)}`}async function Rd(e,t){let s=hy(e);if(!s){process.stderr.write(`invalid month format: ${e}. Use YYYY-MM, month name, or abbreviation.
1643
+ `).all(t),i=o.length,a=new Set;for(let u of o){if(!/Read|Write|Edit/.test(u.tool_names))continue;let m=u.raw_json.match(/"(?:file_path|path)":\s*"([^"]+)"/g);if(m)for(let p of m){let f=p.match(/":\s*"([^"]+)"/);f&&a.add(f[1])}}let l=s.total_input_tokens??0,c=s.total_output_tokens??0;return{sessionTitle:r,sessionDate:s.started_at??new Date().toISOString(),recallDate:new Date().toISOString(),tokenCount:l+c,inputTokens:l,outputTokens:c,messageCount:s.message_count,filesReferenced:a.size,toolCallCount:i,verdict:""}}function Yy(e){process.platform==="darwin"?It(`osascript -e 'set the clipboard to (read (POSIX file "${e}") as \xABclass PNGf\xBB)'`):process.platform==="linux"&&It(`xclip -selection clipboard -t image/png -i "${e}"`)}function Ky(e){try{process.platform==="darwin"?It(`open "${e}"`):process.platform==="linux"?It(`xdg-open "${e}"`):process.platform==="win32"&&It(`start "" "${e}"`)}catch{}}async function Gd(e,t){let s=_(),n;if(e){if(n=Jy(s,e),!n){process.stderr.write(`session not found: ${e}
1644
+ `),process.exitCode=1;return}}else if(n=Gy(s),!n){process.stderr.write("No recalled sessions yet. Run `recall context <id>` first, then `recall share`.\n"),process.exitCode=1;return}let r=zy(s,n);if(!r){process.stderr.write(`failed to load metadata for session ${n}
1645
+ `),process.exitCode=1;return}let o=t.style&&["A","B","C","D"].includes(t.style.toUpperCase())?t.style.toUpperCase():"A";t.verdict&&(r.verdict=t.verdict);let i=await cn(o,r),a=n.slice(0,8),l=t.out??Jd(Xy(),"Downloads");Hy(l)||Wy(l,{recursive:!0});let c=Jd(l,`recall-card-${a}.png`);if(By(c,i),process.stderr.write(`Card saved to ${c}
1646
+ `),t.clipboard&&(Yy(c),process.stderr.write(`Copied PNG to clipboard.
1647
+ `)),t.link){let u=Xd(r,o);process.stdout.write(u+`
1648
+ `),process.platform==="darwin"&&(It("pbcopy",{input:u}),process.stderr.write(`Link copied to clipboard.
1649
+ `))}t.open!==!1&&Ky(c)}T();import{createInterface as qy}from"node:readline";import{writeFileSync as Vy,existsSync as Zy,mkdirSync as Qy}from"node:fs";import{join as Yd}from"node:path";import{homedir as eT}from"node:os";function zd(e){return e.recallCount>=15&&e.uniqueSessionsRecalled>=10?"Context Architect":e.nightSessionRatio>.5?"Night Owl":e.sessionCount>30&&e.avgMessageCount<50?"Rapid Shipper":e.sessionCount<15&&e.avgMessageCount>200?"Deep Diver":e.debugTagRatio>.4?"Debugger":"Power User"}var wt=["january","february","march","april","may","june","july","august","september","october","november","december"],tT=["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"];function sT(e){let t=new Date;if(!e){let i=t.getFullYear(),a=t.getMonth();return{start:`${i}-${String(a+1).padStart(2,"0")}-01`,end:a===11?`${i+1}-01-01`:`${i}-${String(a+2).padStart(2,"0")}-01`,label:`${wt[a][0].toUpperCase()}${wt[a].slice(1)} ${i}`}}let s=e.match(/^(\d{4})-(\d{2})$/);if(s){let i=parseInt(s[1],10),a=parseInt(s[2],10)-1;return a<0||a>11?null:{start:`${i}-${String(a+1).padStart(2,"0")}-01`,end:a===11?`${i+1}-01-01`:`${i}-${String(a+2).padStart(2,"0")}-01`,label:`${wt[a][0].toUpperCase()}${wt[a].slice(1)} ${i}`}}let n=wt.indexOf(e.toLowerCase()),r=n===-1?tT.indexOf(e.toLowerCase()):-1,o=n!==-1?n:r;if(o!==-1){let i=t.getFullYear();return{start:`${i}-${String(o+1).padStart(2,"0")}-01`,end:o===11?`${i+1}-01-01`:`${i}-${String(o+2).padStart(2,"0")}-01`,label:`${wt[o][0].toUpperCase()}${wt[o].slice(1)} ${i}`}}return null}function nT(e){if(e.length===0)return"N/A";let t=r=>r===0?"12am":r<12?`${r}am`:r===12?"12pm":`${r-12}pm`,s=Math.min(...e),n=Math.max(...e);return`${t(s)}-${t(n+1>23?0:n+1)}`}async function Kd(e,t){let s=sT(e);if(!s){process.stderr.write(`invalid month format: ${e}. Use YYYY-MM, month name, or abbreviation.
1627
1650
  `),process.exitCode=1;return}let n=_(),r=n.prepare("SELECT COUNT(*) AS c FROM recall_events WHERE recalled_at >= ? AND recalled_at < ?").get(s.start,s.end).c,o=n.prepare("SELECT COALESCE(SUM(token_count), 0) AS s FROM recall_events WHERE recalled_at >= ? AND recalled_at < ?").get(s.start,s.end).s,i=n.prepare("SELECT COUNT(*) AS c FROM sessions WHERE indexed_at >= ? AND indexed_at < ?").get(s.start,s.end).c,a=n.prepare(`SELECT session_id, COUNT(*) AS c FROM recall_events
1628
1651
  WHERE recalled_at >= ? AND recalled_at < ?
1629
1652
  GROUP BY session_id ORDER BY c DESC LIMIT 1`).get(s.start,s.end),l="None";if(a){let B=n.prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(a.session_id),y=n.prepare("SELECT auto_title, first_user_message, id FROM sessions WHERE id = ?").get(a.session_id);l=B?.alias||y?.auto_title||y?.first_user_message?.slice(0,40)||a.session_id.slice(0,8)}let c=n.prepare("SELECT COALESCE(MAX(token_count), 0) AS m FROM recall_events WHERE recalled_at >= ? AND recalled_at < ?").get(s.start,s.end).m,u=n.prepare(`SELECT CAST(strftime('%H', started_at) AS INTEGER) AS h, COUNT(*) AS c
1630
1653
  FROM sessions WHERE started_at >= ? AND started_at < ?
1631
- GROUP BY h ORDER BY c DESC LIMIT 3`).all(s.start,s.end),p=Ey(u.map(B=>B.h)),m=n.prepare("SELECT COUNT(DISTINCT session_id) AS c FROM recall_events WHERE recalled_at >= ? AND recalled_at < ?").get(s.start,s.end).c,f=n.prepare(`SELECT COUNT(*) AS cnt, COALESCE(AVG(message_count), 0) AS avg_msgs
1654
+ GROUP BY h ORDER BY c DESC LIMIT 3`).all(s.start,s.end),m=nT(u.map(B=>B.h)),p=n.prepare("SELECT COUNT(DISTINCT session_id) AS c FROM recall_events WHERE recalled_at >= ? AND recalled_at < ?").get(s.start,s.end).c,f=n.prepare(`SELECT COUNT(*) AS cnt, COALESCE(AVG(message_count), 0) AS avg_msgs
1632
1655
  FROM sessions WHERE started_at >= ? AND started_at < ?`).get(s.start,s.end),g=n.prepare(`SELECT COUNT(*) AS c FROM sessions
1633
1656
  WHERE started_at >= ? AND started_at < ?
1634
1657
  AND (CAST(strftime('%H', started_at) AS INTEGER) >= 22
1635
1658
  OR CAST(strftime('%H', started_at) AS INTEGER) < 4)`).get(s.start,s.end).c,h=n.prepare(`SELECT COUNT(DISTINCT st.session_id) AS c
1636
1659
  FROM session_tags st JOIN sessions s ON s.id = st.session_id
1637
1660
  WHERE s.started_at >= ? AND s.started_at < ?
1638
- AND (st.tag LIKE '%debug%' OR st.tag LIKE '%fix%' OR st.tag LIKE '%bug%' OR st.tag LIKE '%error%')`).get(s.start,s.end).c,E={recallCount:r,uniqueSessionsRecalled:m,sessionCount:f.cnt,avgMessageCount:f.avg_msgs,nightSessionRatio:f.cnt>0?g/f.cnt:0,debugTagRatio:f.cnt>0?h/f.cnt:0},b=Td(E),S=50;try{let{computeAllHealthScores:B}=await Promise.resolve().then(()=>(Or(),nl)),y=B();y.length>0&&(S=Math.round(y.reduce((U,v)=>U+v.score,0)/y.length))}catch{}let C=t.verdict??"";if(!t.verdict){let B=uy({input:process.stdin,output:process.stderr});C=await new Promise(y=>{B.question("Add your take (one line, or press Enter to skip): ",U=>{B.close(),y(U.trim())})})}let x={month:s.label,totalRecalls:r,totalTokensPiped:o,sessionsIndexed:i,mostRecalledSession:l,biggestRecallTokens:c,healthScore:S,mostActiveHours:p,archetype:b,verdict:C},L=await Zs("E",x),Q=s.start.slice(0,7),I=t.out??wd(fy(),"Downloads");my(I)||gy(I,{recursive:!0});let ee=wd(I,`recall-wrapped-${Q}.png`);py(ee,L),process.stderr.write(`Wrapped card saved to ${ee}
1639
- `)}Se();Mt();import{createRequire as by}from"node:module";import{createInterface as Sy}from"node:readline";import{stdin as yy,stdout as Ty}from"node:process";var wy=by(import.meta.url),Ry=wy(`${ye()}/package.json`).version,Cd="https://clauderecall.com/api/feedback",Xr=process.env.RECALL_FEEDBACK_API??Cd,xd=Xr===Cd,Jr=2e3;function Nd(e){let t=Sy({input:yy,output:Ty});return new Promise(s=>t.question(e,n=>{t.close(),s(n.trim())}))}function kd(e){if(!/^[+-]?\d+$/.test(e))return null;let t=Number.parseInt(e,10);return!Number.isFinite(t)||t<1||t>5?null:t}async function xy(e){if(e.score!==void 0){let n=kd(e.score);return n===null?(console.error(`--score must be an integer from 1 to 5 (got "${e.score}").`),null):n}if(!process.stdin.isTTY)return console.error("feedback needs a TTY to prompt. Pass --score 1..5 (and optionally --message) to send non-interactively."),null;console.log("How is Claude Recall going for you?"),console.log(" 1 = bad 2 = meh 3 = ok 4 = good 5 = great"),console.log("");let t=await Nd("Score (1-5, q to quit): ");if(t.toLowerCase()==="q"||t==="")return console.log("No worries, skipped."),null;let s=kd(t);return s===null?(console.error("Please enter an integer 1 through 5."),null):s}async function ky(e,t){if(e.message!==void 0)return e.message.trim();if(!process.stdin.isTTY)return"";let s=t<=2?"What is the biggest pain point? (Enter to skip): ":"Anything you would add? (Enter to skip): ";return await Nd(s)}function Cy(e){return e.length<=Jr?{value:e,truncated:!1}:{value:e.slice(0,Jr),truncated:!0}}async function Ld(e={}){xd||process.stderr.write(`[recall] RECALL_FEEDBACK_API override active (${Xr}); license token will NOT be sent.
1640
- `);let t=await xy(e);if(t===null)return e.score!==void 0||!process.stdin.isTTY?1:0;let s=await ky(e,t),{value:n,truncated:r}=Cy(s);r&&process.stderr.write(`[recall] --message truncated to ${Jr} characters before send.
1641
- `);let o=await be(),i=vt(),a=xd&&o.tier==="pro"&&i?i.license_jwt:null,l={score:t,comment:n.length>0?n:null,surface:"cli",version:Ry,os:process.platform,trigger_kind:"manual",license_jwt:a};try{let c=await fetch(Xr,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(l)});if(c.ok)return console.log(""),console.log("Thanks. Your feedback landed."),0;let u=await c.json().catch(()=>({}));return c.status===429?(console.log("You submitted feedback recently. Try again later."),0):(console.error(`Feedback failed: ${c.status} ${u.error??"unknown"}`),1)}catch(c){let u=c instanceof Error?c.message:"network error";return console.error(`Feedback could not be sent: ${u}`),1}}var ST=ET(import.meta.url),yT=ST("../package.json").version,k=new bT;k.name("recall").description("Searchable memory for every Claude Code session you have ever run. Local, fast, offline. Run `recall` (no args) for the dashboard, or `recall --help` for the full command list.").version(yT);k.command("index").description("Scan your Claude sessions and build the searchable database. Run this once after install.").option("-f, --force","reindex all files even if unchanged").option("-v, --verbose","show each file as it is processed").action(async e=>{await Ao(e)});k.command("list").description("List your sessions, newest first.").option("-p, --project <name>","filter by project name").option("-n, --limit <n>","max rows to show","30").option("-a, --all","include short sessions (2 messages or fewer)").action(e=>{Io(e)});k.command("show <id>").description("Print a full session transcript. Accepts the full id or an 8-char prefix.").option("-r, --raw","print raw JSONL lines instead of formatted output").option("-n, --limit <n>","max messages to show").option("--no-pager","do not auto-pipe long output through less").action((e,t)=>{Po(e,t)});k.command("search <query...>").description("Search every message in every session.").option("-p, --project <name>","restrict results to one project").option("-n, --limit <n>","max results","20").action(async(e,t)=>{await Vo(e.join(" "),t)});k.command("projects").description("List every project with how many sessions are in each.").action(()=>{ti()});k.command("status").description("Show database size, session counts, and whether the daemon is running.").action(()=>{ei()});k.command("start").description("Start the background daemon. Required for live tab-name tracking and the web UI.").action(async()=>{await ps()});k.command("stop").description("Stop the background daemon.").action(async()=>{await ni()});k.command("open").description("Open the local web UI in your browser. Starts the daemon if it is not already running.").action(async()=>{await ri()});k.command("tui").description("Browse and search sessions in an interactive terminal UI. No browser needed.").action(async()=>{let{runTui:e}=await Promise.resolve().then(()=>(cu(),au));await e()});k.command("context <id>").description("Pipe a past session into a fresh Claude chat. Prints condensed markdown to stdout.").option("-f, --full","include full tool call and result bodies (much longer)").option("--since <when>","only messages at or after this time (2h, 30m, 1d, YYYY-MM-DD, or ISO)").option("--subagents","also include subagent / sidechain messages").option("--prelude <text>",'prepend a custom header (e.g. "Continue this conversation")').action(async(e,t)=>{await Ci(e,t)});k.command("mcp").description("Expose Recall as an MCP server over stdio. Add this to your Claude Desktop / Claude Code MCP config to let Claude search your sessions.").option("--allow-writes","enable write tools (add_tag, set_alias, append_note, \u2026). Off by default; rate-limited and audited when on.").action(async e=>{await Ni({allowWrites:!!e.allowWrites})});k.command("paste").description("Save clipboard content (or stdin) into Recall. Opt-in. Secrets are blocked by default; pass --force to override.").option("-l, --list","list archived pastes").option("--purge <id>","permanently delete one paste by id or 8-char prefix").option("-f, --force","skip the secret-scan confirmation prompt").option("--pipe","echo the content to stdout after archiving (for shell pipelines)").option("--dry-run","preview what would be archived without writing").option("--label <text>","short description shown in `recall paste --list`").action(async e=>{await Li(e)});k.command("audit-secrets").description("Scan the database for secrets that slipped through. Read-only by default; pass --redact to scrub in place.").option("--redact","rewrite offending rows in place (your source files are never touched)").option("-v, --verbose","print every session and message containing a hit").action(async e=>{await Oi(e)});k.command("titles [action]").description('Audit session titles in the current project. Defaults to "audit".').option("-p, --project <name>","project to audit (defaults to current cwd)").option("--json","machine-readable JSON output").option("--dry-run","classify but do not write the title_quality column").action(async(e,t)=>{if((e??"audit").toLowerCase()==="audit"){await Ii(t);return}console.error(`Unknown titles action: ${e}. Supported: audit`),process.exitCode=1});k.command("import-vscode-state").description("Backfill missing tab names by reading VS Code, Cursor, and Windsurf workspace state. Dry-run by default; pass --apply to write.").option("-p, --project <name>","scope to a single project").option("--apply","write the proposed names (default: dry-run)").option("--min-score <n>","minimum match score from 0 to 1 (default 0.7)","0.7").option("--limit <n>","cap the number of proposals returned").option("--source <list>","which editors to scan: vscode | cursor | windsurf | all (default all)","all").option("--json","machine-readable JSON output").action(async e=>{await Fi(e)});k.command("semantic [action] [subAction]").description('Manage semantic search. Defaults to "status". Actions: on, off, status, backfill, pause, resume, install, uninstall, reindex, auto-extract <on|off>.').option("-n, --limit <n>","max sessions to process during backfill","1000").option("-f, --force","regenerate summaries even when one already exists").option("--rate <perMin>","sessions per minute when enabling").option("--model <name>","claude model id (e.g. claude-haiku-4-5-20251001)").action(async(e,t,s)=>{await pa(e,{...s,_autoExtractAction:t})});k.command("embeddings [action]").description('Audit embedding coverage and backfill missing ones. Defaults to "audit". Actions: audit, backfill-summaries, backfill-messages.').option("-p, --project <name>","scope to a single project").option("-n, --limit <n>","max sessions to process during backfill").option("--json","emit JSON instead of formatted output").action(async(e,t)=>{await ha(e,t)});var Qt=k.command("infer").description("Discover links between sessions. Subcommands: outputs | citations | l1 | links | bug-patterns.");function uu(e){return e.description("Extract code, file, and error references from sessions in one project. Uses the local claude CLI.").requiredOption("-p, --project <name>","project name (required)").option("-n, --limit <n>","max sessions to process","200").option("-f, --force","re-extract even if already done").option("--model <name>","override the default Haiku model id").option("-y, --yes","skip the >50-session cost confirmation (for scripts)").option("--json","emit JSON summary instead of formatted output").action(async t=>{await Ra(t)})}function pu(e){return e.description("Find sessions that cite the same files or errors. Lands proposals for review.").requiredOption("-p, --project <name>","project name (required)").option("--json","emit JSON summary instead of formatted output").action(async t=>{await Ma(t)})}function mu(e){return e.description("Fast deterministic link inference across sessions. No LLM cost.").option("-p, --project <name>","restrict to one project (default: all)").option("--json","emit JSON summary instead of formatted output").action(async t=>{await ja(t)})}function gu(e){return e.description("LLM-powered link classification. Pre-filters by confidence, batches the survivors through your local claude CLI (Haiku).").requiredOption("-p, --project <name>","project name (required)").option("--min-conf <n>","pre-filter threshold (default 0.4)","0.4").option("-n, --limit <n>","max candidate pairs to classify (default 1000)","1000").option("--auto-promote","promote high-confidence pairs straight into session_links").option("--auto-promote-threshold <n>","promotion threshold (default 0.95)").option("--model <name>","override the default Haiku model id").option("--json","emit JSON summary instead of formatted output").action(async t=>{await Xa(t)})}function fu(e){return e.description("Cluster sessions that hit the same bug. Idempotent.").option("-p, --project <name>","restrict to one project (default: all)").option("--min-cluster-size <n>","skip clusters smaller than this (default 3)","3").option("--semantic","add an embedding-distance pass to catch near-duplicate snippets").option("-n, --limit <n>","cap clusters in the output (default 100)","100").option("--json","emit JSON summary instead of formatted output").action(async t=>{await tc(t)})}uu(Qt.command("outputs"));pu(Qt.command("citations"));mu(Qt.command("l1"));gu(Qt.command("links"));fu(Qt.command("bug-patterns"));uu(k.command("extract-outputs"));pu(k.command("infer-citations"));mu(k.command("infer-l1"));gu(k.command("infer-links"));fu(k.command("infer-bug-patterns"));k.command("neighborhood <id>").description("Bundle a session with its parents, children, citations, and similar sessions. Pipe into `claude` to seed a fresh chat with rich context.").option("-b, --budget <n>","token budget for the bundle (default 4000)","4000").option("--scoring <mode>","pagerank | embedding-rerank | hybrid (default hybrid)","hybrid").option("-e, --edge-types <list>","comma-separated link types to include: citation,similar,skill_track,bug_pattern,wiki_link,temporal_proximity (default all)").option("--max-depth <n>","how far to walk the link graph (default 2)","2").option("--no-wiki-links","exclude manual wiki links").option("--include-suggestions","include pending suggestions (debug only)").option("--json","emit the full result as JSON instead of markdown").action(async(e,t)=>{await mc(e,t)});k.command("similar <session-id>").description("Find sessions about the same topic as this one. Pro feature.").option("-n, --limit <n>","max results","10").action(async(e,t)=>{let{requireProOrExit:s}=await Promise.resolve().then(()=>(Se(),Ln));await s("Similar sessions");let{isModelInstalled:n}=await Promise.resolve().then(()=>(Ts(),ia)),{loadEmbedder:r,getEmbedderStatus:o}=await Promise.resolve().then(()=>(qe(),Yn)),{findSimilarSessions:i}=await Promise.resolve().then(()=>(du(),lu));if(!n()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}o().loaded||await r();let a=Math.max(1,Math.min(50,Number(t.limit??10))),l=await i(e,a);if(l.length===0){console.log("No similar sessions found.");return}for(let c of l)console.log(` ${c.sessionId} similarity=${c.similarity.toFixed(3)}`)});k.command("stats [id]").description("How much you have spent and how many tokens you have used. No args = overview. Pass a session id for one session, or --project for one project.").option("-p, --project <name>","show stats for a single project").option("-d, --days <n>","restrict the overview to the last N days (7 or 30)").option("--backfill","compute usage for already-indexed messages (safe to rerun)").option("-n, --limit <n>","max messages to scan during backfill").option("--json","emit JSON instead of a formatted table").action(async(e,t)=>{await Sc(e,t)});k.command("correlate [id]").description("Link sessions to the git commits they wrote. Read-only. No args = batch mode; pass an id to correlate one.").option("-n, --limit <n>","max sessions to process in batch mode").option("--json","emit JSON instead of formatted output").action(async(e,t)=>{await Rc(e,t)});var so=k.command("correlator").description("Diagnose and fix terminal-to-session matching. Subcommands: audit | debug | restore.");function _u(e){return e.description("Show how the daemon is matching open terminals to sessions right now.").option("--json","emit JSON instead of formatted output").action(async t=>{await Gc(t)})}function hu(e){return e.description("Restore aliases that `correlator audit --fix` cleared, when they still cleanly match an open terminal. Dry-run by default.").option("--apply","apply the restoration (otherwise dry-run only)").option("--json","emit JSON instead of formatted output").action(async t=>{await zc(t)})}function Eu(e){return e.description("Find sessions with bad terminal-name aliases from the legacy race-window bug. Use --fix to clear suspects.").option("--fix","clear suspect aliases (otherwise dry-run only)").option("-w, --window <seconds>","collision window in seconds (default 60, clamped 5..600)").option("-p, --project <name>","limit detection and --fix to a single project").option("--json","emit JSON instead of formatted output").action(async t=>{await Ac(t)})}_u(so.command("debug"));hu(so.command("restore"));Eu(so.command("audit"));_u(k.command("correlator-debug"));hu(k.command("correlator-restore"));k.command("name <id-prefix> <name>").description("Rename a session. By default it stays linked to its terminal tab, so renaming the tab later still updates the name. Use --pin to lock the name permanently. Daemon must be running.").option("--json","emit JSON").option("--pin","lock the name; later tab renames will NOT overwrite it").action(async(e,t,s)=>{await Hc(e,t,s)});k.command("doctor").description("Diagnose database health: size, WAL, FTS fragmentation, integrity, alias invariant. Exits non-zero on issues.").option("--json","emit JSON instead of formatted output").action(async e=>{let t=await Uc(e);process.exit(t)});k.command("optimize").description("Run maintenance: WAL checkpoint, FTS5 merge, planner stats. Use --vacuum to also reclaim free pages (requires daemon stopped).").option("--vacuum","also run VACUUM to reclaim free pages (rewrites the whole DB; daemon must be stopped)").option("--json","emit JSON instead of formatted output").action(async e=>{let t=await Bc(e);process.exit(t)});Eu(k.command("correlator-audit"));k.command("blame <sha>").description("Look up which session(s) wrote the code in a commit. Reverse of `correlate`.").option("--json","emit JSON instead of formatted output").action(async(e,t)=>{await Yc(e,t)});k.command("digest").description("Today's rediscovery picks: a session worth revisiting, the costliest of the week, and the one behind your latest commit.").option("--json","emit JSON instead of formatted output").action(async e=>{await Vc(e)});k.command("install-extension").description("Install the bundled VS Code / Cursor / Windsurf extension into your editor. Auto-detects which CLIs are installed.").option("--editor <name>","install only into one editor: code | cursor | code-insiders | windsurf").option("--print-path","print the path to the bundled .vsix and exit").action(async e=>{await sl(e)});k.command("health [project]").description("Score how well-organized each project's sessions are. Worst first, or pass a project name for a single breakdown.").option("--json","emit JSON instead of formatted output").action((e,t)=>{ol(e,t)});k.command("verify [action]").description('Toggle verification badges in the UI. Defaults to "status". Actions: on, off, status.').action(e=>{il(e)});k.command("activate <license-key>").description("Activate your Pro license. Run once after purchase.").action(async e=>{await _l(e)});k.command("upgrade").description("Open the Pro pricing page in your browser.").action(async()=>{await El()});var no=k.command("license").description('Show or remove the Pro license on this machine. Defaults to "status".');no.command("status",{isDefault:!0}).description("Show the current license tier.").action(async()=>{await bl()});no.command("deactivate").description("Remove the stored license from this machine. Reverses `recall activate`.").action(()=>{yl()});no.command("check").description("Force a revocation check against the license server. The daemon also runs this on a 24-hour timer in the background.").action(async()=>{await Sl()});var TT=k.command("thread").description("Group related sessions into threads, then list, show, link, merge, or scan them."),wT=k.command("threads").description("Alias for `thread`. Both forms accept the same subcommands.");function bu(e){e.command("sync").description("Capture sessions running in this repo right now into a thread.").option("--preflight","preview the plan without writing").option("-p, --project <name>","override the cwd-based project").option("--window-hours <n>","rolling activity window (default 6)").option("--json","machine-readable JSON output").action(async t=>{await td(t)}),e.command("scan").description("Auto-detect parent-child links across past sessions. Dry-run by default; pass --apply to write.").option("-p, --project <name>","scope to a single project").option("--json","emit JSON instead of formatted output").option("--apply","write edges (default: dry-run preview)").option("--confidence-min <n>","override threshold (dry-run 0.5, apply 0.7)").option("--no-llm-names","skip LLM naming (free, offline)").option("--llm-rescore","LLM re-score borderline pairs (small Haiku call each)").option("--rescore-band-lo <n>","low end of the borderline band (default 0.4)").option("--rescore-band-hi <n>","high end of the borderline band (default 0.7)").option("--rescore-model <id>","model id for the rescore call (default Haiku 4.5)").action(t=>{Ql(t)}),e.command("list").description("List threads, newest first.").option("--archived","include archived threads").option("--json","emit JSON instead of a table").action(t=>{wl(t)}),e.command("show <id-prefix>").description("Show a thread's header and session tree.").option("--json","emit JSON instead of formatted output").action((t,s)=>{Rl(t,s)}),e.command("new <name>").description("Create a new thread.").option("--origin <session-id>","seed with an origin session").option("--summary <text>","optional short summary").option("--json","emit JSON").action((t,s)=>{xl(t,s)}),e.command("link <session-id>").description("Link a session into a thread.").requiredOption("--thread <id-prefix>","thread id or prefix").option("--parent <session-id>","parent session within the thread").option("--role <role>","origin | child (default inferred from --parent)").option("--json","emit JSON").action((t,s)=>{kl(t,s)}),e.command("unlink <session-id>").description("Remove a session from a thread.").requiredOption("--thread <id-prefix>","thread id or prefix").option("--json","emit JSON").action((t,s)=>{Cl(t,s)}),e.command("set-parent <session-id>").description("Change a session's parent within a thread. Use --parent none to promote to origin.").requiredOption("--thread <id-prefix>","thread id or prefix").option("--parent <session-id|none>",'new parent, or "none" to promote to origin').option("--json","emit JSON").action((t,s)=>{Nl(t,s)}),e.command("rename <id-prefix> <new-name>").description("Rename a thread.").option("--json","emit JSON").action((t,s,n)=>{Ll(t,s,n)}),e.command("close <id-prefix>").description("Mark a thread as closed (work complete).").option("--json","emit JSON").action((t,s)=>{Ol(t,s)}),e.command("reopen <id-prefix>").description("Reopen a closed thread.").option("--json","emit JSON").action((t,s)=>{Al(t,s)}),e.command("archive <id-prefix>").description("Archive a thread (hidden from the default list).").option("--json","emit JSON").action((t,s)=>{Il(t,s)}),e.command("merge <source-id-prefix>").description("Merge one thread into another.").requiredOption("--into <id-prefix>","destination thread").option("--json","emit JSON").action((t,s)=>{vl(t,s)}),e.command("split <id-prefix>").description("Split sessions out of a thread into a new thread.").requiredOption("--sessions <s1,s2,...>","comma-separated session ids or prefixes").requiredOption("--name <new-name>","name for the new thread").option("--json","emit JSON").action((t,s)=>{Ml(t,s)})}bu(TT);bu(wT);k.command("share [id]").description("Save a session as a shareable PNG card. No args = your last recalled session. Saved to ~/Downloads and opened.").option("--style <A|B|C|D>","card style (default A: Minimal)").option("--verdict <quote>","your one-line take on the session").option("--link","also generate a shareable URL and copy it to the clipboard").option("--clipboard","also copy the PNG to the system clipboard").option("--out <path>","override the save directory").option("--no-open","do not auto-open the saved PNG").action(async(e,t)=>{await yd(e,t)});k.command("feedback").description("Send a 1-5 rating and optional comment to the team. Interactive by default; pass --score (and optionally --message) to skip prompts.").option("--score <1-5>","rating from 1 (bad) to 5 (great)").option("--message <text>","optional comment to send with the rating").action(async e=>{let t=await Ld(e);t!==0&&(process.exitCode=t)});k.command("wrapped [month]").description("Save your monthly recap as a shareable PNG card. Defaults to the current month. Accepts YYYY-MM, full name, or abbreviation.").option("--verdict <quote>","your one-line take on the month").option("--out <path>","override the save directory").action(async(e,t)=>{await Rd(e,t)});process.env.CLAUDECODE&&process.stderr.write(`<claude-code-hint v="1" type="plugin" value="claude-recall@claude-plugins-official" />
1642
- `);k.action(async()=>{await gl()});k.parseAsync(process.argv).catch(e=>{console.error(e),process.exit(1)});
1661
+ AND (st.tag LIKE '%debug%' OR st.tag LIKE '%fix%' OR st.tag LIKE '%bug%' OR st.tag LIKE '%error%')`).get(s.start,s.end).c,E={recallCount:r,uniqueSessionsRecalled:p,sessionCount:f.cnt,avgMessageCount:f.avg_msgs,nightSessionRatio:f.cnt>0?g/f.cnt:0,debugTagRatio:f.cnt>0?h/f.cnt:0},b=zd(E),S=50;try{let{computeAllHealthScores:B}=await Promise.resolve().then(()=>(Pr(),_l)),y=B();y.length>0&&(S=Math.round(y.reduce((U,M)=>U+M.score,0)/y.length))}catch{}let N=t.verdict??"";if(!t.verdict){let B=qy({input:process.stdin,output:process.stderr});N=await new Promise(y=>{B.question("Add your take (one line, or press Enter to skip): ",U=>{B.close(),y(U.trim())})})}let x={month:s.label,totalRecalls:r,totalTokensPiped:o,sessionsIndexed:i,mostRecalledSession:l,biggestRecallTokens:c,healthScore:S,mostActiveHours:m,archetype:b,verdict:N},L=await cn("E",x),Q=s.start.slice(0,7),v=t.out??Yd(eT(),"Downloads");Zy(v)||Qy(v,{recursive:!0});let ee=Yd(v,`recall-wrapped-${Q}.png`);Vy(ee,L),process.stderr.write(`Wrapped card saved to ${ee}
1662
+ `)}fe();Pt();import{createRequire as rT}from"node:module";import{createInterface as oT}from"node:readline";import{stdin as iT,stdout as aT}from"node:process";var cT=rT(import.meta.url),lT=cT(`${Te()}/package.json`).version,Zd="https://clauderecall.com/api/feedback",so=process.env.RECALL_FEEDBACK_API??Zd,qd=so===Zd,no=2e3;function Qd(e){let t=oT({input:iT,output:aT});return new Promise(s=>t.question(e,n=>{t.close(),s(n.trim())}))}function Vd(e){if(!/^[+-]?\d+$/.test(e))return null;let t=Number.parseInt(e,10);return!Number.isFinite(t)||t<1||t>5?null:t}async function dT(e){if(e.score!==void 0){let n=Vd(e.score);return n===null?(console.error(`--score must be an integer from 1 to 5 (got "${e.score}").`),null):n}if(!process.stdin.isTTY)return console.error("feedback needs a TTY to prompt. Pass --score 1..5 (and optionally --message) to send non-interactively."),null;console.log("How is Claude Recall going for you?"),console.log(" 1 = bad 2 = meh 3 = ok 4 = good 5 = great"),console.log("");let t=await Qd("Score (1-5, q to quit): ");if(t.toLowerCase()==="q"||t==="")return console.log("No worries, skipped."),null;let s=Vd(t);return s===null?(console.error("Please enter an integer 1 through 5."),null):s}async function uT(e,t){if(e.message!==void 0)return e.message.trim();if(!process.stdin.isTTY)return"";let s=t<=2?"What is the biggest pain point? (Enter to skip): ":"Anything you would add? (Enter to skip): ";return await Qd(s)}function mT(e){return e.length<=no?{value:e,truncated:!1}:{value:e.slice(0,no),truncated:!0}}async function eu(e={}){qd||process.stderr.write(`[recall] RECALL_FEEDBACK_API override active (${so}); license token will NOT be sent.
1663
+ `);let t=await dT(e);if(t===null)return e.score!==void 0||!process.stdin.isTTY?1:0;let s=await uT(e,t),{value:n,truncated:r}=mT(s);r&&process.stderr.write(`[recall] --message truncated to ${no} characters before send.
1664
+ `);let o=await ye(),i=jt(),a=qd&&o.tier==="pro"&&i?i.license_jwt:null,l={score:t,comment:n.length>0?n:null,surface:"cli",version:lT,os:process.platform,trigger_kind:"manual",license_jwt:a};try{let c=await fetch(so,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(l)});if(c.ok)return console.log(""),console.log("Thanks. Your feedback landed."),0;let u=await c.json().catch(()=>({}));return c.status===429?(console.log("You submitted feedback recently. Try again later."),0):(console.error(`Feedback failed: ${c.status} ${u.error??"unknown"}`),1)}catch(c){let u=c instanceof Error?c.message:"network error";return console.error(`Feedback could not be sent: ${u}`),1}}var ow=nw(import.meta.url),fo=ow("../package.json").version,k=new rw;k.name("recall").description("Searchable memory for every Claude Code session you have ever run. Local, fast, offline. Run `recall` (no args) for the dashboard, or `recall --help` for the full command list.").version(fo);k.command("index").description("Scan your Claude sessions and build the searchable database. Run this once after install.").option("-f, --force","reindex all files even if unchanged").option("-v, --verbose","show each file as it is processed").action(async e=>{await Xo(e)});k.command("list").description("List your sessions, newest first.").option("-p, --project <name>","filter by project name").option("-n, --limit <n>","max rows to show","30").option("-a, --all","include short sessions (2 messages or fewer)").action(e=>{Jo(e)});k.command("show <id>").description("Print a full session transcript. Accepts the full id or an 8-char prefix.").option("-r, --raw","print raw JSONL lines instead of formatted output").option("-n, --limit <n>","max messages to show").option("--no-pager","do not auto-pipe long output through less").action((e,t)=>{Vo(e,t)});k.command("search <query...>").description("Search every message in every session.").option("-p, --project <name>","restrict results to one project").option("-n, --limit <n>","max results","20").action(async(e,t)=>{await di(e.join(" "),t)});k.command("projects").description("List every project with how many sessions are in each.").action(()=>{gi()});k.command("status").description("Show database size, session counts, and whether the daemon is running.").action(()=>{pi()});k.command("start").description("Start the background daemon. Required for live tab-name tracking and the web UI.").action(async()=>{await hs()});k.command("stop").description("Stop the background daemon.").action(async()=>{await _i()});k.command("open").description("Open the local web UI in your browser. Starts the daemon if it is not already running.").action(async()=>{await hi()});k.command("tui").description("Browse and search sessions in an interactive terminal UI. No browser needed.").action(async()=>{let{runTui:e}=await Promise.resolve().then(()=>(vu(),Iu));await e()});k.command("context <id>").description("Pipe a past session into a fresh Claude chat. Prints condensed markdown to stdout.").option("-f, --full","include full tool call and result bodies (much longer)").option("--since <when>","only messages at or after this time (2h, 30m, 1d, YYYY-MM-DD, or ISO)").option("--subagents","also include subagent / sidechain messages").option("--prelude <text>",'prepend a custom header (e.g. "Continue this conversation")').action(async(e,t)=>{await Ui(e,t)});k.command("mcp").description("Expose Recall as an MCP server over stdio. Add this to your Claude Desktop / Claude Code MCP config to let Claude search your sessions.").option("--allow-writes","enable write tools (add_tag, set_alias, append_note, \u2026). Off by default; rate-limited and audited when on.").action(async e=>{await Bi({allowWrites:!!e.allowWrites})});k.command("paste").description("Save clipboard content (or stdin) into Recall. Opt-in. Secrets are blocked by default; pass --force to override.").option("-l, --list","list archived pastes").option("--purge <id>","permanently delete one paste by id or 8-char prefix").option("-f, --force","skip the secret-scan confirmation prompt").option("--pipe","echo the content to stdout after archiving (for shell pipelines)").option("--dry-run","preview what would be archived without writing").option("--label <text>","short description shown in `recall paste --list`").action(async e=>{await Hi(e)});k.command("audit-secrets").description("Scan the database for secrets that slipped through. Read-only by default; pass --redact to scrub in place.").option("--redact","rewrite offending rows in place (your source files are never touched)").option("-v, --verbose","print every session and message containing a hit").action(async e=>{await Wi(e)});k.command("titles [action]").description('Audit session titles in the current project. Defaults to "audit".').option("-p, --project <name>","project to audit (defaults to current cwd)").option("--json","machine-readable JSON output").option("--dry-run","classify but do not write the title_quality column").action(async(e,t)=>{if((e??"audit").toLowerCase()==="audit"){await Ji(t);return}console.error(`Unknown titles action: ${e}. Supported: audit`),process.exitCode=1});k.command("import-vscode-state").description("Backfill missing tab names by reading VS Code, Cursor, and Windsurf workspace state. Dry-run by default; pass --apply to write.").option("-p, --project <name>","scope to a single project").option("--apply","write the proposed names (default: dry-run)").option("--min-score <n>","minimum match score from 0 to 1 (default 0.7)","0.7").option("--limit <n>","cap the number of proposals returned").option("--source <list>","which editors to scan: vscode | cursor | windsurf | all (default all)","all").option("--json","machine-readable JSON output").action(async e=>{await Zi(e)});k.command("semantic [action] [subAction]").description('Manage semantic search. Defaults to "status". Actions: on, off, status, backfill, pause, resume, install, uninstall, reindex, auto-extract <on|off>.').option("-n, --limit <n>","max sessions to process during backfill","1000").option("-f, --force","regenerate summaries even when one already exists").option("--rate <perMin>","sessions per minute when enabling").option("--model <name>","claude model id (e.g. claude-haiku-4-5-20251001)").action(async(e,t,s)=>{await xa(e,{...s,_autoExtractAction:t})});k.command("embeddings [action]").description('Audit embedding coverage and backfill missing ones. Defaults to "audit". Actions: audit, backfill-summaries, backfill-messages.').option("-p, --project <name>","scope to a single project").option("-n, --limit <n>","max sessions to process during backfill").option("--json","emit JSON instead of formatted output").action(async(e,t)=>{await Oa(e,t)});var ns=k.command("infer").description("Discover links between sessions. Subcommands: outputs | citations | l1 | links | bug-patterns.");function $u(e){return e.description("Extract code, file, and error references from sessions in one project. Uses the local claude CLI.").requiredOption("-p, --project <name>","project name (required)").option("-n, --limit <n>","max sessions to process","200").option("-f, --force","re-extract even if already done").option("--model <name>","override the default Haiku model id").option("-y, --yes","skip the >50-session cost confirmation (for scripts)").option("--json","emit JSON summary instead of formatted output").action(async t=>{await ja(t)})}function ju(e){return e.description("Find sessions that cite the same files or errors. Lands proposals for review.").requiredOption("-p, --project <name>","project name (required)").option("--json","emit JSON summary instead of formatted output").action(async t=>{await za(t)})}function Pu(e){return e.description("Fast deterministic link inference across sessions. No LLM cost.").option("-p, --project <name>","restrict to one project (default: all)").option("--json","emit JSON summary instead of formatted output").action(async t=>{await qa(t)})}function Fu(e){return e.description("LLM-powered link classification. Pre-filters by confidence, batches the survivors through your local claude CLI (Haiku).").requiredOption("-p, --project <name>","project name (required)").option("--min-conf <n>","pre-filter threshold (default 0.4)","0.4").option("-n, --limit <n>","max candidate pairs to classify (default 1000)","1000").option("--auto-promote","promote high-confidence pairs straight into session_links").option("--auto-promote-threshold <n>","promotion threshold (default 0.95)").option("--model <name>","override the default Haiku model id").option("--json","emit JSON summary instead of formatted output").action(async t=>{await nc(t)})}function Uu(e){return e.description("Cluster sessions that hit the same bug. Idempotent.").option("-p, --project <name>","restrict to one project (default: all)").option("--min-cluster-size <n>","skip clusters smaller than this (default 3)","3").option("--semantic","add an embedding-distance pass to catch near-duplicate snippets").option("-n, --limit <n>","cap clusters in the output (default 100)","100").option("--json","emit JSON summary instead of formatted output").action(async t=>{await gc(t)})}$u(ns.command("outputs"));ju(ns.command("citations"));Pu(ns.command("l1"));Fu(ns.command("links"));Uu(ns.command("bug-patterns"));$u(k.command("extract-outputs"));ju(k.command("infer-citations"));Pu(k.command("infer-l1"));Fu(k.command("infer-links"));Uu(k.command("infer-bug-patterns"));k.command("neighborhood <id>").description("Bundle a session with its parents, children, citations, and similar sessions. Pipe into `claude` to seed a fresh chat with rich context.").option("-b, --budget <n>","token budget for the bundle (default 4000)","4000").option("--scoring <mode>","pagerank | embedding-rerank | hybrid (default hybrid)","hybrid").option("-e, --edge-types <list>","comma-separated link types to include: citation,similar,skill_track,bug_pattern,wiki_link,temporal_proximity (default all)").option("--max-depth <n>","how far to walk the link graph (default 2)","2").option("--no-wiki-links","exclude manual wiki links").option("--include-suggestions","include pending suggestions (debug only)").option("--json","emit the full result as JSON instead of markdown").action(async(e,t)=>{await kc(e,t)});k.command("similar <session-id>").description("Find sessions about the same topic as this one. Pro feature.").option("-n, --limit <n>","max results","10").action(async(e,t)=>{let{requireProOrExit:s}=await Promise.resolve().then(()=>(fe(),ps));await s("Similar sessions");let{isModelInstalled:n}=await Promise.resolve().then(()=>(Ns(),ba)),{loadEmbedder:r,getEmbedderStatus:o}=await Promise.resolve().then(()=>(Ve(),sr)),{findSimilarSessions:i}=await Promise.resolve().then(()=>(Du(),Mu));if(!n()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}o().loaded||await r();let a=Math.max(1,Math.min(50,Number(t.limit??10))),l=await i(e,a);if(l.length===0){console.log("No similar sessions found.");return}for(let c of l)console.log(` ${c.sessionId} similarity=${c.similarity.toFixed(3)}`)});k.command("stats [id]").description("How much you have spent and how many tokens you have used. No args = overview. Pass a session id for one session, or --project for one project.").option("-p, --project <name>","show stats for a single project").option("-d, --days <n>","restrict the overview to the last N days (7 or 30)").option("--backfill","compute usage for already-indexed messages (safe to rerun)").option("-n, --limit <n>","max messages to scan during backfill").option("--json","emit JSON instead of a formatted table").action(async(e,t)=>{await vc(e,t)});k.command("correlate [id]").description("Link sessions to the git commits they wrote. Read-only. No args = batch mode; pass an id to correlate one.").option("-n, --limit <n>","max sessions to process in batch mode").option("--json","emit JSON instead of formatted output").action(async(e,t)=>{await jc(e,t)});var _o=k.command("correlator").description("Diagnose and fix terminal-to-session matching. Subcommands: audit | debug | restore.");function Bu(e){return e.description("Show how the daemon is matching open terminals to sessions right now.").option("--json","emit JSON instead of formatted output").action(async t=>{await ol(t)})}function Hu(e){return e.description("Restore aliases that `correlator audit --fix` cleared, when they still cleanly match an open terminal. Dry-run by default.").option("--apply","apply the restoration (otherwise dry-run only)").option("--json","emit JSON instead of formatted output").action(async t=>{await il(t)})}function Wu(e){return e.description("Find sessions with bad terminal-name aliases from the legacy race-window bug. Use --fix to clear suspects.").option("--fix","clear suspect aliases (otherwise dry-run only)").option("-w, --window <seconds>","collision window in seconds (default 60, clamped 5..600)").option("-p, --project <name>","limit detection and --fix to a single project").option("--json","emit JSON instead of formatted output").action(async t=>{await Xc(t)})}Bu(_o.command("debug"));Hu(_o.command("restore"));Wu(_o.command("audit"));Bu(k.command("correlator-debug"));Hu(k.command("correlator-restore"));k.command("name <id-prefix> <name>").description("Rename a session. By default it stays linked to its terminal tab, so renaming the tab later still updates the name. Use --pin to lock the name permanently. Daemon must be running.").option("--json","emit JSON").option("--pin","lock the name; later tab renames will NOT overwrite it").action(async(e,t,s)=>{await tl(e,t,s)});k.command("doctor").description("Diagnose database health: size, WAL, FTS fragmentation, integrity, alias invariant. Exits non-zero on issues.").option("--json","emit JSON instead of formatted output").action(async e=>{let t=await Qc(e);process.exit(t)});k.command("optimize").description("Run maintenance: WAL checkpoint, FTS5 merge, planner stats. Use --vacuum to also reclaim free pages (requires daemon stopped).").option("--vacuum","also run VACUUM to reclaim free pages (rewrites the whole DB; daemon must be stopped)").option("--json","emit JSON instead of formatted output").action(async e=>{let t=await el(e);process.exit(t)});Wu(k.command("correlator-audit"));k.command("blame <sha>").description("Look up which session(s) wrote the code in a commit. Reverse of `correlate`.").option("--json","emit JSON instead of formatted output").action(async(e,t)=>{await al(e,t)});k.command("digest").description("Today's rediscovery picks: a session worth revisiting, the costliest of the week, and the one behind your latest commit.").option("--json","emit JSON instead of formatted output").action(async e=>{await dl(e)});k.command("install-extension").description("Install the bundled VS Code / Cursor / Windsurf extension into your editor. Auto-detects which CLIs are installed.").option("--editor <name>","install only into one editor: code | cursor | code-insiders | windsurf").option("--print-path","print the path to the bundled .vsix and exit").action(async e=>{await fl(e)});k.command("health [project]").description("Score how well-organized each project's sessions are. Worst first, or pass a project name for a single breakdown.").option("--json","emit JSON instead of formatted output").action((e,t)=>{El(e,t)});k.command("verify [action]").description('Toggle verification badges in the UI. Defaults to "status". Actions: on, off, status.').action(e=>{bl(e)});k.command("activate <license-key>").description("Activate your Pro license. Run once after purchase.").action(async e=>{await Ll(e)});k.command("upgrade").description("Open the Pro pricing page in your browser.").action(async()=>{await Al()});k.command("trial").description("Start a 7-day Pro trial. Opens the signup page in your browser. No card required.").action(async()=>{await vl()});var pn=k.command("telemetry").description('Manage the opt-in anonymous install ping. Defaults to "view".');pn.command("view",{isDefault:!0}).description("Show current decision, state file path, and next-ping payload.").action(async()=>{await Bl()});pn.command("on").description("Opt in. One anonymous ping per machine per month. See https://clauderecall.com/telemetry").action(async()=>{await Fl()});pn.command("off").description("Opt out. Deletes the nonce. No further pings.").action(async()=>{await Ul()});pn.command("status").description("Alias for view.").action(async()=>{await Xr()});var ho=k.command("license").description('Show or remove the Pro license on this machine. Defaults to "status".');ho.command("status",{isDefault:!0}).description("Show the current license tier.").action(async()=>{await Xl()});ho.command("deactivate").description("Remove the stored license from this machine. Reverses `recall activate`.").action(()=>{Gl()});ho.command("check").description("Force a revocation check against the license server. The daemon also runs this on a 24-hour timer in the background.").action(async()=>{await Jl()});var iw=k.command("thread").description("Group related sessions into threads, then list, show, link, merge, or scan them."),aw=k.command("threads").description("Alias for `thread`. Both forms accept the same subcommands.");function Xu(e){e.command("sync").description("Capture sessions running in this repo right now into a thread.").option("--preflight","preview the plan without writing").option("-p, --project <name>","override the cwd-based project").option("--window-hours <n>","rolling activity window (default 6)").option("--json","machine-readable JSON output").action(async t=>{await kd(t)}),e.command("scan").description("Auto-detect parent-child links across past sessions. Dry-run by default; pass --apply to write.").option("-p, --project <name>","scope to a single project").option("--json","emit JSON instead of formatted output").option("--apply","write edges (default: dry-run preview)").option("--confidence-min <n>","override threshold (dry-run 0.5, apply 0.7)").option("--no-llm-names","skip LLM naming (free, offline)").option("--llm-rescore","LLM re-score borderline pairs (small Haiku call each)").option("--rescore-band-lo <n>","low end of the borderline band (default 0.4)").option("--rescore-band-hi <n>","high end of the borderline band (default 0.7)").option("--rescore-model <id>","model id for the rescore call (default Haiku 4.5)").action(t=>{Rd(t)}),e.command("list").description("List threads, newest first.").option("--archived","include archived threads").option("--json","emit JSON instead of a table").action(t=>{Yl(t)}),e.command("show <id-prefix>").description("Show a thread's header and session tree.").option("--json","emit JSON instead of formatted output").action((t,s)=>{Kl(t,s)}),e.command("new <name>").description("Create a new thread.").option("--origin <session-id>","seed with an origin session").option("--summary <text>","optional short summary").option("--json","emit JSON").action((t,s)=>{ql(t,s)}),e.command("link <session-id>").description("Link a session into a thread.").requiredOption("--thread <id-prefix>","thread id or prefix").option("--parent <session-id>","parent session within the thread").option("--role <role>","origin | child (default inferred from --parent)").option("--json","emit JSON").action((t,s)=>{Vl(t,s)}),e.command("unlink <session-id>").description("Remove a session from a thread.").requiredOption("--thread <id-prefix>","thread id or prefix").option("--json","emit JSON").action((t,s)=>{Zl(t,s)}),e.command("set-parent <session-id>").description("Change a session's parent within a thread. Use --parent none to promote to origin.").requiredOption("--thread <id-prefix>","thread id or prefix").option("--parent <session-id|none>",'new parent, or "none" to promote to origin').option("--json","emit JSON").action((t,s)=>{Ql(t,s)}),e.command("rename <id-prefix> <new-name>").description("Rename a thread.").option("--json","emit JSON").action((t,s,n)=>{ed(t,s,n)}),e.command("close <id-prefix>").description("Mark a thread as closed (work complete).").option("--json","emit JSON").action((t,s)=>{td(t,s)}),e.command("reopen <id-prefix>").description("Reopen a closed thread.").option("--json","emit JSON").action((t,s)=>{sd(t,s)}),e.command("archive <id-prefix>").description("Archive a thread (hidden from the default list).").option("--json","emit JSON").action((t,s)=>{nd(t,s)}),e.command("merge <source-id-prefix>").description("Merge one thread into another.").requiredOption("--into <id-prefix>","destination thread").option("--json","emit JSON").action((t,s)=>{rd(t,s)}),e.command("split <id-prefix>").description("Split sessions out of a thread into a new thread.").requiredOption("--sessions <s1,s2,...>","comma-separated session ids or prefixes").requiredOption("--name <new-name>","name for the new thread").option("--json","emit JSON").action((t,s)=>{od(t,s)})}Xu(iw);Xu(aw);k.command("share [id]").description("Save a session as a shareable PNG card. No args = your last recalled session. Saved to ~/Downloads and opened.").option("--style <A|B|C|D>","card style (default A: Minimal)").option("--verdict <quote>","your one-line take on the session").option("--link","also generate a shareable URL and copy it to the clipboard").option("--clipboard","also copy the PNG to the system clipboard").option("--out <path>","override the save directory").option("--no-open","do not auto-open the saved PNG").action(async(e,t)=>{await Gd(e,t)});k.command("feedback").description("Send a 1-5 rating and optional comment to the team. Interactive by default; pass --score (and optionally --message) to skip prompts.").option("--score <1-5>","rating from 1 (bad) to 5 (great)").option("--message <text>","optional comment to send with the rating").action(async e=>{let t=await eu(e);t!==0&&(process.exitCode=t)});k.command("wrapped [month]").description("Save your monthly recap as a shareable PNG card. Defaults to the current month. Accepts YYYY-MM, full name, or abbreviation.").option("--verdict <quote>","your one-line take on the month").option("--out <path>","override the save directory").action(async(e,t)=>{await Kd(e,t)});process.env.CLAUDECODE&&process.stderr.write(`<claude-code-hint v="1" type="plugin" value="claude-recall@claude-plugins-official" />
1665
+ `);k.action(async()=>{await Nl()});k.hook("preAction",async(e,t)=>{let s=t.name();try{await Wl(s,fo)}catch{}Pl(fo).catch(()=>{})});k.parseAsync(process.argv).catch(e=>{console.error(e),process.exit(1)});