@clauderecallhq/cli 0.76.3 → 0.77.1

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 zp=Object.defineProperty;var N=(e,t)=>()=>(e&&(t=e(e=0)),t);var he=(e,t)=>{for(var s in t)zp(e,s,{get:t[s],enumerable:!0})};import{createRequire as Kp}from"node:module";var qp,Vp,Zp,Pn,Fn,bs,jn=N(()=>{"use strict";{let e=process.emit.bind(process);process.emit=function(t,...s){let n=s[0];return t==="warning"&&n instanceof Error&&n.name==="ExperimentalWarning"&&/SQLite/i.test(n.message)?!1:e(t,...s)}}qp=Kp(import.meta.url),Vp=["node","sqlite"].join(":"),Zp=qp(Vp),Pn=class{inner;constructor(t){this.inner=t}get(...t){return t.length===0?this.inner.get():this.inner.get(...t)}all(...t){return t.length===0?this.inner.all():this.inner.all(...t)}run(...t){let s=t.length===0?this.inner.run():this.inner.run(...t);return{changes:s.changes,lastInsertRowid:s.lastInsertRowid}}iterate(...t){return t.length===0?this.inner.iterate():this.inner.iterate(...t)}},Fn=class{inner;extensionLoadingEnabled=!1;txDepth=0;constructor(t,s={}){this.inner=new Zp.DatabaseSync(t,{readOnly:s.readonly??!1,allowExtension:!0})}prepare(t){return new Pn(this.inner.prepare(t))}exec(t){this.inner.exec(t)}close(){this.inner.close()}pragma(t,s={}){if(t.includes("=")){this.inner.exec(`PRAGMA ${t}`);return}if(s.simple){let n=this.inner.prepare(`PRAGMA ${t}`).get();return n&&typeof n=="object"?Object.values(n)[0]:void 0}return this.inner.prepare(`PRAGMA ${t}`).all()}transaction(t){return((...n)=>{this.txDepth===0?this.inner.exec("BEGIN"):this.inner.exec(`SAVEPOINT sp_${this.txDepth}`),this.txDepth+=1;try{let r=t(...n);return this.txDepth-=1,this.txDepth===0?this.inner.exec("COMMIT"):this.inner.exec(`RELEASE sp_${this.txDepth}`),r}catch(r){this.txDepth-=1;try{this.txDepth===0?this.inner.exec("ROLLBACK"):(this.inner.exec(`ROLLBACK TO sp_${this.txDepth}`),this.inner.exec(`RELEASE sp_${this.txDepth}`))}catch{}throw r}})}loadExtension(t,s){this.extensionLoadingEnabled||(this.inner.enableLoadExtension(!0),this.extensionLoadingEnabled=!0),s===void 0?this.inner.loadExtension(t):this.inner.loadExtension(t,s)}},bs=Fn});import{homedir as oi}from"node:os";import{join as Jt,basename as Qp}from"node:path";import{existsSync as ii,mkdirSync as em,chmodSync as tm,readdirSync as ri,statSync as sm}from"node:fs";function P(){ii(x)||em(x,{recursive:!0,mode:448}),process.platform!=="win32"&&tm(x,448)}function Un(e){return e.replace(/^-/,"/").replace(/-/g,"/")}function ai(e){let t=Un(e);return Qp(t)||t}function ci(){if(!ii(Lt))return[];let e=[],t=ri(Lt,{withFileTypes:!0}).filter(s=>s.isDirectory()).map(s=>s.name);for(let s of t){let n=Jt(Lt,s),r=ri(n,{withFileTypes:!0});for(let o of r){if(!o.isFile()||!o.name.endsWith(".jsonl"))continue;let i=Jt(n,o.name),a=sm(i);e.push({sessionFile:i,encodedProject:s,mtime:a.mtimeMs,size:a.size})}}return e}var Lt,x,te,D=N(()=>{"use strict";Lt=process.env.CLAUDE_PROJECTS_DIR?process.env.CLAUDE_PROJECTS_DIR:Jt(oi(),".claude","projects"),x=process.env.RECALL_HOME?process.env.RECALL_HOME:Jt(oi(),".recall"),te=Jt(x,"db.sqlite")});function di(e){let t=e.prepare("PRAGMA table_info(sessions)").all(),s=new Set(t.map(g=>g.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"],["archive_status","TEXT NOT NULL DEFAULT 'live'"],["archived_at","TEXT"]];for(let[g,f]of n)s.has(g)||e.exec(`ALTER TABLE sessions ADD COLUMN ${g} ${f}`);let r=e.prepare("PRAGMA table_info(collection_sessions)").all(),o=new Set(r.map(g=>g.name)),i=[["source","TEXT NOT NULL DEFAULT 'manual'"],["rule_id","TEXT"]];for(let[g,f]of i)o.has(g)||e.exec(`ALTER TABLE collection_sessions ADD COLUMN ${g} ${f}`);let a=e.prepare("PRAGMA table_info(session_notes)").all(),d=new Set(a.map(g=>g.name)),l=[["auto_synopsis","TEXT"],["auto_synopsis_generated_at","INTEGER"],["auto_synopsis_history","TEXT"]];for(let[g,f]of l)d.has(g)||e.exec(`ALTER TABLE session_notes ADD COLUMN ${g} ${f}`);let u=e.prepare("PRAGMA table_info(threads)").all();new Set(u.map(g=>g.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(g=>g.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 Qp=Object.defineProperty;var N=(e,t)=>()=>(e&&(t=e(e=0)),t);var he=(e,t)=>{for(var s in t)Qp(e,s,{get:t[s],enumerable:!0})};import{createRequire as em}from"node:module";var tm,sm,nm,jn,Un,bs,Bn=N(()=>{"use strict";{let e=process.emit.bind(process);process.emit=function(t,...s){let n=s[0];return t==="warning"&&n instanceof Error&&n.name==="ExperimentalWarning"&&/SQLite/i.test(n.message)?!1:e(t,...s)}}tm=em(import.meta.url),sm=["node","sqlite"].join(":"),nm=tm(sm),jn=class{inner;constructor(t){this.inner=t}get(...t){return t.length===0?this.inner.get():this.inner.get(...t)}all(...t){return t.length===0?this.inner.all():this.inner.all(...t)}run(...t){let s=t.length===0?this.inner.run():this.inner.run(...t);return{changes:s.changes,lastInsertRowid:s.lastInsertRowid}}iterate(...t){return t.length===0?this.inner.iterate():this.inner.iterate(...t)}},Un=class{inner;extensionLoadingEnabled=!1;txDepth=0;constructor(t,s={}){this.inner=new nm.DatabaseSync(t,{readOnly:s.readonly??!1,allowExtension:!0})}prepare(t){return new jn(this.inner.prepare(t))}exec(t){this.inner.exec(t)}close(){this.inner.close()}pragma(t,s={}){if(t.includes("=")){this.inner.exec(`PRAGMA ${t}`);return}if(s.simple){let n=this.inner.prepare(`PRAGMA ${t}`).get();return n&&typeof n=="object"?Object.values(n)[0]:void 0}return this.inner.prepare(`PRAGMA ${t}`).all()}transaction(t){return((...n)=>{this.txDepth===0?this.inner.exec("BEGIN"):this.inner.exec(`SAVEPOINT sp_${this.txDepth}`),this.txDepth+=1;try{let r=t(...n);return this.txDepth-=1,this.txDepth===0?this.inner.exec("COMMIT"):this.inner.exec(`RELEASE sp_${this.txDepth}`),r}catch(r){this.txDepth-=1;try{this.txDepth===0?this.inner.exec("ROLLBACK"):(this.inner.exec(`ROLLBACK TO sp_${this.txDepth}`),this.inner.exec(`RELEASE sp_${this.txDepth}`))}catch{}throw r}})}loadExtension(t,s){this.extensionLoadingEnabled||(this.inner.enableLoadExtension(!0),this.extensionLoadingEnabled=!0),s===void 0?this.inner.loadExtension(t):this.inner.loadExtension(t,s)}},bs=Un});import{homedir as ui}from"node:os";import{join as Gt,basename as rm}from"node:path";import{existsSync as pi,mkdirSync as om,chmodSync as im,readdirSync as di,statSync as am}from"node:fs";function F(){pi(x)||om(x,{recursive:!0,mode:448}),process.platform!=="win32"&&im(x,448)}function Hn(e){return e.replace(/^-/,"/").replace(/-/g,"/")}function mi(e){let t=Hn(e);return rm(t)||t}function gi(){if(!pi(Lt))return[];let e=[],t=di(Lt,{withFileTypes:!0}).filter(s=>s.isDirectory()).map(s=>s.name);for(let s of t){let n=Gt(Lt,s),r=di(n,{withFileTypes:!0});for(let o of r){if(!o.isFile()||!o.name.endsWith(".jsonl"))continue;let i=Gt(n,o.name),a=am(i);e.push({sessionFile:i,encodedProject:s,mtime:a.mtimeMs,size:a.size})}}return e}var Lt,x,se,P=N(()=>{"use strict";Lt=process.env.CLAUDE_PROJECTS_DIR?process.env.CLAUDE_PROJECTS_DIR:Gt(ui(),".claude","projects"),x=process.env.RECALL_HOME?process.env.RECALL_HOME:Gt(ui(),".recall"),se=Gt(x,"db.sqlite")});function _i(e){let t=e.prepare("PRAGMA table_info(sessions)").all(),s=new Set(t.map(g=>g.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"],["archive_status","TEXT NOT NULL DEFAULT 'live'"],["archived_at","TEXT"],["skipped_reason","TEXT"]];for(let[g,f]of n)s.has(g)||e.exec(`ALTER TABLE sessions ADD COLUMN ${g} ${f}`);let r=e.prepare("PRAGMA table_info(collection_sessions)").all(),o=new Set(r.map(g=>g.name)),i=[["source","TEXT NOT NULL DEFAULT 'manual'"],["rule_id","TEXT"]];for(let[g,f]of i)o.has(g)||e.exec(`ALTER TABLE collection_sessions ADD COLUMN ${g} ${f}`);let a=e.prepare("PRAGMA table_info(session_notes)").all(),d=new Set(a.map(g=>g.name)),l=[["auto_synopsis","TEXT"],["auto_synopsis_generated_at","INTEGER"],["auto_synopsis_history","TEXT"]];for(let[g,f]of l)d.has(g)||e.exec(`ALTER TABLE session_notes ADD COLUMN ${g} ${f}`);let u=e.prepare("PRAGMA table_info(threads)").all();new Set(u.map(g=>g.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(g=>g.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(`
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 zp=Object.defineProperty;var N=(e,t)=>()=>(e&&(t=e(e=0)),t);var he=(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 li,ui=N(()=>{"use strict";li=`
15
+ `)}var fi,hi=N(()=>{"use strict";fi=`
16
16
  PRAGMA journal_mode = WAL;
17
17
  PRAGMA synchronous = NORMAL;
18
18
  PRAGMA foreign_keys = ON;
@@ -668,33 +668,33 @@ CREATE INDEX IF NOT EXISTS idx_synth_results_target
668
668
  ON bug_synthesis_results(scope, target_id, created_at DESC);
669
669
  CREATE INDEX IF NOT EXISTS idx_synth_results_created
670
670
  ON bug_synthesis_results(created_at DESC);
671
- `});import*as pi from"sqlite-vec";function _(){if(ce)return ce;P(),ce=new bs(te),pi.load(ce),ce.pragma("cache_size = -64000"),ce.pragma("mmap_size = 268435456"),ce.pragma("temp_store = MEMORY"),ce.pragma("busy_timeout = 5000"),ce.pragma("journal_size_limit = 67108864"),ce.pragma("wal_autocheckpoint = 1000"),ce.exec(li),di(ce);try{ce.exec("PRAGMA optimize")}catch{}return ce}var ce,w=N(()=>{"use strict";jn();D();ui();ce=null});import Le from"chalk";import{formatDistanceToNowStrict as lm,parseISO as dm}from"date-fns";function q(e,t){if(!e)return"";let s=e.replace(/\s+/g," ").trim();return s.length<=t?s:s.slice(0,t-1)+"\u2026"}function X(e){if(!e)return"";try{return lm(dm(e),{addSuffix:!0})}catch{return""}}function W(e){return e.slice(0,8)}function Jn(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=>Le.bgYellow.black(r))}var c,v=N(()=>{"use strict";c={dim:Le.gray,bold:Le.bold,project:Le.cyan,user:Le.blue,assistant:Le.green,tool:Le.magenta,warn:Le.yellow,err:Le.red,ok:Le.green,accent:Le.hex("#f97316")}});import{existsSync as Ni,readFileSync as ag,writeFileSync as cg,unlinkSync as lg}from"node:fs";import{join as dg}from"node:path";function Kt(){if(!Ni(Et))return null;try{let e=ag(Et,"utf8"),t=JSON.parse(e);return typeof t.license_jwt!="string"||t.license_jwt.length===0?null:t}catch{return null}}function Ts(e){P(),cg(Et,JSON.stringify(e,null,2)+`
672
- `,{mode:384})}function Ai(){Ni(Et)&&lg(Et)}var Et,At=N(()=>{"use strict";D();Et=dg(x,"license.json")});var Oi,nr,vi,Ii,Mi=N(()=>{"use strict";Oi=`-----BEGIN PUBLIC KEY-----
671
+ `});import*as Ei from"sqlite-vec";function _(){if(le)return le;F(),le=new bs(se),Ei.load(le),le.pragma("cache_size = -64000"),le.pragma("mmap_size = 268435456"),le.pragma("temp_store = MEMORY"),le.pragma("busy_timeout = 5000"),le.pragma("journal_size_limit = 67108864"),le.pragma("wal_autocheckpoint = 1000"),le.exec(fi),_i(le);try{le.exec("PRAGMA optimize")}catch{}return le}var le,w=N(()=>{"use strict";Bn();P();hi();le=null});import Le from"chalk";import{formatDistanceToNowStrict as gm,parseISO as fm}from"date-fns";function K(e,t){if(!e)return"";let s=e.replace(/\s+/g," ").trim();return s.length<=t?s:s.slice(0,t-1)+"\u2026"}function J(e){if(!e)return"";try{return gm(fm(e),{addSuffix:!0})}catch{return""}}function X(e){return e.slice(0,8)}function Yn(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=>Le.bgYellow.black(r))}var c,v=N(()=>{"use strict";c={dim:Le.gray,bold:Le.bold,project:Le.cyan,user:Le.blue,assistant:Le.green,tool:Le.magenta,warn:Le.yellow,err:Le.red,ok:Le.green,accent:Le.hex("#f97316")}});import{existsSync as Di,readFileSync as pg,writeFileSync as mg,unlinkSync as gg}from"node:fs";import{join as fg}from"node:path";function Kt(){if(!Di(ht))return null;try{let e=pg(ht,"utf8"),t=JSON.parse(e);return typeof t.license_jwt!="string"||t.license_jwt.length===0?null:t}catch{return null}}function Ts(e){F(),mg(ht,JSON.stringify(e,null,2)+`
672
+ `,{mode:384})}function $i(){Di(ht)&&gg(ht)}var ht,At=N(()=>{"use strict";P();ht=fg(x,"license.json")});var Pi,or,Fi,ji,Ui=N(()=>{"use strict";Pi=`-----BEGIN PUBLIC KEY-----
673
673
  MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZysO2FffTLdyxQnTmnt78/ayvqz9
674
674
  kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
675
675
  -----END PUBLIC KEY-----
676
- `,nr="ES256",vi="clauderecall.com",Ii="clauderecall-cli"});import{jwtVerify as ug,importSPKI as pg}from"jose";async function mg(){return Rs||(Rs=await pg(Oi,nr),Rs)}async function Ot(e){try{let t=await mg(),{payload:s}=await ug(e,t,{issuer:vi,audience:Ii,algorithms:[nr]});return{valid:!0,claims:s}}catch(t){return{valid:!1,reason:t instanceof Error?t.message:"verification failed"}}}var Rs,xs=N(()=>{"use strict";Mi();Rs=null});import{createHash as gg}from"node:crypto";import{hostname as fg,userInfo as _g,platform as hg,arch as Eg}from"node:os";function vt(){let e="unknown";try{e=_g().username}catch{}let t=[fg(),e,hg(),Eg()];return gg("sha256").update(t.join("\0")).digest("hex")}var ks=N(()=>{"use strict"});function et(){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 qt=N(()=>{"use strict"});import{existsSync as bg,readFileSync as Sg,writeFileSync as yg}from"node:fs";import{join as wg}from"node:path";function Cs(){if(!bg(rr))return null;try{let e=JSON.parse(Sg(rr,"utf8"));return typeof e.license_key!="string"||typeof e.last_checked_at!="string"||typeof e.revoked!="boolean"?null:e}catch{return null}}function kg(e){P(),yg(rr,JSON.stringify(e,null,2)+`
677
- `,{mode:384})}async function Cg(e,t){let s=null,n=null;try{s=new AbortController,n=setTimeout(()=>s?.abort(),xg);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 Di(e,t={}){let s=Cs(),n=t.apiUrl??`${et()}/api/license/check`,r=s?.license_key===e,o=!s||!r||Date.now()-new Date(s.last_checked_at).getTime()>=Tg;if(!t.force&&!o)return s;let i=await Cg(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 kg(a),a}function $i(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()>Rg?{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 rr,Tg,Rg,xg,or=N(()=>{"use strict";D();qt();rr=wg(x,"license-check.json"),Tg=1440*60*1e3,Rg=720*60*60*1e3,xg=1e4});function Ng(e=Date.now()){return e<ir}function Fi(e=Date.now()){return Ng(e)?`(one-time purchase, $${Lg} through May 2026 Founder pricing, $${Pi} from June, lifetime updates either way)`:`(one-time purchase, $${Pi}, lifetime updates)`}var ir,Lg,Pi,ar=N(()=>{"use strict";ir=Date.UTC(2026,5,1,7,0,0),Lg="29.69",Pi="49.69"});function dr(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<Ag;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): ${cr}`}}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): ${cr}`};if(e.status.tier==="free"){let o=ir-t;if(o>0&&o<=3*lr){let i=Math.max(1,Math.ceil(o/lr));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: ${cr}`}}}return null}var cr,lr,Ag,ji=N(()=>{"use strict";ar();cr="https://clauderecall.com/pricing",lr=1440*60*1e3,Ag=60*lr});var Vt={};he(Vt,{getLicenseStatus:()=>Te,isPro:()=>vg,performRevocationCheck:()=>ur,printTrialBannerIfAny:()=>Ig,requireProOrExit:()=>Ne});async function Te(){let e=Kt();if(!e)return{tier:"free"};let t=await Ot(e.license_jwt);if(!t.valid||!t.claims)return{tier:"free",invalid_reason:t.reason};if(t.claims.machine_fp&&t.claims.machine_fp!==vt())return{tier:"free",invalid_reason:"machine fingerprint mismatch \u2014 re-activate on this device"};let s=$i(e.license_key);return s?.revoked?{tier:"free",invalid_reason:s.reason}:Og(e,t.claims)}async function ur(e){let t=Kt();if(!t)return{ran:!1,revoked:!1,reason:null,last_checked_at:null};let s=await Di(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 Og(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 vg(){return(await Te()).tier==="pro"}async function Ne(e){let t=await Te();if(t.tier==="pro")return;let s=dr({status:t});s&&process.stderr.write(`
676
+ `,or="ES256",Fi="clauderecall.com",ji="clauderecall-cli"});import{jwtVerify as _g,importSPKI as hg}from"jose";async function Eg(){return Rs||(Rs=await hg(Pi,or),Rs)}async function Ot(e){try{let t=await Eg(),{payload:s}=await _g(e,t,{issuer:Fi,audience:ji,algorithms:[or]});return{valid:!0,claims:s}}catch(t){return{valid:!1,reason:t instanceof Error?t.message:"verification failed"}}}var Rs,xs=N(()=>{"use strict";Ui();Rs=null});import{createHash as bg}from"node:crypto";import{hostname as Sg,userInfo as yg,platform as wg,arch as Tg}from"node:os";function vt(){let e="unknown";try{e=yg().username}catch{}let t=[Sg(),e,wg(),Tg()];return bg("sha256").update(t.join("\0")).digest("hex")}var ks=N(()=>{"use strict"});function tt(){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 Vt=N(()=>{"use strict"});import{existsSync as Rg,readFileSync as xg,writeFileSync as kg}from"node:fs";import{join as Cg}from"node:path";function Cs(){if(!Rg(ir))return null;try{let e=JSON.parse(xg(ir,"utf8"));return typeof e.license_key!="string"||typeof e.last_checked_at!="string"||typeof e.revoked!="boolean"?null:e}catch{return null}}function Og(e){F(),kg(ir,JSON.stringify(e,null,2)+`
677
+ `,{mode:384})}async function vg(e,t){let s=null,n=null;try{s=new AbortController,n=setTimeout(()=>s?.abort(),Ag);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 Bi(e,t={}){let s=Cs(),n=t.apiUrl??`${tt()}/api/license/check`,r=s?.license_key===e,o=!s||!r||Date.now()-new Date(s.last_checked_at).getTime()>=Lg;if(!t.force&&!o)return s;let i=await vg(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 Og(a),a}function Hi(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()>Ng?{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 ir,Lg,Ng,Ag,ar=N(()=>{"use strict";P();Vt();ir=Cg(x,"license-check.json"),Lg=1440*60*1e3,Ng=720*60*60*1e3,Ag=1e4});function Mg(e=Date.now()){return e<cr}function Xi(e=Date.now()){return Mg(e)?`(one-time purchase, $${Ig} through May 2026 Founder pricing, $${Wi} from June, lifetime updates either way)`:`(one-time purchase, $${Wi}, lifetime updates)`}var cr,Ig,Wi,lr=N(()=>{"use strict";cr=Date.UTC(2026,5,1,7,0,0),Ig="29.69",Wi="49.69"});function pr(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<Dg;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): ${dr}`}}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): ${dr}`};if(e.status.tier==="free"){let o=cr-t;if(o>0&&o<=3*ur){let i=Math.max(1,Math.ceil(o/ur));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: ${dr}`}}}return null}var dr,ur,Dg,Ji=N(()=>{"use strict";lr();dr="https://clauderecall.com/pricing",ur=1440*60*1e3,Dg=60*ur});var Zt={};he(Zt,{getLicenseStatus:()=>Te,isPro:()=>Pg,performRevocationCheck:()=>mr,printTrialBannerIfAny:()=>Fg,requireProOrExit:()=>Ne});async function Te(){let e=Kt();if(!e)return{tier:"free"};let t=await Ot(e.license_jwt);if(!t.valid||!t.claims)return{tier:"free",invalid_reason:t.reason};if(t.claims.machine_fp&&t.claims.machine_fp!==vt())return{tier:"free",invalid_reason:"machine fingerprint mismatch \u2014 re-activate on this device"};let s=Hi(e.license_key);return s?.revoked?{tier:"free",invalid_reason:s.reason}:$g(e,t.claims)}async function mr(e){let t=Kt();if(!t)return{ran:!1,revoked:!1,reason:null,last_checked_at:null};let s=await Bi(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 $g(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 Pg(){return(await Te()).tier==="pro"}async function Ne(e){let t=await Te();if(t.tier==="pro")return;let s=pr({status:t});s&&process.stderr.write(`
678
678
  ${s.message}
679
679
  `),process.stderr.write(`
680
680
  ${e} is a Pro feature.
681
681
 
682
682
  Buy a license at https://clauderecall.com/pricing
683
- ${Fi()}.
683
+ ${Xi()}.
684
684
  Then run: recall activate <license-key>
685
685
 
686
686
  `),t.invalid_reason&&process.stderr.write(`(stored license is invalid: ${t.invalid_reason})
687
687
 
688
- `),process.exit(1)}async function Ig(){let e=await Te(),t=dr({status:e});return t?(process.stderr.write(`
688
+ `),process.exit(1)}async function Fg(){let e=await Te(),t=pr({status:e});return t?(process.stderr.write(`
689
689
  ${t.message}
690
690
 
691
- `),!0):!1}var le=N(()=>{"use strict";At();xs();ks();or();ar();ji()});import{writeFileSync as mk,readFileSync as Mg,existsSync as Dg}from"node:fs";import{join as $g}from"node:path";function Ui(){if(!Dg(Ls))return null;try{return Mg(Ls,"utf8").trim()}catch{return null}}var Ls,pr=N(()=>{"use strict";D();Ls=$g(x,"daemon.token")});import{existsSync as Xi,readFileSync as Bg,writeFileSync as Lk,unlinkSync as Hg}from"node:fs";import{join as gr}from"node:path";function Xg(){if(!Xi(mr))return null;try{let e=JSON.parse(Bg(mr,"utf8"));return typeof e.pid!="number"||typeof e.port!="number"?null:e}catch{return null}}function Zt(){for(let e of[mr,Wg,Ls])if(Xi(e))try{Hg(e)}catch{}}function fr(e){try{return process.kill(e,0),!0}catch{return!1}}function Q(){let e=Xg();return e?fr(e.pid)?e:(Zt(),null):null}var mr,Wg,Ns,Ke=N(()=>{"use strict";D();pr();mr=gr(x,"daemon.pid"),Wg=gr(x,"daemon.port"),Ns=gr(x,"daemon.log")});import{existsSync as zg}from"node:fs";import{dirname as Gi}from"node:path";import{fileURLToPath as Kg}from"node:url";function de(){if(As)return As;let e=Gi(Kg(import.meta.url));for(;!zg(`${e}/package.json`);){let t=Gi(e);if(t===e)throw new Error(`package.json not found walking up from ${import.meta.url}`);e=t}return As=e,As}var As,st=N(()=>{"use strict";As=null});import{writeFileSync as Hf}from"node:fs";import{join as Wf}from"node:path";function wr(e){try{let t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return[]}function Ds(e){return _().prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(e)?.alias??null}function Jf(){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:wr(t.previous_aliases)}))}function It(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=wr(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)
691
+ `),!0):!1}var de=N(()=>{"use strict";At();xs();ks();ar();lr();Ji()});import{writeFileSync as Nk,readFileSync as jg,existsSync as Ug}from"node:fs";import{join as Bg}from"node:path";function Gi(){if(!Ug(Ls))return null;try{return jg(Ls,"utf8").trim()}catch{return null}}var Ls,gr=N(()=>{"use strict";P();Ls=Bg(x,"daemon.token")});import{existsSync as Ki,readFileSync as Gg,writeFileSync as Xk,unlinkSync as Yg}from"node:fs";import{join as _r}from"node:path";function qg(){if(!Ki(fr))return null;try{let e=JSON.parse(Gg(fr,"utf8"));return typeof e.pid!="number"||typeof e.port!="number"?null:e}catch{return null}}function hr(){for(let e of[fr,zg,Ls])if(Ki(e))try{Yg(e)}catch{}}function Er(e){try{return process.kill(e,0),!0}catch{return!1}}function Q(){let e=qg();return e?Er(e.pid)?e:(hr(),null):null}var fr,zg,Ns,qe=N(()=>{"use strict";P();gr();fr=_r(x,"daemon.pid"),zg=_r(x,"daemon.port"),Ns=_r(x,"daemon.log")});import{existsSync as Qg}from"node:fs";import{dirname as Qi}from"node:path";import{fileURLToPath as ef}from"node:url";function ee(){if(As)return As;let e=Qi(ef(import.meta.url));for(;!Qg(`${e}/package.json`);){let t=Qi(e);if(t===e)throw new Error(`package.json not found walking up from ${import.meta.url}`);e=t}return As=e,As}var As,Ke=N(()=>{"use strict";As=null});import{writeFileSync as Vf}from"node:fs";import{join as Zf}from"node:path";function xr(e){try{let t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return[]}function Ps(e){return _().prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(e)?.alias??null}function e_(){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:xr(t.previous_aliases)}))}function Mt(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=xr(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)
692
692
  VALUES (?, ?, ?, ?)
693
693
  ON CONFLICT(session_id) DO UPDATE SET
694
694
  alias = excluded.alias,
695
695
  updated_at = excluded.updated_at,
696
- previous_aliases = excluded.previous_aliases`).run(e,s,r,JSON.stringify(i)),va(),{session_id:e,alias:s,updated_at:r,previous_aliases:i}}function Oa(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=wr(n.previous_aliases);r.push({alias:n.alias,replaced_at:s}),t.prepare(`UPDATE session_aliases SET alias = '', updated_at = ?, previous_aliases = ?
697
- WHERE session_id = ?`).run(s,JSON.stringify(r),e),va()}function va(){try{P();let e=Jf(),t={schema:"claude-recall.aliases.v1",backed_up_at:new Date().toISOString(),aliases:e};Hf(Xf,JSON.stringify(t,null,2))}catch(e){console.error("[aliases] backup failed:",e)}}var Xf,bt=N(()=>{"use strict";w();D();Xf=Wf(x,"aliases.json")});import{writeFileSync as __}from"node:fs";import{join as h_}from"node:path";function b_(e){return e.trim().toLowerCase().replace(/^#+/,"").replace(/[\s/\\]+/g,"-").replace(/[^a-z0-9\-._]/g,"").slice(0,40)}function Wa(e,t){let s=b_(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)})(),S_(),{tag:s,added:!0})}function Xa(e){return _().prepare("SELECT tag FROM session_tags WHERE session_id = ? ORDER BY tag").all(e).map(t=>t.tag)}function S_(){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};__(E_,JSON.stringify(n,null,2))}catch(e){console.error("[tags] backup failed:",e)}}var E_,Rr=N(()=>{"use strict";w();D();E_=h_(x,"tags.json")});function y_(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 Ja(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,d)=>`@sid_${d}`).join(", ");r+=` AND s.id IN (${i})`,e.sessionIds.forEach((a,d)=>{s[`sid_${d}`]=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,
696
+ previous_aliases = excluded.previous_aliases`).run(e,s,r,JSON.stringify(i)),Da(),{session_id:e,alias:s,updated_at:r,previous_aliases:i}}function Ma(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=xr(n.previous_aliases);r.push({alias:n.alias,replaced_at:s}),t.prepare(`UPDATE session_aliases SET alias = '', updated_at = ?, previous_aliases = ?
697
+ WHERE session_id = ?`).run(s,JSON.stringify(r),e),Da()}function Da(){try{F();let e=e_(),t={schema:"claude-recall.aliases.v1",backed_up_at:new Date().toISOString(),aliases:e};Vf(Qf,JSON.stringify(t,null,2))}catch(e){console.error("[aliases] backup failed:",e)}}var Qf,Et=N(()=>{"use strict";w();P();Qf=Zf(x,"aliases.json")});import{writeFileSync as x_}from"node:fs";import{join as k_}from"node:path";function L_(e){return e.trim().toLowerCase().replace(/^#+/,"").replace(/[\s/\\]+/g,"-").replace(/[^a-z0-9\-._]/g,"").slice(0,40)}function Ga(e,t){let s=L_(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)})(),N_(),{tag:s,added:!0})}function Ya(e){return _().prepare("SELECT tag FROM session_tags WHERE session_id = ? ORDER BY tag").all(e).map(t=>t.tag)}function N_(){try{F();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};x_(C_,JSON.stringify(n,null,2))}catch(e){console.error("[tags] backup failed:",e)}}var C_,Cr=N(()=>{"use strict";w();P();C_=k_(x,"tags.json")});function A_(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 za(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,d)=>`@sid_${d}`).join(", ");r+=` AND s.id IN (${i})`,e.sessionIds.forEach((a,d)=>{s[`sid_${d}`]=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,
698
698
  NULLIF(sa.alias, '') AS alias,
699
699
  COALESCE(s.first_user_message, '') AS first_user_message
700
700
  FROM sessions s
@@ -704,17 +704,17 @@ ${t.message}
704
704
  ORDER BY COALESCE(s.started_at, '') DESC
705
705
  LIMIT @limit`).all(s).map(i=>{let a=t.prepare(`SELECT role, COALESCE(content_text, '') AS content_text
706
706
  FROM messages WHERE session_id = ?
707
- ORDER BY COALESCE(timestamp, ''), rowid`).all(i.id),l=y_(a,5).map(u=>`${u.role}: ${u.content_text.slice(0,400)}`).join(`
707
+ ORDER BY COALESCE(timestamp, ''), rowid`).all(i.id),l=A_(a,5).map(u=>`${u.role}: ${u.content_text.slice(0,400)}`).join(`
708
708
  ---
709
- `);return{id:i.id,project:i.project,git_branch:i.git_branch,alias:i.alias,first_user_message:i.first_user_message,message_sample:l,current_tags:Xa(i.id)}})}var Ya=N(()=>{"use strict";w();Rr()});import{z as Re}from"zod";function Ga(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(`
710
- `)}var YL,GL,zL,KL,za=N(()=>{"use strict";YL={project:Re.string().optional().describe("Exact project name match (optional)."),collectionId:Re.string().optional().describe("Restrict to sessions in this collection (optional)."),sessionId:Re.string().optional().describe("Full session UUID to tag just one session (optional)."),untaggedOnly:Re.boolean().optional().describe("Skip sessions that already have any tag (default: true)."),limit:Re.number().int().min(1).max(500).optional().describe("Max sessions to process (default: 100)."),minTags:Re.number().int().min(1).max(10).optional().describe("Minimum tags per session (default: 2)."),maxTags:Re.number().int().min(1).max(10).optional().describe("Maximum tags per session (default: 4).")};GL={sessionId:Re.string().describe("Session UUID (or 8+-char prefix) to summarize."),mode:Re.enum(["brief","detailed"]).optional().describe("brief = 3-5 bullets; detailed = paragraph + bullets. Default: brief.")},zL={sessionId:Re.string().describe("Session UUID (or 8+-char prefix) to extract decisions from.")},KL={sessionId:Re.string().describe("Session UUID (or 8+-char prefix) to find similar sessions to."),limit:Re.number().int().min(1).max(20).optional().describe("How many similar sessions to surface (default: 5).")}});function Ka(e,t){let s=w_.get(e);if(!(!s||s.size===0))for(let n of s)try{n(t)}catch{}}var w_,qa=N(()=>{"use strict";w_=new Map});import{existsSync as T_,statSync as R_}from"node:fs";import{delimiter as x_,join as k_}from"node:path";function Va(e){if(e.includes("/")||e.includes("\\")||e.includes(".."))return null;let t=(process.env.PATH??"").split(x_).filter(Boolean),s=process.platform==="win32"?[e,`${e}.exe`,`${e}.cmd`,`${e}.bat`]:[e];for(let n of t)for(let r of s){let o=k_(n,r);try{if(T_(o)&&R_(o).isFile())return o}catch{}}return null}function Za(e){if(process.platform!=="win32"||!e)return!1;let t=e.toLowerCase();return t.endsWith(".cmd")||t.endsWith(".bat")}var Qa=N(()=>{"use strict"});var Fs={};he(Fs,{_resetClaudePathCacheForTests:()=>A_,buildScanPrompt:()=>tc,isClaudeCliAvailable:()=>se,runClaudeCliScan:()=>D_,spawnClaudePrompt:()=>St});import{spawn as C_}from"node:child_process";function ec(){if(Mt!==void 0&&ts!==void 0)return{path:Mt,available:ts};let e=Va("claude");return Mt=e??"claude",ts=e!==null,{path:Mt,available:ts}}function N_(){return ec().path}function se(){return ec().available}function A_(){Mt=void 0,ts=void 0}function tc(e){return Ga({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 O_(e,t){let s=t.get(e);return s||e.slice(0,8)}function v_(e){try{return Ja(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 I_(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 d=a;if(!(d.type!=="assistant"||!d.message?.content))for(let l of d.message.content){if(l?.type!=="tool_use"||l.name!=="mcp__recall__apply_tags")continue;let u=l.input,p=typeof u?.sessionId=="string"?u.sessionId:null;!p||r.has(p)||(r.add(p),Ka(t,{type:"progress",current:r.size,total:s,sessionId:p,sessionLabel:O_(p,n)}))}}}function M_(e){let t="";return s=>{t+=s.toString("utf8");let n=t.indexOf(`
709
+ `);return{id:i.id,project:i.project,git_branch:i.git_branch,alias:i.alias,first_user_message:i.first_user_message,message_sample:l,current_tags:Ya(i.id)}})}var qa=N(()=>{"use strict";w();Cr()});import{z as Re}from"zod";function Ka(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(`
710
+ `)}var pN,mN,gN,fN,Va=N(()=>{"use strict";pN={project:Re.string().optional().describe("Exact project name match (optional)."),collectionId:Re.string().optional().describe("Restrict to sessions in this collection (optional)."),sessionId:Re.string().optional().describe("Full session UUID to tag just one session (optional)."),untaggedOnly:Re.boolean().optional().describe("Skip sessions that already have any tag (default: true)."),limit:Re.number().int().min(1).max(500).optional().describe("Max sessions to process (default: 100)."),minTags:Re.number().int().min(1).max(10).optional().describe("Minimum tags per session (default: 2)."),maxTags:Re.number().int().min(1).max(10).optional().describe("Maximum tags per session (default: 4).")};mN={sessionId:Re.string().describe("Session UUID (or 8+-char prefix) to summarize."),mode:Re.enum(["brief","detailed"]).optional().describe("brief = 3-5 bullets; detailed = paragraph + bullets. Default: brief.")},gN={sessionId:Re.string().describe("Session UUID (or 8+-char prefix) to extract decisions from.")},fN={sessionId:Re.string().describe("Session UUID (or 8+-char prefix) to find similar sessions to."),limit:Re.number().int().min(1).max(20).optional().describe("How many similar sessions to surface (default: 5).")}});function Za(e,t){let s=O_.get(e);if(!(!s||s.size===0))for(let n of s)try{n(t)}catch{}}var O_,Qa=N(()=>{"use strict";O_=new Map});import{existsSync as v_,statSync as I_}from"node:fs";import{delimiter as M_,join as D_}from"node:path";function ec(e){if(e.includes("/")||e.includes("\\")||e.includes(".."))return null;let t=(process.env.PATH??"").split(M_).filter(Boolean),s=process.platform==="win32"?[e,`${e}.exe`,`${e}.cmd`,`${e}.bat`]:[e];for(let n of t)for(let r of s){let o=D_(n,r);try{if(v_(o)&&I_(o).isFile())return o}catch{}}return null}function tc(e){if(process.platform!=="win32"||!e)return!1;let t=e.toLowerCase();return t.endsWith(".cmd")||t.endsWith(".bat")}var sc=N(()=>{"use strict"});var Us={};he(Us,{_resetClaudePathCacheForTests:()=>j_,buildScanPrompt:()=>rc,isClaudeCliAvailable:()=>ne,runClaudeCliScan:()=>X_,spawnClaudePrompt:()=>bt});import{spawn as $_}from"node:child_process";function nc(){if(Dt!==void 0&&ts!==void 0)return{path:Dt,available:ts};let e=ec("claude");return Dt=e??"claude",ts=e!==null,{path:Dt,available:ts}}function F_(){return nc().path}function ne(){return nc().available}function j_(){Dt=void 0,ts=void 0}function rc(e){return Ka({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 U_(e,t){let s=t.get(e);return s||e.slice(0,8)}function B_(e){try{return za(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 H_(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 d=a;if(!(d.type!=="assistant"||!d.message?.content))for(let l of d.message.content){if(l?.type!=="tool_use"||l.name!=="mcp__recall__apply_tags")continue;let u=l.input,p=typeof u?.sessionId=="string"?u.sessionId:null;!p||r.has(p)||(r.add(p),Za(t,{type:"progress",current:r.size,total:s,sessionId:p,sessionLabel:U_(p,n)}))}}}function W_(e){let t="";return s=>{t+=s.toString("utf8");let n=t.indexOf(`
711
711
  `);for(;n!==-1;){let r=t.slice(0,n);t=t.slice(n+1),r.length>0&&e(r),n=t.indexOf(`
712
- `)}}}async function D_(e,t={},s){let n=!!t.scanId,r=n?v_(e):[],o=new Map(r.map(d=>[d.id,d.label])),i=r.length,a;return n&&t.scanId&&(a=I_({scanId:t.scanId,total:i,labelTable:o})),sc({prompt:tc(e),allowedTools:L_.split(","),opts:t,onProgress:s,onStdoutLine:a,outputFormat:n?"stream-json":"json"})}async function St(e,t,s={},n){return sc({prompt:e,allowedTools:t,opts:s,onProgress:n,outputFormat:"json"})}function sc(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","--no-session-persistence"];return i==="stream-json"&&a.push("--verbose"),n.model&&a.push("--model",n.model),new Promise(d=>{let l=N_(),u=C_(l,a,{stdio:["ignore","pipe","pipe"],shell:Za(l)||process.platform==="win32"&&Mt==="claude"}),p=[],m=[],g=o?M_(o):void 0;u.stdout.on("data",h=>{p.push(h),g&&g(h)}),u.stderr.on("data",h=>{if(m.push(h),r){let E=h.toString("utf8").trim();E&&r(E)}});let f=setTimeout(()=>{u.kill("SIGKILL")},1800*1e3);u.on("close",h=>{clearTimeout(f),d({success:h===0,stdout:Buffer.concat(p).toString("utf8"),stderr:Buffer.concat(m).toString("utf8"),exitCode:h})}),u.on("error",h=>{clearTimeout(f),d({success:!1,stdout:"",stderr:String(h),exitCode:null})})})}var L_,Mt,ts,Be=N(()=>{"use strict";Ya();za();qa();Qa();L_=["mcp__recall__list_tags","mcp__recall__list_sessions_to_tag","mcp__recall__apply_tags"].join(",")});var ac={};he(ac,{downloadModel:()=>Lr,getModelDir:()=>Hs,isModelInstalled:()=>yt,uninstallModel:()=>Nr});import{existsSync as Cr,mkdirSync as oc,rmSync as kr,createWriteStream as eh,statSync as th}from"node:fs";import{join as Bs}from"node:path";import{createHash as sh}from"node:crypto";import{readFile as nh}from"node:fs/promises";function Hs(){return Bs(x,"models","BAAI","bge-base-en-v1.5")}function yt(){let e=Hs();return ic.every(t=>Cr(Bs(e,t.path)))}async function Lr(e){let t=Hs();oc(t,{recursive:!0}),oc(Bs(t,"onnx"),{recursive:!0});for(let s of ic){let n=Bs(t,s.path),r=rh+s.path,o=0;Cr(n)&&(o=th(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 d=a.headers.get("content-length"),l=d?o+Number(d):0,u=a.body;if(!u)throw new Error(`No response body for ${s.path}`);let p=eh(n,{flags:o>0?"a":"w"}),m=u.getReader(),g=o;for(;;){let{done:E,value:b}=await m.read();if(E)break;p.write(Buffer.from(b)),g+=b.byteLength,e?.(s.path,g,l)}if(p.end(),await new Promise((E,b)=>{p.on("finish",E),p.on("error",b)}),s.sha256==="TODO_PLACEHOLDER")throw kr(n),new Error(`Refusing to install: SHA-256 not pinned for ${s.path}. Update model-download.ts.`);let f=await nh(n);if(sh("sha256").update(f).digest("hex")!==s.sha256)throw kr(n),new Error(`SHA-256 mismatch for ${s.path}`)}}function Nr(){let e=Hs();Cr(e)&&kr(e,{recursive:!0,force:!0})}var rh,ic,Ws=N(()=>{"use strict";D();rh="https://huggingface.co/BAAI/bge-base-en-v1.5/resolve/main/",ic=[{path:"config.json",sha256:"bc00af31a4a31b74040d73370aa83b62da34c90b75eb77bfa7db039d90abd591"},{path:"tokenizer.json",sha256:"d241a60d5e8f04cc1b2b3e9ef7a4921b27bf526d9f6050ab90f9267a1f9e5c66"},{path:"tokenizer_config.json",sha256:"9261e7d79b44c8195c1cada2b453e55b00aeb81e907a6664974b4d7776172ab3"},{path:"onnx/model.onnx",sha256:"9bc579acdba21c253c62a9bf866891355a63ffa3442b52c8a37d75b2ccb91848"}]});var cc,lc=N(()=>{"use strict";cc="BAAI/bge-base-en-v1.5"});var Ir={};he(Ir,{EmbedderUnavailableError:()=>ns,embed:()=>Dt,embedQuery:()=>vr,getEmbedderStatus:()=>Ve,loadEmbedder:()=>nt,unloadEmbedder:()=>ph});import{Worker as ih}from"node:worker_threads";import{join as ah}from"node:path";import{existsSync as ch}from"node:fs";function lh(){return ah(de(),"dist","daemon","embedder-worker.js")}function dh(e){return["Semantic search is unavailable on this platform.","",`Reason: ${e.detail}`,"",`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(`
713
- `)}function dc(e){for(let t of ss.values())t.reject(e);ss.clear()}function uh(){if(qe)return qe;let e=lh();if(!ch(e))throw new ns({kind:"bundle-missing",detail:"embedder-worker bundle not found \u2014 run `npm run build:cli` to emit it",path:e});let t=new ih(e);return t.on("message",s=>{let n=ss.get(s.id);n&&(ss.delete(s.id),n.resolve(s))}),t.on("error",s=>{console.error("[embedder-worker] thread error:",s);let n=s instanceof Error?s:new Error(String(s));dc(n),qe=null,He=!1}),t.on("exit",s=>{s!==0&&(console.error(`[embedder-worker] exited with code ${s}`),dc(new Error(`embedder worker exited with code ${s}`))),qe=null,He=!1}),qe=t,t}function Xs(e){return new Promise((t,s)=>{let n;try{n=uh()}catch(r){s(r instanceof Error?r:new Error(String(r)));return}ss.set(e.id,{resolve:t,reject:s}),n.postMessage(e)})}function Js(){return Ar=Ar+1>>>0,String(Ar)}function Or(e){if(!e.ok)throw e.unavailable?new ns({kind:"platform-unsupported",detail:"embedder worker reports the runtime is unavailable on this platform",underlying:new Error(e.error)}):new Error(e.error);return e}async function nt(){if(!(He&&qe))try{Or(await Xs({id:Js(),type:"load"})),He=!0}catch(e){throw He=!1,e}}function Ve(){return{loaded:He,modelId:cc,dim:768}}async function Dt(e){if(!He)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");return Or(await Xs({id:Js(),type:"embed",texts:e})).embeddings.map(s=>new Float32Array(s))}async function vr(e){if(!He)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");let t=Or(await Xs({id:Js(),type:"embedQuery",text:e}));return new Float32Array(t.embedding)}async function ph(){if(!qe){He=!1;return}try{await Xs({id:Js(),type:"unload"})}catch{}He=!1;let e=qe;qe=null;try{await e.terminate()}catch{}}var qe,ss,Ar,He,ns,rt=N(()=>{"use strict";st();lc();qe=null,ss=new Map,Ar=0,He=!1,ns=class extends Error{kind;path;underlying;cause;constructor(t){super(dh(t)),this.name="EmbedderUnavailableError",this.kind=t.kind,this.path=t.path,this.underlying=t.underlying,this.cause=t}}});var gc={};he(gc,{detectRunningClaudeOnWindows:()=>mc,ensureTransformersInstalled:()=>Lh});import{execFileSync as Eh,spawn as bh}from"node:child_process";import{existsSync as Sh}from"node:fs";import{dirname as yh,resolve as wh}from"node:path";import{fileURLToPath as Th}from"node:url";function xh(){let e=yh(Th(import.meta.url));return wh(e,"..","..")}async function kh(){try{return await import("@huggingface/transformers"),!0}catch{return!1}}function Ch(e){return new Promise(t=>{let s=["install","--no-save","--no-audit","--no-fund","--prefix",e,`@huggingface/transformers@${Rh}`],n=bh("npm",s,{stdio:["ignore","inherit","inherit"],cwd:e,shell:process.platform==="win32"});n.on("error",r=>{t({ok:!1,error:`npm spawn failed: ${r instanceof Error?r.message:String(r)}`})}),n.on("exit",r=>{t(r===0?{ok:!0,action:"installed"}:{ok:!1,error:`npm install exited with code ${r}`})})})}function mc(){if(process.platform!=="win32")return!1;try{return Eh("tasklist",["/FI","IMAGENAME eq claude.exe"],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).toLowerCase().includes("claude.exe")}catch{return!1}}async function Lh(){if(await kh())return{ok:!0,action:"already-installed"};if(mc())return{ok:!1,error:"Close all Claude Code windows before running `recall semantic install` on Windows. claude.exe holds exclusive locks on shared dependency files (Windows kernel default), which causes the underlying npm install to fail with EBUSY. After closing Claude Code, rerun `recall semantic install` to complete the install."};let e=xh();return Sh(e)?(console.log(`Installing @huggingface/transformers into ${e} ...`),Ch(e)):{ok:!1,error:`package root not found at ${e}`}}var Rh,fc=N(()=>{"use strict";Rh="^3.4.1"});import{writeFileSync as Nc,readFileSync as TA,existsSync as Ac,mkdirSync as Oc,readdirSync as RA}from"node:fs";import{join as zs}from"node:path";function gE(){P(),Ac(Ur)||Oc(Ur,{recursive:!0})}function fE(){P(),Ac(Br)||Oc(Br,{recursive:!0})}function vc(e){try{return JSON.parse(e)}catch{return e}}function Hr(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:vc(e.evidence),approved:e.approved===1,created_at:e.created_at,updated_at:e.updated_at}}function Wr(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:vc(e.evidence),status:e.status,inferred_by:e.inferred_by,created_at:e.created_at,decided_at:e.decided_at}}function _E(e){if(!Number.isFinite(e)||e<0||e>1)throw new Error("confidence must be a number in [0, 1]")}function Ic(e){if(!lE.has(e))throw new Error(`invalid link_type: ${e}`)}function Mc(e){if(!pE.has(e))throw new Error(`invalid inferred_by: ${e}`)}function hE(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 EE(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&&(Ic(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}
712
+ `)}}}async function X_(e,t={},s){let n=!!t.scanId,r=n?B_(e):[],o=new Map(r.map(d=>[d.id,d.label])),i=r.length,a;return n&&t.scanId&&(a=H_({scanId:t.scanId,total:i,labelTable:o})),oc({prompt:rc(e),allowedTools:P_.split(","),opts:t,onProgress:s,onStdoutLine:a,outputFormat:n?"stream-json":"json"})}async function bt(e,t,s={},n){return oc({prompt:e,allowedTools:t,opts:s,onProgress:n,outputFormat:"json"})}function oc(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","--no-session-persistence"];return i==="stream-json"&&a.push("--verbose"),n.model&&a.push("--model",n.model),new Promise(d=>{let l=F_(),u=$_(l,a,{stdio:["ignore","pipe","pipe"],shell:tc(l)||process.platform==="win32"&&Dt==="claude"}),p=[],m=[],g=o?W_(o):void 0;u.stdout.on("data",h=>{p.push(h),g&&g(h)}),u.stderr.on("data",h=>{if(m.push(h),r){let E=h.toString("utf8").trim();E&&r(E)}});let f=setTimeout(()=>{u.kill("SIGKILL")},1800*1e3);u.on("close",h=>{clearTimeout(f),d({success:h===0,stdout:Buffer.concat(p).toString("utf8"),stderr:Buffer.concat(m).toString("utf8"),exitCode:h})}),u.on("error",h=>{clearTimeout(f),d({success:!1,stdout:"",stderr:String(h),exitCode:null})})})}var P_,Dt,ts,Be=N(()=>{"use strict";qa();Va();Qa();sc();P_=["mcp__recall__list_tags","mcp__recall__list_sessions_to_tag","mcp__recall__apply_tags"].join(",")});var dc={};he(dc,{downloadModel:()=>Or,getModelDir:()=>Xs,isModelInstalled:()=>St,uninstallModel:()=>vr});import{existsSync as Ar,mkdirSync as cc,rmSync as Nr,createWriteStream as lh,statSync as dh}from"node:fs";import{join as Ws}from"node:path";import{createHash as uh}from"node:crypto";import{readFile as ph}from"node:fs/promises";function Xs(){return Ws(x,"models","BAAI","bge-base-en-v1.5")}function St(){let e=Xs();return lc.every(t=>Ar(Ws(e,t.path)))}async function Or(e){let t=Xs();cc(t,{recursive:!0}),cc(Ws(t,"onnx"),{recursive:!0});for(let s of lc){let n=Ws(t,s.path),r=mh+s.path,o=0;Ar(n)&&(o=dh(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 d=a.headers.get("content-length"),l=d?o+Number(d):0,u=a.body;if(!u)throw new Error(`No response body for ${s.path}`);let p=lh(n,{flags:o>0?"a":"w"}),m=u.getReader(),g=o;for(;;){let{done:E,value:b}=await m.read();if(E)break;p.write(Buffer.from(b)),g+=b.byteLength,e?.(s.path,g,l)}if(p.end(),await new Promise((E,b)=>{p.on("finish",E),p.on("error",b)}),s.sha256==="TODO_PLACEHOLDER")throw Nr(n),new Error(`Refusing to install: SHA-256 not pinned for ${s.path}. Update model-download.ts.`);let f=await ph(n);if(uh("sha256").update(f).digest("hex")!==s.sha256)throw Nr(n),new Error(`SHA-256 mismatch for ${s.path}`)}}function vr(){let e=Xs();Ar(e)&&Nr(e,{recursive:!0,force:!0})}var mh,lc,Js=N(()=>{"use strict";P();mh="https://huggingface.co/BAAI/bge-base-en-v1.5/resolve/main/",lc=[{path:"config.json",sha256:"bc00af31a4a31b74040d73370aa83b62da34c90b75eb77bfa7db039d90abd591"},{path:"tokenizer.json",sha256:"d241a60d5e8f04cc1b2b3e9ef7a4921b27bf526d9f6050ab90f9267a1f9e5c66"},{path:"tokenizer_config.json",sha256:"9261e7d79b44c8195c1cada2b453e55b00aeb81e907a6664974b4d7776172ab3"},{path:"onnx/model.onnx",sha256:"9bc579acdba21c253c62a9bf866891355a63ffa3442b52c8a37d75b2ccb91848"}]});var uc,pc=N(()=>{"use strict";uc="BAAI/bge-base-en-v1.5"});var Dr={};he(Dr,{EmbedderUnavailableError:()=>ns,embed:()=>$t,embedQuery:()=>yh,getEmbedderStatus:()=>Ze,loadEmbedder:()=>nt,unloadEmbedder:()=>wh});import{Worker as fh}from"node:worker_threads";import{join as _h}from"node:path";import{existsSync as hh}from"node:fs";function Eh(){return _h(ee(),"dist","daemon","embedder-worker.js")}function bh(e){return["Semantic search is unavailable on this platform.","",`Reason: ${e.detail}`,"",`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(`
713
+ `)}function mc(e){for(let t of ss.values())t.reject(e);ss.clear()}function Sh(){if(Ve)return Ve;let e=Eh();if(!hh(e))throw new ns({kind:"bundle-missing",detail:"embedder-worker bundle not found \u2014 run `npm run build:cli` to emit it",path:e});let t=new fh(e);return t.on("message",s=>{let n=ss.get(s.id);n&&(ss.delete(s.id),n.resolve(s))}),t.on("error",s=>{console.error("[embedder-worker] thread error:",s);let n=s instanceof Error?s:new Error(String(s));mc(n),Ve=null,He=!1}),t.on("exit",s=>{s!==0&&(console.error(`[embedder-worker] exited with code ${s}`),mc(new Error(`embedder worker exited with code ${s}`))),Ve=null,He=!1}),Ve=t,t}function Gs(e){return new Promise((t,s)=>{let n;try{n=Sh()}catch(r){s(r instanceof Error?r:new Error(String(r)));return}ss.set(e.id,{resolve:t,reject:s}),n.postMessage(e)})}function Ys(){return Ir=Ir+1>>>0,String(Ir)}function Mr(e){if(!e.ok)throw e.unavailable?new ns({kind:"platform-unsupported",detail:"embedder worker reports the runtime is unavailable on this platform",underlying:new Error(e.error)}):new Error(e.error);return e}async function nt(){if(!(He&&Ve))try{Mr(await Gs({id:Ys(),type:"load"})),He=!0}catch(e){throw He=!1,e}}function Ze(){return{loaded:He,modelId:uc,dim:768}}async function $t(e){if(!He)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");return Mr(await Gs({id:Ys(),type:"embed",texts:e})).embeddings.map(s=>new Float32Array(s))}async function yh(e){if(!He)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");let t=Mr(await Gs({id:Ys(),type:"embedQuery",text:e}));return new Float32Array(t.embedding)}async function wh(){if(!Ve){He=!1;return}try{await Gs({id:Ys(),type:"unload"})}catch{}He=!1;let e=Ve;Ve=null;try{await e.terminate()}catch{}}var Ve,ss,Ir,He,ns,yt=N(()=>{"use strict";Ke();pc();Ve=null,ss=new Map,Ir=0,He=!1,ns=class extends Error{kind;path;underlying;cause;constructor(t){super(bh(t)),this.name="EmbedderUnavailableError",this.kind=t.kind,this.path=t.path,this.underlying=t.underlying,this.cause=t}}});var hc={};he(hc,{detectRunningClaudeOnWindows:()=>_c,ensureTransformersInstalled:()=>Fh});import{execFileSync as Lh,spawn as Nh}from"node:child_process";import{existsSync as Ah}from"node:fs";import{dirname as Oh,resolve as vh}from"node:path";import{fileURLToPath as Ih}from"node:url";function Dh(){let e=Oh(Ih(import.meta.url));return vh(e,"..","..")}async function $h(){try{return await import("@huggingface/transformers"),!0}catch{return!1}}function Ph(e){return new Promise(t=>{let s=["install","--no-save","--no-audit","--no-fund","--prefix",e,`@huggingface/transformers@${Mh}`],n=Nh("npm",s,{stdio:["ignore","inherit","inherit"],cwd:e,shell:process.platform==="win32"});n.on("error",r=>{t({ok:!1,error:`npm spawn failed: ${r instanceof Error?r.message:String(r)}`})}),n.on("exit",r=>{t(r===0?{ok:!0,action:"installed"}:{ok:!1,error:`npm install exited with code ${r}`})})})}function _c(){if(process.platform!=="win32")return!1;try{return Lh("tasklist",["/FI","IMAGENAME eq claude.exe"],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).toLowerCase().includes("claude.exe")}catch{return!1}}async function Fh(){if(await $h())return{ok:!0,action:"already-installed"};if(_c())return{ok:!1,error:"Close all Claude Code windows before running `recall semantic install` on Windows. claude.exe holds exclusive locks on shared dependency files (Windows kernel default), which causes the underlying npm install to fail with EBUSY. After closing Claude Code, rerun `recall semantic install` to complete the install."};let e=Dh();return Ah(e)?(console.log(`Installing @huggingface/transformers into ${e} ...`),Ph(e)):{ok:!1,error:`package root not found at ${e}`}}var Mh,Ec=N(()=>{"use strict";Mh="^4.2.0"});import{writeFileSync as vc,readFileSync as WA,existsSync as Ic,mkdirSync as Mc,readdirSync as XA}from"node:fs";import{join as Ks}from"node:path";function RE(){F(),Ic(Hr)||Mc(Hr,{recursive:!0})}function xE(){F(),Ic(Wr)||Mc(Wr,{recursive:!0})}function Dc(e){try{return JSON.parse(e)}catch{return e}}function Xr(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:Dc(e.evidence),approved:e.approved===1,created_at:e.created_at,updated_at:e.updated_at}}function Jr(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:Dc(e.evidence),status:e.status,inferred_by:e.inferred_by,created_at:e.created_at,decided_at:e.decided_at}}function kE(e){if(!Number.isFinite(e)||e<0||e>1)throw new Error("confidence must be a number in [0, 1]")}function $c(e){if(!bE.has(e))throw new Error(`invalid link_type: ${e}`)}function Pc(e){if(!wE.has(e))throw new Error(`invalid inferred_by: ${e}`)}function CE(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 LE(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&&($c(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}
714
714
  ORDER BY confidence DESC, updated_at DESC
715
- LIMIT ?`).all(...n,o).map(Hr)}function Xr(e){return _().prepare(`SELECT * FROM session_links
715
+ LIMIT ?`).all(...n,o).map(Xr)}function Gr(e){return _().prepare(`SELECT * FROM session_links
716
716
  WHERE source_session_id = ? OR target_session_id = ?
717
- ORDER BY confidence DESC, updated_at DESC`).all(e,e).map(Hr)}function it(e){hE(e.source_session_id,e.target_session_id),Ic(e.link_type),_E(e.confidence),Mc(e.inferred_by);let t=_(),s=new Date().toISOString(),n=JSON.stringify(e.evidence??null);t.prepare(`INSERT INTO session_link_suggestions
717
+ ORDER BY confidence DESC, updated_at DESC`).all(e,e).map(Xr)}function ot(e){CE(e.source_session_id,e.target_session_id),$c(e.link_type),kE(e.confidence),Pc(e.inferred_by);let t=_(),s=new Date().toISOString(),n=JSON.stringify(e.evidence??null);t.prepare(`INSERT INTO session_link_suggestions
718
718
  (source_session_id, target_session_id, link_type,
719
719
  confidence, evidence, status, inferred_by,
720
720
  created_at, decided_at)
@@ -734,9 +734,9 @@ ${t.message}
734
734
  WHERE source_session_id = ?
735
735
  AND target_session_id = ?
736
736
  AND link_type = ?
737
- 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 $c(),Wr(r)}function Ks(e={}){let t=_(),s=[],n=[];if(e.status){if(!uE.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&&(Mc(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}
737
+ 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 jc(),Jr(r)}function Vs(e={}){let t=_(),s=[],n=[];if(e.status){if(!yE.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&&(Pc(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}
738
738
  ORDER BY confidence DESC, created_at DESC
739
- LIMIT ?`).all(...n,o).map(Wr)}function Dc(e,t,s={}){if(t!=="approved"&&t!=="rejected")throw new Error(`invalid decision: ${t}`);let n=s.source??"manual";if(!dE.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
739
+ LIMIT ?`).all(...n,o).map(Jr)}function Fc(e,t,s={}){if(t!=="approved"&&t!=="rejected")throw new Error(`invalid decision: ${t}`);let n=s.source??"manual";if(!SE.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
740
740
  SET status = ?, decided_at = ?
741
741
  WHERE id = ?`).run(t,i,e),t==="approved"&&(r.prepare(`INSERT INTO session_links
742
742
  (source_session_id, target_session_id, link_type,
@@ -751,7 +751,7 @@ ${t.message}
751
751
  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
752
752
  WHERE source_session_id = ?
753
753
  AND target_session_id = ?
754
- AND link_type = ?`).get(o.source_session_id,o.target_session_id,o.link_type))})(),$c(),t==="approved"&&bE(o.source_session_id);let d=r.prepare("SELECT * FROM session_link_suggestions WHERE id = ?").get(e);return{suggestion:Wr(d),link:a?Hr(a):null}}function bE(e){try{gE();let t=EE({sourceSessionId:e}),s=zs(Ur,`${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};Nc(s,JSON.stringify(n,null,2))}catch(t){console.error("[session-links] backup failed:",t)}}function $c(){try{fE();let e=Ks({limit:5e3}),t={schema:"claude-recall.session-link-suggestions.v1",backed_up_at:new Date().toISOString(),suggestions:e};Nc(mE,JSON.stringify(t,null,2))}catch(e){console.error("[session-links] suggestions backup failed:",e)}}var lE,dE,uE,pE,Ur,Br,mE,as=N(()=>{"use strict";w();D();lE=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),dE=new Set(["regex","llm","embedding","manual","auto","citation","git","terminal-registry"]),uE=new Set(["pending","approved","rejected"]),pE=new Set(["L1","L2","L3","L4","user"]),Ur=zs(x,"links"),Br=zs(x,"suggestions"),mE=zs(Br,"index.json")});function en(e){return e?Math.ceil(e.length/4):0}function al(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/Pb);return Math.max(Fb,t)}function cl(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 ll(e){return _().prepare(`SELECT s.id,
754
+ AND link_type = ?`).get(o.source_session_id,o.target_session_id,o.link_type))})(),jc(),t==="approved"&&NE(o.source_session_id);let d=r.prepare("SELECT * FROM session_link_suggestions WHERE id = ?").get(e);return{suggestion:Jr(d),link:a?Xr(a):null}}function NE(e){try{RE();let t=LE({sourceSessionId:e}),s=Ks(Hr,`${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};vc(s,JSON.stringify(n,null,2))}catch(t){console.error("[session-links] backup failed:",t)}}function jc(){try{xE();let e=Vs({limit:5e3}),t={schema:"claude-recall.session-link-suggestions.v1",backed_up_at:new Date().toISOString(),suggestions:e};vc(TE,JSON.stringify(t,null,2))}catch(e){console.error("[session-links] suggestions backup failed:",e)}}var bE,SE,yE,wE,Hr,Wr,TE,as=N(()=>{"use strict";w();P();bE=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),SE=new Set(["regex","llm","embedding","manual","auto","citation","git","terminal-registry"]),yE=new Set(["pending","approved","rejected"]),wE=new Set(["L1","L2","L3","L4","user"]),Hr=Ks(x,"links"),Wr=Ks(x,"suggestions"),TE=Ks(Wr,"index.json")});function sn(e){return e?Math.ceil(e.length/4):0}function dl(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/Yb);return Math.max(zb,t)}function ul(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 pl(e){return _().prepare(`SELECT s.id,
755
755
  NULLIF(sa.alias, '') AS alias,
756
756
  s.auto_title,
757
757
  s.auto_title_source,
@@ -762,18 +762,18 @@ ${t.message}
762
762
  FROM sessions s
763
763
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
764
764
  LEFT JOIN projects p ON p.id = s.project_id
765
- WHERE s.id = ?`).get(e)??null}function dl(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 ul(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 Ub(e){let s=_().prepare(`SELECT id, auto_title, started_at
765
+ WHERE s.id = ?`).get(e)??null}function ml(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 gl(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 Kb(e){let s=_().prepare(`SELECT id, auto_title, started_at
766
766
  FROM sessions
767
767
  WHERE project_id = ?
768
- 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 g=m.auto_title.split(" \xB7 "),f=g[0].trim(),h=g.length>1?g.slice(1).join(" \xB7 ").trim():null;o.push({id:m.id,brand:h||null,skill:f||null}),h&&n.add(h),f&&r.add(f)}let i=[...n].sort(),a=new Map;i.forEach((m,g)=>a.set(m,g));let d=[...r].sort(),l=new Map;d.forEach((m,g)=>l.set(m,g));let u=new Map,p=new Map;for(let m of o){if(!m.brand||!m.skill)continue;let g=a.get(m.brand),f=l.get(m.skill);if(g===void 0||f===void 0)continue;let h=`${g}.${f}`,E=(u.get(h)??0)+1;u.set(h,E),p.set(m.id,`${g}.${f}.${E}`)}return{byId:p}}function Bb(e){return{table:e!==null?Ub(e):null,originProjectId:e,cache:new Map}}function tn(e,t){let s=e.cache.get(t);if(s)return s;let n=ll(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:ul(n),decimal:r,summary:dl(n.id),project:n.project,started_at:n.started_at};return e.cache.set(t,o),o}function Hb(e,t){let n=_().prepare(`SELECT DISTINCT te.parent_session_id AS pid
768
+ 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 g=m.auto_title.split(" \xB7 "),f=g[0].trim(),h=g.length>1?g.slice(1).join(" \xB7 ").trim():null;o.push({id:m.id,brand:h||null,skill:f||null}),h&&n.add(h),f&&r.add(f)}let i=[...n].sort(),a=new Map;i.forEach((m,g)=>a.set(m,g));let d=[...r].sort(),l=new Map;d.forEach((m,g)=>l.set(m,g));let u=new Map,p=new Map;for(let m of o){if(!m.brand||!m.skill)continue;let g=a.get(m.brand),f=l.get(m.skill);if(g===void 0||f===void 0)continue;let h=`${g}.${f}`,E=(u.get(h)??0)+1;u.set(h,E),p.set(m.id,`${g}.${f}.${E}`)}return{byId:p}}function Vb(e){return{table:e!==null?Kb(e):null,originProjectId:e,cache:new Map}}function nn(e,t){let s=e.cache.get(t);if(s)return s;let n=pl(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:gl(n),decimal:r,summary:ml(n.id),project:n.project,started_at:n.started_at};return e.cache.set(t,o),o}function Zb(e,t){let n=_().prepare(`SELECT DISTINCT te.parent_session_id AS pid
769
769
  FROM thread_edges te
770
770
  WHERE te.session_id = ?
771
- AND te.parent_session_id IS NOT NULL`).all(t),r=[];for(let o of n){if(!o.pid)continue;let i=tn(e,o.pid);i&&r.push(i)}return r}function Wb(e,t){let n=_().prepare(`SELECT DISTINCT te.session_id AS sid
771
+ AND te.parent_session_id IS NOT NULL`).all(t),r=[];for(let o of n){if(!o.pid)continue;let i=nn(e,o.pid);i&&r.push(i)}return r}function Qb(e,t){let n=_().prepare(`SELECT DISTINCT te.session_id AS sid
772
772
  FROM thread_edges te
773
- WHERE te.parent_session_id = ?`).all(t),r=[];for(let o of n){if(!o.sid)continue;let i=tn(e,o.sid);i&&r.push(i)}return r}function pl(e){let t=jb[e.linkType]??.5,s=$t(e.confidence),n=t*s,r=al(e.daysApart),o=e.embeddingCosine??.5,i=$t(e.pagerank);if(e.scoring==="pagerank")return $t(i);if(e.scoring==="embedding-rerank")return e.embeddingCosine===null?$t(n):$t(o);let a=.35*n+.2*r+.2*o+.25*i;return $t(a)}function $t(e){return!Number.isFinite(e)||e<0?0:e>1?1:e}function Xb(e,t,s,n,r){let o=new Map;function i(a,d){if(a===d)return;let l=o.get(a);l||(l=new Set,o.set(a,l)),l.add(d)}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]),d=new Set([e]);for(let l=1;l<r;l++){let u=new Set;for(let p of a){let m=o.get(p);if(m)for(let g of m){if(d.has(g))continue;let f=Xr(g).filter(h=>h.approved);for(let h of f)i(h.source_session_id,h.target_session_id),i(h.target_session_id,h.source_session_id);d.add(g),u.add(g)}}if(u.size===0)break;for(let p of u)a.add(p)}}return{edges:o}}function Jb(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(l=>[l,o]));for(let l=0;l<s;l++){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 g=(i.get(p)??0)/m.size;for(let f of m)u.set(f,(u.get(f)??0)+n*g)}i=u}let a=0;for(let l of i.values())l>a&&(a=l);if(a<=0)return i;let d=new Map;for(let[l,u]of i)d.set(l,u/a);return d}function gl(e,t){let s=e.replace(/\s+/g," ").trim();return s.length<=t?s:`${s.slice(0,t-1).trimEnd()}\u2026`}function Yb(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=gl(e.summary,ml);return`${r}
774
- ${o}`}return r}function Gb(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+=en(a),e.summary){let d=gl(e.summary,ml*4);n.push(d),o+=en(d)}n.push("");for(let d of t){if(d.refs.length===0)continue;let l=`## ${d.heading}`,u=en(l),p=[],m=0;for(let g of d.refs){let f=Yb(g),h=en(f);if(o+u+m+h>s){r.push({session_id:g.session_id,title:g.title,decimal:g.decimal,summary:g.summary,project:g.project,started_at:g.started_at});continue}p.push(f),m+=h}if(p.length>0){n.push(l);for(let g of p)n.push(g);n.push(""),o+=u+m}}for(;n.length>0&&n[n.length-1]==="";)n.pop();return{bundle:n.join(`
773
+ WHERE te.parent_session_id = ?`).all(t),r=[];for(let o of n){if(!o.sid)continue;let i=nn(e,o.sid);i&&r.push(i)}return r}function fl(e){let t=qb[e.linkType]??.5,s=Pt(e.confidence),n=t*s,r=dl(e.daysApart),o=e.embeddingCosine??.5,i=Pt(e.pagerank);if(e.scoring==="pagerank")return Pt(i);if(e.scoring==="embedding-rerank")return e.embeddingCosine===null?Pt(n):Pt(o);let a=.35*n+.2*r+.2*o+.25*i;return Pt(a)}function Pt(e){return!Number.isFinite(e)||e<0?0:e>1?1:e}function eS(e,t,s,n,r){let o=new Map;function i(a,d){if(a===d)return;let l=o.get(a);l||(l=new Set,o.set(a,l)),l.add(d)}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]),d=new Set([e]);for(let l=1;l<r;l++){let u=new Set;for(let p of a){let m=o.get(p);if(m)for(let g of m){if(d.has(g))continue;let f=Gr(g).filter(h=>h.approved);for(let h of f)i(h.source_session_id,h.target_session_id),i(h.target_session_id,h.source_session_id);d.add(g),u.add(g)}}if(u.size===0)break;for(let p of u)a.add(p)}}return{edges:o}}function tS(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(l=>[l,o]));for(let l=0;l<s;l++){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 g=(i.get(p)??0)/m.size;for(let f of m)u.set(f,(u.get(f)??0)+n*g)}i=u}let a=0;for(let l of i.values())l>a&&(a=l);if(a<=0)return i;let d=new Map;for(let[l,u]of i)d.set(l,u/a);return d}function hl(e,t){let s=e.replace(/\s+/g," ").trim();return s.length<=t?s:`${s.slice(0,t-1).trimEnd()}\u2026`}function sS(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=hl(e.summary,_l);return`${r}
774
+ ${o}`}return r}function nS(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+=sn(a),e.summary){let d=hl(e.summary,_l*4);n.push(d),o+=sn(d)}n.push("");for(let d of t){if(d.refs.length===0)continue;let l=`## ${d.heading}`,u=sn(l),p=[],m=0;for(let g of d.refs){let f=sS(g),h=sn(f);if(o+u+m+h>s){r.push({session_id:g.session_id,title:g.title,decimal:g.decimal,summary:g.summary,project:g.project,started_at:g.started_at});continue}p.push(f),m+=h}if(p.length>0){n.push(l);for(let g of p)n.push(g);n.push(""),o+=u+m}}for(;n.length>0&&n[n.length-1]==="";)n.pop();return{bundle:n.join(`
775
775
  `)+`
776
- `,budgetUsed:o,truncated:r}}function zb(e,t,s,n,r,o){let i=[];for(let a of s){if(n&&!n.has(a.link_type))continue;let d=null;if(a.source_session_id===t.session_id?d=a.target_session_id:a.target_session_id===t.session_id&&(d=a.source_session_id),!d)continue;let l=tn(e,d);if(!l)continue;let u=cl(t.started_at,l.started_at),p=pl({confidence:a.confidence,linkType:a.link_type,daysApart:u,embeddingCosine:null,pagerank:o.get(d)??0,scoring:r});i.push({...l,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 sn(e,t={}){let s=Math.max(100,Math.floor(t.budget??Db)),n=t.scoring??"hybrid",r=Math.max(1,Math.min(5,t.maxDepth??$b)),o=t.includeWikiLinks??!0,i=t.includeSuggestions??!1,a=t.edgeTypes?new Set(t.edgeTypes):null,d=ll(e);if(!d)throw new Error(`session not found: ${e}`);let l=Bb(d.project_id),u={session_id:d.id,title:ul(d),decimal:l.table?.byId.get(d.id)??null,summary:dl(d.id),project:d.project,started_at:d.started_at};l.cache.set(d.id,u);let p=Hb(l,e),m=Wb(l,e),g=Xr(e).filter(A=>A.approved).filter(A=>!a||a.has(A.link_type)).filter(A=>o||A.link_type!=="wiki_link"),f=Xb(e,g,p,m,r),h=Jb(f),E=[],b=[],S=[],T=[];for(let A of g){let $=A.source_session_id===e?A.target_session_id:A.source_session_id,j=tn(l,$);if(!j)continue;let y=cl(u.started_at,j.started_at),U=pl({confidence:A.confidence,linkType:A.link_type,daysApart:y,embeddingCosine:null,pagerank:h.get($)??0,scoring:n}),M=al(y),V=`${A.link_type} confidence=${A.confidence.toFixed(2)} recency=${M.toFixed(2)} (${Math.round(y)}d apart)`,Ye={...j,score:U,evidence:V,link_type:A.link_type};A.link_type==="citation"?E.push(Ye):A.link_type==="similar"?b.push(Ye):A.link_type==="wiki_link"?T.push(Ye):S.push(Ye)}if(i){let A=Ks({sourceSessionId:e,status:"pending",limit:100}),$=Ks({targetSessionId:e,status:"pending",limit:100}),j=[...A,...$],y=new Set,U=j.filter(V=>y.has(V.id)?!1:(y.add(V.id),!0)),M=zb(l,u,U,a,n,h);for(let V of M)V.link_type==="citation"?E.push(V):V.link_type==="similar"?b.push(V):V.link_type==="wiki_link"?T.push(V):S.push(V)}let R=(A,$)=>$.score-A.score;E.sort(R),b.sort(R),S.sort(R),T.sort(R);let J=Gb(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:T}],s);return{origin:u,parents:p,children:m,citations:E,similar:b,cousins:S,wikiLinks:T,bundle:J.bundle,budgetUsed:J.budgetUsed,budgetRemaining:Math.max(0,s-J.budgetUsed),truncated:J.truncated}}var Db,$b,Pb,Fb,jb,ml,Zr=N(()=>{"use strict";w();as();Db=4e3,$b=2,Pb=30,Fb=.2,jb={citation:1,wiki_link:.9,similar:.7,skill_track:.5,bug_pattern:.4,temporal_proximity:.3};ml=240});var Sd={};he(Sd,{computeAllHealthScores:()=>wo,computeHealthScore:()=>So,computeHealthScoreByName:()=>yo});function ls(e){return Math.max(0,Math.min(1,e))}function So(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,
776
+ `,budgetUsed:o,truncated:r}}function rS(e,t,s,n,r,o){let i=[];for(let a of s){if(n&&!n.has(a.link_type))continue;let d=null;if(a.source_session_id===t.session_id?d=a.target_session_id:a.target_session_id===t.session_id&&(d=a.source_session_id),!d)continue;let l=nn(e,d);if(!l)continue;let u=ul(t.started_at,l.started_at),p=fl({confidence:a.confidence,linkType:a.link_type,daysApart:u,embeddingCosine:null,pagerank:o.get(d)??0,scoring:r});i.push({...l,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 rn(e,t={}){let s=Math.max(100,Math.floor(t.budget??Jb)),n=t.scoring??"hybrid",r=Math.max(1,Math.min(5,t.maxDepth??Gb)),o=t.includeWikiLinks??!0,i=t.includeSuggestions??!1,a=t.edgeTypes?new Set(t.edgeTypes):null,d=pl(e);if(!d)throw new Error(`session not found: ${e}`);let l=Vb(d.project_id),u={session_id:d.id,title:gl(d),decimal:l.table?.byId.get(d.id)??null,summary:ml(d.id),project:d.project,started_at:d.started_at};l.cache.set(d.id,u);let p=Zb(l,e),m=Qb(l,e),g=Gr(e).filter(A=>A.approved).filter(A=>!a||a.has(A.link_type)).filter(A=>o||A.link_type!=="wiki_link"),f=eS(e,g,p,m,r),h=tS(f),E=[],b=[],S=[],R=[];for(let A of g){let $=A.source_session_id===e?A.target_session_id:A.source_session_id,U=nn(l,$);if(!U)continue;let y=ul(u.started_at,U.started_at),B=fl({confidence:A.confidence,linkType:A.link_type,daysApart:y,embeddingCosine:null,pagerank:h.get($)??0,scoring:n}),M=dl(y),V=`${A.link_type} confidence=${A.confidence.toFixed(2)} recency=${M.toFixed(2)} (${Math.round(y)}d apart)`,Ge={...U,score:B,evidence:V,link_type:A.link_type};A.link_type==="citation"?E.push(Ge):A.link_type==="similar"?b.push(Ge):A.link_type==="wiki_link"?R.push(Ge):S.push(Ge)}if(i){let A=Vs({sourceSessionId:e,status:"pending",limit:100}),$=Vs({targetSessionId:e,status:"pending",limit:100}),U=[...A,...$],y=new Set,B=U.filter(V=>y.has(V.id)?!1:(y.add(V.id),!0)),M=rS(l,u,B,a,n,h);for(let V of M)V.link_type==="citation"?E.push(V):V.link_type==="similar"?b.push(V):V.link_type==="wiki_link"?R.push(V):S.push(V)}let T=(A,$)=>$.score-A.score;E.sort(T),b.sort(T),S.sort(T),R.sort(T);let D=nS(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:R}],s);return{origin:u,parents:p,children:m,citations:E,similar:b,cousins:S,wikiLinks:R,bundle:D.bundle,budgetUsed:D.budgetUsed,budgetRemaining:Math.max(0,s-D.budgetUsed),truncated:D.truncated}}var Jb,Gb,Yb,zb,qb,_l,eo=N(()=>{"use strict";w();as();Jb=4e3,Gb=2,Yb=30,zb=.2,qb={citation:1,wiki_link:.9,similar:.7,skill_track:.5,bug_pattern:.4,temporal_proximity:.3};_l=240});var Td={};he(Td,{computeAllHealthScores:()=>Ro,computeHealthScore:()=>wo,computeHealthScoreByName:()=>To});function ls(e){return Math.max(0,Math.min(1,e))}function wo(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,
777
777
  MAX(started_at) AS latest
778
778
  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=ls(r/10),i=n.latest?(Date.now()-new Date(n.latest).getTime())/(1e3*60*60*24):90,a=ls(1-i/90),l=t.prepare(`SELECT AVG(message_count) AS avg_msgs
779
779
  FROM sessions WHERE project_id = ?`).get(e).avg_msgs??0,u=ls((l-2)/3),p=t.prepare(`SELECT COUNT(*) AS total,
@@ -784,15 +784,15 @@ ${t.message}
784
784
  COUNT(DISTINCT st.session_id) AS tagged
785
785
  FROM sessions s
786
786
  LEFT JOIN session_tags st ON st.session_id = s.id
787
- WHERE s.project_id = ?`).get(e),h=f.total>0?f.tagged/f.total:0,E=ls(h),b=Math.round((o*.2+a*.25+u*.15+g*.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(l*10)/10,score:u,weight:.15},searchCoverage:{ratio:Math.round(m*100)/100,score:g,weight:.2},tagCoverage:{ratio:Math.round(h*100)/100,score:E,weight:.2}}}}function yo(e){let s=_().prepare("SELECT id FROM projects WHERE name = ?").get(e);return s?So(s.id):null}function wo(){let t=_().prepare("SELECT id FROM projects ORDER BY name").all(),s=[];for(let n of t){let r=So(n.id);r&&s.push(r)}return s}var To=N(()=>{"use strict";w()});function Au(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:xt,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 ct(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:[Au(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 lt(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:[Au(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 PT(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 FT(e){return e.toLocaleString("en-US")}function dt(e){return e<1e3?String(e):`${PT(e)} (${FT(e)})`}function ut(e){return new Date(e).toLocaleDateString("en-US",{month:"long",day:"numeric",year:"numeric"})}var xt,us=N(()=>{"use strict";xt="#f97316"});var vu={};he(vu,{render:()=>BT});function yn(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:ps,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:wn,textTransform:"uppercase",letterSpacing:"0.16em"},children:t}}]}}}function BT(e){let s=[ut(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?`+ ${dt(e.cachedTokens)} cached`:null,i=[ct(Ou,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:ps,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"20px",color:wn},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:xt,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:r}},{type:"span",props:{style:{marginTop:"16px",fontSize:"16px",color:wn,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:600},children:"session cost"}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:UT}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[yn(String(e.messageCount),"msgs"),yn(String(e.filesReferenced),"files"),yn(String(e.toolCallCount),"tools"),yn(e.model??"\u2014","model")]}}];return o&&i.push({type:"div",props:{style:{fontSize:"14px",color:wn,fontFamily:"JetBrains Mono",opacity:.7},children:o}}),e.verdict&&i.push({type:"div",props:{style:{display:"flex",fontSize:"24px",fontStyle:"italic",color:ps,borderLeft:`3px solid ${xt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),i.push({type:"div",props:{style:{display:"flex",flex:1}}}),i.push(lt(Ou)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:jT,padding:"64px 72px",fontFamily:"Inter",gap:"28px"},children:i}}}var jT,ps,wn,UT,Ou,Iu=N(()=>{"use strict";us();jT="#1a1b1e",ps="#e7e9ee",wn="#8b9098",UT="#2a2c33",Ou={markStroke:ps,wordmarkFg:ps}});var Du={};he(Du,{render:()=>XT});function Tn(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:ms,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:Rn,fontFamily:"JetBrains Mono",textTransform:"lowercase"},children:`// ${t}`}}]}}}function XT(e){let t=[ut(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),s=e.costDollars??"$\u2014",n=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`# ${dt(e.cachedTokens)} tokens cache-replayed (free)`:null,r=[ct(Mu,"recall.cli/share"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"6px"},children:[{type:"div",props:{style:{fontSize:"18px",color:Do,fontFamily:"JetBrains Mono"},children:"$ recall share --session"}},{type:"div",props:{style:{fontSize:"40px",fontWeight:700,color:ms,lineHeight:1.15,wordBreak:"break-word",fontFamily:"JetBrains Mono"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"18px",color:Rn,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:Rn,fontFamily:"JetBrains Mono"},children:"> total_cost:"}},{type:"span",props:{style:{fontSize:"180px",fontWeight:700,color:Do,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:s}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:WT}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[Tn(String(e.messageCount),"msgs"),Tn(String(e.filesReferenced),"files"),Tn(String(e.toolCallCount),"tools"),Tn(e.model??"\u2014","model")]}}];return n&&r.push({type:"div",props:{style:{fontSize:"14px",color:Rn,fontFamily:"JetBrains Mono",opacity:.7},children:n}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"22px",color:ms,fontFamily:"JetBrains Mono",borderLeft:`3px solid ${Do}`,paddingLeft:"20px",marginTop:"8px"},children:`// ${e.verdict}`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(lt(Mu)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:HT,padding:"64px 72px",fontFamily:"Inter",gap:"28px"},children:r}}}var HT,ms,Rn,WT,Do,Mu,$u=N(()=>{"use strict";us();HT="#0d0d0f",ms="#e1e7ee",Rn="#6b7480",WT="#1f2229",Do="#7ee787",Mu={markStroke:ms,wordmarkFg:ms}});var Fu={};he(Fu,{render:()=>YT});function xn(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:kn,textTransform:"uppercase",letterSpacing:"0.16em",fontWeight:600},children:t}}]}}}function YT(e){let t=[ut(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),s=e.costDollars??"$\u2014",n=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${dt(e.cachedTokens)} cached`:null,r=[ct(Pu,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:kt,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"20px",color:kn},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:kt,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:s}},{type:"span",props:{style:{marginTop:"16px",fontSize:"16px",color:kn,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:600},children:"session cost"}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:JT}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[xn(String(e.messageCount),"msgs"),xn(String(e.filesReferenced),"files"),xn(String(e.toolCallCount),"tools"),xn(e.model??"\u2014","model")]}}];return n&&r.push({type:"div",props:{style:{fontSize:"14px",color:kn,fontFamily:"JetBrains Mono",opacity:.85},children:n}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"24px",fontStyle:"italic",color:kt,borderLeft:`3px solid ${kt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(lt(Pu)),{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 kt,kn,JT,Pu,ju=N(()=>{"use strict";us();kt="#ffffff",kn="rgba(255,255,255,0.7)",JT="rgba(255,255,255,0.18)",Pu={markStroke:kt,wordmarkFg:kt}});var Bu={};he(Bu,{render:()=>VT});function Cn(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:800,color:Ut,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:gs,textTransform:"uppercase",letterSpacing:"0.16em",fontWeight:600},children:t}}]}}}function qT(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:KT,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:gs,fontWeight:600,textTransform:"uppercase",letterSpacing:"0.14em"},children:e.map(s=>({type:"span",props:{style:{display:"flex"},children:`${s.label} \xB7 ${s.value}`}}))}}]}}}function VT(e){let t=[ut(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),s=e.costDollars??"$\u2014",n=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${dt(e.cachedTokens)} cached`:null,r=[ct(Uu,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"40px",fontWeight:700,color:Ut,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"18px",color:gs},children:t}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"flex-start",padding:"8px 0"},children:[{type:"span",props:{style:{fontSize:"14px",color:gs,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:700},children:"session cost"}},{type:"span",props:{style:{fontSize:"180px",fontWeight:800,color:Ut,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:s}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:zT}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[Cn(String(e.messageCount),"msgs"),Cn(String(e.filesReferenced),"files"),Cn(String(e.toolCallCount),"tools"),Cn(e.model??"\u2014","model")]}},qT([{value:e.messageCount,color:xt,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:gs,fontFamily:"JetBrains Mono",opacity:.85},children:n}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"22px",fontStyle:"italic",color:Ut,borderLeft:`3px solid ${xt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(lt(Uu)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:GT,padding:"64px 72px",fontFamily:"Inter",gap:"24px"},children:r}}}var GT,Ut,gs,zT,KT,Uu,Hu=N(()=>{"use strict";us();GT="#f6f7f9",Ut="#0a0a0a",gs="#5a6068",zT="#e3e6eb",KT="#dde1e7",Uu={markStroke:Ut,wordmarkFg:Ut}});var Wu={};he(Wu,{render:()=>eR});function $o(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:Ln},children:t}},{type:"div",props:{style:{fontSize:"16px",color:Ht,textTransform:"uppercase",letterSpacing:"2px"},children:e}}]}}}function Po(e,t){return{type:"div",props:{style:{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"16px 24px",backgroundColor:Fo,borderRadius:"12px"},children:[{type:"span",props:{style:{fontSize:"18px",color:Ht},children:e}},{type:"span",props:{style:{fontSize:"20px",fontWeight:700,color:Ln},children:t}}]}}}function eR(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:Ht,textTransform:"uppercase",letterSpacing:"6px"},children:"YOUR MONTH IN CODE"}},{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:Ln},children:e.month}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"12px",backgroundColor:Fo,borderRadius:"16px",padding:"28px",border:`1px solid ${Bt}40`},children:[{type:"div",props:{style:{fontSize:"16px",color:QT,textTransform:"uppercase",letterSpacing:"2px"},children:"You are a"}},{type:"div",props:{style:{fontSize:"36px",fontWeight:700,color:Bt},children:e.archetype}}]}},{type:"div",props:{style:{display:"flex",gap:"16px",width:"100%"},children:[$o("Recalls",String(e.totalRecalls)),$o("Tokens piped",e.totalTokensPiped>999999?`${(e.totalTokensPiped/1e6).toFixed(1)}M`:e.totalTokensPiped.toLocaleString()),$o("Sessions",String(e.sessionsIndexed))]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px",width:"100%"},children:[{type:"div",props:{style:{fontSize:"14px",color:Ht,textTransform:"uppercase",letterSpacing:"2px",marginBottom:"4px"},children:"Highlights"}},Po("Most recalled",e.mostRecalledSession),Po("Biggest recall",`${e.biggestRecallTokens.toLocaleString()} tokens`),Po("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 ${Bt}`,display:"flex",alignItems:"center",justifyContent:"center"},children:{type:"span",props:{style:{fontSize:"32px",fontWeight:700,color:Bt},children:`${t}`}}}},{type:"div",props:{style:{fontSize:"14px",color:Ht,textTransform:"uppercase",letterSpacing:"2px"},children:"Memory health"}}]}}];return e.verdict&&s.push({type:"div",props:{style:{backgroundColor:Fo,borderLeft:`3px solid ${Bt}`,borderRadius:"8px",padding:"20px 24px",fontSize:"20px",color:Ln,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:Bt},children:"Claude Recall"}},{type:"span",props:{style:{fontSize:"18px",color:Ht},children:"clauderecall.com"}}]}}),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:ZT,padding:"72px 64px",fontFamily:"Inter",gap:"36px"},children:s}}}var ZT,Fo,Ln,Ht,Bt,QT,Xu=N(()=>{"use strict";ZT="#0b0c0f",Fo="#15171c",Ln="#e7e9ee",Ht="#8b9098",Bt="#f97316",QT="#fb923c"});var Wo,rp,z,C,ee,De,op,ip,ap,cp,Xo,Jo,pt=N(()=>{"use strict";Wo=[String.raw` ___ _ _ _ _ ___ ___ ___ ___ ___ _ _ _ `,String.raw` / __| | /_\ | | | | \| __| | _ \ __/ __| /_\ | | | | `,String.raw`| (__| |__ / _ \| |_| | |) | _| | / _| (__ / _ \| |__| |__ `,String.raw` \___|____/_/ \_\\___/|___/|___| |_|_\___\___/_/ \_\____|____|`],rp=Wo[0]?.length??64,z="#f97316",C="#8b9098",ee="#10b981",De="#f59e0b",op="#60a5fa",ip="#34d399",ap="#c084fc",cp="CLAUDE RECALL",Xo=100,Jo=30});import{useEffect as OR,useState as vR}from"react";import{Box as lp,Text as ge}from"ink";import{createRequire as IR}from"node:module";import{existsSync as MR}from"node:fs";import{jsx as oe,jsxs as up}from"react/jsx-runtime";function dp({cols:e}){let[t,s]=vR(PR);OR(()=>{let r=!1,o=Q(),i=0,a=0;if(MR(te))try{let l=_().prepare(`SELECT
787
+ WHERE s.project_id = ?`).get(e),h=f.total>0?f.tagged/f.total:0,E=ls(h),b=Math.round((o*.2+a*.25+u*.15+g*.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(l*10)/10,score:u,weight:.15},searchCoverage:{ratio:Math.round(m*100)/100,score:g,weight:.2},tagCoverage:{ratio:Math.round(h*100)/100,score:E,weight:.2}}}}function To(e){let s=_().prepare("SELECT id FROM projects WHERE name = ?").get(e);return s?wo(s.id):null}function Ro(){let t=_().prepare("SELECT id FROM projects ORDER BY name").all(),s=[];for(let n of t){let r=wo(n.id);r&&s.push(r)}return s}var xo=N(()=>{"use strict";w()});function Iu(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:xt,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 at(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:[Iu(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 ct(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:[Iu(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 YT(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 zT(e){return e.toLocaleString("en-US")}function lt(e){return e<1e3?String(e):`${YT(e)} (${zT(e)})`}function dt(e){return new Date(e).toLocaleDateString("en-US",{month:"long",day:"numeric",year:"numeric"})}var xt,us=N(()=>{"use strict";xt="#f97316"});var Du={};he(Du,{render:()=>VT});function Tn(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:ps,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:Rn,textTransform:"uppercase",letterSpacing:"0.16em"},children:t}}]}}}function VT(e){let s=[dt(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?`+ ${lt(e.cachedTokens)} cached`:null,i=[at(Mu,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:ps,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"20px",color:Rn},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:xt,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:r}},{type:"span",props:{style:{marginTop:"16px",fontSize:"16px",color:Rn,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:600},children:"session cost"}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:KT}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[Tn(String(e.messageCount),"msgs"),Tn(String(e.filesReferenced),"files"),Tn(String(e.toolCallCount),"tools"),Tn(e.model??"\u2014","model")]}}];return o&&i.push({type:"div",props:{style:{fontSize:"14px",color:Rn,fontFamily:"JetBrains Mono",opacity:.7},children:o}}),e.verdict&&i.push({type:"div",props:{style:{display:"flex",fontSize:"24px",fontStyle:"italic",color:ps,borderLeft:`3px solid ${xt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),i.push({type:"div",props:{style:{display:"flex",flex:1}}}),i.push(ct(Mu)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:qT,padding:"64px 72px",fontFamily:"Inter",gap:"28px"},children:i}}}var qT,ps,Rn,KT,Mu,$u=N(()=>{"use strict";us();qT="#1a1b1e",ps="#e7e9ee",Rn="#8b9098",KT="#2a2c33",Mu={markStroke:ps,wordmarkFg:ps}});var Fu={};he(Fu,{render:()=>eR});function xn(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:ms,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:kn,fontFamily:"JetBrains Mono",textTransform:"lowercase"},children:`// ${t}`}}]}}}function eR(e){let t=[dt(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),s=e.costDollars??"$\u2014",n=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`# ${lt(e.cachedTokens)} tokens cache-replayed (free)`:null,r=[at(Pu,"recall.cli/share"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"6px"},children:[{type:"div",props:{style:{fontSize:"18px",color:Po,fontFamily:"JetBrains Mono"},children:"$ recall share --session"}},{type:"div",props:{style:{fontSize:"40px",fontWeight:700,color:ms,lineHeight:1.15,wordBreak:"break-word",fontFamily:"JetBrains Mono"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"18px",color:kn,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:kn,fontFamily:"JetBrains Mono"},children:"> total_cost:"}},{type:"span",props:{style:{fontSize:"180px",fontWeight:700,color:Po,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:s}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:QT}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[xn(String(e.messageCount),"msgs"),xn(String(e.filesReferenced),"files"),xn(String(e.toolCallCount),"tools"),xn(e.model??"\u2014","model")]}}];return n&&r.push({type:"div",props:{style:{fontSize:"14px",color:kn,fontFamily:"JetBrains Mono",opacity:.7},children:n}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"22px",color:ms,fontFamily:"JetBrains Mono",borderLeft:`3px solid ${Po}`,paddingLeft:"20px",marginTop:"8px"},children:`// ${e.verdict}`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(ct(Pu)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:ZT,padding:"64px 72px",fontFamily:"Inter",gap:"28px"},children:r}}}var ZT,ms,kn,QT,Po,Pu,ju=N(()=>{"use strict";us();ZT="#0d0d0f",ms="#e1e7ee",kn="#6b7480",QT="#1f2229",Po="#7ee787",Pu={markStroke:ms,wordmarkFg:ms}});var Bu={};he(Bu,{render:()=>sR});function Cn(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:Ln,textTransform:"uppercase",letterSpacing:"0.16em",fontWeight:600},children:t}}]}}}function sR(e){let t=[dt(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),s=e.costDollars??"$\u2014",n=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${lt(e.cachedTokens)} cached`:null,r=[at(Uu,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:kt,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"20px",color:Ln},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:kt,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:s}},{type:"span",props:{style:{marginTop:"16px",fontSize:"16px",color:Ln,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:600},children:"session cost"}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:tR}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[Cn(String(e.messageCount),"msgs"),Cn(String(e.filesReferenced),"files"),Cn(String(e.toolCallCount),"tools"),Cn(e.model??"\u2014","model")]}}];return n&&r.push({type:"div",props:{style:{fontSize:"14px",color:Ln,fontFamily:"JetBrains Mono",opacity:.85},children:n}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"24px",fontStyle:"italic",color:kt,borderLeft:`3px solid ${kt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(ct(Uu)),{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 kt,Ln,tR,Uu,Hu=N(()=>{"use strict";us();kt="#ffffff",Ln="rgba(255,255,255,0.7)",tR="rgba(255,255,255,0.18)",Uu={markStroke:kt,wordmarkFg:kt}});var Xu={};he(Xu,{render:()=>aR});function Nn(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:800,color:Bt,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:gs,textTransform:"uppercase",letterSpacing:"0.16em",fontWeight:600},children:t}}]}}}function iR(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:oR,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:gs,fontWeight:600,textTransform:"uppercase",letterSpacing:"0.14em"},children:e.map(s=>({type:"span",props:{style:{display:"flex"},children:`${s.label} \xB7 ${s.value}`}}))}}]}}}function aR(e){let t=[dt(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),s=e.costDollars??"$\u2014",n=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${lt(e.cachedTokens)} cached`:null,r=[at(Wu,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"40px",fontWeight:700,color:Bt,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"18px",color:gs},children:t}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"flex-start",padding:"8px 0"},children:[{type:"span",props:{style:{fontSize:"14px",color:gs,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:700},children:"session cost"}},{type:"span",props:{style:{fontSize:"180px",fontWeight:800,color:Bt,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:s}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:rR}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[Nn(String(e.messageCount),"msgs"),Nn(String(e.filesReferenced),"files"),Nn(String(e.toolCallCount),"tools"),Nn(e.model??"\u2014","model")]}},iR([{value:e.messageCount,color:xt,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:gs,fontFamily:"JetBrains Mono",opacity:.85},children:n}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"22px",fontStyle:"italic",color:Bt,borderLeft:`3px solid ${xt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(ct(Wu)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:nR,padding:"64px 72px",fontFamily:"Inter",gap:"24px"},children:r}}}var nR,Bt,gs,rR,oR,Wu,Ju=N(()=>{"use strict";us();nR="#f6f7f9",Bt="#0a0a0a",gs="#5a6068",rR="#e3e6eb",oR="#dde1e7",Wu={markStroke:Bt,wordmarkFg:Bt}});var Gu={};he(Gu,{render:()=>dR});function Fo(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:An},children:t}},{type:"div",props:{style:{fontSize:"16px",color:Wt,textTransform:"uppercase",letterSpacing:"2px"},children:e}}]}}}function jo(e,t){return{type:"div",props:{style:{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"16px 24px",backgroundColor:Uo,borderRadius:"12px"},children:[{type:"span",props:{style:{fontSize:"18px",color:Wt},children:e}},{type:"span",props:{style:{fontSize:"20px",fontWeight:700,color:An},children:t}}]}}}function dR(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:Wt,textTransform:"uppercase",letterSpacing:"6px"},children:"YOUR MONTH IN CODE"}},{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:An},children:e.month}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"12px",backgroundColor:Uo,borderRadius:"16px",padding:"28px",border:`1px solid ${Ht}40`},children:[{type:"div",props:{style:{fontSize:"16px",color:lR,textTransform:"uppercase",letterSpacing:"2px"},children:"You are a"}},{type:"div",props:{style:{fontSize:"36px",fontWeight:700,color:Ht},children:e.archetype}}]}},{type:"div",props:{style:{display:"flex",gap:"16px",width:"100%"},children:[Fo("Recalls",String(e.totalRecalls)),Fo("Tokens piped",e.totalTokensPiped>999999?`${(e.totalTokensPiped/1e6).toFixed(1)}M`:e.totalTokensPiped.toLocaleString()),Fo("Sessions",String(e.sessionsIndexed))]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px",width:"100%"},children:[{type:"div",props:{style:{fontSize:"14px",color:Wt,textTransform:"uppercase",letterSpacing:"2px",marginBottom:"4px"},children:"Highlights"}},jo("Most recalled",e.mostRecalledSession),jo("Biggest recall",`${e.biggestRecallTokens.toLocaleString()} tokens`),jo("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 ${Ht}`,display:"flex",alignItems:"center",justifyContent:"center"},children:{type:"span",props:{style:{fontSize:"32px",fontWeight:700,color:Ht},children:`${t}`}}}},{type:"div",props:{style:{fontSize:"14px",color:Wt,textTransform:"uppercase",letterSpacing:"2px"},children:"Memory health"}}]}}];return e.verdict&&s.push({type:"div",props:{style:{backgroundColor:Uo,borderLeft:`3px solid ${Ht}`,borderRadius:"8px",padding:"20px 24px",fontSize:"20px",color:An,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:Ht},children:"Claude Recall"}},{type:"span",props:{style:{fontSize:"18px",color:Wt},children:"clauderecall.com"}}]}}),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:cR,padding:"72px 64px",fontFamily:"Inter",gap:"36px"},children:s}}}var cR,Uo,An,Wt,Ht,lR,Yu=N(()=>{"use strict";cR="#0b0c0f",Uo="#15171c",An="#e7e9ee",Wt="#8b9098",Ht="#f97316",lR="#fb923c"});var Jo,ap,z,k,te,De,cp,lp,dp,up,Go,Yo,ut=N(()=>{"use strict";Jo=[String.raw` ___ _ _ _ _ ___ ___ ___ ___ ___ _ _ _ `,String.raw` / __| | /_\ | | | | \| __| | _ \ __/ __| /_\ | | | | `,String.raw`| (__| |__ / _ \| |_| | |) | _| | / _| (__ / _ \| |__| |__ `,String.raw` \___|____/_/ \_\\___/|___/|___| |_|_\___\___/_/ \_\____|____|`],ap=Jo[0]?.length??64,z="#f97316",k="#8b9098",te="#10b981",De="#f59e0b",cp="#60a5fa",lp="#34d399",dp="#c084fc",up="CLAUDE RECALL",Go=100,Yo=30});import{useEffect as BR,useState as HR}from"react";import{Box as pp,Text as ge}from"ink";import{createRequire as WR}from"node:module";import{existsSync as XR}from"node:fs";import{jsx as ie,jsxs as gp}from"react/jsx-runtime";function mp({cols:e}){let[t,s]=HR(YR);BR(()=>{let r=!1,o=Q(),i=0,a=0;if(XR(se))try{let l=_().prepare(`SELECT
788
788
  (SELECT COUNT(*) FROM sessions) AS sessions,
789
- (SELECT COUNT(*) FROM projects) AS projects`).get();i=l.sessions,a=l.projects}catch{}return s(d=>({...d,daemon:o,sessions:i,projects:a})),Te().then(d=>{r||s(l=>({...l,tier:d.tier}))}).catch(()=>{}),()=>{r=!0}},[]);let n=e>=rp+2;return up(lp,{flexDirection:"column",children:[n?Wo.map((r,o)=>oe(ge,{color:z,bold:!0,children:r},o)):oe(ge,{color:z,bold:!0,children:cp}),oe(FR,{state:t})]})}function FR({state:e}){let t=oe(ge,{color:C,children:" \xB7 "});return up(lp,{children:[oe(ge,{color:C,children:"v"}),oe(ge,{color:z,children:$R}),t,oe(ge,{color:C,children:"daemon: "}),e.daemon?oe(ge,{color:ee,children:`running 127.0.0.1:${e.daemon.port}`}):oe(ge,{color:De,children:"stopped"}),t,oe(ge,{color:C,children:"sessions: "}),oe(ge,{color:z,children:e.sessions}),e.projects>0?oe(ge,{color:C,children:` across ${e.projects} ${e.projects===1?"project":"projects"}`}):null,t,oe(ge,{color:C,children:"license: "}),e.tier==="pro"?oe(ge,{color:ee,children:"Pro"}):oe(ge,{color:C,children:"Free"})]})}var DR,$R,PR,pp=N(()=>{"use strict";Ke();D();w();le();pt();DR=IR(import.meta.url),$R=DR("../../../package.json").version,PR={daemon:null,sessions:0,projects:0,tier:"free"}});import{Box as Qe,Text as ie}from"ink";import{jsx as K,jsxs as On}from"react/jsx-runtime";function UR(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 mt(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 mp({sessions:e,total:t,selected:s,width:n,height:r,loading:o,dbExists:i,filter:a,sortMode:d,groupByProject:l}){let u=Math.max(20,n-2),g=Math.max(1,r-1-1-2),f=UR(s,e.length,g),h=e.slice(f.start,f.end);if(!i)return On(Qe,{flexDirection:"column",width:n,height:r,borderStyle:"round",borderColor:C,children:[K(ie,{color:z,bold:!0,children:" Sessions "}),K(Qe,{paddingX:1,paddingY:1,children:K(ie,{color:C,wrap:"wrap",children:"No sessions indexed yet. Quit (q) and run `recall index` first."})})]});let S=[jR[d],l?"grouped":""].filter(Boolean).join(" \xB7 "),T=o?" Sessions \xB7 loading\u2026 ":a?` Sessions \xB7 ${e.length} of ${t} match "${mt(a,18)}" \xB7 ${S} `:` Sessions \xB7 ${e.length} of ${t} \xB7 ${S} `,R=null;return l&&f.start>0&&(R=e[f.start-1]?.project_name??null),On(Qe,{flexDirection:"column",width:n,height:r,borderStyle:"round",borderColor:C,children:[K(Qe,{width:u+2,paddingLeft:1,children:K(ie,{color:z,bold:!0,children:mt(T,u)})}),K(Qe,{flexDirection:"column",flexGrow:1,paddingX:1,children:h.length===0?K(ie,{color:C,children:a?"no matches.":"no sessions."}):h.flatMap((k,J)=>{let A=f.start+J,$=A===s,j=[];return l&&k.project_name!==R&&(j.push(K(HR,{project:k.project_name,width:u},`hdr-${k.project_name}-${A}`)),R=k.project_name),j.push(K(BR,{session:k,width:u,isSelected:$,indented:l},k.id)),j})}),K(Qe,{width:u+2,paddingLeft:1,children:K(ie,{color:C,children:e.length>0?mt(` ${s+1} / ${e.length}${f.end<e.length?" \xB7 scroll for more":""} `,u):""})})]})}function BR({session:e,width:t,isSelected:s,indented:n}){let r=X(e.started_at)||"",o=n?" ":"",i=s?"\u258C ":" ";if(n){let g=e.alias||e.auto_title||e.first_user_message||"(no title)",f=Math.min(14,Math.max(6,Math.floor(t*.25))),h=Math.max(10,t-i.length-o.length-f-1),E=mt(g,h),b=mt(r,f),S=Math.max(1,t-i.length-o.length-E.length-b.length);return On(Qe,{children:[K(ie,{children:o}),K(ie,{color:s?z:C,bold:s,children:i}),K(ie,{color:s?z:"#fefce8",bold:s,children:E}),K(ie,{children:" ".repeat(S)}),K(ie,{color:C,children:b})]})}let a=e.project_name||"?",d=Math.min(28,Math.floor(t*.7)),l=Math.min(14,t-d-i.length-1),u=mt(a,d),p=mt(r,l),m=Math.max(1,t-i.length-u.length-p.length);return On(Qe,{children:[K(ie,{color:s?z:C,bold:s,children:i}),K(ie,{color:s?z:"#67e8f9",bold:s,children:u}),K(ie,{children:" ".repeat(m)}),K(ie,{color:C,children:p})]})}function HR({project:e,width:t}){return K(Qe,{children:K(ie,{color:"#67e8f9",bold:!0,children:mt(`\u25BE ${e}`,t)})})}var jR,gp=N(()=>{"use strict";v();pt();jR={recent:"recent",longest:"longest",busiest:"busiest project"}});import{useEffect as WR,useState as Yo}from"react";function fp(e,t,s){let n=s?"":"AND is_sidechain = 0";return e.prepare(`SELECT uuid, role, type, timestamp, content_text
789
+ (SELECT COUNT(*) FROM projects) AS projects`).get();i=l.sessions,a=l.projects}catch{}return s(d=>({...d,daemon:o,sessions:i,projects:a})),Te().then(d=>{r||s(l=>({...l,tier:d.tier}))}).catch(()=>{}),()=>{r=!0}},[]);let n=e>=ap+2;return gp(pp,{flexDirection:"column",children:[n?Jo.map((r,o)=>ie(ge,{color:z,bold:!0,children:r},o)):ie(ge,{color:z,bold:!0,children:up}),ie(zR,{state:t})]})}function zR({state:e}){let t=ie(ge,{color:k,children:" \xB7 "});return gp(pp,{children:[ie(ge,{color:k,children:"v"}),ie(ge,{color:z,children:GR}),t,ie(ge,{color:k,children:"daemon: "}),e.daemon?ie(ge,{color:te,children:`running 127.0.0.1:${e.daemon.port}`}):ie(ge,{color:De,children:"stopped"}),t,ie(ge,{color:k,children:"sessions: "}),ie(ge,{color:z,children:e.sessions}),e.projects>0?ie(ge,{color:k,children:` across ${e.projects} ${e.projects===1?"project":"projects"}`}):null,t,ie(ge,{color:k,children:"license: "}),e.tier==="pro"?ie(ge,{color:te,children:"Pro"}):ie(ge,{color:k,children:"Free"})]})}var JR,GR,YR,fp=N(()=>{"use strict";qe();P();w();de();ut();JR=WR(import.meta.url),GR=JR("../../../package.json").version,YR={daemon:null,sessions:0,projects:0,tier:"free"}});import{Box as et,Text as ae}from"ink";import{jsx as q,jsxs as In}from"react/jsx-runtime";function KR(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 pt(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 _p({sessions:e,total:t,selected:s,width:n,height:r,loading:o,dbExists:i,filter:a,sortMode:d,groupByProject:l}){let u=Math.max(20,n-2),g=Math.max(1,r-1-1-2),f=KR(s,e.length,g),h=e.slice(f.start,f.end);if(!i)return In(et,{flexDirection:"column",width:n,height:r,borderStyle:"round",borderColor:k,children:[q(ae,{color:z,bold:!0,children:" Sessions "}),q(et,{paddingX:1,paddingY:1,children:q(ae,{color:k,wrap:"wrap",children:"No sessions indexed yet. Quit (q) and run `recall index` first."})})]});let S=[qR[d],l?"grouped":""].filter(Boolean).join(" \xB7 "),R=o?" Sessions \xB7 loading\u2026 ":a?` Sessions \xB7 ${e.length} of ${t} match "${pt(a,18)}" \xB7 ${S} `:` Sessions \xB7 ${e.length} of ${t} \xB7 ${S} `,T=null;return l&&f.start>0&&(T=e[f.start-1]?.project_name??null),In(et,{flexDirection:"column",width:n,height:r,borderStyle:"round",borderColor:k,children:[q(et,{width:u+2,paddingLeft:1,children:q(ae,{color:z,bold:!0,children:pt(R,u)})}),q(et,{flexDirection:"column",flexGrow:1,paddingX:1,children:h.length===0?q(ae,{color:k,children:a?"no matches.":"no sessions."}):h.flatMap((L,D)=>{let A=f.start+D,$=A===s,U=[];return l&&L.project_name!==T&&(U.push(q(ZR,{project:L.project_name,width:u},`hdr-${L.project_name}-${A}`)),T=L.project_name),U.push(q(VR,{session:L,width:u,isSelected:$,indented:l},L.id)),U})}),q(et,{width:u+2,paddingLeft:1,children:q(ae,{color:k,children:e.length>0?pt(` ${s+1} / ${e.length}${f.end<e.length?" \xB7 scroll for more":""} `,u):""})})]})}function VR({session:e,width:t,isSelected:s,indented:n}){let r=J(e.started_at)||"",o=n?" ":"",i=s?"\u258C ":" ";if(n){let g=e.alias||e.auto_title||e.first_user_message||"(no title)",f=Math.min(14,Math.max(6,Math.floor(t*.25))),h=Math.max(10,t-i.length-o.length-f-1),E=pt(g,h),b=pt(r,f),S=Math.max(1,t-i.length-o.length-E.length-b.length);return In(et,{children:[q(ae,{children:o}),q(ae,{color:s?z:k,bold:s,children:i}),q(ae,{color:s?z:"#fefce8",bold:s,children:E}),q(ae,{children:" ".repeat(S)}),q(ae,{color:k,children:b})]})}let a=e.project_name||"?",d=Math.min(28,Math.floor(t*.7)),l=Math.min(14,t-d-i.length-1),u=pt(a,d),p=pt(r,l),m=Math.max(1,t-i.length-u.length-p.length);return In(et,{children:[q(ae,{color:s?z:k,bold:s,children:i}),q(ae,{color:s?z:"#67e8f9",bold:s,children:u}),q(ae,{children:" ".repeat(m)}),q(ae,{color:k,children:p})]})}function ZR({project:e,width:t}){return q(et,{children:q(ae,{color:"#67e8f9",bold:!0,children:pt(`\u25BE ${e}`,t)})})}var qR,hp=N(()=>{"use strict";v();ut();qR={recent:"recent",longest:"longest",busiest:"busiest project"}});import{useEffect as QR,useState as zo}from"react";function Ep(e,t,s){let n=s?"":"AND is_sidechain = 0";return e.prepare(`SELECT uuid, role, type, timestamp, content_text
790
790
  FROM messages
791
791
  WHERE session_id = @id
792
792
  ${n}
793
793
  ORDER BY timestamp DESC
794
- LIMIT @limit`).all({id:t,limit:XR})}function _p(e){let[t,s]=Yo([]),[n,r]=Yo(!1),[o,i]=Yo(!1);return WR(()=>{if(!e){s([]),i(!1);return}r(!0);try{let a=_(),d=fp(a,e,!1),l=!1;d.length===0&&(d=fp(a,e,!0),l=d.length>0),s([...d].reverse()),i(l)}catch{s([]),i(!1)}finally{r(!1)}},[e]),{messages:t,loading:n,fallbackToSidechain:o}}var XR,hp=N(()=>{"use strict";w();XR=6});import{Box as $e,Text as Xe}from"ink";import{Fragment as zR,jsx as Z,jsxs as Xt}from"react/jsx-runtime";function JR(e){let t=(e.role??"").toLowerCase();return t==="user"?{label:"user",color:op}:t==="assistant"?{label:"asst",color:ip}:t==="tool"?{label:"tool",color:ap}:t==="system"?{label:"sys ",color:C}:e.type==="summary"?{label:"sum ",color:C}:{label:"----",color:C}}function YR(e,t){return e?e.replace(/\s+/g," ").trim().slice(0,t+1).replace(/.{1}$/,s=>e.length>t?"\u2026":s):"(empty)"}function Ep({session:e,width:t,height:s}){let n=e?.id??null,{messages:r,loading:o,fallbackToSidechain:i}=_p(n),a=Math.max(20,t-2),l=Math.max(4,s-2-2),u=Math.max(2,Math.floor(l/Math.max(1,r.length)));return e?Xt($e,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:C,children:[Xt($e,{paddingX:1,flexDirection:"column",children:[Z($e,{width:a,children:Z(Xe,{color:z,bold:!0,wrap:"truncate-end",children:e.alias||e.auto_title||e.first_user_message||"(no title)"})}),Z($e,{width:a,children:Z(Xe,{color:C,wrap:"truncate-end",children:`${e.id.slice(0,8)} \xB7 ${e.message_count} msgs \xB7 ${X(e.started_at)}`})})]}),Z($e,{flexDirection:"column",paddingX:1,flexGrow:1,children:o?Z(Xe,{color:C,children:"loading messages\u2026"}):r.length===0?Z(Xe,{color:C,children:"no messages indexed for this session."}):Xt(zR,{children:[i?Z(Xe,{color:C,children:"(showing sidechain / subagent messages)"}):null,r.map(p=>Z(GR,{message:p,width:a,perMessageLines:u},p.uuid))]})})]}):Xt($e,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:C,children:[Z($e,{paddingX:1,children:Z(Xe,{color:z,bold:!0,children:"Preview"})}),Z($e,{paddingX:1,paddingY:1,children:Z(Xe,{color:C,children:"Select a session on the left to preview."})})]})}function GR({message:e,width:t,perMessageLines:s}){let n=JR(e),r=Math.max(1,s-1),o=Math.max(20,t-2),i=r*o,a=YR(e.content_text,i);return Xt($e,{flexDirection:"column",marginBottom:0,children:[Xt($e,{children:[Z(Xe,{color:n.color,bold:!0,children:n.label}),Z(Xe,{color:C,children:` ${e.timestamp?X(e.timestamp):""}`})]}),Z($e,{width:t,children:Z(Xe,{wrap:"truncate-end",children:a})})]})}var bp=N(()=>{"use strict";v();hp();pt()});import{useMemo as KR}from"react";import{Box as Pe,Text as gt}from"ink";import{jsx as fe,jsxs as fs}from"react/jsx-runtime";function qR(e,t){try{return{ok:!0,result:sn(e,{budget:t})}}catch(s){return{ok:!1,error:s instanceof Error?s.message:String(s)}}}function Sp({session:e,width:t,height:s,budget:n}){let r=KR(()=>e?qR(e.id,n):null,[e?.id,n]),o=Math.max(20,t-2),a=Math.max(4,s-2-2);if(!e)return fs(Pe,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:C,children:[fe(Pe,{paddingX:1,children:fe(gt,{color:z,bold:!0,children:"Neighborhood"})}),fe(Pe,{paddingX:1,paddingY:1,children:fe(gt,{color:C,children:"Select a session and press `n` to assemble its neighborhood."})})]});if(!r)return null;if(!r.ok)return fs(Pe,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:De,children:[fe(Pe,{paddingX:1,children:fe(gt,{color:De,bold:!0,children:"Neighborhood error"})}),fe(Pe,{paddingX:1,paddingY:1,children:fe(gt,{color:De,children:r.error})})]});let{result:d}=r,l=d.bundle.replace(/\n+$/,"").split(`
795
- `),u=l.slice(0,Math.max(1,a-1)),p=l.length-u.length;return fs(Pe,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:ee,children:[fs(Pe,{paddingX:1,flexDirection:"column",children:[fe(Pe,{width:o,children:fe(gt,{color:ee,bold:!0,wrap:"truncate-end",children:"Neighborhood"})}),fe(Pe,{width:o,children:fe(gt,{color:C,wrap:"truncate-end",children:`budget=${n} used=${d.budgetUsed} remaining=${d.budgetRemaining} truncated=${d.truncated.length}`})})]}),fs(Pe,{flexDirection:"column",paddingX:1,flexGrow:1,children:[u.map((m,g)=>fe(gt,{wrap:"truncate-end",children:m||" "},g)),p>0?fe(gt,{color:C,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 yp=N(()=>{"use strict";Zr();pt()});import{useEffect as VR,useState as wp}from"react";import{Box as _s,Text as ft}from"ink";import Go from"ink-text-input";import{jsx as Se,jsxs as zo}from"react/jsx-runtime";function Tp({mode:e,query:t,onQueryChange:s,onSearchSubmit:n,onAliasSubmit:r,onTagSubmit:o,aliasInitial:i,toast:a}){let[d,l]=wp(""),[u,p]=wp("");return VR(()=>{e==="alias"&&l(i),e==="tag"&&p("")},[e,i]),a&&e==="normal"?Se(_s,{children:Se(ft,{color:De,children:`\u25B6 ${a}`})}):e==="search"?zo(_s,{children:[Se(ft,{color:z,bold:!0,children:"/ "}),Se(Go,{value:t,onChange:s,onSubmit:n,placeholder:"filter sessions by project, alias, or opening message..."}),Se(ft,{color:C,children:" esc clear \xB7 enter confirm"})]}):e==="alias"?zo(_s,{children:[Se(ft,{color:ee,bold:!0,children:"alias \u203A "}),Se(Go,{value:d,onChange:l,onSubmit:m=>r(m),placeholder:"terminal-tab name for this session"}),Se(ft,{color:C,children:" esc cancel \xB7 enter save"})]}):e==="tag"?zo(_s,{children:[Se(ft,{color:ee,bold:!0,children:"tag \u203A "}),Se(Go,{value:u,onChange:p,onSubmit:m=>o(m),placeholder:"add a tag to this session"}),Se(ft,{color:C,children:" esc cancel \xB7 enter save"})]}):Se(_s,{children:Se(ft,{color:C,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 Rp=N(()=>{"use strict";pt()});import{Box as _e,Text as H}from"ink";import{jsx as F,jsxs as ye}from"react/jsx-runtime";function xp({width:e,height:t}){return ye(_e,{flexDirection:"column",width:e,height:t,borderStyle:"round",borderColor:z,paddingX:2,paddingY:1,children:[ye(_e,{children:[F(H,{color:z,bold:!0,children:"Claude Recall TUI \u2014 Help"}),F(H,{color:C,children:" \xB7 press ? or esc to close"})]}),ye(_e,{marginTop:1,flexDirection:"column",children:[F(H,{color:ee,bold:!0,children:"Navigation"}),ZR.map(s=>F(Ko,{row:s},s.key))]}),ye(_e,{marginTop:1,flexDirection:"column",children:[F(H,{color:ee,bold:!0,children:"Actions on the selected session"}),QR.map(s=>F(Ko,{row:s},s.key))]}),ye(_e,{marginTop:1,flexDirection:"column",children:[F(H,{color:ee,bold:!0,children:"Right-pane views"}),e0.map(s=>F(Ko,{row:s},s.key))]}),ye(_e,{marginTop:1,flexDirection:"column",children:[F(H,{color:ee,bold:!0,children:"What is Neighborhood?"}),F(H,{color:C,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."})]}),ye(_e,{marginTop:1,flexDirection:"column",children:[F(H,{color:ee,bold:!0,children:"Maintenance & diagnostics"}),F(H,{color:C,wrap:"wrap",children:"Two commands cover everything. Quit the TUI with `q` first, then:"}),ye(_e,{marginTop:1,children:[F(H,{color:C,children:" \u2022 "}),F(H,{children:"recall doctor"})]}),F(H,{color:C,wrap:"wrap",children:" Health report: DB size, WAL, FTS fragmentation, integrity, disk free."}),F(H,{color:C,wrap:"wrap",children:" Run this first if anything feels slow or wrong. Add --json for machine output."}),ye(_e,{marginTop:1,children:[F(H,{color:C,children:" \u2022 "}),F(H,{children:"recall optimize"})]}),F(H,{color:C,wrap:"wrap",children:" Maintenance: WAL truncate + FTS5 merge + planner stats. Safe while daemon is running."}),F(H,{color:C,wrap:"wrap",children:" Add --vacuum (with daemon stopped) to also reclaim disk pages from deleted rows."})]}),ye(_e,{marginTop:1,flexDirection:"column",children:[F(H,{color:ee,bold:!0,children:"How to pipe a session into Claude"}),F(H,{color:C,wrap:"wrap",children:"Two recipes. Both work in any shell \u2014 exit this TUI with `q` first, then run them."}),ye(_e,{marginTop:1,children:[F(H,{color:C,children:" 1. "}),F(H,{children:"recall context <id> | claude"})]}),F(H,{color:C,wrap:"wrap",children:" Pipes one session's full transcript as markdown into a fresh `claude` chat."}),F(H,{color:C,wrap:"wrap",children:" Use when you want to continue exactly where one session left off."}),ye(_e,{marginTop:1,children:[F(H,{color:C,children:" 2. "}),F(H,{children:"recall neighborhood <id> | claude"})]}),F(H,{color:C,wrap:"wrap",children:" Pipes the bundle (parents + children + citations + similar + bug matches)."}),F(H,{color:C,wrap:"wrap",children:" Use when you want broader context, not just one transcript."})]})]})}function Ko({row:e}){return ye(_e,{children:[F(_e,{width:16,children:F(H,{color:z,children:e.key})}),F(H,{color:C,wrap:"truncate-end",children:e.description})]})}var ZR,QR,e0,kp=N(()=>{"use strict";pt();ZR=[{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"}],QR=[{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)"}],e0=[{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 t0,useMemo as s0,useState as vn}from"react";import{existsSync as n0}from"node:fs";function Cp(e){let[t,s]=vn([]),[n,r]=vn(!0),[o,i]=vn(null),[a,d]=vn(!0);return t0(()=>{if(!n0(te)){d(!1),r(!1);return}try{let p=_().prepare(`SELECT s.id, p.name AS project_name, s.started_at,
794
+ LIMIT @limit`).all({id:t,limit:e0})}function bp(e){let[t,s]=zo([]),[n,r]=zo(!1),[o,i]=zo(!1);return QR(()=>{if(!e){s([]),i(!1);return}r(!0);try{let a=_(),d=Ep(a,e,!1),l=!1;d.length===0&&(d=Ep(a,e,!0),l=d.length>0),s([...d].reverse()),i(l)}catch{s([]),i(!1)}finally{r(!1)}},[e]),{messages:t,loading:n,fallbackToSidechain:o}}var e0,Sp=N(()=>{"use strict";w();e0=6});import{Box as $e,Text as Xe}from"ink";import{Fragment as r0,jsx as Z,jsxs as Jt}from"react/jsx-runtime";function t0(e){let t=(e.role??"").toLowerCase();return t==="user"?{label:"user",color:cp}:t==="assistant"?{label:"asst",color:lp}:t==="tool"?{label:"tool",color:dp}:t==="system"?{label:"sys ",color:k}:e.type==="summary"?{label:"sum ",color:k}:{label:"----",color:k}}function s0(e,t){return e?e.replace(/\s+/g," ").trim().slice(0,t+1).replace(/.{1}$/,s=>e.length>t?"\u2026":s):"(empty)"}function yp({session:e,width:t,height:s}){let n=e?.id??null,{messages:r,loading:o,fallbackToSidechain:i}=bp(n),a=Math.max(20,t-2),l=Math.max(4,s-2-2),u=Math.max(2,Math.floor(l/Math.max(1,r.length)));return e?Jt($e,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:k,children:[Jt($e,{paddingX:1,flexDirection:"column",children:[Z($e,{width:a,children:Z(Xe,{color:z,bold:!0,wrap:"truncate-end",children:e.alias||e.auto_title||e.first_user_message||"(no title)"})}),Z($e,{width:a,children:Z(Xe,{color:k,wrap:"truncate-end",children:`${e.id.slice(0,8)} \xB7 ${e.message_count} msgs \xB7 ${J(e.started_at)}`})})]}),Z($e,{flexDirection:"column",paddingX:1,flexGrow:1,children:o?Z(Xe,{color:k,children:"loading messages\u2026"}):r.length===0?Z(Xe,{color:k,children:"no messages indexed for this session."}):Jt(r0,{children:[i?Z(Xe,{color:k,children:"(showing sidechain / subagent messages)"}):null,r.map(p=>Z(n0,{message:p,width:a,perMessageLines:u},p.uuid))]})})]}):Jt($e,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:k,children:[Z($e,{paddingX:1,children:Z(Xe,{color:z,bold:!0,children:"Preview"})}),Z($e,{paddingX:1,paddingY:1,children:Z(Xe,{color:k,children:"Select a session on the left to preview."})})]})}function n0({message:e,width:t,perMessageLines:s}){let n=t0(e),r=Math.max(1,s-1),o=Math.max(20,t-2),i=r*o,a=s0(e.content_text,i);return Jt($e,{flexDirection:"column",marginBottom:0,children:[Jt($e,{children:[Z(Xe,{color:n.color,bold:!0,children:n.label}),Z(Xe,{color:k,children:` ${e.timestamp?J(e.timestamp):""}`})]}),Z($e,{width:t,children:Z(Xe,{wrap:"truncate-end",children:a})})]})}var wp=N(()=>{"use strict";v();Sp();ut()});import{useMemo as o0}from"react";import{Box as Pe,Text as mt}from"ink";import{jsx as fe,jsxs as fs}from"react/jsx-runtime";function i0(e,t){try{return{ok:!0,result:rn(e,{budget:t})}}catch(s){return{ok:!1,error:s instanceof Error?s.message:String(s)}}}function Tp({session:e,width:t,height:s,budget:n}){let r=o0(()=>e?i0(e.id,n):null,[e?.id,n]),o=Math.max(20,t-2),a=Math.max(4,s-2-2);if(!e)return fs(Pe,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:k,children:[fe(Pe,{paddingX:1,children:fe(mt,{color:z,bold:!0,children:"Neighborhood"})}),fe(Pe,{paddingX:1,paddingY:1,children:fe(mt,{color:k,children:"Select a session and press `n` to assemble its neighborhood."})})]});if(!r)return null;if(!r.ok)return fs(Pe,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:De,children:[fe(Pe,{paddingX:1,children:fe(mt,{color:De,bold:!0,children:"Neighborhood error"})}),fe(Pe,{paddingX:1,paddingY:1,children:fe(mt,{color:De,children:r.error})})]});let{result:d}=r,l=d.bundle.replace(/\n+$/,"").split(`
795
+ `),u=l.slice(0,Math.max(1,a-1)),p=l.length-u.length;return fs(Pe,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:te,children:[fs(Pe,{paddingX:1,flexDirection:"column",children:[fe(Pe,{width:o,children:fe(mt,{color:te,bold:!0,wrap:"truncate-end",children:"Neighborhood"})}),fe(Pe,{width:o,children:fe(mt,{color:k,wrap:"truncate-end",children:`budget=${n} used=${d.budgetUsed} remaining=${d.budgetRemaining} truncated=${d.truncated.length}`})})]}),fs(Pe,{flexDirection:"column",paddingX:1,flexGrow:1,children:[u.map((m,g)=>fe(mt,{wrap:"truncate-end",children:m||" "},g)),p>0?fe(mt,{color:k,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 Rp=N(()=>{"use strict";eo();ut()});import{useEffect as a0,useState as xp}from"react";import{Box as _s,Text as gt}from"ink";import qo from"ink-text-input";import{jsx as Se,jsxs as Ko}from"react/jsx-runtime";function kp({mode:e,query:t,onQueryChange:s,onSearchSubmit:n,onAliasSubmit:r,onTagSubmit:o,aliasInitial:i,toast:a}){let[d,l]=xp(""),[u,p]=xp("");return a0(()=>{e==="alias"&&l(i),e==="tag"&&p("")},[e,i]),a&&e==="normal"?Se(_s,{children:Se(gt,{color:De,children:`\u25B6 ${a}`})}):e==="search"?Ko(_s,{children:[Se(gt,{color:z,bold:!0,children:"/ "}),Se(qo,{value:t,onChange:s,onSubmit:n,placeholder:"filter sessions by project, alias, or opening message..."}),Se(gt,{color:k,children:" esc clear \xB7 enter confirm"})]}):e==="alias"?Ko(_s,{children:[Se(gt,{color:te,bold:!0,children:"alias \u203A "}),Se(qo,{value:d,onChange:l,onSubmit:m=>r(m),placeholder:"terminal-tab name for this session"}),Se(gt,{color:k,children:" esc cancel \xB7 enter save"})]}):e==="tag"?Ko(_s,{children:[Se(gt,{color:te,bold:!0,children:"tag \u203A "}),Se(qo,{value:u,onChange:p,onSubmit:m=>o(m),placeholder:"add a tag to this session"}),Se(gt,{color:k,children:" esc cancel \xB7 enter save"})]}):Se(_s,{children:Se(gt,{color:k,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 Cp=N(()=>{"use strict";ut()});import{Box as _e,Text as W}from"ink";import{jsx as j,jsxs as ye}from"react/jsx-runtime";function Lp({width:e,height:t}){return ye(_e,{flexDirection:"column",width:e,height:t,borderStyle:"round",borderColor:z,paddingX:2,paddingY:1,children:[ye(_e,{children:[j(W,{color:z,bold:!0,children:"Claude Recall TUI \u2014 Help"}),j(W,{color:k,children:" \xB7 press ? or esc to close"})]}),ye(_e,{marginTop:1,flexDirection:"column",children:[j(W,{color:te,bold:!0,children:"Navigation"}),c0.map(s=>j(Vo,{row:s},s.key))]}),ye(_e,{marginTop:1,flexDirection:"column",children:[j(W,{color:te,bold:!0,children:"Actions on the selected session"}),l0.map(s=>j(Vo,{row:s},s.key))]}),ye(_e,{marginTop:1,flexDirection:"column",children:[j(W,{color:te,bold:!0,children:"Right-pane views"}),d0.map(s=>j(Vo,{row:s},s.key))]}),ye(_e,{marginTop:1,flexDirection:"column",children:[j(W,{color:te,bold:!0,children:"What is Neighborhood?"}),j(W,{color:k,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."})]}),ye(_e,{marginTop:1,flexDirection:"column",children:[j(W,{color:te,bold:!0,children:"Maintenance & diagnostics"}),j(W,{color:k,wrap:"wrap",children:"Two commands cover everything. Quit the TUI with `q` first, then:"}),ye(_e,{marginTop:1,children:[j(W,{color:k,children:" \u2022 "}),j(W,{children:"recall doctor"})]}),j(W,{color:k,wrap:"wrap",children:" Health report: DB size, WAL, FTS fragmentation, integrity, disk free."}),j(W,{color:k,wrap:"wrap",children:" Run this first if anything feels slow or wrong. Add --json for machine output."}),ye(_e,{marginTop:1,children:[j(W,{color:k,children:" \u2022 "}),j(W,{children:"recall optimize"})]}),j(W,{color:k,wrap:"wrap",children:" Maintenance: WAL truncate + FTS5 merge + planner stats. Safe while daemon is running."}),j(W,{color:k,wrap:"wrap",children:" Add --vacuum (with daemon stopped) to also reclaim disk pages from deleted rows."})]}),ye(_e,{marginTop:1,flexDirection:"column",children:[j(W,{color:te,bold:!0,children:"How to pipe a session into Claude"}),j(W,{color:k,wrap:"wrap",children:"Two recipes. Both work in any shell \u2014 exit this TUI with `q` first, then run them."}),ye(_e,{marginTop:1,children:[j(W,{color:k,children:" 1. "}),j(W,{children:"recall context <id> | claude"})]}),j(W,{color:k,wrap:"wrap",children:" Pipes one session's full transcript as markdown into a fresh `claude` chat."}),j(W,{color:k,wrap:"wrap",children:" Use when you want to continue exactly where one session left off."}),ye(_e,{marginTop:1,children:[j(W,{color:k,children:" 2. "}),j(W,{children:"recall neighborhood <id> | claude"})]}),j(W,{color:k,wrap:"wrap",children:" Pipes the bundle (parents + children + citations + similar + bug matches)."}),j(W,{color:k,wrap:"wrap",children:" Use when you want broader context, not just one transcript."})]})]})}function Vo({row:e}){return ye(_e,{children:[j(_e,{width:16,children:j(W,{color:z,children:e.key})}),j(W,{color:k,wrap:"truncate-end",children:e.description})]})}var c0,l0,d0,Np=N(()=>{"use strict";ut();c0=[{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"}],l0=[{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)"}],d0=[{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 u0,useMemo as p0,useState as Mn}from"react";import{existsSync as m0}from"node:fs";function Ap(e){let[t,s]=Mn([]),[n,r]=Mn(!0),[o,i]=Mn(null),[a,d]=Mn(!0);return u0(()=>{if(!m0(se)){d(!1),r(!1);return}try{let p=_().prepare(`SELECT s.id, p.name AS project_name, s.started_at,
796
796
  s.message_count, s.first_user_message,
797
797
  NULLIF(sa.alias, '') AS alias,
798
798
  s.auto_title
@@ -804,23 +804,20 @@ ${t.message}
804
804
  AND COALESCE(s.auto_title, '') NOT LIKE '[output-index]%'
805
805
  AND COALESCE(s.auto_title, '') NOT LIKE '[skill]%'
806
806
  ORDER BY COALESCE(s.started_at, '') DESC
807
- LIMIT @limit`).all({limit:r0});s(p)}catch(u){i(u instanceof Error?u.message:String(u))}finally{r(!1)}},[]),{sessions:s0(()=>{let u=e.trim().toLowerCase();return u?t.filter(p=>{let m=p.project_name?.toLowerCase()??"",g=p.first_user_message?.toLowerCase()??"";return m.includes(u)||g.includes(u)}):t},[t,e]),total:t.length,loading:n,error:o,dbExists:a}}var r0,Lp=N(()=>{"use strict";w();D();r0=200});import{useEffect as qo,useMemo as o0,useState as Je}from"react";import{Box as _t,Text as In,useApp as i0,useInput as a0}from"ink";import{spawn as c0}from"node:child_process";import{platform as Mn}from"node:os";import{jsx as ae,jsxs as Zo}from"react/jsx-runtime";function Ap(){return{cols:process.stdout.columns??100,rows:process.stdout.rows??30}}function m0(e){let t=Mn()==="darwin"?"open":Mn()==="win32"?"start":"xdg-open",s=Mn()==="win32"?["",e]:[e];c0(t,s,{detached:!0,stdio:"ignore",shell:Mn()==="win32"}).unref()}function Op({onShowSession:e}){let{exit:t}=i0(),s=Ap(),[n,r]=Je(s.cols),[o,i]=Je(s.rows),[a,d]=Je(0),[l,u]=Je(""),[p,m]=Je("normal"),[g,f]=Je(null),[h,E]=Je("preview"),[b,S]=Je("recent"),[T,R]=Je(!1),[k,J]=Je(!1),{sessions:A,total:$,loading:j,error:y,dbExists:U}=Cp(l),M=o0(()=>{if(A.length===0)return A;let B=new Map;if(b==="busiest"||T)for(let O of A)B.set(O.project_name,(B.get(O.project_name)??0)+1);let Y=[...A];if(b==="longest"?Y.sort((O,G)=>(G.message_count??0)-(O.message_count??0)):b==="busiest"&&Y.sort((O,G)=>{let ke=B.get(O.project_name)??0,Ce=B.get(G.project_name)??0;return Ce!==ke?Ce-ke:(G.started_at??"").localeCompare(O.started_at??"")}),T){let O=new Map;for(let Ce of Y){let Ge=O.get(Ce.project_name);Ge||(Ge=[],O.set(Ce.project_name,Ge)),Ge.push(Ce)}let G=Array.from(O.keys()).sort((Ce,Ge)=>{if(b==="busiest"){let si=B.get(Ce)??0,ni=B.get(Ge)??0;if(ni!==si)return ni-si}return Ce.localeCompare(Ge)}),ke=[];for(let Ce of G)for(let Ge of O.get(Ce)??[])ke.push(Ge);return ke}return Y},[A,b,T]);qo(()=>{let B=()=>{let Y=Ap();r(Y.cols),i(Y.rows)};return process.stdout.on("resize",B),()=>{process.stdout.off("resize",B)}},[]),qo(()=>{if(M.length===0){a!==0&&d(0);return}a>=M.length&&d(M.length-1)},[M.length,a]),qo(()=>{if(!g)return;let B=setTimeout(()=>f(null),2500);return()=>clearTimeout(B)},[g]),a0((B,Y)=>{if(p==="search"){Y.escape&&(m("normal"),u(""));return}if(p==="alias"||p==="tag"){Y.escape&&m("normal");return}if(k){(B==="?"||Y.escape||B==="q")&&J(!1);return}if(B==="q"||Y.ctrl&&B==="c"){t();return}if(B==="?"){J(!0);return}if(!(M.length===0&&B!=="/")){if(Y.upArrow||B==="k"){d(O=>Math.max(0,O-1));return}if(Y.downArrow||B==="j"){d(O=>Math.min(M.length-1,O+1));return}if(Y.pageUp){d(O=>Math.max(0,O-10));return}if(Y.pageDown){d(O=>Math.min(M.length-1,O+10));return}if(Y.return){let O=M[a];O&&(e(O.id),t());return}if(B==="o"){let O=M[a];if(!O)return;let G=Q();if(!G){f("start the daemon first (`recall start`)");return}let ke=`http://127.0.0.1:${G.port}/sessions/${O.id}`;m0(ke),f(`opened ${ke}`);return}if(B==="n"){E(G=>G==="neighborhood"?"preview":"neighborhood");let O=M[a];O&&f(h==="neighborhood"?"preview view":`neighborhood for ${O.id.slice(0,8)}`);return}if(B==="/"){m("search");return}if(B==="a"){M[a]&&m("alias");return}if(B==="t"){M[a]&&m("tag");return}if(B==="s"){S(O=>{let G=Vo.indexOf(O),ke=Vo[(G+1)%Vo.length];return f(`sort: ${g0[ke]}`),ke});return}if(B==="g"){R(O=>(f(O?"flat view":"grouped by project"),!O));return}}});function V(B){m("normal");let Y=M[a];if(!Y)return;let O=B.trim();if(!O){f("alias unchanged (empty input)");return}try{It(Y.id,O),f(`alias set: ${O}`)}catch(G){f(`alias failed: ${G instanceof Error?G.message:"unknown"}`)}}function Ye(B){m("normal");let Y=M[a];if(!Y)return;let O=B.trim();if(!O){f("tag unchanged (empty input)");return}try{let G=Wa(Y.id,O);f(G.added?`tag added: ${G.tag}`:`tag exists: ${G.tag}`)}catch(G){f(`tag failed: ${G instanceof Error?G.message:"unknown"}`)}}if(n<Xo||o<Jo)return Zo(_t,{flexDirection:"column",padding:1,children:[ae(In,{color:De,children:"Terminal too small."}),ae(In,{color:C,children:`Resize to at least ${Xo} cols x ${Jo} rows. Current: ${n} x ${o}.`}),ae(In,{color:C,children:"Press q to quit."})]});let Fe=Math.max(10,o-p0-Np),ht=Math.max(36,Math.floor(n*.4)),ti=n-ht-1,$n=M[a]??null;return Zo(_t,{flexDirection:"column",width:n,height:o,children:[ae(dp,{cols:n}),ae(_t,{height:1}),y?ae(_t,{paddingX:1,children:ae(In,{color:De,children:`Error loading sessions: ${y}`})}):k?ae(_t,{height:Fe,children:ae(xp,{width:n,height:Fe})}):Zo(_t,{flexDirection:"row",height:Fe,children:[ae(mp,{sessions:M,total:$,selected:a,width:ht,height:Fe,loading:j,dbExists:U,filter:l,sortMode:b,groupByProject:T}),ae(_t,{width:1,height:Fe}),h==="neighborhood"?ae(Sp,{session:$n,width:ti,height:Fe,budget:4e3}):ae(Ep,{session:$n,width:ti,height:Fe})]}),ae(_t,{height:Np,width:n,paddingX:1,children:ae(Tp,{mode:p,query:l,onQueryChange:u,onSearchSubmit:()=>m("normal"),onAliasSubmit:V,onTagSubmit:Ye,aliasInitial:$n?.alias??"",toast:g})})]})}var l0,d0,u0,Np,p0,Vo,g0,vp=N(()=>{"use strict";pp();gp();bp();yp();Rp();kp();Lp();Ke();bt();Rr();pt();l0=4,d0=1,u0=1,Np=1,p0=l0+d0+u0,Vo=["recent","longest","busiest"];g0={recent:"most recent first",longest:"longest sessions first",busiest:"busiest project first"}});import{render as f0}from"ink";import{jsx as _0}from"react/jsx-runtime";async function Ip(){let e={showSessionId:null};return await f0(_0(Op,{onShowSession:n=>{e.showSessionId=n}})).waitUntilExit(),e}var Mp=N(()=>{"use strict";vp()});var Dp={};he(Dp,{runTui:()=>E0});import{spawn as h0}from"node:child_process";async function E0(){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 Ip();if(!e.showSessionId)return;let t=process.argv[1];t&&await new Promise(s=>{let n=h0(process.execPath,[t,"show",e.showSessionId],{stdio:"inherit"});n.on("exit",()=>s()),n.on("error",()=>s())})}var $p=N(()=>{"use strict";Mp()});var Pp={};he(Pp,{findSimilarSessions:()=>S0,vectorSearch:()=>b0});async function b0(e,t=50){let s=await vr(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
808
- FROM vec_chunks v JOIN chunk_meta cm ON cm.rowid = v.rowid
809
- 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 S0(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
810
- WHERE v.embedding MATCH ? AND k = ? ORDER BY v.distance`).all(o.embedding,t*5),a=new Map;for(let l of i){if(l.session_id===e)continue;let u=a.get(l.session_id);(u===void 0||l.distance<u)&&a.set(l.session_id,l.distance)}let d=[];for(let[l,u]of a){let p=1-u;p>=s&&d.push({sessionId:l,similarity:p})}return d.sort((l,u)=>u.similarity-l.similarity),d.slice(0,t)}var Fp=N(()=>{"use strict";w();rt()});import{createRequire as y0}from"module";import{Command as w0}from"commander";w();D();import{basename as Um}from"node:path";import{createReadStream as nm}from"node:fs";import{createInterface as rm}from"node:readline";function Ss(e){return typeof e=="number"&&Number.isFinite(e)?e:0}function Wn(e){let t=e?.usage;if(!t||typeof t!="object")return null;let s={inputTokens:Ss(t.input_tokens),outputTokens:Ss(t.output_tokens),cacheCreateTokens:Ss(t.cache_creation_input_tokens),cacheReadTokens:Ss(t.cache_read_input_tokens)};return s.inputTokens===0&&s.outputTokens===0&&s.cacheCreateTokens===0&&s.cacheReadTokens===0?null:s}var om=/\x1B\[[0-9;]*[a-zA-Z]/g;function Bn(e){return e.replace(om,"")}var Hn=12e3;function mi(e,t){if(e.length<=Hn)return e;let s=e.slice(0,Hn),n=e.length-Hn;return`${s}
807
+ LIMIT @limit`).all({limit:g0});s(p)}catch(u){i(u instanceof Error?u.message:String(u))}finally{r(!1)}},[]),{sessions:p0(()=>{let u=e.trim().toLowerCase();return u?t.filter(p=>{let m=p.project_name?.toLowerCase()??"",g=p.first_user_message?.toLowerCase()??"";return m.includes(u)||g.includes(u)}):t},[t,e]),total:t.length,loading:n,error:o,dbExists:a}}var g0,Op=N(()=>{"use strict";w();P();g0=200});import{useEffect as Zo,useMemo as f0,useState as Je}from"react";import{Box as ft,Text as Dn,useApp as _0,useInput as h0}from"ink";import{spawn as E0}from"node:child_process";import{platform as $n}from"node:os";import{jsx as ce,jsxs as ei}from"react/jsx-runtime";function Ip(){return{cols:process.stdout.columns??100,rows:process.stdout.rows??30}}function T0(e){let t=$n()==="darwin"?"open":$n()==="win32"?"start":"xdg-open",s=$n()==="win32"?["",e]:[e];E0(t,s,{detached:!0,stdio:"ignore",shell:$n()==="win32"}).unref()}function Mp({onShowSession:e}){let{exit:t}=_0(),s=Ip(),[n,r]=Je(s.cols),[o,i]=Je(s.rows),[a,d]=Je(0),[l,u]=Je(""),[p,m]=Je("normal"),[g,f]=Je(null),[h,E]=Je("preview"),[b,S]=Je("recent"),[R,T]=Je(!1),[L,D]=Je(!1),{sessions:A,total:$,loading:U,error:y,dbExists:B}=Ap(l),M=f0(()=>{if(A.length===0)return A;let H=new Map;if(b==="busiest"||R)for(let O of A)H.set(O.project_name,(H.get(O.project_name)??0)+1);let G=[...A];if(b==="longest"?G.sort((O,Y)=>(Y.message_count??0)-(O.message_count??0)):b==="busiest"&&G.sort((O,Y)=>{let ke=H.get(O.project_name)??0,Ce=H.get(Y.project_name)??0;return Ce!==ke?Ce-ke:(Y.started_at??"").localeCompare(O.started_at??"")}),R){let O=new Map;for(let Ce of G){let Ye=O.get(Ce.project_name);Ye||(Ye=[],O.set(Ce.project_name,Ye)),Ye.push(Ce)}let Y=Array.from(O.keys()).sort((Ce,Ye)=>{if(b==="busiest"){let ci=H.get(Ce)??0,li=H.get(Ye)??0;if(li!==ci)return li-ci}return Ce.localeCompare(Ye)}),ke=[];for(let Ce of Y)for(let Ye of O.get(Ce)??[])ke.push(Ye);return ke}return G},[A,b,R]);Zo(()=>{let H=()=>{let G=Ip();r(G.cols),i(G.rows)};return process.stdout.on("resize",H),()=>{process.stdout.off("resize",H)}},[]),Zo(()=>{if(M.length===0){a!==0&&d(0);return}a>=M.length&&d(M.length-1)},[M.length,a]),Zo(()=>{if(!g)return;let H=setTimeout(()=>f(null),2500);return()=>clearTimeout(H)},[g]),h0((H,G)=>{if(p==="search"){G.escape&&(m("normal"),u(""));return}if(p==="alias"||p==="tag"){G.escape&&m("normal");return}if(L){(H==="?"||G.escape||H==="q")&&D(!1);return}if(H==="q"||G.ctrl&&H==="c"){t();return}if(H==="?"){D(!0);return}if(!(M.length===0&&H!=="/")){if(G.upArrow||H==="k"){d(O=>Math.max(0,O-1));return}if(G.downArrow||H==="j"){d(O=>Math.min(M.length-1,O+1));return}if(G.pageUp){d(O=>Math.max(0,O-10));return}if(G.pageDown){d(O=>Math.min(M.length-1,O+10));return}if(G.return){let O=M[a];O&&(e(O.id),t());return}if(H==="o"){let O=M[a];if(!O)return;let Y=Q();if(!Y){f("start the daemon first (`recall start`)");return}let ke=`http://127.0.0.1:${Y.port}/sessions/${O.id}`;T0(ke),f(`opened ${ke}`);return}if(H==="n"){E(Y=>Y==="neighborhood"?"preview":"neighborhood");let O=M[a];O&&f(h==="neighborhood"?"preview view":`neighborhood for ${O.id.slice(0,8)}`);return}if(H==="/"){m("search");return}if(H==="a"){M[a]&&m("alias");return}if(H==="t"){M[a]&&m("tag");return}if(H==="s"){S(O=>{let Y=Qo.indexOf(O),ke=Qo[(Y+1)%Qo.length];return f(`sort: ${R0[ke]}`),ke});return}if(H==="g"){T(O=>(f(O?"flat view":"grouped by project"),!O));return}}});function V(H){m("normal");let G=M[a];if(!G)return;let O=H.trim();if(!O){f("alias unchanged (empty input)");return}try{Mt(G.id,O),f(`alias set: ${O}`)}catch(Y){f(`alias failed: ${Y instanceof Error?Y.message:"unknown"}`)}}function Ge(H){m("normal");let G=M[a];if(!G)return;let O=H.trim();if(!O){f("tag unchanged (empty input)");return}try{let Y=Ga(G.id,O);f(Y.added?`tag added: ${Y.tag}`:`tag exists: ${Y.tag}`)}catch(Y){f(`tag failed: ${Y instanceof Error?Y.message:"unknown"}`)}}if(n<Go||o<Yo)return ei(ft,{flexDirection:"column",padding:1,children:[ce(Dn,{color:De,children:"Terminal too small."}),ce(Dn,{color:k,children:`Resize to at least ${Go} cols x ${Yo} rows. Current: ${n} x ${o}.`}),ce(Dn,{color:k,children:"Press q to quit."})]});let Fe=Math.max(10,o-w0-vp),_t=Math.max(36,Math.floor(n*.4)),ai=n-_t-1,Fn=M[a]??null;return ei(ft,{flexDirection:"column",width:n,height:o,children:[ce(mp,{cols:n}),ce(ft,{height:1}),y?ce(ft,{paddingX:1,children:ce(Dn,{color:De,children:`Error loading sessions: ${y}`})}):L?ce(ft,{height:Fe,children:ce(Lp,{width:n,height:Fe})}):ei(ft,{flexDirection:"row",height:Fe,children:[ce(_p,{sessions:M,total:$,selected:a,width:_t,height:Fe,loading:U,dbExists:B,filter:l,sortMode:b,groupByProject:R}),ce(ft,{width:1,height:Fe}),h==="neighborhood"?ce(Tp,{session:Fn,width:ai,height:Fe,budget:4e3}):ce(yp,{session:Fn,width:ai,height:Fe})]}),ce(ft,{height:vp,width:n,paddingX:1,children:ce(kp,{mode:p,query:l,onQueryChange:u,onSearchSubmit:()=>m("normal"),onAliasSubmit:V,onTagSubmit:Ge,aliasInitial:Fn?.alias??"",toast:g})})]})}var b0,S0,y0,vp,w0,Qo,R0,Dp=N(()=>{"use strict";fp();hp();wp();Rp();Cp();Np();Op();qe();Et();Cr();ut();b0=4,S0=1,y0=1,vp=1,w0=b0+S0+y0,Qo=["recent","longest","busiest"];R0={recent:"most recent first",longest:"longest sessions first",busiest:"busiest project first"}});import{render as x0}from"ink";import{jsx as k0}from"react/jsx-runtime";async function $p(){let e={showSessionId:null};return await x0(k0(Mp,{onShowSession:n=>{e.showSessionId=n}})).waitUntilExit(),e}var Pp=N(()=>{"use strict";Dp()});var Fp={};he(Fp,{runTui:()=>L0});import{spawn as C0}from"node:child_process";async function L0(){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 $p();if(!e.showSessionId)return;let t=process.argv[1];t&&await new Promise(s=>{let n=C0(process.execPath,[t,"show",e.showSessionId],{stdio:"inherit"});n.on("exit",()=>s()),n.on("error",()=>s())})}var jp=N(()=>{"use strict";Pp()});function si(e,t={}){let s=t.limit??N0()??75e3,r=e.prepare("SELECT COUNT(*) AS n FROM vec_chunks").get()?.n??0;if(r>s)throw new ti(r,s)}function N0(){let e=process.env.RECALL_KNN_MAX_CORPUS;if(!e)return;let t=Number(e);if(!(!Number.isFinite(t)||t<=0||t>1e7))return Math.floor(t)}var ti,Up=N(()=>{"use strict";ti=class extends Error{name="CorpusTooLargeError";code="CORPUS_TOO_LARGE";rowCount;limit;constructor(t,s){super(`semantic search refused: vec_chunks has ${t} rows (cap ${s}). An unindexed kNN over this corpus can pin the SQLite WAL for hours. Workarounds: (a) scope the search to a smaller project, (b) raise the cap via RECALL_KNN_MAX_CORPUS at your own risk, (c) wait for ANN indexing (tracked in the WAL death-spiral plan).`),this.rowCount=t,this.limit=s}}});import{Worker as A0}from"node:worker_threads";import{join as O0}from"node:path";function I0(){let e=process.env.RECALL_KNN_TIMEOUT_MS;if(!e)return;let t=Number(e);if(!(!Number.isFinite(t)||t<=0||t>36e5))return Math.floor(t)}async function ri(e){let t=e.timeoutMs??I0()??v0,s=(e.workerFactory??M0)();return new Promise((n,r)=>{let o=setTimeout(()=>{s.terminate().catch(()=>{}),r(new ni(t))},t);s.once("message",i=>{clearTimeout(o);let a=i;a&&a.ok===!0&&Array.isArray(a.hits)?n(a.hits):r(new Error(a?.error??"worker returned malformed reply")),s.terminate().catch(()=>{})}),s.once("error",i=>{clearTimeout(o),s.terminate().catch(()=>{}),r(i)}),s.postMessage({query:e.query,precomputedVector:e.precomputedVector,limit:e.limit})})}function M0(){let e=O0(ee(),"dist","daemon","query-worker.js");return new A0(e)}var ni,v0,Bp=N(()=>{"use strict";Ke();ni=class extends Error{constructor(s){super(`semantic kNN exceeded ${s}ms wall-clock budget -- query aborted`);this.timeoutMs=s}timeoutMs;name="KnnTimeoutError";code="KNN_TIMEOUT"},v0=1e4});var Hp={};he(Hp,{findSimilarSessions:()=>$0,vectorSearch:()=>D0});async function D0(e,t=50){return si(_()),ri({query:e,limit:t})}async function $0(e,t=10,s=.65){let n=_();si(n);let 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=await ri({precomputedVector:o.embedding,limit:t*5}),a=new Map;for(let l of i){if(l.sessionId===e)continue;let u=a.get(l.sessionId);(u===void 0||l.distance<u)&&a.set(l.sessionId,l.distance)}let d=[];for(let[l,u]of a){let p=1-u;p>=s&&d.push({sessionId:l,similarity:p})}return d.sort((l,u)=>u.similarity-l.similarity),d.slice(0,t)}var Wp=N(()=>{"use strict";w();Up();Bp()});import{createRequire as P0}from"module";import{Command as F0}from"commander";w();P();import{basename as Jm}from"node:path";import{createReadStream as cm}from"node:fs";import{createInterface as lm}from"node:readline";function Ss(e){return typeof e=="number"&&Number.isFinite(e)?e:0}function Jn(e){let t=e?.usage;if(!t||typeof t!="object")return null;let s={inputTokens:Ss(t.input_tokens),outputTokens:Ss(t.output_tokens),cacheCreateTokens:Ss(t.cache_creation_input_tokens),cacheReadTokens:Ss(t.cache_read_input_tokens)};return s.inputTokens===0&&s.outputTokens===0&&s.cacheCreateTokens===0&&s.cacheReadTokens===0?null:s}var dm=/\x1B\[[0-9;]*[a-zA-Z]/g;function Wn(e){return e.replace(dm,"")}var Xn=12e3;function bi(e,t){if(e.length<=Xn)return e;let s=e.slice(0,Xn),n=e.length-Xn;return`${s}
811
808
 
812
- \u27E8\u2026 ${n.toLocaleString()} more chars in ${t}; see raw JSONL for full content \u27E9`}function im(e){try{return JSON.stringify(e,null,2)}catch{return String(e)}}function am(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(`
813
- `)}return""}function cm(e){if(!e)return{text:"",toolNames:[]};if(typeof e.content=="string")return{text:Bn(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(Bn(n.text));continue}if(n.type==="tool_use"&&typeof n.name=="string"){s.push(n.name);let r=n.input!=null?im(n.input):"",o=mi(r,"tool input");t.push(`\u26A1 **Tool call \xB7 \`${n.name}\`**
809
+ \u27E8\u2026 ${n.toLocaleString()} more chars in ${t}; see raw JSONL for full content \u27E9`}function um(e){try{return JSON.stringify(e,null,2)}catch{return String(e)}}function pm(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(`
810
+ `)}return""}function mm(e){if(!e)return{text:"",toolNames:[]};if(typeof e.content=="string")return{text:Wn(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(Wn(n.text));continue}if(n.type==="tool_use"&&typeof n.name=="string"){s.push(n.name);let r=n.input!=null?um(n.input):"",o=bi(r,"tool input");t.push(`\u26A1 **Tool call \xB7 \`${n.name}\`**
814
811
 
815
812
  \`\`\`json
816
813
  ${o}
817
- \`\`\``);continue}if(n.type==="tool_result"){let r=Bn(am(n));if(r){let o=mi(r,"tool result");t.push(`**Tool result**
814
+ \`\`\``);continue}if(n.type==="tool_result"){let r=Wn(pm(n));if(r){let o=bi(r,"tool result");t.push(`**Tool result**
818
815
 
819
816
  \`\`\`
820
817
  ${o}
821
818
  \`\`\``)}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(`
822
819
 
823
- `),toolNames:s}}async function*Xn(e){let t=nm(e,{encoding:"utf8"}),s=rm({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}=cm(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:Wn(r.message),model:r.message?.model??null}}}v();var gi=[{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 fi(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 Yt(e){if(!e)return[];let t=new Set,s=[];for(let n of gi){n.regex.lastIndex=0;for(let r of e.matchAll(n.regex)){let o=r[0],i=`${n.name}::${_i(o)}`;t.has(i)||(t.add(i),s.push({pattern:n.name,maskedPreview:fi(o),offset:r.index??0,severity:n.severity}))}}return s}function _i(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 we(e){if(!e)return{redacted:e,count:0};let t=e,s=0,n=new Set;for(let r of gi)r.regex.lastIndex=0,t=t.replace(r.regex,o=>{let i=`${r.name}::${_i(o)}`;return n.has(i)||(n.add(i),s+=1),`[REDACTED ${r.name}: ${fi(o)}]`});return{redacted:t,count:s}}function Yn(e,t,s){e.prepare("DELETE FROM message_usage WHERE session_id = ?").run(t);let n=e.prepare(`
820
+ `),toolNames:s}}async function*Gn(e){let t=cm(e,{encoding:"utf8"}),s=lm({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}=mm(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:Jn(r.message),model:r.message?.model??null}}}v();var Si=[{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 yi(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 Yt(e){if(!e)return[];let t=new Set,s=[];for(let n of Si){n.regex.lastIndex=0;for(let r of e.matchAll(n.regex)){let o=r[0],i=`${n.name}::${wi(o)}`;t.has(i)||(t.add(i),s.push({pattern:n.name,maskedPreview:yi(o),offset:r.index??0,severity:n.severity}))}}return s}function wi(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 we(e){if(!e)return{redacted:e,count:0};let t=e,s=0,n=new Set;for(let r of Si)r.regex.lastIndex=0,t=t.replace(r.regex,o=>{let i=`${r.name}::${wi(o)}`;return n.has(i)||(n.add(i),s+=1),`[REDACTED ${r.name}: ${yi(o)}]`});return{redacted:t,count:s}}function zn(e,t,s){e.prepare("DELETE FROM message_usage WHERE session_id = ?").run(t);let n=e.prepare(`
824
821
  INSERT INTO message_usage (
825
822
  message_uuid, session_id, model,
826
823
  input_tokens, output_tokens, cache_create_tokens, cache_read_tokens,
@@ -837,7 +834,7 @@ ${o}
837
834
  cache_create_tokens = excluded.cache_create_tokens,
838
835
  cache_read_tokens = excluded.cache_read_tokens,
839
836
  timestamp = excluded.timestamp
840
- `);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 Gt(e,t){let s=e.prepare(`SELECT
837
+ `);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 zt(e,t){let s=e.prepare(`SELECT
841
838
  COALESCE(SUM(input_tokens), 0) AS input_tokens,
842
839
  COALESCE(SUM(output_tokens), 0) AS output_tokens,
843
840
  COALESCE(SUM(cache_create_tokens), 0) AS cache_create_tokens,
@@ -852,17 +849,17 @@ ${o}
852
849
  total_cache_create_tokens = @cc,
853
850
  total_cache_read_tokens = @cr,
854
851
  primary_model = @model
855
- 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})}w();D();import{writeFileSync as fm,mkdirSync as _m,existsSync as hm}from"node:fs";import{join as bi}from"node:path";w();var um=[/^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 Nt=[/^You are summarizing a Claude Code session/i,/^You are extracting a structured Output Index from a Claude/i,/^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,/^Thread context:\n- This session is part of thread/i];var pm=[/^Score this person'?s relevance/i,/^You are a [^\n.]{1,60}co-pilot/i,/^Return ONLY valid JSON/i,/^You are summarizing a Claude Code session/i],mm=[/^Draft (a|an|marketing) [a-z]/i,/^Read the file at /i,/^Read this and then begin/i,/^read this and then begin/i],gm=20;function hi(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<gm)return"low_signal";for(let t of um)if(t.test(e.auto_title))return"recursive_meta";for(let t of pm)if(t.test(e.auto_title))return"programmatic";for(let t of mm)if(t.test(e.auto_title))return"template_pending";return"clean"}function Gn(e){if(!e)return"";let t=e.split("|")[0];return t=t.replace(/\s*\([^)]*\)\s*$/,""),t=t.replace(/\s+/g," ").trim(),t}var Kn=bi(x,"titles"),Em=80,bm=60,Sm=100;function ym(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 Vn(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=wm(t,e);if(s)return s;let n=t.match(/^[^.!?\n]{8,}?[.!?]/)?.[0]?.trim();return(n&&n.length<=Em?n:t.slice(0,bm)).trim()||null}function wm(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=qn(r);return o?zt(`${n} \xB7 ${o}`):n}for(let n of Tm){if(!e.match(n.match))continue;let o=n.prefix,i=n.extract?n.extract(e,t):qn(t);return i?n.completeFromExtract?zt(i):zt(`${o} \xB7 ${i}`):o}for(let n of km){if(!e.match(n.match))continue;let o=n.extract?n.extract(e,t):ys(t);return o?n.completeFromExtract?zt(o):zt(`${n.prefix} \xB7 ${o}`):n.prefix}return null}var Tm=[{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=qn(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)=>xm(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)=>Rm(t)},{match:/^You will receive a sample of user messages from a Claude Code session:/i,prefix:"[meta]",completeFromExtract:!0,extract:(e,t)=>Ei(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)=>Ei(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 Rm(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 Ei(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 d=a.length>60?a.slice(0,57)+"\u2026":a;return`${t} \xB7 ${d}`}return t}function xm(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 km=[{match:/^Score this person'?s relevance/i,prefix:"Score relevance",extract:(e,t)=>ys(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=ys(t);return o?`${r} \xB7 ${o}`:r}},{match:/^Return ONLY valid JSON/i,prefix:"JSON-only",extract:(e,t)=>ys(t)}];function ys(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 Gn(r)||r}return null}function zt(e){return e.slice(0,Sm).trim()}var Cm=[/^deep research$/i,/^reference(?: spec)?$/i,/^canonical spec/i,/^product context/i,/^services?(?: overview)?$/i,/^overview$/i,/^(?:introduction|template|instructions|context)$/i],Lm=[/^(?: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 zn(e){let t=e.trim();return t.length<3?!0:Cm.some(s=>s.test(t))}function Nm(e){let t=e.trim().replace(/\s*\([^)]*\)\s*$/,"").trim();return Lm.some(s=>s.test(t))}function qn(e){let t=Am(e);return t===null?null:Gn(t)||t}function Am(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 d=s[2].trim(),l=s[3].trim().replace(/\s+/g," ");if(!zn(l)){if(Nm(d))return l;n.push(l)}}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]&&!zn(r[1]))return r[1].trim().replace(/\s+/g," ");let o=/===\s*([^=\n]{2,120}?)\s*===/g;for(;(s=o.exec(e))!==null;){let d=s[1].trim().replace(/\.(md|txt|json)$/i,""),l=d.replace(/\s*\([^)]*\)\s*$/,"").trim();if(l&&!zn(l)&&!/product context|reference/i.test(d))return l}let i=e.replace(/^Context for this run[^:]*:\s*/i,"");if(i!==e){let d=i.split(`
852
+ 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})}w();P();import{writeFileSync as Sm,mkdirSync as ym,existsSync as wm}from"node:fs";import{join as xi}from"node:path";w();var _m=[/^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 Nt=[/^You are summarizing a Claude Code session/i,/^You are extracting a structured Output Index from a Claude/i,/^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,/^Thread context:\n- This session is part of thread/i];var hm=[/^Score this person'?s relevance/i,/^You are a [^\n.]{1,60}co-pilot/i,/^Return ONLY valid JSON/i,/^You are summarizing a Claude Code session/i],Em=[/^Draft (a|an|marketing) [a-z]/i,/^Read the file at /i,/^Read this and then begin/i,/^read this and then begin/i],bm=20;function Ti(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<bm)return"low_signal";for(let t of _m)if(t.test(e.auto_title))return"recursive_meta";for(let t of hm)if(t.test(e.auto_title))return"programmatic";for(let t of Em)if(t.test(e.auto_title))return"template_pending";return"clean"}function qn(e){if(!e)return"";let t=e.split("|")[0];return t=t.replace(/\s*\([^)]*\)\s*$/,""),t=t.replace(/\s+/g," ").trim(),t}var Vn=xi(x,"titles"),Tm=80,Rm=60,xm=100;function km(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 Qn(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=Cm(t,e);if(s)return s;let n=t.match(/^[^.!?\n]{8,}?[.!?]/)?.[0]?.trim();return(n&&n.length<=Tm?n:t.slice(0,Rm)).trim()||null}function Cm(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=Zn(r);return o?qt(`${n} \xB7 ${o}`):n}for(let n of Lm){if(!e.match(n.match))continue;let o=n.prefix,i=n.extract?n.extract(e,t):Zn(t);return i?n.completeFromExtract?qt(i):qt(`${o} \xB7 ${i}`):o}for(let n of Om){if(!e.match(n.match))continue;let o=n.extract?n.extract(e,t):ys(t);return o?n.completeFromExtract?qt(o):qt(`${n.prefix} \xB7 ${o}`):n.prefix}return null}var Lm=[{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=Zn(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)=>Am(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)=>Nm(t)},{match:/^You will receive a sample of user messages from a Claude Code session:/i,prefix:"[meta]",completeFromExtract:!0,extract:(e,t)=>Ri(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)=>Ri(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 Nm(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 Ri(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 d=a.length>60?a.slice(0,57)+"\u2026":a;return`${t} \xB7 ${d}`}return t}function Am(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 Om=[{match:/^Score this person'?s relevance/i,prefix:"Score relevance",extract:(e,t)=>ys(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=ys(t);return o?`${r} \xB7 ${o}`:r}},{match:/^Return ONLY valid JSON/i,prefix:"JSON-only",extract:(e,t)=>ys(t)}];function ys(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 qn(r)||r}return null}function qt(e){return e.slice(0,xm).trim()}var vm=[/^deep research$/i,/^reference(?: spec)?$/i,/^canonical spec/i,/^product context/i,/^services?(?: overview)?$/i,/^overview$/i,/^(?:introduction|template|instructions|context)$/i],Im=[/^(?: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 Kn(e){let t=e.trim();return t.length<3?!0:vm.some(s=>s.test(t))}function Mm(e){let t=e.trim().replace(/\s*\([^)]*\)\s*$/,"").trim();return Im.some(s=>s.test(t))}function Zn(e){let t=Dm(e);return t===null?null:qn(t)||t}function Dm(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 d=s[2].trim(),l=s[3].trim().replace(/\s+/g," ");if(!Kn(l)){if(Mm(d))return l;n.push(l)}}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]&&!Kn(r[1]))return r[1].trim().replace(/\s+/g," ");let o=/===\s*([^=\n]{2,120}?)\s*===/g;for(;(s=o.exec(e))!==null;){let d=s[1].trim().replace(/\.(md|txt|json)$/i,""),l=d.replace(/\s*\([^)]*\)\s*$/,"").trim();if(l&&!Kn(l)&&!/product context|reference/i.test(d))return l}let i=e.replace(/^Context for this run[^:]*:\s*/i,"");if(i!==e){let d=i.split(`
856
853
  `).map(l=>l.trim()).find(l=>l.length>=4);if(d)return d.slice(0,60)}let a=e.split(`
857
- `).map(d=>d.trim()).find(d=>d.length>=4);return a?a.slice(0,60):null}function Zn(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
858
- 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=ym(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
854
+ `).map(d=>d.trim()).find(d=>d.length>=4);return a?a.slice(0,60):null}function er(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
855
+ 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=km(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
859
856
  SET auto_title = ?,
860
857
  auto_title_source = ?,
861
858
  auto_title_generated_at = ?,
862
859
  auto_title_history = ?
863
- WHERE id = ?`).run(n,s,Date.now(),JSON.stringify(i),e),vm(e,n,s,a)}function Om(){P(),hm(Kn)||_m(Kn,{recursive:!0})}function vm(e,t,s,n){try{Om();let r=bi(Kn,`${e}.txt`),o=`# Claude Recall auto-title \xB7 session ${e} \xB7 source ${s} \xB7 updated ${n}
864
- `;fm(r,o+t+`
865
- `)}catch(r){console.error("[autoTitle] mirror write failed:",r)}}import{existsSync as Im,mkdirSync as cx,readFileSync as Mm,writeFileSync as lx}from"node:fs";import{homedir as Dm}from"node:os";import{join as Si}from"node:path";import{z as Qn}from"zod";function $m(){return process.env.RECALL_HOME??Si(Dm(),".recall")}function Pm(){return Si($m(),"config.json")}var Fm=Qn.object({heuristicEnabled:Qn.boolean().default(!0),agentEnabled:Qn.boolean().default(!1)}),er={heuristicEnabled:!0,agentEnabled:!1};function jm(){let e=Pm();if(!Im(e))return{};try{return JSON.parse(Mm(e,"utf8"))}catch(t){return console.error("[auto-title-config] failed to parse config.json, using defaults:",t),{}}}function tr(){let e=jm().autoTitle;if(!e)return{...er};let t=Fm.safeParse({...er,...e});return t.success?t.data:{...er}}var Bm=[/^<local-command-caveat>/,/^<command-name>/,/^<command-message>/,/^<system-reminder>/,/^<user-prompt-submit-hook>/,/^Caveat: The messages below were generated/i];function Hm(e){let t=e.trim();return t?Bm.some(s=>s.test(t)):!0}function Wm(e){let t=e;return t=t.replace(/^(?:<[^>]+>[\s\S]*?<\/[^>]+>\s*)+/,"").trim(),t=t.replace(/^<command-[^>]+>[^<]*<\/command-[^>]+>\s*/gm,"").trim(),!t||Hm(t)?null:t}function Xm(e,t,s){let n=Un(t),r=s??n,o=s?Um(s)||s:ai(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 Jm(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 f of Xn(t.sessionFile)){let h=r.get(f.sessionId);if(h||(h={sessionId:f.sessionId,entries:[],earliestTimestamp:null,latestTimestamp:null,firstUserMessage:null,userCount:0,assistantCount:0,cwd:null,gitBranch:null,version:null},r.set(f.sessionId,h)),h.entries.push(f),f.timestamp&&((!h.earliestTimestamp||f.timestamp<h.earliestTimestamp)&&(h.earliestTimestamp=f.timestamp),(!h.latestTimestamp||f.timestamp>h.latestTimestamp)&&(h.latestTimestamp=f.timestamp)),f.role==="user"&&!f.isSidechain){if(h.userCount+=1,!h.firstUserMessage&&f.contentText){let E=Wm(f.contentText);E&&(h.firstUserMessage=q(we(E).redacted,200))}}else f.role==="assistant"&&!f.isSidechain&&(h.assistantCount+=1);!h.cwd&&f.cwd&&(h.cwd=f.cwd),!h.gitBranch&&f.gitBranch&&(h.gitBranch=f.gitBranch),!h.version&&f.version&&(h.version=f.version),!o&&f.cwd&&(o=f.cwd)}let i=Xm(e,t.encodedProject,o),a=new Date().toISOString(),d=e.prepare(`
860
+ WHERE id = ?`).run(n,s,Date.now(),JSON.stringify(i),e),Pm(e,n,s,a)}function $m(){F(),wm(Vn)||ym(Vn,{recursive:!0})}function Pm(e,t,s,n){try{$m();let r=xi(Vn,`${e}.txt`),o=`# Claude Recall auto-title \xB7 session ${e} \xB7 source ${s} \xB7 updated ${n}
861
+ `;Sm(r,o+t+`
862
+ `)}catch(r){console.error("[autoTitle] mirror write failed:",r)}}import{existsSync as Fm,mkdirSync as Rx,readFileSync as jm,writeFileSync as xx}from"node:fs";import{homedir as Um}from"node:os";import{join as ki}from"node:path";import{z as tr}from"zod";function Bm(){return process.env.RECALL_HOME??ki(Um(),".recall")}function Hm(){return ki(Bm(),"config.json")}var Wm=tr.object({heuristicEnabled:tr.boolean().default(!0),agentEnabled:tr.boolean().default(!1)}),sr={heuristicEnabled:!0,agentEnabled:!1};function Xm(){let e=Hm();if(!Fm(e))return{};try{return JSON.parse(jm(e,"utf8"))}catch(t){return console.error("[auto-title-config] failed to parse config.json, using defaults:",t),{}}}function nr(){let e=Xm().autoTitle;if(!e)return{...sr};let t=Wm.safeParse({...sr,...e});return t.success?t.data:{...sr}}var Gm=[/^<local-command-caveat>/,/^<command-name>/,/^<command-message>/,/^<system-reminder>/,/^<user-prompt-submit-hook>/,/^Caveat: The messages below were generated/i];function Ym(e){let t=e.trim();return t?Gm.some(s=>s.test(t)):!0}function zm(e){let t=e;return t=t.replace(/^(?:<[^>]+>[\s\S]*?<\/[^>]+>\s*)+/,"").trim(),t=t.replace(/^<command-[^>]+>[^<]*<\/command-[^>]+>\s*/gm,"").trim(),!t||Ym(t)?null:t}function qm(e,t,s){let n=Hn(t),r=s??n,o=s?Jm(s)||s:mi(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 Km(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 f of Gn(t.sessionFile)){let h=r.get(f.sessionId);if(h||(h={sessionId:f.sessionId,entries:[],earliestTimestamp:null,latestTimestamp:null,firstUserMessage:null,userCount:0,assistantCount:0,cwd:null,gitBranch:null,version:null},r.set(f.sessionId,h)),h.entries.push(f),f.timestamp&&((!h.earliestTimestamp||f.timestamp<h.earliestTimestamp)&&(h.earliestTimestamp=f.timestamp),(!h.latestTimestamp||f.timestamp>h.latestTimestamp)&&(h.latestTimestamp=f.timestamp)),f.role==="user"&&!f.isSidechain){if(h.userCount+=1,!h.firstUserMessage&&f.contentText){let E=zm(f.contentText);E&&(h.firstUserMessage=K(we(E).redacted,200))}}else f.role==="assistant"&&!f.isSidechain&&(h.assistantCount+=1);!h.cwd&&f.cwd&&(h.cwd=f.cwd),!h.gitBranch&&f.gitBranch&&(h.gitBranch=f.gitBranch),!h.version&&f.version&&(h.version=f.version),!o&&f.cwd&&(o=f.cwd)}let i=qm(e,t.encodedProject,o),a=new Date().toISOString(),d=e.prepare(`
866
863
  INSERT INTO sessions (
867
864
  id, project_id, file_path, file_mtime,
868
865
  started_at, ended_at, message_count,
@@ -897,30 +894,30 @@ ${o}
897
894
  @is_sidechain, @content_text, @tool_names, @raw_json
898
895
  )
899
896
  ON CONFLICT(uuid) DO NOTHING
900
- `),u=e.prepare("DELETE FROM messages WHERE session_id = ?"),p=0,m=0;if(e.transaction(()=>{for(let f of r.values()){d.run({id:f.sessionId,project_id:i,file_path:t.sessionFile,file_mtime:t.mtime,started_at:f.earliestTimestamp,ended_at:f.latestTimestamp,message_count:f.entries.length,user_message_count:f.userCount,assistant_message_count:f.assistantCount,first_user_message:f.firstUserMessage,cwd:f.cwd,git_branch:f.gitBranch,version:f.version,indexed_at:a}),u.run(f.sessionId);for(let h of f.entries){let{redacted:E}=we(h.contentText),{redacted:b}=we(h.raw);l.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}Yn(e,f.sessionId,f.entries),Gt(e,f.sessionId),p+=1}})(),tr().heuristicEnabled)for(let f of r.values()){let h=Vn(f.firstUserMessage);h&&Zn(f.sessionId,h,"heuristic")}return{inserted:!0,sessionCount:p,messageCount:m}}async function yi(e){let t=_(),s=ci();console.log(c.dim(`Scanning ${s.length} JSONL session files under ~/.claude/projects/`));let n=0,r=0,o=0,i=0,a=Date.now();for(let l of s)try{let u=await Jm(t,l,e.force??!1);u.inserted?(n+=1,o+=u.sessionCount,i+=u.messageCount,e.verbose&&console.log(c.dim(` + ${l.sessionFile.split("/").slice(-2).join("/")} (${u.messageCount} msgs)`))):r+=1}catch(u){console.error(c.err(` ! failed: ${l.sessionFile}`),u)}let d=((Date.now()-a)/1e3).toFixed(1);console.log(""),console.log(`${c.ok("indexed")}: ${c.bold(String(n))} files, ${c.bold(String(o))} sessions, ${c.bold(String(i))} messages ${c.dim(`in ${d}s`)}`),r>0&&console.log(c.dim(`skipped: ${r} unchanged files (use --force to reindex)`))}w();v();import Ym from"cli-table3";function wi(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,
897
+ `),u=e.prepare("DELETE FROM messages WHERE session_id = ?"),p=0,m=0;if(e.transaction(()=>{for(let f of r.values()){d.run({id:f.sessionId,project_id:i,file_path:t.sessionFile,file_mtime:t.mtime,started_at:f.earliestTimestamp,ended_at:f.latestTimestamp,message_count:f.entries.length,user_message_count:f.userCount,assistant_message_count:f.assistantCount,first_user_message:f.firstUserMessage,cwd:f.cwd,git_branch:f.gitBranch,version:f.version,indexed_at:a}),u.run(f.sessionId);for(let h of f.entries){let{redacted:E}=we(h.contentText),{redacted:b}=we(h.raw);l.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}zn(e,f.sessionId,f.entries),zt(e,f.sessionId),p+=1}})(),nr().heuristicEnabled)for(let f of r.values()){let h=Qn(f.firstUserMessage);h&&er(f.sessionId,h,"heuristic")}return{inserted:!0,sessionCount:p,messageCount:m}}async function Ci(e){let t=_(),s=gi();console.log(c.dim(`Scanning ${s.length} JSONL session files under ~/.claude/projects/`));let n=0,r=0,o=0,i=0,a=Date.now();for(let l of s)try{let u=await Km(t,l,e.force??!1);u.inserted?(n+=1,o+=u.sessionCount,i+=u.messageCount,e.verbose&&console.log(c.dim(` + ${l.sessionFile.split("/").slice(-2).join("/")} (${u.messageCount} msgs)`))):r+=1}catch(u){console.error(c.err(` ! failed: ${l.sessionFile}`),u)}let d=((Date.now()-a)/1e3).toFixed(1);console.log(""),console.log(`${c.ok("indexed")}: ${c.bold(String(n))} files, ${c.bold(String(o))} sessions, ${c.bold(String(i))} messages ${c.dim(`in ${d}s`)}`),r>0&&console.log(c.dim(`skipped: ${r} unchanged files (use --force to reindex)`))}w();v();import Vm from"cli-table3";function Li(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,
901
898
  s.message_count, s.first_user_message, s.git_branch
902
899
  FROM sessions s
903
900
  JOIN projects p ON p.id = s.project_id
904
901
  WHERE ${r}
905
902
  ORDER BY COALESCE(s.started_at, '') DESC
906
- LIMIT @limit`).all(n);if(o.length===0){console.log(c.dim("no sessions found. run `recall index` first."));return}let i=new Ym({head:[c.bold("id"),c.bold("project"),c.bold("when"),c.bold("msgs"),c.bold("opening prompt")],colWidths:[10,22,14,6,70],wordWrap:!0,style:{head:[],border:["grey"]}});for(let a of o)i.push([c.accent(W(a.id)),c.project(q(a.project_name,20)),c.dim(X(a.started_at)),String(a.message_count),q(a.first_user_message,200)]);console.log(i.toString()),console.log(c.dim(`showing ${o.length} session${o.length===1?"":"s"}. use \`recall show <id>\` to view one.`))}w();v();import{spawn as sg}from"node:child_process";import{readFileSync as Gm,writeFileSync as zm,mkdirSync as Km,chmodSync as qm}from"node:fs";import{join as Ti}from"node:path";import{homedir as Ri}from"node:os";function xi(){return Ti(Ri(),".recall","config.json")}function ki(){try{return JSON.parse(Gm(xi(),"utf-8"))}catch{return{}}}function Vm(e){let t=xi();Km(Ti(Ri(),".recall"),{recursive:!0}),zm(t,JSON.stringify(e,null,2)+`
907
- `,"utf-8"),qm(t,384)}function ws(){let t=ki().verification;return typeof t=="object"&&t!==null&&"enabled"in t?!!t.enabled:!1}function sr(e){let t=ki();t.verification={...typeof t.verification=="object"&&t.verification!==null?t.verification:{},enabled:e},Vm(t)}w();var Zm=[/\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],Qm=1440*60*1e3;function eg(e){let t=_(),s=t.prepare(`SELECT content_text, tool_names FROM messages
903
+ LIMIT @limit`).all(n);if(o.length===0){console.log(c.dim("no sessions found. run `recall index` first."));return}let i=new Vm({head:[c.bold("id"),c.bold("project"),c.bold("when"),c.bold("msgs"),c.bold("opening prompt")],colWidths:[10,22,14,6,70],wordWrap:!0,style:{head:[],border:["grey"]}});for(let a of o)i.push([c.accent(X(a.id)),c.project(K(a.project_name,20)),c.dim(J(a.started_at)),String(a.message_count),K(a.first_user_message,200)]);console.log(i.toString()),console.log(c.dim(`showing ${o.length} session${o.length===1?"":"s"}. use \`recall show <id>\` to view one.`))}w();v();import{spawn as ag}from"node:child_process";import{readFileSync as Zm,writeFileSync as Qm,mkdirSync as eg,chmodSync as tg}from"node:fs";import{join as Ni}from"node:path";import{homedir as Ai}from"node:os";function Oi(){return Ni(Ai(),".recall","config.json")}function vi(){try{return JSON.parse(Zm(Oi(),"utf-8"))}catch{return{}}}function sg(e){let t=Oi();eg(Ni(Ai(),".recall"),{recursive:!0}),Qm(t,JSON.stringify(e,null,2)+`
904
+ `,"utf-8"),tg(t,384)}function ws(){let t=vi().verification;return typeof t=="object"&&t!==null&&"enabled"in t?!!t.enabled:!1}function rr(e){let t=vi();t.verification={...typeof t.verification=="object"&&t.verification!==null?t.verification:{},enabled:e},sg(t)}w();var ng=[/\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],rg=1440*60*1e3;function og(e){let t=_(),s=t.prepare(`SELECT content_text, tool_names FROM messages
908
905
  WHERE session_id = ? AND role = 'assistant'
909
- ORDER BY timestamp DESC LIMIT 5`).all(e),n=!1;for(let d of s)if(d.content_text&&Zm.some(l=>l.test(d.content_text))){n=!0;break}let r=t.prepare(`SELECT content_text, tool_names FROM messages
910
- WHERE session_id = ?`).all(e),o={fileWrites:!1,testRuns:!1,commits:!1,buildSuccess:!1};for(let d of r){let l=d.tool_names??"",u=d.content_text??"";/\bWrite\b|\bEdit\b/.test(l)&&(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 tg(e){let t=eg(e);return _().prepare("UPDATE sessions SET verification_status = ?, verification_computed_at = ? WHERE id = ?").run(t.status,Date.now(),e),t}function Ci(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<Qm){let n={fileWrites:!1,testRuns:!1,commits:!1,buildSuccess:!1};return{status:s.verification_status,evidence:n,claimFound:s.verification_status!=="neutral"}}return tg(e)}function ng(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(c.err(`ambiguous id prefix "${t}". be more specific.`)),null)}function rg(e,t){let s=_(),n=s.prepare(`SELECT s.id, p.name AS project_name, p.decoded_path,
906
+ ORDER BY timestamp DESC LIMIT 5`).all(e),n=!1;for(let d of s)if(d.content_text&&ng.some(l=>l.test(d.content_text))){n=!0;break}let r=t.prepare(`SELECT content_text, tool_names FROM messages
907
+ WHERE session_id = ?`).all(e),o={fileWrites:!1,testRuns:!1,commits:!1,buildSuccess:!1};for(let d of r){let l=d.tool_names??"",u=d.content_text??"";/\bWrite\b|\bEdit\b/.test(l)&&(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 ig(e){let t=og(e);return _().prepare("UPDATE sessions SET verification_status = ?, verification_computed_at = ? WHERE id = ?").run(t.status,Date.now(),e),t}function Ii(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<rg){let n={fileWrites:!1,testRuns:!1,commits:!1,buildSuccess:!1};return{status:s.verification_status,evidence:n,claimFound:s.verification_status!=="neutral"}}return ig(e)}function cg(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(c.err(`ambiguous id prefix "${t}". be more specific.`)),null)}function lg(e,t){let s=_(),n=s.prepare(`SELECT s.id, p.name AS project_name, p.decoded_path,
911
908
  s.started_at, s.ended_at, s.message_count,
912
909
  s.git_branch, s.version, s.cwd
913
910
  FROM sessions s
914
911
  JOIN projects p ON p.id = s.project_id
915
- WHERE s.id = ?`).get(e);if(!n)return null;let r=[],o=c.dim("\u2500".repeat(78));if(r.push(""),r.push(c.bold(c.project(n.project_name))+c.dim(` ${n.decoded_path}`)),r.push(c.dim(`session ${n.id} \xB7 ${n.message_count} msgs \xB7 ${X(n.started_at)}`+(n.git_branch?` \xB7 branch: ${n.git_branch}`:""))),ws()){let d=Ci(e);d.status==="verified"?r.push(c.ok("\u2713 verified")):d.status==="unverified"&&r.push(c.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
912
+ WHERE s.id = ?`).get(e);if(!n)return null;let r=[],o=c.dim("\u2500".repeat(78));if(r.push(""),r.push(c.bold(c.project(n.project_name))+c.dim(` ${n.decoded_path}`)),r.push(c.dim(`session ${n.id} \xB7 ${n.message_count} msgs \xB7 ${J(n.started_at)}`+(n.git_branch?` \xB7 branch: ${n.git_branch}`:""))),ws()){let d=Ii(e);d.status==="verified"?r.push(c.ok("\u2713 verified")):d.status==="unverified"&&r.push(c.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
916
913
  FROM messages
917
914
  WHERE session_id = ?
918
915
  ORDER BY COALESCE(timestamp, ''), rowid
919
916
  LIMIT ?`).all(e,i);for(let d of a){if(t.raw){r.push(d.raw_json);continue}let l=d.is_sidechain===1?c.dim(" [subagent]"):"",u=d.role==="user"?c.user("\u25B8 user"):d.role==="assistant"?c.assistant("\u25B8 assistant"):c.dim(`\u25B8 ${d.type}`);if(r.push(`${u}${l} ${c.dim(d.timestamp??"")}`),d.tool_names&&d.tool_names.length>0&&r.push(c.tool(` tools: ${d.tool_names}`)),d.content_text&&d.content_text.trim()){let p=d.content_text.trim().split(`
920
917
  `).map(m=>" "+m).join(`
921
918
  `);r.push(p)}r.push("")}return r.push(o),r.push(c.dim(`end of session ${n.id}`)),r.join(`
922
- `)}function og(e,t){if(!t||!process.stdout.isTTY)return!1;let s=process.stdout.rows||24;return e.split(`
923
- `).length>s}function ig(e){let t=sg("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 Li(e,t){let s=_(),n=ng(s,e);if(!n){e.length>=32&&console.error(c.err(`session not found: ${e}`)),process.exitCode=1;return}let r=rg(n,t);if(r===null){console.error(c.err(`session metadata missing for ${n}`)),process.exitCode=1;return}let o=t.pager!==!1;og(r,o)?ig(r):console.log(r)}w();v();le();D();import{existsSync as Pg,readFileSync as Fg}from"node:fs";import{join as jg}from"node:path";pr();function Bi(e){let t=Ui(),s={...e};return t&&(s["x-recall-token"]=t),s}async function ze(e,t){let s=t?.headers??{};return fetch(e,{...t,headers:Bi(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:Bi(r),body:s!==void 0?JSON.stringify(s):void 0})}function Hi(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 Ug(e,t){let s=jg(x,"daemon.port");Pg(s)||(console.error(c.err("Semantic search requires the daemon to be running.")),console.error(c.dim(" Start it with: recall start")),console.error(c.dim(' Then re-run: recall search "your query" --semantic')),process.exit(1));let n;try{n=Fg(s,"utf8").trim(),/^\d+$/.test(n)||(console.error(c.err(`Daemon port file is corrupt at ${s}.`)),console.error(c.dim(" Restart the daemon: recall stop && recall start")),process.exit(1))}catch(p){console.error(c.err(`Could not read daemon port: ${p instanceof Error?p.message:String(p)}`)),process.exit(1)}let r=Math.max(1,Math.min(200,parseInt(t.limit??"20",10)||20)),o=Hi(e);if(!o){console.log(c.dim("empty query"));return}let i=new URLSearchParams({q:o,mode:"semantic",limit:String(r)});t.project&&i.set("project",t.project);let a;try{a=await ze(`http://127.0.0.1:${n}/api/search?${i.toString()}`)}catch(p){console.error(c.err("Could not reach the daemon for semantic search.")),console.error(c.dim(` ${p instanceof Error?p.message:String(p)}`)),console.error(c.dim(" Is the daemon still running? Try: recall status")),process.exit(1)}if(!a.ok){console.error(c.err(`Semantic search failed: HTTP ${a.status}`));try{let p=await a.text();p&&console.error(c.dim(` ${p.slice(0,500)}`))}catch{}process.exit(1)}let d=await a.json(),l=d.hits??[];if(l.length===0){console.log(c.dim(`no matches for "${e}"`));return}let u=d.fusion==="rrf"?"semantic (BM25 + summary + vector, RRF-fused)":"semantic";console.log(c.dim(`${l.length} match${l.length===1?"":"es"} for "${e}" ${c.dim("\xB7 mode:")} ${u}`)),console.log("");for(let p of l){let m=(p.snippet??"").replace(/<<([\s\S]*?)>>/g,(E,b)=>Jn(b,b).replace(/\n/g," ")).replace(/\n/g," "),g=p.role==="user"?c.user("user"):p.role==="assistant"?c.assistant("asst"):c.dim("----"),f=p.lanes&&p.lanes.length>0?c.dim(`[${p.lanes.join("+")}]`):p.matched_via?c.dim(`[${p.matched_via}]`):"",h=p.project??"(unknown)";console.log(`${c.accent(W(p.session_id))} ${c.project(q(h,20))} ${c.dim(X(p.started_at))} ${g} ${f}`),console.log(` ${q(m,200)}`),console.log("")}console.log(c.dim("`recall show <id>` to read any session."))}async function Wi(e,t){if(await Ne("Full-text search"),t.semantic){await Ug(e,t);return}let s=_(),n=Hi(e);if(!n){console.log(c.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,
919
+ `)}function dg(e,t){if(!t||!process.stdout.isTTY)return!1;let s=process.stdout.rows||24;return e.split(`
920
+ `).length>s}function ug(e){let t=ag("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 Mi(e,t){let s=_(),n=cg(s,e);if(!n){e.length>=32&&console.error(c.err(`session not found: ${e}`)),process.exitCode=1;return}let r=lg(n,t);if(r===null){console.error(c.err(`session metadata missing for ${n}`)),process.exitCode=1;return}let o=t.pager!==!1;dg(r,o)?ug(r):console.log(r)}w();v();de();P();import{existsSync as Hg,readFileSync as Wg}from"node:fs";import{join as Xg}from"node:path";gr();function Yi(e){let t=Gi(),s={...e};return t&&(s["x-recall-token"]=t),s}async function ze(e,t){let s=t?.headers??{};return fetch(e,{...t,headers:Yi(s)})}async function st(e,t,s,n){let r=s!==void 0?{"content-type":"application/json",...n}:{...n};return fetch(t,{method:e,headers:Yi(r),body:s!==void 0?JSON.stringify(s):void 0})}function zi(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 Jg(e,t){let s=Xg(x,"daemon.port");Hg(s)||(console.error(c.err("Semantic search requires the daemon to be running.")),console.error(c.dim(" Start it with: recall start")),console.error(c.dim(' Then re-run: recall search "your query" --semantic')),process.exit(1));let n;try{n=Wg(s,"utf8").trim(),/^\d+$/.test(n)||(console.error(c.err(`Daemon port file is corrupt at ${s}.`)),console.error(c.dim(" Restart the daemon: recall stop && recall start")),process.exit(1))}catch(p){console.error(c.err(`Could not read daemon port: ${p instanceof Error?p.message:String(p)}`)),process.exit(1)}let r=Math.max(1,Math.min(200,parseInt(t.limit??"20",10)||20)),o=zi(e);if(!o){console.log(c.dim("empty query"));return}let i=new URLSearchParams({q:o,mode:"semantic",limit:String(r)});t.project&&i.set("project",t.project);let a;try{a=await ze(`http://127.0.0.1:${n}/api/search?${i.toString()}`)}catch(p){console.error(c.err("Could not reach the daemon for semantic search.")),console.error(c.dim(` ${p instanceof Error?p.message:String(p)}`)),console.error(c.dim(" Is the daemon still running? Try: recall status")),process.exit(1)}if(!a.ok){console.error(c.err(`Semantic search failed: HTTP ${a.status}`));try{let p=await a.text();p&&console.error(c.dim(` ${p.slice(0,500)}`))}catch{}process.exit(1)}let d=await a.json(),l=d.hits??[];if(l.length===0){console.log(c.dim(`no matches for "${e}"`));return}let u=d.fusion==="rrf"?"semantic (BM25 + summary + vector, RRF-fused)":"semantic";console.log(c.dim(`${l.length} match${l.length===1?"":"es"} for "${e}" ${c.dim("\xB7 mode:")} ${u}`)),console.log("");for(let p of l){let m=(p.snippet??"").replace(/<<([\s\S]*?)>>/g,(E,b)=>Yn(b,b).replace(/\n/g," ")).replace(/\n/g," "),g=p.role==="user"?c.user("user"):p.role==="assistant"?c.assistant("asst"):c.dim("----"),f=p.lanes&&p.lanes.length>0?c.dim(`[${p.lanes.join("+")}]`):p.matched_via?c.dim(`[${p.matched_via}]`):"",h=p.project??"(unknown)";console.log(`${c.accent(X(p.session_id))} ${c.project(K(h,20))} ${c.dim(J(p.started_at))} ${g} ${f}`),console.log(` ${K(m,200)}`),console.log("")}console.log(c.dim("`recall show <id>` to read any session."))}async function qi(e,t){if(await Ne("Full-text search"),t.semantic){await Jg(e,t);return}let s=_(),n=zi(e);if(!n){console.log(c.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,
924
921
  p.name AS project_name,
925
922
  s.started_at AS started_at,
926
923
  snippet(messages_fts, 0, '<<', '>>', '\u2026', 16) AS snippet,
@@ -933,13 +930,13 @@ ${o}
933
930
  WHERE messages_fts MATCH @q
934
931
  ${i}
935
932
  ORDER BY bm25(messages_fts)
936
- LIMIT @limit`).all(o);if(a.length===0){console.log(c.dim(`no matches for "${e}"`));return}console.log(c.dim(`${a.length} match${a.length===1?"":"es"} for "${e}"`)),console.log("");for(let d of a){let l=d.snippet.replace(/<<([\s\S]*?)>>/g,(p,m)=>Jn(m,m).replace(/\n/g," ")).replace(/\n/g," "),u=d.role==="user"?c.user("user"):d.role==="assistant"?c.assistant("asst"):c.dim("----");console.log(`${c.accent(W(d.session_id))} ${c.project(q(d.project_name,20))} ${c.dim(X(d.started_at))} ${u}`),console.log(` ${q(l,200)}`),console.log("")}console.log(c.dim("`recall show <id>` to read any session."))}w();D();Ke();v();import{statSync as Jg,existsSync as Yg}from"node:fs";function Ji(){if(console.log(""),console.log(c.bold("Claude Recall status")),console.log(c.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),!Yg(te)){console.log(c.dim(" no database yet. run `recall index`."));return}let t=_().prepare(`SELECT
933
+ LIMIT @limit`).all(o);if(a.length===0){console.log(c.dim(`no matches for "${e}"`));return}console.log(c.dim(`${a.length} match${a.length===1?"":"es"} for "${e}"`)),console.log("");for(let d of a){let l=d.snippet.replace(/<<([\s\S]*?)>>/g,(p,m)=>Yn(m,m).replace(/\n/g," ")).replace(/\n/g," "),u=d.role==="user"?c.user("user"):d.role==="assistant"?c.assistant("asst"):c.dim("----");console.log(`${c.accent(X(d.session_id))} ${c.project(K(d.project_name,20))} ${c.dim(J(d.started_at))} ${u}`),console.log(` ${K(l,200)}`),console.log("")}console.log(c.dim("`recall show <id>` to read any session."))}w();P();qe();v();import{statSync as Kg,existsSync as Vg}from"node:fs";function Vi(){if(console.log(""),console.log(c.bold("Claude Recall status")),console.log(c.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),!Vg(se)){console.log(c.dim(" no database yet. run `recall index`."));return}let t=_().prepare(`SELECT
937
934
  (SELECT COUNT(*) FROM projects) AS projects,
938
935
  (SELECT COUNT(*) FROM sessions) AS sessions,
939
936
  (SELECT COUNT(*) FROM messages) AS messages,
940
937
  (SELECT MIN(started_at) FROM sessions WHERE started_at IS NOT NULL) AS earliest,
941
938
  (SELECT MAX(started_at) FROM sessions WHERE started_at IS NOT NULL) AS latest,
942
- (SELECT MAX(indexed_at) FROM sessions) AS last_indexed`).get(),n=(Jg(te).size/1024/1024).toFixed(1);console.log(` db path ${c.dim(te)}`),console.log(` db size ${c.accent(n+" MB")}`),console.log(` projects ${c.accent(String(t.projects))}`),console.log(` sessions ${c.accent(String(t.sessions))}`),console.log(` messages ${c.accent(String(t.messages))}`),console.log(` earliest ${c.dim(t.earliest??"n/a")}`),console.log(` latest ${c.dim(t.latest??"n/a")} ${c.dim(X(t.latest))}`),console.log(` last index ${c.dim(t.last_indexed??"never")}`),console.log("");let r=Q();r?(console.log(` daemon ${c.ok("running")} pid ${r.pid} \xB7 http://127.0.0.1:${r.port}`),console.log(` started ${c.dim(r.startedAt)} ${c.dim(X(r.startedAt))}`)):console.log(` daemon ${c.dim("stopped")} (run \`recall start\` or \`recall open\`)`),console.log("")}w();v();import Gg from"cli-table3";function Yi(){let t=_().prepare(`SELECT p.name,
939
+ (SELECT MAX(indexed_at) FROM sessions) AS last_indexed`).get(),n=(Kg(se).size/1024/1024).toFixed(1);console.log(` db path ${c.dim(se)}`),console.log(` db size ${c.accent(n+" MB")}`),console.log(` projects ${c.accent(String(t.projects))}`),console.log(` sessions ${c.accent(String(t.sessions))}`),console.log(` messages ${c.accent(String(t.messages))}`),console.log(` earliest ${c.dim(t.earliest??"n/a")}`),console.log(` latest ${c.dim(t.latest??"n/a")} ${c.dim(J(t.latest))}`),console.log(` last index ${c.dim(t.last_indexed??"never")}`),console.log("");let r=Q();r?(console.log(` daemon ${c.ok("running")} pid ${r.pid} \xB7 http://127.0.0.1:${r.port}`),console.log(` started ${c.dim(r.startedAt)} ${c.dim(J(r.startedAt))}`)):console.log(` daemon ${c.dim("stopped")} (run \`recall start\` or \`recall open\`)`),console.log("")}w();v();import Zg from"cli-table3";function Zi(){let t=_().prepare(`SELECT p.name,
943
940
  p.decoded_path,
944
941
  COUNT(s.id) AS session_count,
945
942
  COALESCE(SUM(s.message_count), 0) AS message_count,
@@ -947,10 +944,13 @@ ${o}
947
944
  FROM projects p
948
945
  LEFT JOIN sessions s ON s.project_id = p.id
949
946
  GROUP BY p.id
950
- ORDER BY MAX(COALESCE(s.started_at, '')) DESC`).all();if(t.length===0){console.log(c.dim("no projects indexed yet."));return}let s=new Gg({head:[c.bold("project"),c.bold("sessions"),c.bold("msgs"),c.bold("latest"),c.bold("path")],style:{head:[],border:["grey"]}});for(let n of t)s.push([c.project(q(n.name,30)),String(n.session_count),String(n.message_count),c.dim(X(n.latest)),c.dim(q(n.decoded_path,50))]);console.log(s.toString())}Ke();Ke();D();v();st();import{spawn as qg}from"node:child_process";import{openSync as Vg}from"node:fs";import{join as Zg}from"node:path";function Qg(){return Zg(de(),"dist","daemon","entrypoint.js")}async function Os(){let e=Q();if(e){console.log(`${c.ok("already running")} pid ${e.pid} \xB7 http://127.0.0.1:${e.port}`);return}P();let t=Vg(Ns,"a"),s=Qg();qg(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(`${c.ok("daemon started")} pid ${o.pid} \xB7 http://127.0.0.1:${o.port}`),console.log(c.dim(`logs: ${Ns}`));return}}console.error(c.err("daemon did not come up within 5s \u2014 check the log file")),console.error(c.dim(` ${Ns}`)),process.exitCode=1}Ke();v();async function zi(e,t){let s=Date.now();for(;Date.now()-s<t;)if(await new Promise(n=>setTimeout(n,100)),!fr(e))return!0;return!1}async function Ki(){let e=Q();if(!e){console.log(c.dim("no daemon running.")),Zt();return}try{process.kill(e.pid,"SIGTERM")}catch(t){console.error(c.err(`failed to signal pid ${e.pid}: ${t.message}`)),process.exitCode=1;return}if(await zi(e.pid,5e3)){console.log(c.ok(`stopped daemon pid ${e.pid}`));return}console.log(c.dim(`pid ${e.pid} ignored SIGTERM after 5s \u2014 escalating to SIGKILL`));try{process.kill(e.pid,"SIGKILL")}catch(t){if(t.code==="ESRCH"){Zt(),console.log(c.ok(`stopped daemon pid ${e.pid}`));return}console.error(c.err(`failed to SIGKILL pid ${e.pid}: ${t.message}`)),process.exitCode=1;return}if(await zi(e.pid,2e3)){Zt(),console.log(c.ok(`stopped daemon pid ${e.pid} (forced)`));return}console.error(c.err(`pid ${e.pid} survived SIGKILL \u2014 kernel is unhappy, kill manually with: kill -9 ${e.pid}`)),process.exitCode=1}Ke();import{spawn as ef}from"node:child_process";import{platform as vs}from"node:os";v();function tf(e){let t=vs()==="darwin"?"open":vs()==="win32"?"start":"xdg-open",s=vs()==="win32"?["",e]:[e];ef(t,s,{detached:!0,stdio:"ignore",shell:vs()==="win32"}).unref()}async function qi(){let e=Q();if(!e&&(console.log(c.dim("daemon not running \u2014 starting it\u2026")),await Os(),e=Q(),!e)){console.error(c.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(`${c.ok("opening")} ${t}`),tf(t)}w();var sf=/<(local-command-caveat|local-command-stdout|command-name|command-message|command-args|system-reminder|user-prompt-submit-hook|task-notification)[\s\S]*?<\/\1>/gi,nf=/⚡ \*\*Tool call · `[^`]+`\*\*\s*\n+```json\n[\s\S]*?\n```/g,rf=/\*\*Tool result\*\*\s*\n+```\n[\s\S]*?\n```/g;function of(e){return e.replace(sf,"").trim()}function af(e){let t=e.replace(nf,"[tool call]");return t=t.replace(rf,"[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,`
947
+ ORDER BY MAX(COALESCE(s.started_at, '')) DESC`).all();if(t.length===0){console.log(c.dim("no projects indexed yet."));return}let s=new Zg({head:[c.bold("project"),c.bold("sessions"),c.bold("msgs"),c.bold("latest"),c.bold("path")],style:{head:[],border:["grey"]}});for(let n of t)s.push([c.project(K(n.name,30)),String(n.session_count),String(n.message_count),c.dim(J(n.latest)),c.dim(K(n.decoded_path,50))]);console.log(s.toString())}qe();qe();P();v();Ke();import{spawn as tf}from"node:child_process";import{openSync as sf}from"node:fs";import{join as nf}from"node:path";function rf(){return nf(ee(),"dist","daemon","entrypoint.js")}async function Os(){let e=Q();if(e){console.log(`${c.ok("already running")} pid ${e.pid} \xB7 http://127.0.0.1:${e.port}`);return}F();let t=sf(Ns,"a"),s=rf();tf(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(`${c.ok("daemon started")} pid ${o.pid} \xB7 http://127.0.0.1:${o.port}`),console.log(c.dim(`logs: ${Ns}`));return}}console.error(c.err("daemon did not come up within 5s \u2014 check the log file")),console.error(c.dim(` ${Ns}`)),process.exitCode=1}qe();import*as na from"node:readline";import{execFileSync as ta}from"node:child_process";function Qt(e={}){let t=e.psOutput??of(),s=e.isProcessAlive??af,n=e.getParentCommand??cf,r=[];for(let o of t.split(`
948
+ `)){let i=o.trim();if(!i||!i.includes("dist/mcp/server.js")||lf(i))continue;let a=i.split(/\s+/);if(a.length<5)continue;let d=Number(a[0]),l=Number(a[1]),u=a[2],p=Number(a[3]);if(!Number.isFinite(d)||!Number.isFinite(l))continue;let m=l>1&&s(l);r.push({pid:d,ppid:l,parentAlive:m,etimeSeconds:df(u),pcpu:Number.isFinite(p)?p:0,orphan:!m,parentCommand:m?n(l):null})}return r}function of(){try{return ta("ps",["-eo","pid,ppid,etime,pcpu,command"],{encoding:"utf8",timeout:2e3,maxBuffer:5*1024*1024})}catch(e){let t=e instanceof Error?e.message:String(e);return process.stderr.write(`[mcp-processes] ps -eo failed: ${t}
949
+ `),""}}function af(e){if(!Number.isFinite(e)||e<=1)return!1;try{return process.kill(e,0),!0}catch{return!1}}function cf(e){if(!Number.isFinite(e)||e<=1)return null;try{let s=ta("ps",["-p",String(e),"-o","command="],{encoding:"utf8",timeout:1e3,maxBuffer:1048576}).trim();return s.length?s.slice(0,200):null}catch{return null}}function lf(e){let t=e.split(/\s+/);if(t.length<5)return!1;let s=t[4]??"";return s.endsWith("/grep")||s==="grep"||s.endsWith("/awk")||s==="awk"||s.endsWith("/rg")||s==="rg"}function df(e){if(!e)return 0;let t=0,s=e,n=e.indexOf("-");n>=0&&(t=ea(e.slice(0,n)),s=e.slice(n+1));let r=s.split(":").map(ea),o=0,i=0,a=0;return r.length===3?[o,i,a]=r:r.length===2?[i,a]=r:r.length===1&&(a=r[0]),t*86400+o*3600+i*60+a}function ea(e){let t=Number(e);return Number.isFinite(t)?t:0}var uf=50,pf=60;function vs(e){return e.pcpu>=uf&&e.etimeSeconds>=pf}w();function It(e){if(e<60)return`${e}s`;if(e<3600)return`${Math.floor(e/60)}m`;if(e<86400)return`${Math.floor(e/3600)}h`;let t=Math.floor(e/86400),s=Math.floor(e%86400/3600);return s>0?`${t}d ${s}h`:`${t}d`}var RC=5*6e4,sa=1073741824;var mf=100;function Is(e,t="PASSIVE",s){let n=Date.now(),r=e.pragma(`wal_checkpoint(${t})`),o=gf(r),i={busy:o.busy,log:o.log,moved:o.checkpointed,mode:t,durationMs:Date.now()-n};return s&&(t==="PASSIVE"&&i.log>=mf&&i.moved===0?s(`[wal-maintenance] PASSIVE checkpoint blocked: log=${i.log} frames pending, moved=0 (readers holding snapshots)`):i.moved>0&&s(`[wal-maintenance] ${t} checkpoint: log=${i.log} moved=${i.moved} busy=${i.busy} (${i.durationMs}ms)`)),i}function gf(e){let t=Array.isArray(e)?e[0]??{}:e??{};return{busy:br(t.busy),log:br(t.log),checkpointed:br(t.checkpointed)}}function br(e){return typeof e=="number"&&Number.isFinite(e)?e:typeof e=="bigint"?Number(e):0}var ff=2e3;async function Ms(e={}){let t=e.list??Qt,s=e.kill??_f,n=e.confirm??bf,r=e.sleep??hf,o=e.logger??(g=>{process.stdout.write(g+`
950
+ `)}),i=e.truncateWal??Ef,a=!!e.json,d=a||!!e.yes,l=!!e.all,u=t(),p=l?u:u.filter(g=>g.orphan),m={found:p.length,killed:[],failed:[],walTruncated:!1};if(p.length===0)return o(a?JSON.stringify(m):l?"No MCP children running.":"No orphaned MCP children to prune."),0;if(!a){o(l?`Found ${p.length} MCP child${p.length===1?"":"ren"} (will prune all):`:`Found ${p.length} orphaned MCP child${p.length===1?"":"ren"}:`);for(let g of p){let f=g.orphan?" (orphan)":"";o(` pid ${g.pid} ppid ${g.ppid} age ${It(g.etimeSeconds)}${f}`)}}if(!d&&!await n("Kill these processes? [y/N] "))return o("Aborted."),0;for(let g of p)try{s(g.pid,"SIGTERM"),m.killed.push(g.pid)}catch(f){m.failed.push({pid:g.pid,reason:Sr(f)})}await r(ff);for(let g of[...m.killed])try{s(g,0);try{s(g,"SIGKILL")}catch(f){m.killed=m.killed.filter(h=>h!==g),m.failed.push({pid:g,reason:Sr(f)})}}catch{}if(m.killed.length>0)try{i(),m.walTruncated=!0}catch(g){a||o(` (WAL truncate skipped: ${Sr(g)})`)}if(a)o(JSON.stringify(m));else{o(""),o(`Pruned ${m.killed.length}/${p.length}`+(m.failed.length>0?` -- ${m.failed.length} failed`:"")+(m.walTruncated?". WAL truncated.":"."));for(let g of m.failed)o(` pid ${g.pid}: ${g.reason}`)}return m.failed.length===0?0:1}function _f(e,t){process.kill(e,t)}function hf(e){return new Promise(t=>{setTimeout(t,e)})}function Ef(){Is(_(),"TRUNCATE")}function bf(e){return new Promise(t=>{let s=na.createInterface({input:process.stdin,output:process.stderr});s.question(e,n=>{s.close();let r=n.trim().toLowerCase();t(r==="y"||r==="yes")})})}function Sr(e){if(e instanceof Error){let t=e.code;return t?`${t} ${e.message}`:e.message}return String(e)}w();v();async function ra(e={}){let t=e.logger??(u=>console.log(u)),s=e.logErr??(u=>console.error(u)),n=e.getRunningDaemon??Q,r=e.isProcessAlive??Er,o=e.clearDaemonInfo??hr,i=e.sleep??(u=>new Promise(p=>setTimeout(p,u))),a=e.kill??((u,p)=>{process.kill(u,p)}),d=e.truncateWal??yf,l=await Sf({log:t,logErr:s,getDaemon:n,isAlive:r,clearInfo:o,kill:a,sleep:i});return e.all&&(await Ms({all:!0,yes:!0,list:e.listMcpProcesses,kill:e.kill,sleep:e.sleep,logger:t,truncateWal:d}),d()),l?0:1}async function Sf(e){let t=e.getDaemon();if(!t)return e.log(c.dim("no daemon running.")),e.clearInfo(),!0;try{e.kill(t.pid,"SIGTERM")}catch(s){return e.logErr(c.err(`failed to signal pid ${t.pid}: ${s.message}`)),!1}for(let s=0;s<50;s++)if(await e.sleep(100),!e.isAlive(t.pid))return e.clearInfo(),e.log(c.ok(`stopped daemon pid ${t.pid}`)),!0;e.log(c.dim(`pid ${t.pid} ignored SIGTERM after 5s -- escalating to SIGKILL`));try{e.kill(t.pid,"SIGKILL")}catch(s){return s.code==="ESRCH"?(e.clearInfo(),e.log(c.ok(`stopped daemon pid ${t.pid}`)),!0):(e.logErr(c.err(`failed to SIGKILL pid ${t.pid}: ${s.message}`)),!1)}for(let s=0;s<20;s++)if(await e.sleep(100),!e.isAlive(t.pid))return e.clearInfo(),e.log(c.ok(`stopped daemon pid ${t.pid} (forced)`)),!0;return e.logErr(c.err(`pid ${t.pid} survived SIGKILL -- kill manually: kill -9 ${t.pid}`)),!1}function yf(){try{Is(_(),"TRUNCATE")}catch(e){console.warn(c.dim(`WAL truncate skipped: ${e.message}`))}}qe();import{spawn as wf}from"node:child_process";import{platform as Ds}from"node:os";v();function Tf(e){let t=Ds()==="darwin"?"open":Ds()==="win32"?"start":"xdg-open",s=Ds()==="win32"?["",e]:[e];wf(t,s,{detached:!0,stdio:"ignore",shell:Ds()==="win32"}).unref()}async function oa(){let e=Q();if(!e&&(console.log(c.dim("daemon not running \u2014 starting it\u2026")),await Os(),e=Q(),!e)){console.error(c.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(`${c.ok("opening")} ${t}`),Tf(t)}w();var Rf=/<(local-command-caveat|local-command-stdout|command-name|command-message|command-args|system-reminder|user-prompt-submit-hook|task-notification)[\s\S]*?<\/\1>/gi,xf=/⚡ \*\*Tool call · `[^`]+`\*\*\s*\n+```json\n[\s\S]*?\n```/g,kf=/\*\*Tool result\*\*\s*\n+```\n[\s\S]*?\n```/g;function Cf(e){return e.replace(Rf,"").trim()}function Lf(e){let t=e.replace(xf,"[tool call]");return t=t.replace(kf,"[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,`
951
951
 
952
- `),t.trim()}function cf(e){return e.role??e.type??"message"}function Vi(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 d=0,l=0;for(let u of i){let p=u.content_text??"",m=of(p);n==="condensed"&&(m=af(m));let g=m.length>0,f=!!u.tool_names&&u.tool_names.length>0;if(!g&&!f){l+=1;continue}let h=cf(u),E=u.timestamp?` \`${u.timestamp}\``:"";a.push(`## ${h}${E}`),a.push(""),f&&n==="condensed"&&(a.push(`_tools used: ${u.tool_names}_`),a.push("")),g&&(a.push(m),a.push("")),d+=1}return a.push("---"),a.push(""),a.push(`_${d} messages included_`+(l?`, ${l} empty skipped`:"")+(r?"":", subagent/sidechain hidden")+"."),a.join(`
953
- `)}w();D();import{randomUUID as Zi}from"node:crypto";import{writeFileSync as Qi,readFileSync as gC,existsSync as lf,mkdirSync as df}from"node:fs";import{join as _r}from"node:path";var Is=_r(x,"threads"),uf=_r(Is,"index.json");function ea(){P(),lf(Is)||df(Is,{recursive:!0})}function ta(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 sa(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,
952
+ `),t.trim()}function Nf(e){return e.role??e.type??"message"}function ia(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 d=0,l=0;for(let u of i){let p=u.content_text??"",m=Cf(p);n==="condensed"&&(m=Lf(m));let g=m.length>0,f=!!u.tool_names&&u.tool_names.length>0;if(!g&&!f){l+=1;continue}let h=Nf(u),E=u.timestamp?` \`${u.timestamp}\``:"";a.push(`## ${h}${E}`),a.push(""),f&&n==="condensed"&&(a.push(`_tools used: ${u.tool_names}_`),a.push("")),g&&(a.push(m),a.push("")),d+=1}return a.push("---"),a.push(""),a.push(`_${d} messages included_`+(l?`, ${l} empty skipped`:"")+(r?"":", subagent/sidechain hidden")+"."),a.join(`
953
+ `)}w();P();import{randomUUID as aa}from"node:crypto";import{writeFileSync as ca,readFileSync as GC,existsSync as Af,mkdirSync as Of}from"node:fs";import{join as yr}from"node:path";var $s=yr(x,"threads"),vf=yr($s,"index.json");function la(){F(),Af($s)||Of($s,{recursive:!0})}function da(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 ua(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,
954
954
  p.name AS project,
955
955
  COUNT(*) AS n,
956
956
  SUM(CASE WHEN te.role = 'origin' THEN 1 ELSE 0 END) AS origin_n
@@ -958,7 +958,7 @@ ${o}
958
958
  LEFT JOIN sessions s ON s.id = te.session_id
959
959
  LEFT JOIN projects p ON p.id = s.project_id
960
960
  WHERE te.thread_id IN (${n})
961
- 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 d=a.filter(p=>p.project!==null),l=d.length,u=null;d.length>0&&(u=[...d].sort((m,g)=>g.n-m.n||g.origin_n-m.origin_n||(m.project??"").localeCompare(g.project??""))[0].project),t.set(i,{project:u,project_count:l})}return t}function na(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 ra(e){let s=_().prepare(`SELECT NULLIF(sa.alias, '') AS alias,
961
+ 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 d=a.filter(p=>p.project!==null),l=d.length,u=null;d.length>0&&(u=[...d].sort((m,g)=>g.n-m.n||g.origin_n-m.origin_n||(m.project??"").localeCompare(g.project??""))[0].project),t.set(i,{project:u,project_count:l})}return t}function pa(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 ma(e){let s=_().prepare(`SELECT NULLIF(sa.alias, '') AS alias,
962
962
  s.auto_title AS auto_title,
963
963
  s.auto_title_source AS auto_title_source,
964
964
  s.first_user_message AS first_user_message,
@@ -966,11 +966,11 @@ ${o}
966
966
  FROM (SELECT ? AS sid) q
967
967
  LEFT JOIN sessions s ON s.id = q.sid
968
968
  LEFT JOIN session_aliases sa ON sa.session_id = q.sid
969
- 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 oa(e){let s=_().prepare(`SELECT
969
+ 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 ga(e){let s=_().prepare(`SELECT
970
970
  COUNT(*) AS session_count,
971
971
  SUM(CASE WHEN role = 'origin' THEN 1 ELSE 0 END) AS origin_count
972
- FROM thread_edges WHERE thread_id = ?`).get(e);return{session_count:s?.session_count??0,origin_count:s?.origin_count??0}}function Ae(e){let t=Oe(e);t&&(ea(),Qi(_r(Is,`${e}.json`),JSON.stringify(t,null,2)),ia())}function ia(){ea();let e=hr({includeArchived:!0});Qi(uf,JSON.stringify({threads:e},null,2))}function aa(e){let t=e.name.trim();if(!t)throw new Error("thread name cannot be empty");let s=_(),n=Zi(),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)
973
- VALUES (?, ?, NULL, 'origin', 1.0, 'manual', ?)`).run(n,e.originSessionId,r),Ae(n);let o=Oe(n);if(!o)throw new Error("thread creation succeeded but read-back failed");return o}function hr(e={}){let t=_(),s=e.includeArchived?"":"WHERE archived = 0",n=t.prepare(`SELECT * FROM threads ${s} ORDER BY created_at DESC`).all(),r=sa(n.map(o=>o.id));return n.map(o=>ta(o,oa(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.*,
972
+ FROM thread_edges WHERE thread_id = ?`).get(e);return{session_count:s?.session_count??0,origin_count:s?.origin_count??0}}function Ae(e){let t=Oe(e);t&&(la(),ca(yr($s,`${e}.json`),JSON.stringify(t,null,2)),fa())}function fa(){la();let e=wr({includeArchived:!0});ca(vf,JSON.stringify({threads:e},null,2))}function _a(e){let t=e.name.trim();if(!t)throw new Error("thread name cannot be empty");let s=_(),n=aa(),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)
973
+ VALUES (?, ?, NULL, 'origin', 1.0, 'manual', ?)`).run(n,e.originSessionId,r),Ae(n);let o=Oe(n);if(!o)throw new Error("thread creation succeeded but read-back failed");return o}function wr(e={}){let t=_(),s=e.includeArchived?"":"WHERE archived = 0",n=t.prepare(`SELECT * FROM threads ${s} ORDER BY created_at DESC`).all(),r=ua(n.map(o=>o.id));return n.map(o=>da(o,ga(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.*,
974
974
  NULLIF(sa.alias, '') AS alias,
975
975
  s.auto_title AS auto_title,
976
976
  s.auto_title_source AS auto_title_source,
@@ -981,7 +981,7 @@ ${o}
981
981
  LEFT JOIN session_aliases sa ON sa.session_id = e.session_id
982
982
  LEFT JOIN projects p ON p.id = s.project_id
983
983
  WHERE e.thread_id = ?
984
- ORDER BY e.added_at ASC`).all(e).map(na),r=sa([e]).get(e);return{...ta(s,oa(s.id),r),edges:n}}function ca(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
984
+ ORDER BY e.added_at ASC`).all(e).map(pa),r=ua([e]).get(e);return{...da(s,ga(s.id),r),edges:n}}function ha(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
985
985
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
986
986
  VALUES (?, ?, ?, ?, ?, ?, ?)
987
987
  ON CONFLICT(thread_id, session_id) DO UPDATE SET
@@ -989,76 +989,73 @@ ${o}
989
989
  role = excluded.role,
990
990
  confidence = excluded.confidence,
991
991
  source = excluded.source,
992
- added_at = excluded.added_at`).run(e.threadId,e.sessionId,r,o,i,a,n),Ae(e.threadId);let d=ra(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:d.alias,auto_title:d.auto_title,auto_title_source:d.auto_title_source,alias_source:d.alias?"manual":null,first_user_message:d.first_user_message,project:d.project}}function la(e,t){let n=_().prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e,t);return n.changes>0&&Ae(e),{removed:n.changes}}function da(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 = ?"),d=s,l=new Set;for(;d!==null;){if(d===t)throw new Error(`cycle detected: setting parent of ${t} to ${s} would create a loop`);if(l.has(d))break;l.add(d),d=a.get(e,d)?.parent_session_id??null}}let o=s?"child":"origin";n.prepare(`UPDATE thread_edges
992
+ added_at = excluded.added_at`).run(e.threadId,e.sessionId,r,o,i,a,n),Ae(e.threadId);let d=ma(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:d.alias,auto_title:d.auto_title,auto_title_source:d.auto_title_source,alias_source:d.alias?"manual":null,first_user_message:d.first_user_message,project:d.project}}function Ea(e,t){let n=_().prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e,t);return n.changes>0&&Ae(e),{removed:n.changes}}function ba(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 = ?"),d=s,l=new Set;for(;d!==null;){if(d===t)throw new Error(`cycle detected: setting parent of ${t} to ${s} would create a loop`);if(l.has(d))break;l.add(d),d=a.get(e,d)?.parent_session_id??null}}let o=s?"child":"origin";n.prepare(`UPDATE thread_edges
993
993
  SET parent_session_id = ?, role = ?, added_at = ?
994
- WHERE thread_id = ? AND session_id = ?`).run(s,o,new Date().toISOString(),e,t),Ae(e);let i=ra(t);return na({...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 ua(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),Ae(e);let r=Oe(e);if(!r)throw new Error(`thread ${e} not found`);return r}function pa(e){_().prepare("UPDATE threads SET closed_at = ? WHERE id = ?").run(new Date().toISOString(),e),Ae(e);let s=Oe(e);if(!s)throw new Error(`thread ${e} not found`);return s}function ma(e){_().prepare("UPDATE threads SET closed_at = NULL WHERE id = ?").run(e),Ae(e);let s=Oe(e);if(!s)throw new Error(`thread ${e} not found`);return s}function ga(e){_().prepare("UPDATE threads SET archived = 1 WHERE id = ?").run(e),Ae(e);let s=Oe(e);if(!s)throw new Error(`thread ${e} not found`);return s}function fa(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
994
+ WHERE thread_id = ? AND session_id = ?`).run(s,o,new Date().toISOString(),e,t),Ae(e);let i=ma(t);return pa({...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 Sa(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),Ae(e);let r=Oe(e);if(!r)throw new Error(`thread ${e} not found`);return r}function ya(e){_().prepare("UPDATE threads SET closed_at = ? WHERE id = ?").run(new Date().toISOString(),e),Ae(e);let s=Oe(e);if(!s)throw new Error(`thread ${e} not found`);return s}function wa(e){_().prepare("UPDATE threads SET closed_at = NULL WHERE id = ?").run(e),Ae(e);let s=Oe(e);if(!s)throw new Error(`thread ${e} not found`);return s}function Ta(e){_().prepare("UPDATE threads SET archived = 1 WHERE id = ?").run(e),Ae(e);let s=Oe(e);if(!s)throw new Error(`thread ${e} not found`);return s}function Ra(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
995
995
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
996
996
  VALUES (?, ?, ?, ?, ?, ?, ?)
997
997
  ON CONFLICT(thread_id, session_id) DO UPDATE SET
998
998
  parent_session_id = COALESCE(thread_edges.parent_session_id, excluded.parent_session_id),
999
999
  role = CASE WHEN thread_edges.role = 'origin' OR excluded.role = 'origin' THEN 'origin' ELSE 'child' END,
1000
1000
  confidence = MAX(thread_edges.confidence, excluded.confidence),
1001
- 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)})(),Ae(t),ia();let r=Oe(t);if(!r)throw new Error("merge destination disappeared");return r}function _a(e){if(e.sessionIds.length===0)throw new Error("no sessions to split off");let t=_(),s=new Date().toISOString(),n=Zi();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
1001
+ 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)})(),Ae(t),fa();let r=Oe(t);if(!r)throw new Error("merge destination disappeared");return r}function xa(e){if(e.sessionIds.length===0)throw new Error("no sessions to split off");let t=_(),s=new Date().toISOString(),n=aa();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
1002
1002
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
1003
- 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))}})(),Ae(e.threadId),Ae(n);let r=Oe(n);if(!r)throw new Error("split destination disappeared");return r}function ha(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]}v();le();w();D();import{writeFileSync as pf}from"node:fs";import{join as mf}from"node:path";var gf=mf(x,"recall-events.json");function Er(e,t,s,n="cli"){_().prepare(`
1003
+ 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))}})(),Ae(e.threadId),Ae(n);let r=Oe(n);if(!r)throw new Error("split destination disappeared");return r}function ka(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]}v();de();w();P();import{writeFileSync as If}from"node:fs";import{join as Mf}from"node:path";var Df=Mf(x,"recall-events.json");function Tr(e,t,s,n="cli"){_().prepare(`
1004
1004
  INSERT INTO recall_events (session_id, recalled_at, token_count, mode, caller)
1005
1005
  VALUES (?, datetime('now'), ?, ?, ?)
1006
- `).run(e,t,s,n),ff()}function ff(){P();let t=_().prepare("SELECT id, session_id, recalled_at, token_count, mode, caller FROM recall_events ORDER BY recalled_at DESC").all();pf(gf,JSON.stringify(t,null,2)+`
1007
- `,"utf-8")}function _f(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.
1008
- `),null)}function hf(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 Ef(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:
1009
- `);for(let n of s)process.stderr.write(` ${W(n.id)} ${n.name}
1010
- `);return null}function Ea(e,t,s){let n=e.prepare(`SELECT s.id, p.name AS project_name, p.decoded_path,
1006
+ `).run(e,t,s,n),$f()}function $f(){F();let t=_().prepare("SELECT id, session_id, recalled_at, token_count, mode, caller FROM recall_events ORDER BY recalled_at DESC").all();If(Df,JSON.stringify(t,null,2)+`
1007
+ `,"utf-8")}function Pf(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.
1008
+ `),null)}function Ff(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 jf(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:
1009
+ `);for(let n of s)process.stderr.write(` ${X(n.id)} ${n.name}
1010
+ `);return null}function Ca(e,t,s){let n=e.prepare(`SELECT s.id, p.name AS project_name, p.decoded_path,
1011
1011
  s.started_at, s.ended_at, s.message_count, s.git_branch
1012
1012
  FROM sessions s JOIN projects p ON p.id = s.project_id
1013
1013
  WHERE s.id = ?`).get(t);if(!n)return process.stderr.write(`session metadata missing for ${t}
1014
1014
  `),null;let r=e.prepare(`SELECT uuid, type, role, timestamp, is_sidechain, content_text, tool_names
1015
1015
  FROM messages
1016
1016
  WHERE session_id = ?
1017
- ORDER BY COALESCE(timestamp, ''), rowid`).all(t),o=s.full?"full":"condensed";return Vi(n,r,{mode:o,includeSidechain:s.subagents===!0,prelude:s.prelude??null,since:hf(s.since)})}async function ba(e,t){await Ne("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
1018
- `),process.exitCode=1;return}let a=Ef(s,i);if(!a){process.stderr.write(`thread not found: ${i}
1019
- `),process.exitCode=1;return}let d=ha(a);if(d.length===0){process.stderr.write(`thread ${i} has no linked sessions
1020
- `),process.exitCode=1;return}for(let l=0;l<d.length;l+=1){let u=d[l],p=Ea(s,u,{...t,prelude:l===0?t.prelude:void 0});if(p===null){process.exitCode=1;continue}l>0&&process.stdout.write(`
1017
+ ORDER BY COALESCE(timestamp, ''), rowid`).all(t),o=s.full?"full":"condensed";return ia(n,r,{mode:o,includeSidechain:s.subagents===!0,prelude:s.prelude??null,since:Ff(s.since)})}async function La(e,t){await Ne("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
1018
+ `),process.exitCode=1;return}let a=jf(s,i);if(!a){process.stderr.write(`thread not found: ${i}
1019
+ `),process.exitCode=1;return}let d=ka(a);if(d.length===0){process.stderr.write(`thread ${i} has no linked sessions
1020
+ `),process.exitCode=1;return}for(let l=0;l<d.length;l+=1){let u=d[l],p=Ca(s,u,{...t,prelude:l===0?t.prelude:void 0});if(p===null){process.exitCode=1;continue}l>0&&process.stdout.write(`
1021
1021
  ---
1022
1022
 
1023
1023
  `),process.stdout.write(p),p.endsWith(`
1024
1024
  `)||process.stdout.write(`
1025
- `),Er(u,Math.ceil(p.length/4),"thread","cli")}return}let n=_f(s,e);if(!n){e.length>=32&&process.stderr.write(`session not found: ${e}
1026
- `),process.exitCode=1;return}let r=Ea(s,n,t);if(r===null){process.exitCode=1;return}process.stdout.write(r),r.endsWith(`
1025
+ `),Tr(u,Math.ceil(p.length/4),"thread","cli")}return}let n=Pf(s,e);if(!n){e.length>=32&&process.stderr.write(`session not found: ${e}
1026
+ `),process.exitCode=1;return}let r=Ca(s,n,t);if(r===null){process.exitCode=1;return}process.stdout.write(r),r.endsWith(`
1027
1027
  `)||process.stdout.write(`
1028
- `);let o=t.since?"since":t.full?"full":"condensed";Er(n,Math.ceil(r.length/4),o,"cli"),process.stderr.isTTY&&process.stderr.write(`\x1B[2mShare this recall? \u2192 recall share\x1B[0m
1029
- `)}le();st();import{join as bf}from"node:path";import{spawn as Sf}from"node:child_process";async function Sa(e={}){await Ne("MCP server");let t=bf(de(),"dist","mcp-server.js"),s={...process.env};e.allowWrites&&(s.RECALL_MCP_ALLOW_WRITES="1");let n=Sf(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()})})}import*as xa from"node:readline";import{execFileSync as wa}from"node:child_process";function Ms(e={}){let t=e.psOutput??yf(),s=e.isProcessAlive??wf,n=e.getParentCommand??Tf,r=[];for(let o of t.split(`
1030
- `)){let i=o.trim();if(!i||!i.includes("dist/mcp/server.js")||Rf(i))continue;let a=i.split(/\s+/);if(a.length<4)continue;let d=Number(a[0]),l=Number(a[1]),u=a[2];if(!Number.isFinite(d)||!Number.isFinite(l))continue;let p=l>1&&s(l);r.push({pid:d,ppid:l,parentAlive:p,etimeSeconds:xf(u),orphan:!p,parentCommand:p?n(l):null})}return r}function yf(){try{return wa("ps",["-eo","pid,ppid,etime,command"],{encoding:"utf8",timeout:2e3,maxBuffer:5*1024*1024})}catch(e){let t=e instanceof Error?e.message:String(e);return process.stderr.write(`[mcp-processes] ps -eo failed: ${t}
1031
- `),""}}function wf(e){if(!Number.isFinite(e)||e<=1)return!1;try{return process.kill(e,0),!0}catch{return!1}}function Tf(e){if(!Number.isFinite(e)||e<=1)return null;try{let s=wa("ps",["-p",String(e),"-o","command="],{encoding:"utf8",timeout:1e3,maxBuffer:1048576}).trim();return s.length?s.slice(0,200):null}catch{return null}}function Rf(e){let t=e.split(/\s+/);if(t.length<4)return!1;let s=t[3]??"";return s.endsWith("/grep")||s==="grep"||s.endsWith("/awk")||s==="awk"||s.endsWith("/rg")||s==="rg"}function xf(e){if(!e)return 0;let t=0,s=e,n=e.indexOf("-");n>=0&&(t=ya(e.slice(0,n)),s=e.slice(n+1));let r=s.split(":").map(ya),o=0,i=0,a=0;return r.length===3?[o,i,a]=r:r.length===2?[i,a]=r:r.length===1&&(a=r[0]),t*86400+o*3600+i*60+a}function ya(e){let t=Number(e);return Number.isFinite(t)?t:0}w();function Qt(e){if(e<60)return`${e}s`;if(e<3600)return`${Math.floor(e/60)}m`;if(e<86400)return`${Math.floor(e/3600)}h`;let t=Math.floor(e/86400),s=Math.floor(e%86400/3600);return s>0?`${t}d ${s}h`:`${t}d`}var WC=5*6e4,Ta=1073741824;var kf=100;function Ra(e,t="PASSIVE",s){let n=Date.now(),r=e.pragma(`wal_checkpoint(${t})`),o=Cf(r),i={busy:o.busy,log:o.log,moved:o.checkpointed,mode:t,durationMs:Date.now()-n};return s&&(t==="PASSIVE"&&i.log>=kf&&i.moved===0?s(`[wal-maintenance] PASSIVE checkpoint blocked: log=${i.log} frames pending, moved=0 (readers holding snapshots)`):i.moved>0&&s(`[wal-maintenance] ${t} checkpoint: log=${i.log} moved=${i.moved} busy=${i.busy} (${i.durationMs}ms)`)),i}function Cf(e){let t=Array.isArray(e)?e[0]??{}:e??{};return{busy:br(t.busy),log:br(t.log),checkpointed:br(t.checkpointed)}}function br(e){return typeof e=="number"&&Number.isFinite(e)?e:typeof e=="bigint"?Number(e):0}var Lf=2e3;async function ka(e={}){let t=e.list??Ms,s=e.kill??Nf,n=e.confirm??vf,r=e.sleep??Af,o=e.logger??(g=>{process.stdout.write(g+`
1032
- `)}),i=e.truncateWal??Of,a=!!e.json,d=a||!!e.yes,l=!!e.all,u=t(),p=l?u:u.filter(g=>g.orphan),m={found:p.length,killed:[],failed:[],walTruncated:!1};if(p.length===0)return o(a?JSON.stringify(m):l?"No MCP children running.":"No orphaned MCP children to prune."),0;if(!a){o(l?`Found ${p.length} MCP child${p.length===1?"":"ren"} (will prune all):`:`Found ${p.length} orphaned MCP child${p.length===1?"":"ren"}:`);for(let g of p){let f=g.orphan?" (orphan)":"";o(` pid ${g.pid} ppid ${g.ppid} age ${Qt(g.etimeSeconds)}${f}`)}}if(!d&&!await n("Kill these processes? [y/N] "))return o("Aborted."),0;for(let g of p)try{s(g.pid,"SIGTERM"),m.killed.push(g.pid)}catch(f){m.failed.push({pid:g.pid,reason:Sr(f)})}await r(Lf);for(let g of[...m.killed])try{s(g,0);try{s(g,"SIGKILL")}catch(f){m.killed=m.killed.filter(h=>h!==g),m.failed.push({pid:g,reason:Sr(f)})}}catch{}if(m.killed.length>0)try{i(),m.walTruncated=!0}catch(g){a||o(` (WAL truncate skipped: ${Sr(g)})`)}if(a)o(JSON.stringify(m));else{o(""),o(`Pruned ${m.killed.length}/${p.length}`+(m.failed.length>0?` -- ${m.failed.length} failed`:"")+(m.walTruncated?". WAL truncated.":"."));for(let g of m.failed)o(` pid ${g.pid}: ${g.reason}`)}return m.failed.length===0?0:1}function Nf(e,t){process.kill(e,t)}function Af(e){return new Promise(t=>{setTimeout(t,e)})}function Of(){Ra(_(),"TRUNCATE")}function vf(e){return new Promise(t=>{let s=xa.createInterface({input:process.stdin,output:process.stderr});s.question(e,n=>{s.close();let r=n.trim().toLowerCase();t(r==="y"||r==="yes")})})}function Sr(e){if(e instanceof Error){let t=e.code;return t?`${t} ${e.message}`:e.message}return String(e)}w();import{execSync as yr}from"node:child_process";import{randomUUID as If}from"node:crypto";import Mf from"node:readline/promises";v();async function Ca(e){if(e.list){Df();return}if(e.purge){$f(e.purge);return}let t=await Pf();t||(process.stderr.write(c.err(`clipboard empty / nothing on stdin
1028
+ `);let o=t.since?"since":t.full?"full":"condensed";Tr(n,Math.ceil(r.length/4),o,"cli"),process.stderr.isTTY&&process.stderr.write(`\x1B[2mShare this recall? \u2192 recall share\x1B[0m
1029
+ `)}de();Ke();import{join as Uf}from"node:path";import{spawn as Bf}from"node:child_process";async function Na(e={}){await Ne("MCP server");let t=Uf(ee(),"dist","mcp-server.js"),s={...process.env};e.allowWrites&&(s.RECALL_MCP_ALLOW_WRITES="1");let n=Bf(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()})})}w();import{execSync as Rr}from"node:child_process";import{randomUUID as Hf}from"node:crypto";import Wf from"node:readline/promises";v();async function Aa(e){if(e.list){Xf();return}if(e.purge){Jf(e.purge);return}let t=await Gf();t||(process.stderr.write(c.err(`clipboard empty / nothing on stdin
1033
1030
  `)),process.exit(1));let s=Yt(t);if(s.length>0&&!e.force){process.stderr.write(c.warn(`\u26A0 detected ${s.length} possible secret${s.length===1?"":"s"} in content:
1034
1031
  `));for(let a of s.slice(0,8))process.stderr.write(` ${c.err(a.pattern)} ${c.dim("\u2192")} ${a.maskedPreview}
1035
1032
  `);s.length>8&&process.stderr.write(c.dim(` \u2026 ${s.length-8} more
1036
1033
  `)),e.dryRun&&(process.stderr.write(c.dim(`
1037
1034
  (dry run \u2014 nothing archived)
1038
1035
  `)),process.exit(1)),!process.stdin.isTTY&&!process.stderr.isTTY&&(process.stderr.write(c.err(`refusing to archive secret content in non-interactive mode. use --force to override.
1039
- `)),e.pipe&&process.stdout.write(t),process.exit(1));let o=Mf.createInterface({input:process.stdin,output:process.stderr}),i=await o.question(c.accent("archive anyway? [y/N] "));o.close(),i.trim().toLowerCase()!=="y"&&(process.stderr.write(c.dim(`cancelled \u2014 nothing archived.
1036
+ `)),e.pipe&&process.stdout.write(t),process.exit(1));let o=Wf.createInterface({input:process.stdin,output:process.stderr}),i=await o.question(c.accent("archive anyway? [y/N] "));o.close(),i.trim().toLowerCase()!=="y"&&(process.stderr.write(c.dim(`cancelled \u2014 nothing archived.
1040
1037
  `)),e.pipe&&process.stdout.write(t),process.exit(0))}e.dryRun&&(process.stderr.write(c.dim(`(dry run \u2014 would archive ${t.length.toLocaleString()} chars)
1041
- `)),e.pipe&&process.stdout.write(t),process.exit(0));let n=If(),r=new Date().toISOString();_().prepare(`INSERT INTO paste_archives (id, created_at, content, size_bytes, source, label)
1038
+ `)),e.pipe&&process.stdout.write(t),process.exit(0));let n=Hf(),r=new Date().toISOString();_().prepare(`INSERT INTO paste_archives (id, created_at, content, size_bytes, source, label)
1042
1039
  VALUES (?, ?, ?, ?, ?, ?)`).run(n,r,t,Buffer.byteLength(t,"utf8"),e.pipe?"cli-piped":"cli",e.label??null),process.stderr.write(c.ok(`\u2713 archived ${t.length.toLocaleString()} chars as ${n.slice(0,8)}
1043
1040
  `)),e.label&&process.stderr.write(c.dim(` label: ${e.label}
1044
1041
  `)),process.stderr.write(c.dim(` purge any time with: recall paste --purge ${n.slice(0,8)}
1045
- `)),e.pipe&&process.stdout.write(t)}function Df(){let e=_().prepare(`SELECT id, created_at, size_bytes, source, label,
1042
+ `)),e.pipe&&process.stdout.write(t)}function Xf(){let e=_().prepare(`SELECT id, created_at, size_bytes, source, label,
1046
1043
  substr(replace(replace(content, char(10), '\u21B5'), char(13), ''), 1, 80) AS preview
1047
1044
  FROM paste_archives
1048
1045
  ORDER BY created_at DESC
1049
1046
  LIMIT 100`).all();if(e.length===0){process.stdout.write(c.dim("no pastes archived yet. use `pbpaste | recall paste` to archive.\n"));return}process.stdout.write(`
1050
1047
  ${c.bold(`${e.length} archived paste${e.length===1?"":"s"}`)}
1051
1048
  `),process.stdout.write(c.dim(`\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1052
- `));for(let t of e){let s=t.size_bytes<1024?`${t.size_bytes}b`:t.size_bytes<1048576?`${(t.size_bytes/1024).toFixed(1)}K`:`${(t.size_bytes/1024/1024).toFixed(1)}M`,n=t.label?` ${c.project(t.label)}`:"";process.stdout.write(` ${c.accent(t.id.slice(0,8))} ${c.dim(X(t.created_at).padEnd(12))} ${s.padStart(6)}${n} ${c.dim(t.preview)}
1049
+ `));for(let t of e){let s=t.size_bytes<1024?`${t.size_bytes}b`:t.size_bytes<1048576?`${(t.size_bytes/1024).toFixed(1)}K`:`${(t.size_bytes/1024/1024).toFixed(1)}M`,n=t.label?` ${c.project(t.label)}`:"";process.stdout.write(` ${c.accent(t.id.slice(0,8))} ${c.dim(J(t.created_at).padEnd(12))} ${s.padStart(6)}${n} ${c.dim(t.preview)}
1053
1050
  `)}process.stdout.write(c.dim(`
1054
1051
  show full content: recall paste --show <id>
1055
1052
  `)+c.dim(`purge one (permanent): recall paste --purge <id>
1056
1053
 
1057
- `))}function $f(e){e.length<8&&(process.stderr.write(c.err(`provide at least 8 characters of the paste id to purge.
1054
+ `))}function Jf(e){e.length<8&&(process.stderr.write(c.err(`provide at least 8 characters of the paste id to purge.
1058
1055
  `)),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(c.err(`no paste matches ${e}
1059
1056
  `)),process.exit(1)),s.length>1&&(process.stderr.write(c.err(`prefix ${e} is ambiguous. be more specific.
1060
1057
  `)),process.exit(1)),t.prepare("DELETE FROM paste_archives WHERE id = ?").run(s[0].id),process.stderr.write(c.ok(`\u2713 purged ${s[0].id.slice(0,8)} \u2014 content permanently destroyed
1061
- `))}async function Pf(){if(!process.stdin.isTTY)return await Ff();try{return yr("pbpaste",{encoding:"utf8",maxBuffer:16*1024*1024})}catch{}try{return yr("xclip -o -selection clipboard",{encoding:"utf8",maxBuffer:16*1024*1024})}catch{}try{return yr("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 Ff(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(t));return Buffer.concat(e).toString("utf8")}w();v();async function La(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
1058
+ `))}async function Gf(){if(!process.stdin.isTTY)return await Yf();try{return Rr("pbpaste",{encoding:"utf8",maxBuffer:16*1024*1024})}catch{}try{return Rr("xclip -o -selection clipboard",{encoding:"utf8",maxBuffer:16*1024*1024})}catch{}try{return Rr("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 Yf(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(t));return Buffer.concat(e).toString("utf8")}w();v();async function Oa(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
1062
1059
  FROM messages
1063
1060
  WHERE content_text IS NOT NULL`).all(),d=t.prepare("UPDATE messages SET content_text = ?, raw_json = ? WHERE uuid = ?"),l=(f,h)=>{let E=Yt(f);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(c.dim(`Scanning ${a.length.toLocaleString()} messages\u2026
1064
1061
  `));for(let f of a)if(n+=1,(l(f.content_text??"",f.session_id)||l(f.raw_json??"",f.session_id))&&(r+=1,i.add(f.session_id),e.verbose&&process.stderr.write(c.dim(` hit in session ${f.session_id.slice(0,8)} message ${f.uuid.slice(0,8)}
@@ -1073,22 +1070,22 @@ show full content: recall paste --show <id>
1073
1070
  `)}process.stdout.write(`
1074
1071
  `),e.redact?(process.stdout.write(c.ok(`\u2713 redacted in place: ${o.toLocaleString()} messages, ${m.toLocaleString()} session previews.
1075
1072
  `)),process.stdout.write(c.dim(` (The source JSONL files at ~/.claude/projects/ were not modified.)
1076
- `))):process.stdout.write(c.dim(" Rerun with --redact to scrub these in place, or run `recall index --force`.\n"))}w();v();import{basename as jf}from"node:path";async function Aa(e){let t=_(),s=await Uf(t,e.project);if(!s){console.error(c.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,
1073
+ `))):process.stdout.write(c.dim(" Rerun with --redact to scrub these in place, or run `recall index --force`.\n"))}w();v();import{basename as zf}from"node:path";async function Ia(e){let t=_(),s=await qf(t,e.project);if(!s){console.error(c.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,
1077
1074
  s.auto_title,
1078
1075
  s.auto_title_source,
1079
1076
  CASE WHEN sa.session_id IS NOT NULL THEN 1 ELSE 0 END AS has_alias
1080
1077
  FROM sessions s
1081
1078
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1082
1079
  WHERE s.project_id = ?
1083
- ORDER BY s.started_at`).all(s.id);if(n.length===0){console.error(c.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=hi(p);r[m]+=1,o.push({id:u.id,quality:m})}if(!e.dryRun){let u=t.prepare(`UPDATE sessions
1080
+ ORDER BY s.started_at`).all(s.id);if(n.length===0){console.error(c.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=Ti(p);r[m]+=1,o.push({id:u.id,quality:m})}if(!e.dryRun){let u=t.prepare(`UPDATE sessions
1084
1081
  SET title_quality = ?,
1085
1082
  title_quality_computed_at = ?
1086
- WHERE id = ?`),p=Date.now();t.transaction(g=>{for(let f of g)u.run(f.quality,p,f.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(c.project(`Title quality audit \u2014 project ${c.bold(s.name)}`)),s.decoded_path&&console.log(c.dim(` ${s.decoded_path}`)),console.log(c.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"],d=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),g=Bf(p,i);console.log(` ${u.padEnd(d)} ${c.bold(String(p).padStart(5))} ${m}% ${g}`)}console.log("");let l=r.template_pending+r.programmatic+r.recursive_meta+r.low_signal;if(l>0){let u=(l/i*100).toFixed(1);console.log(c.dim(` ${l} sessions (${u}%) eligible for cleanup phases L1/L3/L4.`))}else console.log(c.ok(" No cleanup-eligible sessions remain in this project. \u2713"));console.log("")}async function Uf(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(jf(s));return r||null}var Na=28;function Bf(e,t){let s=Math.round(e/t*Na);return c.dim("\u2588".repeat(s)+"\xB7".repeat(Na-s))}bt();v();w();jn();w();bt();import{readFileSync as Yf,existsSync as Tr,statSync as Gf,readdirSync as zf}from"node:fs";import{join as $s}from"node:path";import{homedir as Kf}from"node:os";var es=["vscode","cursor","windsurf"],qf={vscode:"Code",cursor:"Cursor",windsurf:"Windsurf"};var Vf=.7,Zf=300*1e3;function Qf(e){let t=e?.homeDir??Kf(),s=e?.sources??es,n=[];for(let r of s){let o=$s(t,"Library","Application Support",qf[r],"User","workspaceStorage");Tr(o)&&n.push({source:r,root:o})}return n}function e_(e,t){let s=$s(e,"workspace.json"),n=$s(e,"state.vscdb");if(!Tr(s)||!Tr(n))return[];let r;try{let d=JSON.parse(Yf(s,"utf8"));if(!d.folder||!d.folder.startsWith("file://"))return[];r=decodeURIComponent(d.folder.replace(/^file:\/\//,""))}catch{return[]}let o;try{o=Gf(n).mtime.toISOString()}catch{return[]}let i;try{i=new bs(n,{readonly:!0})}catch{return[]}let a=[];try{let d=i.prepare("SELECT value FROM ItemTable WHERE key = 'terminal.integrated.bufferState' LIMIT 1").get(),l={};if(d?.value)try{l=JSON.parse(d.value)}catch{}let u=l.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??{},g=typeof m.name=="string"?m.name.trim():"";a.push({workspace_path:r,workspace_storage_dir:e,tab_name:g||null,cwd_hint:typeof m.cwd=="string"?m.cwd:null,last_seen_at:o,source:t})}}finally{i.close()}return a}function t_(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)<=Zf&&(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 s_=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 n_(e){return s_.has(e.trim().toLowerCase())}function r_(e){let t=e.tab_name?.trim();return!t||n_(t)?null:t}function Ia(e){let t=e?.minScore??Vf,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
1083
+ WHERE id = ?`),p=Date.now();t.transaction(g=>{for(let f of g)u.run(f.quality,p,f.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(c.project(`Title quality audit \u2014 project ${c.bold(s.name)}`)),s.decoded_path&&console.log(c.dim(` ${s.decoded_path}`)),console.log(c.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"],d=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),g=Kf(p,i);console.log(` ${u.padEnd(d)} ${c.bold(String(p).padStart(5))} ${m}% ${g}`)}console.log("");let l=r.template_pending+r.programmatic+r.recursive_meta+r.low_signal;if(l>0){let u=(l/i*100).toFixed(1);console.log(c.dim(` ${l} sessions (${u}%) eligible for cleanup phases L1/L3/L4.`))}else console.log(c.ok(" No cleanup-eligible sessions remain in this project. \u2713"));console.log("")}async function qf(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(zf(s));return r||null}var va=28;function Kf(e,t){let s=Math.round(e/t*va);return c.dim("\u2588".repeat(s)+"\xB7".repeat(va-s))}Et();v();w();Bn();w();Et();import{readFileSync as t_,existsSync as kr,statSync as s_,readdirSync as n_}from"node:fs";import{join as Fs}from"node:path";import{homedir as r_}from"node:os";var es=["vscode","cursor","windsurf"],o_={vscode:"Code",cursor:"Cursor",windsurf:"Windsurf"};var i_=.7,a_=300*1e3;function c_(e){let t=e?.homeDir??r_(),s=e?.sources??es,n=[];for(let r of s){let o=Fs(t,"Library","Application Support",o_[r],"User","workspaceStorage");kr(o)&&n.push({source:r,root:o})}return n}function l_(e,t){let s=Fs(e,"workspace.json"),n=Fs(e,"state.vscdb");if(!kr(s)||!kr(n))return[];let r;try{let d=JSON.parse(t_(s,"utf8"));if(!d.folder||!d.folder.startsWith("file://"))return[];r=decodeURIComponent(d.folder.replace(/^file:\/\//,""))}catch{return[]}let o;try{o=s_(n).mtime.toISOString()}catch{return[]}let i;try{i=new bs(n,{readonly:!0})}catch{return[]}let a=[];try{let d=i.prepare("SELECT value FROM ItemTable WHERE key = 'terminal.integrated.bufferState' LIMIT 1").get(),l={};if(d?.value)try{l=JSON.parse(d.value)}catch{}let u=l.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??{},g=typeof m.name=="string"?m.name.trim():"";a.push({workspace_path:r,workspace_storage_dir:e,tab_name:g||null,cwd_hint:typeof m.cwd=="string"?m.cwd:null,last_seen_at:o,source:t})}}finally{i.close()}return a}function d_(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)<=a_&&(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 u_=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 p_(e){return u_.has(e.trim().toLowerCase())}function m_(e){let t=e.tab_name?.trim();return!t||p_(t)?null:t}function $a(e){let t=e?.minScore??i_,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
1087
1084
  FROM sessions s
1088
1085
  JOIN projects p ON p.id = s.project_id
1089
1086
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1090
- WHERE (sa.alias IS NULL OR sa.alias = '')${r}`).all(...o),a=e?.sources??es,d=Qf({sources:a,homeDir:e?.homeDir}),l=[];for(let{source:p,root:m}of d){let g;try{g=zf(m)}catch{continue}for(let f of g){let h=$s(m,f);l.push(...e_(h,p))}}if(l.length===0)return[];let u=[];for(let p of i){let m=null;for(let f of l){let{score:h,matchedOn:E}=t_(p,f);h<t||(!m||h>m.score)&&(m={entry:f,score:h,matched:E})}if(!m)continue;let g=r_(m.entry);g&&u.push({session_id:p.id,proposed_alias:g,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 Ma(e){let t=[],s=[];for(let n of e){let r=Ds(n.session_id);if(r&&r.trim()!==""){s.push(n);continue}t.push(n)}return{applicable:t,skipped:s}}import{basename as o_}from"node:path";async function $a(e){let t=a_(e.source);if(!t){console.error(c.err("Invalid --source. Allowed: vscode | cursor | windsurf | all (default).")),process.exitCode=1;return}let s=c_(e.minScore,.7);if(s===null||s<0||s>1){console.error(c.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(c.err("Invalid --limit. Must be a non-negative integer.")),process.exitCode=1;return}let r=e.project?l_(e.project):void 0;if(e.project&&r===null){console.error(c.err(`No project found matching "${e.project}". Run \`recall projects\`.`)),process.exitCode=1;return}let o=Ia({projectId:r??void 0,sources:t,minScore:s,limit:n}),{applicable:i,skipped:a}=Ma(o);if(e.apply){let d=0;for(let l of i)try{It(l.session_id,l.proposed_alias),d+=1}catch(u){console.error(c.err(`apply failed for ${l.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:d,skipped:a.length,proposals:i.map(Da)},null,2));return}console.log(""),console.log(c.ok(`Applied ${d} alias backfill${d===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(Da),skipped_due_to_existing_alias:a.length},null,2));return}i_(i,t,s,a.length)}function i_(e,t,s,n){if(console.log(""),console.log(c.project(`recall import-vscode-state \xB7 sources=${t.join("+")} min-score=${s.toFixed(2)} \xB7 DRY RUN`)),console.log(c.dim(" Pass --apply to write proposals via setAlias().")),console.log(""),e.length===0){console.log(c.warn(" No proposals \u2014 either no matching workspaces or every candidate session already has an alias.")),n>0&&console.log(c.dim(` ${n} sessions were skipped because they already have aliases.`)),console.log("");return}for(let r of e){let o=c.bold(r.session_id.slice(0,8)),i=c.bold(r.score.toFixed(2)),a=c.dim(`[${r.evidence.source}]`),d=r.evidence.matched_on.join("+");console.log(` ${o} score=${i} ${a} matched=${d}`),console.log(` proposed alias: ${c.bold(r.proposed_alias)}`),console.log(` workspace: ${c.dim(q(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: ${c.dim(q(r.evidence.cwd_hint,70))}`),console.log(` last seen: ${c.dim(r.evidence.last_seen_at)}`),console.log("")}console.log(c.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 Da(e){return e}function a_(e){if(!e||e==="all")return es;let t=e.split(",").map(n=>n.trim().toLowerCase()).filter(Boolean),s=[];for(let n of t)if(es.includes(n))s.push(n);else return null;return s.length>0?s:null}function c_(e,t){if(e===void 0)return t;let s=Number.parseFloat(e);return Number.isFinite(s)?s:null}function l_(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=o_(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}w();import{existsSync as Pa,mkdirSync as d_,readFileSync as u_,writeFileSync as p_}from"node:fs";import{homedir as m_}from"node:os";import{join as Fa}from"node:path";import{z as je}from"zod";function ja(){return process.env.RECALL_HOME??Fa(m_(),".recall")}function g_(){let e=ja();Pa(e)||d_(e,{recursive:!0})}function Ua(){return Fa(ja(),"config.json")}var Ba=je.object({enabled:je.boolean().default(!1),model:je.string().optional(),ratePerMinute:je.number().int().min(1).max(600).default(30),lastProcessedSessionId:je.string().nullable().default(null),backfillPaused:je.boolean().default(!1),autoExtractEnabled:je.boolean().default(!1),autoExtractIntervalMinutes:je.number().int().min(5).max(720).default(60),autoExtractBatchSize:je.number().int().min(1).max(20).default(1),autoResumeWorker:je.boolean().default(!1)}),Ps={enabled:!1,ratePerMinute:30,lastProcessedSessionId:null,backfillPaused:!1,autoExtractEnabled:!1,autoExtractIntervalMinutes:60,autoExtractBatchSize:1,autoResumeWorker:!1};function Ha(){let e=Ua();if(!Pa(e))return{};try{return JSON.parse(u_(e,"utf8"))}catch(t){return console.error("[semantic-config] failed to parse config.json, using defaults:",t),{}}}function ve(){let e=Ha().semantic;if(!e)return{...Ps};let t=Ba.safeParse({...Ps,...e});return t.success?t.data:{...Ps}}function Ue(e){g_();let t=Ha(),s=Ba.parse({...Ps,...t.semantic??{},...e}),n={...t,semantic:s};return p_(Ua(),JSON.stringify(n,null,2)),f_(s.enabled),s}function f_(e){try{_().prepare(`INSERT INTO app_settings(key, value) VALUES ('semantic_enabled', ?)
1091
- ON CONFLICT(key) DO UPDATE SET value = excluded.value`).run(e?"1":"0")}catch(t){let s=t instanceof Error?t.message:String(t);console.error(`[semantic-config] failed to sync semantic_enabled: ${s}`)}}w();Be();import{existsSync as $_,mkdirSync as P_,writeFileSync as F_}from"node:fs";import{homedir as j_}from"node:os";import{join as xr}from"node:path";var U_=1,B_=12e3,H_=3,W_=[];function X_(){return process.env.RECALL_HOME??xr(j_(),".recall")}function nc(){return xr(X_(),"semantic")}function J_(){let e=nc();$_(e)||P_(e,{recursive:!0})}function Y_(e){let t=_(),s=t.prepare(`SELECT s.id, s.message_count, s.first_user_message,
1087
+ WHERE (sa.alias IS NULL OR sa.alias = '')${r}`).all(...o),a=e?.sources??es,d=c_({sources:a,homeDir:e?.homeDir}),l=[];for(let{source:p,root:m}of d){let g;try{g=n_(m)}catch{continue}for(let f of g){let h=Fs(m,f);l.push(...l_(h,p))}}if(l.length===0)return[];let u=[];for(let p of i){let m=null;for(let f of l){let{score:h,matchedOn:E}=d_(p,f);h<t||(!m||h>m.score)&&(m={entry:f,score:h,matched:E})}if(!m)continue;let g=m_(m.entry);g&&u.push({session_id:p.id,proposed_alias:g,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 Pa(e){let t=[],s=[];for(let n of e){let r=Ps(n.session_id);if(r&&r.trim()!==""){s.push(n);continue}t.push(n)}return{applicable:t,skipped:s}}import{basename as g_}from"node:path";async function ja(e){let t=__(e.source);if(!t){console.error(c.err("Invalid --source. Allowed: vscode | cursor | windsurf | all (default).")),process.exitCode=1;return}let s=h_(e.minScore,.7);if(s===null||s<0||s>1){console.error(c.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(c.err("Invalid --limit. Must be a non-negative integer.")),process.exitCode=1;return}let r=e.project?E_(e.project):void 0;if(e.project&&r===null){console.error(c.err(`No project found matching "${e.project}". Run \`recall projects\`.`)),process.exitCode=1;return}let o=$a({projectId:r??void 0,sources:t,minScore:s,limit:n}),{applicable:i,skipped:a}=Pa(o);if(e.apply){let d=0;for(let l of i)try{Mt(l.session_id,l.proposed_alias),d+=1}catch(u){console.error(c.err(`apply failed for ${l.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:d,skipped:a.length,proposals:i.map(Fa)},null,2));return}console.log(""),console.log(c.ok(`Applied ${d} alias backfill${d===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(Fa),skipped_due_to_existing_alias:a.length},null,2));return}f_(i,t,s,a.length)}function f_(e,t,s,n){if(console.log(""),console.log(c.project(`recall import-vscode-state \xB7 sources=${t.join("+")} min-score=${s.toFixed(2)} \xB7 DRY RUN`)),console.log(c.dim(" Pass --apply to write proposals via setAlias().")),console.log(""),e.length===0){console.log(c.warn(" No proposals \u2014 either no matching workspaces or every candidate session already has an alias.")),n>0&&console.log(c.dim(` ${n} sessions were skipped because they already have aliases.`)),console.log("");return}for(let r of e){let o=c.bold(r.session_id.slice(0,8)),i=c.bold(r.score.toFixed(2)),a=c.dim(`[${r.evidence.source}]`),d=r.evidence.matched_on.join("+");console.log(` ${o} score=${i} ${a} matched=${d}`),console.log(` proposed alias: ${c.bold(r.proposed_alias)}`),console.log(` workspace: ${c.dim(K(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: ${c.dim(K(r.evidence.cwd_hint,70))}`),console.log(` last seen: ${c.dim(r.evidence.last_seen_at)}`),console.log("")}console.log(c.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 Fa(e){return e}function __(e){if(!e||e==="all")return es;let t=e.split(",").map(n=>n.trim().toLowerCase()).filter(Boolean),s=[];for(let n of t)if(es.includes(n))s.push(n);else return null;return s.length>0?s:null}function h_(e,t){if(e===void 0)return t;let s=Number.parseFloat(e);return Number.isFinite(s)?s:null}function E_(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=g_(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}w();import{existsSync as Ua,mkdirSync as b_,readFileSync as S_,writeFileSync as y_}from"node:fs";import{homedir as w_}from"node:os";import{join as Ba}from"node:path";import{z as je}from"zod";function Ha(){return process.env.RECALL_HOME??Ba(w_(),".recall")}function T_(){let e=Ha();Ua(e)||b_(e,{recursive:!0})}function Wa(){return Ba(Ha(),"config.json")}var Xa=je.object({enabled:je.boolean().default(!1),model:je.string().optional(),ratePerMinute:je.number().int().min(1).max(600).default(30),lastProcessedSessionId:je.string().nullable().default(null),backfillPaused:je.boolean().default(!1),autoExtractEnabled:je.boolean().default(!1),autoExtractIntervalMinutes:je.number().int().min(5).max(720).default(60),autoExtractBatchSize:je.number().int().min(1).max(20).default(1),autoResumeWorker:je.boolean().default(!1)}),js={enabled:!1,ratePerMinute:30,lastProcessedSessionId:null,backfillPaused:!1,autoExtractEnabled:!1,autoExtractIntervalMinutes:60,autoExtractBatchSize:1,autoResumeWorker:!1};function Ja(){let e=Wa();if(!Ua(e))return{};try{return JSON.parse(S_(e,"utf8"))}catch(t){return console.error("[semantic-config] failed to parse config.json, using defaults:",t),{}}}function ve(){let e=Ja().semantic;if(!e)return{...js};let t=Xa.safeParse({...js,...e});return t.success?t.data:{...js}}function Ue(e){T_();let t=Ja(),s=Xa.parse({...js,...t.semantic??{},...e}),n={...t,semantic:s};return y_(Wa(),JSON.stringify(n,null,2)),R_(s.enabled),s}function R_(e){try{_().prepare(`INSERT INTO app_settings(key, value) VALUES ('semantic_enabled', ?)
1088
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value`).run(e?"1":"0")}catch(t){let s=t instanceof Error?t.message:String(t);console.error(`[semantic-config] failed to sync semantic_enabled: ${s}`)}}w();Be();import{existsSync as J_,mkdirSync as G_,writeFileSync as Y_}from"node:fs";import{homedir as z_}from"node:os";import{join as Lr}from"node:path";var q_=1,K_=12e3,V_=3,Z_=[];function Q_(){return process.env.RECALL_HOME??Lr(z_(),".recall")}function ic(){return Lr(Q_(),"semantic")}function eh(){let e=ic();J_(e)||G_(e,{recursive:!0})}function th(e){let t=_(),s=t.prepare(`SELECT s.id, s.message_count, s.first_user_message,
1092
1089
  p.name AS project,
1093
1090
  NULLIF(sa.alias, '') AS alias
1094
1091
  FROM sessions s
@@ -1097,10 +1094,10 @@ show full content: recall paste --show <id>
1097
1094
  WHERE s.id = ?`).get(e);if(!s)return null;let n=t.prepare(`SELECT role, content_text
1098
1095
  FROM messages
1099
1096
  WHERE session_id = ? AND is_sidechain = 0
1100
- 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",d=i.content_text.replace(/```[\s\S]*?```/g,"[code]").replace(/<[^>]+>[\s\S]*?<\/[^>]+>/g,"").trim();if(!d)continue;let l=d.length>1500?d.slice(0,1500)+"\u2026":d,u=`${a}: ${l}`;if(o+u.length>B_)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(`
1097
+ 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",d=i.content_text.replace(/```[\s\S]*?```/g,"[code]").replace(/<[^>]+>[\s\S]*?<\/[^>]+>/g,"").trim();if(!d)continue;let l=d.length>1500?d.slice(0,1500)+"\u2026":d,u=`${a}: ${l}`;if(o+u.length>K_)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(`
1101
1098
 
1102
- `),messageCount:s.message_count}}function G_(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(`
1103
- `)}function z_(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():"",d=(Array.isArray(o.keywords)?o.keywords:[]).filter(l=>typeof l=="string").map(l=>l.trim().toLowerCase()).filter(l=>l.length>0&&l.length<64);return!i||d.length===0?null:{summary:i,keywords:Array.from(new Set(d)).slice(0,20)}}catch{return null}}function K_(e){let t=_(),s=e.keywords.join(",");t.prepare(`INSERT INTO session_semantic
1099
+ `),messageCount:s.message_count}}function sh(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(`
1100
+ `)}function nh(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():"",d=(Array.isArray(o.keywords)?o.keywords:[]).filter(l=>typeof l=="string").map(l=>l.trim().toLowerCase()).filter(l=>l.length>0&&l.length<64);return!i||d.length===0?null:{summary:i,keywords:Array.from(new Set(d)).slice(0,20)}}catch{return null}}function rh(e){let t=_(),s=e.keywords.join(",");t.prepare(`INSERT INTO session_semantic
1104
1101
  (session_id, summary, keywords, model, source_message_count, generated_at)
1105
1102
  VALUES (@session_id, @summary, @keywords, @model, @source_message_count, @generated_at)
1106
1103
  ON CONFLICT(session_id) DO UPDATE SET
@@ -1108,23 +1105,23 @@ show full content: recall paste --show <id>
1108
1105
  keywords = excluded.keywords,
1109
1106
  model = excluded.model,
1110
1107
  source_message_count = excluded.source_message_count,
1111
- 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}),J_();let n=xr(nc(),`${e.sessionId}.json`);F_(n,JSON.stringify({version:U_,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 js=null;function q_(){let t=ve().ratePerMinute,s=t/6e4;return(!js||js.capacity!==t)&&(js={tokens:t,capacity:t,refillPerMs:s,lastRefill:Date.now()}),js}function V_(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 Z_(e){for(;;){if(e?.aborted)throw new Error("aborted");let t=q_();if(V_(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 Q_(e,t={}){let s=ve();if(!s.enabled)return{sessionId:e,ok:!1,reason:"disabled"};if(!se())return{sessionId:e,ok:!1,reason:"claude-cli-missing"};let n=Y_(e);if(!n)return{sessionId:e,ok:!1,reason:"session-not-found"};if(n.messageCount<H_)return{sessionId:e,ok:!1,reason:"too-short"};if(!n.excerpt.trim())return{sessionId:e,ok:!1,reason:"empty-excerpt"};await Z_(t.signal);let r=G_(n),o=await St(r,W_,{model:s.model});if(!o.success)return{sessionId:e,ok:!1,reason:`claude-cli-exit-${o.exitCode??"null"}`,model:s.model??null};let i=z_(o.stdout);return i?(K_({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 Us(e={}){let t=ve();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
1108
+ 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}),eh();let n=Lr(ic(),`${e.sessionId}.json`);Y_(n,JSON.stringify({version:q_,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 Bs=null;function oh(){let t=ve().ratePerMinute,s=t/6e4;return(!Bs||Bs.capacity!==t)&&(Bs={tokens:t,capacity:t,refillPerMs:s,lastRefill:Date.now()}),Bs}function ih(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 ah(e){for(;;){if(e?.aborted)throw new Error("aborted");let t=oh();if(ih(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 ch(e,t={}){let s=ve();if(!s.enabled)return{sessionId:e,ok:!1,reason:"disabled"};if(!ne())return{sessionId:e,ok:!1,reason:"claude-cli-missing"};let n=th(e);if(!n)return{sessionId:e,ok:!1,reason:"session-not-found"};if(n.messageCount<V_)return{sessionId:e,ok:!1,reason:"too-short"};if(!n.excerpt.trim())return{sessionId:e,ok:!1,reason:"empty-excerpt"};await ah(t.signal);let r=sh(n),o=await bt(r,Z_,{model:s.model});if(!o.success)return{sessionId:e,ok:!1,reason:`claude-cli-exit-${o.exitCode??"null"}`,model:s.model??null};let i=nh(o.stdout);return i?(rh({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 Hs(e={}){let t=ve();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
1112
1109
  FROM sessions s
1113
1110
  LEFT JOIN session_semantic ss ON ss.session_id = s.id
1114
1111
  WHERE ${o}
1115
1112
  ORDER BY COALESCE(s.started_at, '') ASC, s.id ASC
1116
- LIMIT @limit`).all(r),a={total:i.length,processed:0,ok:0,failed:0,currentSessionId:null};e.onProgress?.(a);for(let{id:d}of i){if(e.signal?.aborted||ve().backfillPaused)break;a.currentSessionId=d,e.onProgress?.({...a});try{(await Q_(d,{signal:e.signal})).ok?a.ok+=1:a.failed+=1}catch(u){a.failed+=1,console.error("[semantic.backfill] failed for",d,u)}a.processed+=1,Ue({lastProcessedSessionId:d}),e.onProgress?.({...a})}return a.currentSessionId=null,e.onProgress?.({...a}),a}function rc(){let e=ve(),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:se(),ratePerMinute:e.ratePerMinute,model:e.model??null,totalSessions:s,processedSessions:n,pendingSessions:Math.max(0,s-n),lastProcessedSessionId:e.lastProcessedSessionId,backfillPaused:e.backfillPaused}}Be();Ws();rt();w();rt();w();function uc(e){return e.replace(/```json[\s\S]*?```/g,"[tool-call]").replace(/\{[\s\S]{200,}?\}/g,"[json-object]")}function mh(e){let t=[],o=0;for(;o<e.length;){let i=[],a=0;for(;i.length<5&&o<e.length;){let l=e[o],u=uc(l.content_text??"");if(a+u.length>2e3&&i.length>=3)break;i.push(l),a+=u.length,o++}if(i.length===0)break;let d=i.map(l=>{let u=l.role??"system",p=uc(l.content_text??"");return`[${u}] ${p}`}).join(`
1113
+ LIMIT @limit`).all(r),a={total:i.length,processed:0,ok:0,failed:0,currentSessionId:null};e.onProgress?.(a);for(let{id:d}of i){if(e.signal?.aborted||ve().backfillPaused)break;a.currentSessionId=d,e.onProgress?.({...a});try{(await ch(d,{signal:e.signal})).ok?a.ok+=1:a.failed+=1}catch(u){a.failed+=1,console.error("[semantic.backfill] failed for",d,u)}a.processed+=1,Ue({lastProcessedSessionId:d}),e.onProgress?.({...a})}return a.currentSessionId=null,e.onProgress?.({...a}),a}function ac(){let e=ve(),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:ne(),ratePerMinute:e.ratePerMinute,model:e.model??null,totalSessions:s,processedSessions:n,pendingSessions:Math.max(0,s-n),lastProcessedSessionId:e.lastProcessedSessionId,backfillPaused:e.backfillPaused}}Be();Js();yt();w();yt();w();function gc(e){return e.replace(/```json[\s\S]*?```/g,"[tool-call]").replace(/\{[\s\S]{200,}?\}/g,"[json-object]")}function Th(e){let t=[],o=0;for(;o<e.length;){let i=[],a=0;for(;i.length<5&&o<e.length;){let l=e[o],u=gc(l.content_text??"");if(a+u.length>2e3&&i.length>=3)break;i.push(l),a+=u.length,o++}if(i.length===0)break;let d=i.map(l=>{let u=l.role??"system",p=gc(l.content_text??"");return`[${u}] ${p}`}).join(`
1117
1114
 
1118
- `);t.push({messageUuids:i.map(l=>l.uuid),text:d}),o<e.length&&i.length>=3&&(o=Math.max(o-1,o-1))}return t}function Mr(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 mh(s)}var gh=!1,fh=null;var _h=new Set;function hh(){return _().prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}function pc(){return{running:gh,queueDepth:hh(),lastProcessedAt:fh,blacklistedCount:_h.size}}w();le();async function _c(e,t){let s=(e??"status").toLowerCase();if(s==="on"||s==="enable"){if(!se()){console.error("claude CLI not found on PATH. Install Claude Code first, then re-run."),process.exitCode=1;return}let m={enabled:!0};t.rate&&(m.ratePerMinute=Number(t.rate)),t.model&&(m.model=t.model);let g=Ue(m);console.log("Semantic search: ENABLED"),console.log(` Rate: ${g.ratePerMinute}/min`),g.model&&console.log(` Model: ${g.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"){Ue({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"){Ue({backfillPaused:!0}),console.log("Backfill paused. Resume with `recall semantic resume`.");return}if(s==="resume"){Ue({backfillPaused:!1}),console.log("Backfill resumed.");return}if(s==="backfill"){let m=ve();if(!m.enabled){console.error("Semantic search is disabled. Run `recall semantic on` first."),process.exitCode=1;return}m.backfillPaused&&Ue({backfillPaused:!1});let g=t.limit?Math.max(1,Number(t.limit)):1e3,f=!!t.force;console.log(`Backfilling up to ${g} sessions${f?" (force)":""}\u2026`);let h=Date.now(),E=0,b=await Us({limit:g,force:f,onProgress:T=>{if(T.processed===E)return;E=T.processed;let R=T.total>0?` (${Math.round(T.processed/T.total*100)}%)`:"";process.stdout.write(`\r ${T.processed}/${T.total}${R} ok=${T.ok} failed=${T.failed} `)}});process.stdout.write(`
1119
- `);let S=((Date.now()-h)/1e3).toFixed(1);console.log(`Done in ${S}s \u2014 processed=${b.processed} ok=${b.ok} failed=${b.failed}`);return}if(s==="install"){let{ensureTransformersInstalled:m}=await Promise.resolve().then(()=>(fc(),gc)),g=await m();if(!g.ok){console.error("Failed to install @huggingface/transformers:"),console.error(` ${g.error}`),console.error("Vector search not enabled. Other features unaffected."),process.exitCode=1;return}g.action==="installed"&&console.log("Installed @huggingface/transformers."),yt()?console.log("Model already installed."):(console.log("Downloading bge-base-en-v1.5 (~110MB)..."),await Lr((f,h,E)=>{let b=E>0?Math.round(h/E*100):0;process.stdout.write(`\r ${f}: ${b}% `)}),process.stdout.write(`
1115
+ `);t.push({messageUuids:i.map(l=>l.uuid),text:d}),o<e.length&&i.length>=3&&(o=Math.max(o-1,o-1))}return t}function $r(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 Th(s)}var Rh=!1,xh=null;var kh=new Set;function Ch(){return _().prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}function fc(){return{running:Rh,queueDepth:Ch(),lastProcessedAt:xh,blacklistedCount:kh.size}}w();de();async function bc(e,t){let s=(e??"status").toLowerCase();if(s==="on"||s==="enable"){if(!ne()){console.error("claude CLI not found on PATH. Install Claude Code first, then re-run."),process.exitCode=1;return}let m={enabled:!0};t.rate&&(m.ratePerMinute=Number(t.rate)),t.model&&(m.model=t.model);let g=Ue(m);console.log("Semantic search: ENABLED"),console.log(` Rate: ${g.ratePerMinute}/min`),g.model&&console.log(` Model: ${g.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"){Ue({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"){Ue({backfillPaused:!0}),console.log("Backfill paused. Resume with `recall semantic resume`.");return}if(s==="resume"){Ue({backfillPaused:!1}),console.log("Backfill resumed.");return}if(s==="backfill"){let m=ve();if(!m.enabled){console.error("Semantic search is disabled. Run `recall semantic on` first."),process.exitCode=1;return}m.backfillPaused&&Ue({backfillPaused:!1});let g=t.limit?Math.max(1,Number(t.limit)):1e3,f=!!t.force;console.log(`Backfilling up to ${g} sessions${f?" (force)":""}\u2026`);let h=Date.now(),E=0,b=await Hs({limit:g,force:f,onProgress:R=>{if(R.processed===E)return;E=R.processed;let T=R.total>0?` (${Math.round(R.processed/R.total*100)}%)`:"";process.stdout.write(`\r ${R.processed}/${R.total}${T} ok=${R.ok} failed=${R.failed} `)}});process.stdout.write(`
1116
+ `);let S=((Date.now()-h)/1e3).toFixed(1);console.log(`Done in ${S}s \u2014 processed=${b.processed} ok=${b.ok} failed=${b.failed}`);return}if(s==="install"){let{ensureTransformersInstalled:m}=await Promise.resolve().then(()=>(Ec(),hc)),g=await m();if(!g.ok){console.error("Failed to install @huggingface/transformers:"),console.error(` ${g.error}`),console.error("Vector search not enabled. Other features unaffected."),process.exitCode=1;return}g.action==="installed"&&console.log("Installed @huggingface/transformers."),St()?console.log("Model already installed."):(console.log("Downloading bge-base-en-v1.5 (~110MB)..."),await Or((f,h,E)=>{let b=E>0?Math.round(h/E*100):0;process.stdout.write(`\r ${f}: ${b}% `)}),process.stdout.write(`
1120
1117
  `)),console.log("Loading embedder...");try{await nt(),console.log("Done. Vector search is now active.")}catch(f){console.log("Model files installed."),console.log(` Embedder load skipped: ${f instanceof Error?f.message.split(`
1121
- `)[0]:String(f)}`),console.log(" Vector features remain available; runtime load happens on first use.")}return}if(s==="uninstall"){Nr(),console.log("Model removed. Vector search will fall back to keyword search.");return}if(s==="auto-extract"){let m=t._autoExtractAction;if(m==="on"||m==="enable"){let g=Ue({autoExtractEnabled:!0});console.log("Auto-extract: ENABLED"),console.log(` Cadence: 1 batch every ${g.autoExtractIntervalMinutes} minutes`),console.log(` Batch size: ${g.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(m==="off"||m==="disable"){Ue({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 Ne("Vector reindex"),!Ve().loaded){if(!yt()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}await nt()}let m=_(),g=m.prepare(`
1118
+ `)[0]:String(f)}`),console.log(" Vector features remain available; runtime load happens on first use.")}return}if(s==="uninstall"){vr(),console.log("Model removed. Vector search will fall back to keyword search.");return}if(s==="auto-extract"){let m=t._autoExtractAction;if(m==="on"||m==="enable"){let g=Ue({autoExtractEnabled:!0});console.log("Auto-extract: ENABLED"),console.log(` Cadence: 1 batch every ${g.autoExtractIntervalMinutes} minutes`),console.log(` Batch size: ${g.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(m==="off"||m==="disable"){Ue({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 Ne("Vector reindex"),!Ze().loaded){if(!St()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}await nt()}let m=_(),g=m.prepare(`
1122
1119
  SELECT s.id FROM sessions s
1123
1120
  WHERE s.message_count >= 3
1124
1121
  AND NOT EXISTS (SELECT 1 FROM chunk_meta cm WHERE cm.session_id = s.id)
1125
- `).all(),f=Number(process.env.RECALL_REINDEX_MAX_CHUNKS??"0"),h=f>0?` (cap ${f} chunks/session)`:" (no cap)";console.log(`Reindexing ${g.length} sessions (skipping already-indexed)${h}...`);let E=0;for(let{id:b}of g){let S=Mr(b),T=f>0?S.slice(0,f):S;if(T.length===0){E++;continue}let R=T.map($=>$.text),k=await Dt(R);m.prepare("DELETE FROM vec_chunks WHERE rowid IN (SELECT rowid FROM chunk_meta WHERE session_id = ?)").run(b),m.prepare("DELETE FROM chunk_meta WHERE session_id = ?").run(b);let J=m.prepare(`INSERT INTO chunk_meta(session_id, message_uuids, text, embedding_model_id, embedding_dim, stale, generated_at)
1126
- VALUES (?, ?, ?, 'bge-base-en-v1.5', 768, 0, datetime('now'))`),A=m.prepare("INSERT INTO vec_chunks(rowid, embedding) VALUES (?, ?)");for(let $=0;$<T.length;$++){let j=J.run(b,JSON.stringify(T[$].messageUuids),T[$].text),y=Buffer.from(k[$].buffer,k[$].byteOffset,k[$].byteLength);A.run(BigInt(j.lastInsertRowid),y)}E++,E%10===0&&process.stdout.write(`\r ${E}/${g.length} `)}process.stdout.write(`
1127
- `),console.log(`Reindexed ${E} sessions.`);return}if(s==="verify-spawn"){if(!se()){console.error("claude CLI not found on PATH. Install Claude Code first, then re-run."),process.exitCode=1;return}let{spawnClaudePrompt:m}=await Promise.resolve().then(()=>(Be(),Fs)),{homedir:g}=await import("node:os"),{join:f}=await import("node:path"),{readdirSync:h}=await import("node:fs"),E=f(g(),".claude","projects"),b=()=>{let $=new Set;try{for(let j of h(E,{withFileTypes:!0})){if(!j.isDirectory())continue;let y=f(E,j.name);for(let U of h(y,{withFileTypes:!0}))U.isFile()&&U.name.endsWith(".jsonl")&&$.add(f(y,U.name))}}catch{}return $};console.log("Snapshotting JSONL files in ~/.claude/projects/ ...");let S=b();console.log(` Before: ${S.size} JSONL file(s)`),console.log('Spawning a tiny `claude -p --no-session-persistence "ok"`...');let T=Date.now(),R=await m("Reply with the single word: ok",[],{}),k=((Date.now()-T)/1e3).toFixed(1);if(console.log(` CLI exit: ${R.exitCode}, ${k}s`),!R.success){console.error(` stderr: ${R.stderr.slice(-500)}`),console.error("FAIL: claude CLI exited non-zero. Cannot validate spawn behavior."),process.exitCode=1;return}console.log("Snapshotting again...");let J=b();console.log(` After: ${J.size} JSONL file(s)`);let A=[];for(let $ of J)S.has($)||A.push($);if(A.length===0){console.log(""),console.log("PASS: --no-session-persistence is honored on this claude CLI version."),console.log("It is safe to re-enable Tier-1 features (autoTitle.agentEnabled,"),console.log("semantic.enabled, semantic.autoExtractEnabled) in ~/.recall/config.json.");return}console.error(""),console.error(`FAIL: ${A.length} new JSONL file(s) appeared despite the flag.`),console.error("Tier-1 features WILL produce phantom sessions if re-enabled.");for(let $ of A.slice(0,5))console.error(` - ${$}`);A.length>5&&console.error(` ... and ${A.length-5} more`),console.error(""),console.error("Possible causes:"),console.error(" 1. Your `claude` CLI is older than the version that added the flag."),console.error(" 2. The flag is in --help but not actually wired up in your version."),console.error("Mitigation: keep autoTitle.agentEnabled=false until claude is upgraded."),process.exitCode=1;return}let n=rc(),r=yt(),o=Ve(),i=pc(),a=ve(),d=0;try{d=_().prepare("SELECT COUNT(*) AS n FROM vec_chunks").get()?.n??0}catch{}let l=r||d>0;function u(){console.log("--- Tier 1 (inference \u2014 costs plan tokens) ---"),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`)")}function p(){console.log("--- Tier 2 (vectors \u2014 free, local, zero tokens) ---"),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(` Chunks: ${d} indexed`)}l?(p(),console.log(""),u()):(u(),console.log(""),p()),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}`)}w();w();w();rt();var ot=400,Ys=768,Nh="bge-base-en-v1.5";function Ah(e){return Buffer.from(e.buffer,e.byteOffset,e.byteLength)}function Oh(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!==Ys)throw new Error(`embedding dim mismatch: got ${e.embedding.length}, expected ${Ys}`);let t=e.embedding_model_id??Nh,s=new Date().toISOString();return _().prepare(`INSERT INTO message_embeddings
1122
+ `).all(),f=Number(process.env.RECALL_REINDEX_MAX_CHUNKS??"0"),h=f>0?` (cap ${f} chunks/session)`:" (no cap)";console.log(`Reindexing ${g.length} sessions (skipping already-indexed)${h}...`);let E=0;for(let{id:b}of g){let S=$r(b),R=f>0?S.slice(0,f):S;if(R.length===0){E++;continue}let T=R.map($=>$.text),L=await $t(T);m.prepare("DELETE FROM vec_chunks WHERE rowid IN (SELECT rowid FROM chunk_meta WHERE session_id = ?)").run(b),m.prepare("DELETE FROM chunk_meta WHERE session_id = ?").run(b);let D=m.prepare(`INSERT INTO chunk_meta(session_id, message_uuids, text, embedding_model_id, embedding_dim, stale, generated_at)
1123
+ VALUES (?, ?, ?, 'bge-base-en-v1.5', 768, 0, datetime('now'))`),A=m.prepare("INSERT INTO vec_chunks(rowid, embedding) VALUES (?, ?)");for(let $=0;$<R.length;$++){let U=D.run(b,JSON.stringify(R[$].messageUuids),R[$].text),y=Buffer.from(L[$].buffer,L[$].byteOffset,L[$].byteLength);A.run(BigInt(U.lastInsertRowid),y)}E++,E%10===0&&process.stdout.write(`\r ${E}/${g.length} `)}process.stdout.write(`
1124
+ `),console.log(`Reindexed ${E} sessions.`);return}if(s==="verify-spawn"){if(!ne()){console.error("claude CLI not found on PATH. Install Claude Code first, then re-run."),process.exitCode=1;return}let{spawnClaudePrompt:m}=await Promise.resolve().then(()=>(Be(),Us)),{homedir:g}=await import("node:os"),{join:f}=await import("node:path"),{readdirSync:h}=await import("node:fs"),E=f(g(),".claude","projects"),b=()=>{let $=new Set;try{for(let U of h(E,{withFileTypes:!0})){if(!U.isDirectory())continue;let y=f(E,U.name);for(let B of h(y,{withFileTypes:!0}))B.isFile()&&B.name.endsWith(".jsonl")&&$.add(f(y,B.name))}}catch{}return $};console.log("Snapshotting JSONL files in ~/.claude/projects/ ...");let S=b();console.log(` Before: ${S.size} JSONL file(s)`),console.log('Spawning a tiny `claude -p --no-session-persistence "ok"`...');let R=Date.now(),T=await m("Reply with the single word: ok",[],{}),L=((Date.now()-R)/1e3).toFixed(1);if(console.log(` CLI exit: ${T.exitCode}, ${L}s`),!T.success){console.error(` stderr: ${T.stderr.slice(-500)}`),console.error("FAIL: claude CLI exited non-zero. Cannot validate spawn behavior."),process.exitCode=1;return}console.log("Snapshotting again...");let D=b();console.log(` After: ${D.size} JSONL file(s)`);let A=[];for(let $ of D)S.has($)||A.push($);if(A.length===0){console.log(""),console.log("PASS: --no-session-persistence is honored on this claude CLI version."),console.log("It is safe to re-enable Tier-1 features (autoTitle.agentEnabled,"),console.log("semantic.enabled, semantic.autoExtractEnabled) in ~/.recall/config.json.");return}console.error(""),console.error(`FAIL: ${A.length} new JSONL file(s) appeared despite the flag.`),console.error("Tier-1 features WILL produce phantom sessions if re-enabled.");for(let $ of A.slice(0,5))console.error(` - ${$}`);A.length>5&&console.error(` ... and ${A.length-5} more`),console.error(""),console.error("Possible causes:"),console.error(" 1. Your `claude` CLI is older than the version that added the flag."),console.error(" 2. The flag is in --help but not actually wired up in your version."),console.error("Mitigation: keep autoTitle.agentEnabled=false until claude is upgraded."),process.exitCode=1;return}let n=ac(),r=St(),o=Ze(),i=fc(),a=ve(),d=0;try{d=_().prepare("SELECT COUNT(*) AS n FROM vec_chunks").get()?.n??0}catch{}let l=r||d>0;function u(){console.log("--- Tier 1 (inference \u2014 costs plan tokens) ---"),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`)")}function p(){console.log("--- Tier 2 (vectors \u2014 free, local, zero tokens) ---"),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(` Chunks: ${d} indexed`)}l?(p(),console.log(""),u()):(u(),console.log(""),p()),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}`)}w();w();w();yt();var rt=400,zs=768,jh="bge-base-en-v1.5";function Uh(e){return Buffer.from(e.buffer,e.byteOffset,e.byteLength)}function Bh(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!==zs)throw new Error(`embedding dim mismatch: got ${e.embedding.length}, expected ${zs}`);let t=e.embedding_model_id??jh,s=new Date().toISOString();return _().prepare(`INSERT INTO message_embeddings
1128
1125
  (message_uuid, session_id, embedding,
1129
1126
  embedding_model_id, embedding_dim, text_length, generated_at)
1130
1127
  VALUES (?, ?, ?, ?, ?, ?, ?)
@@ -1134,7 +1131,7 @@ show full content: recall paste --show <id>
1134
1131
  embedding_model_id = excluded.embedding_model_id,
1135
1132
  embedding_dim = excluded.embedding_dim,
1136
1133
  text_length = excluded.text_length,
1137
- generated_at = excluded.generated_at`).run(e.message_uuid,e.session_id,Ah(e.embedding),t,Ys,e.text_length,s),{message_uuid:e.message_uuid,session_id:e.session_id,embedding_model_id:t,embedding_dim:Ys,text_length:e.text_length,generated_at:s}}function vh(e,t={}){let s=_(),n=t.force?`m.session_id = ? AND m.is_sidechain = 0
1134
+ generated_at = excluded.generated_at`).run(e.message_uuid,e.session_id,Uh(e.embedding),t,zs,e.text_length,s),{message_uuid:e.message_uuid,session_id:e.session_id,embedding_model_id:t,embedding_dim:zs,text_length:e.text_length,generated_at:s}}function Hh(e,t={}){let s=_(),n=t.force?`m.session_id = ? AND m.is_sidechain = 0
1138
1135
  AND m.content_text IS NOT NULL
1139
1136
  AND length(m.content_text) > ?`:`m.session_id = ? AND m.is_sidechain = 0
1140
1137
  AND m.content_text IS NOT NULL
@@ -1144,7 +1141,7 @@ show full content: recall paste --show <id>
1144
1141
  LEFT JOIN message_embeddings me ON me.message_uuid = m.uuid
1145
1142
  WHERE ${n}
1146
1143
  ORDER BY m.timestamp ASC, m.rowid ASC
1147
- LIMIT ?`).all(e,ot,r)}var hc=null;async function Ih(){return hc||(Ve().loaded||await nt(),Dt)}async function Mh(e,t={}){let s={embedded:0,skipped:0,failed:0,failures:[]},n=vh(e,{limit:t.limit,force:t.force});if(n.length===0)return s;let r=await Ih(),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(d=>({uuid:d.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{Oh({message_uuid:n[a].uuid,session_id:n[a].session_id,embedding:i[a],text_length:o[a].length}),s.embedded+=1}catch(d){s.failed+=1,s.failures.push({uuid:n[a].uuid,error:d instanceof Error?d.message:String(d)})}return s.skipped=0,s}async function Ec(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
1144
+ LIMIT ?`).all(e,rt,r)}var Sc=null;async function Wh(){return Sc||(Ze().loaded||await nt(),$t)}async function Xh(e,t={}){let s={embedded:0,skipped:0,failed:0,failures:[]},n=Hh(e,{limit:t.limit,force:t.force});if(n.length===0)return s;let r=await Wh(),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(d=>({uuid:d.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{Bh({message_uuid:n[a].uuid,session_id:n[a].session_id,embedding:i[a],text_length:o[a].length}),s.embedded+=1}catch(d){s.failed+=1,s.failures.push({uuid:n[a].uuid,error:d instanceof Error?d.message:String(d)})}return s.skipped=0,s}async function yc(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
1148
1145
  FROM sessions s
1149
1146
  JOIN messages m ON m.session_id = s.id
1150
1147
  LEFT JOIN message_embeddings me ON me.message_uuid = m.uuid
@@ -1154,7 +1151,7 @@ show full content: recall paste --show <id>
1154
1151
  AND length(m.content_text) > ?
1155
1152
  AND me.message_uuid IS NULL
1156
1153
  ORDER BY s.started_at ASC
1157
- LIMIT ?`).all(...s,ot,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 Mh(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 Gs(e,t){return t===0?0:Math.round(e/t*1e3)/10}function Ee(e){return _().prepare("SELECT id, name FROM projects WHERE name = ? LIMIT 1").get(e)??null}function bc(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=Ee(e.projectName));let n=s?" WHERE s.project_id = ?":"",r=s?[s.id]:[],o=t.prepare(`SELECT
1154
+ LIMIT ?`).all(...s,rt,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 Xh(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 qs(e,t){return t===0?0:Math.round(e/t*1e3)/10}function Ee(e){return _().prepare("SELECT id, name FROM projects WHERE name = ? LIMIT 1").get(e)??null}function wc(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=Ee(e.projectName));let n=s?" WHERE s.project_id = ?":"",r=s?[s.id]:[],o=t.prepare(`SELECT
1158
1155
  COUNT(*) AS total,
1159
1156
  SUM(CASE WHEN ss.session_id IS NOT NULL THEN 1 ELSE 0 END) AS with_semantic,
1160
1157
  SUM(CASE WHEN cm_count.session_id IS NOT NULL THEN 1 ELSE 0 END) AS with_chunks,
@@ -1172,7 +1169,7 @@ show full content: recall paste --show <id>
1172
1169
  SUM(CASE
1173
1170
  WHEN m.is_sidechain = 0
1174
1171
  AND m.content_text IS NOT NULL
1175
- AND length(m.content_text) > ${ot}
1172
+ AND length(m.content_text) > ${rt}
1176
1173
  THEN 1 ELSE 0 END) AS eligible
1177
1174
  FROM messages m
1178
1175
  ${u}`).get(...r),m=s?" JOIN sessions s ON s.id = me.session_id WHERE s.project_id = ?":"",g=t.prepare(`SELECT COUNT(*) AS embedded
@@ -1181,8 +1178,8 @@ show full content: recall paste --show <id>
1181
1178
  FROM chunk_meta cm
1182
1179
  ${f}`).get(...r),E=s?" JOIN sessions s ON s.id = cq.session_id WHERE s.project_id = ?":"",b=t.prepare(`SELECT COUNT(*) AS n
1183
1180
  FROM chunk_queue cq
1184
- ${E}`).get(...r);return{project:s,sessions:{total:i,with_semantic:a,with_semantic_pct:Gs(a,i),with_chunks:d,with_chunks_pct:Gs(d,i),with_message_embeddings:l,with_message_embeddings_pct:Gs(l,i)},messages:{total:p.total??0,eligible:p.eligible??0,embedded:g.embedded,embedded_pct:Gs(g.embedded,p.eligible??0),threshold_chars:ot},chunks:{chunk_meta_rows:h.n,chunk_queue_pending:b.n},generated_at:new Date().toISOString()}}function Sc(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}}le();Ws();rt();async function yc(e,t){let s=(e??"audit").toLowerCase();if(s==="audit")return Dh(t);if(s==="backfill-summaries")return Ph(t);if(s==="backfill-messages")return Fh(t);console.error(`Unknown embeddings action: ${e}. Supported: audit | backfill-summaries | backfill-messages`),process.exitCode=1}function Dr(e){if(!e)return null;let t=Ee(e);return t||"not-found"}async function Dh(e){let t=Dr(e.project);if(t==="not-found"){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let s=bc({projectId:t?t.id:void 0}),n=Sc(s);if(e.json){console.log(JSON.stringify({report:s,verdict:n},null,2));return}$h(s,n),n.passes||(process.exitCode=1)}function $h(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 Ph(e){if(!ve().enabled){console.error("Semantic search is disabled. Run `recall semantic on` first."),process.exitCode=1;return}let s=Dr(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 Us({limit:n,projectId:s?s.id:void 0,onProgress:l=>{if(e.json||l.processed===i)return;i=l.processed;let u=l.total>0?` (${Math.round(l.processed/l.total*100)}%)`:"";process.stdout.write(`\r ${l.processed}/${l.total}${u} ok=${l.ok} failed=${l.failed} `)}});e.json||process.stdout.write(`
1185
- `);let d=((Date.now()-o)/1e3).toFixed(1);e.json?console.log(JSON.stringify({...a,elapsed_seconds:Number(d)},null,2)):console.log(`Done in ${d}s \u2014 processed=${a.processed} ok=${a.ok} failed=${a.failed}`)}async function Fh(e){if(await Ne("Per-message embeddings"),!yt()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}Ve().loaded||await nt();let t=Dr(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 > ${ot} chars \u2014 ${n} \u2014 up to ${s} sessions\u2026`);let r=Date.now(),o=0,i=await Ec({projectId:t?t.id:void 0,limitSessions:s,onProgress:m=>{if(e.json||m.processed_sessions===o)return;o=m.processed_sessions;let g=m.total_sessions>0?` (${Math.round(m.processed_sessions/m.total_sessions*100)}%)`:"";process.stdout.write(`\r ${m.processed_sessions}/${m.total_sessions} sessions${g} embedded=${m.embedded_messages} failed=${m.failed_messages} `)}});e.json||process.stdout.write(`
1181
+ ${E}`).get(...r);return{project:s,sessions:{total:i,with_semantic:a,with_semantic_pct:qs(a,i),with_chunks:d,with_chunks_pct:qs(d,i),with_message_embeddings:l,with_message_embeddings_pct:qs(l,i)},messages:{total:p.total??0,eligible:p.eligible??0,embedded:g.embedded,embedded_pct:qs(g.embedded,p.eligible??0),threshold_chars:rt},chunks:{chunk_meta_rows:h.n,chunk_queue_pending:b.n},generated_at:new Date().toISOString()}}function Tc(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}}de();Js();yt();async function Rc(e,t){let s=(e??"audit").toLowerCase();if(s==="audit")return Jh(t);if(s==="backfill-summaries")return Yh(t);if(s==="backfill-messages")return zh(t);console.error(`Unknown embeddings action: ${e}. Supported: audit | backfill-summaries | backfill-messages`),process.exitCode=1}function Pr(e){if(!e)return null;let t=Ee(e);return t||"not-found"}async function Jh(e){let t=Pr(e.project);if(t==="not-found"){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let s=wc({projectId:t?t.id:void 0}),n=Tc(s);if(e.json){console.log(JSON.stringify({report:s,verdict:n},null,2));return}Gh(s,n),n.passes||(process.exitCode=1)}function Gh(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 Yh(e){if(!ve().enabled){console.error("Semantic search is disabled. Run `recall semantic on` first."),process.exitCode=1;return}let s=Pr(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 Hs({limit:n,projectId:s?s.id:void 0,onProgress:l=>{if(e.json||l.processed===i)return;i=l.processed;let u=l.total>0?` (${Math.round(l.processed/l.total*100)}%)`:"";process.stdout.write(`\r ${l.processed}/${l.total}${u} ok=${l.ok} failed=${l.failed} `)}});e.json||process.stdout.write(`
1182
+ `);let d=((Date.now()-o)/1e3).toFixed(1);e.json?console.log(JSON.stringify({...a,elapsed_seconds:Number(d)},null,2)):console.log(`Done in ${d}s \u2014 processed=${a.processed} ok=${a.ok} failed=${a.failed}`)}async function zh(e){if(await Ne("Per-message embeddings"),!St()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}Ze().loaded||await nt();let t=Pr(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 > ${rt} chars \u2014 ${n} \u2014 up to ${s} sessions\u2026`);let r=Date.now(),o=0,i=await yc({projectId:t?t.id:void 0,limitSessions:s,onProgress:m=>{if(e.json||m.processed_sessions===o)return;o=m.processed_sessions;let g=m.total_sessions>0?` (${Math.round(m.processed_sessions/m.total_sessions*100)}%)`:"";process.stdout.write(`\r ${m.processed_sessions}/${m.total_sessions} sessions${g} embedded=${m.embedded_messages} failed=${m.failed_messages} `)}});e.json||process.stdout.write(`
1186
1183
  `);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 d=_(),l=t?" AND s.project_id = ?":"",u=t?[t.id]:[],p=d.prepare(`SELECT COUNT(DISTINCT s.id) AS n
1187
1184
  FROM sessions s
1188
1185
  JOIN messages m ON m.session_id = s.id
@@ -1191,7 +1188,7 @@ show full content: recall paste --show <id>
1191
1188
  AND m.content_text IS NOT NULL
1192
1189
  AND length(m.content_text) > ?
1193
1190
  AND me.message_uuid IS NULL
1194
- ${l}`).get(ot,...u);p.n>0&&console.log(` ${p.n} session(s) still have unembedded eligible messages. Re-run to continue.`)}w();import{createHash as Jh}from"node:crypto";Be();w();D();import{writeFileSync as jh,readFileSync as iA,existsSync as Uh,mkdirSync as Bh,readdirSync as aA}from"node:fs";import{join as wc}from"node:path";var $r=wc(x,"output-index");function Hh(){P(),Uh($r)||Bh($r,{recursive:!0})}function rs(e){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}function Wh(e){if(!e)return null;try{return JSON.parse(e)}catch{return e}}function Tc(e){return{session_id:e.session_id,files_written:rs(e.files_written),brands_mentioned:rs(e.brands_mentioned),terms_introduced:rs(e.terms_introduced),plan_ids_referenced:rs(e.plan_ids_referenced),bug_signatures:rs(e.bug_signatures),raw_extraction:Wh(e.raw_extraction),extracted_at:e.extracted_at,extractor_version:e.extractor_version}}function Rc(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??[]),d=e.raw_extraction===void 0?null:JSON.stringify(e.raw_extraction),l=Math.max(1,Math.floor(e.extractor_version??1));t.prepare(`INSERT INTO session_output_index
1191
+ ${l}`).get(rt,...u);p.n>0&&console.log(` ${p.n} session(s) still have unembedded eligible messages. Re-run to continue.`)}w();import{createHash as tE}from"node:crypto";Be();w();P();import{writeFileSync as qh,readFileSync as kA,existsSync as Kh,mkdirSync as Vh,readdirSync as CA}from"node:fs";import{join as xc}from"node:path";var Fr=xc(x,"output-index");function Zh(){F(),Kh(Fr)||Vh(Fr,{recursive:!0})}function rs(e){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}function Qh(e){if(!e)return null;try{return JSON.parse(e)}catch{return e}}function kc(e){return{session_id:e.session_id,files_written:rs(e.files_written),brands_mentioned:rs(e.brands_mentioned),terms_introduced:rs(e.terms_introduced),plan_ids_referenced:rs(e.plan_ids_referenced),bug_signatures:rs(e.bug_signatures),raw_extraction:Qh(e.raw_extraction),extracted_at:e.extracted_at,extractor_version:e.extractor_version}}function Cc(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??[]),d=e.raw_extraction===void 0?null:JSON.stringify(e.raw_extraction),l=Math.max(1,Math.floor(e.extractor_version??1));t.prepare(`INSERT INTO session_output_index
1195
1192
  (session_id, files_written, brands_mentioned, terms_introduced,
1196
1193
  plan_ids_referenced, bug_signatures, raw_extraction,
1197
1194
  extracted_at, extractor_version)
@@ -1204,7 +1201,7 @@ show full content: recall paste --show <id>
1204
1201
  bug_signatures = excluded.bug_signatures,
1205
1202
  raw_extraction = excluded.raw_extraction,
1206
1203
  extracted_at = excluded.extracted_at,
1207
- extractor_version = excluded.extractor_version`).run(e.session_id,n,r,o,i,a,d,s,l);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=Tc(u);return Xh(e.session_id),p}function os(e){let s=_().prepare("SELECT * FROM session_output_index WHERE session_id = ?").get(e);return s?Tc(s):null}function Xh(e){try{Hh();let t=os(e);if(!t)return;let s=wc($r,`${e}.json`),n={schema:"claude-recall.session-output-index.v1",backed_up_at:new Date().toISOString(),...t};jh(s,JSON.stringify(n,null,2))}catch(t){console.error("[output-index] backup failed:",t)}}var is=1,jr="claude-haiku-4-5-20251001",Yh=3,Gh=32e3,xc=2e3,zh=30,Kh=30,qh=30,Vh=30;function Zh(e){let s=_().prepare(`SELECT s.id,
1204
+ extractor_version = excluded.extractor_version`).run(e.session_id,n,r,o,i,a,d,s,l);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=kc(u);return eE(e.session_id),p}function os(e){let s=_().prepare("SELECT * FROM session_output_index WHERE session_id = ?").get(e);return s?kc(s):null}function eE(e){try{Zh();let t=os(e);if(!t)return;let s=xc(Fr,`${e}.json`),n={schema:"claude-recall.session-output-index.v1",backed_up_at:new Date().toISOString(),...t};qh(s,JSON.stringify(n,null,2))}catch(t){console.error("[output-index] backup failed:",t)}}var is=1,Br="claude-haiku-4-5-20251001",sE=3,nE=32e3,Lc=2e3,rE=30,oE=30,iE=30,aE=30;function cE(e){let s=_().prepare(`SELECT s.id,
1208
1205
  NULLIF(sa.alias, '') AS alias,
1209
1206
  s.auto_title,
1210
1207
  s.auto_title_source,
@@ -1215,15 +1212,15 @@ show full content: recall paste --show <id>
1215
1212
  FROM sessions s
1216
1213
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1217
1214
  LEFT JOIN projects p ON p.id = s.project_id
1218
- WHERE s.id = ?`).get(e);return s?{...s,alias_source:s.alias?"manual":null}:null}function kc(e,t={}){if(e.message_count<Yh)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=os(e.id);if(n&&n.extractor_version>=is)return{eligible:!1,reason:"already-extracted"}}return{eligible:!0}}function Qh(e){let t=Zh(e);if(!t)return null;let n=_().prepare(`SELECT role, content_text
1215
+ WHERE s.id = ?`).get(e);return s?{...s,alias_source:s.alias?"manual":null}:null}function Nc(e,t={}){if(e.message_count<sE)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=os(e.id);if(n&&n.extractor_version>=is)return{eligible:!1,reason:"already-extracted"}}return{eligible:!0}}function lE(e){let t=cE(e);if(!t)return null;let n=_().prepare(`SELECT role, content_text
1219
1216
  FROM messages
1220
1217
  WHERE session_id = ?
1221
1218
  AND is_sidechain = 0
1222
1219
  AND content_text IS NOT NULL
1223
- ORDER BY COALESCE(timestamp, ''), rowid`).all(e),r=[],o=0;for(let i of n){let a=i.role??"system",d=i.content_text.trim();if(!d)continue;let l=d.length>xc?d.slice(0,xc)+"\u2026":d,u=`${a}: ${l}`;if(o+u.length>Gh)break;r.push(u),o+=u.length}return{meta:t,excerpt:r.join(`
1220
+ ORDER BY COALESCE(timestamp, ''), rowid`).all(e),r=[],o=0;for(let i of n){let a=i.role??"system",d=i.content_text.trim();if(!d)continue;let l=d.length>Lc?d.slice(0,Lc)+"\u2026":d,u=`${a}: ${l}`;if(o+u.length>nE)break;r.push(u),o+=u.length}return{meta:t,excerpt:r.join(`
1224
1221
 
1225
- `)}}function eE(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(`
1226
- `)}function tE(e){return Array.isArray(e)&&e.every(t=>typeof t=="string")}function Pr(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 sE(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 d=typeof i=="number"&&Number.isFinite(i)&&i>0?Math.floor(i):1;if(n.push({term:a,frequency:d}),n.length>=t)break}return n}function nE(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",d=typeof o=="string"?o.trim().replace(/\s+/g," ").slice(0,256):"";if(!d)continue;let l=typeof i=="string"&&i.trim().length>0?i.trim().slice(0,256):null,u=Jh("sha256").update(`${a}::${d}`).digest("hex").slice(0,12);if(s.push({error_type:a,message_hash:u,snippet:d,file:l}),s.length>=t)break}return s}function rE(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=Pr(o.files_written,200),a=Pr(o.brands_mentioned,Kh),d=sE(o.terms_introduced,zh),l=Pr(o.plan_ids_referenced,qh),u=nE(o.bug_signatures,Vh);return i.length===0&&a.length===0&&d.length===0&&l.length===0&&u.length===0&&!tE(o.files_written)?null:{files_written:i,brands_mentioned:a,terms_introduced:d,plan_ids_referenced:l,bug_signatures:u}}var Fr=null;async function oE(e,t){return Fr?Fr(e,t):St(e,[],{model:t})}async function iE(e,t={}){if(t.signal?.aborted)return{session_id:e,ok:!1,failed:"aborted"};let s=Qh(e);if(!s)return{session_id:e,ok:!1,skipped:"session-not-found"};let n=kc(s.meta,{force:t.force});if(!n.eligible)return{session_id:e,ok:!1,skipped:n.reason};if(!Fr&&!se())return{session_id:e,ok:!1,failed:"claude-cli-missing"};let r=eE(s),o=t.model??jr,i=await oE(r,o);if(!i.success){let u=(i.stderr||i.stdout||"").slice(0,400),p=u?we(u).redacted:void 0;return{session_id:e,ok:!1,failed:"claude-cli-error",exit_code:i.exitCode,stderr_excerpt:p}}let a=rE(i.stdout);if(!a){let u=i.stdout.slice(0,400),p=u?we(u).redacted:void 0;return{session_id:e,ok:!1,failed:"parse-failed",exit_code:i.exitCode,stderr_excerpt:p}}let d=aE(i.stdout),l=Rc({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:d,raw_response_excerpt:i.stdout.slice(0,4e3)},extractor_version:is});return{session_id:e,ok:!0,index:l,usage:d}}function aE(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 cE(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,
1222
+ `)}}function dE(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(`
1223
+ `)}function uE(e){return Array.isArray(e)&&e.every(t=>typeof t=="string")}function jr(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 pE(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 d=typeof i=="number"&&Number.isFinite(i)&&i>0?Math.floor(i):1;if(n.push({term:a,frequency:d}),n.length>=t)break}return n}function mE(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",d=typeof o=="string"?o.trim().replace(/\s+/g," ").slice(0,256):"";if(!d)continue;let l=typeof i=="string"&&i.trim().length>0?i.trim().slice(0,256):null,u=tE("sha256").update(`${a}::${d}`).digest("hex").slice(0,12);if(s.push({error_type:a,message_hash:u,snippet:d,file:l}),s.length>=t)break}return s}function gE(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=jr(o.files_written,200),a=jr(o.brands_mentioned,oE),d=pE(o.terms_introduced,rE),l=jr(o.plan_ids_referenced,iE),u=mE(o.bug_signatures,aE);return i.length===0&&a.length===0&&d.length===0&&l.length===0&&u.length===0&&!uE(o.files_written)?null:{files_written:i,brands_mentioned:a,terms_introduced:d,plan_ids_referenced:l,bug_signatures:u}}var Ur=null;async function fE(e,t){return Ur?Ur(e,t):bt(e,[],{model:t})}async function _E(e,t={}){if(t.signal?.aborted)return{session_id:e,ok:!1,failed:"aborted"};let s=lE(e);if(!s)return{session_id:e,ok:!1,skipped:"session-not-found"};let n=Nc(s.meta,{force:t.force});if(!n.eligible)return{session_id:e,ok:!1,skipped:n.reason};if(!Ur&&!ne())return{session_id:e,ok:!1,failed:"claude-cli-missing"};let r=dE(s),o=t.model??Br,i=await fE(r,o);if(!i.success){let u=(i.stderr||i.stdout||"").slice(0,400),p=u?we(u).redacted:void 0;return{session_id:e,ok:!1,failed:"claude-cli-error",exit_code:i.exitCode,stderr_excerpt:p}}let a=gE(i.stdout);if(!a){let u=i.stdout.slice(0,400),p=u?we(u).redacted:void 0;return{session_id:e,ok:!1,failed:"parse-failed",exit_code:i.exitCode,stderr_excerpt:p}}let d=hE(i.stdout),l=Cc({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:d,raw_response_excerpt:i.stdout.slice(0,4e3)},extractor_version:is});return{session_id:e,ok:!0,index:l,usage:d}}function hE(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 EE(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,
1227
1224
  NULLIF(sa.alias, '') AS alias,
1228
1225
  s.auto_title,
1229
1226
  s.auto_title_source,
@@ -1235,13 +1232,13 @@ show full content: recall paste --show <id>
1235
1232
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1236
1233
  LEFT JOIN projects p ON p.id = s.project_id
1237
1234
  ${o}
1238
- ORDER BY COALESCE(s.started_at, ''), s.id`).all(...n),a=[],d=new Map;for(let l of i){let u={...l,alias_source:l.alias?"manual":null},p=kc(u,{force:e.force});if(!p.eligible){let m=p.reason??"session-not-found";d.set(m,(d.get(m)??0)+1);continue}if(a.push(u),a.length>=r)break}return{eligible:a,skipped:d}}async function Cc(e={}){let t=cE({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 iE(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}}Be();async function Lc(e){if(!e.project){console.error("--project <name> is required."),process.exitCode=1;return}let t=Ee(e.project);if(!t){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}if(!se()){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??jr;e.json||console.log(`Extracting Output Index \u2014 project "${t.name}" \u2014 extractor v${is} \u2014 model ${n} \u2014 up to ${s} sessions\u2026`);let r=Date.now(),o=-1,{progress:i,results:a}=await Cc({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(`
1239
- `);let d=Number(((Date.now()-r)/1e3).toFixed(1)),l=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:is,model:n,progress:i,acceptance_pct:l,failures:u.slice(0,20),elapsed_seconds:d},null,2))}else console.log(`Done in ${d}s \u2014 ok=${i.ok}/${i.total} (${l}%) failed=${i.failed} skipped=${i.skipped}`),console.log(`Token spend: input=${i.total_input_tokens} output=${i.total_output_tokens}`),i.total>0&&l<90?(console.log(` \u26A0 Phase D acceptance bar is 90% non-empty Output Index; actual ${l}%. Inspect failures and re-run.`),process.exitCode=1):i.total===0&&console.log(" \u24D8 No eligible sessions (all sessions were skipped or already extracted).")}w();as();var Vs={citation:"same-project",similar:"same-project",skill_track:"same-project",bug_pattern:"cross-project",wiki_link:"cross-project",temporal_proximity:"same-project"},SE=2,yE=.25,wE=5,TE=60,RE=25;function qs(e){return e.trim().toLowerCase()}function xE(e){let t=new Set;for(let s of e.files_written)t.add(`file:${qs(s)}`);for(let s of e.brands_mentioned)t.add(`brand:${qs(s)}`);for(let s of e.terms_introduced)t.add(`term:${qs(s)}`);for(let s of e.plan_ids_referenced)t.add(`plan:${qs(s)}`);return t}function kE(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/TE);return Math.max(.2,t)}function CE(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 LE(e){let t=os(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 NE(e){return _().prepare(`SELECT s.id AS id, s.project_id AS project_id, s.started_at AS started_at
1235
+ ORDER BY COALESCE(s.started_at, ''), s.id`).all(...n),a=[],d=new Map;for(let l of i){let u={...l,alias_source:l.alias?"manual":null},p=Nc(u,{force:e.force});if(!p.eligible){let m=p.reason??"session-not-found";d.set(m,(d.get(m)??0)+1);continue}if(a.push(u),a.length>=r)break}return{eligible:a,skipped:d}}async function Ac(e={}){let t=EE({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 _E(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}}Be();async function Oc(e){if(!e.project){console.error("--project <name> is required."),process.exitCode=1;return}let t=Ee(e.project);if(!t){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}if(!ne()){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??Br;e.json||console.log(`Extracting Output Index \u2014 project "${t.name}" \u2014 extractor v${is} \u2014 model ${n} \u2014 up to ${s} sessions\u2026`);let r=Date.now(),o=-1,{progress:i,results:a}=await Ac({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(`
1236
+ `);let d=Number(((Date.now()-r)/1e3).toFixed(1)),l=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:is,model:n,progress:i,acceptance_pct:l,failures:u.slice(0,20),elapsed_seconds:d},null,2))}else console.log(`Done in ${d}s \u2014 ok=${i.ok}/${i.total} (${l}%) failed=${i.failed} skipped=${i.skipped}`),console.log(`Token spend: input=${i.total_input_tokens} output=${i.total_output_tokens}`),i.total>0&&l<90?(console.log(` \u26A0 Phase D acceptance bar is 90% non-empty Output Index; actual ${l}%. Inspect failures and re-run.`),process.exitCode=1):i.total===0&&console.log(" \u24D8 No eligible sessions (all sessions were skipped or already extracted).")}w();as();var Qs={citation:"same-project",similar:"same-project",skill_track:"same-project",bug_pattern:"cross-project",wiki_link:"cross-project",temporal_proximity:"same-project"},AE=2,OE=.25,vE=5,IE=60,ME=25;function Zs(e){return e.trim().toLowerCase()}function DE(e){let t=new Set;for(let s of e.files_written)t.add(`file:${Zs(s)}`);for(let s of e.brands_mentioned)t.add(`brand:${Zs(s)}`);for(let s of e.terms_introduced)t.add(`term:${Zs(s)}`);for(let s of e.plan_ids_referenced)t.add(`plan:${Zs(s)}`);return t}function $E(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/IE);return Math.max(.2,t)}function PE(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 FE(e){let t=os(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 jE(e){return _().prepare(`SELECT s.id AS id, s.project_id AS project_id, s.started_at AS started_at
1240
1237
  FROM sessions s
1241
1238
  JOIN session_output_index oi ON oi.session_id = s.id
1242
1239
  WHERE s.project_id = ?
1243
- ORDER BY COALESCE(s.started_at, ''), s.id`).all(e)}function AE(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=xE(i);if(a.size!==0){n.set(o.id,a);for(let d of a){let l=s.get(d);l?l.push(o.id):s.set(d,[o.id])}}}return{posting:s,vocab:n,startedAt:r}}function OE(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 d of a){if(d===e)continue;let l=t.startedAt.get(d);if(!l||l>=n)continue;let u=r.get(d);u?u.push(i):r.set(d,[i])}}let o=[];for(let[i,a]of r){let d=a.length;if(d<SE)continue;let l=t.startedAt.get(i)??null,u=CE(n,l),p=kE(u),m=Math.min(1,d/wE*p);if(m<yE)continue;let g=a.slice(0,12);o.push({target_session_id:i,matched_terms:g,overlap:d,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,RE)}async function Pc(e){if(Vs.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project \u2014 refusing to run inference");let t=NE(e.projectId),s=new Map;for(let i of t){let a=LE(i.id);a&&s.set(i.id,a)}let n=AE(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=OE(i.id,n);for(let d of a)try{let l=it({source_session_id:i.id,target_session_id:d.target_session_id,link_type:"citation",confidence:d.confidence,evidence:{matched_terms:d.matched_terms,overlap_count:d.overlap,recency:d.recency,days_apart:d.days_apart},inferred_by:"L2"});o.push(l.id),r.suggestions_created+=1}catch(l){console.error("[citation-inference] createSuggestion failed:",l)}r.processed_sessions+=1,e.onProgress?.({...r})}return r.current_session_id=null,e.onProgress?.({...r}),{progress:r,suggestion_ids:o}}async function Fc(e){if(!e.project){console.error("--project <name> is required."),process.exitCode=1;return}let t=Ee(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 Pc({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(`
1244
- `);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 JE,readFileSync as YE}from"node:fs";import{join as GE}from"node:path";w();as();var vE=/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/gi,IE=[/\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],ME=.95,DE=.85,$E=.7,Jr=50,PE=50;function FE(e){if(!e)return[];let t=new Set,s=[],n=e.match(vE);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>=Jr))break}return s}function jE(e){if(!e)return[];let t=new Set,s=[];for(let n of IE){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>=Jr))break}if(s.length>=Jr)break}}return s}function Yr(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 jc(e){let t=_();return typeof e=="number"?t.prepare(`SELECT m.uuid AS message_uuid, m.session_id, m.content_text,
1240
+ ORDER BY COALESCE(s.started_at, ''), s.id`).all(e)}function UE(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=DE(i);if(a.size!==0){n.set(o.id,a);for(let d of a){let l=s.get(d);l?l.push(o.id):s.set(d,[o.id])}}}return{posting:s,vocab:n,startedAt:r}}function BE(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 d of a){if(d===e)continue;let l=t.startedAt.get(d);if(!l||l>=n)continue;let u=r.get(d);u?u.push(i):r.set(d,[i])}}let o=[];for(let[i,a]of r){let d=a.length;if(d<AE)continue;let l=t.startedAt.get(i)??null,u=PE(n,l),p=$E(u),m=Math.min(1,d/vE*p);if(m<OE)continue;let g=a.slice(0,12);o.push({target_session_id:i,matched_terms:g,overlap:d,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,ME)}async function Uc(e){if(Qs.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project \u2014 refusing to run inference");let t=jE(e.projectId),s=new Map;for(let i of t){let a=FE(i.id);a&&s.set(i.id,a)}let n=UE(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=BE(i.id,n);for(let d of a)try{let l=ot({source_session_id:i.id,target_session_id:d.target_session_id,link_type:"citation",confidence:d.confidence,evidence:{matched_terms:d.matched_terms,overlap_count:d.overlap,recency:d.recency,days_apart:d.days_apart},inferred_by:"L2"});o.push(l.id),r.suggestions_created+=1}catch(l){console.error("[citation-inference] createSuggestion failed:",l)}r.processed_sessions+=1,e.onProgress?.({...r})}return r.current_session_id=null,e.onProgress?.({...r}),{progress:r,suggestion_ids:o}}async function Bc(e){if(!e.project){console.error("--project <name> is required."),process.exitCode=1;return}let t=Ee(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 Uc({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(`
1241
+ `);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 tb,readFileSync as sb}from"node:fs";import{join as nb}from"node:path";w();as();var HE=/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/gi,WE=[/\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],XE=.95,JE=.85,GE=.7,Yr=50,YE=50;function zE(e){if(!e)return[];let t=new Set,s=[],n=e.match(HE);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>=Yr))break}return s}function qE(e){if(!e)return[];let t=new Set,s=[];for(let n of WE){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>=Yr))break}if(s.length>=Yr)break}}return s}function zr(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 Hc(e){let t=_();return typeof e=="number"?t.prepare(`SELECT m.uuid AS message_uuid, m.session_id, m.content_text,
1245
1242
  s.project_id
1246
1243
  FROM messages m
1247
1244
  JOIN sessions s ON s.id = m.session_id
@@ -1254,12 +1251,12 @@ show full content: recall paste --show <id>
1254
1251
  JOIN sessions s ON s.id = m.session_id
1255
1252
  WHERE m.is_sidechain = 0
1256
1253
  AND m.content_text IS NOT NULL
1257
- AND length(m.content_text) > 0`).all()}function UE(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,
1254
+ AND length(m.content_text) > 0`).all()}function KE(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,
1258
1255
  s.project_id AS project_id,
1259
1256
  oi.plan_ids_referenced AS plan_ids_json
1260
1257
  FROM session_output_index oi
1261
1258
  JOIN sessions s ON s.id = oi.session_id
1262
- ${s}`).all(...n)}function BE(e){if(!e)return[];try{let t=JSON.parse(e);if(Array.isArray(t))return t.filter(s=>typeof s=="string")}catch{}return[]}function HE(e={}){if(Vs.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project");let t=Yr(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 jc(e.projectId)){if(e.signal?.aborted)break;let i=FE(o.content_text);if(i.length===0)continue;let a=n.get(o.session_id);if(a!==void 0)for(let d of i){if(d===o.session_id)continue;let l=n.get(d);if(!(l===void 0&&!s.has(d))&&!(l!==void 0&&a!==void 0&&l!==a))try{it({source_session_id:o.session_id,target_session_id:d,link_type:"citation",confidence:ME,evidence:{matched_uuid:d,source_message_uuid:o.message_uuid,scanner:"uuid-ref"},inferred_by:"L1"}),r+=1}catch{}}}return{created:r}}function WE(e={}){let t=UE(e.projectId);if(t.length===0)return{created:0};let s=new Map;for(let a of t){let d=BE(a.plan_ids_json);for(let l of d){let u=l.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=Yr(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 jc(e.projectId)){if(e.signal?.aborted)break;let d=jE(a.content_text);if(d.length===0)continue;let l=r.get(a.session_id);if(l!==void 0)for(let u of d){let p=s.get(u);if(p)for(let m of p){if(m.id===a.session_id||m.project_id!==l)continue;let g=i.get(a.session_id);g||(g=new Map,i.set(a.session_id,g));let f=g.get(m.id);f||(f=new Set,g.set(m.id,f)),f.add(u)}}}for(let[a,d]of i)for(let[l,u]of d)try{it({source_session_id:a,target_session_id:l,link_type:"citation",confidence:DE,evidence:{matched_plan_ids:Array.from(u).slice(0,12),scanner:"plan-ref"},inferred_by:"L1"}),o+=1}catch{}return{created:o}}function XE(e){if(Vs.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=Yr(e.projectId),s=new Map,n=new Map;if(t.length>0){let i=_(),a=t.map(u=>u.id),d=a.map(()=>"?").join(","),l=i.prepare(`SELECT id, started_at FROM sessions WHERE id IN (${d})`).all(...a);for(let u of l)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 d=`${i.cwd??"<no-cwd>"}::${i.tab_name}`,l=r.get(d);l||(l=new Set,r.set(d,l));for(let u of a)l.add(u)}let o=0;for(let[,i]of r){if(i.size<2)continue;let a=new Map;for(let d of i){let l=s.get(d);if(l===void 0||typeof e.projectId=="number"&&l!==e.projectId)continue;let u=a.get(l);u||(u=[],a.set(l,u)),u.push(d)}for(let[,d]of a){if(d.length<2)continue;d.sort((u,p)=>{let m=n.get(u)??"",g=n.get(p)??"";return m<g?-1:m>g?1:u<p?-1:1});let l=0;for(let u=1;u<d.length&&!e.signal?.aborted;u++)for(let p=0;p<u&&!(l>=PE);p++)try{it({source_session_id:d[u],target_session_id:d[p],link_type:"skill_track",confidence:$E,evidence:{shared_tab_signature:!0,bucket_size:d.length,scanner:"tab-carry"},inferred_by:"L1"}),o+=1,l+=1}catch{}}}return{created:o}}function Uc(e={}){let t=HE(e);if(e.signal?.aborted)return{uuid_refs_created:t.created,plan_refs_created:0,tab_carry_created:0,total:t.created};let s=WE(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?XE({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}}D();function zE(){let e=GE(x,"terminals.json");if(JE(e))try{let t=YE(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 Bc(e){let t=null;if(e.project&&(t=Ee(e.project),!t)){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let s=zE(),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=Uc({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)."))}w();Be();as();function Gr(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 Kr="claude-haiku-4-5-20251001",Zs=.4,qr=.95,Hc=30,Wc=240,KE=new Set(["CITATION","SIMILAR","SKILL_TRACK","UNRELATED"]),qE={CITATION:"citation",SIMILAR:"similar",SKILL_TRACK:"skill_track"};function Yc(e){return _().prepare(`SELECT s.id,
1259
+ ${s}`).all(...n)}function VE(e){if(!e)return[];try{let t=JSON.parse(e);if(Array.isArray(t))return t.filter(s=>typeof s=="string")}catch{}return[]}function ZE(e={}){if(Qs.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project");let t=zr(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 Hc(e.projectId)){if(e.signal?.aborted)break;let i=zE(o.content_text);if(i.length===0)continue;let a=n.get(o.session_id);if(a!==void 0)for(let d of i){if(d===o.session_id)continue;let l=n.get(d);if(!(l===void 0&&!s.has(d))&&!(l!==void 0&&a!==void 0&&l!==a))try{ot({source_session_id:o.session_id,target_session_id:d,link_type:"citation",confidence:XE,evidence:{matched_uuid:d,source_message_uuid:o.message_uuid,scanner:"uuid-ref"},inferred_by:"L1"}),r+=1}catch{}}}return{created:r}}function QE(e={}){let t=KE(e.projectId);if(t.length===0)return{created:0};let s=new Map;for(let a of t){let d=VE(a.plan_ids_json);for(let l of d){let u=l.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=zr(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 Hc(e.projectId)){if(e.signal?.aborted)break;let d=qE(a.content_text);if(d.length===0)continue;let l=r.get(a.session_id);if(l!==void 0)for(let u of d){let p=s.get(u);if(p)for(let m of p){if(m.id===a.session_id||m.project_id!==l)continue;let g=i.get(a.session_id);g||(g=new Map,i.set(a.session_id,g));let f=g.get(m.id);f||(f=new Set,g.set(m.id,f)),f.add(u)}}}for(let[a,d]of i)for(let[l,u]of d)try{ot({source_session_id:a,target_session_id:l,link_type:"citation",confidence:JE,evidence:{matched_plan_ids:Array.from(u).slice(0,12),scanner:"plan-ref"},inferred_by:"L1"}),o+=1}catch{}return{created:o}}function eb(e){if(Qs.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=zr(e.projectId),s=new Map,n=new Map;if(t.length>0){let i=_(),a=t.map(u=>u.id),d=a.map(()=>"?").join(","),l=i.prepare(`SELECT id, started_at FROM sessions WHERE id IN (${d})`).all(...a);for(let u of l)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 d=`${i.cwd??"<no-cwd>"}::${i.tab_name}`,l=r.get(d);l||(l=new Set,r.set(d,l));for(let u of a)l.add(u)}let o=0;for(let[,i]of r){if(i.size<2)continue;let a=new Map;for(let d of i){let l=s.get(d);if(l===void 0||typeof e.projectId=="number"&&l!==e.projectId)continue;let u=a.get(l);u||(u=[],a.set(l,u)),u.push(d)}for(let[,d]of a){if(d.length<2)continue;d.sort((u,p)=>{let m=n.get(u)??"",g=n.get(p)??"";return m<g?-1:m>g?1:u<p?-1:1});let l=0;for(let u=1;u<d.length&&!e.signal?.aborted;u++)for(let p=0;p<u&&!(l>=YE);p++)try{ot({source_session_id:d[u],target_session_id:d[p],link_type:"skill_track",confidence:GE,evidence:{shared_tab_signature:!0,bucket_size:d.length,scanner:"tab-carry"},inferred_by:"L1"}),o+=1,l+=1}catch{}}}return{created:o}}function Wc(e={}){let t=ZE(e);if(e.signal?.aborted)return{uuid_refs_created:t.created,plan_refs_created:0,tab_carry_created:0,total:t.created};let s=QE(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?eb({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}}P();function rb(){let e=nb(x,"terminals.json");if(tb(e))try{let t=sb(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 Xc(e){let t=null;if(e.project&&(t=Ee(e.project),!t)){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let s=rb(),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=Wc({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)."))}w();Be();as();function qr(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 Vr="claude-haiku-4-5-20251001",en=.4,Zr=.95,Jc=30,Gc=240,ob=new Set(["CITATION","SIMILAR","SKILL_TRACK","UNRELATED"]),ib={CITATION:"citation",SIMILAR:"similar",SKILL_TRACK:"skill_track"};function qc(e){return _().prepare(`SELECT s.id,
1263
1260
  s.source_session_id,
1264
1261
  s.target_session_id,
1265
1262
  s.link_type,
@@ -1269,7 +1266,7 @@ show full content: recall paste --show <id>
1269
1266
  FROM session_link_suggestions s
1270
1267
  JOIN sessions src ON src.id = s.source_session_id
1271
1268
  WHERE s.status = 'pending'
1272
- AND src.project_id = ?`).all(e)}function VE(e){if(e.length===0)return new Map;let t=_(),s=e.map(()=>"?").join(","),n=t.prepare(`SELECT s.id,
1269
+ AND src.project_id = ?`).all(e)}function ab(e){if(e.length===0)return new Map;let t=_(),s=e.map(()=>"?").join(","),n=t.prepare(`SELECT s.id,
1273
1270
  NULLIF(sa.alias, '') AS alias,
1274
1271
  s.auto_title,
1275
1272
  s.first_user_message,
@@ -1278,18 +1275,18 @@ show full content: recall paste --show <id>
1278
1275
  FROM sessions s
1279
1276
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1280
1277
  LEFT JOIN projects p ON p.id = s.project_id
1281
- WHERE s.id IN (${s})`).all(...e),r=new Map;for(let o of n)r.set(o.id,o);return r}function Xc(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 Jc(e){try{return JSON.parse(e)}catch{return e}}function ZE(e){let t=e.minConfidence??Zs,s=Math.max(1,Math.min(500,e.limit??100)),n=Yc(e.projectId);if(n.length===0)return[];let r=new Map,o=new Map;for(let l of n){let u=`${l.source_session_id}|${l.target_session_id}|${l.link_type}`,p=o.get(u);p||(p={source_session_id:l.source_session_id,target_session_id:l.target_session_id,link_type:l.link_type,layers:[]},o.set(u,p));let m=p.layers.find(g=>g.inferred_by===l.inferred_by);m?(m.suggestion_ids.push(l.id),l.confidence>m.confidence&&(m.confidence=l.confidence,m.evidence=Jc(l.evidence))):p.layers.push({inferred_by:l.inferred_by,link_type:l.link_type,confidence:l.confidence,evidence:Jc(l.evidence),suggestion_ids:[l.id]})}let i=new Set;for(let l of o.values())i.add(l.source_session_id),i.add(l.target_session_id);let a=VE(Array.from(i)),d=[];for(let l of o.values()){let u=Gr(l.layers.map(g=>g.confidence));if(u<t)continue;let p=a.get(l.source_session_id),m=a.get(l.target_session_id);d.push({source_session_id:l.source_session_id,target_session_id:l.target_session_id,primary_link_type:l.link_type,combined_confidence:u,layers:l.layers,source_title:Xc(p,l.source_session_id),target_title:Xc(m,l.target_session_id),source_project:p?.project??null})}return d.sort((l,u)=>u.combined_confidence-l.combined_confidence),d.slice(0,s)}function QE(e){let t;try{t=JSON.stringify(e)}catch{t=String(e)}return t.length>Wc&&(t=t.slice(0,Wc)+"\u2026"),t}function eb(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=${QE(r.evidence)}`)}),t.join(`
1282
- `)}var zr=null;async function tb(e,t){return zr?zr(e,t):St(e,[],{model:t})}function sb(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 nb(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,d=typeof a.i=="number"?a.i:typeof a.pair_index=="number"?a.pair_index:NaN;if(!Number.isInteger(d)||d<0)continue;let l=typeof a.label=="string"?a.label.toUpperCase():"";if(!KE.has(l))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:d,label:l,confidence:p,reason:m})}return o}async function Gc(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(!zr&&!se())return t.failures.push({batch_index:-1,error:"claude CLI not available on PATH"}),t;let s=ZE({projectId:e.projectId,minConfidence:e.minConfidence??Zs,limit:e.limit??100});t.candidates_after_filter=s.length;let n=Yc(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??Kr,i=e.autoPromoteThreshold??qr;for(let a=0,d=0;a<s.length&&!e.signal?.aborted;a+=Hc,d+=1){let l=s.slice(a,a+Hc);e.onBatchStart?.({batch:d,pairs:l.length});let u=eb(l),p=await tb(u,o);if(!p.success){t.failures.push({batch_index:d,error:`claude CLI exited ${p.exitCode}: ${p.stderr.slice(0,200)}`});continue}let m=nb(p.stdout);if(!m){t.failures.push({batch_index:d,error:"parse-failed"});continue}let g=sb(p.stdout);t.total_input_tokens+=g.input_tokens,t.total_output_tokens+=g.output_tokens;for(let f of m){if(f.pair_index>=l.length)continue;let h=l[f.pair_index];if(t.classified+=1,f.label==="UNRELATED")continue;let E=qE[f.label];if(E)try{let b=it({source_session_id:h.source_session_id,target_session_id:h.target_session_id,link_type:E,confidence:f.confidence,evidence:{l4_label:f.label,l4_reason:f.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(R=>R.confidence);if(S.push(f.confidence),Gr(S)>=i)try{Dc(b.id,"approved",{source:"auto"}),t.links_promoted+=1}catch{}}}catch{}}}return t}Be();var rb=1e3;function ob(e){let t=e.minConf?Math.max(0,Math.min(1,Number(e.minConf))):Zs,s=e.autoPromoteThreshold!==void 0?Math.max(0,Math.min(1,Number(e.autoPromoteThreshold))):qr,n=e.limit?Math.max(1,Number(e.limit)):rb,r=e.model??Kr,o=!!e.autoPromote||e.autoPromoteThreshold!==void 0;return{minConfidence:t,autoPromoteThreshold:s,limit:n,model:r,autoPromote:o}}async function zc(e){if(!e.project){console.error("--project <name> is required."),process.exitCode=1;return}let t=Ee(e.project);if(!t){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}if(!se()){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}=ob(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(),d=await Gc({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(`
1283
- `);let l=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,...d,elapsed_seconds:l},null,2));else{if(console.log(`Done in ${l}s \u2014 pairs=${d.candidates_after_filter}/${d.candidates_total} classified=${d.classified} suggestions=${d.suggestions_created} promoted=${d.links_promoted} failures=${d.failures.length}`),console.log(`Token spend: input=${d.total_input_tokens} output=${d.total_output_tokens}`),d.failures.length>0)for(let u of d.failures.slice(0,3))console.log(` \u26A0 batch ${u.batch_index}: ${u.error}`);d.suggestions_created>0?console.log(" Review the new L4 suggestions at #view=suggestions (filter by inferred_by=L4)."):d.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.`)}}w();import{createHash as mb}from"node:crypto";w();D();import{writeFileSync as ib,readFileSync as nO,existsSync as ab,mkdirSync as cb,readdirSync as rO,unlinkSync as oO}from"node:fs";import{join as Kc}from"node:path";import{randomUUID as lb}from"node:crypto";var Vr=Kc(x,"bug-patterns");function db(){P(),ab(Vr)||cb(Vr,{recursive:!0})}function Qs(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 ub(e){return{cluster_id:e.cluster_id,session_id:e.session_id,matched_at:e.matched_at}}function qc(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??lb(),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
1278
+ WHERE s.id IN (${s})`).all(...e),r=new Map;for(let o of n)r.set(o.id,o);return r}function Yc(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 zc(e){try{return JSON.parse(e)}catch{return e}}function cb(e){let t=e.minConfidence??en,s=Math.max(1,Math.min(500,e.limit??100)),n=qc(e.projectId);if(n.length===0)return[];let r=new Map,o=new Map;for(let l of n){let u=`${l.source_session_id}|${l.target_session_id}|${l.link_type}`,p=o.get(u);p||(p={source_session_id:l.source_session_id,target_session_id:l.target_session_id,link_type:l.link_type,layers:[]},o.set(u,p));let m=p.layers.find(g=>g.inferred_by===l.inferred_by);m?(m.suggestion_ids.push(l.id),l.confidence>m.confidence&&(m.confidence=l.confidence,m.evidence=zc(l.evidence))):p.layers.push({inferred_by:l.inferred_by,link_type:l.link_type,confidence:l.confidence,evidence:zc(l.evidence),suggestion_ids:[l.id]})}let i=new Set;for(let l of o.values())i.add(l.source_session_id),i.add(l.target_session_id);let a=ab(Array.from(i)),d=[];for(let l of o.values()){let u=qr(l.layers.map(g=>g.confidence));if(u<t)continue;let p=a.get(l.source_session_id),m=a.get(l.target_session_id);d.push({source_session_id:l.source_session_id,target_session_id:l.target_session_id,primary_link_type:l.link_type,combined_confidence:u,layers:l.layers,source_title:Yc(p,l.source_session_id),target_title:Yc(m,l.target_session_id),source_project:p?.project??null})}return d.sort((l,u)=>u.combined_confidence-l.combined_confidence),d.slice(0,s)}function lb(e){let t;try{t=JSON.stringify(e)}catch{t=String(e)}return t.length>Gc&&(t=t.slice(0,Gc)+"\u2026"),t}function db(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=${lb(r.evidence)}`)}),t.join(`
1279
+ `)}var Kr=null;async function ub(e,t){return Kr?Kr(e,t):bt(e,[],{model:t})}function pb(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 mb(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,d=typeof a.i=="number"?a.i:typeof a.pair_index=="number"?a.pair_index:NaN;if(!Number.isInteger(d)||d<0)continue;let l=typeof a.label=="string"?a.label.toUpperCase():"";if(!ob.has(l))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:d,label:l,confidence:p,reason:m})}return o}async function Kc(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(!Kr&&!ne())return t.failures.push({batch_index:-1,error:"claude CLI not available on PATH"}),t;let s=cb({projectId:e.projectId,minConfidence:e.minConfidence??en,limit:e.limit??100});t.candidates_after_filter=s.length;let n=qc(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??Vr,i=e.autoPromoteThreshold??Zr;for(let a=0,d=0;a<s.length&&!e.signal?.aborted;a+=Jc,d+=1){let l=s.slice(a,a+Jc);e.onBatchStart?.({batch:d,pairs:l.length});let u=db(l),p=await ub(u,o);if(!p.success){t.failures.push({batch_index:d,error:`claude CLI exited ${p.exitCode}: ${p.stderr.slice(0,200)}`});continue}let m=mb(p.stdout);if(!m){t.failures.push({batch_index:d,error:"parse-failed"});continue}let g=pb(p.stdout);t.total_input_tokens+=g.input_tokens,t.total_output_tokens+=g.output_tokens;for(let f of m){if(f.pair_index>=l.length)continue;let h=l[f.pair_index];if(t.classified+=1,f.label==="UNRELATED")continue;let E=ib[f.label];if(E)try{let b=ot({source_session_id:h.source_session_id,target_session_id:h.target_session_id,link_type:E,confidence:f.confidence,evidence:{l4_label:f.label,l4_reason:f.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(T=>T.confidence);if(S.push(f.confidence),qr(S)>=i)try{Fc(b.id,"approved",{source:"auto"}),t.links_promoted+=1}catch{}}}catch{}}}return t}Be();var gb=1e3;function fb(e){let t=e.minConf?Math.max(0,Math.min(1,Number(e.minConf))):en,s=e.autoPromoteThreshold!==void 0?Math.max(0,Math.min(1,Number(e.autoPromoteThreshold))):Zr,n=e.limit?Math.max(1,Number(e.limit)):gb,r=e.model??Vr,o=!!e.autoPromote||e.autoPromoteThreshold!==void 0;return{minConfidence:t,autoPromoteThreshold:s,limit:n,model:r,autoPromote:o}}async function Vc(e){if(!e.project){console.error("--project <name> is required."),process.exitCode=1;return}let t=Ee(e.project);if(!t){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}if(!ne()){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}=fb(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(),d=await Kc({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(`
1280
+ `);let l=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,...d,elapsed_seconds:l},null,2));else{if(console.log(`Done in ${l}s \u2014 pairs=${d.candidates_after_filter}/${d.candidates_total} classified=${d.classified} suggestions=${d.suggestions_created} promoted=${d.links_promoted} failures=${d.failures.length}`),console.log(`Token spend: input=${d.total_input_tokens} output=${d.total_output_tokens}`),d.failures.length>0)for(let u of d.failures.slice(0,3))console.log(` \u26A0 batch ${u.batch_index}: ${u.error}`);d.suggestions_created>0?console.log(" Review the new L4 suggestions at #view=suggestions (filter by inferred_by=L4)."):d.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.`)}}w();import{createHash as Tb}from"node:crypto";w();P();import{writeFileSync as _b,readFileSync as TO,existsSync as hb,mkdirSync as Eb,readdirSync as RO,unlinkSync as xO}from"node:fs";import{join as Zc}from"node:path";import{randomUUID as bb}from"node:crypto";var Qr=Zc(x,"bug-patterns");function Sb(){F(),hb(Qr)||Eb(Qr,{recursive:!0})}function tn(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 yb(e){return{cluster_id:e.cluster_id,session_id:e.session_id,matched_at:e.matched_at}}function Qc(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??bb(),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
1284
1281
  (id, signature_hash, example_message, occurrence_count,
1285
1282
  first_seen_at, last_seen_at, resolved_in_session_id, fix_summary)
1286
1283
  VALUES (?, ?, ?, ?, ?, ?, NULL, NULL)`).run(n,e.signature_hash,e.example_message,i.length,r,o);let d=t.prepare(`INSERT INTO bug_pattern_members (cluster_id, session_id, matched_at)
1287
1284
  VALUES (?, ?, ?)
1288
- ON CONFLICT(cluster_id, session_id) DO NOTHING`);for(let l of i)d.run(n,l,s)})();let a=Vc(n);if(!a)throw new Error("createCluster succeeded but read-back failed");return el(n),a}function Vc(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:Qs(s),members:n.map(ub)}}function Zc(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)
1285
+ ON CONFLICT(cluster_id, session_id) DO NOTHING`);for(let l of i)d.run(n,l,s)})();let a=el(n);if(!a)throw new Error("createCluster succeeded but read-back failed");return nl(n),a}function el(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:tn(s),members:n.map(yb)}}function tl(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)
1289
1286
  VALUES (?, ?, ?)
1290
1287
  ON CONFLICT(cluster_id, session_id) DO NOTHING`);for(let d of Array.from(new Set(t)))a.run(e,d,r).changes>0&&(o+=1);if(o>0){let d=s.prepare("SELECT COUNT(*) AS n FROM bug_pattern_members WHERE cluster_id = ?").get(e).n;s.prepare(`UPDATE bug_pattern_clusters
1291
1288
  SET occurrence_count = ?, last_seen_at = ?
1292
- WHERE id = ?`).run(d,r,e)}})(),o>0&&el(e);let i=s.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);return{cluster:Qs(i),added:o}}function pb(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 Qc(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,
1289
+ WHERE id = ?`).run(d,r,e)}})(),o>0&&nl(e);let i=s.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);return{cluster:tn(i),added:o}}function wb(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 sl(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,
1293
1290
  NULLIF(sa.alias, '') AS alias,
1294
1291
  s.auto_title,
1295
1292
  s.first_user_message,
@@ -1300,37 +1297,37 @@ show full content: recall paste --show <id>
1300
1297
  LEFT JOIN session_aliases sa ON sa.session_id = m.session_id
1301
1298
  LEFT JOIN projects p ON p.id = s.project_id
1302
1299
  WHERE m.cluster_id = ?
1303
- ORDER BY COALESCE(s.started_at, ''), m.matched_at, m.session_id`).all(e);return{cluster:Qs(s),members:n.map(pb)}}function el(e){try{db();let t=Vc(e);if(!t)return;let s=Kc(Vr,`${e}.json`),n={schema:"claude-recall.bug-pattern-cluster.v1",cluster:t.cluster,members:t.members,backed_up_at:new Date().toISOString()};ib(s,JSON.stringify(n,null,2))}catch(t){console.error("[bug-patterns] backup failed:",t)}}function tl(e){return e?_().prepare(`SELECT * FROM bug_pattern_clusters
1300
+ ORDER BY COALESCE(s.started_at, ''), m.matched_at, m.session_id`).all(e);return{cluster:tn(s),members:n.map(wb)}}function nl(e){try{Sb();let t=el(e);if(!t)return;let s=Zc(Qr,`${e}.json`),n={schema:"claude-recall.bug-pattern-cluster.v1",cluster:t.cluster,members:t.members,backed_up_at:new Date().toISOString()};_b(s,JSON.stringify(n,null,2))}catch(t){console.error("[bug-patterns] backup failed:",t)}}function rl(e){return e?_().prepare(`SELECT * FROM bug_pattern_clusters
1304
1301
  WHERE signature_hash = ?
1305
- ORDER BY last_seen_at DESC, id ASC`).all(e).map(Qs):[]}function sl(e){if(!e)return new Set;let s=_().prepare(`SELECT DISTINCT m.session_id
1302
+ ORDER BY last_seen_at DESC, id ASC`).all(e).map(tn):[]}function ol(e){if(!e)return new Set;let s=_().prepare(`SELECT DISTINCT m.session_id
1306
1303
  FROM bug_pattern_members m
1307
1304
  JOIN bug_pattern_clusters c ON c.id = m.cluster_id
1308
- WHERE c.signature_hash = ?`).all(e);return new Set(s.map(n=>n.session_id))}var gb=/\b0x[0-9a-fA-F]+\b/g,fb=/\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,_b=/\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z?\b/g,hb=/:\d+:\d+/g,Eb=/\bline\s+\d+\b/gi,bb=/\bcolumn\s+\d+\b/gi,Sb=/\b(?:pid|PID|process(?:\s+id)?)\s*[:=]?\s*\d+\b/gi,yb=/\b(?:port|:)\s*[:=]?\s*\d{2,5}\b/gi,wb=/\b\d{4,}\b/g,Tb=/(['"`])[^'"`\n]{1,128}\1/g;function Rb(e){if(!e)return"";let t=String(e);return t=t.replace(gb,"<hex>"),t=t.replace(fb,"<uuid>"),t=t.replace(_b,"<ts>"),t=t.replace(hb,":<line>:<col>"),t=t.replace(Eb,"line <n>"),t=t.replace(bb,"column <n>"),t=t.replace(Sb,"pid <n>"),t=t.replace(yb,"port <n>"),t=t.replace(wb,"<num>"),t=t.replace(Tb,"<arg>"),t=t.replace(/\s+/g," ").trim(),t.toLowerCase()}function xb(e){let t=(e.error_type??"unknown").toLowerCase().trim(),s=Rb(e.snippet??e.message_hash??""),n=`${t}|${s}`;return mb("sha256").update(n).digest("hex").slice(0,16)}function kb(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,
1305
+ WHERE c.signature_hash = ?`).all(e);return new Set(s.map(n=>n.session_id))}var Rb=/\b0x[0-9a-fA-F]+\b/g,xb=/\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,kb=/\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z?\b/g,Cb=/:\d+:\d+/g,Lb=/\bline\s+\d+\b/gi,Nb=/\bcolumn\s+\d+\b/gi,Ab=/\b(?:pid|PID|process(?:\s+id)?)\s*[:=]?\s*\d+\b/gi,Ob=/\b(?:port|:)\s*[:=]?\s*\d{2,5}\b/gi,vb=/\b\d{4,}\b/g,Ib=/(['"`])[^'"`\n]{1,128}\1/g;function Mb(e){if(!e)return"";let t=String(e);return t=t.replace(Rb,"<hex>"),t=t.replace(xb,"<uuid>"),t=t.replace(kb,"<ts>"),t=t.replace(Cb,":<line>:<col>"),t=t.replace(Lb,"line <n>"),t=t.replace(Nb,"column <n>"),t=t.replace(Ab,"pid <n>"),t=t.replace(Ob,"port <n>"),t=t.replace(vb,"<num>"),t=t.replace(Ib,"<arg>"),t=t.replace(/\s+/g," ").trim(),t.toLowerCase()}function Db(e){let t=(e.error_type??"unknown").toLowerCase().trim(),s=Mb(e.snippet??e.message_hash??""),n=`${t}|${s}`;return Tb("sha256").update(n).digest("hex").slice(0,16)}function $b(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,
1309
1306
  p.name AS project,
1310
1307
  s.started_at AS started_at,
1311
1308
  oi.bug_signatures AS bug_signatures
1312
1309
  FROM session_output_index oi
1313
1310
  LEFT JOIN sessions s ON s.id = oi.session_id
1314
1311
  LEFT JOIN projects p ON p.id = s.project_id
1315
- ${r}`).all(...n),i=[];for(let a of o){if(!a.bug_signatures)continue;let d=[];try{let l=JSON.parse(a.bug_signatures);Array.isArray(l)&&(d=l)}catch{continue}for(let l of d){if(!l||typeof l!="object"||!(l.snippet??"").trim())continue;let p=xb(l);i.push({session_id:a.session_id,project:a.project,started_at:a.started_at,signature:l,fingerprint:p})}}return i}function Cb(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??"",g=p.started_at??"";return m&&g?m<g?-1:m>g?1:0:m?-1:g?1:0}),d=a.find(u=>u.started_at),l=[...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:d?.started_at??new Date().toISOString(),last_seen_at:l?.started_at??new Date().toISOString()})}return s}function Lb(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 Nb(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-Lb(s[u],s[m])<=n&&p.push(m)}i.push(p)}let a=new Array(o).fill(!1),d=new Array(o).fill(-1),l=[];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=l.length;l.push({members:[t[u]]}),d[u]=m;let g=[...p];for(;g.length>0;){let f=g.shift();if(!a[f]&&(a[f]=!0,i[f].length>=r))for(let h of i[f])(!a[h]||d[h]===-1)&&g.push(h);d[f]===-1&&(d[f]=m,l[m].members.push(t[f]))}}return l}async function Ab(e,t,s,n){if(e.length===0)return[];let r=e.map(d=>{let l=d.signature.snippet??d.signature.message_hash??"";return`${d.signature.error_type??""}: ${l}`.trim()}),o=await t(r);if(o.length!==e.length)throw new Error(`embedder returned ${o.length} vectors for ${e.length} inputs`);let i=Nb({records:e,vectors:o,epsilon:s,minPts:n}),a=[];for(let d of i){if(d.members.length===0)continue;let l=new Set,u=[];for(let E of d.members)l.has(E.session_id)||(l.add(E.session_id),u.push(E));if(u.length===0)continue;let m=`sem:${[...u.map(E=>E.fingerprint)].sort()[0]}`,g=[...u].sort((E,b)=>{let S=E.started_at??"",T=b.started_at??"";return S<T?-1:S>T?1:0}),f=g.find(E=>E.started_at),h=[...g].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:f?.started_at??new Date().toISOString(),last_seen_at:h?.started_at??new Date().toISOString()})}return a}function nl(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=tl(n.fingerprint),o=sl(n.fingerprint),i=n.members.map(l=>l.session_id).filter(l=>!o.has(l));if(r.length===0){let l=qc({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+=l.members.length,s.cluster_ids.push(l.cluster.id);continue}if(i.length===0){s.cluster_ids.push(r[0].id);continue}let a=r[0],d=Zc(a.id,i);d.added>0&&(s.clusters_merged+=1,s.members_added+=d.added),s.cluster_ids.push(a.id)}return s}async function rl(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=kb(e.project),i=new Set(o.map(S=>S.session_id)),a=Cb(o),d=[],l=!1;if(e.semantic){let S=e.embedder??null;if(!S)try{S=await Ib()}catch(T){let k=(T instanceof Error?T.message:String(T)).split(`
1316
- `)[0];console.warn(`[bug-pattern] --semantic requested but the embedder is unavailable: ${k}
1317
- Falling back to exact-match-only clustering. Run \`recall semantic install\` to enable the semantic pass.`),l=!0}if(S){let T=[];for(let R of a)R.members.length===1&&T.push(R.members[0]);T.length>=2&&(d=await Ab(T,S,n,r))}}let u=a.filter(S=>S.members.length>=t),p=d.filter(S=>S.members.length>=t),m=nl(u,t),g=nl(p,t),f=[...m.cluster_ids,...g.cluster_ids],h=Array.from(new Set(f)),E=[];if(h.length>0){let S=_(),T=h.map(()=>"?").join(","),R=S.prepare(`SELECT * FROM bug_pattern_clusters
1318
- WHERE id IN (${T})
1312
+ ${r}`).all(...n),i=[];for(let a of o){if(!a.bug_signatures)continue;let d=[];try{let l=JSON.parse(a.bug_signatures);Array.isArray(l)&&(d=l)}catch{continue}for(let l of d){if(!l||typeof l!="object"||!(l.snippet??"").trim())continue;let p=Db(l);i.push({session_id:a.session_id,project:a.project,started_at:a.started_at,signature:l,fingerprint:p})}}return i}function Pb(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??"",g=p.started_at??"";return m&&g?m<g?-1:m>g?1:0:m?-1:g?1:0}),d=a.find(u=>u.started_at),l=[...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:d?.started_at??new Date().toISOString(),last_seen_at:l?.started_at??new Date().toISOString()})}return s}function Fb(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 jb(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-Fb(s[u],s[m])<=n&&p.push(m)}i.push(p)}let a=new Array(o).fill(!1),d=new Array(o).fill(-1),l=[];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=l.length;l.push({members:[t[u]]}),d[u]=m;let g=[...p];for(;g.length>0;){let f=g.shift();if(!a[f]&&(a[f]=!0,i[f].length>=r))for(let h of i[f])(!a[h]||d[h]===-1)&&g.push(h);d[f]===-1&&(d[f]=m,l[m].members.push(t[f]))}}return l}async function Ub(e,t,s,n){if(e.length===0)return[];let r=e.map(d=>{let l=d.signature.snippet??d.signature.message_hash??"";return`${d.signature.error_type??""}: ${l}`.trim()}),o=await t(r);if(o.length!==e.length)throw new Error(`embedder returned ${o.length} vectors for ${e.length} inputs`);let i=jb({records:e,vectors:o,epsilon:s,minPts:n}),a=[];for(let d of i){if(d.members.length===0)continue;let l=new Set,u=[];for(let E of d.members)l.has(E.session_id)||(l.add(E.session_id),u.push(E));if(u.length===0)continue;let m=`sem:${[...u.map(E=>E.fingerprint)].sort()[0]}`,g=[...u].sort((E,b)=>{let S=E.started_at??"",R=b.started_at??"";return S<R?-1:S>R?1:0}),f=g.find(E=>E.started_at),h=[...g].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:f?.started_at??new Date().toISOString(),last_seen_at:h?.started_at??new Date().toISOString()})}return a}function il(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=rl(n.fingerprint),o=ol(n.fingerprint),i=n.members.map(l=>l.session_id).filter(l=>!o.has(l));if(r.length===0){let l=Qc({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+=l.members.length,s.cluster_ids.push(l.cluster.id);continue}if(i.length===0){s.cluster_ids.push(r[0].id);continue}let a=r[0],d=tl(a.id,i);d.added>0&&(s.clusters_merged+=1,s.members_added+=d.added),s.cluster_ids.push(a.id)}return s}async function al(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=$b(e.project),i=new Set(o.map(S=>S.session_id)),a=Pb(o),d=[],l=!1;if(e.semantic){let S=e.embedder??null;if(!S)try{S=await Wb()}catch(R){let L=(R instanceof Error?R.message:String(R)).split(`
1313
+ `)[0];console.warn(`[bug-pattern] --semantic requested but the embedder is unavailable: ${L}
1314
+ Falling back to exact-match-only clustering. Run \`recall semantic install\` to enable the semantic pass.`),l=!0}if(S){let R=[];for(let T of a)T.members.length===1&&R.push(T.members[0]);R.length>=2&&(d=await Ub(R,S,n,r))}}let u=a.filter(S=>S.members.length>=t),p=d.filter(S=>S.members.length>=t),m=il(u,t),g=il(p,t),f=[...m.cluster_ids,...g.cluster_ids],h=Array.from(new Set(f)),E=[];if(h.length>0){let S=_(),R=h.map(()=>"?").join(","),T=S.prepare(`SELECT * FROM bug_pattern_clusters
1315
+ WHERE id IN (${R})
1319
1316
  ORDER BY occurrence_count DESC, last_seen_at DESC
1320
- LIMIT ?`).all(...h,s);for(let k of R)E.push({id:k.id,signature_hash:k.signature_hash,example_message:k.example_message,occurrence_count:k.occurrence_count,first_seen_at:k.first_seen_at,last_seen_at:k.last_seen_at,resolved_in_session_id:k.resolved_in_session_id,fix_summary:k.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+g.clusters_created,clusters_merged:m.clusters_merged+g.clusters_merged,members_added:m.members_added+g.members_added,semantic_skipped:l},clusters:E}}var Ob=async()=>{let{embed:e,loadEmbedder:t,getEmbedderStatus:s}=await Promise.resolve().then(()=>(rt(),Ir));return s().loaded||await t(),e},vb=Ob;async function Ib(){return vb()}function Mb(e,t){let s=Qc(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 ol(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 l=Ee(e.project);if(!l){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}n=l.name}if(!e.json){let l=n?`project "${n}"`:"all projects",u=e.semantic?"exact + semantic":"exact";console.log(`Inferring bug patterns \u2014 ${l}, 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 rl(r)}catch(l){console.error(l instanceof Error?l.message:String(l)),process.exitCode=1;return}let a=Number(((Date.now()-o)/1e3).toFixed(1)),d=[];for(let l of i.clusters.slice(0,s)){let u=Mb(l.id,3);u&&d.push(u)}if(e.json){console.log(JSON.stringify({project:n??null,progress:i.progress,elapsed_seconds:a,clusters:d},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."),d.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(`
1317
+ LIMIT ?`).all(...h,s);for(let L of T)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+g.clusters_created,clusters_merged:m.clusters_merged+g.clusters_merged,members_added:m.members_added+g.members_added,semantic_skipped:l},clusters:E}}var Bb=async()=>{let{embed:e,loadEmbedder:t,getEmbedderStatus:s}=await Promise.resolve().then(()=>(yt(),Dr));return s().loaded||await t(),e},Hb=Bb;async function Wb(){return Hb()}function Xb(e,t){let s=sl(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 cl(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 l=Ee(e.project);if(!l){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}n=l.name}if(!e.json){let l=n?`project "${n}"`:"all projects",u=e.semantic?"exact + semantic":"exact";console.log(`Inferring bug patterns \u2014 ${l}, 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 al(r)}catch(l){console.error(l instanceof Error?l.message:String(l)),process.exitCode=1;return}let a=Number(((Date.now()-o)/1e3).toFixed(1)),d=[];for(let l of i.clusters.slice(0,s)){let u=Xb(l.id,3);u&&d.push(u)}if(e.json){console.log(JSON.stringify({project:n??null,progress:i.progress,elapsed_seconds:a,clusters:d},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."),d.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(`
1321
1318
  Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u2713 resolved":"open",p=l.example_message.slice(0,80);console.log(`
1322
1319
  [${u}] occurs=${l.occurrence_count} hash=${l.signature_hash.slice(0,8)}
1323
1320
  ${p}
1324
- first=${l.first_seen_at} last=${l.last_seen_at}`);for(let m of l.sample_members){let g=m.project?`[${m.project}] `:"";console.log(` \u2022 ${g}${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.")}w();import{z as TO}from"zod";w();function il(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}Zr();var fl=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),_l=new Set(["pagerank","embedding-rerank","hybrid"]);function Kb(e){if(!e)return;let t=e.split(",").map(s=>s.trim()).filter(Boolean);for(let s of t)if(!fl.has(s))throw new Error(`invalid --edge-types value: '${s}'. Valid: ${Array.from(fl).join(", ")}`);return t}function qb(e){if(!e)return"hybrid";if(!_l.has(e))throw new Error(`invalid --scoring value: '${e}'. Valid: ${Array.from(_l).join(", ")}`);return e}async function hl(e,t){let s=il(e);if(!s){console.error(`session not found or prefix ambiguous: ${e}`),process.exitCode=1;return}let n,r;try{n=qb(t.scoring),r=Kb(t.edgeTypes)}catch(d){console.error(d instanceof Error?d.message:String(d)),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=sn(s,{budget:o,maxDepth:i,scoring:n,edgeTypes:r,includeWikiLinks:t.wikiLinks!==!1,includeSuggestions:!!t.includeSuggestions})}catch(d){console.error(d instanceof Error?d.message:String(d)),process.exitCode=1;return}if(t.json){process.stdout.write(JSON.stringify(a,null,2)+`
1321
+ first=${l.first_seen_at} last=${l.last_seen_at}`);for(let m of l.sample_members){let g=m.project?`[${m.project}] `:"";console.log(` \u2022 ${g}${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.")}w();import{z as WO}from"zod";w();function ll(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}eo();var El=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),bl=new Set(["pagerank","embedding-rerank","hybrid"]);function oS(e){if(!e)return;let t=e.split(",").map(s=>s.trim()).filter(Boolean);for(let s of t)if(!El.has(s))throw new Error(`invalid --edge-types value: '${s}'. Valid: ${Array.from(El).join(", ")}`);return t}function iS(e){if(!e)return"hybrid";if(!bl.has(e))throw new Error(`invalid --scoring value: '${e}'. Valid: ${Array.from(bl).join(", ")}`);return e}async function Sl(e,t){let s=ll(e);if(!s){console.error(`session not found or prefix ambiguous: ${e}`),process.exitCode=1;return}let n,r;try{n=iS(t.scoring),r=oS(t.edgeTypes)}catch(d){console.error(d instanceof Error?d.message:String(d)),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=rn(s,{budget:o,maxDepth:i,scoring:n,edgeTypes:r,includeWikiLinks:t.wikiLinks!==!1,includeSuggestions:!!t.includeSuggestions})}catch(d){console.error(d instanceof Error?d.message:String(d)),process.exitCode=1;return}if(t.json){process.stdout.write(JSON.stringify(a,null,2)+`
1325
1322
  `);return}process.stdout.write(a.bundle),a.truncated.length>0&&console.error(`
1326
- [truncated ${a.truncated.length} refs to fit ${o}-token budget; ${a.budgetUsed} used / ${a.budgetRemaining} remaining]`)}w();v();var Vb=[[/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}]],El={label:"unknown",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30};function at(e){if(!e)return El;for(let[t,s]of Vb)if(t.test(e))return s;return El}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[l,u]of Object.entries(e.byModel)){let p=at(l);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 d=i.input+i.output+i.cacheCreate+i.cacheRead;return{cents:d,dollars:d/100,totalTokens:a,parts:i}}let s=at(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 ne(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 ue(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`}w();w();var Zb=500,nn=new Set;function bl(){return nn.size}function Qb(){return`
1323
+ [truncated ${a.truncated.length} refs to fit ${o}-token budget; ${a.budgetUsed} used / ${a.budgetRemaining} remaining]`)}w();v();var aS=[[/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}]],yl={label:"unknown",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30};function it(e){if(!e)return yl;for(let[t,s]of aS)if(t.test(e))return s;return yl}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[l,u]of Object.entries(e.byModel)){let p=it(l);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 d=i.input+i.output+i.cacheCreate+i.cacheRead;return{cents:d,dollars:d/100,totalTokens:a,parts:i}}let s=it(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 re(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 ue(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`}w();w();var cS=500,on=new Set;function wl(){return on.size}function lS(){return`
1327
1324
  SELECT m.uuid, m.session_id, m.timestamp, m.raw_json
1328
1325
  FROM messages m
1329
1326
  LEFT JOIN message_usage mu ON mu.message_uuid = m.uuid
1330
1327
  WHERE m.role = 'assistant' AND mu.message_uuid IS NULL
1331
1328
  AND m.uuid NOT IN (SELECT value FROM json_each(?))
1332
1329
  LIMIT ?
1333
- `}function eS(e,t){let s=t.limit??Number.MAX_SAFE_INTEGER,n=Math.max(1,t.chunkSize??Zb),r=e.prepare(Qb()),o=e.prepare(`
1330
+ `}function dS(e,t){let s=t.limit??Number.MAX_SAFE_INTEGER,n=Math.max(1,t.chunkSize??cS),r=e.prepare(lS()),o=e.prepare(`
1334
1331
  INSERT INTO message_usage (
1335
1332
  message_uuid, session_id, model,
1336
1333
  input_tokens, output_tokens, cache_create_tokens, cache_read_tokens,
@@ -1340,7 +1337,7 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1340
1337
  @input, @output, @cc, @cr, @ts
1341
1338
  )
1342
1339
  ON CONFLICT(message_uuid) DO NOTHING
1343
- `),i=0,a=0,d=new Set;for(;i<s;){let l=Math.min(n,s-i),u=JSON.stringify([...nn]),p=r.all(u,l);if(p.length===0)break;let m=new Set;if(e.transaction(()=>{for(let f of p){let h;try{h=JSON.parse(f.raw_json)}catch{nn.add(f.uuid);continue}let E=Wn(h.message);if(!E){nn.add(f.uuid);continue}o.run({uuid:f.uuid,session_id:f.session_id,model:h.message?.model??null,input:E.inputTokens,output:E.outputTokens,cc:E.cacheCreateTokens,cr:E.cacheReadTokens,ts:f.timestamp}),a+=1,m.add(f.session_id)}for(let f of m)Gt(e,f),d.add(f)})(),i+=p.length,t.onProgress?.({scanned:i,inserted:a,sessionsTouched:d.size,done:p.length<l}),p.length<l)break}return{scanned:i,inserted:a,sessionsTouched:d.size,done:!0}}function Sl(e={}){return eS(_(),e)}function Qr(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:at(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 eo(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 yl(e){let t=_(),s=t.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
1340
+ `),i=0,a=0,d=new Set;for(;i<s;){let l=Math.min(n,s-i),u=JSON.stringify([...on]),p=r.all(u,l);if(p.length===0)break;let m=new Set;if(e.transaction(()=>{for(let f of p){let h;try{h=JSON.parse(f.raw_json)}catch{on.add(f.uuid);continue}let E=Jn(h.message);if(!E){on.add(f.uuid);continue}o.run({uuid:f.uuid,session_id:f.session_id,model:h.message?.model??null,input:E.inputTokens,output:E.outputTokens,cc:E.cacheCreateTokens,cr:E.cacheReadTokens,ts:f.timestamp}),a+=1,m.add(f.session_id)}for(let f of m)zt(e,f),d.add(f)})(),i+=p.length,t.onProgress?.({scanned:i,inserted:a,sessionsTouched:d.size,done:p.length<l}),p.length<l)break}return{scanned:i,inserted:a,sessionsTouched:d.size,done:!0}}function Tl(e={}){return dS(_(),e)}function to(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:it(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 so(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 Rl(e){let t=_(),s=t.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
1344
1341
  s.message_count,
1345
1342
  s.total_input_tokens, s.total_output_tokens,
1346
1343
  s.total_cache_create_tokens, s.total_cache_read_tokens,
@@ -1355,7 +1352,7 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1355
1352
  COUNT(*) AS n
1356
1353
  FROM message_usage
1357
1354
  WHERE session_id = ?
1358
- GROUP BY model`).all(e),r=Qr(n),o=s.total_input_tokens??0,i=s.total_output_tokens??0,a=s.total_cache_create_tokens??0,d=s.total_cache_read_tokens??0,l=Ie({inputTokens:o,outputTokens:i,cacheCreateTokens:a,cacheReadTokens:d,...eo(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:at(s.primary_model).label,inputTokens:o,outputTokens:i,cacheCreateTokens:a,cacheReadTokens:d,totalTokens:l.totalTokens,cost:l,byModel:r,display:{dollars:ne(l.cents),tokens:ue(l.totalTokens),model:at(s.primary_model).label}}}function wl(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,
1355
+ GROUP BY model`).all(e),r=to(n),o=s.total_input_tokens??0,i=s.total_output_tokens??0,a=s.total_cache_create_tokens??0,d=s.total_cache_read_tokens??0,l=Ie({inputTokens:o,outputTokens:i,cacheCreateTokens:a,cacheReadTokens:d,...so(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:it(s.primary_model).label,inputTokens:o,outputTokens:i,cacheCreateTokens:a,cacheReadTokens:d,totalTokens:l.totalTokens,cost:l,byModel:r,display:{dollars:re(l.cents),tokens:ue(l.totalTokens),model:it(s.primary_model).label}}}function xl(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,
1359
1356
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
1360
1357
  COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
1361
1358
  COALESCE(SUM(mu.cache_create_tokens), 0) AS cache_create_tokens,
@@ -1364,12 +1361,12 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1364
1361
  FROM message_usage mu
1365
1362
  JOIN sessions s ON s.id = mu.session_id
1366
1363
  WHERE s.project_id = ?
1367
- GROUP BY mu.model`).all(s.id),r=Qr(n),o=t.prepare(`SELECT COALESCE(SUM(total_input_tokens), 0) AS input_tokens,
1364
+ GROUP BY mu.model`).all(s.id),r=to(n),o=t.prepare(`SELECT COALESCE(SUM(total_input_tokens), 0) AS input_tokens,
1368
1365
  COALESCE(SUM(total_output_tokens), 0) AS output_tokens,
1369
1366
  COALESCE(SUM(total_cache_create_tokens), 0) AS cache_create_tokens,
1370
1367
  COALESCE(SUM(total_cache_read_tokens), 0) AS cache_read_tokens,
1371
1368
  COUNT(*) AS session_count
1372
- 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,...eo(r)},null),d=t.prepare(`SELECT s.id, sa.alias, s.started_at,
1369
+ 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,...so(r)},null),d=t.prepare(`SELECT s.id, sa.alias, s.started_at,
1373
1370
  s.total_input_tokens, s.total_output_tokens,
1374
1371
  s.total_cache_create_tokens, s.total_cache_read_tokens,
1375
1372
  s.primary_model
@@ -1380,7 +1377,7 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1380
1377
  + COALESCE(s.total_output_tokens,0)
1381
1378
  + COALESCE(s.total_cache_create_tokens,0)
1382
1379
  + COALESCE(s.total_cache_read_tokens,0)) DESC
1383
- LIMIT 10`).all(s.id).map(l=>{let u=Ie({inputTokens:l.total_input_tokens??0,outputTokens:l.total_output_tokens??0,cacheCreateTokens:l.total_cache_create_tokens??0,cacheReadTokens:l.total_cache_read_tokens??0},l.primary_model);return{sessionId:l.id,alias:l.alias,startedAt:l.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:d,display:{dollars:ne(i.cents),tokens:ue(i.totalTokens)}}}function Tl(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(),d=a(`SELECT mu.model,
1380
+ LIMIT 10`).all(s.id).map(l=>{let u=Ie({inputTokens:l.total_input_tokens??0,outputTokens:l.total_output_tokens??0,cacheCreateTokens:l.total_cache_create_tokens??0,cacheReadTokens:l.total_cache_read_tokens??0},l.primary_model);return{sessionId:l.id,alias:l.alias,startedAt:l.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:d,display:{dollars:re(i.cents),tokens:ue(i.totalTokens)}}}function kl(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(),d=a(`SELECT mu.model,
1384
1381
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
1385
1382
  COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
1386
1383
  COALESCE(SUM(mu.cache_create_tokens), 0) AS cache_create_tokens,
@@ -1389,7 +1386,7 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1389
1386
  FROM message_usage mu
1390
1387
  JOIN sessions s ON s.id = mu.session_id
1391
1388
  ${n}
1392
- GROUP BY mu.model`),l=Qr(d),u=0,p=0,m=0,g=0;for(let y of l)u+=y.inputTokens,p+=y.outputTokens,m+=y.cacheCreateTokens,g+=y.cacheReadTokens;let f=Ie({inputTokens:u,outputTokens:p,cacheCreateTokens:m,cacheReadTokens:g,...eo(l)},null),h=s?i(`SELECT
1389
+ GROUP BY mu.model`),l=to(d),u=0,p=0,m=0,g=0;for(let y of l)u+=y.inputTokens,p+=y.outputTokens,m+=y.cacheCreateTokens,g+=y.cacheReadTokens;let f=Ie({inputTokens:u,outputTokens:p,cacheCreateTokens:m,cacheReadTokens:g,...so(l)},null),h=s?i(`SELECT
1393
1390
  (SELECT COUNT(DISTINCT m.session_id)
1394
1391
  FROM messages m
1395
1392
  JOIN sessions s2 ON s2.id = m.session_id
@@ -1413,7 +1410,7 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1413
1410
  JOIN sessions s ON s.id = mu.session_id
1414
1411
  ${n}
1415
1412
  GROUP BY day, mu.model
1416
- 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)),R=a(`SELECT s.id, p.name AS project, sa.alias, s.started_at,
1413
+ ORDER BY day ASC`),b=new Map;for(let y of E){if(!y.day)continue;let B=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+=B.totalTokens,M.cents+=B.cents,b.set(y.day,M)}let S=[...b.entries()].map(([y,B])=>({day:y,tokens:B.tokens,cents:B.cents})).sort((y,B)=>y.day.localeCompare(B.day)),T=a(`SELECT s.id, p.name AS project, sa.alias, s.started_at,
1417
1414
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
1418
1415
  COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
1419
1416
  COALESCE(SUM(mu.cache_create_tokens), 0) AS cache_create_tokens,
@@ -1429,7 +1426,7 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1429
1426
  + COALESCE(SUM(mu.output_tokens),0)
1430
1427
  + COALESCE(SUM(mu.cache_create_tokens),0)
1431
1428
  + COALESCE(SUM(mu.cache_read_tokens),0)) DESC
1432
- 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}}),k=a(`SELECT p.id AS project_id,
1429
+ LIMIT 10`).map(y=>{let B=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:B.totalTokens,cost:B}}),L=a(`SELECT p.id AS project_id,
1433
1430
  p.name AS project,
1434
1431
  mu.model,
1435
1432
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
@@ -1441,16 +1438,16 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1441
1438
  JOIN sessions s ON s.id = mu.session_id
1442
1439
  LEFT JOIN projects p ON p.id = s.project_id
1443
1440
  ${n}
1444
- GROUP BY p.id, mu.model`),J=new Map;for(let y of k){let U=y.project_id??"__none__",M=J.get(U);M||(M={project:y.project??"(no project)",sessionIds:new Set,sessionsApprox:0,byModel:{}},J.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 A=[...J.values()].map(y=>{let U=0,M=0,V=0,Ye=0;for(let ht of Object.values(y.byModel))U+=ht.inputTokens,M+=ht.outputTokens,V+=ht.cacheCreateTokens,Ye+=ht.cacheReadTokens;let Fe=Ie({inputTokens:U,outputTokens:M,cacheCreateTokens:V,cacheReadTokens:Ye,byModel:y.byModel},null);return{project:y.project,sessions:y.sessionsApprox,totalTokens:Fe.totalTokens,cost:Fe}});A.sort((y,U)=>U.totalTokens-y.totalTokens);let $=A.slice(0,20),j=t.prepare(`SELECT
1441
+ GROUP BY p.id, mu.model`),D=new Map;for(let y of L){let B=y.project_id??"__none__",M=D.get(B);M||(M={project:y.project??"(no project)",sessionIds:new Set,sessionsApprox:0,byModel:{}},D.set(B,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 A=[...D.values()].map(y=>{let B=0,M=0,V=0,Ge=0;for(let _t of Object.values(y.byModel))B+=_t.inputTokens,M+=_t.outputTokens,V+=_t.cacheCreateTokens,Ge+=_t.cacheReadTokens;let Fe=Ie({inputTokens:B,outputTokens:M,cacheCreateTokens:V,cacheReadTokens:Ge,byModel:y.byModel},null);return{project:y.project,sessions:y.sessionsApprox,totalTokens:Fe.totalTokens,cost:Fe}});A.sort((y,B)=>B.totalTokens-y.totalTokens);let $=A.slice(0,20),U=t.prepare(`SELECT
1445
1442
  (SELECT COUNT(*) FROM messages WHERE role='assistant') AS assistant_messages,
1446
- (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:g,totalTokens:f.totalTokens,cost:f,daily:S,byModel:l,topSessions:R,topRepos:$,backfill:{assistantMessages:j.assistant_messages,messagesWithUsage:j.messages_with_usage,pending:Math.max(0,j.assistant_messages-j.messages_with_usage),unrecoverable:Math.min(bl(),Math.max(0,j.assistant_messages-j.messages_with_usage))},display:{dollars:ne(f.cents),tokens:ue(f.totalTokens)}}}var Ze=e=>e.toLocaleString();function tS(e){return _().prepare("SELECT id FROM sessions WHERE id = ? OR id LIKE ? LIMIT 1").get(e,`${e}%`)?.id??null}async function Rl(e,t){if(t.backfill){let r=t.limit?Math.max(1,Number(t.limit)):void 0;console.log(c.dim("backfilling per-message usage from raw_json\u2026"));let o=Sl({limit:r});if(console.log(`${c.ok("backfill done")}: scanned ${c.bold(String(o.scanned))}, inserted ${c.bold(String(o.inserted))}, rolled-up ${c.bold(String(o.sessionsTouched))} sessions`),!e&&!t.project)return}if(e){let r=tS(e);if(!r){console.error(c.err(`no session matches '${e}'`)),process.exit(1);return}let o=yl(r);if(!o){console.error(c.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(c.bold("session cost")),console.log(c.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` id ${c.dim(o.sessionId)}`),console.log(` project ${c.accent(o.project??"\u2014")}`),console.log(` started ${c.dim(o.startedAt??"n/a")}`),console.log(` messages ${c.accent(Ze(o.messageCount))}`),console.log(` model ${c.accent(o.primaryModelLabel)} ${c.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 ${c.bold(Ze(o.totalTokens).padStart(12))}`),console.log(` estimated cost ${c.accent(ne(o.cost.cents).padStart(12))}`),o.byModel.length>1){console.log(""),console.log(c.dim(" by model:"));for(let i of o.byModel)console.log(` ${i.modelLabel.padEnd(14)} ${ue(i.inputTokens+i.outputTokens+i.cacheCreateTokens+i.cacheReadTokens).padStart(10)} ${c.accent(ne(i.cost.cents).padStart(10))}`)}console.log("");return}if(t.project){let r=wl(t.project);if(!r){console.error(c.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(c.bold(`project \xB7 ${r.project}`)),console.log(c.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 ${c.accent(Ze(r.sessionCount))}`),console.log(` total tokens ${c.accent(ue(r.totalTokens).padStart(12))}`),console.log(` estimated cost ${c.accent(ne(r.cost.cents).padStart(12))}`),r.byModel.length>0){console.log(""),console.log(c.dim(" by model:"));for(let o of r.byModel)console.log(` ${o.modelLabel.padEnd(14)} ${ue(o.inputTokens+o.outputTokens+o.cacheCreateTokens+o.cacheReadTokens).padStart(10)} ${c.accent(ne(o.cost.cents).padStart(10))}`)}if(r.topSessions.length>0){console.log(""),console.log(c.dim(" top sessions:"));for(let o of r.topSessions){let i=o.alias??o.sessionId.slice(0,8);console.log(` ${i.padEnd(22)} ${ue(o.totalTokens).padStart(10)} ${c.accent(ne(o.cost.cents).padStart(10))}`)}}console.log("");return}let s=t.days==="7"?"7d":t.days==="30"?"30d":"all",n=Tl(s);if(t.json){console.log(JSON.stringify(n,null,2));return}if(console.log(""),console.log(c.bold(`overview \xB7 ${s}`)),console.log(c.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 ${c.accent(Ze(n.totalSessions))} ${c.dim(`(${n.sessionsWithUsage} w/ usage)`)}`),console.log(` total tokens ${c.accent(ue(n.totalTokens).padStart(12))}`),console.log(` estimated cost ${c.accent(ne(n.cost.cents).padStart(12))}`),n.backfill.pending>0&&console.log(c.dim(` (${Ze(n.backfill.pending)} assistant messages pending \u2014 run \`recall stats --backfill\`)`)),n.byModel.length>0){console.log(""),console.log(c.dim(" by model:"));for(let r of n.byModel)console.log(` ${r.modelLabel.padEnd(14)} ${ue(r.inputTokens+r.outputTokens+r.cacheCreateTokens+r.cacheReadTokens).padStart(10)} ${c.accent(ne(r.cost.cents).padStart(10))}`)}if(n.topSessions.length>0){console.log(""),console.log(c.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)} ${ue(r.totalTokens).padStart(10)} ${c.accent(ne(r.cost.cents).padStart(10))}`)}}console.log("")}v();w();w();import{execFile as sS}from"node:child_process";import{promisify as nS}from"node:util";import{stat as rS}from"node:fs/promises";var xl=nS(sS),kl=1e4,oS="%H%x09%aI%x09%s";async function iS(e){try{let{stdout:t}=await xl("git",["rev-parse","--is-inside-work-tree"],{cwd:e,timeout:kl});return t.trim()==="true"}catch{return!1}}async function aS(e,t,s){let n=["--no-pager","log","--all","--no-color","--since",t,"--until",s,`--pretty=format:${oS}`],{stdout:r}=await xl("git",n,{cwd:e,timeout:kl,maxBuffer:8*1024*1024}),o=[],i=new Set;for(let a of r.split(`
1447
- `)){if(!a)continue;let[d,l,...u]=a.split(" ");!d||i.has(d)||(i.add(d),o.push({commit_sha:d,committed_at:l??null,subject:u.join(" ")||null}))}return o}function cS(e){return _().prepare(`SELECT id, cwd, started_at, ended_at
1448
- FROM sessions WHERE id = ?`).get(e)??null}function lS(e,t,s){if(s.length===0)return 0;let n=_(),r=new Date().toISOString(),o=n.prepare(`INSERT OR IGNORE INTO session_commits
1443
+ (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:g,totalTokens:f.totalTokens,cost:f,daily:S,byModel:l,topSessions:T,topRepos:$,backfill:{assistantMessages:U.assistant_messages,messagesWithUsage:U.messages_with_usage,pending:Math.max(0,U.assistant_messages-U.messages_with_usage),unrecoverable:Math.min(wl(),Math.max(0,U.assistant_messages-U.messages_with_usage))},display:{dollars:re(f.cents),tokens:ue(f.totalTokens)}}}var Qe=e=>e.toLocaleString();function uS(e){return _().prepare("SELECT id FROM sessions WHERE id = ? OR id LIKE ? LIMIT 1").get(e,`${e}%`)?.id??null}async function Cl(e,t){if(t.backfill){let r=t.limit?Math.max(1,Number(t.limit)):void 0;console.log(c.dim("backfilling per-message usage from raw_json\u2026"));let o=Tl({limit:r});if(console.log(`${c.ok("backfill done")}: scanned ${c.bold(String(o.scanned))}, inserted ${c.bold(String(o.inserted))}, rolled-up ${c.bold(String(o.sessionsTouched))} sessions`),!e&&!t.project)return}if(e){let r=uS(e);if(!r){console.error(c.err(`no session matches '${e}'`)),process.exit(1);return}let o=Rl(r);if(!o){console.error(c.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(c.bold("session cost")),console.log(c.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` id ${c.dim(o.sessionId)}`),console.log(` project ${c.accent(o.project??"\u2014")}`),console.log(` started ${c.dim(o.startedAt??"n/a")}`),console.log(` messages ${c.accent(Qe(o.messageCount))}`),console.log(` model ${c.accent(o.primaryModelLabel)} ${c.dim(o.primaryModel??"")}`),console.log(""),console.log(` input ${Qe(o.inputTokens).padStart(12)}`),console.log(` output ${Qe(o.outputTokens).padStart(12)}`),console.log(` cache write ${Qe(o.cacheCreateTokens).padStart(12)}`),console.log(` cache read ${Qe(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 ${c.bold(Qe(o.totalTokens).padStart(12))}`),console.log(` estimated cost ${c.accent(re(o.cost.cents).padStart(12))}`),o.byModel.length>1){console.log(""),console.log(c.dim(" by model:"));for(let i of o.byModel)console.log(` ${i.modelLabel.padEnd(14)} ${ue(i.inputTokens+i.outputTokens+i.cacheCreateTokens+i.cacheReadTokens).padStart(10)} ${c.accent(re(i.cost.cents).padStart(10))}`)}console.log("");return}if(t.project){let r=xl(t.project);if(!r){console.error(c.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(c.bold(`project \xB7 ${r.project}`)),console.log(c.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 ${c.accent(Qe(r.sessionCount))}`),console.log(` total tokens ${c.accent(ue(r.totalTokens).padStart(12))}`),console.log(` estimated cost ${c.accent(re(r.cost.cents).padStart(12))}`),r.byModel.length>0){console.log(""),console.log(c.dim(" by model:"));for(let o of r.byModel)console.log(` ${o.modelLabel.padEnd(14)} ${ue(o.inputTokens+o.outputTokens+o.cacheCreateTokens+o.cacheReadTokens).padStart(10)} ${c.accent(re(o.cost.cents).padStart(10))}`)}if(r.topSessions.length>0){console.log(""),console.log(c.dim(" top sessions:"));for(let o of r.topSessions){let i=o.alias??o.sessionId.slice(0,8);console.log(` ${i.padEnd(22)} ${ue(o.totalTokens).padStart(10)} ${c.accent(re(o.cost.cents).padStart(10))}`)}}console.log("");return}let s=t.days==="7"?"7d":t.days==="30"?"30d":"all",n=kl(s);if(t.json){console.log(JSON.stringify(n,null,2));return}if(console.log(""),console.log(c.bold(`overview \xB7 ${s}`)),console.log(c.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 ${c.accent(Qe(n.totalSessions))} ${c.dim(`(${n.sessionsWithUsage} w/ usage)`)}`),console.log(` total tokens ${c.accent(ue(n.totalTokens).padStart(12))}`),console.log(` estimated cost ${c.accent(re(n.cost.cents).padStart(12))}`),n.backfill.pending>0&&console.log(c.dim(` (${Qe(n.backfill.pending)} assistant messages pending \u2014 run \`recall stats --backfill\`)`)),n.byModel.length>0){console.log(""),console.log(c.dim(" by model:"));for(let r of n.byModel)console.log(` ${r.modelLabel.padEnd(14)} ${ue(r.inputTokens+r.outputTokens+r.cacheCreateTokens+r.cacheReadTokens).padStart(10)} ${c.accent(re(r.cost.cents).padStart(10))}`)}if(n.topSessions.length>0){console.log(""),console.log(c.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)} ${ue(r.totalTokens).padStart(10)} ${c.accent(re(r.cost.cents).padStart(10))}`)}}console.log("")}v();w();w();import{execFile as pS}from"node:child_process";import{promisify as mS}from"node:util";import{stat as gS}from"node:fs/promises";var Ll=mS(pS),Nl=1e4,fS="%H%x09%aI%x09%s";async function _S(e){try{let{stdout:t}=await Ll("git",["rev-parse","--is-inside-work-tree"],{cwd:e,timeout:Nl});return t.trim()==="true"}catch{return!1}}async function hS(e,t,s){let n=["--no-pager","log","--all","--no-color","--since",t,"--until",s,`--pretty=format:${fS}`],{stdout:r}=await Ll("git",n,{cwd:e,timeout:Nl,maxBuffer:8*1024*1024}),o=[],i=new Set;for(let a of r.split(`
1444
+ `)){if(!a)continue;let[d,l,...u]=a.split(" ");!d||i.has(d)||(i.add(d),o.push({commit_sha:d,committed_at:l??null,subject:u.join(" ")||null}))}return o}function ES(e){return _().prepare(`SELECT id, cwd, started_at, ended_at
1445
+ FROM sessions WHERE id = ?`).get(e)??null}function bS(e,t,s){if(s.length===0)return 0;let n=_(),r=new Date().toISOString(),o=n.prepare(`INSERT OR IGNORE INTO session_commits
1449
1446
  (session_id, commit_sha, committed_at, subject, cwd_snapshot, correlated_at)
1450
- VALUES (?, ?, ?, ?, ?, ?)`),i=0;return n.transaction(d=>{for(let l of d)o.run(e,l.commit_sha,l.committed_at,l.subject,t,r).changes>0&&(i+=1)})(s),i}async function to(e){let t=cS(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 rS(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 iS(t.cwd))return{sessionId:e,status:"not-a-repo",commitsFound:0,commitsInserted:0};try{let o=await aS(t.cwd,s,n),i=lS(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 Cl(e={}){let t=_(),s=Math.max(1,Math.min(1e5,e.limit??1e4)),n=t.prepare(`SELECT id FROM sessions
1447
+ VALUES (?, ?, ?, ?, ?, ?)`),i=0;return n.transaction(d=>{for(let l of d)o.run(e,l.commit_sha,l.committed_at,l.subject,t,r).changes>0&&(i+=1)})(s),i}async function no(e){let t=ES(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 gS(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 _S(t.cwd))return{sessionId:e,status:"not-a-repo",commitsFound:0,commitsInserted:0};try{let o=await hS(t.cwd,s,n),i=bS(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 Al(e={}){let t=_(),s=Math.max(1,Math.min(1e5,e.limit??1e4)),n=t.prepare(`SELECT id FROM sessions
1451
1448
  WHERE cwd IS NOT NULL AND started_at IS NOT NULL AND ended_at IS NOT NULL
1452
1449
  ORDER BY COALESCE(ended_at, started_at) DESC
1453
- 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 to(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 rn(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,
1450
+ 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 no(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 an(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,
1454
1451
  NULLIF(sa.alias, '') AS alias,
1455
1452
  p.name AS project,
1456
1453
  s.started_at AS startedAt,
@@ -1464,33 +1461,33 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1464
1461
  LEFT JOIN session_aliases sa ON sa.session_id = sc.session_id
1465
1462
  WHERE lower(sc.commit_sha) = lower(?)
1466
1463
  OR lower(sc.commit_sha) LIKE ?
1467
- ORDER BY COALESCE(sc.committed_at, s.started_at, '') DESC`).all(s,n)}function dS(e){return _().prepare("SELECT id FROM sessions WHERE id = ? OR id LIKE ? LIMIT 1").get(e,`${e}%`)?.id??null}function uS(e){let t=e.sessionId.slice(0,8);switch(e.status){case"ok":console.log(`${c.ok("\u2713")} ${c.dim(t)} ${c.bold(String(e.commitsFound))} commits (${e.commitsInserted} new)`);break;case"no-cwd":console.log(`${c.dim("\xB7")} ${c.dim(t)} no cwd recorded \u2014 skipped`);break;case"not-a-repo":console.log(`${c.dim("\xB7")} ${c.dim(t)} cwd is not a git worktree \u2014 skipped`);break;case"cwd-missing":console.log(`${c.dim("\xB7")} ${c.dim(t)} cwd no longer exists on disk \u2014 skipped`);break;case"no-window":console.log(`${c.dim("\xB7")} ${c.dim(t)} session has no time window yet \u2014 skipped`);break;case"error":console.log(`${c.err("\u2717")} ${c.dim(t)} ${e.error??"unknown error"}`);break}}async function Ll(e,t){if(e){let r=dS(e);if(!r){console.error(c.err(`no session matches '${e}'`)),process.exit(1);return}let o=await to(r);if(t.json){console.log(JSON.stringify(o,null,2));return}uS(o);return}let s=t.limit?Math.max(1,Number(t.limit)):void 0;console.log(c.dim(`correlating sessions to git commits (limit ${s??"default"})\u2026`));let n=await Cl({limit:s,onProgress:(r,o)=>{(r%25===0||r===o)&&process.stderr.write(`\r${c.dim(` ${r}/${o}`)}`)}});if(process.stderr.write(`
1468
- `),t.json){console.log(JSON.stringify(n,null,2));return}console.log(""),console.log(`${c.ok("correlated")}: ${c.bold(String(n.ok))} sessions \xB7 ${c.bold(String(n.commitsInserted))} new commits`),console.log(c.dim(` skipped ${n.skipped} (no cwd / non-repo / cwd missing), errors ${n.errors}`)),console.log("")}v();w();bt();import{existsSync as ao,readFileSync as co}from"node:fs";D();import{existsSync as pS,readFileSync as mS,writeFileSync as gS}from"node:fs";import{join as fS}from"node:path";import{z as pe}from"zod";var so=fS(x,"terminals.json"),Nl=1440*60*1e3,_S=3e4,hS=6e4,ES=pe.object({shell_pid:pe.number(),tab_name:pe.string(),cwd:pe.string().nullable().optional(),opened_at:pe.string(),last_seen_at:pe.string()}),bS=pe.object({schema:pe.string().optional(),saved_at:pe.string().optional(),terminals:pe.array(ES).max(500).default([]),sessions_by_pid:pe.record(pe.string(),pe.array(pe.string()).max(50)).optional().default({})}),Al=/^[⠀-⣿✳\s]+/,Ol=/^\d+(\.\d+){1,3}$/;function ro(e){let t=e.trim();return!!(!t||Al.test(t)||Ol.test(t))}function vl(e){let t=e.trim();if(!t||Ol.test(t))return null;let s=t.replace(Al,"").trim();return s.length>0?s:null}function no(e,t){if(!ro(e))return e;let s=vl(e);return s||(t&&!ro(t)?t:e)}function SS(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 oo=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,!!pS(so)))try{let t=mS(so,"utf8"),s=JSON.parse(t),n=bS.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 d=new Set;for(let l of i)l.length>0&&d.add(l);d.size>0&&this.sessionsByPid.set(a,d)}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)]))};gS(so,JSON.stringify(t,null,2))}catch{}}upsert(t){this.ensureLoaded();let s=new Date().toISOString(),n=this.entries.get(t.shell_pid),r=no(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=no(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>hS?(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=no(o.tab_name,i?.tab_name),d=i?.opened_at??o.opened_at;this.entries.set(o.shell_pid,{...o,tab_name:a,opened_at:d,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=SS({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()-_S;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()-Nl;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()-Nl;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 d=this.entries.get(i);if(d){let l=Date.parse(d.last_seen_at);if(Number.isFinite(l)&&l>=n)continue}o+=a.size,this.sessionsByPid.delete(i),d&&(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}}},io=new oo;D();function wS(){let e=`${x}/daemon.port`;if(!ao(e))return null;try{let t=co(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function TS(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 RS(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
1464
+ ORDER BY COALESCE(sc.committed_at, s.started_at, '') DESC`).all(s,n)}function SS(e){return _().prepare("SELECT id FROM sessions WHERE id = ? OR id LIKE ? LIMIT 1").get(e,`${e}%`)?.id??null}function yS(e){let t=e.sessionId.slice(0,8);switch(e.status){case"ok":console.log(`${c.ok("\u2713")} ${c.dim(t)} ${c.bold(String(e.commitsFound))} commits (${e.commitsInserted} new)`);break;case"no-cwd":console.log(`${c.dim("\xB7")} ${c.dim(t)} no cwd recorded \u2014 skipped`);break;case"not-a-repo":console.log(`${c.dim("\xB7")} ${c.dim(t)} cwd is not a git worktree \u2014 skipped`);break;case"cwd-missing":console.log(`${c.dim("\xB7")} ${c.dim(t)} cwd no longer exists on disk \u2014 skipped`);break;case"no-window":console.log(`${c.dim("\xB7")} ${c.dim(t)} session has no time window yet \u2014 skipped`);break;case"error":console.log(`${c.err("\u2717")} ${c.dim(t)} ${e.error??"unknown error"}`);break}}async function Ol(e,t){if(e){let r=SS(e);if(!r){console.error(c.err(`no session matches '${e}'`)),process.exit(1);return}let o=await no(r);if(t.json){console.log(JSON.stringify(o,null,2));return}yS(o);return}let s=t.limit?Math.max(1,Number(t.limit)):void 0;console.log(c.dim(`correlating sessions to git commits (limit ${s??"default"})\u2026`));let n=await Al({limit:s,onProgress:(r,o)=>{(r%25===0||r===o)&&process.stderr.write(`\r${c.dim(` ${r}/${o}`)}`)}});if(process.stderr.write(`
1465
+ `),t.json){console.log(JSON.stringify(n,null,2));return}console.log(""),console.log(`${c.ok("correlated")}: ${c.bold(String(n.ok))} sessions \xB7 ${c.bold(String(n.commitsInserted))} new commits`),console.log(c.dim(` skipped ${n.skipped} (no cwd / non-repo / cwd missing), errors ${n.errors}`)),console.log("")}v();w();Et();import{existsSync as lo,readFileSync as uo}from"node:fs";P();import{existsSync as wS,readFileSync as TS,writeFileSync as RS}from"node:fs";import{join as xS}from"node:path";import{z as pe}from"zod";var ro=xS(x,"terminals.json"),vl=1440*60*1e3,kS=3e4,CS=6e4,LS=pe.object({shell_pid:pe.number(),tab_name:pe.string(),cwd:pe.string().nullable().optional(),opened_at:pe.string(),last_seen_at:pe.string()}),NS=pe.object({schema:pe.string().optional(),saved_at:pe.string().optional(),terminals:pe.array(LS).max(500).default([]),sessions_by_pid:pe.record(pe.string(),pe.array(pe.string()).max(50)).optional().default({})}),Il=/^[⠀-⣿✳\s]+/,Ml=/^\d+(\.\d+){1,3}$/;function io(e){let t=e.trim();return!!(!t||Il.test(t)||Ml.test(t))}function Dl(e){let t=e.trim();if(!t||Ml.test(t))return null;let s=t.replace(Il,"").trim();return s.length>0?s:null}function oo(e,t){if(!io(e))return e;let s=Dl(e);return s||(t&&!io(t)?t:e)}function AS(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 ao=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,!!wS(ro)))try{let t=TS(ro,"utf8"),s=JSON.parse(t),n=NS.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 d=new Set;for(let l of i)l.length>0&&d.add(l);d.size>0&&this.sessionsByPid.set(a,d)}this.gc()}catch{}}save(){try{F();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)]))};RS(ro,JSON.stringify(t,null,2))}catch{}}upsert(t){this.ensureLoaded();let s=new Date().toISOString(),n=this.entries.get(t.shell_pid),r=oo(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=oo(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>CS?(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=oo(o.tab_name,i?.tab_name),d=i?.opened_at??o.opened_at;this.entries.set(o.shell_pid,{...o,tab_name:a,opened_at:d,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=AS({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()-kS;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()-vl;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()-vl;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 d=this.entries.get(i);if(d){let l=Date.parse(d.last_seen_at);if(Number.isFinite(l)&&l>=n)continue}o+=a.size,this.sessionsByPid.delete(i),d&&(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}}},co=new ao;P();function vS(){let e=`${x}/daemon.port`;if(!lo(e))return null;try{let t=uo(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function IS(e,t){try{return(await st("POST",`http://127.0.0.1:${e}/api/sessions/${encodeURIComponent(t)}/relink`,{clear:!0})).ok}catch{return!1}}function MS(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
1469
1466
  FROM sessions s
1470
1467
  JOIN projects p ON p.id = s.project_id
1471
1468
  JOIN session_aliases sa ON sa.session_id = s.id
1472
1469
  WHERE s.cwd IS NOT NULL
1473
1470
  AND s.started_at IS NOT NULL
1474
1471
  AND sa.alias IS NOT NULL
1475
- AND sa.alias <> ''${n}`).all(...r),i=new Map;for(let l of o){let u=l.cwd.replace(/\/+$/,""),p=i.get(u);p||(p=[],i.set(u,p)),p.push(l)}let a=e*1e3,d=new Map;for(let[l,u]of i){let p=new Map;for(let m of u){let g=p.get(m.alias);g||(g=[],p.set(m.alias,g)),g.push(m)}for(let m of p.values())if(!(m.length<2))for(let g of m){let f=new Set;for(let h of m)h.id!==g.id&&f.add(h.id);d.set(g.id,{row:g,cwdKey:l,reason:"duplicate-alias",siblingIds:f})}}for(let[l,u]of i){if(u.length<2)continue;u.sort((g,f)=>Date.parse(g.started_at)-Date.parse(f.started_at));let p=[],m=()=>{if(p.length>=2)for(let g of p){if(d.has(g.id))continue;let f=new Set;for(let h of p)h.id!==g.id&&f.add(h.id);d.set(g.id,{row:g,cwdKey:l,reason:"cwd-collision",siblingIds:f})}p=[]};for(let g of u){if(p.length===0){p.push(g);continue}let f=p[p.length-1];Date.parse(g.started_at)-Date.parse(f.started_at)<=a||m(),p.push(g)}m()}return Array.from(d.values()).map(l=>({session_id:l.row.id,project_name:l.row.project_name,cwd:l.cwdKey,started_at:l.row.started_at,alias:l.row.alias,sibling_ids:Array.from(l.siblingIds),reason:l.reason}))}function xS(e){let t=[];try{let s=`${x}/terminals.json`;if(!ao(s))return t;let n=JSON.parse(co(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,d]of Object.entries(r)){let l=Number(a);if(!Number.isFinite(l))continue;let u=o.get(l)??null;for(let p of d){let m=i.prepare(`SELECT s.id, p.name AS project_name, s.cwd, s.started_at,
1472
+ AND sa.alias <> ''${n}`).all(...r),i=new Map;for(let l of o){let u=l.cwd.replace(/\/+$/,""),p=i.get(u);p||(p=[],i.set(u,p)),p.push(l)}let a=e*1e3,d=new Map;for(let[l,u]of i){let p=new Map;for(let m of u){let g=p.get(m.alias);g||(g=[],p.set(m.alias,g)),g.push(m)}for(let m of p.values())if(!(m.length<2))for(let g of m){let f=new Set;for(let h of m)h.id!==g.id&&f.add(h.id);d.set(g.id,{row:g,cwdKey:l,reason:"duplicate-alias",siblingIds:f})}}for(let[l,u]of i){if(u.length<2)continue;u.sort((g,f)=>Date.parse(g.started_at)-Date.parse(f.started_at));let p=[],m=()=>{if(p.length>=2)for(let g of p){if(d.has(g.id))continue;let f=new Set;for(let h of p)h.id!==g.id&&f.add(h.id);d.set(g.id,{row:g,cwdKey:l,reason:"cwd-collision",siblingIds:f})}p=[]};for(let g of u){if(p.length===0){p.push(g);continue}let f=p[p.length-1];Date.parse(g.started_at)-Date.parse(f.started_at)<=a||m(),p.push(g)}m()}return Array.from(d.values()).map(l=>({session_id:l.row.id,project_name:l.row.project_name,cwd:l.cwdKey,started_at:l.row.started_at,alias:l.row.alias,sibling_ids:Array.from(l.siblingIds),reason:l.reason}))}function DS(e){let t=[];try{let s=`${x}/terminals.json`;if(!lo(s))return t;let n=JSON.parse(uo(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,d]of Object.entries(r)){let l=Number(a);if(!Number.isFinite(l))continue;let u=o.get(l)??null;for(let p of d){let m=i.prepare(`SELECT s.id, p.name AS project_name, s.cwd, s.started_at,
1476
1473
  NULLIF(sa.alias, '') AS alias
1477
1474
  FROM sessions s
1478
1475
  JOIN projects p ON p.id = s.project_id
1479
1476
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1480
- 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 kS(e){let t=[],s=`${x}/terminals.json`;if(!ao(s))return t;let n;try{n=JSON.parse(co(s,"utf8"))}catch{return t}let r=new Map;for(let l of n.terminals??[]){if(!l.tab_name)continue;let u=r.get(l.tab_name);u||(u=[],r.set(l.tab_name,u)),u.push(l)}if(r.size===0)return t;let o=_(),i=e?" AND p.name = ?":"",a=e?[e]:[],d=o.prepare(`SELECT s.id, p.name AS project_name, s.cwd, s.started_at, sa.alias
1477
+ 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 $S(e){let t=[],s=`${x}/terminals.json`;if(!lo(s))return t;let n;try{n=JSON.parse(uo(s,"utf8"))}catch{return t}let r=new Map;for(let l of n.terminals??[]){if(!l.tab_name)continue;let u=r.get(l.tab_name);u||(u=[],r.set(l.tab_name,u)),u.push(l)}if(r.size===0)return t;let o=_(),i=e?" AND p.name = ?":"",a=e?[e]:[],d=o.prepare(`SELECT s.id, p.name AS project_name, s.cwd, s.started_at, sa.alias
1481
1478
  FROM sessions s
1482
1479
  JOIN projects p ON p.id = s.project_id
1483
1480
  JOIN session_aliases sa ON sa.session_id = s.id
1484
1481
  WHERE s.started_at IS NOT NULL
1485
1482
  AND sa.alias IS NOT NULL
1486
- AND sa.alias <> ''${i}`).all(...a);for(let l of d){let u=r.get(l.alias);if(!u||u.length===0)continue;let p=Date.parse(l.started_at);if(!Number.isFinite(p))continue;let m=!1,g=null,f=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<f&&(f=E,g=h)}}m||!g||t.push({session_id:l.id,project_name:l.project_name,cwd:l.cwd.replace(/\/+$/,""),started_at:l.started_at,alias:l.alias,sibling_ids:[],reason:"temporal-anomaly",postdating_terminal:g})}return t}function CS(e){if(e.length===0){console.log(c.ok("No suspicious correlations found."));return}console.log(c.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(c.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"?c.err("[dup-alias]"):r.reason==="orphan-link"?c.warn("[orphan-link]"):r.reason==="temporal-anomaly"?c.err("[temporal]"):c.warn("[cwd-collision]"),i=r.reason==="orphan-link"&&r.stale_terminal?`${c.dim("still pointing at pid")} ${r.stale_terminal.shell_pid} ${c.dim("=")} ${c.bold(`"${r.stale_terminal.tab_name}"`)}`:r.reason==="temporal-anomaly"&&r.postdating_terminal?`${c.bold(`"${r.alias}"`)} ${c.dim("\u2190 terminal opened")} ${r.postdating_terminal.opened_at.replace("T"," ").slice(0,19)} ${c.dim("(after session)")}`:c.bold(`"${r.alias}"`);console.log(` ${o} ${c.dim(r.session_id.slice(0,8))} ${c.dim(r.started_at.replace("T"," ").slice(0,19))} \u2192 ${i}`)}console.log()}}async function Il(e){let t=e.window?Math.max(5,Math.min(600,Number(e.window)||60)):60,s=e.project?.trim()||void 0,n=RS(t,s),r=xS(s),o=kS(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(CS(a),!e.fix){a.length>0&&console.log(c.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 d=wS(),l=0,u=0;for(let p of a){if(d){await TS(d,p.session_id)?l++:(u++,console.error(c.err(`failed to clear ${p.session_id.slice(0,8)} via daemon`)));continue}try{Oa(p.session_id),io.unlinkSession(p.session_id),l++}catch(m){u++,console.error(c.err(`failed to clear ${p.session_id.slice(0,8)}: ${m.message}`))}}console.log(c.ok(`Cleared ${l} suspect alias${l===1?"":"es"}.`)),u>0&&console.log(c.warn(`${u} clears failed; see errors above.`)),d||console.log(c.dim("Daemon was not running, so changes were applied directly to state files.")),console.log(c.dim("Open an affected session in the UI and use the \u{1F517} picker to pin the correct terminal."))}v();w();D();import{existsSync as jl,readFileSync as DS,statSync as po,statfsSync as $S}from"node:fs";import{join as Ul}from"node:path";import*as Bl from"node:http";D();w();import{watch as rI}from"chokidar";import{readdirSync as IS,statSync as iI}from"node:fs";import{basename as uI,join as MS}from"node:path";import{execFile as AS}from"node:child_process";import{promisify as OS}from"node:util";bt();w();import{execFile as LS}from"node:child_process";import{promisify as NS}from"node:util";var Sv=NS(LS);var Nv=OS(AS);var Av=3600*1e3;w();D();import{basename as Bv,join as lo}from"node:path";w();D();import{join as vS}from"node:path";var Dv=vS(x,"collections.json");var Ml=lo(x,"auto-rules"),Jv=lo(Ml,"rules.json"),Yv=lo(Ml,"suggestions.json");bt();function Dl(e){let t=e.split(/[/\\]/),s=t.findIndex(n=>n==="projects");return s===-1||s+1>=t.length?null:t[s+1]??null}function $l(e){return e.replace(/\\/g,"/").includes("/subagents/")}function*uo(e){let t;try{t=IS(e,{withFileTypes:!0,encoding:"utf8"})}catch{return}for(let s of t){if(s.isSymbolicLink())continue;let n=MS(e,s.name);s.isDirectory()?yield*uo(n):s.isFile()&&s.name.endsWith(".jsonl")&&(yield n)}}var PS=["VS Code","VS Code Insiders","Cursor","Windsurf","Warp","iTerm","Terminal","WezTerm","Windows Terminal","Kitty","Alacritty"],FS=new RegExp(`^(${PS.map(e=>e.replace(/ /g,"\\s")).join("|")})\\s\xB7\\s`);function jS(e){let t=[];for(let s of e)if(s.alias){if(FS.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 Hl=5*6e4,mo=24,Wl=.5;function US(){let e=Ul(x,"daemon.port");if(!jl(e))return null;try{let t=DS(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 BS(e,t,s=1500){return new Promise(n=>{let r=Bl.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 HS(){let e=Ul(x,"terminals.json");if(!jl(e))return{exists:!1,mtimeMs:null,ageSeconds:null};try{let t=po(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 WS(){let e=new Date(Date.now()-mo*36e5).toISOString();try{let t=_().prepare(`SELECT
1483
+ AND sa.alias <> ''${i}`).all(...a);for(let l of d){let u=r.get(l.alias);if(!u||u.length===0)continue;let p=Date.parse(l.started_at);if(!Number.isFinite(p))continue;let m=!1,g=null,f=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<f&&(f=E,g=h)}}m||!g||t.push({session_id:l.id,project_name:l.project_name,cwd:l.cwd.replace(/\/+$/,""),started_at:l.started_at,alias:l.alias,sibling_ids:[],reason:"temporal-anomaly",postdating_terminal:g})}return t}function PS(e){if(e.length===0){console.log(c.ok("No suspicious correlations found."));return}console.log(c.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(c.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"?c.err("[dup-alias]"):r.reason==="orphan-link"?c.warn("[orphan-link]"):r.reason==="temporal-anomaly"?c.err("[temporal]"):c.warn("[cwd-collision]"),i=r.reason==="orphan-link"&&r.stale_terminal?`${c.dim("still pointing at pid")} ${r.stale_terminal.shell_pid} ${c.dim("=")} ${c.bold(`"${r.stale_terminal.tab_name}"`)}`:r.reason==="temporal-anomaly"&&r.postdating_terminal?`${c.bold(`"${r.alias}"`)} ${c.dim("\u2190 terminal opened")} ${r.postdating_terminal.opened_at.replace("T"," ").slice(0,19)} ${c.dim("(after session)")}`:c.bold(`"${r.alias}"`);console.log(` ${o} ${c.dim(r.session_id.slice(0,8))} ${c.dim(r.started_at.replace("T"," ").slice(0,19))} \u2192 ${i}`)}console.log()}}async function $l(e){let t=e.window?Math.max(5,Math.min(600,Number(e.window)||60)):60,s=e.project?.trim()||void 0,n=MS(t,s),r=DS(s),o=$S(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(PS(a),!e.fix){a.length>0&&console.log(c.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 d=vS(),l=0,u=0;for(let p of a){if(d){await IS(d,p.session_id)?l++:(u++,console.error(c.err(`failed to clear ${p.session_id.slice(0,8)} via daemon`)));continue}try{Ma(p.session_id),co.unlinkSession(p.session_id),l++}catch(m){u++,console.error(c.err(`failed to clear ${p.session_id.slice(0,8)}: ${m.message}`))}}console.log(c.ok(`Cleared ${l} suspect alias${l===1?"":"es"}.`)),u>0&&console.log(c.warn(`${u} clears failed; see errors above.`)),d||console.log(c.dim("Daemon was not running, so changes were applied directly to state files.")),console.log(c.dim("Open an affected session in the UI and use the \u{1F517} picker to pin the correct terminal."))}v();w();P();import{existsSync as Hl,readFileSync as JS,statSync as go,statfsSync as GS}from"node:fs";import{join as Wl}from"node:path";import*as Xl from"node:http";P();w();import{watch as RI}from"chokidar";import{readdirSync as WS,statSync as kI}from"node:fs";import{basename as OI,join as XS}from"node:path";import{execFile as US}from"node:child_process";import{promisify as BS}from"node:util";Et();w();import{execFile as FS}from"node:child_process";import{promisify as jS}from"node:util";var Uv=jS(FS);var qv=BS(US);var Kv=3600*1e3;w();P();import{basename as aI,join as po}from"node:path";w();P();import{join as HS}from"node:path";var tI=HS(x,"collections.json");var Pl=po(x,"auto-rules"),uI=po(Pl,"rules.json"),pI=po(Pl,"suggestions.json");Et();function Fl(e){let t=e.split(/[/\\]/),s=t.findIndex(n=>n==="projects");return s===-1||s+1>=t.length?null:t[s+1]??null}function jl(e){return e.replace(/\\/g,"/").includes("/subagents/")}function*mo(e){let t;try{t=WS(e,{withFileTypes:!0,encoding:"utf8"})}catch{return}for(let s of t){if(s.isSymbolicLink())continue;let n=XS(e,s.name);s.isDirectory()?yield*mo(n):s.isFile()&&s.name.endsWith(".jsonl")&&(yield n)}}var YS=["VS Code","VS Code Insiders","Cursor","Windsurf","Warp","iTerm","Terminal","WezTerm","Windows Terminal","Kitty","Alacritty"],zS=new RegExp(`^(${YS.map(e=>e.replace(/ /g,"\\s")).join("|")})\\s\xB7\\s`);function qS(e){let t=[];for(let s of e)if(s.alias){if(zS.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 Jl=5*6e4,fo=24,Gl=.5;function KS(){let e=Wl(x,"daemon.port");if(!Hl(e))return null;try{let t=JS(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 VS(e,t,s=1500){return new Promise(n=>{let r=Xl.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 ZS(){let e=Wl(x,"terminals.json");if(!Hl(e))return{exists:!1,mtimeMs:null,ageSeconds:null};try{let t=go(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 QS(){let e=new Date(Date.now()-fo*36e5).toISOString();try{let t=_().prepare(`SELECT
1487
1484
  COUNT(*) AS total,
1488
1485
  SUM(CASE WHEN sa.alias IS NULL OR sa.alias = '' THEN 1 ELSE 0 END) AS without_alias,
1489
1486
  SUM(CASE WHEN (sa.alias IS NULL OR sa.alias = '')
1490
1487
  AND s.auto_title_source = 'heuristic' THEN 1 ELSE 0 END) AS heuristic_only
1491
1488
  FROM sessions s
1492
1489
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1493
- 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 XS(){let e=US(),t=HS(),s=WS(),n=!1,r=null,o=null,i=null,a=null,d=null;if(e){let p=await BS(e,"/api/health");if(p){n=!0,r=typeof p.uptimeSeconds=="number"?p.uptimeSeconds:null,o=typeof p.version=="string"?p.version:null,i=typeof p.pipeline?.silentTerminalRejections=="number"?p.pipeline.silentTerminalRejections:null,a=p.pipeline?.lastTerminalSyncAt??null;let m=p.pipeline?.autoExtract;m&&(d={circuitBroken:m.circuitBroken===!0,reason:m.reason??null,brokenAt:typeof m.brokenAt=="number"?m.brokenAt:null,consecutiveZeroTokenRuns:typeof m.consecutiveZeroTokenRuns=="number"?m.consecutiveZeroTokenRuns:0})}}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 p=Date.now()-Date.parse(a);Number.isFinite(p)&&p>Hl&&l.push(`Last successful /api/terminal/sync was ${Math.round(p/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.`),d?.circuitBroken&&l.push(`Auto-extract circuit breaker tripped \u2014 ${d.reason??"reason unknown"}. Run \`recall semantic auto-extract off\` then \`... on\` to reset, or restart the daemon.`),s.total>=3&&s.fractionHeuristic>=Wl&&l.push(`${s.heuristicOnly}/${s.total} sessions in the last ${mo}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,autoExtract:d},terminalsJson:t,recentSessions:s}}function We(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 Pl(e){try{return po(e).size}catch{return 0}}function Fl(e){try{return _().prepare(`SELECT COUNT(*) AS n FROM ${e}_data WHERE block = 1`).get().n}catch{return 0}}function JS(){try{return _().prepare(`SELECT p.name AS project,
1490
+ 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 ey(){let e=KS(),t=ZS(),s=QS(),n=!1,r=null,o=null,i=null,a=null,d=null;if(e){let p=await VS(e,"/api/health");if(p){n=!0,r=typeof p.uptimeSeconds=="number"?p.uptimeSeconds:null,o=typeof p.version=="string"?p.version:null,i=typeof p.pipeline?.silentTerminalRejections=="number"?p.pipeline.silentTerminalRejections:null,a=p.pipeline?.lastTerminalSyncAt??null;let m=p.pipeline?.autoExtract;m&&(d={circuitBroken:m.circuitBroken===!0,reason:m.reason??null,brokenAt:typeof m.brokenAt=="number"?m.brokenAt:null,consecutiveZeroTokenRuns:typeof m.consecutiveZeroTokenRuns=="number"?m.consecutiveZeroTokenRuns:0})}}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 p=Date.now()-Date.parse(a);Number.isFinite(p)&&p>Jl&&l.push(`Last successful /api/terminal/sync was ${Math.round(p/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.`),d?.circuitBroken&&l.push(`Auto-extract circuit breaker tripped \u2014 ${d.reason??"reason unknown"}. Run \`recall semantic auto-extract off\` then \`... on\` to reset, or restart the daemon.`),s.total>=3&&s.fractionHeuristic>=Gl&&l.push(`${s.heuristicOnly}/${s.total} sessions in the last ${fo}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,autoExtract:d},terminalsJson:t,recentSessions:s}}function We(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 Ul(e){try{return go(e).size}catch{return 0}}function Bl(e){try{return _().prepare(`SELECT COUNT(*) AS n FROM ${e}_data WHERE block = 1`).get().n}catch{return 0}}function ty(){try{return _().prepare(`SELECT p.name AS project,
1494
1491
  COALESCE(NULLIF(sa.alias, ''), s.auto_title, substr(s.first_user_message, 1, 60)) AS label,
1495
1492
  COUNT(*) AS count,
1496
1493
  MAX(CASE WHEN sa.alias IS NOT NULL AND sa.alias != '' THEN 1 ELSE 0 END) AS any_aliased
@@ -1502,27 +1499,27 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1502
1499
  GROUP BY p.name, label
1503
1500
  HAVING count >= 2
1504
1501
  ORDER BY count DESC, label ASC
1505
- LIMIT 10`).all().map(e=>{let t=e;return{project:t.project,label:t.label,count:t.count,anyAliased:t.any_aliased===1}})}catch{return[]}}function YS(e){let t=_(),s=t.pragma("page_size",{simple:!0})||4096,n=t.pragma("page_count",{simple:!0})||0,r=t.pragma("freelist_count",{simple:!0})||0;e?.("Checking database integrity");let o="ok";try{let J=t.pragma("quick_check").map(A=>A.quick_check);o=J.length===1&&J[0]==="ok"?"ok":J.join("; ")}catch(k){o=`check failed: ${k.message}`}let i=Pl(te),a=Pl(`${te}-wal`),d=0,l=0;try{let k=$S(x);d=Number(k.bavail)*Number(k.bsize),l=Number(k.blocks)*Number(k.bsize)}catch{}e?.("Counting rows");let u=t.prepare(`SELECT
1502
+ LIMIT 10`).all().map(e=>{let t=e;return{project:t.project,label:t.label,count:t.count,anyAliased:t.any_aliased===1}})}catch{return[]}}function sy(e){let t=_(),s=t.pragma("page_size",{simple:!0})||4096,n=t.pragma("page_count",{simple:!0})||0,r=t.pragma("freelist_count",{simple:!0})||0;e?.("Checking database integrity");let o="ok";try{let A=t.pragma("quick_check").map($=>$.quick_check);o=A.length===1&&A[0]==="ok"?"ok":A.join("; ")}catch(D){o=`check failed: ${D.message}`}let i=Ul(se),a=Ul(`${se}-wal`),d=0,l=0;try{let D=GS(x);d=Number(D.bavail)*Number(D.bsize),l=Number(D.blocks)*Number(D.bsize)}catch{}e?.("Counting rows");let u=t.prepare(`SELECT
1506
1503
  (SELECT COUNT(*) FROM projects) AS projects,
1507
1504
  (SELECT COUNT(*) FROM sessions) AS sessions,
1508
1505
  (SELECT COUNT(*) FROM messages) AS messages,
1509
- (SELECT COUNT(*) FROM message_usage) AS message_usage`).get(),p=0;try{p=t.prepare("SELECT COUNT(*) AS n FROM vec_chunks").get().n}catch{}e?.("Measuring FTS fragmentation");let m=[];d>0&&d<1*1024**3&&m.push(`Disk free is ${We(d)} \u2014 heavy operations (synthesis, extract-outputs, vector ingest) may fail.`);let g=100*1024**2,f=a>=Ta?"error":a>=g?"warn":"ok";f==="error"?m.push(`WAL is ${We(a)} \u2014 readers are pinning the checkpoint frontier. Run \`recall mcp-prune\` to release stuck MCP children, then \`recall optimize\` to truncate.`):f==="warn"&&m.push(`WAL is ${We(a)} \u2014 run \`recall optimize\` to truncate it.`);let h=Ms(),E=h.filter(k=>k.orphan);E.length>0&&m.push(`${E.length} orphaned MCP child${E.length===1?"":"ren"} (pid${E.length===1?"":"s"}: ${E.map(k=>k.pid).join(", ")}). Each holds a SQLite read connection. Run \`recall mcp-prune\` to clean up.`),r>n*.2&&n>1e3&&m.push(`${r.toLocaleString()} free pages (${(r/n*100).toFixed(0)}% of file) \u2014 \`recall optimize --vacuum\` will reclaim them.`);let b=Fl("messages_fts"),S=Fl("sessions_fts");b>16&&m.push(`messages_fts has ${b} segments \u2014 \`recall optimize\` will merge them.`);let T=0;try{T=t.prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}catch{}let R=!1;try{R=t.prepare("SELECT value FROM app_settings WHERE key = 'semantic_enabled'").get()?.value==="1"}catch{}return!R&&T>0?m.push(`${T.toLocaleString()} rows in chunk_queue with semantic disabled \u2014 schema gate is stale; restart daemon (v0.67+) to migrate.`):T>1e5&&m.push(`chunk_queue has ${T.toLocaleString()} pending rows \u2014 embedder is behind. \`recall semantic backfill\` to drain manually.`),{db:{sizeBytes:i,walSizeBytes:a,pageCount:n,pageSize:s,freelistCount:r,freelistBytes:r*s,integrity:o},disk:{freeBytes:d,totalBytes:l},fts:{messages:{fragments:b},sessions:{fragments:S}},vectors:{rows:p},rows:{projects:u.projects,sessions:u.sessions,messages:u.messages,messageUsage:u.message_usage},chunkQueue:{size:T,semanticEnabled:R},wal:{sizeBytes:a,level:f},mcpProcesses:h,warnings:m}}function GS(e){if(!e)return{stage:()=>{},done:()=>{}};let t=!!process.stderr.isTTY,s="",n=0,r=()=>{if(!s)return;let o=Date.now()-n,i=o<1e3?`${o}ms`:`${(o/1e3).toFixed(1)}s`;t?process.stderr.write(`\r\x1B[2K ${c.ok("\u2713")} ${s} ${c.dim(`(${i})`)}
1506
+ (SELECT COUNT(*) FROM message_usage) AS message_usage`).get(),p=0;try{p=t.prepare("SELECT COUNT(*) AS n FROM vec_chunks").get().n}catch{}e?.("Measuring FTS fragmentation");let m=[];d>0&&d<1*1024**3&&m.push(`Disk free is ${We(d)} \u2014 heavy operations (synthesis, extract-outputs, vector ingest) may fail.`);let g=100*1024**2,f=a>=sa?"error":a>=g?"warn":"ok";f==="error"?m.push(`WAL is ${We(a)} \u2014 readers are pinning the checkpoint frontier. Run \`recall mcp-prune\` to release stuck MCP children, then \`recall optimize\` to truncate.`):f==="warn"&&m.push(`WAL is ${We(a)} \u2014 run \`recall optimize\` to truncate it.`);let h=Qt(),E=h.filter(D=>D.orphan);E.length>0&&m.push(`${E.length} orphaned MCP child${E.length===1?"":"ren"} (pid${E.length===1?"":"s"}: ${E.map(D=>D.pid).join(", ")}). Each holds a SQLite read connection. Run \`recall mcp-prune\` to clean up.`);let b=h.filter(vs);b.length>0&&m.push(`${b.length} MCP child${b.length===1?"":"ren"} burning CPU (pid${b.length===1?"":"s"}: ${b.map(D=>D.pid).join(", ")}). Likely runaway vec0 kNN. Run \`recall stop --all\` or \`recall mcp-prune --all\`.`),r>n*.2&&n>1e3&&m.push(`${r.toLocaleString()} free pages (${(r/n*100).toFixed(0)}% of file) \u2014 \`recall optimize --vacuum\` will reclaim them.`);let S=Bl("messages_fts"),R=Bl("sessions_fts");S>16&&m.push(`messages_fts has ${S} segments \u2014 \`recall optimize\` will merge them.`);let T=0;try{T=t.prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}catch{}let L=!1;try{L=t.prepare("SELECT value FROM app_settings WHERE key = 'semantic_enabled'").get()?.value==="1"}catch{}return!L&&T>0?m.push(`${T.toLocaleString()} rows in chunk_queue with semantic disabled \u2014 schema gate is stale; restart daemon (v0.67+) to migrate.`):T>1e5&&m.push(`chunk_queue has ${T.toLocaleString()} pending rows \u2014 embedder is behind. \`recall semantic backfill\` to drain manually.`),{db:{sizeBytes:i,walSizeBytes:a,pageCount:n,pageSize:s,freelistCount:r,freelistBytes:r*s,integrity:o},disk:{freeBytes:d,totalBytes:l},fts:{messages:{fragments:S},sessions:{fragments:R}},vectors:{rows:p},rows:{projects:u.projects,sessions:u.sessions,messages:u.messages,messageUsage:u.message_usage},chunkQueue:{size:T,semanticEnabled:L},wal:{sizeBytes:a,level:f},mcpProcesses:h,warnings:m}}function ny(e){if(!e)return{stage:()=>{},done:()=>{}};let t=!!process.stderr.isTTY,s="",n=0,r=()=>{if(!s)return;let o=Date.now()-n,i=o<1e3?`${o}ms`:`${(o/1e3).toFixed(1)}s`;t?process.stderr.write(`\r\x1B[2K ${c.ok("\u2713")} ${s} ${c.dim(`(${i})`)}
1510
1507
  `):process.stderr.write(` \u2713 ${s} (${i})
1511
1508
  `),s=""};return{stage(o){r(),s=o,n=Date.now(),t?process.stderr.write(` ${c.dim("\u2026")} ${s}`):process.stderr.write(` \u2026 ${s}
1512
- `)},done:r}}function zS(e){if(console.log(c.dim("\u2014 MCP processes \u2014")),e.length===0){console.log(c.ok(" \u2713 no MCP children running"));return}let t=e.filter(r=>r.orphan),s=e.reduce((r,o)=>Math.max(r,o.etimeSeconds),0),n=e.length-t.length;if(console.log(` ${e.length} total, ${n} with live parent, ${t.length===0?c.ok("0 orphaned"):c.err(`${t.length} orphaned`)} (oldest ${Qt(s)})`),t.length>0){console.log(c.dim(" Orphans hold a SQLite read connection and can stall WAL checkpoints. Run `recall mcp-prune` to kill them."));for(let r of t.slice(0,5))console.log(` ${c.dim("\u2022")} pid ${r.pid} age ${Qt(r.etimeSeconds)} ppid=${r.ppid} (gone)`)}}function KS(){let e=_(),t=e.prepare("SELECT encoded_path FROM projects").all(),s=new Set(t.map(l=>l.encoded_path));if(s.size===0)return{status:"ok",staleCount:0,scanned:0,sampleFiles:[],message:"Ingest freshness: ok (no projects indexed yet \u2014 nothing to monitor)."};let n=e.prepare("SELECT file_mtime FROM sessions WHERE file_path = ? LIMIT 1"),r=0,o=0,i=[];for(let l of uo(Lt)){if($l(l))continue;let u=Dl(l);if(!u||!s.has(u))continue;r+=1;let p;try{p=po(l).mtimeMs}catch{continue}let m=n.get(l);(!m||m.file_mtime<p)&&(o+=1,i.length<5&&i.push(l))}if(o===0)return{status:"ok",staleCount:0,scanned:r,sampleFiles:[],message:`Ingest freshness: ok (scanned ${r} JSONL${r===1?"":"s"} in ${s.size} known project${s.size===1?"":"s"}, none newer than the index).`};let a=o>10?"fail":"warn",d=i.slice(0,3).map(l=>l.split(/[/\\]/).pop()??l).join(", ");return{status:a,staleCount:o,scanned:r,sampleFiles:i,message:`Ingest freshness: ${a} \u2014 ${o} JSONL${o===1?"":" files"} newer than the index (sample: ${d}). Run \`recall index\` to force a reindex, or restart the daemon if this is persistent.`}}async function Xl(e={}){let t=GS(!e.json);t.stage("Scanning session aliases");let s=_().prepare(`SELECT sa.session_id AS session_id, sa.alias AS alias, s.cwd AS cwd
1509
+ `)},done:r}}function ry(e){if(console.log(c.dim("\u2014 MCP processes \u2014")),e.length===0){console.log(c.ok(" \u2713 no MCP children running"));return}let t=e.filter(o=>o.orphan),s=e.reduce((o,i)=>Math.max(o,i.etimeSeconds),0),n=e.length-t.length;if(console.log(` ${e.length} total, ${n} with live parent, ${t.length===0?c.ok("0 orphaned"):c.err(`${t.length} orphaned`)} (oldest ${It(s)})`),t.length>0){console.log(c.dim(" Orphans hold a SQLite read connection and can stall WAL checkpoints. Run `recall mcp-prune` to kill them."));for(let o of t.slice(0,5))console.log(` ${c.dim("\u2022")} pid ${o.pid} age ${It(o.etimeSeconds)} ppid=${o.ppid} (gone)`)}let r=e.filter(vs);if(r.length>0){console.log(c.warn(` ! ${r.length} MCP child${r.length===1?"":"ren"} burning CPU (likely runaway vec0 kNN -- see 2026-05-15 incident).`));for(let o of r){let i=o.parentCommand?`parent ${o.parentCommand}`:`ppid ${o.ppid}`;console.log(c.dim(` pid ${o.pid} ${o.pcpu.toFixed(0)}%cpu ${It(o.etimeSeconds)} elapsed (${i})`))}console.log(c.dim(" Run `recall stop --all` for one-command recovery, or `recall mcp-prune --all` to keep the daemon alive."))}}function oy(){let e=_(),t=e.prepare("SELECT encoded_path FROM projects").all(),s=new Set(t.map(l=>l.encoded_path));if(s.size===0)return{status:"ok",staleCount:0,scanned:0,sampleFiles:[],message:"Ingest freshness: ok (no projects indexed yet \u2014 nothing to monitor)."};let n=e.prepare("SELECT file_mtime FROM sessions WHERE file_path = ? LIMIT 1"),r=0,o=0,i=[];for(let l of mo(Lt)){if(jl(l))continue;let u=Fl(l);if(!u||!s.has(u))continue;r+=1;let p;try{p=go(l).mtimeMs}catch{continue}let m=n.get(l);(!m||m.file_mtime<p)&&(o+=1,i.length<5&&i.push(l))}if(o===0)return{status:"ok",staleCount:0,scanned:r,sampleFiles:[],message:`Ingest freshness: ok (scanned ${r} JSONL${r===1?"":"s"} in ${s.size} known project${s.size===1?"":"s"}, none newer than the index).`};let a=o>10?"fail":"warn",d=i.slice(0,3).map(l=>l.split(/[/\\]/).pop()??l).join(", ");return{status:a,staleCount:o,scanned:r,sampleFiles:i,message:`Ingest freshness: ${a} \u2014 ${o} JSONL${o===1?"":" files"} newer than the index (sample: ${d}). Run \`recall index\` to force a reindex, or restart the daemon if this is persistent.`}}async function Yl(e={}){let t=ny(!e.json);t.stage("Scanning session aliases");let s=_().prepare(`SELECT sa.session_id AS session_id, sa.alias AS alias, s.cwd AS cwd
1513
1510
  FROM session_aliases sa
1514
1511
  LEFT JOIN sessions s ON s.id = sa.session_id
1515
- WHERE sa.alias IS NOT NULL AND sa.alias != ''`).all(),n=jS(s),r=YS(t.stage);t.stage("Probing daemon");let o=await XS();t.stage("Detecting label collisions");let i=JS();t.stage("Checking ingest freshness");let a=KS();if(t.done(),e.json){process.stdout.write(JSON.stringify({scanned:s.length,violations:n.length,items:n,health:r,pipeline:o,labelCollisions:i,ingestFreshness:a},null,2)),process.stdout.write(`
1516
- `);let u=o.state==="degraded",p=a.status==="fail";return n.length===0&&r.db.integrity==="ok"&&!u&&!p?0:1}console.log(c.dim("\u2014 System health \u2014")),console.log(` Database ${We(r.db.sizeBytes)} (${r.rows.messages.toLocaleString()} messages across ${r.rows.sessions.toLocaleString()} sessions, ${r.rows.projects.toLocaleString()} projects)`);{let u=r.wal,p=u.level==="error"?c.err(We(u.sizeBytes)):u.level==="warn"?c.warn(We(u.sizeBytes)):c.ok(We(u.sizeBytes)),m=u.level==="error"?" (readers are pinning the checkpoint frontier \u2014 see warnings below)":u.level==="warn"?" (above 100 MB \u2014 daemon will WARN until it drops)":" (daemon checkpoints PASSIVE every 60s, RESTART above 5 GB)";console.log(` WAL ${p}${m}`)}console.log(` Free pages ${r.db.freelistCount.toLocaleString()} (${We(r.db.freelistBytes)} reclaimable via VACUUM)`);{let u=r.fts.messages.fragments,p=r.fts.sessions.fragments,m=u===0&&p===0;console.log(` FTS segments messages=${u}, sessions=${p}`+(m?" (merged \u2014 search uses the index)":" (lower is faster \u2014 `recall optimize` merges them)"))}if(r.chunkQueue.size>0){let p=r.chunkQueue.size>1e5?c.warn(r.chunkQueue.size.toLocaleString()):r.chunkQueue.size.toLocaleString();console.log(` Embed queue ${p}`+(r.chunkQueue.semanticEnabled?" (worker is enabled; should drain over time)":" (semantic disabled \u2014 should be 0; if not, schema migration may be stale)"))}if(console.log(` Vector rows ${r.vectors.rows.toLocaleString()}`),r.disk.totalBytes>0){let u=r.disk.freeBytes/r.disk.totalBytes*100;console.log(` Disk free ${We(r.disk.freeBytes)} of ${We(r.disk.totalBytes)} (${u.toFixed(1)}%)`)}if(console.log(` Integrity ${r.db.integrity==="ok"?c.ok("ok"):c.err(r.db.integrity)}`),r.warnings.length>0){console.log("");for(let u of r.warnings)console.log(` ${c.warn("!")} ${u}`)}if(console.log(""),zS(r.mcpProcesses),console.log(""),console.log(c.dim("\u2014 Ingest freshness \u2014")),a.status==="ok")console.log(c.ok(` \u2713 ${a.scanned.toLocaleString()} JSONL${a.scanned===1?"":"s"} scanned, none newer than the index`));else if(a.status==="warn"){console.log(` ${c.warn(`${a.staleCount} stale file${a.staleCount===1?"":"s"}`)} newer than the index \u2014 live watcher may be missing events`);for(let u of a.sampleFiles.slice(0,5))console.log(` ${c.dim("\u2022")} ${u}`);console.log(c.dim(" Run `recall index` to force a reindex, or restart the daemon if persistent."))}else{console.log(` ${c.err(`${a.staleCount} stale file${a.staleCount===1?"":"s"}`)} newer than the index \u2014 significant ingest gap`);for(let u of a.sampleFiles.slice(0,5))console.log(` ${c.dim("\u2022")} ${u}`);console.log(c.err(" Restart the daemon (recall stop && recall start) \u2014 the live watcher has fallen behind."))}if(console.log(""),console.log(c.dim("\u2014 Pipeline health (tab-name \u2192 session alias) \u2014")),o.daemon.running?console.log(` Daemon ${c.ok("running")} (port ${o.daemon.port}, version ${o.daemon.version??"?"}, up ${o.daemon.uptimeSeconds!==null?Math.round(o.daemon.uptimeSeconds/60)+" min":"?"})`):console.log(` Daemon ${c.warn("not reachable")}`),o.runtime.silentTerminalRejections!==null){let u=o.runtime.silentTerminalRejections;console.log(` Auth rejections ${u===0?c.ok("0"):c.err(u.toLocaleString())} (extension /api/terminal/* requests denied without a valid X-Recall-Token)`)}if(o.runtime.autoExtract){let u=o.runtime.autoExtract;u.circuitBroken?console.log(` Auto-extract ${c.err("circuit broken")} (${u.reason??"unknown"} \u2014 toggle off/on to reset)`):u.consecutiveZeroTokenRuns>0&&console.log(` Auto-extract ${c.warn(`${u.consecutiveZeroTokenRuns} zero-token run(s)`)} (breaker trips at 3)`)}if(o.runtime.lastTerminalSyncAt!==null){let u=Date.now()-Date.parse(o.runtime.lastTerminalSyncAt),p=Number.isFinite(u)?Math.round(u/6e4):null,m=p!==null&&u>Hl;console.log(` Last ext sync ${m?c.warn(`${p} min ago`):c.ok(p===0?"just now":`${p} min ago`)} (most recent successful POST /api/terminal/sync)`)}else o.daemon.running&&console.log(` Last ext sync ${c.warn("never")} (no extension has called /api/terminal/sync since the daemon started)`);if(o.terminalsJson.exists&&o.terminalsJson.ageSeconds!==null){let u=Math.round(o.terminalsJson.ageSeconds/3600),p=o.terminalsJson.ageSeconds>24*3600;console.log(` terminals.json ${p?c.warn(`${u}h old`):c.ok(`${u}h old`)} (persisted registry mtime \u2014 fresh means extensions are connecting)`)}let d=o.recentSessions;if(d.total>0){let u=Math.round(d.fractionHeuristic*100),p=d.fractionHeuristic>=Wl&&d.total>=3;console.log(` Recent titles ${p?c.err(`${u}% heuristic`):c.ok(`${u}% heuristic`)} (${d.heuristicOnly}/${d.total} sessions in last ${mo}h fell back to first-message title)`)}if(o.flags.length>0){console.log("");for(let u of o.flags)console.log(` ${c.warn("!")} ${u}`)}if(console.log(""),console.log(c.dim("\u2014 Label collisions (last 7d) \u2014")),i.length===0)console.log(c.ok(" \u2713 no session-list label collisions in the last week"));else{let u=i.filter(p=>!p.anyAliased);console.log(` ${c.warn(`${i.length} group(s)`)} of 2+ sessions in the same project share an identical display label \u2014 N parallel runs ended up with the same heuristic title.`);for(let p of i.slice(0,5)){let m=p.anyAliased?c.dim("partial alias"):c.warn("NO alias"),g=p.label.length>60?`${p.label.slice(0,57)}\u2026`:p.label;console.log(` ${c.dim(`${p.count}\xD7`)} ${g} ${m} ${c.dim(`(${p.project})`)}`)}i.length>5&&console.log(c.dim(` \u2026 and ${i.length-5} more (--json for full list)`)),console.log(""),console.log(c.dim(" The display layer auto-disambiguates these (HH:MM / msgs / UUID suffix), so customers\n never see two identical rows. To fix at the source \u2014 when spawning `claude -p` from\n a script or Captain-Code subordinate, prepend each prompt with:")),console.log(c.dim(" <!-- claude-recall-alias: T2.1 Run-Prospects -->")),console.log(c.dim(` The watcher will read the header, alias the session, and strip the marker from the
1512
+ WHERE sa.alias IS NOT NULL AND sa.alias != ''`).all(),n=qS(s),r=sy(t.stage);t.stage("Probing daemon");let o=await ey();t.stage("Detecting label collisions");let i=ty();t.stage("Checking ingest freshness");let a=oy();if(t.done(),e.json){process.stdout.write(JSON.stringify({scanned:s.length,violations:n.length,items:n,health:r,pipeline:o,labelCollisions:i,ingestFreshness:a},null,2)),process.stdout.write(`
1513
+ `);let u=o.state==="degraded",p=a.status==="fail";return n.length===0&&r.db.integrity==="ok"&&!u&&!p?0:1}console.log(c.dim("\u2014 System health \u2014")),console.log(` Database ${We(r.db.sizeBytes)} (${r.rows.messages.toLocaleString()} messages across ${r.rows.sessions.toLocaleString()} sessions, ${r.rows.projects.toLocaleString()} projects)`);{let u=r.wal,p=u.level==="error"?c.err(We(u.sizeBytes)):u.level==="warn"?c.warn(We(u.sizeBytes)):c.ok(We(u.sizeBytes)),m=u.level==="error"?" (readers are pinning the checkpoint frontier \u2014 see warnings below)":u.level==="warn"?" (above 100 MB \u2014 daemon will WARN until it drops)":" (daemon checkpoints PASSIVE every 60s, RESTART above 5 GB)";console.log(` WAL ${p}${m}`)}console.log(` Free pages ${r.db.freelistCount.toLocaleString()} (${We(r.db.freelistBytes)} reclaimable via VACUUM)`);{let u=r.fts.messages.fragments,p=r.fts.sessions.fragments,m=u===0&&p===0;console.log(` FTS segments messages=${u}, sessions=${p}`+(m?" (merged \u2014 search uses the index)":" (lower is faster \u2014 `recall optimize` merges them)"))}if(r.chunkQueue.size>0){let p=r.chunkQueue.size>1e5?c.warn(r.chunkQueue.size.toLocaleString()):r.chunkQueue.size.toLocaleString();console.log(` Embed queue ${p}`+(r.chunkQueue.semanticEnabled?" (worker is enabled; should drain over time)":" (semantic disabled \u2014 should be 0; if not, schema migration may be stale)"))}if(console.log(` Vector rows ${r.vectors.rows.toLocaleString()}`),r.disk.totalBytes>0){let u=r.disk.freeBytes/r.disk.totalBytes*100;console.log(` Disk free ${We(r.disk.freeBytes)} of ${We(r.disk.totalBytes)} (${u.toFixed(1)}%)`)}if(console.log(` Integrity ${r.db.integrity==="ok"?c.ok("ok"):c.err(r.db.integrity)}`),r.warnings.length>0){console.log("");for(let u of r.warnings)console.log(` ${c.warn("!")} ${u}`)}if(console.log(""),ry(r.mcpProcesses),console.log(""),console.log(c.dim("\u2014 Ingest freshness \u2014")),a.status==="ok")console.log(c.ok(` \u2713 ${a.scanned.toLocaleString()} JSONL${a.scanned===1?"":"s"} scanned, none newer than the index`));else if(a.status==="warn"){console.log(` ${c.warn(`${a.staleCount} stale file${a.staleCount===1?"":"s"}`)} newer than the index \u2014 live watcher may be missing events`);for(let u of a.sampleFiles.slice(0,5))console.log(` ${c.dim("\u2022")} ${u}`);console.log(c.dim(" Run `recall index` to force a reindex, or restart the daemon if persistent."))}else{console.log(` ${c.err(`${a.staleCount} stale file${a.staleCount===1?"":"s"}`)} newer than the index \u2014 significant ingest gap`);for(let u of a.sampleFiles.slice(0,5))console.log(` ${c.dim("\u2022")} ${u}`);console.log(c.err(" Restart the daemon (recall stop && recall start) \u2014 the live watcher has fallen behind."))}if(console.log(""),console.log(c.dim("\u2014 Pipeline health (tab-name \u2192 session alias) \u2014")),o.daemon.running?console.log(` Daemon ${c.ok("running")} (port ${o.daemon.port}, version ${o.daemon.version??"?"}, up ${o.daemon.uptimeSeconds!==null?Math.round(o.daemon.uptimeSeconds/60)+" min":"?"})`):console.log(` Daemon ${c.warn("not reachable")}`),o.runtime.silentTerminalRejections!==null){let u=o.runtime.silentTerminalRejections;console.log(` Auth rejections ${u===0?c.ok("0"):c.err(u.toLocaleString())} (extension /api/terminal/* requests denied without a valid X-Recall-Token)`)}if(o.runtime.autoExtract){let u=o.runtime.autoExtract;u.circuitBroken?console.log(` Auto-extract ${c.err("circuit broken")} (${u.reason??"unknown"} \u2014 toggle off/on to reset)`):u.consecutiveZeroTokenRuns>0&&console.log(` Auto-extract ${c.warn(`${u.consecutiveZeroTokenRuns} zero-token run(s)`)} (breaker trips at 3)`)}if(o.runtime.lastTerminalSyncAt!==null){let u=Date.now()-Date.parse(o.runtime.lastTerminalSyncAt),p=Number.isFinite(u)?Math.round(u/6e4):null,m=p!==null&&u>Jl;console.log(` Last ext sync ${m?c.warn(`${p} min ago`):c.ok(p===0?"just now":`${p} min ago`)} (most recent successful POST /api/terminal/sync)`)}else o.daemon.running&&console.log(` Last ext sync ${c.warn("never")} (no extension has called /api/terminal/sync since the daemon started)`);if(o.terminalsJson.exists&&o.terminalsJson.ageSeconds!==null){let u=Math.round(o.terminalsJson.ageSeconds/3600),p=o.terminalsJson.ageSeconds>24*3600;console.log(` terminals.json ${p?c.warn(`${u}h old`):c.ok(`${u}h old`)} (persisted registry mtime \u2014 fresh means extensions are connecting)`)}let d=o.recentSessions;if(d.total>0){let u=Math.round(d.fractionHeuristic*100),p=d.fractionHeuristic>=Gl&&d.total>=3;console.log(` Recent titles ${p?c.err(`${u}% heuristic`):c.ok(`${u}% heuristic`)} (${d.heuristicOnly}/${d.total} sessions in last ${fo}h fell back to first-message title)`)}if(o.flags.length>0){console.log("");for(let u of o.flags)console.log(` ${c.warn("!")} ${u}`)}if(console.log(""),console.log(c.dim("\u2014 Label collisions (last 7d) \u2014")),i.length===0)console.log(c.ok(" \u2713 no session-list label collisions in the last week"));else{let u=i.filter(p=>!p.anyAliased);console.log(` ${c.warn(`${i.length} group(s)`)} of 2+ sessions in the same project share an identical display label \u2014 N parallel runs ended up with the same heuristic title.`);for(let p of i.slice(0,5)){let m=p.anyAliased?c.dim("partial alias"):c.warn("NO alias"),g=p.label.length>60?`${p.label.slice(0,57)}\u2026`:p.label;console.log(` ${c.dim(`${p.count}\xD7`)} ${g} ${m} ${c.dim(`(${p.project})`)}`)}i.length>5&&console.log(c.dim(` \u2026 and ${i.length-5} more (--json for full list)`)),console.log(""),console.log(c.dim(" The display layer auto-disambiguates these (HH:MM / msgs / UUID suffix), so customers\n never see two identical rows. To fix at the source \u2014 when spawning `claude -p` from\n a script or Captain-Code subordinate, prepend each prompt with:")),console.log(c.dim(" <!-- claude-recall-alias: T2.1 Run-Prospects -->")),console.log(c.dim(` The watcher will read the header, alias the session, and strip the marker from the
1517
1514
  displayed first user message. See docs/HANDOFF.md \u2192 "Alias header convention".`)),u.length>0&&(console.log(""),console.log(c.warn(` ${u.length} of these groups have NO alias on any row \u2014 strongest candidates
1518
- for the header-alias fix above.`)))}if(console.log(""),console.log(c.dim("\u2014 Tab-name invariant \u2014")),n.length===0)return console.log(c.ok(` \u2713 holds across ${s.length.toLocaleString()} aliased session${s.length===1?"":"s"}`)),console.log(c.dim(" No fabricated origin labels (`VS Code \xB7 cwd \xB7 branch`) found. No deprecated cwd-branch synthesis found.")),r.db.integrity==="ok"&&a.status!=="fail"?0:1;console.log(c.err(`\u2717 ${n.length} invariant violation${n.length===1?"":"s"} found across ${s.length.toLocaleString()} aliased sessions`)),console.log("");let l=new Map;for(let u of n){let p=l.get(u.violation)??[];p.push(u),l.set(u.violation,p)}for(let[u,p]of l){console.log(c.warn(` ${u} (${p.length})`));for(let m of p.slice(0,10))console.log(` ${m.session_id.slice(0,8)} ${c.dim("\u2192")} ${JSON.stringify(m.alias)}`);p.length>10&&console.log(c.dim(` \u2026 and ${p.length-10} more (rerun with --json for the full list)`)),console.log("")}return console.log(c.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}v();w();D();import{existsSync as qS,readFileSync as VS}from"node:fs";import{join as ZS}from"node:path";function QS(){let e=ZS(x,"daemon.pid");if(!qS(e))return!1;try{let t=parseInt(VS(e,"utf-8").trim(),10);return!Number.isFinite(t)||t<=0?!1:(process.kill(t,0),!0)}catch{return!1}}async function cs(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 Jl(e={}){let t=_(),s=[];if(e.vacuum&&QS())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)+`
1515
+ for the header-alias fix above.`)))}if(console.log(""),console.log(c.dim("\u2014 Tab-name invariant \u2014")),n.length===0)return console.log(c.ok(` \u2713 holds across ${s.length.toLocaleString()} aliased session${s.length===1?"":"s"}`)),console.log(c.dim(" No fabricated origin labels (`VS Code \xB7 cwd \xB7 branch`) found. No deprecated cwd-branch synthesis found.")),r.db.integrity==="ok"&&a.status!=="fail"?0:1;console.log(c.err(`\u2717 ${n.length} invariant violation${n.length===1?"":"s"} found across ${s.length.toLocaleString()} aliased sessions`)),console.log("");let l=new Map;for(let u of n){let p=l.get(u.violation)??[];p.push(u),l.set(u.violation,p)}for(let[u,p]of l){console.log(c.warn(` ${u} (${p.length})`));for(let m of p.slice(0,10))console.log(` ${m.session_id.slice(0,8)} ${c.dim("\u2192")} ${JSON.stringify(m.alias)}`);p.length>10&&console.log(c.dim(` \u2026 and ${p.length-10} more (rerun with --json for the full list)`)),console.log("")}return console.log(c.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}v();w();P();import{existsSync as iy,readFileSync as ay}from"node:fs";import{join as cy}from"node:path";function ly(){let e=cy(x,"daemon.pid");if(!iy(e))return!1;try{let t=parseInt(ay(e,"utf-8").trim(),10);return!Number.isFinite(t)||t<=0?!1:(process.kill(t,0),!0)}catch{return!1}}async function cs(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 zl(e={}){let t=_(),s=[];if(e.vacuum&&ly())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)+`
1519
1516
  `),2):(console.error(c.err("\u2717 VACUUM requires the daemon to be stopped. Run `recall stop` first, then re-run with --vacuum.")),2);s.push(await cs("wal_checkpoint(TRUNCATE)",()=>{t.pragma("wal_checkpoint(TRUNCATE)")})),s.push(await cs("messages_fts optimize",()=>{t.exec("INSERT INTO messages_fts(messages_fts) VALUES('optimize');")})),s.push(await cs("sessions_fts optimize",()=>{t.exec("INSERT INTO sessions_fts(sessions_fts) VALUES('optimize');")})),s.push(await cs("PRAGMA optimize",()=>{t.exec("PRAGMA optimize")})),e.vacuum&&s.push(await cs("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)+`
1520
- `),n.length===0?0:1;for(let r of s){let o=r.ok?c.ok("\u2713"):c.err("\u2717"),i=`${r.durationMs} ms`;console.log(` ${o} ${r.step.padEnd(28)} ${c.dim(i)}`),r.error&&console.log(` ${c.err(r.error)}`)}return n.length===0?(console.log(""),console.log(c.ok("All maintenance passes completed.")),e.vacuum||console.log(c.dim(" Run `recall optimize --vacuum` (with the daemon stopped) to reclaim disk pages from deleted rows.")),0):(console.log(""),console.log(c.warn(`${n.length} step(s) failed \u2014 review the errors above.`)),1)}v();w();D();import{copyFileSync as ey,existsSync as ty,readFileSync as sy}from"node:fs";import{join as Yl}from"node:path";function ny(){let e=Yl(x,"daemon.pid");if(!ty(e))return!1;try{let t=parseInt(sy(e,"utf-8").trim(),10);return!Number.isFinite(t)||t<=0?!1:(process.kill(t,0),!0)}catch{return!1}}function ry(){let e=[];for(let t of Nt){let r=t.source.replace(/^\^/,"").replace(/\\d\+/g,"").match(/^([^.*+?{[(\\]+)/)?.[1]??"";r.length>=8&&e.push(r.replace(/'/g,"''"))}return e.length===0?"0":e.map(t=>`first_user_message LIKE '${t}%'`).join(" OR ")}async function Gl(e={}){if(ny()&&!e.dryRun){let m="Daemon is running. Run `recall stop`, then `recall purge-phantoms`, then `recall start`. The purge needs an exclusive write lock and the daemon would race it.";return e.json?(process.stdout.write(JSON.stringify({ok:!1,reason:"daemon-running",message:m},null,2)+`
1521
- `),2):(console.error(c.err(`\u2717 ${m}`)),2)}let t=ry();if(t==="0"){let m="No phantom patterns are registered \u2014 nothing to purge.";return e.json?(process.stdout.write(JSON.stringify({ok:!0,reason:"no-patterns",message:m})+`
1517
+ `),n.length===0?0:1;for(let r of s){let o=r.ok?c.ok("\u2713"):c.err("\u2717"),i=`${r.durationMs} ms`;console.log(` ${o} ${r.step.padEnd(28)} ${c.dim(i)}`),r.error&&console.log(` ${c.err(r.error)}`)}return n.length===0?(console.log(""),console.log(c.ok("All maintenance passes completed.")),e.vacuum||console.log(c.dim(" Run `recall optimize --vacuum` (with the daemon stopped) to reclaim disk pages from deleted rows.")),0):(console.log(""),console.log(c.warn(`${n.length} step(s) failed \u2014 review the errors above.`)),1)}v();w();P();import{copyFileSync as dy,existsSync as uy,readFileSync as py}from"node:fs";import{join as ql}from"node:path";function my(){let e=ql(x,"daemon.pid");if(!uy(e))return!1;try{let t=parseInt(py(e,"utf-8").trim(),10);return!Number.isFinite(t)||t<=0?!1:(process.kill(t,0),!0)}catch{return!1}}function gy(){let e=[];for(let t of Nt){let r=t.source.replace(/^\^/,"").replace(/\\d\+/g,"").match(/^([^.*+?{[(\\]+)/)?.[1]??"";r.length>=8&&e.push(r.replace(/'/g,"''"))}return e.length===0?"0":e.map(t=>`first_user_message LIKE '${t}%'`).join(" OR ")}async function Kl(e={}){if(my()&&!e.dryRun){let m="Daemon is running. Run `recall stop`, then `recall purge-phantoms`, then `recall start`. The purge needs an exclusive write lock and the daemon would race it.";return e.json?(process.stdout.write(JSON.stringify({ok:!1,reason:"daemon-running",message:m},null,2)+`
1518
+ `),2):(console.error(c.err(`\u2717 ${m}`)),2)}let t=gy();if(t==="0"){let m="No phantom patterns are registered \u2014 nothing to purge.";return e.json?(process.stdout.write(JSON.stringify({ok:!0,reason:"no-patterns",message:m})+`
1522
1519
  `),0):(console.log(c.warn(m)),0)}let s=_(),n=s.prepare(`SELECT COUNT(*) AS n FROM sessions WHERE ${t}`).get().n;if(n===0){let m="No phantom sessions found. Your DB is clean.";return e.json?(process.stdout.write(JSON.stringify({ok:!0,sessionsBefore:0,sessionsAfter:0,messagesDeleted:0,aliasesDeleted:0,patternsApplied:Nt.length,vacuumHint:!1,dryRun:!!e.dryRun},null,2)+`
1523
1520
  `),0):(console.log(c.ok(`\u2713 ${m}`)),0)}let r=s.prepare(`SELECT COUNT(*) AS n FROM messages WHERE session_id IN (SELECT id FROM sessions WHERE ${t})`).get().n,o=s.prepare(`SELECT COUNT(*) AS n FROM session_aliases WHERE session_id IN (SELECT id FROM sessions WHERE ${t})`).get().n;if(e.dryRun){let m={ok:!0,sessionsBefore:n,sessionsAfter:n,messagesDeleted:r,aliasesDeleted:o,patternsApplied:Nt.length,vacuumHint:!1,dryRun:!0};return e.json?(process.stdout.write(JSON.stringify(m,null,2)+`
1524
- `),0):(console.log(c.warn("\u2014 dry run, no changes \u2014")),console.log(` Phantoms found: ${c.dim(String(n))} sessions`),console.log(` Messages cascaded: ${c.dim(String(r))}`),console.log(` Aliases cascaded: ${c.dim(String(o))}`),console.log(c.dim(" Re-run without --dry-run to actually delete.")),0)}let i=Yl(x,"db.sqlite"),a=new Date().toISOString().replace(/[-:T]/g,"").replace(/\..+$/,"").slice(0,15),d=`${i}.pre-phantom-purge-${a}`;ey(i,d),s.pragma("foreign_keys = ON"),s.transaction(()=>{s.exec(`DELETE FROM sessions WHERE ${t}`)})();let u=s.prepare(`SELECT COUNT(*) AS n FROM sessions WHERE ${t}`).get().n,p={ok:u===0,backupPath:d,sessionsBefore:n,sessionsAfter:u,messagesDeleted:r,aliasesDeleted:o,patternsApplied:Nt.length,vacuumHint:n>100,dryRun:!1};return e.json?(process.stdout.write(JSON.stringify(p,null,2)+`
1525
- `),p.ok?0:1):(console.log(c.ok(`\u2713 Purged ${n} phantom session(s).`)),console.log(` Cascaded ${r} message(s) and ${o} alias row(s).`),console.log(` Backup: ${c.dim(d)}`),console.log(` Patterns applied: ${c.dim(String(Nt.length))}`),console.log(""),console.log(u===0?c.ok("All known phantom patterns are clear."):c.warn(`${u} phantom row(s) remain after purge \u2014 investigate.`)),p.vacuumHint&&(console.log(""),console.log(c.dim(" Reclaim the disk pages with `recall optimize --vacuum` (daemon must stay stopped)."))),console.log(c.dim(" Restart with `recall start` when ready.")),p.ok?0:1)}v();w();D();w();import{existsSync as oy}from"node:fs";import{join as iy}from"node:path";var on=iy(x,"archive.sqlite");var zl=!1;function Kl(){if(zl&&oy(on))return;P();let e=_(),t=on.replace(/'/g,"''");e.exec(`ATTACH DATABASE '${t}' AS archive`);try{e.exec(`
1521
+ `),0):(console.log(c.warn("\u2014 dry run, no changes \u2014")),console.log(` Phantoms found: ${c.dim(String(n))} sessions`),console.log(` Messages cascaded: ${c.dim(String(r))}`),console.log(` Aliases cascaded: ${c.dim(String(o))}`),console.log(c.dim(" Re-run without --dry-run to actually delete.")),0)}let i=ql(x,"db.sqlite"),a=new Date().toISOString().replace(/[-:T]/g,"").replace(/\..+$/,"").slice(0,15),d=`${i}.pre-phantom-purge-${a}`;dy(i,d),s.pragma("foreign_keys = ON"),s.transaction(()=>{s.exec(`DELETE FROM sessions WHERE ${t}`)})();let u=s.prepare(`SELECT COUNT(*) AS n FROM sessions WHERE ${t}`).get().n,p={ok:u===0,backupPath:d,sessionsBefore:n,sessionsAfter:u,messagesDeleted:r,aliasesDeleted:o,patternsApplied:Nt.length,vacuumHint:n>100,dryRun:!1};return e.json?(process.stdout.write(JSON.stringify(p,null,2)+`
1522
+ `),p.ok?0:1):(console.log(c.ok(`\u2713 Purged ${n} phantom session(s).`)),console.log(` Cascaded ${r} message(s) and ${o} alias row(s).`),console.log(` Backup: ${c.dim(d)}`),console.log(` Patterns applied: ${c.dim(String(Nt.length))}`),console.log(""),console.log(u===0?c.ok("All known phantom patterns are clear."):c.warn(`${u} phantom row(s) remain after purge \u2014 investigate.`)),p.vacuumHint&&(console.log(""),console.log(c.dim(" Reclaim the disk pages with `recall optimize --vacuum` (daemon must stay stopped)."))),console.log(c.dim(" Restart with `recall start` when ready.")),p.ok?0:1)}v();w();P();w();import{existsSync as fy}from"node:fs";import{join as _y}from"node:path";var cn=_y(x,"archive.sqlite");var Vl=!1;function Zl(){if(Vl&&fy(cn))return;F();let e=_(),t=cn.replace(/'/g,"''");e.exec(`ATTACH DATABASE '${t}' AS archive`);try{e.exec(`
1526
1523
  CREATE TABLE IF NOT EXISTS archive.messages_archive (
1527
1524
  uuid TEXT PRIMARY KEY,
1528
1525
  session_id TEXT NOT NULL,
@@ -1537,7 +1534,7 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1537
1534
  archived_at TEXT NOT NULL DEFAULT (datetime('now'))
1538
1535
  );
1539
1536
  CREATE INDEX IF NOT EXISTS archive.idx_messages_archive_session ON messages_archive(session_id);
1540
- `)}finally{e.exec("DETACH DATABASE archive")}zl=!0}import{existsSync as ql,mkdirSync as ay,readFileSync as cy,writeFileSync as ly}from"node:fs";import{homedir as dy}from"node:os";import{join as Vl}from"node:path";import{z as an}from"zod";function Zl(){return process.env.RECALL_HOME??Vl(dy(),".recall")}function uy(){let e=Zl();ql(e)||ay(e,{recursive:!0})}function Ql(){return Vl(Zl(),"config.json")}var ed=an.object({autoArchiveEnabled:an.boolean().default(!1),autoArchiveAfterDays:an.number().int().min(7).max(3650).default(90),lastRunAt:an.string().nullable().default(null)}),cn={autoArchiveEnabled:!1,autoArchiveAfterDays:90,lastRunAt:null};function td(){let e=Ql();if(!ql(e))return{};try{return JSON.parse(cy(e,"utf8"))}catch(t){let s=t instanceof Error?t.message:String(t);return console.error(`[retention-config] failed to parse config.json: ${s}`),{}}}function sd(){let e=td().retention;if(!e)return{...cn};let t=ed.safeParse({...cn,...e});return t.success?t.data:{...cn}}function go(e){uy();let t=td(),s=ed.parse({...cn,...t.retention??{},...e}),n={...t,retention:s};return ly(Ql(),JSON.stringify(n,null,2)),s}function fo(e){Kl();let t=_(),s=on.replace(/'/g,"''");t.exec(`ATTACH DATABASE '${s}' AS archive`);try{return e(t)}finally{t.exec("DETACH DATABASE archive")}}function py(){return fo(e=>{let t=e.prepare(`SELECT
1537
+ `)}finally{e.exec("DETACH DATABASE archive")}Vl=!0}import{existsSync as Ql,mkdirSync as hy,readFileSync as Ey,writeFileSync as by}from"node:fs";import{homedir as Sy}from"node:os";import{join as ed}from"node:path";import{z as ln}from"zod";function td(){return process.env.RECALL_HOME??ed(Sy(),".recall")}function yy(){let e=td();Ql(e)||hy(e,{recursive:!0})}function sd(){return ed(td(),"config.json")}var nd=ln.object({autoArchiveEnabled:ln.boolean().default(!1),autoArchiveAfterDays:ln.number().int().min(7).max(3650).default(90),lastRunAt:ln.string().nullable().default(null)}),dn={autoArchiveEnabled:!1,autoArchiveAfterDays:90,lastRunAt:null};function rd(){let e=sd();if(!Ql(e))return{};try{return JSON.parse(Ey(e,"utf8"))}catch(t){let s=t instanceof Error?t.message:String(t);return console.error(`[retention-config] failed to parse config.json: ${s}`),{}}}function od(){let e=rd().retention;if(!e)return{...dn};let t=nd.safeParse({...dn,...e});return t.success?t.data:{...dn}}function _o(e){yy();let t=rd(),s=nd.parse({...dn,...t.retention??{},...e}),n={...t,retention:s};return by(sd(),JSON.stringify(n,null,2)),s}function ho(e){Zl();let t=_(),s=cn.replace(/'/g,"''");t.exec(`ATTACH DATABASE '${s}' AS archive`);try{return e(t)}finally{t.exec("DETACH DATABASE archive")}}function wy(){return ho(e=>{let t=e.prepare(`SELECT
1541
1538
  SUM(CASE WHEN archive_status = 'archived' THEN 1 ELSE 0 END) AS archived,
1542
1539
  SUM(CASE WHEN archive_status != 'archived' THEN 1 ELSE 0 END) AS live
1543
1540
  FROM sessions`).get(),s=e.prepare("SELECT COUNT(*) AS n FROM messages").get().n,n=e.prepare(`SELECT
@@ -1546,15 +1543,15 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1546
1543
  SELECT MAX(timestamp) AS t FROM main.messages_archive WHERE timestamp IS NOT NULL
1547
1544
  UNION ALL
1548
1545
  SELECT MAX(timestamp) AS t FROM archive.messages_archive WHERE timestamp IS NOT NULL
1549
- )`).get();return{liveSessions:t.live??0,archivedSessions:t.archived??0,liveMessages:s,archivedMessages:n,oldestLiveTimestamp:r.t,newestArchivedTimestamp:o.t}})}function nd(e){return e?e.slice(0,10):"\u2014"}function my(){let e=py();return console.log(c.dim("\u2014 Archive state \u2014")),console.log(` Live sessions ${e.liveSessions.toLocaleString()}`),console.log(` Archived sessions ${e.archivedSessions.toLocaleString()}`),console.log(` Live messages ${e.liveMessages.toLocaleString()}`),console.log(` Archived messages ${e.archivedMessages.toLocaleString()}`),console.log(` Oldest live ${nd(e.oldestLiveTimestamp)}`),console.log(` Newest archived ${nd(e.newestArchivedTimestamp)}`),console.log(""),console.log(c.dim(" recall archive run --before YYYY-MM-DD")),console.log(c.dim(" recall archive restore <session-id>")),0}function gy(e){if(!/^\d{4}-\d{2}-\d{2}$/.test(e.before))return console.error("--before must be YYYY-MM-DD"),1;let s=_().prepare(`SELECT s.id, s.ended_at, s.message_count
1546
+ )`).get();return{liveSessions:t.live??0,archivedSessions:t.archived??0,liveMessages:s,archivedMessages:n,oldestLiveTimestamp:r.t,newestArchivedTimestamp:o.t}})}function id(e){return e?e.slice(0,10):"\u2014"}function Ty(){let e=wy();return console.log(c.dim("\u2014 Archive state \u2014")),console.log(` Live sessions ${e.liveSessions.toLocaleString()}`),console.log(` Archived sessions ${e.archivedSessions.toLocaleString()}`),console.log(` Live messages ${e.liveMessages.toLocaleString()}`),console.log(` Archived messages ${e.archivedMessages.toLocaleString()}`),console.log(` Oldest live ${id(e.oldestLiveTimestamp)}`),console.log(` Newest archived ${id(e.newestArchivedTimestamp)}`),console.log(""),console.log(c.dim(" recall archive run --before YYYY-MM-DD")),console.log(c.dim(" recall archive restore <session-id>")),0}function Ry(e){if(!/^\d{4}-\d{2}-\d{2}$/.test(e.before))return console.error("--before must be YYYY-MM-DD"),1;let s=_().prepare(`SELECT s.id, s.ended_at, s.message_count
1550
1547
  FROM sessions s
1551
1548
  WHERE s.archive_status != 'archived'
1552
- AND COALESCE(s.ended_at, s.started_at) < ?`).all(`${e.before}T00:00:00.000Z`);if(s.length===0)return console.log(`No sessions to archive (none older than ${e.before}).`),0;let n=s.reduce((a,d)=>a+(d.message_count??0),0);if(console.log(`${s.length.toLocaleString()} session(s), ${n.toLocaleString()} message(s) eligible.`),e.dryRun)return console.log(c.dim("Dry run \u2014 no rows moved. Re-run without --dry-run to apply.")),0;let r=s.map(a=>a.id),o=Date.now(),i=fo(a=>a.transaction(l=>{let u=0,p=a.prepare(`INSERT OR IGNORE INTO archive.messages_archive
1549
+ AND COALESCE(s.ended_at, s.started_at) < ?`).all(`${e.before}T00:00:00.000Z`);if(s.length===0)return console.log(`No sessions to archive (none older than ${e.before}).`),0;let n=s.reduce((a,d)=>a+(d.message_count??0),0);if(console.log(`${s.length.toLocaleString()} session(s), ${n.toLocaleString()} message(s) eligible.`),e.dryRun)return console.log(c.dim("Dry run \u2014 no rows moved. Re-run without --dry-run to apply.")),0;let r=s.map(a=>a.id),o=Date.now(),i=ho(a=>a.transaction(l=>{let u=0,p=a.prepare(`INSERT OR IGNORE INTO archive.messages_archive
1553
1550
  (uuid, session_id, parent_uuid, type, role, timestamp,
1554
1551
  is_sidechain, content_text, tool_names, raw_json, archived_at)
1555
1552
  SELECT uuid, session_id, parent_uuid, type, role, timestamp,
1556
1553
  is_sidechain, content_text, tool_names, raw_json, datetime('now')
1557
- FROM messages WHERE session_id = ?`),m=a.prepare("DELETE FROM messages WHERE session_id = ?"),g=a.prepare("UPDATE sessions SET archive_status = 'archived', archived_at = datetime('now') WHERE id = ?");for(let f of l){p.run(f);let h=m.run(f);u+=Number(h.changes??0),g.run(f)}return u})(r));return console.log(`Archived ${s.length.toLocaleString()} session(s), moved ${i.toLocaleString()} message(s) in ${Date.now()-o}ms.`),console.log(c.dim(" Run `recall optimize --vacuum` (with the daemon stopped) to reclaim disk pages from the moved rows.")),0}function fy(e){if(!e)return console.error("Usage: recall archive restore <session-id>"),1;let s=_().prepare("SELECT id, archive_status FROM sessions WHERE id = ?").get(e);if(!s)return console.error(`Session ${e} not found.`),1;if(s.archive_status!=="archived")return console.error(`Session ${e} is not archived (status=${s.archive_status}).`),1;let n=fo(r=>r.transaction(()=>{let i=r.prepare(`INSERT OR IGNORE INTO messages
1554
+ FROM messages WHERE session_id = ?`),m=a.prepare("DELETE FROM messages WHERE session_id = ?"),g=a.prepare("UPDATE sessions SET archive_status = 'archived', archived_at = datetime('now') WHERE id = ?");for(let f of l){p.run(f);let h=m.run(f);u+=Number(h.changes??0),g.run(f)}return u})(r));return console.log(`Archived ${s.length.toLocaleString()} session(s), moved ${i.toLocaleString()} message(s) in ${Date.now()-o}ms.`),console.log(c.dim(" Run `recall optimize --vacuum` (with the daemon stopped) to reclaim disk pages from the moved rows.")),0}function xy(e){if(!e)return console.error("Usage: recall archive restore <session-id>"),1;let s=_().prepare("SELECT id, archive_status FROM sessions WHERE id = ?").get(e);if(!s)return console.error(`Session ${e} not found.`),1;if(s.archive_status!=="archived")return console.error(`Session ${e} is not archived (status=${s.archive_status}).`),1;let n=ho(r=>r.transaction(()=>{let i=r.prepare(`INSERT OR IGNORE INTO messages
1558
1555
  (uuid, session_id, parent_uuid, type, role, timestamp,
1559
1556
  is_sidechain, content_text, tool_names, raw_json)
1560
1557
  SELECT uuid, session_id, parent_uuid, type, role, timestamp,
@@ -1564,33 +1561,33 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1564
1561
  is_sidechain, content_text, tool_names, raw_json)
1565
1562
  SELECT uuid, session_id, parent_uuid, type, role, timestamp,
1566
1563
  is_sidechain, content_text, tool_names, raw_json
1567
- FROM archive.messages_archive WHERE session_id = ?`),d=r.prepare("DELETE FROM main.messages_archive WHERE session_id = ?"),l=r.prepare("DELETE FROM archive.messages_archive WHERE session_id = ?"),u=Number(i.run(e).changes??0),p=Number(a.run(e).changes??0);return d.run(e),l.run(e),r.prepare("UPDATE sessions SET archive_status = 'live', archived_at = NULL WHERE id = ?").run(e),u+p})());return console.log(`Restored ${n.toLocaleString()} message(s) for session ${e}.`),0}function _y(){let e=sd();return console.log(c.dim("\u2014 Auto-archive \u2014")),console.log(` Enabled ${e.autoArchiveEnabled?c.ok("YES"):"no"}`),console.log(` After ${e.autoArchiveAfterDays} days`),console.log(` Last run ${e.lastRunAt??"\u2014"}`),0}function hy(e){if(e===void 0||!Number.isFinite(e))return console.error("Usage: recall archive auto on --after <days>"),1;let t=Math.floor(e);if(t<7||t>3650)return console.error("--after must be between 7 and 3650 days"),1;let s=go({autoArchiveEnabled:!0,autoArchiveAfterDays:t});return console.log(`Auto-archive: ENABLED (after ${s.autoArchiveAfterDays} days).`),console.log(c.dim(" The daemon will run a daily archive pass on the next tick.")),0}function Ey(){return go({autoArchiveEnabled:!1}),console.log("Auto-archive: DISABLED. Existing archived sessions stay archived."),0}async function rd(e){let t=e._action??"list";if(t==="list"||t==="stats")return my();if(t==="run")return e.before?gy({before:e.before,dryRun:e.dryRun===!0}):(console.error("Usage: recall archive run --before YYYY-MM-DD [--dry-run]"),1);if(t==="restore")return fy(e._sessionId??"");if(t==="auto"){let s=e._subAction??"status";return s==="status"?_y():s==="on"||s==="enable"?hy(e.after):s==="off"||s==="disable"?Ey():(console.error("Usage: recall archive auto <status|on|off> [--after <days>]"),1)}return console.error(`Usage: recall archive <list|run|restore|auto> [args]
1564
+ FROM archive.messages_archive WHERE session_id = ?`),d=r.prepare("DELETE FROM main.messages_archive WHERE session_id = ?"),l=r.prepare("DELETE FROM archive.messages_archive WHERE session_id = ?"),u=Number(i.run(e).changes??0),p=Number(a.run(e).changes??0);return d.run(e),l.run(e),r.prepare("UPDATE sessions SET archive_status = 'live', archived_at = NULL WHERE id = ?").run(e),u+p})());return console.log(`Restored ${n.toLocaleString()} message(s) for session ${e}.`),0}function ky(){let e=od();return console.log(c.dim("\u2014 Auto-archive \u2014")),console.log(` Enabled ${e.autoArchiveEnabled?c.ok("YES"):"no"}`),console.log(` After ${e.autoArchiveAfterDays} days`),console.log(` Last run ${e.lastRunAt??"\u2014"}`),0}function Cy(e){if(e===void 0||!Number.isFinite(e))return console.error("Usage: recall archive auto on --after <days>"),1;let t=Math.floor(e);if(t<7||t>3650)return console.error("--after must be between 7 and 3650 days"),1;let s=_o({autoArchiveEnabled:!0,autoArchiveAfterDays:t});return console.log(`Auto-archive: ENABLED (after ${s.autoArchiveAfterDays} days).`),console.log(c.dim(" The daemon will run a daily archive pass on the next tick.")),0}function Ly(){return _o({autoArchiveEnabled:!1}),console.log("Auto-archive: DISABLED. Existing archived sessions stay archived."),0}async function ad(e){let t=e._action??"list";if(t==="list"||t==="stats")return Ty();if(t==="run")return e.before?Ry({before:e.before,dryRun:e.dryRun===!0}):(console.error("Usage: recall archive run --before YYYY-MM-DD [--dry-run]"),1);if(t==="restore")return xy(e._sessionId??"");if(t==="auto"){let s=e._subAction??"status";return s==="status"?ky():s==="on"||s==="enable"?Cy(e.after):s==="off"||s==="disable"?Ly():(console.error("Usage: recall archive auto <status|on|off> [--after <days>]"),1)}return console.error(`Usage: recall archive <list|run|restore|auto> [args]
1568
1565
  list \u2014 show archive counts
1569
1566
  run --before YYYY-MM-DD [--dry-run] \u2014 move sessions older than DATE
1570
1567
  restore <session-id> \u2014 pull a session back from archive
1571
- auto <status|on|off> [--after N] \u2014 daemon auto-archives sessions older than N days`),1}v();w();D();import{existsSync as by,readFileSync as Sy}from"node:fs";function yy(){let e=`${x}/daemon.port`;if(!by(e))return null;try{let t=Sy(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}function wy(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}
1568
+ auto <status|on|off> [--after N] \u2014 daemon auto-archives sessions older than N days`),1}v();w();P();import{existsSync as Ny,readFileSync as Ay}from"node:fs";function Oy(){let e=`${x}/daemon.port`;if(!Ny(e))return null;try{let t=Ay(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}function vy(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}
1572
1569
  `),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}"
1573
1570
  `),null):(process.stderr.write(`ambiguous session prefix "${e}". be more specific.
1574
- `),null)}async function od(e,t,s){let n=wy(e);if(!n){process.exitCode=1;return}let r=t.trim();if(!r){process.stderr.write(`name cannot be empty
1575
- `),process.exitCode=1;return}let o=yy();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(d){process.stderr.write(`failed to reach daemon at 127.0.0.1:${o}: ${d.message}
1571
+ `),null)}async function cd(e,t,s){let n=vy(e);if(!n){process.exitCode=1;return}let r=t.trim();if(!r){process.stderr.write(`name cannot be empty
1572
+ `),process.exitCode=1;return}let o=Oy();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 st("PUT",`http://127.0.0.1:${o}/api/sessions/${encodeURIComponent(n)}/alias`,{alias:r,pin:s.pin===!0})}catch(d){process.stderr.write(`failed to reach daemon at 127.0.0.1:${o}: ${d.message}
1576
1573
  `),process.exitCode=1;return}if(!i.ok){let d="";try{d=await i.text()}catch{}process.stderr.write(`daemon rejected alias write (HTTP ${i.status}): ${d}
1577
- `),process.exitCode=1;return}let a={session_id:n,alias:r};if(s.json){console.log(JSON.stringify(a));return}console.log(`${c.ok("renamed")} ${c.dim(n.slice(0,8))} \u2192 ${c.bold(`"${r}"`)}`)}v();w();var cd=90;async function Ty(){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 ze(`http://127.0.0.1:${s}/api/terminal/registry`);return n.ok?await n.json():null}catch{return null}}function Ry(){let e=Date.now()/1e3-cd;return _().prepare(`SELECT s.id, s.cwd, s.file_mtime, NULLIF(sa.alias, '') AS alias
1574
+ `),process.exitCode=1;return}let a={session_id:n,alias:r};if(s.json){console.log(JSON.stringify(a));return}console.log(`${c.ok("renamed")} ${c.dim(n.slice(0,8))} \u2192 ${c.bold(`"${r}"`)}`)}v();w();var ud=90;async function Iy(){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 ze(`http://127.0.0.1:${s}/api/terminal/registry`);return n.ok?await n.json():null}catch{return null}}function My(){let e=Date.now()/1e3-ud;return _().prepare(`SELECT s.id, s.cwd, s.file_mtime, NULLIF(sa.alias, '') AS alias
1578
1575
  FROM sessions s
1579
1576
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1580
1577
  WHERE s.cwd IS NOT NULL AND s.file_mtime > ?
1581
- ORDER BY s.cwd, s.file_mtime DESC`).all(e)}var xy=new Set(["zsh","bash","fish","sh","dash","ksh","tcsh","csh","pwsh","powershell","cmd","nu"]);function id(e){let t=e.trim().toLowerCase().replace(/^[-/]+/,"").replace(/^.*\//,"").replace(/\s*\(\d+\)\s*$/,"").trim();return!t||xy.has(t)}var ky=/^[⠀-⣿✳\s]+/,Cy=/^\d+(\.\d+){1,3}$/;function ad(e){let t=e.trim();return!!(!t||ky.test(t)||Cy.test(t))}async function ld(e){let t=await Ty(),s=Ry();if(e.json){console.log(JSON.stringify({registry:t,active:s},null,2));return}if(console.log(),console.log(c.bold("TERMINAL REGISTRY")),console.log(c.dim("(what the daemon thinks each VS Code terminal is named)")),console.log(),!t){console.log(c.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(c.dim(` cwd: ${o}`));for(let a of i){let d=id(a.tab_name),l=ad(a.tab_name),p=!d&&!l?c.ok("[usable]"):d?c.warn("[generic-shell]"):c.warn("[claude-auto]");console.log(` ${p} pid ${a.shell_pid} ${c.bold(`"${a.tab_name}"`)}`)}console.log()}if(console.log(c.bold(`ACTIVE SESSIONS (mtime within last ${cd}s)`)),console.log(c.dim("(sessions whose JSONL is being actively written)")),console.log(),s.length===0){console.log(c.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(c.dim(` cwd: ${o}`));for(let a of i)console.log(` ${c.dim(a.id.slice(0,8))} ${c.bold(a.alias??"(no alias)")} ${c.dim(`mtime ${new Date(a.file_mtime*1e3).toISOString().slice(11,19)}`)}`);console.log()}console.log(c.bold("LAYER 5 SWEEP DECISIONS")),console.log(c.dim("(what the live correlator would do for each cwd right now)")),console.log();for(let[o,i]of r){let d=(n.get(o)??[]).filter(l=>!id(l.tab_name)&&!ad(l.tab_name));d.length===0?console.log(` ${c.warn("skip")} ${c.dim(o)} ${c.dim("\u2014 no usable terminal name (all generic or claude-auto)")}`):d.length>1?console.log(` ${c.warn("refuse")} ${c.dim(o)} ${c.dim(`\u2014 ${d.length} usable terminals, ambiguous`)}`):i.length>1?console.log(` ${c.warn("refuse")} ${c.dim(o)} ${c.dim(`\u2014 ${i.length} active sessions, ambiguous`)}`):console.log(` ${c.ok("link")} ${c.dim(o)} ${c.dim("\u2192")} ${c.dim(i[0].id.slice(0,8))} ${c.dim("=")} ${c.bold(`"${d[0].tab_name}"`)}`)}console.log()}v();w();D();import{existsSync as Ly,readFileSync as Ny}from"node:fs";function Ay(){let e=`${x}/daemon.port`;if(!Ly(e))return null;try{let t=Ny(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function Oy(e){try{let t=await ze(`http://127.0.0.1:${e}/api/terminal/registry`);return t.ok?(await t.json()).terminals??[]:[]}catch{return[]}}async function vy(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 Iy(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 My(e){let t=new Map;for(let i of e){if(!i.cwd)continue;let a=i.cwd.replace(/\/+$/,""),d=t.get(a);d||(d=new Map,t.set(a,d)),d.set(i.tab_name,i.shell_pid)}let s=new Map;for(let i of e){if(!i.cwd)continue;let d=`${i.cwd.replace(/\/+$/,"")}::${i.tab_name}`,l=s.get(d);l||(l=new Set,s.set(d,l)),l.add(String(i.shell_pid))}let r=_().prepare(`SELECT sa.session_id, s.cwd, sa.previous_aliases
1578
+ ORDER BY s.cwd, s.file_mtime DESC`).all(e)}var Dy=new Set(["zsh","bash","fish","sh","dash","ksh","tcsh","csh","pwsh","powershell","cmd","nu"]);function ld(e){let t=e.trim().toLowerCase().replace(/^[-/]+/,"").replace(/^.*\//,"").replace(/\s*\(\d+\)\s*$/,"").trim();return!t||Dy.has(t)}var $y=/^[⠀-⣿✳\s]+/,Py=/^\d+(\.\d+){1,3}$/;function dd(e){let t=e.trim();return!!(!t||$y.test(t)||Py.test(t))}async function pd(e){let t=await Iy(),s=My();if(e.json){console.log(JSON.stringify({registry:t,active:s},null,2));return}if(console.log(),console.log(c.bold("TERMINAL REGISTRY")),console.log(c.dim("(what the daemon thinks each VS Code terminal is named)")),console.log(),!t){console.log(c.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(c.dim(` cwd: ${o}`));for(let a of i){let d=ld(a.tab_name),l=dd(a.tab_name),p=!d&&!l?c.ok("[usable]"):d?c.warn("[generic-shell]"):c.warn("[claude-auto]");console.log(` ${p} pid ${a.shell_pid} ${c.bold(`"${a.tab_name}"`)}`)}console.log()}if(console.log(c.bold(`ACTIVE SESSIONS (mtime within last ${ud}s)`)),console.log(c.dim("(sessions whose JSONL is being actively written)")),console.log(),s.length===0){console.log(c.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(c.dim(` cwd: ${o}`));for(let a of i)console.log(` ${c.dim(a.id.slice(0,8))} ${c.bold(a.alias??"(no alias)")} ${c.dim(`mtime ${new Date(a.file_mtime*1e3).toISOString().slice(11,19)}`)}`);console.log()}console.log(c.bold("LAYER 5 SWEEP DECISIONS")),console.log(c.dim("(what the live correlator would do for each cwd right now)")),console.log();for(let[o,i]of r){let d=(n.get(o)??[]).filter(l=>!ld(l.tab_name)&&!dd(l.tab_name));d.length===0?console.log(` ${c.warn("skip")} ${c.dim(o)} ${c.dim("\u2014 no usable terminal name (all generic or claude-auto)")}`):d.length>1?console.log(` ${c.warn("refuse")} ${c.dim(o)} ${c.dim(`\u2014 ${d.length} usable terminals, ambiguous`)}`):i.length>1?console.log(` ${c.warn("refuse")} ${c.dim(o)} ${c.dim(`\u2014 ${i.length} active sessions, ambiguous`)}`):console.log(` ${c.ok("link")} ${c.dim(o)} ${c.dim("\u2192")} ${c.dim(i[0].id.slice(0,8))} ${c.dim("=")} ${c.bold(`"${d[0].tab_name}"`)}`)}console.log()}v();w();P();import{existsSync as Fy,readFileSync as jy}from"node:fs";function Uy(){let e=`${x}/daemon.port`;if(!Fy(e))return null;try{let t=jy(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function By(e){try{let t=await ze(`http://127.0.0.1:${e}/api/terminal/registry`);return t.ok?(await t.json()).terminals??[]:[]}catch{return[]}}async function Hy(e,t,s){try{return(await st("POST",`http://127.0.0.1:${e}/api/sessions/${encodeURIComponent(t)}/relink`,{shell_pid:s})).ok}catch{return!1}}function Wy(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 Xy(e){let t=new Map;for(let i of e){if(!i.cwd)continue;let a=i.cwd.replace(/\/+$/,""),d=t.get(a);d||(d=new Map,t.set(a,d)),d.set(i.tab_name,i.shell_pid)}let s=new Map;for(let i of e){if(!i.cwd)continue;let d=`${i.cwd.replace(/\/+$/,"")}::${i.tab_name}`,l=s.get(d);l||(l=new Set,s.set(d,l)),l.add(String(i.shell_pid))}let r=_().prepare(`SELECT sa.session_id, s.cwd, sa.previous_aliases
1582
1579
  FROM session_aliases sa
1583
1580
  JOIN sessions s ON s.id = sa.session_id
1584
- WHERE sa.alias = '' AND sa.previous_aliases != '[]' AND s.cwd IS NOT NULL`).all(),o=[];for(let i of r){let a=Iy(i.previous_aliases);if(!a)continue;let d=i.cwd.replace(/\/+$/,""),u=t.get(d)?.get(a);if(!u)continue;let p=s.get(`${d}::${a}`);p&&p.size>1||o.push({session_id:i.session_id,cwd:d,alias_to_restore:a,matching_pid:u})}return o}async function dd(e){let t=Ay();t||(console.error(c.err("Daemon is not running. Run `recall start` first.")),process.exit(1));let s=await Oy(t);s.length===0&&(console.error(c.err("Registry is empty. Open VS Code with the extension to populate it.")),process.exit(1));let n=My(s);if(e.json){console.log(JSON.stringify({candidates:n},null,2));return}if(n.length===0){console.log(c.dim("No restorable sessions found.")),console.log(c.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(c.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 d=r.get(a.cwd);d||(d=[],r.set(a.cwd,d)),d.push(a)}for(let[a,d]of r){console.log(c.dim(` cwd: ${a}`));for(let l of d)console.log(` ${c.dim(l.session_id.slice(0,8))} ${c.dim("\u2192 pid")} ${l.matching_pid} ${c.dim("=")} ${c.bold(`"${l.alias_to_restore}"`)}`);console.log()}if(!e.apply){console.log(c.dim("Re-run with --apply to restore these aliases."));return}let o=0,i=0;for(let a of n)await vy(t,a.session_id,a.matching_pid)?o++:(i++,console.error(c.err(`failed to restore ${a.session_id.slice(0,8)}`)));console.log(c.ok(`Restored ${o} alias${o===1?"":"es"}.${i>0?` ${i} failed.`:""}`)),console.log(c.dim("Sessions whose previous alias did not cleanly match a current terminal still need manual relink via the \u{1F517} picker."))}v();async function ud(e,t){let s=e.trim();if(!/^[0-9a-fA-F]{4,40}$/.test(s)){console.error(c.err(`not a valid commit SHA: '${e}'`)),process.exit(1);return}let n=rn(s);if(t.json){console.log(JSON.stringify(n,null,2));return}if(n.length===0){console.log(""),console.log(c.dim(`no correlated sessions for ${s}`)),console.log(c.dim(" (if you haven't yet, run `recall correlate` to backfill)")),console.log("");return}console.log(""),console.log(`${c.bold("commit")} ${c.accent(n[0].commitSha.slice(0,12))} ${c.dim(n[0].committedAt??"")}`),n[0].subject&&console.log(` ${n[0].subject}`),console.log(""),console.log(c.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(` ${c.accent(o.padEnd(24))} ${c.dim((r.project??"").slice(0,24).padEnd(26))} ${c.dim(r.startedAt??"")}`),console.log(` ${c.dim(`recall show ${r.sessionId}`)}`)}console.log("")}v();w();import{execFile as Dy}from"node:child_process";import{promisify as $y}from"node:util";import{stat as Py}from"node:fs/promises";var Fy=$y(Dy),jy=60,Uy=7,By=7,Hy=5e3;function Wy(){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
1581
+ WHERE sa.alias = '' AND sa.previous_aliases != '[]' AND s.cwd IS NOT NULL`).all(),o=[];for(let i of r){let a=Wy(i.previous_aliases);if(!a)continue;let d=i.cwd.replace(/\/+$/,""),u=t.get(d)?.get(a);if(!u)continue;let p=s.get(`${d}::${a}`);p&&p.size>1||o.push({session_id:i.session_id,cwd:d,alias_to_restore:a,matching_pid:u})}return o}async function md(e){let t=Uy();t||(console.error(c.err("Daemon is not running. Run `recall start` first.")),process.exit(1));let s=await By(t);s.length===0&&(console.error(c.err("Registry is empty. Open VS Code with the extension to populate it.")),process.exit(1));let n=Xy(s);if(e.json){console.log(JSON.stringify({candidates:n},null,2));return}if(n.length===0){console.log(c.dim("No restorable sessions found.")),console.log(c.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(c.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 d=r.get(a.cwd);d||(d=[],r.set(a.cwd,d)),d.push(a)}for(let[a,d]of r){console.log(c.dim(` cwd: ${a}`));for(let l of d)console.log(` ${c.dim(l.session_id.slice(0,8))} ${c.dim("\u2192 pid")} ${l.matching_pid} ${c.dim("=")} ${c.bold(`"${l.alias_to_restore}"`)}`);console.log()}if(!e.apply){console.log(c.dim("Re-run with --apply to restore these aliases."));return}let o=0,i=0;for(let a of n)await Hy(t,a.session_id,a.matching_pid)?o++:(i++,console.error(c.err(`failed to restore ${a.session_id.slice(0,8)}`)));console.log(c.ok(`Restored ${o} alias${o===1?"":"es"}.${i>0?` ${i} failed.`:""}`)),console.log(c.dim("Sessions whose previous alias did not cleanly match a current terminal still need manual relink via the \u{1F517} picker."))}v();async function gd(e,t){let s=e.trim();if(!/^[0-9a-fA-F]{4,40}$/.test(s)){console.error(c.err(`not a valid commit SHA: '${e}'`)),process.exit(1);return}let n=an(s);if(t.json){console.log(JSON.stringify(n,null,2));return}if(n.length===0){console.log(""),console.log(c.dim(`no correlated sessions for ${s}`)),console.log(c.dim(" (if you haven't yet, run `recall correlate` to backfill)")),console.log("");return}console.log(""),console.log(`${c.bold("commit")} ${c.accent(n[0].commitSha.slice(0,12))} ${c.dim(n[0].committedAt??"")}`),n[0].subject&&console.log(` ${n[0].subject}`),console.log(""),console.log(c.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(` ${c.accent(o.padEnd(24))} ${c.dim((r.project??"").slice(0,24).padEnd(26))} ${c.dim(r.startedAt??"")}`),console.log(` ${c.dim(`recall show ${r.sessionId}`)}`)}console.log("")}v();w();import{execFile as Jy}from"node:child_process";import{promisify as Gy}from"node:util";import{stat as Yy}from"node:fs/promises";var zy=Gy(Jy),qy=60,Ky=7,Vy=7,Zy=5e3;function Qy(){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
1585
1582
  WHERE (COALESCE(total_input_tokens,0)
1586
1583
  + COALESCE(total_output_tokens,0)
1587
1584
  + COALESCE(total_cache_create_tokens,0)
1588
1585
  + COALESCE(total_cache_read_tokens,0)) > 0
1589
- LIMIT 1`),git:t("SELECT 1 FROM session_commits LIMIT 1")}}function _o(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 pd(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 Xy(){let e=_(),t=e.prepare(`SELECT ss.keywords
1586
+ LIMIT 1`),git:t("SELECT 1 FROM session_commits LIMIT 1")}}function Eo(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 fd(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 ew(){let e=_(),t=e.prepare(`SELECT ss.keywords
1590
1587
  FROM session_semantic ss
1591
1588
  JOIN sessions s ON s.id = ss.session_id
1592
1589
  WHERE s.started_at IS NOT NULL
1593
- AND julianday('now') - julianday(s.started_at) <= @windowDays`).all({windowDays:Uy});if(t.length===0)return null;let s=new Set;for(let o of t)for(let i of _o(o.keywords))s.add(i);if(s.size===0)return null;let n=e.prepare(`SELECT ss.session_id AS session_id,
1590
+ AND julianday('now') - julianday(s.started_at) <= @windowDays`).all({windowDays:Ky});if(t.length===0)return null;let s=new Set;for(let o of t)for(let i of Eo(o.keywords))s.add(i);if(s.size===0)return null;let n=e.prepare(`SELECT ss.session_id AS session_id,
1594
1591
  ss.summary AS summary,
1595
1592
  ss.keywords AS keywords,
1596
1593
  p.name AS project,
@@ -1606,7 +1603,7 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1606
1603
  WHERE s.started_at IS NOT NULL
1607
1604
  AND s.message_count > 2
1608
1605
  AND julianday('now') - julianday(s.started_at) >= @ageDays
1609
- ORDER BY s.started_at ASC`).all({ageDays:jy});if(n.length===0)return null;let r=null;for(let o of n){let a=_o(o.keywords).filter(d=>s.has(d));a.length!==0&&(!r||a.length>r.overlap.length)&&(r={row:o,overlap:a})}return r?{...pd(r.row),summary:r.row.summary,keywords:_o(r.row.keywords),matchedKeywords:r.overlap,daysAgo:Math.max(0,Math.round(r.row.days_old))}:null}function Jy(){let t=_().prepare(`SELECT s.id AS session_id,
1606
+ ORDER BY s.started_at ASC`).all({ageDays:qy});if(n.length===0)return null;let r=null;for(let o of n){let a=Eo(o.keywords).filter(d=>s.has(d));a.length!==0&&(!r||a.length>r.overlap.length)&&(r={row:o,overlap:a})}return r?{...fd(r.row),summary:r.row.summary,keywords:Eo(r.row.keywords),matchedKeywords:r.overlap,daysAgo:Math.max(0,Math.round(r.row.days_old))}:null}function tw(){let t=_().prepare(`SELECT s.id AS session_id,
1610
1607
  p.name AS project,
1611
1608
  NULLIF(sa.alias, '') AS alias,
1612
1609
  s.started_at AS started_at,
@@ -1625,54 +1622,54 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1625
1622
  AND (COALESCE(s.total_input_tokens, 0)
1626
1623
  + COALESCE(s.total_output_tokens, 0)
1627
1624
  + COALESCE(s.total_cache_create_tokens, 0)
1628
- + COALESCE(s.total_cache_read_tokens, 0)) > 0`).all({windowDays:By});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?{...pd(s.row),totalTokens:s.totalTokens,costCents:s.cents,costDisplay:ne(s.cents),tokensDisplay:ue(s.totalTokens),primaryModel:s.row.primary_model,primaryModelLabel:at(s.row.primary_model).label}:null}async function Yy(e){try{if(!(await Py(e)).isDirectory())return null}catch{return null}try{let{stdout:t}=await Fy("git",["rev-parse","HEAD"],{cwd:e,timeout:Hy}),s=t.trim();return/^[0-9a-f]{40}$/.test(s)?s:null}catch{return null}}async function Gy(){let e=_(),t=e.prepare(`SELECT s.id AS id, s.cwd AS cwd
1625
+ + COALESCE(s.total_cache_read_tokens, 0)) > 0`).all({windowDays:Vy});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?{...fd(s.row),totalTokens:s.totalTokens,costCents:s.cents,costDisplay:re(s.cents),tokensDisplay:ue(s.totalTokens),primaryModel:s.row.primary_model,primaryModelLabel:it(s.row.primary_model).label}:null}async function sw(e){try{if(!(await Yy(e)).isDirectory())return null}catch{return null}try{let{stdout:t}=await zy("git",["rev-parse","HEAD"],{cwd:e,timeout:Zy}),s=t.trim();return/^[0-9a-f]{40}$/.test(s)?s:null}catch{return null}}async function nw(){let e=_(),t=e.prepare(`SELECT s.id AS id, s.cwd AS cwd
1629
1626
  FROM sessions s
1630
1627
  WHERE s.cwd IS NOT NULL AND s.started_at IS NOT NULL
1631
1628
  ORDER BY COALESCE(s.ended_at, s.started_at, '') DESC
1632
- LIMIT 1`).get();if(!t?.cwd)return null;let s=await Yy(t.cwd);if(!s)return null;let n=rn(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
1629
+ LIMIT 1`).get();if(!t?.cwd)return null;let s=await sw(t.cwd);if(!s)return null;let n=an(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
1633
1630
  FROM sessions s
1634
- 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 md(){let e=Wy(),t=e.semantic?Promise.resolve().then(()=>{try{return Xy()}catch(a){return console.error("[discover.rediscovered]",a),null}}):Promise.resolve(null),s=e.cost?Promise.resolve().then(()=>{try{return Jy()}catch(a){return console.error("[discover.expensive]",a),null}}):Promise.resolve(null),n=e.git?Gy().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 Eo(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 ho(e){return e.alias??(e.firstUserMessage?Eo(e.firstUserMessage,60):null)??e.sessionId.slice(0,8)}function zy(e){let t=e.rediscovered||e.expensive||e.authored;if(console.log(""),console.log(c.bold("today \xB7 for you")),console.log(c.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(c.dim(" no picks today.")),s.length>0?console.log(c.dim(" enable: "+s.join(", "))):console.log(c.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(` ${c.tool("\u2726 rediscovered")} ${c.dim(`(${s.daysAgo}d ago)`)}`),console.log(` ${c.bold(ho(s))} ${c.dim(s.project?`\xB7 ${s.project}`:"")}`),console.log(` ${c.dim(s.sessionId.slice(0,8))}`),s.matchedKeywords.length>0&&console.log(" "+c.dim("matched: ")+s.matchedKeywords.slice(0,6).map(n=>c.tool(`#${n}`)).join(" ")),s.summary&&console.log(" "+c.dim(Eo(s.summary,100)))}if(e.expensive){let s=e.expensive;console.log(""),console.log(` ${c.accent("$ most expensive \xB7 7d")} ${c.bold(s.costDisplay)} ${c.dim(`(${s.tokensDisplay} \xB7 ${s.primaryModelLabel})`)}`),console.log(` ${c.bold(ho(s))} ${c.dim(s.project?`\xB7 ${s.project}`:"")}`),console.log(` ${c.dim(s.sessionId.slice(0,8))} ${c.dim(s.startedAt?X(s.startedAt):"")}`)}if(e.authored){let s=e.authored;console.log(""),console.log(` ${c.ok("\u2387 authored current HEAD")} ${c.bold(s.shortSha)} ${c.dim(s.committedAt?`(${X(s.committedAt)})`:"")}`),console.log(` ${c.bold(ho(s))} ${c.dim(s.project?`\xB7 ${s.project}`:"")}`),s.subject&&console.log(` ${c.dim(Eo(s.subject,80))}`),console.log(` ${c.dim(s.sessionId.slice(0,8))} ${c.dim("cwd: "+s.cwd)}`)}console.log("")}async function gd(e){let t=await md();if(e.json){console.log(JSON.stringify(t,null,2));return}zy(t)}v();st();import{spawnSync as Ed}from"node:child_process";import{readdirSync as Ky}from"node:fs";import{join as qy,resolve as Vy}from"node:path";var bo=["code","cursor","code-insiders","windsurf"],fd=[{id:"code",label:"VS Code"},{id:"cursor",label:"Cursor"},{id:"code-insiders",label:"VS Code Insiders"},{id:"windsurf",label:"Windsurf"}],Zy="https://marketplace.visualstudio.com/items?itemName=clauderecallhq.clauderecall-vscode";function Qy(){return qy(de(),"extensions","vscode")}function ew(){let e=Qy(),t;try{t=Ky(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})),Vy(e,s[0]))}function _d(e){let t=Ed(e,["--version"],{stdio:"ignore",shell:process.platform==="win32"});return t.error?!1:t.status===0}function tw(e,t){let s=Ed(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 hd(){process.stderr.write(c.err(`no bundled .vsix found at extensions/vscode/(clauderecall|claude-recall)-vscode-*.vsix
1631
+ 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 _d(){let e=Qy(),t=e.semantic?Promise.resolve().then(()=>{try{return ew()}catch(a){return console.error("[discover.rediscovered]",a),null}}):Promise.resolve(null),s=e.cost?Promise.resolve().then(()=>{try{return tw()}catch(a){return console.error("[discover.expensive]",a),null}}):Promise.resolve(null),n=e.git?nw().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 So(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 bo(e){return e.alias??(e.firstUserMessage?So(e.firstUserMessage,60):null)??e.sessionId.slice(0,8)}function rw(e){let t=e.rediscovered||e.expensive||e.authored;if(console.log(""),console.log(c.bold("today \xB7 for you")),console.log(c.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(c.dim(" no picks today.")),s.length>0?console.log(c.dim(" enable: "+s.join(", "))):console.log(c.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(` ${c.tool("\u2726 rediscovered")} ${c.dim(`(${s.daysAgo}d ago)`)}`),console.log(` ${c.bold(bo(s))} ${c.dim(s.project?`\xB7 ${s.project}`:"")}`),console.log(` ${c.dim(s.sessionId.slice(0,8))}`),s.matchedKeywords.length>0&&console.log(" "+c.dim("matched: ")+s.matchedKeywords.slice(0,6).map(n=>c.tool(`#${n}`)).join(" ")),s.summary&&console.log(" "+c.dim(So(s.summary,100)))}if(e.expensive){let s=e.expensive;console.log(""),console.log(` ${c.accent("$ most expensive \xB7 7d")} ${c.bold(s.costDisplay)} ${c.dim(`(${s.tokensDisplay} \xB7 ${s.primaryModelLabel})`)}`),console.log(` ${c.bold(bo(s))} ${c.dim(s.project?`\xB7 ${s.project}`:"")}`),console.log(` ${c.dim(s.sessionId.slice(0,8))} ${c.dim(s.startedAt?J(s.startedAt):"")}`)}if(e.authored){let s=e.authored;console.log(""),console.log(` ${c.ok("\u2387 authored current HEAD")} ${c.bold(s.shortSha)} ${c.dim(s.committedAt?`(${J(s.committedAt)})`:"")}`),console.log(` ${c.bold(bo(s))} ${c.dim(s.project?`\xB7 ${s.project}`:"")}`),s.subject&&console.log(` ${c.dim(So(s.subject,80))}`),console.log(` ${c.dim(s.sessionId.slice(0,8))} ${c.dim("cwd: "+s.cwd)}`)}console.log("")}async function hd(e){let t=await _d();if(e.json){console.log(JSON.stringify(t,null,2));return}rw(t)}v();Ke();import{spawnSync as yd}from"node:child_process";import{readdirSync as ow}from"node:fs";import{join as iw,resolve as aw}from"node:path";var yo=["code","cursor","code-insiders","windsurf"],Ed=[{id:"code",label:"VS Code"},{id:"cursor",label:"Cursor"},{id:"code-insiders",label:"VS Code Insiders"},{id:"windsurf",label:"Windsurf"}],cw="https://marketplace.visualstudio.com/items?itemName=clauderecallhq.clauderecall-vscode";function lw(){return iw(ee(),"extensions","vscode")}function dw(){let e=lw(),t;try{t=ow(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})),aw(e,s[0]))}function bd(e){let t=yd(e,["--version"],{stdio:"ignore",shell:process.platform==="win32"});return t.error?!1:t.status===0}function uw(e,t){let s=yd(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 Sd(){process.stderr.write(c.err(`no bundled .vsix found at extensions/vscode/(clauderecall|claude-recall)-vscode-*.vsix
1635
1632
  `)),process.stderr.write(c.dim(`see PUBLISHING.md for how to build the extension, or run:
1636
1633
  `)),process.stderr.write(c.dim(` (cd extensions/vscode && npm install && npm run build && npm run package)
1637
- `))}function sw(e){return bo.includes(e)}async function bd(e){if(e.editor!==void 0&&!sw(e.editor)){process.stderr.write(c.err(`unknown --editor target: ${e.editor}
1638
- `)),process.stderr.write(c.dim(`valid values: ${bo.join(", ")}
1639
- `)),process.exitCode=1;return}let t=ew();if(e.printPath){if(!t){hd(),process.exitCode=1;return}process.stdout.write(t+`
1640
- `);return}if(!t){hd(),process.exitCode=1;return}let s;if(e.editor){let r=e.editor;if(!_d(r)){process.stderr.write(c.err(`editor CLI not found on PATH: ${r}
1634
+ `))}function pw(e){return yo.includes(e)}async function wd(e){if(e.editor!==void 0&&!pw(e.editor)){process.stderr.write(c.err(`unknown --editor target: ${e.editor}
1635
+ `)),process.stderr.write(c.dim(`valid values: ${yo.join(", ")}
1636
+ `)),process.exitCode=1;return}let t=dw();if(e.printPath){if(!t){Sd(),process.exitCode=1;return}process.stdout.write(t+`
1637
+ `);return}if(!t){Sd(),process.exitCode=1;return}let s;if(e.editor){let r=e.editor;if(!bd(r)){process.stderr.write(c.err(`editor CLI not found on PATH: ${r}
1641
1638
  `)),process.stderr.write(c.dim(`install the editor shell integration, or omit --editor to install into every detected editor.
1642
1639
  `)),process.stderr.write(c.dim(`see PUBLISHING.md for manual install instructions.
1643
- `)),process.exitCode=1;return}s=[fd.find(i=>i.id===r)??{id:r,label:r}]}else s=fd.filter(r=>_d(r.id));if(s.length===0){process.stderr.write(c.err(`no supported editor CLI detected on PATH.
1644
- `)),process.stderr.write(c.dim(`looked for: ${bo.join(", ")}.
1640
+ `)),process.exitCode=1;return}s=[Ed.find(i=>i.id===r)??{id:r,label:r}]}else s=Ed.filter(r=>bd(r.id));if(s.length===0){process.stderr.write(c.err(`no supported editor CLI detected on PATH.
1641
+ `)),process.stderr.write(c.dim(`looked for: ${yo.join(", ")}.
1645
1642
  `)),process.stderr.write(c.dim(`install the editor shell integration and try again.
1646
1643
  `)),process.stderr.write(c.dim(`see PUBLISHING.md for manual install instructions.
1647
1644
  `)),process.exitCode=1;return}process.stderr.write(c.dim(`bundled .vsix: ${t}
1648
1645
 
1649
- `));let n=!1;for(let r of s){let{ok:o,message:i}=tw(r.id,t);o?process.stderr.write(c.ok(`\u2713 installed into ${r.label} (${r.id})
1646
+ `));let n=!1;for(let r of s){let{ok:o,message:i}=uw(r.id,t);o?process.stderr.write(c.ok(`\u2713 installed into ${r.label} (${r.id})
1650
1647
  `)):(n=!0,process.stderr.write(c.err(`\u2717 ${r.label} (${r.id}): ${i}
1651
1648
  `)))}process.stderr.write(`
1652
1649
  `),process.stderr.write(c.bold(`next steps:
1653
1650
  `)),process.stderr.write(` 1. reload the editor window: Cmd/Ctrl+Shift+P then pick "Developer: Reload Window"
1654
1651
  `),process.stderr.write(` 2. enable the extension: open settings and set "claude-recall.autoAlias" to true
1655
1652
  `),process.stderr.write(`
1656
- `),process.stderr.write(c.dim(`marketplace install: ${Zy}
1657
- `)),n&&(process.exitCode=1)}To();v();function Ro(e){return e>=70?c.ok:e>=40?c.warn:c.err}function yd(e,t=20){let s=Math.round(e/100*t);return"\u2588".repeat(s)+"\u2591".repeat(t-s)}function nw(e){let t=Ro(e.score);process.stdout.write(`
1653
+ `),process.stderr.write(c.dim(`marketplace install: ${cw}
1654
+ `)),n&&(process.exitCode=1)}xo();v();function ko(e){return e>=70?c.ok:e>=40?c.warn:c.err}function Rd(e,t=20){let s=Math.round(e/100*t);return"\u2588".repeat(s)+"\u2591".repeat(t-s)}function mw(e){let t=ko(e.score);process.stdout.write(`
1658
1655
  ${c.bold(e.projectName)} ${t(String(e.score)+"/100")}
1659
- `);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=Ro(o);process.stdout.write(` ${r.padEnd(10)} ${a(yd(o,16))} ${String(Math.round(o)).padStart(3)}% ${c.dim(i)}
1660
- `)}}function wd(e,t){if(e){let r=yo(e);if(!r){process.stderr.write(c.err(`project "${e}" not found
1656
+ `);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=ko(o);process.stdout.write(` ${r.padEnd(10)} ${a(Rd(o,16))} ${String(Math.round(o)).padStart(3)}% ${c.dim(i)}
1657
+ `)}}function xd(e,t){if(e){let r=To(e);if(!r){process.stderr.write(c.err(`project "${e}" not found
1661
1658
  `)),process.exitCode=1;return}if(t.json){process.stdout.write(JSON.stringify(r,null,2)+`
1662
- `);return}nw(r);return}let s=wo();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)+`
1659
+ `);return}mw(r);return}let s=Ro();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)+`
1663
1660
  `);return}let n=[...s].sort((r,o)=>r.score-o.score);process.stdout.write(c.bold("Memory Health Scores")+` (worst first)
1664
1661
 
1665
- `);for(let r of n){let o=Ro(r.score);process.stdout.write(` ${o(yd(r.score,12))} ${String(r.score).padStart(3)}/100 ${r.projectName}
1662
+ `);for(let r of n){let o=ko(r.score);process.stdout.write(` ${o(Rd(r.score,12))} ${String(r.score).padStart(3)}/100 ${r.projectName}
1666
1663
  `)}process.stdout.write(`
1667
- `)}v();function Td(e){if(e==="on"){sr(!0),process.stdout.write(c.ok("Verification badges enabled.")+`
1668
- `);return}if(e==="off"){sr(!1),process.stdout.write(`Verification badges disabled.
1664
+ `)}v();function kd(e){if(e==="on"){rr(!0),process.stdout.write(c.ok("Verification badges enabled.")+`
1665
+ `);return}if(e==="off"){rr(!1),process.stdout.write(`Verification badges disabled.
1669
1666
  `);return}let t=ws();process.stdout.write(`Verification badges: ${t?c.ok("ON"):"OFF"}
1670
1667
  `),process.stdout.write(`
1671
1668
  Toggle with: recall verify on | off
1672
- `)}v();qt();xs();At();ks();import{hostname as Iw}from"node:os";import{randomBytes as Mw}from"node:crypto";Ke();le();D();w();st();import{existsSync as rw}from"node:fs";import ow from"node:readline";import{createRequire as iw}from"node:module";import{Chalk as aw}from"chalk";var cw=iw(import.meta.url),lw=cw(`${de()}/package.json`).version,Cd="#f97316",dw="#8b9098",uw="#10b981",pw="#f59e0b",Pt=new aw({level:process.env.NO_COLOR?0:3}),be=Pt.hex(Cd),re=Pt.hex(Cd).bold,I=Pt.hex(dw),wt=Pt.hex(uw),ln=Pt.hex(pw),Ld=Pt.bold,Nd=[" \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"],mw=Nd[0]?.length??49,Rd="Never lose a Claude Code session again.",gw="CLAUDE RECALL";function fw(){if(!rw(te))return{sessions:0,projects:0};try{let t=_().prepare(`SELECT
1669
+ `)}v();Vt();xs();At();ks();import{hostname as Ww}from"node:os";import{randomBytes as Xw}from"node:crypto";qe();de();P();w();Ke();import{existsSync as gw}from"node:fs";import fw from"node:readline";import{createRequire as _w}from"node:module";import{Chalk as hw}from"chalk";var Ew=_w(import.meta.url),bw=Ew(`${ee()}/package.json`).version,Ad="#f97316",Sw="#8b9098",yw="#10b981",ww="#f59e0b",Ft=new hw({level:process.env.NO_COLOR?0:3}),be=Ft.hex(Ad),oe=Ft.hex(Ad).bold,I=Ft.hex(Sw),wt=Ft.hex(yw),un=Ft.hex(ww),Od=Ft.bold,vd=[" \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"],Tw=vd[0]?.length??49,Cd="Never lose a Claude Code session again.",Rw="CLAUDE RECALL";function xw(){if(!gw(se))return{sessions:0,projects:0};try{let t=_().prepare(`SELECT
1673
1670
  (SELECT COUNT(*) FROM sessions) AS sessions,
1674
- (SELECT COUNT(*) FROM projects) AS projects`).get();return{sessions:t.sessions,projects:t.projects}}catch{return{sessions:0,projects:0}}}function _w(){let e=process.stdout.columns;return typeof e!="number"||e<=0?!1:e<mw+2}function Ad(){if(_w()){console.log(`${re(gw)} ${I("\xB7")} ${I(Rd)}`);return}for(let e of Nd)console.log(re(e));console.log(I(Rd))}async function hw(){return{daemon:Q(),counts:fw(),license:await Te()}}function Ew(e){let t=[];if(t.push(` ${I("Version:")} ${be(`v${lw}`)} ${I("\xB7 CLI \xB7 @clauderecallhq/cli")}`),e.daemon){let s=`http://127.0.0.1:${e.daemon.port}`;t.push(` ${I("Daemon:")} ${wt("running")} on ${s} ${I(`(pid ${e.daemon.pid})`)}`)}else t.push(` ${I("Daemon:")} ${ln("stopped")}`);if(e.counts.sessions===0)t.push(` ${I("Sessions:")} ${ln("none indexed yet")}`);else{let s=e.counts.projects===1?"project":"projects";t.push(` ${I("Sessions:")} ${be(String(e.counts.sessions))} indexed across ${be(String(e.counts.projects))} ${s}`)}return e.license.tier==="pro"?t.push(` ${I("License:")} ${wt("Pro")}`):t.push(` ${I("License:")} Free`),t}function bw(e){let t=be(">");if(e.counts.sessions===0)return`${t} Run ${re("recall index")} to scan ~/.claude/projects/`;if(!e.daemon)return`${t} Run ${re("recall start")} to launch the local daemon`;if(e.license.tier==="free")return`${t} Run ${re("recall upgrade")} to unlock Pro features`;let s=`http://127.0.0.1:${e.daemon.port}`;return`${t} Open ${be(s)} in your browser ${I("\xB7")} or run ${re("recall --help")} for all commands`}var dn=[{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"}]}],Sw=dn.reduce((e,t)=>e+t.commands.length,0),yw=new Set([...dn.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 xd(){let e=dn.flatMap(s=>s.commands.map(n=>`recall ${n.name}`)),t=Math.max(...e.map(s=>s.length));console.log(),console.log(`${Ld("COMMANDS")} ${I(`\xB7 ${Sw} total \xB7 q to quit \xB7 recall --help for full details`)}`),console.log(` ${I("All commands run as subcommands of")} ${re("recall")}${I(". There is no separate")} ${be("threads")}${I(",")} ${be("thread")}${I(", or")} ${be("titles")} ${I("binary.")}`);for(let s of dn){console.log(),console.log(` ${re(s.title.toUpperCase())}`);for(let n of s.commands){let r=`recall ${n.name}`.padEnd(t," ");console.log(` ${be(r)} ${I(n.description)}`)}}console.log()}function ww(){return!!process.stdin.isTTY&&!!process.stdout.isTTY}async function Tw(){if(!ww())return;let e=ow.createInterface({input:process.stdin,output:process.stdout}),t=`${I("Type")} ${re("/")} ${I("for commands, or press")} ${re("Enter")} ${I("to exit")} ${be("\u203A")} `;return new Promise(s=>{let n=()=>{e.question(t,r=>{let o=r.trim();if(o==="/"||o==="/help"||o==="help"||o==="?"){xd(),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===""){xd(),n();return}let d=(i.split(/\s+/)[0]??"").toLowerCase();yw.has(d)?console.log(` ${I("Run")} ${re(`recall ${i}`)} ${I("in your shell to invoke that command.")}`):console.log(` ${I(`No command matches "${o}". Type`)} ${re("/")} ${I("to browse, or")} ${re("recall --help")} ${I("for the full list.")}`),n()})};e.on("close",()=>{console.log(),s()}),n()})}async function Od(){let e=await hw();console.log(),Ad(),console.log();for(let t of Ew(e))console.log(t);console.log(),console.log(bw(e)),console.log(),await Tw()}var Rw=[{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 xw(){return process.env.NO_COLOR||process.env.CI||process.env.RECALL_NO_ANIMATION?!1:!!process.stdout.isTTY}function xo(e){return new Promise(t=>setTimeout(t,e))}function kw(e){let s=(e.split("@")[0]??"").split(/[._+\-]/)[0]??"";return s?s.charAt(0).toUpperCase()+s.slice(1).toLowerCase():""}function kd(){process.stdout.write("\r\x1B[2K")}async function un(e){let t=xw();console.log(),Ad(),console.log(),t&&(process.stdout.write(` ${I("Verifying license...")}`),await xo(260),kd()),console.log(` ${wt("\u2713")} ${I("License verified")}`),console.log(` ${wt("\u2713")} ${I("Tier:")} ${re("Pro")} ${I("\xB7 Lifetime")}`),console.log(` ${wt("\u2713")} ${I("Key:")} ${be(e.key_short)}`),console.log(` ${wt("\u2713")} ${I("Email:")} ${e.email}`),e.test_mode&&console.log(` ${ln("!")} ${ln("Test mode:")} this license was issued in test mode.`),console.log(),console.log(` ${Ld("Unlocking Pro features")}`),console.log();for(let r of Rw)t&&(process.stdout.write(` ${I("\xB7")} ${I(r.name)}`),await xo(110),kd()),console.log(` ${wt("\u2713")} ${r.name} ${I(r.detail)}`);t&&await xo(160),console.log();let s=kw(e.email),n=s?`Welcome aboard, ${s}.`:"Welcome aboard.";console.log(` ${re(n)}`),console.log(` ${I("Run")} ${be("recall")} ${I("to open the dashboard, or")} ${be("recall help")} ${I("for the command list.")}`),console.log()}v();qt();xs();At();ks();import{hostname as Cw}from"node:os";import{randomBytes as Lw}from"node:crypto";import{createInterface as Nw}from"node:readline/promises";async function Aw(e){let t=e.fetchFn??fetch,s=`${e.apiBaseUrl}/api/trial/cli-redeem`,n=await t(s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({promo_code:e.promoCode,email:e.email,machine_fingerprint:e.fingerprint,instance_name:e.instanceName,referral_source:"cli"})}),r;try{r=await n.json()}catch{throw new Error(`server returned non-JSON (status ${n.status})`)}return{status:n.status,body:r}}async function Ow(e={}){let t=Nw({input:e.stdin??process.stdin,output:e.stdout??process.stdout});try{return(await t.question(c.bold("Email for your 7-day trial: "))).trim().toLowerCase()}finally{t.close()}}function vw(e){if(e.length<5||e.length>256||!e.includes("@"))return!1;let[t,s]=e.split("@");return!(!t||!s||!s.includes(".")||/\s/.test(e))}async function pn(e,t={}){let s=e.trim().toUpperCase();if(s.length<3&&(console.error(c.warn(`Promo code "${e}" is too short.`)),process.exit(1)),!t.skipExistingProCheck){let{getLicenseStatus:u}=await Promise.resolve().then(()=>(le(),Vt)),p=await u();if(p.tier==="pro"){console.log(),console.log(c.bold("You are already on Pro \u2014 no need to redeem a trial.")),console.log(` ${c.dim("Key:")} ${p.key_short}`),console.log(` ${c.dim("Email:")} ${p.customer_email}`),console.log(),console.log(c.dim("If you wanted to switch accounts, run `recall license deactivate` first.")),console.log();return}}console.log(),console.log(`${c.ok("Redeeming")} promo code ${c.bold(s)} for a 7-day Pro trial.`),console.log(c.dim("You will get an email with your license key for backup.")),console.log(),!t.promptFn&&!process.stdin.isTTY&&(console.error(c.warn("Trial activation needs an interactive terminal so you can type your email.")),console.error(c.dim("Re-run `recall activate "+s+"` in a terminal (not piped, not CI).")),process.exit(1));let r=await(t.promptFn??Ow)();vw(r)||(console.error(c.warn(`"${r}" doesn't look like an email address.`)),process.exit(1));let o=t.instanceName??`${Cw()}-${Lw(4).toString("hex")}`,i=t.fingerprint??vt(),a=t.apiBaseUrl??et(),d;try{d=await Aw({promoCode:s,email:r,fingerprint:i,instanceName:o,apiBaseUrl:a,...t.fetchFn?{fetchFn:t.fetchFn}:{}})}catch(u){let p=u instanceof Error?u.message:"unknown error";console.error(c.warn(`Could not reach the trial server at ${a}: ${p}`)),console.error(c.dim("If you are offline, try again when you have a connection.")),process.exit(1)}if(d.status!==200||!d.body.license_jwt||!d.body.license_key){let u=d.body.error??`trial activation failed (status ${d.status})`;console.error(c.warn(`Trial refused: ${u}`)),process.exit(1)}let l=await Ot(d.body.license_jwt);(!l.valid||!l.claims)&&(console.error(c.warn(`Server returned a JWT that fails local verification: ${l.reason??"unknown"}`)),console.error(c.dim("This usually means the CLI is older than the server. Try `npm i -g @clauderecallhq/cli`.")),process.exit(1)),Ts({license_jwt:d.body.license_jwt,license_key:d.body.license_key,key_short:d.body.key_short??l.claims.key_short,customer_email:d.body.customer_email??l.claims.email,activated_at:new Date().toISOString(),tier:"pro",test_mode:!!l.claims.test_mode}),t.skipSuccessDashboard||await un({...l.claims,key_short:d.body.key_short??l.claims.key_short,email:d.body.customer_email??l.claims.email})}function Dw(e){return/^recall-pro-/i.test(e)}async function vd(e){let t=e.trim();if(t.length<3&&(console.error(c.warn("License key or promo code looks too short.")),console.error(c.dim("Paste the full key from your purchase email, or a promo code like RECALL7DAY.")),process.exit(1)),!Dw(t)){await pn(t);return}t.length<8&&(console.error(c.warn("License key looks too short. Paste the full key from your purchase email.")),process.exit(1));let s=`${Iw()}-${Mw(4).toString("hex")}`,n=`${et()}/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:vt()})})}catch(a){let d=a instanceof Error?a.message:"unknown error";console.error(c.warn(`Could not reach activation server at ${n}: ${d}`)),console.error(c.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(c.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(c.warn(`Activation refused: ${a}`)),process.exit(1)}let i=await Ot(o.license_jwt);(!i.valid||!i.claims)&&(console.error(c.warn(`Server returned a JWT that fails local verification: ${i.reason??"unknown"}`)),console.error(c.dim("This usually means the CLI is older than the server, or the public key was rotated.")),process.exit(1)),Ts({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 un({...i.claims,key_short:o.key_short??i.claims.key_short,email:o.customer_email??i.claims.email})}v();import{spawn as $w}from"node:child_process";import{platform as mn}from"node:os";var Id="https://clauderecall.com/pricing";function Pw(e){let t=mn()==="darwin"?"open":mn()==="win32"?"start":"xdg-open",s=mn()==="win32"?["",e]:[e];$w(t,s,{detached:!0,stdio:"ignore",shell:mn()==="win32"}).unref()}async function Md(){let{getLicenseStatus:e}=await Promise.resolve().then(()=>(le(),Vt)),t=await e();if(t.tier==="pro"){console.log(),console.log(c.bold("Already on Pro.")),console.log(` ${c.dim("Key:")} ${t.key_short}`),console.log(` ${c.dim("Email:")} ${t.customer_email}`),console.log();return}console.log(),console.log(`${c.ok("Opening")} ${Id}`),console.log(c.dim("After purchase, run: recall activate <license-key>")),console.log(),Pw(Id)}v();import{spawn as Fw}from"node:child_process";import{platform as gn}from"node:os";var Dd="https://clauderecall.com/pricing?trial=1&utm_source=cli&utm_medium=recall_trial";function jw(e){let t=gn()==="darwin"?"open":gn()==="win32"?"start":"xdg-open",s=gn()==="win32"?["",e]:[e];Fw(t,s,{detached:!0,stdio:"ignore",shell:gn()==="win32"}).unref()}async function $d(e){if(e&&e.trim().length>0){await pn(e);return}let{getLicenseStatus:t}=await Promise.resolve().then(()=>(le(),Vt)),s=await t();if(s.tier==="pro"){console.log(),console.log(c.bold("You are already on Pro.")),console.log(` ${c.dim("Key:")} ${s.key_short}`),console.log(` ${c.dim("Email:")} ${s.customer_email}`),console.log();return}console.log(),console.log(`${c.ok("Opening")} ${Dd}`),console.log(c.dim("Enter your email to get a 7-day Pro trial link. No card.")),console.log(c.dim("After you click the verification email, run: recall activate <key>")),console.log(),console.log(c.dim("Tip: if you have a promo code, run `recall trial <CODE>` to skip the browser.")),console.log(),jw(Dd)}v();qt();import{existsSync as Pd,mkdirSync as Uw,readFileSync as Bw,writeFileSync as Hw}from"node:fs";import{homedir as Ww}from"node:os";import{join as Fd}from"node:path";import{randomBytes as Xw}from"node:crypto";var Co=Fd(Ww(),".recall"),_n=Fd(Co,"telemetry.json"),ko={decided_at:null,decision:null,last_ping_month:null,nonce_month:null,nonce:null,last_error:null};function Tt(){if(!Pd(_n))return{...ko};try{let e=Bw(_n,"utf8"),t=JSON.parse(e);return{...ko,...t}}catch{return{...ko}}}function fn(e){Pd(Co)||Uw(Co,{recursive:!0}),Hw(_n,JSON.stringify(e,null,2)+`
1675
- `,{mode:384})}function jd(){return _n}function Lo(e=new Date){let t=e.getUTCFullYear(),s=String(e.getUTCMonth()+1).padStart(2,"0");return`${t}-${s}`}function Ud(e,t){return e.nonce&&e.nonce_month===t?e:{...e,nonce:Xw(16).toString("hex"),nonce_month:t}}function Jw(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 Bd(e){let t=Tt();if(t.decision!=="on")return{status:t.decision==="off"?"opted-out":"no-decision"};let s=Lo();if(t.last_ping_month===s)return{status:"already-this-month"};t=Ud(t,s);let n=Jw(e,t);if(!n)return{status:"error",detail:"no nonce"};try{let r=await fetch(`${et()}/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 fn({...t,last_error:`${new Date().toISOString()} ${i}`}),{status:"error",detail:i}}let o=await r.json().catch(()=>({}));return fn({...t,last_ping_month:s,last_error:null}),{status:o.deduped?"deduped":"sent"}}catch(r){let o=r instanceof Error?r.message:"unknown";return fn({...t,last_error:`${new Date().toISOString()} ${o}`}),{status:"error",detail:o}}}function Ft(e){let s={...Tt(),decision:e,decided_at:new Date().toISOString(),last_error:null,...e==="off"?{nonce:null,nonce_month:null,last_ping_month:null}:{}};return fn(s),s}function hn(e){let t=Ud(Tt(),Lo());return{event:"install",version:e,platform:process.platform,arch:process.arch,month:t.nonce_month??Lo(),nonce:t.nonce??"0".repeat(32)}}async function No(e){let t=Tt();console.log(),console.log(c.bold("Telemetry \u2014 anonymous install ping")),console.log(` ${c.dim("decision:")} ${t.decision??"not yet decided"}`),console.log(` ${c.dim("decided at:")} ${t.decided_at??"\u2014"}`),console.log(` ${c.dim("last ping:")} ${t.last_ping_month??"\u2014"}`),console.log(` ${c.dim("state file:")} ${jd()}`),t.last_error&&console.log(` ${c.warn("last error:")} ${t.last_error}`),console.log(),console.log(c.dim("Next-ping payload preview (only sent if decision = on):")),console.log(c.dim(JSON.stringify(hn(e),null,2))),console.log(),console.log(c.dim("Toggle with `recall telemetry on` / `recall telemetry off`.")),console.log(c.dim("Full disclosure: https://clauderecall.com/telemetry")),console.log()}async function Hd(){Ft("on"),console.log(),console.log(c.ok("Telemetry: opted in.")),console.log(c.dim("One anonymous ping per machine per month. No PII. Source: docs/specs/v0.16-install-ping.md")),console.log(c.dim("Reverse with `recall telemetry off`.")),console.log()}async function Wd(){Ft("off"),console.log(),console.log(c.ok("Telemetry: opted out.")),console.log(c.dim("No further pings will be sent. Existing nonce deleted.")),console.log()}async function Xd(e){await No(e)}import{createInterface as Yw}from"node:readline/promises";import{stdin as Jd,stdout as me}from"node:process";var Gw=new Set(["telemetry","trial","upgrade","activate","license","help","version"]);function zw(e){return!(process.env.CI==="true"||process.env.RECALL_QUIET_INSTALL==="1"||process.env.RECALL_DISABLE_TELEMETRY_PROMPT==="1"||!Jd.isTTY||!me.isTTY||e&&Gw.has(e)||Tt().decision!==null)}async function Yd(e,t){if(!zw(e))return;let s=hn(t);me.write(`
1671
+ (SELECT COUNT(*) FROM projects) AS projects`).get();return{sessions:t.sessions,projects:t.projects}}catch{return{sessions:0,projects:0}}}function kw(){let e=process.stdout.columns;return typeof e!="number"||e<=0?!1:e<Tw+2}function Id(){if(kw()){console.log(`${oe(Rw)} ${I("\xB7")} ${I(Cd)}`);return}for(let e of vd)console.log(oe(e));console.log(I(Cd))}async function Cw(){return{daemon:Q(),counts:xw(),license:await Te()}}function Lw(e){let t=[];if(t.push(` ${I("Version:")} ${be(`v${bw}`)} ${I("\xB7 CLI \xB7 @clauderecallhq/cli")}`),e.daemon){let s=`http://127.0.0.1:${e.daemon.port}`;t.push(` ${I("Daemon:")} ${wt("running")} on ${s} ${I(`(pid ${e.daemon.pid})`)}`)}else t.push(` ${I("Daemon:")} ${un("stopped")}`);if(e.counts.sessions===0)t.push(` ${I("Sessions:")} ${un("none indexed yet")}`);else{let s=e.counts.projects===1?"project":"projects";t.push(` ${I("Sessions:")} ${be(String(e.counts.sessions))} indexed across ${be(String(e.counts.projects))} ${s}`)}return e.license.tier==="pro"?t.push(` ${I("License:")} ${wt("Pro")}`):t.push(` ${I("License:")} Free`),t}function Nw(e){let t=be(">");if(e.counts.sessions===0)return`${t} Run ${oe("recall index")} to scan ~/.claude/projects/`;if(!e.daemon)return`${t} Run ${oe("recall start")} to launch the local daemon`;if(e.license.tier==="free")return`${t} Run ${oe("recall upgrade")} to unlock Pro features`;let s=`http://127.0.0.1:${e.daemon.port}`;return`${t} Open ${be(s)} in your browser ${I("\xB7")} or run ${oe("recall --help")} for all commands`}var pn=[{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"}]}],Aw=pn.reduce((e,t)=>e+t.commands.length,0),Ow=new Set([...pn.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 Ld(){let e=pn.flatMap(s=>s.commands.map(n=>`recall ${n.name}`)),t=Math.max(...e.map(s=>s.length));console.log(),console.log(`${Od("COMMANDS")} ${I(`\xB7 ${Aw} total \xB7 q to quit \xB7 recall --help for full details`)}`),console.log(` ${I("All commands run as subcommands of")} ${oe("recall")}${I(". There is no separate")} ${be("threads")}${I(",")} ${be("thread")}${I(", or")} ${be("titles")} ${I("binary.")}`);for(let s of pn){console.log(),console.log(` ${oe(s.title.toUpperCase())}`);for(let n of s.commands){let r=`recall ${n.name}`.padEnd(t," ");console.log(` ${be(r)} ${I(n.description)}`)}}console.log()}function vw(){return!!process.stdin.isTTY&&!!process.stdout.isTTY}async function Iw(){if(!vw())return;let e=fw.createInterface({input:process.stdin,output:process.stdout}),t=`${I("Type")} ${oe("/")} ${I("for commands, or press")} ${oe("Enter")} ${I("to exit")} ${be("\u203A")} `;return new Promise(s=>{let n=()=>{e.question(t,r=>{let o=r.trim();if(o==="/"||o==="/help"||o==="help"||o==="?"){Ld(),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===""){Ld(),n();return}let d=(i.split(/\s+/)[0]??"").toLowerCase();Ow.has(d)?console.log(` ${I("Run")} ${oe(`recall ${i}`)} ${I("in your shell to invoke that command.")}`):console.log(` ${I(`No command matches "${o}". Type`)} ${oe("/")} ${I("to browse, or")} ${oe("recall --help")} ${I("for the full list.")}`),n()})};e.on("close",()=>{console.log(),s()}),n()})}async function Md(){let e=await Cw();console.log(),Id(),console.log();for(let t of Lw(e))console.log(t);console.log(),console.log(Nw(e)),console.log(),await Iw()}var Mw=[{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 Dw(){return process.env.NO_COLOR||process.env.CI||process.env.RECALL_NO_ANIMATION?!1:!!process.stdout.isTTY}function Co(e){return new Promise(t=>setTimeout(t,e))}function $w(e){let s=(e.split("@")[0]??"").split(/[._+\-]/)[0]??"";return s?s.charAt(0).toUpperCase()+s.slice(1).toLowerCase():""}function Nd(){process.stdout.write("\r\x1B[2K")}async function mn(e){let t=Dw();console.log(),Id(),console.log(),t&&(process.stdout.write(` ${I("Verifying license...")}`),await Co(260),Nd()),console.log(` ${wt("\u2713")} ${I("License verified")}`),console.log(` ${wt("\u2713")} ${I("Tier:")} ${oe("Pro")} ${I("\xB7 Lifetime")}`),console.log(` ${wt("\u2713")} ${I("Key:")} ${be(e.key_short)}`),console.log(` ${wt("\u2713")} ${I("Email:")} ${e.email}`),e.test_mode&&console.log(` ${un("!")} ${un("Test mode:")} this license was issued in test mode.`),console.log(),console.log(` ${Od("Unlocking Pro features")}`),console.log();for(let r of Mw)t&&(process.stdout.write(` ${I("\xB7")} ${I(r.name)}`),await Co(110),Nd()),console.log(` ${wt("\u2713")} ${r.name} ${I(r.detail)}`);t&&await Co(160),console.log();let s=$w(e.email),n=s?`Welcome aboard, ${s}.`:"Welcome aboard.";console.log(` ${oe(n)}`),console.log(` ${I("Run")} ${be("recall")} ${I("to open the dashboard, or")} ${be("recall help")} ${I("for the command list.")}`),console.log()}v();Vt();xs();At();ks();import{hostname as Pw}from"node:os";import{randomBytes as Fw}from"node:crypto";import{createInterface as jw}from"node:readline/promises";async function Uw(e){let t=e.fetchFn??fetch,s=`${e.apiBaseUrl}/api/trial/cli-redeem`,n=await t(s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({promo_code:e.promoCode,email:e.email,machine_fingerprint:e.fingerprint,instance_name:e.instanceName,referral_source:"cli"})}),r;try{r=await n.json()}catch{throw new Error(`server returned non-JSON (status ${n.status})`)}return{status:n.status,body:r}}async function Bw(e={}){let t=jw({input:e.stdin??process.stdin,output:e.stdout??process.stdout});try{return(await t.question(c.bold("Email for your 7-day trial: "))).trim().toLowerCase()}finally{t.close()}}function Hw(e){if(e.length<5||e.length>256||!e.includes("@"))return!1;let[t,s]=e.split("@");return!(!t||!s||!s.includes(".")||/\s/.test(e))}async function gn(e,t={}){let s=e.trim().toUpperCase();if(s.length<3&&(console.error(c.warn(`Promo code "${e}" is too short.`)),process.exit(1)),!t.skipExistingProCheck){let{getLicenseStatus:u}=await Promise.resolve().then(()=>(de(),Zt)),p=await u();if(p.tier==="pro"){console.log(),console.log(c.bold("You are already on Pro \u2014 no need to redeem a trial.")),console.log(` ${c.dim("Key:")} ${p.key_short}`),console.log(` ${c.dim("Email:")} ${p.customer_email}`),console.log(),console.log(c.dim("If you wanted to switch accounts, run `recall license deactivate` first.")),console.log();return}}console.log(),console.log(`${c.ok("Redeeming")} promo code ${c.bold(s)} for a 7-day Pro trial.`),console.log(c.dim("You will get an email with your license key for backup.")),console.log(),!t.promptFn&&!process.stdin.isTTY&&(console.error(c.warn("Trial activation needs an interactive terminal so you can type your email.")),console.error(c.dim("Re-run `recall activate "+s+"` in a terminal (not piped, not CI).")),process.exit(1));let r=await(t.promptFn??Bw)();Hw(r)||(console.error(c.warn(`"${r}" doesn't look like an email address.`)),process.exit(1));let o=t.instanceName??`${Pw()}-${Fw(4).toString("hex")}`,i=t.fingerprint??vt(),a=t.apiBaseUrl??tt(),d;try{d=await Uw({promoCode:s,email:r,fingerprint:i,instanceName:o,apiBaseUrl:a,...t.fetchFn?{fetchFn:t.fetchFn}:{}})}catch(u){let p=u instanceof Error?u.message:"unknown error";console.error(c.warn(`Could not reach the trial server at ${a}: ${p}`)),console.error(c.dim("If you are offline, try again when you have a connection.")),process.exit(1)}if(d.status!==200||!d.body.license_jwt||!d.body.license_key){let u=d.body.error??`trial activation failed (status ${d.status})`;console.error(c.warn(`Trial refused: ${u}`)),process.exit(1)}let l=await Ot(d.body.license_jwt);(!l.valid||!l.claims)&&(console.error(c.warn(`Server returned a JWT that fails local verification: ${l.reason??"unknown"}`)),console.error(c.dim("This usually means the CLI is older than the server. Try `npm i -g @clauderecallhq/cli`.")),process.exit(1)),Ts({license_jwt:d.body.license_jwt,license_key:d.body.license_key,key_short:d.body.key_short??l.claims.key_short,customer_email:d.body.customer_email??l.claims.email,activated_at:new Date().toISOString(),tier:"pro",test_mode:!!l.claims.test_mode}),t.skipSuccessDashboard||await mn({...l.claims,key_short:d.body.key_short??l.claims.key_short,email:d.body.customer_email??l.claims.email})}function Jw(e){return/^recall-pro-/i.test(e)}async function Dd(e){let t=e.trim();if(t.length<3&&(console.error(c.warn("License key or promo code looks too short.")),console.error(c.dim("Paste the full key from your purchase email, or a promo code like RECALL7DAY.")),process.exit(1)),!Jw(t)){await gn(t);return}t.length<8&&(console.error(c.warn("License key looks too short. Paste the full key from your purchase email.")),process.exit(1));let s=`${Ww()}-${Xw(4).toString("hex")}`,n=`${tt()}/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:vt()})})}catch(a){let d=a instanceof Error?a.message:"unknown error";console.error(c.warn(`Could not reach activation server at ${n}: ${d}`)),console.error(c.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(c.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(c.warn(`Activation refused: ${a}`)),process.exit(1)}let i=await Ot(o.license_jwt);(!i.valid||!i.claims)&&(console.error(c.warn(`Server returned a JWT that fails local verification: ${i.reason??"unknown"}`)),console.error(c.dim("This usually means the CLI is older than the server, or the public key was rotated.")),process.exit(1)),Ts({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 mn({...i.claims,key_short:o.key_short??i.claims.key_short,email:o.customer_email??i.claims.email})}v();import{spawn as Gw}from"node:child_process";import{platform as fn}from"node:os";var $d="https://clauderecall.com/pricing";function Yw(e){let t=fn()==="darwin"?"open":fn()==="win32"?"start":"xdg-open",s=fn()==="win32"?["",e]:[e];Gw(t,s,{detached:!0,stdio:"ignore",shell:fn()==="win32"}).unref()}async function Pd(){let{getLicenseStatus:e}=await Promise.resolve().then(()=>(de(),Zt)),t=await e();if(t.tier==="pro"){console.log(),console.log(c.bold("Already on Pro.")),console.log(` ${c.dim("Key:")} ${t.key_short}`),console.log(` ${c.dim("Email:")} ${t.customer_email}`),console.log();return}console.log(),console.log(`${c.ok("Opening")} ${$d}`),console.log(c.dim("After purchase, run: recall activate <license-key>")),console.log(),Yw($d)}v();import{spawn as zw}from"node:child_process";import{platform as _n}from"node:os";var Fd="https://clauderecall.com/pricing?trial=1&utm_source=cli&utm_medium=recall_trial";function qw(e){let t=_n()==="darwin"?"open":_n()==="win32"?"start":"xdg-open",s=_n()==="win32"?["",e]:[e];zw(t,s,{detached:!0,stdio:"ignore",shell:_n()==="win32"}).unref()}async function jd(e){if(e&&e.trim().length>0){await gn(e);return}let{getLicenseStatus:t}=await Promise.resolve().then(()=>(de(),Zt)),s=await t();if(s.tier==="pro"){console.log(),console.log(c.bold("You are already on Pro.")),console.log(` ${c.dim("Key:")} ${s.key_short}`),console.log(` ${c.dim("Email:")} ${s.customer_email}`),console.log();return}console.log(),console.log(`${c.ok("Opening")} ${Fd}`),console.log(c.dim("Enter your email to get a 7-day Pro trial link. No card.")),console.log(c.dim("After you click the verification email, run: recall activate <key>")),console.log(),console.log(c.dim("Tip: if you have a promo code, run `recall trial <CODE>` to skip the browser.")),console.log(),qw(Fd)}v();Vt();import{existsSync as Ud,mkdirSync as Kw,readFileSync as Vw,writeFileSync as Zw}from"node:fs";import{homedir as Qw}from"node:os";import{join as Bd}from"node:path";import{randomBytes as eT}from"node:crypto";var No=Bd(Qw(),".recall"),En=Bd(No,"telemetry.json"),Lo={decided_at:null,decision:null,last_ping_month:null,nonce_month:null,nonce:null,last_error:null};function Tt(){if(!Ud(En))return{...Lo};try{let e=Vw(En,"utf8"),t=JSON.parse(e);return{...Lo,...t}}catch{return{...Lo}}}function hn(e){Ud(No)||Kw(No,{recursive:!0}),Zw(En,JSON.stringify(e,null,2)+`
1672
+ `,{mode:384})}function Hd(){return En}function Ao(e=new Date){let t=e.getUTCFullYear(),s=String(e.getUTCMonth()+1).padStart(2,"0");return`${t}-${s}`}function Wd(e,t){return e.nonce&&e.nonce_month===t?e:{...e,nonce:eT(16).toString("hex"),nonce_month:t}}function tT(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 Xd(e){let t=Tt();if(t.decision!=="on")return{status:t.decision==="off"?"opted-out":"no-decision"};let s=Ao();if(t.last_ping_month===s)return{status:"already-this-month"};t=Wd(t,s);let n=tT(e,t);if(!n)return{status:"error",detail:"no nonce"};try{let r=await fetch(`${tt()}/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 hn({...t,last_error:`${new Date().toISOString()} ${i}`}),{status:"error",detail:i}}let o=await r.json().catch(()=>({}));return hn({...t,last_ping_month:s,last_error:null}),{status:o.deduped?"deduped":"sent"}}catch(r){let o=r instanceof Error?r.message:"unknown";return hn({...t,last_error:`${new Date().toISOString()} ${o}`}),{status:"error",detail:o}}}function jt(e){let s={...Tt(),decision:e,decided_at:new Date().toISOString(),last_error:null,...e==="off"?{nonce:null,nonce_month:null,last_ping_month:null}:{}};return hn(s),s}function bn(e){let t=Wd(Tt(),Ao());return{event:"install",version:e,platform:process.platform,arch:process.arch,month:t.nonce_month??Ao(),nonce:t.nonce??"0".repeat(32)}}async function Oo(e){let t=Tt();console.log(),console.log(c.bold("Telemetry \u2014 anonymous install ping")),console.log(` ${c.dim("decision:")} ${t.decision??"not yet decided"}`),console.log(` ${c.dim("decided at:")} ${t.decided_at??"\u2014"}`),console.log(` ${c.dim("last ping:")} ${t.last_ping_month??"\u2014"}`),console.log(` ${c.dim("state file:")} ${Hd()}`),t.last_error&&console.log(` ${c.warn("last error:")} ${t.last_error}`),console.log(),console.log(c.dim("Next-ping payload preview (only sent if decision = on):")),console.log(c.dim(JSON.stringify(bn(e),null,2))),console.log(),console.log(c.dim("Toggle with `recall telemetry on` / `recall telemetry off`.")),console.log(c.dim("Full disclosure: https://clauderecall.com/telemetry")),console.log()}async function Jd(){jt("on"),console.log(),console.log(c.ok("Telemetry: opted in.")),console.log(c.dim("One anonymous ping per machine per month. No PII. Source: docs/specs/v0.16-install-ping.md")),console.log(c.dim("Reverse with `recall telemetry off`.")),console.log()}async function Gd(){jt("off"),console.log(),console.log(c.ok("Telemetry: opted out.")),console.log(c.dim("No further pings will be sent. Existing nonce deleted.")),console.log()}async function Yd(e){await Oo(e)}import{createInterface as sT}from"node:readline/promises";import{stdin as zd,stdout as me}from"node:process";var nT=new Set(["telemetry","trial","upgrade","activate","license","help","version"]);function rT(e){return!(process.env.CI==="true"||process.env.RECALL_QUIET_INSTALL==="1"||process.env.RECALL_DISABLE_TELEMETRY_PROMPT==="1"||!zd.isTTY||!me.isTTY||e&&nT.has(e)||Tt().decision!==null)}async function qd(e,t){if(!rT(e))return;let s=bn(t);me.write(`
1676
1673
  `),me.write(` Claude Recall \u2014 anonymous install ping?
1677
1674
 
1678
1675
  `),me.write(` npm download counts mix real installs with bots and scanners.
@@ -1688,54 +1685,54 @@ Toggle with: recall verify on | off
1688
1685
 
1689
1686
  `),me.write(` Full disclosure: https://clauderecall.com/telemetry
1690
1687
 
1691
- `);let n=Yw({input:Jd,output:me}),r;try{r=(await n.question(" Send the install ping? [y/N]: ")).trim().toLowerCase()}finally{n.close()}r==="y"||r==="yes"?(Ft("on"),me.write(`
1688
+ `);let n=sT({input:zd,output:me}),r;try{r=(await n.question(" Send the install ping? [y/N]: ")).trim().toLowerCase()}finally{n.close()}r==="y"||r==="yes"?(jt("on"),me.write(`
1692
1689
  Opted in. Reverse any time with \`recall telemetry off\`.
1693
1690
 
1694
- `)):(Ft("off"),me.write(`
1691
+ `)):(jt("off"),me.write(`
1695
1692
  Opted out. No pings will be sent. Reverse with \`recall telemetry on\`.
1696
1693
 
1697
- `))}v();le();At();or();async function Gd(){let e=await Te();if(console.log(),e.tier==="free"){console.log(c.bold("Tier: Free")),console.log(c.dim("Free includes: index, list, show, projects, status, the daemon, and the basic web UI.")),e.invalid_reason&&(console.log(),console.log(c.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(c.bold("Tier: Pro")),console.log(` ${c.dim("Key:")} ${e.key_short}`),console.log(` ${c.dim("Email:")} ${e.customer_email}`),console.log(` ${c.dim("Activated:")} ${e.activated_at}`),e.expires_at&&console.log(` ${c.dim("Expires:")} ${e.expires_at}`),e.test_mode&&console.log(` ${c.warn("Test mode:")} this license was issued in test mode.`);let t=Cs();t&&console.log(` ${c.dim("Last server check:")} ${t.last_checked_at}`),console.log()}async function zd(){let e=await ur({force:!0});if(console.log(),!e.ran){console.log(c.warn("No license stored on this machine.")),console.log(c.dim("Run `recall activate <license-key>` first.")),console.log();return}if(!e.last_checked_at){console.log(c.warn("Could not reach the license server.")),console.log(c.dim("Network error. Try again when you have a connection.")),console.log();return}if(e.revoked){console.log(c.warn("License is revoked.")),e.reason&&console.log(` ${c.dim("Reason:")} ${e.reason}`),console.log(` ${c.dim("Checked:")} ${e.last_checked_at}`),console.log();return}console.log(c.ok("License is valid.")),console.log(` ${c.dim("Checked:")} ${e.last_checked_at}`),console.log()}function Kd(){Ai(),console.log(),console.log("License removed from this machine."),console.log(c.dim(`(${Et})`)),console.log()}w();v();import Kw from"cli-table3";function Me(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}
1694
+ `))}v();de();At();ar();async function Kd(){let e=await Te();if(console.log(),e.tier==="free"){console.log(c.bold("Tier: Free")),console.log(c.dim("Free includes: index, list, show, projects, status, the daemon, and the basic web UI.")),e.invalid_reason&&(console.log(),console.log(c.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(c.bold("Tier: Pro")),console.log(` ${c.dim("Key:")} ${e.key_short}`),console.log(` ${c.dim("Email:")} ${e.customer_email}`),console.log(` ${c.dim("Activated:")} ${e.activated_at}`),e.expires_at&&console.log(` ${c.dim("Expires:")} ${e.expires_at}`),e.test_mode&&console.log(` ${c.warn("Test mode:")} this license was issued in test mode.`);let t=Cs();t&&console.log(` ${c.dim("Last server check:")} ${t.last_checked_at}`),console.log()}async function Vd(){let e=await mr({force:!0});if(console.log(),!e.ran){console.log(c.warn("No license stored on this machine.")),console.log(c.dim("Run `recall activate <license-key>` first.")),console.log();return}if(!e.last_checked_at){console.log(c.warn("Could not reach the license server.")),console.log(c.dim("Network error. Try again when you have a connection.")),console.log();return}if(e.revoked){console.log(c.warn("License is revoked.")),e.reason&&console.log(` ${c.dim("Reason:")} ${e.reason}`),console.log(` ${c.dim("Checked:")} ${e.last_checked_at}`),console.log();return}console.log(c.ok("License is valid.")),console.log(` ${c.dim("Checked:")} ${e.last_checked_at}`),console.log()}function Zd(){$i(),console.log(),console.log("License removed from this machine."),console.log(c.dim(`(${ht})`)),console.log()}w();v();import oT from"cli-table3";function Me(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}
1698
1695
  `),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}"
1699
1696
  `),null;process.stderr.write(`ambiguous thread prefix "${e}" \u2014 candidates:
1700
- `);for(let n of s)process.stderr.write(` ${W(n.id)} ${n.name}
1697
+ `);for(let n of s)process.stderr.write(` ${X(n.id)} ${n.name}
1701
1698
  `);return null}function Rt(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}
1702
1699
  `),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}"
1703
1700
  `),null):(process.stderr.write(`ambiguous session prefix "${e}". be more specific.
1704
- `),null)}function qw(e){let t=new Map;if(e.length===0)return t;let s=e.map(()=>"?").join(","),r=_().prepare(`SELECT s.id,
1701
+ `),null)}function iT(e){let t=new Map;if(e.length===0)return t;let s=e.map(()=>"?").join(","),r=_().prepare(`SELECT s.id,
1705
1702
  s.first_user_message,
1706
1703
  p.name AS project_name,
1707
1704
  a.alias AS alias
1708
1705
  FROM sessions s
1709
1706
  LEFT JOIN projects p ON p.id = s.project_id
1710
1707
  LEFT JOIN session_aliases a ON a.session_id = s.id
1711
- WHERE s.id IN (${s})`).all(...e);for(let o of r)t.set(o.id,o);return t}function qd(e,t){let s=t.get(e),n=c.accent(W(e));if(!s)return`${n} ${c.dim("(unindexed)")}`;let r=s.alias??s.first_user_message??"",o=s.project_name?c.project(`[${s.project_name}] `):"";return`${n} ${o}${q(r,80)}`}function Ao(e){return e.archived?"archived":e.closed_at?"closed":"open"}function jt(e){let t=Ao(e);process.stderr.write(c.ok(`\u2713 ${e.name} ${c.dim(`(${W(e.id)})`)} [${t}]
1708
+ WHERE s.id IN (${s})`).all(...e);for(let o of r)t.set(o.id,o);return t}function Qd(e,t){let s=t.get(e),n=c.accent(X(e));if(!s)return`${n} ${c.dim("(unindexed)")}`;let r=s.alias??s.first_user_message??"",o=s.project_name?c.project(`[${s.project_name}] `):"";return`${n} ${o}${K(r,80)}`}function vo(e){return e.archived?"archived":e.closed_at?"closed":"open"}function Ut(e){let t=vo(e);process.stderr.write(c.ok(`\u2713 ${e.name} ${c.dim(`(${X(e.id)})`)} [${t}]
1712
1709
  `))}function xe(e,t,s){if(e){process.stdout.write(JSON.stringify(t,null,2)+`
1713
- `);return}s()}function Vd(e){let t=hr({includeArchived:e.archived===!0});xe(e.json===!0,t,()=>{if(t.length===0){console.log(c.dim("no threads. create one with `recall thread new <name>`."));return}let s=new Kw({head:[c.bold("id"),c.bold("name"),c.bold("sessions"),c.bold("origins"),c.bold("status"),c.bold("created")],colWidths:[10,40,10,9,10,16],wordWrap:!0,style:{head:[],border:["grey"]}});for(let n of t)s.push([c.accent(W(n.id)),q(n.name,38),String(n.session_count),String(n.origin_count),Ao(n),c.dim(X(n.created_at))]);console.log(s.toString()),console.log(c.dim(`${t.length} thread${t.length===1?"":"s"}.`+(e.archived?"":" add --archived to include archived.")))})}function Vw(e,t){let s=new Set(e.edges.map(a=>a.session_id)),n=new Map,r=[];for(let a of e.edges){let d=a.parent_session_id;if(a.role==="origin"||!d||!s.has(d)){r.push(a);continue}let l=n.get(d)??[];l.push(a),n.set(d,l)}let o=new Set,i=(a,d,l,u)=>{if(o.has(a.session_id))return;o.add(a.session_id);let p=u?"":l?"\u2514\u2500 ":"\u251C\u2500 ",m=a.role==="origin"?c.warn("[origin] "):"";process.stdout.write(`${d}${p}${m}${qd(a.session_id,t)}
1714
- `);let g=n.get(a.session_id)??[],f=u?"":d+(l?" ":"\u2502 ");g.forEach((h,E)=>{i(h,f,E===g.length-1,!1)})};r.forEach((a,d)=>i(a,"",d===r.length-1,!0));for(let a of e.edges)o.has(a.session_id)||process.stdout.write(`${c.warn("? ")}${qd(a.session_id,t)}
1715
- `)}function Zd(e,t){let s=Me(e);if(!s){process.exitCode=1;return}let n=Oe(s);if(!n){process.stderr.write(`thread not found: ${e}
1716
- `),process.exitCode=1;return}let r=qw(n.edges.map(o=>o.session_id));xe(t.json===!0,n,()=>{let o=Ao(n);if(console.log(c.bold(n.name)),console.log(c.dim(`id ${W(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 ${X(n.created_at)}`)),n.summary&&console.log(n.summary),console.log(),n.edges.length===0){console.log(c.dim("(no sessions linked \u2014 use `recall thread link ...`)"));return}Vw(n,r)})}function Qd(e,t){let s;if(t.origin){let r=Rt(t.origin);if(!r){process.exitCode=1;return}s=r}let n=aa({name:e,summary:t.summary??null,originSessionId:s});xe(t.json===!0,n,()=>{jt(n),process.stderr.write(c.dim(`id ${n.id}
1717
- `)),s&&process.stderr.write(c.dim(`origin: ${W(s)}
1718
- `))})}function eu(e,t){let s=Me(t.thread);if(!s){process.exitCode=1;return}let n=Rt(e);if(!n){process.exitCode=1;return}let r=null;if(t.parent){let a=Rt(t.parent);if(!a){process.exitCode=1;return}r=a}let o=t.role??(r?"child":"origin"),i=ca({threadId:s,sessionId:n,parentSessionId:r,role:o});xe(t.json===!0,i,()=>{process.stderr.write(c.ok(`\u2713 linked ${W(n)} \u2192 ${W(s)} [${o}]
1719
- `))})}function tu(e,t){let s=Me(t.thread);if(!s){process.exitCode=1;return}let n=Rt(e);if(!n){process.exitCode=1;return}let r=la(s,n);xe(t.json===!0,r,()=>{if(r.removed===0){process.stderr.write(c.warn(`(no edge existed for ${W(n)} in ${W(s)})
1720
- `));return}process.stderr.write(c.ok(`\u2713 unlinked ${W(n)} from ${W(s)}
1721
- `))})}function su(e,t){let s=Me(t.thread);if(!s){process.exitCode=1;return}let n=Rt(e);if(!n){process.exitCode=1;return}let r=null;if(t.parent&&t.parent.toLowerCase()!=="none"){let i=Rt(t.parent);if(!i){process.exitCode=1;return}r=i}let o=da(s,n,r);xe(t.json===!0,o,()=>{process.stderr.write(c.ok(`\u2713 ${W(n)} in ${W(s)} \u2192 `+(r?`child of ${W(r)}`:"origin")+`
1722
- `))})}function nu(e,t,s){let n=Me(e);if(!n){process.exitCode=1;return}let r=ua(n,t);xe(s.json===!0,r,()=>jt(r))}function ru(e,t){let s=Me(e);if(!s){process.exitCode=1;return}let n=pa(s);xe(t.json===!0,n,()=>jt(n))}function ou(e,t){let s=Me(e);if(!s){process.exitCode=1;return}let n=ma(s);xe(t.json===!0,n,()=>jt(n))}function iu(e,t){let s=Me(e);if(!s){process.exitCode=1;return}let n=ga(s);xe(t.json===!0,n,()=>jt(n))}function au(e,t){let s=Me(e);if(!s){process.exitCode=1;return}let n=Me(t.into);if(!n){process.exitCode=1;return}if(s===n){process.stderr.write(c.err(`cannot merge a thread into itself
1723
- `)),process.exitCode=1;return}let r=fa(s,n);xe(t.json===!0,r,()=>{process.stderr.write(c.ok(`\u2713 merged ${W(s)} \u2192 ${W(n)} (${r.session_count} sessions)
1724
- `))})}function cu(e,t){let s=Me(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(c.err(`--sessions must be a non-empty comma-separated list
1725
- `)),process.exitCode=1;return}let r=[];for(let i of n){let a=Rt(i);if(!a){process.exitCode=1;return}r.push(a)}let o=_a({threadId:s,sessionIds:r,newThreadName:t.name});xe(t.json===!0,o,()=>{jt(o),process.stderr.write(c.dim(`split off ${r.length} session${r.length===1?"":"s"} from ${W(s)}
1726
- `))})}w();v();import{randomUUID as ST}from"node:crypto";import{readFileSync as Zw,statSync as Qw}from"node:fs";var eT=200*1024*1024,vo=.7,Io=.5,uu=Io,tT=[{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"}],sT=["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 lu(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 nT(e,t){let s=t-e;if(s<0)return{weight:0,label:null};for(let n of tT)if(s<=n.maxGapMs)return{weight:n.weight,label:n.label};return{weight:0,label:null}}function rT(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 sT)if(o.includes(i))return{weight:t[n],matched:i,matchedIndex:n}}return{weight:0,matched:null,matchedIndex:-1}}function Oo(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 oT(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=Oo(n,r);o>s&&(s=o)}return s}function iT(e,t){let s=Oo(e.mean_embedding,t.mean_embedding),n=Oo(e.tail_pool,t.head_pool),r=oT(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 aT(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 cT(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 lT(e,t){let s=lu(e),n=lu(t);return s&&n&&s===n?{weight:.1,brand:s}:{weight:0,brand:null}}function du(e){return e.replace(/\s+/g," ").trim().toLowerCase()}function dT(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(`
1727
- `).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=du(t.recent_user_messages[0]);if(o.length>=200)for(let i of e.authored_content){let a=du(i);if(a.length<200)continue;let d=Math.min(a.length,240),l=a.slice(0,d);if(o.includes(l)){s+=.4,r=!0;break}}}return{weight:Math.min(.6,s),pathMatch:n,contentMatch:r}}function uT(e,t,s=uu){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=nT(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=rT(o),a=cT(e.touched_files,t.touched_files),d=lT(e.auto_title,t.auto_title),l=iT(e,t),u=aT(e,t),p=dT(e,t),m=r.weight+i.weight+a.weight+d.weight+l.weight+u.weight+p.weight;if(m<s)return null;let g=[];if(r.label&&g.push(`temporal ${r.label} (+${r.weight})`),i.matched){let f=i.matchedIndex===0?"opening message":`message #${i.matchedIndex+1}`;g.push(`continuation phrase "${i.matched}" in ${f} (+${i.weight})`)}if(a.count>0&&g.push(`${a.count} file${a.count===1?"":"s"} overlap (+${a.weight.toFixed(1)})`),d.brand&&g.push(`shared brand "${d.brand}" (+${d.weight})`),l.weight>0&&l.mode&&g.push(`semantic ${l.mode==="asymmetric"?"tail\u2192head":l.mode==="max_pool"?"best-chunk":"mean"} ${l.cosine.toFixed(2)} (+${l.weight.toFixed(2)})`),u.same&&g.push(`same cluster (+${u.weight})`),p.weight>0){let f=[];p.pathMatch&&f.push(`opened authored path "${p.pathMatch.split("/").pop()}"`),p.contentMatch&&f.push("verbatim-paste of authored content"),g.push(`doc-authorship: ${f.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:d.weight,semantic:l.weight,cluster:u.weight,doc_authorship:p.weight},reasons:g}}function pu(e,t=uu){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],d=uT(a,r,t);d&&(!o||d.confidence>o.confidence)&&(o=d)}o&&s.push(o)}return s}function mu(e,t){let s=new Map,n=a=>{let d=a;for(;s.get(d)!==d;)d=s.get(d);let l=a;for(;s.get(l)!==d;){let u=s.get(l);s.set(l,d),l=u}return d},r=(a,d)=>{let l=n(a),u=n(d);l!==u&&s.set(l,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 d=n(a),l=o.get(d);l||(l=[],o.set(d,l)),l.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((d,l)=>(i.get(d)??0)-(i.get(l)??0)),{rootId:a[0],sessionIds:a}))}function gu(e,t={}){let s=t.maxUserMessages??5,n=t.userMessageMaxLen??2e3,r=new Set,o=[],i=new Set,a=[],d;try{if(Qw(e).size>eT)return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a};d=Zw(e,"utf8")}catch{return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a}}let l=0;for(;l<d.length;){let u=d.indexOf(`
1728
- `,l),p=u===-1?d.length:u,m=d.slice(l,p);if(l=u===-1?d.length:u+1,!m.trim())continue;let g;try{g=JSON.parse(m)}catch{continue}let f=g;if(f.type==="user"&&f.message?.role==="user"&&typeof f.message.content=="string"&&o.length<s){let E=f.message.content.trim();E&&o.push(E.length>n?E.slice(0,n):E)}let h=f.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??{},T=typeof S.file_path=="string"?S.file_path:null;if(T){let R=En(T);R&&r.add(R)}if((b.name==="Write"||b.name==="Edit"||b.name==="MultiEdit")&&T){let R=En(T);R&&i.add(R);let k=typeof S.content=="string"?S.content:typeof S.new_string=="string"?S.new_string:null;k&&k.length>=200&&a.push(k.length>4096?k.slice(0,4096):k)}if(b.name==="Bash"&&typeof S.command=="string")for(let R of S.command.matchAll(/(?:^|[\s'"`(=])((?:\.\.?\/|\/|src\/|test\/|docs\/|site\/)[A-Za-z0-9_./-]+)/g)){let k=En(R[1]);k&&r.add(k)}if((b.name==="Glob"||b.name==="Grep")&&typeof S.pattern=="string"){let R=En(S.pattern);R&&!R.includes("*")&&r.add(R)}}}return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a}}function En(e){let t=e.trim().replace(/^['"]|['"]$/g,"");return!t||t.length<4||/[<>|;&\$`]/.test(t)?null:t}w();var fu=10,_u=20;function pT(e){if(!e)return!1;let t=e.split(`
1729
- `);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 mT(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 hu(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 Mo(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 hu(s)?s:null}function Eu(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,
1710
+ `);return}s()}function eu(e){let t=wr({includeArchived:e.archived===!0});xe(e.json===!0,t,()=>{if(t.length===0){console.log(c.dim("no threads. create one with `recall thread new <name>`."));return}let s=new oT({head:[c.bold("id"),c.bold("name"),c.bold("sessions"),c.bold("origins"),c.bold("status"),c.bold("created")],colWidths:[10,40,10,9,10,16],wordWrap:!0,style:{head:[],border:["grey"]}});for(let n of t)s.push([c.accent(X(n.id)),K(n.name,38),String(n.session_count),String(n.origin_count),vo(n),c.dim(J(n.created_at))]);console.log(s.toString()),console.log(c.dim(`${t.length} thread${t.length===1?"":"s"}.`+(e.archived?"":" add --archived to include archived.")))})}function aT(e,t){let s=new Set(e.edges.map(a=>a.session_id)),n=new Map,r=[];for(let a of e.edges){let d=a.parent_session_id;if(a.role==="origin"||!d||!s.has(d)){r.push(a);continue}let l=n.get(d)??[];l.push(a),n.set(d,l)}let o=new Set,i=(a,d,l,u)=>{if(o.has(a.session_id))return;o.add(a.session_id);let p=u?"":l?"\u2514\u2500 ":"\u251C\u2500 ",m=a.role==="origin"?c.warn("[origin] "):"";process.stdout.write(`${d}${p}${m}${Qd(a.session_id,t)}
1711
+ `);let g=n.get(a.session_id)??[],f=u?"":d+(l?" ":"\u2502 ");g.forEach((h,E)=>{i(h,f,E===g.length-1,!1)})};r.forEach((a,d)=>i(a,"",d===r.length-1,!0));for(let a of e.edges)o.has(a.session_id)||process.stdout.write(`${c.warn("? ")}${Qd(a.session_id,t)}
1712
+ `)}function tu(e,t){let s=Me(e);if(!s){process.exitCode=1;return}let n=Oe(s);if(!n){process.stderr.write(`thread not found: ${e}
1713
+ `),process.exitCode=1;return}let r=iT(n.edges.map(o=>o.session_id));xe(t.json===!0,n,()=>{let o=vo(n);if(console.log(c.bold(n.name)),console.log(c.dim(`id ${X(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 ${J(n.created_at)}`)),n.summary&&console.log(n.summary),console.log(),n.edges.length===0){console.log(c.dim("(no sessions linked \u2014 use `recall thread link ...`)"));return}aT(n,r)})}function su(e,t){let s;if(t.origin){let r=Rt(t.origin);if(!r){process.exitCode=1;return}s=r}let n=_a({name:e,summary:t.summary??null,originSessionId:s});xe(t.json===!0,n,()=>{Ut(n),process.stderr.write(c.dim(`id ${n.id}
1714
+ `)),s&&process.stderr.write(c.dim(`origin: ${X(s)}
1715
+ `))})}function nu(e,t){let s=Me(t.thread);if(!s){process.exitCode=1;return}let n=Rt(e);if(!n){process.exitCode=1;return}let r=null;if(t.parent){let a=Rt(t.parent);if(!a){process.exitCode=1;return}r=a}let o=t.role??(r?"child":"origin"),i=ha({threadId:s,sessionId:n,parentSessionId:r,role:o});xe(t.json===!0,i,()=>{process.stderr.write(c.ok(`\u2713 linked ${X(n)} \u2192 ${X(s)} [${o}]
1716
+ `))})}function ru(e,t){let s=Me(t.thread);if(!s){process.exitCode=1;return}let n=Rt(e);if(!n){process.exitCode=1;return}let r=Ea(s,n);xe(t.json===!0,r,()=>{if(r.removed===0){process.stderr.write(c.warn(`(no edge existed for ${X(n)} in ${X(s)})
1717
+ `));return}process.stderr.write(c.ok(`\u2713 unlinked ${X(n)} from ${X(s)}
1718
+ `))})}function ou(e,t){let s=Me(t.thread);if(!s){process.exitCode=1;return}let n=Rt(e);if(!n){process.exitCode=1;return}let r=null;if(t.parent&&t.parent.toLowerCase()!=="none"){let i=Rt(t.parent);if(!i){process.exitCode=1;return}r=i}let o=ba(s,n,r);xe(t.json===!0,o,()=>{process.stderr.write(c.ok(`\u2713 ${X(n)} in ${X(s)} \u2192 `+(r?`child of ${X(r)}`:"origin")+`
1719
+ `))})}function iu(e,t,s){let n=Me(e);if(!n){process.exitCode=1;return}let r=Sa(n,t);xe(s.json===!0,r,()=>Ut(r))}function au(e,t){let s=Me(e);if(!s){process.exitCode=1;return}let n=ya(s);xe(t.json===!0,n,()=>Ut(n))}function cu(e,t){let s=Me(e);if(!s){process.exitCode=1;return}let n=wa(s);xe(t.json===!0,n,()=>Ut(n))}function lu(e,t){let s=Me(e);if(!s){process.exitCode=1;return}let n=Ta(s);xe(t.json===!0,n,()=>Ut(n))}function du(e,t){let s=Me(e);if(!s){process.exitCode=1;return}let n=Me(t.into);if(!n){process.exitCode=1;return}if(s===n){process.stderr.write(c.err(`cannot merge a thread into itself
1720
+ `)),process.exitCode=1;return}let r=Ra(s,n);xe(t.json===!0,r,()=>{process.stderr.write(c.ok(`\u2713 merged ${X(s)} \u2192 ${X(n)} (${r.session_count} sessions)
1721
+ `))})}function uu(e,t){let s=Me(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(c.err(`--sessions must be a non-empty comma-separated list
1722
+ `)),process.exitCode=1;return}let r=[];for(let i of n){let a=Rt(i);if(!a){process.exitCode=1;return}r.push(a)}let o=xa({threadId:s,sessionIds:r,newThreadName:t.name});xe(t.json===!0,o,()=>{Ut(o),process.stderr.write(c.dim(`split off ${r.length} session${r.length===1?"":"s"} from ${X(s)}
1723
+ `))})}w();v();import{randomUUID as AT}from"node:crypto";import{readFileSync as cT,statSync as lT}from"node:fs";var dT=200*1024*1024,Mo=.7,Do=.5,gu=Do,uT=[{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"}],pT=["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 pu(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 mT(e,t){let s=t-e;if(s<0)return{weight:0,label:null};for(let n of uT)if(s<=n.maxGapMs)return{weight:n.weight,label:n.label};return{weight:0,label:null}}function gT(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 pT)if(o.includes(i))return{weight:t[n],matched:i,matchedIndex:n}}return{weight:0,matched:null,matchedIndex:-1}}function Io(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 fT(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=Io(n,r);o>s&&(s=o)}return s}function _T(e,t){let s=Io(e.mean_embedding,t.mean_embedding),n=Io(e.tail_pool,t.head_pool),r=fT(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 hT(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 ET(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 bT(e,t){let s=pu(e),n=pu(t);return s&&n&&s===n?{weight:.1,brand:s}:{weight:0,brand:null}}function mu(e){return e.replace(/\s+/g," ").trim().toLowerCase()}function ST(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(`
1724
+ `).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=mu(t.recent_user_messages[0]);if(o.length>=200)for(let i of e.authored_content){let a=mu(i);if(a.length<200)continue;let d=Math.min(a.length,240),l=a.slice(0,d);if(o.includes(l)){s+=.4,r=!0;break}}}return{weight:Math.min(.6,s),pathMatch:n,contentMatch:r}}function yT(e,t,s=gu){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=mT(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=gT(o),a=ET(e.touched_files,t.touched_files),d=bT(e.auto_title,t.auto_title),l=_T(e,t),u=hT(e,t),p=ST(e,t),m=r.weight+i.weight+a.weight+d.weight+l.weight+u.weight+p.weight;if(m<s)return null;let g=[];if(r.label&&g.push(`temporal ${r.label} (+${r.weight})`),i.matched){let f=i.matchedIndex===0?"opening message":`message #${i.matchedIndex+1}`;g.push(`continuation phrase "${i.matched}" in ${f} (+${i.weight})`)}if(a.count>0&&g.push(`${a.count} file${a.count===1?"":"s"} overlap (+${a.weight.toFixed(1)})`),d.brand&&g.push(`shared brand "${d.brand}" (+${d.weight})`),l.weight>0&&l.mode&&g.push(`semantic ${l.mode==="asymmetric"?"tail\u2192head":l.mode==="max_pool"?"best-chunk":"mean"} ${l.cosine.toFixed(2)} (+${l.weight.toFixed(2)})`),u.same&&g.push(`same cluster (+${u.weight})`),p.weight>0){let f=[];p.pathMatch&&f.push(`opened authored path "${p.pathMatch.split("/").pop()}"`),p.contentMatch&&f.push("verbatim-paste of authored content"),g.push(`doc-authorship: ${f.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:d.weight,semantic:l.weight,cluster:u.weight,doc_authorship:p.weight},reasons:g}}function fu(e,t=gu){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],d=yT(a,r,t);d&&(!o||d.confidence>o.confidence)&&(o=d)}o&&s.push(o)}return s}function _u(e,t){let s=new Map,n=a=>{let d=a;for(;s.get(d)!==d;)d=s.get(d);let l=a;for(;s.get(l)!==d;){let u=s.get(l);s.set(l,d),l=u}return d},r=(a,d)=>{let l=n(a),u=n(d);l!==u&&s.set(l,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 d=n(a),l=o.get(d);l||(l=[],o.set(d,l)),l.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((d,l)=>(i.get(d)??0)-(i.get(l)??0)),{rootId:a[0],sessionIds:a}))}function hu(e,t={}){let s=t.maxUserMessages??5,n=t.userMessageMaxLen??2e3,r=new Set,o=[],i=new Set,a=[],d;try{if(lT(e).size>dT)return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a};d=cT(e,"utf8")}catch{return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a}}let l=0;for(;l<d.length;){let u=d.indexOf(`
1725
+ `,l),p=u===-1?d.length:u,m=d.slice(l,p);if(l=u===-1?d.length:u+1,!m.trim())continue;let g;try{g=JSON.parse(m)}catch{continue}let f=g;if(f.type==="user"&&f.message?.role==="user"&&typeof f.message.content=="string"&&o.length<s){let E=f.message.content.trim();E&&o.push(E.length>n?E.slice(0,n):E)}let h=f.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??{},R=typeof S.file_path=="string"?S.file_path:null;if(R){let T=Sn(R);T&&r.add(T)}if((b.name==="Write"||b.name==="Edit"||b.name==="MultiEdit")&&R){let T=Sn(R);T&&i.add(T);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 T of S.command.matchAll(/(?:^|[\s'"`(=])((?:\.\.?\/|\/|src\/|test\/|docs\/|site\/)[A-Za-z0-9_./-]+)/g)){let L=Sn(T[1]);L&&r.add(L)}if((b.name==="Glob"||b.name==="Grep")&&typeof S.pattern=="string"){let T=Sn(S.pattern);T&&!T.includes("*")&&r.add(T)}}}return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a}}function Sn(e){let t=e.trim().replace(/^['"]|['"]$/g,"");return!t||t.length<4||/[<>|;&\$`]/.test(t)?null:t}w();var Eu=10,bu=20;function wT(e){if(!e)return!1;let t=e.split(`
1726
+ `);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 TT(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 Su(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 $o(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 Su(s)?s:null}function yu(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,
1730
1727
  cm.text AS text, v.embedding AS embedding
1731
1728
  FROM chunk_meta cm
1732
1729
  JOIN vec_chunks v ON v.rowid = cm.rowid
1733
1730
  WHERE cm.stale = 0
1734
1731
  AND cm.session_id IN (${n})
1735
- 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 d=a.filter(R=>!pT(R.text)),l=d.length>0?d:a,u=[];for(let R of l){let k=mT(R.embedding);k&&hu(k)&&u.push(k)}if(u.length===0)continue;let p=Math.min(fu,u.length),m=Math.max(0,u.length-fu),g=u.slice(0,p),f=u.slice(m),h=Mo(g),E=Mo(f),b=Mo(u),S=new Map;for(let R=0;R<g.length&&S.size<_u;R++)S.set(R,g[R]);for(let R=0;R<f.length&&S.size<_u;R++)S.set(m+R,f[R]);let T=Array.from(S.values());t.set(i,{session_id:i,full_mean:b,head_pool:h,tail_pool:E,sample_chunks:T})}return t}function gT(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 bu(e,t=.8){let s=new Map,n=[],r=[];for(let[l,u]of e)u.full_mean&&(n.push(l),r.push(u.full_mean));if(n.length===0)return s;let o=new Int32Array(n.length);for(let l=0;l<o.length;l++)o[l]=l;let i=l=>{let u=l;for(;o[u]!==u;)u=o[u];let p=l;for(;o[p]!==u;){let m=o[p];o[p]=u,p=m}return u},a=(l,u)=>{let p=i(l),m=i(u);p!==m&&(o[p]=m)};for(let l=0;l<n.length;l++)for(let u=l+1;u<n.length;u++)gT(r[l],r[u])>=t&&a(l,u);let d=new Map;for(let l=0;l<n.length;l++){let u=i(l),p=d.get(u);p===void 0&&(p=d.size,d.set(u,p)),s.set(n[l],p)}return s}var ds={lo:.4,hi:.7},bn="claude-haiku-4-5-20251001",Su=50;var fT={same_workflow:.15,unrelated:-.2,unsure:0};function yu(e,t,s=ds){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 _T(e,t){let s=e.replace(/\s+/g," ").trim();return s.length>t?s.slice(0,t-1)+"\u2026":s}function hT(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 ET(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=l=>l.length===0?" (none captured)":l.map(u=>` - ${_T(u,500)}`).join(`
1736
- `),d=hT(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(l=>` - ${l}`).join(`
1732
+ 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 d=a.filter(T=>!wT(T.text)),l=d.length>0?d:a,u=[];for(let T of l){let L=TT(T.embedding);L&&Su(L)&&u.push(L)}if(u.length===0)continue;let p=Math.min(Eu,u.length),m=Math.max(0,u.length-Eu),g=u.slice(0,p),f=u.slice(m),h=$o(g),E=$o(f),b=$o(u),S=new Map;for(let T=0;T<g.length&&S.size<bu;T++)S.set(T,g[T]);for(let T=0;T<f.length&&S.size<bu;T++)S.set(m+T,f[T]);let R=Array.from(S.values());t.set(i,{session_id:i,full_mean:b,head_pool:h,tail_pool:E,sample_chunks:R})}return t}function RT(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 wu(e,t=.8){let s=new Map,n=[],r=[];for(let[l,u]of e)u.full_mean&&(n.push(l),r.push(u.full_mean));if(n.length===0)return s;let o=new Int32Array(n.length);for(let l=0;l<o.length;l++)o[l]=l;let i=l=>{let u=l;for(;o[u]!==u;)u=o[u];let p=l;for(;o[p]!==u;){let m=o[p];o[p]=u,p=m}return u},a=(l,u)=>{let p=i(l),m=i(u);p!==m&&(o[p]=m)};for(let l=0;l<n.length;l++)for(let u=l+1;u<n.length;u++)RT(r[l],r[u])>=t&&a(l,u);let d=new Map;for(let l=0;l<n.length;l++){let u=i(l),p=d.get(u);p===void 0&&(p=d.size,d.set(u,p)),s.set(n[l],p)}return s}var ds={lo:.4,hi:.7},yn="claude-haiku-4-5-20251001",Tu=50;var xT={same_workflow:.15,unrelated:-.2,unsure:0};function Ru(e,t,s=ds){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 kT(e,t){let s=e.replace(/\s+/g," ").trim();return s.length>t?s.slice(0,t-1)+"\u2026":s}function CT(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 LT(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=l=>l.length===0?" (none captured)":l.map(u=>` - ${kT(u,500)}`).join(`
1733
+ `),d=CT(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(l=>` - ${l}`).join(`
1737
1734
  `),` step1_confidence: ${e.step1.confidence.toFixed(2)}`,"","PARENT SESSION","First user messages:",a(r),"Last user messages:",a(o),"",`CHILD SESSION (gap from parent: ${d})`,"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(`
1738
- `)}function bT(e){if(!e)return null;let t=e.trim();if(!t)return null;let s=t;try{let d=JSON.parse(t);typeof d.result=="string"&&(s=d.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:fT[i]}}async function wu(e,t={}){if(t.signal?.aborted)return null;let s=t.model??bn,n=ET(e),r=t.spawn;if(!r)try{let i=await Promise.resolve().then(()=>(Be(),Fs));if(!i.isClaudeCliAvailable())return null;r=(a,d)=>i.spawnClaudePrompt(a,[],d)}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:bT(o.stdout)}function Tu(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 Ru(e){return`${e.parent_id}::${e.child_id}`}async function yT(e){if(e.signal?.aborted)return null;let t,s;try{({spawnClaudePrompt:t,isClaudeCliAvailable:s}=await Promise.resolve().then(()=>(Be(),Fs)))}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:
1735
+ `)}function NT(e){if(!e)return null;let t=e.trim();if(!t)return null;let s=t;try{let d=JSON.parse(t);typeof d.result=="string"&&(s=d.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:xT[i]}}async function xu(e,t={}){if(t.signal?.aborted)return null;let s=t.model??yn,n=LT(e),r=t.spawn;if(!r)try{let i=await Promise.resolve().then(()=>(Be(),Us));if(!i.isClaudeCliAvailable())return null;r=(a,d)=>i.spawnClaudePrompt(a,[],d)}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:NT(o.stdout)}function ku(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 Cu(e){return`${e.parent_id}::${e.child_id}`}async function OT(e){if(e.signal?.aborted)return null;let t,s;try{({spawnClaudePrompt:t,isClaudeCliAvailable:s}=await Promise.resolve().then(()=>(Be(),Us)))}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:
1739
1736
  - 4 to 8 words
1740
1737
  - Title-case, no trailing punctuation
1741
1738
  - Capture the WORKFLOW (e.g., "Update Remotion deps + lint cleanup"), not any one session
@@ -1746,7 +1743,7 @@ Sessions:
1746
1743
  `+n.join(`
1747
1744
  `)+`
1748
1745
 
1749
- 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}))}),d=await Promise.race([o,a]);if(i&&e.signal&&e.signal.removeEventListener("abort",i),!d||!d.success)return null;let l=d.stdout.trim();if(!l)return null;let u;try{let p=JSON.parse(l);u=typeof p.result=="string"?p.result:l}catch{u=l}return u=u.trim().replace(/^["'`]+|["'`]+$/g,"").replace(/[.!?]+$/g,"").trim(),u?u.length>80?u.slice(0,77)+"...":u:null}catch{return null}}function wT(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=Eu(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 d=bu(a,.8),l=[];for(let u of i){let p=RT(u,n,d);p&&l.push(p)}r.set(o,l)}return{byProject:t,scannablesByProject:r}}function TT(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,
1746
+ 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}))}),d=await Promise.race([o,a]);if(i&&e.signal&&e.signal.removeEventListener("abort",i),!d||!d.success)return null;let l=d.stdout.trim();if(!l)return null;let u;try{let p=JSON.parse(l);u=typeof p.result=="string"?p.result:l}catch{u=l}return u=u.trim().replace(/^["'`]+|["'`]+$/g,"").replace(/[.!?]+$/g,"").trim(),u?u.length>80?u.slice(0,77)+"...":u:null}catch{return null}}function vT(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=yu(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 d=wu(a,.8),l=[];for(let u of i){let p=MT(u,n,d);p&&l.push(p)}r.set(o,l)}return{byProject:t,scannablesByProject:r}}function IT(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,
1750
1747
  s.first_user_message, s.auto_title,
1751
1748
  NULLIF(sa.alias, '') AS alias,
1752
1749
  s.file_path
@@ -1754,40 +1751,40 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1754
1751
  JOIN projects p ON p.id = s.project_id
1755
1752
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1756
1753
  WHERE ${n}
1757
- ORDER BY p.name ASC, s.started_at ASC`).all(s)}function RT(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=gu(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 Sn(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 xu(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 ku(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 xT(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??ds,s=e.rescore.cap??Su,n=e.rescore.model??bn,r=new Map(e.scannables.map(m=>[m.id,m])),o=yu(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,d=0,l=0,u=0;for(let m=0;m<o.length&&!e.signal?.aborted;m++){let g=o[m],f=await wu(g,{model:n,signal:e.signal});f?(i.set(Ru(g.step1),f),f.verdict==="same_workflow"?a++:f.verdict==="unrelated"?d++:l++):u++,e.onProgress?.({phase:"rescoring",current:m+1,total:o.length,verdict:f?.verdict??"failed"})}return{proposals:Tu({proposals:e.proposals,rescored:i,applyThreshold:e.applyThreshold}),ran:!0,considered:o.length,promoted:a,demoted:d,unsure:l,failed:u,capped:!1}}async function kT(e){let t=_(),s=new Map(e.rows.map(l=>[l.id,l])),n=mu(e.edges,e.scannables),r=new Date().toISOString(),o=[],i=new Map,a=0;for(let l of n){if(a++,e.signal?.aborted)break;let u=s.get(l.rootId),p=ku(u);if(!e.llmNames){i.set(l.rootId,p),e.onProgress?.({phase:"naming",current:a,total:n.length,thread_name:p});continue}let g=await yT({rootRow:u,sessionIds:l.sessionIds,rowById:s,signal:e.signal,model:e.model})??p;i.set(l.rootId,g),e.onProgress?.({phase:"naming",current:a,total:n.length,thread_name:g})}return t.transaction(()=>{for(let l of n){if(!i.has(l.rootId))continue;let u=s.get(l.rootId),p=`auto-scan-${ST()}`,m=i.get(l.rootId)??ku(u),g=`Auto-detected workflow chain (${l.sessionIds.length} sessions). Source: auto-scan-v1.`;t.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, ?, ?)").run(p,m,g,r),t.prepare(`INSERT INTO thread_edges
1754
+ ORDER BY p.name ASC, s.started_at ASC`).all(s)}function MT(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=hu(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 wn(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 Lu(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 Nu(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 DT(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??ds,s=e.rescore.cap??Tu,n=e.rescore.model??yn,r=new Map(e.scannables.map(m=>[m.id,m])),o=Ru(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,d=0,l=0,u=0;for(let m=0;m<o.length&&!e.signal?.aborted;m++){let g=o[m],f=await xu(g,{model:n,signal:e.signal});f?(i.set(Cu(g.step1),f),f.verdict==="same_workflow"?a++:f.verdict==="unrelated"?d++:l++):u++,e.onProgress?.({phase:"rescoring",current:m+1,total:o.length,verdict:f?.verdict??"failed"})}return{proposals:ku({proposals:e.proposals,rescored:i,applyThreshold:e.applyThreshold}),ran:!0,considered:o.length,promoted:a,demoted:d,unsure:l,failed:u,capped:!1}}async function $T(e){let t=_(),s=new Map(e.rows.map(l=>[l.id,l])),n=_u(e.edges,e.scannables),r=new Date().toISOString(),o=[],i=new Map,a=0;for(let l of n){if(a++,e.signal?.aborted)break;let u=s.get(l.rootId),p=Nu(u);if(!e.llmNames){i.set(l.rootId,p),e.onProgress?.({phase:"naming",current:a,total:n.length,thread_name:p});continue}let g=await OT({rootRow:u,sessionIds:l.sessionIds,rowById:s,signal:e.signal,model:e.model})??p;i.set(l.rootId,g),e.onProgress?.({phase:"naming",current:a,total:n.length,thread_name:g})}return t.transaction(()=>{for(let l of n){if(!i.has(l.rootId))continue;let u=s.get(l.rootId),p=`auto-scan-${AT()}`,m=i.get(l.rootId)??Nu(u),g=`Auto-detected workflow chain (${l.sessionIds.length} sessions). Source: auto-scan-v1.`;t.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, ?, ?)").run(p,m,g,r),t.prepare(`INSERT INTO thread_edges
1758
1755
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
1759
1756
  VALUES (?, ?, NULL, 'origin', 1.0, 'auto-scan-v1', ?)`).run(p,l.rootId,r);let f=new Map;for(let h of e.edges)l.sessionIds.includes(h.child_id)&&f.set(h.child_id,h);for(let h of l.sessionIds){if(h===l.rootId)continue;let E=f.get(h);E&&t.prepare(`INSERT INTO thread_edges
1760
1757
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
1761
- VALUES (?, ?, ?, 'child', ?, 'auto-scan-v1', ?)`).run(p,h,E.parent_id,E.confidence,r)}o.push({thread_id:p,name:m,session_count:l.sessionIds.length})}})(),{project:e.project,threads:o}}async function Cu(e){let t=!!e.apply,s=e.confidenceMin?Number(e.confidenceMin):t?vo:Io;if(!Number.isFinite(s)||s<0||s>1){console.error(c.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):ds.lo,hi:e.rescoreBandHi?Number(e.rescoreBandHi):ds.hi};if(n&&(!Number.isFinite(r.lo)||!Number.isFinite(r.hi)||r.lo<0||r.hi>1||r.lo>r.hi)){console.error(c.err("--rescore-band-lo/hi must satisfy 0 \u2264 lo \u2264 hi \u2264 1")),process.exitCode=1;return}let o=e.rescoreModel??bn,i=TT({project:e.project});if(i.length===0){console.log(c.dim("no sessions matched"));return}let{byProject:a,scannablesByProject:d}=wT(i),l=n?Math.min(s,r.lo):s,u=new Map,p=0;for(let[g]of a){let f=d.get(g)??[],h=pu(f,l);if(n&&h.length>0){let E=await xT({proposals:h,scannables:f,applyThreshold:s,rescore:{enabled:!0,band:r,model:o}});h=E.proposals,E.capped?(console.error(c.err(`[${g}] 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(g,{proposals:h,scannables:f}),p+=h.length}if(t){if(p===0){console.log(c.dim("no edges above threshold; nothing to apply"));return}let g={threads_created:0,edges_written:0,per_project:[]},f=!e.noLlmNames;for(let[h,{proposals:E,scannables:b}]of u){if(E.length===0)continue;let S=await kT({project:h,rows:a.get(h),edges:E,scannables:b,llmNames:f});g.per_project.push(S),g.threads_created+=S.threads.length,g.edges_written+=E.length+S.threads.length}if(e.json){console.log(JSON.stringify({mode:"apply",threshold:s,...g},null,2));return}console.log(c.ok(`Applied ${g.threads_created} thread${g.threads_created===1?"":"s"} with ${g.edges_written} edges total (threshold ${s}).`));for(let h of g.per_project){console.log(` ${c.bold(h.project)}`);for(let E of h.threads)console.log(` ${c.dim(E.thread_id.slice(0,16)+"\u2026")} ${E.name} ${c.dim(`(${E.session_count} sessions)`)}`)}console.log(),console.log(c.dim("Rollback: sqlite3 ~/.recall/db.sqlite \\")),console.log(c.dim(` "DELETE FROM thread_edges WHERE source='auto-scan-v1';`)),console.log(c.dim(` DELETE FROM threads WHERE id LIKE 'auto-scan-%';"`));return}if(e.json){let g=[];for(let[f,{proposals:h}]of u){let E=new Map(a.get(f).map(b=>[b.id,b]));for(let b of h)g.push({project:f,parent_id:b.parent_id,parent_label:Sn(E.get(b.parent_id)),child_id:b.child_id,child_label:Sn(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:g},null,2));return}console.log(c.dim(`recall thread scan \xB7 ${a.size} project${a.size===1?"":"s"} \xB7 DRY RUN \xB7 threshold ${s}`)),console.log(c.dim(" Algorithm: temporal + continuation phrase + file overlap + same brand.")),console.log();for(let[g,f]of a){let{proposals:h}=u.get(g),E=new Map(f.map(S=>[S.id,S]));if(console.log(c.bold(g)),console.log(c.dim(` ${f.length} eligible session${f.length===1?"":"s"}; ${h.length} parent-child edge${h.length===1?"":"s"} proposed.`)),h.length===0){console.log(c.dim(" (no edges above threshold \u2014 all sessions are origins)")),console.log();continue}let b=[...h].sort((S,T)=>{let R=E.get(S.child_id),k=E.get(T.child_id);return(R.started_at??"").localeCompare(k.started_at??"")});for(let S of b){let T=E.get(S.parent_id),R=E.get(S.child_id),k=S.confidence.toFixed(2);console.log(` ${c.dim(xu(T.started_at).padEnd(16))} ${c.bold("PARENT")} ${Sn(T)}`),console.log(` ${c.dim(xu(R.started_at).padEnd(16))} ${c.bold(" \u2514\u2500 child")} ${Sn(R)} ${c.dim(`[conf ${k}]`)}`),console.log(` ${" ".repeat(28)}${c.dim(S.reasons.join(" \xB7 "))}`),console.log()}}let m=Array.from(a.entries()).reduce((g,[f,h])=>g+(h.length-(u.get(f)?.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(c.dim(` This is a DRY RUN. To write: rerun with --apply (default threshold ${vo}).`))}v();D();import{existsSync as CT,readFileSync as LT}from"node:fs";function NT(){let e=`${x}/daemon.port`;if(!CT(e))return null;try{let t=LT(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function AT(e){try{return(await ze(`http://127.0.0.1:${e}/api/health`,{signal:AbortSignal.timeout(1e4)})).ok}catch{return!1}}async function OT(e){let t=await ze(`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 vT(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 IT(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 Lu(e){return e.alias||e.auto_title||(e.first_user_message?q(e.first_user_message,60):"(no title)")}function MT(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 DT(e,t){let s=t==="preflight"?c.dim(`recall threads sync \xB7 ${e.project.name} \xB7 PREFLIGHT (no writes)`):c.dim(`recall threads sync \xB7 ${e.project.name}`);if(console.log(s),console.log(),e.thread.exists?console.log(` ${c.bold("Thread")} ${e.thread.name} ${c.dim(`(reusing, ${e.thread.existing_session_count} existing session${e.thread.existing_session_count===1?"":"s"})`)}`):console.log(` ${c.bold("Thread")} ${e.thread.name} ${c.ok("(new)")}`),console.log(),e.candidates.length===0){if(console.log(c.dim(" No active sessions in the rolling window.")),e.warnings.length>0)for(let l of e.warnings)console.log(c.warn(` \u26A0 ${l}`));return}let n=new Map;for(let l of e.proposed_edges)n.set(l.child_id,l);let r=new Map;for(let l of e.preserved_manual_edges)r.set(l.session_id,l.parent_session_id);let o=new Set(e.candidates.map(l=>l.session_id)),i=e.proposed_additions.length,a=e.candidates.length-i;console.log(` ${c.bold("Candidates")} ${e.candidates.length} active session${e.candidates.length===1?"":"s"} ${c.dim(`(${i} new \xB7 ${a} keep)`)}`);let d=String(e.candidates.length).length;for(let l=0;l<e.candidates.length;l++){let u=e.candidates[l],m=e.proposed_additions.some(S=>S.session_id===u.session_id)?c.ok("NEW "):c.dim("keep"),g=n.get(u.session_id)??(r.has(u.session_id)&&r.get(u.session_id)!==null,null),f=g&&o.has(g.parent_id)?" \u2514\u2500 ":" ",h=MT(u.started_at),E=c.dim(`${String(l+1).padStart(d," ")}.`);console.log(` ${E} ${m} ${c.dim(h.padEnd(16))} ${f}${c.dim(u.session_id.slice(0,8))} ${Lu(u)}`);let b=" ".repeat(d+2);if(g&&o.has(g.parent_id)){let S=g.confidence.toFixed(2),T=Lu(e.candidates.find(R=>R.session_id===g.parent_id));console.log(` ${b}${" ".repeat(28)} parent ${c.dim(g.parent_id.slice(0,8))} (${T}) ${c.dim(`[conf ${S}]`)}`),console.log(` ${b}${" ".repeat(28)} ${c.dim(g.reasons.join(" \xB7 "))}`)}if(r.has(u.session_id)){let S=r.get(u.session_id);S&&console.log(` ${b}${" ".repeat(28)} ${c.bold("manual parent preserved")} ${c.dim(S.slice(0,8))}`)}}if(e.preserved_manual_edges.length>0&&(console.log(),console.log(c.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 l of e.warnings)console.log(c.warn(` \u26A0 ${l}`))}}function $T(e){console.log(),console.log(c.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(c.dim(` thread_id: ${e.thread_id}`))}async function Nu(e){let t=NT();if(!t){console.error(c.err("Daemon is not running. Start it with `recall start`, then re-run this command.")),process.exitCode=1;return}if(!await AT(t)){console.error(c.err(`Daemon on port ${t} is not responding. Try \`recall stop && recall start\`.`)),process.exitCode=1;return}let n;try{n=await OT(t)}catch(l){console.error(c.err(l.message)),process.exitCode=1;return}let r;if(e.project){if(r=IT(n,e.project),!r){console.error(c.err(`No project matching "${e.project}". Run \`recall projects\` to list known projects.`)),process.exitCode=1;return}}else{let l=process.cwd();if(r=vT(n,l),!r){console.error(c.err(`Current directory (${l}) 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(c.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 d;try{let l=await tt("POST",`http://127.0.0.1:${t}/api/threads/sync-active`,a);if(!l.ok){let u=await l.text().catch(()=>"");throw new Error(`HTTP ${l.status}: ${u.slice(0,200)}`)}d=await l.json()}catch(l){console.error(c.err(`Sync failed: ${l.message}`)),process.exitCode=1;return}if(e.json){console.log(JSON.stringify({mode:i,...d},null,2));return}DT(d.plan,i),i==="apply"&&d.result?$T(d.result):i==="preflight"&&(console.log(),console.log(c.dim(" This is a PREFLIGHT. To write: re-run without --preflight.")))}w();import{writeFileSync as oR,existsSync as iR,mkdirSync as aR}from"node:fs";import{join as zu}from"node:path";import{homedir as cR}from"node:os";import{execSync as Wt}from"node:child_process";st();import tR from"satori";import sR from"sharp";import{readFileSync as jo}from"node:fs";import{join as Nn}from"node:path";var Uo=Nn(de(),"dist","share","fonts"),Ju=!1,Yu=[];function nR(){return Ju||(Yu=[{name:"Inter",data:jo(Nn(Uo,"Inter-Regular.woff")),weight:400,style:"normal"},{name:"Inter",data:jo(Nn(Uo,"Inter-Bold.woff")),weight:700,style:"normal"},{name:"JetBrains Mono",data:jo(Nn(Uo,"JetBrainsMono-Regular.woff")),weight:400,style:"normal"}],Ju=!0),Yu}async function rR(e){switch(e){case"A":return await Promise.resolve().then(()=>(Iu(),vu));case"B":return await Promise.resolve().then(()=>($u(),Du));case"C":return await Promise.resolve().then(()=>(ju(),Fu));case"D":return await Promise.resolve().then(()=>(Hu(),Bu));case"E":return await Promise.resolve().then(()=>(Xu(),Wu))}}async function An(e,t){let n=(await rR(e)).render(t),i=await tR(n,{width:1080,height:e==="E"?1920:1350,fonts:nR()});return await sR(Buffer.from(i)).png({quality:90}).toBuffer()}function Gu(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 lR(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.
1762
- `),null)}function dR(e){return e.prepare("SELECT session_id FROM recall_events ORDER BY recalled_at DESC LIMIT 1").get()?.session_id??null}function uR(e,t){let s=e.prepare(`
1758
+ VALUES (?, ?, ?, 'child', ?, 'auto-scan-v1', ?)`).run(p,h,E.parent_id,E.confidence,r)}o.push({thread_id:p,name:m,session_count:l.sessionIds.length})}})(),{project:e.project,threads:o}}async function Au(e){let t=!!e.apply,s=e.confidenceMin?Number(e.confidenceMin):t?Mo:Do;if(!Number.isFinite(s)||s<0||s>1){console.error(c.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):ds.lo,hi:e.rescoreBandHi?Number(e.rescoreBandHi):ds.hi};if(n&&(!Number.isFinite(r.lo)||!Number.isFinite(r.hi)||r.lo<0||r.hi>1||r.lo>r.hi)){console.error(c.err("--rescore-band-lo/hi must satisfy 0 \u2264 lo \u2264 hi \u2264 1")),process.exitCode=1;return}let o=e.rescoreModel??yn,i=IT({project:e.project});if(i.length===0){console.log(c.dim("no sessions matched"));return}let{byProject:a,scannablesByProject:d}=vT(i),l=n?Math.min(s,r.lo):s,u=new Map,p=0;for(let[g]of a){let f=d.get(g)??[],h=fu(f,l);if(n&&h.length>0){let E=await DT({proposals:h,scannables:f,applyThreshold:s,rescore:{enabled:!0,band:r,model:o}});h=E.proposals,E.capped?(console.error(c.err(`[${g}] 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(g,{proposals:h,scannables:f}),p+=h.length}if(t){if(p===0){console.log(c.dim("no edges above threshold; nothing to apply"));return}let g={threads_created:0,edges_written:0,per_project:[]},f=!e.noLlmNames;for(let[h,{proposals:E,scannables:b}]of u){if(E.length===0)continue;let S=await $T({project:h,rows:a.get(h),edges:E,scannables:b,llmNames:f});g.per_project.push(S),g.threads_created+=S.threads.length,g.edges_written+=E.length+S.threads.length}if(e.json){console.log(JSON.stringify({mode:"apply",threshold:s,...g},null,2));return}console.log(c.ok(`Applied ${g.threads_created} thread${g.threads_created===1?"":"s"} with ${g.edges_written} edges total (threshold ${s}).`));for(let h of g.per_project){console.log(` ${c.bold(h.project)}`);for(let E of h.threads)console.log(` ${c.dim(E.thread_id.slice(0,16)+"\u2026")} ${E.name} ${c.dim(`(${E.session_count} sessions)`)}`)}console.log(),console.log(c.dim("Rollback: sqlite3 ~/.recall/db.sqlite \\")),console.log(c.dim(` "DELETE FROM thread_edges WHERE source='auto-scan-v1';`)),console.log(c.dim(` DELETE FROM threads WHERE id LIKE 'auto-scan-%';"`));return}if(e.json){let g=[];for(let[f,{proposals:h}]of u){let E=new Map(a.get(f).map(b=>[b.id,b]));for(let b of h)g.push({project:f,parent_id:b.parent_id,parent_label:wn(E.get(b.parent_id)),child_id:b.child_id,child_label:wn(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:g},null,2));return}console.log(c.dim(`recall thread scan \xB7 ${a.size} project${a.size===1?"":"s"} \xB7 DRY RUN \xB7 threshold ${s}`)),console.log(c.dim(" Algorithm: temporal + continuation phrase + file overlap + same brand.")),console.log();for(let[g,f]of a){let{proposals:h}=u.get(g),E=new Map(f.map(S=>[S.id,S]));if(console.log(c.bold(g)),console.log(c.dim(` ${f.length} eligible session${f.length===1?"":"s"}; ${h.length} parent-child edge${h.length===1?"":"s"} proposed.`)),h.length===0){console.log(c.dim(" (no edges above threshold \u2014 all sessions are origins)")),console.log();continue}let b=[...h].sort((S,R)=>{let T=E.get(S.child_id),L=E.get(R.child_id);return(T.started_at??"").localeCompare(L.started_at??"")});for(let S of b){let R=E.get(S.parent_id),T=E.get(S.child_id),L=S.confidence.toFixed(2);console.log(` ${c.dim(Lu(R.started_at).padEnd(16))} ${c.bold("PARENT")} ${wn(R)}`),console.log(` ${c.dim(Lu(T.started_at).padEnd(16))} ${c.bold(" \u2514\u2500 child")} ${wn(T)} ${c.dim(`[conf ${L}]`)}`),console.log(` ${" ".repeat(28)}${c.dim(S.reasons.join(" \xB7 "))}`),console.log()}}let m=Array.from(a.entries()).reduce((g,[f,h])=>g+(h.length-(u.get(f)?.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(c.dim(` This is a DRY RUN. To write: rerun with --apply (default threshold ${Mo}).`))}v();P();import{existsSync as PT,readFileSync as FT}from"node:fs";function jT(){let e=`${x}/daemon.port`;if(!PT(e))return null;try{let t=FT(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function UT(e){try{return(await ze(`http://127.0.0.1:${e}/api/health`,{signal:AbortSignal.timeout(1e4)})).ok}catch{return!1}}async function BT(e){let t=await ze(`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 HT(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 WT(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 Ou(e){return e.alias||e.auto_title||(e.first_user_message?K(e.first_user_message,60):"(no title)")}function XT(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 JT(e,t){let s=t==="preflight"?c.dim(`recall threads sync \xB7 ${e.project.name} \xB7 PREFLIGHT (no writes)`):c.dim(`recall threads sync \xB7 ${e.project.name}`);if(console.log(s),console.log(),e.thread.exists?console.log(` ${c.bold("Thread")} ${e.thread.name} ${c.dim(`(reusing, ${e.thread.existing_session_count} existing session${e.thread.existing_session_count===1?"":"s"})`)}`):console.log(` ${c.bold("Thread")} ${e.thread.name} ${c.ok("(new)")}`),console.log(),e.candidates.length===0){if(console.log(c.dim(" No active sessions in the rolling window.")),e.warnings.length>0)for(let l of e.warnings)console.log(c.warn(` \u26A0 ${l}`));return}let n=new Map;for(let l of e.proposed_edges)n.set(l.child_id,l);let r=new Map;for(let l of e.preserved_manual_edges)r.set(l.session_id,l.parent_session_id);let o=new Set(e.candidates.map(l=>l.session_id)),i=e.proposed_additions.length,a=e.candidates.length-i;console.log(` ${c.bold("Candidates")} ${e.candidates.length} active session${e.candidates.length===1?"":"s"} ${c.dim(`(${i} new \xB7 ${a} keep)`)}`);let d=String(e.candidates.length).length;for(let l=0;l<e.candidates.length;l++){let u=e.candidates[l],m=e.proposed_additions.some(S=>S.session_id===u.session_id)?c.ok("NEW "):c.dim("keep"),g=n.get(u.session_id)??(r.has(u.session_id)&&r.get(u.session_id)!==null,null),f=g&&o.has(g.parent_id)?" \u2514\u2500 ":" ",h=XT(u.started_at),E=c.dim(`${String(l+1).padStart(d," ")}.`);console.log(` ${E} ${m} ${c.dim(h.padEnd(16))} ${f}${c.dim(u.session_id.slice(0,8))} ${Ou(u)}`);let b=" ".repeat(d+2);if(g&&o.has(g.parent_id)){let S=g.confidence.toFixed(2),R=Ou(e.candidates.find(T=>T.session_id===g.parent_id));console.log(` ${b}${" ".repeat(28)} parent ${c.dim(g.parent_id.slice(0,8))} (${R}) ${c.dim(`[conf ${S}]`)}`),console.log(` ${b}${" ".repeat(28)} ${c.dim(g.reasons.join(" \xB7 "))}`)}if(r.has(u.session_id)){let S=r.get(u.session_id);S&&console.log(` ${b}${" ".repeat(28)} ${c.bold("manual parent preserved")} ${c.dim(S.slice(0,8))}`)}}if(e.preserved_manual_edges.length>0&&(console.log(),console.log(c.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 l of e.warnings)console.log(c.warn(` \u26A0 ${l}`))}}function GT(e){console.log(),console.log(c.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(c.dim(` thread_id: ${e.thread_id}`))}async function vu(e){let t=jT();if(!t){console.error(c.err("Daemon is not running. Start it with `recall start`, then re-run this command.")),process.exitCode=1;return}if(!await UT(t)){console.error(c.err(`Daemon on port ${t} is not responding. Try \`recall stop && recall start\`.`)),process.exitCode=1;return}let n;try{n=await BT(t)}catch(l){console.error(c.err(l.message)),process.exitCode=1;return}let r;if(e.project){if(r=WT(n,e.project),!r){console.error(c.err(`No project matching "${e.project}". Run \`recall projects\` to list known projects.`)),process.exitCode=1;return}}else{let l=process.cwd();if(r=HT(n,l),!r){console.error(c.err(`Current directory (${l}) 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(c.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 d;try{let l=await st("POST",`http://127.0.0.1:${t}/api/threads/sync-active`,a);if(!l.ok){let u=await l.text().catch(()=>"");throw new Error(`HTTP ${l.status}: ${u.slice(0,200)}`)}d=await l.json()}catch(l){console.error(c.err(`Sync failed: ${l.message}`)),process.exitCode=1;return}if(e.json){console.log(JSON.stringify({mode:i,...d},null,2));return}JT(d.plan,i),i==="apply"&&d.result?GT(d.result):i==="preflight"&&(console.log(),console.log(c.dim(" This is a PREFLIGHT. To write: re-run without --preflight.")))}w();import{writeFileSync as fR,existsSync as _R,mkdirSync as hR}from"node:fs";import{join as Vu}from"node:path";import{homedir as ER}from"node:os";import{execSync as Xt}from"node:child_process";Ke();import uR from"satori";import pR from"sharp";import{readFileSync as Bo}from"node:fs";import{join as On}from"node:path";var Ho=On(ee(),"dist","share","fonts"),zu=!1,qu=[];function mR(){return zu||(qu=[{name:"Inter",data:Bo(On(Ho,"Inter-Regular.woff")),weight:400,style:"normal"},{name:"Inter",data:Bo(On(Ho,"Inter-Bold.woff")),weight:700,style:"normal"},{name:"JetBrains Mono",data:Bo(On(Ho,"JetBrainsMono-Regular.woff")),weight:400,style:"normal"}],zu=!0),qu}async function gR(e){switch(e){case"A":return await Promise.resolve().then(()=>($u(),Du));case"B":return await Promise.resolve().then(()=>(ju(),Fu));case"C":return await Promise.resolve().then(()=>(Hu(),Bu));case"D":return await Promise.resolve().then(()=>(Ju(),Xu));case"E":return await Promise.resolve().then(()=>(Yu(),Gu))}}async function vn(e,t){let n=(await gR(e)).render(t),i=await uR(n,{width:1080,height:e==="E"?1920:1350,fonts:mR()});return await pR(Buffer.from(i)).png({quality:90}).toBuffer()}function Ku(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 bR(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.
1759
+ `),null)}function SR(e){return e.prepare("SELECT session_id FROM recall_events ORDER BY recalled_at DESC LIMIT 1").get()?.session_id??null}function yR(e,t){let s=e.prepare(`
1763
1760
  SELECT s.id, s.started_at, s.message_count, s.first_user_message, s.auto_title,
1764
1761
  s.total_input_tokens, s.total_output_tokens
1765
1762
  FROM sessions s WHERE s.id = ?
1766
1763
  `).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(`
1767
1764
  SELECT tool_names, raw_json FROM messages
1768
1765
  WHERE session_id = ? AND tool_names IS NOT NULL AND tool_names != ''
1769
- `).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 g=m.match(/":\s*"([^"]+)"/);g&&a.add(g[1])}}let d=s.total_input_tokens??0,l=s.total_output_tokens??0;return{sessionTitle:r,sessionDate:s.started_at??new Date().toISOString(),recallDate:new Date().toISOString(),tokenCount:d+l,inputTokens:d,outputTokens:l,messageCount:s.message_count,filesReferenced:a.size,toolCallCount:i,verdict:""}}function pR(e){process.platform==="darwin"?Wt(`osascript -e 'set the clipboard to (read (POSIX file "${e}") as \xABclass PNGf\xBB)'`):process.platform==="linux"&&Wt(`xclip -selection clipboard -t image/png -i "${e}"`)}function mR(e){try{process.platform==="darwin"?Wt(`open "${e}"`):process.platform==="linux"?Wt(`xdg-open "${e}"`):process.platform==="win32"&&Wt(`start "" "${e}"`)}catch{}}async function Ku(e,t){let s=_(),n;if(e){if(n=lR(s,e),!n){process.stderr.write(`session not found: ${e}
1770
- `),process.exitCode=1;return}}else if(n=dR(s),!n){process.stderr.write("No recalled sessions yet. Run `recall context <id>` first, then `recall share`.\n"),process.exitCode=1;return}let r=uR(s,n);if(!r){process.stderr.write(`failed to load metadata for session ${n}
1771
- `),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 An(o,r),a=n.slice(0,8),d=t.out??zu(cR(),"Downloads");iR(d)||aR(d,{recursive:!0});let l=zu(d,`recall-card-${a}.png`);if(oR(l,i),process.stderr.write(`Card saved to ${l}
1772
- `),t.clipboard&&(pR(l),process.stderr.write(`Copied PNG to clipboard.
1773
- `)),t.link){let u=Gu(r,o);process.stdout.write(u+`
1774
- `),process.platform==="darwin"&&(Wt("pbcopy",{input:u}),process.stderr.write(`Link copied to clipboard.
1775
- `))}t.open!==!1&&mR(l)}w();import{createInterface as gR}from"node:readline";import{writeFileSync as fR,existsSync as _R,mkdirSync as hR}from"node:fs";import{join as Vu}from"node:path";import{homedir as ER}from"node:os";function qu(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 Ct=["january","february","march","april","may","june","july","august","september","october","november","december"],bR=["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"];function SR(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:`${Ct[a][0].toUpperCase()}${Ct[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:`${Ct[a][0].toUpperCase()}${Ct[a].slice(1)} ${i}`}}let n=Ct.indexOf(e.toLowerCase()),r=n===-1?bR.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:`${Ct[o][0].toUpperCase()}${Ct[o].slice(1)} ${i}`}}return null}function yR(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 Zu(e,t){let s=SR(e);if(!s){process.stderr.write(`invalid month format: ${e}. Use YYYY-MM, month name, or abbreviation.
1766
+ `).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 g=m.match(/":\s*"([^"]+)"/);g&&a.add(g[1])}}let d=s.total_input_tokens??0,l=s.total_output_tokens??0;return{sessionTitle:r,sessionDate:s.started_at??new Date().toISOString(),recallDate:new Date().toISOString(),tokenCount:d+l,inputTokens:d,outputTokens:l,messageCount:s.message_count,filesReferenced:a.size,toolCallCount:i,verdict:""}}function wR(e){process.platform==="darwin"?Xt(`osascript -e 'set the clipboard to (read (POSIX file "${e}") as \xABclass PNGf\xBB)'`):process.platform==="linux"&&Xt(`xclip -selection clipboard -t image/png -i "${e}"`)}function TR(e){try{process.platform==="darwin"?Xt(`open "${e}"`):process.platform==="linux"?Xt(`xdg-open "${e}"`):process.platform==="win32"&&Xt(`start "" "${e}"`)}catch{}}async function Zu(e,t){let s=_(),n;if(e){if(n=bR(s,e),!n){process.stderr.write(`session not found: ${e}
1767
+ `),process.exitCode=1;return}}else if(n=SR(s),!n){process.stderr.write("No recalled sessions yet. Run `recall context <id>` first, then `recall share`.\n"),process.exitCode=1;return}let r=yR(s,n);if(!r){process.stderr.write(`failed to load metadata for session ${n}
1768
+ `),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 vn(o,r),a=n.slice(0,8),d=t.out??Vu(ER(),"Downloads");_R(d)||hR(d,{recursive:!0});let l=Vu(d,`recall-card-${a}.png`);if(fR(l,i),process.stderr.write(`Card saved to ${l}
1769
+ `),t.clipboard&&(wR(l),process.stderr.write(`Copied PNG to clipboard.
1770
+ `)),t.link){let u=Ku(r,o);process.stdout.write(u+`
1771
+ `),process.platform==="darwin"&&(Xt("pbcopy",{input:u}),process.stderr.write(`Link copied to clipboard.
1772
+ `))}t.open!==!1&&TR(l)}w();import{createInterface as RR}from"node:readline";import{writeFileSync as xR,existsSync as kR,mkdirSync as CR}from"node:fs";import{join as ep}from"node:path";import{homedir as LR}from"node:os";function Qu(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 Ct=["january","february","march","april","may","june","july","august","september","october","november","december"],NR=["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"];function AR(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:`${Ct[a][0].toUpperCase()}${Ct[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:`${Ct[a][0].toUpperCase()}${Ct[a].slice(1)} ${i}`}}let n=Ct.indexOf(e.toLowerCase()),r=n===-1?NR.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:`${Ct[o][0].toUpperCase()}${Ct[o].slice(1)} ${i}`}}return null}function OR(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 tp(e,t){let s=AR(e);if(!s){process.stderr.write(`invalid month format: ${e}. Use YYYY-MM, month name, or abbreviation.
1776
1773
  `),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
1777
1774
  WHERE recalled_at >= ? AND recalled_at < ?
1778
- GROUP BY session_id ORDER BY c DESC LIMIT 1`).get(s.start,s.end),d="None";if(a){let j=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);d=j?.alias||y?.auto_title||y?.first_user_message?.slice(0,40)||a.session_id.slice(0,8)}let l=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
1775
+ GROUP BY session_id ORDER BY c DESC LIMIT 1`).get(s.start,s.end),d="None";if(a){let U=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);d=U?.alias||y?.auto_title||y?.first_user_message?.slice(0,40)||a.session_id.slice(0,8)}let l=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
1779
1776
  FROM sessions WHERE started_at >= ? AND started_at < ?
1780
- GROUP BY h ORDER BY c DESC LIMIT 3`).all(s.start,s.end),p=yR(u.map(j=>j.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,g=n.prepare(`SELECT COUNT(*) AS cnt, COALESCE(AVG(message_count), 0) AS avg_msgs
1777
+ GROUP BY h ORDER BY c DESC LIMIT 3`).all(s.start,s.end),p=OR(u.map(U=>U.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,g=n.prepare(`SELECT COUNT(*) AS cnt, COALESCE(AVG(message_count), 0) AS avg_msgs
1781
1778
  FROM sessions WHERE started_at >= ? AND started_at < ?`).get(s.start,s.end),f=n.prepare(`SELECT COUNT(*) AS c FROM sessions
1782
1779
  WHERE started_at >= ? AND started_at < ?
1783
1780
  AND (CAST(strftime('%H', started_at) AS INTEGER) >= 22
1784
1781
  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
1785
1782
  FROM session_tags st JOIN sessions s ON s.id = st.session_id
1786
1783
  WHERE s.started_at >= ? AND s.started_at < ?
1787
- 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:g.cnt,avgMessageCount:g.avg_msgs,nightSessionRatio:g.cnt>0?f/g.cnt:0,debugTagRatio:g.cnt>0?h/g.cnt:0},b=qu(E),S=50;try{let{computeAllHealthScores:j}=await Promise.resolve().then(()=>(To(),Sd)),y=j();y.length>0&&(S=Math.round(y.reduce((U,M)=>U+M.score,0)/y.length))}catch{}let T=t.verdict??"";if(!t.verdict){let j=gR({input:process.stdin,output:process.stderr});T=await new Promise(y=>{j.question("Add your take (one line, or press Enter to skip): ",U=>{j.close(),y(U.trim())})})}let R={month:s.label,totalRecalls:r,totalTokensPiped:o,sessionsIndexed:i,mostRecalledSession:d,biggestRecallTokens:l,healthScore:S,mostActiveHours:p,archetype:b,verdict:T},k=await An("E",R),J=s.start.slice(0,7),A=t.out??Vu(ER(),"Downloads");_R(A)||hR(A,{recursive:!0});let $=Vu(A,`recall-wrapped-${J}.png`);fR($,k),process.stderr.write(`Wrapped card saved to ${$}
1788
- `)}le();At();st();import{createRequire as wR}from"node:module";import{createInterface as TR}from"node:readline";import{stdin as RR,stdout as xR}from"node:process";var kR=wR(import.meta.url),CR=kR(`${de()}/package.json`).version,tp="https://clauderecall.com/api/feedback",Bo=process.env.RECALL_FEEDBACK_API??tp,Qu=Bo===tp,Ho=2e3;function sp(e){let t=TR({input:RR,output:xR});return new Promise(s=>t.question(e,n=>{t.close(),s(n.trim())}))}function ep(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 LR(e){if(e.score!==void 0){let n=ep(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 sp("Score (1-5, q to quit): ");if(t.toLowerCase()==="q"||t==="")return console.log("No worries, skipped."),null;let s=ep(t);return s===null?(console.error("Please enter an integer 1 through 5."),null):s}async function NR(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 sp(s)}function AR(e){return e.length<=Ho?{value:e,truncated:!1}:{value:e.slice(0,Ho),truncated:!0}}async function np(e={}){Qu||process.stderr.write(`[recall] RECALL_FEEDBACK_API override active (${Bo}); license token will NOT be sent.
1789
- `);let t=await LR(e);if(t===null)return e.score!==void 0||!process.stdin.isTTY?1:0;let s=await NR(e,t),{value:n,truncated:r}=AR(s);r&&process.stderr.write(`[recall] --message truncated to ${Ho} characters before send.
1790
- `);let o=await Te(),i=Kt(),a=Qu&&o.tier==="pro"&&i?i.license_jwt:null,d={score:t,comment:n.length>0?n:null,surface:"cli",version:CR,os:process.platform,trigger_kind:"manual",license_jwt:a};try{let l=await fetch(Bo,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(d)});if(l.ok)return console.log(""),console.log("Thanks. Your feedback landed."),0;let u=await l.json().catch(()=>({}));return l.status===429?(console.log("You submitted feedback recently. Try again later."),0):(console.error(`Feedback failed: ${l.status} ${u.error??"unknown"}`),1)}catch(l){let u=l instanceof Error?l.message:"network error";return console.error(`Feedback could not be sent: ${u}`),1}}var T0=y0(import.meta.url),hs=T0("../package.json").version,L=new w0;L.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(hs);L.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 yi(e)});L.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=>{wi(e)});L.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)=>{Li(e,t)});L.command("search <query...>").description("Search every message in every session. Pass --semantic for fused keyword + summary + vector hits (delegates to the running daemon).").option("-p, --project <name>","restrict results to one project").option("-n, --limit <n>","max results","20").option("--semantic","fuse keyword + summary + vector hits via the daemon (Pro; requires `recall start`)").action(async(e,t)=>{await Wi(e.join(" "),t)});L.command("projects").description("List every project with how many sessions are in each.").action(()=>{Yi()});L.command("status").description("Show database size, session counts, and whether the daemon is running.").action(()=>{Ji()});L.command("start").description("Start the background daemon. Required for live tab-name tracking and the web UI.").action(async()=>{await Os()});L.command("stop").description("Stop the background daemon.").action(async()=>{await Ki()});L.command("open").description("Open the local web UI in your browser. Starts the daemon if it is not already running.").action(async()=>{await qi()});L.command("tui").description("Browse and search sessions in an interactive terminal UI. No browser needed.").action(async()=>{let{runTui:e}=await Promise.resolve().then(()=>($p(),Dp));await e()});L.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 ba(e,t)});L.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 Sa({allowWrites:!!e.allowWrites})});L.command("mcp-prune").description("Kill stuck MCP children that are holding SQLite connections. Default scope is orphans (parent claude is gone); pass --all to nuke every MCP child. Runs a WAL TRUNCATE on success so disk space comes back immediately.").option("--all","prune every MCP child, not just orphans").option("--yes","skip the interactive confirmation prompt").option("--json","emit a single JSON line instead of human-readable output (implies --yes)").action(async e=>{let t=await ka({all:!!e.all,yes:!!e.yes,json:!!e.json});process.exit(t)});L.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 Ca(e)});L.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 La(e)});L.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 Aa(t);return}console.error(`Unknown titles action: ${e}. Supported: audit`),process.exitCode=1});L.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 $a(e)});L.command("semantic [action] [subAction]").description('Local on-device semantic search. Default action is "status". Free, local, zero tokens (Tier-2): install, status, reindex, uninstall. Advanced \u2014 sends summaries via your Claude plan and costs plan tokens (Tier-1): on, off, backfill, pause, resume, auto-extract <on|off>. Diagnostic: verify-spawn (confirms claude CLI honors --no-session-persistence before re-enabling Tier-1).').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)").addHelpText("after",`
1784
+ 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:g.cnt,avgMessageCount:g.avg_msgs,nightSessionRatio:g.cnt>0?f/g.cnt:0,debugTagRatio:g.cnt>0?h/g.cnt:0},b=Qu(E),S=50;try{let{computeAllHealthScores:U}=await Promise.resolve().then(()=>(xo(),Td)),y=U();y.length>0&&(S=Math.round(y.reduce((B,M)=>B+M.score,0)/y.length))}catch{}let R=t.verdict??"";if(!t.verdict){let U=RR({input:process.stdin,output:process.stderr});R=await new Promise(y=>{U.question("Add your take (one line, or press Enter to skip): ",B=>{U.close(),y(B.trim())})})}let T={month:s.label,totalRecalls:r,totalTokensPiped:o,sessionsIndexed:i,mostRecalledSession:d,biggestRecallTokens:l,healthScore:S,mostActiveHours:p,archetype:b,verdict:R},L=await vn("E",T),D=s.start.slice(0,7),A=t.out??ep(LR(),"Downloads");kR(A)||CR(A,{recursive:!0});let $=ep(A,`recall-wrapped-${D}.png`);xR($,L),process.stderr.write(`Wrapped card saved to ${$}
1785
+ `)}de();At();Ke();import{createRequire as vR}from"node:module";import{createInterface as IR}from"node:readline";import{stdin as MR,stdout as DR}from"node:process";var $R=vR(import.meta.url),PR=$R(`${ee()}/package.json`).version,rp="https://clauderecall.com/api/feedback",Wo=process.env.RECALL_FEEDBACK_API??rp,sp=Wo===rp,Xo=2e3;function op(e){let t=IR({input:MR,output:DR});return new Promise(s=>t.question(e,n=>{t.close(),s(n.trim())}))}function np(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 FR(e){if(e.score!==void 0){let n=np(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 op("Score (1-5, q to quit): ");if(t.toLowerCase()==="q"||t==="")return console.log("No worries, skipped."),null;let s=np(t);return s===null?(console.error("Please enter an integer 1 through 5."),null):s}async function jR(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 op(s)}function UR(e){return e.length<=Xo?{value:e,truncated:!1}:{value:e.slice(0,Xo),truncated:!0}}async function ip(e={}){sp||process.stderr.write(`[recall] RECALL_FEEDBACK_API override active (${Wo}); license token will NOT be sent.
1786
+ `);let t=await FR(e);if(t===null)return e.score!==void 0||!process.stdin.isTTY?1:0;let s=await jR(e,t),{value:n,truncated:r}=UR(s);r&&process.stderr.write(`[recall] --message truncated to ${Xo} characters before send.
1787
+ `);let o=await Te(),i=Kt(),a=sp&&o.tier==="pro"&&i?i.license_jwt:null,d={score:t,comment:n.length>0?n:null,surface:"cli",version:PR,os:process.platform,trigger_kind:"manual",license_jwt:a};try{let l=await fetch(Wo,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(d)});if(l.ok)return console.log(""),console.log("Thanks. Your feedback landed."),0;let u=await l.json().catch(()=>({}));return l.status===429?(console.log("You submitted feedback recently. Try again later."),0):(console.error(`Feedback failed: ${l.status} ${u.error??"unknown"}`),1)}catch(l){let u=l instanceof Error?l.message:"network error";return console.error(`Feedback could not be sent: ${u}`),1}}var j0=P0(import.meta.url),hs=j0("../package.json").version,C=new F0;C.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(hs);C.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 Ci(e)});C.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=>{Li(e)});C.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)=>{Mi(e,t)});C.command("search <query...>").description("Search every message in every session. Pass --semantic for fused keyword + summary + vector hits (delegates to the running daemon).").option("-p, --project <name>","restrict results to one project").option("-n, --limit <n>","max results","20").option("--semantic","fuse keyword + summary + vector hits via the daemon (Pro; requires `recall start`)").action(async(e,t)=>{await qi(e.join(" "),t)});C.command("projects").description("List every project with how many sessions are in each.").action(()=>{Zi()});C.command("status").description("Show database size, session counts, and whether the daemon is running.").action(()=>{Vi()});C.command("start").description("Start the background daemon. Required for live tab-name tracking and the web UI.").action(async()=>{await Os()});C.command("stop").description("Stop the background daemon.").option("--all","also kill every MCP child and truncate the WAL (one-command WAL-pin recovery)").action(async e=>{process.exitCode=await ra({all:e.all})});C.command("open").description("Open the local web UI in your browser. Starts the daemon if it is not already running.").action(async()=>{await oa()});C.command("tui").description("Browse and search sessions in an interactive terminal UI. No browser needed.").action(async()=>{let{runTui:e}=await Promise.resolve().then(()=>(jp(),Fp));await e()});C.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 La(e,t)});C.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 Na({allowWrites:!!e.allowWrites})});C.command("mcp-prune").description("Kill stuck MCP children that are holding SQLite connections. Default scope is orphans (parent claude is gone); pass --all to nuke every MCP child. Runs a WAL TRUNCATE on success so disk space comes back immediately.").option("--all","prune every MCP child, not just orphans").option("--yes","skip the interactive confirmation prompt").option("--json","emit a single JSON line instead of human-readable output (implies --yes)").action(async e=>{let t=await Ms({all:!!e.all,yes:!!e.yes,json:!!e.json});process.exit(t)});C.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 Aa(e)});C.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 Oa(e)});C.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 Ia(t);return}console.error(`Unknown titles action: ${e}. Supported: audit`),process.exitCode=1});C.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 ja(e)});C.command("semantic [action] [subAction]").description('Local on-device semantic search. Default action is "status". Free, local, zero tokens (Tier-2): install, status, reindex, uninstall. Advanced \u2014 sends summaries via your Claude plan and costs plan tokens (Tier-1): on, off, backfill, pause, resume, auto-extract <on|off>. Diagnostic: verify-spawn (confirms claude CLI honors --no-session-persistence before re-enabling Tier-1).').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)").addHelpText("after",`
1791
1788
  Two lanes:
1792
1789
  Tier-2 (default, recommended): on-device 768-d embeddings via bge-base-en-v1.5
1793
1790
  + sqlite-vec. No network, no token spend. Powered by:
@@ -1803,7 +1800,7 @@ Two lanes:
1803
1800
  Reindex chunks-per-session cap (advanced):
1804
1801
  Set RECALL_REINDEX_MAX_CHUNKS=200 to cap each session at 200 chunks for a
1805
1802
  faster first pass. Default is 0 (no cap, full accuracy).
1806
- `).action(async(e,t,s)=>{await _c(e,{...s,_autoExtractAction:t})});L.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 yc(e,t)});var Es=L.command("infer").description("Discover links between sessions. Subcommands: outputs | citations | l1 | links | bug-patterns.");function jp(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 Lc(t)})}function Up(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 Fc(t)})}function Bp(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 Bc(t)})}function Hp(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 zc(t)})}function Wp(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 ol(t)})}jp(Es.command("outputs"));Up(Es.command("citations"));Bp(Es.command("l1"));Hp(Es.command("links"));Wp(Es.command("bug-patterns"));jp(L.command("extract-outputs"));Up(L.command("infer-citations"));Bp(L.command("infer-l1"));Hp(L.command("infer-links"));Wp(L.command("infer-bug-patterns"));L.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 hl(e,t)});L.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 s=process.env.RECALL_DEBUG_TIMING==="1",n=(f,h)=>{if(s){let E=Math.round(performance.now()-h);process.stderr.write(`[similar:timing] ${f}: ${E}ms
1807
- `)}},r=performance.now(),{requireProOrExit:o}=await Promise.resolve().then(()=>(le(),Vt));await o("Similar sessions"),n("requireProOrExit",r);let i=performance.now(),{isModelInstalled:a}=await Promise.resolve().then(()=>(Ws(),ac)),{loadEmbedder:d,getEmbedderStatus:l}=await Promise.resolve().then(()=>(rt(),Ir)),{findSimilarSessions:u}=await Promise.resolve().then(()=>(Fp(),Pp));if(n("dynamic imports",i),!a()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}if(!l().loaded){process.stderr.write(`[recall similar] loading embedder model (first run is slow, ~5-30s)\u2026
1808
- `);let f=performance.now();await d(),n("loadEmbedder (cold)",f)}let p=Math.max(1,Math.min(50,Number(t.limit??10))),m=performance.now(),g=await u(e,p);if(n("findSimilarSessions",m),g.length===0){console.log("No similar sessions found.");return}for(let f of g)console.log(` ${f.sessionId} similarity=${f.similarity.toFixed(3)}`)});L.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 Rl(e,t)});L.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 Ll(e,t)});var Qo=L.command("correlator").description("Diagnose and fix terminal-to-session matching. Subcommands: audit | debug | restore.");function Xp(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 ld(t)})}function Jp(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 dd(t)})}function Yp(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 Il(t)})}Xp(Qo.command("debug"));Jp(Qo.command("restore"));Yp(Qo.command("audit"));Xp(L.command("correlator-debug"));Jp(L.command("correlator-restore"));L.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 od(e,t,s)});L.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 Xl(e);process.exit(t)});L.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 Jl(e);process.exit(t)});L.command("purge-phantoms").description("Remove session rows produced by historical daemon-autonomous `claude -p` spawns (auto-titler, summariser, output-index, \u2026). Source JSONLs at ~/.claude/projects/ are NEVER touched. Requires daemon stopped.").option("--dry-run","count phantom rows without deleting anything").option("--json","emit JSON instead of formatted output").action(async e=>{let t=await Gl(e);process.exit(t)});L.command("archive").description("Power-user retention. Subcommands: list, run --before YYYY-MM-DD [--dry-run], restore <session-id>, auto <status|on|off> [--after N].").argument("[action]","list | run | restore | auto","list").argument("[arg]","session id (for restore) or sub-action (for auto)").option("--before <date>","YYYY-MM-DD cutoff for `run`").option("--dry-run","show what would be archived without moving rows").option("--after <days>","days threshold for `auto on`",e=>Number.parseInt(e,10)).action(async(e,t,s)=>{let n=e==="auto",r=await rd({_action:e,_subAction:n?t:void 0,_sessionId:n?void 0:t,before:typeof s.before=="string"?s.before:void 0,dryRun:s.dryRun===!0,after:typeof s.after=="number"?s.after:void 0});process.exit(r)});Yp(L.command("correlator-audit"));L.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 ud(e,t)});L.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 gd(e)});L.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 bd(e)});L.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)=>{wd(e,t)});L.command("verify [action]").description('Toggle verification badges in the UI. Defaults to "status". Actions: on, off, status.').action(e=>{Td(e)});L.command("activate <license-key>").description("Activate your Pro license. Run once after purchase.").action(async e=>{await vd(e)});L.command("upgrade").description("Open the Pro pricing page in your browser.").action(async()=>{await Md()});L.command("trial [promo-code]").description("Start a 7-day Pro trial. With a promo code (e.g. RECALL7DAY), redeems it directly from the CLI. With no code, opens the signup page.").action(async e=>{await $d(e)});var Dn=L.command("telemetry").description('Manage the opt-in anonymous install ping. Defaults to "view".');Dn.command("view",{isDefault:!0}).description("Show current decision, state file path, and next-ping payload.").action(async()=>{await Xd(hs)});Dn.command("on").description("Opt in. One anonymous ping per machine per month. See https://clauderecall.com/telemetry").action(async()=>{await Hd()});Dn.command("off").description("Opt out. Deletes the nonce. No further pings.").action(async()=>{await Wd()});Dn.command("status").description("Alias for view.").action(async()=>{await No(hs)});var ei=L.command("license").description('Show or remove the Pro license on this machine. Defaults to "status".');ei.command("status",{isDefault:!0}).description("Show the current license tier.").action(async()=>{await Gd()});ei.command("deactivate").description("Remove the stored license from this machine. Reverses `recall activate`.").action(()=>{Kd()});ei.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 zd()});var R0=L.command("thread").description("Group related sessions into threads, then list, show, link, merge, or scan them."),x0=L.command("threads").description("Alias for `thread`. Both forms accept the same subcommands.");function Gp(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 Nu(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=>{Cu(t)}),e.command("list").description("List threads, newest first.").option("--archived","include archived threads").option("--json","emit JSON instead of a table").action(t=>{Vd(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)=>{Zd(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)=>{Qd(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)=>{eu(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)=>{tu(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)=>{su(t,s)}),e.command("rename <id-prefix> <new-name>").description("Rename a thread.").option("--json","emit JSON").action((t,s,n)=>{nu(t,s,n)}),e.command("close <id-prefix>").description("Mark a thread as closed (work complete).").option("--json","emit JSON").action((t,s)=>{ru(t,s)}),e.command("reopen <id-prefix>").description("Reopen a closed thread.").option("--json","emit JSON").action((t,s)=>{ou(t,s)}),e.command("archive <id-prefix>").description("Archive a thread (hidden from the default list).").option("--json","emit JSON").action((t,s)=>{iu(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)=>{au(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)=>{cu(t,s)})}Gp(R0);Gp(x0);L.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 Ku(e,t)});L.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 np(e);t!==0&&(process.exitCode=t)});L.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 Zu(e,t)});process.env.CLAUDECODE&&!process.stdout.isTTY&&process.stderr.write(`<claude-code-hint v="1" type="plugin" value="claude-recall@claude-plugins-official" />
1809
- `);L.action(async()=>{await Od()});L.hook("preAction",async(e,t)=>{let s=t.name();try{await Yd(s,hs)}catch{}Bd(hs).catch(()=>{})});L.parseAsync(process.argv).catch(e=>{console.error(e),process.exit(1)});
1803
+ `).action(async(e,t,s)=>{await bc(e,{...s,_autoExtractAction:t})});C.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 Rc(e,t)});var Es=C.command("infer").description("Discover links between sessions. Subcommands: outputs | citations | l1 | links | bug-patterns.");function Xp(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 Oc(t)})}function Jp(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 Bc(t)})}function Gp(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 Xc(t)})}function Yp(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 Vc(t)})}function zp(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 cl(t)})}Xp(Es.command("outputs"));Jp(Es.command("citations"));Gp(Es.command("l1"));Yp(Es.command("links"));zp(Es.command("bug-patterns"));Xp(C.command("extract-outputs"));Jp(C.command("infer-citations"));Gp(C.command("infer-l1"));Yp(C.command("infer-links"));zp(C.command("infer-bug-patterns"));C.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 Sl(e,t)});C.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 s=process.env.RECALL_DEBUG_TIMING==="1",n=(f,h)=>{if(s){let E=Math.round(performance.now()-h);process.stderr.write(`[similar:timing] ${f}: ${E}ms
1804
+ `)}},r=performance.now(),{requireProOrExit:o}=await Promise.resolve().then(()=>(de(),Zt));await o("Similar sessions"),n("requireProOrExit",r);let i=performance.now(),{isModelInstalled:a}=await Promise.resolve().then(()=>(Js(),dc)),{loadEmbedder:d,getEmbedderStatus:l}=await Promise.resolve().then(()=>(yt(),Dr)),{findSimilarSessions:u}=await Promise.resolve().then(()=>(Wp(),Hp));if(n("dynamic imports",i),!a()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}if(!l().loaded){process.stderr.write(`[recall similar] loading embedder model (first run is slow, ~5-30s)\u2026
1805
+ `);let f=performance.now();await d(),n("loadEmbedder (cold)",f)}let p=Math.max(1,Math.min(50,Number(t.limit??10))),m=performance.now(),g=await u(e,p);if(n("findSimilarSessions",m),g.length===0){console.log("No similar sessions found.");return}for(let f of g)console.log(` ${f.sessionId} similarity=${f.similarity.toFixed(3)}`)});C.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 Cl(e,t)});C.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 Ol(e,t)});var oi=C.command("correlator").description("Diagnose and fix terminal-to-session matching. Subcommands: audit | debug | restore.");function qp(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 pd(t)})}function Kp(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 md(t)})}function Vp(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 $l(t)})}qp(oi.command("debug"));Kp(oi.command("restore"));Vp(oi.command("audit"));qp(C.command("correlator-debug"));Kp(C.command("correlator-restore"));C.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 cd(e,t,s)});C.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 Yl(e);process.exit(t)});C.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 zl(e);process.exit(t)});C.command("purge-phantoms").description("Remove session rows produced by historical daemon-autonomous `claude -p` spawns (auto-titler, summariser, output-index, \u2026). Source JSONLs at ~/.claude/projects/ are NEVER touched. Requires daemon stopped.").option("--dry-run","count phantom rows without deleting anything").option("--json","emit JSON instead of formatted output").action(async e=>{let t=await Kl(e);process.exit(t)});C.command("archive").description("Power-user retention. Subcommands: list, run --before YYYY-MM-DD [--dry-run], restore <session-id>, auto <status|on|off> [--after N].").argument("[action]","list | run | restore | auto","list").argument("[arg]","session id (for restore) or sub-action (for auto)").option("--before <date>","YYYY-MM-DD cutoff for `run`").option("--dry-run","show what would be archived without moving rows").option("--after <days>","days threshold for `auto on`",e=>Number.parseInt(e,10)).action(async(e,t,s)=>{let n=e==="auto",r=await ad({_action:e,_subAction:n?t:void 0,_sessionId:n?void 0:t,before:typeof s.before=="string"?s.before:void 0,dryRun:s.dryRun===!0,after:typeof s.after=="number"?s.after:void 0});process.exit(r)});Vp(C.command("correlator-audit"));C.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 gd(e,t)});C.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 hd(e)});C.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 wd(e)});C.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)=>{xd(e,t)});C.command("verify [action]").description('Toggle verification badges in the UI. Defaults to "status". Actions: on, off, status.').action(e=>{kd(e)});C.command("activate <license-key>").description("Activate your Pro license. Run once after purchase.").action(async e=>{await Dd(e)});C.command("upgrade").description("Open the Pro pricing page in your browser.").action(async()=>{await Pd()});C.command("trial [promo-code]").description("Start a 7-day Pro trial. With a promo code (e.g. RECALL7DAY), redeems it directly from the CLI. With no code, opens the signup page.").action(async e=>{await jd(e)});var Pn=C.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 Yd(hs)});Pn.command("on").description("Opt in. One anonymous ping per machine per month. See https://clauderecall.com/telemetry").action(async()=>{await Jd()});Pn.command("off").description("Opt out. Deletes the nonce. No further pings.").action(async()=>{await Gd()});Pn.command("status").description("Alias for view.").action(async()=>{await Oo(hs)});var ii=C.command("license").description('Show or remove the Pro license on this machine. Defaults to "status".');ii.command("status",{isDefault:!0}).description("Show the current license tier.").action(async()=>{await Kd()});ii.command("deactivate").description("Remove the stored license from this machine. Reverses `recall activate`.").action(()=>{Zd()});ii.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 Vd()});var U0=C.command("thread").description("Group related sessions into threads, then list, show, link, merge, or scan them."),B0=C.command("threads").description("Alias for `thread`. Both forms accept the same subcommands.");function Zp(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 vu(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=>{Au(t)}),e.command("list").description("List threads, newest first.").option("--archived","include archived threads").option("--json","emit JSON instead of a table").action(t=>{eu(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)=>{tu(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)=>{su(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)=>{nu(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)=>{ru(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)=>{ou(t,s)}),e.command("rename <id-prefix> <new-name>").description("Rename a thread.").option("--json","emit JSON").action((t,s,n)=>{iu(t,s,n)}),e.command("close <id-prefix>").description("Mark a thread as closed (work complete).").option("--json","emit JSON").action((t,s)=>{au(t,s)}),e.command("reopen <id-prefix>").description("Reopen a closed thread.").option("--json","emit JSON").action((t,s)=>{cu(t,s)}),e.command("archive <id-prefix>").description("Archive a thread (hidden from the default list).").option("--json","emit JSON").action((t,s)=>{lu(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)=>{du(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)=>{uu(t,s)})}Zp(U0);Zp(B0);C.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 Zu(e,t)});C.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 ip(e);t!==0&&(process.exitCode=t)});C.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 tp(e,t)});process.env.CLAUDECODE&&!process.stdout.isTTY&&process.stderr.write(`<claude-code-hint v="1" type="plugin" value="claude-recall@claude-plugins-official" />
1806
+ `);C.action(async()=>{await Md()});C.hook("preAction",async(e,t)=>{let s=t.name();try{await qd(s,hs)}catch{}Xd(hs).catch(()=>{})});C.parseAsync(process.argv).catch(e=>{console.error(e),process.exit(1)});