@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.
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /* Claude Recall (proprietary). See LICENSE for terms. */
3
- var Mo=Object.defineProperty;var b=(e,t)=>()=>(e&&(t=e(e=0)),t);var ye=(e,t)=>{for(var n in t)Mo(e,n,{get:t[n],enumerable:!0})};import{createRequire as Po}from"node:module";var Fo,$o,Uo,ft,_t,ht,Et=b(()=>{"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)}}Fo=Po(import.meta.url),$o=["node","sqlite"].join(":"),Uo=Fo($o),ft=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)}},_t=class{inner;extensionLoadingEnabled=!1;txDepth=0;constructor(t,n={}){this.inner=new Uo.DatabaseSync(t,{readOnly:n.readonly??!1,allowExtension:!0})}prepare(t){return new ft(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)}},ht=_t});import{homedir as $n}from"node:os";import{join as St,basename as vp}from"node:path";import{existsSync as jo,mkdirSync as Ho,chmodSync as Wo,readdirSync as Dp,statSync as Mp}from"node:fs";function I(){jo(y)||Ho(y,{recursive:!0,mode:448}),process.platform!=="win32"&&Wo(y,448)}var Tt,y,fe,v=b(()=>{"use strict";Tt=process.env.CLAUDE_PROJECTS_DIR?process.env.CLAUDE_PROJECTS_DIR:St($n(),".claude","projects"),y=process.env.RECALL_HOME?process.env.RECALL_HOME:St($n(),".recall"),fe=St(y,"db.sqlite")});function jn(e){let t=e.prepare("PRAGMA table_info(sessions)").all(),n=new Set(t.map(u=>u.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[u,f]of s)n.has(u)||e.exec(`ALTER TABLE sessions ADD COLUMN ${u} ${f}`);let r=e.prepare("PRAGMA table_info(collection_sessions)").all(),i=new Set(r.map(u=>u.name)),o=[["source","TEXT NOT NULL DEFAULT 'manual'"],["rule_id","TEXT"]];for(let[u,f]of o)i.has(u)||e.exec(`ALTER TABLE collection_sessions ADD COLUMN ${u} ${f}`);let a=e.prepare("PRAGMA table_info(session_notes)").all(),c=new Set(a.map(u=>u.name)),l=[["auto_synopsis","TEXT"],["auto_synopsis_generated_at","INTEGER"],["auto_synopsis_history","TEXT"]];for(let[u,f]of l)c.has(u)||e.exec(`ALTER TABLE session_notes ADD COLUMN ${u} ${f}`);let d=e.prepare("PRAGMA table_info(threads)").all();new Set(d.map(u=>u.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(u=>u.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 Bi=Object.defineProperty;var y=(e,t)=>()=>(e&&(t=e(e=0)),t);var ye=(e,t)=>{for(var n in t)Bi(e,n,{get:t[n],enumerable:!0})};import{createRequire as Wi}from"node:module";var Xi,Gi,zi,ft,_t,ht,Et=y(()=>{"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)}}Xi=Wi(import.meta.url),Gi=["node","sqlite"].join(":"),zi=Xi(Gi),ft=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)}},_t=class{inner;extensionLoadingEnabled=!1;txDepth=0;constructor(t,n={}){this.inner=new zi.DatabaseSync(t,{readOnly:n.readonly??!1,allowExtension:!0})}prepare(t){return new ft(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)}},ht=_t});import{homedir as Un}from"node:os";import{join as St,basename as Xp}from"node:path";import{existsSync as Yi,mkdirSync as Ki,chmodSync as Ji,readdirSync as zp,statSync as Yp}from"node:fs";function I(){Yi(A)||Ki(A,{recursive:!0,mode:448}),process.platform!=="win32"&&Ji(A,448)}var bt,A,pe,v=y(()=>{"use strict";bt=process.env.CLAUDE_PROJECTS_DIR?process.env.CLAUDE_PROJECTS_DIR:St(Un(),".claude","projects"),A=process.env.RECALL_HOME?process.env.RECALL_HOME:St(Un(),".recall"),pe=St(A,"db.sqlite")});function Hn(e){let t=e.prepare("PRAGMA table_info(sessions)").all(),n=new Set(t.map(S=>S.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[S,m]of s)n.has(S)||e.exec(`ALTER TABLE sessions ADD COLUMN ${S} ${m}`);let r=e.prepare("PRAGMA table_info(collection_sessions)").all(),o=new Set(r.map(S=>S.name)),i=[["source","TEXT NOT NULL DEFAULT 'manual'"],["rule_id","TEXT"]];for(let[S,m]of i)o.has(S)||e.exec(`ALTER TABLE collection_sessions ADD COLUMN ${S} ${m}`);let a=e.prepare("PRAGMA table_info(session_notes)").all(),c=new Set(a.map(S=>S.name)),l=[["auto_synopsis","TEXT"],["auto_synopsis_generated_at","INTEGER"],["auto_synopsis_history","TEXT"]];for(let[S,m]of l)c.has(S)||e.exec(`ALTER TABLE session_notes ADD COLUMN ${S} ${m}`);let d=e.prepare("PRAGMA table_info(threads)").all();new Set(d.map(S=>S.name)).has("folder_id")||(e.exec("ALTER TABLE threads ADD COLUMN folder_id TEXT REFERENCES thread_folders(id) ON DELETE SET NULL"),e.exec("CREATE INDEX IF NOT EXISTS idx_threads_folder ON threads(folder_id)"));let p=e.prepare("PRAGMA table_info(thread_folders)").all(),u=new Set(p.map(S=>S.name));u.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)")),u.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 Mo=Object.defineProperty;var b=(e,t)=>()=>(e&&(t=e(e=0)),t);var ye=(e,t)=>{f
12
12
  );
13
13
  CREATE INDEX IF NOT EXISTS idx_message_embeddings_session ON message_embeddings(session_id);
14
14
  CREATE INDEX IF NOT EXISTS idx_message_embeddings_generated ON message_embeddings(generated_at DESC);
15
- `);let g=e.prepare("PRAGMA table_info(projects)").all(),h=new Set(g.map(u=>u.name)),S=[["repo_root","TEXT"],["main_repo","TEXT"],["is_repo","INTEGER NOT NULL DEFAULT 0"],["is_worktree","INTEGER NOT NULL DEFAULT 0"]];for(let[u,f]of S)h.has(u)||e.exec(`ALTER TABLE projects ADD COLUMN ${u} ${f}`)}var Un,Hn=b(()=>{"use strict";Un=`
15
+ `);let g=e.prepare("PRAGMA table_info(projects)").all(),h=new Set(g.map(S=>S.name)),E=[["repo_root","TEXT"],["main_repo","TEXT"],["is_repo","INTEGER NOT NULL DEFAULT 0"],["is_worktree","INTEGER NOT NULL DEFAULT 0"]];for(let[S,m]of E)h.has(S)||e.exec(`ALTER TABLE projects ADD COLUMN ${S} ${m}`)}var jn,Bn=y(()=>{"use strict";jn=`
16
16
  PRAGMA journal_mode = WAL;
17
17
  PRAGMA synchronous = NORMAL;
18
18
  PRAGMA foreign_keys = ON;
@@ -749,11 +749,11 @@ 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 Wn(e,t){let n=t.RECALL_DB_PROFILE;if(n&&Bo.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 Bn(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 Bo,Xn=b(()=>{"use strict";Bo=new Set(["light","full","worker"])});import*as zn from"sqlite-vec";function oe(e){let t=e;Gn.has(t)||(zn.load(e),Gn.add(t))}function Yn(e){e.prepare("SELECT 1 FROM sqlite_master WHERE name = 'vec_chunks'").get()||(oe(e),e.exec(Xo))}var Gn,Xo,Pe=b(()=>{"use strict";Gn=new WeakSet;Xo=`
752
+ `});function Wn(e,t){let n=t.RECALL_DB_PROFILE;if(n&&Vi.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 Xn(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 Vi,Gn=y(()=>{"use strict";Vi=new Set(["light","full","worker"])});import*as Yn from"sqlite-vec";function ie(e){let t=e;zn.has(t)||(Yn.load(e),zn.add(t))}function Kn(e){e.prepare("SELECT 1 FROM sqlite_master WHERE name = 'vec_chunks'").get()||(ie(e),e.exec(qi))}var zn,qi,Pe=y(()=>{"use strict";zn=new WeakSet;qi=`
753
753
  CREATE VIRTUAL TABLE IF NOT EXISTS vec_chunks USING vec0(
754
754
  embedding float[768] distance_metric=cosine
755
- );`});function E(){if(M)return M;I();let e=Wn(process.argv[1],process.env);Kn=e,M=new ht(fe);for(let[t,n]of Bn(e))M.pragma(`${t} = ${n}`);M.pragma("temp_store = MEMORY"),e!=="light"&&oe(M),M.exec(Un),jn(M),Yn(M);try{M.exec("PRAGMA optimize")}catch{}return M}function Jn(){if(M){if(Kn==="light"){try{M.pragma("wal_checkpoint(PASSIVE)")}catch{}M.close(),M=null;return}try{M.exec("PRAGMA optimize")}catch{}try{M.exec("INSERT INTO messages_fts(messages_fts, rank) VALUES('merge', 4);")}catch{}try{M.exec("INSERT INTO sessions_fts(sessions_fts, rank) VALUES('merge', 4);")}catch{}try{M.pragma("wal_checkpoint(TRUNCATE)")}catch{}M.close(),M=null}}var M,Kn,x=b(()=>{"use strict";Et();v();Hn();Xn();Pe();M=null,Kn="full"});function _e(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`}function ne(e){if(e instanceof Error)return e.stack??e.message;try{return JSON.stringify(e)}catch{return String(e)}}var we=b(()=>{"use strict"});import{writeFileSync as sa}from"node:fs";import{join as ra}from"node:path";function pe(e){return e.trim().toLowerCase().replace(/^#+/,"").replace(/[\s/\\]+/g,"-").replace(/[^a-z0-9\-._]/g,"").slice(0,40)}function Fe(e,t){let n=pe(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)})(),ns(),{tag:n,added:!0})}function es(e,t){let n=pe(t);if(!n)return{tag:"",removed:!1};let s=E(),r=new Date().toISOString();return s.prepare("SELECT 1 FROM session_tags WHERE session_id = ? AND tag = ?").get(e,n)?(s.transaction(()=>{s.prepare("DELETE FROM session_tags WHERE session_id = ? AND tag = ?").run(e,n),s.prepare("INSERT INTO tag_events (session_id, tag, action, at) VALUES (?, ?, 'remove', ?)").run(e,n,r)})(),ns(),{tag:n,removed:!0}):{tag:n,removed:!1}}function $e(e){return E().prepare("SELECT tag FROM session_tags WHERE session_id = ? ORDER BY tag").all(e).map(t=>t.tag)}function ts(){return E().prepare(`SELECT tag, COUNT(*) AS count FROM session_tags
756
- GROUP BY tag ORDER BY count DESC, tag ASC`).all()}function ns(){try{I();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};sa(ia,JSON.stringify(s,null,2))}catch(e){console.error("[tags] backup failed:",e)}}var ia,Ue=b(()=>{"use strict";x();v();ia=ra(y,"tags.json")});function oa(e,t){let n=e.filter(i=>i.content_text&&i.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 i=1;i<t-1;i++)s.add(Math.floor(i*r));return Array.from(s).sort((i,o)=>i-o).slice(0,t).map(i=>n[i])}function je(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 o=e.sessionIds.map((a,c)=>`@sid_${c}`).join(", ");r+=` AND s.id IN (${o})`,e.sessionIds.forEach((a,c)=>{n[`sid_${c}`]=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,
755
+ );`});function _(){if(P)return P;I();let e=Wn(process.argv[1],process.env);Jn=e,P=new ht(pe);for(let[t,n]of Xn(e))P.pragma(`${t} = ${n}`);P.pragma("temp_store = MEMORY"),e!=="light"&&ie(P),P.exec(jn),Hn(P),Kn(P);try{P.exec("PRAGMA optimize")}catch{}return P}function Vn(){if(P){if(Jn==="light"){try{P.pragma("wal_checkpoint(PASSIVE)")}catch{}P.close(),P=null;return}try{P.exec("PRAGMA optimize")}catch{}try{P.exec("INSERT INTO messages_fts(messages_fts, rank) VALUES('merge', 4);")}catch{}try{P.exec("INSERT INTO sessions_fts(sessions_fts, rank) VALUES('merge', 4);")}catch{}try{P.pragma("wal_checkpoint(TRUNCATE)")}catch{}P.close(),P=null}}var P,Jn,x=y(()=>{"use strict";Et();v();Bn();Gn();Pe();P=null,Jn="full"});function _e(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`}function se(e){if(e instanceof Error)return e.stack??e.message;try{return JSON.stringify(e)}catch{return String(e)}}var we=y(()=>{"use strict"});import{writeFileSync as da}from"node:fs";import{join as ua}from"node:path";function me(e){return e.trim().toLowerCase().replace(/^#+/,"").replace(/[\s/\\]+/g,"-").replace(/[^a-z0-9\-._]/g,"").slice(0,40)}function Fe(e,t){let n=me(t);if(!n)throw new Error("tag must contain at least one alphanumeric character");let s=_(),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)})(),ss(),{tag:n,added:!0})}function ts(e,t){let n=me(t);if(!n)return{tag:"",removed:!1};let s=_(),r=new Date().toISOString();return s.prepare("SELECT 1 FROM session_tags WHERE session_id = ? AND tag = ?").get(e,n)?(s.transaction(()=>{s.prepare("DELETE FROM session_tags WHERE session_id = ? AND tag = ?").run(e,n),s.prepare("INSERT INTO tag_events (session_id, tag, action, at) VALUES (?, ?, 'remove', ?)").run(e,n,r)})(),ss(),{tag:n,removed:!0}):{tag:n,removed:!1}}function $e(e){return _().prepare("SELECT tag FROM session_tags WHERE session_id = ? ORDER BY tag").all(e).map(t=>t.tag)}function ns(){return _().prepare(`SELECT tag, COUNT(*) AS count FROM session_tags
756
+ GROUP BY tag ORDER BY count DESC, tag ASC`).all()}function ss(){try{I();let 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};da(pa,JSON.stringify(s,null,2))}catch(e){console.error("[tags] backup failed:",e)}}var pa,Ue=y(()=>{"use strict";x();v();pa=ua(A,"tags.json")});function ma(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 je(e){let t=_(),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,c)=>`@sid_${c}`).join(", ");r+=` AND s.id IN (${i})`,e.sessionIds.forEach((a,c)=>{n[`sid_${c}`]=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,
757
757
  NULLIF(sa.alias, '') AS alias,
758
758
  COALESCE(s.first_user_message, '') AS first_user_message
759
759
  FROM sessions s
@@ -761,38 +761,38 @@ CREATE VIRTUAL TABLE IF NOT EXISTS vec_chunks USING vec0(
761
761
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
762
762
  WHERE ${r}
763
763
  ORDER BY COALESCE(s.started_at, '') DESC
764
- LIMIT @limit`).all(n).map(o=>{let a=t.prepare(`SELECT role, COALESCE(content_text, '') AS content_text
764
+ LIMIT @limit`).all(n).map(i=>{let a=t.prepare(`SELECT role, COALESCE(content_text, '') AS content_text
765
765
  FROM messages WHERE session_id = ?
766
- ORDER BY COALESCE(timestamp, ''), rowid`).all(o.id),l=oa(a,5).map(d=>`${d.role}: ${d.content_text.slice(0,400)}`).join(`
766
+ ORDER BY COALESCE(timestamp, ''), rowid`).all(i.id),l=ma(a,5).map(d=>`${d.role}: ${d.content_text.slice(0,400)}`).join(`
767
767
  ---
768
- `);return{id:o.id,project:o.project,git_branch:o.git_branch,alias:o.alias,first_user_message:o.first_user_message,message_sample:l,current_tags:$e(o.id)}})}var yt=b(()=>{"use strict";x();Ue()});import{z as G}from"zod";function At(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:"],i=[];return e.sessionId?(i.push("limit: 1"),r.push(` ${i.join(", ")}`),r.push(` Then match the session id ${e.sessionId} from the returned list.`)):(s&&i.push("untaggedOnly: true"),e.project&&i.push(`project: "${e.project}"`),e.collectionId&&i.push(`collectionId: "${e.collectionId}"`),i.push(`limit: ${e.limit??100}`),r.push(` ${i.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(`
769
- `)}function _a(e){let t=e.mode==="detailed";return[`Summarize Claude Recall session ${e.sessionId} using the MCP tools available to you.`,"",`1. Call \`context_for_session\` with id "${e.sessionId}" and mode "condensed" to get the transcript as markdown.`,t?"2. Write a 1-paragraph overview (\u22643 sentences) of what this session was for, then 5-8 bullet points covering:":"2. Write 3-5 bullet points covering:"," - What was accomplished (shipped, decided, learned)"," - What was tried and abandoned"," - Any explicit open questions or follow-ups","","Rules:",'- Be concrete. Name files, functions, and decisions. Avoid vague "discussed X".',"- If nothing was actually shipped or decided, say so plainly.",'- Reply with just the summary \u2014 no preamble, no "Here is the summary:".'].join(`
770
- `)}function Ea(e){return[`Extract every architectural or product decision made in Claude Recall session ${e.sessionId}.`,"",`1. Call \`context_for_session\` with id "${e.sessionId}" and mode "full" (so tool I/O is included \u2014 sometimes the decision lives in a commit message or diff).`,"2. For each distinct decision, emit one block:",""," - **Decision:** one sentence."," - **Why:** the stated rationale (quote if possible).",' - **Alternatives considered:** bullet list, or "none mentioned".',' - **Where it landed:** file path / function name / commit SHA if identifiable, otherwise "TBD".',"","Rules:","- Include only decisions that were actually made, not ideas merely discussed.","- If an alternative was rejected, list it with a one-line reason.","- Group related decisions under a short heading when useful.",'- If the session made zero real decisions, reply exactly with: "No decisions made in this session."',"- No preamble, no closing, just the decision blocks."].join(`
771
- `)}function Ta(e){let t=e.limit??5;return[`Find ${t} Recall sessions most similar to session ${e.sessionId}.`,"",`1. Call \`get_session\` with id "${e.sessionId}" \u2014 note its alias, first user message, tags, and git branch.`,'2. Derive 2-3 short search queries from that content (topic words, library names, error strings \u2014 NOT generic words like "fix" or "add").',`3. Call \`search\` once per query (limit: ${Math.max(5,t*2)}). Dedupe hits by session_id.`,"4. Also call `list_sessions` with the same tag(s) if the target session has any (pick the most specific tag).","5. Union the results. Exclude the target session itself. Rank by a mix of:"," - Shared tags (strongest signal)"," - Matching search hits across multiple queries"," - Recency as a tiebreaker","",`6. Return the top ${t} as a numbered list. For each:`," - **<short_id> \xB7 <project>** \u2014 <alias or first_user_message truncated>",' - One sentence on WHY it is similar (not a generic "same topic" \u2014 be specific).',"","If fewer than 2 genuinely-similar sessions exist, say so rather than padding with weak matches.","No preamble. Just the ranked list."].join(`
772
- `)}var ga,fa,ha,Sa,ba,ya,wa,Ra,rs,Nt=b(()=>{"use strict";ga={project:G.string().optional().describe("Exact project name match (optional)."),collectionId:G.string().optional().describe("Restrict to sessions in this collection (optional)."),sessionId:G.string().optional().describe("Full session UUID to tag just one session (optional)."),untaggedOnly:G.boolean().optional().describe("Skip sessions that already have any tag (default: true)."),limit:G.number().int().min(1).max(500).optional().describe("Max sessions to process (default: 100)."),minTags:G.number().int().min(1).max(10).optional().describe("Minimum tags per session (default: 2)."),maxTags:G.number().int().min(1).max(10).optional().describe("Maximum tags per session (default: 4).")};fa={sessionId:G.string().describe("Session UUID (or 8+-char prefix) to summarize."),mode:G.enum(["brief","detailed"]).optional().describe("brief = 3-5 bullets; detailed = paragraph + bullets. Default: brief.")};ha={sessionId:G.string().describe("Session UUID (or 8+-char prefix) to extract decisions from.")};Sa={sessionId:G.string().describe("Session UUID (or 8+-char prefix) to find similar sessions to."),limit:G.number().int().min(1).max(20).optional().describe("How many similar sessions to surface (default: 5).")};ba={name:"auto_tag_sessions",title:"Auto-tag Recall sessions",description:"Have the agent auto-tag Recall sessions using the Recall MCP tools. Scope can be restricted to a project, collection, or single session.",argsSchema:ga,build:At,allowedTools:["mcp__recall__list_tags","mcp__recall__list_sessions_to_tag","mcp__recall__apply_tags"]},ya={name:"summarize_session",title:"Summarize a session",description:"Produce a concise, concrete summary of one session \u2014 what shipped, what was tried, what's still open.",argsSchema:fa,build:_a,allowedTools:["mcp__recall__get_session","mcp__recall__context_for_session"]},wa={name:"extract_decisions",title:"Extract architectural decisions",description:"Scan a session and emit one structured block per architectural / product decision: what, why, alternatives, where it landed.",argsSchema:ha,build:Ea,allowedTools:["mcp__recall__get_session","mcp__recall__context_for_session"]},Ra={name:"find_similar_sessions",title:"Find similar sessions",description:"Given a session, find other sessions that touched the same topic / library / error \u2014 ranked with reasons.",argsSchema:Sa,build:Ta,allowedTools:["mcp__recall__get_session","mcp__recall__search","mcp__recall__list_sessions","mcp__recall__list_tags"]},rs=[ba,ya,wa,Ra]});import{writeFileSync as Aa}from"node:fs";import{join as Na}from"node:path";function is(e){try{let t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return[]}function ka(){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:is(t.previous_aliases)}))}function He(e,t){let n=t.trim();if(!n)throw new Error("alias must be non-empty");let s=E(),r=new Date().toISOString(),i=s.prepare("SELECT alias, previous_aliases FROM session_aliases WHERE session_id = ?").get(e),o=[];return i&&(o=is(i.previous_aliases),i.alias!==n&&o.push({alias:i.alias,replaced_at:r})),s.prepare(`INSERT INTO session_aliases (session_id, alias, updated_at, previous_aliases)
768
+ `);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:$e(i.id)}})}var yt=y(()=>{"use strict";x();Ue()});import{z as Y}from"zod";function At(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(`
769
+ `)}function wa(e){let t=e.mode==="detailed";return[`Summarize Claude Recall session ${e.sessionId} using the MCP tools available to you.`,"",`1. Call \`context_for_session\` with id "${e.sessionId}" and mode "condensed" to get the transcript as markdown.`,t?"2. Write a 1-paragraph overview (\u22643 sentences) of what this session was for, then 5-8 bullet points covering:":"2. Write 3-5 bullet points covering:"," - What was accomplished (shipped, decided, learned)"," - What was tried and abandoned"," - Any explicit open questions or follow-ups","","Rules:",'- Be concrete. Name files, functions, and decisions. Avoid vague "discussed X".',"- If nothing was actually shipped or decided, say so plainly.",'- Reply with just the summary \u2014 no preamble, no "Here is the summary:".'].join(`
770
+ `)}function Aa(e){return[`Extract every architectural or product decision made in Claude Recall session ${e.sessionId}.`,"",`1. Call \`context_for_session\` with id "${e.sessionId}" and mode "full" (so tool I/O is included \u2014 sometimes the decision lives in a commit message or diff).`,"2. For each distinct decision, emit one block:",""," - **Decision:** one sentence."," - **Why:** the stated rationale (quote if possible).",' - **Alternatives considered:** bullet list, or "none mentioned".',' - **Where it landed:** file path / function name / commit SHA if identifiable, otherwise "TBD".',"","Rules:","- Include only decisions that were actually made, not ideas merely discussed.","- If an alternative was rejected, list it with a one-line reason.","- Group related decisions under a short heading when useful.",'- If the session made zero real decisions, reply exactly with: "No decisions made in this session."',"- No preamble, no closing, just the decision blocks."].join(`
771
+ `)}function La(e){let t=e.limit??5;return[`Find ${t} Recall sessions most similar to session ${e.sessionId}.`,"",`1. Call \`get_session\` with id "${e.sessionId}" \u2014 note its alias, first user message, tags, and git branch.`,'2. Derive 2-3 short search queries from that content (topic words, library names, error strings \u2014 NOT generic words like "fix" or "add").',`3. Call \`search\` once per query (limit: ${Math.max(5,t*2)}). Dedupe hits by session_id.`,"4. Also call `list_sessions` with the same tag(s) if the target session has any (pick the most specific tag).","5. Union the results. Exclude the target session itself. Rank by a mix of:"," - Shared tags (strongest signal)"," - Matching search hits across multiple queries"," - Recency as a tiebreaker","",`6. Return the top ${t} as a numbered list. For each:`," - **<short_id> \xB7 <project>** \u2014 <alias or first_user_message truncated>",' - One sentence on WHY it is similar (not a generic "same topic" \u2014 be specific).',"","If fewer than 2 genuinely-similar sessions exist, say so rather than padding with weak matches.","No preamble. Just the ranked list."].join(`
772
+ `)}var Ta,ya,Ra,Na,ka,xa,Oa,Ia,os,Nt=y(()=>{"use strict";Ta={project:Y.string().optional().describe("Exact project name match (optional)."),collectionId:Y.string().optional().describe("Restrict to sessions in this collection (optional)."),sessionId:Y.string().optional().describe("Full session UUID to tag just one session (optional)."),untaggedOnly:Y.boolean().optional().describe("Skip sessions that already have any tag (default: true)."),limit:Y.number().int().min(1).max(500).optional().describe("Max sessions to process (default: 100)."),minTags:Y.number().int().min(1).max(10).optional().describe("Minimum tags per session (default: 2)."),maxTags:Y.number().int().min(1).max(10).optional().describe("Maximum tags per session (default: 4).")};ya={sessionId:Y.string().describe("Session UUID (or 8+-char prefix) to summarize."),mode:Y.enum(["brief","detailed"]).optional().describe("brief = 3-5 bullets; detailed = paragraph + bullets. Default: brief.")};Ra={sessionId:Y.string().describe("Session UUID (or 8+-char prefix) to extract decisions from.")};Na={sessionId:Y.string().describe("Session UUID (or 8+-char prefix) to find similar sessions to."),limit:Y.number().int().min(1).max(20).optional().describe("How many similar sessions to surface (default: 5).")};ka={name:"auto_tag_sessions",title:"Auto-tag Recall sessions",description:"Have the agent auto-tag Recall sessions using the Recall MCP tools. Scope can be restricted to a project, collection, or single session.",argsSchema:Ta,build:At,allowedTools:["mcp__recall__list_tags","mcp__recall__list_sessions_to_tag","mcp__recall__apply_tags"]},xa={name:"summarize_session",title:"Summarize a session",description:"Produce a concise, concrete summary of one session \u2014 what shipped, what was tried, what's still open.",argsSchema:ya,build:wa,allowedTools:["mcp__recall__get_session","mcp__recall__context_for_session"]},Oa={name:"extract_decisions",title:"Extract architectural decisions",description:"Scan a session and emit one structured block per architectural / product decision: what, why, alternatives, where it landed.",argsSchema:Ra,build:Aa,allowedTools:["mcp__recall__get_session","mcp__recall__context_for_session"]},Ia={name:"find_similar_sessions",title:"Find similar sessions",description:"Given a session, find other sessions that touched the same topic / library / error \u2014 ranked with reasons.",argsSchema:Na,build:La,allowedTools:["mcp__recall__get_session","mcp__recall__search","mcp__recall__list_sessions","mcp__recall__list_tags"]},os=[ka,xa,Oa,Ia]});import{writeFileSync as va}from"node:fs";import{join as Ca}from"node:path";function is(e){try{let t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return[]}function Ma(){return _().prepare("SELECT session_id, alias, updated_at, previous_aliases FROM session_aliases").all().map(t=>({session_id:t.session_id,alias:t.alias,updated_at:t.updated_at,previous_aliases:is(t.previous_aliases)}))}function He(e,t){let n=t.trim();if(!n)throw new Error("alias must be non-empty");let s=_(),r=new Date().toISOString(),o=s.prepare("SELECT alias, previous_aliases FROM session_aliases WHERE session_id = ?").get(e),i=[];return o&&(i=is(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)
773
773
  VALUES (?, ?, ?, ?)
774
774
  ON CONFLICT(session_id) DO UPDATE SET
775
775
  alias = excluded.alias,
776
776
  updated_at = excluded.updated_at,
777
- previous_aliases = excluded.previous_aliases`).run(e,n,r,JSON.stringify(o)),xa(),{session_id:e,alias:n,updated_at:r,previous_aliases:o}}function xa(){try{I();let e=ka(),t={schema:"claude-recall.aliases.v1",backed_up_at:new Date().toISOString(),aliases:e};Aa(La,JSON.stringify(t,null,2))}catch(e){console.error("[aliases] backup failed:",e)}}var La,We=b(()=>{"use strict";x();v();La=Na(y,"aliases.json")});import{randomUUID as $a}from"node:crypto";import{writeFileSync as Ua,readFileSync as km,existsSync as xm}from"node:fs";import{join as ja}from"node:path";function Wa(e){return{...e}}function xt(e,t,n,s=null,r=new Date().toISOString()){E().prepare(`INSERT INTO collection_events (collection_id, session_id, action, payload, at)
778
- VALUES (?, ?, ?, ?, ?)`).run(e,s,t,n?JSON.stringify(n):null,r)}function Ba(e){let t=E().prepare("SELECT * FROM collections WHERE id = ?").get(e);if(!t)throw new Error(`collection not found: ${e}`);return t}function Xa(e){if(!e)return 0;let t=0,n=e,s=new Set,r=E();for(;n;){if(s.has(n))throw new Error("collection cycle detected");s.add(n);let i=r.prepare("SELECT parent_id FROM collections WHERE id = ?").get(n);if(!i)break;t+=1,n=i.parent_id}return t}function ds(e){let t=E().prepare("SELECT * FROM collections WHERE id = ?").get(e);return t?Wa(t):null}function Ot(e){let t=(e.name??"").trim();if(!t)throw new Error("name required");if(t.length>120)throw new Error("name too long (max 120 chars)");let n=E(),s=new Date().toISOString(),r=$a();if(e.parent_id){if(!ds(e.parent_id))throw new Error("parent collection not found");if(Xa(e.parent_id)>=ls-1)throw new Error(`max collection depth is ${ls}`)}return n.transaction(()=>{n.prepare(`INSERT INTO collections
777
+ previous_aliases = excluded.previous_aliases`).run(e,n,r,JSON.stringify(i)),Pa(),{session_id:e,alias:n,updated_at:r,previous_aliases:i}}function Pa(){try{I();let e=Ma(),t={schema:"claude-recall.aliases.v1",backed_up_at:new Date().toISOString(),aliases:e};va(Da,JSON.stringify(t,null,2))}catch(e){console.error("[aliases] backup failed:",e)}}var Da,Be=y(()=>{"use strict";x();v();Da=Ca(A,"aliases.json")});import{randomUUID as Ga}from"node:crypto";import{writeFileSync as za,readFileSync as jm,existsSync as Hm}from"node:fs";import{join as Ya}from"node:path";function Ja(e){return{...e}}function xt(e,t,n,s=null,r=new Date().toISOString()){_().prepare(`INSERT INTO collection_events (collection_id, session_id, action, payload, at)
778
+ VALUES (?, ?, ?, ?, ?)`).run(e,s,t,n?JSON.stringify(n):null,r)}function Va(e){let t=_().prepare("SELECT * FROM collections WHERE id = ?").get(e);if(!t)throw new Error(`collection not found: ${e}`);return t}function qa(e){if(!e)return 0;let t=0,n=e,s=new Set,r=_();for(;n;){if(s.has(n))throw new Error("collection cycle detected");s.add(n);let o=r.prepare("SELECT parent_id FROM collections WHERE id = ?").get(n);if(!o)break;t+=1,n=o.parent_id}return t}function us(e){let t=_().prepare("SELECT * FROM collections WHERE id = ?").get(e);return t?Ja(t):null}function Ot(e){let t=(e.name??"").trim();if(!t)throw new Error("name required");if(t.length>120)throw new Error("name too long (max 120 chars)");let n=_(),s=new Date().toISOString(),r=Ga();if(e.parent_id){if(!us(e.parent_id))throw new Error("parent collection not found");if(qa(e.parent_id)>=ds-1)throw new Error(`max collection depth is ${ds}`)}return n.transaction(()=>{n.prepare(`INSERT INTO collections
779
779
  (id, name, description, icon, color, parent_id, sort_key, created_at, updated_at, archived_at)
780
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL)`).run(r,t,e.description??null,e.icon??null,e.color??null,e.parent_id??null,e.sort_key??"",s,s),xt(r,"create",{name:t,parent_id:e.parent_id??null,icon:e.icon??null,color:e.color??null},null,s)})(),vt(),ds(r)}function It(e,t,n=null,s={}){let r=E();if(Ba(e),!r.prepare("SELECT 1 FROM sessions WHERE id = ?").get(t))throw new Error(`session not found: ${t}`);if(r.prepare("SELECT 1 FROM collection_sessions WHERE collection_id = ? AND session_id = ?").get(e,t))return{added:!1};let a=s.source??"manual",c=s.rule_id??null;if(a==="auto"&&!c)throw new Error("auto membership requires a rule_id");let l=new Date().toISOString();return r.transaction(()=>{r.prepare(`INSERT INTO collection_sessions (collection_id, session_id, added_at, note, source, rule_id)
781
- VALUES (?, ?, ?, ?, ?, ?)`).run(e,t,l,n,a,c),xt(e,"add",{note:n,source:a,rule_id:c},t,l)})(),vt(),{added:!0}}function us(e,t){let n=E();if(!n.prepare("SELECT 1 FROM collection_sessions WHERE collection_id = ? AND session_id = ?").get(e,t))return{removed:!1};let r=new Date().toISOString();return n.transaction(()=>{n.prepare("DELETE FROM collection_sessions WHERE collection_id = ? AND session_id = ?").run(e,t),xt(e,"remove",null,t,r)})(),vt(),{removed:!0}}function Ga(){return E().prepare(`SELECT id, collection_id, session_id, action, payload, at
780
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL)`).run(r,t,e.description??null,e.icon??null,e.color??null,e.parent_id??null,e.sort_key??"",s,s),xt(r,"create",{name:t,parent_id:e.parent_id??null,icon:e.icon??null,color:e.color??null},null,s)})(),vt(),us(r)}function It(e,t,n=null,s={}){let r=_();if(Va(e),!r.prepare("SELECT 1 FROM sessions WHERE id = ?").get(t))throw new Error(`session not found: ${t}`);if(r.prepare("SELECT 1 FROM collection_sessions WHERE collection_id = ? AND session_id = ?").get(e,t))return{added:!1};let a=s.source??"manual",c=s.rule_id??null;if(a==="auto"&&!c)throw new Error("auto membership requires a rule_id");let l=new Date().toISOString();return r.transaction(()=>{r.prepare(`INSERT INTO collection_sessions (collection_id, session_id, added_at, note, source, rule_id)
781
+ VALUES (?, ?, ?, ?, ?, ?)`).run(e,t,l,n,a,c),xt(e,"add",{note:n,source:a,rule_id:c},t,l)})(),vt(),{added:!0}}function ps(e,t){let n=_();if(!n.prepare("SELECT 1 FROM collection_sessions WHERE collection_id = ? AND session_id = ?").get(e,t))return{removed:!1};let r=new Date().toISOString();return n.transaction(()=>{n.prepare("DELETE FROM collection_sessions WHERE collection_id = ? AND session_id = ?").run(e,t),xt(e,"remove",null,t,r)})(),vt(),{removed:!0}}function Qa(){return _().prepare(`SELECT id, collection_id, session_id, action, payload, at
782
782
  FROM collection_events
783
- ORDER BY at ASC, id ASC`).all()}function vt(){try{I();let e=E(),t=e.prepare(`SELECT id, name, description, icon, color, parent_id, sort_key,
783
+ ORDER BY at ASC, id ASC`).all()}function vt(){try{I();let e=_(),t=e.prepare(`SELECT id, name, description, icon, color, parent_id, sort_key,
784
784
  created_at, updated_at, archived_at
785
785
  FROM collections
786
786
  ORDER BY COALESCE(parent_id, ''), sort_key, LOWER(name)`).all(),n=e.prepare(`SELECT collection_id, session_id, added_at, note, source, rule_id
787
787
  FROM collection_sessions
788
- ORDER BY collection_id, added_at`).all(),s=Ga(),r={schema:"claude-recall.collections.v1",backed_up_at:new Date().toISOString(),collections:t,memberships:n,events:s};Ua(Ha,JSON.stringify(r,null,2))}catch(e){console.error("[collections] backup failed:",e)}}var Ha,ls,Ct=b(()=>{"use strict";x();v();Ha=ja(y,"collections.json"),ls=8});function xs(e){if(e.alias&&e.alias.trim())return e.alias.trim();if(e.auto_title&&e.auto_title.trim())return e.auto_title.trim();let t=(e.first_user_message??"").trim();if(!t)return e.id.slice(0,8);let n=t.split(`
789
- `)[0].trim();return n.length>ks?n.slice(0,ks)+"\u2026":n}function Za(e){return E().prepare(`SELECT s.id AS id,
788
+ ORDER BY collection_id, added_at`).all(),s=Qa(),r={schema:"claude-recall.collections.v1",backed_up_at:new Date().toISOString(),collections:t,memberships:n,events:s};za(Ka,JSON.stringify(r,null,2))}catch(e){console.error("[collections] backup failed:",e)}}var Ka,ds,Ct=y(()=>{"use strict";x();v();Ka=Ya(A,"collections.json"),ds=8});function Os(e){if(e.alias&&e.alias.trim())return e.alias.trim();if(e.auto_title&&e.auto_title.trim())return e.auto_title.trim();let t=(e.first_user_message??"").trim();if(!t)return e.id.slice(0,8);let n=t.split(`
789
+ `)[0].trim();return n.length>xs?n.slice(0,xs)+"\u2026":n}function ic(e){return _().prepare(`SELECT s.id AS id,
790
790
  sa.alias AS alias,
791
791
  s.auto_title AS auto_title,
792
792
  s.first_user_message AS first_user_message
793
793
  FROM sessions s
794
794
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
795
- WHERE s.id = ?`).get(e)??null}function ec(e){let t=Za(e);return t?xs(t):e.slice(0,8)}function Os(e){if(!e)return null;let t=E(),n=t.prepare(`SELECT e.thread_id AS thread_id,
795
+ WHERE s.id = ?`).get(e)??null}function ac(e){let t=ic(e);return t?Os(t):e.slice(0,8)}function Is(e){if(!e)return null;let t=_(),n=t.prepare(`SELECT e.thread_id AS thread_id,
796
796
  t.name AS thread_name,
797
797
  e.parent_session_id AS parent_session_id,
798
798
  e.added_at AS added_at
@@ -801,7 +801,7 @@ CREATE VIRTUAL TABLE IF NOT EXISTS vec_chunks USING vec0(
801
801
  WHERE e.session_id = ?
802
802
  AND t.archived = 0
803
803
  ORDER BY e.added_at DESC
804
- LIMIT 1`).get(e);if(!n)return null;let s=n.parent_session_id?{id:n.parent_session_id,title:ec(n.parent_session_id)}:null,r=n.parent_session_id?[e,n.parent_session_id]:[e],i=r.map(()=>"?").join(", "),a=t.prepare(`SELECT e.session_id AS session_id,
804
+ LIMIT 1`).get(e);if(!n)return null;let s=n.parent_session_id?{id:n.parent_session_id,title:ac(n.parent_session_id)}:null,r=n.parent_session_id?[e,n.parent_session_id]:[e],o=r.map(()=>"?").join(", "),a=t.prepare(`SELECT e.session_id AS session_id,
805
805
  s.id AS id,
806
806
  sa.alias AS alias,
807
807
  s.auto_title AS auto_title,
@@ -810,8 +810,8 @@ CREATE VIRTUAL TABLE IF NOT EXISTS vec_chunks USING vec0(
810
810
  LEFT JOIN sessions s ON s.id = e.session_id
811
811
  LEFT JOIN session_aliases sa ON sa.session_id = e.session_id
812
812
  WHERE e.thread_id = ?
813
- AND e.session_id NOT IN (${i})
814
- ORDER BY e.added_at ASC`).all(n.thread_id,...r).map(c=>({id:c.session_id,title:c.id?xs(c):c.session_id.slice(0,8)}));return{thread_id:n.thread_id,thread_name:n.thread_name,parent_session:s,siblings:a}}var ks,Is=b(()=>{"use strict";x();ks=80});var jt=b(()=>{"use strict"});var vs=b(()=>{"use strict"});import{writeFileSync as tc,mkdirSync as nc,existsSync as sc}from"node:fs";import{join as Cs}from"node:path";function Ds(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 Ms(e){let t=E(),n=t.prepare(`SELECT rowid AS rid, content_text
813
+ AND e.session_id NOT IN (${o})
814
+ ORDER BY e.added_at ASC`).all(n.thread_id,...r).map(c=>({id:c.session_id,title:c.id?Os(c):c.session_id.slice(0,8)}));return{thread_id:n.thread_id,thread_name:n.thread_name,parent_session:s,siblings:a}}var xs,vs=y(()=>{"use strict";x();xs=80});var jt=y(()=>{"use strict"});var Cs=y(()=>{"use strict"});import{writeFileSync as cc,mkdirSync as lc,existsSync as dc}from"node:fs";import{join as Ds}from"node:path";function Ms(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 Ps(e){let t=_(),n=t.prepare(`SELECT rowid AS rid, content_text
815
815
  FROM messages
816
816
  WHERE session_id = ? AND role = 'user' AND is_sidechain = 0
817
817
  AND content_text IS NOT NULL AND content_text != ''
@@ -821,30 +821,34 @@ CREATE VIRTUAL TABLE IF NOT EXISTS vec_chunks USING vec0(
821
821
  WHERE session_id = ? AND role = 'user' AND is_sidechain = 0
822
822
  AND content_text IS NOT NULL AND content_text != ''
823
823
  ORDER BY COALESCE(timestamp, '') DESC, rowid DESC
824
- LIMIT ?`).all(e,Ye),r=new Map;for(let d of n)r.set(d.rid,d.content_text);for(let d of s)r.set(d.rid,d.content_text);if(r.size===0)throw new Error("no user messages available to summarise");let i=Array.from(r.entries()).sort((d,m)=>d[0]-m[0]).map(([,d])=>({content_text:d})),o=n.length===Ae&&s.length===Ye&&r.size===Ae+Ye,a=i.map((d,m)=>{let p=(d.content_text??"").slice(0,rc);return o&&m===Ae?`--- (middle of session omitted) ---
825
- ${m+1}. ${p}`:`${m+1}. ${p}`}).join(`
826
- `),c=null;try{c=Os(e)}catch(d){console.error("[autoTitle] thread context resolution failed:",d),c=null}let l=[];return c&&(l.push(ic(c)),l.push("")),l.push(`You will receive a sample of user messages from a Claude Code session: the first ${Ae}`,`messages (initial intent) and the last ${Ye} messages (current direction).`,"Write a single descriptive title, max 50 characters, focused on what the user is","currently trying to accomplish. If initial intent and current direction differ, prefer","the current direction. Output ONLY the title, with no quotes and no trailing punctuation.","","Messages:",a),l.join(`
827
- `)}function ic(e){let t=[];t.push("Thread context:"),t.push(`- This session is part of thread "${e.thread_name}".`),e.parent_session&&t.push(`- Parent session: "${e.parent_session.title}"`);let n=e.siblings.length;if(n>0){let r=e.siblings.slice(0,Ht).map(o=>`"${o.title}"`).join(", "),i=n>Ht?`, and ${n-Ht} more`:"";t.push(`- Sibling sessions (${n}): ${r}${i}`)}return t.push(""),t.push("Generate a title that reflects this session's role in the thread."),t.push('If siblings use a pattern like "Phase A / Phase B" or "Wave 1 of 4",'),t.push("follow the same pattern."),t.join(`
828
- `)}function Bt(e,t,n){let s=t.trim();if(!s)return;let r=E(),i=r.prepare(`SELECT auto_title, auto_title_source, auto_title_generated_at, auto_title_history
829
- FROM sessions WHERE id = ?`).get(e);if(!i||n==="heuristic"&&i.auto_title_source==="agent"&&i.auto_title||i.auto_title===s&&i.auto_title_source===n)return;let o=Ds(i.auto_title_history),a=new Date().toISOString();i.auto_title&&i.auto_title_source&&o.push({title:i.auto_title,source:i.auto_title_source,replaced_at:a}),r.prepare(`UPDATE sessions
824
+ LIMIT ?`).all(e,Ye),r=new Map;for(let d of n)r.set(d.rid,d.content_text);for(let d of s)r.set(d.rid,d.content_text);if(r.size===0)throw new Error("no user messages available to summarise");let o=Array.from(r.entries()).sort((d,p)=>d[0]-p[0]).map(([,d])=>({content_text:d})),i=n.length===Ae&&s.length===Ye&&r.size===Ae+Ye,a=o.map((d,p)=>{let u=(d.content_text??"").slice(0,uc);return i&&p===Ae?`--- (middle of session omitted) ---
825
+ ${p+1}. ${u}`:`${p+1}. ${u}`}).join(`
826
+ `),c=null;try{c=Is(e)}catch(d){console.error("[autoTitle] thread context resolution failed:",d),c=null}let l=[];return c&&(l.push(pc(c)),l.push("")),l.push(`You will receive a sample of user messages from a Claude Code session: the first ${Ae}`,`messages (initial intent) and the last ${Ye} messages (current direction).`,"Write a single descriptive title, max 50 characters, focused on what the user is","currently trying to accomplish. If initial intent and current direction differ, prefer","the current direction. Output ONLY the title, with no quotes and no trailing punctuation.","","Messages:",a),l.join(`
827
+ `)}function pc(e){let t=[];t.push("Thread context:"),t.push(`- This session is part of thread "${e.thread_name}".`),e.parent_session&&t.push(`- Parent session: "${e.parent_session.title}"`);let n=e.siblings.length;if(n>0){let r=e.siblings.slice(0,Ht).map(i=>`"${i.title}"`).join(", "),o=n>Ht?`, and ${n-Ht} more`:"";t.push(`- Sibling sessions (${n}): ${r}${o}`)}return t.push(""),t.push("Generate a title that reflects this session's role in the thread."),t.push('If siblings use a pattern like "Phase A / Phase B" or "Wave 1 of 4",'),t.push("follow the same pattern."),t.join(`
828
+ `)}function Wt(e,t,n){let s=t.trim();if(!s)return;let r=_(),o=r.prepare(`SELECT auto_title, auto_title_source, auto_title_generated_at, auto_title_history
829
+ 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=Ms(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
830
830
  SET auto_title = ?,
831
831
  auto_title_source = ?,
832
832
  auto_title_generated_at = ?,
833
833
  auto_title_history = ?
834
- WHERE id = ?`).run(s,n,Date.now(),JSON.stringify(o),e),ac(e,s,n,a)}function Ps(e){let t=E().prepare(`SELECT auto_title, auto_title_source, auto_title_generated_at, auto_title_history
835
- FROM sessions WHERE id = ?`).get(e);return t?{auto_title:t.auto_title,auto_title_source:t.auto_title_source??null,auto_title_generated_at:t.auto_title_generated_at,auto_title_history:Ds(t.auto_title_history)}:null}function oc(){I(),sc(Wt)||nc(Wt,{recursive:!0})}function ac(e,t,n,s){try{oc();let r=Cs(Wt,`${e}.txt`),i=`# Claude Recall auto-title \xB7 session ${e} \xB7 source ${n} \xB7 updated ${s}
836
- `;tc(r,i+t+`
837
- `)}catch(r){console.error("[autoTitle] mirror write failed:",r)}}var Wt,Ae,Ye,rc,Ht,Xt=b(()=>{"use strict";x();v();Is();jt();vs();Wt=Cs(y,"titles"),Ae=5,Ye=15,rc=500;Ht=5});function Fs(e,t){let n=cc.get(e);if(!(!n||n.size===0))for(let s of n)try{s(t)}catch{}}var cc,$s=b(()=>{"use strict";cc=new Map});import{existsSync as lc,statSync as dc}from"node:fs";import{delimiter as uc,join as pc}from"node:path";function Us(e){if(e.includes("/")||e.includes("\\")||e.includes(".."))return null;let t=(process.env.PATH??"").split(uc).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 i=pc(s,r);try{if(lc(i)&&dc(i).isFile())return i}catch{}}return null}function js(e){if(process.platform!=="win32"||!e)return!1;let t=e.toLowerCase();return t.endsWith(".cmd")||t.endsWith(".bat")}var Hs=b(()=>{"use strict"});var Ys={};ye(Ys,{_resetClaudePathCacheForTests:()=>_c,buildScanPrompt:()=>Xs,isClaudeCliAvailable:()=>Bs,runClaudeCliScan:()=>bc,spawnClaudePrompt:()=>Gs});import{spawn as mc}from"node:child_process";function Ws(){if(Ee!==void 0&&Ne!==void 0)return{path:Ee,available:Ne};let e=Us("claude");return Ee=e??"claude",Ne=e!==null,{path:Ee,available:Ne}}function fc(){return Ws().path}function Bs(){return Ws().available}function _c(){Ee=void 0,Ne=void 0}function Xs(e){return At({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 hc(e,t){let n=t.get(e);return n||e.slice(0,8)}function Ec(e){try{return je(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 Sc(e){let{scanId:t,total:n,labelTable:s}=e,r=new Set;return i=>{let o=i.trim();if(!o.startsWith("{"))return;let a;try{a=JSON.parse(o)}catch{return}if(!a||typeof a!="object")return;let c=a;if(!(c.type!=="assistant"||!c.message?.content))for(let l of c.message.content){if(l?.type!=="tool_use"||l.name!=="mcp__recall__apply_tags")continue;let d=l.input,m=typeof d?.sessionId=="string"?d.sessionId:null;!m||r.has(m)||(r.add(m),Fs(t,{type:"progress",current:r.size,total:n,sessionId:m,sessionLabel:hc(m,s)}))}}}function Tc(e){let t="";return n=>{t+=n.toString("utf8");let s=t.indexOf(`
834
+ WHERE id = ?`).run(s,n,Date.now(),JSON.stringify(i),e),gc(e,s,n,a)}function Fs(e){let t=_().prepare(`SELECT auto_title, auto_title_source, auto_title_generated_at, auto_title_history
835
+ FROM sessions WHERE id = ?`).get(e);return t?{auto_title:t.auto_title,auto_title_source:t.auto_title_source??null,auto_title_generated_at:t.auto_title_generated_at,auto_title_history:Ms(t.auto_title_history)}:null}function mc(){I(),dc(Bt)||lc(Bt,{recursive:!0})}function gc(e,t,n,s){try{mc();let r=Ds(Bt,`${e}.txt`),o=`# Claude Recall auto-title \xB7 session ${e} \xB7 source ${n} \xB7 updated ${s}
836
+ `;cc(r,o+t+`
837
+ `)}catch(r){console.error("[autoTitle] mirror write failed:",r)}}var Bt,Ae,Ye,uc,Ht,Xt=y(()=>{"use strict";x();v();vs();jt();Cs();Bt=Ds(A,"titles"),Ae=5,Ye=15,uc=500;Ht=5});function $s(e,t){let n=fc.get(e);if(!(!n||n.size===0))for(let s of n)try{s(t)}catch{}}var fc,Us=y(()=>{"use strict";fc=new Map});import{existsSync as _c,statSync as hc}from"node:fs";import{delimiter as Ec,join as Sc}from"node:path";function js(e){if(e.includes("/")||e.includes("\\")||e.includes(".."))return null;let t=(process.env.PATH??"").split(Ec).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=Sc(s,r);try{if(_c(o)&&hc(o).isFile())return o}catch{}}return null}function Hs(e){if(process.platform!=="win32"||!e)return!1;let t=e.toLowerCase();return t.endsWith(".cmd")||t.endsWith(".bat")}var Bs=y(()=>{"use strict"});var Ks={};ye(Ks,{_resetClaudePathCacheForTests:()=>wc,buildScanPrompt:()=>Gs,isClaudeCliAvailable:()=>Xs,runClaudeCliScan:()=>kc,spawnClaudePrompt:()=>zs});import{spawn as bc}from"node:child_process";function Ws(){if(Ee!==void 0&&Ne!==void 0)return{path:Ee,available:Ne};let e=js("claude");return Ee=e??"claude",Ne=e!==null,{path:Ee,available:Ne}}function yc(){return Ws().path}function Xs(){return Ws().available}function wc(){Ee=void 0,Ne=void 0}function Gs(e){return At({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 Rc(e,t){let n=t.get(e);return n||e.slice(0,8)}function Ac(e){try{return je(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 Nc(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 c=a;if(!(c.type!=="assistant"||!c.message?.content))for(let l of c.message.content){if(l?.type!=="tool_use"||l.name!=="mcp__recall__apply_tags")continue;let d=l.input,p=typeof d?.sessionId=="string"?d.sessionId:null;!p||r.has(p)||(r.add(p),$s(t,{type:"progress",current:r.size,total:n,sessionId:p,sessionLabel:Rc(p,s)}))}}}function Lc(e){let t="";return n=>{t+=n.toString("utf8");let s=t.indexOf(`
838
838
  `);for(;s!==-1;){let r=t.slice(0,s);t=t.slice(s+1),r.length>0&&e(r),s=t.indexOf(`
839
- `)}}}async function bc(e,t={},n){let s=!!t.scanId,r=s?Ec(e):[],i=new Map(r.map(c=>[c.id,c.label])),o=r.length,a;return s&&t.scanId&&(a=Sc({scanId:t.scanId,total:o,labelTable:i})),zs({prompt:Xs(e),allowedTools:gc.split(","),opts:t,onProgress:n,onStdoutLine:a,outputFormat:s?"stream-json":"json"})}async function Gs(e,t,n={},s){return zs({prompt:e,allowedTools:t,opts:n,onProgress:s,outputFormat:"json"})}function zs(e){let{prompt:t,allowedTools:n,opts:s,onProgress:r,onStdoutLine:i,outputFormat:o}=e,a=["-p",t,"--output-format",o,"--allowedTools",n.join(","),"--permission-mode","bypassPermissions","--no-session-persistence"];return o==="stream-json"&&a.push("--verbose"),s.model&&a.push("--model",s.model),new Promise(c=>{let l=fc(),d=mc(l,a,{stdio:["ignore","pipe","pipe"],shell:js(l)||process.platform==="win32"&&Ee==="claude"}),m=[],p=[],g=i?Tc(i):void 0;d.stdout.on("data",S=>{m.push(S),g&&g(S)}),d.stderr.on("data",S=>{if(p.push(S),r){let u=S.toString("utf8").trim();u&&r(u)}});let h=setTimeout(()=>{d.kill("SIGKILL")},1800*1e3);d.on("close",S=>{clearTimeout(h),c({success:S===0,stdout:Buffer.concat(m).toString("utf8"),stderr:Buffer.concat(p).toString("utf8"),exitCode:S})}),d.on("error",S=>{clearTimeout(h),c({success:!1,stdout:"",stderr:String(S),exitCode:null})})})}var gc,Ee,Ne,Gt=b(()=>{"use strict";yt();Nt();$s();Hs();gc=["mcp__recall__list_tags","mcp__recall__list_sessions_to_tag","mcp__recall__apply_tags"].join(",")});import{existsSync as nl}from"node:fs";import{dirname as yr}from"node:path";import{fileURLToPath as sl}from"node:url";function Te(){if(Ve)return Ve;let e=yr(sl(import.meta.url));for(;!nl(`${e}/package.json`);){let t=yr(e);if(t===e)throw new Error(`package.json not found walking up from ${import.meta.url}`);e=t}return Ve=e,Ve}var Ve,qe=b(()=>{"use strict";Ve=null});function Qe(e){let t=null;return()=>t||(t=(async()=>{try{return await e()}finally{t=null}})(),t)}var qt=b(()=>{"use strict"});function rl(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(`
840
- `)}var Ze,Y,Le=b(()=>{"use strict";Ze="BAAI/bge-base-en-v1.5",Y=class extends Error{kind;path;underlying;cause;constructor(t){super(rl(t)),this.name="EmbedderUnavailableError",this.kind=t.kind,this.path=t.path,this.underlying=t.underlying,this.cause=t}}});var nt={};ye(nt,{embed:()=>ml,embedQuery:()=>gl,getEmbedderStatus:()=>pl,loadEmbedder:()=>ul,unloadEmbedder:()=>fl});import{Worker as il}from"node:worker_threads";import{join as ol}from"node:path";import{existsSync as al}from"node:fs";function cl(){return ol(Te(),"dist","daemon","embedder-worker.js")}function wr(e){for(let t of ke.values())t.reject(e);ke.clear()}function ll(){if(se)return se;let e=cl();if(!al(e))throw new Y({kind:"bundle-missing",detail:"embedder-worker bundle not found - run `npm run build:cli` to emit it",path:e});let t=new il(e);return t.on("message",n=>{let s=ke.get(n.id);s&&(ke.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));wr(s),se=null,Q=!1}),t.on("exit",n=>{n!==0&&(console.error(`[embedder-worker] exited with code ${n}`),wr(new Error(`embedder worker exited with code ${n}`))),se=null,Q=!1}),se=t,t}function et(e){return new Promise((t,n)=>{let s;try{s=ll()}catch(r){n(r instanceof Error?r:new Error(String(r)));return}ke.set(e.id,{resolve:t,reject:n}),s.postMessage(e)})}function tt(){return Qt=Qt+1>>>0,String(Qt)}function en(e){if(!e.ok)throw e.unavailable?new Y({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 ul(){if(!(Q&&se))try{await dl(),Q=!0}catch(e){throw Q=!1,e}}function pl(){return{loaded:Q,modelId:Ze,dim:768}}async function ml(e){if(!Q)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");return en(await et({id:tt(),type:"embed",texts:e})).embeddings.map(n=>new Float32Array(n))}async function gl(e){if(!Q)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");let t=en(await et({id:tt(),type:"embedQuery",text:e}));return new Float32Array(t.embedding)}async function fl(){if(!se){Q=!1;return}try{await et({id:tt(),type:"unload"})}catch{}Q=!1;let e=se;se=null;try{await e.terminate()}catch{}}var se,ke,Qt,Q,dl,Rr=b(()=>{"use strict";qe();qt();Le();se=null,ke=new Map,Qt=0,Q=!1;dl=Qe(async()=>{en(await et({id:tt(),type:"load"}))})});var sn={};ye(sn,{LLAMACPP_MODEL_ID:()=>Nr,MODEL_ID:()=>Ze,embed:()=>Rl,embedQuery:()=>Al,getEmbedderStatus:()=>wl,loadEmbedder:()=>yl,unloadEmbedder:()=>Nl});import{Worker as _l}from"node:worker_threads";import{join as hl}from"node:path";import{existsSync as El}from"node:fs";function Sl(){return hl(Te(),"dist","daemon","embedder-worker-llamacpp.js")}function Ar(e){for(let t of xe.values())t.reject(e);xe.clear()}function Tl(){if(re)return re;let e=Sl();if(!El(e))throw new Y({kind:"bundle-missing",detail:"embedder-worker-llamacpp bundle not found - run `npm run build:cli` to emit it",path:e});let t=new _l(e);return t.on("message",n=>{let s=xe.get(n.id);s&&(xe.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));Ar(s),re=null,Z=!1}),t.on("exit",n=>{n!==0&&(console.error(`[embedder-worker-llamacpp] exited with code ${n}`),Ar(new Error(`embedder worker exited with code ${n}`))),re=null,Z=!1}),re=t,t}function st(e){return new Promise((t,n)=>{let s;try{s=Tl()}catch(r){n(r instanceof Error?r:new Error(String(r)));return}xe.set(e.id,{resolve:t,reject:n}),s.postMessage(e)})}function rt(){return tn=tn+1>>>0,String(tn)}function nn(e){if(!e.ok)throw e.unavailable?new Y({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 yl(){if(!(Z&&re))try{await bl(),Z=!0}catch(e){throw Z=!1,e}}function wl(){return{loaded:Z,modelId:Nr,dim:768}}async function Rl(e){if(!Z)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");return nn(await st({id:rt(),type:"embed",texts:e})).embeddings.map(n=>new Float32Array(n))}async function Al(e){if(!Z)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");let t=nn(await st({id:rt(),type:"embedQuery",text:e}));return new Float32Array(t.embedding)}async function Nl(){if(!re){Z=!1;return}try{await st({id:rt(),type:"unload"})}catch{}Z=!1;let e=re;re=null;try{await e.terminate()}catch{}}var Nr,re,xe,tn,Z,bl,Lr=b(()=>{"use strict";qe();qt();Le();Le();Nr="BAAI/bge-base-en-v1.5-gguf-q8_0";re=null,xe=new Map,tn=0,Z=!1;bl=Qe(async()=>{nn(await st({id:rt(),type:"load"}))})});function Ll(){let e=(process.env.RECALL_EMBEDDER_BACKEND??"").trim().toLowerCase();return e==="llama"||e==="llamacpp"?sn:(e===""||e==="onnx"||process.stderr.write(`[embedder] RECALL_EMBEDDER_BACKEND="${e}" is not recognized; falling back to onnx. Valid values: onnx, llama.
841
- `),nt)}var Oe,rn,Ie,kl,pf,mf,on=b(()=>{"use strict";Rr();Lr();Le();Oe=Ll(),rn=Oe.loadEmbedder,Ie=Oe.getEmbedderStatus,kl=Oe.embed,pf=Oe.embedQuery,mf=Oe.unloadEmbedder});var Ir=b(()=>{"use strict";x()});var vr=b(()=>{"use strict";x()});function Cr(){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 Bl(){return E().prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}function Dr(){return{running:jl,queueDepth:Bl(),lastProcessedAt:Hl,blacklistedCount:Wl.size,pausedForMigration:Cr()}}var jl,Hl,Wl,un=b(()=>{"use strict";x();on();Ir();vr();jl=!1,Hl=null,Wl=new Set});import ee from"chalk";import{formatDistanceToNowStrict as Y_,parseISO as K_}from"date-fns";var _,hn=b(()=>{"use strict";_={dim:ee.gray,bold:ee.bold,project:ee.cyan,user:ee.blue,assistant:ee.green,tool:ee.magenta,warn:ee.yellow,err:ee.red,ok:ee.green,accent:ee.hex("#f97316")}});var ti=b(()=>{"use strict"});var ni=b(()=>{"use strict"});var si=b(()=>{"use strict"});import{existsSync as Id,readFileSync as vd,writeFileSync as Cd}from"node:fs";import{join as Dd}from"node:path";import{z as W}from"zod";function Tn(e){let t=e.trim();return!!(!t||ii.test(t)||oi.test(t))}function ai(e){let t=e.trim();if(!t||oi.test(t))return null;let n=t.replace(ii,"").trim();return n.length>0?n:null}function Sn(e,t){if(!Tn(e))return e;let n=ai(e);return n||(t&&!Tn(t)?t:e)}function Ud(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(i=>i.cwd&&i.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 En,ri,Md,Pd,Fd,$d,ii,oi,bn,jd,ci=b(()=>{"use strict";v();En=Dd(y,"terminals.json"),ri=1440*60*1e3,Md=3e4,Pd=6e4,Fd=W.object({shell_pid:W.number(),tab_name:W.string(),cwd:W.string().nullable().optional(),opened_at:W.string(),last_seen_at:W.string()}),$d=W.object({schema:W.string().optional(),saved_at:W.string().optional(),terminals:W.array(Fd).max(500).default([]),sessions_by_pid:W.record(W.string(),W.array(W.string()).max(50)).optional().default({})}),ii=/^[⠀-⣿✳\s]+/,oi=/^\d+(\.\d+){1,3}$/;bn=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,!!Id(En)))try{let t=vd(En,"utf8"),n=JSON.parse(t),s=$d.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 i of r.terminals)this.entries.set(i.shell_pid,{shell_pid:i.shell_pid,tab_name:i.tab_name,cwd:i.cwd??null,opened_at:i.opened_at,last_seen_at:i.last_seen_at});for(let[i,o]of Object.entries(r.sessions_by_pid??{})){let a=Number(i);if(!Number.isFinite(a))continue;let c=new Set;for(let l of o)l.length>0&&c.add(l);c.size>0&&this.sessionsByPid.set(a,c)}this.gc()}catch{}}save(){try{I();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)]))};Cd(En,JSON.stringify(t,null,2))}catch{}}upsert(t){this.ensureLoaded();let n=new Date().toISOString(),s=this.entries.get(t.shell_pid),r=Sn(t.tab_name,s?.tab_name),i=s?.opened_at??t.opened_at,o={...t,tab_name:r,opened_at:i,last_seen_at:n};return this.entries.set(t.shell_pid,o),this.gc(),this.save(),o}rename(t,n){this.ensureLoaded();let s=this.entries.get(t);if(!s)return null;let r=Sn(n,s.tab_name),i={...s,tab_name:r,last_seen_at:new Date().toISOString()};return this.entries.set(t,i),this.save(),i}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>Pd?(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 i of t){let o=this.entries.get(i.shell_pid),a=Sn(i.tab_name,o?.tab_name),c=o?.opened_at??i.opened_at;this.entries.set(i.shell_pid,{...i,tab_name:a,opened_at:c,last_seen_at:n}),o?(o.tab_name!==a||o.cwd!==i.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=Ud({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()-Md;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()-ri;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()-ri;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,i=0;for(let[o,a]of this.sessionsByPid){let c=this.entries.get(o);if(c){let l=Date.parse(c.last_seen_at);if(Number.isFinite(l)&&l>=s)continue}i+=a.size,this.sessionsByPid.delete(o),c&&(this.entries.delete(o),r++)}return(r||i)&&this.save(),{pruned_pids:r,pruned_sessions:i}}gcDeadPids(){this.ensureLoaded();let t=0,n=0;for(let s of[...this.entries.keys()]){let r=!0;try{process.kill(s,0)}catch(o){o.code==="ESRCH"&&(r=!1)}if(r)continue;this.entries.delete(s),t++;let i=this.sessionsByPid.get(s);i&&(n+=i.size,this.sessionsByPid.delete(s)),this.outputTails.delete(s),this.pidOwnership.delete(s)}return(t||n)&&this.save(),{pruned_pids:t,pruned_sessions:n}}},jd=new bn});import{execFile as Hd}from"node:child_process";import{promisify as Wd}from"node:util";var oh,li=b(()=>{"use strict";oh=Wd(Hd)});import{execFile as Xd}from"node:child_process";import{promisify as Gd}from"node:util";var fh,_h,di=b(()=>{"use strict";ci();We();x();li();fh=Gd(Xd),_h=3600*1e3});var Eh,ui=b(()=>{"use strict";Eh=64*1024});import{existsSync as zd,mkdirSync as bh,readFileSync as Yd,writeFileSync as yh}from"node:fs";import{homedir as Kd}from"node:os";import{join as pi}from"node:path";import{z as te}from"zod";function Jd(){return process.env.RECALL_HOME??pi(Kd(),".recall")}function Vd(){return pi(Jd(),"config.json")}function Qd(){let e=Vd();if(!zd(e))return{};try{return JSON.parse(Yd(e,"utf8"))}catch(t){return console.error("[semantic-config] failed to parse config.json, using defaults:",t),{}}}function wn(){let e=Qd().semantic;if(!e)return{...yn};let t=qd.safeParse({...yn,...e});return t.success?t.data:{...yn}}var qd,yn,Rn=b(()=>{"use strict";Et();x();v();qd=te.object({enabled:te.boolean().default(!1),model:te.string().optional(),ratePerMinute:te.number().int().min(1).max(600).default(30),lastProcessedSessionId:te.string().nullable().default(null),backfillPaused:te.boolean().default(!1),autoExtractEnabled:te.boolean().default(!1),autoExtractIntervalMinutes:te.number().int().min(5).max(720).default(60),autoExtractBatchSize:te.number().int().min(1).max(20).default(1),autoResumeWorker:te.boolean().default(!1)}),yn={enabled:!1,ratePerMinute:30,lastProcessedSessionId:null,backfillPaused:!1,autoExtractEnabled:!1,autoExtractIntervalMinutes:60,autoExtractBatchSize:1,autoResumeWorker:!1}});var mi=b(()=>{"use strict";x();Gt();Rn()});var gi=b(()=>{"use strict"});import{execFile as Zd}from"node:child_process";import{promisify as eu}from"node:util";var Uh,fi=b(()=>{"use strict";x();Uh=eu(Zd)});import{z as An}from"zod";var Wh,_i=b(()=>{"use strict";Wh=An.object({heuristicEnabled:An.boolean().default(!0),agentEnabled:An.boolean().default(!1)})});import{basename as zh,join as Nn}from"node:path";var hi,Vh,qh,Ei=b(()=>{"use strict";x();v();Ct();hi=Nn(y,"auto-rules"),Vh=Nn(hi,"rules.json"),qh=Nn(hi,"suggestions.json")});var Si=b(()=>{"use strict"});var Ti=b(()=>{"use strict"});var bi=b(()=>{"use strict"});var yi=b(()=>{"use strict";bi()});var wi=b(()=>{"use strict"});var Ri=b(()=>{"use strict"});function Ai(e){return e.replace(/\\/g,"/").includes("/subagents/")}function Ni(e){let t=e.split(/[/\\]/),n=t.findIndex(s=>s==="projects");return n===-1||n+1>=t.length?null:t[n+1]??null}var Li=b(()=>{"use strict"});import{watch as IE}from"chokidar";import{readdirSync as nu,statSync as CE}from"node:fs";import{basename as HE,join as su}from"node:path";function*Ln(e){let t;try{t=nu(e,{withFileTypes:!0,encoding:"utf8"})}catch{return}for(let n of t){if(n.isSymbolicLink())continue;let s=su(e,n.name);n.isDirectory()?yield*Ln(s):n.isFile()&&n.name.endsWith(".jsonl")&&(yield s)}}var ki,xi,Oi=b(()=>{"use strict";v();x();ti();ni();si();di();ui();mi();gi();fi();Xt();_i();Ei();jt();Si();We();Ti();yi();un();wi();Ri();Li();ki=Ni,xi=Ai});import{execFileSync as Di}from"node:child_process";function iu(e){for(let t of ru)if(e.includes(t))return!0;return!1}function ve(e={}){let t=e.psOutput??ou(),n=e.isProcessAlive??au,s=e.getParentCommand??cu,r=[];for(let i of t.split(`
842
- `)){let o=i.trim();if(!o||!iu(o)||lu(o))continue;let a=o.split(/\s+/);if(a.length<5)continue;let c=Number(a[0]),l=Number(a[1]),d=a[2],m=a[3],p=a[4],g=0,h=0;if(/^\d+$/.test(m)&&(p.includes(".")||/^\d+$/.test(p))?(g=Number(m),h=Number(p)):h=Number(m),!Number.isFinite(c)||!Number.isFinite(l))continue;let u=l>1&&n(l);r.push({pid:c,ppid:l,parentAlive:u,etimeSeconds:du(d),pcpu:Number.isFinite(h)?h:0,rssKb:Number.isFinite(g)?g:0,orphan:!u,parentCommand:u?s(l):null})}return r}function ou(){try{return Di("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}
843
- `),""}}function au(e){if(!Number.isFinite(e)||e<=1)return!1;try{return process.kill(e,0),!0}catch{return!1}}function cu(e){if(!Number.isFinite(e)||e<=1)return null;try{let n=Di("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 lu(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 du(e){if(!e)return 0;let t=0,n=e,s=e.indexOf("-");s>=0&&(t=Ii(e.slice(0,s)),n=e.slice(s+1));let r=n.split(":").map(Ii),i=0,o=0,a=0;return r.length===3?[i,o,a]=r:r.length===2?[o,a]=r:r.length===1&&(a=r[0]),t*86400+i*3600+o*60+a}function Ii(e){let t=Number(e);return Number.isFinite(t)?t:0}function lt(e){return e.pcpu>=uu&&e.etimeSeconds>=pu}function Ci(e){return e.reduce((t,n)=>t+(Number.isFinite(n.rssKb)&&n.rssKb>0?n.rssKb:0),0)}function Mi(e){let t=e??ve(),n=t.length,s=Ci(t),r=t.filter(p=>p.orphan),i=r.length,o=Ci(r),a=i>vi,c=o>mu;if(!(a||c))return{flagged:!1,severity:"ok",count:n,aggregateRssKb:s,orphanCount:i,orphanRssKb:o,message:null};let d=[];a&&d.push(`${i} orphaned MCP children (threshold ${vi})`),c&&d.push(`${gu(o)} aggregate RSS across orphaned children (threshold 1 GiB)`);let m=`Zombie MCP threshold breached: ${d.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:i,orphanRssKb:o,message:m}}function gu(e){return e<1024?`${e} KB`:e<1024*1024?`${(e/1024).toFixed(1)} MB`:`${(e/(1024*1024)).toFixed(2)} GB`}var ru,uu,pu,vi,mu,dt=b(()=>{"use strict";ru=["dist/mcp-server.js","dist/mcp/server.js"];uu=50,pu=60;vi=4,mu=1024*1024});import{execFileSync as Pi}from"node:child_process";function _u(e){let t=e.replace(/\\/g,"/");for(let n of fu)if(t.includes(n))return!0;return!1}function hu(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 ut(e={}){let t=e.psOutput??Eu(),n=new Set(e.excludePids??[]),s=[];for(let r of t.split(`
844
- `)){let i=r.trim();if(!i||!_u(i))continue;let o=i.split(/\s+/);if(hu(o)||o.length<5)continue;let a=Number(o[0]),c=Number(o[1]),l=o[2];!Number.isFinite(a)||!Number.isFinite(c)||n.has(a)||s.push({pid:a,ppid:c,etimeSeconds:Su(l),etime:l,command:i})}return s.sort((r,i)=>r.etimeSeconds-i.etimeSeconds),s}function Eu(){if(process.platform==="win32")try{return Pi("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}
845
- `),""}try{return Pi("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}
846
- `),""}}function Su(e){if(!e)return 0;let t=0,n=e,s=e.indexOf("-");s>=0&&(t=Fi(e.slice(0,s)),n=e.slice(s+1));let r=n.split(":").map(Fi),i=0,o=0,a=0;return r.length===3?[i,o,a]=r:r.length===2?[o,a]=r:r.length===1&&(a=r[0]),t*86400+i*3600+o*60+a}function Fi(e){let t=Number(e);return Number.isFinite(t)?t:0}function kn(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"),i=String(s.getMinutes()).padStart(2,"0"),o=String(s.getSeconds()).padStart(2,"0");return`${r}:${i}:${o}`}var fu,xn=b(()=>{"use strict";fu=["dist/daemon/entrypoint.js"]});import{join as Tu}from"node:path";var pS,On=b(()=>{"use strict";v();pS=Tu(y,"daemon.log")});import{join as yu}from"node:path";var $i,Ui=b(()=>{"use strict";v();On();$i=yu(y,"daemon.token")});import{basename as SS,join as In}from"node:path";function ji(){return{pid:wu,port:Ru,token:$i}}function Hi(e){return Au(e)}function Au(e){try{return process.kill(e,0),!0}catch{return!1}}var wu,Ru,RS,Wi=b(()=>{"use strict";v();Ui();xn();On();wu=In(y,"daemon.pid"),Ru=In(y,"daemon.port"),RS=In(y,"daemon.log")});var kS,Bi,Xi=b(()=>{"use strict";we();dt();kS=5*6e4,Bi=1073741824});import{existsSync as Nu,readFileSync as Lu,renameSync as Gi,writeFileSync as ku}from"node:fs";import{join as xu}from"node:path";function zi(){return xu(y,"doctor-state.json")}function Yi(){let e=zi();if(!Nu(e))return{chunkQueue:{samples:[]}};let t;try{t=Lu(e,"utf8")}catch{return{chunkQueue:{samples:[]}}}try{let n=JSON.parse(t),s=n.chunkQueue?.samples,r=Array.isArray(s)?s.filter(c=>typeof c=="object"&&c!==null&&typeof c.ts=="string"&&typeof c.size=="number"&&typeof c.semanticEnabled=="boolean"):[],i=n.autoPruneCounters?.events,o=Array.isArray(i)?i.filter(c=>{if(!c||typeof c!="object")return!1;let l=c;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(o.length>0||i!==void 0)&&(a.autoPruneCounters={events:o}),a}catch{try{Gi(e,`${e}.corrupt.${Date.now()}`)}catch{}return{chunkQueue:{samples:[]}}}}function Ki(e){let t=zi(),n=`${t}.tmp`;try{ku(n,JSON.stringify(e,null,2),{mode:384}),Gi(n,t)}catch{}}function vn(){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=Yi(),r=Date.now(),i=s.chunkQueue.samples,o=i.map(h=>({s:h,ms:Date.parse(h.ts)})).filter(h=>Number.isFinite(h.ms)&&r-h.ms<=Iu).sort((h,S)=>h.ms-S.ms),a=null;o.length>0&&(a=t-o[0].s.size);let c=o.length,d={chunkQueue:{samples:[...i,{ts:new Date(r).toISOString(),size:t,semanticEnabled:n}].slice(-Ou)}};s.autoPruneCounters&&(d.autoPruneCounters=s.autoPruneCounters),Ki(d);let m="ok",p=`chunk_queue growth: ok (current ${t.toLocaleString()} row${t===1?"":"s"}, semantic ${n?"on":"off"}, ${c} prior sample${c===1?"":"s"} in last hour).`,g=null;return t>vu&&!n&&a!==null&&a>Cu?(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>Du?(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>Mu&&(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:c,message:p,remediation:g}}function Ji(e={}){let t=e.now??Date.now(),n=Yi(),s=n.autoPruneCounters?.events??[],r=s.filter(l=>{let d=Date.parse(l.ts);return Number.isFinite(d)&&t-d<=Pu});if(r.length!==s.length)try{let l={chunkQueue:n.chunkQueue,autoPruneCounters:{events:r}};Ki(l)}catch{}let i={orphan_10min:0,runaway_cpu_5min:0},o=0,a=0,c=0;for(let l of r)i[l.reason]+=1,l.action==="would_kill"?o+=1:l.action==="killed"?a+=1:c+=1;return{wouldHaveKilled:o,killed:a,failed:c,byReason:i}}var Ou,Iu,vu,Cu,Du,Mu,Pu,Cn=b(()=>{"use strict";v();x();Ou=24,Iu=3600*1e3,vu=1e3,Cu=1e3,Du=1e4,Mu=5e3,Pu=1440*60*1e3});function qi(e=process.env){let t=e.RECALL_AUTO_PRUNE;if(typeof t!="string")return Vi;let n=t.trim().toLowerCase();return n==="off"||n==="dry-run"||n==="enabled"?n:Vi}var Vi,Qi=b(()=>{"use strict";dt();Cn();Vi="dry-run"});import{existsSync as Fu,readFileSync as $u,renameSync as eo,writeFileSync as Uu}from"node:fs";import{join as ju}from"node:path";function to(){return ju(y,"doctor-alerts.json")}function no(){let e=to();if(!Fu(e))return{version:1,lastTickAt:new Date(0).toISOString(),alerts:[]};let t;try{t=$u(e,"utf8")}catch{return{version:1,lastTickAt:new Date(0).toISOString(),alerts:[]}}let n;try{n=JSON.parse(t)}catch{return Zi(e),{version:1,lastTickAt:new Date(0).toISOString(),alerts:[]}}if(!n||typeof n!="object"||Array.isArray(n))return Zi(e),{version:1,lastTickAt:new Date(0).toISOString(),alerts:[]};let s=n,r=Array.isArray(s.alerts)?s.alerts.filter(Hu):[];return{version:1,lastTickAt:typeof s.lastTickAt=="string"?s.lastTickAt:new Date(0).toISOString(),alerts:r}}function Zi(e){try{eo(e,`${e}.corrupt.${Date.now()}`)}catch{}}function Hu(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 so(e){let t=to(),n=`${t}.tmp`;try{Uu(n,JSON.stringify(e,null,2),{mode:384}),eo(n,t)}catch{}}function ro(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 i={...r,acknowledged:!0},o=e.alerts.map(a=>a.id===r.id?i:a);return{file:{...e,alerts:o},result:{outcome:"acknowledged",matched:i}}}var io=b(()=>{"use strict";v()});var Lo={};ye(Lo,{WATCHER_REFLAG_CRITICAL:()=>mo,buildHealthReport:()=>To,buildPipelineDiagnostic:()=>ho,checkChunkQueueGrowth:()=>vn,checkDaemonSiblings:()=>bo,checkDaemonStateFiles:()=>yo,checkDiskPressureAndBackups:()=>Eo,checkIngestStaleness:()=>Ro,checkSemanticGateDrift:()=>No,checkStaleClaudeJsonMcpPaths:()=>Ao,checkWatcherReflagLoop:()=>go,countBackupOrphans:()=>sp,detectLabelCollisions:()=>So,getFreeDiskBytes:()=>op,renderMigrationDoctorSection:()=>wo,runDoctor:()=>ip});import{existsSync as Ce,readdirSync as Wu,readFileSync as Dn,statSync as pt,statfsSync as uo}from"node:fs";import{homedir as Bu}from"node:os";import{join as mt}from"node:path";import*as po from"node:http";function zu(e){let t=[];for(let n of e)if(n.alias){if(Gu.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 go(e,t=mo){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:
847
- sqlite3 ~/.recall/db.sqlite "UPDATE sessions SET skipped_reason='reflag_loop_breaker' WHERE file_path = '${r}';"`)}return n}function Yu(){let e=mt(y,"daemon.port");if(!Ce(e))return null;try{let t=Dn(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 oo(e,t,n){return new Promise(s=>{let r=po.request({host:"127.0.0.1",port:e,path:t,method:"GET",timeout:n,headers:{host:"127.0.0.1","user-agent":"recall-doctor"}},i=>{let o=[];i.on("data",a=>o.push(Buffer.isBuffer(a)?a:Buffer.from(a))),i.on("end",()=>{if(!i.statusCode||i.statusCode<200||i.statusCode>=300){s({ok:!1,reason:"http"});return}try{s({ok:!0,json:JSON.parse(Buffer.concat(o).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 Ku(e){let t=await oo(e,"/api/health",ao);if(t.ok)return t.json;if(t.reason!=="timeout")return null;let n=await oo(e,"/api/health",ao);return n.ok?n.json:null}function Ju(){let e=mt(y,"terminals.json");if(!Ce(e))return{exists:!1,mtimeMs:null,ageSeconds:null};try{let t=pt(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 Vu(){let e=new Date(Date.now()-Mn*36e5).toISOString();try{let t=E().prepare(`SELECT
839
+ `)}}}async function kc(e,t={},n){let s=!!t.scanId,r=s?Ac(e):[],o=new Map(r.map(c=>[c.id,c.label])),i=r.length,a;return s&&t.scanId&&(a=Nc({scanId:t.scanId,total:i,labelTable:o})),Ys({prompt:Gs(e),allowedTools:Tc.split(","),opts:t,onProgress:n,onStdoutLine:a,outputFormat:s?"stream-json":"json"})}async function zs(e,t,n={},s){return Ys({prompt:e,allowedTools:t,opts:n,onProgress:s,outputFormat:"json"})}function Ys(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(c=>{let l=yc(),d=bc(l,a,{stdio:["ignore","pipe","pipe"],shell:Hs(l)||process.platform==="win32"&&Ee==="claude"}),p=[],u=[],g=o?Lc(o):void 0;d.stdout.on("data",E=>{p.push(E),g&&g(E)}),d.stderr.on("data",E=>{if(u.push(E),r){let S=E.toString("utf8").trim();S&&r(S)}});let h=setTimeout(()=>{d.kill("SIGKILL")},1800*1e3);d.on("close",E=>{clearTimeout(h),c({success:E===0,stdout:Buffer.concat(p).toString("utf8"),stderr:Buffer.concat(u).toString("utf8"),exitCode:E})}),d.on("error",E=>{clearTimeout(h),c({success:!1,stdout:"",stderr:String(E),exitCode:null})})})}var Tc,Ee,Ne,Gt=y(()=>{"use strict";yt();Nt();Us();Bs();Tc=["mcp__recall__list_tags","mcp__recall__list_sessions_to_tag","mcp__recall__apply_tags"].join(",")});import{existsSync as ll}from"node:fs";import{dirname as wr}from"node:path";import{fileURLToPath as dl}from"node:url";function be(){if(Ve)return Ve;let e=wr(dl(import.meta.url));for(;!ll(`${e}/package.json`);){let t=wr(e);if(t===e)throw new Error(`package.json not found walking up from ${import.meta.url}`);e=t}return Ve=e,Ve}var Ve,qe=y(()=>{"use strict";Ve=null});function Qe(e){let t=null;return()=>t||(t=(async()=>{try{return await e()}finally{t=null}})(),t)}var qt=y(()=>{"use strict"});function ul(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(`
840
+ `)}var Ze,J,Le=y(()=>{"use strict";Ze="BAAI/bge-base-en-v1.5",J=class extends Error{kind;path;underlying;cause;constructor(t){super(ul(t)),this.name="EmbedderUnavailableError",this.kind=t.kind,this.path=t.path,this.underlying=t.underlying,this.cause=t}}});var nt={};ye(nt,{embed:()=>bl,embedQuery:()=>Tl,getEmbedderStatus:()=>Sl,loadEmbedder:()=>El,unloadEmbedder:()=>yl});import{Worker as pl}from"node:worker_threads";import{join as ml}from"node:path";import{existsSync as gl}from"node:fs";function fl(){return ml(be(),"dist","daemon","embedder-worker.js")}function Rr(e){for(let t of ke.values())t.reject(e);ke.clear()}function _l(){if(re)return re;let e=fl();if(!gl(e))throw new J({kind:"bundle-missing",detail:"embedder-worker bundle not found - run `npm run build:cli` to emit it",path:e});let t=new pl(e);return t.on("message",n=>{let s=ke.get(n.id);s&&(ke.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));Rr(s),re=null,Z=!1}),t.on("exit",n=>{n!==0&&(console.error(`[embedder-worker] exited with code ${n}`),Rr(new Error(`embedder worker exited with code ${n}`))),re=null,Z=!1}),re=t,t}function et(e){return new Promise((t,n)=>{let s;try{s=_l()}catch(r){n(r instanceof Error?r:new Error(String(r)));return}ke.set(e.id,{resolve:t,reject:n}),s.postMessage(e)})}function tt(){return Qt=Qt+1>>>0,String(Qt)}function en(e){if(!e.ok)throw e.unavailable?new J({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 El(){if(!(Z&&re))try{await hl(),Z=!0}catch(e){throw Z=!1,e}}function Sl(){return{loaded:Z,modelId:Ze,dim:768}}async function bl(e){if(!Z)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");return en(await et({id:tt(),type:"embed",texts:e})).embeddings.map(n=>new Float32Array(n))}async function Tl(e){if(!Z)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");let t=en(await et({id:tt(),type:"embedQuery",text:e}));return new Float32Array(t.embedding)}async function yl(){if(!re){Z=!1;return}try{await et({id:tt(),type:"unload"})}catch{}Z=!1;let e=re;re=null;try{await e.terminate()}catch{}}var re,ke,Qt,Z,hl,Ar=y(()=>{"use strict";qe();qt();Le();re=null,ke=new Map,Qt=0,Z=!1;hl=Qe(async()=>{en(await et({id:tt(),type:"load"}))})});var sn={};ye(sn,{LLAMACPP_MODEL_ID:()=>Lr,MODEL_ID:()=>Ze,embed:()=>Il,embedQuery:()=>vl,getEmbedderStatus:()=>Ol,loadEmbedder:()=>xl,unloadEmbedder:()=>Cl});import{Worker as wl}from"node:worker_threads";import{join as Rl}from"node:path";import{existsSync as Al}from"node:fs";function Nl(){return Rl(be(),"dist","daemon","embedder-worker-llamacpp.js")}function Nr(e){for(let t of xe.values())t.reject(e);xe.clear()}function Ll(){if(oe)return oe;let e=Nl();if(!Al(e))throw new J({kind:"bundle-missing",detail:"embedder-worker-llamacpp bundle not found - run `npm run build:cli` to emit it",path:e});let t=new wl(e);return t.on("message",n=>{let s=xe.get(n.id);s&&(xe.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));Nr(s),oe=null,ee=!1}),t.on("exit",n=>{n!==0&&(console.error(`[embedder-worker-llamacpp] exited with code ${n}`),Nr(new Error(`embedder worker exited with code ${n}`))),oe=null,ee=!1}),oe=t,t}function st(e){return new Promise((t,n)=>{let s;try{s=Ll()}catch(r){n(r instanceof Error?r:new Error(String(r)));return}xe.set(e.id,{resolve:t,reject:n}),s.postMessage(e)})}function rt(){return tn=tn+1>>>0,String(tn)}function nn(e){if(!e.ok)throw e.unavailable?new J({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 xl(){if(!(ee&&oe))try{await kl(),ee=!0}catch(e){throw ee=!1,e}}function Ol(){return{loaded:ee,modelId:Lr,dim:768}}async function Il(e){if(!ee)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");return nn(await st({id:rt(),type:"embed",texts:e})).embeddings.map(n=>new Float32Array(n))}async function vl(e){if(!ee)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");let t=nn(await st({id:rt(),type:"embedQuery",text:e}));return new Float32Array(t.embedding)}async function Cl(){if(!oe){ee=!1;return}try{await st({id:rt(),type:"unload"})}catch{}ee=!1;let e=oe;oe=null;try{await e.terminate()}catch{}}var Lr,oe,xe,tn,ee,kl,kr=y(()=>{"use strict";qe();qt();Le();Le();Lr="BAAI/bge-base-en-v1.5-gguf-q8_0";oe=null,xe=new Map,tn=0,ee=!1;kl=Qe(async()=>{nn(await st({id:rt(),type:"load"}))})});function Dl(){let e=(process.env.RECALL_EMBEDDER_BACKEND??"").trim().toLowerCase();return e==="llama"||e==="llamacpp"?sn:(e===""||e==="onnx"||process.stderr.write(`[embedder] RECALL_EMBEDDER_BACKEND="${e}" is not recognized; falling back to onnx. Valid values: onnx, llama.
841
+ `),nt)}var Oe,rn,Ie,Ml,Rf,Af,on=y(()=>{"use strict";Ar();kr();Le();Oe=Dl(),rn=Oe.loadEmbedder,Ie=Oe.getEmbedderStatus,Ml=Oe.embed,Rf=Oe.embedQuery,Af=Oe.unloadEmbedder});var vr=y(()=>{"use strict";x()});var Cr=y(()=>{"use strict";x()});function Dr(){try{return!!_().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 Vl(){return _().prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}function Mr(){return{running:Yl,queueDepth:Vl(),lastProcessedAt:Kl,blacklistedCount:Jl.size,pausedForMigration:Dr()}}var Yl,Kl,Jl,un=y(()=>{"use strict";x();on();vr();Cr();Yl=!1,Kl=null,Jl=new Set});import te from"chalk";import{formatDistanceToNowStrict as oh,parseISO as ih}from"date-fns";var f,hn=y(()=>{"use strict";f={dim:te.gray,bold:te.bold,project:te.cyan,user:te.blue,assistant:te.green,tool:te.magenta,warn:te.yellow,err:te.red,ok:te.green,accent:te.hex("#f97316")}});var no=y(()=>{"use strict"});var so=y(()=>{"use strict"});var ro=y(()=>{"use strict"});var oo=y(()=>{"use strict"});import{existsSync as $d,readFileSync as Ud,writeFileSync as jd}from"node:fs";import{join as Hd}from"node:path";import{z as W}from"zod";function bn(e){let t=e.trim();return!!(!t||ao.test(t)||co.test(t))}function lo(e){let t=e.trim();if(!t||co.test(t))return null;let n=t.replace(ao,"").trim();return n.length>0?n:null}function Sn(e,t){if(!bn(e))return e;let n=lo(e);return n||(t&&!bn(t)?t:e)}function zd(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 En,io,Bd,Wd,Xd,Gd,ao,co,Tn,Yd,uo=y(()=>{"use strict";v();En=Hd(A,"terminals.json"),io=1440*60*1e3,Bd=3e4,Wd=6e4,Xd=W.object({shell_pid:W.number(),tab_name:W.string(),cwd:W.string().nullable().optional(),opened_at:W.string(),last_seen_at:W.string()}),Gd=W.object({schema:W.string().optional(),saved_at:W.string().optional(),terminals:W.array(Xd).max(500).default([]),sessions_by_pid:W.record(W.string(),W.array(W.string()).max(50)).optional().default({})}),ao=/^[⠀-⣿✳\s]+/,co=/^\d+(\.\d+){1,3}$/;Tn=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,!!$d(En)))try{let t=Ud(En,"utf8"),n=JSON.parse(t),s=Gd.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 c=new Set;for(let l of i)l.length>0&&c.add(l);c.size>0&&this.sessionsByPid.set(a,c)}this.gc()}catch{}}save(){try{I();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)]))};jd(En,JSON.stringify(t,null,2))}catch{}}upsert(t){this.ensureLoaded();let n=new Date().toISOString(),s=this.entries.get(t.shell_pid),r=Sn(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=Sn(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>Wd?(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=Sn(o.tab_name,i?.tab_name),c=i?.opened_at??o.opened_at;this.entries.set(o.shell_pid,{...o,tab_name:a,opened_at:c,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=zd({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()-Bd;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()-io;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()-io;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 c=this.entries.get(i);if(c){let l=Date.parse(c.last_seen_at);if(Number.isFinite(l)&&l>=s)continue}o+=a.size,this.sessionsByPid.delete(i),c&&(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}}},Yd=new Tn});import{execFile as Kd}from"node:child_process";import{promisify as Jd}from"node:util";var Sh,po=y(()=>{"use strict";Sh=Jd(Kd)});import{execFile as qd}from"node:child_process";import{promisify as Qd}from"node:util";var kh,xh,mo=y(()=>{"use strict";uo();Be();x();po();kh=Qd(qd),xh=3600*1e3});var Ih,go=y(()=>{"use strict";Ih=64*1024});import{existsSync as Zd,mkdirSync as Dh,readFileSync as eu,writeFileSync as Mh}from"node:fs";import{homedir as tu}from"node:os";import{join as fo}from"node:path";import{z as ne}from"zod";function nu(){return process.env.RECALL_HOME??fo(tu(),".recall")}function su(){return fo(nu(),"config.json")}function ou(){let e=su();if(!Zd(e))return{};try{return JSON.parse(eu(e,"utf8"))}catch(t){return console.error("[semantic-config] failed to parse config.json, using defaults:",t),{}}}function wn(){let e=ou().semantic;if(!e)return{...yn};let t=ru.safeParse({...yn,...e});return t.success?t.data:{...yn}}var ru,yn,Rn=y(()=>{"use strict";Et();x();v();ru=ne.object({enabled:ne.boolean().default(!1),model:ne.string().optional(),ratePerMinute:ne.number().int().min(1).max(600).default(30),lastProcessedSessionId:ne.string().nullable().default(null),backfillPaused:ne.boolean().default(!1),autoExtractEnabled:ne.boolean().default(!1),autoExtractIntervalMinutes:ne.number().int().min(5).max(720).default(60),autoExtractBatchSize:ne.number().int().min(1).max(20).default(1),autoResumeWorker:ne.boolean().default(!1)}),yn={enabled:!1,ratePerMinute:30,lastProcessedSessionId:null,backfillPaused:!1,autoExtractEnabled:!1,autoExtractIntervalMinutes:60,autoExtractBatchSize:1,autoResumeWorker:!1}});var _o=y(()=>{"use strict";x();Gt();Rn()});var ho=y(()=>{"use strict"});import{execFile as iu}from"node:child_process";import{promisify as au}from"node:util";var Qh,Eo=y(()=>{"use strict";x();Qh=au(iu)});import{z as An}from"zod";var tE,So=y(()=>{"use strict";tE=An.object({heuristicEnabled:An.boolean().default(!0),agentEnabled:An.boolean().default(!1)})});import{basename as oE,join as Nn}from"node:path";var bo,lE,dE,To=y(()=>{"use strict";x();v();Ct();bo=Nn(A,"auto-rules"),lE=Nn(bo,"rules.json"),dE=Nn(bo,"suggestions.json")});var yo=y(()=>{"use strict"});var wo=y(()=>{"use strict"});var Ro=y(()=>{"use strict"});var Ao=y(()=>{"use strict";Ro()});var No=y(()=>{"use strict"});var Lo=y(()=>{"use strict"});function ko(e){return e.replace(/\\/g,"/").includes("/subagents/")}function xo(e){let t=e.split(/[/\\]/),n=t.findIndex(s=>s==="projects");return n===-1||n+1>=t.length?null:t[n+1]??null}var Oo=y(()=>{"use strict"});import{watch as zE}from"chokidar";import{readdirSync as lu,statSync as KE}from"node:fs";import{basename as sS,join as du}from"node:path";function*Ln(e){let t;try{t=lu(e,{withFileTypes:!0,encoding:"utf8"})}catch{return}for(let n of t){if(n.isSymbolicLink())continue;let s=du(e,n.name);n.isDirectory()?yield*Ln(s):n.isFile()&&n.name.endsWith(".jsonl")&&(yield s)}}var Io,vo,Co=y(()=>{"use strict";v();x();no();so();ro();oo();mo();go();_o();ho();Eo();Xt();So();To();jt();yo();Be();wo();Ao();un();No();Lo();Oo();Io=xo,vo=ko});import{execFileSync as Fo}from"node:child_process";function pu(e){for(let t of uu)if(e.includes(t))return!0;return!1}function ve(e={}){let t=e.psOutput??mu(),n=e.isProcessAlive??gu,s=e.getParentCommand??fu,r=[];for(let o of t.split(`
842
+ `)){let i=o.trim();if(!i||!pu(i)||_u(i))continue;let a=i.split(/\s+/);if(a.length<5)continue;let c=Number(a[0]),l=Number(a[1]),d=a[2],p=a[3],u=a[4],g=0,h=0;if(/^\d+$/.test(p)&&(u.includes(".")||/^\d+$/.test(u))?(g=Number(p),h=Number(u)):h=Number(p),!Number.isFinite(c)||!Number.isFinite(l))continue;let S=l>1&&n(l);r.push({pid:c,ppid:l,parentAlive:S,etimeSeconds:hu(d),pcpu:Number.isFinite(h)?h:0,rssKb:Number.isFinite(g)?g:0,orphan:!S,parentCommand:S?s(l):null})}return r}function mu(){try{return Fo("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}
843
+ `),""}}function gu(e){if(!Number.isFinite(e)||e<=1)return!1;try{return process.kill(e,0),!0}catch{return!1}}function fu(e){if(!Number.isFinite(e)||e<=1)return null;try{let n=Fo("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 _u(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 hu(e){if(!e)return 0;let t=0,n=e,s=e.indexOf("-");s>=0&&(t=Do(e.slice(0,s)),n=e.slice(s+1));let r=n.split(":").map(Do),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 Do(e){let t=Number(e);return Number.isFinite(t)?t:0}function lt(e){return e.pcpu>=Eu&&e.etimeSeconds>=Su}function Po(e){return e.reduce((t,n)=>t+(Number.isFinite(n.rssKb)&&n.rssKb>0?n.rssKb:0),0)}function $o(e){let t=e??ve(),n=t.length,s=Po(t),r=t.filter(u=>u.orphan),o=r.length,i=Po(r),a=o>Mo,c=i>bu;if(!(a||c))return{flagged:!1,severity:"ok",count:n,aggregateRssKb:s,orphanCount:o,orphanRssKb:i,message:null};let d=[];a&&d.push(`${o} orphaned MCP children (threshold ${Mo})`),c&&d.push(`${Tu(i)} aggregate RSS across orphaned children (threshold 1 GiB)`);let p=`Zombie MCP threshold breached: ${d.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:p}}function Tu(e){return e<1024?`${e} KB`:e<1024*1024?`${(e/1024).toFixed(1)} MB`:`${(e/(1024*1024)).toFixed(2)} GB`}var uu,Eu,Su,Mo,bu,dt=y(()=>{"use strict";uu=["dist/mcp-server.js","dist/mcp/server.js"];Eu=50,Su=60;Mo=4,bu=1024*1024});import{execFileSync as Uo}from"node:child_process";function wu(e){let t=e.replace(/\\/g,"/");for(let n of yu)if(t.includes(n))return!0;return!1}function Ru(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 ut(e={}){let t=e.psOutput??Au(),n=new Set(e.excludePids??[]),s=[];for(let r of t.split(`
844
+ `)){let o=r.trim();if(!o||!wu(o))continue;let i=o.split(/\s+/);if(Ru(i)||i.length<5)continue;let a=Number(i[0]),c=Number(i[1]),l=i[2];!Number.isFinite(a)||!Number.isFinite(c)||n.has(a)||s.push({pid:a,ppid:c,etimeSeconds:Nu(l),etime:l,command:o})}return s.sort((r,o)=>r.etimeSeconds-o.etimeSeconds),s}function Au(){if(process.platform==="win32")try{return Uo("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}
845
+ `),""}try{return Uo("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}
846
+ `),""}}function Nu(e){if(!e)return 0;let t=0,n=e,s=e.indexOf("-");s>=0&&(t=jo(e.slice(0,s)),n=e.slice(s+1));let r=n.split(":").map(jo),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 jo(e){let t=Number(e);return Number.isFinite(t)?t:0}function kn(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 yu,xn=y(()=>{"use strict";yu=["dist/daemon/entrypoint.js"]});import{join as Lu}from"node:path";var kS,On=y(()=>{"use strict";v();kS=Lu(A,"daemon.log")});import{join as xu}from"node:path";var Ho,Bo=y(()=>{"use strict";v();On();Ho=xu(A,"daemon.token")});import{basename as MS,join as In}from"node:path";function Wo(){return{pid:Ou,port:Iu,token:Ho}}function Xo(e){return vu(e)}function vu(e){try{return process.kill(e,0),!0}catch{return!1}}var Ou,Iu,jS,Go=y(()=>{"use strict";v();Bo();xn();On();Ou=In(A,"daemon.pid"),Iu=In(A,"daemon.port"),jS=In(A,"daemon.log")});var XS,zo,Yo=y(()=>{"use strict";we();dt();XS=5*6e4,zo=1073741824});import{existsSync as Cu,readFileSync as Du,renameSync as Ko,writeFileSync as Mu}from"node:fs";import{join as Pu}from"node:path";function Jo(){return Pu(A,"doctor-state.json")}function Vo(){let e=Jo();if(!Cu(e))return{chunkQueue:{samples:[]}};let t;try{t=Du(e,"utf8")}catch{return{chunkQueue:{samples:[]}}}try{let n=JSON.parse(t),s=n.chunkQueue?.samples,r=Array.isArray(s)?s.filter(c=>typeof c=="object"&&c!==null&&typeof c.ts=="string"&&typeof c.size=="number"&&typeof c.semanticEnabled=="boolean"):[],o=n.autoPruneCounters?.events,i=Array.isArray(o)?o.filter(c=>{if(!c||typeof c!="object")return!1;let l=c;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{Ko(e,`${e}.corrupt.${Date.now()}`)}catch{}return{chunkQueue:{samples:[]}}}}function qo(e){let t=Jo(),n=`${t}.tmp`;try{Mu(n,JSON.stringify(e,null,2),{mode:384}),Ko(n,t)}catch{}}function vn(){let 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=Vo(),r=Date.now(),o=s.chunkQueue.samples,i=o.map(h=>({s:h,ms:Date.parse(h.ts)})).filter(h=>Number.isFinite(h.ms)&&r-h.ms<=$u).sort((h,E)=>h.ms-E.ms),a=null;i.length>0&&(a=t-i[0].s.size);let c=i.length,d={chunkQueue:{samples:[...o,{ts:new Date(r).toISOString(),size:t,semanticEnabled:n}].slice(-Fu)}};s.autoPruneCounters&&(d.autoPruneCounters=s.autoPruneCounters),qo(d);let p="ok",u=`chunk_queue growth: ok (current ${t.toLocaleString()} row${t===1?"":"s"}, semantic ${n?"on":"off"}, ${c} prior sample${c===1?"":"s"} in last hour).`,g=null;return t>Uu&&!n&&a!==null&&a>ju?(p="critical",u=`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>Hu?(p="high",u=`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>Bu&&(p="medium",u=`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:p,currentSize:t,semanticEnabled:n,lastHourGrowth:a,priorSampleCount:c,message:u,remediation:g}}function Qo(e={}){let t=e.now??Date.now(),n=Vo(),s=n.autoPruneCounters?.events??[],r=s.filter(l=>{let d=Date.parse(l.ts);return Number.isFinite(d)&&t-d<=Wu});if(r.length!==s.length)try{let l={chunkQueue:n.chunkQueue,autoPruneCounters:{events:r}};qo(l)}catch{}let o={orphan_10min:0,runaway_cpu_5min:0},i=0,a=0,c=0;for(let l of r)o[l.reason]+=1,l.action==="would_kill"?i+=1:l.action==="killed"?a+=1:c+=1;return{wouldHaveKilled:i,killed:a,failed:c,byReason:o}}var Fu,$u,Uu,ju,Hu,Bu,Wu,Cn=y(()=>{"use strict";v();x();Fu=24,$u=3600*1e3,Uu=1e3,ju=1e3,Hu=1e4,Bu=5e3,Wu=1440*60*1e3});function ei(e=process.env){let t=e.RECALL_AUTO_PRUNE;if(typeof t!="string")return Zo;let n=t.trim().toLowerCase();return n==="off"||n==="dry-run"||n==="enabled"?n:Zo}var Zo,ti=y(()=>{"use strict";dt();Cn();Zo="dry-run"});import{existsSync as Xu,readFileSync as Gu,renameSync as si,writeFileSync as zu}from"node:fs";import{join as Yu}from"node:path";function ri(){return Yu(A,"doctor-alerts.json")}function oi(){let e=ri();if(!Xu(e))return{version:1,lastTickAt:new Date(0).toISOString(),alerts:[]};let t;try{t=Gu(e,"utf8")}catch{return{version:1,lastTickAt:new Date(0).toISOString(),alerts:[]}}let n;try{n=JSON.parse(t)}catch{return ni(e),{version:1,lastTickAt:new Date(0).toISOString(),alerts:[]}}if(!n||typeof n!="object"||Array.isArray(n))return ni(e),{version:1,lastTickAt:new Date(0).toISOString(),alerts:[]};let s=n,r=Array.isArray(s.alerts)?s.alerts.filter(Ku):[];return{version:1,lastTickAt:typeof s.lastTickAt=="string"?s.lastTickAt:new Date(0).toISOString(),alerts:r}}function ni(e){try{si(e,`${e}.corrupt.${Date.now()}`)}catch{}}function Ku(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 ii(e){let t=ri(),n=`${t}.tmp`;try{zu(n,JSON.stringify(e,null,2),{mode:384}),si(n,t)}catch{}}function ai(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}}}var ci=y(()=>{"use strict";v()});function qu(e){let t=e.toLowerCase();return Vu.some(n=>t.includes(n))}function Qu(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 Zu(e){let t=[];for(let n of e){let s=Ju.exec(n);if(!s)continue;let r=s[1],o=s[2];qu(r)&&Qu(o)&&t.push(n)}return t}function li(e){let t=e.listTableNames(),n=[];for(let o of Zu(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(Dn)){let o=e.isRollbackWindowOpen(),i=e.rollbackDaysRemaining();n.push({name:Dn,rows:e.countRows(Dn),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 di(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(`
847
+ `)}var Ju,Vu,Dn,ui=y(()=>{"use strict";Ju=/^(.+?)[_-](\d{8})$/,Vu=["_deferred","_backup"];Dn="vec_chunks_v1_backup"});var Di={};ye(Di,{WATCHER_REFLAG_CRITICAL:()=>Ei,buildHealthReport:()=>Ai,buildInDbBloatReport:()=>xi,buildPipelineDiagnostic:()=>yi,checkChunkQueueGrowth:()=>vn,checkDaemonSiblings:()=>Ni,checkDaemonStateFiles:()=>Li,checkDiskPressureAndBackups:()=>wi,checkIngestStaleness:()=>Ii,checkSemanticGateDrift:()=>Ci,checkStaleClaudeJsonMcpPaths:()=>vi,checkWatcherReflagLoop:()=>Si,countBackupOrphans:()=>fp,detectLabelCollisions:()=>Ri,getFreeDiskBytes:()=>Ep,renderInDbBloatDoctorSection:()=>Oi,renderMigrationDoctorSection:()=>ki,runDoctor:()=>hp});import{existsSync as Ce,readdirSync as ep,readFileSync as Mn,statSync as pt,statfsSync as _i}from"node:fs";import{homedir as tp}from"node:os";import{join as mt}from"node:path";import*as hi from"node:http";function rp(e){let t=[];for(let n of e)if(n.alias){if(sp.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 Si(e,t=Ei){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
848
+ using the resolved DB path below \u2014 this honors $RECALL_HOME and avoids
849
+ the non-expanding \`~\` that breaks in Windows cmd/PowerShell (requires
850
+ the sqlite3 CLI):
851
+ sqlite3 "${pe}" "UPDATE sessions SET skipped_reason='reflag_loop_breaker' WHERE file_path = '${r}';"`)}return n}function op(){let e=mt(A,"daemon.port");if(!Ce(e))return null;try{let t=Mn(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 pi(e,t,n){return new Promise(s=>{let r=hi.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 ip(e){let t=await pi(e,"/api/health",mi);if(t.ok)return t.json;if(t.reason!=="timeout")return null;let n=await pi(e,"/api/health",mi);return n.ok?n.json:null}function ap(){let e=mt(A,"terminals.json");if(!Ce(e))return{exists:!1,mtimeMs:null,ageSeconds:null};try{let t=pt(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 cp(){let e=new Date(Date.now()-Pn*36e5).toISOString();try{let t=_().prepare(`SELECT
848
852
  COUNT(*) AS total,
849
853
  SUM(CASE WHEN sa.alias IS NULL OR sa.alias = '' THEN 1 ELSE 0 END) AS without_alias,
850
854
  SUM(CASE WHEN (sa.alias IS NULL OR sa.alias = '')
@@ -856,7 +860,7 @@ ${m+1}. ${p}`:`${m+1}. ${p}`}).join(`
856
860
  AND COALESCE(s.cwd, '') NOT LIKE '/private/tmp/%'
857
861
  AND COALESCE(s.cwd, '') NOT LIKE '/var/folders/%'
858
862
  AND COALESCE(s.cwd, '') NOT LIKE '/private/var/folders/%'
859
- 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,i=n>0?r/n:0;return{total:n,withoutAlias:s,heuristicOnly:r,fractionHeuristic:i}}catch{return{total:0,withoutAlias:0,heuristicOnly:0,fractionHeuristic:0}}}async function ho(){let e=Yu(),t=Ju(),n=Vu(),s=!1,r=null,i=null,o=null,a=null,c=null,l=[];if(e){let p=await Ku(e);if(p){s=!0,r=typeof p.uptimeSeconds=="number"?p.uptimeSeconds:null,i=typeof p.version=="string"?p.version:null,o=typeof p.pipeline?.silentTerminalRejections=="number"?p.pipeline.silentTerminalRejections:null,a=p.pipeline?.lastTerminalSyncAt??null;let g=p.pipeline?.autoExtract;g&&(c={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 h=p.pipeline?.watcherReindexHotFiles;Array.isArray(h)&&(l=h.filter(S=>typeof S?.path=="string"&&typeof S?.count=="number"&&typeof S?.firstSeenAt=="number").map(S=>({path:S.path,count:S.count,firstSeenAt:S.firstSeenAt,noProgressCount:typeof S.noProgressCount=="number"?S.noProgressCount:S.count})))}}let d=[];if(s||d.push("Daemon not reachable on 127.0.0.1 \u2014 start it with `recall start` before further diagnosis."),o!==null&&o>0&&d.push(`Daemon rejected ${o.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)d.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>fo&&d.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&&d.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.`),c?.circuitBroken&&d.push(`Auto-extract circuit breaker tripped \u2014 ${c.reason??"reason unknown"}. Run \`recall semantic auto-extract off\` then \`... on\` to reset, or restart the daemon.`),n.total>=3&&n.fractionHeuristic>=_o&&d.push(`${n.heuristicOnly}/${n.total} sessions in the last ${Mn}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 go(l))d.push(p);return{state:s?d.length>0?"degraded":"ok":"down",flags:d,daemon:{running:s,port:e,uptimeSeconds:r,version:i},runtime:{silentTerminalRejections:o,lastTerminalSyncAt:a,autoExtract:c},terminalsJson:t,recentSessions:n,watcherReindexHotFiles:l}}function j(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 co(e){try{return pt(e).size}catch{return 0}}function qu(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 Eo(e=y){let t=0,n=0;try{let g=uo(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=Wu(e)}catch{r=[]}let i=0,o=0,a=[],c=Date.now(),l=720*60*60*1e3;for(let g of r){if(!qu(g))continue;let h;try{h=pt(mt(e,g))}catch{continue}if(!h.isFile())continue;o+=1,i+=h.size;let S=Math.max(0,c-h.mtimeMs),u=Math.floor(S/(1440*60*1e3));S>=l&&a.push({name:g,sizeBytes:h.size,ageDays:u})}a.sort((g,h)=>h.sizeBytes!==g.sizeBytes?h.sizeBytes-g.sizeBytes:h.ageDays-g.ageDays);let d=2*1024**3,m=5*1024**3,p="ok";return n>0&&s<10||i>m?p="high":n>0&&s<20||i>d?p="medium":o>0&&(p="low"),{freeBytes:t,totalBytes:n,freePercent:s,backupTotalBytes:i,backupFileCount:o,oldFiles:a,severity:p}}function lo(e){try{return E().prepare(`SELECT COUNT(*) AS n FROM ${e}_data WHERE block = 1`).get().n}catch{return 0}}function So(){try{return E().prepare(`SELECT p.name AS project,
863
+ 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 yi(){let e=op(),t=ap(),n=cp(),s=!1,r=null,o=null,i=null,a=null,c=null,l=[];if(e){let u=await ip(e);if(u){s=!0,r=typeof u.uptimeSeconds=="number"?u.uptimeSeconds:null,o=typeof u.version=="string"?u.version:null,i=typeof u.pipeline?.silentTerminalRejections=="number"?u.pipeline.silentTerminalRejections:null,a=u.pipeline?.lastTerminalSyncAt??null;let g=u.pipeline?.autoExtract;g&&(c={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 h=u.pipeline?.watcherReindexHotFiles;Array.isArray(h)&&(l=h.filter(E=>typeof E?.path=="string"&&typeof E?.count=="number"&&typeof E?.firstSeenAt=="number").map(E=>({path:E.path,count:E.count,firstSeenAt:E.firstSeenAt,noProgressCount:typeof E.noProgressCount=="number"?E.noProgressCount:E.count})))}}let d=[];if(s||d.push("Daemon not reachable on 127.0.0.1 \u2014 start it with `recall start` before further diagnosis."),i!==null&&i>0&&d.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)d.push(`Daemon has been running ${Math.round(r/60)} min but has not yet seen a single successful /api/terminal/sync. Either no editor extension is installed/active, or every attempt is being rejected (see counter above).`);else{let u=Date.now()-Date.parse(a);Number.isFinite(u)&&u>bi&&d.push(`Last successful /api/terminal/sync was ${Math.round(u/6e4)} min ago \u2014 extension may have crashed, been disabled, or is failing auth. Run \`recall doctor\` again after restarting the extension host.`)}!s&&t.exists&&t.ageSeconds!==null&&t.ageSeconds>24*3600&&d.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.`),c?.circuitBroken&&d.push(`Auto-extract circuit breaker tripped \u2014 ${c.reason??"reason unknown"}. Run \`recall semantic auto-extract off\` then \`... on\` to reset, or restart the daemon.`),n.total>=3&&n.fractionHeuristic>=Ti&&d.push(`${n.heuristicOnly}/${n.total} sessions in the last ${Pn}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 u of Si(l))d.push(u);return{state:s?d.length>0?"degraded":"ok":"down",flags:d,daemon:{running:s,port:e,uptimeSeconds:r,version:o},runtime:{silentTerminalRejections:i,lastTerminalSyncAt:a,autoExtract:c},terminalsJson:t,recentSessions:n,watcherReindexHotFiles:l}}function B(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 gi(e){try{return pt(e).size}catch{return 0}}function lp(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 wi(e=A){let t=0,n=0;try{let g=_i(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=ep(e)}catch{r=[]}let o=0,i=0,a=[],c=Date.now(),l=720*60*60*1e3;for(let g of r){if(!lp(g))continue;let h;try{h=pt(mt(e,g))}catch{continue}if(!h.isFile())continue;i+=1,o+=h.size;let E=Math.max(0,c-h.mtimeMs),S=Math.floor(E/(1440*60*1e3));E>=l&&a.push({name:g,sizeBytes:h.size,ageDays:S})}a.sort((g,h)=>h.sizeBytes!==g.sizeBytes?h.sizeBytes-g.sizeBytes:h.ageDays-g.ageDays);let d=2*1024**3,p=5*1024**3,u="ok";return n>0&&s<10||o>p?u="high":n>0&&s<20||o>d?u="medium":i>0&&(u="low"),{freeBytes:t,totalBytes:n,freePercent:s,backupTotalBytes:o,backupFileCount:i,oldFiles:a,severity:u}}function fi(e){try{return _().prepare(`SELECT COUNT(*) AS n FROM ${e}_data WHERE block = 1`).get().n}catch{return 0}}function Ri(){try{return _().prepare(`SELECT p.name AS project,
860
864
  COALESCE(NULLIF(sa.alias, ''), s.auto_title, substr(s.first_user_message, 1, 60)) AS label,
861
865
  COUNT(*) AS count,
862
866
  MAX(CASE WHEN sa.alias IS NOT NULL AND sa.alias != '' THEN 1 ELSE 0 END) AS any_aliased
@@ -875,46 +879,47 @@ ${m+1}. ${p}`:`${m+1}. ${p}`}).join(`
875
879
  GROUP BY p.name, label
876
880
  HAVING count >= 2
877
881
  ORDER BY count DESC, label ASC
878
- 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 To(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 i="ok";try{let H=t.pragma("quick_check").map(J=>J.quick_check);i=H.length===1&&H[0]==="ok"?"ok":H.join("; ")}catch(A){i=`check failed: ${A.message}`}let o=co(fe),a=co(`${fe}-wal`),c=Eo(),l=c.freeBytes,d=c.totalBytes;e?.("Counting rows");let m=t.prepare(`SELECT
882
+ 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 Ai(e){let t=_(),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 M=t.pragma("quick_check").map(X=>X.quick_check);o=M.length===1&&M[0]==="ok"?"ok":M.join("; ")}catch(R){o=`check failed: ${R.message}`}let i=gi(pe),a=gi(`${pe}-wal`),c=wi(),l=c.freeBytes,d=c.totalBytes;e?.("Counting rows");let p=t.prepare(`SELECT
879
883
  (SELECT COUNT(*) FROM projects) AS projects,
880
884
  (SELECT COUNT(*) FROM sessions) AS sessions,
881
885
  (SELECT COUNT(*) FROM messages) AS messages,
882
- (SELECT COUNT(*) FROM message_usage) AS message_usage`).get(),p=0;try{oe(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 ${j(l)} \u2014 heavy operations (synthesis, extract-outputs, vector ingest) may fail.`),c.severity==="high"||c.severity==="medium"){let A=c.severity==="high"?"HIGH":"MEDIUM",H=[];d>0&&H.push(`disk: ${j(l)} free of ${j(d)} (${c.freePercent.toFixed(1)}%)`),c.backupFileCount>0&&H.push(`backups: ${j(c.backupTotalBytes)} in ${c.backupFileCount} file${c.backupFileCount===1?"":"s"}`);let J=`[${A}] disk pressure \u2014 ${H.join(" \xB7 ")}`;if(c.oldFiles.length>0){let ie=c.oldFiles.map(ue=>` \u2022 ${ue.name} ${j(ue.sizeBytes)} (${ue.ageDays} days old)`);J+=`
886
+ (SELECT COUNT(*) FROM message_usage) AS message_usage`).get(),u=0;try{ie(t),u=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 ${B(l)} \u2014 heavy operations (synthesis, extract-outputs, vector ingest) may fail.`),c.severity==="high"||c.severity==="medium"){let R=c.severity==="high"?"HIGH":"MEDIUM",M=[];d>0&&M.push(`disk: ${B(l)} free of ${B(d)} (${c.freePercent.toFixed(1)}%)`),c.backupFileCount>0&&M.push(`backups: ${B(c.backupTotalBytes)} in ${c.backupFileCount} file${c.backupFileCount===1?"":"s"}`);let X=`[${R}] disk pressure \u2014 ${M.join(" \xB7 ")}`;if(c.oldFiles.length>0){let F=c.oldFiles.map(ue=>` \u2022 ${ue.name} ${B(ue.sizeBytes)} (${ue.ageDays} days old)`);X+=`
883
887
  Snapshots older than 30 days:
884
- `+ie.join(`
885
- `)+"\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 c.backupFileCount>0&&(J+=`
886
- 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(J)}let h=100*1024**2,S=a>=Bi?"error":a>=h?"warn":"ok";S==="error"?g.push(`WAL is ${j(a)} \u2014 readers are pinning the checkpoint frontier. Run \`recall mcp-prune\` to release stuck MCP children, then \`recall optimize\` to truncate.`):S==="warn"&&g.push(`WAL is ${j(a)} \u2014 run \`recall optimize\` to truncate it.`);let u=ve(),f=u.filter(A=>A.orphan);f.length>0&&g.push(`${f.length} orphaned MCP child${f.length===1?"":"ren"} (pid${f.length===1?"":"s"}: ${f.map(A=>A.pid).join(", ")}). Each holds a SQLite read connection. Run \`recall mcp-prune\` to clean up.`);let T=u.filter(lt);T.length>0&&g.push(`${T.length} MCP child${T.length===1?"":"ren"} burning CPU (pid${T.length===1?"":"s"}: ${T.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 R=lo("messages_fts"),k=lo("sessions_fts");R>16&&g.push(`messages_fts has ${R} segments \u2014 \`recall optimize\` will merge them.`);let w=0;try{w=t.prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}catch{}let L=!1;try{L=t.prepare("SELECT value FROM app_settings WHERE key = 'semantic_enabled'").get()?.value==="1"}catch{}return!L&&w>0?g.push(`${w.toLocaleString()} rows in chunk_queue with semantic disabled \u2014 schema gate is stale; restart daemon (v0.67+) to migrate.`):w>1e5&&g.push(`chunk_queue has ${w.toLocaleString()} pending rows \u2014 embedder is behind. \`recall semantic backfill\` to drain manually.`),{db:{sizeBytes:o,walSizeBytes:a,pageCount:s,pageSize:n,freelistCount:r,freelistBytes:r*n,integrity:i},disk:{freeBytes:l,totalBytes:d,backups:{totalBytes:c.backupTotalBytes,fileCount:c.backupFileCount,oldFiles:c.oldFiles,severity:c.severity}},fts:{messages:{fragments:R},sessions:{fragments:k}},vectors:{rows:p},rows:{projects:m.projects,sessions:m.sessions,messages:m.messages,messageUsage:m.message_usage},chunkQueue:{size:w,semanticEnabled:L},wal:{sizeBytes:a,level:S},mcpProcesses:u,warnings:g}}function Qu(e){if(!e)return{stage:()=>{},done:()=>{}};let t=!!process.stderr.isTTY,n="",s=0,r=()=>{if(!n)return;let i=Date.now()-s,o=i<1e3?`${i}ms`:`${(i/1e3).toFixed(1)}s`;t?process.stderr.write(`\r\x1B[2K ${_.ok("\u2713")} ${n} ${_.dim(`(${o})`)}
887
- `):process.stderr.write(` \u2713 ${n} (${o})
888
- `),n=""};return{stage(i){r(),n=i,s=Date.now(),t?process.stderr.write(` ${_.dim("\u2026")} ${n}`):process.stderr.write(` \u2026 ${n}
889
- `)},done:r}}function bo(e){let t=e??ut(),n=t.length;if(n<=1)return{flagged:!1,severity:"ok",count:n,processes:t,message:null};let s=t.map(i=>{let o=kn(i.etimeSeconds)??i.etime;return`pid=${i.pid} started=${o} age=${_e(i.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 yo(e={}){if((e.liveDaemons??ut({excludePids:[process.pid]})).length===0)return{flagged:!1,severity:"ok",daemonAlive:!1,missing:[],message:null,remediation:null};let n=e.paths??ji(),s=e.existsSync??Ce,r=e.isProcessAlive??Hi,i=!1;if(s(n.pid))try{let c=JSON.parse(Dn(n.pid,"utf8"));typeof c.pid=="number"&&r(c.pid)&&(i=!0)}catch{}if(!i)return{flagged:!1,severity:"ok",daemonAlive:!0,missing:[],message:null,remediation:null};let o=[];return s(n.port)||o.push("daemon.port"),s(n.token)||o.push("daemon.token"),o.length===0?{flagged:!1,severity:"ok",daemonAlive:!0,missing:[],message:null,remediation:null}:{flagged:!0,severity:"critical",daemonAlive:!0,missing:o,message:`Daemon process is alive (per pidfile) but companion state file${o.length===1?"":"s"} ${o.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 Zu(e){e.flagged&&(console.log(""),console.log(_.dim("\u2014 Daemon state files \u2014")),console.log(_.err(` \u2717 CRITICAL: daemon process alive but missing ${e.missing.join(", ")}`)),e.remediation&&console.log(_.dim(` Remediation: ${e.remediation}`)))}function ep(e){if(e.flagged){console.log(""),console.log(_.dim("\u2014 Daemon processes \u2014")),console.log(_.err(` \u2717 CRITICAL: ${e.count} daemons running (two daemons must never run in parallel)`));for(let t of e.processes){let n=kn(t.etimeSeconds)??t.etime;console.log(` ${_.dim("\u2022")} pid ${t.pid} started ${n} age ${_e(t.etimeSeconds)} ppid=${t.ppid}`)}e.message&&console.log(_.dim(" Remediation: `recall stop` (now nukes orphans too as of Phase 2.6), then `recall start`."))}}function tp(e){if(console.log(_.dim("\u2014 MCP processes \u2014")),e.length===0){console.log(_.ok(" \u2713 no MCP children running"));return}let t=e.filter(o=>o.orphan),n=e.reduce((o,a)=>Math.max(o,a.etimeSeconds),0),s=e.length-t.length;if(console.log(` ${e.length} total, ${s} with live parent, ${t.length===0?_.ok("0 orphaned"):_.err(`${t.length} orphaned`)} (oldest ${_e(n)})`),t.length>0){console.log(_.dim(" Orphans hold a SQLite read connection and can stall WAL checkpoints. Run `recall mcp-prune` to kill them."));for(let o of t.slice(0,5))console.log(` ${_.dim("\u2022")} pid ${o.pid} age ${_e(o.etimeSeconds)} ppid=${o.ppid} (gone)`)}let r=e.filter(lt);if(r.length>0){console.log(_.warn(` ! ${r.length} MCP child${r.length===1?"":"ren"} burning CPU (likely a runaway vec0 kNN query).`));for(let o of r){let a=o.parentCommand?`parent ${o.parentCommand}`:`ppid ${o.ppid}`;console.log(_.dim(` pid ${o.pid} ${o.pcpu.toFixed(0)}%cpu ${_e(o.etimeSeconds)} elapsed (${a})`))}console.log(_.dim(" Run `recall stop --all` for one-command recovery, or `recall mcp-prune --all` to keep the daemon alive."))}let i=Mi(e);i.flagged&&i.message&&console.log(_.warn(` ! ${i.message}`))}function np(){let e=qi(),t=Ji();if(console.log(_.dim("\u2014 Auto-prune (last 24h) \u2014")),console.log(` Mode: ${e}`),e==="off"){console.log(_.dim(" (auto-prune disabled \u2014 orphans + runaway MCPs will accumulate until manually reaped)"));return}e==="dry-run"?console.log(` Would-have-killed: ${t.wouldHaveKilled} ${_.dim("(dry-run only)")}`):(console.log(` Killed: ${t.killed} ${_.dim("(enabled)")}`),t.failed>0&&console.log(` Failed: ${_.warn(String(t.failed))} ${_.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 wo(){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(i){let o=i instanceof Error?i.message:String(i);return o.includes("no such table: migration_state")||process.stderr.write(`[doctor] renderMigrationDoctorSection: ${o}
890
- `),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 o=e.prepare("SELECT CAST((julianday('now') - julianday(?)) AS INTEGER) AS days").get(n.completed_at),a=Math.max(0,30-o.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(`
891
- `)}function sp(){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 Ro(){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,i=0,o=[];for(let l of Ln(Tt)){if(xi(l))continue;let d=ki(l);if(!d||!n.has(d))continue;r+=1;let m;try{m=pt(l).mtimeMs}catch{continue}let p=s.get(l);p&&p.skipped_reason!==null||(!p||p.file_mtime<m)&&(i+=1,o.length<5&&o.push(l))}if(i===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=i>10?"fail":"warn",c=o.slice(0,3).map(l=>l.split(/[/\\]/).pop()??l).join(", ");return{status:a,staleCount:i,scanned:r,sampleFiles:o,message:`Ingest freshness: ${a} \u2014 ${i} JSONL${i===1?"":" files"} newer than the index (sample: ${c}). Run \`recall index\` to force a reindex, or restart the daemon if this is persistent.`}}function Ao(e=mt(Bu(),".claude.json")){let t={status:"ok",configPath:e,configExists:Ce(e),findings:[]};if(!t.configExists)return t;let n;try{n=Dn(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[i,o]of Object.entries(r)){if(!o||typeof o!="object")continue;let a=o.args;if(!Array.isArray(a)||a.length===0)continue;let c=a[0];if(typeof c!="string"||c.length===0||!c.startsWith("/")&&!c.startsWith("~")||Ce(c))continue;let l=i==="recall";t.findings.push({name:i,stalePath:c,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(i=>i.severity==="HIGH")?t.status="fail":t.findings.length>0&&(t.status="warn"),t}function No(){let e=null;try{e=wn().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 rp(e,t){let n=no(),{file:s,result:r}=ro(n,e);if((r.outcome==="acknowledged"||r.outcome==="already-acknowledged")&&s!==n&&so(s),t.json){let i=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(i)}
892
- `)}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 i of r.candidates??[])console.log(` ${i}`);break}return r.outcome==="not-found"||r.outcome==="ambiguous"?1:0}async function ip(e={}){if(typeof e.ack=="string"&&e.ack.length>0)return rp(e.ack,{json:!!e.json});let t=Qu(!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
888
+ `+F.join(`
889
+ `)+"\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 c.backupFileCount>0&&(X+=`
890
+ 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(X)}let h=100*1024**2,E=a>=zo?"error":a>=h?"warn":"ok";E==="error"?g.push(`WAL is ${B(a)} \u2014 readers are pinning the checkpoint frontier. Run \`recall mcp-prune\` to release stuck MCP children, then \`recall optimize\` to truncate.`):E==="warn"&&g.push(`WAL is ${B(a)} \u2014 run \`recall optimize\` to truncate it.`);let S=ve(),m=S.filter(R=>R.orphan);m.length>0&&g.push(`${m.length} orphaned MCP child${m.length===1?"":"ren"} (pid${m.length===1?"":"s"}: ${m.map(R=>R.pid).join(", ")}). Each holds a SQLite read connection. Run \`recall mcp-prune\` to clean up.`);let b=S.filter(lt);b.length>0&&g.push(`${b.length} MCP child${b.length===1?"":"ren"} burning CPU (pid${b.length===1?"":"s"}: ${b.map(R=>R.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 w=fi("messages_fts"),L=fi("sessions_fts");w>16&&g.push(`messages_fts has ${w} segments \u2014 \`recall optimize\` will merge them.`);let T=0;try{T=t.prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}catch{}let N=!1;try{N=t.prepare("SELECT value FROM app_settings WHERE key = 'semantic_enabled'").get()?.value==="1"}catch{}return!N&&T>0?g.push(`${T.toLocaleString()} rows in chunk_queue with semantic disabled \u2014 schema gate is stale; restart daemon (v0.67+) to migrate.`):T>1e5&&g.push(`chunk_queue has ${T.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:d,backups:{totalBytes:c.backupTotalBytes,fileCount:c.backupFileCount,oldFiles:c.oldFiles,severity:c.severity}},fts:{messages:{fragments:w},sessions:{fragments:L}},vectors:{rows:u},rows:{projects:p.projects,sessions:p.sessions,messages:p.messages,messageUsage:p.message_usage},chunkQueue:{size:T,semanticEnabled:N},wal:{sizeBytes:a,level:E},mcpProcesses:S,warnings:g}}function dp(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 ${f.ok("\u2713")} ${n} ${f.dim(`(${i})`)}
891
+ `):process.stderr.write(` \u2713 ${n} (${i})
892
+ `),n=""};return{stage(o){r(),n=o,s=Date.now(),t?process.stderr.write(` ${f.dim("\u2026")} ${n}`):process.stderr.write(` \u2026 ${n}
893
+ `)},done:r}}function Ni(e){let t=e??ut(),n=t.length;if(n<=1)return{flagged:!1,severity:"ok",count:n,processes:t,message:null};let s=t.map(o=>{let i=kn(o.etimeSeconds)??o.etime;return`pid=${o.pid} started=${i} age=${_e(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 Li(e={}){if((e.liveDaemons??ut({excludePids:[process.pid]})).length===0)return{flagged:!1,severity:"ok",daemonAlive:!1,missing:[],message:null,remediation:null};let n=e.paths??Wo(),s=e.existsSync??Ce,r=e.isProcessAlive??Xo,o=!1;if(s(n.pid))try{let c=JSON.parse(Mn(n.pid,"utf8"));typeof c.pid=="number"&&r(c.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 up(e){e.flagged&&(console.log(""),console.log(f.dim("\u2014 Daemon state files \u2014")),console.log(f.err(` \u2717 CRITICAL: daemon process alive but missing ${e.missing.join(", ")}`)),e.remediation&&console.log(f.dim(` Remediation: ${e.remediation}`)))}function pp(e){if(e.flagged){console.log(""),console.log(f.dim("\u2014 Daemon processes \u2014")),console.log(f.err(` \u2717 CRITICAL: ${e.count} daemons running (two daemons must never run in parallel)`));for(let t of e.processes){let n=kn(t.etimeSeconds)??t.etime;console.log(` ${f.dim("\u2022")} pid ${t.pid} started ${n} age ${_e(t.etimeSeconds)} ppid=${t.ppid}`)}e.message&&console.log(f.dim(" Remediation: `recall stop` (now nukes orphans too as of Phase 2.6), then `recall start`."))}}function mp(e){if(console.log(f.dim("\u2014 MCP processes \u2014")),e.length===0){console.log(f.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?f.ok("0 orphaned"):f.err(`${t.length} orphaned`)} (oldest ${_e(n)})`),t.length>0){console.log(f.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(` ${f.dim("\u2022")} pid ${i.pid} age ${_e(i.etimeSeconds)} ppid=${i.ppid} (gone)`)}let r=e.filter(lt);if(r.length>0){console.log(f.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(f.dim(` pid ${i.pid} ${i.pcpu.toFixed(0)}%cpu ${_e(i.etimeSeconds)} elapsed (${a})`))}console.log(f.dim(" Run `recall stop --all` for one-command recovery, or `recall mcp-prune --all` to keep the daemon alive."))}let o=$o(e);o.flagged&&o.message&&console.log(f.warn(` ! ${o.message}`))}function gp(){let e=ei(),t=Qo();if(console.log(f.dim("\u2014 Auto-prune (last 24h) \u2014")),console.log(` Mode: ${e}`),e==="off"){console.log(f.dim(" (auto-prune disabled \u2014 orphans + runaway MCPs will accumulate until manually reaped)"));return}e==="dry-run"?console.log(` Would-have-killed: ${t.wouldHaveKilled} ${f.dim("(dry-run only)")}`):(console.log(` Killed: ${t.killed} ${f.dim("(enabled)")}`),t.failed>0&&console.log(` Failed: ${f.warn(String(t.failed))} ${f.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 ki(){let 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}
894
+ `),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(`
895
+ `)}function fp(){let 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 xi(){let e=_();return li({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 Oi(){let e;try{e=xi()}catch(t){let n=t instanceof Error?t.message:String(t);return process.stderr.write(`[doctor] renderInDbBloatDoctorSection: ${n}
896
+ `),null}return di(e,{dim:f.dim,warn:f.warn})}function Ii(){let 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 Ln(bt)){if(vo(l))continue;let d=Io(l);if(!d||!n.has(d))continue;r+=1;let p;try{p=pt(l).mtimeMs}catch{continue}let u=s.get(l);u&&u.skipped_reason!==null||(!u||u.file_mtime<p)&&(o+=1,i.length<5&&i.push(l))}if(o===0)return{status:"ok",staleCount:0,scanned:r,sampleFiles:[],message:`Ingest freshness: ok (scanned ${r} JSONL${r===1?"":"s"} in ${n.size} known project${n.size===1?"":"s"}, none newer than the index).`};let a=o>10?"fail":"warn",c=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: ${c}). Run \`recall index\` to force a reindex, or restart the daemon if this is persistent.`}}function vi(e=mt(tp(),".claude.json")){let t={status:"ok",configPath:e,configExists:Ce(e),findings:[]};if(!t.configExists)return t;let n;try{n=Mn(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 c=a[0];if(typeof c!="string"||c.length===0||!c.startsWith("/")&&!c.startsWith("~")||Ce(c))continue;let l=o==="recall";t.findings.push({name:o,stalePath:c,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 Ci(){let e=null;try{e=wn().enabled}catch{return{status:"ok",configEnabled:null,dbValue:null,message:null}}let t=null;try{t=_().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 _p(e,t){let n=oi(),{file:s,result:r}=ai(n,e);if((r.outcome==="acknowledged"||r.outcome==="already-acknowledged")&&s!==n&&ii(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)}
897
+ `)}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 hp(e={}){if(typeof e.ack=="string"&&e.ack.length>0)return _p(e.ack,{json:!!e.json});let t=dp(!e.json);t.stage("Scanning session aliases");let n=_().prepare(`SELECT sa.session_id AS session_id, sa.alias AS alias, s.cwd AS cwd
893
898
  FROM session_aliases sa
894
899
  LEFT JOIN sessions s ON s.id = sa.session_id
895
- WHERE sa.alias IS NOT NULL AND sa.alias != ''`).all(),s=zu(n);t.stage("Probing daemon");let r=await ho(),i=To(t.stage);t.stage("Detecting label collisions");let o=So();t.stage("Checking ingest freshness");let a=Ro();t.stage("Checking ~/.claude.json MCP paths");let c=Ao();t.stage("Checking semantic gate drift");let l=No();t.stage("Sampling chunk_queue growth");let d=vn();t.stage("Scanning for sibling daemons");let m=bo();t.stage("Checking daemon state files");let p=yo({liveDaemons:m.processes});if(t.done(),e.json){process.stdout.write(JSON.stringify({scanned:n.length,violations:s.length,items:s,health:i,pipeline:r,labelCollisions:o,ingestFreshness:a,staleMcpEntries:c,semanticGateDrift:l,chunkQueueGrowth:d,siblingDaemons:m,daemonStateFiles:p},null,2)),process.stdout.write(`
896
- `);let u=r.state==="degraded",f=a.status==="fail",T=c.status==="fail",R=d.status==="critical",k=m.flagged,w=p.flagged,L=l.status==="critical";return s.length===0&&i.db.integrity==="ok"&&!u&&!f&&!T&&!R&&!k&&!L&&!w?0:1}console.log(_.dim("\u2014 System health \u2014")),console.log(` Database ${j(i.db.sizeBytes)} (${i.rows.messages.toLocaleString()} messages across ${i.rows.sessions.toLocaleString()} sessions, ${i.rows.projects.toLocaleString()} projects)`);{let u=i.wal,f=u.level==="error"?_.err(j(u.sizeBytes)):u.level==="warn"?_.warn(j(u.sizeBytes)):_.ok(j(u.sizeBytes)),T=u.level==="error"?" (readers are pinning the checkpoint frontier \u2014 see warnings below)":u.level==="warn"?" (above 100 MB \u2014 daemon will WARN until it drops)":" (daemon checkpoints PASSIVE every 60s, RESTART above 5 GB)";console.log(` WAL ${f}${T}`)}console.log(` Free pages ${i.db.freelistCount.toLocaleString()} (${j(i.db.freelistBytes)} reclaimable via VACUUM)`);{let u=i.fts.messages.fragments,f=i.fts.sessions.fragments,T=u===0&&f===0;console.log(` FTS segments messages=${u}, sessions=${f}`+(T?" (merged \u2014 search uses the index)":" (lower is faster \u2014 `recall optimize` merges them)"))}if(i.chunkQueue.size>0){let f=i.chunkQueue.size>1e5?_.warn(i.chunkQueue.size.toLocaleString()):i.chunkQueue.size.toLocaleString();console.log(` Embed queue ${f}`+(i.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 ${i.vectors.rows.toLocaleString()}`),i.disk.totalBytes>0){let u=i.disk.freeBytes/i.disk.totalBytes*100,f=i.disk.backups.severity,T=`${u.toFixed(1)}%`,R=f==="high"?_.err(T):f==="medium"?_.warn(T):_.ok(T);console.log(` Disk free ${j(i.disk.freeBytes)} of ${j(i.disk.totalBytes)} (${R})`)}if(i.disk.backups.fileCount>0){let u=i.disk.backups,f=j(u.totalBytes),T=u.severity==="high"?_.err(f):u.severity==="medium"?_.warn(f):f;console.log(` Snapshot files ${T} across ${u.fileCount} file${u.fileCount===1?"":"s"} in ~/.recall/`+(u.oldFiles.length>0?` (${u.oldFiles.length} older than 30 days)`:" (all recent \u2014 likely rollback-critical)"))}if(console.log(` Integrity ${i.db.integrity==="ok"?_.ok("ok"):_.err(i.db.integrity)}`),i.warnings.length>0){console.log("");for(let u of i.warnings)console.log(` ${_.warn("!")} ${u}`)}console.log(""),ep(m),Zu(p),tp(i.mcpProcesses),console.log(""),np();let g=wo();if(g!==null&&(console.log(""),console.log(g)),console.log(""),console.log(_.dim("\u2014 Ingest freshness \u2014")),a.status==="ok")console.log(_.ok(` \u2713 ${a.scanned.toLocaleString()} JSONL${a.scanned===1?"":"s"} scanned, none newer than the index`));else if(a.status==="warn"){console.log(` ${_.warn(`${a.staleCount} stale file${a.staleCount===1?"":"s"}`)} newer than the index \u2014 live watcher may be missing events`);for(let u of a.sampleFiles.slice(0,5))console.log(` ${_.dim("\u2022")} ${u}`);console.log(_.dim(" Run `recall index` to force a reindex, or restart the daemon if persistent."))}else{console.log(` ${_.err(`${a.staleCount} stale file${a.staleCount===1?"":"s"}`)} newer than the index \u2014 significant ingest gap`);for(let u of a.sampleFiles.slice(0,5))console.log(` ${_.dim("\u2022")} ${u}`);console.log(_.err(" Restart the daemon (recall stop && recall start) \u2014 the live watcher has fallen behind."))}console.log(""),console.log(_.dim("\u2014 chunk_queue growth \u2014"));{let u=d,f=u.status,T=u.currentSize.toLocaleString(),R=u.lastHourGrowth!==null?`\u0394 ${u.lastHourGrowth>=0?"+":""}${u.lastHourGrowth.toLocaleString()}/h`:"no prior sample in last hour",k=u.semanticEnabled?_.dim("semantic=on"):_.dim("semantic=off");f==="ok"?console.log(_.ok(` \u2713 ${T} rows, ${R}`)+` ${k}`+_.dim(` (${u.priorSampleCount} prior sample${u.priorSampleCount===1?"":"s"} in last hour)`)):f==="critical"?(console.log(` ${_.err("CRITICAL")} ${T} rows, ${R} ${k}`),u.remediation&&console.log(_.dim(` ${u.remediation}`))):f==="high"?(console.log(` ${_.warn("HIGH")} ${T} rows, ${R} ${k}`),u.remediation&&console.log(_.dim(` ${u.remediation}`))):(console.log(` ${_.warn("MEDIUM")} ${T} rows, ${R} ${k}`),u.remediation&&console.log(_.dim(` ${u.remediation}`)))}if(console.log(""),console.log(_.dim("\u2014 ~/.claude.json MCP paths \u2014")),!c.configExists)console.log(_.dim(" (no ~/.claude.json on disk \u2014 skipped)"));else if(c.findings.length===0)console.log(_.ok(" \u2713 all MCP server script paths exist on disk"));else{let u=c.findings.filter(T=>T.severity==="HIGH"),f=c.findings.filter(T=>T.severity==="MEDIUM");if(u.length>0){console.log(` ${_.err(`${u.length} stale entry`)}${u.length===1?"":" (HIGH)"} that we own:`);for(let T of u)console.log(` ${_.err("\u2717")} ${T.name} ${_.dim("\u2192")} ${T.stalePath}`),console.log(` ${_.dim("Remediation:")} ${T.remediation}`)}if(f.length>0){console.log(` ${_.warn(`${f.length} third-party stale entr${f.length===1?"y":"ies"}`)} (MEDIUM):`);for(let T of f)console.log(` ${_.warn("!")} ${T.name} ${_.dim("\u2192")} ${T.stalePath}`),console.log(` ${_.dim("Remediation:")} ${T.remediation}`)}}if(console.log(""),console.log(_.dim("\u2014 Semantic gate drift \u2014")),l.status==="ok"?l.configEnabled!==null&&l.dbValue!==null?console.log(_.ok(` \u2713 config.json + DB gate agree (semantic.enabled=${String(l.configEnabled)}, gate=${l.dbValue})`)):console.log(_.dim(" (no gate row to compare \u2014 skipped)")):(console.log(` ${_.err("CRITICAL")} config.json semantic.enabled=${String(l.configEnabled)} but DB gate=${l.dbValue}`),l.message&&console.log(_.dim(` ${l.message}`))),console.log(""),console.log(_.dim("\u2014 Pipeline health (tab-name \u2192 session alias) \u2014")),r.daemon.running?console.log(` Daemon ${_.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 ${_.warn("not reachable")}`),r.runtime.silentTerminalRejections!==null){let u=r.runtime.silentTerminalRejections;console.log(` Auth rejections ${u===0?_.ok("0"):_.err(u.toLocaleString())} (extension /api/terminal/* requests denied without a valid X-Recall-Token)`)}if(r.runtime.autoExtract){let u=r.runtime.autoExtract;u.circuitBroken?console.log(` Auto-extract ${_.err("circuit broken")} (${u.reason??"unknown"} \u2014 toggle off/on to reset)`):u.consecutiveZeroTokenRuns>0&&console.log(` Auto-extract ${_.warn(`${u.consecutiveZeroTokenRuns} zero-token run(s)`)} (breaker trips at 3)`)}if(r.runtime.lastTerminalSyncAt!==null){let u=Date.now()-Date.parse(r.runtime.lastTerminalSyncAt),f=Number.isFinite(u)?Math.round(u/6e4):null,T=f!==null&&u>fo;console.log(` Last ext sync ${T?_.warn(`${f} min ago`):_.ok(f===0?"just now":`${f} min ago`)} (most recent successful POST /api/terminal/sync)`)}else r.daemon.running&&console.log(` Last ext sync ${_.warn("never")} (no extension has called /api/terminal/sync since the daemon started)`);if(r.terminalsJson.exists&&r.terminalsJson.ageSeconds!==null){let u=Math.round(r.terminalsJson.ageSeconds/3600),f=r.terminalsJson.ageSeconds>24*3600;console.log(` terminals.json ${f?_.warn(`${u}h old`):_.ok(`${u}h old`)} (persisted registry mtime \u2014 fresh means extensions are connecting)`)}let h=r.recentSessions;if(h.total>0){let u=Math.round(h.fractionHeuristic*100),f=h.fractionHeuristic>=_o&&h.total>=3;console.log(` Recent titles ${f?_.err(`${u}% heuristic`):_.ok(`${u}% heuristic`)} (${h.heuristicOnly}/${h.total} sessions in last ${Mn}h fell back to first-message title)`)}if(r.flags.length>0){console.log("");for(let u of r.flags)console.log(` ${_.warn("!")} ${u}`)}if(console.log(""),console.log(_.dim("\u2014 Label collisions (last 7d) \u2014")),o.length===0)console.log(_.ok(" \u2713 no session-list label collisions in the last week"));else{let u=o.filter(f=>!f.anyAliased);console.log(` ${_.warn(`${o.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 f of o.slice(0,5)){let T=f.anyAliased?_.dim("partial alias"):_.warn("NO alias"),R=f.label.length>60?`${f.label.slice(0,57)}\u2026`:f.label;console.log(` ${_.dim(`${f.count}\xD7`)} ${R} ${T} ${_.dim(`(${f.project})`)}`)}o.length>5&&console.log(_.dim(` \u2026 and ${o.length-5} more (--json for full list)`)),console.log(""),console.log(_.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(_.dim(" <!-- claude-recall-alias: T1.3 \u2014 Auth Refactor -->")),console.log(_.dim(` The watcher will read the header, alias the session, and strip the marker from the
897
- displayed first user message. See https://clauderecall.com/docs \u2192 "Alias header convention".`)),u.length>0&&(console.log(""),console.log(_.warn(` ${u.length} of these groups have NO alias on any row \u2014 strongest candidates
898
- for the header-alias fix above.`)))}if(console.log(""),console.log(_.dim("\u2014 Tab-name invariant \u2014")),s.length===0)return console.log(_.ok(` \u2713 holds across ${n.length.toLocaleString()} aliased session${n.length===1?"":"s"}`)),console.log(_.dim(" No fabricated origin labels (`VS Code \xB7 cwd \xB7 branch`) found. No deprecated cwd-branch synthesis found.")),i.db.integrity==="ok"&&a.status!=="fail"&&c.status!=="fail"&&d.status!=="critical"&&!m.flagged&&l.status!=="critical"&&!p.flagged?0:1;console.log(_.err(`\u2717 ${s.length} invariant violation${s.length===1?"":"s"} found across ${n.length.toLocaleString()} aliased sessions`)),console.log("");let S=new Map;for(let u of s){let f=S.get(u.violation)??[];f.push(u),S.set(u.violation,f)}for(let[u,f]of S){console.log(_.warn(` ${u} (${f.length})`));for(let T of f.slice(0,10))console.log(` ${T.session_id.slice(0,8)} ${_.dim("\u2192")} ${JSON.stringify(T.alias)}`);f.length>10&&console.log(_.dim(` \u2026 and ${f.length-10} more (rerun with --json for the full list)`)),console.log("")}return console.log(_.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 op(){try{let e=uo(y);return Number(e.bavail)*Number(e.bsize)}catch{return 0}}var Xu,Gu,mo,fo,Mn,_o,ao,ko=b(()=>{"use strict";hn();x();Pe();v();Oi();dt();xn();Wi();Xi();we();Cn();Qi();io();Rn();Xu=["VS Code","VS Code Insiders","Cursor","Windsurf","Warp","iTerm","Terminal","WezTerm","Windows Terminal","Kitty","Alacritty"],Gu=new RegExp(`^(${Xu.map(e=>e.replace(/ /g,"\\s")).join("|")})\\s\xB7\\s`);mo=50;fo=5*6e4,Mn=24,_o=.5;ao=5e3});var xo={};ye(xo,{runOptimize:()=>up});import{existsSync as ap,readFileSync as cp}from"node:fs";import{join as lp}from"node:path";function dp(){let e=lp(y,"daemon.pid");if(!ap(e))return!1;try{let t=parseInt(cp(e,"utf-8").trim(),10);return!Number.isFinite(t)||t<=0?!1:(process.kill(t,0),!0)}catch{return!1}}async function De(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 up(e={}){let t=E(),n=[];if(e.vacuum&&dp())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)+`
899
- `),2):(console.error(_.err("\u2717 VACUUM requires the daemon to be stopped. Run `recall stop` first, then re-run with --vacuum.")),2);n.push(await De("wal_checkpoint(TRUNCATE)",()=>{t.pragma("wal_checkpoint(TRUNCATE)")})),n.push(await De("messages_fts optimize",()=>{t.exec("INSERT INTO messages_fts(messages_fts) VALUES('optimize');")})),n.push(await De("sessions_fts optimize",()=>{t.exec("INSERT INTO sessions_fts(sessions_fts) VALUES('optimize');")})),n.push(await De("PRAGMA optimize",()=>{t.exec("PRAGMA optimize")})),e.vacuum&&n.push(await De("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)+`
900
- `),s.length===0?0:1;for(let r of n){let i=r.ok?_.ok("\u2713"):_.err("\u2717"),o=`${r.durationMs} ms`;console.log(` ${i} ${r.step.padEnd(28)} ${_.dim(o)}`),r.error&&console.log(` ${_.err(r.error)}`)}return s.length===0?(console.log(""),console.log(_.ok("All maintenance passes completed.")),e.vacuum||console.log(_.dim(" Run `recall optimize --vacuum` (with the daemon stopped) to reclaim disk pages from deleted rows.")),0):(console.log(""),console.log(_.warn(`${s.length} step(s) failed \u2014 review the errors above.`)),1)}var Oo=b(()=>{"use strict";hn();x();v()});x();import{McpServer as pp}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as mp}from"@modelcontextprotocol/sdk/server/stdio.js";import{z as N}from"zod";import{fileURLToPath as Do,pathToFileURL as Io}from"node:url";we();function Vn(e){let t=e.onShutdown,n=e.pollIntervalMs??5e3,s=e.logger??(f=>{process.stderr.write(f+`
901
- `)}),r=e.stdin??process.stdin,i=e.getPpid??(()=>process.ppid),o=e.getPid??(()=>process.pid),a=e.startupGraceMs??1500,c=e.now??(()=>process.uptime()*1e3),l=!1,d=null,m=i(),p=()=>{d&&(clearInterval(d),d=null),r.removeListener("end",S),r.removeListener("close",u)},g=f=>{if(l)return;l=!0,s(`[parent-death-guard] shutdown triggered: ${f} (pid=${o()} initialPpid=${m} currentPpid=${i()})`),p();let T;try{T=t()}catch(R){s(`[parent-death-guard] onShutdown threw: ${ne(R)}`);return}T&&typeof T.then=="function"&&T.catch(R=>{s(`[parent-death-guard] onShutdown rejected: ${ne(R)}`)})},h=()=>a>0&&c()<a,S=()=>{if(h()){s(`[parent-death-guard] stdin end ignored during startup grace (${a}ms; ppid=${i()})`);return}g("stdin end")},u=()=>{if(h()){s(`[parent-death-guard] stdin close ignored during startup grace (${a}ms; ppid=${i()})`);return}g("stdin close")};return r.on("end",S),r.on("close",u),m!==1&&(d=setInterval(()=>{let f=i();f!==m&&g(`ppid changed ${m} -> ${f}`)},n),typeof d.unref=="function"&&d.unref()),{stop:p}}we();var qn=Date.now();function bt(e=Date.now()){qn=e}var Go=1800*1e3,zo=60*1e3,Yo=60*1e3,Ko=480*60*1e3;function Jo(){process.stderr.write(`
902
- `)}function Vo(e){return!e||typeof e!="object"?!1:e.code==="EPIPE"}function Qn(e){let t=e.onShutdown,n=e.idleThresholdMs??Go,s=e.idleCheckIntervalMs??zo,r=e.pipeProbeIntervalMs??Yo,i=e.maxLifetimeMs??Ko,o=e.pipeProbe??Jo,a=e.logger??(w=>{process.stderr.write(w+`
903
- `)}),c=e.now??(()=>Date.now()),l=e.setInterval??((w,L)=>setInterval(w,L)),d=e.setTimeout??((w,L)=>setTimeout(w,L)),m=e.clearInterval??(w=>clearInterval(w)),p=e.clearTimeout??(w=>clearTimeout(w));bt(c());let g=!1,h=!1,S=null,u=null,f=null,T=w=>{if(!w)return;let L=w;if(typeof L.unref=="function")try{L.unref()}catch(A){a(`[mcp-lifecycle] unref failed (likely test stub): ${ne(A)}`)}},R=()=>{g||(g=!0,S&&(m(S),S=null),u&&(m(u),u=null),f&&(p(f),f=null))},k=w=>{if(h||g)return;h=!0,a(`[mcp-lifecycle] shutdown triggered: ${w}`),R();let L;try{L=t(w)}catch(A){a(`[mcp-lifecycle] onShutdown threw: ${ne(A)}`);return}L&&typeof L.then=="function"&&L.catch(A=>{a(`[mcp-lifecycle] onShutdown rejected: ${ne(A)}`)})};return S=l(()=>{if(h||g)return;let w=c()-qn;w>n&&k(`idle ${Math.round(w/1e3)}s (threshold ${Math.round(n/1e3)}s)`)},s),T(S),u=l(()=>{if(!(h||g))try{o()}catch(w){Vo(w)?k("stderr EPIPE (parent closed read end)"):a(`[mcp-lifecycle] pipe probe write failed (non-EPIPE): ${ne(w)}`)}},r),T(u),f=d(()=>{k(`max lifetime ${Math.round(i/1e3/60)}m exceeded`)},i),T(f),{stop:R}}var qo=/<(local-command-caveat|local-command-stdout|command-name|command-message|command-args|system-reminder|user-prompt-submit-hook|task-notification)[\s\S]*?<\/\1>/gi,Qo=/⚡ \*\*Tool call · `[^`]+`\*\*\s*\n+```json\n[\s\S]*?\n```/g,Zo=/\*\*Tool result\*\*\s*\n+```\n[\s\S]*?\n```/g;function ea(e){return e.replace(qo,"").trim()}function ta(e){let t=e.replace(Qo,"[tool call]");return t=t.replace(Zo,"[tool result]"),t=t.replace(/_\(unknown block: thinking\)_/g,""),t=t.replace(/(?:\[tool call\]|\[tool result\])(?:\s*(?:\[tool call\]|\[tool result\]))+/g,"[tool activity]"),t=t.replace(/\n{3,}/g,`
900
+ WHERE sa.alias IS NOT NULL AND sa.alias != ''`).all(),s=rp(n);t.stage("Probing daemon");let r=await yi(),o=Ai(t.stage);t.stage("Detecting label collisions");let i=Ri();t.stage("Checking ingest freshness");let a=Ii();t.stage("Checking ~/.claude.json MCP paths");let c=vi();t.stage("Checking semantic gate drift");let l=Ci();t.stage("Sampling chunk_queue growth");let d=vn();t.stage("Scanning for sibling daemons");let p=Ni();t.stage("Checking daemon state files");let u=Li({liveDaemons:p.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:c,semanticGateDrift:l,chunkQueueGrowth:d,siblingDaemons:p,daemonStateFiles:u},null,2)),process.stdout.write(`
901
+ `);let m=r.state==="degraded",b=a.status==="fail",w=c.status==="fail",L=d.status==="critical",T=p.flagged,N=u.flagged,R=l.status==="critical";return s.length===0&&o.db.integrity==="ok"&&!m&&!b&&!w&&!L&&!T&&!R&&!N?0:1}console.log(f.dim("\u2014 System health \u2014")),console.log(` Database ${B(o.db.sizeBytes)} (${o.rows.messages.toLocaleString()} messages across ${o.rows.sessions.toLocaleString()} sessions, ${o.rows.projects.toLocaleString()} projects)`);{let m=o.wal,b=m.level==="error"?f.err(B(m.sizeBytes)):m.level==="warn"?f.warn(B(m.sizeBytes)):f.ok(B(m.sizeBytes)),w=m.level==="error"?" (readers are pinning the checkpoint frontier \u2014 see warnings below)":m.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}${w}`)}console.log(` Free pages ${o.db.freelistCount.toLocaleString()} (${B(o.db.freelistBytes)} reclaimable via VACUUM)`);{let m=o.fts.messages.fragments,b=o.fts.sessions.fragments,w=m===0&&b===0;console.log(` FTS segments messages=${m}, sessions=${b}`+(w?" (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?f.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 m=o.disk.freeBytes/o.disk.totalBytes*100,b=o.disk.backups.severity,w=`${m.toFixed(1)}%`,L=b==="high"?f.err(w):b==="medium"?f.warn(w):f.ok(w);console.log(` Disk free ${B(o.disk.freeBytes)} of ${B(o.disk.totalBytes)} (${L})`)}if(o.disk.backups.fileCount>0){let m=o.disk.backups,b=B(m.totalBytes),w=m.severity==="high"?f.err(b):m.severity==="medium"?f.warn(b):b;console.log(` Snapshot files ${w} across ${m.fileCount} file${m.fileCount===1?"":"s"} in ~/.recall/`+(m.oldFiles.length>0?` (${m.oldFiles.length} older than 30 days)`:" (all recent \u2014 likely rollback-critical)"))}if(console.log(` Integrity ${o.db.integrity==="ok"?f.ok("ok"):f.err(o.db.integrity)}`),o.warnings.length>0){console.log("");for(let m of o.warnings)console.log(` ${f.warn("!")} ${m}`)}console.log(""),pp(p),up(u),mp(o.mcpProcesses),console.log(""),gp();let g=ki();g!==null&&(console.log(""),console.log(g));let h=Oi();if(h!==null&&(console.log(""),console.log(h)),console.log(""),console.log(f.dim("\u2014 Ingest freshness \u2014")),a.status==="ok")console.log(f.ok(` \u2713 ${a.scanned.toLocaleString()} JSONL${a.scanned===1?"":"s"} scanned, none newer than the index`));else if(a.status==="warn"){console.log(` ${f.warn(`${a.staleCount} stale file${a.staleCount===1?"":"s"}`)} newer than the index \u2014 live watcher may be missing events`);for(let m of a.sampleFiles.slice(0,5))console.log(` ${f.dim("\u2022")} ${m}`);console.log(f.dim(" Run `recall index` to force a reindex, or restart the daemon if persistent."))}else{console.log(` ${f.err(`${a.staleCount} stale file${a.staleCount===1?"":"s"}`)} newer than the index \u2014 significant ingest gap`);for(let m of a.sampleFiles.slice(0,5))console.log(` ${f.dim("\u2022")} ${m}`);console.log(f.err(" Restart the daemon (recall stop && recall start) \u2014 the live watcher has fallen behind."))}console.log(""),console.log(f.dim("\u2014 chunk_queue growth \u2014"));{let m=d,b=m.status,w=m.currentSize.toLocaleString(),L=m.lastHourGrowth!==null?`\u0394 ${m.lastHourGrowth>=0?"+":""}${m.lastHourGrowth.toLocaleString()}/h`:"no prior sample in last hour",T=m.semanticEnabled?f.dim("semantic=on"):f.dim("semantic=off");b==="ok"?console.log(f.ok(` \u2713 ${w} rows, ${L}`)+` ${T}`+f.dim(` (${m.priorSampleCount} prior sample${m.priorSampleCount===1?"":"s"} in last hour)`)):b==="critical"?(console.log(` ${f.err("CRITICAL")} ${w} rows, ${L} ${T}`),m.remediation&&console.log(f.dim(` ${m.remediation}`))):b==="high"?(console.log(` ${f.warn("HIGH")} ${w} rows, ${L} ${T}`),m.remediation&&console.log(f.dim(` ${m.remediation}`))):(console.log(` ${f.warn("MEDIUM")} ${w} rows, ${L} ${T}`),m.remediation&&console.log(f.dim(` ${m.remediation}`)))}if(console.log(""),console.log(f.dim("\u2014 ~/.claude.json MCP paths \u2014")),!c.configExists)console.log(f.dim(" (no ~/.claude.json on disk \u2014 skipped)"));else if(c.findings.length===0)console.log(f.ok(" \u2713 all MCP server script paths exist on disk"));else{let m=c.findings.filter(w=>w.severity==="HIGH"),b=c.findings.filter(w=>w.severity==="MEDIUM");if(m.length>0){console.log(` ${f.err(`${m.length} stale entry`)}${m.length===1?"":" (HIGH)"} that we own:`);for(let w of m)console.log(` ${f.err("\u2717")} ${w.name} ${f.dim("\u2192")} ${w.stalePath}`),console.log(` ${f.dim("Remediation:")} ${w.remediation}`)}if(b.length>0){console.log(` ${f.warn(`${b.length} third-party stale entr${b.length===1?"y":"ies"}`)} (MEDIUM):`);for(let w of b)console.log(` ${f.warn("!")} ${w.name} ${f.dim("\u2192")} ${w.stalePath}`),console.log(` ${f.dim("Remediation:")} ${w.remediation}`)}}if(console.log(""),console.log(f.dim("\u2014 Semantic gate drift \u2014")),l.status==="ok"?l.configEnabled!==null&&l.dbValue!==null?console.log(f.ok(` \u2713 config.json + DB gate agree (semantic.enabled=${String(l.configEnabled)}, gate=${l.dbValue})`)):console.log(f.dim(" (no gate row to compare \u2014 skipped)")):(console.log(` ${f.err("CRITICAL")} config.json semantic.enabled=${String(l.configEnabled)} but DB gate=${l.dbValue}`),l.message&&console.log(f.dim(` ${l.message}`))),console.log(""),console.log(f.dim("\u2014 Pipeline health (tab-name \u2192 session alias) \u2014")),r.daemon.running?console.log(` Daemon ${f.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 ${f.warn("not reachable")}`),r.runtime.silentTerminalRejections!==null){let m=r.runtime.silentTerminalRejections;console.log(` Auth rejections ${m===0?f.ok("0"):f.err(m.toLocaleString())} (extension /api/terminal/* requests denied without a valid X-Recall-Token)`)}if(r.runtime.autoExtract){let m=r.runtime.autoExtract;m.circuitBroken?console.log(` Auto-extract ${f.err("circuit broken")} (${m.reason??"unknown"} \u2014 toggle off/on to reset)`):m.consecutiveZeroTokenRuns>0&&console.log(` Auto-extract ${f.warn(`${m.consecutiveZeroTokenRuns} zero-token run(s)`)} (breaker trips at 3)`)}if(r.runtime.lastTerminalSyncAt!==null){let m=Date.now()-Date.parse(r.runtime.lastTerminalSyncAt),b=Number.isFinite(m)?Math.round(m/6e4):null,w=b!==null&&m>bi;console.log(` Last ext sync ${w?f.warn(`${b} min ago`):f.ok(b===0?"just now":`${b} min ago`)} (most recent successful POST /api/terminal/sync)`)}else r.daemon.running&&console.log(` Last ext sync ${f.warn("never")} (no extension has called /api/terminal/sync since the daemon started)`);if(r.terminalsJson.exists&&r.terminalsJson.ageSeconds!==null){let m=Math.round(r.terminalsJson.ageSeconds/3600),b=r.terminalsJson.ageSeconds>24*3600;console.log(` terminals.json ${b?f.warn(`${m}h old`):f.ok(`${m}h old`)} (persisted registry mtime \u2014 fresh means extensions are connecting)`)}let E=r.recentSessions;if(E.total>0){let m=Math.round(E.fractionHeuristic*100),b=E.fractionHeuristic>=Ti&&E.total>=3;console.log(` Recent titles ${b?f.err(`${m}% heuristic`):f.ok(`${m}% heuristic`)} (${E.heuristicOnly}/${E.total} sessions in last ${Pn}h fell back to first-message title)`)}if(r.flags.length>0){console.log("");for(let m of r.flags)console.log(` ${f.warn("!")} ${m}`)}if(console.log(""),console.log(f.dim("\u2014 Label collisions (last 7d) \u2014")),i.length===0)console.log(f.ok(" \u2713 no session-list label collisions in the last week"));else{let m=i.filter(b=>!b.anyAliased);console.log(` ${f.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 w=b.anyAliased?f.dim("partial alias"):f.warn("NO alias"),L=b.label.length>60?`${b.label.slice(0,57)}\u2026`:b.label;console.log(` ${f.dim(`${b.count}\xD7`)} ${L} ${w} ${f.dim(`(${b.project})`)}`)}i.length>5&&console.log(f.dim(` \u2026 and ${i.length-5} more (--json for full list)`)),console.log(""),console.log(f.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(f.dim(" <!-- claude-recall-alias: T1.3 \u2014 Auth Refactor -->")),console.log(f.dim(` The watcher will read the header, alias the session, and strip the marker from the
902
+ displayed first user message. See https://clauderecall.com/docs \u2192 "Alias header convention".`)),m.length>0&&(console.log(""),console.log(f.warn(` ${m.length} of these groups have NO alias on any row \u2014 strongest candidates
903
+ for the header-alias fix above.`)))}if(console.log(""),console.log(f.dim("\u2014 Tab-name invariant \u2014")),s.length===0)return console.log(f.ok(` \u2713 holds across ${n.length.toLocaleString()} aliased session${n.length===1?"":"s"}`)),console.log(f.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"&&c.status!=="fail"&&d.status!=="critical"&&!p.flagged&&l.status!=="critical"&&!u.flagged?0:1;console.log(f.err(`\u2717 ${s.length} invariant violation${s.length===1?"":"s"} found across ${n.length.toLocaleString()} aliased sessions`)),console.log("");let S=new Map;for(let m of s){let b=S.get(m.violation)??[];b.push(m),S.set(m.violation,b)}for(let[m,b]of S){console.log(f.warn(` ${m} (${b.length})`));for(let w of b.slice(0,10))console.log(` ${w.session_id.slice(0,8)} ${f.dim("\u2192")} ${JSON.stringify(w.alias)}`);b.length>10&&console.log(f.dim(` \u2026 and ${b.length-10} more (rerun with --json for the full list)`)),console.log("")}return console.log(f.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 Ep(){try{let e=_i(A);return Number(e.bavail)*Number(e.bsize)}catch{return 0}}var np,sp,Ei,bi,Pn,Ti,mi,Mi=y(()=>{"use strict";hn();x();Pe();v();Co();dt();xn();Go();Yo();we();Cn();ti();ci();Rn();ui();np=["VS Code","VS Code Insiders","Cursor","Windsurf","Warp","iTerm","Terminal","WezTerm","Windows Terminal","Kitty","Alacritty"],sp=new RegExp(`^(${np.map(e=>e.replace(/ /g,"\\s")).join("|")})\\s\xB7\\s`);Ei=50;bi=5*6e4,Pn=24,Ti=.5;mi=5e3});var Pi={};ye(Pi,{runOptimize:()=>wp});import{existsSync as Sp,readFileSync as bp}from"node:fs";import{join as Tp}from"node:path";function yp(){let e=Tp(A,"daemon.pid");if(!Sp(e))return!1;try{let t=parseInt(bp(e,"utf-8").trim(),10);return!Number.isFinite(t)||t<=0?!1:(process.kill(t,0),!0)}catch{return!1}}async function De(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 wp(e={}){let t=_(),n=[];if(e.vacuum&&yp())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)+`
904
+ `),2):(console.error(f.err("\u2717 VACUUM requires the daemon to be stopped. Run `recall stop` first, then re-run with --vacuum.")),2);n.push(await De("wal_checkpoint(TRUNCATE)",()=>{t.pragma("wal_checkpoint(TRUNCATE)")})),n.push(await De("messages_fts optimize",()=>{t.exec("INSERT INTO messages_fts(messages_fts) VALUES('optimize');")})),n.push(await De("sessions_fts optimize",()=>{t.exec("INSERT INTO sessions_fts(sessions_fts) VALUES('optimize');")})),n.push(await De("PRAGMA optimize",()=>{t.exec("PRAGMA optimize")})),e.vacuum&&n.push(await De("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)+`
905
+ `),s.length===0?0:1;for(let r of n){let o=r.ok?f.ok("\u2713"):f.err("\u2717"),i=`${r.durationMs} ms`;console.log(` ${o} ${r.step.padEnd(28)} ${f.dim(i)}`),r.error&&console.log(` ${f.err(r.error)}`)}return s.length===0?(console.log(""),console.log(f.ok("All maintenance passes completed.")),e.vacuum||console.log(f.dim(" Run `recall optimize --vacuum` (with the daemon stopped) to reclaim disk pages from deleted rows.")),0):(console.log(""),console.log(f.warn(`${s.length} step(s) failed \u2014 review the errors above.`)),1)}var Fi=y(()=>{"use strict";hn();x();v()});x();import{McpServer as Rp}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as Ap}from"@modelcontextprotocol/sdk/server/stdio.js";import{z as k}from"zod";import{fileURLToPath as Hi,pathToFileURL as $i}from"node:url";we();function qn(e){let t=e.onShutdown,n=e.pollIntervalMs??5e3,s=e.logger??(m=>{process.stderr.write(m+`
906
+ `)}),r=e.stdin??process.stdin,o=e.getPpid??(()=>process.ppid),i=e.getPid??(()=>process.pid),a=e.startupGraceMs??1500,c=e.now??(()=>process.uptime()*1e3),l=!1,d=null,p=o(),u=()=>{d&&(clearInterval(d),d=null),r.removeListener("end",E),r.removeListener("close",S)},g=m=>{if(l)return;l=!0,s(`[parent-death-guard] shutdown triggered: ${m} (pid=${i()} initialPpid=${p} currentPpid=${o()})`),u();let b;try{b=t()}catch(w){s(`[parent-death-guard] onShutdown threw: ${se(w)}`);return}b&&typeof b.then=="function"&&b.catch(w=>{s(`[parent-death-guard] onShutdown rejected: ${se(w)}`)})},h=()=>a>0&&c()<a,E=()=>{if(h()){s(`[parent-death-guard] stdin end ignored during startup grace (${a}ms; ppid=${o()})`);return}g("stdin end")},S=()=>{if(h()){s(`[parent-death-guard] stdin close ignored during startup grace (${a}ms; ppid=${o()})`);return}g("stdin close")};return r.on("end",E),r.on("close",S),p!==1&&(d=setInterval(()=>{let m=o();m!==p&&g(`ppid changed ${p} -> ${m}`)},n),typeof d.unref=="function"&&d.unref()),{stop:u}}we();var Qn=Date.now();function Tt(e=Date.now()){Qn=e}var Qi=1800*1e3,Zi=60*1e3,ea=60*1e3,ta=480*60*1e3;function na(){process.stderr.write(`
907
+ `)}function sa(e){return!e||typeof e!="object"?!1:e.code==="EPIPE"}function Zn(e){let t=e.onShutdown,n=e.idleThresholdMs??Qi,s=e.idleCheckIntervalMs??Zi,r=e.pipeProbeIntervalMs??ea,o=e.maxLifetimeMs??ta,i=e.pipeProbe??na,a=e.logger??(T=>{process.stderr.write(T+`
908
+ `)}),c=e.now??(()=>Date.now()),l=e.setInterval??((T,N)=>setInterval(T,N)),d=e.setTimeout??((T,N)=>setTimeout(T,N)),p=e.clearInterval??(T=>clearInterval(T)),u=e.clearTimeout??(T=>clearTimeout(T));Tt(c());let g=!1,h=!1,E=null,S=null,m=null,b=T=>{if(!T)return;let N=T;if(typeof N.unref=="function")try{N.unref()}catch(R){a(`[mcp-lifecycle] unref failed (likely test stub): ${se(R)}`)}},w=()=>{g||(g=!0,E&&(p(E),E=null),S&&(p(S),S=null),m&&(u(m),m=null))},L=T=>{if(h||g)return;h=!0,a(`[mcp-lifecycle] shutdown triggered: ${T}`),w();let N;try{N=t(T)}catch(R){a(`[mcp-lifecycle] onShutdown threw: ${se(R)}`);return}N&&typeof N.then=="function"&&N.catch(R=>{a(`[mcp-lifecycle] onShutdown rejected: ${se(R)}`)})};return E=l(()=>{if(h||g)return;let T=c()-Qn;T>n&&L(`idle ${Math.round(T/1e3)}s (threshold ${Math.round(n/1e3)}s)`)},s),b(E),S=l(()=>{if(!(h||g))try{i()}catch(T){sa(T)?L("stderr EPIPE (parent closed read end)"):a(`[mcp-lifecycle] pipe probe write failed (non-EPIPE): ${se(T)}`)}},r),b(S),m=d(()=>{L(`max lifetime ${Math.round(o/1e3/60)}m exceeded`)},o),b(m),{stop:w}}var ra=/<(local-command-caveat|local-command-stdout|command-name|command-message|command-args|system-reminder|user-prompt-submit-hook|task-notification)[\s\S]*?<\/\1>/gi,oa=/⚡ \*\*Tool call · `[^`]+`\*\*\s*\n+```json\n[\s\S]*?\n```/g,ia=/\*\*Tool result\*\*\s*\n+```\n[\s\S]*?\n```/g;function aa(e){return e.replace(ra,"").trim()}function ca(e){let t=e.replace(oa,"[tool call]");return t=t.replace(ia,"[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,`
904
909
 
905
- `),t.trim()}function na(e){return e.role??e.type??"message"}function Zn(e,t,n={}){let s=n.mode??"condensed",r=n.includeSidechain===!0,i=n.since?Date.parse(n.since):0,o=t.filter(d=>!(!r&&d.is_sidechain===1||i&&d.timestamp&&Date.parse(d.timestamp)<i)),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**: ${o.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 c=0,l=0;for(let d of o){let m=d.content_text??"",p=ea(m);s==="condensed"&&(p=ta(p));let g=p.length>0,h=!!d.tool_names&&d.tool_names.length>0;if(!g&&!h){l+=1;continue}let S=na(d),u=d.timestamp?` \`${d.timestamp}\``:"";a.push(`## ${S}${u}`),a.push(""),h&&s==="condensed"&&(a.push(`_tools used: ${d.tool_names}_`),a.push("")),g&&(a.push(p),a.push("")),c+=1}return a.push("---"),a.push(""),a.push(`_${c} messages included_`+(l?`, ${l} empty skipped`:"")+(r?"":", subagent/sidechain hidden")+"."),a.join(`
906
- `)}Ue();yt();import{existsSync as aa,mkdirSync as am,readFileSync as ca,writeFileSync as cm,chmodSync as lm}from"node:fs";import{homedir as la}from"node:os";import{join as ss}from"node:path";import{z as ae}from"zod";function da(){return process.env.RECALL_HOME??ss(la(),".recall")}function ua(){return ss(da(),"config.json")}var pa=ae.object({enabled:ae.boolean().default(!1),backend:ae.enum(["api","mcp"]).default("api"),apiKey:ae.string().optional(),model:ae.string().default("claude-opus-4-7"),maxTagsPerSession:ae.number().int().min(1).max(10).default(4),minTagsPerSession:ae.number().int().min(1).max(10).default(2),autopilot:ae.boolean().default(!1)}),wt={enabled:!1,backend:"api",model:"claude-opus-4-7",maxTagsPerSession:4,minTagsPerSession:2,autopilot:!1};function ma(){let e=ua();if(!aa(e))return{};try{return JSON.parse(ca(e,"utf8"))}catch(t){return console.error("[auto-tag-config] failed to parse config.json, using defaults:",t),{}}}function Rt(){let e=ma().autoTag;if(!e)return{...wt};let t=pa.safeParse({...wt,...e});return t.success?t.data:{...wt}}Nt();x();Ue();We();import{z as P}from"zod";x();v();import{writeFileSync as Oa,mkdirSync as Ia,existsSync as va}from"node:fs";import{join as os}from"node:path";var Lt=os(y,"notes");function as(e){try{let t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return[]}function Ca(e){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t.filter(n=>!!n&&typeof n=="object"&&typeof n.synopsis=="string"&&typeof n.replaced_at=="string"):[]}catch{return[]}}function Da(){I(),va(Lt)||Ia(Lt,{recursive:!0})}function Ma(e){return{session_id:e.session_id,content:e.content,updated_at:e.updated_at,previous_versions:as(e.previous_versions),auto_synopsis:e.auto_synopsis??null,auto_synopsis_generated_at:e.auto_synopsis_generated_at??null,auto_synopsis_history:Ca(e.auto_synopsis_history)}}var Pa="session_id, content, updated_at, previous_versions, auto_synopsis, auto_synopsis_generated_at, auto_synopsis_history";function kt(e){let t=E().prepare(`SELECT ${Pa} FROM session_notes WHERE session_id = ?`).get(e);return t?Ma(t):null}function cs(e,t){let n=E(),s=new Date().toISOString(),r=n.prepare("SELECT content, previous_versions FROM session_notes WHERE session_id = ?").get(e),i=[];return r&&(i=as(r.previous_versions),r.content!==t&&r.content.length>0&&i.push({content:r.content,replaced_at:s})),n.prepare(`INSERT INTO session_notes (session_id, content, updated_at, previous_versions)
910
+ `),t.trim()}function la(e){return e.role??e.type??"message"}function es(e,t,n={}){let s=n.mode??"condensed",r=n.includeSidechain===!0,o=n.since?Date.parse(n.since):0,i=t.filter(d=>!(!r&&d.is_sidechain===1||o&&d.timestamp&&Date.parse(d.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 c=0,l=0;for(let d of i){let p=d.content_text??"",u=aa(p);s==="condensed"&&(u=ca(u));let g=u.length>0,h=!!d.tool_names&&d.tool_names.length>0;if(!g&&!h){l+=1;continue}let E=la(d),S=d.timestamp?` \`${d.timestamp}\``:"";a.push(`## ${E}${S}`),a.push(""),h&&s==="condensed"&&(a.push(`_tools used: ${d.tool_names}_`),a.push("")),g&&(a.push(u),a.push("")),c+=1}return a.push("---"),a.push(""),a.push(`_${c} messages included_`+(l?`, ${l} empty skipped`:"")+(r?"":", subagent/sidechain hidden")+"."),a.join(`
911
+ `)}Ue();yt();import{existsSync as ga,mkdirSync as Sm,readFileSync as fa,writeFileSync as bm,chmodSync as Tm}from"node:fs";import{homedir as _a}from"node:os";import{join as rs}from"node:path";import{z as ae}from"zod";function ha(){return process.env.RECALL_HOME??rs(_a(),".recall")}function Ea(){return rs(ha(),"config.json")}var Sa=ae.object({enabled:ae.boolean().default(!1),backend:ae.enum(["api","mcp"]).default("api"),apiKey:ae.string().optional(),model:ae.string().default("claude-opus-4-7"),maxTagsPerSession:ae.number().int().min(1).max(10).default(4),minTagsPerSession:ae.number().int().min(1).max(10).default(2),autopilot:ae.boolean().default(!1)}),wt={enabled:!1,backend:"api",model:"claude-opus-4-7",maxTagsPerSession:4,minTagsPerSession:2,autopilot:!1};function ba(){let e=Ea();if(!ga(e))return{};try{return JSON.parse(fa(e,"utf8"))}catch(t){return console.error("[auto-tag-config] failed to parse config.json, using defaults:",t),{}}}function Rt(){let e=ba().autoTag;if(!e)return{...wt};let t=Sa.safeParse({...wt,...e});return t.success?t.data:{...wt}}Nt();x();Ue();Be();import{z as $}from"zod";x();v();import{writeFileSync as Fa,mkdirSync as $a,existsSync as Ua}from"node:fs";import{join as as}from"node:path";var Lt=as(A,"notes");function cs(e){try{let t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return[]}function ja(e){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t.filter(n=>!!n&&typeof n=="object"&&typeof n.synopsis=="string"&&typeof n.replaced_at=="string"):[]}catch{return[]}}function Ha(){I(),Ua(Lt)||$a(Lt,{recursive:!0})}function Ba(e){return{session_id:e.session_id,content:e.content,updated_at:e.updated_at,previous_versions:cs(e.previous_versions),auto_synopsis:e.auto_synopsis??null,auto_synopsis_generated_at:e.auto_synopsis_generated_at??null,auto_synopsis_history:ja(e.auto_synopsis_history)}}var Wa="session_id, content, updated_at, previous_versions, auto_synopsis, auto_synopsis_generated_at, auto_synopsis_history";function kt(e){let t=_().prepare(`SELECT ${Wa} FROM session_notes WHERE session_id = ?`).get(e);return t?Ba(t):null}function ls(e,t){let n=_(),s=new Date().toISOString(),r=n.prepare("SELECT content, previous_versions FROM session_notes WHERE session_id = ?").get(e),o=[];return r&&(o=cs(r.previous_versions),r.content!==t&&r.content.length>0&&o.push({content:r.content,replaced_at:s})),n.prepare(`INSERT INTO session_notes (session_id, content, updated_at, previous_versions)
907
912
  VALUES (?, ?, ?, ?)
908
913
  ON CONFLICT(session_id) DO UPDATE SET
909
914
  content = excluded.content,
910
915
  updated_at = excluded.updated_at,
911
- previous_versions = excluded.previous_versions`).run(e,t,s,JSON.stringify(i)),Fa(e,t,s),kt(e)??{session_id:e,content:t,updated_at:s,previous_versions:i,auto_synopsis:null,auto_synopsis_generated_at:null,auto_synopsis_history:[]}}function Fa(e,t,n){try{Da();let s=os(Lt,`${e}.md`),r=`<!-- Claude Recall note \xB7 session ${e} \xB7 updated ${n} -->
912
- `;Oa(s,r+t)}catch(s){console.error("[notes] mirror write failed:",s)}}Ct();x();var Mt=60,za=6e4,he=class extends Error{retryAfterMs;constructor(t){super(`MCP write rate limit exceeded \u2014 try again in ${Math.ceil(t/1e3)}s`),this.name="RateLimitError",this.retryAfterMs=t}};function Dt(e){let t=new Date().toISOString(),n;try{n=JSON.stringify(e.args??null)}catch{n='"<unserializable>"'}E().prepare(`INSERT INTO mcp_audit_events (tool, args_json, result, error_message, caller, at)
913
- VALUES (?, ?, ?, ?, ?, ?)`).run(e.tool,n,e.result,e.errorMessage??null,e.caller??null,t)}var ce=class{capacity;windowMs;hits=[];constructor(t=Mt,n=za){this.capacity=t,this.windowMs=n}consume(t=Date.now()){if(this.evict(t),this.hits.length>=this.capacity){let n=this.hits[0],s=Math.max(1,n+this.windowMs-t);throw new he(s)}this.hits.push(t)}remaining(t=Date.now()){return this.evict(t),Math.max(0,this.capacity-this.hits.length)}reset(){this.hits.length=0}evict(t){let n=t-this.windowMs;for(;this.hits.length>0&&this.hits[0]<n;)this.hits.shift()}};async function D(e){try{e.limiter.consume()}catch(t){throw t instanceof he&&Dt({tool:e.tool,args:e.args,result:"rate_limited",errorMessage:t.message,caller:e.caller}),t}try{let t=await e.run();return Dt({tool:e.tool,args:e.args,result:"ok",caller:e.caller}),t}catch(t){let n=t instanceof Error?t.message:String(t);throw Dt({tool:e.tool,args:e.args,result:"error",errorMessage:n,caller:e.caller}),t}}x();import{z as Ya}from"zod";function z(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}function Be(e){return{content:[{type:"text",text:e}],isError:!0}}function C(e){return e instanceof he?Be(e.message):e instanceof Ya.ZodError?Be(`invalid input: ${e.message}`):e instanceof Error&&e.message.startsWith("SQLITE_")?Be("database constraint error"):Be(e instanceof Error?e.message:String(e))}function me(e){return{content:[{type:"text",text:JSON.stringify(e,null,2)}]}}function le(e){return{content:[{type:"text",text:e}],isError:!0}}var Ka=`
916
+ previous_versions = excluded.previous_versions`).run(e,t,s,JSON.stringify(o)),Xa(e,t,s),kt(e)??{session_id:e,content:t,updated_at:s,previous_versions:o,auto_synopsis:null,auto_synopsis_generated_at:null,auto_synopsis_history:[]}}function Xa(e,t,n){try{Ha();let s=as(Lt,`${e}.md`),r=`<!-- Claude Recall note \xB7 session ${e} \xB7 updated ${n} -->
917
+ `;Fa(s,r+t)}catch(s){console.error("[notes] mirror write failed:",s)}}Ct();x();var Mt=60,Za=6e4,he=class extends Error{retryAfterMs;constructor(t){super(`MCP write rate limit exceeded \u2014 try again in ${Math.ceil(t/1e3)}s`),this.name="RateLimitError",this.retryAfterMs=t}};function Dt(e){let t=new Date().toISOString(),n;try{n=JSON.stringify(e.args??null)}catch{n='"<unserializable>"'}_().prepare(`INSERT INTO mcp_audit_events (tool, args_json, result, error_message, caller, at)
918
+ VALUES (?, ?, ?, ?, ?, ?)`).run(e.tool,n,e.result,e.errorMessage??null,e.caller??null,t)}var ce=class{capacity;windowMs;hits=[];constructor(t=Mt,n=Za){this.capacity=t,this.windowMs=n}consume(t=Date.now()){if(this.evict(t),this.hits.length>=this.capacity){let n=this.hits[0],s=Math.max(1,n+this.windowMs-t);throw new he(s)}this.hits.push(t)}remaining(t=Date.now()){return this.evict(t),Math.max(0,this.capacity-this.hits.length)}reset(){this.hits.length=0}evict(t){let n=t-this.windowMs;for(;this.hits.length>0&&this.hits[0]<n;)this.hits.shift()}};async function D(e){try{e.limiter.consume()}catch(t){throw t instanceof he&&Dt({tool:e.tool,args:e.args,result:"rate_limited",errorMessage:t.message,caller:e.caller}),t}try{let t=await e.run();return Dt({tool:e.tool,args:e.args,result:"ok",caller:e.caller}),t}catch(t){let n=t instanceof Error?t.message:String(t);throw Dt({tool:e.tool,args:e.args,result:"error",errorMessage:n,caller:e.caller}),t}}x();import{z as ec}from"zod";function K(e){let t=e.trim();if(t.length<4)return null;let n=_();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}function We(e){return{content:[{type:"text",text:e}],isError:!0}}function C(e){return e instanceof he?We(e.message):e instanceof ec.ZodError?We(`invalid input: ${e.message}`):e instanceof Error&&e.message.startsWith("SQLITE_")?We("database constraint error"):We(e instanceof Error?e.message:String(e))}function ge(e){return{content:[{type:"text",text:JSON.stringify(e,null,2)}]}}function le(e){return{content:[{type:"text",text:e}],isError:!0}}var tc=`
914
919
 
915
920
  ---
916
921
 
917
- `,Ja=5e5;function ps(e,t={}){let n=t.limiter??new ce;e.registerTool("add_tag",{title:"Add tag to a session",description:"Apply a single tag to a session. Tags are normalized server-side (lowercase, hyphens, strip #). Idempotent.",inputSchema:{sessionId:P.string().describe("Full session UUID or 8+-character prefix."),tag:P.string().min(1).describe("Tag to add. Normalized: lowercase, dashes, max 40 chars.")}},async s=>{try{let r=z(s.sessionId);if(!r)return le(`session not found or prefix ambiguous: ${s.sessionId}`);let i=await D({tool:"add_tag",args:{sessionId:r,tag:s.tag},limiter:n,run:()=>Fe(r,s.tag)});return me({sessionId:r,...i})}catch(r){return C(r)}}),e.registerTool("remove_tag",{title:"Remove tag from a session",description:"Remove a single tag from a session. The removal is recorded in tag_events (append-only) so history is preserved.",inputSchema:{sessionId:P.string().describe("Full session UUID or 8+-character prefix."),tag:P.string().min(1).describe("Tag to remove (normalized server-side).")}},async s=>{try{let r=z(s.sessionId);if(!r)return le(`session not found or prefix ambiguous: ${s.sessionId}`);let i=pe(s.tag);if(!i)return le("tag must contain at least one alphanumeric character");let o=await D({tool:"remove_tag",args:{sessionId:r,tag:i},limiter:n,run:()=>es(r,i)});return me({sessionId:r,...o})}catch(r){return C(r)}}),e.registerTool("set_alias",{title:"Set session alias",description:"Set a human-friendly alias for a session. Previous alias is archived to previous_aliases (never destroyed). Session UUID remains the immutable primary key.",inputSchema:{sessionId:P.string().describe("Full session UUID or 8+-character prefix."),alias:P.string().min(1).max(120).describe("New alias (non-empty, max 120 chars).")}},async s=>{try{let r=z(s.sessionId);if(!r)return le(`session not found or prefix ambiguous: ${s.sessionId}`);let i=await D({tool:"set_alias",args:{sessionId:r,alias:s.alias},limiter:n,run:()=>He(r,s.alias)});return me(i)}catch(r){return C(r)}}),e.registerTool("append_note",{title:"Append to session note",description:"Append markdown to a session note. If a note already exists, the new content is added below a `---` separator. Previous version is archived in previous_versions.",inputSchema:{sessionId:P.string().describe("Full session UUID or 8+-character prefix."),markdown:P.string().min(1).max(5e4).describe("Markdown to append.")}},async s=>{try{let r=z(s.sessionId);if(!r)return le(`session not found or prefix ambiguous: ${s.sessionId}`);let i=await D({tool:"append_note",args:{sessionId:r,length:s.markdown.length},limiter:n,run:()=>{let o=kt(r),a=o&&o.content.length>0?`${o.content}${Ka}${s.markdown}`:s.markdown;if(a.length>Ja)throw new Error(`note would exceed the 500 KB cumulative limit (current: ${o?.content.length??0} bytes, adding: ${s.markdown.length} bytes)`);return cs(r,a)}});return me(i)}catch(r){return C(r)}}),e.registerTool("create_collection",{title:"Create a collection",description:"Create a new collection for grouping sessions. Optionally nest under a parent. Soft-deletion only.",inputSchema:{name:P.string().min(1).max(120),parent_id:P.string().optional().describe("Parent collection id (omit for root)."),icon:P.string().max(32).optional(),color:P.string().max(32).optional(),description:P.string().max(2e3).optional()}},async s=>{try{let r=await D({tool:"create_collection",args:s,limiter:n,run:()=>Ot({name:s.name,parent_id:s.parent_id??null,icon:s.icon??null,color:s.color??null,description:s.description??null})});return me(r)}catch(r){return C(r)}}),e.registerTool("add_session_to_collection",{title:"Add session to collection",description:"Add a session to a collection. Idempotent: re-adding returns added=false.",inputSchema:{collectionId:P.string().min(1),sessionId:P.string().describe("Full session UUID or 8+-character prefix."),note:P.string().max(2e3).optional()}},async s=>{try{let r=z(s.sessionId);if(!r)return le(`session not found or prefix ambiguous: ${s.sessionId}`);if(!E().prepare("SELECT 1 FROM collections WHERE id = ?").get(s.collectionId))return le("collection not found");let a=await D({tool:"add_session_to_collection",args:{collectionId:s.collectionId,sessionId:r,note:s.note??null},limiter:n,run:()=>It(s.collectionId,r,s.note??null)});return me({collectionId:s.collectionId,sessionId:r,...a})}catch(r){return C(r)}}),e.registerTool("remove_session_from_collection",{title:"Remove session from collection",description:"Remove a session from a collection. The removal is recorded in collection_events (append-only); the underlying session is untouched.",inputSchema:{collectionId:P.string().min(1),sessionId:P.string().describe("Full session UUID or 8+-character prefix.")}},async s=>{try{let r=z(s.sessionId);if(!r)return le(`session not found or prefix ambiguous: ${s.sessionId}`);let i=await D({tool:"remove_session_from_collection",args:{collectionId:s.collectionId,sessionId:r},limiter:n,run:()=>us(s.collectionId,r)});return me({collectionId:s.collectionId,sessionId:r,...i})}catch(r){return C(r)}})}import{z as B}from"zod";x();v();import{randomUUID as ms}from"node:crypto";import{writeFileSync as gs,readFileSync as qm,existsSync as Va,mkdirSync as qa}from"node:fs";import{join as Pt}from"node:path";var Xe=Pt(y,"threads"),Qa=Pt(Xe,"index.json");function fs(){I(),Va(Xe)||qa(Xe,{recursive:!0})}function Ft(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 _s(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,
922
+ `,nc=5e5;function ms(e,t={}){let n=t.limiter??new ce;e.registerTool("add_tag",{title:"Add tag to a session",description:"Apply a single tag to a session. Tags are normalized server-side (lowercase, hyphens, strip #). Idempotent.",inputSchema:{sessionId:$.string().describe("Full session UUID or 8+-character prefix."),tag:$.string().min(1).describe("Tag to add. Normalized: lowercase, dashes, max 40 chars.")}},async s=>{try{let r=K(s.sessionId);if(!r)return le(`session not found or prefix ambiguous: ${s.sessionId}`);let o=await D({tool:"add_tag",args:{sessionId:r,tag:s.tag},limiter:n,run:()=>Fe(r,s.tag)});return ge({sessionId:r,...o})}catch(r){return C(r)}}),e.registerTool("remove_tag",{title:"Remove tag from a session",description:"Remove a single tag from a session. The removal is recorded in tag_events (append-only) so history is preserved.",inputSchema:{sessionId:$.string().describe("Full session UUID or 8+-character prefix."),tag:$.string().min(1).describe("Tag to remove (normalized server-side).")}},async s=>{try{let r=K(s.sessionId);if(!r)return le(`session not found or prefix ambiguous: ${s.sessionId}`);let o=me(s.tag);if(!o)return le("tag must contain at least one alphanumeric character");let i=await D({tool:"remove_tag",args:{sessionId:r,tag:o},limiter:n,run:()=>ts(r,o)});return ge({sessionId:r,...i})}catch(r){return C(r)}}),e.registerTool("set_alias",{title:"Set session alias",description:"Set a human-friendly alias for a session. Previous alias is archived to previous_aliases (never destroyed). Session UUID remains the immutable primary key.",inputSchema:{sessionId:$.string().describe("Full session UUID or 8+-character prefix."),alias:$.string().min(1).max(120).describe("New alias (non-empty, max 120 chars).")}},async s=>{try{let r=K(s.sessionId);if(!r)return le(`session not found or prefix ambiguous: ${s.sessionId}`);let o=await D({tool:"set_alias",args:{sessionId:r,alias:s.alias},limiter:n,run:()=>He(r,s.alias)});return ge(o)}catch(r){return C(r)}}),e.registerTool("append_note",{title:"Append to session note",description:"Append markdown to a session note. If a note already exists, the new content is added below a `---` separator. Previous version is archived in previous_versions.",inputSchema:{sessionId:$.string().describe("Full session UUID or 8+-character prefix."),markdown:$.string().min(1).max(5e4).describe("Markdown to append.")}},async s=>{try{let r=K(s.sessionId);if(!r)return le(`session not found or prefix ambiguous: ${s.sessionId}`);let o=await D({tool:"append_note",args:{sessionId:r,length:s.markdown.length},limiter:n,run:()=>{let i=kt(r),a=i&&i.content.length>0?`${i.content}${tc}${s.markdown}`:s.markdown;if(a.length>nc)throw new Error(`note would exceed the 500 KB cumulative limit (current: ${i?.content.length??0} bytes, adding: ${s.markdown.length} bytes)`);return ls(r,a)}});return ge(o)}catch(r){return C(r)}}),e.registerTool("create_collection",{title:"Create a collection",description:"Create a new collection for grouping sessions. Optionally nest under a parent. Soft-deletion only.",inputSchema:{name:$.string().min(1).max(120),parent_id:$.string().optional().describe("Parent collection id (omit for root)."),icon:$.string().max(32).optional(),color:$.string().max(32).optional(),description:$.string().max(2e3).optional()}},async s=>{try{let r=await D({tool:"create_collection",args:s,limiter:n,run:()=>Ot({name:s.name,parent_id:s.parent_id??null,icon:s.icon??null,color:s.color??null,description:s.description??null})});return ge(r)}catch(r){return C(r)}}),e.registerTool("add_session_to_collection",{title:"Add session to collection",description:"Add a session to a collection. Idempotent: re-adding returns added=false.",inputSchema:{collectionId:$.string().min(1),sessionId:$.string().describe("Full session UUID or 8+-character prefix."),note:$.string().max(2e3).optional()}},async s=>{try{let r=K(s.sessionId);if(!r)return le(`session not found or prefix ambiguous: ${s.sessionId}`);if(!_().prepare("SELECT 1 FROM collections WHERE id = ?").get(s.collectionId))return le("collection not found");let a=await D({tool:"add_session_to_collection",args:{collectionId:s.collectionId,sessionId:r,note:s.note??null},limiter:n,run:()=>It(s.collectionId,r,s.note??null)});return ge({collectionId:s.collectionId,sessionId:r,...a})}catch(r){return C(r)}}),e.registerTool("remove_session_from_collection",{title:"Remove session from collection",description:"Remove a session from a collection. The removal is recorded in collection_events (append-only); the underlying session is untouched.",inputSchema:{collectionId:$.string().min(1),sessionId:$.string().describe("Full session UUID or 8+-character prefix.")}},async s=>{try{let r=K(s.sessionId);if(!r)return le(`session not found or prefix ambiguous: ${s.sessionId}`);let o=await D({tool:"remove_session_from_collection",args:{collectionId:s.collectionId,sessionId:r},limiter:n,run:()=>ps(s.collectionId,r)});return ge({collectionId:s.collectionId,sessionId:r,...o})}catch(r){return C(r)}})}import{z as G}from"zod";x();v();import{randomUUID as gs}from"node:crypto";import{writeFileSync as fs,readFileSync as lg,existsSync as sc,mkdirSync as rc}from"node:fs";import{join as Pt}from"node:path";var Xe=Pt(A,"threads"),oc=Pt(Xe,"index.json");function _s(){I(),sc(Xe)||rc(Xe,{recursive:!0})}function Ft(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 hs(e){let t=new Map;if(e.length===0)return t;let n=_(),s=e.map(()=>"?").join(","),r=n.prepare(`SELECT te.thread_id AS thread_id,
918
923
  p.name AS project,
919
924
  COUNT(*) AS n,
920
925
  SUM(CASE WHEN te.role = 'origin' THEN 1 ELSE 0 END) AS origin_n
@@ -922,7 +927,7 @@ ${m+1}. ${p}`:`${m+1}. ${p}`}).join(`
922
927
  LEFT JOIN sessions s ON s.id = te.session_id
923
928
  LEFT JOIN projects p ON p.id = s.project_id
924
929
  WHERE te.thread_id IN (${s})
925
- GROUP BY te.thread_id, p.name`).all(...e),i=new Map;for(let o of r){let a=i.get(o.thread_id);a||(a=[],i.set(o.thread_id,a)),a.push(o)}for(let[o,a]of i){let c=a.filter(m=>m.project!==null),l=c.length,d=null;c.length>0&&(d=[...c].sort((p,g)=>g.n-p.n||g.origin_n-p.origin_n||(p.project??"").localeCompare(g.project??""))[0].project),t.set(o,{project:d,project_count:l})}return t}function hs(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 Es(e){let n=E().prepare(`SELECT NULLIF(sa.alias, '') AS alias,
930
+ 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 c=a.filter(p=>p.project!==null),l=c.length,d=null;c.length>0&&(d=[...c].sort((u,g)=>g.n-u.n||g.origin_n-u.origin_n||(u.project??"").localeCompare(g.project??""))[0].project),t.set(i,{project:d,project_count:l})}return t}function Es(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 Ss(e){let n=_().prepare(`SELECT NULLIF(sa.alias, '') AS alias,
926
931
  s.auto_title AS auto_title,
927
932
  s.auto_title_source AS auto_title_source,
928
933
  s.first_user_message AS first_user_message,
@@ -930,11 +935,11 @@ ${m+1}. ${p}`:`${m+1}. ${p}`}).join(`
930
935
  FROM (SELECT ? AS sid) q
931
936
  LEFT JOIN sessions s ON s.id = q.sid
932
937
  LEFT JOIN session_aliases sa ON sa.session_id = q.sid
933
- 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 $t(e){let n=E().prepare(`SELECT
938
+ 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 $t(e){let n=_().prepare(`SELECT
934
939
  COUNT(*) AS session_count,
935
940
  SUM(CASE WHEN role = 'origin' THEN 1 ELSE 0 END) AS origin_count
936
- FROM thread_edges WHERE thread_id = ?`).get(e);return{session_count:n?.session_count??0,origin_count:n?.origin_count??0}}function V(e){let t=$(e);t&&(fs(),gs(Pt(Xe,`${e}.json`),JSON.stringify(t,null,2)),Ss())}function Ss(){fs();let e=Ut({includeArchived:!0});gs(Qa,JSON.stringify({threads:e},null,2))}function Ge(e){let t=e.name.trim();if(!t)throw new Error("thread name cannot be empty");let n=E(),s=ms(),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)
937
- VALUES (?, ?, NULL, 'origin', 1.0, 'manual', ?)`).run(s,e.originSessionId,r),V(s);let i=$(s);if(!i)throw new Error("thread creation succeeded but read-back failed");return i}function Ut(e={}){let t=E(),n=e.includeArchived?"":"WHERE archived = 0",s=t.prepare(`SELECT * FROM threads ${n} ORDER BY created_at DESC`).all(),r=_s(s.map(i=>i.id));return s.map(i=>Ft(i,$t(i.id),r.get(i.id)))}function $(e){let t=E(),n=t.prepare("SELECT * FROM threads WHERE id = ?").get(e);if(!n)return null;let s=t.prepare(`SELECT e.*,
941
+ FROM thread_edges WHERE thread_id = ?`).get(e);return{session_count:n?.session_count??0,origin_count:n?.origin_count??0}}function q(e){let t=j(e);t&&(_s(),fs(Pt(Xe,`${e}.json`),JSON.stringify(t,null,2)),bs())}function bs(){_s();let e=Ut({includeArchived:!0});fs(oc,JSON.stringify({threads:e},null,2))}function Ge(e){let t=e.name.trim();if(!t)throw new Error("thread name cannot be empty");let n=_(),s=gs(),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)
942
+ VALUES (?, ?, NULL, 'origin', 1.0, 'manual', ?)`).run(s,e.originSessionId,r),q(s);let o=j(s);if(!o)throw new Error("thread creation succeeded but read-back failed");return o}function Ut(e={}){let t=_(),n=e.includeArchived?"":"WHERE archived = 0",s=t.prepare(`SELECT * FROM threads ${n} ORDER BY created_at DESC`).all(),r=hs(s.map(o=>o.id));return s.map(o=>Ft(o,$t(o.id),r.get(o.id)))}function j(e){let t=_(),n=t.prepare("SELECT * FROM threads WHERE id = ?").get(e);if(!n)return null;let s=t.prepare(`SELECT e.*,
938
943
  NULLIF(sa.alias, '') AS alias,
939
944
  s.auto_title AS auto_title,
940
945
  s.auto_title_source AS auto_title_source,
@@ -945,10 +950,10 @@ ${m+1}. ${p}`:`${m+1}. ${p}`}).join(`
945
950
  LEFT JOIN session_aliases sa ON sa.session_id = e.session_id
946
951
  LEFT JOIN projects p ON p.id = s.project_id
947
952
  WHERE e.thread_id = ?
948
- ORDER BY e.added_at ASC`).all(e).map(hs),r=_s([e]).get(e);return{...Ft(n,$t(n.id),r),edges:s}}function Ts(e){return E().prepare(`SELECT t.* FROM threads t
953
+ ORDER BY e.added_at ASC`).all(e).map(Es),r=hs([e]).get(e);return{...Ft(n,$t(n.id),r),edges:s}}function Ts(e){return _().prepare(`SELECT t.* FROM threads t
949
954
  JOIN thread_edges e ON e.thread_id = t.id
950
955
  WHERE e.session_id = ? AND t.archived = 0
951
- ORDER BY t.created_at DESC`).all(e).map(s=>Ft(s,$t(s.id)))}function ze(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,i=e.role??(r?"child":"origin"),o=e.confidence??1,a=e.source??"manual";if(o<0||o>1)throw new Error("confidence must be 0..1");t.prepare(`INSERT INTO thread_edges
956
+ ORDER BY t.created_at DESC`).all(e).map(s=>Ft(s,$t(s.id)))}function ze(e){let t=_();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
952
957
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
953
958
  VALUES (?, ?, ?, ?, ?, ?, ?)
954
959
  ON CONFLICT(thread_id, session_id) DO UPDATE SET
@@ -956,35 +961,35 @@ ${m+1}. ${p}`:`${m+1}. ${p}`}).join(`
956
961
  role = excluded.role,
957
962
  confidence = excluded.confidence,
958
963
  source = excluded.source,
959
- added_at = excluded.added_at`).run(e.threadId,e.sessionId,r,i,o,a,s),V(e.threadId);let c=Es(e.sessionId);return{thread_id:e.threadId,session_id:e.sessionId,parent_session_id:r,role:i,confidence:o,source:a,added_at:s,alias:c.alias,auto_title:c.auto_title,auto_title_source:c.auto_title_source,alias_source:c.alias?"manual":null,first_user_message:c.first_user_message,project:c.project}}function bs(e,t){let s=E().prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e,t);return s.changes>0&&V(e),{removed:s.changes}}function Re(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 = ?"),c=n,l=new Set;for(;c!==null;){if(c===t)throw new Error(`cycle detected: setting parent of ${t} to ${n} would create a loop`);if(l.has(c))break;l.add(c),c=a.get(e,c)?.parent_session_id??null}}let i=n?"child":"origin";s.prepare(`UPDATE thread_edges
964
+ added_at = excluded.added_at`).run(e.threadId,e.sessionId,r,o,i,a,s),q(e.threadId);let c=Ss(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:c.alias,auto_title:c.auto_title,auto_title_source:c.auto_title_source,alias_source:c.alias?"manual":null,first_user_message:c.first_user_message,project:c.project}}function ys(e,t){let s=_().prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e,t);return s.changes>0&&q(e),{removed:s.changes}}function Re(e,t,n){let s=_(),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 = ?"),c=n,l=new Set;for(;c!==null;){if(c===t)throw new Error(`cycle detected: setting parent of ${t} to ${n} would create a loop`);if(l.has(c))break;l.add(c),c=a.get(e,c)?.parent_session_id??null}}let o=n?"child":"origin";s.prepare(`UPDATE thread_edges
960
965
  SET parent_session_id = ?, role = ?, added_at = ?
961
- WHERE thread_id = ? AND session_id = ?`).run(n,i,new Date().toISOString(),e,t),V(e);let o=Es(t);return hs({...r,parent_session_id:n,role:i,added_at:new Date().toISOString(),alias:o.alias,auto_title:o.auto_title,auto_title_source:o.auto_title_source,first_user_message:o.first_user_message,project:o.project})}function ys(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),V(e);let r=$(e);if(!r)throw new Error(`thread ${e} not found`);return r}function ws(e){E().prepare("UPDATE threads SET closed_at = ? WHERE id = ?").run(new Date().toISOString(),e),V(e);let n=$(e);if(!n)throw new Error(`thread ${e} not found`);return n}function Rs(e){E().prepare("UPDATE threads SET closed_at = NULL WHERE id = ?").run(e),V(e);let n=$(e);if(!n)throw new Error(`thread ${e} not found`);return n}function As(e){E().prepare("UPDATE threads SET archived = 1 WHERE id = ?").run(e),V(e);let n=$(e);if(!n)throw new Error(`thread ${e} not found`);return n}function Ns(e,t){if(e===t)throw new Error("cannot merge a thread into itself");let n=E(),s=new Date().toISOString();n.transaction(()=>{let i=n.prepare("SELECT * FROM thread_edges WHERE thread_id = ?").all(e);for(let o of i)n.prepare(`INSERT INTO thread_edges
966
+ WHERE thread_id = ? AND session_id = ?`).run(n,o,new Date().toISOString(),e,t),q(e);let i=Ss(t);return Es({...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 ws(e,t){let n=t.trim();if(!n)throw new Error("name cannot be empty");_().prepare("UPDATE threads SET name = ? WHERE id = ?").run(n,e),q(e);let r=j(e);if(!r)throw new Error(`thread ${e} not found`);return r}function Rs(e){_().prepare("UPDATE threads SET closed_at = ? WHERE id = ?").run(new Date().toISOString(),e),q(e);let n=j(e);if(!n)throw new Error(`thread ${e} not found`);return n}function As(e){_().prepare("UPDATE threads SET closed_at = NULL WHERE id = ?").run(e),q(e);let n=j(e);if(!n)throw new Error(`thread ${e} not found`);return n}function Ns(e){_().prepare("UPDATE threads SET archived = 1 WHERE id = ?").run(e),q(e);let n=j(e);if(!n)throw new Error(`thread ${e} not found`);return n}function Ls(e,t){if(e===t)throw new Error("cannot merge a thread into itself");let n=_(),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
962
967
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
963
968
  VALUES (?, ?, ?, ?, ?, ?, ?)
964
969
  ON CONFLICT(thread_id, session_id) DO UPDATE SET
965
970
  parent_session_id = COALESCE(thread_edges.parent_session_id, excluded.parent_session_id),
966
971
  role = CASE WHEN thread_edges.role = 'origin' OR excluded.role = 'origin' THEN 'origin' ELSE 'child' END,
967
972
  confidence = MAX(thread_edges.confidence, excluded.confidence),
968
- source = thread_edges.source`).run(t,o.session_id,o.parent_session_id,o.role,o.confidence,o.source,s);n.prepare("DELETE FROM threads WHERE id = ?").run(e)})(),V(t),Ss();let r=$(t);if(!r)throw new Error("merge destination disappeared");return r}function Ls(e){if(e.sessionIds.length===0)throw new Error("no sessions to split off");let t=E(),n=new Date().toISOString(),s=ms();t.transaction(()=>{t.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, NULL, ?)").run(s,e.newThreadName.trim(),n);for(let i of e.sessionIds){let o=t.prepare("SELECT * FROM thread_edges WHERE thread_id = ? AND session_id = ?").get(e.threadId,i);o&&(t.prepare(`INSERT INTO thread_edges
973
+ 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)})(),q(t),bs();let r=j(t);if(!r)throw new Error("merge destination disappeared");return r}function ks(e){if(e.sessionIds.length===0)throw new Error("no sessions to split off");let t=_(),n=new Date().toISOString(),s=gs();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
969
974
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
970
- VALUES (?, ?, ?, ?, ?, ?, ?)`).run(s,i,o.parent_session_id,o.role,o.confidence,o.source,n),t.prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e.threadId,i))}})(),V(e.threadId),V(s);let r=$(s);if(!r)throw new Error("split destination disappeared");return r}Xt();var yc=50;function wc(e){if(e.length===0)return[];let t=[...e].sort((c,l)=>c.added_at<l.added_at?-1:c.added_at>l.added_at?1:0),n=new Map,s=new Set,r=[];for(let c of t)if(c.parent_session_id){let l=n.get(c.parent_session_id)??[];l.push(c),n.set(c.parent_session_id,l)}let i=t.filter(c=>c.role==="origin"),a=[...i.length>0?i:t.filter(c=>!c.parent_session_id)];for(;a.length>0;){let c=a.shift();if(s.has(c.session_id))continue;s.add(c.session_id),r.push(c.session_id);let l=n.get(c.session_id)??[];for(let d of l)s.has(d.session_id)||a.push(d)}for(let c of t)s.has(c.session_id)||(s.add(c.session_id),r.push(c.session_id));return r}function Rc(e){let t=Ms(e.sessionId),n=["",`BULK CONTEXT: You are titling session ${e.current} of ${e.total} in this thread.`,"The parent and earlier siblings already have titles (shown above). YOUR JOB:","",'1. Identify the naming pattern. If parent is "Build Feature X" and earlier',' siblings are "Phase A: API design" and "Phase B: client wiring", the pattern',' is "Phase {LETTER}: {topic}".',"2. If no pattern is yet established (this is the first child), INVENT a pattern",' that will scale to N children. Good patterns: "Phase A/B/C", "Wave 1 of M",',' "Step N", or a domain-specific structure if the thread name suggests one.',"3. Output a title that follows the pattern AND describes what THIS session"," does in 50 characters max.","","Output ONLY the title, no quotes, no trailing punctuation."].join(`
975
+ 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))}})(),q(e.threadId),q(s);let r=j(s);if(!r)throw new Error("split destination disappeared");return r}Xt();var xc=50;function Oc(e){if(e.length===0)return[];let t=[...e].sort((c,l)=>c.added_at<l.added_at?-1:c.added_at>l.added_at?1:0),n=new Map,s=new Set,r=[];for(let c of t)if(c.parent_session_id){let l=n.get(c.parent_session_id)??[];l.push(c),n.set(c.parent_session_id,l)}let o=t.filter(c=>c.role==="origin"),a=[...o.length>0?o:t.filter(c=>!c.parent_session_id)];for(;a.length>0;){let c=a.shift();if(s.has(c.session_id))continue;s.add(c.session_id),r.push(c.session_id);let l=n.get(c.session_id)??[];for(let d of l)s.has(d.session_id)||a.push(d)}for(let c of t)s.has(c.session_id)||(s.add(c.session_id),r.push(c.session_id));return r}function Ic(e){let t=Ps(e.sessionId),n=["",`BULK CONTEXT: You are titling session ${e.current} of ${e.total} in this thread.`,"The parent and earlier siblings already have titles (shown above). YOUR JOB:","",'1. Identify the naming pattern. If parent is "Build Feature X" and earlier',' siblings are "Phase A: API design" and "Phase B: client wiring", the pattern',' is "Phase {LETTER}: {topic}".',"2. If no pattern is yet established (this is the first child), INVENT a pattern",' that will scale to N children. Good patterns: "Phase A/B/C", "Wave 1 of M",',' "Step N", or a domain-specific structure if the thread name suggests one.',"3. Output a title that follows the pattern AND describes what THIS session"," does in 50 characters max.","","Output ONLY the title, no quotes, no trailing punctuation."].join(`
971
976
  `);return`${t}
972
- ${n}`}function Ac(e){return Ps(e)?.auto_title_source??null}async function Nc(e){let{spawnClaudePrompt:t,isClaudeCliAvailable:n}=await Promise.resolve().then(()=>(Gt(),Ys));if(!n())throw new Error("claude CLI not found on PATH");let s=await t(e.prompt,[],{model:e.model});if(!s.success)throw new Error(`claude CLI exited ${s.exitCode}: ${s.stderr.slice(-500)}`);let r=Lc(s.stdout);if(!r)throw new Error("claude CLI returned an empty title");return r.slice(0,yc)}function Lc(e){let t=e.trim();if(!t)return"";try{let n=JSON.parse(t);if(n&&typeof n=="object"){let s=n.result;if(typeof s=="string")return Ks(s)}}catch{}return Ks(t)}function Ks(e){return e.trim().replace(/^["'`]+|["'`]+$/g,"").replace(/\s+/g," ").replace(/[.!?]+$/g,"").trim()}async function Vs(e,t={}){let n=$(e);if(!n)throw new Error(`thread not found: ${e}`);let s=wc(n.edges),r=s.length,i=t.force??!1,o=t.signal,a=[],c=[],l=[];for(let d=0;d<s.length;d++){let m=s[d],p=d+1;if(o?.aborted){let h={sessionId:m,reason:"cancelled"};c.push(h),t.onSkipped?.(h);continue}if(!i&&Ac(m)==="agent"){let h={sessionId:m,reason:"already-titled"};c.push(h),t.onSkipped?.(h);continue}let g;try{if(Js)g=await Js({sessionId:m,current:p,total:r});else{let h=Rc({sessionId:m,current:p,total:r});g=await Nc({prompt:h,model:t.model})}}catch(h){let S=h instanceof Error?h.message:String(h??"unknown error"),u={sessionId:m,error:S};l.push(u),t.onFailed?.(u);continue}try{Bt(m,g,"agent")}catch(h){let S=h instanceof Error?h.message:String(h??"unknown error"),u={sessionId:m,error:`setAutoTitle failed: ${S}`};l.push(u),t.onFailed?.(u);continue}a.push(m),t.onProgress?.({current:p,total:r,sessionId:m,title:g})}return{generated:a,skipped:c,failed:l}}var Js=null;x();import{execFile as Wc}from"node:child_process";import{promisify as Bc}from"node:util";import{readlink as Xc,readFile as nr}from"node:fs/promises";import{platform as Je}from"node:os";import{readFileSync as kc,statSync as xc}from"node:fs";var Oc=200*1024*1024;var Yt=.5,Zs=Yt,Ic=[{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 qs(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 Cc(e,t){let n=t-e;if(n<0)return{weight:0,label:null};for(let s of Ic)if(n<=s.maxGapMs)return{weight:s.weight,label:s.label};return{weight:0,label:null}}function Dc(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 i=r.toLowerCase();for(let o of vc)if(i.includes(o))return{weight:t[s],matched:o,matchedIndex:s}}return{weight:0,matched:null,matchedIndex:-1}}function zt(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 Mc(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 i=zt(s,r);i>n&&(n=i)}return n}function Pc(e,t){let n=zt(e.mean_embedding,t.mean_embedding),s=zt(e.tail_pool,t.head_pool),r=Mc(e.sample_chunks,t.sample_chunks),i=0,o=null;if(n>i&&(i=n,o="mean"),s>i&&(i=s,o="asymmetric"),r>i&&(i=r,o="max_pool"),i<.65)return{weight:0,cosine:i,mode:null};if(i>=.85)return{weight:.3,cosine:i,mode:o};let a=(i-.65)/.2*.3;return{weight:Math.round(a*100)/100,cosine:i,mode:o}}function Fc(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 $c(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 Uc(e,t){let n=qs(e),s=qs(t);return n&&s&&n===s?{weight:.1,brand:n}:{weight:0,brand:null}}function Qs(e){return e.replace(/\s+/g," ").trim().toLowerCase()}function jc(e,t){let n=0,s=null,r=!1;if(e.authored_paths.size>0){let i=t.recent_user_messages.slice(0,3).join(`
973
- `).toLowerCase();for(let o of e.authored_paths){let a=o.toLowerCase();if(t.touched_files.has(o)||i.includes(a)){n+=.5,s=o;break}}}if(e.authored_content.length>0&&t.recent_user_messages[0]){let i=Qs(t.recent_user_messages[0]);if(i.length>=200)for(let o of e.authored_content){let a=Qs(o);if(a.length<200)continue;let c=Math.min(a.length,240),l=a.slice(0,c);if(i.includes(l)){n+=.4,r=!0;break}}}return{weight:Math.min(.6,n),pathMatch:s,contentMatch:r}}function Hc(e,t,n=Zs){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=Cc(s,t.started_at_ms),i=t.recent_user_messages.length>0?t.recent_user_messages:t.first_user_message?[t.first_user_message]:[],o=Dc(i),a=$c(e.touched_files,t.touched_files),c=Uc(e.auto_title,t.auto_title),l=Pc(e,t),d=Fc(e,t),m=jc(e,t),p=r.weight+o.weight+a.weight+c.weight+l.weight+d.weight+m.weight;if(p<n)return null;let g=[];if(r.label&&g.push(`temporal ${r.label} (+${r.weight})`),o.matched){let h=o.matchedIndex===0?"opening message":`message #${o.matchedIndex+1}`;g.push(`continuation phrase "${o.matched}" in ${h} (+${o.weight})`)}if(a.count>0&&g.push(`${a.count} file${a.count===1?"":"s"} overlap (+${a.weight.toFixed(1)})`),c.brand&&g.push(`shared brand "${c.brand}" (+${c.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)})`),d.same&&g.push(`same cluster (+${d.weight})`),m.weight>0){let h=[];m.pathMatch&&h.push(`opened authored path "${m.pathMatch.split("/").pop()}"`),m.contentMatch&&h.push("verbatim-paste of authored content"),g.push(`doc-authorship: ${h.join(" + ")} (+${m.weight.toFixed(2)})`)}return{parent_id:e.id,child_id:t.id,confidence:Math.min(1,p),signals:{temporal:r.weight,continuation:o.weight,file_overlap:a.weight,same_brand:c.weight,semantic:l.weight,cluster:d.weight,doc_authorship:m.weight},reasons:g}}function er(e,t=Zs){let n=[];for(let s=0;s<e.length;s++){let r=e[s],i=null;for(let o=0;o<s;o++){let a=e[o],c=Hc(a,r,t);c&&(!i||c.confidence>i.confidence)&&(i=c)}i&&n.push(i)}return n}function tr(e,t={}){let n=t.maxUserMessages??5,s=t.userMessageMaxLen??2e3,r=new Set,i=[],o=new Set,a=[],c;try{if(xc(e).size>Oc)return{touched_files:r,recent_user_messages:i,authored_paths:o,authored_content:a};c=kc(e,"utf8")}catch{return{touched_files:r,recent_user_messages:i,authored_paths:o,authored_content:a}}let l=0;for(;l<c.length;){let d=c.indexOf(`
974
- `,l),m=d===-1?c.length:d,p=c.slice(l,m);if(l=d===-1?c.length:d+1,!p.trim())continue;let g;try{g=JSON.parse(p)}catch{continue}let h=g;if(h.type==="user"&&h.message?.role==="user"&&typeof h.message.content=="string"&&i.length<n){let u=h.message.content.trim();u&&i.push(u.length>s?u.slice(0,s):u)}let S=h.message?.content;if(Array.isArray(S))for(let u of S){if(!u||typeof u!="object")continue;let f=u;if(f.type!=="tool_use")continue;let T=f.input??{},R=typeof T.file_path=="string"?T.file_path:null;if(R){let k=Ke(R);k&&r.add(k)}if((f.name==="Write"||f.name==="Edit"||f.name==="MultiEdit")&&R){let k=Ke(R);k&&o.add(k);let w=typeof T.content=="string"?T.content:typeof T.new_string=="string"?T.new_string:null;w&&w.length>=200&&a.push(w.length>4096?w.slice(0,4096):w)}if(f.name==="Bash"&&typeof T.command=="string")for(let k of T.command.matchAll(/(?:^|[\s'"`(=])((?:\.\.?\/|\/|src\/|test\/|docs\/|site\/)[A-Za-z0-9_./-]+)/g)){let w=Ke(k[1]);w&&r.add(w)}if((f.name==="Glob"||f.name==="Grep")&&typeof T.pattern=="string"){let k=Ke(T.pattern);k&&!k.includes("*")&&r.add(k)}}}return{touched_files:r,recent_user_messages:i,authored_paths:o,authored_content:a}}function Ke(e){let t=e.trim().replace(/^['"]|['"]$/g,"");return!t||t.length<4||/[<>|;&\$`]/.test(t)?null:t}var Jt=Bc(Wc),Gc=6,sr="Active ",rr=" sessions \u2014 ",zc=6e4;async function Yc(){if(Je()==="win32")return[];for(let t of["/bin/ps","/usr/bin/ps"])try{let{stdout:n}=await Jt(t,["-eo","pid=,comm="],{timeout:2e3}),s=[];for(let r of n.split(`
975
- `)){let i=r.trim().match(/^(\d+)\s+(.+)$/);if(!i)continue;let o=Number(i[1]),a=i[2].trim();(a==="claude"||a.endsWith("/claude")||a.endsWith("/bin/claude"))&&Number.isFinite(o)&&s.push(o)}return s}catch{continue}return[]}async function Kc(e){let t=Je();if(t==="linux")try{return(await Xc(`/proc/${e}/cwd`)).replace(/\/+$/,"")}catch{return null}if(t==="darwin"||t==="freebsd"||t==="openbsd")for(let n of["/usr/sbin/lsof","/usr/bin/lsof"])try{let{stdout:s}=await Jt(n,["-a","-p",String(e),"-d","cwd","-Fn"],{timeout:2e3});for(let r of s.split(`
976
- `))if(r.startsWith("n"))return r.slice(1).replace(/\/+$/,"");return null}catch{continue}return null}async function Jc(e){let t=Je();if(t==="linux")try{let n=await nr(`/proc/${e}/stat`,"utf8"),s=n.lastIndexOf(")");if(s===-1)return null;let r=n.slice(s+1).trim().split(/\s+/),i=Number(r[19]);if(!Number.isFinite(i))return null;let o=await nr("/proc/uptime","utf8"),a=Number(o.split(/\s+/)[0]);return Number.isFinite(a)?Date.now()-a*1e3+i/100*1e3:null}catch{return null}if(t==="darwin"||t==="freebsd"||t==="openbsd")for(let n of["/bin/ps","/usr/bin/ps"])try{let{stdout:s}=await Jt(n,["-o","lstart=","-p",String(e)],{timeout:2e3}),r=Date.parse(s.trim());return Number.isFinite(r)?r:null}catch{continue}return null}async function Vc(e,t){let n=await Yc();if(n.length===0)return null;let s=e.replace(/\/+$/,""),r=[];for(let o of n){let a=await Kc(o);if(a&&(a===s||a.startsWith(s+"/"))){let c=await Jc(o);r.push({pid:o,startMs:c})}}if(r.length===0)return new Set;let i=new Set;for(let{startMs:o}of r){if(o==null)continue;let a=null,c=zc;for(let l of t){if(i.has(l.session_id)||!l.started_at)continue;let d=Date.parse(l.started_at);if(!Number.isFinite(d))continue;let m=Math.abs(d-o);m<c&&(c=m,a=l)}a&&i.add(a.session_id)}return i}function qc(e){let n=E().prepare("SELECT id, name, decoded_path FROM projects WHERE id = ? LIMIT 1").get(e);if(!n)throw new Error(`project ${e} not found`);return n}function Qc(e,t){let n=E(),s=`${sr}${t}${rr}%`,r=n.prepare(`SELECT t.id
977
+ ${n}`}function vc(e){return Fs(e)?.auto_title_source??null}async function Cc(e){let{spawnClaudePrompt:t,isClaudeCliAvailable:n}=await Promise.resolve().then(()=>(Gt(),Ks));if(!n())throw new Error("claude CLI not found on PATH");let s=await t(e.prompt,[],{model:e.model});if(!s.success)throw new Error(`claude CLI exited ${s.exitCode}: ${s.stderr.slice(-500)}`);let r=Dc(s.stdout);if(!r)throw new Error("claude CLI returned an empty title");return r.slice(0,xc)}function Dc(e){let t=e.trim();if(!t)return"";try{let n=JSON.parse(t);if(n&&typeof n=="object"){let s=n.result;if(typeof s=="string")return Js(s)}}catch{}return Js(t)}function Js(e){return e.trim().replace(/^["'`]+|["'`]+$/g,"").replace(/\s+/g," ").replace(/[.!?]+$/g,"").trim()}async function qs(e,t={}){let n=j(e);if(!n)throw new Error(`thread not found: ${e}`);let s=Oc(n.edges),r=s.length,o=t.force??!1,i=t.signal,a=[],c=[],l=[];for(let d=0;d<s.length;d++){let p=s[d],u=d+1;if(i?.aborted){let h={sessionId:p,reason:"cancelled"};c.push(h),t.onSkipped?.(h);continue}if(!o&&vc(p)==="agent"){let h={sessionId:p,reason:"already-titled"};c.push(h),t.onSkipped?.(h);continue}let g;try{if(Vs)g=await Vs({sessionId:p,current:u,total:r});else{let h=Ic({sessionId:p,current:u,total:r});g=await Cc({prompt:h,model:t.model})}}catch(h){let E=h instanceof Error?h.message:String(h??"unknown error"),S={sessionId:p,error:E};l.push(S),t.onFailed?.(S);continue}try{Wt(p,g,"agent")}catch(h){let E=h instanceof Error?h.message:String(h??"unknown error"),S={sessionId:p,error:`setAutoTitle failed: ${E}`};l.push(S),t.onFailed?.(S);continue}a.push(p),t.onProgress?.({current:u,total:r,sessionId:p,title:g})}return{generated:a,skipped:c,failed:l}}var Vs=null;x();import{execFile as Jc}from"node:child_process";import{promisify as Vc}from"node:util";import{readlink as qc,readFile as sr}from"node:fs/promises";import{platform as Je}from"node:os";import{readFileSync as Mc,statSync as Pc}from"node:fs";var Fc=200*1024*1024;var Yt=.5,er=Yt,$c=[{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"}],Uc=["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 Qs(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 jc(e,t){let n=t-e;if(n<0)return{weight:0,label:null};for(let s of $c)if(n<=s.maxGapMs)return{weight:s.weight,label:s.label};return{weight:0,label:null}}function Hc(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 Uc)if(o.includes(i))return{weight:t[s],matched:i,matchedIndex:s}}return{weight:0,matched:null,matchedIndex:-1}}function zt(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 Bc(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=zt(s,r);o>n&&(n=o)}return n}function Wc(e,t){let n=zt(e.mean_embedding,t.mean_embedding),s=zt(e.tail_pool,t.head_pool),r=Bc(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 Xc(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 Gc(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 zc(e,t){let n=Qs(e),s=Qs(t);return n&&s&&n===s?{weight:.1,brand:n}:{weight:0,brand:null}}function Zs(e){return e.replace(/\s+/g," ").trim().toLowerCase()}function Yc(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(`
978
+ `).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=Zs(t.recent_user_messages[0]);if(o.length>=200)for(let i of e.authored_content){let a=Zs(i);if(a.length<200)continue;let c=Math.min(a.length,240),l=a.slice(0,c);if(o.includes(l)){n+=.4,r=!0;break}}}return{weight:Math.min(.6,n),pathMatch:s,contentMatch:r}}function Kc(e,t,n=er){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=jc(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=Hc(o),a=Gc(e.touched_files,t.touched_files),c=zc(e.auto_title,t.auto_title),l=Wc(e,t),d=Xc(e,t),p=Yc(e,t),u=r.weight+i.weight+a.weight+c.weight+l.weight+d.weight+p.weight;if(u<n)return null;let g=[];if(r.label&&g.push(`temporal ${r.label} (+${r.weight})`),i.matched){let h=i.matchedIndex===0?"opening message":`message #${i.matchedIndex+1}`;g.push(`continuation phrase "${i.matched}" in ${h} (+${i.weight})`)}if(a.count>0&&g.push(`${a.count} file${a.count===1?"":"s"} overlap (+${a.weight.toFixed(1)})`),c.brand&&g.push(`shared brand "${c.brand}" (+${c.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)})`),d.same&&g.push(`same cluster (+${d.weight})`),p.weight>0){let h=[];p.pathMatch&&h.push(`opened authored path "${p.pathMatch.split("/").pop()}"`),p.contentMatch&&h.push("verbatim-paste of authored content"),g.push(`doc-authorship: ${h.join(" + ")} (+${p.weight.toFixed(2)})`)}return{parent_id:e.id,child_id:t.id,confidence:Math.min(1,u),signals:{temporal:r.weight,continuation:i.weight,file_overlap:a.weight,same_brand:c.weight,semantic:l.weight,cluster:d.weight,doc_authorship:p.weight},reasons:g}}function tr(e,t=er){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],c=Kc(a,r,t);c&&(!o||c.confidence>o.confidence)&&(o=c)}o&&n.push(o)}return n}function nr(e,t={}){let n=t.maxUserMessages??5,s=t.userMessageMaxLen??2e3,r=new Set,o=[],i=new Set,a=[],c;try{if(Pc(e).size>Fc)return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a};c=Mc(e,"utf8")}catch{return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a}}let l=0;for(;l<c.length;){let d=c.indexOf(`
979
+ `,l),p=d===-1?c.length:d,u=c.slice(l,p);if(l=d===-1?c.length:d+1,!u.trim())continue;let g;try{g=JSON.parse(u)}catch{continue}let h=g;if(h.type==="user"&&h.message?.role==="user"&&typeof h.message.content=="string"&&o.length<n){let S=h.message.content.trim();S&&o.push(S.length>s?S.slice(0,s):S)}let E=h.message?.content;if(Array.isArray(E))for(let S of E){if(!S||typeof S!="object")continue;let m=S;if(m.type!=="tool_use")continue;let b=m.input??{},w=typeof b.file_path=="string"?b.file_path:null;if(w){let L=Ke(w);L&&r.add(L)}if((m.name==="Write"||m.name==="Edit"||m.name==="MultiEdit")&&w){let L=Ke(w);L&&i.add(L);let T=typeof b.content=="string"?b.content:typeof b.new_string=="string"?b.new_string:null;T&&T.length>=200&&a.push(T.length>4096?T.slice(0,4096):T)}if(m.name==="Bash"&&typeof b.command=="string")for(let L of b.command.matchAll(/(?:^|[\s'"`(=])((?:\.\.?\/|\/|src\/|test\/|docs\/|site\/)[A-Za-z0-9_./-]+)/g)){let T=Ke(L[1]);T&&r.add(T)}if((m.name==="Glob"||m.name==="Grep")&&typeof b.pattern=="string"){let L=Ke(b.pattern);L&&!L.includes("*")&&r.add(L)}}}return{touched_files:r,recent_user_messages:o,authored_paths:i,authored_content:a}}function Ke(e){let t=e.trim().replace(/^['"]|['"]$/g,"");return!t||t.length<4||/[<>|;&\$`]/.test(t)?null:t}var Jt=Vc(Jc),Qc=6,rr="Active ",or=" sessions \u2014 ",Zc=6e4;async function el(){if(Je()==="win32")return[];for(let t of["/bin/ps","/usr/bin/ps"])try{let{stdout:n}=await Jt(t,["-eo","pid=,comm="],{timeout:2e3}),s=[];for(let r of n.split(`
980
+ `)){let o=r.trim().match(/^(\d+)\s+(.+)$/);if(!o)continue;let i=Number(o[1]),a=o[2].trim();(a==="claude"||a.endsWith("/claude")||a.endsWith("/bin/claude"))&&Number.isFinite(i)&&s.push(i)}return s}catch{continue}return[]}async function tl(e){let t=Je();if(t==="linux")try{return(await qc(`/proc/${e}/cwd`)).replace(/\/+$/,"")}catch{return null}if(t==="darwin"||t==="freebsd"||t==="openbsd")for(let n of["/usr/sbin/lsof","/usr/bin/lsof"])try{let{stdout:s}=await Jt(n,["-a","-p",String(e),"-d","cwd","-Fn"],{timeout:2e3});for(let r of s.split(`
981
+ `))if(r.startsWith("n"))return r.slice(1).replace(/\/+$/,"");return null}catch{continue}return null}async function nl(e){let t=Je();if(t==="linux")try{let n=await sr(`/proc/${e}/stat`,"utf8"),s=n.lastIndexOf(")");if(s===-1)return null;let r=n.slice(s+1).trim().split(/\s+/),o=Number(r[19]);if(!Number.isFinite(o))return null;let i=await sr("/proc/uptime","utf8"),a=Number(i.split(/\s+/)[0]);return Number.isFinite(a)?Date.now()-a*1e3+o/100*1e3:null}catch{return null}if(t==="darwin"||t==="freebsd"||t==="openbsd")for(let n of["/bin/ps","/usr/bin/ps"])try{let{stdout:s}=await Jt(n,["-o","lstart=","-p",String(e)],{timeout:2e3}),r=Date.parse(s.trim());return Number.isFinite(r)?r:null}catch{continue}return null}async function sl(e,t){let n=await el();if(n.length===0)return null;let s=e.replace(/\/+$/,""),r=[];for(let i of n){let a=await tl(i);if(a&&(a===s||a.startsWith(s+"/"))){let c=await nl(i);r.push({pid:i,startMs:c})}}if(r.length===0)return new Set;let o=new Set;for(let{startMs:i}of r){if(i==null)continue;let a=null,c=Zc;for(let l of t){if(o.has(l.session_id)||!l.started_at)continue;let d=Date.parse(l.started_at);if(!Number.isFinite(d))continue;let p=Math.abs(d-i);p<c&&(c=p,a=l)}a&&o.add(a.session_id)}return o}function rl(e){let n=_().prepare("SELECT id, name, decoded_path FROM projects WHERE id = ? LIMIT 1").get(e);if(!n)throw new Error(`project ${e} not found`);return n}function ol(e,t){let n=_(),s=`${rr}${t}${or}%`,r=n.prepare(`SELECT t.id
977
982
  FROM threads t
978
983
  WHERE t.archived = 0
979
984
  AND t.name LIKE ?
980
- ORDER BY t.created_at DESC`).all(s);for(let o of r){let a=$(o.id);if(a&&a.project===t)return a}let i=n.prepare(`SELECT DISTINCT te.thread_id AS id
985
+ ORDER BY t.created_at DESC`).all(s);for(let i of r){let a=j(i.id);if(a&&a.project===t)return a}let o=n.prepare(`SELECT DISTINCT te.thread_id AS id
981
986
  FROM thread_edges te
982
987
  JOIN sessions s ON s.id = te.session_id
983
988
  JOIN threads t ON t.id = te.thread_id
984
989
  WHERE s.project_id = ?
985
990
  AND t.archived = 0
986
991
  AND t.name LIKE ?
987
- LIMIT 1`).get(e,s);return i?$(i.id):null}function ir(e){let t=e?new Date(e):new Date,n=t.getFullYear(),s=String(t.getMonth()+1).padStart(2,"0"),r=String(t.getDate()).padStart(2,"0");return`${n}-${s}-${r}`}function Kt(e,t){let n=E(),s=t>0,r=s?Date.now()-t*60*60*1e3:0;return s?n.prepare(`SELECT s.id AS session_id,
992
+ LIMIT 1`).get(e,s);return o?j(o.id):null}function ir(e){let t=e?new Date(e):new Date,n=t.getFullYear(),s=String(t.getMonth()+1).padStart(2,"0"),r=String(t.getDate()).padStart(2,"0");return`${n}-${s}-${r}`}function Kt(e,t){let n=_(),s=t>0,r=s?Date.now()-t*60*60*1e3:0;return s?n.prepare(`SELECT s.id AS session_id,
988
993
  sa.alias AS alias,
989
994
  s.auto_title AS auto_title,
990
995
  s.first_user_message AS first_user_message,
@@ -1004,25 +1009,25 @@ ${n}`}function Ac(e){return Ps(e)?.auto_title_source??null}async function Nc(e){
1004
1009
  FROM sessions s
1005
1010
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1006
1011
  WHERE s.project_id = ?
1007
- ORDER BY s.started_at ASC`).all(e)}function Zc(e){let t=E(),n=[];for(let s of e){if(!s.started_at)continue;let r=Date.parse(s.started_at);if(!Number.isFinite(r))continue;let i=t.prepare("SELECT file_path, ended_at FROM sessions WHERE id = ?").get(s.session_id);if(!i?.file_path)continue;let o=i.ended_at?Date.parse(i.ended_at):null,a=tr(i.file_path,{maxUserMessages:7});n.push({id:s.session_id,started_at_ms:r,ended_at_ms:Number.isFinite(o)?o:null,first_user_message:s.first_user_message,recent_user_messages:a.recent_user_messages,auto_title:s.auto_title,touched_files:a.touched_files,mean_embedding:null,head_pool:null,tail_pool:null,sample_chunks:[],cluster_id:null,authored_paths:a.authored_paths,authored_content:a.authored_content})}return n}function el(e){let n=E().prepare(`SELECT session_id, parent_session_id, source
1012
+ ORDER BY s.started_at ASC`).all(e)}function il(e){let t=_(),n=[];for(let s of e){if(!s.started_at)continue;let r=Date.parse(s.started_at);if(!Number.isFinite(r))continue;let o=t.prepare("SELECT file_path, ended_at FROM sessions WHERE id = ?").get(s.session_id);if(!o?.file_path)continue;let i=o.ended_at?Date.parse(o.ended_at):null,a=nr(o.file_path,{maxUserMessages:7});n.push({id:s.session_id,started_at_ms:r,ended_at_ms:Number.isFinite(i)?i:null,first_user_message:s.first_user_message,recent_user_messages:a.recent_user_messages,auto_title:s.auto_title,touched_files:a.touched_files,mean_embedding:null,head_pool:null,tail_pool:null,sample_chunks:[],cluster_id:null,authored_paths:a.authored_paths,authored_content:a.authored_content})}return n}function al(e){let n=_().prepare(`SELECT session_id, parent_session_id, source
1008
1013
  FROM thread_edges
1009
- WHERE thread_id = ?`).all(e),s=new Map;for(let r of n)s.set(r.session_id,{parent_session_id:r.parent_session_id,source:r.source});return s}async function Vt(e,t={}){let n=qc(e),s=t.windowHours??Gc,r=t.scoreThreshold??Yt,i=t.useLivePids??!0,o=[],a=[];if(i&&n.decoded_path){let S=Kt(e,0),u=await Vc(n.decoded_path,S);if(u===null){let T=Je()==="win32"?"Windows live-PID detection is not yet supported \u2014 falling back to the rolling mtime window.":"No live `claude` processes detected \u2014 falling back to the rolling mtime window. Output may include sessions that are no longer open.";o.push(T),a=Kt(e,s)}else u.size===0?(o.push(`No active terminals open in ${n.name} (cwd=${n.decoded_path}). Open a Claude terminal in this repo and re-run.`),a=[]):a=S.filter(f=>u.has(f.session_id))}else a=Kt(e,s);a.length===0&&!o.length&&o.push(`No active sessions in ${n.name} within the last ${s}h.`);let c=Qc(e,n.name),l=new Set(c?c.edges.map(S=>S.session_id):[]),d=a.filter(S=>!l.has(S.session_id)),m=Zc(a);m.sort((S,u)=>S.started_at_ms-u.started_at_ms);let p=er(m,r),g=c?c.edges.filter(S=>S.source!=="auto-active"&&(S.parent_session_id||S.role==="origin")).map(S=>({session_id:S.session_id,parent_session_id:S.parent_session_id})):[],h=c?c.name:`${sr}${n.name}${rr}${ir(t.todayIso)}`;return{project:n,thread:{id:c?.id??null,name:h,exists:!!c,existing_session_count:c?.edges.length??0},candidates:a,proposed_additions:d,proposed_edges:p,preserved_manual_edges:g,warnings:o}}function or(e){let t={thread_id:"",added:0,edges_set:0,preserved_manual:e.preserved_manual_edges.length},n;e.thread.exists&&e.thread.id?n=e.thread.id:n=Ge({name:e.thread.name,summary:`Auto-captured by sync-active on ${ir()}. Members are sessions in ${e.project.name} that were active within the rolling window. Re-runnable: subsequent runs append new active sessions and never overwrite manual edges.`}).id,t.thread_id=n;let s=el(n);for(let o of e.candidates)s.has(o.session_id)||(ze({threadId:n,sessionId:o.session_id,source:"auto-active",confidence:.5}),t.added++,s.set(o.session_id,{parent_session_id:null,source:"auto-active"}));for(let o of e.proposed_edges){let a=s.get(o.child_id);if(a&&a.source==="auto-active"&&a.parent_session_id!==o.parent_id&&s.has(o.parent_id))try{Re(n,o.child_id,o.parent_id),t.edges_set++,s.set(o.child_id,{parent_session_id:o.parent_id,source:a.source})}catch{}}let i=E().prepare(`SELECT session_id FROM thread_edges
1014
+ WHERE thread_id = ?`).all(e),s=new Map;for(let r of n)s.set(r.session_id,{parent_session_id:r.parent_session_id,source:r.source});return s}async function Vt(e,t={}){let n=rl(e),s=t.windowHours??Qc,r=t.scoreThreshold??Yt,o=t.useLivePids??!0,i=[],a=[];if(o&&n.decoded_path){let E=Kt(e,0),S=await sl(n.decoded_path,E);if(S===null){let b=Je()==="win32"?"Windows live-PID detection is not yet supported \u2014 falling back to the rolling mtime window.":"No live `claude` processes detected \u2014 falling back to the rolling mtime window. Output may include sessions that are no longer open.";i.push(b),a=Kt(e,s)}else S.size===0?(i.push(`No active terminals open in ${n.name} (cwd=${n.decoded_path}). Open a Claude terminal in this repo and re-run.`),a=[]):a=E.filter(m=>S.has(m.session_id))}else a=Kt(e,s);a.length===0&&!i.length&&i.push(`No active sessions in ${n.name} within the last ${s}h.`);let c=ol(e,n.name),l=new Set(c?c.edges.map(E=>E.session_id):[]),d=a.filter(E=>!l.has(E.session_id)),p=il(a);p.sort((E,S)=>E.started_at_ms-S.started_at_ms);let u=tr(p,r),g=c?c.edges.filter(E=>E.source!=="auto-active"&&(E.parent_session_id||E.role==="origin")).map(E=>({session_id:E.session_id,parent_session_id:E.parent_session_id})):[],h=c?c.name:`${rr}${n.name}${or}${ir(t.todayIso)}`;return{project:n,thread:{id:c?.id??null,name:h,exists:!!c,existing_session_count:c?.edges.length??0},candidates:a,proposed_additions:d,proposed_edges:u,preserved_manual_edges:g,warnings:i}}function ar(e){let t={thread_id:"",added:0,edges_set:0,preserved_manual:e.preserved_manual_edges.length},n;e.thread.exists&&e.thread.id?n=e.thread.id:n=Ge({name:e.thread.name,summary:`Auto-captured by sync-active on ${ir()}. Members are sessions in ${e.project.name} that were active within the rolling window. Re-runnable: subsequent runs append new active sessions and never overwrite manual edges.`}).id,t.thread_id=n;let s=al(n);for(let i of e.candidates)s.has(i.session_id)||(ze({threadId:n,sessionId:i.session_id,source:"auto-active",confidence:.5}),t.added++,s.set(i.session_id,{parent_session_id:null,source:"auto-active"}));for(let i of e.proposed_edges){let a=s.get(i.child_id);if(a&&a.source==="auto-active"&&a.parent_session_id!==i.parent_id&&s.has(i.parent_id))try{Re(n,i.child_id,i.parent_id),t.edges_set++,s.set(i.child_id,{parent_session_id:i.parent_id,source:a.source})}catch{}}let o=_().prepare(`SELECT session_id FROM thread_edges
1010
1015
  WHERE thread_id = ?
1011
1016
  AND source = 'auto-active'
1012
1017
  AND parent_session_id IS NULL
1013
- AND role = 'child'`).all(n);for(let o of i)try{Re(n,o.session_id,null)}catch{}return t}function F(e){return{content:[{type:"text",text:JSON.stringify(e,null,2)}]}}function tl(e){return{content:[{type:"text",text:e}],isError:!0}}function U(e,t){return B.object(e).strict().parse(t)}var Sr=B.string().uuid(),q=Sr.describe("Thread id (UUID)."),de=Sr.describe("Session UUID (exact, not a prefix)."),ar={include_archived:B.boolean().optional().describe("Include archived threads (default false).")},cr={id:q},lr={session_id:de},dr={name:B.string().min(1).max(200).describe("Human-readable thread name."),summary:B.string().max(4e3).optional().describe("Optional short description."),origin_session_id:de.optional().describe("Seed the thread with this session as its origin.")},ur={thread_id:q,session_id:de,parent_session_id:de.optional().describe("If present, the edge is role=child with this parent; otherwise role=origin."),role:B.enum(["origin","child"]).optional()},pr={thread_id:q,session_id:de,parent_session_id:de.nullable().describe("New parent (null to clear and promote the edge back to role=origin).")},mr={thread_id:q,session_id:de},gr={thread_id:q,name:B.string().min(1).max(200)},Se={thread_id:q},fr={source_id:q.describe("Thread to dissolve \u2014 its edges move into dest_id."),dest_id:q.describe("Thread that absorbs source_id.")},_r={thread_id:q,session_ids:B.array(de).min(1).max(500),new_thread_name:B.string().min(1).max(200)},hr={thread_id:q,force:B.boolean().optional().describe("When true, regenerate titles for sessions that already have an agent-sourced title. Default false skips them.")},Er={project_id:B.number().int().positive().describe("Numeric project id from list_projects. The sync is repo-scoped and never crosses projects."),mode:B.enum(["preflight","apply"]).describe("preflight returns the proposed plan without writing; apply writes the thread + edges and is idempotent."),window_hours:B.number().min(.5).max(168).optional().describe("Rolling activity window in hours. Default 6.")};function Tr(e){e.registerTool("thread_list",{title:"List threads",description:"All threads (v0.15a intent groups), newest first. Excludes archived threads unless include_archived is true.",inputSchema:ar},async t=>{try{let{include_archived:n}=U(ar,t);return F(Ut({includeArchived:n??!1}))}catch(n){return C(n)}}),e.registerTool("thread_get",{title:"Get thread with edges",description:"Full thread detail including every session edge (origin + children).",inputSchema:cr},async t=>{try{let{id:n}=U(cr,t),s=$(n);return s?F(s):tl(`thread not found: ${n}`)}catch(n){return C(n)}}),e.registerTool("thread_for_session",{title:"List threads containing a session",description:"Return non-archived threads that reference this session (as origin or child).",inputSchema:lr},async t=>{try{let{session_id:n}=U(lr,t);return F(Ts(n))}catch(n){return C(n)}})}function br(e,t={}){let n=t.limiter??new ce;e.registerTool("thread_create",{title:"Create a thread",description:"Create a new thread. Optionally seed it with an origin session. Name is required; summary is optional.",inputSchema:dr},async s=>{try{let r=U(dr,s),i=await D({tool:"thread_create",args:r,limiter:n,run:()=>Ge({name:r.name,summary:r.summary??null,originSessionId:r.origin_session_id})});return F(i)}catch(r){return C(r)}}),e.registerTool("thread_add_session",{title:"Add session to thread",description:"Attach a session to a thread. If parent_session_id is provided the edge is role=child; otherwise role=origin. Upsert: re-adding updates the edge.",inputSchema:ur},async s=>{try{let r=U(ur,s),i=await D({tool:"thread_add_session",args:r,limiter:n,run:()=>ze({threadId:r.thread_id,sessionId:r.session_id,parentSessionId:r.parent_session_id??null,role:r.role,source:"manual",confidence:1})});return F(i)}catch(r){return C(r)}}),e.registerTool("thread_set_parent",{title:"Set edge parent within thread",description:"Change the parent session of an existing thread edge. Pass null to clear the parent and promote the edge to role=origin.",inputSchema:pr},async s=>{try{let r=U(pr,s),i=await D({tool:"thread_set_parent",args:r,limiter:n,run:()=>Re(r.thread_id,r.session_id,r.parent_session_id)});return F(i)}catch(r){return C(r)}}),e.registerTool("thread_remove_session",{title:"Remove session from thread",description:"Detach a session from a thread. The session itself is untouched; only the edge is removed. The updated thread is re-mirrored to disk.",inputSchema:mr},async s=>{try{let r=U(mr,s),i=await D({tool:"thread_remove_session",args:r,limiter:n,run:()=>bs(r.thread_id,r.session_id)});return F({thread_id:r.thread_id,session_id:r.session_id,...i})}catch(r){return C(r)}}),e.registerTool("thread_rename",{title:"Rename thread",description:"Change the display name of a thread.",inputSchema:gr},async s=>{try{let r=U(gr,s),i=await D({tool:"thread_rename",args:r,limiter:n,run:()=>ys(r.thread_id,r.name)});return F(i)}catch(r){return C(r)}}),e.registerTool("thread_close",{title:"Close thread",description:"Mark the thread as closed (sets closed_at). Thread remains listed; reopen to clear.",inputSchema:Se},async s=>{try{let r=U(Se,s),i=await D({tool:"thread_close",args:r,limiter:n,run:()=>ws(r.thread_id)});return F(i)}catch(r){return C(r)}}),e.registerTool("thread_reopen",{title:"Reopen thread",description:"Clear closed_at on a closed thread.",inputSchema:Se},async s=>{try{let r=U(Se,s),i=await D({tool:"thread_reopen",args:r,limiter:n,run:()=>Rs(r.thread_id)});return F(i)}catch(r){return C(r)}}),e.registerTool("thread_archive",{title:"Archive thread",description:"Soft-delete a thread by setting archived=1. Archived threads are hidden from thread_list by default but never hard-deleted; data is preserved in SQLite and the JSON mirror.",inputSchema:Se},async s=>{try{let r=U(Se,s),i=await D({tool:"thread_archive",args:r,limiter:n,run:()=>As(r.thread_id)});return F(i)}catch(r){return C(r)}}),e.registerTool("thread_merge",{title:"Merge two threads",description:"Move every edge from source_id into dest_id, then delete source_id. Origin roles are preserved when present on either side.",inputSchema:fr},async s=>{try{let r=U(fr,s),i=await D({tool:"thread_merge",args:r,limiter:n,run:()=>Ns(r.source_id,r.dest_id)});return F(i)}catch(r){return C(r)}}),e.registerTool("thread_split",{title:"Split sessions into a new thread",description:"Peel the specified session_ids out of thread_id into a brand-new thread named new_thread_name. Non-member session_ids are silently skipped.",inputSchema:_r},async s=>{try{let r=U(_r,s),i=await D({tool:"thread_split",args:r,limiter:n,run:()=>Ls({threadId:r.thread_id,sessionIds:r.session_ids,newThreadName:r.new_thread_name})});return F(i)}catch(r){return C(r)}}),e.registerTool("sync_active_sessions",{title:"Sync currently active sessions in a repo into a thread",description:'Captures the Captain Code Pattern: scans every Claude session whose JSONL was touched within the rolling window in the given project, infers parent/child edges via the 7-signal scorer (temporal, continuation, file overlap, brand, semantic, cluster, doc-authorship), and stitches them into one thread. Idempotent: re-running reuses the existing "Active <project> sessions \u2014 *" thread, only appends new sessions, and never overwrites edges with source=manual. Use mode=preflight first to show the user the proposed plan, then mode=apply to write.',inputSchema:Er},async s=>{try{let r=U(Er,s);if(r.mode==="preflight"){let o=await Vt(r.project_id,{windowHours:r.window_hours});return F({plan:o})}let i=await D({tool:"sync_active_sessions",args:r,limiter:n,run:async()=>{let o=await Vt(r.project_id,{windowHours:r.window_hours}),a=or(o);return{plan:o,result:a}}});return F(i)}catch(r){return C(r)}}),e.registerTool("generate_thread_titles",{title:"Generate titles for every session in a thread",description:"Walk a thread DAG in topology order (origins first by added_at, then children breadth-first) and generate a coherent agent title for each session. Each successive title sees already-titled ancestors and earlier siblings as strong context so a naming pattern emerges. Set force=true to regenerate already-titled sessions; default false skips them. Returns the final {generated, skipped, failed} summary after the whole walk completes.",inputSchema:hr},async s=>{try{let r=U(hr,s),i=await D({tool:"generate_thread_titles",args:r,limiter:n,run:async()=>{let o=await Vs(r.thread_id,{force:r.force??!1});if(o.failed.length>0&&o.generated.length===0&&o.skipped.length===0)throw new Error(`all ${o.failed.length} session(s) failed title generation`);return o}});return F(i)}catch(r){return C(r)}})}on();x();v();import{writeFileSync as xl}from"node:fs";import{join as Ol}from"node:path";var Il=Ol(y,"recall-events.json");function kr(e,t,n,s="cli"){E().prepare(`
1018
+ AND role = 'child'`).all(n);for(let i of o)try{Re(n,i.session_id,null)}catch{}return t}function U(e){return{content:[{type:"text",text:JSON.stringify(e,null,2)}]}}function cl(e){return{content:[{type:"text",text:e}],isError:!0}}function H(e,t){return G.object(e).strict().parse(t)}var br=G.string().uuid(),Q=br.describe("Thread id (UUID)."),de=br.describe("Session UUID (exact, not a prefix)."),cr={include_archived:G.boolean().optional().describe("Include archived threads (default false).")},lr={id:Q},dr={session_id:de},ur={name:G.string().min(1).max(200).describe("Human-readable thread name."),summary:G.string().max(4e3).optional().describe("Optional short description."),origin_session_id:de.optional().describe("Seed the thread with this session as its origin.")},pr={thread_id:Q,session_id:de,parent_session_id:de.optional().describe("If present, the edge is role=child with this parent; otherwise role=origin."),role:G.enum(["origin","child"]).optional()},mr={thread_id:Q,session_id:de,parent_session_id:de.nullable().describe("New parent (null to clear and promote the edge back to role=origin).")},gr={thread_id:Q,session_id:de},fr={thread_id:Q,name:G.string().min(1).max(200)},Se={thread_id:Q},_r={source_id:Q.describe("Thread to dissolve \u2014 its edges move into dest_id."),dest_id:Q.describe("Thread that absorbs source_id.")},hr={thread_id:Q,session_ids:G.array(de).min(1).max(500),new_thread_name:G.string().min(1).max(200)},Er={thread_id:Q,force:G.boolean().optional().describe("When true, regenerate titles for sessions that already have an agent-sourced title. Default false skips them.")},Sr={project_id:G.number().int().positive().describe("Numeric project id from list_projects. The sync is repo-scoped and never crosses projects."),mode:G.enum(["preflight","apply"]).describe("preflight returns the proposed plan without writing; apply writes the thread + edges and is idempotent."),window_hours:G.number().min(.5).max(168).optional().describe("Rolling activity window in hours. Default 6.")};function Tr(e){e.registerTool("thread_list",{title:"List threads",description:"All threads (v0.15a intent groups), newest first. Excludes archived threads unless include_archived is true.",inputSchema:cr},async t=>{try{let{include_archived:n}=H(cr,t);return U(Ut({includeArchived:n??!1}))}catch(n){return C(n)}}),e.registerTool("thread_get",{title:"Get thread with edges",description:"Full thread detail including every session edge (origin + children).",inputSchema:lr},async t=>{try{let{id:n}=H(lr,t),s=j(n);return s?U(s):cl(`thread not found: ${n}`)}catch(n){return C(n)}}),e.registerTool("thread_for_session",{title:"List threads containing a session",description:"Return non-archived threads that reference this session (as origin or child).",inputSchema:dr},async t=>{try{let{session_id:n}=H(dr,t);return U(Ts(n))}catch(n){return C(n)}})}function yr(e,t={}){let n=t.limiter??new ce;e.registerTool("thread_create",{title:"Create a thread",description:"Create a new thread. Optionally seed it with an origin session. Name is required; summary is optional.",inputSchema:ur},async s=>{try{let r=H(ur,s),o=await D({tool:"thread_create",args:r,limiter:n,run:()=>Ge({name:r.name,summary:r.summary??null,originSessionId:r.origin_session_id})});return U(o)}catch(r){return C(r)}}),e.registerTool("thread_add_session",{title:"Add session to thread",description:"Attach a session to a thread. If parent_session_id is provided the edge is role=child; otherwise role=origin. Upsert: re-adding updates the edge.",inputSchema:pr},async s=>{try{let r=H(pr,s),o=await D({tool:"thread_add_session",args:r,limiter:n,run:()=>ze({threadId:r.thread_id,sessionId:r.session_id,parentSessionId:r.parent_session_id??null,role:r.role,source:"manual",confidence:1})});return U(o)}catch(r){return C(r)}}),e.registerTool("thread_set_parent",{title:"Set edge parent within thread",description:"Change the parent session of an existing thread edge. Pass null to clear the parent and promote the edge to role=origin.",inputSchema:mr},async s=>{try{let r=H(mr,s),o=await D({tool:"thread_set_parent",args:r,limiter:n,run:()=>Re(r.thread_id,r.session_id,r.parent_session_id)});return U(o)}catch(r){return C(r)}}),e.registerTool("thread_remove_session",{title:"Remove session from thread",description:"Detach a session from a thread. The session itself is untouched; only the edge is removed. The updated thread is re-mirrored to disk.",inputSchema:gr},async s=>{try{let r=H(gr,s),o=await D({tool:"thread_remove_session",args:r,limiter:n,run:()=>ys(r.thread_id,r.session_id)});return U({thread_id:r.thread_id,session_id:r.session_id,...o})}catch(r){return C(r)}}),e.registerTool("thread_rename",{title:"Rename thread",description:"Change the display name of a thread.",inputSchema:fr},async s=>{try{let r=H(fr,s),o=await D({tool:"thread_rename",args:r,limiter:n,run:()=>ws(r.thread_id,r.name)});return U(o)}catch(r){return C(r)}}),e.registerTool("thread_close",{title:"Close thread",description:"Mark the thread as closed (sets closed_at). Thread remains listed; reopen to clear.",inputSchema:Se},async s=>{try{let r=H(Se,s),o=await D({tool:"thread_close",args:r,limiter:n,run:()=>Rs(r.thread_id)});return U(o)}catch(r){return C(r)}}),e.registerTool("thread_reopen",{title:"Reopen thread",description:"Clear closed_at on a closed thread.",inputSchema:Se},async s=>{try{let r=H(Se,s),o=await D({tool:"thread_reopen",args:r,limiter:n,run:()=>As(r.thread_id)});return U(o)}catch(r){return C(r)}}),e.registerTool("thread_archive",{title:"Archive thread",description:"Soft-delete a thread by setting archived=1. Archived threads are hidden from thread_list by default but never hard-deleted; data is preserved in SQLite and the JSON mirror.",inputSchema:Se},async s=>{try{let r=H(Se,s),o=await D({tool:"thread_archive",args:r,limiter:n,run:()=>Ns(r.thread_id)});return U(o)}catch(r){return C(r)}}),e.registerTool("thread_merge",{title:"Merge two threads",description:"Move every edge from source_id into dest_id, then delete source_id. Origin roles are preserved when present on either side.",inputSchema:_r},async s=>{try{let r=H(_r,s),o=await D({tool:"thread_merge",args:r,limiter:n,run:()=>Ls(r.source_id,r.dest_id)});return U(o)}catch(r){return C(r)}}),e.registerTool("thread_split",{title:"Split sessions into a new thread",description:"Peel the specified session_ids out of thread_id into a brand-new thread named new_thread_name. Non-member session_ids are silently skipped.",inputSchema:hr},async s=>{try{let r=H(hr,s),o=await D({tool:"thread_split",args:r,limiter:n,run:()=>ks({threadId:r.thread_id,sessionIds:r.session_ids,newThreadName:r.new_thread_name})});return U(o)}catch(r){return C(r)}}),e.registerTool("sync_active_sessions",{title:"Sync currently active sessions in a repo into a thread",description:'Captures the Captain Code Pattern: scans every Claude session whose JSONL was touched within the rolling window in the given project, infers parent/child edges via the 7-signal scorer (temporal, continuation, file overlap, brand, semantic, cluster, doc-authorship), and stitches them into one thread. Idempotent: re-running reuses the existing "Active <project> sessions \u2014 *" thread, only appends new sessions, and never overwrites edges with source=manual. Use mode=preflight first to show the user the proposed plan, then mode=apply to write.',inputSchema:Sr},async s=>{try{let r=H(Sr,s);if(r.mode==="preflight"){let i=await Vt(r.project_id,{windowHours:r.window_hours});return U({plan:i})}let o=await D({tool:"sync_active_sessions",args:r,limiter:n,run:async()=>{let i=await Vt(r.project_id,{windowHours:r.window_hours}),a=ar(i);return{plan:i,result:a}}});return U(o)}catch(r){return C(r)}}),e.registerTool("generate_thread_titles",{title:"Generate titles for every session in a thread",description:"Walk a thread DAG in topology order (origins first by added_at, then children breadth-first) and generate a coherent agent title for each session. Each successive title sees already-titled ancestors and earlier siblings as strong context so a naming pattern emerges. Set force=true to regenerate already-titled sessions; default false skips them. Returns the final {generated, skipped, failed} summary after the whole walk completes.",inputSchema:Er},async s=>{try{let r=H(Er,s),o=await D({tool:"generate_thread_titles",args:r,limiter:n,run:async()=>{let i=await qs(r.thread_id,{force:r.force??!1});if(i.failed.length>0&&i.generated.length===0&&i.skipped.length===0)throw new Error(`all ${i.failed.length} session(s) failed title generation`);return i}});return U(o)}catch(r){return C(r)}})}on();x();v();import{writeFileSync as Pl}from"node:fs";import{join as Fl}from"node:path";var $l=Fl(A,"recall-events.json");function xr(e,t,n,s="cli"){_().prepare(`
1014
1019
  INSERT INTO recall_events (session_id, recalled_at, token_count, mode, caller)
1015
1020
  VALUES (?, datetime('now'), ?, ?, ?)
1016
- `).run(e,t,n,s),vl()}function vl(){I();let t=E().prepare("SELECT id, session_id, recalled_at, token_count, mode, caller FROM recall_events ORDER BY recalled_at DESC").all();xl(Il,JSON.stringify(t,null,2)+`
1017
- `,"utf-8")}x();Pe();var ge=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}};function an(e,t={}){let n=t.limit??Cl()??75e3,r=e.prepare("SELECT COUNT(*) AS n FROM vec_chunks").get()?.n??0;if(r>n)throw new ge(r,n)}function Cl(){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)}qe();import{Worker as Dl}from"node:worker_threads";import{join as Ml}from"node:path";var cn=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"},Pl=1e4;function Fl(){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 ln(e){let t=e.timeoutMs??Fl()??Pl,n=(e.workerFactory??$l)();return new Promise((s,r)=>{let i=setTimeout(()=>{n.terminate().catch(()=>{}),r(new cn(t))},t);n.once("message",o=>{clearTimeout(i);let a=o;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",o=>{clearTimeout(i),n.terminate().catch(()=>{}),r(o)}),n.postMessage({query:e.query,precomputedVector:e.precomputedVector,limit:e.limit})})}function $l(){let e=Ml(Te(),"dist","daemon","query-worker.js"),t={...process.env,RECALL_DB_PROFILE:"worker"};return new Dl(e,{env:t})}async function dn(e,t=50){let n=E();return oe(n),an(n),ln({query:e,limit:t})}async function xr(e,t=10,n=.65){let s=E();oe(s),an(s);let r=s.prepare("SELECT rowid FROM chunk_meta WHERE session_id = ? ORDER BY rowid LIMIT 1").get(e);if(!r)return[];let i=s.prepare("SELECT embedding FROM vec_chunks WHERE rowid = ?").get(r.rowid);if(!i)return[];let o=await ln({precomputedVector:i.embedding,limit:t*5}),a=new Map;for(let l of o){if(l.sessionId===e)continue;let d=a.get(l.sessionId);(d===void 0||l.distance<d)&&a.set(l.sessionId,l.distance)}let c=[];for(let[l,d]of a){let m=1-d;m>=n&&c.push({sessionId:l,similarity:m})}return c.sort((l,d)=>d.similarity-l.similarity),c.slice(0,t)}function Ul(){let e=process.env.RECALL_RRF_K;if(e){let t=parseInt(e,10);if(!isNaN(t)&&t>=1&&t<=1e3)return t}return 60}function Or(e){let t=Ul(),n=new Map;for(let r of e)for(let i=0;i<r.length;i++){let o=r[i],a=1/(t+i+1),c=n.get(o.id);c?(c.score+=a,c.lanes.push(o.lane),i+1<c.bestRank&&(c.bestRank=i+1,c.bestData=o.data)):n.set(o.id,{score:a,lanes:[o.lane],bestRank:i+1,bestData:o.data})}let s=[];for(let[r,i]of n)s.push({id:r,score:i.score,lanes:i.lanes,data:i.bestData});return s.sort((r,i)=>i.score-r.score),s}un();import{existsSync as Xl,mkdirSync as zf,rmSync as Yf,createWriteStream as Kf,statSync as Jf}from"node:fs";import{join as Mr}from"node:path";v();var Gl=[{path:"config.json",sha256:"bc00af31a4a31b74040d73370aa83b62da34c90b75eb77bfa7db039d90abd591"},{path:"tokenizer.json",sha256:"d241a60d5e8f04cc1b2b3e9ef7a4921b27bf526d9f6050ab90f9267a1f9e5c66"},{path:"tokenizer_config.json",sha256:"9261e7d79b44c8195c1cada2b453e55b00aeb81e907a6664974b4d7776172ab3"},{path:"onnx/model.onnx",sha256:"9bc579acdba21c253c62a9bf866891355a63ffa3442b52c8a37d75b2ccb91848"}];function zl(){return Mr(y,"models","BAAI","bge-base-en-v1.5")}function it(){let e=zl();return Gl.every(t=>Xl(Mr(e,t.path)))}v();import{existsSync as Yl,readFileSync as Kl,writeFileSync as e_,unlinkSync as t_}from"node:fs";import{join as Jl}from"node:path";var Pr=Jl(y,"license.json");function Fr(){if(!Yl(Pr))return null;try{let e=Kl(Pr,"utf8"),t=JSON.parse(e);return typeof t.license_jwt!="string"||t.license_jwt.length===0?null:t}catch{return null}}import{jwtVerify as Vl,importSPKI as ql}from"jose";var $r=`-----BEGIN PUBLIC KEY-----
1021
+ `).run(e,t,n,s),Ul()}function Ul(){I();let t=_().prepare("SELECT id, session_id, recalled_at, token_count, mode, caller FROM recall_events ORDER BY recalled_at DESC").all();Pl($l,JSON.stringify(t,null,2)+`
1022
+ `,"utf-8")}x();Pe();var fe=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}};function an(e,t={}){let n=t.limit??jl()??75e3,r=e.prepare("SELECT COUNT(*) AS n FROM vec_chunks").get()?.n??0;if(r>n)throw new fe(r,n)}function jl(){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)}qe();import{Worker as Hl}from"node:worker_threads";import{join as Bl}from"node:path";var cn=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"},Wl=1e4;function Xl(){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 ln(e){let t=e.timeoutMs??Xl()??Wl,n=(e.workerFactory??Gl)();return new Promise((s,r)=>{let o=setTimeout(()=>{n.terminate().catch(()=>{}),r(new cn(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 Gl(){let e=Bl(be(),"dist","daemon","query-worker.js"),t={...process.env,RECALL_DB_PROFILE:"worker"};return new Hl(e,{env:t})}async function dn(e,t=50){let n=_();return ie(n),an(n),ln({query:e,limit:t})}async function Or(e,t=10,n=.65){let s=_();ie(s),an(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 ln({precomputedVector:o.embedding,limit:t*5}),a=new Map;for(let l of i){if(l.sessionId===e)continue;let d=a.get(l.sessionId);(d===void 0||l.distance<d)&&a.set(l.sessionId,l.distance)}let c=[];for(let[l,d]of a){let p=1-d;p>=n&&c.push({sessionId:l,similarity:p})}return c.sort((l,d)=>d.similarity-l.similarity),c.slice(0,t)}function zl(){let e=process.env.RECALL_RRF_K;if(e){let t=parseInt(e,10);if(!isNaN(t)&&t>=1&&t<=1e3)return t}return 60}function Ir(e){let t=zl(),n=new Map;for(let r of e)for(let o=0;o<r.length;o++){let i=r[o],a=1/(t+o+1),c=n.get(i.id);c?(c.score+=a,c.lanes.push(i.lane),o+1<c.bestRank&&(c.bestRank=o+1,c.bestData=i.data)):n.set(i.id,{score:a,lanes:[i.lane],bestRank:o+1,bestData:i.data})}let s=[];for(let[r,o]of n)s.push({id:r,score:o.score,lanes:o.lanes,data:o.bestData});return s.sort((r,o)=>o.score-r.score),s}un();import{existsSync as ql,mkdirSync as r_,rmSync as o_,createWriteStream as i_,statSync as a_}from"node:fs";import{join as Pr}from"node:path";v();var Ql=[{path:"config.json",sha256:"bc00af31a4a31b74040d73370aa83b62da34c90b75eb77bfa7db039d90abd591"},{path:"tokenizer.json",sha256:"d241a60d5e8f04cc1b2b3e9ef7a4921b27bf526d9f6050ab90f9267a1f9e5c66"},{path:"tokenizer_config.json",sha256:"9261e7d79b44c8195c1cada2b453e55b00aeb81e907a6664974b4d7776172ab3"},{path:"onnx/model.onnx",sha256:"9bc579acdba21c253c62a9bf866891355a63ffa3442b52c8a37d75b2ccb91848"}];function Zl(){return Pr(A,"models","BAAI","bge-base-en-v1.5")}function ot(){let e=Zl();return Ql.every(t=>ql(Pr(e,t.path)))}v();import{existsSync as ed,readFileSync as td,writeFileSync as p_,unlinkSync as m_}from"node:fs";import{join as nd}from"node:path";var Fr=nd(A,"license.json");function $r(){if(!ed(Fr))return null;try{let e=td(Fr,"utf8"),t=JSON.parse(e);return typeof t.license_jwt!="string"||t.license_jwt.length===0?null:t}catch{return null}}import{jwtVerify as sd,importSPKI as rd}from"jose";var Ur=`-----BEGIN PUBLIC KEY-----
1018
1023
  MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZysO2FffTLdyxQnTmnt78/ayvqz9
1019
1024
  kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
1020
1025
  -----END PUBLIC KEY-----
1021
- `,pn="ES256",Ur="clauderecall.com",jr="clauderecall-cli";var ot=null;async function Ql(){return ot||(ot=await ql($r,pn),ot)}async function Hr(e){try{let t=await Ql(),{payload:n}=await Vl(e,t,{issuer:Ur,audience:jr,algorithms:[pn]});return{valid:!0,claims:n}}catch(t){return{valid:!1,reason:t instanceof Error?t.message:"verification failed"}}}import{createHash as Zl}from"node:crypto";import{hostname as ed,userInfo as td,platform as nd,arch as sd}from"node:os";function Wr(){let e="unknown";try{e=td().username}catch{}let t=[ed(),e,nd(),sd()];return Zl("sha256").update(t.join("\0")).digest("hex")}v();import{existsSync as rd,readFileSync as id,writeFileSync as f_}from"node:fs";import{join as od}from"node:path";var Br=od(y,"license-check.json"),S_=1440*60*1e3,ad=720*60*60*1e3;function cd(){if(!rd(Br))return null;try{let e=JSON.parse(id(Br,"utf8"));return typeof e.license_key!="string"||typeof e.last_checked_at!="string"||typeof e.revoked!="boolean"?null:e}catch{return null}}function Xr(e){let t=cd();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()>ad?{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 ld=1440*60*1e3,R_=60*ld;async function mn(){let e=Fr();if(!e)return{tier:"free"};let t=await Hr(e.license_jwt);if(!t.valid||!t.claims)return{tier:"free",invalid_reason:t.reason};if(t.claims.machine_fp&&t.claims.machine_fp!==Wr())return{tier:"free",invalid_reason:"machine fingerprint mismatch \u2014 re-activate on this device"};let n=Xr(e.license_key);return n?.revoked?{tier:"free",invalid_reason:n.reason}:dd(e,t.claims)}function dd(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}}x();x();v();import{join as gn}from"node:path";var ud=new Set(["pending","approved","rejected"]),pd=new Set(["L1","L2","L3","L4","user"]),U_=gn(y,"links"),md=gn(y,"suggestions"),j_=gn(md,"index.json");function Gr(e){try{return JSON.parse(e)}catch{return e}}function gd(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:Gr(e.evidence),approved:e.approved===1,created_at:e.created_at,updated_at:e.updated_at}}function fd(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:Gr(e.evidence),status:e.status,inferred_by:e.inferred_by,created_at:e.created_at,decided_at:e.decided_at}}function _d(e){if(!pd.has(e))throw new Error(`invalid inferred_by: ${e}`)}function fn(e){return E().prepare(`SELECT * FROM session_links
1026
+ `,pn="ES256",jr="clauderecall.com",Hr="clauderecall-cli";var it=null;async function od(){return it||(it=await rd(Ur,pn),it)}async function Br(e){try{let t=await od(),{payload:n}=await sd(e,t,{issuer:jr,audience:Hr,algorithms:[pn]});return{valid:!0,claims:n}}catch(t){return{valid:!1,reason:t instanceof Error?t.message:"verification failed"}}}import{createHash as id}from"node:crypto";import{hostname as ad,userInfo as cd,platform as ld,arch as dd}from"node:os";function Wr(){let e="unknown";try{e=cd().username}catch{}let t=[ad(),e,ld(),dd()];return id("sha256").update(t.join("\0")).digest("hex")}v();import{existsSync as ud,readFileSync as pd,writeFileSync as L_}from"node:fs";import{join as md}from"node:path";var Xr=md(A,"license-check.json"),I_=1440*60*1e3,gd=720*60*60*1e3;function fd(){if(!ud(Xr))return null;try{let e=JSON.parse(pd(Xr,"utf8"));return typeof e.license_key!="string"||typeof e.last_checked_at!="string"||typeof e.revoked!="boolean"?null:e}catch{return null}}function Gr(e){let t=fd();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()>gd?{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 _d=1440*60*1e3,P_=60*_d;async function mn(){let e=$r();if(!e)return{tier:"free"};let t=await Br(e.license_jwt);if(!t.valid||!t.claims)return{tier:"free",invalid_reason:t.reason};if(t.claims.machine_fp&&t.claims.machine_fp!==Wr())return{tier:"free",invalid_reason:"machine fingerprint mismatch \u2014 re-activate on this device"};let n=Gr(e.license_key);return n?.revoked?{tier:"free",invalid_reason:n.reason}:hd(e,t.claims)}function hd(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}}x();x();v();import{join as gn}from"node:path";var Ed=new Set(["pending","approved","rejected"]),Sd=new Set(["L1","L2","L3","L4","user"]),q_=gn(A,"links"),bd=gn(A,"suggestions"),Q_=gn(bd,"index.json");function zr(e){try{return JSON.parse(e)}catch{return e}}function Td(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:zr(e.evidence),approved:e.approved===1,created_at:e.created_at,updated_at:e.updated_at}}function yd(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:zr(e.evidence),status:e.status,inferred_by:e.inferred_by,created_at:e.created_at,decided_at:e.decided_at}}function wd(e){if(!Sd.has(e))throw new Error(`invalid inferred_by: ${e}`)}function fn(e){return _().prepare(`SELECT * FROM session_links
1022
1027
  WHERE source_session_id = ? OR target_session_id = ?
1023
- ORDER BY confidence DESC, updated_at DESC`).all(e,e).map(gd)}function _n(e={}){let t=E(),n=[],s=[];if(e.status){if(!ud.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&&(_d(e.inferredBy),n.push("inferred_by = ?"),s.push(e.inferredBy));let r=n.length?`WHERE ${n.join(" AND ")}`:"",i=Math.max(1,Math.min(5e3,e.limit??1e3));return t.prepare(`SELECT * FROM session_link_suggestions ${r}
1028
+ ORDER BY confidence DESC, updated_at DESC`).all(e,e).map(Td)}function _n(e={}){let t=_(),n=[],s=[];if(e.status){if(!Ed.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&&(wd(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}
1024
1029
  ORDER BY confidence DESC, created_at DESC
1025
- LIMIT ?`).all(...s,i).map(fd)}var hd=4e3,Ed=2,Sd=30,Td=.2,bd={citation:1,wiki_link:.9,similar:.7,skill_track:.5,bug_pattern:.4,temporal_proximity:.3};function at(e){return e?Math.ceil(e.length/4):0}function zr(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/Sd);return Math.max(Td,t)}function Yr(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 Kr(e){return E().prepare(`SELECT s.id,
1030
+ LIMIT ?`).all(...s,o).map(yd)}var Rd=4e3,Ad=2,Nd=30,Ld=.2,kd={citation:1,wiki_link:.9,similar:.7,skill_track:.5,bug_pattern:.4,temporal_proximity:.3};function at(e){return e?Math.ceil(e.length/4):0}function Yr(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/Nd);return Math.max(Ld,t)}function Kr(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 Jr(e){return _().prepare(`SELECT s.id,
1026
1031
  NULLIF(sa.alias, '') AS alias,
1027
1032
  s.auto_title,
1028
1033
  s.auto_title_source,
@@ -1033,26 +1038,26 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
1033
1038
  FROM sessions s
1034
1039
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1035
1040
  LEFT JOIN projects p ON p.id = s.project_id
1036
- WHERE s.id = ?`).get(e)??null}function Jr(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 Vr(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 yd(e){let n=E().prepare(`SELECT id, auto_title, started_at
1041
+ WHERE s.id = ?`).get(e)??null}function Vr(e){let n=_().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 qr(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 xd(e){let n=_().prepare(`SELECT id, auto_title, started_at
1037
1042
  FROM sessions
1038
1043
  WHERE project_id = ?
1039
- ORDER BY COALESCE(started_at, ''), id`).all(e),s=new Set,r=new Set,i=[];for(let p of n){if(!p.auto_title||!p.auto_title.startsWith("/")){i.push({id:p.id,brand:null,skill:null});continue}let g=p.auto_title.split(" \xB7 "),h=g[0].trim(),S=g.length>1?g.slice(1).join(" \xB7 ").trim():null;i.push({id:p.id,brand:S||null,skill:h||null}),S&&s.add(S),h&&r.add(h)}let o=[...s].sort(),a=new Map;o.forEach((p,g)=>a.set(p,g));let c=[...r].sort(),l=new Map;c.forEach((p,g)=>l.set(p,g));let d=new Map,m=new Map;for(let p of i){if(!p.brand||!p.skill)continue;let g=a.get(p.brand),h=l.get(p.skill);if(g===void 0||h===void 0)continue;let S=`${g}.${h}`,u=(d.get(S)??0)+1;d.set(S,u),m.set(p.id,`${g}.${h}.${u}`)}return{byId:m}}function wd(e){return{table:e!==null?yd(e):null,originProjectId:e,cache:new Map}}function ct(e,t){let n=e.cache.get(t);if(n)return n;let s=Kr(t);if(!s)return null;let r=e.table&&s.project_id===e.originProjectId?e.table.byId.get(t)??null:null,i={session_id:s.id,title:Vr(s),decimal:r,summary:Jr(s.id),project:s.project,started_at:s.started_at};return e.cache.set(t,i),i}function Rd(e,t){let s=E().prepare(`SELECT DISTINCT te.parent_session_id AS pid
1044
+ ORDER BY COALESCE(started_at, ''), id`).all(e),s=new Set,r=new Set,o=[];for(let u of n){if(!u.auto_title||!u.auto_title.startsWith("/")){o.push({id:u.id,brand:null,skill:null});continue}let g=u.auto_title.split(" \xB7 "),h=g[0].trim(),E=g.length>1?g.slice(1).join(" \xB7 ").trim():null;o.push({id:u.id,brand:E||null,skill:h||null}),E&&s.add(E),h&&r.add(h)}let i=[...s].sort(),a=new Map;i.forEach((u,g)=>a.set(u,g));let c=[...r].sort(),l=new Map;c.forEach((u,g)=>l.set(u,g));let d=new Map,p=new Map;for(let u of o){if(!u.brand||!u.skill)continue;let g=a.get(u.brand),h=l.get(u.skill);if(g===void 0||h===void 0)continue;let E=`${g}.${h}`,S=(d.get(E)??0)+1;d.set(E,S),p.set(u.id,`${g}.${h}.${S}`)}return{byId:p}}function Od(e){return{table:e!==null?xd(e):null,originProjectId:e,cache:new Map}}function ct(e,t){let n=e.cache.get(t);if(n)return n;let s=Jr(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:qr(s),decimal:r,summary:Vr(s.id),project:s.project,started_at:s.started_at};return e.cache.set(t,o),o}function Id(e,t){let s=_().prepare(`SELECT DISTINCT te.parent_session_id AS pid
1040
1045
  FROM thread_edges te
1041
1046
  WHERE te.session_id = ?
1042
- AND te.parent_session_id IS NOT NULL`).all(t),r=[];for(let i of s){if(!i.pid)continue;let o=ct(e,i.pid);o&&r.push(o)}return r}function Ad(e,t){let s=E().prepare(`SELECT DISTINCT te.session_id AS sid
1047
+ AND te.parent_session_id IS NOT NULL`).all(t),r=[];for(let o of s){if(!o.pid)continue;let i=ct(e,o.pid);i&&r.push(i)}return r}function vd(e,t){let s=_().prepare(`SELECT DISTINCT te.session_id AS sid
1043
1048
  FROM thread_edges te
1044
- WHERE te.parent_session_id = ?`).all(t),r=[];for(let i of s){if(!i.sid)continue;let o=ct(e,i.sid);o&&r.push(o)}return r}function qr(e){let t=bd[e.linkType]??.5,n=be(e.confidence),s=t*n,r=zr(e.daysApart),i=e.embeddingCosine??.5,o=be(e.pagerank);if(e.scoring==="pagerank")return be(o);if(e.scoring==="embedding-rerank")return e.embeddingCosine===null?be(s):be(i);let a=.35*s+.2*r+.2*i+.25*o;return be(a)}function be(e){return!Number.isFinite(e)||e<0?0:e>1?1:e}function Nd(e,t,n,s,r){let i=new Map;function o(a,c){if(a===c)return;let l=i.get(a);l||(l=new Set,i.set(a,l)),l.add(c)}for(let a of t)o(a.source_session_id,a.target_session_id),o(a.target_session_id,a.source_session_id);for(let a of n)o(e,a.session_id);for(let a of n)o(a.session_id,e);for(let a of s)o(e,a.session_id);for(let a of s)o(a.session_id,e);if(r>1){let a=new Set([e]),c=new Set([e]);for(let l=1;l<r;l++){let d=new Set;for(let m of a){let p=i.get(m);if(p)for(let g of p){if(c.has(g))continue;let h=fn(g).filter(S=>S.approved);for(let S of h)o(S.source_session_id,S.target_session_id),o(S.target_session_id,S.source_session_id);c.add(g),d.add(g)}}if(d.size===0)break;for(let m of d)a.add(m)}}return{edges:i}}function Ld(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 i=1/r.length,o=new Map(r.map(l=>[l,i]));for(let l=0;l<n;l++){let d=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=(o.get(m)??0)/p.size;for(let h of p)d.set(h,(d.get(h)??0)+s*g)}o=d}let a=0;for(let l of o.values())l>a&&(a=l);if(a<=0)return o;let c=new Map;for(let[l,d]of o)c.set(l,d/a);return c}var Qr=240;function Zr(e,t){let n=e.replace(/\s+/g," ").trim();return n.length<=t?n:`${n.slice(0,t-1).trimEnd()}\u2026`}function kd(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 i=Zr(e.summary,Qr);return`${r}
1045
- ${i}`}return r}function xd(e,t,n){let s=[],r=[],i=0,o=e.decimal?`${e.decimal}: `:"",a=`# Neighborhood for ${e.session_id} (${o}${e.title})`;if(s.push(a),i+=at(a),e.summary){let c=Zr(e.summary,Qr*4);s.push(c),i+=at(c)}s.push("");for(let c of t){if(c.refs.length===0)continue;let l=`## ${c.heading}`,d=at(l),m=[],p=0;for(let g of c.refs){let h=kd(g),S=at(h);if(i+d+p+S>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(h),p+=S}if(m.length>0){s.push(l);for(let g of m)s.push(g);s.push(""),i+=d+p}}for(;s.length>0&&s[s.length-1]==="";)s.pop();return{bundle:s.join(`
1049
+ WHERE te.parent_session_id = ?`).all(t),r=[];for(let o of s){if(!o.sid)continue;let i=ct(e,o.sid);i&&r.push(i)}return r}function Qr(e){let t=kd[e.linkType]??.5,n=Te(e.confidence),s=t*n,r=Yr(e.daysApart),o=e.embeddingCosine??.5,i=Te(e.pagerank);if(e.scoring==="pagerank")return Te(i);if(e.scoring==="embedding-rerank")return e.embeddingCosine===null?Te(s):Te(o);let a=.35*s+.2*r+.2*o+.25*i;return Te(a)}function Te(e){return!Number.isFinite(e)||e<0?0:e>1?1:e}function Cd(e,t,n,s,r){let o=new Map;function i(a,c){if(a===c)return;let l=o.get(a);l||(l=new Set,o.set(a,l)),l.add(c)}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]),c=new Set([e]);for(let l=1;l<r;l++){let d=new Set;for(let p of a){let u=o.get(p);if(u)for(let g of u){if(c.has(g))continue;let h=fn(g).filter(E=>E.approved);for(let E of h)i(E.source_session_id,E.target_session_id),i(E.target_session_id,E.source_session_id);c.add(g),d.add(g)}}if(d.size===0)break;for(let p of d)a.add(p)}}return{edges:o}}function Dd(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 d=new Map(r.map(p=>[p,(1-s)/r.length]));for(let p of r){let u=e.edges.get(p);if(!u||u.size===0)continue;let g=(i.get(p)??0)/u.size;for(let h of u)d.set(h,(d.get(h)??0)+s*g)}i=d}let a=0;for(let l of i.values())l>a&&(a=l);if(a<=0)return i;let c=new Map;for(let[l,d]of i)c.set(l,d/a);return c}var Zr=240;function eo(e,t){let n=e.replace(/\s+/g," ").trim();return n.length<=t?n:`${n.slice(0,t-1).trimEnd()}\u2026`}function Md(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=eo(e.summary,Zr);return`${r}
1050
+ ${o}`}return r}function Pd(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+=at(a),e.summary){let c=eo(e.summary,Zr*4);s.push(c),o+=at(c)}s.push("");for(let c of t){if(c.refs.length===0)continue;let l=`## ${c.heading}`,d=at(l),p=[],u=0;for(let g of c.refs){let h=Md(g),E=at(h);if(o+d+u+E>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}p.push(h),u+=E}if(p.length>0){s.push(l);for(let g of p)s.push(g);s.push(""),o+=d+u}}for(;s.length>0&&s[s.length-1]==="";)s.pop();return{bundle:s.join(`
1046
1051
  `)+`
1047
- `,budgetUsed:i,truncated:r}}function Od(e,t,n,s,r,i){let o=[];for(let a of n){if(s&&!s.has(a.link_type))continue;let c=null;if(a.source_session_id===t.session_id?c=a.target_session_id:a.target_session_id===t.session_id&&(c=a.source_session_id),!c)continue;let l=ct(e,c);if(!l)continue;let d=Yr(t.started_at,l.started_at),m=qr({confidence:a.confidence,linkType:a.link_type,daysApart:d,embeddingCosine:null,pagerank:i.get(c)??0,scoring:r});o.push({...l,score:m,evidence:`(suggestion, ${a.inferred_by}) confidence=${a.confidence.toFixed(2)} ${Math.round(d)}d apart`,link_type:a.link_type})}return o}function ei(e,t={}){let n=Math.max(100,Math.floor(t.budget??hd)),s=t.scoring??"hybrid",r=Math.max(1,Math.min(5,t.maxDepth??Ed)),i=t.includeWikiLinks??!0,o=t.includeSuggestions??!1,a=t.edgeTypes?new Set(t.edgeTypes):null,c=Kr(e);if(!c)throw new Error(`session not found: ${e}`);let l=wd(c.project_id),d={session_id:c.id,title:Vr(c),decimal:l.table?.byId.get(c.id)??null,summary:Jr(c.id),project:c.project,started_at:c.started_at};l.cache.set(c.id,d);let m=Rd(l,e),p=Ad(l,e),g=fn(e).filter(A=>A.approved).filter(A=>!a||a.has(A.link_type)).filter(A=>i||A.link_type!=="wiki_link"),h=Nd(e,g,m,p,r),S=Ld(h),u=[],f=[],T=[],R=[];for(let A of g){let H=A.source_session_id===e?A.target_session_id:A.source_session_id,J=ct(l,H);if(!J)continue;let ie=Yr(d.started_at,J.started_at),ue=qr({confidence:A.confidence,linkType:A.link_type,daysApart:ie,embeddingCosine:null,pagerank:S.get(H)??0,scoring:s}),gt=zr(ie),X=`${A.link_type} confidence=${A.confidence.toFixed(2)} recency=${gt.toFixed(2)} (${Math.round(ie)}d apart)`,Me={...J,score:ue,evidence:X,link_type:A.link_type};A.link_type==="citation"?u.push(Me):A.link_type==="similar"?f.push(Me):A.link_type==="wiki_link"?R.push(Me):T.push(Me)}if(o){let A=_n({sourceSessionId:e,status:"pending",limit:100}),H=_n({targetSessionId:e,status:"pending",limit:100}),J=[...A,...H],ie=new Set,ue=J.filter(X=>ie.has(X.id)?!1:(ie.add(X.id),!0)),gt=Od(l,d,ue,a,s,S);for(let X of gt)X.link_type==="citation"?u.push(X):X.link_type==="similar"?f.push(X):X.link_type==="wiki_link"?R.push(X):T.push(X)}let k=(A,H)=>H.score-A.score;u.sort(k),f.sort(k),T.sort(k),R.sort(k);let L=xd(d,[{heading:"Parents",refs:m},{heading:"Children",refs:p},{heading:"Citations (approved)",refs:u},{heading:"Similar sessions",refs:f},{heading:"Cousins (skill track + temporal)",refs:T},{heading:"Wiki links (manual)",refs:R}],n);return{origin:d,parents:m,children:p,citations:u,similar:f,cousins:T,wikiLinks:R,bundle:L.bundle,budgetUsed:L.budgetUsed,budgetRemaining:Math.max(0,n-L.budgetUsed),truncated:L.truncated}}import{readFileSync as gp,realpathSync as vo}from"node:fs";import{dirname as fp,join as _p}from"node:path";var hp=(()=>{try{let e=fp(Do(import.meta.url));return _p(e,"..","..","package.json")}catch{return"package.json"}})(),Ep=(()=>{try{return JSON.parse(gp(hp,"utf8")).version??"0.0.0"}catch{return"0.0.0"}})();function Sp(){let e=process.env.RECALL_MCP_ALLOW_WRITES;return e==="1"||e==="true"}var Tp=[/no such table:\s*vec_chunks/i,/database is locked/i];function bp(e){return e instanceof Error?Tp.some(t=>t.test(e.message)):!1}async function Pn(e){try{return await e()}catch(t){if(!bp(t))throw t;return await new Promise(n=>setTimeout(n,25)),await e()}}function O(e){return{content:[{type:"text",text:JSON.stringify(e,null,2)}]}}function Fn(e){return{content:[{type:"text",text:e}]}}function K(e){return{content:[{type:"text",text:e}],isError:!0}}function yp(e){if(e instanceof Y)switch(e.kind){case"bundle-missing":return"embedder bundle missing \u2014 dev install requires `npm run build:cli`";case"platform-unsupported":return"embedder not available on this platform \u2014 run `recall semantic install` for setup";case"load-failed":return"embedder load failed \u2014 see daemon logs for details";default:return"embedder not available \u2014 run `recall semantic install`"}return"embedder load failed \u2014 see daemon logs for details"}async function wp(){if((await mn()).tier!=="pro")return O({upgrade_required:!0,reason:"Semantic vector search requires Pro.",buy_url:"https://clauderecall.com/pro"});if(!it())return O({error:"embedder_model_missing",reason:"Run `recall semantic install` to download the embedding model."});if(!Ie().loaded)try{await rn()}catch(t){return O({error:"embedder_load_failed",reason:yp(t)})}return null}async function Co(){try{return(await mn()).tier!=="pro"||!it()?!1:(Ie().loaded||await rn(),!0)}catch(e){return e instanceof Y||process.stderr.write(`[mcp] isVectorLaneReady failed unexpectedly: ${e instanceof Error?e.message:String(e)}
1048
- `),!1}}function Rp(){let e=new pp({name:"claude-recall",version:Ep}),t=Sp();if(e.registerTool("list_projects",{title:"List projects",description:"Every Claude Code project currently indexed by Recall, with session and message counts and the most recent activity timestamp.",inputSchema:{}},async()=>{let s=E().prepare(`SELECT p.name,
1052
+ `,budgetUsed:o,truncated:r}}function Fd(e,t,n,s,r,o){let i=[];for(let a of n){if(s&&!s.has(a.link_type))continue;let c=null;if(a.source_session_id===t.session_id?c=a.target_session_id:a.target_session_id===t.session_id&&(c=a.source_session_id),!c)continue;let l=ct(e,c);if(!l)continue;let d=Kr(t.started_at,l.started_at),p=Qr({confidence:a.confidence,linkType:a.link_type,daysApart:d,embeddingCosine:null,pagerank:o.get(c)??0,scoring:r});i.push({...l,score:p,evidence:`(suggestion, ${a.inferred_by}) confidence=${a.confidence.toFixed(2)} ${Math.round(d)}d apart`,link_type:a.link_type})}return i}function to(e,t={}){let n=Math.max(100,Math.floor(t.budget??Rd)),s=t.scoring??"hybrid",r=Math.max(1,Math.min(5,t.maxDepth??Ad)),o=t.includeWikiLinks??!0,i=t.includeSuggestions??!1,a=t.edgeTypes?new Set(t.edgeTypes):null,c=Jr(e);if(!c)throw new Error(`session not found: ${e}`);let l=Od(c.project_id),d={session_id:c.id,title:qr(c),decimal:l.table?.byId.get(c.id)??null,summary:Vr(c.id),project:c.project,started_at:c.started_at};l.cache.set(c.id,d);let p=Id(l,e),u=vd(l,e),g=fn(e).filter(R=>R.approved).filter(R=>!a||a.has(R.link_type)).filter(R=>o||R.link_type!=="wiki_link"),h=Cd(e,g,p,u,r),E=Dd(h),S=[],m=[],b=[],w=[];for(let R of g){let M=R.source_session_id===e?R.target_session_id:R.source_session_id,X=ct(l,M);if(!X)continue;let F=Kr(d.started_at,X.started_at),ue=Qr({confidence:R.confidence,linkType:R.link_type,daysApart:F,embeddingCosine:null,pagerank:E.get(M)??0,scoring:s}),gt=Yr(F),z=`${R.link_type} confidence=${R.confidence.toFixed(2)} recency=${gt.toFixed(2)} (${Math.round(F)}d apart)`,Me={...X,score:ue,evidence:z,link_type:R.link_type};R.link_type==="citation"?S.push(Me):R.link_type==="similar"?m.push(Me):R.link_type==="wiki_link"?w.push(Me):b.push(Me)}if(i){let R=_n({sourceSessionId:e,status:"pending",limit:100}),M=_n({targetSessionId:e,status:"pending",limit:100}),X=[...R,...M],F=new Set,ue=X.filter(z=>F.has(z.id)?!1:(F.add(z.id),!0)),gt=Fd(l,d,ue,a,s,E);for(let z of gt)z.link_type==="citation"?S.push(z):z.link_type==="similar"?m.push(z):z.link_type==="wiki_link"?w.push(z):b.push(z)}let L=(R,M)=>M.score-R.score;S.sort(L),m.sort(L),b.sort(L),w.sort(L);let N=Pd(d,[{heading:"Parents",refs:p},{heading:"Children",refs:u},{heading:"Citations (approved)",refs:S},{heading:"Similar sessions",refs:m},{heading:"Cousins (skill track + temporal)",refs:b},{heading:"Wiki links (manual)",refs:w}],n);return{origin:d,parents:p,children:u,citations:S,similar:m,cousins:b,wikiLinks:w,bundle:N.bundle,budgetUsed:N.budgetUsed,budgetRemaining:Math.max(0,n-N.budgetUsed),truncated:N.truncated}}import{readFileSync as Np,realpathSync as Ui}from"node:fs";import{dirname as Lp,join as kp}from"node:path";var xp=(()=>{try{let e=Lp(Hi(import.meta.url));return kp(e,"..","..","package.json")}catch{return"package.json"}})(),Op=(()=>{try{return JSON.parse(Np(xp,"utf8")).version??"0.0.0"}catch{return"0.0.0"}})();function Ip(){let e=process.env.RECALL_MCP_ALLOW_WRITES;return e==="1"||e==="true"}var vp=[/no such table:\s*vec_chunks/i,/database is locked/i];function Cp(e){return e instanceof Error?vp.some(t=>t.test(e.message)):!1}async function Fn(e){try{return await e()}catch(t){if(!Cp(t))throw t;return await new Promise(n=>setTimeout(n,25)),await e()}}function O(e){return{content:[{type:"text",text:JSON.stringify(e,null,2)}]}}function $n(e){return{content:[{type:"text",text:e}]}}function V(e){return{content:[{type:"text",text:e}],isError:!0}}function Dp(e){if(e instanceof J)switch(e.kind){case"bundle-missing":return"embedder bundle missing \u2014 dev install requires `npm run build:cli`";case"platform-unsupported":return"embedder not available on this platform \u2014 run `recall semantic install` for setup";case"load-failed":return"embedder load failed \u2014 see daemon logs for details";default:return"embedder not available \u2014 run `recall semantic install`"}return"embedder load failed \u2014 see daemon logs for details"}async function Mp(){if((await mn()).tier!=="pro")return O({upgrade_required:!0,reason:"Semantic vector search requires Pro.",buy_url:"https://clauderecall.com/pro"});if(!ot())return O({error:"embedder_model_missing",reason:"Run `recall semantic install` to download the embedding model."});if(!Ie().loaded)try{await rn()}catch(t){return O({error:"embedder_load_failed",reason:Dp(t)})}return null}async function ji(){try{return(await mn()).tier!=="pro"||!ot()?!1:(Ie().loaded||await rn(),!0)}catch(e){return e instanceof J||process.stderr.write(`[mcp] isVectorLaneReady failed unexpectedly: ${e instanceof Error?e.message:String(e)}
1053
+ `),!1}}function Pp(){let e=new Rp({name:"claude-recall",version:Op}),t=Ip();if(e.registerTool("list_projects",{title:"List projects",description:"Every Claude Code project currently indexed by Recall, with session and message counts and the most recent activity timestamp.",inputSchema:{}},async()=>{let s=_().prepare(`SELECT p.name,
1049
1054
  COUNT(s.id) AS session_count,
1050
1055
  COALESCE(SUM(s.message_count), 0) AS message_count,
1051
1056
  MAX(s.started_at) AS latest
1052
1057
  FROM projects p
1053
1058
  LEFT JOIN sessions s ON s.project_id = p.id
1054
1059
  GROUP BY p.id
1055
- ORDER BY MAX(COALESCE(s.started_at, '')) DESC`).all();return O(s)}),e.registerTool("list_sessions",{title:"List sessions",description:"Recent sessions with alias, tags, and message counts. Optional filters for project, tag, and date range.",inputSchema:{project:N.string().optional().describe("Substring match against project name or decoded filesystem path."),tag:N.string().optional().describe("Only sessions carrying this tag (leading # optional)."),since:N.string().optional().describe("Only sessions started at or after this ISO timestamp or YYYY-MM-DD date."),until:N.string().optional().describe("Only sessions started at or before this ISO timestamp or YYYY-MM-DD date."),limit:N.number().int().min(1).max(500).optional()}},async({project:n,tag:s,since:r,until:i,limit:o})=>{let a=E(),c={limit:o??100},l="s.message_count > 2";if(n&&(l+=" AND (p.name LIKE @proj OR p.decoded_path LIKE @proj)",c.proj=`%${n}%`),r&&(l+=" AND s.started_at >= @since",c.since=r),i&&(l+=" AND s.started_at <= @until",c.until=/^\d{4}-\d{2}-\d{2}$/.test(i)?`${i}T23:59:59.999Z`:i),s){let p=pe(s);p&&(l+=" AND s.id IN (SELECT session_id FROM session_tags WHERE tag = @tag)",c.tag=p)}let m=a.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
1060
+ ORDER BY MAX(COALESCE(s.started_at, '')) DESC`).all();return O(s)}),e.registerTool("list_sessions",{title:"List sessions",description:"Recent sessions with alias, tags, and message counts. Optional filters for project, tag, and date range.",inputSchema:{project:k.string().optional().describe("Substring match against project name or decoded filesystem path."),tag:k.string().optional().describe("Only sessions carrying this tag (leading # optional)."),since:k.string().optional().describe("Only sessions started at or after this ISO timestamp or YYYY-MM-DD date."),until:k.string().optional().describe("Only sessions started at or before this ISO timestamp or YYYY-MM-DD date."),limit:k.number().int().min(1).max(500).optional()}},async({project:n,tag:s,since:r,until:o,limit:i})=>{let a=_(),c={limit:i??100},l="s.message_count > 2";if(n&&(l+=" AND (p.name LIKE @proj OR p.decoded_path LIKE @proj)",c.proj=`%${n}%`),r&&(l+=" AND s.started_at >= @since",c.since=r),o&&(l+=" AND s.started_at <= @until",c.until=/^\d{4}-\d{2}-\d{2}$/.test(o)?`${o}T23:59:59.999Z`:o),s){let u=me(s);u&&(l+=" AND s.id IN (SELECT session_id FROM session_tags WHERE tag = @tag)",c.tag=u)}let p=a.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
1056
1061
  s.message_count, s.first_user_message, s.git_branch,
1057
1062
  NULLIF(sa.alias, '') AS alias,
1058
1063
  CASE WHEN sn.content IS NOT NULL AND sn.content != '' THEN 1 ELSE 0 END AS has_notes,
@@ -1067,7 +1072,7 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
1067
1072
  LEFT JOIN session_notes sn ON sn.session_id = s.id
1068
1073
  WHERE ${l}
1069
1074
  ORDER BY COALESCE(s.started_at, '') DESC
1070
- LIMIT @limit`).all(c).map(({tags_csv:p,...g})=>({...g,tags:p?p.split(","):[]}));return O(m)}),e.registerTool("list_tags",{title:"List tags",description:"Every tag currently applied to a session, with its count, most popular first.",inputSchema:{}},async()=>O(ts())),e.registerTool("search",{title:"Search messages",description:"Full-text search over every message in every indexed session. Use `#tag-name` tokens inside the query string to also filter by tag; plain terms are ANDed together. Pass `mode` to control the search lane: 'fts' = keyword BM25 only (always available, fastest), 'semantic' = vector embedding only (Pro + model installed; uses bge-base on-device), 'fused' = RRF-fused BM25 + vector (default; silently falls back to BM25-only when the vector lane is unavailable).",inputSchema:{query:N.string().describe("Text to find. Supports inline `#tag-name` tokens to narrow to sessions with the tag."),project:N.string().optional().describe("Substring match against project name or path."),limit:N.number().int().min(1).max(200).optional(),mode:N.enum(["fts","semantic","fused"]).optional().describe("Search lane: 'fts' (keyword only), 'semantic' (vector only \u2014 requires Pro + model installed), 'fused' (RRF-fused BM25 + vector, default; falls back to BM25 if vector is unavailable).")}},async({query:n,project:s,limit:r,mode:i})=>{let o=E(),a=n.trim();if(!a)return O({query:"",hits:[],tags:[],mode:i??"fused"});let c=i??"fused",l=a.split(/\s+/).filter(Boolean),d=l.filter(f=>f.startsWith("#")).map(pe).filter(f=>!!f),p=l.filter(f=>!f.startsWith("#")).map(f=>`"${f.replace(/"/g,"")}"`).join(" "),g=Math.max(1,Math.min(200,r??30));if(!p&&d.length>0){let f=`
1075
+ LIMIT @limit`).all(c).map(({tags_csv:u,...g})=>({...g,tags:u?u.split(","):[]}));return O(p)}),e.registerTool("list_tags",{title:"List tags",description:"Every tag currently applied to a session, with its count, most popular first.",inputSchema:{}},async()=>O(ns())),e.registerTool("search",{title:"Search messages",description:"Full-text search over every message in every indexed session. Use `#tag-name` tokens inside the query string to also filter by tag; plain terms are ANDed together. Pass `mode` to control the search lane: 'fts' = keyword BM25 only (always available, fastest), 'semantic' = vector embedding only (Pro + model installed; uses bge-base on-device), 'fused' = RRF-fused BM25 + vector (default; silently falls back to BM25-only when the vector lane is unavailable).",inputSchema:{query:k.string().describe("Text to find. Supports inline `#tag-name` tokens to narrow to sessions with the tag."),project:k.string().optional().describe("Substring match against project name or path."),limit:k.number().int().min(1).max(200).optional(),mode:k.enum(["fts","semantic","fused"]).optional().describe("Search lane: 'fts' (keyword only), 'semantic' (vector only \u2014 requires Pro + model installed), 'fused' (RRF-fused BM25 + vector, default; falls back to BM25 if vector is unavailable).")}},async({query:n,project:s,limit:r,mode:o})=>{let i=_(),a=n.trim();if(!a)return O({query:"",hits:[],tags:[],mode:o??"fused"});let c=o??"fused";if(a.length>500)return O({query:a,hits:[],tags:[],mode:c,error:"query_too_long",reason:"Query too long (max 500 chars). Shorten the search text."});let l=a.split(/\s+/).filter(Boolean),d=l.filter(T=>T.startsWith("#")).map(me).filter(T=>!!T),p=l.filter(T=>!T.startsWith("#")),u=p.length>20,g=u?p.slice(0,20):p,h=u?{truncated:!0}:{},E=g.map(T=>`"${T.replace(/"/g,"")}"`).join(" "),S=Math.max(1,Math.min(200,r??30));if(!E&&d.length>0){let T=`
1071
1076
  SELECT s.id AS session_id,
1072
1077
  s.id AS message_uuid,
1073
1078
  p.name AS project,
@@ -1080,22 +1085,23 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
1080
1085
  JOIN projects p ON p.id = s.project_id
1081
1086
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1082
1087
  WHERE 1=1
1083
- `,T={limit:g};return s&&(f+=" AND (p.name LIKE @proj OR p.decoded_path LIKE @proj)",T.proj=`%${s}%`),d.forEach((R,k)=>{f+=` AND s.id IN (SELECT session_id FROM session_tags WHERE tag = @tag_${k})`,T[`tag_${k}`]=R}),f+=" ORDER BY COALESCE(s.started_at, '') DESC LIMIT @limit",O({query:a,hits:o.prepare(f).all(T),tags:d})}if(!p)return O({query:a,hits:[],tags:d,mode:c});if(c==="semantic"){if(!await Co())return O({query:a,hits:[],tags:d,mode:"semantic",error:"semantic_unavailable",reason:'Semantic-only search requires Pro tier with the embedder model installed. Run `recall semantic install`, or call this tool with mode="fts" or mode="fused" for a BM25 fallback.'});try{let T=(await Pn(()=>dn(a,g))).map(R=>({session_id:R.sessionId,snippet:R.text,matched_via:"vector"}));return O({query:a,hits:T,tags:d,mode:"semantic"})}catch(f){return f instanceof ge?O({query:a,hits:[],tags:d,mode:"semantic",error:"corpus_too_large",message:f.message,meta:{rowCount:f.rowCount,limit:f.limit,env:"RECALL_KNN_MAX_CORPUS"}}):O({query:a,hits:[],tags:d,mode:"semantic",error:"semantic_failed",reason:f instanceof Error?f.message:"vector search failed"})}}let h=`
1084
- SELECT m.session_id AS session_id,
1085
- m.uuid AS message_uuid,
1086
- p.name AS project,
1087
- s.started_at,
1088
- snippet(messages_fts, 0, '<<', '>>', '\u2026', 20) AS snippet,
1089
- m.role,
1090
- m.timestamp,
1091
- NULLIF(sa.alias, '') AS alias
1092
- FROM messages_fts
1093
- JOIN messages m ON m.rowid = messages_fts.rowid
1094
- JOIN sessions s ON s.id = m.session_id
1095
- JOIN projects p ON p.id = s.project_id
1096
- LEFT JOIN session_aliases sa ON sa.session_id = s.id
1097
- WHERE messages_fts MATCH @fts
1098
- `,S={fts:p,limit:g};s&&(h+=" AND (p.name LIKE @proj OR p.decoded_path LIKE @proj)",S.proj=`%${s}%`),d.forEach((f,T)=>{h+=` AND s.id IN (SELECT session_id FROM session_tags WHERE tag = @tag_${T})`,S[`tag_${T}`]=f}),h+=" ORDER BY bm25(messages_fts) LIMIT @limit";let u=o.prepare(h).all(S);if(c==="fts")return O({query:a,hits:u,tags:d,mode:"fts"});if(await Co())try{let f=await Pn(()=>dn(a,g)),T=u.map(L=>({id:String(L.session_id),data:L,lane:"bm25"})),R=f.map(L=>({id:L.sessionId,data:{session_id:L.sessionId,snippet:L.text,matched_via:"vector"},lane:"vector"})),w=Or([T,R]).slice(0,g).map(L=>({...L.data,session_id:L.id,rrf_score:L.score,lanes:L.lanes}));return O({query:a,hits:w,tags:d,fusion:"rrf",mode:"fused"})}catch(f){if(f instanceof ge)return O({query:a,hits:u,tags:d,mode:"fused",error:"corpus_too_large",message:f.message,meta:{rowCount:f.rowCount,limit:f.limit,env:"RECALL_KNN_MAX_CORPUS"}})}return O({query:a,hits:u,tags:d,mode:"fused"})}),e.registerTool("find_similar_sessions",{title:"Find similar sessions",description:"Find sessions semantically similar to a given session using vector embeddings (Pro-only). Returns related sessions ranked by cosine similarity.",inputSchema:{session_id:N.string().uuid().describe("Session UUID to find similar sessions for."),limit:N.number().int().min(1).max(50).optional().describe("Max results (default 10)."),min_cosine:N.number().min(0).max(1).optional().describe("Minimum cosine similarity threshold (default 0.65).")}},async({session_id:n,limit:s,min_cosine:r})=>{let i=await wp();if(i)return i;try{let o=await Pn(()=>xr(n,s??10,r??.65));return O({session_id:n,similar:o})}catch(o){return o instanceof ge?O({session_id:n,similar:[],error:"corpus_too_large",message:o.message,meta:{rowCount:o.rowCount,limit:o.limit,env:"RECALL_KNN_MAX_CORPUS"}}):K(o instanceof Error?o.message:"vector search failed")}}),e.registerTool("semantic_status",{title:"Semantic search status",description:"Health snapshot of the semantic vector search tier: model status, worker status, queue depth.",inputSchema:{}},async()=>{let n=Ie(),s=Dr(),r=it();return O({embedder:n,worker:s,modelInstalled:r})}),e.registerTool("get_session",{title:"Get session transcript",description:"Return the full metadata and ordered messages for a session. Accepts a full UUID or an 8+-character id prefix.",inputSchema:{id:N.string().describe("Session id (full UUID or 8+-character prefix).")}},async({id:n})=>{let s=z(n);if(!s)return K(`session not found or prefix ambiguous: ${n}`);let r=E(),i=r.prepare(`SELECT s.id, s.project_id, s.started_at, s.ended_at,
1088
+ `,N={limit:S};s&&(T+=" AND (p.name LIKE @proj OR p.decoded_path LIKE @proj)",N.proj=`%${s}%`),d.forEach((R,M)=>{T+=` AND s.id IN (SELECT session_id FROM session_tags WHERE tag = @tag_${M})`,N[`tag_${M}`]=R}),T+=" ORDER BY COALESCE(s.started_at, '') DESC LIMIT @limit";try{return O({query:a,hits:i.prepare(T).all(N),tags:d})}catch(R){return console.error(`[mcp] tag-only query failed: ${R instanceof Error?R.message:String(R)}`),O({query:a,hits:[],tags:d,error:"search_failed",reason:R instanceof Error?R.message:String(R)})}}if(!E)return O({query:a,hits:[],tags:d,mode:c});let m=()=>{try{let T=`
1089
+ SELECT m.session_id AS session_id,
1090
+ m.uuid AS message_uuid,
1091
+ p.name AS project,
1092
+ s.started_at,
1093
+ snippet(messages_fts, 0, '<<', '>>', '\u2026', 20) AS snippet,
1094
+ m.role,
1095
+ m.timestamp,
1096
+ NULLIF(sa.alias, '') AS alias
1097
+ FROM messages_fts
1098
+ JOIN messages m ON m.rowid = messages_fts.rowid
1099
+ JOIN sessions s ON s.id = m.session_id
1100
+ JOIN projects p ON p.id = s.project_id
1101
+ LEFT JOIN session_aliases sa ON sa.session_id = s.id
1102
+ WHERE messages_fts MATCH @fts
1103
+ `,N={fts:E,limit:S};return s&&(T+=" AND (p.name LIKE @proj OR p.decoded_path LIKE @proj)",N.proj=`%${s}%`),d.forEach((R,M)=>{T+=` AND s.id IN (SELECT session_id FROM session_tags WHERE tag = @tag_${M})`,N[`tag_${M}`]=R}),T+=" ORDER BY bm25(messages_fts) LIMIT @limit",{hits:i.prepare(T).all(N)}}catch(T){let N=T instanceof Error?T.message:"FTS search failed";return process.stderr.write(`[mcp] runFtsSearch failed: ${N}
1104
+ `),{hits:[],error:"search_failed",reason:N}}};if(c==="semantic"){if(!await ji()){let T=m();return O({query:a,tags:d,mode:"fts",degraded_from:"semantic",error:"semantic_unavailable",reason:'Semantic-only search needs Pro tier with the embedder model installed; fell back to BM25 keyword results. Run `recall semantic install` to enable vector search, or call with mode="fts" to silence this notice.',...h,...T})}try{let N=(await Fn(()=>dn(a,S))).map(R=>({session_id:R.sessionId,snippet:R.text,matched_via:"vector"}));return O({query:a,hits:N,tags:d,mode:"semantic"})}catch(T){if(T instanceof fe){let R=m();return O({query:a,tags:d,mode:"fts",degraded_from:"semantic",error:"corpus_too_large",reason:"Vector index is too large for an unindexed kNN; fell back to BM25 keyword results. Scope the search to a project or raise RECALL_KNN_MAX_CORPUS to use the vector lane.",message:T.message,meta:{rowCount:T.rowCount,limit:T.limit,env:"RECALL_KNN_MAX_CORPUS"},...h,...R})}let N=m();return O({query:a,tags:d,mode:"fts",degraded_from:"semantic",error:"semantic_failed",reason:"Vector search failed; fell back to BM25 keyword results. "+(T instanceof Error?T.message:"vector search failed"),...h,...N})}}let b=m(),w=b.hits,L=b.error?{error:b.error,reason:b.reason}:{};if(c==="fts")return O({query:a,hits:w,tags:d,mode:"fts",...h,...L});if(await ji())try{let T=await Fn(()=>dn(a,S)),N=w.map(F=>({id:String(F.session_id),data:F,lane:"bm25"})),R=T.map(F=>({id:F.sessionId,data:{session_id:F.sessionId,snippet:F.text,matched_via:"vector"},lane:"vector"})),X=Ir([N,R]).slice(0,S).map(F=>({...F.data,session_id:F.id,rrf_score:F.score,lanes:F.lanes}));return O({query:a,hits:X,tags:d,fusion:"rrf",mode:"fused",...h,...L})}catch(T){if(T instanceof fe)return O({query:a,hits:w,tags:d,mode:"fused",degraded:!0,degraded_from:"fused",error:"corpus_too_large",reason:"Vector lane skipped (index too large for an unindexed kNN); returning BM25 keyword results only.",message:T.message,meta:{rowCount:T.rowCount,limit:T.limit,env:"RECALL_KNN_MAX_CORPUS"},...L})}return O({query:a,hits:w,tags:d,mode:"fused",...h,...L})}),e.registerTool("find_similar_sessions",{title:"Find similar sessions",description:"Find sessions semantically similar to a given session using vector embeddings (Pro-only). Returns related sessions ranked by cosine similarity.",inputSchema:{session_id:k.string().uuid().describe("Session UUID to find similar sessions for."),limit:k.number().int().min(1).max(50).optional().describe("Max results (default 10)."),min_cosine:k.number().min(0).max(1).optional().describe("Minimum cosine similarity threshold (default 0.65).")}},async({session_id:n,limit:s,min_cosine:r})=>{let o=await Mp();if(o)return o;try{let i=await Fn(()=>Or(n,s??10,r??.65));return O({session_id:n,similar:i})}catch(i){return i instanceof fe?O({session_id:n,similar:[],error:"corpus_too_large",message:i.message,meta:{rowCount:i.rowCount,limit:i.limit,env:"RECALL_KNN_MAX_CORPUS"}}):V(i instanceof Error?i.message:"vector search failed")}}),e.registerTool("semantic_status",{title:"Semantic search status",description:"Health snapshot of the semantic vector search tier: model status, worker status, queue depth.",inputSchema:{}},async()=>{let n=Ie(),s=Mr(),r=ot();return O({embedder:n,worker:s,modelInstalled:r})}),e.registerTool("get_session",{title:"Get session transcript",description:"Return the full metadata and ordered messages for a session. Accepts a full UUID or an 8+-character id prefix.",inputSchema:{id:k.string().describe("Session id (full UUID or 8+-character prefix).")}},async({id:n})=>{let s=K(n);if(!s)return V(`session not found or prefix ambiguous: ${n}`);let r=_(),o=r.prepare(`SELECT s.id, s.project_id, s.started_at, s.ended_at,
1099
1105
  s.message_count, s.user_message_count, s.assistant_message_count,
1100
1106
  s.first_user_message, s.git_branch, s.version, s.indexed_at,
1101
1107
  p.name AS project_name,
@@ -1103,14 +1109,14 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
1103
1109
  FROM sessions s
1104
1110
  JOIN projects p ON p.id = s.project_id
1105
1111
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1106
- WHERE s.id = ?`).get(s);if(!i)return K(`session metadata missing for ${s}`);let o=$e(s),a=r.prepare(`SELECT uuid, type, role, timestamp, is_sidechain, content_text, tool_names
1112
+ WHERE s.id = ?`).get(s);if(!o)return V(`session metadata missing for ${s}`);let i=$e(s),a=r.prepare(`SELECT uuid, type, role, timestamp, is_sidechain, content_text, tool_names
1107
1113
  FROM messages WHERE session_id = ?
1108
- ORDER BY COALESCE(timestamp, ''), rowid`).all(s);return O({session:{...i,tags:o},messages:a})}),e.registerTool("context_for_session",{title:"Export session as context",description:"Render a past session as markdown ready to paste into a fresh Claude conversation. This is the flagship Recall operation: pipe any previous session back into a new chat as memory.",inputSchema:{id:N.string().describe("Session id (full UUID or 8+-character prefix)."),mode:N.enum(["condensed","full"]).optional().describe("`condensed` (default) strips tool-call JSON; `full` keeps everything."),includeSidechain:N.boolean().optional().describe("Include subagent / sidechain messages (default false)."),prelude:N.string().max(1e4).optional().describe("Optional header prepended above the transcript (max 10 000 chars)."),since:N.string().optional().describe("Only messages at or after this ISO timestamp.")}},async({id:n,mode:s,includeSidechain:r,prelude:i,since:o})=>{let a=z(n);if(!a)return K(`session not found or prefix ambiguous: ${n}`);let c=E(),l=c.prepare(`SELECT s.id, p.name AS project_name,
1114
+ ORDER BY COALESCE(timestamp, ''), rowid`).all(s);return O({session:{...o,tags:i},messages:a})}),e.registerTool("context_for_session",{title:"Export session as context",description:"Render a past session as markdown ready to paste into a fresh Claude conversation. This is the flagship Recall operation: pipe any previous session back into a new chat as memory.",inputSchema:{id:k.string().describe("Session id (full UUID or 8+-character prefix)."),mode:k.enum(["condensed","full"]).optional().describe("`condensed` (default) strips tool-call JSON; `full` keeps everything."),includeSidechain:k.boolean().optional().describe("Include subagent / sidechain messages (default false)."),prelude:k.string().max(1e4).optional().describe("Optional header prepended above the transcript (max 10 000 chars)."),since:k.string().optional().describe("Only messages at or after this ISO timestamp.")}},async({id:n,mode:s,includeSidechain:r,prelude:o,since:i})=>{let a=K(n);if(!a)return V(`session not found or prefix ambiguous: ${n}`);let c=_(),l=c.prepare(`SELECT s.id, p.name AS project_name,
1109
1115
  s.started_at, s.ended_at, s.message_count, s.git_branch
1110
1116
  FROM sessions s JOIN projects p ON p.id = s.project_id
1111
- WHERE s.id = ?`).get(a);if(!l)return K(`session metadata missing for ${a}`);let d=c.prepare(`SELECT uuid, type, role, timestamp, is_sidechain, content_text, tool_names
1117
+ WHERE s.id = ?`).get(a);if(!l)return V(`session metadata missing for ${a}`);let d=c.prepare(`SELECT uuid, type, role, timestamp, is_sidechain, content_text, tool_names
1112
1118
  FROM messages WHERE session_id = ?
1113
- ORDER BY COALESCE(timestamp, ''), rowid`).all(a),m=Zn(l,d,{mode:s??"condensed",includeSidechain:r??!1,prelude:i??null,since:o??null}),p=o?"since":s??"condensed";return kr(a,Math.ceil(m.length/4),p,"mcp"),Fn(m)}),e.registerTool("recall_neighborhood",{title:"Recall: neighborhood context bundle",description:"Build a ranked, budget-bounded markdown bundle for a session: parents + children from thread_edges, plus approved citations / similar / cousins / wiki_links from the cognitive graph. Pipe-friendly output ready to seed a fresh conversation. Reads only approved edges by default \u2014 pending suggestions are opt-in.",inputSchema:{session_id:N.string().describe("Session UUID or 8+-character prefix."),budget:N.number().int().min(100).max(5e4).optional().describe("Token budget for the assembled bundle. Default 4000."),scoring:N.enum(["pagerank","embedding-rerank","hybrid"]).optional().describe("Scoring mode (default hybrid)."),edge_types:N.array(N.enum(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"])).optional().describe("Restrict to certain link types. Default: all approved types."),max_depth:N.number().int().min(1).max(5).optional().describe("Pagerank traversal depth on the local subgraph (default 2)."),include_wiki_links:N.boolean().optional().describe("Include manual wiki_link rows. Default true."),include_suggestions:N.boolean().optional().describe("Surface pending session_link_suggestions. Debug only; default false."),format:N.enum(["markdown","json"]).optional().describe("markdown (default) returns the bundle as text; json returns the full NeighborhoodResult.")}},async({session_id:n,budget:s,scoring:r,edge_types:i,max_depth:o,include_wiki_links:a,include_suggestions:c,format:l})=>{let d=z(n);if(!d)return K(`session not found or prefix ambiguous: ${n}`);try{let m=ei(d,{budget:s,scoring:r,edgeTypes:i,maxDepth:o,includeWikiLinks:a,includeSuggestions:c});return l==="json"?O(m):Fn(m.bundle)}catch(m){return K(m instanceof Error?m.message:String(m))}}),e.registerTool("doctor",{title:"Health check",description:"Read-only diagnostic snapshot of the local Claude Recall database: total size, WAL size, free pages, FTS5 fragmentation for messages and sessions, vector index row count, free disk space, integrity check, and row counts per surface table. Returns structured JSON. Equivalent to running `recall doctor --json` from the shell. Safe to call as often as needed; no side effects.",inputSchema:{}},async()=>{let{buildHealthReport:n}=await Promise.resolve().then(()=>(ko(),Lo));return O(n())}),Tr(e),t){let n=Number(process.env.RECALL_MCP_RATE_LIMIT),s=Number.isFinite(n)&&n>0?n:Mt,r=E(),i=new Date(Date.now()-6e4).toISOString(),o=r.prepare("SELECT at FROM mcp_audit_events WHERE at >= ? ORDER BY at ASC").all(i),a=new ce(s);for(let c of o){let l=new Date(c.at).getTime();if(Number.isFinite(l))try{a.consume(l)}catch{break}}e.registerTool("list_sessions_to_tag",{title:"List sessions to tag",description:"Return session summaries and sampled messages formatted for an agent to propose tags. Respects the same scope filters used by the Recall UI scan. Only returns data if auto-tagging is enabled in config.",inputSchema:{untaggedOnly:N.boolean().optional().describe("Only sessions with zero tags (default false)."),project:N.string().optional().describe("Exact project name match."),collectionId:N.string().optional().describe("Only sessions in this collection."),limit:N.number().int().min(1).max(200).optional()}},async c=>{let l=Rt();if(!l.enabled)return K("auto-tagging is disabled; enable it in Recall settings before scanning");let d=je({untaggedOnly:c.untaggedOnly,project:c.project,collectionId:c.collectionId,limit:c.limit??50});return O({count:d.length,sessions:d,guidance:`Produce ${l.minTagsPerSession}-${l.maxTagsPerSession} tags per session. Prefer existing tags from list_tags for consistency. Use apply_tags to write results.`})}),e.registerTool("apply_tags",{title:"Apply tags to a session",description:"Add one or more tags to a session (merge-mode, never removes existing). Only works when auto-tagging is enabled. Accepts full UUID or 8+-character id prefix.",inputSchema:{sessionId:N.string().describe("Full session UUID or 8+-character prefix."),tags:N.array(N.string()).min(1).max(10).describe("Tags to add. Normalized server-side (lowercase, hyphens, strip #).")}},async({sessionId:c,tags:l})=>{if(!Rt().enabled)return K("auto-tagging is disabled; enable it in Recall settings before writing tags");let m=z(c);if(!m)return K(`session not found or prefix ambiguous: ${c}`);try{let p=await D({tool:"apply_tags",args:{sessionId:m,tags:l},limiter:a,run:()=>{let g=[],h=[];for(let S of l)try{let{tag:u,added:f}=Fe(m,S);f?g.push(u):h.push({tag:u,reason:"already present"})}catch(u){h.push({tag:S,reason:u instanceof Error?u.message:String(u)})}return{sessionId:m,applied:g,skipped:h}}});return O(p)}catch(p){return p instanceof Error&&p.message.startsWith("SQLITE_")?K("database constraint error"):K(p instanceof Error?p.message:String(p))}}),e.registerTool("optimize",{title:"Optimize the database",description:"Run the local maintenance pass: WAL checkpoint (TRUNCATE), FTS5 segment merge for messages and sessions, refresh planner stats. Equivalent to `recall optimize` from the shell. Safe while the daemon is running. Set vacuum=true to also reclaim free pages \u2014 but VACUUM rewrites the entire DB and requires the daemon to be stopped, so it errors out if the daemon is up. Write-mode only.",inputSchema:{vacuum:N.boolean().optional().describe("Also run VACUUM. Requires the daemon to be stopped.")}},async({vacuum:c})=>{let{runOptimize:l}=await Promise.resolve().then(()=>(Oo(),xo)),d=process.stdout.write.bind(process.stdout),m="";process.stdout.write=p=>(m+=typeof p=="string"?p:Buffer.from(p).toString("utf-8"),!0);try{await l({vacuum:!!c,json:!0})}finally{process.stdout.write=d}try{return O(JSON.parse(m.trim()))}catch{return Fn(m.trim())}}),ps(e,{limiter:a}),br(e,{limiter:a}),console.error(`[claude-recall-mcp] MCP writes ENABLED \u2014 write tools registered (rate limit ${s}/min)`),console.error("[claude-recall-mcp] MCP thread writes ENABLED")}else console.error("[claude-recall-mcp] MCP writes DISABLED (read-only) \u2014 pass --allow-writes to enable"),console.error("[claude-recall-mcp] MCP thread writes DISABLED (read-only)");for(let n of rs)e.registerPrompt(n.name,{title:n.title,description:n.description,argsSchema:n.argsSchema},async s=>({messages:[{role:"user",content:{type:"text",text:n.build(s)}}]}));return e}async function Ap(){process.env.RECALL_DB_PROFILE=process.env.RECALL_DB_PROFILE??"light";let e=Rp(),t=new mp;await e.connect(t);let n=!1,s=async o=>{if(!n){n=!0,process.stderr.write(`[claude-recall-mcp] shutting down: ${o}
1119
+ ORDER BY COALESCE(timestamp, ''), rowid`).all(a),p=es(l,d,{mode:s??"condensed",includeSidechain:r??!1,prelude:o??null,since:i??null}),u=i?"since":s??"condensed";return xr(a,Math.ceil(p.length/4),u,"mcp"),$n(p)}),e.registerTool("recall_neighborhood",{title:"Recall: neighborhood context bundle",description:"Build a ranked, budget-bounded markdown bundle for a session: parents + children from thread_edges, plus approved citations / similar / cousins / wiki_links from the cognitive graph. Pipe-friendly output ready to seed a fresh conversation. Reads only approved edges by default \u2014 pending suggestions are opt-in.",inputSchema:{session_id:k.string().describe("Session UUID or 8+-character prefix."),budget:k.number().int().min(100).max(5e4).optional().describe("Token budget for the assembled bundle. Default 4000."),scoring:k.enum(["pagerank","embedding-rerank","hybrid"]).optional().describe("Scoring mode (default hybrid)."),edge_types:k.array(k.enum(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"])).optional().describe("Restrict to certain link types. Default: all approved types."),max_depth:k.number().int().min(1).max(5).optional().describe("Pagerank traversal depth on the local subgraph (default 2)."),include_wiki_links:k.boolean().optional().describe("Include manual wiki_link rows. Default true."),include_suggestions:k.boolean().optional().describe("Surface pending session_link_suggestions. Debug only; default false."),format:k.enum(["markdown","json"]).optional().describe("markdown (default) returns the bundle as text; json returns the full NeighborhoodResult.")}},async({session_id:n,budget:s,scoring:r,edge_types:o,max_depth:i,include_wiki_links:a,include_suggestions:c,format:l})=>{let d=K(n);if(!d)return V(`session not found or prefix ambiguous: ${n}`);try{let p=to(d,{budget:s,scoring:r,edgeTypes:o,maxDepth:i,includeWikiLinks:a,includeSuggestions:c});return l==="json"?O(p):$n(p.bundle)}catch(p){return V(p instanceof Error?p.message:String(p))}}),e.registerTool("doctor",{title:"Health check",description:"Read-only diagnostic snapshot of the local Claude Recall database: total size, WAL size, free pages, FTS5 fragmentation for messages and sessions, vector index row count, free disk space, integrity check, and row counts per surface table. Returns structured JSON. Equivalent to running `recall doctor --json` from the shell. Safe to call as often as needed; no side effects.",inputSchema:{}},async()=>{let{buildHealthReport:n}=await Promise.resolve().then(()=>(Mi(),Di));return O(n())}),Tr(e),t){let n=Number(process.env.RECALL_MCP_RATE_LIMIT),s=Number.isFinite(n)&&n>0?n:Mt,r=_(),o=new Date(Date.now()-6e4).toISOString(),i=r.prepare("SELECT at FROM mcp_audit_events WHERE at >= ? ORDER BY at ASC").all(o),a=new ce(s);for(let c of i){let l=new Date(c.at).getTime();if(Number.isFinite(l))try{a.consume(l)}catch{break}}e.registerTool("list_sessions_to_tag",{title:"List sessions to tag",description:"Return session summaries and sampled messages formatted for an agent to propose tags. Respects the same scope filters used by the Recall UI scan. Only returns data if auto-tagging is enabled in config.",inputSchema:{untaggedOnly:k.boolean().optional().describe("Only sessions with zero tags (default false)."),project:k.string().optional().describe("Exact project name match."),collectionId:k.string().optional().describe("Only sessions in this collection."),limit:k.number().int().min(1).max(200).optional()}},async c=>{let l=Rt();if(!l.enabled)return V("auto-tagging is disabled; enable it in Recall settings before scanning");let d=je({untaggedOnly:c.untaggedOnly,project:c.project,collectionId:c.collectionId,limit:c.limit??50});return O({count:d.length,sessions:d,guidance:`Produce ${l.minTagsPerSession}-${l.maxTagsPerSession} tags per session. Prefer existing tags from list_tags for consistency. Use apply_tags to write results.`})}),e.registerTool("apply_tags",{title:"Apply tags to a session",description:"Add one or more tags to a session (merge-mode, never removes existing). Only works when auto-tagging is enabled. Accepts full UUID or 8+-character id prefix.",inputSchema:{sessionId:k.string().describe("Full session UUID or 8+-character prefix."),tags:k.array(k.string()).min(1).max(10).describe("Tags to add. Normalized server-side (lowercase, hyphens, strip #).")}},async({sessionId:c,tags:l})=>{if(!Rt().enabled)return V("auto-tagging is disabled; enable it in Recall settings before writing tags");let p=K(c);if(!p)return V(`session not found or prefix ambiguous: ${c}`);try{let u=await D({tool:"apply_tags",args:{sessionId:p,tags:l},limiter:a,run:()=>{let g=[],h=[];for(let E of l)try{let{tag:S,added:m}=Fe(p,E);m?g.push(S):h.push({tag:S,reason:"already present"})}catch(S){h.push({tag:E,reason:S instanceof Error?S.message:String(S)})}return{sessionId:p,applied:g,skipped:h}}});return O(u)}catch(u){return u instanceof Error&&u.message.startsWith("SQLITE_")?V("database constraint error"):V(u instanceof Error?u.message:String(u))}}),e.registerTool("optimize",{title:"Optimize the database",description:"Run the local maintenance pass: WAL checkpoint (TRUNCATE), FTS5 segment merge for messages and sessions, refresh planner stats. Equivalent to `recall optimize` from the shell. Safe while the daemon is running. Set vacuum=true to also reclaim free pages \u2014 but VACUUM rewrites the entire DB and requires the daemon to be stopped, so it errors out if the daemon is up. Write-mode only.",inputSchema:{vacuum:k.boolean().optional().describe("Also run VACUUM. Requires the daemon to be stopped.")}},async({vacuum:c})=>{let{runOptimize:l}=await Promise.resolve().then(()=>(Fi(),Pi)),d=process.stdout.write.bind(process.stdout),p="";process.stdout.write=u=>(p+=typeof u=="string"?u:Buffer.from(u).toString("utf-8"),!0);try{await l({vacuum:!!c,json:!0})}finally{process.stdout.write=d}try{return O(JSON.parse(p.trim()))}catch{return $n(p.trim())}}),ms(e,{limiter:a}),yr(e,{limiter:a}),console.error(`[claude-recall-mcp] MCP writes ENABLED \u2014 write tools registered (rate limit ${s}/min)`),console.error("[claude-recall-mcp] MCP thread writes ENABLED")}else console.error("[claude-recall-mcp] MCP writes DISABLED (read-only) \u2014 pass --allow-writes to enable"),console.error("[claude-recall-mcp] MCP thread writes DISABLED (read-only)");for(let n of os)e.registerPrompt(n.name,{title:n.title,description:n.description,argsSchema:n.argsSchema},async s=>({messages:[{role:"user",content:{type:"text",text:n.build(s)}}]}));return e}async function Fp(){process.env.RECALL_DB_PROFILE=process.env.RECALL_DB_PROFILE??"light";let e=Pp(),t=new Ap;await e.connect(t);let n=!1,s=async i=>{if(!n){n=!0,process.stderr.write(`[claude-recall-mcp] shutting down: ${i}
1114
1120
  `);try{await e.close()}catch(a){let c=a instanceof Error?a.message:String(a);process.stderr.write(`[claude-recall-mcp] server.close() failed: ${c}
1115
- `)}Jn(),process.exit(0)}};process.on("SIGINT",()=>{s("SIGINT")}),process.on("SIGTERM",()=>{s("SIGTERM")}),Vn({onShutdown:()=>s("parent death")}),Qn({onShutdown:o=>s(o)});let i=e._registeredTools;if(i&&typeof i=="object")for(let o of Object.values(i)){let a=o.handler;typeof a=="function"&&(o.handler=function(...l){return bt(),a.apply(this,l)})}else process.stderr.write(`[claude-recall-mcp] WARN: MCP SDK tool registry shape changed; idle watchdog will rely on probe+lifetime only
1116
- `)}var Np=(()=>{try{let e=process.argv[1];if(!e)return!1;let t=Io(vo(e)).href;return Io(vo(Do(import.meta.url))).href===t}catch{return!1}})();Np&&Ap().catch(e=>{console.error("[claude-recall-mcp] fatal:",e),process.exit(1)});export{Rp as buildServer,Pn as withVecRetry};
1121
+ `)}Vn(),process.exit(0)}};process.on("SIGINT",()=>{s("SIGINT")}),process.on("SIGTERM",()=>{s("SIGTERM")}),qn({onShutdown:()=>s("parent death")}),Zn({onShutdown:i=>s(i)});let o=e._registeredTools;if(o&&typeof o=="object")for(let i of Object.values(o)){let a=i.handler;typeof a=="function"&&(i.handler=function(...l){return Tt(),a.apply(this,l)})}else process.stderr.write(`[claude-recall-mcp] WARN: MCP SDK tool registry shape changed; idle watchdog will rely on probe+lifetime only
1122
+ `)}var $p=(()=>{try{let e=process.argv[1];if(!e)return!1;let t=$i(Ui(e)).href;return $i(Ui(Hi(import.meta.url))).href===t}catch{return!1}})();$p&&Fp().catch(e=>{console.error("[claude-recall-mcp] fatal:",e),process.exit(1)});export{Pp as buildServer,Fn as withVecRetry};