@clauderecallhq/cli 0.95.11 → 0.95.12

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 E_=Object.defineProperty;var w=(e,t)=>()=>(e&&(t=e(e=0)),t);var V=(e,t)=>{for(var n in t)E_(e,n,{get:t[n],enumerable:!0})};import{createRequire as b_}from"node:module";var S_,y_,w_,Wr,Xr,Pt,Jn=w(()=>{"use strict";{let e=process.emit.bind(process);process.emit=function(t,...n){let s=n[0];return t==="warning"&&s instanceof Error&&s.name==="ExperimentalWarning"&&/SQLite/i.test(s.message)?!1:e(t,...n)}}S_=b_(import.meta.url),y_=["node","sqlite"].join(":"),w_=S_(y_),Wr=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 n=t.length===0?this.inner.run():this.inner.run(...t);return{changes:n.changes,lastInsertRowid:n.lastInsertRowid}}iterate(...t){return t.length===0?this.inner.iterate():this.inner.iterate(...t)}},Xr=class{inner;extensionLoadingEnabled=!1;txDepth=0;constructor(t,n={}){this.inner=new w_.DatabaseSync(t,{readOnly:n.readonly??!1,allowExtension:!0})}prepare(t){return new Wr(this.inner.prepare(t))}exec(t){this.inner.exec(t)}close(){this.inner.close()}pragma(t,n={}){if(t.includes("=")){this.inner.exec(`PRAGMA ${t}`);return}if(n.simple){let s=this.inner.prepare(`PRAGMA ${t}`).get();return s&&typeof s=="object"?Object.values(s)[0]:void 0}return this.inner.prepare(`PRAGMA ${t}`).all()}transaction(t){return((...s)=>{this.txDepth===0?this.inner.exec("BEGIN"):this.inner.exec(`SAVEPOINT sp_${this.txDepth}`),this.txDepth+=1;try{let r=t(...s);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,n){this.extensionLoadingEnabled||(this.inner.enableLoadExtension(!0),this.extensionLoadingEnabled=!0),n===void 0?this.inner.loadExtension(t):this.inner.loadExtension(t,n)}},Pt=Xr});import{homedir as ja}from"node:os";import{join as an,basename as T_}from"node:path";import{existsSync as Ua,mkdirSync as R_,chmodSync as k_,readdirSync as Fa,statSync as x_}from"node:fs";function j(){Ua(C)||R_(C,{recursive:!0,mode:448}),process.platform!=="win32"&&k_(C,448)}function Gr(e){return e.replace(/^-/,"/").replace(/-/g,"/")}function Ba(e){let t=Gr(e);return T_(t)||t}function Ha(){if(!Ua(Ft))return[];let e=[],t=Fa(Ft,{withFileTypes:!0}).filter(n=>n.isDirectory()).map(n=>n.name);for(let n of t){let s=an(Ft,n),r=Fa(s,{withFileTypes:!0});for(let o of r){if(!o.isFile()||!o.name.endsWith(".jsonl"))continue;let i=an(s,o.name),a=x_(i);e.push({sessionFile:i,encodedProject:n,mtime:a.mtimeMs,size:a.size})}}return e}var Ft,C,ee,I=w(()=>{"use strict";Ft=process.env.CLAUDE_PROJECTS_DIR?process.env.CLAUDE_PROJECTS_DIR:an(ja(),".claude","projects"),C=process.env.RECALL_HOME?process.env.RECALL_HOME:an(ja(),".recall"),ee=an(C,"db.sqlite")});function Xa(e){let t=e.prepare("PRAGMA table_info(sessions)").all(),n=new Set(t.map(_=>_.name)),s=[["total_input_tokens","INTEGER"],["total_output_tokens","INTEGER"],["total_cache_create_tokens","INTEGER"],["total_cache_read_tokens","INTEGER"],["primary_model","TEXT"],["auto_title","TEXT"],["auto_title_source","TEXT"],["auto_title_generated_at","INTEGER"],["auto_title_history","TEXT"],["verification_status","TEXT"],["verification_computed_at","INTEGER"],["title_quality","TEXT"],["title_quality_computed_at","INTEGER"],["archive_status","TEXT NOT NULL DEFAULT 'live'"],["archived_at","TEXT"],["skipped_reason","TEXT"]];for(let[_,b]of s)n.has(_)||e.exec(`ALTER TABLE sessions ADD COLUMN ${_} ${b}`);let r=e.prepare("PRAGMA table_info(collection_sessions)").all(),o=new Set(r.map(_=>_.name)),i=[["source","TEXT NOT NULL DEFAULT 'manual'"],["rule_id","TEXT"]];for(let[_,b]of i)o.has(_)||e.exec(`ALTER TABLE collection_sessions ADD COLUMN ${_} ${b}`);let a=e.prepare("PRAGMA table_info(session_notes)").all(),d=new Set(a.map(_=>_.name)),l=[["auto_synopsis","TEXT"],["auto_synopsis_generated_at","INTEGER"],["auto_synopsis_history","TEXT"]];for(let[_,b]of l)d.has(_)||e.exec(`ALTER TABLE session_notes ADD COLUMN ${_} ${b}`);let u=e.prepare("PRAGMA table_info(threads)").all();new Set(u.map(_=>_.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(_=>_.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(`
3
+ var N_=Object.defineProperty;var w=(e,t)=>()=>(e&&(t=e(e=0)),t);var V=(e,t)=>{for(var n in t)N_(e,n,{get:t[n],enumerable:!0})};import{createRequire as O_}from"node:module";var v_,I_,M_,Gr,Jr,Pt,Yn=w(()=>{"use strict";{let e=process.emit.bind(process);process.emit=function(t,...n){let s=n[0];return t==="warning"&&s instanceof Error&&s.name==="ExperimentalWarning"&&/SQLite/i.test(s.message)?!1:e(t,...n)}}v_=O_(import.meta.url),I_=["node","sqlite"].join(":"),M_=v_(I_),Gr=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 n=t.length===0?this.inner.run():this.inner.run(...t);return{changes:n.changes,lastInsertRowid:n.lastInsertRowid}}iterate(...t){return t.length===0?this.inner.iterate():this.inner.iterate(...t)}},Jr=class{inner;extensionLoadingEnabled=!1;txDepth=0;constructor(t,n={}){this.inner=new M_.DatabaseSync(t,{readOnly:n.readonly??!1,allowExtension:!0})}prepare(t){return new Gr(this.inner.prepare(t))}exec(t){this.inner.exec(t)}close(){this.inner.close()}pragma(t,n={}){if(t.includes("=")){this.inner.exec(`PRAGMA ${t}`);return}if(n.simple){let s=this.inner.prepare(`PRAGMA ${t}`).get();return s&&typeof s=="object"?Object.values(s)[0]:void 0}return this.inner.prepare(`PRAGMA ${t}`).all()}transaction(t){return((...s)=>{this.txDepth===0?this.inner.exec("BEGIN"):this.inner.exec(`SAVEPOINT sp_${this.txDepth}`),this.txDepth+=1;try{let r=t(...s);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,n){this.extensionLoadingEnabled||(this.inner.enableLoadExtension(!0),this.extensionLoadingEnabled=!0),n===void 0?this.inner.loadExtension(t):this.inner.loadExtension(t,n)}},Pt=Jr});import{homedir as Xa}from"node:os";import{join as an,basename as D_}from"node:path";import{existsSync as Ga,mkdirSync as $_,chmodSync as P_,readdirSync as Wa,statSync as F_}from"node:fs";function j(){Ga(C)||$_(C,{recursive:!0,mode:448}),process.platform!=="win32"&&P_(C,448)}function zr(e){return e.replace(/^-/,"/").replace(/-/g,"/")}function Ja(e){let t=zr(e);return D_(t)||t}function za(){if(!Ga(Ft))return[];let e=[],t=Wa(Ft,{withFileTypes:!0}).filter(n=>n.isDirectory()).map(n=>n.name);for(let n of t){let s=an(Ft,n),r=Wa(s,{withFileTypes:!0});for(let o of r){if(!o.isFile()||!o.name.endsWith(".jsonl"))continue;let i=an(s,o.name),a=F_(i);e.push({sessionFile:i,encodedProject:n,mtime:a.mtimeMs,size:a.size})}}return e}var Ft,C,ee,I=w(()=>{"use strict";Ft=process.env.CLAUDE_PROJECTS_DIR?process.env.CLAUDE_PROJECTS_DIR:an(Xa(),".claude","projects"),C=process.env.RECALL_HOME?process.env.RECALL_HOME:an(Xa(),".recall"),ee=an(C,"db.sqlite")});function qa(e){let t=e.prepare("PRAGMA table_info(sessions)").all(),n=new Set(t.map(b=>b.name)),s=[["total_input_tokens","INTEGER"],["total_output_tokens","INTEGER"],["total_cache_create_tokens","INTEGER"],["total_cache_read_tokens","INTEGER"],["primary_model","TEXT"],["auto_title","TEXT"],["auto_title_source","TEXT"],["auto_title_generated_at","INTEGER"],["auto_title_history","TEXT"],["verification_status","TEXT"],["verification_computed_at","INTEGER"],["title_quality","TEXT"],["title_quality_computed_at","INTEGER"],["archive_status","TEXT NOT NULL DEFAULT 'live'"],["archived_at","TEXT"],["skipped_reason","TEXT"]];for(let[b,E]of s)n.has(b)||e.exec(`ALTER TABLE sessions ADD COLUMN ${b} ${E}`);let r=e.prepare("PRAGMA table_info(collection_sessions)").all(),o=new Set(r.map(b=>b.name)),i=[["source","TEXT NOT NULL DEFAULT 'manual'"],["rule_id","TEXT"]];for(let[b,E]of i)o.has(b)||e.exec(`ALTER TABLE collection_sessions ADD COLUMN ${b} ${E}`);let a=e.prepare("PRAGMA table_info(session_notes)").all(),d=new Set(a.map(b=>b.name)),l=[["auto_synopsis","TEXT"],["auto_synopsis_generated_at","INTEGER"],["auto_synopsis_history","TEXT"]];for(let[b,E]of l)d.has(b)||e.exec(`ALTER TABLE session_notes ADD COLUMN ${b} ${E}`);let u=e.prepare("PRAGMA table_info(threads)").all();new Set(u.map(b=>b.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(b=>b.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 E_=Object.defineProperty;var w=(e,t)=>()=>(e&&(t=e(e=0)),t);var V=(e,t)=>{fo
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
- `);let g=e.prepare("PRAGMA table_info(projects)").all(),f=new Set(g.map(_=>_.name)),h=[["repo_root","TEXT"],["main_repo","TEXT"],["is_repo","INTEGER NOT NULL DEFAULT 0"],["is_worktree","INTEGER NOT NULL DEFAULT 0"]];for(let[_,b]of h)f.has(_)||e.exec(`ALTER TABLE projects ADD COLUMN ${_} ${b}`)}var Wa,Ga=w(()=>{"use strict";Wa=`
15
+ `);let g=e.prepare("PRAGMA table_info(projects)").all(),f=new Set(g.map(b=>b.name)),_=[["repo_root","TEXT"],["main_repo","TEXT"],["is_repo","INTEGER NOT NULL DEFAULT 0"],["is_worktree","INTEGER NOT NULL DEFAULT 0"]];for(let[b,E]of _)f.has(b)||e.exec(`ALTER TABLE projects ADD COLUMN ${b} ${E}`)}var Ya,Va=w(()=>{"use strict";Ya=`
16
16
  PRAGMA journal_mode = WAL;
17
17
  PRAGMA synchronous = NORMAL;
18
18
  PRAGMA foreign_keys = ON;
@@ -749,23 +749,23 @@ CREATE TABLE IF NOT EXISTS file_cursor (
749
749
  mtime REAL,
750
750
  updated_at TEXT NOT NULL DEFAULT (datetime('now'))
751
751
  );
752
- `});function za(e,t){let n=t.RECALL_DB_PROFILE;if(n&&C_.has(n))return n;let s=(e??"").split(/[\\/]/).pop()??"";return s==="mcp-server.js"||s==="claude-recall-mcp"?"light":s==="query-worker.js"?"worker":"full"}function Ja(e){let t=[["busy_timeout",15e3],["journal_size_limit",67108864],["wal_autocheckpoint",1e3]];return e==="full"?[["cache_size",-64e3],["mmap_size",268435456],...t]:e==="worker"?[["cache_size",-16e3],["mmap_size",0],...t]:[["cache_size",-4e3],["mmap_size",0],...t]}var C_,Ya=w(()=>{"use strict";C_=new Set(["light","full","worker"])});import*as Va from"sqlite-vec";function lt(e){let t=e;qa.has(t)||(Va.load(e),qa.add(t))}function Ka(e){e.prepare("SELECT 1 FROM sqlite_master WHERE name = 'vec_chunks'").get()||(lt(e),e.exec(L_))}var qa,L_,Yn=w(()=>{"use strict";qa=new WeakSet;L_=`
752
+ `});function Ka(e,t){let n=t.RECALL_DB_PROFILE;if(n&&j_.has(n))return n;let s=(e??"").split(/[\\/]/).pop()??"";return s==="mcp-server.js"||s==="claude-recall-mcp"?"light":s==="query-worker.js"?"worker":"full"}function Qa(e){let t=[["busy_timeout",15e3],["journal_size_limit",67108864],["wal_autocheckpoint",1e3]];return e==="full"?[["cache_size",-64e3],["mmap_size",268435456],...t]:e==="worker"?[["cache_size",-16e3],["mmap_size",0],...t]:[["cache_size",-4e3],["mmap_size",0],...t]}var j_,Za=w(()=>{"use strict";j_=new Set(["light","full","worker"])});import*as tc from"sqlite-vec";function lt(e){let t=e;ec.has(t)||(tc.load(e),ec.add(t))}function nc(e){e.prepare("SELECT 1 FROM sqlite_master WHERE name = 'vec_chunks'").get()||(lt(e),e.exec(U_))}var ec,U_,qn=w(()=>{"use strict";ec=new WeakSet;U_=`
753
753
  CREATE VIRTUAL TABLE IF NOT EXISTS vec_chunks USING vec0(
754
754
  embedding float[768] distance_metric=cosine
755
- );`});var qn={};V(qn,{closeDb:()=>A_,getDb:()=>E});function E(){if(K)return K;j();let e=za(process.argv[1],process.env);Qa=e,K=new Pt(ee);for(let[t,n]of Ja(e))K.pragma(`${t} = ${n}`);K.pragma("temp_store = MEMORY"),e!=="light"&&lt(K),K.exec(Wa),Xa(K),Ka(K);try{K.exec("PRAGMA optimize")}catch{}return K}function A_(){if(K){if(Qa==="light"){try{K.pragma("wal_checkpoint(PASSIVE)")}catch{}K.close(),K=null;return}try{K.exec("PRAGMA optimize")}catch{}try{K.exec("INSERT INTO messages_fts(messages_fts, rank) VALUES('merge', 4);")}catch{}try{K.exec("INSERT INTO sessions_fts(sessions_fts, rank) VALUES('merge', 4);")}catch{}try{K.pragma("wal_checkpoint(TRUNCATE)")}catch{}K.close(),K=null}}var K,Qa,k=w(()=>{"use strict";Jn();I();Ga();Ya();Yn();K=null,Qa="full"});import{createReadStream as N_}from"node:fs";import{createInterface as O_}from"node:readline";function Vn(e){return typeof e=="number"&&Number.isFinite(e)?e:0}function Yr(e){let t=e?.usage;if(!t||typeof t!="object")return null;let n={inputTokens:Vn(t.input_tokens),outputTokens:Vn(t.output_tokens),cacheCreateTokens:Vn(t.cache_creation_input_tokens),cacheReadTokens:Vn(t.cache_read_input_tokens)};return n.inputTokens===0&&n.outputTokens===0&&n.cacheCreateTokens===0&&n.cacheReadTokens===0?null:n}function zr(e){return e.replace(v_,"")}function Za(e,t){if(e.length<=Jr)return e;let n=e.slice(0,Jr),s=e.length-Jr;return`${n}
755
+ );`});var Vn={};V(Vn,{closeDb:()=>B_,getDb:()=>h});function h(){if(K)return K;j();let e=Ka(process.argv[1],process.env);sc=e,K=new Pt(ee);for(let[t,n]of Qa(e))K.pragma(`${t} = ${n}`);K.pragma("temp_store = MEMORY"),e!=="light"&&lt(K),K.exec(Ya),qa(K),nc(K);try{K.exec("PRAGMA optimize")}catch{}return K}function B_(){if(K){if(sc==="light"){try{K.pragma("wal_checkpoint(PASSIVE)")}catch{}K.close(),K=null;return}try{K.exec("PRAGMA optimize")}catch{}try{K.exec("INSERT INTO messages_fts(messages_fts, rank) VALUES('merge', 4);")}catch{}try{K.exec("INSERT INTO sessions_fts(sessions_fts, rank) VALUES('merge', 4);")}catch{}try{K.pragma("wal_checkpoint(TRUNCATE)")}catch{}K.close(),K=null}}var K,sc,k=w(()=>{"use strict";Yn();I();Va();Za();qn();K=null,sc="full"});import{createReadStream as H_}from"node:fs";import{createInterface as W_}from"node:readline";function Kn(e){return typeof e=="number"&&Number.isFinite(e)?e:0}function Vr(e){let t=e?.usage;if(!t||typeof t!="object")return null;let n={inputTokens:Kn(t.input_tokens),outputTokens:Kn(t.output_tokens),cacheCreateTokens:Kn(t.cache_creation_input_tokens),cacheReadTokens:Kn(t.cache_read_input_tokens)};return n.inputTokens===0&&n.outputTokens===0&&n.cacheCreateTokens===0&&n.cacheReadTokens===0?null:n}function Yr(e){return e.replace(X_,"")}function rc(e,t){if(e.length<=qr)return e;let n=e.slice(0,qr),s=e.length-qr;return`${n}
756
756
 
757
- \u27E8\u2026 ${s.toLocaleString()} more chars in ${t}; see raw JSONL for full content \u27E9`}function I_(e){try{return JSON.stringify(e,null,2)}catch{return String(e)}}function M_(e){if(typeof e.content=="string")return e.content;if(Array.isArray(e.content)){let t=[];for(let n of e.content)if(n&&typeof n=="object"){let s=n;s.type==="text"&&typeof s.text=="string"?t.push(s.text):s.type==="image"&&t.push("[image]")}return t.join(`
758
- `)}return""}function D_(e){if(!e)return{text:"",toolNames:[]};if(typeof e.content=="string")return{text:zr(e.content),toolNames:[]};if(!Array.isArray(e.content))return{text:"",toolNames:[]};let t=[],n=[];for(let s of e.content)if(!(!s||typeof s!="object")){if(s.type==="text"&&typeof s.text=="string"){t.push(zr(s.text));continue}if(s.type==="tool_use"&&typeof s.name=="string"){n.push(s.name);let r=s.input!=null?I_(s.input):"",o=Za(r,"tool input");t.push(`\u26A1 **Tool call \xB7 \`${s.name}\`**
757
+ \u27E8\u2026 ${s.toLocaleString()} more chars in ${t}; see raw JSONL for full content \u27E9`}function G_(e){try{return JSON.stringify(e,null,2)}catch{return String(e)}}function J_(e){if(typeof e.content=="string")return e.content;if(Array.isArray(e.content)){let t=[];for(let n of e.content)if(n&&typeof n=="object"){let s=n;s.type==="text"&&typeof s.text=="string"?t.push(s.text):s.type==="image"&&t.push("[image]")}return t.join(`
758
+ `)}return""}function z_(e){if(!e)return{text:"",toolNames:[]};if(typeof e.content=="string")return{text:Yr(e.content),toolNames:[]};if(!Array.isArray(e.content))return{text:"",toolNames:[]};let t=[],n=[];for(let s of e.content)if(!(!s||typeof s!="object")){if(s.type==="text"&&typeof s.text=="string"){t.push(Yr(s.text));continue}if(s.type==="tool_use"&&typeof s.name=="string"){n.push(s.name);let r=s.input!=null?G_(s.input):"",o=rc(r,"tool input");t.push(`\u26A1 **Tool call \xB7 \`${s.name}\`**
759
759
 
760
760
  \`\`\`json
761
761
  ${o}
762
- \`\`\``);continue}if(s.type==="tool_result"){let r=zr(M_(s));if(r){let o=Za(r,"tool result");t.push(`**Tool result**
762
+ \`\`\``);continue}if(s.type==="tool_result"){let r=Yr(J_(s));if(r){let o=rc(r,"tool result");t.push(`**Tool result**
763
763
 
764
764
  \`\`\`
765
765
  ${o}
766
766
  \`\`\``)}else t.push("_(tool result was empty or image-only)_");continue}if(s.type==="image"){t.push("_(image)_");continue}t.push(`_(unknown block: ${s.type})_`)}return{text:t.join(`
767
767
 
768
- `),toolNames:n}}function $_(e){if(e.endsWith("\r")&&(e=e.slice(0,-1)),!e.trim())return null;let t;try{t=JSON.parse(e)}catch{return null}if(!t.uuid||!t.sessionId)return null;let{text:n,toolNames:s}=D_(t.message);return{uuid:t.uuid,parentUuid:t.parentUuid??null,sessionId:t.sessionId,type:t.type??"unknown",role:t.message?.role??null,timestamp:t.timestamp??null,isSidechain:t.isSidechain===!0,cwd:t.cwd??null,gitBranch:t.gitBranch??null,version:t.version??null,contentText:n,toolNames:s,raw:e,usage:Yr(t.message),model:t.message?.model??null}}async function*ec(e){let t=N_(e,{encoding:"utf8"}),n=O_({input:t,crlfDelay:1/0});for await(let s of n){let r=$_(s);r!==null&&(yield r)}}var v_,Jr,Kn=w(()=>{"use strict";v_=/\x1B\[[0-9;]*[a-zA-Z]/g;Jr=12e3});import Me from"chalk";import{formatDistanceToNowStrict as P_,parseISO as F_}from"date-fns";function Q(e,t){if(!e)return"";let n=e.replace(/\s+/g," ").trim();return n.length<=t?n:n.slice(0,t-1)+"\u2026"}function G(e){if(!e)return"";try{return P_(F_(e),{addSuffix:!0})}catch{return""}}function X(e){return e.slice(0,8)}function qr(e,t){if(!t)return e;let n=t.split(/\s+/).filter(r=>r.length>1).map(r=>r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));if(n.length===0)return e;let s=new RegExp(`(${n.join("|")})`,"gi");return e.replace(s,r=>Me.bgYellow.black(r))}var c,$=w(()=>{"use strict";c={dim:Me.gray,bold:Me.bold,project:Me.cyan,user:Me.blue,assistant:Me.green,tool:Me.magenta,warn:Me.yellow,err:Me.red,ok:Me.green,accent:Me.hex("#f97316")}});function nc(e){return e===32||e===9||e===10||e===13||e===12||e===11}function rc(e){let t=e.length,n=-1,s=-1,r=0;for(let a=0;a<t;a++)if(nc(e.charCodeAt(a)))r=0;else if(++r>tc){s=a;break}if(s===-1)return e;let o=[],i=0;n=-1;for(let a=0;a<=t;a++){let d=a===t||nc(e.charCodeAt(a));!d&&n===-1?n=a:d&&n!==-1&&(a-n>tc&&(o.push(e.slice(i,n)),o.push(j_),i=a),n=-1)}return o.push(e.slice(i)),o.join("")}function oc(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))),n=e.slice(-Math.min(4,Math.floor(e.length/4)));return`${t}${"\u2022".repeat(Math.max(3,e.length-t.length-n.length))}${n}`}function cn(e){if(!e)return[];e=rc(e);let t=new Set,n=[];for(let s of sc){s.regex.lastIndex=0;for(let r of e.matchAll(s.regex)){let o=r[0],i=`${s.name}::${ic(o)}`;t.has(i)||(t.add(i),n.push({pattern:s.name,maskedPreview:oc(o),offset:r.index??0,severity:s.severity}))}}return n}function ic(e){let t=5381;for(let n=0;n<e.length;n++)t=(t<<5)+t+e.charCodeAt(n)|0;return(t>>>0).toString(36)}function Ce(e){if(!e)return{redacted:e,count:0};e=rc(e);let t=e,n=0,s=new Set;for(let r of sc)r.regex.lastIndex=0,t=t.replace(r.regex,o=>{let i=`${r.name}::${ic(o)}`;return s.has(i)||(s.add(i),n+=1),`[REDACTED ${r.name}: ${oc(o)}]`});return{redacted:t,count:n}}var sc,tc,j_,jt=w(()=>{"use strict";sc=[{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"}],tc=64*1024,j_="[OVERSIZED-BLOB-SKIPPED]"});function Vr(e,t,n,s={}){s.insertOnly||e.prepare("DELETE FROM message_usage WHERE session_id = ?").run(t);let r=e.prepare(`
768
+ `),toolNames:n}}function Y_(e){if(e.endsWith("\r")&&(e=e.slice(0,-1)),!e.trim())return null;let t;try{t=JSON.parse(e)}catch{return null}if(!t.uuid||!t.sessionId)return null;let{text:n,toolNames:s}=z_(t.message);return{uuid:t.uuid,parentUuid:t.parentUuid??null,sessionId:t.sessionId,type:t.type??"unknown",role:t.message?.role??null,timestamp:t.timestamp??null,isSidechain:t.isSidechain===!0,cwd:t.cwd??null,gitBranch:t.gitBranch??null,version:t.version??null,contentText:n,toolNames:s,raw:e,usage:Vr(t.message),model:t.message?.model??null}}async function*oc(e){let t=H_(e,{encoding:"utf8"}),n=W_({input:t,crlfDelay:1/0});for await(let s of n){let r=Y_(s);r!==null&&(yield r)}}var X_,qr,Qn=w(()=>{"use strict";X_=/\x1B\[[0-9;]*[a-zA-Z]/g;qr=12e3});import Me from"chalk";import{formatDistanceToNowStrict as q_,parseISO as V_}from"date-fns";function Q(e,t){if(!e)return"";let n=e.replace(/\s+/g," ").trim();return n.length<=t?n:n.slice(0,t-1)+"\u2026"}function G(e){if(!e)return"";try{return q_(V_(e),{addSuffix:!0})}catch{return""}}function X(e){return e.slice(0,8)}function Kr(e,t){if(!t)return e;let n=t.split(/\s+/).filter(r=>r.length>1).map(r=>r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));if(n.length===0)return e;let s=new RegExp(`(${n.join("|")})`,"gi");return e.replace(s,r=>Me.bgYellow.black(r))}var c,D=w(()=>{"use strict";c={dim:Me.gray,bold:Me.bold,project:Me.cyan,user:Me.blue,assistant:Me.green,tool:Me.magenta,warn:Me.yellow,err:Me.red,ok:Me.green,accent:Me.hex("#f97316")}});function ac(e){return e===32||e===9||e===10||e===13||e===12||e===11}function lc(e){let t=e.length,n=-1,s=-1,r=0;for(let a=0;a<t;a++)if(ac(e.charCodeAt(a)))r=0;else if(++r>ic){s=a;break}if(s===-1)return e;let o=[],i=0;n=-1;for(let a=0;a<=t;a++){let d=a===t||ac(e.charCodeAt(a));!d&&n===-1?n=a:d&&n!==-1&&(a-n>ic&&(o.push(e.slice(i,n)),o.push(K_),i=a),n=-1)}return o.push(e.slice(i)),o.join("")}function dc(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))),n=e.slice(-Math.min(4,Math.floor(e.length/4)));return`${t}${"\u2022".repeat(Math.max(3,e.length-t.length-n.length))}${n}`}function cn(e){if(!e)return[];e=lc(e);let t=new Set,n=[];for(let s of cc){s.regex.lastIndex=0;for(let r of e.matchAll(s.regex)){let o=r[0],i=`${s.name}::${uc(o)}`;t.has(i)||(t.add(i),n.push({pattern:s.name,maskedPreview:dc(o),offset:r.index??0,severity:s.severity}))}}return n}function uc(e){let t=5381;for(let n=0;n<e.length;n++)t=(t<<5)+t+e.charCodeAt(n)|0;return(t>>>0).toString(36)}function Ce(e){if(!e)return{redacted:e,count:0};e=lc(e);let t=e,n=0,s=new Set;for(let r of cc)r.regex.lastIndex=0,t=t.replace(r.regex,o=>{let i=`${r.name}::${uc(o)}`;return s.has(i)||(s.add(i),n+=1),`[REDACTED ${r.name}: ${dc(o)}]`});return{redacted:t,count:n}}var cc,ic,K_,jt=w(()=>{"use strict";cc=[{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"}],ic=64*1024,K_="[OVERSIZED-BLOB-SKIPPED]"});function Qr(e,t,n,s={}){s.insertOnly||e.prepare("DELETE FROM message_usage WHERE session_id = ?").run(t);let r=e.prepare(`
769
769
  INSERT INTO message_usage (
770
770
  message_uuid, session_id, model,
771
771
  input_tokens, output_tokens, cache_create_tokens, cache_read_tokens,
@@ -797,55 +797,55 @@ ${o}
797
797
  total_cache_create_tokens = @cc,
798
798
  total_cache_read_tokens = @cr,
799
799
  primary_model = @model
800
- WHERE id = @id`).run({id:t,input:n.input_tokens,output:n.output_tokens,cc:n.cache_create_tokens,cr:n.cache_read_tokens,model:s?.model??null})}var Qn=w(()=>{"use strict"});var ac=w(()=>{"use strict";k()});function cc(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<W_)return"low_signal";for(let t of U_)if(t.test(e.auto_title))return"recursive_meta";for(let t of B_)if(t.test(e.auto_title))return"programmatic";for(let t of H_)if(t.test(e.auto_title))return"template_pending";return"clean"}var U_,Ut,B_,H_,W_,dn=w(()=>{"use strict";U_=[/^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],Ut=[/^You are summarizing a Claude Code session/i,/^You are extracting a structured Output Index from a Claude/i,/^You will receive a sample of user messages from a Claude Cod/i,/^You will receive the first \d+ user messages from a Claude/i,/^Thread context:\n- This session is part of thread/i],B_=[/^Score this person'?s relevance/i,/^You are a [^\n.]{1,60}co-pilot/i,/^Return ONLY valid JSON/i,/^You are summarizing a Claude Code session/i],H_=[/^Draft (a|an|marketing) [a-z]/i,/^Read the file at /i,/^Read this and then begin/i,/^read this and then begin/i],W_=20});function Kr(e){if(!e)return"";let t=e.split("|")[0];return t=t.replace(/\s*\([^)]*\)\s*$/,""),t=t.replace(/\s+/g," ").trim(),t}var lc=w(()=>{"use strict"});import{writeFileSync as X_,mkdirSync as G_,existsSync as z_}from"node:fs";import{join as uc}from"node:path";function V_(e){if(!e)return[];try{let t=JSON.parse(e);if(Array.isArray(t))return t.filter(n=>!!n&&typeof n=="object"&&typeof n.title=="string"&&typeof n.replaced_at=="string")}catch{}return[]}function to(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 n=K_(t,e);if(n)return n;let s=t.match(/^[^.!?\n]{8,}?[.!?]/)?.[0]?.trim();return(s&&s.length<=J_?s:t.slice(0,Y_)).trim()||null}function K_(e,t){let n=e.match(/^\/([A-Za-z0-9][A-Za-z0-9_-]*)\s+([\s\S]*)$/);if(n){let s=`/${n[1]}`,r=t.replace(/^\s*\/[A-Za-z0-9][A-Za-z0-9_-]*\s+/,""),o=eo(r);return o?un(`${s} \xB7 ${o}`):s}for(let s of Q_){if(!e.match(s.match))continue;let o=s.prefix,i=s.extract?s.extract(e,t):eo(t);return i?s.completeFromExtract?un(i):un(`${o} \xB7 ${i}`):o}for(let s of th){if(!e.match(s.match))continue;let o=s.extract?s.extract(e,t):Zn(t);return o?s.completeFromExtract?un(o):un(`${s.prefix} \xB7 ${o}`):s.prefix}return null}function Z_(e){if(!e)return"[output-index] extractor";let t=e.match(/^Session:\s*([0-9a-f]{8})\b/im),n=e.match(/^Opening prompt:\s*([^\n]{1,140})/im),s=t?.[1]?.trim(),r=n?.[1]?.trim().replace(/\s+/g," "),o=r&&r.length>70?r.slice(0,67)+"\u2026":r;return s&&o?`[output-index] \xB7 ${s} \xB7 ${o}`:s?`[output-index] \xB7 ${s}`:o?`[output-index] \xB7 ${o}`:"[output-index] extractor"}function dc(e,t){if(!e)return t;let n=e.indexOf("Messages:");if(n===-1)return t;let s=e.slice(n+9),r=/^\s*\d+\.\s*([^\n]+)/gm;for(let o of s.matchAll(r)){let i=o[1]?.trim()??"";if(!i)continue;let a=i.replace(/^<[^>]+>[\s\S]*?<\/[^>]+>\s*/g,"").replace(/^\[Pasted text[^\]]*\]\s*/i,"").trim();if(!a||/^<local-command-/.test(a))continue;let d=a.length>60?a.slice(0,57)+"\u2026":a;return`${t} \xB7 ${d}`}return t}function eh(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 n=t[1].split("/").filter(Boolean);return(n[n.length-1]??"").replace(/\.[^.]+$/,"")||null}function Zn(e){let t=/^\s*(Name|Company|Prospect|Author|Brand|Client)\s*:\s*([^\n]+)/gim,n;for(;(n=t.exec(e))!==null;){let s=n[2].trim();if(!s||/^(null|none|n\/a|—|-)$/i.test(s))continue;let r=s.replace(/\s+/g," ");return Kr(r)||r}return null}function un(e){return e.slice(0,q_).trim()}function Qr(e){let t=e.trim();return t.length<3?!0:nh.some(n=>n.test(t))}function rh(e){let t=e.trim().replace(/\s*\([^)]*\)\s*$/,"").trim();return sh.some(n=>n.test(t))}function eo(e){let t=oh(e);return t===null?null:Kr(t)||t}function oh(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,n,s=[];for(;(n=t.exec(e))!==null;){let d=n[2].trim(),l=n[3].trim().replace(/\s+/g," ");if(!Qr(l)){if(rh(d))return l;s.push(l)}}if(s.length>0)return s[0];let r=e.match(/\b(?:Topic|Subject|Brand|About|Client|For|Re)\s*:\s*([^\n]{2,80})/i);if(r?.[1]&&!Qr(r[1]))return r[1].trim().replace(/\s+/g," ");let o=/===\s*([^=\n]{2,120}?)\s*===/g;for(;(n=o.exec(e))!==null;){let d=n[1].trim().replace(/\.(md|txt|json)$/i,""),l=d.replace(/\s*\([^)]*\)\s*$/,"").trim();if(l&&!Qr(l)&&!/product context|reference/i.test(d))return l}let i=e.replace(/^Context for this run[^:]*:\s*/i,"");if(i!==e){let d=i.split(`
800
+ WHERE id = @id`).run({id:t,input:n.input_tokens,output:n.output_tokens,cc:n.cache_create_tokens,cr:n.cache_read_tokens,model:s?.model??null})}var Zn=w(()=>{"use strict"});var pc=w(()=>{"use strict";k()});function mc(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<th)return"low_signal";for(let t of Q_)if(t.test(e.auto_title))return"recursive_meta";for(let t of Z_)if(t.test(e.auto_title))return"programmatic";for(let t of eh)if(t.test(e.auto_title))return"template_pending";return"clean"}var Q_,Ut,Z_,eh,th,dn=w(()=>{"use strict";Q_=[/^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],Ut=[/^You are summarizing a Claude Code session/i,/^You are extracting a structured Output Index from a Claude/i,/^You will receive a sample of user messages from a Claude Cod/i,/^You will receive the first \d+ user messages from a Claude/i,/^Thread context:\n- This session is part of thread/i],Z_=[/^Score this person'?s relevance/i,/^You are a [^\n.]{1,60}co-pilot/i,/^Return ONLY valid JSON/i,/^You are summarizing a Claude Code session/i],eh=[/^Draft (a|an|marketing) [a-z]/i,/^Read the file at /i,/^Read this and then begin/i,/^read this and then begin/i],th=20});function Zr(e){if(!e)return"";let t=e.split("|")[0];return t=t.replace(/\s*\([^)]*\)\s*$/,""),t=t.replace(/\s+/g," ").trim(),t}var gc=w(()=>{"use strict"});import{writeFileSync as nh,mkdirSync as sh,existsSync as rh}from"node:fs";import{join as _c}from"node:path";function ch(e){if(!e)return[];try{let t=JSON.parse(e);if(Array.isArray(t))return t.filter(n=>!!n&&typeof n=="object"&&typeof n.title=="string"&&typeof n.replaced_at=="string")}catch{}return[]}function so(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 n=lh(t,e);if(n)return n;let s=t.match(/^[^.!?\n]{8,}?[.!?]/)?.[0]?.trim();return(s&&s.length<=oh?s:t.slice(0,ih)).trim()||null}function lh(e,t){let n=e.match(/^\/([A-Za-z0-9][A-Za-z0-9_-]*)\s+([\s\S]*)$/);if(n){let s=`/${n[1]}`,r=t.replace(/^\s*\/[A-Za-z0-9][A-Za-z0-9_-]*\s+/,""),o=no(r);return o?un(`${s} \xB7 ${o}`):s}for(let s of dh){if(!e.match(s.match))continue;let o=s.prefix,i=s.extract?s.extract(e,t):no(t);return i?s.completeFromExtract?un(i):un(`${o} \xB7 ${i}`):o}for(let s of mh){if(!e.match(s.match))continue;let o=s.extract?s.extract(e,t):es(t);return o?s.completeFromExtract?un(o):un(`${s.prefix} \xB7 ${o}`):s.prefix}return null}function uh(e){if(!e)return"[output-index] extractor";let t=e.match(/^Session:\s*([0-9a-f]{8})\b/im),n=e.match(/^Opening prompt:\s*([^\n]{1,140})/im),s=t?.[1]?.trim(),r=n?.[1]?.trim().replace(/\s+/g," "),o=r&&r.length>70?r.slice(0,67)+"\u2026":r;return s&&o?`[output-index] \xB7 ${s} \xB7 ${o}`:s?`[output-index] \xB7 ${s}`:o?`[output-index] \xB7 ${o}`:"[output-index] extractor"}function fc(e,t){if(!e)return t;let n=e.indexOf("Messages:");if(n===-1)return t;let s=e.slice(n+9),r=/^\s*\d+\.\s*([^\n]+)/gm;for(let o of s.matchAll(r)){let i=o[1]?.trim()??"";if(!i)continue;let a=i.replace(/^<[^>]+>[\s\S]*?<\/[^>]+>\s*/g,"").replace(/^\[Pasted text[^\]]*\]\s*/i,"").trim();if(!a||/^<local-command-/.test(a))continue;let d=a.length>60?a.slice(0,57)+"\u2026":a;return`${t} \xB7 ${d}`}return t}function ph(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 n=t[1].split("/").filter(Boolean);return(n[n.length-1]??"").replace(/\.[^.]+$/,"")||null}function es(e){let t=/^\s*(Name|Company|Prospect|Author|Brand|Client)\s*:\s*([^\n]+)/gim,n;for(;(n=t.exec(e))!==null;){let s=n[2].trim();if(!s||/^(null|none|n\/a|—|-)$/i.test(s))continue;let r=s.replace(/\s+/g," ");return Zr(r)||r}return null}function un(e){return e.slice(0,ah).trim()}function eo(e){let t=e.trim();return t.length<3?!0:gh.some(n=>n.test(t))}function _h(e){let t=e.trim().replace(/\s*\([^)]*\)\s*$/,"").trim();return fh.some(n=>n.test(t))}function no(e){let t=hh(e);return t===null?null:Zr(t)||t}function hh(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,n,s=[];for(;(n=t.exec(e))!==null;){let d=n[2].trim(),l=n[3].trim().replace(/\s+/g," ");if(!eo(l)){if(_h(d))return l;s.push(l)}}if(s.length>0)return s[0];let r=e.match(/\b(?:Topic|Subject|Brand|About|Client|For|Re)\s*:\s*([^\n]{2,80})/i);if(r?.[1]&&!eo(r[1]))return r[1].trim().replace(/\s+/g," ");let o=/===\s*([^=\n]{2,120}?)\s*===/g;for(;(n=o.exec(e))!==null;){let d=n[1].trim().replace(/\.(md|txt|json)$/i,""),l=d.replace(/\s*\([^)]*\)\s*$/,"").trim();if(l&&!eo(l)&&!/product context|reference/i.test(d))return l}let i=e.replace(/^Context for this run[^:]*:\s*/i,"");if(i!==e){let d=i.split(`
801
801
  `).map(l=>l.trim()).find(l=>l.length>=4);if(d)return d.slice(0,60)}let a=e.split(`
802
- `).map(d=>d.trim()).find(d=>d.length>=4);return a?a.slice(0,60):null}function no(e,t,n){let s=t.trim();if(!s)return;let r=E(),o=r.prepare(`SELECT auto_title, auto_title_source, auto_title_generated_at, auto_title_history
803
- FROM sessions WHERE id = ?`).get(e);if(!o||n==="heuristic"&&o.auto_title_source==="agent"&&o.auto_title||o.auto_title===s&&o.auto_title_source===n)return;let i=V_(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
802
+ `).map(d=>d.trim()).find(d=>d.length>=4);return a?a.slice(0,60):null}function ro(e,t,n){let s=t.trim();if(!s)return;let r=h(),o=r.prepare(`SELECT auto_title, auto_title_source, auto_title_generated_at, auto_title_history
803
+ FROM sessions WHERE id = ?`).get(e);if(!o||n==="heuristic"&&o.auto_title_source==="agent"&&o.auto_title||o.auto_title===s&&o.auto_title_source===n)return;let i=ch(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
804
804
  SET auto_title = ?,
805
805
  auto_title_source = ?,
806
806
  auto_title_generated_at = ?,
807
807
  auto_title_history = ?
808
- WHERE id = ?`).run(s,n,Date.now(),JSON.stringify(i),e),ah(e,s,n,a)}function ih(){j(),z_(Zr)||G_(Zr,{recursive:!0})}function ah(e,t,n,s){try{ih();let r=uc(Zr,`${e}.txt`),o=`# Claude Recall auto-title \xB7 session ${e} \xB7 source ${n} \xB7 updated ${s}
809
- `;X_(r,o+t+`
810
- `)}catch(r){console.error("[autoTitle] mirror write failed:",r)}}var Zr,J_,Y_,q_,Q_,th,nh,sh,so=w(()=>{"use strict";k();I();ac();dn();lc();Zr=uc(C,"titles"),J_=80,Y_=60,q_=100;Q_=[{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 s=e.match(/^Draft (?:a|an) ([a-z]{3,30}(?:\s+[a-z]{3,30}){0,2})\b/i)?.[1]?.trim(),r=eo(t);return s&&r?`${s} \xB7 ${r}`:s||r}},{match:/^Read the file at /i,prefix:"Read",extract:e=>{let n=e.match(/^Read the file at\s+([^\s]+)/i)?.[1];return n?n.split("/").filter(Boolean).slice(-2).join("/")||n:null}},{match:/^(?:read|inspect) this and (?:then )?begin\b/i,prefix:"Begin from preamble",completeFromExtract:!0,extract:(e,t)=>eh(t)},{match:/^Base directory for this skill:/i,prefix:"[skill]",completeFromExtract:!0,extract:(e,t)=>{let n=t.match(/\.claude\/skills\/([^/\s]+)/);return n?.[1]?`[skill] ${n[1]}`:null}},{match:/^You are extracting a structured Output Index/i,prefix:"[output-index]",completeFromExtract:!0,extract:(e,t)=>Z_(t)},{match:/^You will receive a sample of user messages from a Claude Code session:/i,prefix:"[meta]",completeFromExtract:!0,extract:(e,t)=>dc(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)=>dc(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 n=t[1],s=t[2]?.trim();return s?`Implementing ${n} \xB7 ${s}`:`Implementing ${n}`}}];th=[{match:/^Score this person'?s relevance/i,prefix:"Score relevance",extract:(e,t)=>Zn(t)},{match:/^You are a [^\n.]{1,60}co-pilot/i,prefix:"co-pilot",completeFromExtract:!0,extract:(e,t)=>{let s=e.match(/^You are a ([^\n.]{1,60}?)co-pilot/i)?.[1]?.trim(),r=s?`${s} co-pilot`:"co-pilot",o=Zn(t);return o?`${r} \xB7 ${o}`:r}},{match:/^Return ONLY valid JSON/i,prefix:"JSON-only",extract:(e,t)=>Zn(t)}];nh=[/^deep research$/i,/^reference(?: spec)?$/i,/^canonical spec/i,/^product context/i,/^services?(?: overview)?$/i,/^overview$/i,/^(?:introduction|template|instructions|context)$/i],sh=[/^(?:brand|brand brief|brand summary)$/i,/^(?:known facts?|facts)$/i,/^(?:client|prospect|customer|account)$/i,/^(?:topic|subject|brief|task)$/i,/^(?:about|for|re)$/i]});import{existsSync as ch,mkdirSync as JN,readFileSync as lh,writeFileSync as YN}from"node:fs";import{homedir as dh}from"node:os";import{join as pc}from"node:path";import{z as ro}from"zod";function uh(){return process.env.RECALL_HOME??pc(dh(),".recall")}function ph(){return pc(uh(),"config.json")}function gh(){let e=ph();if(!ch(e))return{};try{return JSON.parse(lh(e,"utf8"))}catch(t){return console.error("[auto-title-config] failed to parse config.json, using defaults:",t),{}}}function io(){let e=gh().autoTitle;if(!e)return{...oo};let t=mh.safeParse({...oo,...e});return t.success?t.data:{...oo}}var mh,oo,ao=w(()=>{"use strict";mh=ro.object({heuristicEnabled:ro.boolean().default(!0),agentEnabled:ro.boolean().default(!1)}),oo={heuristicEnabled:!0,agentEnabled:!1}});import{existsSync as yc,readFileSync as $h,writeFileSync as Ph,unlinkSync as Fh}from"node:fs";import{join as jh}from"node:path";function pn(){if(!yc(Ct))return null;try{let e=$h(Ct,"utf8"),t=JSON.parse(e);return typeof t.license_jwt!="string"||t.license_jwt.length===0?null:t}catch{return null}}function ts(e){j(),Ph(Ct,JSON.stringify(e,null,2)+`
811
- `,{mode:384})}function wc(){yc(Ct)&&Fh(Ct)}var Ct,Bt=w(()=>{"use strict";I();Ct=jh(C,"license.json")});var Tc,lo,Rc,kc,xc=w(()=>{"use strict";Tc=`-----BEGIN PUBLIC KEY-----
808
+ WHERE id = ?`).run(s,n,Date.now(),JSON.stringify(i),e),bh(e,s,n,a)}function Eh(){j(),rh(to)||sh(to,{recursive:!0})}function bh(e,t,n,s){try{Eh();let r=_c(to,`${e}.txt`),o=`# Claude Recall auto-title \xB7 session ${e} \xB7 source ${n} \xB7 updated ${s}
809
+ `;nh(r,o+t+`
810
+ `)}catch(r){console.error("[autoTitle] mirror write failed:",r)}}var to,oh,ih,ah,dh,mh,gh,fh,oo=w(()=>{"use strict";k();I();pc();dn();gc();to=_c(C,"titles"),oh=80,ih=60,ah=100;dh=[{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 s=e.match(/^Draft (?:a|an) ([a-z]{3,30}(?:\s+[a-z]{3,30}){0,2})\b/i)?.[1]?.trim(),r=no(t);return s&&r?`${s} \xB7 ${r}`:s||r}},{match:/^Read the file at /i,prefix:"Read",extract:e=>{let n=e.match(/^Read the file at\s+([^\s]+)/i)?.[1];return n?n.split("/").filter(Boolean).slice(-2).join("/")||n:null}},{match:/^(?:read|inspect) this and (?:then )?begin\b/i,prefix:"Begin from preamble",completeFromExtract:!0,extract:(e,t)=>ph(t)},{match:/^Base directory for this skill:/i,prefix:"[skill]",completeFromExtract:!0,extract:(e,t)=>{let n=t.match(/\.claude\/skills\/([^/\s]+)/);return n?.[1]?`[skill] ${n[1]}`:null}},{match:/^You are extracting a structured Output Index/i,prefix:"[output-index]",completeFromExtract:!0,extract:(e,t)=>uh(t)},{match:/^You will receive a sample of user messages from a Claude Code session:/i,prefix:"[meta]",completeFromExtract:!0,extract:(e,t)=>fc(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)=>fc(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 n=t[1],s=t[2]?.trim();return s?`Implementing ${n} \xB7 ${s}`:`Implementing ${n}`}}];mh=[{match:/^Score this person'?s relevance/i,prefix:"Score relevance",extract:(e,t)=>es(t)},{match:/^You are a [^\n.]{1,60}co-pilot/i,prefix:"co-pilot",completeFromExtract:!0,extract:(e,t)=>{let s=e.match(/^You are a ([^\n.]{1,60}?)co-pilot/i)?.[1]?.trim(),r=s?`${s} co-pilot`:"co-pilot",o=es(t);return o?`${r} \xB7 ${o}`:r}},{match:/^Return ONLY valid JSON/i,prefix:"JSON-only",extract:(e,t)=>es(t)}];gh=[/^deep research$/i,/^reference(?: spec)?$/i,/^canonical spec/i,/^product context/i,/^services?(?: overview)?$/i,/^overview$/i,/^(?:introduction|template|instructions|context)$/i],fh=[/^(?:brand|brand brief|brand summary)$/i,/^(?:known facts?|facts)$/i,/^(?:client|prospect|customer|account)$/i,/^(?:topic|subject|brief|task)$/i,/^(?:about|for|re)$/i]});import{existsSync as Sh,mkdirSync as mO,readFileSync as yh,writeFileSync as gO}from"node:fs";import{homedir as wh}from"node:os";import{join as hc}from"node:path";import{z as io}from"zod";function Th(){return process.env.RECALL_HOME??hc(wh(),".recall")}function Rh(){return hc(Th(),"config.json")}function xh(){let e=Rh();if(!Sh(e))return{};try{return JSON.parse(yh(e,"utf8"))}catch(t){return console.error("[auto-title-config] failed to parse config.json, using defaults:",t),{}}}function co(){let e=xh().autoTitle;if(!e)return{...ao};let t=kh.safeParse({...ao,...e});return t.success?t.data:{...ao}}var kh,ao,lo=w(()=>{"use strict";kh=io.object({heuristicEnabled:io.boolean().default(!0),agentEnabled:io.boolean().default(!1)}),ao={heuristicEnabled:!0,agentEnabled:!1}});import{existsSync as xc,readFileSync as Yh,writeFileSync as qh,unlinkSync as Vh}from"node:fs";import{join as Kh}from"node:path";function pn(){if(!xc(Ct))return null;try{let e=Yh(Ct,"utf8"),t=JSON.parse(e);return typeof t.license_jwt!="string"||t.license_jwt.length===0?null:t}catch{return null}}function ns(e){j(),qh(Ct,JSON.stringify(e,null,2)+`
811
+ `,{mode:384})}function Cc(){xc(Ct)&&Vh(Ct)}var Ct,Bt=w(()=>{"use strict";I();Ct=Kh(C,"license.json")});var Ac,po,Lc,Nc,Oc=w(()=>{"use strict";Ac=`-----BEGIN PUBLIC KEY-----
812
812
  MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZysO2FffTLdyxQnTmnt78/ayvqz9
813
813
  kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
814
814
  -----END PUBLIC KEY-----
815
- `,lo="ES256",Rc="clauderecall.com",kc="clauderecall-cli"});import{jwtVerify as Uh,importSPKI as Bh}from"jose";async function Hh(){return ns||(ns=await Bh(Tc,lo),ns)}async function Ht(e){try{let t=await Hh(),{payload:n}=await Uh(e,t,{issuer:Rc,audience:kc,algorithms:[lo]});return{valid:!0,claims:n}}catch(t){return{valid:!1,reason:t instanceof Error?t.message:"verification failed"}}}var ns,ss=w(()=>{"use strict";xc();ns=null});import{createHash as Wh}from"node:crypto";import{hostname as Xh,userInfo as Gh,platform as zh,arch as Jh}from"node:os";function Wt(){let e="unknown";try{e=Gh().username}catch{}let t=[Xh(),e,zh(),Jh()];return Wh("sha256").update(t.join("\0")).digest("hex")}var rs=w(()=>{"use strict"});function dt(){let e=process.env.RECALL_API_BASE;if(e&&e.length>0){let t=e.replace(/\/$/,""),n;try{n=new URL(t)}catch{throw new Error(`RECALL_API_BASE is not a valid URL: ${t}`)}let s=n.hostname==="127.0.0.1"||n.hostname==="localhost"||n.hostname==="::1";if(n.protocol==="https:"||n.protocol==="http:"&&s)return t;throw new Error(`RECALL_API_BASE must be HTTPS, or HTTP with loopback hostname. Got: ${t}`)}return"https://clauderecall.com"}var mn=w(()=>{"use strict"});import{existsSync as Yh,readFileSync as qh,writeFileSync as Vh}from"node:fs";import{join as Kh}from"node:path";function os(){if(!Yh(uo))return null;try{let e=JSON.parse(qh(uo,"utf8"));return typeof e.license_key!="string"||typeof e.last_checked_at!="string"||typeof e.revoked!="boolean"?null:e}catch{return null}}function tE(e){j(),Vh(uo,JSON.stringify(e,null,2)+`
816
- `,{mode:384})}async function nE(e,t){let n=null,s=null;try{n=new AbortController,s=setTimeout(()=>n?.abort(),eE);let r=await fetch(t,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({license_key:e}),signal:n.signal});if(!r.ok)return null;let o=await r.json();return typeof o?.revoked!="boolean"?null:o}catch{return null}finally{s&&clearTimeout(s)}}async function Cc(e,t={}){let n=os(),s=t.apiUrl??`${dt()}/api/license/check`,r=n?.license_key===e,o=!n||!r||Date.now()-new Date(n.last_checked_at).getTime()>=Qh;if(!t.force&&!o)return n;let i=await nE(e,s);if(!i)return r?n:null;let a={license_key:e,last_checked_at:new Date().toISOString(),revoked:i.revoked,reason:i.reason??null};return tE(a),a}function Lc(e){let t=os();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()>Zh?{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 uo,Qh,Zh,eE,po=w(()=>{"use strict";I();mn();uo=Kh(C,"license-check.json"),Qh=1440*60*1e3,Zh=720*60*60*1e3,eE=1e4});function mo(){return`Pro is one-time, lifetime license, $${Ac}. Never a subscription.`}function Nc(){return`(one-time purchase, $${Ac}, lifetime updates)`}var Ac,go=w(()=>{"use strict";Ac="49.69"});function fo(e){let t=e.now??Date.now(),n=e.status.expires_at??null,s=n?new Date(n).getTime():null,r=s!==null&&s-t<rE;if(e.status.tier==="pro"&&r&&s!==null){let o=Math.max(0,Math.floor((s-t)/36e5));if(o<=24)return{kind:"trial-near-expiry",message:`Your Pro trial ends in ${o} hours. ${mo()} ${Oc}`}}return e.status.tier==="free"&&r&&s!==null&&s<t&&Math.floor((t-s)/36e5)<720?{kind:"trial-expired",message:`Your Pro trial ended. Your data is intact; only Pro features are gated. ${mo()} ${Oc}`}:null}var Oc,sE,rE,vc=w(()=>{"use strict";go();Oc="https://clauderecall.com/pricing",sE=1440*60*1e3,rE=60*sE});var gn={};V(gn,{getLicenseStatus:()=>Le,isPro:()=>iE,performRevocationCheck:()=>_o,printTrialBannerIfAny:()=>aE,requireProOrExit:()=>oe});async function Le(){let e=pn();if(!e)return{tier:"free"};let t=await Ht(e.license_jwt);if(!t.valid||!t.claims)return{tier:"free",invalid_reason:t.reason};if(t.claims.machine_fp&&t.claims.machine_fp!==Wt())return{tier:"free",invalid_reason:"machine fingerprint mismatch \u2014 re-activate on this device"};let n=Lc(e.license_key);return n?.revoked?{tier:"free",invalid_reason:n.reason}:oE(e,t.claims)}async function _o(e){let t=pn();if(!t)return{ran:!1,revoked:!1,reason:null,last_checked_at:null};let n=await Cc(t.license_key,{force:e?.force??!1});return n?{ran:!0,revoked:n.revoked,reason:n.reason,last_checked_at:n.last_checked_at}:{ran:!0,revoked:!1,reason:null,last_checked_at:null}}function oE(e,t){let n=t.test_mode===!0&&process.env.NODE_ENV==="production";return{tier:n?"free":"pro",key_short:e.key_short,customer_email:e.customer_email,activated_at:e.activated_at,test_mode:e.test_mode,...n?{test_mode_blocked:!0}:{},expires_at:typeof t.exp=="number"?new Date(t.exp*1e3).toISOString():null}}async function iE(){return(await Le()).tier==="pro"}async function oe(e){let t=await Le();if(t.tier==="pro")return;let n=fo({status:t});n&&process.stderr.write(`
815
+ `,po="ES256",Lc="clauderecall.com",Nc="clauderecall-cli"});import{jwtVerify as Qh,importSPKI as Zh}from"jose";async function eE(){return ss||(ss=await Zh(Ac,po),ss)}async function Ht(e){try{let t=await eE(),{payload:n}=await Qh(e,t,{issuer:Lc,audience:Nc,algorithms:[po]});return{valid:!0,claims:n}}catch(t){return{valid:!1,reason:t instanceof Error?t.message:"verification failed"}}}var ss,rs=w(()=>{"use strict";Oc();ss=null});import{createHash as tE}from"node:crypto";import{hostname as nE,userInfo as sE,platform as rE,arch as oE}from"node:os";function Wt(){let e="unknown";try{e=sE().username}catch{}let t=[nE(),e,rE(),oE()];return tE("sha256").update(t.join("\0")).digest("hex")}var os=w(()=>{"use strict"});function dt(){let e=process.env.RECALL_API_BASE;if(e&&e.length>0){let t=e.replace(/\/$/,""),n;try{n=new URL(t)}catch{throw new Error(`RECALL_API_BASE is not a valid URL: ${t}`)}let s=n.hostname==="127.0.0.1"||n.hostname==="localhost"||n.hostname==="::1";if(n.protocol==="https:"||n.protocol==="http:"&&s)return t;throw new Error(`RECALL_API_BASE must be HTTPS, or HTTP with loopback hostname. Got: ${t}`)}return"https://clauderecall.com"}var mn=w(()=>{"use strict"});import{existsSync as iE,readFileSync as aE,writeFileSync as cE}from"node:fs";import{join as lE}from"node:path";function is(){if(!iE(mo))return null;try{let e=JSON.parse(aE(mo,"utf8"));return typeof e.license_key!="string"||typeof e.last_checked_at!="string"||typeof e.revoked!="boolean"?null:e}catch{return null}}function mE(e){j(),cE(mo,JSON.stringify(e,null,2)+`
816
+ `,{mode:384})}async function gE(e,t){let n=null,s=null;try{n=new AbortController,s=setTimeout(()=>n?.abort(),pE);let r=await fetch(t,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({license_key:e}),signal:n.signal});if(!r.ok)return null;let o=await r.json();return typeof o?.revoked!="boolean"?null:o}catch{return null}finally{s&&clearTimeout(s)}}async function vc(e,t={}){let n=is(),s=t.apiUrl??`${dt()}/api/license/check`,r=n?.license_key===e,o=!n||!r||Date.now()-new Date(n.last_checked_at).getTime()>=dE;if(!t.force&&!o)return n;let i=await gE(e,s);if(!i)return r?n:null;let a={license_key:e,last_checked_at:new Date().toISOString(),revoked:i.revoked,reason:i.reason??null};return mE(a),a}function Ic(e){let t=is();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()>uE?{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 mo,dE,uE,pE,go=w(()=>{"use strict";I();mn();mo=lE(C,"license-check.json"),dE=1440*60*1e3,uE=720*60*60*1e3,pE=1e4});function fo(){return`Pro is one-time, lifetime license, $${Mc}. Never a subscription.`}function Dc(){return`(one-time purchase, $${Mc}, lifetime updates)`}var Mc,_o=w(()=>{"use strict";Mc="49.69"});function ho(e){let t=e.now??Date.now(),n=e.status.expires_at??null,s=n?new Date(n).getTime():null,r=s!==null&&s-t<_E;if(e.status.tier==="pro"&&r&&s!==null){let o=Math.max(0,Math.floor((s-t)/36e5));if(o<=24)return{kind:"trial-near-expiry",message:`Your Pro trial ends in ${o} hours. ${fo()} ${$c}`}}return e.status.tier==="free"&&r&&s!==null&&s<t&&Math.floor((t-s)/36e5)<720?{kind:"trial-expired",message:`Your Pro trial ended. Your data is intact; only Pro features are gated. ${fo()} ${$c}`}:null}var $c,fE,_E,Pc=w(()=>{"use strict";_o();$c="https://clauderecall.com/pricing",fE=1440*60*1e3,_E=60*fE});var gn={};V(gn,{getLicenseStatus:()=>Ae,isPro:()=>EE,performRevocationCheck:()=>Eo,printTrialBannerIfAny:()=>bE,requireProOrExit:()=>ie});async function Ae(){let e=pn();if(!e)return{tier:"free"};let t=await Ht(e.license_jwt);if(!t.valid||!t.claims)return{tier:"free",invalid_reason:t.reason};if(t.claims.machine_fp&&t.claims.machine_fp!==Wt())return{tier:"free",invalid_reason:"machine fingerprint mismatch \u2014 re-activate on this device"};let n=Ic(e.license_key);return n?.revoked?{tier:"free",invalid_reason:n.reason}:hE(e,t.claims)}async function Eo(e){let t=pn();if(!t)return{ran:!1,revoked:!1,reason:null,last_checked_at:null};let n=await vc(t.license_key,{force:e?.force??!1});return n?{ran:!0,revoked:n.revoked,reason:n.reason,last_checked_at:n.last_checked_at}:{ran:!0,revoked:!1,reason:null,last_checked_at:null}}function hE(e,t){let n=t.test_mode===!0&&process.env.NODE_ENV==="production";return{tier:n?"free":"pro",key_short:e.key_short,customer_email:e.customer_email,activated_at:e.activated_at,test_mode:e.test_mode,...n?{test_mode_blocked:!0}:{},expires_at:typeof t.exp=="number"?new Date(t.exp*1e3).toISOString():null}}async function EE(){return(await Ae()).tier==="pro"}async function ie(e){let t=await Ae();if(t.tier==="pro")return;let n=ho({status:t});n&&process.stderr.write(`
817
817
  ${n.message}
818
818
  `),process.stderr.write(`
819
819
  ${e} is a Pro feature.
820
820
 
821
821
  Buy a license at https://clauderecall.com/pricing
822
- ${Nc()}.
822
+ ${Dc()}.
823
823
  Then run: recall activate <license-key>
824
824
 
825
825
  `),t.invalid_reason&&process.stderr.write(`(stored license is invalid: ${t.invalid_reason})
826
826
 
827
- `),process.exit(1)}async function aE(){let e=await Le(),t=fo({status:e});return t?(process.stderr.write(`
827
+ `),process.exit(1)}async function bE(){let e=await Ae(),t=ho({status:e});return t?(process.stderr.write(`
828
828
  ${t.message}
829
829
 
830
- `),!0):!1}var ge=w(()=>{"use strict";Bt();ss();rs();po();go();vc()});import{appendFileSync as cE}from"node:fs";import{join as lE}from"node:path";function Xt(e,t){let s=(new Error().stack??"").split(`
831
- `).slice(2,4).map(i=>i.trim().replace(/file:\/\/.*?(\bdist\b|\bsrc\b)/g,"$1")).join(" << "),o=`${new Date().toISOString()} ${uE} ${e}: ${t} | caller: ${s}
832
- `;try{cE(dE,o)}catch{}}var dE,uE,ho=w(()=>{"use strict";I();dE=lE(C,"daemon.log"),uE="[state-files-audit]"});import{writeFileSync as nv,readFileSync as pE,existsSync as mE}from"node:fs";import{join as gE}from"node:path";function Ic(){if(!mE(is))return null;try{return pE(is,"utf8").trim()}catch{return null}}var is,Eo=w(()=>{"use strict";I();ho();is=gE(C,"daemon.token")});import{execFileSync as Pc}from"node:child_process";function SE(e){let t=e.replace(/\\/g,"/");for(let n of bE)if(t.includes(n))return!0;return!1}function yE(e){if(e.length<5)return!1;let t=[e[5]??"",e[4]??""];for(let n of t)if(n&&(n.endsWith("/grep")||n==="grep"||n.endsWith("/awk")||n==="awk"||n.endsWith("/rg")||n==="rg"))return!0;return!1}function st(e={}){let t=e.psOutput??wE(),n=new Set(e.excludePids??[]),s=[];for(let r of t.split(`
833
- `)){let o=r.trim();if(!o||!SE(o))continue;let i=o.split(/\s+/);if(yE(i)||i.length<5)continue;let a=Number(i[0]),d=Number(i[1]),l=i[2];!Number.isFinite(a)||!Number.isFinite(d)||n.has(a)||s.push({pid:a,ppid:d,etimeSeconds:TE(l),etime:l,command:o})}return s.sort((r,o)=>r.etimeSeconds-o.etimeSeconds),s}function wE(){if(process.platform==="win32")try{return Pc("powershell.exe",["-NoProfile","-NonInteractive","-Command",`Get-CimInstance Win32_Process | Where-Object { $_.Name -eq 'node.exe' -and $_.CommandLine -like '*entrypoint.js*' } | ForEach-Object { "$($_.ProcessId) $($_.ParentProcessId) 00:00 $($_.CommandLine)" }`],{encoding:"utf8",timeout:5e3,maxBuffer:5*1024*1024})}catch(e){let t=e instanceof Error?e.message:String(e);return process.stderr.write(`[daemon-processes] Win32_Process survey failed: ${t}
834
- `),""}try{return Pc("ps",["-axo","pid,ppid,etime,rss,pcpu,command"],{encoding:"utf8",timeout:2e3,maxBuffer:5*1024*1024})}catch(e){let t=e instanceof Error?e.message:String(e);return process.stderr.write(`[daemon-processes] ps -axo failed: ${t}
835
- `),""}}function TE(e){if(!e)return 0;let t=0,n=e,s=e.indexOf("-");s>=0&&(t=Fc(e.slice(0,s)),n=e.slice(s+1));let r=n.split(":").map(Fc),o=0,i=0,a=0;return r.length===3?[o,i,a]=r:r.length===2?[i,a]=r:r.length===1&&(a=r[0]),t*86400+o*3600+i*60+a}function Fc(e){let t=Number(e);return Number.isFinite(t)?t:0}function fn(e,t=new Date){if(!Number.isFinite(e)||e<0)return null;let n=t.getTime()-e*1e3;if(!Number.isFinite(n))return null;let s=new Date(n),r=String(s.getHours()).padStart(2,"0"),o=String(s.getMinutes()).padStart(2,"0"),i=String(s.getSeconds()).padStart(2,"0");return`${r}:${o}:${i}`}var bE,_n=w(()=>{"use strict";bE=["dist/daemon/entrypoint.js"]});import{existsSync as jc,readFileSync as RE,writeFileSync as Sv,unlinkSync as kE}from"node:fs";import{basename as xE,join as bo}from"node:path";function cs(){return{pid:Uc,port:CE,token:is}}function LE(){return Bc(Uc)}function Bc(e){if(!jc(e))return null;try{let t=JSON.parse(RE(e,"utf8"));return typeof t.pid!="number"||typeof t.port!="number"?null:t}catch{return null}}function Hc(e={}){let t=e.paths??cs(),n=e.listDaemons??(()=>st({excludePids:[process.pid]})),s=e.isProcessAlive??Xc,r=n();if(r.length>0){let i=r.map(a=>a.pid).join(",");return Xt("clear-refused",`${r.length} live daemon(s) visible via ps: ${i}`),{deleted:!1,reason:`refused: ${r.length} live daemon(s) in ps (${i})`,cleared:[]}}let o=Bc(t.pid);return o&&s(o.pid)?(Xt("clear-refused",`pidfile owner pid=${o.pid} alive but not surfaced by ps`),{deleted:!1,reason:`refused: pidfile owner pid=${o.pid} alive`,cleared:[]}):AE({paths:t})}function AE(e={}){let t=e.paths??cs(),n=[];for(let s of[t.pid,t.port,t.token])if(jc(s))try{kE(s),n.push(xE(s))}catch{}return Xt("clear-force",`cleared: ${n.join(",")||"(none -- files already absent)"}`),{deleted:!0,reason:`cleared ${n.length} file(s)`,cleared:n}}function Wc(){let e=Hc();e.deleted||Xt("clear-refused-shim",e.reason)}function hn(e){return Xc(e)}function Xc(e){try{return process.kill(e,0),!0}catch{return!1}}function ie(){let e=LE();return e?hn(e.pid)?e:(Hc(),null):null}var Uc,CE,as,Xe=w(()=>{"use strict";I();Eo();_n();ho();Uc=bo(C,"daemon.pid"),CE=bo(C,"daemon.port"),as=bo(C,"daemon.log")});import{existsSync as IE}from"node:fs";import{dirname as Jc}from"node:path";import{fileURLToPath as ME}from"node:url";function te(){if(ls)return ls;let e=Jc(ME(import.meta.url));for(;!IE(`${e}/package.json`);){let t=Jc(e);if(t===e)throw new Error(`package.json not found walking up from ${import.meta.url}`);e=t}return ls=e,ls}var ls,Ge=w(()=>{"use strict";ls=null});import{execFileSync as Kc}from"node:child_process";function HE(e){for(let t of BE)if(e.includes(t))return!0;return!1}function Lt(e={}){let t=e.psOutput??WE(),n=e.isProcessAlive??XE,s=e.getParentCommand??GE,r=[];for(let o of t.split(`
836
- `)){let i=o.trim();if(!i||!HE(i)||zE(i))continue;let a=i.split(/\s+/);if(a.length<5)continue;let d=Number(a[0]),l=Number(a[1]),u=a[2],m=a[3],p=a[4],g=0,f=0;if(/^\d+$/.test(m)&&(p.includes(".")||/^\d+$/.test(p))?(g=Number(m),f=Number(p)):f=Number(m),!Number.isFinite(d)||!Number.isFinite(l))continue;let _=l>1&&n(l);r.push({pid:d,ppid:l,parentAlive:_,etimeSeconds:JE(u),pcpu:Number.isFinite(f)?f:0,rssKb:Number.isFinite(g)?g:0,orphan:!_,parentCommand:_?s(l):null})}return r}function WE(){try{return Kc("ps",["-axo","pid,ppid,etime,rss,pcpu,command"],{encoding:"utf8",timeout:2e3,maxBuffer:5*1024*1024})}catch(e){let t=e instanceof Error?e.message:String(e);return process.stderr.write(`[mcp-processes] ps -axo failed: ${t}
837
- `),""}}function XE(e){if(!Number.isFinite(e)||e<=1)return!1;try{return process.kill(e,0),!0}catch{return!1}}function GE(e){if(!Number.isFinite(e)||e<=1)return null;try{let n=Kc("ps",["-p",String(e),"-o","command="],{encoding:"utf8",timeout:1e3,maxBuffer:1048576}).trim();return n.length?n.slice(0,200):null}catch{return null}}function zE(e){let t=e.split(/\s+/);if(t.length<5)return!1;let n=[t[5]??"",t[4]??""];for(let s of n)if(s&&(s.endsWith("/grep")||s==="grep"||s.endsWith("/awk")||s==="awk"||s.endsWith("/rg")||s==="rg"))return!0;return!1}function JE(e){if(!e)return 0;let t=0,n=e,s=e.indexOf("-");s>=0&&(t=Yc(e.slice(0,s)),n=e.slice(s+1));let r=n.split(":").map(Yc),o=0,i=0,a=0;return r.length===3?[o,i,a]=r:r.length===2?[i,a]=r:r.length===1&&(a=r[0]),t*86400+o*3600+i*60+a}function Yc(e){let t=Number(e);return Number.isFinite(t)?t:0}function us(e){return e.pcpu>=YE&&e.etimeSeconds>=qE}function Vc(e){return e.reduce((t,n)=>t+(Number.isFinite(n.rssKb)&&n.rssKb>0?n.rssKb:0),0)}function Qc(e){let t=e??Lt(),n=t.length,s=Vc(t),r=t.filter(p=>p.orphan),o=r.length,i=Vc(r),a=o>qc,d=i>VE;if(!(a||d))return{flagged:!1,severity:"ok",count:n,aggregateRssKb:s,orphanCount:o,orphanRssKb:i,message:null};let u=[];a&&u.push(`${o} orphaned MCP children (threshold ${qc})`),d&&u.push(`${KE(i)} aggregate RSS across orphaned children (threshold 1 GiB)`);let m=`Zombie MCP threshold breached: ${u.join(" + ")}. Each orphaned MCP child (its parent claude/VS Code tab has exited) still holds a SQLite read connection and can pin WAL checkpoints. Run \`recall mcp-prune --all\` to reap (note: pre-2026-05-23 builds may miss processes from stale install paths -- \`pkill -f mcp-server.js\` is the nuclear option).`;return{flagged:!0,severity:"high",count:n,aggregateRssKb:s,orphanCount:o,orphanRssKb:i,message:m}}function KE(e){return e<1024?`${e} KB`:e<1024*1024?`${(e/1024).toFixed(1)} MB`:`${(e/(1024*1024)).toFixed(2)} GB`}var BE,YE,qE,qc,VE,En=w(()=>{"use strict";BE=["dist/mcp-server.js","dist/mcp/server.js"];YE=50,qE=60;qc=4,VE=1024*1024});function pt(e){if(e<60)return`${e}s`;if(e<3600)return`${Math.floor(e/60)}m`;if(e<86400)return`${Math.floor(e/3600)}h`;let t=Math.floor(e/86400),n=Math.floor(e%86400/3600);return n>0?`${t}d ${n}h`:`${t}d`}var ps=w(()=>{"use strict"});function ms(e,t="PASSIVE",n){let s=Date.now(),r=e.pragma(`wal_checkpoint(${t})`),o=ZE(r),i={busy:o.busy,log:o.log,moved:o.checkpointed,mode:t,durationMs:Date.now()-s};return n&&(t==="PASSIVE"&&i.log>=QE&&i.moved===0?n(`[wal-maintenance] PASSIVE checkpoint blocked: log=${i.log} frames pending, moved=0 (readers holding snapshots)`):i.moved>0&&n(`[wal-maintenance] ${t} checkpoint: log=${i.log} moved=${i.moved} busy=${i.busy} (${i.durationMs}ms)`)),i}function ZE(e){let t=Array.isArray(e)?e[0]??{}:e??{};return{busy:So(t.busy),log:So(t.log),checkpointed:So(t.checkpointed)}}function So(e){return typeof e=="number"&&Number.isFinite(e)?e:typeof e=="bigint"?Number(e):0}var sI,Zc,QE,gs=w(()=>{"use strict";ps();En();sI=5*6e4,Zc=1073741824,QE=100});import{writeFileSync as Pb}from"node:fs";import{join as Fb}from"node:path";function xo(e){try{let t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return[]}function Es(e){return E().prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(e)?.alias??null}function Ub(){return E().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:xo(t.previous_aliases)}))}function Gt(e,t){let n=t.trim();if(!n)throw new Error("alias must be non-empty");let s=E(),r=new Date().toISOString(),o=s.prepare("SELECT alias, previous_aliases FROM session_aliases WHERE session_id = ?").get(e),i=[];return o&&(i=xo(o.previous_aliases),o.alias!==n&&i.push({alias:o.alias,replaced_at:r})),s.prepare(`INSERT INTO session_aliases (session_id, alias, updated_at, previous_aliases)
830
+ `),!0):!1}var ge=w(()=>{"use strict";Bt();rs();os();go();_o();Pc()});import{appendFileSync as SE}from"node:fs";import{join as yE}from"node:path";function Xt(e,t){let s=(new Error().stack??"").split(`
831
+ `).slice(2,4).map(i=>i.trim().replace(/file:\/\/.*?(\bdist\b|\bsrc\b)/g,"$1")).join(" << "),o=`${new Date().toISOString()} ${TE} ${e}: ${t} | caller: ${s}
832
+ `;try{SE(wE,o)}catch{}}var wE,TE,bo=w(()=>{"use strict";I();wE=yE(C,"daemon.log"),TE="[state-files-audit]"});import{writeFileSync as wv,readFileSync as RE,existsSync as kE}from"node:fs";import{join as xE}from"node:path";function Fc(){if(!kE(as))return null;try{return RE(as,"utf8").trim()}catch{return null}}var as,So=w(()=>{"use strict";I();bo();as=xE(C,"daemon.token")});import{execFileSync as Hc}from"node:child_process";function vE(e){let t=e.replace(/\\/g,"/");for(let n of OE)if(t.includes(n))return!0;return!1}function IE(e){if(e.length<5)return!1;let t=[e[5]??"",e[4]??""];for(let n of t)if(n&&(n.endsWith("/grep")||n==="grep"||n.endsWith("/awk")||n==="awk"||n.endsWith("/rg")||n==="rg"))return!0;return!1}function st(e={}){let t=e.psOutput??ME(),n=new Set(e.excludePids??[]),s=[];for(let r of t.split(`
833
+ `)){let o=r.trim();if(!o||!vE(o))continue;let i=o.split(/\s+/);if(IE(i)||i.length<5)continue;let a=Number(i[0]),d=Number(i[1]),l=i[2];!Number.isFinite(a)||!Number.isFinite(d)||n.has(a)||s.push({pid:a,ppid:d,etimeSeconds:DE(l),etime:l,command:o})}return s.sort((r,o)=>r.etimeSeconds-o.etimeSeconds),s}function ME(){if(process.platform==="win32")try{return Hc("powershell.exe",["-NoProfile","-NonInteractive","-Command",`Get-CimInstance Win32_Process | Where-Object { $_.Name -eq 'node.exe' -and $_.CommandLine -like '*entrypoint.js*' } | ForEach-Object { "$($_.ProcessId) $($_.ParentProcessId) 00:00 $($_.CommandLine)" }`],{encoding:"utf8",timeout:5e3,maxBuffer:5*1024*1024})}catch(e){let t=e instanceof Error?e.message:String(e);return process.stderr.write(`[daemon-processes] Win32_Process survey failed: ${t}
834
+ `),""}try{return Hc("ps",["-axo","pid,ppid,etime,rss,pcpu,command"],{encoding:"utf8",timeout:2e3,maxBuffer:5*1024*1024})}catch(e){let t=e instanceof Error?e.message:String(e);return process.stderr.write(`[daemon-processes] ps -axo failed: ${t}
835
+ `),""}}function DE(e){if(!e)return 0;let t=0,n=e,s=e.indexOf("-");s>=0&&(t=Wc(e.slice(0,s)),n=e.slice(s+1));let r=n.split(":").map(Wc),o=0,i=0,a=0;return r.length===3?[o,i,a]=r:r.length===2?[i,a]=r:r.length===1&&(a=r[0]),t*86400+o*3600+i*60+a}function Wc(e){let t=Number(e);return Number.isFinite(t)?t:0}function fn(e,t=new Date){if(!Number.isFinite(e)||e<0)return null;let n=t.getTime()-e*1e3;if(!Number.isFinite(n))return null;let s=new Date(n),r=String(s.getHours()).padStart(2,"0"),o=String(s.getMinutes()).padStart(2,"0"),i=String(s.getSeconds()).padStart(2,"0");return`${r}:${o}:${i}`}var OE,_n=w(()=>{"use strict";OE=["dist/daemon/entrypoint.js"]});import{existsSync as Xc,readFileSync as $E,writeFileSync as Uv,unlinkSync as PE}from"node:fs";import{basename as FE,join as yo}from"node:path";function ls(){return{pid:Gc,port:jE,token:as}}function UE(){return Jc(Gc)}function Jc(e){if(!Xc(e))return null;try{let t=JSON.parse($E(e,"utf8"));return typeof t.pid!="number"||typeof t.port!="number"?null:t}catch{return null}}function zc(e={}){let t=e.paths??ls(),n=e.listDaemons??(()=>st({excludePids:[process.pid]})),s=e.isProcessAlive??qc,r=n();if(r.length>0){let i=r.map(a=>a.pid).join(",");return Xt("clear-refused",`${r.length} live daemon(s) visible via ps: ${i}`),{deleted:!1,reason:`refused: ${r.length} live daemon(s) in ps (${i})`,cleared:[]}}let o=Jc(t.pid);return o&&s(o.pid)?(Xt("clear-refused",`pidfile owner pid=${o.pid} alive but not surfaced by ps`),{deleted:!1,reason:`refused: pidfile owner pid=${o.pid} alive`,cleared:[]}):BE({paths:t})}function BE(e={}){let t=e.paths??ls(),n=[];for(let s of[t.pid,t.port,t.token])if(Xc(s))try{PE(s),n.push(FE(s))}catch{}return Xt("clear-force",`cleared: ${n.join(",")||"(none -- files already absent)"}`),{deleted:!0,reason:`cleared ${n.length} file(s)`,cleared:n}}function Yc(){let e=zc();e.deleted||Xt("clear-refused-shim",e.reason)}function hn(e){return qc(e)}function qc(e){try{return process.kill(e,0),!0}catch{return!1}}function se(){let e=UE();return e?hn(e.pid)?e:(zc(),null):null}var Gc,jE,cs,De=w(()=>{"use strict";I();So();_n();bo();Gc=yo(C,"daemon.pid"),jE=yo(C,"daemon.port"),cs=yo(C,"daemon.log")});import{existsSync as GE}from"node:fs";import{dirname as Qc}from"node:path";import{fileURLToPath as JE}from"node:url";function te(){if(ds)return ds;let e=Qc(JE(import.meta.url));for(;!GE(`${e}/package.json`);){let t=Qc(e);if(t===e)throw new Error(`package.json not found walking up from ${import.meta.url}`);e=t}return ds=e,ds}var ds,Ge=w(()=>{"use strict";ds=null});import{execFileSync as nl}from"node:child_process";function eb(e){for(let t of ZE)if(e.includes(t))return!0;return!1}function At(e={}){let t=e.psOutput??tb(),n=e.isProcessAlive??nb,s=e.getParentCommand??sb,r=[];for(let o of t.split(`
836
+ `)){let i=o.trim();if(!i||!eb(i)||rb(i))continue;let a=i.split(/\s+/);if(a.length<5)continue;let d=Number(a[0]),l=Number(a[1]),u=a[2],m=a[3],p=a[4],g=0,f=0;if(/^\d+$/.test(m)&&(p.includes(".")||/^\d+$/.test(p))?(g=Number(m),f=Number(p)):f=Number(m),!Number.isFinite(d)||!Number.isFinite(l))continue;let b=l>1&&n(l);r.push({pid:d,ppid:l,parentAlive:b,etimeSeconds:ob(u),pcpu:Number.isFinite(f)?f:0,rssKb:Number.isFinite(g)?g:0,orphan:!b,parentCommand:b?s(l):null})}return r}function tb(){try{return nl("ps",["-axo","pid,ppid,etime,rss,pcpu,command"],{encoding:"utf8",timeout:2e3,maxBuffer:5*1024*1024})}catch(e){let t=e instanceof Error?e.message:String(e);return process.stderr.write(`[mcp-processes] ps -axo failed: ${t}
837
+ `),""}}function nb(e){if(!Number.isFinite(e)||e<=1)return!1;try{return process.kill(e,0),!0}catch{return!1}}function sb(e){if(!Number.isFinite(e)||e<=1)return null;try{let n=nl("ps",["-p",String(e),"-o","command="],{encoding:"utf8",timeout:1e3,maxBuffer:1048576}).trim();return n.length?n.slice(0,200):null}catch{return null}}function rb(e){let t=e.split(/\s+/);if(t.length<5)return!1;let n=[t[5]??"",t[4]??""];for(let s of n)if(s&&(s.endsWith("/grep")||s==="grep"||s.endsWith("/awk")||s==="awk"||s.endsWith("/rg")||s==="rg"))return!0;return!1}function ob(e){if(!e)return 0;let t=0,n=e,s=e.indexOf("-");s>=0&&(t=Zc(e.slice(0,s)),n=e.slice(s+1));let r=n.split(":").map(Zc),o=0,i=0,a=0;return r.length===3?[o,i,a]=r:r.length===2?[i,a]=r:r.length===1&&(a=r[0]),t*86400+o*3600+i*60+a}function Zc(e){let t=Number(e);return Number.isFinite(t)?t:0}function ps(e){return e.pcpu>=ib&&e.etimeSeconds>=ab}function tl(e){return e.reduce((t,n)=>t+(Number.isFinite(n.rssKb)&&n.rssKb>0?n.rssKb:0),0)}function sl(e){let t=e??At(),n=t.length,s=tl(t),r=t.filter(p=>p.orphan),o=r.length,i=tl(r),a=o>el,d=i>cb;if(!(a||d))return{flagged:!1,severity:"ok",count:n,aggregateRssKb:s,orphanCount:o,orphanRssKb:i,message:null};let u=[];a&&u.push(`${o} orphaned MCP children (threshold ${el})`),d&&u.push(`${lb(i)} aggregate RSS across orphaned children (threshold 1 GiB)`);let m=`Zombie MCP threshold breached: ${u.join(" + ")}. Each orphaned MCP child (its parent claude/VS Code tab has exited) still holds a SQLite read connection and can pin WAL checkpoints. Run \`recall mcp-prune --all\` to reap (note: pre-2026-05-23 builds may miss processes from stale install paths -- \`pkill -f mcp-server.js\` is the nuclear option).`;return{flagged:!0,severity:"high",count:n,aggregateRssKb:s,orphanCount:o,orphanRssKb:i,message:m}}function lb(e){return e<1024?`${e} KB`:e<1024*1024?`${(e/1024).toFixed(1)} MB`:`${(e/(1024*1024)).toFixed(2)} GB`}var ZE,ib,ab,el,cb,En=w(()=>{"use strict";ZE=["dist/mcp-server.js","dist/mcp/server.js"];ib=50,ab=60;el=4,cb=1024*1024});function pt(e){if(e<60)return`${e}s`;if(e<3600)return`${Math.floor(e/60)}m`;if(e<86400)return`${Math.floor(e/3600)}h`;let t=Math.floor(e/86400),n=Math.floor(e%86400/3600);return n>0?`${t}d ${n}h`:`${t}d`}var ms=w(()=>{"use strict"});function gs(e,t="PASSIVE",n){let s=Date.now(),r=e.pragma(`wal_checkpoint(${t})`),o=ub(r),i={busy:o.busy,log:o.log,moved:o.checkpointed,mode:t,durationMs:Date.now()-s};return n&&(t==="PASSIVE"&&i.log>=db&&i.moved===0?n(`[wal-maintenance] PASSIVE checkpoint blocked: log=${i.log} frames pending, moved=0 (readers holding snapshots)`):i.moved>0&&n(`[wal-maintenance] ${t} checkpoint: log=${i.log} moved=${i.moved} busy=${i.busy} (${i.durationMs}ms)`)),i}function ub(e){let t=Array.isArray(e)?e[0]??{}:e??{};return{busy:wo(t.busy),log:wo(t.log),checkpointed:wo(t.checkpointed)}}function wo(e){return typeof e=="number"&&Number.isFinite(e)?e:typeof e=="bigint"?Number(e):0}var TI,rl,db,fs=w(()=>{"use strict";ms();En();TI=5*6e4,rl=1073741824,db=100});import{writeFileSync as qb}from"node:fs";import{join as Vb}from"node:path";function Ao(e){try{let t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return[]}function bs(e){return h().prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(e)?.alias??null}function Qb(){return h().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:Ao(t.previous_aliases)}))}function Gt(e,t){let n=t.trim();if(!n)throw new Error("alias must be non-empty");let s=h(),r=new Date().toISOString(),o=s.prepare("SELECT alias, previous_aliases FROM session_aliases WHERE session_id = ?").get(e),i=[];return o&&(i=Ao(o.previous_aliases),o.alias!==n&&i.push({alias:o.alias,replaced_at:r})),s.prepare(`INSERT INTO session_aliases (session_id, alias, updated_at, previous_aliases)
838
838
  VALUES (?, ?, ?, ?)
839
839
  ON CONFLICT(session_id) DO UPDATE SET
840
840
  alias = excluded.alias,
841
841
  updated_at = excluded.updated_at,
842
- previous_aliases = excluded.previous_aliases`).run(e,n,r,JSON.stringify(i)),vl(),{session_id:e,alias:n,updated_at:r,previous_aliases:i}}function Ol(e){let t=E(),n=new Date().toISOString(),s=t.prepare("SELECT alias, previous_aliases FROM session_aliases WHERE session_id = ?").get(e);if(!s)return;let r=xo(s.previous_aliases);r.push({alias:s.alias,replaced_at:n}),t.prepare(`UPDATE session_aliases SET alias = '', updated_at = ?, previous_aliases = ?
843
- WHERE session_id = ?`).run(n,JSON.stringify(r),e),vl()}function vl(){try{j();let e=Ub(),t={schema:"claude-recall.aliases.v1",backed_up_at:new Date().toISOString(),aliases:e};Pb(jb,JSON.stringify(t,null,2))}catch(e){console.error("[aliases] backup failed:",e)}}var jb,At=w(()=>{"use strict";k();I();jb=Fb(C,"aliases.json")});import{existsSync as Pl,mkdirSync as oS,readFileSync as iS,writeFileSync as aS}from"node:fs";import{homedir as cS}from"node:os";import{join as Fl}from"node:path";import{z as ze}from"zod";function jl(){return process.env.RECALL_HOME??Fl(cS(),".recall")}function lS(){let e=jl();Pl(e)||oS(e,{recursive:!0})}function Ul(){return Fl(jl(),"config.json")}function Hl(){let e=Ul();if(!Pl(e))return{};try{return JSON.parse(iS(e,"utf8"))}catch(t){return console.error("[semantic-config] failed to parse config.json, using defaults:",t),{}}}function we(){let e=Hl().semantic;if(!e)return{...Ss};let t=Bl.safeParse({...Ss,...e});return t.success?t.data:{...Ss}}function Je(e,t="unknown"){lS();let n=Hl(),s=Bl.parse({...Ss,...n.semantic??{},...e}),r={...n,semantic:s};return aS(Ul(),JSON.stringify(r,null,2)),dS(s.enabled,t),s}function dS(e,t="unknown"){let n=e?"1":"0",s=null;try{E().prepare(`INSERT INTO app_settings(key, value) VALUES ('semantic_enabled', ?)
844
- ON CONFLICT(key) DO UPDATE SET value = excluded.value`).run(n),console.log(`[semantic-config] gate flip: source=${t} value=${n} path=pooled at=${new Date().toISOString()}`);return}catch(r){s=r;let o=r instanceof Error?r.message:String(r);console.error(`[semantic-config] pooled getDb() failed while syncing semantic_enabled=${n}: ${o} \u2014 falling back to raw connection`)}try{let r=new Pt(ee);try{r.exec(`CREATE TABLE IF NOT EXISTS app_settings (
842
+ previous_aliases = excluded.previous_aliases`).run(e,n,r,JSON.stringify(i)),Pl(),{session_id:e,alias:n,updated_at:r,previous_aliases:i}}function $l(e){let t=h(),n=new Date().toISOString(),s=t.prepare("SELECT alias, previous_aliases FROM session_aliases WHERE session_id = ?").get(e);if(!s)return;let r=Ao(s.previous_aliases);r.push({alias:s.alias,replaced_at:n}),t.prepare(`UPDATE session_aliases SET alias = '', updated_at = ?, previous_aliases = ?
843
+ WHERE session_id = ?`).run(n,JSON.stringify(r),e),Pl()}function Pl(){try{j();let e=Qb(),t={schema:"claude-recall.aliases.v1",backed_up_at:new Date().toISOString(),aliases:e};qb(Kb,JSON.stringify(t,null,2))}catch(e){console.error("[aliases] backup failed:",e)}}var Kb,Lt=w(()=>{"use strict";k();I();Kb=Vb(C,"aliases.json")});import{existsSync as Hl,mkdirSync as hS,readFileSync as ES,writeFileSync as bS}from"node:fs";import{homedir as SS}from"node:os";import{join as Wl}from"node:path";import{z as Je}from"zod";function Xl(){return process.env.RECALL_HOME??Wl(SS(),".recall")}function yS(){let e=Xl();Hl(e)||hS(e,{recursive:!0})}function Gl(){return Wl(Xl(),"config.json")}function zl(){let e=Gl();if(!Hl(e))return{};try{return JSON.parse(ES(e,"utf8"))}catch(t){return console.error("[semantic-config] failed to parse config.json, using defaults:",t),{}}}function we(){let e=zl().semantic;if(!e)return{...ys};let t=Jl.safeParse({...ys,...e});return t.success?t.data:{...ys}}function ze(e,t="unknown"){yS();let n=zl(),s=Jl.parse({...ys,...n.semantic??{},...e}),r={...n,semantic:s};return bS(Gl(),JSON.stringify(r,null,2)),wS(s.enabled,t),s}function wS(e,t="unknown"){let n=e?"1":"0",s=null;try{h().prepare(`INSERT INTO app_settings(key, value) VALUES ('semantic_enabled', ?)
844
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value`).run(n),console.log(`[semantic-config] gate flip: source=${t} value=${n} path=pooled at=${new Date().toISOString()}`);return}catch(r){s=r;let o=r instanceof Error?r.message:String(r);console.error(`[semantic-config] pooled getDb() failed while syncing semantic_enabled=${n}: ${o} \u2014 falling back to raw connection`)}try{let r=new Pt(ee);try{r.pragma("busy_timeout = 15000")}catch(o){console.error(`[semantic-config] failed to set busy_timeout on raw fallback connection (will fail instantly under contention): ${o instanceof Error?o.message:String(o)}`)}try{r.exec(`CREATE TABLE IF NOT EXISTS app_settings (
845
845
  key TEXT PRIMARY KEY,
846
846
  value TEXT NOT NULL
847
847
  );`),r.prepare(`INSERT INTO app_settings(key, value) VALUES ('semantic_enabled', ?)
848
- ON CONFLICT(key) DO UPDATE SET value = excluded.value`).run(n),console.log(`[semantic-config] gate flip: source=${t} value=${n} path=fallback at=${new Date().toISOString()}`)}finally{r.close()}}catch(r){let o=r instanceof Error?r.message:String(r);console.error(`[semantic-config] raw-connection fallback ALSO failed for semantic_enabled=${n}: ${o} (original: ${s instanceof Error?s.message:String(s)})`)}}var Bl,Ss,Sn=w(()=>{"use strict";Jn();k();I();Bl=ze.object({enabled:ze.boolean().default(!1),model:ze.string().optional(),ratePerMinute:ze.number().int().min(1).max(600).default(30),lastProcessedSessionId:ze.string().nullable().default(null),backfillPaused:ze.boolean().default(!1),autoExtractEnabled:ze.boolean().default(!1),autoExtractIntervalMinutes:ze.number().int().min(5).max(720).default(60),autoExtractBatchSize:ze.number().int().min(1).max(20).default(1),autoResumeWorker:ze.boolean().default(!1)}),Ss={enabled:!1,ratePerMinute:30,lastProcessedSessionId:null,backfillPaused:!1,autoExtractEnabled:!1,autoExtractIntervalMinutes:60,autoExtractBatchSize:1,autoResumeWorker:!1}});import{writeFileSync as uS}from"node:fs";import{join as pS}from"node:path";function gS(e){return e.trim().toLowerCase().replace(/^#+/,"").replace(/[\s/\\]+/g,"-").replace(/[^a-z0-9\-._]/g,"").slice(0,40)}function Wl(e,t){let n=gS(t);if(!n)throw new Error("tag must contain at least one alphanumeric character");let s=E(),r=new Date().toISOString();return s.prepare("SELECT 1 FROM session_tags WHERE session_id = ? AND tag = ?").get(e,n)?{tag:n,added:!1}:(s.transaction(()=>{s.prepare("INSERT INTO session_tags (session_id, tag, created_at) VALUES (?, ?, ?)").run(e,n,r),s.prepare("INSERT INTO tag_events (session_id, tag, action, at) VALUES (?, ?, 'add', ?)").run(e,n,r)})(),fS(),{tag:n,added:!0})}function Xl(e){return E().prepare("SELECT tag FROM session_tags WHERE session_id = ? ORDER BY tag").all(e).map(t=>t.tag)}function fS(){try{j();let e=E(),t=e.prepare("SELECT session_id, tag, created_at FROM session_tags ORDER BY session_id, tag").all(),n=e.prepare("SELECT id, session_id, tag, action, at FROM tag_events ORDER BY at ASC, id ASC").all(),s={schema:"claude-recall.tags.v1",backed_up_at:new Date().toISOString(),current:t,events:n};uS(mS,JSON.stringify(s,null,2))}catch(e){console.error("[tags] backup failed:",e)}}var mS,Lo=w(()=>{"use strict";k();I();mS=pS(C,"tags.json")});function _S(e,t){let n=e.filter(o=>o.content_text&&o.content_text.trim().length>0);if(n.length<=t)return n;let s=new Set;s.add(0),s.add(n.length-1);let r=(n.length-2)/Math.max(1,t-2);for(let o=1;o<t-1;o++)s.add(Math.floor(o*r));return Array.from(s).sort((o,i)=>o-i).slice(0,t).map(o=>n[o])}function Gl(e){let t=E(),n={limit:e.limit??500},s=e.sessionIds&&e.sessionIds.length>0,r=s?"1=1":"s.message_count > 2";if(s){let i=e.sessionIds.map((a,d)=>`@sid_${d}`).join(", ");r+=` AND s.id IN (${i})`,e.sessionIds.forEach((a,d)=>{n[`sid_${d}`]=a})}return e.untaggedOnly&&(r+=" AND NOT EXISTS (SELECT 1 FROM session_tags st WHERE st.session_id = s.id)"),e.project&&(r+=" AND p.name = @project",n.project=e.project),e.collectionId&&(r+=" AND s.id IN (SELECT session_id FROM collection_sessions WHERE collection_id = @col)",n.col=e.collectionId),t.prepare(`SELECT s.id, p.name AS project, s.git_branch,
848
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value`).run(n),console.log(`[semantic-config] gate flip: source=${t} value=${n} path=fallback at=${new Date().toISOString()}`)}finally{r.close()}}catch(r){let o=r instanceof Error?r.message:String(r);console.error(`[semantic-config] raw-connection fallback ALSO failed for semantic_enabled=${n}: ${o} (original: ${s instanceof Error?s.message:String(s)})`)}}var Jl,ys,Sn=w(()=>{"use strict";Yn();k();I();Jl=Je.object({enabled:Je.boolean().default(!1),model:Je.string().optional(),ratePerMinute:Je.number().int().min(1).max(600).default(30),lastProcessedSessionId:Je.string().nullable().default(null),backfillPaused:Je.boolean().default(!1),autoExtractEnabled:Je.boolean().default(!1),autoExtractIntervalMinutes:Je.number().int().min(5).max(720).default(60),autoExtractBatchSize:Je.number().int().min(1).max(20).default(1),autoResumeWorker:Je.boolean().default(!1)}),ys={enabled:!1,ratePerMinute:30,lastProcessedSessionId:null,backfillPaused:!1,autoExtractEnabled:!1,autoExtractIntervalMinutes:60,autoExtractBatchSize:1,autoResumeWorker:!1}});import{writeFileSync as TS}from"node:fs";import{join as RS}from"node:path";function xS(e){return e.trim().toLowerCase().replace(/^#+/,"").replace(/[\s/\\]+/g,"-").replace(/[^a-z0-9\-._]/g,"").slice(0,40)}function Yl(e,t){let n=xS(t);if(!n)throw new Error("tag must contain at least one alphanumeric character");let s=h(),r=new Date().toISOString();return s.prepare("SELECT 1 FROM session_tags WHERE session_id = ? AND tag = ?").get(e,n)?{tag:n,added:!1}:(s.transaction(()=>{s.prepare("INSERT INTO session_tags (session_id, tag, created_at) VALUES (?, ?, ?)").run(e,n,r),s.prepare("INSERT INTO tag_events (session_id, tag, action, at) VALUES (?, ?, 'add', ?)").run(e,n,r)})(),CS(),{tag:n,added:!0})}function ql(e){return h().prepare("SELECT tag FROM session_tags WHERE session_id = ? ORDER BY tag").all(e).map(t=>t.tag)}function CS(){try{j();let e=h(),t=e.prepare("SELECT session_id, tag, created_at FROM session_tags ORDER BY session_id, tag").all(),n=e.prepare("SELECT id, session_id, tag, action, at FROM tag_events ORDER BY at ASC, id ASC").all(),s={schema:"claude-recall.tags.v1",backed_up_at:new Date().toISOString(),current:t,events:n};TS(kS,JSON.stringify(s,null,2))}catch(e){console.error("[tags] backup failed:",e)}}var kS,No=w(()=>{"use strict";k();I();kS=RS(C,"tags.json")});function AS(e,t){let n=e.filter(o=>o.content_text&&o.content_text.trim().length>0);if(n.length<=t)return n;let s=new Set;s.add(0),s.add(n.length-1);let r=(n.length-2)/Math.max(1,t-2);for(let o=1;o<t-1;o++)s.add(Math.floor(o*r));return Array.from(s).sort((o,i)=>o-i).slice(0,t).map(o=>n[o])}function Vl(e){let t=h(),n={limit:e.limit??500},s=e.sessionIds&&e.sessionIds.length>0,r=s?"1=1":"s.message_count > 2";if(s){let i=e.sessionIds.map((a,d)=>`@sid_${d}`).join(", ");r+=` AND s.id IN (${i})`,e.sessionIds.forEach((a,d)=>{n[`sid_${d}`]=a})}return e.untaggedOnly&&(r+=" AND NOT EXISTS (SELECT 1 FROM session_tags st WHERE st.session_id = s.id)"),e.project&&(r+=" AND p.name = @project",n.project=e.project),e.collectionId&&(r+=" AND s.id IN (SELECT session_id FROM collection_sessions WHERE collection_id = @col)",n.col=e.collectionId),t.prepare(`SELECT s.id, p.name AS project, s.git_branch,
849
849
  NULLIF(sa.alias, '') AS alias,
850
850
  COALESCE(s.first_user_message, '') AS first_user_message
851
851
  FROM sessions s
@@ -855,12 +855,12 @@ ${t.message}
855
855
  ORDER BY COALESCE(s.started_at, '') DESC
856
856
  LIMIT @limit`).all(n).map(i=>{let a=t.prepare(`SELECT role, COALESCE(content_text, '') AS content_text
857
857
  FROM messages WHERE session_id = ?
858
- ORDER BY COALESCE(timestamp, ''), rowid`).all(i.id),l=_S(a,5).map(u=>`${u.role}: ${u.content_text.slice(0,400)}`).join(`
858
+ ORDER BY COALESCE(timestamp, ''), rowid`).all(i.id),l=AS(a,5).map(u=>`${u.role}: ${u.content_text.slice(0,400)}`).join(`
859
859
  ---
860
- `);return{id:i.id,project:i.project,git_branch:i.git_branch,alias:i.alias,first_user_message:i.first_user_message,message_sample:l,current_tags:Xl(i.id)}})}var zl=w(()=>{"use strict";k();Lo()});import{z as Ae}from"zod";function Jl(e){let t=e.minTags??2,n=e.maxTags??4,s=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.`)):(s&&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}-${n} 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(`
861
- `)}var YM,qM,VM,KM,Yl=w(()=>{"use strict";YM={project:Ae.string().optional().describe("Exact project name match (optional)."),collectionId:Ae.string().optional().describe("Restrict to sessions in this collection (optional)."),sessionId:Ae.string().optional().describe("Full session UUID to tag just one session (optional)."),untaggedOnly:Ae.boolean().optional().describe("Skip sessions that already have any tag (default: true)."),limit:Ae.number().int().min(1).max(500).optional().describe("Max sessions to process (default: 100)."),minTags:Ae.number().int().min(1).max(10).optional().describe("Minimum tags per session (default: 2)."),maxTags:Ae.number().int().min(1).max(10).optional().describe("Maximum tags per session (default: 4).")};qM={sessionId:Ae.string().describe("Session UUID (or 8+-char prefix) to summarize."),mode:Ae.enum(["brief","detailed"]).optional().describe("brief = 3-5 bullets; detailed = paragraph + bullets. Default: brief.")},VM={sessionId:Ae.string().describe("Session UUID (or 8+-char prefix) to extract decisions from.")},KM={sessionId:Ae.string().describe("Session UUID (or 8+-char prefix) to find similar sessions to."),limit:Ae.number().int().min(1).max(20).optional().describe("How many similar sessions to surface (default: 5).")}});function ql(e,t){let n=hS.get(e);if(!(!n||n.size===0))for(let s of n)try{s(t)}catch{}}var hS,Vl=w(()=>{"use strict";hS=new Map});import{existsSync as ES,statSync as bS}from"node:fs";import{delimiter as SS,join as yS}from"node:path";function Kl(e){if(e.includes("/")||e.includes("\\")||e.includes(".."))return null;let t=(process.env.PATH??"").split(SS).filter(Boolean),n=process.platform==="win32"?[`${e}.exe`,`${e}.cmd`,`${e}.bat`,e]:[e];for(let s of t)for(let r of n){let o=yS(s,r);try{if(ES(o)&&bS(o).isFile())return o}catch{}}return null}function Ql(e){if(process.platform!=="win32"||!e)return!1;let t=e.toLowerCase();return t.endsWith(".cmd")||t.endsWith(".bat")}var Zl=w(()=>{"use strict"});var ys={};V(ys,{_resetClaudePathCacheForTests:()=>kS,buildScanPrompt:()=>td,isClaudeCliAvailable:()=>ae,runClaudeCliScan:()=>NS,spawnClaudePrompt:()=>Nt});import{spawn as wS}from"node:child_process";function ed(){if(zt!==void 0&&yn!==void 0)return{path:zt,available:yn};let e=Kl("claude");return zt=e??"claude",yn=e!==null,{path:zt,available:yn}}function RS(){return ed().path}function ae(){return ed().available}function kS(){zt=void 0,yn=void 0}function td(e){return Jl({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 xS(e,t){let n=t.get(e);return n||e.slice(0,8)}function CS(e){try{return Gl(e).map(n=>({id:n.id,label:n.alias&&n.alias.trim().length>0?n.alias:n.first_user_message&&n.first_user_message.trim().length>0?n.first_user_message.slice(0,60):n.id.slice(0,8)}))}catch{return[]}}function LS(e){let{scanId:t,total:n,labelTable:s}=e,r=new Set;return o=>{let i=o.trim();if(!i.startsWith("{"))return;let a;try{a=JSON.parse(i)}catch{return}if(!a||typeof a!="object")return;let d=a;if(!(d.type!=="assistant"||!d.message?.content))for(let l of d.message.content){if(l?.type!=="tool_use"||l.name!=="mcp__recall__apply_tags")continue;let u=l.input,m=typeof u?.sessionId=="string"?u.sessionId:null;!m||r.has(m)||(r.add(m),ql(t,{type:"progress",current:r.size,total:n,sessionId:m,sessionLabel:xS(m,s)}))}}}function AS(e){let t="";return n=>{t+=n.toString("utf8");let s=t.indexOf(`
860
+ `);return{id:i.id,project:i.project,git_branch:i.git_branch,alias:i.alias,first_user_message:i.first_user_message,message_sample:l,current_tags:ql(i.id)}})}var Kl=w(()=>{"use strict";k();No()});import{z as Le}from"zod";function Ql(e){let t=e.minTags??2,n=e.maxTags??4,s=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.`)):(s&&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}-${n} 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(`
861
+ `)}var gD,fD,_D,hD,Zl=w(()=>{"use strict";gD={project:Le.string().optional().describe("Exact project name match (optional)."),collectionId:Le.string().optional().describe("Restrict to sessions in this collection (optional)."),sessionId:Le.string().optional().describe("Full session UUID to tag just one session (optional)."),untaggedOnly:Le.boolean().optional().describe("Skip sessions that already have any tag (default: true)."),limit:Le.number().int().min(1).max(500).optional().describe("Max sessions to process (default: 100)."),minTags:Le.number().int().min(1).max(10).optional().describe("Minimum tags per session (default: 2)."),maxTags:Le.number().int().min(1).max(10).optional().describe("Maximum tags per session (default: 4).")};fD={sessionId:Le.string().describe("Session UUID (or 8+-char prefix) to summarize."),mode:Le.enum(["brief","detailed"]).optional().describe("brief = 3-5 bullets; detailed = paragraph + bullets. Default: brief.")},_D={sessionId:Le.string().describe("Session UUID (or 8+-char prefix) to extract decisions from.")},hD={sessionId:Le.string().describe("Session UUID (or 8+-char prefix) to find similar sessions to."),limit:Le.number().int().min(1).max(20).optional().describe("How many similar sessions to surface (default: 5).")}});function ed(e,t){let n=LS.get(e);if(!(!n||n.size===0))for(let s of n)try{s(t)}catch{}}var LS,td=w(()=>{"use strict";LS=new Map});import{existsSync as NS,statSync as OS}from"node:fs";import{delimiter as vS,join as IS}from"node:path";function nd(e){if(e.includes("/")||e.includes("\\")||e.includes(".."))return null;let t=(process.env.PATH??"").split(vS).filter(Boolean),n=process.platform==="win32"?[`${e}.exe`,`${e}.cmd`,`${e}.bat`,e]:[e];for(let s of t)for(let r of n){let o=IS(s,r);try{if(NS(o)&&OS(o).isFile())return o}catch{}}return null}function sd(e){if(process.platform!=="win32"||!e)return!1;let t=e.toLowerCase();return t.endsWith(".cmd")||t.endsWith(".bat")}var rd=w(()=>{"use strict"});var ws={};V(ws,{_resetClaudePathCacheForTests:()=>PS,buildScanPrompt:()=>id,isClaudeCliAvailable:()=>ae,runClaudeCliScan:()=>HS,spawnClaudePrompt:()=>Nt});import{spawn as MS}from"node:child_process";function od(){if(Jt!==void 0&&yn!==void 0)return{path:Jt,available:yn};let e=nd("claude");return Jt=e??"claude",yn=e!==null,{path:Jt,available:yn}}function $S(){return od().path}function ae(){return od().available}function PS(){Jt=void 0,yn=void 0}function id(e){return Ql({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 FS(e,t){let n=t.get(e);return n||e.slice(0,8)}function jS(e){try{return Vl(e).map(n=>({id:n.id,label:n.alias&&n.alias.trim().length>0?n.alias:n.first_user_message&&n.first_user_message.trim().length>0?n.first_user_message.slice(0,60):n.id.slice(0,8)}))}catch{return[]}}function US(e){let{scanId:t,total:n,labelTable:s}=e,r=new Set;return o=>{let i=o.trim();if(!i.startsWith("{"))return;let a;try{a=JSON.parse(i)}catch{return}if(!a||typeof a!="object")return;let d=a;if(!(d.type!=="assistant"||!d.message?.content))for(let l of d.message.content){if(l?.type!=="tool_use"||l.name!=="mcp__recall__apply_tags")continue;let u=l.input,m=typeof u?.sessionId=="string"?u.sessionId:null;!m||r.has(m)||(r.add(m),ed(t,{type:"progress",current:r.size,total:n,sessionId:m,sessionLabel:FS(m,s)}))}}}function BS(e){let t="";return n=>{t+=n.toString("utf8");let s=t.indexOf(`
862
862
  `);for(;s!==-1;){let r=t.slice(0,s);t=t.slice(s+1),r.length>0&&e(r),s=t.indexOf(`
863
- `)}}}async function NS(e,t={},n){let s=!!t.scanId,r=s?CS(e):[],o=new Map(r.map(d=>[d.id,d.label])),i=r.length,a;return s&&t.scanId&&(a=LS({scanId:t.scanId,total:i,labelTable:o})),nd({prompt:td(e),allowedTools:TS.split(","),opts:t,onProgress:n,onStdoutLine:a,outputFormat:s?"stream-json":"json"})}async function Nt(e,t,n={},s){return nd({prompt:e,allowedTools:t,opts:n,onProgress:s,outputFormat:"json"})}function nd(e){let{prompt:t,allowedTools:n,opts:s,onProgress:r,onStdoutLine:o,outputFormat:i}=e,a=["-p",t,"--output-format",i,"--allowedTools",n.join(","),"--permission-mode","bypassPermissions","--no-session-persistence"];return i==="stream-json"&&a.push("--verbose"),s.model&&a.push("--model",s.model),new Promise(d=>{let l=RS(),u=wS(l,a,{stdio:["ignore","pipe","pipe"],shell:Ql(l)||process.platform==="win32"&&zt==="claude"}),m=[],p=[],g=o?AS(o):void 0;u.stdout.on("data",h=>{m.push(h),g&&g(h)}),u.stderr.on("data",h=>{if(p.push(h),r){let _=h.toString("utf8").trim();_&&r(_)}});let f=setTimeout(()=>{u.kill("SIGKILL")},1800*1e3);u.on("close",h=>{clearTimeout(f),d({success:h===0,stdout:Buffer.concat(m).toString("utf8"),stderr:Buffer.concat(p).toString("utf8"),exitCode:h})}),u.on("error",h=>{clearTimeout(f),d({success:!1,stdout:"",stderr:String(h),exitCode:null})})})}var TS,zt,yn,Ye=w(()=>{"use strict";zl();Yl();Vl();Zl();TS=["mcp__recall__list_tags","mcp__recall__list_sessions_to_tag","mcp__recall__apply_tags"].join(",")});import{existsSync as OS,mkdirSync as vS,writeFileSync as IS}from"node:fs";import{homedir as MS}from"node:os";import{join as Ao}from"node:path";function jS(){return process.env.RECALL_HOME??Ao(MS(),".recall")}function sd(){return Ao(jS(),"semantic")}function US(){let e=sd();OS(e)||vS(e,{recursive:!0})}function BS(e){let t=E(),n=t.prepare(`SELECT s.id, s.message_count, s.first_user_message,
863
+ `)}}}async function HS(e,t={},n){let s=!!t.scanId,r=s?jS(e):[],o=new Map(r.map(d=>[d.id,d.label])),i=r.length,a;return s&&t.scanId&&(a=US({scanId:t.scanId,total:i,labelTable:o})),ad({prompt:id(e),allowedTools:DS.split(","),opts:t,onProgress:n,onStdoutLine:a,outputFormat:s?"stream-json":"json"})}async function Nt(e,t,n={},s){return ad({prompt:e,allowedTools:t,opts:n,onProgress:s,outputFormat:"json"})}function ad(e){let{prompt:t,allowedTools:n,opts:s,onProgress:r,onStdoutLine:o,outputFormat:i}=e,a=["-p",t,"--output-format",i,"--allowedTools",n.join(","),"--permission-mode","bypassPermissions","--no-session-persistence"];return i==="stream-json"&&a.push("--verbose"),s.model&&a.push("--model",s.model),new Promise(d=>{let l=$S(),u=MS(l,a,{stdio:["ignore","pipe","pipe"],shell:sd(l)||process.platform==="win32"&&Jt==="claude"}),m=[],p=[],g=o?BS(o):void 0;u.stdout.on("data",_=>{m.push(_),g&&g(_)}),u.stderr.on("data",_=>{if(p.push(_),r){let b=_.toString("utf8").trim();b&&r(b)}});let f=setTimeout(()=>{u.kill("SIGKILL")},1800*1e3);u.on("close",_=>{clearTimeout(f),d({success:_===0,stdout:Buffer.concat(m).toString("utf8"),stderr:Buffer.concat(p).toString("utf8"),exitCode:_})}),u.on("error",_=>{clearTimeout(f),d({success:!1,stdout:"",stderr:String(_),exitCode:null})})})}var DS,Jt,yn,Ye=w(()=>{"use strict";Kl();Zl();td();rd();DS=["mcp__recall__list_tags","mcp__recall__list_sessions_to_tag","mcp__recall__apply_tags"].join(",")});import{existsSync as WS,mkdirSync as XS,writeFileSync as GS}from"node:fs";import{homedir as JS}from"node:os";import{join as Oo}from"node:path";function KS(){return process.env.RECALL_HOME??Oo(JS(),".recall")}function cd(){return Oo(KS(),"semantic")}function QS(){let e=cd();WS(e)||XS(e,{recursive:!0})}function ZS(e){let t=h(),n=t.prepare(`SELECT s.id, s.message_count, s.first_user_message,
864
864
  p.name AS project,
865
865
  NULLIF(sa.alias, '') AS alias
866
866
  FROM sessions s
@@ -869,10 +869,10 @@ ${t.message}
869
869
  WHERE s.id = ?`).get(e);if(!n)return null;let s=t.prepare(`SELECT role, content_text
870
870
  FROM messages
871
871
  WHERE session_id = ? AND is_sidechain = 0
872
- ORDER BY COALESCE(timestamp, ''), rowid`).all(e),r=[],o=0;for(let i of s){if(!i.content_text)continue;let a=i.role??"system",d=i.content_text.replace(/```[\s\S]*?```/g,"[code]").replace(/<[^>]+>[\s\S]*?<\/[^>]+>/g,"").trim();if(!d)continue;let l=d.length>1500?d.slice(0,1500)+"\u2026":d,u=`${a}: ${l}`;if(o+u.length>$S)break;r.push(u),o+=u.length}return{id:n.id,alias:n.alias,project:n.project,firstUserMessage:n.first_user_message,excerpt:r.join(`
872
+ ORDER BY COALESCE(timestamp, ''), rowid`).all(e),r=[],o=0;for(let i of s){if(!i.content_text)continue;let a=i.role??"system",d=i.content_text.replace(/```[\s\S]*?```/g,"[code]").replace(/<[^>]+>[\s\S]*?<\/[^>]+>/g,"").trim();if(!d)continue;let l=d.length>1500?d.slice(0,1500)+"\u2026":d,u=`${a}: ${l}`;if(o+u.length>YS)break;r.push(u),o+=u.length}return{id:n.id,alias:n.alias,project:n.project,firstUserMessage:n.first_user_message,excerpt:r.join(`
873
873
 
874
- `),messageCount:n.message_count}}function HS(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(`
875
- `)}function WS(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 n=t.indexOf("{"),s=t.lastIndexOf("}");if(n===-1||s===-1||s<=n)return null;let r=t.slice(n,s+1);try{let o=JSON.parse(r),i=typeof o.summary=="string"?o.summary.trim():"",d=(Array.isArray(o.keywords)?o.keywords:[]).filter(l=>typeof l=="string").map(l=>l.trim().toLowerCase()).filter(l=>l.length>0&&l.length<64);return!i||d.length===0?null:{summary:i,keywords:Array.from(new Set(d)).slice(0,20)}}catch{return null}}function XS(e){let t=E(),n=e.keywords.join(",");t.prepare(`INSERT INTO session_semantic
874
+ `),messageCount:n.message_count}}function ey(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(`
875
+ `)}function ty(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 n=t.indexOf("{"),s=t.lastIndexOf("}");if(n===-1||s===-1||s<=n)return null;let r=t.slice(n,s+1);try{let o=JSON.parse(r),i=typeof o.summary=="string"?o.summary.trim():"",d=(Array.isArray(o.keywords)?o.keywords:[]).filter(l=>typeof l=="string").map(l=>l.trim().toLowerCase()).filter(l=>l.length>0&&l.length<64);return!i||d.length===0?null:{summary:i,keywords:Array.from(new Set(d)).slice(0,20)}}catch{return null}}function ny(e){let t=h(),n=e.keywords.join(",");t.prepare(`INSERT INTO session_semantic
876
876
  (session_id, summary, keywords, model, source_message_count, generated_at)
877
877
  VALUES (@session_id, @summary, @keywords, @model, @source_message_count, @generated_at)
878
878
  ON CONFLICT(session_id) DO UPDATE SET
@@ -880,23 +880,23 @@ ${t.message}
880
880
  keywords = excluded.keywords,
881
881
  model = excluded.model,
882
882
  source_message_count = excluded.source_message_count,
883
- generated_at = excluded.generated_at`).run({session_id:e.sessionId,summary:e.summary,keywords:n,model:e.model,source_message_count:e.sourceMessageCount,generated_at:e.generatedAt}),US();let s=Ao(sd(),`${e.sessionId}.json`);IS(s,JSON.stringify({version:DS,session_id:e.sessionId,summary:e.summary,keywords:e.keywords,model:e.model,source_message_count:e.sourceMessageCount,generated_at:e.generatedAt},null,2))}function GS(){let t=we().ratePerMinute,n=t/6e4;return(!ws||ws.capacity!==t)&&(ws={tokens:t,capacity:t,refillPerMs:n,lastRefill:Date.now()}),ws}function zS(e){let t=Date.now(),n=t-e.lastRefill;n>0&&(e.tokens=Math.min(e.capacity,e.tokens+n*e.refillPerMs),e.lastRefill=t)}async function JS(e){for(;;){if(e?.aborted)throw new Error("aborted");let t=GS();if(zS(t),t.tokens>=1){t.tokens-=1;return}let n=1-t.tokens,s=Math.max(50,Math.ceil(n/t.refillPerMs));await new Promise(r=>setTimeout(r,Math.min(s,5e3)))}}async function YS(e,t={}){let n=we();if(!n.enabled)return{sessionId:e,ok:!1,reason:"disabled"};if(!ae())return{sessionId:e,ok:!1,reason:"claude-cli-missing"};let s=BS(e);if(!s)return{sessionId:e,ok:!1,reason:"session-not-found"};if(s.messageCount<PS)return{sessionId:e,ok:!1,reason:"too-short"};if(!s.excerpt.trim())return{sessionId:e,ok:!1,reason:"empty-excerpt"};await JS(t.signal);let r=HS(s),o=await Nt(r,FS,{model:n.model});if(!o.success)return{sessionId:e,ok:!1,reason:`claude-cli-exit-${o.exitCode??"null"}`,model:n.model??null};let i=WS(o.stdout);return i?(XS({sessionId:s.id,summary:i.summary,keywords:i.keywords,model:n.model??null,sourceMessageCount:s.messageCount,generatedAt:new Date().toISOString()}),{sessionId:e,ok:!0,model:n.model??null}):{sessionId:e,ok:!1,reason:"parse-failed",model:n.model??null}}async function Ts(e={}){let t=we();if(!t.enabled)return{total:0,processed:0,ok:0,failed:0,currentSessionId:null};let n=E(),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=n.prepare(`SELECT s.id
883
+ generated_at = excluded.generated_at`).run({session_id:e.sessionId,summary:e.summary,keywords:n,model:e.model,source_message_count:e.sourceMessageCount,generated_at:e.generatedAt}),QS();let s=Oo(cd(),`${e.sessionId}.json`);GS(s,JSON.stringify({version:zS,session_id:e.sessionId,summary:e.summary,keywords:e.keywords,model:e.model,source_message_count:e.sourceMessageCount,generated_at:e.generatedAt},null,2))}function sy(){let t=we().ratePerMinute,n=t/6e4;return(!Ts||Ts.capacity!==t)&&(Ts={tokens:t,capacity:t,refillPerMs:n,lastRefill:Date.now()}),Ts}function ry(e){let t=Date.now(),n=t-e.lastRefill;n>0&&(e.tokens=Math.min(e.capacity,e.tokens+n*e.refillPerMs),e.lastRefill=t)}async function oy(e){for(;;){if(e?.aborted)throw new Error("aborted");let t=sy();if(ry(t),t.tokens>=1){t.tokens-=1;return}let n=1-t.tokens,s=Math.max(50,Math.ceil(n/t.refillPerMs));await new Promise(r=>setTimeout(r,Math.min(s,5e3)))}}async function iy(e,t={}){let n=we();if(!n.enabled)return{sessionId:e,ok:!1,reason:"disabled"};if(!ae())return{sessionId:e,ok:!1,reason:"claude-cli-missing"};let s=ZS(e);if(!s)return{sessionId:e,ok:!1,reason:"session-not-found"};if(s.messageCount<qS)return{sessionId:e,ok:!1,reason:"too-short"};if(!s.excerpt.trim())return{sessionId:e,ok:!1,reason:"empty-excerpt"};await oy(t.signal);let r=ey(s),o=await Nt(r,VS,{model:n.model});if(!o.success)return{sessionId:e,ok:!1,reason:`claude-cli-exit-${o.exitCode??"null"}`,model:n.model??null};let i=ty(o.stdout);return i?(ny({sessionId:s.id,summary:i.summary,keywords:i.keywords,model:n.model??null,sourceMessageCount:s.messageCount,generatedAt:new Date().toISOString()}),{sessionId:e,ok:!0,model:n.model??null}):{sessionId:e,ok:!1,reason:"parse-failed",model:n.model??null}}async function Rs(e={}){let t=we();if(!t.enabled)return{total:0,processed:0,ok:0,failed:0,currentSessionId:null};let n=h(),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=n.prepare(`SELECT s.id
884
884
  FROM sessions s
885
885
  LEFT JOIN session_semantic ss ON ss.session_id = s.id
886
886
  WHERE ${o}
887
887
  ORDER BY COALESCE(s.started_at, '') ASC, s.id ASC
888
- LIMIT @limit`).all(r),a={total:i.length,processed:0,ok:0,failed:0,currentSessionId:null};e.onProgress?.(a);for(let{id:d}of i){if(e.signal?.aborted||we().backfillPaused)break;a.currentSessionId=d,e.onProgress?.({...a});try{(await YS(d,{signal:e.signal})).ok?a.ok+=1:a.failed+=1}catch(u){a.failed+=1,console.error("[semantic.backfill] failed for",d,u)}a.processed+=1,Je({lastProcessedSessionId:d},"pipeline"),e.onProgress?.({...a})}return a.currentSessionId=null,e.onProgress?.({...a}),a}function rd(){let e=we(),t=E(),n=t.prepare("SELECT COUNT(*) AS n FROM sessions WHERE message_count >= 3").get().n,s=t.prepare("SELECT COUNT(*) AS n FROM session_semantic").get().n;return{enabled:e.enabled,claudeCliAvailable:ae(),ratePerMinute:e.ratePerMinute,model:e.model??null,totalSessions:n,processedSessions:s,pendingSessions:Math.max(0,n-s),lastProcessedSessionId:e.lastProcessedSessionId,backfillPaused:e.backfillPaused}}var DS,$S,PS,FS,ws,Rs=w(()=>{"use strict";k();Ye();Sn();DS=1,$S=12e3,PS=3,FS=[];ws=null});var ad={};V(ad,{downloadModel:()=>vo,getModelDir:()=>xs,isModelInstalled:()=>rt,uninstallModel:()=>Io});import{existsSync as Oo,mkdirSync as od,rmSync as No,createWriteStream as qS,statSync as VS}from"node:fs";import{join as ks}from"node:path";import{createHash as KS}from"node:crypto";import{readFile as QS}from"node:fs/promises";function xs(){return ks(C,"models","BAAI","bge-base-en-v1.5")}function rt(){let e=xs();return id.every(t=>Oo(ks(e,t.path)))}async function vo(e){let t=xs();od(t,{recursive:!0}),od(ks(t,"onnx"),{recursive:!0});for(let n of id){let s=ks(t,n.path),r=ZS+n.path,o=0;Oo(s)&&(o=VS(s).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 ${n.path}: HTTP ${a.status}`);let d=a.headers.get("content-length"),l=d?o+Number(d):0,u=a.body;if(!u)throw new Error(`No response body for ${n.path}`);let m=qS(s,{flags:o>0?"a":"w"}),p=u.getReader(),g=o;for(;;){let{done:_,value:b}=await p.read();if(_)break;m.write(Buffer.from(b)),g+=b.byteLength,e?.(n.path,g,l)}if(m.end(),await new Promise((_,b)=>{m.on("finish",_),m.on("error",b)}),n.sha256==="TODO_PLACEHOLDER")throw No(s),new Error(`Refusing to install: SHA-256 not pinned for ${n.path}. Update model-download.ts.`);let f=await QS(s);if(KS("sha256").update(f).digest("hex")!==n.sha256)throw No(s),new Error(`SHA-256 mismatch for ${n.path}`)}}function Io(){let e=xs();Oo(e)&&No(e,{recursive:!0,force:!0})}var ZS,id,wn=w(()=>{"use strict";I();ZS="https://huggingface.co/BAAI/bge-base-en-v1.5/resolve/main/",id=[{path:"config.json",sha256:"bc00af31a4a31b74040d73370aa83b62da34c90b75eb77bfa7db039d90abd591"},{path:"tokenizer.json",sha256:"d241a60d5e8f04cc1b2b3e9ef7a4921b27bf526d9f6050ab90f9267a1f9e5c66"},{path:"tokenizer_config.json",sha256:"9261e7d79b44c8195c1cada2b453e55b00aeb81e907a6664974b4d7776172ab3"},{path:"onnx/model.onnx",sha256:"9bc579acdba21c253c62a9bf866891355a63ffa3442b52c8a37d75b2ccb91848"}]});function Cs(e){let t=null;return()=>t||(t=(async()=>{try{return await e()}finally{t=null}})(),t)}var Mo=w(()=>{"use strict"});function ey(e){return["Semantic search is unavailable on this platform.","",`Reason: ${e.detail}`,"",`Platform: ${process.platform}/${process.arch}, Node ${process.version}`,"","Claude Recall supports macOS (arm64/x64), Linux (x64/arm64), and Windows (x64).","Core CLI features (search, list, context, daemon) work everywhere.","Only `recall semantic *` requires the on-device embedder.","","See: https://clauderecall.com/docs (Supported platforms) - or file an issue at","https://gitlab.com/clauderecallhq/clauderecallhq/-/issues with the platform line above."].join(`
889
- `)}var Ls,fe,Jt=w(()=>{"use strict";Ls="BAAI/bge-base-en-v1.5",fe=class extends Error{kind;path;underlying;cause;constructor(t){super(ey(t)),this.name="EmbedderUnavailableError",this.kind=t.kind,this.path=t.path,this.underlying=t.underlying,this.cause=t}}});var Os={};V(Os,{embed:()=>ly,embedQuery:()=>dy,getEmbedderStatus:()=>cy,loadEmbedder:()=>ay,unloadEmbedder:()=>uy});import{Worker as ty}from"node:worker_threads";import{join as ny}from"node:path";import{existsSync as sy}from"node:fs";function ry(){return ny(te(),"dist","daemon","embedder-worker.js")}function cd(e){for(let t of Tn.values())t.reject(e);Tn.clear()}function oy(){if(ot)return ot;let e=ry();if(!sy(e))throw new fe({kind:"bundle-missing",detail:"embedder-worker bundle not found - run `npm run build:cli` to emit it",path:e});let t=new ty(e);return t.on("message",n=>{let s=Tn.get(n.id);s&&(Tn.delete(n.id),s.resolve(n))}),t.on("error",n=>{console.error("[embedder-worker] thread error:",n);let s=n instanceof Error?n:new Error(String(n));cd(s),ot=null,qe=!1}),t.on("exit",n=>{n!==0&&(console.error(`[embedder-worker] exited with code ${n}`),cd(new Error(`embedder worker exited with code ${n}`))),ot=null,qe=!1}),ot=t,t}function As(e){return new Promise((t,n)=>{let s;try{s=oy()}catch(r){n(r instanceof Error?r:new Error(String(r)));return}Tn.set(e.id,{resolve:t,reject:n}),s.postMessage(e)})}function Ns(){return Do=Do+1>>>0,String(Do)}function Po(e){if(!e.ok)throw e.unavailable?new fe({kind:"platform-unsupported",detail:"embedder worker reports the runtime is unavailable on this platform",underlying:new Error(e.error)}):new Error(e.error);return e}async function ay(){if(!(qe&&ot))try{await iy(),qe=!0}catch(e){throw qe=!1,e}}function cy(){return{loaded:qe,modelId:Ls,dim:768}}async function ly(e){if(!qe)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");return Po(await As({id:Ns(),type:"embed",texts:e})).embeddings.map(n=>new Float32Array(n))}async function dy(e){if(!qe)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");let t=Po(await As({id:Ns(),type:"embedQuery",text:e}));return new Float32Array(t.embedding)}async function uy(){if(!ot){qe=!1;return}try{await As({id:Ns(),type:"unload"})}catch{}qe=!1;let e=ot;ot=null;try{await e.terminate()}catch{}}var ot,Tn,Do,qe,iy,ld=w(()=>{"use strict";Ge();Mo();Jt();ot=null,Tn=new Map,Do=0,qe=!1;iy=Cs(async()=>{Po(await As({id:Ns(),type:"load"}))})});var Uo={};V(Uo,{LLAMACPP_MODEL_ID:()=>ud,MODEL_ID:()=>Ls,embed:()=>Sy,embedQuery:()=>yy,getEmbedderStatus:()=>by,loadEmbedder:()=>Ey,unloadEmbedder:()=>wy});import{Worker as py}from"node:worker_threads";import{join as my}from"node:path";import{existsSync as gy}from"node:fs";function fy(){return my(te(),"dist","daemon","embedder-worker-llamacpp.js")}function dd(e){for(let t of Rn.values())t.reject(e);Rn.clear()}function _y(){if(it)return it;let e=fy();if(!gy(e))throw new fe({kind:"bundle-missing",detail:"embedder-worker-llamacpp bundle not found - run `npm run build:cli` to emit it",path:e});let t=new py(e);return t.on("message",n=>{let s=Rn.get(n.id);s&&(Rn.delete(n.id),s.resolve(n))}),t.on("error",n=>{console.error("[embedder-worker-llamacpp] thread error:",n);let s=n instanceof Error?n:new Error(String(n));dd(s),it=null,Ve=!1}),t.on("exit",n=>{n!==0&&(console.error(`[embedder-worker-llamacpp] exited with code ${n}`),dd(new Error(`embedder worker exited with code ${n}`))),it=null,Ve=!1}),it=t,t}function vs(e){return new Promise((t,n)=>{let s;try{s=_y()}catch(r){n(r instanceof Error?r:new Error(String(r)));return}Rn.set(e.id,{resolve:t,reject:n}),s.postMessage(e)})}function Is(){return Fo=Fo+1>>>0,String(Fo)}function jo(e){if(!e.ok)throw e.unavailable?new fe({kind:"platform-unsupported",detail:"embedder worker reports the llama.cpp runtime is unavailable on this platform",underlying:new Error(e.error)}):new Error(e.error);return e}async function Ey(){if(!(Ve&&it))try{await hy(),Ve=!0}catch(e){throw Ve=!1,e}}function by(){return{loaded:Ve,modelId:ud,dim:768}}async function Sy(e){if(!Ve)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");return jo(await vs({id:Is(),type:"embed",texts:e})).embeddings.map(n=>new Float32Array(n))}async function yy(e){if(!Ve)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");let t=jo(await vs({id:Is(),type:"embedQuery",text:e}));return new Float32Array(t.embedding)}async function wy(){if(!it){Ve=!1;return}try{await vs({id:Is(),type:"unload"})}catch{}Ve=!1;let e=it;it=null;try{await e.terminate()}catch{}}var ud,it,Rn,Fo,Ve,hy,pd=w(()=>{"use strict";Ge();Mo();Jt();Jt();ud="BAAI/bge-base-en-v1.5-gguf-q8_0";it=null,Rn=new Map,Fo=0,Ve=!1;hy=Cs(async()=>{jo(await vs({id:Is(),type:"load"}))})});var Ms={};V(Ms,{EmbedderUnavailableError:()=>fe,embed:()=>Ne,embedQuery:()=>Ry,getEmbedderStatus:()=>Z,loadEmbedder:()=>Ke,unloadEmbedder:()=>ky});function Ty(){let e=(process.env.RECALL_EMBEDDER_BACKEND??"").trim().toLowerCase();return e==="llama"||e==="llamacpp"?Uo:(e===""||e==="onnx"||process.stderr.write(`[embedder] RECALL_EMBEDDER_BACKEND="${e}" is not recognized; falling back to onnx. Valid values: onnx, llama.
890
- `),Os)}var kn,Ke,Z,Ne,Ry,ky,Pe=w(()=>{"use strict";ld();pd();Jt();kn=Ty(),Ke=kn.loadEmbedder,Z=kn.getEmbedderStatus,Ne=kn.embed,Ry=kn.embedQuery,ky=kn.unloadEmbedder});function md(e){return e.replace(/```json[\s\S]*?```/g,"[tool-call]").replace(/\{[\s\S]{200,}?\}/g,"[json-object]")}function xy(e){let t=[],o=0;for(;o<e.length;){let i=[],a=0;for(;i.length<5&&o<e.length;){let l=e[o],u=md(l.content_text??"");if(a+u.length>2e3&&i.length>=3)break;i.push(l),a+=u.length,o++}if(i.length===0)break;let d=i.map(l=>{let u=l.role??"system",m=md(l.content_text??"");return`[${u}] ${m}`}).join(`
888
+ LIMIT @limit`).all(r),a={total:i.length,processed:0,ok:0,failed:0,currentSessionId:null};e.onProgress?.(a);for(let{id:d}of i){if(e.signal?.aborted||we().backfillPaused)break;a.currentSessionId=d,e.onProgress?.({...a});try{(await iy(d,{signal:e.signal})).ok?a.ok+=1:a.failed+=1}catch(u){a.failed+=1,console.error("[semantic.backfill] failed for",d,u)}a.processed+=1,ze({lastProcessedSessionId:d},"pipeline"),e.onProgress?.({...a})}return a.currentSessionId=null,e.onProgress?.({...a}),a}function ld(){let e=we(),t=h(),n=t.prepare("SELECT COUNT(*) AS n FROM sessions WHERE message_count >= 3").get().n,s=t.prepare("SELECT COUNT(*) AS n FROM session_semantic").get().n;return{enabled:e.enabled,claudeCliAvailable:ae(),ratePerMinute:e.ratePerMinute,model:e.model??null,totalSessions:n,processedSessions:s,pendingSessions:Math.max(0,n-s),lastProcessedSessionId:e.lastProcessedSessionId,backfillPaused:e.backfillPaused}}var zS,YS,qS,VS,Ts,ks=w(()=>{"use strict";k();Ye();Sn();zS=1,YS=12e3,qS=3,VS=[];Ts=null});var pd={};V(pd,{downloadModel:()=>Mo,getModelDir:()=>Cs,isModelInstalled:()=>rt,uninstallModel:()=>Do});import{existsSync as Io,mkdirSync as dd,rmSync as vo,createWriteStream as ay,statSync as cy}from"node:fs";import{join as xs}from"node:path";import{createHash as ly}from"node:crypto";import{readFile as dy}from"node:fs/promises";function Cs(){return xs(C,"models","BAAI","bge-base-en-v1.5")}function rt(){let e=Cs();return ud.every(t=>Io(xs(e,t.path)))}async function Mo(e){let t=Cs();dd(t,{recursive:!0}),dd(xs(t,"onnx"),{recursive:!0});for(let n of ud){let s=xs(t,n.path),r=uy+n.path,o=0;Io(s)&&(o=cy(s).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 ${n.path}: HTTP ${a.status}`);let d=a.headers.get("content-length"),l=d?o+Number(d):0,u=a.body;if(!u)throw new Error(`No response body for ${n.path}`);let m=ay(s,{flags:o>0?"a":"w"}),p=u.getReader(),g=o;for(;;){let{done:b,value:E}=await p.read();if(b)break;m.write(Buffer.from(E)),g+=E.byteLength,e?.(n.path,g,l)}if(m.end(),await new Promise((b,E)=>{m.on("finish",b),m.on("error",E)}),n.sha256==="TODO_PLACEHOLDER")throw vo(s),new Error(`Refusing to install: SHA-256 not pinned for ${n.path}. Update model-download.ts.`);let f=await dy(s);if(ly("sha256").update(f).digest("hex")!==n.sha256)throw vo(s),new Error(`SHA-256 mismatch for ${n.path}`)}}function Do(){let e=Cs();Io(e)&&vo(e,{recursive:!0,force:!0})}var uy,ud,wn=w(()=>{"use strict";I();uy="https://huggingface.co/BAAI/bge-base-en-v1.5/resolve/main/",ud=[{path:"config.json",sha256:"bc00af31a4a31b74040d73370aa83b62da34c90b75eb77bfa7db039d90abd591"},{path:"tokenizer.json",sha256:"d241a60d5e8f04cc1b2b3e9ef7a4921b27bf526d9f6050ab90f9267a1f9e5c66"},{path:"tokenizer_config.json",sha256:"9261e7d79b44c8195c1cada2b453e55b00aeb81e907a6664974b4d7776172ab3"},{path:"onnx/model.onnx",sha256:"9bc579acdba21c253c62a9bf866891355a63ffa3442b52c8a37d75b2ccb91848"}]});function As(e){let t=null;return()=>t||(t=(async()=>{try{return await e()}finally{t=null}})(),t)}var $o=w(()=>{"use strict"});function py(e){return["Semantic search is unavailable on this platform.","",`Reason: ${e.detail}`,"",`Platform: ${process.platform}/${process.arch}, Node ${process.version}`,"","Claude Recall supports macOS (arm64/x64), Linux (x64/arm64), and Windows (x64).","Core CLI features (search, list, context, daemon) work everywhere.","Only `recall semantic *` requires the on-device embedder.","","See: https://clauderecall.com/docs (Supported platforms) - or file an issue at","https://gitlab.com/clauderecallhq/clauderecallhq/-/issues with the platform line above."].join(`
889
+ `)}var Ls,fe,zt=w(()=>{"use strict";Ls="BAAI/bge-base-en-v1.5",fe=class extends Error{kind;path;underlying;cause;constructor(t){super(py(t)),this.name="EmbedderUnavailableError",this.kind=t.kind,this.path=t.path,this.underlying=t.underlying,this.cause=t}}});var vs={};V(vs,{embed:()=>yy,embedQuery:()=>wy,getEmbedderStatus:()=>Sy,loadEmbedder:()=>by,unloadEmbedder:()=>Ty});import{Worker as my}from"node:worker_threads";import{join as gy}from"node:path";import{existsSync as fy}from"node:fs";function _y(){return gy(te(),"dist","daemon","embedder-worker.js")}function md(e){for(let t of Tn.values())t.reject(e);Tn.clear()}function hy(){if(ot)return ot;let e=_y();if(!fy(e))throw new fe({kind:"bundle-missing",detail:"embedder-worker bundle not found - run `npm run build:cli` to emit it",path:e});let t=new my(e);return t.on("message",n=>{let s=Tn.get(n.id);s&&(Tn.delete(n.id),s.resolve(n))}),t.on("error",n=>{console.error("[embedder-worker] thread error:",n);let s=n instanceof Error?n:new Error(String(n));md(s),ot=null,qe=!1}),t.on("exit",n=>{n!==0&&(console.error(`[embedder-worker] exited with code ${n}`),md(new Error(`embedder worker exited with code ${n}`))),ot=null,qe=!1}),ot=t,t}function Ns(e){return new Promise((t,n)=>{let s;try{s=hy()}catch(r){n(r instanceof Error?r:new Error(String(r)));return}Tn.set(e.id,{resolve:t,reject:n}),s.postMessage(e)})}function Os(){return Po=Po+1>>>0,String(Po)}function jo(e){if(!e.ok)throw e.unavailable?new fe({kind:"platform-unsupported",detail:"embedder worker reports the runtime is unavailable on this platform",underlying:new Error(e.error)}):new Error(e.error);return e}async function by(){if(!(qe&&ot))try{await Ey(),qe=!0}catch(e){throw qe=!1,e}}function Sy(){return{loaded:qe,modelId:Ls,dim:768}}async function yy(e){if(!qe)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");return jo(await Ns({id:Os(),type:"embed",texts:e})).embeddings.map(n=>new Float32Array(n))}async function wy(e){if(!qe)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");let t=jo(await Ns({id:Os(),type:"embedQuery",text:e}));return new Float32Array(t.embedding)}async function Ty(){if(!ot){qe=!1;return}try{await Ns({id:Os(),type:"unload"})}catch{}qe=!1;let e=ot;ot=null;try{await e.terminate()}catch{}}var ot,Tn,Po,qe,Ey,gd=w(()=>{"use strict";Ge();$o();zt();ot=null,Tn=new Map,Po=0,qe=!1;Ey=As(async()=>{jo(await Ns({id:Os(),type:"load"}))})});var Ho={};V(Ho,{LLAMACPP_MODEL_ID:()=>_d,MODEL_ID:()=>Ls,embed:()=>vy,embedQuery:()=>Iy,getEmbedderStatus:()=>Oy,loadEmbedder:()=>Ny,unloadEmbedder:()=>My});import{Worker as Ry}from"node:worker_threads";import{join as ky}from"node:path";import{existsSync as xy}from"node:fs";function Cy(){return ky(te(),"dist","daemon","embedder-worker-llamacpp.js")}function fd(e){for(let t of Rn.values())t.reject(e);Rn.clear()}function Ay(){if(it)return it;let e=Cy();if(!xy(e))throw new fe({kind:"bundle-missing",detail:"embedder-worker-llamacpp bundle not found - run `npm run build:cli` to emit it",path:e});let t=new Ry(e);return t.on("message",n=>{let s=Rn.get(n.id);s&&(Rn.delete(n.id),s.resolve(n))}),t.on("error",n=>{console.error("[embedder-worker-llamacpp] thread error:",n);let s=n instanceof Error?n:new Error(String(n));fd(s),it=null,Ve=!1}),t.on("exit",n=>{n!==0&&(console.error(`[embedder-worker-llamacpp] exited with code ${n}`),fd(new Error(`embedder worker exited with code ${n}`))),it=null,Ve=!1}),it=t,t}function Is(e){return new Promise((t,n)=>{let s;try{s=Ay()}catch(r){n(r instanceof Error?r:new Error(String(r)));return}Rn.set(e.id,{resolve:t,reject:n}),s.postMessage(e)})}function Ms(){return Uo=Uo+1>>>0,String(Uo)}function Bo(e){if(!e.ok)throw e.unavailable?new fe({kind:"platform-unsupported",detail:"embedder worker reports the llama.cpp runtime is unavailable on this platform",underlying:new Error(e.error)}):new Error(e.error);return e}async function Ny(){if(!(Ve&&it))try{await Ly(),Ve=!0}catch(e){throw Ve=!1,e}}function Oy(){return{loaded:Ve,modelId:_d,dim:768}}async function vy(e){if(!Ve)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");return Bo(await Is({id:Ms(),type:"embed",texts:e})).embeddings.map(n=>new Float32Array(n))}async function Iy(e){if(!Ve)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");let t=Bo(await Is({id:Ms(),type:"embedQuery",text:e}));return new Float32Array(t.embedding)}async function My(){if(!it){Ve=!1;return}try{await Is({id:Ms(),type:"unload"})}catch{}Ve=!1;let e=it;it=null;try{await e.terminate()}catch{}}var _d,it,Rn,Uo,Ve,Ly,hd=w(()=>{"use strict";Ge();$o();zt();zt();_d="BAAI/bge-base-en-v1.5-gguf-q8_0";it=null,Rn=new Map,Uo=0,Ve=!1;Ly=As(async()=>{Bo(await Is({id:Ms(),type:"load"}))})});var Ds={};V(Ds,{EmbedderUnavailableError:()=>fe,embed:()=>Ne,embedQuery:()=>$y,getEmbedderStatus:()=>Z,loadEmbedder:()=>Ke,unloadEmbedder:()=>Py});function Dy(){let e=(process.env.RECALL_EMBEDDER_BACKEND??"").trim().toLowerCase();return e==="llama"||e==="llamacpp"?Ho:(e===""||e==="onnx"||process.stderr.write(`[embedder] RECALL_EMBEDDER_BACKEND="${e}" is not recognized; falling back to onnx. Valid values: onnx, llama.
890
+ `),vs)}var kn,Ke,Z,Ne,$y,Py,Fe=w(()=>{"use strict";gd();hd();zt();kn=Dy(),Ke=kn.loadEmbedder,Z=kn.getEmbedderStatus,Ne=kn.embed,$y=kn.embedQuery,Py=kn.unloadEmbedder});function Ed(e){return e.replace(/```json[\s\S]*?```/g,"[tool-call]").replace(/\{[\s\S]{200,}?\}/g,"[json-object]")}function Fy(e){let t=[],o=0;for(;o<e.length;){let i=[],a=0;for(;i.length<5&&o<e.length;){let l=e[o],u=Ed(l.content_text??"");if(a+u.length>2e3&&i.length>=3)break;i.push(l),a+=u.length,o++}if(i.length===0)break;let d=i.map(l=>{let u=l.role??"system",m=Ed(l.content_text??"");return`[${u}] ${m}`}).join(`
891
891
 
892
- `);t.push({messageUuids:i.map(l=>l.uuid),text:d}),o<e.length&&i.length>=3&&(o=Math.max(o-1,o-1))}return t}function Bo(e){let n=E().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 xy(n)}var Ho=w(()=>{"use strict";k()});function Wo(e){let t=E();t.transaction(()=>{t.prepare("DELETE FROM vec_chunks WHERE rowid IN (SELECT rowid FROM chunk_meta WHERE session_id = ?)").run(e),t.prepare("SELECT name FROM sqlite_master WHERE name='vec_chunks_v1_backup'").get()&&t.prepare("DELETE FROM vec_chunks_v1_backup WHERE rowid IN (SELECT rowid FROM chunk_meta WHERE session_id = ?)").run(e),t.prepare("DELETE FROM chunk_meta WHERE session_id = ?").run(e)})()}var Xo=w(()=>{"use strict";k()});function gd(){try{return!!E().prepare("SELECT 1 AS held FROM migration_state WHERE status IN ('in_progress', 'paused') LIMIT 1").get()}catch(e){if((e instanceof Error?e.message:String(e)).includes("no such table: migration_state"))return!1;throw e}}function Go(){return E().prepare("UPDATE chunk_queue SET action = 'embed' WHERE action = 'pending_post_migration'").run().changes}function Ny(){return E().prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}function fd(){return{running:Cy,queueDepth:Ny(),lastProcessedAt:Ly,blacklistedCount:Ay.size,pausedForMigration:gd()}}var Cy,Ly,Ay,Ds=w(()=>{"use strict";k();Pe();Ho();Xo();Cy=!1,Ly=null,Ay=new Set});var bd={};V(bd,{ensureLlamaCppInstalled:()=>zy});import{spawn as Py}from"node:child_process";import{existsSync as Fy}from"node:fs";import{dirname as jy,resolve as Uy}from"node:path";import{fileURLToPath as By}from"node:url";function Wy(){let e=jy(By(import.meta.url));return Uy(e,"..","..")}async function Xy(){try{return await import("node-llama-cpp"),!0}catch{return!1}}function Gy(e){return new Promise(t=>{let n=["install","--no-save","--no-audit","--no-fund","--prefix",e,`node-llama-cpp@${Hy}`],s=Py("npm",n,{stdio:["ignore","inherit","inherit"],cwd:e,shell:process.platform==="win32"});s.on("error",r=>{t({ok:!1,error:`npm spawn failed: ${r instanceof Error?r.message:String(r)}`})}),s.on("exit",r=>{t(r===0?{ok:!0,action:"installed"}:{ok:!1,error:`npm install exited with code ${r}`})})})}async function zy(){if(await Xy())return{ok:!0,action:"already-installed"};let e=Wy();return Fy(e)?(console.log(`Installing node-llama-cpp into ${e} ...`),await Gy(e)):{ok:!1,error:`package root not found at ${e}`}}var Hy,Sd=w(()=>{"use strict";Hy="3.18.1"});var js={};V(js,{BGE_GGUF_Q8_EXPECTED_BYTES:()=>Rd,BGE_GGUF_Q8_SHA256:()=>Yt,BGE_GGUF_Q8_URL:()=>Td,downloadGgufModel:()=>nw,getGgufModelDir:()=>xn,getGgufModelPath:()=>Fs,isGgufModelInstalled:()=>tw,uninstallGgufModel:()=>sw,verifyGgufModelHash:()=>Cd});import{createHash as yd}from"node:crypto";import{createWriteStream as Jy,existsSync as Ps,mkdirSync as Yy,readFileSync as qy,rmSync as $s,statSync as wd,writeFileSync as Vy}from"node:fs";import{createReadStream as Ky}from"node:fs";import{join as zo}from"node:path";function xn(){return zo(C,"models","gguf")}function Fs(){return zo(xn(),Qy)}function kd(){return zo(xn(),Zy)}function ew(){try{let e=qy(kd(),"utf8"),t=JSON.parse(e);return typeof t.size=="number"&&typeof t.mtimeMs=="number"&&typeof t.sha256=="string"?t:null}catch{return null}}function xd(e){try{Vy(kd(),JSON.stringify(e)+`
893
- `,"utf8")}catch(t){console.warn("[recall] gguf verify-cache write failed (will rehash on next start):",t instanceof Error?t.message:String(t))}}function tw(){return Ps(Fs())}async function Cd(){let e=Fs();if(!Ps(e))return{ok:!1,reason:"model file missing"};let t=wd(e),n=ew();if(n!==null&&n.size===t.size&&n.mtimeMs===t.mtimeMs&&n.sha256===Yt)return{ok:!0};let s=yd("sha256"),r=Ky(e);await new Promise((i,a)=>{r.on("data",d=>s.update(d)),r.on("end",()=>i()),r.on("error",d=>a(d))});let o=s.digest("hex");return o!==Yt?(console.error(`[recall] GGUF integrity check failed at ${e}: computed ${o}, expected ${Yt}`),{ok:!1,reason:"model integrity check failed"}):(xd({size:t.size,mtimeMs:t.mtimeMs,sha256:o}),{ok:!0})}async function nw(e){let t=xn();Yy(t,{recursive:!0});let n=Fs();if(Ps(n)){if((await Cd()).ok)return;$s(n)}let s=await fetch(Td);if(!s.ok)throw new Error(`Failed to download GGUF model: HTTP ${s.status} ${s.statusText}`);let r=s.body;if(!r)throw new Error("Failed to download GGUF model: no response body");let o=s.headers.get("content-length"),i=o?Number(o):Rd,a=yd("sha256"),d=Jy(n,{flags:"w"}),l=r.getReader(),u=0,m=!1;try{for(;;){let{done:f,value:h}=await l.read();if(f)break;let _=Buffer.from(h);a.update(_),d.write(_)||await new Promise(b=>d.once("drain",b)),u+=_.byteLength,e?.(u,i)}d.end(),await new Promise((f,h)=>{d.on("finish",()=>f()),d.on("error",_=>h(_))})}catch(f){throw m=!0,f}finally{if(m){try{d.destroy()}catch{}try{$s(n,{force:!0})}catch{}}}let p=a.digest("hex");if(p!==Yt)throw $s(n,{force:!0}),console.error(`[recall] GGUF integrity check failed during download: computed ${p}, expected ${Yt}`),new fe({kind:"platform-unsupported",detail:"GGUF model integrity check failed during download"});let g=wd(n);xd({size:g.size,mtimeMs:g.mtimeMs,sha256:p})}function sw(){let e=xn();Ps(e)&&$s(e,{recursive:!0,force:!0})}var Yt,Td,Rd,Qy,Zy,Us=w(()=>{"use strict";I();Jt();Yt="ad1afe72cd6654a558667a3db10878b049a75bfd72912e1dabb91310d671173c",Td="https://huggingface.co/CompendiumLabs/bge-base-en-v1.5-gguf/resolve/main/bge-base-en-v1.5-q8_0.gguf",Rd=118438752,Qy="bge-base-en-v1.5-q8_0.gguf",Zy=".gguf-verify-cache.json"});var Md={};V(Md,{applyIntelMacOnnxFallback:()=>qo,detectRunningClaudeOnWindows:()=>Id,ensureTransformersInstalled:()=>gw});import{execFileSync as Hs,spawn as rw}from"node:child_process";import{existsSync as Jo,mkdtempSync as ow,mkdirSync as iw,readdirSync as vd,rmSync as Ld}from"node:fs";import{createRequire as aw}from"node:module";import{tmpdir as cw}from"node:os";import{dirname as Yo,join as Ws,resolve as lw}from"node:path";import{fileURLToPath as dw}from"node:url";function Nd(e){let t=Ws(e,"bin");if(!Jo(t))return!1;try{for(let n of vd(t)){if(!n.startsWith("napi-"))continue;let s=Ws(t,n,"darwin","x64","onnxruntime_binding.node");if(Jo(s))return!0}}catch{return!1}return!1}function Od(){let e=Yo(dw(import.meta.url));return lw(e,"..","..")}async function pw(){try{return await import("@huggingface/transformers"),!0}catch{return!1}}function mw(e){return new Promise(t=>{let n=["install","--no-save","--no-audit","--no-fund","--prefix",e,`@huggingface/transformers@${uw}`],s=rw("npm",n,{stdio:["ignore","inherit","inherit"],cwd:e,shell:process.platform==="win32"});s.on("error",r=>{t({ok:!1,error:`npm spawn failed: ${r instanceof Error?r.message:String(r)}`})}),s.on("exit",r=>{t(r===0?{ok:!0,action:"installed"}:{ok:!1,error:`npm install exited with code ${r}`})})})}function Id(){if(process.platform!=="win32")return!1;try{return Hs("tasklist",["/FI","IMAGENAME eq claude.exe"],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).toLowerCase().includes("claude.exe")}catch{return!1}}async function qo(e){if(process.platform!=="darwin"||process.arch!=="x64")return;let t;try{let s=Ad.resolve("@huggingface/transformers/package.json",{paths:[e]}),r=Ad.resolve("onnxruntime-node/package.json",{paths:[Yo(s)]});t=Yo(r)}catch{return}if(Nd(t))return;console.log(`[recall] Intel macOS detected: onnxruntime-node at ${t} is missing the darwin/x64 binding. Applying ${Bs} fallback (npm overrides did not propagate through the scoped-package hoisting).`);let n=ow(Ws(cw(),"recall-ort-pin-"));try{Hs("npm",["pack","--pack-destination",n,`onnxruntime-node@${Bs}`],{cwd:n,stdio:["ignore","inherit","inherit"]});let s=vd(n).find(r=>r.startsWith("onnxruntime-node-")&&r.endsWith(".tgz"));if(!s){console.warn("[recall] npm pack did not produce a tarball; Intel-Mac fallback skipped. Tier 2 may be unavailable.");return}if(Nd(t)){console.log("[recall] onnxruntime-node@"+Bs+" already in place (concurrent install raced us). Nothing to do.");return}Ld(t,{recursive:!0}),iw(t,{recursive:!0}),Hs("tar",["-xzf",Ws(n,s),"-C",t,"--strip-components=1"],{stdio:["ignore","inherit","inherit"]});try{Hs("node",["./script/install"],{cwd:t,stdio:["ignore","inherit","inherit"]})}catch{console.warn("[recall] onnxruntime-node postinstall returned non-zero; binding files are still in place. Continuing.")}console.log(`[recall] onnxruntime-node@${Bs} fallback applied at ${t}.`)}catch(s){console.error("[recall] Intel macOS onnxruntime-node fallback failed:",s instanceof Error?s.message:String(s)),console.error("[recall] Tier 2 (vector search) will be unavailable on this machine. Core CLI features remain functional.")}finally{try{Ld(n,{recursive:!0,force:!0})}catch{}}}async function gw(){if(await pw())return await qo(Od()),{ok:!0,action:"already-installed"};if(Id())return{ok:!1,error:"Close all Claude Code windows before running `recall semantic install` on Windows. claude.exe holds exclusive locks on shared dependency files (Windows kernel default), which causes the underlying npm install to fail with EBUSY. After closing Claude Code, rerun `recall semantic install` to complete the install."};let e=Od();if(!Jo(e))return{ok:!1,error:`package root not found at ${e}`};console.log(`Installing @huggingface/transformers into ${e} ...`);let t=await mw(e);return t.ok&&await qo(e),t}var Ad,uw,Bs,Dd=w(()=>{"use strict";Ad=aw(import.meta.url),uw="^4.2.0",Bs="1.23.2"});var Js={};V(Js,{CURRENT_MIGRATION_SCHEMA_VERSION:()=>Gs,UnsupportedMigrationSchemaError:()=>Xs,completeMigration:()=>Ko,detectStaleLock:()=>ei,failMigration:()=>Qo,getActiveMigration:()=>Cn,pauseMigration:()=>fw,releaseStaleLock:()=>ti,rollbackMigration:()=>Zo,rowToState:()=>qt,startMigration:()=>zs,updateCursor:()=>Vo});function qt(e){for(let t of["id","schema_version","status","started_at","model_id_old","model_id_new"])if(!(t in e))throw new Error(`migration_state row missing required column '${t}' (got: ${Object.keys(e).join(", ")})`);if(e.schema_version!==Gs)throw new Xs(typeof e.schema_version=="number"?e.schema_version:-1);return{id:e.id,schemaVersion:e.schema_version,status:e.status,startedAt:e.started_at,completedAt:e.completed_at??null,lockTakenAt:e.lock_taken_at??null,lockTakenByPid:e.lock_taken_by_pid??null,cursorSessionId:e.cursor_session_id??null,cursorChunkId:e.cursor_chunk_id??null,modelIdOld:e.model_id_old,modelIdNew:e.model_id_new}}function Cn(){let t=E().prepare("SELECT * FROM migration_state WHERE status IN ('in_progress', 'paused') ORDER BY id DESC LIMIT 1").get();return t?qt(t):null}function zs(e){let t=E(),n=Cn();if(n)throw new Error(`migration already in progress (id=${n.id})`);let s=new Date().toISOString(),r;try{r=t.prepare("INSERT INTO migration_state(schema_version, status, started_at, lock_taken_at, lock_taken_by_pid, model_id_old, model_id_new) VALUES (?, 'in_progress', ?, ?, ?, ?, ?)").run(Gs,s,s,process.pid,e.modelIdOld,e.modelIdNew)}catch(i){throw i instanceof Error&&i.message.includes("UNIQUE constraint failed")?new Error("migration already in progress (started by a parallel process)"):i}let o=t.prepare("SELECT * FROM migration_state WHERE id = ?").get(Number(r.lastInsertRowid));return qt(o)}function Ln(e,t,n){if(e.changes!==1)throw new Error(`${t}: expected exactly 1 row to update, got ${e.changes}. migrationId=${n} likely refers to a row that does not exist. This typically means the caller is holding a stale id from a previous daemon process.`)}function Vo(e,t){let s=E().prepare("UPDATE migration_state SET cursor_session_id = ?, cursor_chunk_id = ? WHERE id = ?").run(t.sessionId,t.chunkId,e);Ln(s,"updateCursor",e)}function fw(e){let n=E().prepare("UPDATE migration_state SET status = 'paused' WHERE id = ? AND status = 'in_progress'").run(e);Ln(n,"pauseMigration",e)}function Ko(e){let n=E().prepare("UPDATE migration_state SET status = 'completed', completed_at = datetime('now'), lock_taken_at = NULL, lock_taken_by_pid = NULL WHERE id = ?").run(e);Ln(n,"completeMigration",e)}function Qo(e,t){let n=E();console.error(`[migration] failed: ${t}`);let s=n.prepare("UPDATE migration_state SET status = 'failed', completed_at = datetime('now'), lock_taken_at = NULL, lock_taken_by_pid = NULL WHERE id = ?").run(e);Ln(s,"failMigration",e)}function Zo(e){let n=E().prepare("UPDATE migration_state SET status = 'rolled_back', completed_at = datetime('now') WHERE id = ?").run(e);Ln(n,"rollbackMigration",e)}function _w(e){try{return process.kill(e,0),!0}catch(t){return t.code==="EPERM"}}function ei(){let t=E().prepare("SELECT * FROM migration_state WHERE status = 'in_progress' AND lock_taken_by_pid IS NOT NULL LIMIT 1").get();if(!t)return null;let n=qt(t);return n.lockTakenByPid===null||n.lockTakenByPid===process.pid||_w(n.lockTakenByPid)?null:n}function ti(e,t={preserveCursor:!0}){let n=E(),s=n.prepare("SELECT id, cursor_chunk_id FROM migration_state WHERE status = 'in_progress' AND lock_taken_by_pid = ? LIMIT 1").get(e);if(!s)return console.warn(`[migration] releaseStaleLock: no row matched pid=${e} (already released or never existed)`),{released:!1,status:"no-op"};let r=t.preserveCursor&&s.cursor_chunk_id!==null,o=r?"paused":"failed",i=n.prepare(o==="paused"?"UPDATE migration_state SET status = 'paused', lock_taken_at = NULL, lock_taken_by_pid = NULL WHERE id = ? AND status = 'in_progress'":"UPDATE migration_state SET status = 'failed', completed_at = datetime('now'), lock_taken_at = NULL, lock_taken_by_pid = NULL WHERE id = ? AND status = 'in_progress'").run(s.id);return console.warn(`[migration] released stale lock pid=${e}, transitioned to '${o}' (${i.changes} row(s) updated; cursor preserved=${r})`),{released:i.changes===1,status:o}}var Gs,Xs,Vt=w(()=>{"use strict";k();Gs=1,Xs=class extends Error{constructor(t){super(`unsupported migration schema_version: found ${t}, this CLI understands ${Gs}. Upgrade or run 'recall semantic migrate --reset' to discard the cursor and start fresh.`),this.name="UnsupportedMigrationSchemaError"}}});async function si(e){let t=E(),n=t.pragma("busy_timeout",{simple:!0})??5e3;t.pragma("busy_timeout = 60000");try{if(t.prepare("SELECT name FROM sqlite_master WHERE name = 'vec_chunks_v1_backup'").get()){let i=t.prepare("SELECT COUNT(*) AS n FROM vec_chunks_v1_backup").get();console.warn(`[migration-swap] Existing rollback backup from prior migration replaced (vec_chunks_v1_backup had ${i.n} rows). The prior migration's 30-day rollback window is implicitly superseded by this new migration.`)}t.transaction(()=>{t.exec("DROP TABLE IF EXISTS vec_chunks_v1_backup;"),t.exec(`
892
+ `);t.push({messageUuids:i.map(l=>l.uuid),text:d}),o<e.length&&i.length>=3&&(o=Math.max(o-1,o-1))}return t}function Wo(e){let n=h().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 Fy(n)}var Xo=w(()=>{"use strict";k()});function Go(e){let t=h();t.transaction(()=>{t.prepare("DELETE FROM vec_chunks WHERE rowid IN (SELECT rowid FROM chunk_meta WHERE session_id = ?)").run(e),t.prepare("SELECT name FROM sqlite_master WHERE name='vec_chunks_v1_backup'").get()&&t.prepare("DELETE FROM vec_chunks_v1_backup WHERE rowid IN (SELECT rowid FROM chunk_meta WHERE session_id = ?)").run(e),t.prepare("DELETE FROM chunk_meta WHERE session_id = ?").run(e)})()}var Jo=w(()=>{"use strict";k()});function bd(){try{return!!h().prepare("SELECT 1 AS held FROM migration_state WHERE status IN ('in_progress', 'paused') LIMIT 1").get()}catch(e){if((e instanceof Error?e.message:String(e)).includes("no such table: migration_state"))return!1;throw e}}function zo(){return h().prepare("UPDATE chunk_queue SET action = 'embed' WHERE action = 'pending_post_migration'").run().changes}function Hy(){return h().prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}function Sd(){return{running:jy,queueDepth:Hy(),lastProcessedAt:Uy,blacklistedCount:By.size,pausedForMigration:bd()}}var jy,Uy,By,$s=w(()=>{"use strict";k();Fe();Xo();Jo();jy=!1,Uy=null,By=new Set});var Rd={};V(Rd,{ensureLlamaCppInstalled:()=>rw});import{spawn as qy}from"node:child_process";import{existsSync as Vy}from"node:fs";import{dirname as Ky,resolve as Qy}from"node:path";import{fileURLToPath as Zy}from"node:url";function tw(){let e=Ky(Zy(import.meta.url));return Qy(e,"..","..")}async function nw(){try{return await import("node-llama-cpp"),!0}catch{return!1}}function sw(e){return new Promise(t=>{let n=["install","--no-save","--no-audit","--no-fund","--prefix",e,`node-llama-cpp@${ew}`],s=qy("npm",n,{stdio:["ignore","inherit","inherit"],cwd:e,shell:process.platform==="win32"});s.on("error",r=>{t({ok:!1,error:`npm spawn failed: ${r instanceof Error?r.message:String(r)}`})}),s.on("exit",r=>{t(r===0?{ok:!0,action:"installed"}:{ok:!1,error:`npm install exited with code ${r}`})})})}async function rw(){if(await nw())return{ok:!0,action:"already-installed"};let e=tw();return Vy(e)?(console.log(`Installing node-llama-cpp into ${e} ...`),await sw(e)):{ok:!1,error:`package root not found at ${e}`}}var ew,kd=w(()=>{"use strict";ew="3.18.1"});var Us={};V(Us,{BGE_GGUF_Q8_EXPECTED_BYTES:()=>Ld,BGE_GGUF_Q8_SHA256:()=>Yt,BGE_GGUF_Q8_URL:()=>Ad,downloadGgufModel:()=>gw,getGgufModelDir:()=>xn,getGgufModelPath:()=>js,isGgufModelInstalled:()=>mw,uninstallGgufModel:()=>fw,verifyGgufModelHash:()=>vd});import{createHash as xd}from"node:crypto";import{createWriteStream as ow,existsSync as Fs,mkdirSync as iw,readFileSync as aw,rmSync as Ps,statSync as Cd,writeFileSync as cw}from"node:fs";import{createReadStream as lw}from"node:fs";import{join as Yo}from"node:path";function xn(){return Yo(C,"models","gguf")}function js(){return Yo(xn(),dw)}function Nd(){return Yo(xn(),uw)}function pw(){try{let e=aw(Nd(),"utf8"),t=JSON.parse(e);return typeof t.size=="number"&&typeof t.mtimeMs=="number"&&typeof t.sha256=="string"?t:null}catch{return null}}function Od(e){try{cw(Nd(),JSON.stringify(e)+`
893
+ `,"utf8")}catch(t){console.warn("[recall] gguf verify-cache write failed (will rehash on next start):",t instanceof Error?t.message:String(t))}}function mw(){return Fs(js())}async function vd(){let e=js();if(!Fs(e))return{ok:!1,reason:"model file missing"};let t=Cd(e),n=pw();if(n!==null&&n.size===t.size&&n.mtimeMs===t.mtimeMs&&n.sha256===Yt)return{ok:!0};let s=xd("sha256"),r=lw(e);await new Promise((i,a)=>{r.on("data",d=>s.update(d)),r.on("end",()=>i()),r.on("error",d=>a(d))});let o=s.digest("hex");return o!==Yt?(console.error(`[recall] GGUF integrity check failed at ${e}: computed ${o}, expected ${Yt}`),{ok:!1,reason:"model integrity check failed"}):(Od({size:t.size,mtimeMs:t.mtimeMs,sha256:o}),{ok:!0})}async function gw(e){let t=xn();iw(t,{recursive:!0});let n=js();if(Fs(n)){if((await vd()).ok)return;Ps(n)}let s=await fetch(Ad);if(!s.ok)throw new Error(`Failed to download GGUF model: HTTP ${s.status} ${s.statusText}`);let r=s.body;if(!r)throw new Error("Failed to download GGUF model: no response body");let o=s.headers.get("content-length"),i=o?Number(o):Ld,a=xd("sha256"),d=ow(n,{flags:"w"}),l=r.getReader(),u=0,m=!1;try{for(;;){let{done:f,value:_}=await l.read();if(f)break;let b=Buffer.from(_);a.update(b),d.write(b)||await new Promise(E=>d.once("drain",E)),u+=b.byteLength,e?.(u,i)}d.end(),await new Promise((f,_)=>{d.on("finish",()=>f()),d.on("error",b=>_(b))})}catch(f){throw m=!0,f}finally{if(m){try{d.destroy()}catch{}try{Ps(n,{force:!0})}catch{}}}let p=a.digest("hex");if(p!==Yt)throw Ps(n,{force:!0}),console.error(`[recall] GGUF integrity check failed during download: computed ${p}, expected ${Yt}`),new fe({kind:"platform-unsupported",detail:"GGUF model integrity check failed during download"});let g=Cd(n);Od({size:g.size,mtimeMs:g.mtimeMs,sha256:p})}function fw(){let e=xn();Fs(e)&&Ps(e,{recursive:!0,force:!0})}var Yt,Ad,Ld,dw,uw,Bs=w(()=>{"use strict";I();zt();Yt="ad1afe72cd6654a558667a3db10878b049a75bfd72912e1dabb91310d671173c",Ad="https://huggingface.co/CompendiumLabs/bge-base-en-v1.5-gguf/resolve/main/bge-base-en-v1.5-q8_0.gguf",Ld=118438752,dw="bge-base-en-v1.5-q8_0.gguf",uw=".gguf-verify-cache.json"});var jd={};V(jd,{applyIntelMacOnnxFallback:()=>Ko,detectRunningClaudeOnWindows:()=>Fd,ensureTransformersInstalled:()=>xw});import{execFileSync as Ws,spawn as _w}from"node:child_process";import{existsSync as qo,mkdtempSync as hw,mkdirSync as Ew,readdirSync as Pd,rmSync as Id}from"node:fs";import{createRequire as bw}from"node:module";import{tmpdir as Sw}from"node:os";import{dirname as Vo,join as Xs,resolve as yw}from"node:path";import{fileURLToPath as ww}from"node:url";function Dd(e){let t=Xs(e,"bin");if(!qo(t))return!1;try{for(let n of Pd(t)){if(!n.startsWith("napi-"))continue;let s=Xs(t,n,"darwin","x64","onnxruntime_binding.node");if(qo(s))return!0}}catch{return!1}return!1}function $d(){let e=Vo(ww(import.meta.url));return yw(e,"..","..")}async function Rw(){try{return await import("@huggingface/transformers"),!0}catch{return!1}}function kw(e){return new Promise(t=>{let n=["install","--no-save","--no-audit","--no-fund","--prefix",e,`@huggingface/transformers@${Tw}`],s=_w("npm",n,{stdio:["ignore","inherit","inherit"],cwd:e,shell:process.platform==="win32"});s.on("error",r=>{t({ok:!1,error:`npm spawn failed: ${r instanceof Error?r.message:String(r)}`})}),s.on("exit",r=>{t(r===0?{ok:!0,action:"installed"}:{ok:!1,error:`npm install exited with code ${r}`})})})}function Fd(){if(process.platform!=="win32")return!1;try{return Ws("tasklist",["/FI","IMAGENAME eq claude.exe"],{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).toLowerCase().includes("claude.exe")}catch{return!1}}async function Ko(e){if(process.platform!=="darwin"||process.arch!=="x64")return;let t;try{let s=Md.resolve("@huggingface/transformers/package.json",{paths:[e]}),r=Md.resolve("onnxruntime-node/package.json",{paths:[Vo(s)]});t=Vo(r)}catch{return}if(Dd(t))return;console.log(`[recall] Intel macOS detected: onnxruntime-node at ${t} is missing the darwin/x64 binding. Applying ${Hs} fallback (npm overrides did not propagate through the scoped-package hoisting).`);let n=hw(Xs(Sw(),"recall-ort-pin-"));try{Ws("npm",["pack","--pack-destination",n,`onnxruntime-node@${Hs}`],{cwd:n,stdio:["ignore","inherit","inherit"]});let s=Pd(n).find(r=>r.startsWith("onnxruntime-node-")&&r.endsWith(".tgz"));if(!s){console.warn("[recall] npm pack did not produce a tarball; Intel-Mac fallback skipped. Tier 2 may be unavailable.");return}if(Dd(t)){console.log("[recall] onnxruntime-node@"+Hs+" already in place (concurrent install raced us). Nothing to do.");return}Id(t,{recursive:!0}),Ew(t,{recursive:!0}),Ws("tar",["-xzf",Xs(n,s),"-C",t,"--strip-components=1"],{stdio:["ignore","inherit","inherit"]});try{Ws("node",["./script/install"],{cwd:t,stdio:["ignore","inherit","inherit"]})}catch{console.warn("[recall] onnxruntime-node postinstall returned non-zero; binding files are still in place. Continuing.")}console.log(`[recall] onnxruntime-node@${Hs} fallback applied at ${t}.`)}catch(s){console.error("[recall] Intel macOS onnxruntime-node fallback failed:",s instanceof Error?s.message:String(s)),console.error("[recall] Tier 2 (vector search) will be unavailable on this machine. Core CLI features remain functional.")}finally{try{Id(n,{recursive:!0,force:!0})}catch{}}}async function xw(){if(await Rw())return await Ko($d()),{ok:!0,action:"already-installed"};if(Fd())return{ok:!1,error:"Close all Claude Code windows before running `recall semantic install` on Windows. claude.exe holds exclusive locks on shared dependency files (Windows kernel default), which causes the underlying npm install to fail with EBUSY. After closing Claude Code, rerun `recall semantic install` to complete the install."};let e=$d();if(!qo(e))return{ok:!1,error:`package root not found at ${e}`};console.log(`Installing @huggingface/transformers into ${e} ...`);let t=await kw(e);return t.ok&&await Ko(e),t}var Md,Tw,Hs,Ud=w(()=>{"use strict";Md=bw(import.meta.url),Tw="^4.2.0",Hs="1.23.2"});var Ys={};V(Ys,{CURRENT_MIGRATION_SCHEMA_VERSION:()=>Js,UnsupportedMigrationSchemaError:()=>Gs,completeMigration:()=>Zo,detectStaleLock:()=>ni,failMigration:()=>ei,getActiveMigration:()=>Cn,pauseMigration:()=>Cw,releaseStaleLock:()=>si,rollbackMigration:()=>ti,rowToState:()=>qt,startMigration:()=>zs,updateCursor:()=>Qo});function qt(e){for(let t of["id","schema_version","status","started_at","model_id_old","model_id_new"])if(!(t in e))throw new Error(`migration_state row missing required column '${t}' (got: ${Object.keys(e).join(", ")})`);if(e.schema_version!==Js)throw new Gs(typeof e.schema_version=="number"?e.schema_version:-1);return{id:e.id,schemaVersion:e.schema_version,status:e.status,startedAt:e.started_at,completedAt:e.completed_at??null,lockTakenAt:e.lock_taken_at??null,lockTakenByPid:e.lock_taken_by_pid??null,cursorSessionId:e.cursor_session_id??null,cursorChunkId:e.cursor_chunk_id??null,modelIdOld:e.model_id_old,modelIdNew:e.model_id_new}}function Cn(){let t=h().prepare("SELECT * FROM migration_state WHERE status IN ('in_progress', 'paused') ORDER BY id DESC LIMIT 1").get();return t?qt(t):null}function zs(e){let t=h(),n=Cn();if(n)throw new Error(`migration already in progress (id=${n.id})`);let s=new Date().toISOString(),r;try{r=t.prepare("INSERT INTO migration_state(schema_version, status, started_at, lock_taken_at, lock_taken_by_pid, model_id_old, model_id_new) VALUES (?, 'in_progress', ?, ?, ?, ?, ?)").run(Js,s,s,process.pid,e.modelIdOld,e.modelIdNew)}catch(i){throw i instanceof Error&&i.message.includes("UNIQUE constraint failed")?new Error("migration already in progress (started by a parallel process)"):i}let o=t.prepare("SELECT * FROM migration_state WHERE id = ?").get(Number(r.lastInsertRowid));return qt(o)}function An(e,t,n){if(e.changes!==1)throw new Error(`${t}: expected exactly 1 row to update, got ${e.changes}. migrationId=${n} likely refers to a row that does not exist. This typically means the caller is holding a stale id from a previous daemon process.`)}function Qo(e,t){let s=h().prepare("UPDATE migration_state SET cursor_session_id = ?, cursor_chunk_id = ? WHERE id = ?").run(t.sessionId,t.chunkId,e);An(s,"updateCursor",e)}function Cw(e){let n=h().prepare("UPDATE migration_state SET status = 'paused' WHERE id = ? AND status = 'in_progress'").run(e);An(n,"pauseMigration",e)}function Zo(e){let n=h().prepare("UPDATE migration_state SET status = 'completed', completed_at = datetime('now'), lock_taken_at = NULL, lock_taken_by_pid = NULL WHERE id = ?").run(e);An(n,"completeMigration",e)}function ei(e,t){let n=h();console.error(`[migration] failed: ${t}`);let s=n.prepare("UPDATE migration_state SET status = 'failed', completed_at = datetime('now'), lock_taken_at = NULL, lock_taken_by_pid = NULL WHERE id = ?").run(e);An(s,"failMigration",e)}function ti(e){let n=h().prepare("UPDATE migration_state SET status = 'rolled_back', completed_at = datetime('now') WHERE id = ?").run(e);An(n,"rollbackMigration",e)}function Aw(e){try{return process.kill(e,0),!0}catch(t){return t.code==="EPERM"}}function ni(){let t=h().prepare("SELECT * FROM migration_state WHERE status = 'in_progress' AND lock_taken_by_pid IS NOT NULL LIMIT 1").get();if(!t)return null;let n=qt(t);return n.lockTakenByPid===null||n.lockTakenByPid===process.pid||Aw(n.lockTakenByPid)?null:n}function si(e,t={preserveCursor:!0}){let n=h(),s=n.prepare("SELECT id, cursor_chunk_id FROM migration_state WHERE status = 'in_progress' AND lock_taken_by_pid = ? LIMIT 1").get(e);if(!s)return console.warn(`[migration] releaseStaleLock: no row matched pid=${e} (already released or never existed)`),{released:!1,status:"no-op"};let r=t.preserveCursor&&s.cursor_chunk_id!==null,o=r?"paused":"failed",i=n.prepare(o==="paused"?"UPDATE migration_state SET status = 'paused', lock_taken_at = NULL, lock_taken_by_pid = NULL WHERE id = ? AND status = 'in_progress'":"UPDATE migration_state SET status = 'failed', completed_at = datetime('now'), lock_taken_at = NULL, lock_taken_by_pid = NULL WHERE id = ? AND status = 'in_progress'").run(s.id);return console.warn(`[migration] released stale lock pid=${e}, transitioned to '${o}' (${i.changes} row(s) updated; cursor preserved=${r})`),{released:i.changes===1,status:o}}var Js,Gs,Vt=w(()=>{"use strict";k();Js=1,Gs=class extends Error{constructor(t){super(`unsupported migration schema_version: found ${t}, this CLI understands ${Js}. Upgrade or run 'recall semantic migrate --reset' to discard the cursor and start fresh.`),this.name="UnsupportedMigrationSchemaError"}}});async function oi(e){let t=h(),n=t.pragma("busy_timeout",{simple:!0})??5e3;t.pragma("busy_timeout = 60000");try{if(t.prepare("SELECT name FROM sqlite_master WHERE name = 'vec_chunks_v1_backup'").get()){let i=t.prepare("SELECT COUNT(*) AS n FROM vec_chunks_v1_backup").get();console.warn(`[migration-swap] Existing rollback backup from prior migration replaced (vec_chunks_v1_backup had ${i.n} rows). The prior migration's 30-day rollback window is implicitly superseded by this new migration.`)}t.transaction(()=>{t.exec("DROP TABLE IF EXISTS vec_chunks_v1_backup;"),t.exec(`
894
894
  CREATE TABLE IF NOT EXISTS vec_chunks_v1_backup (
895
895
  rowid INTEGER PRIMARY KEY,
896
896
  embedding BLOB NOT NULL
897
897
  );
898
- `),t.exec("INSERT INTO vec_chunks_v1_backup(rowid, embedding) SELECT rowid, embedding FROM vec_chunks;"),t.exec("DELETE FROM vec_chunks;"),t.exec("INSERT INTO vec_chunks(rowid, embedding) SELECT rowid, embedding FROM vec_chunks_v2;"),t.exec("DROP TABLE vec_chunks_v2;"),t.prepare("UPDATE chunk_meta SET embedding_model_id = (SELECT model_id_new FROM migration_state WHERE id = ?) WHERE rowid IN (SELECT rowid FROM vec_chunks)").run(e)})();let o;try{o=await hw()}catch(i){let{failMigration:a}=await Promise.resolve().then(()=>(Vt(),Js)),d=i instanceof Error?i.message:String(i);throw a(e,d),i}if(!o.ok){let{failMigration:i}=await Promise.resolve().then(()=>(Vt(),Js));throw i(e,o.message),new Error(`atomic swap verification failed: ${o.message}`)}try{Ko(e)}catch(i){console.error(`[migration-swap] CRITICAL: swap + verify succeeded but completeMigration(${e}) threw: ${i instanceof Error?i.message:String(i)}. Live vec_chunks holds the new backend's vectors and vec_chunks_v1_backup retains the old set, but migration_state row is stuck in_progress. Recover via: sqlite3 ~/.recall/db.sqlite "UPDATE migration_state SET status='completed', completed_at=datetime('now'), lock_taken_at=NULL, lock_taken_by_pid=NULL WHERE id=${e};"`)}}finally{t.pragma(`busy_timeout = ${n}`)}}async function hw(){let e=E();try{let t=e.prepare("SELECT COUNT(*) AS n FROM vec_chunks").get(),n=e.prepare("SELECT COUNT(*) AS n FROM chunk_meta").get();if(n.n!==t.n)return{ok:!1,message:`post-swap row count mismatch: vec_chunks=${t.n}, chunk_meta=${n.n}, delta=${n.n-t.n} (chunk_meta rows without matching vec_chunks vectors)`,rowCount:t.n};if(t.n===0)return{ok:!0,message:"vec_chunks empty post-swap (no data to migrate)",rowCount:0};let s=e.prepare("SELECT embedding FROM vec_chunks LIMIT 1").get();return e.prepare("SELECT rowid, distance FROM vec_chunks WHERE embedding MATCH ? ORDER BY distance LIMIT 1").all(s.embedding).length===0?{ok:!1,message:"post-swap kNN returned no rows",rowCount:t.n}:{ok:!0,message:`post-swap smoke kNN ok, ${t.n} rows (matches chunk_meta)`,rowCount:t.n}}catch(t){throw process.stderr.write(`[migration-swap] verifyPostSwap threw after swap commit: ${t instanceof Error?t.stack??t.message:String(t)}
899
- `),new ni(`post-swap verification failed: ${t instanceof Error?t.message:String(t)}`,t)}}var ni,$d=w(()=>{"use strict";k();Vt();ni=class extends Error{cause;constructor(t,n){super(t),this.name="MigrationVerificationError",this.cause=n}}});import{promises as Ew}from"node:fs";import{dirname as ri}from"node:path";function Pd(e){return e<=0?0:Math.ceil(e*(bw+Sw)*yw)}async function Fd(e){let t=e.dbPath??ee,n;try{n=await Ew.statfs(ri(t))}catch(i){return{ok:!1,message:`disk space check failed: could not read filesystem at ${ri(t)}: ${i instanceof Error?i.message:String(i)}`,availableBytes:0,requiredBytes:e.requiredBytes}}let s=Number(n.bavail)*Number(n.bsize),r=s>=e.requiredBytes,o=r?`disk space check: required: ${e.requiredBytes} bytes, available: ${s} bytes`:`disk space check FAILED. required: ${e.requiredBytes} bytes, available: ${s} bytes. Free up space on ${ri(t)} or run on a different filesystem.`;return{ok:r,message:o,availableBytes:s,requiredBytes:e.requiredBytes}}function jd(e={}){let t=E(),n=Z().modelId;if(!n)throw new Error("countChunksToMigrate: embedder not loaded or modelId is empty");return e.scopeProjectId!==void 0?t.prepare(`SELECT COUNT(*) AS n FROM chunk_meta cm
898
+ `),t.exec("INSERT INTO vec_chunks_v1_backup(rowid, embedding) SELECT rowid, embedding FROM vec_chunks;"),t.exec("DELETE FROM vec_chunks;"),t.exec("INSERT INTO vec_chunks(rowid, embedding) SELECT rowid, embedding FROM vec_chunks_v2;"),t.exec("DROP TABLE vec_chunks_v2;"),t.prepare("UPDATE chunk_meta SET embedding_model_id = (SELECT model_id_new FROM migration_state WHERE id = ?) WHERE rowid IN (SELECT rowid FROM vec_chunks)").run(e)})();let o;try{o=await Lw()}catch(i){let{failMigration:a}=await Promise.resolve().then(()=>(Vt(),Ys)),d=i instanceof Error?i.message:String(i);throw a(e,d),i}if(!o.ok){let{failMigration:i}=await Promise.resolve().then(()=>(Vt(),Ys));throw i(e,o.message),new Error(`atomic swap verification failed: ${o.message}`)}try{Zo(e)}catch(i){console.error(`[migration-swap] CRITICAL: swap + verify succeeded but completeMigration(${e}) threw: ${i instanceof Error?i.message:String(i)}. Live vec_chunks holds the new backend's vectors and vec_chunks_v1_backup retains the old set, but migration_state row is stuck in_progress. Recover via: sqlite3 ~/.recall/db.sqlite "UPDATE migration_state SET status='completed', completed_at=datetime('now'), lock_taken_at=NULL, lock_taken_by_pid=NULL WHERE id=${e};"`)}}finally{t.pragma(`busy_timeout = ${n}`)}}async function Lw(){let e=h();try{let t=e.prepare("SELECT COUNT(*) AS n FROM vec_chunks").get(),n=e.prepare("SELECT COUNT(*) AS n FROM chunk_meta").get();if(n.n!==t.n)return{ok:!1,message:`post-swap row count mismatch: vec_chunks=${t.n}, chunk_meta=${n.n}, delta=${n.n-t.n} (chunk_meta rows without matching vec_chunks vectors)`,rowCount:t.n};if(t.n===0)return{ok:!0,message:"vec_chunks empty post-swap (no data to migrate)",rowCount:0};let s=e.prepare("SELECT embedding FROM vec_chunks LIMIT 1").get();return e.prepare("SELECT rowid, distance FROM vec_chunks WHERE embedding MATCH ? ORDER BY distance LIMIT 1").all(s.embedding).length===0?{ok:!1,message:"post-swap kNN returned no rows",rowCount:t.n}:{ok:!0,message:`post-swap smoke kNN ok, ${t.n} rows (matches chunk_meta)`,rowCount:t.n}}catch(t){throw process.stderr.write(`[migration-swap] verifyPostSwap threw after swap commit: ${t instanceof Error?t.stack??t.message:String(t)}
899
+ `),new ri(`post-swap verification failed: ${t instanceof Error?t.message:String(t)}`,t)}}var ri,Bd=w(()=>{"use strict";k();Vt();ri=class extends Error{cause;constructor(t,n){super(t),this.name="MigrationVerificationError",this.cause=n}}});import{promises as Nw}from"node:fs";import{dirname as ii}from"node:path";function Hd(e){return e<=0?0:Math.ceil(e*(Ow+vw)*Iw)}async function Wd(e){let t=e.dbPath??ee,n;try{n=await Nw.statfs(ii(t))}catch(i){return{ok:!1,message:`disk space check failed: could not read filesystem at ${ii(t)}: ${i instanceof Error?i.message:String(i)}`,availableBytes:0,requiredBytes:e.requiredBytes}}let s=Number(n.bavail)*Number(n.bsize),r=s>=e.requiredBytes,o=r?`disk space check: required: ${e.requiredBytes} bytes, available: ${s} bytes`:`disk space check FAILED. required: ${e.requiredBytes} bytes, available: ${s} bytes. Free up space on ${ii(t)} or run on a different filesystem.`;return{ok:r,message:o,availableBytes:s,requiredBytes:e.requiredBytes}}function Xd(e={}){let t=h(),n=Z().modelId;if(!n)throw new Error("countChunksToMigrate: embedder not loaded or modelId is empty");return e.scopeProjectId!==void 0?t.prepare(`SELECT COUNT(*) AS n FROM chunk_meta cm
900
900
  JOIN sessions s ON s.id = cm.session_id
901
901
  WHERE s.project_id = ?
902
902
  AND cm.embedding_model_id != ?
@@ -906,14 +906,14 @@ ${t.message}
906
906
  WHERE embedding_model_id != ?
907
907
  AND NOT EXISTS (
908
908
  SELECT 1 FROM vec_chunks_v2 v WHERE v.rowid = chunk_meta.rowid
909
- )`).get(n).n}async function Ud(e){if(e==="onnx"){let r=rt();return{ok:r,message:r?"ONNX backend ready (bge-base-en-v1.5 model present)":"ONNX backend not installed. Run `recall semantic install` first."}}let{isGgufModelInstalled:t,verifyGgufModelHash:n}=await Promise.resolve().then(()=>(Us(),js));if(!t())return{ok:!1,message:"llama.cpp backend not installed. Set RECALL_EMBEDDER_BACKEND=llama and run `recall semantic install` first."};let s=await n();return{ok:s.ok,message:s.ok?"llama.cpp backend ready (GGUF model present + hash verified)":`llama.cpp GGUF model integrity check failed: ${s.reason}. Re-run \`recall semantic install\` to fetch a clean copy.`}}function Bd(e,t){return e<=0?0:t<=0?null:Math.ceil(e/t/60)}async function Hd(e={}){let t=e.sampleSize??oi,n=E(),s=Z().modelId;if(!s)throw new Error("sampleEmbedderThroughput: embedder not loaded or modelId is empty");let r=e.scopeProjectId!==void 0?n.prepare(`SELECT cm.text FROM chunk_meta cm
909
+ )`).get(n).n}async function Gd(e){if(e==="onnx"){let r=rt();return{ok:r,message:r?"ONNX backend ready (bge-base-en-v1.5 model present)":"ONNX backend not installed. Run `recall semantic install` first."}}let{isGgufModelInstalled:t,verifyGgufModelHash:n}=await Promise.resolve().then(()=>(Bs(),Us));if(!t())return{ok:!1,message:"llama.cpp backend not installed. Set RECALL_EMBEDDER_BACKEND=llama and run `recall semantic install` first."};let s=await n();return{ok:s.ok,message:s.ok?"llama.cpp backend ready (GGUF model present + hash verified)":`llama.cpp GGUF model integrity check failed: ${s.reason}. Re-run \`recall semantic install\` to fetch a clean copy.`}}function Jd(e,t){return e<=0?0:t<=0?null:Math.ceil(e/t/60)}async function zd(e={}){let t=e.sampleSize??ai,n=h(),s=Z().modelId;if(!s)throw new Error("sampleEmbedderThroughput: embedder not loaded or modelId is empty");let r=e.scopeProjectId!==void 0?n.prepare(`SELECT cm.text FROM chunk_meta cm
910
910
  JOIN sessions s ON s.id = cm.session_id
911
911
  WHERE s.project_id = ?
912
912
  AND cm.embedding_model_id != ?
913
913
  AND cm.text IS NOT NULL
914
914
  AND length(cm.text) > 0
915
- LIMIT ?`).all(e.scopeProjectId,s,t):n.prepare("SELECT text FROM chunk_meta WHERE embedding_model_id != ? AND text IS NOT NULL AND length(text) > 0 LIMIT ?").all(s,t);if(r.length===0)return{ok:!0,chunksPerSec:null,sampleSize:0,elapsedMs:0,message:"throughput probe skipped: no chunks to sample"};let o=r.map(u=>u.text),i=process.hrtime.bigint();await Ne(o);let a=Number(process.hrtime.bigint()-i)/1e6,d=a/1e3,l=d>0?r.length/d:null;return{ok:!0,chunksPerSec:l,sampleSize:r.length,elapsedMs:a,message:l===null?`throughput probe: ${r.length} chunks in <1ms (n/a)`:`throughput probe: ${r.length} chunks in ${a.toFixed(0)}ms \u2192 ${l.toFixed(1)} chunks/sec`}}var bw,Sw,yw,oi,Wd=w(()=>{"use strict";k();Pe();wn();I();bw=768*4,Sw=64,yw=1.2;oi=50});var Ys={};V(Ys,{MigrationLoopError:()=>An,createParallelVectorTable:()=>Gd,maybeAutoPruneExpiredBackup:()=>vw,migrateChunkRange:()=>zd,migrateOneChunk:()=>Lw,pruneRollbackBackup:()=>Ow,rollbackMigration:()=>Nw,runMigration:()=>Aw});import{createInterface as ww}from"node:readline/promises";import{stdin as Tw,stdout as Xd,stderr as Rw}from"node:process";async function kw(e,t){if(!Xd.isTTY)return Rw.write(`Interactive confirmation requested but stdout is not a TTY. Re-run with --yes.
916
- `),!1;let n=ww({input:Tw,output:Xd}),s=t===null?"":` (~${t} min)`,r=await n.question(`Migrate ${e} chunks${s}? Type YES to proceed: `);return n.close(),r.trim()==="YES"}function Gd(){E().exec(Cw)}async function Lw(e){let t=E(),n=t.prepare("SELECT text FROM chunk_meta WHERE rowid = ?").get(e);if(!n)throw new Error(`chunk_meta row not found: rowid=${e}`);let[s]=await Ne([n.text]),r=Buffer.from(s.buffer,s.byteOffset,s.byteLength);t.prepare("DELETE FROM vec_chunks_v2 WHERE rowid = ?").run(BigInt(e)),t.prepare("INSERT INTO vec_chunks_v2(rowid, embedding) VALUES (?, ?)").run(BigInt(e),r)}async function zd(e){let t=E(),n=e.batchSize??50,s=Cn();if(!s||s.id!==e.migrationId)throw new Error(`no active migration with id=${e.migrationId}`);let r=s.cursorChunkId??0,i=t.prepare(`SELECT COUNT(*) AS n FROM chunk_meta
915
+ LIMIT ?`).all(e.scopeProjectId,s,t):n.prepare("SELECT text FROM chunk_meta WHERE embedding_model_id != ? AND text IS NOT NULL AND length(text) > 0 LIMIT ?").all(s,t);if(r.length===0)return{ok:!0,chunksPerSec:null,sampleSize:0,elapsedMs:0,message:"throughput probe skipped: no chunks to sample"};let o=r.map(u=>u.text),i=process.hrtime.bigint();await Ne(o);let a=Number(process.hrtime.bigint()-i)/1e6,d=a/1e3,l=d>0?r.length/d:null;return{ok:!0,chunksPerSec:l,sampleSize:r.length,elapsedMs:a,message:l===null?`throughput probe: ${r.length} chunks in <1ms (n/a)`:`throughput probe: ${r.length} chunks in ${a.toFixed(0)}ms \u2192 ${l.toFixed(1)} chunks/sec`}}var Ow,vw,Iw,ai,Yd=w(()=>{"use strict";k();Fe();wn();I();Ow=768*4,vw=64,Iw=1.2;ai=50});var qs={};V(qs,{MigrationLoopError:()=>Ln,createParallelVectorTable:()=>Vd,maybeAutoPruneExpiredBackup:()=>Xw,migrateChunkRange:()=>Kd,migrateOneChunk:()=>Uw,pruneRollbackBackup:()=>Ww,rollbackMigration:()=>Hw,runMigration:()=>Bw});import{createInterface as Mw}from"node:readline/promises";import{stdin as Dw,stdout as qd,stderr as $w}from"node:process";async function Pw(e,t){if(!qd.isTTY)return $w.write(`Interactive confirmation requested but stdout is not a TTY. Re-run with --yes.
916
+ `),!1;let n=Mw({input:Dw,output:qd}),s=t===null?"":` (~${t} min)`,r=await n.question(`Migrate ${e} chunks${s}? Type YES to proceed: `);return n.close(),r.trim()==="YES"}function Vd(){h().exec(jw)}async function Uw(e){let t=h(),n=t.prepare("SELECT text FROM chunk_meta WHERE rowid = ?").get(e);if(!n)throw new Error(`chunk_meta row not found: rowid=${e}`);let[s]=await Ne([n.text]),r=Buffer.from(s.buffer,s.byteOffset,s.byteLength);t.prepare("DELETE FROM vec_chunks_v2 WHERE rowid = ?").run(BigInt(e)),t.prepare("INSERT INTO vec_chunks_v2(rowid, embedding) VALUES (?, ?)").run(BigInt(e),r)}async function Kd(e){let t=h(),n=e.batchSize??50,s=Cn();if(!s||s.id!==e.migrationId)throw new Error(`no active migration with id=${e.migrationId}`);let r=s.cursorChunkId??0,i=t.prepare(`SELECT COUNT(*) AS n FROM chunk_meta
917
917
  WHERE rowid > ?
918
918
  AND embedding_model_id != ?
919
919
  AND NOT EXISTS (
@@ -924,8 +924,8 @@ ${t.message}
924
924
  AND NOT EXISTS (
925
925
  SELECT 1 FROM vec_chunks_v2 v WHERE v.rowid = chunk_meta.rowid
926
926
  )
927
- ORDER BY rowid LIMIT ?`),m=r;for(;;){let p=u.all(m,s.modelIdNew,n);if(p.length===0)break;let g;try{g=await Ne(p.map(h=>h.text))}catch(h){throw new An(`embed() failed at cursor=${m}, migrated=${a}: ${h instanceof Error?h.message:String(h)}`,a,h)}if(t.transaction(()=>{let h=t.prepare("DELETE FROM vec_chunks_v2 WHERE rowid = ?"),_=t.prepare("INSERT INTO vec_chunks_v2(rowid, embedding) VALUES (?, ?)");for(let b=0;b<p.length;b++){let S=p[b],y=g[b],T=Buffer.from(y.buffer,y.byteOffset,y.byteLength);h.run(BigInt(S.rowid)),_.run(BigInt(S.rowid),T)}})(),m=p[p.length-1].rowid,a+=p.length,Vo(s.id,{sessionId:p[p.length-1].session_id,chunkId:m}),e.signal?.aborted)return{migrated:a,total:i};if(a-l>=xw&&(t.exec("PRAGMA wal_checkpoint(PASSIVE);"),l=a),e.onProgress){let h=(Date.now()-d)/1e3;e.onProgress({migrated:a,total:i,chunksPerSec:h>0?a/h:0})}}return{migrated:a,total:i}}async function Aw(e){let t=ei();t&&t.lockTakenByPid!==null&&(console.warn(`[migrate] Stale lock detected from pid ${t.lockTakenByPid}. Releasing.`),ti(t.lockTakenByPid,{preserveCursor:!0}));let n=Cn(),r=Z().modelId.includes("gguf")?"llama":"onnx",o=await Ud(r);if(!o.ok)return{ok:!1,message:o.message,migrated:0,backupRetained:!1};if(!Z().loaded)try{await Ke()}catch(g){if(g instanceof fe)return{ok:!1,message:g.message.split(`
928
- `)[0],migrated:0,backupRetained:!1};throw g}Gd();let i;if(e.projectName){let g=E().prepare("SELECT id FROM projects WHERE name = ?").get(e.projectName);if(!g)return{ok:!1,message:`project not found: ${e.projectName}`,migrated:0,backupRetained:!1};i=g.id}let a=jd({scopeProjectId:i});if(a===0){if(i===void 0){let g=E().prepare("SELECT COUNT(*) AS n FROM vec_chunks_v2").get();if(g.n>0){if(!n){let f=Z().modelId,_=E().prepare("SELECT embedding_model_id FROM chunk_meta WHERE embedding_model_id != ? LIMIT 1").get(f)?.embedding_model_id??"unknown";n=zs({modelIdOld:_,modelIdNew:f})}try{await si(n.id)}catch(f){return{ok:!1,message:f instanceof Error?f.message:String(f),migrated:0,backupRetained:!1}}try{Go()}catch(f){console.warn(`[migrate] post-swap promote failed (daemon will drain on next tick): ${f instanceof Error?f.message:String(f)}`)}return{ok:!0,message:`swap committed: ${g.n} staged chunks promoted to live vec_chunks`,migrated:0,backupRetained:e.keepBackup}}}return{ok:!0,message:i!==void 0?`nothing to migrate for project ${e.projectName} (all chunks already staged)`:"nothing to migrate (all chunks already on active backend)",migrated:0,backupRetained:!1}}let d=Pd(a),l=await Fd({requiredBytes:d});if(!l.ok)return{ok:!1,message:l.message,migrated:0,backupRetained:!1};(e.interactive||e.dryRun)&&console.log(`Measuring embedder throughput (sampling up to ${oi} chunks)...`);let u=await Hd({scopeProjectId:i}),m=u.chunksPerSec===null?null:Bd(a,u.chunksPerSec);if(e.dryRun){let g=E().prepare("SELECT embedding_model_id, COUNT(*) AS n FROM chunk_meta WHERE embedding_model_id != ? GROUP BY embedding_model_id ORDER BY n DESC").all(Z().modelId),f=h=>(h/1024**3).toFixed(2);console.log(""),console.log("=== Dry run: migration plan ==="),console.log(`Target backend: ${Z().modelId}`),console.log(`Chunks to migrate: ${a.toLocaleString()}`),console.log(`Disk required: ${f(d)} GB (${f(l.availableBytes)} GB available)`),u.chunksPerSec!==null?(console.log(`Measured throughput: ${u.chunksPerSec.toFixed(1)} chunks/sec (live sample of ${u.sampleSize} in ${u.elapsedMs.toFixed(0)}ms)`),console.log(`Projected duration: ~${m} min`)):(console.log("Measured throughput: n/a (probe returned no signal)"),console.log("Projected duration: n/a")),console.log(""),console.log("Source breakdown:");for(let h of g)console.log(` ${h.n.toLocaleString().padStart(10)} ${h.embedding_model_id}`);return console.log(""),console.log("No writes performed. Re-run without --dry-run to execute."),{ok:!0,message:"dry run complete \u2014 no changes made",migrated:0,backupRetained:!1}}if(e.interactive){let g=u.chunksPerSec===null?"":` (based on ${u.sampleSize}-chunk live sample @ ${u.chunksPerSec.toFixed(1)} chunks/sec)`;if(console.log(`About to migrate ${a} chunks${m===null?"":` (~${m} min${g})`}.`),console.log(`Disk: ${l.message}`),!await kw(a,m))return{ok:!1,message:"user declined confirmation (re-run with --yes to skip the prompt)",migrated:0,backupRetained:!1}}if(i!==void 0){let g=E(),f=Z().modelId,h=50,_=g.prepare(`SELECT cm.rowid, cm.session_id, cm.text FROM chunk_meta cm
927
+ ORDER BY rowid LIMIT ?`),m=r;for(;;){let p=u.all(m,s.modelIdNew,n);if(p.length===0)break;let g;try{g=await Ne(p.map(_=>_.text))}catch(_){throw new Ln(`embed() failed at cursor=${m}, migrated=${a}: ${_ instanceof Error?_.message:String(_)}`,a,_)}if(t.transaction(()=>{let _=t.prepare("DELETE FROM vec_chunks_v2 WHERE rowid = ?"),b=t.prepare("INSERT INTO vec_chunks_v2(rowid, embedding) VALUES (?, ?)");for(let E=0;E<p.length;E++){let S=p[E],y=g[E],T=Buffer.from(y.buffer,y.byteOffset,y.byteLength);_.run(BigInt(S.rowid)),b.run(BigInt(S.rowid),T)}})(),m=p[p.length-1].rowid,a+=p.length,Qo(s.id,{sessionId:p[p.length-1].session_id,chunkId:m}),e.signal?.aborted)return{migrated:a,total:i};if(a-l>=Fw&&(t.exec("PRAGMA wal_checkpoint(PASSIVE);"),l=a),e.onProgress){let _=(Date.now()-d)/1e3;e.onProgress({migrated:a,total:i,chunksPerSec:_>0?a/_:0})}}return{migrated:a,total:i}}async function Bw(e){let t=ni();t&&t.lockTakenByPid!==null&&(console.warn(`[migrate] Stale lock detected from pid ${t.lockTakenByPid}. Releasing.`),si(t.lockTakenByPid,{preserveCursor:!0}));let n=Cn(),r=Z().modelId.includes("gguf")?"llama":"onnx",o=await Gd(r);if(!o.ok)return{ok:!1,message:o.message,migrated:0,backupRetained:!1};if(!Z().loaded)try{await Ke()}catch(g){if(g instanceof fe)return{ok:!1,message:g.message.split(`
928
+ `)[0],migrated:0,backupRetained:!1};throw g}Vd();let i;if(e.projectName){let g=h().prepare("SELECT id FROM projects WHERE name = ?").get(e.projectName);if(!g)return{ok:!1,message:`project not found: ${e.projectName}`,migrated:0,backupRetained:!1};i=g.id}let a=Xd({scopeProjectId:i});if(a===0){if(i===void 0){let g=h().prepare("SELECT COUNT(*) AS n FROM vec_chunks_v2").get();if(g.n>0){if(!n){let f=Z().modelId,b=h().prepare("SELECT embedding_model_id FROM chunk_meta WHERE embedding_model_id != ? LIMIT 1").get(f)?.embedding_model_id??"unknown";n=zs({modelIdOld:b,modelIdNew:f})}try{await oi(n.id)}catch(f){return{ok:!1,message:f instanceof Error?f.message:String(f),migrated:0,backupRetained:!1}}try{zo()}catch(f){console.warn(`[migrate] post-swap promote failed (daemon will drain on next tick): ${f instanceof Error?f.message:String(f)}`)}return{ok:!0,message:`swap committed: ${g.n} staged chunks promoted to live vec_chunks`,migrated:0,backupRetained:e.keepBackup}}}return{ok:!0,message:i!==void 0?`nothing to migrate for project ${e.projectName} (all chunks already staged)`:"nothing to migrate (all chunks already on active backend)",migrated:0,backupRetained:!1}}let d=Hd(a),l=await Wd({requiredBytes:d});if(!l.ok)return{ok:!1,message:l.message,migrated:0,backupRetained:!1};(e.interactive||e.dryRun)&&console.log(`Measuring embedder throughput (sampling up to ${ai} chunks)...`);let u=await zd({scopeProjectId:i}),m=u.chunksPerSec===null?null:Jd(a,u.chunksPerSec);if(e.dryRun){let g=h().prepare("SELECT embedding_model_id, COUNT(*) AS n FROM chunk_meta WHERE embedding_model_id != ? GROUP BY embedding_model_id ORDER BY n DESC").all(Z().modelId),f=_=>(_/1024**3).toFixed(2);console.log(""),console.log("=== Dry run: migration plan ==="),console.log(`Target backend: ${Z().modelId}`),console.log(`Chunks to migrate: ${a.toLocaleString()}`),console.log(`Disk required: ${f(d)} GB (${f(l.availableBytes)} GB available)`),u.chunksPerSec!==null?(console.log(`Measured throughput: ${u.chunksPerSec.toFixed(1)} chunks/sec (live sample of ${u.sampleSize} in ${u.elapsedMs.toFixed(0)}ms)`),console.log(`Projected duration: ~${m} min`)):(console.log("Measured throughput: n/a (probe returned no signal)"),console.log("Projected duration: n/a")),console.log(""),console.log("Source breakdown:");for(let _ of g)console.log(` ${_.n.toLocaleString().padStart(10)} ${_.embedding_model_id}`);return console.log(""),console.log("No writes performed. Re-run without --dry-run to execute."),{ok:!0,message:"dry run complete \u2014 no changes made",migrated:0,backupRetained:!1}}if(e.interactive){let g=u.chunksPerSec===null?"":` (based on ${u.sampleSize}-chunk live sample @ ${u.chunksPerSec.toFixed(1)} chunks/sec)`;if(console.log(`About to migrate ${a} chunks${m===null?"":` (~${m} min${g})`}.`),console.log(`Disk: ${l.message}`),!await Pw(a,m))return{ok:!1,message:"user declined confirmation (re-run with --yes to skip the prompt)",migrated:0,backupRetained:!1}}if(i!==void 0){let g=h(),f=Z().modelId,_=50,b=g.prepare(`SELECT cm.rowid, cm.session_id, cm.text FROM chunk_meta cm
929
929
  JOIN sessions s ON s.id = cm.session_id
930
930
  WHERE s.project_id = ?
931
931
  AND cm.embedding_model_id != ?
@@ -939,25 +939,25 @@ ${t.message}
939
939
  AND cm.embedding_model_id != ?
940
940
  AND NOT EXISTS (
941
941
  SELECT 1 FROM vec_chunks_v2 v WHERE v.rowid = cm.rowid
942
- )`).get(i,f).n,y=0,T=Date.now();for(;;){let R=_.all(i,f,h);if(R.length===0)break;let B;try{B=await Ne(R.map(v=>v.text))}catch(v){return{ok:!1,message:`embed() failed at scoped migrated=${y}: ${v instanceof Error?v.message:String(v)}`,migrated:y,backupRetained:!1}}if(g.transaction(()=>{let v=g.prepare("INSERT INTO vec_chunks_v2(rowid, embedding) VALUES (?, ?)");for(let O=0;O<R.length;O++){let x=R[O],M=B[O],F=Buffer.from(M.buffer,M.byteOffset,M.byteLength);v.run(BigInt(x.rowid),F)}})(),y+=R.length,e.onProgress){let v=(Date.now()-T)/1e3;e.onProgress({migrated:y,total:S,chunksPerSec:v>0?y/v:0})}}return{ok:!0,message:`scoped: ${y} chunks staged for project ${e.projectName}. Run \`recall semantic migrate\` (no --project) to finalize across the corpus.`,migrated:y,backupRetained:!1}}if(!n){let g=Z().modelId,h=(await Promise.resolve().then(()=>(k(),qn))).getDb().prepare("SELECT embedding_model_id FROM chunk_meta WHERE embedding_model_id != ? LIMIT 1").get(g)?.embedding_model_id??"unknown";n=zs({modelIdOld:h,modelIdNew:g})}E().prepare(`INSERT INTO vec_chunks_v2(rowid, embedding)
942
+ )`).get(i,f).n,y=0,T=Date.now();for(;;){let R=b.all(i,f,_);if(R.length===0)break;let B;try{B=await Ne(R.map(v=>v.text))}catch(v){return{ok:!1,message:`embed() failed at scoped migrated=${y}: ${v instanceof Error?v.message:String(v)}`,migrated:y,backupRetained:!1}}if(g.transaction(()=>{let v=g.prepare("INSERT INTO vec_chunks_v2(rowid, embedding) VALUES (?, ?)");for(let O=0;O<R.length;O++){let x=R[O],M=B[O],F=Buffer.from(M.buffer,M.byteOffset,M.byteLength);v.run(BigInt(x.rowid),F)}})(),y+=R.length,e.onProgress){let v=(Date.now()-T)/1e3;e.onProgress({migrated:y,total:S,chunksPerSec:v>0?y/v:0})}}return{ok:!0,message:`scoped: ${y} chunks staged for project ${e.projectName}. Run \`recall semantic migrate\` (no --project) to finalize across the corpus.`,migrated:y,backupRetained:!1}}if(!n){let g=Z().modelId,_=(await Promise.resolve().then(()=>(k(),Vn))).getDb().prepare("SELECT embedding_model_id FROM chunk_meta WHERE embedding_model_id != ? LIMIT 1").get(g)?.embedding_model_id??"unknown";n=zs({modelIdOld:_,modelIdNew:g})}h().prepare(`INSERT INTO vec_chunks_v2(rowid, embedding)
943
943
  SELECT v.rowid, v.embedding
944
944
  FROM vec_chunks v
945
945
  JOIN chunk_meta cm ON cm.rowid = v.rowid
946
946
  WHERE cm.embedding_model_id = ?
947
947
  AND NOT EXISTS (
948
948
  SELECT 1 FROM vec_chunks_v2 v2 WHERE v2.rowid = v.rowid
949
- )`).run(n.modelIdNew);let p;try{p=await zd({migrationId:n.id,onProgress:e.onProgress})}catch(g){Qo(n.id,g instanceof Error?g.message:String(g));let f=g instanceof An?g.partialMigrated:0;return{ok:!1,message:g instanceof Error?g.message:String(g),migrated:f,backupRetained:!1}}try{await si(n.id)}catch(g){return{ok:!1,message:g instanceof Error?g.message:String(g),migrated:p.migrated,backupRetained:!1}}try{Go()}catch(g){let f="";try{f=`${E().prepare("SELECT COUNT(*) AS n FROM chunk_queue WHERE action = 'pending_post_migration'").get().n} chunk_queue rows still flagged pending_post_migration; `}catch{}console.warn(`[migrate] post-swap promotePendingPostMigration failed: ${g instanceof Error?g.message:String(g)}. ${f}the daemon will drain on next tick.`)}return e.keepBackup||(await Promise.resolve().then(()=>(k(),qn))).getDb().exec("DROP TABLE IF EXISTS vec_chunks_v1_backup;"),{ok:!0,message:"migration complete",migrated:p.migrated,backupRetained:e.keepBackup}}async function Nw(e){let t=E();if(!t.prepare("SELECT name FROM sqlite_master WHERE type IN ('table','virtual') AND name='vec_chunks_v1_backup'").get())return{ok:!1,message:"no vec_chunks_v1_backup found (already pruned, or no migration has run)"};let s=t.prepare("SELECT * FROM migration_state WHERE status = 'completed' ORDER BY id DESC LIMIT 1").get();if(!s)return{ok:!1,message:"no completed migration found to roll back"};let r=qt(s);return e.force?(t.transaction(()=>{t.exec("DELETE FROM vec_chunks;"),t.exec("INSERT INTO vec_chunks(rowid, embedding) SELECT rowid, embedding FROM vec_chunks_v1_backup;"),t.prepare("UPDATE chunk_meta SET embedding_model_id = ? WHERE rowid IN (SELECT rowid FROM vec_chunks)").run(r.modelIdOld)})(),Zo(r.id),{ok:!0,message:"rollback complete"}):{ok:!1,message:"rollback requires --force (any chunks indexed AFTER the migration completed will be lost on rollback because they were embedded with the new backend)"}}async function Ow(e){let t=E();return t.prepare("SELECT name FROM sqlite_master WHERE name='vec_chunks_v1_backup'").get()?!e.force&&t.prepare("SELECT completed_at FROM migration_state WHERE status = 'completed' AND completed_at > datetime('now', '-30 days') ORDER BY id DESC LIMIT 1").get()?{ok:!1,message:"most recent migration completed less than 30 days ago. Use --force to prune anyway (rollback will no longer be possible)."}:(t.exec("DROP TABLE vec_chunks_v1_backup;"),{ok:!0,message:"rollback backup pruned"}):{ok:!1,message:"no vec_chunks_v1_backup to prune"}}function vw(){let e=E();if(!e.prepare("SELECT name FROM sqlite_master WHERE name='vec_chunks_v1_backup'").get())return{outcome:"absent",message:"no vec_chunks_v1_backup present"};let n=e.prepare("SELECT completed_at FROM migration_state WHERE status = 'completed' ORDER BY id DESC LIMIT 1").get();return n?e.prepare("SELECT 1 AS x FROM migration_state WHERE status = 'completed' AND completed_at > datetime('now', '-30 days') ORDER BY id DESC LIMIT 1").get()?{outcome:"kept",message:`backup retained \u2014 last migration (${n.completed_at}) is within the 30-day rollback window`}:(e.exec("DROP TABLE vec_chunks_v1_backup;"),{outcome:"pruned",message:`auto-pruned vec_chunks_v1_backup \u2014 last migration (${n.completed_at}) is older than 30 days`}):{outcome:"kept",message:"backup present but no completed migration on record \u2014 left for manual inspection"}}var An,xw,Cw,qs=w(()=>{"use strict";k();Pe();Vt();$d();Wd();Pe();Ds();An=class extends Error{partialMigrated;cause;constructor(t,n,s){super(t),this.name="MigrationLoopError",this.partialMigrated=n,this.cause=s}};xw=5e3,Cw=`
949
+ )`).run(n.modelIdNew);let p;try{p=await Kd({migrationId:n.id,onProgress:e.onProgress})}catch(g){ei(n.id,g instanceof Error?g.message:String(g));let f=g instanceof Ln?g.partialMigrated:0;return{ok:!1,message:g instanceof Error?g.message:String(g),migrated:f,backupRetained:!1}}try{await oi(n.id)}catch(g){return{ok:!1,message:g instanceof Error?g.message:String(g),migrated:p.migrated,backupRetained:!1}}try{zo()}catch(g){let f="";try{f=`${h().prepare("SELECT COUNT(*) AS n FROM chunk_queue WHERE action = 'pending_post_migration'").get().n} chunk_queue rows still flagged pending_post_migration; `}catch{}console.warn(`[migrate] post-swap promotePendingPostMigration failed: ${g instanceof Error?g.message:String(g)}. ${f}the daemon will drain on next tick.`)}return e.keepBackup||(await Promise.resolve().then(()=>(k(),Vn))).getDb().exec("DROP TABLE IF EXISTS vec_chunks_v1_backup;"),{ok:!0,message:"migration complete",migrated:p.migrated,backupRetained:e.keepBackup}}async function Hw(e){let t=h();if(!t.prepare("SELECT name FROM sqlite_master WHERE type IN ('table','virtual') AND name='vec_chunks_v1_backup'").get())return{ok:!1,message:"no vec_chunks_v1_backup found (already pruned, or no migration has run)"};let s=t.prepare("SELECT * FROM migration_state WHERE status = 'completed' ORDER BY id DESC LIMIT 1").get();if(!s)return{ok:!1,message:"no completed migration found to roll back"};let r=qt(s);return e.force?(t.transaction(()=>{t.exec("DELETE FROM vec_chunks;"),t.exec("INSERT INTO vec_chunks(rowid, embedding) SELECT rowid, embedding FROM vec_chunks_v1_backup;"),t.prepare("UPDATE chunk_meta SET embedding_model_id = ? WHERE rowid IN (SELECT rowid FROM vec_chunks)").run(r.modelIdOld)})(),ti(r.id),{ok:!0,message:"rollback complete"}):{ok:!1,message:"rollback requires --force (any chunks indexed AFTER the migration completed will be lost on rollback because they were embedded with the new backend)"}}async function Ww(e){let t=h();return t.prepare("SELECT name FROM sqlite_master WHERE name='vec_chunks_v1_backup'").get()?!e.force&&t.prepare("SELECT completed_at FROM migration_state WHERE status = 'completed' AND completed_at > datetime('now', '-30 days') ORDER BY id DESC LIMIT 1").get()?{ok:!1,message:"most recent migration completed less than 30 days ago. Use --force to prune anyway (rollback will no longer be possible)."}:(t.exec("DROP TABLE vec_chunks_v1_backup;"),{ok:!0,message:"rollback backup pruned"}):{ok:!1,message:"no vec_chunks_v1_backup to prune"}}function Xw(){let e=h();if(!e.prepare("SELECT name FROM sqlite_master WHERE name='vec_chunks_v1_backup'").get())return{outcome:"absent",message:"no vec_chunks_v1_backup present"};let n=e.prepare("SELECT completed_at FROM migration_state WHERE status = 'completed' ORDER BY id DESC LIMIT 1").get();return n?e.prepare("SELECT 1 AS x FROM migration_state WHERE status = 'completed' AND completed_at > datetime('now', '-30 days') ORDER BY id DESC LIMIT 1").get()?{outcome:"kept",message:`backup retained \u2014 last migration (${n.completed_at}) is within the 30-day rollback window`}:(e.exec("DROP TABLE vec_chunks_v1_backup;"),{outcome:"pruned",message:`auto-pruned vec_chunks_v1_backup \u2014 last migration (${n.completed_at}) is older than 30 days`}):{outcome:"kept",message:"backup present but no completed migration on record \u2014 left for manual inspection"}}var Ln,Fw,jw,Vs=w(()=>{"use strict";k();Fe();Vt();Bd();Yd();Fe();$s();Ln=class extends Error{partialMigrated;cause;constructor(t,n,s){super(t),this.name="MigrationLoopError",this.partialMigrated=n,this.cause=s}};Fw=5e3,jw=`
950
950
  CREATE VIRTUAL TABLE IF NOT EXISTS vec_chunks_v2 USING vec0(
951
951
  embedding float[768] distance_metric=cosine
952
952
  );
953
- `});var Jd=w(()=>{"use strict"});var Yd=w(()=>{"use strict"});import{existsSync as Iw,readFileSync as Mw,writeFileSync as Dw}from"node:fs";import{join as $w}from"node:path";import{z as _e}from"zod";function ci(e){let t=e.trim();return!!(!t||Vd.test(t)||Kd.test(t))}function Qd(e){let t=e.trim();if(!t||Kd.test(t))return null;let n=t.replace(Vd,"").trim();return n.length>0?n:null}function ai(e,t){if(!ci(e))return e;let n=Qd(e);return n||(t&&!ci(t)?t:e)}function Bw(e){let t=e.now-e.withinMs,n=e.pending.filter(s=>{let r=Date.parse(s.started_at);return Number.isFinite(r)&&r>=t});if(n.length===0)return{kind:"none"};if(e.shellPid!=null){let s=n.find(r=>r.shell_pid===e.shellPid);if(s)return{kind:"pid-match",entry:s}}if(e.cwd){let s=e.cwd.replace(/\/+$/,""),r=n.filter(o=>o.cwd&&o.cwd.replace(/\/+$/,"")===s);if(r.length===1)return{kind:"singleton-cwd",entry:r[0]};if(r.length>=2)return{kind:"ambiguous",candidates:r}}return{kind:"none"}}var ii,qd,Pw,Fw,jw,Uw,Vd,Kd,li,di,ui=w(()=>{"use strict";I();ii=$w(C,"terminals.json"),qd=1440*60*1e3,Pw=3e4,Fw=6e4,jw=_e.object({shell_pid:_e.number(),tab_name:_e.string(),cwd:_e.string().nullable().optional(),opened_at:_e.string(),last_seen_at:_e.string()}),Uw=_e.object({schema:_e.string().optional(),saved_at:_e.string().optional(),terminals:_e.array(jw).max(500).default([]),sessions_by_pid:_e.record(_e.string(),_e.array(_e.string()).max(50)).optional().default({})}),Vd=/^[⠀-⣿✳\s]+/,Kd=/^\d+(\.\d+){1,3}$/;li=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,!!Iw(ii)))try{let t=Mw(ii,"utf8"),n=JSON.parse(t),s=Uw.safeParse(n);if(!s.success){console.warn("[terminal-registry] terminals.json failed validation, starting with empty registry:",s.error.issues);return}let r=s.data;for(let o of r.terminals)this.entries.set(o.shell_pid,{shell_pid:o.shell_pid,tab_name:o.tab_name,cwd:o.cwd??null,opened_at:o.opened_at,last_seen_at:o.last_seen_at});for(let[o,i]of Object.entries(r.sessions_by_pid??{})){let a=Number(o);if(!Number.isFinite(a))continue;let d=new Set;for(let l of i)l.length>0&&d.add(l);d.size>0&&this.sessionsByPid.set(a,d)}this.gc()}catch{}}save(){try{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(([n,s])=>[String(n),Array.from(s)]))};Dw(ii,JSON.stringify(t,null,2))}catch{}}upsert(t){this.ensureLoaded();let n=new Date().toISOString(),s=this.entries.get(t.shell_pid),r=ai(t.tab_name,s?.tab_name),o=s?.opened_at??t.opened_at,i={...t,tab_name:r,opened_at:o,last_seen_at:n};return this.entries.set(t.shell_pid,i),this.gc(),this.save(),i}rename(t,n){this.ensureLoaded();let s=this.entries.get(t);if(!s)return null;let r=ai(n,s.tab_name),o={...s,tab_name:r,last_seen_at:new Date().toISOString()};return this.entries.set(t,o),this.save(),o}remove(t){this.ensureLoaded();let n=this.entries.delete(t),s=this.sessionsByPid.delete(t);return this.outputTails.delete(t),this.pidOwnership.delete(t),(n||s)&&this.save(),n}claimPidOwnership(t,n,s=Date.now()){if(this.ensureLoaded(),!n)return"anonymous";let r=this.pidOwnership.get(t);return r?r.instance_id===n?(r.last_claim_at=s,"refreshed"):s-r.last_claim_at>Fw?(this.pidOwnership.set(t,{instance_id:n,last_claim_at:s}),"claimed"):"rejected":(this.pidOwnership.set(t,{instance_id:n,last_claim_at:s}),"claimed")}pidOwnershipSnapshot(){return this.ensureLoaded(),Array.from(this.pidOwnership.entries()).map(([t,n])=>({shell_pid:t,instance_id:n.instance_id,last_claim_at:n.last_claim_at}))}sync(t){this.ensureLoaded();let n=new Date().toISOString(),s=0,r=0;for(let o of t){let i=this.entries.get(o.shell_pid),a=ai(o.tab_name,i?.tab_name),d=i?.opened_at??o.opened_at;this.entries.set(o.shell_pid,{...o,tab_name:a,opened_at:d,last_seen_at:n}),i?(i.tab_name!==a||i.cwd!==o.cwd)&&r++:s++}return this.gc(),this.save(),{added:s,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,n){this.ensureLoaded();let s=this.sessionsByPid.get(n);s||(s=new Set,this.sessionsByPid.set(n,s)),s.has(t)||(s.add(t),this.save())}sessionsFor(t){return this.ensureLoaded(),Array.from(this.sessionsByPid.get(t)??[])}isSessionAutoLinked(t){this.ensureLoaded();for(let n of this.sessionsByPid.values())if(n.has(t))return!0;return!1}unlinkSession(t){this.ensureLoaded();let n=!1;for(let[s,r]of this.sessionsByPid)r.delete(t)&&(n=!0,r.size===0&&this.sessionsByPid.delete(s));return n&&this.save(),n}pushPending(t){this.ensureLoaded(),this.gcPending(),this.pendingClaudeStarts.push({...t})}takePendingMatched(t){this.ensureLoaded(),this.gcPending();let n=Bw({pending:this.pendingClaudeStarts,shellPid:t.shellPid,cwd:t.cwd,withinMs:t.withinMs,now:Date.now()});if(n.kind==="pid-match"||n.kind==="singleton-cwd"){let s=this.pendingClaudeStarts.indexOf(n.entry);s>=0&&this.pendingClaudeStarts.splice(s,1)}return n}pendingSize(){return this.ensureLoaded(),this.gcPending(),this.pendingClaudeStarts.length}deferSessionLink(t,n,s,r){this.ensureLoaded(),this.gcDeferredLinks(),this.deferredLinks.set(t,{parent_shell_pid:n,queued_at:Date.now(),cwd:s,git_branch:r})}allDeferredLinks(){return this.ensureLoaded(),this.gcDeferredLinks(),Array.from(this.deferredLinks.entries()).map(([t,n])=>({session_id:t,...n}))}resolveDeferredLink(t){return this.deferredLinks.delete(t)}deferredLinkSize(){return this.ensureLoaded(),this.gcDeferredLinks(),this.deferredLinks.size}gcDeferredLinks(){let t=Date.now()-9e4;for(let[n,s]of this.deferredLinks)s.queued_at<t&&this.deferredLinks.delete(n)}gcPending(){let t=Date.now()-Pw;this.pendingClaudeStarts.length!==0&&(this.pendingClaudeStarts=this.pendingClaudeStarts.filter(n=>{let s=Date.parse(n.started_at);return Number.isFinite(s)&&s>=t}))}outputTails=new Map;setOutputTail(t,n,s){this.ensureLoaded(),this.outputTails.set(t,{text:n,captured_at:s})}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,n){this.ensureLoaded(),this.origins.set(t,n),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()-qd;for(let[n,s]of this.entries){let r=Date.parse(s.last_seen_at);!Number.isNaN(r)&&r<t&&this.entries.delete(n)}}gcOrigins(){let t=Date.now()-qd;for(let[n,s]of this.origins)s.detectedAt<t&&this.origins.delete(n)}reapStaleLinks(t=10080*60*1e3){this.ensureLoaded();let s=Date.now()-t,r=0,o=0;for(let[i,a]of this.sessionsByPid){let d=this.entries.get(i);if(d){let l=Date.parse(d.last_seen_at);if(Number.isFinite(l)&&l>=s)continue}o+=a.size,this.sessionsByPid.delete(i),d&&(this.entries.delete(i),r++)}return(r||o)&&this.save(),{pruned_pids:r,pruned_sessions:o}}gcDeadPids(){this.ensureLoaded();let t=0,n=0;for(let s of[...this.entries.keys()]){let r=!0;try{process.kill(s,0)}catch(i){i.code==="ESRCH"&&(r=!1)}if(r)continue;this.entries.delete(s),t++;let o=this.sessionsByPid.get(s);o&&(n+=o.size,this.sessionsByPid.delete(s)),this.outputTails.delete(s),this.pidOwnership.delete(s)}return(t||n)&&this.save(),{pruned_pids:t,pruned_sessions:n}}},di=new li});import{execFile as Hw}from"node:child_process";import{promisify as Ww}from"node:util";var B$,Zd=w(()=>{"use strict";B$=Ww(Hw)});import{execFile as Xw}from"node:child_process";import{promisify as Gw}from"node:util";var V$,K$,eu=w(()=>{"use strict";ui();At();k();Zd();V$=Gw(Xw),K$=3600*1e3});import{execFile as zw}from"node:child_process";import{promisify as Jw}from"node:util";import{stat as Yw}from"node:fs/promises";async function Vw(e){try{let{stdout:t}=await tu("git",["rev-parse","--is-inside-work-tree"],{cwd:e,timeout:nu});return t.trim()==="true"}catch{return!1}}async function Kw(e,t,n){let s=["--no-pager","log","--all","--no-color","--since",t,"--until",n,`--pretty=format:${qw}`],{stdout:r}=await tu("git",s,{cwd:e,timeout:nu,maxBuffer:8*1024*1024}),o=[],i=new Set;for(let a of r.split(`
954
- `)){if(!a)continue;let[d,l,...u]=a.split(" ");!d||i.has(d)||(i.add(d),o.push({commit_sha:d,committed_at:l??null,subject:u.join(" ")||null}))}return o}function Qw(e){return E().prepare(`SELECT id, cwd, started_at, ended_at
955
- FROM sessions WHERE id = ?`).get(e)??null}function Zw(e,t,n){if(n.length===0)return 0;let s=E(),r=new Date().toISOString(),o=s.prepare(`INSERT OR IGNORE INTO session_commits
953
+ `});var Qd=w(()=>{"use strict"});var Zd=w(()=>{"use strict"});var eu=w(()=>{"use strict"});import{existsSync as Gw,readFileSync as Jw,writeFileSync as zw}from"node:fs";import{join as Yw}from"node:path";import{z as _e}from"zod";function di(e){let t=e.trim();return!!(!t||nu.test(t)||su.test(t))}function ru(e){let t=e.trim();if(!t||su.test(t))return null;let n=t.replace(nu,"").trim();return n.length>0?n:null}function li(e,t){if(!di(e))return e;let n=ru(e);return n||(t&&!di(t)?t:e)}function Zw(e){let t=e.now-e.withinMs,n=e.pending.filter(s=>{let r=Date.parse(s.started_at);return Number.isFinite(r)&&r>=t});if(n.length===0)return{kind:"none"};if(e.shellPid!=null){let s=n.find(r=>r.shell_pid===e.shellPid);if(s)return{kind:"pid-match",entry:s}}if(e.cwd){let s=e.cwd.replace(/\/+$/,""),r=n.filter(o=>o.cwd&&o.cwd.replace(/\/+$/,"")===s);if(r.length===1)return{kind:"singleton-cwd",entry:r[0]};if(r.length>=2)return{kind:"ambiguous",candidates:r}}return{kind:"none"}}var ci,tu,qw,Vw,Kw,Qw,nu,su,ui,pi,mi=w(()=>{"use strict";I();ci=Yw(C,"terminals.json"),tu=1440*60*1e3,qw=3e4,Vw=6e4,Kw=_e.object({shell_pid:_e.number(),tab_name:_e.string(),cwd:_e.string().nullable().optional(),opened_at:_e.string(),last_seen_at:_e.string()}),Qw=_e.object({schema:_e.string().optional(),saved_at:_e.string().optional(),terminals:_e.array(Kw).max(500).default([]),sessions_by_pid:_e.record(_e.string(),_e.array(_e.string()).max(50)).optional().default({})}),nu=/^[⠀-⣿✳\s]+/,su=/^\d+(\.\d+){1,3}$/;ui=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,!!Gw(ci)))try{let t=Jw(ci,"utf8"),n=JSON.parse(t),s=Qw.safeParse(n);if(!s.success){console.warn("[terminal-registry] terminals.json failed validation, starting with empty registry:",s.error.issues);return}let r=s.data;for(let o of r.terminals)this.entries.set(o.shell_pid,{shell_pid:o.shell_pid,tab_name:o.tab_name,cwd:o.cwd??null,opened_at:o.opened_at,last_seen_at:o.last_seen_at});for(let[o,i]of Object.entries(r.sessions_by_pid??{})){let a=Number(o);if(!Number.isFinite(a))continue;let d=new Set;for(let l of i)l.length>0&&d.add(l);d.size>0&&this.sessionsByPid.set(a,d)}this.gc()}catch{}}save(){try{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(([n,s])=>[String(n),Array.from(s)]))};zw(ci,JSON.stringify(t,null,2))}catch{}}upsert(t){this.ensureLoaded();let n=new Date().toISOString(),s=this.entries.get(t.shell_pid),r=li(t.tab_name,s?.tab_name),o=s?.opened_at??t.opened_at,i={...t,tab_name:r,opened_at:o,last_seen_at:n};return this.entries.set(t.shell_pid,i),this.gc(),this.save(),i}rename(t,n){this.ensureLoaded();let s=this.entries.get(t);if(!s)return null;let r=li(n,s.tab_name),o={...s,tab_name:r,last_seen_at:new Date().toISOString()};return this.entries.set(t,o),this.save(),o}remove(t){this.ensureLoaded();let n=this.entries.delete(t),s=this.sessionsByPid.delete(t);return this.outputTails.delete(t),this.pidOwnership.delete(t),(n||s)&&this.save(),n}claimPidOwnership(t,n,s=Date.now()){if(this.ensureLoaded(),!n)return"anonymous";let r=this.pidOwnership.get(t);return r?r.instance_id===n?(r.last_claim_at=s,"refreshed"):s-r.last_claim_at>Vw?(this.pidOwnership.set(t,{instance_id:n,last_claim_at:s}),"claimed"):"rejected":(this.pidOwnership.set(t,{instance_id:n,last_claim_at:s}),"claimed")}pidOwnershipSnapshot(){return this.ensureLoaded(),Array.from(this.pidOwnership.entries()).map(([t,n])=>({shell_pid:t,instance_id:n.instance_id,last_claim_at:n.last_claim_at}))}sync(t){this.ensureLoaded();let n=new Date().toISOString(),s=0,r=0;for(let o of t){let i=this.entries.get(o.shell_pid),a=li(o.tab_name,i?.tab_name),d=i?.opened_at??o.opened_at;this.entries.set(o.shell_pid,{...o,tab_name:a,opened_at:d,last_seen_at:n}),i?(i.tab_name!==a||i.cwd!==o.cwd)&&r++:s++}return this.gc(),this.save(),{added:s,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,n){this.ensureLoaded();let s=this.sessionsByPid.get(n);s||(s=new Set,this.sessionsByPid.set(n,s)),s.has(t)||(s.add(t),this.save())}sessionsFor(t){return this.ensureLoaded(),Array.from(this.sessionsByPid.get(t)??[])}isSessionAutoLinked(t){this.ensureLoaded();for(let n of this.sessionsByPid.values())if(n.has(t))return!0;return!1}unlinkSession(t){this.ensureLoaded();let n=!1;for(let[s,r]of this.sessionsByPid)r.delete(t)&&(n=!0,r.size===0&&this.sessionsByPid.delete(s));return n&&this.save(),n}pushPending(t){this.ensureLoaded(),this.gcPending(),this.pendingClaudeStarts.push({...t})}takePendingMatched(t){this.ensureLoaded(),this.gcPending();let n=Zw({pending:this.pendingClaudeStarts,shellPid:t.shellPid,cwd:t.cwd,withinMs:t.withinMs,now:Date.now()});if(n.kind==="pid-match"||n.kind==="singleton-cwd"){let s=this.pendingClaudeStarts.indexOf(n.entry);s>=0&&this.pendingClaudeStarts.splice(s,1)}return n}pendingSize(){return this.ensureLoaded(),this.gcPending(),this.pendingClaudeStarts.length}deferSessionLink(t,n,s,r){this.ensureLoaded(),this.gcDeferredLinks(),this.deferredLinks.set(t,{parent_shell_pid:n,queued_at:Date.now(),cwd:s,git_branch:r})}allDeferredLinks(){return this.ensureLoaded(),this.gcDeferredLinks(),Array.from(this.deferredLinks.entries()).map(([t,n])=>({session_id:t,...n}))}resolveDeferredLink(t){return this.deferredLinks.delete(t)}deferredLinkSize(){return this.ensureLoaded(),this.gcDeferredLinks(),this.deferredLinks.size}gcDeferredLinks(){let t=Date.now()-9e4;for(let[n,s]of this.deferredLinks)s.queued_at<t&&this.deferredLinks.delete(n)}gcPending(){let t=Date.now()-qw;this.pendingClaudeStarts.length!==0&&(this.pendingClaudeStarts=this.pendingClaudeStarts.filter(n=>{let s=Date.parse(n.started_at);return Number.isFinite(s)&&s>=t}))}outputTails=new Map;setOutputTail(t,n,s){this.ensureLoaded(),this.outputTails.set(t,{text:n,captured_at:s})}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,n){this.ensureLoaded(),this.origins.set(t,n),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()-tu;for(let[n,s]of this.entries){let r=Date.parse(s.last_seen_at);!Number.isNaN(r)&&r<t&&this.entries.delete(n)}}gcOrigins(){let t=Date.now()-tu;for(let[n,s]of this.origins)s.detectedAt<t&&this.origins.delete(n)}reapStaleLinks(t=10080*60*1e3){this.ensureLoaded();let s=Date.now()-t,r=0,o=0;for(let[i,a]of this.sessionsByPid){let d=this.entries.get(i);if(d){let l=Date.parse(d.last_seen_at);if(Number.isFinite(l)&&l>=s)continue}o+=a.size,this.sessionsByPid.delete(i),d&&(this.entries.delete(i),r++)}return(r||o)&&this.save(),{pruned_pids:r,pruned_sessions:o}}gcDeadPids(){this.ensureLoaded();let t=0,n=0;for(let s of[...this.entries.keys()]){let r=!0;try{process.kill(s,0)}catch(i){i.code==="ESRCH"&&(r=!1)}if(r)continue;this.entries.delete(s),t++;let o=this.sessionsByPid.get(s);o&&(n+=o.size,this.sessionsByPid.delete(s)),this.outputTails.delete(s),this.pidOwnership.delete(s)}return(t||n)&&this.save(),{pruned_pids:t,pruned_sessions:n}}},pi=new ui});import{execFile as eT}from"node:child_process";import{promisify as tT}from"node:util";var cP,ou=w(()=>{"use strict";cP=tT(eT)});import{execFile as nT}from"node:child_process";import{promisify as sT}from"node:util";var hP,EP,iu=w(()=>{"use strict";mi();Lt();k();ou();hP=sT(nT),EP=3600*1e3});import{execFile as rT}from"node:child_process";import{promisify as oT}from"node:util";import{stat as iT}from"node:fs/promises";async function cT(e){try{let{stdout:t}=await au("git",["rev-parse","--is-inside-work-tree"],{cwd:e,timeout:cu});return t.trim()==="true"}catch{return!1}}async function lT(e,t,n){let s=["--no-pager","log","--all","--no-color","--since",t,"--until",n,`--pretty=format:${aT}`],{stdout:r}=await au("git",s,{cwd:e,timeout:cu,maxBuffer:8*1024*1024}),o=[],i=new Set;for(let a of r.split(`
954
+ `)){if(!a)continue;let[d,l,...u]=a.split(" ");!d||i.has(d)||(i.add(d),o.push({commit_sha:d,committed_at:l??null,subject:u.join(" ")||null}))}return o}function dT(e){return h().prepare(`SELECT id, cwd, started_at, ended_at
955
+ FROM sessions WHERE id = ?`).get(e)??null}function uT(e,t,n){if(n.length===0)return 0;let s=h(),r=new Date().toISOString(),o=s.prepare(`INSERT OR IGNORE INTO session_commits
956
956
  (session_id, commit_sha, committed_at, subject, cwd_snapshot, correlated_at)
957
- VALUES (?, ?, ?, ?, ?, ?)`),i=0;return s.transaction(d=>{for(let l of d)o.run(e,l.commit_sha,l.committed_at,l.subject,t,r).changes>0&&(i+=1)})(n),i}async function pi(e){let t=Qw(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 n=t.started_at,s=t.ended_at===t.started_at?new Date(Date.parse(t.ended_at)+1e3).toISOString():t.ended_at;try{if(!(await Yw(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 Vw(t.cwd))return{sessionId:e,status:"not-a-repo",commitsFound:0,commitsInserted:0};try{let o=await Kw(t.cwd,n,s),i=Zw(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 su(e={}){let t=E(),n=Math.max(1,Math.min(1e5,e.limit??1e4)),s=t.prepare(`SELECT id FROM sessions
957
+ VALUES (?, ?, ?, ?, ?, ?)`),i=0;return s.transaction(d=>{for(let l of d)o.run(e,l.commit_sha,l.committed_at,l.subject,t,r).changes>0&&(i+=1)})(n),i}async function gi(e){let t=dT(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 n=t.started_at,s=t.ended_at===t.started_at?new Date(Date.parse(t.ended_at)+1e3).toISOString():t.ended_at;try{if(!(await iT(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 cT(t.cwd))return{sessionId:e,status:"not-a-repo",commitsFound:0,commitsInserted:0};try{let o=await lT(t.cwd,n,s),i=uT(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 lu(e={}){let t=h(),n=Math.max(1,Math.min(1e5,e.limit??1e4)),s=t.prepare(`SELECT id FROM sessions
958
958
  WHERE cwd IS NOT NULL AND started_at IS NOT NULL AND ended_at IS NOT NULL
959
959
  ORDER BY COALESCE(ended_at, started_at) DESC
960
- LIMIT ?`).all(n),r={total:s.length,ok:0,skipped:0,errors:0,commitsInserted:0,results:[]},o=0;for(let i of s){let a=await pi(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,s.length)}return r}function Vs(e){let t=E(),n=e.trim();if(!/^[0-9a-fA-F]{4,40}$/.test(n))return[];let s=`${n.toLowerCase()}%`;return t.prepare(`SELECT sc.session_id AS sessionId,
960
+ LIMIT ?`).all(n),r={total:s.length,ok:0,skipped:0,errors:0,commitsInserted:0,results:[]},o=0;for(let i of s){let a=await gi(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,s.length)}return r}function Ks(e){let t=h(),n=e.trim();if(!/^[0-9a-fA-F]{4,40}$/.test(n))return[];let s=`${n.toLowerCase()}%`;return t.prepare(`SELECT sc.session_id AS sessionId,
961
961
  NULLIF(sa.alias, '') AS alias,
962
962
  p.name AS project,
963
963
  s.started_at AS startedAt,
@@ -971,8 +971,12 @@ CREATE VIRTUAL TABLE IF NOT EXISTS vec_chunks_v2 USING vec0(
971
971
  LEFT JOIN session_aliases sa ON sa.session_id = sc.session_id
972
972
  WHERE lower(sc.commit_sha) = lower(?)
973
973
  OR lower(sc.commit_sha) LIKE ?
974
- ORDER BY COALESCE(sc.committed_at, s.started_at, '') DESC`).all(n,s)}var tu,nu,qw,Nn=w(()=>{"use strict";k();tu=Jw(zw),nu=1e4,qw="%H%x09%aI%x09%s"});import{join as eT}from"node:path";var aP,ru=w(()=>{"use strict";k();I();aP=eT(C,"collections.json")});import{basename as mP,join as mi}from"node:path";var ou,hP,EP,iu=w(()=>{"use strict";k();I();ru();ou=mi(C,"auto-rules"),hP=mi(ou,"rules.json"),EP=mi(ou,"suggestions.json")});var au=w(()=>{"use strict"});var cu=w(()=>{"use strict"});var lu=w(()=>{"use strict"});var du=w(()=>{"use strict";lu()});var uu=w(()=>{"use strict"});var pu=w(()=>{"use strict"});function mu(e){return e.replace(/\\/g,"/").includes("/subagents/")}function gu(e){let t=e.split(/[/\\]/),n=t.findIndex(s=>s==="projects");return n===-1||n+1>=t.length?null:t[n+1]??null}var fu=w(()=>{"use strict"});import{watch as JP}from"chokidar";import{readdirSync as nT,statSync as qP}from"node:fs";import{basename as sF,join as sT}from"node:path";function*gi(e){let t;try{t=nT(e,{withFileTypes:!0,encoding:"utf8"})}catch{return}for(let n of t){if(n.isSymbolicLink())continue;let s=sT(e,n.name);n.isDirectory()?yield*gi(s):n.isFile()&&n.name.endsWith(".jsonl")&&(yield s)}}var _u,hu,Eu=w(()=>{"use strict";I();k();Kn();Jd();Yd();eu();jt();Rs();Qn();Nn();so();ao();iu();dn();au();At();cu();du();Ds();uu();pu();fu();_u=gu,hu=mu});import{existsSync as rT,readFileSync as oT,renameSync as bu,writeFileSync as iT}from"node:fs";import{join as aT}from"node:path";function Su(){return aT(C,"doctor-state.json")}function yu(){let e=Su();if(!rT(e))return{chunkQueue:{samples:[]}};let t;try{t=oT(e,"utf8")}catch{return{chunkQueue:{samples:[]}}}try{let n=JSON.parse(t),s=n.chunkQueue?.samples,r=Array.isArray(s)?s.filter(d=>typeof d=="object"&&d!==null&&typeof d.ts=="string"&&typeof d.size=="number"&&typeof d.semanticEnabled=="boolean"):[],o=n.autoPruneCounters?.events,i=Array.isArray(o)?o.filter(d=>{if(!d||typeof d!="object")return!1;let l=d;return!(typeof l.ts!="string"||typeof l.pid!="number"||!Number.isFinite(l.pid)||l.action!=="would_kill"&&l.action!=="killed"&&l.action!=="failed"||l.reason!=="orphan_10min"&&l.reason!=="runaway_cpu_5min")}):[],a={chunkQueue:{samples:r}};return(i.length>0||o!==void 0)&&(a.autoPruneCounters={events:i}),a}catch{try{bu(e,`${e}.corrupt.${Date.now()}`)}catch{}return{chunkQueue:{samples:[]}}}}function wu(e){let t=Su(),n=`${t}.tmp`;try{iT(n,JSON.stringify(e,null,2),{mode:384}),bu(n,t)}catch{}}function fi(){let e=E(),t=0;try{t=e.prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}catch{}let n=!1;try{n=e.prepare("SELECT value FROM app_settings WHERE key = 'semantic_enabled'").get()?.value==="1"}catch{}let s=yu(),r=Date.now(),o=s.chunkQueue.samples,i=o.map(f=>({s:f,ms:Date.parse(f.ts)})).filter(f=>Number.isFinite(f.ms)&&r-f.ms<=lT).sort((f,h)=>f.ms-h.ms),a=null;i.length>0&&(a=t-i[0].s.size);let d=i.length,u={chunkQueue:{samples:[...o,{ts:new Date(r).toISOString(),size:t,semanticEnabled:n}].slice(-cT)}};s.autoPruneCounters&&(u.autoPruneCounters=s.autoPruneCounters),wu(u);let m="ok",p=`chunk_queue growth: ok (current ${t.toLocaleString()} row${t===1?"":"s"}, semantic ${n?"on":"off"}, ${d} prior sample${d===1?"":"s"} in last hour).`,g=null;return t>dT&&!n&&a!==null&&a>uT?(m="critical",p=`chunk_queue growth: CRITICAL \u2014 ${t.toLocaleString()} rows with semantic disabled, grew by ${a.toLocaleString()} in the last hour. Schema-sync race shape.`,g="Schema-sync race likely \u2014 Phase 1.1 fix shipped on `feat/daemon-state-integrity`; if rows persist after a clean restart, re-investigate. Inspect with `sqlite3 ~/.recall/db.sqlite 'SELECT action, COUNT(*) FROM chunk_queue GROUP BY action;'`."):t>pT?(m="high",p=`chunk_queue growth: HIGH \u2014 ${t.toLocaleString()} rows pending (semantic ${n?"on":"off"}`+(a!==null?`, last-hour \u0394 ${a>=0?"+":""}${a.toLocaleString()}`:"")+").",g="Queue is large but stable \u2014 operator-authorized `recall semantic backfill` (or the daemon's embed worker, if intentionally on) would drain."):a!==null&&a>mT&&(m="medium",p=`chunk_queue growth: MEDIUM \u2014 grew by ${a.toLocaleString()} in the last hour (current ${t.toLocaleString()}, semantic ${n?"on":"off"}).`,g="Growth is fast even though the absolute size is small. Re-run `recall doctor` in 10\u201330 min; if growth continues without semantic on, investigate the schema-sync gate."),{status:m,currentSize:t,semanticEnabled:n,lastHourGrowth:a,priorSampleCount:d,message:p,remediation:g}}function Tu(e={}){let t=e.now??Date.now(),n=yu(),s=n.autoPruneCounters?.events??[],r=s.filter(l=>{let u=Date.parse(l.ts);return Number.isFinite(u)&&t-u<=gT});if(r.length!==s.length)try{let l={chunkQueue:n.chunkQueue,autoPruneCounters:{events:r}};wu(l)}catch{}let o={orphan_10min:0,runaway_cpu_5min:0},i=0,a=0,d=0;for(let l of r)o[l.reason]+=1,l.action==="would_kill"?i+=1:l.action==="killed"?a+=1:d+=1;return{wouldHaveKilled:i,killed:a,failed:d,byReason:o}}var cT,lT,dT,uT,pT,mT,gT,_i=w(()=>{"use strict";I();k();cT=24,lT=3600*1e3,dT=1e3,uT=1e3,pT=1e4,mT=5e3,gT=1440*60*1e3});function ku(e=process.env){let t=e.RECALL_AUTO_PRUNE;if(typeof t!="string")return Ru;let n=t.trim().toLowerCase();return n==="off"||n==="dry-run"||n==="enabled"?n:Ru}var Ru,xu=w(()=>{"use strict";En();_i();Ru="dry-run"});import{existsSync as fT,readFileSync as _T,renameSync as Lu,writeFileSync as hT}from"node:fs";import{join as ET}from"node:path";function Au(){return ET(C,"doctor-alerts.json")}function Ks(){let e=Au();if(!fT(e))return{version:1,lastTickAt:new Date(0).toISOString(),alerts:[]};let t;try{t=_T(e,"utf8")}catch{return{version:1,lastTickAt:new Date(0).toISOString(),alerts:[]}}let n;try{n=JSON.parse(t)}catch{return Cu(e),{version:1,lastTickAt:new Date(0).toISOString(),alerts:[]}}if(!n||typeof n!="object"||Array.isArray(n))return Cu(e),{version:1,lastTickAt:new Date(0).toISOString(),alerts:[]};let s=n,r=Array.isArray(s.alerts)?s.alerts.filter(bT):[];return{version:1,lastTickAt:typeof s.lastTickAt=="string"?s.lastTickAt:new Date(0).toISOString(),alerts:r}}function Cu(e){try{Lu(e,`${e}.corrupt.${Date.now()}`)}catch{}}function bT(e){if(!e||typeof e!="object")return!1;let t=e;return typeof t.id=="string"&&typeof t.check=="string"&&(t.severity==="critical"||t.severity==="high"||t.severity==="medium")&&typeof t.message=="string"&&typeof t.remediation=="string"&&typeof t.firstSeenAt=="string"&&typeof t.lastSeenAt=="string"&&typeof t.seenCount=="number"&&typeof t.acknowledged=="boolean"}function Nu(e){let t=Au(),n=`${t}.tmp`;try{hT(n,JSON.stringify(e,null,2),{mode:384}),Lu(n,t)}catch{}}function Ou(e,t){let n=t.trim().toLowerCase();if(n.length<4)return{file:e,result:{outcome:"not-found"}};let s=e.alerts.filter(a=>a.id.startsWith(n));if(s.length===0)return{file:e,result:{outcome:"not-found"}};if(s.length>1)return{file:e,result:{outcome:"ambiguous",candidates:s.map(a=>a.id)}};let r=s[0];if(r.acknowledged)return{file:e,result:{outcome:"already-acknowledged",matched:r}};let o={...r,acknowledged:!0},i=e.alerts.map(a=>a.id===r.id?o:a);return{file:{...e,alerts:i},result:{outcome:"acknowledged",matched:o}}}function vu(e,t="critical"){let n={medium:0,high:1,critical:2},s=n[t];return e.alerts.filter(r=>!r.acknowledged&&n[r.severity]>=s)}var hi=w(()=>{"use strict";I()});var Zu={};V(Zu,{WATCHER_REFLAG_CRITICAL:()=>ju,buildHealthReport:()=>zu,buildPipelineDiagnostic:()=>Wu,checkChunkQueueGrowth:()=>fi,checkDaemonSiblings:()=>Ju,checkDaemonStateFiles:()=>Yu,checkDiskPressureAndBackups:()=>Xu,checkIngestStaleness:()=>Vu,checkSemanticGateDrift:()=>Qu,checkStaleClaudeJsonMcpPaths:()=>Ku,checkWatcherReflagLoop:()=>Uu,countBackupOrphans:()=>DT,detectLabelCollisions:()=>Gu,getFreeDiskBytes:()=>PT,renderMigrationDoctorSection:()=>qu,runDoctor:()=>Si});import{existsSync as On,readdirSync as ST,readFileSync as Ei,statSync as Qs,statfsSync as Pu}from"node:fs";import{homedir as yT}from"node:os";import{join as Zs}from"node:path";import*as Fu from"node:http";function RT(e){let t=[];for(let n of e)if(n.alias){if(TT.test(n.alias)){t.push({session_id:n.session_id,alias:n.alias,violation:"fabricated-origin-label",cwd:n.cwd});continue}if(n.cwd){let s=n.cwd.replace(/\/+$/,"").split("/").pop();s&&n.alias.startsWith(`${s} \xB7 `)&&t.push({session_id:n.session_id,alias:n.alias,violation:"fabricated-cwd-branch",cwd:n.cwd})}}return t}function Uu(e,t=ju){let n=[];for(let s of e){if(s.noProgressCount<=t)continue;let r=s.path.replace(/'/g,"''");n.push(`Watcher reindexed ${s.path} ${s.count.toLocaleString()} times in the last hour (${s.noProgressCount.toLocaleString()} with no new content) \u2014 reflag loop. Mark it skipped with a SQL one-liner:
975
- sqlite3 ~/.recall/db.sqlite "UPDATE sessions SET skipped_reason='reflag_loop_breaker' WHERE file_path = '${r}';"`)}return n}function kT(){let e=Zs(C,"daemon.port");if(!On(e))return null;try{let t=Ei(e,"utf8").trim();if(t.startsWith("{")){let s=JSON.parse(t);return typeof s.port=="number"?s.port:null}let n=Number.parseInt(t,10);return Number.isFinite(n)&&n>0&&n<65536?n:null}catch{return null}}function Iu(e,t,n){return new Promise(s=>{let r=Fu.request({host:"127.0.0.1",port:e,path:t,method:"GET",timeout:n,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){s({ok:!1,reason:"http"});return}try{s({ok:!0,json:JSON.parse(Buffer.concat(i).toString("utf8"))})}catch{s({ok:!1,reason:"parse"})}})});r.on("error",()=>s({ok:!1,reason:"error"})),r.on("timeout",()=>{r.destroy(),s({ok:!1,reason:"timeout"})}),r.end()})}async function xT(e){let t=await Iu(e,"/api/health",Mu);if(t.ok)return t.json;if(t.reason!=="timeout")return null;let n=await Iu(e,"/api/health",Mu);return n.ok?n.json:null}function CT(){let e=Zs(C,"terminals.json");if(!On(e))return{exists:!1,mtimeMs:null,ageSeconds:null};try{let t=Qs(e),n=Math.floor((Date.now()-t.mtimeMs)/1e3);return{exists:!0,mtimeMs:t.mtimeMs,ageSeconds:n}}catch{return{exists:!1,mtimeMs:null,ageSeconds:null}}}function LT(){let e=new Date(Date.now()-bi*36e5).toISOString();try{let t=E().prepare(`SELECT
974
+ ORDER BY COALESCE(sc.committed_at, s.started_at, '') DESC`).all(n,s)}var au,cu,aT,Nn=w(()=>{"use strict";k();au=oT(rT),cu=1e4,aT="%H%x09%aI%x09%s"});import{join as pT}from"node:path";var AP,du=w(()=>{"use strict";k();I();AP=pT(C,"collections.json")});import{basename as MP,join as fi}from"node:path";var uu,FP,jP,pu=w(()=>{"use strict";k();I();du();uu=fi(C,"auto-rules"),FP=fi(uu,"rules.json"),jP=fi(uu,"suggestions.json")});var mu=w(()=>{"use strict"});var gu=w(()=>{"use strict"});var fu=w(()=>{"use strict"});var _u=w(()=>{"use strict";fu()});var hu=w(()=>{"use strict"});var Eu=w(()=>{"use strict"});function bu(e){return e.replace(/\\/g,"/").includes("/subagents/")}function Su(e){let t=e.split(/[/\\]/),n=t.findIndex(s=>s==="projects");return n===-1||n+1>=t.length?null:t[n+1]??null}var yu=w(()=>{"use strict"});import{watch as _F}from"chokidar";import{readdirSync as gT,statSync as EF}from"node:fs";import{basename as CF,join as fT}from"node:path";function*_i(e){let t;try{t=gT(e,{withFileTypes:!0,encoding:"utf8"})}catch{return}for(let n of t){if(n.isSymbolicLink())continue;let s=fT(e,n.name);n.isDirectory()?yield*_i(s):n.isFile()&&n.name.endsWith(".jsonl")&&(yield s)}}var wu,Tu,Ru=w(()=>{"use strict";I();k();Qn();Qd();Zd();eu();iu();jt();ks();Zn();Nn();oo();lo();pu();dn();mu();Lt();gu();_u();$s();hu();Eu();yu();wu=Su,Tu=bu});import{existsSync as _T,readFileSync as hT,renameSync as ku,writeFileSync as ET}from"node:fs";import{join as bT}from"node:path";function xu(){return bT(C,"doctor-state.json")}function Cu(){let e=xu();if(!_T(e))return{chunkQueue:{samples:[]}};let t;try{t=hT(e,"utf8")}catch{return{chunkQueue:{samples:[]}}}try{let n=JSON.parse(t),s=n.chunkQueue?.samples,r=Array.isArray(s)?s.filter(d=>typeof d=="object"&&d!==null&&typeof d.ts=="string"&&typeof d.size=="number"&&typeof d.semanticEnabled=="boolean"):[],o=n.autoPruneCounters?.events,i=Array.isArray(o)?o.filter(d=>{if(!d||typeof d!="object")return!1;let l=d;return!(typeof l.ts!="string"||typeof l.pid!="number"||!Number.isFinite(l.pid)||l.action!=="would_kill"&&l.action!=="killed"&&l.action!=="failed"||l.reason!=="orphan_10min"&&l.reason!=="runaway_cpu_5min")}):[],a={chunkQueue:{samples:r}};return(i.length>0||o!==void 0)&&(a.autoPruneCounters={events:i}),a}catch{try{ku(e,`${e}.corrupt.${Date.now()}`)}catch{}return{chunkQueue:{samples:[]}}}}function Au(e){let t=xu(),n=`${t}.tmp`;try{ET(n,JSON.stringify(e,null,2),{mode:384}),ku(n,t)}catch{}}function hi(){let e=h(),t=0;try{t=e.prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}catch{}let n=!1;try{n=e.prepare("SELECT value FROM app_settings WHERE key = 'semantic_enabled'").get()?.value==="1"}catch{}let s=Cu(),r=Date.now(),o=s.chunkQueue.samples,i=o.map(f=>({s:f,ms:Date.parse(f.ts)})).filter(f=>Number.isFinite(f.ms)&&r-f.ms<=yT).sort((f,_)=>f.ms-_.ms),a=null;i.length>0&&(a=t-i[0].s.size);let d=i.length,u={chunkQueue:{samples:[...o,{ts:new Date(r).toISOString(),size:t,semanticEnabled:n}].slice(-ST)}};s.autoPruneCounters&&(u.autoPruneCounters=s.autoPruneCounters),Au(u);let m="ok",p=`chunk_queue growth: ok (current ${t.toLocaleString()} row${t===1?"":"s"}, semantic ${n?"on":"off"}, ${d} prior sample${d===1?"":"s"} in last hour).`,g=null;return t>wT&&!n&&a!==null&&a>TT?(m="critical",p=`chunk_queue growth: CRITICAL \u2014 ${t.toLocaleString()} rows with semantic disabled, grew by ${a.toLocaleString()} in the last hour. Schema-sync race shape.`,g="Schema-sync race likely \u2014 Phase 1.1 fix shipped on `feat/daemon-state-integrity`; if rows persist after a clean restart, re-investigate. Inspect with `sqlite3 ~/.recall/db.sqlite 'SELECT action, COUNT(*) FROM chunk_queue GROUP BY action;'`."):t>RT?(m="high",p=`chunk_queue growth: HIGH \u2014 ${t.toLocaleString()} rows pending (semantic ${n?"on":"off"}`+(a!==null?`, last-hour \u0394 ${a>=0?"+":""}${a.toLocaleString()}`:"")+").",g="Queue is large but stable \u2014 operator-authorized `recall semantic backfill` (or the daemon's embed worker, if intentionally on) would drain."):a!==null&&a>kT&&(m="medium",p=`chunk_queue growth: MEDIUM \u2014 grew by ${a.toLocaleString()} in the last hour (current ${t.toLocaleString()}, semantic ${n?"on":"off"}).`,g="Growth is fast even though the absolute size is small. Re-run `recall doctor` in 10\u201330 min; if growth continues without semantic on, investigate the schema-sync gate."),{status:m,currentSize:t,semanticEnabled:n,lastHourGrowth:a,priorSampleCount:d,message:p,remediation:g}}function Lu(e={}){let t=e.now??Date.now(),n=Cu(),s=n.autoPruneCounters?.events??[],r=s.filter(l=>{let u=Date.parse(l.ts);return Number.isFinite(u)&&t-u<=xT});if(r.length!==s.length)try{let l={chunkQueue:n.chunkQueue,autoPruneCounters:{events:r}};Au(l)}catch{}let o={orphan_10min:0,runaway_cpu_5min:0},i=0,a=0,d=0;for(let l of r)o[l.reason]+=1,l.action==="would_kill"?i+=1:l.action==="killed"?a+=1:d+=1;return{wouldHaveKilled:i,killed:a,failed:d,byReason:o}}var ST,yT,wT,TT,RT,kT,xT,Ei=w(()=>{"use strict";I();k();ST=24,yT=3600*1e3,wT=1e3,TT=1e3,RT=1e4,kT=5e3,xT=1440*60*1e3});function Ou(e=process.env){let t=e.RECALL_AUTO_PRUNE;if(typeof t!="string")return Nu;let n=t.trim().toLowerCase();return n==="off"||n==="dry-run"||n==="enabled"?n:Nu}var Nu,vu=w(()=>{"use strict";En();Ei();Nu="dry-run"});import{existsSync as CT,readFileSync as AT,renameSync as Mu,writeFileSync as LT}from"node:fs";import{join as NT}from"node:path";function Du(){return NT(C,"doctor-alerts.json")}function Qs(){let e=Du();if(!CT(e))return{version:1,lastTickAt:new Date(0).toISOString(),alerts:[]};let t;try{t=AT(e,"utf8")}catch{return{version:1,lastTickAt:new Date(0).toISOString(),alerts:[]}}let n;try{n=JSON.parse(t)}catch{return Iu(e),{version:1,lastTickAt:new Date(0).toISOString(),alerts:[]}}if(!n||typeof n!="object"||Array.isArray(n))return Iu(e),{version:1,lastTickAt:new Date(0).toISOString(),alerts:[]};let s=n,r=Array.isArray(s.alerts)?s.alerts.filter(OT):[];return{version:1,lastTickAt:typeof s.lastTickAt=="string"?s.lastTickAt:new Date(0).toISOString(),alerts:r}}function Iu(e){try{Mu(e,`${e}.corrupt.${Date.now()}`)}catch{}}function OT(e){if(!e||typeof e!="object")return!1;let t=e;return typeof t.id=="string"&&typeof t.check=="string"&&(t.severity==="critical"||t.severity==="high"||t.severity==="medium")&&typeof t.message=="string"&&typeof t.remediation=="string"&&typeof t.firstSeenAt=="string"&&typeof t.lastSeenAt=="string"&&typeof t.seenCount=="number"&&typeof t.acknowledged=="boolean"}function $u(e){let t=Du(),n=`${t}.tmp`;try{LT(n,JSON.stringify(e,null,2),{mode:384}),Mu(n,t)}catch{}}function Pu(e,t){let n=t.trim().toLowerCase();if(n.length<4)return{file:e,result:{outcome:"not-found"}};let s=e.alerts.filter(a=>a.id.startsWith(n));if(s.length===0)return{file:e,result:{outcome:"not-found"}};if(s.length>1)return{file:e,result:{outcome:"ambiguous",candidates:s.map(a=>a.id)}};let r=s[0];if(r.acknowledged)return{file:e,result:{outcome:"already-acknowledged",matched:r}};let o={...r,acknowledged:!0},i=e.alerts.map(a=>a.id===r.id?o:a);return{file:{...e,alerts:i},result:{outcome:"acknowledged",matched:o}}}function Fu(e,t="critical"){let n={medium:0,high:1,critical:2},s=n[t];return e.alerts.filter(r=>!r.acknowledged&&n[r.severity]>=s)}var bi=w(()=>{"use strict";I()});function MT(e){let t=e.toLowerCase();return IT.some(n=>t.includes(n))}function DT(e){let t=Number(e.slice(0,4)),n=Number(e.slice(4,6)),s=Number(e.slice(6,8));if(t<2e3||t>2099||n<1||n>12||s<1||s>31)return!1;let r=new Date(t,n-1,s);return r.getFullYear()===t&&r.getMonth()===n-1&&r.getDate()===s}function $T(e){let t=[];for(let n of e){let s=vT.exec(n);if(!s)continue;let r=s[1],o=s[2];MT(r)&&DT(o)&&t.push(n)}return t}function Zs(e,t){let n=Date.now();try{return t(),{step:e,ok:!0,durationMs:Date.now()-n}}catch(s){return{step:e,ok:!1,durationMs:Date.now()-n,error:s instanceof Error?s.message:String(s)}}}function yi(e,t){let s=On(e).tables.filter(d=>d.safeToDropNow).map(d=>d.name);if(!PT.test(t))return{ok:!1,table:t,reason:"invalid-identifier",steps:[],approved:s,message:`refused: ${JSON.stringify(t)} is not a valid table identifier`};if(!s.includes(t))return{ok:!1,table:t,reason:"not-safe-to-drop",steps:[],approved:s,message:s.length>0?`refused: "${t}" is not a reclaimable table. Safe to drop: ${s.join(", ")}`:`refused: "${t}" is not a reclaimable table (nothing is currently safe to drop)`};let r=[];r.push(Zs("DROP",()=>e.dropTable(t))),r.push(Zs("CHECKPOINT",()=>e.walCheckpointTruncate())),r.push(Zs("VACUUM",()=>e.vacuum()));let o=r.find(d=>!d.ok);if(o)return{ok:!1,table:t,reason:"step-failed",steps:r,approved:s,message:`${o.step} failed: ${o.error??"unknown error"}`};let i="unknown",a=Zs("INTEGRITY",()=>{i=e.integrityCheck()});return r.push(a),a.ok?i!=="ok"?{ok:!1,table:t,reason:"integrity-check-failed",integrity:i,steps:r,approved:s,message:`integrity_check reported: ${i}`}:{ok:!0,table:t,integrity:i,steps:r,approved:s,message:`dropped ${t} and reclaimed pages (integrity_check: ok)`}:{ok:!1,table:t,reason:"integrity-check-failed",integrity:i,steps:r,approved:s,message:`integrity_check could not run: ${a.error??"unknown error"}`}}function On(e){let t=e.listTableNames(),n=[];for(let o of $T(t))n.push({name:o,rows:e.countRows(o),kind:"dated-snapshot",safeToDropNow:!0,note:"dated one-off snapshot/parking-lot table \u2014 derived state, safe to drop"});if(t.includes(Si)){let o=e.isRollbackWindowOpen(),i=e.rollbackDaysRemaining();n.push({name:Si,rows:e.countRows(Si),kind:"vector-rollback-backup",safeToDropNow:!o,note:o?`rollback safety net \u2014 keep until the 30-day window closes${i!==null?` (${i} day(s) left; daemon auto-prunes)`:""}`:"rollback window elapsed \u2014 safe to drop (daemon normally auto-prunes this)"})}let s=n.reduce((o,i)=>o+i.rows,0),r=n.some(o=>o.safeToDropNow);return{tables:n,totalRows:s,hasReclaimable:r}}function ju(e,t={dim:n=>n,warn:n=>n}){if(e.tables.length===0)return null;let n=["--- In-database bloat ---"];for(let r of e.tables){let o=r.safeToDropNow?t.warn("reclaimable"):t.dim("keep");n.push(` ${r.name} ${r.rows.toLocaleString()} rows [${o}]`),n.push(t.dim(` ${r.note}`))}let s=e.tables.filter(r=>r.safeToDropNow);if(s.length>0){n.push(""),n.push(t.dim(" To reclaim: `recall stop`, then for each [reclaimable] table run"));for(let r of s)n.push(t.dim(` recall db drop-table ${r.name}`));n.push(t.dim(" then `recall start`. The command DROPs the table, reclaims pages (VACUUM),")),n.push(t.dim(" and verifies integrity. Do not interrupt it mid-VACUUM (see its warning)."))}return n.join(`
975
+ `)}var vT,IT,PT,Si,wi=w(()=>{"use strict";vT=/^(.+?)[_-](\d{8})$/,IT=["_deferred","_backup"];PT=/^[A-Za-z_][A-Za-z0-9_]*$/;Si="vec_chunks_v1_backup"});var cp={};V(cp,{WATCHER_REFLAG_CRITICAL:()=>Ju,buildHealthReport:()=>Zu,buildInDbBloatReport:()=>sp,buildPipelineDiagnostic:()=>Vu,checkChunkQueueGrowth:()=>hi,checkDaemonSiblings:()=>ep,checkDaemonStateFiles:()=>tp,checkDiskPressureAndBackups:()=>Ku,checkIngestStaleness:()=>op,checkSemanticGateDrift:()=>ap,checkStaleClaudeJsonMcpPaths:()=>ip,checkWatcherReflagLoop:()=>zu,countBackupOrphans:()=>ZT,detectLabelCollisions:()=>Qu,getFreeDiskBytes:()=>tR,renderInDbBloatDoctorSection:()=>rp,renderMigrationDoctorSection:()=>np,runDoctor:()=>ki});import{existsSync as vn,readdirSync as FT,readFileSync as Ti,statSync as er,statfsSync as Xu}from"node:fs";import{homedir as jT}from"node:os";import{join as tr}from"node:path";import*as Gu from"node:http";function HT(e){let t=[];for(let n of e)if(n.alias){if(BT.test(n.alias)){t.push({session_id:n.session_id,alias:n.alias,violation:"fabricated-origin-label",cwd:n.cwd});continue}if(n.cwd){let s=n.cwd.replace(/\/+$/,"").split("/").pop();s&&n.alias.startsWith(`${s} \xB7 `)&&t.push({session_id:n.session_id,alias:n.alias,violation:"fabricated-cwd-branch",cwd:n.cwd})}}return t}function zu(e,t=Ju){let n=[];for(let s of e){if(s.noProgressCount<=t)continue;let r=s.path.replace(/'/g,"''");n.push(`Watcher reindexed ${s.path} ${s.count.toLocaleString()} times in the last hour (${s.noProgressCount.toLocaleString()} with no new content) \u2014 reflag loop. With the daemon stopped (\`recall stop\`), mark it skipped
976
+ using the resolved DB path below \u2014 this honors $RECALL_HOME and avoids
977
+ the non-expanding \`~\` that breaks in Windows cmd/PowerShell (requires
978
+ the sqlite3 CLI):
979
+ sqlite3 "${ee}" "UPDATE sessions SET skipped_reason='reflag_loop_breaker' WHERE file_path = '${r}';"`)}return n}function WT(){let e=tr(C,"daemon.port");if(!vn(e))return null;try{let t=Ti(e,"utf8").trim();if(t.startsWith("{")){let s=JSON.parse(t);return typeof s.port=="number"?s.port:null}let n=Number.parseInt(t,10);return Number.isFinite(n)&&n>0&&n<65536?n:null}catch{return null}}function Uu(e,t,n){return new Promise(s=>{let r=Gu.request({host:"127.0.0.1",port:e,path:t,method:"GET",timeout:n,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){s({ok:!1,reason:"http"});return}try{s({ok:!0,json:JSON.parse(Buffer.concat(i).toString("utf8"))})}catch{s({ok:!1,reason:"parse"})}})});r.on("error",()=>s({ok:!1,reason:"error"})),r.on("timeout",()=>{r.destroy(),s({ok:!1,reason:"timeout"})}),r.end()})}async function XT(e){let t=await Uu(e,"/api/health",Bu);if(t.ok)return t.json;if(t.reason!=="timeout")return null;let n=await Uu(e,"/api/health",Bu);return n.ok?n.json:null}function GT(){let e=tr(C,"terminals.json");if(!vn(e))return{exists:!1,mtimeMs:null,ageSeconds:null};try{let t=er(e),n=Math.floor((Date.now()-t.mtimeMs)/1e3);return{exists:!0,mtimeMs:t.mtimeMs,ageSeconds:n}}catch{return{exists:!1,mtimeMs:null,ageSeconds:null}}}function JT(){let e=new Date(Date.now()-Ri*36e5).toISOString();try{let t=h().prepare(`SELECT
976
980
  COUNT(*) AS total,
977
981
  SUM(CASE WHEN sa.alias IS NULL OR sa.alias = '' THEN 1 ELSE 0 END) AS without_alias,
978
982
  SUM(CASE WHEN (sa.alias IS NULL OR sa.alias = '')
@@ -984,7 +988,7 @@ CREATE VIRTUAL TABLE IF NOT EXISTS vec_chunks_v2 USING vec0(
984
988
  AND COALESCE(s.cwd, '') NOT LIKE '/private/tmp/%'
985
989
  AND COALESCE(s.cwd, '') NOT LIKE '/var/folders/%'
986
990
  AND COALESCE(s.cwd, '') NOT LIKE '/private/var/folders/%'
987
- AND COALESCE(s.cwd, '') NOT IN ('/tmp', '/private/tmp', '/')`).get(e),n=t.total??0,s=t.without_alias??0,r=t.heuristic_only??0,o=n>0?r/n:0;return{total:n,withoutAlias:s,heuristicOnly:r,fractionHeuristic:o}}catch{return{total:0,withoutAlias:0,heuristicOnly:0,fractionHeuristic:0}}}async function Wu(){let e=kT(),t=CT(),n=LT(),s=!1,r=null,o=null,i=null,a=null,d=null,l=[];if(e){let p=await xT(e);if(p){s=!0,r=typeof p.uptimeSeconds=="number"?p.uptimeSeconds:null,o=typeof p.version=="string"?p.version:null,i=typeof p.pipeline?.silentTerminalRejections=="number"?p.pipeline.silentTerminalRejections:null,a=p.pipeline?.lastTerminalSyncAt??null;let g=p.pipeline?.autoExtract;g&&(d={circuitBroken:g.circuitBroken===!0,reason:g.reason??null,brokenAt:typeof g.brokenAt=="number"?g.brokenAt:null,consecutiveZeroTokenRuns:typeof g.consecutiveZeroTokenRuns=="number"?g.consecutiveZeroTokenRuns:0});let f=p.pipeline?.watcherReindexHotFiles;Array.isArray(f)&&(l=f.filter(h=>typeof h?.path=="string"&&typeof h?.count=="number"&&typeof h?.firstSeenAt=="number").map(h=>({path:h.path,count:h.count,firstSeenAt:h.firstSeenAt,noProgressCount:typeof h.noProgressCount=="number"?h.noProgressCount:h.count})))}}let u=[];if(s||u.push("Daemon not reachable on 127.0.0.1 \u2014 start it with `recall start` before further diagnosis."),i!==null&&i>0&&u.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").`),s&&r!==null&&r>30)if(!a)u.push(`Daemon has been running ${Math.round(r/60)} min but has not yet seen a single successful /api/terminal/sync. Either no editor extension is installed/active, or every attempt is being rejected (see counter above).`);else{let p=Date.now()-Date.parse(a);Number.isFinite(p)&&p>Bu&&u.push(`Last successful /api/terminal/sync was ${Math.round(p/6e4)} min ago \u2014 extension may have crashed, been disabled, or is failing auth. Run \`recall doctor\` again after restarting the extension host.`)}!s&&t.exists&&t.ageSeconds!==null&&t.ageSeconds>24*3600&&u.push(`~/.recall/terminals.json is ${Math.round(t.ageSeconds/3600)}h old \u2014 pipeline has not produced fresh data recently. Likely root cause is the same as the rejection counter would show; start the daemon and re-run.`),d?.circuitBroken&&u.push(`Auto-extract circuit breaker tripped \u2014 ${d.reason??"reason unknown"}. Run \`recall semantic auto-extract off\` then \`... on\` to reset, or restart the daemon.`),n.total>=3&&n.fractionHeuristic>=Hu&&u.push(`${n.heuristicOnly}/${n.total} sessions in the last ${bi}h (${Math.round(n.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.`);for(let p of Uu(l))u.push(p);return{state:s?u.length>0?"degraded":"ok":"down",flags:u,daemon:{running:s,port:e,uptimeSeconds:r,version:o},runtime:{silentTerminalRejections:i,lastTerminalSyncAt:a,autoExtract:d},terminalsJson:t,recentSessions:n,watcherReindexHotFiles:l}}function ce(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 Du(e){try{return Qs(e).size}catch{return 0}}function AT(e){return e==="db.sqlite"||e==="db.sqlite-wal"||e==="db.sqlite-shm"?!1:!!(e.startsWith("db.sqlite.")||e.endsWith(".bak")||e.includes(".bak."))}function Xu(e=C){let t=0,n=0;try{let g=Pu(e);t=Number(g.bavail)*Number(g.bsize),n=Number(g.blocks)*Number(g.bsize)}catch{}let s=n>0?t/n*100:100,r=[];try{r=ST(e)}catch{r=[]}let o=0,i=0,a=[],d=Date.now(),l=720*60*60*1e3;for(let g of r){if(!AT(g))continue;let f;try{f=Qs(Zs(e,g))}catch{continue}if(!f.isFile())continue;i+=1,o+=f.size;let h=Math.max(0,d-f.mtimeMs),_=Math.floor(h/(1440*60*1e3));h>=l&&a.push({name:g,sizeBytes:f.size,ageDays:_})}a.sort((g,f)=>f.sizeBytes!==g.sizeBytes?f.sizeBytes-g.sizeBytes:f.ageDays-g.ageDays);let u=2*1024**3,m=5*1024**3,p="ok";return n>0&&s<10||o>m?p="high":n>0&&s<20||o>u?p="medium":i>0&&(p="low"),{freeBytes:t,totalBytes:n,freePercent:s,backupTotalBytes:o,backupFileCount:i,oldFiles:a,severity:p}}function $u(e){try{return E().prepare(`SELECT COUNT(*) AS n FROM ${e}_data WHERE block = 1`).get().n}catch{return 0}}function Gu(){try{return E().prepare(`SELECT p.name AS project,
991
+ AND COALESCE(s.cwd, '') NOT IN ('/tmp', '/private/tmp', '/')`).get(e),n=t.total??0,s=t.without_alias??0,r=t.heuristic_only??0,o=n>0?r/n:0;return{total:n,withoutAlias:s,heuristicOnly:r,fractionHeuristic:o}}catch{return{total:0,withoutAlias:0,heuristicOnly:0,fractionHeuristic:0}}}async function Vu(){let e=WT(),t=GT(),n=JT(),s=!1,r=null,o=null,i=null,a=null,d=null,l=[];if(e){let p=await XT(e);if(p){s=!0,r=typeof p.uptimeSeconds=="number"?p.uptimeSeconds:null,o=typeof p.version=="string"?p.version:null,i=typeof p.pipeline?.silentTerminalRejections=="number"?p.pipeline.silentTerminalRejections:null,a=p.pipeline?.lastTerminalSyncAt??null;let g=p.pipeline?.autoExtract;g&&(d={circuitBroken:g.circuitBroken===!0,reason:g.reason??null,brokenAt:typeof g.brokenAt=="number"?g.brokenAt:null,consecutiveZeroTokenRuns:typeof g.consecutiveZeroTokenRuns=="number"?g.consecutiveZeroTokenRuns:0});let f=p.pipeline?.watcherReindexHotFiles;Array.isArray(f)&&(l=f.filter(_=>typeof _?.path=="string"&&typeof _?.count=="number"&&typeof _?.firstSeenAt=="number").map(_=>({path:_.path,count:_.count,firstSeenAt:_.firstSeenAt,noProgressCount:typeof _.noProgressCount=="number"?_.noProgressCount:_.count})))}}let u=[];if(s||u.push("Daemon not reachable on 127.0.0.1 \u2014 start it with `recall start` before further diagnosis."),i!==null&&i>0&&u.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").`),s&&r!==null&&r>30)if(!a)u.push(`Daemon has been running ${Math.round(r/60)} min but has not yet seen a single successful /api/terminal/sync. Either no editor extension is installed/active, or every attempt is being rejected (see counter above).`);else{let p=Date.now()-Date.parse(a);Number.isFinite(p)&&p>Yu&&u.push(`Last successful /api/terminal/sync was ${Math.round(p/6e4)} min ago \u2014 extension may have crashed, been disabled, or is failing auth. Run \`recall doctor\` again after restarting the extension host.`)}!s&&t.exists&&t.ageSeconds!==null&&t.ageSeconds>24*3600&&u.push(`~/.recall/terminals.json is ${Math.round(t.ageSeconds/3600)}h old \u2014 pipeline has not produced fresh data recently. Likely root cause is the same as the rejection counter would show; start the daemon and re-run.`),d?.circuitBroken&&u.push(`Auto-extract circuit breaker tripped \u2014 ${d.reason??"reason unknown"}. Run \`recall semantic auto-extract off\` then \`... on\` to reset, or restart the daemon.`),n.total>=3&&n.fractionHeuristic>=qu&&u.push(`${n.heuristicOnly}/${n.total} sessions in the last ${Ri}h (${Math.round(n.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.`);for(let p of zu(l))u.push(p);return{state:s?u.length>0?"degraded":"ok":"down",flags:u,daemon:{running:s,port:e,uptimeSeconds:r,version:o},runtime:{silentTerminalRejections:i,lastTerminalSyncAt:a,autoExtract:d},terminalsJson:t,recentSessions:n,watcherReindexHotFiles:l}}function ce(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 Hu(e){try{return er(e).size}catch{return 0}}function zT(e){return e==="db.sqlite"||e==="db.sqlite-wal"||e==="db.sqlite-shm"?!1:!!(e.startsWith("db.sqlite.")||e.endsWith(".bak")||e.includes(".bak."))}function Ku(e=C){let t=0,n=0;try{let g=Xu(e);t=Number(g.bavail)*Number(g.bsize),n=Number(g.blocks)*Number(g.bsize)}catch{}let s=n>0?t/n*100:100,r=[];try{r=FT(e)}catch{r=[]}let o=0,i=0,a=[],d=Date.now(),l=720*60*60*1e3;for(let g of r){if(!zT(g))continue;let f;try{f=er(tr(e,g))}catch{continue}if(!f.isFile())continue;i+=1,o+=f.size;let _=Math.max(0,d-f.mtimeMs),b=Math.floor(_/(1440*60*1e3));_>=l&&a.push({name:g,sizeBytes:f.size,ageDays:b})}a.sort((g,f)=>f.sizeBytes!==g.sizeBytes?f.sizeBytes-g.sizeBytes:f.ageDays-g.ageDays);let u=2*1024**3,m=5*1024**3,p="ok";return n>0&&s<10||o>m?p="high":n>0&&s<20||o>u?p="medium":i>0&&(p="low"),{freeBytes:t,totalBytes:n,freePercent:s,backupTotalBytes:o,backupFileCount:i,oldFiles:a,severity:p}}function Wu(e){try{return h().prepare(`SELECT COUNT(*) AS n FROM ${e}_data WHERE block = 1`).get().n}catch{return 0}}function Qu(){try{return h().prepare(`SELECT p.name AS project,
988
992
  COALESCE(NULLIF(sa.alias, ''), s.auto_title, substr(s.first_user_message, 1, 60)) AS label,
989
993
  COUNT(*) AS count,
990
994
  MAX(CASE WHEN sa.alias IS NOT NULL AND sa.alias != '' THEN 1 ELSE 0 END) AS any_aliased
@@ -1003,31 +1007,32 @@ CREATE VIRTUAL TABLE IF NOT EXISTS vec_chunks_v2 USING vec0(
1003
1007
  GROUP BY p.name, label
1004
1008
  HAVING count >= 2
1005
1009
  ORDER BY count DESC, label ASC
1006
- LIMIT 10`).all().map(e=>{let t=e;return{project:t.project,label:t.label,count:t.count,anyAliased:t.any_aliased===1}})}catch{return[]}}function zu(e){let t=E(),n=t.pragma("page_size",{simple:!0})||4096,s=t.pragma("page_count",{simple:!0})||0,r=t.pragma("freelist_count",{simple:!0})||0;e?.("Checking database integrity");let o="ok";try{let v=t.pragma("quick_check").map(O=>O.quick_check);o=v.length===1&&v[0]==="ok"?"ok":v.join("; ")}catch(L){o=`check failed: ${L.message}`}let i=Du(ee),a=Du(`${ee}-wal`),d=Xu(),l=d.freeBytes,u=d.totalBytes;e?.("Counting rows");let m=t.prepare(`SELECT
1010
+ LIMIT 10`).all().map(e=>{let t=e;return{project:t.project,label:t.label,count:t.count,anyAliased:t.any_aliased===1}})}catch{return[]}}function Zu(e){let t=h(),n=t.pragma("page_size",{simple:!0})||4096,s=t.pragma("page_count",{simple:!0})||0,r=t.pragma("freelist_count",{simple:!0})||0;e?.("Checking database integrity");let o="ok";try{let v=t.pragma("quick_check").map(O=>O.quick_check);o=v.length===1&&v[0]==="ok"?"ok":v.join("; ")}catch(A){o=`check failed: ${A.message}`}let i=Hu(ee),a=Hu(`${ee}-wal`),d=Ku(),l=d.freeBytes,u=d.totalBytes;e?.("Counting rows");let m=t.prepare(`SELECT
1007
1011
  (SELECT COUNT(*) FROM projects) AS projects,
1008
1012
  (SELECT COUNT(*) FROM sessions) AS sessions,
1009
1013
  (SELECT COUNT(*) FROM messages) AS messages,
1010
- (SELECT COUNT(*) FROM message_usage) AS message_usage`).get(),p=0;try{lt(t),p=t.prepare("SELECT COUNT(*) AS n FROM vec_chunks").get().n}catch{}e?.("Measuring FTS fragmentation");let g=[];if(l>0&&l<1*1024**3&&g.push(`Disk free is ${ce(l)} \u2014 heavy operations (synthesis, extract-outputs, vector ingest) may fail.`),d.severity==="high"||d.severity==="medium"){let L=d.severity==="high"?"HIGH":"MEDIUM",v=[];u>0&&v.push(`disk: ${ce(l)} free of ${ce(u)} (${d.freePercent.toFixed(1)}%)`),d.backupFileCount>0&&v.push(`backups: ${ce(d.backupTotalBytes)} in ${d.backupFileCount} file${d.backupFileCount===1?"":"s"}`);let O=`[${L}] disk pressure \u2014 ${v.join(" \xB7 ")}`;if(d.oldFiles.length>0){let x=d.oldFiles.map(M=>` \u2022 ${M.name} ${ce(M.sizeBytes)} (${M.ageDays} days old)`);O+=`
1014
+ (SELECT COUNT(*) FROM message_usage) AS message_usage`).get(),p=0;try{lt(t),p=t.prepare("SELECT COUNT(*) AS n FROM vec_chunks").get().n}catch{}e?.("Measuring FTS fragmentation");let g=[];if(l>0&&l<1*1024**3&&g.push(`Disk free is ${ce(l)} \u2014 heavy operations (synthesis, extract-outputs, vector ingest) may fail.`),d.severity==="high"||d.severity==="medium"){let A=d.severity==="high"?"HIGH":"MEDIUM",v=[];u>0&&v.push(`disk: ${ce(l)} free of ${ce(u)} (${d.freePercent.toFixed(1)}%)`),d.backupFileCount>0&&v.push(`backups: ${ce(d.backupTotalBytes)} in ${d.backupFileCount} file${d.backupFileCount===1?"":"s"}`);let O=`[${A}] disk pressure \u2014 ${v.join(" \xB7 ")}`;if(d.oldFiles.length>0){let x=d.oldFiles.map(M=>` \u2022 ${M.name} ${ce(M.sizeBytes)} (${M.ageDays} days old)`);O+=`
1011
1015
  Snapshots older than 30 days:
1012
1016
  `+x.join(`
1013
1017
  `)+"\n review then delete with: `ls -la ~/.recall/*.bak* | sort -k6,7` \u2014 items older than 30 days are typically safe per memory `partial_corpus_swap_bug_20260519` (keep most recent .pre-swap for rollback)."}else d.backupFileCount>0&&(O+=`
1014
- No snapshots older than 30 days \u2014 recent ones may still be rollback-critical; leave them alone unless you know what you're doing.`);g.push(O)}let f=100*1024**2,h=a>=Zc?"error":a>=f?"warn":"ok";h==="error"?g.push(`WAL is ${ce(a)} \u2014 readers are pinning the checkpoint frontier. Run \`recall mcp-prune\` to release stuck MCP children, then \`recall optimize\` to truncate.`):h==="warn"&&g.push(`WAL is ${ce(a)} \u2014 run \`recall optimize\` to truncate it.`);let _=Lt(),b=_.filter(L=>L.orphan);b.length>0&&g.push(`${b.length} orphaned MCP child${b.length===1?"":"ren"} (pid${b.length===1?"":"s"}: ${b.map(L=>L.pid).join(", ")}). Each holds a SQLite read connection. Run \`recall mcp-prune\` to clean up.`);let S=_.filter(us);S.length>0&&g.push(`${S.length} MCP child${S.length===1?"":"ren"} burning CPU (pid${S.length===1?"":"s"}: ${S.map(L=>L.pid).join(", ")}). Likely runaway vec0 kNN. Run \`recall stop --all\` or \`recall mcp-prune --all\`.`),r>s*.2&&s>1e3&&g.push(`${r.toLocaleString()} free pages (${(r/s*100).toFixed(0)}% of file) \u2014 \`recall optimize --vacuum\` will reclaim them.`);let y=$u("messages_fts"),T=$u("sessions_fts");y>16&&g.push(`messages_fts has ${y} segments \u2014 \`recall optimize\` will merge them.`);let R=0;try{R=t.prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}catch{}let B=!1;try{B=t.prepare("SELECT value FROM app_settings WHERE key = 'semantic_enabled'").get()?.value==="1"}catch{}return!B&&R>0?g.push(`${R.toLocaleString()} rows in chunk_queue with semantic disabled \u2014 schema gate is stale; restart daemon (v0.67+) to migrate.`):R>1e5&&g.push(`chunk_queue has ${R.toLocaleString()} pending rows \u2014 embedder is behind. \`recall semantic backfill\` to drain manually.`),{db:{sizeBytes:i,walSizeBytes:a,pageCount:s,pageSize:n,freelistCount:r,freelistBytes:r*n,integrity:o},disk:{freeBytes:l,totalBytes:u,backups:{totalBytes:d.backupTotalBytes,fileCount:d.backupFileCount,oldFiles:d.oldFiles,severity:d.severity}},fts:{messages:{fragments:y},sessions:{fragments:T}},vectors:{rows:p},rows:{projects:m.projects,sessions:m.sessions,messages:m.messages,messageUsage:m.message_usage},chunkQueue:{size:R,semanticEnabled:B},wal:{sizeBytes:a,level:h},mcpProcesses:_,warnings:g}}function NT(e){if(!e)return{stage:()=>{},done:()=>{}};let t=!!process.stderr.isTTY,n="",s=0,r=()=>{if(!n)return;let o=Date.now()-s,i=o<1e3?`${o}ms`:`${(o/1e3).toFixed(1)}s`;t?process.stderr.write(`\r\x1B[2K ${c.ok("\u2713")} ${n} ${c.dim(`(${i})`)}
1018
+ No snapshots older than 30 days \u2014 recent ones may still be rollback-critical; leave them alone unless you know what you're doing.`);g.push(O)}let f=100*1024**2,_=a>=rl?"error":a>=f?"warn":"ok";_==="error"?g.push(`WAL is ${ce(a)} \u2014 readers are pinning the checkpoint frontier. Run \`recall mcp-prune\` to release stuck MCP children, then \`recall optimize\` to truncate.`):_==="warn"&&g.push(`WAL is ${ce(a)} \u2014 run \`recall optimize\` to truncate it.`);let b=At(),E=b.filter(A=>A.orphan);E.length>0&&g.push(`${E.length} orphaned MCP child${E.length===1?"":"ren"} (pid${E.length===1?"":"s"}: ${E.map(A=>A.pid).join(", ")}). Each holds a SQLite read connection. Run \`recall mcp-prune\` to clean up.`);let S=b.filter(ps);S.length>0&&g.push(`${S.length} MCP child${S.length===1?"":"ren"} burning CPU (pid${S.length===1?"":"s"}: ${S.map(A=>A.pid).join(", ")}). Likely runaway vec0 kNN. Run \`recall stop --all\` or \`recall mcp-prune --all\`.`),r>s*.2&&s>1e3&&g.push(`${r.toLocaleString()} free pages (${(r/s*100).toFixed(0)}% of file) \u2014 \`recall optimize --vacuum\` will reclaim them.`);let y=Wu("messages_fts"),T=Wu("sessions_fts");y>16&&g.push(`messages_fts has ${y} segments \u2014 \`recall optimize\` will merge them.`);let R=0;try{R=t.prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}catch{}let B=!1;try{B=t.prepare("SELECT value FROM app_settings WHERE key = 'semantic_enabled'").get()?.value==="1"}catch{}return!B&&R>0?g.push(`${R.toLocaleString()} rows in chunk_queue with semantic disabled \u2014 schema gate is stale; restart daemon (v0.67+) to migrate.`):R>1e5&&g.push(`chunk_queue has ${R.toLocaleString()} pending rows \u2014 embedder is behind. \`recall semantic backfill\` to drain manually.`),{db:{sizeBytes:i,walSizeBytes:a,pageCount:s,pageSize:n,freelistCount:r,freelistBytes:r*n,integrity:o},disk:{freeBytes:l,totalBytes:u,backups:{totalBytes:d.backupTotalBytes,fileCount:d.backupFileCount,oldFiles:d.oldFiles,severity:d.severity}},fts:{messages:{fragments:y},sessions:{fragments:T}},vectors:{rows:p},rows:{projects:m.projects,sessions:m.sessions,messages:m.messages,messageUsage:m.message_usage},chunkQueue:{size:R,semanticEnabled:B},wal:{sizeBytes:a,level:_},mcpProcesses:b,warnings:g}}function YT(e){if(!e)return{stage:()=>{},done:()=>{}};let t=!!process.stderr.isTTY,n="",s=0,r=()=>{if(!n)return;let o=Date.now()-s,i=o<1e3?`${o}ms`:`${(o/1e3).toFixed(1)}s`;t?process.stderr.write(`\r\x1B[2K ${c.ok("\u2713")} ${n} ${c.dim(`(${i})`)}
1015
1019
  `):process.stderr.write(` \u2713 ${n} (${i})
1016
1020
  `),n=""};return{stage(o){r(),n=o,s=Date.now(),t?process.stderr.write(` ${c.dim("\u2026")} ${n}`):process.stderr.write(` \u2026 ${n}
1017
- `)},done:r}}function Ju(e){let t=e??st(),n=t.length;if(n<=1)return{flagged:!1,severity:"ok",count:n,processes:t,message:null};let s=t.map(o=>{let i=fn(o.etimeSeconds)??o.etime;return`pid=${o.pid} started=${i} age=${pt(o.etimeSeconds)}`}),r=`${n} Recall daemons running simultaneously: ${s.join("; ")}. Two daemons write the same db.sqlite and corrupt state (chunk_queue fills, schema-sync race re-enables feature flags). Run \`recall stop\` to kill all (now nukes orphans too as of Phase 2.6), then \`recall start\`.`;return{flagged:!0,severity:"critical",count:n,processes:t,message:r}}function Yu(e={}){if((e.liveDaemons??st({excludePids:[process.pid]})).length===0)return{flagged:!1,severity:"ok",daemonAlive:!1,missing:[],message:null,remediation:null};let n=e.paths??cs(),s=e.existsSync??On,r=e.isProcessAlive??hn,o=!1;if(s(n.pid))try{let d=JSON.parse(Ei(n.pid,"utf8"));typeof d.pid=="number"&&r(d.pid)&&(o=!0)}catch{}if(!o)return{flagged:!1,severity:"ok",daemonAlive:!0,missing:[],message:null,remediation:null};let i=[];return s(n.port)||i.push("daemon.port"),s(n.token)||i.push("daemon.token"),i.length===0?{flagged:!1,severity:"ok",daemonAlive:!0,missing:[],message:null,remediation:null}:{flagged:!0,severity:"critical",daemonAlive:!0,missing:i,message:`Daemon process is alive (per pidfile) but companion state file${i.length===1?"":"s"} ${i.join(", ")} missing. Web UI and authenticated CLI calls will return 401 until the 30s heal tick restores them.`,remediation:"The 30-second heal tick re-creates these files automatically. To force immediate recovery: recall stop && recall start. Inspect ~/.recall/daemon.log for [state-files-audit] entries to identify the deletion source."}}function OT(e){e.flagged&&(console.log(""),console.log(c.dim("\u2014 Daemon state files \u2014")),console.log(c.err(` \u2717 CRITICAL: daemon process alive but missing ${e.missing.join(", ")}`)),e.remediation&&console.log(c.dim(` Remediation: ${e.remediation}`)))}function vT(e){if(e.flagged){console.log(""),console.log(c.dim("\u2014 Daemon processes \u2014")),console.log(c.err(` \u2717 CRITICAL: ${e.count} daemons running (two daemons must never run in parallel)`));for(let t of e.processes){let n=fn(t.etimeSeconds)??t.etime;console.log(` ${c.dim("\u2022")} pid ${t.pid} started ${n} age ${pt(t.etimeSeconds)} ppid=${t.ppid}`)}e.message&&console.log(c.dim(" Remediation: `recall stop` (now nukes orphans too as of Phase 2.6), then `recall start`."))}}function IT(e){if(console.log(c.dim("\u2014 MCP processes \u2014")),e.length===0){console.log(c.ok(" \u2713 no MCP children running"));return}let t=e.filter(i=>i.orphan),n=e.reduce((i,a)=>Math.max(i,a.etimeSeconds),0),s=e.length-t.length;if(console.log(` ${e.length} total, ${s} with live parent, ${t.length===0?c.ok("0 orphaned"):c.err(`${t.length} orphaned`)} (oldest ${pt(n)})`),t.length>0){console.log(c.dim(" Orphans hold a SQLite read connection and can stall WAL checkpoints. Run `recall mcp-prune` to kill them."));for(let i of t.slice(0,5))console.log(` ${c.dim("\u2022")} pid ${i.pid} age ${pt(i.etimeSeconds)} ppid=${i.ppid} (gone)`)}let r=e.filter(us);if(r.length>0){console.log(c.warn(` ! ${r.length} MCP child${r.length===1?"":"ren"} burning CPU (likely a runaway vec0 kNN query).`));for(let i of r){let a=i.parentCommand?`parent ${i.parentCommand}`:`ppid ${i.ppid}`;console.log(c.dim(` pid ${i.pid} ${i.pcpu.toFixed(0)}%cpu ${pt(i.etimeSeconds)} elapsed (${a})`))}console.log(c.dim(" Run `recall stop --all` for one-command recovery, or `recall mcp-prune --all` to keep the daemon alive."))}let o=Qc(e);o.flagged&&o.message&&console.log(c.warn(` ! ${o.message}`))}function MT(){let e=ku(),t=Tu();if(console.log(c.dim("\u2014 Auto-prune (last 24h) \u2014")),console.log(` Mode: ${e}`),e==="off"){console.log(c.dim(" (auto-prune disabled \u2014 orphans + runaway MCPs will accumulate until manually reaped)"));return}e==="dry-run"?console.log(` Would-have-killed: ${t.wouldHaveKilled} ${c.dim("(dry-run only)")}`):(console.log(` Killed: ${t.killed} ${c.dim("(enabled)")}`),t.failed>0&&console.log(` Failed: ${c.warn(String(t.failed))} ${c.dim("(kill returned EPERM or similar)")}`));let n=t.byReason;console.log(` By reason: orphan_10min=${n.orphan_10min}, runaway_cpu_5min=${n.runaway_cpu_5min}`)}function qu(){let e=E(),t,n,s;try{t=e.prepare("SELECT * FROM migration_state WHERE status IN ('in_progress', 'paused') LIMIT 1").get(),n=e.prepare("SELECT * FROM migration_state WHERE status = 'completed' ORDER BY id DESC LIMIT 1").get(),s=e.prepare("SELECT * FROM migration_state WHERE status IN ('failed', 'rolled_back') ORDER BY id DESC LIMIT 1").get()}catch(o){let i=o instanceof Error?o.message:String(o);return i.includes("no such table: migration_state")||process.stderr.write(`[doctor] renderMigrationDoctorSection: ${i}
1021
+ `)},done:r}}function ep(e){let t=e??st(),n=t.length;if(n<=1)return{flagged:!1,severity:"ok",count:n,processes:t,message:null};let s=t.map(o=>{let i=fn(o.etimeSeconds)??o.etime;return`pid=${o.pid} started=${i} age=${pt(o.etimeSeconds)}`}),r=`${n} Recall daemons running simultaneously: ${s.join("; ")}. Two daemons write the same db.sqlite and corrupt state (chunk_queue fills, schema-sync race re-enables feature flags). Run \`recall stop\` to kill all (now nukes orphans too as of Phase 2.6), then \`recall start\`.`;return{flagged:!0,severity:"critical",count:n,processes:t,message:r}}function tp(e={}){if((e.liveDaemons??st({excludePids:[process.pid]})).length===0)return{flagged:!1,severity:"ok",daemonAlive:!1,missing:[],message:null,remediation:null};let n=e.paths??ls(),s=e.existsSync??vn,r=e.isProcessAlive??hn,o=!1;if(s(n.pid))try{let d=JSON.parse(Ti(n.pid,"utf8"));typeof d.pid=="number"&&r(d.pid)&&(o=!0)}catch{}if(!o)return{flagged:!1,severity:"ok",daemonAlive:!0,missing:[],message:null,remediation:null};let i=[];return s(n.port)||i.push("daemon.port"),s(n.token)||i.push("daemon.token"),i.length===0?{flagged:!1,severity:"ok",daemonAlive:!0,missing:[],message:null,remediation:null}:{flagged:!0,severity:"critical",daemonAlive:!0,missing:i,message:`Daemon process is alive (per pidfile) but companion state file${i.length===1?"":"s"} ${i.join(", ")} missing. Web UI and authenticated CLI calls will return 401 until the 30s heal tick restores them.`,remediation:"The 30-second heal tick re-creates these files automatically. To force immediate recovery: recall stop && recall start. Inspect ~/.recall/daemon.log for [state-files-audit] entries to identify the deletion source."}}function qT(e){e.flagged&&(console.log(""),console.log(c.dim("\u2014 Daemon state files \u2014")),console.log(c.err(` \u2717 CRITICAL: daemon process alive but missing ${e.missing.join(", ")}`)),e.remediation&&console.log(c.dim(` Remediation: ${e.remediation}`)))}function VT(e){if(e.flagged){console.log(""),console.log(c.dim("\u2014 Daemon processes \u2014")),console.log(c.err(` \u2717 CRITICAL: ${e.count} daemons running (two daemons must never run in parallel)`));for(let t of e.processes){let n=fn(t.etimeSeconds)??t.etime;console.log(` ${c.dim("\u2022")} pid ${t.pid} started ${n} age ${pt(t.etimeSeconds)} ppid=${t.ppid}`)}e.message&&console.log(c.dim(" Remediation: `recall stop` (now nukes orphans too as of Phase 2.6), then `recall start`."))}}function KT(e){if(console.log(c.dim("\u2014 MCP processes \u2014")),e.length===0){console.log(c.ok(" \u2713 no MCP children running"));return}let t=e.filter(i=>i.orphan),n=e.reduce((i,a)=>Math.max(i,a.etimeSeconds),0),s=e.length-t.length;if(console.log(` ${e.length} total, ${s} with live parent, ${t.length===0?c.ok("0 orphaned"):c.err(`${t.length} orphaned`)} (oldest ${pt(n)})`),t.length>0){console.log(c.dim(" Orphans hold a SQLite read connection and can stall WAL checkpoints. Run `recall mcp-prune` to kill them."));for(let i of t.slice(0,5))console.log(` ${c.dim("\u2022")} pid ${i.pid} age ${pt(i.etimeSeconds)} ppid=${i.ppid} (gone)`)}let r=e.filter(ps);if(r.length>0){console.log(c.warn(` ! ${r.length} MCP child${r.length===1?"":"ren"} burning CPU (likely a runaway vec0 kNN query).`));for(let i of r){let a=i.parentCommand?`parent ${i.parentCommand}`:`ppid ${i.ppid}`;console.log(c.dim(` pid ${i.pid} ${i.pcpu.toFixed(0)}%cpu ${pt(i.etimeSeconds)} elapsed (${a})`))}console.log(c.dim(" Run `recall stop --all` for one-command recovery, or `recall mcp-prune --all` to keep the daemon alive."))}let o=sl(e);o.flagged&&o.message&&console.log(c.warn(` ! ${o.message}`))}function QT(){let e=Ou(),t=Lu();if(console.log(c.dim("\u2014 Auto-prune (last 24h) \u2014")),console.log(` Mode: ${e}`),e==="off"){console.log(c.dim(" (auto-prune disabled \u2014 orphans + runaway MCPs will accumulate until manually reaped)"));return}e==="dry-run"?console.log(` Would-have-killed: ${t.wouldHaveKilled} ${c.dim("(dry-run only)")}`):(console.log(` Killed: ${t.killed} ${c.dim("(enabled)")}`),t.failed>0&&console.log(` Failed: ${c.warn(String(t.failed))} ${c.dim("(kill returned EPERM or similar)")}`));let n=t.byReason;console.log(` By reason: orphan_10min=${n.orphan_10min}, runaway_cpu_5min=${n.runaway_cpu_5min}`)}function np(){let e=h(),t,n,s;try{t=e.prepare("SELECT * FROM migration_state WHERE status IN ('in_progress', 'paused') LIMIT 1").get(),n=e.prepare("SELECT * FROM migration_state WHERE status = 'completed' ORDER BY id DESC LIMIT 1").get(),s=e.prepare("SELECT * FROM migration_state WHERE status IN ('failed', 'rolled_back') ORDER BY id DESC LIMIT 1").get()}catch(o){let i=o instanceof Error?o.message:String(o);return i.includes("no such table: migration_state")||process.stderr.write(`[doctor] renderMigrationDoctorSection: ${i}
1018
1022
  `),null}if(!t&&!n&&!s)return null;let r=["--- Migration status ---"];if(t&&(r.push(` Status: ${t.status}`),r.push(` Cursor: chunk_id=${t.cursor_chunk_id??"(none yet)"}`),r.push(` Lock pid: ${t.lock_taken_by_pid??"(released)"}`),r.push(` Old model: ${t.model_id_old}`),r.push(` New model: ${t.model_id_new}`)),n&&!t&&e.prepare("SELECT name FROM sqlite_master WHERE name='vec_chunks_v1_backup'").get()){let i=e.prepare("SELECT CAST((julianday('now') - julianday(?)) AS INTEGER) AS days").get(n.completed_at),a=Math.max(0,30-i.days);r.push(` Backup retained: ${a} day(s) until auto-prune (daemon drops it automatically).`),r.push(` Last completed: ${n.completed_at}`),r.push(` Old model: ${n.model_id_old}`),r.push(` New model: ${n.model_id_new}`)}return s&&!t&&!n&&(r.push(` ! Last migration: ${s.status}`),r.push(` Completed at: ${s.completed_at}`),r.push(` Old model: ${s.model_id_old}`),r.push(` New model: ${s.model_id_new}`),r.push(" Remediation: inspect daemon log; re-run `recall semantic migrate` to retry")),r.join(`
1019
- `)}function DT(){let e=E();return e.prepare("SELECT name FROM sqlite_master WHERE name='vec_chunks_v1_backup'").get()?e.prepare("SELECT COUNT(*) AS n FROM vec_chunks_v1_backup b LEFT JOIN chunk_meta cm ON cm.rowid = b.rowid WHERE cm.rowid IS NULL").get().n:0}function Vu(){let e=E(),t=e.prepare("SELECT encoded_path FROM projects").all(),n=new Set(t.map(l=>l.encoded_path));if(n.size===0)return{status:"ok",staleCount:0,scanned:0,sampleFiles:[],message:"Ingest freshness: ok (no projects indexed yet \u2014 nothing to monitor)."};let s=e.prepare("SELECT file_mtime, skipped_reason FROM sessions WHERE file_path = ? LIMIT 1"),r=0,o=0,i=[];for(let l of gi(Ft)){if(hu(l))continue;let u=_u(l);if(!u||!n.has(u))continue;r+=1;let m;try{m=Qs(l).mtimeMs}catch{continue}let p=s.get(l);p&&p.skipped_reason!==null||(!p||p.file_mtime<m)&&(o+=1,i.length<5&&i.push(l))}if(o===0)return{status:"ok",staleCount:0,scanned:r,sampleFiles:[],message:`Ingest freshness: ok (scanned ${r} JSONL${r===1?"":"s"} in ${n.size} known project${n.size===1?"":"s"}, none newer than the index).`};let a=o>10?"fail":"warn",d=i.slice(0,3).map(l=>l.split(/[/\\]/).pop()??l).join(", ");return{status:a,staleCount:o,scanned:r,sampleFiles:i,message:`Ingest freshness: ${a} \u2014 ${o} JSONL${o===1?"":" files"} newer than the index (sample: ${d}). Run \`recall index\` to force a reindex, or restart the daemon if this is persistent.`}}function Ku(e=Zs(yT(),".claude.json")){let t={status:"ok",configPath:e,configExists:On(e),findings:[]};if(!t.configExists)return t;let n;try{n=Ei(e,"utf8")}catch{return t}let s;try{s=JSON.parse(n)}catch{return t}if(!s||typeof s!="object"||Array.isArray(s))return t;let r=s.mcpServers;if(!r||typeof r!="object"||Array.isArray(r))return t;for(let[o,i]of Object.entries(r)){if(!i||typeof i!="object")continue;let a=i.args;if(!Array.isArray(a)||a.length===0)continue;let d=a[0];if(typeof d!="string"||d.length===0||!d.startsWith("/")&&!d.startsWith("~")||On(d))continue;let l=o==="recall";t.findings.push({name:o,stalePath:d,severity:l?"HIGH":"MEDIUM",remediation:l?"restart daemon (`recall stop && recall start`) \u2014 auto-repoint runs on boot now":"this is a third-party MCP \u2014 the vendor's package may have moved; reinstall their package"})}return t.findings.some(o=>o.severity==="HIGH")?t.status="fail":t.findings.length>0&&(t.status="warn"),t}function Qu(){let e=null;try{e=we().enabled}catch{return{status:"ok",configEnabled:null,dbValue:null,message:null}}let t=null;try{t=E().prepare("SELECT value FROM app_settings WHERE key = 'semantic_enabled'").get()?.value??null}catch{return{status:"ok",configEnabled:e,dbValue:null,message:null}}if(t===null)return{status:"ok",configEnabled:e,dbValue:null,message:null};if(t==="1"===e)return{status:"ok",configEnabled:e,dbValue:t,message:null};let s=`config.json says ${String(e)} but DB gate says ${t}. Recover with \`recall stop && recall start\` (boot sync re-reads config). If this recurs, grep daemon.log for \`[semantic-config] gate flip\` to identify the runtime flipper.`;return{status:"critical",configEnabled:e,dbValue:t,message:s}}function $T(e,t){let n=Ks(),{file:s,result:r}=Ou(n,e);if((r.outcome==="acknowledged"||r.outcome==="already-acknowledged")&&s!==n&&Nu(s),t.json){let o=r.outcome==="acknowledged"||r.outcome==="already-acknowledged"?{outcome:r.outcome,id:r.matched?.id,check:r.matched?.check,message:r.matched?.message}:{outcome:r.outcome,candidates:r.candidates??[]};process.stdout.write(`${JSON.stringify(o)}
1020
- `)}else switch(r.outcome){case"acknowledged":console.log(`acknowledged: ${r.matched?.message??"(no message)"}`);break;case"already-acknowledged":console.log(`already acknowledged: ${r.matched?.message??"(no message)"}`);break;case"not-found":console.log(`no alert matched "${e}". Run \`recall doctor\` to list current alerts.`);break;case"ambiguous":console.log(`"${e}" matched ${r.candidates?.length??0} alerts \u2014 use a longer prefix:`);for(let o of r.candidates??[])console.log(` ${o}`);break}return r.outcome==="not-found"||r.outcome==="ambiguous"?1:0}async function Si(e={}){if(typeof e.ack=="string"&&e.ack.length>0)return $T(e.ack,{json:!!e.json});let t=NT(!e.json);t.stage("Scanning session aliases");let n=E().prepare(`SELECT sa.session_id AS session_id, sa.alias AS alias, s.cwd AS cwd
1023
+ `)}function ZT(){let e=h();return e.prepare("SELECT name FROM sqlite_master WHERE name='vec_chunks_v1_backup'").get()?e.prepare("SELECT COUNT(*) AS n FROM vec_chunks_v1_backup b LEFT JOIN chunk_meta cm ON cm.rowid = b.rowid WHERE cm.rowid IS NULL").get().n:0}function sp(){let e=h();return On({listTableNames(){return e.prepare("SELECT name FROM sqlite_master WHERE type = 'table'").all().map(n=>n.name)},countRows(n){if(!/^[A-Za-z_][A-Za-z0-9_]*$/.test(n))return 0;try{return e.prepare(`SELECT COUNT(*) AS n FROM "${n}"`).get().n}catch{return 0}},isRollbackWindowOpen(){try{return!!e.prepare("SELECT 1 AS x FROM migration_state WHERE status = 'completed' AND completed_at > datetime('now', '-30 days') ORDER BY id DESC LIMIT 1").get()}catch{return!1}},rollbackDaysRemaining(){try{let n=e.prepare("SELECT completed_at FROM migration_state WHERE status = 'completed' ORDER BY id DESC LIMIT 1").get();if(!n)return null;let s=e.prepare("SELECT CAST((julianday('now') - julianday(?)) AS INTEGER) AS days").get(n.completed_at);return Math.max(0,30-s.days)}catch{return null}}})}function rp(){let e;try{e=sp()}catch(t){let n=t instanceof Error?t.message:String(t);return process.stderr.write(`[doctor] renderInDbBloatDoctorSection: ${n}
1024
+ `),null}return ju(e,{dim:c.dim,warn:c.warn})}function op(){let e=h(),t=e.prepare("SELECT encoded_path FROM projects").all(),n=new Set(t.map(l=>l.encoded_path));if(n.size===0)return{status:"ok",staleCount:0,scanned:0,sampleFiles:[],message:"Ingest freshness: ok (no projects indexed yet \u2014 nothing to monitor)."};let s=e.prepare("SELECT file_mtime, skipped_reason FROM sessions WHERE file_path = ? LIMIT 1"),r=0,o=0,i=[];for(let l of _i(Ft)){if(Tu(l))continue;let u=wu(l);if(!u||!n.has(u))continue;r+=1;let m;try{m=er(l).mtimeMs}catch{continue}let p=s.get(l);p&&p.skipped_reason!==null||(!p||p.file_mtime<m)&&(o+=1,i.length<5&&i.push(l))}if(o===0)return{status:"ok",staleCount:0,scanned:r,sampleFiles:[],message:`Ingest freshness: ok (scanned ${r} JSONL${r===1?"":"s"} in ${n.size} known project${n.size===1?"":"s"}, none newer than the index).`};let a=o>10?"fail":"warn",d=i.slice(0,3).map(l=>l.split(/[/\\]/).pop()??l).join(", ");return{status:a,staleCount:o,scanned:r,sampleFiles:i,message:`Ingest freshness: ${a} \u2014 ${o} JSONL${o===1?"":" files"} newer than the index (sample: ${d}). Run \`recall index\` to force a reindex, or restart the daemon if this is persistent.`}}function ip(e=tr(jT(),".claude.json")){let t={status:"ok",configPath:e,configExists:vn(e),findings:[]};if(!t.configExists)return t;let n;try{n=Ti(e,"utf8")}catch{return t}let s;try{s=JSON.parse(n)}catch{return t}if(!s||typeof s!="object"||Array.isArray(s))return t;let r=s.mcpServers;if(!r||typeof r!="object"||Array.isArray(r))return t;for(let[o,i]of Object.entries(r)){if(!i||typeof i!="object")continue;let a=i.args;if(!Array.isArray(a)||a.length===0)continue;let d=a[0];if(typeof d!="string"||d.length===0||!d.startsWith("/")&&!d.startsWith("~")||vn(d))continue;let l=o==="recall";t.findings.push({name:o,stalePath:d,severity:l?"HIGH":"MEDIUM",remediation:l?"restart daemon (`recall stop && recall start`) \u2014 auto-repoint runs on boot now":"this is a third-party MCP \u2014 the vendor's package may have moved; reinstall their package"})}return t.findings.some(o=>o.severity==="HIGH")?t.status="fail":t.findings.length>0&&(t.status="warn"),t}function ap(){let e=null;try{e=we().enabled}catch{return{status:"ok",configEnabled:null,dbValue:null,message:null}}let t=null;try{t=h().prepare("SELECT value FROM app_settings WHERE key = 'semantic_enabled'").get()?.value??null}catch{return{status:"ok",configEnabled:e,dbValue:null,message:null}}if(t===null)return{status:"ok",configEnabled:e,dbValue:null,message:null};if(t==="1"===e)return{status:"ok",configEnabled:e,dbValue:t,message:null};let s=`config.json says ${String(e)} but DB gate says ${t}. Recover with \`recall stop && recall start\` (boot sync re-reads config). If this recurs, grep daemon.log for \`[semantic-config] gate flip\` to identify the runtime flipper.`;return{status:"critical",configEnabled:e,dbValue:t,message:s}}function eR(e,t){let n=Qs(),{file:s,result:r}=Pu(n,e);if((r.outcome==="acknowledged"||r.outcome==="already-acknowledged")&&s!==n&&$u(s),t.json){let o=r.outcome==="acknowledged"||r.outcome==="already-acknowledged"?{outcome:r.outcome,id:r.matched?.id,check:r.matched?.check,message:r.matched?.message}:{outcome:r.outcome,candidates:r.candidates??[]};process.stdout.write(`${JSON.stringify(o)}
1025
+ `)}else switch(r.outcome){case"acknowledged":console.log(`acknowledged: ${r.matched?.message??"(no message)"}`);break;case"already-acknowledged":console.log(`already acknowledged: ${r.matched?.message??"(no message)"}`);break;case"not-found":console.log(`no alert matched "${e}". Run \`recall doctor\` to list current alerts.`);break;case"ambiguous":console.log(`"${e}" matched ${r.candidates?.length??0} alerts \u2014 use a longer prefix:`);for(let o of r.candidates??[])console.log(` ${o}`);break}return r.outcome==="not-found"||r.outcome==="ambiguous"?1:0}async function ki(e={}){if(typeof e.ack=="string"&&e.ack.length>0)return eR(e.ack,{json:!!e.json});let t=YT(!e.json);t.stage("Scanning session aliases");let n=h().prepare(`SELECT sa.session_id AS session_id, sa.alias AS alias, s.cwd AS cwd
1021
1026
  FROM session_aliases sa
1022
1027
  LEFT JOIN sessions s ON s.id = sa.session_id
1023
- WHERE sa.alias IS NOT NULL AND sa.alias != ''`).all(),s=RT(n);t.stage("Probing daemon");let r=await Wu(),o=zu(t.stage);t.stage("Detecting label collisions");let i=Gu();t.stage("Checking ingest freshness");let a=Vu();t.stage("Checking ~/.claude.json MCP paths");let d=Ku();t.stage("Checking semantic gate drift");let l=Qu();t.stage("Sampling chunk_queue growth");let u=fi();t.stage("Scanning for sibling daemons");let m=Ju();t.stage("Checking daemon state files");let p=Yu({liveDaemons:m.processes});if(t.done(),e.json){process.stdout.write(JSON.stringify({scanned:n.length,violations:s.length,items:s,health:o,pipeline:r,labelCollisions:i,ingestFreshness:a,staleMcpEntries:d,semanticGateDrift:l,chunkQueueGrowth:u,siblingDaemons:m,daemonStateFiles:p},null,2)),process.stdout.write(`
1024
- `);let _=r.state==="degraded",b=a.status==="fail",S=d.status==="fail",y=u.status==="critical",T=m.flagged,R=p.flagged,B=l.status==="critical";return s.length===0&&o.db.integrity==="ok"&&!_&&!b&&!S&&!y&&!T&&!B&&!R?0:1}console.log(c.dim("\u2014 System health \u2014")),console.log(` Database ${ce(o.db.sizeBytes)} (${o.rows.messages.toLocaleString()} messages across ${o.rows.sessions.toLocaleString()} sessions, ${o.rows.projects.toLocaleString()} projects)`);{let _=o.wal,b=_.level==="error"?c.err(ce(_.sizeBytes)):_.level==="warn"?c.warn(ce(_.sizeBytes)):c.ok(ce(_.sizeBytes)),S=_.level==="error"?" (readers are pinning the checkpoint frontier \u2014 see warnings below)":_.level==="warn"?" (above 100 MB \u2014 daemon will WARN until it drops)":" (daemon checkpoints PASSIVE every 60s, RESTART above 5 GB)";console.log(` WAL ${b}${S}`)}console.log(` Free pages ${o.db.freelistCount.toLocaleString()} (${ce(o.db.freelistBytes)} reclaimable via VACUUM)`);{let _=o.fts.messages.fragments,b=o.fts.sessions.fragments,S=_===0&&b===0;console.log(` FTS segments messages=${_}, sessions=${b}`+(S?" (merged \u2014 search uses the index)":" (lower is faster \u2014 `recall optimize` merges them)"))}if(o.chunkQueue.size>0){let b=o.chunkQueue.size>1e5?c.warn(o.chunkQueue.size.toLocaleString()):o.chunkQueue.size.toLocaleString();console.log(` Embed queue ${b}`+(o.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 ${o.vectors.rows.toLocaleString()}`),o.disk.totalBytes>0){let _=o.disk.freeBytes/o.disk.totalBytes*100,b=o.disk.backups.severity,S=`${_.toFixed(1)}%`,y=b==="high"?c.err(S):b==="medium"?c.warn(S):c.ok(S);console.log(` Disk free ${ce(o.disk.freeBytes)} of ${ce(o.disk.totalBytes)} (${y})`)}if(o.disk.backups.fileCount>0){let _=o.disk.backups,b=ce(_.totalBytes),S=_.severity==="high"?c.err(b):_.severity==="medium"?c.warn(b):b;console.log(` Snapshot files ${S} across ${_.fileCount} file${_.fileCount===1?"":"s"} in ~/.recall/`+(_.oldFiles.length>0?` (${_.oldFiles.length} older than 30 days)`:" (all recent \u2014 likely rollback-critical)"))}if(console.log(` Integrity ${o.db.integrity==="ok"?c.ok("ok"):c.err(o.db.integrity)}`),o.warnings.length>0){console.log("");for(let _ of o.warnings)console.log(` ${c.warn("!")} ${_}`)}console.log(""),vT(m),OT(p),IT(o.mcpProcesses),console.log(""),MT();let g=qu();if(g!==null&&(console.log(""),console.log(g)),console.log(""),console.log(c.dim("\u2014 Ingest freshness \u2014")),a.status==="ok")console.log(c.ok(` \u2713 ${a.scanned.toLocaleString()} JSONL${a.scanned===1?"":"s"} scanned, none newer than the index`));else if(a.status==="warn"){console.log(` ${c.warn(`${a.staleCount} stale file${a.staleCount===1?"":"s"}`)} newer than the index \u2014 live watcher may be missing events`);for(let _ of a.sampleFiles.slice(0,5))console.log(` ${c.dim("\u2022")} ${_}`);console.log(c.dim(" Run `recall index` to force a reindex, or restart the daemon if persistent."))}else{console.log(` ${c.err(`${a.staleCount} stale file${a.staleCount===1?"":"s"}`)} newer than the index \u2014 significant ingest gap`);for(let _ of a.sampleFiles.slice(0,5))console.log(` ${c.dim("\u2022")} ${_}`);console.log(c.err(" Restart the daemon (recall stop && recall start) \u2014 the live watcher has fallen behind."))}console.log(""),console.log(c.dim("\u2014 chunk_queue growth \u2014"));{let _=u,b=_.status,S=_.currentSize.toLocaleString(),y=_.lastHourGrowth!==null?`\u0394 ${_.lastHourGrowth>=0?"+":""}${_.lastHourGrowth.toLocaleString()}/h`:"no prior sample in last hour",T=_.semanticEnabled?c.dim("semantic=on"):c.dim("semantic=off");b==="ok"?console.log(c.ok(` \u2713 ${S} rows, ${y}`)+` ${T}`+c.dim(` (${_.priorSampleCount} prior sample${_.priorSampleCount===1?"":"s"} in last hour)`)):b==="critical"?(console.log(` ${c.err("CRITICAL")} ${S} rows, ${y} ${T}`),_.remediation&&console.log(c.dim(` ${_.remediation}`))):b==="high"?(console.log(` ${c.warn("HIGH")} ${S} rows, ${y} ${T}`),_.remediation&&console.log(c.dim(` ${_.remediation}`))):(console.log(` ${c.warn("MEDIUM")} ${S} rows, ${y} ${T}`),_.remediation&&console.log(c.dim(` ${_.remediation}`)))}if(console.log(""),console.log(c.dim("\u2014 ~/.claude.json MCP paths \u2014")),!d.configExists)console.log(c.dim(" (no ~/.claude.json on disk \u2014 skipped)"));else if(d.findings.length===0)console.log(c.ok(" \u2713 all MCP server script paths exist on disk"));else{let _=d.findings.filter(S=>S.severity==="HIGH"),b=d.findings.filter(S=>S.severity==="MEDIUM");if(_.length>0){console.log(` ${c.err(`${_.length} stale entry`)}${_.length===1?"":" (HIGH)"} that we own:`);for(let S of _)console.log(` ${c.err("\u2717")} ${S.name} ${c.dim("\u2192")} ${S.stalePath}`),console.log(` ${c.dim("Remediation:")} ${S.remediation}`)}if(b.length>0){console.log(` ${c.warn(`${b.length} third-party stale entr${b.length===1?"y":"ies"}`)} (MEDIUM):`);for(let S of b)console.log(` ${c.warn("!")} ${S.name} ${c.dim("\u2192")} ${S.stalePath}`),console.log(` ${c.dim("Remediation:")} ${S.remediation}`)}}if(console.log(""),console.log(c.dim("\u2014 Semantic gate drift \u2014")),l.status==="ok"?l.configEnabled!==null&&l.dbValue!==null?console.log(c.ok(` \u2713 config.json + DB gate agree (semantic.enabled=${String(l.configEnabled)}, gate=${l.dbValue})`)):console.log(c.dim(" (no gate row to compare \u2014 skipped)")):(console.log(` ${c.err("CRITICAL")} config.json semantic.enabled=${String(l.configEnabled)} but DB gate=${l.dbValue}`),l.message&&console.log(c.dim(` ${l.message}`))),console.log(""),console.log(c.dim("\u2014 Pipeline health (tab-name \u2192 session alias) \u2014")),r.daemon.running?console.log(` Daemon ${c.ok("running")} (port ${r.daemon.port}, version ${r.daemon.version??"?"}, up ${r.daemon.uptimeSeconds!==null?Math.round(r.daemon.uptimeSeconds/60)+" min":"?"})`):console.log(` Daemon ${c.warn("not reachable")}`),r.runtime.silentTerminalRejections!==null){let _=r.runtime.silentTerminalRejections;console.log(` Auth rejections ${_===0?c.ok("0"):c.err(_.toLocaleString())} (extension /api/terminal/* requests denied without a valid X-Recall-Token)`)}if(r.runtime.autoExtract){let _=r.runtime.autoExtract;_.circuitBroken?console.log(` Auto-extract ${c.err("circuit broken")} (${_.reason??"unknown"} \u2014 toggle off/on to reset)`):_.consecutiveZeroTokenRuns>0&&console.log(` Auto-extract ${c.warn(`${_.consecutiveZeroTokenRuns} zero-token run(s)`)} (breaker trips at 3)`)}if(r.runtime.lastTerminalSyncAt!==null){let _=Date.now()-Date.parse(r.runtime.lastTerminalSyncAt),b=Number.isFinite(_)?Math.round(_/6e4):null,S=b!==null&&_>Bu;console.log(` Last ext sync ${S?c.warn(`${b} min ago`):c.ok(b===0?"just now":`${b} min ago`)} (most recent successful POST /api/terminal/sync)`)}else r.daemon.running&&console.log(` Last ext sync ${c.warn("never")} (no extension has called /api/terminal/sync since the daemon started)`);if(r.terminalsJson.exists&&r.terminalsJson.ageSeconds!==null){let _=Math.round(r.terminalsJson.ageSeconds/3600),b=r.terminalsJson.ageSeconds>24*3600;console.log(` terminals.json ${b?c.warn(`${_}h old`):c.ok(`${_}h old`)} (persisted registry mtime \u2014 fresh means extensions are connecting)`)}let f=r.recentSessions;if(f.total>0){let _=Math.round(f.fractionHeuristic*100),b=f.fractionHeuristic>=Hu&&f.total>=3;console.log(` Recent titles ${b?c.err(`${_}% heuristic`):c.ok(`${_}% heuristic`)} (${f.heuristicOnly}/${f.total} sessions in last ${bi}h fell back to first-message title)`)}if(r.flags.length>0){console.log("");for(let _ of r.flags)console.log(` ${c.warn("!")} ${_}`)}if(console.log(""),console.log(c.dim("\u2014 Label collisions (last 7d) \u2014")),i.length===0)console.log(c.ok(" \u2713 no session-list label collisions in the last week"));else{let _=i.filter(b=>!b.anyAliased);console.log(` ${c.warn(`${i.length} group(s)`)} of 2+ sessions in the same project share an identical display label \u2014 N parallel runs ended up with the same heuristic title.`);for(let b of i.slice(0,5)){let S=b.anyAliased?c.dim("partial alias"):c.warn("NO alias"),y=b.label.length>60?`${b.label.slice(0,57)}\u2026`:b.label;console.log(` ${c.dim(`${b.count}\xD7`)} ${y} ${S} ${c.dim(`(${b.project})`)}`)}i.length>5&&console.log(c.dim(` \u2026 and ${i.length-5} more (--json for full list)`)),console.log(""),console.log(c.dim(" The display layer auto-disambiguates these (HH:MM / msgs / UUID suffix), so customers\n never see two identical rows. To fix at the source \u2014 when spawning `claude -p` from\n a script or Captain-Code subordinate, prepend each prompt with:")),console.log(c.dim(" <!-- claude-recall-alias: T1.3 \u2014 Auth Refactor -->")),console.log(c.dim(` The watcher will read the header, alias the session, and strip the marker from the
1025
- displayed first user message. See https://clauderecall.com/docs \u2192 "Alias header convention".`)),_.length>0&&(console.log(""),console.log(c.warn(` ${_.length} of these groups have NO alias on any row \u2014 strongest candidates
1026
- for the header-alias fix above.`)))}if(console.log(""),console.log(c.dim("\u2014 Tab-name invariant \u2014")),s.length===0)return console.log(c.ok(` \u2713 holds across ${n.length.toLocaleString()} aliased session${n.length===1?"":"s"}`)),console.log(c.dim(" No fabricated origin labels (`VS Code \xB7 cwd \xB7 branch`) found. No deprecated cwd-branch synthesis found.")),o.db.integrity==="ok"&&a.status!=="fail"&&d.status!=="fail"&&u.status!=="critical"&&!m.flagged&&l.status!=="critical"&&!p.flagged?0:1;console.log(c.err(`\u2717 ${s.length} invariant violation${s.length===1?"":"s"} found across ${n.length.toLocaleString()} aliased sessions`)),console.log("");let h=new Map;for(let _ of s){let b=h.get(_.violation)??[];b.push(_),h.set(_.violation,b)}for(let[_,b]of h){console.log(c.warn(` ${_} (${b.length})`));for(let S of b.slice(0,10))console.log(` ${S.session_id.slice(0,8)} ${c.dim("\u2192")} ${JSON.stringify(S.alias)}`);b.length>10&&console.log(c.dim(` \u2026 and ${b.length-10} more (rerun with --json for the full list)`)),console.log("")}return console.log(c.dim('Remediation: `recall name <id-prefix> ""` clears a bad alias so the heuristic title takes over,\nor `recall name <id-prefix> "<actual tab name>"` sets it to the real value.')),1}function PT(){try{let e=Pu(C);return Number(e.bavail)*Number(e.bsize)}catch{return 0}}var wT,TT,ju,Bu,bi,Hu,Mu,yi=w(()=>{"use strict";$();k();Yn();I();Eu();En();_n();Xe();gs();ps();_i();xu();hi();Sn();wT=["VS Code","VS Code Insiders","Cursor","Windsurf","Warp","iTerm","Terminal","WezTerm","Windows Terminal","Kitty","Alacritty"],TT=new RegExp(`^(${wT.map(e=>e.replace(/ /g,"\\s")).join("|")})\\s\xB7\\s`);ju=50;Bu=5*6e4,bi=24,Hu=.5;Mu=5e3});import{writeFileSync as mp,readFileSync as G1,existsSync as gp,mkdirSync as fp,readdirSync as z1}from"node:fs";import{join as nr}from"node:path";function TR(){j(),gp(Ci)||fp(Ci,{recursive:!0})}function RR(){j(),gp(Li)||fp(Li,{recursive:!0})}function _p(e){try{return JSON.parse(e)}catch{return e}}function Ai(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:_p(e.evidence),approved:e.approved===1,created_at:e.created_at,updated_at:e.updated_at}}function Ni(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:_p(e.evidence),status:e.status,inferred_by:e.inferred_by,created_at:e.created_at,decided_at:e.decided_at}}function kR(e){if(!Number.isFinite(e)||e<0||e>1)throw new Error("confidence must be a number in [0, 1]")}function hp(e){if(!ER.has(e))throw new Error(`invalid link_type: ${e}`)}function Ep(e){if(!yR.has(e))throw new Error(`invalid inferred_by: ${e}`)}function xR(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 CR(e={}){let t=E(),n=[],s=[];e.sourceSessionId&&(n.push("source_session_id = ?"),s.push(e.sourceSessionId)),e.targetSessionId&&(n.push("target_session_id = ?"),s.push(e.targetSessionId)),e.linkType&&(hp(e.linkType),n.push("link_type = ?"),s.push(e.linkType)),e.approvedOnly&&n.push("approved = 1");let r=n.length?`WHERE ${n.join(" AND ")}`:"",o=Math.max(1,Math.min(5e3,e.limit??1e3));return t.prepare(`SELECT * FROM session_links ${r}
1028
+ WHERE sa.alias IS NOT NULL AND sa.alias != ''`).all(),s=HT(n);t.stage("Probing daemon");let r=await Vu(),o=Zu(t.stage);t.stage("Detecting label collisions");let i=Qu();t.stage("Checking ingest freshness");let a=op();t.stage("Checking ~/.claude.json MCP paths");let d=ip();t.stage("Checking semantic gate drift");let l=ap();t.stage("Sampling chunk_queue growth");let u=hi();t.stage("Scanning for sibling daemons");let m=ep();t.stage("Checking daemon state files");let p=tp({liveDaemons:m.processes});if(t.done(),e.json){process.stdout.write(JSON.stringify({scanned:n.length,violations:s.length,items:s,health:o,pipeline:r,labelCollisions:i,ingestFreshness:a,staleMcpEntries:d,semanticGateDrift:l,chunkQueueGrowth:u,siblingDaemons:m,daemonStateFiles:p},null,2)),process.stdout.write(`
1029
+ `);let E=r.state==="degraded",S=a.status==="fail",y=d.status==="fail",T=u.status==="critical",R=m.flagged,B=p.flagged,A=l.status==="critical";return s.length===0&&o.db.integrity==="ok"&&!E&&!S&&!y&&!T&&!R&&!A&&!B?0:1}console.log(c.dim("\u2014 System health \u2014")),console.log(` Database ${ce(o.db.sizeBytes)} (${o.rows.messages.toLocaleString()} messages across ${o.rows.sessions.toLocaleString()} sessions, ${o.rows.projects.toLocaleString()} projects)`);{let E=o.wal,S=E.level==="error"?c.err(ce(E.sizeBytes)):E.level==="warn"?c.warn(ce(E.sizeBytes)):c.ok(ce(E.sizeBytes)),y=E.level==="error"?" (readers are pinning the checkpoint frontier \u2014 see warnings below)":E.level==="warn"?" (above 100 MB \u2014 daemon will WARN until it drops)":" (daemon checkpoints PASSIVE every 60s, RESTART above 5 GB)";console.log(` WAL ${S}${y}`)}console.log(` Free pages ${o.db.freelistCount.toLocaleString()} (${ce(o.db.freelistBytes)} reclaimable via VACUUM)`);{let E=o.fts.messages.fragments,S=o.fts.sessions.fragments,y=E===0&&S===0;console.log(` FTS segments messages=${E}, sessions=${S}`+(y?" (merged \u2014 search uses the index)":" (lower is faster \u2014 `recall optimize` merges them)"))}if(o.chunkQueue.size>0){let S=o.chunkQueue.size>1e5?c.warn(o.chunkQueue.size.toLocaleString()):o.chunkQueue.size.toLocaleString();console.log(` Embed queue ${S}`+(o.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 ${o.vectors.rows.toLocaleString()}`),o.disk.totalBytes>0){let E=o.disk.freeBytes/o.disk.totalBytes*100,S=o.disk.backups.severity,y=`${E.toFixed(1)}%`,T=S==="high"?c.err(y):S==="medium"?c.warn(y):c.ok(y);console.log(` Disk free ${ce(o.disk.freeBytes)} of ${ce(o.disk.totalBytes)} (${T})`)}if(o.disk.backups.fileCount>0){let E=o.disk.backups,S=ce(E.totalBytes),y=E.severity==="high"?c.err(S):E.severity==="medium"?c.warn(S):S;console.log(` Snapshot files ${y} across ${E.fileCount} file${E.fileCount===1?"":"s"} in ~/.recall/`+(E.oldFiles.length>0?` (${E.oldFiles.length} older than 30 days)`:" (all recent \u2014 likely rollback-critical)"))}if(console.log(` Integrity ${o.db.integrity==="ok"?c.ok("ok"):c.err(o.db.integrity)}`),o.warnings.length>0){console.log("");for(let E of o.warnings)console.log(` ${c.warn("!")} ${E}`)}console.log(""),VT(m),qT(p),KT(o.mcpProcesses),console.log(""),QT();let g=np();g!==null&&(console.log(""),console.log(g));let f=rp();if(f!==null&&(console.log(""),console.log(f)),console.log(""),console.log(c.dim("\u2014 Ingest freshness \u2014")),a.status==="ok")console.log(c.ok(` \u2713 ${a.scanned.toLocaleString()} JSONL${a.scanned===1?"":"s"} scanned, none newer than the index`));else if(a.status==="warn"){console.log(` ${c.warn(`${a.staleCount} stale file${a.staleCount===1?"":"s"}`)} newer than the index \u2014 live watcher may be missing events`);for(let E of a.sampleFiles.slice(0,5))console.log(` ${c.dim("\u2022")} ${E}`);console.log(c.dim(" Run `recall index` to force a reindex, or restart the daemon if persistent."))}else{console.log(` ${c.err(`${a.staleCount} stale file${a.staleCount===1?"":"s"}`)} newer than the index \u2014 significant ingest gap`);for(let E of a.sampleFiles.slice(0,5))console.log(` ${c.dim("\u2022")} ${E}`);console.log(c.err(" Restart the daemon (recall stop && recall start) \u2014 the live watcher has fallen behind."))}console.log(""),console.log(c.dim("\u2014 chunk_queue growth \u2014"));{let E=u,S=E.status,y=E.currentSize.toLocaleString(),T=E.lastHourGrowth!==null?`\u0394 ${E.lastHourGrowth>=0?"+":""}${E.lastHourGrowth.toLocaleString()}/h`:"no prior sample in last hour",R=E.semanticEnabled?c.dim("semantic=on"):c.dim("semantic=off");S==="ok"?console.log(c.ok(` \u2713 ${y} rows, ${T}`)+` ${R}`+c.dim(` (${E.priorSampleCount} prior sample${E.priorSampleCount===1?"":"s"} in last hour)`)):S==="critical"?(console.log(` ${c.err("CRITICAL")} ${y} rows, ${T} ${R}`),E.remediation&&console.log(c.dim(` ${E.remediation}`))):S==="high"?(console.log(` ${c.warn("HIGH")} ${y} rows, ${T} ${R}`),E.remediation&&console.log(c.dim(` ${E.remediation}`))):(console.log(` ${c.warn("MEDIUM")} ${y} rows, ${T} ${R}`),E.remediation&&console.log(c.dim(` ${E.remediation}`)))}if(console.log(""),console.log(c.dim("\u2014 ~/.claude.json MCP paths \u2014")),!d.configExists)console.log(c.dim(" (no ~/.claude.json on disk \u2014 skipped)"));else if(d.findings.length===0)console.log(c.ok(" \u2713 all MCP server script paths exist on disk"));else{let E=d.findings.filter(y=>y.severity==="HIGH"),S=d.findings.filter(y=>y.severity==="MEDIUM");if(E.length>0){console.log(` ${c.err(`${E.length} stale entry`)}${E.length===1?"":" (HIGH)"} that we own:`);for(let y of E)console.log(` ${c.err("\u2717")} ${y.name} ${c.dim("\u2192")} ${y.stalePath}`),console.log(` ${c.dim("Remediation:")} ${y.remediation}`)}if(S.length>0){console.log(` ${c.warn(`${S.length} third-party stale entr${S.length===1?"y":"ies"}`)} (MEDIUM):`);for(let y of S)console.log(` ${c.warn("!")} ${y.name} ${c.dim("\u2192")} ${y.stalePath}`),console.log(` ${c.dim("Remediation:")} ${y.remediation}`)}}if(console.log(""),console.log(c.dim("\u2014 Semantic gate drift \u2014")),l.status==="ok"?l.configEnabled!==null&&l.dbValue!==null?console.log(c.ok(` \u2713 config.json + DB gate agree (semantic.enabled=${String(l.configEnabled)}, gate=${l.dbValue})`)):console.log(c.dim(" (no gate row to compare \u2014 skipped)")):(console.log(` ${c.err("CRITICAL")} config.json semantic.enabled=${String(l.configEnabled)} but DB gate=${l.dbValue}`),l.message&&console.log(c.dim(` ${l.message}`))),console.log(""),console.log(c.dim("\u2014 Pipeline health (tab-name \u2192 session alias) \u2014")),r.daemon.running?console.log(` Daemon ${c.ok("running")} (port ${r.daemon.port}, version ${r.daemon.version??"?"}, up ${r.daemon.uptimeSeconds!==null?Math.round(r.daemon.uptimeSeconds/60)+" min":"?"})`):console.log(` Daemon ${c.warn("not reachable")}`),r.runtime.silentTerminalRejections!==null){let E=r.runtime.silentTerminalRejections;console.log(` Auth rejections ${E===0?c.ok("0"):c.err(E.toLocaleString())} (extension /api/terminal/* requests denied without a valid X-Recall-Token)`)}if(r.runtime.autoExtract){let E=r.runtime.autoExtract;E.circuitBroken?console.log(` Auto-extract ${c.err("circuit broken")} (${E.reason??"unknown"} \u2014 toggle off/on to reset)`):E.consecutiveZeroTokenRuns>0&&console.log(` Auto-extract ${c.warn(`${E.consecutiveZeroTokenRuns} zero-token run(s)`)} (breaker trips at 3)`)}if(r.runtime.lastTerminalSyncAt!==null){let E=Date.now()-Date.parse(r.runtime.lastTerminalSyncAt),S=Number.isFinite(E)?Math.round(E/6e4):null,y=S!==null&&E>Yu;console.log(` Last ext sync ${y?c.warn(`${S} min ago`):c.ok(S===0?"just now":`${S} min ago`)} (most recent successful POST /api/terminal/sync)`)}else r.daemon.running&&console.log(` Last ext sync ${c.warn("never")} (no extension has called /api/terminal/sync since the daemon started)`);if(r.terminalsJson.exists&&r.terminalsJson.ageSeconds!==null){let E=Math.round(r.terminalsJson.ageSeconds/3600),S=r.terminalsJson.ageSeconds>24*3600;console.log(` terminals.json ${S?c.warn(`${E}h old`):c.ok(`${E}h old`)} (persisted registry mtime \u2014 fresh means extensions are connecting)`)}let _=r.recentSessions;if(_.total>0){let E=Math.round(_.fractionHeuristic*100),S=_.fractionHeuristic>=qu&&_.total>=3;console.log(` Recent titles ${S?c.err(`${E}% heuristic`):c.ok(`${E}% heuristic`)} (${_.heuristicOnly}/${_.total} sessions in last ${Ri}h fell back to first-message title)`)}if(r.flags.length>0){console.log("");for(let E of r.flags)console.log(` ${c.warn("!")} ${E}`)}if(console.log(""),console.log(c.dim("\u2014 Label collisions (last 7d) \u2014")),i.length===0)console.log(c.ok(" \u2713 no session-list label collisions in the last week"));else{let E=i.filter(S=>!S.anyAliased);console.log(` ${c.warn(`${i.length} group(s)`)} of 2+ sessions in the same project share an identical display label \u2014 N parallel runs ended up with the same heuristic title.`);for(let S of i.slice(0,5)){let y=S.anyAliased?c.dim("partial alias"):c.warn("NO alias"),T=S.label.length>60?`${S.label.slice(0,57)}\u2026`:S.label;console.log(` ${c.dim(`${S.count}\xD7`)} ${T} ${y} ${c.dim(`(${S.project})`)}`)}i.length>5&&console.log(c.dim(` \u2026 and ${i.length-5} more (--json for full list)`)),console.log(""),console.log(c.dim(" The display layer auto-disambiguates these (HH:MM / msgs / UUID suffix), so customers\n never see two identical rows. To fix at the source \u2014 when spawning `claude -p` from\n a script or Captain-Code subordinate, prepend each prompt with:")),console.log(c.dim(" <!-- claude-recall-alias: T1.3 \u2014 Auth Refactor -->")),console.log(c.dim(` The watcher will read the header, alias the session, and strip the marker from the
1030
+ displayed first user message. See https://clauderecall.com/docs \u2192 "Alias header convention".`)),E.length>0&&(console.log(""),console.log(c.warn(` ${E.length} of these groups have NO alias on any row \u2014 strongest candidates
1031
+ for the header-alias fix above.`)))}if(console.log(""),console.log(c.dim("\u2014 Tab-name invariant \u2014")),s.length===0)return console.log(c.ok(` \u2713 holds across ${n.length.toLocaleString()} aliased session${n.length===1?"":"s"}`)),console.log(c.dim(" No fabricated origin labels (`VS Code \xB7 cwd \xB7 branch`) found. No deprecated cwd-branch synthesis found.")),o.db.integrity==="ok"&&a.status!=="fail"&&d.status!=="fail"&&u.status!=="critical"&&!m.flagged&&l.status!=="critical"&&!p.flagged?0:1;console.log(c.err(`\u2717 ${s.length} invariant violation${s.length===1?"":"s"} found across ${n.length.toLocaleString()} aliased sessions`)),console.log("");let b=new Map;for(let E of s){let S=b.get(E.violation)??[];S.push(E),b.set(E.violation,S)}for(let[E,S]of b){console.log(c.warn(` ${E} (${S.length})`));for(let y of S.slice(0,10))console.log(` ${y.session_id.slice(0,8)} ${c.dim("\u2192")} ${JSON.stringify(y.alias)}`);S.length>10&&console.log(c.dim(` \u2026 and ${S.length-10} more (rerun with --json for the full list)`)),console.log("")}return console.log(c.dim('Remediation: `recall name <id-prefix> ""` clears a bad alias so the heuristic title takes over,\nor `recall name <id-prefix> "<actual tab name>"` sets it to the real value.')),1}function tR(){try{let e=Xu(C);return Number(e.bavail)*Number(e.bsize)}catch{return 0}}var UT,BT,Ju,Yu,Ri,qu,Bu,xi=w(()=>{"use strict";D();k();qn();I();Ru();En();_n();De();fs();ms();Ei();vu();bi();Sn();wi();UT=["VS Code","VS Code Insiders","Cursor","Windsurf","Warp","iTerm","Terminal","WezTerm","Windows Terminal","Kitty","Alacritty"],BT=new RegExp(`^(${UT.map(e=>e.replace(/ /g,"\\s")).join("|")})\\s\xB7\\s`);Ju=50;Yu=5*6e4,Ri=24,qu=.5;Bu=5e3});import{writeFileSync as wp,readFileSync as hj,existsSync as Tp,mkdirSync as Rp,readdirSync as Ej}from"node:fs";import{join as rr}from"node:path";function BR(){j(),Tp(vi)||Rp(vi,{recursive:!0})}function HR(){j(),Tp(Ii)||Rp(Ii,{recursive:!0})}function kp(e){try{return JSON.parse(e)}catch{return e}}function Mi(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:kp(e.evidence),approved:e.approved===1,created_at:e.created_at,updated_at:e.updated_at}}function Di(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:kp(e.evidence),status:e.status,inferred_by:e.inferred_by,created_at:e.created_at,decided_at:e.decided_at}}function WR(e){if(!Number.isFinite(e)||e<0||e>1)throw new Error("confidence must be a number in [0, 1]")}function xp(e){if(!$R.has(e))throw new Error(`invalid link_type: ${e}`)}function Cp(e){if(!jR.has(e))throw new Error(`invalid inferred_by: ${e}`)}function XR(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 GR(e={}){let t=h(),n=[],s=[];e.sourceSessionId&&(n.push("source_session_id = ?"),s.push(e.sourceSessionId)),e.targetSessionId&&(n.push("target_session_id = ?"),s.push(e.targetSessionId)),e.linkType&&(xp(e.linkType),n.push("link_type = ?"),s.push(e.linkType)),e.approvedOnly&&n.push("approved = 1");let r=n.length?`WHERE ${n.join(" AND ")}`:"",o=Math.max(1,Math.min(5e3,e.limit??1e3));return t.prepare(`SELECT * FROM session_links ${r}
1027
1032
  ORDER BY confidence DESC, updated_at DESC
1028
- LIMIT ?`).all(...s,o).map(Ai)}function Oi(e){return E().prepare(`SELECT * FROM session_links
1033
+ LIMIT ?`).all(...s,o).map(Mi)}function $i(e){return h().prepare(`SELECT * FROM session_links
1029
1034
  WHERE source_session_id = ? OR target_session_id = ?
1030
- ORDER BY confidence DESC, updated_at DESC`).all(e,e).map(Ai)}function gt(e,t={}){xR(e.source_session_id,e.target_session_id),hp(e.link_type),kR(e.confidence),Ep(e.inferred_by);let n=E(),s=new Date().toISOString(),r=JSON.stringify(e.evidence??null);n.prepare(`INSERT INTO session_link_suggestions
1035
+ ORDER BY confidence DESC, updated_at DESC`).all(e,e).map(Mi)}function gt(e,t={}){XR(e.source_session_id,e.target_session_id),xp(e.link_type),WR(e.confidence),Cp(e.inferred_by);let n=h(),s=new Date().toISOString(),r=JSON.stringify(e.evidence??null);n.prepare(`INSERT INTO session_link_suggestions
1031
1036
  (source_session_id, target_session_id, link_type,
1032
1037
  confidence, evidence, status, inferred_by,
1033
1038
  created_at, decided_at)
@@ -1047,9 +1052,9 @@ CREATE VIRTUAL TABLE IF NOT EXISTS vec_chunks_v2 USING vec0(
1047
1052
  WHERE source_session_id = ?
1048
1053
  AND target_session_id = ?
1049
1054
  AND link_type = ?
1050
- AND inferred_by = ?`).get(e.source_session_id,e.target_session_id,e.link_type,e.inferred_by);if(!o)throw new Error("createSuggestion succeeded but read-back failed");return t.deferMirror||ft(),Ni(o)}function sr(e={}){let t=E(),n=[],s=[];if(e.status){if(!SR.has(e.status))throw new Error(`invalid status: ${e.status}`);n.push("status = ?"),s.push(e.status)}e.sourceSessionId&&(n.push("source_session_id = ?"),s.push(e.sourceSessionId)),e.targetSessionId&&(n.push("target_session_id = ?"),s.push(e.targetSessionId)),e.inferredBy&&(Ep(e.inferredBy),n.push("inferred_by = ?"),s.push(e.inferredBy));let r=n.length?`WHERE ${n.join(" AND ")}`:"",o=Math.max(1,Math.min(5e3,e.limit??1e3));return t.prepare(`SELECT * FROM session_link_suggestions ${r}
1055
+ AND inferred_by = ?`).get(e.source_session_id,e.target_session_id,e.link_type,e.inferred_by);if(!o)throw new Error("createSuggestion succeeded but read-back failed");return t.deferMirror||ft(),Di(o)}function or(e={}){let t=h(),n=[],s=[];if(e.status){if(!FR.has(e.status))throw new Error(`invalid status: ${e.status}`);n.push("status = ?"),s.push(e.status)}e.sourceSessionId&&(n.push("source_session_id = ?"),s.push(e.sourceSessionId)),e.targetSessionId&&(n.push("target_session_id = ?"),s.push(e.targetSessionId)),e.inferredBy&&(Cp(e.inferredBy),n.push("inferred_by = ?"),s.push(e.inferredBy));let r=n.length?`WHERE ${n.join(" AND ")}`:"",o=Math.max(1,Math.min(5e3,e.limit??1e3));return t.prepare(`SELECT * FROM session_link_suggestions ${r}
1051
1056
  ORDER BY confidence DESC, created_at DESC
1052
- LIMIT ?`).all(...s,o).map(Ni)}function bp(e,t,n={}){if(t!=="approved"&&t!=="rejected")throw new Error(`invalid decision: ${t}`);let s=n.source??"manual";if(!bR.has(s))throw new Error(`invalid source: ${s}`);let r=E(),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
1057
+ LIMIT ?`).all(...s,o).map(Di)}function Ap(e,t,n={}){if(t!=="approved"&&t!=="rejected")throw new Error(`invalid decision: ${t}`);let s=n.source??"manual";if(!PR.has(s))throw new Error(`invalid source: ${s}`);let r=h(),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
1053
1058
  SET status = ?, decided_at = ?
1054
1059
  WHERE id = ?`).run(t,i,e),t==="approved"&&(r.prepare(`INSERT INTO session_links
1055
1060
  (source_session_id, target_session_id, link_type,
@@ -1064,7 +1069,7 @@ CREATE VIRTUAL TABLE IF NOT EXISTS vec_chunks_v2 USING vec0(
1064
1069
  updated_at = excluded.updated_at`).run(o.source_session_id,o.target_session_id,o.link_type,o.confidence,s,o.evidence,i,i),a=r.prepare(`SELECT * FROM session_links
1065
1070
  WHERE source_session_id = ?
1066
1071
  AND target_session_id = ?
1067
- AND link_type = ?`).get(o.source_session_id,o.target_session_id,o.link_type))})(),ft(),t==="approved"&&LR(o.source_session_id);let d=r.prepare("SELECT * FROM session_link_suggestions WHERE id = ?").get(e);return{suggestion:Ni(d),link:a?Ai(a):null}}function LR(e){try{TR();let t=CR({sourceSessionId:e}),n=nr(Ci,`${e}.json`);if(t.length===0)return;let s={schema:"claude-recall.session-links.v1",source_session_id:e,backed_up_at:new Date().toISOString(),links:t};mp(n,JSON.stringify(s,null,2))}catch(t){console.error("[session-links] backup failed:",t)}}function ft(){try{RR();let e=sr({limit:5e3}),t={schema:"claude-recall.session-link-suggestions.v1",backed_up_at:new Date().toISOString(),suggestions:e};mp(wR,JSON.stringify(t,null,2))}catch(e){console.error("[session-links] suggestions backup failed:",e)}}var ER,bR,SR,yR,Ci,Li,wR,Dn=w(()=>{"use strict";k();I();ER=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),bR=new Set(["regex","llm","embedding","manual","auto","citation","git","terminal-registry"]),SR=new Set(["pending","approved","rejected"]),yR=new Set(["L1","L2","L3","L4","user"]),Ci=nr(C,"links"),Li=nr(C,"suggestions"),wR=nr(Li,"index.json")});function cr(e){return e?Math.ceil(e.length/4):0}function Xp(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/zk);return Math.max(Jk,t)}function Gp(e,t){if(!e||!t)return 0;let n=Date.parse(e),s=Date.parse(t);return!Number.isFinite(n)||!Number.isFinite(s)?0:Math.abs(s-n)/(1e3*60*60*24)}function zp(e){return E().prepare(`SELECT s.id,
1072
+ AND link_type = ?`).get(o.source_session_id,o.target_session_id,o.link_type))})(),ft(),t==="approved"&&JR(o.source_session_id);let d=r.prepare("SELECT * FROM session_link_suggestions WHERE id = ?").get(e);return{suggestion:Di(d),link:a?Mi(a):null}}function JR(e){try{BR();let t=GR({sourceSessionId:e}),n=rr(vi,`${e}.json`);if(t.length===0)return;let s={schema:"claude-recall.session-links.v1",source_session_id:e,backed_up_at:new Date().toISOString(),links:t};wp(n,JSON.stringify(s,null,2))}catch(t){console.error("[session-links] backup failed:",t)}}function ft(){try{HR();let e=or({limit:5e3}),t={schema:"claude-recall.session-link-suggestions.v1",backed_up_at:new Date().toISOString(),suggestions:e};wp(UR,JSON.stringify(t,null,2))}catch(e){console.error("[session-links] suggestions backup failed:",e)}}var $R,PR,FR,jR,vi,Ii,UR,$n=w(()=>{"use strict";k();I();$R=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),PR=new Set(["regex","llm","embedding","manual","auto","citation","git","terminal-registry"]),FR=new Set(["pending","approved","rejected"]),jR=new Set(["L1","L2","L3","L4","user"]),vi=rr(C,"links"),Ii=rr(C,"suggestions"),UR=rr(Ii,"index.json")});function dr(e){return e?Math.ceil(e.length/4):0}function Zp(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/d0);return Math.max(u0,t)}function em(e,t){if(!e||!t)return 0;let n=Date.parse(e),s=Date.parse(t);return!Number.isFinite(n)||!Number.isFinite(s)?0:Math.abs(s-n)/(1e3*60*60*24)}function tm(e){return h().prepare(`SELECT s.id,
1068
1073
  NULLIF(sa.alias, '') AS alias,
1069
1074
  s.auto_title,
1070
1075
  s.auto_title_source,
@@ -1075,37 +1080,37 @@ CREATE VIRTUAL TABLE IF NOT EXISTS vec_chunks_v2 USING vec0(
1075
1080
  FROM sessions s
1076
1081
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1077
1082
  LEFT JOIN projects p ON p.id = s.project_id
1078
- WHERE s.id = ?`).get(e)??null}function Jp(e){let n=E().prepare("SELECT summary FROM session_semantic WHERE session_id = ?").get(e);if(!n||!n.summary)return null;let s=n.summary.trim();return s.length>0?s:null}function Yp(e){let t=e.alias?.trim(),n=e.auto_title?.trim(),s=e.first_user_message?.trim();return n&&e.auto_title_source==="agent"?n:t||n||(s?s.slice(0,80):e.id.slice(0,8))}function qk(e){let n=E().prepare(`SELECT id, auto_title, started_at
1083
+ WHERE s.id = ?`).get(e)??null}function nm(e){let n=h().prepare("SELECT summary FROM session_semantic WHERE session_id = ?").get(e);if(!n||!n.summary)return null;let s=n.summary.trim();return s.length>0?s:null}function sm(e){let t=e.alias?.trim(),n=e.auto_title?.trim(),s=e.first_user_message?.trim();return n&&e.auto_title_source==="agent"?n:t||n||(s?s.slice(0,80):e.id.slice(0,8))}function m0(e){let n=h().prepare(`SELECT id, auto_title, started_at
1079
1084
  FROM sessions
1080
1085
  WHERE project_id = ?
1081
- ORDER BY COALESCE(started_at, ''), id`).all(e),s=new Set,r=new Set,o=[];for(let p of n){if(!p.auto_title||!p.auto_title.startsWith("/")){o.push({id:p.id,brand:null,skill:null});continue}let g=p.auto_title.split(" \xB7 "),f=g[0].trim(),h=g.length>1?g.slice(1).join(" \xB7 ").trim():null;o.push({id:p.id,brand:h||null,skill:f||null}),h&&s.add(h),f&&r.add(f)}let i=[...s].sort(),a=new Map;i.forEach((p,g)=>a.set(p,g));let d=[...r].sort(),l=new Map;d.forEach((p,g)=>l.set(p,g));let u=new Map,m=new Map;for(let p of o){if(!p.brand||!p.skill)continue;let g=a.get(p.brand),f=l.get(p.skill);if(g===void 0||f===void 0)continue;let h=`${g}.${f}`,_=(u.get(h)??0)+1;u.set(h,_),m.set(p.id,`${g}.${f}.${_}`)}return{byId:m}}function Vk(e){return{table:e!==null?qk(e):null,originProjectId:e,cache:new Map}}function lr(e,t){let n=e.cache.get(t);if(n)return n;let s=zp(t);if(!s)return null;let r=e.table&&s.project_id===e.originProjectId?e.table.byId.get(t)??null:null,o={session_id:s.id,title:Yp(s),decimal:r,summary:Jp(s.id),project:s.project,started_at:s.started_at};return e.cache.set(t,o),o}function Kk(e,t){let s=E().prepare(`SELECT DISTINCT te.parent_session_id AS pid
1086
+ ORDER BY COALESCE(started_at, ''), id`).all(e),s=new Set,r=new Set,o=[];for(let p of n){if(!p.auto_title||!p.auto_title.startsWith("/")){o.push({id:p.id,brand:null,skill:null});continue}let g=p.auto_title.split(" \xB7 "),f=g[0].trim(),_=g.length>1?g.slice(1).join(" \xB7 ").trim():null;o.push({id:p.id,brand:_||null,skill:f||null}),_&&s.add(_),f&&r.add(f)}let i=[...s].sort(),a=new Map;i.forEach((p,g)=>a.set(p,g));let d=[...r].sort(),l=new Map;d.forEach((p,g)=>l.set(p,g));let u=new Map,m=new Map;for(let p of o){if(!p.brand||!p.skill)continue;let g=a.get(p.brand),f=l.get(p.skill);if(g===void 0||f===void 0)continue;let _=`${g}.${f}`,b=(u.get(_)??0)+1;u.set(_,b),m.set(p.id,`${g}.${f}.${b}`)}return{byId:m}}function g0(e){return{table:e!==null?m0(e):null,originProjectId:e,cache:new Map}}function ur(e,t){let n=e.cache.get(t);if(n)return n;let s=tm(t);if(!s)return null;let r=e.table&&s.project_id===e.originProjectId?e.table.byId.get(t)??null:null,o={session_id:s.id,title:sm(s),decimal:r,summary:nm(s.id),project:s.project,started_at:s.started_at};return e.cache.set(t,o),o}function f0(e,t){let s=h().prepare(`SELECT DISTINCT te.parent_session_id AS pid
1082
1087
  FROM thread_edges te
1083
1088
  WHERE te.session_id = ?
1084
- AND te.parent_session_id IS NOT NULL`).all(t),r=[];for(let o of s){if(!o.pid)continue;let i=lr(e,o.pid);i&&r.push(i)}return r}function Qk(e,t){let s=E().prepare(`SELECT DISTINCT te.session_id AS sid
1089
+ AND te.parent_session_id IS NOT NULL`).all(t),r=[];for(let o of s){if(!o.pid)continue;let i=ur(e,o.pid);i&&r.push(i)}return r}function _0(e,t){let s=h().prepare(`SELECT DISTINCT te.session_id AS sid
1085
1090
  FROM thread_edges te
1086
- WHERE te.parent_session_id = ?`).all(t),r=[];for(let o of s){if(!o.sid)continue;let i=lr(e,o.sid);i&&r.push(i)}return r}function qp(e){let t=Yk[e.linkType]??.5,n=Kt(e.confidence),s=t*n,r=Xp(e.daysApart),o=e.embeddingCosine??.5,i=Kt(e.pagerank);if(e.scoring==="pagerank")return Kt(i);if(e.scoring==="embedding-rerank")return e.embeddingCosine===null?Kt(s):Kt(o);let a=.35*s+.2*r+.2*o+.25*i;return Kt(a)}function Kt(e){return!Number.isFinite(e)||e<0?0:e>1?1:e}function Zk(e,t,n,s,r){let o=new Map;function i(a,d){if(a===d)return;let l=o.get(a);l||(l=new Set,o.set(a,l)),l.add(d)}for(let a of t)i(a.source_session_id,a.target_session_id),i(a.target_session_id,a.source_session_id);for(let a of n)i(e,a.session_id);for(let a of n)i(a.session_id,e);for(let a of s)i(e,a.session_id);for(let a of s)i(a.session_id,e);if(r>1){let a=new Set([e]),d=new Set([e]);for(let l=1;l<r;l++){let u=new Set;for(let m of a){let p=o.get(m);if(p)for(let g of p){if(d.has(g))continue;let f=Oi(g).filter(h=>h.approved);for(let h of f)i(h.source_session_id,h.target_session_id),i(h.target_session_id,h.source_session_id);d.add(g),u.add(g)}}if(u.size===0)break;for(let m of u)a.add(m)}}return{edges:o}}function e0(e,t={}){let n=t.iterations??12,s=t.damping??.85,r=Array.from(e.edges.keys());if(r.length===0)return new Map;let o=1/r.length,i=new Map(r.map(l=>[l,o]));for(let l=0;l<n;l++){let u=new Map(r.map(m=>[m,(1-s)/r.length]));for(let m of r){let p=e.edges.get(m);if(!p||p.size===0)continue;let g=(i.get(m)??0)/p.size;for(let f of p)u.set(f,(u.get(f)??0)+s*g)}i=u}let a=0;for(let l of i.values())l>a&&(a=l);if(a<=0)return i;let d=new Map;for(let[l,u]of i)d.set(l,u/a);return d}function Kp(e,t){let n=e.replace(/\s+/g," ").trim();return n.length<=t?n:`${n.slice(0,t-1).trimEnd()}\u2026`}function t0(e){let t=e.decimal?`${e.decimal} `:"",n=e.session_id.slice(0,8),s="evidence"in e&&e.evidence?` \u2014 ${e.evidence}`:"",r=`- ${t}${e.title} (${n})${s}`;if(e.summary){let o=Kp(e.summary,Vp);return`${r}
1087
- ${o}`}return r}function n0(e,t,n){let s=[],r=[],o=0,i=e.decimal?`${e.decimal}: `:"",a=`# Neighborhood for ${e.session_id} (${i}${e.title})`;if(s.push(a),o+=cr(a),e.summary){let d=Kp(e.summary,Vp*4);s.push(d),o+=cr(d)}s.push("");for(let d of t){if(d.refs.length===0)continue;let l=`## ${d.heading}`,u=cr(l),m=[],p=0;for(let g of d.refs){let f=t0(g),h=cr(f);if(o+u+p+h>n){r.push({session_id:g.session_id,title:g.title,decimal:g.decimal,summary:g.summary,project:g.project,started_at:g.started_at});continue}m.push(f),p+=h}if(m.length>0){s.push(l);for(let g of m)s.push(g);s.push(""),o+=u+p}}for(;s.length>0&&s[s.length-1]==="";)s.pop();return{bundle:s.join(`
1091
+ WHERE te.parent_session_id = ?`).all(t),r=[];for(let o of s){if(!o.sid)continue;let i=ur(e,o.sid);i&&r.push(i)}return r}function rm(e){let t=p0[e.linkType]??.5,n=Kt(e.confidence),s=t*n,r=Zp(e.daysApart),o=e.embeddingCosine??.5,i=Kt(e.pagerank);if(e.scoring==="pagerank")return Kt(i);if(e.scoring==="embedding-rerank")return e.embeddingCosine===null?Kt(s):Kt(o);let a=.35*s+.2*r+.2*o+.25*i;return Kt(a)}function Kt(e){return!Number.isFinite(e)||e<0?0:e>1?1:e}function h0(e,t,n,s,r){let o=new Map;function i(a,d){if(a===d)return;let l=o.get(a);l||(l=new Set,o.set(a,l)),l.add(d)}for(let a of t)i(a.source_session_id,a.target_session_id),i(a.target_session_id,a.source_session_id);for(let a of n)i(e,a.session_id);for(let a of n)i(a.session_id,e);for(let a of s)i(e,a.session_id);for(let a of s)i(a.session_id,e);if(r>1){let a=new Set([e]),d=new Set([e]);for(let l=1;l<r;l++){let u=new Set;for(let m of a){let p=o.get(m);if(p)for(let g of p){if(d.has(g))continue;let f=$i(g).filter(_=>_.approved);for(let _ of f)i(_.source_session_id,_.target_session_id),i(_.target_session_id,_.source_session_id);d.add(g),u.add(g)}}if(u.size===0)break;for(let m of u)a.add(m)}}return{edges:o}}function E0(e,t={}){let n=t.iterations??12,s=t.damping??.85,r=Array.from(e.edges.keys());if(r.length===0)return new Map;let o=1/r.length,i=new Map(r.map(l=>[l,o]));for(let l=0;l<n;l++){let u=new Map(r.map(m=>[m,(1-s)/r.length]));for(let m of r){let p=e.edges.get(m);if(!p||p.size===0)continue;let g=(i.get(m)??0)/p.size;for(let f of p)u.set(f,(u.get(f)??0)+s*g)}i=u}let a=0;for(let l of i.values())l>a&&(a=l);if(a<=0)return i;let d=new Map;for(let[l,u]of i)d.set(l,u/a);return d}function im(e,t){let n=e.replace(/\s+/g," ").trim();return n.length<=t?n:`${n.slice(0,t-1).trimEnd()}\u2026`}function b0(e){let t=e.decimal?`${e.decimal} `:"",n=e.session_id.slice(0,8),s="evidence"in e&&e.evidence?` \u2014 ${e.evidence}`:"",r=`- ${t}${e.title} (${n})${s}`;if(e.summary){let o=im(e.summary,om);return`${r}
1092
+ ${o}`}return r}function S0(e,t,n){let s=[],r=[],o=0,i=e.decimal?`${e.decimal}: `:"",a=`# Neighborhood for ${e.session_id} (${i}${e.title})`;if(s.push(a),o+=dr(a),e.summary){let d=im(e.summary,om*4);s.push(d),o+=dr(d)}s.push("");for(let d of t){if(d.refs.length===0)continue;let l=`## ${d.heading}`,u=dr(l),m=[],p=0;for(let g of d.refs){let f=b0(g),_=dr(f);if(o+u+p+_>n){r.push({session_id:g.session_id,title:g.title,decimal:g.decimal,summary:g.summary,project:g.project,started_at:g.started_at});continue}m.push(f),p+=_}if(m.length>0){s.push(l);for(let g of m)s.push(g);s.push(""),o+=u+p}}for(;s.length>0&&s[s.length-1]==="";)s.pop();return{bundle:s.join(`
1088
1093
  `)+`
1089
- `,budgetUsed:o,truncated:r}}function s0(e,t,n,s,r,o){let i=[];for(let a of n){if(s&&!s.has(a.link_type))continue;let d=null;if(a.source_session_id===t.session_id?d=a.target_session_id:a.target_session_id===t.session_id&&(d=a.source_session_id),!d)continue;let l=lr(e,d);if(!l)continue;let u=Gp(t.started_at,l.started_at),m=qp({confidence:a.confidence,linkType:a.link_type,daysApart:u,embeddingCosine:null,pagerank:o.get(d)??0,scoring:r});i.push({...l,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 dr(e,t={}){let n=Math.max(100,Math.floor(t.budget??Xk)),s=t.scoring??"hybrid",r=Math.max(1,Math.min(5,t.maxDepth??Gk)),o=t.includeWikiLinks??!0,i=t.includeSuggestions??!1,a=t.edgeTypes?new Set(t.edgeTypes):null,d=zp(e);if(!d)throw new Error(`session not found: ${e}`);let l=Vk(d.project_id),u={session_id:d.id,title:Yp(d),decimal:l.table?.byId.get(d.id)??null,summary:Jp(d.id),project:d.project,started_at:d.started_at};l.cache.set(d.id,u);let m=Kk(l,e),p=Qk(l,e),g=Oi(e).filter(L=>L.approved).filter(L=>!a||a.has(L.link_type)).filter(L=>o||L.link_type!=="wiki_link"),f=Zk(e,g,m,p,r),h=e0(f),_=[],b=[],S=[],y=[];for(let L of g){let v=L.source_session_id===e?L.target_session_id:L.source_session_id,O=lr(l,v);if(!O)continue;let x=Gp(u.started_at,O.started_at),M=qp({confidence:L.confidence,linkType:L.link_type,daysApart:x,embeddingCosine:null,pagerank:h.get(v)??0,scoring:s}),F=Xp(x),ne=`${L.link_type} confidence=${L.confidence.toFixed(2)} recency=${F.toFixed(2)} (${Math.round(x)}d apart)`,et={...O,score:M,evidence:ne,link_type:L.link_type};L.link_type==="citation"?_.push(et):L.link_type==="similar"?b.push(et):L.link_type==="wiki_link"?y.push(et):S.push(et)}if(i){let L=sr({sourceSessionId:e,status:"pending",limit:100}),v=sr({targetSessionId:e,status:"pending",limit:100}),O=[...L,...v],x=new Set,M=O.filter(ne=>x.has(ne.id)?!1:(x.add(ne.id),!0)),F=s0(l,u,M,a,s,h);for(let ne of F)ne.link_type==="citation"?_.push(ne):ne.link_type==="similar"?b.push(ne):ne.link_type==="wiki_link"?y.push(ne):S.push(ne)}let T=(L,v)=>v.score-L.score;_.sort(T),b.sort(T),S.sort(T),y.sort(T);let B=n0(u,[{heading:"Parents",refs:m},{heading:"Children",refs:p},{heading:"Citations (approved)",refs:_},{heading:"Similar sessions",refs:b},{heading:"Cousins (skill track + temporal)",refs:S},{heading:"Wiki links (manual)",refs:y}],n);return{origin:u,parents:m,children:p,citations:_,similar:b,cousins:S,wikiLinks:y,bundle:B.bundle,budgetUsed:B.budgetUsed,budgetRemaining:Math.max(0,n-B.budgetUsed),truncated:B.truncated}}var Xk,Gk,zk,Jk,Yk,Vp,ji=w(()=>{"use strict";k();Dn();Xk=4e3,Gk=2,zk=30,Jk=.2,Yk={citation:1,wiki_link:.9,similar:.7,skill_track:.5,bug_pattern:.4,temporal_proximity:.3};Vp=240});var jm={};V(jm,{computeAllHealthScores:()=>Qi,computeHealthScore:()=>Vi,computeHealthScoreByName:()=>Ki});function Pn(e){return Math.max(0,Math.min(1,e))}function Vi(e){let t=E(),n=t.prepare("SELECT id, name FROM projects WHERE id = ?").get(e);if(!n)return null;let s=t.prepare(`SELECT COUNT(*) AS cnt,
1094
+ `,budgetUsed:o,truncated:r}}function y0(e,t,n,s,r,o){let i=[];for(let a of n){if(s&&!s.has(a.link_type))continue;let d=null;if(a.source_session_id===t.session_id?d=a.target_session_id:a.target_session_id===t.session_id&&(d=a.source_session_id),!d)continue;let l=ur(e,d);if(!l)continue;let u=em(t.started_at,l.started_at),m=rm({confidence:a.confidence,linkType:a.link_type,daysApart:u,embeddingCosine:null,pagerank:o.get(d)??0,scoring:r});i.push({...l,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 pr(e,t={}){let n=Math.max(100,Math.floor(t.budget??c0)),s=t.scoring??"hybrid",r=Math.max(1,Math.min(5,t.maxDepth??l0)),o=t.includeWikiLinks??!0,i=t.includeSuggestions??!1,a=t.edgeTypes?new Set(t.edgeTypes):null,d=tm(e);if(!d)throw new Error(`session not found: ${e}`);let l=g0(d.project_id),u={session_id:d.id,title:sm(d),decimal:l.table?.byId.get(d.id)??null,summary:nm(d.id),project:d.project,started_at:d.started_at};l.cache.set(d.id,u);let m=f0(l,e),p=_0(l,e),g=$i(e).filter(A=>A.approved).filter(A=>!a||a.has(A.link_type)).filter(A=>o||A.link_type!=="wiki_link"),f=h0(e,g,m,p,r),_=E0(f),b=[],E=[],S=[],y=[];for(let A of g){let v=A.source_session_id===e?A.target_session_id:A.source_session_id,O=ur(l,v);if(!O)continue;let x=em(u.started_at,O.started_at),M=rm({confidence:A.confidence,linkType:A.link_type,daysApart:x,embeddingCosine:null,pagerank:_.get(v)??0,scoring:s}),F=Zp(x),ne=`${A.link_type} confidence=${A.confidence.toFixed(2)} recency=${F.toFixed(2)} (${Math.round(x)}d apart)`,et={...O,score:M,evidence:ne,link_type:A.link_type};A.link_type==="citation"?b.push(et):A.link_type==="similar"?E.push(et):A.link_type==="wiki_link"?y.push(et):S.push(et)}if(i){let A=or({sourceSessionId:e,status:"pending",limit:100}),v=or({targetSessionId:e,status:"pending",limit:100}),O=[...A,...v],x=new Set,M=O.filter(ne=>x.has(ne.id)?!1:(x.add(ne.id),!0)),F=y0(l,u,M,a,s,_);for(let ne of F)ne.link_type==="citation"?b.push(ne):ne.link_type==="similar"?E.push(ne):ne.link_type==="wiki_link"?y.push(ne):S.push(ne)}let T=(A,v)=>v.score-A.score;b.sort(T),E.sort(T),S.sort(T),y.sort(T);let B=S0(u,[{heading:"Parents",refs:m},{heading:"Children",refs:p},{heading:"Citations (approved)",refs:b},{heading:"Similar sessions",refs:E},{heading:"Cousins (skill track + temporal)",refs:S},{heading:"Wiki links (manual)",refs:y}],n);return{origin:u,parents:m,children:p,citations:b,similar:E,cousins:S,wikiLinks:y,bundle:B.bundle,budgetUsed:B.budgetUsed,budgetRemaining:Math.max(0,n-B.budgetUsed),truncated:B.truncated}}var c0,l0,d0,u0,p0,om,Xi=w(()=>{"use strict";k();$n();c0=4e3,l0=2,d0=30,u0=.2,p0={citation:1,wiki_link:.9,similar:.7,skill_track:.5,bug_pattern:.4,temporal_proximity:.3};om=240});var Km={};V(Km,{computeAllHealthScores:()=>sa,computeHealthScore:()=>ta,computeHealthScoreByName:()=>na});function Fn(e){return Math.max(0,Math.min(1,e))}function ta(e){let t=h(),n=t.prepare("SELECT id, name FROM projects WHERE id = ?").get(e);if(!n)return null;let s=t.prepare(`SELECT COUNT(*) AS cnt,
1090
1095
  MAX(started_at) AS latest
1091
- FROM sessions WHERE project_id = ?`).get(e),r=s.cnt;if(r===0)return{projectId:e,projectName:n.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=Pn(r/10),i=s.latest?(Date.now()-new Date(s.latest).getTime())/(1e3*60*60*24):90,a=Pn(1-i/90),l=t.prepare(`SELECT AVG(message_count) AS avg_msgs
1092
- FROM sessions WHERE project_id = ?`).get(e).avg_msgs??0,u=Pn((l-2)/3),m=t.prepare(`SELECT COUNT(*) AS total,
1096
+ FROM sessions WHERE project_id = ?`).get(e),r=s.cnt;if(r===0)return{projectId:e,projectName:n.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=Fn(r/10),i=s.latest?(Date.now()-new Date(s.latest).getTime())/(1e3*60*60*24):90,a=Fn(1-i/90),l=t.prepare(`SELECT AVG(message_count) AS avg_msgs
1097
+ FROM sessions WHERE project_id = ?`).get(e).avg_msgs??0,u=Fn((l-2)/3),m=t.prepare(`SELECT COUNT(*) AS total,
1093
1098
  SUM(CASE WHEN m.content_text IS NOT NULL AND m.content_text != '' THEN 1 ELSE 0 END) AS covered
1094
1099
  FROM messages m
1095
1100
  JOIN sessions s ON s.id = m.session_id
1096
- WHERE s.project_id = ?`).get(e),p=m.total>0?m.covered/m.total:.5,g=Pn(p),f=t.prepare(`SELECT COUNT(DISTINCT s.id) AS total,
1101
+ WHERE s.project_id = ?`).get(e),p=m.total>0?m.covered/m.total:.5,g=Fn(p),f=t.prepare(`SELECT COUNT(DISTINCT s.id) AS total,
1097
1102
  COUNT(DISTINCT st.session_id) AS tagged
1098
1103
  FROM sessions s
1099
1104
  LEFT JOIN session_tags st ON st.session_id = s.id
1100
- WHERE s.project_id = ?`).get(e),h=f.total>0?f.tagged/f.total:0,_=Pn(h),b=Math.round((o*.2+a*.25+u*.15+g*.2+_*.2)*100);return{projectId:e,projectName:n.name,score:b,breakdown:{sessionCount:{raw:r,score:o,weight:.2},recency:{daysSinceLastSession:Math.round(i),score:a,weight:.25},fragmentation:{avgMessages:Math.round(l*10)/10,score:u,weight:.15},searchCoverage:{ratio:Math.round(p*100)/100,score:g,weight:.2},tagCoverage:{ratio:Math.round(h*100)/100,score:_,weight:.2}}}}function Ki(e){let n=E().prepare("SELECT id FROM projects WHERE name = ?").get(e);return n?Vi(n.id):null}function Qi(){let t=E().prepare("SELECT id FROM projects ORDER BY name").all(),n=[];for(let s of t){let r=Vi(s.id);r&&n.push(r)}return n}var Zi=w(()=>{"use strict";k()});function Kg(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:Mt,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 ht(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:[Kg(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 Et(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:[Kg(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 mL(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 gL(e){return e.toLocaleString("en-US")}function bt(e){return e<1e3?String(e):`${mL(e)} (${gL(e)})`}function St(e){return new Date(e).toLocaleDateString("en-US",{month:"long",day:"numeric",year:"numeric"})}var Mt,jn=w(()=>{"use strict";Mt="#f97316"});var Zg={};V(Zg,{render:()=>hL});function Cr(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:Un,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:Lr,textTransform:"uppercase",letterSpacing:"0.16em"},children:t}}]}}}function hL(e){let n=[St(e.sessionDate)];e.durationLabel&&n.push(e.durationLabel);let s=n.join(" \xB7 "),r=e.costDollars??"$\u2014",o=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${bt(e.cachedTokens)} cached`:null,i=[ht(Qg,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:Un,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"20px",color:Lr},children:s}}]}},{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:Mt,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:r}},{type:"span",props:{style:{marginTop:"16px",fontSize:"16px",color:Lr,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:600},children:"session cost"}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:_L}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[Cr(String(e.messageCount),"msgs"),Cr(String(e.filesReferenced),"files"),Cr(String(e.toolCallCount),"tools"),Cr(e.model??"\u2014","model")]}}];return o&&i.push({type:"div",props:{style:{fontSize:"14px",color:Lr,fontFamily:"JetBrains Mono",opacity:.7},children:o}}),e.verdict&&i.push({type:"div",props:{style:{display:"flex",fontSize:"24px",fontStyle:"italic",color:Un,borderLeft:`3px solid ${Mt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),i.push({type:"div",props:{style:{display:"flex",flex:1}}}),i.push(Et(Qg)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:fL,padding:"64px 72px",fontFamily:"Inter",gap:"28px"},children:i}}}var fL,Un,Lr,_L,Qg,ef=w(()=>{"use strict";jn();fL="#1a1b1e",Un="#e7e9ee",Lr="#8b9098",_L="#2a2c33",Qg={markStroke:Un,wordmarkFg:Un}});var nf={};V(nf,{render:()=>SL});function Ar(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:Bn,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:Nr,fontFamily:"JetBrains Mono",textTransform:"lowercase"},children:`// ${t}`}}]}}}function SL(e){let t=[St(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),n=e.costDollars??"$\u2014",s=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`# ${bt(e.cachedTokens)} tokens cache-replayed (free)`:null,r=[ht(tf,"recall.cli/share"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"6px"},children:[{type:"div",props:{style:{fontSize:"18px",color:ua,fontFamily:"JetBrains Mono"},children:"$ recall share --session"}},{type:"div",props:{style:{fontSize:"40px",fontWeight:700,color:Bn,lineHeight:1.15,wordBreak:"break-word",fontFamily:"JetBrains Mono"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"18px",color:Nr,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:Nr,fontFamily:"JetBrains Mono"},children:"> total_cost:"}},{type:"span",props:{style:{fontSize:"180px",fontWeight:700,color:ua,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:n}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:bL}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[Ar(String(e.messageCount),"msgs"),Ar(String(e.filesReferenced),"files"),Ar(String(e.toolCallCount),"tools"),Ar(e.model??"\u2014","model")]}}];return s&&r.push({type:"div",props:{style:{fontSize:"14px",color:Nr,fontFamily:"JetBrains Mono",opacity:.7},children:s}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"22px",color:Bn,fontFamily:"JetBrains Mono",borderLeft:`3px solid ${ua}`,paddingLeft:"20px",marginTop:"8px"},children:`// ${e.verdict}`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(Et(tf)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:EL,padding:"64px 72px",fontFamily:"Inter",gap:"28px"},children:r}}}var EL,Bn,Nr,bL,ua,tf,sf=w(()=>{"use strict";jn();EL="#0d0d0f",Bn="#e1e7ee",Nr="#6b7480",bL="#1f2229",ua="#7ee787",tf={markStroke:Bn,wordmarkFg:Bn}});var of={};V(of,{render:()=>wL});function Or(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:Dt,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:vr,textTransform:"uppercase",letterSpacing:"0.16em",fontWeight:600},children:t}}]}}}function wL(e){let t=[St(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),n=e.costDollars??"$\u2014",s=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${bt(e.cachedTokens)} cached`:null,r=[ht(rf,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:Dt,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"20px",color:vr},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:Dt,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:n}},{type:"span",props:{style:{marginTop:"16px",fontSize:"16px",color:vr,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:600},children:"session cost"}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:yL}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[Or(String(e.messageCount),"msgs"),Or(String(e.filesReferenced),"files"),Or(String(e.toolCallCount),"tools"),Or(e.model??"\u2014","model")]}}];return s&&r.push({type:"div",props:{style:{fontSize:"14px",color:vr,fontFamily:"JetBrains Mono",opacity:.85},children:s}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"24px",fontStyle:"italic",color:Dt,borderLeft:`3px solid ${Dt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(Et(rf)),{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 Dt,vr,yL,rf,af=w(()=>{"use strict";jn();Dt="#ffffff",vr="rgba(255,255,255,0.7)",yL="rgba(255,255,255,0.18)",rf={markStroke:Dt,wordmarkFg:Dt}});var lf={};V(lf,{render:()=>CL});function Ir(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:800,color:tn,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:Hn,textTransform:"uppercase",letterSpacing:"0.16em",fontWeight:600},children:t}}]}}}function xL(e){let t=e.reduce((n,s)=>n+s.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:kL,overflow:"hidden"},children:e.map(n=>({type:"div",props:{style:{display:"flex",width:`${n.value/t*100}%`,height:"100%",backgroundColor:n.color}}}))}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",fontSize:"12px",color:Hn,fontWeight:600,textTransform:"uppercase",letterSpacing:"0.14em"},children:e.map(n=>({type:"span",props:{style:{display:"flex"},children:`${n.label} \xB7 ${n.value}`}}))}}]}}}function CL(e){let t=[St(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),n=e.costDollars??"$\u2014",s=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${bt(e.cachedTokens)} cached`:null,r=[ht(cf,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"40px",fontWeight:700,color:tn,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"18px",color:Hn},children:t}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"flex-start",padding:"8px 0"},children:[{type:"span",props:{style:{fontSize:"14px",color:Hn,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:700},children:"session cost"}},{type:"span",props:{style:{fontSize:"180px",fontWeight:800,color:tn,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:n}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:RL}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[Ir(String(e.messageCount),"msgs"),Ir(String(e.filesReferenced),"files"),Ir(String(e.toolCallCount),"tools"),Ir(e.model??"\u2014","model")]}},xL([{value:e.messageCount,color:Mt,label:"msgs"},{value:e.filesReferenced,color:"#0a0a0a",label:"files"},{value:e.toolCallCount,color:"#5a6068",label:"tools"}])];return s&&r.push({type:"div",props:{style:{fontSize:"14px",color:Hn,fontFamily:"JetBrains Mono",opacity:.85},children:s}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"22px",fontStyle:"italic",color:tn,borderLeft:`3px solid ${Mt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(Et(cf)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:TL,padding:"64px 72px",fontFamily:"Inter",gap:"24px"},children:r}}}var TL,tn,Hn,RL,kL,cf,df=w(()=>{"use strict";jn();TL="#f6f7f9",tn="#0a0a0a",Hn="#5a6068",RL="#e3e6eb",kL="#dde1e7",cf={markStroke:tn,wordmarkFg:tn}});var uf={};V(uf,{render:()=>NL});function pa(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:Mr},children:t}},{type:"div",props:{style:{fontSize:"16px",color:sn,textTransform:"uppercase",letterSpacing:"2px"},children:e}}]}}}function ma(e,t){return{type:"div",props:{style:{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"16px 24px",backgroundColor:ga,borderRadius:"12px"},children:[{type:"span",props:{style:{fontSize:"18px",color:sn},children:e}},{type:"span",props:{style:{fontSize:"20px",fontWeight:700,color:Mr},children:t}}]}}}function NL(e){let t=Math.round(e.healthScore),n=[{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"16px",color:sn,textTransform:"uppercase",letterSpacing:"6px"},children:"YOUR MONTH IN CODE"}},{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:Mr},children:e.month}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"12px",backgroundColor:ga,borderRadius:"16px",padding:"28px",border:`1px solid ${nn}40`},children:[{type:"div",props:{style:{fontSize:"16px",color:AL,textTransform:"uppercase",letterSpacing:"2px"},children:"You are a"}},{type:"div",props:{style:{fontSize:"36px",fontWeight:700,color:nn},children:e.archetype}}]}},{type:"div",props:{style:{display:"flex",gap:"16px",width:"100%"},children:[pa("Recalls",String(e.totalRecalls)),pa("Tokens piped",e.totalTokensPiped>999999?`${(e.totalTokensPiped/1e6).toFixed(1)}M`:e.totalTokensPiped.toLocaleString()),pa("Sessions",String(e.sessionsIndexed))]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px",width:"100%"},children:[{type:"div",props:{style:{fontSize:"14px",color:sn,textTransform:"uppercase",letterSpacing:"2px",marginBottom:"4px"},children:"Highlights"}},ma("Most recalled",e.mostRecalledSession),ma("Biggest recall",`${e.biggestRecallTokens.toLocaleString()} tokens`),ma("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 ${nn}`,display:"flex",alignItems:"center",justifyContent:"center"},children:{type:"span",props:{style:{fontSize:"32px",fontWeight:700,color:nn},children:`${t}`}}}},{type:"div",props:{style:{fontSize:"14px",color:sn,textTransform:"uppercase",letterSpacing:"2px"},children:"Memory health"}}]}}];return e.verdict&&n.push({type:"div",props:{style:{backgroundColor:ga,borderLeft:`3px solid ${nn}`,borderRadius:"8px",padding:"20px 24px",fontSize:"20px",color:Mr,fontStyle:"italic"},children:`"${e.verdict}"`}}),n.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:nn},children:"Claude Recall"}},{type:"span",props:{style:{fontSize:"18px",color:sn},children:"clauderecall.com"}}]}}),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:LL,padding:"72px 64px",fontFamily:"Inter",gap:"36px"},children:n}}}var LL,ga,Mr,sn,nn,AL,pf=w(()=>{"use strict";LL="#0b0c0f",ga="#15171c",Mr="#e7e9ee",sn="#8b9098",nn="#f97316",AL="#fb923c"});var ba,xf,Y,A,re,Ue,Cf,Lf,Af,Nf,Sa,ya,yt=w(()=>{"use strict";ba=[String.raw` ___ _ _ _ _ ___ ___ ___ ___ ___ _ _ _ `,String.raw` / __| | /_\ | | | | \| __| | _ \ __/ __| /_\ | | | | `,String.raw`| (__| |__ / _ \| |_| | |) | _| | / _| (__ / _ \| |__| |__ `,String.raw` \___|____/_/ \_\\___/|___/|___| |_|_\___\___/_/ \_\____|____|`],xf=ba[0]?.length??64,Y="#f97316",A="#8b9098",re="#10b981",Ue="#f59e0b",Cf="#60a5fa",Lf="#34d399",Af="#c084fc",Nf="CLAUDE RECALL",Sa=100,ya=30});import{useEffect as aA,useState as cA}from"react";import{Box as Of,Text as be}from"ink";import{createRequire as lA}from"node:module";import{existsSync as dA}from"node:fs";import{jsx as ue,jsxs as If}from"react/jsx-runtime";function vf({cols:e}){let[t,n]=cA(mA);aA(()=>{let r=!1,o=ie(),i=0,a=0;if(dA(ee))try{let l=E().prepare(`SELECT
1105
+ WHERE s.project_id = ?`).get(e),_=f.total>0?f.tagged/f.total:0,b=Fn(_),E=Math.round((o*.2+a*.25+u*.15+g*.2+b*.2)*100);return{projectId:e,projectName:n.name,score:E,breakdown:{sessionCount:{raw:r,score:o,weight:.2},recency:{daysSinceLastSession:Math.round(i),score:a,weight:.25},fragmentation:{avgMessages:Math.round(l*10)/10,score:u,weight:.15},searchCoverage:{ratio:Math.round(p*100)/100,score:g,weight:.2},tagCoverage:{ratio:Math.round(_*100)/100,score:b,weight:.2}}}}function na(e){let n=h().prepare("SELECT id FROM projects WHERE name = ?").get(e);return n?ta(n.id):null}function sa(){let t=h().prepare("SELECT id FROM projects ORDER BY name").all(),n=[];for(let s of t){let r=ta(s.id);r&&n.push(r)}return n}var ra=w(()=>{"use strict";k()});function df(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:Mt,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 ht(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:[df(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 Et(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:[df(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 IA(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 MA(e){return e.toLocaleString("en-US")}function bt(e){return e<1e3?String(e):`${IA(e)} (${MA(e)})`}function St(e){return new Date(e).toLocaleDateString("en-US",{month:"long",day:"numeric",year:"numeric"})}var Mt,Un=w(()=>{"use strict";Mt="#f97316"});var pf={};V(pf,{render:()=>PA});function Lr(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:Bn,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:Nr,textTransform:"uppercase",letterSpacing:"0.16em"},children:t}}]}}}function PA(e){let n=[St(e.sessionDate)];e.durationLabel&&n.push(e.durationLabel);let s=n.join(" \xB7 "),r=e.costDollars??"$\u2014",o=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${bt(e.cachedTokens)} cached`:null,i=[ht(uf,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:Bn,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"20px",color:Nr},children:s}}]}},{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:Mt,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:r}},{type:"span",props:{style:{marginTop:"16px",fontSize:"16px",color:Nr,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:600},children:"session cost"}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:$A}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[Lr(String(e.messageCount),"msgs"),Lr(String(e.filesReferenced),"files"),Lr(String(e.toolCallCount),"tools"),Lr(e.model??"\u2014","model")]}}];return o&&i.push({type:"div",props:{style:{fontSize:"14px",color:Nr,fontFamily:"JetBrains Mono",opacity:.7},children:o}}),e.verdict&&i.push({type:"div",props:{style:{display:"flex",fontSize:"24px",fontStyle:"italic",color:Bn,borderLeft:`3px solid ${Mt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),i.push({type:"div",props:{style:{display:"flex",flex:1}}}),i.push(Et(uf)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:DA,padding:"64px 72px",fontFamily:"Inter",gap:"28px"},children:i}}}var DA,Bn,Nr,$A,uf,mf=w(()=>{"use strict";Un();DA="#1a1b1e",Bn="#e7e9ee",Nr="#8b9098",$A="#2a2c33",uf={markStroke:Bn,wordmarkFg:Bn}});var ff={};V(ff,{render:()=>UA});function Or(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:Hn,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:vr,fontFamily:"JetBrains Mono",textTransform:"lowercase"},children:`// ${t}`}}]}}}function UA(e){let t=[St(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),n=e.costDollars??"$\u2014",s=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`# ${bt(e.cachedTokens)} tokens cache-replayed (free)`:null,r=[ht(gf,"recall.cli/share"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"6px"},children:[{type:"div",props:{style:{fontSize:"18px",color:_a,fontFamily:"JetBrains Mono"},children:"$ recall share --session"}},{type:"div",props:{style:{fontSize:"40px",fontWeight:700,color:Hn,lineHeight:1.15,wordBreak:"break-word",fontFamily:"JetBrains Mono"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"18px",color:vr,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:vr,fontFamily:"JetBrains Mono"},children:"> total_cost:"}},{type:"span",props:{style:{fontSize:"180px",fontWeight:700,color:_a,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:n}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:jA}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[Or(String(e.messageCount),"msgs"),Or(String(e.filesReferenced),"files"),Or(String(e.toolCallCount),"tools"),Or(e.model??"\u2014","model")]}}];return s&&r.push({type:"div",props:{style:{fontSize:"14px",color:vr,fontFamily:"JetBrains Mono",opacity:.7},children:s}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"22px",color:Hn,fontFamily:"JetBrains Mono",borderLeft:`3px solid ${_a}`,paddingLeft:"20px",marginTop:"8px"},children:`// ${e.verdict}`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(Et(gf)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:FA,padding:"64px 72px",fontFamily:"Inter",gap:"28px"},children:r}}}var FA,Hn,vr,jA,_a,gf,_f=w(()=>{"use strict";Un();FA="#0d0d0f",Hn="#e1e7ee",vr="#6b7480",jA="#1f2229",_a="#7ee787",gf={markStroke:Hn,wordmarkFg:Hn}});var Ef={};V(Ef,{render:()=>HA});function Ir(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:700,color:Dt,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:Mr,textTransform:"uppercase",letterSpacing:"0.16em",fontWeight:600},children:t}}]}}}function HA(e){let t=[St(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),n=e.costDollars??"$\u2014",s=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${bt(e.cachedTokens)} cached`:null,r=[ht(hf,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:Dt,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"20px",color:Mr},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:Dt,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:n}},{type:"span",props:{style:{marginTop:"16px",fontSize:"16px",color:Mr,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:600},children:"session cost"}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:BA}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[Ir(String(e.messageCount),"msgs"),Ir(String(e.filesReferenced),"files"),Ir(String(e.toolCallCount),"tools"),Ir(e.model??"\u2014","model")]}}];return s&&r.push({type:"div",props:{style:{fontSize:"14px",color:Mr,fontFamily:"JetBrains Mono",opacity:.85},children:s}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"24px",fontStyle:"italic",color:Dt,borderLeft:`3px solid ${Dt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(Et(hf)),{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 Dt,Mr,BA,hf,bf=w(()=>{"use strict";Un();Dt="#ffffff",Mr="rgba(255,255,255,0.7)",BA="rgba(255,255,255,0.18)",hf={markStroke:Dt,wordmarkFg:Dt}});var yf={};V(yf,{render:()=>zA});function Dr(e,t){return{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"4px"},children:[{type:"span",props:{style:{fontSize:"34px",fontWeight:800,color:tn,fontFamily:"JetBrains Mono"},children:e}},{type:"span",props:{style:{fontSize:"14px",color:Wn,textTransform:"uppercase",letterSpacing:"0.16em",fontWeight:600},children:t}}]}}}function JA(e){let t=e.reduce((n,s)=>n+s.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:GA,overflow:"hidden"},children:e.map(n=>({type:"div",props:{style:{display:"flex",width:`${n.value/t*100}%`,height:"100%",backgroundColor:n.color}}}))}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",fontSize:"12px",color:Wn,fontWeight:600,textTransform:"uppercase",letterSpacing:"0.14em"},children:e.map(n=>({type:"span",props:{style:{display:"flex"},children:`${n.label} \xB7 ${n.value}`}}))}}]}}}function zA(e){let t=[St(e.sessionDate),e.durationLabel].filter(Boolean).join(" \xB7 "),n=e.costDollars??"$\u2014",s=typeof e.cachedTokens=="number"&&e.cachedTokens>=1e5?`+ ${bt(e.cachedTokens)} cached`:null,r=[ht(Sf,"session receipt"),{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"40px",fontWeight:700,color:tn,lineHeight:1.15,wordBreak:"break-word"},children:e.sessionTitle}},{type:"div",props:{style:{fontSize:"18px",color:Wn},children:t}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"flex-start",padding:"8px 0"},children:[{type:"span",props:{style:{fontSize:"14px",color:Wn,textTransform:"uppercase",letterSpacing:"0.24em",fontWeight:700},children:"session cost"}},{type:"span",props:{style:{fontSize:"180px",fontWeight:800,color:tn,fontFamily:"JetBrains Mono",lineHeight:1,letterSpacing:"-0.04em"},children:n}}]}},{type:"div",props:{style:{display:"flex",width:"100%",height:"1px",backgroundColor:XA}}},{type:"div",props:{style:{display:"flex",justifyContent:"space-between",gap:"24px"},children:[Dr(String(e.messageCount),"msgs"),Dr(String(e.filesReferenced),"files"),Dr(String(e.toolCallCount),"tools"),Dr(e.model??"\u2014","model")]}},JA([{value:e.messageCount,color:Mt,label:"msgs"},{value:e.filesReferenced,color:"#0a0a0a",label:"files"},{value:e.toolCallCount,color:"#5a6068",label:"tools"}])];return s&&r.push({type:"div",props:{style:{fontSize:"14px",color:Wn,fontFamily:"JetBrains Mono",opacity:.85},children:s}}),e.verdict&&r.push({type:"div",props:{style:{display:"flex",fontSize:"22px",fontStyle:"italic",color:tn,borderLeft:`3px solid ${Mt}`,paddingLeft:"20px",marginTop:"8px"},children:`"${e.verdict}"`}}),r.push({type:"div",props:{style:{display:"flex",flex:1}}}),r.push(Et(Sf)),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:WA,padding:"64px 72px",fontFamily:"Inter",gap:"24px"},children:r}}}var WA,tn,Wn,XA,GA,Sf,wf=w(()=>{"use strict";Un();WA="#f6f7f9",tn="#0a0a0a",Wn="#5a6068",XA="#e3e6eb",GA="#dde1e7",Sf={markStroke:tn,wordmarkFg:tn}});var Tf={};V(Tf,{render:()=>VA});function ha(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:$r},children:t}},{type:"div",props:{style:{fontSize:"16px",color:sn,textTransform:"uppercase",letterSpacing:"2px"},children:e}}]}}}function Ea(e,t){return{type:"div",props:{style:{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"16px 24px",backgroundColor:ba,borderRadius:"12px"},children:[{type:"span",props:{style:{fontSize:"18px",color:sn},children:e}},{type:"span",props:{style:{fontSize:"20px",fontWeight:700,color:$r},children:t}}]}}}function VA(e){let t=Math.round(e.healthScore),n=[{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"8px"},children:[{type:"div",props:{style:{fontSize:"16px",color:sn,textTransform:"uppercase",letterSpacing:"6px"},children:"YOUR MONTH IN CODE"}},{type:"div",props:{style:{fontSize:"44px",fontWeight:700,color:$r},children:e.month}}]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"12px",backgroundColor:ba,borderRadius:"16px",padding:"28px",border:`1px solid ${nn}40`},children:[{type:"div",props:{style:{fontSize:"16px",color:qA,textTransform:"uppercase",letterSpacing:"2px"},children:"You are a"}},{type:"div",props:{style:{fontSize:"36px",fontWeight:700,color:nn},children:e.archetype}}]}},{type:"div",props:{style:{display:"flex",gap:"16px",width:"100%"},children:[ha("Recalls",String(e.totalRecalls)),ha("Tokens piped",e.totalTokensPiped>999999?`${(e.totalTokensPiped/1e6).toFixed(1)}M`:e.totalTokensPiped.toLocaleString()),ha("Sessions",String(e.sessionsIndexed))]}},{type:"div",props:{style:{display:"flex",flexDirection:"column",gap:"8px",width:"100%"},children:[{type:"div",props:{style:{fontSize:"14px",color:sn,textTransform:"uppercase",letterSpacing:"2px",marginBottom:"4px"},children:"Highlights"}},Ea("Most recalled",e.mostRecalledSession),Ea("Biggest recall",`${e.biggestRecallTokens.toLocaleString()} tokens`),Ea("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 ${nn}`,display:"flex",alignItems:"center",justifyContent:"center"},children:{type:"span",props:{style:{fontSize:"32px",fontWeight:700,color:nn},children:`${t}`}}}},{type:"div",props:{style:{fontSize:"14px",color:sn,textTransform:"uppercase",letterSpacing:"2px"},children:"Memory health"}}]}}];return e.verdict&&n.push({type:"div",props:{style:{backgroundColor:ba,borderLeft:`3px solid ${nn}`,borderRadius:"8px",padding:"20px 24px",fontSize:"20px",color:$r,fontStyle:"italic"},children:`"${e.verdict}"`}}),n.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:nn},children:"Claude Recall"}},{type:"span",props:{style:{fontSize:"18px",color:sn},children:"clauderecall.com"}}]}}),{type:"div",props:{style:{display:"flex",flexDirection:"column",width:"100%",height:"100%",backgroundColor:YA,padding:"72px 64px",fontFamily:"Inter",gap:"36px"},children:n}}}var YA,ba,$r,sn,nn,qA,Rf=w(()=>{"use strict";YA="#0b0c0f",ba="#15171c",$r="#e7e9ee",sn="#8b9098",nn="#f97316",qA="#fb923c"});var Ra,Ff,Y,L,oe,Be,jf,Uf,Bf,Hf,ka,xa,yt=w(()=>{"use strict";Ra=[String.raw` ___ _ _ _ _ ___ ___ ___ ___ ___ _ _ _ `,String.raw` / __| | /_\ | | | | \| __| | _ \ __/ __| /_\ | | | | `,String.raw`| (__| |__ / _ \| |_| | |) | _| | / _| (__ / _ \| |__| |__ `,String.raw` \___|____/_/ \_\\___/|___/|___| |_|_\___\___/_/ \_\____|____|`],Ff=Ra[0]?.length??64,Y="#f97316",L="#8b9098",oe="#10b981",Be="#f59e0b",jf="#60a5fa",Uf="#34d399",Bf="#c084fc",Hf="CLAUDE RECALL",ka=100,xa=30});import{useEffect as CL,useState as AL}from"react";import{Box as Wf,Text as be}from"ink";import{createRequire as LL}from"node:module";import{existsSync as NL}from"node:fs";import{jsx as ue,jsxs as Gf}from"react/jsx-runtime";function Xf({cols:e}){let[t,n]=AL(IL);CL(()=>{let r=!1,o=se(),i=0,a=0;if(NL(ee))try{let l=h().prepare(`SELECT
1101
1106
  (SELECT COUNT(*) FROM sessions) AS sessions,
1102
- (SELECT COUNT(*) FROM projects) AS projects`).get();i=l.sessions,a=l.projects}catch{}return n(d=>({...d,daemon:o,sessions:i,projects:a})),Le().then(d=>{r||n(l=>({...l,tier:d.tier}))}).catch(()=>{}),()=>{r=!0}},[]);let s=e>=xf+2;return If(Of,{flexDirection:"column",children:[s?ba.map((r,o)=>ue(be,{color:Y,bold:!0,children:r},o)):ue(be,{color:Y,bold:!0,children:Nf}),ue(gA,{state:t})]})}function gA({state:e}){let t=ue(be,{color:A,children:" \xB7 "});return If(Of,{children:[ue(be,{color:A,children:"v"}),ue(be,{color:Y,children:pA}),t,ue(be,{color:A,children:"daemon: "}),e.daemon?ue(be,{color:re,children:`running 127.0.0.1:${e.daemon.port}`}):ue(be,{color:Ue,children:"stopped"}),t,ue(be,{color:A,children:"sessions: "}),ue(be,{color:Y,children:e.sessions}),e.projects>0?ue(be,{color:A,children:` across ${e.projects} ${e.projects===1?"project":"projects"}`}):null,t,ue(be,{color:A,children:"license: "}),e.tier==="pro"?ue(be,{color:re,children:"Pro"}):ue(be,{color:A,children:"Free"})]})}var uA,pA,mA,Mf=w(()=>{"use strict";Xe();I();k();ge();yt();uA=lA(import.meta.url),pA=uA("../../../package.json").version,mA={daemon:null,sessions:0,projects:0,tier:"free"}});import{Box as ct,Text as pe}from"ink";import{jsx as q,jsxs as Pr}from"react/jsx-runtime";function _A(e,t,n){if(t<=n)return{start:0,end:t};let s=e-Math.floor(n/2);return s<0&&(s=0),s+n>t&&(s=t-n),{start:s,end:s+n}}function wt(e,t){if(t<=0)return"";let n=e.replace(/\s+/g," ").trim();return n.length<=t?n:n.slice(0,Math.max(0,t-1))+"\u2026"}function Df({sessions:e,total:t,selected:n,width:s,height:r,loading:o,dbExists:i,filter:a,sortMode:d,groupByProject:l}){let u=Math.max(20,s-2),g=Math.max(1,r-1-1-2),f=_A(n,e.length,g),h=e.slice(f.start,f.end);if(!i)return Pr(ct,{flexDirection:"column",width:s,height:r,borderStyle:"round",borderColor:A,children:[q(pe,{color:Y,bold:!0,children:" Sessions "}),q(ct,{paddingX:1,paddingY:1,children:q(pe,{color:A,wrap:"wrap",children:"No sessions indexed yet. Quit (q) and run `recall index` first."})})]});let S=[fA[d],l?"grouped":""].filter(Boolean).join(" \xB7 "),y=o?" Sessions \xB7 loading\u2026 ":a?` Sessions \xB7 ${e.length} of ${t} match "${wt(a,18)}" \xB7 ${S} `:` Sessions \xB7 ${e.length} of ${t} \xB7 ${S} `,T=null;return l&&f.start>0&&(T=e[f.start-1]?.project_name??null),Pr(ct,{flexDirection:"column",width:s,height:r,borderStyle:"round",borderColor:A,children:[q(ct,{width:u+2,paddingLeft:1,children:q(pe,{color:Y,bold:!0,children:wt(y,u)})}),q(ct,{flexDirection:"column",flexGrow:1,paddingX:1,children:h.length===0?q(pe,{color:A,children:a?"no matches.":"no sessions."}):h.flatMap((R,B)=>{let L=f.start+B,v=L===n,O=[];return l&&R.project_name!==T&&(O.push(q(EA,{project:R.project_name,width:u},`hdr-${R.project_name}-${L}`)),T=R.project_name),O.push(q(hA,{session:R,width:u,isSelected:v,indented:l},R.id)),O})}),q(ct,{width:u+2,paddingLeft:1,children:q(pe,{color:A,children:e.length>0?wt(` ${n+1} / ${e.length}${f.end<e.length?" \xB7 scroll for more":""} `,u):""})})]})}function hA({session:e,width:t,isSelected:n,indented:s}){let r=G(e.started_at)||"",o=s?" ":"",i=n?"\u258C ":" ";if(s){let g=e.alias||e.auto_title||e.first_user_message||"(no title)",f=Math.min(14,Math.max(6,Math.floor(t*.25))),h=Math.max(10,t-i.length-o.length-f-1),_=wt(g,h),b=wt(r,f),S=Math.max(1,t-i.length-o.length-_.length-b.length);return Pr(ct,{children:[q(pe,{children:o}),q(pe,{color:n?Y:A,bold:n,children:i}),q(pe,{color:n?Y:"#fefce8",bold:n,children:_}),q(pe,{children:" ".repeat(S)}),q(pe,{color:A,children:b})]})}let a=e.project_name||"?",d=Math.min(28,Math.floor(t*.7)),l=Math.min(14,t-d-i.length-1),u=wt(a,d),m=wt(r,l),p=Math.max(1,t-i.length-u.length-m.length);return Pr(ct,{children:[q(pe,{color:n?Y:A,bold:n,children:i}),q(pe,{color:n?Y:"#67e8f9",bold:n,children:u}),q(pe,{children:" ".repeat(p)}),q(pe,{color:A,children:m})]})}function EA({project:e,width:t}){return q(ct,{children:q(pe,{color:"#67e8f9",bold:!0,children:wt(`\u25BE ${e}`,t)})})}var fA,$f=w(()=>{"use strict";$();yt();fA={recent:"recent",longest:"longest",busiest:"busiest project"}});import{useEffect as bA,useState as wa}from"react";function Pf(e,t,n){let s=n?"":"AND is_sidechain = 0";return e.prepare(`SELECT uuid, role, type, timestamp, content_text
1107
+ (SELECT COUNT(*) FROM projects) AS projects`).get();i=l.sessions,a=l.projects}catch{}return n(d=>({...d,daemon:o,sessions:i,projects:a})),Ae().then(d=>{r||n(l=>({...l,tier:d.tier}))}).catch(()=>{}),()=>{r=!0}},[]);let s=e>=Ff+2;return Gf(Wf,{flexDirection:"column",children:[s?Ra.map((r,o)=>ue(be,{color:Y,bold:!0,children:r},o)):ue(be,{color:Y,bold:!0,children:Hf}),ue(ML,{state:t})]})}function ML({state:e}){let t=ue(be,{color:L,children:" \xB7 "});return Gf(Wf,{children:[ue(be,{color:L,children:"v"}),ue(be,{color:Y,children:vL}),t,ue(be,{color:L,children:"daemon: "}),e.daemon?ue(be,{color:oe,children:`running 127.0.0.1:${e.daemon.port}`}):ue(be,{color:Be,children:"stopped"}),t,ue(be,{color:L,children:"sessions: "}),ue(be,{color:Y,children:e.sessions}),e.projects>0?ue(be,{color:L,children:` across ${e.projects} ${e.projects===1?"project":"projects"}`}):null,t,ue(be,{color:L,children:"license: "}),e.tier==="pro"?ue(be,{color:oe,children:"Pro"}):ue(be,{color:L,children:"Free"})]})}var OL,vL,IL,Jf=w(()=>{"use strict";De();I();k();ge();yt();OL=LL(import.meta.url),vL=OL("../../../package.json").version,IL={daemon:null,sessions:0,projects:0,tier:"free"}});import{Box as ct,Text as pe}from"ink";import{jsx as q,jsxs as jr}from"react/jsx-runtime";function $L(e,t,n){if(t<=n)return{start:0,end:t};let s=e-Math.floor(n/2);return s<0&&(s=0),s+n>t&&(s=t-n),{start:s,end:s+n}}function wt(e,t){if(t<=0)return"";let n=e.replace(/\s+/g," ").trim();return n.length<=t?n:n.slice(0,Math.max(0,t-1))+"\u2026"}function zf({sessions:e,total:t,selected:n,width:s,height:r,loading:o,dbExists:i,filter:a,sortMode:d,groupByProject:l}){let u=Math.max(20,s-2),g=Math.max(1,r-1-1-2),f=$L(n,e.length,g),_=e.slice(f.start,f.end);if(!i)return jr(ct,{flexDirection:"column",width:s,height:r,borderStyle:"round",borderColor:L,children:[q(pe,{color:Y,bold:!0,children:" Sessions "}),q(ct,{paddingX:1,paddingY:1,children:q(pe,{color:L,wrap:"wrap",children:"No sessions indexed yet. Quit (q) and run `recall index` first."})})]});let S=[DL[d],l?"grouped":""].filter(Boolean).join(" \xB7 "),y=o?" Sessions \xB7 loading\u2026 ":a?` Sessions \xB7 ${e.length} of ${t} match "${wt(a,18)}" \xB7 ${S} `:` Sessions \xB7 ${e.length} of ${t} \xB7 ${S} `,T=null;return l&&f.start>0&&(T=e[f.start-1]?.project_name??null),jr(ct,{flexDirection:"column",width:s,height:r,borderStyle:"round",borderColor:L,children:[q(ct,{width:u+2,paddingLeft:1,children:q(pe,{color:Y,bold:!0,children:wt(y,u)})}),q(ct,{flexDirection:"column",flexGrow:1,paddingX:1,children:_.length===0?q(pe,{color:L,children:a?"no matches.":"no sessions."}):_.flatMap((R,B)=>{let A=f.start+B,v=A===n,O=[];return l&&R.project_name!==T&&(O.push(q(FL,{project:R.project_name,width:u},`hdr-${R.project_name}-${A}`)),T=R.project_name),O.push(q(PL,{session:R,width:u,isSelected:v,indented:l},R.id)),O})}),q(ct,{width:u+2,paddingLeft:1,children:q(pe,{color:L,children:e.length>0?wt(` ${n+1} / ${e.length}${f.end<e.length?" \xB7 scroll for more":""} `,u):""})})]})}function PL({session:e,width:t,isSelected:n,indented:s}){let r=G(e.started_at)||"",o=s?" ":"",i=n?"\u258C ":" ";if(s){let g=e.alias||e.auto_title||e.first_user_message||"(no title)",f=Math.min(14,Math.max(6,Math.floor(t*.25))),_=Math.max(10,t-i.length-o.length-f-1),b=wt(g,_),E=wt(r,f),S=Math.max(1,t-i.length-o.length-b.length-E.length);return jr(ct,{children:[q(pe,{children:o}),q(pe,{color:n?Y:L,bold:n,children:i}),q(pe,{color:n?Y:"#fefce8",bold:n,children:b}),q(pe,{children:" ".repeat(S)}),q(pe,{color:L,children:E})]})}let a=e.project_name||"?",d=Math.min(28,Math.floor(t*.7)),l=Math.min(14,t-d-i.length-1),u=wt(a,d),m=wt(r,l),p=Math.max(1,t-i.length-u.length-m.length);return jr(ct,{children:[q(pe,{color:n?Y:L,bold:n,children:i}),q(pe,{color:n?Y:"#67e8f9",bold:n,children:u}),q(pe,{children:" ".repeat(p)}),q(pe,{color:L,children:m})]})}function FL({project:e,width:t}){return q(ct,{children:q(pe,{color:"#67e8f9",bold:!0,children:wt(`\u25BE ${e}`,t)})})}var DL,Yf=w(()=>{"use strict";D();yt();DL={recent:"recent",longest:"longest",busiest:"busiest project"}});import{useEffect as jL,useState as Ca}from"react";function qf(e,t,n){let s=n?"":"AND is_sidechain = 0";return e.prepare(`SELECT uuid, role, type, timestamp, content_text
1103
1108
  FROM messages
1104
1109
  WHERE session_id = @id
1105
1110
  ${s}
1106
1111
  ORDER BY timestamp DESC
1107
- LIMIT @limit`).all({id:t,limit:SA})}function Ff(e){let[t,n]=wa([]),[s,r]=wa(!1),[o,i]=wa(!1);return bA(()=>{if(!e){n([]),i(!1);return}r(!0);try{let a=E(),d=Pf(a,e,!1),l=!1;d.length===0&&(d=Pf(a,e,!0),l=d.length>0),n([...d].reverse()),i(l)}catch{n([]),i(!1)}finally{r(!1)}},[e]),{messages:t,loading:s,fallbackToSidechain:o}}var SA,jf=w(()=>{"use strict";k();SA=6});import{Box as Be,Text as Qe}from"ink";import{Fragment as RA,jsx as se,jsxs as on}from"react/jsx-runtime";function yA(e){let t=(e.role??"").toLowerCase();return t==="user"?{label:"user",color:Cf}:t==="assistant"?{label:"asst",color:Lf}:t==="tool"?{label:"tool",color:Af}:t==="system"?{label:"sys ",color:A}:e.type==="summary"?{label:"sum ",color:A}:{label:"----",color:A}}function wA(e,t){return e?e.replace(/\s+/g," ").trim().slice(0,t+1).replace(/.{1}$/,n=>e.length>t?"\u2026":n):"(empty)"}function Uf({session:e,width:t,height:n}){let s=e?.id??null,{messages:r,loading:o,fallbackToSidechain:i}=Ff(s),a=Math.max(20,t-2),l=Math.max(4,n-2-2),u=Math.max(2,Math.floor(l/Math.max(1,r.length)));return e?on(Be,{flexDirection:"column",width:t,height:n,borderStyle:"round",borderColor:A,children:[on(Be,{paddingX:1,flexDirection:"column",children:[se(Be,{width:a,children:se(Qe,{color:Y,bold:!0,wrap:"truncate-end",children:e.alias||e.auto_title||e.first_user_message||"(no title)"})}),se(Be,{width:a,children:se(Qe,{color:A,wrap:"truncate-end",children:`${e.id.slice(0,8)} \xB7 ${e.message_count} msgs \xB7 ${G(e.started_at)}`})})]}),se(Be,{flexDirection:"column",paddingX:1,flexGrow:1,children:o?se(Qe,{color:A,children:"loading messages\u2026"}):r.length===0?se(Qe,{color:A,children:"no messages indexed for this session."}):on(RA,{children:[i?se(Qe,{color:A,children:"(showing sidechain / subagent messages)"}):null,r.map(m=>se(TA,{message:m,width:a,perMessageLines:u},m.uuid))]})})]}):on(Be,{flexDirection:"column",width:t,height:n,borderStyle:"round",borderColor:A,children:[se(Be,{paddingX:1,children:se(Qe,{color:Y,bold:!0,children:"Preview"})}),se(Be,{paddingX:1,paddingY:1,children:se(Qe,{color:A,children:"Select a session on the left to preview."})})]})}function TA({message:e,width:t,perMessageLines:n}){let s=yA(e),r=Math.max(1,n-1),o=Math.max(20,t-2),i=r*o,a=wA(e.content_text,i);return on(Be,{flexDirection:"column",marginBottom:0,children:[on(Be,{children:[se(Qe,{color:s.color,bold:!0,children:s.label}),se(Qe,{color:A,children:` ${e.timestamp?G(e.timestamp):""}`})]}),se(Be,{width:t,children:se(Qe,{wrap:"truncate-end",children:a})})]})}var Bf=w(()=>{"use strict";$();jf();yt()});import{useMemo as kA}from"react";import{Box as He,Text as Tt}from"ink";import{jsx as Se,jsxs as Wn}from"react/jsx-runtime";function xA(e,t){try{return{ok:!0,result:dr(e,{budget:t})}}catch(n){return{ok:!1,error:n instanceof Error?n.message:String(n)}}}function Hf({session:e,width:t,height:n,budget:s}){let r=kA(()=>e?xA(e.id,s):null,[e?.id,s]),o=Math.max(20,t-2),a=Math.max(4,n-2-2);if(!e)return Wn(He,{flexDirection:"column",width:t,height:n,borderStyle:"round",borderColor:A,children:[Se(He,{paddingX:1,children:Se(Tt,{color:Y,bold:!0,children:"Neighborhood"})}),Se(He,{paddingX:1,paddingY:1,children:Se(Tt,{color:A,children:"Select a session and press `n` to assemble its neighborhood."})})]});if(!r)return null;if(!r.ok)return Wn(He,{flexDirection:"column",width:t,height:n,borderStyle:"round",borderColor:Ue,children:[Se(He,{paddingX:1,children:Se(Tt,{color:Ue,bold:!0,children:"Neighborhood error"})}),Se(He,{paddingX:1,paddingY:1,children:Se(Tt,{color:Ue,children:r.error})})]});let{result:d}=r,l=d.bundle.replace(/\n+$/,"").split(`
1108
- `),u=l.slice(0,Math.max(1,a-1)),m=l.length-u.length;return Wn(He,{flexDirection:"column",width:t,height:n,borderStyle:"round",borderColor:re,children:[Wn(He,{paddingX:1,flexDirection:"column",children:[Se(He,{width:o,children:Se(Tt,{color:re,bold:!0,wrap:"truncate-end",children:"Neighborhood"})}),Se(He,{width:o,children:Se(Tt,{color:A,wrap:"truncate-end",children:`budget=${s} used=${d.budgetUsed} remaining=${d.budgetRemaining} truncated=${d.truncated.length}`})})]}),Wn(He,{flexDirection:"column",paddingX:1,flexGrow:1,children:[u.map((p,g)=>Se(Tt,{wrap:"truncate-end",children:p||" "},g)),m>0?Se(Tt,{color:A,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 Wf=w(()=>{"use strict";ji();yt()});import{useEffect as CA,useState as Xf}from"react";import{Box as Xn,Text as Rt}from"ink";import Ta from"ink-text-input";import{jsx as ke,jsxs as Ra}from"react/jsx-runtime";function Gf({mode:e,query:t,onQueryChange:n,onSearchSubmit:s,onAliasSubmit:r,onTagSubmit:o,aliasInitial:i,toast:a}){let[d,l]=Xf(""),[u,m]=Xf("");return CA(()=>{e==="alias"&&l(i),e==="tag"&&m("")},[e,i]),a&&e==="normal"?ke(Xn,{children:ke(Rt,{color:Ue,children:`\u25B6 ${a}`})}):e==="search"?Ra(Xn,{children:[ke(Rt,{color:Y,bold:!0,children:"/ "}),ke(Ta,{value:t,onChange:n,onSubmit:s,placeholder:"filter sessions by project, alias, or opening message..."}),ke(Rt,{color:A,children:" esc clear \xB7 enter confirm"})]}):e==="alias"?Ra(Xn,{children:[ke(Rt,{color:re,bold:!0,children:"alias \u203A "}),ke(Ta,{value:d,onChange:l,onSubmit:p=>r(p),placeholder:"terminal-tab name for this session"}),ke(Rt,{color:A,children:" esc cancel \xB7 enter save"})]}):e==="tag"?Ra(Xn,{children:[ke(Rt,{color:re,bold:!0,children:"tag \u203A "}),ke(Ta,{value:u,onChange:m,onSubmit:p=>o(p),placeholder:"add a tag to this session"}),ke(Rt,{color:A,children:" esc cancel \xB7 enter save"})]}):ke(Xn,{children:ke(Rt,{color:A,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 zf=w(()=>{"use strict";yt()});import{Box as ye,Text as W}from"ink";import{jsx as U,jsxs as xe}from"react/jsx-runtime";function Jf({width:e,height:t}){return xe(ye,{flexDirection:"column",width:e,height:t,borderStyle:"round",borderColor:Y,paddingX:2,paddingY:1,children:[xe(ye,{children:[U(W,{color:Y,bold:!0,children:"Claude Recall TUI \u2014 Help"}),U(W,{color:A,children:" \xB7 press ? or esc to close"})]}),xe(ye,{marginTop:1,flexDirection:"column",children:[U(W,{color:re,bold:!0,children:"Navigation"}),LA.map(n=>U(ka,{row:n},n.key))]}),xe(ye,{marginTop:1,flexDirection:"column",children:[U(W,{color:re,bold:!0,children:"Actions on the selected session"}),AA.map(n=>U(ka,{row:n},n.key))]}),xe(ye,{marginTop:1,flexDirection:"column",children:[U(W,{color:re,bold:!0,children:"Right-pane views"}),NA.map(n=>U(ka,{row:n},n.key))]}),xe(ye,{marginTop:1,flexDirection:"column",children:[U(W,{color:re,bold:!0,children:"What is Neighborhood?"}),U(W,{color:A,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."})]}),xe(ye,{marginTop:1,flexDirection:"column",children:[U(W,{color:re,bold:!0,children:"Maintenance & diagnostics"}),U(W,{color:A,wrap:"wrap",children:"Two commands cover everything. Quit the TUI with `q` first, then:"}),xe(ye,{marginTop:1,children:[U(W,{color:A,children:" \u2022 "}),U(W,{children:"recall doctor"})]}),U(W,{color:A,wrap:"wrap",children:" Health report: DB size, WAL, FTS fragmentation, integrity, disk free."}),U(W,{color:A,wrap:"wrap",children:" Run this first if anything feels slow or wrong. Add --json for machine output."}),xe(ye,{marginTop:1,children:[U(W,{color:A,children:" \u2022 "}),U(W,{children:"recall optimize"})]}),U(W,{color:A,wrap:"wrap",children:" Maintenance: WAL truncate + FTS5 merge + planner stats. Safe while daemon is running."}),U(W,{color:A,wrap:"wrap",children:" Add --vacuum (with daemon stopped) to also reclaim disk pages from deleted rows."})]}),xe(ye,{marginTop:1,flexDirection:"column",children:[U(W,{color:re,bold:!0,children:"How to pipe a session into Claude"}),U(W,{color:A,wrap:"wrap",children:"Two recipes. Both work in any shell \u2014 exit this TUI with `q` first, then run them."}),xe(ye,{marginTop:1,children:[U(W,{color:A,children:" 1. "}),U(W,{children:"recall context <id> | claude"})]}),U(W,{color:A,wrap:"wrap",children:" Pipes one session's full transcript as markdown into a fresh `claude` chat."}),U(W,{color:A,wrap:"wrap",children:" Use when you want to continue exactly where one session left off."}),xe(ye,{marginTop:1,children:[U(W,{color:A,children:" 2. "}),U(W,{children:"recall neighborhood <id> | claude"})]}),U(W,{color:A,wrap:"wrap",children:" Pipes the bundle (parents + children + citations + similar + bug matches)."}),U(W,{color:A,wrap:"wrap",children:" Use when you want broader context, not just one transcript."})]})]})}function ka({row:e}){return xe(ye,{children:[U(ye,{width:16,children:U(W,{color:Y,children:e.key})}),U(W,{color:A,wrap:"truncate-end",children:e.description})]})}var LA,AA,NA,Yf=w(()=>{"use strict";yt();LA=[{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"}],AA=[{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)"}],NA=[{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 OA,useMemo as vA,useState as Fr}from"react";import{existsSync as IA}from"node:fs";function qf(e){let[t,n]=Fr([]),[s,r]=Fr(!0),[o,i]=Fr(null),[a,d]=Fr(!0);return OA(()=>{if(!IA(ee)){d(!1),r(!1);return}try{let m=E().prepare(`SELECT s.id, p.name AS project_name, s.started_at,
1112
+ LIMIT @limit`).all({id:t,limit:UL})}function Vf(e){let[t,n]=Ca([]),[s,r]=Ca(!1),[o,i]=Ca(!1);return jL(()=>{if(!e){n([]),i(!1);return}r(!0);try{let a=h(),d=qf(a,e,!1),l=!1;d.length===0&&(d=qf(a,e,!0),l=d.length>0),n([...d].reverse()),i(l)}catch{n([]),i(!1)}finally{r(!1)}},[e]),{messages:t,loading:s,fallbackToSidechain:o}}var UL,Kf=w(()=>{"use strict";k();UL=6});import{Box as He,Text as Qe}from"ink";import{Fragment as XL,jsx as re,jsxs as on}from"react/jsx-runtime";function BL(e){let t=(e.role??"").toLowerCase();return t==="user"?{label:"user",color:jf}:t==="assistant"?{label:"asst",color:Uf}:t==="tool"?{label:"tool",color:Bf}:t==="system"?{label:"sys ",color:L}:e.type==="summary"?{label:"sum ",color:L}:{label:"----",color:L}}function HL(e,t){return e?e.replace(/\s+/g," ").trim().slice(0,t+1).replace(/.{1}$/,n=>e.length>t?"\u2026":n):"(empty)"}function Qf({session:e,width:t,height:n}){let s=e?.id??null,{messages:r,loading:o,fallbackToSidechain:i}=Vf(s),a=Math.max(20,t-2),l=Math.max(4,n-2-2),u=Math.max(2,Math.floor(l/Math.max(1,r.length)));return e?on(He,{flexDirection:"column",width:t,height:n,borderStyle:"round",borderColor:L,children:[on(He,{paddingX:1,flexDirection:"column",children:[re(He,{width:a,children:re(Qe,{color:Y,bold:!0,wrap:"truncate-end",children:e.alias||e.auto_title||e.first_user_message||"(no title)"})}),re(He,{width:a,children:re(Qe,{color:L,wrap:"truncate-end",children:`${e.id.slice(0,8)} \xB7 ${e.message_count} msgs \xB7 ${G(e.started_at)}`})})]}),re(He,{flexDirection:"column",paddingX:1,flexGrow:1,children:o?re(Qe,{color:L,children:"loading messages\u2026"}):r.length===0?re(Qe,{color:L,children:"no messages indexed for this session."}):on(XL,{children:[i?re(Qe,{color:L,children:"(showing sidechain / subagent messages)"}):null,r.map(m=>re(WL,{message:m,width:a,perMessageLines:u},m.uuid))]})})]}):on(He,{flexDirection:"column",width:t,height:n,borderStyle:"round",borderColor:L,children:[re(He,{paddingX:1,children:re(Qe,{color:Y,bold:!0,children:"Preview"})}),re(He,{paddingX:1,paddingY:1,children:re(Qe,{color:L,children:"Select a session on the left to preview."})})]})}function WL({message:e,width:t,perMessageLines:n}){let s=BL(e),r=Math.max(1,n-1),o=Math.max(20,t-2),i=r*o,a=HL(e.content_text,i);return on(He,{flexDirection:"column",marginBottom:0,children:[on(He,{children:[re(Qe,{color:s.color,bold:!0,children:s.label}),re(Qe,{color:L,children:` ${e.timestamp?G(e.timestamp):""}`})]}),re(He,{width:t,children:re(Qe,{wrap:"truncate-end",children:a})})]})}var Zf=w(()=>{"use strict";D();Kf();yt()});import{useMemo as GL}from"react";import{Box as We,Text as Tt}from"ink";import{jsx as Se,jsxs as Xn}from"react/jsx-runtime";function JL(e,t){try{return{ok:!0,result:pr(e,{budget:t})}}catch(n){return{ok:!1,error:n instanceof Error?n.message:String(n)}}}function e_({session:e,width:t,height:n,budget:s}){let r=GL(()=>e?JL(e.id,s):null,[e?.id,s]),o=Math.max(20,t-2),a=Math.max(4,n-2-2);if(!e)return Xn(We,{flexDirection:"column",width:t,height:n,borderStyle:"round",borderColor:L,children:[Se(We,{paddingX:1,children:Se(Tt,{color:Y,bold:!0,children:"Neighborhood"})}),Se(We,{paddingX:1,paddingY:1,children:Se(Tt,{color:L,children:"Select a session and press `n` to assemble its neighborhood."})})]});if(!r)return null;if(!r.ok)return Xn(We,{flexDirection:"column",width:t,height:n,borderStyle:"round",borderColor:Be,children:[Se(We,{paddingX:1,children:Se(Tt,{color:Be,bold:!0,children:"Neighborhood error"})}),Se(We,{paddingX:1,paddingY:1,children:Se(Tt,{color:Be,children:r.error})})]});let{result:d}=r,l=d.bundle.replace(/\n+$/,"").split(`
1113
+ `),u=l.slice(0,Math.max(1,a-1)),m=l.length-u.length;return Xn(We,{flexDirection:"column",width:t,height:n,borderStyle:"round",borderColor:oe,children:[Xn(We,{paddingX:1,flexDirection:"column",children:[Se(We,{width:o,children:Se(Tt,{color:oe,bold:!0,wrap:"truncate-end",children:"Neighborhood"})}),Se(We,{width:o,children:Se(Tt,{color:L,wrap:"truncate-end",children:`budget=${s} used=${d.budgetUsed} remaining=${d.budgetRemaining} truncated=${d.truncated.length}`})})]}),Xn(We,{flexDirection:"column",paddingX:1,flexGrow:1,children:[u.map((p,g)=>Se(Tt,{wrap:"truncate-end",children:p||" "},g)),m>0?Se(Tt,{color:L,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 t_=w(()=>{"use strict";Xi();yt()});import{useEffect as zL,useState as n_}from"react";import{Box as Gn,Text as Rt}from"ink";import Aa from"ink-text-input";import{jsx as ke,jsxs as La}from"react/jsx-runtime";function s_({mode:e,query:t,onQueryChange:n,onSearchSubmit:s,onAliasSubmit:r,onTagSubmit:o,aliasInitial:i,toast:a}){let[d,l]=n_(""),[u,m]=n_("");return zL(()=>{e==="alias"&&l(i),e==="tag"&&m("")},[e,i]),a&&e==="normal"?ke(Gn,{children:ke(Rt,{color:Be,children:`\u25B6 ${a}`})}):e==="search"?La(Gn,{children:[ke(Rt,{color:Y,bold:!0,children:"/ "}),ke(Aa,{value:t,onChange:n,onSubmit:s,placeholder:"filter sessions by project, alias, or opening message..."}),ke(Rt,{color:L,children:" esc clear \xB7 enter confirm"})]}):e==="alias"?La(Gn,{children:[ke(Rt,{color:oe,bold:!0,children:"alias \u203A "}),ke(Aa,{value:d,onChange:l,onSubmit:p=>r(p),placeholder:"terminal-tab name for this session"}),ke(Rt,{color:L,children:" esc cancel \xB7 enter save"})]}):e==="tag"?La(Gn,{children:[ke(Rt,{color:oe,bold:!0,children:"tag \u203A "}),ke(Aa,{value:u,onChange:m,onSubmit:p=>o(p),placeholder:"add a tag to this session"}),ke(Rt,{color:L,children:" esc cancel \xB7 enter save"})]}):ke(Gn,{children:ke(Rt,{color:L,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 r_=w(()=>{"use strict";yt()});import{Box as ye,Text as W}from"ink";import{jsx as U,jsxs as xe}from"react/jsx-runtime";function o_({width:e,height:t}){return xe(ye,{flexDirection:"column",width:e,height:t,borderStyle:"round",borderColor:Y,paddingX:2,paddingY:1,children:[xe(ye,{children:[U(W,{color:Y,bold:!0,children:"Claude Recall TUI \u2014 Help"}),U(W,{color:L,children:" \xB7 press ? or esc to close"})]}),xe(ye,{marginTop:1,flexDirection:"column",children:[U(W,{color:oe,bold:!0,children:"Navigation"}),YL.map(n=>U(Na,{row:n},n.key))]}),xe(ye,{marginTop:1,flexDirection:"column",children:[U(W,{color:oe,bold:!0,children:"Actions on the selected session"}),qL.map(n=>U(Na,{row:n},n.key))]}),xe(ye,{marginTop:1,flexDirection:"column",children:[U(W,{color:oe,bold:!0,children:"Right-pane views"}),VL.map(n=>U(Na,{row:n},n.key))]}),xe(ye,{marginTop:1,flexDirection:"column",children:[U(W,{color:oe,bold:!0,children:"What is Neighborhood?"}),U(W,{color:L,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."})]}),xe(ye,{marginTop:1,flexDirection:"column",children:[U(W,{color:oe,bold:!0,children:"Maintenance & diagnostics"}),U(W,{color:L,wrap:"wrap",children:"Two commands cover everything. Quit the TUI with `q` first, then:"}),xe(ye,{marginTop:1,children:[U(W,{color:L,children:" \u2022 "}),U(W,{children:"recall doctor"})]}),U(W,{color:L,wrap:"wrap",children:" Health report: DB size, WAL, FTS fragmentation, integrity, disk free."}),U(W,{color:L,wrap:"wrap",children:" Run this first if anything feels slow or wrong. Add --json for machine output."}),xe(ye,{marginTop:1,children:[U(W,{color:L,children:" \u2022 "}),U(W,{children:"recall optimize"})]}),U(W,{color:L,wrap:"wrap",children:" Maintenance: WAL truncate + FTS5 merge + planner stats. Safe while daemon is running."}),U(W,{color:L,wrap:"wrap",children:" Add --vacuum (with daemon stopped) to also reclaim disk pages from deleted rows."})]}),xe(ye,{marginTop:1,flexDirection:"column",children:[U(W,{color:oe,bold:!0,children:"How to pipe a session into Claude"}),U(W,{color:L,wrap:"wrap",children:"Two recipes. Both work in any shell \u2014 exit this TUI with `q` first, then run them."}),xe(ye,{marginTop:1,children:[U(W,{color:L,children:" 1. "}),U(W,{children:"recall context <id> | claude"})]}),U(W,{color:L,wrap:"wrap",children:" Pipes one session's full transcript as markdown into a fresh `claude` chat."}),U(W,{color:L,wrap:"wrap",children:" Use when you want to continue exactly where one session left off."}),xe(ye,{marginTop:1,children:[U(W,{color:L,children:" 2. "}),U(W,{children:"recall neighborhood <id> | claude"})]}),U(W,{color:L,wrap:"wrap",children:" Pipes the bundle (parents + children + citations + similar + bug matches)."}),U(W,{color:L,wrap:"wrap",children:" Use when you want broader context, not just one transcript."})]})]})}function Na({row:e}){return xe(ye,{children:[U(ye,{width:16,children:U(W,{color:Y,children:e.key})}),U(W,{color:L,wrap:"truncate-end",children:e.description})]})}var YL,qL,VL,i_=w(()=>{"use strict";yt();YL=[{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"}],qL=[{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)"}],VL=[{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 KL,useMemo as QL,useState as Ur}from"react";import{existsSync as ZL}from"node:fs";function a_(e){let[t,n]=Ur([]),[s,r]=Ur(!0),[o,i]=Ur(null),[a,d]=Ur(!0);return KL(()=>{if(!ZL(ee)){d(!1),r(!1);return}try{let m=h().prepare(`SELECT s.id, p.name AS project_name, s.started_at,
1109
1114
  s.message_count, s.first_user_message,
1110
1115
  NULLIF(sa.alias, '') AS alias,
1111
1116
  s.auto_title
@@ -1117,7 +1122,7 @@ CREATE VIRTUAL TABLE IF NOT EXISTS vec_chunks_v2 USING vec0(
1117
1122
  AND COALESCE(s.auto_title, '') NOT LIKE '[output-index]%'
1118
1123
  AND COALESCE(s.auto_title, '') NOT LIKE '[skill]%'
1119
1124
  ORDER BY COALESCE(s.started_at, '') DESC
1120
- LIMIT @limit`).all({limit:MA});n(m)}catch(u){i(u instanceof Error?u.message:String(u))}finally{r(!1)}},[]),{sessions:vA(()=>{let u=e.trim().toLowerCase();return u?t.filter(m=>{let p=m.project_name?.toLowerCase()??"",g=m.first_user_message?.toLowerCase()??"";return p.includes(u)||g.includes(u)}):t},[t,e]),total:t.length,loading:s,error:o,dbExists:a}}var MA,Vf=w(()=>{"use strict";k();I();MA=200});import{useEffect as xa,useMemo as DA,useState as Ze}from"react";import{Box as kt,Text as jr,useApp as $A,useInput as PA}from"ink";import{spawn as FA}from"node:child_process";import{platform as Ur}from"node:os";import{jsx as me,jsxs as La}from"react/jsx-runtime";function Qf(){return{cols:process.stdout.columns??100,rows:process.stdout.rows??30}}function WA(e){let t=Ur()==="darwin"?"open":Ur()==="win32"?"start":"xdg-open",n=Ur()==="win32"?["",e]:[e];FA(t,n,{detached:!0,stdio:"ignore",shell:Ur()==="win32"}).unref()}function Zf({onShowSession:e}){let{exit:t}=$A(),n=Qf(),[s,r]=Ze(n.cols),[o,i]=Ze(n.rows),[a,d]=Ze(0),[l,u]=Ze(""),[m,p]=Ze("normal"),[g,f]=Ze(null),[h,_]=Ze("preview"),[b,S]=Ze("recent"),[y,T]=Ze(!1),[R,B]=Ze(!1),{sessions:L,total:v,loading:O,error:x,dbExists:M}=qf(l),F=DA(()=>{if(L.length===0)return L;let H=new Map;if(b==="busiest"||y)for(let D of L)H.set(D.project_name,(H.get(D.project_name)??0)+1);let z=[...L];if(b==="longest"?z.sort((D,J)=>(J.message_count??0)-(D.message_count??0)):b==="busiest"&&z.sort((D,J)=>{let ve=H.get(D.project_name)??0,Ie=H.get(J.project_name)??0;return Ie!==ve?Ie-ve:(J.started_at??"").localeCompare(D.started_at??"")}),y){let D=new Map;for(let Ie of z){let tt=D.get(Ie.project_name);tt||(tt=[],D.set(Ie.project_name,tt)),tt.push(Ie)}let J=Array.from(D.keys()).sort((Ie,tt)=>{if(b==="busiest"){let $a=H.get(Ie)??0,Pa=H.get(tt)??0;if(Pa!==$a)return Pa-$a}return Ie.localeCompare(tt)}),ve=[];for(let Ie of J)for(let tt of D.get(Ie)??[])ve.push(tt);return ve}return z},[L,b,y]);xa(()=>{let H=()=>{let z=Qf();r(z.cols),i(z.rows)};return process.stdout.on("resize",H),()=>{process.stdout.off("resize",H)}},[]),xa(()=>{if(F.length===0){a!==0&&d(0);return}a>=F.length&&d(F.length-1)},[F.length,a]),xa(()=>{if(!g)return;let H=setTimeout(()=>f(null),2500);return()=>clearTimeout(H)},[g]),PA((H,z)=>{if(m==="search"){z.escape&&(p("normal"),u(""));return}if(m==="alias"||m==="tag"){z.escape&&p("normal");return}if(R){(H==="?"||z.escape||H==="q")&&B(!1);return}if(H==="q"||z.ctrl&&H==="c"){t();return}if(H==="?"){B(!0);return}if(!(F.length===0&&H!=="/")){if(z.upArrow||H==="k"){d(D=>Math.max(0,D-1));return}if(z.downArrow||H==="j"){d(D=>Math.min(F.length-1,D+1));return}if(z.pageUp){d(D=>Math.max(0,D-10));return}if(z.pageDown){d(D=>Math.min(F.length-1,D+10));return}if(z.return){let D=F[a];D&&(e(D.id),t());return}if(H==="o"){let D=F[a];if(!D)return;let J=ie();if(!J){f("start the daemon first (`recall start`)");return}let ve=`http://127.0.0.1:${J.port}/sessions/${D.id}`;WA(ve),f(`opened ${ve}`);return}if(H==="n"){_(J=>J==="neighborhood"?"preview":"neighborhood");let D=F[a];D&&f(h==="neighborhood"?"preview view":`neighborhood for ${D.id.slice(0,8)}`);return}if(H==="/"){p("search");return}if(H==="a"){F[a]&&p("alias");return}if(H==="t"){F[a]&&p("tag");return}if(H==="s"){S(D=>{let J=Ca.indexOf(D),ve=Ca[(J+1)%Ca.length];return f(`sort: ${XA[ve]}`),ve});return}if(H==="g"){T(D=>(f(D?"flat view":"grouped by project"),!D));return}}});function ne(H){p("normal");let z=F[a];if(!z)return;let D=H.trim();if(!D){f("alias unchanged (empty input)");return}try{Gt(z.id,D),f(`alias set: ${D}`)}catch(J){f(`alias failed: ${J instanceof Error?J.message:"unknown"}`)}}function et(H){p("normal");let z=F[a];if(!z)return;let D=H.trim();if(!D){f("tag unchanged (empty input)");return}try{let J=Wl(z.id,D);f(J.added?`tag added: ${J.tag}`:`tag exists: ${J.tag}`)}catch(J){f(`tag failed: ${J instanceof Error?J.message:"unknown"}`)}}if(s<Sa||o<ya)return La(kt,{flexDirection:"column",padding:1,children:[me(jr,{color:Ue,children:"Terminal too small."}),me(jr,{color:A,children:`Resize to at least ${Sa} cols x ${ya} rows. Current: ${s} x ${o}.`}),me(jr,{color:A,children:"Press q to quit."})]});let We=Math.max(10,o-HA-Kf),xt=Math.max(36,Math.floor(s*.4)),Da=s-xt-1,Hr=F[a]??null;return La(kt,{flexDirection:"column",width:s,height:o,children:[me(vf,{cols:s}),me(kt,{height:1}),x?me(kt,{paddingX:1,children:me(jr,{color:Ue,children:`Error loading sessions: ${x}`})}):R?me(kt,{height:We,children:me(Jf,{width:s,height:We})}):La(kt,{flexDirection:"row",height:We,children:[me(Df,{sessions:F,total:v,selected:a,width:xt,height:We,loading:O,dbExists:M,filter:l,sortMode:b,groupByProject:y}),me(kt,{width:1,height:We}),h==="neighborhood"?me(Hf,{session:Hr,width:Da,height:We,budget:4e3}):me(Uf,{session:Hr,width:Da,height:We})]}),me(kt,{height:Kf,width:s,paddingX:1,children:me(Gf,{mode:m,query:l,onQueryChange:u,onSearchSubmit:()=>p("normal"),onAliasSubmit:ne,onTagSubmit:et,aliasInitial:Hr?.alias??"",toast:g})})]})}var jA,UA,BA,Kf,HA,Ca,XA,e_=w(()=>{"use strict";Mf();$f();Bf();Wf();zf();Yf();Vf();Xe();At();Lo();yt();jA=4,UA=1,BA=1,Kf=1,HA=jA+UA+BA,Ca=["recent","longest","busiest"];XA={recent:"most recent first",longest:"longest sessions first",busiest:"busiest project first"}});import{render as GA}from"ink";import{jsx as zA}from"react/jsx-runtime";async function t_(){let e={showSessionId:null};return await GA(zA(Zf,{onShowSession:s=>{e.showSessionId=s}})).waitUntilExit(),e}var n_=w(()=>{"use strict";e_()});var s_={};V(s_,{runTui:()=>YA});import{spawn as JA}from"node:child_process";async function YA(){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 t_();if(!e.showSessionId)return;let t=process.argv[1];t&&await new Promise(n=>{let s=JA(process.execPath,[t,"show",e.showSessionId],{stdio:"inherit"});s.on("exit",()=>n()),s.on("error",()=>n())})}var r_=w(()=>{"use strict";n_()});function Na(e,t={}){let n=t.limit??qA()??75e3,r=e.prepare("SELECT COUNT(*) AS n FROM vec_chunks").get()?.n??0;if(r>n)throw new Aa(r,n)}function qA(){let e=process.env.RECALL_KNN_MAX_CORPUS;if(!e)return;let t=Number(e);if(!(!Number.isFinite(t)||t<=0||t>1e7))return Math.floor(t)}var Aa,o_=w(()=>{"use strict";Aa=class extends Error{name="CorpusTooLargeError";code="CORPUS_TOO_LARGE";rowCount;limit;constructor(t,n){super(`semantic search refused: vec_chunks has ${t} rows (cap ${n}). An unindexed kNN over this corpus can pin the SQLite WAL for hours. Workarounds: (a) scope the search to a smaller project, (b) raise the cap via RECALL_KNN_MAX_CORPUS at your own risk, (c) wait for ANN indexing (tracked in the WAL death-spiral plan).`),this.rowCount=t,this.limit=n}}});import{Worker as VA}from"node:worker_threads";import{join as KA}from"node:path";function ZA(){let e=process.env.RECALL_KNN_TIMEOUT_MS;if(!e)return;let t=Number(e);if(!(!Number.isFinite(t)||t<=0||t>36e5))return Math.floor(t)}async function va(e){let t=e.timeoutMs??ZA()??QA,n=(e.workerFactory??eN)();return new Promise((s,r)=>{let o=setTimeout(()=>{n.terminate().catch(()=>{}),r(new Oa(t))},t);n.once("message",i=>{clearTimeout(o);let a=i;a&&a.ok===!0&&Array.isArray(a.hits)?s(a.hits):r(new Error(a?.error??"worker returned malformed reply")),n.terminate().catch(()=>{})}),n.once("error",i=>{clearTimeout(o),n.terminate().catch(()=>{}),r(i)}),n.postMessage({query:e.query,precomputedVector:e.precomputedVector,limit:e.limit})})}function eN(){let e=KA(te(),"dist","daemon","query-worker.js"),t={...process.env,RECALL_DB_PROFILE:"worker"};return new VA(e,{env:t})}var Oa,QA,i_=w(()=>{"use strict";Ge();Oa=class extends Error{constructor(n){super(`semantic kNN exceeded ${n}ms wall-clock budget -- query aborted`);this.timeoutMs=n}timeoutMs;name="KnnTimeoutError";code="KNN_TIMEOUT"},QA=1e4});var a_={};V(a_,{findSimilarSessions:()=>nN,vectorSearch:()=>tN});async function tN(e,t=50){let n=E();return lt(n),Na(n),va({query:e,limit:t})}async function nN(e,t=10,n=.65){let s=E();lt(s),Na(s);let r=s.prepare("SELECT rowid FROM chunk_meta WHERE session_id = ? ORDER BY rowid LIMIT 1").get(e);if(!r)return[];let o=s.prepare("SELECT embedding FROM vec_chunks WHERE rowid = ?").get(r.rowid);if(!o)return[];let i=await va({precomputedVector:o.embedding,limit:t*5}),a=new Map;for(let l of i){if(l.sessionId===e)continue;let u=a.get(l.sessionId);(u===void 0||l.distance<u)&&a.set(l.sessionId,l.distance)}let d=[];for(let[l,u]of a){let m=1-u;m>=n&&d.push({sessionId:l,similarity:m})}return d.sort((l,u)=>u.similarity-l.similarity),d.slice(0,t)}var c_=w(()=>{"use strict";k();Yn();o_();i_()});import{createRequire as sN}from"module";import{Command as rN}from"commander";k();I();Kn();$();jt();Qn();so();ao();import{basename as fh}from"node:path";var _h=[/^<local-command-caveat>/,/^<command-name>/,/^<command-message>/,/^<system-reminder>/,/^<user-prompt-submit-hook>/,/^Caveat: The messages below were generated/i];function hh(e){let t=e.trim();return t?_h.some(n=>n.test(t)):!0}function Eh(e){let t=e;return t=t.replace(/^(?:<[^>]+>[\s\S]*?<\/[^>]+>\s*)+/,"").trim(),t=t.replace(/^<command-[^>]+>[^<]*<\/command-[^>]+>\s*/gm,"").trim(),!t||hh(t)?null:t}function bh(e,t,n){let s=Gr(t),r=n??s,o=n?fh(n)||n:Ba(t),i=e.prepare("SELECT id, decoded_path FROM projects WHERE encoded_path = ?").get(t);if(i)return n&&i.decoded_path!==n&&e.prepare("UPDATE projects SET decoded_path = ?, name = ? WHERE id = ?").run(n,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 Sh(e,t,n){let s=e.prepare("SELECT id, file_mtime FROM sessions WHERE file_path = ? LIMIT 1").get(t.sessionFile);if(!n&&s&&s.file_mtime>=t.mtime)return{inserted:!1,sessionCount:0,messageCount:0};let r=new Map,o=null;for await(let f of ec(t.sessionFile)){let h=r.get(f.sessionId);if(h||(h={sessionId:f.sessionId,entries:[],earliestTimestamp:null,latestTimestamp:null,firstUserMessage:null,userCount:0,assistantCount:0,cwd:null,gitBranch:null,version:null},r.set(f.sessionId,h)),h.entries.push(f),f.timestamp&&((!h.earliestTimestamp||f.timestamp<h.earliestTimestamp)&&(h.earliestTimestamp=f.timestamp),(!h.latestTimestamp||f.timestamp>h.latestTimestamp)&&(h.latestTimestamp=f.timestamp)),f.role==="user"&&!f.isSidechain){if(h.userCount+=1,!h.firstUserMessage&&f.contentText){let _=Eh(f.contentText);_&&(h.firstUserMessage=Q(Ce(_).redacted,200))}}else f.role==="assistant"&&!f.isSidechain&&(h.assistantCount+=1);!h.cwd&&f.cwd&&(h.cwd=f.cwd),!h.gitBranch&&f.gitBranch&&(h.gitBranch=f.gitBranch),!h.version&&f.version&&(h.version=f.version),!o&&f.cwd&&(o=f.cwd)}let i=bh(e,t.encodedProject,o),a=new Date().toISOString(),d=e.prepare(`
1125
+ LIMIT @limit`).all({limit:eN});n(m)}catch(u){i(u instanceof Error?u.message:String(u))}finally{r(!1)}},[]),{sessions:QL(()=>{let u=e.trim().toLowerCase();return u?t.filter(m=>{let p=m.project_name?.toLowerCase()??"",g=m.first_user_message?.toLowerCase()??"";return p.includes(u)||g.includes(u)}):t},[t,e]),total:t.length,loading:s,error:o,dbExists:a}}var eN,c_=w(()=>{"use strict";k();I();eN=200});import{useEffect as Oa,useMemo as tN,useState as Ze}from"react";import{Box as kt,Text as Br,useApp as nN,useInput as sN}from"ink";import{spawn as rN}from"node:child_process";import{platform as Hr}from"node:os";import{jsx as me,jsxs as Ia}from"react/jsx-runtime";function d_(){return{cols:process.stdout.columns??100,rows:process.stdout.rows??30}}function lN(e){let t=Hr()==="darwin"?"open":Hr()==="win32"?"start":"xdg-open",n=Hr()==="win32"?["",e]:[e];rN(t,n,{detached:!0,stdio:"ignore",shell:Hr()==="win32"}).unref()}function u_({onShowSession:e}){let{exit:t}=nN(),n=d_(),[s,r]=Ze(n.cols),[o,i]=Ze(n.rows),[a,d]=Ze(0),[l,u]=Ze(""),[m,p]=Ze("normal"),[g,f]=Ze(null),[_,b]=Ze("preview"),[E,S]=Ze("recent"),[y,T]=Ze(!1),[R,B]=Ze(!1),{sessions:A,total:v,loading:O,error:x,dbExists:M}=a_(l),F=tN(()=>{if(A.length===0)return A;let H=new Map;if(E==="busiest"||y)for(let $ of A)H.set($.project_name,(H.get($.project_name)??0)+1);let J=[...A];if(E==="longest"?J.sort(($,z)=>(z.message_count??0)-($.message_count??0)):E==="busiest"&&J.sort(($,z)=>{let ve=H.get($.project_name)??0,Ie=H.get(z.project_name)??0;return Ie!==ve?Ie-ve:(z.started_at??"").localeCompare($.started_at??"")}),y){let $=new Map;for(let Ie of J){let tt=$.get(Ie.project_name);tt||(tt=[],$.set(Ie.project_name,tt)),tt.push(Ie)}let z=Array.from($.keys()).sort((Ie,tt)=>{if(E==="busiest"){let Ba=H.get(Ie)??0,Ha=H.get(tt)??0;if(Ha!==Ba)return Ha-Ba}return Ie.localeCompare(tt)}),ve=[];for(let Ie of z)for(let tt of $.get(Ie)??[])ve.push(tt);return ve}return J},[A,E,y]);Oa(()=>{let H=()=>{let J=d_();r(J.cols),i(J.rows)};return process.stdout.on("resize",H),()=>{process.stdout.off("resize",H)}},[]),Oa(()=>{if(F.length===0){a!==0&&d(0);return}a>=F.length&&d(F.length-1)},[F.length,a]),Oa(()=>{if(!g)return;let H=setTimeout(()=>f(null),2500);return()=>clearTimeout(H)},[g]),sN((H,J)=>{if(m==="search"){J.escape&&(p("normal"),u(""));return}if(m==="alias"||m==="tag"){J.escape&&p("normal");return}if(R){(H==="?"||J.escape||H==="q")&&B(!1);return}if(H==="q"||J.ctrl&&H==="c"){t();return}if(H==="?"){B(!0);return}if(!(F.length===0&&H!=="/")){if(J.upArrow||H==="k"){d($=>Math.max(0,$-1));return}if(J.downArrow||H==="j"){d($=>Math.min(F.length-1,$+1));return}if(J.pageUp){d($=>Math.max(0,$-10));return}if(J.pageDown){d($=>Math.min(F.length-1,$+10));return}if(J.return){let $=F[a];$&&(e($.id),t());return}if(H==="o"){let $=F[a];if(!$)return;let z=se();if(!z){f("start the daemon first (`recall start`)");return}let ve=`http://127.0.0.1:${z.port}/sessions/${$.id}`;lN(ve),f(`opened ${ve}`);return}if(H==="n"){b(z=>z==="neighborhood"?"preview":"neighborhood");let $=F[a];$&&f(_==="neighborhood"?"preview view":`neighborhood for ${$.id.slice(0,8)}`);return}if(H==="/"){p("search");return}if(H==="a"){F[a]&&p("alias");return}if(H==="t"){F[a]&&p("tag");return}if(H==="s"){S($=>{let z=va.indexOf($),ve=va[(z+1)%va.length];return f(`sort: ${dN[ve]}`),ve});return}if(H==="g"){T($=>(f($?"flat view":"grouped by project"),!$));return}}});function ne(H){p("normal");let J=F[a];if(!J)return;let $=H.trim();if(!$){f("alias unchanged (empty input)");return}try{Gt(J.id,$),f(`alias set: ${$}`)}catch(z){f(`alias failed: ${z instanceof Error?z.message:"unknown"}`)}}function et(H){p("normal");let J=F[a];if(!J)return;let $=H.trim();if(!$){f("tag unchanged (empty input)");return}try{let z=Yl(J.id,$);f(z.added?`tag added: ${z.tag}`:`tag exists: ${z.tag}`)}catch(z){f(`tag failed: ${z instanceof Error?z.message:"unknown"}`)}}if(s<ka||o<xa)return Ia(kt,{flexDirection:"column",padding:1,children:[me(Br,{color:Be,children:"Terminal too small."}),me(Br,{color:L,children:`Resize to at least ${ka} cols x ${xa} rows. Current: ${s} x ${o}.`}),me(Br,{color:L,children:"Press q to quit."})]});let Xe=Math.max(10,o-cN-l_),xt=Math.max(36,Math.floor(s*.4)),Ua=s-xt-1,Xr=F[a]??null;return Ia(kt,{flexDirection:"column",width:s,height:o,children:[me(Xf,{cols:s}),me(kt,{height:1}),x?me(kt,{paddingX:1,children:me(Br,{color:Be,children:`Error loading sessions: ${x}`})}):R?me(kt,{height:Xe,children:me(o_,{width:s,height:Xe})}):Ia(kt,{flexDirection:"row",height:Xe,children:[me(zf,{sessions:F,total:v,selected:a,width:xt,height:Xe,loading:O,dbExists:M,filter:l,sortMode:E,groupByProject:y}),me(kt,{width:1,height:Xe}),_==="neighborhood"?me(e_,{session:Xr,width:Ua,height:Xe,budget:4e3}):me(Qf,{session:Xr,width:Ua,height:Xe})]}),me(kt,{height:l_,width:s,paddingX:1,children:me(s_,{mode:m,query:l,onQueryChange:u,onSearchSubmit:()=>p("normal"),onAliasSubmit:ne,onTagSubmit:et,aliasInitial:Xr?.alias??"",toast:g})})]})}var oN,iN,aN,l_,cN,va,dN,p_=w(()=>{"use strict";Jf();Yf();Zf();t_();r_();i_();c_();De();Lt();No();yt();oN=4,iN=1,aN=1,l_=1,cN=oN+iN+aN,va=["recent","longest","busiest"];dN={recent:"most recent first",longest:"longest sessions first",busiest:"busiest project first"}});import{render as uN}from"ink";import{jsx as pN}from"react/jsx-runtime";async function m_(){let e={showSessionId:null};return await uN(pN(u_,{onShowSession:s=>{e.showSessionId=s}})).waitUntilExit(),e}var g_=w(()=>{"use strict";p_()});var f_={};V(f_,{runTui:()=>gN});import{spawn as mN}from"node:child_process";async function gN(){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 m_();if(!e.showSessionId)return;let t=process.argv[1];t&&await new Promise(n=>{let s=mN(process.execPath,[t,"show",e.showSessionId],{stdio:"inherit"});s.on("exit",()=>n()),s.on("error",()=>n())})}var __=w(()=>{"use strict";g_()});function Da(e,t={}){let n=t.limit??fN()??75e3,r=e.prepare("SELECT COUNT(*) AS n FROM vec_chunks").get()?.n??0;if(r>n)throw new Ma(r,n)}function fN(){let e=process.env.RECALL_KNN_MAX_CORPUS;if(!e)return;let t=Number(e);if(!(!Number.isFinite(t)||t<=0||t>1e7))return Math.floor(t)}var Ma,h_=w(()=>{"use strict";Ma=class extends Error{name="CorpusTooLargeError";code="CORPUS_TOO_LARGE";rowCount;limit;constructor(t,n){super(`semantic search refused: vec_chunks has ${t} rows (cap ${n}). An unindexed kNN over this corpus can pin the SQLite WAL for hours. Workarounds: (a) scope the search to a smaller project, (b) raise the cap via RECALL_KNN_MAX_CORPUS at your own risk, (c) wait for ANN indexing (tracked in the WAL death-spiral plan).`),this.rowCount=t,this.limit=n}}});import{Worker as _N}from"node:worker_threads";import{join as hN}from"node:path";function bN(){let e=process.env.RECALL_KNN_TIMEOUT_MS;if(!e)return;let t=Number(e);if(!(!Number.isFinite(t)||t<=0||t>36e5))return Math.floor(t)}async function Pa(e){let t=e.timeoutMs??bN()??EN,n=(e.workerFactory??SN)();return new Promise((s,r)=>{let o=setTimeout(()=>{n.terminate().catch(()=>{}),r(new $a(t))},t);n.once("message",i=>{clearTimeout(o);let a=i;a&&a.ok===!0&&Array.isArray(a.hits)?s(a.hits):r(new Error(a?.error??"worker returned malformed reply")),n.terminate().catch(()=>{})}),n.once("error",i=>{clearTimeout(o),n.terminate().catch(()=>{}),r(i)}),n.postMessage({query:e.query,precomputedVector:e.precomputedVector,limit:e.limit})})}function SN(){let e=hN(te(),"dist","daemon","query-worker.js"),t={...process.env,RECALL_DB_PROFILE:"worker"};return new _N(e,{env:t})}var $a,EN,E_=w(()=>{"use strict";Ge();$a=class extends Error{constructor(n){super(`semantic kNN exceeded ${n}ms wall-clock budget -- query aborted`);this.timeoutMs=n}timeoutMs;name="KnnTimeoutError";code="KNN_TIMEOUT"},EN=1e4});var b_={};V(b_,{findSimilarSessions:()=>wN,vectorSearch:()=>yN});async function yN(e,t=50){let n=h();return lt(n),Da(n),Pa({query:e,limit:t})}async function wN(e,t=10,n=.65){let s=h();lt(s),Da(s);let r=s.prepare("SELECT rowid FROM chunk_meta WHERE session_id = ? ORDER BY rowid LIMIT 1").get(e);if(!r)return[];let o=s.prepare("SELECT embedding FROM vec_chunks WHERE rowid = ?").get(r.rowid);if(!o)return[];let i=await Pa({precomputedVector:o.embedding,limit:t*5}),a=new Map;for(let l of i){if(l.sessionId===e)continue;let u=a.get(l.sessionId);(u===void 0||l.distance<u)&&a.set(l.sessionId,l.distance)}let d=[];for(let[l,u]of a){let m=1-u;m>=n&&d.push({sessionId:l,similarity:m})}return d.sort((l,u)=>u.similarity-l.similarity),d.slice(0,t)}var S_=w(()=>{"use strict";k();qn();h_();E_()});import{createRequire as TN}from"module";import{Command as RN}from"commander";k();I();Qn();D();jt();Zn();oo();lo();import{basename as Ch}from"node:path";var Ah=[/^<local-command-caveat>/,/^<command-name>/,/^<command-message>/,/^<system-reminder>/,/^<user-prompt-submit-hook>/,/^Caveat: The messages below were generated/i];function Lh(e){let t=e.trim();return t?Ah.some(n=>n.test(t)):!0}function Nh(e){let t=e;return t=t.replace(/^(?:<[^>]+>[\s\S]*?<\/[^>]+>\s*)+/,"").trim(),t=t.replace(/^<command-[^>]+>[^<]*<\/command-[^>]+>\s*/gm,"").trim(),!t||Lh(t)?null:t}function Oh(e,t,n){let s=zr(t),r=n??s,o=n?Ch(n)||n:Ja(t),i=e.prepare("SELECT id, decoded_path FROM projects WHERE encoded_path = ?").get(t);if(i)return n&&i.decoded_path!==n&&e.prepare("UPDATE projects SET decoded_path = ?, name = ? WHERE id = ?").run(n,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 vh(e,t,n){let s=e.prepare("SELECT id, file_mtime FROM sessions WHERE file_path = ? LIMIT 1").get(t.sessionFile);if(!n&&s&&s.file_mtime>=t.mtime)return{inserted:!1,sessionCount:0,messageCount:0};let r=new Map,o=null;for await(let f of oc(t.sessionFile)){let _=r.get(f.sessionId);if(_||(_={sessionId:f.sessionId,entries:[],earliestTimestamp:null,latestTimestamp:null,firstUserMessage:null,userCount:0,assistantCount:0,cwd:null,gitBranch:null,version:null},r.set(f.sessionId,_)),_.entries.push(f),f.timestamp&&((!_.earliestTimestamp||f.timestamp<_.earliestTimestamp)&&(_.earliestTimestamp=f.timestamp),(!_.latestTimestamp||f.timestamp>_.latestTimestamp)&&(_.latestTimestamp=f.timestamp)),f.role==="user"&&!f.isSidechain){if(_.userCount+=1,!_.firstUserMessage&&f.contentText){let b=Nh(f.contentText);b&&(_.firstUserMessage=Q(Ce(b).redacted,200))}}else f.role==="assistant"&&!f.isSidechain&&(_.assistantCount+=1);!_.cwd&&f.cwd&&(_.cwd=f.cwd),!_.gitBranch&&f.gitBranch&&(_.gitBranch=f.gitBranch),!_.version&&f.version&&(_.version=f.version),!o&&f.cwd&&(o=f.cwd)}let i=Oh(e,t.encodedProject,o),a=new Date().toISOString(),d=e.prepare(`
1121
1126
  INSERT INTO sessions (
1122
1127
  id, project_id, file_path, file_mtime,
1123
1128
  started_at, ended_at, message_count,
@@ -1152,30 +1157,30 @@ CREATE VIRTUAL TABLE IF NOT EXISTS vec_chunks_v2 USING vec0(
1152
1157
  @is_sidechain, @content_text, @tool_names, @raw_json
1153
1158
  )
1154
1159
  ON CONFLICT(uuid) DO NOTHING
1155
- `),u=e.prepare("DELETE FROM messages WHERE session_id = ?"),m=0,p=0;if(e.transaction(()=>{for(let f of r.values()){d.run({id:f.sessionId,project_id:i,file_path:t.sessionFile,file_mtime:t.mtime,started_at:f.earliestTimestamp,ended_at:f.latestTimestamp,message_count:f.entries.length,user_message_count:f.userCount,assistant_message_count:f.assistantCount,first_user_message:f.firstUserMessage,cwd:f.cwd,git_branch:f.gitBranch,version:f.version,indexed_at:a}),u.run(f.sessionId);for(let h of f.entries){let{redacted:_}=Ce(h.contentText),{redacted:b}=Ce(h.raw);l.run({uuid:h.uuid,session_id:h.sessionId,parent_uuid:h.parentUuid,type:h.type,role:h.role,timestamp:h.timestamp,is_sidechain:h.isSidechain?1:0,content_text:_,tool_names:h.toolNames.join(","),raw_json:b}),p+=1}Vr(e,f.sessionId,f.entries),ln(e,f.sessionId),m+=1}})(),io().heuristicEnabled)for(let f of r.values()){let h=to(f.firstUserMessage);h&&no(f.sessionId,h,"heuristic")}return{inserted:!0,sessionCount:m,messageCount:p}}async function mc(e){let t=E(),n=Ha();console.log(c.dim(`Scanning ${n.length} JSONL session files under ~/.claude/projects/`));let s=0,r=0,o=0,i=0,a=Date.now();for(let l of n)try{let u=await Sh(t,l,e.force??!1);u.inserted?(s+=1,o+=u.sessionCount,i+=u.messageCount,e.verbose&&console.log(c.dim(` + ${l.sessionFile.split("/").slice(-2).join("/")} (${u.messageCount} msgs)`))):r+=1}catch(u){console.error(c.err(` ! failed: ${l.sessionFile}`),u)}let d=((Date.now()-a)/1e3).toFixed(1);console.log(""),console.log(`${c.ok("indexed")}: ${c.bold(String(s))} files, ${c.bold(String(o))} sessions, ${c.bold(String(i))} messages ${c.dim(`in ${d}s`)}`),r>0&&console.log(c.dim(`skipped: ${r} unchanged files (use --force to reindex)`))}k();$();import yh from"cli-table3";function gc(e){let t=E(),s={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)",s.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,
1160
+ `),u=e.prepare("DELETE FROM messages WHERE session_id = ?"),m=0,p=0;if(e.transaction(()=>{for(let f of r.values()){d.run({id:f.sessionId,project_id:i,file_path:t.sessionFile,file_mtime:t.mtime,started_at:f.earliestTimestamp,ended_at:f.latestTimestamp,message_count:f.entries.length,user_message_count:f.userCount,assistant_message_count:f.assistantCount,first_user_message:f.firstUserMessage,cwd:f.cwd,git_branch:f.gitBranch,version:f.version,indexed_at:a}),u.run(f.sessionId);for(let _ of f.entries){let{redacted:b}=Ce(_.contentText),{redacted:E}=Ce(_.raw);l.run({uuid:_.uuid,session_id:_.sessionId,parent_uuid:_.parentUuid,type:_.type,role:_.role,timestamp:_.timestamp,is_sidechain:_.isSidechain?1:0,content_text:b,tool_names:_.toolNames.join(","),raw_json:E}),p+=1}Qr(e,f.sessionId,f.entries),ln(e,f.sessionId),m+=1}})(),co().heuristicEnabled)for(let f of r.values()){let _=so(f.firstUserMessage);_&&ro(f.sessionId,_,"heuristic")}return{inserted:!0,sessionCount:m,messageCount:p}}async function Ec(e){let t=h(),n=za();console.log(c.dim(`Scanning ${n.length} JSONL session files under ~/.claude/projects/`));let s=0,r=0,o=0,i=0,a=Date.now();for(let l of n)try{let u=await vh(t,l,e.force??!1);u.inserted?(s+=1,o+=u.sessionCount,i+=u.messageCount,e.verbose&&console.log(c.dim(` + ${l.sessionFile.split("/").slice(-2).join("/")} (${u.messageCount} msgs)`))):r+=1}catch(u){console.error(c.err(` ! failed: ${l.sessionFile}`),u)}let d=((Date.now()-a)/1e3).toFixed(1);console.log(""),console.log(`${c.ok("indexed")}: ${c.bold(String(s))} files, ${c.bold(String(o))} sessions, ${c.bold(String(i))} messages ${c.dim(`in ${d}s`)}`),r>0&&console.log(c.dim(`skipped: ${r} unchanged files (use --force to reindex)`))}k();D();import Ih from"cli-table3";function bc(e){let t=h(),s={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)",s.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,
1156
1161
  s.message_count, s.first_user_message, s.git_branch
1157
1162
  FROM sessions s
1158
1163
  JOIN projects p ON p.id = s.project_id
1159
1164
  WHERE ${r}
1160
1165
  ORDER BY COALESCE(s.started_at, '') DESC
1161
- LIMIT @limit`).all(s);if(o.length===0){console.log(c.dim("no sessions found. run `recall index` first."));return}let i=new yh({head:[c.bold("id"),c.bold("project"),c.bold("when"),c.bold("msgs"),c.bold("opening prompt")],colWidths:[10,22,14,6,70],wordWrap:!0,style:{head:[],border:["grey"]}});for(let a of o)i.push([c.accent(X(a.id)),c.project(Q(a.project_name,20)),c.dim(G(a.started_at)),String(a.message_count),Q(a.first_user_message,200)]);console.log(i.toString()),console.log(c.dim(`showing ${o.length} session${o.length===1?"":"s"}. use \`recall show <id>\` to view one.`))}k();$();import{spawn as Oh}from"node:child_process";import{readFileSync as wh,writeFileSync as Th,mkdirSync as Rh,chmodSync as kh}from"node:fs";import{join as fc}from"node:path";import{homedir as _c}from"node:os";function hc(){return fc(_c(),".recall","config.json")}function Ec(){try{return JSON.parse(wh(hc(),"utf-8"))}catch{return{}}}function xh(e){let t=hc();Rh(fc(_c(),".recall"),{recursive:!0}),Th(t,JSON.stringify(e,null,2)+`
1162
- `,"utf-8"),kh(t,384)}function es(){let t=Ec().verification;return typeof t=="object"&&t!==null&&"enabled"in t?!!t.enabled:!1}function co(e){let t=Ec();t.verification={...typeof t.verification=="object"&&t.verification!==null?t.verification:{},enabled:e},xh(t)}k();var Ch=[/\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],Lh=1440*60*1e3;function Ah(e){let t=E(),n=t.prepare(`SELECT content_text, tool_names FROM messages
1166
+ LIMIT @limit`).all(s);if(o.length===0){console.log(c.dim("no sessions found. run `recall index` first."));return}let i=new Ih({head:[c.bold("id"),c.bold("project"),c.bold("when"),c.bold("msgs"),c.bold("opening prompt")],colWidths:[10,22,14,6,70],wordWrap:!0,style:{head:[],border:["grey"]}});for(let a of o)i.push([c.accent(X(a.id)),c.project(Q(a.project_name,20)),c.dim(G(a.started_at)),String(a.message_count),Q(a.first_user_message,200)]);console.log(i.toString()),console.log(c.dim(`showing ${o.length} session${o.length===1?"":"s"}. use \`recall show <id>\` to view one.`))}k();D();import{spawn as Wh}from"node:child_process";import{readFileSync as Mh,writeFileSync as Dh,mkdirSync as $h,chmodSync as Ph}from"node:fs";import{join as Sc}from"node:path";import{homedir as yc}from"node:os";function wc(){return Sc(yc(),".recall","config.json")}function Tc(){try{return JSON.parse(Mh(wc(),"utf-8"))}catch{return{}}}function Fh(e){let t=wc();$h(Sc(yc(),".recall"),{recursive:!0}),Dh(t,JSON.stringify(e,null,2)+`
1167
+ `,"utf-8"),Ph(t,384)}function ts(){let t=Tc().verification;return typeof t=="object"&&t!==null&&"enabled"in t?!!t.enabled:!1}function uo(e){let t=Tc();t.verification={...typeof t.verification=="object"&&t.verification!==null?t.verification:{},enabled:e},Fh(t)}k();var jh=[/\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],Uh=1440*60*1e3;function Bh(e){let t=h(),n=t.prepare(`SELECT content_text, tool_names FROM messages
1163
1168
  WHERE session_id = ? AND role = 'assistant'
1164
- ORDER BY timestamp DESC LIMIT 5`).all(e),s=!1;for(let d of n)if(d.content_text&&Ch.some(l=>l.test(d.content_text))){s=!0;break}let r=t.prepare(`SELECT content_text, tool_names FROM messages
1165
- WHERE session_id = ?`).all(e),o={fileWrites:!1,testRuns:!1,commits:!1,buildSuccess:!1};for(let d of r){let l=d.tool_names??"",u=d.content_text??"";/\bWrite\b|\bEdit\b/.test(l)&&(o.fileWrites=!0),/\b(?:jest|pytest|vitest|mocha|test|spec)\b/i.test(u)&&/pass|ok|✓/i.test(u)&&(o.testRuns=!0),/\bgit\s+commit\b/i.test(u)&&(o.commits=!0),(/\bbuild\s+(?:succeeded|success|passed)\b/i.test(u)||/tsc.*(?:0 errors|no errors)/i.test(u))&&(o.buildSuccess=!0)}return s?{status:[o.fileWrites,o.testRuns,o.commits,o.buildSuccess].filter(Boolean).length>=2?"verified":"unverified",evidence:o,claimFound:s}:{status:"neutral",evidence:o,claimFound:s}}function Nh(e){let t=Ah(e);return E().prepare("UPDATE sessions SET verification_status = ?, verification_computed_at = ? WHERE id = ?").run(t.status,Date.now(),e),t}function bc(e){let n=E().prepare("SELECT verification_status, verification_computed_at FROM sessions WHERE id = ?").get(e);if(n?.verification_status&&n.verification_computed_at&&Date.now()-n.verification_computed_at<Lh){let s={fileWrites:!1,testRuns:!1,commits:!1,buildSuccess:!1};return{status:n.verification_status,evidence:s,claimFound:n.verification_status!=="neutral"}}return Nh(e)}function vh(e,t){if(t.length>=32)return e.prepare("SELECT id FROM sessions WHERE id = ?").get(t)?.id??null;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||console.error(c.err(`ambiguous id prefix "${t}". be more specific.`)),null)}function Ih(e,t){let n=E(),s=n.prepare(`SELECT s.id, p.name AS project_name, p.decoded_path,
1169
+ ORDER BY timestamp DESC LIMIT 5`).all(e),s=!1;for(let d of n)if(d.content_text&&jh.some(l=>l.test(d.content_text))){s=!0;break}let r=t.prepare(`SELECT content_text, tool_names FROM messages
1170
+ WHERE session_id = ?`).all(e),o={fileWrites:!1,testRuns:!1,commits:!1,buildSuccess:!1};for(let d of r){let l=d.tool_names??"",u=d.content_text??"";/\bWrite\b|\bEdit\b/.test(l)&&(o.fileWrites=!0),/\b(?:jest|pytest|vitest|mocha|test|spec)\b/i.test(u)&&/pass|ok|✓/i.test(u)&&(o.testRuns=!0),/\bgit\s+commit\b/i.test(u)&&(o.commits=!0),(/\bbuild\s+(?:succeeded|success|passed)\b/i.test(u)||/tsc.*(?:0 errors|no errors)/i.test(u))&&(o.buildSuccess=!0)}return s?{status:[o.fileWrites,o.testRuns,o.commits,o.buildSuccess].filter(Boolean).length>=2?"verified":"unverified",evidence:o,claimFound:s}:{status:"neutral",evidence:o,claimFound:s}}function Hh(e){let t=Bh(e);return h().prepare("UPDATE sessions SET verification_status = ?, verification_computed_at = ? WHERE id = ?").run(t.status,Date.now(),e),t}function Rc(e){let n=h().prepare("SELECT verification_status, verification_computed_at FROM sessions WHERE id = ?").get(e);if(n?.verification_status&&n.verification_computed_at&&Date.now()-n.verification_computed_at<Uh){let s={fileWrites:!1,testRuns:!1,commits:!1,buildSuccess:!1};return{status:n.verification_status,evidence:s,claimFound:n.verification_status!=="neutral"}}return Hh(e)}function Xh(e,t){if(t.length>=32)return e.prepare("SELECT id FROM sessions WHERE id = ?").get(t)?.id??null;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||console.error(c.err(`ambiguous id prefix "${t}". be more specific.`)),null)}function Gh(e,t){let n=h(),s=n.prepare(`SELECT s.id, p.name AS project_name, p.decoded_path,
1166
1171
  s.started_at, s.ended_at, s.message_count,
1167
1172
  s.git_branch, s.version, s.cwd
1168
1173
  FROM sessions s
1169
1174
  JOIN projects p ON p.id = s.project_id
1170
- WHERE s.id = ?`).get(e);if(!s)return null;let r=[],o=c.dim("\u2500".repeat(78));if(r.push(""),r.push(c.bold(c.project(s.project_name))+c.dim(` ${s.decoded_path}`)),r.push(c.dim(`session ${s.id} \xB7 ${s.message_count} msgs \xB7 ${G(s.started_at)}`+(s.git_branch?` \xB7 branch: ${s.git_branch}`:""))),es()){let d=bc(e);d.status==="verified"?r.push(c.ok("\u2713 verified")):d.status==="unverified"&&r.push(c.warn("\u26A0 unverified"))}r.push(o);let i=t.limit?Math.max(1,parseInt(t.limit,10)||9999):9999,a=n.prepare(`SELECT uuid, type, role, timestamp, is_sidechain, content_text, tool_names, raw_json
1175
+ WHERE s.id = ?`).get(e);if(!s)return null;let r=[],o=c.dim("\u2500".repeat(78));if(r.push(""),r.push(c.bold(c.project(s.project_name))+c.dim(` ${s.decoded_path}`)),r.push(c.dim(`session ${s.id} \xB7 ${s.message_count} msgs \xB7 ${G(s.started_at)}`+(s.git_branch?` \xB7 branch: ${s.git_branch}`:""))),ts()){let d=Rc(e);d.status==="verified"?r.push(c.ok("\u2713 verified")):d.status==="unverified"&&r.push(c.warn("\u26A0 unverified"))}r.push(o);let i=t.limit?Math.max(1,parseInt(t.limit,10)||9999):9999,a=n.prepare(`SELECT uuid, type, role, timestamp, is_sidechain, content_text, tool_names, raw_json
1171
1176
  FROM messages
1172
1177
  WHERE session_id = ?
1173
1178
  ORDER BY COALESCE(timestamp, ''), rowid
1174
1179
  LIMIT ?`).all(e,i);for(let d of a){if(t.raw){r.push(d.raw_json);continue}let l=d.is_sidechain===1?c.dim(" [subagent]"):"",u=d.role==="user"?c.user("\u25B8 user"):d.role==="assistant"?c.assistant("\u25B8 assistant"):c.dim(`\u25B8 ${d.type}`);if(r.push(`${u}${l} ${c.dim(d.timestamp??"")}`),d.tool_names&&d.tool_names.length>0&&r.push(c.tool(` tools: ${d.tool_names}`)),d.content_text&&d.content_text.trim()){let m=d.content_text.trim().split(`
1175
1180
  `).map(p=>" "+p).join(`
1176
1181
  `);r.push(m)}r.push("")}return r.push(o),r.push(c.dim(`end of session ${s.id}`)),r.join(`
1177
- `)}function Mh(e,t){if(!t||!process.stdout.isTTY)return!1;let n=process.stdout.rows||24;return e.split(`
1178
- `).length>n}function Dh(e){let t=Oh("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 Sc(e,t){let n=E(),s=vh(n,e);if(!s){e.length>=32&&console.error(c.err(`session not found: ${e}`)),process.exitCode=1;return}let r=Ih(s,t);if(r===null){console.error(c.err(`session metadata missing for ${s}`)),process.exitCode=1;return}let o=t.pager!==!1;Mh(r,o)?Dh(r):console.log(r)}k();$();ge();I();import{existsSync as fE,readFileSync as _E}from"node:fs";import{join as hE}from"node:path";Eo();function Mc(e){let t=Ic(),n={...e};return t&&(n["x-recall-token"]=t),n}async function nt(e,t){let n=t?.headers??{};return fetch(e,{...t,headers:Mc(n)})}async function ut(e,t,n,s){let r=n!==void 0?{"content-type":"application/json",...s}:{...s};return fetch(t,{method:e,headers:Mc(r),body:n!==void 0?JSON.stringify(n):void 0})}function Dc(e){let t=e.split(/\s+/).filter(Boolean).map(n=>n.replace(/"/g,"")).filter(n=>n.length>0);return t.length===0?"":t.map(n=>`"${n}"`).join(" ")}async function EE(e,t){let n=hE(C,"daemon.port");fE(n)||(console.error(c.err("Semantic search requires the daemon to be running.")),console.error(c.dim(" Start it with: recall start")),console.error(c.dim(' Then re-run: recall search "your query" --semantic')),process.exit(1));let s;try{s=_E(n,"utf8").trim(),/^\d+$/.test(s)||(console.error(c.err(`Daemon port file is corrupt at ${n}.`)),console.error(c.dim(" Restart the daemon: recall stop && recall start")),process.exit(1))}catch(m){console.error(c.err(`Could not read daemon port: ${m instanceof Error?m.message:String(m)}`)),process.exit(1)}let r=Math.max(1,Math.min(200,parseInt(t.limit??"20",10)||20)),o=Dc(e);if(!o){console.log(c.dim("empty query"));return}let i=new URLSearchParams({q:o,mode:"semantic",limit:String(r)});t.project&&i.set("project",t.project);let a;try{a=await nt(`http://127.0.0.1:${s}/api/search?${i.toString()}`)}catch(m){console.error(c.err("Could not reach the daemon for semantic search.")),console.error(c.dim(` ${m instanceof Error?m.message:String(m)}`)),console.error(c.dim(" Is the daemon still running? Try: recall status")),process.exit(1)}if(!a.ok){console.error(c.err(`Semantic search failed: HTTP ${a.status}`));try{let m=await a.text();m&&console.error(c.dim(` ${m.slice(0,500)}`))}catch{}process.exit(1)}let d=await a.json(),l=d.hits??[];if(l.length===0){console.log(c.dim(`no matches for "${e}"`));return}let u=d.fusion==="rrf"?"semantic (BM25 + summary + vector, RRF-fused)":"semantic";console.log(c.dim(`${l.length} match${l.length===1?"":"es"} for "${e}" ${c.dim("\xB7 mode:")} ${u}`)),console.log("");for(let m of l){let p=(m.snippet??"").replace(/<<([\s\S]*?)>>/g,(_,b)=>qr(b,b).replace(/\n/g," ")).replace(/\n/g," "),g=m.role==="user"?c.user("user"):m.role==="assistant"?c.assistant("asst"):c.dim("----"),f=m.lanes&&m.lanes.length>0?c.dim(`[${m.lanes.join("+")}]`):m.matched_via?c.dim(`[${m.matched_via}]`):"",h=m.project??"(unknown)";console.log(`${c.accent(X(m.session_id))} ${c.project(Q(h,20))} ${c.dim(G(m.started_at))} ${g} ${f}`),console.log(` ${Q(p,200)}`),console.log("")}console.log(c.dim("`recall show <id>` to read any session."))}async function $c(e,t){if(await oe("Full-text search"),t.semantic){await EE(e,t);return}let n=E(),s=Dc(e);if(!s){console.log(c.dim("empty query"));return}let r=Math.max(1,Math.min(200,parseInt(t.limit??"20",10)||20)),o={q:s,limit:r},i="";t.project&&(i=" AND (p.name LIKE @proj OR p.decoded_path LIKE @proj) ",o.proj=`%${t.project}%`);let a=n.prepare(`SELECT m.session_id AS session_id,
1182
+ `)}function Jh(e,t){if(!t||!process.stdout.isTTY)return!1;let n=process.stdout.rows||24;return e.split(`
1183
+ `).length>n}function zh(e){let t=Wh("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 kc(e,t){let n=h(),s=Xh(n,e);if(!s){e.length>=32&&console.error(c.err(`session not found: ${e}`)),process.exitCode=1;return}let r=Gh(s,t);if(r===null){console.error(c.err(`session metadata missing for ${s}`)),process.exitCode=1;return}let o=t.pager!==!1;Jh(r,o)?zh(r):console.log(r)}k();D();ge();I();import{existsSync as CE,readFileSync as AE}from"node:fs";import{join as LE}from"node:path";So();function jc(e){let t=Fc(),n={...e};return t&&(n["x-recall-token"]=t),n}async function nt(e,t){let n=t?.headers??{};return fetch(e,{...t,headers:jc(n)})}async function ut(e,t,n,s){let r=n!==void 0?{"content-type":"application/json",...s}:{...s};return fetch(t,{method:e,headers:jc(r),body:n!==void 0?JSON.stringify(n):void 0})}function Uc(e){let t=e.split(/\s+/).filter(Boolean).map(n=>n.replace(/"/g,"")).filter(n=>n.length>0);return t.length===0?"":t.map(n=>`"${n}"`).join(" ")}async function NE(e,t){let n=LE(C,"daemon.port");CE(n)||(console.error(c.err("Semantic search requires the daemon to be running.")),console.error(c.dim(" Start it with: recall start")),console.error(c.dim(' Then re-run: recall search "your query" --semantic')),process.exit(1));let s;try{s=AE(n,"utf8").trim(),/^\d+$/.test(s)||(console.error(c.err(`Daemon port file is corrupt at ${n}.`)),console.error(c.dim(" Restart the daemon: recall stop && recall start")),process.exit(1))}catch(m){console.error(c.err(`Could not read daemon port: ${m instanceof Error?m.message:String(m)}`)),process.exit(1)}let r=Math.max(1,Math.min(200,parseInt(t.limit??"20",10)||20)),o=Uc(e);if(!o){console.log(c.dim("empty query"));return}let i=new URLSearchParams({q:o,mode:"semantic",limit:String(r)});t.project&&i.set("project",t.project);let a;try{a=await nt(`http://127.0.0.1:${s}/api/search?${i.toString()}`)}catch(m){console.error(c.err("Could not reach the daemon for semantic search.")),console.error(c.dim(` ${m instanceof Error?m.message:String(m)}`)),console.error(c.dim(" Is the daemon still running? Try: recall status")),process.exit(1)}if(!a.ok){console.error(c.err(`Semantic search failed: HTTP ${a.status}`));try{let m=await a.text();m&&console.error(c.dim(` ${m.slice(0,500)}`))}catch{}process.exit(1)}let d=await a.json(),l=d.hits??[];if(l.length===0){console.log(c.dim(`no matches for "${e}"`));return}let u=d.fusion==="rrf"?"semantic (BM25 + summary + vector, RRF-fused)":"semantic";console.log(c.dim(`${l.length} match${l.length===1?"":"es"} for "${e}" ${c.dim("\xB7 mode:")} ${u}`)),console.log("");for(let m of l){let p=(m.snippet??"").replace(/<<([\s\S]*?)>>/g,(b,E)=>Kr(E,E).replace(/\n/g," ")).replace(/\n/g," "),g=m.role==="user"?c.user("user"):m.role==="assistant"?c.assistant("asst"):c.dim("----"),f=m.lanes&&m.lanes.length>0?c.dim(`[${m.lanes.join("+")}]`):m.matched_via?c.dim(`[${m.matched_via}]`):"",_=m.project??"(unknown)";console.log(`${c.accent(X(m.session_id))} ${c.project(Q(_,20))} ${c.dim(G(m.started_at))} ${g} ${f}`),console.log(` ${Q(p,200)}`),console.log("")}console.log(c.dim("`recall show <id>` to read any session."))}async function Bc(e,t){if(await ie("Full-text search"),t.semantic){await NE(e,t);return}let n=h(),s=Uc(e);if(!s){console.log(c.dim("empty query"));return}let r=Math.max(1,Math.min(200,parseInt(t.limit??"20",10)||20)),o={q:s,limit:r},i="";t.project&&(i=" AND (p.name LIKE @proj OR p.decoded_path LIKE @proj) ",o.proj=`%${t.project}%`);let a=n.prepare(`SELECT m.session_id AS session_id,
1179
1184
  p.name AS project_name,
1180
1185
  s.started_at AS started_at,
1181
1186
  snippet(messages_fts, 0, '<<', '>>', '\u2026', 16) AS snippet,
@@ -1188,13 +1193,13 @@ CREATE VIRTUAL TABLE IF NOT EXISTS vec_chunks_v2 USING vec0(
1188
1193
  WHERE messages_fts MATCH @q
1189
1194
  ${i}
1190
1195
  ORDER BY bm25(messages_fts)
1191
- LIMIT @limit`).all(o);if(a.length===0){console.log(c.dim(`no matches for "${e}"`));return}console.log(c.dim(`${a.length} match${a.length===1?"":"es"} for "${e}"`)),console.log("");for(let d of a){let l=d.snippet.replace(/<<([\s\S]*?)>>/g,(m,p)=>qr(p,p).replace(/\n/g," ")).replace(/\n/g," "),u=d.role==="user"?c.user("user"):d.role==="assistant"?c.assistant("asst"):c.dim("----");console.log(`${c.accent(X(d.session_id))} ${c.project(Q(d.project_name,20))} ${c.dim(G(d.started_at))} ${u}`),console.log(` ${Q(l,200)}`),console.log("")}console.log(c.dim("`recall show <id>` to read any session."))}k();I();Xe();$();import{statSync as NE,existsSync as OE}from"node:fs";function Gc(){if(console.log(""),console.log(c.bold("Claude Recall status")),console.log(c.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),!OE(ee)){console.log(c.dim(" no database yet. run `recall index`."));return}let t=E().prepare(`SELECT
1196
+ LIMIT @limit`).all(o);if(a.length===0){console.log(c.dim(`no matches for "${e}"`));return}console.log(c.dim(`${a.length} match${a.length===1?"":"es"} for "${e}"`)),console.log("");for(let d of a){let l=d.snippet.replace(/<<([\s\S]*?)>>/g,(m,p)=>Kr(p,p).replace(/\n/g," ")).replace(/\n/g," "),u=d.role==="user"?c.user("user"):d.role==="assistant"?c.assistant("asst"):c.dim("----");console.log(`${c.accent(X(d.session_id))} ${c.project(Q(d.project_name,20))} ${c.dim(G(d.started_at))} ${u}`),console.log(` ${Q(l,200)}`),console.log("")}console.log(c.dim("`recall show <id>` to read any session."))}k();I();De();D();import{statSync as HE,existsSync as WE}from"node:fs";function Vc(){if(console.log(""),console.log(c.bold("Claude Recall status")),console.log(c.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),!WE(ee)){console.log(c.dim(" no database yet. run `recall index`."));return}let t=h().prepare(`SELECT
1192
1197
  (SELECT COUNT(*) FROM projects) AS projects,
1193
1198
  (SELECT COUNT(*) FROM sessions) AS sessions,
1194
1199
  (SELECT COUNT(*) FROM messages) AS messages,
1195
1200
  (SELECT MIN(started_at) FROM sessions WHERE started_at IS NOT NULL) AS earliest,
1196
1201
  (SELECT MAX(started_at) FROM sessions WHERE started_at IS NOT NULL) AS latest,
1197
- (SELECT MAX(indexed_at) FROM sessions) AS last_indexed`).get(),s=(NE(ee).size/1024/1024).toFixed(1);console.log(` db path ${c.dim(ee)}`),console.log(` db size ${c.accent(s+" MB")}`),console.log(` projects ${c.accent(String(t.projects))}`),console.log(` sessions ${c.accent(String(t.sessions))}`),console.log(` messages ${c.accent(String(t.messages))}`),console.log(` earliest ${c.dim(t.earliest??"n/a")}`),console.log(` latest ${c.dim(t.latest??"n/a")} ${c.dim(G(t.latest))}`),console.log(` last index ${c.dim(t.last_indexed??"never")}`),console.log("");let r=ie();r?(console.log(` daemon ${c.ok("running")} pid ${r.pid} \xB7 http://127.0.0.1:${r.port}`),console.log(` started ${c.dim(r.startedAt)} ${c.dim(G(r.startedAt))}`)):console.log(` daemon ${c.dim("stopped")} (run \`recall start\` or \`recall open\`)`),console.log("")}k();$();import vE from"cli-table3";function zc(){let t=E().prepare(`SELECT p.name,
1202
+ (SELECT MAX(indexed_at) FROM sessions) AS last_indexed`).get(),s=(HE(ee).size/1024/1024).toFixed(1);console.log(` db path ${c.dim(ee)}`),console.log(` db size ${c.accent(s+" MB")}`),console.log(` projects ${c.accent(String(t.projects))}`),console.log(` sessions ${c.accent(String(t.sessions))}`),console.log(` messages ${c.accent(String(t.messages))}`),console.log(` earliest ${c.dim(t.earliest??"n/a")}`),console.log(` latest ${c.dim(t.latest??"n/a")} ${c.dim(G(t.latest))}`),console.log(` last index ${c.dim(t.last_indexed??"never")}`),console.log("");let r=se();r?(console.log(` daemon ${c.ok("running")} pid ${r.pid} \xB7 http://127.0.0.1:${r.port}`),console.log(` started ${c.dim(r.startedAt)} ${c.dim(G(r.startedAt))}`)):console.log(` daemon ${c.dim("stopped")} (run \`recall start\` or \`recall open\`)`),console.log("")}k();D();import XE from"cli-table3";function Kc(){let t=h().prepare(`SELECT p.name,
1198
1203
  p.decoded_path,
1199
1204
  COUNT(s.id) AS session_count,
1200
1205
  COALESCE(SUM(s.message_count), 0) AS message_count,
@@ -1202,12 +1207,12 @@ CREATE VIRTUAL TABLE IF NOT EXISTS vec_chunks_v2 USING vec0(
1202
1207
  FROM projects p
1203
1208
  LEFT JOIN sessions s ON s.project_id = p.id
1204
1209
  GROUP BY p.id
1205
- ORDER BY MAX(COALESCE(s.started_at, '')) DESC`).all();if(t.length===0){console.log(c.dim("no projects indexed yet."));return}let n=new vE({head:[c.bold("project"),c.bold("sessions"),c.bold("msgs"),c.bold("latest"),c.bold("path")],style:{head:[],border:["grey"]}});for(let s of t)n.push([c.project(Q(s.name,30)),String(s.session_count),String(s.message_count),c.dim(G(s.latest)),c.dim(Q(s.decoded_path,50))]);console.log(n.toString())}Xe();Xe();I();$();Ge();_n();import{spawn as DE}from"node:child_process";import{openSync as $E}from"node:fs";import{join as PE}from"node:path";function FE(){return PE(te(),"dist","daemon","entrypoint.js")}function jE(e){return e.list({excludePids:[e.selfPid]})}function UE(e){let t=[];t.push("ERROR: another Recall daemon is already running:");for(let n of e){let s=fn(n.etimeSeconds)??n.etime,r=n.command.length>200?`${n.command.slice(0,197)}...`:n.command;t.push(` pid=${n.pid} started=${s} command=${r}`)}if(t.push("Only one daemon may run at a time (both would write to the same DB and corrupt state)."),t.push("Stop it first: recall stop"),e.length>0){let n=e[0].pid;t.push(`If 'recall stop' didn't kill it, use: kill ${n}`)}return t.join(`
1206
- `)}async function ds(e={}){let t=e.listDaemonProcesses??st,n=e.selfPid??process.pid,s=e.getRunningDaemon??ie,r=e.logger??(p=>console.log(p)),o=e.logErr??(p=>console.error(p)),i=jE({list:t,selfPid:n});if(i.length>0){o(UE(i)),process.exitCode=1;return}let a=s();if(a){r(`${c.ok("already running")} pid ${a.pid} \xB7 http://127.0.0.1:${a.port}`);return}j();let d=$E(as,"a"),l=FE();DE(process.execPath,[l],{detached:!0,stdio:["ignore",d,d],env:{...process.env}}).unref();let m=Date.now();for(;Date.now()-m<5e3;){await new Promise(g=>setTimeout(g,150));let p=s();if(p){r(`${c.ok("daemon started")} pid ${p.pid} \xB7 http://127.0.0.1:${p.port}`),r(c.dim(`logs: ${as}`));return}}o(c.err("daemon did not come up within 5s \u2014 check the log file")),o(c.dim(` ${as}`)),process.exitCode=1}Xe();_n();En();k();gs();ps();import*as el from"node:readline";var eb=2e3;async function fs(e={}){let t=e.list??Lt,n=e.kill??tb,s=e.confirm??rb,r=e.sleep??nb,o=e.logger??(g=>{process.stdout.write(g+`
1207
- `)}),i=e.truncateWal??sb,a=!!e.json,d=a||!!e.yes,l=!!e.all,u=t(),m=l?u:u.filter(g=>g.orphan),p={found:m.length,killed:[],failed:[],walTruncated:!1};if(m.length===0)return o(a?JSON.stringify(p):l?"No MCP children running.":"No orphaned MCP children to prune."),0;if(!a){o(l?`Found ${m.length} MCP child${m.length===1?"":"ren"} (will prune all):`:`Found ${m.length} orphaned MCP child${m.length===1?"":"ren"}:`);for(let g of m){let f=g.orphan?" (orphan)":"";o(` pid ${g.pid} ppid ${g.ppid} age ${pt(g.etimeSeconds)}${f}`)}}if(!d&&!await s("Kill these processes? [y/N] "))return o("Aborted."),0;for(let g of m)try{n(g.pid,"SIGTERM"),p.killed.push(g.pid)}catch(f){p.failed.push({pid:g.pid,reason:yo(f)})}await r(eb);for(let g of[...p.killed])try{n(g,0);try{n(g,"SIGKILL")}catch(f){p.killed=p.killed.filter(h=>h!==g),p.failed.push({pid:g,reason:yo(f)})}}catch{}if(p.killed.length>0)try{i(),p.walTruncated=!0}catch(g){a||o(` (WAL truncate skipped: ${yo(g)})`)}if(a)o(JSON.stringify(p));else{o(""),o(`Pruned ${p.killed.length}/${m.length}`+(p.failed.length>0?` -- ${p.failed.length} failed`:"")+(p.walTruncated?". WAL truncated.":"."));for(let g of p.failed)o(` pid ${g.pid}: ${g.reason}`)}return p.failed.length===0?0:1}function tb(e,t){process.kill(e,t)}function nb(e){return new Promise(t=>{setTimeout(t,e)})}function sb(){ms(E(),"TRUNCATE")}function rb(e){return new Promise(t=>{let n=el.createInterface({input:process.stdin,output:process.stderr});n.question(e,s=>{n.close();let r=s.trim().toLowerCase();t(r==="y"||r==="yes")})})}function yo(e){if(e instanceof Error){let t=e.code;return t?`${t} ${e.message}`:e.message}return String(e)}k();gs();$();async function tl(e={}){let t=e.logger??(y=>console.log(y)),n=e.logErr??(y=>console.error(y)),s=e.getRunningDaemon??ie,r=e.isProcessAlive??hn,o=e.clearDaemonInfo??Wc,i=e.sleep??(y=>new Promise(T=>setTimeout(T,y))),a=e.kill??((y,T)=>{process.kill(y,T)}),d=e.truncateWal??ab,l=e.listDaemonProcesses??st,u=e.selfPid??process.pid,p=s()?.pid,{ok:g,killed:f}=await ib({log:t,logErr:n,getDaemon:s,isAlive:r,clearInfo:o,kill:a,sleep:i}),h=p!=null?[u,p]:[u],_=await ob({log:t,logErr:n,listDaemons:l,isAlive:r,kill:a,sleep:i,excludePids:h}),S=(f&&g?1:0)+_;return t(S===0?c.dim("no daemons running."):c.ok(`stopped ${S} daemon${S===1?"":"s"}`)),e.all&&(await fs({all:!0,yes:!0,list:e.listMcpProcesses,kill:e.kill,sleep:e.sleep,logger:t,truncateWal:d}),d()),g?0:1}async function ob(e){let t=e.listDaemons({excludePids:e.excludePids});if(t.length===0)return 0;let n=0;for(let s of t){try{e.kill(s.pid,"SIGTERM")}catch(o){if(o.code==="ESRCH"){e.log(c.ok(`stopped daemon pid ${s.pid}`)),n+=1;continue}e.logErr(c.err(`failed to signal pid ${s.pid}: ${o.message}`));continue}let r=!1;for(let o=0;o<50;o++)if(await e.sleep(100),!e.isAlive(s.pid)){r=!0;break}if(!r){e.log(c.dim(`pid ${s.pid} ignored SIGTERM after 5s -- escalating to SIGKILL`));try{e.kill(s.pid,"SIGKILL")}catch(o){if(o.code==="ESRCH"){e.log(c.ok(`stopped daemon pid ${s.pid}`)),n+=1;continue}e.logErr(c.err(`failed to SIGKILL pid ${s.pid}: ${o.message}`));continue}for(let o=0;o<20;o++)if(await e.sleep(100),!e.isAlive(s.pid)){r=!0;break}if(!r){e.logErr(c.err(`pid ${s.pid} survived SIGKILL -- kill manually: kill -9 ${s.pid}`));continue}}e.log(c.ok(`stopped daemon pid ${s.pid}`)),n+=1}return n}async function ib(e){let t=e.getDaemon();if(!t)return e.clearInfo(),{ok:!0,killed:!1};try{e.kill(t.pid,"SIGTERM")}catch(n){return e.logErr(c.err(`failed to signal pid ${t.pid}: ${n.message}`)),{ok:!1,killed:!1}}for(let n=0;n<120;n++)if(await e.sleep(100),!e.isAlive(t.pid))return e.clearInfo(),e.log(c.ok(`stopped daemon pid ${t.pid}`)),{ok:!0,killed:!0};e.log(c.dim(`pid ${t.pid} ignored SIGTERM after 12s -- escalating to SIGKILL`));try{e.kill(t.pid,"SIGKILL")}catch(n){return n.code==="ESRCH"?(e.clearInfo(),e.log(c.ok(`stopped daemon pid ${t.pid}`)),{ok:!0,killed:!0}):(e.logErr(c.err(`failed to SIGKILL pid ${t.pid}: ${n.message}`)),{ok:!1,killed:!1})}for(let n=0;n<20;n++)if(await e.sleep(100),!e.isAlive(t.pid))return e.clearInfo(),e.log(c.ok(`stopped daemon pid ${t.pid} (forced)`)),{ok:!0,killed:!0};return e.logErr(c.err(`pid ${t.pid} survived SIGKILL -- kill manually: kill -9 ${t.pid}`)),{ok:!1,killed:!1}}function ab(){try{ms(E(),"TRUNCATE")}catch(e){console.warn(c.dim(`WAL truncate skipped: ${e.message}`))}}Xe();import{spawn as cb}from"node:child_process";import{platform as _s}from"node:os";$();function lb(e){let t=_s()==="darwin"?"open":_s()==="win32"?"start":"xdg-open",n=_s()==="win32"?["",e]:[e];cb(t,n,{detached:!0,stdio:"ignore",shell:_s()==="win32"}).unref()}async function nl(){let e=ie();if(!e&&(console.log(c.dim("daemon not running \u2014 starting it\u2026")),await ds(),e=ie(),!e)){console.error(c.err("could not start the daemon. run `recall start` manually and check logs.")),process.exitCode=1;return}let t=`http://127.0.0.1:${e.port}`;console.log(`${c.ok("opening")} ${t}`),lb(t)}k();var db=/<(local-command-caveat|local-command-stdout|command-name|command-message|command-args|system-reminder|user-prompt-submit-hook|task-notification)[\s\S]*?<\/\1>/gi,ub=/⚡ \*\*Tool call · `[^`]+`\*\*\s*\n+```json\n[\s\S]*?\n```/g,pb=/\*\*Tool result\*\*\s*\n+```\n[\s\S]*?\n```/g;function mb(e){return e.replace(db,"").trim()}function gb(e){let t=e.replace(ub,"[tool call]");return t=t.replace(pb,"[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,`
1210
+ ORDER BY MAX(COALESCE(s.started_at, '')) DESC`).all();if(t.length===0){console.log(c.dim("no projects indexed yet."));return}let n=new XE({head:[c.bold("project"),c.bold("sessions"),c.bold("msgs"),c.bold("latest"),c.bold("path")],style:{head:[],border:["grey"]}});for(let s of t)n.push([c.project(Q(s.name,30)),String(s.session_count),String(s.message_count),c.dim(G(s.latest)),c.dim(Q(s.decoded_path,50))]);console.log(n.toString())}De();De();I();D();Ge();_n();import{spawn as zE}from"node:child_process";import{openSync as YE}from"node:fs";import{join as qE}from"node:path";function VE(){return qE(te(),"dist","daemon","entrypoint.js")}function KE(e){return e.list({excludePids:[e.selfPid]})}function QE(e){let t=[];t.push("ERROR: another Recall daemon is already running:");for(let n of e){let s=fn(n.etimeSeconds)??n.etime,r=n.command.length>200?`${n.command.slice(0,197)}...`:n.command;t.push(` pid=${n.pid} started=${s} command=${r}`)}if(t.push("Only one daemon may run at a time (both would write to the same DB and corrupt state)."),t.push("Stop it first: recall stop"),e.length>0){let n=e[0].pid;t.push(`If 'recall stop' didn't kill it, use: kill ${n}`)}return t.join(`
1211
+ `)}async function us(e={}){let t=e.listDaemonProcesses??st,n=e.selfPid??process.pid,s=e.getRunningDaemon??se,r=e.logger??(p=>console.log(p)),o=e.logErr??(p=>console.error(p)),i=KE({list:t,selfPid:n});if(i.length>0){o(QE(i)),process.exitCode=1;return}let a=s();if(a){r(`${c.ok("already running")} pid ${a.pid} \xB7 http://127.0.0.1:${a.port}`);return}j();let d=YE(cs,"a"),l=VE();zE(process.execPath,[l],{detached:!0,stdio:["ignore",d,d],env:{...process.env}}).unref();let m=Date.now();for(;Date.now()-m<5e3;){await new Promise(g=>setTimeout(g,150));let p=s();if(p){r(`${c.ok("daemon started")} pid ${p.pid} \xB7 http://127.0.0.1:${p.port}`),r(c.dim(`logs: ${cs}`));return}}o(c.err("daemon did not come up within 5s \u2014 check the log file")),o(c.dim(` ${cs}`)),process.exitCode=1}De();_n();En();k();fs();ms();import*as ol from"node:readline";var pb=2e3;async function _s(e={}){let t=e.list??At,n=e.kill??mb,s=e.confirm??_b,r=e.sleep??gb,o=e.logger??(g=>{process.stdout.write(g+`
1212
+ `)}),i=e.truncateWal??fb,a=!!e.json,d=a||!!e.yes,l=!!e.all,u=t(),m=l?u:u.filter(g=>g.orphan),p={found:m.length,killed:[],failed:[],walTruncated:!1};if(m.length===0)return o(a?JSON.stringify(p):l?"No MCP children running.":"No orphaned MCP children to prune."),0;if(!a){o(l?`Found ${m.length} MCP child${m.length===1?"":"ren"} (will prune all):`:`Found ${m.length} orphaned MCP child${m.length===1?"":"ren"}:`);for(let g of m){let f=g.orphan?" (orphan)":"";o(` pid ${g.pid} ppid ${g.ppid} age ${pt(g.etimeSeconds)}${f}`)}}if(!d&&!await s("Kill these processes? [y/N] "))return o("Aborted."),0;for(let g of m)try{n(g.pid,"SIGTERM"),p.killed.push(g.pid)}catch(f){p.failed.push({pid:g.pid,reason:To(f)})}await r(pb);for(let g of[...p.killed])try{n(g,0);try{n(g,"SIGKILL")}catch(f){p.killed=p.killed.filter(_=>_!==g),p.failed.push({pid:g,reason:To(f)})}}catch{}if(p.killed.length>0)try{i(),p.walTruncated=!0}catch(g){a||o(` (WAL truncate skipped: ${To(g)})`)}if(a)o(JSON.stringify(p));else{o(""),o(`Pruned ${p.killed.length}/${m.length}`+(p.failed.length>0?` -- ${p.failed.length} failed`:"")+(p.walTruncated?". WAL truncated.":"."));for(let g of p.failed)o(` pid ${g.pid}: ${g.reason}`)}return p.failed.length===0?0:1}function mb(e,t){process.kill(e,t)}function gb(e){return new Promise(t=>{setTimeout(t,e)})}function fb(){gs(h(),"TRUNCATE")}function _b(e){return new Promise(t=>{let n=ol.createInterface({input:process.stdin,output:process.stderr});n.question(e,s=>{n.close();let r=s.trim().toLowerCase();t(r==="y"||r==="yes")})})}function To(e){if(e instanceof Error){let t=e.code;return t?`${t} ${e.message}`:e.message}return String(e)}k();fs();D();async function il(e={}){let t=e.logger??(y=>console.log(y)),n=e.logErr??(y=>console.error(y)),s=e.getRunningDaemon??se,r=e.isProcessAlive??hn,o=e.clearDaemonInfo??Yc,i=e.sleep??(y=>new Promise(T=>setTimeout(T,y))),a=e.kill??((y,T)=>{process.kill(y,T)}),d=e.truncateWal??bb,l=e.listDaemonProcesses??st,u=e.selfPid??process.pid,p=s()?.pid,{ok:g,killed:f}=await Eb({log:t,logErr:n,getDaemon:s,isAlive:r,clearInfo:o,kill:a,sleep:i}),_=p!=null?[u,p]:[u],b=await hb({log:t,logErr:n,listDaemons:l,isAlive:r,kill:a,sleep:i,excludePids:_}),S=(f&&g?1:0)+b;return t(S===0?c.dim("no daemons running."):c.ok(`stopped ${S} daemon${S===1?"":"s"}`)),e.all&&(await _s({all:!0,yes:!0,list:e.listMcpProcesses,kill:e.kill,sleep:e.sleep,logger:t,truncateWal:d}),d()),g?0:1}async function hb(e){let t=e.listDaemons({excludePids:e.excludePids});if(t.length===0)return 0;let n=0;for(let s of t){try{e.kill(s.pid,"SIGTERM")}catch(o){if(o.code==="ESRCH"){e.log(c.ok(`stopped daemon pid ${s.pid}`)),n+=1;continue}e.logErr(c.err(`failed to signal pid ${s.pid}: ${o.message}`));continue}let r=!1;for(let o=0;o<50;o++)if(await e.sleep(100),!e.isAlive(s.pid)){r=!0;break}if(!r){e.log(c.dim(`pid ${s.pid} ignored SIGTERM after 5s -- escalating to SIGKILL`));try{e.kill(s.pid,"SIGKILL")}catch(o){if(o.code==="ESRCH"){e.log(c.ok(`stopped daemon pid ${s.pid}`)),n+=1;continue}e.logErr(c.err(`failed to SIGKILL pid ${s.pid}: ${o.message}`));continue}for(let o=0;o<20;o++)if(await e.sleep(100),!e.isAlive(s.pid)){r=!0;break}if(!r){e.logErr(c.err(`pid ${s.pid} survived SIGKILL -- kill manually: kill -9 ${s.pid}`));continue}}e.log(c.ok(`stopped daemon pid ${s.pid}`)),n+=1}return n}async function Eb(e){let t=e.getDaemon();if(!t)return e.clearInfo(),{ok:!0,killed:!1};try{e.kill(t.pid,"SIGTERM")}catch(n){return e.logErr(c.err(`failed to signal pid ${t.pid}: ${n.message}`)),{ok:!1,killed:!1}}for(let n=0;n<120;n++)if(await e.sleep(100),!e.isAlive(t.pid))return e.clearInfo(),e.log(c.ok(`stopped daemon pid ${t.pid}`)),{ok:!0,killed:!0};e.log(c.dim(`pid ${t.pid} ignored SIGTERM after 12s -- escalating to SIGKILL`));try{e.kill(t.pid,"SIGKILL")}catch(n){return n.code==="ESRCH"?(e.clearInfo(),e.log(c.ok(`stopped daemon pid ${t.pid}`)),{ok:!0,killed:!0}):(e.logErr(c.err(`failed to SIGKILL pid ${t.pid}: ${n.message}`)),{ok:!1,killed:!1})}for(let n=0;n<20;n++)if(await e.sleep(100),!e.isAlive(t.pid))return e.clearInfo(),e.log(c.ok(`stopped daemon pid ${t.pid} (forced)`)),{ok:!0,killed:!0};return e.logErr(c.err(`pid ${t.pid} survived SIGKILL -- kill manually: kill -9 ${t.pid}`)),{ok:!1,killed:!1}}function bb(){try{gs(h(),"TRUNCATE")}catch(e){console.warn(c.dim(`WAL truncate skipped: ${e.message}`))}}De();import{spawn as Sb}from"node:child_process";import{platform as hs}from"node:os";D();function yb(e){let t=hs()==="darwin"?"open":hs()==="win32"?"start":"xdg-open",n=hs()==="win32"?["",e]:[e];Sb(t,n,{detached:!0,stdio:"ignore",shell:hs()==="win32"}).unref()}async function al(){let e=se();if(!e&&(console.log(c.dim("daemon not running \u2014 starting it\u2026")),await us(),e=se(),!e)){console.error(c.err("could not start the daemon. run `recall start` manually and check logs.")),process.exitCode=1;return}let t=`http://127.0.0.1:${e.port}`;console.log(`${c.ok("opening")} ${t}`),yb(t)}k();var wb=/<(local-command-caveat|local-command-stdout|command-name|command-message|command-args|system-reminder|user-prompt-submit-hook|task-notification)[\s\S]*?<\/\1>/gi,Tb=/⚡ \*\*Tool call · `[^`]+`\*\*\s*\n+```json\n[\s\S]*?\n```/g,Rb=/\*\*Tool result\*\*\s*\n+```\n[\s\S]*?\n```/g;function kb(e){return e.replace(wb,"").trim()}function xb(e){let t=e.replace(Tb,"[tool call]");return t=t.replace(Rb,"[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,`
1208
1213
 
1209
- `),t.trim()}function fb(e){return e.role??e.type??"message"}function sl(e,t,n={}){let s=n.mode??"condensed",r=n.includeSidechain===!0,o=n.since?Date.parse(n.since):0,i=t.filter(u=>!(!r&&u.is_sidechain===1||o&&u.timestamp&&Date.parse(u.timestamp)<o)),a=[];n.prelude&&(a.push(n.prelude.trim()),a.push("")),a.push(`# Claude Recall, past session context (${s})`),a.push(""),a.push(`- **Project**: ${e.project_name}`),e.decoded_path&&a.push(`- **Path**: \`${e.decoded_path}\``),a.push(`- **Session ID**: \`${e.id}\``),e.started_at&&a.push(`- **Started**: ${e.started_at}`),e.ended_at&&a.push(`- **Ended**: ${e.ended_at}`),e.git_branch&&a.push(`- **Branch**: \`${e.git_branch}\``),a.push(`- **Messages**: ${i.length}`),a.push(""),a.push("> This is a transcript of a previous Claude Code session, included for context. Refer back to it when the user asks about past decisions, code written, or problems debugged in this work."),a.push(""),a.push("---"),a.push("");let d=0,l=0;for(let u of i){let m=u.content_text??"",p=mb(m);s==="condensed"&&(p=gb(p));let g=p.length>0,f=!!u.tool_names&&u.tool_names.length>0;if(!g&&!f){l+=1;continue}let h=fb(u),_=u.timestamp?` \`${u.timestamp}\``:"";a.push(`## ${h}${_}`),a.push(""),f&&s==="condensed"&&(a.push(`_tools used: ${u.tool_names}_`),a.push("")),g&&(a.push(p),a.push("")),d+=1}return a.push("---"),a.push(""),a.push(`_${d} messages included_`+(l?`, ${l} empty skipped`:"")+(r?"":", subagent/sidechain hidden")+"."),a.join(`
1210
- `)}k();I();import{randomUUID as rl}from"node:crypto";import{writeFileSync as ol,readFileSync as xI,existsSync as _b,mkdirSync as hb}from"node:fs";import{join as wo}from"node:path";var hs=wo(C,"threads"),Eb=wo(hs,"index.json");function il(){j(),_b(hs)||hb(hs,{recursive:!0})}function al(e,t,n){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:n?.project??null,project_count:n?.project_count??0,folder_id:e.folder_id??null}}function cl(e){let t=new Map;if(e.length===0)return t;let n=E(),s=e.map(()=>"?").join(","),r=n.prepare(`SELECT te.thread_id AS thread_id,
1214
+ `),t.trim()}function Cb(e){return e.role??e.type??"message"}function cl(e,t,n={}){let s=n.mode??"condensed",r=n.includeSidechain===!0,o=n.since?Date.parse(n.since):0,i=t.filter(u=>!(!r&&u.is_sidechain===1||o&&u.timestamp&&Date.parse(u.timestamp)<o)),a=[];n.prelude&&(a.push(n.prelude.trim()),a.push("")),a.push(`# Claude Recall, past session context (${s})`),a.push(""),a.push(`- **Project**: ${e.project_name}`),e.decoded_path&&a.push(`- **Path**: \`${e.decoded_path}\``),a.push(`- **Session ID**: \`${e.id}\``),e.started_at&&a.push(`- **Started**: ${e.started_at}`),e.ended_at&&a.push(`- **Ended**: ${e.ended_at}`),e.git_branch&&a.push(`- **Branch**: \`${e.git_branch}\``),a.push(`- **Messages**: ${i.length}`),a.push(""),a.push("> This is a transcript of a previous Claude Code session, included for context. Refer back to it when the user asks about past decisions, code written, or problems debugged in this work."),a.push(""),a.push("---"),a.push("");let d=0,l=0;for(let u of i){let m=u.content_text??"",p=kb(m);s==="condensed"&&(p=xb(p));let g=p.length>0,f=!!u.tool_names&&u.tool_names.length>0;if(!g&&!f){l+=1;continue}let _=Cb(u),b=u.timestamp?` \`${u.timestamp}\``:"";a.push(`## ${_}${b}`),a.push(""),f&&s==="condensed"&&(a.push(`_tools used: ${u.tool_names}_`),a.push("")),g&&(a.push(p),a.push("")),d+=1}return a.push("---"),a.push(""),a.push(`_${d} messages included_`+(l?`, ${l} empty skipped`:"")+(r?"":", subagent/sidechain hidden")+"."),a.join(`
1215
+ `)}k();I();import{randomUUID as ll}from"node:crypto";import{writeFileSync as dl,readFileSync as JI,existsSync as Ab,mkdirSync as Lb}from"node:fs";import{join as Ro}from"node:path";var Es=Ro(C,"threads"),Nb=Ro(Es,"index.json");function ul(){j(),Ab(Es)||Lb(Es,{recursive:!0})}function pl(e,t,n){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:n?.project??null,project_count:n?.project_count??0,folder_id:e.folder_id??null}}function ml(e){let t=new Map;if(e.length===0)return t;let n=h(),s=e.map(()=>"?").join(","),r=n.prepare(`SELECT te.thread_id AS thread_id,
1211
1216
  p.name AS project,
1212
1217
  COUNT(*) AS n,
1213
1218
  SUM(CASE WHEN te.role = 'origin' THEN 1 ELSE 0 END) AS origin_n
@@ -1215,7 +1220,7 @@ CREATE VIRTUAL TABLE IF NOT EXISTS vec_chunks_v2 USING vec0(
1215
1220
  LEFT JOIN sessions s ON s.id = te.session_id
1216
1221
  LEFT JOIN projects p ON p.id = s.project_id
1217
1222
  WHERE te.thread_id IN (${s})
1218
- GROUP BY te.thread_id, p.name`).all(...e),o=new Map;for(let i of r){let a=o.get(i.thread_id);a||(a=[],o.set(i.thread_id,a)),a.push(i)}for(let[i,a]of o){let d=a.filter(m=>m.project!==null),l=d.length,u=null;d.length>0&&(u=[...d].sort((p,g)=>g.n-p.n||g.origin_n-p.origin_n||(p.project??"").localeCompare(g.project??""))[0].project),t.set(i,{project:u,project_count:l})}return t}function ll(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 dl(e){let n=E().prepare(`SELECT NULLIF(sa.alias, '') AS alias,
1223
+ GROUP BY te.thread_id, p.name`).all(...e),o=new Map;for(let i of r){let a=o.get(i.thread_id);a||(a=[],o.set(i.thread_id,a)),a.push(i)}for(let[i,a]of o){let d=a.filter(m=>m.project!==null),l=d.length,u=null;d.length>0&&(u=[...d].sort((p,g)=>g.n-p.n||g.origin_n-p.origin_n||(p.project??"").localeCompare(g.project??""))[0].project),t.set(i,{project:u,project_count:l})}return t}function gl(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 fl(e){let n=h().prepare(`SELECT NULLIF(sa.alias, '') AS alias,
1219
1224
  s.auto_title AS auto_title,
1220
1225
  s.auto_title_source AS auto_title_source,
1221
1226
  s.first_user_message AS first_user_message,
@@ -1223,11 +1228,11 @@ CREATE VIRTUAL TABLE IF NOT EXISTS vec_chunks_v2 USING vec0(
1223
1228
  FROM (SELECT ? AS sid) q
1224
1229
  LEFT JOIN sessions s ON s.id = q.sid
1225
1230
  LEFT JOIN session_aliases sa ON sa.session_id = q.sid
1226
- LEFT JOIN projects p ON p.id = s.project_id`).get(e),s=n?.auto_title_source??null;return{alias:n?.alias??null,auto_title:n?.auto_title??null,auto_title_source:s==="agent"||s==="heuristic"?s:null,first_user_message:n?.first_user_message??null,project:n?.project??null}}function ul(e){let n=E().prepare(`SELECT
1231
+ LEFT JOIN projects p ON p.id = s.project_id`).get(e),s=n?.auto_title_source??null;return{alias:n?.alias??null,auto_title:n?.auto_title??null,auto_title_source:s==="agent"||s==="heuristic"?s:null,first_user_message:n?.first_user_message??null,project:n?.project??null}}function _l(e){let n=h().prepare(`SELECT
1227
1232
  COUNT(*) AS session_count,
1228
1233
  SUM(CASE WHEN role = 'origin' THEN 1 ELSE 0 END) AS origin_count
1229
- FROM thread_edges WHERE thread_id = ?`).get(e);return{session_count:n?.session_count??0,origin_count:n?.origin_count??0}}function De(e){let t=$e(e);t&&(il(),ol(wo(hs,`${e}.json`),JSON.stringify(t,null,2)),pl())}function pl(){il();let e=To({includeArchived:!0});ol(Eb,JSON.stringify({threads:e},null,2))}function ml(e){let t=e.name.trim();if(!t)throw new Error("thread name cannot be empty");let n=E(),s=rl(),r=new Date().toISOString();n.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, ?, ?)").run(s,t,e.summary?.trim()||null,r),e.originSessionId&&n.prepare(`INSERT INTO thread_edges (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
1230
- VALUES (?, ?, NULL, 'origin', 1.0, 'manual', ?)`).run(s,e.originSessionId,r),De(s);let o=$e(s);if(!o)throw new Error("thread creation succeeded but read-back failed");return o}function To(e={}){let t=E(),n=e.includeArchived?"":"WHERE archived = 0",s=t.prepare(`SELECT * FROM threads ${n} ORDER BY created_at DESC`).all(),r=cl(s.map(o=>o.id));return s.map(o=>al(o,ul(o.id),r.get(o.id)))}function $e(e){let t=E(),n=t.prepare("SELECT * FROM threads WHERE id = ?").get(e);if(!n)return null;let s=t.prepare(`SELECT e.*,
1234
+ FROM thread_edges WHERE thread_id = ?`).get(e);return{session_count:n?.session_count??0,origin_count:n?.origin_count??0}}function $e(e){let t=Pe(e);t&&(ul(),dl(Ro(Es,`${e}.json`),JSON.stringify(t,null,2)),hl())}function hl(){ul();let e=ko({includeArchived:!0});dl(Nb,JSON.stringify({threads:e},null,2))}function El(e){let t=e.name.trim();if(!t)throw new Error("thread name cannot be empty");let n=h(),s=ll(),r=new Date().toISOString();n.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, ?, ?)").run(s,t,e.summary?.trim()||null,r),e.originSessionId&&n.prepare(`INSERT INTO thread_edges (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
1235
+ VALUES (?, ?, NULL, 'origin', 1.0, 'manual', ?)`).run(s,e.originSessionId,r),$e(s);let o=Pe(s);if(!o)throw new Error("thread creation succeeded but read-back failed");return o}function ko(e={}){let t=h(),n=e.includeArchived?"":"WHERE archived = 0",s=t.prepare(`SELECT * FROM threads ${n} ORDER BY created_at DESC`).all(),r=ml(s.map(o=>o.id));return s.map(o=>pl(o,_l(o.id),r.get(o.id)))}function Pe(e){let t=h(),n=t.prepare("SELECT * FROM threads WHERE id = ?").get(e);if(!n)return null;let s=t.prepare(`SELECT e.*,
1231
1236
  NULLIF(sa.alias, '') AS alias,
1232
1237
  s.auto_title AS auto_title,
1233
1238
  s.auto_title_source AS auto_title_source,
@@ -1238,7 +1243,7 @@ CREATE VIRTUAL TABLE IF NOT EXISTS vec_chunks_v2 USING vec0(
1238
1243
  LEFT JOIN session_aliases sa ON sa.session_id = e.session_id
1239
1244
  LEFT JOIN projects p ON p.id = s.project_id
1240
1245
  WHERE e.thread_id = ?
1241
- ORDER BY e.added_at ASC`).all(e).map(ll),r=cl([e]).get(e);return{...al(n,ul(n.id),r),edges:s}}function gl(e){let t=E();if(!t.prepare("SELECT * FROM threads WHERE id = ?").get(e.threadId))throw new Error(`thread ${e.threadId} not found`);let s=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
1246
+ ORDER BY e.added_at ASC`).all(e).map(gl),r=ml([e]).get(e);return{...pl(n,_l(n.id),r),edges:s}}function bl(e){let t=h();if(!t.prepare("SELECT * FROM threads WHERE id = ?").get(e.threadId))throw new Error(`thread ${e.threadId} not found`);let s=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
1242
1247
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
1243
1248
  VALUES (?, ?, ?, ?, ?, ?, ?)
1244
1249
  ON CONFLICT(thread_id, session_id) DO UPDATE SET
@@ -1246,57 +1251,57 @@ CREATE VIRTUAL TABLE IF NOT EXISTS vec_chunks_v2 USING vec0(
1246
1251
  role = excluded.role,
1247
1252
  confidence = excluded.confidence,
1248
1253
  source = excluded.source,
1249
- added_at = excluded.added_at`).run(e.threadId,e.sessionId,r,o,i,a,s),De(e.threadId);let d=dl(e.sessionId);return{thread_id:e.threadId,session_id:e.sessionId,parent_session_id:r,role:o,confidence:i,source:a,added_at:s,alias:d.alias,auto_title:d.auto_title,auto_title_source:d.auto_title_source,alias_source:d.alias?"manual":null,first_user_message:d.first_user_message,project:d.project}}function fl(e,t){let s=E().prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e,t);return s.changes>0&&De(e),{removed:s.changes}}function _l(e,t,n){let s=E(),r=s.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(n!==null){if(n===t)throw new Error("cycle detected: session cannot be its own parent");let a=s.prepare("SELECT parent_session_id FROM thread_edges WHERE thread_id = ? AND session_id = ?"),d=n,l=new Set;for(;d!==null;){if(d===t)throw new Error(`cycle detected: setting parent of ${t} to ${n} would create a loop`);if(l.has(d))break;l.add(d),d=a.get(e,d)?.parent_session_id??null}}let o=n?"child":"origin";s.prepare(`UPDATE thread_edges
1254
+ added_at = excluded.added_at`).run(e.threadId,e.sessionId,r,o,i,a,s),$e(e.threadId);let d=fl(e.sessionId);return{thread_id:e.threadId,session_id:e.sessionId,parent_session_id:r,role:o,confidence:i,source:a,added_at:s,alias:d.alias,auto_title:d.auto_title,auto_title_source:d.auto_title_source,alias_source:d.alias?"manual":null,first_user_message:d.first_user_message,project:d.project}}function Sl(e,t){let s=h().prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e,t);return s.changes>0&&$e(e),{removed:s.changes}}function yl(e,t,n){let s=h(),r=s.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(n!==null){if(n===t)throw new Error("cycle detected: session cannot be its own parent");let a=s.prepare("SELECT parent_session_id FROM thread_edges WHERE thread_id = ? AND session_id = ?"),d=n,l=new Set;for(;d!==null;){if(d===t)throw new Error(`cycle detected: setting parent of ${t} to ${n} would create a loop`);if(l.has(d))break;l.add(d),d=a.get(e,d)?.parent_session_id??null}}let o=n?"child":"origin";s.prepare(`UPDATE thread_edges
1250
1255
  SET parent_session_id = ?, role = ?, added_at = ?
1251
- WHERE thread_id = ? AND session_id = ?`).run(n,o,new Date().toISOString(),e,t),De(e);let i=dl(t);return ll({...r,parent_session_id:n,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 hl(e,t){let n=t.trim();if(!n)throw new Error("name cannot be empty");E().prepare("UPDATE threads SET name = ? WHERE id = ?").run(n,e),De(e);let r=$e(e);if(!r)throw new Error(`thread ${e} not found`);return r}function El(e){E().prepare("UPDATE threads SET closed_at = ? WHERE id = ?").run(new Date().toISOString(),e),De(e);let n=$e(e);if(!n)throw new Error(`thread ${e} not found`);return n}function bl(e){E().prepare("UPDATE threads SET closed_at = NULL WHERE id = ?").run(e),De(e);let n=$e(e);if(!n)throw new Error(`thread ${e} not found`);return n}function Sl(e){E().prepare("UPDATE threads SET archived = 1 WHERE id = ?").run(e),De(e);let n=$e(e);if(!n)throw new Error(`thread ${e} not found`);return n}function yl(e,t){if(e===t)throw new Error("cannot merge a thread into itself");let n=E(),s=new Date().toISOString();n.transaction(()=>{let o=n.prepare("SELECT * FROM thread_edges WHERE thread_id = ?").all(e);for(let i of o)n.prepare(`INSERT INTO thread_edges
1256
+ WHERE thread_id = ? AND session_id = ?`).run(n,o,new Date().toISOString(),e,t),$e(e);let i=fl(t);return gl({...r,parent_session_id:n,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 wl(e,t){let n=t.trim();if(!n)throw new Error("name cannot be empty");h().prepare("UPDATE threads SET name = ? WHERE id = ?").run(n,e),$e(e);let r=Pe(e);if(!r)throw new Error(`thread ${e} not found`);return r}function Tl(e){h().prepare("UPDATE threads SET closed_at = ? WHERE id = ?").run(new Date().toISOString(),e),$e(e);let n=Pe(e);if(!n)throw new Error(`thread ${e} not found`);return n}function Rl(e){h().prepare("UPDATE threads SET closed_at = NULL WHERE id = ?").run(e),$e(e);let n=Pe(e);if(!n)throw new Error(`thread ${e} not found`);return n}function kl(e){h().prepare("UPDATE threads SET archived = 1 WHERE id = ?").run(e),$e(e);let n=Pe(e);if(!n)throw new Error(`thread ${e} not found`);return n}function xl(e,t){if(e===t)throw new Error("cannot merge a thread into itself");let n=h(),s=new Date().toISOString();n.transaction(()=>{let o=n.prepare("SELECT * FROM thread_edges WHERE thread_id = ?").all(e);for(let i of o)n.prepare(`INSERT INTO thread_edges
1252
1257
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
1253
1258
  VALUES (?, ?, ?, ?, ?, ?, ?)
1254
1259
  ON CONFLICT(thread_id, session_id) DO UPDATE SET
1255
1260
  parent_session_id = COALESCE(thread_edges.parent_session_id, excluded.parent_session_id),
1256
1261
  role = CASE WHEN thread_edges.role = 'origin' OR excluded.role = 'origin' THEN 'origin' ELSE 'child' END,
1257
1262
  confidence = MAX(thread_edges.confidence, excluded.confidence),
1258
- source = thread_edges.source`).run(t,i.session_id,i.parent_session_id,i.role,i.confidence,i.source,s);n.prepare("DELETE FROM threads WHERE id = ?").run(e)})(),De(t),pl();let r=$e(t);if(!r)throw new Error("merge destination disappeared");return r}function wl(e){if(e.sessionIds.length===0)throw new Error("no sessions to split off");let t=E(),n=new Date().toISOString(),s=rl();t.transaction(()=>{t.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, NULL, ?)").run(s,e.newThreadName.trim(),n);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
1263
+ source = thread_edges.source`).run(t,i.session_id,i.parent_session_id,i.role,i.confidence,i.source,s);n.prepare("DELETE FROM threads WHERE id = ?").run(e)})(),$e(t),hl();let r=Pe(t);if(!r)throw new Error("merge destination disappeared");return r}function Cl(e){if(e.sessionIds.length===0)throw new Error("no sessions to split off");let t=h(),n=new Date().toISOString(),s=ll();t.transaction(()=>{t.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, NULL, ?)").run(s,e.newThreadName.trim(),n);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
1259
1264
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
1260
- VALUES (?, ?, ?, ?, ?, ?, ?)`).run(s,o,i.parent_session_id,i.role,i.confidence,i.source,n),t.prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e.threadId,o))}})(),De(e.threadId),De(s);let r=$e(s);if(!r)throw new Error("split destination disappeared");return r}function Tl(e){let t=$e(e);if(!t)return[];let n=t.edges.filter(r=>r.role==="origin").map(r=>r.session_id),s=t.edges.filter(r=>r.role==="child").map(r=>r.session_id);return[...n,...s]}$();ge();k();I();import{writeFileSync as bb}from"node:fs";import{join as Sb}from"node:path";var yb=Sb(C,"recall-events.json");function Ro(e,t,n,s="cli"){E().prepare(`
1265
+ VALUES (?, ?, ?, ?, ?, ?, ?)`).run(s,o,i.parent_session_id,i.role,i.confidence,i.source,n),t.prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e.threadId,o))}})(),$e(e.threadId),$e(s);let r=Pe(s);if(!r)throw new Error("split destination disappeared");return r}function Al(e){let t=Pe(e);if(!t)return[];let n=t.edges.filter(r=>r.role==="origin").map(r=>r.session_id),s=t.edges.filter(r=>r.role==="child").map(r=>r.session_id);return[...n,...s]}D();ge();k();I();import{writeFileSync as Ob}from"node:fs";import{join as vb}from"node:path";var Ib=vb(C,"recall-events.json");function xo(e,t,n,s="cli"){h().prepare(`
1261
1266
  INSERT INTO recall_events (session_id, recalled_at, token_count, mode, caller)
1262
1267
  VALUES (?, datetime('now'), ?, ?, ?)
1263
- `).run(e,t,n,s),wb()}function wb(){j();let t=E().prepare("SELECT id, session_id, recalled_at, token_count, mode, caller FROM recall_events ORDER BY recalled_at DESC").all();bb(yb,JSON.stringify(t,null,2)+`
1264
- `,"utf-8")}function Tb(e,t){if(t.length>=32)return e.prepare("SELECT id FROM sessions WHERE id = ?").get(t)?.id??null;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.
1265
- `),null)}function Rb(e){if(!e)return null;let t=e.match(/^(\d+)\s*(s|m|h|d)$/i);if(t){let s=parseInt(t[1],10),r=t[2].toLowerCase(),o=r==="s"?1e3:r==="m"?6e4:r==="h"?36e5:864e5;return new Date(Date.now()-s*o).toISOString()}if(/^\d{4}-\d{2}-\d{2}$/.test(e))return`${e}T00:00:00.000Z`;let n=Date.parse(e);return Number.isNaN(n)?null:new Date(n).toISOString()}function kb(e,t){if(t.length>=32)return e.prepare("SELECT id FROM threads WHERE id = ?").get(t)?.id??null;let n=e.prepare("SELECT id, name FROM threads WHERE id LIKE ? ORDER BY created_at DESC").all(t+"%");if(n.length===1)return n[0].id;if(n.length===0)return null;process.stderr.write(`ambiguous thread prefix "${t}" \u2014 candidates:
1268
+ `).run(e,t,n,s),Mb()}function Mb(){j();let t=h().prepare("SELECT id, session_id, recalled_at, token_count, mode, caller FROM recall_events ORDER BY recalled_at DESC").all();Ob(Ib,JSON.stringify(t,null,2)+`
1269
+ `,"utf-8")}function Db(e,t){if(t.length>=32)return e.prepare("SELECT id FROM sessions WHERE id = ?").get(t)?.id??null;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.
1270
+ `),null)}function $b(e){if(!e)return null;let t=e.match(/^(\d+)\s*(s|m|h|d)$/i);if(t){let s=parseInt(t[1],10),r=t[2].toLowerCase(),o=r==="s"?1e3:r==="m"?6e4:r==="h"?36e5:864e5;return new Date(Date.now()-s*o).toISOString()}if(/^\d{4}-\d{2}-\d{2}$/.test(e))return`${e}T00:00:00.000Z`;let n=Date.parse(e);return Number.isNaN(n)?null:new Date(n).toISOString()}function Pb(e,t){if(t.length>=32)return e.prepare("SELECT id FROM threads WHERE id = ?").get(t)?.id??null;let n=e.prepare("SELECT id, name FROM threads WHERE id LIKE ? ORDER BY created_at DESC").all(t+"%");if(n.length===1)return n[0].id;if(n.length===0)return null;process.stderr.write(`ambiguous thread prefix "${t}" \u2014 candidates:
1266
1271
  `);for(let s of n)process.stderr.write(` ${X(s.id)} ${s.name}
1267
- `);return null}function Rl(e,t,n){let s=e.prepare(`SELECT s.id, p.name AS project_name, p.decoded_path,
1272
+ `);return null}function Ll(e,t,n){let s=e.prepare(`SELECT s.id, p.name AS project_name, p.decoded_path,
1268
1273
  s.started_at, s.ended_at, s.message_count, s.git_branch
1269
1274
  FROM sessions s JOIN projects p ON p.id = s.project_id
1270
1275
  WHERE s.id = ?`).get(t);if(!s)return process.stderr.write(`session metadata missing for ${t}
1271
1276
  `),null;let r=e.prepare(`SELECT uuid, type, role, timestamp, is_sidechain, content_text, tool_names
1272
1277
  FROM messages
1273
1278
  WHERE session_id = ?
1274
- ORDER BY COALESCE(timestamp, ''), rowid`).all(t),o=n.full?"full":"condensed";return sl(s,r,{mode:o,includeSidechain:n.subagents===!0,prelude:n.prelude??null,since:Rb(n.since)})}async function kl(e,t){await oe("Context re-injection");let n=E();if(e.startsWith("thread:")){let i=e.slice(7).trim();if(!i){process.stderr.write(`thread: target requires an id or prefix
1275
- `),process.exitCode=1;return}let a=kb(n,i);if(!a){process.stderr.write(`thread not found: ${i}
1276
- `),process.exitCode=1;return}let d=Tl(a);if(d.length===0){process.stderr.write(`thread ${i} has no linked sessions
1277
- `),process.exitCode=1;return}for(let l=0;l<d.length;l+=1){let u=d[l],m=Rl(n,u,{...t,prelude:l===0?t.prelude:void 0});if(m===null){process.exitCode=1;continue}l>0&&process.stdout.write(`
1279
+ ORDER BY COALESCE(timestamp, ''), rowid`).all(t),o=n.full?"full":"condensed";return cl(s,r,{mode:o,includeSidechain:n.subagents===!0,prelude:n.prelude??null,since:$b(n.since)})}async function Nl(e,t){await ie("Context re-injection");let n=h();if(e.startsWith("thread:")){let i=e.slice(7).trim();if(!i){process.stderr.write(`thread: target requires an id or prefix
1280
+ `),process.exitCode=1;return}let a=Pb(n,i);if(!a){process.stderr.write(`thread not found: ${i}
1281
+ `),process.exitCode=1;return}let d=Al(a);if(d.length===0){process.stderr.write(`thread ${i} has no linked sessions
1282
+ `),process.exitCode=1;return}for(let l=0;l<d.length;l+=1){let u=d[l],m=Ll(n,u,{...t,prelude:l===0?t.prelude:void 0});if(m===null){process.exitCode=1;continue}l>0&&process.stdout.write(`
1278
1283
  ---
1279
1284
 
1280
1285
  `),process.stdout.write(m),m.endsWith(`
1281
1286
  `)||process.stdout.write(`
1282
- `),Ro(u,Math.ceil(m.length/4),"thread","cli")}return}let s=Tb(n,e);if(!s){e.length>=32&&process.stderr.write(`session not found: ${e}
1283
- `),process.exitCode=1;return}let r=Rl(n,s,t);if(r===null){process.exitCode=1;return}process.stdout.write(r),r.endsWith(`
1287
+ `),xo(u,Math.ceil(m.length/4),"thread","cli")}return}let s=Db(n,e);if(!s){e.length>=32&&process.stderr.write(`session not found: ${e}
1288
+ `),process.exitCode=1;return}let r=Ll(n,s,t);if(r===null){process.exitCode=1;return}process.stdout.write(r),r.endsWith(`
1284
1289
  `)||process.stdout.write(`
1285
- `);let o=t.since?"since":t.full?"full":"condensed";Ro(s,Math.ceil(r.length/4),o,"cli"),process.stderr.isTTY&&process.stderr.write(`\x1B[2mShare this recall? \u2192 recall share\x1B[0m
1286
- `)}ge();Ge();import{join as xb}from"node:path";import{spawn as Cb}from"node:child_process";async function xl(e={}){await oe("MCP server");let t=xb(te(),"dist","mcp-server.js"),n={...process.env};e.allowWrites&&(n.RECALL_MCP_ALLOW_WRITES="1");let s=Cb(process.execPath,[t],{stdio:"inherit",env:n});return new Promise((r,o)=>{s.on("error",o),s.on("exit",(i,a)=>{if(a){process.kill(process.pid,a);return}process.exitCode=i??0,r()})})}k();jt();$();import{execSync as ko}from"node:child_process";import{randomUUID as Lb}from"node:crypto";import Ab from"node:readline/promises";async function Cl(e){if(e.list){Nb();return}if(e.purge){Ob(e.purge);return}let t=await vb();t||(process.stderr.write(c.err(`clipboard empty / nothing on stdin
1290
+ `);let o=t.since?"since":t.full?"full":"condensed";xo(s,Math.ceil(r.length/4),o,"cli"),process.stderr.isTTY&&process.stderr.write(`\x1B[2mShare this recall? \u2192 recall share\x1B[0m
1291
+ `)}ge();Ge();import{join as Fb}from"node:path";import{spawn as jb}from"node:child_process";async function Ol(e={}){await ie("MCP server");let t=Fb(te(),"dist","mcp-server.js"),n={...process.env};e.allowWrites&&(n.RECALL_MCP_ALLOW_WRITES="1");let s=jb(process.execPath,[t],{stdio:"inherit",env:n});return new Promise((r,o)=>{s.on("error",o),s.on("exit",(i,a)=>{if(a){process.kill(process.pid,a);return}process.exitCode=i??0,r()})})}k();jt();D();import{execSync as Co}from"node:child_process";import{randomUUID as Ub}from"node:crypto";import Bb from"node:readline/promises";async function vl(e){if(e.list){Hb();return}if(e.purge){Wb(e.purge);return}let t=await Xb();t||(process.stderr.write(c.err(`clipboard empty / nothing on stdin
1287
1292
  `)),process.exit(1));let n=cn(t);if(n.length>0&&!e.force){process.stderr.write(c.warn(`\u26A0 detected ${n.length} possible secret${n.length===1?"":"s"} in content:
1288
1293
  `));for(let a of n.slice(0,8))process.stderr.write(` ${c.err(a.pattern)} ${c.dim("\u2192")} ${a.maskedPreview}
1289
1294
  `);n.length>8&&process.stderr.write(c.dim(` \u2026 ${n.length-8} more
1290
1295
  `)),e.dryRun&&(process.stderr.write(c.dim(`
1291
1296
  (dry run \u2014 nothing archived)
1292
1297
  `)),process.exit(1)),!process.stdin.isTTY&&!process.stderr.isTTY&&(process.stderr.write(c.err(`refusing to archive secret content in non-interactive mode. use --force to override.
1293
- `)),e.pipe&&process.stdout.write(t),process.exit(1));let o=Ab.createInterface({input:process.stdin,output:process.stderr}),i=await o.question(c.accent("archive anyway? [y/N] "));o.close(),i.trim().toLowerCase()!=="y"&&(process.stderr.write(c.dim(`cancelled \u2014 nothing archived.
1298
+ `)),e.pipe&&process.stdout.write(t),process.exit(1));let o=Bb.createInterface({input:process.stdin,output:process.stderr}),i=await o.question(c.accent("archive anyway? [y/N] "));o.close(),i.trim().toLowerCase()!=="y"&&(process.stderr.write(c.dim(`cancelled \u2014 nothing archived.
1294
1299
  `)),e.pipe&&process.stdout.write(t),process.exit(0))}e.dryRun&&(process.stderr.write(c.dim(`(dry run \u2014 would archive ${t.length.toLocaleString()} chars)
1295
- `)),e.pipe&&process.stdout.write(t),process.exit(0));let s=Lb(),r=new Date().toISOString();E().prepare(`INSERT INTO paste_archives (id, created_at, content, size_bytes, source, label)
1300
+ `)),e.pipe&&process.stdout.write(t),process.exit(0));let s=Ub(),r=new Date().toISOString();h().prepare(`INSERT INTO paste_archives (id, created_at, content, size_bytes, source, label)
1296
1301
  VALUES (?, ?, ?, ?, ?, ?)`).run(s,r,t,Buffer.byteLength(t,"utf8"),e.pipe?"cli-piped":"cli",e.label??null),process.stderr.write(c.ok(`\u2713 archived ${t.length.toLocaleString()} chars as ${s.slice(0,8)}
1297
1302
  `)),e.label&&process.stderr.write(c.dim(` label: ${e.label}
1298
1303
  `)),process.stderr.write(c.dim(` purge any time with: recall paste --purge ${s.slice(0,8)}
1299
- `)),e.pipe&&process.stdout.write(t)}function Nb(){let e=E().prepare(`SELECT id, created_at, size_bytes, source, label,
1304
+ `)),e.pipe&&process.stdout.write(t)}function Hb(){let e=h().prepare(`SELECT id, created_at, size_bytes, source, label,
1300
1305
  substr(replace(replace(content, char(10), '\u21B5'), char(13), ''), 1, 80) AS preview
1301
1306
  FROM paste_archives
1302
1307
  ORDER BY created_at DESC
@@ -1308,53 +1313,53 @@ ${c.bold(`${e.length} archived paste${e.length===1?"":"s"}`)}
1308
1313
  show full content: recall paste --show <id>
1309
1314
  `)+c.dim(`purge one (permanent): recall paste --purge <id>
1310
1315
 
1311
- `))}function Ob(e){e.length<8&&(process.stderr.write(c.err(`provide at least 8 characters of the paste id to purge.
1312
- `)),process.exit(1));let t=E(),n=t.prepare("SELECT id FROM paste_archives WHERE id = ? OR id LIKE ? LIMIT 2").all(e,`${e}%`);n.length===0&&(process.stderr.write(c.err(`no paste matches ${e}
1316
+ `))}function Wb(e){e.length<8&&(process.stderr.write(c.err(`provide at least 8 characters of the paste id to purge.
1317
+ `)),process.exit(1));let t=h(),n=t.prepare("SELECT id FROM paste_archives WHERE id = ? OR id LIKE ? LIMIT 2").all(e,`${e}%`);n.length===0&&(process.stderr.write(c.err(`no paste matches ${e}
1313
1318
  `)),process.exit(1)),n.length>1&&(process.stderr.write(c.err(`prefix ${e} is ambiguous. be more specific.
1314
1319
  `)),process.exit(1)),t.prepare("DELETE FROM paste_archives WHERE id = ?").run(n[0].id),process.stderr.write(c.ok(`\u2713 purged ${n[0].id.slice(0,8)} \u2014 content permanently destroyed
1315
- `))}async function vb(){if(!process.stdin.isTTY)return await Ib();try{return ko("pbpaste",{encoding:"utf8",maxBuffer:16*1024*1024})}catch{}try{return ko("xclip -o -selection clipboard",{encoding:"utf8",maxBuffer:16*1024*1024})}catch{}try{return ko("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 Ib(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(t));return Buffer.concat(e).toString("utf8")}k();jt();$();async function Ll(e){let t=E(),n=new Map,s=0,r=0,o=0,i=new Set,a=t.prepare(`SELECT uuid, session_id, content_text, raw_json
1320
+ `))}async function Xb(){if(!process.stdin.isTTY)return await Gb();try{return Co("pbpaste",{encoding:"utf8",maxBuffer:16*1024*1024})}catch{}try{return Co("xclip -o -selection clipboard",{encoding:"utf8",maxBuffer:16*1024*1024})}catch{}try{return Co("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 Gb(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(t));return Buffer.concat(e).toString("utf8")}k();jt();D();async function Il(e){let t=h(),n=new Map,s=0,r=0,o=0,i=new Set,a=t.prepare(`SELECT uuid, session_id, content_text, raw_json
1316
1321
  FROM messages
1317
- WHERE content_text IS NOT NULL`).all(),d=t.prepare("UPDATE messages SET content_text = ?, raw_json = ? WHERE uuid = ?"),l=(f,h)=>{let _=cn(f);if(_.length===0)return!1;for(let b of _){let S=n.get(b.pattern)??{pattern:b.pattern,severity:b.severity,hits:0,sessions:new Set};S.hits+=1,S.sessions.add(h),n.set(b.pattern,S)}return!0};process.stdout.write(c.dim(`Scanning ${a.length.toLocaleString()} messages\u2026
1322
+ WHERE content_text IS NOT NULL`).all(),d=t.prepare("UPDATE messages SET content_text = ?, raw_json = ? WHERE uuid = ?"),l=(f,_)=>{let b=cn(f);if(b.length===0)return!1;for(let E of b){let S=n.get(E.pattern)??{pattern:E.pattern,severity:E.severity,hits:0,sessions:new Set};S.hits+=1,S.sessions.add(_),n.set(E.pattern,S)}return!0};process.stdout.write(c.dim(`Scanning ${a.length.toLocaleString()} messages\u2026
1318
1323
  `));for(let f of a)if(s+=1,(l(f.content_text??"",f.session_id)||l(f.raw_json??"",f.session_id))&&(r+=1,i.add(f.session_id),e.verbose&&process.stderr.write(c.dim(` hit in session ${f.session_id.slice(0,8)} message ${f.uuid.slice(0,8)}
1319
- `)),e.redact)){let _=Ce(f.content_text??"").redacted,b=f.raw_json?Ce(f.raw_json).redacted:null;d.run(_,b,f.uuid),o+=1}let u=t.prepare(`SELECT id, first_user_message FROM sessions
1324
+ `)),e.redact)){let b=Ce(f.content_text??"").redacted,E=f.raw_json?Ce(f.raw_json).redacted:null;d.run(b,E,f.uuid),o+=1}let u=t.prepare(`SELECT id, first_user_message FROM sessions
1320
1325
  WHERE first_user_message IS NOT NULL`).all(),m=t.prepare("UPDATE sessions SET first_user_message = ? WHERE id = ?"),p=0;for(let f of u)cn(f.first_user_message).length>0&&(i.add(f.id),e.redact&&(m.run(Ce(f.first_user_message).redacted,f.id),p+=1));if(process.stdout.write(`
1321
1326
  `),n.size===0){process.stdout.write(c.ok(`\u2713 clean \u2014 no secrets detected across ${s.toLocaleString()} messages.
1322
- `));return}let g=[...n.values()].sort((f,h)=>h.hits-f.hits);process.stdout.write(c.warn(`\u26A0 ${r.toLocaleString()} message${r===1?"":"s"} across ${i.size.toLocaleString()} session${i.size===1?"":"s"} contain detected secrets.
1327
+ `));return}let g=[...n.values()].sort((f,_)=>_.hits-f.hits);process.stdout.write(c.warn(`\u26A0 ${r.toLocaleString()} message${r===1?"":"s"} across ${i.size.toLocaleString()} session${i.size===1?"":"s"} contain detected secrets.
1323
1328
 
1324
1329
  `)),process.stdout.write(c.bold(` Pattern Hits Sessions
1325
1330
  `)),process.stdout.write(c.dim(` \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1326
- `));for(let f of g){let h=f.severity==="high"?c.err("\u25CF"):c.warn("\u25CF");process.stdout.write(` ${h} ${f.pattern.padEnd(30)} ${String(f.hits).padStart(5)} ${String(f.sessions.size).padStart(4)}
1331
+ `));for(let f of g){let _=f.severity==="high"?c.err("\u25CF"):c.warn("\u25CF");process.stdout.write(` ${_} ${f.pattern.padEnd(30)} ${String(f.hits).padStart(5)} ${String(f.sessions.size).padStart(4)}
1327
1332
  `)}process.stdout.write(`
1328
1333
  `),e.redact?(process.stdout.write(c.ok(`\u2713 redacted in place: ${o.toLocaleString()} messages, ${p.toLocaleString()} session previews.
1329
1334
  `)),process.stdout.write(c.dim(` (The source JSONL files at ~/.claude/projects/ were not modified.)
1330
- `))):process.stdout.write(c.dim(" Rerun with --redact to scrub these in place, or run `recall index --force`.\n"))}k();dn();$();import{basename as Mb}from"node:path";async function Nl(e){let t=E(),n=await Db(t,e.project);if(!n){console.error(c.err(`No project found${e.project?` matching "${e.project}"`:" for current cwd"}. Run \`recall projects\` to list available projects.`)),process.exitCode=1;return}let s=t.prepare(`SELECT s.id,
1335
+ `))):process.stdout.write(c.dim(" Rerun with --redact to scrub these in place, or run `recall index --force`.\n"))}k();dn();D();import{basename as Jb}from"node:path";async function Dl(e){let t=h(),n=await zb(t,e.project);if(!n){console.error(c.err(`No project found${e.project?` matching "${e.project}"`:" for current cwd"}. Run \`recall projects\` to list available projects.`)),process.exitCode=1;return}let s=t.prepare(`SELECT s.id,
1331
1336
  s.auto_title,
1332
1337
  s.auto_title_source,
1333
1338
  CASE WHEN sa.session_id IS NOT NULL THEN 1 ELSE 0 END AS has_alias
1334
1339
  FROM sessions s
1335
1340
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1336
1341
  WHERE s.project_id = ?
1337
- ORDER BY s.started_at`).all(n.id);if(s.length===0){console.error(c.warn(`Project "${n.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 s){let m={auto_title:u.auto_title,auto_title_source:u.auto_title_source??null,has_alias:u.has_alias===1},p=cc(m);r[p]+=1,o.push({id:u.id,quality:p})}if(!e.dryRun){let u=t.prepare(`UPDATE sessions
1342
+ ORDER BY s.started_at`).all(n.id);if(s.length===0){console.error(c.warn(`Project "${n.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 s){let m={auto_title:u.auto_title,auto_title_source:u.auto_title_source??null,has_alias:u.has_alias===1},p=mc(m);r[p]+=1,o.push({id:u.id,quality:p})}if(!e.dryRun){let u=t.prepare(`UPDATE sessions
1338
1343
  SET title_quality = ?,
1339
1344
  title_quality_computed_at = ?
1340
- WHERE id = ?`),m=Date.now();t.transaction(g=>{for(let f of g)u.run(f.quality,m,f.id)})(o)}if(e.json){console.log(JSON.stringify({project:n.name,project_id:n.id,total_sessions:s.length,dry_run:!!e.dryRun,counts:r},null,2));return}let i=s.length;console.log(""),console.log(c.project(`Title quality audit \u2014 project ${c.bold(n.name)}`)),n.decoded_path&&console.log(c.dim(` ${n.decoded_path}`)),console.log(c.dim(` ${i} sessions${e.dryRun?" (DRY RUN \u2014 no DB writes)":""}`)),console.log("");let a=["clean","fixed_v0.16.1","agent","manual_alias","template_pending","programmatic","recursive_meta","low_signal"],d=Math.max(...a.map(u=>u.length));for(let u of a){let m=r[u];if(m===0)continue;let p=(m/i*100).toFixed(1).padStart(5),g=$b(m,i);console.log(` ${u.padEnd(d)} ${c.bold(String(m).padStart(5))} ${p}% ${g}`)}console.log("");let l=r.template_pending+r.programmatic+r.recursive_meta+r.low_signal;if(l>0){let u=(l/i*100).toFixed(1);console.log(c.dim(` ${l} sessions (${u}%) eligible for cleanup phases L1/L3/L4.`))}else console.log(c.ok(" No cleanup-eligible sessions remain in this project. \u2713"));console.log("")}async function Db(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 n=process.cwd(),s=e.prepare("SELECT id, name, decoded_path FROM projects WHERE decoded_path = ?").get(n);if(s)return s;let r=e.prepare("SELECT id, name, decoded_path FROM projects WHERE name = ? LIMIT 1").get(Mb(n));return r||null}var Al=28;function $b(e,t){let n=Math.round(e/t*Al);return c.dim("\u2588".repeat(n)+"\xB7".repeat(Al-n))}At();$();k();Jn();k();At();import{readFileSync as Bb,existsSync as Co,statSync as Hb,readdirSync as Wb}from"node:fs";import{join as bs}from"node:path";import{homedir as Xb}from"node:os";var bn=["vscode","cursor","windsurf"],Gb={vscode:"Code",cursor:"Cursor",windsurf:"Windsurf"};var zb=.7,Jb=300*1e3;function Yb(e){let t=e?.homeDir??Xb(),n=e?.sources??bn,s=[];for(let r of n){let o=bs(t,"Library","Application Support",Gb[r],"User","workspaceStorage");Co(o)&&s.push({source:r,root:o})}return s}function qb(e,t){let n=bs(e,"workspace.json"),s=bs(e,"state.vscdb");if(!Co(n)||!Co(s))return[];let r;try{let d=JSON.parse(Bb(n,"utf8"));if(!d.folder||!d.folder.startsWith("file://"))return[];r=decodeURIComponent(d.folder.replace(/^file:\/\//,""))}catch{return[]}let o;try{o=Hb(s).mtime.toISOString()}catch{return[]}let i;try{i=new Pt(s,{readonly:!0})}catch{return[]}let a=[];try{let d=i.prepare("SELECT value FROM ItemTable WHERE key = 'terminal.integrated.bufferState' LIMIT 1").get(),l={};if(d?.value)try{l=JSON.parse(d.value)}catch{}let u=l.state??[];if(u.length===0)a.push({workspace_path:r,workspace_storage_dir:e,tab_name:null,cwd_hint:null,last_seen_at:o,source:t});else for(let m of u){let p=m.shellLaunchConfig??{},g=typeof p.name=="string"?p.name.trim():"";a.push({workspace_path:r,workspace_storage_dir:e,tab_name:g||null,cwd_hint:typeof p.cwd=="string"?p.cwd:null,last_seen_at:o,source:t})}}finally{i.close()}return a}function Vb(e,t){let n=[],s=0;if(e.cwd&&t.workspace_path){let r=e.cwd,o=t.workspace_path;(r===o||r.startsWith(o+"/")||o.startsWith(r+"/"))&&(s+=.5,n.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)<=Jb&&(s+=.4,n.push("time_window"))}return e.cwd&&t.cwd_hint&&e.cwd===t.cwd_hint&&(s+=.1,n.push("cwd_exact")),t.tab_name&&(s+=.2,n.push("has_name")),s>1&&(s=1),{score:s,matchedOn:n}}var Kb=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 Qb(e){return Kb.has(e.trim().toLowerCase())}function Zb(e){let t=e.tab_name?.trim();return!t||Qb(t)?null:t}function Il(e){let t=e?.minScore??zb,n=e?.limit,s=E(),r=e?.projectId?" AND s.project_id = ?":"",o=e?.projectId?[e.projectId]:[],i=s.prepare(`SELECT s.id, p.decoded_path AS cwd, s.started_at
1345
+ WHERE id = ?`),m=Date.now();t.transaction(g=>{for(let f of g)u.run(f.quality,m,f.id)})(o)}if(e.json){console.log(JSON.stringify({project:n.name,project_id:n.id,total_sessions:s.length,dry_run:!!e.dryRun,counts:r},null,2));return}let i=s.length;console.log(""),console.log(c.project(`Title quality audit \u2014 project ${c.bold(n.name)}`)),n.decoded_path&&console.log(c.dim(` ${n.decoded_path}`)),console.log(c.dim(` ${i} sessions${e.dryRun?" (DRY RUN \u2014 no DB writes)":""}`)),console.log("");let a=["clean","fixed_v0.16.1","agent","manual_alias","template_pending","programmatic","recursive_meta","low_signal"],d=Math.max(...a.map(u=>u.length));for(let u of a){let m=r[u];if(m===0)continue;let p=(m/i*100).toFixed(1).padStart(5),g=Yb(m,i);console.log(` ${u.padEnd(d)} ${c.bold(String(m).padStart(5))} ${p}% ${g}`)}console.log("");let l=r.template_pending+r.programmatic+r.recursive_meta+r.low_signal;if(l>0){let u=(l/i*100).toFixed(1);console.log(c.dim(` ${l} sessions (${u}%) eligible for cleanup phases L1/L3/L4.`))}else console.log(c.ok(" No cleanup-eligible sessions remain in this project. \u2713"));console.log("")}async function zb(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 n=process.cwd(),s=e.prepare("SELECT id, name, decoded_path FROM projects WHERE decoded_path = ?").get(n);if(s)return s;let r=e.prepare("SELECT id, name, decoded_path FROM projects WHERE name = ? LIMIT 1").get(Jb(n));return r||null}var Ml=28;function Yb(e,t){let n=Math.round(e/t*Ml);return c.dim("\u2588".repeat(n)+"\xB7".repeat(Ml-n))}Lt();D();k();Yn();k();Lt();import{readFileSync as Zb,existsSync as Lo,statSync as eS,readdirSync as tS}from"node:fs";import{join as Ss}from"node:path";import{homedir as nS}from"node:os";var bn=["vscode","cursor","windsurf"],sS={vscode:"Code",cursor:"Cursor",windsurf:"Windsurf"};var rS=.7,oS=300*1e3;function iS(e){let t=e?.homeDir??nS(),n=e?.sources??bn,s=[];for(let r of n){let o=Ss(t,"Library","Application Support",sS[r],"User","workspaceStorage");Lo(o)&&s.push({source:r,root:o})}return s}function aS(e,t){let n=Ss(e,"workspace.json"),s=Ss(e,"state.vscdb");if(!Lo(n)||!Lo(s))return[];let r;try{let d=JSON.parse(Zb(n,"utf8"));if(!d.folder||!d.folder.startsWith("file://"))return[];r=decodeURIComponent(d.folder.replace(/^file:\/\//,""))}catch{return[]}let o;try{o=eS(s).mtime.toISOString()}catch{return[]}let i;try{i=new Pt(s,{readonly:!0})}catch{return[]}let a=[];try{let d=i.prepare("SELECT value FROM ItemTable WHERE key = 'terminal.integrated.bufferState' LIMIT 1").get(),l={};if(d?.value)try{l=JSON.parse(d.value)}catch{}let u=l.state??[];if(u.length===0)a.push({workspace_path:r,workspace_storage_dir:e,tab_name:null,cwd_hint:null,last_seen_at:o,source:t});else for(let m of u){let p=m.shellLaunchConfig??{},g=typeof p.name=="string"?p.name.trim():"";a.push({workspace_path:r,workspace_storage_dir:e,tab_name:g||null,cwd_hint:typeof p.cwd=="string"?p.cwd:null,last_seen_at:o,source:t})}}finally{i.close()}return a}function cS(e,t){let n=[],s=0;if(e.cwd&&t.workspace_path){let r=e.cwd,o=t.workspace_path;(r===o||r.startsWith(o+"/")||o.startsWith(r+"/"))&&(s+=.5,n.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)<=oS&&(s+=.4,n.push("time_window"))}return e.cwd&&t.cwd_hint&&e.cwd===t.cwd_hint&&(s+=.1,n.push("cwd_exact")),t.tab_name&&(s+=.2,n.push("has_name")),s>1&&(s=1),{score:s,matchedOn:n}}var lS=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 dS(e){return lS.has(e.trim().toLowerCase())}function uS(e){let t=e.tab_name?.trim();return!t||dS(t)?null:t}function Fl(e){let t=e?.minScore??rS,n=e?.limit,s=h(),r=e?.projectId?" AND s.project_id = ?":"",o=e?.projectId?[e.projectId]:[],i=s.prepare(`SELECT s.id, p.decoded_path AS cwd, s.started_at
1341
1346
  FROM sessions s
1342
1347
  JOIN projects p ON p.id = s.project_id
1343
1348
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1344
- WHERE (sa.alias IS NULL OR sa.alias = '')${r}`).all(...o),a=e?.sources??bn,d=Yb({sources:a,homeDir:e?.homeDir}),l=[];for(let{source:m,root:p}of d){let g;try{g=Wb(p)}catch{continue}for(let f of g){let h=bs(p,f);l.push(...qb(h,m))}}if(l.length===0)return[];let u=[];for(let m of i){let p=null;for(let f of l){let{score:h,matchedOn:_}=Vb(m,f);h<t||(!p||h>p.score)&&(p={entry:f,score:h,matched:_})}if(!p)continue;let g=Zb(p.entry);g&&u.push({session_id:m.id,proposed_alias:g,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 n=="number"&&n>=0&&u.length>n?u.slice(0,n):u}function Ml(e){let t=[],n=[];for(let s of e){let r=Es(s.session_id);if(r&&r.trim()!==""){n.push(s);continue}t.push(s)}return{applicable:t,skipped:n}}import{basename as eS}from"node:path";async function $l(e){let t=nS(e.source);if(!t){console.error(c.err("Invalid --source. Allowed: vscode | cursor | windsurf | all (default).")),process.exitCode=1;return}let n=sS(e.minScore,.7);if(n===null||n<0||n>1){console.error(c.err("Invalid --min-score. Must be a number in [0, 1].")),process.exitCode=1;return}let s=e.limit?parseInt(e.limit,10):void 0;if(s!==void 0&&(!Number.isFinite(s)||s<0)){console.error(c.err("Invalid --limit. Must be a non-negative integer.")),process.exitCode=1;return}let r=e.project?rS(e.project):void 0;if(e.project&&r===null){console.error(c.err(`No project found matching "${e.project}". Run \`recall projects\`.`)),process.exitCode=1;return}let o=Il({projectId:r??void 0,sources:t,minScore:n,limit:s}),{applicable:i,skipped:a}=Ml(o);if(e.apply){let d=0;for(let l of i)try{Gt(l.session_id,l.proposed_alias),d+=1}catch(u){console.error(c.err(`apply failed for ${l.session_id.slice(0,8)}: ${u.message}`))}if(e.json){console.log(JSON.stringify({mode:"apply",sources:t,min_score:n,project_id:r??null,applied:d,skipped:a.length,proposals:i.map(Dl)},null,2));return}console.log(""),console.log(c.ok(`Applied ${d} alias backfill${d===1?"":"s"}`+(a.length?` \xB7 skipped ${a.length} (alias appeared since proposal)`:""))),console.log("");return}if(e.json){console.log(JSON.stringify({mode:"dry-run",sources:t,min_score:n,project_id:r??null,proposals:i.map(Dl),skipped_due_to_existing_alias:a.length},null,2));return}tS(i,t,n,a.length)}function tS(e,t,n,s){if(console.log(""),console.log(c.project(`recall import-vscode-state \xB7 sources=${t.join("+")} min-score=${n.toFixed(2)} \xB7 DRY RUN`)),console.log(c.dim(" Pass --apply to write proposals via setAlias().")),console.log(""),e.length===0){console.log(c.warn(" No proposals \u2014 either no matching workspaces or every candidate session already has an alias.")),s>0&&console.log(c.dim(` ${s} sessions were skipped because they already have aliases.`)),console.log("");return}for(let r of e){let o=c.bold(r.session_id.slice(0,8)),i=c.bold(r.score.toFixed(2)),a=c.dim(`[${r.evidence.source}]`),d=r.evidence.matched_on.join("+");console.log(` ${o} score=${i} ${a} matched=${d}`),console.log(` proposed alias: ${c.bold(r.proposed_alias)}`),console.log(` workspace: ${c.dim(Q(r.evidence.workspace_path,70))}`),r.evidence.tab_name&&console.log(` tab name: ${r.evidence.tab_name}`),r.evidence.cwd_hint&&console.log(` cwd hint: ${c.dim(Q(r.evidence.cwd_hint,70))}`),console.log(` last seen: ${c.dim(r.evidence.last_seen_at)}`),console.log("")}console.log(c.dim(` ${e.length} proposal${e.length===1?"":"s"}`+(s>0?` \xB7 ${s} skipped (existing alias)`:"")+" \xB7 pass --apply to write via setAlias()")),console.log("")}function Dl(e){return e}function nS(e){if(!e||e==="all")return bn;let t=e.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean),n=[];for(let s of t)if(bn.includes(s))n.push(s);else return null;return n.length>0?n:null}function sS(e,t){if(e===void 0)return t;let n=Number.parseFloat(e);return Number.isFinite(n)?n:null}function rS(e){let t=E(),n=t.prepare("SELECT id FROM projects WHERE name = ? LIMIT 1").get(e);if(n)return n.id;let s=t.prepare("SELECT id FROM projects WHERE name LIKE ? ORDER BY name LIMIT 1").get(`%${e}%`);if(s)return s.id;let r=eS(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}Sn();Rs();Ye();wn();Pe();Ds();Ho();k();ge();Xo();I();import Oy from"node:http";import{existsSync as vy,readFileSync as Iy}from"node:fs";import{join as My}from"node:path";var _d=5e3;function Dy(){let e=My(C,"daemon.port");if(!vy(e))return null;try{let t=Iy(e,"utf8").trim();if(t.startsWith("{")){let s=JSON.parse(t);return typeof s.port=="number"?s.port:null}let n=Number.parseInt(t,10);return Number.isFinite(n)&&n>0&&n<65536?n:null}catch{return null}}function hd(e,t,n){return new Promise(s=>{let r=Oy.request({host:"127.0.0.1",port:e,path:t,method:"GET",timeout:n,headers:{host:"127.0.0.1","user-agent":"recall-semantic-status"}},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){s({ok:!1,reason:"http"});return}try{s({ok:!0,json:JSON.parse(Buffer.concat(i).toString("utf8"))})}catch{s({ok:!1,reason:"parse"})}})});r.on("error",()=>s({ok:!1,reason:"error"})),r.on("timeout",()=>{r.destroy(),s({ok:!1,reason:"timeout"})}),r.end()})}async function $y(e){let t=await hd(e,"/api/health",_d);if(t.ok)return t.json;if(t.reason!=="timeout")return null;let n=await hd(e,"/api/health",_d);return n.ok?n.json:null}async function Ed(){let e=Dy();if(e===null)return null;let t=await $y(e);if(!t||typeof t!="object")return null;let n=t.pipeline?.autoExtract;return!n||typeof n!="object"||typeof n.circuitBroken!="boolean"?null:{circuitBroken:n.circuitBroken,reason:typeof n.reason=="string"?n.reason:null,consecutiveZeroTokenRuns:typeof n.consecutiveZeroTokenRuns=="number"?n.consecutiveZeroTokenRuns:0}}async function ep(e,t){let n=(e??"status").toLowerCase();if(n==="on"||n==="enable"){if(!ae()){console.error("claude CLI not found on PATH. Install Claude Code first, then re-run."),process.exitCode=1;return}let p={enabled:!0};t.rate&&(p.ratePerMinute=Number(t.rate)),t.model&&(p.model=t.model);let g=Je(p,"cli");console.log("Semantic search: ENABLED"),console.log(` Rate: ${g.ratePerMinute}/min`),g.model&&console.log(` Model: ${g.model}`),console.log(""),console.log("Disclosure: enabling semantic search sends condensed session"),console.log("summaries to Claude via your local `claude` CLI using your existing"),console.log("plan. New sessions are summarized on close. Run `recall semantic backfill`"),console.log("to summarize the existing archive.");return}if(n==="off"||n==="disable"){Je({enabled:!1},"cli"),console.log("Semantic search: DISABLED"),console.log("Existing summaries are kept in the database; the pipeline will not run.");return}if(n==="pause"){Je({backfillPaused:!0},"cli"),console.log("Backfill paused. Resume with `recall semantic resume`.");return}if(n==="resume"){Je({backfillPaused:!1},"cli"),console.log("Backfill resumed.");return}if(n==="backfill"){let p=we();if(!p.enabled){console.error("Semantic search is disabled. Run `recall semantic on` first."),process.exitCode=1;return}p.backfillPaused&&Je({backfillPaused:!1},"cli");let g=t.limit?Math.max(1,Number(t.limit)):1e3,f=!!t.force;console.log(`Backfilling up to ${g} sessions${f?" (force)":""}\u2026`);let h=Date.now(),_=0,b=await Ts({limit:g,force:f,onProgress:y=>{if(y.processed===_)return;_=y.processed;let T=y.total>0?` (${Math.round(y.processed/y.total*100)}%)`:"";process.stdout.write(`\r ${y.processed}/${y.total}${T} ok=${y.ok} failed=${y.failed} `)}});process.stdout.write(`
1345
- `);let S=((Date.now()-h)/1e3).toFixed(1);console.log(`Done in ${S}s \u2014 processed=${b.processed} ok=${b.ok} failed=${b.failed}`);return}if(n==="install"){let p=(process.env.RECALL_EMBEDDER_BACKEND??"").trim().toLowerCase();if(p==="llama"||p==="llamacpp"){let{ensureLlamaCppInstalled:f}=await Promise.resolve().then(()=>(Sd(),bd)),h=await f();if(!h.ok){console.error("Failed to install node-llama-cpp:"),console.error(` ${h.error}`),console.error("Vector search not enabled. Other features unaffected."),process.exitCode=1;return}h.action==="installed"&&console.log("Installed node-llama-cpp.");let{isGgufModelInstalled:_,downloadGgufModel:b,verifyGgufModelHash:S}=await Promise.resolve().then(()=>(Us(),js));if(_()){let y=await S();y.ok?console.log("GGUF model already installed and verified."):(console.log(`Re-downloading GGUF model (existing file ${y.reason}).`),await b((T,R)=>{let B=R>0?Math.round(T/R*100):0;process.stdout.write(`\r bge-base-en-v1.5-q8_0.gguf: ${B}% `)}),process.stdout.write(`
1346
- `))}else console.log("Downloading bge-base-en-v1.5-q8_0.gguf (~113MB)..."),await b((y,T)=>{let R=T>0?Math.round(y/T*100):0;process.stdout.write(`\r bge-base-en-v1.5-q8_0.gguf: ${R}% `)}),process.stdout.write(`
1347
- `);console.log("Loading embedder (llamacpp backend)...")}else{let{ensureTransformersInstalled:f}=await Promise.resolve().then(()=>(Dd(),Md)),h=await f();if(!h.ok){console.error("Failed to install @huggingface/transformers:"),console.error(` ${h.error}`),console.error("Vector search not enabled. Other features unaffected."),process.exitCode=1;return}h.action==="installed"&&console.log("Installed @huggingface/transformers."),rt()?console.log("Model already installed."):(console.log("Downloading bge-base-en-v1.5 (~110MB)..."),await vo((_,b,S)=>{let y=S>0?Math.round(b/S*100):0;process.stdout.write(`\r ${_}: ${y}% `)}),process.stdout.write(`
1348
- `)),console.log("Loading embedder...")}try{await Ke(),console.log("Done. Vector search is now active.")}catch(f){let{EmbedderUnavailableError:h}=await Promise.resolve().then(()=>(Pe(),Ms));f instanceof h?(console.log("Model files installed."),console.log(` Embedder load skipped: ${f.message.split(`
1349
+ WHERE (sa.alias IS NULL OR sa.alias = '')${r}`).all(...o),a=e?.sources??bn,d=iS({sources:a,homeDir:e?.homeDir}),l=[];for(let{source:m,root:p}of d){let g;try{g=tS(p)}catch{continue}for(let f of g){let _=Ss(p,f);l.push(...aS(_,m))}}if(l.length===0)return[];let u=[];for(let m of i){let p=null;for(let f of l){let{score:_,matchedOn:b}=cS(m,f);_<t||(!p||_>p.score)&&(p={entry:f,score:_,matched:b})}if(!p)continue;let g=uS(p.entry);g&&u.push({session_id:m.id,proposed_alias:g,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 n=="number"&&n>=0&&u.length>n?u.slice(0,n):u}function jl(e){let t=[],n=[];for(let s of e){let r=bs(s.session_id);if(r&&r.trim()!==""){n.push(s);continue}t.push(s)}return{applicable:t,skipped:n}}import{basename as pS}from"node:path";async function Bl(e){let t=gS(e.source);if(!t){console.error(c.err("Invalid --source. Allowed: vscode | cursor | windsurf | all (default).")),process.exitCode=1;return}let n=fS(e.minScore,.7);if(n===null||n<0||n>1){console.error(c.err("Invalid --min-score. Must be a number in [0, 1].")),process.exitCode=1;return}let s=e.limit?parseInt(e.limit,10):void 0;if(s!==void 0&&(!Number.isFinite(s)||s<0)){console.error(c.err("Invalid --limit. Must be a non-negative integer.")),process.exitCode=1;return}let r=e.project?_S(e.project):void 0;if(e.project&&r===null){console.error(c.err(`No project found matching "${e.project}". Run \`recall projects\`.`)),process.exitCode=1;return}let o=Fl({projectId:r??void 0,sources:t,minScore:n,limit:s}),{applicable:i,skipped:a}=jl(o);if(e.apply){let d=0;for(let l of i)try{Gt(l.session_id,l.proposed_alias),d+=1}catch(u){console.error(c.err(`apply failed for ${l.session_id.slice(0,8)}: ${u.message}`))}if(e.json){console.log(JSON.stringify({mode:"apply",sources:t,min_score:n,project_id:r??null,applied:d,skipped:a.length,proposals:i.map(Ul)},null,2));return}console.log(""),console.log(c.ok(`Applied ${d} alias backfill${d===1?"":"s"}`+(a.length?` \xB7 skipped ${a.length} (alias appeared since proposal)`:""))),console.log("");return}if(e.json){console.log(JSON.stringify({mode:"dry-run",sources:t,min_score:n,project_id:r??null,proposals:i.map(Ul),skipped_due_to_existing_alias:a.length},null,2));return}mS(i,t,n,a.length)}function mS(e,t,n,s){if(console.log(""),console.log(c.project(`recall import-vscode-state \xB7 sources=${t.join("+")} min-score=${n.toFixed(2)} \xB7 DRY RUN`)),console.log(c.dim(" Pass --apply to write proposals via setAlias().")),console.log(""),e.length===0){console.log(c.warn(" No proposals \u2014 either no matching workspaces or every candidate session already has an alias.")),s>0&&console.log(c.dim(` ${s} sessions were skipped because they already have aliases.`)),console.log("");return}for(let r of e){let o=c.bold(r.session_id.slice(0,8)),i=c.bold(r.score.toFixed(2)),a=c.dim(`[${r.evidence.source}]`),d=r.evidence.matched_on.join("+");console.log(` ${o} score=${i} ${a} matched=${d}`),console.log(` proposed alias: ${c.bold(r.proposed_alias)}`),console.log(` workspace: ${c.dim(Q(r.evidence.workspace_path,70))}`),r.evidence.tab_name&&console.log(` tab name: ${r.evidence.tab_name}`),r.evidence.cwd_hint&&console.log(` cwd hint: ${c.dim(Q(r.evidence.cwd_hint,70))}`),console.log(` last seen: ${c.dim(r.evidence.last_seen_at)}`),console.log("")}console.log(c.dim(` ${e.length} proposal${e.length===1?"":"s"}`+(s>0?` \xB7 ${s} skipped (existing alias)`:"")+" \xB7 pass --apply to write via setAlias()")),console.log("")}function Ul(e){return e}function gS(e){if(!e||e==="all")return bn;let t=e.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean),n=[];for(let s of t)if(bn.includes(s))n.push(s);else return null;return n.length>0?n:null}function fS(e,t){if(e===void 0)return t;let n=Number.parseFloat(e);return Number.isFinite(n)?n:null}function _S(e){let t=h(),n=t.prepare("SELECT id FROM projects WHERE name = ? LIMIT 1").get(e);if(n)return n.id;let s=t.prepare("SELECT id FROM projects WHERE name LIKE ? ORDER BY name LIMIT 1").get(`%${e}%`);if(s)return s.id;let r=pS(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}Sn();ks();Ye();wn();Fe();$s();Xo();k();ge();Jo();I();import Wy from"node:http";import{existsSync as Xy,readFileSync as Gy}from"node:fs";import{join as Jy}from"node:path";var yd=5e3;function zy(){let e=Jy(C,"daemon.port");if(!Xy(e))return null;try{let t=Gy(e,"utf8").trim();if(t.startsWith("{")){let s=JSON.parse(t);return typeof s.port=="number"?s.port:null}let n=Number.parseInt(t,10);return Number.isFinite(n)&&n>0&&n<65536?n:null}catch{return null}}function wd(e,t,n){return new Promise(s=>{let r=Wy.request({host:"127.0.0.1",port:e,path:t,method:"GET",timeout:n,headers:{host:"127.0.0.1","user-agent":"recall-semantic-status"}},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){s({ok:!1,reason:"http"});return}try{s({ok:!0,json:JSON.parse(Buffer.concat(i).toString("utf8"))})}catch{s({ok:!1,reason:"parse"})}})});r.on("error",()=>s({ok:!1,reason:"error"})),r.on("timeout",()=>{r.destroy(),s({ok:!1,reason:"timeout"})}),r.end()})}async function Yy(e){let t=await wd(e,"/api/health",yd);if(t.ok)return t.json;if(t.reason!=="timeout")return null;let n=await wd(e,"/api/health",yd);return n.ok?n.json:null}async function Td(){let e=zy();if(e===null)return null;let t=await Yy(e);if(!t||typeof t!="object")return null;let n=t.pipeline?.autoExtract;return!n||typeof n!="object"||typeof n.circuitBroken!="boolean"?null:{circuitBroken:n.circuitBroken,reason:typeof n.reason=="string"?n.reason:null,consecutiveZeroTokenRuns:typeof n.consecutiveZeroTokenRuns=="number"?n.consecutiveZeroTokenRuns:0}}async function lp(e,t){let n=(e??"status").toLowerCase();if(n==="on"||n==="enable"){if(!ae()){console.error("claude CLI not found on PATH. Install Claude Code first, then re-run."),process.exitCode=1;return}let p={enabled:!0};t.rate&&(p.ratePerMinute=Number(t.rate)),t.model&&(p.model=t.model);let g=ze(p,"cli");console.log("Semantic search: ENABLED"),console.log(` Rate: ${g.ratePerMinute}/min`),g.model&&console.log(` Model: ${g.model}`),console.log(""),console.log("Disclosure: enabling semantic search sends condensed session"),console.log("summaries to Claude via your local `claude` CLI using your existing"),console.log("plan. New sessions are summarized on close. Run `recall semantic backfill`"),console.log("to summarize the existing archive.");return}if(n==="off"||n==="disable"){ze({enabled:!1},"cli"),console.log("Semantic search: DISABLED"),console.log("Existing summaries are kept in the database; the pipeline will not run.");return}if(n==="pause"){ze({backfillPaused:!0},"cli"),console.log("Backfill paused. Resume with `recall semantic resume`.");return}if(n==="resume"){ze({backfillPaused:!1},"cli"),console.log("Backfill resumed.");return}if(n==="backfill"){let p=we();if(!p.enabled){console.error("Semantic search is disabled. Run `recall semantic on` first."),process.exitCode=1;return}p.backfillPaused&&ze({backfillPaused:!1},"cli");let g=t.limit?Math.max(1,Number(t.limit)):1e3,f=!!t.force;console.log(`Backfilling up to ${g} sessions${f?" (force)":""}\u2026`);let _=Date.now(),b=0,E=await Rs({limit:g,force:f,onProgress:y=>{if(y.processed===b)return;b=y.processed;let T=y.total>0?` (${Math.round(y.processed/y.total*100)}%)`:"";process.stdout.write(`\r ${y.processed}/${y.total}${T} ok=${y.ok} failed=${y.failed} `)}});process.stdout.write(`
1350
+ `);let S=((Date.now()-_)/1e3).toFixed(1);console.log(`Done in ${S}s \u2014 processed=${E.processed} ok=${E.ok} failed=${E.failed}`);return}if(n==="install"){let p=(process.env.RECALL_EMBEDDER_BACKEND??"").trim().toLowerCase();if(p==="llama"||p==="llamacpp"){let{ensureLlamaCppInstalled:f}=await Promise.resolve().then(()=>(kd(),Rd)),_=await f();if(!_.ok){console.error("Failed to install node-llama-cpp:"),console.error(` ${_.error}`),console.error("Vector search not enabled. Other features unaffected."),process.exitCode=1;return}_.action==="installed"&&console.log("Installed node-llama-cpp.");let{isGgufModelInstalled:b,downloadGgufModel:E,verifyGgufModelHash:S}=await Promise.resolve().then(()=>(Bs(),Us));if(b()){let y=await S();y.ok?console.log("GGUF model already installed and verified."):(console.log(`Re-downloading GGUF model (existing file ${y.reason}).`),await E((T,R)=>{let B=R>0?Math.round(T/R*100):0;process.stdout.write(`\r bge-base-en-v1.5-q8_0.gguf: ${B}% `)}),process.stdout.write(`
1351
+ `))}else console.log("Downloading bge-base-en-v1.5-q8_0.gguf (~113MB)..."),await E((y,T)=>{let R=T>0?Math.round(y/T*100):0;process.stdout.write(`\r bge-base-en-v1.5-q8_0.gguf: ${R}% `)}),process.stdout.write(`
1352
+ `);console.log("Loading embedder (llamacpp backend)...")}else{let{ensureTransformersInstalled:f}=await Promise.resolve().then(()=>(Ud(),jd)),_=await f();if(!_.ok){console.error("Failed to install @huggingface/transformers:"),console.error(` ${_.error}`),console.error("Vector search not enabled. Other features unaffected."),process.exitCode=1;return}_.action==="installed"&&console.log("Installed @huggingface/transformers."),rt()?console.log("Model already installed."):(console.log("Downloading bge-base-en-v1.5 (~110MB)..."),await Mo((b,E,S)=>{let y=S>0?Math.round(E/S*100):0;process.stdout.write(`\r ${b}: ${y}% `)}),process.stdout.write(`
1353
+ `)),console.log("Loading embedder...")}try{await Ke(),console.log("Done. Vector search is now active.")}catch(f){let{EmbedderUnavailableError:_}=await Promise.resolve().then(()=>(Fe(),Ds));f instanceof _?(console.log("Model files installed."),console.log(` Embedder load skipped: ${f.message.split(`
1349
1354
  `)[0]}`),console.log(" Vector features remain available; runtime load happens on first use.")):(console.error("Model files installed but embedder load failed:"),console.error(` ${f instanceof Error?f.message.split(`
1350
- `)[0]:String(f)}`),console.error(" This is unexpected. Run `recall doctor` for diagnostics."),process.exitCode=1)}return}if(n==="uninstall"){Io();let{isGgufModelInstalled:p,uninstallGgufModel:g}=await Promise.resolve().then(()=>(Us(),js));p()?(g(),console.log("Model removed (ONNX + GGUF). Vector search will fall back to keyword search.")):console.log("Model removed. Vector search will fall back to keyword search.");return}if(n==="auto-extract"){let p=t._autoExtractAction;if(p==="on"||p==="enable"){let g=Je({autoExtractEnabled:!0},"cli");console.log("Auto-extract: ENABLED"),console.log(` Cadence: 1 batch every ${g.autoExtractIntervalMinutes} minutes`),console.log(` Batch size: ${g.autoExtractBatchSize} session(s) per tick`),console.log(" Honors your 5-hour Claude plan window \u2014 at 60min/1, that is"),console.log(" ~5 extractions per window, leaving 95%+ of the rate budget free."),console.log(" The daemon will start nibbling through un-extracted sessions on"),console.log(" the next tick (within 15 minutes). Status: `recall semantic status`.");return}if(p==="off"||p==="disable"){Je({autoExtractEnabled:!1},"cli"),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(n==="reindex"){if(await oe("Vector reindex"),!Z().loaded){if(!rt()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}await Ke()}let p=E(),g=p.prepare(`
1355
+ `)[0]:String(f)}`),console.error(" This is unexpected. Run `recall doctor` for diagnostics."),process.exitCode=1)}return}if(n==="uninstall"){Do();let{isGgufModelInstalled:p,uninstallGgufModel:g}=await Promise.resolve().then(()=>(Bs(),Us));p()?(g(),console.log("Model removed (ONNX + GGUF). Vector search will fall back to keyword search.")):console.log("Model removed. Vector search will fall back to keyword search.");return}if(n==="auto-extract"){let p=t._autoExtractAction;if(p==="on"||p==="enable"){let g=ze({autoExtractEnabled:!0},"cli");console.log("Auto-extract: ENABLED"),console.log(` Cadence: 1 batch every ${g.autoExtractIntervalMinutes} minutes`),console.log(` Batch size: ${g.autoExtractBatchSize} session(s) per tick`),console.log(" Honors your 5-hour Claude plan window \u2014 at 60min/1, that is"),console.log(" ~5 extractions per window, leaving 95%+ of the rate budget free."),console.log(" The daemon will start nibbling through un-extracted sessions on"),console.log(" the next tick (within 15 minutes). Status: `recall semantic status`.");return}if(p==="off"||p==="disable"){ze({autoExtractEnabled:!1},"cli"),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(n==="reindex"){if(await ie("Vector reindex"),!Z().loaded){if(!rt()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}await Ke()}let p=h(),g=p.prepare(`
1351
1356
  SELECT s.id FROM sessions s
1352
1357
  WHERE s.message_count >= 3
1353
1358
  AND NOT EXISTS (SELECT 1 FROM chunk_meta cm WHERE cm.session_id = s.id)
1354
- `).all(),f=Number(process.env.RECALL_REINDEX_MAX_CHUNKS??"0"),h=f>0?` (cap ${f} chunks/session)`:" (no cap)";console.log(`Reindexing ${g.length} sessions (skipping already-indexed)${h}...`);let _=0;for(let{id:b}of g){let S=Bo(b),y=f>0?S.slice(0,f):S;if(y.length===0){_++;continue}let T=y.map(O=>O.text),R=await Ne(T);Wo(b);let B=Z().modelId,L=p.prepare(`INSERT INTO chunk_meta(session_id, message_uuids, text, embedding_model_id, embedding_dim, stale, generated_at)
1355
- VALUES (?, ?, ?, ?, 768, 0, datetime('now'))`),v=p.prepare("INSERT INTO vec_chunks(rowid, embedding) VALUES (?, ?)");for(let O=0;O<y.length;O++){let x=L.run(b,JSON.stringify(y[O].messageUuids),y[O].text,B),M=Buffer.from(R[O].buffer,R[O].byteOffset,R[O].byteLength);v.run(BigInt(x.lastInsertRowid),M)}_++,_%10===0&&process.stdout.write(`\r ${_}/${g.length} `)}process.stdout.write(`
1356
- `),console.log(`Reindexed ${_} sessions.`);return}if(n==="migrate"){await oe("Vector migration");let{runMigration:p}=await Promise.resolve().then(()=>(qs(),Ys)),{getActiveMigration:g,pauseMigration:f}=await Promise.resolve().then(()=>(Vt(),Js)),h=t.yes??!1,_=t.noBackup??!1,b=t.dryRun??!1,S=()=>{try{let R=g();R&&(f(R.id),console.error("\n[migrate] received SIGINT; migration paused (cursor preserved). Re-run `recall semantic migrate` to resume."))}catch(R){console.error("[migrate] failed to pause migration on SIGINT:",R)}process.exit(130)};b||process.on("SIGINT",S);let y;try{y=await p({interactive:!h,keepBackup:!_,dryRun:b,projectName:t.project,onProgress:R=>{let L=(R.total>0?R.migrated/R.total*100:0).toFixed(1);process.stdout.write(`\r ${R.migrated}/${R.total} (${L}%) ${R.chunksPerSec.toFixed(1)} chunks/sec `)}})}finally{b||process.off("SIGINT",S)}process.stdout.write(`
1357
- `);let T=0;y.ok?t.project?console.log(y.message):(console.log(`Migration complete. ${y.migrated} chunks re-embedded.`),y.backupRetained&&(console.log("Old vectors retained in vec_chunks_v1_backup for 30 days."),console.log("Run `recall semantic rollback-migration` to revert if needed."))):(console.error(`Migration: ${y.message}`),/nothing to migrate|user declined confirmation/.test(y.message)||(T=1)),process.exit(T)}if(n==="rollback-migration"){await oe("Vector migration rollback");let{rollbackMigration:p}=await Promise.resolve().then(()=>(qs(),Ys)),g=t.force??!1,f=await p({force:g});f.ok?console.log(f.message):(console.error(f.message),process.exitCode=1),process.exit(process.exitCode??0)}if(n==="prune-rollback"){await oe("Vector migration rollback pruning");let{pruneRollbackBackup:p}=await Promise.resolve().then(()=>(qs(),Ys)),g=t.force??!1,f=await p({force:g});f.ok?console.log(f.message):(console.error(f.message),process.exitCode=1),process.exit(process.exitCode??0)}if(n==="verify-backup"){await oe("Vector backup verification");let{getDb:p}=await Promise.resolve().then(()=>(k(),qn));p().prepare("SELECT name FROM sqlite_master WHERE name='vec_chunks_v1_backup'").get()||(console.log("No vec_chunks_v1_backup table present (already pruned, or no migration has run). Nothing to verify."),process.exit(0));let{countBackupOrphans:h}=await Promise.resolve().then(()=>(yi(),Zu));console.log("Scanning vec_chunks_v1_backup for orphan rows \u2014 this can take several minutes on a large backup (it scans every vector row).");let _=Date.now(),b=h(),S=((Date.now()-_)/1e3).toFixed(1);b===0&&(console.log(`\u2713 No orphan rows. Backup is consistent with chunk_meta (${S}s).`),process.exit(0)),console.error(`! ${b} orphan row(s) in vec_chunks_v1_backup (${S}s) \u2014 the backup-aware delete path missed these. This is a maintainer-facing bug; please report it. The backup is still safe for rollback.`),process.exit(1)}if(n==="verify-spawn"){if(!ae()){console.error("claude CLI not found on PATH. Install Claude Code first, then re-run."),process.exitCode=1;return}let{spawnClaudePrompt:p}=await Promise.resolve().then(()=>(Ye(),ys)),{homedir:g}=await import("node:os"),{join:f}=await import("node:path"),{readdirSync:h}=await import("node:fs"),_=f(g(),".claude","projects"),b=()=>{let v=new Set;try{for(let O of h(_,{withFileTypes:!0})){if(!O.isDirectory())continue;let x=f(_,O.name);for(let M of h(x,{withFileTypes:!0}))M.isFile()&&M.name.endsWith(".jsonl")&&v.add(f(x,M.name))}}catch{}return v};console.log("Snapshotting JSONL files in ~/.claude/projects/ ...");let S=b();console.log(` Before: ${S.size} JSONL file(s)`),console.log('Spawning a tiny `claude -p --no-session-persistence "ok"`...');let y=Date.now(),T=await p("Reply with the single word: ok",[],{}),R=((Date.now()-y)/1e3).toFixed(1);if(console.log(` CLI exit: ${T.exitCode}, ${R}s`),!T.success){console.error(` stderr: ${T.stderr.slice(-500)}`),console.error("FAIL: claude CLI exited non-zero. Cannot validate spawn behavior."),process.exitCode=1;return}console.log("Snapshotting again...");let B=b();console.log(` After: ${B.size} JSONL file(s)`);let L=[];for(let v of B)S.has(v)||L.push(v);if(L.length===0){console.log(""),console.log("PASS: --no-session-persistence is honored on this claude CLI version."),console.log("It is safe to re-enable Tier-1 features (autoTitle.agentEnabled,"),console.log("semantic.enabled, semantic.autoExtractEnabled) in ~/.recall/config.json.");return}console.error(""),console.error(`FAIL: ${L.length} new JSONL file(s) appeared despite the flag.`),console.error("Tier-1 features WILL produce phantom sessions if re-enabled.");for(let v of L.slice(0,5))console.error(` - ${v}`);L.length>5&&console.error(` ... and ${L.length-5} more`),console.error(""),console.error("Possible causes:"),console.error(" 1. Your `claude` CLI is older than the version that added the flag."),console.error(" 2. The flag is in --help but not actually wired up in your version."),console.error("Mitigation: keep autoTitle.agentEnabled=false until claude is upgraded."),process.exitCode=1;return}let s=rd(),r=rt(),o=Z(),i=fd(),a=we(),d=0;try{d=E().prepare("SELECT COUNT(*) AS n FROM vec_chunks").get()?.n??0}catch{}let l=r||d>0;function u(){console.log("--- Tier 1 (inference \u2014 costs plan tokens) ---"),console.log(`Semantic search: ${s.enabled?"ENABLED":"disabled"}`),console.log(` claude CLI: ${s.claudeCliAvailable?"available":"NOT FOUND"}`),console.log(` Rate: ${s.ratePerMinute}/min`),console.log(` Model: ${s.model??"claude default"}`),console.log(` Sessions: ${s.processedSessions}/${s.totalSessions} summarized`),console.log(` Pending: ${s.pendingSessions}`),s.lastProcessedSessionId&&console.log(` Cursor: ${s.lastProcessedSessionId}`),s.backfillPaused&&console.log(" Backfill: PAUSED (run `recall semantic resume`)")}function m(){console.log("--- Tier 2 (vectors \u2014 free, local, zero tokens) ---"),console.log("Vector tier (Pro):"),console.log(` Model: ${r?"installed":"not installed"}`),console.log(` Embedder: ${o.loaded?"loaded":"not loaded"} (${o.modelId}, ${o.dim}d)`),console.log(` Worker: ${i.running?"running":"stopped"} (queue: ${i.queueDepth})`),console.log(` Chunks: ${d} indexed`)}if(l?(m(),console.log(""),u()):(u(),console.log(""),m()),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)`);let p=await Ed();p?.circuitBroken?console.log(` Breaker: TRIPPED \u2014 ${p.reason??"reason unknown"}. Run \`recall semantic auto-extract off\` then \`... on\` to reset, or restart the daemon.`):p&&p.consecutiveZeroTokenRuns>0&&console.log(` Breaker: ${p.consecutiveZeroTokenRuns} zero-token run(s) (trips at 3)`)}else 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}`)}k();k();k();Pe();var mt=400,er=768,FT="bge-base-en-v1.5";function jT(e){return Buffer.from(e.buffer,e.byteOffset,e.byteLength)}function UT(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!==er)throw new Error(`embedding dim mismatch: got ${e.embedding.length}, expected ${er}`);let t=e.embedding_model_id??FT,n=new Date().toISOString();return E().prepare(`INSERT INTO message_embeddings
1359
+ `).all(),f=Number(process.env.RECALL_REINDEX_MAX_CHUNKS??"0"),_=f>0?` (cap ${f} chunks/session)`:" (no cap)";console.log(`Reindexing ${g.length} sessions (skipping already-indexed)${_}...`);let b=0;for(let{id:E}of g){let S=Wo(E),y=f>0?S.slice(0,f):S;if(y.length===0){b++;continue}let T=y.map(O=>O.text),R=await Ne(T);Go(E);let B=Z().modelId,A=p.prepare(`INSERT INTO chunk_meta(session_id, message_uuids, text, embedding_model_id, embedding_dim, stale, generated_at)
1360
+ VALUES (?, ?, ?, ?, 768, 0, datetime('now'))`),v=p.prepare("INSERT INTO vec_chunks(rowid, embedding) VALUES (?, ?)");for(let O=0;O<y.length;O++){let x=A.run(E,JSON.stringify(y[O].messageUuids),y[O].text,B),M=Buffer.from(R[O].buffer,R[O].byteOffset,R[O].byteLength);v.run(BigInt(x.lastInsertRowid),M)}b++,b%10===0&&process.stdout.write(`\r ${b}/${g.length} `)}process.stdout.write(`
1361
+ `),console.log(`Reindexed ${b} sessions.`);return}if(n==="migrate"){await ie("Vector migration");let{runMigration:p}=await Promise.resolve().then(()=>(Vs(),qs)),{getActiveMigration:g,pauseMigration:f}=await Promise.resolve().then(()=>(Vt(),Ys)),_=t.yes??!1,b=t.noBackup??!1,E=t.dryRun??!1,S=()=>{try{let R=g();R&&(f(R.id),console.error("\n[migrate] received SIGINT; migration paused (cursor preserved). Re-run `recall semantic migrate` to resume."))}catch(R){console.error("[migrate] failed to pause migration on SIGINT:",R)}process.exit(130)};E||process.on("SIGINT",S);let y;try{y=await p({interactive:!_,keepBackup:!b,dryRun:E,projectName:t.project,onProgress:R=>{let A=(R.total>0?R.migrated/R.total*100:0).toFixed(1);process.stdout.write(`\r ${R.migrated}/${R.total} (${A}%) ${R.chunksPerSec.toFixed(1)} chunks/sec `)}})}finally{E||process.off("SIGINT",S)}process.stdout.write(`
1362
+ `);let T=0;y.ok?t.project?console.log(y.message):(console.log(`Migration complete. ${y.migrated} chunks re-embedded.`),y.backupRetained&&(console.log("Old vectors retained in vec_chunks_v1_backup for 30 days."),console.log("Run `recall semantic rollback-migration` to revert if needed."))):(console.error(`Migration: ${y.message}`),/nothing to migrate|user declined confirmation/.test(y.message)||(T=1)),process.exit(T)}if(n==="rollback-migration"){await ie("Vector migration rollback");let{rollbackMigration:p}=await Promise.resolve().then(()=>(Vs(),qs)),g=t.force??!1,f=await p({force:g});f.ok?console.log(f.message):(console.error(f.message),process.exitCode=1),process.exit(process.exitCode??0)}if(n==="prune-rollback"){await ie("Vector migration rollback pruning");let{pruneRollbackBackup:p}=await Promise.resolve().then(()=>(Vs(),qs)),g=t.force??!1,f=await p({force:g});f.ok?console.log(f.message):(console.error(f.message),process.exitCode=1),process.exit(process.exitCode??0)}if(n==="verify-backup"){await ie("Vector backup verification");let{getDb:p}=await Promise.resolve().then(()=>(k(),Vn));p().prepare("SELECT name FROM sqlite_master WHERE name='vec_chunks_v1_backup'").get()||(console.log("No vec_chunks_v1_backup table present (already pruned, or no migration has run). Nothing to verify."),process.exit(0));let{countBackupOrphans:_}=await Promise.resolve().then(()=>(xi(),cp));console.log("Scanning vec_chunks_v1_backup for orphan rows \u2014 this can take several minutes on a large backup (it scans every vector row).");let b=Date.now(),E=_(),S=((Date.now()-b)/1e3).toFixed(1);E===0&&(console.log(`\u2713 No orphan rows. Backup is consistent with chunk_meta (${S}s).`),process.exit(0)),console.error(`! ${E} orphan row(s) in vec_chunks_v1_backup (${S}s) \u2014 the backup-aware delete path missed these. This is a maintainer-facing bug; please report it. The backup is still safe for rollback.`),process.exit(1)}if(n==="verify-spawn"){if(!ae()){console.error("claude CLI not found on PATH. Install Claude Code first, then re-run."),process.exitCode=1;return}let{spawnClaudePrompt:p}=await Promise.resolve().then(()=>(Ye(),ws)),{homedir:g}=await import("node:os"),{join:f}=await import("node:path"),{readdirSync:_}=await import("node:fs"),b=f(g(),".claude","projects"),E=()=>{let v=new Set;try{for(let O of _(b,{withFileTypes:!0})){if(!O.isDirectory())continue;let x=f(b,O.name);for(let M of _(x,{withFileTypes:!0}))M.isFile()&&M.name.endsWith(".jsonl")&&v.add(f(x,M.name))}}catch{}return v};console.log("Snapshotting JSONL files in ~/.claude/projects/ ...");let S=E();console.log(` Before: ${S.size} JSONL file(s)`),console.log('Spawning a tiny `claude -p --no-session-persistence "ok"`...');let y=Date.now(),T=await p("Reply with the single word: ok",[],{}),R=((Date.now()-y)/1e3).toFixed(1);if(console.log(` CLI exit: ${T.exitCode}, ${R}s`),!T.success){console.error(` stderr: ${T.stderr.slice(-500)}`),console.error("FAIL: claude CLI exited non-zero. Cannot validate spawn behavior."),process.exitCode=1;return}console.log("Snapshotting again...");let B=E();console.log(` After: ${B.size} JSONL file(s)`);let A=[];for(let v of B)S.has(v)||A.push(v);if(A.length===0){console.log(""),console.log("PASS: --no-session-persistence is honored on this claude CLI version."),console.log("It is safe to re-enable Tier-1 features (autoTitle.agentEnabled,"),console.log("semantic.enabled, semantic.autoExtractEnabled) in ~/.recall/config.json.");return}console.error(""),console.error(`FAIL: ${A.length} new JSONL file(s) appeared despite the flag.`),console.error("Tier-1 features WILL produce phantom sessions if re-enabled.");for(let v of A.slice(0,5))console.error(` - ${v}`);A.length>5&&console.error(` ... and ${A.length-5} more`),console.error(""),console.error("Possible causes:"),console.error(" 1. Your `claude` CLI is older than the version that added the flag."),console.error(" 2. The flag is in --help but not actually wired up in your version."),console.error("Mitigation: keep autoTitle.agentEnabled=false until claude is upgraded."),process.exitCode=1;return}let s=ld(),r=rt(),o=Z(),i=Sd(),a=we(),d=0;try{d=h().prepare("SELECT COUNT(*) AS n FROM vec_chunks").get()?.n??0}catch{}let l=r||d>0;function u(){console.log("--- Tier 1 (inference \u2014 costs plan tokens) ---"),console.log(`Semantic search: ${s.enabled?"ENABLED":"disabled"}`),console.log(` claude CLI: ${s.claudeCliAvailable?"available":"NOT FOUND"}`),console.log(` Rate: ${s.ratePerMinute}/min`),console.log(` Model: ${s.model??"claude default"}`),console.log(` Sessions: ${s.processedSessions}/${s.totalSessions} summarized`),console.log(` Pending: ${s.pendingSessions}`),s.lastProcessedSessionId&&console.log(` Cursor: ${s.lastProcessedSessionId}`),s.backfillPaused&&console.log(" Backfill: PAUSED (run `recall semantic resume`)")}function m(){console.log("--- Tier 2 (vectors \u2014 free, local, zero tokens) ---"),console.log("Vector tier (Pro):"),console.log(` Model: ${r?"installed":"not installed"}`),console.log(` Embedder: ${o.loaded?"loaded":"not loaded"} (${o.modelId}, ${o.dim}d)`),console.log(` Worker: ${i.running?"running":"stopped"} (queue: ${i.queueDepth})`),console.log(` Chunks: ${d} indexed`)}if(l?(m(),console.log(""),u()):(u(),console.log(""),m()),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)`);let p=await Td();p?.circuitBroken?console.log(` Breaker: TRIPPED \u2014 ${p.reason??"reason unknown"}. Run \`recall semantic auto-extract off\` then \`... on\` to reset, or restart the daemon.`):p&&p.consecutiveZeroTokenRuns>0&&console.log(` Breaker: ${p.consecutiveZeroTokenRuns} zero-token run(s) (trips at 3)`)}else 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}`)}k();k();k();Fe();var mt=400,nr=768,nR="bge-base-en-v1.5";function sR(e){return Buffer.from(e.buffer,e.byteOffset,e.byteLength)}function rR(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!==nr)throw new Error(`embedding dim mismatch: got ${e.embedding.length}, expected ${nr}`);let t=e.embedding_model_id??nR,n=new Date().toISOString();return h().prepare(`INSERT INTO message_embeddings
1358
1363
  (message_uuid, session_id, embedding,
1359
1364
  embedding_model_id, embedding_dim, text_length, generated_at)
1360
1365
  VALUES (?, ?, ?, ?, ?, ?, ?)
@@ -1364,7 +1369,7 @@ show full content: recall paste --show <id>
1364
1369
  embedding_model_id = excluded.embedding_model_id,
1365
1370
  embedding_dim = excluded.embedding_dim,
1366
1371
  text_length = excluded.text_length,
1367
- generated_at = excluded.generated_at`).run(e.message_uuid,e.session_id,jT(e.embedding),t,er,e.text_length,n),{message_uuid:e.message_uuid,session_id:e.session_id,embedding_model_id:t,embedding_dim:er,text_length:e.text_length,generated_at:n}}function BT(e,t={}){let n=E(),s=t.force?`m.session_id = ? AND m.is_sidechain = 0
1372
+ generated_at = excluded.generated_at`).run(e.message_uuid,e.session_id,sR(e.embedding),t,nr,e.text_length,n),{message_uuid:e.message_uuid,session_id:e.session_id,embedding_model_id:t,embedding_dim:nr,text_length:e.text_length,generated_at:n}}function oR(e,t={}){let n=h(),s=t.force?`m.session_id = ? AND m.is_sidechain = 0
1368
1373
  AND m.content_text IS NOT NULL
1369
1374
  AND length(m.content_text) > ?`:`m.session_id = ? AND m.is_sidechain = 0
1370
1375
  AND m.content_text IS NOT NULL
@@ -1374,7 +1379,7 @@ show full content: recall paste --show <id>
1374
1379
  LEFT JOIN message_embeddings me ON me.message_uuid = m.uuid
1375
1380
  WHERE ${s}
1376
1381
  ORDER BY m.timestamp ASC, m.rowid ASC
1377
- LIMIT ?`).all(e,mt,r)}var tp=null;async function HT(){return tp||(Z().loaded||await Ke(),Ne)}async function WT(e,t={}){let n={embedded:0,skipped:0,failed:0,failures:[]},s=BT(e,{limit:t.limit,force:t.force});if(s.length===0)return n;let r=await HT(),o=s.map(a=>a.content_text),i;try{if(t.signal?.aborted)return n;i=await r(o)}catch(a){return n.failed=s.length,n.failures=s.map(d=>({uuid:d.uuid,error:a instanceof Error?a.message:String(a)})),n}if(i.length!==s.length)return n.failed=s.length,n.failures=s.map(a=>({uuid:a.uuid,error:`embedder returned ${i.length} vectors for ${s.length} inputs`})),n;for(let a=0;a<s.length&&!t.signal?.aborted;a++)try{UT({message_uuid:s[a].uuid,session_id:s[a].session_id,embedding:i[a],text_length:o[a].length}),n.embedded+=1}catch(d){n.failed+=1,n.failures.push({uuid:s[a].uuid,error:d instanceof Error?d.message:String(d)})}return n.skipped=0,n}async function np(e={}){let t=E(),n=[],s="s.message_count >= 1";typeof e.projectId=="number"&&(s+=" AND s.project_id = ?",n.push(e.projectId));let r=t.prepare(`SELECT DISTINCT s.id AS id
1382
+ LIMIT ?`).all(e,mt,r)}var dp=null;async function iR(){return dp||(Z().loaded||await Ke(),Ne)}async function aR(e,t={}){let n={embedded:0,skipped:0,failed:0,failures:[]},s=oR(e,{limit:t.limit,force:t.force});if(s.length===0)return n;let r=await iR(),o=s.map(a=>a.content_text),i;try{if(t.signal?.aborted)return n;i=await r(o)}catch(a){return n.failed=s.length,n.failures=s.map(d=>({uuid:d.uuid,error:a instanceof Error?a.message:String(a)})),n}if(i.length!==s.length)return n.failed=s.length,n.failures=s.map(a=>({uuid:a.uuid,error:`embedder returned ${i.length} vectors for ${s.length} inputs`})),n;for(let a=0;a<s.length&&!t.signal?.aborted;a++)try{rR({message_uuid:s[a].uuid,session_id:s[a].session_id,embedding:i[a],text_length:o[a].length}),n.embedded+=1}catch(d){n.failed+=1,n.failures.push({uuid:s[a].uuid,error:d instanceof Error?d.message:String(d)})}return n.skipped=0,n}async function up(e={}){let t=h(),n=[],s="s.message_count >= 1";typeof e.projectId=="number"&&(s+=" AND s.project_id = ?",n.push(e.projectId));let r=t.prepare(`SELECT DISTINCT s.id AS id
1378
1383
  FROM sessions s
1379
1384
  JOIN messages m ON m.session_id = s.id
1380
1385
  LEFT JOIN message_embeddings me ON me.message_uuid = m.uuid
@@ -1384,7 +1389,7 @@ show full content: recall paste --show <id>
1384
1389
  AND length(m.content_text) > ?
1385
1390
  AND me.message_uuid IS NULL
1386
1391
  ORDER BY s.started_at ASC
1387
- LIMIT ?`).all(...n,mt,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 WT(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 tr(e,t){return t===0?0:Math.round(e/t*1e3)/10}function Te(e){return E().prepare("SELECT id, name FROM projects WHERE name = ? LIMIT 1").get(e)??null}function sp(e={}){let t=E(),n=null;if(typeof e.projectId=="number"){let S=t.prepare("SELECT id, name FROM projects WHERE id = ?").get(e.projectId);S&&(n=S)}else e.projectName&&(n=Te(e.projectName));let s=n?" WHERE s.project_id = ?":"",r=n?[n.id]:[],o=t.prepare(`SELECT
1392
+ LIMIT ?`).all(...n,mt,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 aR(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 sr(e,t){return t===0?0:Math.round(e/t*1e3)/10}function Te(e){return h().prepare("SELECT id, name FROM projects WHERE name = ? LIMIT 1").get(e)??null}function pp(e={}){let t=h(),n=null;if(typeof e.projectId=="number"){let S=t.prepare("SELECT id, name FROM projects WHERE id = ?").get(e.projectId);S&&(n=S)}else e.projectName&&(n=Te(e.projectName));let s=n?" WHERE s.project_id = ?":"",r=n?[n.id]:[],o=t.prepare(`SELECT
1388
1393
  COUNT(*) AS total,
1389
1394
  SUM(CASE WHEN ss.session_id IS NOT NULL THEN 1 ELSE 0 END) AS with_semantic,
1390
1395
  SUM(CASE WHEN cm_count.session_id IS NOT NULL THEN 1 ELSE 0 END) AS with_chunks,
@@ -1407,13 +1412,13 @@ show full content: recall paste --show <id>
1407
1412
  FROM messages m
1408
1413
  ${u}`).get(...r),p=n?" JOIN sessions s ON s.id = me.session_id WHERE s.project_id = ?":"",g=t.prepare(`SELECT COUNT(*) AS embedded
1409
1414
  FROM message_embeddings me
1410
- ${p}`).get(...r),f=n?" JOIN sessions s ON s.id = cm.session_id WHERE s.project_id = ?":"",h=t.prepare(`SELECT COUNT(*) AS n
1415
+ ${p}`).get(...r),f=n?" JOIN sessions s ON s.id = cm.session_id WHERE s.project_id = ?":"",_=t.prepare(`SELECT COUNT(*) AS n
1411
1416
  FROM chunk_meta cm
1412
- ${f}`).get(...r),_=n?" JOIN sessions s ON s.id = cq.session_id WHERE s.project_id = ?":"",b=t.prepare(`SELECT COUNT(*) AS n
1417
+ ${f}`).get(...r),b=n?" JOIN sessions s ON s.id = cq.session_id WHERE s.project_id = ?":"",E=t.prepare(`SELECT COUNT(*) AS n
1413
1418
  FROM chunk_queue cq
1414
- ${_}`).get(...r);return{project:n,sessions:{total:i,with_semantic:a,with_semantic_pct:tr(a,i),with_chunks:d,with_chunks_pct:tr(d,i),with_message_embeddings:l,with_message_embeddings_pct:tr(l,i)},messages:{total:m.total??0,eligible:m.eligible??0,embedded:g.embedded,embedded_pct:tr(g.embedded,m.eligible??0),threshold_chars:mt},chunks:{chunk_meta_rows:h.n,chunk_queue_pending:b.n},generated_at:new Date().toISOString()}}function rp(e){let n=e.sessions.with_semantic_pct,s=e.sessions.total-e.sessions.with_semantic,r=e.sessions.total>0&&n>=95,o=r?`${n}% session_semantic coverage (${e.sessions.with_semantic} of ${e.sessions.total})`:e.sessions.total===0?"no sessions in scope":`${n}% session_semantic coverage (need \u226595%); ${s} sessions missing summaries`;return{passes:r,required_pct:95,actual_pct:n,missing_sessions:s,reason:o}}Rs();Sn();ge();wn();Pe();async function op(e,t){let n=(e??"audit").toLowerCase();if(n==="audit")return XT(t);if(n==="backfill-summaries")return zT(t);if(n==="backfill-messages")return JT(t);console.error(`Unknown embeddings action: ${e}. Supported: audit | backfill-summaries | backfill-messages`),process.exitCode=1}function wi(e){if(!e)return null;let t=Te(e);return t||"not-found"}async function XT(e){let t=wi(e.project);if(t==="not-found"){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let n=sp({projectId:t?t.id:void 0}),s=rp(n);if(e.json){console.log(JSON.stringify({report:n,verdict:s},null,2));return}GT(n,s),s.passes||(process.exitCode=1)}function GT(e,t){let n=e.project?`project "${e.project.name}"`:"all projects";console.log(`Embeddings coverage \u2014 ${n}`),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 zT(e){if(!we().enabled){console.error("Semantic search is disabled. Run `recall semantic on` first."),process.exitCode=1;return}let n=wi(e.project);if(n==="not-found"){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let s=e.limit?Math.max(1,Number(e.limit)):1e3,r=n?`project "${n.name}"`:"all projects";console.log(`Backfilling session_semantic \u2014 ${r} \u2014 up to ${s} sessions\u2026`);let o=Date.now(),i=0,a=await Ts({limit:s,projectId:n?n.id:void 0,onProgress:l=>{if(e.json||l.processed===i)return;i=l.processed;let u=l.total>0?` (${Math.round(l.processed/l.total*100)}%)`:"";process.stdout.write(`\r ${l.processed}/${l.total}${u} ok=${l.ok} failed=${l.failed} `)}});e.json||process.stdout.write(`
1415
- `);let d=((Date.now()-o)/1e3).toFixed(1);e.json?console.log(JSON.stringify({...a,elapsed_seconds:Number(d)},null,2)):console.log(`Done in ${d}s \u2014 processed=${a.processed} ok=${a.ok} failed=${a.failed}`)}async function JT(e){if(await oe("Per-message embeddings"),!rt()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}Z().loaded||await Ke();let t=wi(e.project);if(t==="not-found"){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let n=e.limit?Math.max(1,Number(e.limit)):200,s=t?`project "${t.name}"`:"all projects";console.log(`Embedding messages > ${mt} chars \u2014 ${s} \u2014 up to ${n} sessions\u2026`);let r=Date.now(),o=0,i=await np({projectId:t?t.id:void 0,limitSessions:n,onProgress:p=>{if(e.json||p.processed_sessions===o)return;o=p.processed_sessions;let g=p.total_sessions>0?` (${Math.round(p.processed_sessions/p.total_sessions*100)}%)`:"";process.stdout.write(`\r ${p.processed_sessions}/${p.total_sessions} sessions${g} embedded=${p.embedded_messages} failed=${p.failed_messages} `)}});e.json||process.stdout.write(`
1416
- `);let a=((Date.now()-r)/1e3).toFixed(1);e.json?console.log(JSON.stringify({...i,elapsed_seconds:Number(a)},null,2)):console.log(`Done in ${a}s \u2014 sessions=${i.processed_sessions}/${i.total_sessions} embedded=${i.embedded_messages} failed=${i.failed_messages}`);let d=E(),l=t?" AND s.project_id = ?":"",u=t?[t.id]:[],m=d.prepare(`SELECT COUNT(DISTINCT s.id) AS n
1419
+ ${b}`).get(...r);return{project:n,sessions:{total:i,with_semantic:a,with_semantic_pct:sr(a,i),with_chunks:d,with_chunks_pct:sr(d,i),with_message_embeddings:l,with_message_embeddings_pct:sr(l,i)},messages:{total:m.total??0,eligible:m.eligible??0,embedded:g.embedded,embedded_pct:sr(g.embedded,m.eligible??0),threshold_chars:mt},chunks:{chunk_meta_rows:_.n,chunk_queue_pending:E.n},generated_at:new Date().toISOString()}}function mp(e){let n=e.sessions.with_semantic_pct,s=e.sessions.total-e.sessions.with_semantic,r=e.sessions.total>0&&n>=95,o=r?`${n}% session_semantic coverage (${e.sessions.with_semantic} of ${e.sessions.total})`:e.sessions.total===0?"no sessions in scope":`${n}% session_semantic coverage (need \u226595%); ${s} sessions missing summaries`;return{passes:r,required_pct:95,actual_pct:n,missing_sessions:s,reason:o}}ks();Sn();ge();wn();Fe();async function gp(e,t){let n=(e??"audit").toLowerCase();if(n==="audit")return cR(t);if(n==="backfill-summaries")return dR(t);if(n==="backfill-messages")return uR(t);console.error(`Unknown embeddings action: ${e}. Supported: audit | backfill-summaries | backfill-messages`),process.exitCode=1}function Ci(e){if(!e)return null;let t=Te(e);return t||"not-found"}async function cR(e){let t=Ci(e.project);if(t==="not-found"){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let n=pp({projectId:t?t.id:void 0}),s=mp(n);if(e.json){console.log(JSON.stringify({report:n,verdict:s},null,2));return}lR(n,s),s.passes||(process.exitCode=1)}function lR(e,t){let n=e.project?`project "${e.project.name}"`:"all projects";console.log(`Embeddings coverage \u2014 ${n}`),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 dR(e){if(!we().enabled){console.error("Semantic search is disabled. Run `recall semantic on` first."),process.exitCode=1;return}let n=Ci(e.project);if(n==="not-found"){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let s=e.limit?Math.max(1,Number(e.limit)):1e3,r=n?`project "${n.name}"`:"all projects";console.log(`Backfilling session_semantic \u2014 ${r} \u2014 up to ${s} sessions\u2026`);let o=Date.now(),i=0,a=await Rs({limit:s,projectId:n?n.id:void 0,onProgress:l=>{if(e.json||l.processed===i)return;i=l.processed;let u=l.total>0?` (${Math.round(l.processed/l.total*100)}%)`:"";process.stdout.write(`\r ${l.processed}/${l.total}${u} ok=${l.ok} failed=${l.failed} `)}});e.json||process.stdout.write(`
1420
+ `);let d=((Date.now()-o)/1e3).toFixed(1);e.json?console.log(JSON.stringify({...a,elapsed_seconds:Number(d)},null,2)):console.log(`Done in ${d}s \u2014 processed=${a.processed} ok=${a.ok} failed=${a.failed}`)}async function uR(e){if(await ie("Per-message embeddings"),!rt()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}Z().loaded||await Ke();let t=Ci(e.project);if(t==="not-found"){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let n=e.limit?Math.max(1,Number(e.limit)):200,s=t?`project "${t.name}"`:"all projects";console.log(`Embedding messages > ${mt} chars \u2014 ${s} \u2014 up to ${n} sessions\u2026`);let r=Date.now(),o=0,i=await up({projectId:t?t.id:void 0,limitSessions:n,onProgress:p=>{if(e.json||p.processed_sessions===o)return;o=p.processed_sessions;let g=p.total_sessions>0?` (${Math.round(p.processed_sessions/p.total_sessions*100)}%)`:"";process.stdout.write(`\r ${p.processed_sessions}/${p.total_sessions} sessions${g} embedded=${p.embedded_messages} failed=${p.failed_messages} `)}});e.json||process.stdout.write(`
1421
+ `);let a=((Date.now()-r)/1e3).toFixed(1);e.json?console.log(JSON.stringify({...i,elapsed_seconds:Number(a)},null,2)):console.log(`Done in ${a}s \u2014 sessions=${i.processed_sessions}/${i.total_sessions} embedded=${i.embedded_messages} failed=${i.failed_messages}`);let d=h(),l=t?" AND s.project_id = ?":"",u=t?[t.id]:[],m=d.prepare(`SELECT COUNT(DISTINCT s.id) AS n
1417
1422
  FROM sessions s
1418
1423
  JOIN messages m ON m.session_id = s.id
1419
1424
  LEFT JOIN message_embeddings me ON me.message_uuid = m.uuid
@@ -1421,7 +1426,7 @@ show full content: recall paste --show <id>
1421
1426
  AND m.content_text IS NOT NULL
1422
1427
  AND length(m.content_text) > ?
1423
1428
  AND me.message_uuid IS NULL
1424
- ${l}`).get(mt,...u);m.n>0&&console.log(` ${m.n} session(s) still have unembedded eligible messages. Re-run to continue.`)}k();jt();Ye();import{createHash as eR}from"node:crypto";k();I();import{writeFileSync as YT,readFileSync as L1,existsSync as qT,mkdirSync as VT,readdirSync as A1}from"node:fs";import{join as ip}from"node:path";var Ti=ip(C,"output-index");function KT(){j(),qT(Ti)||VT(Ti,{recursive:!0})}function vn(e){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}function QT(e){if(!e)return null;try{return JSON.parse(e)}catch{return e}}function ap(e){return{session_id:e.session_id,files_written:vn(e.files_written),brands_mentioned:vn(e.brands_mentioned),terms_introduced:vn(e.terms_introduced),plan_ids_referenced:vn(e.plan_ids_referenced),bug_signatures:vn(e.bug_signatures),raw_extraction:QT(e.raw_extraction),extracted_at:e.extracted_at,extractor_version:e.extractor_version}}function cp(e){if(!e.session_id)throw new Error("session_id is required");let t=E(),n=new Date().toISOString(),s=JSON.stringify(e.files_written??[]),r=JSON.stringify(e.brands_mentioned??[]),o=JSON.stringify(e.terms_introduced??[]),i=JSON.stringify(e.plan_ids_referenced??[]),a=JSON.stringify(e.bug_signatures??[]),d=e.raw_extraction===void 0?null:JSON.stringify(e.raw_extraction),l=Math.max(1,Math.floor(e.extractor_version??1));t.prepare(`INSERT INTO session_output_index
1429
+ ${l}`).get(mt,...u);m.n>0&&console.log(` ${m.n} session(s) still have unembedded eligible messages. Re-run to continue.`)}k();jt();Ye();import{createHash as ER}from"node:crypto";k();I();import{writeFileSync as pR,readFileSync as ej,existsSync as mR,mkdirSync as gR,readdirSync as tj}from"node:fs";import{join as fp}from"node:path";var Ai=fp(C,"output-index");function fR(){j(),mR(Ai)||gR(Ai,{recursive:!0})}function In(e){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}function _R(e){if(!e)return null;try{return JSON.parse(e)}catch{return e}}function _p(e){return{session_id:e.session_id,files_written:In(e.files_written),brands_mentioned:In(e.brands_mentioned),terms_introduced:In(e.terms_introduced),plan_ids_referenced:In(e.plan_ids_referenced),bug_signatures:In(e.bug_signatures),raw_extraction:_R(e.raw_extraction),extracted_at:e.extracted_at,extractor_version:e.extractor_version}}function hp(e){if(!e.session_id)throw new Error("session_id is required");let t=h(),n=new Date().toISOString(),s=JSON.stringify(e.files_written??[]),r=JSON.stringify(e.brands_mentioned??[]),o=JSON.stringify(e.terms_introduced??[]),i=JSON.stringify(e.plan_ids_referenced??[]),a=JSON.stringify(e.bug_signatures??[]),d=e.raw_extraction===void 0?null:JSON.stringify(e.raw_extraction),l=Math.max(1,Math.floor(e.extractor_version??1));t.prepare(`INSERT INTO session_output_index
1425
1430
  (session_id, files_written, brands_mentioned, terms_introduced,
1426
1431
  plan_ids_referenced, bug_signatures, raw_extraction,
1427
1432
  extracted_at, extractor_version)
@@ -1434,7 +1439,7 @@ show full content: recall paste --show <id>
1434
1439
  bug_signatures = excluded.bug_signatures,
1435
1440
  raw_extraction = excluded.raw_extraction,
1436
1441
  extracted_at = excluded.extracted_at,
1437
- extractor_version = excluded.extractor_version`).run(e.session_id,s,r,o,i,a,d,n,l);let u=t.prepare("SELECT * FROM session_output_index WHERE session_id = ?").get(e.session_id);if(!u)throw new Error("setOutputIndex succeeded but read-back failed");let m=ap(u);return ZT(e.session_id),m}function In(e){let n=E().prepare("SELECT * FROM session_output_index WHERE session_id = ?").get(e);return n?ap(n):null}function ZT(e){try{KT();let t=In(e);if(!t)return;let n=ip(Ti,`${e}.json`),s={schema:"claude-recall.session-output-index.v1",backed_up_at:new Date().toISOString(),...t};YT(n,JSON.stringify(s,null,2))}catch(t){console.error("[output-index] backup failed:",t)}}var Mn=1,xi="claude-haiku-4-5-20251001",tR=3,nR=32e3,lp=2e3,sR=30,rR=30,oR=30,iR=30;function aR(e){let n=E().prepare(`SELECT s.id,
1442
+ extractor_version = excluded.extractor_version`).run(e.session_id,s,r,o,i,a,d,n,l);let u=t.prepare("SELECT * FROM session_output_index WHERE session_id = ?").get(e.session_id);if(!u)throw new Error("setOutputIndex succeeded but read-back failed");let m=_p(u);return hR(e.session_id),m}function Mn(e){let n=h().prepare("SELECT * FROM session_output_index WHERE session_id = ?").get(e);return n?_p(n):null}function hR(e){try{fR();let t=Mn(e);if(!t)return;let n=fp(Ai,`${e}.json`),s={schema:"claude-recall.session-output-index.v1",backed_up_at:new Date().toISOString(),...t};pR(n,JSON.stringify(s,null,2))}catch(t){console.error("[output-index] backup failed:",t)}}var Dn=1,Oi="claude-haiku-4-5-20251001",bR=3,SR=32e3,Ep=2e3,yR=30,wR=30,TR=30,RR=30;function kR(e){let n=h().prepare(`SELECT s.id,
1438
1443
  NULLIF(sa.alias, '') AS alias,
1439
1444
  s.auto_title,
1440
1445
  s.auto_title_source,
@@ -1445,15 +1450,15 @@ show full content: recall paste --show <id>
1445
1450
  FROM sessions s
1446
1451
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1447
1452
  LEFT JOIN projects p ON p.id = s.project_id
1448
- WHERE s.id = ?`).get(e);return n?{...n,alias_source:n.alias?"manual":null}:null}function dp(e,t={}){if(e.message_count<tR)return{eligible:!1,reason:"too-short"};let n=e.title_quality;if(n==="programmatic"||n==="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 s=In(e.id);if(s&&s.extractor_version>=Mn)return{eligible:!1,reason:"already-extracted"}}return{eligible:!0}}function cR(e){let t=aR(e);if(!t)return null;let s=E().prepare(`SELECT role, content_text
1453
+ WHERE s.id = ?`).get(e);return n?{...n,alias_source:n.alias?"manual":null}:null}function bp(e,t={}){if(e.message_count<bR)return{eligible:!1,reason:"too-short"};let n=e.title_quality;if(n==="programmatic"||n==="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 s=Mn(e.id);if(s&&s.extractor_version>=Dn)return{eligible:!1,reason:"already-extracted"}}return{eligible:!0}}function xR(e){let t=kR(e);if(!t)return null;let s=h().prepare(`SELECT role, content_text
1449
1454
  FROM messages
1450
1455
  WHERE session_id = ?
1451
1456
  AND is_sidechain = 0
1452
1457
  AND content_text IS NOT NULL
1453
- ORDER BY COALESCE(timestamp, ''), rowid`).all(e),r=[],o=0;for(let i of s){let a=i.role??"system",d=i.content_text.trim();if(!d)continue;let l=d.length>lp?d.slice(0,lp)+"\u2026":d,u=`${a}: ${l}`;if(o+u.length>nR)break;r.push(u),o+=u.length}return{meta:t,excerpt:r.join(`
1458
+ ORDER BY COALESCE(timestamp, ''), rowid`).all(e),r=[],o=0;for(let i of s){let a=i.role??"system",d=i.content_text.trim();if(!d)continue;let l=d.length>Ep?d.slice(0,Ep)+"\u2026":d,u=`${a}: ${l}`;if(o+u.length>SR)break;r.push(u),o+=u.length}return{meta:t,excerpt:r.join(`
1454
1459
 
1455
- `)}}function lR(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: "Acme 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(`
1456
- `)}function dR(e){return Array.isArray(e)&&e.every(t=>typeof t=="string")}function Ri(e,t,n=!1){if(!Array.isArray(e))return[];let s=new Set,r=[];for(let o of e){if(typeof o!="string")continue;let i=n?o.trim().toLowerCase():o.trim();if(!(!i||i.length>256)&&!s.has(i)&&(s.add(i),r.push(i),r.length>=t))break}return r}function uR(e,t){if(!Array.isArray(e))return[];let n=new Set,s=[];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||n.has(a))continue;n.add(a);let d=typeof i=="number"&&Number.isFinite(i)&&i>0?Math.floor(i):1;if(s.push({term:a,frequency:d}),s.length>=t)break}return s}function pR(e,t){if(!Array.isArray(e))return[];let n=[];for(let s of e){if(!s||typeof s!="object")continue;let r=s.error_type,o=s.snippet,i=s.file,a=typeof r=="string"&&r.trim().length>0?r.trim().slice(0,64):"unknown",d=typeof o=="string"?o.trim().replace(/\s+/g," ").slice(0,256):"";if(!d)continue;let l=typeof i=="string"&&i.trim().length>0?i.trim().slice(0,256):null,u=eR("sha256").update(`${a}::${d}`).digest("hex").slice(0,12);if(n.push({error_type:a,message_hash:u,snippet:d,file:l}),n.length>=t)break}return n}function mR(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 n=t.indexOf("{"),s=t.lastIndexOf("}");if(n===-1||s===-1||s<=n)return null;let r=t.slice(n,s+1),o;try{o=JSON.parse(r)}catch{return null}let i=Ri(o.files_written,200),a=Ri(o.brands_mentioned,rR),d=uR(o.terms_introduced,sR),l=Ri(o.plan_ids_referenced,oR),u=pR(o.bug_signatures,iR);return i.length===0&&a.length===0&&d.length===0&&l.length===0&&u.length===0&&!dR(o.files_written)?null:{files_written:i,brands_mentioned:a,terms_introduced:d,plan_ids_referenced:l,bug_signatures:u}}var ki=null;async function gR(e,t){return ki?ki(e,t):Nt(e,[],{model:t})}async function fR(e,t={}){if(t.signal?.aborted)return{session_id:e,ok:!1,failed:"aborted"};let n=cR(e);if(!n)return{session_id:e,ok:!1,skipped:"session-not-found"};let s=dp(n.meta,{force:t.force});if(!s.eligible)return{session_id:e,ok:!1,skipped:s.reason};if(!ki&&!ae())return{session_id:e,ok:!1,failed:"claude-cli-missing"};let r=lR(n),o=t.model??xi,i=await gR(r,o);if(!i.success){let u=(i.stderr||i.stdout||"").slice(0,400),m=u?Ce(u).redacted:void 0;return{session_id:e,ok:!1,failed:"claude-cli-error",exit_code:i.exitCode,stderr_excerpt:m}}let a=mR(i.stdout);if(!a){let u=i.stdout.slice(0,400),m=u?Ce(u).redacted:void 0;return{session_id:e,ok:!1,failed:"parse-failed",exit_code:i.exitCode,stderr_excerpt:m}}let d=_R(i.stdout),l=cp({session_id:e,files_written:a.files_written,brands_mentioned:a.brands_mentioned,terms_introduced:a.terms_introduced,plan_ids_referenced:a.plan_ids_referenced,bug_signatures:a.bug_signatures,raw_extraction:{model:o,usage:d,raw_response_excerpt:i.stdout.slice(0,4e3)},extractor_version:Mn});return{session_id:e,ok:!0,index:l,usage:d}}function _R(e){try{let t=JSON.parse(e.trim());if(t&&typeof t=="object"&&t.usage){let n=t.usage,s={};return typeof n.input_tokens=="number"&&(s.input_tokens=n.input_tokens),typeof n.output_tokens=="number"&&(s.output_tokens=n.output_tokens),s}}catch{}return null}function hR(e={}){let t=E(),n=[],s=[];typeof e.projectId=="number"&&(n.push("s.project_id = ?"),s.push(e.projectId));let r=Math.max(1,Math.min(1e4,e.limit??1e3)),o=n.length?`WHERE ${n.join(" AND ")}`:"",i=t.prepare(`SELECT s.id,
1460
+ `)}}function CR(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: "Acme 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(`
1461
+ `)}function AR(e){return Array.isArray(e)&&e.every(t=>typeof t=="string")}function Li(e,t,n=!1){if(!Array.isArray(e))return[];let s=new Set,r=[];for(let o of e){if(typeof o!="string")continue;let i=n?o.trim().toLowerCase():o.trim();if(!(!i||i.length>256)&&!s.has(i)&&(s.add(i),r.push(i),r.length>=t))break}return r}function LR(e,t){if(!Array.isArray(e))return[];let n=new Set,s=[];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||n.has(a))continue;n.add(a);let d=typeof i=="number"&&Number.isFinite(i)&&i>0?Math.floor(i):1;if(s.push({term:a,frequency:d}),s.length>=t)break}return s}function NR(e,t){if(!Array.isArray(e))return[];let n=[];for(let s of e){if(!s||typeof s!="object")continue;let r=s.error_type,o=s.snippet,i=s.file,a=typeof r=="string"&&r.trim().length>0?r.trim().slice(0,64):"unknown",d=typeof o=="string"?o.trim().replace(/\s+/g," ").slice(0,256):"";if(!d)continue;let l=typeof i=="string"&&i.trim().length>0?i.trim().slice(0,256):null,u=ER("sha256").update(`${a}::${d}`).digest("hex").slice(0,12);if(n.push({error_type:a,message_hash:u,snippet:d,file:l}),n.length>=t)break}return n}function OR(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 n=t.indexOf("{"),s=t.lastIndexOf("}");if(n===-1||s===-1||s<=n)return null;let r=t.slice(n,s+1),o;try{o=JSON.parse(r)}catch{return null}let i=Li(o.files_written,200),a=Li(o.brands_mentioned,wR),d=LR(o.terms_introduced,yR),l=Li(o.plan_ids_referenced,TR),u=NR(o.bug_signatures,RR);return i.length===0&&a.length===0&&d.length===0&&l.length===0&&u.length===0&&!AR(o.files_written)?null:{files_written:i,brands_mentioned:a,terms_introduced:d,plan_ids_referenced:l,bug_signatures:u}}var Ni=null;async function vR(e,t){return Ni?Ni(e,t):Nt(e,[],{model:t})}async function IR(e,t={}){if(t.signal?.aborted)return{session_id:e,ok:!1,failed:"aborted"};let n=xR(e);if(!n)return{session_id:e,ok:!1,skipped:"session-not-found"};let s=bp(n.meta,{force:t.force});if(!s.eligible)return{session_id:e,ok:!1,skipped:s.reason};if(!Ni&&!ae())return{session_id:e,ok:!1,failed:"claude-cli-missing"};let r=CR(n),o=t.model??Oi,i=await vR(r,o);if(!i.success){let u=(i.stderr||i.stdout||"").slice(0,400),m=u?Ce(u).redacted:void 0;return{session_id:e,ok:!1,failed:"claude-cli-error",exit_code:i.exitCode,stderr_excerpt:m}}let a=OR(i.stdout);if(!a){let u=i.stdout.slice(0,400),m=u?Ce(u).redacted:void 0;return{session_id:e,ok:!1,failed:"parse-failed",exit_code:i.exitCode,stderr_excerpt:m}}let d=MR(i.stdout),l=hp({session_id:e,files_written:a.files_written,brands_mentioned:a.brands_mentioned,terms_introduced:a.terms_introduced,plan_ids_referenced:a.plan_ids_referenced,bug_signatures:a.bug_signatures,raw_extraction:{model:o,usage:d,raw_response_excerpt:i.stdout.slice(0,4e3)},extractor_version:Dn});return{session_id:e,ok:!0,index:l,usage:d}}function MR(e){try{let t=JSON.parse(e.trim());if(t&&typeof t=="object"&&t.usage){let n=t.usage,s={};return typeof n.input_tokens=="number"&&(s.input_tokens=n.input_tokens),typeof n.output_tokens=="number"&&(s.output_tokens=n.output_tokens),s}}catch{}return null}function DR(e={}){let t=h(),n=[],s=[];typeof e.projectId=="number"&&(n.push("s.project_id = ?"),s.push(e.projectId));let r=Math.max(1,Math.min(1e4,e.limit??1e3)),o=n.length?`WHERE ${n.join(" AND ")}`:"",i=t.prepare(`SELECT s.id,
1457
1462
  NULLIF(sa.alias, '') AS alias,
1458
1463
  s.auto_title,
1459
1464
  s.auto_title_source,
@@ -1465,16 +1470,16 @@ show full content: recall paste --show <id>
1465
1470
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1466
1471
  LEFT JOIN projects p ON p.id = s.project_id
1467
1472
  ${o}
1468
- ORDER BY COALESCE(s.started_at, ''), s.id`).all(...s),a=[],d=new Map;for(let l of i){let u={...l,alias_source:l.alias?"manual":null},m=dp(u,{force:e.force});if(!m.eligible){let p=m.reason??"session-not-found";d.set(p,(d.get(p)??0)+1);continue}if(a.push(u),a.length>=r)break}return{eligible:a,skipped:d}}async function up(e={}){let t=hR({projectId:e.projectId,limit:e.limit,force:e.force}),n={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())n.skipped+=r;e.onProgress?.({...n});let s=[];for(let r of t.eligible){if(e.signal?.aborted)break;n.current_session_id=r.id,e.onProgress?.({...n});let o=await fR(r.id,{model:e.model,force:e.force,signal:e.signal});s.push(o),e.onResult?.(o),o.ok?n.ok+=1:o.skipped?n.skipped+=1:n.failed+=1,o.usage?.input_tokens&&(n.total_input_tokens+=o.usage.input_tokens),o.usage?.output_tokens&&(n.total_output_tokens+=o.usage.output_tokens),n.processed+=1,e.onProgress?.({...n})}return n.current_session_id=null,e.onProgress?.({...n}),{progress:n,results:s}}Ye();async function pp(e){if(!e.project){console.error("--project <name> is required."),process.exitCode=1;return}let t=Te(e.project);if(!t){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}if(!ae()){console.error("claude CLI not found on PATH. Install Claude Code first, then re-run."),process.exitCode=1;return}let n=e.limit?Math.max(1,Number(e.limit)):200,s=e.model??xi;e.json||console.log(`Extracting Output Index \u2014 project "${t.name}" \u2014 extractor v${Mn} \u2014 model ${s} \u2014 up to ${n} sessions\u2026`);let r=Date.now(),o=-1,{progress:i,results:a}=await up({projectId:t.id,limit:n,force:e.force,model:s,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(`
1469
- `);let d=Number(((Date.now()-r)/1e3).toFixed(1)),l=i.total>0?Math.round(i.ok/i.total*1e3)/10:0;if(e.json){let u=a.filter(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:Mn,model:s,progress:i,acceptance_pct:l,failures:u.slice(0,20),elapsed_seconds:d},null,2))}else console.log(`Done in ${d}s \u2014 ok=${i.ok}/${i.total} (${l}%) failed=${i.failed} skipped=${i.skipped}`),console.log(`Token spend: input=${i.total_input_tokens} output=${i.total_output_tokens}`),i.total>0&&l<90?(console.log(` \u26A0 Phase D acceptance bar is 90% non-empty Output Index; actual ${l}%. Inspect failures and re-run.`),process.exitCode=1):i.total===0&&console.log(" \u24D8 No eligible sessions (all sessions were skipped or already extracted).")}k();Dn();var or={citation:"same-project",similar:"same-project",skill_track:"same-project",bug_pattern:"cross-project",wiki_link:"cross-project",temporal_proximity:"same-project"},AR=2,NR=.25,OR=5,vR=60,IR=25;function rr(e){return e.trim().toLowerCase()}function MR(e){let t=new Set;for(let n of e.files_written)t.add(`file:${rr(n)}`);for(let n of e.brands_mentioned)t.add(`brand:${rr(n)}`);for(let n of e.terms_introduced)t.add(`term:${rr(n)}`);for(let n of e.plan_ids_referenced)t.add(`plan:${rr(n)}`);return t}function DR(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/vR);return Math.max(.2,t)}function $R(e,t){if(!e||!t)return 0;let n=Date.parse(e),s=Date.parse(t);return!Number.isFinite(n)||!Number.isFinite(s)?0:Math.abs(s-n)/(1e3*60*60*24)}function PR(e){let t=In(e);return t?{session_id:t.session_id,files_written:t.files_written,brands_mentioned:t.brands_mentioned,terms_introduced:t.terms_introduced.map(n=>n.term),plan_ids_referenced:t.plan_ids_referenced}:null}function FR(e){return E().prepare(`SELECT s.id AS id, s.project_id AS project_id, s.started_at AS started_at,
1473
+ ORDER BY COALESCE(s.started_at, ''), s.id`).all(...s),a=[],d=new Map;for(let l of i){let u={...l,alias_source:l.alias?"manual":null},m=bp(u,{force:e.force});if(!m.eligible){let p=m.reason??"session-not-found";d.set(p,(d.get(p)??0)+1);continue}if(a.push(u),a.length>=r)break}return{eligible:a,skipped:d}}async function Sp(e={}){let t=DR({projectId:e.projectId,limit:e.limit,force:e.force}),n={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())n.skipped+=r;e.onProgress?.({...n});let s=[];for(let r of t.eligible){if(e.signal?.aborted)break;n.current_session_id=r.id,e.onProgress?.({...n});let o=await IR(r.id,{model:e.model,force:e.force,signal:e.signal});s.push(o),e.onResult?.(o),o.ok?n.ok+=1:o.skipped?n.skipped+=1:n.failed+=1,o.usage?.input_tokens&&(n.total_input_tokens+=o.usage.input_tokens),o.usage?.output_tokens&&(n.total_output_tokens+=o.usage.output_tokens),n.processed+=1,e.onProgress?.({...n})}return n.current_session_id=null,e.onProgress?.({...n}),{progress:n,results:s}}Ye();async function yp(e){if(!e.project){console.error("--project <name> is required."),process.exitCode=1;return}let t=Te(e.project);if(!t){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}if(!ae()){console.error("claude CLI not found on PATH. Install Claude Code first, then re-run."),process.exitCode=1;return}let n=e.limit?Math.max(1,Number(e.limit)):200,s=e.model??Oi;e.json||console.log(`Extracting Output Index \u2014 project "${t.name}" \u2014 extractor v${Dn} \u2014 model ${s} \u2014 up to ${n} sessions\u2026`);let r=Date.now(),o=-1,{progress:i,results:a}=await Sp({projectId:t.id,limit:n,force:e.force,model:s,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(`
1474
+ `);let d=Number(((Date.now()-r)/1e3).toFixed(1)),l=i.total>0?Math.round(i.ok/i.total*1e3)/10:0;if(e.json){let u=a.filter(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:Dn,model:s,progress:i,acceptance_pct:l,failures:u.slice(0,20),elapsed_seconds:d},null,2))}else console.log(`Done in ${d}s \u2014 ok=${i.ok}/${i.total} (${l}%) failed=${i.failed} skipped=${i.skipped}`),console.log(`Token spend: input=${i.total_input_tokens} output=${i.total_output_tokens}`),i.total>0&&l<90?(console.log(` \u26A0 Phase D acceptance bar is 90% non-empty Output Index; actual ${l}%. Inspect failures and re-run.`),process.exitCode=1):i.total===0&&console.log(" \u24D8 No eligible sessions (all sessions were skipped or already extracted).")}k();$n();var ar={citation:"same-project",similar:"same-project",skill_track:"same-project",bug_pattern:"cross-project",wiki_link:"cross-project",temporal_proximity:"same-project"},zR=2,YR=.25,qR=5,VR=60,KR=25;function ir(e){return e.trim().toLowerCase()}function QR(e){let t=new Set;for(let n of e.files_written)t.add(`file:${ir(n)}`);for(let n of e.brands_mentioned)t.add(`brand:${ir(n)}`);for(let n of e.terms_introduced)t.add(`term:${ir(n)}`);for(let n of e.plan_ids_referenced)t.add(`plan:${ir(n)}`);return t}function ZR(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/VR);return Math.max(.2,t)}function ek(e,t){if(!e||!t)return 0;let n=Date.parse(e),s=Date.parse(t);return!Number.isFinite(n)||!Number.isFinite(s)?0:Math.abs(s-n)/(1e3*60*60*24)}function tk(e){let t=Mn(e);return t?{session_id:t.session_id,files_written:t.files_written,brands_mentioned:t.brands_mentioned,terms_introduced:t.terms_introduced.map(n=>n.term),plan_ids_referenced:t.plan_ids_referenced}:null}function nk(e){return h().prepare(`SELECT s.id AS id, s.project_id AS project_id, s.started_at AS started_at,
1470
1475
  s.rowid AS rowid,
1471
1476
  (SELECT COALESCE(MAX(m.rowid), 0) FROM messages m WHERE m.session_id = s.id)
1472
1477
  AS maxMessageRowid
1473
1478
  FROM sessions s
1474
1479
  JOIN session_output_index oi ON oi.session_id = s.id
1475
1480
  WHERE s.project_id = ?
1476
- ORDER BY COALESCE(s.started_at, ''), s.id`).all(e)}function jR(e,t){let n=new Map,s=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=MR(i);if(a.size!==0){s.set(o.id,a);for(let d of a){let l=n.get(d);l?l.push(o.id):n.set(d,[o.id])}}}return{posting:n,vocab:s,startedAt:r}}function UR(e,t){let n=t.vocab.get(e),s=t.startedAt.get(e)??null;if(!n||!s)return[];let r=new Map;for(let i of n){let a=t.posting.get(i);if(a)for(let d of a){if(d===e)continue;let l=t.startedAt.get(d);if(!l||l>=s)continue;let u=r.get(d);u?u.push(i):r.set(d,[i])}}let o=[];for(let[i,a]of r){let d=a.length;if(d<AR)continue;let l=t.startedAt.get(i)??null,u=$R(s,l),m=DR(u),p=Math.min(1,d/OR*m);if(p<NR)continue;let g=a.slice(0,12);o.push({target_session_id:i,matched_terms:g,overlap:d,days_apart:Math.round(u*10)/10,recency:Math.round(m*1e3)/1e3,confidence:Math.round(p*1e3)/1e3})}return o.sort((i,a)=>a.confidence-i.confidence),o.slice(0,IR)}async function Sp(e){if(or.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project \u2014 refusing to run inference");let t=FR(e.projectId),n=new Map;for(let a of t){let d=PR(a.id);d&&n.set(a.id,d)}let s=jR(t,n),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 a of t){if(e.signal?.aborted)break;if(typeof e.sinceRowid=="number"&&a.maxMessageRowid<=e.sinceRowid)continue;r.current_session_id=a.id,e.onProgress?.({...r});let d=UR(a.id,s);for(let l of d)o.push({source_session_id:a.id,target_session_id:l.target_session_id,confidence:l.confidence,matched_terms:l.matched_terms,overlap:l.overlap,recency:l.recency,days_apart:l.days_apart});r.processed_sessions+=1,e.onProgress?.({...r})}let i=[];return o.length>0&&(E().transaction(()=>{for(let l of o)try{let u=gt({source_session_id:l.source_session_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"},{deferMirror:!0});i.push(u.id),r.suggestions_created+=1}catch(u){console.error("[citation-inference] createSuggestion failed:",u)}})(),ft()),r.current_session_id=null,e.onProgress?.({...r}),{progress:r,suggestion_ids:i}}async function yp(e){if(!e.project){console.error("--project <name> is required."),process.exitCode=1;return}let t=Te(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 n=Date.now(),s=-1,r=await Sp({projectId:t.id,onProgress:i=>{if(e.json||i.processed_sessions===s)return;s=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(`
1477
- `);let o=Number(((Date.now()-n)/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 ek,readFileSync as tk}from"node:fs";import{join as nk}from"node:path";k();Dn();var BR=/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/gi,HR=[/\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],WR=.95,XR=.85,GR=.7,vi=50,zR=50;function JR(e){if(!e)return[];let t=new Set,n=[],s=e.match(BR);if(!s)return n;for(let r of s){let o=r.toLowerCase();if(!t.has(o)&&(t.add(o),n.push(o),n.length>=vi))break}return n}function YR(e){if(!e)return[];let t=new Set,n=[];for(let s of HR){s.lastIndex=0;let r=e.match(s);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),n.push(i),n.length>=vi))break}if(n.length>=vi)break}}return n}function Ii(e){let t=E();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 wp(e,t){let n=E(),s=typeof t=="number";if(typeof e=="number"){let o=`SELECT m.uuid AS message_uuid, m.session_id, m.content_text,
1481
+ ORDER BY COALESCE(s.started_at, ''), s.id`).all(e)}function sk(e,t){let n=new Map,s=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=QR(i);if(a.size!==0){s.set(o.id,a);for(let d of a){let l=n.get(d);l?l.push(o.id):n.set(d,[o.id])}}}return{posting:n,vocab:s,startedAt:r}}function rk(e,t){let n=t.vocab.get(e),s=t.startedAt.get(e)??null;if(!n||!s)return[];let r=new Map;for(let i of n){let a=t.posting.get(i);if(a)for(let d of a){if(d===e)continue;let l=t.startedAt.get(d);if(!l||l>=s)continue;let u=r.get(d);u?u.push(i):r.set(d,[i])}}let o=[];for(let[i,a]of r){let d=a.length;if(d<zR)continue;let l=t.startedAt.get(i)??null,u=ek(s,l),m=ZR(u),p=Math.min(1,d/qR*m);if(p<YR)continue;let g=a.slice(0,12);o.push({target_session_id:i,matched_terms:g,overlap:d,days_apart:Math.round(u*10)/10,recency:Math.round(m*1e3)/1e3,confidence:Math.round(p*1e3)/1e3})}return o.sort((i,a)=>a.confidence-i.confidence),o.slice(0,KR)}async function Lp(e){if(ar.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project \u2014 refusing to run inference");let t=nk(e.projectId),n=new Map;for(let a of t){let d=tk(a.id);d&&n.set(a.id,d)}let s=sk(t,n),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 a of t){if(e.signal?.aborted)break;if(typeof e.sinceRowid=="number"&&a.maxMessageRowid<=e.sinceRowid)continue;r.current_session_id=a.id,e.onProgress?.({...r});let d=rk(a.id,s);for(let l of d)o.push({source_session_id:a.id,target_session_id:l.target_session_id,confidence:l.confidence,matched_terms:l.matched_terms,overlap:l.overlap,recency:l.recency,days_apart:l.days_apart});r.processed_sessions+=1,e.onProgress?.({...r})}let i=[];return o.length>0&&(h().transaction(()=>{for(let l of o)try{let u=gt({source_session_id:l.source_session_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"},{deferMirror:!0});i.push(u.id),r.suggestions_created+=1}catch(u){console.error("[citation-inference] createSuggestion failed:",u)}})(),ft()),r.current_session_id=null,e.onProgress?.({...r}),{progress:r,suggestion_ids:i}}async function Np(e){if(!e.project){console.error("--project <name> is required."),process.exitCode=1;return}let t=Te(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 n=Date.now(),s=-1,r=await Lp({projectId:t.id,onProgress:i=>{if(e.json||i.processed_sessions===s)return;s=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(`
1482
+ `);let o=Number(((Date.now()-n)/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 Ek,readFileSync as bk}from"node:fs";import{join as Sk}from"node:path";k();$n();var ok=/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/gi,ik=[/\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],ak=.95,ck=.85,lk=.7,Pi=50,dk=50;function uk(e){if(!e)return[];let t=new Set,n=[],s=e.match(ok);if(!s)return n;for(let r of s){let o=r.toLowerCase();if(!t.has(o)&&(t.add(o),n.push(o),n.length>=Pi))break}return n}function pk(e){if(!e)return[];let t=new Set,n=[];for(let s of ik){s.lastIndex=0;let r=e.match(s);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),n.push(i),n.length>=Pi))break}if(n.length>=Pi)break}}return n}function Fi(e){let t=h();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 Op(e,t){let n=h(),s=typeof t=="number";if(typeof e=="number"){let o=`SELECT m.uuid AS message_uuid, m.session_id, m.content_text,
1478
1483
  s.project_id
1479
1484
  FROM messages m
1480
1485
  JOIN sessions s ON s.id = m.session_id
@@ -1489,12 +1494,12 @@ show full content: recall paste --show <id>
1489
1494
  WHERE m.is_sidechain = 0
1490
1495
  AND m.content_text IS NOT NULL
1491
1496
  AND length(m.content_text) > 0`+(s?`
1492
- AND m.rowid > ?`:"");return s?n.prepare(r).all(t):n.prepare(r).all()}function qR(e){let t=E(),n=typeof e=="number"?"WHERE s.project_id = ?":"",s=typeof e=="number"?[e]:[];return t.prepare(`SELECT oi.session_id AS session_id,
1497
+ AND m.rowid > ?`:"");return s?n.prepare(r).all(t):n.prepare(r).all()}function mk(e){let t=h(),n=typeof e=="number"?"WHERE s.project_id = ?":"",s=typeof e=="number"?[e]:[];return t.prepare(`SELECT oi.session_id AS session_id,
1493
1498
  s.project_id AS project_id,
1494
1499
  oi.plan_ids_referenced AS plan_ids_json
1495
1500
  FROM session_output_index oi
1496
1501
  JOIN sessions s ON s.id = oi.session_id
1497
- ${n}`).all(...s)}function VR(e){if(!e)return[];try{let t=JSON.parse(e);if(Array.isArray(t))return t.filter(n=>typeof n=="string")}catch{}return[]}function KR(e={}){if(or.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project");let t=Ii(e.projectId),n=new Set(t.map(a=>a.id)),s=new Map;for(let a of t)s.set(a.id,a.project_id);let r=E(),o=0;return r.transaction(()=>{for(let a of wp(e.projectId,e.sinceRowid)){if(e.signal?.aborted)break;let d=JR(a.content_text);if(d.length===0)continue;let l=s.get(a.session_id);if(l!==void 0)for(let u of d){if(u===a.session_id)continue;let m=s.get(u);if(!(m===void 0&&!n.has(u))&&!(m!==void 0&&l!==void 0&&m!==l))try{gt({source_session_id:a.session_id,target_session_id:u,link_type:"citation",confidence:WR,evidence:{matched_uuid:u,source_message_uuid:a.message_uuid,scanner:"uuid-ref"},inferred_by:"L1"},{deferMirror:!0}),o+=1}catch{}}}})(),o>0&&ft(),{created:o}}function QR(e={}){let t=qR(e.projectId);if(t.length===0)return{created:0};let n=new Map;for(let l of t){let u=VR(l.plan_ids_json);for(let m of u){let p=m.trim().toLowerCase();if(!p)continue;let g=n.get(p);g?g.push({id:l.session_id,project_id:l.project_id}):n.set(p,[{id:l.session_id,project_id:l.project_id}])}}if(n.size===0)return{created:0};let s=Ii(e.projectId),r=new Map;for(let l of s)r.set(l.id,l.project_id);let o=0,i=new Map;for(let l of wp(e.projectId,e.sinceRowid)){if(e.signal?.aborted)break;let u=YR(l.content_text);if(u.length===0)continue;let m=r.get(l.session_id);if(m!==void 0)for(let p of u){let g=n.get(p);if(g)for(let f of g){if(f.id===l.session_id||f.project_id!==m)continue;let h=i.get(l.session_id);h||(h=new Map,i.set(l.session_id,h));let _=h.get(f.id);_||(_=new Set,h.set(f.id,_)),_.add(p)}}}return E().transaction(()=>{for(let[l,u]of i)for(let[m,p]of u)try{gt({source_session_id:l,target_session_id:m,link_type:"citation",confidence:XR,evidence:{matched_plan_ids:Array.from(p).slice(0,12),scanner:"plan-ref"},inferred_by:"L1"},{deferMirror:!0}),o+=1}catch{}})(),o>0&&ft(),{created:o}}function ZR(e){if(or.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=Ii(e.projectId),n=new Map,s=new Map;if(t.length>0){let d=E(),l=t.map(p=>p.id),u=l.map(()=>"?").join(","),m=d.prepare(`SELECT id, started_at FROM sessions WHERE id IN (${u})`).all(...l);for(let p of m)s.set(p.id,p.started_at)}for(let d of t)n.set(d.id,d.project_id);let r=new Map;for(let d of e.registry.terminals){let l=e.registry.sessions_by_pid[String(d.shell_pid)]??[];if(l.length===0)continue;let u=`${d.cwd??"<no-cwd>"}::${d.tab_name}`,m=r.get(u);m||(m=new Set,r.set(u,m));for(let p of l)m.add(p)}let o=E(),i=0;return o.transaction(()=>{for(let[,d]of r){if(d.size<2)continue;let l=new Map;for(let u of d){let m=n.get(u);if(m===void 0||typeof e.projectId=="number"&&m!==e.projectId)continue;let p=l.get(m);p||(p=[],l.set(m,p)),p.push(u)}for(let[,u]of l){if(u.length<2)continue;u.sort((p,g)=>{let f=s.get(p)??"",h=s.get(g)??"";return f<h?-1:f>h?1:p<g?-1:1});let m=0;for(let p=1;p<u.length&&!e.signal?.aborted;p++)for(let g=0;g<p&&!(m>=zR);g++)try{gt({source_session_id:u[p],target_session_id:u[g],link_type:"skill_track",confidence:GR,evidence:{shared_tab_signature:!0,bucket_size:u.length,scanner:"tab-carry"},inferred_by:"L1"},{deferMirror:!0}),i+=1,m+=1}catch{}}}})(),i>0&&ft(),{created:i}}function Tp(e={}){let t=KR(e);if(e.signal?.aborted)return{uuid_refs_created:t.created,plan_refs_created:0,tab_carry_created:0,total:t.created};let n=QR(e);if(e.signal?.aborted)return{uuid_refs_created:t.created,plan_refs_created:n.created,tab_carry_created:0,total:t.created+n.created};let s=e.registry?ZR({projectId:e.projectId,signal:e.signal,registry:e.registry}):{created:0};return{uuid_refs_created:t.created,plan_refs_created:n.created,tab_carry_created:s.created,total:t.created+n.created+s.created}}I();function sk(){let e=nk(C,"terminals.json");if(ek(e))try{let t=tk(e,"utf8"),n=JSON.parse(t);if(!Array.isArray(n.terminals))return;let s=n.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=n.sessions_by_pid??{};return{terminals:s,sessions_by_pid:r}}catch{return}}async function Rp(e){let t=null;if(e.project&&(t=Te(e.project),!t)){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let n=sk(),s=t?`project "${t.name}"`:"all projects";e.json||console.log(`L1 deterministic inference \u2014 ${s} \u2014 `+(n?`(tab registry has ${n.terminals.length} entries)`:"(no tab registry; tab-carry scanner skipped)"));let r=Date.now(),o=Tp({projectId:t?.id,registry:n}),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)."))}k();Ye();Dn();function Mi(e){if(!e||e.length===0)return 0;let t=1,n=0;for(let s of e){if(!Number.isFinite(s))continue;let r=Math.max(0,Math.min(1,s));if(t*=1-r,n+=1,t<=1e-9)return 1}return n===0?0:Math.round((1-t)*1e4)/1e4}var $i="claude-haiku-4-5-20251001",ir=.4,Pi=.95,kp=30,xp=240,rk=new Set(["CITATION","SIMILAR","SKILL_TRACK","UNRELATED"]),ok={CITATION:"citation",SIMILAR:"similar",SKILL_TRACK:"skill_track"};function Ap(e){return E().prepare(`SELECT s.id,
1502
+ ${n}`).all(...s)}function gk(e){if(!e)return[];try{let t=JSON.parse(e);if(Array.isArray(t))return t.filter(n=>typeof n=="string")}catch{}return[]}function fk(e={}){if(ar.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project");let t=Fi(e.projectId),n=new Set(t.map(a=>a.id)),s=new Map;for(let a of t)s.set(a.id,a.project_id);let r=h(),o=0;return r.transaction(()=>{for(let a of Op(e.projectId,e.sinceRowid)){if(e.signal?.aborted)break;let d=uk(a.content_text);if(d.length===0)continue;let l=s.get(a.session_id);if(l!==void 0)for(let u of d){if(u===a.session_id)continue;let m=s.get(u);if(!(m===void 0&&!n.has(u))&&!(m!==void 0&&l!==void 0&&m!==l))try{gt({source_session_id:a.session_id,target_session_id:u,link_type:"citation",confidence:ak,evidence:{matched_uuid:u,source_message_uuid:a.message_uuid,scanner:"uuid-ref"},inferred_by:"L1"},{deferMirror:!0}),o+=1}catch{}}}})(),o>0&&ft(),{created:o}}function _k(e={}){let t=mk(e.projectId);if(t.length===0)return{created:0};let n=new Map;for(let l of t){let u=gk(l.plan_ids_json);for(let m of u){let p=m.trim().toLowerCase();if(!p)continue;let g=n.get(p);g?g.push({id:l.session_id,project_id:l.project_id}):n.set(p,[{id:l.session_id,project_id:l.project_id}])}}if(n.size===0)return{created:0};let s=Fi(e.projectId),r=new Map;for(let l of s)r.set(l.id,l.project_id);let o=0,i=new Map;for(let l of Op(e.projectId,e.sinceRowid)){if(e.signal?.aborted)break;let u=pk(l.content_text);if(u.length===0)continue;let m=r.get(l.session_id);if(m!==void 0)for(let p of u){let g=n.get(p);if(g)for(let f of g){if(f.id===l.session_id||f.project_id!==m)continue;let _=i.get(l.session_id);_||(_=new Map,i.set(l.session_id,_));let b=_.get(f.id);b||(b=new Set,_.set(f.id,b)),b.add(p)}}}return h().transaction(()=>{for(let[l,u]of i)for(let[m,p]of u)try{gt({source_session_id:l,target_session_id:m,link_type:"citation",confidence:ck,evidence:{matched_plan_ids:Array.from(p).slice(0,12),scanner:"plan-ref"},inferred_by:"L1"},{deferMirror:!0}),o+=1}catch{}})(),o>0&&ft(),{created:o}}function hk(e){if(ar.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=Fi(e.projectId),n=new Map,s=new Map;if(t.length>0){let d=h(),l=t.map(p=>p.id),u=l.map(()=>"?").join(","),m=d.prepare(`SELECT id, started_at FROM sessions WHERE id IN (${u})`).all(...l);for(let p of m)s.set(p.id,p.started_at)}for(let d of t)n.set(d.id,d.project_id);let r=new Map;for(let d of e.registry.terminals){let l=e.registry.sessions_by_pid[String(d.shell_pid)]??[];if(l.length===0)continue;let u=`${d.cwd??"<no-cwd>"}::${d.tab_name}`,m=r.get(u);m||(m=new Set,r.set(u,m));for(let p of l)m.add(p)}let o=h(),i=0;return o.transaction(()=>{for(let[,d]of r){if(d.size<2)continue;let l=new Map;for(let u of d){let m=n.get(u);if(m===void 0||typeof e.projectId=="number"&&m!==e.projectId)continue;let p=l.get(m);p||(p=[],l.set(m,p)),p.push(u)}for(let[,u]of l){if(u.length<2)continue;u.sort((p,g)=>{let f=s.get(p)??"",_=s.get(g)??"";return f<_?-1:f>_?1:p<g?-1:1});let m=0;for(let p=1;p<u.length&&!e.signal?.aborted;p++)for(let g=0;g<p&&!(m>=dk);g++)try{gt({source_session_id:u[p],target_session_id:u[g],link_type:"skill_track",confidence:lk,evidence:{shared_tab_signature:!0,bucket_size:u.length,scanner:"tab-carry"},inferred_by:"L1"},{deferMirror:!0}),i+=1,m+=1}catch{}}}})(),i>0&&ft(),{created:i}}function vp(e={}){let t=fk(e);if(e.signal?.aborted)return{uuid_refs_created:t.created,plan_refs_created:0,tab_carry_created:0,total:t.created};let n=_k(e);if(e.signal?.aborted)return{uuid_refs_created:t.created,plan_refs_created:n.created,tab_carry_created:0,total:t.created+n.created};let s=e.registry?hk({projectId:e.projectId,signal:e.signal,registry:e.registry}):{created:0};return{uuid_refs_created:t.created,plan_refs_created:n.created,tab_carry_created:s.created,total:t.created+n.created+s.created}}I();function yk(){let e=Sk(C,"terminals.json");if(Ek(e))try{let t=bk(e,"utf8"),n=JSON.parse(t);if(!Array.isArray(n.terminals))return;let s=n.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=n.sessions_by_pid??{};return{terminals:s,sessions_by_pid:r}}catch{return}}async function Ip(e){let t=null;if(e.project&&(t=Te(e.project),!t)){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}let n=yk(),s=t?`project "${t.name}"`:"all projects";e.json||console.log(`L1 deterministic inference \u2014 ${s} \u2014 `+(n?`(tab registry has ${n.terminals.length} entries)`:"(no tab registry; tab-carry scanner skipped)"));let r=Date.now(),o=vp({projectId:t?.id,registry:n}),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)."))}k();Ye();$n();function ji(e){if(!e||e.length===0)return 0;let t=1,n=0;for(let s of e){if(!Number.isFinite(s))continue;let r=Math.max(0,Math.min(1,s));if(t*=1-r,n+=1,t<=1e-9)return 1}return n===0?0:Math.round((1-t)*1e4)/1e4}var Bi="claude-haiku-4-5-20251001",cr=.4,Hi=.95,Mp=30,Dp=240,wk=new Set(["CITATION","SIMILAR","SKILL_TRACK","UNRELATED"]),Tk={CITATION:"citation",SIMILAR:"similar",SKILL_TRACK:"skill_track"};function Fp(e){return h().prepare(`SELECT s.id,
1498
1503
  s.source_session_id,
1499
1504
  s.target_session_id,
1500
1505
  s.link_type,
@@ -1504,7 +1509,7 @@ show full content: recall paste --show <id>
1504
1509
  FROM session_link_suggestions s
1505
1510
  JOIN sessions src ON src.id = s.source_session_id
1506
1511
  WHERE s.status = 'pending'
1507
- AND src.project_id = ?`).all(e)}function ik(e){if(e.length===0)return new Map;let t=E(),n=e.map(()=>"?").join(","),s=t.prepare(`SELECT s.id,
1512
+ AND src.project_id = ?`).all(e)}function Rk(e){if(e.length===0)return new Map;let t=h(),n=e.map(()=>"?").join(","),s=t.prepare(`SELECT s.id,
1508
1513
  NULLIF(sa.alias, '') AS alias,
1509
1514
  s.auto_title,
1510
1515
  s.first_user_message,
@@ -1513,18 +1518,18 @@ show full content: recall paste --show <id>
1513
1518
  FROM sessions s
1514
1519
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1515
1520
  LEFT JOIN projects p ON p.id = s.project_id
1516
- WHERE s.id IN (${n})`).all(...e),r=new Map;for(let o of s)r.set(o.id,o);return r}function Cp(e,t){if(!e)return t.slice(0,8);let n=e.first_user_message?e.first_user_message.slice(0,80):null;return e.alias??e.auto_title??n??t.slice(0,8)}function Lp(e){try{return JSON.parse(e)}catch{return e}}function ak(e){let t=e.minConfidence??ir,n=Math.max(1,Math.min(500,e.limit??100)),s=Ap(e.projectId);if(s.length===0)return[];let r=new Map,o=new Map;for(let l of s){let u=`${l.source_session_id}|${l.target_session_id}|${l.link_type}`,m=o.get(u);m||(m={source_session_id:l.source_session_id,target_session_id:l.target_session_id,link_type:l.link_type,layers:[]},o.set(u,m));let p=m.layers.find(g=>g.inferred_by===l.inferred_by);p?(p.suggestion_ids.push(l.id),l.confidence>p.confidence&&(p.confidence=l.confidence,p.evidence=Lp(l.evidence))):m.layers.push({inferred_by:l.inferred_by,link_type:l.link_type,confidence:l.confidence,evidence:Lp(l.evidence),suggestion_ids:[l.id]})}let i=new Set;for(let l of o.values())i.add(l.source_session_id),i.add(l.target_session_id);let a=ik(Array.from(i)),d=[];for(let l of o.values()){let u=Mi(l.layers.map(g=>g.confidence));if(u<t)continue;let m=a.get(l.source_session_id),p=a.get(l.target_session_id);d.push({source_session_id:l.source_session_id,target_session_id:l.target_session_id,primary_link_type:l.link_type,combined_confidence:u,layers:l.layers,source_title:Cp(m,l.source_session_id),target_title:Cp(p,l.target_session_id),source_project:m?.project??null})}return d.sort((l,u)=>u.combined_confidence-l.combined_confidence),d.slice(0,n)}function ck(e){let t;try{t=JSON.stringify(e)}catch{t=String(e)}return t.length>xp&&(t=t.slice(0,xp)+"\u2026"),t}function lk(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((n,s)=>{t.push(""),t.push(`[${s}] B="${(n.source_title??"").slice(0,80)}" [${n.source_session_id.slice(0,8)}] -> A="${(n.target_title??"").slice(0,80)}" [${n.target_session_id.slice(0,8)}]`),t.push(` primary_type: ${n.primary_link_type}`),t.push(` combined_conf: ${n.combined_confidence.toFixed(3)}`);for(let r of n.layers)t.push(` ${r.inferred_by} ${r.link_type} conf=${r.confidence.toFixed(2)} ev=${ck(r.evidence)}`)}),t.join(`
1517
- `)}var Di=null;async function dk(e,t){return Di?Di(e,t):Nt(e,[],{model:t})}function uk(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 pk(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 n=t.indexOf("{"),s=t.lastIndexOf("}");if(n===-1||s===-1||s<=n)return null;let r;try{r=JSON.parse(t.slice(n,s+1))}catch{return null}if(!Array.isArray(r.classifications))return null;let o=[];for(let i of r.classifications){if(!i||typeof i!="object")continue;let a=i,d=typeof a.i=="number"?a.i:typeof a.pair_index=="number"?a.pair_index:NaN;if(!Number.isInteger(d)||d<0)continue;let l=typeof a.label=="string"?a.label.toUpperCase():"";if(!rk.has(l))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:d,label:l,confidence:m,reason:p})}return o}async function Np(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(!Di&&!ae())return t.failures.push({batch_index:-1,error:"claude CLI not available on PATH"}),t;let n=ak({projectId:e.projectId,minConfidence:e.minConfidence??ir,limit:e.limit??100});t.candidates_after_filter=n.length;let s=Ap(e.projectId),r=new Set;for(let a of s)r.add(`${a.source_session_id}|${a.target_session_id}|${a.link_type}`);if(t.candidates_total=r.size,n.length===0)return t;let o=e.model??$i,i=e.autoPromoteThreshold??Pi;for(let a=0,d=0;a<n.length&&!e.signal?.aborted;a+=kp,d+=1){let l=n.slice(a,a+kp);e.onBatchStart?.({batch:d,pairs:l.length});let u=lk(l),m=await dk(u,o);if(!m.success){t.failures.push({batch_index:d,error:`claude CLI exited ${m.exitCode}: ${m.stderr.slice(0,200)}`});continue}let p=pk(m.stdout);if(!p){t.failures.push({batch_index:d,error:"parse-failed"});continue}let g=uk(m.stdout);t.total_input_tokens+=g.input_tokens,t.total_output_tokens+=g.output_tokens;for(let f of p){if(f.pair_index>=l.length)continue;let h=l[f.pair_index];if(t.classified+=1,f.label==="UNRELATED")continue;let _=ok[f.label];if(_)try{let b=gt({source_session_id:h.source_session_id,target_session_id:h.target_session_id,link_type:_,confidence:f.confidence,evidence:{l4_label:f.label,l4_reason:f.reason,primary_type_l1_l2_l3:h.primary_link_type,combined_pre_l4:h.combined_confidence,scanner:"l4-llm",model:o},inferred_by:"L4"});if(t.suggestions_created+=1,e.autoPromote){let S=h.layers.map(T=>T.confidence);if(S.push(f.confidence),Mi(S)>=i)try{bp(b.id,"approved",{source:"auto"}),t.links_promoted+=1}catch{}}}catch{}}}return t}Ye();var mk=1e3;function gk(e){let t=e.minConf?Math.max(0,Math.min(1,Number(e.minConf))):ir,n=e.autoPromoteThreshold!==void 0?Math.max(0,Math.min(1,Number(e.autoPromoteThreshold))):Pi,s=e.limit?Math.max(1,Number(e.limit)):mk,r=e.model??$i,o=!!e.autoPromote||e.autoPromoteThreshold!==void 0;return{minConfidence:t,autoPromoteThreshold:n,limit:s,model:r,autoPromote:o}}async function Op(e){if(!e.project){console.error("--project <name> is required."),process.exitCode=1;return}let t=Te(e.project);if(!t){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}if(!ae()){console.error("claude CLI not found on PATH. Install Claude Code first, then re-run."),process.exitCode=1;return}let{minConfidence:n,autoPromoteThreshold:s,limit:r,model:o,autoPromote:i}=gk(e);e.json||console.log(`L4 inference \u2014 project "${t.name}" \u2014 model ${o} \u2014 pre-filter conf \u2265 ${n} \u2014 limit ${r} \u2014 auto-promote ${i?`ON (\u2265 ${s})`:"OFF"}`);let a=Date.now(),d=await Np({projectId:t.id,minConfidence:n,limit:r,autoPromote:i,autoPromoteThreshold:s,model:o,onBatchStart:u=>{e.json||process.stdout.write(`\r batch ${u.batch} (${u.pairs} pairs)\u2026 `)}});e.json||process.stdout.write(`
1518
- `);let l=Number(((Date.now()-a)/1e3).toFixed(1));if(e.json)console.log(JSON.stringify({project:t.name,model:o,pre_filter_threshold:n,auto_promote:i,auto_promote_threshold:i?s:null,...d,elapsed_seconds:l},null,2));else{if(console.log(`Done in ${l}s \u2014 pairs=${d.candidates_after_filter}/${d.candidates_total} classified=${d.classified} suggestions=${d.suggestions_created} promoted=${d.links_promoted} failures=${d.failures.length}`),console.log(`Token spend: input=${d.total_input_tokens} output=${d.total_output_tokens}`),d.failures.length>0)for(let u of d.failures.slice(0,3))console.log(` \u26A0 batch ${u.batch_index}: ${u.error}`);d.suggestions_created>0?console.log(" Review the new L4 suggestions at #view=suggestions (filter by inferred_by=L4)."):d.candidates_after_filter===0&&console.log(` \u24D8 No pairs cleared the pre-filter (combined conf \u2265 ${n}). Lower --min-conf to widen the batch, or run more L1/L2/L3 inference first.`)}}k();import{createHash as wk}from"node:crypto";k();I();import{writeFileSync as fk,readFileSync as kj,existsSync as _k,mkdirSync as hk,readdirSync as xj,unlinkSync as Cj}from"node:fs";import{join as vp}from"node:path";import{randomUUID as Ek}from"node:crypto";var Fi=vp(C,"bug-patterns");function bk(){j(),_k(Fi)||hk(Fi,{recursive:!0})}function ar(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 Sk(e){return{cluster_id:e.cluster_id,session_id:e.session_id,matched_at:e.matched_at}}function Ip(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=E(),n=new Date().toISOString(),s=e.id??Ek(),r=e.first_seen_at??n,o=e.last_seen_at??n,i=Array.from(new Set(e.member_session_ids));t.transaction(()=>{t.prepare(`INSERT INTO bug_pattern_clusters
1521
+ WHERE s.id IN (${n})`).all(...e),r=new Map;for(let o of s)r.set(o.id,o);return r}function $p(e,t){if(!e)return t.slice(0,8);let n=e.first_user_message?e.first_user_message.slice(0,80):null;return e.alias??e.auto_title??n??t.slice(0,8)}function Pp(e){try{return JSON.parse(e)}catch{return e}}function kk(e){let t=e.minConfidence??cr,n=Math.max(1,Math.min(500,e.limit??100)),s=Fp(e.projectId);if(s.length===0)return[];let r=new Map,o=new Map;for(let l of s){let u=`${l.source_session_id}|${l.target_session_id}|${l.link_type}`,m=o.get(u);m||(m={source_session_id:l.source_session_id,target_session_id:l.target_session_id,link_type:l.link_type,layers:[]},o.set(u,m));let p=m.layers.find(g=>g.inferred_by===l.inferred_by);p?(p.suggestion_ids.push(l.id),l.confidence>p.confidence&&(p.confidence=l.confidence,p.evidence=Pp(l.evidence))):m.layers.push({inferred_by:l.inferred_by,link_type:l.link_type,confidence:l.confidence,evidence:Pp(l.evidence),suggestion_ids:[l.id]})}let i=new Set;for(let l of o.values())i.add(l.source_session_id),i.add(l.target_session_id);let a=Rk(Array.from(i)),d=[];for(let l of o.values()){let u=ji(l.layers.map(g=>g.confidence));if(u<t)continue;let m=a.get(l.source_session_id),p=a.get(l.target_session_id);d.push({source_session_id:l.source_session_id,target_session_id:l.target_session_id,primary_link_type:l.link_type,combined_confidence:u,layers:l.layers,source_title:$p(m,l.source_session_id),target_title:$p(p,l.target_session_id),source_project:m?.project??null})}return d.sort((l,u)=>u.combined_confidence-l.combined_confidence),d.slice(0,n)}function xk(e){let t;try{t=JSON.stringify(e)}catch{t=String(e)}return t.length>Dp&&(t=t.slice(0,Dp)+"\u2026"),t}function Ck(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((n,s)=>{t.push(""),t.push(`[${s}] B="${(n.source_title??"").slice(0,80)}" [${n.source_session_id.slice(0,8)}] -> A="${(n.target_title??"").slice(0,80)}" [${n.target_session_id.slice(0,8)}]`),t.push(` primary_type: ${n.primary_link_type}`),t.push(` combined_conf: ${n.combined_confidence.toFixed(3)}`);for(let r of n.layers)t.push(` ${r.inferred_by} ${r.link_type} conf=${r.confidence.toFixed(2)} ev=${xk(r.evidence)}`)}),t.join(`
1522
+ `)}var Ui=null;async function Ak(e,t){return Ui?Ui(e,t):Nt(e,[],{model:t})}function Lk(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 Nk(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 n=t.indexOf("{"),s=t.lastIndexOf("}");if(n===-1||s===-1||s<=n)return null;let r;try{r=JSON.parse(t.slice(n,s+1))}catch{return null}if(!Array.isArray(r.classifications))return null;let o=[];for(let i of r.classifications){if(!i||typeof i!="object")continue;let a=i,d=typeof a.i=="number"?a.i:typeof a.pair_index=="number"?a.pair_index:NaN;if(!Number.isInteger(d)||d<0)continue;let l=typeof a.label=="string"?a.label.toUpperCase():"";if(!wk.has(l))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:d,label:l,confidence:m,reason:p})}return o}async function jp(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(!Ui&&!ae())return t.failures.push({batch_index:-1,error:"claude CLI not available on PATH"}),t;let n=kk({projectId:e.projectId,minConfidence:e.minConfidence??cr,limit:e.limit??100});t.candidates_after_filter=n.length;let s=Fp(e.projectId),r=new Set;for(let a of s)r.add(`${a.source_session_id}|${a.target_session_id}|${a.link_type}`);if(t.candidates_total=r.size,n.length===0)return t;let o=e.model??Bi,i=e.autoPromoteThreshold??Hi;for(let a=0,d=0;a<n.length&&!e.signal?.aborted;a+=Mp,d+=1){let l=n.slice(a,a+Mp);e.onBatchStart?.({batch:d,pairs:l.length});let u=Ck(l),m=await Ak(u,o);if(!m.success){t.failures.push({batch_index:d,error:`claude CLI exited ${m.exitCode}: ${m.stderr.slice(0,200)}`});continue}let p=Nk(m.stdout);if(!p){t.failures.push({batch_index:d,error:"parse-failed"});continue}let g=Lk(m.stdout);t.total_input_tokens+=g.input_tokens,t.total_output_tokens+=g.output_tokens;for(let f of p){if(f.pair_index>=l.length)continue;let _=l[f.pair_index];if(t.classified+=1,f.label==="UNRELATED")continue;let b=Tk[f.label];if(b)try{let E=gt({source_session_id:_.source_session_id,target_session_id:_.target_session_id,link_type:b,confidence:f.confidence,evidence:{l4_label:f.label,l4_reason:f.reason,primary_type_l1_l2_l3:_.primary_link_type,combined_pre_l4:_.combined_confidence,scanner:"l4-llm",model:o},inferred_by:"L4"});if(t.suggestions_created+=1,e.autoPromote){let S=_.layers.map(T=>T.confidence);if(S.push(f.confidence),ji(S)>=i)try{Ap(E.id,"approved",{source:"auto"}),t.links_promoted+=1}catch{}}}catch{}}}return t}Ye();var Ok=1e3;function vk(e){let t=e.minConf?Math.max(0,Math.min(1,Number(e.minConf))):cr,n=e.autoPromoteThreshold!==void 0?Math.max(0,Math.min(1,Number(e.autoPromoteThreshold))):Hi,s=e.limit?Math.max(1,Number(e.limit)):Ok,r=e.model??Bi,o=!!e.autoPromote||e.autoPromoteThreshold!==void 0;return{minConfidence:t,autoPromoteThreshold:n,limit:s,model:r,autoPromote:o}}async function Up(e){if(!e.project){console.error("--project <name> is required."),process.exitCode=1;return}let t=Te(e.project);if(!t){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}if(!ae()){console.error("claude CLI not found on PATH. Install Claude Code first, then re-run."),process.exitCode=1;return}let{minConfidence:n,autoPromoteThreshold:s,limit:r,model:o,autoPromote:i}=vk(e);e.json||console.log(`L4 inference \u2014 project "${t.name}" \u2014 model ${o} \u2014 pre-filter conf \u2265 ${n} \u2014 limit ${r} \u2014 auto-promote ${i?`ON (\u2265 ${s})`:"OFF"}`);let a=Date.now(),d=await jp({projectId:t.id,minConfidence:n,limit:r,autoPromote:i,autoPromoteThreshold:s,model:o,onBatchStart:u=>{e.json||process.stdout.write(`\r batch ${u.batch} (${u.pairs} pairs)\u2026 `)}});e.json||process.stdout.write(`
1523
+ `);let l=Number(((Date.now()-a)/1e3).toFixed(1));if(e.json)console.log(JSON.stringify({project:t.name,model:o,pre_filter_threshold:n,auto_promote:i,auto_promote_threshold:i?s:null,...d,elapsed_seconds:l},null,2));else{if(console.log(`Done in ${l}s \u2014 pairs=${d.candidates_after_filter}/${d.candidates_total} classified=${d.classified} suggestions=${d.suggestions_created} promoted=${d.links_promoted} failures=${d.failures.length}`),console.log(`Token spend: input=${d.total_input_tokens} output=${d.total_output_tokens}`),d.failures.length>0)for(let u of d.failures.slice(0,3))console.log(` \u26A0 batch ${u.batch_index}: ${u.error}`);d.suggestions_created>0?console.log(" Review the new L4 suggestions at #view=suggestions (filter by inferred_by=L4)."):d.candidates_after_filter===0&&console.log(` \u24D8 No pairs cleared the pre-filter (combined conf \u2265 ${n}). Lower --min-conf to widen the batch, or run more L1/L2/L3 inference first.`)}}k();import{createHash as Uk}from"node:crypto";k();I();import{writeFileSync as Ik,readFileSync as Kj,existsSync as Mk,mkdirSync as Dk,readdirSync as Qj,unlinkSync as Zj}from"node:fs";import{join as Bp}from"node:path";import{randomUUID as $k}from"node:crypto";var Wi=Bp(C,"bug-patterns");function Pk(){j(),Mk(Wi)||Dk(Wi,{recursive:!0})}function lr(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 Fk(e){return{cluster_id:e.cluster_id,session_id:e.session_id,matched_at:e.matched_at}}function Hp(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=h(),n=new Date().toISOString(),s=e.id??$k(),r=e.first_seen_at??n,o=e.last_seen_at??n,i=Array.from(new Set(e.member_session_ids));t.transaction(()=>{t.prepare(`INSERT INTO bug_pattern_clusters
1519
1524
  (id, signature_hash, example_message, occurrence_count,
1520
1525
  first_seen_at, last_seen_at, resolved_in_session_id, fix_summary)
1521
1526
  VALUES (?, ?, ?, ?, ?, ?, NULL, NULL)`).run(s,e.signature_hash,e.example_message,i.length,r,o);let d=t.prepare(`INSERT INTO bug_pattern_members (cluster_id, session_id, matched_at)
1522
1527
  VALUES (?, ?, ?)
1523
- ON CONFLICT(cluster_id, session_id) DO NOTHING`);for(let l of i)d.run(s,l,n)})();let a=Mp(s);if(!a)throw new Error("createCluster succeeded but read-back failed");return Pp(s),a}function Mp(e){let t=E(),n=t.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);if(!n)return null;let s=t.prepare("SELECT * FROM bug_pattern_members WHERE cluster_id = ? ORDER BY matched_at ASC, session_id ASC").all(e);return{cluster:ar(n),members:s.map(Sk)}}function Dp(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 n=E();if(!n.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;n.transaction(()=>{let a=n.prepare(`INSERT INTO bug_pattern_members (cluster_id, session_id, matched_at)
1528
+ ON CONFLICT(cluster_id, session_id) DO NOTHING`);for(let l of i)d.run(s,l,n)})();let a=Wp(s);if(!a)throw new Error("createCluster succeeded but read-back failed");return Jp(s),a}function Wp(e){let t=h(),n=t.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);if(!n)return null;let s=t.prepare("SELECT * FROM bug_pattern_members WHERE cluster_id = ? ORDER BY matched_at ASC, session_id ASC").all(e);return{cluster:lr(n),members:s.map(Fk)}}function Xp(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 n=h();if(!n.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;n.transaction(()=>{let a=n.prepare(`INSERT INTO bug_pattern_members (cluster_id, session_id, matched_at)
1524
1529
  VALUES (?, ?, ?)
1525
1530
  ON CONFLICT(cluster_id, session_id) DO NOTHING`);for(let d of Array.from(new Set(t)))a.run(e,d,r).changes>0&&(o+=1);if(o>0){let d=n.prepare("SELECT COUNT(*) AS n FROM bug_pattern_members WHERE cluster_id = ?").get(e).n;n.prepare(`UPDATE bug_pattern_clusters
1526
1531
  SET occurrence_count = ?, last_seen_at = ?
1527
- WHERE id = ?`).run(d,r,e)}})(),o>0&&Pp(e);let i=n.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);return{cluster:ar(i),added:o}}function yk(e){let t=e.first_user_message?e.first_user_message.slice(0,80):null,n=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:n,alias:e.alias,auto_title:e.auto_title,project:e.project,started_at:e.started_at}}function $p(e){let t=E(),n=t.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);if(!n)return null;let s=t.prepare(`SELECT m.cluster_id, m.session_id, m.matched_at,
1532
+ WHERE id = ?`).run(d,r,e)}})(),o>0&&Jp(e);let i=n.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);return{cluster:lr(i),added:o}}function jk(e){let t=e.first_user_message?e.first_user_message.slice(0,80):null,n=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:n,alias:e.alias,auto_title:e.auto_title,project:e.project,started_at:e.started_at}}function Gp(e){let t=h(),n=t.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);if(!n)return null;let s=t.prepare(`SELECT m.cluster_id, m.session_id, m.matched_at,
1528
1533
  NULLIF(sa.alias, '') AS alias,
1529
1534
  s.auto_title,
1530
1535
  s.first_user_message,
@@ -1535,37 +1540,37 @@ show full content: recall paste --show <id>
1535
1540
  LEFT JOIN session_aliases sa ON sa.session_id = m.session_id
1536
1541
  LEFT JOIN projects p ON p.id = s.project_id
1537
1542
  WHERE m.cluster_id = ?
1538
- ORDER BY COALESCE(s.started_at, ''), m.matched_at, m.session_id`).all(e);return{cluster:ar(n),members:s.map(yk)}}function Pp(e){try{bk();let t=Mp(e);if(!t)return;let n=vp(Fi,`${e}.json`),s={schema:"claude-recall.bug-pattern-cluster.v1",cluster:t.cluster,members:t.members,backed_up_at:new Date().toISOString()};fk(n,JSON.stringify(s,null,2))}catch(t){console.error("[bug-patterns] backup failed:",t)}}function Fp(e){return e?E().prepare(`SELECT * FROM bug_pattern_clusters
1543
+ ORDER BY COALESCE(s.started_at, ''), m.matched_at, m.session_id`).all(e);return{cluster:lr(n),members:s.map(jk)}}function Jp(e){try{Pk();let t=Wp(e);if(!t)return;let n=Bp(Wi,`${e}.json`),s={schema:"claude-recall.bug-pattern-cluster.v1",cluster:t.cluster,members:t.members,backed_up_at:new Date().toISOString()};Ik(n,JSON.stringify(s,null,2))}catch(t){console.error("[bug-patterns] backup failed:",t)}}function zp(e){return e?h().prepare(`SELECT * FROM bug_pattern_clusters
1539
1544
  WHERE signature_hash = ?
1540
- ORDER BY last_seen_at DESC, id ASC`).all(e).map(ar):[]}function jp(e){if(!e)return new Set;let n=E().prepare(`SELECT DISTINCT m.session_id
1545
+ ORDER BY last_seen_at DESC, id ASC`).all(e).map(lr):[]}function Yp(e){if(!e)return new Set;let n=h().prepare(`SELECT DISTINCT m.session_id
1541
1546
  FROM bug_pattern_members m
1542
1547
  JOIN bug_pattern_clusters c ON c.id = m.cluster_id
1543
- WHERE c.signature_hash = ?`).all(e);return new Set(n.map(s=>s.session_id))}var Tk=/\b0x[0-9a-fA-F]+\b/g,Rk=/\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,kk=/\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z?\b/g,xk=/:\d+:\d+/g,Ck=/\bline\s+\d+\b/gi,Lk=/\bcolumn\s+\d+\b/gi,Ak=/\b(?:pid|PID|process(?:\s+id)?)\s*[:=]?\s*\d+\b/gi,Nk=/\b(?:port|:)\s*[:=]?\s*\d{2,5}\b/gi,Ok=/\b\d{4,}\b/g,vk=/(['"`])[^'"`\n]{1,128}\1/g;function Ik(e){if(!e)return"";let t=String(e);return t=t.replace(Tk,"<hex>"),t=t.replace(Rk,"<uuid>"),t=t.replace(kk,"<ts>"),t=t.replace(xk,":<line>:<col>"),t=t.replace(Ck,"line <n>"),t=t.replace(Lk,"column <n>"),t=t.replace(Ak,"pid <n>"),t=t.replace(Nk,"port <n>"),t=t.replace(Ok,"<num>"),t=t.replace(vk,"<arg>"),t=t.replace(/\s+/g," ").trim(),t.toLowerCase()}function Mk(e){let t=(e.error_type??"unknown").toLowerCase().trim(),n=Ik(e.snippet??e.message_hash??""),s=`${t}|${n}`;return wk("sha256").update(s).digest("hex").slice(0,16)}function Dk(e){let t=E(),n=["oi.bug_signatures IS NOT NULL"],s=[];e&&(n.push("p.name = ?"),s.push(e));let r=`WHERE ${n.join(" AND ")}`,o=t.prepare(`SELECT oi.session_id AS session_id,
1548
+ WHERE c.signature_hash = ?`).all(e);return new Set(n.map(s=>s.session_id))}var Bk=/\b0x[0-9a-fA-F]+\b/g,Hk=/\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,Wk=/\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z?\b/g,Xk=/:\d+:\d+/g,Gk=/\bline\s+\d+\b/gi,Jk=/\bcolumn\s+\d+\b/gi,zk=/\b(?:pid|PID|process(?:\s+id)?)\s*[:=]?\s*\d+\b/gi,Yk=/\b(?:port|:)\s*[:=]?\s*\d{2,5}\b/gi,qk=/\b\d{4,}\b/g,Vk=/(['"`])[^'"`\n]{1,128}\1/g;function Kk(e){if(!e)return"";let t=String(e);return t=t.replace(Bk,"<hex>"),t=t.replace(Hk,"<uuid>"),t=t.replace(Wk,"<ts>"),t=t.replace(Xk,":<line>:<col>"),t=t.replace(Gk,"line <n>"),t=t.replace(Jk,"column <n>"),t=t.replace(zk,"pid <n>"),t=t.replace(Yk,"port <n>"),t=t.replace(qk,"<num>"),t=t.replace(Vk,"<arg>"),t=t.replace(/\s+/g," ").trim(),t.toLowerCase()}function Qk(e){let t=(e.error_type??"unknown").toLowerCase().trim(),n=Kk(e.snippet??e.message_hash??""),s=`${t}|${n}`;return Uk("sha256").update(s).digest("hex").slice(0,16)}function Zk(e){let t=h(),n=["oi.bug_signatures IS NOT NULL"],s=[];e&&(n.push("p.name = ?"),s.push(e));let r=`WHERE ${n.join(" AND ")}`,o=t.prepare(`SELECT oi.session_id AS session_id,
1544
1549
  p.name AS project,
1545
1550
  s.started_at AS started_at,
1546
1551
  oi.bug_signatures AS bug_signatures
1547
1552
  FROM session_output_index oi
1548
1553
  LEFT JOIN sessions s ON s.id = oi.session_id
1549
1554
  LEFT JOIN projects p ON p.id = s.project_id
1550
- ${r}`).all(...s),i=[];for(let a of o){if(!a.bug_signatures)continue;let d=[];try{let l=JSON.parse(a.bug_signatures);Array.isArray(l)&&(d=l)}catch{continue}for(let l of d){if(!l||typeof l!="object"||!(l.snippet??"").trim())continue;let m=Mk(l);i.push({session_id:a.session_id,project:a.project,started_at:a.started_at,signature:l,fingerprint:m})}}return i}function $k(e){let t=new Map;for(let s of e){let r=t.get(s.fingerprint);r||(r=[],t.set(s.fingerprint,r)),r.push(s)}let n=[];for(let[s,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??"",g=m.started_at??"";return p&&g?p<g?-1:p>g?1:0:p?-1:g?1:0}),d=a.find(u=>u.started_at),l=[...a].reverse().find(u=>u.started_at);n.push({fingerprint:s,example_message:i[0].signature.snippet??i[0].signature.message_hash??"",members:i,first_seen_at:d?.started_at??new Date().toISOString(),last_seen_at:l?.started_at??new Date().toISOString()})}return n}function Pk(e,t){if(e.length!==t.length)return 0;let n=0,s=0,r=0;for(let i=0;i<e.length;i++)n+=e[i]*t[i],s+=e[i]*e[i],r+=t[i]*t[i];let o=Math.sqrt(s)*Math.sqrt(r);return o>0?n/o:0}function Fk(e){let{records:t,vectors:n,epsilon:s,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-Pk(n[u],n[p])<=s&&m.push(p)}i.push(m)}let a=new Array(o).fill(!1),d=new Array(o).fill(-1),l=[];for(let u=0;u<o;u++){if(a[u])continue;a[u]=!0;let m=i[u];if(m.length<r)continue;let p=l.length;l.push({members:[t[u]]}),d[u]=p;let g=[...m];for(;g.length>0;){let f=g.shift();if(!a[f]&&(a[f]=!0,i[f].length>=r))for(let h of i[f])(!a[h]||d[h]===-1)&&g.push(h);d[f]===-1&&(d[f]=p,l[p].members.push(t[f]))}}return l}async function jk(e,t,n,s){if(e.length===0)return[];let r=e.map(d=>{let l=d.signature.snippet??d.signature.message_hash??"";return`${d.signature.error_type??""}: ${l}`.trim()}),o=await t(r);if(o.length!==e.length)throw new Error(`embedder returned ${o.length} vectors for ${e.length} inputs`);let i=Fk({records:e,vectors:o,epsilon:n,minPts:s}),a=[];for(let d of i){if(d.members.length===0)continue;let l=new Set,u=[];for(let _ of d.members)l.has(_.session_id)||(l.add(_.session_id),u.push(_));if(u.length===0)continue;let p=`sem:${[...u.map(_=>_.fingerprint)].sort()[0]}`,g=[...u].sort((_,b)=>{let S=_.started_at??"",y=b.started_at??"";return S<y?-1:S>y?1:0}),f=g.find(_=>_.started_at),h=[...g].reverse().find(_=>_.started_at);a.push({fingerprint:p,example_message:u[0].signature.snippet??u[0].signature.message_hash??"",members:u,first_seen_at:f?.started_at??new Date().toISOString(),last_seen_at:h?.started_at??new Date().toISOString()})}return a}function Up(e,t){let n={clusters_created:0,clusters_merged:0,members_added:0,cluster_ids:[]};for(let s of e){if(s.members.length<t)continue;let r=Fp(s.fingerprint),o=jp(s.fingerprint),i=s.members.map(l=>l.session_id).filter(l=>!o.has(l));if(r.length===0){let l=Ip({signature_hash:s.fingerprint,example_message:s.example_message.slice(0,256),member_session_ids:s.members.map(u=>u.session_id),first_seen_at:s.first_seen_at,last_seen_at:s.last_seen_at});n.clusters_created+=1,n.members_added+=l.members.length,n.cluster_ids.push(l.cluster.id);continue}if(i.length===0){n.cluster_ids.push(r[0].id);continue}let a=r[0],d=Dp(a.id,i);d.added>0&&(n.clusters_merged+=1,n.members_added+=d.added),n.cluster_ids.push(a.id)}return n}async function Bp(e={}){let t=Math.max(2,Math.floor(e.minClusterSize??3)),n=Math.max(1,Math.min(5e3,Math.floor(e.limit??1e3))),s=e.semanticEpsilon??.15,r=Math.max(1,Math.floor(e.semanticMinPts??1)),o=Dk(e.project),i=new Set(o.map(S=>S.session_id)),a=$k(o),d=[],l=!1;if(e.semantic){let S=e.embedder??null;if(!S)try{S=await Hk()}catch(y){let R=(y instanceof Error?y.message:String(y)).split(`
1555
+ ${r}`).all(...s),i=[];for(let a of o){if(!a.bug_signatures)continue;let d=[];try{let l=JSON.parse(a.bug_signatures);Array.isArray(l)&&(d=l)}catch{continue}for(let l of d){if(!l||typeof l!="object"||!(l.snippet??"").trim())continue;let m=Qk(l);i.push({session_id:a.session_id,project:a.project,started_at:a.started_at,signature:l,fingerprint:m})}}return i}function e0(e){let t=new Map;for(let s of e){let r=t.get(s.fingerprint);r||(r=[],t.set(s.fingerprint,r)),r.push(s)}let n=[];for(let[s,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??"",g=m.started_at??"";return p&&g?p<g?-1:p>g?1:0:p?-1:g?1:0}),d=a.find(u=>u.started_at),l=[...a].reverse().find(u=>u.started_at);n.push({fingerprint:s,example_message:i[0].signature.snippet??i[0].signature.message_hash??"",members:i,first_seen_at:d?.started_at??new Date().toISOString(),last_seen_at:l?.started_at??new Date().toISOString()})}return n}function t0(e,t){if(e.length!==t.length)return 0;let n=0,s=0,r=0;for(let i=0;i<e.length;i++)n+=e[i]*t[i],s+=e[i]*e[i],r+=t[i]*t[i];let o=Math.sqrt(s)*Math.sqrt(r);return o>0?n/o:0}function n0(e){let{records:t,vectors:n,epsilon:s,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-t0(n[u],n[p])<=s&&m.push(p)}i.push(m)}let a=new Array(o).fill(!1),d=new Array(o).fill(-1),l=[];for(let u=0;u<o;u++){if(a[u])continue;a[u]=!0;let m=i[u];if(m.length<r)continue;let p=l.length;l.push({members:[t[u]]}),d[u]=p;let g=[...m];for(;g.length>0;){let f=g.shift();if(!a[f]&&(a[f]=!0,i[f].length>=r))for(let _ of i[f])(!a[_]||d[_]===-1)&&g.push(_);d[f]===-1&&(d[f]=p,l[p].members.push(t[f]))}}return l}async function s0(e,t,n,s){if(e.length===0)return[];let r=e.map(d=>{let l=d.signature.snippet??d.signature.message_hash??"";return`${d.signature.error_type??""}: ${l}`.trim()}),o=await t(r);if(o.length!==e.length)throw new Error(`embedder returned ${o.length} vectors for ${e.length} inputs`);let i=n0({records:e,vectors:o,epsilon:n,minPts:s}),a=[];for(let d of i){if(d.members.length===0)continue;let l=new Set,u=[];for(let b of d.members)l.has(b.session_id)||(l.add(b.session_id),u.push(b));if(u.length===0)continue;let p=`sem:${[...u.map(b=>b.fingerprint)].sort()[0]}`,g=[...u].sort((b,E)=>{let S=b.started_at??"",y=E.started_at??"";return S<y?-1:S>y?1:0}),f=g.find(b=>b.started_at),_=[...g].reverse().find(b=>b.started_at);a.push({fingerprint:p,example_message:u[0].signature.snippet??u[0].signature.message_hash??"",members:u,first_seen_at:f?.started_at??new Date().toISOString(),last_seen_at:_?.started_at??new Date().toISOString()})}return a}function qp(e,t){let n={clusters_created:0,clusters_merged:0,members_added:0,cluster_ids:[]};for(let s of e){if(s.members.length<t)continue;let r=zp(s.fingerprint),o=Yp(s.fingerprint),i=s.members.map(l=>l.session_id).filter(l=>!o.has(l));if(r.length===0){let l=Hp({signature_hash:s.fingerprint,example_message:s.example_message.slice(0,256),member_session_ids:s.members.map(u=>u.session_id),first_seen_at:s.first_seen_at,last_seen_at:s.last_seen_at});n.clusters_created+=1,n.members_added+=l.members.length,n.cluster_ids.push(l.cluster.id);continue}if(i.length===0){n.cluster_ids.push(r[0].id);continue}let a=r[0],d=Xp(a.id,i);d.added>0&&(n.clusters_merged+=1,n.members_added+=d.added),n.cluster_ids.push(a.id)}return n}async function Vp(e={}){let t=Math.max(2,Math.floor(e.minClusterSize??3)),n=Math.max(1,Math.min(5e3,Math.floor(e.limit??1e3))),s=e.semanticEpsilon??.15,r=Math.max(1,Math.floor(e.semanticMinPts??1)),o=Zk(e.project),i=new Set(o.map(S=>S.session_id)),a=e0(o),d=[],l=!1;if(e.semantic){let S=e.embedder??null;if(!S)try{S=await i0()}catch(y){let R=(y instanceof Error?y.message:String(y)).split(`
1551
1556
  `)[0];console.warn(`[bug-pattern] --semantic requested but the embedder is unavailable: ${R}
1552
- Falling back to exact-match-only clustering. Run \`recall semantic install\` to enable the semantic pass.`),l=!0}if(S){let y=[];for(let T of a)T.members.length===1&&y.push(T.members[0]);y.length>=2&&(d=await jk(y,S,s,r))}}let u=a.filter(S=>S.members.length>=t),m=d.filter(S=>S.members.length>=t),p=Up(u,t),g=Up(m,t),f=[...p.cluster_ids,...g.cluster_ids],h=Array.from(new Set(f)),_=[];if(h.length>0){let S=E(),y=h.map(()=>"?").join(","),T=S.prepare(`SELECT * FROM bug_pattern_clusters
1557
+ Falling back to exact-match-only clustering. Run \`recall semantic install\` to enable the semantic pass.`),l=!0}if(S){let y=[];for(let T of a)T.members.length===1&&y.push(T.members[0]);y.length>=2&&(d=await s0(y,S,s,r))}}let u=a.filter(S=>S.members.length>=t),m=d.filter(S=>S.members.length>=t),p=qp(u,t),g=qp(m,t),f=[...p.cluster_ids,...g.cluster_ids],_=Array.from(new Set(f)),b=[];if(_.length>0){let S=h(),y=_.map(()=>"?").join(","),T=S.prepare(`SELECT * FROM bug_pattern_clusters
1553
1558
  WHERE id IN (${y})
1554
1559
  ORDER BY occurrence_count DESC, last_seen_at DESC
1555
- LIMIT ?`).all(...h,n);for(let R of T)_.push({id:R.id,signature_hash:R.signature_hash,example_message:R.example_message,occurrence_count:R.occurrence_count,first_seen_at:R.first_seen_at,last_seen_at:R.last_seen_at,resolved_in_session_id:R.resolved_in_session_id,fix_summary:R.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+g.clusters_created,clusters_merged:p.clusters_merged+g.clusters_merged,members_added:p.members_added+g.members_added,semantic_skipped:l},clusters:_}}var Uk=async()=>{let{embed:e,loadEmbedder:t,getEmbedderStatus:n}=await Promise.resolve().then(()=>(Pe(),Ms));return n().loaded||await t(),e},Bk=Uk;async function Hk(){return Bk()}function Wk(e,t){let n=$p(e);if(!n)return null;let s=n.cluster,r=n.members.slice(0,t).map(o=>({session_id:o.session_id,title:o.title,project:o.project,started_at:o.started_at}));return{id:s.id,signature_hash:s.signature_hash,example_message:s.example_message,occurrence_count:s.occurrence_count,first_seen_at:s.first_seen_at,last_seen_at:s.last_seen_at,status:s.resolved_in_session_id?"resolved":"open",resolved_in_session_id:s.resolved_in_session_id,sample_members:r}}async function Hp(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 n=e.limit?Math.max(1,Math.floor(Number(e.limit))):100;if(!Number.isFinite(n)){console.error("--limit must be a positive number"),process.exitCode=1;return}let s;if(e.project){let l=Te(e.project);if(!l){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}s=l.name}if(!e.json){let l=s?`project "${s}"`:"all projects",u=e.semantic?"exact + semantic":"exact";console.log(`Inferring bug patterns \u2014 ${l}, min-cluster-size=${t}, ${u} passes\u2026`)}let r={project:s,minClusterSize:t,semantic:!!e.semantic,limit:n},o=Date.now(),i;try{i=await Bp(r)}catch(l){console.error(l instanceof Error?l.message:String(l)),process.exitCode=1;return}let a=Number(((Date.now()-o)/1e3).toFixed(1)),d=[];for(let l of i.clusters.slice(0,n)){let u=Wk(l.id,3);u&&d.push(u)}if(e.json){console.log(JSON.stringify({project:s??null,progress:i.progress,elapsed_seconds:a,clusters:d},null,2));return}if(console.log(`Done in ${a}s \u2014 sessions=${i.progress.total_sessions} signatures=${i.progress.total_signatures} clusters: created=${i.progress.clusters_created} merged=${i.progress.clusters_merged} members_added=${i.progress.members_added}`),i.progress.semantic_skipped&&console.log(" \u24D8 semantic pass skipped \u2014 embedder unavailable. Run `recall semantic install` to enable."),d.length===0){i.progress.total_signatures===0?console.log(" \u24D8 No bug signatures in the corpus yet. Run `recall extract-outputs --project <name>` first to populate session_output_index."):console.log(` \u24D8 No clusters at min-cluster-size=${t}. Try \`--semantic\` to merge near-duplicate snippets, or lower \`--min-cluster-size 2\` to surface pairs.`);return}console.log(`
1560
+ LIMIT ?`).all(..._,n);for(let R of T)b.push({id:R.id,signature_hash:R.signature_hash,example_message:R.example_message,occurrence_count:R.occurrence_count,first_seen_at:R.first_seen_at,last_seen_at:R.last_seen_at,resolved_in_session_id:R.resolved_in_session_id,fix_summary:R.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+g.clusters_created,clusters_merged:p.clusters_merged+g.clusters_merged,members_added:p.members_added+g.members_added,semantic_skipped:l},clusters:b}}var r0=async()=>{let{embed:e,loadEmbedder:t,getEmbedderStatus:n}=await Promise.resolve().then(()=>(Fe(),Ds));return n().loaded||await t(),e},o0=r0;async function i0(){return o0()}function a0(e,t){let n=Gp(e);if(!n)return null;let s=n.cluster,r=n.members.slice(0,t).map(o=>({session_id:o.session_id,title:o.title,project:o.project,started_at:o.started_at}));return{id:s.id,signature_hash:s.signature_hash,example_message:s.example_message,occurrence_count:s.occurrence_count,first_seen_at:s.first_seen_at,last_seen_at:s.last_seen_at,status:s.resolved_in_session_id?"resolved":"open",resolved_in_session_id:s.resolved_in_session_id,sample_members:r}}async function Kp(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 n=e.limit?Math.max(1,Math.floor(Number(e.limit))):100;if(!Number.isFinite(n)){console.error("--limit must be a positive number"),process.exitCode=1;return}let s;if(e.project){let l=Te(e.project);if(!l){console.error(`Project "${e.project}" not found.`),process.exitCode=1;return}s=l.name}if(!e.json){let l=s?`project "${s}"`:"all projects",u=e.semantic?"exact + semantic":"exact";console.log(`Inferring bug patterns \u2014 ${l}, min-cluster-size=${t}, ${u} passes\u2026`)}let r={project:s,minClusterSize:t,semantic:!!e.semantic,limit:n},o=Date.now(),i;try{i=await Vp(r)}catch(l){console.error(l instanceof Error?l.message:String(l)),process.exitCode=1;return}let a=Number(((Date.now()-o)/1e3).toFixed(1)),d=[];for(let l of i.clusters.slice(0,n)){let u=a0(l.id,3);u&&d.push(u)}if(e.json){console.log(JSON.stringify({project:s??null,progress:i.progress,elapsed_seconds:a,clusters:d},null,2));return}if(console.log(`Done in ${a}s \u2014 sessions=${i.progress.total_sessions} signatures=${i.progress.total_signatures} clusters: created=${i.progress.clusters_created} merged=${i.progress.clusters_merged} members_added=${i.progress.members_added}`),i.progress.semantic_skipped&&console.log(" \u24D8 semantic pass skipped \u2014 embedder unavailable. Run `recall semantic install` to enable."),d.length===0){i.progress.total_signatures===0?console.log(" \u24D8 No bug signatures in the corpus yet. Run `recall extract-outputs --project <name>` first to populate session_output_index."):console.log(` \u24D8 No clusters at min-cluster-size=${t}. Try \`--semantic\` to merge near-duplicate snippets, or lower \`--min-cluster-size 2\` to surface pairs.`);return}console.log(`
1556
1561
  Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u2713 resolved":"open",m=l.example_message.slice(0,80);console.log(`
1557
1562
  [${u}] occurs=${l.occurrence_count} hash=${l.signature_hash.slice(0,8)}
1558
1563
  ${m}
1559
- first=${l.first_seen_at} last=${l.last_seen_at}`);for(let p of l.sample_members){let g=p.project?`[${p.project}] `:"";console.log(` \u2022 ${g}${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.")}k();import{z as Gj}from"zod";k();function Wp(e){let t=e.trim();if(t.length<4)return null;let n=E();if(t.length>=32)return n.prepare("SELECT id FROM sessions WHERE id = ?").get(t)?.id??null;let s=n.prepare("SELECT id FROM sessions WHERE id LIKE ? LIMIT 2").all(`${t}%`);return s.length===1?s[0].id:null}ji();var Qp=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),Zp=new Set(["pagerank","embedding-rerank","hybrid"]);function r0(e){if(!e)return;let t=e.split(",").map(n=>n.trim()).filter(Boolean);for(let n of t)if(!Qp.has(n))throw new Error(`invalid --edge-types value: '${n}'. Valid: ${Array.from(Qp).join(", ")}`);return t}function o0(e){if(!e)return"hybrid";if(!Zp.has(e))throw new Error(`invalid --scoring value: '${e}'. Valid: ${Array.from(Zp).join(", ")}`);return e}async function em(e,t){let n=Wp(e);if(!n){console.error(`session not found or prefix ambiguous: ${e}`),process.exitCode=1;return}let s,r;try{s=o0(t.scoring),r=r0(t.edgeTypes)}catch(d){console.error(d instanceof Error?d.message:String(d)),process.exitCode=1;return}let o=t.budget?Math.max(100,Number(t.budget)):4e3;if(!Number.isFinite(o)){console.error("--budget must be a positive number"),process.exitCode=1;return}let i=t.maxDepth?Math.max(1,Number(t.maxDepth)):2;if(!Number.isFinite(i)){console.error("--max-depth must be a positive number"),process.exitCode=1;return}let a;try{a=dr(n,{budget:o,maxDepth:i,scoring:s,edgeTypes:r,includeWikiLinks:t.wikiLinks!==!1,includeSuggestions:!!t.includeSuggestions})}catch(d){console.error(d instanceof Error?d.message:String(d)),process.exitCode=1;return}if(t.json){process.stdout.write(JSON.stringify(a,null,2)+`
1564
+ first=${l.first_seen_at} last=${l.last_seen_at}`);for(let p of l.sample_members){let g=p.project?`[${p.project}] `:"";console.log(` \u2022 ${g}${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.")}k();import{z as hU}from"zod";k();function Qp(e){let t=e.trim();if(t.length<4)return null;let n=h();if(t.length>=32)return n.prepare("SELECT id FROM sessions WHERE id = ?").get(t)?.id??null;let s=n.prepare("SELECT id FROM sessions WHERE id LIKE ? LIMIT 2").all(`${t}%`);return s.length===1?s[0].id:null}Xi();var am=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),cm=new Set(["pagerank","embedding-rerank","hybrid"]);function w0(e){if(!e)return;let t=e.split(",").map(n=>n.trim()).filter(Boolean);for(let n of t)if(!am.has(n))throw new Error(`invalid --edge-types value: '${n}'. Valid: ${Array.from(am).join(", ")}`);return t}function T0(e){if(!e)return"hybrid";if(!cm.has(e))throw new Error(`invalid --scoring value: '${e}'. Valid: ${Array.from(cm).join(", ")}`);return e}async function lm(e,t){let n=Qp(e);if(!n){console.error(`session not found or prefix ambiguous: ${e}`),process.exitCode=1;return}let s,r;try{s=T0(t.scoring),r=w0(t.edgeTypes)}catch(d){console.error(d instanceof Error?d.message:String(d)),process.exitCode=1;return}let o=t.budget?Math.max(100,Number(t.budget)):4e3;if(!Number.isFinite(o)){console.error("--budget must be a positive number"),process.exitCode=1;return}let i=t.maxDepth?Math.max(1,Number(t.maxDepth)):2;if(!Number.isFinite(i)){console.error("--max-depth must be a positive number"),process.exitCode=1;return}let a;try{a=pr(n,{budget:o,maxDepth:i,scoring:s,edgeTypes:r,includeWikiLinks:t.wikiLinks!==!1,includeSuggestions:!!t.includeSuggestions})}catch(d){console.error(d instanceof Error?d.message:String(d)),process.exitCode=1;return}if(t.json){process.stdout.write(JSON.stringify(a,null,2)+`
1560
1565
  `);return}process.stdout.write(a.bundle),a.truncated.length>0&&console.error(`
1561
- [truncated ${a.truncated.length} refs to fit ${o}-token budget; ${a.budgetUsed} used / ${a.budgetRemaining} remaining]`)}k();$();var i0=[[/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}]],tm={label:"unknown",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30};function _t(e){if(!e)return tm;for(let[t,n]of i0)if(t.test(e))return n;return tm}function Fe(e,t){if(e.byModel&&Object.keys(e.byModel).length>0){let i={input:0,output:0,cacheCreate:0,cacheRead:0},a=0;for(let[l,u]of Object.entries(e.byModel)){let m=_t(l);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 d=i.input+i.output+i.cacheCreate+i.cacheRead;return{cents:d,dollars:d/100,totalTokens:a,parts:i}}let n=_t(t),s={input:e.inputTokens/1e6*n.inputCentsPerMtok,output:e.outputTokens/1e6*n.outputCentsPerMtok,cacheCreate:e.cacheCreateTokens/1e6*n.cacheCreateCentsPerMtok,cacheRead:e.cacheReadTokens/1e6*n.cacheReadCentsPerMtok},r=s.input+s.output+s.cacheCreate+s.cacheRead,o=e.inputTokens+e.outputTokens+e.cacheCreateTokens+e.cacheReadTokens;return{cents:r,dollars:r/100,totalTokens:o,parts:s}}function le(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 he(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`}k();k();Kn();Qn();var a0=500,ur=new Set;function nm(){return ur.size}function c0(){return`
1566
+ [truncated ${a.truncated.length} refs to fit ${o}-token budget; ${a.budgetUsed} used / ${a.budgetRemaining} remaining]`)}k();D();var R0=[[/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}]],dm={label:"unknown",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30};function _t(e){if(!e)return dm;for(let[t,n]of R0)if(t.test(e))return n;return dm}function je(e,t){if(e.byModel&&Object.keys(e.byModel).length>0){let i={input:0,output:0,cacheCreate:0,cacheRead:0},a=0;for(let[l,u]of Object.entries(e.byModel)){let m=_t(l);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 d=i.input+i.output+i.cacheCreate+i.cacheRead;return{cents:d,dollars:d/100,totalTokens:a,parts:i}}let n=_t(t),s={input:e.inputTokens/1e6*n.inputCentsPerMtok,output:e.outputTokens/1e6*n.outputCentsPerMtok,cacheCreate:e.cacheCreateTokens/1e6*n.cacheCreateCentsPerMtok,cacheRead:e.cacheReadTokens/1e6*n.cacheReadCentsPerMtok},r=s.input+s.output+s.cacheCreate+s.cacheRead,o=e.inputTokens+e.outputTokens+e.cacheCreateTokens+e.cacheReadTokens;return{cents:r,dollars:r/100,totalTokens:o,parts:s}}function le(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 he(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`}k();k();Qn();Zn();var k0=500,mr=new Set;function um(){return mr.size}function x0(){return`
1562
1567
  SELECT m.uuid, m.session_id, m.timestamp, m.raw_json
1563
1568
  FROM messages m
1564
1569
  LEFT JOIN message_usage mu ON mu.message_uuid = m.uuid
1565
1570
  WHERE m.role = 'assistant' AND mu.message_uuid IS NULL
1566
1571
  AND m.uuid NOT IN (SELECT value FROM json_each(?))
1567
1572
  LIMIT ?
1568
- `}function l0(e,t){let n=t.limit??Number.MAX_SAFE_INTEGER,s=Math.max(1,t.chunkSize??a0),r=e.prepare(c0()),o=e.prepare(`
1573
+ `}function C0(e,t){let n=t.limit??Number.MAX_SAFE_INTEGER,s=Math.max(1,t.chunkSize??k0),r=e.prepare(x0()),o=e.prepare(`
1569
1574
  INSERT INTO message_usage (
1570
1575
  message_uuid, session_id, model,
1571
1576
  input_tokens, output_tokens, cache_create_tokens, cache_read_tokens,
@@ -1575,7 +1580,7 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1575
1580
  @input, @output, @cc, @cr, @ts
1576
1581
  )
1577
1582
  ON CONFLICT(message_uuid) DO NOTHING
1578
- `),i=0,a=0,d=new Set;for(;i<n;){let l=Math.min(s,n-i),u=JSON.stringify([...ur]),m=r.all(u,l);if(m.length===0)break;let p=new Set;if(e.transaction(()=>{for(let f of m){let h;try{h=JSON.parse(f.raw_json)}catch{ur.add(f.uuid);continue}let _=Yr(h.message);if(!_){ur.add(f.uuid);continue}o.run({uuid:f.uuid,session_id:f.session_id,model:h.message?.model??null,input:_.inputTokens,output:_.outputTokens,cc:_.cacheCreateTokens,cr:_.cacheReadTokens,ts:f.timestamp}),a+=1,p.add(f.session_id)}for(let f of p)ln(e,f),d.add(f)})(),i+=m.length,t.onProgress?.({scanned:i,inserted:a,sessionsTouched:d.size,done:m.length<l}),m.length<l)break}return{scanned:i,inserted:a,sessionsTouched:d.size,done:!0}}function sm(e={}){return l0(E(),e)}function Ui(e){let t=new Map;for(let s of e){let r=s.model??null,o=t.get(r)??{inputTokens:0,outputTokens:0,cacheCreateTokens:0,cacheReadTokens:0,messageCount:0};o.inputTokens+=s.input_tokens,o.outputTokens+=s.output_tokens,o.cacheCreateTokens+=s.cache_create_tokens,o.cacheReadTokens+=s.cache_read_tokens,o.messageCount+=s.n,t.set(r,o)}let n=[];for(let[s,r]of t.entries()){let o=Fe({inputTokens:r.inputTokens,outputTokens:r.outputTokens,cacheCreateTokens:r.cacheCreateTokens,cacheReadTokens:r.cacheReadTokens},s);n.push({model:s,modelLabel:_t(s).label,inputTokens:r.inputTokens,outputTokens:r.outputTokens,cacheCreateTokens:r.cacheCreateTokens,cacheReadTokens:r.cacheReadTokens,messageCount:r.messageCount,cost:o})}return n.sort((s,r)=>r.cost.cents-s.cost.cents)}function Bi(e){let t={};for(let n of e)t[n.model??"__unknown__"]={inputTokens:n.inputTokens,outputTokens:n.outputTokens,cacheCreateTokens:n.cacheCreateTokens,cacheReadTokens:n.cacheReadTokens};return{byModel:t}}function rm(e){let t=E(),n=t.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
1583
+ `),i=0,a=0,d=new Set;for(;i<n;){let l=Math.min(s,n-i),u=JSON.stringify([...mr]),m=r.all(u,l);if(m.length===0)break;let p=new Set;if(e.transaction(()=>{for(let f of m){let _;try{_=JSON.parse(f.raw_json)}catch{mr.add(f.uuid);continue}let b=Vr(_.message);if(!b){mr.add(f.uuid);continue}o.run({uuid:f.uuid,session_id:f.session_id,model:_.message?.model??null,input:b.inputTokens,output:b.outputTokens,cc:b.cacheCreateTokens,cr:b.cacheReadTokens,ts:f.timestamp}),a+=1,p.add(f.session_id)}for(let f of p)ln(e,f),d.add(f)})(),i+=m.length,t.onProgress?.({scanned:i,inserted:a,sessionsTouched:d.size,done:m.length<l}),m.length<l)break}return{scanned:i,inserted:a,sessionsTouched:d.size,done:!0}}function pm(e={}){return C0(h(),e)}function Gi(e){let t=new Map;for(let s of e){let r=s.model??null,o=t.get(r)??{inputTokens:0,outputTokens:0,cacheCreateTokens:0,cacheReadTokens:0,messageCount:0};o.inputTokens+=s.input_tokens,o.outputTokens+=s.output_tokens,o.cacheCreateTokens+=s.cache_create_tokens,o.cacheReadTokens+=s.cache_read_tokens,o.messageCount+=s.n,t.set(r,o)}let n=[];for(let[s,r]of t.entries()){let o=je({inputTokens:r.inputTokens,outputTokens:r.outputTokens,cacheCreateTokens:r.cacheCreateTokens,cacheReadTokens:r.cacheReadTokens},s);n.push({model:s,modelLabel:_t(s).label,inputTokens:r.inputTokens,outputTokens:r.outputTokens,cacheCreateTokens:r.cacheCreateTokens,cacheReadTokens:r.cacheReadTokens,messageCount:r.messageCount,cost:o})}return n.sort((s,r)=>r.cost.cents-s.cost.cents)}function Ji(e){let t={};for(let n of e)t[n.model??"__unknown__"]={inputTokens:n.inputTokens,outputTokens:n.outputTokens,cacheCreateTokens:n.cacheCreateTokens,cacheReadTokens:n.cacheReadTokens};return{byModel:t}}function mm(e){let t=h(),n=t.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
1579
1584
  s.message_count,
1580
1585
  s.total_input_tokens, s.total_output_tokens,
1581
1586
  s.total_cache_create_tokens, s.total_cache_read_tokens,
@@ -1590,7 +1595,7 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1590
1595
  COUNT(*) AS n
1591
1596
  FROM message_usage
1592
1597
  WHERE session_id = ?
1593
- GROUP BY model`).all(e),r=Ui(s),o=n.total_input_tokens??0,i=n.total_output_tokens??0,a=n.total_cache_create_tokens??0,d=n.total_cache_read_tokens??0,l=Fe({inputTokens:o,outputTokens:i,cacheCreateTokens:a,cacheReadTokens:d,...Bi(r)},n.primary_model);return{sessionId:n.id,project:n.project,startedAt:n.started_at,endedAt:n.ended_at,messageCount:n.message_count,primaryModel:n.primary_model,primaryModelLabel:_t(n.primary_model).label,inputTokens:o,outputTokens:i,cacheCreateTokens:a,cacheReadTokens:d,totalTokens:l.totalTokens,cost:l,byModel:r,display:{dollars:le(l.cents),tokens:he(l.totalTokens),model:_t(n.primary_model).label}}}function om(e){let t=E(),n=t.prepare("SELECT id, name FROM projects WHERE name = ?").get(e);if(!n)return null;let s=t.prepare(`SELECT mu.model,
1598
+ GROUP BY model`).all(e),r=Gi(s),o=n.total_input_tokens??0,i=n.total_output_tokens??0,a=n.total_cache_create_tokens??0,d=n.total_cache_read_tokens??0,l=je({inputTokens:o,outputTokens:i,cacheCreateTokens:a,cacheReadTokens:d,...Ji(r)},n.primary_model);return{sessionId:n.id,project:n.project,startedAt:n.started_at,endedAt:n.ended_at,messageCount:n.message_count,primaryModel:n.primary_model,primaryModelLabel:_t(n.primary_model).label,inputTokens:o,outputTokens:i,cacheCreateTokens:a,cacheReadTokens:d,totalTokens:l.totalTokens,cost:l,byModel:r,display:{dollars:le(l.cents),tokens:he(l.totalTokens),model:_t(n.primary_model).label}}}function gm(e){let t=h(),n=t.prepare("SELECT id, name FROM projects WHERE name = ?").get(e);if(!n)return null;let s=t.prepare(`SELECT mu.model,
1594
1599
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
1595
1600
  COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
1596
1601
  COALESCE(SUM(mu.cache_create_tokens), 0) AS cache_create_tokens,
@@ -1599,12 +1604,12 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1599
1604
  FROM message_usage mu
1600
1605
  JOIN sessions s ON s.id = mu.session_id
1601
1606
  WHERE s.project_id = ?
1602
- GROUP BY mu.model`).all(n.id),r=Ui(s),o=t.prepare(`SELECT COALESCE(SUM(total_input_tokens), 0) AS input_tokens,
1607
+ GROUP BY mu.model`).all(n.id),r=Gi(s),o=t.prepare(`SELECT COALESCE(SUM(total_input_tokens), 0) AS input_tokens,
1603
1608
  COALESCE(SUM(total_output_tokens), 0) AS output_tokens,
1604
1609
  COALESCE(SUM(total_cache_create_tokens), 0) AS cache_create_tokens,
1605
1610
  COALESCE(SUM(total_cache_read_tokens), 0) AS cache_read_tokens,
1606
1611
  COUNT(*) AS session_count
1607
- FROM sessions WHERE project_id = ?`).get(n.id),i=Fe({inputTokens:o.input_tokens,outputTokens:o.output_tokens,cacheCreateTokens:o.cache_create_tokens,cacheReadTokens:o.cache_read_tokens,...Bi(r)},null),d=t.prepare(`SELECT s.id, sa.alias, s.started_at,
1612
+ FROM sessions WHERE project_id = ?`).get(n.id),i=je({inputTokens:o.input_tokens,outputTokens:o.output_tokens,cacheCreateTokens:o.cache_create_tokens,cacheReadTokens:o.cache_read_tokens,...Ji(r)},null),d=t.prepare(`SELECT s.id, sa.alias, s.started_at,
1608
1613
  s.total_input_tokens, s.total_output_tokens,
1609
1614
  s.total_cache_create_tokens, s.total_cache_read_tokens,
1610
1615
  s.primary_model
@@ -1615,7 +1620,7 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1615
1620
  + COALESCE(s.total_output_tokens,0)
1616
1621
  + COALESCE(s.total_cache_create_tokens,0)
1617
1622
  + COALESCE(s.total_cache_read_tokens,0)) DESC
1618
- LIMIT 10`).all(n.id).map(l=>{let u=Fe({inputTokens:l.total_input_tokens??0,outputTokens:l.total_output_tokens??0,cacheCreateTokens:l.total_cache_create_tokens??0,cacheReadTokens:l.total_cache_read_tokens??0},l.primary_model);return{sessionId:l.id,alias:l.alias,startedAt:l.started_at,totalTokens:u.totalTokens,cost:u}});return{project:n.name,sessionCount:o.session_count,inputTokens:o.input_tokens,outputTokens:o.output_tokens,cacheCreateTokens:o.cache_create_tokens,cacheReadTokens:o.cache_read_tokens,totalTokens:i.totalTokens,cost:i,byModel:r,topSessions:d,display:{dollars:le(i.cents),tokens:he(i.totalTokens)}}}function im(e="all"){let t=E(),n=e==="7d"?new Date(Date.now()-7*864e5).toISOString():e==="30d"?new Date(Date.now()-30*864e5).toISOString():null,s=n?"WHERE mu.timestamp >= @since OR (mu.timestamp IS NULL AND s.started_at >= @since)":"",r=n?"WHERE m.timestamp >= @since OR (m.timestamp IS NULL AND s2.started_at >= @since)":"",o=n?{since:n}:{},i=x=>n?t.prepare(x).get(o):t.prepare(x).get(),a=x=>n?t.prepare(x).all(o):t.prepare(x).all(),d=a(`SELECT mu.model,
1623
+ LIMIT 10`).all(n.id).map(l=>{let u=je({inputTokens:l.total_input_tokens??0,outputTokens:l.total_output_tokens??0,cacheCreateTokens:l.total_cache_create_tokens??0,cacheReadTokens:l.total_cache_read_tokens??0},l.primary_model);return{sessionId:l.id,alias:l.alias,startedAt:l.started_at,totalTokens:u.totalTokens,cost:u}});return{project:n.name,sessionCount:o.session_count,inputTokens:o.input_tokens,outputTokens:o.output_tokens,cacheCreateTokens:o.cache_create_tokens,cacheReadTokens:o.cache_read_tokens,totalTokens:i.totalTokens,cost:i,byModel:r,topSessions:d,display:{dollars:le(i.cents),tokens:he(i.totalTokens)}}}function fm(e="all"){let t=h(),n=e==="7d"?new Date(Date.now()-7*864e5).toISOString():e==="30d"?new Date(Date.now()-30*864e5).toISOString():null,s=n?"WHERE mu.timestamp >= @since OR (mu.timestamp IS NULL AND s.started_at >= @since)":"",r=n?"WHERE m.timestamp >= @since OR (m.timestamp IS NULL AND s2.started_at >= @since)":"",o=n?{since:n}:{},i=x=>n?t.prepare(x).get(o):t.prepare(x).get(),a=x=>n?t.prepare(x).all(o):t.prepare(x).all(),d=a(`SELECT mu.model,
1619
1624
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
1620
1625
  COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
1621
1626
  COALESCE(SUM(mu.cache_create_tokens), 0) AS cache_create_tokens,
@@ -1624,7 +1629,7 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1624
1629
  FROM message_usage mu
1625
1630
  JOIN sessions s ON s.id = mu.session_id
1626
1631
  ${s}
1627
- GROUP BY mu.model`),l=Ui(d),u=0,m=0,p=0,g=0;for(let x of l)u+=x.inputTokens,m+=x.outputTokens,p+=x.cacheCreateTokens,g+=x.cacheReadTokens;let f=Fe({inputTokens:u,outputTokens:m,cacheCreateTokens:p,cacheReadTokens:g,...Bi(l)},null),h=n?i(`SELECT
1632
+ GROUP BY mu.model`),l=Gi(d),u=0,m=0,p=0,g=0;for(let x of l)u+=x.inputTokens,m+=x.outputTokens,p+=x.cacheCreateTokens,g+=x.cacheReadTokens;let f=je({inputTokens:u,outputTokens:m,cacheCreateTokens:p,cacheReadTokens:g,...Ji(l)},null),_=n?i(`SELECT
1628
1633
  (SELECT COUNT(DISTINCT m.session_id)
1629
1634
  FROM messages m
1630
1635
  JOIN sessions s2 ON s2.id = m.session_id
@@ -1638,7 +1643,7 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1638
1643
  WHERE (COALESCE(total_input_tokens,0)
1639
1644
  +COALESCE(total_output_tokens,0)
1640
1645
  +COALESCE(total_cache_create_tokens,0)
1641
- +COALESCE(total_cache_read_tokens,0)) > 0) AS sessions_with_usage`).get(),_=a(`SELECT substr(datetime(COALESCE(mu.timestamp, s.started_at, ''), 'localtime'), 1, 10) AS day,
1646
+ +COALESCE(total_cache_read_tokens,0)) > 0) AS sessions_with_usage`).get(),b=a(`SELECT substr(datetime(COALESCE(mu.timestamp, s.started_at, ''), 'localtime'), 1, 10) AS day,
1642
1647
  mu.model,
1643
1648
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
1644
1649
  COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
@@ -1648,7 +1653,7 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1648
1653
  JOIN sessions s ON s.id = mu.session_id
1649
1654
  ${s}
1650
1655
  GROUP BY day, mu.model
1651
- ORDER BY day ASC`),b=new Map;for(let x of _){if(!x.day)continue;let M=Fe({inputTokens:x.input_tokens,outputTokens:x.output_tokens,cacheCreateTokens:x.cache_create_tokens,cacheReadTokens:x.cache_read_tokens},x.model),F=b.get(x.day)??{tokens:0,cents:0};F.tokens+=M.totalTokens,F.cents+=M.cents,b.set(x.day,F)}let S=[...b.entries()].map(([x,M])=>({day:x,tokens:M.tokens,cents:M.cents})).sort((x,M)=>x.day.localeCompare(M.day)),T=a(`SELECT s.id, p.name AS project, sa.alias, s.started_at,
1656
+ ORDER BY day ASC`),E=new Map;for(let x of b){if(!x.day)continue;let M=je({inputTokens:x.input_tokens,outputTokens:x.output_tokens,cacheCreateTokens:x.cache_create_tokens,cacheReadTokens:x.cache_read_tokens},x.model),F=E.get(x.day)??{tokens:0,cents:0};F.tokens+=M.totalTokens,F.cents+=M.cents,E.set(x.day,F)}let S=[...E.entries()].map(([x,M])=>({day:x,tokens:M.tokens,cents:M.cents})).sort((x,M)=>x.day.localeCompare(M.day)),T=a(`SELECT s.id, p.name AS project, sa.alias, s.started_at,
1652
1657
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
1653
1658
  COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
1654
1659
  COALESCE(SUM(mu.cache_create_tokens), 0) AS cache_create_tokens,
@@ -1664,7 +1669,7 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1664
1669
  + COALESCE(SUM(mu.output_tokens),0)
1665
1670
  + COALESCE(SUM(mu.cache_create_tokens),0)
1666
1671
  + COALESCE(SUM(mu.cache_read_tokens),0)) DESC
1667
- LIMIT 10`).map(x=>{let M=Fe({inputTokens:x.input_tokens,outputTokens:x.output_tokens,cacheCreateTokens:x.cache_create_tokens,cacheReadTokens:x.cache_read_tokens},x.primary_model);return{sessionId:x.id,project:x.project,alias:x.alias,startedAt:x.started_at,totalTokens:M.totalTokens,cost:M}}),R=a(`SELECT p.id AS project_id,
1672
+ LIMIT 10`).map(x=>{let M=je({inputTokens:x.input_tokens,outputTokens:x.output_tokens,cacheCreateTokens:x.cache_create_tokens,cacheReadTokens:x.cache_read_tokens},x.primary_model);return{sessionId:x.id,project:x.project,alias:x.alias,startedAt:x.started_at,totalTokens:M.totalTokens,cost:M}}),R=a(`SELECT p.id AS project_id,
1668
1673
  p.name AS project,
1669
1674
  mu.model,
1670
1675
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
@@ -1676,35 +1681,41 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1676
1681
  JOIN sessions s ON s.id = mu.session_id
1677
1682
  LEFT JOIN projects p ON p.id = s.project_id
1678
1683
  ${s}
1679
- GROUP BY p.id, mu.model`),B=new Map;for(let x of R){let M=x.project_id??"__none__",F=B.get(M);F||(F={project:x.project??"(no project)",sessionIds:new Set,sessionsApprox:0,byModel:{}},B.set(M,F)),x.sessions>F.sessionsApprox&&(F.sessionsApprox=x.sessions),F.byModel[x.model??"__unknown__"]={inputTokens:x.input_tokens,outputTokens:x.output_tokens,cacheCreateTokens:x.cache_create_tokens,cacheReadTokens:x.cache_read_tokens}}let L=[...B.values()].map(x=>{let M=0,F=0,ne=0,et=0;for(let xt of Object.values(x.byModel))M+=xt.inputTokens,F+=xt.outputTokens,ne+=xt.cacheCreateTokens,et+=xt.cacheReadTokens;let We=Fe({inputTokens:M,outputTokens:F,cacheCreateTokens:ne,cacheReadTokens:et,byModel:x.byModel},null);return{project:x.project,sessions:x.sessionsApprox,totalTokens:We.totalTokens,cost:We}});L.sort((x,M)=>M.totalTokens-x.totalTokens);let v=L.slice(0,20),O=t.prepare(`SELECT
1684
+ GROUP BY p.id, mu.model`),B=new Map;for(let x of R){let M=x.project_id??"__none__",F=B.get(M);F||(F={project:x.project??"(no project)",sessionIds:new Set,sessionsApprox:0,byModel:{}},B.set(M,F)),x.sessions>F.sessionsApprox&&(F.sessionsApprox=x.sessions),F.byModel[x.model??"__unknown__"]={inputTokens:x.input_tokens,outputTokens:x.output_tokens,cacheCreateTokens:x.cache_create_tokens,cacheReadTokens:x.cache_read_tokens}}let A=[...B.values()].map(x=>{let M=0,F=0,ne=0,et=0;for(let xt of Object.values(x.byModel))M+=xt.inputTokens,F+=xt.outputTokens,ne+=xt.cacheCreateTokens,et+=xt.cacheReadTokens;let Xe=je({inputTokens:M,outputTokens:F,cacheCreateTokens:ne,cacheReadTokens:et,byModel:x.byModel},null);return{project:x.project,sessions:x.sessionsApprox,totalTokens:Xe.totalTokens,cost:Xe}});A.sort((x,M)=>M.totalTokens-x.totalTokens);let v=A.slice(0,20),O=t.prepare(`SELECT
1680
1685
  (SELECT COUNT(*) FROM messages WHERE role='assistant') AS assistant_messages,
1681
- (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:g,totalTokens:f.totalTokens,cost:f,daily:S,byModel:l,topSessions:T,topRepos:v,backfill:{assistantMessages:O.assistant_messages,messagesWithUsage:O.messages_with_usage,pending:Math.max(0,O.assistant_messages-O.messages_with_usage),unrecoverable:Math.min(nm(),Math.max(0,O.assistant_messages-O.messages_with_usage))},display:{dollars:le(f.cents),tokens:he(f.totalTokens)}}}var at=e=>e.toLocaleString();function d0(e){return E().prepare("SELECT id FROM sessions WHERE id = ? OR id LIKE ? LIMIT 1").get(e,`${e}%`)?.id??null}async function am(e,t){if(t.backfill){let r=t.limit?Math.max(1,Number(t.limit)):void 0;console.log(c.dim("backfilling per-message usage from raw_json\u2026"));let o=sm({limit:r});if(console.log(`${c.ok("backfill done")}: scanned ${c.bold(String(o.scanned))}, inserted ${c.bold(String(o.inserted))}, rolled-up ${c.bold(String(o.sessionsTouched))} sessions`),!e&&!t.project)return}if(e){let r=d0(e);if(!r){console.error(c.err(`no session matches '${e}'`)),process.exit(1);return}let o=rm(r);if(!o){console.error(c.err("session has no usage data yet \u2014 try --backfill")),process.exit(1);return}if(t.json){console.log(JSON.stringify(o,null,2));return}if(console.log(""),console.log(c.bold("session cost")),console.log(c.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` id ${c.dim(o.sessionId)}`),console.log(` project ${c.accent(o.project??"\u2014")}`),console.log(` started ${c.dim(o.startedAt??"n/a")}`),console.log(` messages ${c.accent(at(o.messageCount))}`),console.log(` model ${c.accent(o.primaryModelLabel)} ${c.dim(o.primaryModel??"")}`),console.log(""),console.log(` input ${at(o.inputTokens).padStart(12)}`),console.log(` output ${at(o.outputTokens).padStart(12)}`),console.log(` cache write ${at(o.cacheCreateTokens).padStart(12)}`),console.log(` cache read ${at(o.cacheReadTokens).padStart(12)}`),console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),console.log(` total tokens ${c.bold(at(o.totalTokens).padStart(12))}`),console.log(` estimated cost ${c.accent(le(o.cost.cents).padStart(12))}`),o.byModel.length>1){console.log(""),console.log(c.dim(" by model:"));for(let i of o.byModel)console.log(` ${i.modelLabel.padEnd(14)} ${he(i.inputTokens+i.outputTokens+i.cacheCreateTokens+i.cacheReadTokens).padStart(10)} ${c.accent(le(i.cost.cents).padStart(10))}`)}console.log("");return}if(t.project){let r=om(t.project);if(!r){console.error(c.err(`project '${t.project}' not found`)),process.exit(1);return}if(t.json){console.log(JSON.stringify(r,null,2));return}if(console.log(""),console.log(c.bold(`project \xB7 ${r.project}`)),console.log(c.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` sessions ${c.accent(at(r.sessionCount))}`),console.log(` total tokens ${c.accent(he(r.totalTokens).padStart(12))}`),console.log(` estimated cost ${c.accent(le(r.cost.cents).padStart(12))}`),r.byModel.length>0){console.log(""),console.log(c.dim(" by model:"));for(let o of r.byModel)console.log(` ${o.modelLabel.padEnd(14)} ${he(o.inputTokens+o.outputTokens+o.cacheCreateTokens+o.cacheReadTokens).padStart(10)} ${c.accent(le(o.cost.cents).padStart(10))}`)}if(r.topSessions.length>0){console.log(""),console.log(c.dim(" top sessions:"));for(let o of r.topSessions){let i=o.alias??o.sessionId.slice(0,8);console.log(` ${i.padEnd(22)} ${he(o.totalTokens).padStart(10)} ${c.accent(le(o.cost.cents).padStart(10))}`)}}console.log("");return}let n=t.days==="7"?"7d":t.days==="30"?"30d":"all",s=im(n);if(t.json){console.log(JSON.stringify(s,null,2));return}if(console.log(""),console.log(c.bold(`overview \xB7 ${n}`)),console.log(c.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` sessions ${c.accent(at(s.totalSessions))} ${c.dim(`(${s.sessionsWithUsage} w/ usage)`)}`),console.log(` total tokens ${c.accent(he(s.totalTokens).padStart(12))}`),console.log(` estimated cost ${c.accent(le(s.cost.cents).padStart(12))}`),s.backfill.pending>0&&console.log(c.dim(` (${at(s.backfill.pending)} assistant messages pending \u2014 run \`recall stats --backfill\`)`)),s.byModel.length>0){console.log(""),console.log(c.dim(" by model:"));for(let r of s.byModel)console.log(` ${r.modelLabel.padEnd(14)} ${he(r.inputTokens+r.outputTokens+r.cacheCreateTokens+r.cacheReadTokens).padStart(10)} ${c.accent(le(r.cost.cents).padStart(10))}`)}if(s.topSessions.length>0){console.log(""),console.log(c.dim(" top sessions:"));for(let r of s.topSessions){let o=r.alias??r.sessionId.slice(0,8);console.log(` ${o.padEnd(22)} ${(r.project??"").slice(0,20).padEnd(22)} ${he(r.totalTokens).padStart(10)} ${c.accent(le(r.cost.cents).padStart(10))}`)}}console.log("")}$();k();Nn();function u0(e){return E().prepare("SELECT id FROM sessions WHERE id = ? OR id LIKE ? LIMIT 1").get(e,`${e}%`)?.id??null}function p0(e){let t=e.sessionId.slice(0,8);switch(e.status){case"ok":console.log(`${c.ok("\u2713")} ${c.dim(t)} ${c.bold(String(e.commitsFound))} commits (${e.commitsInserted} new)`);break;case"no-cwd":console.log(`${c.dim("\xB7")} ${c.dim(t)} no cwd recorded \u2014 skipped`);break;case"not-a-repo":console.log(`${c.dim("\xB7")} ${c.dim(t)} cwd is not a git worktree \u2014 skipped`);break;case"cwd-missing":console.log(`${c.dim("\xB7")} ${c.dim(t)} cwd no longer exists on disk \u2014 skipped`);break;case"no-window":console.log(`${c.dim("\xB7")} ${c.dim(t)} session has no time window yet \u2014 skipped`);break;case"error":console.log(`${c.err("\u2717")} ${c.dim(t)} ${e.error??"unknown error"}`);break}}async function cm(e,t){if(e){let r=u0(e);if(!r){console.error(c.err(`no session matches '${e}'`)),process.exit(1);return}let o=await pi(r);if(t.json){console.log(JSON.stringify(o,null,2));return}p0(o);return}let n=t.limit?Math.max(1,Number(t.limit)):void 0;console.log(c.dim(`correlating sessions to git commits (limit ${n??"default"})\u2026`));let s=await su({limit:n,onProgress:(r,o)=>{(r%25===0||r===o)&&process.stderr.write(`\r${c.dim(` ${r}/${o}`)}`)}});if(process.stderr.write(`
1682
- `),t.json){console.log(JSON.stringify(s,null,2));return}console.log(""),console.log(`${c.ok("correlated")}: ${c.bold(String(s.ok))} sessions \xB7 ${c.bold(String(s.commitsInserted))} new commits`),console.log(c.dim(` skipped ${s.skipped} (no cwd / non-repo / cwd missing), errors ${s.errors}`)),console.log("")}$();k();At();ui();import{existsSync as Hi,readFileSync as Wi}from"node:fs";I();function g0(){let e=`${C}/daemon.port`;if(!Hi(e))return null;try{let t=Wi(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function f0(e,t){try{return(await ut("POST",`http://127.0.0.1:${e}/api/sessions/${encodeURIComponent(t)}/relink`,{clear:!0})).ok}catch{return!1}}function _0(e,t){let n=E(),s=t?" AND p.name = ?":"",r=t?[t]:[],o=n.prepare(`SELECT s.id, p.name AS project_name, s.cwd, s.started_at, sa.alias
1686
+ (SELECT COUNT(*) FROM message_usage) AS messages_with_usage`).get();return{range:e,totalSessions:_.total_sessions,sessionsWithUsage:_.sessions_with_usage,inputTokens:u,outputTokens:m,cacheCreateTokens:p,cacheReadTokens:g,totalTokens:f.totalTokens,cost:f,daily:S,byModel:l,topSessions:T,topRepos:v,backfill:{assistantMessages:O.assistant_messages,messagesWithUsage:O.messages_with_usage,pending:Math.max(0,O.assistant_messages-O.messages_with_usage),unrecoverable:Math.min(um(),Math.max(0,O.assistant_messages-O.messages_with_usage))},display:{dollars:le(f.cents),tokens:he(f.totalTokens)}}}var at=e=>e.toLocaleString();function A0(e){return h().prepare("SELECT id FROM sessions WHERE id = ? OR id LIKE ? LIMIT 1").get(e,`${e}%`)?.id??null}async function _m(e,t){if(t.backfill){let r=t.limit?Math.max(1,Number(t.limit)):void 0;console.log(c.dim("backfilling per-message usage from raw_json\u2026"));let o=pm({limit:r});if(console.log(`${c.ok("backfill done")}: scanned ${c.bold(String(o.scanned))}, inserted ${c.bold(String(o.inserted))}, rolled-up ${c.bold(String(o.sessionsTouched))} sessions`),!e&&!t.project)return}if(e){let r=A0(e);if(!r){console.error(c.err(`no session matches '${e}'`)),process.exit(1);return}let o=mm(r);if(!o){console.error(c.err("session has no usage data yet \u2014 try --backfill")),process.exit(1);return}if(t.json){console.log(JSON.stringify(o,null,2));return}if(console.log(""),console.log(c.bold("session cost")),console.log(c.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` id ${c.dim(o.sessionId)}`),console.log(` project ${c.accent(o.project??"\u2014")}`),console.log(` started ${c.dim(o.startedAt??"n/a")}`),console.log(` messages ${c.accent(at(o.messageCount))}`),console.log(` model ${c.accent(o.primaryModelLabel)} ${c.dim(o.primaryModel??"")}`),console.log(""),console.log(` input ${at(o.inputTokens).padStart(12)}`),console.log(` output ${at(o.outputTokens).padStart(12)}`),console.log(` cache write ${at(o.cacheCreateTokens).padStart(12)}`),console.log(` cache read ${at(o.cacheReadTokens).padStart(12)}`),console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),console.log(` total tokens ${c.bold(at(o.totalTokens).padStart(12))}`),console.log(` estimated cost ${c.accent(le(o.cost.cents).padStart(12))}`),o.byModel.length>1){console.log(""),console.log(c.dim(" by model:"));for(let i of o.byModel)console.log(` ${i.modelLabel.padEnd(14)} ${he(i.inputTokens+i.outputTokens+i.cacheCreateTokens+i.cacheReadTokens).padStart(10)} ${c.accent(le(i.cost.cents).padStart(10))}`)}console.log("");return}if(t.project){let r=gm(t.project);if(!r){console.error(c.err(`project '${t.project}' not found`)),process.exit(1);return}if(t.json){console.log(JSON.stringify(r,null,2));return}if(console.log(""),console.log(c.bold(`project \xB7 ${r.project}`)),console.log(c.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` sessions ${c.accent(at(r.sessionCount))}`),console.log(` total tokens ${c.accent(he(r.totalTokens).padStart(12))}`),console.log(` estimated cost ${c.accent(le(r.cost.cents).padStart(12))}`),r.byModel.length>0){console.log(""),console.log(c.dim(" by model:"));for(let o of r.byModel)console.log(` ${o.modelLabel.padEnd(14)} ${he(o.inputTokens+o.outputTokens+o.cacheCreateTokens+o.cacheReadTokens).padStart(10)} ${c.accent(le(o.cost.cents).padStart(10))}`)}if(r.topSessions.length>0){console.log(""),console.log(c.dim(" top sessions:"));for(let o of r.topSessions){let i=o.alias??o.sessionId.slice(0,8);console.log(` ${i.padEnd(22)} ${he(o.totalTokens).padStart(10)} ${c.accent(le(o.cost.cents).padStart(10))}`)}}console.log("");return}let n=t.days==="7"?"7d":t.days==="30"?"30d":"all",s=fm(n);if(t.json){console.log(JSON.stringify(s,null,2));return}if(console.log(""),console.log(c.bold(`overview \xB7 ${n}`)),console.log(c.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),console.log(` sessions ${c.accent(at(s.totalSessions))} ${c.dim(`(${s.sessionsWithUsage} w/ usage)`)}`),console.log(` total tokens ${c.accent(he(s.totalTokens).padStart(12))}`),console.log(` estimated cost ${c.accent(le(s.cost.cents).padStart(12))}`),s.backfill.pending>0&&console.log(c.dim(` (${at(s.backfill.pending)} assistant messages pending \u2014 run \`recall stats --backfill\`)`)),s.byModel.length>0){console.log(""),console.log(c.dim(" by model:"));for(let r of s.byModel)console.log(` ${r.modelLabel.padEnd(14)} ${he(r.inputTokens+r.outputTokens+r.cacheCreateTokens+r.cacheReadTokens).padStart(10)} ${c.accent(le(r.cost.cents).padStart(10))}`)}if(s.topSessions.length>0){console.log(""),console.log(c.dim(" top sessions:"));for(let r of s.topSessions){let o=r.alias??r.sessionId.slice(0,8);console.log(` ${o.padEnd(22)} ${(r.project??"").slice(0,20).padEnd(22)} ${he(r.totalTokens).padStart(10)} ${c.accent(le(r.cost.cents).padStart(10))}`)}}console.log("")}D();k();Nn();function L0(e){return h().prepare("SELECT id FROM sessions WHERE id = ? OR id LIKE ? LIMIT 1").get(e,`${e}%`)?.id??null}function N0(e){let t=e.sessionId.slice(0,8);switch(e.status){case"ok":console.log(`${c.ok("\u2713")} ${c.dim(t)} ${c.bold(String(e.commitsFound))} commits (${e.commitsInserted} new)`);break;case"no-cwd":console.log(`${c.dim("\xB7")} ${c.dim(t)} no cwd recorded \u2014 skipped`);break;case"not-a-repo":console.log(`${c.dim("\xB7")} ${c.dim(t)} cwd is not a git worktree \u2014 skipped`);break;case"cwd-missing":console.log(`${c.dim("\xB7")} ${c.dim(t)} cwd no longer exists on disk \u2014 skipped`);break;case"no-window":console.log(`${c.dim("\xB7")} ${c.dim(t)} session has no time window yet \u2014 skipped`);break;case"error":console.log(`${c.err("\u2717")} ${c.dim(t)} ${e.error??"unknown error"}`);break}}async function hm(e,t){if(e){let r=L0(e);if(!r){console.error(c.err(`no session matches '${e}'`)),process.exit(1);return}let o=await gi(r);if(t.json){console.log(JSON.stringify(o,null,2));return}N0(o);return}let n=t.limit?Math.max(1,Number(t.limit)):void 0;console.log(c.dim(`correlating sessions to git commits (limit ${n??"default"})\u2026`));let s=await lu({limit:n,onProgress:(r,o)=>{(r%25===0||r===o)&&process.stderr.write(`\r${c.dim(` ${r}/${o}`)}`)}});if(process.stderr.write(`
1687
+ `),t.json){console.log(JSON.stringify(s,null,2));return}console.log(""),console.log(`${c.ok("correlated")}: ${c.bold(String(s.ok))} sessions \xB7 ${c.bold(String(s.commitsInserted))} new commits`),console.log(c.dim(` skipped ${s.skipped} (no cwd / non-repo / cwd missing), errors ${s.errors}`)),console.log("")}D();k();Lt();mi();import{existsSync as zi,readFileSync as Yi}from"node:fs";I();function v0(){let e=`${C}/daemon.port`;if(!zi(e))return null;try{let t=Yi(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function I0(e,t){try{return(await ut("POST",`http://127.0.0.1:${e}/api/sessions/${encodeURIComponent(t)}/relink`,{clear:!0})).ok}catch{return!1}}function M0(e,t){let n=h(),s=t?" AND p.name = ?":"",r=t?[t]:[],o=n.prepare(`SELECT s.id, p.name AS project_name, s.cwd, s.started_at, sa.alias
1683
1688
  FROM sessions s
1684
1689
  JOIN projects p ON p.id = s.project_id
1685
1690
  JOIN session_aliases sa ON sa.session_id = s.id
1686
1691
  WHERE s.cwd IS NOT NULL
1687
1692
  AND s.started_at IS NOT NULL
1688
1693
  AND sa.alias IS NOT NULL
1689
- AND sa.alias <> ''${s}`).all(...r),i=new Map;for(let l of o){let u=l.cwd.replace(/\/+$/,""),m=i.get(u);m||(m=[],i.set(u,m)),m.push(l)}let a=e*1e3,d=new Map;for(let[l,u]of i){let m=new Map;for(let p of u){let g=m.get(p.alias);g||(g=[],m.set(p.alias,g)),g.push(p)}for(let p of m.values())if(!(p.length<2))for(let g of p){let f=new Set;for(let h of p)h.id!==g.id&&f.add(h.id);d.set(g.id,{row:g,cwdKey:l,reason:"duplicate-alias",siblingIds:f})}}for(let[l,u]of i){if(u.length<2)continue;u.sort((g,f)=>Date.parse(g.started_at)-Date.parse(f.started_at));let m=[],p=()=>{if(m.length>=2)for(let g of m){if(d.has(g.id))continue;let f=new Set;for(let h of m)h.id!==g.id&&f.add(h.id);d.set(g.id,{row:g,cwdKey:l,reason:"cwd-collision",siblingIds:f})}m=[]};for(let g of u){if(m.length===0){m.push(g);continue}let f=m[m.length-1];Date.parse(g.started_at)-Date.parse(f.started_at)<=a||p(),m.push(g)}p()}return Array.from(d.values()).map(l=>({session_id:l.row.id,project_name:l.row.project_name,cwd:l.cwdKey,started_at:l.row.started_at,alias:l.row.alias,sibling_ids:Array.from(l.siblingIds),reason:l.reason}))}function h0(e){let t=[];try{let n=`${C}/terminals.json`;if(!Hi(n))return t;let s=JSON.parse(Wi(n,"utf8")),r=s.sessions_by_pid??{},o=new Map;for(let a of s.terminals??[])o.set(a.shell_pid,a);let i=E();for(let[a,d]of Object.entries(r)){let l=Number(a);if(!Number.isFinite(l))continue;let u=o.get(l)??null;for(let m of d){let p=i.prepare(`SELECT s.id, p.name AS project_name, s.cwd, s.started_at,
1694
+ AND sa.alias <> ''${s}`).all(...r),i=new Map;for(let l of o){let u=l.cwd.replace(/\/+$/,""),m=i.get(u);m||(m=[],i.set(u,m)),m.push(l)}let a=e*1e3,d=new Map;for(let[l,u]of i){let m=new Map;for(let p of u){let g=m.get(p.alias);g||(g=[],m.set(p.alias,g)),g.push(p)}for(let p of m.values())if(!(p.length<2))for(let g of p){let f=new Set;for(let _ of p)_.id!==g.id&&f.add(_.id);d.set(g.id,{row:g,cwdKey:l,reason:"duplicate-alias",siblingIds:f})}}for(let[l,u]of i){if(u.length<2)continue;u.sort((g,f)=>Date.parse(g.started_at)-Date.parse(f.started_at));let m=[],p=()=>{if(m.length>=2)for(let g of m){if(d.has(g.id))continue;let f=new Set;for(let _ of m)_.id!==g.id&&f.add(_.id);d.set(g.id,{row:g,cwdKey:l,reason:"cwd-collision",siblingIds:f})}m=[]};for(let g of u){if(m.length===0){m.push(g);continue}let f=m[m.length-1];Date.parse(g.started_at)-Date.parse(f.started_at)<=a||p(),m.push(g)}p()}return Array.from(d.values()).map(l=>({session_id:l.row.id,project_name:l.row.project_name,cwd:l.cwdKey,started_at:l.row.started_at,alias:l.row.alias,sibling_ids:Array.from(l.siblingIds),reason:l.reason}))}function D0(e){let t=[];try{let n=`${C}/terminals.json`;if(!zi(n))return t;let s=JSON.parse(Yi(n,"utf8")),r=s.sessions_by_pid??{},o=new Map;for(let a of s.terminals??[])o.set(a.shell_pid,a);let i=h();for(let[a,d]of Object.entries(r)){let l=Number(a);if(!Number.isFinite(l))continue;let u=o.get(l)??null;for(let m of d){let p=i.prepare(`SELECT s.id, p.name AS project_name, s.cwd, s.started_at,
1690
1695
  NULLIF(sa.alias, '') AS alias
1691
1696
  FROM sessions s
1692
1697
  JOIN projects p ON p.id = s.project_id
1693
1698
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1694
- 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 E0(e){let t=[],n=`${C}/terminals.json`;if(!Hi(n))return t;let s;try{s=JSON.parse(Wi(n,"utf8"))}catch{return t}let r=new Map;for(let l of s.terminals??[]){if(!l.tab_name)continue;let u=r.get(l.tab_name);u||(u=[],r.set(l.tab_name,u)),u.push(l)}if(r.size===0)return t;let o=E(),i=e?" AND p.name = ?":"",a=e?[e]:[],d=o.prepare(`SELECT s.id, p.name AS project_name, s.cwd, s.started_at, sa.alias
1699
+ 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 $0(e){let t=[],n=`${C}/terminals.json`;if(!zi(n))return t;let s;try{s=JSON.parse(Yi(n,"utf8"))}catch{return t}let r=new Map;for(let l of s.terminals??[]){if(!l.tab_name)continue;let u=r.get(l.tab_name);u||(u=[],r.set(l.tab_name,u)),u.push(l)}if(r.size===0)return t;let o=h(),i=e?" AND p.name = ?":"",a=e?[e]:[],d=o.prepare(`SELECT s.id, p.name AS project_name, s.cwd, s.started_at, sa.alias
1695
1700
  FROM sessions s
1696
1701
  JOIN projects p ON p.id = s.project_id
1697
1702
  JOIN session_aliases sa ON sa.session_id = s.id
1698
1703
  WHERE s.started_at IS NOT NULL
1699
1704
  AND sa.alias IS NOT NULL
1700
- AND sa.alias <> ''${i}`).all(...a);for(let l of d){let u=r.get(l.alias);if(!u||u.length===0)continue;let m=Date.parse(l.started_at);if(!Number.isFinite(m))continue;let p=!1,g=null,f=1/0;for(let h of u){let _=Date.parse(h.opened_at);if(Number.isFinite(_)){if(_-m<=6e4){p=!0;break}_<f&&(f=_,g=h)}}p||!g||t.push({session_id:l.id,project_name:l.project_name,cwd:l.cwd.replace(/\/+$/,""),started_at:l.started_at,alias:l.alias,sibling_ids:[],reason:"temporal-anomaly",postdating_terminal:g})}return t}function b0(e){if(e.length===0){console.log(c.ok("No suspicious correlations found."));return}console.log(c.warn(`Found ${e.length} session${e.length===1?"":"s"} with likely-bad correlator aliases:`)),console.log();let t=new Map;for(let n of e){let s=t.get(n.cwd);s||(s=[],t.set(n.cwd,s)),s.push(n)}for(let[n,s]of t){console.log(c.dim(` cwd: ${n}`)),s.sort((r,o)=>Date.parse(r.started_at)-Date.parse(o.started_at));for(let r of s){let o=r.reason==="duplicate-alias"?c.err("[dup-alias]"):r.reason==="orphan-link"?c.warn("[orphan-link]"):r.reason==="temporal-anomaly"?c.err("[temporal]"):c.warn("[cwd-collision]"),i=r.reason==="orphan-link"&&r.stale_terminal?`${c.dim("still pointing at pid")} ${r.stale_terminal.shell_pid} ${c.dim("=")} ${c.bold(`"${r.stale_terminal.tab_name}"`)}`:r.reason==="temporal-anomaly"&&r.postdating_terminal?`${c.bold(`"${r.alias}"`)} ${c.dim("\u2190 terminal opened")} ${r.postdating_terminal.opened_at.replace("T"," ").slice(0,19)} ${c.dim("(after session)")}`:c.bold(`"${r.alias}"`);console.log(` ${o} ${c.dim(r.session_id.slice(0,8))} ${c.dim(r.started_at.replace("T"," ").slice(0,19))} \u2192 ${i}`)}console.log()}}async function lm(e){let t=e.window?Math.max(5,Math.min(600,Number(e.window)||60)):60,n=e.project?.trim()||void 0,s=_0(t,n),r=h0(n),o=E0(n),i=new Set,a=[];for(let m of[...s,...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(b0(a),!e.fix){a.length>0&&console.log(c.dim("Re-run with --fix to clear these aliases. Heuristic titles will display instead, and you can manually relink via the UI's \u{1F517} picker."));return}let d=g0(),l=0,u=0;for(let m of a){if(d){await f0(d,m.session_id)?l++:(u++,console.error(c.err(`failed to clear ${m.session_id.slice(0,8)} via daemon`)));continue}try{Ol(m.session_id),di.unlinkSession(m.session_id),l++}catch(p){u++,console.error(c.err(`failed to clear ${m.session_id.slice(0,8)}: ${p.message}`))}}console.log(c.ok(`Cleared ${l} suspect alias${l===1?"":"es"}.`)),u>0&&console.log(c.warn(`${u} clears failed; see errors above.`)),d||console.log(c.dim("Daemon was not running, so changes were applied directly to state files.")),console.log(c.dim("Open an affected session in the UI and use the \u{1F517} picker to pin the correct terminal."))}yi();$();k();I();import{existsSync as S0,readFileSync as y0}from"node:fs";import{join as w0}from"node:path";function T0(){let e=w0(C,"daemon.pid");if(!S0(e))return!1;try{let t=parseInt(y0(e,"utf-8").trim(),10);return!Number.isFinite(t)||t<=0?!1:(process.kill(t,0),!0)}catch{return!1}}async function $n(e,t){let n=Date.now();try{return t(),{step:e,ok:!0,durationMs:Date.now()-n}}catch(s){return{step:e,ok:!1,durationMs:Date.now()-n,error:s.message}}}async function dm(e={}){let t=E(),n=[];if(e.vacuum&&T0())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)+`
1701
- `),2):(console.error(c.err("\u2717 VACUUM requires the daemon to be stopped. Run `recall stop` first, then re-run with --vacuum.")),2);n.push(await $n("wal_checkpoint(TRUNCATE)",()=>{t.pragma("wal_checkpoint(TRUNCATE)")})),n.push(await $n("messages_fts optimize",()=>{t.exec("INSERT INTO messages_fts(messages_fts) VALUES('optimize');")})),n.push(await $n("sessions_fts optimize",()=>{t.exec("INSERT INTO sessions_fts(sessions_fts) VALUES('optimize');")})),n.push(await $n("PRAGMA optimize",()=>{t.exec("PRAGMA optimize")})),e.vacuum&&n.push(await $n("VACUUM",()=>{t.exec("VACUUM")}));let s=n.filter(r=>!r.ok);if(e.json)return process.stdout.write(JSON.stringify({ok:s.length===0,steps:n,vacuum:!!e.vacuum},null,2)+`
1702
- `),s.length===0?0:1;for(let r of n){let o=r.ok?c.ok("\u2713"):c.err("\u2717"),i=`${r.durationMs} ms`;console.log(` ${o} ${r.step.padEnd(28)} ${c.dim(i)}`),r.error&&console.log(` ${c.err(r.error)}`)}return s.length===0?(console.log(""),console.log(c.ok("All maintenance passes completed.")),e.vacuum||console.log(c.dim(" Run `recall optimize --vacuum` (with the daemon stopped) to reclaim disk pages from deleted rows.")),0):(console.log(""),console.log(c.warn(`${s.length} step(s) failed \u2014 review the errors above.`)),1)}$();k();I();dn();import{copyFileSync as R0,existsSync as k0,readFileSync as x0}from"node:fs";import{join as um}from"node:path";function C0(){let e=um(C,"daemon.pid");if(!k0(e))return!1;try{let t=parseInt(x0(e,"utf-8").trim(),10);return!Number.isFinite(t)||t<=0?!1:(process.kill(t,0),!0)}catch{return!1}}function L0(){let e=[];for(let t of Ut){let r=t.source.replace(/^\^/,"").replace(/\\d\+/g,"").match(/^([^.*+?{[(\\]+)/)?.[1]??"";r.length>=8&&e.push(r.replace(/'/g,"''"))}return e.length===0?"0":e.map(t=>`first_user_message LIKE '${t}%'`).join(" OR ")}async function pm(e={}){if(C0()&&!e.dryRun){let p="Daemon is running. Run `recall stop`, then `recall purge-phantoms`, then `recall start`. The purge needs an exclusive write lock and the daemon would race it.";return e.json?(process.stdout.write(JSON.stringify({ok:!1,reason:"daemon-running",message:p},null,2)+`
1703
- `),2):(console.error(c.err(`\u2717 ${p}`)),2)}let t=L0();if(t==="0"){let p="No phantom patterns are registered \u2014 nothing to purge.";return e.json?(process.stdout.write(JSON.stringify({ok:!0,reason:"no-patterns",message:p})+`
1704
- `),0):(console.log(c.warn(p)),0)}let n=E(),s=n.prepare(`SELECT COUNT(*) AS n FROM sessions WHERE ${t}`).get().n;if(s===0){let p="No phantom sessions found. Your DB is clean.";return e.json?(process.stdout.write(JSON.stringify({ok:!0,sessionsBefore:0,sessionsAfter:0,messagesDeleted:0,aliasesDeleted:0,patternsApplied:Ut.length,vacuumHint:!1,dryRun:!!e.dryRun},null,2)+`
1705
+ AND sa.alias <> ''${i}`).all(...a);for(let l of d){let u=r.get(l.alias);if(!u||u.length===0)continue;let m=Date.parse(l.started_at);if(!Number.isFinite(m))continue;let p=!1,g=null,f=1/0;for(let _ of u){let b=Date.parse(_.opened_at);if(Number.isFinite(b)){if(b-m<=6e4){p=!0;break}b<f&&(f=b,g=_)}}p||!g||t.push({session_id:l.id,project_name:l.project_name,cwd:l.cwd.replace(/\/+$/,""),started_at:l.started_at,alias:l.alias,sibling_ids:[],reason:"temporal-anomaly",postdating_terminal:g})}return t}function P0(e){if(e.length===0){console.log(c.ok("No suspicious correlations found."));return}console.log(c.warn(`Found ${e.length} session${e.length===1?"":"s"} with likely-bad correlator aliases:`)),console.log();let t=new Map;for(let n of e){let s=t.get(n.cwd);s||(s=[],t.set(n.cwd,s)),s.push(n)}for(let[n,s]of t){console.log(c.dim(` cwd: ${n}`)),s.sort((r,o)=>Date.parse(r.started_at)-Date.parse(o.started_at));for(let r of s){let o=r.reason==="duplicate-alias"?c.err("[dup-alias]"):r.reason==="orphan-link"?c.warn("[orphan-link]"):r.reason==="temporal-anomaly"?c.err("[temporal]"):c.warn("[cwd-collision]"),i=r.reason==="orphan-link"&&r.stale_terminal?`${c.dim("still pointing at pid")} ${r.stale_terminal.shell_pid} ${c.dim("=")} ${c.bold(`"${r.stale_terminal.tab_name}"`)}`:r.reason==="temporal-anomaly"&&r.postdating_terminal?`${c.bold(`"${r.alias}"`)} ${c.dim("\u2190 terminal opened")} ${r.postdating_terminal.opened_at.replace("T"," ").slice(0,19)} ${c.dim("(after session)")}`:c.bold(`"${r.alias}"`);console.log(` ${o} ${c.dim(r.session_id.slice(0,8))} ${c.dim(r.started_at.replace("T"," ").slice(0,19))} \u2192 ${i}`)}console.log()}}async function Em(e){let t=e.window?Math.max(5,Math.min(600,Number(e.window)||60)):60,n=e.project?.trim()||void 0,s=M0(t,n),r=D0(n),o=$0(n),i=new Set,a=[];for(let m of[...s,...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(P0(a),!e.fix){a.length>0&&console.log(c.dim("Re-run with --fix to clear these aliases. Heuristic titles will display instead, and you can manually relink via the UI's \u{1F517} picker."));return}let d=v0(),l=0,u=0;for(let m of a){if(d){await I0(d,m.session_id)?l++:(u++,console.error(c.err(`failed to clear ${m.session_id.slice(0,8)} via daemon`)));continue}try{$l(m.session_id),pi.unlinkSession(m.session_id),l++}catch(p){u++,console.error(c.err(`failed to clear ${m.session_id.slice(0,8)}: ${p.message}`))}}console.log(c.ok(`Cleared ${l} suspect alias${l===1?"":"es"}.`)),u>0&&console.log(c.warn(`${u} clears failed; see errors above.`)),d||console.log(c.dim("Daemon was not running, so changes were applied directly to state files.")),console.log(c.dim("Open an affected session in the UI and use the \u{1F517} picker to pin the correct terminal."))}xi();D();k();I();import{existsSync as F0,readFileSync as j0}from"node:fs";import{join as U0}from"node:path";function B0(){let e=U0(C,"daemon.pid");if(!F0(e))return!1;try{let t=parseInt(j0(e,"utf-8").trim(),10);return!Number.isFinite(t)||t<=0?!1:(process.kill(t,0),!0)}catch{return!1}}async function Pn(e,t){let n=Date.now();try{return t(),{step:e,ok:!0,durationMs:Date.now()-n}}catch(s){return{step:e,ok:!1,durationMs:Date.now()-n,error:s.message}}}async function bm(e={}){let t=h(),n=[];if(e.vacuum&&B0())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)+`
1706
+ `),2):(console.error(c.err("\u2717 VACUUM requires the daemon to be stopped. Run `recall stop` first, then re-run with --vacuum.")),2);n.push(await Pn("wal_checkpoint(TRUNCATE)",()=>{t.pragma("wal_checkpoint(TRUNCATE)")})),n.push(await Pn("messages_fts optimize",()=>{t.exec("INSERT INTO messages_fts(messages_fts) VALUES('optimize');")})),n.push(await Pn("sessions_fts optimize",()=>{t.exec("INSERT INTO sessions_fts(sessions_fts) VALUES('optimize');")})),n.push(await Pn("PRAGMA optimize",()=>{t.exec("PRAGMA optimize")})),e.vacuum&&n.push(await Pn("VACUUM",()=>{t.exec("VACUUM")}));let s=n.filter(r=>!r.ok);if(e.json)return process.stdout.write(JSON.stringify({ok:s.length===0,steps:n,vacuum:!!e.vacuum},null,2)+`
1707
+ `),s.length===0?0:1;for(let r of n){let o=r.ok?c.ok("\u2713"):c.err("\u2717"),i=`${r.durationMs} ms`;console.log(` ${o} ${r.step.padEnd(28)} ${c.dim(i)}`),r.error&&console.log(` ${c.err(r.error)}`)}return s.length===0?(console.log(""),console.log(c.ok("All maintenance passes completed.")),e.vacuum||console.log(c.dim(" Run `recall optimize --vacuum` (with the daemon stopped) to reclaim disk pages from deleted rows.")),0):(console.log(""),console.log(c.warn(`${s.length} step(s) failed \u2014 review the errors above.`)),1)}D();k();De();wi();var Sm=/^[A-Za-z_][A-Za-z0-9_]*$/;function H0(){let e=h();return{listTableNames(){return e.prepare("SELECT name FROM sqlite_master WHERE type = 'table'").all().map(t=>t.name)},countRows(t){if(!Sm.test(t))return 0;try{return e.prepare(`SELECT COUNT(*) AS n FROM "${t}"`).get().n}catch{return 0}},isRollbackWindowOpen(){try{return!!e.prepare("SELECT 1 AS x FROM migration_state WHERE status = 'completed' AND completed_at > datetime('now', '-30 days') ORDER BY id DESC LIMIT 1").get()}catch{return!1}},rollbackDaysRemaining(){try{let t=e.prepare("SELECT completed_at FROM migration_state WHERE status = 'completed' ORDER BY id DESC LIMIT 1").get();if(!t)return null;let n=e.prepare("SELECT CAST((julianday('now') - julianday(?)) AS INTEGER) AS days").get(t.completed_at);return Math.max(0,30-n.days)}catch{return null}},dropTable(t){if(!Sm.test(t))throw new Error(`unsafe identifier reached dropTable: ${t}`);e.exec(`DROP TABLE "${t}"`)},walCheckpointTruncate(){e.pragma("wal_checkpoint(TRUNCATE)")},vacuum(){e.exec("VACUUM")},integrityCheck(){let n=e.pragma("integrity_check")[0];if(!n)return"unknown";let s=Object.values(n)[0];return typeof s=="string"?s:String(s)}}}function ym(e){if(e.ok){console.log(c.ok(`\u2713 ${e.message}`));for(let t of e.steps)console.log(` ${c.ok("\u2713")} ${t.step.padEnd(12)} ${c.dim(`${t.durationMs} ms`)}`);console.log(""),console.log(c.dim(" Run `recall start` to bring the daemon back up."));return}console.error(c.err(`\u2717 ${e.message}`));for(let t of e.steps){let n=t.ok?c.ok("\u2713"):c.err("\u2717");console.error(` ${n} ${t.step.padEnd(12)} ${c.dim(`${t.durationMs} ms`)}`),t.error&&console.error(` ${c.err(t.error)}`)}e.reason==="integrity-check-failed"&&(console.error(""),console.error(c.warn(" ! The database may have been left in an inconsistent state. Restore from a")),console.error(c.warn(" backup (or re-run `recall doctor`) before starting the daemon again.")))}async function W0(e,t){if(!e)return t.json?process.stdout.write(JSON.stringify({ok:!1,error:"missing-table",message:"usage: recall db drop-table <name>"})+`
1708
+ `):(console.error(c.err("\u2717 usage: recall db drop-table <name>")),console.error(c.dim(" Run `recall doctor` to see which tables are reclaimable."))),2;if(se())return t.json?process.stdout.write(JSON.stringify({ok:!1,error:"daemon-running",message:"Stop the daemon first: `recall stop`, then re-run."})+`
1709
+ `):console.error(c.err("\u2717 The daemon is running. Stop it first: `recall stop`, then re-run this command.")),2;let s;try{s=H0()}catch(i){let a=i instanceof Error?i.message:String(i);return t.json?process.stdout.write(JSON.stringify({ok:!1,error:"exception",message:a})+`
1710
+ `):console.error(c.err(`\u2717 unexpected error opening the database: ${a}`)),1}if(!On(s).tables.filter(i=>i.safeToDropNow).map(i=>i.name).includes(e)){let i=yi(s,e);return t.json?process.stdout.write(JSON.stringify(i,null,2)+`
1711
+ `):ym(i),1}t.json||(console.log(c.warn("! This will DROP the table and VACUUM the database (rewrites the whole file).")),console.log(c.dim(" Do NOT interrupt it mid-VACUUM \u2014 an interrupted VACUUM can corrupt the DB.")),console.log(c.dim(" Integrity is verified afterwards; keep a backup if the DB is irreplaceable.")),console.log(""));let o;try{o=yi(s,e)}catch(i){let a=i instanceof Error?i.message:String(i);return t.json?process.stdout.write(JSON.stringify({ok:!1,error:"exception",message:a})+`
1712
+ `):console.error(c.err(`\u2717 unexpected error: ${a}`)),1}return t.json?(process.stdout.write(JSON.stringify(o,null,2)+`
1713
+ `),o.ok?0:1):(ym(o),o.ok?0:1)}async function wm(e={}){let t=e._action;return t==="drop-table"?W0(e._table,e):(console.error(c.err(`\u2717 unknown db action: ${t??"(none)"}`)),console.error(c.dim(" Available: recall db drop-table <name>")),2)}D();k();I();dn();import{copyFileSync as X0,existsSync as G0,readFileSync as J0}from"node:fs";import{join as Tm}from"node:path";function z0(){let e=Tm(C,"daemon.pid");if(!G0(e))return!1;try{let t=parseInt(J0(e,"utf-8").trim(),10);return!Number.isFinite(t)||t<=0?!1:(process.kill(t,0),!0)}catch{return!1}}function Y0(){let e=[];for(let t of Ut){let r=t.source.replace(/^\^/,"").replace(/\\d\+/g,"").match(/^([^.*+?{[(\\]+)/)?.[1]??"";r.length>=8&&e.push(r.replace(/'/g,"''"))}return e.length===0?"0":e.map(t=>`first_user_message LIKE '${t}%'`).join(" OR ")}async function Rm(e={}){if(z0()&&!e.dryRun){let p="Daemon is running. Run `recall stop`, then `recall purge-phantoms`, then `recall start`. The purge needs an exclusive write lock and the daemon would race it.";return e.json?(process.stdout.write(JSON.stringify({ok:!1,reason:"daemon-running",message:p},null,2)+`
1714
+ `),2):(console.error(c.err(`\u2717 ${p}`)),2)}let t=Y0();if(t==="0"){let p="No phantom patterns are registered \u2014 nothing to purge.";return e.json?(process.stdout.write(JSON.stringify({ok:!0,reason:"no-patterns",message:p})+`
1715
+ `),0):(console.log(c.warn(p)),0)}let n=h(),s=n.prepare(`SELECT COUNT(*) AS n FROM sessions WHERE ${t}`).get().n;if(s===0){let p="No phantom sessions found. Your DB is clean.";return e.json?(process.stdout.write(JSON.stringify({ok:!0,sessionsBefore:0,sessionsAfter:0,messagesDeleted:0,aliasesDeleted:0,patternsApplied:Ut.length,vacuumHint:!1,dryRun:!!e.dryRun},null,2)+`
1705
1716
  `),0):(console.log(c.ok(`\u2713 ${p}`)),0)}let r=n.prepare(`SELECT COUNT(*) AS n FROM messages WHERE session_id IN (SELECT id FROM sessions WHERE ${t})`).get().n,o=n.prepare(`SELECT COUNT(*) AS n FROM session_aliases WHERE session_id IN (SELECT id FROM sessions WHERE ${t})`).get().n;if(e.dryRun){let p={ok:!0,sessionsBefore:s,sessionsAfter:s,messagesDeleted:r,aliasesDeleted:o,patternsApplied:Ut.length,vacuumHint:!1,dryRun:!0};return e.json?(process.stdout.write(JSON.stringify(p,null,2)+`
1706
- `),0):(console.log(c.warn("\u2014 dry run, no changes \u2014")),console.log(` Phantoms found: ${c.dim(String(s))} sessions`),console.log(` Messages cascaded: ${c.dim(String(r))}`),console.log(` Aliases cascaded: ${c.dim(String(o))}`),console.log(c.dim(" Re-run without --dry-run to actually delete.")),0)}let i=um(C,"db.sqlite"),a=new Date().toISOString().replace(/[-:T]/g,"").replace(/\..+$/,"").slice(0,15),d=`${i}.pre-phantom-purge-${a}`;R0(i,d),n.pragma("foreign_keys = ON"),n.transaction(()=>{n.exec(`DELETE FROM sessions WHERE ${t}`)})();let u=n.prepare(`SELECT COUNT(*) AS n FROM sessions WHERE ${t}`).get().n,m={ok:u===0,backupPath:d,sessionsBefore:s,sessionsAfter:u,messagesDeleted:r,aliasesDeleted:o,patternsApplied:Ut.length,vacuumHint:s>100,dryRun:!1};return e.json?(process.stdout.write(JSON.stringify(m,null,2)+`
1707
- `),m.ok?0:1):(console.log(c.ok(`\u2713 Purged ${s} phantom session(s).`)),console.log(` Cascaded ${r} message(s) and ${o} alias row(s).`),console.log(` Backup: ${c.dim(d)}`),console.log(` Patterns applied: ${c.dim(String(Ut.length))}`),console.log(""),console.log(u===0?c.ok("All known phantom patterns are clear."):c.warn(`${u} phantom row(s) remain after purge \u2014 investigate.`)),m.vacuumHint&&(console.log(""),console.log(c.dim(" Reclaim the disk pages with `recall optimize --vacuum` (daemon must stay stopped)."))),console.log(c.dim(" Restart with `recall start` when ready.")),m.ok?0:1)}$();k();I();k();import{existsSync as A0}from"node:fs";import{join as N0}from"node:path";var pr=N0(C,"archive.sqlite");var mm=!1;function gm(){if(mm&&A0(pr))return;j();let e=E(),t=pr.replace(/'/g,"''");e.exec(`ATTACH DATABASE '${t}' AS archive`);try{e.exec(`
1717
+ `),0):(console.log(c.warn("\u2014 dry run, no changes \u2014")),console.log(` Phantoms found: ${c.dim(String(s))} sessions`),console.log(` Messages cascaded: ${c.dim(String(r))}`),console.log(` Aliases cascaded: ${c.dim(String(o))}`),console.log(c.dim(" Re-run without --dry-run to actually delete.")),0)}let i=Tm(C,"db.sqlite"),a=new Date().toISOString().replace(/[-:T]/g,"").replace(/\..+$/,"").slice(0,15),d=`${i}.pre-phantom-purge-${a}`;X0(i,d),n.pragma("foreign_keys = ON"),n.transaction(()=>{n.exec(`DELETE FROM sessions WHERE ${t}`)})();let u=n.prepare(`SELECT COUNT(*) AS n FROM sessions WHERE ${t}`).get().n,m={ok:u===0,backupPath:d,sessionsBefore:s,sessionsAfter:u,messagesDeleted:r,aliasesDeleted:o,patternsApplied:Ut.length,vacuumHint:s>100,dryRun:!1};return e.json?(process.stdout.write(JSON.stringify(m,null,2)+`
1718
+ `),m.ok?0:1):(console.log(c.ok(`\u2713 Purged ${s} phantom session(s).`)),console.log(` Cascaded ${r} message(s) and ${o} alias row(s).`),console.log(` Backup: ${c.dim(d)}`),console.log(` Patterns applied: ${c.dim(String(Ut.length))}`),console.log(""),console.log(u===0?c.ok("All known phantom patterns are clear."):c.warn(`${u} phantom row(s) remain after purge \u2014 investigate.`)),m.vacuumHint&&(console.log(""),console.log(c.dim(" Reclaim the disk pages with `recall optimize --vacuum` (daemon must stay stopped)."))),console.log(c.dim(" Restart with `recall start` when ready.")),m.ok?0:1)}D();k();I();k();import{existsSync as q0}from"node:fs";import{join as V0}from"node:path";var gr=V0(C,"archive.sqlite");var km=!1;function xm(){if(km&&q0(gr))return;j();let e=h(),t=gr.replace(/'/g,"''");e.exec(`ATTACH DATABASE '${t}' AS archive`);try{e.exec(`
1708
1719
  CREATE TABLE IF NOT EXISTS archive.messages_archive (
1709
1720
  uuid TEXT PRIMARY KEY,
1710
1721
  session_id TEXT NOT NULL,
@@ -1719,7 +1730,7 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1719
1730
  archived_at TEXT NOT NULL DEFAULT (datetime('now'))
1720
1731
  );
1721
1732
  CREATE INDEX IF NOT EXISTS archive.idx_messages_archive_session ON messages_archive(session_id);
1722
- `)}finally{e.exec("DETACH DATABASE archive")}mm=!0}import{existsSync as fm,mkdirSync as O0,readFileSync as v0,writeFileSync as I0}from"node:fs";import{homedir as M0}from"node:os";import{join as _m}from"node:path";import{z as mr}from"zod";function hm(){return process.env.RECALL_HOME??_m(M0(),".recall")}function D0(){let e=hm();fm(e)||O0(e,{recursive:!0})}function Em(){return _m(hm(),"config.json")}var bm=mr.object({autoArchiveEnabled:mr.boolean().default(!1),autoArchiveAfterDays:mr.number().int().min(7).max(3650).default(90),lastRunAt:mr.string().nullable().default(null)}),gr={autoArchiveEnabled:!1,autoArchiveAfterDays:90,lastRunAt:null};function Sm(){let e=Em();if(!fm(e))return{};try{return JSON.parse(v0(e,"utf8"))}catch(t){let n=t instanceof Error?t.message:String(t);return console.error(`[retention-config] failed to parse config.json: ${n}`),{}}}function ym(){let e=Sm().retention;if(!e)return{...gr};let t=bm.safeParse({...gr,...e});return t.success?t.data:{...gr}}function Xi(e){D0();let t=Sm(),n=bm.parse({...gr,...t.retention??{},...e}),s={...t,retention:n};return I0(Em(),JSON.stringify(s,null,2)),n}function Gi(e){gm();let t=E(),n=pr.replace(/'/g,"''");t.exec(`ATTACH DATABASE '${n}' AS archive`);try{return e(t)}finally{t.exec("DETACH DATABASE archive")}}function $0(){return Gi(e=>{let t=e.prepare(`SELECT
1733
+ `)}finally{e.exec("DETACH DATABASE archive")}km=!0}import{existsSync as Cm,mkdirSync as K0,readFileSync as Q0,writeFileSync as Z0}from"node:fs";import{homedir as ex}from"node:os";import{join as Am}from"node:path";import{z as fr}from"zod";function Lm(){return process.env.RECALL_HOME??Am(ex(),".recall")}function tx(){let e=Lm();Cm(e)||K0(e,{recursive:!0})}function Nm(){return Am(Lm(),"config.json")}var Om=fr.object({autoArchiveEnabled:fr.boolean().default(!1),autoArchiveAfterDays:fr.number().int().min(7).max(3650).default(90),lastRunAt:fr.string().nullable().default(null)}),_r={autoArchiveEnabled:!1,autoArchiveAfterDays:90,lastRunAt:null};function vm(){let e=Nm();if(!Cm(e))return{};try{return JSON.parse(Q0(e,"utf8"))}catch(t){let n=t instanceof Error?t.message:String(t);return console.error(`[retention-config] failed to parse config.json: ${n}`),{}}}function Im(){let e=vm().retention;if(!e)return{..._r};let t=Om.safeParse({..._r,...e});return t.success?t.data:{..._r}}function qi(e){tx();let t=vm(),n=Om.parse({..._r,...t.retention??{},...e}),s={...t,retention:n};return Z0(Nm(),JSON.stringify(s,null,2)),n}function Vi(e){xm();let t=h(),n=gr.replace(/'/g,"''");t.exec(`ATTACH DATABASE '${n}' AS archive`);try{return e(t)}finally{t.exec("DETACH DATABASE archive")}}function nx(){return Vi(e=>{let t=e.prepare(`SELECT
1723
1734
  SUM(CASE WHEN archive_status = 'archived' THEN 1 ELSE 0 END) AS archived,
1724
1735
  SUM(CASE WHEN archive_status != 'archived' THEN 1 ELSE 0 END) AS live
1725
1736
  FROM sessions`).get(),n=e.prepare("SELECT COUNT(*) AS n FROM messages").get().n,s=e.prepare(`SELECT
@@ -1728,15 +1739,15 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1728
1739
  SELECT MAX(timestamp) AS t FROM main.messages_archive WHERE timestamp IS NOT NULL
1729
1740
  UNION ALL
1730
1741
  SELECT MAX(timestamp) AS t FROM archive.messages_archive WHERE timestamp IS NOT NULL
1731
- )`).get();return{liveSessions:t.live??0,archivedSessions:t.archived??0,liveMessages:n,archivedMessages:s,oldestLiveTimestamp:r.t,newestArchivedTimestamp:o.t}})}function wm(e){return e?e.slice(0,10):"\u2014"}function P0(){let e=$0();return console.log(c.dim("\u2014 Archive state \u2014")),console.log(` Live sessions ${e.liveSessions.toLocaleString()}`),console.log(` Archived sessions ${e.archivedSessions.toLocaleString()}`),console.log(` Live messages ${e.liveMessages.toLocaleString()}`),console.log(` Archived messages ${e.archivedMessages.toLocaleString()}`),console.log(` Oldest live ${wm(e.oldestLiveTimestamp)}`),console.log(` Newest archived ${wm(e.newestArchivedTimestamp)}`),console.log(""),console.log(c.dim(" recall archive run --before YYYY-MM-DD")),console.log(c.dim(" recall archive restore <session-id>")),0}function F0(e){if(!/^\d{4}-\d{2}-\d{2}$/.test(e.before))return console.error("--before must be YYYY-MM-DD"),1;let n=E().prepare(`SELECT s.id, s.ended_at, s.message_count
1742
+ )`).get();return{liveSessions:t.live??0,archivedSessions:t.archived??0,liveMessages:n,archivedMessages:s,oldestLiveTimestamp:r.t,newestArchivedTimestamp:o.t}})}function Mm(e){return e?e.slice(0,10):"\u2014"}function sx(){let e=nx();return console.log(c.dim("\u2014 Archive state \u2014")),console.log(` Live sessions ${e.liveSessions.toLocaleString()}`),console.log(` Archived sessions ${e.archivedSessions.toLocaleString()}`),console.log(` Live messages ${e.liveMessages.toLocaleString()}`),console.log(` Archived messages ${e.archivedMessages.toLocaleString()}`),console.log(` Oldest live ${Mm(e.oldestLiveTimestamp)}`),console.log(` Newest archived ${Mm(e.newestArchivedTimestamp)}`),console.log(""),console.log(c.dim(" recall archive run --before YYYY-MM-DD")),console.log(c.dim(" recall archive restore <session-id>")),0}function rx(e){if(!/^\d{4}-\d{2}-\d{2}$/.test(e.before))return console.error("--before must be YYYY-MM-DD"),1;let n=h().prepare(`SELECT s.id, s.ended_at, s.message_count
1732
1743
  FROM sessions s
1733
1744
  WHERE s.archive_status != 'archived'
1734
- AND COALESCE(s.ended_at, s.started_at) < ?`).all(`${e.before}T00:00:00.000Z`);if(n.length===0)return console.log(`No sessions to archive (none older than ${e.before}).`),0;let s=n.reduce((a,d)=>a+(d.message_count??0),0);if(console.log(`${n.length.toLocaleString()} session(s), ${s.toLocaleString()} message(s) eligible.`),e.dryRun)return console.log(c.dim("Dry run \u2014 no rows moved. Re-run without --dry-run to apply.")),0;let r=n.map(a=>a.id),o=Date.now(),i=Gi(a=>a.transaction(l=>{let u=0,m=a.prepare(`INSERT OR IGNORE INTO archive.messages_archive
1745
+ AND COALESCE(s.ended_at, s.started_at) < ?`).all(`${e.before}T00:00:00.000Z`);if(n.length===0)return console.log(`No sessions to archive (none older than ${e.before}).`),0;let s=n.reduce((a,d)=>a+(d.message_count??0),0);if(console.log(`${n.length.toLocaleString()} session(s), ${s.toLocaleString()} message(s) eligible.`),e.dryRun)return console.log(c.dim("Dry run \u2014 no rows moved. Re-run without --dry-run to apply.")),0;let r=n.map(a=>a.id),o=Date.now(),i=Vi(a=>a.transaction(l=>{let u=0,m=a.prepare(`INSERT OR IGNORE INTO archive.messages_archive
1735
1746
  (uuid, session_id, parent_uuid, type, role, timestamp,
1736
1747
  is_sidechain, content_text, tool_names, raw_json, archived_at)
1737
1748
  SELECT uuid, session_id, parent_uuid, type, role, timestamp,
1738
1749
  is_sidechain, content_text, tool_names, raw_json, datetime('now')
1739
- FROM messages WHERE session_id = ?`),p=a.prepare("DELETE FROM messages WHERE session_id = ?"),g=a.prepare("UPDATE sessions SET archive_status = 'archived', archived_at = datetime('now') WHERE id = ?");for(let f of l){m.run(f);let h=p.run(f);u+=Number(h.changes??0),g.run(f)}return u})(r));return console.log(`Archived ${n.length.toLocaleString()} session(s), moved ${i.toLocaleString()} message(s) in ${Date.now()-o}ms.`),console.log(c.dim(" Run `recall optimize --vacuum` (with the daemon stopped) to reclaim disk pages from the moved rows.")),0}function j0(e){if(!e)return console.error("Usage: recall archive restore <session-id>"),1;let n=E().prepare("SELECT id, archive_status FROM sessions WHERE id = ?").get(e);if(!n)return console.error(`Session ${e} not found.`),1;if(n.archive_status!=="archived")return console.error(`Session ${e} is not archived (status=${n.archive_status}).`),1;let s=Gi(r=>r.transaction(()=>{let i=r.prepare(`INSERT OR IGNORE INTO messages
1750
+ FROM messages WHERE session_id = ?`),p=a.prepare("DELETE FROM messages WHERE session_id = ?"),g=a.prepare("UPDATE sessions SET archive_status = 'archived', archived_at = datetime('now') WHERE id = ?");for(let f of l){m.run(f);let _=p.run(f);u+=Number(_.changes??0),g.run(f)}return u})(r));return console.log(`Archived ${n.length.toLocaleString()} session(s), moved ${i.toLocaleString()} message(s) in ${Date.now()-o}ms.`),console.log(c.dim(" Run `recall optimize --vacuum` (with the daemon stopped) to reclaim disk pages from the moved rows.")),0}function ox(e){if(!e)return console.error("Usage: recall archive restore <session-id>"),1;let n=h().prepare("SELECT id, archive_status FROM sessions WHERE id = ?").get(e);if(!n)return console.error(`Session ${e} not found.`),1;if(n.archive_status!=="archived")return console.error(`Session ${e} is not archived (status=${n.archive_status}).`),1;let s=Vi(r=>r.transaction(()=>{let i=r.prepare(`INSERT OR IGNORE INTO messages
1740
1751
  (uuid, session_id, parent_uuid, type, role, timestamp,
1741
1752
  is_sidechain, content_text, tool_names, raw_json)
1742
1753
  SELECT uuid, session_id, parent_uuid, type, role, timestamp,
@@ -1746,33 +1757,33 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1746
1757
  is_sidechain, content_text, tool_names, raw_json)
1747
1758
  SELECT uuid, session_id, parent_uuid, type, role, timestamp,
1748
1759
  is_sidechain, content_text, tool_names, raw_json
1749
- FROM archive.messages_archive WHERE session_id = ?`),d=r.prepare("DELETE FROM main.messages_archive WHERE session_id = ?"),l=r.prepare("DELETE FROM archive.messages_archive WHERE session_id = ?"),u=Number(i.run(e).changes??0),m=Number(a.run(e).changes??0);return d.run(e),l.run(e),r.prepare("UPDATE sessions SET archive_status = 'live', archived_at = NULL WHERE id = ?").run(e),u+m})());return console.log(`Restored ${s.toLocaleString()} message(s) for session ${e}.`),0}function U0(){let e=ym();return console.log(c.dim("\u2014 Auto-archive \u2014")),console.log(` Enabled ${e.autoArchiveEnabled?c.ok("YES"):"no"}`),console.log(` After ${e.autoArchiveAfterDays} days`),console.log(` Last run ${e.lastRunAt??"\u2014"}`),0}function B0(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 n=Xi({autoArchiveEnabled:!0,autoArchiveAfterDays:t});return console.log(`Auto-archive: ENABLED (after ${n.autoArchiveAfterDays} days).`),console.log(c.dim(" The daemon will run a daily archive pass on the next tick.")),0}function H0(){return Xi({autoArchiveEnabled:!1}),console.log("Auto-archive: DISABLED. Existing archived sessions stay archived."),0}async function Tm(e){let t=e._action??"list";if(t==="list"||t==="stats")return P0();if(t==="run")return e.before?F0({before:e.before,dryRun:e.dryRun===!0}):(console.error("Usage: recall archive run --before YYYY-MM-DD [--dry-run]"),1);if(t==="restore")return j0(e._sessionId??"");if(t==="auto"){let n=e._subAction??"status";return n==="status"?U0():n==="on"||n==="enable"?B0(e.after):n==="off"||n==="disable"?H0():(console.error("Usage: recall archive auto <status|on|off> [--after <days>]"),1)}return console.error(`Usage: recall archive <list|run|restore|auto> [args]
1760
+ FROM archive.messages_archive WHERE session_id = ?`),d=r.prepare("DELETE FROM main.messages_archive WHERE session_id = ?"),l=r.prepare("DELETE FROM archive.messages_archive WHERE session_id = ?"),u=Number(i.run(e).changes??0),m=Number(a.run(e).changes??0);return d.run(e),l.run(e),r.prepare("UPDATE sessions SET archive_status = 'live', archived_at = NULL WHERE id = ?").run(e),u+m})());return console.log(`Restored ${s.toLocaleString()} message(s) for session ${e}.`),0}function ix(){let e=Im();return console.log(c.dim("\u2014 Auto-archive \u2014")),console.log(` Enabled ${e.autoArchiveEnabled?c.ok("YES"):"no"}`),console.log(` After ${e.autoArchiveAfterDays} days`),console.log(` Last run ${e.lastRunAt??"\u2014"}`),0}function ax(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 n=qi({autoArchiveEnabled:!0,autoArchiveAfterDays:t});return console.log(`Auto-archive: ENABLED (after ${n.autoArchiveAfterDays} days).`),console.log(c.dim(" The daemon will run a daily archive pass on the next tick.")),0}function cx(){return qi({autoArchiveEnabled:!1}),console.log("Auto-archive: DISABLED. Existing archived sessions stay archived."),0}async function Dm(e){let t=e._action??"list";if(t==="list"||t==="stats")return sx();if(t==="run")return e.before?rx({before:e.before,dryRun:e.dryRun===!0}):(console.error("Usage: recall archive run --before YYYY-MM-DD [--dry-run]"),1);if(t==="restore")return ox(e._sessionId??"");if(t==="auto"){let n=e._subAction??"status";return n==="status"?ix():n==="on"||n==="enable"?ax(e.after):n==="off"||n==="disable"?cx():(console.error("Usage: recall archive auto <status|on|off> [--after <days>]"),1)}return console.error(`Usage: recall archive <list|run|restore|auto> [args]
1750
1761
  list \u2014 show archive counts
1751
1762
  run --before YYYY-MM-DD [--dry-run] \u2014 move sessions older than DATE
1752
1763
  restore <session-id> \u2014 pull a session back from archive
1753
- auto <status|on|off> [--after N] \u2014 daemon auto-archives sessions older than N days`),1}$();k();I();import{existsSync as W0,readFileSync as X0}from"node:fs";function G0(){let e=`${C}/daemon.port`;if(!W0(e))return null;try{let t=X0(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}function z0(e){let t=E();if(e.length>=32){let s=t.prepare("SELECT id FROM sessions WHERE id = ?").get(e);return s?s.id:(process.stderr.write(`session not found: ${e}
1764
+ auto <status|on|off> [--after N] \u2014 daemon auto-archives sessions older than N days`),1}D();k();I();import{existsSync as lx,readFileSync as dx}from"node:fs";function ux(){let e=`${C}/daemon.port`;if(!lx(e))return null;try{let t=dx(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}function px(e){let t=h();if(e.length>=32){let s=t.prepare("SELECT id FROM sessions WHERE id = ?").get(e);return s?s.id:(process.stderr.write(`session not found: ${e}
1754
1765
  `),null)}let n=t.prepare("SELECT id FROM sessions WHERE id LIKE ? LIMIT 2").all(e+"%");return n.length===1?n[0].id:n.length===0?(process.stderr.write(`no session matches prefix "${e}"
1755
1766
  `),null):(process.stderr.write(`ambiguous session prefix "${e}". be more specific.
1756
- `),null)}async function Rm(e,t,n){let s=z0(e);if(!s){process.exitCode=1;return}let r=t.trim();if(!r){process.stderr.write(`name cannot be empty
1757
- `),process.exitCode=1;return}let o=G0();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 ut("PUT",`http://127.0.0.1:${o}/api/sessions/${encodeURIComponent(s)}/alias`,{alias:r,pin:n.pin===!0})}catch(d){process.stderr.write(`failed to reach daemon at 127.0.0.1:${o}: ${d.message}
1767
+ `),null)}async function $m(e,t,n){let s=px(e);if(!s){process.exitCode=1;return}let r=t.trim();if(!r){process.stderr.write(`name cannot be empty
1768
+ `),process.exitCode=1;return}let o=ux();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 ut("PUT",`http://127.0.0.1:${o}/api/sessions/${encodeURIComponent(s)}/alias`,{alias:r,pin:n.pin===!0})}catch(d){process.stderr.write(`failed to reach daemon at 127.0.0.1:${o}: ${d.message}
1758
1769
  `),process.exitCode=1;return}if(!i.ok){let d="";try{d=await i.text()}catch{}process.stderr.write(`daemon rejected alias write (HTTP ${i.status}): ${d}
1759
- `),process.exitCode=1;return}let a={session_id:s,alias:r};if(n.json){console.log(JSON.stringify(a));return}console.log(`${c.ok("renamed")} ${c.dim(s.slice(0,8))} \u2192 ${c.bold(`"${r}"`)}`)}$();k();import{join as J0}from"node:path";import{existsSync as Y0,readFileSync as q0}from"node:fs";I();var Cm=90;async function V0(){try{let e=J0(C,"daemon.port");if(!Y0(e))return null;let t=q0(e,"utf8").trim(),n=await nt(`http://127.0.0.1:${t}/api/terminal/registry`);return n.ok?await n.json():null}catch{return null}}function K0(){let e=Date.now()/1e3-Cm;return E().prepare(`SELECT s.id, s.cwd, s.file_mtime, NULLIF(sa.alias, '') AS alias
1770
+ `),process.exitCode=1;return}let a={session_id:s,alias:r};if(n.json){console.log(JSON.stringify(a));return}console.log(`${c.ok("renamed")} ${c.dim(s.slice(0,8))} \u2192 ${c.bold(`"${r}"`)}`)}D();k();import{join as mx}from"node:path";import{existsSync as gx,readFileSync as fx}from"node:fs";I();var jm=90;async function _x(){try{let e=mx(C,"daemon.port");if(!gx(e))return null;let t=fx(e,"utf8").trim(),n=await nt(`http://127.0.0.1:${t}/api/terminal/registry`);return n.ok?await n.json():null}catch{return null}}function hx(){let e=Date.now()/1e3-jm;return h().prepare(`SELECT s.id, s.cwd, s.file_mtime, NULLIF(sa.alias, '') AS alias
1760
1771
  FROM sessions s
1761
1772
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1762
1773
  WHERE s.cwd IS NOT NULL AND s.file_mtime > ?
1763
- ORDER BY s.cwd, s.file_mtime DESC`).all(e)}var Q0=new Set(["zsh","bash","fish","sh","dash","ksh","tcsh","csh","pwsh","powershell","cmd","nu"]);function km(e){let t=e.trim().toLowerCase().replace(/^[-/]+/,"").replace(/^.*\//,"").replace(/\s*\(\d+\)\s*$/,"").trim();return!t||Q0.has(t)}var Z0=/^[⠀-⣿✳\s]+/,ex=/^\d+(\.\d+){1,3}$/;function xm(e){let t=e.trim();return!!(!t||Z0.test(t)||ex.test(t))}async function Lm(e){let t=await V0(),n=K0();if(e.json){console.log(JSON.stringify({registry:t,active:n},null,2));return}if(console.log(),console.log(c.bold("TERMINAL REGISTRY")),console.log(c.dim("(what the daemon thinks each VS Code terminal is named)")),console.log(),!t){console.log(c.err(" Could not reach daemon. Is recall start running?"));return}let s=new Map;for(let o of t.terminals){let i=o.cwd??"(no cwd)",a=s.get(i);a||(a=[],s.set(i,a)),a.push(o)}for(let[o,i]of s){console.log(c.dim(` cwd: ${o}`));for(let a of i){let d=km(a.tab_name),l=xm(a.tab_name),m=!d&&!l?c.ok("[usable]"):d?c.warn("[generic-shell]"):c.warn("[claude-auto]");console.log(` ${m} pid ${a.shell_pid} ${c.bold(`"${a.tab_name}"`)}`)}console.log()}if(console.log(c.bold(`ACTIVE SESSIONS (mtime within last ${Cm}s)`)),console.log(c.dim("(sessions whose JSONL is being actively written)")),console.log(),n.length===0){console.log(c.dim(" (none)")),console.log();return}let r=new Map;for(let o of n){let i=r.get(o.cwd);i||(i=[],r.set(o.cwd,i)),i.push(o)}for(let[o,i]of r){console.log(c.dim(` cwd: ${o}`));for(let a of i)console.log(` ${c.dim(a.id.slice(0,8))} ${c.bold(a.alias??"(no alias)")} ${c.dim(`mtime ${new Date(a.file_mtime*1e3).toISOString().slice(11,19)}`)}`);console.log()}console.log(c.bold("LAYER 5 SWEEP DECISIONS")),console.log(c.dim("(what the live correlator would do for each cwd right now)")),console.log();for(let[o,i]of r){let d=(s.get(o)??[]).filter(l=>!km(l.tab_name)&&!xm(l.tab_name));d.length===0?console.log(` ${c.warn("skip")} ${c.dim(o)} ${c.dim("\u2014 no usable terminal name (all generic or claude-auto)")}`):d.length>1?console.log(` ${c.warn("refuse")} ${c.dim(o)} ${c.dim(`\u2014 ${d.length} usable terminals, ambiguous`)}`):i.length>1?console.log(` ${c.warn("refuse")} ${c.dim(o)} ${c.dim(`\u2014 ${i.length} active sessions, ambiguous`)}`):console.log(` ${c.ok("link")} ${c.dim(o)} ${c.dim("\u2192")} ${c.dim(i[0].id.slice(0,8))} ${c.dim("=")} ${c.bold(`"${d[0].tab_name}"`)}`)}console.log()}$();k();I();import{existsSync as tx,readFileSync as nx}from"node:fs";function sx(){let e=`${C}/daemon.port`;if(!tx(e))return null;try{let t=nx(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function rx(e){try{let t=await nt(`http://127.0.0.1:${e}/api/terminal/registry`);return t.ok?(await t.json()).terminals??[]:[]}catch{return[]}}async function ox(e,t,n){try{return(await ut("POST",`http://127.0.0.1:${e}/api/sessions/${encodeURIComponent(t)}/relink`,{shell_pid:n})).ok}catch{return!1}}function ix(e){try{let t=JSON.parse(e);if(!Array.isArray(t))return null;for(let n=t.length-1;n>=0;n--){let s=t[n];if(s&&typeof s.alias=="string"&&s.alias!=="")return s.alias}return null}catch{return null}}function ax(e){let t=new Map;for(let i of e){if(!i.cwd)continue;let a=i.cwd.replace(/\/+$/,""),d=t.get(a);d||(d=new Map,t.set(a,d)),d.set(i.tab_name,i.shell_pid)}let n=new Map;for(let i of e){if(!i.cwd)continue;let d=`${i.cwd.replace(/\/+$/,"")}::${i.tab_name}`,l=n.get(d);l||(l=new Set,n.set(d,l)),l.add(String(i.shell_pid))}let r=E().prepare(`SELECT sa.session_id, s.cwd, sa.previous_aliases
1774
+ ORDER BY s.cwd, s.file_mtime DESC`).all(e)}var Ex=new Set(["zsh","bash","fish","sh","dash","ksh","tcsh","csh","pwsh","powershell","cmd","nu"]);function Pm(e){let t=e.trim().toLowerCase().replace(/^[-/]+/,"").replace(/^.*\//,"").replace(/\s*\(\d+\)\s*$/,"").trim();return!t||Ex.has(t)}var bx=/^[⠀-⣿✳\s]+/,Sx=/^\d+(\.\d+){1,3}$/;function Fm(e){let t=e.trim();return!!(!t||bx.test(t)||Sx.test(t))}async function Um(e){let t=await _x(),n=hx();if(e.json){console.log(JSON.stringify({registry:t,active:n},null,2));return}if(console.log(),console.log(c.bold("TERMINAL REGISTRY")),console.log(c.dim("(what the daemon thinks each VS Code terminal is named)")),console.log(),!t){console.log(c.err(" Could not reach daemon. Is recall start running?"));return}let s=new Map;for(let o of t.terminals){let i=o.cwd??"(no cwd)",a=s.get(i);a||(a=[],s.set(i,a)),a.push(o)}for(let[o,i]of s){console.log(c.dim(` cwd: ${o}`));for(let a of i){let d=Pm(a.tab_name),l=Fm(a.tab_name),m=!d&&!l?c.ok("[usable]"):d?c.warn("[generic-shell]"):c.warn("[claude-auto]");console.log(` ${m} pid ${a.shell_pid} ${c.bold(`"${a.tab_name}"`)}`)}console.log()}if(console.log(c.bold(`ACTIVE SESSIONS (mtime within last ${jm}s)`)),console.log(c.dim("(sessions whose JSONL is being actively written)")),console.log(),n.length===0){console.log(c.dim(" (none)")),console.log();return}let r=new Map;for(let o of n){let i=r.get(o.cwd);i||(i=[],r.set(o.cwd,i)),i.push(o)}for(let[o,i]of r){console.log(c.dim(` cwd: ${o}`));for(let a of i)console.log(` ${c.dim(a.id.slice(0,8))} ${c.bold(a.alias??"(no alias)")} ${c.dim(`mtime ${new Date(a.file_mtime*1e3).toISOString().slice(11,19)}`)}`);console.log()}console.log(c.bold("LAYER 5 SWEEP DECISIONS")),console.log(c.dim("(what the live correlator would do for each cwd right now)")),console.log();for(let[o,i]of r){let d=(s.get(o)??[]).filter(l=>!Pm(l.tab_name)&&!Fm(l.tab_name));d.length===0?console.log(` ${c.warn("skip")} ${c.dim(o)} ${c.dim("\u2014 no usable terminal name (all generic or claude-auto)")}`):d.length>1?console.log(` ${c.warn("refuse")} ${c.dim(o)} ${c.dim(`\u2014 ${d.length} usable terminals, ambiguous`)}`):i.length>1?console.log(` ${c.warn("refuse")} ${c.dim(o)} ${c.dim(`\u2014 ${i.length} active sessions, ambiguous`)}`):console.log(` ${c.ok("link")} ${c.dim(o)} ${c.dim("\u2192")} ${c.dim(i[0].id.slice(0,8))} ${c.dim("=")} ${c.bold(`"${d[0].tab_name}"`)}`)}console.log()}D();k();I();import{existsSync as yx,readFileSync as wx}from"node:fs";function Tx(){let e=`${C}/daemon.port`;if(!yx(e))return null;try{let t=wx(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function Rx(e){try{let t=await nt(`http://127.0.0.1:${e}/api/terminal/registry`);return t.ok?(await t.json()).terminals??[]:[]}catch{return[]}}async function kx(e,t,n){try{return(await ut("POST",`http://127.0.0.1:${e}/api/sessions/${encodeURIComponent(t)}/relink`,{shell_pid:n})).ok}catch{return!1}}function xx(e){try{let t=JSON.parse(e);if(!Array.isArray(t))return null;for(let n=t.length-1;n>=0;n--){let s=t[n];if(s&&typeof s.alias=="string"&&s.alias!=="")return s.alias}return null}catch{return null}}function Cx(e){let t=new Map;for(let i of e){if(!i.cwd)continue;let a=i.cwd.replace(/\/+$/,""),d=t.get(a);d||(d=new Map,t.set(a,d)),d.set(i.tab_name,i.shell_pid)}let n=new Map;for(let i of e){if(!i.cwd)continue;let d=`${i.cwd.replace(/\/+$/,"")}::${i.tab_name}`,l=n.get(d);l||(l=new Set,n.set(d,l)),l.add(String(i.shell_pid))}let r=h().prepare(`SELECT sa.session_id, s.cwd, sa.previous_aliases
1764
1775
  FROM session_aliases sa
1765
1776
  JOIN sessions s ON s.id = sa.session_id
1766
- WHERE sa.alias = '' AND sa.previous_aliases != '[]' AND s.cwd IS NOT NULL`).all(),o=[];for(let i of r){let a=ix(i.previous_aliases);if(!a)continue;let d=i.cwd.replace(/\/+$/,""),u=t.get(d)?.get(a);if(!u)continue;let m=n.get(`${d}::${a}`);m&&m.size>1||o.push({session_id:i.session_id,cwd:d,alias_to_restore:a,matching_pid:u})}return o}async function Am(e){let t=sx();t||(console.error(c.err("Daemon is not running. Run `recall start` first.")),process.exit(1));let n=await rx(t);n.length===0&&(console.error(c.err("Registry is empty. Open VS Code with the extension to populate it.")),process.exit(1));let s=ax(n);if(e.json){console.log(JSON.stringify({candidates:s},null,2));return}if(s.length===0){console.log(c.dim("No restorable sessions found.")),console.log(c.dim("A session is restorable when its previous alias still matches a currently-open terminal in the same cwd, with no name collisions."));return}console.log(c.bold(`Found ${s.length} session${s.length===1?"":"s"} that can be cleanly restored:`)),console.log();let r=new Map;for(let a of s){let d=r.get(a.cwd);d||(d=[],r.set(a.cwd,d)),d.push(a)}for(let[a,d]of r){console.log(c.dim(` cwd: ${a}`));for(let l of d)console.log(` ${c.dim(l.session_id.slice(0,8))} ${c.dim("\u2192 pid")} ${l.matching_pid} ${c.dim("=")} ${c.bold(`"${l.alias_to_restore}"`)}`);console.log()}if(!e.apply){console.log(c.dim("Re-run with --apply to restore these aliases."));return}let o=0,i=0;for(let a of s)await ox(t,a.session_id,a.matching_pid)?o++:(i++,console.error(c.err(`failed to restore ${a.session_id.slice(0,8)}`)));console.log(c.ok(`Restored ${o} alias${o===1?"":"es"}.${i>0?` ${i} failed.`:""}`)),console.log(c.dim("Sessions whose previous alias did not cleanly match a current terminal still need manual relink via the \u{1F517} picker."))}$();Nn();async function Nm(e,t){let n=e.trim();if(!/^[0-9a-fA-F]{4,40}$/.test(n)){console.error(c.err(`not a valid commit SHA: '${e}'`)),process.exit(1);return}let s=Vs(n);if(t.json){console.log(JSON.stringify(s,null,2));return}if(s.length===0){console.log(""),console.log(c.dim(`no correlated sessions for ${n}`)),console.log(c.dim(" (if you haven't yet, run `recall correlate` to backfill)")),console.log("");return}console.log(""),console.log(`${c.bold("commit")} ${c.accent(s[0].commitSha.slice(0,12))} ${c.dim(s[0].committedAt??"")}`),s[0].subject&&console.log(` ${s[0].subject}`),console.log(""),console.log(c.dim(`authored during ${s.length} session${s.length===1?"":"s"}:`));for(let r of s){let o=r.alias??r.sessionId.slice(0,8);console.log(` ${c.accent(o.padEnd(24))} ${c.dim((r.project??"").slice(0,24).padEnd(26))} ${c.dim(r.startedAt??"")}`),console.log(` ${c.dim(`recall show ${r.sessionId}`)}`)}console.log("")}$();k();import{execFile as cx}from"node:child_process";import{promisify as lx}from"node:util";import{stat as dx}from"node:fs/promises";Nn();var ux=lx(cx),px=60,mx=7,gx=7,fx=5e3;function _x(){let e=E(),t=n=>{try{return!!e.prepare(n).get()}catch{return!1}};return{semantic:t("SELECT 1 FROM session_semantic LIMIT 1"),cost:t(`SELECT 1 FROM sessions
1777
+ WHERE sa.alias = '' AND sa.previous_aliases != '[]' AND s.cwd IS NOT NULL`).all(),o=[];for(let i of r){let a=xx(i.previous_aliases);if(!a)continue;let d=i.cwd.replace(/\/+$/,""),u=t.get(d)?.get(a);if(!u)continue;let m=n.get(`${d}::${a}`);m&&m.size>1||o.push({session_id:i.session_id,cwd:d,alias_to_restore:a,matching_pid:u})}return o}async function Bm(e){let t=Tx();t||(console.error(c.err("Daemon is not running. Run `recall start` first.")),process.exit(1));let n=await Rx(t);n.length===0&&(console.error(c.err("Registry is empty. Open VS Code with the extension to populate it.")),process.exit(1));let s=Cx(n);if(e.json){console.log(JSON.stringify({candidates:s},null,2));return}if(s.length===0){console.log(c.dim("No restorable sessions found.")),console.log(c.dim("A session is restorable when its previous alias still matches a currently-open terminal in the same cwd, with no name collisions."));return}console.log(c.bold(`Found ${s.length} session${s.length===1?"":"s"} that can be cleanly restored:`)),console.log();let r=new Map;for(let a of s){let d=r.get(a.cwd);d||(d=[],r.set(a.cwd,d)),d.push(a)}for(let[a,d]of r){console.log(c.dim(` cwd: ${a}`));for(let l of d)console.log(` ${c.dim(l.session_id.slice(0,8))} ${c.dim("\u2192 pid")} ${l.matching_pid} ${c.dim("=")} ${c.bold(`"${l.alias_to_restore}"`)}`);console.log()}if(!e.apply){console.log(c.dim("Re-run with --apply to restore these aliases."));return}let o=0,i=0;for(let a of s)await kx(t,a.session_id,a.matching_pid)?o++:(i++,console.error(c.err(`failed to restore ${a.session_id.slice(0,8)}`)));console.log(c.ok(`Restored ${o} alias${o===1?"":"es"}.${i>0?` ${i} failed.`:""}`)),console.log(c.dim("Sessions whose previous alias did not cleanly match a current terminal still need manual relink via the \u{1F517} picker."))}D();Nn();async function Hm(e,t){let n=e.trim();if(!/^[0-9a-fA-F]{4,40}$/.test(n)){console.error(c.err(`not a valid commit SHA: '${e}'`)),process.exit(1);return}let s=Ks(n);if(t.json){console.log(JSON.stringify(s,null,2));return}if(s.length===0){console.log(""),console.log(c.dim(`no correlated sessions for ${n}`)),console.log(c.dim(" (if you haven't yet, run `recall correlate` to backfill)")),console.log("");return}console.log(""),console.log(`${c.bold("commit")} ${c.accent(s[0].commitSha.slice(0,12))} ${c.dim(s[0].committedAt??"")}`),s[0].subject&&console.log(` ${s[0].subject}`),console.log(""),console.log(c.dim(`authored during ${s.length} session${s.length===1?"":"s"}:`));for(let r of s){let o=r.alias??r.sessionId.slice(0,8);console.log(` ${c.accent(o.padEnd(24))} ${c.dim((r.project??"").slice(0,24).padEnd(26))} ${c.dim(r.startedAt??"")}`),console.log(` ${c.dim(`recall show ${r.sessionId}`)}`)}console.log("")}D();k();import{execFile as Ax}from"node:child_process";import{promisify as Lx}from"node:util";import{stat as Nx}from"node:fs/promises";Nn();var Ox=Lx(Ax),vx=60,Ix=7,Mx=7,Dx=5e3;function $x(){let e=h(),t=n=>{try{return!!e.prepare(n).get()}catch{return!1}};return{semantic:t("SELECT 1 FROM session_semantic LIMIT 1"),cost:t(`SELECT 1 FROM sessions
1767
1778
  WHERE (COALESCE(total_input_tokens,0)
1768
1779
  + COALESCE(total_output_tokens,0)
1769
1780
  + COALESCE(total_cache_create_tokens,0)
1770
1781
  + COALESCE(total_cache_read_tokens,0)) > 0
1771
- LIMIT 1`),git:t("SELECT 1 FROM session_commits LIMIT 1")}}function zi(e){if(!e)return[];let t=new Set,n=[];for(let s of e.split(",")){let r=s.trim().toLowerCase();!r||t.has(r)||(t.add(r),n.push(r))}return n}function Om(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 hx(){let e=E(),t=e.prepare(`SELECT ss.keywords
1782
+ LIMIT 1`),git:t("SELECT 1 FROM session_commits LIMIT 1")}}function Ki(e){if(!e)return[];let t=new Set,n=[];for(let s of e.split(",")){let r=s.trim().toLowerCase();!r||t.has(r)||(t.add(r),n.push(r))}return n}function Wm(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 Px(){let e=h(),t=e.prepare(`SELECT ss.keywords
1772
1783
  FROM session_semantic ss
1773
1784
  JOIN sessions s ON s.id = ss.session_id
1774
1785
  WHERE s.started_at IS NOT NULL
1775
- AND julianday('now') - julianday(s.started_at) <= @windowDays`).all({windowDays:mx});if(t.length===0)return null;let n=new Set;for(let o of t)for(let i of zi(o.keywords))n.add(i);if(n.size===0)return null;let s=e.prepare(`SELECT ss.session_id AS session_id,
1786
+ AND julianday('now') - julianday(s.started_at) <= @windowDays`).all({windowDays:Ix});if(t.length===0)return null;let n=new Set;for(let o of t)for(let i of Ki(o.keywords))n.add(i);if(n.size===0)return null;let s=e.prepare(`SELECT ss.session_id AS session_id,
1776
1787
  ss.summary AS summary,
1777
1788
  ss.keywords AS keywords,
1778
1789
  p.name AS project,
@@ -1788,7 +1799,7 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1788
1799
  WHERE s.started_at IS NOT NULL
1789
1800
  AND s.message_count > 2
1790
1801
  AND julianday('now') - julianday(s.started_at) >= @ageDays
1791
- ORDER BY s.started_at ASC`).all({ageDays:px});if(s.length===0)return null;let r=null;for(let o of s){let a=zi(o.keywords).filter(d=>n.has(d));a.length!==0&&(!r||a.length>r.overlap.length)&&(r={row:o,overlap:a})}return r?{...Om(r.row),summary:r.row.summary,keywords:zi(r.row.keywords),matchedKeywords:r.overlap,daysAgo:Math.max(0,Math.round(r.row.days_old))}:null}function Ex(){let t=E().prepare(`SELECT s.id AS session_id,
1802
+ ORDER BY s.started_at ASC`).all({ageDays:vx});if(s.length===0)return null;let r=null;for(let o of s){let a=Ki(o.keywords).filter(d=>n.has(d));a.length!==0&&(!r||a.length>r.overlap.length)&&(r={row:o,overlap:a})}return r?{...Wm(r.row),summary:r.row.summary,keywords:Ki(r.row.keywords),matchedKeywords:r.overlap,daysAgo:Math.max(0,Math.round(r.row.days_old))}:null}function Fx(){let t=h().prepare(`SELECT s.id AS session_id,
1792
1803
  p.name AS project,
1793
1804
  NULLIF(sa.alias, '') AS alias,
1794
1805
  s.started_at AS started_at,
@@ -1807,54 +1818,54 @@ Top ${d.length} cluster(s):`);for(let l of d){let u=l.status==="resolved"?"\u271
1807
1818
  AND (COALESCE(s.total_input_tokens, 0)
1808
1819
  + COALESCE(s.total_output_tokens, 0)
1809
1820
  + COALESCE(s.total_cache_create_tokens, 0)
1810
- + COALESCE(s.total_cache_read_tokens, 0)) > 0`).all({windowDays:gx});if(t.length===0)return null;let n=null;for(let s of t){let r=Fe({inputTokens:s.input_tokens,outputTokens:s.output_tokens,cacheCreateTokens:s.cache_create_tokens,cacheReadTokens:s.cache_read_tokens},s.primary_model);r.cents<=0||(!n||r.cents>n.cents)&&(n={row:s,cents:r.cents,totalTokens:r.totalTokens})}return n?{...Om(n.row),totalTokens:n.totalTokens,costCents:n.cents,costDisplay:le(n.cents),tokensDisplay:he(n.totalTokens),primaryModel:n.row.primary_model,primaryModelLabel:_t(n.row.primary_model).label}:null}async function bx(e){try{if(!(await dx(e)).isDirectory())return null}catch{return null}try{let{stdout:t}=await ux("git",["rev-parse","HEAD"],{cwd:e,timeout:fx}),n=t.trim();return/^[0-9a-f]{40}$/.test(n)?n:null}catch{return null}}async function Sx(){let e=E(),t=e.prepare(`SELECT s.id AS id, s.cwd AS cwd
1821
+ + COALESCE(s.total_cache_read_tokens, 0)) > 0`).all({windowDays:Mx});if(t.length===0)return null;let n=null;for(let s of t){let r=je({inputTokens:s.input_tokens,outputTokens:s.output_tokens,cacheCreateTokens:s.cache_create_tokens,cacheReadTokens:s.cache_read_tokens},s.primary_model);r.cents<=0||(!n||r.cents>n.cents)&&(n={row:s,cents:r.cents,totalTokens:r.totalTokens})}return n?{...Wm(n.row),totalTokens:n.totalTokens,costCents:n.cents,costDisplay:le(n.cents),tokensDisplay:he(n.totalTokens),primaryModel:n.row.primary_model,primaryModelLabel:_t(n.row.primary_model).label}:null}async function jx(e){try{if(!(await Nx(e)).isDirectory())return null}catch{return null}try{let{stdout:t}=await Ox("git",["rev-parse","HEAD"],{cwd:e,timeout:Dx}),n=t.trim();return/^[0-9a-f]{40}$/.test(n)?n:null}catch{return null}}async function Ux(){let e=h(),t=e.prepare(`SELECT s.id AS id, s.cwd AS cwd
1811
1822
  FROM sessions s
1812
1823
  WHERE s.cwd IS NOT NULL AND s.started_at IS NOT NULL
1813
1824
  ORDER BY COALESCE(s.ended_at, s.started_at, '') DESC
1814
- LIMIT 1`).get();if(!t?.cwd)return null;let n=await bx(t.cwd);if(!n)return null;let s=Vs(n);if(s.length===0)return null;let r=s[0],o=e.prepare(`SELECT s.first_user_message AS first_user_message, s.ended_at AS ended_at
1825
+ LIMIT 1`).get();if(!t?.cwd)return null;let n=await jx(t.cwd);if(!n)return null;let s=Ks(n);if(s.length===0)return null;let r=s[0],o=e.prepare(`SELECT s.first_user_message AS first_user_message, s.ended_at AS ended_at
1815
1826
  FROM sessions s
1816
- 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 vm(){let e=_x(),t=e.semantic?Promise.resolve().then(()=>{try{return hx()}catch(a){return console.error("[discover.rediscovered]",a),null}}):Promise.resolve(null),n=e.cost?Promise.resolve().then(()=>{try{return Ex()}catch(a){return console.error("[discover.expensive]",a),null}}):Promise.resolve(null),s=e.git?Sx().catch(a=>(console.error("[discover.authored]",a),null)):Promise.resolve(null),[r,o,i]=await Promise.all([t,n,s]);return{rediscovered:r,expensive:o,authored:i,availability:e,generatedAt:new Date().toISOString()}}function Yi(e,t=60){if(!e)return"";let n=e.replace(/\s+/g," ").trim();return n.length<=t?n:n.slice(0,t-1)+"\u2026"}function Ji(e){return e.alias??(e.firstUserMessage?Yi(e.firstUserMessage,60):null)??e.sessionId.slice(0,8)}function yx(e){let t=e.rediscovered||e.expensive||e.authored;if(console.log(""),console.log(c.bold("today \xB7 for you")),console.log(c.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),!t){let n=[];e.availability.semantic||n.push("v0.11 semantic (`recall semantic on`)"),e.availability.cost||n.push("v0.10a cost (`recall stats --backfill`)"),e.availability.git||n.push("v0.10b git (`recall correlate`)"),console.log(c.dim(" no picks today.")),n.length>0?console.log(c.dim(" enable: "+n.join(", "))):console.log(c.dim(" data sources are live but nothing matched \u2014 try again tomorrow.")),console.log("");return}if(e.rediscovered){let n=e.rediscovered;console.log(""),console.log(` ${c.tool("\u2726 rediscovered")} ${c.dim(`(${n.daysAgo}d ago)`)}`),console.log(` ${c.bold(Ji(n))} ${c.dim(n.project?`\xB7 ${n.project}`:"")}`),console.log(` ${c.dim(n.sessionId.slice(0,8))}`),n.matchedKeywords.length>0&&console.log(" "+c.dim("matched: ")+n.matchedKeywords.slice(0,6).map(s=>c.tool(`#${s}`)).join(" ")),n.summary&&console.log(" "+c.dim(Yi(n.summary,100)))}if(e.expensive){let n=e.expensive;console.log(""),console.log(` ${c.accent("$ most expensive \xB7 7d")} ${c.bold(n.costDisplay)} ${c.dim(`(${n.tokensDisplay} \xB7 ${n.primaryModelLabel})`)}`),console.log(` ${c.bold(Ji(n))} ${c.dim(n.project?`\xB7 ${n.project}`:"")}`),console.log(` ${c.dim(n.sessionId.slice(0,8))} ${c.dim(n.startedAt?G(n.startedAt):"")}`)}if(e.authored){let n=e.authored;console.log(""),console.log(` ${c.ok("\u2387 authored current HEAD")} ${c.bold(n.shortSha)} ${c.dim(n.committedAt?`(${G(n.committedAt)})`:"")}`),console.log(` ${c.bold(Ji(n))} ${c.dim(n.project?`\xB7 ${n.project}`:"")}`),n.subject&&console.log(` ${c.dim(Yi(n.subject,80))}`),console.log(` ${c.dim(n.sessionId.slice(0,8))} ${c.dim("cwd: "+n.cwd)}`)}console.log("")}async function Im(e){let t=await vm();if(e.json){console.log(JSON.stringify(t,null,2));return}yx(t)}$();Ge();import{spawnSync as Pm}from"node:child_process";import{readdirSync as wx}from"node:fs";import{join as Tx,resolve as Rx}from"node:path";var qi=["code","cursor","code-insiders","windsurf"],Mm=[{id:"code",label:"VS Code"},{id:"cursor",label:"Cursor"},{id:"code-insiders",label:"VS Code Insiders"},{id:"windsurf",label:"Windsurf"}],kx="https://marketplace.visualstudio.com/items?itemName=clauderecallhq.clauderecall-vscode";function xx(){return Tx(te(),"extensions","vscode")}function Cx(){let e=xx(),t;try{t=wx(e)}catch{return null}let n=t.filter(s=>/^(clauderecall|claude-recall)-vscode-.*\.vsix$/i.test(s));return n.length===0?null:(n.sort((s,r)=>r.localeCompare(s,void 0,{numeric:!0})),Rx(e,n[0]))}function Dm(e){let t=Pm(e,["--version"],{stdio:"ignore",shell:process.platform==="win32"});return t.error?!1:t.status===0}function Lx(e,t){let n=Pm(e,["--install-extension",t],{stdio:"pipe",encoding:"utf8",shell:process.platform==="win32"});return n.error?{ok:!1,message:n.error.message}:n.status!==0?{ok:!1,message:(n.stderr??"").trim()||`exit code ${n.status??"null"}`}:{ok:!0,message:""}}function $m(){process.stderr.write(c.err(`no bundled .vsix found at extensions/vscode/(clauderecall|claude-recall)-vscode-*.vsix
1827
+ 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 Xm(){let e=$x(),t=e.semantic?Promise.resolve().then(()=>{try{return Px()}catch(a){return console.error("[discover.rediscovered]",a),null}}):Promise.resolve(null),n=e.cost?Promise.resolve().then(()=>{try{return Fx()}catch(a){return console.error("[discover.expensive]",a),null}}):Promise.resolve(null),s=e.git?Ux().catch(a=>(console.error("[discover.authored]",a),null)):Promise.resolve(null),[r,o,i]=await Promise.all([t,n,s]);return{rediscovered:r,expensive:o,authored:i,availability:e,generatedAt:new Date().toISOString()}}function Zi(e,t=60){if(!e)return"";let n=e.replace(/\s+/g," ").trim();return n.length<=t?n:n.slice(0,t-1)+"\u2026"}function Qi(e){return e.alias??(e.firstUserMessage?Zi(e.firstUserMessage,60):null)??e.sessionId.slice(0,8)}function Bx(e){let t=e.rediscovered||e.expensive||e.authored;if(console.log(""),console.log(c.bold("today \xB7 for you")),console.log(c.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),!t){let n=[];e.availability.semantic||n.push("v0.11 semantic (`recall semantic on`)"),e.availability.cost||n.push("v0.10a cost (`recall stats --backfill`)"),e.availability.git||n.push("v0.10b git (`recall correlate`)"),console.log(c.dim(" no picks today.")),n.length>0?console.log(c.dim(" enable: "+n.join(", "))):console.log(c.dim(" data sources are live but nothing matched \u2014 try again tomorrow.")),console.log("");return}if(e.rediscovered){let n=e.rediscovered;console.log(""),console.log(` ${c.tool("\u2726 rediscovered")} ${c.dim(`(${n.daysAgo}d ago)`)}`),console.log(` ${c.bold(Qi(n))} ${c.dim(n.project?`\xB7 ${n.project}`:"")}`),console.log(` ${c.dim(n.sessionId.slice(0,8))}`),n.matchedKeywords.length>0&&console.log(" "+c.dim("matched: ")+n.matchedKeywords.slice(0,6).map(s=>c.tool(`#${s}`)).join(" ")),n.summary&&console.log(" "+c.dim(Zi(n.summary,100)))}if(e.expensive){let n=e.expensive;console.log(""),console.log(` ${c.accent("$ most expensive \xB7 7d")} ${c.bold(n.costDisplay)} ${c.dim(`(${n.tokensDisplay} \xB7 ${n.primaryModelLabel})`)}`),console.log(` ${c.bold(Qi(n))} ${c.dim(n.project?`\xB7 ${n.project}`:"")}`),console.log(` ${c.dim(n.sessionId.slice(0,8))} ${c.dim(n.startedAt?G(n.startedAt):"")}`)}if(e.authored){let n=e.authored;console.log(""),console.log(` ${c.ok("\u2387 authored current HEAD")} ${c.bold(n.shortSha)} ${c.dim(n.committedAt?`(${G(n.committedAt)})`:"")}`),console.log(` ${c.bold(Qi(n))} ${c.dim(n.project?`\xB7 ${n.project}`:"")}`),n.subject&&console.log(` ${c.dim(Zi(n.subject,80))}`),console.log(` ${c.dim(n.sessionId.slice(0,8))} ${c.dim("cwd: "+n.cwd)}`)}console.log("")}async function Gm(e){let t=await Xm();if(e.json){console.log(JSON.stringify(t,null,2));return}Bx(t)}D();Ge();import{spawnSync as qm}from"node:child_process";import{readdirSync as Hx}from"node:fs";import{join as Wx,resolve as Xx}from"node:path";var ea=["code","cursor","code-insiders","windsurf"],Jm=[{id:"code",label:"VS Code"},{id:"cursor",label:"Cursor"},{id:"code-insiders",label:"VS Code Insiders"},{id:"windsurf",label:"Windsurf"}],Gx="https://marketplace.visualstudio.com/items?itemName=clauderecallhq.clauderecall-vscode";function Jx(){return Wx(te(),"extensions","vscode")}function zx(){let e=Jx(),t;try{t=Hx(e)}catch{return null}let n=t.filter(s=>/^(clauderecall|claude-recall)-vscode-.*\.vsix$/i.test(s));return n.length===0?null:(n.sort((s,r)=>r.localeCompare(s,void 0,{numeric:!0})),Xx(e,n[0]))}function zm(e){let t=qm(e,["--version"],{stdio:"ignore",shell:process.platform==="win32"});return t.error?!1:t.status===0}function Yx(e,t){let n=qm(e,["--install-extension",t],{stdio:"pipe",encoding:"utf8",shell:process.platform==="win32"});return n.error?{ok:!1,message:n.error.message}:n.status!==0?{ok:!1,message:(n.stderr??"").trim()||`exit code ${n.status??"null"}`}:{ok:!0,message:""}}function Ym(){process.stderr.write(c.err(`no bundled .vsix found at extensions/vscode/(clauderecall|claude-recall)-vscode-*.vsix
1817
1828
  `)),process.stderr.write(c.dim(`see PUBLISHING.md for how to build the extension, or run:
1818
1829
  `)),process.stderr.write(c.dim(` (cd extensions/vscode && npm install && npm run build && npm run package)
1819
- `))}function Ax(e){return qi.includes(e)}async function Fm(e){if(e.editor!==void 0&&!Ax(e.editor)){process.stderr.write(c.err(`unknown --editor target: ${e.editor}
1820
- `)),process.stderr.write(c.dim(`valid values: ${qi.join(", ")}
1821
- `)),process.exitCode=1;return}let t=Cx();if(e.printPath){if(!t){$m(),process.exitCode=1;return}process.stdout.write(t+`
1822
- `);return}if(!t){$m(),process.exitCode=1;return}let n;if(e.editor){let r=e.editor;if(!Dm(r)){process.stderr.write(c.err(`editor CLI not found on PATH: ${r}
1830
+ `))}function qx(e){return ea.includes(e)}async function Vm(e){if(e.editor!==void 0&&!qx(e.editor)){process.stderr.write(c.err(`unknown --editor target: ${e.editor}
1831
+ `)),process.stderr.write(c.dim(`valid values: ${ea.join(", ")}
1832
+ `)),process.exitCode=1;return}let t=zx();if(e.printPath){if(!t){Ym(),process.exitCode=1;return}process.stdout.write(t+`
1833
+ `);return}if(!t){Ym(),process.exitCode=1;return}let n;if(e.editor){let r=e.editor;if(!zm(r)){process.stderr.write(c.err(`editor CLI not found on PATH: ${r}
1823
1834
  `)),process.stderr.write(c.dim(`install the editor shell integration, or omit --editor to install into every detected editor.
1824
1835
  `)),process.stderr.write(c.dim(`see PUBLISHING.md for manual install instructions.
1825
- `)),process.exitCode=1;return}n=[Mm.find(i=>i.id===r)??{id:r,label:r}]}else n=Mm.filter(r=>Dm(r.id));if(n.length===0){process.stderr.write(c.err(`no supported editor CLI detected on PATH.
1826
- `)),process.stderr.write(c.dim(`looked for: ${qi.join(", ")}.
1836
+ `)),process.exitCode=1;return}n=[Jm.find(i=>i.id===r)??{id:r,label:r}]}else n=Jm.filter(r=>zm(r.id));if(n.length===0){process.stderr.write(c.err(`no supported editor CLI detected on PATH.
1837
+ `)),process.stderr.write(c.dim(`looked for: ${ea.join(", ")}.
1827
1838
  `)),process.stderr.write(c.dim(`install the editor shell integration and try again.
1828
1839
  `)),process.stderr.write(c.dim(`see PUBLISHING.md for manual install instructions.
1829
1840
  `)),process.exitCode=1;return}process.stderr.write(c.dim(`bundled .vsix: ${t}
1830
1841
 
1831
- `));let s=!1;for(let r of n){let{ok:o,message:i}=Lx(r.id,t);o?process.stderr.write(c.ok(`\u2713 installed into ${r.label} (${r.id})
1842
+ `));let s=!1;for(let r of n){let{ok:o,message:i}=Yx(r.id,t);o?process.stderr.write(c.ok(`\u2713 installed into ${r.label} (${r.id})
1832
1843
  `)):(s=!0,process.stderr.write(c.err(`\u2717 ${r.label} (${r.id}): ${i}
1833
1844
  `)))}process.stderr.write(`
1834
1845
  `),process.stderr.write(c.bold(`next steps:
1835
1846
  `)),process.stderr.write(` 1. reload the editor window: Cmd/Ctrl+Shift+P then pick "Developer: Reload Window"
1836
1847
  `),process.stderr.write(` 2. enable the extension: open settings and set "claude-recall.autoAlias" to true
1837
1848
  `),process.stderr.write(`
1838
- `),process.stderr.write(c.dim(`marketplace install: ${kx}
1839
- `)),s&&(process.exitCode=1)}Zi();$();function ea(e){return e>=70?c.ok:e>=40?c.warn:c.err}function Um(e,t=20){let n=Math.round(e/100*t);return"\u2588".repeat(n)+"\u2591".repeat(t-n)}function Nx(e){let t=ea(e.score);process.stdout.write(`
1849
+ `),process.stderr.write(c.dim(`marketplace install: ${Gx}
1850
+ `)),s&&(process.exitCode=1)}ra();D();function oa(e){return e>=70?c.ok:e>=40?c.warn:c.err}function Qm(e,t=20){let n=Math.round(e/100*t);return"\u2588".repeat(n)+"\u2591".repeat(t-n)}function Vx(e){let t=oa(e.score);process.stdout.write(`
1840
1851
  ${c.bold(e.projectName)} ${t(String(e.score)+"/100")}
1841
- `);let n=e.breakdown,s=[["Sessions",n.sessionCount.score*100,`${n.sessionCount.raw} sessions`],["Recency",n.recency.score*100,`${n.recency.daysSinceLastSession}d ago`],["Depth",n.fragmentation.score*100,`avg ${n.fragmentation.avgMessages} msgs`],["Search",n.searchCoverage.score*100,`${Math.round(n.searchCoverage.ratio*100)}% covered`],["Tags",n.tagCoverage.score*100,`${Math.round(n.tagCoverage.ratio*100)}% tagged`]];for(let[r,o,i]of s){let a=ea(o);process.stdout.write(` ${r.padEnd(10)} ${a(Um(o,16))} ${String(Math.round(o)).padStart(3)}% ${c.dim(i)}
1842
- `)}}function Bm(e,t){if(e){let r=Ki(e);if(!r){process.stderr.write(c.err(`project "${e}" not found
1852
+ `);let n=e.breakdown,s=[["Sessions",n.sessionCount.score*100,`${n.sessionCount.raw} sessions`],["Recency",n.recency.score*100,`${n.recency.daysSinceLastSession}d ago`],["Depth",n.fragmentation.score*100,`avg ${n.fragmentation.avgMessages} msgs`],["Search",n.searchCoverage.score*100,`${Math.round(n.searchCoverage.ratio*100)}% covered`],["Tags",n.tagCoverage.score*100,`${Math.round(n.tagCoverage.ratio*100)}% tagged`]];for(let[r,o,i]of s){let a=oa(o);process.stdout.write(` ${r.padEnd(10)} ${a(Qm(o,16))} ${String(Math.round(o)).padStart(3)}% ${c.dim(i)}
1853
+ `)}}function Zm(e,t){if(e){let r=na(e);if(!r){process.stderr.write(c.err(`project "${e}" not found
1843
1854
  `)),process.exitCode=1;return}if(t.json){process.stdout.write(JSON.stringify(r,null,2)+`
1844
- `);return}Nx(r);return}let n=Qi();if(n.length===0){process.stdout.write("No projects found. Run `recall index` first.\n");return}if(t.json){process.stdout.write(JSON.stringify(n,null,2)+`
1855
+ `);return}Vx(r);return}let n=sa();if(n.length===0){process.stdout.write("No projects found. Run `recall index` first.\n");return}if(t.json){process.stdout.write(JSON.stringify(n,null,2)+`
1845
1856
  `);return}let s=[...n].sort((r,o)=>r.score-o.score);process.stdout.write(c.bold("Memory Health Scores")+` (worst first)
1846
1857
 
1847
- `);for(let r of s){let o=ea(r.score);process.stdout.write(` ${o(Um(r.score,12))} ${String(r.score).padStart(3)}/100 ${r.projectName}
1858
+ `);for(let r of s){let o=oa(r.score);process.stdout.write(` ${o(Qm(r.score,12))} ${String(r.score).padStart(3)}/100 ${r.projectName}
1848
1859
  `)}process.stdout.write(`
1849
- `)}$();function Hm(e){if(e==="on"){co(!0),process.stdout.write(c.ok("Verification badges enabled.")+`
1850
- `);return}if(e==="off"){co(!1),process.stdout.write(`Verification badges disabled.
1851
- `);return}let t=es();process.stdout.write(`Verification badges: ${t?c.ok("ON"):"OFF"}
1860
+ `)}D();function eg(e){if(e==="on"){uo(!0),process.stdout.write(c.ok("Verification badges enabled.")+`
1861
+ `);return}if(e==="off"){uo(!1),process.stdout.write(`Verification badges disabled.
1862
+ `);return}let t=ts();process.stdout.write(`Verification badges: ${t?c.ok("ON"):"OFF"}
1852
1863
  `),process.stdout.write(`
1853
1864
  Toggle with: recall verify on | off
1854
- `)}$();mn();ss();Bt();rs();import{hostname as iC}from"node:os";import{randomBytes as aC}from"node:crypto";Xe();ge();I();k();Ge();import{existsSync as Ox}from"node:fs";import vx from"node:readline";import{createRequire as Ix}from"node:module";import{Chalk as Mx}from"chalk";var Dx=Ix(import.meta.url),$x=Dx(`${te()}/package.json`).version,zm="#f97316",Px="#8b9098",Fx="#10b981",jx="#f59e0b",Qt=new Mx({level:process.env.NO_COLOR?0:3}),Re=Qt.hex(zm),de=Qt.hex(zm).bold,P=Qt.hex(Px),Ot=Qt.hex(Fx),fr=Qt.hex(jx),Jm=Qt.bold,Ym=[" \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"],Ux=Ym[0]?.length??49,Wm="Never lose a Claude Code session again.",Bx="CLAUDE RECALL";function Hx(){if(!Ox(ee))return{sessions:0,projects:0};try{let t=E().prepare(`SELECT
1865
+ `)}D();mn();rs();Bt();os();import{hostname as xC}from"node:os";import{randomBytes as CC}from"node:crypto";De();ge();I();k();Ge();import{existsSync as Kx}from"node:fs";import Qx from"node:readline";import{createRequire as Zx}from"node:module";import{Chalk as eC}from"chalk";var tC=Zx(import.meta.url),nC=tC(`${te()}/package.json`).version,rg="#f97316",sC="#8b9098",rC="#10b981",oC="#f59e0b",Qt=new eC({level:process.env.NO_COLOR?0:3}),Re=Qt.hex(rg),de=Qt.hex(rg).bold,P=Qt.hex(sC),Ot=Qt.hex(rC),hr=Qt.hex(oC),og=Qt.bold,ig=[" \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"],iC=ig[0]?.length??49,tg="Never lose a Claude Code session again.",aC="CLAUDE RECALL";function cC(){if(!Kx(ee))return{sessions:0,projects:0};try{let t=h().prepare(`SELECT
1855
1866
  (SELECT COUNT(*) FROM sessions) AS sessions,
1856
- (SELECT COUNT(*) FROM projects) AS projects`).get();return{sessions:t.sessions,projects:t.projects}}catch{return{sessions:0,projects:0}}}function Wx(){let e=process.stdout.columns;return typeof e!="number"||e<=0?!1:e<Ux+2}function qm(){if(Wx()){console.log(`${de(Bx)} ${P("\xB7")} ${P(Wm)}`);return}for(let e of Ym)console.log(de(e));console.log(P(Wm))}async function Xx(){return{daemon:ie(),counts:Hx(),license:await Le()}}function Gx(e){let t=[];if(t.push(` ${P("Version:")} ${Re(`v${$x}`)} ${P("\xB7 CLI \xB7 @clauderecallhq/cli")}`),e.daemon){let n=`http://127.0.0.1:${e.daemon.port}`;t.push(` ${P("Daemon:")} ${Ot("running")} on ${n} ${P(`(pid ${e.daemon.pid})`)}`)}else t.push(` ${P("Daemon:")} ${fr("stopped")}`);if(e.counts.sessions===0)t.push(` ${P("Sessions:")} ${fr("none indexed yet")}`);else{let n=e.counts.projects===1?"project":"projects";t.push(` ${P("Sessions:")} ${Re(String(e.counts.sessions))} indexed across ${Re(String(e.counts.projects))} ${n}`)}return e.license.tier==="pro"?t.push(` ${P("License:")} ${Ot("Pro")}`):t.push(` ${P("License:")} Free`),t}function zx(e){let t=Re(">");if(e.counts.sessions===0)return`${t} Run ${de("recall index")} to scan ~/.claude/projects/`;if(!e.daemon)return`${t} Run ${de("recall start")} to launch the local daemon`;if(e.license.tier==="free")return`${t} Run ${de("recall upgrade")} to unlock Pro features`;let n=`http://127.0.0.1:${e.daemon.port}`;return`${t} Open ${Re(n)} in your browser ${P("\xB7")} or run ${de("recall --help")} for all commands`}var _r=[{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"}]}],Jx=_r.reduce((e,t)=>e+t.commands.length,0),Yx=new Set([..._r.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 Xm(){let e=_r.flatMap(n=>n.commands.map(s=>`recall ${s.name}`)),t=Math.max(...e.map(n=>n.length));console.log(),console.log(`${Jm("COMMANDS")} ${P(`\xB7 ${Jx} total \xB7 q to quit \xB7 recall --help for full details`)}`),console.log(` ${P("All commands run as subcommands of")} ${de("recall")}${P(". There is no separate")} ${Re("threads")}${P(",")} ${Re("thread")}${P(", or")} ${Re("titles")} ${P("binary.")}`);for(let n of _r){console.log(),console.log(` ${de(n.title.toUpperCase())}`);for(let s of n.commands){let r=`recall ${s.name}`.padEnd(t," ");console.log(` ${Re(r)} ${P(s.description)}`)}}console.log()}function qx(){return!!process.stdin.isTTY&&!!process.stdout.isTTY}async function Vx(){if(!qx())return;let e=vx.createInterface({input:process.stdin,output:process.stdout}),t=`${P("Type")} ${de("/")} ${P("for commands, or press")} ${de("Enter")} ${P("to exit")} ${Re("\u203A")} `;return new Promise(n=>{let s=()=>{e.question(t,r=>{let o=r.trim();if(o==="/"||o==="/help"||o==="help"||o==="?"){Xm(),s();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===""){Xm(),s();return}let d=(i.split(/\s+/)[0]??"").toLowerCase();Yx.has(d)?console.log(` ${P("Run")} ${de(`recall ${i}`)} ${P("in your shell to invoke that command.")}`):console.log(` ${P(`No command matches "${o}". Type`)} ${de("/")} ${P("to browse, or")} ${de("recall --help")} ${P("for the full list.")}`),s()})};e.on("close",()=>{console.log(),n()}),s()})}async function Vm(){let e=await Xx();console.log(),qm(),console.log();for(let t of Gx(e))console.log(t);console.log(),console.log(zx(e)),console.log(),await Vx()}var Kx=[{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 Qx(){return process.env.NO_COLOR||process.env.CI||process.env.RECALL_NO_ANIMATION?!1:!!process.stdout.isTTY}function ta(e){return new Promise(t=>setTimeout(t,e))}function Zx(e){let n=(e.split("@")[0]??"").split(/[._+\-]/)[0]??"";return n?n.charAt(0).toUpperCase()+n.slice(1).toLowerCase():""}function Gm(){process.stdout.write("\r\x1B[2K")}async function hr(e){let t=Qx();console.log(),qm(),console.log(),t&&(process.stdout.write(` ${P("Verifying license...")}`),await ta(260),Gm()),console.log(` ${Ot("\u2713")} ${P("License verified")}`),console.log(` ${Ot("\u2713")} ${P("Tier:")} ${de("Pro")} ${P("\xB7 Lifetime")}`),console.log(` ${Ot("\u2713")} ${P("Key:")} ${Re(e.key_short)}`),console.log(` ${Ot("\u2713")} ${P("Email:")} ${e.email}`),e.test_mode&&console.log(` ${fr("!")} ${fr("Test mode:")} this license was issued in test mode.`),console.log(),console.log(` ${Jm("Unlocking Pro features")}`),console.log();for(let r of Kx)t&&(process.stdout.write(` ${P("\xB7")} ${P(r.name)}`),await ta(110),Gm()),console.log(` ${Ot("\u2713")} ${r.name} ${P(r.detail)}`);t&&await ta(160),console.log();let n=Zx(e.email),s=n?`Welcome aboard, ${n}.`:"Welcome aboard.";console.log(` ${de(s)}`),console.log(` ${P("Run")} ${Re("recall")} ${P("to open the dashboard, or")} ${Re("recall help")} ${P("for the command list.")}`),console.log()}$();mn();ss();Bt();rs();import{hostname as eC}from"node:os";import{randomBytes as tC}from"node:crypto";import{createInterface as nC}from"node:readline/promises";async function sC(e){let t=e.fetchFn??fetch,n=`${e.apiBaseUrl}/api/trial/cli-redeem`,s=await t(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({promo_code:e.promoCode,email:e.email,machine_fingerprint:e.fingerprint,instance_name:e.instanceName,referral_source:"cli"})}),r;try{r=await s.json()}catch{throw new Error(`server returned non-JSON (status ${s.status})`)}return{status:s.status,body:r}}async function rC(e={}){let t=nC({input:e.stdin??process.stdin,output:e.stdout??process.stdout});try{return(await t.question(c.bold("Email for your 7-day trial: "))).trim().toLowerCase()}finally{t.close()}}function oC(e){if(e.length<5||e.length>256||!e.includes("@"))return!1;let[t,n]=e.split("@");return!(!t||!n||!n.includes(".")||/\s/.test(e))}async function Er(e,t={}){let n=e.trim().toUpperCase();if(n.length<3&&(console.error(c.warn(`Promo code "${e}" is too short.`)),process.exit(1)),!t.skipExistingProCheck){let{getLicenseStatus:u}=await Promise.resolve().then(()=>(ge(),gn)),m=await u();if(m.tier==="pro"){console.log(),console.log(c.bold("You are already on Pro \u2014 no need to redeem a trial.")),console.log(` ${c.dim("Key:")} ${m.key_short}`),console.log(` ${c.dim("Email:")} ${m.customer_email}`),console.log(),console.log(c.dim("If you wanted to switch accounts, run `recall license deactivate` first.")),console.log();return}}console.log(),console.log(`${c.ok("Redeeming")} promo code ${c.bold(n)} for a 7-day Pro trial.`),console.log(c.dim("You will get an email with your license key for backup.")),console.log(),!t.promptFn&&!process.stdin.isTTY&&(console.error(c.warn("Trial activation needs an interactive terminal so you can type your email.")),console.error(c.dim("Re-run `recall activate "+n+"` in a terminal (not piped, not CI).")),process.exit(1));let r=await(t.promptFn??rC)();oC(r)||(console.error(c.warn(`"${r}" doesn't look like an email address.`)),process.exit(1));let o=t.instanceName??`${eC()}-${tC(4).toString("hex")}`,i=t.fingerprint??Wt(),a=t.apiBaseUrl??dt(),d;try{d=await sC({promoCode:n,email:r,fingerprint:i,instanceName:o,apiBaseUrl:a,...t.fetchFn?{fetchFn:t.fetchFn}:{}})}catch(u){let m=u instanceof Error?u.message:"unknown error";console.error(c.warn(`Could not reach the trial server at ${a}: ${m}`)),console.error(c.dim("If you are offline, try again when you have a connection.")),process.exit(1)}if(d.status!==200||!d.body.license_jwt||!d.body.license_key){let u=d.body.error??`trial activation failed (status ${d.status})`;console.error(c.warn(`Trial refused: ${u}`)),process.exit(1)}let l=await Ht(d.body.license_jwt);(!l.valid||!l.claims)&&(console.error(c.warn(`Server returned a JWT that fails local verification: ${l.reason??"unknown"}`)),console.error(c.dim("This usually means the CLI is older than the server. Try `npm i -g @clauderecallhq/cli`.")),process.exit(1)),ts({license_jwt:d.body.license_jwt,license_key:d.body.license_key,key_short:d.body.key_short??l.claims.key_short,customer_email:d.body.customer_email??l.claims.email,activated_at:new Date().toISOString(),tier:"pro",test_mode:!!l.claims.test_mode}),t.skipSuccessDashboard||await hr({...l.claims,key_short:d.body.key_short??l.claims.key_short,email:d.body.customer_email??l.claims.email})}function cC(e){return/^recall-pro-/i.test(e)}async function Km(e){let t=e.trim();if(t.length<3&&(console.error(c.warn("License key or promo code looks too short.")),console.error(c.dim("Paste the full key from your purchase email, or a promo code like RECALL7DAY.")),process.exit(1)),!cC(t)){await Er(t);return}t.length<8&&(console.error(c.warn("License key looks too short. Paste the full key from your purchase email.")),process.exit(1));let n=`${iC()}-${aC(4).toString("hex")}`,s=`${dt()}/api/license/activate`,r;try{r=await fetch(s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({license_key:t,instance_name:n,machine_fingerprint:Wt()})})}catch(a){let d=a instanceof Error?a.message:"unknown error";console.error(c.warn(`Could not reach activation server at ${s}: ${d}`)),console.error(c.dim("If you are offline, try again when you have a connection.")),process.exit(1)}let o;try{o=await r.json()}catch{console.error(c.warn(`Activation server returned invalid JSON (status ${r.status}).`)),process.exit(1)}if(r.status!==200||!o.license_jwt){let a=o.error??`activation failed (status ${r.status})`;console.error(c.warn(`Activation refused: ${a}`)),process.exit(1)}let i=await Ht(o.license_jwt);(!i.valid||!i.claims)&&(console.error(c.warn(`Server returned a JWT that fails local verification: ${i.reason??"unknown"}`)),console.error(c.dim("This usually means the CLI is older than the server, or the public key was rotated.")),process.exit(1)),ts({license_jwt:o.license_jwt,license_key:t,key_short:o.key_short??i.claims.key_short,customer_email:o.customer_email??i.claims.email,activated_at:new Date().toISOString(),tier:"pro",test_mode:!!i.claims.test_mode}),await hr({...i.claims,key_short:o.key_short??i.claims.key_short,email:o.customer_email??i.claims.email})}$();import{spawn as lC}from"node:child_process";import{platform as br}from"node:os";var Qm="https://clauderecall.com/pricing";function dC(e){let t=br()==="darwin"?"open":br()==="win32"?"start":"xdg-open",n=br()==="win32"?["",e]:[e];lC(t,n,{detached:!0,stdio:"ignore",shell:br()==="win32"}).unref()}async function Zm(){let{getLicenseStatus:e}=await Promise.resolve().then(()=>(ge(),gn)),t=await e();if(t.tier==="pro"){console.log(),console.log(c.bold("Already on Pro.")),console.log(` ${c.dim("Key:")} ${t.key_short}`),console.log(` ${c.dim("Email:")} ${t.customer_email}`),console.log();return}console.log(),console.log(`${c.ok("Opening")} ${Qm}`),console.log(c.dim("After purchase, run: recall activate <license-key>")),console.log(),dC(Qm)}$();import{spawn as uC}from"node:child_process";import{platform as Sr}from"node:os";var eg="https://clauderecall.com/pricing?trial=1&utm_source=cli&utm_medium=recall_trial";function pC(e){let t=Sr()==="darwin"?"open":Sr()==="win32"?"start":"xdg-open",n=Sr()==="win32"?["",e]:[e];uC(t,n,{detached:!0,stdio:"ignore",shell:Sr()==="win32"}).unref()}async function tg(e){if(e&&e.trim().length>0){await Er(e);return}let{getLicenseStatus:t}=await Promise.resolve().then(()=>(ge(),gn)),n=await t();if(n.tier==="pro"){console.log(),console.log(c.bold("You are already on Pro.")),console.log(` ${c.dim("Key:")} ${n.key_short}`),console.log(` ${c.dim("Email:")} ${n.customer_email}`),console.log();return}console.log(),console.log(`${c.ok("Opening")} ${eg}`),console.log(c.dim("Enter your email to get a 7-day Pro trial link. No card.")),console.log(c.dim("After you click the verification email, run: recall activate <key>")),console.log(),console.log(c.dim("Tip: if you have a promo code, run `recall trial <CODE>` to skip the browser.")),console.log(),pC(eg)}$();mn();import{existsSync as ng,mkdirSync as mC,readFileSync as gC,writeFileSync as fC}from"node:fs";import{homedir as _C}from"node:os";import{join as sg}from"node:path";import{randomBytes as hC}from"node:crypto";var sa=sg(_C(),".recall"),wr=sg(sa,"telemetry.json"),na={decided_at:null,decision:null,last_ping_month:null,nonce_month:null,nonce:null,last_error:null};function vt(){if(!ng(wr))return{...na};try{let e=gC(wr,"utf8"),t=JSON.parse(e);return{...na,...t}}catch{return{...na}}}function yr(e){ng(sa)||mC(sa,{recursive:!0}),fC(wr,JSON.stringify(e,null,2)+`
1857
- `,{mode:384})}function rg(){return wr}function ra(e=new Date){let t=e.getUTCFullYear(),n=String(e.getUTCMonth()+1).padStart(2,"0");return`${t}-${n}`}function og(e,t){return e.nonce&&e.nonce_month===t?e:{...e,nonce:hC(16).toString("hex"),nonce_month:t}}function EC(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 ig(e){let t=vt();if(t.decision!=="on")return{status:t.decision==="off"?"opted-out":"no-decision"};let n=ra();if(t.last_ping_month===n)return{status:"already-this-month"};t=og(t,n);let s=EC(e,t);if(!s)return{status:"error",detail:"no nonce"};try{let r=await fetch(`${dt()}/api/install-ping`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s),signal:AbortSignal.timeout(5e3)});if(!r.ok){let i=`http ${r.status}`;return yr({...t,last_error:`${new Date().toISOString()} ${i}`}),{status:"error",detail:i}}let o=await r.json().catch(()=>({}));return yr({...t,last_ping_month:n,last_error:null}),{status:o.deduped?"deduped":"sent"}}catch(r){let o=r instanceof Error?r.message:"unknown";return yr({...t,last_error:`${new Date().toISOString()} ${o}`}),{status:"error",detail:o}}}function Zt(e){let n={...vt(),decision:e,decided_at:new Date().toISOString(),last_error:null,...e==="off"?{nonce:null,nonce_month:null,last_ping_month:null}:{}};return yr(n),n}function Tr(e){let t=og(vt(),ra());return{event:"install",version:e,platform:process.platform,arch:process.arch,month:t.nonce_month??ra(),nonce:t.nonce??"0".repeat(32)}}async function oa(e){let t=vt();console.log(),console.log(c.bold("Telemetry \u2014 anonymous install ping")),console.log(` ${c.dim("decision:")} ${t.decision??"not yet decided"}`),console.log(` ${c.dim("decided at:")} ${t.decided_at??"\u2014"}`),console.log(` ${c.dim("last ping:")} ${t.last_ping_month??"\u2014"}`),console.log(` ${c.dim("state file:")} ${rg()}`),t.last_error&&console.log(` ${c.warn("last error:")} ${t.last_error}`),console.log(),console.log(c.dim("Next-ping payload preview (only sent if decision = on):")),console.log(c.dim(JSON.stringify(Tr(e),null,2))),console.log(),console.log(c.dim("Toggle with `recall telemetry on` / `recall telemetry off`.")),console.log(c.dim("Full disclosure: https://clauderecall.com/telemetry")),console.log()}async function ag(){Zt("on"),console.log(),console.log(c.ok("Telemetry: opted in.")),console.log(c.dim("One anonymous ping per machine per month. No PII. Source: docs/specs/v0.16-install-ping.md")),console.log(c.dim("Reverse with `recall telemetry off`.")),console.log()}async function cg(){Zt("off"),console.log(),console.log(c.ok("Telemetry: opted out.")),console.log(c.dim("No further pings will be sent. Existing nonce deleted.")),console.log()}async function lg(e){await oa(e)}import{createInterface as bC}from"node:readline/promises";import{stdin as dg,stdout as Ee}from"node:process";var SC=new Set(["telemetry","trial","upgrade","activate","license","help","version"]);function yC(e){return!(process.env.CI==="true"||process.env.RECALL_QUIET_INSTALL==="1"||process.env.RECALL_DISABLE_TELEMETRY_PROMPT==="1"||!dg.isTTY||!Ee.isTTY||e&&SC.has(e)||vt().decision!==null)}async function ug(e,t){if(!yC(e))return;let n=Tr(t);Ee.write(`
1867
+ (SELECT COUNT(*) FROM projects) AS projects`).get();return{sessions:t.sessions,projects:t.projects}}catch{return{sessions:0,projects:0}}}function lC(){let e=process.stdout.columns;return typeof e!="number"||e<=0?!1:e<iC+2}function ag(){if(lC()){console.log(`${de(aC)} ${P("\xB7")} ${P(tg)}`);return}for(let e of ig)console.log(de(e));console.log(P(tg))}async function dC(){return{daemon:se(),counts:cC(),license:await Ae()}}function uC(e){let t=[];if(t.push(` ${P("Version:")} ${Re(`v${nC}`)} ${P("\xB7 CLI \xB7 @clauderecallhq/cli")}`),e.daemon){let n=`http://127.0.0.1:${e.daemon.port}`;t.push(` ${P("Daemon:")} ${Ot("running")} on ${n} ${P(`(pid ${e.daemon.pid})`)}`)}else t.push(` ${P("Daemon:")} ${hr("stopped")}`);if(e.counts.sessions===0)t.push(` ${P("Sessions:")} ${hr("none indexed yet")}`);else{let n=e.counts.projects===1?"project":"projects";t.push(` ${P("Sessions:")} ${Re(String(e.counts.sessions))} indexed across ${Re(String(e.counts.projects))} ${n}`)}return e.license.tier==="pro"?t.push(` ${P("License:")} ${Ot("Pro")}`):t.push(` ${P("License:")} Free`),t}function pC(e){let t=Re(">");if(e.counts.sessions===0)return`${t} Run ${de("recall index")} to scan ~/.claude/projects/`;if(!e.daemon)return`${t} Run ${de("recall start")} to launch the local daemon`;if(e.license.tier==="free")return`${t} Run ${de("recall upgrade")} to unlock Pro features`;let n=`http://127.0.0.1:${e.daemon.port}`;return`${t} Open ${Re(n)} in your browser ${P("\xB7")} or run ${de("recall --help")} for all commands`}var Er=[{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"}]}],mC=Er.reduce((e,t)=>e+t.commands.length,0),gC=new Set([...Er.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 ng(){let e=Er.flatMap(n=>n.commands.map(s=>`recall ${s.name}`)),t=Math.max(...e.map(n=>n.length));console.log(),console.log(`${og("COMMANDS")} ${P(`\xB7 ${mC} total \xB7 q to quit \xB7 recall --help for full details`)}`),console.log(` ${P("All commands run as subcommands of")} ${de("recall")}${P(". There is no separate")} ${Re("threads")}${P(",")} ${Re("thread")}${P(", or")} ${Re("titles")} ${P("binary.")}`);for(let n of Er){console.log(),console.log(` ${de(n.title.toUpperCase())}`);for(let s of n.commands){let r=`recall ${s.name}`.padEnd(t," ");console.log(` ${Re(r)} ${P(s.description)}`)}}console.log()}function fC(){return!!process.stdin.isTTY&&!!process.stdout.isTTY}async function _C(){if(!fC())return;let e=Qx.createInterface({input:process.stdin,output:process.stdout}),t=`${P("Type")} ${de("/")} ${P("for commands, or press")} ${de("Enter")} ${P("to exit")} ${Re("\u203A")} `;return new Promise(n=>{let s=()=>{e.question(t,r=>{let o=r.trim();if(o==="/"||o==="/help"||o==="help"||o==="?"){ng(),s();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===""){ng(),s();return}let d=(i.split(/\s+/)[0]??"").toLowerCase();gC.has(d)?console.log(` ${P("Run")} ${de(`recall ${i}`)} ${P("in your shell to invoke that command.")}`):console.log(` ${P(`No command matches "${o}". Type`)} ${de("/")} ${P("to browse, or")} ${de("recall --help")} ${P("for the full list.")}`),s()})};e.on("close",()=>{console.log(),n()}),s()})}async function cg(){let e=await dC();console.log(),ag(),console.log();for(let t of uC(e))console.log(t);console.log(),console.log(pC(e)),console.log(),await _C()}var hC=[{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 EC(){return process.env.NO_COLOR||process.env.CI||process.env.RECALL_NO_ANIMATION?!1:!!process.stdout.isTTY}function ia(e){return new Promise(t=>setTimeout(t,e))}function bC(e){let n=(e.split("@")[0]??"").split(/[._+\-]/)[0]??"";return n?n.charAt(0).toUpperCase()+n.slice(1).toLowerCase():""}function sg(){process.stdout.write("\r\x1B[2K")}async function br(e){let t=EC();console.log(),ag(),console.log(),t&&(process.stdout.write(` ${P("Verifying license...")}`),await ia(260),sg()),console.log(` ${Ot("\u2713")} ${P("License verified")}`),console.log(` ${Ot("\u2713")} ${P("Tier:")} ${de("Pro")} ${P("\xB7 Lifetime")}`),console.log(` ${Ot("\u2713")} ${P("Key:")} ${Re(e.key_short)}`),console.log(` ${Ot("\u2713")} ${P("Email:")} ${e.email}`),e.test_mode&&console.log(` ${hr("!")} ${hr("Test mode:")} this license was issued in test mode.`),console.log(),console.log(` ${og("Unlocking Pro features")}`),console.log();for(let r of hC)t&&(process.stdout.write(` ${P("\xB7")} ${P(r.name)}`),await ia(110),sg()),console.log(` ${Ot("\u2713")} ${r.name} ${P(r.detail)}`);t&&await ia(160),console.log();let n=bC(e.email),s=n?`Welcome aboard, ${n}.`:"Welcome aboard.";console.log(` ${de(s)}`),console.log(` ${P("Run")} ${Re("recall")} ${P("to open the dashboard, or")} ${Re("recall help")} ${P("for the command list.")}`),console.log()}D();mn();rs();Bt();os();import{hostname as SC}from"node:os";import{randomBytes as yC}from"node:crypto";import{createInterface as wC}from"node:readline/promises";async function TC(e){let t=e.fetchFn??fetch,n=`${e.apiBaseUrl}/api/trial/cli-redeem`,s=await t(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({promo_code:e.promoCode,email:e.email,machine_fingerprint:e.fingerprint,instance_name:e.instanceName,referral_source:"cli"})}),r;try{r=await s.json()}catch{throw new Error(`server returned non-JSON (status ${s.status})`)}return{status:s.status,body:r}}async function RC(e={}){let t=wC({input:e.stdin??process.stdin,output:e.stdout??process.stdout});try{return(await t.question(c.bold("Email for your 7-day trial: "))).trim().toLowerCase()}finally{t.close()}}function kC(e){if(e.length<5||e.length>256||!e.includes("@"))return!1;let[t,n]=e.split("@");return!(!t||!n||!n.includes(".")||/\s/.test(e))}async function Sr(e,t={}){let n=e.trim().toUpperCase();if(n.length<3&&(console.error(c.warn(`Promo code "${e}" is too short.`)),process.exit(1)),!t.skipExistingProCheck){let{getLicenseStatus:u}=await Promise.resolve().then(()=>(ge(),gn)),m=await u();if(m.tier==="pro"){console.log(),console.log(c.bold("You are already on Pro \u2014 no need to redeem a trial.")),console.log(` ${c.dim("Key:")} ${m.key_short}`),console.log(` ${c.dim("Email:")} ${m.customer_email}`),console.log(),console.log(c.dim("If you wanted to switch accounts, run `recall license deactivate` first.")),console.log();return}}console.log(),console.log(`${c.ok("Redeeming")} promo code ${c.bold(n)} for a 7-day Pro trial.`),console.log(c.dim("You will get an email with your license key for backup.")),console.log(),!t.promptFn&&!process.stdin.isTTY&&(console.error(c.warn("Trial activation needs an interactive terminal so you can type your email.")),console.error(c.dim("Re-run `recall activate "+n+"` in a terminal (not piped, not CI).")),process.exit(1));let r=await(t.promptFn??RC)();kC(r)||(console.error(c.warn(`"${r}" doesn't look like an email address.`)),process.exit(1));let o=t.instanceName??`${SC()}-${yC(4).toString("hex")}`,i=t.fingerprint??Wt(),a=t.apiBaseUrl??dt(),d;try{d=await TC({promoCode:n,email:r,fingerprint:i,instanceName:o,apiBaseUrl:a,...t.fetchFn?{fetchFn:t.fetchFn}:{}})}catch(u){let m=u instanceof Error?u.message:"unknown error";console.error(c.warn(`Could not reach the trial server at ${a}: ${m}`)),console.error(c.dim("If you are offline, try again when you have a connection.")),process.exit(1)}if(d.status!==200||!d.body.license_jwt||!d.body.license_key){let u=d.body.error??`trial activation failed (status ${d.status})`;console.error(c.warn(`Trial refused: ${u}`)),process.exit(1)}let l=await Ht(d.body.license_jwt);(!l.valid||!l.claims)&&(console.error(c.warn(`Server returned a JWT that fails local verification: ${l.reason??"unknown"}`)),console.error(c.dim("This usually means the CLI is older than the server. Try `npm i -g @clauderecallhq/cli`.")),process.exit(1)),ns({license_jwt:d.body.license_jwt,license_key:d.body.license_key,key_short:d.body.key_short??l.claims.key_short,customer_email:d.body.customer_email??l.claims.email,activated_at:new Date().toISOString(),tier:"pro",test_mode:!!l.claims.test_mode}),t.skipSuccessDashboard||await br({...l.claims,key_short:d.body.key_short??l.claims.key_short,email:d.body.customer_email??l.claims.email})}function AC(e){return/^recall-pro-/i.test(e)}async function lg(e){let t=e.trim();if(t.length<3&&(console.error(c.warn("License key or promo code looks too short.")),console.error(c.dim("Paste the full key from your purchase email, or a promo code like RECALL7DAY.")),process.exit(1)),!AC(t)){await Sr(t);return}t.length<8&&(console.error(c.warn("License key looks too short. Paste the full key from your purchase email.")),process.exit(1));let n=`${xC()}-${CC(4).toString("hex")}`,s=`${dt()}/api/license/activate`,r;try{r=await fetch(s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({license_key:t,instance_name:n,machine_fingerprint:Wt()})})}catch(a){let d=a instanceof Error?a.message:"unknown error";console.error(c.warn(`Could not reach activation server at ${s}: ${d}`)),console.error(c.dim("If you are offline, try again when you have a connection.")),process.exit(1)}let o;try{o=await r.json()}catch{console.error(c.warn(`Activation server returned invalid JSON (status ${r.status}).`)),process.exit(1)}if(r.status!==200||!o.license_jwt){let a=o.error??`activation failed (status ${r.status})`;console.error(c.warn(`Activation refused: ${a}`)),process.exit(1)}let i=await Ht(o.license_jwt);(!i.valid||!i.claims)&&(console.error(c.warn(`Server returned a JWT that fails local verification: ${i.reason??"unknown"}`)),console.error(c.dim("This usually means the CLI is older than the server, or the public key was rotated.")),process.exit(1)),ns({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 br({...i.claims,key_short:o.key_short??i.claims.key_short,email:o.customer_email??i.claims.email})}D();import{spawn as LC}from"node:child_process";import{platform as yr}from"node:os";var dg="https://clauderecall.com/pricing";function NC(e){let t=yr()==="darwin"?"open":yr()==="win32"?"start":"xdg-open",n=yr()==="win32"?["",e]:[e];LC(t,n,{detached:!0,stdio:"ignore",shell:yr()==="win32"}).unref()}async function ug(){let{getLicenseStatus:e}=await Promise.resolve().then(()=>(ge(),gn)),t=await e();if(t.tier==="pro"){console.log(),console.log(c.bold("Already on Pro.")),console.log(` ${c.dim("Key:")} ${t.key_short}`),console.log(` ${c.dim("Email:")} ${t.customer_email}`),console.log();return}console.log(),console.log(`${c.ok("Opening")} ${dg}`),console.log(c.dim("After purchase, run: recall activate <license-key>")),console.log(),NC(dg)}D();import{spawn as OC}from"node:child_process";import{platform as wr}from"node:os";var pg="https://clauderecall.com/pricing?trial=1&utm_source=cli&utm_medium=recall_trial";function vC(e){let t=wr()==="darwin"?"open":wr()==="win32"?"start":"xdg-open",n=wr()==="win32"?["",e]:[e];OC(t,n,{detached:!0,stdio:"ignore",shell:wr()==="win32"}).unref()}async function mg(e){if(e&&e.trim().length>0){await Sr(e);return}let{getLicenseStatus:t}=await Promise.resolve().then(()=>(ge(),gn)),n=await t();if(n.tier==="pro"){console.log(),console.log(c.bold("You are already on Pro.")),console.log(` ${c.dim("Key:")} ${n.key_short}`),console.log(` ${c.dim("Email:")} ${n.customer_email}`),console.log();return}console.log(),console.log(`${c.ok("Opening")} ${pg}`),console.log(c.dim("Enter your email to get a 7-day Pro trial link. No card.")),console.log(c.dim("After you click the verification email, run: recall activate <key>")),console.log(),console.log(c.dim("Tip: if you have a promo code, run `recall trial <CODE>` to skip the browser.")),console.log(),vC(pg)}D();mn();import{existsSync as gg,mkdirSync as IC,readFileSync as MC,writeFileSync as DC}from"node:fs";import{homedir as $C}from"node:os";import{join as fg}from"node:path";import{randomBytes as PC}from"node:crypto";var ca=fg($C(),".recall"),Rr=fg(ca,"telemetry.json"),aa={decided_at:null,decision:null,last_ping_month:null,nonce_month:null,nonce:null,last_error:null};function vt(){if(!gg(Rr))return{...aa};try{let e=MC(Rr,"utf8"),t=JSON.parse(e);return{...aa,...t}}catch{return{...aa}}}function Tr(e){gg(ca)||IC(ca,{recursive:!0}),DC(Rr,JSON.stringify(e,null,2)+`
1868
+ `,{mode:384})}function _g(){return Rr}function la(e=new Date){let t=e.getUTCFullYear(),n=String(e.getUTCMonth()+1).padStart(2,"0");return`${t}-${n}`}function hg(e,t){return e.nonce&&e.nonce_month===t?e:{...e,nonce:PC(16).toString("hex"),nonce_month:t}}function FC(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 Eg(e){let t=vt();if(t.decision!=="on")return{status:t.decision==="off"?"opted-out":"no-decision"};let n=la();if(t.last_ping_month===n)return{status:"already-this-month"};t=hg(t,n);let s=FC(e,t);if(!s)return{status:"error",detail:"no nonce"};try{let r=await fetch(`${dt()}/api/install-ping`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s),signal:AbortSignal.timeout(5e3)});if(!r.ok){let i=`http ${r.status}`;return Tr({...t,last_error:`${new Date().toISOString()} ${i}`}),{status:"error",detail:i}}let o=await r.json().catch(()=>({}));return Tr({...t,last_ping_month:n,last_error:null}),{status:o.deduped?"deduped":"sent"}}catch(r){let o=r instanceof Error?r.message:"unknown";return Tr({...t,last_error:`${new Date().toISOString()} ${o}`}),{status:"error",detail:o}}}function Zt(e){let n={...vt(),decision:e,decided_at:new Date().toISOString(),last_error:null,...e==="off"?{nonce:null,nonce_month:null,last_ping_month:null}:{}};return Tr(n),n}function kr(e){let t=hg(vt(),la());return{event:"install",version:e,platform:process.platform,arch:process.arch,month:t.nonce_month??la(),nonce:t.nonce??"0".repeat(32)}}async function da(e){let t=vt();console.log(),console.log(c.bold("Telemetry \u2014 anonymous install ping")),console.log(` ${c.dim("decision:")} ${t.decision??"not yet decided"}`),console.log(` ${c.dim("decided at:")} ${t.decided_at??"\u2014"}`),console.log(` ${c.dim("last ping:")} ${t.last_ping_month??"\u2014"}`),console.log(` ${c.dim("state file:")} ${_g()}`),t.last_error&&console.log(` ${c.warn("last error:")} ${t.last_error}`),console.log(),console.log(c.dim("Next-ping payload preview (only sent if decision = on):")),console.log(c.dim(JSON.stringify(kr(e),null,2))),console.log(),console.log(c.dim("Toggle with `recall telemetry on` / `recall telemetry off`.")),console.log(c.dim("Full disclosure: https://clauderecall.com/telemetry")),console.log()}async function bg(){Zt("on"),console.log(),console.log(c.ok("Telemetry: opted in.")),console.log(c.dim("One anonymous ping per machine per month. No PII. Source: docs/specs/v0.16-install-ping.md")),console.log(c.dim("Reverse with `recall telemetry off`.")),console.log()}async function Sg(){Zt("off"),console.log(),console.log(c.ok("Telemetry: opted out.")),console.log(c.dim("No further pings will be sent. Existing nonce deleted.")),console.log()}async function yg(e){await da(e)}import{createInterface as jC}from"node:readline/promises";import{stdin as wg,stdout as Ee}from"node:process";var UC=new Set(["telemetry","trial","upgrade","activate","license","help","version"]);function BC(e){return!(process.env.CI==="true"||process.env.RECALL_QUIET_INSTALL==="1"||process.env.RECALL_DISABLE_TELEMETRY_PROMPT==="1"||!wg.isTTY||!Ee.isTTY||e&&UC.has(e)||vt().decision!==null)}async function Tg(e,t){if(!BC(e))return;let n=kr(t);Ee.write(`
1858
1869
  `),Ee.write(` Claude Recall \u2014 anonymous install ping?
1859
1870
 
1860
1871
  `),Ee.write(` npm download counts mix real installs with bots and scanners.
@@ -1870,55 +1881,55 @@ Toggle with: recall verify on | off
1870
1881
 
1871
1882
  `),Ee.write(` Full disclosure: https://clauderecall.com/telemetry
1872
1883
 
1873
- `);let s=bC({input:dg,output:Ee}),r;try{r=(await s.question(" Send the install ping? [y/N]: ")).trim().toLowerCase()}finally{s.close()}r==="y"||r==="yes"?(Zt("on"),Ee.write(`
1884
+ `);let s=jC({input:wg,output:Ee}),r;try{r=(await s.question(" Send the install ping? [y/N]: ")).trim().toLowerCase()}finally{s.close()}r==="y"||r==="yes"?(Zt("on"),Ee.write(`
1874
1885
  Opted in. Reverse any time with \`recall telemetry off\`.
1875
1886
 
1876
1887
  `)):(Zt("off"),Ee.write(`
1877
1888
  Opted out. No pings will be sent. Reverse with \`recall telemetry on\`.
1878
1889
 
1879
- `))}hi();var wC="RECALL_NO_BANNER",TC=new Set(["doctor"]),pg=!1;function mg(e){if(pg||TC.has(e.commandName)||(e.optOut!==void 0?e.optOut:process.env[wC]==="1"))return 0;let n=e.write??(r=>process.stderr.write(r)),s=0;try{let r=Ks(),o=vu(r,"critical");if(o.length===0)return 0;s=o.length,n(RC(o)),pg=!0}catch{return 0}return s}function RC(e){let t=[];t.push(""),t.push(`! ${e.length} unacknowledged critical alert(s) from background doctor:`);for(let n of e.slice(0,5))t.push(` - [${n.id.slice(0,8)}] ${n.message}`);return e.length>5&&t.push(` \u2026 and ${e.length-5} more (run \`recall doctor\` for the full list).`),t.push("Run `recall doctor` for full details. Acknowledge with `recall doctor --ack <id>`."),t.push(""),t.join(`
1880
- `)}$();ge();Bt();po();async function gg(){let e=await Le();if(console.log(),e.tier==="free"){console.log(c.bold("Tier: Free")),console.log(c.dim("Free includes: index, list, show, projects, status, the daemon, and the basic web UI.")),e.invalid_reason&&(console.log(),console.log(c.warn(`Stored license is invalid: ${e.invalid_reason}`))),console.log(),console.log("Buy Pro at https://clauderecall.com/pricing"),console.log("Then run: recall activate <license-key>"),console.log();return}console.log(c.bold("Tier: Pro")),console.log(` ${c.dim("Key:")} ${e.key_short}`),console.log(` ${c.dim("Email:")} ${e.customer_email}`),console.log(` ${c.dim("Activated:")} ${e.activated_at}`),e.expires_at&&console.log(` ${c.dim("Expires:")} ${e.expires_at}`),e.test_mode&&console.log(` ${c.warn("Test mode:")} this license was issued in test mode.`);let t=os();t&&console.log(` ${c.dim("Last server check:")} ${t.last_checked_at}`),console.log()}async function fg(){let e=await _o({force:!0});if(console.log(),!e.ran){console.log(c.warn("No license stored on this machine.")),console.log(c.dim("Run `recall activate <license-key>` first.")),console.log();return}if(!e.last_checked_at){console.log(c.warn("Could not reach the license server.")),console.log(c.dim("Network error. Try again when you have a connection.")),console.log();return}if(e.revoked){console.log(c.warn("License is revoked.")),e.reason&&console.log(` ${c.dim("Reason:")} ${e.reason}`),console.log(` ${c.dim("Checked:")} ${e.last_checked_at}`),console.log();return}console.log(c.ok("License is valid.")),console.log(` ${c.dim("Checked:")} ${e.last_checked_at}`),console.log()}function _g(){wc(),console.log(),console.log("License removed from this machine."),console.log(c.dim(`(${Ct})`)),console.log()}k();$();import kC from"cli-table3";function je(e){let t=E();if(e.length>=32){let s=t.prepare("SELECT id FROM threads WHERE id = ?").get(e);return s?s.id:(process.stderr.write(`thread not found: ${e}
1890
+ `))}bi();var HC="RECALL_NO_BANNER",WC=new Set(["doctor"]),Rg=!1;function kg(e){if(Rg||WC.has(e.commandName)||(e.optOut!==void 0?e.optOut:process.env[HC]==="1"))return 0;let n=e.write??(r=>process.stderr.write(r)),s=0;try{let r=Qs(),o=Fu(r,"critical");if(o.length===0)return 0;s=o.length,n(XC(o)),Rg=!0}catch{return 0}return s}function XC(e){let t=[];t.push(""),t.push(`! ${e.length} unacknowledged critical alert(s) from background doctor:`);for(let n of e.slice(0,5))t.push(` - [${n.id.slice(0,8)}] ${n.message}`);return e.length>5&&t.push(` \u2026 and ${e.length-5} more (run \`recall doctor\` for the full list).`),t.push("Run `recall doctor` for full details. Acknowledge with `recall doctor --ack <id>`."),t.push(""),t.join(`
1891
+ `)}D();ge();Bt();go();async function xg(){let e=await Ae();if(console.log(),e.tier==="free"){console.log(c.bold("Tier: Free")),console.log(c.dim("Free includes: index, list, show, projects, status, the daemon, and the basic web UI.")),e.invalid_reason&&(console.log(),console.log(c.warn(`Stored license is invalid: ${e.invalid_reason}`))),console.log(),console.log("Buy Pro at https://clauderecall.com/pricing"),console.log("Then run: recall activate <license-key>"),console.log();return}console.log(c.bold("Tier: Pro")),console.log(` ${c.dim("Key:")} ${e.key_short}`),console.log(` ${c.dim("Email:")} ${e.customer_email}`),console.log(` ${c.dim("Activated:")} ${e.activated_at}`),e.expires_at&&console.log(` ${c.dim("Expires:")} ${e.expires_at}`),e.test_mode&&console.log(` ${c.warn("Test mode:")} this license was issued in test mode.`);let t=is();t&&console.log(` ${c.dim("Last server check:")} ${t.last_checked_at}`),console.log()}async function Cg(){let e=await Eo({force:!0});if(console.log(),!e.ran){console.log(c.warn("No license stored on this machine.")),console.log(c.dim("Run `recall activate <license-key>` first.")),console.log();return}if(!e.last_checked_at){console.log(c.warn("Could not reach the license server.")),console.log(c.dim("Network error. Try again when you have a connection.")),console.log();return}if(e.revoked){console.log(c.warn("License is revoked.")),e.reason&&console.log(` ${c.dim("Reason:")} ${e.reason}`),console.log(` ${c.dim("Checked:")} ${e.last_checked_at}`),console.log();return}console.log(c.ok("License is valid.")),console.log(` ${c.dim("Checked:")} ${e.last_checked_at}`),console.log()}function Ag(){Cc(),console.log(),console.log("License removed from this machine."),console.log(c.dim(`(${Ct})`)),console.log()}k();D();import GC from"cli-table3";function Ue(e){let t=h();if(e.length>=32){let s=t.prepare("SELECT id FROM threads WHERE id = ?").get(e);return s?s.id:(process.stderr.write(`thread not found: ${e}
1881
1892
  `),null)}let n=t.prepare("SELECT id, name FROM threads WHERE id LIKE ? ORDER BY created_at DESC").all(e+"%");if(n.length===1)return n[0].id;if(n.length===0)return process.stderr.write(`no thread matches prefix "${e}"
1882
1893
  `),null;process.stderr.write(`ambiguous thread prefix "${e}" \u2014 candidates:
1883
1894
  `);for(let s of n)process.stderr.write(` ${X(s.id)} ${s.name}
1884
- `);return null}function It(e){let t=E();if(e.length>=32){let s=t.prepare("SELECT id FROM sessions WHERE id = ?").get(e);return s?s.id:(process.stderr.write(`session not found: ${e}
1895
+ `);return null}function It(e){let t=h();if(e.length>=32){let s=t.prepare("SELECT id FROM sessions WHERE id = ?").get(e);return s?s.id:(process.stderr.write(`session not found: ${e}
1885
1896
  `),null)}let n=t.prepare("SELECT id FROM sessions WHERE id LIKE ? LIMIT 2").all(e+"%");return n.length===1?n[0].id:n.length===0?(process.stderr.write(`no session matches prefix "${e}"
1886
1897
  `),null):(process.stderr.write(`ambiguous session prefix "${e}". be more specific.
1887
- `),null)}function xC(e){let t=new Map;if(e.length===0)return t;let n=e.map(()=>"?").join(","),r=E().prepare(`SELECT s.id,
1898
+ `),null)}function JC(e){let t=new Map;if(e.length===0)return t;let n=e.map(()=>"?").join(","),r=h().prepare(`SELECT s.id,
1888
1899
  s.first_user_message,
1889
1900
  p.name AS project_name,
1890
1901
  a.alias AS alias
1891
1902
  FROM sessions s
1892
1903
  LEFT JOIN projects p ON p.id = s.project_id
1893
1904
  LEFT JOIN session_aliases a ON a.session_id = s.id
1894
- WHERE s.id IN (${n})`).all(...e);for(let o of r)t.set(o.id,o);return t}function hg(e,t){let n=t.get(e),s=c.accent(X(e));if(!n)return`${s} ${c.dim("(unindexed)")}`;let r=n.alias??n.first_user_message??"",o=n.project_name?c.project(`[${n.project_name}] `):"";return`${s} ${o}${Q(r,80)}`}function ia(e){return e.archived?"archived":e.closed_at?"closed":"open"}function en(e){let t=ia(e);process.stderr.write(c.ok(`\u2713 ${e.name} ${c.dim(`(${X(e.id)})`)} [${t}]
1905
+ WHERE s.id IN (${n})`).all(...e);for(let o of r)t.set(o.id,o);return t}function Lg(e,t){let n=t.get(e),s=c.accent(X(e));if(!n)return`${s} ${c.dim("(unindexed)")}`;let r=n.alias??n.first_user_message??"",o=n.project_name?c.project(`[${n.project_name}] `):"";return`${s} ${o}${Q(r,80)}`}function ua(e){return e.archived?"archived":e.closed_at?"closed":"open"}function en(e){let t=ua(e);process.stderr.write(c.ok(`\u2713 ${e.name} ${c.dim(`(${X(e.id)})`)} [${t}]
1895
1906
  `))}function Oe(e,t,n){if(e){process.stdout.write(JSON.stringify(t,null,2)+`
1896
- `);return}n()}function Eg(e){let t=To({includeArchived:e.archived===!0});Oe(e.json===!0,t,()=>{if(t.length===0){console.log(c.dim("no threads. create one with `recall thread new <name>`."));return}let n=new kC({head:[c.bold("id"),c.bold("name"),c.bold("sessions"),c.bold("origins"),c.bold("status"),c.bold("created")],colWidths:[10,40,10,9,10,16],wordWrap:!0,style:{head:[],border:["grey"]}});for(let s of t)n.push([c.accent(X(s.id)),Q(s.name,38),String(s.session_count),String(s.origin_count),ia(s),c.dim(G(s.created_at))]);console.log(n.toString()),console.log(c.dim(`${t.length} thread${t.length===1?"":"s"}.`+(e.archived?"":" add --archived to include archived.")))})}function CC(e,t){let n=new Set(e.edges.map(a=>a.session_id)),s=new Map,r=[];for(let a of e.edges){let d=a.parent_session_id;if(a.role==="origin"||!d||!n.has(d)){r.push(a);continue}let l=s.get(d)??[];l.push(a),s.set(d,l)}let o=new Set,i=(a,d,l,u)=>{if(o.has(a.session_id))return;o.add(a.session_id);let m=u?"":l?"\u2514\u2500 ":"\u251C\u2500 ",p=a.role==="origin"?c.warn("[origin] "):"";process.stdout.write(`${d}${m}${p}${hg(a.session_id,t)}
1897
- `);let g=s.get(a.session_id)??[],f=u?"":d+(l?" ":"\u2502 ");g.forEach((h,_)=>{i(h,f,_===g.length-1,!1)})};r.forEach((a,d)=>i(a,"",d===r.length-1,!0));for(let a of e.edges)o.has(a.session_id)||process.stdout.write(`${c.warn("? ")}${hg(a.session_id,t)}
1898
- `)}function bg(e,t){let n=je(e);if(!n){process.exitCode=1;return}let s=$e(n);if(!s){process.stderr.write(`thread not found: ${e}
1899
- `),process.exitCode=1;return}let r=xC(s.edges.map(o=>o.session_id));Oe(t.json===!0,s,()=>{let o=ia(s);if(console.log(c.bold(s.name)),console.log(c.dim(`id ${X(s.id)} \xB7 ${o} \xB7 ${s.session_count} session${s.session_count===1?"":"s"} \xB7 ${s.origin_count} origin${s.origin_count===1?"":"s"} \xB7 created ${G(s.created_at)}`)),s.summary&&console.log(s.summary),console.log(),s.edges.length===0){console.log(c.dim("(no sessions linked \u2014 use `recall thread link ...`)"));return}CC(s,r)})}function Sg(e,t){let n;if(t.origin){let r=It(t.origin);if(!r){process.exitCode=1;return}n=r}let s=ml({name:e,summary:t.summary??null,originSessionId:n});Oe(t.json===!0,s,()=>{en(s),process.stderr.write(c.dim(`id ${s.id}
1907
+ `);return}n()}function Ng(e){let t=ko({includeArchived:e.archived===!0});Oe(e.json===!0,t,()=>{if(t.length===0){console.log(c.dim("no threads. create one with `recall thread new <name>`."));return}let n=new GC({head:[c.bold("id"),c.bold("name"),c.bold("sessions"),c.bold("origins"),c.bold("status"),c.bold("created")],colWidths:[10,40,10,9,10,16],wordWrap:!0,style:{head:[],border:["grey"]}});for(let s of t)n.push([c.accent(X(s.id)),Q(s.name,38),String(s.session_count),String(s.origin_count),ua(s),c.dim(G(s.created_at))]);console.log(n.toString()),console.log(c.dim(`${t.length} thread${t.length===1?"":"s"}.`+(e.archived?"":" add --archived to include archived.")))})}function zC(e,t){let n=new Set(e.edges.map(a=>a.session_id)),s=new Map,r=[];for(let a of e.edges){let d=a.parent_session_id;if(a.role==="origin"||!d||!n.has(d)){r.push(a);continue}let l=s.get(d)??[];l.push(a),s.set(d,l)}let o=new Set,i=(a,d,l,u)=>{if(o.has(a.session_id))return;o.add(a.session_id);let m=u?"":l?"\u2514\u2500 ":"\u251C\u2500 ",p=a.role==="origin"?c.warn("[origin] "):"";process.stdout.write(`${d}${m}${p}${Lg(a.session_id,t)}
1908
+ `);let g=s.get(a.session_id)??[],f=u?"":d+(l?" ":"\u2502 ");g.forEach((_,b)=>{i(_,f,b===g.length-1,!1)})};r.forEach((a,d)=>i(a,"",d===r.length-1,!0));for(let a of e.edges)o.has(a.session_id)||process.stdout.write(`${c.warn("? ")}${Lg(a.session_id,t)}
1909
+ `)}function Og(e,t){let n=Ue(e);if(!n){process.exitCode=1;return}let s=Pe(n);if(!s){process.stderr.write(`thread not found: ${e}
1910
+ `),process.exitCode=1;return}let r=JC(s.edges.map(o=>o.session_id));Oe(t.json===!0,s,()=>{let o=ua(s);if(console.log(c.bold(s.name)),console.log(c.dim(`id ${X(s.id)} \xB7 ${o} \xB7 ${s.session_count} session${s.session_count===1?"":"s"} \xB7 ${s.origin_count} origin${s.origin_count===1?"":"s"} \xB7 created ${G(s.created_at)}`)),s.summary&&console.log(s.summary),console.log(),s.edges.length===0){console.log(c.dim("(no sessions linked \u2014 use `recall thread link ...`)"));return}zC(s,r)})}function vg(e,t){let n;if(t.origin){let r=It(t.origin);if(!r){process.exitCode=1;return}n=r}let s=El({name:e,summary:t.summary??null,originSessionId:n});Oe(t.json===!0,s,()=>{en(s),process.stderr.write(c.dim(`id ${s.id}
1900
1911
  `)),n&&process.stderr.write(c.dim(`origin: ${X(n)}
1901
- `))})}function yg(e,t){let n=je(t.thread);if(!n){process.exitCode=1;return}let s=It(e);if(!s){process.exitCode=1;return}let r=null;if(t.parent){let a=It(t.parent);if(!a){process.exitCode=1;return}r=a}let o=t.role??(r?"child":"origin"),i=gl({threadId:n,sessionId:s,parentSessionId:r,role:o});Oe(t.json===!0,i,()=>{process.stderr.write(c.ok(`\u2713 linked ${X(s)} \u2192 ${X(n)} [${o}]
1902
- `))})}function wg(e,t){let n=je(t.thread);if(!n){process.exitCode=1;return}let s=It(e);if(!s){process.exitCode=1;return}let r=fl(n,s);Oe(t.json===!0,r,()=>{if(r.removed===0){process.stderr.write(c.warn(`(no edge existed for ${X(s)} in ${X(n)})
1912
+ `))})}function Ig(e,t){let n=Ue(t.thread);if(!n){process.exitCode=1;return}let s=It(e);if(!s){process.exitCode=1;return}let r=null;if(t.parent){let a=It(t.parent);if(!a){process.exitCode=1;return}r=a}let o=t.role??(r?"child":"origin"),i=bl({threadId:n,sessionId:s,parentSessionId:r,role:o});Oe(t.json===!0,i,()=>{process.stderr.write(c.ok(`\u2713 linked ${X(s)} \u2192 ${X(n)} [${o}]
1913
+ `))})}function Mg(e,t){let n=Ue(t.thread);if(!n){process.exitCode=1;return}let s=It(e);if(!s){process.exitCode=1;return}let r=Sl(n,s);Oe(t.json===!0,r,()=>{if(r.removed===0){process.stderr.write(c.warn(`(no edge existed for ${X(s)} in ${X(n)})
1903
1914
  `));return}process.stderr.write(c.ok(`\u2713 unlinked ${X(s)} from ${X(n)}
1904
- `))})}function Tg(e,t){let n=je(t.thread);if(!n){process.exitCode=1;return}let s=It(e);if(!s){process.exitCode=1;return}let r=null;if(t.parent&&t.parent.toLowerCase()!=="none"){let i=It(t.parent);if(!i){process.exitCode=1;return}r=i}let o=_l(n,s,r);Oe(t.json===!0,o,()=>{process.stderr.write(c.ok(`\u2713 ${X(s)} in ${X(n)} \u2192 `+(r?`child of ${X(r)}`:"origin")+`
1905
- `))})}function Rg(e,t,n){let s=je(e);if(!s){process.exitCode=1;return}let r=hl(s,t);Oe(n.json===!0,r,()=>en(r))}function kg(e,t){let n=je(e);if(!n){process.exitCode=1;return}let s=El(n);Oe(t.json===!0,s,()=>en(s))}function xg(e,t){let n=je(e);if(!n){process.exitCode=1;return}let s=bl(n);Oe(t.json===!0,s,()=>en(s))}function Cg(e,t){let n=je(e);if(!n){process.exitCode=1;return}let s=Sl(n);Oe(t.json===!0,s,()=>en(s))}function Lg(e,t){let n=je(e);if(!n){process.exitCode=1;return}let s=je(t.into);if(!s){process.exitCode=1;return}if(n===s){process.stderr.write(c.err(`cannot merge a thread into itself
1906
- `)),process.exitCode=1;return}let r=yl(n,s);Oe(t.json===!0,r,()=>{process.stderr.write(c.ok(`\u2713 merged ${X(n)} \u2192 ${X(s)} (${r.session_count} sessions)
1907
- `))})}function Ag(e,t){let n=je(e);if(!n){process.exitCode=1;return}let s=t.sessions.split(",").map(i=>i.trim()).filter(Boolean);if(s.length===0){process.stderr.write(c.err(`--sessions must be a non-empty comma-separated list
1908
- `)),process.exitCode=1;return}let r=[];for(let i of s){let a=It(i);if(!a){process.exitCode=1;return}r.push(a)}let o=wl({threadId:n,sessionIds:r,newThreadName:t.name});Oe(t.json===!0,o,()=>{en(o),process.stderr.write(c.dim(`split off ${r.length} session${r.length===1?"":"s"} from ${X(n)}
1909
- `))})}k();$();import{randomUUID as VC}from"node:crypto";import{readFileSync as LC,statSync as AC}from"node:fs";var NC=200*1024*1024,ca=.7,la=.5,vg=la,OC=[{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"}],vC=["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 Ng(e){if(!e)return null;if(e.startsWith("/")){let n=e.split(" \xB7 ");if(n.length>1)return n[1].trim().toLowerCase()}let t=e.split(" \xB7 ");return t.length>1?t[t.length-1].trim().toLowerCase():null}function IC(e,t){let n=t-e;if(n<0)return{weight:0,label:null};for(let s of OC)if(n<=s.maxGapMs)return{weight:s.weight,label:s.label};return{weight:0,label:null}}function MC(e){if(e.length===0)return{weight:0,matched:null,matchedIndex:-1};let t=[.4,.35,.3,.25,.2,.15,.1],n=Math.min(e.length,t.length);for(let s=0;s<n;s++){let r=e[s];if(!r)continue;let o=r.toLowerCase();for(let i of vC)if(o.includes(i))return{weight:t[s],matched:i,matchedIndex:s}}return{weight:0,matched:null,matchedIndex:-1}}function aa(e,t){if(!e||!t||e.length!==t.length)return 0;let n=0;for(let s=0;s<e.length;s++)n+=e[s]*t[s];return n<-1?-1:n>1?1:n}function DC(e,t){if(e.length===0||t.length===0)return 0;let n=0;for(let s of e)for(let r of t){let o=aa(s,r);o>n&&(n=o)}return n}function $C(e,t){let n=aa(e.mean_embedding,t.mean_embedding),s=aa(e.tail_pool,t.head_pool),r=DC(e.sample_chunks,t.sample_chunks),o=0,i=null;if(n>o&&(o=n,i="mean"),s>o&&(o=s,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 PC(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 FC(e,t){if(e.size===0||t.size===0)return{weight:0,count:0};let n=0;for(let r of t)e.has(r)&&n++;return n===0?{weight:0,count:0}:{weight:Math.min(.4,n*.1),count:n}}function jC(e,t){let n=Ng(e),s=Ng(t);return n&&s&&n===s?{weight:.1,brand:n}:{weight:0,brand:null}}function Og(e){return e.replace(/\s+/g," ").trim().toLowerCase()}function UC(e,t){let n=0,s=null,r=!1;if(e.authored_paths.size>0){let o=t.recent_user_messages.slice(0,3).join(`
1910
- `).toLowerCase();for(let i of e.authored_paths){let a=i.toLowerCase();if(t.touched_files.has(i)||o.includes(a)){n+=.5,s=i;break}}}if(e.authored_content.length>0&&t.recent_user_messages[0]){let o=Og(t.recent_user_messages[0]);if(o.length>=200)for(let i of e.authored_content){let a=Og(i);if(a.length<200)continue;let d=Math.min(a.length,240),l=a.slice(0,d);if(o.includes(l)){n+=.4,r=!0;break}}}return{weight:Math.min(.6,n),pathMatch:s,contentMatch:r}}function BC(e,t,n=vg){if(t.started_at_ms<=e.started_at_ms)return null;let s=e.ended_at_ms??e.started_at_ms;if(t.started_at_ms<s)return null;let r=IC(s,t.started_at_ms),o=t.recent_user_messages.length>0?t.recent_user_messages:t.first_user_message?[t.first_user_message]:[],i=MC(o),a=FC(e.touched_files,t.touched_files),d=jC(e.auto_title,t.auto_title),l=$C(e,t),u=PC(e,t),m=UC(e,t),p=r.weight+i.weight+a.weight+d.weight+l.weight+u.weight+m.weight;if(p<n)return null;let g=[];if(r.label&&g.push(`temporal ${r.label} (+${r.weight})`),i.matched){let f=i.matchedIndex===0?"opening message":`message #${i.matchedIndex+1}`;g.push(`continuation phrase "${i.matched}" in ${f} (+${i.weight})`)}if(a.count>0&&g.push(`${a.count} file${a.count===1?"":"s"} overlap (+${a.weight.toFixed(1)})`),d.brand&&g.push(`shared brand "${d.brand}" (+${d.weight})`),l.weight>0&&l.mode&&g.push(`semantic ${l.mode==="asymmetric"?"tail\u2192head":l.mode==="max_pool"?"best-chunk":"mean"} ${l.cosine.toFixed(2)} (+${l.weight.toFixed(2)})`),u.same&&g.push(`same cluster (+${u.weight})`),m.weight>0){let f=[];m.pathMatch&&f.push(`opened authored path "${m.pathMatch.split("/").pop()}"`),m.contentMatch&&f.push("verbatim-paste of authored content"),g.push(`doc-authorship: ${f.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:d.weight,semantic:l.weight,cluster:u.weight,doc_authorship:m.weight},reasons:g}}function Ig(e,t=vg){let n=[];for(let s=0;s<e.length;s++){let r=e[s],o=null;for(let i=0;i<s;i++){let a=e[i],d=BC(a,r,t);d&&(!o||d.confidence>o.confidence)&&(o=d)}o&&n.push(o)}return n}function Mg(e,t){let n=new Map,s=a=>{let d=a;for(;n.get(d)!==d;)d=n.get(d);let l=a;for(;n.get(l)!==d;){let u=n.get(l);n.set(l,d),l=u}return d},r=(a,d)=>{let l=s(a),u=s(d);l!==u&&n.set(l,u)};for(let a of e)n.has(a.parent_id)||n.set(a.parent_id,a.parent_id),n.has(a.child_id)||n.set(a.child_id,a.child_id),r(a.parent_id,a.child_id);let o=new Map;for(let a of n.keys()){let d=s(a),l=o.get(d);l||(l=[],o.set(d,l)),l.push(a)}let i=new Map;for(let a of t)i.set(a.id,a.started_at_ms);return Array.from(o.values()).map(a=>(a.sort((d,l)=>(i.get(d)??0)-(i.get(l)??0)),{rootId:a[0],sessionIds:a}))}function Dg(e,t={}){let n=t.maxUserMessages??5,s=t.userMessageMaxLen??2e3,r=new Set,o=[],i=new Set,a=[],d;try{if(AC(e).size>NC)return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a};d=LC(e,"utf8")}catch{return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a}}let l=0;for(;l<d.length;){let u=d.indexOf(`
1911
- `,l),m=u===-1?d.length:u,p=d.slice(l,m);if(l=u===-1?d.length:u+1,!p.trim())continue;let g;try{g=JSON.parse(p)}catch{continue}let f=g;if(f.type==="user"&&f.message?.role==="user"&&typeof f.message.content=="string"&&o.length<n){let _=f.message.content.trim();_&&o.push(_.length>s?_.slice(0,s):_)}let h=f.message?.content;if(Array.isArray(h))for(let _ of h){if(!_||typeof _!="object")continue;let b=_;if(b.type!=="tool_use")continue;let S=b.input??{},y=typeof S.file_path=="string"?S.file_path:null;if(y){let T=Rr(y);T&&r.add(T)}if((b.name==="Write"||b.name==="Edit"||b.name==="MultiEdit")&&y){let T=Rr(y);T&&i.add(T);let R=typeof S.content=="string"?S.content:typeof S.new_string=="string"?S.new_string:null;R&&R.length>=200&&a.push(R.length>4096?R.slice(0,4096):R)}if(b.name==="Bash"&&typeof S.command=="string")for(let T of S.command.matchAll(/(?:^|[\s'"`(=])((?:\.\.?\/|\/|src\/|test\/|docs\/|site\/)[A-Za-z0-9_./-]+)/g)){let R=Rr(T[1]);R&&r.add(R)}if((b.name==="Glob"||b.name==="Grep")&&typeof S.pattern=="string"){let T=Rr(S.pattern);T&&!T.includes("*")&&r.add(T)}}}return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a}}function Rr(e){let t=e.trim().replace(/^['"]|['"]$/g,"");return!t||t.length<4||/[<>|;&\$`]/.test(t)?null:t}k();var $g=10,Pg=20;function HC(e){if(!e)return!1;let t=e.split(`
1912
- `);if(t.length<4)return!1;let n=0,s=0;for(let r of t)/^\s*\d{1,5}\t/.test(r)?n++:/^\s*\/[A-Za-z0-9_./-]+/.test(r.trim())&&s++;return n/t.length>.7||s/t.length>.5}function WC(e){let t=e.byteLength/4;if(!Number.isInteger(t)||t<=0)return null;let n=new Float32Array(t),s=new Float32Array(e.buffer,e.byteOffset,t);return n.set(s),n}function Fg(e){let t=0;for(let s=0;s<e.length;s++)t+=e[s]*e[s];if(t<=0)return!1;let n=1/Math.sqrt(t);for(let s=0;s<e.length;s++)e[s]*=n;return!0}function da(e){if(e.length===0)return null;let t=e[0].length,n=new Float32Array(t);for(let s of e)if(s.length===t)for(let r=0;r<t;r++)n[r]+=s[r];for(let s=0;s<t;s++)n[s]/=e.length;return Fg(n)?n:null}function jg(e){let t=new Map;if(e.length===0)return t;let n=E(),s=e.map(()=>"?").join(","),r=[];try{r=n.prepare(`SELECT cm.rowid AS rowid, cm.session_id AS session_id,
1915
+ `))})}function Dg(e,t){let n=Ue(t.thread);if(!n){process.exitCode=1;return}let s=It(e);if(!s){process.exitCode=1;return}let r=null;if(t.parent&&t.parent.toLowerCase()!=="none"){let i=It(t.parent);if(!i){process.exitCode=1;return}r=i}let o=yl(n,s,r);Oe(t.json===!0,o,()=>{process.stderr.write(c.ok(`\u2713 ${X(s)} in ${X(n)} \u2192 `+(r?`child of ${X(r)}`:"origin")+`
1916
+ `))})}function $g(e,t,n){let s=Ue(e);if(!s){process.exitCode=1;return}let r=wl(s,t);Oe(n.json===!0,r,()=>en(r))}function Pg(e,t){let n=Ue(e);if(!n){process.exitCode=1;return}let s=Tl(n);Oe(t.json===!0,s,()=>en(s))}function Fg(e,t){let n=Ue(e);if(!n){process.exitCode=1;return}let s=Rl(n);Oe(t.json===!0,s,()=>en(s))}function jg(e,t){let n=Ue(e);if(!n){process.exitCode=1;return}let s=kl(n);Oe(t.json===!0,s,()=>en(s))}function Ug(e,t){let n=Ue(e);if(!n){process.exitCode=1;return}let s=Ue(t.into);if(!s){process.exitCode=1;return}if(n===s){process.stderr.write(c.err(`cannot merge a thread into itself
1917
+ `)),process.exitCode=1;return}let r=xl(n,s);Oe(t.json===!0,r,()=>{process.stderr.write(c.ok(`\u2713 merged ${X(n)} \u2192 ${X(s)} (${r.session_count} sessions)
1918
+ `))})}function Bg(e,t){let n=Ue(e);if(!n){process.exitCode=1;return}let s=t.sessions.split(",").map(i=>i.trim()).filter(Boolean);if(s.length===0){process.stderr.write(c.err(`--sessions must be a non-empty comma-separated list
1919
+ `)),process.exitCode=1;return}let r=[];for(let i of s){let a=It(i);if(!a){process.exitCode=1;return}r.push(a)}let o=Cl({threadId:n,sessionIds:r,newThreadName:t.name});Oe(t.json===!0,o,()=>{en(o),process.stderr.write(c.dim(`split off ${r.length} session${r.length===1?"":"s"} from ${X(n)}
1920
+ `))})}k();D();import{randomUUID as _A}from"node:crypto";import{readFileSync as YC,statSync as qC}from"node:fs";var VC=200*1024*1024,ma=.7,ga=.5,Xg=ga,KC=[{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"}],QC=["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 Hg(e){if(!e)return null;if(e.startsWith("/")){let n=e.split(" \xB7 ");if(n.length>1)return n[1].trim().toLowerCase()}let t=e.split(" \xB7 ");return t.length>1?t[t.length-1].trim().toLowerCase():null}function ZC(e,t){let n=t-e;if(n<0)return{weight:0,label:null};for(let s of KC)if(n<=s.maxGapMs)return{weight:s.weight,label:s.label};return{weight:0,label:null}}function eA(e){if(e.length===0)return{weight:0,matched:null,matchedIndex:-1};let t=[.4,.35,.3,.25,.2,.15,.1],n=Math.min(e.length,t.length);for(let s=0;s<n;s++){let r=e[s];if(!r)continue;let o=r.toLowerCase();for(let i of QC)if(o.includes(i))return{weight:t[s],matched:i,matchedIndex:s}}return{weight:0,matched:null,matchedIndex:-1}}function pa(e,t){if(!e||!t||e.length!==t.length)return 0;let n=0;for(let s=0;s<e.length;s++)n+=e[s]*t[s];return n<-1?-1:n>1?1:n}function tA(e,t){if(e.length===0||t.length===0)return 0;let n=0;for(let s of e)for(let r of t){let o=pa(s,r);o>n&&(n=o)}return n}function nA(e,t){let n=pa(e.mean_embedding,t.mean_embedding),s=pa(e.tail_pool,t.head_pool),r=tA(e.sample_chunks,t.sample_chunks),o=0,i=null;if(n>o&&(o=n,i="mean"),s>o&&(o=s,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 sA(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 rA(e,t){if(e.size===0||t.size===0)return{weight:0,count:0};let n=0;for(let r of t)e.has(r)&&n++;return n===0?{weight:0,count:0}:{weight:Math.min(.4,n*.1),count:n}}function oA(e,t){let n=Hg(e),s=Hg(t);return n&&s&&n===s?{weight:.1,brand:n}:{weight:0,brand:null}}function Wg(e){return e.replace(/\s+/g," ").trim().toLowerCase()}function iA(e,t){let n=0,s=null,r=!1;if(e.authored_paths.size>0){let o=t.recent_user_messages.slice(0,3).join(`
1921
+ `).toLowerCase();for(let i of e.authored_paths){let a=i.toLowerCase();if(t.touched_files.has(i)||o.includes(a)){n+=.5,s=i;break}}}if(e.authored_content.length>0&&t.recent_user_messages[0]){let o=Wg(t.recent_user_messages[0]);if(o.length>=200)for(let i of e.authored_content){let a=Wg(i);if(a.length<200)continue;let d=Math.min(a.length,240),l=a.slice(0,d);if(o.includes(l)){n+=.4,r=!0;break}}}return{weight:Math.min(.6,n),pathMatch:s,contentMatch:r}}function aA(e,t,n=Xg){if(t.started_at_ms<=e.started_at_ms)return null;let s=e.ended_at_ms??e.started_at_ms;if(t.started_at_ms<s)return null;let r=ZC(s,t.started_at_ms),o=t.recent_user_messages.length>0?t.recent_user_messages:t.first_user_message?[t.first_user_message]:[],i=eA(o),a=rA(e.touched_files,t.touched_files),d=oA(e.auto_title,t.auto_title),l=nA(e,t),u=sA(e,t),m=iA(e,t),p=r.weight+i.weight+a.weight+d.weight+l.weight+u.weight+m.weight;if(p<n)return null;let g=[];if(r.label&&g.push(`temporal ${r.label} (+${r.weight})`),i.matched){let f=i.matchedIndex===0?"opening message":`message #${i.matchedIndex+1}`;g.push(`continuation phrase "${i.matched}" in ${f} (+${i.weight})`)}if(a.count>0&&g.push(`${a.count} file${a.count===1?"":"s"} overlap (+${a.weight.toFixed(1)})`),d.brand&&g.push(`shared brand "${d.brand}" (+${d.weight})`),l.weight>0&&l.mode&&g.push(`semantic ${l.mode==="asymmetric"?"tail\u2192head":l.mode==="max_pool"?"best-chunk":"mean"} ${l.cosine.toFixed(2)} (+${l.weight.toFixed(2)})`),u.same&&g.push(`same cluster (+${u.weight})`),m.weight>0){let f=[];m.pathMatch&&f.push(`opened authored path "${m.pathMatch.split("/").pop()}"`),m.contentMatch&&f.push("verbatim-paste of authored content"),g.push(`doc-authorship: ${f.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:d.weight,semantic:l.weight,cluster:u.weight,doc_authorship:m.weight},reasons:g}}function Gg(e,t=Xg){let n=[];for(let s=0;s<e.length;s++){let r=e[s],o=null;for(let i=0;i<s;i++){let a=e[i],d=aA(a,r,t);d&&(!o||d.confidence>o.confidence)&&(o=d)}o&&n.push(o)}return n}function Jg(e,t){let n=new Map,s=a=>{let d=a;for(;n.get(d)!==d;)d=n.get(d);let l=a;for(;n.get(l)!==d;){let u=n.get(l);n.set(l,d),l=u}return d},r=(a,d)=>{let l=s(a),u=s(d);l!==u&&n.set(l,u)};for(let a of e)n.has(a.parent_id)||n.set(a.parent_id,a.parent_id),n.has(a.child_id)||n.set(a.child_id,a.child_id),r(a.parent_id,a.child_id);let o=new Map;for(let a of n.keys()){let d=s(a),l=o.get(d);l||(l=[],o.set(d,l)),l.push(a)}let i=new Map;for(let a of t)i.set(a.id,a.started_at_ms);return Array.from(o.values()).map(a=>(a.sort((d,l)=>(i.get(d)??0)-(i.get(l)??0)),{rootId:a[0],sessionIds:a}))}function zg(e,t={}){let n=t.maxUserMessages??5,s=t.userMessageMaxLen??2e3,r=new Set,o=[],i=new Set,a=[],d;try{if(qC(e).size>VC)return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a};d=YC(e,"utf8")}catch{return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a}}let l=0;for(;l<d.length;){let u=d.indexOf(`
1922
+ `,l),m=u===-1?d.length:u,p=d.slice(l,m);if(l=u===-1?d.length:u+1,!p.trim())continue;let g;try{g=JSON.parse(p)}catch{continue}let f=g;if(f.type==="user"&&f.message?.role==="user"&&typeof f.message.content=="string"&&o.length<n){let b=f.message.content.trim();b&&o.push(b.length>s?b.slice(0,s):b)}let _=f.message?.content;if(Array.isArray(_))for(let b of _){if(!b||typeof b!="object")continue;let E=b;if(E.type!=="tool_use")continue;let S=E.input??{},y=typeof S.file_path=="string"?S.file_path:null;if(y){let T=xr(y);T&&r.add(T)}if((E.name==="Write"||E.name==="Edit"||E.name==="MultiEdit")&&y){let T=xr(y);T&&i.add(T);let R=typeof S.content=="string"?S.content:typeof S.new_string=="string"?S.new_string:null;R&&R.length>=200&&a.push(R.length>4096?R.slice(0,4096):R)}if(E.name==="Bash"&&typeof S.command=="string")for(let T of S.command.matchAll(/(?:^|[\s'"`(=])((?:\.\.?\/|\/|src\/|test\/|docs\/|site\/)[A-Za-z0-9_./-]+)/g)){let R=xr(T[1]);R&&r.add(R)}if((E.name==="Glob"||E.name==="Grep")&&typeof S.pattern=="string"){let T=xr(S.pattern);T&&!T.includes("*")&&r.add(T)}}}return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a}}function xr(e){let t=e.trim().replace(/^['"]|['"]$/g,"");return!t||t.length<4||/[<>|;&\$`]/.test(t)?null:t}k();var Yg=10,qg=20;function cA(e){if(!e)return!1;let t=e.split(`
1923
+ `);if(t.length<4)return!1;let n=0,s=0;for(let r of t)/^\s*\d{1,5}\t/.test(r)?n++:/^\s*\/[A-Za-z0-9_./-]+/.test(r.trim())&&s++;return n/t.length>.7||s/t.length>.5}function lA(e){let t=e.byteLength/4;if(!Number.isInteger(t)||t<=0)return null;let n=new Float32Array(t),s=new Float32Array(e.buffer,e.byteOffset,t);return n.set(s),n}function Vg(e){let t=0;for(let s=0;s<e.length;s++)t+=e[s]*e[s];if(t<=0)return!1;let n=1/Math.sqrt(t);for(let s=0;s<e.length;s++)e[s]*=n;return!0}function fa(e){if(e.length===0)return null;let t=e[0].length,n=new Float32Array(t);for(let s of e)if(s.length===t)for(let r=0;r<t;r++)n[r]+=s[r];for(let s=0;s<t;s++)n[s]/=e.length;return Vg(n)?n:null}function Kg(e){let t=new Map;if(e.length===0)return t;let n=h(),s=e.map(()=>"?").join(","),r=[];try{r=n.prepare(`SELECT cm.rowid AS rowid, cm.session_id AS session_id,
1913
1924
  cm.text AS text, v.embedding AS embedding
1914
1925
  FROM chunk_meta cm
1915
1926
  JOIN vec_chunks v ON v.rowid = cm.rowid
1916
1927
  WHERE cm.stale = 0
1917
1928
  AND cm.session_id IN (${s})
1918
- ORDER BY cm.session_id, cm.rowid ASC`).all(...e)}catch{return t}if(r.length===0)return t;let o=new Map;for(let i of r){let a=o.get(i.session_id);a||(a=[],o.set(i.session_id,a)),a.push(i)}for(let[i,a]of o){let d=a.filter(T=>!HC(T.text)),l=d.length>0?d:a,u=[];for(let T of l){let R=WC(T.embedding);R&&Fg(R)&&u.push(R)}if(u.length===0)continue;let m=Math.min($g,u.length),p=Math.max(0,u.length-$g),g=u.slice(0,m),f=u.slice(p),h=da(g),_=da(f),b=da(u),S=new Map;for(let T=0;T<g.length&&S.size<Pg;T++)S.set(T,g[T]);for(let T=0;T<f.length&&S.size<Pg;T++)S.set(p+T,f[T]);let y=Array.from(S.values());t.set(i,{session_id:i,full_mean:b,head_pool:h,tail_pool:_,sample_chunks:y})}return t}function XC(e,t){if(e.length!==t.length)return 0;let n=0;for(let s=0;s<e.length;s++)n+=e[s]*t[s];return n<-1?-1:n>1?1:n}function Ug(e,t=.8){let n=new Map,s=[],r=[];for(let[l,u]of e)u.full_mean&&(s.push(l),r.push(u.full_mean));if(s.length===0)return n;let o=new Int32Array(s.length);for(let l=0;l<o.length;l++)o[l]=l;let i=l=>{let u=l;for(;o[u]!==u;)u=o[u];let m=l;for(;o[m]!==u;){let p=o[m];o[m]=u,m=p}return u},a=(l,u)=>{let m=i(l),p=i(u);m!==p&&(o[m]=p)};for(let l=0;l<s.length;l++)for(let u=l+1;u<s.length;u++)XC(r[l],r[u])>=t&&a(l,u);let d=new Map;for(let l=0;l<s.length;l++){let u=i(l),m=d.get(u);m===void 0&&(m=d.size,d.set(u,m)),n.set(s[l],m)}return n}var Fn={lo:.4,hi:.7},kr="claude-haiku-4-5-20251001",Bg=50;var GC={same_workflow:.15,unrelated:-.2,unsure:0};function Hg(e,t,n=Fn){if(n.lo>n.hi)throw new Error(`borderline band invalid: lo=${n.lo} > hi=${n.hi}`);let s=[];for(let r of e){if(r.confidence<n.lo||r.confidence>n.hi)continue;let o=t.get(r.parent_id),i=t.get(r.child_id);!o||!i||s.push({parent:o,child:i,step1:r})}return s.sort((r,o)=>r.child.started_at_ms-o.child.started_at_ms),s}function zC(e,t){let n=e.replace(/\s+/g," ").trim();return n.length>t?n.slice(0,t-1)+"\u2026":n}function JC(e,t){if(e===null)return"unknown";let n=t-e;if(n<0)return"overlap";let s=Math.round(n/6e4);if(s<60)return`${s}m`;let r=Math.round(n/36e5);return r<24?`${r}h`:`${Math.round(n/864e5)}d`}function YC(e){let n=e.parent.recent_user_messages,s=e.child.recent_user_messages,r=n.slice(0,3),o=n.length>3?n.slice(-3):[],i=s.slice(0,3),a=l=>l.length===0?" (none captured)":l.map(u=>` - ${zC(u,500)}`).join(`
1919
- `),d=JC(e.parent.ended_at_ms??e.parent.started_at_ms,e.child.started_at_ms);return["You are evaluating whether two Claude Code sessions belong to the same continuous workflow.","","A deterministic scorer rated this pair in the borderline band. Its signals:",e.step1.reasons.length===0?" (no signals fired strongly)":e.step1.reasons.map(l=>` - ${l}`).join(`
1929
+ ORDER BY cm.session_id, cm.rowid ASC`).all(...e)}catch{return t}if(r.length===0)return t;let o=new Map;for(let i of r){let a=o.get(i.session_id);a||(a=[],o.set(i.session_id,a)),a.push(i)}for(let[i,a]of o){let d=a.filter(T=>!cA(T.text)),l=d.length>0?d:a,u=[];for(let T of l){let R=lA(T.embedding);R&&Vg(R)&&u.push(R)}if(u.length===0)continue;let m=Math.min(Yg,u.length),p=Math.max(0,u.length-Yg),g=u.slice(0,m),f=u.slice(p),_=fa(g),b=fa(f),E=fa(u),S=new Map;for(let T=0;T<g.length&&S.size<qg;T++)S.set(T,g[T]);for(let T=0;T<f.length&&S.size<qg;T++)S.set(p+T,f[T]);let y=Array.from(S.values());t.set(i,{session_id:i,full_mean:E,head_pool:_,tail_pool:b,sample_chunks:y})}return t}function dA(e,t){if(e.length!==t.length)return 0;let n=0;for(let s=0;s<e.length;s++)n+=e[s]*t[s];return n<-1?-1:n>1?1:n}function Qg(e,t=.8){let n=new Map,s=[],r=[];for(let[l,u]of e)u.full_mean&&(s.push(l),r.push(u.full_mean));if(s.length===0)return n;let o=new Int32Array(s.length);for(let l=0;l<o.length;l++)o[l]=l;let i=l=>{let u=l;for(;o[u]!==u;)u=o[u];let m=l;for(;o[m]!==u;){let p=o[m];o[m]=u,m=p}return u},a=(l,u)=>{let m=i(l),p=i(u);m!==p&&(o[m]=p)};for(let l=0;l<s.length;l++)for(let u=l+1;u<s.length;u++)dA(r[l],r[u])>=t&&a(l,u);let d=new Map;for(let l=0;l<s.length;l++){let u=i(l),m=d.get(u);m===void 0&&(m=d.size,d.set(u,m)),n.set(s[l],m)}return n}var jn={lo:.4,hi:.7},Cr="claude-haiku-4-5-20251001",Zg=50;var uA={same_workflow:.15,unrelated:-.2,unsure:0};function ef(e,t,n=jn){if(n.lo>n.hi)throw new Error(`borderline band invalid: lo=${n.lo} > hi=${n.hi}`);let s=[];for(let r of e){if(r.confidence<n.lo||r.confidence>n.hi)continue;let o=t.get(r.parent_id),i=t.get(r.child_id);!o||!i||s.push({parent:o,child:i,step1:r})}return s.sort((r,o)=>r.child.started_at_ms-o.child.started_at_ms),s}function pA(e,t){let n=e.replace(/\s+/g," ").trim();return n.length>t?n.slice(0,t-1)+"\u2026":n}function mA(e,t){if(e===null)return"unknown";let n=t-e;if(n<0)return"overlap";let s=Math.round(n/6e4);if(s<60)return`${s}m`;let r=Math.round(n/36e5);return r<24?`${r}h`:`${Math.round(n/864e5)}d`}function gA(e){let n=e.parent.recent_user_messages,s=e.child.recent_user_messages,r=n.slice(0,3),o=n.length>3?n.slice(-3):[],i=s.slice(0,3),a=l=>l.length===0?" (none captured)":l.map(u=>` - ${pA(u,500)}`).join(`
1930
+ `),d=mA(e.parent.ended_at_ms??e.parent.started_at_ms,e.child.started_at_ms);return["You are evaluating whether two Claude Code sessions belong to the same continuous workflow.","","A deterministic scorer rated this pair in the borderline band. Its signals:",e.step1.reasons.length===0?" (no signals fired strongly)":e.step1.reasons.map(l=>` - ${l}`).join(`
1920
1931
  `),` step1_confidence: ${e.step1.confidence.toFixed(2)}`,"","PARENT SESSION","First user messages:",a(r),"Last user messages:",a(o),"",`CHILD SESSION (gap from parent: ${d})`,"First user messages:",a(i),"","Reply with EXACTLY one JSON object on a single line, no prose, no markdown:",'{"verdict":"same_workflow"|"unrelated"|"unsure","reason":"<one short sentence>"}',"","Guidance:",'- "same_workflow" = the child is clearly continuing what the parent was doing.','- "unrelated" = different problem, different files, different intent.','- "unsure" = could go either way; do not force a verdict.'].join(`
1921
- `)}function qC(e){if(!e)return null;let t=e.trim();if(!t)return null;let n=t;try{let d=JSON.parse(t);typeof d.result=="string"&&(n=d.result.trim())}catch{}let s=n.match(/\{[\s\S]*\}/);if(!s)return null;let r;try{r=JSON.parse(s[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:GC[i]}}async function Wg(e,t={}){if(t.signal?.aborted)return null;let n=t.model??kr,s=YC(e),r=t.spawn;if(!r)try{let i=await Promise.resolve().then(()=>(Ye(),ys));if(!i.isClaudeCliAvailable())return null;r=(a,d)=>i.spawnClaudePrompt(a,[],d)}catch{return null}let o;try{o=await Promise.race([r(s,{model:n}),new Promise(i=>{t.signal&&t.signal.addEventListener("abort",()=>i({success:!1,stdout:""}),{once:!0})})])}catch{return null}return!o.success||!o.stdout?null:qC(o.stdout)}function Xg(e){let t=[];for(let n of e.proposals){let s=`${n.parent_id}::${n.child_id}`,r=e.rescored.get(s);if(!r){t.push(n);continue}let o=Math.max(0,Math.min(1,n.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({...n,confidence:o,reasons:[...n.reasons,i]})}return t}function Gg(e){return`${e.parent_id}::${e.child_id}`}async function KC(e){if(e.signal?.aborted)return null;let t,n;try{({spawnClaudePrompt:t,isClaudeCliAvailable:n}=await Promise.resolve().then(()=>(Ye(),ys)))}catch{return null}if(!n())return null;let s=[];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)");s.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:
1932
+ `)}function fA(e){if(!e)return null;let t=e.trim();if(!t)return null;let n=t;try{let d=JSON.parse(t);typeof d.result=="string"&&(n=d.result.trim())}catch{}let s=n.match(/\{[\s\S]*\}/);if(!s)return null;let r;try{r=JSON.parse(s[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:uA[i]}}async function tf(e,t={}){if(t.signal?.aborted)return null;let n=t.model??Cr,s=gA(e),r=t.spawn;if(!r)try{let i=await Promise.resolve().then(()=>(Ye(),ws));if(!i.isClaudeCliAvailable())return null;r=(a,d)=>i.spawnClaudePrompt(a,[],d)}catch{return null}let o;try{o=await Promise.race([r(s,{model:n}),new Promise(i=>{t.signal&&t.signal.addEventListener("abort",()=>i({success:!1,stdout:""}),{once:!0})})])}catch{return null}return!o.success||!o.stdout?null:fA(o.stdout)}function nf(e){let t=[];for(let n of e.proposals){let s=`${n.parent_id}::${n.child_id}`,r=e.rescored.get(s);if(!r){t.push(n);continue}let o=Math.max(0,Math.min(1,n.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({...n,confidence:o,reasons:[...n.reasons,i]})}return t}function sf(e){return`${e.parent_id}::${e.child_id}`}async function hA(e){if(e.signal?.aborted)return null;let t,n;try{({spawnClaudePrompt:t,isClaudeCliAvailable:n}=await Promise.resolve().then(()=>(Ye(),ws)))}catch{return null}if(!n())return null;let s=[];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)");s.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:
1922
1933
  - 4 to 8 words
1923
1934
  - Title-case, no trailing punctuation
1924
1935
  - Capture the WORKFLOW (e.g., "Update Remotion deps + lint cleanup"), not any one session
@@ -1929,7 +1940,7 @@ Sessions:
1929
1940
  `+s.join(`
1930
1941
  `)+`
1931
1942
 
1932
- 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}))}),d=await Promise.race([o,a]);if(i&&e.signal&&e.signal.removeEventListener("abort",i),!d||!d.success)return null;let l=d.stdout.trim();if(!l)return null;let u;try{let m=JSON.parse(l);u=typeof m.result=="string"?m.result:l}catch{u=l}return u=u.trim().replace(/^["'`]+|["'`]+$/g,"").replace(/[.!?]+$/g,"").trim(),u?u.length>80?u.slice(0,77)+"...":u:null}catch{return null}}function QC(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 n=e.map(o=>o.id),s=new Map;try{s=jg(n)}catch{s=new Map}let r=new Map;for(let[o,i]of t){let a=new Map;for(let u of i){let m=s.get(u.id);m&&a.set(u.id,m)}let d=Ug(a,.8),l=[];for(let u of i){let m=eL(u,s,d);m&&l.push(m)}r.set(o,l)}return{byProject:t,scannablesByProject:r}}function ZC(e){let t=E(),n={},s="1=1 AND s.message_count > 2";return s+=" 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&&(s+=" AND p.name = @project",n.project=e.project),t.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
1943
+ 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}))}),d=await Promise.race([o,a]);if(i&&e.signal&&e.signal.removeEventListener("abort",i),!d||!d.success)return null;let l=d.stdout.trim();if(!l)return null;let u;try{let m=JSON.parse(l);u=typeof m.result=="string"?m.result:l}catch{u=l}return u=u.trim().replace(/^["'`]+|["'`]+$/g,"").replace(/[.!?]+$/g,"").trim(),u?u.length>80?u.slice(0,77)+"...":u:null}catch{return null}}function EA(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 n=e.map(o=>o.id),s=new Map;try{s=Kg(n)}catch{s=new Map}let r=new Map;for(let[o,i]of t){let a=new Map;for(let u of i){let m=s.get(u.id);m&&a.set(u.id,m)}let d=Qg(a,.8),l=[];for(let u of i){let m=SA(u,s,d);m&&l.push(m)}r.set(o,l)}return{byProject:t,scannablesByProject:r}}function bA(e){let t=h(),n={},s="1=1 AND s.message_count > 2";return s+=" 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&&(s+=" AND p.name = @project",n.project=e.project),t.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
1933
1944
  s.first_user_message, s.auto_title,
1934
1945
  NULLIF(sa.alias, '') AS alias,
1935
1946
  s.file_path
@@ -1937,40 +1948,40 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1937
1948
  JOIN projects p ON p.id = s.project_id
1938
1949
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1939
1950
  WHERE ${s}
1940
- ORDER BY p.name ASC, s.started_at ASC`).all(n)}function eL(e,t,n){if(!e.started_at)return null;let s=Date.parse(e.started_at);if(!Number.isFinite(s))return null;let r=e.ended_at?Date.parse(e.ended_at):null,o=Dg(e.file_path,{maxUserMessages:7}),i=t?.get(e.id);return{id:e.id,started_at_ms:s,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:n?.get(e.id)??null,authored_paths:o.authored_paths,authored_content:o.authored_content}}function xr(e){let t=e.id.slice(0,8),n=e.alias||e.auto_title||(e.first_user_message?e.first_user_message.slice(0,50):"(no title)");return`${t} ${n}`}function zg(e){if(!e)return"?";let t=new Date(e);if(Number.isNaN(t.getTime()))return"?";let n=s=>String(s).padStart(2,"0");return`${t.getFullYear()}-${n(t.getMonth()+1)}-${n(t.getDate())} ${n(t.getHours())}:${n(t.getMinutes())}`}function Jg(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 tL(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??Fn,n=e.rescore.cap??Bg,s=e.rescore.model??kr,r=new Map(e.scannables.map(p=>[p.id,p])),o=Hg(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>n)return{proposals:e.proposals,ran:!1,considered:o.length,promoted:0,demoted:0,unsure:0,failed:0,capped:!0};let i=new Map,a=0,d=0,l=0,u=0;for(let p=0;p<o.length&&!e.signal?.aborted;p++){let g=o[p],f=await Wg(g,{model:s,signal:e.signal});f?(i.set(Gg(g.step1),f),f.verdict==="same_workflow"?a++:f.verdict==="unrelated"?d++:l++):u++,e.onProgress?.({phase:"rescoring",current:p+1,total:o.length,verdict:f?.verdict??"failed"})}return{proposals:Xg({proposals:e.proposals,rescored:i,applyThreshold:e.applyThreshold}),ran:!0,considered:o.length,promoted:a,demoted:d,unsure:l,failed:u,capped:!1}}async function nL(e){let t=E(),n=new Map(e.rows.map(l=>[l.id,l])),s=Mg(e.edges,e.scannables),r=new Date().toISOString(),o=[],i=new Map,a=0;for(let l of s){if(a++,e.signal?.aborted)break;let u=n.get(l.rootId),m=Jg(u);if(!e.llmNames){i.set(l.rootId,m),e.onProgress?.({phase:"naming",current:a,total:s.length,thread_name:m});continue}let g=await KC({rootRow:u,sessionIds:l.sessionIds,rowById:n,signal:e.signal,model:e.model})??m;i.set(l.rootId,g),e.onProgress?.({phase:"naming",current:a,total:s.length,thread_name:g})}return t.transaction(()=>{for(let l of s){if(!i.has(l.rootId))continue;let u=n.get(l.rootId),m=`auto-scan-${VC()}`,p=i.get(l.rootId)??Jg(u),g=`Auto-detected workflow chain (${l.sessionIds.length} sessions). Source: auto-scan-v1.`;t.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, ?, ?)").run(m,p,g,r),t.prepare(`INSERT INTO thread_edges
1951
+ ORDER BY p.name ASC, s.started_at ASC`).all(n)}function SA(e,t,n){if(!e.started_at)return null;let s=Date.parse(e.started_at);if(!Number.isFinite(s))return null;let r=e.ended_at?Date.parse(e.ended_at):null,o=zg(e.file_path,{maxUserMessages:7}),i=t?.get(e.id);return{id:e.id,started_at_ms:s,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:n?.get(e.id)??null,authored_paths:o.authored_paths,authored_content:o.authored_content}}function Ar(e){let t=e.id.slice(0,8),n=e.alias||e.auto_title||(e.first_user_message?e.first_user_message.slice(0,50):"(no title)");return`${t} ${n}`}function rf(e){if(!e)return"?";let t=new Date(e);if(Number.isNaN(t.getTime()))return"?";let n=s=>String(s).padStart(2,"0");return`${t.getFullYear()}-${n(t.getMonth()+1)}-${n(t.getDate())} ${n(t.getHours())}:${n(t.getMinutes())}`}function of(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 yA(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??jn,n=e.rescore.cap??Zg,s=e.rescore.model??Cr,r=new Map(e.scannables.map(p=>[p.id,p])),o=ef(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>n)return{proposals:e.proposals,ran:!1,considered:o.length,promoted:0,demoted:0,unsure:0,failed:0,capped:!0};let i=new Map,a=0,d=0,l=0,u=0;for(let p=0;p<o.length&&!e.signal?.aborted;p++){let g=o[p],f=await tf(g,{model:s,signal:e.signal});f?(i.set(sf(g.step1),f),f.verdict==="same_workflow"?a++:f.verdict==="unrelated"?d++:l++):u++,e.onProgress?.({phase:"rescoring",current:p+1,total:o.length,verdict:f?.verdict??"failed"})}return{proposals:nf({proposals:e.proposals,rescored:i,applyThreshold:e.applyThreshold}),ran:!0,considered:o.length,promoted:a,demoted:d,unsure:l,failed:u,capped:!1}}async function wA(e){let t=h(),n=new Map(e.rows.map(l=>[l.id,l])),s=Jg(e.edges,e.scannables),r=new Date().toISOString(),o=[],i=new Map,a=0;for(let l of s){if(a++,e.signal?.aborted)break;let u=n.get(l.rootId),m=of(u);if(!e.llmNames){i.set(l.rootId,m),e.onProgress?.({phase:"naming",current:a,total:s.length,thread_name:m});continue}let g=await hA({rootRow:u,sessionIds:l.sessionIds,rowById:n,signal:e.signal,model:e.model})??m;i.set(l.rootId,g),e.onProgress?.({phase:"naming",current:a,total:s.length,thread_name:g})}return t.transaction(()=>{for(let l of s){if(!i.has(l.rootId))continue;let u=n.get(l.rootId),m=`auto-scan-${_A()}`,p=i.get(l.rootId)??of(u),g=`Auto-detected workflow chain (${l.sessionIds.length} sessions). Source: auto-scan-v1.`;t.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, ?, ?)").run(m,p,g,r),t.prepare(`INSERT INTO thread_edges
1941
1952
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
1942
- VALUES (?, ?, NULL, 'origin', 1.0, 'auto-scan-v1', ?)`).run(m,l.rootId,r);let f=new Map;for(let h of e.edges)l.sessionIds.includes(h.child_id)&&f.set(h.child_id,h);for(let h of l.sessionIds){if(h===l.rootId)continue;let _=f.get(h);_&&t.prepare(`INSERT INTO thread_edges
1953
+ VALUES (?, ?, NULL, 'origin', 1.0, 'auto-scan-v1', ?)`).run(m,l.rootId,r);let f=new Map;for(let _ of e.edges)l.sessionIds.includes(_.child_id)&&f.set(_.child_id,_);for(let _ of l.sessionIds){if(_===l.rootId)continue;let b=f.get(_);b&&t.prepare(`INSERT INTO thread_edges
1943
1954
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
1944
- VALUES (?, ?, ?, 'child', ?, 'auto-scan-v1', ?)`).run(m,h,_.parent_id,_.confidence,r)}o.push({thread_id:m,name:p,session_count:l.sessionIds.length})}})(),{project:e.project,threads:o}}async function Yg(e){let t=!!e.apply,n=e.confidenceMin?Number(e.confidenceMin):t?ca:la;if(!Number.isFinite(n)||n<0||n>1){console.error(c.err("--confidence-min must be a number in [0, 1]")),process.exitCode=1;return}let s=!!e.llmRescore,r={lo:e.rescoreBandLo?Number(e.rescoreBandLo):Fn.lo,hi:e.rescoreBandHi?Number(e.rescoreBandHi):Fn.hi};if(s&&(!Number.isFinite(r.lo)||!Number.isFinite(r.hi)||r.lo<0||r.hi>1||r.lo>r.hi)){console.error(c.err("--rescore-band-lo/hi must satisfy 0 \u2264 lo \u2264 hi \u2264 1")),process.exitCode=1;return}let o=e.rescoreModel??kr,i=ZC({project:e.project});if(i.length===0){console.log(c.dim("no sessions matched"));return}let{byProject:a,scannablesByProject:d}=QC(i),l=s?Math.min(n,r.lo):n,u=new Map,m=0;for(let[g]of a){let f=d.get(g)??[],h=Ig(f,l);if(s&&h.length>0){let _=await tL({proposals:h,scannables:f,applyThreshold:n,rescore:{enabled:!0,band:r,model:o}});h=_.proposals,_.capped?(console.error(c.err(`[${g}] borderline pairs exceeded cap (${_.considered}); skipped LLM rescore. Tighten the band or scan a smaller project.`)),h=h.filter(b=>b.confidence>=n)):s?_.failed===_.considered&&_.considered>0&&(h=h.filter(b=>b.confidence>=n)):h=h.filter(b=>b.confidence>=n)}else s&&(h=h.filter(_=>_.confidence>=n));u.set(g,{proposals:h,scannables:f}),m+=h.length}if(t){if(m===0){console.log(c.dim("no edges above threshold; nothing to apply"));return}let g={threads_created:0,edges_written:0,per_project:[]},f=!e.noLlmNames;for(let[h,{proposals:_,scannables:b}]of u){if(_.length===0)continue;let S=await nL({project:h,rows:a.get(h),edges:_,scannables:b,llmNames:f});g.per_project.push(S),g.threads_created+=S.threads.length,g.edges_written+=_.length+S.threads.length}if(e.json){console.log(JSON.stringify({mode:"apply",threshold:n,...g},null,2));return}console.log(c.ok(`Applied ${g.threads_created} thread${g.threads_created===1?"":"s"} with ${g.edges_written} edges total (threshold ${n}).`));for(let h of g.per_project){console.log(` ${c.bold(h.project)}`);for(let _ of h.threads)console.log(` ${c.dim(_.thread_id.slice(0,16)+"\u2026")} ${_.name} ${c.dim(`(${_.session_count} sessions)`)}`)}console.log(),console.log(c.dim("Rollback: sqlite3 ~/.recall/db.sqlite \\")),console.log(c.dim(` "DELETE FROM thread_edges WHERE source='auto-scan-v1';`)),console.log(c.dim(` DELETE FROM threads WHERE id LIKE 'auto-scan-%';"`));return}if(e.json){let g=[];for(let[f,{proposals:h}]of u){let _=new Map(a.get(f).map(b=>[b.id,b]));for(let b of h)g.push({project:f,parent_id:b.parent_id,parent_label:xr(_.get(b.parent_id)),child_id:b.child_id,child_label:xr(_.get(b.child_id)),confidence:b.confidence,signals:b.signals,reasons:b.reasons})}console.log(JSON.stringify({mode:"dry-run",threshold:n,total:m,edges:g},null,2));return}console.log(c.dim(`recall thread scan \xB7 ${a.size} project${a.size===1?"":"s"} \xB7 DRY RUN \xB7 threshold ${n}`)),console.log(c.dim(" Algorithm: temporal + continuation phrase + file overlap + same brand.")),console.log();for(let[g,f]of a){let{proposals:h}=u.get(g),_=new Map(f.map(S=>[S.id,S]));if(console.log(c.bold(g)),console.log(c.dim(` ${f.length} eligible session${f.length===1?"":"s"}; ${h.length} parent-child edge${h.length===1?"":"s"} proposed.`)),h.length===0){console.log(c.dim(" (no edges above threshold \u2014 all sessions are origins)")),console.log();continue}let b=[...h].sort((S,y)=>{let T=_.get(S.child_id),R=_.get(y.child_id);return(T.started_at??"").localeCompare(R.started_at??"")});for(let S of b){let y=_.get(S.parent_id),T=_.get(S.child_id),R=S.confidence.toFixed(2);console.log(` ${c.dim(zg(y.started_at).padEnd(16))} ${c.bold("PARENT")} ${xr(y)}`),console.log(` ${c.dim(zg(T.started_at).padEnd(16))} ${c.bold(" \u2514\u2500 child")} ${xr(T)} ${c.dim(`[conf ${R}]`)}`),console.log(` ${" ".repeat(28)}${c.dim(S.reasons.join(" \xB7 "))}`),console.log()}}let p=Array.from(a.entries()).reduce((g,[f,h])=>g+(h.length-(u.get(f)?.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(c.dim(` This is a DRY RUN. To write: rerun with --apply (default threshold ${ca}).`))}$();I();import{existsSync as sL,readFileSync as rL}from"node:fs";function oL(){let e=`${C}/daemon.port`;if(!sL(e))return null;try{let t=rL(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function iL(e){try{return(await nt(`http://127.0.0.1:${e}/api/health`,{signal:AbortSignal.timeout(1e4)})).ok}catch{return!1}}async function aL(e){let t=await nt(`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 cL(e,t){let n=t.replace(/\/+$/,""),s=null,r=-1;for(let o of e){if(!o.decoded_path)continue;let i=o.decoded_path.replace(/\/+$/,"");(n===i||n.startsWith(i+"/"))&&i.length>r&&(s=o,r=i.length)}return s}function lL(e,t){let n=e.find(r=>r.name===t);if(n)return n;let s=e.filter(r=>r.name.toLowerCase().includes(t.toLowerCase()));return s.length===1?s[0]:null}function qg(e){return e.alias||e.auto_title||(e.first_user_message?Q(e.first_user_message,60):"(no title)")}function dL(e){if(!e)return"?";let t=new Date(e);if(Number.isNaN(t.getTime()))return"?";let n=s=>String(s).padStart(2,"0");return`${t.getFullYear()}-${n(t.getMonth()+1)}-${n(t.getDate())} ${n(t.getHours())}:${n(t.getMinutes())}`}function uL(e,t){let n=t==="preflight"?c.dim(`recall threads sync \xB7 ${e.project.name} \xB7 PREFLIGHT (no writes)`):c.dim(`recall threads sync \xB7 ${e.project.name}`);if(console.log(n),console.log(),e.thread.exists?console.log(` ${c.bold("Thread")} ${e.thread.name} ${c.dim(`(reusing, ${e.thread.existing_session_count} existing session${e.thread.existing_session_count===1?"":"s"})`)}`):console.log(` ${c.bold("Thread")} ${e.thread.name} ${c.ok("(new)")}`),console.log(),e.candidates.length===0){if(console.log(c.dim(" No active sessions in the rolling window.")),e.warnings.length>0)for(let l of e.warnings)console.log(c.warn(` \u26A0 ${l}`));return}let s=new Map;for(let l of e.proposed_edges)s.set(l.child_id,l);let r=new Map;for(let l of e.preserved_manual_edges)r.set(l.session_id,l.parent_session_id);let o=new Set(e.candidates.map(l=>l.session_id)),i=e.proposed_additions.length,a=e.candidates.length-i;console.log(` ${c.bold("Candidates")} ${e.candidates.length} active session${e.candidates.length===1?"":"s"} ${c.dim(`(${i} new \xB7 ${a} keep)`)}`);let d=String(e.candidates.length).length;for(let l=0;l<e.candidates.length;l++){let u=e.candidates[l],p=e.proposed_additions.some(S=>S.session_id===u.session_id)?c.ok("NEW "):c.dim("keep"),g=s.get(u.session_id)??(r.has(u.session_id)&&r.get(u.session_id)!==null,null),f=g&&o.has(g.parent_id)?" \u2514\u2500 ":" ",h=dL(u.started_at),_=c.dim(`${String(l+1).padStart(d," ")}.`);console.log(` ${_} ${p} ${c.dim(h.padEnd(16))} ${f}${c.dim(u.session_id.slice(0,8))} ${qg(u)}`);let b=" ".repeat(d+2);if(g&&o.has(g.parent_id)){let S=g.confidence.toFixed(2),y=qg(e.candidates.find(T=>T.session_id===g.parent_id));console.log(` ${b}${" ".repeat(28)} parent ${c.dim(g.parent_id.slice(0,8))} (${y}) ${c.dim(`[conf ${S}]`)}`),console.log(` ${b}${" ".repeat(28)} ${c.dim(g.reasons.join(" \xB7 "))}`)}if(r.has(u.session_id)){let S=r.get(u.session_id);S&&console.log(` ${b}${" ".repeat(28)} ${c.bold("manual parent preserved")} ${c.dim(S.slice(0,8))}`)}}if(e.preserved_manual_edges.length>0&&(console.log(),console.log(c.dim(` ${e.preserved_manual_edges.length} manual edge${e.preserved_manual_edges.length===1?"":"s"} will be preserved.`))),e.warnings.length>0){console.log();for(let l of e.warnings)console.log(c.warn(` \u26A0 ${l}`))}}function pL(e){console.log(),console.log(c.ok(`Added ${e.added} session${e.added===1?"":"s"}, set ${e.edges_set} parent edge${e.edges_set===1?"":"s"}, preserved ${e.preserved_manual} manual edge${e.preserved_manual===1?"":"s"}.`)),console.log(c.dim(` thread_id: ${e.thread_id}`))}async function Vg(e){let t=oL();if(!t){console.error(c.err("Daemon is not running. Start it with `recall start`, then re-run this command.")),process.exitCode=1;return}if(!await iL(t)){console.error(c.err(`Daemon on port ${t} is not responding. Try \`recall stop && recall start\`.`)),process.exitCode=1;return}let s;try{s=await aL(t)}catch(l){console.error(c.err(l.message)),process.exitCode=1;return}let r;if(e.project){if(r=lL(s,e.project),!r){console.error(c.err(`No project matching "${e.project}". Run \`recall projects\` to list known projects.`)),process.exitCode=1;return}}else{let l=process.cwd();if(r=cL(s,l),!r){console.error(c.err(`Current directory (${l}) does not match any known project. Pass --project <name> or cd into a project root.`)),process.exitCode=1;return}}let o=e.windowHours?Number(e.windowHours):void 0;if(o!==void 0&&(!Number.isFinite(o)||o<=0)){console.error(c.err("--window-hours must be a positive number")),process.exitCode=1;return}let i=e.preflight?"preflight":"apply",a={project_id:r.id,mode:i};o!==void 0&&(a.window_hours=o);let d;try{let l=await ut("POST",`http://127.0.0.1:${t}/api/threads/sync-active`,a);if(!l.ok){let u=await l.text().catch(()=>"");throw new Error(`HTTP ${l.status}: ${u.slice(0,200)}`)}d=await l.json()}catch(l){console.error(c.err(`Sync failed: ${l.message}`)),process.exitCode=1;return}if(e.json){console.log(JSON.stringify({mode:i,...d},null,2));return}uL(d.plan,i),i==="apply"&&d.result?pL(d.result):i==="preflight"&&(console.log(),console.log(c.dim(" This is a PREFLIGHT. To write: re-run without --preflight.")))}k();import{writeFileSync as DL,existsSync as $L,mkdirSync as PL}from"node:fs";import{join as _f}from"node:path";import{homedir as FL}from"node:os";import{execSync as rn}from"node:child_process";Ge();import OL from"satori";import vL from"sharp";import{readFileSync as fa}from"node:fs";import{join as Dr}from"node:path";var _a=Dr(te(),"dist","share","fonts"),mf=!1,gf=[];function IL(){return mf||(gf=[{name:"Inter",data:fa(Dr(_a,"Inter-Regular.woff")),weight:400,style:"normal"},{name:"Inter",data:fa(Dr(_a,"Inter-Bold.woff")),weight:700,style:"normal"},{name:"JetBrains Mono",data:fa(Dr(_a,"JetBrainsMono-Regular.woff")),weight:400,style:"normal"}],mf=!0),gf}async function ML(e){switch(e){case"A":return await Promise.resolve().then(()=>(ef(),Zg));case"B":return await Promise.resolve().then(()=>(sf(),nf));case"C":return await Promise.resolve().then(()=>(af(),of));case"D":return await Promise.resolve().then(()=>(df(),lf));case"E":return await Promise.resolve().then(()=>(pf(),uf))}}async function $r(e,t){let s=(await ML(e)).render(t),i=await OL(s,{width:1080,height:e==="E"?1920:1350,fonts:IL()});return await vL(Buffer.from(i)).png({quality:90}).toBuffer()}function ff(e,t){let n=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"&&n.set("i",String(e.inputTokens)),typeof e.outputTokens=="number"&&n.set("o",String(e.outputTokens)),e.verdict&&n.set("q",e.verdict),`https://clauderecall.com/card?${n.toString()}`}function jL(e,t){if(t.length>=32)return e.prepare("SELECT id FROM sessions WHERE id = ?").get(t)?.id??null;let n=e.prepare("SELECT session_id FROM session_aliases WHERE alias = ?").get(t);if(n)return n.session_id;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.
1945
- `),null)}function UL(e){return e.prepare("SELECT session_id FROM recall_events ORDER BY recalled_at DESC LIMIT 1").get()?.session_id??null}function BL(e,t){let n=e.prepare(`
1955
+ VALUES (?, ?, ?, 'child', ?, 'auto-scan-v1', ?)`).run(m,_,b.parent_id,b.confidence,r)}o.push({thread_id:m,name:p,session_count:l.sessionIds.length})}})(),{project:e.project,threads:o}}async function af(e){let t=!!e.apply,n=e.confidenceMin?Number(e.confidenceMin):t?ma:ga;if(!Number.isFinite(n)||n<0||n>1){console.error(c.err("--confidence-min must be a number in [0, 1]")),process.exitCode=1;return}let s=!!e.llmRescore,r={lo:e.rescoreBandLo?Number(e.rescoreBandLo):jn.lo,hi:e.rescoreBandHi?Number(e.rescoreBandHi):jn.hi};if(s&&(!Number.isFinite(r.lo)||!Number.isFinite(r.hi)||r.lo<0||r.hi>1||r.lo>r.hi)){console.error(c.err("--rescore-band-lo/hi must satisfy 0 \u2264 lo \u2264 hi \u2264 1")),process.exitCode=1;return}let o=e.rescoreModel??Cr,i=bA({project:e.project});if(i.length===0){console.log(c.dim("no sessions matched"));return}let{byProject:a,scannablesByProject:d}=EA(i),l=s?Math.min(n,r.lo):n,u=new Map,m=0;for(let[g]of a){let f=d.get(g)??[],_=Gg(f,l);if(s&&_.length>0){let b=await yA({proposals:_,scannables:f,applyThreshold:n,rescore:{enabled:!0,band:r,model:o}});_=b.proposals,b.capped?(console.error(c.err(`[${g}] borderline pairs exceeded cap (${b.considered}); skipped LLM rescore. Tighten the band or scan a smaller project.`)),_=_.filter(E=>E.confidence>=n)):s?b.failed===b.considered&&b.considered>0&&(_=_.filter(E=>E.confidence>=n)):_=_.filter(E=>E.confidence>=n)}else s&&(_=_.filter(b=>b.confidence>=n));u.set(g,{proposals:_,scannables:f}),m+=_.length}if(t){if(m===0){console.log(c.dim("no edges above threshold; nothing to apply"));return}let g={threads_created:0,edges_written:0,per_project:[]},f=!e.noLlmNames;for(let[_,{proposals:b,scannables:E}]of u){if(b.length===0)continue;let S=await wA({project:_,rows:a.get(_),edges:b,scannables:E,llmNames:f});g.per_project.push(S),g.threads_created+=S.threads.length,g.edges_written+=b.length+S.threads.length}if(e.json){console.log(JSON.stringify({mode:"apply",threshold:n,...g},null,2));return}console.log(c.ok(`Applied ${g.threads_created} thread${g.threads_created===1?"":"s"} with ${g.edges_written} edges total (threshold ${n}).`));for(let _ of g.per_project){console.log(` ${c.bold(_.project)}`);for(let b of _.threads)console.log(` ${c.dim(b.thread_id.slice(0,16)+"\u2026")} ${b.name} ${c.dim(`(${b.session_count} sessions)`)}`)}console.log(),console.log(c.dim("Rollback: sqlite3 ~/.recall/db.sqlite \\")),console.log(c.dim(` "DELETE FROM thread_edges WHERE source='auto-scan-v1';`)),console.log(c.dim(` DELETE FROM threads WHERE id LIKE 'auto-scan-%';"`));return}if(e.json){let g=[];for(let[f,{proposals:_}]of u){let b=new Map(a.get(f).map(E=>[E.id,E]));for(let E of _)g.push({project:f,parent_id:E.parent_id,parent_label:Ar(b.get(E.parent_id)),child_id:E.child_id,child_label:Ar(b.get(E.child_id)),confidence:E.confidence,signals:E.signals,reasons:E.reasons})}console.log(JSON.stringify({mode:"dry-run",threshold:n,total:m,edges:g},null,2));return}console.log(c.dim(`recall thread scan \xB7 ${a.size} project${a.size===1?"":"s"} \xB7 DRY RUN \xB7 threshold ${n}`)),console.log(c.dim(" Algorithm: temporal + continuation phrase + file overlap + same brand.")),console.log();for(let[g,f]of a){let{proposals:_}=u.get(g),b=new Map(f.map(S=>[S.id,S]));if(console.log(c.bold(g)),console.log(c.dim(` ${f.length} eligible session${f.length===1?"":"s"}; ${_.length} parent-child edge${_.length===1?"":"s"} proposed.`)),_.length===0){console.log(c.dim(" (no edges above threshold \u2014 all sessions are origins)")),console.log();continue}let E=[..._].sort((S,y)=>{let T=b.get(S.child_id),R=b.get(y.child_id);return(T.started_at??"").localeCompare(R.started_at??"")});for(let S of E){let y=b.get(S.parent_id),T=b.get(S.child_id),R=S.confidence.toFixed(2);console.log(` ${c.dim(rf(y.started_at).padEnd(16))} ${c.bold("PARENT")} ${Ar(y)}`),console.log(` ${c.dim(rf(T.started_at).padEnd(16))} ${c.bold(" \u2514\u2500 child")} ${Ar(T)} ${c.dim(`[conf ${R}]`)}`),console.log(` ${" ".repeat(28)}${c.dim(S.reasons.join(" \xB7 "))}`),console.log()}}let p=Array.from(a.entries()).reduce((g,[f,_])=>g+(_.length-(u.get(f)?.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(c.dim(` This is a DRY RUN. To write: rerun with --apply (default threshold ${ma}).`))}D();I();import{existsSync as TA,readFileSync as RA}from"node:fs";function kA(){let e=`${C}/daemon.port`;if(!TA(e))return null;try{let t=RA(e,"utf8").trim();return/^\d+$/.test(t)?t:null}catch{return null}}async function xA(e){try{return(await nt(`http://127.0.0.1:${e}/api/health`,{signal:AbortSignal.timeout(1e4)})).ok}catch{return!1}}async function CA(e){let t=await nt(`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 AA(e,t){let n=t.replace(/\/+$/,""),s=null,r=-1;for(let o of e){if(!o.decoded_path)continue;let i=o.decoded_path.replace(/\/+$/,"");(n===i||n.startsWith(i+"/"))&&i.length>r&&(s=o,r=i.length)}return s}function LA(e,t){let n=e.find(r=>r.name===t);if(n)return n;let s=e.filter(r=>r.name.toLowerCase().includes(t.toLowerCase()));return s.length===1?s[0]:null}function cf(e){return e.alias||e.auto_title||(e.first_user_message?Q(e.first_user_message,60):"(no title)")}function NA(e){if(!e)return"?";let t=new Date(e);if(Number.isNaN(t.getTime()))return"?";let n=s=>String(s).padStart(2,"0");return`${t.getFullYear()}-${n(t.getMonth()+1)}-${n(t.getDate())} ${n(t.getHours())}:${n(t.getMinutes())}`}function OA(e,t){let n=t==="preflight"?c.dim(`recall threads sync \xB7 ${e.project.name} \xB7 PREFLIGHT (no writes)`):c.dim(`recall threads sync \xB7 ${e.project.name}`);if(console.log(n),console.log(),e.thread.exists?console.log(` ${c.bold("Thread")} ${e.thread.name} ${c.dim(`(reusing, ${e.thread.existing_session_count} existing session${e.thread.existing_session_count===1?"":"s"})`)}`):console.log(` ${c.bold("Thread")} ${e.thread.name} ${c.ok("(new)")}`),console.log(),e.candidates.length===0){if(console.log(c.dim(" No active sessions in the rolling window.")),e.warnings.length>0)for(let l of e.warnings)console.log(c.warn(` \u26A0 ${l}`));return}let s=new Map;for(let l of e.proposed_edges)s.set(l.child_id,l);let r=new Map;for(let l of e.preserved_manual_edges)r.set(l.session_id,l.parent_session_id);let o=new Set(e.candidates.map(l=>l.session_id)),i=e.proposed_additions.length,a=e.candidates.length-i;console.log(` ${c.bold("Candidates")} ${e.candidates.length} active session${e.candidates.length===1?"":"s"} ${c.dim(`(${i} new \xB7 ${a} keep)`)}`);let d=String(e.candidates.length).length;for(let l=0;l<e.candidates.length;l++){let u=e.candidates[l],p=e.proposed_additions.some(S=>S.session_id===u.session_id)?c.ok("NEW "):c.dim("keep"),g=s.get(u.session_id)??(r.has(u.session_id)&&r.get(u.session_id)!==null,null),f=g&&o.has(g.parent_id)?" \u2514\u2500 ":" ",_=NA(u.started_at),b=c.dim(`${String(l+1).padStart(d," ")}.`);console.log(` ${b} ${p} ${c.dim(_.padEnd(16))} ${f}${c.dim(u.session_id.slice(0,8))} ${cf(u)}`);let E=" ".repeat(d+2);if(g&&o.has(g.parent_id)){let S=g.confidence.toFixed(2),y=cf(e.candidates.find(T=>T.session_id===g.parent_id));console.log(` ${E}${" ".repeat(28)} parent ${c.dim(g.parent_id.slice(0,8))} (${y}) ${c.dim(`[conf ${S}]`)}`),console.log(` ${E}${" ".repeat(28)} ${c.dim(g.reasons.join(" \xB7 "))}`)}if(r.has(u.session_id)){let S=r.get(u.session_id);S&&console.log(` ${E}${" ".repeat(28)} ${c.bold("manual parent preserved")} ${c.dim(S.slice(0,8))}`)}}if(e.preserved_manual_edges.length>0&&(console.log(),console.log(c.dim(` ${e.preserved_manual_edges.length} manual edge${e.preserved_manual_edges.length===1?"":"s"} will be preserved.`))),e.warnings.length>0){console.log();for(let l of e.warnings)console.log(c.warn(` \u26A0 ${l}`))}}function vA(e){console.log(),console.log(c.ok(`Added ${e.added} session${e.added===1?"":"s"}, set ${e.edges_set} parent edge${e.edges_set===1?"":"s"}, preserved ${e.preserved_manual} manual edge${e.preserved_manual===1?"":"s"}.`)),console.log(c.dim(` thread_id: ${e.thread_id}`))}async function lf(e){let t=kA();if(!t){console.error(c.err("Daemon is not running. Start it with `recall start`, then re-run this command.")),process.exitCode=1;return}if(!await xA(t)){console.error(c.err(`Daemon on port ${t} is not responding. Try \`recall stop && recall start\`.`)),process.exitCode=1;return}let s;try{s=await CA(t)}catch(l){console.error(c.err(l.message)),process.exitCode=1;return}let r;if(e.project){if(r=LA(s,e.project),!r){console.error(c.err(`No project matching "${e.project}". Run \`recall projects\` to list known projects.`)),process.exitCode=1;return}}else{let l=process.cwd();if(r=AA(s,l),!r){console.error(c.err(`Current directory (${l}) does not match any known project. Pass --project <name> or cd into a project root.`)),process.exitCode=1;return}}let o=e.windowHours?Number(e.windowHours):void 0;if(o!==void 0&&(!Number.isFinite(o)||o<=0)){console.error(c.err("--window-hours must be a positive number")),process.exitCode=1;return}let i=e.preflight?"preflight":"apply",a={project_id:r.id,mode:i};o!==void 0&&(a.window_hours=o);let d;try{let l=await ut("POST",`http://127.0.0.1:${t}/api/threads/sync-active`,a);if(!l.ok){let u=await l.text().catch(()=>"");throw new Error(`HTTP ${l.status}: ${u.slice(0,200)}`)}d=await l.json()}catch(l){console.error(c.err(`Sync failed: ${l.message}`)),process.exitCode=1;return}if(e.json){console.log(JSON.stringify({mode:i,...d},null,2));return}OA(d.plan,i),i==="apply"&&d.result?vA(d.result):i==="preflight"&&(console.log(),console.log(c.dim(" This is a PREFLIGHT. To write: re-run without --preflight.")))}k();import{writeFileSync as tL,existsSync as nL,mkdirSync as sL}from"node:fs";import{join as Af}from"node:path";import{homedir as rL}from"node:os";import{execSync as rn}from"node:child_process";Ge();import KA from"satori";import QA from"sharp";import{readFileSync as Sa}from"node:fs";import{join as Pr}from"node:path";var ya=Pr(te(),"dist","share","fonts"),kf=!1,xf=[];function ZA(){return kf||(xf=[{name:"Inter",data:Sa(Pr(ya,"Inter-Regular.woff")),weight:400,style:"normal"},{name:"Inter",data:Sa(Pr(ya,"Inter-Bold.woff")),weight:700,style:"normal"},{name:"JetBrains Mono",data:Sa(Pr(ya,"JetBrainsMono-Regular.woff")),weight:400,style:"normal"}],kf=!0),xf}async function eL(e){switch(e){case"A":return await Promise.resolve().then(()=>(mf(),pf));case"B":return await Promise.resolve().then(()=>(_f(),ff));case"C":return await Promise.resolve().then(()=>(bf(),Ef));case"D":return await Promise.resolve().then(()=>(wf(),yf));case"E":return await Promise.resolve().then(()=>(Rf(),Tf))}}async function Fr(e,t){let s=(await eL(e)).render(t),i=await KA(s,{width:1080,height:e==="E"?1920:1350,fonts:ZA()});return await QA(Buffer.from(i)).png({quality:90}).toBuffer()}function Cf(e,t){let n=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"&&n.set("i",String(e.inputTokens)),typeof e.outputTokens=="number"&&n.set("o",String(e.outputTokens)),e.verdict&&n.set("q",e.verdict),`https://clauderecall.com/card?${n.toString()}`}function oL(e,t){if(t.length>=32)return e.prepare("SELECT id FROM sessions WHERE id = ?").get(t)?.id??null;let n=e.prepare("SELECT session_id FROM session_aliases WHERE alias = ?").get(t);if(n)return n.session_id;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.
1956
+ `),null)}function iL(e){return e.prepare("SELECT session_id FROM recall_events ORDER BY recalled_at DESC LIMIT 1").get()?.session_id??null}function aL(e,t){let n=e.prepare(`
1946
1957
  SELECT s.id, s.started_at, s.message_count, s.first_user_message, s.auto_title,
1947
1958
  s.total_input_tokens, s.total_output_tokens
1948
1959
  FROM sessions s WHERE s.id = ?
1949
1960
  `).get(t);if(!n)return null;let r=e.prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(t)?.alias||n.auto_title||n.first_user_message?.slice(0,80)||n.id.slice(0,8),o=e.prepare(`
1950
1961
  SELECT tool_names, raw_json FROM messages
1951
1962
  WHERE session_id = ? AND tool_names IS NOT NULL AND tool_names != ''
1952
- `).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 g=p.match(/":\s*"([^"]+)"/);g&&a.add(g[1])}}let d=n.total_input_tokens??0,l=n.total_output_tokens??0;return{sessionTitle:r,sessionDate:n.started_at??new Date().toISOString(),recallDate:new Date().toISOString(),tokenCount:d+l,inputTokens:d,outputTokens:l,messageCount:n.message_count,filesReferenced:a.size,toolCallCount:i,verdict:""}}function HL(e){process.platform==="darwin"?rn(`osascript -e 'set the clipboard to (read (POSIX file "${e}") as \xABclass PNGf\xBB)'`):process.platform==="linux"&&rn(`xclip -selection clipboard -t image/png -i "${e}"`)}function WL(e){try{process.platform==="darwin"?rn(`open "${e}"`):process.platform==="linux"?rn(`xdg-open "${e}"`):process.platform==="win32"&&rn(`start "" "${e}"`)}catch{}}async function hf(e,t){let n=E(),s;if(e){if(s=jL(n,e),!s){process.stderr.write(`session not found: ${e}
1953
- `),process.exitCode=1;return}}else if(s=UL(n),!s){process.stderr.write("No recalled sessions yet. Run `recall context <id>` first, then `recall share`.\n"),process.exitCode=1;return}let r=BL(n,s);if(!r){process.stderr.write(`failed to load metadata for session ${s}
1954
- `),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 $r(o,r),a=s.slice(0,8),d=t.out??_f(FL(),"Downloads");$L(d)||PL(d,{recursive:!0});let l=_f(d,`recall-card-${a}.png`);if(DL(l,i),process.stderr.write(`Card saved to ${l}
1955
- `),t.clipboard&&(HL(l),process.stderr.write(`Copied PNG to clipboard.
1956
- `)),t.link){let u=ff(r,o);process.stdout.write(u+`
1963
+ `).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 g=p.match(/":\s*"([^"]+)"/);g&&a.add(g[1])}}let d=n.total_input_tokens??0,l=n.total_output_tokens??0;return{sessionTitle:r,sessionDate:n.started_at??new Date().toISOString(),recallDate:new Date().toISOString(),tokenCount:d+l,inputTokens:d,outputTokens:l,messageCount:n.message_count,filesReferenced:a.size,toolCallCount:i,verdict:""}}function cL(e){process.platform==="darwin"?rn(`osascript -e 'set the clipboard to (read (POSIX file "${e}") as \xABclass PNGf\xBB)'`):process.platform==="linux"&&rn(`xclip -selection clipboard -t image/png -i "${e}"`)}function lL(e){try{process.platform==="darwin"?rn(`open "${e}"`):process.platform==="linux"?rn(`xdg-open "${e}"`):process.platform==="win32"&&rn(`start "" "${e}"`)}catch{}}async function Lf(e,t){let n=h(),s;if(e){if(s=oL(n,e),!s){process.stderr.write(`session not found: ${e}
1964
+ `),process.exitCode=1;return}}else if(s=iL(n),!s){process.stderr.write("No recalled sessions yet. Run `recall context <id>` first, then `recall share`.\n"),process.exitCode=1;return}let r=aL(n,s);if(!r){process.stderr.write(`failed to load metadata for session ${s}
1965
+ `),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 Fr(o,r),a=s.slice(0,8),d=t.out??Af(rL(),"Downloads");nL(d)||sL(d,{recursive:!0});let l=Af(d,`recall-card-${a}.png`);if(tL(l,i),process.stderr.write(`Card saved to ${l}
1966
+ `),t.clipboard&&(cL(l),process.stderr.write(`Copied PNG to clipboard.
1967
+ `)),t.link){let u=Cf(r,o);process.stdout.write(u+`
1957
1968
  `),process.platform==="darwin"&&(rn("pbcopy",{input:u}),process.stderr.write(`Link copied to clipboard.
1958
- `))}t.open!==!1&&WL(l)}k();import{createInterface as XL}from"node:readline";import{writeFileSync as GL,existsSync as zL,mkdirSync as JL}from"node:fs";import{join as bf}from"node:path";import{homedir as YL}from"node:os";function Ef(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 $t=["january","february","march","april","may","june","july","august","september","october","november","december"],qL=["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"];function VL(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:`${$t[a][0].toUpperCase()}${$t[a].slice(1)} ${i}`}}let n=e.match(/^(\d{4})-(\d{2})$/);if(n){let i=parseInt(n[1],10),a=parseInt(n[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:`${$t[a][0].toUpperCase()}${$t[a].slice(1)} ${i}`}}let s=$t.indexOf(e.toLowerCase()),r=s===-1?qL.indexOf(e.toLowerCase()):-1,o=s!==-1?s: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:`${$t[o][0].toUpperCase()}${$t[o].slice(1)} ${i}`}}return null}function KL(e){if(e.length===0)return"N/A";let t=r=>r===0?"12am":r<12?`${r}am`:r===12?"12pm":`${r-12}pm`,n=Math.min(...e),s=Math.max(...e);return`${t(n)}-${t(s+1>23?0:s+1)}`}async function Sf(e,t){let n=VL(e);if(!n){process.stderr.write(`invalid month format: ${e}. Use YYYY-MM, month name, or abbreviation.
1959
- `),process.exitCode=1;return}let s=E(),r=s.prepare("SELECT COUNT(*) AS c FROM recall_events WHERE recalled_at >= ? AND recalled_at < ?").get(n.start,n.end).c,o=s.prepare("SELECT COALESCE(SUM(token_count), 0) AS s FROM recall_events WHERE recalled_at >= ? AND recalled_at < ?").get(n.start,n.end).s,i=s.prepare("SELECT COUNT(*) AS c FROM sessions WHERE indexed_at >= ? AND indexed_at < ?").get(n.start,n.end).c,a=s.prepare(`SELECT session_id, COUNT(*) AS c FROM recall_events
1969
+ `))}t.open!==!1&&lL(l)}k();import{createInterface as dL}from"node:readline";import{writeFileSync as uL,existsSync as pL,mkdirSync as mL}from"node:fs";import{join as Of}from"node:path";import{homedir as gL}from"node:os";function Nf(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 $t=["january","february","march","april","may","june","july","august","september","october","november","december"],fL=["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"];function _L(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:`${$t[a][0].toUpperCase()}${$t[a].slice(1)} ${i}`}}let n=e.match(/^(\d{4})-(\d{2})$/);if(n){let i=parseInt(n[1],10),a=parseInt(n[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:`${$t[a][0].toUpperCase()}${$t[a].slice(1)} ${i}`}}let s=$t.indexOf(e.toLowerCase()),r=s===-1?fL.indexOf(e.toLowerCase()):-1,o=s!==-1?s: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:`${$t[o][0].toUpperCase()}${$t[o].slice(1)} ${i}`}}return null}function hL(e){if(e.length===0)return"N/A";let t=r=>r===0?"12am":r<12?`${r}am`:r===12?"12pm":`${r-12}pm`,n=Math.min(...e),s=Math.max(...e);return`${t(n)}-${t(s+1>23?0:s+1)}`}async function vf(e,t){let n=_L(e);if(!n){process.stderr.write(`invalid month format: ${e}. Use YYYY-MM, month name, or abbreviation.
1970
+ `),process.exitCode=1;return}let s=h(),r=s.prepare("SELECT COUNT(*) AS c FROM recall_events WHERE recalled_at >= ? AND recalled_at < ?").get(n.start,n.end).c,o=s.prepare("SELECT COALESCE(SUM(token_count), 0) AS s FROM recall_events WHERE recalled_at >= ? AND recalled_at < ?").get(n.start,n.end).s,i=s.prepare("SELECT COUNT(*) AS c FROM sessions WHERE indexed_at >= ? AND indexed_at < ?").get(n.start,n.end).c,a=s.prepare(`SELECT session_id, COUNT(*) AS c FROM recall_events
1960
1971
  WHERE recalled_at >= ? AND recalled_at < ?
1961
1972
  GROUP BY session_id ORDER BY c DESC LIMIT 1`).get(n.start,n.end),d="None";if(a){let O=s.prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(a.session_id),x=s.prepare("SELECT auto_title, first_user_message, id FROM sessions WHERE id = ?").get(a.session_id);d=O?.alias||x?.auto_title||x?.first_user_message?.slice(0,40)||a.session_id.slice(0,8)}let l=s.prepare("SELECT COALESCE(MAX(token_count), 0) AS m FROM recall_events WHERE recalled_at >= ? AND recalled_at < ?").get(n.start,n.end).m,u=s.prepare(`SELECT CAST(strftime('%H', started_at) AS INTEGER) AS h, COUNT(*) AS c
1962
1973
  FROM sessions WHERE started_at >= ? AND started_at < ?
1963
- GROUP BY h ORDER BY c DESC LIMIT 3`).all(n.start,n.end),m=KL(u.map(O=>O.h)),p=s.prepare("SELECT COUNT(DISTINCT session_id) AS c FROM recall_events WHERE recalled_at >= ? AND recalled_at < ?").get(n.start,n.end).c,g=s.prepare(`SELECT COUNT(*) AS cnt, COALESCE(AVG(message_count), 0) AS avg_msgs
1974
+ GROUP BY h ORDER BY c DESC LIMIT 3`).all(n.start,n.end),m=hL(u.map(O=>O.h)),p=s.prepare("SELECT COUNT(DISTINCT session_id) AS c FROM recall_events WHERE recalled_at >= ? AND recalled_at < ?").get(n.start,n.end).c,g=s.prepare(`SELECT COUNT(*) AS cnt, COALESCE(AVG(message_count), 0) AS avg_msgs
1964
1975
  FROM sessions WHERE started_at >= ? AND started_at < ?`).get(n.start,n.end),f=s.prepare(`SELECT COUNT(*) AS c FROM sessions
1965
1976
  WHERE started_at >= ? AND started_at < ?
1966
1977
  AND (CAST(strftime('%H', started_at) AS INTEGER) >= 22
1967
- OR CAST(strftime('%H', started_at) AS INTEGER) < 4)`).get(n.start,n.end).c,h=s.prepare(`SELECT COUNT(DISTINCT st.session_id) AS c
1978
+ OR CAST(strftime('%H', started_at) AS INTEGER) < 4)`).get(n.start,n.end).c,_=s.prepare(`SELECT COUNT(DISTINCT st.session_id) AS c
1968
1979
  FROM session_tags st JOIN sessions s ON s.id = st.session_id
1969
1980
  WHERE s.started_at >= ? AND s.started_at < ?
1970
- AND (st.tag LIKE '%debug%' OR st.tag LIKE '%fix%' OR st.tag LIKE '%bug%' OR st.tag LIKE '%error%')`).get(n.start,n.end).c,_={recallCount:r,uniqueSessionsRecalled:p,sessionCount:g.cnt,avgMessageCount:g.avg_msgs,nightSessionRatio:g.cnt>0?f/g.cnt:0,debugTagRatio:g.cnt>0?h/g.cnt:0},b=Ef(_),S=50;try{let{computeAllHealthScores:O}=await Promise.resolve().then(()=>(Zi(),jm)),x=O();x.length>0&&(S=Math.round(x.reduce((M,F)=>M+F.score,0)/x.length))}catch{}let y=t.verdict??"";if(!t.verdict){let O=XL({input:process.stdin,output:process.stderr});y=await new Promise(x=>{O.question("Add your take (one line, or press Enter to skip): ",M=>{O.close(),x(M.trim())})})}let T={month:n.label,totalRecalls:r,totalTokensPiped:o,sessionsIndexed:i,mostRecalledSession:d,biggestRecallTokens:l,healthScore:S,mostActiveHours:m,archetype:b,verdict:y},R=await $r("E",T),B=n.start.slice(0,7),L=t.out??bf(YL(),"Downloads");zL(L)||JL(L,{recursive:!0});let v=bf(L,`recall-wrapped-${B}.png`);GL(v,R),process.stderr.write(`Wrapped card saved to ${v}
1971
- `)}ge();Bt();Ge();import{createRequire as QL}from"node:module";import{createInterface as ZL}from"node:readline";import{stdin as eA,stdout as tA}from"node:process";var nA=QL(import.meta.url),sA=nA(`${te()}/package.json`).version,Tf="https://clauderecall.com/api/feedback",ha=process.env.RECALL_FEEDBACK_API??Tf,yf=ha===Tf,Ea=2e3;function Rf(e){let t=ZL({input:eA,output:tA});return new Promise(n=>t.question(e,s=>{t.close(),n(s.trim())}))}function wf(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 rA(e){if(e.score!==void 0){let s=wf(e.score);return s===null?(console.error(`--score must be an integer from 1 to 5 (got "${e.score}").`),null):s}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 Rf("Score (1-5, q to quit): ");if(t.toLowerCase()==="q"||t==="")return console.log("No worries, skipped."),null;let n=wf(t);return n===null?(console.error("Please enter an integer 1 through 5."),null):n}async function oA(e,t){if(e.message!==void 0)return e.message.trim();if(!process.stdin.isTTY)return"";let n=t<=2?"What is the biggest pain point? (Enter to skip): ":"Anything you would add? (Enter to skip): ";return await Rf(n)}function iA(e){return e.length<=Ea?{value:e,truncated:!1}:{value:e.slice(0,Ea),truncated:!0}}async function kf(e={}){yf||process.stderr.write(`[recall] RECALL_FEEDBACK_API override active (${ha}); license token will NOT be sent.
1972
- `);let t=await rA(e);if(t===null)return e.score!==void 0||!process.stdin.isTTY?1:0;let n=await oA(e,t),{value:s,truncated:r}=iA(n);r&&process.stderr.write(`[recall] --message truncated to ${Ea} characters before send.
1973
- `);let o=await Le(),i=pn(),a=yf&&o.tier==="pro"&&i?i.license_jwt:null,d={score:t,comment:s.length>0?s:null,surface:"cli",version:sA,os:process.platform,trigger_kind:"manual",license_jwt:a};try{let l=await fetch(ha,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(d)});if(l.ok)return console.log(""),console.log("Thanks. Your feedback landed."),0;let u=await l.json().catch(()=>({}));return l.status===429?(console.log("You submitted feedback recently. Try again later."),0):(console.error(`Feedback failed: ${l.status} ${u.error??"unknown"}`),1)}catch(l){let u=l instanceof Error?l.message:"network error";return console.error(`Feedback could not be sent: ${u}`),1}}var oN=sN(import.meta.url),Gn=oN("../package.json").version,N=new rN;N.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(Gn);N.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 mc(e)});N.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=>{gc(e)});N.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)=>{Sc(e,t)});N.command("search <query...>").description("Search every message in every session. Pass --semantic for fused keyword + summary + vector hits (delegates to the running daemon).").option("-p, --project <name>","restrict results to one project").option("-n, --limit <n>","max results","20").option("--semantic","fuse keyword + summary + vector hits via the daemon (Pro; requires `recall start`)").action(async(e,t)=>{await $c(e.join(" "),t)});N.command("projects").description("List every project with how many sessions are in each.").action(()=>{zc()});N.command("status").description("Show database size, session counts, and whether the daemon is running.").action(()=>{Gc()});N.command("start").description("Start the background daemon. Required for live tab-name tracking and the web UI.").action(async()=>{await ds()});N.command("stop").description("Stop the background daemon.").option("--all","also kill every MCP child and truncate the WAL (one-command WAL-pin recovery)").action(async e=>{process.exitCode=await tl({all:e.all})});N.command("open").description("Open the local web UI in your browser. Starts the daemon if it is not already running.").action(async()=>{await nl()});N.command("tui").description("Browse and search sessions in an interactive terminal UI. No browser needed.").action(async()=>{let{runTui:e}=await Promise.resolve().then(()=>(r_(),s_));await e()});N.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 kl(e,t)});N.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 xl({allowWrites:!!e.allowWrites})});N.command("mcp-prune").description("Kill stuck MCP children that are holding SQLite connections. Default scope is orphans (parent claude is gone); pass --all to nuke every MCP child. Runs a WAL TRUNCATE on success so disk space comes back immediately.").option("--all","prune every MCP child, not just orphans").option("--yes","skip the interactive confirmation prompt").option("--json","emit a single JSON line instead of human-readable output (implies --yes)").action(async e=>{let t=await fs({all:!!e.all,yes:!!e.yes,json:!!e.json});process.exit(t)});N.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 Cl(e)});N.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 Ll(e)});N.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 Nl(t);return}console.error(`Unknown titles action: ${e}. Supported: audit`),process.exitCode=1});N.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 $l(e)});N.command("semantic [action] [subAction]").description('Local on-device semantic search. Default action is "status". Free, local, zero tokens (Tier-2): install, status, reindex, uninstall. Advanced \u2014 sends summaries via your Claude plan and costs plan tokens (Tier-1): on, off, backfill, pause, resume, auto-extract <on|off>. Diagnostic: verify-spawn (confirms claude CLI honors --no-session-persistence before re-enabling Tier-1), verify-backup (on-demand orphan check of the migration rollback backup; slow on large backups).').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)").option("--yes","skip interactive confirmation for `recall semantic migrate`").option("--no-backup","after `recall semantic migrate`, do NOT retain the old vectors in vec_chunks_v1_backup").option("--dry-run","for `recall semantic migrate`: print the plan + measured throughput and exit without writing anything").option("-p, --project <name>","for `recall semantic migrate`: scope to one project. Runs the embed loop only (no swap, no chunk_meta retag). Use repeated runs to drip-migrate per project; finalize with the unscoped `recall semantic migrate`.").addHelpText("after",`
1981
+ AND (st.tag LIKE '%debug%' OR st.tag LIKE '%fix%' OR st.tag LIKE '%bug%' OR st.tag LIKE '%error%')`).get(n.start,n.end).c,b={recallCount:r,uniqueSessionsRecalled:p,sessionCount:g.cnt,avgMessageCount:g.avg_msgs,nightSessionRatio:g.cnt>0?f/g.cnt:0,debugTagRatio:g.cnt>0?_/g.cnt:0},E=Nf(b),S=50;try{let{computeAllHealthScores:O}=await Promise.resolve().then(()=>(ra(),Km)),x=O();x.length>0&&(S=Math.round(x.reduce((M,F)=>M+F.score,0)/x.length))}catch{}let y=t.verdict??"";if(!t.verdict){let O=dL({input:process.stdin,output:process.stderr});y=await new Promise(x=>{O.question("Add your take (one line, or press Enter to skip): ",M=>{O.close(),x(M.trim())})})}let T={month:n.label,totalRecalls:r,totalTokensPiped:o,sessionsIndexed:i,mostRecalledSession:d,biggestRecallTokens:l,healthScore:S,mostActiveHours:m,archetype:E,verdict:y},R=await Fr("E",T),B=n.start.slice(0,7),A=t.out??Of(gL(),"Downloads");pL(A)||mL(A,{recursive:!0});let v=Of(A,`recall-wrapped-${B}.png`);uL(v,R),process.stderr.write(`Wrapped card saved to ${v}
1982
+ `)}ge();Bt();Ge();import{createRequire as EL}from"node:module";import{createInterface as bL}from"node:readline";import{stdin as SL,stdout as yL}from"node:process";var wL=EL(import.meta.url),TL=wL(`${te()}/package.json`).version,Df="https://clauderecall.com/api/feedback",wa=process.env.RECALL_FEEDBACK_API??Df,If=wa===Df,Ta=2e3;function $f(e){let t=bL({input:SL,output:yL});return new Promise(n=>t.question(e,s=>{t.close(),n(s.trim())}))}function Mf(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 RL(e){if(e.score!==void 0){let s=Mf(e.score);return s===null?(console.error(`--score must be an integer from 1 to 5 (got "${e.score}").`),null):s}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 $f("Score (1-5, q to quit): ");if(t.toLowerCase()==="q"||t==="")return console.log("No worries, skipped."),null;let n=Mf(t);return n===null?(console.error("Please enter an integer 1 through 5."),null):n}async function kL(e,t){if(e.message!==void 0)return e.message.trim();if(!process.stdin.isTTY)return"";let n=t<=2?"What is the biggest pain point? (Enter to skip): ":"Anything you would add? (Enter to skip): ";return await $f(n)}function xL(e){return e.length<=Ta?{value:e,truncated:!1}:{value:e.slice(0,Ta),truncated:!0}}async function Pf(e={}){If||process.stderr.write(`[recall] RECALL_FEEDBACK_API override active (${wa}); license token will NOT be sent.
1983
+ `);let t=await RL(e);if(t===null)return e.score!==void 0||!process.stdin.isTTY?1:0;let n=await kL(e,t),{value:s,truncated:r}=xL(n);r&&process.stderr.write(`[recall] --message truncated to ${Ta} characters before send.
1984
+ `);let o=await Ae(),i=pn(),a=If&&o.tier==="pro"&&i?i.license_jwt:null,d={score:t,comment:s.length>0?s:null,surface:"cli",version:TL,os:process.platform,trigger_kind:"manual",license_jwt:a};try{let l=await fetch(wa,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(d)});if(l.ok)return console.log(""),console.log("Thanks. Your feedback landed."),0;let u=await l.json().catch(()=>({}));return l.status===429?(console.log("You submitted feedback recently. Try again later."),0):(console.error(`Feedback failed: ${l.status} ${u.error??"unknown"}`),1)}catch(l){let u=l instanceof Error?l.message:"network error";return console.error(`Feedback could not be sent: ${u}`),1}}var kN=TN(import.meta.url),Jn=kN("../package.json").version,N=new RN;N.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(Jn);N.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 Ec(e)});N.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=>{bc(e)});N.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)=>{kc(e,t)});N.command("search <query...>").description("Search every message in every session. Pass --semantic for fused keyword + summary + vector hits (delegates to the running daemon).").option("-p, --project <name>","restrict results to one project").option("-n, --limit <n>","max results","20").option("--semantic","fuse keyword + summary + vector hits via the daemon (Pro; requires `recall start`)").action(async(e,t)=>{await Bc(e.join(" "),t)});N.command("projects").description("List every project with how many sessions are in each.").action(()=>{Kc()});N.command("status").description("Show database size, session counts, and whether the daemon is running.").action(()=>{Vc()});N.command("start").description("Start the background daemon. Required for live tab-name tracking and the web UI.").action(async()=>{await us()});N.command("stop").description("Stop the background daemon.").option("--all","also kill every MCP child and truncate the WAL (one-command WAL-pin recovery)").action(async e=>{process.exitCode=await il({all:e.all})});N.command("open").description("Open the local web UI in your browser. Starts the daemon if it is not already running.").action(async()=>{await al()});N.command("tui").description("Browse and search sessions in an interactive terminal UI. No browser needed.").action(async()=>{let{runTui:e}=await Promise.resolve().then(()=>(__(),f_));await e()});N.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 Nl(e,t)});N.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 Ol({allowWrites:!!e.allowWrites})});N.command("mcp-prune").description("Kill stuck MCP children that are holding SQLite connections. Default scope is orphans (parent claude is gone); pass --all to nuke every MCP child. Runs a WAL TRUNCATE on success so disk space comes back immediately.").option("--all","prune every MCP child, not just orphans").option("--yes","skip the interactive confirmation prompt").option("--json","emit a single JSON line instead of human-readable output (implies --yes)").action(async e=>{let t=await _s({all:!!e.all,yes:!!e.yes,json:!!e.json});process.exit(t)});N.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 vl(e)});N.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 Il(e)});N.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 Dl(t);return}console.error(`Unknown titles action: ${e}. Supported: audit`),process.exitCode=1});N.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 Bl(e)});N.command("semantic [action] [subAction]").description('Local on-device semantic search. Default action is "status". Free, local, zero tokens (Tier-2): install, status, reindex, uninstall. Advanced \u2014 sends summaries via your Claude plan and costs plan tokens (Tier-1): on, off, backfill, pause, resume, auto-extract <on|off>. Diagnostic: verify-spawn (confirms claude CLI honors --no-session-persistence before re-enabling Tier-1), verify-backup (on-demand orphan check of the migration rollback backup; slow on large backups).').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)").option("--yes","skip interactive confirmation for `recall semantic migrate`").option("--no-backup","after `recall semantic migrate`, do NOT retain the old vectors in vec_chunks_v1_backup").option("--dry-run","for `recall semantic migrate`: print the plan + measured throughput and exit without writing anything").option("-p, --project <name>","for `recall semantic migrate`: scope to one project. Runs the embed loop only (no swap, no chunk_meta retag). Use repeated runs to drip-migrate per project; finalize with the unscoped `recall semantic migrate`.").addHelpText("after",`
1974
1985
  Two lanes:
1975
1986
  Tier-2 (default, recommended): on-device 768-d embeddings via bge-base-en-v1.5
1976
1987
  + sqlite-vec. No network, no token spend. Powered by:
@@ -1986,7 +1997,7 @@ Two lanes:
1986
1997
  Reindex chunks-per-session cap (advanced):
1987
1998
  Set RECALL_REINDEX_MAX_CHUNKS=200 to cap each session at 200 chunks for a
1988
1999
  faster first pass. Default is 0 (no cap, full accuracy).
1989
- `).action(async(e,t,n)=>{await ep(e,{...n,_autoExtractAction:t})});N.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 op(e,t)});var zn=N.command("infer").description("Discover links between sessions. Subcommands: outputs | citations | l1 | links | bug-patterns.");function l_(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 pp(t)})}function d_(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 yp(t)})}function u_(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 Rp(t)})}function p_(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 Op(t)})}function m_(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 Hp(t)})}l_(zn.command("outputs"));d_(zn.command("citations"));u_(zn.command("l1"));p_(zn.command("links"));m_(zn.command("bug-patterns"));l_(N.command("extract-outputs"));d_(N.command("infer-citations"));u_(N.command("infer-l1"));p_(N.command("infer-links"));m_(N.command("infer-bug-patterns"));N.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 em(e,t)});N.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 n=process.env.RECALL_DEBUG_TIMING==="1",s=(f,h)=>{if(n){let _=Math.round(performance.now()-h);process.stderr.write(`[similar:timing] ${f}: ${_}ms
1990
- `)}},r=performance.now(),{requireProOrExit:o}=await Promise.resolve().then(()=>(ge(),gn));await o("Similar sessions"),s("requireProOrExit",r);let i=performance.now(),{isModelInstalled:a}=await Promise.resolve().then(()=>(wn(),ad)),{loadEmbedder:d,getEmbedderStatus:l}=await Promise.resolve().then(()=>(Pe(),Ms)),{findSimilarSessions:u}=await Promise.resolve().then(()=>(c_(),a_));if(s("dynamic imports",i),!a()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}if(!l().loaded){process.stderr.write(`[recall similar] loading embedder model (first run is slow, ~5-30s)\u2026
1991
- `);let f=performance.now();await d(),s("loadEmbedder (cold)",f)}let m=Math.max(1,Math.min(50,Number(t.limit??10))),p=performance.now(),g=await u(e,m);if(s("findSimilarSessions",p),g.length===0){console.log("No similar sessions found.");return}for(let f of g)console.log(` ${f.sessionId} similarity=${f.similarity.toFixed(3)}`)});N.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 am(e,t)});N.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 cm(e,t)});var Ia=N.command("correlator").description("Diagnose and fix terminal-to-session matching. Subcommands: audit | debug | restore.");function g_(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 Lm(t)})}function f_(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 Am(t)})}function __(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 lm(t)})}g_(Ia.command("debug"));f_(Ia.command("restore"));__(Ia.command("audit"));g_(N.command("correlator-debug"));f_(N.command("correlator-restore"));N.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,n)=>{await Rm(e,t,n)});N.command("doctor").description("Diagnose database health: size, WAL, FTS fragmentation, integrity, alias invariant. Exits non-zero on issues. Pass --ack <id> to acknowledge a background alert.").option("--json","emit JSON instead of formatted output").option("--ack <id>","acknowledge a background doctor alert by id (8-char prefix accepted)").action(async e=>{let t=await Si(e);process.exit(t)});N.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 dm(e);process.exit(t)});N.command("purge-phantoms").description("Remove session rows produced by historical daemon-autonomous `claude -p` spawns (auto-titler, summariser, output-index, \u2026). Source JSONLs at ~/.claude/projects/ are NEVER touched. Requires daemon stopped.").option("--dry-run","count phantom rows without deleting anything").option("--json","emit JSON instead of formatted output").action(async e=>{let t=await pm(e);process.exit(t)});N.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,n)=>{let s=e==="auto",r=await Tm({_action:e,_subAction:s?t:void 0,_sessionId:s?void 0:t,before:typeof n.before=="string"?n.before:void 0,dryRun:n.dryRun===!0,after:typeof n.after=="number"?n.after:void 0});process.exit(r)});__(N.command("correlator-audit"));N.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 Nm(e,t)});N.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 Im(e)});N.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 Fm(e)});N.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)=>{Bm(e,t)});N.command("verify [action]").description('Toggle verification badges in the UI. Defaults to "status". Actions: on, off, status.').action(e=>{Hm(e)});N.command("activate <license-key>").description("Activate your Pro license. Run once after purchase.").action(async e=>{await Km(e)});N.command("upgrade").description("Open the Pro pricing page in your browser.").action(async()=>{await Zm()});N.command("trial [promo-code]").description("Start a 7-day Pro trial. With a promo code (e.g. RECALL7DAY), redeems it directly from the CLI. With no code, opens the signup page.").action(async e=>{await tg(e)});var Br=N.command("telemetry").description('Manage the opt-in anonymous install ping. Defaults to "view".');Br.command("view",{isDefault:!0}).description("Show current decision, state file path, and next-ping payload.").action(async()=>{await lg(Gn)});Br.command("on").description("Opt in. One anonymous ping per machine per month. See https://clauderecall.com/telemetry").action(async()=>{await ag()});Br.command("off").description("Opt out. Deletes the nonce. No further pings.").action(async()=>{await cg()});Br.command("status").description("Alias for view.").action(async()=>{await oa(Gn)});var Ma=N.command("license").description('Show or remove the Pro license on this machine. Defaults to "status".');Ma.command("status",{isDefault:!0}).description("Show the current license tier.").action(async()=>{await gg()});Ma.command("deactivate").description("Remove the stored license from this machine. Reverses `recall activate`.").action(()=>{_g()});Ma.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 fg()});var iN=N.command("thread").description("Group related sessions into threads, then list, show, link, merge, or scan them."),aN=N.command("threads").description("Alias for `thread`. Both forms accept the same subcommands.");function h_(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 Vg(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=>{Yg(t)}),e.command("list").description("List threads, newest first.").option("--archived","include archived threads").option("--json","emit JSON instead of a table").action(t=>{Eg(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,n)=>{bg(t,n)}),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,n)=>{Sg(t,n)}),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,n)=>{yg(t,n)}),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,n)=>{wg(t,n)}),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,n)=>{Tg(t,n)}),e.command("rename <id-prefix> <new-name>").description("Rename a thread.").option("--json","emit JSON").action((t,n,s)=>{Rg(t,n,s)}),e.command("close <id-prefix>").description("Mark a thread as closed (work complete).").option("--json","emit JSON").action((t,n)=>{kg(t,n)}),e.command("reopen <id-prefix>").description("Reopen a closed thread.").option("--json","emit JSON").action((t,n)=>{xg(t,n)}),e.command("archive <id-prefix>").description("Archive a thread (hidden from the default list).").option("--json","emit JSON").action((t,n)=>{Cg(t,n)}),e.command("merge <source-id-prefix>").description("Merge one thread into another.").requiredOption("--into <id-prefix>","destination thread").option("--json","emit JSON").action((t,n)=>{Lg(t,n)}),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,n)=>{Ag(t,n)})}h_(iN);h_(aN);N.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 hf(e,t)});N.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 kf(e);t!==0&&(process.exitCode=t)});N.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 Sf(e,t)});process.env.CLAUDECODE&&!process.stdout.isTTY&&process.stderr.write(`<claude-code-hint v="1" type="plugin" value="claude-recall@claude-plugins-official" />
1992
- `);N.action(async()=>{await Vm()});N.hook("preAction",async(e,t)=>{let n=t.name();try{await ug(n,Gn)}catch{}ig(Gn).catch(()=>{});try{mg({commandName:n})}catch{}});N.parseAsync(process.argv).catch(e=>{console.error(e),process.exit(1)});
2000
+ `).action(async(e,t,n)=>{await lp(e,{...n,_autoExtractAction:t})});N.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 gp(e,t)});var zn=N.command("infer").description("Discover links between sessions. Subcommands: outputs | citations | l1 | links | bug-patterns.");function y_(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 yp(t)})}function w_(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 Np(t)})}function T_(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 Ip(t)})}function R_(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 Up(t)})}function k_(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 Kp(t)})}y_(zn.command("outputs"));w_(zn.command("citations"));T_(zn.command("l1"));R_(zn.command("links"));k_(zn.command("bug-patterns"));y_(N.command("extract-outputs"));w_(N.command("infer-citations"));T_(N.command("infer-l1"));R_(N.command("infer-links"));k_(N.command("infer-bug-patterns"));N.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 lm(e,t)});N.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 n=process.env.RECALL_DEBUG_TIMING==="1",s=(f,_)=>{if(n){let b=Math.round(performance.now()-_);process.stderr.write(`[similar:timing] ${f}: ${b}ms
2001
+ `)}},r=performance.now(),{requireProOrExit:o}=await Promise.resolve().then(()=>(ge(),gn));await o("Similar sessions"),s("requireProOrExit",r);let i=performance.now(),{isModelInstalled:a}=await Promise.resolve().then(()=>(wn(),pd)),{loadEmbedder:d,getEmbedderStatus:l}=await Promise.resolve().then(()=>(Fe(),Ds)),{findSimilarSessions:u}=await Promise.resolve().then(()=>(S_(),b_));if(s("dynamic imports",i),!a()){console.error("Model not installed. Run `recall semantic install` first."),process.exitCode=1;return}if(!l().loaded){process.stderr.write(`[recall similar] loading embedder model (first run is slow, ~5-30s)\u2026
2002
+ `);let f=performance.now();await d(),s("loadEmbedder (cold)",f)}let m=Math.max(1,Math.min(50,Number(t.limit??10))),p=performance.now(),g=await u(e,m);if(s("findSimilarSessions",p),g.length===0){console.log("No similar sessions found.");return}for(let f of g)console.log(` ${f.sessionId} similarity=${f.similarity.toFixed(3)}`)});N.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 _m(e,t)});N.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 hm(e,t)});var Fa=N.command("correlator").description("Diagnose and fix terminal-to-session matching. Subcommands: audit | debug | restore.");function x_(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 Um(t)})}function C_(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 Bm(t)})}function A_(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 Em(t)})}x_(Fa.command("debug"));C_(Fa.command("restore"));A_(Fa.command("audit"));x_(N.command("correlator-debug"));C_(N.command("correlator-restore"));N.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,n)=>{await $m(e,t,n)});N.command("doctor").description("Diagnose database health: size, WAL, FTS fragmentation, integrity, alias invariant. Exits non-zero on issues. Pass --ack <id> to acknowledge a background alert.").option("--json","emit JSON instead of formatted output").option("--ack <id>","acknowledge a background doctor alert by id (8-char prefix accepted)").action(async e=>{let t=await ki(e);process.exit(t)});N.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 bm(e);process.exit(t)});N.command("db <action> [name]").description("Low-level DB maintenance. Action: drop-table <name> \u2014 drop a reclaimable in-DB bloat table surfaced by `recall doctor` (cross-platform; uses embedded SQLite; requires daemon stopped). Only drops detector-approved tables.").option("--json","emit JSON instead of formatted output").action(async(e,t,n)=>{let s=await wm({_action:e,_table:t,json:n.json===!0});process.exit(s)});N.command("purge-phantoms").description("Remove session rows produced by historical daemon-autonomous `claude -p` spawns (auto-titler, summariser, output-index, \u2026). Source JSONLs at ~/.claude/projects/ are NEVER touched. Requires daemon stopped.").option("--dry-run","count phantom rows without deleting anything").option("--json","emit JSON instead of formatted output").action(async e=>{let t=await Rm(e);process.exit(t)});N.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,n)=>{let s=e==="auto",r=await Dm({_action:e,_subAction:s?t:void 0,_sessionId:s?void 0:t,before:typeof n.before=="string"?n.before:void 0,dryRun:n.dryRun===!0,after:typeof n.after=="number"?n.after:void 0});process.exit(r)});A_(N.command("correlator-audit"));N.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 Hm(e,t)});N.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 Gm(e)});N.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 Vm(e)});N.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)=>{Zm(e,t)});N.command("verify [action]").description('Toggle verification badges in the UI. Defaults to "status". Actions: on, off, status.').action(e=>{eg(e)});N.command("activate <license-key>").description("Activate your Pro license. Run once after purchase.").action(async e=>{await lg(e)});N.command("upgrade").description("Open the Pro pricing page in your browser.").action(async()=>{await ug()});N.command("trial [promo-code]").description("Start a 7-day Pro trial. With a promo code (e.g. RECALL7DAY), redeems it directly from the CLI. With no code, opens the signup page.").action(async e=>{await mg(e)});var Wr=N.command("telemetry").description('Manage the opt-in anonymous install ping. Defaults to "view".');Wr.command("view",{isDefault:!0}).description("Show current decision, state file path, and next-ping payload.").action(async()=>{await yg(Jn)});Wr.command("on").description("Opt in. One anonymous ping per machine per month. See https://clauderecall.com/telemetry").action(async()=>{await bg()});Wr.command("off").description("Opt out. Deletes the nonce. No further pings.").action(async()=>{await Sg()});Wr.command("status").description("Alias for view.").action(async()=>{await da(Jn)});var ja=N.command("license").description('Show or remove the Pro license on this machine. Defaults to "status".');ja.command("status",{isDefault:!0}).description("Show the current license tier.").action(async()=>{await xg()});ja.command("deactivate").description("Remove the stored license from this machine. Reverses `recall activate`.").action(()=>{Ag()});ja.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 Cg()});var xN=N.command("thread").description("Group related sessions into threads, then list, show, link, merge, or scan them."),CN=N.command("threads").description("Alias for `thread`. Both forms accept the same subcommands.");function L_(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 lf(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=>{af(t)}),e.command("list").description("List threads, newest first.").option("--archived","include archived threads").option("--json","emit JSON instead of a table").action(t=>{Ng(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,n)=>{Og(t,n)}),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,n)=>{vg(t,n)}),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,n)=>{Ig(t,n)}),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,n)=>{Mg(t,n)}),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,n)=>{Dg(t,n)}),e.command("rename <id-prefix> <new-name>").description("Rename a thread.").option("--json","emit JSON").action((t,n,s)=>{$g(t,n,s)}),e.command("close <id-prefix>").description("Mark a thread as closed (work complete).").option("--json","emit JSON").action((t,n)=>{Pg(t,n)}),e.command("reopen <id-prefix>").description("Reopen a closed thread.").option("--json","emit JSON").action((t,n)=>{Fg(t,n)}),e.command("archive <id-prefix>").description("Archive a thread (hidden from the default list).").option("--json","emit JSON").action((t,n)=>{jg(t,n)}),e.command("merge <source-id-prefix>").description("Merge one thread into another.").requiredOption("--into <id-prefix>","destination thread").option("--json","emit JSON").action((t,n)=>{Ug(t,n)}),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,n)=>{Bg(t,n)})}L_(xN);L_(CN);N.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 Lf(e,t)});N.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 Pf(e);t!==0&&(process.exitCode=t)});N.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 vf(e,t)});process.env.CLAUDECODE&&!process.stdout.isTTY&&process.stderr.write(`<claude-code-hint v="1" type="plugin" value="claude-recall@claude-plugins-official" />
2003
+ `);N.action(async()=>{await cg()});N.hook("preAction",async(e,t)=>{let n=t.name();try{await Tg(n,Jn)}catch{}Eg(Jn).catch(()=>{});try{kg({commandName:n})}catch{}});N.parseAsync(process.argv).catch(e=>{console.error(e),process.exit(1)});