@clauderecallhq/cli 0.66.0 → 0.68.3

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 Vu=Object.defineProperty;var N=(e,t)=>()=>(e&&(t=e(e=0)),t);var fe=(e,t)=>{for(var s in t)Vu(e,s,{get:t[s],enumerable:!0})};import{createRequire as Zu}from"node:module";var Qu,ep,tp,_n,hn,rs,En=N(()=>{"use strict";{let e=process.emit.bind(process);process.emit=function(t,...s){let n=s[0];return t==="warning"&&n instanceof Error&&n.name==="ExperimentalWarning"&&/SQLite/i.test(n.message)?!1:e(t,...s)}}Qu=Zu(import.meta.url),ep=["node","sqlite"].join(":"),tp=Qu(ep),_n=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)}},hn=class{inner;extensionLoadingEnabled=!1;txDepth=0;constructor(t,s={}){this.inner=new tp.DatabaseSync(t,{readOnly:s.readonly??!1,allowExtension:!0})}prepare(t){return new _n(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)}},rs=hn});import{homedir as ko}from"node:os";import{join as Mt,basename as sp}from"node:path";import{existsSync as No,mkdirSync as np,chmodSync as rp,readdirSync as Ro,statSync as op}from"node:fs";function P(){No(x)||np(x,{recursive:!0,mode:448}),process.platform!=="win32"&&rp(x,448)}function Sn(e){return e.replace(/^-/,"/").replace(/-/g,"/")}function Co(e){let t=Sn(e);return sp(t)||t}function Lo(){if(!No(bn))return[];let e=[],t=Ro(bn,{withFileTypes:!0}).filter(s=>s.isDirectory()).map(s=>s.name);for(let s of t){let n=Mt(bn,s),r=Ro(n,{withFileTypes:!0});for(let o of r){if(!o.isFile()||!o.name.endsWith(".jsonl"))continue;let i=Mt(n,o.name),a=op(i);e.push({sessionFile:i,encodedProject:s,mtime:a.mtimeMs,size:a.size})}}return e}var bn,x,te,j=N(()=>{"use strict";bn=Mt(ko(),".claude","projects"),x=process.env.RECALL_HOME?process.env.RECALL_HOME:Mt(ko(),".recall"),te=Mt(x,"db.sqlite")});function Ao(e){let t=e.prepare("PRAGMA table_info(sessions)").all(),s=new Set(t.map(f=>f.name)),n=[["total_input_tokens","INTEGER"],["total_output_tokens","INTEGER"],["total_cache_create_tokens","INTEGER"],["total_cache_read_tokens","INTEGER"],["primary_model","TEXT"],["auto_title","TEXT"],["auto_title_source","TEXT"],["auto_title_generated_at","INTEGER"],["auto_title_history","TEXT"],["verification_status","TEXT"],["verification_computed_at","INTEGER"],["title_quality","TEXT"],["title_quality_computed_at","INTEGER"]];for(let[f,g]of n)s.has(f)||e.exec(`ALTER TABLE sessions ADD COLUMN ${f} ${g}`);let r=e.prepare("PRAGMA table_info(collection_sessions)").all(),o=new Set(r.map(f=>f.name)),i=[["source","TEXT NOT NULL DEFAULT 'manual'"],["rule_id","TEXT"]];for(let[f,g]of i)o.has(f)||e.exec(`ALTER TABLE collection_sessions ADD COLUMN ${f} ${g}`);let a=e.prepare("PRAGMA table_info(session_notes)").all(),l=new Set(a.map(f=>f.name)),c=[["auto_synopsis","TEXT"],["auto_synopsis_generated_at","INTEGER"],["auto_synopsis_history","TEXT"]];for(let[f,g]of c)l.has(f)||e.exec(`ALTER TABLE session_notes ADD COLUMN ${f} ${g}`);let u=e.prepare("PRAGMA table_info(threads)").all();new Set(u.map(f=>f.name)).has("folder_id")||(e.exec("ALTER TABLE threads ADD COLUMN folder_id TEXT REFERENCES thread_folders(id) ON DELETE SET NULL"),e.exec("CREATE INDEX IF NOT EXISTS idx_threads_folder ON threads(folder_id)"));let p=e.prepare("PRAGMA table_info(thread_folders)").all(),m=new Set(p.map(f=>f.name));m.has("project_scope")||(e.exec("ALTER TABLE thread_folders ADD COLUMN project_scope TEXT"),e.exec("CREATE INDEX IF NOT EXISTS idx_thread_folders_project ON thread_folders(project_scope)")),m.has("sort_order")||e.exec("ALTER TABLE thread_folders ADD COLUMN sort_order INTEGER NOT NULL DEFAULT 0"),e.exec(`
3
+ var fm=Object.defineProperty;var L=(e,t)=>()=>(e&&(t=e(e=0)),t);var fe=(e,t)=>{for(var s in t)fm(e,s,{get:t[s],enumerable:!0})};import{createRequire as _m}from"node:module";var hm,Em,bm,Tn,yn,is,wn=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)}}hm=_m(import.meta.url),Em=["node","sqlite"].join(":"),bm=hm(Em),Tn=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)}},yn=class{inner;extensionLoadingEnabled=!1;txDepth=0;constructor(t,s={}){this.inner=new bm.DatabaseSync(t,{readOnly:s.readonly??!1,allowExtension:!0})}prepare(t){return new Tn(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)}},is=yn});import{homedir as vo}from"node:os";import{join as Mt,basename as Sm}from"node:path";import{existsSync as Io,mkdirSync as Tm,chmodSync as ym,readdirSync as Oo,statSync as wm}from"node:fs";function j(){Io(x)||Tm(x,{recursive:!0,mode:448}),process.platform!=="win32"&&ym(x,448)}function xn(e){return e.replace(/^-/,"/").replace(/-/g,"/")}function Mo(e){let t=xn(e);return Sm(t)||t}function Do(){if(!Io(Rn))return[];let e=[],t=Oo(Rn,{withFileTypes:!0}).filter(s=>s.isDirectory()).map(s=>s.name);for(let s of t){let n=Mt(Rn,s),r=Oo(n,{withFileTypes:!0});for(let o of r){if(!o.isFile()||!o.name.endsWith(".jsonl"))continue;let i=Mt(n,o.name),a=wm(i);e.push({sessionFile:i,encodedProject:s,mtime:a.mtimeMs,size:a.size})}}return e}var Rn,x,te,P=L(()=>{"use strict";Rn=process.env.CLAUDE_PROJECTS_DIR?process.env.CLAUDE_PROJECTS_DIR:Mt(vo(),".claude","projects"),x=process.env.RECALL_HOME?process.env.RECALL_HOME:Mt(vo(),".recall"),te=Mt(x,"db.sqlite")});function jo(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(),l=new Set(a.map(f=>f.name)),c=[["auto_synopsis","TEXT"],["auto_synopsis_generated_at","INTEGER"],["auto_synopsis_history","TEXT"]];for(let[f,g]of c)l.has(f)||e.exec(`ALTER TABLE session_notes ADD COLUMN ${f} ${g}`);let u=e.prepare("PRAGMA table_info(threads)").all();new Set(u.map(f=>f.name)).has("folder_id")||(e.exec("ALTER TABLE threads ADD COLUMN folder_id TEXT REFERENCES thread_folders(id) ON DELETE SET NULL"),e.exec("CREATE INDEX IF NOT EXISTS idx_threads_folder ON threads(folder_id)"));let m=e.prepare("PRAGMA table_info(thread_folders)").all(),p=new Set(m.map(f=>f.name));p.has("project_scope")||(e.exec("ALTER TABLE thread_folders ADD COLUMN project_scope TEXT"),e.exec("CREATE INDEX IF NOT EXISTS idx_thread_folders_project ON thread_folders(project_scope)")),p.has("sort_order")||e.exec("ALTER TABLE thread_folders ADD COLUMN sort_order INTEGER NOT NULL DEFAULT 0"),e.exec(`
4
4
  CREATE TABLE IF NOT EXISTS message_embeddings (
5
5
  message_uuid TEXT PRIMARY KEY REFERENCES messages(uuid) ON DELETE CASCADE,
6
6
  session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
@@ -12,7 +12,7 @@ var Vu=Object.defineProperty;var N=(e,t)=>()=>(e&&(t=e(e=0)),t);var fe=(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 Oo,Io=N(()=>{"use strict";Oo=`
15
+ `)}var $o,Po=L(()=>{"use strict";$o=`
16
16
  PRAGMA journal_mode = WAL;
17
17
  PRAGMA synchronous = NORMAL;
18
18
  PRAGMA foreign_keys = ON;
@@ -251,20 +251,70 @@ CREATE TABLE IF NOT EXISTS chunk_queue (
251
251
  );
252
252
  CREATE INDEX IF NOT EXISTS idx_chunk_queue_session ON chunk_queue(session_id);
253
253
 
254
- CREATE TRIGGER IF NOT EXISTS messages_vec_ai AFTER INSERT ON messages
255
- WHEN new.is_sidechain = 0 AND new.content_text IS NOT NULL
254
+ -- v0.67.0 -- retention/archive (P6). Power-user durability: sessions older
255
+ -- than the user chosen window can be moved to messages_archive so the hot
256
+ -- DB stays small without dropping data. Sessions metadata stays hot for
257
+ -- list/search by title; only the message bodies move. The "recall archive
258
+ -- restore <id>" command reverses the move. Source JSONLs are still the
259
+ -- immutable ground truth -- the archive table is a fast-path; in extremis
260
+ -- a session can be reindexed from its file_path on disk.
261
+ --
262
+ -- archive_status on the sessions row drives the UI: archived sessions show
263
+ -- a badge and a "restore to load full transcript" affordance.
264
+ CREATE TABLE IF NOT EXISTS messages_archive (
265
+ uuid TEXT PRIMARY KEY,
266
+ session_id TEXT NOT NULL,
267
+ parent_uuid TEXT,
268
+ type TEXT,
269
+ role TEXT,
270
+ timestamp TEXT,
271
+ is_sidechain INTEGER NOT NULL DEFAULT 0,
272
+ content_text TEXT,
273
+ tool_names TEXT,
274
+ raw_json TEXT,
275
+ archived_at TEXT NOT NULL DEFAULT (datetime('now'))
276
+ );
277
+ CREATE INDEX IF NOT EXISTS idx_messages_archive_session ON messages_archive(session_id);
278
+
279
+ -- v0.67.0 \u2014 semantic enqueue gate. Without this, every INSERT/DELETE/UPDATE
280
+ -- on messages enqueued a chunk_queue row, regardless of whether the embedder
281
+ -- worker was running. Power users with semantic disabled (the default)
282
+ -- accumulated 50M+ orphan rows in days, growing the DB by ~1 GB/day.
283
+ -- The gate is a single key in app_settings, kept in sync with
284
+ -- ~/.recall/config.json:semantic.enabled by the daemon at boot and on every
285
+ -- semantic-config write.
286
+ CREATE TABLE IF NOT EXISTS app_settings (
287
+ key TEXT PRIMARY KEY,
288
+ value TEXT NOT NULL
289
+ );
290
+ INSERT OR IGNORE INTO app_settings(key, value) VALUES ('semantic_enabled', '0');
291
+
292
+ -- Drop unconditional v0.10/v0.11-era triggers; replaced below with the gated
293
+ -- versions. Idempotent: SQLite no-ops when the trigger does not exist, so
294
+ -- this is safe to run on every boot and on fresh databases.
295
+ DROP TRIGGER IF EXISTS messages_vec_ai;
296
+ DROP TRIGGER IF EXISTS messages_vec_ad;
297
+ DROP TRIGGER IF EXISTS messages_vec_au;
298
+
299
+ CREATE TRIGGER messages_vec_ai AFTER INSERT ON messages
300
+ WHEN new.is_sidechain = 0
301
+ AND new.content_text IS NOT NULL
302
+ AND (SELECT value FROM app_settings WHERE key = 'semantic_enabled') = '1'
256
303
  BEGIN
257
304
  INSERT INTO chunk_queue(session_id, message_uuid, action, enqueued_at)
258
305
  VALUES (new.session_id, new.uuid, 'embed', datetime('now'));
259
306
  END;
260
307
 
261
- CREATE TRIGGER IF NOT EXISTS messages_vec_ad AFTER DELETE ON messages BEGIN
308
+ CREATE TRIGGER messages_vec_ad AFTER DELETE ON messages
309
+ WHEN (SELECT value FROM app_settings WHERE key = 'semantic_enabled') = '1'
310
+ BEGIN
262
311
  INSERT INTO chunk_queue(session_id, message_uuid, action, enqueued_at)
263
312
  VALUES (old.session_id, old.uuid, 'delete', datetime('now'));
264
313
  END;
265
314
 
266
- CREATE TRIGGER IF NOT EXISTS messages_vec_au AFTER UPDATE OF content_text ON messages
315
+ CREATE TRIGGER messages_vec_au AFTER UPDATE OF content_text ON messages
267
316
  WHEN new.is_sidechain = 0
317
+ AND (SELECT value FROM app_settings WHERE key = 'semantic_enabled') = '1'
268
318
  BEGIN
269
319
  INSERT INTO chunk_queue(session_id, message_uuid, action, enqueued_at)
270
320
  VALUES (new.session_id, new.uuid, 'reembed', datetime('now'));
@@ -618,33 +668,33 @@ CREATE INDEX IF NOT EXISTS idx_synth_results_target
618
668
  ON bug_synthesis_results(scope, target_id, created_at DESC);
619
669
  CREATE INDEX IF NOT EXISTS idx_synth_results_created
620
670
  ON bug_synthesis_results(created_at DESC);
621
- `});import*as vo from"sqlite-vec";function _(){if(ae)return ae;P(),ae=new rs(te),vo.load(ae),ae.pragma("cache_size = -64000"),ae.pragma("mmap_size = 268435456"),ae.pragma("temp_store = MEMORY"),ae.pragma("busy_timeout = 5000"),ae.pragma("journal_size_limit = 67108864"),ae.pragma("wal_autocheckpoint = 1000"),ae.exec(Oo),Ao(ae);try{ae.exec("PRAGMA optimize")}catch{}return ae}var ae,T=N(()=>{"use strict";En();j();Io();ae=null});import Ne from"chalk";import{formatDistanceToNowStrict as pp,parseISO as mp}from"date-fns";function Y(e,t){if(!e)return"";let s=e.replace(/\s+/g," ").trim();return s.length<=t?s:s.slice(0,t-1)+"\u2026"}function W(e){if(!e)return"";try{return pp(mp(e),{addSuffix:!0})}catch{return""}}function H(e){return e.slice(0,8)}function Do(e,t){if(!t)return e;let s=t.split(/\s+/).filter(r=>r.length>1).map(r=>r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));if(s.length===0)return e;let n=new RegExp(`(${s.join("|")})`,"gi");return e.replace(n,r=>Ne.bgYellow.black(r))}var d,I=N(()=>{"use strict";d={dim:Ne.gray,bold:Ne.bold,project:Ne.cyan,user:Ne.blue,assistant:Ne.green,tool:Ne.magenta,warn:Ne.yellow,err:Ne.red,ok:Ne.green,accent:Ne.hex("#f97316")}});import{existsSync as si,readFileSync as dm,writeFileSync as um,unlinkSync as pm}from"node:fs";import{join as mm}from"node:path";function jt(){if(!si(pt))return null;try{let e=dm(pt,"utf8"),t=JSON.parse(e);return typeof t.license_jwt!="string"||t.license_jwt.length===0?null:t}catch{return null}}function ni(e){P(),um(pt,JSON.stringify(e,null,2)+`
622
- `,{mode:384})}function ri(){si(pt)&&pm(pt)}var pt,Pt=N(()=>{"use strict";j();pt=mm(x,"license.json")});var oi,An,ii,ai,ci=N(()=>{"use strict";oi=`-----BEGIN PUBLIC KEY-----
671
+ `});import*as Fo from"sqlite-vec";function _(){if(ae)return ae;j(),ae=new is(te),Fo.load(ae),ae.pragma("cache_size = -64000"),ae.pragma("mmap_size = 268435456"),ae.pragma("temp_store = MEMORY"),ae.pragma("busy_timeout = 5000"),ae.pragma("journal_size_limit = 67108864"),ae.pragma("wal_autocheckpoint = 1000"),ae.exec($o),jo(ae);try{ae.exec("PRAGMA optimize")}catch{}return ae}var ae,w=L(()=>{"use strict";wn();P();Po();ae=null});import Ne from"chalk";import{formatDistanceToNowStrict as Am,parseISO as Om}from"date-fns";function z(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 Am(Om(e),{addSuffix:!0})}catch{return""}}function H(e){return e.slice(0,8)}function Ho(e,t){if(!t)return e;let s=t.split(/\s+/).filter(r=>r.length>1).map(r=>r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));if(s.length===0)return e;let n=new RegExp(`(${s.join("|")})`,"gi");return e.replace(n,r=>Ne.bgYellow.black(r))}var d,v=L(()=>{"use strict";d={dim:Ne.gray,bold:Ne.bold,project:Ne.cyan,user:Ne.blue,assistant:Ne.green,tool:Ne.magenta,warn:Ne.yellow,err:Ne.red,ok:Ne.green,accent:Ne.hex("#f97316")}});import{existsSync as ci,readFileSync as Lp,writeFileSync as Cp,unlinkSync as Ap}from"node:fs";import{join as Op}from"node:path";function jt(){if(!ci(mt))return null;try{let e=Lp(mt,"utf8"),t=JSON.parse(e);return typeof t.license_jwt!="string"||t.license_jwt.length===0?null:t}catch{return null}}function li(e){j(),Cp(mt,JSON.stringify(e,null,2)+`
672
+ `,{mode:384})}function di(){ci(mt)&&Ap(mt)}var mt,Pt=L(()=>{"use strict";P();mt=Op(x,"license.json")});var ui,$n,mi,pi,gi=L(()=>{"use strict";ui=`-----BEGIN PUBLIC KEY-----
623
673
  MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZysO2FffTLdyxQnTmnt78/ayvqz9
624
674
  kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
625
675
  -----END PUBLIC KEY-----
626
- `,An="ES256",ii="clauderecall.com",ai="clauderecall-cli"});import{jwtVerify as gm,importSPKI as fm}from"jose";async function _m(){return ls||(ls=await fm(oi,An),ls)}async function ds(e){try{let t=await _m(),{payload:s}=await gm(e,t,{issuer:ii,audience:ai,algorithms:[An]});return{valid:!0,claims:s}}catch(t){return{valid:!1,reason:t instanceof Error?t.message:"verification failed"}}}var ls,In=N(()=>{"use strict";ci();ls=null});import{createHash as hm}from"node:crypto";import{hostname as Em,userInfo as bm,platform as Sm,arch as ym}from"node:os";function us(){let e="unknown";try{e=bm().username}catch{}let t=[Em(),e,Sm(),ym()];return hm("sha256").update(t.join("\0")).digest("hex")}var vn=N(()=>{"use strict"});function xt(){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 ps=N(()=>{"use strict"});import{existsSync as Tm,readFileSync as wm,writeFileSync as xm}from"node:fs";import{join as Rm}from"node:path";function ms(){if(!Tm(Mn))return null;try{let e=JSON.parse(wm(Mn,"utf8"));return typeof e.license_key!="string"||typeof e.last_checked_at!="string"||typeof e.revoked!="boolean"?null:e}catch{return null}}function Lm(e){P(),xm(Mn,JSON.stringify(e,null,2)+`
627
- `,{mode:384})}async function Om(e,t){let s=null,n=null;try{s=new AbortController,n=setTimeout(()=>s?.abort(),Cm);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 li(e,t={}){let s=ms(),n=t.apiUrl??`${xt()}/api/license/check`,r=s?.license_key===e,o=!s||!r||Date.now()-new Date(s.last_checked_at).getTime()>=km;if(!t.force&&!o)return s;let i=await Om(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 Lm(a),a}function di(e){let t=ms();return!t||t.license_key!==e?null:t.revoked?{revoked:!0,reason:t.reason?`license revoked: ${t.reason}`:"license revoked by issuer"}:Date.now()-new Date(t.last_checked_at).getTime()>Nm?{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 Mn,km,Nm,Cm,$n=N(()=>{"use strict";j();ps();Mn=Rm(x,"license-check.json"),km=1440*60*1e3,Nm=720*60*60*1e3,Cm=1e4});function Im(e=Date.now()){return e<Dn}function pi(e=Date.now()){return Im(e)?`(one-time purchase, $${Am} through May 2026 Founder pricing, $${ui} from June, lifetime updates either way)`:`(one-time purchase, $${ui}, lifetime updates)`}var Dn,Am,ui,jn=N(()=>{"use strict";Dn=Date.UTC(2026,5,1,7,0,0),Am="29.69",ui="49.69"});function Un(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<vm;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): ${Pn}`}}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): ${Pn}`};if(e.status.tier==="free"){let o=Dn-t;if(o>0&&o<=3*Fn){let i=Math.max(1,Math.ceil(o/Fn));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: ${Pn}`}}}return null}var Pn,Fn,vm,mi=N(()=>{"use strict";jn();Pn="https://clauderecall.com/pricing",Fn=1440*60*1e3,vm=60*Fn});var gs={};fe(gs,{getLicenseStatus:()=>ye,isPro:()=>$m,performRevocationCheck:()=>Bn,printTrialBannerIfAny:()=>Dm,requireProOrExit:()=>Ce});async function ye(){let e=jt();if(!e)return{tier:"free"};let t=await ds(e.license_jwt);if(!t.valid||!t.claims)return{tier:"free",invalid_reason:t.reason};if(t.claims.machine_fp&&t.claims.machine_fp!==us())return{tier:"free",invalid_reason:"machine fingerprint mismatch \u2014 re-activate on this device"};let s=di(e.license_key);return s?.revoked?{tier:"free",invalid_reason:s.reason}:Mm(e,t.claims)}async function Bn(e){let t=jt();if(!t)return{ran:!1,revoked:!1,reason:null,last_checked_at:null};let s=await li(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 Mm(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 $m(){return(await ye()).tier==="pro"}async function Ce(e){let t=await ye();if(t.tier==="pro")return;let s=Un({status:t});s&&process.stderr.write(`
676
+ `,$n="ES256",mi="clauderecall.com",pi="clauderecall-cli"});import{jwtVerify as vp,importSPKI as Ip}from"jose";async function Mp(){return us||(us=await Ip(ui,$n),us)}async function ms(e){try{let t=await Mp(),{payload:s}=await vp(e,t,{issuer:mi,audience:pi,algorithms:[$n]});return{valid:!0,claims:s}}catch(t){return{valid:!1,reason:t instanceof Error?t.message:"verification failed"}}}var us,jn=L(()=>{"use strict";gi();us=null});import{createHash as Dp}from"node:crypto";import{hostname as $p,userInfo as jp,platform as Pp,arch as Fp}from"node:os";function ps(){let e="unknown";try{e=jp().username}catch{}let t=[$p(),e,Pp(),Fp()];return Dp("sha256").update(t.join("\0")).digest("hex")}var Pn=L(()=>{"use strict"});function Rt(){let e=process.env.RECALL_API_BASE;if(e&&e.length>0){let t=e.replace(/\/$/,""),s;try{s=new URL(t)}catch{throw new Error(`RECALL_API_BASE is not a valid URL: ${t}`)}let n=s.hostname==="127.0.0.1"||s.hostname==="localhost"||s.hostname==="::1";if(s.protocol==="https:"||s.protocol==="http:"&&n)return t;throw new Error(`RECALL_API_BASE must be HTTPS, or HTTP with loopback hostname. Got: ${t}`)}return"https://clauderecall.com"}var gs=L(()=>{"use strict"});import{existsSync as Up,readFileSync as Bp,writeFileSync as Hp}from"node:fs";import{join as Wp}from"node:path";function fs(){if(!Up(Fn))return null;try{let e=JSON.parse(Bp(Fn,"utf8"));return typeof e.license_key!="string"||typeof e.last_checked_at!="string"||typeof e.revoked!="boolean"?null:e}catch{return null}}function Yp(e){j(),Hp(Fn,JSON.stringify(e,null,2)+`
677
+ `,{mode:384})}async function zp(e,t){let s=null,n=null;try{s=new AbortController,n=setTimeout(()=>s?.abort(),Gp);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 fi(e,t={}){let s=fs(),n=t.apiUrl??`${Rt()}/api/license/check`,r=s?.license_key===e,o=!s||!r||Date.now()-new Date(s.last_checked_at).getTime()>=Xp;if(!t.force&&!o)return s;let i=await zp(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 Yp(a),a}function _i(e){let t=fs();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()>Jp?{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 Fn,Xp,Jp,Gp,Un=L(()=>{"use strict";P();gs();Fn=Wp(x,"license-check.json"),Xp=1440*60*1e3,Jp=720*60*60*1e3,Gp=1e4});function Kp(e=Date.now()){return e<Bn}function Ei(e=Date.now()){return Kp(e)?`(one-time purchase, $${qp} through May 2026 Founder pricing, $${hi} from June, lifetime updates either way)`:`(one-time purchase, $${hi}, lifetime updates)`}var Bn,qp,hi,Hn=L(()=>{"use strict";Bn=Date.UTC(2026,5,1,7,0,0),qp="29.69",hi="49.69"});function Jn(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<Vp;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): ${Wn}`}}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): ${Wn}`};if(e.status.tier==="free"){let o=Bn-t;if(o>0&&o<=3*Xn){let i=Math.max(1,Math.ceil(o/Xn));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: ${Wn}`}}}return null}var Wn,Xn,Vp,bi=L(()=>{"use strict";Hn();Wn="https://clauderecall.com/pricing",Xn=1440*60*1e3,Vp=60*Xn});var _s={};fe(_s,{getLicenseStatus:()=>Te,isPro:()=>Qp,performRevocationCheck:()=>Gn,printTrialBannerIfAny:()=>eg,requireProOrExit:()=>Ce});async function Te(){let e=jt();if(!e)return{tier:"free"};let t=await ms(e.license_jwt);if(!t.valid||!t.claims)return{tier:"free",invalid_reason:t.reason};if(t.claims.machine_fp&&t.claims.machine_fp!==ps())return{tier:"free",invalid_reason:"machine fingerprint mismatch \u2014 re-activate on this device"};let s=_i(e.license_key);return s?.revoked?{tier:"free",invalid_reason:s.reason}:Zp(e,t.claims)}async function Gn(e){let t=jt();if(!t)return{ran:!1,revoked:!1,reason:null,last_checked_at:null};let s=await fi(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 Zp(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 Qp(){return(await Te()).tier==="pro"}async function Ce(e){let t=await Te();if(t.tier==="pro")return;let s=Jn({status:t});s&&process.stderr.write(`
628
678
  ${s.message}
629
679
  `),process.stderr.write(`
630
680
  ${e} is a Pro feature.
631
681
 
632
682
  Buy a license at https://clauderecall.com/pricing
633
- ${pi()}.
683
+ ${Ei()}.
634
684
  Then run: recall activate <license-key>
635
685
 
636
686
  `),t.invalid_reason&&process.stderr.write(`(stored license is invalid: ${t.invalid_reason})
637
687
 
638
- `),process.exit(1)}async function Dm(){let e=await ye(),t=Un({status:e});return t?(process.stderr.write(`
688
+ `),process.exit(1)}async function eg(){let e=await Te(),t=Jn({status:e});return t?(process.stderr.write(`
639
689
  ${t.message}
640
690
 
641
- `),!0):!1}var _e=N(()=>{"use strict";Pt();In();vn();$n();jn();mi()});import{writeFileSync as bR,readFileSync as Pm,existsSync as Fm}from"node:fs";import{join as Um}from"node:path";function fi(){if(!Fm(fs))return null;try{return Pm(fs,"utf8").trim()}catch{return null}}var fs,Hn=N(()=>{"use strict";j();fs=Um(x,"daemon.token")});import{existsSync as _i,readFileSync as Bm,writeFileSync as xR,unlinkSync as Hm}from"node:fs";import{join as Xn}from"node:path";function Xm(){if(!_i(Wn))return null;try{let e=JSON.parse(Bm(Wn,"utf8"));return typeof e.pid!="number"||typeof e.port!="number"?null:e}catch{return null}}function Jn(){for(let e of[Wn,Wm,fs])if(_i(e))try{Hm(e)}catch{}}function Jm(e){try{return process.kill(e,0),!0}catch{return!1}}function K(){let e=Xm();return e?Jm(e.pid)?e:(Jn(),null):null}var Wn,Wm,_s,We=N(()=>{"use strict";j();Hn();Wn=Xn(x,"daemon.pid"),Wm=Xn(x,"daemon.port"),_s=Xn(x,"daemon.log")});import{writeFileSync as Og}from"node:fs";import{join as Ag}from"node:path";function Kn(e){try{let t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return[]}function Ki(e){return _().prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(e)?.alias??null}function vg(){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:Kn(t.previous_aliases)}))}function ys(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=Kn(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 _e=L(()=>{"use strict";Pt();jn();Pn();Un();Hn();bi()});import{writeFileSync as Y0,readFileSync as sg,existsSync as ng}from"node:fs";import{join as rg}from"node:path";function Ti(){if(!ng(hs))return null;try{return sg(hs,"utf8").trim()}catch{return null}}var hs,Yn=L(()=>{"use strict";P();hs=rg(x,"daemon.token")});import{existsSync as yi,readFileSync as og,writeFileSync as Z0,unlinkSync as ig}from"node:fs";import{join as qn}from"node:path";function cg(){if(!yi(zn))return null;try{let e=JSON.parse(og(zn,"utf8"));return typeof e.pid!="number"||typeof e.port!="number"?null:e}catch{return null}}function Ft(){for(let e of[zn,ag,hs])if(yi(e))try{ig(e)}catch{}}function Kn(e){try{return process.kill(e,0),!0}catch{return!1}}function Z(){let e=cg();return e?Kn(e.pid)?e:(Ft(),null):null}var zn,ag,Es,Xe=L(()=>{"use strict";P();Yn();zn=qn(x,"daemon.pid"),ag=qn(x,"daemon.port"),Es=qn(x,"daemon.log")});import{writeFileSync as Yg}from"node:fs";import{join as zg}from"node:path";function tr(e){try{let t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return[]}function na(e){return _().prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(e)?.alias??null}function Kg(){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:tr(t.previous_aliases)}))}function ws(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=tr(o.previous_aliases),o.alias!==s&&i.push({alias:o.alias,replaced_at:r})),n.prepare(`INSERT INTO session_aliases (session_id, alias, updated_at, previous_aliases)
642
692
  VALUES (?, ?, ?, ?)
643
693
  ON CONFLICT(session_id) DO UPDATE SET
644
694
  alias = excluded.alias,
645
695
  updated_at = excluded.updated_at,
646
- previous_aliases = excluded.previous_aliases`).run(e,s,r,JSON.stringify(i)),Zi(),{session_id:e,alias:s,updated_at:r,previous_aliases:i}}function Vi(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=Kn(n.previous_aliases);r.push({alias:n.alias,replaced_at:s}),t.prepare(`UPDATE session_aliases SET alias = '', updated_at = ?, previous_aliases = ?
647
- WHERE session_id = ?`).run(s,JSON.stringify(r),e),Zi()}function Zi(){try{P();let e=vg(),t={schema:"claude-recall.aliases.v1",backed_up_at:new Date().toISOString(),aliases:e};Og(Ig,JSON.stringify(t,null,2))}catch(e){console.error("[aliases] backup failed:",e)}}var Ig,Ft=N(()=>{"use strict";T();j();Ig=Ag(x,"aliases.json")});import{writeFileSync as nf}from"node:fs";import{join as rf}from"node:path";function af(e){return e.trim().toLowerCase().replace(/^#+/,"").replace(/[\s/\\]+/g,"-").replace(/[^a-z0-9\-._]/g,"").slice(0,40)}function la(e,t){let s=af(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)})(),cf(),{tag:s,added:!0})}function da(e){return _().prepare("SELECT tag FROM session_tags WHERE session_id = ? ORDER BY tag").all(e).map(t=>t.tag)}function cf(){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};nf(of,JSON.stringify(n,null,2))}catch(e){console.error("[tags] backup failed:",e)}}var of,Zn=N(()=>{"use strict";T();j();of=rf(x,"tags.json")});function lf(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 ua(e){let t=_(),s={limit:e.limit??500},n=e.sessionIds&&e.sessionIds.length>0,r=n?"1=1":"s.message_count > 2";if(n){let i=e.sessionIds.map((a,l)=>`@sid_${l}`).join(", ");r+=` AND s.id IN (${i})`,e.sessionIds.forEach((a,l)=>{s[`sid_${l}`]=a})}return e.untaggedOnly&&(r+=" AND NOT EXISTS (SELECT 1 FROM session_tags st WHERE st.session_id = s.id)"),e.project&&(r+=" AND p.name = @project",s.project=e.project),e.collectionId&&(r+=" AND s.id IN (SELECT session_id FROM collection_sessions WHERE collection_id = @col)",s.col=e.collectionId),t.prepare(`SELECT s.id, p.name AS project, s.git_branch,
696
+ previous_aliases = excluded.previous_aliases`).run(e,s,r,JSON.stringify(i)),oa(),{session_id:e,alias:s,updated_at:r,previous_aliases:i}}function ra(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=tr(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),oa()}function oa(){try{j();let e=Kg(),t={schema:"claude-recall.aliases.v1",backed_up_at:new Date().toISOString(),aliases:e};Yg(qg,JSON.stringify(t,null,2))}catch(e){console.error("[aliases] backup failed:",e)}}var qg,Ut=L(()=>{"use strict";w();P();qg=zg(x,"aliases.json")});import{writeFileSync as yf}from"node:fs";import{join as wf}from"node:path";function xf(e){return e.trim().toLowerCase().replace(/^#+/,"").replace(/[\s/\\]+/g,"-").replace(/[^a-z0-9\-._]/g,"").slice(0,40)}function _a(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)})(),kf(),{tag:s,added:!0})}function ha(e){return _().prepare("SELECT tag FROM session_tags WHERE session_id = ? ORDER BY tag").all(e).map(t=>t.tag)}function kf(){try{j();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(Rf,JSON.stringify(n,null,2))}catch(e){console.error("[tags] backup failed:",e)}}var Rf,nr=L(()=>{"use strict";w();P();Rf=wf(x,"tags.json")});function Nf(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 Ea(e){let t=_(),s={limit:e.limit??500},n=e.sessionIds&&e.sessionIds.length>0,r=n?"1=1":"s.message_count > 2";if(n){let i=e.sessionIds.map((a,l)=>`@sid_${l}`).join(", ");r+=` AND s.id IN (${i})`,e.sessionIds.forEach((a,l)=>{s[`sid_${l}`]=a})}return e.untaggedOnly&&(r+=" AND NOT EXISTS (SELECT 1 FROM session_tags st WHERE st.session_id = s.id)"),e.project&&(r+=" AND p.name = @project",s.project=e.project),e.collectionId&&(r+=" AND s.id IN (SELECT session_id FROM collection_sessions WHERE collection_id = @col)",s.col=e.collectionId),t.prepare(`SELECT s.id, p.name AS project, s.git_branch,
648
698
  NULLIF(sa.alias, '') AS alias,
649
699
  COALESCE(s.first_user_message, '') AS first_user_message
650
700
  FROM sessions s
@@ -654,17 +704,17 @@ ${t.message}
654
704
  ORDER BY COALESCE(s.started_at, '') DESC
655
705
  LIMIT @limit`).all(s).map(i=>{let a=t.prepare(`SELECT role, COALESCE(content_text, '') AS content_text
656
706
  FROM messages WHERE session_id = ?
657
- ORDER BY COALESCE(timestamp, ''), rowid`).all(i.id),c=lf(a,5).map(u=>`${u.role}: ${u.content_text.slice(0,400)}`).join(`
707
+ ORDER BY COALESCE(timestamp, ''), rowid`).all(i.id),c=Nf(a,5).map(u=>`${u.role}: ${u.content_text.slice(0,400)}`).join(`
658
708
  ---
659
- `);return{id:i.id,project:i.project,git_branch:i.git_branch,alias:i.alias,first_user_message:i.first_user_message,message_sample:c,current_tags:da(i.id)}})}var pa=N(()=>{"use strict";T();Zn()});import{z as we}from"zod";function ma(e){let t=e.minTags??2,s=e.maxTags??4,n=e.untaggedOnly??!e.sessionId,r=["Auto-tag my Claude Recall sessions using the MCP tools available to you.","","1. Call `list_tags` first to see which tags I already use (prefer those for consistency over inventing new ones).","2. Call `list_sessions_to_tag` with these filters:"],o=[];return e.sessionId?(o.push("limit: 1"),r.push(` ${o.join(", ")}`),r.push(` Then match the session id ${e.sessionId} from the returned list.`)):(n&&o.push("untaggedOnly: true"),e.project&&o.push(`project: "${e.project}"`),e.collectionId&&o.push(`collectionId: "${e.collectionId}"`),o.push(`limit: ${e.limit??100}`),r.push(` ${o.join(", ")}`)),r.push(""),r.push(`3. For each session returned, look at the alias, first user message, git branch, and sampled messages. Pick ${t}-${s} concise, lowercase, hyphen-separated tags describing:`),r.push(" - domain/subsystem (auth, db, frontend, billing, etc.)"),r.push(" - kind of work (bugfix, feature, refactor, research)"),r.push(" - prominent tools or libraries if relevant"),r.push(""),r.push("4. Call `apply_tags` once per session to write the tags."),r.push(""),r.push("Work through EVERY session returned \u2014 do not stop partway. When done, reply with a short summary of how many sessions were tagged. Do not ask clarifying questions; just do the work."),r.join(`
660
- `)}var Lk,Ok,Ak,Ik,ga=N(()=>{"use strict";Lk={project:we.string().optional().describe("Exact project name match (optional)."),collectionId:we.string().optional().describe("Restrict to sessions in this collection (optional)."),sessionId:we.string().optional().describe("Full session UUID to tag just one session (optional)."),untaggedOnly:we.boolean().optional().describe("Skip sessions that already have any tag (default: true)."),limit:we.number().int().min(1).max(500).optional().describe("Max sessions to process (default: 100)."),minTags:we.number().int().min(1).max(10).optional().describe("Minimum tags per session (default: 2)."),maxTags:we.number().int().min(1).max(10).optional().describe("Maximum tags per session (default: 4).")};Ok={sessionId:we.string().describe("Session UUID (or 8+-char prefix) to summarize."),mode:we.enum(["brief","detailed"]).optional().describe("brief = 3-5 bullets; detailed = paragraph + bullets. Default: brief.")},Ak={sessionId:we.string().describe("Session UUID (or 8+-char prefix) to extract decisions from.")},Ik={sessionId:we.string().describe("Session UUID (or 8+-char prefix) to find similar sessions to."),limit:we.number().int().min(1).max(20).optional().describe("How many similar sessions to surface (default: 5).")}});function fa(e,t){let s=df.get(e);if(!(!s||s.size===0))for(let n of s)try{n(t)}catch{}}var df,_a=N(()=>{"use strict";df=new Map});var Qn={};fe(Qn,{buildScanPrompt:()=>ha,isClaudeCliAvailable:()=>ce,runClaudeCliScan:()=>Sf,spawnClaudePrompt:()=>mt});import{execFileSync as uf,execSync as pf,spawn as mf}from"node:child_process";function ff(){if(Bt)return Bt;try{Bt=pf("which claude",{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim()}catch{Bt="claude"}return Bt}function ce(){try{return uf("command",["-v","claude"],{stdio:"ignore"}),!0}catch{return!1}}function ha(e){return ma({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 _f(e,t){let s=t.get(e);return s||e.slice(0,8)}function hf(e){try{return ua(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 Ef(e){let{scanId:t,total:s,labelTable:n}=e,r=new Set;return o=>{let i=o.trim();if(!i.startsWith("{"))return;let a;try{a=JSON.parse(i)}catch{return}if(!a||typeof a!="object")return;let l=a;if(!(l.type!=="assistant"||!l.message?.content))for(let c of l.message.content){if(c?.type!=="tool_use"||c.name!=="mcp__recall__apply_tags")continue;let u=c.input,p=typeof u?.sessionId=="string"?u.sessionId:null;!p||r.has(p)||(r.add(p),fa(t,{type:"progress",current:r.size,total:s,sessionId:p,sessionLabel:_f(p,n)}))}}}function bf(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:c,current_tags:ha(i.id)}})}var ba=L(()=>{"use strict";w();nr()});import{z as we}from"zod";function Sa(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 rN,oN,iN,aN,Ta=L(()=>{"use strict";rN={project:we.string().optional().describe("Exact project name match (optional)."),collectionId:we.string().optional().describe("Restrict to sessions in this collection (optional)."),sessionId:we.string().optional().describe("Full session UUID to tag just one session (optional)."),untaggedOnly:we.boolean().optional().describe("Skip sessions that already have any tag (default: true)."),limit:we.number().int().min(1).max(500).optional().describe("Max sessions to process (default: 100)."),minTags:we.number().int().min(1).max(10).optional().describe("Minimum tags per session (default: 2)."),maxTags:we.number().int().min(1).max(10).optional().describe("Maximum tags per session (default: 4).")};oN={sessionId:we.string().describe("Session UUID (or 8+-char prefix) to summarize."),mode:we.enum(["brief","detailed"]).optional().describe("brief = 3-5 bullets; detailed = paragraph + bullets. Default: brief.")},iN={sessionId:we.string().describe("Session UUID (or 8+-char prefix) to extract decisions from.")},aN={sessionId:we.string().describe("Session UUID (or 8+-char prefix) to find similar sessions to."),limit:we.number().int().min(1).max(20).optional().describe("How many similar sessions to surface (default: 5).")}});function ya(e,t){let s=Lf.get(e);if(!(!s||s.size===0))for(let n of s)try{n(t)}catch{}}var Lf,wa=L(()=>{"use strict";Lf=new Map});var rr={};fe(rr,{buildScanPrompt:()=>Ra,isClaudeCliAvailable:()=>ce,runClaudeCliScan:()=>Pf,spawnClaudePrompt:()=>pt});import{execFileSync as Cf,execSync as Af,spawn as Of}from"node:child_process";function If(){if(Ht)return Ht;try{Ht=Af("which claude",{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim()}catch{Ht="claude"}return Ht}function ce(){try{return Cf("command",["-v","claude"],{stdio:"ignore"}),!0}catch{return!1}}function Ra(e){return Sa({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 Mf(e,t){let s=t.get(e);return s||e.slice(0,8)}function Df(e){try{return Ea(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 $f(e){let{scanId:t,total:s,labelTable:n}=e,r=new Set;return o=>{let i=o.trim();if(!i.startsWith("{"))return;let a;try{a=JSON.parse(i)}catch{return}if(!a||typeof a!="object")return;let l=a;if(!(l.type!=="assistant"||!l.message?.content))for(let c of l.message.content){if(c?.type!=="tool_use"||c.name!=="mcp__recall__apply_tags")continue;let u=c.input,m=typeof u?.sessionId=="string"?u.sessionId:null;!m||r.has(m)||(r.add(m),ya(t,{type:"progress",current:r.size,total:s,sessionId:m,sessionLabel:Mf(m,n)}))}}}function jf(e){let t="";return s=>{t+=s.toString("utf8");let n=t.indexOf(`
661
711
  `);for(;n!==-1;){let r=t.slice(0,n);t=t.slice(n+1),r.length>0&&e(r),n=t.indexOf(`
662
- `)}}}async function Sf(e,t={},s){let n=!!t.scanId,r=n?hf(e):[],o=new Map(r.map(l=>[l.id,l.label])),i=r.length,a;return n&&t.scanId&&(a=Ef({scanId:t.scanId,total:i,labelTable:o})),Ea({prompt:ha(e),allowedTools:gf.split(","),opts:t,onProgress:s,onStdoutLine:a,outputFormat:n?"stream-json":"json"})}async function mt(e,t,s={},n){return Ea({prompt:e,allowedTools:t,opts:s,onProgress:n,outputFormat:"json"})}function Ea(e){let{prompt:t,allowedTools:s,opts:n,onProgress:r,onStdoutLine:o,outputFormat:i}=e,a=["-p",t,"--output-format",i,"--allowedTools",s.join(","),"--permission-mode","bypassPermissions"];return i==="stream-json"&&a.push("--verbose"),n.model&&a.push("--model",n.model),new Promise(l=>{let c=mf(ff(),a,{stdio:["ignore","pipe","pipe"]}),u=[],p=[],m=o?bf(o):void 0;c.stdout.on("data",g=>{u.push(g),m&&m(g)}),c.stderr.on("data",g=>{if(p.push(g),r){let h=g.toString("utf8").trim();h&&r(h)}});let f=setTimeout(()=>{c.kill("SIGKILL")},1800*1e3);c.on("close",g=>{clearTimeout(f),l({success:g===0,stdout:Buffer.concat(u).toString("utf8"),stderr:Buffer.concat(p).toString("utf8"),exitCode:g})}),c.on("error",g=>{clearTimeout(f),l({success:!1,stdout:"",stderr:String(g),exitCode:null})})})}var gf,Bt,Je=N(()=>{"use strict";pa();ga();_a();gf=["mcp__recall__list_tags","mcp__recall__list_sessions_to_tag","mcp__recall__apply_tags"].join(",")});var wa={};fe(wa,{downloadModel:()=>nr,getModelDir:()=>Ns,isModelInstalled:()=>gt,uninstallModel:()=>rr});import{existsSync as sr,mkdirSync as ya,rmSync as tr,createWriteStream as Ff,statSync as Uf}from"node:fs";import{join as ks}from"node:path";import{createHash as Bf}from"node:crypto";import{readFile as Hf}from"node:fs/promises";function Ns(){return ks(x,"models","BAAI","bge-base-en-v1.5")}function gt(){let e=Ns();return Ta.every(t=>sr(ks(e,t.path)))}async function nr(e){let t=Ns();ya(t,{recursive:!0}),ya(ks(t,"onnx"),{recursive:!0});for(let s of Ta){let n=ks(t,s.path),r=Wf+s.path,o=0;sr(n)&&(o=Uf(n).size);let i={};o>0&&(i.Range=`bytes=${o}-`);let a=await fetch(r,{headers:i});if(!a.ok&&a.status!==206)throw new Error(`Failed to download ${s.path}: HTTP ${a.status}`);let l=a.headers.get("content-length"),c=l?o+Number(l):0,u=a.body;if(!u)throw new Error(`No response body for ${s.path}`);let p=Ff(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 tr(n),new Error(`Refusing to install: SHA-256 not pinned for ${s.path}. Update model-download.ts.`);let g=await Hf(n);if(Bf("sha256").update(g).digest("hex")!==s.sha256)throw tr(n),new Error(`SHA-256 mismatch for ${s.path}`)}}function rr(){let e=Ns();sr(e)&&tr(e,{recursive:!0,force:!0})}var Wf,Ta,Cs=N(()=>{"use strict";j();Wf="https://huggingface.co/BAAI/bge-base-en-v1.5/resolve/main/",Ta=[{path:"config.json",sha256:"bc00af31a4a31b74040d73370aa83b62da34c90b75eb77bfa7db039d90abd591"},{path:"tokenizer.json",sha256:"d241a60d5e8f04cc1b2b3e9ef7a4921b27bf526d9f6050ab90f9267a1f9e5c66"},{path:"tokenizer_config.json",sha256:"9261e7d79b44c8195c1cada2b453e55b00aeb81e907a6664974b4d7776172ab3"},{path:"onnx/model.onnx",sha256:"9bc579acdba21c253c62a9bf866891355a63ffa3442b52c8a37d75b2ccb91848"}]});var ir={};fe(ir,{EmbedderUnavailableError:()=>Wt,embed:()=>ft,embedQuery:()=>or,getEmbedderStatus:()=>Ge,loadEmbedder:()=>Ke,unloadEmbedder:()=>zf});import{join as Ra}from"node:path";function Gf(){return Ra(x,"models","bge-base-en-v1.5")}async function Ke(){if(Ls&&Ht)return;let e;try{e=await import("@huggingface/transformers")}catch(n){throw new Wt(n)}let{pipeline:t,env:s}=e;s.localModelPath=Ra(x,"models"),s.allowRemoteModels=!1;try{Ht=await t("feature-extraction",ka,{local_files_only:!0,cache_dir:Gf()}),Ls=!0}catch(n){throw n instanceof Error&&/Cannot find module|onnxruntime_binding/.test(n.message)?new Wt(n):n}}function Ge(){return{loaded:Ls,modelId:ka,dim:Xf}}async function ft(e){if(!Ht)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");let t=[];for(let s=0;s<e.length;s+=xa){let n=e.slice(s,s+xa),o=(await Ht(n,{pooling:"cls",normalize:!0})).tolist();for(let i=0;i<n.length;i++){let a=o[i],l=Array.isArray(a[0])?a[0]:a;t.push(new Float32Array(l))}}return t}async function or(e){let t=Jf+e,[s]=await ft([t]);return s}function zf(){Ht=null,Ls=!1}var ka,Xf,xa,Jf,Ht,Ls,Wt,Ve=N(()=>{"use strict";j();ka="BAAI/bge-base-en-v1.5",Xf=768,xa=16,Jf="Represent this sentence for searching relevant passages: ",Ht=null,Ls=!1;Wt=class extends Error{cause;constructor(t){let s=t instanceof Error?t.message:String(t);super(["Semantic search is unavailable on this platform.","",`Reason: ${s}`,"",`Platform: ${process.platform}/${process.arch}, Node ${process.version}`,"","Claude Recall supports macOS (arm64/x64), Linux (x64/arm64), and Windows (x64).","Core CLI features (search, list, context, daemon) work everywhere.","Only `recall semantic *` requires the on-device embedder.","","See: https://clauderecall.com/docs (Supported platforms) \u2014 or file an issue at","https://gitlab.com/clauderecallhq/clauderecallhq/-/issues with the platform line above."].join(`
663
- `)),this.name="EmbedderUnavailableError",this.cause=t}}});var La={};fe(La,{ensureTransformersInstalled:()=>a_});import{spawn as Zf}from"node:child_process";import{existsSync as Qf}from"node:fs";import{dirname as e_,resolve as t_}from"node:path";import{fileURLToPath as s_}from"node:url";function r_(){let e=e_(s_(import.meta.url));return t_(e,"..","..")}async function o_(){try{return await import("@huggingface/transformers"),!0}catch{return!1}}function i_(e){return new Promise(t=>{let s=["install","--no-save","--no-audit","--no-fund","--prefix",e,`@huggingface/transformers@${n_}`],n=Zf("npm",s,{stdio:["ignore","inherit","inherit"],cwd:e});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 a_(){if(await o_())return{ok:!0,action:"already-installed"};let e=r_();return Qf(e)?(console.log(`Installing @huggingface/transformers into ${e} ...`),i_(e)):{ok:!1,error:`package root not found at ${e}`}}var n_,Oa=N(()=>{"use strict";n_="^3.4.1"});import{writeFileSync as Xa,readFileSync as VN,existsSync as Ja,mkdirSync as Ga,readdirSync as ZN}from"node:fs";import{join as Is}from"node:path";function z_(){P(),Ja(mr)||Ga(mr,{recursive:!0})}function Y_(){P(),Ja(gr)||Ga(gr,{recursive:!0})}function za(e){try{return JSON.parse(e)}catch{return e}}function fr(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:za(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:za(e.evidence),status:e.status,inferred_by:e.inferred_by,created_at:e.created_at,decided_at:e.decided_at}}function q_(e){if(!Number.isFinite(e)||e<0||e>1)throw new Error("confidence must be a number in [0, 1]")}function Ya(e){if(!H_.has(e))throw new Error(`invalid link_type: ${e}`)}function qa(e){if(!J_.has(e))throw new Error(`invalid inferred_by: ${e}`)}function K_(e,t){if(!e||!t)throw new Error("source_session_id and target_session_id are required");if(e===t)throw new Error("a session cannot link to itself")}function V_(e={}){let t=_(),s=[],n=[];e.sourceSessionId&&(s.push("source_session_id = ?"),n.push(e.sourceSessionId)),e.targetSessionId&&(s.push("target_session_id = ?"),n.push(e.targetSessionId)),e.linkType&&(Ya(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 Pf(e,t={},s){let n=!!t.scanId,r=n?Df(e):[],o=new Map(r.map(l=>[l.id,l.label])),i=r.length,a;return n&&t.scanId&&(a=$f({scanId:t.scanId,total:i,labelTable:o})),xa({prompt:Ra(e),allowedTools:vf.split(","),opts:t,onProgress:s,onStdoutLine:a,outputFormat:n?"stream-json":"json"})}async function pt(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"];return i==="stream-json"&&a.push("--verbose"),n.model&&a.push("--model",n.model),new Promise(l=>{let c=Of(If(),a,{stdio:["ignore","pipe","pipe"]}),u=[],m=[],p=o?jf(o):void 0;c.stdout.on("data",g=>{u.push(g),p&&p(g)}),c.stderr.on("data",g=>{if(m.push(g),r){let h=g.toString("utf8").trim();h&&r(h)}});let f=setTimeout(()=>{c.kill("SIGKILL")},1800*1e3);c.on("close",g=>{clearTimeout(f),l({success:g===0,stdout:Buffer.concat(u).toString("utf8"),stderr:Buffer.concat(m).toString("utf8"),exitCode:g})}),c.on("error",g=>{clearTimeout(f),l({success:!1,stdout:"",stderr:String(g),exitCode:null})})})}var vf,Ht,Ge=L(()=>{"use strict";ba();Ta();wa();vf=["mcp__recall__list_tags","mcp__recall__list_sessions_to_tag","mcp__recall__apply_tags"].join(",")});var Aa={};fe(Aa,{downloadModel:()=>cr,getModelDir:()=>Cs,isModelInstalled:()=>gt,uninstallModel:()=>lr});import{existsSync as ar,mkdirSync as La,rmSync as ir,createWriteStream as n_,statSync as r_}from"node:fs";import{join as Ls}from"node:path";import{createHash as o_}from"node:crypto";import{readFile as i_}from"node:fs/promises";function Cs(){return Ls(x,"models","BAAI","bge-base-en-v1.5")}function gt(){let e=Cs();return Ca.every(t=>ar(Ls(e,t.path)))}async function cr(e){let t=Cs();La(t,{recursive:!0}),La(Ls(t,"onnx"),{recursive:!0});for(let s of Ca){let n=Ls(t,s.path),r=a_+s.path,o=0;ar(n)&&(o=r_(n).size);let i={};o>0&&(i.Range=`bytes=${o}-`);let a=await fetch(r,{headers:i});if(!a.ok&&a.status!==206)throw new Error(`Failed to download ${s.path}: HTTP ${a.status}`);let l=a.headers.get("content-length"),c=l?o+Number(l):0,u=a.body;if(!u)throw new Error(`No response body for ${s.path}`);let m=n_(n,{flags:o>0?"a":"w"}),p=u.getReader(),f=o;for(;;){let{done:E,value:b}=await p.read();if(E)break;m.write(Buffer.from(b)),f+=b.byteLength,e?.(s.path,f,c)}if(m.end(),await new Promise((E,b)=>{m.on("finish",E),m.on("error",b)}),s.sha256==="TODO_PLACEHOLDER")throw ir(n),new Error(`Refusing to install: SHA-256 not pinned for ${s.path}. Update model-download.ts.`);let g=await i_(n);if(o_("sha256").update(g).digest("hex")!==s.sha256)throw ir(n),new Error(`SHA-256 mismatch for ${s.path}`)}}function lr(){let e=Cs();ar(e)&&ir(e,{recursive:!0,force:!0})}var a_,Ca,As=L(()=>{"use strict";P();a_="https://huggingface.co/BAAI/bge-base-en-v1.5/resolve/main/",Ca=[{path:"config.json",sha256:"bc00af31a4a31b74040d73370aa83b62da34c90b75eb77bfa7db039d90abd591"},{path:"tokenizer.json",sha256:"d241a60d5e8f04cc1b2b3e9ef7a4921b27bf526d9f6050ab90f9267a1f9e5c66"},{path:"tokenizer_config.json",sha256:"9261e7d79b44c8195c1cada2b453e55b00aeb81e907a6664974b4d7776172ab3"},{path:"onnx/model.onnx",sha256:"9bc579acdba21c253c62a9bf866891355a63ffa3442b52c8a37d75b2ccb91848"}]});var ur={};fe(ur,{EmbedderUnavailableError:()=>Xt,embed:()=>ft,embedQuery:()=>dr,getEmbedderStatus:()=>Ye,loadEmbedder:()=>Ke,unloadEmbedder:()=>u_});import{join as va}from"node:path";function d_(){return va(x,"models","bge-base-en-v1.5")}async function Ke(){if(Os&&Wt)return;let e;try{e=await import("@huggingface/transformers")}catch(n){throw new Xt(n)}let{pipeline:t,env:s}=e;s.localModelPath=va(x,"models"),s.allowRemoteModels=!1;try{Wt=await t("feature-extraction",Ia,{local_files_only:!0,cache_dir:d_()}),Os=!0}catch(n){throw n instanceof Error&&/Cannot find module|onnxruntime_binding/.test(n.message)?new Xt(n):n}}function Ye(){return{loaded:Os,modelId:Ia,dim:c_}}async function ft(e){if(!Wt)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");let t=[];for(let s=0;s<e.length;s+=Oa){let n=e.slice(s,s+Oa),o=(await Wt(n,{pooling:"cls",normalize:!0})).tolist();for(let i=0;i<n.length;i++){let a=o[i],l=Array.isArray(a[0])?a[0]:a;t.push(new Float32Array(l))}}return t}async function dr(e){let t=l_+e,[s]=await ft([t]);return s}function u_(){Wt=null,Os=!1}var Ia,c_,Oa,l_,Wt,Os,Xt,Ve=L(()=>{"use strict";P();Ia="BAAI/bge-base-en-v1.5",c_=768,Oa=64,l_="Represent this sentence for searching relevant passages: ",Wt=null,Os=!1;Xt=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 $a={};fe($a,{ensureTransformersInstalled:()=>x_});import{spawn as __}from"node:child_process";import{existsSync as h_}from"node:fs";import{dirname as E_,resolve as b_}from"node:path";import{fileURLToPath as S_}from"node:url";function y_(){let e=E_(S_(import.meta.url));return b_(e,"..","..")}async function w_(){try{return await import("@huggingface/transformers"),!0}catch{return!1}}function R_(e){return new Promise(t=>{let s=["install","--no-save","--no-audit","--no-fund","--prefix",e,`@huggingface/transformers@${T_}`],n=__("npm",s,{stdio:["ignore","inherit","inherit"],cwd:e});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 x_(){if(await w_())return{ok:!0,action:"already-installed"};let e=y_();return h_(e)?(console.log(`Installing @huggingface/transformers into ${e} ...`),R_(e)):{ok:!1,error:`package root not found at ${e}`}}var T_,ja=L(()=>{"use strict";T_="^3.4.1"});import{writeFileSync as Va,readFileSync as NL,existsSync as Za,mkdirSync as Qa,readdirSync as LL}from"node:fs";import{join as Ms}from"node:path";function uh(){j(),Za(Er)||Qa(Er,{recursive:!0})}function mh(){j(),Za(br)||Qa(br,{recursive:!0})}function ec(e){try{return JSON.parse(e)}catch{return e}}function Sr(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:ec(e.evidence),approved:e.approved===1,created_at:e.created_at,updated_at:e.updated_at}}function Tr(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:ec(e.evidence),status:e.status,inferred_by:e.inferred_by,created_at:e.created_at,decided_at:e.decided_at}}function ph(e){if(!Number.isFinite(e)||e<0||e>1)throw new Error("confidence must be a number in [0, 1]")}function tc(e){if(!ih.has(e))throw new Error(`invalid link_type: ${e}`)}function sc(e){if(!lh.has(e))throw new Error(`invalid inferred_by: ${e}`)}function gh(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 fh(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&&(tc(e.linkType),s.push("link_type = ?"),n.push(e.linkType)),e.approvedOnly&&s.push("approved = 1");let r=s.length?`WHERE ${s.join(" AND ")}`:"",o=Math.max(1,Math.min(5e3,e.limit??1e3));return t.prepare(`SELECT * FROM session_links ${r}
664
714
  ORDER BY confidence DESC, updated_at DESC
665
- LIMIT ?`).all(...n,o).map(fr)}function hr(e){return _().prepare(`SELECT * FROM session_links
715
+ LIMIT ?`).all(...n,o).map(Sr)}function yr(e){return _().prepare(`SELECT * FROM session_links
666
716
  WHERE source_session_id = ? OR target_session_id = ?
667
- ORDER BY confidence DESC, updated_at DESC`).all(e,e).map(fr)}function Qe(e){K_(e.source_session_id,e.target_session_id),Ya(e.link_type),q_(e.confidence),qa(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(Sr)}function Qe(e){gh(e.source_session_id,e.target_session_id),tc(e.link_type),ph(e.confidence),sc(e.inferred_by);let t=_(),s=new Date().toISOString(),n=JSON.stringify(e.evidence??null);t.prepare(`INSERT INTO session_link_suggestions
668
718
  (source_session_id, target_session_id, link_type,
669
719
  confidence, evidence, status, inferred_by,
670
720
  created_at, decided_at)
@@ -684,9 +734,9 @@ ${t.message}
684
734
  WHERE source_session_id = ?
685
735
  AND target_session_id = ?
686
736
  AND link_type = ?
687
- AND inferred_by = ?`).get(e.source_session_id,e.target_session_id,e.link_type,e.inferred_by);if(!r)throw new Error("createSuggestion succeeded but read-back failed");return Va(),_r(r)}function vs(e={}){let t=_(),s=[],n=[];if(e.status){if(!X_.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&&(qa(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(),Tr(r)}function Ds(e={}){let t=_(),s=[],n=[];if(e.status){if(!ch.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&&(sc(e.inferredBy),s.push("inferred_by = ?"),n.push(e.inferredBy));let r=s.length?`WHERE ${s.join(" AND ")}`:"",o=Math.max(1,Math.min(5e3,e.limit??1e3));return t.prepare(`SELECT * FROM session_link_suggestions ${r}
688
738
  ORDER BY confidence DESC, created_at DESC
689
- LIMIT ?`).all(...n,o).map(_r)}function Ka(e,t,s={}){if(t!=="approved"&&t!=="rejected")throw new Error(`invalid decision: ${t}`);let n=s.source??"manual";if(!W_.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(Tr)}function nc(e,t,s={}){if(t!=="approved"&&t!=="rejected")throw new Error(`invalid decision: ${t}`);let n=s.source??"manual";if(!ah.has(n))throw new Error(`invalid source: ${n}`);let r=_(),o=r.prepare("SELECT * FROM session_link_suggestions WHERE id = ?").get(e);if(!o)throw new Error(`suggestion ${e} not found`);if(o.status!=="pending")throw new Error(`suggestion ${e} already decided as ${o.status}`);let i=new Date().toISOString(),a;r.transaction(()=>{r.prepare(`UPDATE session_link_suggestions
690
740
  SET status = ?, decided_at = ?
691
741
  WHERE id = ?`).run(t,i,e),t==="approved"&&(r.prepare(`INSERT INTO session_links
692
742
  (source_session_id, target_session_id, link_type,
@@ -701,7 +751,7 @@ ${t.message}
701
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
702
752
  WHERE source_session_id = ?
703
753
  AND target_session_id = ?
704
- AND link_type = ?`).get(o.source_session_id,o.target_session_id,o.link_type))})(),Va(),t==="approved"&&Z_(o.source_session_id);let l=r.prepare("SELECT * FROM session_link_suggestions WHERE id = ?").get(e);return{suggestion:_r(l),link:a?fr(a):null}}function Z_(e){try{z_();let t=V_({sourceSessionId:e}),s=Is(mr,`${e}.json`);if(t.length===0)return;let n={schema:"claude-recall.session-links.v1",source_session_id:e,backed_up_at:new Date().toISOString(),links:t};Xa(s,JSON.stringify(n,null,2))}catch(t){console.error("[session-links] backup failed:",t)}}function Va(){try{Y_();let e=vs({limit:5e3}),t={schema:"claude-recall.session-link-suggestions.v1",backed_up_at:new Date().toISOString(),suggestions:e};Xa(G_,JSON.stringify(t,null,2))}catch(e){console.error("[session-links] suggestions backup failed:",e)}}var H_,W_,X_,J_,mr,gr,G_,zt=N(()=>{"use strict";T();j();H_=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),W_=new Set(["regex","llm","embedding","manual","auto","citation","git","terminal-registry"]),X_=new Set(["pending","approved","rejected"]),J_=new Set(["L1","L2","L3","L4","user"]),mr=Is(x,"links"),gr=Is(x,"suggestions"),G_=Is(gr,"index.json")});function Ps(e){return e?Math.ceil(e.length/4):0}function Tc(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/_E);return Math.max(hE,t)}function wc(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 xc(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"&&_h(o.source_session_id);let l=r.prepare("SELECT * FROM session_link_suggestions WHERE id = ?").get(e);return{suggestion:Tr(l),link:a?Sr(a):null}}function _h(e){try{uh();let t=fh({sourceSessionId:e}),s=Ms(Er,`${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};Va(s,JSON.stringify(n,null,2))}catch(t){console.error("[session-links] backup failed:",t)}}function rc(){try{mh();let e=Ds({limit:5e3}),t={schema:"claude-recall.session-link-suggestions.v1",backed_up_at:new Date().toISOString(),suggestions:e};Va(dh,JSON.stringify(t,null,2))}catch(e){console.error("[session-links] suggestions backup failed:",e)}}var ih,ah,ch,lh,Er,br,dh,zt=L(()=>{"use strict";w();P();ih=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),ah=new Set(["regex","llm","embedding","manual","auto","citation","git","terminal-registry"]),ch=new Set(["pending","approved","rejected"]),lh=new Set(["L1","L2","L3","L4","user"]),Er=Ms(x,"links"),br=Ms(x,"suggestions"),dh=Ms(br,"index.json")});function Us(e){return e?Math.ceil(e.length/4):0}function Cc(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/ME);return Math.max(DE,t)}function Ac(e,t){if(!e||!t)return 0;let s=Date.parse(e),n=Date.parse(t);return!Number.isFinite(s)||!Number.isFinite(n)?0:Math.abs(n-s)/(1e3*60*60*24)}function Oc(e){return _().prepare(`SELECT s.id,
705
755
  NULLIF(sa.alias, '') AS alias,
706
756
  s.auto_title,
707
757
  s.auto_title_source,
@@ -712,37 +762,37 @@ ${t.message}
712
762
  FROM sessions s
713
763
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
714
764
  LEFT JOIN projects p ON p.id = s.project_id
715
- WHERE s.id = ?`).get(e)??null}function Rc(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 kc(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 bE(e){let s=_().prepare(`SELECT id, auto_title, started_at
765
+ WHERE s.id = ?`).get(e)??null}function vc(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 Ic(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 jE(e){let s=_().prepare(`SELECT id, auto_title, started_at
716
766
  FROM sessions
717
767
  WHERE project_id = ?
718
- ORDER BY COALESCE(started_at, ''), id`).all(e),n=new Set,r=new Set,o=[];for(let m of s){if(!m.auto_title||!m.auto_title.startsWith("/")){o.push({id:m.id,brand:null,skill:null});continue}let f=m.auto_title.split(" \xB7 "),g=f[0].trim(),h=f.length>1?f.slice(1).join(" \xB7 ").trim():null;o.push({id:m.id,brand:h||null,skill:g||null}),h&&n.add(h),g&&r.add(g)}let i=[...n].sort(),a=new Map;i.forEach((m,f)=>a.set(m,f));let l=[...r].sort(),c=new Map;l.forEach((m,f)=>c.set(m,f));let u=new Map,p=new Map;for(let m of o){if(!m.brand||!m.skill)continue;let f=a.get(m.brand),g=c.get(m.skill);if(f===void 0||g===void 0)continue;let h=`${f}.${g}`,E=(u.get(h)??0)+1;u.set(h,E),p.set(m.id,`${f}.${g}.${E}`)}return{byId:p}}function SE(e){return{table:e!==null?bE(e):null,originProjectId:e,cache:new Map}}function Fs(e,t){let s=e.cache.get(t);if(s)return s;let n=xc(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:kc(n),decimal:r,summary:Rc(n.id),project:n.project,started_at:n.started_at};return e.cache.set(t,o),o}function yE(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 p of s){if(!p.auto_title||!p.auto_title.startsWith("/")){o.push({id:p.id,brand:null,skill:null});continue}let f=p.auto_title.split(" \xB7 "),g=f[0].trim(),h=f.length>1?f.slice(1).join(" \xB7 ").trim():null;o.push({id:p.id,brand:h||null,skill:g||null}),h&&n.add(h),g&&r.add(g)}let i=[...n].sort(),a=new Map;i.forEach((p,f)=>a.set(p,f));let l=[...r].sort(),c=new Map;l.forEach((p,f)=>c.set(p,f));let u=new Map,m=new Map;for(let p of o){if(!p.brand||!p.skill)continue;let f=a.get(p.brand),g=c.get(p.skill);if(f===void 0||g===void 0)continue;let h=`${f}.${g}`,E=(u.get(h)??0)+1;u.set(h,E),m.set(p.id,`${f}.${g}.${E}`)}return{byId:m}}function PE(e){return{table:e!==null?jE(e):null,originProjectId:e,cache:new Map}}function Bs(e,t){let s=e.cache.get(t);if(s)return s;let n=Oc(t);if(!n)return null;let r=e.table&&n.project_id===e.originProjectId?e.table.byId.get(t)??null:null,o={session_id:n.id,title:Ic(n),decimal:r,summary:vc(n.id),project:n.project,started_at:n.started_at};return e.cache.set(t,o),o}function FE(e,t){let n=_().prepare(`SELECT DISTINCT te.parent_session_id AS pid
719
769
  FROM thread_edges te
720
770
  WHERE te.session_id = ?
721
- AND te.parent_session_id IS NOT NULL`).all(t),r=[];for(let o of n){if(!o.pid)continue;let i=Fs(e,o.pid);i&&r.push(i)}return r}function TE(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=Bs(e,o.pid);i&&r.push(i)}return r}function UE(e,t){let n=_().prepare(`SELECT DISTINCT te.session_id AS sid
722
772
  FROM thread_edges te
723
- WHERE te.parent_session_id = ?`).all(t),r=[];for(let o of n){if(!o.sid)continue;let i=Fs(e,o.sid);i&&r.push(i)}return r}function Nc(e){let t=EE[e.linkType]??.5,s=Rt(e.confidence),n=t*s,r=Tc(e.daysApart),o=e.embeddingCosine??.5,i=Rt(e.pagerank);if(e.scoring==="pagerank")return Rt(i);if(e.scoring==="embedding-rerank")return e.embeddingCosine===null?Rt(n):Rt(o);let a=.35*n+.2*r+.2*o+.25*i;return Rt(a)}function Rt(e){return!Number.isFinite(e)||e<0?0:e>1?1:e}function wE(e,t,s,n,r){let o=new Map;function i(a,l){if(a===l)return;let c=o.get(a);c||(c=new Set,o.set(a,c)),c.add(l)}for(let a of t)i(a.source_session_id,a.target_session_id),i(a.target_session_id,a.source_session_id);for(let a of s)i(e,a.session_id);for(let a of s)i(a.session_id,e);for(let a of n)i(e,a.session_id);for(let a of n)i(a.session_id,e);if(r>1){let a=new Set([e]),l=new Set([e]);for(let c=1;c<r;c++){let u=new Set;for(let p of a){let m=o.get(p);if(m)for(let f of m){if(l.has(f))continue;let g=hr(f).filter(h=>h.approved);for(let h of g)i(h.source_session_id,h.target_session_id),i(h.target_session_id,h.source_session_id);l.add(f),u.add(f)}}if(u.size===0)break;for(let p of u)a.add(p)}}return{edges:o}}function xE(e,t={}){let s=t.iterations??12,n=t.damping??.85,r=Array.from(e.edges.keys());if(r.length===0)return new Map;let o=1/r.length,i=new Map(r.map(c=>[c,o]));for(let c=0;c<s;c++){let u=new Map(r.map(p=>[p,(1-n)/r.length]));for(let p of r){let m=e.edges.get(p);if(!m||m.size===0)continue;let f=(i.get(p)??0)/m.size;for(let g of m)u.set(g,(u.get(g)??0)+n*f)}i=u}let a=0;for(let c of i.values())c>a&&(a=c);if(a<=0)return i;let l=new Map;for(let[c,u]of i)l.set(c,u/a);return l}function Lc(e,t){let s=e.replace(/\s+/g," ").trim();return s.length<=t?s:`${s.slice(0,t-1).trimEnd()}\u2026`}function RE(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=Lc(e.summary,Cc);return`${r}
724
- ${o}`}return r}function kE(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+=Ps(a),e.summary){let l=Lc(e.summary,Cc*4);n.push(l),o+=Ps(l)}n.push("");for(let l of t){if(l.refs.length===0)continue;let c=`## ${l.heading}`,u=Ps(c),p=[],m=0;for(let f of l.refs){let g=RE(f),h=Ps(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=Bs(e,o.sid);i&&r.push(i)}return r}function Mc(e){let t=$E[e.linkType]??.5,s=xt(e.confidence),n=t*s,r=Cc(e.daysApart),o=e.embeddingCosine??.5,i=xt(e.pagerank);if(e.scoring==="pagerank")return xt(i);if(e.scoring==="embedding-rerank")return e.embeddingCosine===null?xt(n):xt(o);let a=.35*n+.2*r+.2*o+.25*i;return xt(a)}function xt(e){return!Number.isFinite(e)||e<0?0:e>1?1:e}function BE(e,t,s,n,r){let o=new Map;function i(a,l){if(a===l)return;let c=o.get(a);c||(c=new Set,o.set(a,c)),c.add(l)}for(let a of t)i(a.source_session_id,a.target_session_id),i(a.target_session_id,a.source_session_id);for(let a of s)i(e,a.session_id);for(let a of s)i(a.session_id,e);for(let a of n)i(e,a.session_id);for(let a of n)i(a.session_id,e);if(r>1){let a=new Set([e]),l=new Set([e]);for(let c=1;c<r;c++){let u=new Set;for(let m of a){let p=o.get(m);if(p)for(let f of p){if(l.has(f))continue;let g=yr(f).filter(h=>h.approved);for(let h of g)i(h.source_session_id,h.target_session_id),i(h.target_session_id,h.source_session_id);l.add(f),u.add(f)}}if(u.size===0)break;for(let m of u)a.add(m)}}return{edges:o}}function HE(e,t={}){let s=t.iterations??12,n=t.damping??.85,r=Array.from(e.edges.keys());if(r.length===0)return new Map;let o=1/r.length,i=new Map(r.map(c=>[c,o]));for(let c=0;c<s;c++){let u=new Map(r.map(m=>[m,(1-n)/r.length]));for(let m of r){let p=e.edges.get(m);if(!p||p.size===0)continue;let f=(i.get(m)??0)/p.size;for(let g of p)u.set(g,(u.get(g)??0)+n*f)}i=u}let a=0;for(let c of i.values())c>a&&(a=c);if(a<=0)return i;let l=new Map;for(let[c,u]of i)l.set(c,u/a);return l}function $c(e,t){let s=e.replace(/\s+/g," ").trim();return s.length<=t?s:`${s.slice(0,t-1).trimEnd()}\u2026`}function WE(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=$c(e.summary,Dc);return`${r}
774
+ ${o}`}return r}function XE(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+=Us(a),e.summary){let l=$c(e.summary,Dc*4);n.push(l),o+=Us(l)}n.push("");for(let l of t){if(l.refs.length===0)continue;let c=`## ${l.heading}`,u=Us(c),m=[],p=0;for(let f of l.refs){let g=WE(f),h=Us(g);if(o+u+p+h>s){r.push({session_id:f.session_id,title:f.title,decimal:f.decimal,summary:f.summary,project:f.project,started_at:f.started_at});continue}m.push(g),p+=h}if(m.length>0){n.push(c);for(let f of m)n.push(f);n.push(""),o+=u+p}}for(;n.length>0&&n[n.length-1]==="";)n.pop();return{bundle:n.join(`
725
775
  `)+`
726
- `,budgetUsed:o,truncated:r}}function NE(e,t,s,n,r,o){let i=[];for(let a of s){if(n&&!n.has(a.link_type))continue;let l=null;if(a.source_session_id===t.session_id?l=a.target_session_id:a.target_session_id===t.session_id&&(l=a.source_session_id),!l)continue;let c=Fs(e,l);if(!c)continue;let u=wc(t.started_at,c.started_at),p=Nc({confidence:a.confidence,linkType:a.link_type,daysApart:u,embeddingCosine:null,pagerank:o.get(l)??0,scoring:r});i.push({...c,score:p,evidence:`(suggestion, ${a.inferred_by}) confidence=${a.confidence.toFixed(2)} ${Math.round(u)}d apart`,link_type:a.link_type})}return i}function Us(e,t={}){let s=Math.max(100,Math.floor(t.budget??gE)),n=t.scoring??"hybrid",r=Math.max(1,Math.min(5,t.maxDepth??fE)),o=t.includeWikiLinks??!0,i=t.includeSuggestions??!1,a=t.edgeTypes?new Set(t.edgeTypes):null,l=xc(e);if(!l)throw new Error(`session not found: ${e}`);let c=SE(l.project_id),u={session_id:l.id,title:kc(l),decimal:c.table?.byId.get(l.id)??null,summary:Rc(l.id),project:l.project,started_at:l.started_at};c.cache.set(l.id,u);let p=yE(c,e),m=TE(c,e),f=hr(e).filter(v=>v.approved).filter(v=>!a||a.has(v.link_type)).filter(v=>o||v.link_type!=="wiki_link"),g=wE(e,f,p,m,r),h=xE(g),E=[],b=[],S=[],C=[];for(let v of f){let ee=v.source_session_id===e?v.target_session_id:v.source_session_id,B=Fs(c,ee);if(!B)continue;let y=wc(u.started_at,B.started_at),U=Nc({confidence:v.confidence,linkType:v.link_type,daysApart:y,embeddingCosine:null,pagerank:h.get(ee)??0,scoring:n}),M=Tc(y),q=`${v.link_type} confidence=${v.confidence.toFixed(2)} recency=${M.toFixed(2)} (${Math.round(y)}d apart)`,Be={...B,score:U,evidence:q,link_type:v.link_type};v.link_type==="citation"?E.push(Be):v.link_type==="similar"?b.push(Be):v.link_type==="wiki_link"?C.push(Be):S.push(Be)}if(i){let v=vs({sourceSessionId:e,status:"pending",limit:100}),ee=vs({targetSessionId:e,status:"pending",limit:100}),B=[...v,...ee],y=new Set,U=B.filter(q=>y.has(q.id)?!1:(y.add(q.id),!0)),M=NE(c,u,U,a,n,h);for(let q of M)q.link_type==="citation"?E.push(q):q.link_type==="similar"?b.push(q):q.link_type==="wiki_link"?C.push(q):S.push(q)}let R=(v,ee)=>ee.score-v.score;E.sort(R),b.sort(R),S.sort(R),C.sort(R);let Q=kE(u,[{heading:"Parents",refs:p},{heading:"Children",refs:m},{heading:"Citations (approved)",refs:E},{heading:"Similar sessions",refs:b},{heading:"Cousins (skill track + temporal)",refs:S},{heading:"Wiki links (manual)",refs:C}],s);return{origin:u,parents:p,children:m,citations:E,similar:b,cousins:S,wikiLinks:C,bundle:Q.bundle,budgetUsed:Q.budgetUsed,budgetRemaining:Math.max(0,s-Q.budgetUsed),truncated:Q.truncated}}var gE,fE,_E,hE,EE,Cc,Rr=N(()=>{"use strict";T();zt();gE=4e3,fE=2,_E=30,hE=.2,EE={citation:1,wiki_link:.9,similar:.7,skill_track:.5,bug_pattern:.4,temporal_proximity:.3};Cc=240});var Tl={};fe(Tl,{computeAllHealthScores:()=>Br,computeHealthScore:()=>Fr,computeHealthScoreByName:()=>Ur});function qt(e){return Math.max(0,Math.min(1,e))}function Fr(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 JE(e,t,s,n,r,o){let i=[];for(let a of s){if(n&&!n.has(a.link_type))continue;let l=null;if(a.source_session_id===t.session_id?l=a.target_session_id:a.target_session_id===t.session_id&&(l=a.source_session_id),!l)continue;let c=Bs(e,l);if(!c)continue;let u=Ac(t.started_at,c.started_at),m=Mc({confidence:a.confidence,linkType:a.link_type,daysApart:u,embeddingCosine:null,pagerank:o.get(l)??0,scoring:r});i.push({...c,score:m,evidence:`(suggestion, ${a.inferred_by}) confidence=${a.confidence.toFixed(2)} ${Math.round(u)}d apart`,link_type:a.link_type})}return i}function Hs(e,t={}){let s=Math.max(100,Math.floor(t.budget??vE)),n=t.scoring??"hybrid",r=Math.max(1,Math.min(5,t.maxDepth??IE)),o=t.includeWikiLinks??!0,i=t.includeSuggestions??!1,a=t.edgeTypes?new Set(t.edgeTypes):null,l=Oc(e);if(!l)throw new Error(`session not found: ${e}`);let c=PE(l.project_id),u={session_id:l.id,title:Ic(l),decimal:c.table?.byId.get(l.id)??null,summary:vc(l.id),project:l.project,started_at:l.started_at};c.cache.set(l.id,u);let m=FE(c,e),p=UE(c,e),f=yr(e).filter(I=>I.approved).filter(I=>!a||a.has(I.link_type)).filter(I=>o||I.link_type!=="wiki_link"),g=BE(e,f,m,p,r),h=HE(g),E=[],b=[],S=[],N=[];for(let I of f){let ee=I.source_session_id===e?I.target_session_id:I.source_session_id,B=Bs(c,ee);if(!B)continue;let T=Ac(u.started_at,B.started_at),U=Mc({confidence:I.confidence,linkType:I.link_type,daysApart:T,embeddingCosine:null,pagerank:h.get(ee)??0,scoring:n}),M=Cc(T),K=`${I.link_type} confidence=${I.confidence.toFixed(2)} recency=${M.toFixed(2)} (${Math.round(T)}d apart)`,He={...B,score:U,evidence:K,link_type:I.link_type};I.link_type==="citation"?E.push(He):I.link_type==="similar"?b.push(He):I.link_type==="wiki_link"?N.push(He):S.push(He)}if(i){let I=Ds({sourceSessionId:e,status:"pending",limit:100}),ee=Ds({targetSessionId:e,status:"pending",limit:100}),B=[...I,...ee],T=new Set,U=B.filter(K=>T.has(K.id)?!1:(T.add(K.id),!0)),M=JE(c,u,U,a,n,h);for(let K of M)K.link_type==="citation"?E.push(K):K.link_type==="similar"?b.push(K):K.link_type==="wiki_link"?N.push(K):S.push(K)}let y=(I,ee)=>ee.score-I.score;E.sort(y),b.sort(y),S.sort(y),N.sort(y);let q=XE(u,[{heading:"Parents",refs:m},{heading:"Children",refs:p},{heading:"Citations (approved)",refs:E},{heading:"Similar sessions",refs:b},{heading:"Cousins (skill track + temporal)",refs:S},{heading:"Wiki links (manual)",refs:N}],s);return{origin:u,parents:m,children:p,citations:E,similar:b,cousins:S,wikiLinks:N,bundle:q.bundle,budgetUsed:q.budgetUsed,budgetRemaining:Math.max(0,s-q.budgetUsed),truncated:q.truncated}}var vE,IE,ME,DE,$E,Dc,Ar=L(()=>{"use strict";w();zt();vE=4e3,IE=2,ME=30,DE=.2,$E={citation:1,wiki_link:.9,similar:.7,skill_track:.5,bug_pattern:.4,temporal_proximity:.3};Dc=240});var Ul={};fe(Ul,{computeAllHealthScores:()=>zr,computeHealthScore:()=>Gr,computeHealthScoreByName:()=>Yr});function Kt(e){return Math.max(0,Math.min(1,e))}function Gr(e){let t=_(),s=t.prepare("SELECT id, name FROM projects WHERE id = ?").get(e);if(!s)return null;let n=t.prepare(`SELECT COUNT(*) AS cnt,
727
777
  MAX(started_at) AS latest
728
- FROM sessions WHERE project_id = ?`).get(e),r=n.cnt;if(r===0)return{projectId:e,projectName:s.name,score:0,breakdown:{sessionCount:{raw:0,score:0,weight:.2},recency:{daysSinceLastSession:1/0,score:0,weight:.25},fragmentation:{avgMessages:0,score:0,weight:.15},searchCoverage:{ratio:0,score:0,weight:.2},tagCoverage:{ratio:0,score:0,weight:.2}}};let o=qt(r/10),i=n.latest?(Date.now()-new Date(n.latest).getTime())/(1e3*60*60*24):90,a=qt(1-i/90),c=t.prepare(`SELECT AVG(message_count) AS avg_msgs
729
- FROM sessions WHERE project_id = ?`).get(e).avg_msgs??0,u=qt((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=Kt(r/10),i=n.latest?(Date.now()-new Date(n.latest).getTime())/(1e3*60*60*24):90,a=Kt(1-i/90),c=t.prepare(`SELECT AVG(message_count) AS avg_msgs
779
+ FROM sessions WHERE project_id = ?`).get(e).avg_msgs??0,u=Kt((c-2)/3),m=t.prepare(`SELECT COUNT(*) AS total,
730
780
  SUM(CASE WHEN m.content_text IS NOT NULL AND m.content_text != '' THEN 1 ELSE 0 END) AS covered
731
781
  FROM messages m
732
782
  JOIN sessions s ON s.id = m.session_id
733
- WHERE s.project_id = ?`).get(e),m=p.total>0?p.covered/p.total:.5,f=qt(m),g=t.prepare(`SELECT COUNT(DISTINCT s.id) AS total,
783
+ WHERE s.project_id = ?`).get(e),p=m.total>0?m.covered/m.total:.5,f=Kt(p),g=t.prepare(`SELECT COUNT(DISTINCT s.id) AS total,
734
784
  COUNT(DISTINCT st.session_id) AS tagged
735
785
  FROM sessions s
736
786
  LEFT JOIN session_tags st ON st.session_id = s.id
737
- WHERE s.project_id = ?`).get(e),h=g.total>0?g.tagged/g.total:0,E=qt(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 Ur(e){let s=_().prepare("SELECT id FROM projects WHERE name = ?").get(e);return s?Fr(s.id):null}function Br(){let t=_().prepare("SELECT id FROM projects ORDER BY name").all(),s=[];for(let n of t){let r=Fr(n.id);r&&s.push(r)}return s}var Hr=N(()=>{"use strict";T()});function vd(e,t){return{type:"svg",props:{width:e,height:e,viewBox:"0 0 64 64",style:{display:"flex"},children:[{type:"line",props:{x1:14,y1:16,x2:46,y2:16,stroke:t,strokeWidth:3,strokeLinecap:"round"}},{type:"line",props:{x1:14,y1:24,x2:38,y2:24,stroke:t,strokeWidth:3,strokeLinecap:"round"}},{type:"line",props:{x1:10,y1:32,x2:54,y2:32,stroke:yt,strokeWidth:5,strokeLinecap:"round"}},{type:"line",props:{x1:14,y1:40,x2:42,y2:40,stroke:t,strokeWidth:3,strokeLinecap:"round"}},{type:"line",props:{x1:14,y1:48,x2:36,y2:48,stroke:t,strokeWidth:3,strokeLinecap:"round"}}]}}}function st(e,t){return{type:"div",props:{style:{display:"flex",alignItems:"center",justifyContent:"space-between",width:"100%"},children:[{type:"div",props:{style:{display:"flex",alignItems:"center",gap:"18px"},children:[vd(72,e.markStroke),{type:"span",props:{style:{fontSize:"36px",fontWeight:700,color:e.wordmarkFg,letterSpacing:"-0.01em"},children:"Claude Recall"}}]}},{type:"span",props:{style:{fontSize:"17px",color:e.wordmarkFg,opacity:.6,textTransform:"uppercase",letterSpacing:"0.18em",fontWeight:600},children:t}}]}}}function nt(e){return{type:"div",props:{style:{display:"flex",alignItems:"center",justifyContent:"space-between",width:"100%"},children:[{type:"div",props:{style:{display:"flex",alignItems:"center",gap:"14px"},children:[vd(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 Fy(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 Uy(e){return e.toLocaleString("en-US")}function rt(e){return e<1e3?String(e):`${Fy(e)} (${Uy(e)})`}function ot(e){return new Date(e).toLocaleDateString("en-US",{month:"long",day:"numeric",year:"numeric"})}var yt,Vt=N(()=>{"use strict";yt="#f97316"});var $d={};fe($d,{render:()=>Wy});function Qs(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:Zt,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:en,textTransform:"uppercase",letterSpacing:"0.16em"},children:t}}]}}}function Wy(e){let s=[ot(e.sessionDate)];e.durationLabel&&s.push(e.durationLabel);let n=s.join(" \xB7 "),r=e.costDollars??"$\u2014",o=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${rt(e.cachedTokens)} cached`:null,i=[st(Md,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:Zt,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"20px",color:en},children:n}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",padding:"32px 0"},children:[{type:"span",props:{style:{fontSize:"180px",fontWeight:700,color:yt,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:r}},{type:"span",props:{style:{marginTop:"16px",fontSize:"16px",color:en,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:600},children:"session cost"}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:Hy}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[Qs(String(e.messageCount),"msgs"),Qs(String(e.filesReferenced),"files"),Qs(String(e.toolCallCount),"tools"),Qs(e.model??"\u2014","model")]}}];return o&&i.push({type:"div",props:{style:{fontSize:"14px",color:en,fontFamily:"JetBrains Mono",opacity:.7},children:o}}),e.verdict&&i.push({type:"div",props:{style:{display:"flex",fontSize:"24px",fontStyle:"italic",color:Zt,borderLeft:`3px solid ${yt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),i.push({type:"div",props:{style:{display:"flex",flex:1}}}),i.push(nt(Md)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:By,padding:"64px 72px",fontFamily:"Inter",gap:"28px"},children:i}}}var By,Zt,en,Hy,Md,Dd=N(()=>{"use strict";Vt();By="#1a1b1e",Zt="#e7e9ee",en="#8b9098",Hy="#2a2c33",Md={markStroke:Zt,wordmarkFg:Zt}});var Pd={};fe(Pd,{render:()=>Gy});function tn(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:Qt,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:sn,fontFamily:"JetBrains Mono",textTransform:"lowercase"},children:`// ${t}`}}]}}}function Gy(e){let t=[ot(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),s=e.costDollars??"$\u2014",n=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`# ${rt(e.cachedTokens)} tokens cache-replayed (free)`:null,r=[st(jd,"recall.cli/share"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"6px"},children:[{type:"div",props:{style:{fontSize:"18px",color:eo,fontFamily:"JetBrains Mono"},children:"$ recall share --session"}},{type:"div",props:{style:{fontSize:"40px",fontWeight:700,color:Qt,lineHeight:1.15,wordBreak:"break-word",fontFamily:"JetBrains Mono"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"18px",color:sn,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:sn,fontFamily:"JetBrains Mono"},children:"> total_cost:"}},{type:"span",props:{style:{fontSize:"180px",fontWeight:700,color:eo,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:s}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:Jy}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[tn(String(e.messageCount),"msgs"),tn(String(e.filesReferenced),"files"),tn(String(e.toolCallCount),"tools"),tn(e.model??"\u2014","model")]}}];return n&&r.push({type:"div",props:{style:{fontSize:"14px",color:sn,fontFamily:"JetBrains Mono",opacity:.7},children:n}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"22px",color:Qt,fontFamily:"JetBrains Mono",borderLeft:`3px solid ${eo}`,paddingLeft:"20px",marginTop:"8px"},children:`// ${e.verdict}`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(nt(jd)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:Xy,padding:"64px 72px",fontFamily:"Inter",gap:"28px"},children:r}}}var Xy,Qt,sn,Jy,eo,jd,Fd=N(()=>{"use strict";Vt();Xy="#0d0d0f",Qt="#e1e7ee",sn="#6b7480",Jy="#1f2229",eo="#7ee787",jd={markStroke:Qt,wordmarkFg:Qt}});var Bd={};fe(Bd,{render:()=>Yy});function nn(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:Tt,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:rn,textTransform:"uppercase",letterSpacing:"0.16em",fontWeight:600},children:t}}]}}}function Yy(e){let t=[ot(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),s=e.costDollars??"$\u2014",n=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${rt(e.cachedTokens)} cached`:null,r=[st(Ud,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:Tt,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"20px",color:rn},children:t}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",padding:"32px 0"},children:[{type:"span",props:{style:{fontSize:"180px",fontWeight:700,color:Tt,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:s}},{type:"span",props:{style:{marginTop:"16px",fontSize:"16px",color:rn,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:600},children:"session cost"}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:zy}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[nn(String(e.messageCount),"msgs"),nn(String(e.filesReferenced),"files"),nn(String(e.toolCallCount),"tools"),nn(e.model??"\u2014","model")]}}];return n&&r.push({type:"div",props:{style:{fontSize:"14px",color:rn,fontFamily:"JetBrains Mono",opacity:.85},children:n}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"24px",fontStyle:"italic",color:Tt,borderLeft:`3px solid ${Tt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(nt(Ud)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundImage:"linear-gradient(135deg, #b1370f 0%, #f97316 55%, #fbbf24 100%)",padding:"64px 72px",fontFamily:"Inter",gap:"28px"},children:r}}}var Tt,rn,zy,Ud,Hd=N(()=>{"use strict";Vt();Tt="#ffffff",rn="rgba(255,255,255,0.7)",zy="rgba(255,255,255,0.18)",Ud={markStroke:Tt,wordmarkFg:Tt}});var Xd={};fe(Xd,{render:()=>Qy});function on(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:800,color:Lt,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:es,textTransform:"uppercase",letterSpacing:"0.16em",fontWeight:600},children:t}}]}}}function Zy(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:Vy,overflow:"hidden"},children:e.map(s=>({type:"div",props:{style:{display:"flex",width:`${s.value/t*100}%`,height:"100%",backgroundColor:s.color}}}))}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",fontSize:"12px",color:es,fontWeight:600,textTransform:"uppercase",letterSpacing:"0.14em"},children:e.map(s=>({type:"span",props:{style:{display:"flex"},children:`${s.label} \xB7 ${s.value}`}}))}}]}}}function Qy(e){let t=[ot(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),s=e.costDollars??"$\u2014",n=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${rt(e.cachedTokens)} cached`:null,r=[st(Wd,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"40px",fontWeight:700,color:Lt,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"18px",color:es},children:t}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"flex-start",padding:"8px 0"},children:[{type:"span",props:{style:{fontSize:"14px",color:es,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:700},children:"session cost"}},{type:"span",props:{style:{fontSize:"180px",fontWeight:800,color:Lt,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:s}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:Ky}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[on(String(e.messageCount),"msgs"),on(String(e.filesReferenced),"files"),on(String(e.toolCallCount),"tools"),on(e.model??"\u2014","model")]}},Zy([{value:e.messageCount,color:yt,label:"msgs"},{value:e.filesReferenced,color:"#0a0a0a",label:"files"},{value:e.toolCallCount,color:"#5a6068",label:"tools"}])];return n&&r.push({type:"div",props:{style:{fontSize:"14px",color:es,fontFamily:"JetBrains Mono",opacity:.85},children:n}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"22px",fontStyle:"italic",color:Lt,borderLeft:`3px solid ${yt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(nt(Wd)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:qy,padding:"64px 72px",fontFamily:"Inter",gap:"24px"},children:r}}}var qy,Lt,es,Ky,Vy,Wd,Jd=N(()=>{"use strict";Vt();qy="#f6f7f9",Lt="#0a0a0a",es="#5a6068",Ky="#e3e6eb",Vy="#dde1e7",Wd={markStroke:Lt,wordmarkFg:Lt}});var Gd={};fe(Gd,{render:()=>sT});function to(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"8px",flex:1},children:[{type:"div",props:{style:{fontSize:"52px",fontWeight:700,color:an},children:t}},{type:"div",props:{style:{fontSize:"16px",color:At,textTransform:"uppercase",letterSpacing:"2px"},children:e}}]}}}function so(e,t){return{type:"div",props:{style:{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"16px 24px",backgroundColor:no,borderRadius:"12px"},children:[{type:"span",props:{style:{fontSize:"18px",color:At},children:e}},{type:"span",props:{style:{fontSize:"20px",fontWeight:700,color:an},children:t}}]}}}function sT(e){let t=Math.round(e.healthScore),s=[{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"16px",color:At,textTransform:"uppercase",letterSpacing:"6px"},children:"YOUR MONTH IN CODE"}},{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:an},children:e.month}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"12px",backgroundColor:no,borderRadius:"16px",padding:"28px",border:`1px solid ${Ot}40`},children:[{type:"div",props:{style:{fontSize:"16px",color:tT,textTransform:"uppercase",letterSpacing:"2px"},children:"You are a"}},{type:"div",props:{style:{fontSize:"36px",fontWeight:700,color:Ot},children:e.archetype}}]}},{type:"div",props:{style:{display:"flex",gap:"16px",width:"100%"},children:[to("Recalls",String(e.totalRecalls)),to("Tokens piped",e.totalTokensPiped>999999?`${(e.totalTokensPiped/1e6).toFixed(1)}M`:e.totalTokensPiped.toLocaleString()),to("Sessions",String(e.sessionsIndexed))]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px",width:"100%"},children:[{type:"div",props:{style:{fontSize:"14px",color:At,textTransform:"uppercase",letterSpacing:"2px",marginBottom:"4px"},children:"Highlights"}},so("Most recalled",e.mostRecalledSession),so("Biggest recall",`${e.biggestRecallTokens.toLocaleString()} tokens`),so("Peak hours",e.mostActiveHours)]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"12px"},children:[{type:"div",props:{style:{width:"100px",height:"100px",borderRadius:"50%",border:`6px solid ${Ot}`,display:"flex",alignItems:"center",justifyContent:"center"},children:{type:"span",props:{style:{fontSize:"32px",fontWeight:700,color:Ot},children:`${t}`}}}},{type:"div",props:{style:{fontSize:"14px",color:At,textTransform:"uppercase",letterSpacing:"2px"},children:"Memory health"}}]}}];return e.verdict&&s.push({type:"div",props:{style:{backgroundColor:no,borderLeft:`3px solid ${Ot}`,borderRadius:"8px",padding:"20px 24px",fontSize:"20px",color:an,fontStyle:"italic"},children:`"${e.verdict}"`}}),s.push({type:"div",props:{style:{display:"flex",alignItems:"center",justifyContent:"center",gap:"12px",marginTop:"auto"},children:[{type:"span",props:{style:{fontSize:"22px",fontWeight:700,color:Ot},children:"Claude Recall"}},{type:"span",props:{style:{fontSize:"18px",color:At},children:"clauderecall.com"}}]}}),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:eT,padding:"72px 64px",fontFamily:"Inter",gap:"36px"},children:s}}}var eT,no,an,At,Ot,tT,zd=N(()=>{"use strict";eT="#0b0c0f",no="#15171c",an="#e7e9ee",At="#8b9098",Ot="#f97316",tT="#fb923c"});var co,au,G,w,Z,Me,cu,lu,du,uu,lo,uo,it=N(()=>{"use strict";co=[String.raw` ___ _ _ _ _ ___ ___ ___ ___ ___ _ _ _ `,String.raw` / __| | /_\ | | | | \| __| | _ \ __/ __| /_\ | | | | `,String.raw`| (__| |__ / _ \| |_| | |) | _| | / _| (__ / _ \| |__| |__ `,String.raw` \___|____/_/ \_\\___/|___/|___| |_|_\___\___/_/ \_\____|____|`],au=co[0]?.length??64,G="#f97316",w="#8b9098",Z="#10b981",Me="#f59e0b",cu="#60a5fa",lu="#34d399",du="#c084fc",uu="CLAUDE RECALL",lo=100,uo=30});import{useEffect as vT,useState as MT}from"react";import{Box as pu,Text as pe}from"ink";import{createRequire as $T}from"node:module";import{existsSync as DT}from"node:fs";import{jsx as re,jsxs as gu}from"react/jsx-runtime";function mu({cols:e}){let[t,s]=MT(FT);vT(()=>{let r=!1,o=K(),i=0,a=0;if(DT(te))try{let c=_().prepare(`SELECT
787
+ WHERE s.project_id = ?`).get(e),h=g.total>0?g.tagged/g.total:0,E=Kt(h),b=Math.round((o*.2+a*.25+u*.15+f*.2+E*.2)*100);return{projectId:e,projectName:s.name,score:b,breakdown:{sessionCount:{raw:r,score:o,weight:.2},recency:{daysSinceLastSession:Math.round(i),score:a,weight:.25},fragmentation:{avgMessages:Math.round(c*10)/10,score:u,weight:.15},searchCoverage:{ratio:Math.round(p*100)/100,score:f,weight:.2},tagCoverage:{ratio:Math.round(h*100)/100,score:E,weight:.2}}}}function Yr(e){let s=_().prepare("SELECT id FROM projects WHERE name = ?").get(e);return s?Gr(s.id):null}function zr(){let t=_().prepare("SELECT id FROM projects ORDER BY name").all(),s=[];for(let n of t){let r=Gr(n.id);r&&s.push(r)}return s}var qr=L(()=>{"use strict";w()});function Vd(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:Tt,strokeWidth:5,strokeLinecap:"round"}},{type:"line",props:{x1:14,y1:40,x2:42,y2:40,stroke:t,strokeWidth:3,strokeLinecap:"round"}},{type:"line",props:{x1:14,y1:48,x2:36,y2:48,stroke:t,strokeWidth:3,strokeLinecap:"round"}}]}}}function st(e,t){return{type:"div",props:{style:{display:"flex",alignItems:"center",justifyContent:"space-between",width:"100%"},children:[{type:"div",props:{style:{display:"flex",alignItems:"center",gap:"18px"},children:[Vd(72,e.markStroke),{type:"span",props:{style:{fontSize:"36px",fontWeight:700,color:e.wordmarkFg,letterSpacing:"-0.01em"},children:"Claude Recall"}}]}},{type:"span",props:{style:{fontSize:"17px",color:e.wordmarkFg,opacity:.6,textTransform:"uppercase",letterSpacing:"0.18em",fontWeight:600},children:t}}]}}}function nt(e){return{type:"div",props:{style:{display:"flex",alignItems:"center",justifyContent:"space-between",width:"100%"},children:[{type:"div",props:{style:{display:"flex",alignItems:"center",gap:"14px"},children:[Vd(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 py(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 gy(e){return e.toLocaleString("en-US")}function rt(e){return e<1e3?String(e):`${py(e)} (${gy(e)})`}function ot(e){return new Date(e).toLocaleDateString("en-US",{month:"long",day:"numeric",year:"numeric"})}var Tt,Zt=L(()=>{"use strict";Tt="#f97316"});var Qd={};fe(Qd,{render:()=>hy});function rn(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:Qt,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:on,textTransform:"uppercase",letterSpacing:"0.16em"},children:t}}]}}}function hy(e){let s=[ot(e.sessionDate)];e.durationLabel&&s.push(e.durationLabel);let n=s.join(" \xB7 "),r=e.costDollars??"$\u2014",o=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${rt(e.cachedTokens)} cached`:null,i=[st(Zd,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:Qt,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"20px",color:on},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:Tt,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:r}},{type:"span",props:{style:{marginTop:"16px",fontSize:"16px",color:on,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:600},children:"session cost"}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:_y}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[rn(String(e.messageCount),"msgs"),rn(String(e.filesReferenced),"files"),rn(String(e.toolCallCount),"tools"),rn(e.model??"\u2014","model")]}}];return o&&i.push({type:"div",props:{style:{fontSize:"14px",color:on,fontFamily:"JetBrains Mono",opacity:.7},children:o}}),e.verdict&&i.push({type:"div",props:{style:{display:"flex",fontSize:"24px",fontStyle:"italic",color:Qt,borderLeft:`3px solid ${Tt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),i.push({type:"div",props:{style:{display:"flex",flex:1}}}),i.push(nt(Zd)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:fy,padding:"64px 72px",fontFamily:"Inter",gap:"28px"},children:i}}}var fy,Qt,on,_y,Zd,eu=L(()=>{"use strict";Zt();fy="#1a1b1e",Qt="#e7e9ee",on="#8b9098",_y="#2a2c33",Zd={markStroke:Qt,wordmarkFg:Qt}});var su={};fe(su,{render:()=>Sy});function an(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:es,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:cn,fontFamily:"JetBrains Mono",textTransform:"lowercase"},children:`// ${t}`}}]}}}function Sy(e){let t=[ot(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),s=e.costDollars??"$\u2014",n=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`# ${rt(e.cachedTokens)} tokens cache-replayed (free)`:null,r=[st(tu,"recall.cli/share"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"6px"},children:[{type:"div",props:{style:{fontSize:"18px",color:ao,fontFamily:"JetBrains Mono"},children:"$ recall share --session"}},{type:"div",props:{style:{fontSize:"40px",fontWeight:700,color:es,lineHeight:1.15,wordBreak:"break-word",fontFamily:"JetBrains Mono"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"18px",color:cn,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:cn,fontFamily:"JetBrains Mono"},children:"> total_cost:"}},{type:"span",props:{style:{fontSize:"180px",fontWeight:700,color:ao,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:s}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:by}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[an(String(e.messageCount),"msgs"),an(String(e.filesReferenced),"files"),an(String(e.toolCallCount),"tools"),an(e.model??"\u2014","model")]}}];return n&&r.push({type:"div",props:{style:{fontSize:"14px",color:cn,fontFamily:"JetBrains Mono",opacity:.7},children:n}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"22px",color:es,fontFamily:"JetBrains Mono",borderLeft:`3px solid ${ao}`,paddingLeft:"20px",marginTop:"8px"},children:`// ${e.verdict}`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(nt(tu)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:Ey,padding:"64px 72px",fontFamily:"Inter",gap:"28px"},children:r}}}var Ey,es,cn,by,ao,tu,nu=L(()=>{"use strict";Zt();Ey="#0d0d0f",es="#e1e7ee",cn="#6b7480",by="#1f2229",ao="#7ee787",tu={markStroke:es,wordmarkFg:es}});var ou={};fe(ou,{render:()=>yy});function ln(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:yt,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:dn,textTransform:"uppercase",letterSpacing:"0.16em",fontWeight:600},children:t}}]}}}function yy(e){let t=[ot(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),s=e.costDollars??"$\u2014",n=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${rt(e.cachedTokens)} cached`:null,r=[st(ru,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:yt,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"20px",color:dn},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:yt,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:s}},{type:"span",props:{style:{marginTop:"16px",fontSize:"16px",color:dn,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:600},children:"session cost"}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:Ty}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[ln(String(e.messageCount),"msgs"),ln(String(e.filesReferenced),"files"),ln(String(e.toolCallCount),"tools"),ln(e.model??"\u2014","model")]}}];return n&&r.push({type:"div",props:{style:{fontSize:"14px",color:dn,fontFamily:"JetBrains Mono",opacity:.85},children:n}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"24px",fontStyle:"italic",color:yt,borderLeft:`3px solid ${yt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(nt(ru)),{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 yt,dn,Ty,ru,iu=L(()=>{"use strict";Zt();yt="#ffffff",dn="rgba(255,255,255,0.7)",Ty="rgba(255,255,255,0.18)",ru={markStroke:yt,wordmarkFg:yt}});var cu={};fe(cu,{render:()=>Ny});function un(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:800,color:Ct,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:ts,textTransform:"uppercase",letterSpacing:"0.16em",fontWeight:600},children:t}}]}}}function ky(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:xy,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:ts,fontWeight:600,textTransform:"uppercase",letterSpacing:"0.14em"},children:e.map(s=>({type:"span",props:{style:{display:"flex"},children:`${s.label} \xB7 ${s.value}`}}))}}]}}}function Ny(e){let t=[ot(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),s=e.costDollars??"$\u2014",n=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${rt(e.cachedTokens)} cached`:null,r=[st(au,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"40px",fontWeight:700,color:Ct,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"18px",color:ts},children:t}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"flex-start",padding:"8px 0"},children:[{type:"span",props:{style:{fontSize:"14px",color:ts,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:700},children:"session cost"}},{type:"span",props:{style:{fontSize:"180px",fontWeight:800,color:Ct,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:s}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:Ry}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[un(String(e.messageCount),"msgs"),un(String(e.filesReferenced),"files"),un(String(e.toolCallCount),"tools"),un(e.model??"\u2014","model")]}},ky([{value:e.messageCount,color:Tt,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:ts,fontFamily:"JetBrains Mono",opacity:.85},children:n}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"22px",fontStyle:"italic",color:Ct,borderLeft:`3px solid ${Tt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(nt(au)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:wy,padding:"64px 72px",fontFamily:"Inter",gap:"24px"},children:r}}}var wy,Ct,ts,Ry,xy,au,lu=L(()=>{"use strict";Zt();wy="#f6f7f9",Ct="#0a0a0a",ts="#5a6068",Ry="#e3e6eb",xy="#dde1e7",au={markStroke:Ct,wordmarkFg:Ct}});var du={};fe(du,{render:()=>Ay});function co(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:mn},children:t}},{type:"div",props:{style:{fontSize:"16px",color:Ot,textTransform:"uppercase",letterSpacing:"2px"},children:e}}]}}}function lo(e,t){return{type:"div",props:{style:{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"16px 24px",backgroundColor:uo,borderRadius:"12px"},children:[{type:"span",props:{style:{fontSize:"18px",color:Ot},children:e}},{type:"span",props:{style:{fontSize:"20px",fontWeight:700,color:mn},children:t}}]}}}function Ay(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:Ot,textTransform:"uppercase",letterSpacing:"6px"},children:"YOUR MONTH IN CODE"}},{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:mn},children:e.month}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"12px",backgroundColor:uo,borderRadius:"16px",padding:"28px",border:`1px solid ${At}40`},children:[{type:"div",props:{style:{fontSize:"16px",color:Cy,textTransform:"uppercase",letterSpacing:"2px"},children:"You are a"}},{type:"div",props:{style:{fontSize:"36px",fontWeight:700,color:At},children:e.archetype}}]}},{type:"div",props:{style:{display:"flex",gap:"16px",width:"100%"},children:[co("Recalls",String(e.totalRecalls)),co("Tokens piped",e.totalTokensPiped>999999?`${(e.totalTokensPiped/1e6).toFixed(1)}M`:e.totalTokensPiped.toLocaleString()),co("Sessions",String(e.sessionsIndexed))]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px",width:"100%"},children:[{type:"div",props:{style:{fontSize:"14px",color:Ot,textTransform:"uppercase",letterSpacing:"2px",marginBottom:"4px"},children:"Highlights"}},lo("Most recalled",e.mostRecalledSession),lo("Biggest recall",`${e.biggestRecallTokens.toLocaleString()} tokens`),lo("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 ${At}`,display:"flex",alignItems:"center",justifyContent:"center"},children:{type:"span",props:{style:{fontSize:"32px",fontWeight:700,color:At},children:`${t}`}}}},{type:"div",props:{style:{fontSize:"14px",color:Ot,textTransform:"uppercase",letterSpacing:"2px"},children:"Memory health"}}]}}];return e.verdict&&s.push({type:"div",props:{style:{backgroundColor:uo,borderLeft:`3px solid ${At}`,borderRadius:"8px",padding:"20px 24px",fontSize:"20px",color:mn,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:At},children:"Claude Recall"}},{type:"span",props:{style:{fontSize:"18px",color:Ot},children:"clauderecall.com"}}]}}),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:Ly,padding:"72px 64px",fontFamily:"Inter",gap:"36px"},children:s}}}var Ly,uo,mn,Ot,At,Cy,uu=L(()=>{"use strict";Ly="#0b0c0f",uo="#15171c",mn="#e7e9ee",Ot="#8b9098",At="#f97316",Cy="#fb923c"});var _o,xu,G,R,Q,De,ku,Nu,Lu,Cu,ho,Eo,it=L(()=>{"use strict";_o=[String.raw` ___ _ _ _ _ ___ ___ ___ ___ ___ _ _ _ `,String.raw` / __| | /_\ | | | | \| __| | _ \ __/ __| /_\ | | | | `,String.raw`| (__| |__ / _ \| |_| | |) | _| | / _| (__ / _ \| |__| |__ `,String.raw` \___|____/_/ \_\\___/|___/|___| |_|_\___\___/_/ \_\____|____|`],xu=_o[0]?.length??64,G="#f97316",R="#8b9098",Q="#10b981",De="#f59e0b",ku="#60a5fa",Nu="#34d399",Lu="#c084fc",Cu="CLAUDE RECALL",ho=100,Eo=30});import{useEffect as aw,useState as cw}from"react";import{Box as Au,Text as me}from"ink";import{createRequire as lw}from"node:module";import{existsSync as dw}from"node:fs";import{jsx as re,jsxs as vu}from"react/jsx-runtime";function Ou({cols:e}){let[t,s]=cw(pw);aw(()=>{let r=!1,o=Z(),i=0,a=0;if(dw(te))try{let c=_().prepare(`SELECT
738
788
  (SELECT COUNT(*) FROM sessions) AS sessions,
739
- (SELECT COUNT(*) FROM projects) AS projects`).get();i=c.sessions,a=c.projects}catch{}return s(l=>({...l,daemon:o,sessions:i,projects:a})),ye().then(l=>{r||s(c=>({...c,tier:l.tier}))}).catch(()=>{}),()=>{r=!0}},[]);let n=e>=au+2;return gu(pu,{flexDirection:"column",children:[n?co.map((r,o)=>re(pe,{color:G,bold:!0,children:r},o)):re(pe,{color:G,bold:!0,children:uu}),re(UT,{state:t})]})}function UT({state:e}){let t=re(pe,{color:w,children:" \xB7 "});return gu(pu,{children:[re(pe,{color:w,children:"v"}),re(pe,{color:G,children:PT}),t,re(pe,{color:w,children:"daemon: "}),e.daemon?re(pe,{color:Z,children:`running 127.0.0.1:${e.daemon.port}`}):re(pe,{color:Me,children:"stopped"}),t,re(pe,{color:w,children:"sessions: "}),re(pe,{color:G,children:e.sessions}),e.projects>0?re(pe,{color:w,children:` across ${e.projects} ${e.projects===1?"project":"projects"}`}):null,t,re(pe,{color:w,children:"license: "}),e.tier==="pro"?re(pe,{color:Z,children:"Pro"}):re(pe,{color:w,children:"Free"})]})}var jT,PT,FT,fu=N(()=>{"use strict";We();j();T();_e();it();jT=$T(import.meta.url),PT=jT("../../../package.json").version,FT={daemon:null,sessions:0,projects:0,tier:"free"}});import{Box as Ye,Text as oe}from"ink";import{jsx as z,jsxs as dn}from"react/jsx-runtime";function HT(e,t,s){if(t<=s)return{start:0,end:t};let n=e-Math.floor(s/2);return n<0&&(n=0),n+s>t&&(n=t-s),{start:n,end:n+s}}function at(e,t){if(t<=0)return"";let s=e.replace(/\s+/g," ").trim();return s.length<=t?s:s.slice(0,Math.max(0,t-1))+"\u2026"}function _u({sessions:e,total:t,selected:s,width:n,height:r,loading:o,dbExists:i,filter:a,sortMode:l,groupByProject:c}){let u=Math.max(20,n-2),f=Math.max(1,r-1-1-2),g=HT(s,e.length,f),h=e.slice(g.start,g.end);if(!i)return dn(Ye,{flexDirection:"column",width:n,height:r,borderStyle:"round",borderColor:w,children:[z(oe,{color:G,bold:!0,children:" Sessions "}),z(Ye,{paddingX:1,paddingY:1,children:z(oe,{color:w,wrap:"wrap",children:"No sessions indexed yet. Quit (q) and run `recall index` first."})})]});let S=[BT[l],c?"grouped":""].filter(Boolean).join(" \xB7 "),C=o?" Sessions \xB7 loading\u2026 ":a?` Sessions \xB7 ${e.length} of ${t} match "${at(a,18)}" \xB7 ${S} `:` Sessions \xB7 ${e.length} of ${t} \xB7 ${S} `,R=null;return c&&g.start>0&&(R=e[g.start-1]?.project_name??null),dn(Ye,{flexDirection:"column",width:n,height:r,borderStyle:"round",borderColor:w,children:[z(Ye,{width:u+2,paddingLeft:1,children:z(oe,{color:G,bold:!0,children:at(C,u)})}),z(Ye,{flexDirection:"column",flexGrow:1,paddingX:1,children:h.length===0?z(oe,{color:w,children:a?"no matches.":"no sessions."}):h.flatMap((L,Q)=>{let v=g.start+Q,ee=v===s,B=[];return c&&L.project_name!==R&&(B.push(z(XT,{project:L.project_name,width:u},`hdr-${L.project_name}-${v}`)),R=L.project_name),B.push(z(WT,{session:L,width:u,isSelected:ee,indented:c},L.id)),B})}),z(Ye,{width:u+2,paddingLeft:1,children:z(oe,{color:w,children:e.length>0?at(` ${s+1} / ${e.length}${g.end<e.length?" \xB7 scroll for more":""} `,u):""})})]})}function WT({session:e,width:t,isSelected:s,indented:n}){let r=W(e.started_at)||"",o=n?" ":"",i=s?"\u258C ":" ";if(n){let f=e.alias||e.auto_title||e.first_user_message||"(no title)",g=Math.min(14,Math.max(6,Math.floor(t*.25))),h=Math.max(10,t-i.length-o.length-g-1),E=at(f,h),b=at(r,g),S=Math.max(1,t-i.length-o.length-E.length-b.length);return dn(Ye,{children:[z(oe,{children:o}),z(oe,{color:s?G:w,bold:s,children:i}),z(oe,{color:s?G:"#fefce8",bold:s,children:E}),z(oe,{children:" ".repeat(S)}),z(oe,{color:w,children:b})]})}let a=e.project_name||"?",l=Math.min(28,Math.floor(t*.7)),c=Math.min(14,t-l-i.length-1),u=at(a,l),p=at(r,c),m=Math.max(1,t-i.length-u.length-p.length);return dn(Ye,{children:[z(oe,{color:s?G:w,bold:s,children:i}),z(oe,{color:s?G:"#67e8f9",bold:s,children:u}),z(oe,{children:" ".repeat(m)}),z(oe,{color:w,children:p})]})}function XT({project:e,width:t}){return z(Ye,{children:z(oe,{color:"#67e8f9",bold:!0,children:at(`\u25BE ${e}`,t)})})}var BT,hu=N(()=>{"use strict";I();it();BT={recent:"recent",longest:"longest",busiest:"busiest project"}});import{useEffect as JT,useState as po}from"react";function Eu(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=c.sessions,a=c.projects}catch{}return s(l=>({...l,daemon:o,sessions:i,projects:a})),Te().then(l=>{r||s(c=>({...c,tier:l.tier}))}).catch(()=>{}),()=>{r=!0}},[]);let n=e>=xu+2;return vu(Au,{flexDirection:"column",children:[n?_o.map((r,o)=>re(me,{color:G,bold:!0,children:r},o)):re(me,{color:G,bold:!0,children:Cu}),re(gw,{state:t})]})}function gw({state:e}){let t=re(me,{color:R,children:" \xB7 "});return vu(Au,{children:[re(me,{color:R,children:"v"}),re(me,{color:G,children:mw}),t,re(me,{color:R,children:"daemon: "}),e.daemon?re(me,{color:Q,children:`running 127.0.0.1:${e.daemon.port}`}):re(me,{color:De,children:"stopped"}),t,re(me,{color:R,children:"sessions: "}),re(me,{color:G,children:e.sessions}),e.projects>0?re(me,{color:R,children:` across ${e.projects} ${e.projects===1?"project":"projects"}`}):null,t,re(me,{color:R,children:"license: "}),e.tier==="pro"?re(me,{color:Q,children:"Pro"}):re(me,{color:R,children:"Free"})]})}var uw,mw,pw,Iu=L(()=>{"use strict";Xe();P();w();_e();it();uw=lw(import.meta.url),mw=uw("../../../package.json").version,pw={daemon:null,sessions:0,projects:0,tier:"free"}});import{Box as qe,Text as oe}from"ink";import{jsx as Y,jsxs as fn}from"react/jsx-runtime";function _w(e,t,s){if(t<=s)return{start:0,end:t};let n=e-Math.floor(s/2);return n<0&&(n=0),n+s>t&&(n=t-s),{start:n,end:n+s}}function at(e,t){if(t<=0)return"";let s=e.replace(/\s+/g," ").trim();return s.length<=t?s:s.slice(0,Math.max(0,t-1))+"\u2026"}function Mu({sessions:e,total:t,selected:s,width:n,height:r,loading:o,dbExists:i,filter:a,sortMode:l,groupByProject:c}){let u=Math.max(20,n-2),f=Math.max(1,r-1-1-2),g=_w(s,e.length,f),h=e.slice(g.start,g.end);if(!i)return fn(qe,{flexDirection:"column",width:n,height:r,borderStyle:"round",borderColor:R,children:[Y(oe,{color:G,bold:!0,children:" Sessions "}),Y(qe,{paddingX:1,paddingY:1,children:Y(oe,{color:R,wrap:"wrap",children:"No sessions indexed yet. Quit (q) and run `recall index` first."})})]});let S=[fw[l],c?"grouped":""].filter(Boolean).join(" \xB7 "),N=o?" Sessions \xB7 loading\u2026 ":a?` Sessions \xB7 ${e.length} of ${t} match "${at(a,18)}" \xB7 ${S} `:` Sessions \xB7 ${e.length} of ${t} \xB7 ${S} `,y=null;return c&&g.start>0&&(y=e[g.start-1]?.project_name??null),fn(qe,{flexDirection:"column",width:n,height:r,borderStyle:"round",borderColor:R,children:[Y(qe,{width:u+2,paddingLeft:1,children:Y(oe,{color:G,bold:!0,children:at(N,u)})}),Y(qe,{flexDirection:"column",flexGrow:1,paddingX:1,children:h.length===0?Y(oe,{color:R,children:a?"no matches.":"no sessions."}):h.flatMap((C,q)=>{let I=g.start+q,ee=I===s,B=[];return c&&C.project_name!==y&&(B.push(Y(Ew,{project:C.project_name,width:u},`hdr-${C.project_name}-${I}`)),y=C.project_name),B.push(Y(hw,{session:C,width:u,isSelected:ee,indented:c},C.id)),B})}),Y(qe,{width:u+2,paddingLeft:1,children:Y(oe,{color:R,children:e.length>0?at(` ${s+1} / ${e.length}${g.end<e.length?" \xB7 scroll for more":""} `,u):""})})]})}function hw({session:e,width:t,isSelected:s,indented:n}){let r=W(e.started_at)||"",o=n?" ":"",i=s?"\u258C ":" ";if(n){let f=e.alias||e.auto_title||e.first_user_message||"(no title)",g=Math.min(14,Math.max(6,Math.floor(t*.25))),h=Math.max(10,t-i.length-o.length-g-1),E=at(f,h),b=at(r,g),S=Math.max(1,t-i.length-o.length-E.length-b.length);return fn(qe,{children:[Y(oe,{children:o}),Y(oe,{color:s?G:R,bold:s,children:i}),Y(oe,{color:s?G:"#fefce8",bold:s,children:E}),Y(oe,{children:" ".repeat(S)}),Y(oe,{color:R,children:b})]})}let a=e.project_name||"?",l=Math.min(28,Math.floor(t*.7)),c=Math.min(14,t-l-i.length-1),u=at(a,l),m=at(r,c),p=Math.max(1,t-i.length-u.length-m.length);return fn(qe,{children:[Y(oe,{color:s?G:R,bold:s,children:i}),Y(oe,{color:s?G:"#67e8f9",bold:s,children:u}),Y(oe,{children:" ".repeat(p)}),Y(oe,{color:R,children:m})]})}function Ew({project:e,width:t}){return Y(qe,{children:Y(oe,{color:"#67e8f9",bold:!0,children:at(`\u25BE ${e}`,t)})})}var fw,Du=L(()=>{"use strict";v();it();fw={recent:"recent",longest:"longest",busiest:"busiest project"}});import{useEffect as bw,useState as bo}from"react";function $u(e,t,s){let n=s?"":"AND is_sidechain = 0";return e.prepare(`SELECT uuid, role, type, timestamp, content_text
740
790
  FROM messages
741
791
  WHERE session_id = @id
742
792
  ${n}
743
793
  ORDER BY timestamp DESC
744
- LIMIT @limit`).all({id:t,limit:GT})}function bu(e){let[t,s]=po([]),[n,r]=po(!1),[o,i]=po(!1);return JT(()=>{if(!e){s([]),i(!1);return}r(!0);try{let a=_(),l=Eu(a,e,!1),c=!1;l.length===0&&(l=Eu(a,e,!0),c=l.length>0),s([...l].reverse()),i(c)}catch{s([]),i(!1)}finally{r(!1)}},[e]),{messages:t,loading:n,fallbackToSidechain:o}}var GT,Su=N(()=>{"use strict";T();GT=6});import{Box as $e,Text as Fe}from"ink";import{Fragment as KT,jsx as V,jsxs as vt}from"react/jsx-runtime";function zT(e){let t=(e.role??"").toLowerCase();return t==="user"?{label:"user",color:cu}:t==="assistant"?{label:"asst",color:lu}:t==="tool"?{label:"tool",color:du}:t==="system"?{label:"sys ",color:w}:e.type==="summary"?{label:"sum ",color:w}:{label:"----",color:w}}function YT(e,t){return e?e.replace(/\s+/g," ").trim().slice(0,t+1).replace(/.{1}$/,s=>e.length>t?"\u2026":s):"(empty)"}function yu({session:e,width:t,height:s}){let n=e?.id??null,{messages:r,loading:o,fallbackToSidechain:i}=bu(n),a=Math.max(20,t-2),c=Math.max(4,s-2-2),u=Math.max(2,Math.floor(c/Math.max(1,r.length)));return e?vt($e,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:w,children:[vt($e,{paddingX:1,flexDirection:"column",children:[V($e,{width:a,children:V(Fe,{color:G,bold:!0,wrap:"truncate-end",children:e.alias||e.auto_title||e.first_user_message||"(no title)"})}),V($e,{width:a,children:V(Fe,{color:w,wrap:"truncate-end",children:`${e.id.slice(0,8)} \xB7 ${e.message_count} msgs \xB7 ${W(e.started_at)}`})})]}),V($e,{flexDirection:"column",paddingX:1,flexGrow:1,children:o?V(Fe,{color:w,children:"loading messages\u2026"}):r.length===0?V(Fe,{color:w,children:"no messages indexed for this session."}):vt(KT,{children:[i?V(Fe,{color:w,children:"(showing sidechain / subagent messages)"}):null,r.map(p=>V(qT,{message:p,width:a,perMessageLines:u},p.uuid))]})})]}):vt($e,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:w,children:[V($e,{paddingX:1,children:V(Fe,{color:G,bold:!0,children:"Preview"})}),V($e,{paddingX:1,paddingY:1,children:V(Fe,{color:w,children:"Select a session on the left to preview."})})]})}function qT({message:e,width:t,perMessageLines:s}){let n=zT(e),r=Math.max(1,s-1),o=Math.max(20,t-2),i=r*o,a=YT(e.content_text,i);return vt($e,{flexDirection:"column",marginBottom:0,children:[vt($e,{children:[V(Fe,{color:n.color,bold:!0,children:n.label}),V(Fe,{color:w,children:` ${e.timestamp?W(e.timestamp):""}`})]}),V($e,{width:t,children:V(Fe,{wrap:"truncate-end",children:a})})]})}var Tu=N(()=>{"use strict";I();Su();it()});import{useMemo as VT}from"react";import{Box as De,Text as ct}from"ink";import{jsx as me,jsxs as ts}from"react/jsx-runtime";function ZT(e,t){try{return{ok:!0,result:Us(e,{budget:t})}}catch(s){return{ok:!1,error:s instanceof Error?s.message:String(s)}}}function wu({session:e,width:t,height:s,budget:n}){let r=VT(()=>e?ZT(e.id,n):null,[e?.id,n]),o=Math.max(20,t-2),a=Math.max(4,s-2-2);if(!e)return ts(De,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:w,children:[me(De,{paddingX:1,children:me(ct,{color:G,bold:!0,children:"Neighborhood"})}),me(De,{paddingX:1,paddingY:1,children:me(ct,{color:w,children:"Select a session and press `n` to assemble its neighborhood."})})]});if(!r)return null;if(!r.ok)return ts(De,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:Me,children:[me(De,{paddingX:1,children:me(ct,{color:Me,bold:!0,children:"Neighborhood error"})}),me(De,{paddingX:1,paddingY:1,children:me(ct,{color:Me,children:r.error})})]});let{result:l}=r,c=l.bundle.replace(/\n+$/,"").split(`
745
- `),u=c.slice(0,Math.max(1,a-1)),p=c.length-u.length;return ts(De,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:Z,children:[ts(De,{paddingX:1,flexDirection:"column",children:[me(De,{width:o,children:me(ct,{color:Z,bold:!0,wrap:"truncate-end",children:"Neighborhood"})}),me(De,{width:o,children:me(ct,{color:w,wrap:"truncate-end",children:`budget=${n} used=${l.budgetUsed} remaining=${l.budgetRemaining} truncated=${l.truncated.length}`})})]}),ts(De,{flexDirection:"column",paddingX:1,flexGrow:1,children:[u.map((m,f)=>me(ct,{wrap:"truncate-end",children:m||" "},f)),p>0?me(ct,{color:w,children:`\u2026 ${p} more line${p===1?"":"s"} (resize the terminal or use \`recall neighborhood ${e.id.slice(0,8)}\` for the full bundle)`}):null]})]})}var xu=N(()=>{"use strict";Rr();it()});import{useEffect as QT,useState as Ru}from"react";import{Box as ss,Text as lt}from"ink";import mo from"ink-text-input";import{jsx as be,jsxs as go}from"react/jsx-runtime";function ku({mode:e,query:t,onQueryChange:s,onSearchSubmit:n,onAliasSubmit:r,onTagSubmit:o,aliasInitial:i,toast:a}){let[l,c]=Ru(""),[u,p]=Ru("");return QT(()=>{e==="alias"&&c(i),e==="tag"&&p("")},[e,i]),a&&e==="normal"?be(ss,{children:be(lt,{color:Me,children:`\u25B6 ${a}`})}):e==="search"?go(ss,{children:[be(lt,{color:G,bold:!0,children:"/ "}),be(mo,{value:t,onChange:s,onSubmit:n,placeholder:"filter sessions by project, alias, or opening message..."}),be(lt,{color:w,children:" esc clear \xB7 enter confirm"})]}):e==="alias"?go(ss,{children:[be(lt,{color:Z,bold:!0,children:"alias \u203A "}),be(mo,{value:l,onChange:c,onSubmit:m=>r(m),placeholder:"terminal-tab name for this session"}),be(lt,{color:w,children:" esc cancel \xB7 enter save"})]}):e==="tag"?go(ss,{children:[be(lt,{color:Z,bold:!0,children:"tag \u203A "}),be(mo,{value:u,onChange:p,onSubmit:m=>o(m),placeholder:"add a tag to this session"}),be(lt,{color:w,children:" esc cancel \xB7 enter save"})]}):be(ss,{children:be(lt,{color:w,children:"\u2191\u2193 nav \xB7 / filter \xB7 enter view \xB7 a alias \xB7 t tag \xB7 s sort \xB7 g group \xB7 n bundle \xB7 o browser \xB7 ? help \xB7 q quit"})})}var Nu=N(()=>{"use strict";it()});import{Box as ge,Text as F}from"ink";import{jsx as $,jsxs as Se}from"react/jsx-runtime";function Cu({width:e,height:t}){return Se(ge,{flexDirection:"column",width:e,height:t,borderStyle:"round",borderColor:G,paddingX:2,paddingY:1,children:[Se(ge,{children:[$(F,{color:G,bold:!0,children:"Claude Recall TUI \u2014 Help"}),$(F,{color:w,children:" \xB7 press ? or esc to close"})]}),Se(ge,{marginTop:1,flexDirection:"column",children:[$(F,{color:Z,bold:!0,children:"Navigation"}),ew.map(s=>$(fo,{row:s},s.key))]}),Se(ge,{marginTop:1,flexDirection:"column",children:[$(F,{color:Z,bold:!0,children:"Actions on the selected session"}),tw.map(s=>$(fo,{row:s},s.key))]}),Se(ge,{marginTop:1,flexDirection:"column",children:[$(F,{color:Z,bold:!0,children:"Right-pane views"}),sw.map(s=>$(fo,{row:s},s.key))]}),Se(ge,{marginTop:1,flexDirection:"column",children:[$(F,{color:Z,bold:!0,children:"What is Neighborhood?"}),$(F,{color:w,wrap:"wrap",children:"Neighborhood assembles a ranked, token-budgeted bundle of context around the selected session: its parent and child sessions, citations (sessions it referenced), similar sessions (by embedding), and any related bug-pattern matches. Press `n` in the TUI to preview it on the right."})]}),Se(ge,{marginTop:1,flexDirection:"column",children:[$(F,{color:Z,bold:!0,children:"Maintenance & diagnostics"}),$(F,{color:w,wrap:"wrap",children:"Two commands cover everything. Quit the TUI with `q` first, then:"}),Se(ge,{marginTop:1,children:[$(F,{color:w,children:" \u2022 "}),$(F,{children:"recall doctor"})]}),$(F,{color:w,wrap:"wrap",children:" Health report: DB size, WAL, FTS fragmentation, integrity, disk free."}),$(F,{color:w,wrap:"wrap",children:" Run this first if anything feels slow or wrong. Add --json for machine output."}),Se(ge,{marginTop:1,children:[$(F,{color:w,children:" \u2022 "}),$(F,{children:"recall optimize"})]}),$(F,{color:w,wrap:"wrap",children:" Maintenance: WAL truncate + FTS5 merge + planner stats. Safe while daemon is running."}),$(F,{color:w,wrap:"wrap",children:" Add --vacuum (with daemon stopped) to also reclaim disk pages from deleted rows."})]}),Se(ge,{marginTop:1,flexDirection:"column",children:[$(F,{color:Z,bold:!0,children:"How to pipe a session into Claude"}),$(F,{color:w,wrap:"wrap",children:"Two recipes. Both work in any shell \u2014 exit this TUI with `q` first, then run them."}),Se(ge,{marginTop:1,children:[$(F,{color:w,children:" 1. "}),$(F,{children:"recall context <id> | claude"})]}),$(F,{color:w,wrap:"wrap",children:" Pipes one session's full transcript as markdown into a fresh `claude` chat."}),$(F,{color:w,wrap:"wrap",children:" Use when you want to continue exactly where one session left off."}),Se(ge,{marginTop:1,children:[$(F,{color:w,children:" 2. "}),$(F,{children:"recall neighborhood <id> | claude"})]}),$(F,{color:w,wrap:"wrap",children:" Pipes the bundle (parents + children + citations + similar + bug matches)."}),$(F,{color:w,wrap:"wrap",children:" Use when you want broader context, not just one transcript."})]})]})}function fo({row:e}){return Se(ge,{children:[$(ge,{width:16,children:$(F,{color:G,children:e.key})}),$(F,{color:w,wrap:"truncate-end",children:e.description})]})}var ew,tw,sw,Lu=N(()=>{"use strict";it();ew=[{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"}],tw=[{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)"}],sw=[{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 nw,useMemo as rw,useState as un}from"react";import{existsSync as ow}from"node:fs";function Ou(e){let[t,s]=un([]),[n,r]=un(!0),[o,i]=un(null),[a,l]=un(!0);return nw(()=>{if(!ow(te)){l(!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:Sw})}function ju(e){let[t,s]=bo([]),[n,r]=bo(!1),[o,i]=bo(!1);return bw(()=>{if(!e){s([]),i(!1);return}r(!0);try{let a=_(),l=$u(a,e,!1),c=!1;l.length===0&&(l=$u(a,e,!0),c=l.length>0),s([...l].reverse()),i(c)}catch{s([]),i(!1)}finally{r(!1)}},[e]),{messages:t,loading:n,fallbackToSidechain:o}}var Sw,Pu=L(()=>{"use strict";w();Sw=6});import{Box as $e,Text as Ue}from"ink";import{Fragment as Rw,jsx as V,jsxs as It}from"react/jsx-runtime";function Tw(e){let t=(e.role??"").toLowerCase();return t==="user"?{label:"user",color:ku}:t==="assistant"?{label:"asst",color:Nu}:t==="tool"?{label:"tool",color:Lu}:t==="system"?{label:"sys ",color:R}:e.type==="summary"?{label:"sum ",color:R}:{label:"----",color:R}}function yw(e,t){return e?e.replace(/\s+/g," ").trim().slice(0,t+1).replace(/.{1}$/,s=>e.length>t?"\u2026":s):"(empty)"}function Fu({session:e,width:t,height:s}){let n=e?.id??null,{messages:r,loading:o,fallbackToSidechain:i}=ju(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?It($e,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:R,children:[It($e,{paddingX:1,flexDirection:"column",children:[V($e,{width:a,children:V(Ue,{color:G,bold:!0,wrap:"truncate-end",children:e.alias||e.auto_title||e.first_user_message||"(no title)"})}),V($e,{width:a,children:V(Ue,{color:R,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(Ue,{color:R,children:"loading messages\u2026"}):r.length===0?V(Ue,{color:R,children:"no messages indexed for this session."}):It(Rw,{children:[i?V(Ue,{color:R,children:"(showing sidechain / subagent messages)"}):null,r.map(m=>V(ww,{message:m,width:a,perMessageLines:u},m.uuid))]})})]}):It($e,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:R,children:[V($e,{paddingX:1,children:V(Ue,{color:G,bold:!0,children:"Preview"})}),V($e,{paddingX:1,paddingY:1,children:V(Ue,{color:R,children:"Select a session on the left to preview."})})]})}function ww({message:e,width:t,perMessageLines:s}){let n=Tw(e),r=Math.max(1,s-1),o=Math.max(20,t-2),i=r*o,a=yw(e.content_text,i);return It($e,{flexDirection:"column",marginBottom:0,children:[It($e,{children:[V(Ue,{color:n.color,bold:!0,children:n.label}),V(Ue,{color:R,children:` ${e.timestamp?W(e.timestamp):""}`})]}),V($e,{width:t,children:V(Ue,{wrap:"truncate-end",children:a})})]})}var Uu=L(()=>{"use strict";v();Pu();it()});import{useMemo as xw}from"react";import{Box as je,Text as ct}from"ink";import{jsx as pe,jsxs as ss}from"react/jsx-runtime";function kw(e,t){try{return{ok:!0,result:Hs(e,{budget:t})}}catch(s){return{ok:!1,error:s instanceof Error?s.message:String(s)}}}function Bu({session:e,width:t,height:s,budget:n}){let r=xw(()=>e?kw(e.id,n):null,[e?.id,n]),o=Math.max(20,t-2),a=Math.max(4,s-2-2);if(!e)return ss(je,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:R,children:[pe(je,{paddingX:1,children:pe(ct,{color:G,bold:!0,children:"Neighborhood"})}),pe(je,{paddingX:1,paddingY:1,children:pe(ct,{color:R,children:"Select a session and press `n` to assemble its neighborhood."})})]});if(!r)return null;if(!r.ok)return ss(je,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:De,children:[pe(je,{paddingX:1,children:pe(ct,{color:De,bold:!0,children:"Neighborhood error"})}),pe(je,{paddingX:1,paddingY:1,children:pe(ct,{color:De,children:r.error})})]});let{result:l}=r,c=l.bundle.replace(/\n+$/,"").split(`
795
+ `),u=c.slice(0,Math.max(1,a-1)),m=c.length-u.length;return ss(je,{flexDirection:"column",width:t,height:s,borderStyle:"round",borderColor:Q,children:[ss(je,{paddingX:1,flexDirection:"column",children:[pe(je,{width:o,children:pe(ct,{color:Q,bold:!0,wrap:"truncate-end",children:"Neighborhood"})}),pe(je,{width:o,children:pe(ct,{color:R,wrap:"truncate-end",children:`budget=${n} used=${l.budgetUsed} remaining=${l.budgetRemaining} truncated=${l.truncated.length}`})})]}),ss(je,{flexDirection:"column",paddingX:1,flexGrow:1,children:[u.map((p,f)=>pe(ct,{wrap:"truncate-end",children:p||" "},f)),m>0?pe(ct,{color:R,children:`\u2026 ${m} more line${m===1?"":"s"} (resize the terminal or use \`recall neighborhood ${e.id.slice(0,8)}\` for the full bundle)`}):null]})]})}var Hu=L(()=>{"use strict";Ar();it()});import{useEffect as Nw,useState as Wu}from"react";import{Box as ns,Text as lt}from"ink";import So from"ink-text-input";import{jsx as be,jsxs as To}from"react/jsx-runtime";function Xu({mode:e,query:t,onQueryChange:s,onSearchSubmit:n,onAliasSubmit:r,onTagSubmit:o,aliasInitial:i,toast:a}){let[l,c]=Wu(""),[u,m]=Wu("");return Nw(()=>{e==="alias"&&c(i),e==="tag"&&m("")},[e,i]),a&&e==="normal"?be(ns,{children:be(lt,{color:De,children:`\u25B6 ${a}`})}):e==="search"?To(ns,{children:[be(lt,{color:G,bold:!0,children:"/ "}),be(So,{value:t,onChange:s,onSubmit:n,placeholder:"filter sessions by project, alias, or opening message..."}),be(lt,{color:R,children:" esc clear \xB7 enter confirm"})]}):e==="alias"?To(ns,{children:[be(lt,{color:Q,bold:!0,children:"alias \u203A "}),be(So,{value:l,onChange:c,onSubmit:p=>r(p),placeholder:"terminal-tab name for this session"}),be(lt,{color:R,children:" esc cancel \xB7 enter save"})]}):e==="tag"?To(ns,{children:[be(lt,{color:Q,bold:!0,children:"tag \u203A "}),be(So,{value:u,onChange:m,onSubmit:p=>o(p),placeholder:"add a tag to this session"}),be(lt,{color:R,children:" esc cancel \xB7 enter save"})]}):be(ns,{children:be(lt,{color:R,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 Ju=L(()=>{"use strict";it()});import{Box as ge,Text as F}from"ink";import{jsx as D,jsxs as Se}from"react/jsx-runtime";function Gu({width:e,height:t}){return Se(ge,{flexDirection:"column",width:e,height:t,borderStyle:"round",borderColor:G,paddingX:2,paddingY:1,children:[Se(ge,{children:[D(F,{color:G,bold:!0,children:"Claude Recall TUI \u2014 Help"}),D(F,{color:R,children:" \xB7 press ? or esc to close"})]}),Se(ge,{marginTop:1,flexDirection:"column",children:[D(F,{color:Q,bold:!0,children:"Navigation"}),Lw.map(s=>D(yo,{row:s},s.key))]}),Se(ge,{marginTop:1,flexDirection:"column",children:[D(F,{color:Q,bold:!0,children:"Actions on the selected session"}),Cw.map(s=>D(yo,{row:s},s.key))]}),Se(ge,{marginTop:1,flexDirection:"column",children:[D(F,{color:Q,bold:!0,children:"Right-pane views"}),Aw.map(s=>D(yo,{row:s},s.key))]}),Se(ge,{marginTop:1,flexDirection:"column",children:[D(F,{color:Q,bold:!0,children:"What is Neighborhood?"}),D(F,{color:R,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."})]}),Se(ge,{marginTop:1,flexDirection:"column",children:[D(F,{color:Q,bold:!0,children:"Maintenance & diagnostics"}),D(F,{color:R,wrap:"wrap",children:"Two commands cover everything. Quit the TUI with `q` first, then:"}),Se(ge,{marginTop:1,children:[D(F,{color:R,children:" \u2022 "}),D(F,{children:"recall doctor"})]}),D(F,{color:R,wrap:"wrap",children:" Health report: DB size, WAL, FTS fragmentation, integrity, disk free."}),D(F,{color:R,wrap:"wrap",children:" Run this first if anything feels slow or wrong. Add --json for machine output."}),Se(ge,{marginTop:1,children:[D(F,{color:R,children:" \u2022 "}),D(F,{children:"recall optimize"})]}),D(F,{color:R,wrap:"wrap",children:" Maintenance: WAL truncate + FTS5 merge + planner stats. Safe while daemon is running."}),D(F,{color:R,wrap:"wrap",children:" Add --vacuum (with daemon stopped) to also reclaim disk pages from deleted rows."})]}),Se(ge,{marginTop:1,flexDirection:"column",children:[D(F,{color:Q,bold:!0,children:"How to pipe a session into Claude"}),D(F,{color:R,wrap:"wrap",children:"Two recipes. Both work in any shell \u2014 exit this TUI with `q` first, then run them."}),Se(ge,{marginTop:1,children:[D(F,{color:R,children:" 1. "}),D(F,{children:"recall context <id> | claude"})]}),D(F,{color:R,wrap:"wrap",children:" Pipes one session's full transcript as markdown into a fresh `claude` chat."}),D(F,{color:R,wrap:"wrap",children:" Use when you want to continue exactly where one session left off."}),Se(ge,{marginTop:1,children:[D(F,{color:R,children:" 2. "}),D(F,{children:"recall neighborhood <id> | claude"})]}),D(F,{color:R,wrap:"wrap",children:" Pipes the bundle (parents + children + citations + similar + bug matches)."}),D(F,{color:R,wrap:"wrap",children:" Use when you want broader context, not just one transcript."})]})]})}function yo({row:e}){return Se(ge,{children:[D(ge,{width:16,children:D(F,{color:G,children:e.key})}),D(F,{color:R,wrap:"truncate-end",children:e.description})]})}var Lw,Cw,Aw,Yu=L(()=>{"use strict";it();Lw=[{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"}],Cw=[{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)"}],Aw=[{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 Ow,useMemo as vw,useState as _n}from"react";import{existsSync as Iw}from"node:fs";function zu(e){let[t,s]=_n([]),[n,r]=_n(!0),[o,i]=_n(null),[a,l]=_n(!0);return Ow(()=>{if(!Iw(te)){l(!1),r(!1);return}try{let m=_().prepare(`SELECT s.id, p.name AS project_name, s.started_at,
746
796
  s.message_count, s.first_user_message,
747
797
  NULLIF(sa.alias, '') AS alias,
748
798
  s.auto_title
@@ -754,23 +804,23 @@ ${t.message}
754
804
  AND COALESCE(s.auto_title, '') NOT LIKE '[output-index]%'
755
805
  AND COALESCE(s.auto_title, '') NOT LIKE '[skill]%'
756
806
  ORDER BY COALESCE(s.started_at, '') DESC
757
- LIMIT @limit`).all({limit:iw});s(p)}catch(u){i(u instanceof Error?u.message:String(u))}finally{r(!1)}},[]),{sessions:rw(()=>{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 iw,Au=N(()=>{"use strict";T();j();iw=200});import{useEffect as _o,useMemo as aw,useState as Ue}from"react";import{Box as dt,Text as pn,useApp as cw,useInput as lw}from"ink";import{spawn as dw}from"node:child_process";import{platform as mn}from"node:os";import{jsx as ie,jsxs as Eo}from"react/jsx-runtime";function vu(){return{cols:process.stdout.columns??100,rows:process.stdout.rows??30}}function fw(e){let t=mn()==="darwin"?"open":mn()==="win32"?"start":"xdg-open",s=mn()==="win32"?["",e]:[e];dw(t,s,{detached:!0,stdio:"ignore",shell:mn()==="win32"}).unref()}function Mu({onShowSession:e}){let{exit:t}=cw(),s=vu(),[n,r]=Ue(s.cols),[o,i]=Ue(s.rows),[a,l]=Ue(0),[c,u]=Ue(""),[p,m]=Ue("normal"),[f,g]=Ue(null),[h,E]=Ue("preview"),[b,S]=Ue("recent"),[C,R]=Ue(!1),[L,Q]=Ue(!1),{sessions:v,total:ee,loading:B,error:y,dbExists:U}=Ou(c),M=aw(()=>{if(v.length===0)return v;let D=new Map;if(b==="busiest"||C)for(let O of v)D.set(O.project_name,(D.get(O.project_name)??0)+1);let X=[...v];if(b==="longest"?X.sort((O,J)=>(J.message_count??0)-(O.message_count??0)):b==="busiest"&&X.sort((O,J)=>{let Re=D.get(O.project_name)??0,ke=D.get(J.project_name)??0;return ke!==Re?ke-Re:(J.started_at??"").localeCompare(O.started_at??"")}),C){let O=new Map;for(let ke of X){let He=O.get(ke.project_name);He||(He=[],O.set(ke.project_name,He)),He.push(ke)}let J=Array.from(O.keys()).sort((ke,He)=>{if(b==="busiest"){let wo=D.get(ke)??0,xo=D.get(He)??0;if(xo!==wo)return xo-wo}return ke.localeCompare(He)}),Re=[];for(let ke of J)for(let He of O.get(ke)??[])Re.push(He);return Re}return X},[v,b,C]);_o(()=>{let D=()=>{let X=vu();r(X.cols),i(X.rows)};return process.stdout.on("resize",D),()=>{process.stdout.off("resize",D)}},[]),_o(()=>{if(M.length===0){a!==0&&l(0);return}a>=M.length&&l(M.length-1)},[M.length,a]),_o(()=>{if(!f)return;let D=setTimeout(()=>g(null),2500);return()=>clearTimeout(D)},[f]),lw((D,X)=>{if(p==="search"){X.escape&&(m("normal"),u(""));return}if(p==="alias"||p==="tag"){X.escape&&m("normal");return}if(L){(D==="?"||X.escape||D==="q")&&Q(!1);return}if(D==="q"||X.ctrl&&D==="c"){t();return}if(D==="?"){Q(!0);return}if(!(M.length===0&&D!=="/")){if(X.upArrow||D==="k"){l(O=>Math.max(0,O-1));return}if(X.downArrow||D==="j"){l(O=>Math.min(M.length-1,O+1));return}if(X.pageUp){l(O=>Math.max(0,O-10));return}if(X.pageDown){l(O=>Math.min(M.length-1,O+10));return}if(X.return){let O=M[a];O&&(e(O.id),t());return}if(D==="o"){let O=M[a];if(!O)return;let J=K();if(!J){g("start the daemon first (`recall start`)");return}let Re=`http://127.0.0.1:${J.port}/sessions/${O.id}`;fw(Re),g(`opened ${Re}`);return}if(D==="n"){E(J=>J==="neighborhood"?"preview":"neighborhood");let O=M[a];O&&g(h==="neighborhood"?"preview view":`neighborhood for ${O.id.slice(0,8)}`);return}if(D==="/"){m("search");return}if(D==="a"){M[a]&&m("alias");return}if(D==="t"){M[a]&&m("tag");return}if(D==="s"){S(O=>{let J=ho.indexOf(O),Re=ho[(J+1)%ho.length];return g(`sort: ${_w[Re]}`),Re});return}if(D==="g"){R(O=>(g(O?"flat view":"grouped by project"),!O));return}}});function q(D){m("normal");let X=M[a];if(!X)return;let O=D.trim();if(!O){g("alias unchanged (empty input)");return}try{ys(X.id,O),g(`alias set: ${O}`)}catch(J){g(`alias failed: ${J instanceof Error?J.message:"unknown"}`)}}function Be(D){m("normal");let X=M[a];if(!X)return;let O=D.trim();if(!O){g("tag unchanged (empty input)");return}try{let J=la(X.id,O);g(J.added?`tag added: ${J.tag}`:`tag exists: ${J.tag}`)}catch(J){g(`tag failed: ${J instanceof Error?J.message:"unknown"}`)}}if(n<lo||o<uo)return Eo(dt,{flexDirection:"column",padding:1,children:[ie(pn,{color:Me,children:"Terminal too small."}),ie(pn,{color:w,children:`Resize to at least ${lo} cols x ${uo} rows. Current: ${n} x ${o}.`}),ie(pn,{color:w,children:"Press q to quit."})]});let je=Math.max(10,o-gw-Iu),ut=Math.max(36,Math.floor(n*.4)),To=n-ut-1,fn=M[a]??null;return Eo(dt,{flexDirection:"column",width:n,height:o,children:[ie(mu,{cols:n}),ie(dt,{height:1}),y?ie(dt,{paddingX:1,children:ie(pn,{color:Me,children:`Error loading sessions: ${y}`})}):L?ie(dt,{height:je,children:ie(Cu,{width:n,height:je})}):Eo(dt,{flexDirection:"row",height:je,children:[ie(_u,{sessions:M,total:ee,selected:a,width:ut,height:je,loading:B,dbExists:U,filter:c,sortMode:b,groupByProject:C}),ie(dt,{width:1,height:je}),h==="neighborhood"?ie(wu,{session:fn,width:To,height:je,budget:4e3}):ie(yu,{session:fn,width:To,height:je})]}),ie(dt,{height:Iu,width:n,paddingX:1,children:ie(ku,{mode:p,query:c,onQueryChange:u,onSearchSubmit:()=>m("normal"),onAliasSubmit:q,onTagSubmit:Be,aliasInitial:fn?.alias??"",toast:f})})]})}var uw,pw,mw,Iu,gw,ho,_w,$u=N(()=>{"use strict";fu();hu();Tu();xu();Nu();Lu();Au();We();Ft();Zn();it();uw=4,pw=1,mw=1,Iu=1,gw=uw+pw+mw,ho=["recent","longest","busiest"];_w={recent:"most recent first",longest:"longest sessions first",busiest:"busiest project first"}});import{render as hw}from"ink";import{jsx as Ew}from"react/jsx-runtime";async function Du(){let e={showSessionId:null};return await hw(Ew(Mu,{onShowSession:n=>{e.showSessionId=n}})).waitUntilExit(),e}var ju=N(()=>{"use strict";$u()});var Pu={};fe(Pu,{runTui:()=>Sw});import{spawn as bw}from"node:child_process";async function Sw(){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 Du();if(!e.showSessionId)return;let t=process.argv[1];t&&await new Promise(s=>{let n=bw(process.execPath,[t,"show",e.showSessionId],{stdio:"inherit"});n.on("exit",()=>s()),n.on("error",()=>s())})}var Fu=N(()=>{"use strict";ju()});var Uu={};fe(Uu,{findSimilarSessions:()=>Tw,vectorSearch:()=>yw});async function yw(e,t=50){let s=await or(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:Mw});s(m)}catch(u){i(u instanceof Error?u.message:String(u))}finally{r(!1)}},[]),{sessions:vw(()=>{let u=e.trim().toLowerCase();return u?t.filter(m=>{let p=m.project_name?.toLowerCase()??"",f=m.first_user_message?.toLowerCase()??"";return p.includes(u)||f.includes(u)}):t},[t,e]),total:t.length,loading:n,error:o,dbExists:a}}var Mw,qu=L(()=>{"use strict";w();P();Mw=200});import{useEffect as wo,useMemo as Dw,useState as Be}from"react";import{Box as dt,Text as hn,useApp as $w,useInput as jw}from"ink";import{spawn as Pw}from"node:child_process";import{platform as En}from"node:os";import{jsx as ie,jsxs as xo}from"react/jsx-runtime";function Vu(){return{cols:process.stdout.columns??100,rows:process.stdout.rows??30}}function Ww(e){let t=En()==="darwin"?"open":En()==="win32"?"start":"xdg-open",s=En()==="win32"?["",e]:[e];Pw(t,s,{detached:!0,stdio:"ignore",shell:En()==="win32"}).unref()}function Zu({onShowSession:e}){let{exit:t}=$w(),s=Vu(),[n,r]=Be(s.cols),[o,i]=Be(s.rows),[a,l]=Be(0),[c,u]=Be(""),[m,p]=Be("normal"),[f,g]=Be(null),[h,E]=Be("preview"),[b,S]=Be("recent"),[N,y]=Be(!1),[C,q]=Be(!1),{sessions:I,total:ee,loading:B,error:T,dbExists:U}=zu(c),M=Dw(()=>{if(I.length===0)return I;let $=new Map;if(b==="busiest"||N)for(let A of I)$.set(A.project_name,($.get(A.project_name)??0)+1);let X=[...I];if(b==="longest"?X.sort((A,J)=>(J.message_count??0)-(A.message_count??0)):b==="busiest"&&X.sort((A,J)=>{let xe=$.get(A.project_name)??0,ke=$.get(J.project_name)??0;return ke!==xe?ke-xe:(J.started_at??"").localeCompare(A.started_at??"")}),N){let A=new Map;for(let ke of X){let We=A.get(ke.project_name);We||(We=[],A.set(ke.project_name,We)),We.push(ke)}let J=Array.from(A.keys()).sort((ke,We)=>{if(b==="busiest"){let Co=$.get(ke)??0,Ao=$.get(We)??0;if(Ao!==Co)return Ao-Co}return ke.localeCompare(We)}),xe=[];for(let ke of J)for(let We of A.get(ke)??[])xe.push(We);return xe}return X},[I,b,N]);wo(()=>{let $=()=>{let X=Vu();r(X.cols),i(X.rows)};return process.stdout.on("resize",$),()=>{process.stdout.off("resize",$)}},[]),wo(()=>{if(M.length===0){a!==0&&l(0);return}a>=M.length&&l(M.length-1)},[M.length,a]),wo(()=>{if(!f)return;let $=setTimeout(()=>g(null),2500);return()=>clearTimeout($)},[f]),jw(($,X)=>{if(m==="search"){X.escape&&(p("normal"),u(""));return}if(m==="alias"||m==="tag"){X.escape&&p("normal");return}if(C){($==="?"||X.escape||$==="q")&&q(!1);return}if($==="q"||X.ctrl&&$==="c"){t();return}if($==="?"){q(!0);return}if(!(M.length===0&&$!=="/")){if(X.upArrow||$==="k"){l(A=>Math.max(0,A-1));return}if(X.downArrow||$==="j"){l(A=>Math.min(M.length-1,A+1));return}if(X.pageUp){l(A=>Math.max(0,A-10));return}if(X.pageDown){l(A=>Math.min(M.length-1,A+10));return}if(X.return){let A=M[a];A&&(e(A.id),t());return}if($==="o"){let A=M[a];if(!A)return;let J=Z();if(!J){g("start the daemon first (`recall start`)");return}let xe=`http://127.0.0.1:${J.port}/sessions/${A.id}`;Ww(xe),g(`opened ${xe}`);return}if($==="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($==="/"){p("search");return}if($==="a"){M[a]&&p("alias");return}if($==="t"){M[a]&&p("tag");return}if($==="s"){S(A=>{let J=Ro.indexOf(A),xe=Ro[(J+1)%Ro.length];return g(`sort: ${Xw[xe]}`),xe});return}if($==="g"){y(A=>(g(A?"flat view":"grouped by project"),!A));return}}});function K($){p("normal");let X=M[a];if(!X)return;let A=$.trim();if(!A){g("alias unchanged (empty input)");return}try{ws(X.id,A),g(`alias set: ${A}`)}catch(J){g(`alias failed: ${J instanceof Error?J.message:"unknown"}`)}}function He($){p("normal");let X=M[a];if(!X)return;let A=$.trim();if(!A){g("tag unchanged (empty input)");return}try{let J=_a(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<ho||o<Eo)return xo(dt,{flexDirection:"column",padding:1,children:[ie(hn,{color:De,children:"Terminal too small."}),ie(hn,{color:R,children:`Resize to at least ${ho} cols x ${Eo} rows. Current: ${n} x ${o}.`}),ie(hn,{color:R,children:"Press q to quit."})]});let Pe=Math.max(10,o-Hw-Ku),ut=Math.max(36,Math.floor(n*.4)),Lo=n-ut-1,Sn=M[a]??null;return xo(dt,{flexDirection:"column",width:n,height:o,children:[ie(Ou,{cols:n}),ie(dt,{height:1}),T?ie(dt,{paddingX:1,children:ie(hn,{color:De,children:`Error loading sessions: ${T}`})}):C?ie(dt,{height:Pe,children:ie(Gu,{width:n,height:Pe})}):xo(dt,{flexDirection:"row",height:Pe,children:[ie(Mu,{sessions:M,total:ee,selected:a,width:ut,height:Pe,loading:B,dbExists:U,filter:c,sortMode:b,groupByProject:N}),ie(dt,{width:1,height:Pe}),h==="neighborhood"?ie(Bu,{session:Sn,width:Lo,height:Pe,budget:4e3}):ie(Fu,{session:Sn,width:Lo,height:Pe})]}),ie(dt,{height:Ku,width:n,paddingX:1,children:ie(Xu,{mode:m,query:c,onQueryChange:u,onSearchSubmit:()=>p("normal"),onAliasSubmit:K,onTagSubmit:He,aliasInitial:Sn?.alias??"",toast:f})})]})}var Fw,Uw,Bw,Ku,Hw,Ro,Xw,Qu=L(()=>{"use strict";Iu();Du();Uu();Hu();Ju();Yu();qu();Xe();Ut();nr();it();Fw=4,Uw=1,Bw=1,Ku=1,Hw=Fw+Uw+Bw,Ro=["recent","longest","busiest"];Xw={recent:"most recent first",longest:"longest sessions first",busiest:"busiest project first"}});import{render as Jw}from"ink";import{jsx as Gw}from"react/jsx-runtime";async function em(){let e={showSessionId:null};return await Jw(Gw(Zu,{onShowSession:n=>{e.showSessionId=n}})).waitUntilExit(),e}var tm=L(()=>{"use strict";Qu()});var sm={};fe(sm,{runTui:()=>zw});import{spawn as Yw}from"node:child_process";async function zw(){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 em();if(!e.showSessionId)return;let t=process.argv[1];t&&await new Promise(s=>{let n=Yw(process.execPath,[t,"show",e.showSessionId],{stdio:"inherit"});n.on("exit",()=>s()),n.on("error",()=>s())})}var nm=L(()=>{"use strict";tm()});var rm={};fe(rm,{findSimilarSessions:()=>Kw,vectorSearch:()=>qw});async function qw(e,t=50){let s=await dr(e),n=_(),r=Buffer.from(s.buffer,s.byteOffset,s.byteLength);return n.prepare(`SELECT v.rowid, v.distance, cm.session_id, cm.text, cm.message_uuids
758
808
  FROM vec_chunks v JOIN chunk_meta cm ON cm.rowid = v.rowid
759
- WHERE v.embedding MATCH ? AND k = ? ORDER BY v.distance`).all(r,t).map(i=>({sessionId:i.session_id,chunkRowid:i.rowid,distance:i.distance,text:i.text,messageUuids:JSON.parse(i.message_uuids)}))}async function Tw(e,t=10,s=.65){let n=_(),r=n.prepare("SELECT rowid FROM chunk_meta WHERE session_id = ? ORDER BY rowid LIMIT 1").get(e);if(!r)return[];let o=n.prepare("SELECT embedding FROM vec_chunks WHERE rowid = ?").get(r.rowid);if(!o)return[];let i=n.prepare(`SELECT v.rowid, v.distance, cm.session_id FROM vec_chunks v JOIN chunk_meta cm ON cm.rowid = v.rowid
760
- WHERE v.embedding MATCH ? AND k = ? ORDER BY v.distance`).all(o.embedding,t*5),a=new Map;for(let c of i){if(c.session_id===e)continue;let u=a.get(c.session_id);(u===void 0||c.distance<u)&&a.set(c.session_id,c.distance)}let l=[];for(let[c,u]of a){let p=1-u;p>=s&&l.push({sessionId:c,similarity:p})}return l.sort((c,u)=>u.similarity-c.similarity),l.slice(0,t)}var Bu=N(()=>{"use strict";T();Ve()});import{createRequire as ww}from"module";import{Command as xw}from"commander";T();j();import{basename as Wp}from"node:path";import{createReadStream as ip}from"node:fs";import{createInterface as ap}from"node:readline";function os(e){return typeof e=="number"&&Number.isFinite(e)?e:0}function wn(e){let t=e?.usage;if(!t||typeof t!="object")return null;let s={inputTokens:os(t.input_tokens),outputTokens:os(t.output_tokens),cacheCreateTokens:os(t.cache_creation_input_tokens),cacheReadTokens:os(t.cache_read_input_tokens)};return s.inputTokens===0&&s.outputTokens===0&&s.cacheCreateTokens===0&&s.cacheReadTokens===0?null:s}var cp=/\x1B\[[0-9;]*[a-zA-Z]/g;function yn(e){return e.replace(cp,"")}var Tn=12e3;function Mo(e,t){if(e.length<=Tn)return e;let s=e.slice(0,Tn),n=e.length-Tn;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 Kw(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 l=[];for(let[c,u]of a){let m=1-u;m>=s&&l.push({sessionId:c,similarity:m})}return l.sort((c,u)=>u.similarity-c.similarity),l.slice(0,t)}var om=L(()=>{"use strict";w();Ve()});import{createRequire as Vw}from"module";import{Command as Zw}from"commander";w();P();import{basename as ap}from"node:path";import{createReadStream as Rm}from"node:fs";import{createInterface as xm}from"node:readline";function as(e){return typeof e=="number"&&Number.isFinite(e)?e:0}function Ln(e){let t=e?.usage;if(!t||typeof t!="object")return null;let s={inputTokens:as(t.input_tokens),outputTokens:as(t.output_tokens),cacheCreateTokens:as(t.cache_creation_input_tokens),cacheReadTokens:as(t.cache_read_input_tokens)};return s.inputTokens===0&&s.outputTokens===0&&s.cacheCreateTokens===0&&s.cacheReadTokens===0?null:s}var km=/\x1B\[[0-9;]*[a-zA-Z]/g;function kn(e){return e.replace(km,"")}var Nn=12e3;function Uo(e,t){if(e.length<=Nn)return e;let s=e.slice(0,Nn),n=e.length-Nn;return`${s}
761
811
 
762
- \u27E8\u2026 ${n.toLocaleString()} more chars in ${t}; see raw JSONL for full content \u27E9`}function lp(e){try{return JSON.stringify(e,null,2)}catch{return String(e)}}function dp(e){if(typeof e.content=="string")return e.content;if(Array.isArray(e.content)){let t=[];for(let s of e.content)if(s&&typeof s=="object"){let n=s;n.type==="text"&&typeof n.text=="string"?t.push(n.text):n.type==="image"&&t.push("[image]")}return t.join(`
763
- `)}return""}function up(e){if(!e)return{text:"",toolNames:[]};if(typeof e.content=="string")return{text:yn(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(yn(n.text));continue}if(n.type==="tool_use"&&typeof n.name=="string"){s.push(n.name);let r=n.input!=null?lp(n.input):"",o=Mo(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 Nm(e){try{return JSON.stringify(e,null,2)}catch{return String(e)}}function Lm(e){if(typeof e.content=="string")return e.content;if(Array.isArray(e.content)){let t=[];for(let s of e.content)if(s&&typeof s=="object"){let n=s;n.type==="text"&&typeof n.text=="string"?t.push(n.text):n.type==="image"&&t.push("[image]")}return t.join(`
813
+ `)}return""}function Cm(e){if(!e)return{text:"",toolNames:[]};if(typeof e.content=="string")return{text:kn(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(kn(n.text));continue}if(n.type==="tool_use"&&typeof n.name=="string"){s.push(n.name);let r=n.input!=null?Nm(n.input):"",o=Uo(r,"tool input");t.push(`\u26A1 **Tool call \xB7 \`${n.name}\`**
764
814
 
765
815
  \`\`\`json
766
816
  ${o}
767
- \`\`\``);continue}if(n.type==="tool_result"){let r=yn(dp(n));if(r){let o=Mo(r,"tool result");t.push(`**Tool result**
817
+ \`\`\``);continue}if(n.type==="tool_result"){let r=kn(Lm(n));if(r){let o=Uo(r,"tool result");t.push(`**Tool result**
768
818
 
769
819
  \`\`\`
770
820
  ${o}
771
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(`
772
822
 
773
- `),toolNames:s}}async function*$o(e){let t=ip(e,{encoding:"utf8"}),s=ap({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}=up(r.message);yield{uuid:r.uuid,parentUuid:r.parentUuid??null,sessionId:r.sessionId,type:r.type??"unknown",role:r.message?.role??null,timestamp:r.timestamp??null,isSidechain:r.isSidechain===!0,cwd:r.cwd??null,gitBranch:r.gitBranch??null,version:r.version??null,contentText:o,toolNames:i,raw:n,usage:wn(r.message),model:r.message?.model??null}}}I();var jo=[{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 Po(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 $t(e){if(!e)return[];let t=new Set,s=[];for(let n of jo){n.regex.lastIndex=0;for(let r of e.matchAll(n.regex)){let o=r[0],i=`${n.name}::${Fo(o)}`;t.has(i)||(t.add(i),s.push({pattern:n.name,maskedPreview:Po(o),offset:r.index??0,severity:n.severity}))}}return s}function Fo(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 qe(e){if(!e)return{redacted:e,count:0};let t=e,s=0,n=new Set;for(let r of jo)r.regex.lastIndex=0,t=t.replace(r.regex,o=>{let i=`${r.name}::${Fo(o)}`;return n.has(i)||(n.add(i),s+=1),`[REDACTED ${r.name}: ${Po(o)}]`});return{redacted:t,count:s}}function Uo(e,t,s){e.prepare("DELETE FROM message_usage WHERE session_id = ?").run(t);let n=e.prepare(`
823
+ `),toolNames:s}}async function*Bo(e){let t=Rm(e,{encoding:"utf8"}),s=xm({input:t,crlfDelay:1/0});for await(let n of s){if(!n.trim())continue;let r;try{r=JSON.parse(n)}catch{continue}if(!r.uuid||!r.sessionId)continue;let{text:o,toolNames:i}=Cm(r.message);yield{uuid:r.uuid,parentUuid:r.parentUuid??null,sessionId:r.sessionId,type:r.type??"unknown",role:r.message?.role??null,timestamp:r.timestamp??null,isSidechain:r.isSidechain===!0,cwd:r.cwd??null,gitBranch:r.gitBranch??null,version:r.version??null,contentText:o,toolNames:i,raw:n,usage:Ln(r.message),model:r.message?.model??null}}}v();var Wo=[{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 Xo(e){if(e.length<=8)return e.slice(0,2)+"\u2022".repeat(Math.max(0,e.length-4))+e.slice(-2);let t=e.slice(0,Math.min(6,Math.floor(e.length/3))),s=e.slice(-Math.min(4,Math.floor(e.length/4)));return`${t}${"\u2022".repeat(Math.max(3,e.length-t.length-s.length))}${s}`}function Dt(e){if(!e)return[];let t=new Set,s=[];for(let n of Wo){n.regex.lastIndex=0;for(let r of e.matchAll(n.regex)){let o=r[0],i=`${n.name}::${Jo(o)}`;t.has(i)||(t.add(i),s.push({pattern:n.name,maskedPreview:Xo(o),offset:r.index??0,severity:n.severity}))}}return s}function Jo(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 Le(e){if(!e)return{redacted:e,count:0};let t=e,s=0,n=new Set;for(let r of Wo)r.regex.lastIndex=0,t=t.replace(r.regex,o=>{let i=`${r.name}::${Jo(o)}`;return n.has(i)||(n.add(i),s+=1),`[REDACTED ${r.name}: ${Xo(o)}]`});return{redacted:t,count:s}}function Go(e,t,s){e.prepare("DELETE FROM message_usage WHERE session_id = ?").run(t);let n=e.prepare(`
774
824
  INSERT INTO message_usage (
775
825
  message_uuid, session_id, model,
776
826
  input_tokens, output_tokens, cache_create_tokens, cache_read_tokens,
@@ -787,7 +837,7 @@ ${o}
787
837
  cache_create_tokens = excluded.cache_create_tokens,
788
838
  cache_read_tokens = excluded.cache_read_tokens,
789
839
  timestamp = excluded.timestamp
790
- `);for(let r of s)r.usage&&r.role==="assistant"&&n.run({uuid:r.uuid,session_id:t,model:r.model,input:r.usage.inputTokens,output:r.usage.outputTokens,cc:r.usage.cacheCreateTokens,cr:r.usage.cacheReadTokens,ts:r.timestamp})}function is(e,t){let s=e.prepare(`SELECT
840
+ `);for(let r of s)r.usage&&r.role==="assistant"&&n.run({uuid:r.uuid,session_id:t,model:r.model,input:r.usage.inputTokens,output:r.usage.outputTokens,cc:r.usage.cacheCreateTokens,cr:r.usage.cacheReadTokens,ts:r.timestamp})}function cs(e,t){let s=e.prepare(`SELECT
791
841
  COALESCE(SUM(input_tokens), 0) AS input_tokens,
792
842
  COALESCE(SUM(output_tokens), 0) AS output_tokens,
793
843
  COALESCE(SUM(cache_create_tokens), 0) AS cache_create_tokens,
@@ -802,17 +852,17 @@ ${o}
802
852
  total_cache_create_tokens = @cc,
803
853
  total_cache_read_tokens = @cr,
804
854
  primary_model = @model
805
- WHERE id = @id`).run({id:t,input:s.input_tokens,output:s.output_tokens,cc:s.cache_create_tokens,cr:s.cache_read_tokens,model:n?.model??null})}T();j();import{writeFileSync as Ep,mkdirSync as bp,existsSync as Sp}from"node:fs";import{join as Wo}from"node:path";T();var gp=[/^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 fp=[/^Score this person'?s relevance/i,/^You are a [^\n.]{1,60}co-pilot/i,/^Return ONLY valid JSON/i],_p=[/^Draft (a|an|marketing) [a-z]/i,/^Read the file at /i,/^Read this and then begin/i,/^read this and then begin/i],hp=20;function Bo(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<hp)return"low_signal";for(let t of gp)if(t.test(e.auto_title))return"recursive_meta";for(let t of fp)if(t.test(e.auto_title))return"programmatic";for(let t of _p)if(t.test(e.auto_title))return"template_pending";return"clean"}function xn(e){if(!e)return"";let t=e.split("|")[0];return t=t.replace(/\s*\([^)]*\)\s*$/,""),t=t.replace(/\s+/g," ").trim(),t}var kn=Wo(x,"titles"),yp=80,Tp=60,wp=100;function xp(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 Xo(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=Rp(t,e);if(s)return s;let n=t.match(/^[^.!?\n]{8,}?[.!?]/)?.[0]?.trim();return(n&&n.length<=yp?n:t.slice(0,Tp)).trim()||null}function Rp(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=Nn(r);return o?Dt(`${n} \xB7 ${o}`):n}for(let n of kp){if(!e.match(n.match))continue;let o=n.prefix,i=n.extract?n.extract(e,t):Nn(t);return i?n.completeFromExtract?Dt(i):Dt(`${o} \xB7 ${i}`):o}for(let n of Lp){if(!e.match(n.match))continue;let o=n.extract?n.extract(e,t):as(t);return o?n.completeFromExtract?Dt(o):Dt(`${n.prefix} \xB7 ${o}`):n.prefix}return null}var kp=[{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=Nn(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)=>Cp(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)=>Np(t)},{match:/^You will receive a sample of user messages from a Claude Code session:/i,prefix:"[meta]",completeFromExtract:!0,extract:(e,t)=>Ho(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)=>Ho(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 Np(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 Ho(e,t){if(!e)return t;let s=e.indexOf("Messages:");if(s===-1)return t;let n=e.slice(s+9),r=/^\s*\d+\.\s*([^\n]+)/gm;for(let o of n.matchAll(r)){let i=o[1]?.trim()??"";if(!i)continue;let a=i.replace(/^<[^>]+>[\s\S]*?<\/[^>]+>\s*/g,"").replace(/^\[Pasted text[^\]]*\]\s*/i,"").trim();if(!a||/^<local-command-/.test(a))continue;let l=a.length>60?a.slice(0,57)+"\u2026":a;return`${t} \xB7 ${l}`}return t}function Cp(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 Lp=[{match:/^Score this person'?s relevance/i,prefix:"Score relevance",extract:(e,t)=>as(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=as(t);return o?`${r} \xB7 ${o}`:r}},{match:/^Return ONLY valid JSON/i,prefix:"JSON-only",extract:(e,t)=>as(t)}];function as(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 xn(r)||r}return null}function Dt(e){return e.slice(0,wp).trim()}var Op=[/^deep research$/i,/^reference(?: spec)?$/i,/^canonical spec/i,/^product context/i,/^services?(?: overview)?$/i,/^overview$/i,/^(?:introduction|template|instructions|context)$/i],Ap=[/^(?: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 Rn(e){let t=e.trim();return t.length<3?!0:Op.some(s=>s.test(t))}function Ip(e){let t=e.trim().replace(/\s*\([^)]*\)\s*$/,"").trim();return Ap.some(s=>s.test(t))}function Nn(e){let t=vp(e);return t===null?null:xn(t)||t}function vp(e){if(/^\s*Skill smoke test\b/i.test(e))return"smoke test";let t=/(^|\n)#{1,3}\s+([^\n]+?)\s+(?:—|–|-|:)\s+([^\n]{2,80})/g,s,n=[];for(;(s=t.exec(e))!==null;){let l=s[2].trim(),c=s[3].trim().replace(/\s+/g," ");if(!Rn(c)){if(Ip(l))return c;n.push(c)}}if(n.length>0)return n[0];let r=e.match(/\b(?:Topic|Subject|Brand|About|Client|For|Re)\s*:\s*([^\n]{2,80})/i);if(r?.[1]&&!Rn(r[1]))return r[1].trim().replace(/\s+/g," ");let o=/===\s*([^=\n]{2,120}?)\s*===/g;for(;(s=o.exec(e))!==null;){let l=s[1].trim().replace(/\.(md|txt|json)$/i,""),c=l.replace(/\s*\([^)]*\)\s*$/,"").trim();if(c&&!Rn(c)&&!/product context|reference/i.test(l))return c}let i=e.replace(/^Context for this run[^:]*:\s*/i,"");if(i!==e){let l=i.split(`
855
+ WHERE id = @id`).run({id:t,input:s.input_tokens,output:s.output_tokens,cc:s.cache_create_tokens,cr:s.cache_read_tokens,model:n?.model??null})}w();P();import{writeFileSync as $m,mkdirSync as jm,existsSync as Pm}from"node:fs";import{join as qo}from"node:path";w();var vm=[/^You will receive a sample of user messages from a Claude Cod/i,/^You will receive the first \d+ user messages from a Claude/i,/^Base directory for this skill:/i,/^You are Claude Code in a fresh terminal/i,/^You are extracting a structured Output Index from a Claude/i];var Im=[/^Score this person'?s relevance/i,/^You are a [^\n.]{1,60}co-pilot/i,/^Return ONLY valid JSON/i],Mm=[/^Draft (a|an|marketing) [a-z]/i,/^Read the file at /i,/^Read this and then begin/i,/^read this and then begin/i],Dm=20;function Yo(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<Dm)return"low_signal";for(let t of vm)if(t.test(e.auto_title))return"recursive_meta";for(let t of Im)if(t.test(e.auto_title))return"programmatic";for(let t of Mm)if(t.test(e.auto_title))return"template_pending";return"clean"}function Cn(e){if(!e)return"";let t=e.split("|")[0];return t=t.replace(/\s*\([^)]*\)\s*$/,""),t=t.replace(/\s+/g," ").trim(),t}var On=qo(x,"titles"),Fm=80,Um=60,Bm=100;function Hm(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 Ko(e){if(!e)return null;let t=e;if(t=t.replace(/```[\s\S]*?```/g," "),t=t.replace(/`[^`]+`/g," "),t=t.replace(/https?:\/\/\S+/g,"[url]"),t=t.replace(/\s+/g," ").trim(),!t)return null;let s=Wm(t,e);if(s)return s;let n=t.match(/^[^.!?\n]{8,}?[.!?]/)?.[0]?.trim();return(n&&n.length<=Fm?n:t.slice(0,Um)).trim()||null}function Wm(e,t){let s=e.match(/^\/([A-Za-z0-9][A-Za-z0-9_-]*)\s+([\s\S]*)$/);if(s){let n=`/${s[1]}`,r=t.replace(/^\s*\/[A-Za-z0-9][A-Za-z0-9_-]*\s+/,""),o=vn(r);return o?$t(`${n} \xB7 ${o}`):n}for(let n of Xm){if(!e.match(n.match))continue;let o=n.prefix,i=n.extract?n.extract(e,t):vn(t);return i?n.completeFromExtract?$t(i):$t(`${o} \xB7 ${i}`):o}for(let n of Ym){if(!e.match(n.match))continue;let o=n.extract?n.extract(e,t):ls(t);return o?n.completeFromExtract?$t(o):$t(`${n.prefix} \xB7 ${o}`):n.prefix}return null}var Xm=[{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=vn(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)=>Jm(t)},{match:/^You will receive a sample of user messages from a Claude Code session:/i,prefix:"[meta]",completeFromExtract:!0,extract:(e,t)=>zo(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)=>zo(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 Jm(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 zo(e,t){if(!e)return t;let s=e.indexOf("Messages:");if(s===-1)return t;let n=e.slice(s+9),r=/^\s*\d+\.\s*([^\n]+)/gm;for(let o of n.matchAll(r)){let i=o[1]?.trim()??"";if(!i)continue;let a=i.replace(/^<[^>]+>[\s\S]*?<\/[^>]+>\s*/g,"").replace(/^\[Pasted text[^\]]*\]\s*/i,"").trim();if(!a||/^<local-command-/.test(a))continue;let l=a.length>60?a.slice(0,57)+"\u2026":a;return`${t} \xB7 ${l}`}return t}function 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 Ym=[{match:/^Score this person'?s relevance/i,prefix:"Score relevance",extract:(e,t)=>ls(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=ls(t);return o?`${r} \xB7 ${o}`:r}},{match:/^Return ONLY valid JSON/i,prefix:"JSON-only",extract:(e,t)=>ls(t)}];function ls(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 Cn(r)||r}return null}function $t(e){return e.slice(0,Bm).trim()}var zm=[/^deep research$/i,/^reference(?: spec)?$/i,/^canonical spec/i,/^product context/i,/^services?(?: overview)?$/i,/^overview$/i,/^(?:introduction|template|instructions|context)$/i],qm=[/^(?: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 An(e){let t=e.trim();return t.length<3?!0:zm.some(s=>s.test(t))}function Km(e){let t=e.trim().replace(/\s*\([^)]*\)\s*$/,"").trim();return qm.some(s=>s.test(t))}function vn(e){let t=Vm(e);return t===null?null:Cn(t)||t}function Vm(e){if(/^\s*Skill smoke test\b/i.test(e))return"smoke test";let t=/(^|\n)#{1,3}\s+([^\n]+?)\s+(?:—|–|-|:)\s+([^\n]{2,80})/g,s,n=[];for(;(s=t.exec(e))!==null;){let l=s[2].trim(),c=s[3].trim().replace(/\s+/g," ");if(!An(c)){if(Km(l))return c;n.push(c)}}if(n.length>0)return n[0];let r=e.match(/\b(?:Topic|Subject|Brand|About|Client|For|Re)\s*:\s*([^\n]{2,80})/i);if(r?.[1]&&!An(r[1]))return r[1].trim().replace(/\s+/g," ");let o=/===\s*([^=\n]{2,120}?)\s*===/g;for(;(s=o.exec(e))!==null;){let l=s[1].trim().replace(/\.(md|txt|json)$/i,""),c=l.replace(/\s*\([^)]*\)\s*$/,"").trim();if(c&&!An(c)&&!/product context|reference/i.test(l))return c}let i=e.replace(/^Context for this run[^:]*:\s*/i,"");if(i!==e){let l=i.split(`
806
856
  `).map(c=>c.trim()).find(c=>c.length>=4);if(l)return l.slice(0,60)}let a=e.split(`
807
- `).map(l=>l.trim()).find(l=>l.length>=4);return a?a.slice(0,60):null}function Jo(e,t,s){let n=t.trim();if(!n)return;let r=_(),o=r.prepare(`SELECT auto_title, auto_title_source, auto_title_generated_at, auto_title_history
808
- FROM sessions WHERE id = ?`).get(e);if(!o||s==="heuristic"&&o.auto_title_source==="agent"&&o.auto_title||o.auto_title===n&&o.auto_title_source===s)return;let i=xp(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
857
+ `).map(l=>l.trim()).find(l=>l.length>=4);return a?a.slice(0,60):null}function Vo(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=Hm(o.auto_title_history),a=new Date().toISOString();o.auto_title&&o.auto_title_source&&i.push({title:o.auto_title,source:o.auto_title_source,replaced_at:a}),r.prepare(`UPDATE sessions
809
859
  SET auto_title = ?,
810
860
  auto_title_source = ?,
811
861
  auto_title_generated_at = ?,
812
862
  auto_title_history = ?
813
- WHERE id = ?`).run(n,s,Date.now(),JSON.stringify(i),e),$p(e,n,s,a)}function Mp(){P(),Sp(kn)||bp(kn,{recursive:!0})}function $p(e,t,s,n){try{Mp();let r=Wo(kn,`${e}.txt`),o=`# Claude Recall auto-title \xB7 session ${e} \xB7 source ${s} \xB7 updated ${n}
814
- `;Ep(r,o+t+`
815
- `)}catch(r){console.error("[autoTitle] mirror write failed:",r)}}import{existsSync as Dp,mkdirSync as dx,readFileSync as jp,writeFileSync as ux}from"node:fs";import{homedir as Pp}from"node:os";import{join as Go}from"node:path";import{z as Cn}from"zod";function Fp(){return process.env.RECALL_HOME??Go(Pp(),".recall")}function Up(){return Go(Fp(),"config.json")}var Bp=Cn.object({heuristicEnabled:Cn.boolean().default(!0),agentEnabled:Cn.boolean().default(!1)}),Ln={heuristicEnabled:!0,agentEnabled:!1};function Hp(){let e=Up();if(!Dp(e))return{};try{return JSON.parse(jp(e,"utf8"))}catch(t){return console.error("[auto-title-config] failed to parse config.json, using defaults:",t),{}}}function zo(){let e=Hp().autoTitle;if(!e)return{...Ln};let t=Bp.safeParse({...Ln,...e});return t.success?t.data:{...Ln}}var Xp=[/^<local-command-caveat>/,/^<command-name>/,/^<command-message>/,/^<system-reminder>/,/^<user-prompt-submit-hook>/,/^Caveat: The messages below were generated/i];function Jp(e){let t=e.trim();return t?Xp.some(s=>s.test(t)):!0}function Gp(e){let t=e;return t=t.replace(/^(?:<[^>]+>[\s\S]*?<\/[^>]+>\s*)+/,"").trim(),t=t.replace(/^<command-[^>]+>[^<]*<\/command-[^>]+>\s*/gm,"").trim(),!t||Jp(t)?null:t}function zp(e,t,s){let n=Sn(t),r=s??n,o=s?Wp(s)||s:Co(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 Yp(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 $o(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=Gp(g.contentText);E&&(h.firstUserMessage=Y(qe(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=zp(e,t.encodedProject,o),a=new Date().toISOString(),l=e.prepare(`
863
+ WHERE id = ?`).run(n,s,Date.now(),JSON.stringify(i),e),Qm(e,n,s,a)}function Zm(){j(),Pm(On)||jm(On,{recursive:!0})}function Qm(e,t,s,n){try{Zm();let r=qo(On,`${e}.txt`),o=`# Claude Recall auto-title \xB7 session ${e} \xB7 source ${s} \xB7 updated ${n}
864
+ `;$m(r,o+t+`
865
+ `)}catch(r){console.error("[autoTitle] mirror write failed:",r)}}import{existsSync as ep,mkdirSync as PR,readFileSync as tp,writeFileSync as FR}from"node:fs";import{homedir as sp}from"node:os";import{join as Zo}from"node:path";import{z as In}from"zod";function np(){return process.env.RECALL_HOME??Zo(sp(),".recall")}function rp(){return Zo(np(),"config.json")}var op=In.object({heuristicEnabled:In.boolean().default(!0),agentEnabled:In.boolean().default(!1)}),Mn={heuristicEnabled:!0,agentEnabled:!1};function ip(){let e=rp();if(!ep(e))return{};try{return JSON.parse(tp(e,"utf8"))}catch(t){return console.error("[auto-title-config] failed to parse config.json, using defaults:",t),{}}}function Qo(){let e=ip().autoTitle;if(!e)return{...Mn};let t=op.safeParse({...Mn,...e});return t.success?t.data:{...Mn}}var cp=[/^<local-command-caveat>/,/^<command-name>/,/^<command-message>/,/^<system-reminder>/,/^<user-prompt-submit-hook>/,/^Caveat: The messages below were generated/i];function lp(e){let t=e.trim();return t?cp.some(s=>s.test(t)):!0}function dp(e){let t=e;return t=t.replace(/^(?:<[^>]+>[\s\S]*?<\/[^>]+>\s*)+/,"").trim(),t=t.replace(/^<command-[^>]+>[^<]*<\/command-[^>]+>\s*/gm,"").trim(),!t||lp(t)?null:t}function up(e,t,s){let n=xn(t),r=s??n,o=s?ap(s)||s:Mo(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 mp(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 Bo(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=dp(g.contentText);E&&(h.firstUserMessage=z(Le(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=up(e,t.encodedProject,o),a=new Date().toISOString(),l=e.prepare(`
816
866
  INSERT INTO sessions (
817
867
  id, project_id, file_path, file_mtime,
818
868
  started_at, ended_at, message_count,
@@ -847,30 +897,30 @@ ${o}
847
897
  @is_sidechain, @content_text, @tool_names, @raw_json
848
898
  )
849
899
  ON CONFLICT(uuid) DO NOTHING
850
- `),u=e.prepare("DELETE FROM messages WHERE session_id = ?"),p=0,m=0;if(e.transaction(()=>{for(let g of r.values()){l.run({id:g.sessionId,project_id:i,file_path:t.sessionFile,file_mtime:t.mtime,started_at:g.earliestTimestamp,ended_at:g.latestTimestamp,message_count:g.entries.length,user_message_count:g.userCount,assistant_message_count:g.assistantCount,first_user_message:g.firstUserMessage,cwd:g.cwd,git_branch:g.gitBranch,version:g.version,indexed_at:a}),u.run(g.sessionId);for(let h of g.entries){let{redacted:E}=qe(h.contentText),{redacted:b}=qe(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}Uo(e,g.sessionId,g.entries),is(e,g.sessionId),p+=1}})(),zo().heuristicEnabled)for(let g of r.values()){let h=Xo(g.firstUserMessage);h&&Jo(g.sessionId,h,"heuristic")}return{inserted:!0,sessionCount:p,messageCount:m}}async function Yo(e){let t=_(),s=Lo();console.log(d.dim(`Scanning ${s.length} JSONL session files under ~/.claude/projects/`));let n=0,r=0,o=0,i=0,a=Date.now();for(let c of s)try{let u=await Yp(t,c,e.force??!1);u.inserted?(n+=1,o+=u.sessionCount,i+=u.messageCount,e.verbose&&console.log(d.dim(` + ${c.sessionFile.split("/").slice(-2).join("/")} (${u.messageCount} msgs)`))):r+=1}catch(u){console.error(d.err(` ! failed: ${c.sessionFile}`),u)}let l=((Date.now()-a)/1e3).toFixed(1);console.log(""),console.log(`${d.ok("indexed")}: ${d.bold(String(n))} files, ${d.bold(String(o))} sessions, ${d.bold(String(i))} messages ${d.dim(`in ${l}s`)}`),r>0&&console.log(d.dim(`skipped: ${r} unchanged files (use --force to reindex)`))}T();I();import qp from"cli-table3";function qo(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 = ?"),m=0,p=0;if(e.transaction(()=>{for(let g of r.values()){l.run({id:g.sessionId,project_id:i,file_path:t.sessionFile,file_mtime:t.mtime,started_at:g.earliestTimestamp,ended_at:g.latestTimestamp,message_count:g.entries.length,user_message_count:g.userCount,assistant_message_count:g.assistantCount,first_user_message:g.firstUserMessage,cwd:g.cwd,git_branch:g.gitBranch,version:g.version,indexed_at:a}),u.run(g.sessionId);for(let h of g.entries){let{redacted:E}=Le(h.contentText),{redacted:b}=Le(h.raw);c.run({uuid:h.uuid,session_id:h.sessionId,parent_uuid:h.parentUuid,type:h.type,role:h.role,timestamp:h.timestamp,is_sidechain:h.isSidechain?1:0,content_text:E,tool_names:h.toolNames.join(","),raw_json:b}),p+=1}Go(e,g.sessionId,g.entries),cs(e,g.sessionId),m+=1}})(),Qo().heuristicEnabled)for(let g of r.values()){let h=Ko(g.firstUserMessage);h&&Vo(g.sessionId,h,"heuristic")}return{inserted:!0,sessionCount:m,messageCount:p}}async function ei(e){let t=_(),s=Do();console.log(d.dim(`Scanning ${s.length} JSONL session files under ~/.claude/projects/`));let n=0,r=0,o=0,i=0,a=Date.now();for(let c of s)try{let u=await mp(t,c,e.force??!1);u.inserted?(n+=1,o+=u.sessionCount,i+=u.messageCount,e.verbose&&console.log(d.dim(` + ${c.sessionFile.split("/").slice(-2).join("/")} (${u.messageCount} msgs)`))):r+=1}catch(u){console.error(d.err(` ! failed: ${c.sessionFile}`),u)}let l=((Date.now()-a)/1e3).toFixed(1);console.log(""),console.log(`${d.ok("indexed")}: ${d.bold(String(n))} files, ${d.bold(String(o))} sessions, ${d.bold(String(i))} messages ${d.dim(`in ${l}s`)}`),r>0&&console.log(d.dim(`skipped: ${r} unchanged files (use --force to reindex)`))}w();v();import pp from"cli-table3";function ti(e){let t=_(),n={limit:Math.max(1,Math.min(500,parseInt(e.limit??"30",10)||30))},r="1=1";e.project&&(r+=" AND (p.name LIKE @proj OR p.decoded_path LIKE @proj OR p.encoded_path LIKE @proj)",n.proj=`%${e.project}%`),e.all||(r+=" AND s.message_count > 2");let o=t.prepare(`SELECT s.id, p.name AS project_name, s.started_at,
851
901
  s.message_count, s.first_user_message, s.git_branch
852
902
  FROM sessions s
853
903
  JOIN projects p ON p.id = s.project_id
854
904
  WHERE ${r}
855
905
  ORDER BY COALESCE(s.started_at, '') DESC
856
- LIMIT @limit`).all(n);if(o.length===0){console.log(d.dim("no sessions found. run `recall index` first."));return}let i=new qp({head:[d.bold("id"),d.bold("project"),d.bold("when"),d.bold("msgs"),d.bold("opening prompt")],colWidths:[10,22,14,6,70],wordWrap:!0,style:{head:[],border:["grey"]}});for(let a of o)i.push([d.accent(H(a.id)),d.project(Y(a.project_name,20)),d.dim(W(a.started_at)),String(a.message_count),Y(a.first_user_message,200)]);console.log(i.toString()),console.log(d.dim(`showing ${o.length} session${o.length===1?"":"s"}. use \`recall show <id>\` to view one.`))}T();I();import{spawn as om}from"node:child_process";import{readFileSync as Kp,writeFileSync as Vp,mkdirSync as Zp,chmodSync as Qp}from"node:fs";import{join as Ko}from"node:path";import{homedir as Vo}from"node:os";function Zo(){return Ko(Vo(),".recall","config.json")}function Qo(){try{return JSON.parse(Kp(Zo(),"utf-8"))}catch{return{}}}function em(e){let t=Zo();Zp(Ko(Vo(),".recall"),{recursive:!0}),Vp(t,JSON.stringify(e,null,2)+`
857
- `,"utf-8"),Qp(t,384)}function cs(){let t=Qo().verification;return typeof t=="object"&&t!==null&&"enabled"in t?!!t.enabled:!1}function On(e){let t=Qo();t.verification={...typeof t.verification=="object"&&t.verification!==null?t.verification:{},enabled:e},em(t)}T();var tm=[/\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],sm=1440*60*1e3;function nm(e){let t=_(),s=t.prepare(`SELECT content_text, tool_names FROM messages
906
+ LIMIT @limit`).all(n);if(o.length===0){console.log(d.dim("no sessions found. run `recall index` first."));return}let i=new pp({head:[d.bold("id"),d.bold("project"),d.bold("when"),d.bold("msgs"),d.bold("opening prompt")],colWidths:[10,22,14,6,70],wordWrap:!0,style:{head:[],border:["grey"]}});for(let a of o)i.push([d.accent(H(a.id)),d.project(z(a.project_name,20)),d.dim(W(a.started_at)),String(a.message_count),z(a.first_user_message,200)]);console.log(i.toString()),console.log(d.dim(`showing ${o.length} session${o.length===1?"":"s"}. use \`recall show <id>\` to view one.`))}w();v();import{spawn as wp}from"node:child_process";import{readFileSync as gp,writeFileSync as fp,mkdirSync as _p,chmodSync as hp}from"node:fs";import{join as si}from"node:path";import{homedir as ni}from"node:os";function ri(){return si(ni(),".recall","config.json")}function oi(){try{return JSON.parse(gp(ri(),"utf-8"))}catch{return{}}}function Ep(e){let t=ri();_p(si(ni(),".recall"),{recursive:!0}),fp(t,JSON.stringify(e,null,2)+`
907
+ `,"utf-8"),hp(t,384)}function ds(){let t=oi().verification;return typeof t=="object"&&t!==null&&"enabled"in t?!!t.enabled:!1}function Dn(e){let t=oi();t.verification={...typeof t.verification=="object"&&t.verification!==null?t.verification:{},enabled:e},Ep(t)}w();var bp=[/\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],Sp=1440*60*1e3;function Tp(e){let t=_(),s=t.prepare(`SELECT content_text, tool_names FROM messages
858
908
  WHERE session_id = ? AND role = 'assistant'
859
- ORDER BY timestamp DESC LIMIT 5`).all(e),n=!1;for(let l of s)if(l.content_text&&tm.some(c=>c.test(l.content_text))){n=!0;break}let r=t.prepare(`SELECT content_text, tool_names FROM messages
860
- WHERE session_id = ?`).all(e),o={fileWrites:!1,testRuns:!1,commits:!1,buildSuccess:!1};for(let l of r){let c=l.tool_names??"",u=l.content_text??"";/\bWrite\b|\bEdit\b/.test(c)&&(o.fileWrites=!0),/\b(?:jest|pytest|vitest|mocha|test|spec)\b/i.test(u)&&/pass|ok|✓/i.test(u)&&(o.testRuns=!0),/\bgit\s+commit\b/i.test(u)&&(o.commits=!0),(/\bbuild\s+(?:succeeded|success|passed)\b/i.test(u)||/tsc.*(?:0 errors|no errors)/i.test(u))&&(o.buildSuccess=!0)}return n?{status:[o.fileWrites,o.testRuns,o.commits,o.buildSuccess].filter(Boolean).length>=2?"verified":"unverified",evidence:o,claimFound:n}:{status:"neutral",evidence:o,claimFound:n}}function rm(e){let t=nm(e);return _().prepare("UPDATE sessions SET verification_status = ?, verification_computed_at = ? WHERE id = ?").run(t.status,Date.now(),e),t}function ei(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<sm){let n={fileWrites:!1,testRuns:!1,commits:!1,buildSuccess:!1};return{status:s.verification_status,evidence:n,claimFound:s.verification_status!=="neutral"}}return rm(e)}function im(e,t){if(t.length>=32)return e.prepare("SELECT id FROM sessions WHERE id = ?").get(t)?.id??null;let s=e.prepare("SELECT id FROM sessions WHERE id LIKE ? LIMIT 2").all(t+"%");return s.length===1?s[0].id:(s.length===0||console.error(d.err(`ambiguous id prefix "${t}". be more specific.`)),null)}function am(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 l of s)if(l.content_text&&bp.some(c=>c.test(l.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 l of r){let c=l.tool_names??"",u=l.content_text??"";/\bWrite\b|\bEdit\b/.test(c)&&(o.fileWrites=!0),/\b(?:jest|pytest|vitest|mocha|test|spec)\b/i.test(u)&&/pass|ok|✓/i.test(u)&&(o.testRuns=!0),/\bgit\s+commit\b/i.test(u)&&(o.commits=!0),(/\bbuild\s+(?:succeeded|success|passed)\b/i.test(u)||/tsc.*(?:0 errors|no errors)/i.test(u))&&(o.buildSuccess=!0)}return n?{status:[o.fileWrites,o.testRuns,o.commits,o.buildSuccess].filter(Boolean).length>=2?"verified":"unverified",evidence:o,claimFound:n}:{status:"neutral",evidence:o,claimFound:n}}function yp(e){let t=Tp(e);return _().prepare("UPDATE sessions SET verification_status = ?, verification_computed_at = ? WHERE id = ?").run(t.status,Date.now(),e),t}function ii(e){let s=_().prepare("SELECT verification_status, verification_computed_at FROM sessions WHERE id = ?").get(e);if(s?.verification_status&&s.verification_computed_at&&Date.now()-s.verification_computed_at<Sp){let n={fileWrites:!1,testRuns:!1,commits:!1,buildSuccess:!1};return{status:s.verification_status,evidence:n,claimFound:s.verification_status!=="neutral"}}return yp(e)}function Rp(e,t){if(t.length>=32)return e.prepare("SELECT id FROM sessions WHERE id = ?").get(t)?.id??null;let s=e.prepare("SELECT id FROM sessions WHERE id LIKE ? LIMIT 2").all(t+"%");return s.length===1?s[0].id:(s.length===0||console.error(d.err(`ambiguous id prefix "${t}". be more specific.`)),null)}function xp(e,t){let s=_(),n=s.prepare(`SELECT s.id, p.name AS project_name, p.decoded_path,
861
911
  s.started_at, s.ended_at, s.message_count,
862
912
  s.git_branch, s.version, s.cwd
863
913
  FROM sessions s
864
914
  JOIN projects p ON p.id = s.project_id
865
- WHERE s.id = ?`).get(e);if(!n)return null;let r=[],o=d.dim("\u2500".repeat(78));if(r.push(""),r.push(d.bold(d.project(n.project_name))+d.dim(` ${n.decoded_path}`)),r.push(d.dim(`session ${n.id} \xB7 ${n.message_count} msgs \xB7 ${W(n.started_at)}`+(n.git_branch?` \xB7 branch: ${n.git_branch}`:""))),cs()){let l=ei(e);l.status==="verified"?r.push(d.ok("\u2713 verified")):l.status==="unverified"&&r.push(d.warn("\u26A0 unverified"))}r.push(o);let i=t.limit?Math.max(1,parseInt(t.limit,10)||9999):9999,a=s.prepare(`SELECT uuid, type, role, timestamp, is_sidechain, content_text, tool_names, raw_json
915
+ WHERE s.id = ?`).get(e);if(!n)return null;let r=[],o=d.dim("\u2500".repeat(78));if(r.push(""),r.push(d.bold(d.project(n.project_name))+d.dim(` ${n.decoded_path}`)),r.push(d.dim(`session ${n.id} \xB7 ${n.message_count} msgs \xB7 ${W(n.started_at)}`+(n.git_branch?` \xB7 branch: ${n.git_branch}`:""))),ds()){let l=ii(e);l.status==="verified"?r.push(d.ok("\u2713 verified")):l.status==="unverified"&&r.push(d.warn("\u26A0 unverified"))}r.push(o);let i=t.limit?Math.max(1,parseInt(t.limit,10)||9999):9999,a=s.prepare(`SELECT uuid, type, role, timestamp, is_sidechain, content_text, tool_names, raw_json
866
916
  FROM messages
867
917
  WHERE session_id = ?
868
918
  ORDER BY COALESCE(timestamp, ''), rowid
869
- LIMIT ?`).all(e,i);for(let l of a){if(t.raw){r.push(l.raw_json);continue}let c=l.is_sidechain===1?d.dim(" [subagent]"):"",u=l.role==="user"?d.user("\u25B8 user"):l.role==="assistant"?d.assistant("\u25B8 assistant"):d.dim(`\u25B8 ${l.type}`);if(r.push(`${u}${c} ${d.dim(l.timestamp??"")}`),l.tool_names&&l.tool_names.length>0&&r.push(d.tool(` tools: ${l.tool_names}`)),l.content_text&&l.content_text.trim()){let p=l.content_text.trim().split(`
870
- `).map(m=>" "+m).join(`
871
- `);r.push(p)}r.push("")}return r.push(o),r.push(d.dim(`end of session ${n.id}`)),r.join(`
872
- `)}function cm(e,t){if(!t||!process.stdout.isTTY)return!1;let s=process.stdout.rows||24;return e.split(`
873
- `).length>s}function lm(e){let t=om("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 ti(e,t){let s=_(),n=im(s,e);if(!n){e.length>=32&&console.error(d.err(`session not found: ${e}`)),process.exitCode=1;return}let r=am(n,t);if(r===null){console.error(d.err(`session metadata missing for ${n}`)),process.exitCode=1;return}let o=t.pager!==!1;cm(r,o)?lm(r):console.log(r)}T();I();_e();function jm(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 gi(e,t){await Ce("Full-text search");let s=_(),n=jm(e);if(!n){console.log(d.dim("empty query"));return}let r=Math.max(1,Math.min(200,parseInt(t.limit??"20",10)||20)),o={q:n,limit:r},i="";t.project&&(i=" AND (p.name LIKE @proj OR p.decoded_path LIKE @proj) ",o.proj=`%${t.project}%`);let a=s.prepare(`SELECT m.session_id AS session_id,
919
+ LIMIT ?`).all(e,i);for(let l of a){if(t.raw){r.push(l.raw_json);continue}let c=l.is_sidechain===1?d.dim(" [subagent]"):"",u=l.role==="user"?d.user("\u25B8 user"):l.role==="assistant"?d.assistant("\u25B8 assistant"):d.dim(`\u25B8 ${l.type}`);if(r.push(`${u}${c} ${d.dim(l.timestamp??"")}`),l.tool_names&&l.tool_names.length>0&&r.push(d.tool(` tools: ${l.tool_names}`)),l.content_text&&l.content_text.trim()){let m=l.content_text.trim().split(`
920
+ `).map(p=>" "+p).join(`
921
+ `);r.push(m)}r.push("")}return r.push(o),r.push(d.dim(`end of session ${n.id}`)),r.join(`
922
+ `)}function kp(e,t){if(!t||!process.stdout.isTTY)return!1;let s=process.stdout.rows||24;return e.split(`
923
+ `).length>s}function Np(e){let t=wp("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 ai(e,t){let s=_(),n=Rp(s,e);if(!n){e.length>=32&&console.error(d.err(`session not found: ${e}`)),process.exitCode=1;return}let r=xp(n,t);if(r===null){console.error(d.err(`session metadata missing for ${n}`)),process.exitCode=1;return}let o=t.pager!==!1;kp(r,o)?Np(r):console.log(r)}w();v();_e();function tg(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 Si(e,t){await Ce("Full-text search");let s=_(),n=tg(e);if(!n){console.log(d.dim("empty query"));return}let r=Math.max(1,Math.min(200,parseInt(t.limit??"20",10)||20)),o={q:n,limit:r},i="";t.project&&(i=" AND (p.name LIKE @proj OR p.decoded_path LIKE @proj) ",o.proj=`%${t.project}%`);let a=s.prepare(`SELECT m.session_id AS session_id,
874
924
  p.name AS project_name,
875
925
  s.started_at AS started_at,
876
926
  snippet(messages_fts, 0, '<<', '>>', '\u2026', 16) AS snippet,
@@ -883,13 +933,13 @@ ${o}
883
933
  WHERE messages_fts MATCH @q
884
934
  ${i}
885
935
  ORDER BY bm25(messages_fts)
886
- LIMIT @limit`).all(o);if(a.length===0){console.log(d.dim(`no matches for "${e}"`));return}console.log(d.dim(`${a.length} match${a.length===1?"":"es"} for "${e}"`)),console.log("");for(let l of a){let c=l.snippet.replace(/<<([\s\S]*?)>>/g,(p,m)=>Do(m,m).replace(/\n/g," ")).replace(/\n/g," "),u=l.role==="user"?d.user("user"):l.role==="assistant"?d.assistant("asst"):d.dim("----");console.log(`${d.accent(H(l.session_id))} ${d.project(Y(l.project_name,20))} ${d.dim(W(l.started_at))} ${u}`),console.log(` ${Y(c,200)}`),console.log("")}console.log(d.dim("`recall show <id>` to read any session."))}T();j();We();I();import{statSync as Gm,existsSync as zm}from"node:fs";function hi(){if(console.log(""),console.log(d.bold("Claude Recall status")),console.log(d.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),!zm(te)){console.log(d.dim(" no database yet. run `recall index`."));return}let t=_().prepare(`SELECT
936
+ LIMIT @limit`).all(o);if(a.length===0){console.log(d.dim(`no matches for "${e}"`));return}console.log(d.dim(`${a.length} match${a.length===1?"":"es"} for "${e}"`)),console.log("");for(let l of a){let c=l.snippet.replace(/<<([\s\S]*?)>>/g,(m,p)=>Ho(p,p).replace(/\n/g," ")).replace(/\n/g," "),u=l.role==="user"?d.user("user"):l.role==="assistant"?d.assistant("asst"):d.dim("----");console.log(`${d.accent(H(l.session_id))} ${d.project(z(l.project_name,20))} ${d.dim(W(l.started_at))} ${u}`),console.log(` ${z(c,200)}`),console.log("")}console.log(d.dim("`recall show <id>` to read any session."))}w();P();Xe();v();import{statSync as lg,existsSync as dg}from"node:fs";function wi(){if(console.log(""),console.log(d.bold("Claude Recall status")),console.log(d.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),!dg(te)){console.log(d.dim(" no database yet. run `recall index`."));return}let t=_().prepare(`SELECT
887
937
  (SELECT COUNT(*) FROM projects) AS projects,
888
938
  (SELECT COUNT(*) FROM sessions) AS sessions,
889
939
  (SELECT COUNT(*) FROM messages) AS messages,
890
940
  (SELECT MIN(started_at) FROM sessions WHERE started_at IS NOT NULL) AS earliest,
891
941
  (SELECT MAX(started_at) FROM sessions WHERE started_at IS NOT NULL) AS latest,
892
- (SELECT MAX(indexed_at) FROM sessions) AS last_indexed`).get(),n=(Gm(te).size/1024/1024).toFixed(1);console.log(` db path ${d.dim(te)}`),console.log(` db size ${d.accent(n+" MB")}`),console.log(` projects ${d.accent(String(t.projects))}`),console.log(` sessions ${d.accent(String(t.sessions))}`),console.log(` messages ${d.accent(String(t.messages))}`),console.log(` earliest ${d.dim(t.earliest??"n/a")}`),console.log(` latest ${d.dim(t.latest??"n/a")} ${d.dim(W(t.latest))}`),console.log(` last index ${d.dim(t.last_indexed??"never")}`),console.log("");let r=K();r?(console.log(` daemon ${d.ok("running")} pid ${r.pid} \xB7 http://127.0.0.1:${r.port}`),console.log(` started ${d.dim(r.startedAt)} ${d.dim(W(r.startedAt))}`)):console.log(` daemon ${d.dim("stopped")} (run \`recall start\` or \`recall open\`)`),console.log("")}T();I();import Ym from"cli-table3";function Ei(){let t=_().prepare(`SELECT p.name,
942
+ (SELECT MAX(indexed_at) FROM sessions) AS last_indexed`).get(),n=(lg(te).size/1024/1024).toFixed(1);console.log(` db path ${d.dim(te)}`),console.log(` db size ${d.accent(n+" MB")}`),console.log(` projects ${d.accent(String(t.projects))}`),console.log(` sessions ${d.accent(String(t.sessions))}`),console.log(` messages ${d.accent(String(t.messages))}`),console.log(` earliest ${d.dim(t.earliest??"n/a")}`),console.log(` latest ${d.dim(t.latest??"n/a")} ${d.dim(W(t.latest))}`),console.log(` last index ${d.dim(t.last_indexed??"never")}`),console.log("");let r=Z();r?(console.log(` daemon ${d.ok("running")} pid ${r.pid} \xB7 http://127.0.0.1:${r.port}`),console.log(` started ${d.dim(r.startedAt)} ${d.dim(W(r.startedAt))}`)):console.log(` daemon ${d.dim("stopped")} (run \`recall start\` or \`recall open\`)`),console.log("")}w();v();import ug from"cli-table3";function Ri(){let t=_().prepare(`SELECT p.name,
893
943
  p.decoded_path,
894
944
  COUNT(s.id) AS session_count,
895
945
  COALESCE(SUM(s.message_count), 0) AS message_count,
@@ -897,10 +947,10 @@ ${o}
897
947
  FROM projects p
898
948
  LEFT JOIN sessions s ON s.project_id = p.id
899
949
  GROUP BY p.id
900
- ORDER BY MAX(COALESCE(s.started_at, '')) DESC`).all();if(t.length===0){console.log(d.dim("no projects indexed yet."));return}let s=new Ym({head:[d.bold("project"),d.bold("sessions"),d.bold("msgs"),d.bold("latest"),d.bold("path")],style:{head:[],border:["grey"]}});for(let n of t)s.push([d.project(Y(n.name,30)),String(n.session_count),String(n.message_count),d.dim(W(n.latest)),d.dim(Y(n.decoded_path,50))]);console.log(s.toString())}We();We();j();I();import{spawn as Vm}from"node:child_process";import{openSync as Zm}from"node:fs";import{join as Qm}from"node:path";import{existsSync as qm}from"node:fs";import{dirname as bi}from"node:path";import{fileURLToPath as Km}from"node:url";var hs=null;function Te(){if(hs)return hs;let e=bi(Km(import.meta.url));for(;!qm(`${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 hs=e,hs}function eg(){return Qm(Te(),"dist","daemon","entrypoint.js")}async function Es(){let e=K();if(e){console.log(`${d.ok("already running")} pid ${e.pid} \xB7 http://127.0.0.1:${e.port}`);return}P();let t=Zm(_s,"a"),s=eg();Vm(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=K();if(o){console.log(`${d.ok("daemon started")} pid ${o.pid} \xB7 http://127.0.0.1:${o.port}`),console.log(d.dim(`logs: ${_s}`));return}}console.error(d.err("daemon did not come up within 5s \u2014 check the log file")),console.error(d.dim(` ${_s}`)),process.exitCode=1}We();I();async function Si(){let e=K();if(!e){console.log(d.dim("no daemon running.")),Jn();return}try{process.kill(e.pid,"SIGTERM")}catch(s){console.error(d.err(`failed to signal pid ${e.pid}: ${s.message}`)),process.exitCode=1;return}let t=Date.now();for(;Date.now()-t<5e3;)if(await new Promise(s=>setTimeout(s,100)),!K()){console.log(d.ok(`stopped daemon pid ${e.pid}`));return}console.error(d.err(`pid ${e.pid} did not exit within 5s \u2014 you may need to kill it manually`)),process.exitCode=1}We();import{spawn as tg}from"node:child_process";import{platform as bs}from"node:os";I();function sg(e){let t=bs()==="darwin"?"open":bs()==="win32"?"start":"xdg-open",s=bs()==="win32"?["",e]:[e];tg(t,s,{detached:!0,stdio:"ignore",shell:bs()==="win32"}).unref()}async function yi(){let e=K();if(!e&&(console.log(d.dim("daemon not running \u2014 starting it\u2026")),await Es(),e=K(),!e)){console.error(d.err("could not start the daemon. run `recall start` manually and check logs.")),process.exitCode=1;return}let t=`http://127.0.0.1:${e.port}`;console.log(`${d.ok("opening")} ${t}`),sg(t)}T();var ng=/<(local-command-caveat|local-command-stdout|command-name|command-message|command-args|system-reminder|user-prompt-submit-hook|task-notification)[\s\S]*?<\/\1>/gi,rg=/⚡ \*\*Tool call · `[^`]+`\*\*\s*\n+```json\n[\s\S]*?\n```/g,og=/\*\*Tool result\*\*\s*\n+```\n[\s\S]*?\n```/g;function ig(e){return e.replace(ng,"").trim()}function ag(e){let t=e.replace(rg,"[tool call]");return t=t.replace(og,"[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(d.dim("no projects indexed yet."));return}let s=new ug({head:[d.bold("project"),d.bold("sessions"),d.bold("msgs"),d.bold("latest"),d.bold("path")],style:{head:[],border:["grey"]}});for(let n of t)s.push([d.project(z(n.name,30)),String(n.session_count),String(n.message_count),d.dim(W(n.latest)),d.dim(z(n.decoded_path,50))]);console.log(s.toString())}Xe();Xe();P();v();import{spawn as gg}from"node:child_process";import{openSync as fg}from"node:fs";import{join as _g}from"node:path";import{existsSync as mg}from"node:fs";import{dirname as xi}from"node:path";import{fileURLToPath as pg}from"node:url";var bs=null;function ye(){if(bs)return bs;let e=xi(pg(import.meta.url));for(;!mg(`${e}/package.json`);){let t=xi(e);if(t===e)throw new Error(`package.json not found walking up from ${import.meta.url}`);e=t}return bs=e,bs}function hg(){return _g(ye(),"dist","daemon","entrypoint.js")}async function Ss(){let e=Z();if(e){console.log(`${d.ok("already running")} pid ${e.pid} \xB7 http://127.0.0.1:${e.port}`);return}j();let t=fg(Es,"a"),s=hg();gg(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(`${d.ok("daemon started")} pid ${o.pid} \xB7 http://127.0.0.1:${o.port}`),console.log(d.dim(`logs: ${Es}`));return}}console.error(d.err("daemon did not come up within 5s \u2014 check the log file")),console.error(d.dim(` ${Es}`)),process.exitCode=1}Xe();v();async function ki(e,t){let s=Date.now();for(;Date.now()-s<t;)if(await new Promise(n=>setTimeout(n,100)),!Kn(e))return!0;return!1}async function Ni(){let e=Z();if(!e){console.log(d.dim("no daemon running.")),Ft();return}try{process.kill(e.pid,"SIGTERM")}catch(t){console.error(d.err(`failed to signal pid ${e.pid}: ${t.message}`)),process.exitCode=1;return}if(await ki(e.pid,5e3)){console.log(d.ok(`stopped daemon pid ${e.pid}`));return}console.log(d.dim(`pid ${e.pid} ignored SIGTERM after 5s \u2014 escalating to SIGKILL`));try{process.kill(e.pid,"SIGKILL")}catch(t){if(t.code==="ESRCH"){Ft(),console.log(d.ok(`stopped daemon pid ${e.pid}`));return}console.error(d.err(`failed to SIGKILL pid ${e.pid}: ${t.message}`)),process.exitCode=1;return}if(await ki(e.pid,2e3)){Ft(),console.log(d.ok(`stopped daemon pid ${e.pid} (forced)`));return}console.error(d.err(`pid ${e.pid} survived SIGKILL \u2014 kernel is unhappy, kill manually with: kill -9 ${e.pid}`)),process.exitCode=1}Xe();import{spawn as Eg}from"node:child_process";import{platform as Ts}from"node:os";v();function bg(e){let t=Ts()==="darwin"?"open":Ts()==="win32"?"start":"xdg-open",s=Ts()==="win32"?["",e]:[e];Eg(t,s,{detached:!0,stdio:"ignore",shell:Ts()==="win32"}).unref()}async function Li(){let e=Z();if(!e&&(console.log(d.dim("daemon not running \u2014 starting it\u2026")),await Ss(),e=Z(),!e)){console.error(d.err("could not start the daemon. run `recall start` manually and check logs.")),process.exitCode=1;return}let t=`http://127.0.0.1:${e.port}`;console.log(`${d.ok("opening")} ${t}`),bg(t)}w();var Sg=/<(local-command-caveat|local-command-stdout|command-name|command-message|command-args|system-reminder|user-prompt-submit-hook|task-notification)[\s\S]*?<\/\1>/gi,Tg=/⚡ \*\*Tool call · `[^`]+`\*\*\s*\n+```json\n[\s\S]*?\n```/g,yg=/\*\*Tool result\*\*\s*\n+```\n[\s\S]*?\n```/g;function wg(e){return e.replace(Sg,"").trim()}function Rg(e){let t=e.replace(Tg,"[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,`
901
951
 
902
- `),t.trim()}function cg(e){return e.role??e.type??"message"}function Ti(e,t,s={}){let n=s.mode??"condensed",r=s.includeSidechain===!0,o=s.since?Date.parse(s.since):0,i=t.filter(u=>!(!r&&u.is_sidechain===1||o&&u.timestamp&&Date.parse(u.timestamp)<o)),a=[];s.prelude&&(a.push(s.prelude.trim()),a.push("")),a.push(`# Claude Recall, past session context (${n})`),a.push(""),a.push(`- **Project**: ${e.project_name}`),e.decoded_path&&a.push(`- **Path**: \`${e.decoded_path}\``),a.push(`- **Session ID**: \`${e.id}\``),e.started_at&&a.push(`- **Started**: ${e.started_at}`),e.ended_at&&a.push(`- **Ended**: ${e.ended_at}`),e.git_branch&&a.push(`- **Branch**: \`${e.git_branch}\``),a.push(`- **Messages**: ${i.length}`),a.push(""),a.push("> This is a transcript of a previous Claude Code session, included for context. Refer back to it when the user asks about past decisions, code written, or problems debugged in this work."),a.push(""),a.push("---"),a.push("");let l=0,c=0;for(let u of i){let p=u.content_text??"",m=ig(p);n==="condensed"&&(m=ag(m));let f=m.length>0,g=!!u.tool_names&&u.tool_names.length>0;if(!f&&!g){c+=1;continue}let h=cg(u),E=u.timestamp?` \`${u.timestamp}\``:"";a.push(`## ${h}${E}`),a.push(""),g&&n==="condensed"&&(a.push(`_tools used: ${u.tool_names}_`),a.push("")),f&&(a.push(m),a.push("")),l+=1}return a.push("---"),a.push(""),a.push(`_${l} messages included_`+(c?`, ${c} empty skipped`:"")+(r?"":", subagent/sidechain hidden")+"."),a.join(`
903
- `)}T();j();import{randomUUID as wi}from"node:crypto";import{writeFileSync as xi,readFileSync as d0,existsSync as lg,mkdirSync as dg}from"node:fs";import{join as Gn}from"node:path";var Ss=Gn(x,"threads"),ug=Gn(Ss,"index.json");function Ri(){P(),lg(Ss)||dg(Ss,{recursive:!0})}function ki(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 Ni(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 xg(e){return e.role??e.type??"message"}function Ci(e,t,s={}){let n=s.mode??"condensed",r=s.includeSidechain===!0,o=s.since?Date.parse(s.since):0,i=t.filter(u=>!(!r&&u.is_sidechain===1||o&&u.timestamp&&Date.parse(u.timestamp)<o)),a=[];s.prelude&&(a.push(s.prelude.trim()),a.push("")),a.push(`# Claude Recall, past session context (${n})`),a.push(""),a.push(`- **Project**: ${e.project_name}`),e.decoded_path&&a.push(`- **Path**: \`${e.decoded_path}\``),a.push(`- **Session ID**: \`${e.id}\``),e.started_at&&a.push(`- **Started**: ${e.started_at}`),e.ended_at&&a.push(`- **Ended**: ${e.ended_at}`),e.git_branch&&a.push(`- **Branch**: \`${e.git_branch}\``),a.push(`- **Messages**: ${i.length}`),a.push(""),a.push("> This is a transcript of a previous Claude Code session, included for context. Refer back to it when the user asks about past decisions, code written, or problems debugged in this work."),a.push(""),a.push("---"),a.push("");let l=0,c=0;for(let u of i){let m=u.content_text??"",p=wg(m);n==="condensed"&&(p=Rg(p));let f=p.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(p),a.push("")),l+=1}return a.push("---"),a.push(""),a.push(`_${l} messages included_`+(c?`, ${c} empty skipped`:"")+(r?"":", subagent/sidechain hidden")+"."),a.join(`
953
+ `)}w();P();import{randomUUID as Ai}from"node:crypto";import{writeFileSync as Oi,readFileSync as Px,existsSync as kg,mkdirSync as Ng}from"node:fs";import{join as Vn}from"node:path";var ys=Vn(x,"threads"),Lg=Vn(ys,"index.json");function vi(){j(),kg(ys)||Ng(ys,{recursive:!0})}function Ii(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 Mi(e){let t=new Map;if(e.length===0)return t;let s=_(),n=e.map(()=>"?").join(","),r=s.prepare(`SELECT te.thread_id AS thread_id,
904
954
  p.name AS project,
905
955
  COUNT(*) AS n,
906
956
  SUM(CASE WHEN te.role = 'origin' THEN 1 ELSE 0 END) AS origin_n
@@ -908,7 +958,7 @@ ${o}
908
958
  LEFT JOIN sessions s ON s.id = te.session_id
909
959
  LEFT JOIN projects p ON p.id = s.project_id
910
960
  WHERE te.thread_id IN (${n})
911
- GROUP BY te.thread_id, p.name`).all(...e),o=new Map;for(let i of r){let a=o.get(i.thread_id);a||(a=[],o.set(i.thread_id,a)),a.push(i)}for(let[i,a]of o){let l=a.filter(p=>p.project!==null),c=l.length,u=null;l.length>0&&(u=[...l].sort((m,f)=>f.n-m.n||f.origin_n-m.origin_n||(m.project??"").localeCompare(f.project??""))[0].project),t.set(i,{project:u,project_count:c})}return t}function Ci(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 Li(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 l=a.filter(m=>m.project!==null),c=l.length,u=null;l.length>0&&(u=[...l].sort((p,f)=>f.n-p.n||f.origin_n-p.origin_n||(p.project??"").localeCompare(f.project??""))[0].project),t.set(i,{project:u,project_count:c})}return t}function Di(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 $i(e){let s=_().prepare(`SELECT NULLIF(sa.alias, '') AS alias,
912
962
  s.auto_title AS auto_title,
913
963
  s.auto_title_source AS auto_title_source,
914
964
  s.first_user_message AS first_user_message,
@@ -916,11 +966,11 @@ ${o}
916
966
  FROM (SELECT ? AS sid) q
917
967
  LEFT JOIN sessions s ON s.id = q.sid
918
968
  LEFT JOIN session_aliases sa ON sa.session_id = q.sid
919
- LEFT JOIN projects p ON p.id = s.project_id`).get(e),n=s?.auto_title_source??null;return{alias:s?.alias??null,auto_title:s?.auto_title??null,auto_title_source:n==="agent"||n==="heuristic"?n:null,first_user_message:s?.first_user_message??null,project:s?.project??null}}function Oi(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 ji(e){let s=_().prepare(`SELECT
920
970
  COUNT(*) AS session_count,
921
971
  SUM(CASE WHEN role = 'origin' THEN 1 ELSE 0 END) AS origin_count
922
- FROM thread_edges WHERE thread_id = ?`).get(e);return{session_count:s?.session_count??0,origin_count:s?.origin_count??0}}function Le(e){let t=Oe(e);t&&(Ri(),xi(Gn(Ss,`${e}.json`),JSON.stringify(t,null,2)),Ai())}function Ai(){Ri();let e=zn({includeArchived:!0});xi(ug,JSON.stringify({threads:e},null,2))}function Ii(e){let t=e.name.trim();if(!t)throw new Error("thread name cannot be empty");let s=_(),n=wi(),r=new Date().toISOString();s.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, ?, ?)").run(n,t,e.summary?.trim()||null,r),e.originSessionId&&s.prepare(`INSERT INTO thread_edges (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
923
- VALUES (?, ?, NULL, 'origin', 1.0, 'manual', ?)`).run(n,e.originSessionId,r),Le(n);let o=Oe(n);if(!o)throw new Error("thread creation succeeded but read-back failed");return o}function zn(e={}){let t=_(),s=e.includeArchived?"":"WHERE archived = 0",n=t.prepare(`SELECT * FROM threads ${s} ORDER BY created_at DESC`).all(),r=Ni(n.map(o=>o.id));return n.map(o=>ki(o,Oi(o.id),r.get(o.id)))}function Oe(e){let t=_(),s=t.prepare("SELECT * FROM threads WHERE id = ?").get(e);if(!s)return null;let n=t.prepare(`SELECT e.*,
972
+ FROM thread_edges WHERE thread_id = ?`).get(e);return{session_count:s?.session_count??0,origin_count:s?.origin_count??0}}function Ae(e){let t=Oe(e);t&&(vi(),Oi(Vn(ys,`${e}.json`),JSON.stringify(t,null,2)),Pi())}function Pi(){vi();let e=Zn({includeArchived:!0});Oi(Lg,JSON.stringify({threads:e},null,2))}function Fi(e){let t=e.name.trim();if(!t)throw new Error("thread name cannot be empty");let s=_(),n=Ai(),r=new Date().toISOString();s.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, ?, ?)").run(n,t,e.summary?.trim()||null,r),e.originSessionId&&s.prepare(`INSERT INTO thread_edges (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
973
+ VALUES (?, ?, NULL, 'origin', 1.0, 'manual', ?)`).run(n,e.originSessionId,r),Ae(n);let o=Oe(n);if(!o)throw new Error("thread creation succeeded but read-back failed");return o}function Zn(e={}){let t=_(),s=e.includeArchived?"":"WHERE archived = 0",n=t.prepare(`SELECT * FROM threads ${s} ORDER BY created_at DESC`).all(),r=Mi(n.map(o=>o.id));return n.map(o=>Ii(o,ji(o.id),r.get(o.id)))}function Oe(e){let t=_(),s=t.prepare("SELECT * FROM threads WHERE id = ?").get(e);if(!s)return null;let n=t.prepare(`SELECT e.*,
924
974
  NULLIF(sa.alias, '') AS alias,
925
975
  s.auto_title AS auto_title,
926
976
  s.auto_title_source AS auto_title_source,
@@ -931,7 +981,7 @@ ${o}
931
981
  LEFT JOIN session_aliases sa ON sa.session_id = e.session_id
932
982
  LEFT JOIN projects p ON p.id = s.project_id
933
983
  WHERE e.thread_id = ?
934
- ORDER BY e.added_at ASC`).all(e).map(Ci),r=Ni([e]).get(e);return{...ki(s,Oi(s.id),r),edges:n}}function vi(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(Di),r=Mi([e]).get(e);return{...Ii(s,ji(s.id),r),edges:n}}function Ui(e){let t=_();if(!t.prepare("SELECT * FROM threads WHERE id = ?").get(e.threadId))throw new Error(`thread ${e.threadId} not found`);let n=new Date().toISOString(),r=e.parentSessionId??null,o=e.role??(r?"child":"origin"),i=e.confidence??1,a=e.source??"manual";if(i<0||i>1)throw new Error("confidence must be 0..1");t.prepare(`INSERT INTO thread_edges
935
985
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
936
986
  VALUES (?, ?, ?, ?, ?, ?, ?)
937
987
  ON CONFLICT(thread_id, session_id) DO UPDATE SET
@@ -939,57 +989,57 @@ ${o}
939
989
  role = excluded.role,
940
990
  confidence = excluded.confidence,
941
991
  source = excluded.source,
942
- added_at = excluded.added_at`).run(e.threadId,e.sessionId,r,o,i,a,n),Le(e.threadId);let l=Li(e.sessionId);return{thread_id:e.threadId,session_id:e.sessionId,parent_session_id:r,role:o,confidence:i,source:a,added_at:n,alias:l.alias,auto_title:l.auto_title,auto_title_source:l.auto_title_source,alias_source:l.alias?"manual":null,first_user_message:l.first_user_message,project:l.project}}function Mi(e,t){let n=_().prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e,t);return n.changes>0&&Le(e),{removed:n.changes}}function $i(e,t,s){let n=_(),r=n.prepare("SELECT * FROM thread_edges WHERE thread_id = ? AND session_id = ?").get(e,t);if(!r)throw new Error("edge not found; add the session first");if(s!==null){if(s===t)throw new Error("cycle detected: session cannot be its own parent");let a=n.prepare("SELECT parent_session_id FROM thread_edges WHERE thread_id = ? AND session_id = ?"),l=s,c=new Set;for(;l!==null;){if(l===t)throw new Error(`cycle detected: setting parent of ${t} to ${s} would create a loop`);if(c.has(l))break;c.add(l),l=a.get(e,l)?.parent_session_id??null}}let o=s?"child":"origin";n.prepare(`UPDATE thread_edges
992
+ added_at = excluded.added_at`).run(e.threadId,e.sessionId,r,o,i,a,n),Ae(e.threadId);let l=$i(e.sessionId);return{thread_id:e.threadId,session_id:e.sessionId,parent_session_id:r,role:o,confidence:i,source:a,added_at:n,alias:l.alias,auto_title:l.auto_title,auto_title_source:l.auto_title_source,alias_source:l.alias?"manual":null,first_user_message:l.first_user_message,project:l.project}}function Bi(e,t){let n=_().prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e,t);return n.changes>0&&Ae(e),{removed:n.changes}}function Hi(e,t,s){let n=_(),r=n.prepare("SELECT * FROM thread_edges WHERE thread_id = ? AND session_id = ?").get(e,t);if(!r)throw new Error("edge not found; add the session first");if(s!==null){if(s===t)throw new Error("cycle detected: session cannot be its own parent");let a=n.prepare("SELECT parent_session_id FROM thread_edges WHERE thread_id = ? AND session_id = ?"),l=s,c=new Set;for(;l!==null;){if(l===t)throw new Error(`cycle detected: setting parent of ${t} to ${s} would create a loop`);if(c.has(l))break;c.add(l),l=a.get(e,l)?.parent_session_id??null}}let o=s?"child":"origin";n.prepare(`UPDATE thread_edges
943
993
  SET parent_session_id = ?, role = ?, added_at = ?
944
- WHERE thread_id = ? AND session_id = ?`).run(s,o,new Date().toISOString(),e,t),Le(e);let i=Li(t);return Ci({...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 Di(e,t){let s=t.trim();if(!s)throw new Error("name cannot be empty");_().prepare("UPDATE threads SET name = ? WHERE id = ?").run(s,e),Le(e);let r=Oe(e);if(!r)throw new Error(`thread ${e} not found`);return r}function ji(e){_().prepare("UPDATE threads SET closed_at = ? WHERE id = ?").run(new Date().toISOString(),e),Le(e);let s=Oe(e);if(!s)throw new Error(`thread ${e} not found`);return s}function Pi(e){_().prepare("UPDATE threads SET closed_at = NULL WHERE id = ?").run(e),Le(e);let s=Oe(e);if(!s)throw new Error(`thread ${e} not found`);return s}function Fi(e){_().prepare("UPDATE threads SET archived = 1 WHERE id = ?").run(e),Le(e);let s=Oe(e);if(!s)throw new Error(`thread ${e} not found`);return s}function Ui(e,t){if(e===t)throw new Error("cannot merge a thread into itself");let s=_(),n=new Date().toISOString();s.transaction(()=>{let o=s.prepare("SELECT * FROM thread_edges WHERE thread_id = ?").all(e);for(let i of o)s.prepare(`INSERT INTO thread_edges
994
+ WHERE thread_id = ? AND session_id = ?`).run(s,o,new Date().toISOString(),e,t),Ae(e);let i=$i(t);return Di({...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 Wi(e,t){let s=t.trim();if(!s)throw new Error("name cannot be empty");_().prepare("UPDATE threads SET name = ? WHERE id = ?").run(s,e),Ae(e);let r=Oe(e);if(!r)throw new Error(`thread ${e} not found`);return r}function Xi(e){_().prepare("UPDATE threads SET closed_at = ? WHERE id = ?").run(new Date().toISOString(),e),Ae(e);let s=Oe(e);if(!s)throw new Error(`thread ${e} not found`);return s}function Ji(e){_().prepare("UPDATE threads SET closed_at = NULL WHERE id = ?").run(e),Ae(e);let s=Oe(e);if(!s)throw new Error(`thread ${e} not found`);return s}function Gi(e){_().prepare("UPDATE threads SET archived = 1 WHERE id = ?").run(e),Ae(e);let s=Oe(e);if(!s)throw new Error(`thread ${e} not found`);return s}function Yi(e,t){if(e===t)throw new Error("cannot merge a thread into itself");let s=_(),n=new Date().toISOString();s.transaction(()=>{let o=s.prepare("SELECT * FROM thread_edges WHERE thread_id = ?").all(e);for(let i of o)s.prepare(`INSERT INTO thread_edges
945
995
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
946
996
  VALUES (?, ?, ?, ?, ?, ?, ?)
947
997
  ON CONFLICT(thread_id, session_id) DO UPDATE SET
948
998
  parent_session_id = COALESCE(thread_edges.parent_session_id, excluded.parent_session_id),
949
999
  role = CASE WHEN thread_edges.role = 'origin' OR excluded.role = 'origin' THEN 'origin' ELSE 'child' END,
950
1000
  confidence = MAX(thread_edges.confidence, excluded.confidence),
951
- source = thread_edges.source`).run(t,i.session_id,i.parent_session_id,i.role,i.confidence,i.source,n);s.prepare("DELETE FROM threads WHERE id = ?").run(e)})(),Le(t),Ai();let r=Oe(t);if(!r)throw new Error("merge destination disappeared");return r}function Bi(e){if(e.sessionIds.length===0)throw new Error("no sessions to split off");let t=_(),s=new Date().toISOString(),n=wi();t.transaction(()=>{t.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, NULL, ?)").run(n,e.newThreadName.trim(),s);for(let o of e.sessionIds){let i=t.prepare("SELECT * FROM thread_edges WHERE thread_id = ? AND session_id = ?").get(e.threadId,o);i&&(t.prepare(`INSERT INTO thread_edges
1001
+ source = thread_edges.source`).run(t,i.session_id,i.parent_session_id,i.role,i.confidence,i.source,n);s.prepare("DELETE FROM threads WHERE id = ?").run(e)})(),Ae(t),Pi();let r=Oe(t);if(!r)throw new Error("merge destination disappeared");return r}function zi(e){if(e.sessionIds.length===0)throw new Error("no sessions to split off");let t=_(),s=new Date().toISOString(),n=Ai();t.transaction(()=>{t.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, NULL, ?)").run(n,e.newThreadName.trim(),s);for(let o of e.sessionIds){let i=t.prepare("SELECT * FROM thread_edges WHERE thread_id = ? AND session_id = ?").get(e.threadId,o);i&&(t.prepare(`INSERT INTO thread_edges
952
1002
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
953
- VALUES (?, ?, ?, ?, ?, ?, ?)`).run(n,o,i.parent_session_id,i.role,i.confidence,i.source,s),t.prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e.threadId,o))}})(),Le(e.threadId),Le(n);let r=Oe(n);if(!r)throw new Error("split destination disappeared");return r}function Hi(e){let t=Oe(e);if(!t)return[];let s=t.edges.filter(r=>r.role==="origin").map(r=>r.session_id),n=t.edges.filter(r=>r.role==="child").map(r=>r.session_id);return[...s,...n]}I();_e();T();j();import{writeFileSync as pg}from"node:fs";import{join as mg}from"node:path";var gg=mg(x,"recall-events.json");function Yn(e,t,s,n="cli"){_().prepare(`
1003
+ VALUES (?, ?, ?, ?, ?, ?, ?)`).run(n,o,i.parent_session_id,i.role,i.confidence,i.source,s),t.prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e.threadId,o))}})(),Ae(e.threadId),Ae(n);let r=Oe(n);if(!r)throw new Error("split destination disappeared");return r}function qi(e){let t=Oe(e);if(!t)return[];let s=t.edges.filter(r=>r.role==="origin").map(r=>r.session_id),n=t.edges.filter(r=>r.role==="child").map(r=>r.session_id);return[...s,...n]}v();_e();w();P();import{writeFileSync as Cg}from"node:fs";import{join as Ag}from"node:path";var Og=Ag(x,"recall-events.json");function Qn(e,t,s,n="cli"){_().prepare(`
954
1004
  INSERT INTO recall_events (session_id, recalled_at, token_count, mode, caller)
955
1005
  VALUES (?, datetime('now'), ?, ?, ?)
956
- `).run(e,t,s,n),fg()}function fg(){P();let t=_().prepare("SELECT id, session_id, recalled_at, token_count, mode, caller FROM recall_events ORDER BY recalled_at DESC").all();pg(gg,JSON.stringify(t,null,2)+`
957
- `,"utf-8")}function _g(e,t){if(t.length>=32)return e.prepare("SELECT id FROM sessions WHERE id = ?").get(t)?.id??null;let s=e.prepare("SELECT id FROM sessions WHERE id LIKE ? LIMIT 2").all(t+"%");return s.length===1?s[0].id:(s.length===0||process.stderr.write(`ambiguous id prefix "${t}". be more specific.
958
- `),null)}function hg(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 Eg(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:
1006
+ `).run(e,t,s,n),vg()}function vg(){j();let t=_().prepare("SELECT id, session_id, recalled_at, token_count, mode, caller FROM recall_events ORDER BY recalled_at DESC").all();Cg(Og,JSON.stringify(t,null,2)+`
1007
+ `,"utf-8")}function Ig(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 Mg(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 Dg(e,t){if(t.length>=32)return e.prepare("SELECT id FROM threads WHERE id = ?").get(t)?.id??null;let s=e.prepare("SELECT id, name FROM threads WHERE id LIKE ? ORDER BY created_at DESC").all(t+"%");if(s.length===1)return s[0].id;if(s.length===0)return null;process.stderr.write(`ambiguous thread prefix "${t}" \u2014 candidates:
959
1009
  `);for(let n of s)process.stderr.write(` ${H(n.id)} ${n.name}
960
- `);return null}function Wi(e,t,s){let n=e.prepare(`SELECT s.id, p.name AS project_name, p.decoded_path,
1010
+ `);return null}function Ki(e,t,s){let n=e.prepare(`SELECT s.id, p.name AS project_name, p.decoded_path,
961
1011
  s.started_at, s.ended_at, s.message_count, s.git_branch
962
1012
  FROM sessions s JOIN projects p ON p.id = s.project_id
963
1013
  WHERE s.id = ?`).get(t);if(!n)return process.stderr.write(`session metadata missing for ${t}
964
1014
  `),null;let r=e.prepare(`SELECT uuid, type, role, timestamp, is_sidechain, content_text, tool_names
965
1015
  FROM messages
966
1016
  WHERE session_id = ?
967
- ORDER BY COALESCE(timestamp, ''), rowid`).all(t),o=s.full?"full":"condensed";return Ti(n,r,{mode:o,includeSidechain:s.subagents===!0,prelude:s.prelude??null,since:hg(s.since)})}async function Xi(e,t){await Ce("Context re-injection");let s=_();if(e.startsWith("thread:")){let i=e.slice(7).trim();if(!i){process.stderr.write(`thread: target requires an id or prefix
968
- `),process.exitCode=1;return}let a=Eg(s,i);if(!a){process.stderr.write(`thread not found: ${i}
969
- `),process.exitCode=1;return}let l=Hi(a);if(l.length===0){process.stderr.write(`thread ${i} has no linked sessions
970
- `),process.exitCode=1;return}for(let c=0;c<l.length;c+=1){let u=l[c],p=Wi(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 Ci(n,r,{mode:o,includeSidechain:s.subagents===!0,prelude:s.prelude??null,since:Mg(s.since)})}async function Vi(e,t){await Ce("Context re-injection");let s=_();if(e.startsWith("thread:")){let i=e.slice(7).trim();if(!i){process.stderr.write(`thread: target requires an id or prefix
1018
+ `),process.exitCode=1;return}let a=Dg(s,i);if(!a){process.stderr.write(`thread not found: ${i}
1019
+ `),process.exitCode=1;return}let l=qi(a);if(l.length===0){process.stderr.write(`thread ${i} has no linked sessions
1020
+ `),process.exitCode=1;return}for(let c=0;c<l.length;c+=1){let u=l[c],m=Ki(s,u,{...t,prelude:c===0?t.prelude:void 0});if(m===null){process.exitCode=1;continue}c>0&&process.stdout.write(`
971
1021
  ---
972
1022
 
973
- `),process.stdout.write(p),p.endsWith(`
1023
+ `),process.stdout.write(m),m.endsWith(`
974
1024
  `)||process.stdout.write(`
975
- `),Yn(u,Math.ceil(p.length/4),"thread","cli")}return}let n=_g(s,e);if(!n){e.length>=32&&process.stderr.write(`session not found: ${e}
976
- `),process.exitCode=1;return}let r=Wi(s,n,t);if(r===null){process.exitCode=1;return}process.stdout.write(r),r.endsWith(`
1025
+ `),Qn(u,Math.ceil(m.length/4),"thread","cli")}return}let n=Ig(s,e);if(!n){e.length>=32&&process.stderr.write(`session not found: ${e}
1026
+ `),process.exitCode=1;return}let r=Ki(s,n,t);if(r===null){process.exitCode=1;return}process.stdout.write(r),r.endsWith(`
977
1027
  `)||process.stdout.write(`
978
- `);let o=t.since?"since":t.full?"full":"condensed";Yn(n,Math.ceil(r.length/4),o,"cli"),process.stderr.isTTY&&process.stderr.write(`\x1B[2mShare this recall? \u2192 recall share\x1B[0m
979
- `)}_e();import{join as bg}from"node:path";import{spawn as Sg}from"node:child_process";async function Ji(e={}){await Ce("MCP server");let t=bg(Te(),"dist","mcp-server.js"),s={...process.env};e.allowWrites&&(s.RECALL_MCP_ALLOW_WRITES="1");let n=Sg(process.execPath,[t],{stdio:"inherit",env:s});return new Promise((r,o)=>{n.on("error",o),n.on("exit",(i,a)=>{if(a){process.kill(process.pid,a);return}process.exitCode=i??0,r()})})}T();import{execSync as qn}from"node:child_process";import{randomUUID as yg}from"node:crypto";import Tg from"node:readline/promises";I();async function Gi(e){if(e.list){wg();return}if(e.purge){xg(e.purge);return}let t=await Rg();t||(process.stderr.write(d.err(`clipboard empty / nothing on stdin
980
- `)),process.exit(1));let s=$t(t);if(s.length>0&&!e.force){process.stderr.write(d.warn(`\u26A0 detected ${s.length} possible secret${s.length===1?"":"s"} in content:
1028
+ `);let o=t.since?"since":t.full?"full":"condensed";Qn(n,Math.ceil(r.length/4),o,"cli"),process.stderr.isTTY&&process.stderr.write(`\x1B[2mShare this recall? \u2192 recall share\x1B[0m
1029
+ `)}_e();import{join as $g}from"node:path";import{spawn as jg}from"node:child_process";async function Zi(e={}){await Ce("MCP server");let t=$g(ye(),"dist","mcp-server.js"),s={...process.env};e.allowWrites&&(s.RECALL_MCP_ALLOW_WRITES="1");let n=jg(process.execPath,[t],{stdio:"inherit",env:s});return new Promise((r,o)=>{n.on("error",o),n.on("exit",(i,a)=>{if(a){process.kill(process.pid,a);return}process.exitCode=i??0,r()})})}w();import{execSync as er}from"node:child_process";import{randomUUID as Pg}from"node:crypto";import Fg from"node:readline/promises";v();async function Qi(e){if(e.list){Ug();return}if(e.purge){Bg(e.purge);return}let t=await Hg();t||(process.stderr.write(d.err(`clipboard empty / nothing on stdin
1030
+ `)),process.exit(1));let s=Dt(t);if(s.length>0&&!e.force){process.stderr.write(d.warn(`\u26A0 detected ${s.length} possible secret${s.length===1?"":"s"} in content:
981
1031
  `));for(let a of s.slice(0,8))process.stderr.write(` ${d.err(a.pattern)} ${d.dim("\u2192")} ${a.maskedPreview}
982
1032
  `);s.length>8&&process.stderr.write(d.dim(` \u2026 ${s.length-8} more
983
1033
  `)),e.dryRun&&(process.stderr.write(d.dim(`
984
1034
  (dry run \u2014 nothing archived)
985
1035
  `)),process.exit(1)),!process.stdin.isTTY&&!process.stderr.isTTY&&(process.stderr.write(d.err(`refusing to archive secret content in non-interactive mode. use --force to override.
986
- `)),e.pipe&&process.stdout.write(t),process.exit(1));let o=Tg.createInterface({input:process.stdin,output:process.stderr}),i=await o.question(d.accent("archive anyway? [y/N] "));o.close(),i.trim().toLowerCase()!=="y"&&(process.stderr.write(d.dim(`cancelled \u2014 nothing archived.
1036
+ `)),e.pipe&&process.stdout.write(t),process.exit(1));let o=Fg.createInterface({input:process.stdin,output:process.stderr}),i=await o.question(d.accent("archive anyway? [y/N] "));o.close(),i.trim().toLowerCase()!=="y"&&(process.stderr.write(d.dim(`cancelled \u2014 nothing archived.
987
1037
  `)),e.pipe&&process.stdout.write(t),process.exit(0))}e.dryRun&&(process.stderr.write(d.dim(`(dry run \u2014 would archive ${t.length.toLocaleString()} chars)
988
- `)),e.pipe&&process.stdout.write(t),process.exit(0));let n=yg(),r=new Date().toISOString();_().prepare(`INSERT INTO paste_archives (id, created_at, content, size_bytes, source, label)
1038
+ `)),e.pipe&&process.stdout.write(t),process.exit(0));let n=Pg(),r=new Date().toISOString();_().prepare(`INSERT INTO paste_archives (id, created_at, content, size_bytes, source, label)
989
1039
  VALUES (?, ?, ?, ?, ?, ?)`).run(n,r,t,Buffer.byteLength(t,"utf8"),e.pipe?"cli-piped":"cli",e.label??null),process.stderr.write(d.ok(`\u2713 archived ${t.length.toLocaleString()} chars as ${n.slice(0,8)}
990
1040
  `)),e.label&&process.stderr.write(d.dim(` label: ${e.label}
991
1041
  `)),process.stderr.write(d.dim(` purge any time with: recall paste --purge ${n.slice(0,8)}
992
- `)),e.pipe&&process.stdout.write(t)}function wg(){let e=_().prepare(`SELECT id, created_at, size_bytes, source, label,
1042
+ `)),e.pipe&&process.stdout.write(t)}function Ug(){let e=_().prepare(`SELECT id, created_at, size_bytes, source, label,
993
1043
  substr(replace(replace(content, char(10), '\u21B5'), char(13), ''), 1, 80) AS preview
994
1044
  FROM paste_archives
995
1045
  ORDER BY created_at DESC
@@ -1001,16 +1051,16 @@ ${d.bold(`${e.length} archived paste${e.length===1?"":"s"}`)}
1001
1051
  show full content: recall paste --show <id>
1002
1052
  `)+d.dim(`purge one (permanent): recall paste --purge <id>
1003
1053
 
1004
- `))}function xg(e){e.length<8&&(process.stderr.write(d.err(`provide at least 8 characters of the paste id to purge.
1054
+ `))}function Bg(e){e.length<8&&(process.stderr.write(d.err(`provide at least 8 characters of the paste id to purge.
1005
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(d.err(`no paste matches ${e}
1006
1056
  `)),process.exit(1)),s.length>1&&(process.stderr.write(d.err(`prefix ${e} is ambiguous. be more specific.
1007
1057
  `)),process.exit(1)),t.prepare("DELETE FROM paste_archives WHERE id = ?").run(s[0].id),process.stderr.write(d.ok(`\u2713 purged ${s[0].id.slice(0,8)} \u2014 content permanently destroyed
1008
- `))}async function Rg(){if(!process.stdin.isTTY)return await kg();try{return qn("pbpaste",{encoding:"utf8",maxBuffer:16*1024*1024})}catch{}try{return qn("xclip -o -selection clipboard",{encoding:"utf8",maxBuffer:16*1024*1024})}catch{}try{return qn("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 kg(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(t));return Buffer.concat(e).toString("utf8")}T();I();async function zi(e){let t=_(),s=new Map,n=0,r=0,o=0,i=new Set,a=t.prepare(`SELECT uuid, session_id, content_text, raw_json
1058
+ `))}async function Hg(){if(!process.stdin.isTTY)return await Wg();try{return er("pbpaste",{encoding:"utf8",maxBuffer:16*1024*1024})}catch{}try{return er("xclip -o -selection clipboard",{encoding:"utf8",maxBuffer:16*1024*1024})}catch{}try{return er("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 Wg(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(t));return Buffer.concat(e).toString("utf8")}w();v();async function ea(e){let t=_(),s=new Map,n=0,r=0,o=0,i=new Set,a=t.prepare(`SELECT uuid, session_id, content_text, raw_json
1009
1059
  FROM messages
1010
- WHERE content_text IS NOT NULL`).all(),l=t.prepare("UPDATE messages SET content_text = ?, raw_json = ? WHERE uuid = ?"),c=(g,h)=>{let E=$t(g);if(E.length===0)return!1;for(let b of E){let S=s.get(b.pattern)??{pattern:b.pattern,severity:b.severity,hits:0,sessions:new Set};S.hits+=1,S.sessions.add(h),s.set(b.pattern,S)}return!0};process.stdout.write(d.dim(`Scanning ${a.length.toLocaleString()} messages\u2026
1060
+ WHERE content_text IS NOT NULL`).all(),l=t.prepare("UPDATE messages SET content_text = ?, raw_json = ? WHERE uuid = ?"),c=(g,h)=>{let E=Dt(g);if(E.length===0)return!1;for(let b of E){let S=s.get(b.pattern)??{pattern:b.pattern,severity:b.severity,hits:0,sessions:new Set};S.hits+=1,S.sessions.add(h),s.set(b.pattern,S)}return!0};process.stdout.write(d.dim(`Scanning ${a.length.toLocaleString()} messages\u2026
1011
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(d.dim(` hit in session ${g.session_id.slice(0,8)} message ${g.uuid.slice(0,8)}
1012
- `)),e.redact)){let E=qe(g.content_text??"").redacted,b=g.raw_json?qe(g.raw_json).redacted:null;l.run(E,b,g.uuid),o+=1}let u=t.prepare(`SELECT id, first_user_message FROM sessions
1013
- WHERE first_user_message IS NOT NULL`).all(),p=t.prepare("UPDATE sessions SET first_user_message = ? WHERE id = ?"),m=0;for(let g of u)$t(g.first_user_message).length>0&&(i.add(g.id),e.redact&&(p.run(qe(g.first_user_message).redacted,g.id),m+=1));if(process.stdout.write(`
1062
+ `)),e.redact)){let E=Le(g.content_text??"").redacted,b=g.raw_json?Le(g.raw_json).redacted:null;l.run(E,b,g.uuid),o+=1}let u=t.prepare(`SELECT id, first_user_message FROM sessions
1063
+ WHERE first_user_message IS NOT NULL`).all(),m=t.prepare("UPDATE sessions SET first_user_message = ? WHERE id = ?"),p=0;for(let g of u)Dt(g.first_user_message).length>0&&(i.add(g.id),e.redact&&(m.run(Le(g.first_user_message).redacted,g.id),p+=1));if(process.stdout.write(`
1014
1064
  `),s.size===0){process.stdout.write(d.ok(`\u2713 clean \u2014 no secrets detected across ${n.toLocaleString()} messages.
1015
1065
  `));return}let f=[...s.values()].sort((g,h)=>h.hits-g.hits);process.stdout.write(d.warn(`\u26A0 ${r.toLocaleString()} message${r===1?"":"s"} across ${i.size.toLocaleString()} session${i.size===1?"":"s"} contain detected secrets.
1016
1066
 
@@ -1018,23 +1068,24 @@ show full content: recall paste --show <id>
1018
1068
  `)),process.stdout.write(d.dim(` \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1019
1069
  `));for(let g of f){let h=g.severity==="high"?d.err("\u25CF"):d.warn("\u25CF");process.stdout.write(` ${h} ${g.pattern.padEnd(30)} ${String(g.hits).padStart(5)} ${String(g.sessions.size).padStart(4)}
1020
1070
  `)}process.stdout.write(`
1021
- `),e.redact?(process.stdout.write(d.ok(`\u2713 redacted in place: ${o.toLocaleString()} messages, ${m.toLocaleString()} session previews.
1071
+ `),e.redact?(process.stdout.write(d.ok(`\u2713 redacted in place: ${o.toLocaleString()} messages, ${p.toLocaleString()} session previews.
1022
1072
  `)),process.stdout.write(d.dim(` (The source JSONL files at ~/.claude/projects/ were not modified.)
1023
- `))):process.stdout.write(d.dim(" Rerun with --redact to scrub these in place, or run `recall index --force`.\n"))}T();I();import{basename as Ng}from"node:path";async function qi(e){let t=_(),s=await Cg(t,e.project);if(!s){console.error(d.err(`No project found${e.project?` matching "${e.project}"`:" for current cwd"}. Run \`recall projects\` to list available projects.`)),process.exitCode=1;return}let n=t.prepare(`SELECT s.id,
1073
+ `))):process.stdout.write(d.dim(" Rerun with --redact to scrub these in place, or run `recall index --force`.\n"))}w();v();import{basename as Xg}from"node:path";async function sa(e){let t=_(),s=await Jg(t,e.project);if(!s){console.error(d.err(`No project found${e.project?` matching "${e.project}"`:" for current cwd"}. Run \`recall projects\` to list available projects.`)),process.exitCode=1;return}let n=t.prepare(`SELECT s.id,
1024
1074
  s.auto_title,
1025
1075
  s.auto_title_source,
1026
1076
  CASE WHEN sa.session_id IS NOT NULL THEN 1 ELSE 0 END AS has_alias
1027
1077
  FROM sessions s
1028
1078
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1029
1079
  WHERE s.project_id = ?
1030
- ORDER BY s.started_at`).all(s.id);if(n.length===0){console.error(d.warn(`Project "${s.name}" has 0 sessions.`));return}let r={clean:0,"fixed_v0.16.1":0,agent:0,manual_alias:0,template_pending:0,programmatic:0,recursive_meta:0,low_signal:0},o=[];for(let u of n){let p={auto_title:u.auto_title,auto_title_source:u.auto_title_source??null,has_alias:u.has_alias===1},m=Bo(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(d.warn(`Project "${s.name}" has 0 sessions.`));return}let r={clean:0,"fixed_v0.16.1":0,agent:0,manual_alias:0,template_pending:0,programmatic:0,recursive_meta:0,low_signal:0},o=[];for(let u of n){let m={auto_title:u.auto_title,auto_title_source:u.auto_title_source??null,has_alias:u.has_alias===1},p=Yo(m);r[p]+=1,o.push({id:u.id,quality:p})}if(!e.dryRun){let u=t.prepare(`UPDATE sessions
1031
1081
  SET title_quality = ?,
1032
1082
  title_quality_computed_at = ?
1033
- WHERE id = ?`),p=Date.now();t.transaction(f=>{for(let g of f)u.run(g.quality,p,g.id)})(o)}if(e.json){console.log(JSON.stringify({project:s.name,project_id:s.id,total_sessions:n.length,dry_run:!!e.dryRun,counts:r},null,2));return}let i=n.length;console.log(""),console.log(d.project(`Title quality audit \u2014 project ${d.bold(s.name)}`)),s.decoded_path&&console.log(d.dim(` ${s.decoded_path}`)),console.log(d.dim(` ${i} sessions${e.dryRun?" (DRY RUN \u2014 no DB writes)":""}`)),console.log("");let a=["clean","fixed_v0.16.1","agent","manual_alias","template_pending","programmatic","recursive_meta","low_signal"],l=Math.max(...a.map(u=>u.length));for(let u of a){let p=r[u];if(p===0)continue;let m=(p/i*100).toFixed(1).padStart(5),f=Lg(p,i);console.log(` ${u.padEnd(l)} ${d.bold(String(p).padStart(5))} ${m}% ${f}`)}console.log("");let c=r.template_pending+r.programmatic+r.recursive_meta+r.low_signal;if(c>0){let u=(c/i*100).toFixed(1);console.log(d.dim(` ${c} sessions (${u}%) eligible for cleanup phases L1/L3/L4.`))}else console.log(d.ok(" No cleanup-eligible sessions remain in this project. \u2713"));console.log("")}async function Cg(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(Ng(s));return r||null}var Yi=28;function Lg(e,t){let s=Math.round(e/t*Yi);return d.dim("\u2588".repeat(s)+"\xB7".repeat(Yi-s))}Ft();I();T();En();T();Ft();import{readFileSync as Mg,existsSync as Vn,statSync as $g,readdirSync as Dg}from"node:fs";import{join as Ts}from"node:path";import{homedir as jg}from"node:os";var Ut=["vscode","cursor","windsurf"],Pg={vscode:"Code",cursor:"Cursor",windsurf:"Windsurf"};var Fg=.7,Ug=300*1e3;function Bg(e){let t=e?.homeDir??jg(),s=e?.sources??Ut,n=[];for(let r of s){let o=Ts(t,"Library","Application Support",Pg[r],"User","workspaceStorage");Vn(o)&&n.push({source:r,root:o})}return n}function Hg(e,t){let s=Ts(e,"workspace.json"),n=Ts(e,"state.vscdb");if(!Vn(s)||!Vn(n))return[];let r;try{let l=JSON.parse(Mg(s,"utf8"));if(!l.folder||!l.folder.startsWith("file://"))return[];r=decodeURIComponent(l.folder.replace(/^file:\/\//,""))}catch{return[]}let o;try{o=$g(n).mtime.toISOString()}catch{return[]}let i;try{i=new rs(n,{readonly:!0})}catch{return[]}let a=[];try{let l=i.prepare("SELECT value FROM ItemTable WHERE key = 'terminal.integrated.bufferState' LIMIT 1").get(),c={};if(l?.value)try{c=JSON.parse(l.value)}catch{}let u=c.state??[];if(u.length===0)a.push({workspace_path:r,workspace_storage_dir:e,tab_name:null,cwd_hint:null,last_seen_at:o,source:t});else for(let p of u){let m=p.shellLaunchConfig??{},f=typeof m.name=="string"?m.name.trim():"";a.push({workspace_path:r,workspace_storage_dir:e,tab_name:f||null,cwd_hint:typeof m.cwd=="string"?m.cwd:null,last_seen_at:o,source:t})}}finally{i.close()}return a}function Wg(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)<=Ug&&(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 Xg=new Set(["zsh","bash","fish","sh","dash","ksh","tcsh","csh","pwsh","powershell","cmd","nu","node","deno","bun","python","python3","ruby","ts-node","tsx","go","cargo","java","php","irb","pry","iex","task","tasks","terminal","copilot","cascade","composer","claude","claude code"]);function Jg(e){return Xg.has(e.trim().toLowerCase())}function Gg(e){let t=e.tab_name?.trim();return!t||Jg(t)?null:t}function Qi(e){let t=e?.minScore??Fg,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 = ?`),m=Date.now();t.transaction(f=>{for(let g of f)u.run(g.quality,m,g.id)})(o)}if(e.json){console.log(JSON.stringify({project:s.name,project_id:s.id,total_sessions:n.length,dry_run:!!e.dryRun,counts:r},null,2));return}let i=n.length;console.log(""),console.log(d.project(`Title quality audit \u2014 project ${d.bold(s.name)}`)),s.decoded_path&&console.log(d.dim(` ${s.decoded_path}`)),console.log(d.dim(` ${i} sessions${e.dryRun?" (DRY RUN \u2014 no DB writes)":""}`)),console.log("");let a=["clean","fixed_v0.16.1","agent","manual_alias","template_pending","programmatic","recursive_meta","low_signal"],l=Math.max(...a.map(u=>u.length));for(let u of a){let m=r[u];if(m===0)continue;let p=(m/i*100).toFixed(1).padStart(5),f=Gg(m,i);console.log(` ${u.padEnd(l)} ${d.bold(String(m).padStart(5))} ${p}% ${f}`)}console.log("");let c=r.template_pending+r.programmatic+r.recursive_meta+r.low_signal;if(c>0){let u=(c/i*100).toFixed(1);console.log(d.dim(` ${c} sessions (${u}%) eligible for cleanup phases L1/L3/L4.`))}else console.log(d.ok(" No cleanup-eligible sessions remain in this project. \u2713"));console.log("")}async function Jg(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(Xg(s));return r||null}var ta=28;function Gg(e,t){let s=Math.round(e/t*ta);return d.dim("\u2588".repeat(s)+"\xB7".repeat(ta-s))}Ut();v();w();wn();w();Ut();import{readFileSync as Vg,existsSync as sr,statSync as Zg,readdirSync as Qg}from"node:fs";import{join as Rs}from"node:path";import{homedir as ef}from"node:os";var Bt=["vscode","cursor","windsurf"],tf={vscode:"Code",cursor:"Cursor",windsurf:"Windsurf"};var sf=.7,nf=300*1e3;function rf(e){let t=e?.homeDir??ef(),s=e?.sources??Bt,n=[];for(let r of s){let o=Rs(t,"Library","Application Support",tf[r],"User","workspaceStorage");sr(o)&&n.push({source:r,root:o})}return n}function of(e,t){let s=Rs(e,"workspace.json"),n=Rs(e,"state.vscdb");if(!sr(s)||!sr(n))return[];let r;try{let l=JSON.parse(Vg(s,"utf8"));if(!l.folder||!l.folder.startsWith("file://"))return[];r=decodeURIComponent(l.folder.replace(/^file:\/\//,""))}catch{return[]}let o;try{o=Zg(n).mtime.toISOString()}catch{return[]}let i;try{i=new is(n,{readonly:!0})}catch{return[]}let a=[];try{let l=i.prepare("SELECT value FROM ItemTable WHERE key = 'terminal.integrated.bufferState' LIMIT 1").get(),c={};if(l?.value)try{c=JSON.parse(l.value)}catch{}let u=c.state??[];if(u.length===0)a.push({workspace_path:r,workspace_storage_dir:e,tab_name:null,cwd_hint:null,last_seen_at:o,source:t});else for(let m of u){let p=m.shellLaunchConfig??{},f=typeof p.name=="string"?p.name.trim():"";a.push({workspace_path:r,workspace_storage_dir:e,tab_name:f||null,cwd_hint:typeof p.cwd=="string"?p.cwd:null,last_seen_at:o,source:t})}}finally{i.close()}return a}function af(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 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 df(e){let t=e.tab_name?.trim();return!t||lf(t)?null:t}function ia(e){let t=e?.minScore??sf,s=e?.limit,n=_(),r=e?.projectId?" AND s.project_id = ?":"",o=e?.projectId?[e.projectId]:[],i=n.prepare(`SELECT s.id, p.decoded_path AS cwd, s.started_at
1034
1084
  FROM sessions s
1035
1085
  JOIN projects p ON p.id = s.project_id
1036
1086
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1037
- WHERE (sa.alias IS NULL OR sa.alias = '')${r}`).all(...o),a=e?.sources??Ut,l=Bg({sources:a,homeDir:e?.homeDir}),c=[];for(let{source:p,root:m}of l){let f;try{f=Dg(m)}catch{continue}for(let g of f){let h=Ts(m,g);c.push(...Hg(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}=Wg(p,g);h<t||(!m||h>m.score)&&(m={entry:g,score:h,matched:E})}if(!m)continue;let f=Gg(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 ea(e){let t=[],s=[];for(let n of e){let r=Ki(n.session_id);if(r&&r.trim()!==""){s.push(n);continue}t.push(n)}return{applicable:t,skipped:s}}import{basename as zg}from"node:path";async function sa(e){let t=qg(e.source);if(!t){console.error(d.err("Invalid --source. Allowed: vscode | cursor | windsurf | all (default).")),process.exitCode=1;return}let s=Kg(e.minScore,.7);if(s===null||s<0||s>1){console.error(d.err("Invalid --min-score. Must be a number in [0, 1].")),process.exitCode=1;return}let n=e.limit?parseInt(e.limit,10):void 0;if(n!==void 0&&(!Number.isFinite(n)||n<0)){console.error(d.err("Invalid --limit. Must be a non-negative integer.")),process.exitCode=1;return}let r=e.project?Vg(e.project):void 0;if(e.project&&r===null){console.error(d.err(`No project found matching "${e.project}". Run \`recall projects\`.`)),process.exitCode=1;return}let o=Qi({projectId:r??void 0,sources:t,minScore:s,limit:n}),{applicable:i,skipped:a}=ea(o);if(e.apply){let l=0;for(let c of i)try{ys(c.session_id,c.proposed_alias),l+=1}catch(u){console.error(d.err(`apply failed for ${c.session_id.slice(0,8)}: ${u.message}`))}if(e.json){console.log(JSON.stringify({mode:"apply",sources:t,min_score:s,project_id:r??null,applied:l,skipped:a.length,proposals:i.map(ta)},null,2));return}console.log(""),console.log(d.ok(`Applied ${l} alias backfill${l===1?"":"s"}`+(a.length?` \xB7 skipped ${a.length} (alias appeared since proposal)`:""))),console.log("");return}if(e.json){console.log(JSON.stringify({mode:"dry-run",sources:t,min_score:s,project_id:r??null,proposals:i.map(ta),skipped_due_to_existing_alias:a.length},null,2));return}Yg(i,t,s,a.length)}function Yg(e,t,s,n){if(console.log(""),console.log(d.project(`recall import-vscode-state \xB7 sources=${t.join("+")} min-score=${s.toFixed(2)} \xB7 DRY RUN`)),console.log(d.dim(" Pass --apply to write proposals via setAlias().")),console.log(""),e.length===0){console.log(d.warn(" No proposals \u2014 either no matching workspaces or every candidate session already has an alias.")),n>0&&console.log(d.dim(` ${n} sessions were skipped because they already have aliases.`)),console.log("");return}for(let r of e){let o=d.bold(r.session_id.slice(0,8)),i=d.bold(r.score.toFixed(2)),a=d.dim(`[${r.evidence.source}]`),l=r.evidence.matched_on.join("+");console.log(` ${o} score=${i} ${a} matched=${l}`),console.log(` proposed alias: ${d.bold(r.proposed_alias)}`),console.log(` workspace: ${d.dim(Y(r.evidence.workspace_path,70))}`),r.evidence.tab_name&&console.log(` tab name: ${r.evidence.tab_name}`),r.evidence.cwd_hint&&console.log(` cwd hint: ${d.dim(Y(r.evidence.cwd_hint,70))}`),console.log(` last seen: ${d.dim(r.evidence.last_seen_at)}`),console.log("")}console.log(d.dim(` ${e.length} proposal${e.length===1?"":"s"}`+(n>0?` \xB7 ${n} skipped (existing alias)`:"")+" \xB7 pass --apply to write via setAlias()")),console.log("")}function ta(e){return e}function qg(e){if(!e||e==="all")return Ut;let t=e.split(",").map(n=>n.trim().toLowerCase()).filter(Boolean),s=[];for(let n of t)if(Ut.includes(n))s.push(n);else return null;return s.length>0?s:null}function Kg(e,t){if(e===void 0)return t;let s=Number.parseFloat(e);return Number.isFinite(s)?s:null}function Vg(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=zg(e);if(r&&r!==e){let o=t.prepare("SELECT id FROM projects WHERE name = ? LIMIT 1").get(r);if(o)return o.id}return null}import{existsSync as na,mkdirSync as Zg,readFileSync as Qg,writeFileSync as ef}from"node:fs";import{homedir as tf}from"node:os";import{join as ra}from"node:path";import{z as Xe}from"zod";function oa(){return process.env.RECALL_HOME??ra(tf(),".recall")}function sf(){let e=oa();na(e)||Zg(e,{recursive:!0})}function ia(){return ra(oa(),"config.json")}var aa=Xe.object({enabled:Xe.boolean().default(!1),model:Xe.string().optional(),ratePerMinute:Xe.number().int().min(1).max(600).default(30),lastProcessedSessionId:Xe.string().nullable().default(null),backfillPaused:Xe.boolean().default(!1),autoExtractEnabled:Xe.boolean().default(!1),autoExtractIntervalMinutes:Xe.number().int().min(5).max(720).default(60),autoExtractBatchSize:Xe.number().int().min(1).max(20).default(1)}),ws={enabled:!1,ratePerMinute:30,lastProcessedSessionId:null,backfillPaused:!1,autoExtractEnabled:!1,autoExtractIntervalMinutes:60,autoExtractBatchSize:1};function ca(){let e=ia();if(!na(e))return{};try{return JSON.parse(Qg(e,"utf8"))}catch(t){return console.error("[semantic-config] failed to parse config.json, using defaults:",t),{}}}function Ae(){let e=ca().semantic;if(!e)return{...ws};let t=aa.safeParse({...ws,...e});return t.success?t.data:{...ws}}function Pe(e){sf();let t=ca(),s=aa.parse({...ws,...t.semantic??{},...e}),n={...t,semantic:s};return ef(ia(),JSON.stringify(n,null,2)),s}T();Je();import{existsSync as yf,mkdirSync as Tf,writeFileSync as wf}from"node:fs";import{homedir as xf}from"node:os";import{join as er}from"node:path";var Rf=1,kf=12e3,Nf=3,Cf=[];function Lf(){return process.env.RECALL_HOME??er(xf(),".recall")}function ba(){return er(Lf(),"semantic")}function Of(){let e=ba();yf(e)||Tf(e,{recursive:!0})}function Af(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??Bt,l=rf({sources:a,homeDir:e?.homeDir}),c=[];for(let{source:m,root:p}of l){let f;try{f=Qg(p)}catch{continue}for(let g of f){let h=Rs(p,g);c.push(...of(h,m))}}if(c.length===0)return[];let u=[];for(let m of i){let p=null;for(let g of c){let{score:h,matchedOn:E}=af(m,g);h<t||(!p||h>p.score)&&(p={entry:g,score:h,matched:E})}if(!p)continue;let f=df(p.entry);f&&u.push({session_id:m.id,proposed_alias:f,score:p.score,evidence:{source:p.entry.source,workspace_path:p.entry.workspace_path,workspace_storage_dir:p.entry.workspace_storage_dir,tab_name:p.entry.tab_name,cwd_hint:p.entry.cwd_hint,last_seen_at:p.entry.last_seen_at,matched_on:p.matched}})}return u.sort((m,p)=>p.score-m.score||m.session_id.localeCompare(p.session_id)),typeof s=="number"&&s>=0&&u.length>s?u.slice(0,s):u}function aa(e){let t=[],s=[];for(let n of e){let r=na(n.session_id);if(r&&r.trim()!==""){s.push(n);continue}t.push(n)}return{applicable:t,skipped:s}}import{basename as uf}from"node:path";async function la(e){let t=pf(e.source);if(!t){console.error(d.err("Invalid --source. Allowed: vscode | cursor | windsurf | all (default).")),process.exitCode=1;return}let s=gf(e.minScore,.7);if(s===null||s<0||s>1){console.error(d.err("Invalid --min-score. Must be a number in [0, 1].")),process.exitCode=1;return}let n=e.limit?parseInt(e.limit,10):void 0;if(n!==void 0&&(!Number.isFinite(n)||n<0)){console.error(d.err("Invalid --limit. Must be a non-negative integer.")),process.exitCode=1;return}let r=e.project?ff(e.project):void 0;if(e.project&&r===null){console.error(d.err(`No project found matching "${e.project}". Run \`recall projects\`.`)),process.exitCode=1;return}let o=ia({projectId:r??void 0,sources:t,minScore:s,limit:n}),{applicable:i,skipped:a}=aa(o);if(e.apply){let l=0;for(let c of i)try{ws(c.session_id,c.proposed_alias),l+=1}catch(u){console.error(d.err(`apply failed for ${c.session_id.slice(0,8)}: ${u.message}`))}if(e.json){console.log(JSON.stringify({mode:"apply",sources:t,min_score:s,project_id:r??null,applied:l,skipped:a.length,proposals:i.map(ca)},null,2));return}console.log(""),console.log(d.ok(`Applied ${l} alias backfill${l===1?"":"s"}`+(a.length?` \xB7 skipped ${a.length} (alias appeared since proposal)`:""))),console.log("");return}if(e.json){console.log(JSON.stringify({mode:"dry-run",sources:t,min_score:s,project_id:r??null,proposals:i.map(ca),skipped_due_to_existing_alias:a.length},null,2));return}mf(i,t,s,a.length)}function mf(e,t,s,n){if(console.log(""),console.log(d.project(`recall import-vscode-state \xB7 sources=${t.join("+")} min-score=${s.toFixed(2)} \xB7 DRY RUN`)),console.log(d.dim(" Pass --apply to write proposals via setAlias().")),console.log(""),e.length===0){console.log(d.warn(" No proposals \u2014 either no matching workspaces or every candidate session already has an alias.")),n>0&&console.log(d.dim(` ${n} sessions were skipped because they already have aliases.`)),console.log("");return}for(let r of e){let o=d.bold(r.session_id.slice(0,8)),i=d.bold(r.score.toFixed(2)),a=d.dim(`[${r.evidence.source}]`),l=r.evidence.matched_on.join("+");console.log(` ${o} score=${i} ${a} matched=${l}`),console.log(` proposed alias: ${d.bold(r.proposed_alias)}`),console.log(` workspace: ${d.dim(z(r.evidence.workspace_path,70))}`),r.evidence.tab_name&&console.log(` tab name: ${r.evidence.tab_name}`),r.evidence.cwd_hint&&console.log(` cwd hint: ${d.dim(z(r.evidence.cwd_hint,70))}`),console.log(` last seen: ${d.dim(r.evidence.last_seen_at)}`),console.log("")}console.log(d.dim(` ${e.length} proposal${e.length===1?"":"s"}`+(n>0?` \xB7 ${n} skipped (existing alias)`:"")+" \xB7 pass --apply to write via setAlias()")),console.log("")}function ca(e){return e}function pf(e){if(!e||e==="all")return Bt;let t=e.split(",").map(n=>n.trim().toLowerCase()).filter(Boolean),s=[];for(let n of t)if(Bt.includes(n))s.push(n);else return null;return s.length>0?s:null}function gf(e,t){if(e===void 0)return t;let s=Number.parseFloat(e);return Number.isFinite(s)?s:null}function ff(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=uf(e);if(r&&r!==e){let o=t.prepare("SELECT id FROM projects WHERE name = ? LIMIT 1").get(r);if(o)return o.id}return null}w();import{existsSync as da,mkdirSync as _f,readFileSync as hf,writeFileSync as Ef}from"node:fs";import{homedir as bf}from"node:os";import{join as ua}from"node:path";import{z as Je}from"zod";function ma(){return process.env.RECALL_HOME??ua(bf(),".recall")}function Sf(){let e=ma();da(e)||_f(e,{recursive:!0})}function pa(){return ua(ma(),"config.json")}var ga=Je.object({enabled:Je.boolean().default(!1),model:Je.string().optional(),ratePerMinute:Je.number().int().min(1).max(600).default(30),lastProcessedSessionId:Je.string().nullable().default(null),backfillPaused:Je.boolean().default(!1),autoExtractEnabled:Je.boolean().default(!1),autoExtractIntervalMinutes:Je.number().int().min(5).max(720).default(60),autoExtractBatchSize:Je.number().int().min(1).max(20).default(1)}),xs={enabled:!1,ratePerMinute:30,lastProcessedSessionId:null,backfillPaused:!1,autoExtractEnabled:!1,autoExtractIntervalMinutes:60,autoExtractBatchSize:1};function fa(){let e=pa();if(!da(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=fa().semantic;if(!e)return{...xs};let t=ga.safeParse({...xs,...e});return t.success?t.data:{...xs}}function Fe(e){Sf();let t=fa(),s=ga.parse({...xs,...t.semantic??{},...e}),n={...t,semantic:s};return Ef(pa(),JSON.stringify(n,null,2)),Tf(s.enabled),s}function Tf(e){try{_().prepare(`INSERT INTO app_settings(key, value) VALUES ('semantic_enabled', ?)
1088
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value`).run(e?"1":"0")}catch(t){let s=t instanceof Error?t.message:String(t);console.error(`[semantic-config] failed to sync semantic_enabled: ${s}`)}}w();Ge();import{existsSync as Ff,mkdirSync as Uf,writeFileSync as Bf}from"node:fs";import{homedir as Hf}from"node:os";import{join as or}from"node:path";var Wf=1,Xf=12e3,Jf=3,Gf=[];function Yf(){return process.env.RECALL_HOME??or(Hf(),".recall")}function ka(){return or(Yf(),"semantic")}function zf(){let e=ka();Ff(e)||Uf(e,{recursive:!0})}function qf(e){let t=_(),s=t.prepare(`SELECT s.id, s.message_count, s.first_user_message,
1038
1089
  p.name AS project,
1039
1090
  NULLIF(sa.alias, '') AS alias
1040
1091
  FROM sessions s
@@ -1043,10 +1094,10 @@ show full content: recall paste --show <id>
1043
1094
  WHERE s.id = ?`).get(e);if(!s)return null;let n=t.prepare(`SELECT role, content_text
1044
1095
  FROM messages
1045
1096
  WHERE session_id = ? AND is_sidechain = 0
1046
- ORDER BY COALESCE(timestamp, ''), rowid`).all(e),r=[],o=0;for(let i of n){if(!i.content_text)continue;let a=i.role??"system",l=i.content_text.replace(/```[\s\S]*?```/g,"[code]").replace(/<[^>]+>[\s\S]*?<\/[^>]+>/g,"").trim();if(!l)continue;let c=l.length>1500?l.slice(0,1500)+"\u2026":l,u=`${a}: ${c}`;if(o+u.length>kf)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",l=i.content_text.replace(/```[\s\S]*?```/g,"[code]").replace(/<[^>]+>[\s\S]*?<\/[^>]+>/g,"").trim();if(!l)continue;let c=l.length>1500?l.slice(0,1500)+"\u2026":l,u=`${a}: ${c}`;if(o+u.length>Xf)break;r.push(u),o+=u.length}return{id:s.id,alias:s.alias,project:s.project,firstUserMessage:s.first_user_message,excerpt:r.join(`
1047
1098
 
1048
- `),messageCount:s.message_count}}function If(e){return["You are summarizing a Claude Code session for a local semantic-search index. The summary will be stored as plain text and matched against future natural-language queries.","",`Session: ${e.alias??e.id}`,`Project: ${e.project}`,e.firstUserMessage?`Opening prompt: ${e.firstUserMessage}`:"","","Transcript excerpt (truncated):","---",e.excerpt,"---","","Output a single JSON object on one line, with no Markdown fences and no commentary:",'{"summary": "<3 sentences describing what the user was trying to do, what was built or debugged, and the outcome>", "keywords": ["<concept>", "<technology>", "<problem>", ...]}',"","Constraints:","- summary: 3 sentences, plain prose, no bullet points",'- keywords: 10\u201315 lowercase tokens, multi-word entries hyphenated (e.g. "memory-leak"); no duplicates; no generic words like "code" or "session"',"- Output JSON only. Do not echo this prompt."].filter(Boolean).join(`
1049
- `)}function vf(e){let t=e.trim();try{let o=JSON.parse(t);typeof o.result=="string"&&(t=o.result.trim())}catch{}t=t.replace(/^```(?:json)?\s*/i,"").replace(/```\s*$/i,"").trim();let s=t.indexOf("{"),n=t.lastIndexOf("}");if(s===-1||n===-1||n<=s)return null;let r=t.slice(s,n+1);try{let o=JSON.parse(r),i=typeof o.summary=="string"?o.summary.trim():"",l=(Array.isArray(o.keywords)?o.keywords:[]).filter(c=>typeof c=="string").map(c=>c.trim().toLowerCase()).filter(c=>c.length>0&&c.length<64);return!i||l.length===0?null:{summary:i,keywords:Array.from(new Set(l)).slice(0,20)}}catch{return null}}function Mf(e){let t=_(),s=e.keywords.join(",");t.prepare(`INSERT INTO session_semantic
1099
+ `),messageCount:s.message_count}}function Kf(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 Vf(e){let t=e.trim();try{let o=JSON.parse(t);typeof o.result=="string"&&(t=o.result.trim())}catch{}t=t.replace(/^```(?:json)?\s*/i,"").replace(/```\s*$/i,"").trim();let s=t.indexOf("{"),n=t.lastIndexOf("}");if(s===-1||n===-1||n<=s)return null;let r=t.slice(s,n+1);try{let o=JSON.parse(r),i=typeof o.summary=="string"?o.summary.trim():"",l=(Array.isArray(o.keywords)?o.keywords:[]).filter(c=>typeof c=="string").map(c=>c.trim().toLowerCase()).filter(c=>c.length>0&&c.length<64);return!i||l.length===0?null:{summary:i,keywords:Array.from(new Set(l)).slice(0,20)}}catch{return null}}function Zf(e){let t=_(),s=e.keywords.join(",");t.prepare(`INSERT INTO session_semantic
1050
1101
  (session_id, summary, keywords, model, source_message_count, generated_at)
1051
1102
  VALUES (@session_id, @summary, @keywords, @model, @source_message_count, @generated_at)
1052
1103
  ON CONFLICT(session_id) DO UPDATE SET
@@ -1054,19 +1105,23 @@ show full content: recall paste --show <id>
1054
1105
  keywords = excluded.keywords,
1055
1106
  model = excluded.model,
1056
1107
  source_message_count = excluded.source_message_count,
1057
- generated_at = excluded.generated_at`).run({session_id:e.sessionId,summary:e.summary,keywords:s,model:e.model,source_message_count:e.sourceMessageCount,generated_at:e.generatedAt}),Of();let n=er(ba(),`${e.sessionId}.json`);wf(n,JSON.stringify({version:Rf,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 xs=null;function $f(){let t=Ae().ratePerMinute,s=t/6e4;return(!xs||xs.capacity!==t)&&(xs={tokens:t,capacity:t,refillPerMs:s,lastRefill:Date.now()}),xs}function Df(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 jf(e){for(;;){if(e?.aborted)throw new Error("aborted");let t=$f();if(Df(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 Pf(e,t={}){let s=Ae();if(!s.enabled)return{sessionId:e,ok:!1,reason:"disabled"};if(!ce())return{sessionId:e,ok:!1,reason:"claude-cli-missing"};let n=Af(e);if(!n)return{sessionId:e,ok:!1,reason:"session-not-found"};if(n.messageCount<Nf)return{sessionId:e,ok:!1,reason:"too-short"};if(!n.excerpt.trim())return{sessionId:e,ok:!1,reason:"empty-excerpt"};await jf(t.signal);let r=If(n),o=await mt(r,Cf,{model:s.model});if(!o.success)return{sessionId:e,ok:!1,reason:`claude-cli-exit-${o.exitCode??"null"}`,model:s.model??null};let i=vf(o.stdout);return i?(Mf({sessionId:n.id,summary:i.summary,keywords:i.keywords,model:s.model??null,sourceMessageCount:n.messageCount,generatedAt:new Date().toISOString()}),{sessionId:e,ok:!0,model:s.model??null}):{sessionId:e,ok:!1,reason:"parse-failed",model:s.model??null}}async function Rs(e={}){let t=Ae();if(!t.enabled)return{total:0,processed:0,ok:0,failed:0,currentSessionId:null};let s=_(),r={limit:e.limit??1e3},o="s.message_count >= 3";e.force||(o+=" AND ss.session_id IS NULL"),typeof e.projectId=="number"&&(o+=" AND s.project_id = @projectId",r.projectId=e.projectId),t.lastProcessedSessionId&&e.force;let i=s.prepare(`SELECT s.id
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}),zf();let n=or(ka(),`${e.sessionId}.json`);Bf(n,JSON.stringify({version:Wf,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 ks=null;function Qf(){let t=ve().ratePerMinute,s=t/6e4;return(!ks||ks.capacity!==t)&&(ks={tokens:t,capacity:t,refillPerMs:s,lastRefill:Date.now()}),ks}function e_(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=Qf();if(e_(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 s_(e,t={}){let s=ve();if(!s.enabled)return{sessionId:e,ok:!1,reason:"disabled"};if(!ce())return{sessionId:e,ok:!1,reason:"claude-cli-missing"};let n=qf(e);if(!n)return{sessionId:e,ok:!1,reason:"session-not-found"};if(n.messageCount<Jf)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=Kf(n),o=await pt(r,Gf,{model:s.model});if(!o.success)return{sessionId:e,ok:!1,reason:`claude-cli-exit-${o.exitCode??"null"}`,model:s.model??null};let i=Vf(o.stdout);return i?(Zf({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 Ns(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
1058
1109
  FROM sessions s
1059
1110
  LEFT JOIN session_semantic ss ON ss.session_id = s.id
1060
1111
  WHERE ${o}
1061
1112
  ORDER BY COALESCE(s.started_at, '') ASC, s.id ASC
1062
- LIMIT @limit`).all(r),a={total:i.length,processed:0,ok:0,failed:0,currentSessionId:null};e.onProgress?.(a);for(let{id:l}of i){if(e.signal?.aborted||Ae().backfillPaused)break;a.currentSessionId=l,e.onProgress?.({...a});try{(await Pf(l,{signal:e.signal})).ok?a.ok+=1:a.failed+=1}catch(u){a.failed+=1,console.error("[semantic.backfill] failed for",l,u)}a.processed+=1,Pe({lastProcessedSessionId:l}),e.onProgress?.({...a})}return a.currentSessionId=null,e.onProgress?.({...a}),a}function Sa(){let e=Ae(),t=_(),s=t.prepare("SELECT COUNT(*) AS n FROM sessions WHERE message_count >= 3").get().n,n=t.prepare("SELECT COUNT(*) AS n FROM session_semantic").get().n;return{enabled:e.enabled,claudeCliAvailable:ce(),ratePerMinute:e.ratePerMinute,model:e.model??null,totalSessions:s,processedSessions:n,pendingSessions:Math.max(0,s-n),lastProcessedSessionId:e.lastProcessedSessionId,backfillPaused:e.backfillPaused}}Je();Cs();Ve();T();Ve();T();function Na(e){return e.replace(/```json[\s\S]*?```/g,"[tool-call]").replace(/\{[\s\S]{200,}?\}/g,"[json-object]")}function Yf(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=Na(c.content_text??"");if(a+u.length>2e3&&i.length>=3)break;i.push(c),a+=u.length,o++}if(i.length===0)break;let l=i.map(c=>{let u=c.role??"system",p=Na(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:l}of i){if(e.signal?.aborted||ve().backfillPaused)break;a.currentSessionId=l,e.onProgress?.({...a});try{(await s_(l,{signal:e.signal})).ok?a.ok+=1:a.failed+=1}catch(u){a.failed+=1,console.error("[semantic.backfill] failed for",l,u)}a.processed+=1,Fe({lastProcessedSessionId:l}),e.onProgress?.({...a})}return a.currentSessionId=null,e.onProgress?.({...a}),a}function Na(){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:ce(),ratePerMinute:e.ratePerMinute,model:e.model??null,totalSessions:s,processedSessions:n,pendingSessions:Math.max(0,s-n),lastProcessedSessionId:e.lastProcessedSessionId,backfillPaused:e.backfillPaused}}Ge();As();Ve();w();Ve();w();function Ma(e){return e.replace(/```json[\s\S]*?```/g,"[tool-call]").replace(/\{[\s\S]{200,}?\}/g,"[json-object]")}function m_(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=Ma(c.content_text??"");if(a+u.length>2e3&&i.length>=3)break;i.push(c),a+=u.length,o++}if(i.length===0)break;let l=i.map(c=>{let u=c.role??"system",m=Ma(c.content_text??"");return`[${u}] ${m}`}).join(`
1063
1114
 
1064
- `);t.push({messageUuids:i.map(c=>c.uuid),text:l}),o<e.length&&i.length>=3&&(o=Math.max(o-1,o-1))}return t}function ar(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 Yf(s)}var qf=!1,Kf=null;function Vf(){return _().prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}function Ca(){return{running:qf,queueDepth:Vf(),lastProcessedAt:Kf}}T();_e();async function Aa(e,t){let s=(e??"status").toLowerCase();if(s==="on"||s==="enable"){if(!ce()){console.error("claude CLI not found on PATH. Install Claude Code first, then re-run."),process.exitCode=1;return}let l={enabled:!0};t.rate&&(l.ratePerMinute=Number(t.rate)),t.model&&(l.model=t.model);let c=Pe(l);console.log("Semantic search: ENABLED"),console.log(` Rate: ${c.ratePerMinute}/min`),c.model&&console.log(` Model: ${c.model}`),console.log(""),console.log("Disclosure: enabling semantic search sends condensed session"),console.log("summaries to Claude via your local `claude` CLI using your existing"),console.log("plan. New sessions are summarized on close. Run `recall semantic backfill`"),console.log("to summarize the existing archive.");return}if(s==="off"||s==="disable"){Pe({enabled:!1}),console.log("Semantic search: DISABLED"),console.log("Existing summaries are kept in the database; the pipeline will not run.");return}if(s==="pause"){Pe({backfillPaused:!0}),console.log("Backfill paused. Resume with `recall semantic resume`.");return}if(s==="resume"){Pe({backfillPaused:!1}),console.log("Backfill resumed.");return}if(s==="backfill"){let l=Ae();if(!l.enabled){console.error("Semantic search is disabled. Run `recall semantic on` first."),process.exitCode=1;return}l.backfillPaused&&Pe({backfillPaused:!1});let c=t.limit?Math.max(1,Number(t.limit)):1e3,u=!!t.force;console.log(`Backfilling up to ${c} sessions${u?" (force)":""}\u2026`);let p=Date.now(),m=0,f=await Rs({limit:c,force:u,onProgress:h=>{if(h.processed===m)return;m=h.processed;let E=h.total>0?` (${Math.round(h.processed/h.total*100)}%)`:"";process.stdout.write(`\r ${h.processed}/${h.total}${E} ok=${h.ok} failed=${h.failed} `)}});process.stdout.write(`
1065
- `);let g=((Date.now()-p)/1e3).toFixed(1);console.log(`Done in ${g}s \u2014 processed=${f.processed} ok=${f.ok} failed=${f.failed}`);return}if(s==="install"){let{ensureTransformersInstalled:l}=await Promise.resolve().then(()=>(Oa(),La)),c=await l();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."),gt()?console.log("Model already installed."):(console.log("Downloading bge-base-en-v1.5 (~110MB)..."),await nr((u,p,m)=>{let f=m>0?Math.round(p/m*100):0;process.stdout.write(`\r ${u}: ${f}% `)}),process.stdout.write(`
1115
+ `);t.push({messageUuids:i.map(c=>c.uuid),text:l}),o<e.length&&i.length>=3&&(o=Math.max(o-1,o-1))}return t}function mr(e){let s=_().prepare("SELECT uuid, role, content_text FROM messages WHERE session_id = ? AND is_sidechain = 0 AND content_text IS NOT NULL ORDER BY rowid").all(e);return m_(s)}var p_=!1,g_=null;function f_(){return _().prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}function Da(){return{running:p_,queueDepth:f_(),lastProcessedAt:g_}}w();_e();async function Pa(e,t){let s=(e??"status").toLowerCase();if(s==="on"||s==="enable"){if(!ce()){console.error("claude CLI not found on PATH. Install Claude Code first, then re-run."),process.exitCode=1;return}let l={enabled:!0};t.rate&&(l.ratePerMinute=Number(t.rate)),t.model&&(l.model=t.model);let c=Fe(l);console.log("Semantic search: ENABLED"),console.log(` Rate: ${c.ratePerMinute}/min`),c.model&&console.log(` Model: ${c.model}`),console.log(""),console.log("Disclosure: enabling semantic search sends condensed session"),console.log("summaries to Claude via your local `claude` CLI using your existing"),console.log("plan. New sessions are summarized on close. Run `recall semantic backfill`"),console.log("to summarize the existing archive.");return}if(s==="off"||s==="disable"){Fe({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"){Fe({backfillPaused:!0}),console.log("Backfill paused. Resume with `recall semantic resume`.");return}if(s==="resume"){Fe({backfillPaused:!1}),console.log("Backfill resumed.");return}if(s==="backfill"){let l=ve();if(!l.enabled){console.error("Semantic search is disabled. Run `recall semantic on` first."),process.exitCode=1;return}l.backfillPaused&&Fe({backfillPaused:!1});let c=t.limit?Math.max(1,Number(t.limit)):1e3,u=!!t.force;console.log(`Backfilling up to ${c} sessions${u?" (force)":""}\u2026`);let m=Date.now(),p=0,f=await Ns({limit:c,force:u,onProgress:h=>{if(h.processed===p)return;p=h.processed;let E=h.total>0?` (${Math.round(h.processed/h.total*100)}%)`:"";process.stdout.write(`\r ${h.processed}/${h.total}${E} ok=${h.ok} failed=${h.failed} `)}});process.stdout.write(`
1116
+ `);let g=((Date.now()-m)/1e3).toFixed(1);console.log(`Done in ${g}s \u2014 processed=${f.processed} ok=${f.ok} failed=${f.failed}`);return}if(s==="install"){let{ensureTransformersInstalled:l}=await Promise.resolve().then(()=>(ja(),$a)),c=await l();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."),gt()?console.log("Model already installed."):(console.log("Downloading bge-base-en-v1.5 (~110MB)..."),await cr((u,m,p)=>{let f=p>0?Math.round(m/p*100):0;process.stdout.write(`\r ${u}: ${f}% `)}),process.stdout.write(`
1066
1117
  `)),console.log("Loading embedder...");try{await Ke(),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(`
1067
- `)[0]:String(u)}`),console.log(" Vector features remain available; runtime load happens on first use.")}return}if(s==="uninstall"){rr(),console.log("Model removed. Vector search will fall back to keyword search.");return}if(s==="auto-extract"){let l=t._autoExtractAction;if(l==="on"||l==="enable"){let c=Pe({autoExtractEnabled:!0});console.log("Auto-extract: ENABLED"),console.log(` Cadence: 1 batch every ${c.autoExtractIntervalMinutes} minutes`),console.log(` Batch size: ${c.autoExtractBatchSize} session(s) per tick`),console.log(" Honors your 5-hour Claude plan window \u2014 at 60min/1, that is"),console.log(" ~5 extractions per window, leaving 95%+ of the rate budget free."),console.log(" The daemon will start nibbling through un-extracted sessions on"),console.log(" the next tick (within 15 minutes). Status: `recall semantic status`.");return}if(l==="off"||l==="disable"){Pe({autoExtractEnabled:!1}),console.log("Auto-extract: DISABLED. The daemon will stop running extract-outputs.");return}console.error("Usage: recall semantic auto-extract <on|off>"),process.exitCode=1;return}if(s==="reindex"){if(await Ce("Vector reindex"),!Ge().loaded){if(!gt()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}await Ke()}let l=_(),c=l.prepare("SELECT id FROM sessions WHERE message_count >= 3").all();console.log(`Reindexing ${c.length} sessions...`);let u=0;for(let{id:p}of c){let m=ar(p);if(m.length===0){u++;continue}let f=m.map(b=>b.text),g=await ft(f);l.prepare("DELETE FROM vec_chunks WHERE rowid IN (SELECT rowid FROM chunk_meta WHERE session_id = ?)").run(p),l.prepare("DELETE FROM chunk_meta WHERE session_id = ?").run(p);let h=l.prepare(`INSERT INTO chunk_meta(session_id, message_uuids, text, embedding_model_id, embedding_dim, stale, generated_at)
1068
- VALUES (?, ?, ?, 'bge-base-en-v1.5', 768, 0, datetime('now'))`),E=l.prepare("INSERT INTO vec_chunks(rowid, embedding) VALUES (?, ?)");for(let b=0;b<m.length;b++){let S=h.run(p,JSON.stringify(m[b].messageUuids),m[b].text),C=Buffer.from(g[b].buffer,g[b].byteOffset,g[b].byteLength);E.run(S.lastInsertRowid,C)}u++,u%10===0&&process.stdout.write(`\r ${u}/${c.length} `)}process.stdout.write(`
1069
- `),console.log(`Reindexed ${u} sessions.`);return}let n=Sa();console.log(`Semantic search: ${n.enabled?"ENABLED":"disabled"}`),console.log(` claude CLI: ${n.claudeCliAvailable?"available":"NOT FOUND"}`),console.log(` Rate: ${n.ratePerMinute}/min`),console.log(` Model: ${n.model??"claude default"}`),console.log(` Sessions: ${n.processedSessions}/${n.totalSessions} summarized`),console.log(` Pending: ${n.pendingSessions}`),n.lastProcessedSessionId&&console.log(` Cursor: ${n.lastProcessedSessionId}`),n.backfillPaused&&console.log(" Backfill: PAUSED (run `recall semantic resume`)");let r=gt(),o=Ge(),i=Ca(),a=Ae();console.log(""),console.log("Vector tier (Pro):"),console.log(` Model: ${r?"installed":"not installed"}`),console.log(` Embedder: ${o.loaded?"loaded":"not loaded"} (${o.modelId}, ${o.dim}d)`),console.log(` Worker: ${i.running?"running":"stopped"} (queue: ${i.queueDepth})`),console.log(""),console.log("Auto-extract:"),console.log(` Enabled: ${a.autoExtractEnabled?"YES":"no"}`),a.autoExtractEnabled?console.log(` Cadence: 1 batch every ${a.autoExtractIntervalMinutes} min \xD7 ${a.autoExtractBatchSize} session(s)`):console.log(" Run `recall semantic auto-extract on` to populate Patterns / Galaxy automatically."),process.env.RECALL_RRF_K&&console.log(` RRF k: ${process.env.RECALL_RRF_K}`)}T();T();T();Ve();var Ze=400,Os=768,c_="bge-base-en-v1.5";function l_(e){return Buffer.from(e.buffer,e.byteOffset,e.byteLength)}function d_(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!==Os)throw new Error(`embedding dim mismatch: got ${e.embedding.length}, expected ${Os}`);let t=e.embedding_model_id??c_,s=new Date().toISOString();return _().prepare(`INSERT INTO message_embeddings
1118
+ `)[0]:String(u)}`),console.log(" Vector features remain available; runtime load happens on first use.")}return}if(s==="uninstall"){lr(),console.log("Model removed. Vector search will fall back to keyword search.");return}if(s==="auto-extract"){let l=t._autoExtractAction;if(l==="on"||l==="enable"){let c=Fe({autoExtractEnabled:!0});console.log("Auto-extract: ENABLED"),console.log(` Cadence: 1 batch every ${c.autoExtractIntervalMinutes} minutes`),console.log(` Batch size: ${c.autoExtractBatchSize} session(s) per tick`),console.log(" Honors your 5-hour Claude plan window \u2014 at 60min/1, that is"),console.log(" ~5 extractions per window, leaving 95%+ of the rate budget free."),console.log(" The daemon will start nibbling through un-extracted sessions on"),console.log(" the next tick (within 15 minutes). Status: `recall semantic status`.");return}if(l==="off"||l==="disable"){Fe({autoExtractEnabled:!1}),console.log("Auto-extract: DISABLED. The daemon will stop running extract-outputs.");return}console.error("Usage: recall semantic auto-extract <on|off>"),process.exitCode=1;return}if(s==="reindex"){if(await Ce("Vector reindex"),!Ye().loaded){if(!gt()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}await Ke()}let l=_(),c=l.prepare(`
1119
+ SELECT s.id FROM sessions s
1120
+ WHERE s.message_count >= 3
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"),m=u>0?` (cap ${u} chunks/session)`:" (no cap)";console.log(`Reindexing ${c.length} sessions (skipping already-indexed)${m}...`);let p=0;for(let{id:f}of c){let g=mr(f),h=u>0?g.slice(0,u):g;if(h.length===0){p++;continue}let E=h.map(y=>y.text),b=await ft(E);l.prepare("DELETE FROM vec_chunks WHERE rowid IN (SELECT rowid FROM chunk_meta WHERE session_id = ?)").run(f),l.prepare("DELETE FROM chunk_meta WHERE session_id = ?").run(f);let S=l.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'))`),N=l.prepare("INSERT INTO vec_chunks(rowid, embedding) VALUES (?, ?)");for(let y=0;y<h.length;y++){let C=S.run(f,JSON.stringify(h[y].messageUuids),h[y].text),q=Buffer.from(b[y].buffer,b[y].byteOffset,b[y].byteLength);N.run(BigInt(C.lastInsertRowid),q)}p++,p%10===0&&process.stdout.write(`\r ${p}/${c.length} `)}process.stdout.write(`
1124
+ `),console.log(`Reindexed ${p} sessions.`);return}let n=Na();console.log(`Semantic search: ${n.enabled?"ENABLED":"disabled"}`),console.log(` claude CLI: ${n.claudeCliAvailable?"available":"NOT FOUND"}`),console.log(` Rate: ${n.ratePerMinute}/min`),console.log(` Model: ${n.model??"claude default"}`),console.log(` Sessions: ${n.processedSessions}/${n.totalSessions} summarized`),console.log(` Pending: ${n.pendingSessions}`),n.lastProcessedSessionId&&console.log(` Cursor: ${n.lastProcessedSessionId}`),n.backfillPaused&&console.log(" Backfill: PAUSED (run `recall semantic resume`)");let r=gt(),o=Ye(),i=Da(),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}`)}w();w();w();Ve();var Ze=400,vs=768,k_="bge-base-en-v1.5";function N_(e){return Buffer.from(e.buffer,e.byteOffset,e.byteLength)}function L_(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!==vs)throw new Error(`embedding dim mismatch: got ${e.embedding.length}, expected ${vs}`);let t=e.embedding_model_id??k_,s=new Date().toISOString();return _().prepare(`INSERT INTO message_embeddings
1070
1125
  (message_uuid, session_id, embedding,
1071
1126
  embedding_model_id, embedding_dim, text_length, generated_at)
1072
1127
  VALUES (?, ?, ?, ?, ?, ?, ?)
@@ -1076,7 +1131,7 @@ show full content: recall paste --show <id>
1076
1131
  embedding_model_id = excluded.embedding_model_id,
1077
1132
  embedding_dim = excluded.embedding_dim,
1078
1133
  text_length = excluded.text_length,
1079
- generated_at = excluded.generated_at`).run(e.message_uuid,e.session_id,l_(e.embedding),t,Os,e.text_length,s),{message_uuid:e.message_uuid,session_id:e.session_id,embedding_model_id:t,embedding_dim:Os,text_length:e.text_length,generated_at:s}}function u_(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,N_(e.embedding),t,vs,e.text_length,s),{message_uuid:e.message_uuid,session_id:e.session_id,embedding_model_id:t,embedding_dim:vs,text_length:e.text_length,generated_at:s}}function C_(e,t={}){let s=_(),n=t.force?`m.session_id = ? AND m.is_sidechain = 0
1080
1135
  AND m.content_text IS NOT NULL
1081
1136
  AND length(m.content_text) > ?`:`m.session_id = ? AND m.is_sidechain = 0
1082
1137
  AND m.content_text IS NOT NULL
@@ -1086,7 +1141,7 @@ show full content: recall paste --show <id>
1086
1141
  LEFT JOIN message_embeddings me ON me.message_uuid = m.uuid
1087
1142
  WHERE ${n}
1088
1143
  ORDER BY m.timestamp ASC, m.rowid ASC
1089
- LIMIT ?`).all(e,Ze,r)}var Ia=null;async function p_(){return Ia||(Ge().loaded||await Ke(),ft)}async function m_(e,t={}){let s={embedded:0,skipped:0,failed:0,failures:[]},n=u_(e,{limit:t.limit,force:t.force});if(n.length===0)return s;let r=await p_(),o=n.map(a=>a.content_text),i;try{if(t.signal?.aborted)return s;i=await r(o)}catch(a){return s.failed=n.length,s.failures=n.map(l=>({uuid:l.uuid,error:a instanceof Error?a.message:String(a)})),s}if(i.length!==n.length)return s.failed=n.length,s.failures=n.map(a=>({uuid:a.uuid,error:`embedder returned ${i.length} vectors for ${n.length} inputs`})),s;for(let a=0;a<n.length&&!t.signal?.aborted;a++)try{d_({message_uuid:n[a].uuid,session_id:n[a].session_id,embedding:i[a],text_length:o[a].length}),s.embedded+=1}catch(l){s.failed+=1,s.failures.push({uuid:n[a].uuid,error:l instanceof Error?l.message:String(l)})}return s.skipped=0,s}async function va(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,Ze,r)}var Fa=null;async function A_(){return Fa||(Ye().loaded||await Ke(),ft)}async function O_(e,t={}){let s={embedded:0,skipped:0,failed:0,failures:[]},n=C_(e,{limit:t.limit,force:t.force});if(n.length===0)return s;let r=await A_(),o=n.map(a=>a.content_text),i;try{if(t.signal?.aborted)return s;i=await r(o)}catch(a){return s.failed=n.length,s.failures=n.map(l=>({uuid:l.uuid,error:a instanceof Error?a.message:String(a)})),s}if(i.length!==n.length)return s.failed=n.length,s.failures=n.map(a=>({uuid:a.uuid,error:`embedder returned ${i.length} vectors for ${n.length} inputs`})),s;for(let a=0;a<n.length&&!t.signal?.aborted;a++)try{L_({message_uuid:n[a].uuid,session_id:n[a].session_id,embedding:i[a],text_length:o[a].length}),s.embedded+=1}catch(l){s.failed+=1,s.failures.push({uuid:n[a].uuid,error:l instanceof Error?l.message:String(l)})}return s.skipped=0,s}async function Ua(e={}){let t=_(),s=[],n="s.message_count >= 1";typeof e.projectId=="number"&&(n+=" AND s.project_id = ?",s.push(e.projectId));let r=t.prepare(`SELECT DISTINCT s.id AS id
1090
1145
  FROM sessions s
1091
1146
  JOIN messages m ON m.session_id = s.id
1092
1147
  LEFT JOIN message_embeddings me ON me.message_uuid = m.uuid
@@ -1096,7 +1151,7 @@ show full content: recall paste --show <id>
1096
1151
  AND length(m.content_text) > ?
1097
1152
  AND me.message_uuid IS NULL
1098
1153
  ORDER BY s.started_at ASC
1099
- LIMIT ?`).all(...s,Ze,e.limitSessions??1e3),o={total_sessions:r.length,processed_sessions:0,embedded_messages:0,failed_messages:0,current_session_id:null};e.onProgress?.({...o});for(let{id:i}of r){if(e.signal?.aborted)break;o.current_session_id=i,e.onProgress?.({...o});let a=await m_(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 As(e,t){return t===0?0:Math.round(e/t*1e3)/10}function he(e){return _().prepare("SELECT id, name FROM projects WHERE name = ? LIMIT 1").get(e)??null}function Ma(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=he(e.projectName));let n=s?" WHERE s.project_id = ?":"",r=s?[s.id]:[],o=t.prepare(`SELECT
1154
+ LIMIT ?`).all(...s,Ze,e.limitSessions??1e3),o={total_sessions:r.length,processed_sessions:0,embedded_messages:0,failed_messages:0,current_session_id:null};e.onProgress?.({...o});for(let{id:i}of r){if(e.signal?.aborted)break;o.current_session_id=i,e.onProgress?.({...o});let a=await O_(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 Is(e,t){return t===0?0:Math.round(e/t*1e3)/10}function he(e){return _().prepare("SELECT id, name FROM projects WHERE name = ? LIMIT 1").get(e)??null}function Ba(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=he(e.projectName));let n=s?" WHERE s.project_id = ?":"",r=s?[s.id]:[],o=t.prepare(`SELECT
1100
1155
  COUNT(*) AS total,
1101
1156
  SUM(CASE WHEN ss.session_id IS NOT NULL THEN 1 ELSE 0 END) AS with_semantic,
1102
1157
  SUM(CASE WHEN cm_count.session_id IS NOT NULL THEN 1 ELSE 0 END) AS with_chunks,
@@ -1109,7 +1164,7 @@ show full content: recall paste --show <id>
1109
1164
  LEFT JOIN (
1110
1165
  SELECT DISTINCT session_id FROM message_embeddings
1111
1166
  ) me_count ON me_count.session_id = s.id
1112
- ${n}`).get(...r),i=o.total??0,a=o.with_semantic??0,l=o.with_chunks??0,c=o.with_msg_emb??0,u=s?" JOIN sessions s ON s.id = m.session_id WHERE s.project_id = ?":"",p=t.prepare(`SELECT
1167
+ ${n}`).get(...r),i=o.total??0,a=o.with_semantic??0,l=o.with_chunks??0,c=o.with_msg_emb??0,u=s?" JOIN sessions s ON s.id = m.session_id WHERE s.project_id = ?":"",m=t.prepare(`SELECT
1113
1168
  COUNT(*) AS total,
1114
1169
  SUM(CASE
1115
1170
  WHEN m.is_sidechain = 0
@@ -1117,15 +1172,15 @@ show full content: recall paste --show <id>
1117
1172
  AND length(m.content_text) > ${Ze}
1118
1173
  THEN 1 ELSE 0 END) AS eligible
1119
1174
  FROM messages m
1120
- ${u}`).get(...r),m=s?" JOIN sessions s ON s.id = me.session_id WHERE s.project_id = ?":"",f=t.prepare(`SELECT COUNT(*) AS embedded
1175
+ ${u}`).get(...r),p=s?" JOIN sessions s ON s.id = me.session_id WHERE s.project_id = ?":"",f=t.prepare(`SELECT COUNT(*) AS embedded
1121
1176
  FROM message_embeddings me
1122
- ${m}`).get(...r),g=s?" JOIN sessions s ON s.id = cm.session_id WHERE s.project_id = ?":"",h=t.prepare(`SELECT COUNT(*) AS n
1177
+ ${p}`).get(...r),g=s?" JOIN sessions s ON s.id = cm.session_id WHERE s.project_id = ?":"",h=t.prepare(`SELECT COUNT(*) AS n
1123
1178
  FROM chunk_meta cm
1124
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
1125
1180
  FROM chunk_queue cq
1126
- ${E}`).get(...r);return{project:s,sessions:{total:i,with_semantic:a,with_semantic_pct:As(a,i),with_chunks:l,with_chunks_pct:As(l,i),with_message_embeddings:c,with_message_embeddings_pct:As(c,i)},messages:{total:p.total??0,eligible:p.eligible??0,embedded:f.embedded,embedded_pct:As(f.embedded,p.eligible??0),threshold_chars:Ze},chunks:{chunk_meta_rows:h.n,chunk_queue_pending:b.n},generated_at:new Date().toISOString()}}function $a(e){let s=e.sessions.with_semantic_pct,n=e.sessions.total-e.sessions.with_semantic,r=e.sessions.total>0&&s>=95,o=r?`${s}% session_semantic coverage (${e.sessions.with_semantic} of ${e.sessions.total})`:e.sessions.total===0?"no sessions in scope":`${s}% session_semantic coverage (need \u226595%); ${n} sessions missing summaries`;return{passes:r,required_pct:95,actual_pct:s,missing_sessions:n,reason:o}}_e();Cs();Ve();async function Da(e,t){let s=(e??"audit").toLowerCase();if(s==="audit")return g_(t);if(s==="backfill-summaries")return __(t);if(s==="backfill-messages")return h_(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=he(e);return t||"not-found"}async function g_(e){let t=cr(e.project);if(t==="not-found"){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let s=Ma({projectId:t?t.id:void 0}),n=$a(s);if(e.json){console.log(JSON.stringify({report:s,verdict:n},null,2));return}f_(s,n),n.passes||(process.exitCode=1)}function f_(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 __(e){if(!Ae().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 Rs({limit:n,projectId:s?s.id:void 0,onProgress:c=>{if(e.json||c.processed===i)return;i=c.processed;let u=c.total>0?` (${Math.round(c.processed/c.total*100)}%)`:"";process.stdout.write(`\r ${c.processed}/${c.total}${u} ok=${c.ok} failed=${c.failed} `)}});e.json||process.stdout.write(`
1127
- `);let l=((Date.now()-o)/1e3).toFixed(1);e.json?console.log(JSON.stringify({...a,elapsed_seconds:Number(l)},null,2)):console.log(`Done in ${l}s \u2014 processed=${a.processed} ok=${a.ok} failed=${a.failed}`)}async function h_(e){if(await Ce("Per-message embeddings"),!gt()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}Ge().loaded||await Ke();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 > ${Ze} chars \u2014 ${n} \u2014 up to ${s} sessions\u2026`);let r=Date.now(),o=0,i=await va({projectId:t?t.id:void 0,limitSessions:s,onProgress:m=>{if(e.json||m.processed_sessions===o)return;o=m.processed_sessions;let f=m.total_sessions>0?` (${Math.round(m.processed_sessions/m.total_sessions*100)}%)`:"";process.stdout.write(`\r ${m.processed_sessions}/${m.total_sessions} sessions${f} embedded=${m.embedded_messages} failed=${m.failed_messages} `)}});e.json||process.stdout.write(`
1128
- `);let a=((Date.now()-r)/1e3).toFixed(1);e.json?console.log(JSON.stringify({...i,elapsed_seconds:Number(a)},null,2)):console.log(`Done in ${a}s \u2014 sessions=${i.processed_sessions}/${i.total_sessions} embedded=${i.embedded_messages} failed=${i.failed_messages}`);let l=_(),c=t?" AND s.project_id = ?":"",u=t?[t.id]:[],p=l.prepare(`SELECT COUNT(DISTINCT s.id) AS n
1181
+ ${E}`).get(...r);return{project:s,sessions:{total:i,with_semantic:a,with_semantic_pct:Is(a,i),with_chunks:l,with_chunks_pct:Is(l,i),with_message_embeddings:c,with_message_embeddings_pct:Is(c,i)},messages:{total:m.total??0,eligible:m.eligible??0,embedded:f.embedded,embedded_pct:Is(f.embedded,m.eligible??0),threshold_chars:Ze},chunks:{chunk_meta_rows:h.n,chunk_queue_pending:b.n},generated_at:new Date().toISOString()}}function Ha(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}}_e();As();Ve();async function Wa(e,t){let s=(e??"audit").toLowerCase();if(s==="audit")return v_(t);if(s==="backfill-summaries")return M_(t);if(s==="backfill-messages")return D_(t);console.error(`Unknown embeddings action: ${e}. Supported: audit | backfill-summaries | backfill-messages`),process.exitCode=1}function pr(e){if(!e)return null;let t=he(e);return t||"not-found"}async function v_(e){let t=pr(e.project);if(t==="not-found"){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let s=Ba({projectId:t?t.id:void 0}),n=Ha(s);if(e.json){console.log(JSON.stringify({report:s,verdict:n},null,2));return}I_(s,n),n.passes||(process.exitCode=1)}function I_(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 M_(e){if(!ve().enabled){console.error("Semantic search is disabled. Run `recall semantic on` first."),process.exitCode=1;return}let s=pr(e.project);if(s==="not-found"){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let n=e.limit?Math.max(1,Number(e.limit)):1e3,r=s?`project "${s.name}"`:"all projects";console.log(`Backfilling session_semantic \u2014 ${r} \u2014 up to ${n} sessions\u2026`);let o=Date.now(),i=0,a=await Ns({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 l=((Date.now()-o)/1e3).toFixed(1);e.json?console.log(JSON.stringify({...a,elapsed_seconds:Number(l)},null,2)):console.log(`Done in ${l}s \u2014 processed=${a.processed} ok=${a.ok} failed=${a.failed}`)}async function D_(e){if(await Ce("Per-message embeddings"),!gt()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}Ye().loaded||await Ke();let t=pr(e.project);if(t==="not-found"){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let s=e.limit?Math.max(1,Number(e.limit)):200,n=t?`project "${t.name}"`:"all projects";console.log(`Embedding messages > ${Ze} chars \u2014 ${n} \u2014 up to ${s} sessions\u2026`);let r=Date.now(),o=0,i=await Ua({projectId:t?t.id:void 0,limitSessions:s,onProgress:p=>{if(e.json||p.processed_sessions===o)return;o=p.processed_sessions;let f=p.total_sessions>0?` (${Math.round(p.processed_sessions/p.total_sessions*100)}%)`:"";process.stdout.write(`\r ${p.processed_sessions}/${p.total_sessions} sessions${f} embedded=${p.embedded_messages} failed=${p.failed_messages} `)}});e.json||process.stdout.write(`
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 l=_(),c=t?" AND s.project_id = ?":"",u=t?[t.id]:[],m=l.prepare(`SELECT COUNT(DISTINCT s.id) AS n
1129
1184
  FROM sessions s
1130
1185
  JOIN messages m ON m.session_id = s.id
1131
1186
  LEFT JOIN message_embeddings me ON me.message_uuid = m.uuid
@@ -1133,7 +1188,7 @@ show full content: recall paste --show <id>
1133
1188
  AND m.content_text IS NOT NULL
1134
1189
  AND length(m.content_text) > ?
1135
1190
  AND me.message_uuid IS NULL
1136
- ${c}`).get(Ze,...u);p.n>0&&console.log(` ${p.n} session(s) still have unembedded eligible messages. Re-run to continue.`)}T();Je();import{createHash as x_}from"node:crypto";T();j();import{writeFileSync as E_,readFileSync as $N,existsSync as b_,mkdirSync as S_,readdirSync as DN}from"node:fs";import{join as ja}from"node:path";var lr=ja(x,"output-index");function y_(){P(),b_(lr)||S_(lr,{recursive:!0})}function Xt(e){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}function T_(e){if(!e)return null;try{return JSON.parse(e)}catch{return e}}function Pa(e){return{session_id:e.session_id,files_written:Xt(e.files_written),brands_mentioned:Xt(e.brands_mentioned),terms_introduced:Xt(e.terms_introduced),plan_ids_referenced:Xt(e.plan_ids_referenced),bug_signatures:Xt(e.bug_signatures),raw_extraction:T_(e.raw_extraction),extracted_at:e.extracted_at,extractor_version:e.extractor_version}}function Fa(e){if(!e.session_id)throw new Error("session_id is required");let t=_(),s=new Date().toISOString(),n=JSON.stringify(e.files_written??[]),r=JSON.stringify(e.brands_mentioned??[]),o=JSON.stringify(e.terms_introduced??[]),i=JSON.stringify(e.plan_ids_referenced??[]),a=JSON.stringify(e.bug_signatures??[]),l=e.raw_extraction===void 0?null:JSON.stringify(e.raw_extraction),c=Math.max(1,Math.floor(e.extractor_version??1));t.prepare(`INSERT INTO session_output_index
1191
+ ${c}`).get(Ze,...u);m.n>0&&console.log(` ${m.n} session(s) still have unembedded eligible messages. Re-run to continue.`)}w();import{createHash as H_}from"node:crypto";Ge();w();P();import{writeFileSync as $_,readFileSync as dL,existsSync as j_,mkdirSync as P_,readdirSync as uL}from"node:fs";import{join as Xa}from"node:path";var gr=Xa(x,"output-index");function F_(){j(),j_(gr)||P_(gr,{recursive:!0})}function Jt(e){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}function U_(e){if(!e)return null;try{return JSON.parse(e)}catch{return e}}function Ja(e){return{session_id:e.session_id,files_written:Jt(e.files_written),brands_mentioned:Jt(e.brands_mentioned),terms_introduced:Jt(e.terms_introduced),plan_ids_referenced:Jt(e.plan_ids_referenced),bug_signatures:Jt(e.bug_signatures),raw_extraction:U_(e.raw_extraction),extracted_at:e.extracted_at,extractor_version:e.extractor_version}}function Ga(e){if(!e.session_id)throw new Error("session_id is required");let t=_(),s=new Date().toISOString(),n=JSON.stringify(e.files_written??[]),r=JSON.stringify(e.brands_mentioned??[]),o=JSON.stringify(e.terms_introduced??[]),i=JSON.stringify(e.plan_ids_referenced??[]),a=JSON.stringify(e.bug_signatures??[]),l=e.raw_extraction===void 0?null:JSON.stringify(e.raw_extraction),c=Math.max(1,Math.floor(e.extractor_version??1));t.prepare(`INSERT INTO session_output_index
1137
1192
  (session_id, files_written, brands_mentioned, terms_introduced,
1138
1193
  plan_ids_referenced, bug_signatures, raw_extraction,
1139
1194
  extracted_at, extractor_version)
@@ -1146,7 +1201,7 @@ show full content: recall paste --show <id>
1146
1201
  bug_signatures = excluded.bug_signatures,
1147
1202
  raw_extraction = excluded.raw_extraction,
1148
1203
  extracted_at = excluded.extracted_at,
1149
- extractor_version = excluded.extractor_version`).run(e.session_id,n,r,o,i,a,l,s,c);let u=t.prepare("SELECT * FROM session_output_index WHERE session_id = ?").get(e.session_id);if(!u)throw new Error("setOutputIndex succeeded but read-back failed");let p=Pa(u);return w_(e.session_id),p}function Jt(e){let s=_().prepare("SELECT * FROM session_output_index WHERE session_id = ?").get(e);return s?Pa(s):null}function w_(e){try{y_();let t=Jt(e);if(!t)return;let s=ja(lr,`${e}.json`),n={schema:"claude-recall.session-output-index.v1",backed_up_at:new Date().toISOString(),...t};E_(s,JSON.stringify(n,null,2))}catch(t){console.error("[output-index] backup failed:",t)}}var Gt=1,pr="claude-haiku-4-5-20251001",R_=3,k_=32e3,Ua=2e3,N_=30,C_=30,L_=30,O_=30;function A_(e){let s=_().prepare(`SELECT s.id,
1204
+ extractor_version = excluded.extractor_version`).run(e.session_id,n,r,o,i,a,l,s,c);let u=t.prepare("SELECT * FROM session_output_index WHERE session_id = ?").get(e.session_id);if(!u)throw new Error("setOutputIndex succeeded but read-back failed");let m=Ja(u);return B_(e.session_id),m}function Gt(e){let s=_().prepare("SELECT * FROM session_output_index WHERE session_id = ?").get(e);return s?Ja(s):null}function B_(e){try{F_();let t=Gt(e);if(!t)return;let s=Xa(gr,`${e}.json`),n={schema:"claude-recall.session-output-index.v1",backed_up_at:new Date().toISOString(),...t};$_(s,JSON.stringify(n,null,2))}catch(t){console.error("[output-index] backup failed:",t)}}var Yt=1,hr="claude-haiku-4-5-20251001",W_=3,X_=32e3,Ya=2e3,J_=30,G_=30,Y_=30,z_=30;function q_(e){let s=_().prepare(`SELECT s.id,
1150
1205
  NULLIF(sa.alias, '') AS alias,
1151
1206
  s.auto_title,
1152
1207
  s.auto_title_source,
@@ -1157,15 +1212,15 @@ show full content: recall paste --show <id>
1157
1212
  FROM sessions s
1158
1213
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1159
1214
  LEFT JOIN projects p ON p.id = s.project_id
1160
- WHERE s.id = ?`).get(e);return s?{...s,alias_source:s.alias?"manual":null}:null}function Ba(e,t={}){if(e.message_count<R_)return{eligible:!1,reason:"too-short"};let s=e.title_quality;if(s==="programmatic"||s==="recursive_meta")return{eligible:!1,reason:"low-signal-title"};if(e.auto_title_source==="agent"&&!e.alias)return{eligible:!1,reason:"agent-titled-no-override"};if(!t.force){let n=Jt(e.id);if(n&&n.extractor_version>=Gt)return{eligible:!1,reason:"already-extracted"}}return{eligible:!0}}function I_(e){let t=A_(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 za(e,t={}){if(e.message_count<W_)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=Gt(e.id);if(n&&n.extractor_version>=Yt)return{eligible:!1,reason:"already-extracted"}}return{eligible:!0}}function K_(e){let t=q_(e);if(!t)return null;let n=_().prepare(`SELECT role, content_text
1161
1216
  FROM messages
1162
1217
  WHERE session_id = ?
1163
1218
  AND is_sidechain = 0
1164
1219
  AND content_text IS NOT NULL
1165
- ORDER BY COALESCE(timestamp, ''), rowid`).all(e),r=[],o=0;for(let i of n){let a=i.role??"system",l=i.content_text.trim();if(!l)continue;let c=l.length>Ua?l.slice(0,Ua)+"\u2026":l,u=`${a}: ${c}`;if(o+u.length>k_)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",l=i.content_text.trim();if(!l)continue;let c=l.length>Ya?l.slice(0,Ya)+"\u2026":l,u=`${a}: ${c}`;if(o+u.length>X_)break;r.push(u),o+=u.length}return{meta:t,excerpt:r.join(`
1166
1221
 
1167
- `)}}function v_(e){let{meta:t}=e;return["You are extracting a structured Output Index from a Claude Code session for a local knowledge graph.","","Read the transcript and produce a single JSON object with EXACTLY these fields. Output JSON only \u2014 no Markdown fences, no commentary, no explanation.","","Fields (every field MUST appear; use [] for empty):","- files_written: array of strings. Relative or absolute file paths the assistant created, edited, or extensively discussed (Write/Edit tool calls or paths quoted verbatim).",'- brands_mentioned: array of strings. Distinct proper-noun company / product / brand names mentioned. Examples of valid: "Glaser Group", "Apollo", "TikTok", "Cloudflare R2". NOT generic terms like "the company" or "users".','- terms_introduced: array of objects { "term": "<lowercase phrase>", "freq": <int> }. Distinctive multi-word noun phrases the session introduced or extensively discussed. Skip generic words. Cap at 30 entries.','- plan_ids_referenced: array of strings. Planning identifiers like "v0.18.A", "Phase D", "L3", "MASTER-PLAN-cognitive-graph". Empty array if none.','- bug_signatures: array of objects { "error_type": "<class or null>", "snippet": "<first line of the error>", "file": "<path or null>" }. Errors actually encountered in the session (not hypothetical). The error_type is the exception class (e.g. "TypeError", "ReferenceError") or null if unspecified.',"","Hard constraints:","- Do NOT fabricate. If a field has no concrete content from the transcript, output an empty array.","- Output JSON ONLY. No backticks, no markdown, no preamble.","- terms_introduced \u2264 30 entries; brands_mentioned \u2264 30 distinct entries; plan_ids_referenced \u2264 30; bug_signatures \u2264 30.","",`Session: ${t.alias??t.id.slice(0,8)}`,`Project: ${t.project??"unknown"}`,t.first_user_message?`Opening prompt: ${t.first_user_message.slice(0,500)}`:"","","Transcript excerpt (may be truncated):","---",e.excerpt,"---"].filter(Boolean).join(`
1168
- `)}function M_(e){return Array.isArray(e)&&e.every(t=>typeof t=="string")}function dr(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 $_(e,t){if(!Array.isArray(e))return[];let s=new Set,n=[];for(let r of e){if(!r||typeof r!="object")continue;let o=r.term,i=r.freq;if(typeof o!="string")continue;let a=o.trim().toLowerCase();if(!a||a.length>128||s.has(a))continue;s.add(a);let l=typeof i=="number"&&Number.isFinite(i)&&i>0?Math.floor(i):1;if(n.push({term:a,frequency:l}),n.length>=t)break}return n}function D_(e,t){if(!Array.isArray(e))return[];let s=[];for(let n of e){if(!n||typeof n!="object")continue;let r=n.error_type,o=n.snippet,i=n.file,a=typeof r=="string"&&r.trim().length>0?r.trim().slice(0,64):"unknown",l=typeof o=="string"?o.trim().replace(/\s+/g," ").slice(0,256):"";if(!l)continue;let c=typeof i=="string"&&i.trim().length>0?i.trim().slice(0,256):null,u=x_("sha256").update(`${a}::${l}`).digest("hex").slice(0,12);if(s.push({error_type:a,message_hash:u,snippet:l,file:c}),s.length>=t)break}return s}function j_(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=dr(o.files_written,200),a=dr(o.brands_mentioned,C_),l=$_(o.terms_introduced,N_),c=dr(o.plan_ids_referenced,L_),u=D_(o.bug_signatures,O_);return i.length===0&&a.length===0&&l.length===0&&c.length===0&&u.length===0&&!M_(o.files_written)?null:{files_written:i,brands_mentioned:a,terms_introduced:l,plan_ids_referenced:c,bug_signatures:u}}var ur=null;async function P_(e,t){return ur?ur(e,t):mt(e,[],{model:t})}async function F_(e,t={}){if(t.signal?.aborted)return{session_id:e,ok:!1,failed:"aborted"};let s=I_(e);if(!s)return{session_id:e,ok:!1,skipped:"session-not-found"};let n=Ba(s.meta,{force:t.force});if(!n.eligible)return{session_id:e,ok:!1,skipped:n.reason};if(!ur&&!ce())return{session_id:e,ok:!1,failed:"claude-cli-missing"};let r=v_(s),o=t.model??pr,i=await P_(r,o);if(!i.success)return{session_id:e,ok:!1,failed:"claude-cli-error",exit_code:i.exitCode};let a=j_(i.stdout);if(!a)return{session_id:e,ok:!1,failed:"parse-failed",exit_code:i.exitCode};let l=U_(i.stdout),c=Fa({session_id:e,files_written:a.files_written,brands_mentioned:a.brands_mentioned,terms_introduced:a.terms_introduced,plan_ids_referenced:a.plan_ids_referenced,bug_signatures:a.bug_signatures,raw_extraction:{model:o,usage:l,raw_response_excerpt:i.stdout.slice(0,4e3)},extractor_version:Gt});return{session_id:e,ok:!0,index:c,usage:l}}function U_(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 B_(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 V_(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 Z_(e){return Array.isArray(e)&&e.every(t=>typeof t=="string")}function fr(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 Q_(e,t){if(!Array.isArray(e))return[];let s=new Set,n=[];for(let r of e){if(!r||typeof r!="object")continue;let o=r.term,i=r.freq;if(typeof o!="string")continue;let a=o.trim().toLowerCase();if(!a||a.length>128||s.has(a))continue;s.add(a);let l=typeof i=="number"&&Number.isFinite(i)&&i>0?Math.floor(i):1;if(n.push({term:a,frequency:l}),n.length>=t)break}return n}function eh(e,t){if(!Array.isArray(e))return[];let s=[];for(let n of e){if(!n||typeof n!="object")continue;let r=n.error_type,o=n.snippet,i=n.file,a=typeof r=="string"&&r.trim().length>0?r.trim().slice(0,64):"unknown",l=typeof o=="string"?o.trim().replace(/\s+/g," ").slice(0,256):"";if(!l)continue;let c=typeof i=="string"&&i.trim().length>0?i.trim().slice(0,256):null,u=H_("sha256").update(`${a}::${l}`).digest("hex").slice(0,12);if(s.push({error_type:a,message_hash:u,snippet:l,file:c}),s.length>=t)break}return s}function th(e){let t=e.trim();try{let p=JSON.parse(t);typeof p.result=="string"&&(t=p.result.trim())}catch{}t=t.replace(/^```(?:json)?\s*/i,"").replace(/```\s*$/i,"").trim();let s=t.indexOf("{"),n=t.lastIndexOf("}");if(s===-1||n===-1||n<=s)return null;let r=t.slice(s,n+1),o;try{o=JSON.parse(r)}catch{return null}let i=fr(o.files_written,200),a=fr(o.brands_mentioned,G_),l=Q_(o.terms_introduced,J_),c=fr(o.plan_ids_referenced,Y_),u=eh(o.bug_signatures,z_);return i.length===0&&a.length===0&&l.length===0&&c.length===0&&u.length===0&&!Z_(o.files_written)?null:{files_written:i,brands_mentioned:a,terms_introduced:l,plan_ids_referenced:c,bug_signatures:u}}var _r=null;async function sh(e,t){return _r?_r(e,t):pt(e,[],{model:t})}async function nh(e,t={}){if(t.signal?.aborted)return{session_id:e,ok:!1,failed:"aborted"};let s=K_(e);if(!s)return{session_id:e,ok:!1,skipped:"session-not-found"};let n=za(s.meta,{force:t.force});if(!n.eligible)return{session_id:e,ok:!1,skipped:n.reason};if(!_r&&!ce())return{session_id:e,ok:!1,failed:"claude-cli-missing"};let r=V_(s),o=t.model??hr,i=await sh(r,o);if(!i.success){let u=(i.stderr||i.stdout||"").slice(0,400),m=u?Le(u).redacted:void 0;return{session_id:e,ok:!1,failed:"claude-cli-error",exit_code:i.exitCode,stderr_excerpt:m}}let a=th(i.stdout);if(!a){let u=i.stdout.slice(0,400),m=u?Le(u).redacted:void 0;return{session_id:e,ok:!1,failed:"parse-failed",exit_code:i.exitCode,stderr_excerpt:m}}let l=rh(i.stdout),c=Ga({session_id:e,files_written:a.files_written,brands_mentioned:a.brands_mentioned,terms_introduced:a.terms_introduced,plan_ids_referenced:a.plan_ids_referenced,bug_signatures:a.bug_signatures,raw_extraction:{model:o,usage:l,raw_response_excerpt:i.stdout.slice(0,4e3)},extractor_version:Yt});return{session_id:e,ok:!0,index:c,usage:l}}function rh(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 oh(e={}){let t=_(),s=[],n=[];typeof e.projectId=="number"&&(s.push("s.project_id = ?"),n.push(e.projectId));let r=Math.max(1,Math.min(1e4,e.limit??1e3)),o=s.length?`WHERE ${s.join(" AND ")}`:"",i=t.prepare(`SELECT s.id,
1169
1224
  NULLIF(sa.alias, '') AS alias,
1170
1225
  s.auto_title,
1171
1226
  s.auto_title_source,
@@ -1177,13 +1232,13 @@ show full content: recall paste --show <id>
1177
1232
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1178
1233
  LEFT JOIN projects p ON p.id = s.project_id
1179
1234
  ${o}
1180
- ORDER BY COALESCE(s.started_at, ''), s.id`).all(...n),a=[],l=new Map;for(let c of i){let u={...c,alias_source:c.alias?"manual":null},p=Ba(u,{force:e.force});if(!p.eligible){let m=p.reason??"session-not-found";l.set(m,(l.get(m)??0)+1);continue}if(a.push(u),a.length>=r)break}return{eligible:a,skipped:l}}async function Ha(e={}){let t=B_({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 F_(r.id,{model:e.model,force:e.force,signal:e.signal});n.push(o),e.onResult?.(o),o.ok?s.ok+=1:o.skipped?s.skipped+=1:s.failed+=1,o.usage?.input_tokens&&(s.total_input_tokens+=o.usage.input_tokens),o.usage?.output_tokens&&(s.total_output_tokens+=o.usage.output_tokens),s.processed+=1,e.onProgress?.({...s})}return s.current_session_id=null,e.onProgress?.({...s}),{progress:s,results:n}}Je();async function Wa(e){if(!e.project){console.error("--project <name> is required."),process.exitCode=1;return}let t=he(e.project);if(!t){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}if(!ce()){console.error("claude CLI not found on PATH. Install Claude Code first, then re-run."),process.exitCode=1;return}let s=e.limit?Math.max(1,Number(e.limit)):200,n=e.model??pr;e.json||console.log(`Extracting Output Index \u2014 project "${t.name}" \u2014 extractor v${Gt} \u2014 model ${n} \u2014 up to ${s} sessions\u2026`);let r=Date.now(),o=-1,{progress:i,results:a}=await Ha({projectId:t.id,limit:s,force:e.force,model:n,onProgress:u=>{if(e.json||u.processed===o)return;o=u.processed;let p=u.total>0?` (${Math.round(u.processed/u.total*100)}%)`:"";process.stdout.write(`\r ${u.processed}/${u.total}${p} ok=${u.ok} failed=${u.failed} skipped=${u.skipped} in=${u.total_input_tokens} out=${u.total_output_tokens} `)}});e.json||process.stdout.write(`
1181
- `);let l=Number(((Date.now()-r)/1e3).toFixed(1)),c=i.total>0?Math.round(i.ok/i.total*1e3)/10:0;if(e.json){let u=a.filter(p=>!p.ok&&p.failed).map(p=>({session_id:p.session_id,failed:p.failed,exit_code:p.exit_code??null}));console.log(JSON.stringify({project:t.name,extractor_version:Gt,model:n,progress:i,acceptance_pct:c,failures:u.slice(0,20),elapsed_seconds:l},null,2))}else console.log(`Done in ${l}s \u2014 ok=${i.ok}/${i.total} (${c}%) failed=${i.failed} skipped=${i.skipped}`),console.log(`Token spend: input=${i.total_input_tokens} output=${i.total_output_tokens}`),i.total>0&&c<90?(console.log(` \u26A0 Phase D acceptance bar is 90% non-empty Output Index; actual ${c}%. Inspect failures and re-run.`),process.exitCode=1):i.total===0&&console.log(" \u24D8 No eligible sessions (all sessions were skipped or already extracted).")}T();zt();var $s={citation:"same-project",similar:"same-project",skill_track:"same-project",bug_pattern:"cross-project",wiki_link:"cross-project",temporal_proximity:"same-project"},Q_=2,eh=.25,th=5,sh=60,nh=25;function Ms(e){return e.trim().toLowerCase()}function rh(e){let t=new Set;for(let s of e.files_written)t.add(`file:${Ms(s)}`);for(let s of e.brands_mentioned)t.add(`brand:${Ms(s)}`);for(let s of e.terms_introduced)t.add(`term:${Ms(s)}`);for(let s of e.plan_ids_referenced)t.add(`plan:${Ms(s)}`);return t}function oh(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/sh);return Math.max(.2,t)}function ih(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 ah(e){let t=Jt(e);return t?{session_id:t.session_id,files_written:t.files_written,brands_mentioned:t.brands_mentioned,terms_introduced:t.terms_introduced.map(s=>s.term),plan_ids_referenced:t.plan_ids_referenced}:null}function ch(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=[],l=new Map;for(let c of i){let u={...c,alias_source:c.alias?"manual":null},m=za(u,{force:e.force});if(!m.eligible){let p=m.reason??"session-not-found";l.set(p,(l.get(p)??0)+1);continue}if(a.push(u),a.length>=r)break}return{eligible:a,skipped:l}}async function qa(e={}){let t=oh({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}}Ge();async function Ka(e){if(!e.project){console.error("--project <name> is required."),process.exitCode=1;return}let t=he(e.project);if(!t){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}if(!ce()){console.error("claude CLI not found on PATH. Install Claude Code first, then re-run."),process.exitCode=1;return}let s=e.limit?Math.max(1,Number(e.limit)):200,n=e.model??hr;e.json||console.log(`Extracting Output Index \u2014 project "${t.name}" \u2014 extractor v${Yt} \u2014 model ${n} \u2014 up to ${s} sessions\u2026`);let r=Date.now(),o=-1,{progress:i,results:a}=await qa({projectId:t.id,limit:s,force:e.force,model:n,onProgress:u=>{if(e.json||u.processed===o)return;o=u.processed;let m=u.total>0?` (${Math.round(u.processed/u.total*100)}%)`:"";process.stdout.write(`\r ${u.processed}/${u.total}${m} ok=${u.ok} failed=${u.failed} skipped=${u.skipped} in=${u.total_input_tokens} out=${u.total_output_tokens} `)}});e.json||process.stdout.write(`
1236
+ `);let l=Number(((Date.now()-r)/1e3).toFixed(1)),c=i.total>0?Math.round(i.ok/i.total*1e3)/10:0;if(e.json){let u=a.filter(m=>!m.ok&&m.failed).map(m=>({session_id:m.session_id,failed:m.failed,exit_code:m.exit_code??null}));console.log(JSON.stringify({project:t.name,extractor_version:Yt,model:n,progress:i,acceptance_pct:c,failures:u.slice(0,20),elapsed_seconds:l},null,2))}else console.log(`Done in ${l}s \u2014 ok=${i.ok}/${i.total} (${c}%) failed=${i.failed} skipped=${i.skipped}`),console.log(`Token spend: input=${i.total_input_tokens} output=${i.total_output_tokens}`),i.total>0&&c<90?(console.log(` \u26A0 Phase D acceptance bar is 90% non-empty Output Index; actual ${c}%. Inspect failures and re-run.`),process.exitCode=1):i.total===0&&console.log(" \u24D8 No eligible sessions (all sessions were skipped or already extracted).")}w();zt();var js={citation:"same-project",similar:"same-project",skill_track:"same-project",bug_pattern:"cross-project",wiki_link:"cross-project",temporal_proximity:"same-project"},hh=2,Eh=.25,bh=5,Sh=60,Th=25;function $s(e){return e.trim().toLowerCase()}function yh(e){let t=new Set;for(let s of e.files_written)t.add(`file:${$s(s)}`);for(let s of e.brands_mentioned)t.add(`brand:${$s(s)}`);for(let s of e.terms_introduced)t.add(`term:${$s(s)}`);for(let s of e.plan_ids_referenced)t.add(`plan:${$s(s)}`);return t}function wh(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/Sh);return Math.max(.2,t)}function Rh(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 xh(e){let t=Gt(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 kh(e){return _().prepare(`SELECT s.id AS id, s.project_id AS project_id, s.started_at AS started_at
1182
1237
  FROM sessions s
1183
1238
  JOIN session_output_index oi ON oi.session_id = s.id
1184
1239
  WHERE s.project_id = ?
1185
- ORDER BY COALESCE(s.started_at, ''), s.id`).all(e)}function lh(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=rh(i);if(a.size!==0){n.set(o.id,a);for(let l of a){let c=s.get(l);c?c.push(o.id):s.set(l,[o.id])}}}return{posting:s,vocab:n,startedAt:r}}function dh(e,t){let s=t.vocab.get(e),n=t.startedAt.get(e)??null;if(!s||!n)return[];let r=new Map;for(let i of s){let a=t.posting.get(i);if(a)for(let l of a){if(l===e)continue;let c=t.startedAt.get(l);if(!c||c>=n)continue;let u=r.get(l);u?u.push(i):r.set(l,[i])}}let o=[];for(let[i,a]of r){let l=a.length;if(l<Q_)continue;let c=t.startedAt.get(i)??null,u=ih(n,c),p=oh(u),m=Math.min(1,l/th*p);if(m<eh)continue;let f=a.slice(0,12);o.push({target_session_id:i,matched_terms:f,overlap:l,days_apart:Math.round(u*10)/10,recency:Math.round(p*1e3)/1e3,confidence:Math.round(m*1e3)/1e3})}return o.sort((i,a)=>a.confidence-i.confidence),o.slice(0,nh)}async function Za(e){if($s.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project \u2014 refusing to run inference");let t=ch(e.projectId),s=new Map;for(let i of t){let a=ah(i.id);a&&s.set(i.id,a)}let n=lh(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=dh(i.id,n);for(let l of a)try{let c=Qe({source_session_id:i.id,target_session_id:l.target_session_id,link_type:"citation",confidence:l.confidence,evidence:{matched_terms:l.matched_terms,overlap_count:l.overlap,recency:l.recency,days_apart:l.days_apart},inferred_by:"L2"});o.push(c.id),r.suggestions_created+=1}catch(c){console.error("[citation-inference] createSuggestion failed:",c)}r.processed_sessions+=1,e.onProgress?.({...r})}return r.current_session_id=null,e.onProgress?.({...r}),{progress:r,suggestion_ids:o}}async function Qa(e){if(!e.project){console.error("--project <name> is required."),process.exitCode=1;return}let t=he(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 Za({projectId:t.id,onProgress:i=>{if(e.json||i.processed_sessions===n)return;n=i.processed_sessions;let a=i.total_sessions>0?` (${Math.round(i.processed_sessions/i.total_sessions*100)}%)`:"";process.stdout.write(`\r ${i.processed_sessions}/${i.total_sessions} sessions${a} suggestions=${i.suggestions_created} `)}});e.json||process.stdout.write(`
1186
- `);let o=Number(((Date.now()-s)/1e3).toFixed(1));e.json?console.log(JSON.stringify({project:t.name,progress:r.progress,suggestion_count:r.suggestion_ids.length,sample_suggestion_ids:r.suggestion_ids.slice(0,25),elapsed_seconds:o},null,2)):(console.log(`Done in ${o}s \u2014 sessions=${r.progress.processed_sessions}/${r.progress.total_sessions} suggestions=${r.progress.suggestions_created}`),r.progress.total_sessions===0?console.log(` \u24D8 No sessions had a populated Output Index. Run \`recall extract-outputs --project ${t.name}\` first.`):r.progress.suggestions_created===0?console.log(" \u24D8 No suggestions met the confidence threshold. This is expected on small corpora; the Output Index needs more shared vocabulary across sessions for citations to surface."):console.log(" Review the queue at GET /api/links/suggestions?status=pending (Phase F UI ships the queue review)."))}import{existsSync as xh,readFileSync as Rh}from"node:fs";import{join as kh}from"node:path";T();zt();var uh=/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/gi,ph=[/\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],mh=.95,gh=.85,fh=.7,Er=50,_h=50;function hh(e){if(!e)return[];let t=new Set,s=[],n=e.match(uh);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>=Er))break}return s}function Eh(e){if(!e)return[];let t=new Set,s=[];for(let n of ph){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>=Er))break}if(s.length>=Er)break}}return s}function br(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 ec(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 Nh(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=yh(i);if(a.size!==0){n.set(o.id,a);for(let l of a){let c=s.get(l);c?c.push(o.id):s.set(l,[o.id])}}}return{posting:s,vocab:n,startedAt:r}}function Lh(e,t){let s=t.vocab.get(e),n=t.startedAt.get(e)??null;if(!s||!n)return[];let r=new Map;for(let i of s){let a=t.posting.get(i);if(a)for(let l of a){if(l===e)continue;let c=t.startedAt.get(l);if(!c||c>=n)continue;let u=r.get(l);u?u.push(i):r.set(l,[i])}}let o=[];for(let[i,a]of r){let l=a.length;if(l<hh)continue;let c=t.startedAt.get(i)??null,u=Rh(n,c),m=wh(u),p=Math.min(1,l/bh*m);if(p<Eh)continue;let f=a.slice(0,12);o.push({target_session_id:i,matched_terms:f,overlap:l,days_apart:Math.round(u*10)/10,recency:Math.round(m*1e3)/1e3,confidence:Math.round(p*1e3)/1e3})}return o.sort((i,a)=>a.confidence-i.confidence),o.slice(0,Th)}async function oc(e){if(js.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project \u2014 refusing to run inference");let t=kh(e.projectId),s=new Map;for(let i of t){let a=xh(i.id);a&&s.set(i.id,a)}let n=Nh(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=Lh(i.id,n);for(let l of a)try{let c=Qe({source_session_id:i.id,target_session_id:l.target_session_id,link_type:"citation",confidence:l.confidence,evidence:{matched_terms:l.matched_terms,overlap_count:l.overlap,recency:l.recency,days_apart:l.days_apart},inferred_by:"L2"});o.push(c.id),r.suggestions_created+=1}catch(c){console.error("[citation-inference] createSuggestion failed:",c)}r.processed_sessions+=1,e.onProgress?.({...r})}return r.current_session_id=null,e.onProgress?.({...r}),{progress:r,suggestion_ids:o}}async function ic(e){if(!e.project){console.error("--project <name> is required."),process.exitCode=1;return}let t=he(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 oc({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 Hh,readFileSync as Wh}from"node:fs";import{join as Xh}from"node:path";w();zt();var Ch=/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/gi,Ah=[/\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],Oh=.95,vh=.85,Ih=.7,wr=50,Mh=50;function Dh(e){if(!e)return[];let t=new Set,s=[],n=e.match(Ch);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>=wr))break}return s}function $h(e){if(!e)return[];let t=new Set,s=[];for(let n of Ah){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>=wr))break}if(s.length>=wr)break}}return s}function Rr(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 ac(e){let t=_();return typeof e=="number"?t.prepare(`SELECT m.uuid AS message_uuid, m.session_id, m.content_text,
1187
1242
  s.project_id
1188
1243
  FROM messages m
1189
1244
  JOIN sessions s ON s.id = m.session_id
@@ -1196,12 +1251,12 @@ show full content: recall paste --show <id>
1196
1251
  JOIN sessions s ON s.id = m.session_id
1197
1252
  WHERE m.is_sidechain = 0
1198
1253
  AND m.content_text IS NOT NULL
1199
- AND length(m.content_text) > 0`).all()}function bh(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 jh(e){let t=_(),s=typeof e=="number"?"WHERE s.project_id = ?":"",n=typeof e=="number"?[e]:[];return t.prepare(`SELECT oi.session_id AS session_id,
1200
1255
  s.project_id AS project_id,
1201
1256
  oi.plan_ids_referenced AS plan_ids_json
1202
1257
  FROM session_output_index oi
1203
1258
  JOIN sessions s ON s.id = oi.session_id
1204
- ${s}`).all(...n)}function Sh(e){if(!e)return[];try{let t=JSON.parse(e);if(Array.isArray(t))return t.filter(s=>typeof s=="string")}catch{}return[]}function yh(e={}){if($s.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project");let t=br(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 ec(e.projectId)){if(e.signal?.aborted)break;let i=hh(o.content_text);if(i.length===0)continue;let a=n.get(o.session_id);if(a!==void 0)for(let l of i){if(l===o.session_id)continue;let c=n.get(l);if(!(c===void 0&&!s.has(l))&&!(c!==void 0&&a!==void 0&&c!==a))try{Qe({source_session_id:o.session_id,target_session_id:l,link_type:"citation",confidence:mh,evidence:{matched_uuid:l,source_message_uuid:o.message_uuid,scanner:"uuid-ref"},inferred_by:"L1"}),r+=1}catch{}}}return{created:r}}function Th(e={}){let t=bh(e.projectId);if(t.length===0)return{created:0};let s=new Map;for(let a of t){let l=Sh(a.plan_ids_json);for(let c of l){let u=c.trim().toLowerCase();if(!u)continue;let 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=br(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 ec(e.projectId)){if(e.signal?.aborted)break;let l=Eh(a.content_text);if(l.length===0)continue;let c=r.get(a.session_id);if(c!==void 0)for(let u of l){let p=s.get(u);if(p)for(let m of p){if(m.id===a.session_id||m.project_id!==c)continue;let f=i.get(a.session_id);f||(f=new Map,i.set(a.session_id,f));let g=f.get(m.id);g||(g=new Set,f.set(m.id,g)),g.add(u)}}}for(let[a,l]of i)for(let[c,u]of l)try{Qe({source_session_id:a,target_session_id:c,link_type:"citation",confidence:gh,evidence:{matched_plan_ids:Array.from(u).slice(0,12),scanner:"plan-ref"},inferred_by:"L1"}),o+=1}catch{}return{created:o}}function wh(e){if($s.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=br(e.projectId),s=new Map,n=new Map;if(t.length>0){let i=_(),a=t.map(u=>u.id),l=a.map(()=>"?").join(","),c=i.prepare(`SELECT id, started_at FROM sessions WHERE id IN (${l})`).all(...a);for(let u of c)n.set(u.id,u.started_at)}for(let i of t)s.set(i.id,i.project_id);let r=new Map;for(let i of e.registry.terminals){let a=e.registry.sessions_by_pid[String(i.shell_pid)]??[];if(a.length===0)continue;let l=`${i.cwd??"<no-cwd>"}::${i.tab_name}`,c=r.get(l);c||(c=new Set,r.set(l,c));for(let u of a)c.add(u)}let o=0;for(let[,i]of r){if(i.size<2)continue;let a=new Map;for(let l of i){let c=s.get(l);if(c===void 0||typeof e.projectId=="number"&&c!==e.projectId)continue;let u=a.get(c);u||(u=[],a.set(c,u)),u.push(l)}for(let[,l]of a){if(l.length<2)continue;l.sort((u,p)=>{let m=n.get(u)??"",f=n.get(p)??"";return m<f?-1:m>f?1:u<p?-1:1});let c=0;for(let u=1;u<l.length&&!e.signal?.aborted;u++)for(let p=0;p<u&&!(c>=_h);p++)try{Qe({source_session_id:l[u],target_session_id:l[p],link_type:"skill_track",confidence:fh,evidence:{shared_tab_signature:!0,bucket_size:l.length,scanner:"tab-carry"},inferred_by:"L1"}),o+=1,c+=1}catch{}}}return{created:o}}function tc(e={}){let t=yh(e);if(e.signal?.aborted)return{uuid_refs_created:t.created,plan_refs_created:0,tab_carry_created:0,total:t.created};let s=Th(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?wh({projectId:e.projectId,signal:e.signal,registry:e.registry}):{created:0};return{uuid_refs_created:t.created,plan_refs_created:s.created,tab_carry_created:n.created,total:t.created+s.created+n.created}}j();function Nh(){let e=kh(x,"terminals.json");if(xh(e))try{let t=Rh(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 sc(e){let t=null;if(e.project&&(t=he(e.project),!t)){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let s=Nh(),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=tc({projectId:t?.id,registry:s}),i=Number(((Date.now()-r)/1e3).toFixed(2));e.json?console.log(JSON.stringify({project:t?.name??null,...o,elapsed_seconds:i},null,2)):(console.log(`Done in ${i}s \u2014 uuid_refs=${o.uuid_refs_created} plan_refs=${o.plan_refs_created} tab_carry=${o.tab_carry_created} (total=${o.total})`),o.total===0?console.log(" \u24D8 Zero new suggestions. This is expected when L1 has already run against this corpus or when the project has no inter-session references. (Tombstones from prior reject decisions also keep re-runs idempotent.)"):console.log(" Review the queue at GET /api/links/suggestions?status=pending (or the web UI at #view=suggestions)."))}T();Je();zt();function Sr(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 Tr="claude-haiku-4-5-20251001",Ds=.4,wr=.95,nc=30,rc=240,Ch=new Set(["CITATION","SIMILAR","SKILL_TRACK","UNRELATED"]),Lh={CITATION:"citation",SIMILAR:"similar",SKILL_TRACK:"skill_track"};function ac(e){return _().prepare(`SELECT s.id,
1259
+ ${s}`).all(...n)}function Ph(e){if(!e)return[];try{let t=JSON.parse(e);if(Array.isArray(t))return t.filter(s=>typeof s=="string")}catch{}return[]}function Fh(e={}){if(js.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project");let t=Rr(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 ac(e.projectId)){if(e.signal?.aborted)break;let i=Dh(o.content_text);if(i.length===0)continue;let a=n.get(o.session_id);if(a!==void 0)for(let l of i){if(l===o.session_id)continue;let c=n.get(l);if(!(c===void 0&&!s.has(l))&&!(c!==void 0&&a!==void 0&&c!==a))try{Qe({source_session_id:o.session_id,target_session_id:l,link_type:"citation",confidence:Oh,evidence:{matched_uuid:l,source_message_uuid:o.message_uuid,scanner:"uuid-ref"},inferred_by:"L1"}),r+=1}catch{}}}return{created:r}}function Uh(e={}){let t=jh(e.projectId);if(t.length===0)return{created:0};let s=new Map;for(let a of t){let l=Ph(a.plan_ids_json);for(let c of l){let u=c.trim().toLowerCase();if(!u)continue;let m=s.get(u);m?m.push({id:a.session_id,project_id:a.project_id}):s.set(u,[{id:a.session_id,project_id:a.project_id}])}}if(s.size===0)return{created:0};let n=Rr(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 ac(e.projectId)){if(e.signal?.aborted)break;let l=$h(a.content_text);if(l.length===0)continue;let c=r.get(a.session_id);if(c!==void 0)for(let u of l){let m=s.get(u);if(m)for(let p of m){if(p.id===a.session_id||p.project_id!==c)continue;let f=i.get(a.session_id);f||(f=new Map,i.set(a.session_id,f));let g=f.get(p.id);g||(g=new Set,f.set(p.id,g)),g.add(u)}}}for(let[a,l]of i)for(let[c,u]of l)try{Qe({source_session_id:a,target_session_id:c,link_type:"citation",confidence:vh,evidence:{matched_plan_ids:Array.from(u).slice(0,12),scanner:"plan-ref"},inferred_by:"L1"}),o+=1}catch{}return{created:o}}function Bh(e){if(js.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=Rr(e.projectId),s=new Map,n=new Map;if(t.length>0){let i=_(),a=t.map(u=>u.id),l=a.map(()=>"?").join(","),c=i.prepare(`SELECT id, started_at FROM sessions WHERE id IN (${l})`).all(...a);for(let u of c)n.set(u.id,u.started_at)}for(let i of t)s.set(i.id,i.project_id);let r=new Map;for(let i of e.registry.terminals){let a=e.registry.sessions_by_pid[String(i.shell_pid)]??[];if(a.length===0)continue;let l=`${i.cwd??"<no-cwd>"}::${i.tab_name}`,c=r.get(l);c||(c=new Set,r.set(l,c));for(let u of a)c.add(u)}let o=0;for(let[,i]of r){if(i.size<2)continue;let a=new Map;for(let l of i){let c=s.get(l);if(c===void 0||typeof e.projectId=="number"&&c!==e.projectId)continue;let u=a.get(c);u||(u=[],a.set(c,u)),u.push(l)}for(let[,l]of a){if(l.length<2)continue;l.sort((u,m)=>{let p=n.get(u)??"",f=n.get(m)??"";return p<f?-1:p>f?1:u<m?-1:1});let c=0;for(let u=1;u<l.length&&!e.signal?.aborted;u++)for(let m=0;m<u&&!(c>=Mh);m++)try{Qe({source_session_id:l[u],target_session_id:l[m],link_type:"skill_track",confidence:Ih,evidence:{shared_tab_signature:!0,bucket_size:l.length,scanner:"tab-carry"},inferred_by:"L1"}),o+=1,c+=1}catch{}}}return{created:o}}function cc(e={}){let t=Fh(e);if(e.signal?.aborted)return{uuid_refs_created:t.created,plan_refs_created:0,tab_carry_created:0,total:t.created};let s=Uh(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?Bh({projectId:e.projectId,signal:e.signal,registry:e.registry}):{created:0};return{uuid_refs_created:t.created,plan_refs_created:s.created,tab_carry_created:n.created,total:t.created+s.created+n.created}}P();function Jh(){let e=Xh(x,"terminals.json");if(Hh(e))try{let t=Wh(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 lc(e){let t=null;if(e.project&&(t=he(e.project),!t)){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let s=Jh(),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=cc({projectId:t?.id,registry:s}),i=Number(((Date.now()-r)/1e3).toFixed(2));e.json?console.log(JSON.stringify({project:t?.name??null,...o,elapsed_seconds:i},null,2)):(console.log(`Done in ${i}s \u2014 uuid_refs=${o.uuid_refs_created} plan_refs=${o.plan_refs_created} tab_carry=${o.tab_carry_created} (total=${o.total})`),o.total===0?console.log(" \u24D8 Zero new suggestions. This is expected when L1 has already run against this corpus or when the project has no inter-session references. (Tombstones from prior reject decisions also keep re-runs idempotent.)"):console.log(" Review the queue at GET /api/links/suggestions?status=pending (or the web UI at #view=suggestions)."))}w();Ge();zt();function xr(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 Nr="claude-haiku-4-5-20251001",Ps=.4,Lr=.95,dc=30,uc=240,Gh=new Set(["CITATION","SIMILAR","SKILL_TRACK","UNRELATED"]),Yh={CITATION:"citation",SIMILAR:"similar",SKILL_TRACK:"skill_track"};function gc(e){return _().prepare(`SELECT s.id,
1205
1260
  s.source_session_id,
1206
1261
  s.target_session_id,
1207
1262
  s.link_type,
@@ -1211,7 +1266,7 @@ show full content: recall paste --show <id>
1211
1266
  FROM session_link_suggestions s
1212
1267
  JOIN sessions src ON src.id = s.source_session_id
1213
1268
  WHERE s.status = 'pending'
1214
- AND src.project_id = ?`).all(e)}function Oh(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 zh(e){if(e.length===0)return new Map;let t=_(),s=e.map(()=>"?").join(","),n=t.prepare(`SELECT s.id,
1215
1270
  NULLIF(sa.alias, '') AS alias,
1216
1271
  s.auto_title,
1217
1272
  s.first_user_message,
@@ -1220,18 +1275,18 @@ show full content: recall paste --show <id>
1220
1275
  FROM sessions s
1221
1276
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1222
1277
  LEFT JOIN projects p ON p.id = s.project_id
1223
- WHERE s.id IN (${s})`).all(...e),r=new Map;for(let o of n)r.set(o.id,o);return r}function oc(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 Ah(e){let t=e.minConfidence??Ds,s=Math.max(1,Math.min(500,e.limit??100)),n=ac(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=ic(c.evidence))):p.layers.push({inferred_by:c.inferred_by,link_type:c.link_type,confidence:c.confidence,evidence:ic(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=Oh(Array.from(i)),l=[];for(let c of o.values()){let u=Sr(c.layers.map(f=>f.confidence));if(u<t)continue;let p=a.get(c.source_session_id),m=a.get(c.target_session_id);l.push({source_session_id:c.source_session_id,target_session_id:c.target_session_id,primary_link_type:c.link_type,combined_confidence:u,layers:c.layers,source_title:oc(p,c.source_session_id),target_title:oc(m,c.target_session_id),source_project:p?.project??null})}return l.sort((c,u)=>u.combined_confidence-c.combined_confidence),l.slice(0,s)}function Ih(e){let t;try{t=JSON.stringify(e)}catch{t=String(e)}return t.length>rc&&(t=t.slice(0,rc)+"\u2026"),t}function vh(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=${Ih(r.evidence)}`)}),t.join(`
1224
- `)}var yr=null;async function Mh(e,t){return yr?yr(e,t):mt(e,[],{model:t})}function $h(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 Dh(e){let t=e.trim();try{let i=JSON.parse(t);typeof i.result=="string"&&(t=i.result.trim())}catch{}t=t.replace(/^```(?:json)?\s*/i,"").replace(/```\s*$/i,"").trim();let s=t.indexOf("{"),n=t.lastIndexOf("}");if(s===-1||n===-1||n<=s)return null;let r;try{r=JSON.parse(t.slice(s,n+1))}catch{return null}if(!Array.isArray(r.classifications))return null;let o=[];for(let i of r.classifications){if(!i||typeof i!="object")continue;let a=i,l=typeof a.i=="number"?a.i:typeof a.pair_index=="number"?a.pair_index:NaN;if(!Number.isInteger(l)||l<0)continue;let c=typeof a.label=="string"?a.label.toUpperCase():"";if(!Ch.has(c))continue;let u=typeof a.conf=="number"?a.conf:typeof a.confidence=="number"?a.confidence:NaN;if(!Number.isFinite(u))continue;let p=Math.max(0,Math.min(1,u)),m=typeof a.why=="string"?a.why.trim().slice(0,200):typeof a.reason=="string"?a.reason.trim().slice(0,200):"";o.push({pair_index:l,label:c,confidence:p,reason:m})}return o}async function cc(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(!yr&&!ce())return t.failures.push({batch_index:-1,error:"claude CLI not available on PATH"}),t;let s=Ah({projectId:e.projectId,minConfidence:e.minConfidence??Ds,limit:e.limit??100});t.candidates_after_filter=s.length;let n=ac(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??Tr,i=e.autoPromoteThreshold??wr;for(let a=0,l=0;a<s.length&&!e.signal?.aborted;a+=nc,l+=1){let c=s.slice(a,a+nc);e.onBatchStart?.({batch:l,pairs:c.length});let u=vh(c),p=await Mh(u,o);if(!p.success){t.failures.push({batch_index:l,error:`claude CLI exited ${p.exitCode}: ${p.stderr.slice(0,200)}`});continue}let m=Dh(p.stdout);if(!m){t.failures.push({batch_index:l,error:"parse-failed"});continue}let f=$h(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=Lh[g.label];if(E)try{let b=Qe({source_session_id:h.source_session_id,target_session_id:h.target_session_id,link_type:E,confidence:g.confidence,evidence:{l4_label:g.label,l4_reason:g.reason,primary_type_l1_l2_l3:h.primary_link_type,combined_pre_l4:h.combined_confidence,scanner:"l4-llm",model:o},inferred_by:"L4"});if(t.suggestions_created+=1,e.autoPromote){let S=h.layers.map(R=>R.confidence);if(S.push(g.confidence),Sr(S)>=i)try{Ka(b.id,"approved",{source:"auto"}),t.links_promoted+=1}catch{}}}catch{}}}return t}Je();var jh=1e3;function Ph(e){let t=e.minConf?Math.max(0,Math.min(1,Number(e.minConf))):Ds,s=e.autoPromoteThreshold!==void 0?Math.max(0,Math.min(1,Number(e.autoPromoteThreshold))):wr,n=e.limit?Math.max(1,Number(e.limit)):jh,r=e.model??Tr,o=!!e.autoPromote||e.autoPromoteThreshold!==void 0;return{minConfidence:t,autoPromoteThreshold:s,limit:n,model:r,autoPromote:o}}async function lc(e){if(!e.project){console.error("--project <name> is required."),process.exitCode=1;return}let t=he(e.project);if(!t){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}if(!ce()){console.error("claude CLI not found on PATH. Install Claude Code first, then re-run."),process.exitCode=1;return}let{minConfidence:s,autoPromoteThreshold:n,limit:r,model:o,autoPromote:i}=Ph(e);e.json||console.log(`L4 inference \u2014 project "${t.name}" \u2014 model ${o} \u2014 pre-filter conf \u2265 ${s} \u2014 limit ${r} \u2014 auto-promote ${i?`ON (\u2265 ${n})`:"OFF"}`);let a=Date.now(),l=await cc({projectId:t.id,minConfidence:s,limit:r,autoPromote:i,autoPromoteThreshold:n,model:o,onBatchStart:u=>{e.json||process.stdout.write(`\r batch ${u.batch} (${u.pairs} pairs)\u2026 `)}});e.json||process.stdout.write(`
1225
- `);let c=Number(((Date.now()-a)/1e3).toFixed(1));if(e.json)console.log(JSON.stringify({project:t.name,model:o,pre_filter_threshold:s,auto_promote:i,auto_promote_threshold:i?n:null,...l,elapsed_seconds:c},null,2));else{if(console.log(`Done in ${c}s \u2014 pairs=${l.candidates_after_filter}/${l.candidates_total} classified=${l.classified} suggestions=${l.suggestions_created} promoted=${l.links_promoted} failures=${l.failures.length}`),console.log(`Token spend: input=${l.total_input_tokens} output=${l.total_output_tokens}`),l.failures.length>0)for(let u of l.failures.slice(0,3))console.log(` \u26A0 batch ${u.batch_index}: ${u.error}`);l.suggestions_created>0?console.log(" Review the new L4 suggestions at #view=suggestions (filter by inferred_by=L4)."):l.candidates_after_filter===0&&console.log(` \u24D8 No pairs cleared the pre-filter (combined conf \u2265 ${s}). Lower --min-conf to widen the batch, or run more L1/L2/L3 inference first.`)}}T();import{createHash as Gh}from"node:crypto";T();j();import{writeFileSync as Fh,readFileSync as AC,existsSync as Uh,mkdirSync as Bh,readdirSync as IC,unlinkSync as vC}from"node:fs";import{join as dc}from"node:path";import{randomUUID as Hh}from"node:crypto";var xr=dc(x,"bug-patterns");function Wh(){P(),Uh(xr)||Bh(xr,{recursive:!0})}function js(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 Xh(e){return{cluster_id:e.cluster_id,session_id:e.session_id,matched_at:e.matched_at}}function uc(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??Hh(),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 mc(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 pc(e){try{return JSON.parse(e)}catch{return e}}function qh(e){let t=e.minConfidence??Ps,s=Math.max(1,Math.min(500,e.limit??100)),n=gc(e.projectId);if(n.length===0)return[];let r=new Map,o=new Map;for(let c of n){let u=`${c.source_session_id}|${c.target_session_id}|${c.link_type}`,m=o.get(u);m||(m={source_session_id:c.source_session_id,target_session_id:c.target_session_id,link_type:c.link_type,layers:[]},o.set(u,m));let p=m.layers.find(f=>f.inferred_by===c.inferred_by);p?(p.suggestion_ids.push(c.id),c.confidence>p.confidence&&(p.confidence=c.confidence,p.evidence=pc(c.evidence))):m.layers.push({inferred_by:c.inferred_by,link_type:c.link_type,confidence:c.confidence,evidence:pc(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=zh(Array.from(i)),l=[];for(let c of o.values()){let u=xr(c.layers.map(f=>f.confidence));if(u<t)continue;let m=a.get(c.source_session_id),p=a.get(c.target_session_id);l.push({source_session_id:c.source_session_id,target_session_id:c.target_session_id,primary_link_type:c.link_type,combined_confidence:u,layers:c.layers,source_title:mc(m,c.source_session_id),target_title:mc(p,c.target_session_id),source_project:m?.project??null})}return l.sort((c,u)=>u.combined_confidence-c.combined_confidence),l.slice(0,s)}function Kh(e){let t;try{t=JSON.stringify(e)}catch{t=String(e)}return t.length>uc&&(t=t.slice(0,uc)+"\u2026"),t}function Vh(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=${Kh(r.evidence)}`)}),t.join(`
1279
+ `)}var kr=null;async function Zh(e,t){return kr?kr(e,t):pt(e,[],{model:t})}function Qh(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 eE(e){let t=e.trim();try{let i=JSON.parse(t);typeof i.result=="string"&&(t=i.result.trim())}catch{}t=t.replace(/^```(?:json)?\s*/i,"").replace(/```\s*$/i,"").trim();let s=t.indexOf("{"),n=t.lastIndexOf("}");if(s===-1||n===-1||n<=s)return null;let r;try{r=JSON.parse(t.slice(s,n+1))}catch{return null}if(!Array.isArray(r.classifications))return null;let o=[];for(let i of r.classifications){if(!i||typeof i!="object")continue;let a=i,l=typeof a.i=="number"?a.i:typeof a.pair_index=="number"?a.pair_index:NaN;if(!Number.isInteger(l)||l<0)continue;let c=typeof a.label=="string"?a.label.toUpperCase():"";if(!Gh.has(c))continue;let u=typeof a.conf=="number"?a.conf:typeof a.confidence=="number"?a.confidence:NaN;if(!Number.isFinite(u))continue;let m=Math.max(0,Math.min(1,u)),p=typeof a.why=="string"?a.why.trim().slice(0,200):typeof a.reason=="string"?a.reason.trim().slice(0,200):"";o.push({pair_index:l,label:c,confidence:m,reason:p})}return o}async function fc(e){let t={candidates_total:0,candidates_after_filter:0,classified:0,suggestions_created:0,links_promoted:0,total_input_tokens:0,total_output_tokens:0,failures:[]};if(!kr&&!ce())return t.failures.push({batch_index:-1,error:"claude CLI not available on PATH"}),t;let s=qh({projectId:e.projectId,minConfidence:e.minConfidence??Ps,limit:e.limit??100});t.candidates_after_filter=s.length;let n=gc(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??Nr,i=e.autoPromoteThreshold??Lr;for(let a=0,l=0;a<s.length&&!e.signal?.aborted;a+=dc,l+=1){let c=s.slice(a,a+dc);e.onBatchStart?.({batch:l,pairs:c.length});let u=Vh(c),m=await Zh(u,o);if(!m.success){t.failures.push({batch_index:l,error:`claude CLI exited ${m.exitCode}: ${m.stderr.slice(0,200)}`});continue}let p=eE(m.stdout);if(!p){t.failures.push({batch_index:l,error:"parse-failed"});continue}let f=Qh(m.stdout);t.total_input_tokens+=f.input_tokens,t.total_output_tokens+=f.output_tokens;for(let g of p){if(g.pair_index>=c.length)continue;let h=c[g.pair_index];if(t.classified+=1,g.label==="UNRELATED")continue;let E=Yh[g.label];if(E)try{let b=Qe({source_session_id:h.source_session_id,target_session_id:h.target_session_id,link_type:E,confidence:g.confidence,evidence:{l4_label:g.label,l4_reason:g.reason,primary_type_l1_l2_l3:h.primary_link_type,combined_pre_l4:h.combined_confidence,scanner:"l4-llm",model:o},inferred_by:"L4"});if(t.suggestions_created+=1,e.autoPromote){let S=h.layers.map(y=>y.confidence);if(S.push(g.confidence),xr(S)>=i)try{nc(b.id,"approved",{source:"auto"}),t.links_promoted+=1}catch{}}}catch{}}}return t}Ge();var tE=1e3;function sE(e){let t=e.minConf?Math.max(0,Math.min(1,Number(e.minConf))):Ps,s=e.autoPromoteThreshold!==void 0?Math.max(0,Math.min(1,Number(e.autoPromoteThreshold))):Lr,n=e.limit?Math.max(1,Number(e.limit)):tE,r=e.model??Nr,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=he(e.project);if(!t){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}if(!ce()){console.error("claude CLI not found on PATH. Install Claude Code first, then re-run."),process.exitCode=1;return}let{minConfidence:s,autoPromoteThreshold:n,limit:r,model:o,autoPromote:i}=sE(e);e.json||console.log(`L4 inference \u2014 project "${t.name}" \u2014 model ${o} \u2014 pre-filter conf \u2265 ${s} \u2014 limit ${r} \u2014 auto-promote ${i?`ON (\u2265 ${n})`:"OFF"}`);let a=Date.now(),l=await fc({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,...l,elapsed_seconds:c},null,2));else{if(console.log(`Done in ${c}s \u2014 pairs=${l.candidates_after_filter}/${l.candidates_total} classified=${l.classified} suggestions=${l.suggestions_created} promoted=${l.links_promoted} failures=${l.failures.length}`),console.log(`Token spend: input=${l.total_input_tokens} output=${l.total_output_tokens}`),l.failures.length>0)for(let u of l.failures.slice(0,3))console.log(` \u26A0 batch ${u.batch_index}: ${u.error}`);l.suggestions_created>0?console.log(" Review the new L4 suggestions at #view=suggestions (filter by inferred_by=L4)."):l.candidates_after_filter===0&&console.log(` \u24D8 No pairs cleared the pre-filter (combined conf \u2265 ${s}). Lower --min-conf to widen the batch, or run more L1/L2/L3 inference first.`)}}w();import{createHash as dE}from"node:crypto";w();P();import{writeFileSync as nE,readFileSync as aC,existsSync as rE,mkdirSync as oE,readdirSync as cC,unlinkSync as lC}from"node:fs";import{join as hc}from"node:path";import{randomUUID as iE}from"node:crypto";var Cr=hc(x,"bug-patterns");function aE(){j(),rE(Cr)||oE(Cr,{recursive:!0})}function Fs(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 cE(e){return{cluster_id:e.cluster_id,session_id:e.session_id,matched_at:e.matched_at}}function Ec(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??iE(),r=e.first_seen_at??s,o=e.last_seen_at??s,i=Array.from(new Set(e.member_session_ids));t.transaction(()=>{t.prepare(`INSERT INTO bug_pattern_clusters
1226
1281
  (id, signature_hash, example_message, occurrence_count,
1227
1282
  first_seen_at, last_seen_at, resolved_in_session_id, fix_summary)
1228
1283
  VALUES (?, ?, ?, ?, ?, ?, NULL, NULL)`).run(n,e.signature_hash,e.example_message,i.length,r,o);let l=t.prepare(`INSERT INTO bug_pattern_members (cluster_id, session_id, matched_at)
1229
1284
  VALUES (?, ?, ?)
1230
- ON CONFLICT(cluster_id, session_id) DO NOTHING`);for(let c of i)l.run(n,c,s)})();let a=pc(n);if(!a)throw new Error("createCluster succeeded but read-back failed");return fc(n),a}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 * FROM bug_pattern_members WHERE cluster_id = ? ORDER BY matched_at ASC, session_id ASC").all(e);return{cluster:js(s),members:n.map(Xh)}}function mc(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 c of i)l.run(n,c,s)})();let a=bc(n);if(!a)throw new Error("createCluster succeeded but read-back failed");return yc(n),a}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 * FROM bug_pattern_members WHERE cluster_id = ? ORDER BY matched_at ASC, session_id ASC").all(e);return{cluster:Fs(s),members:n.map(cE)}}function Sc(e,t){if(!e)throw new Error("clusterId is required");if(!Array.isArray(t)||t.length===0)throw new Error("sessionIds must be a non-empty array");let s=_();if(!s.prepare("SELECT 1 FROM bug_pattern_clusters WHERE id = ?").get(e))throw new Error(`cluster ${e} not found`);let r=new Date().toISOString(),o=0;s.transaction(()=>{let a=s.prepare(`INSERT INTO bug_pattern_members (cluster_id, session_id, matched_at)
1231
1286
  VALUES (?, ?, ?)
1232
1287
  ON CONFLICT(cluster_id, session_id) DO NOTHING`);for(let l of Array.from(new Set(t)))a.run(e,l,r).changes>0&&(o+=1);if(o>0){let l=s.prepare("SELECT COUNT(*) AS n FROM bug_pattern_members WHERE cluster_id = ?").get(e).n;s.prepare(`UPDATE bug_pattern_clusters
1233
1288
  SET occurrence_count = ?, last_seen_at = ?
1234
- WHERE id = ?`).run(l,r,e)}})(),o>0&&fc(e);let i=s.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);return{cluster:js(i),added:o}}function Jh(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 gc(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(l,r,e)}})(),o>0&&yc(e);let i=s.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);return{cluster:Fs(i),added:o}}function lE(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 Tc(e){let t=_(),s=t.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);if(!s)return null;let n=t.prepare(`SELECT m.cluster_id, m.session_id, m.matched_at,
1235
1290
  NULLIF(sa.alias, '') AS alias,
1236
1291
  s.auto_title,
1237
1292
  s.first_user_message,
@@ -1242,37 +1297,37 @@ show full content: recall paste --show <id>
1242
1297
  LEFT JOIN session_aliases sa ON sa.session_id = m.session_id
1243
1298
  LEFT JOIN projects p ON p.id = s.project_id
1244
1299
  WHERE m.cluster_id = ?
1245
- ORDER BY COALESCE(s.started_at, ''), m.matched_at, m.session_id`).all(e);return{cluster:js(s),members:n.map(Jh)}}function fc(e){try{Wh();let t=pc(e);if(!t)return;let s=dc(xr,`${e}.json`),n={schema:"claude-recall.bug-pattern-cluster.v1",cluster:t.cluster,members:t.members,backed_up_at:new Date().toISOString()};Fh(s,JSON.stringify(n,null,2))}catch(t){console.error("[bug-patterns] backup failed:",t)}}function _c(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:Fs(s),members:n.map(lE)}}function yc(e){try{aE();let t=bc(e);if(!t)return;let s=hc(Cr,`${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 wc(e){return e?_().prepare(`SELECT * FROM bug_pattern_clusters
1246
1301
  WHERE signature_hash = ?
1247
- ORDER BY last_seen_at DESC, id ASC`).all(e).map(js):[]}function hc(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(Fs):[]}function Rc(e){if(!e)return new Set;let s=_().prepare(`SELECT DISTINCT m.session_id
1248
1303
  FROM bug_pattern_members m
1249
1304
  JOIN bug_pattern_clusters c ON c.id = m.cluster_id
1250
- WHERE c.signature_hash = ?`).all(e);return new Set(s.map(n=>n.session_id))}var zh=/\b0x[0-9a-fA-F]+\b/g,Yh=/\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,qh=/\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z?\b/g,Kh=/:\d+:\d+/g,Vh=/\bline\s+\d+\b/gi,Zh=/\bcolumn\s+\d+\b/gi,Qh=/\b(?:pid|PID|process(?:\s+id)?)\s*[:=]?\s*\d+\b/gi,eE=/\b(?:port|:)\s*[:=]?\s*\d{2,5}\b/gi,tE=/\b\d{4,}\b/g,sE=/(['"`])[^'"`\n]{1,128}\1/g;function nE(e){if(!e)return"";let t=String(e);return t=t.replace(zh,"<hex>"),t=t.replace(Yh,"<uuid>"),t=t.replace(qh,"<ts>"),t=t.replace(Kh,":<line>:<col>"),t=t.replace(Vh,"line <n>"),t=t.replace(Zh,"column <n>"),t=t.replace(Qh,"pid <n>"),t=t.replace(eE,"port <n>"),t=t.replace(tE,"<num>"),t=t.replace(sE,"<arg>"),t=t.replace(/\s+/g," ").trim(),t.toLowerCase()}function rE(e){let t=(e.error_type??"unknown").toLowerCase().trim(),s=nE(e.snippet??e.message_hash??""),n=`${t}|${s}`;return Gh("sha256").update(n).digest("hex").slice(0,16)}function oE(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 uE=/\b0x[0-9a-fA-F]+\b/g,mE=/\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,pE=/\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z?\b/g,gE=/:\d+:\d+/g,fE=/\bline\s+\d+\b/gi,_E=/\bcolumn\s+\d+\b/gi,hE=/\b(?:pid|PID|process(?:\s+id)?)\s*[:=]?\s*\d+\b/gi,EE=/\b(?:port|:)\s*[:=]?\s*\d{2,5}\b/gi,bE=/\b\d{4,}\b/g,SE=/(['"`])[^'"`\n]{1,128}\1/g;function TE(e){if(!e)return"";let t=String(e);return t=t.replace(uE,"<hex>"),t=t.replace(mE,"<uuid>"),t=t.replace(pE,"<ts>"),t=t.replace(gE,":<line>:<col>"),t=t.replace(fE,"line <n>"),t=t.replace(_E,"column <n>"),t=t.replace(hE,"pid <n>"),t=t.replace(EE,"port <n>"),t=t.replace(bE,"<num>"),t=t.replace(SE,"<arg>"),t=t.replace(/\s+/g," ").trim(),t.toLowerCase()}function yE(e){let t=(e.error_type??"unknown").toLowerCase().trim(),s=TE(e.snippet??e.message_hash??""),n=`${t}|${s}`;return dE("sha256").update(n).digest("hex").slice(0,16)}function wE(e){let t=_(),s=["oi.bug_signatures IS NOT NULL"],n=[];e&&(s.push("p.name = ?"),n.push(e));let r=`WHERE ${s.join(" AND ")}`,o=t.prepare(`SELECT oi.session_id AS session_id,
1251
1306
  p.name AS project,
1252
1307
  s.started_at AS started_at,
1253
1308
  oi.bug_signatures AS bug_signatures
1254
1309
  FROM session_output_index oi
1255
1310
  LEFT JOIN sessions s ON s.id = oi.session_id
1256
1311
  LEFT JOIN projects p ON p.id = s.project_id
1257
- ${r}`).all(...n),i=[];for(let a of o){if(!a.bug_signatures)continue;let l=[];try{let c=JSON.parse(a.bug_signatures);Array.isArray(c)&&(l=c)}catch{continue}for(let c of l){if(!c||typeof c!="object"||!(c.snippet??"").trim())continue;let p=rE(c);i.push({session_id:a.session_id,project:a.project,started_at:a.started_at,signature:c,fingerprint:p})}}return i}function iE(e){let t=new Map;for(let n of e){let r=t.get(n.fingerprint);r||(r=[],t.set(n.fingerprint,r)),r.push(n)}let s=[];for(let[n,r]of t){let o=new Set,i=[];for(let u of r)o.has(u.session_id)||(o.add(u.session_id),i.push(u));let a=[...i].sort((u,p)=>{let m=u.started_at??"",f=p.started_at??"";return m&&f?m<f?-1:m>f?1:0:m?-1:f?1:0}),l=a.find(u=>u.started_at),c=[...a].reverse().find(u=>u.started_at);s.push({fingerprint:n,example_message:i[0].signature.snippet??i[0].signature.message_hash??"",members:i,first_seen_at:l?.started_at??new Date().toISOString(),last_seen_at:c?.started_at??new Date().toISOString()})}return s}function aE(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 cE(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-aE(s[u],s[m])<=n&&p.push(m)}i.push(p)}let a=new Array(o).fill(!1),l=new Array(o).fill(-1),c=[];for(let u=0;u<o;u++){if(a[u])continue;a[u]=!0;let p=i[u];if(p.length<r)continue;let m=c.length;c.push({members:[t[u]]}),l[u]=m;let f=[...p];for(;f.length>0;){let g=f.shift();if(!a[g]&&(a[g]=!0,i[g].length>=r))for(let h of i[g])(!a[h]||l[h]===-1)&&f.push(h);l[g]===-1&&(l[g]=m,c[m].members.push(t[g]))}}return c}async function lE(e,t,s,n){if(e.length===0)return[];let r=e.map(l=>{let c=l.signature.snippet??l.signature.message_hash??"";return`${l.signature.error_type??""}: ${c}`.trim()}),o=await t(r);if(o.length!==e.length)throw new Error(`embedder returned ${o.length} vectors for ${e.length} inputs`);let i=cE({records:e,vectors:o,epsilon:s,minPts:n}),a=[];for(let l of i){if(l.members.length===0)continue;let c=new Set,u=[];for(let E of l.members)c.has(E.session_id)||(c.add(E.session_id),u.push(E));if(u.length===0)continue;let m=`sem:${[...u.map(E=>E.fingerprint)].sort()[0]}`,f=[...u].sort((E,b)=>{let S=E.started_at??"",C=b.started_at??"";return S<C?-1:S>C?1:0}),g=f.find(E=>E.started_at),h=[...f].reverse().find(E=>E.started_at);a.push({fingerprint:m,example_message:u[0].signature.snippet??u[0].signature.message_hash??"",members:u,first_seen_at:g?.started_at??new Date().toISOString(),last_seen_at:h?.started_at??new Date().toISOString()})}return a}function Ec(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=_c(n.fingerprint),o=hc(n.fingerprint),i=n.members.map(c=>c.session_id).filter(c=>!o.has(c));if(r.length===0){let c=uc({signature_hash:n.fingerprint,example_message:n.example_message.slice(0,256),member_session_ids:n.members.map(u=>u.session_id),first_seen_at:n.first_seen_at,last_seen_at:n.last_seen_at});s.clusters_created+=1,s.members_added+=c.members.length,s.cluster_ids.push(c.cluster.id);continue}if(i.length===0){s.cluster_ids.push(r[0].id);continue}let a=r[0],l=mc(a.id,i);l.added>0&&(s.clusters_merged+=1,s.members_added+=l.added),s.cluster_ids.push(a.id)}return s}async function bc(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=oE(e.project),i=new Set(o.map(S=>S.session_id)),a=iE(o),l=[],c=!1;if(e.semantic){let S=e.embedder??null;if(!S)try{S=await pE()}catch(C){let L=(C instanceof Error?C.message:String(C)).split(`
1258
- `)[0];console.warn(`[bug-pattern] --semantic requested but the embedder is unavailable: ${L}
1259
- Falling back to exact-match-only clustering. Run \`recall semantic install\` to enable the semantic pass.`),c=!0}if(S){let C=[];for(let R of a)R.members.length===1&&C.push(R.members[0]);C.length>=2&&(l=await lE(C,S,n,r))}}let u=a.filter(S=>S.members.length>=t),p=l.filter(S=>S.members.length>=t),m=Ec(u,t),f=Ec(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(","),R=S.prepare(`SELECT * FROM bug_pattern_clusters
1260
- WHERE id IN (${C})
1312
+ ${r}`).all(...n),i=[];for(let a of o){if(!a.bug_signatures)continue;let l=[];try{let c=JSON.parse(a.bug_signatures);Array.isArray(c)&&(l=c)}catch{continue}for(let c of l){if(!c||typeof c!="object"||!(c.snippet??"").trim())continue;let m=yE(c);i.push({session_id:a.session_id,project:a.project,started_at:a.started_at,signature:c,fingerprint:m})}}return i}function RE(e){let t=new Map;for(let n of e){let r=t.get(n.fingerprint);r||(r=[],t.set(n.fingerprint,r)),r.push(n)}let s=[];for(let[n,r]of t){let o=new Set,i=[];for(let u of r)o.has(u.session_id)||(o.add(u.session_id),i.push(u));let a=[...i].sort((u,m)=>{let p=u.started_at??"",f=m.started_at??"";return p&&f?p<f?-1:p>f?1:0:p?-1:f?1:0}),l=a.find(u=>u.started_at),c=[...a].reverse().find(u=>u.started_at);s.push({fingerprint:n,example_message:i[0].signature.snippet??i[0].signature.message_hash??"",members:i,first_seen_at:l?.started_at??new Date().toISOString(),last_seen_at:c?.started_at??new Date().toISOString()})}return s}function xE(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 kE(e){let{records:t,vectors:s,epsilon:n,minPts:r}=e,o=t.length;if(o===0)return[];let i=[];for(let u=0;u<o;u++){let m=[];for(let p=0;p<o;p++){if(u===p)continue;1-xE(s[u],s[p])<=n&&m.push(p)}i.push(m)}let a=new Array(o).fill(!1),l=new Array(o).fill(-1),c=[];for(let u=0;u<o;u++){if(a[u])continue;a[u]=!0;let m=i[u];if(m.length<r)continue;let p=c.length;c.push({members:[t[u]]}),l[u]=p;let f=[...m];for(;f.length>0;){let g=f.shift();if(!a[g]&&(a[g]=!0,i[g].length>=r))for(let h of i[g])(!a[h]||l[h]===-1)&&f.push(h);l[g]===-1&&(l[g]=p,c[p].members.push(t[g]))}}return c}async function NE(e,t,s,n){if(e.length===0)return[];let r=e.map(l=>{let c=l.signature.snippet??l.signature.message_hash??"";return`${l.signature.error_type??""}: ${c}`.trim()}),o=await t(r);if(o.length!==e.length)throw new Error(`embedder returned ${o.length} vectors for ${e.length} inputs`);let i=kE({records:e,vectors:o,epsilon:s,minPts:n}),a=[];for(let l of i){if(l.members.length===0)continue;let c=new Set,u=[];for(let E of l.members)c.has(E.session_id)||(c.add(E.session_id),u.push(E));if(u.length===0)continue;let p=`sem:${[...u.map(E=>E.fingerprint)].sort()[0]}`,f=[...u].sort((E,b)=>{let S=E.started_at??"",N=b.started_at??"";return S<N?-1:S>N?1:0}),g=f.find(E=>E.started_at),h=[...f].reverse().find(E=>E.started_at);a.push({fingerprint:p,example_message:u[0].signature.snippet??u[0].signature.message_hash??"",members:u,first_seen_at:g?.started_at??new Date().toISOString(),last_seen_at:h?.started_at??new Date().toISOString()})}return a}function xc(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=Rc(n.fingerprint),i=n.members.map(c=>c.session_id).filter(c=>!o.has(c));if(r.length===0){let c=Ec({signature_hash:n.fingerprint,example_message:n.example_message.slice(0,256),member_session_ids:n.members.map(u=>u.session_id),first_seen_at:n.first_seen_at,last_seen_at:n.last_seen_at});s.clusters_created+=1,s.members_added+=c.members.length,s.cluster_ids.push(c.cluster.id);continue}if(i.length===0){s.cluster_ids.push(r[0].id);continue}let a=r[0],l=Sc(a.id,i);l.added>0&&(s.clusters_merged+=1,s.members_added+=l.added),s.cluster_ids.push(a.id)}return s}async function kc(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=wE(e.project),i=new Set(o.map(S=>S.session_id)),a=RE(o),l=[],c=!1;if(e.semantic){let S=e.embedder??null;if(!S)try{S=await AE()}catch(N){let C=(N instanceof Error?N.message:String(N)).split(`
1313
+ `)[0];console.warn(`[bug-pattern] --semantic requested but the embedder is unavailable: ${C}
1314
+ Falling back to exact-match-only clustering. Run \`recall semantic install\` to enable the semantic pass.`),c=!0}if(S){let N=[];for(let y of a)y.members.length===1&&N.push(y.members[0]);N.length>=2&&(l=await NE(N,S,n,r))}}let u=a.filter(S=>S.members.length>=t),m=l.filter(S=>S.members.length>=t),p=xc(u,t),f=xc(m,t),g=[...p.cluster_ids,...f.cluster_ids],h=Array.from(new Set(g)),E=[];if(h.length>0){let S=_(),N=h.map(()=>"?").join(","),y=S.prepare(`SELECT * FROM bug_pattern_clusters
1315
+ WHERE id IN (${N})
1261
1316
  ORDER BY occurrence_count DESC, last_seen_at DESC
1262
- LIMIT ?`).all(...h,s);for(let L of R)E.push({id:L.id,signature_hash:L.signature_hash,example_message:L.example_message,occurrence_count:L.occurrence_count,first_seen_at:L.first_seen_at,last_seen_at:L.last_seen_at,resolved_in_session_id:L.resolved_in_session_id,fix_summary:L.fix_summary})}return{progress:{total_sessions:i.size,total_signatures:o.length,exact_match_groups:u.length,semantic_groups:p.length,clusters_created:m.clusters_created+f.clusters_created,clusters_merged:m.clusters_merged+f.clusters_merged,members_added:m.members_added+f.members_added,semantic_skipped:c},clusters:E}}var dE=async()=>{let{embed:e,loadEmbedder:t,getEmbedderStatus:s}=await Promise.resolve().then(()=>(Ve(),ir));return s().loaded||await t(),e},uE=dE;async function pE(){return uE()}function mE(e,t){let s=gc(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 Sc(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=he(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 bc(r)}catch(c){console.error(c instanceof Error?c.message:String(c)),process.exitCode=1;return}let a=Number(((Date.now()-o)/1e3).toFixed(1)),l=[];for(let c of i.clusters.slice(0,s)){let u=mE(c.id,3);u&&l.push(u)}if(e.json){console.log(JSON.stringify({project:n??null,progress:i.progress,elapsed_seconds:a,clusters:l},null,2));return}if(console.log(`Done in ${a}s \u2014 sessions=${i.progress.total_sessions} signatures=${i.progress.total_signatures} clusters: created=${i.progress.clusters_created} merged=${i.progress.clusters_merged} members_added=${i.progress.members_added}`),i.progress.semantic_skipped&&console.log(" \u24D8 semantic pass skipped \u2014 embedder unavailable. Run `recall semantic install` to enable."),l.length===0){i.progress.total_signatures===0?console.log(" \u24D8 No bug signatures in the corpus yet. Run `recall extract-outputs --project <name>` first to populate session_output_index."):console.log(` \u24D8 No clusters at min-cluster-size=${t}. Try \`--semantic\` to merge near-duplicate snippets, or lower \`--min-cluster-size 2\` to surface pairs.`);return}console.log(`
1263
- Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u2713 resolved":"open",p=c.example_message.slice(0,80);console.log(`
1317
+ LIMIT ?`).all(...h,s);for(let C of y)E.push({id:C.id,signature_hash:C.signature_hash,example_message:C.example_message,occurrence_count:C.occurrence_count,first_seen_at:C.first_seen_at,last_seen_at:C.last_seen_at,resolved_in_session_id:C.resolved_in_session_id,fix_summary:C.fix_summary})}return{progress:{total_sessions:i.size,total_signatures:o.length,exact_match_groups:u.length,semantic_groups:m.length,clusters_created:p.clusters_created+f.clusters_created,clusters_merged:p.clusters_merged+f.clusters_merged,members_added:p.members_added+f.members_added,semantic_skipped:c},clusters:E}}var LE=async()=>{let{embed:e,loadEmbedder:t,getEmbedderStatus:s}=await Promise.resolve().then(()=>(Ve(),ur));return s().loaded||await t(),e},CE=LE;async function AE(){return CE()}function OE(e,t){let s=Tc(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 Nc(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=he(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 kc(r)}catch(c){console.error(c instanceof Error?c.message:String(c)),process.exitCode=1;return}let a=Number(((Date.now()-o)/1e3).toFixed(1)),l=[];for(let c of i.clusters.slice(0,s)){let u=OE(c.id,3);u&&l.push(u)}if(e.json){console.log(JSON.stringify({project:n??null,progress:i.progress,elapsed_seconds:a,clusters:l},null,2));return}if(console.log(`Done in ${a}s \u2014 sessions=${i.progress.total_sessions} signatures=${i.progress.total_signatures} clusters: created=${i.progress.clusters_created} merged=${i.progress.clusters_merged} members_added=${i.progress.members_added}`),i.progress.semantic_skipped&&console.log(" \u24D8 semantic pass skipped \u2014 embedder unavailable. Run `recall semantic install` to enable."),l.length===0){i.progress.total_signatures===0?console.log(" \u24D8 No bug signatures in the corpus yet. Run `recall extract-outputs --project <name>` first to populate session_output_index."):console.log(` \u24D8 No clusters at min-cluster-size=${t}. Try \`--semantic\` to merge near-duplicate snippets, or lower \`--min-cluster-size 2\` to surface pairs.`);return}console.log(`
1318
+ Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u2713 resolved":"open",m=c.example_message.slice(0,80);console.log(`
1264
1319
  [${u}] occurs=${c.occurrence_count} hash=${c.signature_hash.slice(0,8)}
1265
- ${p}
1266
- first=${c.first_seen_at} last=${c.last_seen_at}`);for(let m of c.sample_members){let f=m.project?`[${m.project}] `:"";console.log(` \u2022 ${f}${m.title} (${m.session_id.slice(0,8)})`)}}console.log("\n Review at /graph/patterns in the web UI, or `recall neighborhood <session-id>` for an agent-facing bundle.")}T();import{z as VC}from"zod";T();function yc(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}Rr();var Oc=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),Ac=new Set(["pagerank","embedding-rerank","hybrid"]);function CE(e){if(!e)return;let t=e.split(",").map(s=>s.trim()).filter(Boolean);for(let s of t)if(!Oc.has(s))throw new Error(`invalid --edge-types value: '${s}'. Valid: ${Array.from(Oc).join(", ")}`);return t}function LE(e){if(!e)return"hybrid";if(!Ac.has(e))throw new Error(`invalid --scoring value: '${e}'. Valid: ${Array.from(Ac).join(", ")}`);return e}async function Ic(e,t){let s=yc(e);if(!s){console.error(`session not found or prefix ambiguous: ${e}`),process.exitCode=1;return}let n,r;try{n=LE(t.scoring),r=CE(t.edgeTypes)}catch(l){console.error(l instanceof Error?l.message:String(l)),process.exitCode=1;return}let o=t.budget?Math.max(100,Number(t.budget)):4e3;if(!Number.isFinite(o)){console.error("--budget must be a positive number"),process.exitCode=1;return}let i=t.maxDepth?Math.max(1,Number(t.maxDepth)):2;if(!Number.isFinite(i)){console.error("--max-depth must be a positive number"),process.exitCode=1;return}let a;try{a=Us(s,{budget:o,maxDepth:i,scoring:n,edgeTypes:r,includeWikiLinks:t.wikiLinks!==!1,includeSuggestions:!!t.includeSuggestions})}catch(l){console.error(l instanceof Error?l.message:String(l)),process.exitCode=1;return}if(t.json){process.stdout.write(JSON.stringify(a,null,2)+`
1320
+ ${m}
1321
+ first=${c.first_seen_at} last=${c.last_seen_at}`);for(let p of c.sample_members){let f=p.project?`[${p.project}] `:"";console.log(` \u2022 ${f}${p.title} (${p.session_id.slice(0,8)})`)}}console.log("\n Review at /graph/patterns in the web UI, or `recall neighborhood <session-id>` for an agent-facing bundle.")}w();import{z as NC}from"zod";w();function Lc(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}Ar();var jc=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),Pc=new Set(["pagerank","embedding-rerank","hybrid"]);function GE(e){if(!e)return;let t=e.split(",").map(s=>s.trim()).filter(Boolean);for(let s of t)if(!jc.has(s))throw new Error(`invalid --edge-types value: '${s}'. Valid: ${Array.from(jc).join(", ")}`);return t}function YE(e){if(!e)return"hybrid";if(!Pc.has(e))throw new Error(`invalid --scoring value: '${e}'. Valid: ${Array.from(Pc).join(", ")}`);return e}async function Fc(e,t){let s=Lc(e);if(!s){console.error(`session not found or prefix ambiguous: ${e}`),process.exitCode=1;return}let n,r;try{n=YE(t.scoring),r=GE(t.edgeTypes)}catch(l){console.error(l instanceof Error?l.message:String(l)),process.exitCode=1;return}let o=t.budget?Math.max(100,Number(t.budget)):4e3;if(!Number.isFinite(o)){console.error("--budget must be a positive number"),process.exitCode=1;return}let i=t.maxDepth?Math.max(1,Number(t.maxDepth)):2;if(!Number.isFinite(i)){console.error("--max-depth must be a positive number"),process.exitCode=1;return}let a;try{a=Hs(s,{budget:o,maxDepth:i,scoring:n,edgeTypes:r,includeWikiLinks:t.wikiLinks!==!1,includeSuggestions:!!t.includeSuggestions})}catch(l){console.error(l instanceof Error?l.message:String(l)),process.exitCode=1;return}if(t.json){process.stdout.write(JSON.stringify(a,null,2)+`
1267
1322
  `);return}process.stdout.write(a.bundle),a.truncated.length>0&&console.error(`
1268
- [truncated ${a.truncated.length} refs to fit ${o}-token budget; ${a.budgetUsed} used / ${a.budgetRemaining} remaining]`)}T();I();var OE=[[/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}]],vc={label:"unknown",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30};function et(e){if(!e)return vc;for(let[t,s]of OE)if(t.test(e))return s;return vc}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=et(c);i.input+=u.inputTokens/1e6*p.inputCentsPerMtok,i.output+=u.outputTokens/1e6*p.outputCentsPerMtok,i.cacheCreate+=u.cacheCreateTokens/1e6*p.cacheCreateCentsPerMtok,i.cacheRead+=u.cacheReadTokens/1e6*p.cacheReadCentsPerMtok,a+=u.inputTokens+u.outputTokens+u.cacheCreateTokens+u.cacheReadTokens}let l=i.input+i.output+i.cacheCreate+i.cacheRead;return{cents:l,dollars:l/100,totalTokens:a,parts:i}}let s=et(t),n={input:e.inputTokens/1e6*s.inputCentsPerMtok,output:e.outputTokens/1e6*s.outputCentsPerMtok,cacheCreate:e.cacheCreateTokens/1e6*s.cacheCreateCentsPerMtok,cacheRead:e.cacheReadTokens/1e6*s.cacheReadCentsPerMtok},r=n.input+n.output+n.cacheCreate+n.cacheRead,o=e.inputTokens+e.outputTokens+e.cacheCreateTokens+e.cacheReadTokens;return{cents:r,dollars:r/100,totalTokens:o,parts:n}}function se(e){let t=e/100;return t===0?"$0.00":t<.01?"<$0.01":t<1?`$${t.toFixed(2)}`:t<100?`$${t.toFixed(2)}`:t<1e4?`$${t.toFixed(0)}`:`$${(t/1e3).toFixed(1)}k`}function le(e){return!Number.isFinite(e)||e<0?"0":e<1e3?String(Math.round(e)):e<1e6?`${(e/1e3).toFixed(1)}k`:e<1e9?`${(e/1e6).toFixed(2)}M`:e<1e12?`${(e/1e9).toFixed(2)}B`:`${(e/1e12).toFixed(2)}T`}T();T();var AE=500,Bs=new Set;function Mc(){return Bs.size}function IE(){return`
1323
+ [truncated ${a.truncated.length} refs to fit ${o}-token budget; ${a.budgetUsed} used / ${a.budgetRemaining} remaining]`)}w();v();var zE=[[/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}]],Uc={label:"unknown",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30};function et(e){if(!e)return Uc;for(let[t,s]of zE)if(t.test(e))return s;return Uc}function Ie(e,t){if(e.byModel&&Object.keys(e.byModel).length>0){let i={input:0,output:0,cacheCreate:0,cacheRead:0},a=0;for(let[c,u]of Object.entries(e.byModel)){let m=et(c);i.input+=u.inputTokens/1e6*m.inputCentsPerMtok,i.output+=u.outputTokens/1e6*m.outputCentsPerMtok,i.cacheCreate+=u.cacheCreateTokens/1e6*m.cacheCreateCentsPerMtok,i.cacheRead+=u.cacheReadTokens/1e6*m.cacheReadCentsPerMtok,a+=u.inputTokens+u.outputTokens+u.cacheCreateTokens+u.cacheReadTokens}let l=i.input+i.output+i.cacheCreate+i.cacheRead;return{cents:l,dollars:l/100,totalTokens:a,parts:i}}let s=et(t),n={input:e.inputTokens/1e6*s.inputCentsPerMtok,output:e.outputTokens/1e6*s.outputCentsPerMtok,cacheCreate:e.cacheCreateTokens/1e6*s.cacheCreateCentsPerMtok,cacheRead:e.cacheReadTokens/1e6*s.cacheReadCentsPerMtok},r=n.input+n.output+n.cacheCreate+n.cacheRead,o=e.inputTokens+e.outputTokens+e.cacheCreateTokens+e.cacheReadTokens;return{cents:r,dollars:r/100,totalTokens:o,parts:n}}function se(e){let t=e/100;return t===0?"$0.00":t<.01?"<$0.01":t<1?`$${t.toFixed(2)}`:t<100?`$${t.toFixed(2)}`:t<1e4?`$${t.toFixed(0)}`:`$${(t/1e3).toFixed(1)}k`}function le(e){return!Number.isFinite(e)||e<0?"0":e<1e3?String(Math.round(e)):e<1e6?`${(e/1e3).toFixed(1)}k`:e<1e9?`${(e/1e6).toFixed(2)}M`:e<1e12?`${(e/1e9).toFixed(2)}B`:`${(e/1e12).toFixed(2)}T`}w();w();var qE=500,Ws=new Set;function Bc(){return Ws.size}function KE(){return`
1269
1324
  SELECT m.uuid, m.session_id, m.timestamp, m.raw_json
1270
1325
  FROM messages m
1271
1326
  LEFT JOIN message_usage mu ON mu.message_uuid = m.uuid
1272
1327
  WHERE m.role = 'assistant' AND mu.message_uuid IS NULL
1273
1328
  AND m.uuid NOT IN (SELECT value FROM json_each(?))
1274
1329
  LIMIT ?
1275
- `}function vE(e,t){let s=t.limit??Number.MAX_SAFE_INTEGER,n=Math.max(1,t.chunkSize??AE),r=e.prepare(IE()),o=e.prepare(`
1330
+ `}function VE(e,t){let s=t.limit??Number.MAX_SAFE_INTEGER,n=Math.max(1,t.chunkSize??qE),r=e.prepare(KE()),o=e.prepare(`
1276
1331
  INSERT INTO message_usage (
1277
1332
  message_uuid, session_id, model,
1278
1333
  input_tokens, output_tokens, cache_create_tokens, cache_read_tokens,
@@ -1282,7 +1337,7 @@ Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u271
1282
1337
  @input, @output, @cc, @cr, @ts
1283
1338
  )
1284
1339
  ON CONFLICT(message_uuid) DO NOTHING
1285
- `),i=0,a=0,l=new Set;for(;i<s;){let c=Math.min(n,s-i),u=JSON.stringify([...Bs]),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{Bs.add(g.uuid);continue}let E=wn(h.message);if(!E){Bs.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)is(e,g),l.add(g)})(),i+=p.length,t.onProgress?.({scanned:i,inserted:a,sessionsTouched:l.size,done:p.length<c}),p.length<c)break}return{scanned:i,inserted:a,sessionsTouched:l.size,done:!0}}function $c(e={}){return vE(_(),e)}function kr(e){let t=new Map;for(let n of e){let r=n.model??null,o=t.get(r)??{inputTokens:0,outputTokens:0,cacheCreateTokens:0,cacheReadTokens:0,messageCount:0};o.inputTokens+=n.input_tokens,o.outputTokens+=n.output_tokens,o.cacheCreateTokens+=n.cache_create_tokens,o.cacheReadTokens+=n.cache_read_tokens,o.messageCount+=n.n,t.set(r,o)}let s=[];for(let[n,r]of t.entries()){let o=Ie({inputTokens:r.inputTokens,outputTokens:r.outputTokens,cacheCreateTokens:r.cacheCreateTokens,cacheReadTokens:r.cacheReadTokens},n);s.push({model:n,modelLabel:et(n).label,inputTokens:r.inputTokens,outputTokens:r.outputTokens,cacheCreateTokens:r.cacheCreateTokens,cacheReadTokens:r.cacheReadTokens,messageCount:r.messageCount,cost:o})}return s.sort((n,r)=>r.cost.cents-n.cost.cents)}function Nr(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 Dc(e){let t=_(),s=t.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
1340
+ `),i=0,a=0,l=new Set;for(;i<s;){let c=Math.min(n,s-i),u=JSON.stringify([...Ws]),m=r.all(u,c);if(m.length===0)break;let p=new Set;if(e.transaction(()=>{for(let g of m){let h;try{h=JSON.parse(g.raw_json)}catch{Ws.add(g.uuid);continue}let E=Ln(h.message);if(!E){Ws.add(g.uuid);continue}o.run({uuid:g.uuid,session_id:g.session_id,model:h.message?.model??null,input:E.inputTokens,output:E.outputTokens,cc:E.cacheCreateTokens,cr:E.cacheReadTokens,ts:g.timestamp}),a+=1,p.add(g.session_id)}for(let g of p)cs(e,g),l.add(g)})(),i+=m.length,t.onProgress?.({scanned:i,inserted:a,sessionsTouched:l.size,done:m.length<c}),m.length<c)break}return{scanned:i,inserted:a,sessionsTouched:l.size,done:!0}}function Hc(e={}){return VE(_(),e)}function Or(e){let t=new Map;for(let n of e){let r=n.model??null,o=t.get(r)??{inputTokens:0,outputTokens:0,cacheCreateTokens:0,cacheReadTokens:0,messageCount:0};o.inputTokens+=n.input_tokens,o.outputTokens+=n.output_tokens,o.cacheCreateTokens+=n.cache_create_tokens,o.cacheReadTokens+=n.cache_read_tokens,o.messageCount+=n.n,t.set(r,o)}let s=[];for(let[n,r]of t.entries()){let o=Ie({inputTokens:r.inputTokens,outputTokens:r.outputTokens,cacheCreateTokens:r.cacheCreateTokens,cacheReadTokens:r.cacheReadTokens},n);s.push({model:n,modelLabel:et(n).label,inputTokens:r.inputTokens,outputTokens:r.outputTokens,cacheCreateTokens:r.cacheCreateTokens,cacheReadTokens:r.cacheReadTokens,messageCount:r.messageCount,cost:o})}return s.sort((n,r)=>r.cost.cents-n.cost.cents)}function vr(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 Wc(e){let t=_(),s=t.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
1286
1341
  s.message_count,
1287
1342
  s.total_input_tokens, s.total_output_tokens,
1288
1343
  s.total_cache_create_tokens, s.total_cache_read_tokens,
@@ -1297,7 +1352,7 @@ Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u271
1297
1352
  COUNT(*) AS n
1298
1353
  FROM message_usage
1299
1354
  WHERE session_id = ?
1300
- GROUP BY model`).all(e),r=kr(n),o=s.total_input_tokens??0,i=s.total_output_tokens??0,a=s.total_cache_create_tokens??0,l=s.total_cache_read_tokens??0,c=Ie({inputTokens:o,outputTokens:i,cacheCreateTokens:a,cacheReadTokens:l,...Nr(r)},s.primary_model);return{sessionId:s.id,project:s.project,startedAt:s.started_at,endedAt:s.ended_at,messageCount:s.message_count,primaryModel:s.primary_model,primaryModelLabel:et(s.primary_model).label,inputTokens:o,outputTokens:i,cacheCreateTokens:a,cacheReadTokens:l,totalTokens:c.totalTokens,cost:c,byModel:r,display:{dollars:se(c.cents),tokens:le(c.totalTokens),model:et(s.primary_model).label}}}function jc(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=Or(n),o=s.total_input_tokens??0,i=s.total_output_tokens??0,a=s.total_cache_create_tokens??0,l=s.total_cache_read_tokens??0,c=Ie({inputTokens:o,outputTokens:i,cacheCreateTokens:a,cacheReadTokens:l,...vr(r)},s.primary_model);return{sessionId:s.id,project:s.project,startedAt:s.started_at,endedAt:s.ended_at,messageCount:s.message_count,primaryModel:s.primary_model,primaryModelLabel:et(s.primary_model).label,inputTokens:o,outputTokens:i,cacheCreateTokens:a,cacheReadTokens:l,totalTokens:c.totalTokens,cost:c,byModel:r,display:{dollars:se(c.cents),tokens:le(c.totalTokens),model:et(s.primary_model).label}}}function Xc(e){let t=_(),s=t.prepare("SELECT id, name FROM projects WHERE name = ?").get(e);if(!s)return null;let n=t.prepare(`SELECT mu.model,
1301
1356
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
1302
1357
  COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
1303
1358
  COALESCE(SUM(mu.cache_create_tokens), 0) AS cache_create_tokens,
@@ -1306,12 +1361,12 @@ Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u271
1306
1361
  FROM message_usage mu
1307
1362
  JOIN sessions s ON s.id = mu.session_id
1308
1363
  WHERE s.project_id = ?
1309
- GROUP BY mu.model`).all(s.id),r=kr(n),o=t.prepare(`SELECT COALESCE(SUM(total_input_tokens), 0) AS input_tokens,
1364
+ GROUP BY mu.model`).all(s.id),r=Or(n),o=t.prepare(`SELECT COALESCE(SUM(total_input_tokens), 0) AS input_tokens,
1310
1365
  COALESCE(SUM(total_output_tokens), 0) AS output_tokens,
1311
1366
  COALESCE(SUM(total_cache_create_tokens), 0) AS cache_create_tokens,
1312
1367
  COALESCE(SUM(total_cache_read_tokens), 0) AS cache_read_tokens,
1313
1368
  COUNT(*) AS session_count
1314
- FROM sessions WHERE project_id = ?`).get(s.id),i=Ie({inputTokens:o.input_tokens,outputTokens:o.output_tokens,cacheCreateTokens:o.cache_create_tokens,cacheReadTokens:o.cache_read_tokens,...Nr(r)},null),l=t.prepare(`SELECT s.id, sa.alias, s.started_at,
1369
+ FROM sessions WHERE project_id = ?`).get(s.id),i=Ie({inputTokens:o.input_tokens,outputTokens:o.output_tokens,cacheCreateTokens:o.cache_create_tokens,cacheReadTokens:o.cache_read_tokens,...vr(r)},null),l=t.prepare(`SELECT s.id, sa.alias, s.started_at,
1315
1370
  s.total_input_tokens, s.total_output_tokens,
1316
1371
  s.total_cache_create_tokens, s.total_cache_read_tokens,
1317
1372
  s.primary_model
@@ -1322,7 +1377,7 @@ Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u271
1322
1377
  + COALESCE(s.total_output_tokens,0)
1323
1378
  + COALESCE(s.total_cache_create_tokens,0)
1324
1379
  + COALESCE(s.total_cache_read_tokens,0)) DESC
1325
- LIMIT 10`).all(s.id).map(c=>{let u=Ie({inputTokens:c.total_input_tokens??0,outputTokens:c.total_output_tokens??0,cacheCreateTokens:c.total_cache_create_tokens??0,cacheReadTokens:c.total_cache_read_tokens??0},c.primary_model);return{sessionId:c.id,alias:c.alias,startedAt:c.started_at,totalTokens:u.totalTokens,cost:u}});return{project:s.name,sessionCount:o.session_count,inputTokens:o.input_tokens,outputTokens:o.output_tokens,cacheCreateTokens:o.cache_create_tokens,cacheReadTokens:o.cache_read_tokens,totalTokens:i.totalTokens,cost:i,byModel:r,topSessions:l,display:{dollars:se(i.cents),tokens:le(i.totalTokens)}}}function Pc(e="all"){let t=_(),s=e==="7d"?new Date(Date.now()-7*864e5).toISOString():e==="30d"?new Date(Date.now()-30*864e5).toISOString():null,n=s?"WHERE mu.timestamp >= @since OR (mu.timestamp IS NULL AND s.started_at >= @since)":"",r=s?"WHERE m.timestamp >= @since OR (m.timestamp IS NULL AND s2.started_at >= @since)":"",o=s?{since:s}:{},i=y=>s?t.prepare(y).get(o):t.prepare(y).get(),a=y=>s?t.prepare(y).all(o):t.prepare(y).all(),l=a(`SELECT mu.model,
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:l,display:{dollars:se(i.cents),tokens:le(i.totalTokens)}}}function Jc(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(),l=a(`SELECT mu.model,
1326
1381
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
1327
1382
  COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
1328
1383
  COALESCE(SUM(mu.cache_create_tokens), 0) AS cache_create_tokens,
@@ -1331,7 +1386,7 @@ Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u271
1331
1386
  FROM message_usage mu
1332
1387
  JOIN sessions s ON s.id = mu.session_id
1333
1388
  ${n}
1334
- GROUP BY mu.model`),c=kr(l),u=0,p=0,m=0,f=0;for(let y of c)u+=y.inputTokens,p+=y.outputTokens,m+=y.cacheCreateTokens,f+=y.cacheReadTokens;let g=Ie({inputTokens:u,outputTokens:p,cacheCreateTokens:m,cacheReadTokens:f,...Nr(c)},null),h=s?i(`SELECT
1389
+ GROUP BY mu.model`),c=Or(l),u=0,m=0,p=0,f=0;for(let T of c)u+=T.inputTokens,m+=T.outputTokens,p+=T.cacheCreateTokens,f+=T.cacheReadTokens;let g=Ie({inputTokens:u,outputTokens:m,cacheCreateTokens:p,cacheReadTokens:f,...vr(c)},null),h=s?i(`SELECT
1335
1390
  (SELECT COUNT(DISTINCT m.session_id)
1336
1391
  FROM messages m
1337
1392
  JOIN sessions s2 ON s2.id = m.session_id
@@ -1355,7 +1410,7 @@ Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u271
1355
1410
  JOIN sessions s ON s.id = mu.session_id
1356
1411
  ${n}
1357
1412
  GROUP BY day, mu.model
1358
- ORDER BY day ASC`),b=new Map;for(let y of E){if(!y.day)continue;let U=Ie({inputTokens:y.input_tokens,outputTokens:y.output_tokens,cacheCreateTokens:y.cache_create_tokens,cacheReadTokens:y.cache_read_tokens},y.model),M=b.get(y.day)??{tokens:0,cents:0};M.tokens+=U.totalTokens,M.cents+=U.cents,b.set(y.day,M)}let S=[...b.entries()].map(([y,U])=>({day:y,tokens:U.tokens,cents:U.cents})).sort((y,U)=>y.day.localeCompare(U.day)),R=a(`SELECT s.id, p.name AS project, sa.alias, s.started_at,
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)),y=a(`SELECT s.id, p.name AS project, sa.alias, s.started_at,
1359
1414
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
1360
1415
  COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
1361
1416
  COALESCE(SUM(mu.cache_create_tokens), 0) AS cache_create_tokens,
@@ -1371,7 +1426,7 @@ Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u271
1371
1426
  + COALESCE(SUM(mu.output_tokens),0)
1372
1427
  + COALESCE(SUM(mu.cache_create_tokens),0)
1373
1428
  + COALESCE(SUM(mu.cache_read_tokens),0)) DESC
1374
- LIMIT 10`).map(y=>{let U=Ie({inputTokens:y.input_tokens,outputTokens:y.output_tokens,cacheCreateTokens:y.cache_create_tokens,cacheReadTokens:y.cache_read_tokens},y.primary_model);return{sessionId:y.id,project:y.project,alias:y.alias,startedAt:y.started_at,totalTokens:U.totalTokens,cost:U}}),L=a(`SELECT p.id AS project_id,
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}}),C=a(`SELECT p.id AS project_id,
1375
1430
  p.name AS project,
1376
1431
  mu.model,
1377
1432
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
@@ -1383,16 +1438,16 @@ Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u271
1383
1438
  JOIN sessions s ON s.id = mu.session_id
1384
1439
  LEFT JOIN projects p ON p.id = s.project_id
1385
1440
  ${n}
1386
- GROUP BY p.id, mu.model`),Q=new Map;for(let y of L){let U=y.project_id??"__none__",M=Q.get(U);M||(M={project:y.project??"(no project)",sessionIds:new Set,sessionsApprox:0,byModel:{}},Q.set(U,M)),y.sessions>M.sessionsApprox&&(M.sessionsApprox=y.sessions),M.byModel[y.model??"__unknown__"]={inputTokens:y.input_tokens,outputTokens:y.output_tokens,cacheCreateTokens:y.cache_create_tokens,cacheReadTokens:y.cache_read_tokens}}let v=[...Q.values()].map(y=>{let U=0,M=0,q=0,Be=0;for(let ut of Object.values(y.byModel))U+=ut.inputTokens,M+=ut.outputTokens,q+=ut.cacheCreateTokens,Be+=ut.cacheReadTokens;let je=Ie({inputTokens:U,outputTokens:M,cacheCreateTokens:q,cacheReadTokens:Be,byModel:y.byModel},null);return{project:y.project,sessions:y.sessionsApprox,totalTokens:je.totalTokens,cost:je}});v.sort((y,U)=>U.totalTokens-y.totalTokens);let ee=v.slice(0,20),B=t.prepare(`SELECT
1441
+ GROUP BY p.id, mu.model`),q=new Map;for(let T of C){let U=T.project_id??"__none__",M=q.get(U);M||(M={project:T.project??"(no project)",sessionIds:new Set,sessionsApprox:0,byModel:{}},q.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 I=[...q.values()].map(T=>{let U=0,M=0,K=0,He=0;for(let ut of Object.values(T.byModel))U+=ut.inputTokens,M+=ut.outputTokens,K+=ut.cacheCreateTokens,He+=ut.cacheReadTokens;let Pe=Ie({inputTokens:U,outputTokens:M,cacheCreateTokens:K,cacheReadTokens:He,byModel:T.byModel},null);return{project:T.project,sessions:T.sessionsApprox,totalTokens:Pe.totalTokens,cost:Pe}});I.sort((T,U)=>U.totalTokens-T.totalTokens);let ee=I.slice(0,20),B=t.prepare(`SELECT
1387
1442
  (SELECT COUNT(*) FROM messages WHERE role='assistant') AS assistant_messages,
1388
- (SELECT COUNT(*) FROM message_usage) AS messages_with_usage`).get();return{range:e,totalSessions:h.total_sessions,sessionsWithUsage:h.sessions_with_usage,inputTokens:u,outputTokens:p,cacheCreateTokens:m,cacheReadTokens:f,totalTokens:g.totalTokens,cost:g,daily:S,byModel:c,topSessions:R,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(Mc(),Math.max(0,B.assistant_messages-B.messages_with_usage))},display:{dollars:se(g.cents),tokens:le(g.totalTokens)}}}var ze=e=>e.toLocaleString();function ME(e){return _().prepare("SELECT id FROM sessions WHERE id = ? OR id LIKE ? LIMIT 1").get(e,`${e}%`)?.id??null}async function Fc(e,t){if(t.backfill){let r=t.limit?Math.max(1,Number(t.limit)):void 0;console.log(d.dim("backfilling per-message usage from raw_json\u2026"));let o=$c({limit:r});if(console.log(`${d.ok("backfill done")}: scanned ${d.bold(String(o.scanned))}, inserted ${d.bold(String(o.inserted))}, rolled-up ${d.bold(String(o.sessionsTouched))} sessions`),!e&&!t.project)return}if(e){let r=ME(e);if(!r){console.error(d.err(`no session matches '${e}'`)),process.exit(1);return}let o=Dc(r);if(!o){console.error(d.err("session has no usage data yet \u2014 try --backfill")),process.exit(1);return}if(t.json){console.log(JSON.stringify(o,null,2));return}if(console.log(""),console.log(d.bold("session cost")),console.log(d.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` id ${d.dim(o.sessionId)}`),console.log(` project ${d.accent(o.project??"\u2014")}`),console.log(` started ${d.dim(o.startedAt??"n/a")}`),console.log(` messages ${d.accent(ze(o.messageCount))}`),console.log(` model ${d.accent(o.primaryModelLabel)} ${d.dim(o.primaryModel??"")}`),console.log(""),console.log(` input ${ze(o.inputTokens).padStart(12)}`),console.log(` output ${ze(o.outputTokens).padStart(12)}`),console.log(` cache write ${ze(o.cacheCreateTokens).padStart(12)}`),console.log(` cache read ${ze(o.cacheReadTokens).padStart(12)}`),console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),console.log(` total tokens ${d.bold(ze(o.totalTokens).padStart(12))}`),console.log(` estimated cost ${d.accent(se(o.cost.cents).padStart(12))}`),o.byModel.length>1){console.log(""),console.log(d.dim(" by model:"));for(let i of o.byModel)console.log(` ${i.modelLabel.padEnd(14)} ${le(i.inputTokens+i.outputTokens+i.cacheCreateTokens+i.cacheReadTokens).padStart(10)} ${d.accent(se(i.cost.cents).padStart(10))}`)}console.log("");return}if(t.project){let r=jc(t.project);if(!r){console.error(d.err(`project '${t.project}' not found`)),process.exit(1);return}if(t.json){console.log(JSON.stringify(r,null,2));return}if(console.log(""),console.log(d.bold(`project \xB7 ${r.project}`)),console.log(d.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` sessions ${d.accent(ze(r.sessionCount))}`),console.log(` total tokens ${d.accent(le(r.totalTokens).padStart(12))}`),console.log(` estimated cost ${d.accent(se(r.cost.cents).padStart(12))}`),r.byModel.length>0){console.log(""),console.log(d.dim(" by model:"));for(let o of r.byModel)console.log(` ${o.modelLabel.padEnd(14)} ${le(o.inputTokens+o.outputTokens+o.cacheCreateTokens+o.cacheReadTokens).padStart(10)} ${d.accent(se(o.cost.cents).padStart(10))}`)}if(r.topSessions.length>0){console.log(""),console.log(d.dim(" top sessions:"));for(let o of r.topSessions){let i=o.alias??o.sessionId.slice(0,8);console.log(` ${i.padEnd(22)} ${le(o.totalTokens).padStart(10)} ${d.accent(se(o.cost.cents).padStart(10))}`)}}console.log("");return}let s=t.days==="7"?"7d":t.days==="30"?"30d":"all",n=Pc(s);if(t.json){console.log(JSON.stringify(n,null,2));return}if(console.log(""),console.log(d.bold(`overview \xB7 ${s}`)),console.log(d.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` sessions ${d.accent(ze(n.totalSessions))} ${d.dim(`(${n.sessionsWithUsage} w/ usage)`)}`),console.log(` total tokens ${d.accent(le(n.totalTokens).padStart(12))}`),console.log(` estimated cost ${d.accent(se(n.cost.cents).padStart(12))}`),n.backfill.pending>0&&console.log(d.dim(` (${ze(n.backfill.pending)} assistant messages pending \u2014 run \`recall stats --backfill\`)`)),n.byModel.length>0){console.log(""),console.log(d.dim(" by model:"));for(let r of n.byModel)console.log(` ${r.modelLabel.padEnd(14)} ${le(r.inputTokens+r.outputTokens+r.cacheCreateTokens+r.cacheReadTokens).padStart(10)} ${d.accent(se(r.cost.cents).padStart(10))}`)}if(n.topSessions.length>0){console.log(""),console.log(d.dim(" top sessions:"));for(let r of n.topSessions){let o=r.alias??r.sessionId.slice(0,8);console.log(` ${o.padEnd(22)} ${(r.project??"").slice(0,20).padEnd(22)} ${le(r.totalTokens).padStart(10)} ${d.accent(se(r.cost.cents).padStart(10))}`)}}console.log("")}I();T();T();import{execFile as $E}from"node:child_process";import{promisify as DE}from"node:util";import{stat as jE}from"node:fs/promises";var Uc=DE($E),Bc=1e4,PE="%H%x09%aI%x09%s";async function FE(e){try{let{stdout:t}=await Uc("git",["rev-parse","--is-inside-work-tree"],{cwd:e,timeout:Bc});return t.trim()==="true"}catch{return!1}}async function UE(e,t,s){let n=["--no-pager","log","--all","--no-color","--since",t,"--until",s,`--pretty=format:${PE}`],{stdout:r}=await Uc("git",n,{cwd:e,timeout:Bc,maxBuffer:8*1024*1024}),o=[],i=new Set;for(let a of r.split(`
1389
- `)){if(!a)continue;let[l,c,...u]=a.split(" ");!l||i.has(l)||(i.add(l),o.push({commit_sha:l,committed_at:c??null,subject:u.join(" ")||null}))}return o}function BE(e){return _().prepare(`SELECT id, cwd, started_at, ended_at
1390
- FROM sessions WHERE id = ?`).get(e)??null}function HE(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:m,cacheCreateTokens:p,cacheReadTokens:f,totalTokens:g.totalTokens,cost:g,daily:S,byModel:c,topSessions:y,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(Bc(),Math.max(0,B.assistant_messages-B.messages_with_usage))},display:{dollars:se(g.cents),tokens:le(g.totalTokens)}}}var ze=e=>e.toLocaleString();function ZE(e){return _().prepare("SELECT id FROM sessions WHERE id = ? OR id LIKE ? LIMIT 1").get(e,`${e}%`)?.id??null}async function Gc(e,t){if(t.backfill){let r=t.limit?Math.max(1,Number(t.limit)):void 0;console.log(d.dim("backfilling per-message usage from raw_json\u2026"));let o=Hc({limit:r});if(console.log(`${d.ok("backfill done")}: scanned ${d.bold(String(o.scanned))}, inserted ${d.bold(String(o.inserted))}, rolled-up ${d.bold(String(o.sessionsTouched))} sessions`),!e&&!t.project)return}if(e){let r=ZE(e);if(!r){console.error(d.err(`no session matches '${e}'`)),process.exit(1);return}let o=Wc(r);if(!o){console.error(d.err("session has no usage data yet \u2014 try --backfill")),process.exit(1);return}if(t.json){console.log(JSON.stringify(o,null,2));return}if(console.log(""),console.log(d.bold("session cost")),console.log(d.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` id ${d.dim(o.sessionId)}`),console.log(` project ${d.accent(o.project??"\u2014")}`),console.log(` started ${d.dim(o.startedAt??"n/a")}`),console.log(` messages ${d.accent(ze(o.messageCount))}`),console.log(` model ${d.accent(o.primaryModelLabel)} ${d.dim(o.primaryModel??"")}`),console.log(""),console.log(` input ${ze(o.inputTokens).padStart(12)}`),console.log(` output ${ze(o.outputTokens).padStart(12)}`),console.log(` cache write ${ze(o.cacheCreateTokens).padStart(12)}`),console.log(` cache read ${ze(o.cacheReadTokens).padStart(12)}`),console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),console.log(` total tokens ${d.bold(ze(o.totalTokens).padStart(12))}`),console.log(` estimated cost ${d.accent(se(o.cost.cents).padStart(12))}`),o.byModel.length>1){console.log(""),console.log(d.dim(" by model:"));for(let i of o.byModel)console.log(` ${i.modelLabel.padEnd(14)} ${le(i.inputTokens+i.outputTokens+i.cacheCreateTokens+i.cacheReadTokens).padStart(10)} ${d.accent(se(i.cost.cents).padStart(10))}`)}console.log("");return}if(t.project){let r=Xc(t.project);if(!r){console.error(d.err(`project '${t.project}' not found`)),process.exit(1);return}if(t.json){console.log(JSON.stringify(r,null,2));return}if(console.log(""),console.log(d.bold(`project \xB7 ${r.project}`)),console.log(d.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` sessions ${d.accent(ze(r.sessionCount))}`),console.log(` total tokens ${d.accent(le(r.totalTokens).padStart(12))}`),console.log(` estimated cost ${d.accent(se(r.cost.cents).padStart(12))}`),r.byModel.length>0){console.log(""),console.log(d.dim(" by model:"));for(let o of r.byModel)console.log(` ${o.modelLabel.padEnd(14)} ${le(o.inputTokens+o.outputTokens+o.cacheCreateTokens+o.cacheReadTokens).padStart(10)} ${d.accent(se(o.cost.cents).padStart(10))}`)}if(r.topSessions.length>0){console.log(""),console.log(d.dim(" top sessions:"));for(let o of r.topSessions){let i=o.alias??o.sessionId.slice(0,8);console.log(` ${i.padEnd(22)} ${le(o.totalTokens).padStart(10)} ${d.accent(se(o.cost.cents).padStart(10))}`)}}console.log("");return}let s=t.days==="7"?"7d":t.days==="30"?"30d":"all",n=Jc(s);if(t.json){console.log(JSON.stringify(n,null,2));return}if(console.log(""),console.log(d.bold(`overview \xB7 ${s}`)),console.log(d.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` sessions ${d.accent(ze(n.totalSessions))} ${d.dim(`(${n.sessionsWithUsage} w/ usage)`)}`),console.log(` total tokens ${d.accent(le(n.totalTokens).padStart(12))}`),console.log(` estimated cost ${d.accent(se(n.cost.cents).padStart(12))}`),n.backfill.pending>0&&console.log(d.dim(` (${ze(n.backfill.pending)} assistant messages pending \u2014 run \`recall stats --backfill\`)`)),n.byModel.length>0){console.log(""),console.log(d.dim(" by model:"));for(let r of n.byModel)console.log(` ${r.modelLabel.padEnd(14)} ${le(r.inputTokens+r.outputTokens+r.cacheCreateTokens+r.cacheReadTokens).padStart(10)} ${d.accent(se(r.cost.cents).padStart(10))}`)}if(n.topSessions.length>0){console.log(""),console.log(d.dim(" top sessions:"));for(let r of n.topSessions){let o=r.alias??r.sessionId.slice(0,8);console.log(` ${o.padEnd(22)} ${(r.project??"").slice(0,20).padEnd(22)} ${le(r.totalTokens).padStart(10)} ${d.accent(se(r.cost.cents).padStart(10))}`)}}console.log("")}v();w();w();import{execFile as QE}from"node:child_process";import{promisify as eb}from"node:util";import{stat as tb}from"node:fs/promises";var Yc=eb(QE),zc=1e4,sb="%H%x09%aI%x09%s";async function nb(e){try{let{stdout:t}=await Yc("git",["rev-parse","--is-inside-work-tree"],{cwd:e,timeout:zc});return t.trim()==="true"}catch{return!1}}async function rb(e,t,s){let n=["--no-pager","log","--all","--no-color","--since",t,"--until",s,`--pretty=format:${sb}`],{stdout:r}=await Yc("git",n,{cwd:e,timeout:zc,maxBuffer:8*1024*1024}),o=[],i=new Set;for(let a of r.split(`
1444
+ `)){if(!a)continue;let[l,c,...u]=a.split(" ");!l||i.has(l)||(i.add(l),o.push({commit_sha:l,committed_at:c??null,subject:u.join(" ")||null}))}return o}function ob(e){return _().prepare(`SELECT id, cwd, started_at, ended_at
1445
+ FROM sessions WHERE id = ?`).get(e)??null}function ib(e,t,s){if(s.length===0)return 0;let n=_(),r=new Date().toISOString(),o=n.prepare(`INSERT OR IGNORE INTO session_commits
1391
1446
  (session_id, commit_sha, committed_at, subject, cwd_snapshot, correlated_at)
1392
- VALUES (?, ?, ?, ?, ?, ?)`),i=0;return n.transaction(l=>{for(let c of l)o.run(e,c.commit_sha,c.committed_at,c.subject,t,r).changes>0&&(i+=1)})(s),i}async function Cr(e){let t=BE(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 jE(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 FE(t.cwd))return{sessionId:e,status:"not-a-repo",commitsFound:0,commitsInserted:0};try{let o=await UE(t.cwd,s,n),i=HE(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 Hc(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(l=>{for(let c of l)o.run(e,c.commit_sha,c.committed_at,c.subject,t,r).changes>0&&(i+=1)})(s),i}async function Ir(e){let t=ob(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 tb(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 rb(t.cwd,s,n),i=ib(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 qc(e={}){let t=_(),s=Math.max(1,Math.min(1e5,e.limit??1e4)),n=t.prepare(`SELECT id FROM sessions
1393
1448
  WHERE cwd IS NOT NULL AND started_at IS NOT NULL AND ended_at IS NOT NULL
1394
1449
  ORDER BY COALESCE(ended_at, started_at) DESC
1395
- LIMIT ?`).all(s),r={total:n.length,ok:0,skipped:0,errors:0,commitsInserted:0,results:[]},o=0;for(let i of n){let a=await Cr(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 Hs(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 Ir(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 Xs(e){let t=_(),s=e.trim();if(!/^[0-9a-fA-F]{4,40}$/.test(s))return[];let n=`${s.toLowerCase()}%`;return t.prepare(`SELECT sc.session_id AS sessionId,
1396
1451
  NULLIF(sa.alias, '') AS alias,
1397
1452
  p.name AS project,
1398
1453
  s.started_at AS startedAt,
@@ -1406,68 +1461,114 @@ Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u271
1406
1461
  LEFT JOIN session_aliases sa ON sa.session_id = sc.session_id
1407
1462
  WHERE lower(sc.commit_sha) = lower(?)
1408
1463
  OR lower(sc.commit_sha) LIKE ?
1409
- ORDER BY COALESCE(sc.committed_at, s.started_at, '') DESC`).all(s,n)}function WE(e){return _().prepare("SELECT id FROM sessions WHERE id = ? OR id LIKE ? LIMIT 1").get(e,`${e}%`)?.id??null}function XE(e){let t=e.sessionId.slice(0,8);switch(e.status){case"ok":console.log(`${d.ok("\u2713")} ${d.dim(t)} ${d.bold(String(e.commitsFound))} commits (${e.commitsInserted} new)`);break;case"no-cwd":console.log(`${d.dim("\xB7")} ${d.dim(t)} no cwd recorded \u2014 skipped`);break;case"not-a-repo":console.log(`${d.dim("\xB7")} ${d.dim(t)} cwd is not a git worktree \u2014 skipped`);break;case"cwd-missing":console.log(`${d.dim("\xB7")} ${d.dim(t)} cwd no longer exists on disk \u2014 skipped`);break;case"no-window":console.log(`${d.dim("\xB7")} ${d.dim(t)} session has no time window yet \u2014 skipped`);break;case"error":console.log(`${d.err("\u2717")} ${d.dim(t)} ${e.error??"unknown error"}`);break}}async function Wc(e,t){if(e){let r=WE(e);if(!r){console.error(d.err(`no session matches '${e}'`)),process.exit(1);return}let o=await Cr(r);if(t.json){console.log(JSON.stringify(o,null,2));return}XE(o);return}let s=t.limit?Math.max(1,Number(t.limit)):void 0;console.log(d.dim(`correlating sessions to git commits (limit ${s??"default"})\u2026`));let n=await Hc({limit:s,onProgress:(r,o)=>{(r%25===0||r===o)&&process.stderr.write(`\r${d.dim(` ${r}/${o}`)}`)}});if(process.stderr.write(`
1410
- `),t.json){console.log(JSON.stringify(n,null,2));return}console.log(""),console.log(`${d.ok("correlated")}: ${d.bold(String(n.ok))} sessions \xB7 ${d.bold(String(n.commitsInserted))} new commits`),console.log(d.dim(` skipped ${n.skipped} (no cwd / non-repo / cwd missing), errors ${n.errors}`)),console.log("")}I();T();Ft();import{existsSync as Ir,readFileSync as vr}from"node:fs";j();import{existsSync as JE,readFileSync as GE,writeFileSync as zE}from"node:fs";import{join as YE}from"node:path";import{z as de}from"zod";var Lr=YE(x,"terminals.json"),Xc=1440*60*1e3,qE=3e4,KE=6e4,VE=de.object({shell_pid:de.number(),tab_name:de.string(),cwd:de.string().nullable().optional(),opened_at:de.string(),last_seen_at:de.string()}),ZE=de.object({schema:de.string().optional(),saved_at:de.string().optional(),terminals:de.array(VE).max(500).default([]),sessions_by_pid:de.record(de.string(),de.array(de.string()).max(50)).optional().default({})}),Gc=/^[⠀-⣿✳\s]+/,zc=/^\d+(\.\d+){1,3}$/;function Jc(e){let t=e.trim();return!!(!t||Gc.test(t)||zc.test(t))}function QE(e){let t=e.trim();if(!t||zc.test(t))return null;let s=t.replace(Gc,"").trim();return s.length>0?s:null}function Or(e,t){if(!Jc(e))return e;let s=QE(e);return s||(t&&!Jc(t)?t:e)}function eb(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 Ar=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,!!JE(Lr)))try{let t=GE(Lr,"utf8"),s=JSON.parse(t),n=ZE.safeParse(s);if(!n.success){console.warn("[terminal-registry] terminals.json failed validation, starting with empty registry:",n.error.issues);return}let r=n.data;for(let o of r.terminals)this.entries.set(o.shell_pid,{shell_pid:o.shell_pid,tab_name:o.tab_name,cwd:o.cwd??null,opened_at:o.opened_at,last_seen_at:o.last_seen_at});for(let[o,i]of Object.entries(r.sessions_by_pid??{})){let a=Number(o);if(!Number.isFinite(a))continue;let l=new Set;for(let c of i)c.length>0&&l.add(c);l.size>0&&this.sessionsByPid.set(a,l)}this.gc()}catch{}}save(){try{P();let t={schema:"claude-recall.terminals.v1",saved_at:new Date().toISOString(),terminals:Array.from(this.entries.values()),sessions_by_pid:Object.fromEntries(Array.from(this.sessionsByPid.entries()).map(([s,n])=>[String(s),Array.from(n)]))};zE(Lr,JSON.stringify(t,null,2))}catch{}}upsert(t){this.ensureLoaded();let s=new Date().toISOString(),n=this.entries.get(t.shell_pid),r=Or(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=Or(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>KE?(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=Or(o.tab_name,i?.tab_name),l=i?.opened_at??o.opened_at;this.entries.set(o.shell_pid,{...o,tab_name:a,opened_at:l,last_seen_at:s}),i?(i.tab_name!==a||i.cwd!==o.cwd)&&r++:n++}return this.gc(),this.save(),{added:n,updated:r,removed:0}}get(t){return this.ensureLoaded(),this.entries.get(t)??null}all(){return this.ensureLoaded(),this.gc(),Array.from(this.entries.values())}size(){return this.ensureLoaded(),this.entries.size}linkSession(t,s){this.ensureLoaded();let n=this.sessionsByPid.get(s);n||(n=new Set,this.sessionsByPid.set(s,n)),n.has(t)||(n.add(t),this.save())}sessionsFor(t){return this.ensureLoaded(),Array.from(this.sessionsByPid.get(t)??[])}isSessionAutoLinked(t){this.ensureLoaded();for(let s of this.sessionsByPid.values())if(s.has(t))return!0;return!1}unlinkSession(t){this.ensureLoaded();let s=!1;for(let[n,r]of this.sessionsByPid)r.delete(t)&&(s=!0,r.size===0&&this.sessionsByPid.delete(n));return s&&this.save(),s}pushPending(t){this.ensureLoaded(),this.gcPending(),this.pendingClaudeStarts.push({...t})}takePendingMatched(t){this.ensureLoaded(),this.gcPending();let s=eb({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()-qE;this.pendingClaudeStarts.length!==0&&(this.pendingClaudeStarts=this.pendingClaudeStarts.filter(s=>{let n=Date.parse(s.started_at);return Number.isFinite(n)&&n>=t}))}outputTails=new Map;setOutputTail(t,s,n){this.ensureLoaded(),this.outputTails.set(t,{text:s,captured_at:n})}getOutputTail(t){return this.ensureLoaded(),this.outputTails.get(t)??null}allOutputTails(){return this.ensureLoaded(),new Map(this.outputTails)}removeOutputTail(t){return this.outputTails.delete(t)}setOrigin(t,s){this.ensureLoaded(),this.origins.set(t,s),this.gcOrigins()}getOrigin(t){return this.ensureLoaded(),this.origins.get(t)??null}removeOrigin(t){return this.ensureLoaded(),this.origins.delete(t)}allOrigins(){return this.ensureLoaded(),this.gcOrigins(),new Map(this.origins)}originSize(){return this.ensureLoaded(),this.origins.size}gc(){let t=Date.now()-Xc;for(let[s,n]of this.entries){let r=Date.parse(n.last_seen_at);!Number.isNaN(r)&&r<t&&this.entries.delete(s)}}gcOrigins(){let t=Date.now()-Xc;for(let[s,n]of this.origins)n.detectedAt<t&&this.origins.delete(s)}reapStaleLinks(t=10080*60*1e3){this.ensureLoaded();let n=Date.now()-t,r=0,o=0;for(let[i,a]of this.sessionsByPid){let l=this.entries.get(i);if(l){let c=Date.parse(l.last_seen_at);if(Number.isFinite(c)&&c>=n)continue}o+=a.size,this.sessionsByPid.delete(i),l&&(this.entries.delete(i),r++)}return(r||o)&&this.save(),{pruned_pids:r,pruned_sessions:o}}gcDeadPids(){this.ensureLoaded();let t=0,s=0;for(let n of[...this.entries.keys()]){let r=!0;try{process.kill(n,0)}catch(i){i.code==="ESRCH"&&(r=!1)}if(r)continue;this.entries.delete(n),t++;let o=this.sessionsByPid.get(n);o&&(s+=o.size,this.sessionsByPid.delete(n)),this.outputTails.delete(n),this.pidOwnership.delete(n)}return(t||s)&&this.save(),{pruned_pids:t,pruned_sessions:s}}},Yc=new Ar;Hn();function qc(e){let t=fi(),s={...e};return t&&(s["x-recall-token"]=t),s}async function _t(e,t){let s=t?.headers??{};return fetch(e,{...t,headers:qc(s)})}async function tt(e,t,s,n){let r=s!==void 0?{"content-type":"application/json",...n}:{...n};return fetch(t,{method:e,headers:qc(r),body:s!==void 0?JSON.stringify(s):void 0})}j();function sb(){let e=`${x}/daemon.port`;if(!Ir(e))return null;try{let t=vr(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function nb(e,t){try{return(await tt("POST",`http://127.0.0.1:${e}/api/sessions/${encodeURIComponent(t)}/relink`,{clear:!0})).ok}catch{return!1}}function rb(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 ab(e){return _().prepare("SELECT id FROM sessions WHERE id = ? OR id LIKE ? LIMIT 1").get(e,`${e}%`)?.id??null}function cb(e){let t=e.sessionId.slice(0,8);switch(e.status){case"ok":console.log(`${d.ok("\u2713")} ${d.dim(t)} ${d.bold(String(e.commitsFound))} commits (${e.commitsInserted} new)`);break;case"no-cwd":console.log(`${d.dim("\xB7")} ${d.dim(t)} no cwd recorded \u2014 skipped`);break;case"not-a-repo":console.log(`${d.dim("\xB7")} ${d.dim(t)} cwd is not a git worktree \u2014 skipped`);break;case"cwd-missing":console.log(`${d.dim("\xB7")} ${d.dim(t)} cwd no longer exists on disk \u2014 skipped`);break;case"no-window":console.log(`${d.dim("\xB7")} ${d.dim(t)} session has no time window yet \u2014 skipped`);break;case"error":console.log(`${d.err("\u2717")} ${d.dim(t)} ${e.error??"unknown error"}`);break}}async function Kc(e,t){if(e){let r=ab(e);if(!r){console.error(d.err(`no session matches '${e}'`)),process.exit(1);return}let o=await Ir(r);if(t.json){console.log(JSON.stringify(o,null,2));return}cb(o);return}let s=t.limit?Math.max(1,Number(t.limit)):void 0;console.log(d.dim(`correlating sessions to git commits (limit ${s??"default"})\u2026`));let n=await qc({limit:s,onProgress:(r,o)=>{(r%25===0||r===o)&&process.stderr.write(`\r${d.dim(` ${r}/${o}`)}`)}});if(process.stderr.write(`
1465
+ `),t.json){console.log(JSON.stringify(n,null,2));return}console.log(""),console.log(`${d.ok("correlated")}: ${d.bold(String(n.ok))} sessions \xB7 ${d.bold(String(n.commitsInserted))} new commits`),console.log(d.dim(` skipped ${n.skipped} (no cwd / non-repo / cwd missing), errors ${n.errors}`)),console.log("")}v();w();Ut();import{existsSync as jr,readFileSync as Pr}from"node:fs";P();import{existsSync as lb,readFileSync as db,writeFileSync as ub}from"node:fs";import{join as mb}from"node:path";import{z as de}from"zod";var Mr=mb(x,"terminals.json"),Vc=1440*60*1e3,pb=3e4,gb=6e4,fb=de.object({shell_pid:de.number(),tab_name:de.string(),cwd:de.string().nullable().optional(),opened_at:de.string(),last_seen_at:de.string()}),_b=de.object({schema:de.string().optional(),saved_at:de.string().optional(),terminals:de.array(fb).max(500).default([]),sessions_by_pid:de.record(de.string(),de.array(de.string()).max(50)).optional().default({})}),Qc=/^[⠀-⣿✳\s]+/,el=/^\d+(\.\d+){1,3}$/;function Zc(e){let t=e.trim();return!!(!t||Qc.test(t)||el.test(t))}function hb(e){let t=e.trim();if(!t||el.test(t))return null;let s=t.replace(Qc,"").trim();return s.length>0?s:null}function Dr(e,t){if(!Zc(e))return e;let s=hb(e);return s||(t&&!Zc(t)?t:e)}function Eb(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 $r=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,!!lb(Mr)))try{let t=db(Mr,"utf8"),s=JSON.parse(t),n=_b.safeParse(s);if(!n.success){console.warn("[terminal-registry] terminals.json failed validation, starting with empty registry:",n.error.issues);return}let r=n.data;for(let o of r.terminals)this.entries.set(o.shell_pid,{shell_pid:o.shell_pid,tab_name:o.tab_name,cwd:o.cwd??null,opened_at:o.opened_at,last_seen_at:o.last_seen_at});for(let[o,i]of Object.entries(r.sessions_by_pid??{})){let a=Number(o);if(!Number.isFinite(a))continue;let l=new Set;for(let c of i)c.length>0&&l.add(c);l.size>0&&this.sessionsByPid.set(a,l)}this.gc()}catch{}}save(){try{j();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)]))};ub(Mr,JSON.stringify(t,null,2))}catch{}}upsert(t){this.ensureLoaded();let s=new Date().toISOString(),n=this.entries.get(t.shell_pid),r=Dr(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=Dr(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>gb?(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=Dr(o.tab_name,i?.tab_name),l=i?.opened_at??o.opened_at;this.entries.set(o.shell_pid,{...o,tab_name:a,opened_at:l,last_seen_at:s}),i?(i.tab_name!==a||i.cwd!==o.cwd)&&r++:n++}return this.gc(),this.save(),{added:n,updated:r,removed:0}}get(t){return this.ensureLoaded(),this.entries.get(t)??null}all(){return this.ensureLoaded(),this.gc(),Array.from(this.entries.values())}size(){return this.ensureLoaded(),this.entries.size}linkSession(t,s){this.ensureLoaded();let n=this.sessionsByPid.get(s);n||(n=new Set,this.sessionsByPid.set(s,n)),n.has(t)||(n.add(t),this.save())}sessionsFor(t){return this.ensureLoaded(),Array.from(this.sessionsByPid.get(t)??[])}isSessionAutoLinked(t){this.ensureLoaded();for(let s of this.sessionsByPid.values())if(s.has(t))return!0;return!1}unlinkSession(t){this.ensureLoaded();let s=!1;for(let[n,r]of this.sessionsByPid)r.delete(t)&&(s=!0,r.size===0&&this.sessionsByPid.delete(n));return s&&this.save(),s}pushPending(t){this.ensureLoaded(),this.gcPending(),this.pendingClaudeStarts.push({...t})}takePendingMatched(t){this.ensureLoaded(),this.gcPending();let s=Eb({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()-pb;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()-Vc;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()-Vc;for(let[s,n]of this.origins)n.detectedAt<t&&this.origins.delete(s)}reapStaleLinks(t=10080*60*1e3){this.ensureLoaded();let n=Date.now()-t,r=0,o=0;for(let[i,a]of this.sessionsByPid){let l=this.entries.get(i);if(l){let c=Date.parse(l.last_seen_at);if(Number.isFinite(c)&&c>=n)continue}o+=a.size,this.sessionsByPid.delete(i),l&&(this.entries.delete(i),r++)}return(r||o)&&this.save(),{pruned_pids:r,pruned_sessions:o}}gcDeadPids(){this.ensureLoaded();let t=0,s=0;for(let n of[...this.entries.keys()]){let r=!0;try{process.kill(n,0)}catch(i){i.code==="ESRCH"&&(r=!1)}if(r)continue;this.entries.delete(n),t++;let o=this.sessionsByPid.get(n);o&&(s+=o.size,this.sessionsByPid.delete(n)),this.outputTails.delete(n),this.pidOwnership.delete(n)}return(t||s)&&this.save(),{pruned_pids:t,pruned_sessions:s}}},tl=new $r;Yn();function sl(e){let t=Ti(),s={...e};return t&&(s["x-recall-token"]=t),s}async function _t(e,t){let s=t?.headers??{};return fetch(e,{...t,headers:sl(s)})}async function tt(e,t,s,n){let r=s!==void 0?{"content-type":"application/json",...n}:{...n};return fetch(t,{method:e,headers:sl(r),body:s!==void 0?JSON.stringify(s):void 0})}P();function Sb(){let e=`${x}/daemon.port`;if(!jr(e))return null;try{let t=Pr(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function Tb(e,t){try{return(await tt("POST",`http://127.0.0.1:${e}/api/sessions/${encodeURIComponent(t)}/relink`,{clear:!0})).ok}catch{return!1}}function yb(e,t){let s=_(),n=t?" AND p.name = ?":"",r=t?[t]:[],o=s.prepare(`SELECT s.id, p.name AS project_name, s.cwd, s.started_at, sa.alias
1411
1466
  FROM sessions s
1412
1467
  JOIN projects p ON p.id = s.project_id
1413
1468
  JOIN session_aliases sa ON sa.session_id = s.id
1414
1469
  WHERE s.cwd IS NOT NULL
1415
1470
  AND s.started_at IS NOT NULL
1416
1471
  AND sa.alias IS NOT NULL
1417
- AND sa.alias <> ''${n}`).all(...r),i=new Map;for(let c of o){let u=c.cwd.replace(/\/+$/,""),p=i.get(u);p||(p=[],i.set(u,p)),p.push(c)}let a=e*1e3,l=new Map;for(let[c,u]of i){let p=new Map;for(let m of u){let f=p.get(m.alias);f||(f=[],p.set(m.alias,f)),f.push(m)}for(let m of p.values())if(!(m.length<2))for(let f of m){let g=new Set;for(let h of m)h.id!==f.id&&g.add(h.id);l.set(f.id,{row:f,cwdKey:c,reason:"duplicate-alias",siblingIds:g})}}for(let[c,u]of i){if(u.length<2)continue;u.sort((f,g)=>Date.parse(f.started_at)-Date.parse(g.started_at));let p=[],m=()=>{if(p.length>=2)for(let f of p){if(l.has(f.id))continue;let g=new Set;for(let h of p)h.id!==f.id&&g.add(h.id);l.set(f.id,{row:f,cwdKey:c,reason:"cwd-collision",siblingIds:g})}p=[]};for(let f of u){if(p.length===0){p.push(f);continue}let g=p[p.length-1];Date.parse(f.started_at)-Date.parse(g.started_at)<=a||m(),p.push(f)}m()}return Array.from(l.values()).map(c=>({session_id:c.row.id,project_name:c.row.project_name,cwd:c.cwdKey,started_at:c.row.started_at,alias:c.row.alias,sibling_ids:Array.from(c.siblingIds),reason:c.reason}))}function ob(e){let t=[];try{let s=`${x}/terminals.json`;if(!Ir(s))return t;let n=JSON.parse(vr(s,"utf8")),r=n.sessions_by_pid??{},o=new Map;for(let a of n.terminals??[])o.set(a.shell_pid,a);let i=_();for(let[a,l]of Object.entries(r)){let c=Number(a);if(!Number.isFinite(c))continue;let u=o.get(c)??null;for(let p of l){let m=i.prepare(`SELECT s.id, p.name AS project_name, s.cwd, s.started_at,
1472
+ AND sa.alias <> ''${n}`).all(...r),i=new Map;for(let c of o){let u=c.cwd.replace(/\/+$/,""),m=i.get(u);m||(m=[],i.set(u,m)),m.push(c)}let a=e*1e3,l=new Map;for(let[c,u]of i){let m=new Map;for(let p of u){let f=m.get(p.alias);f||(f=[],m.set(p.alias,f)),f.push(p)}for(let p of m.values())if(!(p.length<2))for(let f of p){let g=new Set;for(let h of p)h.id!==f.id&&g.add(h.id);l.set(f.id,{row:f,cwdKey:c,reason:"duplicate-alias",siblingIds:g})}}for(let[c,u]of i){if(u.length<2)continue;u.sort((f,g)=>Date.parse(f.started_at)-Date.parse(g.started_at));let m=[],p=()=>{if(m.length>=2)for(let f of m){if(l.has(f.id))continue;let g=new Set;for(let h of m)h.id!==f.id&&g.add(h.id);l.set(f.id,{row:f,cwdKey:c,reason:"cwd-collision",siblingIds:g})}m=[]};for(let f of u){if(m.length===0){m.push(f);continue}let g=m[m.length-1];Date.parse(f.started_at)-Date.parse(g.started_at)<=a||p(),m.push(f)}p()}return Array.from(l.values()).map(c=>({session_id:c.row.id,project_name:c.row.project_name,cwd:c.cwdKey,started_at:c.row.started_at,alias:c.row.alias,sibling_ids:Array.from(c.siblingIds),reason:c.reason}))}function wb(e){let t=[];try{let s=`${x}/terminals.json`;if(!jr(s))return t;let n=JSON.parse(Pr(s,"utf8")),r=n.sessions_by_pid??{},o=new Map;for(let a of n.terminals??[])o.set(a.shell_pid,a);let i=_();for(let[a,l]of Object.entries(r)){let c=Number(a);if(!Number.isFinite(c))continue;let u=o.get(c)??null;for(let m of l){let p=i.prepare(`SELECT s.id, p.name AS project_name, s.cwd, s.started_at,
1418
1473
  NULLIF(sa.alias, '') AS alias
1419
1474
  FROM sessions s
1420
1475
  JOIN projects p ON p.id = s.project_id
1421
1476
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1422
- WHERE s.id = ?`).get(p);m&&(m.alias||e&&m.project_name!==e||t.push({session_id:m.id,project_name:m.project_name,cwd:(m.cwd??"").replace(/\/+$/,""),started_at:m.started_at??"",alias:"",sibling_ids:[],reason:"orphan-link",stale_terminal:u}))}}}catch{}return t}function ib(e){let t=[],s=`${x}/terminals.json`;if(!Ir(s))return t;let n;try{n=JSON.parse(vr(s,"utf8"))}catch{return t}let r=new Map;for(let c of n.terminals??[]){if(!c.tab_name)continue;let u=r.get(c.tab_name);u||(u=[],r.set(c.tab_name,u)),u.push(c)}if(r.size===0)return t;let o=_(),i=e?" AND p.name = ?":"",a=e?[e]:[],l=o.prepare(`SELECT s.id, p.name AS project_name, s.cwd, s.started_at, sa.alias
1477
+ WHERE s.id = ?`).get(m);p&&(p.alias||e&&p.project_name!==e||t.push({session_id:p.id,project_name:p.project_name,cwd:(p.cwd??"").replace(/\/+$/,""),started_at:p.started_at??"",alias:"",sibling_ids:[],reason:"orphan-link",stale_terminal:u}))}}}catch{}return t}function Rb(e){let t=[],s=`${x}/terminals.json`;if(!jr(s))return t;let n;try{n=JSON.parse(Pr(s,"utf8"))}catch{return t}let r=new Map;for(let c of n.terminals??[]){if(!c.tab_name)continue;let u=r.get(c.tab_name);u||(u=[],r.set(c.tab_name,u)),u.push(c)}if(r.size===0)return t;let o=_(),i=e?" AND p.name = ?":"",a=e?[e]:[],l=o.prepare(`SELECT s.id, p.name AS project_name, s.cwd, s.started_at, sa.alias
1423
1478
  FROM sessions s
1424
1479
  JOIN projects p ON p.id = s.project_id
1425
1480
  JOIN session_aliases sa ON sa.session_id = s.id
1426
1481
  WHERE s.started_at IS NOT NULL
1427
1482
  AND sa.alias IS NOT NULL
1428
- AND sa.alias <> ''${i}`).all(...a);for(let c of l){let u=r.get(c.alias);if(!u||u.length===0)continue;let p=Date.parse(c.started_at);if(!Number.isFinite(p))continue;let m=!1,f=null,g=1/0;for(let h of u){let E=Date.parse(h.opened_at);if(Number.isFinite(E)){if(E-p<=6e4){m=!0;break}E<g&&(g=E,f=h)}}m||!f||t.push({session_id:c.id,project_name:c.project_name,cwd:c.cwd.replace(/\/+$/,""),started_at:c.started_at,alias:c.alias,sibling_ids:[],reason:"temporal-anomaly",postdating_terminal:f})}return t}function ab(e){if(e.length===0){console.log(d.ok("No suspicious correlations found."));return}console.log(d.warn(`Found ${e.length} session${e.length===1?"":"s"} with likely-bad correlator aliases:`)),console.log();let t=new Map;for(let s of e){let n=t.get(s.cwd);n||(n=[],t.set(s.cwd,n)),n.push(s)}for(let[s,n]of t){console.log(d.dim(` cwd: ${s}`)),n.sort((r,o)=>Date.parse(r.started_at)-Date.parse(o.started_at));for(let r of n){let o=r.reason==="duplicate-alias"?d.err("[dup-alias]"):r.reason==="orphan-link"?d.warn("[orphan-link]"):r.reason==="temporal-anomaly"?d.err("[temporal]"):d.warn("[cwd-collision]"),i=r.reason==="orphan-link"&&r.stale_terminal?`${d.dim("still pointing at pid")} ${r.stale_terminal.shell_pid} ${d.dim("=")} ${d.bold(`"${r.stale_terminal.tab_name}"`)}`:r.reason==="temporal-anomaly"&&r.postdating_terminal?`${d.bold(`"${r.alias}"`)} ${d.dim("\u2190 terminal opened")} ${r.postdating_terminal.opened_at.replace("T"," ").slice(0,19)} ${d.dim("(after session)")}`:d.bold(`"${r.alias}"`);console.log(` ${o} ${d.dim(r.session_id.slice(0,8))} ${d.dim(r.started_at.replace("T"," ").slice(0,19))} \u2192 ${i}`)}console.log()}}async function Kc(e){let t=e.window?Math.max(5,Math.min(600,Number(e.window)||60)):60,s=e.project?.trim()||void 0,n=rb(t,s),r=ob(s),o=ib(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(ab(a),!e.fix){a.length>0&&console.log(d.dim("Re-run with --fix to clear these aliases. Heuristic titles will display instead, and you can manually relink via the UI's \u{1F517} picker."));return}let l=sb(),c=0,u=0;for(let p of a){if(l){await nb(l,p.session_id)?c++:(u++,console.error(d.err(`failed to clear ${p.session_id.slice(0,8)} via daemon`)));continue}try{Vi(p.session_id),Yc.unlinkSession(p.session_id),c++}catch(m){u++,console.error(d.err(`failed to clear ${p.session_id.slice(0,8)}: ${m.message}`))}}console.log(d.ok(`Cleared ${c} suspect alias${c===1?"":"es"}.`)),u>0&&console.log(d.warn(`${u} clears failed; see errors above.`)),l||console.log(d.dim("Daemon was not running, so changes were applied directly to state files.")),console.log(d.dim("Open an affected session in the UI and use the \u{1F517} picker to pin the correct terminal."))}I();T();j();import{existsSync as Qc,readFileSync as cb,statSync as el,statfsSync as lb}from"node:fs";import{join as tl}from"node:path";import*as sl from"node:http";var db=["VS Code","VS Code Insiders","Cursor","Windsurf","Warp","iTerm","Terminal","WezTerm","Windows Terminal","Kitty","Alacritty"],ub=new RegExp(`^(${db.map(e=>e.replace(/ /g,"\\s")).join("|")})\\s\xB7\\s`);function pb(e){let t=[];for(let s of e)if(s.alias){if(ub.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 nl=5*6e4,Mr=24,rl=.5;function mb(){let e=tl(x,"daemon.port");if(!Qc(e))return null;try{let t=cb(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 gb(e,t,s=1500){return new Promise(n=>{let r=sl.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 fb(){let e=tl(x,"terminals.json");if(!Qc(e))return{exists:!1,mtimeMs:null,ageSeconds:null};try{let t=el(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 _b(){let e=new Date(Date.now()-Mr*36e5).toISOString();try{let t=_().prepare(`SELECT
1483
+ AND sa.alias <> ''${i}`).all(...a);for(let c of l){let u=r.get(c.alias);if(!u||u.length===0)continue;let m=Date.parse(c.started_at);if(!Number.isFinite(m))continue;let p=!1,f=null,g=1/0;for(let h of u){let E=Date.parse(h.opened_at);if(Number.isFinite(E)){if(E-m<=6e4){p=!0;break}E<g&&(g=E,f=h)}}p||!f||t.push({session_id:c.id,project_name:c.project_name,cwd:c.cwd.replace(/\/+$/,""),started_at:c.started_at,alias:c.alias,sibling_ids:[],reason:"temporal-anomaly",postdating_terminal:f})}return t}function xb(e){if(e.length===0){console.log(d.ok("No suspicious correlations found."));return}console.log(d.warn(`Found ${e.length} session${e.length===1?"":"s"} with likely-bad correlator aliases:`)),console.log();let t=new Map;for(let s of e){let n=t.get(s.cwd);n||(n=[],t.set(s.cwd,n)),n.push(s)}for(let[s,n]of t){console.log(d.dim(` cwd: ${s}`)),n.sort((r,o)=>Date.parse(r.started_at)-Date.parse(o.started_at));for(let r of n){let o=r.reason==="duplicate-alias"?d.err("[dup-alias]"):r.reason==="orphan-link"?d.warn("[orphan-link]"):r.reason==="temporal-anomaly"?d.err("[temporal]"):d.warn("[cwd-collision]"),i=r.reason==="orphan-link"&&r.stale_terminal?`${d.dim("still pointing at pid")} ${r.stale_terminal.shell_pid} ${d.dim("=")} ${d.bold(`"${r.stale_terminal.tab_name}"`)}`:r.reason==="temporal-anomaly"&&r.postdating_terminal?`${d.bold(`"${r.alias}"`)} ${d.dim("\u2190 terminal opened")} ${r.postdating_terminal.opened_at.replace("T"," ").slice(0,19)} ${d.dim("(after session)")}`:d.bold(`"${r.alias}"`);console.log(` ${o} ${d.dim(r.session_id.slice(0,8))} ${d.dim(r.started_at.replace("T"," ").slice(0,19))} \u2192 ${i}`)}console.log()}}async function nl(e){let t=e.window?Math.max(5,Math.min(600,Number(e.window)||60)):60,s=e.project?.trim()||void 0,n=yb(t,s),r=wb(s),o=Rb(s),i=new Set,a=[];for(let m of[...n,...r,...o])i.has(m.session_id)||(i.add(m.session_id),a.push(m));if(e.json){console.log(JSON.stringify({window_sec:t,suspects:a},null,2));return}if(xb(a),!e.fix){a.length>0&&console.log(d.dim("Re-run with --fix to clear these aliases. Heuristic titles will display instead, and you can manually relink via the UI's \u{1F517} picker."));return}let l=Sb(),c=0,u=0;for(let m of a){if(l){await Tb(l,m.session_id)?c++:(u++,console.error(d.err(`failed to clear ${m.session_id.slice(0,8)} via daemon`)));continue}try{ra(m.session_id),tl.unlinkSession(m.session_id),c++}catch(p){u++,console.error(d.err(`failed to clear ${m.session_id.slice(0,8)}: ${p.message}`))}}console.log(d.ok(`Cleared ${c} suspect alias${c===1?"":"es"}.`)),u>0&&console.log(d.warn(`${u} clears failed; see errors above.`)),l||console.log(d.dim("Daemon was not running, so changes were applied directly to state files.")),console.log(d.dim("Open an affected session in the UI and use the \u{1F517} picker to pin the correct terminal."))}v();w();P();import{existsSync as il,readFileSync as kb,statSync as al,statfsSync as Nb}from"node:fs";import{join as cl}from"node:path";import*as ll from"node:http";var Lb=["VS Code","VS Code Insiders","Cursor","Windsurf","Warp","iTerm","Terminal","WezTerm","Windows Terminal","Kitty","Alacritty"],Cb=new RegExp(`^(${Lb.map(e=>e.replace(/ /g,"\\s")).join("|")})\\s\xB7\\s`);function Ab(e){let t=[];for(let s of e)if(s.alias){if(Cb.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 dl=5*6e4,Fr=24,ul=.5;function Ob(){let e=cl(x,"daemon.port");if(!il(e))return null;try{let t=kb(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 vb(e,t,s=1500){return new Promise(n=>{let r=ll.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 Ib(){let e=cl(x,"terminals.json");if(!il(e))return{exists:!1,mtimeMs:null,ageSeconds:null};try{let t=al(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 Mb(){let e=new Date(Date.now()-Fr*36e5).toISOString();try{let t=_().prepare(`SELECT
1429
1484
  COUNT(*) AS total,
1430
1485
  SUM(CASE WHEN sa.alias IS NULL OR sa.alias = '' THEN 1 ELSE 0 END) AS without_alias,
1431
1486
  SUM(CASE WHEN (sa.alias IS NULL OR sa.alias = '')
1432
1487
  AND s.auto_title_source = 'heuristic' THEN 1 ELSE 0 END) AS heuristic_only
1433
1488
  FROM sessions s
1434
1489
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1435
- WHERE s.started_at >= ?`).get(e),s=t.total??0,n=t.without_alias??0,r=t.heuristic_only??0,o=s>0?r/s:0;return{total:s,withoutAlias:n,heuristicOnly:r,fractionHeuristic:o}}catch{return{total:0,withoutAlias:0,heuristicOnly:0,fractionHeuristic:0}}}async function hb(){let e=mb(),t=fb(),s=_b(),n=!1,r=null,o=null,i=null,a=null;if(e){let u=await gb(e,"/api/health");u&&(n=!0,r=typeof u.uptimeSeconds=="number"?u.uptimeSeconds:null,o=typeof u.version=="string"?u.version:null,i=typeof u.pipeline?.silentTerminalRejections=="number"?u.pipeline.silentTerminalRejections:null,a=u.pipeline?.lastTerminalSyncAt??null)}let l=[];if(n||l.push("Daemon not reachable on 127.0.0.1 \u2014 start it with `recall start` before further diagnosis."),i!==null&&i>0&&l.push(`Daemon rejected ${i.toLocaleString()} /api/terminal/* request(s) without a valid X-Recall-Token. The editor extension is outdated relative to this daemon \u2014 tab names are not flowing through. Reinstall: \`code --install-extension extensions/vscode/clauderecall-vscode-*.vsix\`, then reload the extension host (Cmd/Ctrl+Shift+P \u2192 "Developer: Restart Extension Host").`),n&&r!==null&&r>30)if(!a)l.push(`Daemon has been running ${Math.round(r/60)} min but has not yet seen a single successful /api/terminal/sync. Either no editor extension is installed/active, or every attempt is being rejected (see counter above).`);else{let u=Date.now()-Date.parse(a);Number.isFinite(u)&&u>nl&&l.push(`Last successful /api/terminal/sync was ${Math.round(u/6e4)} min ago \u2014 extension may have crashed, been disabled, or is failing auth. Run \`recall doctor\` again after restarting the extension host.`)}return!n&&t.exists&&t.ageSeconds!==null&&t.ageSeconds>24*3600&&l.push(`~/.recall/terminals.json is ${Math.round(t.ageSeconds/3600)}h old \u2014 pipeline has not produced fresh data recently. Likely root cause is the same as the rejection counter would show; start the daemon and re-run.`),s.total>=3&&s.fractionHeuristic>=rl&&l.push(`${s.heuristicOnly}/${s.total} sessions in the last ${Mr}h (${Math.round(s.fractionHeuristic*100)}%) fell back to the heuristic first-message title. A healthy pipeline rate is < 20%. Either the extension is not syncing tab names, or the correlator cannot disambiguate. Reinstall the extension and verify the rejection counter drops to 0.`),{state:n?l.length>0?"degraded":"ok":"down",flags:l,daemon:{running:n,port:e,uptimeSeconds:r,version:o},runtime:{silentTerminalRejections:i,lastTerminalSyncAt:a},terminalsJson:t,recentSessions:s}}function ht(e){return e<1024?`${e} B`:e<1024**2?`${(e/1024).toFixed(1)} KB`:e<1024**3?`${(e/1024**2).toFixed(1)} MB`:`${(e/1024**3).toFixed(2)} GB`}function Vc(e){try{return el(e).size}catch{return 0}}function Zc(e){try{return _().prepare(`SELECT COUNT(*) AS n FROM ${e}_data WHERE block = 1`).get().n}catch{return 0}}function Eb(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 E=t.pragma("quick_check").map(b=>b.quick_check);o=E.length===1&&E[0]==="ok"?"ok":E.join("; ")}catch(h){o=`check failed: ${h.message}`}let i=Vc(te),a=Vc(`${te}-wal`),l=0,c=0;try{let h=lb(x);l=Number(h.bavail)*Number(h.bsize),c=Number(h.blocks)*Number(h.bsize)}catch{}e?.("Counting rows");let u=t.prepare(`SELECT
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 Db(){let e=Ob(),t=Ib(),s=Mb(),n=!1,r=null,o=null,i=null,a=null,l=null;if(e){let m=await vb(e,"/api/health");if(m){n=!0,r=typeof m.uptimeSeconds=="number"?m.uptimeSeconds:null,o=typeof m.version=="string"?m.version:null,i=typeof m.pipeline?.silentTerminalRejections=="number"?m.pipeline.silentTerminalRejections:null,a=m.pipeline?.lastTerminalSyncAt??null;let p=m.pipeline?.autoExtract;p&&(l={circuitBroken:p.circuitBroken===!0,reason:p.reason??null,brokenAt:typeof p.brokenAt=="number"?p.brokenAt:null,consecutiveZeroTokenRuns:typeof p.consecutiveZeroTokenRuns=="number"?p.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 m=Date.now()-Date.parse(a);Number.isFinite(m)&&m>dl&&c.push(`Last successful /api/terminal/sync was ${Math.round(m/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.`),l?.circuitBroken&&c.push(`Auto-extract circuit breaker tripped \u2014 ${l.reason??"reason unknown"}. Run \`recall semantic auto-extract off\` then \`... on\` to reset, or restart the daemon.`),s.total>=3&&s.fractionHeuristic>=ul&&c.push(`${s.heuristicOnly}/${s.total} sessions in the last ${Fr}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:l},terminalsJson:t,recentSessions:s}}function ht(e){return e<1024?`${e} B`:e<1024**2?`${(e/1024).toFixed(1)} KB`:e<1024**3?`${(e/1024**2).toFixed(1)} MB`:`${(e/1024**3).toFixed(2)} GB`}function rl(e){try{return al(e).size}catch{return 0}}function ol(e){try{return _().prepare(`SELECT COUNT(*) AS n FROM ${e}_data WHERE block = 1`).get().n}catch{return 0}}function $b(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(N=>N.quick_check);o=S.length===1&&S[0]==="ok"?"ok":S.join("; ")}catch(b){o=`check failed: ${b.message}`}let i=rl(te),a=rl(`${te}-wal`),l=0,c=0;try{let b=Nb(x);l=Number(b.bavail)*Number(b.bsize),c=Number(b.blocks)*Number(b.bsize)}catch{}e?.("Counting rows");let u=t.prepare(`SELECT
1436
1491
  (SELECT COUNT(*) FROM projects) AS projects,
1437
1492
  (SELECT COUNT(*) FROM sessions) AS sessions,
1438
1493
  (SELECT COUNT(*) FROM messages) AS messages,
1439
- (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=[];l>0&&l<1*1024**3&&m.push(`Disk free is ${ht(l)} \u2014 heavy operations (synthesis, extract-outputs, vector ingest) may fail.`),a>50*1024**2&&m.push(`WAL is ${ht(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=Zc("messages_fts"),g=Zc("sessions_fts");return f>16&&m.push(`messages_fts has ${f} segments \u2014 \`recall optimize\` will merge them.`),{db:{sizeBytes:i,walSizeBytes:a,pageCount:n,pageSize:s,freelistCount:r,freelistBytes:r*s,integrity:o},disk:{freeBytes:l,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},warnings:m}}function bb(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 ${d.ok("\u2713")} ${s} ${d.dim(`(${i})`)}
1494
+ (SELECT COUNT(*) FROM message_usage) AS message_usage`).get(),m=0;try{m=t.prepare("SELECT COUNT(*) AS n FROM vec_chunks").get().n}catch{}e?.("Measuring FTS fragmentation");let p=[];l>0&&l<1*1024**3&&p.push(`Disk free is ${ht(l)} \u2014 heavy operations (synthesis, extract-outputs, vector ingest) may fail.`),a>50*1024**2&&p.push(`WAL is ${ht(a)} \u2014 run \`recall optimize\` to truncate it.`),r>n*.2&&n>1e3&&p.push(`${r.toLocaleString()} free pages (${(r/n*100).toFixed(0)}% of file) \u2014 \`recall optimize --vacuum\` will reclaim them.`);let f=ol("messages_fts"),g=ol("sessions_fts");f>16&&p.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?p.push(`${h.toLocaleString()} rows in chunk_queue with semantic disabled \u2014 schema gate is stale; restart daemon (v0.67+) to migrate.`):h>1e5&&p.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:l,totalBytes:c},fts:{messages:{fragments:f},sessions:{fragments:g}},vectors:{rows:m},rows:{projects:u.projects,sessions:u.sessions,messages:u.messages,messageUsage:u.message_usage},chunkQueue:{size:h,semanticEnabled:E},warnings:p}}function jb(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 ${d.ok("\u2713")} ${s} ${d.dim(`(${i})`)}
1440
1495
  `):process.stderr.write(` \u2713 ${s} (${i})
1441
1496
  `),s=""};return{stage(o){r(),s=o,n=Date.now(),t?process.stderr.write(` ${d.dim("\u2026")} ${s}`):process.stderr.write(` \u2026 ${s}
1442
- `)},done:r}}async function ol(e={}){let t=bb(!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
1497
+ `)},done:r}}async function ml(e={}){let t=jb(!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
1443
1498
  FROM session_aliases sa
1444
1499
  LEFT JOIN sessions s ON s.id = sa.session_id
1445
- WHERE sa.alias IS NOT NULL AND sa.alias != ''`).all(),n=pb(s),r=Eb(t.stage);t.stage("Probing daemon");let o=await hb();if(t.done(),e.json){process.stdout.write(JSON.stringify({scanned:s.length,violations:n.length,items:n,health:r,pipeline:o},null,2)),process.stdout.write(`
1446
- `);let l=o.state==="degraded";return n.length===0&&r.db.integrity==="ok"&&!l?0:1}if(console.log(d.dim("\u2014 System health \u2014")),console.log(` Database ${ht(r.db.sizeBytes)} (${r.rows.messages.toLocaleString()} messages across ${r.rows.sessions.toLocaleString()} sessions, ${r.rows.projects.toLocaleString()} projects)`),console.log(` WAL ${ht(r.db.walSizeBytes)} (capped at 64 MB; truncated on clean shutdown)`),console.log(` Free pages ${r.db.freelistCount.toLocaleString()} (${ht(r.db.freelistBytes)} reclaimable via VACUUM)`),console.log(` FTS segments messages=${r.fts.messages.fragments}, sessions=${r.fts.sessions.fragments} (lower is faster \u2014 \`recall optimize\` merges them)`),console.log(` Vector rows ${r.vectors.rows.toLocaleString()}`),r.disk.totalBytes>0){let l=r.disk.freeBytes/r.disk.totalBytes*100;console.log(` Disk free ${ht(r.disk.freeBytes)} of ${ht(r.disk.totalBytes)} (${l.toFixed(1)}%)`)}if(console.log(` Integrity ${r.db.integrity==="ok"?d.ok("ok"):d.err(r.db.integrity)}`),r.warnings.length>0){console.log("");for(let l of r.warnings)console.log(` ${d.warn("!")} ${l}`)}if(console.log(""),console.log(d.dim("\u2014 Pipeline health (tab-name \u2192 session alias) \u2014")),o.daemon.running?console.log(` Daemon ${d.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 ${d.warn("not reachable")}`),o.runtime.silentTerminalRejections!==null){let l=o.runtime.silentTerminalRejections;console.log(` Auth rejections ${l===0?d.ok("0"):d.err(l.toLocaleString())} (extension /api/terminal/* requests denied without a valid X-Recall-Token)`)}if(o.runtime.lastTerminalSyncAt!==null){let l=Date.now()-Date.parse(o.runtime.lastTerminalSyncAt),c=Number.isFinite(l)?Math.round(l/6e4):null,u=c!==null&&l>nl;console.log(` Last ext sync ${u?d.warn(`${c} min ago`):d.ok(c===0?"just now":`${c} min ago`)} (most recent successful POST /api/terminal/sync)`)}else o.daemon.running&&console.log(` Last ext sync ${d.warn("never")} (no extension has called /api/terminal/sync since the daemon started)`);if(o.terminalsJson.exists&&o.terminalsJson.ageSeconds!==null){let l=Math.round(o.terminalsJson.ageSeconds/3600),c=o.terminalsJson.ageSeconds>24*3600;console.log(` terminals.json ${c?d.warn(`${l}h old`):d.ok(`${l}h old`)} (persisted registry mtime \u2014 fresh means extensions are connecting)`)}let i=o.recentSessions;if(i.total>0){let l=Math.round(i.fractionHeuristic*100),c=i.fractionHeuristic>=rl&&i.total>=3;console.log(` Recent titles ${c?d.err(`${l}% heuristic`):d.ok(`${l}% heuristic`)} (${i.heuristicOnly}/${i.total} sessions in last ${Mr}h fell back to first-message title)`)}if(o.flags.length>0){console.log("");for(let l of o.flags)console.log(` ${d.warn("!")} ${l}`)}if(console.log(""),console.log(d.dim("\u2014 Tab-name invariant \u2014")),n.length===0)return console.log(d.ok(` \u2713 holds across ${s.length.toLocaleString()} aliased session${s.length===1?"":"s"}`)),console.log(d.dim(" No fabricated origin labels (`VS Code \xB7 cwd \xB7 branch`) found. No deprecated cwd-branch synthesis found.")),r.db.integrity==="ok"?0:1;console.log(d.err(`\u2717 ${n.length} invariant violation${n.length===1?"":"s"} found across ${s.length.toLocaleString()} aliased sessions`)),console.log("");let a=new Map;for(let l of n){let c=a.get(l.violation)??[];c.push(l),a.set(l.violation,c)}for(let[l,c]of a){console.log(d.warn(` ${l} (${c.length})`));for(let u of c.slice(0,10))console.log(` ${u.session_id.slice(0,8)} ${d.dim("\u2192")} ${JSON.stringify(u.alias)}`);c.length>10&&console.log(d.dim(` \u2026 and ${c.length-10} more (rerun with --json for the full list)`)),console.log("")}return console.log(d.dim('Remediation: `recall name <id-prefix> ""` clears a bad alias so the heuristic title takes over,\nor `recall name <id-prefix> "<actual tab name>"` sets it to the real value.')),1}I();T();j();import{existsSync as Sb,readFileSync as yb}from"node:fs";import{join as Tb}from"node:path";function wb(){let e=Tb(x,"daemon.pid");if(!Sb(e))return!1;try{let t=parseInt(yb(e,"utf-8").trim(),10);return!Number.isFinite(t)||t<=0?!1:(process.kill(t,0),!0)}catch{return!1}}async function Yt(e,t){let s=Date.now();try{return t(),{step:e,ok:!0,durationMs:Date.now()-s}}catch(n){return{step:e,ok:!1,durationMs:Date.now()-s,error:n.message}}}async function il(e={}){let t=_(),s=[];if(e.vacuum&&wb())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)+`
1447
- `),2):(console.error(d.err("\u2717 VACUUM requires the daemon to be stopped. Run `recall stop` first, then re-run with --vacuum.")),2);s.push(await Yt("wal_checkpoint(TRUNCATE)",()=>{t.pragma("wal_checkpoint(TRUNCATE)")})),s.push(await Yt("messages_fts optimize",()=>{t.exec("INSERT INTO messages_fts(messages_fts) VALUES('optimize');")})),s.push(await Yt("sessions_fts optimize",()=>{t.exec("INSERT INTO sessions_fts(sessions_fts) VALUES('optimize');")})),s.push(await Yt("PRAGMA optimize",()=>{t.exec("PRAGMA optimize")})),e.vacuum&&s.push(await Yt("VACUUM",()=>{t.exec("VACUUM")}));let n=s.filter(r=>!r.ok);if(e.json)return process.stdout.write(JSON.stringify({ok:n.length===0,steps:s,vacuum:!!e.vacuum},null,2)+`
1448
- `),n.length===0?0:1;for(let r of s){let o=r.ok?d.ok("\u2713"):d.err("\u2717"),i=`${r.durationMs} ms`;console.log(` ${o} ${r.step.padEnd(28)} ${d.dim(i)}`),r.error&&console.log(` ${d.err(r.error)}`)}return n.length===0?(console.log(""),console.log(d.ok("All maintenance passes completed.")),e.vacuum||console.log(d.dim(" Run `recall optimize --vacuum` (with the daemon stopped) to reclaim disk pages from deleted rows.")),0):(console.log(""),console.log(d.warn(`${n.length} step(s) failed \u2014 review the errors above.`)),1)}I();T();j();import{existsSync as xb,readFileSync as Rb}from"node:fs";function kb(){let e=`${x}/daemon.port`;if(!xb(e))return null;try{let t=Rb(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}function Nb(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}
1500
+ WHERE sa.alias IS NOT NULL AND sa.alias != ''`).all(),n=Ab(s),r=$b(t.stage);t.stage("Probing daemon");let o=await Db();if(t.done(),e.json){process.stdout.write(JSON.stringify({scanned:s.length,violations:n.length,items:n,health:r,pipeline:o},null,2)),process.stdout.write(`
1501
+ `);let l=o.state==="degraded";return n.length===0&&r.db.integrity==="ok"&&!l?0:1}console.log(d.dim("\u2014 System health \u2014")),console.log(` Database ${ht(r.db.sizeBytes)} (${r.rows.messages.toLocaleString()} messages across ${r.rows.sessions.toLocaleString()} sessions, ${r.rows.projects.toLocaleString()} projects)`),console.log(` WAL ${ht(r.db.walSizeBytes)} (capped at 64 MB; truncated on clean shutdown)`),console.log(` Free pages ${r.db.freelistCount.toLocaleString()} (${ht(r.db.freelistBytes)} reclaimable via VACUUM)`);{let l=r.fts.messages.fragments,c=r.fts.sessions.fragments,u=l===0&&c===0;console.log(` FTS segments messages=${l}, sessions=${c}`+(u?" (merged \u2014 search uses the index)":" (lower is faster \u2014 `recall optimize` merges them)"))}if(r.chunkQueue.size>0){let c=r.chunkQueue.size>1e5?d.warn(r.chunkQueue.size.toLocaleString()):r.chunkQueue.size.toLocaleString();console.log(` Embed queue ${c}`+(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 l=r.disk.freeBytes/r.disk.totalBytes*100;console.log(` Disk free ${ht(r.disk.freeBytes)} of ${ht(r.disk.totalBytes)} (${l.toFixed(1)}%)`)}if(console.log(` Integrity ${r.db.integrity==="ok"?d.ok("ok"):d.err(r.db.integrity)}`),r.warnings.length>0){console.log("");for(let l of r.warnings)console.log(` ${d.warn("!")} ${l}`)}if(console.log(""),console.log(d.dim("\u2014 Pipeline health (tab-name \u2192 session alias) \u2014")),o.daemon.running?console.log(` Daemon ${d.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 ${d.warn("not reachable")}`),o.runtime.silentTerminalRejections!==null){let l=o.runtime.silentTerminalRejections;console.log(` Auth rejections ${l===0?d.ok("0"):d.err(l.toLocaleString())} (extension /api/terminal/* requests denied without a valid X-Recall-Token)`)}if(o.runtime.autoExtract){let l=o.runtime.autoExtract;l.circuitBroken?console.log(` Auto-extract ${d.err("circuit broken")} (${l.reason??"unknown"} \u2014 toggle off/on to reset)`):l.consecutiveZeroTokenRuns>0&&console.log(` Auto-extract ${d.warn(`${l.consecutiveZeroTokenRuns} zero-token run(s)`)} (breaker trips at 3)`)}if(o.runtime.lastTerminalSyncAt!==null){let l=Date.now()-Date.parse(o.runtime.lastTerminalSyncAt),c=Number.isFinite(l)?Math.round(l/6e4):null,u=c!==null&&l>dl;console.log(` Last ext sync ${u?d.warn(`${c} min ago`):d.ok(c===0?"just now":`${c} min ago`)} (most recent successful POST /api/terminal/sync)`)}else o.daemon.running&&console.log(` Last ext sync ${d.warn("never")} (no extension has called /api/terminal/sync since the daemon started)`);if(o.terminalsJson.exists&&o.terminalsJson.ageSeconds!==null){let l=Math.round(o.terminalsJson.ageSeconds/3600),c=o.terminalsJson.ageSeconds>24*3600;console.log(` terminals.json ${c?d.warn(`${l}h old`):d.ok(`${l}h old`)} (persisted registry mtime \u2014 fresh means extensions are connecting)`)}let i=o.recentSessions;if(i.total>0){let l=Math.round(i.fractionHeuristic*100),c=i.fractionHeuristic>=ul&&i.total>=3;console.log(` Recent titles ${c?d.err(`${l}% heuristic`):d.ok(`${l}% heuristic`)} (${i.heuristicOnly}/${i.total} sessions in last ${Fr}h fell back to first-message title)`)}if(o.flags.length>0){console.log("");for(let l of o.flags)console.log(` ${d.warn("!")} ${l}`)}if(console.log(""),console.log(d.dim("\u2014 Tab-name invariant \u2014")),n.length===0)return console.log(d.ok(` \u2713 holds across ${s.length.toLocaleString()} aliased session${s.length===1?"":"s"}`)),console.log(d.dim(" No fabricated origin labels (`VS Code \xB7 cwd \xB7 branch`) found. No deprecated cwd-branch synthesis found.")),r.db.integrity==="ok"?0:1;console.log(d.err(`\u2717 ${n.length} invariant violation${n.length===1?"":"s"} found across ${s.length.toLocaleString()} aliased sessions`)),console.log("");let a=new Map;for(let l of n){let c=a.get(l.violation)??[];c.push(l),a.set(l.violation,c)}for(let[l,c]of a){console.log(d.warn(` ${l} (${c.length})`));for(let u of c.slice(0,10))console.log(` ${u.session_id.slice(0,8)} ${d.dim("\u2192")} ${JSON.stringify(u.alias)}`);c.length>10&&console.log(d.dim(` \u2026 and ${c.length-10} more (rerun with --json for the full list)`)),console.log("")}return console.log(d.dim('Remediation: `recall name <id-prefix> ""` clears a bad alias so the heuristic title takes over,\nor `recall name <id-prefix> "<actual tab name>"` sets it to the real value.')),1}v();w();P();import{existsSync as Pb,readFileSync as Fb}from"node:fs";import{join as Ub}from"node:path";function Bb(){let e=Ub(x,"daemon.pid");if(!Pb(e))return!1;try{let t=parseInt(Fb(e,"utf-8").trim(),10);return!Number.isFinite(t)||t<=0?!1:(process.kill(t,0),!0)}catch{return!1}}async function qt(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 pl(e={}){let t=_(),s=[];if(e.vacuum&&Bb())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)+`
1502
+ `),2):(console.error(d.err("\u2717 VACUUM requires the daemon to be stopped. Run `recall stop` first, then re-run with --vacuum.")),2);s.push(await qt("wal_checkpoint(TRUNCATE)",()=>{t.pragma("wal_checkpoint(TRUNCATE)")})),s.push(await qt("messages_fts optimize",()=>{t.exec("INSERT INTO messages_fts(messages_fts) VALUES('optimize');")})),s.push(await qt("sessions_fts optimize",()=>{t.exec("INSERT INTO sessions_fts(sessions_fts) VALUES('optimize');")})),s.push(await qt("PRAGMA optimize",()=>{t.exec("PRAGMA optimize")})),e.vacuum&&s.push(await qt("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)+`
1503
+ `),n.length===0?0:1;for(let r of s){let o=r.ok?d.ok("\u2713"):d.err("\u2717"),i=`${r.durationMs} ms`;console.log(` ${o} ${r.step.padEnd(28)} ${d.dim(i)}`),r.error&&console.log(` ${d.err(r.error)}`)}return n.length===0?(console.log(""),console.log(d.ok("All maintenance passes completed.")),e.vacuum||console.log(d.dim(" Run `recall optimize --vacuum` (with the daemon stopped) to reclaim disk pages from deleted rows.")),0):(console.log(""),console.log(d.warn(`${n.length} step(s) failed \u2014 review the errors above.`)),1)}v();w();P();w();import{existsSync as Hb}from"node:fs";import{join as Wb}from"node:path";var Js=Wb(x,"archive.sqlite");var gl=!1;function fl(){if(gl&&Hb(Js))return;j();let e=_(),t=Js.replace(/'/g,"''");e.exec(`ATTACH DATABASE '${t}' AS archive`);try{e.exec(`
1504
+ CREATE TABLE IF NOT EXISTS archive.messages_archive (
1505
+ uuid TEXT PRIMARY KEY,
1506
+ session_id TEXT NOT NULL,
1507
+ parent_uuid TEXT,
1508
+ type TEXT,
1509
+ role TEXT,
1510
+ timestamp TEXT,
1511
+ is_sidechain INTEGER NOT NULL DEFAULT 0,
1512
+ content_text TEXT,
1513
+ tool_names TEXT,
1514
+ raw_json TEXT,
1515
+ archived_at TEXT NOT NULL DEFAULT (datetime('now'))
1516
+ );
1517
+ CREATE INDEX IF NOT EXISTS archive.idx_messages_archive_session ON messages_archive(session_id);
1518
+ `)}finally{e.exec("DETACH DATABASE archive")}gl=!0}import{existsSync as _l,mkdirSync as Xb,readFileSync as Jb,writeFileSync as Gb}from"node:fs";import{homedir as Yb}from"node:os";import{join as hl}from"node:path";import{z as Gs}from"zod";function El(){return process.env.RECALL_HOME??hl(Yb(),".recall")}function zb(){let e=El();_l(e)||Xb(e,{recursive:!0})}function bl(){return hl(El(),"config.json")}var Sl=Gs.object({autoArchiveEnabled:Gs.boolean().default(!1),autoArchiveAfterDays:Gs.number().int().min(7).max(3650).default(90),lastRunAt:Gs.string().nullable().default(null)}),Ys={autoArchiveEnabled:!1,autoArchiveAfterDays:90,lastRunAt:null};function Tl(){let e=bl();if(!_l(e))return{};try{return JSON.parse(Jb(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 yl(){let e=Tl().retention;if(!e)return{...Ys};let t=Sl.safeParse({...Ys,...e});return t.success?t.data:{...Ys}}function Ur(e){zb();let t=Tl(),s=Sl.parse({...Ys,...t.retention??{},...e}),n={...t,retention:s};return Gb(bl(),JSON.stringify(n,null,2)),s}function Br(e){fl();let t=_(),s=Js.replace(/'/g,"''");t.exec(`ATTACH DATABASE '${s}' AS archive`);try{return e(t)}finally{t.exec("DETACH DATABASE archive")}}function qb(){return Br(e=>{let t=e.prepare(`SELECT
1519
+ SUM(CASE WHEN archive_status = 'archived' THEN 1 ELSE 0 END) AS archived,
1520
+ SUM(CASE WHEN archive_status != 'archived' THEN 1 ELSE 0 END) AS live
1521
+ FROM sessions`).get(),s=e.prepare("SELECT COUNT(*) AS n FROM messages").get().n,n=e.prepare(`SELECT
1522
+ (SELECT COUNT(*) FROM main.messages_archive) +
1523
+ (SELECT COUNT(*) FROM archive.messages_archive) AS n`).get().n,r=e.prepare("SELECT MIN(timestamp) AS t FROM messages WHERE timestamp IS NOT NULL").get(),o=e.prepare(`SELECT MAX(t) AS t FROM (
1524
+ SELECT MAX(timestamp) AS t FROM main.messages_archive WHERE timestamp IS NOT NULL
1525
+ UNION ALL
1526
+ SELECT MAX(timestamp) AS t FROM archive.messages_archive WHERE timestamp IS NOT NULL
1527
+ )`).get();return{liveSessions:t.live??0,archivedSessions:t.archived??0,liveMessages:s,archivedMessages:n,oldestLiveTimestamp:r.t,newestArchivedTimestamp:o.t}})}function wl(e){return e?e.slice(0,10):"\u2014"}function Kb(){let e=qb();return console.log(d.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 ${wl(e.oldestLiveTimestamp)}`),console.log(` Newest archived ${wl(e.newestArchivedTimestamp)}`),console.log(""),console.log(d.dim(" recall archive run --before YYYY-MM-DD")),console.log(d.dim(" recall archive restore <session-id>")),0}function Vb(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
1528
+ FROM sessions s
1529
+ WHERE s.archive_status != 'archived'
1530
+ 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,l)=>a+(l.message_count??0),0);if(console.log(`${s.length.toLocaleString()} session(s), ${n.toLocaleString()} message(s) eligible.`),e.dryRun)return console.log(d.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=Br(a=>a.transaction(c=>{let u=0,m=a.prepare(`INSERT OR IGNORE INTO archive.messages_archive
1531
+ (uuid, session_id, parent_uuid, type, role, timestamp,
1532
+ is_sidechain, content_text, tool_names, raw_json, archived_at)
1533
+ SELECT uuid, session_id, parent_uuid, type, role, timestamp,
1534
+ is_sidechain, content_text, tool_names, raw_json, datetime('now')
1535
+ FROM messages WHERE session_id = ?`),p=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){m.run(g);let h=p.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(d.dim(" Run `recall optimize --vacuum` (with the daemon stopped) to reclaim disk pages from the moved rows.")),0}function Zb(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=Br(r=>r.transaction(()=>{let i=r.prepare(`INSERT OR IGNORE INTO messages
1536
+ (uuid, session_id, parent_uuid, type, role, timestamp,
1537
+ is_sidechain, content_text, tool_names, raw_json)
1538
+ SELECT uuid, session_id, parent_uuid, type, role, timestamp,
1539
+ is_sidechain, content_text, tool_names, raw_json
1540
+ FROM main.messages_archive WHERE session_id = ?`),a=r.prepare(`INSERT OR IGNORE INTO messages
1541
+ (uuid, session_id, parent_uuid, type, role, timestamp,
1542
+ is_sidechain, content_text, tool_names, raw_json)
1543
+ SELECT uuid, session_id, parent_uuid, type, role, timestamp,
1544
+ is_sidechain, content_text, tool_names, raw_json
1545
+ FROM archive.messages_archive WHERE session_id = ?`),l=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),m=Number(a.run(e).changes??0);return l.run(e),c.run(e),r.prepare("UPDATE sessions SET archive_status = 'live', archived_at = NULL WHERE id = ?").run(e),u+m})());return console.log(`Restored ${n.toLocaleString()} message(s) for session ${e}.`),0}function Qb(){let e=yl();return console.log(d.dim("\u2014 Auto-archive \u2014")),console.log(` Enabled ${e.autoArchiveEnabled?d.ok("YES"):"no"}`),console.log(` After ${e.autoArchiveAfterDays} days`),console.log(` Last run ${e.lastRunAt??"\u2014"}`),0}function eS(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=Ur({autoArchiveEnabled:!0,autoArchiveAfterDays:t});return console.log(`Auto-archive: ENABLED (after ${s.autoArchiveAfterDays} days).`),console.log(d.dim(" The daemon will run a daily archive pass on the next tick.")),0}function tS(){return Ur({autoArchiveEnabled:!1}),console.log("Auto-archive: DISABLED. Existing archived sessions stay archived."),0}async function Rl(e){let t=e._action??"list";if(t==="list"||t==="stats")return Kb();if(t==="run")return e.before?Vb({before:e.before,dryRun:e.dryRun===!0}):(console.error("Usage: recall archive run --before YYYY-MM-DD [--dry-run]"),1);if(t==="restore")return Zb(e._sessionId??"");if(t==="auto"){let s=e._subAction??"status";return s==="status"?Qb():s==="on"||s==="enable"?eS(e.after):s==="off"||s==="disable"?tS():(console.error("Usage: recall archive auto <status|on|off> [--after <days>]"),1)}return console.error(`Usage: recall archive <list|run|restore|auto> [args]
1546
+ list \u2014 show archive counts
1547
+ run --before YYYY-MM-DD [--dry-run] \u2014 move sessions older than DATE
1548
+ restore <session-id> \u2014 pull a session back from archive
1549
+ auto <status|on|off> [--after N] \u2014 daemon auto-archives sessions older than N days`),1}v();w();P();import{existsSync as sS,readFileSync as nS}from"node:fs";function rS(){let e=`${x}/daemon.port`;if(!sS(e))return null;try{let t=nS(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}function oS(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}
1449
1550
  `),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}"
1450
1551
  `),null):(process.stderr.write(`ambiguous session prefix "${e}". be more specific.
1451
- `),null)}async function al(e,t,s){let n=Nb(e);if(!n){process.exitCode=1;return}let r=t.trim();if(!r){process.stderr.write(`name cannot be empty
1452
- `),process.exitCode=1;return}let o=kb();if(!o){process.stderr.write("daemon is not running. start it with `recall start` so the alias write is durable.\n"),process.exitCode=1;return}let i;try{i=await tt("PUT",`http://127.0.0.1:${o}/api/sessions/${encodeURIComponent(n)}/alias`,{alias:r,pin:s.pin===!0})}catch(l){process.stderr.write(`failed to reach daemon at 127.0.0.1:${o}: ${l.message}
1552
+ `),null)}async function xl(e,t,s){let n=oS(e);if(!n){process.exitCode=1;return}let r=t.trim();if(!r){process.stderr.write(`name cannot be empty
1553
+ `),process.exitCode=1;return}let o=rS();if(!o){process.stderr.write("daemon is not running. start it with `recall start` so the alias write is durable.\n"),process.exitCode=1;return}let i;try{i=await tt("PUT",`http://127.0.0.1:${o}/api/sessions/${encodeURIComponent(n)}/alias`,{alias:r,pin:s.pin===!0})}catch(l){process.stderr.write(`failed to reach daemon at 127.0.0.1:${o}: ${l.message}
1453
1554
  `),process.exitCode=1;return}if(!i.ok){let l="";try{l=await i.text()}catch{}process.stderr.write(`daemon rejected alias write (HTTP ${i.status}): ${l}
1454
- `),process.exitCode=1;return}let a={session_id:n,alias:r};if(s.json){console.log(JSON.stringify(a));return}console.log(`${d.ok("renamed")} ${d.dim(n.slice(0,8))} \u2192 ${d.bold(`"${r}"`)}`)}I();T();var dl=90;async function Cb(){try{let e=`${process.env.HOME}/.recall/daemon.port`,t=await import("node:fs");if(!t.existsSync(e))return null;let s=t.readFileSync(e,"utf8").trim(),n=await _t(`http://127.0.0.1:${s}/api/terminal/registry`);return n.ok?await n.json():null}catch{return null}}function Lb(){let e=Date.now()/1e3-dl;return _().prepare(`SELECT s.id, s.cwd, s.file_mtime, NULLIF(sa.alias, '') AS alias
1555
+ `),process.exitCode=1;return}let a={session_id:n,alias:r};if(s.json){console.log(JSON.stringify(a));return}console.log(`${d.ok("renamed")} ${d.dim(n.slice(0,8))} \u2192 ${d.bold(`"${r}"`)}`)}v();w();var Ll=90;async function iS(){try{let e=`${process.env.HOME}/.recall/daemon.port`,t=await import("node:fs");if(!t.existsSync(e))return null;let s=t.readFileSync(e,"utf8").trim(),n=await _t(`http://127.0.0.1:${s}/api/terminal/registry`);return n.ok?await n.json():null}catch{return null}}function aS(){let e=Date.now()/1e3-Ll;return _().prepare(`SELECT s.id, s.cwd, s.file_mtime, NULLIF(sa.alias, '') AS alias
1455
1556
  FROM sessions s
1456
1557
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1457
1558
  WHERE s.cwd IS NOT NULL AND s.file_mtime > ?
1458
- ORDER BY s.cwd, s.file_mtime DESC`).all(e)}var Ob=new Set(["zsh","bash","fish","sh","dash","ksh","tcsh","csh","pwsh","powershell","cmd","nu"]);function cl(e){let t=e.trim().toLowerCase().replace(/^[-/]+/,"").replace(/^.*\//,"").replace(/\s*\(\d+\)\s*$/,"").trim();return!t||Ob.has(t)}var Ab=/^[⠀-⣿✳\s]+/,Ib=/^\d+(\.\d+){1,3}$/;function ll(e){let t=e.trim();return!!(!t||Ab.test(t)||Ib.test(t))}async function ul(e){let t=await Cb(),s=Lb();if(e.json){console.log(JSON.stringify({registry:t,active:s},null,2));return}if(console.log(),console.log(d.bold("TERMINAL REGISTRY")),console.log(d.dim("(what the daemon thinks each VS Code terminal is named)")),console.log(),!t){console.log(d.err(" Could not reach daemon. Is recall start running?"));return}let n=new Map;for(let o of t.terminals){let i=o.cwd??"(no cwd)",a=n.get(i);a||(a=[],n.set(i,a)),a.push(o)}for(let[o,i]of n){console.log(d.dim(` cwd: ${o}`));for(let a of i){let l=cl(a.tab_name),c=ll(a.tab_name),p=!l&&!c?d.ok("[usable]"):l?d.warn("[generic-shell]"):d.warn("[claude-auto]");console.log(` ${p} pid ${a.shell_pid} ${d.bold(`"${a.tab_name}"`)}`)}console.log()}if(console.log(d.bold(`ACTIVE SESSIONS (mtime within last ${dl}s)`)),console.log(d.dim("(sessions whose JSONL is being actively written)")),console.log(),s.length===0){console.log(d.dim(" (none)")),console.log();return}let r=new Map;for(let o of s){let i=r.get(o.cwd);i||(i=[],r.set(o.cwd,i)),i.push(o)}for(let[o,i]of r){console.log(d.dim(` cwd: ${o}`));for(let a of i)console.log(` ${d.dim(a.id.slice(0,8))} ${d.bold(a.alias??"(no alias)")} ${d.dim(`mtime ${new Date(a.file_mtime*1e3).toISOString().slice(11,19)}`)}`);console.log()}console.log(d.bold("LAYER 5 SWEEP DECISIONS")),console.log(d.dim("(what the live correlator would do for each cwd right now)")),console.log();for(let[o,i]of r){let l=(n.get(o)??[]).filter(c=>!cl(c.tab_name)&&!ll(c.tab_name));l.length===0?console.log(` ${d.warn("skip")} ${d.dim(o)} ${d.dim("\u2014 no usable terminal name (all generic or claude-auto)")}`):l.length>1?console.log(` ${d.warn("refuse")} ${d.dim(o)} ${d.dim(`\u2014 ${l.length} usable terminals, ambiguous`)}`):i.length>1?console.log(` ${d.warn("refuse")} ${d.dim(o)} ${d.dim(`\u2014 ${i.length} active sessions, ambiguous`)}`):console.log(` ${d.ok("link")} ${d.dim(o)} ${d.dim("\u2192")} ${d.dim(i[0].id.slice(0,8))} ${d.dim("=")} ${d.bold(`"${l[0].tab_name}"`)}`)}console.log()}I();T();j();import{existsSync as vb,readFileSync as Mb}from"node:fs";function $b(){let e=`${x}/daemon.port`;if(!vb(e))return null;try{let t=Mb(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function Db(e){try{let t=await _t(`http://127.0.0.1:${e}/api/terminal/registry`);return t.ok?(await t.json()).terminals??[]:[]}catch{return[]}}async function jb(e,t,s){try{return(await tt("POST",`http://127.0.0.1:${e}/api/sessions/${encodeURIComponent(t)}/relink`,{shell_pid:s})).ok}catch{return!1}}function Pb(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 Fb(e){let t=new Map;for(let i of e){if(!i.cwd)continue;let a=i.cwd.replace(/\/+$/,""),l=t.get(a);l||(l=new Map,t.set(a,l)),l.set(i.tab_name,i.shell_pid)}let s=new Map;for(let i of e){if(!i.cwd)continue;let l=`${i.cwd.replace(/\/+$/,"")}::${i.tab_name}`,c=s.get(l);c||(c=new Set,s.set(l,c)),c.add(String(i.shell_pid))}let r=_().prepare(`SELECT sa.session_id, s.cwd, sa.previous_aliases
1559
+ ORDER BY s.cwd, s.file_mtime DESC`).all(e)}var cS=new Set(["zsh","bash","fish","sh","dash","ksh","tcsh","csh","pwsh","powershell","cmd","nu"]);function kl(e){let t=e.trim().toLowerCase().replace(/^[-/]+/,"").replace(/^.*\//,"").replace(/\s*\(\d+\)\s*$/,"").trim();return!t||cS.has(t)}var lS=/^[⠀-⣿✳\s]+/,dS=/^\d+(\.\d+){1,3}$/;function Nl(e){let t=e.trim();return!!(!t||lS.test(t)||dS.test(t))}async function Cl(e){let t=await iS(),s=aS();if(e.json){console.log(JSON.stringify({registry:t,active:s},null,2));return}if(console.log(),console.log(d.bold("TERMINAL REGISTRY")),console.log(d.dim("(what the daemon thinks each VS Code terminal is named)")),console.log(),!t){console.log(d.err(" Could not reach daemon. Is recall start running?"));return}let n=new Map;for(let o of t.terminals){let i=o.cwd??"(no cwd)",a=n.get(i);a||(a=[],n.set(i,a)),a.push(o)}for(let[o,i]of n){console.log(d.dim(` cwd: ${o}`));for(let a of i){let l=kl(a.tab_name),c=Nl(a.tab_name),m=!l&&!c?d.ok("[usable]"):l?d.warn("[generic-shell]"):d.warn("[claude-auto]");console.log(` ${m} pid ${a.shell_pid} ${d.bold(`"${a.tab_name}"`)}`)}console.log()}if(console.log(d.bold(`ACTIVE SESSIONS (mtime within last ${Ll}s)`)),console.log(d.dim("(sessions whose JSONL is being actively written)")),console.log(),s.length===0){console.log(d.dim(" (none)")),console.log();return}let r=new Map;for(let o of s){let i=r.get(o.cwd);i||(i=[],r.set(o.cwd,i)),i.push(o)}for(let[o,i]of r){console.log(d.dim(` cwd: ${o}`));for(let a of i)console.log(` ${d.dim(a.id.slice(0,8))} ${d.bold(a.alias??"(no alias)")} ${d.dim(`mtime ${new Date(a.file_mtime*1e3).toISOString().slice(11,19)}`)}`);console.log()}console.log(d.bold("LAYER 5 SWEEP DECISIONS")),console.log(d.dim("(what the live correlator would do for each cwd right now)")),console.log();for(let[o,i]of r){let l=(n.get(o)??[]).filter(c=>!kl(c.tab_name)&&!Nl(c.tab_name));l.length===0?console.log(` ${d.warn("skip")} ${d.dim(o)} ${d.dim("\u2014 no usable terminal name (all generic or claude-auto)")}`):l.length>1?console.log(` ${d.warn("refuse")} ${d.dim(o)} ${d.dim(`\u2014 ${l.length} usable terminals, ambiguous`)}`):i.length>1?console.log(` ${d.warn("refuse")} ${d.dim(o)} ${d.dim(`\u2014 ${i.length} active sessions, ambiguous`)}`):console.log(` ${d.ok("link")} ${d.dim(o)} ${d.dim("\u2192")} ${d.dim(i[0].id.slice(0,8))} ${d.dim("=")} ${d.bold(`"${l[0].tab_name}"`)}`)}console.log()}v();w();P();import{existsSync as uS,readFileSync as mS}from"node:fs";function pS(){let e=`${x}/daemon.port`;if(!uS(e))return null;try{let t=mS(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function gS(e){try{let t=await _t(`http://127.0.0.1:${e}/api/terminal/registry`);return t.ok?(await t.json()).terminals??[]:[]}catch{return[]}}async function fS(e,t,s){try{return(await tt("POST",`http://127.0.0.1:${e}/api/sessions/${encodeURIComponent(t)}/relink`,{shell_pid:s})).ok}catch{return!1}}function _S(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 hS(e){let t=new Map;for(let i of e){if(!i.cwd)continue;let a=i.cwd.replace(/\/+$/,""),l=t.get(a);l||(l=new Map,t.set(a,l)),l.set(i.tab_name,i.shell_pid)}let s=new Map;for(let i of e){if(!i.cwd)continue;let l=`${i.cwd.replace(/\/+$/,"")}::${i.tab_name}`,c=s.get(l);c||(c=new Set,s.set(l,c)),c.add(String(i.shell_pid))}let r=_().prepare(`SELECT sa.session_id, s.cwd, sa.previous_aliases
1459
1560
  FROM session_aliases sa
1460
1561
  JOIN sessions s ON s.id = sa.session_id
1461
- WHERE sa.alias = '' AND sa.previous_aliases != '[]' AND s.cwd IS NOT NULL`).all(),o=[];for(let i of r){let a=Pb(i.previous_aliases);if(!a)continue;let l=i.cwd.replace(/\/+$/,""),u=t.get(l)?.get(a);if(!u)continue;let p=s.get(`${l}::${a}`);p&&p.size>1||o.push({session_id:i.session_id,cwd:l,alias_to_restore:a,matching_pid:u})}return o}async function pl(e){let t=$b();t||(console.error(d.err("Daemon is not running. Run `recall start` first.")),process.exit(1));let s=await Db(t);s.length===0&&(console.error(d.err("Registry is empty. Open VS Code with the extension to populate it.")),process.exit(1));let n=Fb(s);if(e.json){console.log(JSON.stringify({candidates:n},null,2));return}if(n.length===0){console.log(d.dim("No restorable sessions found.")),console.log(d.dim("A session is restorable when its previous alias still matches a currently-open terminal in the same cwd, with no name collisions."));return}console.log(d.bold(`Found ${n.length} session${n.length===1?"":"s"} that can be cleanly restored:`)),console.log();let r=new Map;for(let a of n){let l=r.get(a.cwd);l||(l=[],r.set(a.cwd,l)),l.push(a)}for(let[a,l]of r){console.log(d.dim(` cwd: ${a}`));for(let c of l)console.log(` ${d.dim(c.session_id.slice(0,8))} ${d.dim("\u2192 pid")} ${c.matching_pid} ${d.dim("=")} ${d.bold(`"${c.alias_to_restore}"`)}`);console.log()}if(!e.apply){console.log(d.dim("Re-run with --apply to restore these aliases."));return}let o=0,i=0;for(let a of n)await jb(t,a.session_id,a.matching_pid)?o++:(i++,console.error(d.err(`failed to restore ${a.session_id.slice(0,8)}`)));console.log(d.ok(`Restored ${o} alias${o===1?"":"es"}.${i>0?` ${i} failed.`:""}`)),console.log(d.dim("Sessions whose previous alias did not cleanly match a current terminal still need manual relink via the \u{1F517} picker."))}I();async function ml(e,t){let s=e.trim();if(!/^[0-9a-fA-F]{4,40}$/.test(s)){console.error(d.err(`not a valid commit SHA: '${e}'`)),process.exit(1);return}let n=Hs(s);if(t.json){console.log(JSON.stringify(n,null,2));return}if(n.length===0){console.log(""),console.log(d.dim(`no correlated sessions for ${s}`)),console.log(d.dim(" (if you haven't yet, run `recall correlate` to backfill)")),console.log("");return}console.log(""),console.log(`${d.bold("commit")} ${d.accent(n[0].commitSha.slice(0,12))} ${d.dim(n[0].committedAt??"")}`),n[0].subject&&console.log(` ${n[0].subject}`),console.log(""),console.log(d.dim(`authored during ${n.length} session${n.length===1?"":"s"}:`));for(let r of n){let o=r.alias??r.sessionId.slice(0,8);console.log(` ${d.accent(o.padEnd(24))} ${d.dim((r.project??"").slice(0,24).padEnd(26))} ${d.dim(r.startedAt??"")}`),console.log(` ${d.dim(`recall show ${r.sessionId}`)}`)}console.log("")}I();T();import{execFile as Ub}from"node:child_process";import{promisify as Bb}from"node:util";import{stat as Hb}from"node:fs/promises";var Wb=Bb(Ub),Xb=60,Jb=7,Gb=7,zb=5e3;function Yb(){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
1562
+ WHERE sa.alias = '' AND sa.previous_aliases != '[]' AND s.cwd IS NOT NULL`).all(),o=[];for(let i of r){let a=_S(i.previous_aliases);if(!a)continue;let l=i.cwd.replace(/\/+$/,""),u=t.get(l)?.get(a);if(!u)continue;let m=s.get(`${l}::${a}`);m&&m.size>1||o.push({session_id:i.session_id,cwd:l,alias_to_restore:a,matching_pid:u})}return o}async function Al(e){let t=pS();t||(console.error(d.err("Daemon is not running. Run `recall start` first.")),process.exit(1));let s=await gS(t);s.length===0&&(console.error(d.err("Registry is empty. Open VS Code with the extension to populate it.")),process.exit(1));let n=hS(s);if(e.json){console.log(JSON.stringify({candidates:n},null,2));return}if(n.length===0){console.log(d.dim("No restorable sessions found.")),console.log(d.dim("A session is restorable when its previous alias still matches a currently-open terminal in the same cwd, with no name collisions."));return}console.log(d.bold(`Found ${n.length} session${n.length===1?"":"s"} that can be cleanly restored:`)),console.log();let r=new Map;for(let a of n){let l=r.get(a.cwd);l||(l=[],r.set(a.cwd,l)),l.push(a)}for(let[a,l]of r){console.log(d.dim(` cwd: ${a}`));for(let c of l)console.log(` ${d.dim(c.session_id.slice(0,8))} ${d.dim("\u2192 pid")} ${c.matching_pid} ${d.dim("=")} ${d.bold(`"${c.alias_to_restore}"`)}`);console.log()}if(!e.apply){console.log(d.dim("Re-run with --apply to restore these aliases."));return}let o=0,i=0;for(let a of n)await fS(t,a.session_id,a.matching_pid)?o++:(i++,console.error(d.err(`failed to restore ${a.session_id.slice(0,8)}`)));console.log(d.ok(`Restored ${o} alias${o===1?"":"es"}.${i>0?` ${i} failed.`:""}`)),console.log(d.dim("Sessions whose previous alias did not cleanly match a current terminal still need manual relink via the \u{1F517} picker."))}v();async function Ol(e,t){let s=e.trim();if(!/^[0-9a-fA-F]{4,40}$/.test(s)){console.error(d.err(`not a valid commit SHA: '${e}'`)),process.exit(1);return}let n=Xs(s);if(t.json){console.log(JSON.stringify(n,null,2));return}if(n.length===0){console.log(""),console.log(d.dim(`no correlated sessions for ${s}`)),console.log(d.dim(" (if you haven't yet, run `recall correlate` to backfill)")),console.log("");return}console.log(""),console.log(`${d.bold("commit")} ${d.accent(n[0].commitSha.slice(0,12))} ${d.dim(n[0].committedAt??"")}`),n[0].subject&&console.log(` ${n[0].subject}`),console.log(""),console.log(d.dim(`authored during ${n.length} session${n.length===1?"":"s"}:`));for(let r of n){let o=r.alias??r.sessionId.slice(0,8);console.log(` ${d.accent(o.padEnd(24))} ${d.dim((r.project??"").slice(0,24).padEnd(26))} ${d.dim(r.startedAt??"")}`),console.log(` ${d.dim(`recall show ${r.sessionId}`)}`)}console.log("")}v();w();import{execFile as ES}from"node:child_process";import{promisify as bS}from"node:util";import{stat as SS}from"node:fs/promises";var TS=bS(ES),yS=60,wS=7,RS=7,xS=5e3;function kS(){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
1462
1563
  WHERE (COALESCE(total_input_tokens,0)
1463
1564
  + COALESCE(total_output_tokens,0)
1464
1565
  + COALESCE(total_cache_create_tokens,0)
1465
1566
  + COALESCE(total_cache_read_tokens,0)) > 0
1466
- LIMIT 1`),git:t("SELECT 1 FROM session_commits LIMIT 1")}}function $r(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 gl(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 qb(){let e=_(),t=e.prepare(`SELECT ss.keywords
1567
+ LIMIT 1`),git:t("SELECT 1 FROM session_commits LIMIT 1")}}function Hr(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 NS(){let e=_(),t=e.prepare(`SELECT ss.keywords
1467
1568
  FROM session_semantic ss
1468
1569
  JOIN sessions s ON s.id = ss.session_id
1469
1570
  WHERE s.started_at IS NOT NULL
1470
- AND julianday('now') - julianday(s.started_at) <= @windowDays`).all({windowDays:Jb});if(t.length===0)return null;let s=new Set;for(let o of t)for(let i of $r(o.keywords))s.add(i);if(s.size===0)return null;let n=e.prepare(`SELECT ss.session_id AS session_id,
1571
+ AND julianday('now') - julianday(s.started_at) <= @windowDays`).all({windowDays:wS});if(t.length===0)return null;let s=new Set;for(let o of t)for(let i of Hr(o.keywords))s.add(i);if(s.size===0)return null;let n=e.prepare(`SELECT ss.session_id AS session_id,
1471
1572
  ss.summary AS summary,
1472
1573
  ss.keywords AS keywords,
1473
1574
  p.name AS project,
@@ -1483,7 +1584,7 @@ Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u271
1483
1584
  WHERE s.started_at IS NOT NULL
1484
1585
  AND s.message_count > 2
1485
1586
  AND julianday('now') - julianday(s.started_at) >= @ageDays
1486
- ORDER BY s.started_at ASC`).all({ageDays:Xb});if(n.length===0)return null;let r=null;for(let o of n){let a=$r(o.keywords).filter(l=>s.has(l));a.length!==0&&(!r||a.length>r.overlap.length)&&(r={row:o,overlap:a})}return r?{...gl(r.row),summary:r.row.summary,keywords:$r(r.row.keywords),matchedKeywords:r.overlap,daysAgo:Math.max(0,Math.round(r.row.days_old))}:null}function Kb(){let t=_().prepare(`SELECT s.id AS session_id,
1587
+ ORDER BY s.started_at ASC`).all({ageDays:yS});if(n.length===0)return null;let r=null;for(let o of n){let a=Hr(o.keywords).filter(l=>s.has(l));a.length!==0&&(!r||a.length>r.overlap.length)&&(r={row:o,overlap:a})}return r?{...vl(r.row),summary:r.row.summary,keywords:Hr(r.row.keywords),matchedKeywords:r.overlap,daysAgo:Math.max(0,Math.round(r.row.days_old))}:null}function LS(){let t=_().prepare(`SELECT s.id AS session_id,
1487
1588
  p.name AS project,
1488
1589
  NULLIF(sa.alias, '') AS alias,
1489
1590
  s.started_at AS started_at,
@@ -1502,54 +1603,54 @@ Top ${l.length} cluster(s):`);for(let c of l){let u=c.status==="resolved"?"\u271
1502
1603
  AND (COALESCE(s.total_input_tokens, 0)
1503
1604
  + COALESCE(s.total_output_tokens, 0)
1504
1605
  + COALESCE(s.total_cache_create_tokens, 0)
1505
- + COALESCE(s.total_cache_read_tokens, 0)) > 0`).all({windowDays:Gb});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?{...gl(s.row),totalTokens:s.totalTokens,costCents:s.cents,costDisplay:se(s.cents),tokensDisplay:le(s.totalTokens),primaryModel:s.row.primary_model,primaryModelLabel:et(s.row.primary_model).label}:null}async function Vb(e){try{if(!(await Hb(e)).isDirectory())return null}catch{return null}try{let{stdout:t}=await Wb("git",["rev-parse","HEAD"],{cwd:e,timeout:zb}),s=t.trim();return/^[0-9a-f]{40}$/.test(s)?s:null}catch{return null}}async function Zb(){let e=_(),t=e.prepare(`SELECT s.id AS id, s.cwd AS cwd
1606
+ + COALESCE(s.total_cache_read_tokens, 0)) > 0`).all({windowDays:RS});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:se(s.cents),tokensDisplay:le(s.totalTokens),primaryModel:s.row.primary_model,primaryModelLabel:et(s.row.primary_model).label}:null}async function CS(e){try{if(!(await SS(e)).isDirectory())return null}catch{return null}try{let{stdout:t}=await TS("git",["rev-parse","HEAD"],{cwd:e,timeout:xS}),s=t.trim();return/^[0-9a-f]{40}$/.test(s)?s:null}catch{return null}}async function AS(){let e=_(),t=e.prepare(`SELECT s.id AS id, s.cwd AS cwd
1506
1607
  FROM sessions s
1507
1608
  WHERE s.cwd IS NOT NULL AND s.started_at IS NOT NULL
1508
1609
  ORDER BY COALESCE(s.ended_at, s.started_at, '') DESC
1509
- LIMIT 1`).get();if(!t?.cwd)return null;let s=await Vb(t.cwd);if(!s)return null;let n=Hs(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
1610
+ LIMIT 1`).get();if(!t?.cwd)return null;let s=await CS(t.cwd);if(!s)return null;let n=Xs(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
1510
1611
  FROM sessions s
1511
- 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 fl(){let e=Yb(),t=e.semantic?Promise.resolve().then(()=>{try{return qb()}catch(a){return console.error("[discover.rediscovered]",a),null}}):Promise.resolve(null),s=e.cost?Promise.resolve().then(()=>{try{return Kb()}catch(a){return console.error("[discover.expensive]",a),null}}):Promise.resolve(null),n=e.git?Zb().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 jr(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 Dr(e){return e.alias??(e.firstUserMessage?jr(e.firstUserMessage,60):null)??e.sessionId.slice(0,8)}function Qb(e){let t=e.rediscovered||e.expensive||e.authored;if(console.log(""),console.log(d.bold("today \xB7 for you")),console.log(d.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),!t){let s=[];e.availability.semantic||s.push("v0.11 semantic (`recall semantic on`)"),e.availability.cost||s.push("v0.10a cost (`recall stats --backfill`)"),e.availability.git||s.push("v0.10b git (`recall correlate`)"),console.log(d.dim(" no picks today.")),s.length>0?console.log(d.dim(" enable: "+s.join(", "))):console.log(d.dim(" data sources are live but nothing matched \u2014 try again tomorrow.")),console.log("");return}if(e.rediscovered){let s=e.rediscovered;console.log(""),console.log(` ${d.tool("\u2726 rediscovered")} ${d.dim(`(${s.daysAgo}d ago)`)}`),console.log(` ${d.bold(Dr(s))} ${d.dim(s.project?`\xB7 ${s.project}`:"")}`),console.log(` ${d.dim(s.sessionId.slice(0,8))}`),s.matchedKeywords.length>0&&console.log(" "+d.dim("matched: ")+s.matchedKeywords.slice(0,6).map(n=>d.tool(`#${n}`)).join(" ")),s.summary&&console.log(" "+d.dim(jr(s.summary,100)))}if(e.expensive){let s=e.expensive;console.log(""),console.log(` ${d.accent("$ most expensive \xB7 7d")} ${d.bold(s.costDisplay)} ${d.dim(`(${s.tokensDisplay} \xB7 ${s.primaryModelLabel})`)}`),console.log(` ${d.bold(Dr(s))} ${d.dim(s.project?`\xB7 ${s.project}`:"")}`),console.log(` ${d.dim(s.sessionId.slice(0,8))} ${d.dim(s.startedAt?W(s.startedAt):"")}`)}if(e.authored){let s=e.authored;console.log(""),console.log(` ${d.ok("\u2387 authored current HEAD")} ${d.bold(s.shortSha)} ${d.dim(s.committedAt?`(${W(s.committedAt)})`:"")}`),console.log(` ${d.bold(Dr(s))} ${d.dim(s.project?`\xB7 ${s.project}`:"")}`),s.subject&&console.log(` ${d.dim(jr(s.subject,80))}`),console.log(` ${d.dim(s.sessionId.slice(0,8))} ${d.dim("cwd: "+s.cwd)}`)}console.log("")}async function _l(e){let t=await fl();if(e.json){console.log(JSON.stringify(t,null,2));return}Qb(t)}I();import{spawnSync as Sl}from"node:child_process";import{readdirSync as eS}from"node:fs";import{join as tS,resolve as sS}from"node:path";var Pr=["code","cursor","code-insiders","windsurf"],hl=[{id:"code",label:"VS Code"},{id:"cursor",label:"Cursor"},{id:"code-insiders",label:"VS Code Insiders"},{id:"windsurf",label:"Windsurf"}],nS="https://marketplace.visualstudio.com/items?itemName=clauderecallhq.clauderecall-vscode";function rS(){return tS(Te(),"extensions","vscode")}function oS(){let e=rS(),t;try{t=eS(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})),sS(e,s[0]))}function El(e){let t=Sl(e,["--version"],{stdio:"ignore",shell:process.platform==="win32"});return t.error?!1:t.status===0}function iS(e,t){let s=Sl(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 bl(){process.stderr.write(d.err(`no bundled .vsix found at extensions/vscode/(clauderecall|claude-recall)-vscode-*.vsix
1612
+ 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 Il(){let e=kS(),t=e.semantic?Promise.resolve().then(()=>{try{return NS()}catch(a){return console.error("[discover.rediscovered]",a),null}}):Promise.resolve(null),s=e.cost?Promise.resolve().then(()=>{try{return LS()}catch(a){return console.error("[discover.expensive]",a),null}}):Promise.resolve(null),n=e.git?AS().catch(a=>(console.error("[discover.authored]",a),null)):Promise.resolve(null),[r,o,i]=await Promise.all([t,s,n]);return{rediscovered:r,expensive:o,authored:i,availability:e,generatedAt:new Date().toISOString()}}function Xr(e,t=60){if(!e)return"";let s=e.replace(/\s+/g," ").trim();return s.length<=t?s:s.slice(0,t-1)+"\u2026"}function Wr(e){return e.alias??(e.firstUserMessage?Xr(e.firstUserMessage,60):null)??e.sessionId.slice(0,8)}function OS(e){let t=e.rediscovered||e.expensive||e.authored;if(console.log(""),console.log(d.bold("today \xB7 for you")),console.log(d.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),!t){let s=[];e.availability.semantic||s.push("v0.11 semantic (`recall semantic on`)"),e.availability.cost||s.push("v0.10a cost (`recall stats --backfill`)"),e.availability.git||s.push("v0.10b git (`recall correlate`)"),console.log(d.dim(" no picks today.")),s.length>0?console.log(d.dim(" enable: "+s.join(", "))):console.log(d.dim(" data sources are live but nothing matched \u2014 try again tomorrow.")),console.log("");return}if(e.rediscovered){let s=e.rediscovered;console.log(""),console.log(` ${d.tool("\u2726 rediscovered")} ${d.dim(`(${s.daysAgo}d ago)`)}`),console.log(` ${d.bold(Wr(s))} ${d.dim(s.project?`\xB7 ${s.project}`:"")}`),console.log(` ${d.dim(s.sessionId.slice(0,8))}`),s.matchedKeywords.length>0&&console.log(" "+d.dim("matched: ")+s.matchedKeywords.slice(0,6).map(n=>d.tool(`#${n}`)).join(" ")),s.summary&&console.log(" "+d.dim(Xr(s.summary,100)))}if(e.expensive){let s=e.expensive;console.log(""),console.log(` ${d.accent("$ most expensive \xB7 7d")} ${d.bold(s.costDisplay)} ${d.dim(`(${s.tokensDisplay} \xB7 ${s.primaryModelLabel})`)}`),console.log(` ${d.bold(Wr(s))} ${d.dim(s.project?`\xB7 ${s.project}`:"")}`),console.log(` ${d.dim(s.sessionId.slice(0,8))} ${d.dim(s.startedAt?W(s.startedAt):"")}`)}if(e.authored){let s=e.authored;console.log(""),console.log(` ${d.ok("\u2387 authored current HEAD")} ${d.bold(s.shortSha)} ${d.dim(s.committedAt?`(${W(s.committedAt)})`:"")}`),console.log(` ${d.bold(Wr(s))} ${d.dim(s.project?`\xB7 ${s.project}`:"")}`),s.subject&&console.log(` ${d.dim(Xr(s.subject,80))}`),console.log(` ${d.dim(s.sessionId.slice(0,8))} ${d.dim("cwd: "+s.cwd)}`)}console.log("")}async function Ml(e){let t=await Il();if(e.json){console.log(JSON.stringify(t,null,2));return}OS(t)}v();import{spawnSync as Pl}from"node:child_process";import{readdirSync as vS}from"node:fs";import{join as IS,resolve as MS}from"node:path";var Jr=["code","cursor","code-insiders","windsurf"],Dl=[{id:"code",label:"VS Code"},{id:"cursor",label:"Cursor"},{id:"code-insiders",label:"VS Code Insiders"},{id:"windsurf",label:"Windsurf"}],DS="https://marketplace.visualstudio.com/items?itemName=clauderecallhq.clauderecall-vscode";function $S(){return IS(ye(),"extensions","vscode")}function jS(){let e=$S(),t;try{t=vS(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})),MS(e,s[0]))}function $l(e){let t=Pl(e,["--version"],{stdio:"ignore",shell:process.platform==="win32"});return t.error?!1:t.status===0}function PS(e,t){let s=Pl(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 jl(){process.stderr.write(d.err(`no bundled .vsix found at extensions/vscode/(clauderecall|claude-recall)-vscode-*.vsix
1512
1613
  `)),process.stderr.write(d.dim(`see PUBLISHING.md for how to build the extension, or run:
1513
1614
  `)),process.stderr.write(d.dim(` (cd extensions/vscode && npm install && npm run build && npm run package)
1514
- `))}function aS(e){return Pr.includes(e)}async function yl(e){if(e.editor!==void 0&&!aS(e.editor)){process.stderr.write(d.err(`unknown --editor target: ${e.editor}
1515
- `)),process.stderr.write(d.dim(`valid values: ${Pr.join(", ")}
1516
- `)),process.exitCode=1;return}let t=oS();if(e.printPath){if(!t){bl(),process.exitCode=1;return}process.stdout.write(t+`
1517
- `);return}if(!t){bl(),process.exitCode=1;return}let s;if(e.editor){let r=e.editor;if(!El(r)){process.stderr.write(d.err(`editor CLI not found on PATH: ${r}
1615
+ `))}function FS(e){return Jr.includes(e)}async function Fl(e){if(e.editor!==void 0&&!FS(e.editor)){process.stderr.write(d.err(`unknown --editor target: ${e.editor}
1616
+ `)),process.stderr.write(d.dim(`valid values: ${Jr.join(", ")}
1617
+ `)),process.exitCode=1;return}let t=jS();if(e.printPath){if(!t){jl(),process.exitCode=1;return}process.stdout.write(t+`
1618
+ `);return}if(!t){jl(),process.exitCode=1;return}let s;if(e.editor){let r=e.editor;if(!$l(r)){process.stderr.write(d.err(`editor CLI not found on PATH: ${r}
1518
1619
  `)),process.stderr.write(d.dim(`install the editor shell integration, or omit --editor to install into every detected editor.
1519
1620
  `)),process.stderr.write(d.dim(`see PUBLISHING.md for manual install instructions.
1520
- `)),process.exitCode=1;return}s=[hl.find(i=>i.id===r)??{id:r,label:r}]}else s=hl.filter(r=>El(r.id));if(s.length===0){process.stderr.write(d.err(`no supported editor CLI detected on PATH.
1521
- `)),process.stderr.write(d.dim(`looked for: ${Pr.join(", ")}.
1621
+ `)),process.exitCode=1;return}s=[Dl.find(i=>i.id===r)??{id:r,label:r}]}else s=Dl.filter(r=>$l(r.id));if(s.length===0){process.stderr.write(d.err(`no supported editor CLI detected on PATH.
1622
+ `)),process.stderr.write(d.dim(`looked for: ${Jr.join(", ")}.
1522
1623
  `)),process.stderr.write(d.dim(`install the editor shell integration and try again.
1523
1624
  `)),process.stderr.write(d.dim(`see PUBLISHING.md for manual install instructions.
1524
1625
  `)),process.exitCode=1;return}process.stderr.write(d.dim(`bundled .vsix: ${t}
1525
1626
 
1526
- `));let n=!1;for(let r of s){let{ok:o,message:i}=iS(r.id,t);o?process.stderr.write(d.ok(`\u2713 installed into ${r.label} (${r.id})
1627
+ `));let n=!1;for(let r of s){let{ok:o,message:i}=PS(r.id,t);o?process.stderr.write(d.ok(`\u2713 installed into ${r.label} (${r.id})
1527
1628
  `)):(n=!0,process.stderr.write(d.err(`\u2717 ${r.label} (${r.id}): ${i}
1528
1629
  `)))}process.stderr.write(`
1529
1630
  `),process.stderr.write(d.bold(`next steps:
1530
1631
  `)),process.stderr.write(` 1. reload the editor window: Cmd/Ctrl+Shift+P then pick "Developer: Reload Window"
1531
1632
  `),process.stderr.write(` 2. enable the extension: open settings and set "claude-recall.autoAlias" to true
1532
1633
  `),process.stderr.write(`
1533
- `),process.stderr.write(d.dim(`marketplace install: ${nS}
1534
- `)),n&&(process.exitCode=1)}Hr();I();function Wr(e){return e>=70?d.ok:e>=40?d.warn:d.err}function wl(e,t=20){let s=Math.round(e/100*t);return"\u2588".repeat(s)+"\u2591".repeat(t-s)}function cS(e){let t=Wr(e.score);process.stdout.write(`
1634
+ `),process.stderr.write(d.dim(`marketplace install: ${DS}
1635
+ `)),n&&(process.exitCode=1)}qr();v();function Kr(e){return e>=70?d.ok:e>=40?d.warn:d.err}function Bl(e,t=20){let s=Math.round(e/100*t);return"\u2588".repeat(s)+"\u2591".repeat(t-s)}function US(e){let t=Kr(e.score);process.stdout.write(`
1535
1636
  ${d.bold(e.projectName)} ${t(String(e.score)+"/100")}
1536
- `);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=Wr(o);process.stdout.write(` ${r.padEnd(10)} ${a(wl(o,16))} ${String(Math.round(o)).padStart(3)}% ${d.dim(i)}
1537
- `)}}function xl(e,t){if(e){let r=Ur(e);if(!r){process.stderr.write(d.err(`project "${e}" not found
1637
+ `);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=Kr(o);process.stdout.write(` ${r.padEnd(10)} ${a(Bl(o,16))} ${String(Math.round(o)).padStart(3)}% ${d.dim(i)}
1638
+ `)}}function Hl(e,t){if(e){let r=Yr(e);if(!r){process.stderr.write(d.err(`project "${e}" not found
1538
1639
  `)),process.exitCode=1;return}if(t.json){process.stdout.write(JSON.stringify(r,null,2)+`
1539
- `);return}cS(r);return}let s=Br();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)+`
1640
+ `);return}US(r);return}let s=zr();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)+`
1540
1641
  `);return}let n=[...s].sort((r,o)=>r.score-o.score);process.stdout.write(d.bold("Memory Health Scores")+` (worst first)
1541
1642
 
1542
- `);for(let r of n){let o=Wr(r.score);process.stdout.write(` ${o(wl(r.score,12))} ${String(r.score).padStart(3)}/100 ${r.projectName}
1643
+ `);for(let r of n){let o=Kr(r.score);process.stdout.write(` ${o(Bl(r.score,12))} ${String(r.score).padStart(3)}/100 ${r.projectName}
1543
1644
  `)}process.stdout.write(`
1544
- `)}I();function Rl(e){if(e==="on"){On(!0),process.stdout.write(d.ok("Verification badges enabled.")+`
1545
- `);return}if(e==="off"){On(!1),process.stdout.write(`Verification badges disabled.
1546
- `);return}let t=cs();process.stdout.write(`Verification badges: ${t?d.ok("ON"):"OFF"}
1645
+ `)}v();function Wl(e){if(e==="on"){Dn(!0),process.stdout.write(d.ok("Verification badges enabled.")+`
1646
+ `);return}if(e==="off"){Dn(!1),process.stdout.write(`Verification badges disabled.
1647
+ `);return}let t=ds();process.stdout.write(`Verification badges: ${t?d.ok("ON"):"OFF"}
1547
1648
  `),process.stdout.write(`
1548
1649
  Toggle with: recall verify on | off
1549
- `)}I();ps();In();Pt();vn();import{hostname as IS}from"node:os";import{randomBytes as vS}from"node:crypto";We();_e();j();T();import{existsSync as lS}from"node:fs";import dS from"node:readline";import{createRequire as uS}from"node:module";import{Chalk as pS}from"chalk";var mS=uS(import.meta.url),gS=mS(`${Te()}/package.json`).version,Ll="#f97316",fS="#8b9098",_S="#10b981",hS="#f59e0b",kt=new pS({level:process.env.NO_COLOR?0:3}),Ee=kt.hex(Ll),ne=kt.hex(Ll).bold,A=kt.hex(fS),Et=kt.hex(_S),Ws=kt.hex(hS),Ol=kt.bold,Al=[" \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"],ES=Al[0]?.length??49,kl="Never lose a Claude Code session again.",bS="CLAUDE RECALL";function SS(){if(!lS(te))return{sessions:0,projects:0};try{let t=_().prepare(`SELECT
1650
+ `)}v();gs();jn();Pt();Pn();import{hostname as dT}from"node:os";import{randomBytes as uT}from"node:crypto";Xe();_e();P();w();import{existsSync as BS}from"node:fs";import HS from"node:readline";import{createRequire as WS}from"node:module";import{Chalk as XS}from"chalk";var JS=WS(import.meta.url),GS=JS(`${ye()}/package.json`).version,Yl="#f97316",YS="#8b9098",zS="#10b981",qS="#f59e0b",kt=new XS({level:process.env.NO_COLOR?0:3}),Ee=kt.hex(Yl),ne=kt.hex(Yl).bold,O=kt.hex(YS),Et=kt.hex(zS),zs=kt.hex(qS),zl=kt.bold,ql=[" \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"],KS=ql[0]?.length??49,Xl="Never lose a Claude Code session again.",VS="CLAUDE RECALL";function ZS(){if(!BS(te))return{sessions:0,projects:0};try{let t=_().prepare(`SELECT
1550
1651
  (SELECT COUNT(*) FROM sessions) AS sessions,
1551
- (SELECT COUNT(*) FROM projects) AS projects`).get();return{sessions:t.sessions,projects:t.projects}}catch{return{sessions:0,projects:0}}}function yS(){let e=process.stdout.columns;return typeof e!="number"||e<=0?!1:e<ES+2}function Il(){if(yS()){console.log(`${ne(bS)} ${A("\xB7")} ${A(kl)}`);return}for(let e of Al)console.log(ne(e));console.log(A(kl))}async function TS(){return{daemon:K(),counts:SS(),license:await ye()}}function wS(e){let t=[];if(t.push(` ${A("Version:")} ${Ee(`v${gS}`)} ${A("\xB7 CLI \xB7 @clauderecallhq/cli")}`),e.daemon){let s=`http://127.0.0.1:${e.daemon.port}`;t.push(` ${A("Daemon:")} ${Et("running")} on ${s} ${A(`(pid ${e.daemon.pid})`)}`)}else t.push(` ${A("Daemon:")} ${Ws("stopped")}`);if(e.counts.sessions===0)t.push(` ${A("Sessions:")} ${Ws("none indexed yet")}`);else{let s=e.counts.projects===1?"project":"projects";t.push(` ${A("Sessions:")} ${Ee(String(e.counts.sessions))} indexed across ${Ee(String(e.counts.projects))} ${s}`)}return e.license.tier==="pro"?t.push(` ${A("License:")} ${Et("Pro")}`):t.push(` ${A("License:")} Free`),t}function xS(e){let t=Ee(">");if(e.counts.sessions===0)return`${t} Run ${ne("recall index")} to scan ~/.claude/projects/`;if(!e.daemon)return`${t} Run ${ne("recall start")} to launch the local daemon`;if(e.license.tier==="free")return`${t} Run ${ne("recall upgrade")} to unlock Pro features`;let s=`http://127.0.0.1:${e.daemon.port}`;return`${t} Open ${Ee(s)} in your browser ${A("\xB7")} or run ${ne("recall --help")} for all commands`}var Xs=[{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"}]}],RS=Xs.reduce((e,t)=>e+t.commands.length,0),kS=new Set([...Xs.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 Nl(){let e=Xs.flatMap(s=>s.commands.map(n=>`recall ${n.name}`)),t=Math.max(...e.map(s=>s.length));console.log(),console.log(`${Ol("COMMANDS")} ${A(`\xB7 ${RS} total \xB7 q to quit \xB7 recall --help for full details`)}`),console.log(` ${A("All commands run as subcommands of")} ${ne("recall")}${A(". There is no separate")} ${Ee("threads")}${A(",")} ${Ee("thread")}${A(", or")} ${Ee("titles")} ${A("binary.")}`);for(let s of Xs){console.log(),console.log(` ${ne(s.title.toUpperCase())}`);for(let n of s.commands){let r=`recall ${n.name}`.padEnd(t," ");console.log(` ${Ee(r)} ${A(n.description)}`)}}console.log()}function NS(){return!!process.stdin.isTTY&&!!process.stdout.isTTY}async function CS(){if(!NS())return;let e=dS.createInterface({input:process.stdin,output:process.stdout}),t=`${A("Type")} ${ne("/")} ${A("for commands, or press")} ${ne("Enter")} ${A("to exit")} ${Ee("\u203A")} `;return new Promise(s=>{let n=()=>{e.question(t,r=>{let o=r.trim();if(o==="/"||o==="/help"||o==="help"||o==="?"){Nl(),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===""){Nl(),n();return}let l=(i.split(/\s+/)[0]??"").toLowerCase();kS.has(l)?console.log(` ${A("Run")} ${ne(`recall ${i}`)} ${A("in your shell to invoke that command.")}`):console.log(` ${A(`No command matches "${o}". Type`)} ${ne("/")} ${A("to browse, or")} ${ne("recall --help")} ${A("for the full list.")}`),n()})};e.on("close",()=>{console.log(),s()}),n()})}async function vl(){let e=await TS();console.log(),Il(),console.log();for(let t of wS(e))console.log(t);console.log(),console.log(xS(e)),console.log(),await CS()}var LS=[{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 OS(){return process.env.NO_COLOR||process.env.CI||process.env.RECALL_NO_ANIMATION?!1:!!process.stdout.isTTY}function Xr(e){return new Promise(t=>setTimeout(t,e))}function AS(e){let s=(e.split("@")[0]??"").split(/[._+\-]/)[0]??"";return s?s.charAt(0).toUpperCase()+s.slice(1).toLowerCase():""}function Cl(){process.stdout.write("\r\x1B[2K")}async function Ml(e){let t=OS();console.log(),Il(),console.log(),t&&(process.stdout.write(` ${A("Verifying license...")}`),await Xr(260),Cl()),console.log(` ${Et("\u2713")} ${A("License verified")}`),console.log(` ${Et("\u2713")} ${A("Tier:")} ${ne("Pro")} ${A("\xB7 Lifetime")}`),console.log(` ${Et("\u2713")} ${A("Key:")} ${Ee(e.key_short)}`),console.log(` ${Et("\u2713")} ${A("Email:")} ${e.email}`),e.test_mode&&console.log(` ${Ws("!")} ${Ws("Test mode:")} this license was issued in test mode.`),console.log(),console.log(` ${Ol("Unlocking Pro features")}`),console.log();for(let r of LS)t&&(process.stdout.write(` ${A("\xB7")} ${A(r.name)}`),await Xr(110),Cl()),console.log(` ${Et("\u2713")} ${r.name} ${A(r.detail)}`);t&&await Xr(160),console.log();let s=AS(e.email),n=s?`Welcome aboard, ${s}.`:"Welcome aboard.";console.log(` ${ne(n)}`),console.log(` ${A("Run")} ${Ee("recall")} ${A("to open the dashboard, or")} ${Ee("recall help")} ${A("for the command list.")}`),console.log()}async function $l(e){let t=e.trim();t.length<8&&(console.error(d.warn("License key looks too short. Paste the full key from your purchase email.")),process.exit(1));let s=`${IS()}-${vS(4).toString("hex")}`,n=`${xt()}/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:us()})})}catch(a){let l=a instanceof Error?a.message:"unknown error";console.error(d.warn(`Could not reach activation server at ${n}: ${l}`)),console.error(d.dim("If you are offline, try again when you have a connection.")),process.exit(1)}let o;try{o=await r.json()}catch{console.error(d.warn(`Activation server returned invalid JSON (status ${r.status}).`)),process.exit(1)}if(r.status!==200||!o.license_jwt){let a=o.error??`activation failed (status ${r.status})`;console.error(d.warn(`Activation refused: ${a}`)),process.exit(1)}let i=await ds(o.license_jwt);(!i.valid||!i.claims)&&(console.error(d.warn(`Server returned a JWT that fails local verification: ${i.reason??"unknown"}`)),console.error(d.dim("This usually means the CLI is older than the server, or the public key was rotated.")),process.exit(1)),ni({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 Ml({...i.claims,key_short:o.key_short??i.claims.key_short,email:o.customer_email??i.claims.email})}I();import{spawn as MS}from"node:child_process";import{platform as Js}from"node:os";var Dl="https://clauderecall.com/pricing";function $S(e){let t=Js()==="darwin"?"open":Js()==="win32"?"start":"xdg-open",s=Js()==="win32"?["",e]:[e];MS(t,s,{detached:!0,stdio:"ignore",shell:Js()==="win32"}).unref()}async function jl(){let{getLicenseStatus:e}=await Promise.resolve().then(()=>(_e(),gs)),t=await e();if(t.tier==="pro"){console.log(),console.log(d.bold("Already on Pro.")),console.log(` ${d.dim("Key:")} ${t.key_short}`),console.log(` ${d.dim("Email:")} ${t.customer_email}`),console.log();return}console.log(),console.log(`${d.ok("Opening")} ${Dl}`),console.log(d.dim("After purchase, run: recall activate <license-key>")),console.log(),$S(Dl)}I();import{spawn as DS}from"node:child_process";import{platform as Gs}from"node:os";var Pl="https://clauderecall.com/pricing?trial=1&utm_source=cli&utm_medium=recall_trial";function jS(e){let t=Gs()==="darwin"?"open":Gs()==="win32"?"start":"xdg-open",s=Gs()==="win32"?["",e]:[e];DS(t,s,{detached:!0,stdio:"ignore",shell:Gs()==="win32"}).unref()}async function Fl(){let{getLicenseStatus:e}=await Promise.resolve().then(()=>(_e(),gs)),t=await e();if(t.tier==="pro"){console.log(),console.log(d.bold("You are already on Pro.")),console.log(` ${d.dim("Key:")} ${t.key_short}`),console.log(` ${d.dim("Email:")} ${t.customer_email}`),console.log();return}console.log(),console.log(`${d.ok("Opening")} ${Pl}`),console.log(d.dim("Enter your email to get a 7-day Pro trial link. No card.")),console.log(d.dim("After you click the verification email, run: recall activate <key>")),console.log(),jS(Pl)}I();import{createRequire as XS}from"module";ps();import{existsSync as Ul,mkdirSync as PS,readFileSync as FS,writeFileSync as US}from"node:fs";import{homedir as BS}from"node:os";import{join as Bl}from"node:path";import{randomBytes as HS}from"node:crypto";var Gr=Bl(BS(),".recall"),Ys=Bl(Gr,"telemetry.json"),Jr={decided_at:null,decision:null,last_ping_month:null,nonce_month:null,nonce:null,last_error:null};function bt(){if(!Ul(Ys))return{...Jr};try{let e=FS(Ys,"utf8"),t=JSON.parse(e);return{...Jr,...t}}catch{return{...Jr}}}function zs(e){Ul(Gr)||PS(Gr,{recursive:!0}),US(Ys,JSON.stringify(e,null,2)+`
1552
- `,{mode:384})}function Hl(){return Ys}function zr(e=new Date){let t=e.getUTCFullYear(),s=String(e.getUTCMonth()+1).padStart(2,"0");return`${t}-${s}`}function Wl(e,t){return e.nonce&&e.nonce_month===t?e:{...e,nonce:HS(16).toString("hex"),nonce_month:t}}function WS(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 Xl(e){let t=bt();if(t.decision!=="on")return{status:t.decision==="off"?"opted-out":"no-decision"};let s=zr();if(t.last_ping_month===s)return{status:"already-this-month"};t=Wl(t,s);let n=WS(e,t);if(!n)return{status:"error",detail:"no nonce"};try{let r=await fetch(`${xt()}/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 zs({...t,last_error:`${new Date().toISOString()} ${i}`}),{status:"error",detail:i}}let o=await r.json().catch(()=>({}));return zs({...t,last_ping_month:s,last_error:null}),{status:o.deduped?"deduped":"sent"}}catch(r){let o=r instanceof Error?r.message:"unknown";return zs({...t,last_error:`${new Date().toISOString()} ${o}`}),{status:"error",detail:o}}}function Nt(e){let s={...bt(),decision:e,decided_at:new Date().toISOString(),last_error:null,...e==="off"?{nonce:null,nonce_month:null,last_ping_month:null}:{}};return zs(s),s}function qs(e){let t=Wl(bt(),zr());return{event:"install",version:e,platform:process.platform,arch:process.arch,month:t.nonce_month??zr(),nonce:t.nonce??"0".repeat(32)}}var JS=XS(import.meta.url);function GS(){for(let e of["../package.json","../../package.json"])try{return JS(e).version}catch{}return"0.0.0"}var zS=GS();async function Yr(){let e=bt();console.log(),console.log(d.bold("Telemetry \u2014 anonymous install ping")),console.log(` ${d.dim("decision:")} ${e.decision??"not yet decided"}`),console.log(` ${d.dim("decided at:")} ${e.decided_at??"\u2014"}`),console.log(` ${d.dim("last ping:")} ${e.last_ping_month??"\u2014"}`),console.log(` ${d.dim("state file:")} ${Hl()}`),e.last_error&&console.log(` ${d.warn("last error:")} ${e.last_error}`),console.log(),console.log(d.dim("Next-ping payload preview (only sent if decision = on):")),console.log(d.dim(JSON.stringify(qs(zS),null,2))),console.log(),console.log(d.dim("Toggle with `recall telemetry on` / `recall telemetry off`.")),console.log(d.dim("Full disclosure: https://clauderecall.com/telemetry")),console.log()}async function Jl(){Nt("on"),console.log(),console.log(d.ok("Telemetry: opted in.")),console.log(d.dim("One anonymous ping per machine per month. No PII. Source: docs/specs/v0.16-install-ping.md")),console.log(d.dim("Reverse with `recall telemetry off`.")),console.log()}async function Gl(){Nt("off"),console.log(),console.log(d.ok("Telemetry: opted out.")),console.log(d.dim("No further pings will be sent. Existing nonce deleted.")),console.log()}async function zl(){await Yr()}import{createInterface as YS}from"node:readline/promises";import{stdin as Yl,stdout as ue}from"node:process";var qS=new Set(["telemetry","trial","upgrade","activate","license","help","version"]);function KS(e){return!(process.env.CI==="true"||process.env.RECALL_QUIET_INSTALL==="1"||process.env.RECALL_DISABLE_TELEMETRY_PROMPT==="1"||!Yl.isTTY||!ue.isTTY||e&&qS.has(e)||bt().decision!==null)}async function ql(e,t){if(!KS(e))return;let s=qs(t);ue.write(`
1652
+ (SELECT COUNT(*) FROM projects) AS projects`).get();return{sessions:t.sessions,projects:t.projects}}catch{return{sessions:0,projects:0}}}function QS(){let e=process.stdout.columns;return typeof e!="number"||e<=0?!1:e<KS+2}function Kl(){if(QS()){console.log(`${ne(VS)} ${O("\xB7")} ${O(Xl)}`);return}for(let e of ql)console.log(ne(e));console.log(O(Xl))}async function eT(){return{daemon:Z(),counts:ZS(),license:await Te()}}function tT(e){let t=[];if(t.push(` ${O("Version:")} ${Ee(`v${GS}`)} ${O("\xB7 CLI \xB7 @clauderecallhq/cli")}`),e.daemon){let s=`http://127.0.0.1:${e.daemon.port}`;t.push(` ${O("Daemon:")} ${Et("running")} on ${s} ${O(`(pid ${e.daemon.pid})`)}`)}else t.push(` ${O("Daemon:")} ${zs("stopped")}`);if(e.counts.sessions===0)t.push(` ${O("Sessions:")} ${zs("none indexed yet")}`);else{let s=e.counts.projects===1?"project":"projects";t.push(` ${O("Sessions:")} ${Ee(String(e.counts.sessions))} indexed across ${Ee(String(e.counts.projects))} ${s}`)}return e.license.tier==="pro"?t.push(` ${O("License:")} ${Et("Pro")}`):t.push(` ${O("License:")} Free`),t}function sT(e){let t=Ee(">");if(e.counts.sessions===0)return`${t} Run ${ne("recall index")} to scan ~/.claude/projects/`;if(!e.daemon)return`${t} Run ${ne("recall start")} to launch the local daemon`;if(e.license.tier==="free")return`${t} Run ${ne("recall upgrade")} to unlock Pro features`;let s=`http://127.0.0.1:${e.daemon.port}`;return`${t} Open ${Ee(s)} in your browser ${O("\xB7")} or run ${ne("recall --help")} for all commands`}var qs=[{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"}]}],nT=qs.reduce((e,t)=>e+t.commands.length,0),rT=new Set([...qs.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 Jl(){let e=qs.flatMap(s=>s.commands.map(n=>`recall ${n.name}`)),t=Math.max(...e.map(s=>s.length));console.log(),console.log(`${zl("COMMANDS")} ${O(`\xB7 ${nT} total \xB7 q to quit \xB7 recall --help for full details`)}`),console.log(` ${O("All commands run as subcommands of")} ${ne("recall")}${O(". There is no separate")} ${Ee("threads")}${O(",")} ${Ee("thread")}${O(", or")} ${Ee("titles")} ${O("binary.")}`);for(let s of qs){console.log(),console.log(` ${ne(s.title.toUpperCase())}`);for(let n of s.commands){let r=`recall ${n.name}`.padEnd(t," ");console.log(` ${Ee(r)} ${O(n.description)}`)}}console.log()}function oT(){return!!process.stdin.isTTY&&!!process.stdout.isTTY}async function iT(){if(!oT())return;let e=HS.createInterface({input:process.stdin,output:process.stdout}),t=`${O("Type")} ${ne("/")} ${O("for commands, or press")} ${ne("Enter")} ${O("to exit")} ${Ee("\u203A")} `;return new Promise(s=>{let n=()=>{e.question(t,r=>{let o=r.trim();if(o==="/"||o==="/help"||o==="help"||o==="?"){Jl(),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===""){Jl(),n();return}let l=(i.split(/\s+/)[0]??"").toLowerCase();rT.has(l)?console.log(` ${O("Run")} ${ne(`recall ${i}`)} ${O("in your shell to invoke that command.")}`):console.log(` ${O(`No command matches "${o}". Type`)} ${ne("/")} ${O("to browse, or")} ${ne("recall --help")} ${O("for the full list.")}`),n()})};e.on("close",()=>{console.log(),s()}),n()})}async function Vl(){let e=await eT();console.log(),Kl(),console.log();for(let t of tT(e))console.log(t);console.log(),console.log(sT(e)),console.log(),await iT()}var aT=[{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 cT(){return process.env.NO_COLOR||process.env.CI||process.env.RECALL_NO_ANIMATION?!1:!!process.stdout.isTTY}function Vr(e){return new Promise(t=>setTimeout(t,e))}function lT(e){let s=(e.split("@")[0]??"").split(/[._+\-]/)[0]??"";return s?s.charAt(0).toUpperCase()+s.slice(1).toLowerCase():""}function Gl(){process.stdout.write("\r\x1B[2K")}async function Zl(e){let t=cT();console.log(),Kl(),console.log(),t&&(process.stdout.write(` ${O("Verifying license...")}`),await Vr(260),Gl()),console.log(` ${Et("\u2713")} ${O("License verified")}`),console.log(` ${Et("\u2713")} ${O("Tier:")} ${ne("Pro")} ${O("\xB7 Lifetime")}`),console.log(` ${Et("\u2713")} ${O("Key:")} ${Ee(e.key_short)}`),console.log(` ${Et("\u2713")} ${O("Email:")} ${e.email}`),e.test_mode&&console.log(` ${zs("!")} ${zs("Test mode:")} this license was issued in test mode.`),console.log(),console.log(` ${zl("Unlocking Pro features")}`),console.log();for(let r of aT)t&&(process.stdout.write(` ${O("\xB7")} ${O(r.name)}`),await Vr(110),Gl()),console.log(` ${Et("\u2713")} ${r.name} ${O(r.detail)}`);t&&await Vr(160),console.log();let s=lT(e.email),n=s?`Welcome aboard, ${s}.`:"Welcome aboard.";console.log(` ${ne(n)}`),console.log(` ${O("Run")} ${Ee("recall")} ${O("to open the dashboard, or")} ${Ee("recall help")} ${O("for the command list.")}`),console.log()}async function Ql(e){let t=e.trim();t.length<8&&(console.error(d.warn("License key looks too short. Paste the full key from your purchase email.")),process.exit(1));let s=`${dT()}-${uT(4).toString("hex")}`,n=`${Rt()}/api/license/activate`,r;try{r=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({license_key:t,instance_name:s,machine_fingerprint:ps()})})}catch(a){let l=a instanceof Error?a.message:"unknown error";console.error(d.warn(`Could not reach activation server at ${n}: ${l}`)),console.error(d.dim("If you are offline, try again when you have a connection.")),process.exit(1)}let o;try{o=await r.json()}catch{console.error(d.warn(`Activation server returned invalid JSON (status ${r.status}).`)),process.exit(1)}if(r.status!==200||!o.license_jwt){let a=o.error??`activation failed (status ${r.status})`;console.error(d.warn(`Activation refused: ${a}`)),process.exit(1)}let i=await ms(o.license_jwt);(!i.valid||!i.claims)&&(console.error(d.warn(`Server returned a JWT that fails local verification: ${i.reason??"unknown"}`)),console.error(d.dim("This usually means the CLI is older than the server, or the public key was rotated.")),process.exit(1)),li({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 Zl({...i.claims,key_short:o.key_short??i.claims.key_short,email:o.customer_email??i.claims.email})}v();import{spawn as mT}from"node:child_process";import{platform as Ks}from"node:os";var ed="https://clauderecall.com/pricing";function pT(e){let t=Ks()==="darwin"?"open":Ks()==="win32"?"start":"xdg-open",s=Ks()==="win32"?["",e]:[e];mT(t,s,{detached:!0,stdio:"ignore",shell:Ks()==="win32"}).unref()}async function td(){let{getLicenseStatus:e}=await Promise.resolve().then(()=>(_e(),_s)),t=await e();if(t.tier==="pro"){console.log(),console.log(d.bold("Already on Pro.")),console.log(` ${d.dim("Key:")} ${t.key_short}`),console.log(` ${d.dim("Email:")} ${t.customer_email}`),console.log();return}console.log(),console.log(`${d.ok("Opening")} ${ed}`),console.log(d.dim("After purchase, run: recall activate <license-key>")),console.log(),pT(ed)}v();import{spawn as gT}from"node:child_process";import{platform as Vs}from"node:os";var sd="https://clauderecall.com/pricing?trial=1&utm_source=cli&utm_medium=recall_trial";function fT(e){let t=Vs()==="darwin"?"open":Vs()==="win32"?"start":"xdg-open",s=Vs()==="win32"?["",e]:[e];gT(t,s,{detached:!0,stdio:"ignore",shell:Vs()==="win32"}).unref()}async function nd(){let{getLicenseStatus:e}=await Promise.resolve().then(()=>(_e(),_s)),t=await e();if(t.tier==="pro"){console.log(),console.log(d.bold("You are already on Pro.")),console.log(` ${d.dim("Key:")} ${t.key_short}`),console.log(` ${d.dim("Email:")} ${t.customer_email}`),console.log();return}console.log(),console.log(`${d.ok("Opening")} ${sd}`),console.log(d.dim("Enter your email to get a 7-day Pro trial link. No card.")),console.log(d.dim("After you click the verification email, run: recall activate <key>")),console.log(),fT(sd)}v();gs();import{existsSync as rd,mkdirSync as _T,readFileSync as hT,writeFileSync as ET}from"node:fs";import{homedir as bT}from"node:os";import{join as od}from"node:path";import{randomBytes as ST}from"node:crypto";var Qr=od(bT(),".recall"),Qs=od(Qr,"telemetry.json"),Zr={decided_at:null,decision:null,last_ping_month:null,nonce_month:null,nonce:null,last_error:null};function bt(){if(!rd(Qs))return{...Zr};try{let e=hT(Qs,"utf8"),t=JSON.parse(e);return{...Zr,...t}}catch{return{...Zr}}}function Zs(e){rd(Qr)||_T(Qr,{recursive:!0}),ET(Qs,JSON.stringify(e,null,2)+`
1653
+ `,{mode:384})}function id(){return Qs}function eo(e=new Date){let t=e.getUTCFullYear(),s=String(e.getUTCMonth()+1).padStart(2,"0");return`${t}-${s}`}function ad(e,t){return e.nonce&&e.nonce_month===t?e:{...e,nonce:ST(16).toString("hex"),nonce_month:t}}function TT(e,t){return!t.nonce||!t.nonce_month?null:{event:"install",version:e,platform:process.platform,arch:process.arch,month:t.nonce_month,nonce:t.nonce}}async function cd(e){let t=bt();if(t.decision!=="on")return{status:t.decision==="off"?"opted-out":"no-decision"};let s=eo();if(t.last_ping_month===s)return{status:"already-this-month"};t=ad(t,s);let n=TT(e,t);if(!n)return{status:"error",detail:"no nonce"};try{let r=await fetch(`${Rt()}/api/install-ping`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n),signal:AbortSignal.timeout(5e3)});if(!r.ok){let i=`http ${r.status}`;return Zs({...t,last_error:`${new Date().toISOString()} ${i}`}),{status:"error",detail:i}}let o=await r.json().catch(()=>({}));return Zs({...t,last_ping_month:s,last_error:null}),{status:o.deduped?"deduped":"sent"}}catch(r){let o=r instanceof Error?r.message:"unknown";return Zs({...t,last_error:`${new Date().toISOString()} ${o}`}),{status:"error",detail:o}}}function Nt(e){let s={...bt(),decision:e,decided_at:new Date().toISOString(),last_error:null,...e==="off"?{nonce:null,nonce_month:null,last_ping_month:null}:{}};return Zs(s),s}function en(e){let t=ad(bt(),eo());return{event:"install",version:e,platform:process.platform,arch:process.arch,month:t.nonce_month??eo(),nonce:t.nonce??"0".repeat(32)}}async function to(e){let t=bt();console.log(),console.log(d.bold("Telemetry \u2014 anonymous install ping")),console.log(` ${d.dim("decision:")} ${t.decision??"not yet decided"}`),console.log(` ${d.dim("decided at:")} ${t.decided_at??"\u2014"}`),console.log(` ${d.dim("last ping:")} ${t.last_ping_month??"\u2014"}`),console.log(` ${d.dim("state file:")} ${id()}`),t.last_error&&console.log(` ${d.warn("last error:")} ${t.last_error}`),console.log(),console.log(d.dim("Next-ping payload preview (only sent if decision = on):")),console.log(d.dim(JSON.stringify(en(e),null,2))),console.log(),console.log(d.dim("Toggle with `recall telemetry on` / `recall telemetry off`.")),console.log(d.dim("Full disclosure: https://clauderecall.com/telemetry")),console.log()}async function ld(){Nt("on"),console.log(),console.log(d.ok("Telemetry: opted in.")),console.log(d.dim("One anonymous ping per machine per month. No PII. Source: docs/specs/v0.16-install-ping.md")),console.log(d.dim("Reverse with `recall telemetry off`.")),console.log()}async function dd(){Nt("off"),console.log(),console.log(d.ok("Telemetry: opted out.")),console.log(d.dim("No further pings will be sent. Existing nonce deleted.")),console.log()}async function ud(e){await to(e)}import{createInterface as yT}from"node:readline/promises";import{stdin as md,stdout as ue}from"node:process";var wT=new Set(["telemetry","trial","upgrade","activate","license","help","version"]);function RT(e){return!(process.env.CI==="true"||process.env.RECALL_QUIET_INSTALL==="1"||process.env.RECALL_DISABLE_TELEMETRY_PROMPT==="1"||!md.isTTY||!ue.isTTY||e&&wT.has(e)||bt().decision!==null)}async function pd(e,t){if(!RT(e))return;let s=en(t);ue.write(`
1553
1654
  `),ue.write(` Claude Recall \u2014 anonymous install ping?
1554
1655
 
1555
1656
  `),ue.write(` npm download counts mix real installs with bots and scanners.
@@ -1565,54 +1666,54 @@ Toggle with: recall verify on | off
1565
1666
 
1566
1667
  `),ue.write(` Full disclosure: https://clauderecall.com/telemetry
1567
1668
 
1568
- `);let n=YS({input:Yl,output:ue}),r;try{r=(await n.question(" Send the install ping? [y/N]: ")).trim().toLowerCase()}finally{n.close()}r==="y"||r==="yes"?(Nt("on"),ue.write(`
1669
+ `);let n=yT({input:md,output:ue}),r;try{r=(await n.question(" Send the install ping? [y/N]: ")).trim().toLowerCase()}finally{n.close()}r==="y"||r==="yes"?(Nt("on"),ue.write(`
1569
1670
  Opted in. Reverse any time with \`recall telemetry off\`.
1570
1671
 
1571
1672
  `)):(Nt("off"),ue.write(`
1572
1673
  Opted out. No pings will be sent. Reverse with \`recall telemetry on\`.
1573
1674
 
1574
- `))}I();_e();Pt();$n();async function Kl(){let e=await ye();if(console.log(),e.tier==="free"){console.log(d.bold("Tier: Free")),console.log(d.dim("Free includes: index, list, show, projects, status, the daemon, and the basic web UI.")),e.invalid_reason&&(console.log(),console.log(d.warn(`Stored license is invalid: ${e.invalid_reason}`))),console.log(),console.log("Buy Pro at https://clauderecall.com/pricing"),console.log("Then run: recall activate <license-key>"),console.log();return}console.log(d.bold("Tier: Pro")),console.log(` ${d.dim("Key:")} ${e.key_short}`),console.log(` ${d.dim("Email:")} ${e.customer_email}`),console.log(` ${d.dim("Activated:")} ${e.activated_at}`),e.expires_at&&console.log(` ${d.dim("Expires:")} ${e.expires_at}`),e.test_mode&&console.log(` ${d.warn("Test mode:")} this license was issued in test mode.`);let t=ms();t&&console.log(` ${d.dim("Last server check:")} ${t.last_checked_at}`),console.log()}async function Vl(){let e=await Bn({force:!0});if(console.log(),!e.ran){console.log(d.warn("No license stored on this machine.")),console.log(d.dim("Run `recall activate <license-key>` first.")),console.log();return}if(!e.last_checked_at){console.log(d.warn("Could not reach the license server.")),console.log(d.dim("Network error. Try again when you have a connection.")),console.log();return}if(e.revoked){console.log(d.warn("License is revoked.")),e.reason&&console.log(` ${d.dim("Reason:")} ${e.reason}`),console.log(` ${d.dim("Checked:")} ${e.last_checked_at}`),console.log();return}console.log(d.ok("License is valid.")),console.log(` ${d.dim("Checked:")} ${e.last_checked_at}`),console.log()}function Zl(){ri(),console.log(),console.log("License removed from this machine."),console.log(d.dim(`(${pt})`)),console.log()}T();I();import VS from"cli-table3";function ve(e){let t=_();if(e.length>=32){let n=t.prepare("SELECT id FROM threads WHERE id = ?").get(e);return n?n.id:(process.stderr.write(`thread not found: ${e}
1675
+ `))}v();_e();Pt();Un();async function gd(){let e=await Te();if(console.log(),e.tier==="free"){console.log(d.bold("Tier: Free")),console.log(d.dim("Free includes: index, list, show, projects, status, the daemon, and the basic web UI.")),e.invalid_reason&&(console.log(),console.log(d.warn(`Stored license is invalid: ${e.invalid_reason}`))),console.log(),console.log("Buy Pro at https://clauderecall.com/pricing"),console.log("Then run: recall activate <license-key>"),console.log();return}console.log(d.bold("Tier: Pro")),console.log(` ${d.dim("Key:")} ${e.key_short}`),console.log(` ${d.dim("Email:")} ${e.customer_email}`),console.log(` ${d.dim("Activated:")} ${e.activated_at}`),e.expires_at&&console.log(` ${d.dim("Expires:")} ${e.expires_at}`),e.test_mode&&console.log(` ${d.warn("Test mode:")} this license was issued in test mode.`);let t=fs();t&&console.log(` ${d.dim("Last server check:")} ${t.last_checked_at}`),console.log()}async function fd(){let e=await Gn({force:!0});if(console.log(),!e.ran){console.log(d.warn("No license stored on this machine.")),console.log(d.dim("Run `recall activate <license-key>` first.")),console.log();return}if(!e.last_checked_at){console.log(d.warn("Could not reach the license server.")),console.log(d.dim("Network error. Try again when you have a connection.")),console.log();return}if(e.revoked){console.log(d.warn("License is revoked.")),e.reason&&console.log(` ${d.dim("Reason:")} ${e.reason}`),console.log(` ${d.dim("Checked:")} ${e.last_checked_at}`),console.log();return}console.log(d.ok("License is valid.")),console.log(` ${d.dim("Checked:")} ${e.last_checked_at}`),console.log()}function _d(){di(),console.log(),console.log("License removed from this machine."),console.log(d.dim(`(${mt})`)),console.log()}w();v();import xT 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}
1575
1676
  `),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}"
1576
1677
  `),null;process.stderr.write(`ambiguous thread prefix "${e}" \u2014 candidates:
1577
1678
  `);for(let n of s)process.stderr.write(` ${H(n.id)} ${n.name}
1578
1679
  `);return null}function St(e){let t=_();if(e.length>=32){let n=t.prepare("SELECT id FROM sessions WHERE id = ?").get(e);return n?n.id:(process.stderr.write(`session not found: ${e}
1579
1680
  `),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}"
1580
1681
  `),null):(process.stderr.write(`ambiguous session prefix "${e}". be more specific.
1581
- `),null)}function ZS(e){let t=new Map;if(e.length===0)return t;let s=e.map(()=>"?").join(","),r=_().prepare(`SELECT s.id,
1682
+ `),null)}function kT(e){let t=new Map;if(e.length===0)return t;let s=e.map(()=>"?").join(","),r=_().prepare(`SELECT s.id,
1582
1683
  s.first_user_message,
1583
1684
  p.name AS project_name,
1584
1685
  a.alias AS alias
1585
1686
  FROM sessions s
1586
1687
  LEFT JOIN projects p ON p.id = s.project_id
1587
1688
  LEFT JOIN session_aliases a ON a.session_id = s.id
1588
- WHERE s.id IN (${s})`).all(...e);for(let o of r)t.set(o.id,o);return t}function Ql(e,t){let s=t.get(e),n=d.accent(H(e));if(!s)return`${n} ${d.dim("(unindexed)")}`;let r=s.alias??s.first_user_message??"",o=s.project_name?d.project(`[${s.project_name}] `):"";return`${n} ${o}${Y(r,80)}`}function qr(e){return e.archived?"archived":e.closed_at?"closed":"open"}function Ct(e){let t=qr(e);process.stderr.write(d.ok(`\u2713 ${e.name} ${d.dim(`(${H(e.id)})`)} [${t}]
1589
- `))}function xe(e,t,s){if(e){process.stdout.write(JSON.stringify(t,null,2)+`
1590
- `);return}s()}function ed(e){let t=zn({includeArchived:e.archived===!0});xe(e.json===!0,t,()=>{if(t.length===0){console.log(d.dim("no threads. create one with `recall thread new <name>`."));return}let s=new VS({head:[d.bold("id"),d.bold("name"),d.bold("sessions"),d.bold("origins"),d.bold("status"),d.bold("created")],colWidths:[10,40,10,9,10,16],wordWrap:!0,style:{head:[],border:["grey"]}});for(let n of t)s.push([d.accent(H(n.id)),Y(n.name,38),String(n.session_count),String(n.origin_count),qr(n),d.dim(W(n.created_at))]);console.log(s.toString()),console.log(d.dim(`${t.length} thread${t.length===1?"":"s"}.`+(e.archived?"":" add --archived to include archived.")))})}function QS(e,t){let s=new Set(e.edges.map(a=>a.session_id)),n=new Map,r=[];for(let a of e.edges){let l=a.parent_session_id;if(a.role==="origin"||!l||!s.has(l)){r.push(a);continue}let c=n.get(l)??[];c.push(a),n.set(l,c)}let o=new Set,i=(a,l,c,u)=>{if(o.has(a.session_id))return;o.add(a.session_id);let p=u?"":c?"\u2514\u2500 ":"\u251C\u2500 ",m=a.role==="origin"?d.warn("[origin] "):"";process.stdout.write(`${l}${p}${m}${Ql(a.session_id,t)}
1591
- `);let f=n.get(a.session_id)??[],g=u?"":l+(c?" ":"\u2502 ");f.forEach((h,E)=>{i(h,g,E===f.length-1,!1)})};r.forEach((a,l)=>i(a,"",l===r.length-1,!0));for(let a of e.edges)o.has(a.session_id)||process.stdout.write(`${d.warn("? ")}${Ql(a.session_id,t)}
1592
- `)}function td(e,t){let s=ve(e);if(!s){process.exitCode=1;return}let n=Oe(s);if(!n){process.stderr.write(`thread not found: ${e}
1593
- `),process.exitCode=1;return}let r=ZS(n.edges.map(o=>o.session_id));xe(t.json===!0,n,()=>{let o=qr(n);if(console.log(d.bold(n.name)),console.log(d.dim(`id ${H(n.id)} \xB7 ${o} \xB7 ${n.session_count} session${n.session_count===1?"":"s"} \xB7 ${n.origin_count} origin${n.origin_count===1?"":"s"} \xB7 created ${W(n.created_at)}`)),n.summary&&console.log(n.summary),console.log(),n.edges.length===0){console.log(d.dim("(no sessions linked \u2014 use `recall thread link ...`)"));return}QS(n,r)})}function sd(e,t){let s;if(t.origin){let r=St(t.origin);if(!r){process.exitCode=1;return}s=r}let n=Ii({name:e,summary:t.summary??null,originSessionId:s});xe(t.json===!0,n,()=>{Ct(n),process.stderr.write(d.dim(`id ${n.id}
1689
+ WHERE s.id IN (${s})`).all(...e);for(let o of r)t.set(o.id,o);return t}function hd(e,t){let s=t.get(e),n=d.accent(H(e));if(!s)return`${n} ${d.dim("(unindexed)")}`;let r=s.alias??s.first_user_message??"",o=s.project_name?d.project(`[${s.project_name}] `):"";return`${n} ${o}${z(r,80)}`}function so(e){return e.archived?"archived":e.closed_at?"closed":"open"}function Lt(e){let t=so(e);process.stderr.write(d.ok(`\u2713 ${e.name} ${d.dim(`(${H(e.id)})`)} [${t}]
1690
+ `))}function Re(e,t,s){if(e){process.stdout.write(JSON.stringify(t,null,2)+`
1691
+ `);return}s()}function Ed(e){let t=Zn({includeArchived:e.archived===!0});Re(e.json===!0,t,()=>{if(t.length===0){console.log(d.dim("no threads. create one with `recall thread new <name>`."));return}let s=new xT({head:[d.bold("id"),d.bold("name"),d.bold("sessions"),d.bold("origins"),d.bold("status"),d.bold("created")],colWidths:[10,40,10,9,10,16],wordWrap:!0,style:{head:[],border:["grey"]}});for(let n of t)s.push([d.accent(H(n.id)),z(n.name,38),String(n.session_count),String(n.origin_count),so(n),d.dim(W(n.created_at))]);console.log(s.toString()),console.log(d.dim(`${t.length} thread${t.length===1?"":"s"}.`+(e.archived?"":" add --archived to include archived.")))})}function NT(e,t){let s=new Set(e.edges.map(a=>a.session_id)),n=new Map,r=[];for(let a of e.edges){let l=a.parent_session_id;if(a.role==="origin"||!l||!s.has(l)){r.push(a);continue}let c=n.get(l)??[];c.push(a),n.set(l,c)}let o=new Set,i=(a,l,c,u)=>{if(o.has(a.session_id))return;o.add(a.session_id);let m=u?"":c?"\u2514\u2500 ":"\u251C\u2500 ",p=a.role==="origin"?d.warn("[origin] "):"";process.stdout.write(`${l}${m}${p}${hd(a.session_id,t)}
1692
+ `);let f=n.get(a.session_id)??[],g=u?"":l+(c?" ":"\u2502 ");f.forEach((h,E)=>{i(h,g,E===f.length-1,!1)})};r.forEach((a,l)=>i(a,"",l===r.length-1,!0));for(let a of e.edges)o.has(a.session_id)||process.stdout.write(`${d.warn("? ")}${hd(a.session_id,t)}
1693
+ `)}function bd(e,t){let s=Me(e);if(!s){process.exitCode=1;return}let n=Oe(s);if(!n){process.stderr.write(`thread not found: ${e}
1694
+ `),process.exitCode=1;return}let r=kT(n.edges.map(o=>o.session_id));Re(t.json===!0,n,()=>{let o=so(n);if(console.log(d.bold(n.name)),console.log(d.dim(`id ${H(n.id)} \xB7 ${o} \xB7 ${n.session_count} session${n.session_count===1?"":"s"} \xB7 ${n.origin_count} origin${n.origin_count===1?"":"s"} \xB7 created ${W(n.created_at)}`)),n.summary&&console.log(n.summary),console.log(),n.edges.length===0){console.log(d.dim("(no sessions linked \u2014 use `recall thread link ...`)"));return}NT(n,r)})}function Sd(e,t){let s;if(t.origin){let r=St(t.origin);if(!r){process.exitCode=1;return}s=r}let n=Fi({name:e,summary:t.summary??null,originSessionId:s});Re(t.json===!0,n,()=>{Lt(n),process.stderr.write(d.dim(`id ${n.id}
1594
1695
  `)),s&&process.stderr.write(d.dim(`origin: ${H(s)}
1595
- `))})}function nd(e,t){let s=ve(t.thread);if(!s){process.exitCode=1;return}let n=St(e);if(!n){process.exitCode=1;return}let r=null;if(t.parent){let a=St(t.parent);if(!a){process.exitCode=1;return}r=a}let o=t.role??(r?"child":"origin"),i=vi({threadId:s,sessionId:n,parentSessionId:r,role:o});xe(t.json===!0,i,()=>{process.stderr.write(d.ok(`\u2713 linked ${H(n)} \u2192 ${H(s)} [${o}]
1596
- `))})}function rd(e,t){let s=ve(t.thread);if(!s){process.exitCode=1;return}let n=St(e);if(!n){process.exitCode=1;return}let r=Mi(s,n);xe(t.json===!0,r,()=>{if(r.removed===0){process.stderr.write(d.warn(`(no edge existed for ${H(n)} in ${H(s)})
1696
+ `))})}function Td(e,t){let s=Me(t.thread);if(!s){process.exitCode=1;return}let n=St(e);if(!n){process.exitCode=1;return}let r=null;if(t.parent){let a=St(t.parent);if(!a){process.exitCode=1;return}r=a}let o=t.role??(r?"child":"origin"),i=Ui({threadId:s,sessionId:n,parentSessionId:r,role:o});Re(t.json===!0,i,()=>{process.stderr.write(d.ok(`\u2713 linked ${H(n)} \u2192 ${H(s)} [${o}]
1697
+ `))})}function yd(e,t){let s=Me(t.thread);if(!s){process.exitCode=1;return}let n=St(e);if(!n){process.exitCode=1;return}let r=Bi(s,n);Re(t.json===!0,r,()=>{if(r.removed===0){process.stderr.write(d.warn(`(no edge existed for ${H(n)} in ${H(s)})
1597
1698
  `));return}process.stderr.write(d.ok(`\u2713 unlinked ${H(n)} from ${H(s)}
1598
- `))})}function od(e,t){let s=ve(t.thread);if(!s){process.exitCode=1;return}let n=St(e);if(!n){process.exitCode=1;return}let r=null;if(t.parent&&t.parent.toLowerCase()!=="none"){let i=St(t.parent);if(!i){process.exitCode=1;return}r=i}let o=$i(s,n,r);xe(t.json===!0,o,()=>{process.stderr.write(d.ok(`\u2713 ${H(n)} in ${H(s)} \u2192 `+(r?`child of ${H(r)}`:"origin")+`
1599
- `))})}function id(e,t,s){let n=ve(e);if(!n){process.exitCode=1;return}let r=Di(n,t);xe(s.json===!0,r,()=>Ct(r))}function ad(e,t){let s=ve(e);if(!s){process.exitCode=1;return}let n=ji(s);xe(t.json===!0,n,()=>Ct(n))}function cd(e,t){let s=ve(e);if(!s){process.exitCode=1;return}let n=Pi(s);xe(t.json===!0,n,()=>Ct(n))}function ld(e,t){let s=ve(e);if(!s){process.exitCode=1;return}let n=Fi(s);xe(t.json===!0,n,()=>Ct(n))}function dd(e,t){let s=ve(e);if(!s){process.exitCode=1;return}let n=ve(t.into);if(!n){process.exitCode=1;return}if(s===n){process.stderr.write(d.err(`cannot merge a thread into itself
1600
- `)),process.exitCode=1;return}let r=Ui(s,n);xe(t.json===!0,r,()=>{process.stderr.write(d.ok(`\u2713 merged ${H(s)} \u2192 ${H(n)} (${r.session_count} sessions)
1601
- `))})}function ud(e,t){let s=ve(e);if(!s){process.exitCode=1;return}let n=t.sessions.split(",").map(i=>i.trim()).filter(Boolean);if(n.length===0){process.stderr.write(d.err(`--sessions must be a non-empty comma-separated list
1602
- `)),process.exitCode=1;return}let r=[];for(let i of n){let a=St(i);if(!a){process.exitCode=1;return}r.push(a)}let o=Bi({threadId:s,sessionIds:r,newThreadName:t.name});xe(t.json===!0,o,()=>{Ct(o),process.stderr.write(d.dim(`split off ${r.length} session${r.length===1?"":"s"} from ${H(s)}
1603
- `))})}T();I();import{randomUUID as Ty}from"node:crypto";import{readFileSync as ey,statSync as ty}from"node:fs";var sy=200*1024*1024,Vr=.7,Zr=.5,gd=Zr,ny=[{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"}],ry=["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 pd(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 oy(e,t){let s=t-e;if(s<0)return{weight:0,label:null};for(let n of ny)if(s<=n.maxGapMs)return{weight:n.weight,label:n.label};return{weight:0,label:null}}function iy(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 ry)if(o.includes(i))return{weight:t[n],matched:i,matchedIndex:n}}return{weight:0,matched:null,matchedIndex:-1}}function Kr(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 ay(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=Kr(n,r);o>s&&(s=o)}return s}function cy(e,t){let s=Kr(e.mean_embedding,t.mean_embedding),n=Kr(e.tail_pool,t.head_pool),r=ay(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 ly(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 dy(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 uy(e,t){let s=pd(e),n=pd(t);return s&&n&&s===n?{weight:.1,brand:s}:{weight:0,brand:null}}function md(e){return e.replace(/\s+/g," ").trim().toLowerCase()}function py(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(`
1604
- `).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=md(t.recent_user_messages[0]);if(o.length>=200)for(let i of e.authored_content){let a=md(i);if(a.length<200)continue;let l=Math.min(a.length,240),c=a.slice(0,l);if(o.includes(c)){s+=.4,r=!0;break}}}return{weight:Math.min(.6,s),pathMatch:n,contentMatch:r}}function my(e,t,s=gd){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=oy(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=iy(o),a=dy(e.touched_files,t.touched_files),l=uy(e.auto_title,t.auto_title),c=cy(e,t),u=ly(e,t),p=py(e,t),m=r.weight+i.weight+a.weight+l.weight+c.weight+u.weight+p.weight;if(m<s)return null;let f=[];if(r.label&&f.push(`temporal ${r.label} (+${r.weight})`),i.matched){let g=i.matchedIndex===0?"opening message":`message #${i.matchedIndex+1}`;f.push(`continuation phrase "${i.matched}" in ${g} (+${i.weight})`)}if(a.count>0&&f.push(`${a.count} file${a.count===1?"":"s"} overlap (+${a.weight.toFixed(1)})`),l.brand&&f.push(`shared brand "${l.brand}" (+${l.weight})`),c.weight>0&&c.mode&&f.push(`semantic ${c.mode==="asymmetric"?"tail\u2192head":c.mode==="max_pool"?"best-chunk":"mean"} ${c.cosine.toFixed(2)} (+${c.weight.toFixed(2)})`),u.same&&f.push(`same cluster (+${u.weight})`),p.weight>0){let g=[];p.pathMatch&&g.push(`opened authored path "${p.pathMatch.split("/").pop()}"`),p.contentMatch&&g.push("verbatim-paste of authored content"),f.push(`doc-authorship: ${g.join(" + ")} (+${p.weight.toFixed(2)})`)}return{parent_id:e.id,child_id:t.id,confidence:Math.min(1,m),signals:{temporal:r.weight,continuation:i.weight,file_overlap:a.weight,same_brand:l.weight,semantic:c.weight,cluster:u.weight,doc_authorship:p.weight},reasons:f}}function fd(e,t=gd){let s=[];for(let n=0;n<e.length;n++){let r=e[n],o=null;for(let i=0;i<n;i++){let a=e[i],l=my(a,r,t);l&&(!o||l.confidence>o.confidence)&&(o=l)}o&&s.push(o)}return s}function _d(e,t){let s=new Map,n=a=>{let l=a;for(;s.get(l)!==l;)l=s.get(l);let c=a;for(;s.get(c)!==l;){let u=s.get(c);s.set(c,l),c=u}return l},r=(a,l)=>{let c=n(a),u=n(l);c!==u&&s.set(c,u)};for(let a of e)s.has(a.parent_id)||s.set(a.parent_id,a.parent_id),s.has(a.child_id)||s.set(a.child_id,a.child_id),r(a.parent_id,a.child_id);let o=new Map;for(let a of s.keys()){let l=n(a),c=o.get(l);c||(c=[],o.set(l,c)),c.push(a)}let i=new Map;for(let a of t)i.set(a.id,a.started_at_ms);return Array.from(o.values()).map(a=>(a.sort((l,c)=>(i.get(l)??0)-(i.get(c)??0)),{rootId:a[0],sessionIds:a}))}function hd(e,t={}){let s=t.maxUserMessages??5,n=t.userMessageMaxLen??2e3,r=new Set,o=[],i=new Set,a=[],l;try{if(ty(e).size>sy)return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a};l=ey(e,"utf8")}catch{return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a}}let c=0;for(;c<l.length;){let u=l.indexOf(`
1605
- `,c),p=u===-1?l.length:u,m=l.slice(c,p);if(c=u===-1?l.length:u+1,!m.trim())continue;let f;try{f=JSON.parse(m)}catch{continue}let g=f;if(g.type==="user"&&g.message?.role==="user"&&typeof g.message.content=="string"&&o.length<s){let E=g.message.content.trim();E&&o.push(E.length>n?E.slice(0,n):E)}let h=g.message?.content;if(Array.isArray(h))for(let E of h){if(!E||typeof E!="object")continue;let b=E;if(b.type!=="tool_use")continue;let S=b.input??{},C=typeof S.file_path=="string"?S.file_path:null;if(C){let R=Ks(C);R&&r.add(R)}if((b.name==="Write"||b.name==="Edit"||b.name==="MultiEdit")&&C){let R=Ks(C);R&&i.add(R);let L=typeof S.content=="string"?S.content:typeof S.new_string=="string"?S.new_string:null;L&&L.length>=200&&a.push(L.length>4096?L.slice(0,4096):L)}if(b.name==="Bash"&&typeof S.command=="string")for(let R of S.command.matchAll(/(?:^|[\s'"`(=])((?:\.\.?\/|\/|src\/|test\/|docs\/|site\/)[A-Za-z0-9_./-]+)/g)){let L=Ks(R[1]);L&&r.add(L)}if((b.name==="Glob"||b.name==="Grep")&&typeof S.pattern=="string"){let R=Ks(S.pattern);R&&!R.includes("*")&&r.add(R)}}}return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a}}function Ks(e){let t=e.trim().replace(/^['"]|['"]$/g,"");return!t||t.length<4||/[<>|;&\$`]/.test(t)?null:t}T();var Ed=10,bd=20;function gy(e){if(!e)return!1;let t=e.split(`
1606
- `);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 fy(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 Sd(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 Qr(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 Sd(s)?s:null}function yd(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,
1699
+ `))})}function wd(e,t){let s=Me(t.thread);if(!s){process.exitCode=1;return}let n=St(e);if(!n){process.exitCode=1;return}let r=null;if(t.parent&&t.parent.toLowerCase()!=="none"){let i=St(t.parent);if(!i){process.exitCode=1;return}r=i}let o=Hi(s,n,r);Re(t.json===!0,o,()=>{process.stderr.write(d.ok(`\u2713 ${H(n)} in ${H(s)} \u2192 `+(r?`child of ${H(r)}`:"origin")+`
1700
+ `))})}function Rd(e,t,s){let n=Me(e);if(!n){process.exitCode=1;return}let r=Wi(n,t);Re(s.json===!0,r,()=>Lt(r))}function xd(e,t){let s=Me(e);if(!s){process.exitCode=1;return}let n=Xi(s);Re(t.json===!0,n,()=>Lt(n))}function kd(e,t){let s=Me(e);if(!s){process.exitCode=1;return}let n=Ji(s);Re(t.json===!0,n,()=>Lt(n))}function Nd(e,t){let s=Me(e);if(!s){process.exitCode=1;return}let n=Gi(s);Re(t.json===!0,n,()=>Lt(n))}function Ld(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(d.err(`cannot merge a thread into itself
1701
+ `)),process.exitCode=1;return}let r=Yi(s,n);Re(t.json===!0,r,()=>{process.stderr.write(d.ok(`\u2713 merged ${H(s)} \u2192 ${H(n)} (${r.session_count} sessions)
1702
+ `))})}function Cd(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(d.err(`--sessions must be a non-empty comma-separated list
1703
+ `)),process.exitCode=1;return}let r=[];for(let i of n){let a=St(i);if(!a){process.exitCode=1;return}r.push(a)}let o=zi({threadId:s,sessionIds:r,newThreadName:t.name});Re(t.json===!0,o,()=>{Lt(o),process.stderr.write(d.dim(`split off ${r.length} session${r.length===1?"":"s"} from ${H(s)}
1704
+ `))})}w();v();import{randomUUID as KT}from"node:crypto";import{readFileSync as LT,statSync as CT}from"node:fs";var AT=200*1024*1024,ro=.7,oo=.5,vd=oo,OT=[{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"}],vT=["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 Ad(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 IT(e,t){let s=t-e;if(s<0)return{weight:0,label:null};for(let n of OT)if(s<=n.maxGapMs)return{weight:n.weight,label:n.label};return{weight:0,label:null}}function MT(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 vT)if(o.includes(i))return{weight:t[n],matched:i,matchedIndex:n}}return{weight:0,matched:null,matchedIndex:-1}}function no(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 DT(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=no(n,r);o>s&&(s=o)}return s}function $T(e,t){let s=no(e.mean_embedding,t.mean_embedding),n=no(e.tail_pool,t.head_pool),r=DT(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 jT(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 PT(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 FT(e,t){let s=Ad(e),n=Ad(t);return s&&n&&s===n?{weight:.1,brand:s}:{weight:0,brand:null}}function Od(e){return e.replace(/\s+/g," ").trim().toLowerCase()}function UT(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(`
1705
+ `).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=Od(t.recent_user_messages[0]);if(o.length>=200)for(let i of e.authored_content){let a=Od(i);if(a.length<200)continue;let l=Math.min(a.length,240),c=a.slice(0,l);if(o.includes(c)){s+=.4,r=!0;break}}}return{weight:Math.min(.6,s),pathMatch:n,contentMatch:r}}function BT(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=IT(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=MT(o),a=PT(e.touched_files,t.touched_files),l=FT(e.auto_title,t.auto_title),c=$T(e,t),u=jT(e,t),m=UT(e,t),p=r.weight+i.weight+a.weight+l.weight+c.weight+u.weight+m.weight;if(p<s)return null;let f=[];if(r.label&&f.push(`temporal ${r.label} (+${r.weight})`),i.matched){let g=i.matchedIndex===0?"opening message":`message #${i.matchedIndex+1}`;f.push(`continuation phrase "${i.matched}" in ${g} (+${i.weight})`)}if(a.count>0&&f.push(`${a.count} file${a.count===1?"":"s"} overlap (+${a.weight.toFixed(1)})`),l.brand&&f.push(`shared brand "${l.brand}" (+${l.weight})`),c.weight>0&&c.mode&&f.push(`semantic ${c.mode==="asymmetric"?"tail\u2192head":c.mode==="max_pool"?"best-chunk":"mean"} ${c.cosine.toFixed(2)} (+${c.weight.toFixed(2)})`),u.same&&f.push(`same cluster (+${u.weight})`),m.weight>0){let g=[];m.pathMatch&&g.push(`opened authored path "${m.pathMatch.split("/").pop()}"`),m.contentMatch&&g.push("verbatim-paste of authored content"),f.push(`doc-authorship: ${g.join(" + ")} (+${m.weight.toFixed(2)})`)}return{parent_id:e.id,child_id:t.id,confidence:Math.min(1,p),signals:{temporal:r.weight,continuation:i.weight,file_overlap:a.weight,same_brand:l.weight,semantic:c.weight,cluster:u.weight,doc_authorship:m.weight},reasons:f}}function Id(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],l=BT(a,r,t);l&&(!o||l.confidence>o.confidence)&&(o=l)}o&&s.push(o)}return s}function Md(e,t){let s=new Map,n=a=>{let l=a;for(;s.get(l)!==l;)l=s.get(l);let c=a;for(;s.get(c)!==l;){let u=s.get(c);s.set(c,l),c=u}return l},r=(a,l)=>{let c=n(a),u=n(l);c!==u&&s.set(c,u)};for(let a of e)s.has(a.parent_id)||s.set(a.parent_id,a.parent_id),s.has(a.child_id)||s.set(a.child_id,a.child_id),r(a.parent_id,a.child_id);let o=new Map;for(let a of s.keys()){let l=n(a),c=o.get(l);c||(c=[],o.set(l,c)),c.push(a)}let i=new Map;for(let a of t)i.set(a.id,a.started_at_ms);return Array.from(o.values()).map(a=>(a.sort((l,c)=>(i.get(l)??0)-(i.get(c)??0)),{rootId:a[0],sessionIds:a}))}function Dd(e,t={}){let s=t.maxUserMessages??5,n=t.userMessageMaxLen??2e3,r=new Set,o=[],i=new Set,a=[],l;try{if(CT(e).size>AT)return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a};l=LT(e,"utf8")}catch{return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a}}let c=0;for(;c<l.length;){let u=l.indexOf(`
1706
+ `,c),m=u===-1?l.length:u,p=l.slice(c,m);if(c=u===-1?l.length:u+1,!p.trim())continue;let f;try{f=JSON.parse(p)}catch{continue}let g=f;if(g.type==="user"&&g.message?.role==="user"&&typeof g.message.content=="string"&&o.length<s){let E=g.message.content.trim();E&&o.push(E.length>n?E.slice(0,n):E)}let h=g.message?.content;if(Array.isArray(h))for(let E of h){if(!E||typeof E!="object")continue;let b=E;if(b.type!=="tool_use")continue;let S=b.input??{},N=typeof S.file_path=="string"?S.file_path:null;if(N){let y=tn(N);y&&r.add(y)}if((b.name==="Write"||b.name==="Edit"||b.name==="MultiEdit")&&N){let y=tn(N);y&&i.add(y);let C=typeof S.content=="string"?S.content:typeof S.new_string=="string"?S.new_string:null;C&&C.length>=200&&a.push(C.length>4096?C.slice(0,4096):C)}if(b.name==="Bash"&&typeof S.command=="string")for(let y of S.command.matchAll(/(?:^|[\s'"`(=])((?:\.\.?\/|\/|src\/|test\/|docs\/|site\/)[A-Za-z0-9_./-]+)/g)){let C=tn(y[1]);C&&r.add(C)}if((b.name==="Glob"||b.name==="Grep")&&typeof S.pattern=="string"){let y=tn(S.pattern);y&&!y.includes("*")&&r.add(y)}}}return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a}}function tn(e){let t=e.trim().replace(/^['"]|['"]$/g,"");return!t||t.length<4||/[<>|;&\$`]/.test(t)?null:t}w();var $d=10,jd=20;function HT(e){if(!e)return!1;let t=e.split(`
1707
+ `);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 WT(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 Pd(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 io(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 Pd(s)?s:null}function Fd(e){let t=new Map;if(e.length===0)return t;let s=_(),n=e.map(()=>"?").join(","),r=[];try{r=s.prepare(`SELECT cm.rowid AS rowid, cm.session_id AS session_id,
1607
1708
  cm.text AS text, v.embedding AS embedding
1608
1709
  FROM chunk_meta cm
1609
1710
  JOIN vec_chunks v ON v.rowid = cm.rowid
1610
1711
  WHERE cm.stale = 0
1611
1712
  AND cm.session_id IN (${n})
1612
- ORDER BY cm.session_id, cm.rowid ASC`).all(...e)}catch{return t}if(r.length===0)return t;let o=new Map;for(let i of r){let a=o.get(i.session_id);a||(a=[],o.set(i.session_id,a)),a.push(i)}for(let[i,a]of o){let l=a.filter(R=>!gy(R.text)),c=l.length>0?l:a,u=[];for(let R of c){let L=fy(R.embedding);L&&Sd(L)&&u.push(L)}if(u.length===0)continue;let p=Math.min(Ed,u.length),m=Math.max(0,u.length-Ed),f=u.slice(0,p),g=u.slice(m),h=Qr(f),E=Qr(g),b=Qr(u),S=new Map;for(let R=0;R<f.length&&S.size<bd;R++)S.set(R,f[R]);for(let R=0;R<g.length&&S.size<bd;R++)S.set(m+R,g[R]);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 _y(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 Td(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++)_y(r[c],r[u])>=t&&a(c,u);let l=new Map;for(let c=0;c<n.length;c++){let u=i(c),p=l.get(u);p===void 0&&(p=l.size,l.set(u,p)),s.set(n[c],p)}return s}var Kt={lo:.4,hi:.7},Vs="claude-haiku-4-5-20251001",wd=50;var hy={same_workflow:.15,unrelated:-.2,unsure:0};function xd(e,t,s=Kt){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 Ey(e,t){let s=e.replace(/\s+/g," ").trim();return s.length>t?s.slice(0,t-1)+"\u2026":s}function by(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 Sy(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=>` - ${Ey(u,500)}`).join(`
1613
- `),l=by(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(`
1713
+ ORDER BY cm.session_id, cm.rowid ASC`).all(...e)}catch{return t}if(r.length===0)return t;let o=new Map;for(let i of r){let a=o.get(i.session_id);a||(a=[],o.set(i.session_id,a)),a.push(i)}for(let[i,a]of o){let l=a.filter(y=>!HT(y.text)),c=l.length>0?l:a,u=[];for(let y of c){let C=WT(y.embedding);C&&Pd(C)&&u.push(C)}if(u.length===0)continue;let m=Math.min($d,u.length),p=Math.max(0,u.length-$d),f=u.slice(0,m),g=u.slice(p),h=io(f),E=io(g),b=io(u),S=new Map;for(let y=0;y<f.length&&S.size<jd;y++)S.set(y,f[y]);for(let y=0;y<g.length&&S.size<jd;y++)S.set(p+y,g[y]);let N=Array.from(S.values());t.set(i,{session_id:i,full_mean:b,head_pool:h,tail_pool:E,sample_chunks:N})}return t}function XT(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 Ud(e,t=.8){let s=new Map,n=[],r=[];for(let[c,u]of e)u.full_mean&&(n.push(c),r.push(u.full_mean));if(n.length===0)return s;let o=new Int32Array(n.length);for(let c=0;c<o.length;c++)o[c]=c;let i=c=>{let u=c;for(;o[u]!==u;)u=o[u];let m=c;for(;o[m]!==u;){let p=o[m];o[m]=u,m=p}return u},a=(c,u)=>{let m=i(c),p=i(u);m!==p&&(o[m]=p)};for(let c=0;c<n.length;c++)for(let u=c+1;u<n.length;u++)XT(r[c],r[u])>=t&&a(c,u);let l=new Map;for(let c=0;c<n.length;c++){let u=i(c),m=l.get(u);m===void 0&&(m=l.size,l.set(u,m)),s.set(n[c],m)}return s}var Vt={lo:.4,hi:.7},sn="claude-haiku-4-5-20251001",Bd=50;var JT={same_workflow:.15,unrelated:-.2,unsure:0};function Hd(e,t,s=Vt){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 GT(e,t){let s=e.replace(/\s+/g," ").trim();return s.length>t?s.slice(0,t-1)+"\u2026":s}function YT(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 zT(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=>` - ${GT(u,500)}`).join(`
1714
+ `),l=YT(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(`
1614
1715
  `),` step1_confidence: ${e.step1.confidence.toFixed(2)}`,"","PARENT SESSION","First user messages:",a(r),"Last user messages:",a(o),"",`CHILD SESSION (gap from parent: ${l})`,"First user messages:",a(i),"","Reply with EXACTLY one JSON object on a single line, no prose, no markdown:",'{"verdict":"same_workflow"|"unrelated"|"unsure","reason":"<one short sentence>"}',"","Guidance:",'- "same_workflow" = the child is clearly continuing what the parent was doing.','- "unrelated" = different problem, different files, different intent.','- "unsure" = could go either way; do not force a verdict.'].join(`
1615
- `)}function yy(e){if(!e)return null;let t=e.trim();if(!t)return null;let s=t;try{let l=JSON.parse(t);typeof l.result=="string"&&(s=l.result.trim())}catch{}let n=s.match(/\{[\s\S]*\}/);if(!n)return null;let r;try{r=JSON.parse(n[0])}catch{return null}if(!r||typeof r!="object")return null;let o=r,i=typeof o.verdict=="string"?o.verdict.toLowerCase():"";if(i!=="same_workflow"&&i!=="unrelated"&&i!=="unsure")return null;let a=typeof o.reason=="string"&&o.reason.trim()?o.reason.trim():"";return{verdict:i,reason:a,delta:hy[i]}}async function Rd(e,t={}){if(t.signal?.aborted)return null;let s=t.model??Vs,n=Sy(e),r=t.spawn;if(!r)try{let i=await Promise.resolve().then(()=>(Je(),Qn));if(!i.isClaudeCliAvailable())return null;r=(a,l)=>i.spawnClaudePrompt(a,[],l)}catch{return null}let o;try{o=await Promise.race([r(n,{model:s}),new Promise(i=>{t.signal&&t.signal.addEventListener("abort",()=>i({success:!1,stdout:""}),{once:!0})})])}catch{return null}return!o.success||!o.stdout?null:yy(o.stdout)}function kd(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 Nd(e){return`${e.parent_id}::${e.child_id}`}async function wy(e){if(e.signal?.aborted)return null;let t,s;try{({spawnClaudePrompt:t,isClaudeCliAvailable:s}=await Promise.resolve().then(()=>(Je(),Qn)))}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:
1716
+ `)}function qT(e){if(!e)return null;let t=e.trim();if(!t)return null;let s=t;try{let l=JSON.parse(t);typeof l.result=="string"&&(s=l.result.trim())}catch{}let n=s.match(/\{[\s\S]*\}/);if(!n)return null;let r;try{r=JSON.parse(n[0])}catch{return null}if(!r||typeof r!="object")return null;let o=r,i=typeof o.verdict=="string"?o.verdict.toLowerCase():"";if(i!=="same_workflow"&&i!=="unrelated"&&i!=="unsure")return null;let a=typeof o.reason=="string"&&o.reason.trim()?o.reason.trim():"";return{verdict:i,reason:a,delta:JT[i]}}async function Wd(e,t={}){if(t.signal?.aborted)return null;let s=t.model??sn,n=zT(e),r=t.spawn;if(!r)try{let i=await Promise.resolve().then(()=>(Ge(),rr));if(!i.isClaudeCliAvailable())return null;r=(a,l)=>i.spawnClaudePrompt(a,[],l)}catch{return null}let o;try{o=await Promise.race([r(n,{model:s}),new Promise(i=>{t.signal&&t.signal.addEventListener("abort",()=>i({success:!1,stdout:""}),{once:!0})})])}catch{return null}return!o.success||!o.stdout?null:qT(o.stdout)}function Xd(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 Jd(e){return`${e.parent_id}::${e.child_id}`}async function VT(e){if(e.signal?.aborted)return null;let t,s;try{({spawnClaudePrompt:t,isClaudeCliAvailable:s}=await Promise.resolve().then(()=>(Ge(),rr)))}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:
1616
1717
  - 4 to 8 words
1617
1718
  - Title-case, no trailing punctuation
1618
1719
  - Capture the WORKFLOW (e.g., "Update Remotion deps + lint cleanup"), not any one session
@@ -1623,7 +1724,7 @@ Sessions:
1623
1724
  `+n.join(`
1624
1725
  `)+`
1625
1726
 
1626
- Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model:e.model}:{}),i=null,a=new Promise(p=>{e.signal&&(i=()=>p(null),e.signal.addEventListener("abort",i,{once:!0}))}),l=await Promise.race([o,a]);if(i&&e.signal&&e.signal.removeEventListener("abort",i),!l||!l.success)return null;let c=l.stdout.trim();if(!c)return null;let u;try{let p=JSON.parse(c);u=typeof p.result=="string"?p.result:c}catch{u=c}return u=u.trim().replace(/^["'`]+|["'`]+$/g,"").replace(/[.!?]+$/g,"").trim(),u?u.length>80?u.slice(0,77)+"...":u:null}catch{return null}}function xy(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=yd(s)}catch{n=new Map}let r=new Map;for(let[o,i]of t){let a=new Map;for(let u of i){let p=n.get(u.id);p&&a.set(u.id,p)}let l=Td(a,.8),c=[];for(let u of i){let p=ky(u,n,l);p&&c.push(p)}r.set(o,c)}return{byProject:t,scannablesByProject:r}}function Ry(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,
1727
+ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model:e.model}:{}),i=null,a=new Promise(m=>{e.signal&&(i=()=>m(null),e.signal.addEventListener("abort",i,{once:!0}))}),l=await Promise.race([o,a]);if(i&&e.signal&&e.signal.removeEventListener("abort",i),!l||!l.success)return null;let c=l.stdout.trim();if(!c)return null;let u;try{let m=JSON.parse(c);u=typeof m.result=="string"?m.result:c}catch{u=c}return u=u.trim().replace(/^["'`]+|["'`]+$/g,"").replace(/[.!?]+$/g,"").trim(),u?u.length>80?u.slice(0,77)+"...":u:null}catch{return null}}function ZT(e){let t=new Map;for(let o of e){let i=t.get(o.project);i||(i=[],t.set(o.project,i)),i.push(o)}let s=e.map(o=>o.id),n=new Map;try{n=Fd(s)}catch{n=new Map}let r=new Map;for(let[o,i]of t){let a=new Map;for(let u of i){let m=n.get(u.id);m&&a.set(u.id,m)}let l=Ud(a,.8),c=[];for(let u of i){let m=ey(u,n,l);m&&c.push(m)}r.set(o,c)}return{byProject:t,scannablesByProject:r}}function QT(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,
1627
1728
  s.first_user_message, s.auto_title,
1628
1729
  NULLIF(sa.alias, '') AS alias,
1629
1730
  s.file_path
@@ -1631,38 +1732,42 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1631
1732
  JOIN projects p ON p.id = s.project_id
1632
1733
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1633
1734
  WHERE ${n}
1634
- ORDER BY p.name ASC, s.started_at ASC`).all(s)}function ky(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=hd(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 Zs(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 Cd(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 Ld(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 Ny(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??Kt,s=e.rescore.cap??wd,n=e.rescore.model??Vs,r=new Map(e.scannables.map(m=>[m.id,m])),o=xd(e.proposals,r,t);if(o.length===0)return{proposals:e.proposals,ran:!0,considered:0,promoted:0,demoted:0,unsure:0,failed:0,capped:!1};if(o.length>s)return{proposals:e.proposals,ran:!1,considered:o.length,promoted:0,demoted:0,unsure:0,failed:0,capped:!0};let i=new Map,a=0,l=0,c=0,u=0;for(let m=0;m<o.length&&!e.signal?.aborted;m++){let f=o[m],g=await Rd(f,{model:n,signal:e.signal});g?(i.set(Nd(f.step1),g),g.verdict==="same_workflow"?a++:g.verdict==="unrelated"?l++:c++):u++,e.onProgress?.({phase:"rescoring",current:m+1,total:o.length,verdict:g?.verdict??"failed"})}return{proposals:kd({proposals:e.proposals,rescored:i,applyThreshold:e.applyThreshold}),ran:!0,considered:o.length,promoted:a,demoted:l,unsure:c,failed:u,capped:!1}}async function Cy(e){let t=_(),s=new Map(e.rows.map(c=>[c.id,c])),n=_d(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=Ld(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 wy({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-${Ty()}`,m=i.get(c.rootId)??Ld(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
1735
+ ORDER BY p.name ASC, s.started_at ASC`).all(s)}function ey(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=Dd(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 nn(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 Gd(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 Yd(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 ty(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??Vt,s=e.rescore.cap??Bd,n=e.rescore.model??sn,r=new Map(e.scannables.map(p=>[p.id,p])),o=Hd(e.proposals,r,t);if(o.length===0)return{proposals:e.proposals,ran:!0,considered:0,promoted:0,demoted:0,unsure:0,failed:0,capped:!1};if(o.length>s)return{proposals:e.proposals,ran:!1,considered:o.length,promoted:0,demoted:0,unsure:0,failed:0,capped:!0};let i=new Map,a=0,l=0,c=0,u=0;for(let p=0;p<o.length&&!e.signal?.aborted;p++){let f=o[p],g=await Wd(f,{model:n,signal:e.signal});g?(i.set(Jd(f.step1),g),g.verdict==="same_workflow"?a++:g.verdict==="unrelated"?l++:c++):u++,e.onProgress?.({phase:"rescoring",current:p+1,total:o.length,verdict:g?.verdict??"failed"})}return{proposals:Xd({proposals:e.proposals,rescored:i,applyThreshold:e.applyThreshold}),ran:!0,considered:o.length,promoted:a,demoted:l,unsure:c,failed:u,capped:!1}}async function sy(e){let t=_(),s=new Map(e.rows.map(c=>[c.id,c])),n=Md(e.edges,e.scannables),r=new Date().toISOString(),o=[],i=new Map,a=0;for(let c of n){if(a++,e.signal?.aborted)break;let u=s.get(c.rootId),m=Yd(u);if(!e.llmNames){i.set(c.rootId,m),e.onProgress?.({phase:"naming",current:a,total:n.length,thread_name:m});continue}let f=await VT({rootRow:u,sessionIds:c.sessionIds,rowById:s,signal:e.signal,model:e.model})??m;i.set(c.rootId,f),e.onProgress?.({phase:"naming",current:a,total:n.length,thread_name:f})}return t.transaction(()=>{for(let c of n){if(!i.has(c.rootId))continue;let u=s.get(c.rootId),m=`auto-scan-${KT()}`,p=i.get(c.rootId)??Yd(u),f=`Auto-detected workflow chain (${c.sessionIds.length} sessions). Source: auto-scan-v1.`;t.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, ?, ?)").run(m,p,f,r),t.prepare(`INSERT INTO thread_edges
1635
1736
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
1636
- 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
1737
+ VALUES (?, ?, NULL, 'origin', 1.0, 'auto-scan-v1', ?)`).run(m,c.rootId,r);let g=new Map;for(let h of e.edges)c.sessionIds.includes(h.child_id)&&g.set(h.child_id,h);for(let h of c.sessionIds){if(h===c.rootId)continue;let E=g.get(h);E&&t.prepare(`INSERT INTO thread_edges
1637
1738
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
1638
- 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 Od(e){let t=!!e.apply,s=e.confidenceMin?Number(e.confidenceMin):t?Vr:Zr;if(!Number.isFinite(s)||s<0||s>1){console.error(d.err("--confidence-min must be a number in [0, 1]")),process.exitCode=1;return}let n=!!e.llmRescore,r={lo:e.rescoreBandLo?Number(e.rescoreBandLo):Kt.lo,hi:e.rescoreBandHi?Number(e.rescoreBandHi):Kt.hi};if(n&&(!Number.isFinite(r.lo)||!Number.isFinite(r.hi)||r.lo<0||r.hi>1||r.lo>r.hi)){console.error(d.err("--rescore-band-lo/hi must satisfy 0 \u2264 lo \u2264 hi \u2264 1")),process.exitCode=1;return}let o=e.rescoreModel??Vs,i=Ry({project:e.project});if(i.length===0){console.log(d.dim("no sessions matched"));return}let{byProject:a,scannablesByProject:l}=xy(i),c=n?Math.min(s,r.lo):s,u=new Map,p=0;for(let[f]of a){let g=l.get(f)??[],h=fd(g,c);if(n&&h.length>0){let E=await Ny({proposals:h,scannables:g,applyThreshold:s,rescore:{enabled:!0,band:r,model:o}});h=E.proposals,E.capped?(console.error(d.err(`[${f}] borderline pairs exceeded cap (${E.considered}); skipped LLM rescore. Tighten the band or scan a smaller project.`)),h=h.filter(b=>b.confidence>=s)):n?E.failed===E.considered&&E.considered>0&&(h=h.filter(b=>b.confidence>=s)):h=h.filter(b=>b.confidence>=s)}else n&&(h=h.filter(E=>E.confidence>=s));u.set(f,{proposals:h,scannables:g}),p+=h.length}if(t){if(p===0){console.log(d.dim("no edges above threshold; nothing to apply"));return}let f={threads_created:0,edges_written:0,per_project:[]},g=!e.noLlmNames;for(let[h,{proposals:E,scannables:b}]of u){if(E.length===0)continue;let S=await Cy({project:h,rows:a.get(h),edges:E,scannables:b,llmNames:g});f.per_project.push(S),f.threads_created+=S.threads.length,f.edges_written+=E.length+S.threads.length}if(e.json){console.log(JSON.stringify({mode:"apply",threshold:s,...f},null,2));return}console.log(d.ok(`Applied ${f.threads_created} thread${f.threads_created===1?"":"s"} with ${f.edges_written} edges total (threshold ${s}).`));for(let h of f.per_project){console.log(` ${d.bold(h.project)}`);for(let E of h.threads)console.log(` ${d.dim(E.thread_id.slice(0,16)+"\u2026")} ${E.name} ${d.dim(`(${E.session_count} sessions)`)}`)}console.log(),console.log(d.dim("Rollback: sqlite3 ~/.recall/db.sqlite \\")),console.log(d.dim(` "DELETE FROM thread_edges WHERE source='auto-scan-v1';`)),console.log(d.dim(` DELETE FROM threads WHERE id LIKE 'auto-scan-%';"`));return}if(e.json){let f=[];for(let[g,{proposals:h}]of u){let E=new Map(a.get(g).map(b=>[b.id,b]));for(let b of h)f.push({project:g,parent_id:b.parent_id,parent_label:Zs(E.get(b.parent_id)),child_id:b.child_id,child_label:Zs(E.get(b.child_id)),confidence:b.confidence,signals:b.signals,reasons:b.reasons})}console.log(JSON.stringify({mode:"dry-run",threshold:s,total:p,edges:f},null,2));return}console.log(d.dim(`recall thread scan \xB7 ${a.size} project${a.size===1?"":"s"} \xB7 DRY RUN \xB7 threshold ${s}`)),console.log(d.dim(" Algorithm: temporal + continuation phrase + file overlap + same brand.")),console.log();for(let[f,g]of a){let{proposals:h}=u.get(f),E=new Map(g.map(S=>[S.id,S]));if(console.log(d.bold(f)),console.log(d.dim(` ${g.length} eligible session${g.length===1?"":"s"}; ${h.length} parent-child edge${h.length===1?"":"s"} proposed.`)),h.length===0){console.log(d.dim(" (no edges above threshold \u2014 all sessions are origins)")),console.log();continue}let b=[...h].sort((S,C)=>{let R=E.get(S.child_id),L=E.get(C.child_id);return(R.started_at??"").localeCompare(L.started_at??"")});for(let S of b){let C=E.get(S.parent_id),R=E.get(S.child_id),L=S.confidence.toFixed(2);console.log(` ${d.dim(Cd(C.started_at).padEnd(16))} ${d.bold("PARENT")} ${Zs(C)}`),console.log(` ${d.dim(Cd(R.started_at).padEnd(16))} ${d.bold(" \u2514\u2500 child")} ${Zs(R)} ${d.dim(`[conf ${L}]`)}`),console.log(` ${" ".repeat(28)}${d.dim(S.reasons.join(" \xB7 "))}`),console.log()}}let m=Array.from(a.entries()).reduce((f,[g,h])=>f+(h.length-(u.get(g)?.proposals.length??0)),0);console.log(`${p} edge${p===1?"":"s"} proposed across ${a.size} project${a.size===1?"":"s"}; ${m} origin session${m===1?"":"s"} (no proposed parent).`),console.log(d.dim(` This is a DRY RUN. To write: rerun with --apply (default threshold ${Vr}).`))}I();j();import{existsSync as Ly,readFileSync as Oy}from"node:fs";function Ay(){let e=`${x}/daemon.port`;if(!Ly(e))return null;try{let t=Oy(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function Iy(e){try{return(await _t(`http://127.0.0.1:${e}/api/health`,{signal:AbortSignal.timeout(1e4)})).ok}catch{return!1}}async function vy(e){let t=await _t(`http://127.0.0.1:${e}/api/projects`);if(!t.ok)throw new Error(`failed to list projects: HTTP ${t.status}`);return await t.json()}function My(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 $y(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 Ad(e){return e.alias||e.auto_title||(e.first_user_message?Y(e.first_user_message,60):"(no title)")}function Dy(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 jy(e,t){let s=t==="preflight"?d.dim(`recall threads sync \xB7 ${e.project.name} \xB7 PREFLIGHT (no writes)`):d.dim(`recall threads sync \xB7 ${e.project.name}`);if(console.log(s),console.log(),e.thread.exists?console.log(` ${d.bold("Thread")} ${e.thread.name} ${d.dim(`(reusing, ${e.thread.existing_session_count} existing session${e.thread.existing_session_count===1?"":"s"})`)}`):console.log(` ${d.bold("Thread")} ${e.thread.name} ${d.ok("(new)")}`),console.log(),e.candidates.length===0){if(console.log(d.dim(" No active sessions in the rolling window.")),e.warnings.length>0)for(let c of e.warnings)console.log(d.warn(` \u26A0 ${c}`));return}let n=new Map;for(let c of e.proposed_edges)n.set(c.child_id,c);let r=new Map;for(let c of e.preserved_manual_edges)r.set(c.session_id,c.parent_session_id);let o=new Set(e.candidates.map(c=>c.session_id)),i=e.proposed_additions.length,a=e.candidates.length-i;console.log(` ${d.bold("Candidates")} ${e.candidates.length} active session${e.candidates.length===1?"":"s"} ${d.dim(`(${i} new \xB7 ${a} keep)`)}`);let l=String(e.candidates.length).length;for(let c=0;c<e.candidates.length;c++){let u=e.candidates[c],m=e.proposed_additions.some(S=>S.session_id===u.session_id)?d.ok("NEW "):d.dim("keep"),f=n.get(u.session_id)??(r.has(u.session_id)&&r.get(u.session_id)!==null,null),g=f&&o.has(f.parent_id)?" \u2514\u2500 ":" ",h=Dy(u.started_at),E=d.dim(`${String(c+1).padStart(l," ")}.`);console.log(` ${E} ${m} ${d.dim(h.padEnd(16))} ${g}${d.dim(u.session_id.slice(0,8))} ${Ad(u)}`);let b=" ".repeat(l+2);if(f&&o.has(f.parent_id)){let S=f.confidence.toFixed(2),C=Ad(e.candidates.find(R=>R.session_id===f.parent_id));console.log(` ${b}${" ".repeat(28)} parent ${d.dim(f.parent_id.slice(0,8))} (${C}) ${d.dim(`[conf ${S}]`)}`),console.log(` ${b}${" ".repeat(28)} ${d.dim(f.reasons.join(" \xB7 "))}`)}if(r.has(u.session_id)){let S=r.get(u.session_id);S&&console.log(` ${b}${" ".repeat(28)} ${d.bold("manual parent preserved")} ${d.dim(S.slice(0,8))}`)}}if(e.preserved_manual_edges.length>0&&(console.log(),console.log(d.dim(` ${e.preserved_manual_edges.length} manual edge${e.preserved_manual_edges.length===1?"":"s"} will be preserved.`))),e.warnings.length>0){console.log();for(let c of e.warnings)console.log(d.warn(` \u26A0 ${c}`))}}function Py(e){console.log(),console.log(d.ok(`Added ${e.added} session${e.added===1?"":"s"}, set ${e.edges_set} parent edge${e.edges_set===1?"":"s"}, preserved ${e.preserved_manual} manual edge${e.preserved_manual===1?"":"s"}.`)),console.log(d.dim(` thread_id: ${e.thread_id}`))}async function Id(e){let t=Ay();if(!t){console.error(d.err("Daemon is not running. Start it with `recall start`, then re-run this command.")),process.exitCode=1;return}if(!await Iy(t)){console.error(d.err(`Daemon on port ${t} is not responding. Try \`recall stop && recall start\`.`)),process.exitCode=1;return}let n;try{n=await vy(t)}catch(c){console.error(d.err(c.message)),process.exitCode=1;return}let r;if(e.project){if(r=$y(n,e.project),!r){console.error(d.err(`No project matching "${e.project}". Run \`recall projects\` to list known projects.`)),process.exitCode=1;return}}else{let c=process.cwd();if(r=My(n,c),!r){console.error(d.err(`Current directory (${c}) does not match any known project. Pass --project <name> or cd into a project root.`)),process.exitCode=1;return}}let o=e.windowHours?Number(e.windowHours):void 0;if(o!==void 0&&(!Number.isFinite(o)||o<=0)){console.error(d.err("--window-hours must be a positive number")),process.exitCode=1;return}let i=e.preflight?"preflight":"apply",a={project_id:r.id,mode:i};o!==void 0&&(a.window_hours=o);let l;try{let c=await tt("POST",`http://127.0.0.1:${t}/api/threads/sync-active`,a);if(!c.ok){let u=await c.text().catch(()=>"");throw new Error(`HTTP ${c.status}: ${u.slice(0,200)}`)}l=await c.json()}catch(c){console.error(d.err(`Sync failed: ${c.message}`)),process.exitCode=1;return}if(e.json){console.log(JSON.stringify({mode:i,...l},null,2));return}jy(l.plan,i),i==="apply"&&l.result?Py(l.result):i==="preflight"&&(console.log(),console.log(d.dim(" This is a PREFLIGHT. To write: re-run without --preflight.")))}T();import{writeFileSync as aT,existsSync as cT,mkdirSync as lT}from"node:fs";import{join as Vd}from"node:path";import{homedir as dT}from"node:os";import{execSync as It}from"node:child_process";import nT from"satori";import rT from"sharp";import{readFileSync as ro}from"node:fs";import{join as cn}from"node:path";var oo=cn(Te(),"dist","share","fonts"),Yd=!1,qd=[];function oT(){return Yd||(qd=[{name:"Inter",data:ro(cn(oo,"Inter-Regular.woff")),weight:400,style:"normal"},{name:"Inter",data:ro(cn(oo,"Inter-Bold.woff")),weight:700,style:"normal"},{name:"JetBrains Mono",data:ro(cn(oo,"JetBrainsMono-Regular.woff")),weight:400,style:"normal"}],Yd=!0),qd}async function iT(e){switch(e){case"A":return await Promise.resolve().then(()=>(Dd(),$d));case"B":return await Promise.resolve().then(()=>(Fd(),Pd));case"C":return await Promise.resolve().then(()=>(Hd(),Bd));case"D":return await Promise.resolve().then(()=>(Jd(),Xd));case"E":return await Promise.resolve().then(()=>(zd(),Gd))}}async function ln(e,t){let n=(await iT(e)).render(t),i=await nT(n,{width:1080,height:e==="E"?1920:1350,fonts:oT()});return await rT(Buffer.from(i)).png({quality:90}).toBuffer()}function Kd(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 uT(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.
1639
- `),null)}function pT(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(`
1739
+ VALUES (?, ?, ?, 'child', ?, 'auto-scan-v1', ?)`).run(m,h,E.parent_id,E.confidence,r)}o.push({thread_id:m,name:p,session_count:c.sessionIds.length})}})(),{project:e.project,threads:o}}async function zd(e){let t=!!e.apply,s=e.confidenceMin?Number(e.confidenceMin):t?ro:oo;if(!Number.isFinite(s)||s<0||s>1){console.error(d.err("--confidence-min must be a number in [0, 1]")),process.exitCode=1;return}let n=!!e.llmRescore,r={lo:e.rescoreBandLo?Number(e.rescoreBandLo):Vt.lo,hi:e.rescoreBandHi?Number(e.rescoreBandHi):Vt.hi};if(n&&(!Number.isFinite(r.lo)||!Number.isFinite(r.hi)||r.lo<0||r.hi>1||r.lo>r.hi)){console.error(d.err("--rescore-band-lo/hi must satisfy 0 \u2264 lo \u2264 hi \u2264 1")),process.exitCode=1;return}let o=e.rescoreModel??sn,i=QT({project:e.project});if(i.length===0){console.log(d.dim("no sessions matched"));return}let{byProject:a,scannablesByProject:l}=ZT(i),c=n?Math.min(s,r.lo):s,u=new Map,m=0;for(let[f]of a){let g=l.get(f)??[],h=Id(g,c);if(n&&h.length>0){let E=await ty({proposals:h,scannables:g,applyThreshold:s,rescore:{enabled:!0,band:r,model:o}});h=E.proposals,E.capped?(console.error(d.err(`[${f}] borderline pairs exceeded cap (${E.considered}); skipped LLM rescore. Tighten the band or scan a smaller project.`)),h=h.filter(b=>b.confidence>=s)):n?E.failed===E.considered&&E.considered>0&&(h=h.filter(b=>b.confidence>=s)):h=h.filter(b=>b.confidence>=s)}else n&&(h=h.filter(E=>E.confidence>=s));u.set(f,{proposals:h,scannables:g}),m+=h.length}if(t){if(m===0){console.log(d.dim("no edges above threshold; nothing to apply"));return}let f={threads_created:0,edges_written:0,per_project:[]},g=!e.noLlmNames;for(let[h,{proposals:E,scannables:b}]of u){if(E.length===0)continue;let S=await sy({project:h,rows:a.get(h),edges:E,scannables:b,llmNames:g});f.per_project.push(S),f.threads_created+=S.threads.length,f.edges_written+=E.length+S.threads.length}if(e.json){console.log(JSON.stringify({mode:"apply",threshold:s,...f},null,2));return}console.log(d.ok(`Applied ${f.threads_created} thread${f.threads_created===1?"":"s"} with ${f.edges_written} edges total (threshold ${s}).`));for(let h of f.per_project){console.log(` ${d.bold(h.project)}`);for(let E of h.threads)console.log(` ${d.dim(E.thread_id.slice(0,16)+"\u2026")} ${E.name} ${d.dim(`(${E.session_count} sessions)`)}`)}console.log(),console.log(d.dim("Rollback: sqlite3 ~/.recall/db.sqlite \\")),console.log(d.dim(` "DELETE FROM thread_edges WHERE source='auto-scan-v1';`)),console.log(d.dim(` DELETE FROM threads WHERE id LIKE 'auto-scan-%';"`));return}if(e.json){let f=[];for(let[g,{proposals:h}]of u){let E=new Map(a.get(g).map(b=>[b.id,b]));for(let b of h)f.push({project:g,parent_id:b.parent_id,parent_label:nn(E.get(b.parent_id)),child_id:b.child_id,child_label:nn(E.get(b.child_id)),confidence:b.confidence,signals:b.signals,reasons:b.reasons})}console.log(JSON.stringify({mode:"dry-run",threshold:s,total:m,edges:f},null,2));return}console.log(d.dim(`recall thread scan \xB7 ${a.size} project${a.size===1?"":"s"} \xB7 DRY RUN \xB7 threshold ${s}`)),console.log(d.dim(" Algorithm: temporal + continuation phrase + file overlap + same brand.")),console.log();for(let[f,g]of a){let{proposals:h}=u.get(f),E=new Map(g.map(S=>[S.id,S]));if(console.log(d.bold(f)),console.log(d.dim(` ${g.length} eligible session${g.length===1?"":"s"}; ${h.length} parent-child edge${h.length===1?"":"s"} proposed.`)),h.length===0){console.log(d.dim(" (no edges above threshold \u2014 all sessions are origins)")),console.log();continue}let b=[...h].sort((S,N)=>{let y=E.get(S.child_id),C=E.get(N.child_id);return(y.started_at??"").localeCompare(C.started_at??"")});for(let S of b){let N=E.get(S.parent_id),y=E.get(S.child_id),C=S.confidence.toFixed(2);console.log(` ${d.dim(Gd(N.started_at).padEnd(16))} ${d.bold("PARENT")} ${nn(N)}`),console.log(` ${d.dim(Gd(y.started_at).padEnd(16))} ${d.bold(" \u2514\u2500 child")} ${nn(y)} ${d.dim(`[conf ${C}]`)}`),console.log(` ${" ".repeat(28)}${d.dim(S.reasons.join(" \xB7 "))}`),console.log()}}let p=Array.from(a.entries()).reduce((f,[g,h])=>f+(h.length-(u.get(g)?.proposals.length??0)),0);console.log(`${m} edge${m===1?"":"s"} proposed across ${a.size} project${a.size===1?"":"s"}; ${p} origin session${p===1?"":"s"} (no proposed parent).`),console.log(d.dim(` This is a DRY RUN. To write: rerun with --apply (default threshold ${ro}).`))}v();P();import{existsSync as ny,readFileSync as ry}from"node:fs";function oy(){let e=`${x}/daemon.port`;if(!ny(e))return null;try{let t=ry(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function iy(e){try{return(await _t(`http://127.0.0.1:${e}/api/health`,{signal:AbortSignal.timeout(1e4)})).ok}catch{return!1}}async function ay(e){let t=await _t(`http://127.0.0.1:${e}/api/projects`);if(!t.ok)throw new Error(`failed to list projects: HTTP ${t.status}`);return await t.json()}function cy(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 ly(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 qd(e){return e.alias||e.auto_title||(e.first_user_message?z(e.first_user_message,60):"(no title)")}function dy(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 uy(e,t){let s=t==="preflight"?d.dim(`recall threads sync \xB7 ${e.project.name} \xB7 PREFLIGHT (no writes)`):d.dim(`recall threads sync \xB7 ${e.project.name}`);if(console.log(s),console.log(),e.thread.exists?console.log(` ${d.bold("Thread")} ${e.thread.name} ${d.dim(`(reusing, ${e.thread.existing_session_count} existing session${e.thread.existing_session_count===1?"":"s"})`)}`):console.log(` ${d.bold("Thread")} ${e.thread.name} ${d.ok("(new)")}`),console.log(),e.candidates.length===0){if(console.log(d.dim(" No active sessions in the rolling window.")),e.warnings.length>0)for(let c of e.warnings)console.log(d.warn(` \u26A0 ${c}`));return}let n=new Map;for(let c of e.proposed_edges)n.set(c.child_id,c);let r=new Map;for(let c of e.preserved_manual_edges)r.set(c.session_id,c.parent_session_id);let o=new Set(e.candidates.map(c=>c.session_id)),i=e.proposed_additions.length,a=e.candidates.length-i;console.log(` ${d.bold("Candidates")} ${e.candidates.length} active session${e.candidates.length===1?"":"s"} ${d.dim(`(${i} new \xB7 ${a} keep)`)}`);let l=String(e.candidates.length).length;for(let c=0;c<e.candidates.length;c++){let u=e.candidates[c],p=e.proposed_additions.some(S=>S.session_id===u.session_id)?d.ok("NEW "):d.dim("keep"),f=n.get(u.session_id)??(r.has(u.session_id)&&r.get(u.session_id)!==null,null),g=f&&o.has(f.parent_id)?" \u2514\u2500 ":" ",h=dy(u.started_at),E=d.dim(`${String(c+1).padStart(l," ")}.`);console.log(` ${E} ${p} ${d.dim(h.padEnd(16))} ${g}${d.dim(u.session_id.slice(0,8))} ${qd(u)}`);let b=" ".repeat(l+2);if(f&&o.has(f.parent_id)){let S=f.confidence.toFixed(2),N=qd(e.candidates.find(y=>y.session_id===f.parent_id));console.log(` ${b}${" ".repeat(28)} parent ${d.dim(f.parent_id.slice(0,8))} (${N}) ${d.dim(`[conf ${S}]`)}`),console.log(` ${b}${" ".repeat(28)} ${d.dim(f.reasons.join(" \xB7 "))}`)}if(r.has(u.session_id)){let S=r.get(u.session_id);S&&console.log(` ${b}${" ".repeat(28)} ${d.bold("manual parent preserved")} ${d.dim(S.slice(0,8))}`)}}if(e.preserved_manual_edges.length>0&&(console.log(),console.log(d.dim(` ${e.preserved_manual_edges.length} manual edge${e.preserved_manual_edges.length===1?"":"s"} will be preserved.`))),e.warnings.length>0){console.log();for(let c of e.warnings)console.log(d.warn(` \u26A0 ${c}`))}}function my(e){console.log(),console.log(d.ok(`Added ${e.added} session${e.added===1?"":"s"}, set ${e.edges_set} parent edge${e.edges_set===1?"":"s"}, preserved ${e.preserved_manual} manual edge${e.preserved_manual===1?"":"s"}.`)),console.log(d.dim(` thread_id: ${e.thread_id}`))}async function Kd(e){let t=oy();if(!t){console.error(d.err("Daemon is not running. Start it with `recall start`, then re-run this command.")),process.exitCode=1;return}if(!await iy(t)){console.error(d.err(`Daemon on port ${t} is not responding. Try \`recall stop && recall start\`.`)),process.exitCode=1;return}let n;try{n=await ay(t)}catch(c){console.error(d.err(c.message)),process.exitCode=1;return}let r;if(e.project){if(r=ly(n,e.project),!r){console.error(d.err(`No project matching "${e.project}". Run \`recall projects\` to list known projects.`)),process.exitCode=1;return}}else{let c=process.cwd();if(r=cy(n,c),!r){console.error(d.err(`Current directory (${c}) does not match any known project. Pass --project <name> or cd into a project root.`)),process.exitCode=1;return}}let o=e.windowHours?Number(e.windowHours):void 0;if(o!==void 0&&(!Number.isFinite(o)||o<=0)){console.error(d.err("--window-hours must be a positive number")),process.exitCode=1;return}let i=e.preflight?"preflight":"apply",a={project_id:r.id,mode:i};o!==void 0&&(a.window_hours=o);let l;try{let c=await tt("POST",`http://127.0.0.1:${t}/api/threads/sync-active`,a);if(!c.ok){let u=await c.text().catch(()=>"");throw new Error(`HTTP ${c.status}: ${u.slice(0,200)}`)}l=await c.json()}catch(c){console.error(d.err(`Sync failed: ${c.message}`)),process.exitCode=1;return}if(e.json){console.log(JSON.stringify({mode:i,...l},null,2));return}uy(l.plan,i),i==="apply"&&l.result?my(l.result):i==="preflight"&&(console.log(),console.log(d.dim(" This is a PREFLIGHT. To write: re-run without --preflight.")))}w();import{writeFileSync as Dy,existsSync as $y,mkdirSync as jy}from"node:fs";import{join as fu}from"node:path";import{homedir as Py}from"node:os";import{execSync as vt}from"node:child_process";import Oy from"satori";import vy from"sharp";import{readFileSync as mo}from"node:fs";import{join as pn}from"node:path";var po=pn(ye(),"dist","share","fonts"),mu=!1,pu=[];function Iy(){return mu||(pu=[{name:"Inter",data:mo(pn(po,"Inter-Regular.woff")),weight:400,style:"normal"},{name:"Inter",data:mo(pn(po,"Inter-Bold.woff")),weight:700,style:"normal"},{name:"JetBrains Mono",data:mo(pn(po,"JetBrainsMono-Regular.woff")),weight:400,style:"normal"}],mu=!0),pu}async function My(e){switch(e){case"A":return await Promise.resolve().then(()=>(eu(),Qd));case"B":return await Promise.resolve().then(()=>(nu(),su));case"C":return await Promise.resolve().then(()=>(iu(),ou));case"D":return await Promise.resolve().then(()=>(lu(),cu));case"E":return await Promise.resolve().then(()=>(uu(),du))}}async function gn(e,t){let n=(await My(e)).render(t),i=await Oy(n,{width:1080,height:e==="E"?1920:1350,fonts:Iy()});return await vy(Buffer.from(i)).png({quality:90}).toBuffer()}function gu(e,t){let s=new URLSearchParams({v:"1",s:t,t:e.sessionTitle,d:e.sessionDate.slice(0,10),tk:String(e.tokenCount),m:String(e.messageCount)});return typeof e.inputTokens=="number"&&s.set("i",String(e.inputTokens)),typeof e.outputTokens=="number"&&s.set("o",String(e.outputTokens)),e.verdict&&s.set("q",e.verdict),`https://clauderecall.com/card?${s.toString()}`}function Fy(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.
1740
+ `),null)}function Uy(e){return e.prepare("SELECT session_id FROM recall_events ORDER BY recalled_at DESC LIMIT 1").get()?.session_id??null}function By(e,t){let s=e.prepare(`
1640
1741
  SELECT s.id, s.started_at, s.message_count, s.first_user_message, s.auto_title,
1641
1742
  s.total_input_tokens, s.total_output_tokens
1642
1743
  FROM sessions s WHERE s.id = ?
1643
1744
  `).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(`
1644
1745
  SELECT tool_names, raw_json FROM messages
1645
1746
  WHERE session_id = ? AND tool_names IS NOT NULL AND tool_names != ''
1646
- `).all(t),i=o.length,a=new Set;for(let u of o){if(!/Read|Write|Edit/.test(u.tool_names))continue;let p=u.raw_json.match(/"(?:file_path|path)":\s*"([^"]+)"/g);if(p)for(let m of p){let f=m.match(/":\s*"([^"]+)"/);f&&a.add(f[1])}}let l=s.total_input_tokens??0,c=s.total_output_tokens??0;return{sessionTitle:r,sessionDate:s.started_at??new Date().toISOString(),recallDate:new Date().toISOString(),tokenCount:l+c,inputTokens:l,outputTokens:c,messageCount:s.message_count,filesReferenced:a.size,toolCallCount:i,verdict:""}}function gT(e){process.platform==="darwin"?It(`osascript -e 'set the clipboard to (read (POSIX file "${e}") as \xABclass PNGf\xBB)'`):process.platform==="linux"&&It(`xclip -selection clipboard -t image/png -i "${e}"`)}function fT(e){try{process.platform==="darwin"?It(`open "${e}"`):process.platform==="linux"?It(`xdg-open "${e}"`):process.platform==="win32"&&It(`start "" "${e}"`)}catch{}}async function Zd(e,t){let s=_(),n;if(e){if(n=uT(s,e),!n){process.stderr.write(`session not found: ${e}
1647
- `),process.exitCode=1;return}}else if(n=pT(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}
1648
- `),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 ln(o,r),a=n.slice(0,8),l=t.out??Vd(dT(),"Downloads");cT(l)||lT(l,{recursive:!0});let c=Vd(l,`recall-card-${a}.png`);if(aT(c,i),process.stderr.write(`Card saved to ${c}
1649
- `),t.clipboard&&(gT(c),process.stderr.write(`Copied PNG to clipboard.
1650
- `)),t.link){let u=Kd(r,o);process.stdout.write(u+`
1651
- `),process.platform==="darwin"&&(It("pbcopy",{input:u}),process.stderr.write(`Link copied to clipboard.
1652
- `))}t.open!==!1&&fT(c)}T();import{createInterface as _T}from"node:readline";import{writeFileSync as hT,existsSync as ET,mkdirSync as bT}from"node:fs";import{join as eu}from"node:path";import{homedir as ST}from"node:os";function Qd(e){return e.recallCount>=15&&e.uniqueSessionsRecalled>=10?"Context Architect":e.nightSessionRatio>.5?"Night Owl":e.sessionCount>30&&e.avgMessageCount<50?"Rapid Shipper":e.sessionCount<15&&e.avgMessageCount>200?"Deep Diver":e.debugTagRatio>.4?"Debugger":"Power User"}var wt=["january","february","march","april","may","june","july","august","september","october","november","december"],yT=["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"];function TT(e){let t=new Date;if(!e){let i=t.getFullYear(),a=t.getMonth();return{start:`${i}-${String(a+1).padStart(2,"0")}-01`,end:a===11?`${i+1}-01-01`:`${i}-${String(a+2).padStart(2,"0")}-01`,label:`${wt[a][0].toUpperCase()}${wt[a].slice(1)} ${i}`}}let s=e.match(/^(\d{4})-(\d{2})$/);if(s){let i=parseInt(s[1],10),a=parseInt(s[2],10)-1;return a<0||a>11?null:{start:`${i}-${String(a+1).padStart(2,"0")}-01`,end:a===11?`${i+1}-01-01`:`${i}-${String(a+2).padStart(2,"0")}-01`,label:`${wt[a][0].toUpperCase()}${wt[a].slice(1)} ${i}`}}let n=wt.indexOf(e.toLowerCase()),r=n===-1?yT.indexOf(e.toLowerCase()):-1,o=n!==-1?n:r;if(o!==-1){let i=t.getFullYear();return{start:`${i}-${String(o+1).padStart(2,"0")}-01`,end:o===11?`${i+1}-01-01`:`${i}-${String(o+2).padStart(2,"0")}-01`,label:`${wt[o][0].toUpperCase()}${wt[o].slice(1)} ${i}`}}return null}function wT(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 tu(e,t){let s=TT(e);if(!s){process.stderr.write(`invalid month format: ${e}. Use YYYY-MM, month name, or abbreviation.
1747
+ `).all(t),i=o.length,a=new Set;for(let u of o){if(!/Read|Write|Edit/.test(u.tool_names))continue;let m=u.raw_json.match(/"(?:file_path|path)":\s*"([^"]+)"/g);if(m)for(let p of m){let f=p.match(/":\s*"([^"]+)"/);f&&a.add(f[1])}}let l=s.total_input_tokens??0,c=s.total_output_tokens??0;return{sessionTitle:r,sessionDate:s.started_at??new Date().toISOString(),recallDate:new Date().toISOString(),tokenCount:l+c,inputTokens:l,outputTokens:c,messageCount:s.message_count,filesReferenced:a.size,toolCallCount:i,verdict:""}}function Hy(e){process.platform==="darwin"?vt(`osascript -e 'set the clipboard to (read (POSIX file "${e}") as \xABclass PNGf\xBB)'`):process.platform==="linux"&&vt(`xclip -selection clipboard -t image/png -i "${e}"`)}function Wy(e){try{process.platform==="darwin"?vt(`open "${e}"`):process.platform==="linux"?vt(`xdg-open "${e}"`):process.platform==="win32"&&vt(`start "" "${e}"`)}catch{}}async function _u(e,t){let s=_(),n;if(e){if(n=Fy(s,e),!n){process.stderr.write(`session not found: ${e}
1748
+ `),process.exitCode=1;return}}else if(n=Uy(s),!n){process.stderr.write("No recalled sessions yet. Run `recall context <id>` first, then `recall share`.\n"),process.exitCode=1;return}let r=By(s,n);if(!r){process.stderr.write(`failed to load metadata for session ${n}
1749
+ `),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 gn(o,r),a=n.slice(0,8),l=t.out??fu(Py(),"Downloads");$y(l)||jy(l,{recursive:!0});let c=fu(l,`recall-card-${a}.png`);if(Dy(c,i),process.stderr.write(`Card saved to ${c}
1750
+ `),t.clipboard&&(Hy(c),process.stderr.write(`Copied PNG to clipboard.
1751
+ `)),t.link){let u=gu(r,o);process.stdout.write(u+`
1752
+ `),process.platform==="darwin"&&(vt("pbcopy",{input:u}),process.stderr.write(`Link copied to clipboard.
1753
+ `))}t.open!==!1&&Wy(c)}w();import{createInterface as Xy}from"node:readline";import{writeFileSync as Jy,existsSync as Gy,mkdirSync as Yy}from"node:fs";import{join as Eu}from"node:path";import{homedir as zy}from"node:os";function hu(e){return e.recallCount>=15&&e.uniqueSessionsRecalled>=10?"Context Architect":e.nightSessionRatio>.5?"Night Owl":e.sessionCount>30&&e.avgMessageCount<50?"Rapid Shipper":e.sessionCount<15&&e.avgMessageCount>200?"Deep Diver":e.debugTagRatio>.4?"Debugger":"Power User"}var wt=["january","february","march","april","may","june","july","august","september","october","november","december"],qy=["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"];function Ky(e){let t=new Date;if(!e){let i=t.getFullYear(),a=t.getMonth();return{start:`${i}-${String(a+1).padStart(2,"0")}-01`,end:a===11?`${i+1}-01-01`:`${i}-${String(a+2).padStart(2,"0")}-01`,label:`${wt[a][0].toUpperCase()}${wt[a].slice(1)} ${i}`}}let s=e.match(/^(\d{4})-(\d{2})$/);if(s){let i=parseInt(s[1],10),a=parseInt(s[2],10)-1;return a<0||a>11?null:{start:`${i}-${String(a+1).padStart(2,"0")}-01`,end:a===11?`${i+1}-01-01`:`${i}-${String(a+2).padStart(2,"0")}-01`,label:`${wt[a][0].toUpperCase()}${wt[a].slice(1)} ${i}`}}let n=wt.indexOf(e.toLowerCase()),r=n===-1?qy.indexOf(e.toLowerCase()):-1,o=n!==-1?n:r;if(o!==-1){let i=t.getFullYear();return{start:`${i}-${String(o+1).padStart(2,"0")}-01`,end:o===11?`${i+1}-01-01`:`${i}-${String(o+2).padStart(2,"0")}-01`,label:`${wt[o][0].toUpperCase()}${wt[o].slice(1)} ${i}`}}return null}function Vy(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=Ky(e);if(!s){process.stderr.write(`invalid month format: ${e}. Use YYYY-MM, month name, or abbreviation.
1653
1754
  `),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
1654
1755
  WHERE recalled_at >= ? AND recalled_at < ?
1655
- GROUP BY session_id ORDER BY c DESC LIMIT 1`).get(s.start,s.end),l="None";if(a){let B=n.prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(a.session_id),y=n.prepare("SELECT auto_title, first_user_message, id FROM sessions WHERE id = ?").get(a.session_id);l=B?.alias||y?.auto_title||y?.first_user_message?.slice(0,40)||a.session_id.slice(0,8)}let c=n.prepare("SELECT COALESCE(MAX(token_count), 0) AS m FROM recall_events WHERE recalled_at >= ? AND recalled_at < ?").get(s.start,s.end).m,u=n.prepare(`SELECT CAST(strftime('%H', started_at) AS INTEGER) AS h, COUNT(*) AS c
1756
+ GROUP BY session_id ORDER BY c DESC LIMIT 1`).get(s.start,s.end),l="None";if(a){let B=n.prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(a.session_id),T=n.prepare("SELECT auto_title, first_user_message, id FROM sessions WHERE id = ?").get(a.session_id);l=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
1656
1757
  FROM sessions WHERE started_at >= ? AND started_at < ?
1657
- GROUP BY h ORDER BY c DESC LIMIT 3`).all(s.start,s.end),p=wT(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
1758
+ GROUP BY h ORDER BY c DESC LIMIT 3`).all(s.start,s.end),m=Vy(u.map(B=>B.h)),p=n.prepare("SELECT COUNT(DISTINCT session_id) AS c FROM recall_events WHERE recalled_at >= ? AND recalled_at < ?").get(s.start,s.end).c,f=n.prepare(`SELECT COUNT(*) AS cnt, COALESCE(AVG(message_count), 0) AS avg_msgs
1658
1759
  FROM sessions WHERE started_at >= ? AND started_at < ?`).get(s.start,s.end),g=n.prepare(`SELECT COUNT(*) AS c FROM sessions
1659
1760
  WHERE started_at >= ? AND started_at < ?
1660
1761
  AND (CAST(strftime('%H', started_at) AS INTEGER) >= 22
1661
1762
  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
1662
1763
  FROM session_tags st JOIN sessions s ON s.id = st.session_id
1663
1764
  WHERE s.started_at >= ? AND s.started_at < ?
1664
- 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=Qd(E),S=50;try{let{computeAllHealthScores:B}=await Promise.resolve().then(()=>(Hr(),Tl)),y=B();y.length>0&&(S=Math.round(y.reduce((U,M)=>U+M.score,0)/y.length))}catch{}let C=t.verdict??"";if(!t.verdict){let B=_T({input:process.stdin,output:process.stderr});C=await new Promise(y=>{B.question("Add your take (one line, or press Enter to skip): ",U=>{B.close(),y(U.trim())})})}let R={month:s.label,totalRecalls:r,totalTokensPiped:o,sessionsIndexed:i,mostRecalledSession:l,biggestRecallTokens:c,healthScore:S,mostActiveHours:p,archetype:b,verdict:C},L=await ln("E",R),Q=s.start.slice(0,7),v=t.out??eu(ST(),"Downloads");ET(v)||bT(v,{recursive:!0});let ee=eu(v,`recall-wrapped-${Q}.png`);hT(ee,L),process.stderr.write(`Wrapped card saved to ${ee}
1665
- `)}_e();Pt();import{createRequire as xT}from"node:module";import{createInterface as RT}from"node:readline";import{stdin as kT,stdout as NT}from"node:process";var CT=xT(import.meta.url),LT=CT(`${Te()}/package.json`).version,ru="https://clauderecall.com/api/feedback",io=process.env.RECALL_FEEDBACK_API??ru,su=io===ru,ao=2e3;function ou(e){let t=RT({input:kT,output:NT});return new Promise(s=>t.question(e,n=>{t.close(),s(n.trim())}))}function nu(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 OT(e){if(e.score!==void 0){let n=nu(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 ou("Score (1-5, q to quit): ");if(t.toLowerCase()==="q"||t==="")return console.log("No worries, skipped."),null;let s=nu(t);return s===null?(console.error("Please enter an integer 1 through 5."),null):s}async function AT(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 ou(s)}function IT(e){return e.length<=ao?{value:e,truncated:!1}:{value:e.slice(0,ao),truncated:!0}}async function iu(e={}){su||process.stderr.write(`[recall] RECALL_FEEDBACK_API override active (${io}); license token will NOT be sent.
1666
- `);let t=await OT(e);if(t===null)return e.score!==void 0||!process.stdin.isTTY?1:0;let s=await AT(e,t),{value:n,truncated:r}=IT(s);r&&process.stderr.write(`[recall] --message truncated to ${ao} characters before send.
1667
- `);let o=await ye(),i=jt(),a=su&&o.tier==="pro"&&i?i.license_jwt:null,l={score:t,comment:n.length>0?n:null,surface:"cli",version:LT,os:process.platform,trigger_kind:"manual",license_jwt:a};try{let c=await fetch(io,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(l)});if(c.ok)return console.log(""),console.log("Thanks. Your feedback landed."),0;let u=await c.json().catch(()=>({}));return c.status===429?(console.log("You submitted feedback recently. Try again later."),0):(console.error(`Feedback failed: ${c.status} ${u.error??"unknown"}`),1)}catch(c){let u=c instanceof Error?c.message:"network error";return console.error(`Feedback could not be sent: ${u}`),1}}var Rw=ww(import.meta.url),bo=Rw("../package.json").version,k=new xw;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(bo);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 Yo(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=>{qo(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)=>{ti(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 gi(e.join(" "),t)});k.command("projects").description("List every project with how many sessions are in each.").action(()=>{Ei()});k.command("status").description("Show database size, session counts, and whether the daemon is running.").action(()=>{hi()});k.command("start").description("Start the background daemon. Required for live tab-name tracking and the web UI.").action(async()=>{await Es()});k.command("stop").description("Stop the background daemon.").action(async()=>{await Si()});k.command("open").description("Open the local web UI in your browser. Starts the daemon if it is not already running.").action(async()=>{await yi()});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(()=>(Fu(),Pu));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 Xi(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 Ji({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 Gi(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 zi(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 qi(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 sa(e)});k.command("semantic [action] [subAction]").description('Manage semantic search. Defaults to "status". Actions: on, off, status, backfill, pause, resume, install, uninstall, reindex, auto-extract <on|off>.').option("-n, --limit <n>","max sessions to process during backfill","1000").option("-f, --force","regenerate summaries even when one already exists").option("--rate <perMin>","sessions per minute when enabling").option("--model <name>","claude model id (e.g. claude-haiku-4-5-20251001)").action(async(e,t,s)=>{await Aa(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 Da(e,t)});var ns=k.command("infer").description("Discover links between sessions. Subcommands: outputs | citations | l1 | links | bug-patterns.");function Hu(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 Wa(t)})}function Wu(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 Qa(t)})}function Xu(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 sc(t)})}function Ju(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 lc(t)})}function Gu(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 Sc(t)})}Hu(ns.command("outputs"));Wu(ns.command("citations"));Xu(ns.command("l1"));Ju(ns.command("links"));Gu(ns.command("bug-patterns"));Hu(k.command("extract-outputs"));Wu(k.command("infer-citations"));Xu(k.command("infer-l1"));Ju(k.command("infer-links"));Gu(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 Ic(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(()=>(_e(),gs));await s("Similar sessions");let{isModelInstalled:n}=await Promise.resolve().then(()=>(Cs(),wa)),{loadEmbedder:r,getEmbedderStatus:o}=await Promise.resolve().then(()=>(Ve(),ir)),{findSimilarSessions:i}=await Promise.resolve().then(()=>(Bu(),Uu));if(!n()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}o().loaded||await r();let a=Math.max(1,Math.min(50,Number(t.limit??10))),l=await i(e,a);if(l.length===0){console.log("No similar sessions found.");return}for(let c of l)console.log(` ${c.sessionId} similarity=${c.similarity.toFixed(3)}`)});k.command("stats [id]").description("How much you have spent and how many tokens you have used. No args = overview. Pass a session id for one session, or --project for one project.").option("-p, --project <name>","show stats for a single project").option("-d, --days <n>","restrict the overview to the last N days (7 or 30)").option("--backfill","compute usage for already-indexed messages (safe to rerun)").option("-n, --limit <n>","max messages to scan during backfill").option("--json","emit JSON instead of a formatted table").action(async(e,t)=>{await Fc(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 Wc(e,t)});var So=k.command("correlator").description("Diagnose and fix terminal-to-session matching. Subcommands: audit | debug | restore.");function zu(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 ul(t)})}function Yu(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 pl(t)})}function qu(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 Kc(t)})}zu(So.command("debug"));Yu(So.command("restore"));qu(So.command("audit"));zu(k.command("correlator-debug"));Yu(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 al(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 ol(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 il(e);process.exit(t)});qu(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 ml(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 _l(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 yl(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)=>{xl(e,t)});k.command("verify [action]").description('Toggle verification badges in the UI. Defaults to "status". Actions: on, off, status.').action(e=>{Rl(e)});k.command("activate <license-key>").description("Activate your Pro license. Run once after purchase.").action(async e=>{await $l(e)});k.command("upgrade").description("Open the Pro pricing page in your browser.").action(async()=>{await jl()});k.command("trial").description("Start a 7-day Pro trial. Opens the signup page in your browser. No card required.").action(async()=>{await Fl()});var gn=k.command("telemetry").description('Manage the opt-in anonymous install ping. Defaults to "view".');gn.command("view",{isDefault:!0}).description("Show current decision, state file path, and next-ping payload.").action(async()=>{await zl()});gn.command("on").description("Opt in. One anonymous ping per machine per month. See https://clauderecall.com/telemetry").action(async()=>{await Jl()});gn.command("off").description("Opt out. Deletes the nonce. No further pings.").action(async()=>{await Gl()});gn.command("status").description("Alias for view.").action(async()=>{await Yr()});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 Kl()});yo.command("deactivate").description("Remove the stored license from this machine. Reverses `recall activate`.").action(()=>{Zl()});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 Vl()});var kw=k.command("thread").description("Group related sessions into threads, then list, show, link, merge, or scan them."),Nw=k.command("threads").description("Alias for `thread`. Both forms accept the same subcommands.");function Ku(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 Id(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=>{Od(t)}),e.command("list").description("List threads, newest first.").option("--archived","include archived threads").option("--json","emit JSON instead of a table").action(t=>{ed(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)=>{td(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)=>{sd(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)=>{nd(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)=>{rd(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)=>{od(t,s)}),e.command("rename <id-prefix> <new-name>").description("Rename a thread.").option("--json","emit JSON").action((t,s,n)=>{id(t,s,n)}),e.command("close <id-prefix>").description("Mark a thread as closed (work complete).").option("--json","emit JSON").action((t,s)=>{ad(t,s)}),e.command("reopen <id-prefix>").description("Reopen a closed thread.").option("--json","emit JSON").action((t,s)=>{cd(t,s)}),e.command("archive <id-prefix>").description("Archive a thread (hidden from the default list).").option("--json","emit JSON").action((t,s)=>{ld(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)=>{dd(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)=>{ud(t,s)})}Ku(kw);Ku(Nw);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 Zd(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 iu(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 tu(e,t)});process.env.CLAUDECODE&&process.stderr.write(`<claude-code-hint v="1" type="plugin" value="claude-recall@claude-plugins-official" />
1668
- `);k.action(async()=>{await vl()});k.hook("preAction",async(e,t)=>{let s=t.name();try{await ql(s,bo)}catch{}Xl(bo).catch(()=>{})});k.parseAsync(process.argv).catch(e=>{console.error(e),process.exit(1)});
1765
+ AND (st.tag LIKE '%debug%' OR st.tag LIKE '%fix%' OR st.tag LIKE '%bug%' OR st.tag LIKE '%error%')`).get(s.start,s.end).c,E={recallCount:r,uniqueSessionsRecalled:p,sessionCount:f.cnt,avgMessageCount:f.avg_msgs,nightSessionRatio:f.cnt>0?g/f.cnt:0,debugTagRatio:f.cnt>0?h/f.cnt:0},b=hu(E),S=50;try{let{computeAllHealthScores:B}=await Promise.resolve().then(()=>(qr(),Ul)),T=B();T.length>0&&(S=Math.round(T.reduce((U,M)=>U+M.score,0)/T.length))}catch{}let N=t.verdict??"";if(!t.verdict){let B=Xy({input:process.stdin,output:process.stderr});N=await new Promise(T=>{B.question("Add your take (one line, or press Enter to skip): ",U=>{B.close(),T(U.trim())})})}let y={month:s.label,totalRecalls:r,totalTokensPiped:o,sessionsIndexed:i,mostRecalledSession:l,biggestRecallTokens:c,healthScore:S,mostActiveHours:m,archetype:b,verdict:N},C=await gn("E",y),q=s.start.slice(0,7),I=t.out??Eu(zy(),"Downloads");Gy(I)||Yy(I,{recursive:!0});let ee=Eu(I,`recall-wrapped-${q}.png`);Jy(ee,C),process.stderr.write(`Wrapped card saved to ${ee}
1766
+ `)}_e();Pt();import{createRequire as Zy}from"node:module";import{createInterface as Qy}from"node:readline";import{stdin as ew,stdout as tw}from"node:process";var sw=Zy(import.meta.url),nw=sw(`${ye()}/package.json`).version,yu="https://clauderecall.com/api/feedback",go=process.env.RECALL_FEEDBACK_API??yu,Su=go===yu,fo=2e3;function wu(e){let t=Qy({input:ew,output:tw});return new Promise(s=>t.question(e,n=>{t.close(),s(n.trim())}))}function Tu(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 rw(e){if(e.score!==void 0){let n=Tu(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 wu("Score (1-5, q to quit): ");if(t.toLowerCase()==="q"||t==="")return console.log("No worries, skipped."),null;let s=Tu(t);return s===null?(console.error("Please enter an integer 1 through 5."),null):s}async function ow(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 wu(s)}function iw(e){return e.length<=fo?{value:e,truncated:!1}:{value:e.slice(0,fo),truncated:!0}}async function Ru(e={}){Su||process.stderr.write(`[recall] RECALL_FEEDBACK_API override active (${go}); license token will NOT be sent.
1767
+ `);let t=await rw(e);if(t===null)return e.score!==void 0||!process.stdin.isTTY?1:0;let s=await ow(e,t),{value:n,truncated:r}=iw(s);r&&process.stderr.write(`[recall] --message truncated to ${fo} characters before send.
1768
+ `);let o=await Te(),i=jt(),a=Su&&o.tier==="pro"&&i?i.license_jwt:null,l={score:t,comment:n.length>0?n:null,surface:"cli",version:nw,os:process.platform,trigger_kind:"manual",license_jwt:a};try{let c=await fetch(go,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(l)});if(c.ok)return console.log(""),console.log("Thanks. Your feedback landed."),0;let u=await c.json().catch(()=>({}));return c.status===429?(console.log("You submitted feedback recently. Try again later."),0):(console.error(`Feedback failed: ${c.status} ${u.error??"unknown"}`),1)}catch(c){let u=c instanceof Error?c.message:"network error";return console.error(`Feedback could not be sent: ${u}`),1}}var Qw=Vw(import.meta.url),rs=Qw("../package.json").version,k=new Zw;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(rs);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 ei(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=>{ti(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)=>{ai(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 Si(e.join(" "),t)});k.command("projects").description("List every project with how many sessions are in each.").action(()=>{Ri()});k.command("status").description("Show database size, session counts, and whether the daemon is running.").action(()=>{wi()});k.command("start").description("Start the background daemon. Required for live tab-name tracking and the web UI.").action(async()=>{await Ss()});k.command("stop").description("Stop the background daemon.").action(async()=>{await Ni()});k.command("open").description("Open the local web UI in your browser. Starts the daemon if it is not already running.").action(async()=>{await Li()});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(()=>(nm(),sm));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 Vi(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 Zi({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 Qi(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 ea(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 sa(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 la(e)});k.command("semantic [action] [subAction]").description('Manage semantic search. Defaults to "status". Actions: on, off, status, backfill, pause, resume, install, uninstall, reindex, auto-extract <on|off>.').option("-n, --limit <n>","max sessions to process during backfill","1000").option("-f, --force","regenerate summaries even when one already exists").option("--rate <perMin>","sessions per minute when enabling").option("--model <name>","claude model id (e.g. claude-haiku-4-5-20251001)").addHelpText("after",`
1769
+ Reindex chunks-per-session cap (advanced):
1770
+ Set RECALL_REINDEX_MAX_CHUNKS=200 to cap each session at 200 chunks for a
1771
+ faster first pass. Default is 0 (no cap, full accuracy).
1772
+ `).action(async(e,t,s)=>{await Pa(e,{...s,_autoExtractAction:t})});k.command("embeddings [action]").description('Audit embedding coverage and backfill missing ones. Defaults to "audit". Actions: audit, backfill-summaries, backfill-messages.').option("-p, --project <name>","scope to a single project").option("-n, --limit <n>","max sessions to process during backfill").option("--json","emit JSON instead of formatted output").action(async(e,t)=>{await Wa(e,t)});var os=k.command("infer").description("Discover links between sessions. Subcommands: outputs | citations | l1 | links | bug-patterns.");function im(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 Ka(t)})}function am(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 ic(t)})}function cm(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 lc(t)})}function lm(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 dm(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 Nc(t)})}im(os.command("outputs"));am(os.command("citations"));cm(os.command("l1"));lm(os.command("links"));dm(os.command("bug-patterns"));im(k.command("extract-outputs"));am(k.command("infer-citations"));cm(k.command("infer-l1"));lm(k.command("infer-links"));dm(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 Fc(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(()=>(_e(),_s));await s("Similar sessions");let{isModelInstalled:n}=await Promise.resolve().then(()=>(As(),Aa)),{loadEmbedder:r,getEmbedderStatus:o}=await Promise.resolve().then(()=>(Ve(),ur)),{findSimilarSessions:i}=await Promise.resolve().then(()=>(om(),rm));if(!n()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}o().loaded||await r();let a=Math.max(1,Math.min(50,Number(t.limit??10))),l=await i(e,a);if(l.length===0){console.log("No similar sessions found.");return}for(let c of l)console.log(` ${c.sessionId} similarity=${c.similarity.toFixed(3)}`)});k.command("stats [id]").description("How much you have spent and how many tokens you have used. No args = overview. Pass a session id for one session, or --project for one project.").option("-p, --project <name>","show stats for a single project").option("-d, --days <n>","restrict the overview to the last N days (7 or 30)").option("--backfill","compute usage for already-indexed messages (safe to rerun)").option("-n, --limit <n>","max messages to scan during backfill").option("--json","emit JSON instead of a formatted table").action(async(e,t)=>{await Gc(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 Kc(e,t)});var ko=k.command("correlator").description("Diagnose and fix terminal-to-session matching. Subcommands: audit | debug | restore.");function um(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 Cl(t)})}function mm(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 Al(t)})}function pm(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 nl(t)})}um(ko.command("debug"));mm(ko.command("restore"));pm(ko.command("audit"));um(k.command("correlator-debug"));mm(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 ml(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 pl(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 Rl({_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)});pm(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 Ol(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 Ml(e)});k.command("install-extension").description("Install the bundled VS Code / Cursor / Windsurf extension into your editor. Auto-detects which CLIs are installed.").option("--editor <name>","install only into one editor: code | cursor | code-insiders | windsurf").option("--print-path","print the path to the bundled .vsix and exit").action(async e=>{await Fl(e)});k.command("health [project]").description("Score how well-organized each project's sessions are. Worst first, or pass a project name for a single breakdown.").option("--json","emit JSON instead of formatted output").action((e,t)=>{Hl(e,t)});k.command("verify [action]").description('Toggle verification badges in the UI. Defaults to "status". Actions: on, off, status.').action(e=>{Wl(e)});k.command("activate <license-key>").description("Activate your Pro license. Run once after purchase.").action(async e=>{await Ql(e)});k.command("upgrade").description("Open the Pro pricing page in your browser.").action(async()=>{await td()});k.command("trial").description("Start a 7-day Pro trial. Opens the signup page in your browser. No card required.").action(async()=>{await nd()});var bn=k.command("telemetry").description('Manage the opt-in anonymous install ping. Defaults to "view".');bn.command("view",{isDefault:!0}).description("Show current decision, state file path, and next-ping payload.").action(async()=>{await ud(rs)});bn.command("on").description("Opt in. One anonymous ping per machine per month. See https://clauderecall.com/telemetry").action(async()=>{await ld()});bn.command("off").description("Opt out. Deletes the nonce. No further pings.").action(async()=>{await dd()});bn.command("status").description("Alias for view.").action(async()=>{await to(rs)});var No=k.command("license").description('Show or remove the Pro license on this machine. Defaults to "status".');No.command("status",{isDefault:!0}).description("Show the current license tier.").action(async()=>{await gd()});No.command("deactivate").description("Remove the stored license from this machine. Reverses `recall activate`.").action(()=>{_d()});No.command("check").description("Force a revocation check against the license server. The daemon also runs this on a 24-hour timer in the background.").action(async()=>{await fd()});var eR=k.command("thread").description("Group related sessions into threads, then list, show, link, merge, or scan them."),tR=k.command("threads").description("Alias for `thread`. Both forms accept the same subcommands.");function gm(e){e.command("sync").description("Capture sessions running in this repo right now into a thread.").option("--preflight","preview the plan without writing").option("-p, --project <name>","override the cwd-based project").option("--window-hours <n>","rolling activity window (default 6)").option("--json","machine-readable JSON output").action(async t=>{await Kd(t)}),e.command("scan").description("Auto-detect parent-child links across past sessions. Dry-run by default; pass --apply to write.").option("-p, --project <name>","scope to a single project").option("--json","emit JSON instead of formatted output").option("--apply","write edges (default: dry-run preview)").option("--confidence-min <n>","override threshold (dry-run 0.5, apply 0.7)").option("--no-llm-names","skip LLM naming (free, offline)").option("--llm-rescore","LLM re-score borderline pairs (small Haiku call each)").option("--rescore-band-lo <n>","low end of the borderline band (default 0.4)").option("--rescore-band-hi <n>","high end of the borderline band (default 0.7)").option("--rescore-model <id>","model id for the rescore call (default Haiku 4.5)").action(t=>{zd(t)}),e.command("list").description("List threads, newest first.").option("--archived","include archived threads").option("--json","emit JSON instead of a table").action(t=>{Ed(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)=>{Sd(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)=>{Td(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)=>{yd(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)=>{wd(t,s)}),e.command("rename <id-prefix> <new-name>").description("Rename a thread.").option("--json","emit JSON").action((t,s,n)=>{Rd(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)=>{kd(t,s)}),e.command("archive <id-prefix>").description("Archive a thread (hidden from the default list).").option("--json","emit JSON").action((t,s)=>{Nd(t,s)}),e.command("merge <source-id-prefix>").description("Merge one thread into another.").requiredOption("--into <id-prefix>","destination thread").option("--json","emit JSON").action((t,s)=>{Ld(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)=>{Cd(t,s)})}gm(eR);gm(tR);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 _u(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 Ru(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 bu(e,t)});process.env.CLAUDECODE&&process.stderr.write(`<claude-code-hint v="1" type="plugin" value="claude-recall@claude-plugins-official" />
1773
+ `);k.action(async()=>{await Vl()});k.hook("preAction",async(e,t)=>{let s=t.name();try{await pd(s,rs)}catch{}cd(rs).catch(()=>{})});k.parseAsync(process.argv).catch(e=>{console.error(e),process.exit(1)});