@clauderecallhq/cli 0.75.0 → 0.75.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 Mp=Object.defineProperty;var L=(e,t)=>()=>(e&&(t=e(e=0)),t);var _e=(e,t)=>{for(var s in t)Mp(e,s,{get:t[s],enumerable:!0})};import{createRequire as Dp}from"node:module";var $p,Pp,jp,On,An,gs,vn=L(()=>{"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)}}$p=Dp(import.meta.url),Pp=["node","sqlite"].join(":"),jp=$p(Pp),On=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)}},An=class{inner;extensionLoadingEnabled=!1;txDepth=0;constructor(t,s={}){this.inner=new jp.DatabaseSync(t,{readOnly:s.readonly??!1,allowExtension:!0})}prepare(t){return new On(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)}},gs=An});import{homedir as Vo}from"node:os";import{join as Ht,basename as Fp}from"node:path";import{existsSync as Zo,mkdirSync as Up,chmodSync as Bp,readdirSync as Ko,statSync as Hp}from"node:fs";function $(){Zo(R)||Up(R,{recursive:!0,mode:448}),process.platform!=="win32"&&Bp(R,448)}function In(e){return e.replace(/^-/,"/").replace(/-/g,"/")}function Qo(e){let t=In(e);return Fp(t)||t}function ei(){if(!Zo(Ct))return[];let e=[],t=Ko(Ct,{withFileTypes:!0}).filter(s=>s.isDirectory()).map(s=>s.name);for(let s of t){let n=Ht(Ct,s),r=Ko(n,{withFileTypes:!0});for(let o of r){if(!o.isFile()||!o.name.endsWith(".jsonl"))continue;let i=Ht(n,o.name),a=Hp(i);e.push({sessionFile:i,encodedProject:s,mtime:a.mtimeMs,size:a.size})}}return e}var Ct,R,te,D=L(()=>{"use strict";Ct=process.env.CLAUDE_PROJECTS_DIR?process.env.CLAUDE_PROJECTS_DIR:Ht(Vo(),".claude","projects"),R=process.env.RECALL_HOME?process.env.RECALL_HOME:Ht(Vo(),".recall"),te=Ht(R,"db.sqlite")});function si(e){let t=e.prepare("PRAGMA table_info(sessions)").all(),s=new Set(t.map(f=>f.name)),n=[["total_input_tokens","INTEGER"],["total_output_tokens","INTEGER"],["total_cache_create_tokens","INTEGER"],["total_cache_read_tokens","INTEGER"],["primary_model","TEXT"],["auto_title","TEXT"],["auto_title_source","TEXT"],["auto_title_generated_at","INTEGER"],["auto_title_history","TEXT"],["verification_status","TEXT"],["verification_computed_at","INTEGER"],["title_quality","TEXT"],["title_quality_computed_at","INTEGER"],["archive_status","TEXT NOT NULL DEFAULT 'live'"],["archived_at","TEXT"]];for(let[f,g]of n)s.has(f)||e.exec(`ALTER TABLE sessions ADD COLUMN ${f} ${g}`);let r=e.prepare("PRAGMA table_info(collection_sessions)").all(),o=new Set(r.map(f=>f.name)),i=[["source","TEXT NOT NULL DEFAULT 'manual'"],["rule_id","TEXT"]];for(let[f,g]of i)o.has(f)||e.exec(`ALTER TABLE collection_sessions ADD COLUMN ${f} ${g}`);let a=e.prepare("PRAGMA table_info(session_notes)").all(),d=new Set(a.map(f=>f.name)),c=[["auto_synopsis","TEXT"],["auto_synopsis_generated_at","INTEGER"],["auto_synopsis_history","TEXT"]];for(let[f,g]of c)d.has(f)||e.exec(`ALTER TABLE session_notes ADD COLUMN ${f} ${g}`);let u=e.prepare("PRAGMA table_info(threads)").all();new Set(u.map(f=>f.name)).has("folder_id")||(e.exec("ALTER TABLE threads ADD COLUMN folder_id TEXT REFERENCES thread_folders(id) ON DELETE SET NULL"),e.exec("CREATE INDEX IF NOT EXISTS idx_threads_folder ON threads(folder_id)"));let p=e.prepare("PRAGMA table_info(thread_folders)").all(),m=new Set(p.map(f=>f.name));m.has("project_scope")||(e.exec("ALTER TABLE thread_folders ADD COLUMN project_scope TEXT"),e.exec("CREATE INDEX IF NOT EXISTS idx_thread_folders_project ON thread_folders(project_scope)")),m.has("sort_order")||e.exec("ALTER TABLE thread_folders ADD COLUMN sort_order INTEGER NOT NULL DEFAULT 0"),e.exec(`
3
+ var Pp=Object.defineProperty;var L=(e,t)=>()=>(e&&(t=e(e=0)),t);var _e=(e,t)=>{for(var s in t)Pp(e,s,{get:t[s],enumerable:!0})};import{createRequire as jp}from"node:module";var Fp,Up,Bp,On,An,gs,vn=L(()=>{"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)}}Fp=jp(import.meta.url),Up=["node","sqlite"].join(":"),Bp=Fp(Up),On=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)}},An=class{inner;extensionLoadingEnabled=!1;txDepth=0;constructor(t,s={}){this.inner=new Bp.DatabaseSync(t,{readOnly:s.readonly??!1,allowExtension:!0})}prepare(t){return new On(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)}},gs=An});import{homedir as Zo}from"node:os";import{join as Ht,basename as Hp}from"node:path";import{existsSync as Qo,mkdirSync as Wp,chmodSync as Xp,readdirSync as Vo,statSync as Jp}from"node:fs";function P(){Qo(R)||Wp(R,{recursive:!0,mode:448}),process.platform!=="win32"&&Xp(R,448)}function In(e){return e.replace(/^-/,"/").replace(/-/g,"/")}function ei(e){let t=In(e);return Hp(t)||t}function ti(){if(!Qo(Ct))return[];let e=[],t=Vo(Ct,{withFileTypes:!0}).filter(s=>s.isDirectory()).map(s=>s.name);for(let s of t){let n=Ht(Ct,s),r=Vo(n,{withFileTypes:!0});for(let o of r){if(!o.isFile()||!o.name.endsWith(".jsonl"))continue;let i=Ht(n,o.name),a=Jp(i);e.push({sessionFile:i,encodedProject:s,mtime:a.mtimeMs,size:a.size})}}return e}var Ct,R,te,D=L(()=>{"use strict";Ct=process.env.CLAUDE_PROJECTS_DIR?process.env.CLAUDE_PROJECTS_DIR:Ht(Zo(),".claude","projects"),R=process.env.RECALL_HOME?process.env.RECALL_HOME:Ht(Zo(),".recall"),te=Ht(R,"db.sqlite")});function ni(e){let t=e.prepare("PRAGMA table_info(sessions)").all(),s=new Set(t.map(f=>f.name)),n=[["total_input_tokens","INTEGER"],["total_output_tokens","INTEGER"],["total_cache_create_tokens","INTEGER"],["total_cache_read_tokens","INTEGER"],["primary_model","TEXT"],["auto_title","TEXT"],["auto_title_source","TEXT"],["auto_title_generated_at","INTEGER"],["auto_title_history","TEXT"],["verification_status","TEXT"],["verification_computed_at","INTEGER"],["title_quality","TEXT"],["title_quality_computed_at","INTEGER"],["archive_status","TEXT NOT NULL DEFAULT 'live'"],["archived_at","TEXT"]];for(let[f,g]of n)s.has(f)||e.exec(`ALTER TABLE sessions ADD COLUMN ${f} ${g}`);let r=e.prepare("PRAGMA table_info(collection_sessions)").all(),o=new Set(r.map(f=>f.name)),i=[["source","TEXT NOT NULL DEFAULT 'manual'"],["rule_id","TEXT"]];for(let[f,g]of i)o.has(f)||e.exec(`ALTER TABLE collection_sessions ADD COLUMN ${f} ${g}`);let a=e.prepare("PRAGMA table_info(session_notes)").all(),d=new Set(a.map(f=>f.name)),l=[["auto_synopsis","TEXT"],["auto_synopsis_generated_at","INTEGER"],["auto_synopsis_history","TEXT"]];for(let[f,g]of l)d.has(f)||e.exec(`ALTER TABLE session_notes ADD COLUMN ${f} ${g}`);let u=e.prepare("PRAGMA table_info(threads)").all();new Set(u.map(f=>f.name)).has("folder_id")||(e.exec("ALTER TABLE threads ADD COLUMN folder_id TEXT REFERENCES thread_folders(id) ON DELETE SET NULL"),e.exec("CREATE INDEX IF NOT EXISTS idx_threads_folder ON threads(folder_id)"));let p=e.prepare("PRAGMA table_info(thread_folders)").all(),m=new Set(p.map(f=>f.name));m.has("project_scope")||(e.exec("ALTER TABLE thread_folders ADD COLUMN project_scope TEXT"),e.exec("CREATE INDEX IF NOT EXISTS idx_thread_folders_project ON thread_folders(project_scope)")),m.has("sort_order")||e.exec("ALTER TABLE thread_folders ADD COLUMN sort_order INTEGER NOT NULL DEFAULT 0"),e.exec(`
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 Mp=Object.defineProperty;var L=(e,t)=>()=>(e&&(t=e(e=0)),t);var _e=(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 ti,ni=L(()=>{"use strict";ti=`
15
+ `)}var si,ri=L(()=>{"use strict";si=`
16
16
  PRAGMA journal_mode = WAL;
17
17
  PRAGMA synchronous = NORMAL;
18
18
  PRAGMA foreign_keys = ON;
@@ -668,13 +668,13 @@ 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 ri from"sqlite-vec";function _(){if(ce)return ce;$(),ce=new gs(te),ri.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(ti),si(ce);try{ce.exec("PRAGMA optimize")}catch{}return ce}var ce,y=L(()=>{"use strict";vn();D();ni();ce=null});import Le from"chalk";import{formatDistanceToNowStrict as qp,parseISO as Kp}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 W(e){if(!e)return"";try{return qp(Kp(e),{addSuffix:!0})}catch{return""}}function H(e){return e.slice(0,8)}function ii(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 l,v=L(()=>{"use strict";l={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 yi,readFileSync as Gm,writeFileSync as zm,unlinkSync as qm}from"node:fs";import{join as Km}from"node:path";function Yt(){if(!yi(ft))return null;try{let e=Gm(ft,"utf8"),t=JSON.parse(e);return typeof t.license_jwt!="string"||t.license_jwt.length===0?null:t}catch{return null}}function Ti(e){$(),zm(ft,JSON.stringify(e,null,2)+`
672
- `,{mode:384})}function Ri(){yi(ft)&&qm(ft)}var ft,Gt=L(()=>{"use strict";D();ft=Km(R,"license.json")});var xi,qn,ki,Ci,Li=L(()=>{"use strict";xi=`-----BEGIN PUBLIC KEY-----
671
+ `});import*as oi from"sqlite-vec";function _(){if(ce)return ce;P(),ce=new gs(te),oi.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(si),ni(ce);try{ce.exec("PRAGMA optimize")}catch{}return ce}var ce,y=L(()=>{"use strict";vn();D();ri();ce=null});import Le from"chalk";import{formatDistanceToNowStrict as Zp,parseISO as Qp}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 Zp(Qp(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=L(()=>{"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 yi,readFileSync as Km,writeFileSync as Vm,unlinkSync as Zm}from"node:fs";import{join as Qm}from"node:path";function Gt(){if(!yi(_t))return null;try{let e=Km(_t,"utf8"),t=JSON.parse(e);return typeof t.license_jwt!="string"||t.license_jwt.length===0?null:t}catch{return null}}function Ti(e){P(),Vm(_t,JSON.stringify(e,null,2)+`
672
+ `,{mode:384})}function Ri(){yi(_t)&&Zm(_t)}var _t,Yt=L(()=>{"use strict";D();_t=Qm(R,"license.json")});var xi,Kn,ki,Ci,Li=L(()=>{"use strict";xi=`-----BEGIN PUBLIC KEY-----
673
673
  MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZysO2FffTLdyxQnTmnt78/ayvqz9
674
674
  kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
675
675
  -----END PUBLIC KEY-----
676
- `,qn="ES256",ki="clauderecall.com",Ci="clauderecall-cli"});import{jwtVerify as Vm,importSPKI as Zm}from"jose";async function Qm(){return Es||(Es=await Zm(xi,qn),Es)}async function bs(e){try{let t=await Qm(),{payload:s}=await Vm(e,t,{issuer:ki,audience:Ci,algorithms:[qn]});return{valid:!0,claims:s}}catch(t){return{valid:!1,reason:t instanceof Error?t.message:"verification failed"}}}var Es,Kn=L(()=>{"use strict";Li();Es=null});import{createHash as eg}from"node:crypto";import{hostname as tg,userInfo as sg,platform as ng,arch as rg}from"node:os";function Ss(){let e="unknown";try{e=sg().username}catch{}let t=[tg(),e,ng(),rg()];return eg("sha256").update(t.join("\0")).digest("hex")}var Vn=L(()=>{"use strict"});function Nt(){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 ws=L(()=>{"use strict"});import{existsSync as og,readFileSync as ig,writeFileSync as ag}from"node:fs";import{join as cg}from"node:path";function ys(){if(!og(Zn))return null;try{let e=JSON.parse(ig(Zn,"utf8"));return typeof e.license_key!="string"||typeof e.last_checked_at!="string"||typeof e.revoked!="boolean"?null:e}catch{return null}}function pg(e){$(),ag(Zn,JSON.stringify(e,null,2)+`
677
- `,{mode:384})}async function mg(e,t){let s=null,n=null;try{s=new AbortController,n=setTimeout(()=>s?.abort(),ug);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 Ni(e,t={}){let s=ys(),n=t.apiUrl??`${Nt()}/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 mg(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 pg(a),a}function Oi(e){let t=ys();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()>dg?{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 Zn,lg,dg,ug,Qn=L(()=>{"use strict";D();ws();Zn=cg(R,"license-check.json"),lg=1440*60*1e3,dg=720*60*60*1e3,ug=1e4});function fg(e=Date.now()){return e<er}function vi(e=Date.now()){return fg(e)?`(one-time purchase, $${gg} through May 2026 Founder pricing, $${Ai} from June, lifetime updates either way)`:`(one-time purchase, $${Ai}, lifetime updates)`}var er,gg,Ai,tr=L(()=>{"use strict";er=Date.UTC(2026,5,1,7,0,0),gg="29.69",Ai="49.69"});function rr(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<_g;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): ${sr}`}}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): ${sr}`};if(e.status.tier==="free"){let o=er-t;if(o>0&&o<=3*nr){let i=Math.max(1,Math.ceil(o/nr));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: ${sr}`}}}return null}var sr,nr,_g,Ii=L(()=>{"use strict";tr();sr="https://clauderecall.com/pricing",nr=1440*60*1e3,_g=60*nr});var Ts={};_e(Ts,{getLicenseStatus:()=>Te,isPro:()=>Eg,performRevocationCheck:()=>or,printTrialBannerIfAny:()=>bg,requireProOrExit:()=>Ne});async function Te(){let e=Yt();if(!e)return{tier:"free"};let t=await bs(e.license_jwt);if(!t.valid||!t.claims)return{tier:"free",invalid_reason:t.reason};if(t.claims.machine_fp&&t.claims.machine_fp!==Ss())return{tier:"free",invalid_reason:"machine fingerprint mismatch \u2014 re-activate on this device"};let s=Oi(e.license_key);return s?.revoked?{tier:"free",invalid_reason:s.reason}:hg(e,t.claims)}async function or(e){let t=Yt();if(!t)return{ran:!1,revoked:!1,reason:null,last_checked_at:null};let s=await Ni(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 hg(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 Eg(){return(await Te()).tier==="pro"}async function Ne(e){let t=await Te();if(t.tier==="pro")return;let s=rr({status:t});s&&process.stderr.write(`
676
+ `,Kn="ES256",ki="clauderecall.com",Ci="clauderecall-cli"});import{jwtVerify as eg,importSPKI as tg}from"jose";async function sg(){return Es||(Es=await tg(xi,Kn),Es)}async function bs(e){try{let t=await sg(),{payload:s}=await eg(e,t,{issuer:ki,audience:Ci,algorithms:[Kn]});return{valid:!0,claims:s}}catch(t){return{valid:!1,reason:t instanceof Error?t.message:"verification failed"}}}var Es,Vn=L(()=>{"use strict";Li();Es=null});import{createHash as ng}from"node:crypto";import{hostname as rg,userInfo as og,platform as ig,arch as ag}from"node:os";function Ss(){let e="unknown";try{e=og().username}catch{}let t=[rg(),e,ig(),ag()];return ng("sha256").update(t.join("\0")).digest("hex")}var Zn=L(()=>{"use strict"});function Nt(){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 ws=L(()=>{"use strict"});import{existsSync as cg,readFileSync as lg,writeFileSync as dg}from"node:fs";import{join as ug}from"node:path";function ys(){if(!cg(Qn))return null;try{let e=JSON.parse(lg(Qn,"utf8"));return typeof e.license_key!="string"||typeof e.last_checked_at!="string"||typeof e.revoked!="boolean"?null:e}catch{return null}}function fg(e){P(),dg(Qn,JSON.stringify(e,null,2)+`
677
+ `,{mode:384})}async function _g(e,t){let s=null,n=null;try{s=new AbortController,n=setTimeout(()=>s?.abort(),gg);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 Ni(e,t={}){let s=ys(),n=t.apiUrl??`${Nt()}/api/license/check`,r=s?.license_key===e,o=!s||!r||Date.now()-new Date(s.last_checked_at).getTime()>=pg;if(!t.force&&!o)return s;let i=await _g(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 fg(a),a}function Oi(e){let t=ys();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()>mg?{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 Qn,pg,mg,gg,er=L(()=>{"use strict";D();ws();Qn=ug(R,"license-check.json"),pg=1440*60*1e3,mg=720*60*60*1e3,gg=1e4});function Eg(e=Date.now()){return e<tr}function vi(e=Date.now()){return Eg(e)?`(one-time purchase, $${hg} through May 2026 Founder pricing, $${Ai} from June, lifetime updates either way)`:`(one-time purchase, $${Ai}, lifetime updates)`}var tr,hg,Ai,sr=L(()=>{"use strict";tr=Date.UTC(2026,5,1,7,0,0),hg="29.69",Ai="49.69"});function or(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<bg;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): ${nr}`}}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): ${nr}`};if(e.status.tier==="free"){let o=tr-t;if(o>0&&o<=3*rr){let i=Math.max(1,Math.ceil(o/rr));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: ${nr}`}}}return null}var nr,rr,bg,Ii=L(()=>{"use strict";sr();nr="https://clauderecall.com/pricing",rr=1440*60*1e3,bg=60*rr});var Ts={};_e(Ts,{getLicenseStatus:()=>Te,isPro:()=>wg,performRevocationCheck:()=>ir,printTrialBannerIfAny:()=>yg,requireProOrExit:()=>Ne});async function Te(){let e=Gt();if(!e)return{tier:"free"};let t=await bs(e.license_jwt);if(!t.valid||!t.claims)return{tier:"free",invalid_reason:t.reason};if(t.claims.machine_fp&&t.claims.machine_fp!==Ss())return{tier:"free",invalid_reason:"machine fingerprint mismatch \u2014 re-activate on this device"};let s=Oi(e.license_key);return s?.revoked?{tier:"free",invalid_reason:s.reason}:Sg(e,t.claims)}async function ir(e){let t=Gt();if(!t)return{ran:!1,revoked:!1,reason:null,last_checked_at:null};let s=await Ni(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 Sg(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 wg(){return(await Te()).tier==="pro"}async function Ne(e){let t=await Te();if(t.tier==="pro")return;let s=or({status:t});s&&process.stderr.write(`
678
678
  ${s.message}
679
679
  `),process.stderr.write(`
680
680
  ${e} is a Pro feature.
@@ -685,16 +685,16 @@ 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 bg(){let e=await Te(),t=rr({status:e});return t?(process.stderr.write(`
688
+ `),process.exit(1)}async function yg(){let e=await Te(),t=or({status:e});return t?(process.stderr.write(`
689
689
  ${t.message}
690
690
 
691
- `),!0):!1}var he=L(()=>{"use strict";Gt();Kn();Vn();Qn();tr();Ii()});import{writeFileSync as v0,readFileSync as wg,existsSync as yg}from"node:fs";import{join as Tg}from"node:path";function Di(){if(!yg(Rs))return null;try{return wg(Rs,"utf8").trim()}catch{return null}}var Rs,ir=L(()=>{"use strict";D();Rs=Tg(R,"daemon.token")});import{existsSync as $i,readFileSync as Rg,writeFileSync as P0,unlinkSync as xg}from"node:fs";import{join as cr}from"node:path";function Cg(){if(!$i(ar))return null;try{let e=JSON.parse(Rg(ar,"utf8"));return typeof e.pid!="number"||typeof e.port!="number"?null:e}catch{return null}}function zt(){for(let e of[ar,kg,Rs])if($i(e))try{xg(e)}catch{}}function lr(e){try{return process.kill(e,0),!0}catch{return!1}}function Z(){let e=Cg();return e?lr(e.pid)?e:(zt(),null):null}var ar,kg,xs,Ge=L(()=>{"use strict";D();ir();ar=cr(R,"daemon.pid"),kg=cr(R,"daemon.port"),xs=cr(R,"daemon.log")});import{existsSync as Ag}from"node:fs";import{dirname as Fi}from"node:path";import{fileURLToPath as vg}from"node:url";function le(){if(ks)return ks;let e=Fi(vg(import.meta.url));for(;!Ag(`${e}/package.json`);){let t=Fi(e);if(t===e)throw new Error(`package.json not found walking up from ${import.meta.url}`);e=t}return ks=e,ks}var ks,Ze=L(()=>{"use strict";ks=null});import{writeFileSync as mf}from"node:fs";import{join as gf}from"node:path";function gr(e){try{let t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return[]}function Os(e){return _().prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(e)?.alias??null}function _f(){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:gr(t.previous_aliases)}))}function Ot(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=gr(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 he=L(()=>{"use strict";Yt();Vn();Zn();er();sr();Ii()});import{writeFileSync as $0,readFileSync as Tg,existsSync as Rg}from"node:fs";import{join as xg}from"node:path";function Mi(){if(!Rg(Rs))return null;try{return Tg(Rs,"utf8").trim()}catch{return null}}var Rs,ar=L(()=>{"use strict";D();Rs=xg(R,"daemon.token")});import{existsSync as ji,readFileSync as Og,writeFileSync as V0,unlinkSync as Ag}from"node:fs";import{join as lr}from"node:path";function Ig(){if(!ji(cr))return null;try{let e=JSON.parse(Og(cr,"utf8"));return typeof e.pid!="number"||typeof e.port!="number"?null:e}catch{return null}}function zt(){for(let e of[cr,vg,Rs])if(ji(e))try{Ag(e)}catch{}}function dr(e){try{return process.kill(e,0),!0}catch{return!1}}function Q(){let e=Ig();return e?dr(e.pid)?e:(zt(),null):null}var cr,vg,xs,ze=L(()=>{"use strict";D();ar();cr=lr(R,"daemon.pid"),vg=lr(R,"daemon.port"),xs=lr(R,"daemon.log")});import{existsSync as Pg}from"node:fs";import{dirname as Bi}from"node:path";import{fileURLToPath as jg}from"node:url";function le(){if(ks)return ks;let e=Bi(jg(import.meta.url));for(;!Pg(`${e}/package.json`);){let t=Bi(e);if(t===e)throw new Error(`package.json not found walking up from ${import.meta.url}`);e=t}return ks=e,ks}var ks,et=L(()=>{"use strict";ks=null});import{writeFileSync as bf}from"node:fs";import{join as Sf}from"node:path";function fr(e){try{let t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return[]}function Os(e){return _().prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(e)?.alias??null}function yf(){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:fr(t.previous_aliases)}))}function Ot(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=fr(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)),Ea(),{session_id:e,alias:s,updated_at:r,previous_aliases:i}}function ha(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=gr(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),Ea()}function Ea(){try{$();let e=_f(),t={schema:"claude-recall.aliases.v1",backed_up_at:new Date().toISOString(),aliases:e};mf(ff,JSON.stringify(t,null,2))}catch(e){console.error("[aliases] backup failed:",e)}}var ff,_t=L(()=>{"use strict";y();D();ff=gf(R,"aliases.json")});import{writeFileSync as Bf}from"node:fs";import{join as Hf}from"node:path";function Xf(e){return e.trim().toLowerCase().replace(/^#+/,"").replace(/[\s/\\]+/g,"-").replace(/[^a-z0-9\-._]/g,"").slice(0,40)}function Na(e,t){let s=Xf(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)})(),Jf(),{tag:s,added:!0})}function Oa(e){return _().prepare("SELECT tag FROM session_tags WHERE session_id = ? ORDER BY tag").all(e).map(t=>t.tag)}function Jf(){try{$();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};Bf(Wf,JSON.stringify(n,null,2))}catch(e){console.error("[tags] backup failed:",e)}}var Wf,_r=L(()=>{"use strict";y();D();Wf=Hf(R,"tags.json")});function Yf(e,t){let s=e.filter(o=>o.content_text&&o.content_text.trim().length>0);if(s.length<=t)return s;let n=new Set;n.add(0),n.add(s.length-1);let r=(s.length-2)/Math.max(1,t-2);for(let o=1;o<t-1;o++)n.add(Math.floor(o*r));return Array.from(n).sort((o,i)=>o-i).slice(0,t).map(o=>s[o])}function Aa(e){let t=_(),s={limit:e.limit??500},n=e.sessionIds&&e.sessionIds.length>0,r=n?"1=1":"s.message_count > 2";if(n){let i=e.sessionIds.map((a,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)),Sa(),{session_id:e,alias:s,updated_at:r,previous_aliases:i}}function ba(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=fr(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),Sa()}function Sa(){try{P();let e=yf(),t={schema:"claude-recall.aliases.v1",backed_up_at:new Date().toISOString(),aliases:e};bf(wf,JSON.stringify(t,null,2))}catch(e){console.error("[aliases] backup failed:",e)}}var wf,ht=L(()=>{"use strict";y();D();wf=Sf(R,"aliases.json")});import{writeFileSync as Yf}from"node:fs";import{join as zf}from"node:path";function Kf(e){return e.trim().toLowerCase().replace(/^#+/,"").replace(/[\s/\\]+/g,"-").replace(/[^a-z0-9\-._]/g,"").slice(0,40)}function Aa(e,t){let s=Kf(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)})(),Vf(),{tag:s,added:!0})}function va(e){return _().prepare("SELECT tag FROM session_tags WHERE session_id = ? ORDER BY tag").all(e).map(t=>t.tag)}function Vf(){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};Yf(qf,JSON.stringify(n,null,2))}catch(e){console.error("[tags] backup failed:",e)}}var qf,hr=L(()=>{"use strict";y();D();qf=zf(R,"tags.json")});function Zf(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 Ia(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),c=Yf(a,5).map(u=>`${u.role}: ${u.content_text.slice(0,400)}`).join(`
707
+ ORDER BY COALESCE(timestamp, ''), rowid`).all(i.id),l=Zf(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:c,current_tags:Oa(i.id)}})}var va=L(()=>{"use strict";y();_r()});import{z as Re}from"zod";function Ia(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 WC,XC,JC,YC,Ma=L(()=>{"use strict";WC={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).")};XC={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.")},JC={sessionId:Re.string().describe("Session UUID (or 8+-char prefix) to extract decisions from.")},YC={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 Da(e,t){let s=Gf.get(e);if(!(!s||s.size===0))for(let n of s)try{n(t)}catch{}}var Gf,$a=L(()=>{"use strict";Gf=new Map});import{existsSync as zf,statSync as qf}from"node:fs";import{delimiter as Kf,join as Vf}from"node:path";function Pa(e){if(e.includes("/")||e.includes("\\")||e.includes(".."))return null;let t=(process.env.PATH??"").split(Kf).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=Vf(n,r);try{if(zf(o)&&qf(o).isFile())return o}catch{}}return null}var ja=L(()=>{"use strict"});var Is={};_e(Is,{_resetClaudePathCacheForTests:()=>t_,buildScanPrompt:()=>Ua,isClaudeCliAvailable:()=>se,runClaudeCliScan:()=>i_,spawnClaudePrompt:()=>ht});import{spawn as Zf}from"node:child_process";function Fa(){if(At!==void 0&&Kt!==void 0)return{path:At,available:Kt};let e=Pa("claude");return At=e??"claude",Kt=e!==null,{path:At,available:Kt}}function e_(){return Fa().path}function se(){return Fa().available}function t_(){At=void 0,Kt=void 0}function Ua(e){return Ia({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 s_(e,t){let s=t.get(e);return s||e.slice(0,8)}function n_(e){try{return Aa(e).map(s=>({id:s.id,label:s.alias&&s.alias.trim().length>0?s.alias:s.first_user_message&&s.first_user_message.trim().length>0?s.first_user_message.slice(0,60):s.id.slice(0,8)}))}catch{return[]}}function r_(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 c of d.message.content){if(c?.type!=="tool_use"||c.name!=="mcp__recall__apply_tags")continue;let u=c.input,p=typeof u?.sessionId=="string"?u.sessionId:null;!p||r.has(p)||(r.add(p),Da(t,{type:"progress",current:r.size,total:s,sessionId:p,sessionLabel:s_(p,n)}))}}}function o_(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:va(i.id)}})}var Ma=L(()=>{"use strict";y();hr()});import{z as Re}from"zod";function Da(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 nL,rL,oL,iL,$a=L(()=>{"use strict";nL={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).")};rL={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.")},oL={sessionId:Re.string().describe("Session UUID (or 8+-char prefix) to extract decisions from.")},iL={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 Pa(e,t){let s=Qf.get(e);if(!(!s||s.size===0))for(let n of s)try{n(t)}catch{}}var Qf,ja=L(()=>{"use strict";Qf=new Map});import{existsSync as e_,statSync as t_}from"node:fs";import{delimiter as s_,join as n_}from"node:path";function Fa(e){if(e.includes("/")||e.includes("\\")||e.includes(".."))return null;let t=(process.env.PATH??"").split(s_).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=n_(n,r);try{if(e_(o)&&t_(o).isFile())return o}catch{}}return null}function Ua(e){if(process.platform!=="win32"||!e)return!1;let t=e.toLowerCase();return t.endsWith(".cmd")||t.endsWith(".bat")}var Ba=L(()=>{"use strict"});var Is={};_e(Is,{_resetClaudePathCacheForTests:()=>a_,buildScanPrompt:()=>Wa,isClaudeCliAvailable:()=>se,runClaudeCliScan:()=>p_,spawnClaudePrompt:()=>Et});import{spawn as r_}from"node:child_process";function Ha(){if(At!==void 0&&Kt!==void 0)return{path:At,available:Kt};let e=Fa("claude");return At=e??"claude",Kt=e!==null,{path:At,available:Kt}}function i_(){return Ha().path}function se(){return Ha().available}function a_(){At=void 0,Kt=void 0}function Wa(e){return Da({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 c_(e,t){let s=t.get(e);return s||e.slice(0,8)}function l_(e){try{return Ia(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 d_(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),Pa(t,{type:"progress",current:r.size,total:s,sessionId:p,sessionLabel:c_(p,n)}))}}}function u_(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 i_(e,t={},s){let n=!!t.scanId,r=n?n_(e):[],o=new Map(r.map(d=>[d.id,d.label])),i=r.length,a;return n&&t.scanId&&(a=r_({scanId:t.scanId,total:i,labelTable:o})),Ba({prompt:Ua(e),allowedTools:Qf.split(","),opts:t,onProgress:s,onStdoutLine:a,outputFormat:n?"stream-json":"json"})}async function ht(e,t,s={},n){return Ba({prompt:e,allowedTools:t,opts:s,onProgress:n,outputFormat:"json"})}function Ba(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 c=Zf(e_(),a,{stdio:["ignore","pipe","pipe"],shell:process.platform==="win32"&&At==="claude"}),u=[],p=[],m=o?o_(o):void 0;c.stdout.on("data",g=>{u.push(g),m&&m(g)}),c.stderr.on("data",g=>{if(p.push(g),r){let h=g.toString("utf8").trim();h&&r(h)}});let f=setTimeout(()=>{c.kill("SIGKILL")},1800*1e3);c.on("close",g=>{clearTimeout(f),d({success:g===0,stdout:Buffer.concat(u).toString("utf8"),stderr:Buffer.concat(p).toString("utf8"),exitCode:g})}),c.on("error",g=>{clearTimeout(f),d({success:!1,stdout:"",stderr:String(g),exitCode:null})})})}var Qf,At,Kt,Be=L(()=>{"use strict";va();Ma();$a();ja();Qf=["mcp__recall__list_tags","mcp__recall__list_sessions_to_tag","mcp__recall__apply_tags"].join(",")});var Ya={};_e(Ya,{downloadModel:()=>Sr,getModelDir:()=>Ps,isModelInstalled:()=>Et,uninstallModel:()=>wr});import{existsSync as br,mkdirSync as Xa,rmSync as Er,createWriteStream as x_,statSync as k_}from"node:fs";import{join as $s}from"node:path";import{createHash as C_}from"node:crypto";import{readFile as L_}from"node:fs/promises";function Ps(){return $s(R,"models","BAAI","bge-base-en-v1.5")}function Et(){let e=Ps();return Ja.every(t=>br($s(e,t.path)))}async function Sr(e){let t=Ps();Xa(t,{recursive:!0}),Xa($s(t,"onnx"),{recursive:!0});for(let s of Ja){let n=$s(t,s.path),r=N_+s.path,o=0;br(n)&&(o=k_(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"),c=d?o+Number(d):0,u=a.body;if(!u)throw new Error(`No response body for ${s.path}`);let p=x_(n,{flags:o>0?"a":"w"}),m=u.getReader(),f=o;for(;;){let{done:E,value:b}=await m.read();if(E)break;p.write(Buffer.from(b)),f+=b.byteLength,e?.(s.path,f,c)}if(p.end(),await new Promise((E,b)=>{p.on("finish",E),p.on("error",b)}),s.sha256==="TODO_PLACEHOLDER")throw Er(n),new Error(`Refusing to install: SHA-256 not pinned for ${s.path}. Update model-download.ts.`);let g=await L_(n);if(C_("sha256").update(g).digest("hex")!==s.sha256)throw Er(n),new Error(`SHA-256 mismatch for ${s.path}`)}}function wr(){let e=Ps();br(e)&&Er(e,{recursive:!0,force:!0})}var N_,Ja,js=L(()=>{"use strict";D();N_="https://huggingface.co/BAAI/bge-base-en-v1.5/resolve/main/",Ja=[{path:"config.json",sha256:"bc00af31a4a31b74040d73370aa83b62da34c90b75eb77bfa7db039d90abd591"},{path:"tokenizer.json",sha256:"d241a60d5e8f04cc1b2b3e9ef7a4921b27bf526d9f6050ab90f9267a1f9e5c66"},{path:"tokenizer_config.json",sha256:"9261e7d79b44c8195c1cada2b453e55b00aeb81e907a6664974b4d7776172ab3"},{path:"onnx/model.onnx",sha256:"9bc579acdba21c253c62a9bf866891355a63ffa3442b52c8a37d75b2ccb91848"}]});var Ga,za=L(()=>{"use strict";Ga="BAAI/bge-base-en-v1.5"});var xr={};_e(xr,{EmbedderUnavailableError:()=>Zt,embed:()=>vt,embedQuery:()=>Rr,getEmbedderStatus:()=>qe,loadEmbedder:()=>Qe,unloadEmbedder:()=>$_});import{Worker as A_}from"node:worker_threads";import{join as v_}from"node:path";import{existsSync as I_}from"node:fs";function M_(){return v_(le(),"dist","daemon","embedder-worker.js")}function qa(e){for(let t of Vt.values())t.reject(e);Vt.clear()}function D_(){if(ze)return ze;let e=M_();if(!I_(e))throw new Zt(new Error(`embedder-worker bundle not found at ${e}. Run \`npm run build:cli\` to emit it.`));let t=new A_(e);return t.on("message",s=>{let n=Vt.get(s.id);n&&(Vt.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));qa(n),ze=null,He=!1}),t.on("exit",s=>{s!==0&&(console.error(`[embedder-worker] exited with code ${s}`),qa(new Error(`embedder worker exited with code ${s}`))),ze=null,He=!1}),ze=t,t}function Fs(e){return new Promise((t,s)=>{let n;try{n=D_()}catch(r){s(r instanceof Error?r:new Error(String(r)));return}Vt.set(e.id,{resolve:t,reject:s}),n.postMessage(e)})}function Us(){return yr=yr+1>>>0,String(yr)}function Tr(e){if(!e.ok)throw e.unavailable?new Zt(new Error(e.error)):new Error(e.error);return e}async function Qe(){if(!(He&&ze))try{Tr(await Fs({id:Us(),type:"load"})),He=!0}catch(e){throw He=!1,e}}function qe(){return{loaded:He,modelId:Ga,dim:768}}async function vt(e){if(!He)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");return Tr(await Fs({id:Us(),type:"embed",texts:e})).embeddings.map(s=>new Float32Array(s))}async function Rr(e){if(!He)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");let t=Tr(await Fs({id:Us(),type:"embedQuery",text:e}));return new Float32Array(t.embedding)}async function $_(){if(!ze){He=!1;return}try{await Fs({id:Us(),type:"unload"})}catch{}He=!1;let e=ze;ze=null;try{await e.terminate()}catch{}}var ze,Vt,yr,He,Zt,et=L(()=>{"use strict";Ze();za();ze=null,Vt=new Map,yr=0,He=!1,Zt=class extends Error{cause;constructor(t){let s=t instanceof Error?t.message:String(t);super(["Semantic search is unavailable on this platform.","",`Reason: ${s}`,"",`Platform: ${process.platform}/${process.arch}, Node ${process.version}`,"","Claude Recall supports macOS (arm64/x64), Linux (x64/arm64), and Windows (x64).","Core CLI features (search, list, context, daemon) work everywhere.","Only `recall semantic *` requires the on-device embedder.","","See: https://clauderecall.com/docs (Supported platforms) \u2014 or file an issue at","https://gitlab.com/clauderecallhq/clauderecallhq/-/issues with the platform line above."].join(`
713
- `)),this.name="EmbedderUnavailableError",this.cause=t}}});var Za={};_e(Za,{ensureTransformersInstalled:()=>V_});import{spawn as H_}from"node:child_process";import{existsSync as W_}from"node:fs";import{dirname as X_,resolve as J_}from"node:path";import{fileURLToPath as Y_}from"node:url";function z_(){let e=X_(Y_(import.meta.url));return J_(e,"..","..")}async function q_(){try{return await import("@huggingface/transformers"),!0}catch{return!1}}function K_(e){return new Promise(t=>{let s=["install","--no-save","--no-audit","--no-fund","--prefix",e,`@huggingface/transformers@${G_}`],n=H_("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}`})})})}async function V_(){if(await q_())return{ok:!0,action:"already-installed"};let e=z_();return W_(e)?(console.log(`Installing @huggingface/transformers into ${e} ...`),K_(e)):{ok:!1,error:`package root not found at ${e}`}}var G_,Qa=L(()=>{"use strict";G_="^3.4.1"});import{writeFileSync as mc,readFileSync as SN,existsSync as gc,mkdirSync as fc,readdirSync as wN}from"node:fs";import{join as Ws}from"node:path";function Ph(){$(),gc(vr)||fc(vr,{recursive:!0})}function jh(){$(),gc(Ir)||fc(Ir,{recursive:!0})}function _c(e){try{return JSON.parse(e)}catch{return e}}function Mr(e){return{id:e.id,source_session_id:e.source_session_id,target_session_id:e.target_session_id,link_type:e.link_type,confidence:e.confidence,source:e.source,evidence:_c(e.evidence),approved:e.approved===1,created_at:e.created_at,updated_at:e.updated_at}}function Dr(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:_c(e.evidence),status:e.status,inferred_by:e.inferred_by,created_at:e.created_at,decided_at:e.decided_at}}function Fh(e){if(!Number.isFinite(e)||e<0||e>1)throw new Error("confidence must be a number in [0, 1]")}function hc(e){if(!vh.has(e))throw new Error(`invalid link_type: ${e}`)}function Ec(e){if(!Dh.has(e))throw new Error(`invalid inferred_by: ${e}`)}function Uh(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 Bh(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&&(hc(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 p_(e,t={},s){let n=!!t.scanId,r=n?l_(e):[],o=new Map(r.map(d=>[d.id,d.label])),i=r.length,a;return n&&t.scanId&&(a=d_({scanId:t.scanId,total:i,labelTable:o})),Xa({prompt:Wa(e),allowedTools:o_.split(","),opts:t,onProgress:s,onStdoutLine:a,outputFormat:n?"stream-json":"json"})}async function Et(e,t,s={},n){return Xa({prompt:e,allowedTools:t,opts:s,onProgress:n,outputFormat:"json"})}function Xa(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=i_(),u=r_(l,a,{stdio:["ignore","pipe","pipe"],shell:Ua(l)||process.platform==="win32"&&At==="claude"}),p=[],m=[],f=o?u_(o):void 0;u.stdout.on("data",h=>{p.push(h),f&&f(h)}),u.stderr.on("data",h=>{if(m.push(h),r){let E=h.toString("utf8").trim();E&&r(E)}});let g=setTimeout(()=>{u.kill("SIGKILL")},1800*1e3);u.on("close",h=>{clearTimeout(g),d({success:h===0,stdout:Buffer.concat(p).toString("utf8"),stderr:Buffer.concat(m).toString("utf8"),exitCode:h})}),u.on("error",h=>{clearTimeout(g),d({success:!1,stdout:"",stderr:String(h),exitCode:null})})})}var o_,At,Kt,Be=L(()=>{"use strict";Ma();$a();ja();Ba();o_=["mcp__recall__list_tags","mcp__recall__list_sessions_to_tag","mcp__recall__apply_tags"].join(",")});var qa={};_e(qa,{downloadModel:()=>wr,getModelDir:()=>Ps,isModelInstalled:()=>bt,uninstallModel:()=>yr});import{existsSync as Sr,mkdirSync as Ya,rmSync as br,createWriteStream as A_,statSync as v_}from"node:fs";import{join as $s}from"node:path";import{createHash as I_}from"node:crypto";import{readFile as M_}from"node:fs/promises";function Ps(){return $s(R,"models","BAAI","bge-base-en-v1.5")}function bt(){let e=Ps();return za.every(t=>Sr($s(e,t.path)))}async function wr(e){let t=Ps();Ya(t,{recursive:!0}),Ya($s(t,"onnx"),{recursive:!0});for(let s of za){let n=$s(t,s.path),r=D_+s.path,o=0;Sr(n)&&(o=v_(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=A_(n,{flags:o>0?"a":"w"}),m=u.getReader(),f=o;for(;;){let{done:E,value:b}=await m.read();if(E)break;p.write(Buffer.from(b)),f+=b.byteLength,e?.(s.path,f,l)}if(p.end(),await new Promise((E,b)=>{p.on("finish",E),p.on("error",b)}),s.sha256==="TODO_PLACEHOLDER")throw br(n),new Error(`Refusing to install: SHA-256 not pinned for ${s.path}. Update model-download.ts.`);let g=await M_(n);if(I_("sha256").update(g).digest("hex")!==s.sha256)throw br(n),new Error(`SHA-256 mismatch for ${s.path}`)}}function yr(){let e=Ps();Sr(e)&&br(e,{recursive:!0,force:!0})}var D_,za,js=L(()=>{"use strict";D();D_="https://huggingface.co/BAAI/bge-base-en-v1.5/resolve/main/",za=[{path:"config.json",sha256:"bc00af31a4a31b74040d73370aa83b62da34c90b75eb77bfa7db039d90abd591"},{path:"tokenizer.json",sha256:"d241a60d5e8f04cc1b2b3e9ef7a4921b27bf526d9f6050ab90f9267a1f9e5c66"},{path:"tokenizer_config.json",sha256:"9261e7d79b44c8195c1cada2b453e55b00aeb81e907a6664974b4d7776172ab3"},{path:"onnx/model.onnx",sha256:"9bc579acdba21c253c62a9bf866891355a63ffa3442b52c8a37d75b2ccb91848"}]});var Ka,Va=L(()=>{"use strict";Ka="BAAI/bge-base-en-v1.5"});var kr={};_e(kr,{EmbedderUnavailableError:()=>Zt,embed:()=>vt,embedQuery:()=>xr,getEmbedderStatus:()=>Ke,loadEmbedder:()=>tt,unloadEmbedder:()=>W_});import{Worker as P_}from"node:worker_threads";import{join as j_}from"node:path";import{existsSync as F_}from"node:fs";function U_(){return j_(le(),"dist","daemon","embedder-worker.js")}function B_(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 Za(e){for(let t of Vt.values())t.reject(e);Vt.clear()}function H_(){if(qe)return qe;let e=U_();if(!F_(e))throw new Zt({kind:"bundle-missing",detail:"embedder-worker bundle not found \u2014 run `npm run build:cli` to emit it",path:e});let t=new P_(e);return t.on("message",s=>{let n=Vt.get(s.id);n&&(Vt.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));Za(n),qe=null,He=!1}),t.on("exit",s=>{s!==0&&(console.error(`[embedder-worker] exited with code ${s}`),Za(new Error(`embedder worker exited with code ${s}`))),qe=null,He=!1}),qe=t,t}function Fs(e){return new Promise((t,s)=>{let n;try{n=H_()}catch(r){s(r instanceof Error?r:new Error(String(r)));return}Vt.set(e.id,{resolve:t,reject:s}),n.postMessage(e)})}function Us(){return Tr=Tr+1>>>0,String(Tr)}function Rr(e){if(!e.ok)throw e.unavailable?new Zt({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 tt(){if(!(He&&qe))try{Rr(await Fs({id:Us(),type:"load"})),He=!0}catch(e){throw He=!1,e}}function Ke(){return{loaded:He,modelId:Ka,dim:768}}async function vt(e){if(!He)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");return Rr(await Fs({id:Us(),type:"embed",texts:e})).embeddings.map(s=>new Float32Array(s))}async function xr(e){if(!He)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");let t=Rr(await Fs({id:Us(),type:"embedQuery",text:e}));return new Float32Array(t.embedding)}async function W_(){if(!qe){He=!1;return}try{await Fs({id:Us(),type:"unload"})}catch{}He=!1;let e=qe;qe=null;try{await e.terminate()}catch{}}var qe,Vt,Tr,He,Zt,st=L(()=>{"use strict";et();Va();qe=null,Vt=new Map,Tr=0,He=!1,Zt=class extends Error{kind;path;underlying;cause;constructor(t){super(B_(t)),this.name="EmbedderUnavailableError",this.kind=t.kind,this.path=t.path,this.underlying=t.underlying,this.cause=t}}});var sc={};_e(sc,{detectRunningClaudeOnWindows:()=>tc,ensureTransformersInstalled:()=>oh});import{execFileSync as q_,spawn as K_}from"node:child_process";import{existsSync as V_}from"node:fs";import{dirname as Z_,resolve as Q_}from"node:path";import{fileURLToPath as eh}from"node:url";function sh(){let e=Z_(eh(import.meta.url));return Q_(e,"..","..")}async function nh(){try{return await import("@huggingface/transformers"),!0}catch{return!1}}function rh(e){return new Promise(t=>{let s=["install","--no-save","--no-audit","--no-fund","--prefix",e,`@huggingface/transformers@${th}`],n=K_("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 tc(){if(process.platform!=="win32")return!1;try{return q_("tasklist",["/FI","IMAGENAME eq claude.exe"],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).toLowerCase().includes("claude.exe")}catch{return!1}}async function oh(){if(await nh())return{ok:!0,action:"already-installed"};if(tc())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=sh();return V_(e)?(console.log(`Installing @huggingface/transformers into ${e} ...`),rh(e)):{ok:!1,error:`package root not found at ${e}`}}var th,nc=L(()=>{"use strict";th="^3.4.1"});import{writeFileSync as hc,readFileSync as MN,existsSync as Ec,mkdirSync as bc,readdirSync as DN}from"node:fs";import{join as Ws}from"node:path";function Jh(){P(),Ec(Ir)||bc(Ir,{recursive:!0})}function Gh(){P(),Ec(Mr)||bc(Mr,{recursive:!0})}function Sc(e){try{return JSON.parse(e)}catch{return e}}function Dr(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:Sc(e.evidence),approved:e.approved===1,created_at:e.created_at,updated_at:e.updated_at}}function $r(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:Sc(e.evidence),status:e.status,inferred_by:e.inferred_by,created_at:e.created_at,decided_at:e.decided_at}}function Yh(e){if(!Number.isFinite(e)||e<0||e>1)throw new Error("confidence must be a number in [0, 1]")}function wc(e){if(!Uh.has(e))throw new Error(`invalid link_type: ${e}`)}function yc(e){if(!Wh.has(e))throw new Error(`invalid inferred_by: ${e}`)}function zh(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 qh(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&&(wc(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(Mr)}function $r(e){return _().prepare(`SELECT * FROM session_links
715
+ LIMIT ?`).all(...n,o).map(Dr)}function Pr(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(Mr)}function st(e){Uh(e.source_session_id,e.target_session_id),hc(e.link_type),Fh(e.confidence),Ec(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(Dr)}function rt(e){zh(e.source_session_id,e.target_session_id),wc(e.link_type),Yh(e.confidence),yc(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 Sc(),Dr(r)}function Xs(e={}){let t=_(),s=[],n=[];if(e.status){if(!Mh.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&&(Ec(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 Rc(),$r(r)}function Xs(e={}){let t=_(),s=[],n=[];if(e.status){if(!Hh.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&&(yc(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(Dr)}function bc(e,t,s={}){if(t!=="approved"&&t!=="rejected")throw new Error(`invalid decision: ${t}`);let n=s.source??"manual";if(!Ih.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($r)}function Tc(e,t,s={}){if(t!=="approved"&&t!=="rejected")throw new Error(`invalid decision: ${t}`);let n=s.source??"manual";if(!Bh.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))})(),Sc(),t==="approved"&&Hh(o.source_session_id);let d=r.prepare("SELECT * FROM session_link_suggestions WHERE id = ?").get(e);return{suggestion:Dr(d),link:a?Mr(a):null}}function Hh(e){try{Ph();let t=Bh({sourceSessionId:e}),s=Ws(vr,`${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};mc(s,JSON.stringify(n,null,2))}catch(t){console.error("[session-links] backup failed:",t)}}function Sc(){try{jh();let e=Xs({limit:5e3}),t={schema:"claude-recall.session-link-suggestions.v1",backed_up_at:new Date().toISOString(),suggestions:e};mc($h,JSON.stringify(t,null,2))}catch(e){console.error("[session-links] suggestions backup failed:",e)}}var vh,Ih,Mh,Dh,vr,Ir,$h,ss=L(()=>{"use strict";y();D();vh=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),Ih=new Set(["regex","llm","embedding","manual","auto","citation","git","terminal-registry"]),Mh=new Set(["pending","approved","rejected"]),Dh=new Set(["L1","L2","L3","L4","user"]),vr=Ws(R,"links"),Ir=Ws(R,"suggestions"),$h=Ws(Ir,"index.json")});function qs(e){return e?Math.ceil(e.length/4):0}function Jc(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/ib);return Math.max(ab,t)}function Yc(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 Gc(e){return _().prepare(`SELECT s.id,
754
+ AND link_type = ?`).get(o.source_session_id,o.target_session_id,o.link_type))})(),Rc(),t==="approved"&&Kh(o.source_session_id);let d=r.prepare("SELECT * FROM session_link_suggestions WHERE id = ?").get(e);return{suggestion:$r(d),link:a?Dr(a):null}}function Kh(e){try{Jh();let t=qh({sourceSessionId:e}),s=Ws(Ir,`${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};hc(s,JSON.stringify(n,null,2))}catch(t){console.error("[session-links] backup failed:",t)}}function Rc(){try{Gh();let e=Xs({limit:5e3}),t={schema:"claude-recall.session-link-suggestions.v1",backed_up_at:new Date().toISOString(),suggestions:e};hc(Xh,JSON.stringify(t,null,2))}catch(e){console.error("[session-links] suggestions backup failed:",e)}}var Uh,Bh,Hh,Wh,Ir,Mr,Xh,ss=L(()=>{"use strict";y();D();Uh=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),Bh=new Set(["regex","llm","embedding","manual","auto","citation","git","terminal-registry"]),Hh=new Set(["pending","approved","rejected"]),Wh=new Set(["L1","L2","L3","L4","user"]),Ir=Ws(R,"links"),Mr=Ws(R,"suggestions"),Xh=Ws(Mr,"index.json")});function qs(e){return e?Math.ceil(e.length/4):0}function qc(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/gb);return Math.max(fb,t)}function Kc(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 Vc(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,21 +762,21 @@ ${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 zc(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 qc(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 lb(e){let s=_().prepare(`SELECT id, auto_title, started_at
765
+ WHERE s.id = ?`).get(e)??null}function Zc(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 Qc(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 hb(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 f=m.auto_title.split(" \xB7 "),g=f[0].trim(),h=f.length>1?f.slice(1).join(" \xB7 ").trim():null;o.push({id:m.id,brand:h||null,skill:g||null}),h&&n.add(h),g&&r.add(g)}let i=[...n].sort(),a=new Map;i.forEach((m,f)=>a.set(m,f));let d=[...r].sort(),c=new Map;d.forEach((m,f)=>c.set(m,f));let u=new Map,p=new Map;for(let m of o){if(!m.brand||!m.skill)continue;let f=a.get(m.brand),g=c.get(m.skill);if(f===void 0||g===void 0)continue;let h=`${f}.${g}`,E=(u.get(h)??0)+1;u.set(h,E),p.set(m.id,`${f}.${g}.${E}`)}return{byId:p}}function db(e){return{table:e!==null?lb(e):null,originProjectId:e,cache:new Map}}function Ks(e,t){let s=e.cache.get(t);if(s)return s;let n=Gc(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:qc(n),decimal:r,summary:zc(n.id),project:n.project,started_at:n.started_at};return e.cache.set(t,o),o}function ub(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 f=m.auto_title.split(" \xB7 "),g=f[0].trim(),h=f.length>1?f.slice(1).join(" \xB7 ").trim():null;o.push({id:m.id,brand:h||null,skill:g||null}),h&&n.add(h),g&&r.add(g)}let i=[...n].sort(),a=new Map;i.forEach((m,f)=>a.set(m,f));let d=[...r].sort(),l=new Map;d.forEach((m,f)=>l.set(m,f));let u=new Map,p=new Map;for(let m of o){if(!m.brand||!m.skill)continue;let f=a.get(m.brand),g=l.get(m.skill);if(f===void 0||g===void 0)continue;let h=`${f}.${g}`,E=(u.get(h)??0)+1;u.set(h,E),p.set(m.id,`${f}.${g}.${E}`)}return{byId:p}}function Eb(e){return{table:e!==null?hb(e):null,originProjectId:e,cache:new Map}}function Ks(e,t){let s=e.cache.get(t);if(s)return s;let n=Vc(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:Qc(n),decimal:r,summary:Zc(n.id),project:n.project,started_at:n.started_at};return e.cache.set(t,o),o}function bb(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=Ks(e,o.pid);i&&r.push(i)}return r}function pb(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=Ks(e,o.pid);i&&r.push(i)}return r}function Sb(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=Ks(e,o.sid);i&&r.push(i)}return r}function Kc(e){let t=cb[e.linkType]??.5,s=It(e.confidence),n=t*s,r=Jc(e.daysApart),o=e.embeddingCosine??.5,i=It(e.pagerank);if(e.scoring==="pagerank")return It(i);if(e.scoring==="embedding-rerank")return e.embeddingCosine===null?It(n):It(o);let a=.35*n+.2*r+.2*o+.25*i;return It(a)}function It(e){return!Number.isFinite(e)||e<0?0:e>1?1:e}function mb(e,t,s,n,r){let o=new Map;function i(a,d){if(a===d)return;let c=o.get(a);c||(c=new Set,o.set(a,c)),c.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 c=1;c<r;c++){let u=new Set;for(let p of a){let m=o.get(p);if(m)for(let f of m){if(d.has(f))continue;let g=$r(f).filter(h=>h.approved);for(let h of g)i(h.source_session_id,h.target_session_id),i(h.target_session_id,h.source_session_id);d.add(f),u.add(f)}}if(u.size===0)break;for(let p of u)a.add(p)}}return{edges:o}}function gb(e,t={}){let s=t.iterations??12,n=t.damping??.85,r=Array.from(e.edges.keys());if(r.length===0)return new Map;let o=1/r.length,i=new Map(r.map(c=>[c,o]));for(let c=0;c<s;c++){let u=new Map(r.map(p=>[p,(1-n)/r.length]));for(let p of r){let m=e.edges.get(p);if(!m||m.size===0)continue;let f=(i.get(p)??0)/m.size;for(let g of m)u.set(g,(u.get(g)??0)+n*f)}i=u}let a=0;for(let c of i.values())c>a&&(a=c);if(a<=0)return i;let d=new Map;for(let[c,u]of i)d.set(c,u/a);return d}function Zc(e,t){let s=e.replace(/\s+/g," ").trim();return s.length<=t?s:`${s.slice(0,t-1).trimEnd()}\u2026`}function fb(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=Zc(e.summary,Vc);return`${r}
774
- ${o}`}return r}function _b(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+=qs(a),e.summary){let d=Zc(e.summary,Vc*4);n.push(d),o+=qs(d)}n.push("");for(let d of t){if(d.refs.length===0)continue;let c=`## ${d.heading}`,u=qs(c),p=[],m=0;for(let f of d.refs){let g=fb(f),h=qs(g);if(o+u+m+h>s){r.push({session_id:f.session_id,title:f.title,decimal:f.decimal,summary:f.summary,project:f.project,started_at:f.started_at});continue}p.push(g),m+=h}if(p.length>0){n.push(c);for(let f of p)n.push(f);n.push(""),o+=u+m}}for(;n.length>0&&n[n.length-1]==="";)n.pop();return{bundle:n.join(`
773
+ WHERE te.parent_session_id = ?`).all(t),r=[];for(let o of n){if(!o.sid)continue;let i=Ks(e,o.sid);i&&r.push(i)}return r}function el(e){let t=_b[e.linkType]??.5,s=It(e.confidence),n=t*s,r=qc(e.daysApart),o=e.embeddingCosine??.5,i=It(e.pagerank);if(e.scoring==="pagerank")return It(i);if(e.scoring==="embedding-rerank")return e.embeddingCosine===null?It(n):It(o);let a=.35*n+.2*r+.2*o+.25*i;return It(a)}function It(e){return!Number.isFinite(e)||e<0?0:e>1?1:e}function wb(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 f of m){if(d.has(f))continue;let g=Pr(f).filter(h=>h.approved);for(let h of g)i(h.source_session_id,h.target_session_id),i(h.target_session_id,h.source_session_id);d.add(f),u.add(f)}}if(u.size===0)break;for(let p of u)a.add(p)}}return{edges:o}}function yb(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 f=(i.get(p)??0)/m.size;for(let g of m)u.set(g,(u.get(g)??0)+n*f)}i=u}let a=0;for(let 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 sl(e,t){let s=e.replace(/\s+/g," ").trim();return s.length<=t?s:`${s.slice(0,t-1).trimEnd()}\u2026`}function Tb(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=sl(e.summary,tl);return`${r}
774
+ ${o}`}return r}function Rb(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+=qs(a),e.summary){let d=sl(e.summary,tl*4);n.push(d),o+=qs(d)}n.push("");for(let d of t){if(d.refs.length===0)continue;let l=`## ${d.heading}`,u=qs(l),p=[],m=0;for(let f of d.refs){let g=Tb(f),h=qs(g);if(o+u+m+h>s){r.push({session_id:f.session_id,title:f.title,decimal:f.decimal,summary:f.summary,project:f.project,started_at:f.started_at});continue}p.push(g),m+=h}if(p.length>0){n.push(l);for(let f of p)n.push(f);n.push(""),o+=u+m}}for(;n.length>0&&n[n.length-1]==="";)n.pop();return{bundle:n.join(`
775
775
  `)+`
776
- `,budgetUsed:o,truncated:r}}function hb(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 c=Ks(e,d);if(!c)continue;let u=Yc(t.started_at,c.started_at),p=Kc({confidence:a.confidence,linkType:a.link_type,daysApart:u,embeddingCosine:null,pagerank:o.get(d)??0,scoring:r});i.push({...c,score:p,evidence:`(suggestion, ${a.inferred_by}) confidence=${a.confidence.toFixed(2)} ${Math.round(u)}d apart`,link_type:a.link_type})}return i}function Vs(e,t={}){let s=Math.max(100,Math.floor(t.budget??rb)),n=t.scoring??"hybrid",r=Math.max(1,Math.min(5,t.maxDepth??ob)),o=t.includeWikiLinks??!0,i=t.includeSuggestions??!1,a=t.edgeTypes?new Set(t.edgeTypes):null,d=Gc(e);if(!d)throw new Error(`session not found: ${e}`);let c=db(d.project_id),u={session_id:d.id,title:qc(d),decimal:c.table?.byId.get(d.id)??null,summary:zc(d.id),project:d.project,started_at:d.started_at};c.cache.set(d.id,u);let p=ub(c,e),m=pb(c,e),f=$r(e).filter(O=>O.approved).filter(O=>!a||a.has(O.link_type)).filter(O=>o||O.link_type!=="wiki_link"),g=mb(e,f,p,m,r),h=gb(g),E=[],b=[],S=[],C=[];for(let O of f){let ee=O.source_session_id===e?O.target_session_id:O.source_session_id,B=Ks(c,ee);if(!B)continue;let T=Yc(u.started_at,B.started_at),U=Kc({confidence:O.confidence,linkType:O.link_type,daysApart:T,embeddingCosine:null,pagerank:h.get(ee)??0,scoring:n}),M=Jc(T),K=`${O.link_type} confidence=${O.confidence.toFixed(2)} recency=${M.toFixed(2)} (${Math.round(T)}d apart)`,Je={...B,score:U,evidence:K,link_type:O.link_type};O.link_type==="citation"?E.push(Je):O.link_type==="similar"?b.push(Je):O.link_type==="wiki_link"?C.push(Je):S.push(Je)}if(i){let O=Xs({sourceSessionId:e,status:"pending",limit:100}),ee=Xs({targetSessionId:e,status:"pending",limit:100}),B=[...O,...ee],T=new Set,U=B.filter(K=>T.has(K.id)?!1:(T.add(K.id),!0)),M=hb(c,u,U,a,n,h);for(let K of M)K.link_type==="citation"?E.push(K):K.link_type==="similar"?b.push(K):K.link_type==="wiki_link"?C.push(K):S.push(K)}let w=(O,ee)=>ee.score-O.score;E.sort(w),b.sort(w),S.sort(w),C.sort(w);let z=_b(u,[{heading:"Parents",refs:p},{heading:"Children",refs:m},{heading:"Citations (approved)",refs:E},{heading:"Similar sessions",refs:b},{heading:"Cousins (skill track + temporal)",refs:S},{heading:"Wiki links (manual)",refs:C}],s);return{origin:u,parents:p,children:m,citations:E,similar:b,cousins:S,wikiLinks:C,bundle:z.bundle,budgetUsed:z.budgetUsed,budgetRemaining:Math.max(0,s-z.budgetUsed),truncated:z.truncated}}var rb,ob,ib,ab,cb,Vc,Xr=L(()=>{"use strict";y();ss();rb=4e3,ob=2,ib=30,ab=.2,cb={citation:1,wiki_link:.9,similar:.7,skill_track:.5,bug_pattern:.4,temporal_proximity:.3};Vc=240});var od={};_e(od,{computeAllHealthScores:()=>go,computeHealthScore:()=>po,computeHealthScoreByName:()=>mo});function rs(e){return Math.max(0,Math.min(1,e))}function po(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 xb(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=Ks(e,d);if(!l)continue;let u=Kc(t.started_at,l.started_at),p=el({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 Vs(e,t={}){let s=Math.max(100,Math.floor(t.budget??pb)),n=t.scoring??"hybrid",r=Math.max(1,Math.min(5,t.maxDepth??mb)),o=t.includeWikiLinks??!0,i=t.includeSuggestions??!1,a=t.edgeTypes?new Set(t.edgeTypes):null,d=Vc(e);if(!d)throw new Error(`session not found: ${e}`);let l=Eb(d.project_id),u={session_id:d.id,title:Qc(d),decimal:l.table?.byId.get(d.id)??null,summary:Zc(d.id),project:d.project,started_at:d.started_at};l.cache.set(d.id,u);let p=bb(l,e),m=Sb(l,e),f=Pr(e).filter(O=>O.approved).filter(O=>!a||a.has(O.link_type)).filter(O=>o||O.link_type!=="wiki_link"),g=wb(e,f,p,m,r),h=yb(g),E=[],b=[],S=[],T=[];for(let O of f){let $=O.source_session_id===e?O.target_session_id:O.source_session_id,F=Ks(l,$);if(!F)continue;let w=Kc(u.started_at,F.started_at),U=el({confidence:O.confidence,linkType:O.link_type,daysApart:w,embeddingCosine:null,pagerank:h.get($)??0,scoring:n}),M=qc(w),V=`${O.link_type} confidence=${O.confidence.toFixed(2)} recency=${M.toFixed(2)} (${Math.round(w)}d apart)`,Je={...F,score:U,evidence:V,link_type:O.link_type};O.link_type==="citation"?E.push(Je):O.link_type==="similar"?b.push(Je):O.link_type==="wiki_link"?T.push(Je):S.push(Je)}if(i){let O=Xs({sourceSessionId:e,status:"pending",limit:100}),$=Xs({targetSessionId:e,status:"pending",limit:100}),F=[...O,...$],w=new Set,U=F.filter(V=>w.has(V.id)?!1:(w.add(V.id),!0)),M=xb(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 x=(O,$)=>$.score-O.score;E.sort(x),b.sort(x),S.sort(x),T.sort(x);let K=Rb(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:K.bundle,budgetUsed:K.budgetUsed,budgetRemaining:Math.max(0,s-K.budgetUsed),truncated:K.truncated}}var pb,mb,gb,fb,_b,tl,Jr=L(()=>{"use strict";y();ss();pb=4e3,mb=2,gb=30,fb=.2,_b={citation:1,wiki_link:.9,similar:.7,skill_track:.5,bug_pattern:.4,temporal_proximity:.3};tl=240});var cd={};_e(cd,{computeAllHealthScores:()=>fo,computeHealthScore:()=>mo,computeHealthScoreByName:()=>go});function rs(e){return Math.max(0,Math.min(1,e))}function mo(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
- 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=rs(r/10),i=n.latest?(Date.now()-new Date(n.latest).getTime())/(1e3*60*60*24):90,a=rs(1-i/90),c=t.prepare(`SELECT AVG(message_count) AS avg_msgs
779
- FROM sessions WHERE project_id = ?`).get(e).avg_msgs??0,u=rs((c-2)/3),p=t.prepare(`SELECT COUNT(*) AS total,
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=rs(r/10),i=n.latest?(Date.now()-new Date(n.latest).getTime())/(1e3*60*60*24):90,a=rs(1-i/90),l=t.prepare(`SELECT AVG(message_count) AS avg_msgs
779
+ FROM sessions WHERE project_id = ?`).get(e).avg_msgs??0,u=rs((l-2)/3),p=t.prepare(`SELECT COUNT(*) AS total,
780
780
  SUM(CASE WHEN m.content_text IS NOT NULL AND m.content_text != '' THEN 1 ELSE 0 END) AS covered
781
781
  FROM messages m
782
782
  JOIN sessions s ON s.id = m.session_id
@@ -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=g.total>0?g.tagged/g.total:0,E=rs(h),b=Math.round((o*.2+a*.25+u*.15+f*.2+E*.2)*100);return{projectId:e,projectName:s.name,score:b,breakdown:{sessionCount:{raw:r,score:o,weight:.2},recency:{daysSinceLastSession:Math.round(i),score:a,weight:.25},fragmentation:{avgMessages:Math.round(c*10)/10,score:u,weight:.15},searchCoverage:{ratio:Math.round(m*100)/100,score:f,weight:.2},tagCoverage:{ratio:Math.round(h*100)/100,score:E,weight:.2}}}}function mo(e){let s=_().prepare("SELECT id FROM projects WHERE name = ?").get(e);return s?po(s.id):null}function go(){let t=_().prepare("SELECT id FROM projects ORDER BY name").all(),s=[];for(let n of t){let r=po(n.id);r&&s.push(r)}return s}var fo=L(()=>{"use strict";y()});function _u(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:Rt,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 ot(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:[_u(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 it(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:[_u(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 Zy(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 Qy(e){return e.toLocaleString("en-US")}function at(e){return e<1e3?String(e):`${Zy(e)} (${Qy(e)})`}function ct(e){return new Date(e).toLocaleDateString("en-US",{month:"long",day:"numeric",year:"numeric"})}var Rt,is=L(()=>{"use strict";Rt="#f97316"});var Eu={};_e(Eu,{render:()=>sT});function gn(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:as,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:fn,textTransform:"uppercase",letterSpacing:"0.16em"},children:t}}]}}}function sT(e){let s=[ct(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?`+ ${at(e.cachedTokens)} cached`:null,i=[ot(hu,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:as,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"20px",color:fn},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:Rt,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:r}},{type:"span",props:{style:{marginTop:"16px",fontSize:"16px",color:fn,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:600},children:"session cost"}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:tT}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[gn(String(e.messageCount),"msgs"),gn(String(e.filesReferenced),"files"),gn(String(e.toolCallCount),"tools"),gn(e.model??"\u2014","model")]}}];return o&&i.push({type:"div",props:{style:{fontSize:"14px",color:fn,fontFamily:"JetBrains Mono",opacity:.7},children:o}}),e.verdict&&i.push({type:"div",props:{style:{display:"flex",fontSize:"24px",fontStyle:"italic",color:as,borderLeft:`3px solid ${Rt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),i.push({type:"div",props:{style:{display:"flex",flex:1}}}),i.push(it(hu)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:eT,padding:"64px 72px",fontFamily:"Inter",gap:"28px"},children:i}}}var eT,as,fn,tT,hu,bu=L(()=>{"use strict";is();eT="#1a1b1e",as="#e7e9ee",fn="#8b9098",tT="#2a2c33",hu={markStroke:as,wordmarkFg:as}});var wu={};_e(wu,{render:()=>oT});function _n(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:cs,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:hn,fontFamily:"JetBrains Mono",textTransform:"lowercase"},children:`// ${t}`}}]}}}function oT(e){let t=[ct(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),s=e.costDollars??"$\u2014",n=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`# ${at(e.cachedTokens)} tokens cache-replayed (free)`:null,r=[ot(Su,"recall.cli/share"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"6px"},children:[{type:"div",props:{style:{fontSize:"18px",color:Co,fontFamily:"JetBrains Mono"},children:"$ recall share --session"}},{type:"div",props:{style:{fontSize:"40px",fontWeight:700,color:cs,lineHeight:1.15,wordBreak:"break-word",fontFamily:"JetBrains Mono"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"18px",color:hn,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:hn,fontFamily:"JetBrains Mono"},children:"> total_cost:"}},{type:"span",props:{style:{fontSize:"180px",fontWeight:700,color:Co,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:s}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:rT}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[_n(String(e.messageCount),"msgs"),_n(String(e.filesReferenced),"files"),_n(String(e.toolCallCount),"tools"),_n(e.model??"\u2014","model")]}}];return n&&r.push({type:"div",props:{style:{fontSize:"14px",color:hn,fontFamily:"JetBrains Mono",opacity:.7},children:n}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"22px",color:cs,fontFamily:"JetBrains Mono",borderLeft:`3px solid ${Co}`,paddingLeft:"20px",marginTop:"8px"},children:`// ${e.verdict}`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(it(Su)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:nT,padding:"64px 72px",fontFamily:"Inter",gap:"28px"},children:r}}}var nT,cs,hn,rT,Co,Su,yu=L(()=>{"use strict";is();nT="#0d0d0f",cs="#e1e7ee",hn="#6b7480",rT="#1f2229",Co="#7ee787",Su={markStroke:cs,wordmarkFg:cs}});var Ru={};_e(Ru,{render:()=>aT});function En(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:xt,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:bn,textTransform:"uppercase",letterSpacing:"0.16em",fontWeight:600},children:t}}]}}}function aT(e){let t=[ct(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),s=e.costDollars??"$\u2014",n=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${at(e.cachedTokens)} cached`:null,r=[ot(Tu,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:xt,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"20px",color:bn},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:xt,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:s}},{type:"span",props:{style:{marginTop:"16px",fontSize:"16px",color:bn,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:600},children:"session cost"}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:iT}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[En(String(e.messageCount),"msgs"),En(String(e.filesReferenced),"files"),En(String(e.toolCallCount),"tools"),En(e.model??"\u2014","model")]}}];return n&&r.push({type:"div",props:{style:{fontSize:"14px",color:bn,fontFamily:"JetBrains Mono",opacity:.85},children:n}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"24px",fontStyle:"italic",color:xt,borderLeft:`3px solid ${xt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(it(Tu)),{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 xt,bn,iT,Tu,xu=L(()=>{"use strict";is();xt="#ffffff",bn="rgba(255,255,255,0.7)",iT="rgba(255,255,255,0.18)",Tu={markStroke:xt,wordmarkFg:xt}});var Cu={};_e(Cu,{render:()=>pT});function Sn(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:800,color:Pt,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:ls,textTransform:"uppercase",letterSpacing:"0.16em",fontWeight:600},children:t}}]}}}function uT(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:dT,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:ls,fontWeight:600,textTransform:"uppercase",letterSpacing:"0.14em"},children:e.map(s=>({type:"span",props:{style:{display:"flex"},children:`${s.label} \xB7 ${s.value}`}}))}}]}}}function pT(e){let t=[ct(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),s=e.costDollars??"$\u2014",n=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${at(e.cachedTokens)} cached`:null,r=[ot(ku,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"40px",fontWeight:700,color:Pt,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"18px",color:ls},children:t}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"flex-start",padding:"8px 0"},children:[{type:"span",props:{style:{fontSize:"14px",color:ls,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:700},children:"session cost"}},{type:"span",props:{style:{fontSize:"180px",fontWeight:800,color:Pt,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:s}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:lT}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[Sn(String(e.messageCount),"msgs"),Sn(String(e.filesReferenced),"files"),Sn(String(e.toolCallCount),"tools"),Sn(e.model??"\u2014","model")]}},uT([{value:e.messageCount,color:Rt,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:ls,fontFamily:"JetBrains Mono",opacity:.85},children:n}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"22px",fontStyle:"italic",color:Pt,borderLeft:`3px solid ${Rt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(it(ku)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:cT,padding:"64px 72px",fontFamily:"Inter",gap:"24px"},children:r}}}var cT,Pt,ls,lT,dT,ku,Lu=L(()=>{"use strict";is();cT="#f6f7f9",Pt="#0a0a0a",ls="#5a6068",lT="#e3e6eb",dT="#dde1e7",ku={markStroke:Pt,wordmarkFg:Pt}});var Nu={};_e(Nu,{render:()=>fT});function Lo(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:wn},children:t}},{type:"div",props:{style:{fontSize:"16px",color:Ft,textTransform:"uppercase",letterSpacing:"2px"},children:e}}]}}}function No(e,t){return{type:"div",props:{style:{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"16px 24px",backgroundColor:Oo,borderRadius:"12px"},children:[{type:"span",props:{style:{fontSize:"18px",color:Ft},children:e}},{type:"span",props:{style:{fontSize:"20px",fontWeight:700,color:wn},children:t}}]}}}function fT(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:Ft,textTransform:"uppercase",letterSpacing:"6px"},children:"YOUR MONTH IN CODE"}},{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:wn},children:e.month}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"12px",backgroundColor:Oo,borderRadius:"16px",padding:"28px",border:`1px solid ${jt}40`},children:[{type:"div",props:{style:{fontSize:"16px",color:gT,textTransform:"uppercase",letterSpacing:"2px"},children:"You are a"}},{type:"div",props:{style:{fontSize:"36px",fontWeight:700,color:jt},children:e.archetype}}]}},{type:"div",props:{style:{display:"flex",gap:"16px",width:"100%"},children:[Lo("Recalls",String(e.totalRecalls)),Lo("Tokens piped",e.totalTokensPiped>999999?`${(e.totalTokensPiped/1e6).toFixed(1)}M`:e.totalTokensPiped.toLocaleString()),Lo("Sessions",String(e.sessionsIndexed))]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px",width:"100%"},children:[{type:"div",props:{style:{fontSize:"14px",color:Ft,textTransform:"uppercase",letterSpacing:"2px",marginBottom:"4px"},children:"Highlights"}},No("Most recalled",e.mostRecalledSession),No("Biggest recall",`${e.biggestRecallTokens.toLocaleString()} tokens`),No("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 ${jt}`,display:"flex",alignItems:"center",justifyContent:"center"},children:{type:"span",props:{style:{fontSize:"32px",fontWeight:700,color:jt},children:`${t}`}}}},{type:"div",props:{style:{fontSize:"14px",color:Ft,textTransform:"uppercase",letterSpacing:"2px"},children:"Memory health"}}]}}];return e.verdict&&s.push({type:"div",props:{style:{backgroundColor:Oo,borderLeft:`3px solid ${jt}`,borderRadius:"8px",padding:"20px 24px",fontSize:"20px",color:wn,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:jt},children:"Claude Recall"}},{type:"span",props:{style:{fontSize:"18px",color:Ft},children:"clauderecall.com"}}]}}),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:mT,padding:"72px 64px",fontFamily:"Inter",gap:"36px"},children:s}}}var mT,Oo,wn,Ft,jt,gT,Ou=L(()=>{"use strict";mT="#0b0c0f",Oo="#15171c",wn="#e7e9ee",Ft="#8b9098",jt="#f97316",gT="#fb923c"});var Do,Xu,Y,x,Q,De,Ju,Yu,Gu,zu,$o,Po,lt=L(()=>{"use strict";Do=[String.raw` ___ _ _ _ _ ___ ___ ___ ___ ___ _ _ _ `,String.raw` / __| | /_\ | | | | \| __| | _ \ __/ __| /_\ | | | | `,String.raw`| (__| |__ / _ \| |_| | |) | _| | / _| (__ / _ \| |__| |__ `,String.raw` \___|____/_/ \_\\___/|___/|___| |_|_\___\___/_/ \_\____|____|`],Xu=Do[0]?.length??64,Y="#f97316",x="#8b9098",Q="#10b981",De="#f59e0b",Ju="#60a5fa",Yu="#34d399",Gu="#c084fc",zu="CLAUDE RECALL",$o=100,Po=30});import{useEffect as YT,useState as GT}from"react";import{Box as qu,Text as me}from"ink";import{createRequire as zT}from"node:module";import{existsSync as qT}from"node:fs";import{jsx as oe,jsxs as Vu}from"react/jsx-runtime";function Ku({cols:e}){let[t,s]=GT(ZT);YT(()=>{let r=!1,o=Z(),i=0,a=0;if(qT(te))try{let c=_().prepare(`SELECT
787
+ WHERE s.project_id = ?`).get(e),h=g.total>0?g.tagged/g.total:0,E=rs(h),b=Math.round((o*.2+a*.25+u*.15+f*.2+E*.2)*100);return{projectId:e,projectName:s.name,score:b,breakdown:{sessionCount:{raw:r,score:o,weight:.2},recency:{daysSinceLastSession:Math.round(i),score:a,weight:.25},fragmentation:{avgMessages:Math.round(l*10)/10,score:u,weight:.15},searchCoverage:{ratio:Math.round(m*100)/100,score:f,weight:.2},tagCoverage:{ratio:Math.round(h*100)/100,score:E,weight:.2}}}}function go(e){let s=_().prepare("SELECT id FROM projects WHERE name = ?").get(e);return s?mo(s.id):null}function fo(){let t=_().prepare("SELECT id FROM projects ORDER BY name").all(),s=[];for(let n of t){let r=mo(n.id);r&&s.push(r)}return s}var _o=L(()=>{"use strict";y()});function bu(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:Rt,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 it(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:[bu(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 at(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:[bu(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 iT(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 aT(e){return e.toLocaleString("en-US")}function ct(e){return e<1e3?String(e):`${iT(e)} (${aT(e)})`}function lt(e){return new Date(e).toLocaleDateString("en-US",{month:"long",day:"numeric",year:"numeric"})}var Rt,is=L(()=>{"use strict";Rt="#f97316"});var wu={};_e(wu,{render:()=>dT});function gn(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:as,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:fn,textTransform:"uppercase",letterSpacing:"0.16em"},children:t}}]}}}function dT(e){let s=[lt(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?`+ ${ct(e.cachedTokens)} cached`:null,i=[it(Su,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:as,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"20px",color:fn},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:Rt,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:r}},{type:"span",props:{style:{marginTop:"16px",fontSize:"16px",color:fn,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:600},children:"session cost"}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:lT}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[gn(String(e.messageCount),"msgs"),gn(String(e.filesReferenced),"files"),gn(String(e.toolCallCount),"tools"),gn(e.model??"\u2014","model")]}}];return o&&i.push({type:"div",props:{style:{fontSize:"14px",color:fn,fontFamily:"JetBrains Mono",opacity:.7},children:o}}),e.verdict&&i.push({type:"div",props:{style:{display:"flex",fontSize:"24px",fontStyle:"italic",color:as,borderLeft:`3px solid ${Rt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),i.push({type:"div",props:{style:{display:"flex",flex:1}}}),i.push(at(Su)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:cT,padding:"64px 72px",fontFamily:"Inter",gap:"28px"},children:i}}}var cT,as,fn,lT,Su,yu=L(()=>{"use strict";is();cT="#1a1b1e",as="#e7e9ee",fn="#8b9098",lT="#2a2c33",Su={markStroke:as,wordmarkFg:as}});var Ru={};_e(Ru,{render:()=>mT});function _n(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:cs,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:hn,fontFamily:"JetBrains Mono",textTransform:"lowercase"},children:`// ${t}`}}]}}}function mT(e){let t=[lt(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),s=e.costDollars??"$\u2014",n=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`# ${ct(e.cachedTokens)} tokens cache-replayed (free)`:null,r=[it(Tu,"recall.cli/share"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"6px"},children:[{type:"div",props:{style:{fontSize:"18px",color:Lo,fontFamily:"JetBrains Mono"},children:"$ recall share --session"}},{type:"div",props:{style:{fontSize:"40px",fontWeight:700,color:cs,lineHeight:1.15,wordBreak:"break-word",fontFamily:"JetBrains Mono"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"18px",color:hn,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:hn,fontFamily:"JetBrains Mono"},children:"> total_cost:"}},{type:"span",props:{style:{fontSize:"180px",fontWeight:700,color:Lo,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:s}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:pT}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[_n(String(e.messageCount),"msgs"),_n(String(e.filesReferenced),"files"),_n(String(e.toolCallCount),"tools"),_n(e.model??"\u2014","model")]}}];return n&&r.push({type:"div",props:{style:{fontSize:"14px",color:hn,fontFamily:"JetBrains Mono",opacity:.7},children:n}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"22px",color:cs,fontFamily:"JetBrains Mono",borderLeft:`3px solid ${Lo}`,paddingLeft:"20px",marginTop:"8px"},children:`// ${e.verdict}`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(at(Tu)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:uT,padding:"64px 72px",fontFamily:"Inter",gap:"28px"},children:r}}}var uT,cs,hn,pT,Lo,Tu,xu=L(()=>{"use strict";is();uT="#0d0d0f",cs="#e1e7ee",hn="#6b7480",pT="#1f2229",Lo="#7ee787",Tu={markStroke:cs,wordmarkFg:cs}});var Cu={};_e(Cu,{render:()=>fT});function En(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:xt,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:bn,textTransform:"uppercase",letterSpacing:"0.16em",fontWeight:600},children:t}}]}}}function fT(e){let t=[lt(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),s=e.costDollars??"$\u2014",n=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${ct(e.cachedTokens)} cached`:null,r=[it(ku,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:xt,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"20px",color:bn},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:xt,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:s}},{type:"span",props:{style:{marginTop:"16px",fontSize:"16px",color:bn,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:600},children:"session cost"}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:gT}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[En(String(e.messageCount),"msgs"),En(String(e.filesReferenced),"files"),En(String(e.toolCallCount),"tools"),En(e.model??"\u2014","model")]}}];return n&&r.push({type:"div",props:{style:{fontSize:"14px",color:bn,fontFamily:"JetBrains Mono",opacity:.85},children:n}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"24px",fontStyle:"italic",color:xt,borderLeft:`3px solid ${xt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(at(ku)),{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 xt,bn,gT,ku,Lu=L(()=>{"use strict";is();xt="#ffffff",bn="rgba(255,255,255,0.7)",gT="rgba(255,255,255,0.18)",ku={markStroke:xt,wordmarkFg:xt}});var Ou={};_e(Ou,{render:()=>ST});function Sn(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:800,color:Pt,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:ls,textTransform:"uppercase",letterSpacing:"0.16em",fontWeight:600},children:t}}]}}}function bT(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:ET,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:ls,fontWeight:600,textTransform:"uppercase",letterSpacing:"0.14em"},children:e.map(s=>({type:"span",props:{style:{display:"flex"},children:`${s.label} \xB7 ${s.value}`}}))}}]}}}function ST(e){let t=[lt(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),s=e.costDollars??"$\u2014",n=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${ct(e.cachedTokens)} cached`:null,r=[it(Nu,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"40px",fontWeight:700,color:Pt,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"18px",color:ls},children:t}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"flex-start",padding:"8px 0"},children:[{type:"span",props:{style:{fontSize:"14px",color:ls,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:700},children:"session cost"}},{type:"span",props:{style:{fontSize:"180px",fontWeight:800,color:Pt,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:s}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:hT}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[Sn(String(e.messageCount),"msgs"),Sn(String(e.filesReferenced),"files"),Sn(String(e.toolCallCount),"tools"),Sn(e.model??"\u2014","model")]}},bT([{value:e.messageCount,color:Rt,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:ls,fontFamily:"JetBrains Mono",opacity:.85},children:n}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"22px",fontStyle:"italic",color:Pt,borderLeft:`3px solid ${Rt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(at(Nu)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:_T,padding:"64px 72px",fontFamily:"Inter",gap:"24px"},children:r}}}var _T,Pt,ls,hT,ET,Nu,Au=L(()=>{"use strict";is();_T="#f6f7f9",Pt="#0a0a0a",ls="#5a6068",hT="#e3e6eb",ET="#dde1e7",Nu={markStroke:Pt,wordmarkFg:Pt}});var vu={};_e(vu,{render:()=>TT});function No(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:wn},children:t}},{type:"div",props:{style:{fontSize:"16px",color:Ft,textTransform:"uppercase",letterSpacing:"2px"},children:e}}]}}}function Oo(e,t){return{type:"div",props:{style:{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"16px 24px",backgroundColor:Ao,borderRadius:"12px"},children:[{type:"span",props:{style:{fontSize:"18px",color:Ft},children:e}},{type:"span",props:{style:{fontSize:"20px",fontWeight:700,color:wn},children:t}}]}}}function TT(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:Ft,textTransform:"uppercase",letterSpacing:"6px"},children:"YOUR MONTH IN CODE"}},{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:wn},children:e.month}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"12px",backgroundColor:Ao,borderRadius:"16px",padding:"28px",border:`1px solid ${jt}40`},children:[{type:"div",props:{style:{fontSize:"16px",color:yT,textTransform:"uppercase",letterSpacing:"2px"},children:"You are a"}},{type:"div",props:{style:{fontSize:"36px",fontWeight:700,color:jt},children:e.archetype}}]}},{type:"div",props:{style:{display:"flex",gap:"16px",width:"100%"},children:[No("Recalls",String(e.totalRecalls)),No("Tokens piped",e.totalTokensPiped>999999?`${(e.totalTokensPiped/1e6).toFixed(1)}M`:e.totalTokensPiped.toLocaleString()),No("Sessions",String(e.sessionsIndexed))]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px",width:"100%"},children:[{type:"div",props:{style:{fontSize:"14px",color:Ft,textTransform:"uppercase",letterSpacing:"2px",marginBottom:"4px"},children:"Highlights"}},Oo("Most recalled",e.mostRecalledSession),Oo("Biggest recall",`${e.biggestRecallTokens.toLocaleString()} tokens`),Oo("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 ${jt}`,display:"flex",alignItems:"center",justifyContent:"center"},children:{type:"span",props:{style:{fontSize:"32px",fontWeight:700,color:jt},children:`${t}`}}}},{type:"div",props:{style:{fontSize:"14px",color:Ft,textTransform:"uppercase",letterSpacing:"2px"},children:"Memory health"}}]}}];return e.verdict&&s.push({type:"div",props:{style:{backgroundColor:Ao,borderLeft:`3px solid ${jt}`,borderRadius:"8px",padding:"20px 24px",fontSize:"20px",color:wn,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:jt},children:"Claude Recall"}},{type:"span",props:{style:{fontSize:"18px",color:Ft},children:"clauderecall.com"}}]}}),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:wT,padding:"72px 64px",fontFamily:"Inter",gap:"36px"},children:s}}}var wT,Ao,wn,Ft,jt,yT,Iu=L(()=>{"use strict";wT="#0b0c0f",Ao="#15171c",wn="#e7e9ee",Ft="#8b9098",jt="#f97316",yT="#fb923c"});var $o,Yu,Y,k,ee,De,zu,qu,Ku,Vu,Po,jo,dt=L(()=>{"use strict";$o=[String.raw` ___ _ _ _ _ ___ ___ ___ ___ ___ _ _ _ `,String.raw` / __| | /_\ | | | | \| __| | _ \ __/ __| /_\ | | | | `,String.raw`| (__| |__ / _ \| |_| | |) | _| | / _| (__ / _ \| |__| |__ `,String.raw` \___|____/_/ \_\\___/|___/|___| |_|_\___\___/_/ \_\____|____|`],Yu=$o[0]?.length??64,Y="#f97316",k="#8b9098",ee="#10b981",De="#f59e0b",zu="#60a5fa",qu="#34d399",Ku="#c084fc",Vu="CLAUDE RECALL",Po=100,jo=30});import{useEffect as eR,useState as tR}from"react";import{Box as Zu,Text as me}from"ink";import{createRequire as sR}from"node:module";import{existsSync as nR}from"node:fs";import{jsx as oe,jsxs as ep}from"react/jsx-runtime";function Qu({cols:e}){let[t,s]=tR(iR);eR(()=>{let r=!1,o=Q(),i=0,a=0;if(nR(te))try{let l=_().prepare(`SELECT
788
788
  (SELECT COUNT(*) FROM sessions) AS sessions,
789
- (SELECT COUNT(*) FROM projects) AS projects`).get();i=c.sessions,a=c.projects}catch{}return s(d=>({...d,daemon:o,sessions:i,projects:a})),Te().then(d=>{r||s(c=>({...c,tier:d.tier}))}).catch(()=>{}),()=>{r=!0}},[]);let n=e>=Xu+2;return Vu(qu,{flexDirection:"column",children:[n?Do.map((r,o)=>oe(me,{color:Y,bold:!0,children:r},o)):oe(me,{color:Y,bold:!0,children:zu}),oe(QT,{state:t})]})}function QT({state:e}){let t=oe(me,{color:x,children:" \xB7 "});return Vu(qu,{children:[oe(me,{color:x,children:"v"}),oe(me,{color:Y,children:VT}),t,oe(me,{color:x,children:"daemon: "}),e.daemon?oe(me,{color:Q,children:`running 127.0.0.1:${e.daemon.port}`}):oe(me,{color:De,children:"stopped"}),t,oe(me,{color:x,children:"sessions: "}),oe(me,{color:Y,children:e.sessions}),e.projects>0?oe(me,{color:x,children:` across ${e.projects} ${e.projects===1?"project":"projects"}`}):null,t,oe(me,{color:x,children:"license: "}),e.tier==="pro"?oe(me,{color:Q,children:"Pro"}):oe(me,{color:x,children:"Free"})]})}var KT,VT,ZT,Zu=L(()=>{"use strict";Ge();D();y();he();lt();KT=zT(import.meta.url),VT=KT("../../../package.json").version,ZT={daemon:null,sessions:0,projects:0,tier:"free"}});import{Box as Ve,Text as ie}from"ink";import{jsx as G,jsxs as Rn}from"react/jsx-runtime";function tR(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 dt(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 Qu({sessions:e,total:t,selected:s,width:n,height:r,loading:o,dbExists:i,filter:a,sortMode:d,groupByProject:c}){let u=Math.max(20,n-2),f=Math.max(1,r-1-1-2),g=tR(s,e.length,f),h=e.slice(g.start,g.end);if(!i)return Rn(Ve,{flexDirection:"column",width:n,height:r,borderStyle:"round",borderColor:x,children:[G(ie,{color:Y,bold:!0,children:" Sessions "}),G(Ve,{paddingX:1,paddingY:1,children:G(ie,{color:x,wrap:"wrap",children:"No sessions indexed yet. Quit (q) and run `recall index` first."})})]});let S=[eR[d],c?"grouped":""].filter(Boolean).join(" \xB7 "),C=o?" Sessions \xB7 loading\u2026 ":a?` Sessions \xB7 ${e.length} of ${t} match "${dt(a,18)}" \xB7 ${S} `:` Sessions \xB7 ${e.length} of ${t} \xB7 ${S} `,w=null;return c&&g.start>0&&(w=e[g.start-1]?.project_name??null),Rn(Ve,{flexDirection:"column",width:n,height:r,borderStyle:"round",borderColor:x,children:[G(Ve,{width:u+2,paddingLeft:1,children:G(ie,{color:Y,bold:!0,children:dt(C,u)})}),G(Ve,{flexDirection:"column",flexGrow:1,paddingX:1,children:h.length===0?G(ie,{color:x,children:a?"no matches.":"no sessions."}):h.flatMap((N,z)=>{let O=g.start+z,ee=O===s,B=[];return c&&N.project_name!==w&&(B.push(G(nR,{project:N.project_name,width:u},`hdr-${N.project_name}-${O}`)),w=N.project_name),B.push(G(sR,{session:N,width:u,isSelected:ee,indented:c},N.id)),B})}),G(Ve,{width:u+2,paddingLeft:1,children:G(ie,{color:x,children:e.length>0?dt(` ${s+1} / ${e.length}${g.end<e.length?" \xB7 scroll for more":""} `,u):""})})]})}function sR({session:e,width:t,isSelected:s,indented:n}){let r=W(e.started_at)||"",o=n?" ":"",i=s?"\u258C ":" ";if(n){let f=e.alias||e.auto_title||e.first_user_message||"(no title)",g=Math.min(14,Math.max(6,Math.floor(t*.25))),h=Math.max(10,t-i.length-o.length-g-1),E=dt(f,h),b=dt(r,g),S=Math.max(1,t-i.length-o.length-E.length-b.length);return Rn(Ve,{children:[G(ie,{children:o}),G(ie,{color:s?Y:x,bold:s,children:i}),G(ie,{color:s?Y:"#fefce8",bold:s,children:E}),G(ie,{children:" ".repeat(S)}),G(ie,{color:x,children:b})]})}let a=e.project_name||"?",d=Math.min(28,Math.floor(t*.7)),c=Math.min(14,t-d-i.length-1),u=dt(a,d),p=dt(r,c),m=Math.max(1,t-i.length-u.length-p.length);return Rn(Ve,{children:[G(ie,{color:s?Y:x,bold:s,children:i}),G(ie,{color:s?Y:"#67e8f9",bold:s,children:u}),G(ie,{children:" ".repeat(m)}),G(ie,{color:x,children:p})]})}function nR({project:e,width:t}){return G(Ve,{children:G(ie,{color:"#67e8f9",bold:!0,children:dt(`\u25BE ${e}`,t)})})}var eR,ep=L(()=>{"use strict";v();lt();eR={recent:"recent",longest:"longest",busiest:"busiest project"}});import{useEffect as rR,useState as jo}from"react";function tp(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>=Yu+2;return ep(Zu,{flexDirection:"column",children:[n?$o.map((r,o)=>oe(me,{color:Y,bold:!0,children:r},o)):oe(me,{color:Y,bold:!0,children:Vu}),oe(aR,{state:t})]})}function aR({state:e}){let t=oe(me,{color:k,children:" \xB7 "});return ep(Zu,{children:[oe(me,{color:k,children:"v"}),oe(me,{color:Y,children:oR}),t,oe(me,{color:k,children:"daemon: "}),e.daemon?oe(me,{color:ee,children:`running 127.0.0.1:${e.daemon.port}`}):oe(me,{color:De,children:"stopped"}),t,oe(me,{color:k,children:"sessions: "}),oe(me,{color:Y,children:e.sessions}),e.projects>0?oe(me,{color:k,children:` across ${e.projects} ${e.projects===1?"project":"projects"}`}):null,t,oe(me,{color:k,children:"license: "}),e.tier==="pro"?oe(me,{color:ee,children:"Pro"}):oe(me,{color:k,children:"Free"})]})}var rR,oR,iR,tp=L(()=>{"use strict";ze();D();y();he();dt();rR=sR(import.meta.url),oR=rR("../../../package.json").version,iR={daemon:null,sessions:0,projects:0,tier:"free"}});import{Box as Ze,Text as ie}from"ink";import{jsx as z,jsxs as Rn}from"react/jsx-runtime";function lR(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 ut(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 sp({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),f=Math.max(1,r-1-1-2),g=lR(s,e.length,f),h=e.slice(g.start,g.end);if(!i)return Rn(Ze,{flexDirection:"column",width:n,height:r,borderStyle:"round",borderColor:k,children:[z(ie,{color:Y,bold:!0,children:" Sessions "}),z(Ze,{paddingX:1,paddingY:1,children:z(ie,{color:k,wrap:"wrap",children:"No sessions indexed yet. Quit (q) and run `recall index` first."})})]});let S=[cR[d],l?"grouped":""].filter(Boolean).join(" \xB7 "),T=o?" Sessions \xB7 loading\u2026 ":a?` Sessions \xB7 ${e.length} of ${t} match "${ut(a,18)}" \xB7 ${S} `:` Sessions \xB7 ${e.length} of ${t} \xB7 ${S} `,x=null;return l&&g.start>0&&(x=e[g.start-1]?.project_name??null),Rn(Ze,{flexDirection:"column",width:n,height:r,borderStyle:"round",borderColor:k,children:[z(Ze,{width:u+2,paddingLeft:1,children:z(ie,{color:Y,bold:!0,children:ut(T,u)})}),z(Ze,{flexDirection:"column",flexGrow:1,paddingX:1,children:h.length===0?z(ie,{color:k,children:a?"no matches.":"no sessions."}):h.flatMap((N,K)=>{let O=g.start+K,$=O===s,F=[];return l&&N.project_name!==x&&(F.push(z(uR,{project:N.project_name,width:u},`hdr-${N.project_name}-${O}`)),x=N.project_name),F.push(z(dR,{session:N,width:u,isSelected:$,indented:l},N.id)),F})}),z(Ze,{width:u+2,paddingLeft:1,children:z(ie,{color:k,children:e.length>0?ut(` ${s+1} / ${e.length}${g.end<e.length?" \xB7 scroll for more":""} `,u):""})})]})}function dR({session:e,width:t,isSelected:s,indented:n}){let r=X(e.started_at)||"",o=n?" ":"",i=s?"\u258C ":" ";if(n){let f=e.alias||e.auto_title||e.first_user_message||"(no title)",g=Math.min(14,Math.max(6,Math.floor(t*.25))),h=Math.max(10,t-i.length-o.length-g-1),E=ut(f,h),b=ut(r,g),S=Math.max(1,t-i.length-o.length-E.length-b.length);return Rn(Ze,{children:[z(ie,{children:o}),z(ie,{color:s?Y:k,bold:s,children:i}),z(ie,{color:s?Y:"#fefce8",bold:s,children:E}),z(ie,{children:" ".repeat(S)}),z(ie,{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=ut(a,d),p=ut(r,l),m=Math.max(1,t-i.length-u.length-p.length);return Rn(Ze,{children:[z(ie,{color:s?Y:k,bold:s,children:i}),z(ie,{color:s?Y:"#67e8f9",bold:s,children:u}),z(ie,{children:" ".repeat(m)}),z(ie,{color:k,children:p})]})}function uR({project:e,width:t}){return z(Ze,{children:z(ie,{color:"#67e8f9",bold:!0,children:ut(`\u25BE ${e}`,t)})})}var cR,np=L(()=>{"use strict";v();dt();cR={recent:"recent",longest:"longest",busiest:"busiest project"}});import{useEffect as pR,useState as Fo}from"react";function rp(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:oR})}function sp(e){let[t,s]=jo([]),[n,r]=jo(!1),[o,i]=jo(!1);return rR(()=>{if(!e){s([]),i(!1);return}r(!0);try{let a=_(),d=tp(a,e,!1),c=!1;d.length===0&&(d=tp(a,e,!0),c=d.length>0),s([...d].reverse()),i(c)}catch{s([]),i(!1)}finally{r(!1)}},[e]),{messages:t,loading:n,fallbackToSidechain:o}}var oR,np=L(()=>{"use strict";y();oR=6});import{Box as $e,Text as We}from"ink";import{Fragment as lR,jsx as V,jsxs as Bt}from"react/jsx-runtime";function iR(e){let t=(e.role??"").toLowerCase();return t==="user"?{label:"user",color:Ju}:t==="assistant"?{label:"asst",color:Yu}:t==="tool"?{label:"tool",color:Gu}:t==="system"?{label:"sys ",color:x}:e.type==="summary"?{label:"sum ",color:x}:{label:"----",color:x}}function aR(e,t){return e?e.replace(/\s+/g," ").trim().slice(0,t+1).replace(/.{1}$/,s=>e.length>t?"\u2026":s):"(empty)"}function rp({session:e,width:t,height:s}){let n=e?.id??null,{messages:r,loading:o,fallbackToSidechain:i}=sp(n),a=Math.max(20,t-2),c=Math.max(4,s-2-2),u=Math.max(2,Math.floor(c/Math.max(1,r.length)));return e?Bt($e,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:x,children:[Bt($e,{paddingX:1,flexDirection:"column",children:[V($e,{width:a,children:V(We,{color:Y,bold:!0,wrap:"truncate-end",children:e.alias||e.auto_title||e.first_user_message||"(no title)"})}),V($e,{width:a,children:V(We,{color:x,wrap:"truncate-end",children:`${e.id.slice(0,8)} \xB7 ${e.message_count} msgs \xB7 ${W(e.started_at)}`})})]}),V($e,{flexDirection:"column",paddingX:1,flexGrow:1,children:o?V(We,{color:x,children:"loading messages\u2026"}):r.length===0?V(We,{color:x,children:"no messages indexed for this session."}):Bt(lR,{children:[i?V(We,{color:x,children:"(showing sidechain / subagent messages)"}):null,r.map(p=>V(cR,{message:p,width:a,perMessageLines:u},p.uuid))]})})]}):Bt($e,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:x,children:[V($e,{paddingX:1,children:V(We,{color:Y,bold:!0,children:"Preview"})}),V($e,{paddingX:1,paddingY:1,children:V(We,{color:x,children:"Select a session on the left to preview."})})]})}function cR({message:e,width:t,perMessageLines:s}){let n=iR(e),r=Math.max(1,s-1),o=Math.max(20,t-2),i=r*o,a=aR(e.content_text,i);return Bt($e,{flexDirection:"column",marginBottom:0,children:[Bt($e,{children:[V(We,{color:n.color,bold:!0,children:n.label}),V(We,{color:x,children:` ${e.timestamp?W(e.timestamp):""}`})]}),V($e,{width:t,children:V(We,{wrap:"truncate-end",children:a})})]})}var op=L(()=>{"use strict";v();np();lt()});import{useMemo as dR}from"react";import{Box as Pe,Text as ut}from"ink";import{jsx as ge,jsxs as ds}from"react/jsx-runtime";function uR(e,t){try{return{ok:!0,result:Vs(e,{budget:t})}}catch(s){return{ok:!1,error:s instanceof Error?s.message:String(s)}}}function ip({session:e,width:t,height:s,budget:n}){let r=dR(()=>e?uR(e.id,n):null,[e?.id,n]),o=Math.max(20,t-2),a=Math.max(4,s-2-2);if(!e)return ds(Pe,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:x,children:[ge(Pe,{paddingX:1,children:ge(ut,{color:Y,bold:!0,children:"Neighborhood"})}),ge(Pe,{paddingX:1,paddingY:1,children:ge(ut,{color:x,children:"Select a session and press `n` to assemble its neighborhood."})})]});if(!r)return null;if(!r.ok)return ds(Pe,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:De,children:[ge(Pe,{paddingX:1,children:ge(ut,{color:De,bold:!0,children:"Neighborhood error"})}),ge(Pe,{paddingX:1,paddingY:1,children:ge(ut,{color:De,children:r.error})})]});let{result:d}=r,c=d.bundle.replace(/\n+$/,"").split(`
795
- `),u=c.slice(0,Math.max(1,a-1)),p=c.length-u.length;return ds(Pe,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:Q,children:[ds(Pe,{paddingX:1,flexDirection:"column",children:[ge(Pe,{width:o,children:ge(ut,{color:Q,bold:!0,wrap:"truncate-end",children:"Neighborhood"})}),ge(Pe,{width:o,children:ge(ut,{color:x,wrap:"truncate-end",children:`budget=${n} used=${d.budgetUsed} remaining=${d.budgetRemaining} truncated=${d.truncated.length}`})})]}),ds(Pe,{flexDirection:"column",paddingX:1,flexGrow:1,children:[u.map((m,f)=>ge(ut,{wrap:"truncate-end",children:m||" "},f)),p>0?ge(ut,{color:x,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 ap=L(()=>{"use strict";Xr();lt()});import{useEffect as pR,useState as cp}from"react";import{Box as us,Text as pt}from"ink";import Fo from"ink-text-input";import{jsx as Se,jsxs as Uo}from"react/jsx-runtime";function lp({mode:e,query:t,onQueryChange:s,onSearchSubmit:n,onAliasSubmit:r,onTagSubmit:o,aliasInitial:i,toast:a}){let[d,c]=cp(""),[u,p]=cp("");return pR(()=>{e==="alias"&&c(i),e==="tag"&&p("")},[e,i]),a&&e==="normal"?Se(us,{children:Se(pt,{color:De,children:`\u25B6 ${a}`})}):e==="search"?Uo(us,{children:[Se(pt,{color:Y,bold:!0,children:"/ "}),Se(Fo,{value:t,onChange:s,onSubmit:n,placeholder:"filter sessions by project, alias, or opening message..."}),Se(pt,{color:x,children:" esc clear \xB7 enter confirm"})]}):e==="alias"?Uo(us,{children:[Se(pt,{color:Q,bold:!0,children:"alias \u203A "}),Se(Fo,{value:d,onChange:c,onSubmit:m=>r(m),placeholder:"terminal-tab name for this session"}),Se(pt,{color:x,children:" esc cancel \xB7 enter save"})]}):e==="tag"?Uo(us,{children:[Se(pt,{color:Q,bold:!0,children:"tag \u203A "}),Se(Fo,{value:u,onChange:p,onSubmit:m=>o(m),placeholder:"add a tag to this session"}),Se(pt,{color:x,children:" esc cancel \xB7 enter save"})]}):Se(us,{children:Se(pt,{color:x,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 dp=L(()=>{"use strict";lt()});import{Box as fe,Text as F}from"ink";import{jsx as P,jsxs as we}from"react/jsx-runtime";function up({width:e,height:t}){return we(fe,{flexDirection:"column",width:e,height:t,borderStyle:"round",borderColor:Y,paddingX:2,paddingY:1,children:[we(fe,{children:[P(F,{color:Y,bold:!0,children:"Claude Recall TUI \u2014 Help"}),P(F,{color:x,children:" \xB7 press ? or esc to close"})]}),we(fe,{marginTop:1,flexDirection:"column",children:[P(F,{color:Q,bold:!0,children:"Navigation"}),mR.map(s=>P(Bo,{row:s},s.key))]}),we(fe,{marginTop:1,flexDirection:"column",children:[P(F,{color:Q,bold:!0,children:"Actions on the selected session"}),gR.map(s=>P(Bo,{row:s},s.key))]}),we(fe,{marginTop:1,flexDirection:"column",children:[P(F,{color:Q,bold:!0,children:"Right-pane views"}),fR.map(s=>P(Bo,{row:s},s.key))]}),we(fe,{marginTop:1,flexDirection:"column",children:[P(F,{color:Q,bold:!0,children:"What is Neighborhood?"}),P(F,{color:x,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."})]}),we(fe,{marginTop:1,flexDirection:"column",children:[P(F,{color:Q,bold:!0,children:"Maintenance & diagnostics"}),P(F,{color:x,wrap:"wrap",children:"Two commands cover everything. Quit the TUI with `q` first, then:"}),we(fe,{marginTop:1,children:[P(F,{color:x,children:" \u2022 "}),P(F,{children:"recall doctor"})]}),P(F,{color:x,wrap:"wrap",children:" Health report: DB size, WAL, FTS fragmentation, integrity, disk free."}),P(F,{color:x,wrap:"wrap",children:" Run this first if anything feels slow or wrong. Add --json for machine output."}),we(fe,{marginTop:1,children:[P(F,{color:x,children:" \u2022 "}),P(F,{children:"recall optimize"})]}),P(F,{color:x,wrap:"wrap",children:" Maintenance: WAL truncate + FTS5 merge + planner stats. Safe while daemon is running."}),P(F,{color:x,wrap:"wrap",children:" Add --vacuum (with daemon stopped) to also reclaim disk pages from deleted rows."})]}),we(fe,{marginTop:1,flexDirection:"column",children:[P(F,{color:Q,bold:!0,children:"How to pipe a session into Claude"}),P(F,{color:x,wrap:"wrap",children:"Two recipes. Both work in any shell \u2014 exit this TUI with `q` first, then run them."}),we(fe,{marginTop:1,children:[P(F,{color:x,children:" 1. "}),P(F,{children:"recall context <id> | claude"})]}),P(F,{color:x,wrap:"wrap",children:" Pipes one session's full transcript as markdown into a fresh `claude` chat."}),P(F,{color:x,wrap:"wrap",children:" Use when you want to continue exactly where one session left off."}),we(fe,{marginTop:1,children:[P(F,{color:x,children:" 2. "}),P(F,{children:"recall neighborhood <id> | claude"})]}),P(F,{color:x,wrap:"wrap",children:" Pipes the bundle (parents + children + citations + similar + bug matches)."}),P(F,{color:x,wrap:"wrap",children:" Use when you want broader context, not just one transcript."})]})]})}function Bo({row:e}){return we(fe,{children:[P(fe,{width:16,children:P(F,{color:Y,children:e.key})}),P(F,{color:x,wrap:"truncate-end",children:e.description})]})}var mR,gR,fR,pp=L(()=>{"use strict";lt();mR=[{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"}],gR=[{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)"}],fR=[{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 _R,useMemo as hR,useState as xn}from"react";import{existsSync as ER}from"node:fs";function mp(e){let[t,s]=xn([]),[n,r]=xn(!0),[o,i]=xn(null),[a,d]=xn(!0);return _R(()=>{if(!ER(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:mR})}function op(e){let[t,s]=Fo([]),[n,r]=Fo(!1),[o,i]=Fo(!1);return pR(()=>{if(!e){s([]),i(!1);return}r(!0);try{let a=_(),d=rp(a,e,!1),l=!1;d.length===0&&(d=rp(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 mR,ip=L(()=>{"use strict";y();mR=6});import{Box as $e,Text as We}from"ink";import{Fragment as hR,jsx as Z,jsxs as Bt}from"react/jsx-runtime";function gR(e){let t=(e.role??"").toLowerCase();return t==="user"?{label:"user",color:zu}:t==="assistant"?{label:"asst",color:qu}:t==="tool"?{label:"tool",color:Ku}:t==="system"?{label:"sys ",color:k}:e.type==="summary"?{label:"sum ",color:k}:{label:"----",color:k}}function fR(e,t){return e?e.replace(/\s+/g," ").trim().slice(0,t+1).replace(/.{1}$/,s=>e.length>t?"\u2026":s):"(empty)"}function ap({session:e,width:t,height:s}){let n=e?.id??null,{messages:r,loading:o,fallbackToSidechain:i}=op(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?Bt($e,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:k,children:[Bt($e,{paddingX:1,flexDirection:"column",children:[Z($e,{width:a,children:Z(We,{color:Y,bold:!0,wrap:"truncate-end",children:e.alias||e.auto_title||e.first_user_message||"(no title)"})}),Z($e,{width:a,children:Z(We,{color:k,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(We,{color:k,children:"loading messages\u2026"}):r.length===0?Z(We,{color:k,children:"no messages indexed for this session."}):Bt(hR,{children:[i?Z(We,{color:k,children:"(showing sidechain / subagent messages)"}):null,r.map(p=>Z(_R,{message:p,width:a,perMessageLines:u},p.uuid))]})})]}):Bt($e,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:k,children:[Z($e,{paddingX:1,children:Z(We,{color:Y,bold:!0,children:"Preview"})}),Z($e,{paddingX:1,paddingY:1,children:Z(We,{color:k,children:"Select a session on the left to preview."})})]})}function _R({message:e,width:t,perMessageLines:s}){let n=gR(e),r=Math.max(1,s-1),o=Math.max(20,t-2),i=r*o,a=fR(e.content_text,i);return Bt($e,{flexDirection:"column",marginBottom:0,children:[Bt($e,{children:[Z(We,{color:n.color,bold:!0,children:n.label}),Z(We,{color:k,children:` ${e.timestamp?X(e.timestamp):""}`})]}),Z($e,{width:t,children:Z(We,{wrap:"truncate-end",children:a})})]})}var cp=L(()=>{"use strict";v();ip();dt()});import{useMemo as ER}from"react";import{Box as Pe,Text as pt}from"ink";import{jsx as ge,jsxs as ds}from"react/jsx-runtime";function bR(e,t){try{return{ok:!0,result:Vs(e,{budget:t})}}catch(s){return{ok:!1,error:s instanceof Error?s.message:String(s)}}}function lp({session:e,width:t,height:s,budget:n}){let r=ER(()=>e?bR(e.id,n):null,[e?.id,n]),o=Math.max(20,t-2),a=Math.max(4,s-2-2);if(!e)return ds(Pe,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:k,children:[ge(Pe,{paddingX:1,children:ge(pt,{color:Y,bold:!0,children:"Neighborhood"})}),ge(Pe,{paddingX:1,paddingY:1,children:ge(pt,{color:k,children:"Select a session and press `n` to assemble its neighborhood."})})]});if(!r)return null;if(!r.ok)return ds(Pe,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:De,children:[ge(Pe,{paddingX:1,children:ge(pt,{color:De,bold:!0,children:"Neighborhood error"})}),ge(Pe,{paddingX:1,paddingY:1,children:ge(pt,{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 ds(Pe,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:ee,children:[ds(Pe,{paddingX:1,flexDirection:"column",children:[ge(Pe,{width:o,children:ge(pt,{color:ee,bold:!0,wrap:"truncate-end",children:"Neighborhood"})}),ge(Pe,{width:o,children:ge(pt,{color:k,wrap:"truncate-end",children:`budget=${n} used=${d.budgetUsed} remaining=${d.budgetRemaining} truncated=${d.truncated.length}`})})]}),ds(Pe,{flexDirection:"column",paddingX:1,flexGrow:1,children:[u.map((m,f)=>ge(pt,{wrap:"truncate-end",children:m||" "},f)),p>0?ge(pt,{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 dp=L(()=>{"use strict";Jr();dt()});import{useEffect as SR,useState as up}from"react";import{Box as us,Text as mt}from"ink";import Uo from"ink-text-input";import{jsx as Se,jsxs as Bo}from"react/jsx-runtime";function pp({mode:e,query:t,onQueryChange:s,onSearchSubmit:n,onAliasSubmit:r,onTagSubmit:o,aliasInitial:i,toast:a}){let[d,l]=up(""),[u,p]=up("");return SR(()=>{e==="alias"&&l(i),e==="tag"&&p("")},[e,i]),a&&e==="normal"?Se(us,{children:Se(mt,{color:De,children:`\u25B6 ${a}`})}):e==="search"?Bo(us,{children:[Se(mt,{color:Y,bold:!0,children:"/ "}),Se(Uo,{value:t,onChange:s,onSubmit:n,placeholder:"filter sessions by project, alias, or opening message..."}),Se(mt,{color:k,children:" esc clear \xB7 enter confirm"})]}):e==="alias"?Bo(us,{children:[Se(mt,{color:ee,bold:!0,children:"alias \u203A "}),Se(Uo,{value:d,onChange:l,onSubmit:m=>r(m),placeholder:"terminal-tab name for this session"}),Se(mt,{color:k,children:" esc cancel \xB7 enter save"})]}):e==="tag"?Bo(us,{children:[Se(mt,{color:ee,bold:!0,children:"tag \u203A "}),Se(Uo,{value:u,onChange:p,onSubmit:m=>o(m),placeholder:"add a tag to this session"}),Se(mt,{color:k,children:" esc cancel \xB7 enter save"})]}):Se(us,{children:Se(mt,{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 mp=L(()=>{"use strict";dt()});import{Box as fe,Text as H}from"ink";import{jsx as j,jsxs as we}from"react/jsx-runtime";function gp({width:e,height:t}){return we(fe,{flexDirection:"column",width:e,height:t,borderStyle:"round",borderColor:Y,paddingX:2,paddingY:1,children:[we(fe,{children:[j(H,{color:Y,bold:!0,children:"Claude Recall TUI \u2014 Help"}),j(H,{color:k,children:" \xB7 press ? or esc to close"})]}),we(fe,{marginTop:1,flexDirection:"column",children:[j(H,{color:ee,bold:!0,children:"Navigation"}),wR.map(s=>j(Ho,{row:s},s.key))]}),we(fe,{marginTop:1,flexDirection:"column",children:[j(H,{color:ee,bold:!0,children:"Actions on the selected session"}),yR.map(s=>j(Ho,{row:s},s.key))]}),we(fe,{marginTop:1,flexDirection:"column",children:[j(H,{color:ee,bold:!0,children:"Right-pane views"}),TR.map(s=>j(Ho,{row:s},s.key))]}),we(fe,{marginTop:1,flexDirection:"column",children:[j(H,{color:ee,bold:!0,children:"What is Neighborhood?"}),j(H,{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."})]}),we(fe,{marginTop:1,flexDirection:"column",children:[j(H,{color:ee,bold:!0,children:"Maintenance & diagnostics"}),j(H,{color:k,wrap:"wrap",children:"Two commands cover everything. Quit the TUI with `q` first, then:"}),we(fe,{marginTop:1,children:[j(H,{color:k,children:" \u2022 "}),j(H,{children:"recall doctor"})]}),j(H,{color:k,wrap:"wrap",children:" Health report: DB size, WAL, FTS fragmentation, integrity, disk free."}),j(H,{color:k,wrap:"wrap",children:" Run this first if anything feels slow or wrong. Add --json for machine output."}),we(fe,{marginTop:1,children:[j(H,{color:k,children:" \u2022 "}),j(H,{children:"recall optimize"})]}),j(H,{color:k,wrap:"wrap",children:" Maintenance: WAL truncate + FTS5 merge + planner stats. Safe while daemon is running."}),j(H,{color:k,wrap:"wrap",children:" Add --vacuum (with daemon stopped) to also reclaim disk pages from deleted rows."})]}),we(fe,{marginTop:1,flexDirection:"column",children:[j(H,{color:ee,bold:!0,children:"How to pipe a session into Claude"}),j(H,{color:k,wrap:"wrap",children:"Two recipes. Both work in any shell \u2014 exit this TUI with `q` first, then run them."}),we(fe,{marginTop:1,children:[j(H,{color:k,children:" 1. "}),j(H,{children:"recall context <id> | claude"})]}),j(H,{color:k,wrap:"wrap",children:" Pipes one session's full transcript as markdown into a fresh `claude` chat."}),j(H,{color:k,wrap:"wrap",children:" Use when you want to continue exactly where one session left off."}),we(fe,{marginTop:1,children:[j(H,{color:k,children:" 2. "}),j(H,{children:"recall neighborhood <id> | claude"})]}),j(H,{color:k,wrap:"wrap",children:" Pipes the bundle (parents + children + citations + similar + bug matches)."}),j(H,{color:k,wrap:"wrap",children:" Use when you want broader context, not just one transcript."})]})]})}function Ho({row:e}){return we(fe,{children:[j(fe,{width:16,children:j(H,{color:Y,children:e.key})}),j(H,{color:k,wrap:"truncate-end",children:e.description})]})}var wR,yR,TR,fp=L(()=>{"use strict";dt();wR=[{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"}],yR=[{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)"}],TR=[{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 RR,useMemo as xR,useState as xn}from"react";import{existsSync as kR}from"node:fs";function _p(e){let[t,s]=xn([]),[n,r]=xn(!0),[o,i]=xn(null),[a,d]=xn(!0);return RR(()=>{if(!kR(te)){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,23 @@ ${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:bR});s(p)}catch(u){i(u instanceof Error?u.message:String(u))}finally{r(!1)}},[]),{sessions:hR(()=>{let u=e.trim().toLowerCase();return u?t.filter(p=>{let m=p.project_name?.toLowerCase()??"",f=p.first_user_message?.toLowerCase()??"";return m.includes(u)||f.includes(u)}):t},[t,e]),total:t.length,loading:n,error:o,dbExists:a}}var bR,gp=L(()=>{"use strict";y();D();bR=200});import{useEffect as Ho,useMemo as SR,useState as Xe}from"react";import{Box as mt,Text as kn,useApp as wR,useInput as yR}from"ink";import{spawn as TR}from"node:child_process";import{platform as Cn}from"node:os";import{jsx as ae,jsxs as Xo}from"react/jsx-runtime";function _p(){return{cols:process.stdout.columns??100,rows:process.stdout.rows??30}}function LR(e){let t=Cn()==="darwin"?"open":Cn()==="win32"?"start":"xdg-open",s=Cn()==="win32"?["",e]:[e];TR(t,s,{detached:!0,stdio:"ignore",shell:Cn()==="win32"}).unref()}function hp({onShowSession:e}){let{exit:t}=wR(),s=_p(),[n,r]=Xe(s.cols),[o,i]=Xe(s.rows),[a,d]=Xe(0),[c,u]=Xe(""),[p,m]=Xe("normal"),[f,g]=Xe(null),[h,E]=Xe("preview"),[b,S]=Xe("recent"),[C,w]=Xe(!1),[N,z]=Xe(!1),{sessions:O,total:ee,loading:B,error:T,dbExists:U}=mp(c),M=SR(()=>{if(O.length===0)return O;let j=new Map;if(b==="busiest"||C)for(let A of O)j.set(A.project_name,(j.get(A.project_name)??0)+1);let X=[...O];if(b==="longest"?X.sort((A,J)=>(J.message_count??0)-(A.message_count??0)):b==="busiest"&&X.sort((A,J)=>{let ke=j.get(A.project_name)??0,Ce=j.get(J.project_name)??0;return Ce!==ke?Ce-ke:(J.started_at??"").localeCompare(A.started_at??"")}),C){let A=new Map;for(let Ce of X){let Ye=A.get(Ce.project_name);Ye||(Ye=[],A.set(Ce.project_name,Ye)),Ye.push(Ce)}let J=Array.from(A.keys()).sort((Ce,Ye)=>{if(b==="busiest"){let zo=j.get(Ce)??0,qo=j.get(Ye)??0;if(qo!==zo)return qo-zo}return Ce.localeCompare(Ye)}),ke=[];for(let Ce of J)for(let Ye of A.get(Ce)??[])ke.push(Ye);return ke}return X},[O,b,C]);Ho(()=>{let j=()=>{let X=_p();r(X.cols),i(X.rows)};return process.stdout.on("resize",j),()=>{process.stdout.off("resize",j)}},[]),Ho(()=>{if(M.length===0){a!==0&&d(0);return}a>=M.length&&d(M.length-1)},[M.length,a]),Ho(()=>{if(!f)return;let j=setTimeout(()=>g(null),2500);return()=>clearTimeout(j)},[f]),yR((j,X)=>{if(p==="search"){X.escape&&(m("normal"),u(""));return}if(p==="alias"||p==="tag"){X.escape&&m("normal");return}if(N){(j==="?"||X.escape||j==="q")&&z(!1);return}if(j==="q"||X.ctrl&&j==="c"){t();return}if(j==="?"){z(!0);return}if(!(M.length===0&&j!=="/")){if(X.upArrow||j==="k"){d(A=>Math.max(0,A-1));return}if(X.downArrow||j==="j"){d(A=>Math.min(M.length-1,A+1));return}if(X.pageUp){d(A=>Math.max(0,A-10));return}if(X.pageDown){d(A=>Math.min(M.length-1,A+10));return}if(X.return){let A=M[a];A&&(e(A.id),t());return}if(j==="o"){let A=M[a];if(!A)return;let J=Z();if(!J){g("start the daemon first (`recall start`)");return}let ke=`http://127.0.0.1:${J.port}/sessions/${A.id}`;LR(ke),g(`opened ${ke}`);return}if(j==="n"){E(J=>J==="neighborhood"?"preview":"neighborhood");let A=M[a];A&&g(h==="neighborhood"?"preview view":`neighborhood for ${A.id.slice(0,8)}`);return}if(j==="/"){m("search");return}if(j==="a"){M[a]&&m("alias");return}if(j==="t"){M[a]&&m("tag");return}if(j==="s"){S(A=>{let J=Wo.indexOf(A),ke=Wo[(J+1)%Wo.length];return g(`sort: ${NR[ke]}`),ke});return}if(j==="g"){w(A=>(g(A?"flat view":"grouped by project"),!A));return}}});function K(j){m("normal");let X=M[a];if(!X)return;let A=j.trim();if(!A){g("alias unchanged (empty input)");return}try{Ot(X.id,A),g(`alias set: ${A}`)}catch(J){g(`alias failed: ${J instanceof Error?J.message:"unknown"}`)}}function Je(j){m("normal");let X=M[a];if(!X)return;let A=j.trim();if(!A){g("tag unchanged (empty input)");return}try{let J=Na(X.id,A);g(J.added?`tag added: ${J.tag}`:`tag exists: ${J.tag}`)}catch(J){g(`tag failed: ${J instanceof Error?J.message:"unknown"}`)}}if(n<$o||o<Po)return Xo(mt,{flexDirection:"column",padding:1,children:[ae(kn,{color:De,children:"Terminal too small."}),ae(kn,{color:x,children:`Resize to at least ${$o} cols x ${Po} rows. Current: ${n} x ${o}.`}),ae(kn,{color:x,children:"Press q to quit."})]});let je=Math.max(10,o-CR-fp),gt=Math.max(36,Math.floor(n*.4)),Go=n-gt-1,Nn=M[a]??null;return Xo(mt,{flexDirection:"column",width:n,height:o,children:[ae(Ku,{cols:n}),ae(mt,{height:1}),T?ae(mt,{paddingX:1,children:ae(kn,{color:De,children:`Error loading sessions: ${T}`})}):N?ae(mt,{height:je,children:ae(up,{width:n,height:je})}):Xo(mt,{flexDirection:"row",height:je,children:[ae(Qu,{sessions:M,total:ee,selected:a,width:gt,height:je,loading:B,dbExists:U,filter:c,sortMode:b,groupByProject:C}),ae(mt,{width:1,height:je}),h==="neighborhood"?ae(ip,{session:Nn,width:Go,height:je,budget:4e3}):ae(rp,{session:Nn,width:Go,height:je})]}),ae(mt,{height:fp,width:n,paddingX:1,children:ae(lp,{mode:p,query:c,onQueryChange:u,onSearchSubmit:()=>m("normal"),onAliasSubmit:K,onTagSubmit:Je,aliasInitial:Nn?.alias??"",toast:f})})]})}var RR,xR,kR,fp,CR,Wo,NR,Ep=L(()=>{"use strict";Zu();ep();op();ap();dp();pp();gp();Ge();_t();_r();lt();RR=4,xR=1,kR=1,fp=1,CR=RR+xR+kR,Wo=["recent","longest","busiest"];NR={recent:"most recent first",longest:"longest sessions first",busiest:"busiest project first"}});import{render as OR}from"ink";import{jsx as AR}from"react/jsx-runtime";async function bp(){let e={showSessionId:null};return await OR(AR(hp,{onShowSession:n=>{e.showSessionId=n}})).waitUntilExit(),e}var Sp=L(()=>{"use strict";Ep()});var wp={};_e(wp,{runTui:()=>IR});import{spawn as vR}from"node:child_process";async function IR(){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 bp();if(!e.showSessionId)return;let t=process.argv[1];t&&await new Promise(s=>{let n=vR(process.execPath,[t,"show",e.showSessionId],{stdio:"inherit"});n.on("exit",()=>s()),n.on("error",()=>s())})}var yp=L(()=>{"use strict";Sp()});var Tp={};_e(Tp,{findSimilarSessions:()=>DR,vectorSearch:()=>MR});async function MR(e,t=50){let s=await Rr(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
807
+ LIMIT @limit`).all({limit:CR});s(p)}catch(u){i(u instanceof Error?u.message:String(u))}finally{r(!1)}},[]),{sessions:xR(()=>{let u=e.trim().toLowerCase();return u?t.filter(p=>{let m=p.project_name?.toLowerCase()??"",f=p.first_user_message?.toLowerCase()??"";return m.includes(u)||f.includes(u)}):t},[t,e]),total:t.length,loading:n,error:o,dbExists:a}}var CR,hp=L(()=>{"use strict";y();D();CR=200});import{useEffect as Wo,useMemo as LR,useState as Xe}from"react";import{Box as gt,Text as kn,useApp as NR,useInput as OR}from"ink";import{spawn as AR}from"node:child_process";import{platform as Cn}from"node:os";import{jsx as ae,jsxs as Jo}from"react/jsx-runtime";function bp(){return{cols:process.stdout.columns??100,rows:process.stdout.rows??30}}function $R(e){let t=Cn()==="darwin"?"open":Cn()==="win32"?"start":"xdg-open",s=Cn()==="win32"?["",e]:[e];AR(t,s,{detached:!0,stdio:"ignore",shell:Cn()==="win32"}).unref()}function Sp({onShowSession:e}){let{exit:t}=NR(),s=bp(),[n,r]=Xe(s.cols),[o,i]=Xe(s.rows),[a,d]=Xe(0),[l,u]=Xe(""),[p,m]=Xe("normal"),[f,g]=Xe(null),[h,E]=Xe("preview"),[b,S]=Xe("recent"),[T,x]=Xe(!1),[N,K]=Xe(!1),{sessions:O,total:$,loading:F,error:w,dbExists:U}=_p(l),M=LR(()=>{if(O.length===0)return O;let B=new Map;if(b==="busiest"||T)for(let A of O)B.set(A.project_name,(B.get(A.project_name)??0)+1);let J=[...O];if(b==="longest"?J.sort((A,G)=>(G.message_count??0)-(A.message_count??0)):b==="busiest"&&J.sort((A,G)=>{let ke=B.get(A.project_name)??0,Ce=B.get(G.project_name)??0;return Ce!==ke?Ce-ke:(G.started_at??"").localeCompare(A.started_at??"")}),T){let A=new Map;for(let Ce of J){let Ge=A.get(Ce.project_name);Ge||(Ge=[],A.set(Ce.project_name,Ge)),Ge.push(Ce)}let G=Array.from(A.keys()).sort((Ce,Ge)=>{if(b==="busiest"){let qo=B.get(Ce)??0,Ko=B.get(Ge)??0;if(Ko!==qo)return Ko-qo}return Ce.localeCompare(Ge)}),ke=[];for(let Ce of G)for(let Ge of A.get(Ce)??[])ke.push(Ge);return ke}return J},[O,b,T]);Wo(()=>{let B=()=>{let J=bp();r(J.cols),i(J.rows)};return process.stdout.on("resize",B),()=>{process.stdout.off("resize",B)}},[]),Wo(()=>{if(M.length===0){a!==0&&d(0);return}a>=M.length&&d(M.length-1)},[M.length,a]),Wo(()=>{if(!f)return;let B=setTimeout(()=>g(null),2500);return()=>clearTimeout(B)},[f]),OR((B,J)=>{if(p==="search"){J.escape&&(m("normal"),u(""));return}if(p==="alias"||p==="tag"){J.escape&&m("normal");return}if(N){(B==="?"||J.escape||B==="q")&&K(!1);return}if(B==="q"||J.ctrl&&B==="c"){t();return}if(B==="?"){K(!0);return}if(!(M.length===0&&B!=="/")){if(J.upArrow||B==="k"){d(A=>Math.max(0,A-1));return}if(J.downArrow||B==="j"){d(A=>Math.min(M.length-1,A+1));return}if(J.pageUp){d(A=>Math.max(0,A-10));return}if(J.pageDown){d(A=>Math.min(M.length-1,A+10));return}if(J.return){let A=M[a];A&&(e(A.id),t());return}if(B==="o"){let A=M[a];if(!A)return;let G=Q();if(!G){g("start the daemon first (`recall start`)");return}let ke=`http://127.0.0.1:${G.port}/sessions/${A.id}`;$R(ke),g(`opened ${ke}`);return}if(B==="n"){E(G=>G==="neighborhood"?"preview":"neighborhood");let A=M[a];A&&g(h==="neighborhood"?"preview view":`neighborhood for ${A.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(A=>{let G=Xo.indexOf(A),ke=Xo[(G+1)%Xo.length];return g(`sort: ${PR[ke]}`),ke});return}if(B==="g"){x(A=>(g(A?"flat view":"grouped by project"),!A));return}}});function V(B){m("normal");let J=M[a];if(!J)return;let A=B.trim();if(!A){g("alias unchanged (empty input)");return}try{Ot(J.id,A),g(`alias set: ${A}`)}catch(G){g(`alias failed: ${G instanceof Error?G.message:"unknown"}`)}}function Je(B){m("normal");let J=M[a];if(!J)return;let A=B.trim();if(!A){g("tag unchanged (empty input)");return}try{let G=Aa(J.id,A);g(G.added?`tag added: ${G.tag}`:`tag exists: ${G.tag}`)}catch(G){g(`tag failed: ${G instanceof Error?G.message:"unknown"}`)}}if(n<Po||o<jo)return Jo(gt,{flexDirection:"column",padding:1,children:[ae(kn,{color:De,children:"Terminal too small."}),ae(kn,{color:k,children:`Resize to at least ${Po} cols x ${jo} rows. Current: ${n} x ${o}.`}),ae(kn,{color:k,children:"Press q to quit."})]});let je=Math.max(10,o-DR-Ep),ft=Math.max(36,Math.floor(n*.4)),zo=n-ft-1,Nn=M[a]??null;return Jo(gt,{flexDirection:"column",width:n,height:o,children:[ae(Qu,{cols:n}),ae(gt,{height:1}),w?ae(gt,{paddingX:1,children:ae(kn,{color:De,children:`Error loading sessions: ${w}`})}):N?ae(gt,{height:je,children:ae(gp,{width:n,height:je})}):Jo(gt,{flexDirection:"row",height:je,children:[ae(sp,{sessions:M,total:$,selected:a,width:ft,height:je,loading:F,dbExists:U,filter:l,sortMode:b,groupByProject:T}),ae(gt,{width:1,height:je}),h==="neighborhood"?ae(lp,{session:Nn,width:zo,height:je,budget:4e3}):ae(ap,{session:Nn,width:zo,height:je})]}),ae(gt,{height:Ep,width:n,paddingX:1,children:ae(pp,{mode:p,query:l,onQueryChange:u,onSearchSubmit:()=>m("normal"),onAliasSubmit:V,onTagSubmit:Je,aliasInitial:Nn?.alias??"",toast:f})})]})}var vR,IR,MR,Ep,DR,Xo,PR,wp=L(()=>{"use strict";tp();np();cp();dp();mp();fp();hp();ze();ht();hr();dt();vR=4,IR=1,MR=1,Ep=1,DR=vR+IR+MR,Xo=["recent","longest","busiest"];PR={recent:"most recent first",longest:"longest sessions first",busiest:"busiest project first"}});import{render as jR}from"ink";import{jsx as FR}from"react/jsx-runtime";async function yp(){let e={showSessionId:null};return await jR(FR(Sp,{onShowSession:n=>{e.showSessionId=n}})).waitUntilExit(),e}var Tp=L(()=>{"use strict";wp()});var Rp={};_e(Rp,{runTui:()=>BR});import{spawn as UR}from"node:child_process";async function BR(){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 yp();if(!e.showSessionId)return;let t=process.argv[1];t&&await new Promise(s=>{let n=UR(process.execPath,[t,"show",e.showSessionId],{stdio:"inherit"});n.on("exit",()=>s()),n.on("error",()=>s())})}var xp=L(()=>{"use strict";Tp()});var kp={};_e(kp,{findSimilarSessions:()=>WR,vectorSearch:()=>HR});async function HR(e,t=50){let s=await xr(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
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 DR(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 c of i){if(c.session_id===e)continue;let u=a.get(c.session_id);(u===void 0||c.distance<u)&&a.set(c.session_id,c.distance)}let d=[];for(let[c,u]of a){let p=1-u;p>=s&&d.push({sessionId:c,similarity:p})}return d.sort((c,u)=>u.similarity-c.similarity),d.slice(0,t)}var Rp=L(()=>{"use strict";y();et()});import{createRequire as $R}from"module";import{Command as PR}from"commander";y();D();import{basename as km}from"node:path";import{createReadStream as Wp}from"node:fs";import{createInterface as Xp}from"node:readline";function fs(e){return typeof e=="number"&&Number.isFinite(e)?e:0}function $n(e){let t=e?.usage;if(!t||typeof t!="object")return null;let s={inputTokens:fs(t.input_tokens),outputTokens:fs(t.output_tokens),cacheCreateTokens:fs(t.cache_creation_input_tokens),cacheReadTokens:fs(t.cache_read_input_tokens)};return s.inputTokens===0&&s.outputTokens===0&&s.cacheCreateTokens===0&&s.cacheReadTokens===0?null:s}var Jp=/\x1B\[[0-9;]*[a-zA-Z]/g;function Mn(e){return e.replace(Jp,"")}var Dn=12e3;function oi(e,t){if(e.length<=Dn)return e;let s=e.slice(0,Dn),n=e.length-Dn;return`${s}
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 WR(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 Cp=L(()=>{"use strict";y();st()});import{createRequire as XR}from"module";import{Command as JR}from"commander";y();D();import{basename as Nm}from"node:path";import{createReadStream as Gp}from"node:fs";import{createInterface as Yp}from"node:readline";function fs(e){return typeof e=="number"&&Number.isFinite(e)?e:0}function $n(e){let t=e?.usage;if(!t||typeof t!="object")return null;let s={inputTokens:fs(t.input_tokens),outputTokens:fs(t.output_tokens),cacheCreateTokens:fs(t.cache_creation_input_tokens),cacheReadTokens:fs(t.cache_read_input_tokens)};return s.inputTokens===0&&s.outputTokens===0&&s.cacheCreateTokens===0&&s.cacheReadTokens===0?null:s}var zp=/\x1B\[[0-9;]*[a-zA-Z]/g;function Mn(e){return e.replace(zp,"")}var Dn=12e3;function ii(e,t){if(e.length<=Dn)return e;let s=e.slice(0,Dn),n=e.length-Dn;return`${s}
811
811
 
812
- \u27E8\u2026 ${n.toLocaleString()} more chars in ${t}; see raw JSONL for full content \u27E9`}function Yp(e){try{return JSON.stringify(e,null,2)}catch{return String(e)}}function Gp(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 zp(e){if(!e)return{text:"",toolNames:[]};if(typeof e.content=="string")return{text:Mn(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(Mn(n.text));continue}if(n.type==="tool_use"&&typeof n.name=="string"){s.push(n.name);let r=n.input!=null?Yp(n.input):"",o=oi(r,"tool input");t.push(`\u26A1 **Tool call \xB7 \`${n.name}\`**
812
+ \u27E8\u2026 ${n.toLocaleString()} more chars in ${t}; see raw JSONL for full content \u27E9`}function qp(e){try{return JSON.stringify(e,null,2)}catch{return String(e)}}function Kp(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 Vp(e){if(!e)return{text:"",toolNames:[]};if(typeof e.content=="string")return{text:Mn(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(Mn(n.text));continue}if(n.type==="tool_use"&&typeof n.name=="string"){s.push(n.name);let r=n.input!=null?qp(n.input):"",o=ii(r,"tool input");t.push(`\u26A1 **Tool call \xB7 \`${n.name}\`**
814
814
 
815
815
  \`\`\`json
816
816
  ${o}
817
- \`\`\``);continue}if(n.type==="tool_result"){let r=Mn(Gp(n));if(r){let o=oi(r,"tool result");t.push(`**Tool result**
817
+ \`\`\``);continue}if(n.type==="tool_result"){let r=Mn(Kp(n));if(r){let o=ii(r,"tool result");t.push(`**Tool result**
818
818
 
819
819
  \`\`\`
820
820
  ${o}
821
821
  \`\`\``)}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
822
 
823
- `),toolNames:s}}async function*Pn(e){let t=Wp(e,{encoding:"utf8"}),s=Xp({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}=zp(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:$n(r.message),model:r.message?.model??null}}}v();var ai=[{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 ci(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 Wt(e){if(!e)return[];let t=new Set,s=[];for(let n of ai){n.regex.lastIndex=0;for(let r of e.matchAll(n.regex)){let o=r[0],i=`${n.name}::${li(o)}`;t.has(i)||(t.add(i),s.push({pattern:n.name,maskedPreview:ci(o),offset:r.index??0,severity:n.severity}))}}return s}function li(e){let t=5381;for(let s=0;s<e.length;s++)t=(t<<5)+t+e.charCodeAt(s)|0;return(t>>>0).toString(36)}function ye(e){if(!e)return{redacted:e,count:0};let t=e,s=0,n=new Set;for(let r of ai)r.regex.lastIndex=0,t=t.replace(r.regex,o=>{let i=`${r.name}::${li(o)}`;return n.has(i)||(n.add(i),s+=1),`[REDACTED ${r.name}: ${ci(o)}]`});return{redacted:t,count:s}}function jn(e,t,s){e.prepare("DELETE FROM message_usage WHERE session_id = ?").run(t);let n=e.prepare(`
823
+ `),toolNames:s}}async function*Pn(e){let t=Gp(e,{encoding:"utf8"}),s=Yp({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}=Vp(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:$n(r.message),model:r.message?.model??null}}}v();var ai=[{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 ci(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 Wt(e){if(!e)return[];let t=new Set,s=[];for(let n of ai){n.regex.lastIndex=0;for(let r of e.matchAll(n.regex)){let o=r[0],i=`${n.name}::${li(o)}`;t.has(i)||(t.add(i),s.push({pattern:n.name,maskedPreview:ci(o),offset:r.index??0,severity:n.severity}))}}return s}function li(e){let t=5381;for(let s=0;s<e.length;s++)t=(t<<5)+t+e.charCodeAt(s)|0;return(t>>>0).toString(36)}function ye(e){if(!e)return{redacted:e,count:0};let t=e,s=0,n=new Set;for(let r of ai)r.regex.lastIndex=0,t=t.replace(r.regex,o=>{let i=`${r.name}::${li(o)}`;return n.has(i)||(n.add(i),s+=1),`[REDACTED ${r.name}: ${ci(o)}]`});return{redacted:t,count:s}}function Fn(e,t,s){e.prepare("DELETE FROM message_usage WHERE session_id = ?").run(t);let n=e.prepare(`
824
824
  INSERT INTO message_usage (
825
825
  message_uuid, session_id, model,
826
826
  input_tokens, output_tokens, cache_create_tokens, cache_read_tokens,
@@ -852,17 +852,17 @@ ${o}
852
852
  total_cache_create_tokens = @cc,
853
853
  total_cache_read_tokens = @cr,
854
854
  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})}y();D();import{writeFileSync as tm,mkdirSync as sm,existsSync as nm}from"node:fs";import{join as pi}from"node:path";y();var Vp=[/^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 Lt=[/^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 Zp=[/^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],Qp=[/^Draft (a|an|marketing) [a-z]/i,/^Read the file at /i,/^Read this and then begin/i,/^read this and then begin/i],em=20;function di(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<em)return"low_signal";for(let t of Vp)if(t.test(e.auto_title))return"recursive_meta";for(let t of Zp)if(t.test(e.auto_title))return"programmatic";for(let t of Qp)if(t.test(e.auto_title))return"template_pending";return"clean"}function Fn(e){if(!e)return"";let t=e.split("|")[0];return t=t.replace(/\s*\([^)]*\)\s*$/,""),t=t.replace(/\s+/g," ").trim(),t}var Bn=pi(R,"titles"),rm=80,om=60,im=100;function am(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 Wn(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<=rm?n:t.slice(0,om)).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=Hn(r);return o?Jt(`${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):Hn(t);return i?n.completeFromExtract?Jt(i):Jt(`${o} \xB7 ${i}`):o}for(let n of pm){if(!e.match(n.match))continue;let o=n.extract?n.extract(e,t):_s(t);return o?n.completeFromExtract?Jt(o):Jt(`${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=Hn(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)=>um(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)=>dm(t)},{match:/^You will receive a sample of user messages from a Claude Code session:/i,prefix:"[meta]",completeFromExtract:!0,extract:(e,t)=>ui(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)=>ui(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 dm(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 ui(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 um(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 pm=[{match:/^Score this person'?s relevance/i,prefix:"Score relevance",extract:(e,t)=>_s(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=_s(t);return o?`${r} \xB7 ${o}`:r}},{match:/^Return ONLY valid JSON/i,prefix:"JSON-only",extract:(e,t)=>_s(t)}];function _s(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 Fn(r)||r}return null}function Jt(e){return e.slice(0,im).trim()}var mm=[/^deep research$/i,/^reference(?: spec)?$/i,/^canonical spec/i,/^product context/i,/^services?(?: overview)?$/i,/^overview$/i,/^(?:introduction|template|instructions|context)$/i],gm=[/^(?:brand|brand brief|brand summary)$/i,/^(?:known facts?|facts)$/i,/^(?:client|prospect|customer|account)$/i,/^(?:topic|subject|brief|task)$/i,/^(?:about|for|re)$/i];function Un(e){let t=e.trim();return t.length<3?!0:mm.some(s=>s.test(t))}function fm(e){let t=e.trim().replace(/\s*\([^)]*\)\s*$/,"").trim();return gm.some(s=>s.test(t))}function Hn(e){let t=_m(e);return t===null?null:Fn(t)||t}function _m(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(),c=s[3].trim().replace(/\s+/g," ");if(!Un(c)){if(fm(d))return c;n.push(c)}}if(n.length>0)return n[0];let r=e.match(/\b(?:Topic|Subject|Brand|About|Client|For|Re)\s*:\s*([^\n]{2,80})/i);if(r?.[1]&&!Un(r[1]))return r[1].trim().replace(/\s+/g," ");let o=/===\s*([^=\n]{2,120}?)\s*===/g;for(;(s=o.exec(e))!==null;){let d=s[1].trim().replace(/\.(md|txt|json)$/i,""),c=d.replace(/\s*\([^)]*\)\s*$/,"").trim();if(c&&!Un(c)&&!/product context|reference/i.test(d))return c}let i=e.replace(/^Context for this run[^:]*:\s*/i,"");if(i!==e){let d=i.split(`
856
- `).map(c=>c.trim()).find(c=>c.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 Xn(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=am(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
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})}y();D();import{writeFileSync as rm,mkdirSync as om,existsSync as im}from"node:fs";import{join as pi}from"node:path";y();var em=[/^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 Lt=[/^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 tm=[/^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],sm=[/^Draft (a|an|marketing) [a-z]/i,/^Read the file at /i,/^Read this and then begin/i,/^read this and then begin/i],nm=20;function di(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<nm)return"low_signal";for(let t of em)if(t.test(e.auto_title))return"recursive_meta";for(let t of tm)if(t.test(e.auto_title))return"programmatic";for(let t of sm)if(t.test(e.auto_title))return"template_pending";return"clean"}function Un(e){if(!e)return"";let t=e.split("|")[0];return t=t.replace(/\s*\([^)]*\)\s*$/,""),t=t.replace(/\s+/g," ").trim(),t}var Hn=pi(R,"titles"),am=80,cm=60,lm=100;function dm(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 Xn(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=um(t,e);if(s)return s;let n=t.match(/^[^.!?\n]{8,}?[.!?]/)?.[0]?.trim();return(n&&n.length<=am?n:t.slice(0,cm)).trim()||null}function um(e,t){let s=e.match(/^\/([A-Za-z0-9][A-Za-z0-9_-]*)\s+([\s\S]*)$/);if(s){let n=`/${s[1]}`,r=t.replace(/^\s*\/[A-Za-z0-9][A-Za-z0-9_-]*\s+/,""),o=Wn(r);return o?Jt(`${n} \xB7 ${o}`):n}for(let n of pm){if(!e.match(n.match))continue;let o=n.prefix,i=n.extract?n.extract(e,t):Wn(t);return i?n.completeFromExtract?Jt(i):Jt(`${o} \xB7 ${i}`):o}for(let n of fm){if(!e.match(n.match))continue;let o=n.extract?n.extract(e,t):_s(t);return o?n.completeFromExtract?Jt(o):Jt(`${n.prefix} \xB7 ${o}`):n.prefix}return null}var pm=[{match:/^Draft (?:a|an) brand brief\b/i,prefix:"Draft brand brief"},{match:/^Draft (?:a|an) sales brief\b/i,prefix:"Draft sales brief"},{match:/^Draft (?:a|an) leave-behind\b/i,prefix:"Draft leave-behind"},{match:/^Draft (?:a|an) audio identity brief\b/i,prefix:"Draft audio identity brief"},{match:/^Draft marketing ideas\b/i,prefix:"Draft marketing ideas"},{match:/^Draft (?:a|an) ([a-z]{3,30}(?:\s+[a-z]{3,30}){0,2})\b/i,prefix:"Draft",extract:(e,t)=>{let n=e.match(/^Draft (?:a|an) ([a-z]{3,30}(?:\s+[a-z]{3,30}){0,2})\b/i)?.[1]?.trim(),r=Wn(t);return n&&r?`${n} \xB7 ${r}`:n||r}},{match:/^Read the file at /i,prefix:"Read",extract:e=>{let s=e.match(/^Read the file at\s+([^\s]+)/i)?.[1];return s?s.split("/").filter(Boolean).slice(-2).join("/")||s:null}},{match:/^(?:read|inspect) this and then begin\b/i,prefix:"Begin from preamble",completeFromExtract:!0,extract:(e,t)=>gm(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)=>mm(t)},{match:/^You will receive a sample of user messages from a Claude Code session:/i,prefix:"[meta]",completeFromExtract:!0,extract:(e,t)=>ui(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)=>ui(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 mm(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 ui(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 gm(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 fm=[{match:/^Score this person'?s relevance/i,prefix:"Score relevance",extract:(e,t)=>_s(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=_s(t);return o?`${r} \xB7 ${o}`:r}},{match:/^Return ONLY valid JSON/i,prefix:"JSON-only",extract:(e,t)=>_s(t)}];function _s(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 Un(r)||r}return null}function Jt(e){return e.slice(0,lm).trim()}var _m=[/^deep research$/i,/^reference(?: spec)?$/i,/^canonical spec/i,/^product context/i,/^services?(?: overview)?$/i,/^overview$/i,/^(?:introduction|template|instructions|context)$/i],hm=[/^(?: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 Bn(e){let t=e.trim();return t.length<3?!0:_m.some(s=>s.test(t))}function Em(e){let t=e.trim().replace(/\s*\([^)]*\)\s*$/,"").trim();return hm.some(s=>s.test(t))}function Wn(e){let t=bm(e);return t===null?null:Un(t)||t}function bm(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(!Bn(l)){if(Em(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]&&!Bn(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&&!Bn(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
+ `).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 Jn(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=dm(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
859
  SET auto_title = ?,
860
860
  auto_title_source = ?,
861
861
  auto_title_generated_at = ?,
862
862
  auto_title_history = ?
863
- WHERE id = ?`).run(n,s,Date.now(),JSON.stringify(i),e),Em(e,n,s,a)}function hm(){$(),nm(Bn)||sm(Bn,{recursive:!0})}function Em(e,t,s,n){try{hm();let r=pi(Bn,`${e}.txt`),o=`# Claude Recall auto-title \xB7 session ${e} \xB7 source ${s} \xB7 updated ${n}
864
- `;tm(r,o+t+`
865
- `)}catch(r){console.error("[autoTitle] mirror write failed:",r)}}import{existsSync as bm,mkdirSync as Tx,readFileSync as Sm,writeFileSync as Rx}from"node:fs";import{homedir as wm}from"node:os";import{join as mi}from"node:path";import{z as Jn}from"zod";function ym(){return process.env.RECALL_HOME??mi(wm(),".recall")}function Tm(){return mi(ym(),"config.json")}var Rm=Jn.object({heuristicEnabled:Jn.boolean().default(!0),agentEnabled:Jn.boolean().default(!1)}),Yn={heuristicEnabled:!0,agentEnabled:!1};function xm(){let e=Tm();if(!bm(e))return{};try{return JSON.parse(Sm(e,"utf8"))}catch(t){return console.error("[auto-title-config] failed to parse config.json, using defaults:",t),{}}}function Gn(){let e=xm().autoTitle;if(!e)return{...Yn};let t=Rm.safeParse({...Yn,...e});return t.success?t.data:{...Yn}}var Cm=[/^<local-command-caveat>/,/^<command-name>/,/^<command-message>/,/^<system-reminder>/,/^<user-prompt-submit-hook>/,/^Caveat: The messages below were generated/i];function Lm(e){let t=e.trim();return t?Cm.some(s=>s.test(t)):!0}function Nm(e){let t=e;return t=t.replace(/^(?:<[^>]+>[\s\S]*?<\/[^>]+>\s*)+/,"").trim(),t=t.replace(/^<command-[^>]+>[^<]*<\/command-[^>]+>\s*/gm,"").trim(),!t||Lm(t)?null:t}function Om(e,t,s){let n=In(t),r=s??n,o=s?km(s)||s:Qo(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 Am(e,t,s){let n=e.prepare("SELECT id, file_mtime FROM sessions WHERE file_path = ? LIMIT 1").get(t.sessionFile);if(!s&&n&&n.file_mtime>=t.mtime)return{inserted:!1,sessionCount:0,messageCount:0};let r=new Map,o=null;for await(let g of Pn(t.sessionFile)){let h=r.get(g.sessionId);if(h||(h={sessionId:g.sessionId,entries:[],earliestTimestamp:null,latestTimestamp:null,firstUserMessage:null,userCount:0,assistantCount:0,cwd:null,gitBranch:null,version:null},r.set(g.sessionId,h)),h.entries.push(g),g.timestamp&&((!h.earliestTimestamp||g.timestamp<h.earliestTimestamp)&&(h.earliestTimestamp=g.timestamp),(!h.latestTimestamp||g.timestamp>h.latestTimestamp)&&(h.latestTimestamp=g.timestamp)),g.role==="user"&&!g.isSidechain){if(h.userCount+=1,!h.firstUserMessage&&g.contentText){let E=Nm(g.contentText);E&&(h.firstUserMessage=q(ye(E).redacted,200))}}else g.role==="assistant"&&!g.isSidechain&&(h.assistantCount+=1);!h.cwd&&g.cwd&&(h.cwd=g.cwd),!h.gitBranch&&g.gitBranch&&(h.gitBranch=g.gitBranch),!h.version&&g.version&&(h.version=g.version),!o&&g.cwd&&(o=g.cwd)}let i=Om(e,t.encodedProject,o),a=new Date().toISOString(),d=e.prepare(`
863
+ WHERE id = ?`).run(n,s,Date.now(),JSON.stringify(i),e),wm(e,n,s,a)}function Sm(){P(),im(Hn)||om(Hn,{recursive:!0})}function wm(e,t,s,n){try{Sm();let r=pi(Hn,`${e}.txt`),o=`# Claude Recall auto-title \xB7 session ${e} \xB7 source ${s} \xB7 updated ${n}
864
+ `;rm(r,o+t+`
865
+ `)}catch(r){console.error("[autoTitle] mirror write failed:",r)}}import{existsSync as ym,mkdirSync as Ax,readFileSync as Tm,writeFileSync as vx}from"node:fs";import{homedir as Rm}from"node:os";import{join as mi}from"node:path";import{z as Gn}from"zod";function xm(){return process.env.RECALL_HOME??mi(Rm(),".recall")}function km(){return mi(xm(),"config.json")}var Cm=Gn.object({heuristicEnabled:Gn.boolean().default(!0),agentEnabled:Gn.boolean().default(!1)}),Yn={heuristicEnabled:!0,agentEnabled:!1};function Lm(){let e=km();if(!ym(e))return{};try{return JSON.parse(Tm(e,"utf8"))}catch(t){return console.error("[auto-title-config] failed to parse config.json, using defaults:",t),{}}}function zn(){let e=Lm().autoTitle;if(!e)return{...Yn};let t=Cm.safeParse({...Yn,...e});return t.success?t.data:{...Yn}}var Om=[/^<local-command-caveat>/,/^<command-name>/,/^<command-message>/,/^<system-reminder>/,/^<user-prompt-submit-hook>/,/^Caveat: The messages below were generated/i];function Am(e){let t=e.trim();return t?Om.some(s=>s.test(t)):!0}function vm(e){let t=e;return t=t.replace(/^(?:<[^>]+>[\s\S]*?<\/[^>]+>\s*)+/,"").trim(),t=t.replace(/^<command-[^>]+>[^<]*<\/command-[^>]+>\s*/gm,"").trim(),!t||Am(t)?null:t}function Im(e,t,s){let n=In(t),r=s??n,o=s?Nm(s)||s:ei(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 Mm(e,t,s){let n=e.prepare("SELECT id, file_mtime FROM sessions WHERE file_path = ? LIMIT 1").get(t.sessionFile);if(!s&&n&&n.file_mtime>=t.mtime)return{inserted:!1,sessionCount:0,messageCount:0};let r=new Map,o=null;for await(let g of Pn(t.sessionFile)){let h=r.get(g.sessionId);if(h||(h={sessionId:g.sessionId,entries:[],earliestTimestamp:null,latestTimestamp:null,firstUserMessage:null,userCount:0,assistantCount:0,cwd:null,gitBranch:null,version:null},r.set(g.sessionId,h)),h.entries.push(g),g.timestamp&&((!h.earliestTimestamp||g.timestamp<h.earliestTimestamp)&&(h.earliestTimestamp=g.timestamp),(!h.latestTimestamp||g.timestamp>h.latestTimestamp)&&(h.latestTimestamp=g.timestamp)),g.role==="user"&&!g.isSidechain){if(h.userCount+=1,!h.firstUserMessage&&g.contentText){let E=vm(g.contentText);E&&(h.firstUserMessage=q(ye(E).redacted,200))}}else g.role==="assistant"&&!g.isSidechain&&(h.assistantCount+=1);!h.cwd&&g.cwd&&(h.cwd=g.cwd),!h.gitBranch&&g.gitBranch&&(h.gitBranch=g.gitBranch),!h.version&&g.version&&(h.version=g.version),!o&&g.cwd&&(o=g.cwd)}let i=Im(e,t.encodedProject,o),a=new Date().toISOString(),d=e.prepare(`
866
866
  INSERT INTO sessions (
867
867
  id, project_id, file_path, file_mtime,
868
868
  started_at, ended_at, message_count,
@@ -888,7 +888,7 @@ ${o}
888
888
  git_branch = excluded.git_branch,
889
889
  version = excluded.version,
890
890
  indexed_at = excluded.indexed_at
891
- `),c=e.prepare(`
891
+ `),l=e.prepare(`
892
892
  INSERT INTO messages (
893
893
  uuid, session_id, parent_uuid, type, role, timestamp,
894
894
  is_sidechain, content_text, tool_names, raw_json
@@ -897,30 +897,30 @@ ${o}
897
897
  @is_sidechain, @content_text, @tool_names, @raw_json
898
898
  )
899
899
  ON CONFLICT(uuid) DO NOTHING
900
- `),u=e.prepare("DELETE FROM messages WHERE session_id = ?"),p=0,m=0;if(e.transaction(()=>{for(let g of r.values()){d.run({id:g.sessionId,project_id:i,file_path:t.sessionFile,file_mtime:t.mtime,started_at:g.earliestTimestamp,ended_at:g.latestTimestamp,message_count:g.entries.length,user_message_count:g.userCount,assistant_message_count:g.assistantCount,first_user_message:g.firstUserMessage,cwd:g.cwd,git_branch:g.gitBranch,version:g.version,indexed_at:a}),u.run(g.sessionId);for(let h of g.entries){let{redacted:E}=ye(h.contentText),{redacted:b}=ye(h.raw);c.run({uuid:h.uuid,session_id:h.sessionId,parent_uuid:h.parentUuid,type:h.type,role:h.role,timestamp:h.timestamp,is_sidechain:h.isSidechain?1:0,content_text:E,tool_names:h.toolNames.join(","),raw_json:b}),m+=1}jn(e,g.sessionId,g.entries),Xt(e,g.sessionId),p+=1}})(),Gn().heuristicEnabled)for(let g of r.values()){let h=Wn(g.firstUserMessage);h&&Xn(g.sessionId,h,"heuristic")}return{inserted:!0,sessionCount:p,messageCount:m}}async function gi(e){let t=_(),s=ei();console.log(l.dim(`Scanning ${s.length} JSONL session files under ~/.claude/projects/`));let n=0,r=0,o=0,i=0,a=Date.now();for(let c of s)try{let u=await Am(t,c,e.force??!1);u.inserted?(n+=1,o+=u.sessionCount,i+=u.messageCount,e.verbose&&console.log(l.dim(` + ${c.sessionFile.split("/").slice(-2).join("/")} (${u.messageCount} msgs)`))):r+=1}catch(u){console.error(l.err(` ! failed: ${c.sessionFile}`),u)}let d=((Date.now()-a)/1e3).toFixed(1);console.log(""),console.log(`${l.ok("indexed")}: ${l.bold(String(n))} files, ${l.bold(String(o))} sessions, ${l.bold(String(i))} messages ${l.dim(`in ${d}s`)}`),r>0&&console.log(l.dim(`skipped: ${r} unchanged files (use --force to reindex)`))}y();v();import vm from"cli-table3";function fi(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,
900
+ `),u=e.prepare("DELETE FROM messages WHERE session_id = ?"),p=0,m=0;if(e.transaction(()=>{for(let g of r.values()){d.run({id:g.sessionId,project_id:i,file_path:t.sessionFile,file_mtime:t.mtime,started_at:g.earliestTimestamp,ended_at:g.latestTimestamp,message_count:g.entries.length,user_message_count:g.userCount,assistant_message_count:g.assistantCount,first_user_message:g.firstUserMessage,cwd:g.cwd,git_branch:g.gitBranch,version:g.version,indexed_at:a}),u.run(g.sessionId);for(let h of g.entries){let{redacted:E}=ye(h.contentText),{redacted:b}=ye(h.raw);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}Fn(e,g.sessionId,g.entries),Xt(e,g.sessionId),p+=1}})(),zn().heuristicEnabled)for(let g of r.values()){let h=Xn(g.firstUserMessage);h&&Jn(g.sessionId,h,"heuristic")}return{inserted:!0,sessionCount:p,messageCount:m}}async function gi(e){let t=_(),s=ti();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 Mm(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)`))}y();v();import Dm from"cli-table3";function fi(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
901
  s.message_count, s.first_user_message, s.git_branch
902
902
  FROM sessions s
903
903
  JOIN projects p ON p.id = s.project_id
904
904
  WHERE ${r}
905
905
  ORDER BY COALESCE(s.started_at, '') DESC
906
- LIMIT @limit`).all(n);if(o.length===0){console.log(l.dim("no sessions found. run `recall index` first."));return}let i=new vm({head:[l.bold("id"),l.bold("project"),l.bold("when"),l.bold("msgs"),l.bold("opening prompt")],colWidths:[10,22,14,6,70],wordWrap:!0,style:{head:[],border:["grey"]}});for(let a of o)i.push([l.accent(H(a.id)),l.project(q(a.project_name,20)),l.dim(W(a.started_at)),String(a.message_count),q(a.first_user_message,200)]);console.log(i.toString()),console.log(l.dim(`showing ${o.length} session${o.length===1?"":"s"}. use \`recall show <id>\` to view one.`))}y();v();import{spawn as Hm}from"node:child_process";import{readFileSync as Im,writeFileSync as Mm,mkdirSync as Dm,chmodSync as $m}from"node:fs";import{join as _i}from"node:path";import{homedir as hi}from"node:os";function Ei(){return _i(hi(),".recall","config.json")}function bi(){try{return JSON.parse(Im(Ei(),"utf-8"))}catch{return{}}}function Pm(e){let t=Ei();Dm(_i(hi(),".recall"),{recursive:!0}),Mm(t,JSON.stringify(e,null,2)+`
907
- `,"utf-8"),$m(t,384)}function hs(){let t=bi().verification;return typeof t=="object"&&t!==null&&"enabled"in t?!!t.enabled:!1}function zn(e){let t=bi();t.verification={...typeof t.verification=="object"&&t.verification!==null?t.verification:{},enabled:e},Pm(t)}y();var jm=[/\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],Fm=1440*60*1e3;function Um(e){let t=_(),s=t.prepare(`SELECT content_text, tool_names FROM messages
906
+ LIMIT @limit`).all(n);if(o.length===0){console.log(c.dim("no sessions found. run `recall index` first."));return}let i=new Dm({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.`))}y();v();import{spawn as Jm}from"node:child_process";import{readFileSync as $m,writeFileSync as Pm,mkdirSync as jm,chmodSync as Fm}from"node:fs";import{join as _i}from"node:path";import{homedir as hi}from"node:os";function Ei(){return _i(hi(),".recall","config.json")}function bi(){try{return JSON.parse($m(Ei(),"utf-8"))}catch{return{}}}function Um(e){let t=Ei();jm(_i(hi(),".recall"),{recursive:!0}),Pm(t,JSON.stringify(e,null,2)+`
907
+ `,"utf-8"),Fm(t,384)}function hs(){let t=bi().verification;return typeof t=="object"&&t!==null&&"enabled"in t?!!t.enabled:!1}function qn(e){let t=bi();t.verification={...typeof t.verification=="object"&&t.verification!==null?t.verification:{},enabled:e},Um(t)}y();var Bm=[/\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],Hm=1440*60*1e3;function Wm(e){let t=_(),s=t.prepare(`SELECT content_text, tool_names FROM messages
908
908
  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&&jm.some(c=>c.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 c=d.tool_names??"",u=d.content_text??"";/\bWrite\b|\bEdit\b/.test(c)&&(o.fileWrites=!0),/\b(?:jest|pytest|vitest|mocha|test|spec)\b/i.test(u)&&/pass|ok|✓/i.test(u)&&(o.testRuns=!0),/\bgit\s+commit\b/i.test(u)&&(o.commits=!0),(/\bbuild\s+(?:succeeded|success|passed)\b/i.test(u)||/tsc.*(?:0 errors|no errors)/i.test(u))&&(o.buildSuccess=!0)}return n?{status:[o.fileWrites,o.testRuns,o.commits,o.buildSuccess].filter(Boolean).length>=2?"verified":"unverified",evidence:o,claimFound:n}:{status:"neutral",evidence:o,claimFound:n}}function Bm(e){let t=Um(e);return _().prepare("UPDATE sessions SET verification_status = ?, verification_computed_at = ? WHERE id = ?").run(t.status,Date.now(),e),t}function Si(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<Fm){let n={fileWrites:!1,testRuns:!1,commits:!1,buildSuccess:!1};return{status:s.verification_status,evidence:n,claimFound:s.verification_status!=="neutral"}}return Bm(e)}function Wm(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(l.err(`ambiguous id prefix "${t}". be more specific.`)),null)}function Xm(e,t){let s=_(),n=s.prepare(`SELECT s.id, p.name AS project_name, p.decoded_path,
909
+ ORDER BY timestamp DESC LIMIT 5`).all(e),n=!1;for(let d of s)if(d.content_text&&Bm.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 Xm(e){let t=Wm(e);return _().prepare("UPDATE sessions SET verification_status = ?, verification_computed_at = ? WHERE id = ?").run(t.status,Date.now(),e),t}function Si(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<Hm){let n={fileWrites:!1,testRuns:!1,commits:!1,buildSuccess:!1};return{status:s.verification_status,evidence:n,claimFound:s.verification_status!=="neutral"}}return Xm(e)}function Gm(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 Ym(e,t){let s=_(),n=s.prepare(`SELECT s.id, p.name AS project_name, p.decoded_path,
911
911
  s.started_at, s.ended_at, s.message_count,
912
912
  s.git_branch, s.version, s.cwd
913
913
  FROM sessions s
914
914
  JOIN projects p ON p.id = s.project_id
915
- WHERE s.id = ?`).get(e);if(!n)return null;let r=[],o=l.dim("\u2500".repeat(78));if(r.push(""),r.push(l.bold(l.project(n.project_name))+l.dim(` ${n.decoded_path}`)),r.push(l.dim(`session ${n.id} \xB7 ${n.message_count} msgs \xB7 ${W(n.started_at)}`+(n.git_branch?` \xB7 branch: ${n.git_branch}`:""))),hs()){let d=Si(e);d.status==="verified"?r.push(l.ok("\u2713 verified")):d.status==="unverified"&&r.push(l.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
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}`:""))),hs()){let d=Si(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
916
  FROM messages
917
917
  WHERE session_id = ?
918
918
  ORDER BY COALESCE(timestamp, ''), rowid
919
- LIMIT ?`).all(e,i);for(let d of a){if(t.raw){r.push(d.raw_json);continue}let c=d.is_sidechain===1?l.dim(" [subagent]"):"",u=d.role==="user"?l.user("\u25B8 user"):d.role==="assistant"?l.assistant("\u25B8 assistant"):l.dim(`\u25B8 ${d.type}`);if(r.push(`${u}${c} ${l.dim(d.timestamp??"")}`),d.tool_names&&d.tool_names.length>0&&r.push(l.tool(` tools: ${d.tool_names}`)),d.content_text&&d.content_text.trim()){let p=d.content_text.trim().split(`
919
+ 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
920
  `).map(m=>" "+m).join(`
921
- `);r.push(p)}r.push("")}return r.push(o),r.push(l.dim(`end of session ${n.id}`)),r.join(`
922
- `)}function Jm(e,t){if(!t||!process.stdout.isTTY)return!1;let s=process.stdout.rows||24;return e.split(`
923
- `).length>s}function Ym(e){let t=Hm("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 wi(e,t){let s=_(),n=Wm(s,e);if(!n){e.length>=32&&console.error(l.err(`session not found: ${e}`)),process.exitCode=1;return}let r=Xm(n,t);if(r===null){console.error(l.err(`session metadata missing for ${n}`)),process.exitCode=1;return}let o=t.pager!==!1;Jm(r,o)?Ym(r):console.log(r)}y();v();he();function Sg(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 Mi(e,t){await Ne("Full-text search");let s=_(),n=Sg(e);if(!n){console.log(l.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,
921
+ `);r.push(p)}r.push("")}return r.push(o),r.push(c.dim(`end of session ${n.id}`)),r.join(`
922
+ `)}function zm(e,t){if(!t||!process.stdout.isTTY)return!1;let s=process.stdout.rows||24;return e.split(`
923
+ `).length>s}function qm(e){let t=Jm("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 wi(e,t){let s=_(),n=Gm(s,e);if(!n){e.length>=32&&console.error(c.err(`session not found: ${e}`)),process.exitCode=1;return}let r=Ym(n,t);if(r===null){console.error(c.err(`session metadata missing for ${n}`)),process.exitCode=1;return}let o=t.pager!==!1;zm(r,o)?qm(r):console.log(r)}y();v();he();D();import{existsSync as kg,readFileSync as Cg}from"node:fs";import{join as Lg}from"node:path";ar();function Di(e){let t=Mi(),s={...e};return t&&(s["x-recall-token"]=t),s}async function Ye(e,t){let s=t?.headers??{};return fetch(e,{...t,headers:Di(s)})}async function Qe(e,t,s,n){let r=s!==void 0?{"content-type":"application/json",...n}:{...n};return fetch(t,{method:e,headers:Di(r),body:s!==void 0?JSON.stringify(s):void 0})}function $i(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 Ng(e,t){let s=Lg(R,"daemon.port");kg(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=Cg(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=$i(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 Ye(`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," "),f=p.role==="user"?c.user("user"):p.role==="assistant"?c.assistant("asst"):c.dim("----"),g=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))} ${f} ${g}`),console.log(` ${q(m,200)}`),console.log("")}console.log(c.dim("`recall show <id>` to read any session."))}async function Pi(e,t){if(await Ne("Full-text search"),t.semantic){await Ng(e,t);return}let s=_(),n=$i(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
924
  p.name AS project_name,
925
925
  s.started_at AS started_at,
926
926
  snippet(messages_fts, 0, '<<', '>>', '\u2026', 16) AS snippet,
@@ -933,13 +933,13 @@ ${o}
933
933
  WHERE messages_fts MATCH @q
934
934
  ${i}
935
935
  ORDER BY bm25(messages_fts)
936
- LIMIT @limit`).all(o);if(a.length===0){console.log(l.dim(`no matches for "${e}"`));return}console.log(l.dim(`${a.length} match${a.length===1?"":"es"} for "${e}"`)),console.log("");for(let d of a){let c=d.snippet.replace(/<<([\s\S]*?)>>/g,(p,m)=>ii(m,m).replace(/\n/g," ")).replace(/\n/g," "),u=d.role==="user"?l.user("user"):d.role==="assistant"?l.assistant("asst"):l.dim("----");console.log(`${l.accent(H(d.session_id))} ${l.project(q(d.project_name,20))} ${l.dim(W(d.started_at))} ${u}`),console.log(` ${q(c,200)}`),console.log("")}console.log(l.dim("`recall show <id>` to read any session."))}y();D();Ge();v();import{statSync as Lg,existsSync as Ng}from"node:fs";function Pi(){if(console.log(""),console.log(l.bold("Claude Recall status")),console.log(l.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),!Ng(te)){console.log(l.dim(" no database yet. run `recall index`."));return}let t=_().prepare(`SELECT
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."))}y();D();ze();v();import{statSync as Mg,existsSync as Dg}from"node:fs";function Fi(){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")),!Dg(te)){console.log(c.dim(" no database yet. run `recall index`."));return}let t=_().prepare(`SELECT
937
937
  (SELECT COUNT(*) FROM projects) AS projects,
938
938
  (SELECT COUNT(*) FROM sessions) AS sessions,
939
939
  (SELECT COUNT(*) FROM messages) AS messages,
940
940
  (SELECT MIN(started_at) FROM sessions WHERE started_at IS NOT NULL) AS earliest,
941
941
  (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=(Lg(te).size/1024/1024).toFixed(1);console.log(` db path ${l.dim(te)}`),console.log(` db size ${l.accent(n+" MB")}`),console.log(` projects ${l.accent(String(t.projects))}`),console.log(` sessions ${l.accent(String(t.sessions))}`),console.log(` messages ${l.accent(String(t.messages))}`),console.log(` earliest ${l.dim(t.earliest??"n/a")}`),console.log(` latest ${l.dim(t.latest??"n/a")} ${l.dim(W(t.latest))}`),console.log(` last index ${l.dim(t.last_indexed??"never")}`),console.log("");let r=Z();r?(console.log(` daemon ${l.ok("running")} pid ${r.pid} \xB7 http://127.0.0.1:${r.port}`),console.log(` started ${l.dim(r.startedAt)} ${l.dim(W(r.startedAt))}`)):console.log(` daemon ${l.dim("stopped")} (run \`recall start\` or \`recall open\`)`),console.log("")}y();v();import Og from"cli-table3";function ji(){let t=_().prepare(`SELECT p.name,
942
+ (SELECT MAX(indexed_at) FROM sessions) AS last_indexed`).get(),n=(Mg(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("")}y();v();import $g from"cli-table3";function Ui(){let t=_().prepare(`SELECT p.name,
943
943
  p.decoded_path,
944
944
  COUNT(s.id) AS session_count,
945
945
  COALESCE(SUM(s.message_count), 0) AS message_count,
@@ -947,10 +947,10 @@ ${o}
947
947
  FROM projects p
948
948
  LEFT JOIN sessions s ON s.project_id = p.id
949
949
  GROUP BY p.id
950
- ORDER BY MAX(COALESCE(s.started_at, '')) DESC`).all();if(t.length===0){console.log(l.dim("no projects indexed yet."));return}let s=new Og({head:[l.bold("project"),l.bold("sessions"),l.bold("msgs"),l.bold("latest"),l.bold("path")],style:{head:[],border:["grey"]}});for(let n of t)s.push([l.project(q(n.name,30)),String(n.session_count),String(n.message_count),l.dim(W(n.latest)),l.dim(q(n.decoded_path,50))]);console.log(s.toString())}Ge();Ge();D();v();Ze();import{spawn as Ig}from"node:child_process";import{openSync as Mg}from"node:fs";import{join as Dg}from"node:path";function $g(){return Dg(le(),"dist","daemon","entrypoint.js")}async function Cs(){let e=Z();if(e){console.log(`${l.ok("already running")} pid ${e.pid} \xB7 http://127.0.0.1:${e.port}`);return}$();let t=Mg(xs,"a"),s=$g();Ig(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=Z();if(o){console.log(`${l.ok("daemon started")} pid ${o.pid} \xB7 http://127.0.0.1:${o.port}`),console.log(l.dim(`logs: ${xs}`));return}}console.error(l.err("daemon did not come up within 5s \u2014 check the log file")),console.error(l.dim(` ${xs}`)),process.exitCode=1}Ge();v();async function Ui(e,t){let s=Date.now();for(;Date.now()-s<t;)if(await new Promise(n=>setTimeout(n,100)),!lr(e))return!0;return!1}async function Bi(){let e=Z();if(!e){console.log(l.dim("no daemon running.")),zt();return}try{process.kill(e.pid,"SIGTERM")}catch(t){console.error(l.err(`failed to signal pid ${e.pid}: ${t.message}`)),process.exitCode=1;return}if(await Ui(e.pid,5e3)){console.log(l.ok(`stopped daemon pid ${e.pid}`));return}console.log(l.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(l.ok(`stopped daemon pid ${e.pid}`));return}console.error(l.err(`failed to SIGKILL pid ${e.pid}: ${t.message}`)),process.exitCode=1;return}if(await Ui(e.pid,2e3)){zt(),console.log(l.ok(`stopped daemon pid ${e.pid} (forced)`));return}console.error(l.err(`pid ${e.pid} survived SIGKILL \u2014 kernel is unhappy, kill manually with: kill -9 ${e.pid}`)),process.exitCode=1}Ge();import{spawn as Pg}from"node:child_process";import{platform as Ls}from"node:os";v();function jg(e){let t=Ls()==="darwin"?"open":Ls()==="win32"?"start":"xdg-open",s=Ls()==="win32"?["",e]:[e];Pg(t,s,{detached:!0,stdio:"ignore",shell:Ls()==="win32"}).unref()}async function Hi(){let e=Z();if(!e&&(console.log(l.dim("daemon not running \u2014 starting it\u2026")),await Cs(),e=Z(),!e)){console.error(l.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(`${l.ok("opening")} ${t}`),jg(t)}y();var Fg=/<(local-command-caveat|local-command-stdout|command-name|command-message|command-args|system-reminder|user-prompt-submit-hook|task-notification)[\s\S]*?<\/\1>/gi,Ug=/⚡ \*\*Tool call · `[^`]+`\*\*\s*\n+```json\n[\s\S]*?\n```/g,Bg=/\*\*Tool result\*\*\s*\n+```\n[\s\S]*?\n```/g;function Hg(e){return e.replace(Fg,"").trim()}function Wg(e){let t=e.replace(Ug,"[tool call]");return t=t.replace(Bg,"[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,`
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 $g({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())}ze();ze();D();v();et();import{spawn as Fg}from"node:child_process";import{openSync as Ug}from"node:fs";import{join as Bg}from"node:path";function Hg(){return Bg(le(),"dist","daemon","entrypoint.js")}async function Cs(){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=Ug(xs,"a"),s=Hg();Fg(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: ${xs}`));return}}console.error(c.err("daemon did not come up within 5s \u2014 check the log file")),console.error(c.dim(` ${xs}`)),process.exitCode=1}ze();v();async function Hi(e,t){let s=Date.now();for(;Date.now()-s<t;)if(await new Promise(n=>setTimeout(n,100)),!dr(e))return!0;return!1}async function Wi(){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 Hi(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 Hi(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}ze();import{spawn as Wg}from"node:child_process";import{platform as Ls}from"node:os";v();function Xg(e){let t=Ls()==="darwin"?"open":Ls()==="win32"?"start":"xdg-open",s=Ls()==="win32"?["",e]:[e];Wg(t,s,{detached:!0,stdio:"ignore",shell:Ls()==="win32"}).unref()}async function Xi(){let e=Q();if(!e&&(console.log(c.dim("daemon not running \u2014 starting it\u2026")),await Cs(),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}`),Xg(t)}y();var Jg=/<(local-command-caveat|local-command-stdout|command-name|command-message|command-args|system-reminder|user-prompt-submit-hook|task-notification)[\s\S]*?<\/\1>/gi,Gg=/⚡ \*\*Tool call · `[^`]+`\*\*\s*\n+```json\n[\s\S]*?\n```/g,Yg=/\*\*Tool result\*\*\s*\n+```\n[\s\S]*?\n```/g;function zg(e){return e.replace(Jg,"").trim()}function qg(e){let t=e.replace(Gg,"[tool call]");return t=t.replace(Yg,"[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 Xg(e){return e.role??e.type??"message"}function Wi(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,c=0;for(let u of i){let p=u.content_text??"",m=Hg(p);n==="condensed"&&(m=Wg(m));let f=m.length>0,g=!!u.tool_names&&u.tool_names.length>0;if(!f&&!g){c+=1;continue}let h=Xg(u),E=u.timestamp?` \`${u.timestamp}\``:"";a.push(`## ${h}${E}`),a.push(""),g&&n==="condensed"&&(a.push(`_tools used: ${u.tool_names}_`),a.push("")),f&&(a.push(m),a.push("")),d+=1}return a.push("---"),a.push(""),a.push(`_${d} messages included_`+(c?`, ${c} empty skipped`:"")+(r?"":", subagent/sidechain hidden")+"."),a.join(`
953
- `)}y();D();import{randomUUID as Xi}from"node:crypto";import{writeFileSync as Ji,readFileSync as Tk,existsSync as Jg,mkdirSync as Yg}from"node:fs";import{join as dr}from"node:path";var Ns=dr(R,"threads"),Gg=dr(Ns,"index.json");function Yi(){$(),Jg(Ns)||Yg(Ns,{recursive:!0})}function Gi(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 zi(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 Kg(e){return e.role??e.type??"message"}function Ji(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=zg(p);n==="condensed"&&(m=qg(m));let f=m.length>0,g=!!u.tool_names&&u.tool_names.length>0;if(!f&&!g){l+=1;continue}let h=Kg(u),E=u.timestamp?` \`${u.timestamp}\``:"";a.push(`## ${h}${E}`),a.push(""),g&&n==="condensed"&&(a.push(`_tools used: ${u.tool_names}_`),a.push("")),f&&(a.push(m),a.push("")),d+=1}return a.push("---"),a.push(""),a.push(`_${d} messages included_`+(l?`, ${l} empty skipped`:"")+(r?"":", subagent/sidechain hidden")+"."),a.join(`
953
+ `)}y();D();import{randomUUID as Gi}from"node:crypto";import{writeFileSync as Yi,readFileSync as Pk,existsSync as Vg,mkdirSync as Zg}from"node:fs";import{join as ur}from"node:path";var Ns=ur(R,"threads"),Qg=ur(Ns,"index.json");function zi(){P(),Vg(Ns)||Zg(Ns,{recursive:!0})}function qi(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 Ki(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),c=d.length,u=null;d.length>0&&(u=[...d].sort((m,f)=>f.n-m.n||f.origin_n-m.origin_n||(m.project??"").localeCompare(f.project??""))[0].project),t.set(i,{project:u,project_count:c})}return t}function qi(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 Ki(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,f)=>f.n-m.n||f.origin_n-m.origin_n||(m.project??"").localeCompare(f.project??""))[0].project),t.set(i,{project:u,project_count:l})}return t}function Vi(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 Zi(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 Vi(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 Qi(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 Oe(e){let t=Ae(e);t&&(Yi(),Ji(dr(Ns,`${e}.json`),JSON.stringify(t,null,2)),Zi())}function Zi(){Yi();let e=ur({includeArchived:!0});Ji(Gg,JSON.stringify({threads:e},null,2))}function Qi(e){let t=e.name.trim();if(!t)throw new Error("thread name cannot be empty");let s=_(),n=Xi(),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),Oe(n);let o=Ae(n);if(!o)throw new Error("thread creation succeeded but read-back failed");return o}function ur(e={}){let t=_(),s=e.includeArchived?"":"WHERE archived = 0",n=t.prepare(`SELECT * FROM threads ${s} ORDER BY created_at DESC`).all(),r=zi(n.map(o=>o.id));return n.map(o=>Gi(o,Vi(o.id),r.get(o.id)))}function Ae(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 Oe(e){let t=Ae(e);t&&(zi(),Yi(ur(Ns,`${e}.json`),JSON.stringify(t,null,2)),ea())}function ea(){zi();let e=pr({includeArchived:!0});Yi(Qg,JSON.stringify({threads:e},null,2))}function ta(e){let t=e.name.trim();if(!t)throw new Error("thread name cannot be empty");let s=_(),n=Gi(),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),Oe(n);let o=Ae(n);if(!o)throw new Error("thread creation succeeded but read-back failed");return o}function pr(e={}){let t=_(),s=e.includeArchived?"":"WHERE archived = 0",n=t.prepare(`SELECT * FROM threads ${s} ORDER BY created_at DESC`).all(),r=Ki(n.map(o=>o.id));return n.map(o=>qi(o,Qi(o.id),r.get(o.id)))}function Ae(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(qi),r=zi([e]).get(e);return{...Gi(s,Vi(s.id),r),edges:n}}function ea(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(Vi),r=Ki([e]).get(e);return{...qi(s,Qi(s.id),r),edges:n}}function sa(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,103 +989,103 @@ ${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),Oe(e.threadId);let d=Ki(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 ta(e,t){let n=_().prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e,t);return n.changes>0&&Oe(e),{removed:n.changes}}function sa(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,c=new Set;for(;d!==null;){if(d===t)throw new Error(`cycle detected: setting parent of ${t} to ${s} would create a loop`);if(c.has(d))break;c.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),Oe(e.threadId);let d=Zi(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 na(e,t){let n=_().prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e,t);return n.changes>0&&Oe(e),{removed:n.changes}}function ra(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),Oe(e);let i=Ki(t);return qi({...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 na(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),Oe(e);let r=Ae(e);if(!r)throw new Error(`thread ${e} not found`);return r}function ra(e){_().prepare("UPDATE threads SET closed_at = ? WHERE id = ?").run(new Date().toISOString(),e),Oe(e);let s=Ae(e);if(!s)throw new Error(`thread ${e} not found`);return s}function oa(e){_().prepare("UPDATE threads SET closed_at = NULL WHERE id = ?").run(e),Oe(e);let s=Ae(e);if(!s)throw new Error(`thread ${e} not found`);return s}function ia(e){_().prepare("UPDATE threads SET archived = 1 WHERE id = ?").run(e),Oe(e);let s=Ae(e);if(!s)throw new Error(`thread ${e} not found`);return s}function aa(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),Oe(e);let i=Zi(t);return Vi({...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 oa(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),Oe(e);let r=Ae(e);if(!r)throw new Error(`thread ${e} not found`);return r}function ia(e){_().prepare("UPDATE threads SET closed_at = ? WHERE id = ?").run(new Date().toISOString(),e),Oe(e);let s=Ae(e);if(!s)throw new Error(`thread ${e} not found`);return s}function aa(e){_().prepare("UPDATE threads SET closed_at = NULL WHERE id = ?").run(e),Oe(e);let s=Ae(e);if(!s)throw new Error(`thread ${e} not found`);return s}function ca(e){_().prepare("UPDATE threads SET archived = 1 WHERE id = ?").run(e),Oe(e);let s=Ae(e);if(!s)throw new Error(`thread ${e} not found`);return s}function la(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)})(),Oe(t),Zi();let r=Ae(t);if(!r)throw new Error("merge destination disappeared");return r}function ca(e){if(e.sessionIds.length===0)throw new Error("no sessions to split off");let t=_(),s=new Date().toISOString(),n=Xi();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)})(),Oe(t),ea();let r=Ae(t);if(!r)throw new Error("merge destination disappeared");return r}function da(e){if(e.sessionIds.length===0)throw new Error("no sessions to split off");let t=_(),s=new Date().toISOString(),n=Gi();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))}})(),Oe(e.threadId),Oe(n);let r=Ae(n);if(!r)throw new Error("split destination disappeared");return r}function la(e){let t=Ae(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();he();y();D();import{writeFileSync as zg}from"node:fs";import{join as qg}from"node:path";var Kg=qg(R,"recall-events.json");function pr(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))}})(),Oe(e.threadId),Oe(n);let r=Ae(n);if(!r)throw new Error("split destination disappeared");return r}function ua(e){let t=Ae(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();he();y();D();import{writeFileSync as ef}from"node:fs";import{join as tf}from"node:path";var sf=tf(R,"recall-events.json");function mr(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),Vg()}function Vg(){$();let t=_().prepare("SELECT id, session_id, recalled_at, token_count, mode, caller FROM recall_events ORDER BY recalled_at DESC").all();zg(Kg,JSON.stringify(t,null,2)+`
1007
- `,"utf-8")}function Zg(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 Qg(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(` ${H(n.id)} ${n.name}
1010
- `);return null}function da(e,t,s){let n=e.prepare(`SELECT s.id, p.name AS project_name, p.decoded_path,
1006
+ `).run(e,t,s,n),nf()}function nf(){P();let t=_().prepare("SELECT id, session_id, recalled_at, token_count, mode, caller FROM recall_events ORDER BY recalled_at DESC").all();ef(sf,JSON.stringify(t,null,2)+`
1007
+ `,"utf-8")}function rf(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 of(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 af(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 pa(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 Wi(n,r,{mode:o,includeSidechain:s.subagents===!0,prelude:s.prelude??null,since:Qg(s.since)})}async function ua(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=la(a);if(d.length===0){process.stderr.write(`thread ${i} has no linked sessions
1020
- `),process.exitCode=1;return}for(let c=0;c<d.length;c+=1){let u=d[c],p=da(s,u,{...t,prelude:c===0?t.prelude:void 0});if(p===null){process.exitCode=1;continue}c>0&&process.stdout.write(`
1017
+ ORDER BY COALESCE(timestamp, ''), rowid`).all(t),o=s.full?"full":"condensed";return Ji(n,r,{mode:o,includeSidechain:s.subagents===!0,prelude:s.prelude??null,since:of(s.since)})}async function ma(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=af(s,i);if(!a){process.stderr.write(`thread not found: ${i}
1019
+ `),process.exitCode=1;return}let d=ua(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=pa(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
- `),pr(u,Math.ceil(p.length/4),"thread","cli")}return}let n=Zg(s,e);if(!n){e.length>=32&&process.stderr.write(`session not found: ${e}
1026
- `),process.exitCode=1;return}let r=da(s,n,t);if(r===null){process.exitCode=1;return}process.stdout.write(r),r.endsWith(`
1025
+ `),mr(u,Math.ceil(p.length/4),"thread","cli")}return}let n=rf(s,e);if(!n){e.length>=32&&process.stderr.write(`session not found: ${e}
1026
+ `),process.exitCode=1;return}let r=pa(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";pr(n,Math.ceil(r.length/4),o,"cli"),process.stderr.isTTY&&process.stderr.write(`\x1B[2mShare this recall? \u2192 recall share\x1B[0m
1029
- `)}he();Ze();import{join as tf}from"node:path";import{spawn as sf}from"node:child_process";async function pa(e={}){await Ne("MCP server");let t=tf(le(),"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()})})}y();import{execSync as mr}from"node:child_process";import{randomUUID as nf}from"node:crypto";import rf from"node:readline/promises";v();async function ma(e){if(e.list){of();return}if(e.purge){af(e.purge);return}let t=await cf();t||(process.stderr.write(l.err(`clipboard empty / nothing on stdin
1030
- `)),process.exit(1));let s=Wt(t);if(s.length>0&&!e.force){process.stderr.write(l.warn(`\u26A0 detected ${s.length} possible secret${s.length===1?"":"s"} in content:
1031
- `));for(let a of s.slice(0,8))process.stderr.write(` ${l.err(a.pattern)} ${l.dim("\u2192")} ${a.maskedPreview}
1032
- `);s.length>8&&process.stderr.write(l.dim(` \u2026 ${s.length-8} more
1033
- `)),e.dryRun&&(process.stderr.write(l.dim(`
1028
+ `);let o=t.since?"since":t.full?"full":"condensed";mr(n,Math.ceil(r.length/4),o,"cli"),process.stderr.isTTY&&process.stderr.write(`\x1B[2mShare this recall? \u2192 recall share\x1B[0m
1029
+ `)}he();et();import{join as cf}from"node:path";import{spawn as lf}from"node:child_process";async function ga(e={}){await Ne("MCP server");let t=cf(le(),"dist","mcp-server.js"),s={...process.env};e.allowWrites&&(s.RECALL_MCP_ALLOW_WRITES="1");let n=lf(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()})})}y();import{execSync as gr}from"node:child_process";import{randomUUID as df}from"node:crypto";import uf from"node:readline/promises";v();async function fa(e){if(e.list){pf();return}if(e.purge){mf(e.purge);return}let t=await gf();t||(process.stderr.write(c.err(`clipboard empty / nothing on stdin
1030
+ `)),process.exit(1));let s=Wt(t);if(s.length>0&&!e.force){process.stderr.write(c.warn(`\u26A0 detected ${s.length} possible secret${s.length===1?"":"s"} in content:
1031
+ `));for(let a of s.slice(0,8))process.stderr.write(` ${c.err(a.pattern)} ${c.dim("\u2192")} ${a.maskedPreview}
1032
+ `);s.length>8&&process.stderr.write(c.dim(` \u2026 ${s.length-8} more
1033
+ `)),e.dryRun&&(process.stderr.write(c.dim(`
1034
1034
  (dry run \u2014 nothing archived)
1035
- `)),process.exit(1)),!process.stdin.isTTY&&!process.stderr.isTTY&&(process.stderr.write(l.err(`refusing to archive secret content in non-interactive mode. use --force to override.
1036
- `)),e.pipe&&process.stdout.write(t),process.exit(1));let o=rf.createInterface({input:process.stdin,output:process.stderr}),i=await o.question(l.accent("archive anyway? [y/N] "));o.close(),i.trim().toLowerCase()!=="y"&&(process.stderr.write(l.dim(`cancelled \u2014 nothing archived.
1037
- `)),e.pipe&&process.stdout.write(t),process.exit(0))}e.dryRun&&(process.stderr.write(l.dim(`(dry run \u2014 would archive ${t.length.toLocaleString()} chars)
1038
- `)),e.pipe&&process.stdout.write(t),process.exit(0));let n=nf(),r=new Date().toISOString();_().prepare(`INSERT INTO paste_archives (id, created_at, content, size_bytes, source, label)
1039
- VALUES (?, ?, ?, ?, ?, ?)`).run(n,r,t,Buffer.byteLength(t,"utf8"),e.pipe?"cli-piped":"cli",e.label??null),process.stderr.write(l.ok(`\u2713 archived ${t.length.toLocaleString()} chars as ${n.slice(0,8)}
1040
- `)),e.label&&process.stderr.write(l.dim(` label: ${e.label}
1041
- `)),process.stderr.write(l.dim(` purge any time with: recall paste --purge ${n.slice(0,8)}
1042
- `)),e.pipe&&process.stdout.write(t)}function of(){let e=_().prepare(`SELECT id, created_at, size_bytes, source, label,
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.
1036
+ `)),e.pipe&&process.stdout.write(t),process.exit(1));let o=uf.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.
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)
1038
+ `)),e.pipe&&process.stdout.write(t),process.exit(0));let n=df(),r=new Date().toISOString();_().prepare(`INSERT INTO paste_archives (id, created_at, content, size_bytes, source, label)
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)}
1040
+ `)),e.label&&process.stderr.write(c.dim(` label: ${e.label}
1041
+ `)),process.stderr.write(c.dim(` purge any time with: recall paste --purge ${n.slice(0,8)}
1042
+ `)),e.pipe&&process.stdout.write(t)}function pf(){let e=_().prepare(`SELECT id, created_at, size_bytes, source, label,
1043
1043
  substr(replace(replace(content, char(10), '\u21B5'), char(13), ''), 1, 80) AS preview
1044
1044
  FROM paste_archives
1045
1045
  ORDER BY created_at DESC
1046
- LIMIT 100`).all();if(e.length===0){process.stdout.write(l.dim("no pastes archived yet. use `pbpaste | recall paste` to archive.\n"));return}process.stdout.write(`
1047
- ${l.bold(`${e.length} archived paste${e.length===1?"":"s"}`)}
1048
- `),process.stdout.write(l.dim(`\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
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?` ${l.project(t.label)}`:"";process.stdout.write(` ${l.accent(t.id.slice(0,8))} ${l.dim(W(t.created_at).padEnd(12))} ${s.padStart(6)}${n} ${l.dim(t.preview)}
1050
- `)}process.stdout.write(l.dim(`
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(`
1047
+ ${c.bold(`${e.length} archived paste${e.length===1?"":"s"}`)}
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
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(X(t.created_at).padEnd(12))} ${s.padStart(6)}${n} ${c.dim(t.preview)}
1050
+ `)}process.stdout.write(c.dim(`
1051
1051
  show full content: recall paste --show <id>
1052
- `)+l.dim(`purge one (permanent): recall paste --purge <id>
1052
+ `)+c.dim(`purge one (permanent): recall paste --purge <id>
1053
1053
 
1054
- `))}function af(e){e.length<8&&(process.stderr.write(l.err(`provide at least 8 characters of the paste id to purge.
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(l.err(`no paste matches ${e}
1056
- `)),process.exit(1)),s.length>1&&(process.stderr.write(l.err(`prefix ${e} is ambiguous. be more specific.
1057
- `)),process.exit(1)),t.prepare("DELETE FROM paste_archives WHERE id = ?").run(s[0].id),process.stderr.write(l.ok(`\u2713 purged ${s[0].id.slice(0,8)} \u2014 content permanently destroyed
1058
- `))}async function cf(){if(!process.stdin.isTTY)return await lf();try{return mr("pbpaste",{encoding:"utf8",maxBuffer:16*1024*1024})}catch{}try{return mr("xclip -o -selection clipboard",{encoding:"utf8",maxBuffer:16*1024*1024})}catch{}try{return mr("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 lf(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(t));return Buffer.concat(e).toString("utf8")}y();v();async function ga(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
1054
+ `))}function mf(e){e.length<8&&(process.stderr.write(c.err(`provide at least 8 characters of the paste id to purge.
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}
1056
+ `)),process.exit(1)),s.length>1&&(process.stderr.write(c.err(`prefix ${e} is ambiguous. be more specific.
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
1058
+ `))}async function gf(){if(!process.stdin.isTTY)return await ff();try{return gr("pbpaste",{encoding:"utf8",maxBuffer:16*1024*1024})}catch{}try{return gr("xclip -o -selection clipboard",{encoding:"utf8",maxBuffer:16*1024*1024})}catch{}try{return gr("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")}y();v();async function _a(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
1059
1059
  FROM messages
1060
- WHERE content_text IS NOT NULL`).all(),d=t.prepare("UPDATE messages SET content_text = ?, raw_json = ? WHERE uuid = ?"),c=(g,h)=>{let E=Wt(g);if(E.length===0)return!1;for(let b of E){let S=s.get(b.pattern)??{pattern:b.pattern,severity:b.severity,hits:0,sessions:new Set};S.hits+=1,S.sessions.add(h),s.set(b.pattern,S)}return!0};process.stdout.write(l.dim(`Scanning ${a.length.toLocaleString()} messages\u2026
1061
- `));for(let g of a)if(n+=1,(c(g.content_text??"",g.session_id)||c(g.raw_json??"",g.session_id))&&(r+=1,i.add(g.session_id),e.verbose&&process.stderr.write(l.dim(` hit in session ${g.session_id.slice(0,8)} message ${g.uuid.slice(0,8)}
1060
+ WHERE content_text IS NOT NULL`).all(),d=t.prepare("UPDATE messages SET content_text = ?, raw_json = ? WHERE uuid = ?"),l=(g,h)=>{let E=Wt(g);if(E.length===0)return!1;for(let b of E){let S=s.get(b.pattern)??{pattern:b.pattern,severity:b.severity,hits:0,sessions:new Set};S.hits+=1,S.sessions.add(h),s.set(b.pattern,S)}return!0};process.stdout.write(c.dim(`Scanning ${a.length.toLocaleString()} messages\u2026
1061
+ `));for(let g of a)if(n+=1,(l(g.content_text??"",g.session_id)||l(g.raw_json??"",g.session_id))&&(r+=1,i.add(g.session_id),e.verbose&&process.stderr.write(c.dim(` hit in session ${g.session_id.slice(0,8)} message ${g.uuid.slice(0,8)}
1062
1062
  `)),e.redact)){let E=ye(g.content_text??"").redacted,b=g.raw_json?ye(g.raw_json).redacted:null;d.run(E,b,g.uuid),o+=1}let u=t.prepare(`SELECT id, first_user_message FROM sessions
1063
1063
  WHERE first_user_message IS NOT NULL`).all(),p=t.prepare("UPDATE sessions SET first_user_message = ? WHERE id = ?"),m=0;for(let g of u)Wt(g.first_user_message).length>0&&(i.add(g.id),e.redact&&(p.run(ye(g.first_user_message).redacted,g.id),m+=1));if(process.stdout.write(`
1064
- `),s.size===0){process.stdout.write(l.ok(`\u2713 clean \u2014 no secrets detected across ${n.toLocaleString()} messages.
1065
- `));return}let f=[...s.values()].sort((g,h)=>h.hits-g.hits);process.stdout.write(l.warn(`\u26A0 ${r.toLocaleString()} message${r===1?"":"s"} across ${i.size.toLocaleString()} session${i.size===1?"":"s"} contain detected secrets.
1064
+ `),s.size===0){process.stdout.write(c.ok(`\u2713 clean \u2014 no secrets detected across ${n.toLocaleString()} messages.
1065
+ `));return}let f=[...s.values()].sort((g,h)=>h.hits-g.hits);process.stdout.write(c.warn(`\u26A0 ${r.toLocaleString()} message${r===1?"":"s"} across ${i.size.toLocaleString()} session${i.size===1?"":"s"} contain detected secrets.
1066
1066
 
1067
- `)),process.stdout.write(l.bold(` Pattern Hits Sessions
1068
- `)),process.stdout.write(l.dim(` \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1069
- `));for(let g of f){let h=g.severity==="high"?l.err("\u25CF"):l.warn("\u25CF");process.stdout.write(` ${h} ${g.pattern.padEnd(30)} ${String(g.hits).padStart(5)} ${String(g.sessions.size).padStart(4)}
1067
+ `)),process.stdout.write(c.bold(` Pattern Hits Sessions
1068
+ `)),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\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
1069
+ `));for(let g of f){let h=g.severity==="high"?c.err("\u25CF"):c.warn("\u25CF");process.stdout.write(` ${h} ${g.pattern.padEnd(30)} ${String(g.hits).padStart(5)} ${String(g.sessions.size).padStart(4)}
1070
1070
  `)}process.stdout.write(`
1071
- `),e.redact?(process.stdout.write(l.ok(`\u2713 redacted in place: ${o.toLocaleString()} messages, ${m.toLocaleString()} session previews.
1072
- `)),process.stdout.write(l.dim(` (The source JSONL files at ~/.claude/projects/ were not modified.)
1073
- `))):process.stdout.write(l.dim(" Rerun with --redact to scrub these in place, or run `recall index --force`.\n"))}y();v();import{basename as df}from"node:path";async function _a(e){let t=_(),s=await uf(t,e.project);if(!s){console.error(l.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,
1071
+ `),e.redact?(process.stdout.write(c.ok(`\u2713 redacted in place: ${o.toLocaleString()} messages, ${m.toLocaleString()} session previews.
1072
+ `)),process.stdout.write(c.dim(` (The source JSONL files at ~/.claude/projects/ were not modified.)
1073
+ `))):process.stdout.write(c.dim(" Rerun with --redact to scrub these in place, or run `recall index --force`.\n"))}y();v();import{basename as _f}from"node:path";async function Ea(e){let t=_(),s=await hf(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,
1074
1074
  s.auto_title,
1075
1075
  s.auto_title_source,
1076
1076
  CASE WHEN sa.session_id IS NOT NULL THEN 1 ELSE 0 END AS has_alias
1077
1077
  FROM sessions s
1078
1078
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1079
1079
  WHERE s.project_id = ?
1080
- ORDER BY s.started_at`).all(s.id);if(n.length===0){console.error(l.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=di(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=di(p);r[m]+=1,o.push({id:u.id,quality:m})}if(!e.dryRun){let u=t.prepare(`UPDATE sessions
1081
1081
  SET title_quality = ?,
1082
1082
  title_quality_computed_at = ?
1083
- WHERE id = ?`),p=Date.now();t.transaction(f=>{for(let g of f)u.run(g.quality,p,g.id)})(o)}if(e.json){console.log(JSON.stringify({project:s.name,project_id:s.id,total_sessions:n.length,dry_run:!!e.dryRun,counts:r},null,2));return}let i=n.length;console.log(""),console.log(l.project(`Title quality audit \u2014 project ${l.bold(s.name)}`)),s.decoded_path&&console.log(l.dim(` ${s.decoded_path}`)),console.log(l.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),f=pf(p,i);console.log(` ${u.padEnd(d)} ${l.bold(String(p).padStart(5))} ${m}% ${f}`)}console.log("");let c=r.template_pending+r.programmatic+r.recursive_meta+r.low_signal;if(c>0){let u=(c/i*100).toFixed(1);console.log(l.dim(` ${c} sessions (${u}%) eligible for cleanup phases L1/L3/L4.`))}else console.log(l.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(df(s));return r||null}var fa=28;function pf(e,t){let s=Math.round(e/t*fa);return l.dim("\u2588".repeat(s)+"\xB7".repeat(fa-s))}_t();v();y();vn();y();_t();import{readFileSync as hf,existsSync as fr,statSync as Ef,readdirSync as bf}from"node:fs";import{join as As}from"node:path";import{homedir as Sf}from"node:os";var qt=["vscode","cursor","windsurf"],wf={vscode:"Code",cursor:"Cursor",windsurf:"Windsurf"};var yf=.7,Tf=300*1e3;function Rf(e){let t=e?.homeDir??Sf(),s=e?.sources??qt,n=[];for(let r of s){let o=As(t,"Library","Application Support",wf[r],"User","workspaceStorage");fr(o)&&n.push({source:r,root:o})}return n}function xf(e,t){let s=As(e,"workspace.json"),n=As(e,"state.vscdb");if(!fr(s)||!fr(n))return[];let r;try{let d=JSON.parse(hf(s,"utf8"));if(!d.folder||!d.folder.startsWith("file://"))return[];r=decodeURIComponent(d.folder.replace(/^file:\/\//,""))}catch{return[]}let o;try{o=Ef(n).mtime.toISOString()}catch{return[]}let i;try{i=new gs(n,{readonly:!0})}catch{return[]}let a=[];try{let d=i.prepare("SELECT value FROM ItemTable WHERE key = 'terminal.integrated.bufferState' LIMIT 1").get(),c={};if(d?.value)try{c=JSON.parse(d.value)}catch{}let u=c.state??[];if(u.length===0)a.push({workspace_path:r,workspace_storage_dir:e,tab_name:null,cwd_hint:null,last_seen_at:o,source:t});else for(let p of u){let m=p.shellLaunchConfig??{},f=typeof m.name=="string"?m.name.trim():"";a.push({workspace_path:r,workspace_storage_dir:e,tab_name:f||null,cwd_hint:typeof m.cwd=="string"?m.cwd:null,last_seen_at:o,source:t})}}finally{i.close()}return a}function kf(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)<=Tf&&(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 Cf=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 Lf(e){return Cf.has(e.trim().toLowerCase())}function Nf(e){let t=e.tab_name?.trim();return!t||Lf(t)?null:t}function ba(e){let t=e?.minScore??yf,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(f=>{for(let g of f)u.run(g.quality,p,g.id)})(o)}if(e.json){console.log(JSON.stringify({project:s.name,project_id:s.id,total_sessions:n.length,dry_run:!!e.dryRun,counts:r},null,2));return}let i=n.length;console.log(""),console.log(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),f=Ef(p,i);console.log(` ${u.padEnd(d)} ${c.bold(String(p).padStart(5))} ${m}% ${f}`)}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 hf(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(_f(s));return r||null}var ha=28;function Ef(e,t){let s=Math.round(e/t*ha);return c.dim("\u2588".repeat(s)+"\xB7".repeat(ha-s))}ht();v();y();vn();y();ht();import{readFileSync as Tf,existsSync as _r,statSync as Rf,readdirSync as xf}from"node:fs";import{join as As}from"node:path";import{homedir as kf}from"node:os";var qt=["vscode","cursor","windsurf"],Cf={vscode:"Code",cursor:"Cursor",windsurf:"Windsurf"};var Lf=.7,Nf=300*1e3;function Of(e){let t=e?.homeDir??kf(),s=e?.sources??qt,n=[];for(let r of s){let o=As(t,"Library","Application Support",Cf[r],"User","workspaceStorage");_r(o)&&n.push({source:r,root:o})}return n}function Af(e,t){let s=As(e,"workspace.json"),n=As(e,"state.vscdb");if(!_r(s)||!_r(n))return[];let r;try{let d=JSON.parse(Tf(s,"utf8"));if(!d.folder||!d.folder.startsWith("file://"))return[];r=decodeURIComponent(d.folder.replace(/^file:\/\//,""))}catch{return[]}let o;try{o=Rf(n).mtime.toISOString()}catch{return[]}let i;try{i=new gs(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??{},f=typeof m.name=="string"?m.name.trim():"";a.push({workspace_path:r,workspace_storage_dir:e,tab_name:f||null,cwd_hint:typeof m.cwd=="string"?m.cwd:null,last_seen_at:o,source:t})}}finally{i.close()}return a}function vf(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)<=Nf&&(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 If=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 Mf(e){return If.has(e.trim().toLowerCase())}function Df(e){let t=e.tab_name?.trim();return!t||Mf(t)?null:t}function wa(e){let t=e?.minScore??Lf,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
1084
1084
  FROM sessions s
1085
1085
  JOIN projects p ON p.id = s.project_id
1086
1086
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1087
- WHERE (sa.alias IS NULL OR sa.alias = '')${r}`).all(...o),a=e?.sources??qt,d=Rf({sources:a,homeDir:e?.homeDir}),c=[];for(let{source:p,root:m}of d){let f;try{f=bf(m)}catch{continue}for(let g of f){let h=As(m,g);c.push(...xf(h,p))}}if(c.length===0)return[];let u=[];for(let p of i){let m=null;for(let g of c){let{score:h,matchedOn:E}=kf(p,g);h<t||(!m||h>m.score)&&(m={entry:g,score:h,matched:E})}if(!m)continue;let f=Nf(m.entry);f&&u.push({session_id:p.id,proposed_alias:f,score:m.score,evidence:{source:m.entry.source,workspace_path:m.entry.workspace_path,workspace_storage_dir:m.entry.workspace_storage_dir,tab_name:m.entry.tab_name,cwd_hint:m.entry.cwd_hint,last_seen_at:m.entry.last_seen_at,matched_on:m.matched}})}return u.sort((p,m)=>m.score-p.score||p.session_id.localeCompare(m.session_id)),typeof s=="number"&&s>=0&&u.length>s?u.slice(0,s):u}function Sa(e){let t=[],s=[];for(let n of e){let r=Os(n.session_id);if(r&&r.trim()!==""){s.push(n);continue}t.push(n)}return{applicable:t,skipped:s}}import{basename as Of}from"node:path";async function ya(e){let t=vf(e.source);if(!t){console.error(l.err("Invalid --source. Allowed: vscode | cursor | windsurf | all (default).")),process.exitCode=1;return}let s=If(e.minScore,.7);if(s===null||s<0||s>1){console.error(l.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(l.err("Invalid --limit. Must be a non-negative integer.")),process.exitCode=1;return}let r=e.project?Mf(e.project):void 0;if(e.project&&r===null){console.error(l.err(`No project found matching "${e.project}". Run \`recall projects\`.`)),process.exitCode=1;return}let o=ba({projectId:r??void 0,sources:t,minScore:s,limit:n}),{applicable:i,skipped:a}=Sa(o);if(e.apply){let d=0;for(let c of i)try{Ot(c.session_id,c.proposed_alias),d+=1}catch(u){console.error(l.err(`apply failed for ${c.session_id.slice(0,8)}: ${u.message}`))}if(e.json){console.log(JSON.stringify({mode:"apply",sources:t,min_score:s,project_id:r??null,applied:d,skipped:a.length,proposals:i.map(wa)},null,2));return}console.log(""),console.log(l.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(wa),skipped_due_to_existing_alias:a.length},null,2));return}Af(i,t,s,a.length)}function Af(e,t,s,n){if(console.log(""),console.log(l.project(`recall import-vscode-state \xB7 sources=${t.join("+")} min-score=${s.toFixed(2)} \xB7 DRY RUN`)),console.log(l.dim(" Pass --apply to write proposals via setAlias().")),console.log(""),e.length===0){console.log(l.warn(" No proposals \u2014 either no matching workspaces or every candidate session already has an alias.")),n>0&&console.log(l.dim(` ${n} sessions were skipped because they already have aliases.`)),console.log("");return}for(let r of e){let o=l.bold(r.session_id.slice(0,8)),i=l.bold(r.score.toFixed(2)),a=l.dim(`[${r.evidence.source}]`),d=r.evidence.matched_on.join("+");console.log(` ${o} score=${i} ${a} matched=${d}`),console.log(` proposed alias: ${l.bold(r.proposed_alias)}`),console.log(` workspace: ${l.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: ${l.dim(q(r.evidence.cwd_hint,70))}`),console.log(` last seen: ${l.dim(r.evidence.last_seen_at)}`),console.log("")}console.log(l.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 wa(e){return e}function vf(e){if(!e||e==="all")return qt;let t=e.split(",").map(n=>n.trim().toLowerCase()).filter(Boolean),s=[];for(let n of t)if(qt.includes(n))s.push(n);else return null;return s.length>0?s:null}function If(e,t){if(e===void 0)return t;let s=Number.parseFloat(e);return Number.isFinite(s)?s:null}function Mf(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=Of(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}y();import{existsSync as Ta,mkdirSync as Df,readFileSync as $f,writeFileSync as Pf}from"node:fs";import{homedir as jf}from"node:os";import{join as Ra}from"node:path";import{z as Fe}from"zod";function xa(){return process.env.RECALL_HOME??Ra(jf(),".recall")}function Ff(){let e=xa();Ta(e)||Df(e,{recursive:!0})}function ka(){return Ra(xa(),"config.json")}var Ca=Fe.object({enabled:Fe.boolean().default(!1),model:Fe.string().optional(),ratePerMinute:Fe.number().int().min(1).max(600).default(30),lastProcessedSessionId:Fe.string().nullable().default(null),backfillPaused:Fe.boolean().default(!1),autoExtractEnabled:Fe.boolean().default(!1),autoExtractIntervalMinutes:Fe.number().int().min(5).max(720).default(60),autoExtractBatchSize:Fe.number().int().min(1).max(20).default(1),autoResumeWorker:Fe.boolean().default(!1)}),vs={enabled:!1,ratePerMinute:30,lastProcessedSessionId:null,backfillPaused:!1,autoExtractEnabled:!1,autoExtractIntervalMinutes:60,autoExtractBatchSize:1,autoResumeWorker:!1};function La(){let e=ka();if(!Ta(e))return{};try{return JSON.parse($f(e,"utf8"))}catch(t){return console.error("[semantic-config] failed to parse config.json, using defaults:",t),{}}}function ve(){let e=La().semantic;if(!e)return{...vs};let t=Ca.safeParse({...vs,...e});return t.success?t.data:{...vs}}function Ue(e){Ff();let t=La(),s=Ca.parse({...vs,...t.semantic??{},...e}),n={...t,semantic:s};return Pf(ka(),JSON.stringify(n,null,2)),Uf(s.enabled),s}function Uf(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}`)}}y();Be();import{existsSync as a_,mkdirSync as c_,writeFileSync as l_}from"node:fs";import{homedir as d_}from"node:os";import{join as hr}from"node:path";var u_=1,p_=12e3,m_=3,g_=[];function f_(){return process.env.RECALL_HOME??hr(d_(),".recall")}function Ha(){return hr(f_(),"semantic")}function __(){let e=Ha();a_(e)||c_(e,{recursive:!0})}function h_(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??qt,d=Of({sources:a,homeDir:e?.homeDir}),l=[];for(let{source:p,root:m}of d){let f;try{f=xf(m)}catch{continue}for(let g of f){let h=As(m,g);l.push(...Af(h,p))}}if(l.length===0)return[];let u=[];for(let p of i){let m=null;for(let g of l){let{score:h,matchedOn:E}=vf(p,g);h<t||(!m||h>m.score)&&(m={entry:g,score:h,matched:E})}if(!m)continue;let f=Df(m.entry);f&&u.push({session_id:p.id,proposed_alias:f,score:m.score,evidence:{source:m.entry.source,workspace_path:m.entry.workspace_path,workspace_storage_dir:m.entry.workspace_storage_dir,tab_name:m.entry.tab_name,cwd_hint:m.entry.cwd_hint,last_seen_at:m.entry.last_seen_at,matched_on:m.matched}})}return u.sort((p,m)=>m.score-p.score||p.session_id.localeCompare(m.session_id)),typeof s=="number"&&s>=0&&u.length>s?u.slice(0,s):u}function ya(e){let t=[],s=[];for(let n of e){let r=Os(n.session_id);if(r&&r.trim()!==""){s.push(n);continue}t.push(n)}return{applicable:t,skipped:s}}import{basename as $f}from"node:path";async function Ra(e){let t=jf(e.source);if(!t){console.error(c.err("Invalid --source. Allowed: vscode | cursor | windsurf | all (default).")),process.exitCode=1;return}let s=Ff(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?Uf(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=wa({projectId:r??void 0,sources:t,minScore:s,limit:n}),{applicable:i,skipped:a}=ya(o);if(e.apply){let d=0;for(let l of i)try{Ot(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(Ta)},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(Ta),skipped_due_to_existing_alias:a.length},null,2));return}Pf(i,t,s,a.length)}function Pf(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 Ta(e){return e}function jf(e){if(!e||e==="all")return qt;let t=e.split(",").map(n=>n.trim().toLowerCase()).filter(Boolean),s=[];for(let n of t)if(qt.includes(n))s.push(n);else return null;return s.length>0?s:null}function Ff(e,t){if(e===void 0)return t;let s=Number.parseFloat(e);return Number.isFinite(s)?s:null}function Uf(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=$f(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}y();import{existsSync as xa,mkdirSync as Bf,readFileSync as Hf,writeFileSync as Wf}from"node:fs";import{homedir as Xf}from"node:os";import{join as ka}from"node:path";import{z as Fe}from"zod";function Ca(){return process.env.RECALL_HOME??ka(Xf(),".recall")}function Jf(){let e=Ca();xa(e)||Bf(e,{recursive:!0})}function La(){return ka(Ca(),"config.json")}var Na=Fe.object({enabled:Fe.boolean().default(!1),model:Fe.string().optional(),ratePerMinute:Fe.number().int().min(1).max(600).default(30),lastProcessedSessionId:Fe.string().nullable().default(null),backfillPaused:Fe.boolean().default(!1),autoExtractEnabled:Fe.boolean().default(!1),autoExtractIntervalMinutes:Fe.number().int().min(5).max(720).default(60),autoExtractBatchSize:Fe.number().int().min(1).max(20).default(1),autoResumeWorker:Fe.boolean().default(!1)}),vs={enabled:!1,ratePerMinute:30,lastProcessedSessionId:null,backfillPaused:!1,autoExtractEnabled:!1,autoExtractIntervalMinutes:60,autoExtractBatchSize:1,autoResumeWorker:!1};function Oa(){let e=La();if(!xa(e))return{};try{return JSON.parse(Hf(e,"utf8"))}catch(t){return console.error("[semantic-config] failed to parse config.json, using defaults:",t),{}}}function ve(){let e=Oa().semantic;if(!e)return{...vs};let t=Na.safeParse({...vs,...e});return t.success?t.data:{...vs}}function Ue(e){Jf();let t=Oa(),s=Na.parse({...vs,...t.semantic??{},...e}),n={...t,semantic:s};return Wf(La(),JSON.stringify(n,null,2)),Gf(s.enabled),s}function Gf(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}`)}}y();Be();import{existsSync as m_,mkdirSync as g_,writeFileSync as f_}from"node:fs";import{homedir as __}from"node:os";import{join as Er}from"node:path";var h_=1,E_=12e3,b_=3,S_=[];function w_(){return process.env.RECALL_HOME??Er(__(),".recall")}function Ja(){return Er(w_(),"semantic")}function y_(){let e=Ja();m_(e)||g_(e,{recursive:!0})}function T_(e){let t=_(),s=t.prepare(`SELECT s.id, s.message_count, s.first_user_message,
1089
1089
  p.name AS project,
1090
1090
  NULLIF(sa.alias, '') AS alias
1091
1091
  FROM sessions s
@@ -1094,10 +1094,10 @@ show full content: recall paste --show <id>
1094
1094
  WHERE s.id = ?`).get(e);if(!s)return null;let n=t.prepare(`SELECT role, content_text
1095
1095
  FROM messages
1096
1096
  WHERE session_id = ? AND is_sidechain = 0
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 c=d.length>1500?d.slice(0,1500)+"\u2026":d,u=`${a}: ${c}`;if(o+u.length>p_)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>E_)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(`
1098
1098
 
1099
- `),messageCount:s.message_count}}function E_(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 b_(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(c=>typeof c=="string").map(c=>c.trim().toLowerCase()).filter(c=>c.length>0&&c.length<64);return!i||d.length===0?null:{summary:i,keywords:Array.from(new Set(d)).slice(0,20)}}catch{return null}}function S_(e){let t=_(),s=e.keywords.join(",");t.prepare(`INSERT INTO session_semantic
1099
+ `),messageCount:s.message_count}}function R_(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 x_(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
1101
1101
  (session_id, summary, keywords, model, source_message_count, generated_at)
1102
1102
  VALUES (@session_id, @summary, @keywords, @model, @source_message_count, @generated_at)
1103
1103
  ON CONFLICT(session_id) DO UPDATE SET
@@ -1105,23 +1105,23 @@ show full content: recall paste --show <id>
1105
1105
  keywords = excluded.keywords,
1106
1106
  model = excluded.model,
1107
1107
  source_message_count = excluded.source_message_count,
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}),__();let n=hr(Ha(),`${e.sessionId}.json`);l_(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 Ms=null;function w_(){let t=ve().ratePerMinute,s=t/6e4;return(!Ms||Ms.capacity!==t)&&(Ms={tokens:t,capacity:t,refillPerMs:s,lastRefill:Date.now()}),Ms}function y_(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 T_(e){for(;;){if(e?.aborted)throw new Error("aborted");let t=w_();if(y_(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 R_(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=h_(e);if(!n)return{sessionId:e,ok:!1,reason:"session-not-found"};if(n.messageCount<m_)return{sessionId:e,ok:!1,reason:"too-short"};if(!n.excerpt.trim())return{sessionId:e,ok:!1,reason:"empty-excerpt"};await T_(t.signal);let r=E_(n),o=await ht(r,g_,{model:s.model});if(!o.success)return{sessionId:e,ok:!1,reason:`claude-cli-exit-${o.exitCode??"null"}`,model:s.model??null};let i=b_(o.stdout);return i?(S_({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 Ds(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}),y_();let n=Er(Ja(),`${e.sessionId}.json`);f_(n,JSON.stringify({version:h_,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 Ms=null;function C_(){let t=ve().ratePerMinute,s=t/6e4;return(!Ms||Ms.capacity!==t)&&(Ms={tokens:t,capacity:t,refillPerMs:s,lastRefill:Date.now()}),Ms}function L_(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 N_(e){for(;;){if(e?.aborted)throw new Error("aborted");let t=C_();if(L_(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 O_(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=T_(e);if(!n)return{sessionId:e,ok:!1,reason:"session-not-found"};if(n.messageCount<b_)return{sessionId:e,ok:!1,reason:"too-short"};if(!n.excerpt.trim())return{sessionId:e,ok:!1,reason:"empty-excerpt"};await N_(t.signal);let r=R_(n),o=await Et(r,S_,{model:s.model});if(!o.success)return{sessionId:e,ok:!1,reason:`claude-cli-exit-${o.exitCode??"null"}`,model:s.model??null};let i=x_(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 Ds(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
1109
1109
  FROM sessions s
1110
1110
  LEFT JOIN session_semantic ss ON ss.session_id = s.id
1111
1111
  WHERE ${o}
1112
1112
  ORDER BY COALESCE(s.started_at, '') ASC, s.id ASC
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 R_(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 Wa(){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();js();et();y();et();y();function Ka(e){return e.replace(/```json[\s\S]*?```/g,"[tool-call]").replace(/\{[\s\S]{200,}?\}/g,"[json-object]")}function P_(e){let t=[],o=0;for(;o<e.length;){let i=[],a=0;for(;i.length<5&&o<e.length;){let c=e[o],u=Ka(c.content_text??"");if(a+u.length>2e3&&i.length>=3)break;i.push(c),a+=u.length,o++}if(i.length===0)break;let d=i.map(c=>{let u=c.role??"system",p=Ka(c.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 O_(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 Ga(){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();js();st();y();st();y();function Qa(e){return e.replace(/```json[\s\S]*?```/g,"[tool-call]").replace(/\{[\s\S]{200,}?\}/g,"[json-object]")}function X_(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=Qa(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=Qa(l.content_text??"");return`[${u}] ${p}`}).join(`
1114
1114
 
1115
- `);t.push({messageUuids:i.map(c=>c.uuid),text:d}),o<e.length&&i.length>=3&&(o=Math.max(o-1,o-1))}return t}function kr(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 P_(s)}var j_=!1,F_=null;var U_=new Set;function B_(){return _().prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}function Va(){return{running:j_,queueDepth:B_(),lastProcessedAt:F_,blacklistedCount:U_.size}}y();he();async function ec(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 d={enabled:!0};t.rate&&(d.ratePerMinute=Number(t.rate)),t.model&&(d.model=t.model);let c=Ue(d);console.log("Semantic search: ENABLED"),console.log(` Rate: ${c.ratePerMinute}/min`),c.model&&console.log(` Model: ${c.model}`),console.log(""),console.log("Disclosure: enabling semantic search sends condensed session"),console.log("summaries to Claude via your local `claude` CLI using your existing"),console.log("plan. New sessions are summarized on close. Run `recall semantic backfill`"),console.log("to summarize the existing archive.");return}if(s==="off"||s==="disable"){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 d=ve();if(!d.enabled){console.error("Semantic search is disabled. Run `recall semantic on` first."),process.exitCode=1;return}d.backfillPaused&&Ue({backfillPaused:!1});let c=t.limit?Math.max(1,Number(t.limit)):1e3,u=!!t.force;console.log(`Backfilling up to ${c} sessions${u?" (force)":""}\u2026`);let p=Date.now(),m=0,f=await Ds({limit:c,force:u,onProgress:h=>{if(h.processed===m)return;m=h.processed;let E=h.total>0?` (${Math.round(h.processed/h.total*100)}%)`:"";process.stdout.write(`\r ${h.processed}/${h.total}${E} ok=${h.ok} failed=${h.failed} `)}});process.stdout.write(`
1116
- `);let g=((Date.now()-p)/1e3).toFixed(1);console.log(`Done in ${g}s \u2014 processed=${f.processed} ok=${f.ok} failed=${f.failed}`);return}if(s==="install"){let{ensureTransformersInstalled:d}=await Promise.resolve().then(()=>(Qa(),Za)),c=await d();if(!c.ok){console.error("Failed to install @huggingface/transformers:"),console.error(` ${c.error}`),console.error("Vector search not enabled. Other features unaffected."),process.exitCode=1;return}c.action==="installed"&&console.log("Installed @huggingface/transformers."),Et()?console.log("Model already installed."):(console.log("Downloading bge-base-en-v1.5 (~110MB)..."),await Sr((u,p,m)=>{let f=m>0?Math.round(p/m*100):0;process.stdout.write(`\r ${u}: ${f}% `)}),process.stdout.write(`
1117
- `)),console.log("Loading embedder...");try{await Qe(),console.log("Done. Vector search is now active.")}catch(u){console.log("Model files installed."),console.log(` Embedder load skipped: ${u instanceof Error?u.message.split(`
1118
- `)[0]:String(u)}`),console.log(" Vector features remain available; runtime load happens on first use.")}return}if(s==="uninstall"){wr(),console.log("Model removed. Vector search will fall back to keyword search.");return}if(s==="auto-extract"){let d=t._autoExtractAction;if(d==="on"||d==="enable"){let c=Ue({autoExtractEnabled:!0});console.log("Auto-extract: ENABLED"),console.log(` Cadence: 1 batch every ${c.autoExtractIntervalMinutes} minutes`),console.log(` Batch size: ${c.autoExtractBatchSize} session(s) per tick`),console.log(" Honors your 5-hour Claude plan window \u2014 at 60min/1, that is"),console.log(" ~5 extractions per window, leaving 95%+ of the rate budget free."),console.log(" The daemon will start nibbling through un-extracted sessions on"),console.log(" the next tick (within 15 minutes). Status: `recall semantic status`.");return}if(d==="off"||d==="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"),!qe().loaded){if(!Et()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}await Qe()}let d=_(),c=d.prepare(`
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 Cr(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 X_(s)}var J_=!1,G_=null;var Y_=new Set;function z_(){return _().prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}function ec(){return{running:J_,queueDepth:z_(),lastProcessedAt:G_,blacklistedCount:Y_.size}}y();he();async function rc(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 f=Ue(m);console.log("Semantic search: ENABLED"),console.log(` Rate: ${f.ratePerMinute}/min`),f.model&&console.log(` Model: ${f.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 f=t.limit?Math.max(1,Number(t.limit)):1e3,g=!!t.force;console.log(`Backfilling up to ${f} sessions${g?" (force)":""}\u2026`);let h=Date.now(),E=0,b=await Ds({limit:f,force:g,onProgress:T=>{if(T.processed===E)return;E=T.processed;let x=T.total>0?` (${Math.round(T.processed/T.total*100)}%)`:"";process.stdout.write(`\r ${T.processed}/${T.total}${x} ok=${T.ok} failed=${T.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(()=>(nc(),sc)),f=await m();if(!f.ok){console.error("Failed to install @huggingface/transformers:"),console.error(` ${f.error}`),console.error("Vector search not enabled. Other features unaffected."),process.exitCode=1;return}f.action==="installed"&&console.log("Installed @huggingface/transformers."),bt()?console.log("Model already installed."):(console.log("Downloading bge-base-en-v1.5 (~110MB)..."),await wr((g,h,E)=>{let b=E>0?Math.round(h/E*100):0;process.stdout.write(`\r ${g}: ${b}% `)}),process.stdout.write(`
1117
+ `)),console.log("Loading embedder...");try{await tt(),console.log("Done. Vector search is now active.")}catch(g){console.log("Model files installed."),console.log(` Embedder load skipped: ${g instanceof Error?g.message.split(`
1118
+ `)[0]:String(g)}`),console.log(" Vector features remain available; runtime load happens on first use.")}return}if(s==="uninstall"){yr(),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 f=Ue({autoExtractEnabled:!0});console.log("Auto-extract: ENABLED"),console.log(` Cadence: 1 batch every ${f.autoExtractIntervalMinutes} minutes`),console.log(` Batch size: ${f.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"),!Ke().loaded){if(!bt()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}await tt()}let m=_(),f=m.prepare(`
1119
1119
  SELECT s.id FROM sessions s
1120
1120
  WHERE s.message_count >= 3
1121
1121
  AND NOT EXISTS (SELECT 1 FROM chunk_meta cm WHERE cm.session_id = s.id)
1122
- `).all(),u=Number(process.env.RECALL_REINDEX_MAX_CHUNKS??"0"),p=u>0?` (cap ${u} chunks/session)`:" (no cap)";console.log(`Reindexing ${c.length} sessions (skipping already-indexed)${p}...`);let m=0;for(let{id:f}of c){let g=kr(f),h=u>0?g.slice(0,u):g;if(h.length===0){m++;continue}let E=h.map(w=>w.text),b=await vt(E);d.prepare("DELETE FROM vec_chunks WHERE rowid IN (SELECT rowid FROM chunk_meta WHERE session_id = ?)").run(f),d.prepare("DELETE FROM chunk_meta WHERE session_id = ?").run(f);let S=d.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'))`),C=d.prepare("INSERT INTO vec_chunks(rowid, embedding) VALUES (?, ?)");for(let w=0;w<h.length;w++){let N=S.run(f,JSON.stringify(h[w].messageUuids),h[w].text),z=Buffer.from(b[w].buffer,b[w].byteOffset,b[w].byteLength);C.run(BigInt(N.lastInsertRowid),z)}m++,m%10===0&&process.stdout.write(`\r ${m}/${c.length} `)}process.stdout.write(`
1124
- `),console.log(`Reindexed ${m} 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:d}=await Promise.resolve().then(()=>(Be(),Is)),{homedir:c}=await import("node:os"),{join:u}=await import("node:path"),{readdirSync:p}=await import("node:fs"),m=u(c(),".claude","projects"),f=()=>{let w=new Set;try{for(let N of p(m,{withFileTypes:!0})){if(!N.isDirectory())continue;let z=u(m,N.name);for(let O of p(z,{withFileTypes:!0}))O.isFile()&&O.name.endsWith(".jsonl")&&w.add(u(z,O.name))}}catch{}return w};console.log("Snapshotting JSONL files in ~/.claude/projects/ ...");let g=f();console.log(` Before: ${g.size} JSONL file(s)`),console.log('Spawning a tiny `claude -p --no-session-persistence "ok"`...');let h=Date.now(),E=await d("Reply with the single word: ok",[],{}),b=((Date.now()-h)/1e3).toFixed(1);if(console.log(` CLI exit: ${E.exitCode}, ${b}s`),!E.success){console.error(` stderr: ${E.stderr.slice(-500)}`),console.error("FAIL: claude CLI exited non-zero. Cannot validate spawn behavior."),process.exitCode=1;return}console.log("Snapshotting again...");let S=f();console.log(` After: ${S.size} JSONL file(s)`);let C=[];for(let w of S)g.has(w)||C.push(w);if(C.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: ${C.length} new JSONL file(s) appeared despite the flag.`),console.error("Tier-1 features WILL produce phantom sessions if re-enabled.");for(let w of C.slice(0,5))console.error(` - ${w}`);C.length>5&&console.error(` ... and ${C.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=Wa();console.log(`Semantic search: ${n.enabled?"ENABLED":"disabled"}`),console.log(` claude CLI: ${n.claudeCliAvailable?"available":"NOT FOUND"}`),console.log(` Rate: ${n.ratePerMinute}/min`),console.log(` Model: ${n.model??"claude default"}`),console.log(` Sessions: ${n.processedSessions}/${n.totalSessions} summarized`),console.log(` Pending: ${n.pendingSessions}`),n.lastProcessedSessionId&&console.log(` Cursor: ${n.lastProcessedSessionId}`),n.backfillPaused&&console.log(" Backfill: PAUSED (run `recall semantic resume`)");let r=Et(),o=qe(),i=Va(),a=ve();console.log(""),console.log("Vector tier (Pro):"),console.log(` Model: ${r?"installed":"not installed"}`),console.log(` Embedder: ${o.loaded?"loaded":"not loaded"} (${o.modelId}, ${o.dim}d)`),console.log(` Worker: ${i.running?"running":"stopped"} (queue: ${i.queueDepth})`),console.log(""),console.log("Auto-extract:"),console.log(` Enabled: ${a.autoExtractEnabled?"YES":"no"}`),a.autoExtractEnabled?console.log(` Cadence: 1 batch every ${a.autoExtractIntervalMinutes} min \xD7 ${a.autoExtractBatchSize} session(s)`):console.log(" Run `recall semantic auto-extract on` to populate Patterns / Galaxy automatically."),process.env.RECALL_RRF_K&&console.log(` RRF k: ${process.env.RECALL_RRF_K}`)}y();y();y();et();var tt=400,Bs=768,Z_="bge-base-en-v1.5";function Q_(e){return Buffer.from(e.buffer,e.byteOffset,e.byteLength)}function eh(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!==Bs)throw new Error(`embedding dim mismatch: got ${e.embedding.length}, expected ${Bs}`);let t=e.embedding_model_id??Z_,s=new Date().toISOString();return _().prepare(`INSERT INTO message_embeddings
1122
+ `).all(),g=Number(process.env.RECALL_REINDEX_MAX_CHUNKS??"0"),h=g>0?` (cap ${g} chunks/session)`:" (no cap)";console.log(`Reindexing ${f.length} sessions (skipping already-indexed)${h}...`);let E=0;for(let{id:b}of f){let S=Cr(b),T=g>0?S.slice(0,g):S;if(T.length===0){E++;continue}let x=T.map($=>$.text),N=await vt(x);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 K=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'))`),O=m.prepare("INSERT INTO vec_chunks(rowid, embedding) VALUES (?, ?)");for(let $=0;$<T.length;$++){let F=K.run(b,JSON.stringify(T[$].messageUuids),T[$].text),w=Buffer.from(N[$].buffer,N[$].byteOffset,N[$].byteLength);O.run(BigInt(F.lastInsertRowid),w)}E++,E%10===0&&process.stdout.write(`\r ${E}/${f.length} `)}process.stdout.write(`
1124
+ `),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(),Is)),{homedir:f}=await import("node:os"),{join:g}=await import("node:path"),{readdirSync:h}=await import("node:fs"),E=g(f(),".claude","projects"),b=()=>{let $=new Set;try{for(let F of h(E,{withFileTypes:!0})){if(!F.isDirectory())continue;let w=g(E,F.name);for(let U of h(w,{withFileTypes:!0}))U.isFile()&&U.name.endsWith(".jsonl")&&$.add(g(w,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(),x=await m("Reply with the single word: ok",[],{}),N=((Date.now()-T)/1e3).toFixed(1);if(console.log(` CLI exit: ${x.exitCode}, ${N}s`),!x.success){console.error(` stderr: ${x.stderr.slice(-500)}`),console.error("FAIL: claude CLI exited non-zero. Cannot validate spawn behavior."),process.exitCode=1;return}console.log("Snapshotting again...");let K=b();console.log(` After: ${K.size} JSONL file(s)`);let O=[];for(let $ of K)S.has($)||O.push($);if(O.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: ${O.length} new JSONL file(s) appeared despite the flag.`),console.error("Tier-1 features WILL produce phantom sessions if re-enabled.");for(let $ of O.slice(0,5))console.error(` - ${$}`);O.length>5&&console.error(` ... and ${O.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=Ga(),r=bt(),o=Ke(),i=ec(),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}`)}y();y();y();st();var nt=400,Bs=768,ih="bge-base-en-v1.5";function ah(e){return Buffer.from(e.buffer,e.byteOffset,e.byteLength)}function ch(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!==Bs)throw new Error(`embedding dim mismatch: got ${e.embedding.length}, expected ${Bs}`);let t=e.embedding_model_id??ih,s=new Date().toISOString();return _().prepare(`INSERT INTO message_embeddings
1125
1125
  (message_uuid, session_id, embedding,
1126
1126
  embedding_model_id, embedding_dim, text_length, generated_at)
1127
1127
  VALUES (?, ?, ?, ?, ?, ?, ?)
@@ -1131,7 +1131,7 @@ show full content: recall paste --show <id>
1131
1131
  embedding_model_id = excluded.embedding_model_id,
1132
1132
  embedding_dim = excluded.embedding_dim,
1133
1133
  text_length = excluded.text_length,
1134
- generated_at = excluded.generated_at`).run(e.message_uuid,e.session_id,Q_(e.embedding),t,Bs,e.text_length,s),{message_uuid:e.message_uuid,session_id:e.session_id,embedding_model_id:t,embedding_dim:Bs,text_length:e.text_length,generated_at:s}}function th(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,ah(e.embedding),t,Bs,e.text_length,s),{message_uuid:e.message_uuid,session_id:e.session_id,embedding_model_id:t,embedding_dim:Bs,text_length:e.text_length,generated_at:s}}function lh(e,t={}){let s=_(),n=t.force?`m.session_id = ? AND m.is_sidechain = 0
1135
1135
  AND m.content_text IS NOT NULL
1136
1136
  AND length(m.content_text) > ?`:`m.session_id = ? AND m.is_sidechain = 0
1137
1137
  AND m.content_text IS NOT NULL
@@ -1141,7 +1141,7 @@ show full content: recall paste --show <id>
1141
1141
  LEFT JOIN message_embeddings me ON me.message_uuid = m.uuid
1142
1142
  WHERE ${n}
1143
1143
  ORDER BY m.timestamp ASC, m.rowid ASC
1144
- LIMIT ?`).all(e,tt,r)}var tc=null;async function sh(){return tc||(qe().loaded||await Qe(),vt)}async function nh(e,t={}){let s={embedded:0,skipped:0,failed:0,failures:[]},n=th(e,{limit:t.limit,force:t.force});if(n.length===0)return s;let r=await sh(),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{eh({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 sc(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,nt,r)}var oc=null;async function dh(){return oc||(Ke().loaded||await tt(),vt)}async function uh(e,t={}){let s={embedded:0,skipped:0,failed:0,failures:[]},n=lh(e,{limit:t.limit,force:t.force});if(n.length===0)return s;let r=await dh(),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{ch({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 ic(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
1145
1145
  FROM sessions s
1146
1146
  JOIN messages m ON m.session_id = s.id
1147
1147
  LEFT JOIN message_embeddings me ON me.message_uuid = m.uuid
@@ -1151,7 +1151,7 @@ show full content: recall paste --show <id>
1151
1151
  AND length(m.content_text) > ?
1152
1152
  AND me.message_uuid IS NULL
1153
1153
  ORDER BY s.started_at ASC
1154
- LIMIT ?`).all(...s,tt,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 nh(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 Hs(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 nc(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,nt,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 uh(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 Hs(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 ac(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
1155
1155
  COUNT(*) AS total,
1156
1156
  SUM(CASE WHEN ss.session_id IS NOT NULL THEN 1 ELSE 0 END) AS with_semantic,
1157
1157
  SUM(CASE WHEN cm_count.session_id IS NOT NULL THEN 1 ELSE 0 END) AS with_chunks,
@@ -1164,12 +1164,12 @@ show full content: recall paste --show <id>
1164
1164
  LEFT JOIN (
1165
1165
  SELECT DISTINCT session_id FROM message_embeddings
1166
1166
  ) me_count ON me_count.session_id = s.id
1167
- ${n}`).get(...r),i=o.total??0,a=o.with_semantic??0,d=o.with_chunks??0,c=o.with_msg_emb??0,u=s?" JOIN sessions s ON s.id = m.session_id WHERE s.project_id = ?":"",p=t.prepare(`SELECT
1167
+ ${n}`).get(...r),i=o.total??0,a=o.with_semantic??0,d=o.with_chunks??0,l=o.with_msg_emb??0,u=s?" JOIN sessions s ON s.id = m.session_id WHERE s.project_id = ?":"",p=t.prepare(`SELECT
1168
1168
  COUNT(*) AS total,
1169
1169
  SUM(CASE
1170
1170
  WHEN m.is_sidechain = 0
1171
1171
  AND m.content_text IS NOT NULL
1172
- AND length(m.content_text) > ${tt}
1172
+ AND length(m.content_text) > ${nt}
1173
1173
  THEN 1 ELSE 0 END) AS eligible
1174
1174
  FROM messages m
1175
1175
  ${u}`).get(...r),m=s?" JOIN sessions s ON s.id = me.session_id WHERE s.project_id = ?":"",f=t.prepare(`SELECT COUNT(*) AS embedded
@@ -1178,9 +1178,9 @@ show full content: recall paste --show <id>
1178
1178
  FROM chunk_meta cm
1179
1179
  ${g}`).get(...r),E=s?" JOIN sessions s ON s.id = cq.session_id WHERE s.project_id = ?":"",b=t.prepare(`SELECT COUNT(*) AS n
1180
1180
  FROM chunk_queue cq
1181
- ${E}`).get(...r);return{project:s,sessions:{total:i,with_semantic:a,with_semantic_pct:Hs(a,i),with_chunks:d,with_chunks_pct:Hs(d,i),with_message_embeddings:c,with_message_embeddings_pct:Hs(c,i)},messages:{total:p.total??0,eligible:p.eligible??0,embedded:f.embedded,embedded_pct:Hs(f.embedded,p.eligible??0),threshold_chars:tt},chunks:{chunk_meta_rows:h.n,chunk_queue_pending:b.n},generated_at:new Date().toISOString()}}function rc(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}}he();js();et();async function oc(e,t){let s=(e??"audit").toLowerCase();if(s==="audit")return rh(t);if(s==="backfill-summaries")return ih(t);if(s==="backfill-messages")return ah(t);console.error(`Unknown embeddings action: ${e}. Supported: audit | backfill-summaries | backfill-messages`),process.exitCode=1}function Cr(e){if(!e)return null;let t=Ee(e);return t||"not-found"}async function rh(e){let t=Cr(e.project);if(t==="not-found"){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let s=nc({projectId:t?t.id:void 0}),n=rc(s);if(e.json){console.log(JSON.stringify({report:s,verdict:n},null,2));return}oh(s,n),n.passes||(process.exitCode=1)}function oh(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 ih(e){if(!ve().enabled){console.error("Semantic search is disabled. Run `recall semantic on` first."),process.exitCode=1;return}let s=Cr(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 Ds({limit:n,projectId:s?s.id:void 0,onProgress:c=>{if(e.json||c.processed===i)return;i=c.processed;let u=c.total>0?` (${Math.round(c.processed/c.total*100)}%)`:"";process.stdout.write(`\r ${c.processed}/${c.total}${u} ok=${c.ok} failed=${c.failed} `)}});e.json||process.stdout.write(`
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 ah(e){if(await Ne("Per-message embeddings"),!Et()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}qe().loaded||await Qe();let t=Cr(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 > ${tt} chars \u2014 ${n} \u2014 up to ${s} sessions\u2026`);let r=Date.now(),o=0,i=await sc({projectId:t?t.id:void 0,limitSessions:s,onProgress:m=>{if(e.json||m.processed_sessions===o)return;o=m.processed_sessions;let f=m.total_sessions>0?` (${Math.round(m.processed_sessions/m.total_sessions*100)}%)`:"";process.stdout.write(`\r ${m.processed_sessions}/${m.total_sessions} sessions${f} embedded=${m.embedded_messages} failed=${m.failed_messages} `)}});e.json||process.stdout.write(`
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=_(),c=t?" AND s.project_id = ?":"",u=t?[t.id]:[],p=d.prepare(`SELECT COUNT(DISTINCT s.id) AS n
1181
+ ${E}`).get(...r);return{project:s,sessions:{total:i,with_semantic:a,with_semantic_pct:Hs(a,i),with_chunks:d,with_chunks_pct:Hs(d,i),with_message_embeddings:l,with_message_embeddings_pct:Hs(l,i)},messages:{total:p.total??0,eligible:p.eligible??0,embedded:f.embedded,embedded_pct:Hs(f.embedded,p.eligible??0),threshold_chars:nt},chunks:{chunk_meta_rows:h.n,chunk_queue_pending:b.n},generated_at:new Date().toISOString()}}function cc(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}}he();js();st();async function lc(e,t){let s=(e??"audit").toLowerCase();if(s==="audit")return ph(t);if(s==="backfill-summaries")return gh(t);if(s==="backfill-messages")return fh(t);console.error(`Unknown embeddings action: ${e}. Supported: audit | backfill-summaries | backfill-messages`),process.exitCode=1}function Lr(e){if(!e)return null;let t=Ee(e);return t||"not-found"}async function ph(e){let t=Lr(e.project);if(t==="not-found"){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let s=ac({projectId:t?t.id:void 0}),n=cc(s);if(e.json){console.log(JSON.stringify({report:s,verdict:n},null,2));return}mh(s,n),n.passes||(process.exitCode=1)}function mh(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 gh(e){if(!ve().enabled){console.error("Semantic search is disabled. Run `recall semantic on` first."),process.exitCode=1;return}let s=Lr(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 Ds({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 fh(e){if(await Ne("Per-message embeddings"),!bt()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}Ke().loaded||await tt();let t=Lr(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 > ${nt} chars \u2014 ${n} \u2014 up to ${s} sessions\u2026`);let r=Date.now(),o=0,i=await ic({projectId:t?t.id:void 0,limitSessions:s,onProgress:m=>{if(e.json||m.processed_sessions===o)return;o=m.processed_sessions;let f=m.total_sessions>0?` (${Math.round(m.processed_sessions/m.total_sessions*100)}%)`:"";process.stdout.write(`\r ${m.processed_sessions}/${m.total_sessions} sessions${f} embedded=${m.embedded_messages} failed=${m.failed_messages} `)}});e.json||process.stdout.write(`
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
1184
1184
  FROM sessions s
1185
1185
  JOIN messages m ON m.session_id = s.id
1186
1186
  LEFT JOIN message_embeddings me ON me.message_uuid = m.uuid
@@ -1188,7 +1188,7 @@ show full content: recall paste --show <id>
1188
1188
  AND m.content_text IS NOT NULL
1189
1189
  AND length(m.content_text) > ?
1190
1190
  AND me.message_uuid IS NULL
1191
- ${c}`).get(tt,...u);p.n>0&&console.log(` ${p.n} session(s) still have unembedded eligible messages. Re-run to continue.`)}y();import{createHash as gh}from"node:crypto";Be();y();D();import{writeFileSync as ch,readFileSync as nN,existsSync as lh,mkdirSync as dh,readdirSync as rN}from"node:fs";import{join as ic}from"node:path";var Lr=ic(R,"output-index");function uh(){$(),lh(Lr)||dh(Lr,{recursive:!0})}function Qt(e){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}function ph(e){if(!e)return null;try{return JSON.parse(e)}catch{return e}}function ac(e){return{session_id:e.session_id,files_written:Qt(e.files_written),brands_mentioned:Qt(e.brands_mentioned),terms_introduced:Qt(e.terms_introduced),plan_ids_referenced:Qt(e.plan_ids_referenced),bug_signatures:Qt(e.bug_signatures),raw_extraction:ph(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),c=Math.max(1,Math.floor(e.extractor_version??1));t.prepare(`INSERT INTO session_output_index
1191
+ ${l}`).get(nt,...u);p.n>0&&console.log(` ${p.n} session(s) still have unembedded eligible messages. Re-run to continue.`)}y();import{createHash as yh}from"node:crypto";Be();y();D();import{writeFileSync as _h,readFileSync as hN,existsSync as hh,mkdirSync as Eh,readdirSync as EN}from"node:fs";import{join as dc}from"node:path";var Nr=dc(R,"output-index");function bh(){P(),hh(Nr)||Eh(Nr,{recursive:!0})}function Qt(e){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}function Sh(e){if(!e)return null;try{return JSON.parse(e)}catch{return e}}function uc(e){return{session_id:e.session_id,files_written:Qt(e.files_written),brands_mentioned:Qt(e.brands_mentioned),terms_introduced:Qt(e.terms_introduced),plan_ids_referenced:Qt(e.plan_ids_referenced),bug_signatures:Qt(e.bug_signatures),raw_extraction:Sh(e.raw_extraction),extracted_at:e.extracted_at,extractor_version:e.extractor_version}}function pc(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
1192
1192
  (session_id, files_written, brands_mentioned, terms_introduced,
1193
1193
  plan_ids_referenced, bug_signatures, raw_extraction,
1194
1194
  extracted_at, extractor_version)
@@ -1201,7 +1201,7 @@ show full content: recall paste --show <id>
1201
1201
  bug_signatures = excluded.bug_signatures,
1202
1202
  raw_extraction = excluded.raw_extraction,
1203
1203
  extracted_at = excluded.extracted_at,
1204
- extractor_version = excluded.extractor_version`).run(e.session_id,n,r,o,i,a,d,s,c);let u=t.prepare("SELECT * FROM session_output_index WHERE session_id = ?").get(e.session_id);if(!u)throw new Error("setOutputIndex succeeded but read-back failed");let p=ac(u);return mh(e.session_id),p}function es(e){let s=_().prepare("SELECT * FROM session_output_index WHERE session_id = ?").get(e);return s?ac(s):null}function mh(e){try{uh();let t=es(e);if(!t)return;let s=ic(Lr,`${e}.json`),n={schema:"claude-recall.session-output-index.v1",backed_up_at:new Date().toISOString(),...t};ch(s,JSON.stringify(n,null,2))}catch(t){console.error("[output-index] backup failed:",t)}}var ts=1,Ar="claude-haiku-4-5-20251001",fh=3,_h=32e3,lc=2e3,hh=30,Eh=30,bh=30,Sh=30;function wh(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=uc(u);return wh(e.session_id),p}function es(e){let s=_().prepare("SELECT * FROM session_output_index WHERE session_id = ?").get(e);return s?uc(s):null}function wh(e){try{bh();let t=es(e);if(!t)return;let s=dc(Nr,`${e}.json`),n={schema:"claude-recall.session-output-index.v1",backed_up_at:new Date().toISOString(),...t};_h(s,JSON.stringify(n,null,2))}catch(t){console.error("[output-index] backup failed:",t)}}var ts=1,vr="claude-haiku-4-5-20251001",Th=3,Rh=32e3,mc=2e3,xh=30,kh=30,Ch=30,Lh=30;function Nh(e){let s=_().prepare(`SELECT s.id,
1205
1205
  NULLIF(sa.alias, '') AS alias,
1206
1206
  s.auto_title,
1207
1207
  s.auto_title_source,
@@ -1212,15 +1212,15 @@ show full content: recall paste --show <id>
1212
1212
  FROM sessions s
1213
1213
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1214
1214
  LEFT JOIN projects p ON p.id = s.project_id
1215
- WHERE s.id = ?`).get(e);return s?{...s,alias_source:s.alias?"manual":null}:null}function dc(e,t={}){if(e.message_count<fh)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=es(e.id);if(n&&n.extractor_version>=ts)return{eligible:!1,reason:"already-extracted"}}return{eligible:!0}}function yh(e){let t=wh(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 gc(e,t={}){if(e.message_count<Th)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=es(e.id);if(n&&n.extractor_version>=ts)return{eligible:!1,reason:"already-extracted"}}return{eligible:!0}}function Oh(e){let t=Nh(e);if(!t)return null;let n=_().prepare(`SELECT role, content_text
1216
1216
  FROM messages
1217
1217
  WHERE session_id = ?
1218
1218
  AND is_sidechain = 0
1219
1219
  AND content_text IS NOT NULL
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 c=d.length>lc?d.slice(0,lc)+"\u2026":d,u=`${a}: ${c}`;if(o+u.length>_h)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>mc?d.slice(0,mc)+"\u2026":d,u=`${a}: ${l}`;if(o+u.length>Rh)break;r.push(u),o+=u.length}return{meta:t,excerpt:r.join(`
1221
1221
 
1222
- `)}}function Th(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 Rh(e){return Array.isArray(e)&&e.every(t=>typeof t=="string")}function Nr(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 xh(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 kh(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 c=typeof i=="string"&&i.trim().length>0?i.trim().slice(0,256):null,u=gh("sha256").update(`${a}::${d}`).digest("hex").slice(0,12);if(s.push({error_type:a,message_hash:u,snippet:d,file:c}),s.length>=t)break}return s}function Ch(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=Nr(o.files_written,200),a=Nr(o.brands_mentioned,Eh),d=xh(o.terms_introduced,hh),c=Nr(o.plan_ids_referenced,bh),u=kh(o.bug_signatures,Sh);return i.length===0&&a.length===0&&d.length===0&&c.length===0&&u.length===0&&!Rh(o.files_written)?null:{files_written:i,brands_mentioned:a,terms_introduced:d,plan_ids_referenced:c,bug_signatures:u}}var Or=null;async function Lh(e,t){return Or?Or(e,t):ht(e,[],{model:t})}async function Nh(e,t={}){if(t.signal?.aborted)return{session_id:e,ok:!1,failed:"aborted"};let s=yh(e);if(!s)return{session_id:e,ok:!1,skipped:"session-not-found"};let n=dc(s.meta,{force:t.force});if(!n.eligible)return{session_id:e,ok:!1,skipped:n.reason};if(!Or&&!se())return{session_id:e,ok:!1,failed:"claude-cli-missing"};let r=Th(s),o=t.model??Ar,i=await Lh(r,o);if(!i.success){let u=(i.stderr||i.stdout||"").slice(0,400),p=u?ye(u).redacted:void 0;return{session_id:e,ok:!1,failed:"claude-cli-error",exit_code:i.exitCode,stderr_excerpt:p}}let a=Ch(i.stdout);if(!a){let u=i.stdout.slice(0,400),p=u?ye(u).redacted:void 0;return{session_id:e,ok:!1,failed:"parse-failed",exit_code:i.exitCode,stderr_excerpt:p}}let d=Oh(i.stdout),c=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:ts});return{session_id:e,ok:!0,index:c,usage:d}}function Oh(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 Ah(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 Ah(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 vh(e){return Array.isArray(e)&&e.every(t=>typeof t=="string")}function Or(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 Ih(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 Mh(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=yh("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 Dh(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=Or(o.files_written,200),a=Or(o.brands_mentioned,kh),d=Ih(o.terms_introduced,xh),l=Or(o.plan_ids_referenced,Ch),u=Mh(o.bug_signatures,Lh);return i.length===0&&a.length===0&&d.length===0&&l.length===0&&u.length===0&&!vh(o.files_written)?null:{files_written:i,brands_mentioned:a,terms_introduced:d,plan_ids_referenced:l,bug_signatures:u}}var Ar=null;async function $h(e,t){return Ar?Ar(e,t):Et(e,[],{model:t})}async function Ph(e,t={}){if(t.signal?.aborted)return{session_id:e,ok:!1,failed:"aborted"};let s=Oh(e);if(!s)return{session_id:e,ok:!1,skipped:"session-not-found"};let n=gc(s.meta,{force:t.force});if(!n.eligible)return{session_id:e,ok:!1,skipped:n.reason};if(!Ar&&!se())return{session_id:e,ok:!1,failed:"claude-cli-missing"};let r=Ah(s),o=t.model??vr,i=await $h(r,o);if(!i.success){let u=(i.stderr||i.stdout||"").slice(0,400),p=u?ye(u).redacted:void 0;return{session_id:e,ok:!1,failed:"claude-cli-error",exit_code:i.exitCode,stderr_excerpt:p}}let a=Dh(i.stdout);if(!a){let u=i.stdout.slice(0,400),p=u?ye(u).redacted:void 0;return{session_id:e,ok:!1,failed:"parse-failed",exit_code:i.exitCode,stderr_excerpt:p}}let d=jh(i.stdout),l=pc({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:ts});return{session_id:e,ok:!0,index:l,usage:d}}function jh(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 Fh(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,
1224
1224
  NULLIF(sa.alias, '') AS alias,
1225
1225
  s.auto_title,
1226
1226
  s.auto_title_source,
@@ -1232,13 +1232,13 @@ show full content: recall paste --show <id>
1232
1232
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1233
1233
  LEFT JOIN projects p ON p.id = s.project_id
1234
1234
  ${o}
1235
- ORDER BY COALESCE(s.started_at, ''), s.id`).all(...n),a=[],d=new Map;for(let c of i){let u={...c,alias_source:c.alias?"manual":null},p=dc(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 uc(e={}){let t=Ah({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 Nh(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 pc(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??Ar;e.json||console.log(`Extracting Output Index \u2014 project "${t.name}" \u2014 extractor v${ts} \u2014 model ${n} \u2014 up to ${s} sessions\u2026`);let r=Date.now(),o=-1,{progress:i,results:a}=await uc({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)),c=i.total>0?Math.round(i.ok/i.total*1e3)/10:0;if(e.json){let u=a.filter(p=>!p.ok&&p.failed).map(p=>({session_id:p.session_id,failed:p.failed,exit_code:p.exit_code??null}));console.log(JSON.stringify({project:t.name,extractor_version:ts,model:n,progress:i,acceptance_pct:c,failures:u.slice(0,20),elapsed_seconds:d},null,2))}else console.log(`Done in ${d}s \u2014 ok=${i.ok}/${i.total} (${c}%) failed=${i.failed} skipped=${i.skipped}`),console.log(`Token spend: input=${i.total_input_tokens} output=${i.total_output_tokens}`),i.total>0&&c<90?(console.log(` \u26A0 Phase D acceptance bar is 90% non-empty Output Index; actual ${c}%. Inspect failures and re-run.`),process.exitCode=1):i.total===0&&console.log(" \u24D8 No eligible sessions (all sessions were skipped or already extracted).")}y();ss();var Ys={citation:"same-project",similar:"same-project",skill_track:"same-project",bug_pattern:"cross-project",wiki_link:"cross-project",temporal_proximity:"same-project"},Wh=2,Xh=.25,Jh=5,Yh=60,Gh=25;function Js(e){return e.trim().toLowerCase()}function zh(e){let t=new Set;for(let s of e.files_written)t.add(`file:${Js(s)}`);for(let s of e.brands_mentioned)t.add(`brand:${Js(s)}`);for(let s of e.terms_introduced)t.add(`term:${Js(s)}`);for(let s of e.plan_ids_referenced)t.add(`plan:${Js(s)}`);return t}function qh(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/Yh);return Math.max(.2,t)}function Kh(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 Vh(e){let t=es(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 Zh(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=gc(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 fc(e={}){let t=Fh({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 Ph(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 _c(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??vr;e.json||console.log(`Extracting Output Index \u2014 project "${t.name}" \u2014 extractor v${ts} \u2014 model ${n} \u2014 up to ${s} sessions\u2026`);let r=Date.now(),o=-1,{progress:i,results:a}=await fc({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:ts,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).")}y();ss();var Gs={citation:"same-project",similar:"same-project",skill_track:"same-project",bug_pattern:"cross-project",wiki_link:"cross-project",temporal_proximity:"same-project"},Vh=2,Zh=.25,Qh=5,eE=60,tE=25;function Js(e){return e.trim().toLowerCase()}function sE(e){let t=new Set;for(let s of e.files_written)t.add(`file:${Js(s)}`);for(let s of e.brands_mentioned)t.add(`brand:${Js(s)}`);for(let s of e.terms_introduced)t.add(`term:${Js(s)}`);for(let s of e.plan_ids_referenced)t.add(`plan:${Js(s)}`);return t}function nE(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/eE);return Math.max(.2,t)}function rE(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 oE(e){let t=es(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 iE(e){return _().prepare(`SELECT s.id AS id, s.project_id AS project_id, s.started_at AS started_at
1237
1237
  FROM sessions s
1238
1238
  JOIN session_output_index oi ON oi.session_id = s.id
1239
1239
  WHERE s.project_id = ?
1240
- ORDER BY COALESCE(s.started_at, ''), s.id`).all(e)}function Qh(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=zh(i);if(a.size!==0){n.set(o.id,a);for(let d of a){let c=s.get(d);c?c.push(o.id):s.set(d,[o.id])}}}return{posting:s,vocab:n,startedAt:r}}function eE(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 c=t.startedAt.get(d);if(!c||c>=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<Wh)continue;let c=t.startedAt.get(i)??null,u=Kh(n,c),p=qh(u),m=Math.min(1,d/Jh*p);if(m<Xh)continue;let f=a.slice(0,12);o.push({target_session_id:i,matched_terms:f,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,Gh)}async function wc(e){if(Ys.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project \u2014 refusing to run inference");let t=Zh(e.projectId),s=new Map;for(let i of t){let a=Vh(i.id);a&&s.set(i.id,a)}let n=Qh(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=eE(i.id,n);for(let d of a)try{let c=st({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(c.id),r.suggestions_created+=1}catch(c){console.error("[citation-inference] createSuggestion failed:",c)}r.processed_sessions+=1,e.onProgress?.({...r})}return r.current_session_id=null,e.onProgress?.({...r}),{progress:r,suggestion_ids:o}}async function yc(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 wc({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 gE,readFileSync as fE}from"node:fs";import{join as _E}from"node:path";y();ss();var tE=/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/gi,sE=[/\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],nE=.95,rE=.85,oE=.7,Pr=50,iE=50;function aE(e){if(!e)return[];let t=new Set,s=[],n=e.match(tE);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>=Pr))break}return s}function cE(e){if(!e)return[];let t=new Set,s=[];for(let n of sE){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>=Pr))break}if(s.length>=Pr)break}}return s}function jr(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 Tc(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 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=sE(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 cE(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<Vh)continue;let l=t.startedAt.get(i)??null,u=rE(n,l),p=nE(u),m=Math.min(1,d/Qh*p);if(m<Zh)continue;let f=a.slice(0,12);o.push({target_session_id:i,matched_terms:f,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,tE)}async function xc(e){if(Gs.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project \u2014 refusing to run inference");let t=iE(e.projectId),s=new Map;for(let i of t){let a=oE(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=cE(i.id,n);for(let d of a)try{let l=rt({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 kc(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 xc({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 yE,readFileSync as TE}from"node:fs";import{join as RE}from"node:path";y();ss();var lE=/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/gi,dE=[/\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],uE=.95,pE=.85,mE=.7,jr=50,gE=50;function fE(e){if(!e)return[];let t=new Set,s=[],n=e.match(lE);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 _E(e){if(!e)return[];let t=new Set,s=[];for(let n of dE){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 Fr(e){let t=_();return typeof e=="number"?t.prepare("SELECT id, project_id FROM sessions WHERE project_id = ?").all(e):t.prepare("SELECT id, project_id FROM sessions").all()}function Cc(e){let t=_();return typeof e=="number"?t.prepare(`SELECT m.uuid AS message_uuid, m.session_id, m.content_text,
1242
1242
  s.project_id
1243
1243
  FROM messages m
1244
1244
  JOIN sessions s ON s.id = m.session_id
@@ -1251,12 +1251,12 @@ show full content: recall paste --show <id>
1251
1251
  JOIN sessions s ON s.id = m.session_id
1252
1252
  WHERE m.is_sidechain = 0
1253
1253
  AND m.content_text IS NOT NULL
1254
- AND length(m.content_text) > 0`).all()}function lE(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 hE(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,
1255
1255
  s.project_id AS project_id,
1256
1256
  oi.plan_ids_referenced AS plan_ids_json
1257
1257
  FROM session_output_index oi
1258
1258
  JOIN sessions s ON s.id = oi.session_id
1259
- ${s}`).all(...n)}function dE(e){if(!e)return[];try{let t=JSON.parse(e);if(Array.isArray(t))return t.filter(s=>typeof s=="string")}catch{}return[]}function uE(e={}){if(Ys.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project");let t=jr(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 Tc(e.projectId)){if(e.signal?.aborted)break;let i=aE(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 c=n.get(d);if(!(c===void 0&&!s.has(d))&&!(c!==void 0&&a!==void 0&&c!==a))try{st({source_session_id:o.session_id,target_session_id:d,link_type:"citation",confidence:nE,evidence:{matched_uuid:d,source_message_uuid:o.message_uuid,scanner:"uuid-ref"},inferred_by:"L1"}),r+=1}catch{}}}return{created:r}}function pE(e={}){let t=lE(e.projectId);if(t.length===0)return{created:0};let s=new Map;for(let a of t){let d=dE(a.plan_ids_json);for(let c of d){let u=c.trim().toLowerCase();if(!u)continue;let p=s.get(u);p?p.push({id:a.session_id,project_id:a.project_id}):s.set(u,[{id:a.session_id,project_id:a.project_id}])}}if(s.size===0)return{created:0};let n=jr(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 Tc(e.projectId)){if(e.signal?.aborted)break;let d=cE(a.content_text);if(d.length===0)continue;let c=r.get(a.session_id);if(c!==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!==c)continue;let f=i.get(a.session_id);f||(f=new Map,i.set(a.session_id,f));let g=f.get(m.id);g||(g=new Set,f.set(m.id,g)),g.add(u)}}}for(let[a,d]of i)for(let[c,u]of d)try{st({source_session_id:a,target_session_id:c,link_type:"citation",confidence:rE,evidence:{matched_plan_ids:Array.from(u).slice(0,12),scanner:"plan-ref"},inferred_by:"L1"}),o+=1}catch{}return{created:o}}function mE(e){if(Ys.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=jr(e.projectId),s=new Map,n=new Map;if(t.length>0){let i=_(),a=t.map(u=>u.id),d=a.map(()=>"?").join(","),c=i.prepare(`SELECT id, started_at FROM sessions WHERE id IN (${d})`).all(...a);for(let u of c)n.set(u.id,u.started_at)}for(let i of t)s.set(i.id,i.project_id);let r=new Map;for(let i of e.registry.terminals){let a=e.registry.sessions_by_pid[String(i.shell_pid)]??[];if(a.length===0)continue;let d=`${i.cwd??"<no-cwd>"}::${i.tab_name}`,c=r.get(d);c||(c=new Set,r.set(d,c));for(let u of a)c.add(u)}let o=0;for(let[,i]of r){if(i.size<2)continue;let a=new Map;for(let d of i){let c=s.get(d);if(c===void 0||typeof e.projectId=="number"&&c!==e.projectId)continue;let u=a.get(c);u||(u=[],a.set(c,u)),u.push(d)}for(let[,d]of a){if(d.length<2)continue;d.sort((u,p)=>{let m=n.get(u)??"",f=n.get(p)??"";return m<f?-1:m>f?1:u<p?-1:1});let c=0;for(let u=1;u<d.length&&!e.signal?.aborted;u++)for(let p=0;p<u&&!(c>=iE);p++)try{st({source_session_id:d[u],target_session_id:d[p],link_type:"skill_track",confidence:oE,evidence:{shared_tab_signature:!0,bucket_size:d.length,scanner:"tab-carry"},inferred_by:"L1"}),o+=1,c+=1}catch{}}}return{created:o}}function Rc(e={}){let t=uE(e);if(e.signal?.aborted)return{uuid_refs_created:t.created,plan_refs_created:0,tab_carry_created:0,total:t.created};let s=pE(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?mE({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 hE(){let e=_E(R,"terminals.json");if(gE(e))try{let t=fE(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=hE(),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=Rc({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)."))}y();Be();ss();function Fr(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 Br="claude-haiku-4-5-20251001",Gs=.4,Hr=.95,kc=30,Cc=240,EE=new Set(["CITATION","SIMILAR","SKILL_TRACK","UNRELATED"]),bE={CITATION:"citation",SIMILAR:"similar",SKILL_TRACK:"skill_track"};function Oc(e){return _().prepare(`SELECT s.id,
1259
+ ${s}`).all(...n)}function EE(e){if(!e)return[];try{let t=JSON.parse(e);if(Array.isArray(t))return t.filter(s=>typeof s=="string")}catch{}return[]}function bE(e={}){if(Gs.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project");let t=Fr(e.projectId),s=new Set(t.map(o=>o.id)),n=new Map;for(let o of t)n.set(o.id,o.project_id);let r=0;for(let o of Cc(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{rt({source_session_id:o.session_id,target_session_id:d,link_type:"citation",confidence:uE,evidence:{matched_uuid:d,source_message_uuid:o.message_uuid,scanner:"uuid-ref"},inferred_by:"L1"}),r+=1}catch{}}}return{created:r}}function SE(e={}){let t=hE(e.projectId);if(t.length===0)return{created:0};let s=new Map;for(let a of t){let d=EE(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=Fr(e.projectId),r=new Map;for(let a of n)r.set(a.id,a.project_id);let o=0,i=new Map;for(let a of Cc(e.projectId)){if(e.signal?.aborted)break;let d=_E(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 f=i.get(a.session_id);f||(f=new Map,i.set(a.session_id,f));let g=f.get(m.id);g||(g=new Set,f.set(m.id,g)),g.add(u)}}}for(let[a,d]of i)for(let[l,u]of d)try{rt({source_session_id:a,target_session_id:l,link_type:"citation",confidence:pE,evidence:{matched_plan_ids:Array.from(u).slice(0,12),scanner:"plan-ref"},inferred_by:"L1"}),o+=1}catch{}return{created:o}}function wE(e){if(Gs.skill_track!=="same-project")throw new Error("skill_track policy unexpectedly not same-project");if(!e.registry||!Array.isArray(e.registry.terminals))return{created:0};let t=Fr(e.projectId),s=new Map,n=new Map;if(t.length>0){let i=_(),a=t.map(u=>u.id),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)??"",f=n.get(p)??"";return m<f?-1:m>f?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>=gE);p++)try{rt({source_session_id:d[u],target_session_id:d[p],link_type:"skill_track",confidence:mE,evidence:{shared_tab_signature:!0,bucket_size:d.length,scanner:"tab-carry"},inferred_by:"L1"}),o+=1,l+=1}catch{}}}return{created:o}}function Lc(e={}){let t=bE(e);if(e.signal?.aborted)return{uuid_refs_created:t.created,plan_refs_created:0,tab_carry_created:0,total:t.created};let s=SE(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?wE({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 xE(){let e=RE(R,"terminals.json");if(yE(e))try{let t=TE(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 Nc(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=xE(),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=Lc({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)."))}y();Be();ss();function Ur(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 Hr="claude-haiku-4-5-20251001",Ys=.4,Wr=.95,Oc=30,Ac=240,kE=new Set(["CITATION","SIMILAR","SKILL_TRACK","UNRELATED"]),CE={CITATION:"citation",SIMILAR:"similar",SKILL_TRACK:"skill_track"};function Mc(e){return _().prepare(`SELECT s.id,
1260
1260
  s.source_session_id,
1261
1261
  s.target_session_id,
1262
1262
  s.link_type,
@@ -1266,7 +1266,7 @@ show full content: recall paste --show <id>
1266
1266
  FROM session_link_suggestions s
1267
1267
  JOIN sessions src ON src.id = s.source_session_id
1268
1268
  WHERE s.status = 'pending'
1269
- AND src.project_id = ?`).all(e)}function SE(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 LE(e){if(e.length===0)return new Map;let t=_(),s=e.map(()=>"?").join(","),n=t.prepare(`SELECT s.id,
1270
1270
  NULLIF(sa.alias, '') AS alias,
1271
1271
  s.auto_title,
1272
1272
  s.first_user_message,
@@ -1275,18 +1275,18 @@ show full content: recall paste --show <id>
1275
1275
  FROM sessions s
1276
1276
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1277
1277
  LEFT JOIN projects p ON p.id = s.project_id
1278
- WHERE s.id IN (${s})`).all(...e),r=new Map;for(let o of n)r.set(o.id,o);return r}function Lc(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 Nc(e){try{return JSON.parse(e)}catch{return e}}function wE(e){let t=e.minConfidence??Gs,s=Math.max(1,Math.min(500,e.limit??100)),n=Oc(e.projectId);if(n.length===0)return[];let r=new Map,o=new Map;for(let c of n){let u=`${c.source_session_id}|${c.target_session_id}|${c.link_type}`,p=o.get(u);p||(p={source_session_id:c.source_session_id,target_session_id:c.target_session_id,link_type:c.link_type,layers:[]},o.set(u,p));let m=p.layers.find(f=>f.inferred_by===c.inferred_by);m?(m.suggestion_ids.push(c.id),c.confidence>m.confidence&&(m.confidence=c.confidence,m.evidence=Nc(c.evidence))):p.layers.push({inferred_by:c.inferred_by,link_type:c.link_type,confidence:c.confidence,evidence:Nc(c.evidence),suggestion_ids:[c.id]})}let i=new Set;for(let c of o.values())i.add(c.source_session_id),i.add(c.target_session_id);let a=SE(Array.from(i)),d=[];for(let c of o.values()){let u=Fr(c.layers.map(f=>f.confidence));if(u<t)continue;let p=a.get(c.source_session_id),m=a.get(c.target_session_id);d.push({source_session_id:c.source_session_id,target_session_id:c.target_session_id,primary_link_type:c.link_type,combined_confidence:u,layers:c.layers,source_title:Lc(p,c.source_session_id),target_title:Lc(m,c.target_session_id),source_project:p?.project??null})}return d.sort((c,u)=>u.combined_confidence-c.combined_confidence),d.slice(0,s)}function yE(e){let t;try{t=JSON.stringify(e)}catch{t=String(e)}return t.length>Cc&&(t=t.slice(0,Cc)+"\u2026"),t}function TE(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=${yE(r.evidence)}`)}),t.join(`
1279
- `)}var Ur=null;async function RE(e,t){return Ur?Ur(e,t):ht(e,[],{model:t})}function xE(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 kE(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 c=typeof a.label=="string"?a.label.toUpperCase():"";if(!EE.has(c))continue;let u=typeof a.conf=="number"?a.conf:typeof a.confidence=="number"?a.confidence:NaN;if(!Number.isFinite(u))continue;let p=Math.max(0,Math.min(1,u)),m=typeof a.why=="string"?a.why.trim().slice(0,200):typeof a.reason=="string"?a.reason.trim().slice(0,200):"";o.push({pair_index:d,label:c,confidence:p,reason:m})}return o}async function Ac(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(!Ur&&!se())return t.failures.push({batch_index:-1,error:"claude CLI not available on PATH"}),t;let s=wE({projectId:e.projectId,minConfidence:e.minConfidence??Gs,limit:e.limit??100});t.candidates_after_filter=s.length;let n=Oc(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??Br,i=e.autoPromoteThreshold??Hr;for(let a=0,d=0;a<s.length&&!e.signal?.aborted;a+=kc,d+=1){let c=s.slice(a,a+kc);e.onBatchStart?.({batch:d,pairs:c.length});let u=TE(c),p=await RE(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=kE(p.stdout);if(!m){t.failures.push({batch_index:d,error:"parse-failed"});continue}let f=xE(p.stdout);t.total_input_tokens+=f.input_tokens,t.total_output_tokens+=f.output_tokens;for(let g of m){if(g.pair_index>=c.length)continue;let h=c[g.pair_index];if(t.classified+=1,g.label==="UNRELATED")continue;let E=bE[g.label];if(E)try{let b=st({source_session_id:h.source_session_id,target_session_id:h.target_session_id,link_type:E,confidence:g.confidence,evidence:{l4_label:g.label,l4_reason:g.reason,primary_type_l1_l2_l3:h.primary_link_type,combined_pre_l4:h.combined_confidence,scanner:"l4-llm",model:o},inferred_by:"L4"});if(t.suggestions_created+=1,e.autoPromote){let S=h.layers.map(w=>w.confidence);if(S.push(g.confidence),Fr(S)>=i)try{bc(b.id,"approved",{source:"auto"}),t.links_promoted+=1}catch{}}}catch{}}}return t}Be();var CE=1e3;function LE(e){let t=e.minConf?Math.max(0,Math.min(1,Number(e.minConf))):Gs,s=e.autoPromoteThreshold!==void 0?Math.max(0,Math.min(1,Number(e.autoPromoteThreshold))):Hr,n=e.limit?Math.max(1,Number(e.limit)):CE,r=e.model??Br,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(!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}=LE(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 Ac({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 c=Number(((Date.now()-a)/1e3).toFixed(1));if(e.json)console.log(JSON.stringify({project:t.name,model:o,pre_filter_threshold:s,auto_promote:i,auto_promote_threshold:i?n:null,...d,elapsed_seconds:c},null,2));else{if(console.log(`Done in ${c}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.`)}}y();import{createHash as $E}from"node:crypto";y();D();import{writeFileSync as NE,readFileSync as eO,existsSync as OE,mkdirSync as AE,readdirSync as tO,unlinkSync as sO}from"node:fs";import{join as Ic}from"node:path";import{randomUUID as vE}from"node:crypto";var Wr=Ic(R,"bug-patterns");function IE(){$(),OE(Wr)||AE(Wr,{recursive:!0})}function zs(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 ME(e){return{cluster_id:e.cluster_id,session_id:e.session_id,matched_at:e.matched_at}}function Mc(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??vE(),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 vc(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 Ic(e){try{return JSON.parse(e)}catch{return e}}function NE(e){let t=e.minConfidence??Ys,s=Math.max(1,Math.min(500,e.limit??100)),n=Mc(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(f=>f.inferred_by===l.inferred_by);m?(m.suggestion_ids.push(l.id),l.confidence>m.confidence&&(m.confidence=l.confidence,m.evidence=Ic(l.evidence))):p.layers.push({inferred_by:l.inferred_by,link_type:l.link_type,confidence:l.confidence,evidence:Ic(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=LE(Array.from(i)),d=[];for(let l of o.values()){let u=Ur(l.layers.map(f=>f.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:vc(p,l.source_session_id),target_title:vc(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 OE(e){let t;try{t=JSON.stringify(e)}catch{t=String(e)}return t.length>Ac&&(t=t.slice(0,Ac)+"\u2026"),t}function AE(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=${OE(r.evidence)}`)}),t.join(`
1279
+ `)}var Br=null;async function vE(e,t){return Br?Br(e,t):Et(e,[],{model:t})}function IE(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 ME(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 Dc(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(!Br&&!se())return t.failures.push({batch_index:-1,error:"claude CLI not available on PATH"}),t;let s=NE({projectId:e.projectId,minConfidence:e.minConfidence??Ys,limit:e.limit??100});t.candidates_after_filter=s.length;let n=Mc(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??Hr,i=e.autoPromoteThreshold??Wr;for(let a=0,d=0;a<s.length&&!e.signal?.aborted;a+=Oc,d+=1){let l=s.slice(a,a+Oc);e.onBatchStart?.({batch:d,pairs:l.length});let u=AE(l),p=await vE(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=ME(p.stdout);if(!m){t.failures.push({batch_index:d,error:"parse-failed"});continue}let f=IE(p.stdout);t.total_input_tokens+=f.input_tokens,t.total_output_tokens+=f.output_tokens;for(let g of m){if(g.pair_index>=l.length)continue;let h=l[g.pair_index];if(t.classified+=1,g.label==="UNRELATED")continue;let E=CE[g.label];if(E)try{let b=rt({source_session_id:h.source_session_id,target_session_id:h.target_session_id,link_type:E,confidence:g.confidence,evidence:{l4_label:g.label,l4_reason:g.reason,primary_type_l1_l2_l3:h.primary_link_type,combined_pre_l4:h.combined_confidence,scanner:"l4-llm",model:o},inferred_by:"L4"});if(t.suggestions_created+=1,e.autoPromote){let S=h.layers.map(x=>x.confidence);if(S.push(g.confidence),Ur(S)>=i)try{Tc(b.id,"approved",{source:"auto"}),t.links_promoted+=1}catch{}}}catch{}}}return t}Be();var DE=1e3;function $E(e){let t=e.minConf?Math.max(0,Math.min(1,Number(e.minConf))):Ys,s=e.autoPromoteThreshold!==void 0?Math.max(0,Math.min(1,Number(e.autoPromoteThreshold))):Wr,n=e.limit?Math.max(1,Number(e.limit)):DE,r=e.model??Hr,o=!!e.autoPromote||e.autoPromoteThreshold!==void 0;return{minConfidence:t,autoPromoteThreshold:s,limit:n,model:r,autoPromote:o}}async function $c(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}=$E(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 Dc({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.`)}}y();import{createHash as XE}from"node:crypto";y();D();import{writeFileSync as PE,readFileSync as gO,existsSync as jE,mkdirSync as FE,readdirSync as fO,unlinkSync as _O}from"node:fs";import{join as Pc}from"node:path";import{randomUUID as UE}from"node:crypto";var Xr=Pc(R,"bug-patterns");function BE(){P(),jE(Xr)||FE(Xr,{recursive:!0})}function zs(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 HE(e){return{cluster_id:e.cluster_id,session_id:e.session_id,matched_at:e.matched_at}}function jc(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??UE(),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
1281
1281
  (id, signature_hash, example_message, occurrence_count,
1282
1282
  first_seen_at, last_seen_at, resolved_in_session_id, fix_summary)
1283
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)
1284
1284
  VALUES (?, ?, ?)
1285
- ON CONFLICT(cluster_id, session_id) DO NOTHING`);for(let c of i)d.run(n,c,s)})();let a=Dc(n);if(!a)throw new Error("createCluster succeeded but read-back failed");return jc(n),a}function Dc(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:zs(s),members:n.map(ME)}}function $c(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=Fc(n);if(!a)throw new Error("createCluster succeeded but read-back failed");return Hc(n),a}function Fc(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:zs(s),members:n.map(HE)}}function Uc(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)
1286
1286
  VALUES (?, ?, ?)
1287
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
1288
1288
  SET occurrence_count = ?, last_seen_at = ?
1289
- WHERE id = ?`).run(d,r,e)}})(),o>0&&jc(e);let i=s.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);return{cluster:zs(i),added:o}}function DE(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 Pc(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&&Hc(e);let i=s.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);return{cluster:zs(i),added:o}}function WE(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 Bc(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,
1290
1290
  NULLIF(sa.alias, '') AS alias,
1291
1291
  s.auto_title,
1292
1292
  s.first_user_message,
@@ -1297,37 +1297,37 @@ show full content: recall paste --show <id>
1297
1297
  LEFT JOIN session_aliases sa ON sa.session_id = m.session_id
1298
1298
  LEFT JOIN projects p ON p.id = s.project_id
1299
1299
  WHERE m.cluster_id = ?
1300
- ORDER BY COALESCE(s.started_at, ''), m.matched_at, m.session_id`).all(e);return{cluster:zs(s),members:n.map(DE)}}function jc(e){try{IE();let t=Dc(e);if(!t)return;let s=Ic(Wr,`${e}.json`),n={schema:"claude-recall.bug-pattern-cluster.v1",cluster:t.cluster,members:t.members,backed_up_at:new Date().toISOString()};NE(s,JSON.stringify(n,null,2))}catch(t){console.error("[bug-patterns] backup failed:",t)}}function Fc(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:zs(s),members:n.map(WE)}}function Hc(e){try{BE();let t=Fc(e);if(!t)return;let s=Pc(Xr,`${e}.json`),n={schema:"claude-recall.bug-pattern-cluster.v1",cluster:t.cluster,members:t.members,backed_up_at:new Date().toISOString()};PE(s,JSON.stringify(n,null,2))}catch(t){console.error("[bug-patterns] backup failed:",t)}}function Wc(e){return e?_().prepare(`SELECT * FROM bug_pattern_clusters
1301
1301
  WHERE signature_hash = ?
1302
- ORDER BY last_seen_at DESC, id ASC`).all(e).map(zs):[]}function Uc(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(zs):[]}function Xc(e){if(!e)return new Set;let s=_().prepare(`SELECT DISTINCT m.session_id
1303
1303
  FROM bug_pattern_members m
1304
1304
  JOIN bug_pattern_clusters c ON c.id = m.cluster_id
1305
- WHERE c.signature_hash = ?`).all(e);return new Set(s.map(n=>n.session_id))}var PE=/\b0x[0-9a-fA-F]+\b/g,jE=/\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,FE=/\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z?\b/g,UE=/:\d+:\d+/g,BE=/\bline\s+\d+\b/gi,HE=/\bcolumn\s+\d+\b/gi,WE=/\b(?:pid|PID|process(?:\s+id)?)\s*[:=]?\s*\d+\b/gi,XE=/\b(?:port|:)\s*[:=]?\s*\d{2,5}\b/gi,JE=/\b\d{4,}\b/g,YE=/(['"`])[^'"`\n]{1,128}\1/g;function GE(e){if(!e)return"";let t=String(e);return t=t.replace(PE,"<hex>"),t=t.replace(jE,"<uuid>"),t=t.replace(FE,"<ts>"),t=t.replace(UE,":<line>:<col>"),t=t.replace(BE,"line <n>"),t=t.replace(HE,"column <n>"),t=t.replace(WE,"pid <n>"),t=t.replace(XE,"port <n>"),t=t.replace(JE,"<num>"),t=t.replace(YE,"<arg>"),t=t.replace(/\s+/g," ").trim(),t.toLowerCase()}function zE(e){let t=(e.error_type??"unknown").toLowerCase().trim(),s=GE(e.snippet??e.message_hash??""),n=`${t}|${s}`;return $E("sha256").update(n).digest("hex").slice(0,16)}function qE(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 JE=/\b0x[0-9a-fA-F]+\b/g,GE=/\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,YE=/\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z?\b/g,zE=/:\d+:\d+/g,qE=/\bline\s+\d+\b/gi,KE=/\bcolumn\s+\d+\b/gi,VE=/\b(?:pid|PID|process(?:\s+id)?)\s*[:=]?\s*\d+\b/gi,ZE=/\b(?:port|:)\s*[:=]?\s*\d{2,5}\b/gi,QE=/\b\d{4,}\b/g,eb=/(['"`])[^'"`\n]{1,128}\1/g;function tb(e){if(!e)return"";let t=String(e);return t=t.replace(JE,"<hex>"),t=t.replace(GE,"<uuid>"),t=t.replace(YE,"<ts>"),t=t.replace(zE,":<line>:<col>"),t=t.replace(qE,"line <n>"),t=t.replace(KE,"column <n>"),t=t.replace(VE,"pid <n>"),t=t.replace(ZE,"port <n>"),t=t.replace(QE,"<num>"),t=t.replace(eb,"<arg>"),t=t.replace(/\s+/g," ").trim(),t.toLowerCase()}function sb(e){let t=(e.error_type??"unknown").toLowerCase().trim(),s=tb(e.snippet??e.message_hash??""),n=`${t}|${s}`;return XE("sha256").update(n).digest("hex").slice(0,16)}function nb(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,
1306
1306
  p.name AS project,
1307
1307
  s.started_at AS started_at,
1308
1308
  oi.bug_signatures AS bug_signatures
1309
1309
  FROM session_output_index oi
1310
1310
  LEFT JOIN sessions s ON s.id = oi.session_id
1311
1311
  LEFT JOIN projects p ON p.id = s.project_id
1312
- ${r}`).all(...n),i=[];for(let a of o){if(!a.bug_signatures)continue;let d=[];try{let c=JSON.parse(a.bug_signatures);Array.isArray(c)&&(d=c)}catch{continue}for(let c of d){if(!c||typeof c!="object"||!(c.snippet??"").trim())continue;let p=zE(c);i.push({session_id:a.session_id,project:a.project,started_at:a.started_at,signature:c,fingerprint:p})}}return i}function KE(e){let t=new Map;for(let n of e){let r=t.get(n.fingerprint);r||(r=[],t.set(n.fingerprint,r)),r.push(n)}let s=[];for(let[n,r]of t){let o=new Set,i=[];for(let u of r)o.has(u.session_id)||(o.add(u.session_id),i.push(u));let a=[...i].sort((u,p)=>{let m=u.started_at??"",f=p.started_at??"";return m&&f?m<f?-1:m>f?1:0:m?-1:f?1:0}),d=a.find(u=>u.started_at),c=[...a].reverse().find(u=>u.started_at);s.push({fingerprint:n,example_message:i[0].signature.snippet??i[0].signature.message_hash??"",members:i,first_seen_at:d?.started_at??new Date().toISOString(),last_seen_at:c?.started_at??new Date().toISOString()})}return s}function VE(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 ZE(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-VE(s[u],s[m])<=n&&p.push(m)}i.push(p)}let a=new Array(o).fill(!1),d=new Array(o).fill(-1),c=[];for(let u=0;u<o;u++){if(a[u])continue;a[u]=!0;let p=i[u];if(p.length<r)continue;let m=c.length;c.push({members:[t[u]]}),d[u]=m;let f=[...p];for(;f.length>0;){let g=f.shift();if(!a[g]&&(a[g]=!0,i[g].length>=r))for(let h of i[g])(!a[h]||d[h]===-1)&&f.push(h);d[g]===-1&&(d[g]=m,c[m].members.push(t[g]))}}return c}async function QE(e,t,s,n){if(e.length===0)return[];let r=e.map(d=>{let c=d.signature.snippet??d.signature.message_hash??"";return`${d.signature.error_type??""}: ${c}`.trim()}),o=await t(r);if(o.length!==e.length)throw new Error(`embedder returned ${o.length} vectors for ${e.length} inputs`);let i=ZE({records:e,vectors:o,epsilon:s,minPts:n}),a=[];for(let d of i){if(d.members.length===0)continue;let c=new Set,u=[];for(let E of d.members)c.has(E.session_id)||(c.add(E.session_id),u.push(E));if(u.length===0)continue;let m=`sem:${[...u.map(E=>E.fingerprint)].sort()[0]}`,f=[...u].sort((E,b)=>{let S=E.started_at??"",C=b.started_at??"";return S<C?-1:S>C?1:0}),g=f.find(E=>E.started_at),h=[...f].reverse().find(E=>E.started_at);a.push({fingerprint:m,example_message:u[0].signature.snippet??u[0].signature.message_hash??"",members:u,first_seen_at:g?.started_at??new Date().toISOString(),last_seen_at:h?.started_at??new Date().toISOString()})}return a}function Bc(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=Fc(n.fingerprint),o=Uc(n.fingerprint),i=n.members.map(c=>c.session_id).filter(c=>!o.has(c));if(r.length===0){let c=Mc({signature_hash:n.fingerprint,example_message:n.example_message.slice(0,256),member_session_ids:n.members.map(u=>u.session_id),first_seen_at:n.first_seen_at,last_seen_at:n.last_seen_at});s.clusters_created+=1,s.members_added+=c.members.length,s.cluster_ids.push(c.cluster.id);continue}if(i.length===0){s.cluster_ids.push(r[0].id);continue}let a=r[0],d=$c(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 Hc(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=qE(e.project),i=new Set(o.map(S=>S.session_id)),a=KE(o),d=[],c=!1;if(e.semantic){let S=e.embedder??null;if(!S)try{S=await sb()}catch(C){let N=(C instanceof Error?C.message:String(C)).split(`
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=sb(l);i.push({session_id:a.session_id,project:a.project,started_at:a.started_at,signature:l,fingerprint:p})}}return i}function rb(e){let t=new Map;for(let n of e){let r=t.get(n.fingerprint);r||(r=[],t.set(n.fingerprint,r)),r.push(n)}let s=[];for(let[n,r]of t){let o=new Set,i=[];for(let u of r)o.has(u.session_id)||(o.add(u.session_id),i.push(u));let a=[...i].sort((u,p)=>{let m=u.started_at??"",f=p.started_at??"";return m&&f?m<f?-1:m>f?1:0:m?-1:f?1:0}),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 ob(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 ib(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-ob(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 f=[...p];for(;f.length>0;){let g=f.shift();if(!a[g]&&(a[g]=!0,i[g].length>=r))for(let h of i[g])(!a[h]||d[h]===-1)&&f.push(h);d[g]===-1&&(d[g]=m,l[m].members.push(t[g]))}}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=ib({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]}`,f=[...u].sort((E,b)=>{let S=E.started_at??"",T=b.started_at??"";return S<T?-1:S>T?1:0}),g=f.find(E=>E.started_at),h=[...f].reverse().find(E=>E.started_at);a.push({fingerprint:m,example_message:u[0].signature.snippet??u[0].signature.message_hash??"",members:u,first_seen_at:g?.started_at??new Date().toISOString(),last_seen_at:h?.started_at??new Date().toISOString()})}return a}function Jc(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=Wc(n.fingerprint),o=Xc(n.fingerprint),i=n.members.map(l=>l.session_id).filter(l=>!o.has(l));if(r.length===0){let l=jc({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=Uc(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 Gc(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=nb(e.project),i=new Set(o.map(S=>S.session_id)),a=rb(o),d=[],l=!1;if(e.semantic){let S=e.embedder??null;if(!S)try{S=await db()}catch(T){let N=(T instanceof Error?T.message:String(T)).split(`
1313
1313
  `)[0];console.warn(`[bug-pattern] --semantic requested but the embedder is unavailable: ${N}
1314
- Falling back to exact-match-only clustering. Run \`recall semantic install\` to enable the semantic pass.`),c=!0}if(S){let C=[];for(let w of a)w.members.length===1&&C.push(w.members[0]);C.length>=2&&(d=await QE(C,S,n,r))}}let u=a.filter(S=>S.members.length>=t),p=d.filter(S=>S.members.length>=t),m=Bc(u,t),f=Bc(p,t),g=[...m.cluster_ids,...f.cluster_ids],h=Array.from(new Set(g)),E=[];if(h.length>0){let S=_(),C=h.map(()=>"?").join(","),w=S.prepare(`SELECT * FROM bug_pattern_clusters
1315
- WHERE id IN (${C})
1314
+ Falling back to exact-match-only clustering. Run \`recall semantic install\` to enable the semantic pass.`),l=!0}if(S){let T=[];for(let x of a)x.members.length===1&&T.push(x.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=Jc(u,t),f=Jc(p,t),g=[...m.cluster_ids,...f.cluster_ids],h=Array.from(new Set(g)),E=[];if(h.length>0){let S=_(),T=h.map(()=>"?").join(","),x=S.prepare(`SELECT * FROM bug_pattern_clusters
1315
+ WHERE id IN (${T})
1316
1316
  ORDER BY occurrence_count DESC, last_seen_at DESC
1317
- LIMIT ?`).all(...h,s);for(let N of w)E.push({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,resolved_in_session_id:N.resolved_in_session_id,fix_summary:N.fix_summary})}return{progress:{total_sessions:i.size,total_signatures:o.length,exact_match_groups:u.length,semantic_groups:p.length,clusters_created:m.clusters_created+f.clusters_created,clusters_merged:m.clusters_merged+f.clusters_merged,members_added:m.members_added+f.members_added,semantic_skipped:c},clusters:E}}var eb=async()=>{let{embed:e,loadEmbedder:t,getEmbedderStatus:s}=await Promise.resolve().then(()=>(et(),xr));return s().loaded||await t(),e},tb=eb;async function sb(){return tb()}function nb(e,t){let s=Pc(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 Wc(e){let t=e.minClusterSize?Math.max(2,Math.floor(Number(e.minClusterSize))):3;if(!Number.isFinite(t)){console.error("--min-cluster-size must be a positive number"),process.exitCode=1;return}let s=e.limit?Math.max(1,Math.floor(Number(e.limit))):100;if(!Number.isFinite(s)){console.error("--limit must be a positive number"),process.exitCode=1;return}let n;if(e.project){let c=Ee(e.project);if(!c){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}n=c.name}if(!e.json){let c=n?`project "${n}"`:"all projects",u=e.semantic?"exact + semantic":"exact";console.log(`Inferring bug patterns \u2014 ${c}, min-cluster-size=${t}, ${u} passes\u2026`)}let r={project:n,minClusterSize:t,semantic:!!e.semantic,limit:s},o=Date.now(),i;try{i=await Hc(r)}catch(c){console.error(c instanceof Error?c.message:String(c)),process.exitCode=1;return}let a=Number(((Date.now()-o)/1e3).toFixed(1)),d=[];for(let c of i.clusters.slice(0,s)){let u=nb(c.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(`
1318
- Top ${d.length} cluster(s):`);for(let c of d){let u=c.status==="resolved"?"\u2713 resolved":"open",p=c.example_message.slice(0,80);console.log(`
1319
- [${u}] occurs=${c.occurrence_count} hash=${c.signature_hash.slice(0,8)}
1317
+ LIMIT ?`).all(...h,s);for(let N of x)E.push({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,resolved_in_session_id:N.resolved_in_session_id,fix_summary:N.fix_summary})}return{progress:{total_sessions:i.size,total_signatures:o.length,exact_match_groups:u.length,semantic_groups:p.length,clusters_created:m.clusters_created+f.clusters_created,clusters_merged:m.clusters_merged+f.clusters_merged,members_added:m.members_added+f.members_added,semantic_skipped:l},clusters:E}}var cb=async()=>{let{embed:e,loadEmbedder:t,getEmbedderStatus:s}=await Promise.resolve().then(()=>(st(),kr));return s().loaded||await t(),e},lb=cb;async function db(){return lb()}function ub(e,t){let s=Bc(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 Yc(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 Gc(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=ub(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(`
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(`
1319
+ [${u}] occurs=${l.occurrence_count} hash=${l.signature_hash.slice(0,8)}
1320
1320
  ${p}
1321
- first=${c.first_seen_at} last=${c.last_seen_at}`);for(let m of c.sample_members){let f=m.project?`[${m.project}] `:"";console.log(` \u2022 ${f}${m.title} (${m.session_id.slice(0,8)})`)}}console.log("\n Review at /graph/patterns in the web UI, or `recall neighborhood <session-id>` for an agent-facing bundle.")}y();import{z as SO}from"zod";y();function Xc(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}Xr();var Qc=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),el=new Set(["pagerank","embedding-rerank","hybrid"]);function Eb(e){if(!e)return;let t=e.split(",").map(s=>s.trim()).filter(Boolean);for(let s of t)if(!Qc.has(s))throw new Error(`invalid --edge-types value: '${s}'. Valid: ${Array.from(Qc).join(", ")}`);return t}function bb(e){if(!e)return"hybrid";if(!el.has(e))throw new Error(`invalid --scoring value: '${e}'. Valid: ${Array.from(el).join(", ")}`);return e}async function tl(e,t){let s=Xc(e);if(!s){console.error(`session not found or prefix ambiguous: ${e}`),process.exitCode=1;return}let n,r;try{n=bb(t.scoring),r=Eb(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=Vs(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 f=m.project?`[${m.project}] `:"";console.log(` \u2022 ${f}${m.title} (${m.session_id.slice(0,8)})`)}}console.log("\n Review at /graph/patterns in the web UI, or `recall neighborhood <session-id>` for an agent-facing bundle.")}y();import{z as MO}from"zod";y();function zc(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}Jr();var nl=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),rl=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(!nl.has(s))throw new Error(`invalid --edge-types value: '${s}'. Valid: ${Array.from(nl).join(", ")}`);return t}function Cb(e){if(!e)return"hybrid";if(!rl.has(e))throw new Error(`invalid --scoring value: '${e}'. Valid: ${Array.from(rl).join(", ")}`);return e}async function ol(e,t){let s=zc(e);if(!s){console.error(`session not found or prefix ambiguous: ${e}`),process.exitCode=1;return}let n,r;try{n=Cb(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=Vs(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)+`
1322
1322
  `);return}process.stdout.write(a.bundle),a.truncated.length>0&&console.error(`
1323
- [truncated ${a.truncated.length} refs to fit ${o}-token budget; ${a.budgetUsed} used / ${a.budgetRemaining} remaining]`)}y();v();var Sb=[[/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}]],sl={label:"unknown",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30};function nt(e){if(!e)return sl;for(let[t,s]of Sb)if(t.test(e))return s;return sl}function Ie(e,t){if(e.byModel&&Object.keys(e.byModel).length>0){let i={input:0,output:0,cacheCreate:0,cacheRead:0},a=0;for(let[c,u]of Object.entries(e.byModel)){let p=nt(c);i.input+=u.inputTokens/1e6*p.inputCentsPerMtok,i.output+=u.outputTokens/1e6*p.outputCentsPerMtok,i.cacheCreate+=u.cacheCreateTokens/1e6*p.cacheCreateCentsPerMtok,i.cacheRead+=u.cacheReadTokens/1e6*p.cacheReadCentsPerMtok,a+=u.inputTokens+u.outputTokens+u.cacheCreateTokens+u.cacheReadTokens}let d=i.input+i.output+i.cacheCreate+i.cacheRead;return{cents:d,dollars:d/100,totalTokens:a,parts:i}}let s=nt(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 de(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`}y();y();var wb=500,Zs=new Set;function nl(){return Zs.size}function yb(){return`
1323
+ [truncated ${a.truncated.length} refs to fit ${o}-token budget; ${a.budgetUsed} used / ${a.budgetRemaining} remaining]`)}y();v();var Lb=[[/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}]],il={label:"unknown",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30};function ot(e){if(!e)return il;for(let[t,s]of Lb)if(t.test(e))return s;return il}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=ot(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=ot(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 de(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`}y();y();var Nb=500,Zs=new Set;function al(){return Zs.size}function Ob(){return`
1324
1324
  SELECT m.uuid, m.session_id, m.timestamp, m.raw_json
1325
1325
  FROM messages m
1326
1326
  LEFT JOIN message_usage mu ON mu.message_uuid = m.uuid
1327
1327
  WHERE m.role = 'assistant' AND mu.message_uuid IS NULL
1328
1328
  AND m.uuid NOT IN (SELECT value FROM json_each(?))
1329
1329
  LIMIT ?
1330
- `}function Tb(e,t){let s=t.limit??Number.MAX_SAFE_INTEGER,n=Math.max(1,t.chunkSize??wb),r=e.prepare(yb()),o=e.prepare(`
1330
+ `}function Ab(e,t){let s=t.limit??Number.MAX_SAFE_INTEGER,n=Math.max(1,t.chunkSize??Nb),r=e.prepare(Ob()),o=e.prepare(`
1331
1331
  INSERT INTO message_usage (
1332
1332
  message_uuid, session_id, model,
1333
1333
  input_tokens, output_tokens, cache_create_tokens, cache_read_tokens,
@@ -1337,7 +1337,7 @@ Top ${d.length} cluster(s):`);for(let c of d){let u=c.status==="resolved"?"\u271
1337
1337
  @input, @output, @cc, @cr, @ts
1338
1338
  )
1339
1339
  ON CONFLICT(message_uuid) DO NOTHING
1340
- `),i=0,a=0,d=new Set;for(;i<s;){let c=Math.min(n,s-i),u=JSON.stringify([...Zs]),p=r.all(u,c);if(p.length===0)break;let m=new Set;if(e.transaction(()=>{for(let g of p){let h;try{h=JSON.parse(g.raw_json)}catch{Zs.add(g.uuid);continue}let E=$n(h.message);if(!E){Zs.add(g.uuid);continue}o.run({uuid:g.uuid,session_id:g.session_id,model:h.message?.model??null,input:E.inputTokens,output:E.outputTokens,cc:E.cacheCreateTokens,cr:E.cacheReadTokens,ts:g.timestamp}),a+=1,m.add(g.session_id)}for(let g of m)Xt(e,g),d.add(g)})(),i+=p.length,t.onProgress?.({scanned:i,inserted:a,sessionsTouched:d.size,done:p.length<c}),p.length<c)break}return{scanned:i,inserted:a,sessionsTouched:d.size,done:!0}}function rl(e={}){return Tb(_(),e)}function Jr(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:nt(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 Yr(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 ol(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([...Zs]),p=r.all(u,l);if(p.length===0)break;let m=new Set;if(e.transaction(()=>{for(let g of p){let h;try{h=JSON.parse(g.raw_json)}catch{Zs.add(g.uuid);continue}let E=$n(h.message);if(!E){Zs.add(g.uuid);continue}o.run({uuid:g.uuid,session_id:g.session_id,model:h.message?.model??null,input:E.inputTokens,output:E.outputTokens,cc:E.cacheCreateTokens,cr:E.cacheReadTokens,ts:g.timestamp}),a+=1,m.add(g.session_id)}for(let g of m)Xt(e,g),d.add(g)})(),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 cl(e={}){return Ab(_(),e)}function Gr(e){let t=new Map;for(let n of e){let r=n.model??null,o=t.get(r)??{inputTokens:0,outputTokens:0,cacheCreateTokens:0,cacheReadTokens:0,messageCount:0};o.inputTokens+=n.input_tokens,o.outputTokens+=n.output_tokens,o.cacheCreateTokens+=n.cache_create_tokens,o.cacheReadTokens+=n.cache_read_tokens,o.messageCount+=n.n,t.set(r,o)}let s=[];for(let[n,r]of t.entries()){let o=Ie({inputTokens:r.inputTokens,outputTokens:r.outputTokens,cacheCreateTokens:r.cacheCreateTokens,cacheReadTokens:r.cacheReadTokens},n);s.push({model:n,modelLabel:ot(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 Yr(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 ll(e){let t=_(),s=t.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
1341
1341
  s.message_count,
1342
1342
  s.total_input_tokens, s.total_output_tokens,
1343
1343
  s.total_cache_create_tokens, s.total_cache_read_tokens,
@@ -1352,7 +1352,7 @@ Top ${d.length} cluster(s):`);for(let c of d){let u=c.status==="resolved"?"\u271
1352
1352
  COUNT(*) AS n
1353
1353
  FROM message_usage
1354
1354
  WHERE session_id = ?
1355
- GROUP BY model`).all(e),r=Jr(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,c=Ie({inputTokens:o,outputTokens:i,cacheCreateTokens:a,cacheReadTokens:d,...Yr(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:nt(s.primary_model).label,inputTokens:o,outputTokens:i,cacheCreateTokens:a,cacheReadTokens:d,totalTokens:c.totalTokens,cost:c,byModel:r,display:{dollars:ne(c.cents),tokens:de(c.totalTokens),model:nt(s.primary_model).label}}}function il(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=Gr(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,...Yr(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:ot(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:de(l.totalTokens),model:ot(s.primary_model).label}}}function dl(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,
1356
1356
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
1357
1357
  COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
1358
1358
  COALESCE(SUM(mu.cache_create_tokens), 0) AS cache_create_tokens,
@@ -1361,7 +1361,7 @@ Top ${d.length} cluster(s):`);for(let c of d){let u=c.status==="resolved"?"\u271
1361
1361
  FROM message_usage mu
1362
1362
  JOIN sessions s ON s.id = mu.session_id
1363
1363
  WHERE s.project_id = ?
1364
- GROUP BY mu.model`).all(s.id),r=Jr(n),o=t.prepare(`SELECT COALESCE(SUM(total_input_tokens), 0) AS input_tokens,
1364
+ GROUP BY mu.model`).all(s.id),r=Gr(n),o=t.prepare(`SELECT COALESCE(SUM(total_input_tokens), 0) AS input_tokens,
1365
1365
  COALESCE(SUM(total_output_tokens), 0) AS output_tokens,
1366
1366
  COALESCE(SUM(total_cache_create_tokens), 0) AS cache_create_tokens,
1367
1367
  COALESCE(SUM(total_cache_read_tokens), 0) AS cache_read_tokens,
@@ -1377,7 +1377,7 @@ Top ${d.length} cluster(s):`);for(let c of d){let u=c.status==="resolved"?"\u271
1377
1377
  + COALESCE(s.total_output_tokens,0)
1378
1378
  + COALESCE(s.total_cache_create_tokens,0)
1379
1379
  + COALESCE(s.total_cache_read_tokens,0)) DESC
1380
- LIMIT 10`).all(s.id).map(c=>{let u=Ie({inputTokens:c.total_input_tokens??0,outputTokens:c.total_output_tokens??0,cacheCreateTokens:c.total_cache_create_tokens??0,cacheReadTokens:c.total_cache_read_tokens??0},c.primary_model);return{sessionId:c.id,alias:c.alias,startedAt:c.started_at,totalTokens:u.totalTokens,cost:u}});return{project:s.name,sessionCount:o.session_count,inputTokens:o.input_tokens,outputTokens:o.output_tokens,cacheCreateTokens:o.cache_create_tokens,cacheReadTokens:o.cache_read_tokens,totalTokens:i.totalTokens,cost:i,byModel:r,topSessions:d,display:{dollars:ne(i.cents),tokens:de(i.totalTokens)}}}function al(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=T=>s?t.prepare(T).get(o):t.prepare(T).get(),a=T=>s?t.prepare(T).all(o):t.prepare(T).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:ne(i.cents),tokens:de(i.totalTokens)}}}function ul(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=w=>s?t.prepare(w).get(o):t.prepare(w).get(),a=w=>s?t.prepare(w).all(o):t.prepare(w).all(),d=a(`SELECT mu.model,
1381
1381
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
1382
1382
  COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
1383
1383
  COALESCE(SUM(mu.cache_create_tokens), 0) AS cache_create_tokens,
@@ -1386,7 +1386,7 @@ Top ${d.length} cluster(s):`);for(let c of d){let u=c.status==="resolved"?"\u271
1386
1386
  FROM message_usage mu
1387
1387
  JOIN sessions s ON s.id = mu.session_id
1388
1388
  ${n}
1389
- GROUP BY mu.model`),c=Jr(d),u=0,p=0,m=0,f=0;for(let T of c)u+=T.inputTokens,p+=T.outputTokens,m+=T.cacheCreateTokens,f+=T.cacheReadTokens;let g=Ie({inputTokens:u,outputTokens:p,cacheCreateTokens:m,cacheReadTokens:f,...Yr(c)},null),h=s?i(`SELECT
1389
+ GROUP BY mu.model`),l=Gr(d),u=0,p=0,m=0,f=0;for(let w of l)u+=w.inputTokens,p+=w.outputTokens,m+=w.cacheCreateTokens,f+=w.cacheReadTokens;let g=Ie({inputTokens:u,outputTokens:p,cacheCreateTokens:m,cacheReadTokens:f,...Yr(l)},null),h=s?i(`SELECT
1390
1390
  (SELECT COUNT(DISTINCT m.session_id)
1391
1391
  FROM messages m
1392
1392
  JOIN sessions s2 ON s2.id = m.session_id
@@ -1410,7 +1410,7 @@ Top ${d.length} cluster(s):`);for(let c of d){let u=c.status==="resolved"?"\u271
1410
1410
  JOIN sessions s ON s.id = mu.session_id
1411
1411
  ${n}
1412
1412
  GROUP BY day, mu.model
1413
- ORDER BY day ASC`),b=new Map;for(let T of E){if(!T.day)continue;let U=Ie({inputTokens:T.input_tokens,outputTokens:T.output_tokens,cacheCreateTokens:T.cache_create_tokens,cacheReadTokens:T.cache_read_tokens},T.model),M=b.get(T.day)??{tokens:0,cents:0};M.tokens+=U.totalTokens,M.cents+=U.cents,b.set(T.day,M)}let S=[...b.entries()].map(([T,U])=>({day:T,tokens:U.tokens,cents:U.cents})).sort((T,U)=>T.day.localeCompare(U.day)),w=a(`SELECT s.id, p.name AS project, sa.alias, s.started_at,
1413
+ ORDER BY day ASC`),b=new Map;for(let w of E){if(!w.day)continue;let U=Ie({inputTokens:w.input_tokens,outputTokens:w.output_tokens,cacheCreateTokens:w.cache_create_tokens,cacheReadTokens:w.cache_read_tokens},w.model),M=b.get(w.day)??{tokens:0,cents:0};M.tokens+=U.totalTokens,M.cents+=U.cents,b.set(w.day,M)}let S=[...b.entries()].map(([w,U])=>({day:w,tokens:U.tokens,cents:U.cents})).sort((w,U)=>w.day.localeCompare(U.day)),x=a(`SELECT s.id, p.name AS project, sa.alias, s.started_at,
1414
1414
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
1415
1415
  COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
1416
1416
  COALESCE(SUM(mu.cache_create_tokens), 0) AS cache_create_tokens,
@@ -1426,7 +1426,7 @@ Top ${d.length} cluster(s):`);for(let c of d){let u=c.status==="resolved"?"\u271
1426
1426
  + COALESCE(SUM(mu.output_tokens),0)
1427
1427
  + COALESCE(SUM(mu.cache_create_tokens),0)
1428
1428
  + COALESCE(SUM(mu.cache_read_tokens),0)) DESC
1429
- LIMIT 10`).map(T=>{let U=Ie({inputTokens:T.input_tokens,outputTokens:T.output_tokens,cacheCreateTokens:T.cache_create_tokens,cacheReadTokens:T.cache_read_tokens},T.primary_model);return{sessionId:T.id,project:T.project,alias:T.alias,startedAt:T.started_at,totalTokens:U.totalTokens,cost:U}}),N=a(`SELECT p.id AS project_id,
1429
+ LIMIT 10`).map(w=>{let U=Ie({inputTokens:w.input_tokens,outputTokens:w.output_tokens,cacheCreateTokens:w.cache_create_tokens,cacheReadTokens:w.cache_read_tokens},w.primary_model);return{sessionId:w.id,project:w.project,alias:w.alias,startedAt:w.started_at,totalTokens:U.totalTokens,cost:U}}),N=a(`SELECT p.id AS project_id,
1430
1430
  p.name AS project,
1431
1431
  mu.model,
1432
1432
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
@@ -1438,16 +1438,16 @@ Top ${d.length} cluster(s):`);for(let c of d){let u=c.status==="resolved"?"\u271
1438
1438
  JOIN sessions s ON s.id = mu.session_id
1439
1439
  LEFT JOIN projects p ON p.id = s.project_id
1440
1440
  ${n}
1441
- GROUP BY p.id, mu.model`),z=new Map;for(let T of N){let U=T.project_id??"__none__",M=z.get(U);M||(M={project:T.project??"(no project)",sessionIds:new Set,sessionsApprox:0,byModel:{}},z.set(U,M)),T.sessions>M.sessionsApprox&&(M.sessionsApprox=T.sessions),M.byModel[T.model??"__unknown__"]={inputTokens:T.input_tokens,outputTokens:T.output_tokens,cacheCreateTokens:T.cache_create_tokens,cacheReadTokens:T.cache_read_tokens}}let O=[...z.values()].map(T=>{let U=0,M=0,K=0,Je=0;for(let gt of Object.values(T.byModel))U+=gt.inputTokens,M+=gt.outputTokens,K+=gt.cacheCreateTokens,Je+=gt.cacheReadTokens;let je=Ie({inputTokens:U,outputTokens:M,cacheCreateTokens:K,cacheReadTokens:Je,byModel:T.byModel},null);return{project:T.project,sessions:T.sessionsApprox,totalTokens:je.totalTokens,cost:je}});O.sort((T,U)=>U.totalTokens-T.totalTokens);let ee=O.slice(0,20),B=t.prepare(`SELECT
1441
+ GROUP BY p.id, mu.model`),K=new Map;for(let w of N){let U=w.project_id??"__none__",M=K.get(U);M||(M={project:w.project??"(no project)",sessionIds:new Set,sessionsApprox:0,byModel:{}},K.set(U,M)),w.sessions>M.sessionsApprox&&(M.sessionsApprox=w.sessions),M.byModel[w.model??"__unknown__"]={inputTokens:w.input_tokens,outputTokens:w.output_tokens,cacheCreateTokens:w.cache_create_tokens,cacheReadTokens:w.cache_read_tokens}}let O=[...K.values()].map(w=>{let U=0,M=0,V=0,Je=0;for(let ft of Object.values(w.byModel))U+=ft.inputTokens,M+=ft.outputTokens,V+=ft.cacheCreateTokens,Je+=ft.cacheReadTokens;let je=Ie({inputTokens:U,outputTokens:M,cacheCreateTokens:V,cacheReadTokens:Je,byModel:w.byModel},null);return{project:w.project,sessions:w.sessionsApprox,totalTokens:je.totalTokens,cost:je}});O.sort((w,U)=>U.totalTokens-w.totalTokens);let $=O.slice(0,20),F=t.prepare(`SELECT
1442
1442
  (SELECT COUNT(*) FROM messages WHERE role='assistant') AS assistant_messages,
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:f,totalTokens:g.totalTokens,cost:g,daily:S,byModel:c,topSessions:w,topRepos:ee,backfill:{assistantMessages:B.assistant_messages,messagesWithUsage:B.messages_with_usage,pending:Math.max(0,B.assistant_messages-B.messages_with_usage),unrecoverable:Math.min(nl(),Math.max(0,B.assistant_messages-B.messages_with_usage))},display:{dollars:ne(g.cents),tokens:de(g.totalTokens)}}}var Ke=e=>e.toLocaleString();function Rb(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(l.dim("backfilling per-message usage from raw_json\u2026"));let o=rl({limit:r});if(console.log(`${l.ok("backfill done")}: scanned ${l.bold(String(o.scanned))}, inserted ${l.bold(String(o.inserted))}, rolled-up ${l.bold(String(o.sessionsTouched))} sessions`),!e&&!t.project)return}if(e){let r=Rb(e);if(!r){console.error(l.err(`no session matches '${e}'`)),process.exit(1);return}let o=ol(r);if(!o){console.error(l.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(l.bold("session cost")),console.log(l.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` id ${l.dim(o.sessionId)}`),console.log(` project ${l.accent(o.project??"\u2014")}`),console.log(` started ${l.dim(o.startedAt??"n/a")}`),console.log(` messages ${l.accent(Ke(o.messageCount))}`),console.log(` model ${l.accent(o.primaryModelLabel)} ${l.dim(o.primaryModel??"")}`),console.log(""),console.log(` input ${Ke(o.inputTokens).padStart(12)}`),console.log(` output ${Ke(o.outputTokens).padStart(12)}`),console.log(` cache write ${Ke(o.cacheCreateTokens).padStart(12)}`),console.log(` cache read ${Ke(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 ${l.bold(Ke(o.totalTokens).padStart(12))}`),console.log(` estimated cost ${l.accent(ne(o.cost.cents).padStart(12))}`),o.byModel.length>1){console.log(""),console.log(l.dim(" by model:"));for(let i of o.byModel)console.log(` ${i.modelLabel.padEnd(14)} ${de(i.inputTokens+i.outputTokens+i.cacheCreateTokens+i.cacheReadTokens).padStart(10)} ${l.accent(ne(i.cost.cents).padStart(10))}`)}console.log("");return}if(t.project){let r=il(t.project);if(!r){console.error(l.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(l.bold(`project \xB7 ${r.project}`)),console.log(l.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 ${l.accent(Ke(r.sessionCount))}`),console.log(` total tokens ${l.accent(de(r.totalTokens).padStart(12))}`),console.log(` estimated cost ${l.accent(ne(r.cost.cents).padStart(12))}`),r.byModel.length>0){console.log(""),console.log(l.dim(" by model:"));for(let o of r.byModel)console.log(` ${o.modelLabel.padEnd(14)} ${de(o.inputTokens+o.outputTokens+o.cacheCreateTokens+o.cacheReadTokens).padStart(10)} ${l.accent(ne(o.cost.cents).padStart(10))}`)}if(r.topSessions.length>0){console.log(""),console.log(l.dim(" top sessions:"));for(let o of r.topSessions){let i=o.alias??o.sessionId.slice(0,8);console.log(` ${i.padEnd(22)} ${de(o.totalTokens).padStart(10)} ${l.accent(ne(o.cost.cents).padStart(10))}`)}}console.log("");return}let s=t.days==="7"?"7d":t.days==="30"?"30d":"all",n=al(s);if(t.json){console.log(JSON.stringify(n,null,2));return}if(console.log(""),console.log(l.bold(`overview \xB7 ${s}`)),console.log(l.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 ${l.accent(Ke(n.totalSessions))} ${l.dim(`(${n.sessionsWithUsage} w/ usage)`)}`),console.log(` total tokens ${l.accent(de(n.totalTokens).padStart(12))}`),console.log(` estimated cost ${l.accent(ne(n.cost.cents).padStart(12))}`),n.backfill.pending>0&&console.log(l.dim(` (${Ke(n.backfill.pending)} assistant messages pending \u2014 run \`recall stats --backfill\`)`)),n.byModel.length>0){console.log(""),console.log(l.dim(" by model:"));for(let r of n.byModel)console.log(` ${r.modelLabel.padEnd(14)} ${de(r.inputTokens+r.outputTokens+r.cacheCreateTokens+r.cacheReadTokens).padStart(10)} ${l.accent(ne(r.cost.cents).padStart(10))}`)}if(n.topSessions.length>0){console.log(""),console.log(l.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)} ${de(r.totalTokens).padStart(10)} ${l.accent(ne(r.cost.cents).padStart(10))}`)}}console.log("")}v();y();y();import{execFile as xb}from"node:child_process";import{promisify as kb}from"node:util";import{stat as Cb}from"node:fs/promises";var ll=kb(xb),dl=1e4,Lb="%H%x09%aI%x09%s";async function Nb(e){try{let{stdout:t}=await ll("git",["rev-parse","--is-inside-work-tree"],{cwd:e,timeout:dl});return t.trim()==="true"}catch{return!1}}async function Ob(e,t,s){let n=["--no-pager","log","--all","--no-color","--since",t,"--until",s,`--pretty=format:${Lb}`],{stdout:r}=await ll("git",n,{cwd:e,timeout:dl,maxBuffer:8*1024*1024}),o=[],i=new Set;for(let a of r.split(`
1444
- `)){if(!a)continue;let[d,c,...u]=a.split(" ");!d||i.has(d)||(i.add(d),o.push({commit_sha:d,committed_at:c??null,subject:u.join(" ")||null}))}return o}function Ab(e){return _().prepare(`SELECT id, cwd, started_at, ended_at
1445
- FROM sessions WHERE id = ?`).get(e)??null}function vb(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:f,totalTokens:g.totalTokens,cost:g,daily:S,byModel:l,topSessions:x,topRepos:$,backfill:{assistantMessages:F.assistant_messages,messagesWithUsage:F.messages_with_usage,pending:Math.max(0,F.assistant_messages-F.messages_with_usage),unrecoverable:Math.min(al(),Math.max(0,F.assistant_messages-F.messages_with_usage))},display:{dollars:ne(g.cents),tokens:de(g.totalTokens)}}}var Ve=e=>e.toLocaleString();function vb(e){return _().prepare("SELECT id FROM sessions WHERE id = ? OR id LIKE ? LIMIT 1").get(e,`${e}%`)?.id??null}async function pl(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=cl({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=vb(e);if(!r){console.error(c.err(`no session matches '${e}'`)),process.exit(1);return}let o=ll(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(Ve(o.messageCount))}`),console.log(` model ${c.accent(o.primaryModelLabel)} ${c.dim(o.primaryModel??"")}`),console.log(""),console.log(` input ${Ve(o.inputTokens).padStart(12)}`),console.log(` output ${Ve(o.outputTokens).padStart(12)}`),console.log(` cache write ${Ve(o.cacheCreateTokens).padStart(12)}`),console.log(` cache read ${Ve(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(Ve(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)} ${de(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=dl(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(Ve(r.sessionCount))}`),console.log(` total tokens ${c.accent(de(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)} ${de(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)} ${de(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=ul(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(Ve(n.totalSessions))} ${c.dim(`(${n.sessionsWithUsage} w/ usage)`)}`),console.log(` total tokens ${c.accent(de(n.totalTokens).padStart(12))}`),console.log(` estimated cost ${c.accent(ne(n.cost.cents).padStart(12))}`),n.backfill.pending>0&&console.log(c.dim(` (${Ve(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)} ${de(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)} ${de(r.totalTokens).padStart(10)} ${c.accent(ne(r.cost.cents).padStart(10))}`)}}console.log("")}v();y();y();import{execFile as Ib}from"node:child_process";import{promisify as Mb}from"node:util";import{stat as Db}from"node:fs/promises";var ml=Mb(Ib),gl=1e4,$b="%H%x09%aI%x09%s";async function Pb(e){try{let{stdout:t}=await ml("git",["rev-parse","--is-inside-work-tree"],{cwd:e,timeout:gl});return t.trim()==="true"}catch{return!1}}async function jb(e,t,s){let n=["--no-pager","log","--all","--no-color","--since",t,"--until",s,`--pretty=format:${$b}`],{stdout:r}=await ml("git",n,{cwd:e,timeout:gl,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 Fb(e){return _().prepare(`SELECT id, cwd, started_at, ended_at
1445
+ FROM sessions WHERE id = ?`).get(e)??null}function Ub(e,t,s){if(s.length===0)return 0;let n=_(),r=new Date().toISOString(),o=n.prepare(`INSERT OR IGNORE INTO session_commits
1446
1446
  (session_id, commit_sha, committed_at, subject, cwd_snapshot, correlated_at)
1447
- VALUES (?, ?, ?, ?, ?, ?)`),i=0;return n.transaction(d=>{for(let c of d)o.run(e,c.commit_sha,c.committed_at,c.subject,t,r).changes>0&&(i+=1)})(s),i}async function Gr(e){let t=Ab(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 Cb(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 Nb(t.cwd))return{sessionId:e,status:"not-a-repo",commitsFound:0,commitsInserted:0};try{let o=await Ob(t.cwd,s,n),i=vb(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 ul(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 zr(e){let t=Fb(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 Db(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 Pb(t.cwd))return{sessionId:e,status:"not-a-repo",commitsFound:0,commitsInserted:0};try{let o=await jb(t.cwd,s,n),i=Ub(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 fl(e={}){let t=_(),s=Math.max(1,Math.min(1e5,e.limit??1e4)),n=t.prepare(`SELECT id FROM sessions
1448
1448
  WHERE cwd IS NOT NULL AND started_at IS NOT NULL AND ended_at IS NOT NULL
1449
1449
  ORDER BY COALESCE(ended_at, started_at) DESC
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 Gr(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 Qs(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 zr(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 Qs(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,
1451
1451
  NULLIF(sa.alias, '') AS alias,
1452
1452
  p.name AS project,
1453
1453
  s.started_at AS startedAt,
@@ -1461,33 +1461,33 @@ Top ${d.length} cluster(s):`);for(let c of d){let u=c.status==="resolved"?"\u271
1461
1461
  LEFT JOIN session_aliases sa ON sa.session_id = sc.session_id
1462
1462
  WHERE lower(sc.commit_sha) = lower(?)
1463
1463
  OR lower(sc.commit_sha) LIKE ?
1464
- ORDER BY COALESCE(sc.committed_at, s.started_at, '') DESC`).all(s,n)}function Ib(e){return _().prepare("SELECT id FROM sessions WHERE id = ? OR id LIKE ? LIMIT 1").get(e,`${e}%`)?.id??null}function Mb(e){let t=e.sessionId.slice(0,8);switch(e.status){case"ok":console.log(`${l.ok("\u2713")} ${l.dim(t)} ${l.bold(String(e.commitsFound))} commits (${e.commitsInserted} new)`);break;case"no-cwd":console.log(`${l.dim("\xB7")} ${l.dim(t)} no cwd recorded \u2014 skipped`);break;case"not-a-repo":console.log(`${l.dim("\xB7")} ${l.dim(t)} cwd is not a git worktree \u2014 skipped`);break;case"cwd-missing":console.log(`${l.dim("\xB7")} ${l.dim(t)} cwd no longer exists on disk \u2014 skipped`);break;case"no-window":console.log(`${l.dim("\xB7")} ${l.dim(t)} session has no time window yet \u2014 skipped`);break;case"error":console.log(`${l.err("\u2717")} ${l.dim(t)} ${e.error??"unknown error"}`);break}}async function pl(e,t){if(e){let r=Ib(e);if(!r){console.error(l.err(`no session matches '${e}'`)),process.exit(1);return}let o=await Gr(r);if(t.json){console.log(JSON.stringify(o,null,2));return}Mb(o);return}let s=t.limit?Math.max(1,Number(t.limit)):void 0;console.log(l.dim(`correlating sessions to git commits (limit ${s??"default"})\u2026`));let n=await ul({limit:s,onProgress:(r,o)=>{(r%25===0||r===o)&&process.stderr.write(`\r${l.dim(` ${r}/${o}`)}`)}});if(process.stderr.write(`
1465
- `),t.json){console.log(JSON.stringify(n,null,2));return}console.log(""),console.log(`${l.ok("correlated")}: ${l.bold(String(n.ok))} sessions \xB7 ${l.bold(String(n.commitsInserted))} new commits`),console.log(l.dim(` skipped ${n.skipped} (no cwd / non-repo / cwd missing), errors ${n.errors}`)),console.log("")}v();y();_t();import{existsSync as Qr,readFileSync as eo}from"node:fs";D();import{existsSync as Db,readFileSync as $b,writeFileSync as Pb}from"node:fs";import{join as jb}from"node:path";import{z as ue}from"zod";var zr=jb(R,"terminals.json"),ml=1440*60*1e3,Fb=3e4,Ub=6e4,Bb=ue.object({shell_pid:ue.number(),tab_name:ue.string(),cwd:ue.string().nullable().optional(),opened_at:ue.string(),last_seen_at:ue.string()}),Hb=ue.object({schema:ue.string().optional(),saved_at:ue.string().optional(),terminals:ue.array(Bb).max(500).default([]),sessions_by_pid:ue.record(ue.string(),ue.array(ue.string()).max(50)).optional().default({})}),gl=/^[⠀-⣿✳\s]+/,fl=/^\d+(\.\d+){1,3}$/;function Kr(e){let t=e.trim();return!!(!t||gl.test(t)||fl.test(t))}function _l(e){let t=e.trim();if(!t||fl.test(t))return null;let s=t.replace(gl,"").trim();return s.length>0?s:null}function qr(e,t){if(!Kr(e))return e;let s=_l(e);return s||(t&&!Kr(t)?t:e)}function Wb(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 Vr=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,!!Db(zr)))try{let t=$b(zr,"utf8"),s=JSON.parse(t),n=Hb.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 c of i)c.length>0&&d.add(c);d.size>0&&this.sessionsByPid.set(a,d)}this.gc()}catch{}}save(){try{$();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)]))};Pb(zr,JSON.stringify(t,null,2))}catch{}}upsert(t){this.ensureLoaded();let s=new Date().toISOString(),n=this.entries.get(t.shell_pid),r=qr(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=qr(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>Ub?(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=qr(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=Wb({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()-Fb;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()-ml;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()-ml;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 c=Date.parse(d.last_seen_at);if(Number.isFinite(c)&&c>=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}}},Zr=new Vr;ir();function hl(e){let t=Di(),s={...e};return t&&(s["x-recall-token"]=t),s}async function bt(e,t){let s=t?.headers??{};return fetch(e,{...t,headers:hl(s)})}async function rt(e,t,s,n){let r=s!==void 0?{"content-type":"application/json",...n}:{...n};return fetch(t,{method:e,headers:hl(r),body:s!==void 0?JSON.stringify(s):void 0})}D();function Jb(){let e=`${R}/daemon.port`;if(!Qr(e))return null;try{let t=eo(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function Yb(e,t){try{return(await rt("POST",`http://127.0.0.1:${e}/api/sessions/${encodeURIComponent(t)}/relink`,{clear:!0})).ok}catch{return!1}}function Gb(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 Bb(e){return _().prepare("SELECT id FROM sessions WHERE id = ? OR id LIKE ? LIMIT 1").get(e,`${e}%`)?.id??null}function Hb(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 _l(e,t){if(e){let r=Bb(e);if(!r){console.error(c.err(`no session matches '${e}'`)),process.exit(1);return}let o=await zr(r);if(t.json){console.log(JSON.stringify(o,null,2));return}Hb(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 fl({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();y();ht();import{existsSync as eo,readFileSync as to}from"node:fs";D();import{existsSync as Wb,readFileSync as Xb,writeFileSync as Jb}from"node:fs";import{join as Gb}from"node:path";import{z as ue}from"zod";var qr=Gb(R,"terminals.json"),hl=1440*60*1e3,Yb=3e4,zb=6e4,qb=ue.object({shell_pid:ue.number(),tab_name:ue.string(),cwd:ue.string().nullable().optional(),opened_at:ue.string(),last_seen_at:ue.string()}),Kb=ue.object({schema:ue.string().optional(),saved_at:ue.string().optional(),terminals:ue.array(qb).max(500).default([]),sessions_by_pid:ue.record(ue.string(),ue.array(ue.string()).max(50)).optional().default({})}),El=/^[⠀-⣿✳\s]+/,bl=/^\d+(\.\d+){1,3}$/;function Vr(e){let t=e.trim();return!!(!t||El.test(t)||bl.test(t))}function Sl(e){let t=e.trim();if(!t||bl.test(t))return null;let s=t.replace(El,"").trim();return s.length>0?s:null}function Kr(e,t){if(!Vr(e))return e;let s=Sl(e);return s||(t&&!Vr(t)?t:e)}function Vb(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 Zr=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,!!Wb(qr)))try{let t=Xb(qr,"utf8"),s=JSON.parse(t),n=Kb.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)]))};Jb(qr,JSON.stringify(t,null,2))}catch{}}upsert(t){this.ensureLoaded();let s=new Date().toISOString(),n=this.entries.get(t.shell_pid),r=Kr(t.tab_name,n?.tab_name),o=n?.opened_at??t.opened_at,i={...t,tab_name:r,opened_at:o,last_seen_at:s};return this.entries.set(t.shell_pid,i),this.gc(),this.save(),i}rename(t,s){this.ensureLoaded();let n=this.entries.get(t);if(!n)return null;let r=Kr(s,n.tab_name),o={...n,tab_name:r,last_seen_at:new Date().toISOString()};return this.entries.set(t,o),this.save(),o}remove(t){this.ensureLoaded();let s=this.entries.delete(t),n=this.sessionsByPid.delete(t);return this.outputTails.delete(t),this.pidOwnership.delete(t),(s||n)&&this.save(),s}claimPidOwnership(t,s,n=Date.now()){if(this.ensureLoaded(),!s)return"anonymous";let r=this.pidOwnership.get(t);return r?r.instance_id===s?(r.last_claim_at=n,"refreshed"):n-r.last_claim_at>zb?(this.pidOwnership.set(t,{instance_id:s,last_claim_at:n}),"claimed"):"rejected":(this.pidOwnership.set(t,{instance_id:s,last_claim_at:n}),"claimed")}pidOwnershipSnapshot(){return this.ensureLoaded(),Array.from(this.pidOwnership.entries()).map(([t,s])=>({shell_pid:t,instance_id:s.instance_id,last_claim_at:s.last_claim_at}))}sync(t){this.ensureLoaded();let s=new Date().toISOString(),n=0,r=0;for(let o of t){let i=this.entries.get(o.shell_pid),a=Kr(o.tab_name,i?.tab_name),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=Vb({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()-Yb;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()-hl;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()-hl;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}}},Qr=new Zr;D();function Qb(){let e=`${R}/daemon.port`;if(!eo(e))return null;try{let t=to(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function eS(e,t){try{return(await Qe("POST",`http://127.0.0.1:${e}/api/sessions/${encodeURIComponent(t)}/relink`,{clear:!0})).ok}catch{return!1}}function tS(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
1466
1466
  FROM sessions s
1467
1467
  JOIN projects p ON p.id = s.project_id
1468
1468
  JOIN session_aliases sa ON sa.session_id = s.id
1469
1469
  WHERE s.cwd IS NOT NULL
1470
1470
  AND s.started_at IS NOT NULL
1471
1471
  AND sa.alias IS NOT NULL
1472
- AND sa.alias <> ''${n}`).all(...r),i=new Map;for(let c of o){let u=c.cwd.replace(/\/+$/,""),p=i.get(u);p||(p=[],i.set(u,p)),p.push(c)}let a=e*1e3,d=new Map;for(let[c,u]of i){let p=new Map;for(let m of u){let f=p.get(m.alias);f||(f=[],p.set(m.alias,f)),f.push(m)}for(let m of p.values())if(!(m.length<2))for(let f of m){let g=new Set;for(let h of m)h.id!==f.id&&g.add(h.id);d.set(f.id,{row:f,cwdKey:c,reason:"duplicate-alias",siblingIds:g})}}for(let[c,u]of i){if(u.length<2)continue;u.sort((f,g)=>Date.parse(f.started_at)-Date.parse(g.started_at));let p=[],m=()=>{if(p.length>=2)for(let f of p){if(d.has(f.id))continue;let g=new Set;for(let h of p)h.id!==f.id&&g.add(h.id);d.set(f.id,{row:f,cwdKey:c,reason:"cwd-collision",siblingIds:g})}p=[]};for(let f of u){if(p.length===0){p.push(f);continue}let g=p[p.length-1];Date.parse(f.started_at)-Date.parse(g.started_at)<=a||m(),p.push(f)}m()}return Array.from(d.values()).map(c=>({session_id:c.row.id,project_name:c.row.project_name,cwd:c.cwdKey,started_at:c.row.started_at,alias:c.row.alias,sibling_ids:Array.from(c.siblingIds),reason:c.reason}))}function zb(e){let t=[];try{let s=`${R}/terminals.json`;if(!Qr(s))return t;let n=JSON.parse(eo(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 c=Number(a);if(!Number.isFinite(c))continue;let u=o.get(c)??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 f=p.get(m.alias);f||(f=[],p.set(m.alias,f)),f.push(m)}for(let m of p.values())if(!(m.length<2))for(let f of m){let g=new Set;for(let h of m)h.id!==f.id&&g.add(h.id);d.set(f.id,{row:f,cwdKey:l,reason:"duplicate-alias",siblingIds:g})}}for(let[l,u]of i){if(u.length<2)continue;u.sort((f,g)=>Date.parse(f.started_at)-Date.parse(g.started_at));let p=[],m=()=>{if(p.length>=2)for(let f of p){if(d.has(f.id))continue;let g=new Set;for(let h of p)h.id!==f.id&&g.add(h.id);d.set(f.id,{row:f,cwdKey:l,reason:"cwd-collision",siblingIds:g})}p=[]};for(let f of u){if(p.length===0){p.push(f);continue}let g=p[p.length-1];Date.parse(f.started_at)-Date.parse(g.started_at)<=a||m(),p.push(f)}m()}return Array.from(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 sS(e){let t=[];try{let s=`${R}/terminals.json`;if(!eo(s))return t;let n=JSON.parse(to(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,
1473
1473
  NULLIF(sa.alias, '') AS alias
1474
1474
  FROM sessions s
1475
1475
  JOIN projects p ON p.id = s.project_id
1476
1476
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
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 qb(e){let t=[],s=`${R}/terminals.json`;if(!Qr(s))return t;let n;try{n=JSON.parse(eo(s,"utf8"))}catch{return t}let r=new Map;for(let c of n.terminals??[]){if(!c.tab_name)continue;let u=r.get(c.tab_name);u||(u=[],r.set(c.tab_name,u)),u.push(c)}if(r.size===0)return t;let o=_(),i=e?" AND p.name = ?":"",a=e?[e]:[],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 nS(e){let t=[],s=`${R}/terminals.json`;if(!eo(s))return t;let n;try{n=JSON.parse(to(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
1478
1478
  FROM sessions s
1479
1479
  JOIN projects p ON p.id = s.project_id
1480
1480
  JOIN session_aliases sa ON sa.session_id = s.id
1481
1481
  WHERE s.started_at IS NOT NULL
1482
1482
  AND sa.alias IS NOT NULL
1483
- AND sa.alias <> ''${i}`).all(...a);for(let c of d){let u=r.get(c.alias);if(!u||u.length===0)continue;let p=Date.parse(c.started_at);if(!Number.isFinite(p))continue;let m=!1,f=null,g=1/0;for(let h of u){let E=Date.parse(h.opened_at);if(Number.isFinite(E)){if(E-p<=6e4){m=!0;break}E<g&&(g=E,f=h)}}m||!f||t.push({session_id:c.id,project_name:c.project_name,cwd:c.cwd.replace(/\/+$/,""),started_at:c.started_at,alias:c.alias,sibling_ids:[],reason:"temporal-anomaly",postdating_terminal:f})}return t}function Kb(e){if(e.length===0){console.log(l.ok("No suspicious correlations found."));return}console.log(l.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(l.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"?l.err("[dup-alias]"):r.reason==="orphan-link"?l.warn("[orphan-link]"):r.reason==="temporal-anomaly"?l.err("[temporal]"):l.warn("[cwd-collision]"),i=r.reason==="orphan-link"&&r.stale_terminal?`${l.dim("still pointing at pid")} ${r.stale_terminal.shell_pid} ${l.dim("=")} ${l.bold(`"${r.stale_terminal.tab_name}"`)}`:r.reason==="temporal-anomaly"&&r.postdating_terminal?`${l.bold(`"${r.alias}"`)} ${l.dim("\u2190 terminal opened")} ${r.postdating_terminal.opened_at.replace("T"," ").slice(0,19)} ${l.dim("(after session)")}`:l.bold(`"${r.alias}"`);console.log(` ${o} ${l.dim(r.session_id.slice(0,8))} ${l.dim(r.started_at.replace("T"," ").slice(0,19))} \u2192 ${i}`)}console.log()}}async function El(e){let t=e.window?Math.max(5,Math.min(600,Number(e.window)||60)):60,s=e.project?.trim()||void 0,n=Gb(t,s),r=zb(s),o=qb(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(Kb(a),!e.fix){a.length>0&&console.log(l.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=Jb(),c=0,u=0;for(let p of a){if(d){await Yb(d,p.session_id)?c++:(u++,console.error(l.err(`failed to clear ${p.session_id.slice(0,8)} via daemon`)));continue}try{ha(p.session_id),Zr.unlinkSession(p.session_id),c++}catch(m){u++,console.error(l.err(`failed to clear ${p.session_id.slice(0,8)}: ${m.message}`))}}console.log(l.ok(`Cleared ${c} suspect alias${c===1?"":"es"}.`)),u>0&&console.log(l.warn(`${u} clears failed; see errors above.`)),d||console.log(l.dim("Daemon was not running, so changes were applied directly to state files.")),console.log(l.dim("Open an affected session in the UI and use the \u{1F517} picker to pin the correct terminal."))}v();y();D();import{existsSync as Rl,readFileSync as rS,statSync as no,statfsSync as oS}from"node:fs";import{join as xl}from"node:path";import*as kl from"node:http";D();y();import{watch as tv}from"chokidar";import{readdirSync as sS,statSync as nv}from"node:fs";import{basename as cv,join as nS}from"node:path";import{execFile as Qb}from"node:child_process";import{promisify as eS}from"node:util";_t();y();import{execFile as Vb}from"node:child_process";import{promisify as Zb}from"node:util";var bA=Zb(Vb);var LA=eS(Qb);var NA=3600*1e3;y();D();import{basename as UA,join as to}from"node:path";y();D();import{join as tS}from"node:path";var MA=tS(R,"collections.json");var bl=to(R,"auto-rules"),XA=to(bl,"rules.json"),JA=to(bl,"suggestions.json");_t();function Sl(e){let t=e.split(/[/\\]/),s=t.findIndex(n=>n==="projects");return s===-1||s+1>=t.length?null:t[s+1]??null}function wl(e){return e.replace(/\\/g,"/").includes("/subagents/")}function*so(e){let t;try{t=sS(e,{withFileTypes:!0,encoding:"utf8"})}catch{return}for(let s of t){if(s.isSymbolicLink())continue;let n=nS(e,s.name);s.isDirectory()?yield*so(n):s.isFile()&&s.name.endsWith(".jsonl")&&(yield n)}}var iS=["VS Code","VS Code Insiders","Cursor","Windsurf","Warp","iTerm","Terminal","WezTerm","Windows Terminal","Kitty","Alacritty"],aS=new RegExp(`^(${iS.map(e=>e.replace(/ /g,"\\s")).join("|")})\\s\xB7\\s`);function cS(e){let t=[];for(let s of e)if(s.alias){if(aS.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 Cl=5*6e4,ro=24,Ll=.5;function lS(){let e=xl(R,"daemon.port");if(!Rl(e))return null;try{let t=rS(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 dS(e,t,s=1500){return new Promise(n=>{let r=kl.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 uS(){let e=xl(R,"terminals.json");if(!Rl(e))return{exists:!1,mtimeMs:null,ageSeconds:null};try{let t=no(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 pS(){let e=new Date(Date.now()-ro*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,f=null,g=1/0;for(let h of u){let E=Date.parse(h.opened_at);if(Number.isFinite(E)){if(E-p<=6e4){m=!0;break}E<g&&(g=E,f=h)}}m||!f||t.push({session_id: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:f})}return t}function rS(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 wl(e){let t=e.window?Math.max(5,Math.min(600,Number(e.window)||60)):60,s=e.project?.trim()||void 0,n=tS(t,s),r=sS(s),o=nS(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(rS(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=Qb(),l=0,u=0;for(let p of a){if(d){await eS(d,p.session_id)?l++:(u++,console.error(c.err(`failed to clear ${p.session_id.slice(0,8)} via daemon`)));continue}try{ba(p.session_id),Qr.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();y();D();import{existsSync as Cl,readFileSync as pS,statSync as ro,statfsSync as mS}from"node:fs";import{join as Ll}from"node:path";import*as Nl from"node:http";D();y();import{watch as fv}from"chokidar";import{readdirSync as dS,statSync as hv}from"node:fs";import{basename as yv,join as uS}from"node:path";import{execFile as aS}from"node:child_process";import{promisify as cS}from"node:util";ht();y();import{execFile as oS}from"node:child_process";import{promisify as iS}from"node:util";var AA=iS(oS);var UA=cS(aS);var BA=3600*1e3;y();D();import{basename as ZA,join as so}from"node:path";y();D();import{join as lS}from"node:path";var GA=lS(R,"collections.json");var yl=so(R,"auto-rules"),sv=so(yl,"rules.json"),nv=so(yl,"suggestions.json");ht();function Tl(e){let t=e.split(/[/\\]/),s=t.findIndex(n=>n==="projects");return s===-1||s+1>=t.length?null:t[s+1]??null}function Rl(e){return e.replace(/\\/g,"/").includes("/subagents/")}function*no(e){let t;try{t=dS(e,{withFileTypes:!0,encoding:"utf8"})}catch{return}for(let s of t){if(s.isSymbolicLink())continue;let n=uS(e,s.name);s.isDirectory()?yield*no(n):s.isFile()&&s.name.endsWith(".jsonl")&&(yield n)}}var gS=["VS Code","VS Code Insiders","Cursor","Windsurf","Warp","iTerm","Terminal","WezTerm","Windows Terminal","Kitty","Alacritty"],fS=new RegExp(`^(${gS.map(e=>e.replace(/ /g,"\\s")).join("|")})\\s\xB7\\s`);function _S(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 Ol=5*6e4,oo=24,Al=.5;function hS(){let e=Ll(R,"daemon.port");if(!Cl(e))return null;try{let t=pS(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 ES(e,t,s=1500){return new Promise(n=>{let r=Nl.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 bS(){let e=Ll(R,"terminals.json");if(!Cl(e))return{exists:!1,mtimeMs:null,ageSeconds:null};try{let t=ro(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 SS(){let e=new Date(Date.now()-oo*36e5).toISOString();try{let t=_().prepare(`SELECT
1484
1484
  COUNT(*) AS total,
1485
1485
  SUM(CASE WHEN sa.alias IS NULL OR sa.alias = '' THEN 1 ELSE 0 END) AS without_alias,
1486
1486
  SUM(CASE WHEN (sa.alias IS NULL OR sa.alias = '')
1487
1487
  AND s.auto_title_source = 'heuristic' THEN 1 ELSE 0 END) AS heuristic_only
1488
1488
  FROM sessions s
1489
1489
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
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 mS(){let e=lS(),t=uS(),s=pS(),n=!1,r=null,o=null,i=null,a=null,d=null;if(e){let p=await dS(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 c=[];if(n||c.push("Daemon not reachable on 127.0.0.1 \u2014 start it with `recall start` before further diagnosis."),i!==null&&i>0&&c.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)c.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>Cl&&c.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&&c.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&&c.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>=Ll&&c.push(`${s.heuristicOnly}/${s.total} sessions in the last ${ro}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?c.length>0?"degraded":"ok":"down",flags:c,daemon:{running:n,port:e,uptimeSeconds:r,version:o},runtime:{silentTerminalRejections:i,lastTerminalSyncAt:a,autoExtract:d},terminalsJson:t,recentSessions:s}}function St(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 yl(e){try{return no(e).size}catch{return 0}}function Tl(e){try{return _().prepare(`SELECT COUNT(*) AS n FROM ${e}_data WHERE block = 1`).get().n}catch{return 0}}function gS(){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 wS(){let e=hS(),t=bS(),s=SS(),n=!1,r=null,o=null,i=null,a=null,d=null;if(e){let p=await ES(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>Ol&&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>=Al&&l.push(`${s.heuristicOnly}/${s.total} sessions in the last ${oo}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 St(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 xl(e){try{return ro(e).size}catch{return 0}}function kl(e){try{return _().prepare(`SELECT COUNT(*) AS n FROM ${e}_data WHERE block = 1`).get().n}catch{return 0}}function yS(){try{return _().prepare(`SELECT p.name AS project,
1491
1491
  COALESCE(NULLIF(sa.alias, ''), s.auto_title, substr(s.first_user_message, 1, 60)) AS label,
1492
1492
  COUNT(*) AS count,
1493
1493
  MAX(CASE WHEN sa.alias IS NOT NULL AND sa.alias != '' THEN 1 ELSE 0 END) AS any_aliased
@@ -1499,27 +1499,27 @@ Top ${d.length} cluster(s):`);for(let c of d){let u=c.status==="resolved"?"\u271
1499
1499
  GROUP BY p.name, label
1500
1500
  HAVING count >= 2
1501
1501
  ORDER BY count DESC, label ASC
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 fS(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 S=t.pragma("quick_check").map(C=>C.quick_check);o=S.length===1&&S[0]==="ok"?"ok":S.join("; ")}catch(b){o=`check failed: ${b.message}`}let i=yl(te),a=yl(`${te}-wal`),d=0,c=0;try{let b=oS(R);d=Number(b.bavail)*Number(b.bsize),c=Number(b.blocks)*Number(b.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 TS(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 S=t.pragma("quick_check").map(T=>T.quick_check);o=S.length===1&&S[0]==="ok"?"ok":S.join("; ")}catch(b){o=`check failed: ${b.message}`}let i=xl(te),a=xl(`${te}-wal`),d=0,l=0;try{let b=mS(R);d=Number(b.bavail)*Number(b.bsize),l=Number(b.blocks)*Number(b.bsize)}catch{}e?.("Counting rows");let u=t.prepare(`SELECT
1503
1503
  (SELECT COUNT(*) FROM projects) AS projects,
1504
1504
  (SELECT COUNT(*) FROM sessions) AS sessions,
1505
1505
  (SELECT COUNT(*) FROM messages) AS messages,
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 ${St(d)} \u2014 heavy operations (synthesis, extract-outputs, vector ingest) may fail.`),a>50*1024**2&&m.push(`WAL is ${St(a)} \u2014 run \`recall optimize\` to truncate it.`),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 f=Tl("messages_fts"),g=Tl("sessions_fts");f>16&&m.push(`messages_fts has ${f} segments \u2014 \`recall optimize\` will merge them.`);let h=0;try{h=t.prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}catch{}let E=!1;try{E=t.prepare("SELECT value FROM app_settings WHERE key = 'semantic_enabled'").get()?.value==="1"}catch{}return!E&&h>0?m.push(`${h.toLocaleString()} rows in chunk_queue with semantic disabled \u2014 schema gate is stale; restart daemon (v0.67+) to migrate.`):h>1e5&&m.push(`chunk_queue has ${h.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:c},fts:{messages:{fragments:f},sessions:{fragments:g}},vectors:{rows:p},rows:{projects:u.projects,sessions:u.sessions,messages:u.messages,messageUsage:u.message_usage},chunkQueue:{size:h,semanticEnabled:E},warnings:m}}function _S(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 ${l.ok("\u2713")} ${s} ${l.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 ${St(d)} \u2014 heavy operations (synthesis, extract-outputs, vector ingest) may fail.`),a>50*1024**2&&m.push(`WAL is ${St(a)} \u2014 run \`recall optimize\` to truncate it.`),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 f=kl("messages_fts"),g=kl("sessions_fts");f>16&&m.push(`messages_fts has ${f} segments \u2014 \`recall optimize\` will merge them.`);let h=0;try{h=t.prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}catch{}let E=!1;try{E=t.prepare("SELECT value FROM app_settings WHERE key = 'semantic_enabled'").get()?.value==="1"}catch{}return!E&&h>0?m.push(`${h.toLocaleString()} rows in chunk_queue with semantic disabled \u2014 schema gate is stale; restart daemon (v0.67+) to migrate.`):h>1e5&&m.push(`chunk_queue has ${h.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:f},sessions:{fragments:g}},vectors:{rows:p},rows:{projects:u.projects,sessions:u.sessions,messages:u.messages,messageUsage:u.message_usage},chunkQueue:{size:h,semanticEnabled:E},warnings:m}}function RS(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})`)}
1507
1507
  `):process.stderr.write(` \u2713 ${s} (${i})
1508
- `),s=""};return{stage(o){r(),s=o,n=Date.now(),t?process.stderr.write(` ${l.dim("\u2026")} ${s}`):process.stderr.write(` \u2026 ${s}
1509
- `)},done:r}}function hS(){let e=_(),t=e.prepare("SELECT encoded_path FROM projects").all(),s=new Set(t.map(c=>c.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 c of so(Ct)){if(wl(c))continue;let u=Sl(c);if(!u||!s.has(u))continue;r+=1;let p;try{p=no(c).mtimeMs}catch{continue}let m=n.get(c);(!m||m.file_mtime<p)&&(o+=1,i.length<5&&i.push(c))}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(c=>c.split(/[/\\]/).pop()??c).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 Nl(e={}){let t=_S(!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
1508
+ `),s=""};return{stage(o){r(),s=o,n=Date.now(),t?process.stderr.write(` ${c.dim("\u2026")} ${s}`):process.stderr.write(` \u2026 ${s}
1509
+ `)},done:r}}function xS(){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 no(Ct)){if(Rl(l))continue;let u=Tl(l);if(!u||!s.has(u))continue;r+=1;let p;try{p=ro(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 vl(e={}){let t=RS(!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
1510
1510
  FROM session_aliases sa
1511
1511
  LEFT JOIN sessions s ON s.id = sa.session_id
1512
- WHERE sa.alias IS NOT NULL AND sa.alias != ''`).all(),n=cS(s),r=fS(t.stage);t.stage("Probing daemon");let o=await mS();t.stage("Detecting label collisions");let i=gS();t.stage("Checking ingest freshness");let a=hS();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(l.dim("\u2014 System health \u2014")),console.log(` Database ${St(r.db.sizeBytes)} (${r.rows.messages.toLocaleString()} messages across ${r.rows.sessions.toLocaleString()} sessions, ${r.rows.projects.toLocaleString()} projects)`),console.log(` WAL ${St(r.db.walSizeBytes)} (capped at 64 MB; truncated on clean shutdown)`),console.log(` Free pages ${r.db.freelistCount.toLocaleString()} (${St(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?l.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 ${St(r.disk.freeBytes)} of ${St(r.disk.totalBytes)} (${u.toFixed(1)}%)`)}if(console.log(` Integrity ${r.db.integrity==="ok"?l.ok("ok"):l.err(r.db.integrity)}`),r.warnings.length>0){console.log("");for(let u of r.warnings)console.log(` ${l.warn("!")} ${u}`)}if(console.log(""),console.log(l.dim("\u2014 Ingest freshness \u2014")),a.status==="ok")console.log(l.ok(` \u2713 ${a.scanned.toLocaleString()} JSONL${a.scanned===1?"":"s"} scanned, none newer than the index`));else if(a.status==="warn"){console.log(` ${l.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(` ${l.dim("\u2022")} ${u}`);console.log(l.dim(" Run `recall index` to force a reindex, or restart the daemon if persistent."))}else{console.log(` ${l.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(` ${l.dim("\u2022")} ${u}`);console.log(l.err(" Restart the daemon (recall stop && recall start) \u2014 the live watcher has fallen behind."))}if(console.log(""),console.log(l.dim("\u2014 Pipeline health (tab-name \u2192 session alias) \u2014")),o.daemon.running?console.log(` Daemon ${l.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 ${l.warn("not reachable")}`),o.runtime.silentTerminalRejections!==null){let u=o.runtime.silentTerminalRejections;console.log(` Auth rejections ${u===0?l.ok("0"):l.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 ${l.err("circuit broken")} (${u.reason??"unknown"} \u2014 toggle off/on to reset)`):u.consecutiveZeroTokenRuns>0&&console.log(` Auto-extract ${l.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>Cl;console.log(` Last ext sync ${m?l.warn(`${p} min ago`):l.ok(p===0?"just now":`${p} min ago`)} (most recent successful POST /api/terminal/sync)`)}else o.daemon.running&&console.log(` Last ext sync ${l.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?l.warn(`${u}h old`):l.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>=Ll&&d.total>=3;console.log(` Recent titles ${p?l.err(`${u}% heuristic`):l.ok(`${u}% heuristic`)} (${d.heuristicOnly}/${d.total} sessions in last ${ro}h fell back to first-message title)`)}if(o.flags.length>0){console.log("");for(let u of o.flags)console.log(` ${l.warn("!")} ${u}`)}if(console.log(""),console.log(l.dim("\u2014 Label collisions (last 7d) \u2014")),i.length===0)console.log(l.ok(" \u2713 no session-list label collisions in the last week"));else{let u=i.filter(p=>!p.anyAliased);console.log(` ${l.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?l.dim("partial alias"):l.warn("NO alias"),f=p.label.length>60?`${p.label.slice(0,57)}\u2026`:p.label;console.log(` ${l.dim(`${p.count}\xD7`)} ${f} ${m} ${l.dim(`(${p.project})`)}`)}i.length>5&&console.log(l.dim(` \u2026 and ${i.length-5} more (--json for full list)`)),console.log(""),console.log(l.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(l.dim(" <!-- claude-recall-alias: T2.1 Run-Prospects -->")),console.log(l.dim(` The watcher will read the header, alias the session, and strip the marker from the
1514
- displayed first user message. See docs/HANDOFF.md \u2192 "Alias header convention".`)),u.length>0&&(console.log(""),console.log(l.warn(` ${u.length} of these groups have NO alias on any row \u2014 strongest candidates
1515
- for the header-alias fix above.`)))}if(console.log(""),console.log(l.dim("\u2014 Tab-name invariant \u2014")),n.length===0)return console.log(l.ok(` \u2713 holds across ${s.length.toLocaleString()} aliased session${s.length===1?"":"s"}`)),console.log(l.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(l.err(`\u2717 ${n.length} invariant violation${n.length===1?"":"s"} found across ${s.length.toLocaleString()} aliased sessions`)),console.log("");let c=new Map;for(let u of n){let p=c.get(u.violation)??[];p.push(u),c.set(u.violation,p)}for(let[u,p]of c){console.log(l.warn(` ${u} (${p.length})`));for(let m of p.slice(0,10))console.log(` ${m.session_id.slice(0,8)} ${l.dim("\u2192")} ${JSON.stringify(m.alias)}`);p.length>10&&console.log(l.dim(` \u2026 and ${p.length-10} more (rerun with --json for the full list)`)),console.log("")}return console.log(l.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();y();D();import{existsSync as ES,readFileSync as bS}from"node:fs";import{join as SS}from"node:path";function wS(){let e=SS(R,"daemon.pid");if(!ES(e))return!1;try{let t=parseInt(bS(e,"utf-8").trim(),10);return!Number.isFinite(t)||t<=0?!1:(process.kill(t,0),!0)}catch{return!1}}async function ns(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 Ol(e={}){let t=_(),s=[];if(e.vacuum&&wS())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)+`
1516
- `),2):(console.error(l.err("\u2717 VACUUM requires the daemon to be stopped. Run `recall stop` first, then re-run with --vacuum.")),2);s.push(await ns("wal_checkpoint(TRUNCATE)",()=>{t.pragma("wal_checkpoint(TRUNCATE)")})),s.push(await ns("messages_fts optimize",()=>{t.exec("INSERT INTO messages_fts(messages_fts) VALUES('optimize');")})),s.push(await ns("sessions_fts optimize",()=>{t.exec("INSERT INTO sessions_fts(sessions_fts) VALUES('optimize');")})),s.push(await ns("PRAGMA optimize",()=>{t.exec("PRAGMA optimize")})),e.vacuum&&s.push(await ns("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)+`
1517
- `),n.length===0?0:1;for(let r of s){let o=r.ok?l.ok("\u2713"):l.err("\u2717"),i=`${r.durationMs} ms`;console.log(` ${o} ${r.step.padEnd(28)} ${l.dim(i)}`),r.error&&console.log(` ${l.err(r.error)}`)}return n.length===0?(console.log(""),console.log(l.ok("All maintenance passes completed.")),e.vacuum||console.log(l.dim(" Run `recall optimize --vacuum` (with the daemon stopped) to reclaim disk pages from deleted rows.")),0):(console.log(""),console.log(l.warn(`${n.length} step(s) failed \u2014 review the errors above.`)),1)}v();y();D();import{copyFileSync as yS,existsSync as TS,readFileSync as RS}from"node:fs";import{join as Al}from"node:path";function xS(){let e=Al(R,"daemon.pid");if(!TS(e))return!1;try{let t=parseInt(RS(e,"utf-8").trim(),10);return!Number.isFinite(t)||t<=0?!1:(process.kill(t,0),!0)}catch{return!1}}function kS(){let e=[];for(let t of Lt){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 vl(e={}){if(xS()&&!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(l.err(`\u2717 ${m}`)),2)}let t=kS();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})+`
1519
- `),0):(console.log(l.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:Lt.length,vacuumHint:!1,dryRun:!!e.dryRun},null,2)+`
1520
- `),0):(console.log(l.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:Lt.length,vacuumHint:!1,dryRun:!0};return e.json?(process.stdout.write(JSON.stringify(m,null,2)+`
1521
- `),0):(console.log(l.warn("\u2014 dry run, no changes \u2014")),console.log(` Phantoms found: ${l.dim(String(n))} sessions`),console.log(` Messages cascaded: ${l.dim(String(r))}`),console.log(` Aliases cascaded: ${l.dim(String(o))}`),console.log(l.dim(" Re-run without --dry-run to actually delete.")),0)}let i=Al(R,"db.sqlite"),a=new Date().toISOString().replace(/[-:T]/g,"").replace(/\..+$/,"").slice(0,15),d=`${i}.pre-phantom-purge-${a}`;yS(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:Lt.length,vacuumHint:n>100,dryRun:!1};return e.json?(process.stdout.write(JSON.stringify(p,null,2)+`
1522
- `),p.ok?0:1):(console.log(l.ok(`\u2713 Purged ${n} phantom session(s).`)),console.log(` Cascaded ${r} message(s) and ${o} alias row(s).`),console.log(` Backup: ${l.dim(d)}`),console.log(` Patterns applied: ${l.dim(String(Lt.length))}`),console.log(""),console.log(u===0?l.ok("All known phantom patterns are clear."):l.warn(`${u} phantom row(s) remain after purge \u2014 investigate.`)),p.vacuumHint&&(console.log(""),console.log(l.dim(" Reclaim the disk pages with `recall optimize --vacuum` (daemon must stay stopped)."))),console.log(l.dim(" Restart with `recall start` when ready.")),p.ok?0:1)}v();y();D();y();import{existsSync as CS}from"node:fs";import{join as LS}from"node:path";var en=LS(R,"archive.sqlite");var Il=!1;function Ml(){if(Il&&CS(en))return;$();let e=_(),t=en.replace(/'/g,"''");e.exec(`ATTACH DATABASE '${t}' AS archive`);try{e.exec(`
1512
+ WHERE sa.alias IS NOT NULL AND sa.alias != ''`).all(),n=_S(s),r=TS(t.stage);t.stage("Probing daemon");let o=await wS();t.stage("Detecting label collisions");let i=yS();t.stage("Checking ingest freshness");let a=xS();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 ${St(r.db.sizeBytes)} (${r.rows.messages.toLocaleString()} messages across ${r.rows.sessions.toLocaleString()} sessions, ${r.rows.projects.toLocaleString()} projects)`),console.log(` WAL ${St(r.db.walSizeBytes)} (capped at 64 MB; truncated on clean shutdown)`),console.log(` Free pages ${r.db.freelistCount.toLocaleString()} (${St(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 ${St(r.disk.freeBytes)} of ${St(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(""),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>Ol;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>=Al&&d.total>=3;console.log(` Recent titles ${p?c.err(`${u}% heuristic`):c.ok(`${u}% heuristic`)} (${d.heuristicOnly}/${d.total} sessions in last ${oo}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"),f=p.label.length>60?`${p.label.slice(0,57)}\u2026`:p.label;console.log(` ${c.dim(`${p.count}\xD7`)} ${f} ${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
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
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();y();D();import{existsSync as kS,readFileSync as CS}from"node:fs";import{join as LS}from"node:path";function NS(){let e=LS(R,"daemon.pid");if(!kS(e))return!1;try{let t=parseInt(CS(e,"utf-8").trim(),10);return!Number.isFinite(t)||t<=0?!1:(process.kill(t,0),!0)}catch{return!1}}async function ns(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 Il(e={}){let t=_(),s=[];if(e.vacuum&&NS())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)+`
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 ns("wal_checkpoint(TRUNCATE)",()=>{t.pragma("wal_checkpoint(TRUNCATE)")})),s.push(await ns("messages_fts optimize",()=>{t.exec("INSERT INTO messages_fts(messages_fts) VALUES('optimize');")})),s.push(await ns("sessions_fts optimize",()=>{t.exec("INSERT INTO sessions_fts(sessions_fts) VALUES('optimize');")})),s.push(await ns("PRAGMA optimize",()=>{t.exec("PRAGMA optimize")})),e.vacuum&&s.push(await ns("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)+`
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();y();D();import{copyFileSync as OS,existsSync as AS,readFileSync as vS}from"node:fs";import{join as Ml}from"node:path";function IS(){let e=Ml(R,"daemon.pid");if(!AS(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}}function MS(){let e=[];for(let t of Lt){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 Dl(e={}){if(IS()&&!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=MS();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})+`
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:Lt.length,vacuumHint:!1,dryRun:!!e.dryRun},null,2)+`
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:Lt.length,vacuumHint:!1,dryRun:!0};return e.json?(process.stdout.write(JSON.stringify(m,null,2)+`
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=Ml(R,"db.sqlite"),a=new Date().toISOString().replace(/[-:T]/g,"").replace(/\..+$/,"").slice(0,15),d=`${i}.pre-phantom-purge-${a}`;OS(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:Lt.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(Lt.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();y();D();y();import{existsSync as DS}from"node:fs";import{join as $S}from"node:path";var en=$S(R,"archive.sqlite");var $l=!1;function Pl(){if($l&&DS(en))return;P();let e=_(),t=en.replace(/'/g,"''");e.exec(`ATTACH DATABASE '${t}' AS archive`);try{e.exec(`
1523
1523
  CREATE TABLE IF NOT EXISTS archive.messages_archive (
1524
1524
  uuid TEXT PRIMARY KEY,
1525
1525
  session_id TEXT NOT NULL,
@@ -1534,7 +1534,7 @@ Top ${d.length} cluster(s):`);for(let c of d){let u=c.status==="resolved"?"\u271
1534
1534
  archived_at TEXT NOT NULL DEFAULT (datetime('now'))
1535
1535
  );
1536
1536
  CREATE INDEX IF NOT EXISTS archive.idx_messages_archive_session ON messages_archive(session_id);
1537
- `)}finally{e.exec("DETACH DATABASE archive")}Il=!0}import{existsSync as Dl,mkdirSync as NS,readFileSync as OS,writeFileSync as AS}from"node:fs";import{homedir as vS}from"node:os";import{join as $l}from"node:path";import{z as tn}from"zod";function Pl(){return process.env.RECALL_HOME??$l(vS(),".recall")}function IS(){let e=Pl();Dl(e)||NS(e,{recursive:!0})}function jl(){return $l(Pl(),"config.json")}var Fl=tn.object({autoArchiveEnabled:tn.boolean().default(!1),autoArchiveAfterDays:tn.number().int().min(7).max(3650).default(90),lastRunAt:tn.string().nullable().default(null)}),sn={autoArchiveEnabled:!1,autoArchiveAfterDays:90,lastRunAt:null};function Ul(){let e=jl();if(!Dl(e))return{};try{return JSON.parse(OS(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 Bl(){let e=Ul().retention;if(!e)return{...sn};let t=Fl.safeParse({...sn,...e});return t.success?t.data:{...sn}}function oo(e){IS();let t=Ul(),s=Fl.parse({...sn,...t.retention??{},...e}),n={...t,retention:s};return AS(jl(),JSON.stringify(n,null,2)),s}function io(e){Ml();let t=_(),s=en.replace(/'/g,"''");t.exec(`ATTACH DATABASE '${s}' AS archive`);try{return e(t)}finally{t.exec("DETACH DATABASE archive")}}function MS(){return io(e=>{let t=e.prepare(`SELECT
1537
+ `)}finally{e.exec("DETACH DATABASE archive")}$l=!0}import{existsSync as jl,mkdirSync as PS,readFileSync as jS,writeFileSync as FS}from"node:fs";import{homedir as US}from"node:os";import{join as Fl}from"node:path";import{z as tn}from"zod";function Ul(){return process.env.RECALL_HOME??Fl(US(),".recall")}function BS(){let e=Ul();jl(e)||PS(e,{recursive:!0})}function Bl(){return Fl(Ul(),"config.json")}var Hl=tn.object({autoArchiveEnabled:tn.boolean().default(!1),autoArchiveAfterDays:tn.number().int().min(7).max(3650).default(90),lastRunAt:tn.string().nullable().default(null)}),sn={autoArchiveEnabled:!1,autoArchiveAfterDays:90,lastRunAt:null};function Wl(){let e=Bl();if(!jl(e))return{};try{return JSON.parse(jS(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 Xl(){let e=Wl().retention;if(!e)return{...sn};let t=Hl.safeParse({...sn,...e});return t.success?t.data:{...sn}}function io(e){BS();let t=Wl(),s=Hl.parse({...sn,...t.retention??{},...e}),n={...t,retention:s};return FS(Bl(),JSON.stringify(n,null,2)),s}function ao(e){Pl();let t=_(),s=en.replace(/'/g,"''");t.exec(`ATTACH DATABASE '${s}' AS archive`);try{return e(t)}finally{t.exec("DETACH DATABASE archive")}}function HS(){return ao(e=>{let t=e.prepare(`SELECT
1538
1538
  SUM(CASE WHEN archive_status = 'archived' THEN 1 ELSE 0 END) AS archived,
1539
1539
  SUM(CASE WHEN archive_status != 'archived' THEN 1 ELSE 0 END) AS live
1540
1540
  FROM sessions`).get(),s=e.prepare("SELECT COUNT(*) AS n FROM messages").get().n,n=e.prepare(`SELECT
@@ -1543,15 +1543,15 @@ Top ${d.length} cluster(s):`);for(let c of d){let u=c.status==="resolved"?"\u271
1543
1543
  SELECT MAX(timestamp) AS t FROM main.messages_archive WHERE timestamp IS NOT NULL
1544
1544
  UNION ALL
1545
1545
  SELECT MAX(timestamp) AS t FROM archive.messages_archive WHERE timestamp IS NOT NULL
1546
- )`).get();return{liveSessions:t.live??0,archivedSessions:t.archived??0,liveMessages:s,archivedMessages:n,oldestLiveTimestamp:r.t,newestArchivedTimestamp:o.t}})}function Hl(e){return e?e.slice(0,10):"\u2014"}function DS(){let e=MS();return console.log(l.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 ${Hl(e.oldestLiveTimestamp)}`),console.log(` Newest archived ${Hl(e.newestArchivedTimestamp)}`),console.log(""),console.log(l.dim(" recall archive run --before YYYY-MM-DD")),console.log(l.dim(" recall archive restore <session-id>")),0}function $S(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 Jl(e){return e?e.slice(0,10):"\u2014"}function WS(){let e=HS();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 ${Jl(e.oldestLiveTimestamp)}`),console.log(` Newest archived ${Jl(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 XS(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
1547
1547
  FROM sessions s
1548
1548
  WHERE s.archive_status != 'archived'
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(l.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=io(a=>a.transaction(c=>{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=ao(a=>a.transaction(l=>{let u=0,p=a.prepare(`INSERT OR IGNORE INTO archive.messages_archive
1550
1550
  (uuid, session_id, parent_uuid, type, role, timestamp,
1551
1551
  is_sidechain, content_text, tool_names, raw_json, archived_at)
1552
1552
  SELECT uuid, session_id, parent_uuid, type, role, timestamp,
1553
1553
  is_sidechain, content_text, tool_names, raw_json, datetime('now')
1554
- FROM messages WHERE session_id = ?`),m=a.prepare("DELETE FROM messages WHERE session_id = ?"),f=a.prepare("UPDATE sessions SET archive_status = 'archived', archived_at = datetime('now') WHERE id = ?");for(let g of c){p.run(g);let h=m.run(g);u+=Number(h.changes??0),f.run(g)}return u})(r));return console.log(`Archived ${s.length.toLocaleString()} session(s), moved ${i.toLocaleString()} message(s) in ${Date.now()-o}ms.`),console.log(l.dim(" Run `recall optimize --vacuum` (with the daemon stopped) to reclaim disk pages from the moved rows.")),0}function PS(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=io(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 = ?"),f=a.prepare("UPDATE sessions SET archive_status = 'archived', archived_at = datetime('now') WHERE id = ?");for(let g of l){p.run(g);let h=m.run(g);u+=Number(h.changes??0),f.run(g)}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 JS(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=ao(r=>r.transaction(()=>{let i=r.prepare(`INSERT OR IGNORE INTO messages
1555
1555
  (uuid, session_id, parent_uuid, type, role, timestamp,
1556
1556
  is_sidechain, content_text, tool_names, raw_json)
1557
1557
  SELECT uuid, session_id, parent_uuid, type, role, timestamp,
@@ -1561,33 +1561,33 @@ Top ${d.length} cluster(s):`);for(let c of d){let u=c.status==="resolved"?"\u271
1561
1561
  is_sidechain, content_text, tool_names, raw_json)
1562
1562
  SELECT uuid, session_id, parent_uuid, type, role, timestamp,
1563
1563
  is_sidechain, content_text, tool_names, raw_json
1564
- FROM archive.messages_archive WHERE session_id = ?`),d=r.prepare("DELETE FROM main.messages_archive WHERE session_id = ?"),c=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),c.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 jS(){let e=Bl();return console.log(l.dim("\u2014 Auto-archive \u2014")),console.log(` Enabled ${e.autoArchiveEnabled?l.ok("YES"):"no"}`),console.log(` After ${e.autoArchiveAfterDays} days`),console.log(` Last run ${e.lastRunAt??"\u2014"}`),0}function FS(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=oo({autoArchiveEnabled:!0,autoArchiveAfterDays:t});return console.log(`Auto-archive: ENABLED (after ${s.autoArchiveAfterDays} days).`),console.log(l.dim(" The daemon will run a daily archive pass on the next tick.")),0}function US(){return oo({autoArchiveEnabled:!1}),console.log("Auto-archive: DISABLED. Existing archived sessions stay archived."),0}async function Wl(e){let t=e._action??"list";if(t==="list"||t==="stats")return DS();if(t==="run")return e.before?$S({before:e.before,dryRun:e.dryRun===!0}):(console.error("Usage: recall archive run --before YYYY-MM-DD [--dry-run]"),1);if(t==="restore")return PS(e._sessionId??"");if(t==="auto"){let s=e._subAction??"status";return s==="status"?jS():s==="on"||s==="enable"?FS(e.after):s==="off"||s==="disable"?US():(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 GS(){let e=Xl();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 YS(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=io({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 zS(){return io({autoArchiveEnabled:!1}),console.log("Auto-archive: DISABLED. Existing archived sessions stay archived."),0}async function Gl(e){let t=e._action??"list";if(t==="list"||t==="stats")return WS();if(t==="run")return e.before?XS({before:e.before,dryRun:e.dryRun===!0}):(console.error("Usage: recall archive run --before YYYY-MM-DD [--dry-run]"),1);if(t==="restore")return JS(e._sessionId??"");if(t==="auto"){let s=e._subAction??"status";return s==="status"?GS():s==="on"||s==="enable"?YS(e.after):s==="off"||s==="disable"?zS():(console.error("Usage: recall archive auto <status|on|off> [--after <days>]"),1)}return console.error(`Usage: recall archive <list|run|restore|auto> [args]
1565
1565
  list \u2014 show archive counts
1566
1566
  run --before YYYY-MM-DD [--dry-run] \u2014 move sessions older than DATE
1567
1567
  restore <session-id> \u2014 pull a session back from archive
1568
- auto <status|on|off> [--after N] \u2014 daemon auto-archives sessions older than N days`),1}v();y();D();import{existsSync as BS,readFileSync as HS}from"node:fs";function WS(){let e=`${R}/daemon.port`;if(!BS(e))return null;try{let t=HS(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}function XS(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();y();D();import{existsSync as qS,readFileSync as KS}from"node:fs";function VS(){let e=`${R}/daemon.port`;if(!qS(e))return null;try{let t=KS(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}function ZS(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}
1569
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}"
1570
1570
  `),null):(process.stderr.write(`ambiguous session prefix "${e}". be more specific.
1571
- `),null)}async function Xl(e,t,s){let n=XS(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=WS();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 rt("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 Yl(e,t,s){let n=ZS(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=VS();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 Qe("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}
1573
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}
1574
- `),process.exitCode=1;return}let a={session_id:n,alias:r};if(s.json){console.log(JSON.stringify(a));return}console.log(`${l.ok("renamed")} ${l.dim(n.slice(0,8))} \u2192 ${l.bold(`"${r}"`)}`)}v();y();var Gl=90;async function JS(){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 bt(`http://127.0.0.1:${s}/api/terminal/registry`);return n.ok?await n.json():null}catch{return null}}function YS(){let e=Date.now()/1e3-Gl;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();y();var Kl=90;async function QS(){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 Ye(`http://127.0.0.1:${s}/api/terminal/registry`);return n.ok?await n.json():null}catch{return null}}function ew(){let e=Date.now()/1e3-Kl;return _().prepare(`SELECT s.id, s.cwd, s.file_mtime, NULLIF(sa.alias, '') AS alias
1575
1575
  FROM sessions s
1576
1576
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1577
1577
  WHERE s.cwd IS NOT NULL AND s.file_mtime > ?
1578
- ORDER BY s.cwd, s.file_mtime DESC`).all(e)}var GS=new Set(["zsh","bash","fish","sh","dash","ksh","tcsh","csh","pwsh","powershell","cmd","nu"]);function Jl(e){let t=e.trim().toLowerCase().replace(/^[-/]+/,"").replace(/^.*\//,"").replace(/\s*\(\d+\)\s*$/,"").trim();return!t||GS.has(t)}var zS=/^[⠀-⣿✳\s]+/,qS=/^\d+(\.\d+){1,3}$/;function Yl(e){let t=e.trim();return!!(!t||zS.test(t)||qS.test(t))}async function zl(e){let t=await JS(),s=YS();if(e.json){console.log(JSON.stringify({registry:t,active:s},null,2));return}if(console.log(),console.log(l.bold("TERMINAL REGISTRY")),console.log(l.dim("(what the daemon thinks each VS Code terminal is named)")),console.log(),!t){console.log(l.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(l.dim(` cwd: ${o}`));for(let a of i){let d=Jl(a.tab_name),c=Yl(a.tab_name),p=!d&&!c?l.ok("[usable]"):d?l.warn("[generic-shell]"):l.warn("[claude-auto]");console.log(` ${p} pid ${a.shell_pid} ${l.bold(`"${a.tab_name}"`)}`)}console.log()}if(console.log(l.bold(`ACTIVE SESSIONS (mtime within last ${Gl}s)`)),console.log(l.dim("(sessions whose JSONL is being actively written)")),console.log(),s.length===0){console.log(l.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(l.dim(` cwd: ${o}`));for(let a of i)console.log(` ${l.dim(a.id.slice(0,8))} ${l.bold(a.alias??"(no alias)")} ${l.dim(`mtime ${new Date(a.file_mtime*1e3).toISOString().slice(11,19)}`)}`);console.log()}console.log(l.bold("LAYER 5 SWEEP DECISIONS")),console.log(l.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(c=>!Jl(c.tab_name)&&!Yl(c.tab_name));d.length===0?console.log(` ${l.warn("skip")} ${l.dim(o)} ${l.dim("\u2014 no usable terminal name (all generic or claude-auto)")}`):d.length>1?console.log(` ${l.warn("refuse")} ${l.dim(o)} ${l.dim(`\u2014 ${d.length} usable terminals, ambiguous`)}`):i.length>1?console.log(` ${l.warn("refuse")} ${l.dim(o)} ${l.dim(`\u2014 ${i.length} active sessions, ambiguous`)}`):console.log(` ${l.ok("link")} ${l.dim(o)} ${l.dim("\u2192")} ${l.dim(i[0].id.slice(0,8))} ${l.dim("=")} ${l.bold(`"${d[0].tab_name}"`)}`)}console.log()}v();y();D();import{existsSync as KS,readFileSync as VS}from"node:fs";function ZS(){let e=`${R}/daemon.port`;if(!KS(e))return null;try{let t=VS(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function QS(e){try{let t=await bt(`http://127.0.0.1:${e}/api/terminal/registry`);return t.ok?(await t.json()).terminals??[]:[]}catch{return[]}}async function ew(e,t,s){try{return(await rt("POST",`http://127.0.0.1:${e}/api/sessions/${encodeURIComponent(t)}/relink`,{shell_pid:s})).ok}catch{return!1}}function tw(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 sw(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}`,c=s.get(d);c||(c=new Set,s.set(d,c)),c.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 tw=new Set(["zsh","bash","fish","sh","dash","ksh","tcsh","csh","pwsh","powershell","cmd","nu"]);function zl(e){let t=e.trim().toLowerCase().replace(/^[-/]+/,"").replace(/^.*\//,"").replace(/\s*\(\d+\)\s*$/,"").trim();return!t||tw.has(t)}var sw=/^[⠀-⣿✳\s]+/,nw=/^\d+(\.\d+){1,3}$/;function ql(e){let t=e.trim();return!!(!t||sw.test(t)||nw.test(t))}async function Vl(e){let t=await QS(),s=ew();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=zl(a.tab_name),l=ql(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 ${Kl}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=>!zl(l.tab_name)&&!ql(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();y();D();import{existsSync as rw,readFileSync as ow}from"node:fs";function iw(){let e=`${R}/daemon.port`;if(!rw(e))return null;try{let t=ow(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function aw(e){try{let t=await Ye(`http://127.0.0.1:${e}/api/terminal/registry`);return t.ok?(await t.json()).terminals??[]:[]}catch{return[]}}async function cw(e,t,s){try{return(await Qe("POST",`http://127.0.0.1:${e}/api/sessions/${encodeURIComponent(t)}/relink`,{shell_pid:s})).ok}catch{return!1}}function lw(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 dw(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
1579
1579
  FROM session_aliases sa
1580
1580
  JOIN sessions s ON s.id = sa.session_id
1581
- WHERE sa.alias = '' AND sa.previous_aliases != '[]' AND s.cwd IS NOT NULL`).all(),o=[];for(let i of r){let a=tw(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 ql(e){let t=ZS();t||(console.error(l.err("Daemon is not running. Run `recall start` first.")),process.exit(1));let s=await QS(t);s.length===0&&(console.error(l.err("Registry is empty. Open VS Code with the extension to populate it.")),process.exit(1));let n=sw(s);if(e.json){console.log(JSON.stringify({candidates:n},null,2));return}if(n.length===0){console.log(l.dim("No restorable sessions found.")),console.log(l.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(l.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(l.dim(` cwd: ${a}`));for(let c of d)console.log(` ${l.dim(c.session_id.slice(0,8))} ${l.dim("\u2192 pid")} ${c.matching_pid} ${l.dim("=")} ${l.bold(`"${c.alias_to_restore}"`)}`);console.log()}if(!e.apply){console.log(l.dim("Re-run with --apply to restore these aliases."));return}let o=0,i=0;for(let a of n)await ew(t,a.session_id,a.matching_pid)?o++:(i++,console.error(l.err(`failed to restore ${a.session_id.slice(0,8)}`)));console.log(l.ok(`Restored ${o} alias${o===1?"":"es"}.${i>0?` ${i} failed.`:""}`)),console.log(l.dim("Sessions whose previous alias did not cleanly match a current terminal still need manual relink via the \u{1F517} picker."))}v();async function Kl(e,t){let s=e.trim();if(!/^[0-9a-fA-F]{4,40}$/.test(s)){console.error(l.err(`not a valid commit SHA: '${e}'`)),process.exit(1);return}let n=Qs(s);if(t.json){console.log(JSON.stringify(n,null,2));return}if(n.length===0){console.log(""),console.log(l.dim(`no correlated sessions for ${s}`)),console.log(l.dim(" (if you haven't yet, run `recall correlate` to backfill)")),console.log("");return}console.log(""),console.log(`${l.bold("commit")} ${l.accent(n[0].commitSha.slice(0,12))} ${l.dim(n[0].committedAt??"")}`),n[0].subject&&console.log(` ${n[0].subject}`),console.log(""),console.log(l.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(` ${l.accent(o.padEnd(24))} ${l.dim((r.project??"").slice(0,24).padEnd(26))} ${l.dim(r.startedAt??"")}`),console.log(` ${l.dim(`recall show ${r.sessionId}`)}`)}console.log("")}v();y();import{execFile as nw}from"node:child_process";import{promisify as rw}from"node:util";import{stat as ow}from"node:fs/promises";var iw=rw(nw),aw=60,cw=7,lw=7,dw=5e3;function uw(){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=lw(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 Zl(e){let t=iw();t||(console.error(c.err("Daemon is not running. Run `recall start` first.")),process.exit(1));let s=await aw(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=dw(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 cw(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 Ql(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=Qs(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();y();import{execFile as uw}from"node:child_process";import{promisify as pw}from"node:util";import{stat as mw}from"node:fs/promises";var gw=pw(uw),fw=60,_w=7,hw=7,Ew=5e3;function bw(){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
1582
1582
  WHERE (COALESCE(total_input_tokens,0)
1583
1583
  + COALESCE(total_output_tokens,0)
1584
1584
  + COALESCE(total_cache_create_tokens,0)
1585
1585
  + COALESCE(total_cache_read_tokens,0)) > 0
1586
- LIMIT 1`),git:t("SELECT 1 FROM session_commits LIMIT 1")}}function ao(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 Vl(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 pw(){let e=_(),t=e.prepare(`SELECT ss.keywords
1586
+ LIMIT 1`),git:t("SELECT 1 FROM session_commits LIMIT 1")}}function co(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 ed(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 Sw(){let e=_(),t=e.prepare(`SELECT ss.keywords
1587
1587
  FROM session_semantic ss
1588
1588
  JOIN sessions s ON s.id = ss.session_id
1589
1589
  WHERE s.started_at IS NOT NULL
1590
- AND julianday('now') - julianday(s.started_at) <= @windowDays`).all({windowDays:cw});if(t.length===0)return null;let s=new Set;for(let o of t)for(let i of ao(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:_w});if(t.length===0)return null;let s=new Set;for(let o of t)for(let i of co(o.keywords))s.add(i);if(s.size===0)return null;let n=e.prepare(`SELECT ss.session_id AS session_id,
1591
1591
  ss.summary AS summary,
1592
1592
  ss.keywords AS keywords,
1593
1593
  p.name AS project,
@@ -1603,7 +1603,7 @@ Top ${d.length} cluster(s):`);for(let c of d){let u=c.status==="resolved"?"\u271
1603
1603
  WHERE s.started_at IS NOT NULL
1604
1604
  AND s.message_count > 2
1605
1605
  AND julianday('now') - julianday(s.started_at) >= @ageDays
1606
- ORDER BY s.started_at ASC`).all({ageDays:aw});if(n.length===0)return null;let r=null;for(let o of n){let a=ao(o.keywords).filter(d=>s.has(d));a.length!==0&&(!r||a.length>r.overlap.length)&&(r={row:o,overlap:a})}return r?{...Vl(r.row),summary:r.row.summary,keywords:ao(r.row.keywords),matchedKeywords:r.overlap,daysAgo:Math.max(0,Math.round(r.row.days_old))}:null}function mw(){let t=_().prepare(`SELECT s.id AS session_id,
1606
+ ORDER BY s.started_at ASC`).all({ageDays:fw});if(n.length===0)return null;let r=null;for(let o of n){let a=co(o.keywords).filter(d=>s.has(d));a.length!==0&&(!r||a.length>r.overlap.length)&&(r={row:o,overlap:a})}return r?{...ed(r.row),summary:r.row.summary,keywords:co(r.row.keywords),matchedKeywords:r.overlap,daysAgo:Math.max(0,Math.round(r.row.days_old))}:null}function ww(){let t=_().prepare(`SELECT s.id AS session_id,
1607
1607
  p.name AS project,
1608
1608
  NULLIF(sa.alias, '') AS alias,
1609
1609
  s.started_at AS started_at,
@@ -1622,54 +1622,54 @@ Top ${d.length} cluster(s):`);for(let c of d){let u=c.status==="resolved"?"\u271
1622
1622
  AND (COALESCE(s.total_input_tokens, 0)
1623
1623
  + COALESCE(s.total_output_tokens, 0)
1624
1624
  + COALESCE(s.total_cache_create_tokens, 0)
1625
- + COALESCE(s.total_cache_read_tokens, 0)) > 0`).all({windowDays:lw});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?{...Vl(s.row),totalTokens:s.totalTokens,costCents:s.cents,costDisplay:ne(s.cents),tokensDisplay:de(s.totalTokens),primaryModel:s.row.primary_model,primaryModelLabel:nt(s.row.primary_model).label}:null}async function gw(e){try{if(!(await ow(e)).isDirectory())return null}catch{return null}try{let{stdout:t}=await iw("git",["rev-parse","HEAD"],{cwd:e,timeout:dw}),s=t.trim();return/^[0-9a-f]{40}$/.test(s)?s:null}catch{return null}}async function fw(){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:hw});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?{...ed(s.row),totalTokens:s.totalTokens,costCents:s.cents,costDisplay:ne(s.cents),tokensDisplay:de(s.totalTokens),primaryModel:s.row.primary_model,primaryModelLabel:ot(s.row.primary_model).label}:null}async function yw(e){try{if(!(await mw(e)).isDirectory())return null}catch{return null}try{let{stdout:t}=await gw("git",["rev-parse","HEAD"],{cwd:e,timeout:Ew}),s=t.trim();return/^[0-9a-f]{40}$/.test(s)?s:null}catch{return null}}async function Tw(){let e=_(),t=e.prepare(`SELECT s.id AS id, s.cwd AS cwd
1626
1626
  FROM sessions s
1627
1627
  WHERE s.cwd IS NOT NULL AND s.started_at IS NOT NULL
1628
1628
  ORDER BY COALESCE(s.ended_at, s.started_at, '') DESC
1629
- LIMIT 1`).get();if(!t?.cwd)return null;let s=await gw(t.cwd);if(!s)return null;let n=Qs(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 yw(t.cwd);if(!s)return null;let n=Qs(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
1630
1630
  FROM sessions s
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 Zl(){let e=uw(),t=e.semantic?Promise.resolve().then(()=>{try{return pw()}catch(a){return console.error("[discover.rediscovered]",a),null}}):Promise.resolve(null),s=e.cost?Promise.resolve().then(()=>{try{return mw()}catch(a){return console.error("[discover.expensive]",a),null}}):Promise.resolve(null),n=e.git?fw().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 lo(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 co(e){return e.alias??(e.firstUserMessage?lo(e.firstUserMessage,60):null)??e.sessionId.slice(0,8)}function _w(e){let t=e.rediscovered||e.expensive||e.authored;if(console.log(""),console.log(l.bold("today \xB7 for you")),console.log(l.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(l.dim(" no picks today.")),s.length>0?console.log(l.dim(" enable: "+s.join(", "))):console.log(l.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(` ${l.tool("\u2726 rediscovered")} ${l.dim(`(${s.daysAgo}d ago)`)}`),console.log(` ${l.bold(co(s))} ${l.dim(s.project?`\xB7 ${s.project}`:"")}`),console.log(` ${l.dim(s.sessionId.slice(0,8))}`),s.matchedKeywords.length>0&&console.log(" "+l.dim("matched: ")+s.matchedKeywords.slice(0,6).map(n=>l.tool(`#${n}`)).join(" ")),s.summary&&console.log(" "+l.dim(lo(s.summary,100)))}if(e.expensive){let s=e.expensive;console.log(""),console.log(` ${l.accent("$ most expensive \xB7 7d")} ${l.bold(s.costDisplay)} ${l.dim(`(${s.tokensDisplay} \xB7 ${s.primaryModelLabel})`)}`),console.log(` ${l.bold(co(s))} ${l.dim(s.project?`\xB7 ${s.project}`:"")}`),console.log(` ${l.dim(s.sessionId.slice(0,8))} ${l.dim(s.startedAt?W(s.startedAt):"")}`)}if(e.authored){let s=e.authored;console.log(""),console.log(` ${l.ok("\u2387 authored current HEAD")} ${l.bold(s.shortSha)} ${l.dim(s.committedAt?`(${W(s.committedAt)})`:"")}`),console.log(` ${l.bold(co(s))} ${l.dim(s.project?`\xB7 ${s.project}`:"")}`),s.subject&&console.log(` ${l.dim(lo(s.subject,80))}`),console.log(` ${l.dim(s.sessionId.slice(0,8))} ${l.dim("cwd: "+s.cwd)}`)}console.log("")}async function Ql(e){let t=await Zl();if(e.json){console.log(JSON.stringify(t,null,2));return}_w(t)}v();Ze();import{spawnSync as nd}from"node:child_process";import{readdirSync as hw}from"node:fs";import{join as Ew,resolve as bw}from"node:path";var uo=["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"}],Sw="https://marketplace.visualstudio.com/items?itemName=clauderecallhq.clauderecall-vscode";function ww(){return Ew(le(),"extensions","vscode")}function yw(){let e=ww(),t;try{t=hw(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})),bw(e,s[0]))}function td(e){let t=nd(e,["--version"],{stdio:"ignore",shell:process.platform==="win32"});return t.error?!1:t.status===0}function Tw(e,t){let s=nd(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(l.err(`no bundled .vsix found at extensions/vscode/(clauderecall|claude-recall)-vscode-*.vsix
1632
- `)),process.stderr.write(l.dim(`see PUBLISHING.md for how to build the extension, or run:
1633
- `)),process.stderr.write(l.dim(` (cd extensions/vscode && npm install && npm run build && npm run package)
1634
- `))}function Rw(e){return uo.includes(e)}async function rd(e){if(e.editor!==void 0&&!Rw(e.editor)){process.stderr.write(l.err(`unknown --editor target: ${e.editor}
1635
- `)),process.stderr.write(l.dim(`valid values: ${uo.join(", ")}
1636
- `)),process.exitCode=1;return}let t=yw();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(!td(r)){process.stderr.write(l.err(`editor CLI not found on PATH: ${r}
1638
- `)),process.stderr.write(l.dim(`install the editor shell integration, or omit --editor to install into every detected editor.
1639
- `)),process.stderr.write(l.dim(`see PUBLISHING.md for manual install instructions.
1640
- `)),process.exitCode=1;return}s=[ed.find(i=>i.id===r)??{id:r,label:r}]}else s=ed.filter(r=>td(r.id));if(s.length===0){process.stderr.write(l.err(`no supported editor CLI detected on PATH.
1641
- `)),process.stderr.write(l.dim(`looked for: ${uo.join(", ")}.
1642
- `)),process.stderr.write(l.dim(`install the editor shell integration and try again.
1643
- `)),process.stderr.write(l.dim(`see PUBLISHING.md for manual install instructions.
1644
- `)),process.exitCode=1;return}process.stderr.write(l.dim(`bundled .vsix: ${t}
1645
-
1646
- `));let n=!1;for(let r of s){let{ok:o,message:i}=Tw(r.id,t);o?process.stderr.write(l.ok(`\u2713 installed into ${r.label} (${r.id})
1647
- `)):(n=!0,process.stderr.write(l.err(`\u2717 ${r.label} (${r.id}): ${i}
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 td(){let e=bw(),t=e.semantic?Promise.resolve().then(()=>{try{return Sw()}catch(a){return console.error("[discover.rediscovered]",a),null}}):Promise.resolve(null),s=e.cost?Promise.resolve().then(()=>{try{return ww()}catch(a){return console.error("[discover.expensive]",a),null}}):Promise.resolve(null),n=e.git?Tw().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 uo(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 lo(e){return e.alias??(e.firstUserMessage?uo(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(lo(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(uo(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(lo(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(lo(s))} ${c.dim(s.project?`\xB7 ${s.project}`:"")}`),s.subject&&console.log(` ${c.dim(uo(s.subject,80))}`),console.log(` ${c.dim(s.sessionId.slice(0,8))} ${c.dim("cwd: "+s.cwd)}`)}console.log("")}async function sd(e){let t=await td();if(e.json){console.log(JSON.stringify(t,null,2));return}Rw(t)}v();et();import{spawnSync as id}from"node:child_process";import{readdirSync as xw}from"node:fs";import{join as kw,resolve as Cw}from"node:path";var po=["code","cursor","code-insiders","windsurf"],nd=[{id:"code",label:"VS Code"},{id:"cursor",label:"Cursor"},{id:"code-insiders",label:"VS Code Insiders"},{id:"windsurf",label:"Windsurf"}],Lw="https://marketplace.visualstudio.com/items?itemName=clauderecallhq.clauderecall-vscode";function Nw(){return kw(le(),"extensions","vscode")}function Ow(){let e=Nw(),t;try{t=xw(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})),Cw(e,s[0]))}function rd(e){let t=id(e,["--version"],{stdio:"ignore",shell:process.platform==="win32"});return t.error?!1:t.status===0}function Aw(e,t){let s=id(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 od(){process.stderr.write(c.err(`no bundled .vsix found at extensions/vscode/(clauderecall|claude-recall)-vscode-*.vsix
1632
+ `)),process.stderr.write(c.dim(`see PUBLISHING.md for how to build the extension, or run:
1633
+ `)),process.stderr.write(c.dim(` (cd extensions/vscode && npm install && npm run build && npm run package)
1634
+ `))}function vw(e){return po.includes(e)}async function ad(e){if(e.editor!==void 0&&!vw(e.editor)){process.stderr.write(c.err(`unknown --editor target: ${e.editor}
1635
+ `)),process.stderr.write(c.dim(`valid values: ${po.join(", ")}
1636
+ `)),process.exitCode=1;return}let t=Ow();if(e.printPath){if(!t){od(),process.exitCode=1;return}process.stdout.write(t+`
1637
+ `);return}if(!t){od(),process.exitCode=1;return}let s;if(e.editor){let r=e.editor;if(!rd(r)){process.stderr.write(c.err(`editor CLI not found on PATH: ${r}
1638
+ `)),process.stderr.write(c.dim(`install the editor shell integration, or omit --editor to install into every detected editor.
1639
+ `)),process.stderr.write(c.dim(`see PUBLISHING.md for manual install instructions.
1640
+ `)),process.exitCode=1;return}s=[nd.find(i=>i.id===r)??{id:r,label:r}]}else s=nd.filter(r=>rd(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: ${po.join(", ")}.
1642
+ `)),process.stderr.write(c.dim(`install the editor shell integration and try again.
1643
+ `)),process.stderr.write(c.dim(`see PUBLISHING.md for manual install instructions.
1644
+ `)),process.exitCode=1;return}process.stderr.write(c.dim(`bundled .vsix: ${t}
1645
+
1646
+ `));let n=!1;for(let r of s){let{ok:o,message:i}=Aw(r.id,t);o?process.stderr.write(c.ok(`\u2713 installed into ${r.label} (${r.id})
1647
+ `)):(n=!0,process.stderr.write(c.err(`\u2717 ${r.label} (${r.id}): ${i}
1648
1648
  `)))}process.stderr.write(`
1649
- `),process.stderr.write(l.bold(`next steps:
1649
+ `),process.stderr.write(c.bold(`next steps:
1650
1650
  `)),process.stderr.write(` 1. reload the editor window: Cmd/Ctrl+Shift+P then pick "Developer: Reload Window"
1651
1651
  `),process.stderr.write(` 2. enable the extension: open settings and set "claude-recall.autoAlias" to true
1652
1652
  `),process.stderr.write(`
1653
- `),process.stderr.write(l.dim(`marketplace install: ${Sw}
1654
- `)),n&&(process.exitCode=1)}fo();v();function _o(e){return e>=70?l.ok:e>=40?l.warn:l.err}function id(e,t=20){let s=Math.round(e/100*t);return"\u2588".repeat(s)+"\u2591".repeat(t-s)}function xw(e){let t=_o(e.score);process.stdout.write(`
1655
- ${l.bold(e.projectName)} ${t(String(e.score)+"/100")}
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=_o(o);process.stdout.write(` ${r.padEnd(10)} ${a(id(o,16))} ${String(Math.round(o)).padStart(3)}% ${l.dim(i)}
1657
- `)}}function ad(e,t){if(e){let r=mo(e);if(!r){process.stderr.write(l.err(`project "${e}" not found
1653
+ `),process.stderr.write(c.dim(`marketplace install: ${Lw}
1654
+ `)),n&&(process.exitCode=1)}_o();v();function ho(e){return e>=70?c.ok:e>=40?c.warn:c.err}function ld(e,t=20){let s=Math.round(e/100*t);return"\u2588".repeat(s)+"\u2591".repeat(t-s)}function Iw(e){let t=ho(e.score);process.stdout.write(`
1655
+ ${c.bold(e.projectName)} ${t(String(e.score)+"/100")}
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=ho(o);process.stdout.write(` ${r.padEnd(10)} ${a(ld(o,16))} ${String(Math.round(o)).padStart(3)}% ${c.dim(i)}
1657
+ `)}}function dd(e,t){if(e){let r=go(e);if(!r){process.stderr.write(c.err(`project "${e}" not found
1658
1658
  `)),process.exitCode=1;return}if(t.json){process.stdout.write(JSON.stringify(r,null,2)+`
1659
- `);return}xw(r);return}let s=go();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)+`
1660
- `);return}let n=[...s].sort((r,o)=>r.score-o.score);process.stdout.write(l.bold("Memory Health Scores")+` (worst first)
1659
+ `);return}Iw(r);return}let s=fo();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)+`
1660
+ `);return}let n=[...s].sort((r,o)=>r.score-o.score);process.stdout.write(c.bold("Memory Health Scores")+` (worst first)
1661
1661
 
1662
- `);for(let r of n){let o=_o(r.score);process.stdout.write(` ${o(id(r.score,12))} ${String(r.score).padStart(3)}/100 ${r.projectName}
1662
+ `);for(let r of n){let o=ho(r.score);process.stdout.write(` ${o(ld(r.score,12))} ${String(r.score).padStart(3)}/100 ${r.projectName}
1663
1663
  `)}process.stdout.write(`
1664
- `)}v();function cd(e){if(e==="on"){zn(!0),process.stdout.write(l.ok("Verification badges enabled.")+`
1665
- `);return}if(e==="off"){zn(!1),process.stdout.write(`Verification badges disabled.
1666
- `);return}let t=hs();process.stdout.write(`Verification badges: ${t?l.ok("ON"):"OFF"}
1664
+ `)}v();function ud(e){if(e==="on"){qn(!0),process.stdout.write(c.ok("Verification badges enabled.")+`
1665
+ `);return}if(e==="off"){qn(!1),process.stdout.write(`Verification badges disabled.
1666
+ `);return}let t=hs();process.stdout.write(`Verification badges: ${t?c.ok("ON"):"OFF"}
1667
1667
  `),process.stdout.write(`
1668
1668
  Toggle with: recall verify on | off
1669
- `)}v();ws();Kn();Gt();Vn();import{hostname as qw}from"node:os";import{randomBytes as Kw}from"node:crypto";Ge();he();D();y();Ze();import{existsSync as kw}from"node:fs";import Cw from"node:readline";import{createRequire as Lw}from"node:module";import{Chalk as Nw}from"chalk";var Ow=Lw(import.meta.url),Aw=Ow(`${le()}/package.json`).version,pd="#f97316",vw="#8b9098",Iw="#10b981",Mw="#f59e0b",Mt=new Nw({level:process.env.NO_COLOR?0:3}),be=Mt.hex(pd),re=Mt.hex(pd).bold,I=Mt.hex(vw),wt=Mt.hex(Iw),nn=Mt.hex(Mw),md=Mt.bold,gd=[" \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"],Dw=gd[0]?.length??49,ld="Never lose a Claude Code session again.",$w="CLAUDE RECALL";function Pw(){if(!kw(te))return{sessions:0,projects:0};try{let t=_().prepare(`SELECT
1669
+ `)}v();ws();Vn();Yt();Zn();import{hostname as ny}from"node:os";import{randomBytes as ry}from"node:crypto";ze();he();D();y();et();import{existsSync as Mw}from"node:fs";import Dw from"node:readline";import{createRequire as $w}from"node:module";import{Chalk as Pw}from"chalk";var jw=$w(import.meta.url),Fw=jw(`${le()}/package.json`).version,fd="#f97316",Uw="#8b9098",Bw="#10b981",Hw="#f59e0b",Mt=new Pw({level:process.env.NO_COLOR?0:3}),be=Mt.hex(fd),re=Mt.hex(fd).bold,I=Mt.hex(Uw),wt=Mt.hex(Bw),nn=Mt.hex(Hw),_d=Mt.bold,hd=[" \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"],Ww=hd[0]?.length??49,pd="Never lose a Claude Code session again.",Xw="CLAUDE RECALL";function Jw(){if(!Mw(te))return{sessions:0,projects:0};try{let t=_().prepare(`SELECT
1670
1670
  (SELECT COUNT(*) FROM sessions) AS sessions,
1671
- (SELECT COUNT(*) FROM projects) AS projects`).get();return{sessions:t.sessions,projects:t.projects}}catch{return{sessions:0,projects:0}}}function jw(){let e=process.stdout.columns;return typeof e!="number"||e<=0?!1:e<Dw+2}function fd(){if(jw()){console.log(`${re($w)} ${I("\xB7")} ${I(ld)}`);return}for(let e of gd)console.log(re(e));console.log(I(ld))}async function Fw(){return{daemon:Z(),counts:Pw(),license:await Te()}}function Uw(e){let t=[];if(t.push(` ${I("Version:")} ${be(`v${Aw}`)} ${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:")} ${nn("stopped")}`);if(e.counts.sessions===0)t.push(` ${I("Sessions:")} ${nn("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 rn=[{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"}]}],Hw=rn.reduce((e,t)=>e+t.commands.length,0),Ww=new Set([...rn.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 dd(){let e=rn.flatMap(s=>s.commands.map(n=>`recall ${n.name}`)),t=Math.max(...e.map(s=>s.length));console.log(),console.log(`${md("COMMANDS")} ${I(`\xB7 ${Hw} 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 rn){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 Xw(){return!!process.stdin.isTTY&&!!process.stdout.isTTY}async function Jw(){if(!Xw())return;let e=Cw.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==="?"){dd(),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===""){dd(),n();return}let d=(i.split(/\s+/)[0]??"").toLowerCase();Ww.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 _d(){let e=await Fw();console.log(),fd(),console.log();for(let t of Uw(e))console.log(t);console.log(),console.log(Bw(e)),console.log(),await Jw()}var Yw=[{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 Gw(){return process.env.NO_COLOR||process.env.CI||process.env.RECALL_NO_ANIMATION?!1:!!process.stdout.isTTY}function ho(e){return new Promise(t=>setTimeout(t,e))}function zw(e){let s=(e.split("@")[0]??"").split(/[._+\-]/)[0]??"";return s?s.charAt(0).toUpperCase()+s.slice(1).toLowerCase():""}function ud(){process.stdout.write("\r\x1B[2K")}async function hd(e){let t=Gw();console.log(),fd(),console.log(),t&&(process.stdout.write(` ${I("Verifying license...")}`),await ho(260),ud()),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(` ${nn("!")} ${nn("Test mode:")} this license was issued in test mode.`),console.log(),console.log(` ${md("Unlocking Pro features")}`),console.log();for(let r of Yw)t&&(process.stdout.write(` ${I("\xB7")} ${I(r.name)}`),await ho(110),ud()),console.log(` ${wt("\u2713")} ${r.name} ${I(r.detail)}`);t&&await ho(160),console.log();let s=zw(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()}async function Ed(e){let t=e.trim();t.length<8&&(console.error(l.warn("License key looks too short. Paste the full key from your purchase email.")),process.exit(1));let s=`${qw()}-${Kw(4).toString("hex")}`,n=`${Nt()}/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:Ss()})})}catch(a){let d=a instanceof Error?a.message:"unknown error";console.error(l.warn(`Could not reach activation server at ${n}: ${d}`)),console.error(l.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(l.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(l.warn(`Activation refused: ${a}`)),process.exit(1)}let i=await bs(o.license_jwt);(!i.valid||!i.claims)&&(console.error(l.warn(`Server returned a JWT that fails local verification: ${i.reason??"unknown"}`)),console.error(l.dim("This usually means the CLI is older than the server, or the public key was rotated.")),process.exit(1)),Ti({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 hd({...i.claims,key_short:o.key_short??i.claims.key_short,email:o.customer_email??i.claims.email})}v();import{spawn as Vw}from"node:child_process";import{platform as on}from"node:os";var bd="https://clauderecall.com/pricing";function Zw(e){let t=on()==="darwin"?"open":on()==="win32"?"start":"xdg-open",s=on()==="win32"?["",e]:[e];Vw(t,s,{detached:!0,stdio:"ignore",shell:on()==="win32"}).unref()}async function Sd(){let{getLicenseStatus:e}=await Promise.resolve().then(()=>(he(),Ts)),t=await e();if(t.tier==="pro"){console.log(),console.log(l.bold("Already on Pro.")),console.log(` ${l.dim("Key:")} ${t.key_short}`),console.log(` ${l.dim("Email:")} ${t.customer_email}`),console.log();return}console.log(),console.log(`${l.ok("Opening")} ${bd}`),console.log(l.dim("After purchase, run: recall activate <license-key>")),console.log(),Zw(bd)}v();import{spawn as Qw}from"node:child_process";import{platform as an}from"node:os";var wd="https://clauderecall.com/pricing?trial=1&utm_source=cli&utm_medium=recall_trial";function ey(e){let t=an()==="darwin"?"open":an()==="win32"?"start":"xdg-open",s=an()==="win32"?["",e]:[e];Qw(t,s,{detached:!0,stdio:"ignore",shell:an()==="win32"}).unref()}async function yd(){let{getLicenseStatus:e}=await Promise.resolve().then(()=>(he(),Ts)),t=await e();if(t.tier==="pro"){console.log(),console.log(l.bold("You are already on Pro.")),console.log(` ${l.dim("Key:")} ${t.key_short}`),console.log(` ${l.dim("Email:")} ${t.customer_email}`),console.log();return}console.log(),console.log(`${l.ok("Opening")} ${wd}`),console.log(l.dim("Enter your email to get a 7-day Pro trial link. No card.")),console.log(l.dim("After you click the verification email, run: recall activate <key>")),console.log(),ey(wd)}v();ws();import{existsSync as Td,mkdirSync as ty,readFileSync as sy,writeFileSync as ny}from"node:fs";import{homedir as ry}from"node:os";import{join as Rd}from"node:path";import{randomBytes as oy}from"node:crypto";var bo=Rd(ry(),".recall"),ln=Rd(bo,"telemetry.json"),Eo={decided_at:null,decision:null,last_ping_month:null,nonce_month:null,nonce:null,last_error:null};function yt(){if(!Td(ln))return{...Eo};try{let e=sy(ln,"utf8"),t=JSON.parse(e);return{...Eo,...t}}catch{return{...Eo}}}function cn(e){Td(bo)||ty(bo,{recursive:!0}),ny(ln,JSON.stringify(e,null,2)+`
1672
- `,{mode:384})}function xd(){return ln}function So(e=new Date){let t=e.getUTCFullYear(),s=String(e.getUTCMonth()+1).padStart(2,"0");return`${t}-${s}`}function kd(e,t){return e.nonce&&e.nonce_month===t?e:{...e,nonce:oy(16).toString("hex"),nonce_month:t}}function iy(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 Cd(e){let t=yt();if(t.decision!=="on")return{status:t.decision==="off"?"opted-out":"no-decision"};let s=So();if(t.last_ping_month===s)return{status:"already-this-month"};t=kd(t,s);let n=iy(e,t);if(!n)return{status:"error",detail:"no nonce"};try{let r=await fetch(`${Nt()}/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 cn({...t,last_error:`${new Date().toISOString()} ${i}`}),{status:"error",detail:i}}let o=await r.json().catch(()=>({}));return cn({...t,last_ping_month:s,last_error:null}),{status:o.deduped?"deduped":"sent"}}catch(r){let o=r instanceof Error?r.message:"unknown";return cn({...t,last_error:`${new Date().toISOString()} ${o}`}),{status:"error",detail:o}}}function Dt(e){let s={...yt(),decision:e,decided_at:new Date().toISOString(),last_error:null,...e==="off"?{nonce:null,nonce_month:null,last_ping_month:null}:{}};return cn(s),s}function dn(e){let t=kd(yt(),So());return{event:"install",version:e,platform:process.platform,arch:process.arch,month:t.nonce_month??So(),nonce:t.nonce??"0".repeat(32)}}async function wo(e){let t=yt();console.log(),console.log(l.bold("Telemetry \u2014 anonymous install ping")),console.log(` ${l.dim("decision:")} ${t.decision??"not yet decided"}`),console.log(` ${l.dim("decided at:")} ${t.decided_at??"\u2014"}`),console.log(` ${l.dim("last ping:")} ${t.last_ping_month??"\u2014"}`),console.log(` ${l.dim("state file:")} ${xd()}`),t.last_error&&console.log(` ${l.warn("last error:")} ${t.last_error}`),console.log(),console.log(l.dim("Next-ping payload preview (only sent if decision = on):")),console.log(l.dim(JSON.stringify(dn(e),null,2))),console.log(),console.log(l.dim("Toggle with `recall telemetry on` / `recall telemetry off`.")),console.log(l.dim("Full disclosure: https://clauderecall.com/telemetry")),console.log()}async function Ld(){Dt("on"),console.log(),console.log(l.ok("Telemetry: opted in.")),console.log(l.dim("One anonymous ping per machine per month. No PII. Source: docs/specs/v0.16-install-ping.md")),console.log(l.dim("Reverse with `recall telemetry off`.")),console.log()}async function Nd(){Dt("off"),console.log(),console.log(l.ok("Telemetry: opted out.")),console.log(l.dim("No further pings will be sent. Existing nonce deleted.")),console.log()}async function Od(e){await wo(e)}import{createInterface as ay}from"node:readline/promises";import{stdin as Ad,stdout as pe}from"node:process";var cy=new Set(["telemetry","trial","upgrade","activate","license","help","version"]);function ly(e){return!(process.env.CI==="true"||process.env.RECALL_QUIET_INSTALL==="1"||process.env.RECALL_DISABLE_TELEMETRY_PROMPT==="1"||!Ad.isTTY||!pe.isTTY||e&&cy.has(e)||yt().decision!==null)}async function vd(e,t){if(!ly(e))return;let s=dn(t);pe.write(`
1671
+ (SELECT COUNT(*) FROM projects) AS projects`).get();return{sessions:t.sessions,projects:t.projects}}catch{return{sessions:0,projects:0}}}function Gw(){let e=process.stdout.columns;return typeof e!="number"||e<=0?!1:e<Ww+2}function Ed(){if(Gw()){console.log(`${re(Xw)} ${I("\xB7")} ${I(pd)}`);return}for(let e of hd)console.log(re(e));console.log(I(pd))}async function Yw(){return{daemon:Q(),counts:Jw(),license:await Te()}}function zw(e){let t=[];if(t.push(` ${I("Version:")} ${be(`v${Fw}`)} ${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:")} ${nn("stopped")}`);if(e.counts.sessions===0)t.push(` ${I("Sessions:")} ${nn("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 qw(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 rn=[{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"}]}],Kw=rn.reduce((e,t)=>e+t.commands.length,0),Vw=new Set([...rn.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 md(){let e=rn.flatMap(s=>s.commands.map(n=>`recall ${n.name}`)),t=Math.max(...e.map(s=>s.length));console.log(),console.log(`${_d("COMMANDS")} ${I(`\xB7 ${Kw} 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 rn){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 Zw(){return!!process.stdin.isTTY&&!!process.stdout.isTTY}async function Qw(){if(!Zw())return;let e=Dw.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==="?"){md(),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===""){md(),n();return}let d=(i.split(/\s+/)[0]??"").toLowerCase();Vw.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 bd(){let e=await Yw();console.log(),Ed(),console.log();for(let t of zw(e))console.log(t);console.log(),console.log(qw(e)),console.log(),await Qw()}var ey=[{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 ty(){return process.env.NO_COLOR||process.env.CI||process.env.RECALL_NO_ANIMATION?!1:!!process.stdout.isTTY}function Eo(e){return new Promise(t=>setTimeout(t,e))}function sy(e){let s=(e.split("@")[0]??"").split(/[._+\-]/)[0]??"";return s?s.charAt(0).toUpperCase()+s.slice(1).toLowerCase():""}function gd(){process.stdout.write("\r\x1B[2K")}async function Sd(e){let t=ty();console.log(),Ed(),console.log(),t&&(process.stdout.write(` ${I("Verifying license...")}`),await Eo(260),gd()),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(` ${nn("!")} ${nn("Test mode:")} this license was issued in test mode.`),console.log(),console.log(` ${_d("Unlocking Pro features")}`),console.log();for(let r of ey)t&&(process.stdout.write(` ${I("\xB7")} ${I(r.name)}`),await Eo(110),gd()),console.log(` ${wt("\u2713")} ${r.name} ${I(r.detail)}`);t&&await Eo(160),console.log();let s=sy(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()}async function wd(e){let t=e.trim();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=`${ny()}-${ry(4).toString("hex")}`,n=`${Nt()}/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:Ss()})})}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 bs(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)),Ti({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 Sd({...i.claims,key_short:o.key_short??i.claims.key_short,email:o.customer_email??i.claims.email})}v();import{spawn as oy}from"node:child_process";import{platform as on}from"node:os";var yd="https://clauderecall.com/pricing";function iy(e){let t=on()==="darwin"?"open":on()==="win32"?"start":"xdg-open",s=on()==="win32"?["",e]:[e];oy(t,s,{detached:!0,stdio:"ignore",shell:on()==="win32"}).unref()}async function Td(){let{getLicenseStatus:e}=await Promise.resolve().then(()=>(he(),Ts)),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")} ${yd}`),console.log(c.dim("After purchase, run: recall activate <license-key>")),console.log(),iy(yd)}v();import{spawn as ay}from"node:child_process";import{platform as an}from"node:os";var Rd="https://clauderecall.com/pricing?trial=1&utm_source=cli&utm_medium=recall_trial";function cy(e){let t=an()==="darwin"?"open":an()==="win32"?"start":"xdg-open",s=an()==="win32"?["",e]:[e];ay(t,s,{detached:!0,stdio:"ignore",shell:an()==="win32"}).unref()}async function xd(){let{getLicenseStatus:e}=await Promise.resolve().then(()=>(he(),Ts)),t=await e();if(t.tier==="pro"){console.log(),console.log(c.bold("You are 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")} ${Rd}`),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(),cy(Rd)}v();ws();import{existsSync as kd,mkdirSync as ly,readFileSync as dy,writeFileSync as uy}from"node:fs";import{homedir as py}from"node:os";import{join as Cd}from"node:path";import{randomBytes as my}from"node:crypto";var So=Cd(py(),".recall"),ln=Cd(So,"telemetry.json"),bo={decided_at:null,decision:null,last_ping_month:null,nonce_month:null,nonce:null,last_error:null};function yt(){if(!kd(ln))return{...bo};try{let e=dy(ln,"utf8"),t=JSON.parse(e);return{...bo,...t}}catch{return{...bo}}}function cn(e){kd(So)||ly(So,{recursive:!0}),uy(ln,JSON.stringify(e,null,2)+`
1672
+ `,{mode:384})}function Ld(){return ln}function wo(e=new Date){let t=e.getUTCFullYear(),s=String(e.getUTCMonth()+1).padStart(2,"0");return`${t}-${s}`}function Nd(e,t){return e.nonce&&e.nonce_month===t?e:{...e,nonce:my(16).toString("hex"),nonce_month:t}}function gy(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 Od(e){let t=yt();if(t.decision!=="on")return{status:t.decision==="off"?"opted-out":"no-decision"};let s=wo();if(t.last_ping_month===s)return{status:"already-this-month"};t=Nd(t,s);let n=gy(e,t);if(!n)return{status:"error",detail:"no nonce"};try{let r=await fetch(`${Nt()}/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 cn({...t,last_error:`${new Date().toISOString()} ${i}`}),{status:"error",detail:i}}let o=await r.json().catch(()=>({}));return cn({...t,last_ping_month:s,last_error:null}),{status:o.deduped?"deduped":"sent"}}catch(r){let o=r instanceof Error?r.message:"unknown";return cn({...t,last_error:`${new Date().toISOString()} ${o}`}),{status:"error",detail:o}}}function Dt(e){let s={...yt(),decision:e,decided_at:new Date().toISOString(),last_error:null,...e==="off"?{nonce:null,nonce_month:null,last_ping_month:null}:{}};return cn(s),s}function dn(e){let t=Nd(yt(),wo());return{event:"install",version:e,platform:process.platform,arch:process.arch,month:t.nonce_month??wo(),nonce:t.nonce??"0".repeat(32)}}async function yo(e){let t=yt();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:")} ${Ld()}`),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(dn(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 Ad(){Dt("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 vd(){Dt("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 Id(e){await yo(e)}import{createInterface as fy}from"node:readline/promises";import{stdin as Md,stdout as pe}from"node:process";var _y=new Set(["telemetry","trial","upgrade","activate","license","help","version"]);function hy(e){return!(process.env.CI==="true"||process.env.RECALL_QUIET_INSTALL==="1"||process.env.RECALL_DISABLE_TELEMETRY_PROMPT==="1"||!Md.isTTY||!pe.isTTY||e&&_y.has(e)||yt().decision!==null)}async function Dd(e,t){if(!hy(e))return;let s=dn(t);pe.write(`
1673
1673
  `),pe.write(` Claude Recall \u2014 anonymous install ping?
1674
1674
 
1675
1675
  `),pe.write(` npm download counts mix real installs with bots and scanners.
@@ -1685,54 +1685,54 @@ Toggle with: recall verify on | off
1685
1685
 
1686
1686
  `),pe.write(` Full disclosure: https://clauderecall.com/telemetry
1687
1687
 
1688
- `);let n=ay({input:Ad,output:pe}),r;try{r=(await n.question(" Send the install ping? [y/N]: ")).trim().toLowerCase()}finally{n.close()}r==="y"||r==="yes"?(Dt("on"),pe.write(`
1688
+ `);let n=fy({input:Md,output:pe}),r;try{r=(await n.question(" Send the install ping? [y/N]: ")).trim().toLowerCase()}finally{n.close()}r==="y"||r==="yes"?(Dt("on"),pe.write(`
1689
1689
  Opted in. Reverse any time with \`recall telemetry off\`.
1690
1690
 
1691
1691
  `)):(Dt("off"),pe.write(`
1692
1692
  Opted out. No pings will be sent. Reverse with \`recall telemetry on\`.
1693
1693
 
1694
- `))}v();he();Gt();Qn();async function Id(){let e=await Te();if(console.log(),e.tier==="free"){console.log(l.bold("Tier: Free")),console.log(l.dim("Free includes: index, list, show, projects, status, the daemon, and the basic web UI.")),e.invalid_reason&&(console.log(),console.log(l.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(l.bold("Tier: Pro")),console.log(` ${l.dim("Key:")} ${e.key_short}`),console.log(` ${l.dim("Email:")} ${e.customer_email}`),console.log(` ${l.dim("Activated:")} ${e.activated_at}`),e.expires_at&&console.log(` ${l.dim("Expires:")} ${e.expires_at}`),e.test_mode&&console.log(` ${l.warn("Test mode:")} this license was issued in test mode.`);let t=ys();t&&console.log(` ${l.dim("Last server check:")} ${t.last_checked_at}`),console.log()}async function Md(){let e=await or({force:!0});if(console.log(),!e.ran){console.log(l.warn("No license stored on this machine.")),console.log(l.dim("Run `recall activate <license-key>` first.")),console.log();return}if(!e.last_checked_at){console.log(l.warn("Could not reach the license server.")),console.log(l.dim("Network error. Try again when you have a connection.")),console.log();return}if(e.revoked){console.log(l.warn("License is revoked.")),e.reason&&console.log(` ${l.dim("Reason:")} ${e.reason}`),console.log(` ${l.dim("Checked:")} ${e.last_checked_at}`),console.log();return}console.log(l.ok("License is valid.")),console.log(` ${l.dim("Checked:")} ${e.last_checked_at}`),console.log()}function Dd(){Ri(),console.log(),console.log("License removed from this machine."),console.log(l.dim(`(${ft})`)),console.log()}y();v();import dy 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();he();Yt();er();async function $d(){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=ys();t&&console.log(` ${c.dim("Last server check:")} ${t.last_checked_at}`),console.log()}async function Pd(){let e=await ir({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 jd(){Ri(),console.log(),console.log("License removed from this machine."),console.log(c.dim(`(${_t})`)),console.log()}y();v();import Ey 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}
1695
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}"
1696
1696
  `),null;process.stderr.write(`ambiguous thread prefix "${e}" \u2014 candidates:
1697
- `);for(let n of s)process.stderr.write(` ${H(n.id)} ${n.name}
1697
+ `);for(let n of s)process.stderr.write(` ${W(n.id)} ${n.name}
1698
1698
  `);return null}function Tt(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}
1699
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}"
1700
1700
  `),null):(process.stderr.write(`ambiguous session prefix "${e}". be more specific.
1701
- `),null)}function uy(e){let t=new Map;if(e.length===0)return t;let s=e.map(()=>"?").join(","),r=_().prepare(`SELECT s.id,
1701
+ `),null)}function by(e){let t=new Map;if(e.length===0)return t;let s=e.map(()=>"?").join(","),r=_().prepare(`SELECT s.id,
1702
1702
  s.first_user_message,
1703
1703
  p.name AS project_name,
1704
1704
  a.alias AS alias
1705
1705
  FROM sessions s
1706
1706
  LEFT JOIN projects p ON p.id = s.project_id
1707
1707
  LEFT JOIN session_aliases a ON a.session_id = s.id
1708
- WHERE s.id IN (${s})`).all(...e);for(let o of r)t.set(o.id,o);return t}function $d(e,t){let s=t.get(e),n=l.accent(H(e));if(!s)return`${n} ${l.dim("(unindexed)")}`;let r=s.alias??s.first_user_message??"",o=s.project_name?l.project(`[${s.project_name}] `):"";return`${n} ${o}${q(r,80)}`}function yo(e){return e.archived?"archived":e.closed_at?"closed":"open"}function $t(e){let t=yo(e);process.stderr.write(l.ok(`\u2713 ${e.name} ${l.dim(`(${H(e.id)})`)} [${t}]
1708
+ WHERE s.id IN (${s})`).all(...e);for(let o of r)t.set(o.id,o);return t}function Fd(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 To(e){return e.archived?"archived":e.closed_at?"closed":"open"}function $t(e){let t=To(e);process.stderr.write(c.ok(`\u2713 ${e.name} ${c.dim(`(${W(e.id)})`)} [${t}]
1709
1709
  `))}function xe(e,t,s){if(e){process.stdout.write(JSON.stringify(t,null,2)+`
1710
- `);return}s()}function Pd(e){let t=ur({includeArchived:e.archived===!0});xe(e.json===!0,t,()=>{if(t.length===0){console.log(l.dim("no threads. create one with `recall thread new <name>`."));return}let s=new dy({head:[l.bold("id"),l.bold("name"),l.bold("sessions"),l.bold("origins"),l.bold("status"),l.bold("created")],colWidths:[10,40,10,9,10,16],wordWrap:!0,style:{head:[],border:["grey"]}});for(let n of t)s.push([l.accent(H(n.id)),q(n.name,38),String(n.session_count),String(n.origin_count),yo(n),l.dim(W(n.created_at))]);console.log(s.toString()),console.log(l.dim(`${t.length} thread${t.length===1?"":"s"}.`+(e.archived?"":" add --archived to include archived.")))})}function py(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 c=n.get(d)??[];c.push(a),n.set(d,c)}let o=new Set,i=(a,d,c,u)=>{if(o.has(a.session_id))return;o.add(a.session_id);let p=u?"":c?"\u2514\u2500 ":"\u251C\u2500 ",m=a.role==="origin"?l.warn("[origin] "):"";process.stdout.write(`${d}${p}${m}${$d(a.session_id,t)}
1711
- `);let f=n.get(a.session_id)??[],g=u?"":d+(c?" ":"\u2502 ");f.forEach((h,E)=>{i(h,g,E===f.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(`${l.warn("? ")}${$d(a.session_id,t)}
1712
- `)}function jd(e,t){let s=Me(e);if(!s){process.exitCode=1;return}let n=Ae(s);if(!n){process.stderr.write(`thread not found: ${e}
1713
- `),process.exitCode=1;return}let r=uy(n.edges.map(o=>o.session_id));xe(t.json===!0,n,()=>{let o=yo(n);if(console.log(l.bold(n.name)),console.log(l.dim(`id ${H(n.id)} \xB7 ${o} \xB7 ${n.session_count} session${n.session_count===1?"":"s"} \xB7 ${n.origin_count} origin${n.origin_count===1?"":"s"} \xB7 created ${W(n.created_at)}`)),n.summary&&console.log(n.summary),console.log(),n.edges.length===0){console.log(l.dim("(no sessions linked \u2014 use `recall thread link ...`)"));return}py(n,r)})}function Fd(e,t){let s;if(t.origin){let r=Tt(t.origin);if(!r){process.exitCode=1;return}s=r}let n=Qi({name:e,summary:t.summary??null,originSessionId:s});xe(t.json===!0,n,()=>{$t(n),process.stderr.write(l.dim(`id ${n.id}
1714
- `)),s&&process.stderr.write(l.dim(`origin: ${H(s)}
1715
- `))})}function Ud(e,t){let s=Me(t.thread);if(!s){process.exitCode=1;return}let n=Tt(e);if(!n){process.exitCode=1;return}let r=null;if(t.parent){let a=Tt(t.parent);if(!a){process.exitCode=1;return}r=a}let o=t.role??(r?"child":"origin"),i=ea({threadId:s,sessionId:n,parentSessionId:r,role:o});xe(t.json===!0,i,()=>{process.stderr.write(l.ok(`\u2713 linked ${H(n)} \u2192 ${H(s)} [${o}]
1716
- `))})}function Bd(e,t){let s=Me(t.thread);if(!s){process.exitCode=1;return}let n=Tt(e);if(!n){process.exitCode=1;return}let r=ta(s,n);xe(t.json===!0,r,()=>{if(r.removed===0){process.stderr.write(l.warn(`(no edge existed for ${H(n)} in ${H(s)})
1717
- `));return}process.stderr.write(l.ok(`\u2713 unlinked ${H(n)} from ${H(s)}
1718
- `))})}function Hd(e,t){let s=Me(t.thread);if(!s){process.exitCode=1;return}let n=Tt(e);if(!n){process.exitCode=1;return}let r=null;if(t.parent&&t.parent.toLowerCase()!=="none"){let i=Tt(t.parent);if(!i){process.exitCode=1;return}r=i}let o=sa(s,n,r);xe(t.json===!0,o,()=>{process.stderr.write(l.ok(`\u2713 ${H(n)} in ${H(s)} \u2192 `+(r?`child of ${H(r)}`:"origin")+`
1719
- `))})}function Wd(e,t,s){let n=Me(e);if(!n){process.exitCode=1;return}let r=na(n,t);xe(s.json===!0,r,()=>$t(r))}function Xd(e,t){let s=Me(e);if(!s){process.exitCode=1;return}let n=ra(s);xe(t.json===!0,n,()=>$t(n))}function Jd(e,t){let s=Me(e);if(!s){process.exitCode=1;return}let n=oa(s);xe(t.json===!0,n,()=>$t(n))}function Yd(e,t){let s=Me(e);if(!s){process.exitCode=1;return}let n=ia(s);xe(t.json===!0,n,()=>$t(n))}function Gd(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(l.err(`cannot merge a thread into itself
1720
- `)),process.exitCode=1;return}let r=aa(s,n);xe(t.json===!0,r,()=>{process.stderr.write(l.ok(`\u2713 merged ${H(s)} \u2192 ${H(n)} (${r.session_count} sessions)
1721
- `))})}function zd(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(l.err(`--sessions must be a non-empty comma-separated list
1722
- `)),process.exitCode=1;return}let r=[];for(let i of n){let a=Tt(i);if(!a){process.exitCode=1;return}r.push(a)}let o=ca({threadId:s,sessionIds:r,newThreadName:t.name});xe(t.json===!0,o,()=>{$t(o),process.stderr.write(l.dim(`split off ${r.length} session${r.length===1?"":"s"} from ${H(s)}
1723
- `))})}y();v();import{randomUUID as Dy}from"node:crypto";import{readFileSync as my,statSync as gy}from"node:fs";var fy=200*1024*1024,Ro=.7,xo=.5,Vd=xo,_y=[{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"}],hy=["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 qd(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 Ey(e,t){let s=t-e;if(s<0)return{weight:0,label:null};for(let n of _y)if(s<=n.maxGapMs)return{weight:n.weight,label:n.label};return{weight:0,label:null}}function by(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 hy)if(o.includes(i))return{weight:t[n],matched:i,matchedIndex:n}}return{weight:0,matched:null,matchedIndex:-1}}function To(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 Sy(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=To(n,r);o>s&&(s=o)}return s}function wy(e,t){let s=To(e.mean_embedding,t.mean_embedding),n=To(e.tail_pool,t.head_pool),r=Sy(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 yy(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 Ty(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 Ry(e,t){let s=qd(e),n=qd(t);return s&&n&&s===n?{weight:.1,brand:s}:{weight:0,brand:null}}function Kd(e){return e.replace(/\s+/g," ").trim().toLowerCase()}function xy(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=Kd(t.recent_user_messages[0]);if(o.length>=200)for(let i of e.authored_content){let a=Kd(i);if(a.length<200)continue;let d=Math.min(a.length,240),c=a.slice(0,d);if(o.includes(c)){s+=.4,r=!0;break}}}return{weight:Math.min(.6,s),pathMatch:n,contentMatch:r}}function ky(e,t,s=Vd){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=Ey(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=by(o),a=Ty(e.touched_files,t.touched_files),d=Ry(e.auto_title,t.auto_title),c=wy(e,t),u=yy(e,t),p=xy(e,t),m=r.weight+i.weight+a.weight+d.weight+c.weight+u.weight+p.weight;if(m<s)return null;let f=[];if(r.label&&f.push(`temporal ${r.label} (+${r.weight})`),i.matched){let g=i.matchedIndex===0?"opening message":`message #${i.matchedIndex+1}`;f.push(`continuation phrase "${i.matched}" in ${g} (+${i.weight})`)}if(a.count>0&&f.push(`${a.count} file${a.count===1?"":"s"} overlap (+${a.weight.toFixed(1)})`),d.brand&&f.push(`shared brand "${d.brand}" (+${d.weight})`),c.weight>0&&c.mode&&f.push(`semantic ${c.mode==="asymmetric"?"tail\u2192head":c.mode==="max_pool"?"best-chunk":"mean"} ${c.cosine.toFixed(2)} (+${c.weight.toFixed(2)})`),u.same&&f.push(`same cluster (+${u.weight})`),p.weight>0){let g=[];p.pathMatch&&g.push(`opened authored path "${p.pathMatch.split("/").pop()}"`),p.contentMatch&&g.push("verbatim-paste of authored content"),f.push(`doc-authorship: ${g.join(" + ")} (+${p.weight.toFixed(2)})`)}return{parent_id:e.id,child_id:t.id,confidence:Math.min(1,m),signals:{temporal:r.weight,continuation:i.weight,file_overlap:a.weight,same_brand:d.weight,semantic:c.weight,cluster:u.weight,doc_authorship:p.weight},reasons:f}}function Zd(e,t=Vd){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=ky(a,r,t);d&&(!o||d.confidence>o.confidence)&&(o=d)}o&&s.push(o)}return s}function Qd(e,t){let s=new Map,n=a=>{let d=a;for(;s.get(d)!==d;)d=s.get(d);let c=a;for(;s.get(c)!==d;){let u=s.get(c);s.set(c,d),c=u}return d},r=(a,d)=>{let c=n(a),u=n(d);c!==u&&s.set(c,u)};for(let a of e)s.has(a.parent_id)||s.set(a.parent_id,a.parent_id),s.has(a.child_id)||s.set(a.child_id,a.child_id),r(a.parent_id,a.child_id);let o=new Map;for(let a of s.keys()){let d=n(a),c=o.get(d);c||(c=[],o.set(d,c)),c.push(a)}let i=new Map;for(let a of t)i.set(a.id,a.started_at_ms);return Array.from(o.values()).map(a=>(a.sort((d,c)=>(i.get(d)??0)-(i.get(c)??0)),{rootId:a[0],sessionIds:a}))}function eu(e,t={}){let s=t.maxUserMessages??5,n=t.userMessageMaxLen??2e3,r=new Set,o=[],i=new Set,a=[],d;try{if(gy(e).size>fy)return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a};d=my(e,"utf8")}catch{return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a}}let c=0;for(;c<d.length;){let u=d.indexOf(`
1725
- `,c),p=u===-1?d.length:u,m=d.slice(c,p);if(c=u===-1?d.length:u+1,!m.trim())continue;let f;try{f=JSON.parse(m)}catch{continue}let g=f;if(g.type==="user"&&g.message?.role==="user"&&typeof g.message.content=="string"&&o.length<s){let E=g.message.content.trim();E&&o.push(E.length>n?E.slice(0,n):E)}let h=g.message?.content;if(Array.isArray(h))for(let E of h){if(!E||typeof E!="object")continue;let b=E;if(b.type!=="tool_use")continue;let S=b.input??{},C=typeof S.file_path=="string"?S.file_path:null;if(C){let w=un(C);w&&r.add(w)}if((b.name==="Write"||b.name==="Edit"||b.name==="MultiEdit")&&C){let w=un(C);w&&i.add(w);let N=typeof S.content=="string"?S.content:typeof S.new_string=="string"?S.new_string:null;N&&N.length>=200&&a.push(N.length>4096?N.slice(0,4096):N)}if(b.name==="Bash"&&typeof S.command=="string")for(let w of S.command.matchAll(/(?:^|[\s'"`(=])((?:\.\.?\/|\/|src\/|test\/|docs\/|site\/)[A-Za-z0-9_./-]+)/g)){let N=un(w[1]);N&&r.add(N)}if((b.name==="Glob"||b.name==="Grep")&&typeof S.pattern=="string"){let w=un(S.pattern);w&&!w.includes("*")&&r.add(w)}}}return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a}}function un(e){let t=e.trim().replace(/^['"]|['"]$/g,"");return!t||t.length<4||/[<>|;&\$`]/.test(t)?null:t}y();var tu=10,su=20;function Cy(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 Ly(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 nu(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 ko(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 nu(s)?s:null}function ru(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 Ud(e){let t=pr({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 Ey({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),To(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 Sy(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}${Fd(a.session_id,t)}
1711
+ `);let f=n.get(a.session_id)??[],g=u?"":d+(l?" ":"\u2502 ");f.forEach((h,E)=>{i(h,g,E===f.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("? ")}${Fd(a.session_id,t)}
1712
+ `)}function Bd(e,t){let s=Me(e);if(!s){process.exitCode=1;return}let n=Ae(s);if(!n){process.stderr.write(`thread not found: ${e}
1713
+ `),process.exitCode=1;return}let r=by(n.edges.map(o=>o.session_id));xe(t.json===!0,n,()=>{let o=To(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}Sy(n,r)})}function Hd(e,t){let s;if(t.origin){let r=Tt(t.origin);if(!r){process.exitCode=1;return}s=r}let n=ta({name:e,summary:t.summary??null,originSessionId:s});xe(t.json===!0,n,()=>{$t(n),process.stderr.write(c.dim(`id ${n.id}
1714
+ `)),s&&process.stderr.write(c.dim(`origin: ${W(s)}
1715
+ `))})}function Wd(e,t){let s=Me(t.thread);if(!s){process.exitCode=1;return}let n=Tt(e);if(!n){process.exitCode=1;return}let r=null;if(t.parent){let a=Tt(t.parent);if(!a){process.exitCode=1;return}r=a}let o=t.role??(r?"child":"origin"),i=sa({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}]
1716
+ `))})}function Xd(e,t){let s=Me(t.thread);if(!s){process.exitCode=1;return}let n=Tt(e);if(!n){process.exitCode=1;return}let r=na(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)})
1717
+ `));return}process.stderr.write(c.ok(`\u2713 unlinked ${W(n)} from ${W(s)}
1718
+ `))})}function Jd(e,t){let s=Me(t.thread);if(!s){process.exitCode=1;return}let n=Tt(e);if(!n){process.exitCode=1;return}let r=null;if(t.parent&&t.parent.toLowerCase()!=="none"){let i=Tt(t.parent);if(!i){process.exitCode=1;return}r=i}let o=ra(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")+`
1719
+ `))})}function Gd(e,t,s){let n=Me(e);if(!n){process.exitCode=1;return}let r=oa(n,t);xe(s.json===!0,r,()=>$t(r))}function Yd(e,t){let s=Me(e);if(!s){process.exitCode=1;return}let n=ia(s);xe(t.json===!0,n,()=>$t(n))}function zd(e,t){let s=Me(e);if(!s){process.exitCode=1;return}let n=aa(s);xe(t.json===!0,n,()=>$t(n))}function qd(e,t){let s=Me(e);if(!s){process.exitCode=1;return}let n=ca(s);xe(t.json===!0,n,()=>$t(n))}function Kd(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=la(s,n);xe(t.json===!0,r,()=>{process.stderr.write(c.ok(`\u2713 merged ${W(s)} \u2192 ${W(n)} (${r.session_count} sessions)
1721
+ `))})}function Vd(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=Tt(i);if(!a){process.exitCode=1;return}r.push(a)}let o=da({threadId:s,sessionIds:r,newThreadName:t.name});xe(t.json===!0,o,()=>{$t(o),process.stderr.write(c.dim(`split off ${r.length} session${r.length===1?"":"s"} from ${W(s)}
1723
+ `))})}y();v();import{randomUUID as Wy}from"node:crypto";import{readFileSync as wy,statSync as yy}from"node:fs";var Ty=200*1024*1024,xo=.7,ko=.5,eu=ko,Ry=[{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"}],xy=["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 Zd(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 ky(e,t){let s=t-e;if(s<0)return{weight:0,label:null};for(let n of Ry)if(s<=n.maxGapMs)return{weight:n.weight,label:n.label};return{weight:0,label:null}}function Cy(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 xy)if(o.includes(i))return{weight:t[n],matched:i,matchedIndex:n}}return{weight:0,matched:null,matchedIndex:-1}}function Ro(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 Ly(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=Ro(n,r);o>s&&(s=o)}return s}function Ny(e,t){let s=Ro(e.mean_embedding,t.mean_embedding),n=Ro(e.tail_pool,t.head_pool),r=Ly(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 Oy(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 Ay(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 vy(e,t){let s=Zd(e),n=Zd(t);return s&&n&&s===n?{weight:.1,brand:s}:{weight:0,brand:null}}function Qd(e){return e.replace(/\s+/g," ").trim().toLowerCase()}function Iy(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=Qd(t.recent_user_messages[0]);if(o.length>=200)for(let i of e.authored_content){let a=Qd(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 My(e,t,s=eu){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=ky(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=Cy(o),a=Ay(e.touched_files,t.touched_files),d=vy(e.auto_title,t.auto_title),l=Ny(e,t),u=Oy(e,t),p=Iy(e,t),m=r.weight+i.weight+a.weight+d.weight+l.weight+u.weight+p.weight;if(m<s)return null;let f=[];if(r.label&&f.push(`temporal ${r.label} (+${r.weight})`),i.matched){let g=i.matchedIndex===0?"opening message":`message #${i.matchedIndex+1}`;f.push(`continuation phrase "${i.matched}" in ${g} (+${i.weight})`)}if(a.count>0&&f.push(`${a.count} file${a.count===1?"":"s"} overlap (+${a.weight.toFixed(1)})`),d.brand&&f.push(`shared brand "${d.brand}" (+${d.weight})`),l.weight>0&&l.mode&&f.push(`semantic ${l.mode==="asymmetric"?"tail\u2192head":l.mode==="max_pool"?"best-chunk":"mean"} ${l.cosine.toFixed(2)} (+${l.weight.toFixed(2)})`),u.same&&f.push(`same cluster (+${u.weight})`),p.weight>0){let g=[];p.pathMatch&&g.push(`opened authored path "${p.pathMatch.split("/").pop()}"`),p.contentMatch&&g.push("verbatim-paste of authored content"),f.push(`doc-authorship: ${g.join(" + ")} (+${p.weight.toFixed(2)})`)}return{parent_id:e.id,child_id:t.id,confidence:Math.min(1,m),signals:{temporal:r.weight,continuation:i.weight,file_overlap:a.weight,same_brand:d.weight,semantic:l.weight,cluster:u.weight,doc_authorship:p.weight},reasons:f}}function tu(e,t=eu){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=My(a,r,t);d&&(!o||d.confidence>o.confidence)&&(o=d)}o&&s.push(o)}return s}function su(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 nu(e,t={}){let s=t.maxUserMessages??5,n=t.userMessageMaxLen??2e3,r=new Set,o=[],i=new Set,a=[],d;try{if(yy(e).size>Ty)return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a};d=wy(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 f;try{f=JSON.parse(m)}catch{continue}let g=f;if(g.type==="user"&&g.message?.role==="user"&&typeof g.message.content=="string"&&o.length<s){let E=g.message.content.trim();E&&o.push(E.length>n?E.slice(0,n):E)}let h=g.message?.content;if(Array.isArray(h))for(let E of h){if(!E||typeof E!="object")continue;let b=E;if(b.type!=="tool_use")continue;let S=b.input??{},T=typeof S.file_path=="string"?S.file_path:null;if(T){let x=un(T);x&&r.add(x)}if((b.name==="Write"||b.name==="Edit"||b.name==="MultiEdit")&&T){let x=un(T);x&&i.add(x);let N=typeof S.content=="string"?S.content:typeof S.new_string=="string"?S.new_string:null;N&&N.length>=200&&a.push(N.length>4096?N.slice(0,4096):N)}if(b.name==="Bash"&&typeof S.command=="string")for(let x of S.command.matchAll(/(?:^|[\s'"`(=])((?:\.\.?\/|\/|src\/|test\/|docs\/|site\/)[A-Za-z0-9_./-]+)/g)){let N=un(x[1]);N&&r.add(N)}if((b.name==="Glob"||b.name==="Grep")&&typeof S.pattern=="string"){let x=un(S.pattern);x&&!x.includes("*")&&r.add(x)}}}return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a}}function un(e){let t=e.trim().replace(/^['"]|['"]$/g,"");return!t||t.length<4||/[<>|;&\$`]/.test(t)?null:t}y();var ru=10,ou=20;function Dy(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 $y(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 iu(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 Co(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 iu(s)?s:null}function au(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,
1727
1727
  cm.text AS text, v.embedding AS embedding
1728
1728
  FROM chunk_meta cm
1729
1729
  JOIN vec_chunks v ON v.rowid = cm.rowid
1730
1730
  WHERE cm.stale = 0
1731
1731
  AND cm.session_id IN (${n})
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(w=>!Cy(w.text)),c=d.length>0?d:a,u=[];for(let w of c){let N=Ly(w.embedding);N&&nu(N)&&u.push(N)}if(u.length===0)continue;let p=Math.min(tu,u.length),m=Math.max(0,u.length-tu),f=u.slice(0,p),g=u.slice(m),h=ko(f),E=ko(g),b=ko(u),S=new Map;for(let w=0;w<f.length&&S.size<su;w++)S.set(w,f[w]);for(let w=0;w<g.length&&S.size<su;w++)S.set(m+w,g[w]);let C=Array.from(S.values());t.set(i,{session_id:i,full_mean:b,head_pool:h,tail_pool:E,sample_chunks:C})}return t}function Ny(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 ou(e,t=.8){let s=new Map,n=[],r=[];for(let[c,u]of e)u.full_mean&&(n.push(c),r.push(u.full_mean));if(n.length===0)return s;let o=new Int32Array(n.length);for(let c=0;c<o.length;c++)o[c]=c;let i=c=>{let u=c;for(;o[u]!==u;)u=o[u];let p=c;for(;o[p]!==u;){let m=o[p];o[p]=u,p=m}return u},a=(c,u)=>{let p=i(c),m=i(u);p!==m&&(o[p]=m)};for(let c=0;c<n.length;c++)for(let u=c+1;u<n.length;u++)Ny(r[c],r[u])>=t&&a(c,u);let d=new Map;for(let c=0;c<n.length;c++){let u=i(c),p=d.get(u);p===void 0&&(p=d.size,d.set(u,p)),s.set(n[c],p)}return s}var os={lo:.4,hi:.7},pn="claude-haiku-4-5-20251001",iu=50;var Oy={same_workflow:.15,unrelated:-.2,unsure:0};function au(e,t,s=os){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 Ay(e,t){let s=e.replace(/\s+/g," ").trim();return s.length>t?s.slice(0,t-1)+"\u2026":s}function vy(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 Iy(e){let s=e.parent.recent_user_messages,n=e.child.recent_user_messages,r=s.slice(0,3),o=s.length>3?s.slice(-3):[],i=n.slice(0,3),a=c=>c.length===0?" (none captured)":c.map(u=>` - ${Ay(u,500)}`).join(`
1733
- `),d=vy(e.parent.ended_at_ms??e.parent.started_at_ms,e.child.started_at_ms);return["You are evaluating whether two Claude Code sessions belong to the same continuous workflow.","","A deterministic scorer rated this pair in the borderline band. Its signals:",e.step1.reasons.length===0?" (no signals fired strongly)":e.step1.reasons.map(c=>` - ${c}`).join(`
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(x=>!Dy(x.text)),l=d.length>0?d:a,u=[];for(let x of l){let N=$y(x.embedding);N&&iu(N)&&u.push(N)}if(u.length===0)continue;let p=Math.min(ru,u.length),m=Math.max(0,u.length-ru),f=u.slice(0,p),g=u.slice(m),h=Co(f),E=Co(g),b=Co(u),S=new Map;for(let x=0;x<f.length&&S.size<ou;x++)S.set(x,f[x]);for(let x=0;x<g.length&&S.size<ou;x++)S.set(m+x,g[x]);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 Py(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 cu(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++)Py(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 os={lo:.4,hi:.7},pn="claude-haiku-4-5-20251001",lu=50;var jy={same_workflow:.15,unrelated:-.2,unsure:0};function du(e,t,s=os){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 Fy(e,t){let s=e.replace(/\s+/g," ").trim();return s.length>t?s.slice(0,t-1)+"\u2026":s}function Uy(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 By(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=>` - ${Fy(u,500)}`).join(`
1733
+ `),d=Uy(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(`
1734
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(`
1735
- `)}function My(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:Oy[i]}}async function cu(e,t={}){if(t.signal?.aborted)return null;let s=t.model??pn,n=Iy(e),r=t.spawn;if(!r)try{let i=await Promise.resolve().then(()=>(Be(),Is));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:My(o.stdout)}function lu(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 du(e){return`${e.parent_id}::${e.child_id}`}async function $y(e){if(e.signal?.aborted)return null;let t,s;try{({spawnClaudePrompt:t,isClaudeCliAvailable:s}=await Promise.resolve().then(()=>(Be(),Is)))}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 Hy(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:jy[i]}}async function uu(e,t={}){if(t.signal?.aborted)return null;let s=t.model??pn,n=By(e),r=t.spawn;if(!r)try{let i=await Promise.resolve().then(()=>(Be(),Is));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:Hy(o.stdout)}function pu(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 mu(e){return`${e.parent_id}::${e.child_id}`}async function Xy(e){if(e.signal?.aborted)return null;let t,s;try{({spawnClaudePrompt:t,isClaudeCliAvailable:s}=await Promise.resolve().then(()=>(Be(),Is)))}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:
1736
1736
  - 4 to 8 words
1737
1737
  - Title-case, no trailing punctuation
1738
1738
  - Capture the WORKFLOW (e.g., "Update Remotion deps + lint cleanup"), not any one session
@@ -1743,7 +1743,7 @@ Sessions:
1743
1743
  `+n.join(`
1744
1744
  `)+`
1745
1745
 
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 c=d.stdout.trim();if(!c)return null;let u;try{let p=JSON.parse(c);u=typeof p.result=="string"?p.result:c}catch{u=c}return u=u.trim().replace(/^["'`]+|["'`]+$/g,"").replace(/[.!?]+$/g,"").trim(),u?u.length>80?u.slice(0,77)+"...":u:null}catch{return null}}function Py(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=ru(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=ou(a,.8),c=[];for(let u of i){let p=Fy(u,n,d);p&&c.push(p)}r.set(o,c)}return{byProject:t,scannablesByProject:r}}function jy(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 Jy(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=au(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=cu(a,.8),l=[];for(let u of i){let p=Yy(u,n,d);p&&l.push(p)}r.set(o,l)}return{byProject:t,scannablesByProject:r}}function Gy(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,
1747
1747
  s.first_user_message, s.auto_title,
1748
1748
  NULLIF(sa.alias, '') AS alias,
1749
1749
  s.file_path
@@ -1751,40 +1751,40 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1751
1751
  JOIN projects p ON p.id = s.project_id
1752
1752
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1753
1753
  WHERE ${n}
1754
- ORDER BY p.name ASC, s.started_at ASC`).all(s)}function Fy(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=eu(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 mn(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 uu(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 pu(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 Uy(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??os,s=e.rescore.cap??iu,n=e.rescore.model??pn,r=new Map(e.scannables.map(m=>[m.id,m])),o=au(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,c=0,u=0;for(let m=0;m<o.length&&!e.signal?.aborted;m++){let f=o[m],g=await cu(f,{model:n,signal:e.signal});g?(i.set(du(f.step1),g),g.verdict==="same_workflow"?a++:g.verdict==="unrelated"?d++:c++):u++,e.onProgress?.({phase:"rescoring",current:m+1,total:o.length,verdict:g?.verdict??"failed"})}return{proposals:lu({proposals:e.proposals,rescored:i,applyThreshold:e.applyThreshold}),ran:!0,considered:o.length,promoted:a,demoted:d,unsure:c,failed:u,capped:!1}}async function By(e){let t=_(),s=new Map(e.rows.map(c=>[c.id,c])),n=Qd(e.edges,e.scannables),r=new Date().toISOString(),o=[],i=new Map,a=0;for(let c of n){if(a++,e.signal?.aborted)break;let u=s.get(c.rootId),p=pu(u);if(!e.llmNames){i.set(c.rootId,p),e.onProgress?.({phase:"naming",current:a,total:n.length,thread_name:p});continue}let f=await $y({rootRow:u,sessionIds:c.sessionIds,rowById:s,signal:e.signal,model:e.model})??p;i.set(c.rootId,f),e.onProgress?.({phase:"naming",current:a,total:n.length,thread_name:f})}return t.transaction(()=>{for(let c of n){if(!i.has(c.rootId))continue;let u=s.get(c.rootId),p=`auto-scan-${Dy()}`,m=i.get(c.rootId)??pu(u),f=`Auto-detected workflow chain (${c.sessionIds.length} sessions). Source: auto-scan-v1.`;t.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, ?, ?)").run(p,m,f,r),t.prepare(`INSERT INTO thread_edges
1754
+ ORDER BY p.name ASC, s.started_at ASC`).all(s)}function Yy(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=nu(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 mn(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 gu(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 fu(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 zy(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??os,s=e.rescore.cap??lu,n=e.rescore.model??pn,r=new Map(e.scannables.map(m=>[m.id,m])),o=du(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 f=o[m],g=await uu(f,{model:n,signal:e.signal});g?(i.set(mu(f.step1),g),g.verdict==="same_workflow"?a++:g.verdict==="unrelated"?d++:l++):u++,e.onProgress?.({phase:"rescoring",current:m+1,total:o.length,verdict:g?.verdict??"failed"})}return{proposals:pu({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 qy(e){let t=_(),s=new Map(e.rows.map(l=>[l.id,l])),n=su(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=fu(u);if(!e.llmNames){i.set(l.rootId,p),e.onProgress?.({phase:"naming",current:a,total:n.length,thread_name:p});continue}let f=await Xy({rootRow:u,sessionIds:l.sessionIds,rowById:s,signal:e.signal,model:e.model})??p;i.set(l.rootId,f),e.onProgress?.({phase:"naming",current:a,total:n.length,thread_name:f})}return t.transaction(()=>{for(let l of n){if(!i.has(l.rootId))continue;let u=s.get(l.rootId),p=`auto-scan-${Wy()}`,m=i.get(l.rootId)??fu(u),f=`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,f,r),t.prepare(`INSERT INTO thread_edges
1755
1755
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
1756
- VALUES (?, ?, NULL, 'origin', 1.0, 'auto-scan-v1', ?)`).run(p,c.rootId,r);let g=new Map;for(let h of e.edges)c.sessionIds.includes(h.child_id)&&g.set(h.child_id,h);for(let h of c.sessionIds){if(h===c.rootId)continue;let E=g.get(h);E&&t.prepare(`INSERT INTO thread_edges
1756
+ VALUES (?, ?, NULL, 'origin', 1.0, 'auto-scan-v1', ?)`).run(p,l.rootId,r);let g=new Map;for(let h of e.edges)l.sessionIds.includes(h.child_id)&&g.set(h.child_id,h);for(let h of l.sessionIds){if(h===l.rootId)continue;let E=g.get(h);E&&t.prepare(`INSERT INTO thread_edges
1757
1757
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
1758
- VALUES (?, ?, ?, 'child', ?, 'auto-scan-v1', ?)`).run(p,h,E.parent_id,E.confidence,r)}o.push({thread_id:p,name:m,session_count:c.sessionIds.length})}})(),{project:e.project,threads:o}}async function mu(e){let t=!!e.apply,s=e.confidenceMin?Number(e.confidenceMin):t?Ro:xo;if(!Number.isFinite(s)||s<0||s>1){console.error(l.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):os.lo,hi:e.rescoreBandHi?Number(e.rescoreBandHi):os.hi};if(n&&(!Number.isFinite(r.lo)||!Number.isFinite(r.hi)||r.lo<0||r.hi>1||r.lo>r.hi)){console.error(l.err("--rescore-band-lo/hi must satisfy 0 \u2264 lo \u2264 hi \u2264 1")),process.exitCode=1;return}let o=e.rescoreModel??pn,i=jy({project:e.project});if(i.length===0){console.log(l.dim("no sessions matched"));return}let{byProject:a,scannablesByProject:d}=Py(i),c=n?Math.min(s,r.lo):s,u=new Map,p=0;for(let[f]of a){let g=d.get(f)??[],h=Zd(g,c);if(n&&h.length>0){let E=await Uy({proposals:h,scannables:g,applyThreshold:s,rescore:{enabled:!0,band:r,model:o}});h=E.proposals,E.capped?(console.error(l.err(`[${f}] borderline pairs exceeded cap (${E.considered}); skipped LLM rescore. Tighten the band or scan a smaller project.`)),h=h.filter(b=>b.confidence>=s)):n?E.failed===E.considered&&E.considered>0&&(h=h.filter(b=>b.confidence>=s)):h=h.filter(b=>b.confidence>=s)}else n&&(h=h.filter(E=>E.confidence>=s));u.set(f,{proposals:h,scannables:g}),p+=h.length}if(t){if(p===0){console.log(l.dim("no edges above threshold; nothing to apply"));return}let f={threads_created:0,edges_written:0,per_project:[]},g=!e.noLlmNames;for(let[h,{proposals:E,scannables:b}]of u){if(E.length===0)continue;let S=await By({project:h,rows:a.get(h),edges:E,scannables:b,llmNames:g});f.per_project.push(S),f.threads_created+=S.threads.length,f.edges_written+=E.length+S.threads.length}if(e.json){console.log(JSON.stringify({mode:"apply",threshold:s,...f},null,2));return}console.log(l.ok(`Applied ${f.threads_created} thread${f.threads_created===1?"":"s"} with ${f.edges_written} edges total (threshold ${s}).`));for(let h of f.per_project){console.log(` ${l.bold(h.project)}`);for(let E of h.threads)console.log(` ${l.dim(E.thread_id.slice(0,16)+"\u2026")} ${E.name} ${l.dim(`(${E.session_count} sessions)`)}`)}console.log(),console.log(l.dim("Rollback: sqlite3 ~/.recall/db.sqlite \\")),console.log(l.dim(` "DELETE FROM thread_edges WHERE source='auto-scan-v1';`)),console.log(l.dim(` DELETE FROM threads WHERE id LIKE 'auto-scan-%';"`));return}if(e.json){let f=[];for(let[g,{proposals:h}]of u){let E=new Map(a.get(g).map(b=>[b.id,b]));for(let b of h)f.push({project:g,parent_id:b.parent_id,parent_label:mn(E.get(b.parent_id)),child_id:b.child_id,child_label:mn(E.get(b.child_id)),confidence:b.confidence,signals:b.signals,reasons:b.reasons})}console.log(JSON.stringify({mode:"dry-run",threshold:s,total:p,edges:f},null,2));return}console.log(l.dim(`recall thread scan \xB7 ${a.size} project${a.size===1?"":"s"} \xB7 DRY RUN \xB7 threshold ${s}`)),console.log(l.dim(" Algorithm: temporal + continuation phrase + file overlap + same brand.")),console.log();for(let[f,g]of a){let{proposals:h}=u.get(f),E=new Map(g.map(S=>[S.id,S]));if(console.log(l.bold(f)),console.log(l.dim(` ${g.length} eligible session${g.length===1?"":"s"}; ${h.length} parent-child edge${h.length===1?"":"s"} proposed.`)),h.length===0){console.log(l.dim(" (no edges above threshold \u2014 all sessions are origins)")),console.log();continue}let b=[...h].sort((S,C)=>{let w=E.get(S.child_id),N=E.get(C.child_id);return(w.started_at??"").localeCompare(N.started_at??"")});for(let S of b){let C=E.get(S.parent_id),w=E.get(S.child_id),N=S.confidence.toFixed(2);console.log(` ${l.dim(uu(C.started_at).padEnd(16))} ${l.bold("PARENT")} ${mn(C)}`),console.log(` ${l.dim(uu(w.started_at).padEnd(16))} ${l.bold(" \u2514\u2500 child")} ${mn(w)} ${l.dim(`[conf ${N}]`)}`),console.log(` ${" ".repeat(28)}${l.dim(S.reasons.join(" \xB7 "))}`),console.log()}}let m=Array.from(a.entries()).reduce((f,[g,h])=>f+(h.length-(u.get(g)?.proposals.length??0)),0);console.log(`${p} edge${p===1?"":"s"} proposed across ${a.size} project${a.size===1?"":"s"}; ${m} origin session${m===1?"":"s"} (no proposed parent).`),console.log(l.dim(` This is a DRY RUN. To write: rerun with --apply (default threshold ${Ro}).`))}v();D();import{existsSync as Hy,readFileSync as Wy}from"node:fs";function Xy(){let e=`${R}/daemon.port`;if(!Hy(e))return null;try{let t=Wy(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function Jy(e){try{return(await bt(`http://127.0.0.1:${e}/api/health`,{signal:AbortSignal.timeout(1e4)})).ok}catch{return!1}}async function Yy(e){let t=await bt(`http://127.0.0.1:${e}/api/projects`);if(!t.ok)throw new Error(`failed to list projects: HTTP ${t.status}`);return await t.json()}function Gy(e,t){let s=t.replace(/\/+$/,""),n=null,r=-1;for(let o of e){if(!o.decoded_path)continue;let i=o.decoded_path.replace(/\/+$/,"");(s===i||s.startsWith(i+"/"))&&i.length>r&&(n=o,r=i.length)}return n}function zy(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 gu(e){return e.alias||e.auto_title||(e.first_user_message?q(e.first_user_message,60):"(no title)")}function qy(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 Ky(e,t){let s=t==="preflight"?l.dim(`recall threads sync \xB7 ${e.project.name} \xB7 PREFLIGHT (no writes)`):l.dim(`recall threads sync \xB7 ${e.project.name}`);if(console.log(s),console.log(),e.thread.exists?console.log(` ${l.bold("Thread")} ${e.thread.name} ${l.dim(`(reusing, ${e.thread.existing_session_count} existing session${e.thread.existing_session_count===1?"":"s"})`)}`):console.log(` ${l.bold("Thread")} ${e.thread.name} ${l.ok("(new)")}`),console.log(),e.candidates.length===0){if(console.log(l.dim(" No active sessions in the rolling window.")),e.warnings.length>0)for(let c of e.warnings)console.log(l.warn(` \u26A0 ${c}`));return}let n=new Map;for(let c of e.proposed_edges)n.set(c.child_id,c);let r=new Map;for(let c of e.preserved_manual_edges)r.set(c.session_id,c.parent_session_id);let o=new Set(e.candidates.map(c=>c.session_id)),i=e.proposed_additions.length,a=e.candidates.length-i;console.log(` ${l.bold("Candidates")} ${e.candidates.length} active session${e.candidates.length===1?"":"s"} ${l.dim(`(${i} new \xB7 ${a} keep)`)}`);let d=String(e.candidates.length).length;for(let c=0;c<e.candidates.length;c++){let u=e.candidates[c],m=e.proposed_additions.some(S=>S.session_id===u.session_id)?l.ok("NEW "):l.dim("keep"),f=n.get(u.session_id)??(r.has(u.session_id)&&r.get(u.session_id)!==null,null),g=f&&o.has(f.parent_id)?" \u2514\u2500 ":" ",h=qy(u.started_at),E=l.dim(`${String(c+1).padStart(d," ")}.`);console.log(` ${E} ${m} ${l.dim(h.padEnd(16))} ${g}${l.dim(u.session_id.slice(0,8))} ${gu(u)}`);let b=" ".repeat(d+2);if(f&&o.has(f.parent_id)){let S=f.confidence.toFixed(2),C=gu(e.candidates.find(w=>w.session_id===f.parent_id));console.log(` ${b}${" ".repeat(28)} parent ${l.dim(f.parent_id.slice(0,8))} (${C}) ${l.dim(`[conf ${S}]`)}`),console.log(` ${b}${" ".repeat(28)} ${l.dim(f.reasons.join(" \xB7 "))}`)}if(r.has(u.session_id)){let S=r.get(u.session_id);S&&console.log(` ${b}${" ".repeat(28)} ${l.bold("manual parent preserved")} ${l.dim(S.slice(0,8))}`)}}if(e.preserved_manual_edges.length>0&&(console.log(),console.log(l.dim(` ${e.preserved_manual_edges.length} manual edge${e.preserved_manual_edges.length===1?"":"s"} will be preserved.`))),e.warnings.length>0){console.log();for(let c of e.warnings)console.log(l.warn(` \u26A0 ${c}`))}}function Vy(e){console.log(),console.log(l.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(l.dim(` thread_id: ${e.thread_id}`))}async function fu(e){let t=Xy();if(!t){console.error(l.err("Daemon is not running. Start it with `recall start`, then re-run this command.")),process.exitCode=1;return}if(!await Jy(t)){console.error(l.err(`Daemon on port ${t} is not responding. Try \`recall stop && recall start\`.`)),process.exitCode=1;return}let n;try{n=await Yy(t)}catch(c){console.error(l.err(c.message)),process.exitCode=1;return}let r;if(e.project){if(r=zy(n,e.project),!r){console.error(l.err(`No project matching "${e.project}". Run \`recall projects\` to list known projects.`)),process.exitCode=1;return}}else{let c=process.cwd();if(r=Gy(n,c),!r){console.error(l.err(`Current directory (${c}) does not match any known project. Pass --project <name> or cd into a project root.`)),process.exitCode=1;return}}let o=e.windowHours?Number(e.windowHours):void 0;if(o!==void 0&&(!Number.isFinite(o)||o<=0)){console.error(l.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 c=await rt("POST",`http://127.0.0.1:${t}/api/threads/sync-active`,a);if(!c.ok){let u=await c.text().catch(()=>"");throw new Error(`HTTP ${c.status}: ${u.slice(0,200)}`)}d=await c.json()}catch(c){console.error(l.err(`Sync failed: ${c.message}`)),process.exitCode=1;return}if(e.json){console.log(JSON.stringify({mode:i,...d},null,2));return}Ky(d.plan,i),i==="apply"&&d.result?Vy(d.result):i==="preflight"&&(console.log(),console.log(l.dim(" This is a PREFLIGHT. To write: re-run without --preflight.")))}y();import{writeFileSync as ST,existsSync as wT,mkdirSync as yT}from"node:fs";import{join as Mu}from"node:path";import{homedir as TT}from"node:os";import{execSync as Ut}from"node:child_process";Ze();import _T from"satori";import hT from"sharp";import{readFileSync as Ao}from"node:fs";import{join as yn}from"node:path";var vo=yn(le(),"dist","share","fonts"),Au=!1,vu=[];function ET(){return Au||(vu=[{name:"Inter",data:Ao(yn(vo,"Inter-Regular.woff")),weight:400,style:"normal"},{name:"Inter",data:Ao(yn(vo,"Inter-Bold.woff")),weight:700,style:"normal"},{name:"JetBrains Mono",data:Ao(yn(vo,"JetBrainsMono-Regular.woff")),weight:400,style:"normal"}],Au=!0),vu}async function bT(e){switch(e){case"A":return await Promise.resolve().then(()=>(bu(),Eu));case"B":return await Promise.resolve().then(()=>(yu(),wu));case"C":return await Promise.resolve().then(()=>(xu(),Ru));case"D":return await Promise.resolve().then(()=>(Lu(),Cu));case"E":return await Promise.resolve().then(()=>(Ou(),Nu))}}async function Tn(e,t){let n=(await bT(e)).render(t),i=await _T(n,{width:1080,height:e==="E"?1920:1350,fonts:ET()});return await hT(Buffer.from(i)).png({quality:90}).toBuffer()}function Iu(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 RT(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 xT(e){return e.prepare("SELECT session_id FROM recall_events ORDER BY recalled_at DESC LIMIT 1").get()?.session_id??null}function kT(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 _u(e){let t=!!e.apply,s=e.confidenceMin?Number(e.confidenceMin):t?xo:ko;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):os.lo,hi:e.rescoreBandHi?Number(e.rescoreBandHi):os.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??pn,i=Gy({project:e.project});if(i.length===0){console.log(c.dim("no sessions matched"));return}let{byProject:a,scannablesByProject:d}=Jy(i),l=n?Math.min(s,r.lo):s,u=new Map,p=0;for(let[f]of a){let g=d.get(f)??[],h=tu(g,l);if(n&&h.length>0){let E=await zy({proposals:h,scannables:g,applyThreshold:s,rescore:{enabled:!0,band:r,model:o}});h=E.proposals,E.capped?(console.error(c.err(`[${f}] borderline pairs exceeded cap (${E.considered}); skipped LLM rescore. Tighten the band or scan a smaller project.`)),h=h.filter(b=>b.confidence>=s)):n?E.failed===E.considered&&E.considered>0&&(h=h.filter(b=>b.confidence>=s)):h=h.filter(b=>b.confidence>=s)}else n&&(h=h.filter(E=>E.confidence>=s));u.set(f,{proposals:h,scannables:g}),p+=h.length}if(t){if(p===0){console.log(c.dim("no edges above threshold; nothing to apply"));return}let f={threads_created:0,edges_written:0,per_project:[]},g=!e.noLlmNames;for(let[h,{proposals:E,scannables:b}]of u){if(E.length===0)continue;let S=await qy({project:h,rows:a.get(h),edges:E,scannables:b,llmNames:g});f.per_project.push(S),f.threads_created+=S.threads.length,f.edges_written+=E.length+S.threads.length}if(e.json){console.log(JSON.stringify({mode:"apply",threshold:s,...f},null,2));return}console.log(c.ok(`Applied ${f.threads_created} thread${f.threads_created===1?"":"s"} with ${f.edges_written} edges total (threshold ${s}).`));for(let h of f.per_project){console.log(` ${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 f=[];for(let[g,{proposals:h}]of u){let E=new Map(a.get(g).map(b=>[b.id,b]));for(let b of h)f.push({project:g,parent_id:b.parent_id,parent_label:mn(E.get(b.parent_id)),child_id:b.child_id,child_label:mn(E.get(b.child_id)),confidence:b.confidence,signals:b.signals,reasons:b.reasons})}console.log(JSON.stringify({mode:"dry-run",threshold:s,total:p,edges:f},null,2));return}console.log(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[f,g]of a){let{proposals:h}=u.get(f),E=new Map(g.map(S=>[S.id,S]));if(console.log(c.bold(f)),console.log(c.dim(` ${g.length} eligible session${g.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 x=E.get(S.child_id),N=E.get(T.child_id);return(x.started_at??"").localeCompare(N.started_at??"")});for(let S of b){let T=E.get(S.parent_id),x=E.get(S.child_id),N=S.confidence.toFixed(2);console.log(` ${c.dim(gu(T.started_at).padEnd(16))} ${c.bold("PARENT")} ${mn(T)}`),console.log(` ${c.dim(gu(x.started_at).padEnd(16))} ${c.bold(" \u2514\u2500 child")} ${mn(x)} ${c.dim(`[conf ${N}]`)}`),console.log(` ${" ".repeat(28)}${c.dim(S.reasons.join(" \xB7 "))}`),console.log()}}let m=Array.from(a.entries()).reduce((f,[g,h])=>f+(h.length-(u.get(g)?.proposals.length??0)),0);console.log(`${p} edge${p===1?"":"s"} proposed across ${a.size} project${a.size===1?"":"s"}; ${m} origin session${m===1?"":"s"} (no proposed parent).`),console.log(c.dim(` This is a DRY RUN. To write: rerun with --apply (default threshold ${xo}).`))}v();D();import{existsSync as Ky,readFileSync as Vy}from"node:fs";function Zy(){let e=`${R}/daemon.port`;if(!Ky(e))return null;try{let t=Vy(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function Qy(e){try{return(await Ye(`http://127.0.0.1:${e}/api/health`,{signal:AbortSignal.timeout(1e4)})).ok}catch{return!1}}async function eT(e){let t=await Ye(`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 tT(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 sT(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 hu(e){return e.alias||e.auto_title||(e.first_user_message?q(e.first_user_message,60):"(no title)")}function nT(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 rT(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"),f=n.get(u.session_id)??(r.has(u.session_id)&&r.get(u.session_id)!==null,null),g=f&&o.has(f.parent_id)?" \u2514\u2500 ":" ",h=nT(u.started_at),E=c.dim(`${String(l+1).padStart(d," ")}.`);console.log(` ${E} ${m} ${c.dim(h.padEnd(16))} ${g}${c.dim(u.session_id.slice(0,8))} ${hu(u)}`);let b=" ".repeat(d+2);if(f&&o.has(f.parent_id)){let S=f.confidence.toFixed(2),T=hu(e.candidates.find(x=>x.session_id===f.parent_id));console.log(` ${b}${" ".repeat(28)} parent ${c.dim(f.parent_id.slice(0,8))} (${T}) ${c.dim(`[conf ${S}]`)}`),console.log(` ${b}${" ".repeat(28)} ${c.dim(f.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 oT(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 Eu(e){let t=Zy();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 Qy(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 eT(t)}catch(l){console.error(c.err(l.message)),process.exitCode=1;return}let r;if(e.project){if(r=sT(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=tT(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 Qe("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}rT(d.plan,i),i==="apply"&&d.result?oT(d.result):i==="preflight"&&(console.log(),console.log(c.dim(" This is a PREFLIGHT. To write: re-run without --preflight.")))}y();import{writeFileSync as LT,existsSync as NT,mkdirSync as OT}from"node:fs";import{join as Pu}from"node:path";import{homedir as AT}from"node:os";import{execSync as Ut}from"node:child_process";et();import RT from"satori";import xT from"sharp";import{readFileSync as vo}from"node:fs";import{join as yn}from"node:path";var Io=yn(le(),"dist","share","fonts"),Mu=!1,Du=[];function kT(){return Mu||(Du=[{name:"Inter",data:vo(yn(Io,"Inter-Regular.woff")),weight:400,style:"normal"},{name:"Inter",data:vo(yn(Io,"Inter-Bold.woff")),weight:700,style:"normal"},{name:"JetBrains Mono",data:vo(yn(Io,"JetBrainsMono-Regular.woff")),weight:400,style:"normal"}],Mu=!0),Du}async function CT(e){switch(e){case"A":return await Promise.resolve().then(()=>(yu(),wu));case"B":return await Promise.resolve().then(()=>(xu(),Ru));case"C":return await Promise.resolve().then(()=>(Lu(),Cu));case"D":return await Promise.resolve().then(()=>(Au(),Ou));case"E":return await Promise.resolve().then(()=>(Iu(),vu))}}async function Tn(e,t){let n=(await CT(e)).render(t),i=await RT(n,{width:1080,height:e==="E"?1920:1350,fonts:kT()});return await xT(Buffer.from(i)).png({quality:90}).toBuffer()}function $u(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 vT(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 IT(e){return e.prepare("SELECT session_id FROM recall_events ORDER BY recalled_at DESC LIMIT 1").get()?.session_id??null}function MT(e,t){let s=e.prepare(`
1760
1760
  SELECT s.id, s.started_at, s.message_count, s.first_user_message, s.auto_title,
1761
1761
  s.total_input_tokens, s.total_output_tokens
1762
1762
  FROM sessions s WHERE s.id = ?
1763
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(`
1764
1764
  SELECT tool_names, raw_json FROM messages
1765
1765
  WHERE session_id = ? AND tool_names IS NOT NULL AND tool_names != ''
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 f=m.match(/":\s*"([^"]+)"/);f&&a.add(f[1])}}let d=s.total_input_tokens??0,c=s.total_output_tokens??0;return{sessionTitle:r,sessionDate:s.started_at??new Date().toISOString(),recallDate:new Date().toISOString(),tokenCount:d+c,inputTokens:d,outputTokens:c,messageCount:s.message_count,filesReferenced:a.size,toolCallCount:i,verdict:""}}function CT(e){process.platform==="darwin"?Ut(`osascript -e 'set the clipboard to (read (POSIX file "${e}") as \xABclass PNGf\xBB)'`):process.platform==="linux"&&Ut(`xclip -selection clipboard -t image/png -i "${e}"`)}function LT(e){try{process.platform==="darwin"?Ut(`open "${e}"`):process.platform==="linux"?Ut(`xdg-open "${e}"`):process.platform==="win32"&&Ut(`start "" "${e}"`)}catch{}}async function Du(e,t){let s=_(),n;if(e){if(n=RT(s,e),!n){process.stderr.write(`session not found: ${e}
1767
- `),process.exitCode=1;return}}else if(n=xT(s),!n){process.stderr.write("No recalled sessions yet. Run `recall context <id>` first, then `recall share`.\n"),process.exitCode=1;return}let r=kT(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 Tn(o,r),a=n.slice(0,8),d=t.out??Mu(TT(),"Downloads");wT(d)||yT(d,{recursive:!0});let c=Mu(d,`recall-card-${a}.png`);if(ST(c,i),process.stderr.write(`Card saved to ${c}
1769
- `),t.clipboard&&(CT(c),process.stderr.write(`Copied PNG to clipboard.
1770
- `)),t.link){let u=Iu(r,o);process.stdout.write(u+`
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 f=m.match(/":\s*"([^"]+)"/);f&&a.add(f[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 DT(e){process.platform==="darwin"?Ut(`osascript -e 'set the clipboard to (read (POSIX file "${e}") as \xABclass PNGf\xBB)'`):process.platform==="linux"&&Ut(`xclip -selection clipboard -t image/png -i "${e}"`)}function $T(e){try{process.platform==="darwin"?Ut(`open "${e}"`):process.platform==="linux"?Ut(`xdg-open "${e}"`):process.platform==="win32"&&Ut(`start "" "${e}"`)}catch{}}async function ju(e,t){let s=_(),n;if(e){if(n=vT(s,e),!n){process.stderr.write(`session not found: ${e}
1767
+ `),process.exitCode=1;return}}else if(n=IT(s),!n){process.stderr.write("No recalled sessions yet. Run `recall context <id>` first, then `recall share`.\n"),process.exitCode=1;return}let r=MT(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 Tn(o,r),a=n.slice(0,8),d=t.out??Pu(AT(),"Downloads");NT(d)||OT(d,{recursive:!0});let l=Pu(d,`recall-card-${a}.png`);if(LT(l,i),process.stderr.write(`Card saved to ${l}
1769
+ `),t.clipboard&&(DT(l),process.stderr.write(`Copied PNG to clipboard.
1770
+ `)),t.link){let u=$u(r,o);process.stdout.write(u+`
1771
1771
  `),process.platform==="darwin"&&(Ut("pbcopy",{input:u}),process.stderr.write(`Link copied to clipboard.
1772
- `))}t.open!==!1&&LT(c)}y();import{createInterface as NT}from"node:readline";import{writeFileSync as OT,existsSync as AT,mkdirSync as vT}from"node:fs";import{join as Pu}from"node:path";import{homedir as IT}from"node:os";function $u(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 kt=["january","february","march","april","may","june","july","august","september","october","november","december"],MT=["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"];function DT(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:`${kt[a][0].toUpperCase()}${kt[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:`${kt[a][0].toUpperCase()}${kt[a].slice(1)} ${i}`}}let n=kt.indexOf(e.toLowerCase()),r=n===-1?MT.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:`${kt[o][0].toUpperCase()}${kt[o].slice(1)} ${i}`}}return null}function $T(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 ju(e,t){let s=DT(e);if(!s){process.stderr.write(`invalid month format: ${e}. Use YYYY-MM, month name, or abbreviation.
1772
+ `))}t.open!==!1&&$T(l)}y();import{createInterface as PT}from"node:readline";import{writeFileSync as jT,existsSync as FT,mkdirSync as UT}from"node:fs";import{join as Uu}from"node:path";import{homedir as BT}from"node:os";function Fu(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 kt=["january","february","march","april","may","june","july","august","september","october","november","december"],HT=["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"];function WT(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:`${kt[a][0].toUpperCase()}${kt[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:`${kt[a][0].toUpperCase()}${kt[a].slice(1)} ${i}`}}let n=kt.indexOf(e.toLowerCase()),r=n===-1?HT.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:`${kt[o][0].toUpperCase()}${kt[o].slice(1)} ${i}`}}return null}function XT(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 Bu(e,t){let s=WT(e);if(!s){process.stderr.write(`invalid month format: ${e}. Use YYYY-MM, month name, or abbreviation.
1773
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
1774
1774
  WHERE recalled_at >= ? AND recalled_at < ?
1775
- GROUP BY session_id ORDER BY c DESC LIMIT 1`).get(s.start,s.end),d="None";if(a){let B=n.prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(a.session_id),T=n.prepare("SELECT auto_title, first_user_message, id FROM sessions WHERE id = ?").get(a.session_id);d=B?.alias||T?.auto_title||T?.first_user_message?.slice(0,40)||a.session_id.slice(0,8)}let c=n.prepare("SELECT COALESCE(MAX(token_count), 0) AS m FROM recall_events WHERE recalled_at >= ? AND recalled_at < ?").get(s.start,s.end).m,u=n.prepare(`SELECT CAST(strftime('%H', started_at) AS INTEGER) AS h, COUNT(*) AS c
1775
+ GROUP BY session_id ORDER BY c DESC LIMIT 1`).get(s.start,s.end),d="None";if(a){let F=n.prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(a.session_id),w=n.prepare("SELECT auto_title, first_user_message, id FROM sessions WHERE id = ?").get(a.session_id);d=F?.alias||w?.auto_title||w?.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
1776
1776
  FROM sessions WHERE started_at >= ? AND started_at < ?
1777
- GROUP BY h ORDER BY c DESC LIMIT 3`).all(s.start,s.end),p=$T(u.map(B=>B.h)),m=n.prepare("SELECT COUNT(DISTINCT session_id) AS c FROM recall_events WHERE recalled_at >= ? AND recalled_at < ?").get(s.start,s.end).c,f=n.prepare(`SELECT COUNT(*) AS cnt, COALESCE(AVG(message_count), 0) AS avg_msgs
1777
+ GROUP BY h ORDER BY c DESC LIMIT 3`).all(s.start,s.end),p=XT(u.map(F=>F.h)),m=n.prepare("SELECT COUNT(DISTINCT session_id) AS c FROM recall_events WHERE recalled_at >= ? AND recalled_at < ?").get(s.start,s.end).c,f=n.prepare(`SELECT COUNT(*) AS cnt, COALESCE(AVG(message_count), 0) AS avg_msgs
1778
1778
  FROM sessions WHERE started_at >= ? AND started_at < ?`).get(s.start,s.end),g=n.prepare(`SELECT COUNT(*) AS c FROM sessions
1779
1779
  WHERE started_at >= ? AND started_at < ?
1780
1780
  AND (CAST(strftime('%H', started_at) AS INTEGER) >= 22
1781
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
1782
1782
  FROM session_tags st JOIN sessions s ON s.id = st.session_id
1783
1783
  WHERE s.started_at >= ? AND s.started_at < ?
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:f.cnt,avgMessageCount:f.avg_msgs,nightSessionRatio:f.cnt>0?g/f.cnt:0,debugTagRatio:f.cnt>0?h/f.cnt:0},b=$u(E),S=50;try{let{computeAllHealthScores:B}=await Promise.resolve().then(()=>(fo(),od)),T=B();T.length>0&&(S=Math.round(T.reduce((U,M)=>U+M.score,0)/T.length))}catch{}let C=t.verdict??"";if(!t.verdict){let B=NT({input:process.stdin,output:process.stderr});C=await new Promise(T=>{B.question("Add your take (one line, or press Enter to skip): ",U=>{B.close(),T(U.trim())})})}let w={month:s.label,totalRecalls:r,totalTokensPiped:o,sessionsIndexed:i,mostRecalledSession:d,biggestRecallTokens:c,healthScore:S,mostActiveHours:p,archetype:b,verdict:C},N=await Tn("E",w),z=s.start.slice(0,7),O=t.out??Pu(IT(),"Downloads");AT(O)||vT(O,{recursive:!0});let ee=Pu(O,`recall-wrapped-${z}.png`);OT(ee,N),process.stderr.write(`Wrapped card saved to ${ee}
1785
- `)}he();Gt();Ze();import{createRequire as PT}from"node:module";import{createInterface as jT}from"node:readline";import{stdin as FT,stdout as UT}from"node:process";var BT=PT(import.meta.url),HT=BT(`${le()}/package.json`).version,Bu="https://clauderecall.com/api/feedback",Io=process.env.RECALL_FEEDBACK_API??Bu,Fu=Io===Bu,Mo=2e3;function Hu(e){let t=jT({input:FT,output:UT});return new Promise(s=>t.question(e,n=>{t.close(),s(n.trim())}))}function Uu(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 WT(e){if(e.score!==void 0){let n=Uu(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 Hu("Score (1-5, q to quit): ");if(t.toLowerCase()==="q"||t==="")return console.log("No worries, skipped."),null;let s=Uu(t);return s===null?(console.error("Please enter an integer 1 through 5."),null):s}async function XT(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 Hu(s)}function JT(e){return e.length<=Mo?{value:e,truncated:!1}:{value:e.slice(0,Mo),truncated:!0}}async function Wu(e={}){Fu||process.stderr.write(`[recall] RECALL_FEEDBACK_API override active (${Io}); license token will NOT be sent.
1786
- `);let t=await WT(e);if(t===null)return e.score!==void 0||!process.stdin.isTTY?1:0;let s=await XT(e,t),{value:n,truncated:r}=JT(s);r&&process.stderr.write(`[recall] --message truncated to ${Mo} characters before send.
1787
- `);let o=await Te(),i=Yt(),a=Fu&&o.tier==="pro"&&i?i.license_jwt:null,d={score:t,comment:n.length>0?n:null,surface:"cli",version:HT,os:process.platform,trigger_kind:"manual",license_jwt:a};try{let c=await fetch(Io,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(d)});if(c.ok)return console.log(""),console.log("Thanks. Your feedback landed."),0;let u=await c.json().catch(()=>({}));return c.status===429?(console.log("You submitted feedback recently. Try again later."),0):(console.error(`Feedback failed: ${c.status} ${u.error??"unknown"}`),1)}catch(c){let u=c instanceof Error?c.message:"network error";return console.error(`Feedback could not be sent: ${u}`),1}}var jR=$R(import.meta.url),ps=jR("../package.json").version,k=new PR;k.name("recall").description("Searchable memory for every Claude Code session you have ever run. Local, fast, offline. Run `recall` (no args) for the dashboard, or `recall --help` for the full command list.").version(ps);k.command("index").description("Scan your Claude sessions and build the searchable database. Run this once after install.").option("-f, --force","reindex all files even if unchanged").option("-v, --verbose","show each file as it is processed").action(async e=>{await gi(e)});k.command("list").description("List your sessions, newest first.").option("-p, --project <name>","filter by project name").option("-n, --limit <n>","max rows to show","30").option("-a, --all","include short sessions (2 messages or fewer)").action(e=>{fi(e)});k.command("show <id>").description("Print a full session transcript. Accepts the full id or an 8-char prefix.").option("-r, --raw","print raw JSONL lines instead of formatted output").option("-n, --limit <n>","max messages to show").option("--no-pager","do not auto-pipe long output through less").action((e,t)=>{wi(e,t)});k.command("search <query...>").description("Search every message in every session.").option("-p, --project <name>","restrict results to one project").option("-n, --limit <n>","max results","20").action(async(e,t)=>{await Mi(e.join(" "),t)});k.command("projects").description("List every project with how many sessions are in each.").action(()=>{ji()});k.command("status").description("Show database size, session counts, and whether the daemon is running.").action(()=>{Pi()});k.command("start").description("Start the background daemon. Required for live tab-name tracking and the web UI.").action(async()=>{await Cs()});k.command("stop").description("Stop the background daemon.").action(async()=>{await Bi()});k.command("open").description("Open the local web UI in your browser. Starts the daemon if it is not already running.").action(async()=>{await Hi()});k.command("tui").description("Browse and search sessions in an interactive terminal UI. No browser needed.").action(async()=>{let{runTui:e}=await Promise.resolve().then(()=>(yp(),wp));await e()});k.command("context <id>").description("Pipe a past session into a fresh Claude chat. Prints condensed markdown to stdout.").option("-f, --full","include full tool call and result bodies (much longer)").option("--since <when>","only messages at or after this time (2h, 30m, 1d, YYYY-MM-DD, or ISO)").option("--subagents","also include subagent / sidechain messages").option("--prelude <text>",'prepend a custom header (e.g. "Continue this conversation")').action(async(e,t)=>{await ua(e,t)});k.command("mcp").description("Expose Recall as an MCP server over stdio. Add this to your Claude Desktop / Claude Code MCP config to let Claude search your sessions.").option("--allow-writes","enable write tools (add_tag, set_alias, append_note, \u2026). Off by default; rate-limited and audited when on.").action(async e=>{await pa({allowWrites:!!e.allowWrites})});k.command("paste").description("Save clipboard content (or stdin) into Recall. Opt-in. Secrets are blocked by default; pass --force to override.").option("-l, --list","list archived pastes").option("--purge <id>","permanently delete one paste by id or 8-char prefix").option("-f, --force","skip the secret-scan confirmation prompt").option("--pipe","echo the content to stdout after archiving (for shell pipelines)").option("--dry-run","preview what would be archived without writing").option("--label <text>","short description shown in `recall paste --list`").action(async e=>{await ma(e)});k.command("audit-secrets").description("Scan the database for secrets that slipped through. Read-only by default; pass --redact to scrub in place.").option("--redact","rewrite offending rows in place (your source files are never touched)").option("-v, --verbose","print every session and message containing a hit").action(async e=>{await ga(e)});k.command("titles [action]").description('Audit session titles in the current project. Defaults to "audit".').option("-p, --project <name>","project to audit (defaults to current cwd)").option("--json","machine-readable JSON output").option("--dry-run","classify but do not write the title_quality column").action(async(e,t)=>{if((e??"audit").toLowerCase()==="audit"){await _a(t);return}console.error(`Unknown titles action: ${e}. Supported: audit`),process.exitCode=1});k.command("import-vscode-state").description("Backfill missing tab names by reading VS Code, Cursor, and Windsurf workspace state. Dry-run by default; pass --apply to write.").option("-p, --project <name>","scope to a single project").option("--apply","write the proposed names (default: dry-run)").option("--min-score <n>","minimum match score from 0 to 1 (default 0.7)","0.7").option("--limit <n>","cap the number of proposals returned").option("--source <list>","which editors to scan: vscode | cursor | windsurf | all (default all)","all").option("--json","machine-readable JSON output").action(async e=>{await ya(e)});k.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:f.cnt,avgMessageCount:f.avg_msgs,nightSessionRatio:f.cnt>0?g/f.cnt:0,debugTagRatio:f.cnt>0?h/f.cnt:0},b=Fu(E),S=50;try{let{computeAllHealthScores:F}=await Promise.resolve().then(()=>(_o(),cd)),w=F();w.length>0&&(S=Math.round(w.reduce((U,M)=>U+M.score,0)/w.length))}catch{}let T=t.verdict??"";if(!t.verdict){let F=PT({input:process.stdin,output:process.stderr});T=await new Promise(w=>{F.question("Add your take (one line, or press Enter to skip): ",U=>{F.close(),w(U.trim())})})}let x={month:s.label,totalRecalls:r,totalTokensPiped:o,sessionsIndexed:i,mostRecalledSession:d,biggestRecallTokens:l,healthScore:S,mostActiveHours:p,archetype:b,verdict:T},N=await Tn("E",x),K=s.start.slice(0,7),O=t.out??Uu(BT(),"Downloads");FT(O)||UT(O,{recursive:!0});let $=Uu(O,`recall-wrapped-${K}.png`);jT($,N),process.stderr.write(`Wrapped card saved to ${$}
1785
+ `)}he();Yt();et();import{createRequire as JT}from"node:module";import{createInterface as GT}from"node:readline";import{stdin as YT,stdout as zT}from"node:process";var qT=JT(import.meta.url),KT=qT(`${le()}/package.json`).version,Xu="https://clauderecall.com/api/feedback",Mo=process.env.RECALL_FEEDBACK_API??Xu,Hu=Mo===Xu,Do=2e3;function Ju(e){let t=GT({input:YT,output:zT});return new Promise(s=>t.question(e,n=>{t.close(),s(n.trim())}))}function Wu(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 VT(e){if(e.score!==void 0){let n=Wu(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 Ju("Score (1-5, q to quit): ");if(t.toLowerCase()==="q"||t==="")return console.log("No worries, skipped."),null;let s=Wu(t);return s===null?(console.error("Please enter an integer 1 through 5."),null):s}async function ZT(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 Ju(s)}function QT(e){return e.length<=Do?{value:e,truncated:!1}:{value:e.slice(0,Do),truncated:!0}}async function Gu(e={}){Hu||process.stderr.write(`[recall] RECALL_FEEDBACK_API override active (${Mo}); license token will NOT be sent.
1786
+ `);let t=await VT(e);if(t===null)return e.score!==void 0||!process.stdin.isTTY?1:0;let s=await ZT(e,t),{value:n,truncated:r}=QT(s);r&&process.stderr.write(`[recall] --message truncated to ${Do} characters before send.
1787
+ `);let o=await Te(),i=Gt(),a=Hu&&o.tier==="pro"&&i?i.license_jwt:null,d={score:t,comment:n.length>0?n:null,surface:"cli",version:KT,os:process.platform,trigger_kind:"manual",license_jwt:a};try{let l=await fetch(Mo,{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 GR=XR(import.meta.url),ps=GR("../package.json").version,C=new JR;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(ps);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 gi(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=>{fi(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)=>{wi(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 Pi(e.join(" "),t)});C.command("projects").description("List every project with how many sessions are in each.").action(()=>{Ui()});C.command("status").description("Show database size, session counts, and whether the daemon is running.").action(()=>{Fi()});C.command("start").description("Start the background daemon. Required for live tab-name tracking and the web UI.").action(async()=>{await Cs()});C.command("stop").description("Stop the background daemon.").action(async()=>{await Wi()});C.command("open").description("Open the local web UI in your browser. Starts the daemon if it is not already running.").action(async()=>{await Xi()});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(()=>(xp(),Rp));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 ma(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 ga({allowWrites:!!e.allowWrites})});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 fa(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 _a(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 Ea(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 Ra(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",`
1788
1788
  Two lanes:
1789
1789
  Tier-2 (default, recommended): on-device 768-d embeddings via bge-base-en-v1.5
1790
1790
  + sqlite-vec. No network, no token spend. Powered by:
@@ -1800,5 +1800,7 @@ Two lanes:
1800
1800
  Reindex chunks-per-session cap (advanced):
1801
1801
  Set RECALL_REINDEX_MAX_CHUNKS=200 to cap each session at 200 chunks for a
1802
1802
  faster first pass. Default is 0 (no cap, full accuracy).
1803
- `).action(async(e,t,s)=>{await ec(e,{...s,_autoExtractAction:t})});k.command("embeddings [action]").description('Audit embedding coverage and backfill missing ones. Defaults to "audit". Actions: audit, backfill-summaries, backfill-messages.').option("-p, --project <name>","scope to a single project").option("-n, --limit <n>","max sessions to process during backfill").option("--json","emit JSON instead of formatted output").action(async(e,t)=>{await oc(e,t)});var ms=k.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 pc(t)})}function kp(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 yc(t)})}function Cp(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 Lp(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 Np(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 Wc(t)})}xp(ms.command("outputs"));kp(ms.command("citations"));Cp(ms.command("l1"));Lp(ms.command("links"));Np(ms.command("bug-patterns"));xp(k.command("extract-outputs"));kp(k.command("infer-citations"));Cp(k.command("infer-l1"));Lp(k.command("infer-links"));Np(k.command("infer-bug-patterns"));k.command("neighborhood <id>").description("Bundle a session with its parents, children, citations, and similar sessions. Pipe into `claude` to seed a fresh chat with rich context.").option("-b, --budget <n>","token budget for the bundle (default 4000)","4000").option("--scoring <mode>","pagerank | embedding-rerank | hybrid (default hybrid)","hybrid").option("-e, --edge-types <list>","comma-separated link types to include: citation,similar,skill_track,bug_pattern,wiki_link,temporal_proximity (default all)").option("--max-depth <n>","how far to walk the link graph (default 2)","2").option("--no-wiki-links","exclude manual wiki links").option("--include-suggestions","include pending suggestions (debug only)").option("--json","emit the full result as JSON instead of markdown").action(async(e,t)=>{await tl(e,t)});k.command("similar <session-id>").description("Find sessions about the same topic as this one. Pro feature.").option("-n, --limit <n>","max results","10").action(async(e,t)=>{let{requireProOrExit:s}=await Promise.resolve().then(()=>(he(),Ts));await s("Similar sessions");let{isModelInstalled:n}=await Promise.resolve().then(()=>(js(),Ya)),{loadEmbedder:r,getEmbedderStatus:o}=await Promise.resolve().then(()=>(et(),xr)),{findSimilarSessions:i}=await Promise.resolve().then(()=>(Rp(),Tp));if(!n()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}o().loaded||await r();let a=Math.max(1,Math.min(50,Number(t.limit??10))),d=await i(e,a);if(d.length===0){console.log("No similar sessions found.");return}for(let c of d)console.log(` ${c.sessionId} similarity=${c.similarity.toFixed(3)}`)});k.command("stats [id]").description("How much you have spent and how many tokens you have used. No args = overview. Pass a session id for one session, or --project for one project.").option("-p, --project <name>","show stats for a single project").option("-d, --days <n>","restrict the overview to the last N days (7 or 30)").option("--backfill","compute usage for already-indexed messages (safe to rerun)").option("-n, --limit <n>","max messages to scan during backfill").option("--json","emit JSON instead of a formatted table").action(async(e,t)=>{await cl(e,t)});k.command("correlate [id]").description("Link sessions to the git commits they wrote. Read-only. No args = batch mode; pass an id to correlate one.").option("-n, --limit <n>","max sessions to process in batch mode").option("--json","emit JSON instead of formatted output").action(async(e,t)=>{await pl(e,t)});var Jo=k.command("correlator").description("Diagnose and fix terminal-to-session matching. Subcommands: audit | debug | restore.");function Op(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 zl(t)})}function Ap(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 ql(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 El(t)})}Op(Jo.command("debug"));Ap(Jo.command("restore"));vp(Jo.command("audit"));Op(k.command("correlator-debug"));Ap(k.command("correlator-restore"));k.command("name <id-prefix> <name>").description("Rename a session. By default it stays linked to its terminal tab, so renaming the tab later still updates the name. Use --pin to lock the name permanently. Daemon must be running.").option("--json","emit JSON").option("--pin","lock the name; later tab renames will NOT overwrite it").action(async(e,t,s)=>{await Xl(e,t,s)});k.command("doctor").description("Diagnose database health: size, WAL, FTS fragmentation, integrity, alias invariant. Exits non-zero on issues.").option("--json","emit JSON instead of formatted output").action(async e=>{let t=await Nl(e);process.exit(t)});k.command("optimize").description("Run maintenance: WAL checkpoint, FTS5 merge, planner stats. Use --vacuum to also reclaim free pages (requires daemon stopped).").option("--vacuum","also run VACUUM to reclaim free pages (rewrites the whole DB; daemon must be stopped)").option("--json","emit JSON instead of formatted output").action(async e=>{let t=await Ol(e);process.exit(t)});k.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 vl(e);process.exit(t)});k.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 Wl({_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(k.command("correlator-audit"));k.command("blame <sha>").description("Look up which session(s) wrote the code in a commit. Reverse of `correlate`.").option("--json","emit JSON instead of formatted output").action(async(e,t)=>{await Kl(e,t)});k.command("digest").description("Today's rediscovery picks: a session worth revisiting, the costliest of the week, and the one behind your latest commit.").option("--json","emit JSON instead of formatted output").action(async e=>{await Ql(e)});k.command("install-extension").description("Install the bundled VS Code / Cursor / Windsurf extension into your editor. Auto-detects which CLIs are installed.").option("--editor <name>","install only into one editor: code | cursor | code-insiders | windsurf").option("--print-path","print the path to the bundled .vsix and exit").action(async e=>{await rd(e)});k.command("health [project]").description("Score how well-organized each project's sessions are. Worst first, or pass a project name for a single breakdown.").option("--json","emit JSON instead of formatted output").action((e,t)=>{ad(e,t)});k.command("verify [action]").description('Toggle verification badges in the UI. Defaults to "status". Actions: on, off, status.').action(e=>{cd(e)});k.command("activate <license-key>").description("Activate your Pro license. Run once after purchase.").action(async e=>{await Ed(e)});k.command("upgrade").description("Open the Pro pricing page in your browser.").action(async()=>{await Sd()});k.command("trial").description("Start a 7-day Pro trial. Opens the signup page in your browser. No card required.").action(async()=>{await yd()});var Ln=k.command("telemetry").description('Manage the opt-in anonymous install ping. Defaults to "view".');Ln.command("view",{isDefault:!0}).description("Show current decision, state file path, and next-ping payload.").action(async()=>{await Od(ps)});Ln.command("on").description("Opt in. One anonymous ping per machine per month. See https://clauderecall.com/telemetry").action(async()=>{await Ld()});Ln.command("off").description("Opt out. Deletes the nonce. No further pings.").action(async()=>{await Nd()});Ln.command("status").description("Alias for view.").action(async()=>{await wo(ps)});var Yo=k.command("license").description('Show or remove the Pro license on this machine. Defaults to "status".');Yo.command("status",{isDefault:!0}).description("Show the current license tier.").action(async()=>{await Id()});Yo.command("deactivate").description("Remove the stored license from this machine. Reverses `recall activate`.").action(()=>{Dd()});Yo.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 Md()});var FR=k.command("thread").description("Group related sessions into threads, then list, show, link, merge, or scan them."),UR=k.command("threads").description("Alias for `thread`. Both forms accept the same subcommands.");function Ip(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 fu(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=>{mu(t)}),e.command("list").description("List threads, newest first.").option("--archived","include archived threads").option("--json","emit JSON instead of a table").action(t=>{Pd(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)=>{jd(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)=>{Fd(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)=>{Ud(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)=>{Bd(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)=>{Hd(t,s)}),e.command("rename <id-prefix> <new-name>").description("Rename a thread.").option("--json","emit JSON").action((t,s,n)=>{Wd(t,s,n)}),e.command("close <id-prefix>").description("Mark a thread as closed (work complete).").option("--json","emit JSON").action((t,s)=>{Xd(t,s)}),e.command("reopen <id-prefix>").description("Reopen a closed thread.").option("--json","emit JSON").action((t,s)=>{Jd(t,s)}),e.command("archive <id-prefix>").description("Archive a thread (hidden from the default list).").option("--json","emit JSON").action((t,s)=>{Yd(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)=>{Gd(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)=>{zd(t,s)})}Ip(FR);Ip(UR);k.command("share [id]").description("Save a session as a shareable PNG card. No args = your last recalled session. Saved to ~/Downloads and opened.").option("--style <A|B|C|D>","card style (default A: Minimal)").option("--verdict <quote>","your one-line take on the session").option("--link","also generate a shareable URL and copy it to the clipboard").option("--clipboard","also copy the PNG to the system clipboard").option("--out <path>","override the save directory").option("--no-open","do not auto-open the saved PNG").action(async(e,t)=>{await Du(e,t)});k.command("feedback").description("Send a 1-5 rating and optional comment to the team. Interactive by default; pass --score (and optionally --message) to skip prompts.").option("--score <1-5>","rating from 1 (bad) to 5 (great)").option("--message <text>","optional comment to send with the rating").action(async e=>{let t=await Wu(e);t!==0&&(process.exitCode=t)});k.command("wrapped [month]").description("Save your monthly recap as a shareable PNG card. Defaults to the current month. Accepts YYYY-MM, full name, or abbreviation.").option("--verdict <quote>","your one-line take on the month").option("--out <path>","override the save directory").action(async(e,t)=>{await ju(e,t)});process.env.CLAUDECODE&&!process.stdout.isTTY&&process.stderr.write(`<claude-code-hint v="1" type="plugin" value="claude-recall@claude-plugins-official" />
1804
- `);k.action(async()=>{await _d()});k.hook("preAction",async(e,t)=>{let s=t.name();try{await vd(s,ps)}catch{}Cd(ps).catch(()=>{})});k.parseAsync(process.argv).catch(e=>{console.error(e),process.exit(1)});
1803
+ `).action(async(e,t,s)=>{await rc(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 lc(e,t)});var ms=C.command("infer").description("Discover links between sessions. Subcommands: outputs | citations | l1 | links | bug-patterns.");function Lp(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 _c(t)})}function Np(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 kc(t)})}function Op(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 Nc(t)})}function Ap(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 $c(t)})}function vp(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 Yc(t)})}Lp(ms.command("outputs"));Np(ms.command("citations"));Op(ms.command("l1"));Ap(ms.command("links"));vp(ms.command("bug-patterns"));Lp(C.command("extract-outputs"));Np(C.command("infer-citations"));Op(C.command("infer-l1"));Ap(C.command("infer-links"));vp(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 ol(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=(g,h)=>{if(s){let E=Math.round(performance.now()-h);process.stderr.write(`[similar:timing] ${g}: ${E}ms
1804
+ `)}},r=performance.now(),{requireProOrExit:o}=await Promise.resolve().then(()=>(he(),Ts));await o("Similar sessions"),n("requireProOrExit",r);let i=performance.now(),{isModelInstalled:a}=await Promise.resolve().then(()=>(js(),qa)),{loadEmbedder:d,getEmbedderStatus:l}=await Promise.resolve().then(()=>(st(),kr)),{findSimilarSessions:u}=await Promise.resolve().then(()=>(Cp(),kp));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 g=performance.now();await d(),n("loadEmbedder (cold)",g)}let p=Math.max(1,Math.min(50,Number(t.limit??10))),m=performance.now(),f=await u(e,p);if(n("findSimilarSessions",m),f.length===0){console.log("No similar sessions found.");return}for(let g of f)console.log(` ${g.sessionId} similarity=${g.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 pl(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 _l(e,t)});var Go=C.command("correlator").description("Diagnose and fix terminal-to-session matching. Subcommands: audit | debug | restore.");function Ip(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 Vl(t)})}function Mp(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 Zl(t)})}function Dp(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 wl(t)})}Ip(Go.command("debug"));Mp(Go.command("restore"));Dp(Go.command("audit"));Ip(C.command("correlator-debug"));Mp(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 Yl(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 vl(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 Il(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 Dl(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 Gl({_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)});Dp(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 Ql(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 sd(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 ad(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)=>{dd(e,t)});C.command("verify [action]").description('Toggle verification badges in the UI. Defaults to "status". Actions: on, off, status.').action(e=>{ud(e)});C.command("activate <license-key>").description("Activate your Pro license. Run once after purchase.").action(async e=>{await wd(e)});C.command("upgrade").description("Open the Pro pricing page in your browser.").action(async()=>{await Td()});C.command("trial").description("Start a 7-day Pro trial. Opens the signup page in your browser. No card required.").action(async()=>{await xd()});var Ln=C.command("telemetry").description('Manage the opt-in anonymous install ping. Defaults to "view".');Ln.command("view",{isDefault:!0}).description("Show current decision, state file path, and next-ping payload.").action(async()=>{await Id(ps)});Ln.command("on").description("Opt in. One anonymous ping per machine per month. See https://clauderecall.com/telemetry").action(async()=>{await Ad()});Ln.command("off").description("Opt out. Deletes the nonce. No further pings.").action(async()=>{await vd()});Ln.command("status").description("Alias for view.").action(async()=>{await yo(ps)});var Yo=C.command("license").description('Show or remove the Pro license on this machine. Defaults to "status".');Yo.command("status",{isDefault:!0}).description("Show the current license tier.").action(async()=>{await $d()});Yo.command("deactivate").description("Remove the stored license from this machine. Reverses `recall activate`.").action(()=>{jd()});Yo.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 Pd()});var YR=C.command("thread").description("Group related sessions into threads, then list, show, link, merge, or scan them."),zR=C.command("threads").description("Alias for `thread`. Both forms accept the same subcommands.");function $p(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 Eu(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=>{_u(t)}),e.command("list").description("List threads, newest first.").option("--archived","include archived threads").option("--json","emit JSON instead of a table").action(t=>{Ud(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)=>{Bd(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)=>{Hd(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)=>{Wd(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)=>{Xd(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)=>{Jd(t,s)}),e.command("rename <id-prefix> <new-name>").description("Rename a thread.").option("--json","emit JSON").action((t,s,n)=>{Gd(t,s,n)}),e.command("close <id-prefix>").description("Mark a thread as closed (work complete).").option("--json","emit JSON").action((t,s)=>{Yd(t,s)}),e.command("reopen <id-prefix>").description("Reopen a closed thread.").option("--json","emit JSON").action((t,s)=>{zd(t,s)}),e.command("archive <id-prefix>").description("Archive a thread (hidden from the default list).").option("--json","emit JSON").action((t,s)=>{qd(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)=>{Kd(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)=>{Vd(t,s)})}$p(YR);$p(zR);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 ju(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 Gu(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 Bu(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 bd()});C.hook("preAction",async(e,t)=>{let s=t.name();try{await Dd(s,ps)}catch{}Od(ps).catch(()=>{})});C.parseAsync(process.argv).catch(e=>{console.error(e),process.exit(1)});