@clauderecallhq/cli 0.76.3 → 0.77.0

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 Sm=Object.defineProperty;var ae=(e,t)=>()=>(e&&(t=e(e=0)),t);var xn=(e,t)=>{for(var n in t)Sm(e,n,{get:t[n],enumerable:!0})};import{homedir as Li}from"node:os";import{join as sr,basename as s0}from"node:path";import{existsSync as Tm,mkdirSync as ym,chmodSync as wm,readdirSync as o0,statSync as i0}from"node:fs";function z(){Tm(H)||ym(H,{recursive:!0,mode:448}),process.platform!=="win32"&&wm(H,448)}var Ut,H,Bt,ee=ae(()=>{"use strict";Ut=process.env.CLAUDE_PROJECTS_DIR?process.env.CLAUDE_PROJECTS_DIR:sr(Li(),".claude","projects"),H=process.env.RECALL_HOME?process.env.RECALL_HOME:sr(Li(),".recall"),Bt=sr(H,"db.sqlite")});import{createRequire as Ym}from"node:module";var Gm,zm,Km,ir,ar,Wi,qi=ae(()=>{"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)}}Gm=Ym(import.meta.url),zm=["node","sqlite"].join(":"),Km=Gm(zm),ir=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)}},ar=class{inner;extensionLoadingEnabled=!1;txDepth=0;constructor(t,n={}){this.inner=new Km.DatabaseSync(t,{readOnly:n.readonly??!1,allowExtension:!0})}prepare(t){return new ir(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)}},Wi=ar});function Ji(e){let t=e.prepare("PRAGMA table_info(sessions)").all(),n=new Set(t.map(b=>b.name)),s=[["total_input_tokens","INTEGER"],["total_output_tokens","INTEGER"],["total_cache_create_tokens","INTEGER"],["total_cache_read_tokens","INTEGER"],["primary_model","TEXT"],["auto_title","TEXT"],["auto_title_source","TEXT"],["auto_title_generated_at","INTEGER"],["auto_title_history","TEXT"],["verification_status","TEXT"],["verification_computed_at","INTEGER"],["title_quality","TEXT"],["title_quality_computed_at","INTEGER"],["archive_status","TEXT NOT NULL DEFAULT 'live'"],["archived_at","TEXT"]];for(let[b,T]of s)n.has(b)||e.exec(`ALTER TABLE sessions ADD COLUMN ${b} ${T}`);let r=e.prepare("PRAGMA table_info(collection_sessions)").all(),o=new Set(r.map(b=>b.name)),a=[["source","TEXT NOT NULL DEFAULT 'manual'"],["rule_id","TEXT"]];for(let[b,T]of a)o.has(b)||e.exec(`ALTER TABLE collection_sessions ADD COLUMN ${b} ${T}`);let c=e.prepare("PRAGMA table_info(session_notes)").all(),u=new Set(c.map(b=>b.name)),d=[["auto_synopsis","TEXT"],["auto_synopsis_generated_at","INTEGER"],["auto_synopsis_history","TEXT"]];for(let[b,T]of d)u.has(b)||e.exec(`ALTER TABLE session_notes ADD COLUMN ${b} ${T}`);let m=e.prepare("PRAGMA table_info(threads)").all();new Set(m.map(b=>b.name)).has("folder_id")||(e.exec("ALTER TABLE threads ADD COLUMN folder_id TEXT REFERENCES thread_folders(id) ON DELETE SET NULL"),e.exec("CREATE INDEX IF NOT EXISTS idx_threads_folder ON threads(folder_id)"));let h=e.prepare("PRAGMA table_info(thread_folders)").all(),S=new Set(h.map(b=>b.name));S.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)")),S.has("sort_order")||e.exec("ALTER TABLE thread_folders ADD COLUMN sort_order INTEGER NOT NULL DEFAULT 0"),e.exec(`
3
+ var xm=Object.defineProperty;var ae=(e,t)=>()=>(e&&(t=e(e=0)),t);var xn=(e,t)=>{for(var n in t)xm(e,n,{get:t[n],enumerable:!0})};import{homedir as Fi}from"node:os";import{join as rr,basename as k0}from"node:path";import{existsSync as Nm,mkdirSync as Om,chmodSync as Lm,readdirSync as x0,statSync as N0}from"node:fs";function z(){Nm(W)||Om(W,{recursive:!0,mode:448}),process.platform!=="win32"&&Lm(W,448)}var Ut,W,Bt,ee=ae(()=>{"use strict";Ut=process.env.CLAUDE_PROJECTS_DIR?process.env.CLAUDE_PROJECTS_DIR:rr(Fi(),".claude","projects"),W=process.env.RECALL_HOME?process.env.RECALL_HOME:rr(Fi(),".recall"),Bt=rr(W,"db.sqlite")});import{createRequire as eg}from"node:module";var tg,ng,sg,ar,cr,Ki,Vi=ae(()=>{"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)}}tg=eg(import.meta.url),ng=["node","sqlite"].join(":"),sg=tg(ng),ar=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)}},cr=class{inner;extensionLoadingEnabled=!1;txDepth=0;constructor(t,n={}){this.inner=new sg.DatabaseSync(t,{readOnly:n.readonly??!1,allowExtension:!0})}prepare(t){return new ar(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)}},Ki=cr});function Qi(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,T]of s)n.has(S)||e.exec(`ALTER TABLE sessions ADD COLUMN ${S} ${T}`);let r=e.prepare("PRAGMA table_info(collection_sessions)").all(),o=new Set(r.map(S=>S.name)),a=[["source","TEXT NOT NULL DEFAULT 'manual'"],["rule_id","TEXT"]];for(let[S,T]of a)o.has(S)||e.exec(`ALTER TABLE collection_sessions ADD COLUMN ${S} ${T}`);let c=e.prepare("PRAGMA table_info(session_notes)").all(),u=new Set(c.map(S=>S.name)),d=[["auto_synopsis","TEXT"],["auto_synopsis_generated_at","INTEGER"],["auto_synopsis_history","TEXT"]];for(let[S,T]of d)u.has(S)||e.exec(`ALTER TABLE session_notes ADD COLUMN ${S} ${T}`);let m=e.prepare("PRAGMA table_info(threads)").all();new Set(m.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 h=e.prepare("PRAGMA table_info(thread_folders)").all(),b=new Set(h.map(S=>S.name));b.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)")),b.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 Sm=Object.defineProperty;var ae=(e,t)=>()=>(e&&(t=e(e=0)),t);var xn=(e,t)=>{
12
12
  );
13
13
  CREATE INDEX IF NOT EXISTS idx_message_embeddings_session ON message_embeddings(session_id);
14
14
  CREATE INDEX IF NOT EXISTS idx_message_embeddings_generated ON message_embeddings(generated_at DESC);
15
- `)}var Xi,Yi=ae(()=>{"use strict";Xi=`
15
+ `)}var Zi,ea=ae(()=>{"use strict";Zi=`
16
16
  PRAGMA journal_mode = WAL;
17
17
  PRAGMA synchronous = NORMAL;
18
18
  PRAGMA foreign_keys = ON;
@@ -668,9 +668,9 @@ CREATE INDEX IF NOT EXISTS idx_synth_results_target
668
668
  ON bug_synthesis_results(scope, target_id, created_at DESC);
669
669
  CREATE INDEX IF NOT EXISTS idx_synth_results_created
670
670
  ON bug_synthesis_results(created_at DESC);
671
- `});import*as Gi from"sqlite-vec";function f(){if(ge)return ge;z(),ge=new Wi(Bt),Gi.load(ge),ge.pragma("cache_size = -64000"),ge.pragma("mmap_size = 268435456"),ge.pragma("temp_store = MEMORY"),ge.pragma("busy_timeout = 5000"),ge.pragma("journal_size_limit = 67108864"),ge.pragma("wal_autocheckpoint = 1000"),ge.exec(Xi),Ji(ge);try{ge.exec("PRAGMA optimize")}catch{}return ge}var ge,U=ae(()=>{"use strict";qi();ee();Yi();ge=null});import{existsSync as ng}from"node:fs";import{dirname as aa}from"node:path";import{fileURLToPath as sg}from"node:url";function ca(){if(On)return On;let e=aa(sg(import.meta.url));for(;!ng(`${e}/package.json`);){let t=aa(e);if(t===e)throw new Error(`package.json not found walking up from ${import.meta.url}`);e=t}return On=e,On}var On,la=ae(()=>{"use strict";On=null});var ua,da=ae(()=>{"use strict";ua="BAAI/bge-base-en-v1.5"});var ma={};xn(ma,{EmbedderUnavailableError:()=>Xt,embed:()=>ct,embedQuery:()=>dr,getEmbedderStatus:()=>_e,loadEmbedder:()=>Ue,unloadEmbedder:()=>dg});import{Worker as og}from"node:worker_threads";import{join as ig}from"node:path";import{existsSync as ag}from"node:fs";function cg(){return ig(ca(),"dist","daemon","embedder-worker.js")}function lg(e){return["Semantic search is unavailable on this platform.","",`Reason: ${e.detail}`,"",`Platform: ${process.platform}/${process.arch}, Node ${process.version}`,"","Claude Recall supports macOS (arm64/x64), Linux (x64/arm64), and Windows (x64).","Core CLI features (search, list, context, daemon) work everywhere.","Only `recall semantic *` requires the on-device embedder.","","See: https://clauderecall.com/docs (Supported platforms) \u2014 or file an issue at","https://gitlab.com/clauderecallhq/clauderecallhq/-/issues with the platform line above."].join(`
672
- `)}function pa(e){for(let t of qt.values())t.reject(e);qt.clear()}function ug(){if(De)return De;let e=cg();if(!ag(e))throw new Xt({kind:"bundle-missing",detail:"embedder-worker bundle not found \u2014 run `npm run build:cli` to emit it",path:e});let t=new og(e);return t.on("message",n=>{let s=qt.get(n.id);s&&(qt.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));pa(s),De=null,xe=!1}),t.on("exit",n=>{n!==0&&(console.error(`[embedder-worker] exited with code ${n}`),pa(new Error(`embedder worker exited with code ${n}`))),De=null,xe=!1}),De=t,t}function Ln(e){return new Promise((t,n)=>{let s;try{s=ug()}catch(r){n(r instanceof Error?r:new Error(String(r)));return}qt.set(e.id,{resolve:t,reject:n}),s.postMessage(e)})}function Cn(){return lr=lr+1>>>0,String(lr)}function ur(e){if(!e.ok)throw e.unavailable?new Xt({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 Ue(){if(!(xe&&De))try{ur(await Ln({id:Cn(),type:"load"})),xe=!0}catch(e){throw xe=!1,e}}function _e(){return{loaded:xe,modelId:ua,dim:768}}async function ct(e){if(!xe)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");return ur(await Ln({id:Cn(),type:"embed",texts:e})).embeddings.map(n=>new Float32Array(n))}async function dr(e){if(!xe)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");let t=ur(await Ln({id:Cn(),type:"embedQuery",text:e}));return new Float32Array(t.embedding)}async function dg(){if(!De){xe=!1;return}try{await Ln({id:Cn(),type:"unload"})}catch{}xe=!1;let e=De;De=null;try{await e.terminate()}catch{}}var De,qt,lr,xe,Xt,Ve=ae(()=>{"use strict";la();da();De=null,qt=new Map,lr=0,xe=!1,Xt=class extends Error{kind;path;underlying;cause;constructor(t){super(lg(t)),this.name="EmbedderUnavailableError",this.kind=t.kind,this.path=t.path,this.underlying=t.underlying,this.cause=t}}});import{writeFileSync as p_}from"node:fs";import{join as m_}from"node:path";function Qe(e){return e.trim().toLowerCase().replace(/^#+/,"").replace(/[\s/\\]+/g,"-").replace(/[^a-z0-9\-._]/g,"").slice(0,40)}function ut(e,t){let n=Qe(t);if(!n)throw new Error("tag must contain at least one alphanumeric character");let s=f(),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)})(),Da(),{tag:n,added:!0})}function Ma(e,t){let n=Qe(t);if(!n)return{tag:"",removed:!1};let s=f(),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)})(),Da(),{tag:n,removed:!0}):{tag:n,removed:!1}}function zt(e){return f().prepare("SELECT tag FROM session_tags WHERE session_id = ? ORDER BY tag").all(e).map(t=>t.tag)}function dt(){return f().prepare(`SELECT tag, COUNT(*) AS count FROM session_tags
673
- GROUP BY tag ORDER BY count DESC, tag ASC`).all()}function Da(){try{z();let e=f(),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};p_(g_,JSON.stringify(s,null,2))}catch(e){console.error("[tags] backup failed:",e)}}var g_,pt=ae(()=>{"use strict";U();ee();g_=m_(H,"tags.json")});function __(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,a)=>o-a).slice(0,t).map(o=>n[o])}function mt(e){let t=f(),n={limit:e.limit??500},s=e.sessionIds&&e.sessionIds.length>0,r=s?"1=1":"s.message_count > 2";if(s){let a=e.sessionIds.map((c,u)=>`@sid_${u}`).join(", ");r+=` AND s.id IN (${a})`,e.sessionIds.forEach((c,u)=>{n[`sid_${u}`]=c})}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,
671
+ `});import*as ta from"sqlite-vec";function f(){if(ge)return ge;z(),ge=new Ki(Bt),ta.load(ge),ge.pragma("cache_size = -64000"),ge.pragma("mmap_size = 268435456"),ge.pragma("temp_store = MEMORY"),ge.pragma("busy_timeout = 5000"),ge.pragma("journal_size_limit = 67108864"),ge.pragma("wal_autocheckpoint = 1000"),ge.exec(Zi),Qi(ge);try{ge.exec("PRAGMA optimize")}catch{}return ge}var ge,B=ae(()=>{"use strict";Vi();ee();ea();ge=null});import{existsSync as lg}from"node:fs";import{dirname as ga}from"node:path";import{fileURLToPath as ug}from"node:url";function Ln(){if(On)return On;let e=ga(ug(import.meta.url));for(;!lg(`${e}/package.json`);){let t=ga(e);if(t===e)throw new Error(`package.json not found walking up from ${import.meta.url}`);e=t}return On=e,On}var On,ur=ae(()=>{"use strict";On=null});var _a,fa=ae(()=>{"use strict";_a="BAAI/bge-base-en-v1.5"});var Ea={};xn(Ea,{EmbedderUnavailableError:()=>Xt,embed:()=>at,embedQuery:()=>Eg,getEmbedderStatus:()=>_e,loadEmbedder:()=>Ue,unloadEmbedder:()=>bg});import{Worker as pg}from"node:worker_threads";import{join as mg}from"node:path";import{existsSync as gg}from"node:fs";function _g(){return mg(Ln(),"dist","daemon","embedder-worker.js")}function fg(e){return["Semantic search is unavailable on this platform.","",`Reason: ${e.detail}`,"",`Platform: ${process.platform}/${process.arch}, Node ${process.version}`,"","Claude Recall supports macOS (arm64/x64), Linux (x64/arm64), and Windows (x64).","Core CLI features (search, list, context, daemon) work everywhere.","Only `recall semantic *` requires the on-device embedder.","","See: https://clauderecall.com/docs (Supported platforms) \u2014 or file an issue at","https://gitlab.com/clauderecallhq/clauderecallhq/-/issues with the platform line above."].join(`
672
+ `)}function ha(e){for(let t of qt.values())t.reject(e);qt.clear()}function hg(){if(De)return De;let e=_g();if(!gg(e))throw new Xt({kind:"bundle-missing",detail:"embedder-worker bundle not found \u2014 run `npm run build:cli` to emit it",path:e});let t=new pg(e);return t.on("message",n=>{let s=qt.get(n.id);s&&(qt.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));ha(s),De=null,xe=!1}),t.on("exit",n=>{n!==0&&(console.error(`[embedder-worker] exited with code ${n}`),ha(new Error(`embedder worker exited with code ${n}`))),De=null,xe=!1}),De=t,t}function Cn(e){return new Promise((t,n)=>{let s;try{s=hg()}catch(r){n(r instanceof Error?r:new Error(String(r)));return}qt.set(e.id,{resolve:t,reject:n}),s.postMessage(e)})}function vn(){return dr=dr+1>>>0,String(dr)}function pr(e){if(!e.ok)throw e.unavailable?new Xt({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 Ue(){if(!(xe&&De))try{pr(await Cn({id:vn(),type:"load"})),xe=!0}catch(e){throw xe=!1,e}}function _e(){return{loaded:xe,modelId:_a,dim:768}}async function at(e){if(!xe)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");return pr(await Cn({id:vn(),type:"embed",texts:e})).embeddings.map(n=>new Float32Array(n))}async function Eg(e){if(!xe)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");let t=pr(await Cn({id:vn(),type:"embedQuery",text:e}));return new Float32Array(t.embedding)}async function bg(){if(!De){xe=!1;return}try{await Cn({id:vn(),type:"unload"})}catch{}xe=!1;let e=De;De=null;try{await e.terminate()}catch{}}var De,qt,dr,xe,Xt,ct=ae(()=>{"use strict";ur();fa();De=null,qt=new Map,dr=0,xe=!1,Xt=class extends Error{kind;path;underlying;cause;constructor(t){super(fg(t)),this.name="EmbedderUnavailableError",this.kind=t.kind,this.path=t.path,this.underlying=t.underlying,this.cause=t}}});import{writeFileSync as S_}from"node:fs";import{join as T_}from"node:path";function Ze(e){return e.trim().toLowerCase().replace(/^#+/,"").replace(/[\s/\\]+/g,"-").replace(/[^a-z0-9\-._]/g,"").slice(0,40)}function ut(e,t){let n=Ze(t);if(!n)throw new Error("tag must contain at least one alphanumeric character");let s=f(),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)})(),Ba(),{tag:n,added:!0})}function Ua(e,t){let n=Ze(t);if(!n)return{tag:"",removed:!1};let s=f(),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)})(),Ba(),{tag:n,removed:!0}):{tag:n,removed:!1}}function zt(e){return f().prepare("SELECT tag FROM session_tags WHERE session_id = ? ORDER BY tag").all(e).map(t=>t.tag)}function dt(){return f().prepare(`SELECT tag, COUNT(*) AS count FROM session_tags
673
+ GROUP BY tag ORDER BY count DESC, tag ASC`).all()}function Ba(){try{z();let e=f(),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};S_(y_,JSON.stringify(s,null,2))}catch(e){console.error("[tags] backup failed:",e)}}var y_,pt=ae(()=>{"use strict";B();ee();y_=T_(W,"tags.json")});function w_(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,a)=>o-a).slice(0,t).map(o=>n[o])}function mt(e){let t=f(),n={limit:e.limit??500},s=e.sessionIds&&e.sessionIds.length>0,r=s?"1=1":"s.message_count > 2";if(s){let a=e.sessionIds.map((c,u)=>`@sid_${u}`).join(", ");r+=` AND s.id IN (${a})`,e.sessionIds.forEach((c,u)=>{n[`sid_${u}`]=c})}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,
674
674
  NULLIF(sa.alias, '') AS alias,
675
675
  COALESCE(s.first_user_message, '') AS first_user_message
676
676
  FROM sessions s
@@ -680,15 +680,15 @@ CREATE INDEX IF NOT EXISTS idx_synth_results_created
680
680
  ORDER BY COALESCE(s.started_at, '') DESC
681
681
  LIMIT @limit`).all(n).map(a=>{let c=t.prepare(`SELECT role, COALESCE(content_text, '') AS content_text
682
682
  FROM messages WHERE session_id = ?
683
- ORDER BY COALESCE(timestamp, ''), rowid`).all(a.id),d=__(c,5).map(m=>`${m.role}: ${m.content_text.slice(0,400)}`).join(`
683
+ ORDER BY COALESCE(timestamp, ''), rowid`).all(a.id),d=w_(c,5).map(m=>`${m.role}: ${m.content_text.slice(0,400)}`).join(`
684
684
  ---
685
- `);return{id:a.id,project:a.project,git_branch:a.git_branch,alias:a.alias,first_user_message:a.first_user_message,message_sample:d,current_tags:zt(a.id)}})}var Dn=ae(()=>{"use strict";U();pt()});import{z as be}from"zod";function Tr(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(`
686
- `)}function E_(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(`
687
- `)}function S_(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(`
688
- `)}function y_(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(`
689
- `)}function Fa(e){return yr.find(t=>t.name===e)}var f_,h_,b_,T_,w_,R_,k_,A_,yr,wr=ae(()=>{"use strict";f_={project:be.string().optional().describe("Exact project name match (optional)."),collectionId:be.string().optional().describe("Restrict to sessions in this collection (optional)."),sessionId:be.string().optional().describe("Full session UUID to tag just one session (optional)."),untaggedOnly:be.boolean().optional().describe("Skip sessions that already have any tag (default: true)."),limit:be.number().int().min(1).max(500).optional().describe("Max sessions to process (default: 100)."),minTags:be.number().int().min(1).max(10).optional().describe("Minimum tags per session (default: 2)."),maxTags:be.number().int().min(1).max(10).optional().describe("Maximum tags per session (default: 4).")};h_={sessionId:be.string().describe("Session UUID (or 8+-char prefix) to summarize."),mode:be.enum(["brief","detailed"]).optional().describe("brief = 3-5 bullets; detailed = paragraph + bullets. Default: brief.")};b_={sessionId:be.string().describe("Session UUID (or 8+-char prefix) to extract decisions from.")};T_={sessionId:be.string().describe("Session UUID (or 8+-char prefix) to find similar sessions to."),limit:be.number().int().min(1).max(20).optional().describe("How many similar sessions to surface (default: 5).")};w_={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:f_,build:Tr,allowedTools:["mcp__recall__list_tags","mcp__recall__list_sessions_to_tag","mcp__recall__apply_tags"]},R_={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:h_,build:E_,allowedTools:["mcp__recall__get_session","mcp__recall__context_for_session"]},k_={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:b_,build:S_,allowedTools:["mcp__recall__get_session","mcp__recall__context_for_session"]},A_={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:T_,build:y_,allowedTools:["mcp__recall__get_session","mcp__recall__search","mcp__recall__list_sessions","mcp__recall__list_tags"]},yr=[w_,R_,k_,A_]});function Fn(e,t){let n=Kt.get(e);if(!(!n||n.size===0))for(let s of n)try{s(t)}catch{}}function Pa(e,t){let n=Kt.get(e);return n||(n=new Set,Kt.set(e,n)),n.add(t),()=>{let s=Kt.get(e);s&&(s.delete(t),s.size===0&&Kt.delete(e))}}var Kt,Rr=ae(()=>{"use strict";Kt=new Map});import{existsSync as x_,statSync as N_}from"node:fs";import{delimiter as O_,join as L_}from"node:path";function gt(e){if(e.includes("/")||e.includes("\\")||e.includes(".."))return null;let t=(process.env.PATH??"").split(O_).filter(Boolean),n=process.platform==="win32"?[e,`${e}.exe`,`${e}.cmd`,`${e}.bat`]:[e];for(let s of t)for(let r of n){let o=L_(s,r);try{if(x_(o)&&N_(o).isFile())return o}catch{}}return null}function Pn(e){if(process.platform!=="win32"||!e)return!1;let t=e.toLowerCase();return t.endsWith(".cmd")||t.endsWith(".bat")}var $n=ae(()=>{"use strict"});var tt={};xn(tt,{_resetClaudePathCacheForTests:()=>j_,buildScanPrompt:()=>Ua,isClaudeCliAvailable:()=>pe,runClaudeCliScan:()=>kr,spawnClaudePrompt:()=>et});import{spawn as C_}from"node:child_process";function $a(){if(_t!==void 0&&Vt!==void 0)return{path:_t,available:Vt};let e=gt("claude");return _t=e??"claude",Vt=e!==null,{path:_t,available:Vt}}function I_(){return $a().path}function pe(){return $a().available}function j_(){_t=void 0,Vt=void 0}function Ua(e){return Tr({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 M_(e,t){let n=t.get(e);return n||e.slice(0,8)}function D_(e){try{return mt(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 F_(e){let{scanId:t,total:n,labelTable:s}=e,r=new Set;return o=>{let a=o.trim();if(!a.startsWith("{"))return;let c;try{c=JSON.parse(a)}catch{return}if(!c||typeof c!="object")return;let u=c;if(!(u.type!=="assistant"||!u.message?.content))for(let d of u.message.content){if(d?.type!=="tool_use"||d.name!=="mcp__recall__apply_tags")continue;let m=d.input,h=typeof m?.sessionId=="string"?m.sessionId:null;!h||r.has(h)||(r.add(h),Fn(t,{type:"progress",current:r.size,total:n,sessionId:h,sessionLabel:M_(h,s)}))}}}function P_(e){let t="";return n=>{t+=n.toString("utf8");let s=t.indexOf(`
685
+ `);return{id:a.id,project:a.project,git_branch:a.git_branch,alias:a.alias,first_user_message:a.first_user_message,message_sample:d,current_tags:zt(a.id)}})}var Fn=ae(()=>{"use strict";B();pt()});import{z as be}from"zod";function yr(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(`
686
+ `)}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(`
687
+ `)}function N_(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(`
688
+ `)}function L_(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(`
689
+ `)}function Ha(e){return wr.find(t=>t.name===e)}var R_,k_,x_,O_,C_,v_,I_,j_,wr,Rr=ae(()=>{"use strict";R_={project:be.string().optional().describe("Exact project name match (optional)."),collectionId:be.string().optional().describe("Restrict to sessions in this collection (optional)."),sessionId:be.string().optional().describe("Full session UUID to tag just one session (optional)."),untaggedOnly:be.boolean().optional().describe("Skip sessions that already have any tag (default: true)."),limit:be.number().int().min(1).max(500).optional().describe("Max sessions to process (default: 100)."),minTags:be.number().int().min(1).max(10).optional().describe("Minimum tags per session (default: 2)."),maxTags:be.number().int().min(1).max(10).optional().describe("Maximum tags per session (default: 4).")};k_={sessionId:be.string().describe("Session UUID (or 8+-char prefix) to summarize."),mode:be.enum(["brief","detailed"]).optional().describe("brief = 3-5 bullets; detailed = paragraph + bullets. Default: brief.")};x_={sessionId:be.string().describe("Session UUID (or 8+-char prefix) to extract decisions from.")};O_={sessionId:be.string().describe("Session UUID (or 8+-char prefix) to find similar sessions to."),limit:be.number().int().min(1).max(20).optional().describe("How many similar sessions to surface (default: 5).")};C_={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:R_,build:yr,allowedTools:["mcp__recall__list_tags","mcp__recall__list_sessions_to_tag","mcp__recall__apply_tags"]},v_={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:k_,build:A_,allowedTools:["mcp__recall__get_session","mcp__recall__context_for_session"]},I_={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:x_,build:N_,allowedTools:["mcp__recall__get_session","mcp__recall__context_for_session"]},j_={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:O_,build:L_,allowedTools:["mcp__recall__get_session","mcp__recall__search","mcp__recall__list_sessions","mcp__recall__list_tags"]},wr=[C_,v_,I_,j_]});function Pn(e,t){let n=Kt.get(e);if(!(!n||n.size===0))for(let s of n)try{s(t)}catch{}}function Wa(e,t){let n=Kt.get(e);return n||(n=new Set,Kt.set(e,n)),n.add(t),()=>{let s=Kt.get(e);s&&(s.delete(t),s.size===0&&Kt.delete(e))}}var Kt,kr=ae(()=>{"use strict";Kt=new Map});import{existsSync as M_,statSync as D_}from"node:fs";import{delimiter as F_,join as P_}from"node:path";function gt(e){if(e.includes("/")||e.includes("\\")||e.includes(".."))return null;let t=(process.env.PATH??"").split(F_).filter(Boolean),n=process.platform==="win32"?[e,`${e}.exe`,`${e}.cmd`,`${e}.bat`]:[e];for(let s of t)for(let r of n){let o=P_(s,r);try{if(M_(o)&&D_(o).isFile())return o}catch{}}return null}function $n(e){if(process.platform!=="win32"||!e)return!1;let t=e.toLowerCase();return t.endsWith(".cmd")||t.endsWith(".bat")}var Un=ae(()=>{"use strict"});var et={};xn(et,{_resetClaudePathCacheForTests:()=>H_,buildScanPrompt:()=>Xa,isClaudeCliAvailable:()=>pe,runClaudeCliScan:()=>Ar,spawnClaudePrompt:()=>Qe});import{spawn as $_}from"node:child_process";function qa(){if(_t!==void 0&&Vt!==void 0)return{path:_t,available:Vt};let e=gt("claude");return _t=e??"claude",Vt=e!==null,{path:_t,available:Vt}}function B_(){return qa().path}function pe(){return qa().available}function H_(){_t=void 0,Vt=void 0}function Xa(e){return yr({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 W_(e,t){let n=t.get(e);return n||e.slice(0,8)}function q_(e){try{return mt(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 X_(e){let{scanId:t,total:n,labelTable:s}=e,r=new Set;return o=>{let a=o.trim();if(!a.startsWith("{"))return;let c;try{c=JSON.parse(a)}catch{return}if(!c||typeof c!="object")return;let u=c;if(!(u.type!=="assistant"||!u.message?.content))for(let d of u.message.content){if(d?.type!=="tool_use"||d.name!=="mcp__recall__apply_tags")continue;let m=d.input,h=typeof m?.sessionId=="string"?m.sessionId:null;!h||r.has(h)||(r.add(h),Pn(t,{type:"progress",current:r.size,total:n,sessionId:h,sessionLabel:W_(h,s)}))}}}function J_(e){let t="";return n=>{t+=n.toString("utf8");let s=t.indexOf(`
690
690
  `);for(;s!==-1;){let r=t.slice(0,s);t=t.slice(s+1),r.length>0&&e(r),s=t.indexOf(`
691
- `)}}}async function kr(e,t={},n){let s=!!t.scanId,r=s?D_(e):[],o=new Map(r.map(u=>[u.id,u.label])),a=r.length,c;return s&&t.scanId&&(c=F_({scanId:t.scanId,total:a,labelTable:o})),Ba({prompt:Ua(e),allowedTools:v_.split(","),opts:t,onProgress:n,onStdoutLine:c,outputFormat:s?"stream-json":"json"})}async function et(e,t,n={},s){return Ba({prompt:e,allowedTools:t,opts:n,onProgress:s,outputFormat:"json"})}function Ba(e){let{prompt:t,allowedTools:n,opts:s,onProgress:r,onStdoutLine:o,outputFormat:a}=e,c=["-p",t,"--output-format",a,"--allowedTools",n.join(","),"--permission-mode","bypassPermissions","--no-session-persistence"];return a==="stream-json"&&c.push("--verbose"),s.model&&c.push("--model",s.model),new Promise(u=>{let d=I_(),m=C_(d,c,{stdio:["ignore","pipe","pipe"],shell:Pn(d)||process.platform==="win32"&&_t==="claude"}),h=[],S=[],b=o?P_(o):void 0;m.stdout.on("data",R=>{h.push(R),b&&b(R)}),m.stderr.on("data",R=>{if(S.push(R),r){let w=R.toString("utf8").trim();w&&r(w)}});let T=setTimeout(()=>{m.kill("SIGKILL")},1800*1e3);m.on("close",R=>{clearTimeout(T),u({success:R===0,stdout:Buffer.concat(h).toString("utf8"),stderr:Buffer.concat(S).toString("utf8"),exitCode:R})}),m.on("error",R=>{clearTimeout(T),u({success:!1,stdout:"",stderr:String(R),exitCode:null})})})}var v_,_t,Vt,ye=ae(()=>{"use strict";Dn();wr();Rr();$n();v_=["mcp__recall__list_tags","mcp__recall__list_sessions_to_tag","mcp__recall__apply_tags"].join(",")});var rc={};xn(rc,{RetentionConfigSchema:()=>Ir,readRetentionConfig:()=>jr,writeRetentionConfig:()=>Gn});import{existsSync as Qa,mkdirSync as Af,readFileSync as xf,writeFileSync as Nf}from"node:fs";import{homedir as Of}from"node:os";import{join as ec}from"node:path";import{z as Jn}from"zod";function tc(){return process.env.RECALL_HOME??ec(Of(),".recall")}function Lf(){let e=tc();Qa(e)||Af(e,{recursive:!0})}function nc(){return ec(tc(),"config.json")}function sc(){let e=nc();if(!Qa(e))return{};try{return JSON.parse(xf(e,"utf8"))}catch(t){let n=t instanceof Error?t.message:String(t);return console.error(`[retention-config] failed to parse config.json: ${n}`),{}}}function jr(){let e=sc().retention;if(!e)return{...Yn};let t=Ir.safeParse({...Yn,...e});return t.success?t.data:{...Yn}}function Gn(e){Lf();let t=sc(),n=Ir.parse({...Yn,...t.retention??{},...e}),s={...t,retention:n};return Nf(nc(),JSON.stringify(s,null,2)),n}var Ir,Yn,Mr=ae(()=>{"use strict";Ir=Jn.object({autoArchiveEnabled:Jn.boolean().default(!1),autoArchiveAfterDays:Jn.number().int().min(7).max(3650).default(90),lastRunAt:Jn.string().nullable().default(null)}),Yn={autoArchiveEnabled:!1,autoArchiveAfterDays:90,lastRunAt:null}});import Oe from"chalk";import{formatDistanceToNowStrict as Ok,parseISO as Lk}from"date-fns";var we,zn=ae(()=>{"use strict";we={dim:Oe.gray,bold:Oe.bold,project:Oe.cyan,user:Oe.blue,assistant:Oe.green,tool:Oe.magenta,warn:Oe.yellow,err:Oe.red,ok:Oe.green,accent:Oe.hex("#f97316")}});import{existsSync as Cf}from"node:fs";import{join as vf}from"node:path";function Qt(){if(oc&&Cf(Zt))return;z();let e=f(),t=Zt.replace(/'/g,"''");e.exec(`ATTACH DATABASE '${t}' AS archive`);try{e.exec(`
691
+ `)}}}async function Ar(e,t={},n){let s=!!t.scanId,r=s?q_(e):[],o=new Map(r.map(u=>[u.id,u.label])),a=r.length,c;return s&&t.scanId&&(c=X_({scanId:t.scanId,total:a,labelTable:o})),Ja({prompt:Xa(e),allowedTools:U_.split(","),opts:t,onProgress:n,onStdoutLine:c,outputFormat:s?"stream-json":"json"})}async function Qe(e,t,n={},s){return Ja({prompt:e,allowedTools:t,opts:n,onProgress:s,outputFormat:"json"})}function Ja(e){let{prompt:t,allowedTools:n,opts:s,onProgress:r,onStdoutLine:o,outputFormat:a}=e,c=["-p",t,"--output-format",a,"--allowedTools",n.join(","),"--permission-mode","bypassPermissions","--no-session-persistence"];return a==="stream-json"&&c.push("--verbose"),s.model&&c.push("--model",s.model),new Promise(u=>{let d=B_(),m=$_(d,c,{stdio:["ignore","pipe","pipe"],shell:$n(d)||process.platform==="win32"&&_t==="claude"}),h=[],b=[],S=o?J_(o):void 0;m.stdout.on("data",R=>{h.push(R),S&&S(R)}),m.stderr.on("data",R=>{if(b.push(R),r){let O=R.toString("utf8").trim();O&&r(O)}});let T=setTimeout(()=>{m.kill("SIGKILL")},1800*1e3);m.on("close",R=>{clearTimeout(T),u({success:R===0,stdout:Buffer.concat(h).toString("utf8"),stderr:Buffer.concat(b).toString("utf8"),exitCode:R})}),m.on("error",R=>{clearTimeout(T),u({success:!1,stdout:"",stderr:String(R),exitCode:null})})})}var U_,_t,Vt,ye=ae(()=>{"use strict";Fn();Rr();kr();Un();U_=["mcp__recall__list_tags","mcp__recall__list_sessions_to_tag","mcp__recall__apply_tags"].join(",")});var lc={};xn(lc,{RetentionConfigSchema:()=>jr,readRetentionConfig:()=>Mr,writeRetentionConfig:()=>zn});import{existsSync as rc,mkdirSync as jf,readFileSync as Mf,writeFileSync as Df}from"node:fs";import{homedir as Ff}from"node:os";import{join as oc}from"node:path";import{z as Gn}from"zod";function ic(){return process.env.RECALL_HOME??oc(Ff(),".recall")}function Pf(){let e=ic();rc(e)||jf(e,{recursive:!0})}function ac(){return oc(ic(),"config.json")}function cc(){let e=ac();if(!rc(e))return{};try{return JSON.parse(Mf(e,"utf8"))}catch(t){let n=t instanceof Error?t.message:String(t);return console.error(`[retention-config] failed to parse config.json: ${n}`),{}}}function Mr(){let e=cc().retention;if(!e)return{...Yn};let t=jr.safeParse({...Yn,...e});return t.success?t.data:{...Yn}}function zn(e){Pf();let t=cc(),n=jr.parse({...Yn,...t.retention??{},...e}),s={...t,retention:n};return Df(ac(),JSON.stringify(s,null,2)),n}var jr,Yn,Dr=ae(()=>{"use strict";jr=Gn.object({autoArchiveEnabled:Gn.boolean().default(!1),autoArchiveAfterDays:Gn.number().int().min(7).max(3650).default(90),lastRunAt:Gn.string().nullable().default(null)}),Yn={autoArchiveEnabled:!1,autoArchiveAfterDays:90,lastRunAt:null}});import Oe from"chalk";import{formatDistanceToNowStrict as Vk,parseISO as Zk}from"date-fns";var we,Kn=ae(()=>{"use strict";we={dim:Oe.gray,bold:Oe.bold,project:Oe.cyan,user:Oe.blue,assistant:Oe.green,tool:Oe.magenta,warn:Oe.yellow,err:Oe.red,ok:Oe.green,accent:Oe.hex("#f97316")}});import{existsSync as $f}from"node:fs";import{join as Uf}from"node:path";function Qt(){if(uc&&$f(Zt))return;z();let e=f(),t=Zt.replace(/'/g,"''");e.exec(`ATTACH DATABASE '${t}' AS archive`);try{e.exec(`
692
692
  CREATE TABLE IF NOT EXISTS archive.messages_archive (
693
693
  uuid TEXT PRIMARY KEY,
694
694
  session_id TEXT NOT NULL,
@@ -703,12 +703,12 @@ CREATE INDEX IF NOT EXISTS idx_synth_results_created
703
703
  archived_at TEXT NOT NULL DEFAULT (datetime('now'))
704
704
  );
705
705
  CREATE INDEX IF NOT EXISTS archive.idx_messages_archive_session ON messages_archive(session_id);
706
- `)}finally{e.exec("DETACH DATABASE archive")}oc=!0}function ic(){let e=f();if(e.prepare("SELECT COUNT(*) AS n FROM messages_archive").get().n===0)return 0;Qt();let n=Zt.replace(/'/g,"''"),s=0;e.exec(`ATTACH DATABASE '${n}' AS archive`);try{e.transaction(()=>{s=e.prepare(`INSERT OR IGNORE INTO archive.messages_archive
706
+ `)}finally{e.exec("DETACH DATABASE archive")}uc=!0}function dc(){let e=f();if(e.prepare("SELECT COUNT(*) AS n FROM messages_archive").get().n===0)return 0;Qt();let n=Zt.replace(/'/g,"''"),s=0;e.exec(`ATTACH DATABASE '${n}' AS archive`);try{e.transaction(()=>{s=e.prepare(`INSERT OR IGNORE INTO archive.messages_archive
707
707
  (uuid, session_id, parent_uuid, type, role, timestamp,
708
708
  is_sidechain, content_text, tool_names, raw_json, archived_at)
709
709
  SELECT uuid, session_id, parent_uuid, type, role, timestamp,
710
710
  is_sidechain, content_text, tool_names, raw_json, archived_at
711
- FROM main.messages_archive`).run().changes,e.prepare("DELETE FROM main.messages_archive").run()})()}finally{e.exec("DETACH DATABASE archive")}return s}var Zt,oc,Dr=ae(()=>{"use strict";ee();U();Zt=vf(H,"archive.sqlite"),oc=!1});var cc={};xn(cc,{runArchive:()=>Uf});function Fr(e){Qt();let t=f(),n=Zt.replace(/'/g,"''");t.exec(`ATTACH DATABASE '${n}' AS archive`);try{return e(t)}finally{t.exec("DETACH DATABASE archive")}}function If(){return Fr(e=>{let t=e.prepare(`SELECT
711
+ FROM main.messages_archive`).run().changes,e.prepare("DELETE FROM main.messages_archive").run()})()}finally{e.exec("DETACH DATABASE archive")}return s}var Zt,uc,Fr=ae(()=>{"use strict";ee();B();Zt=Uf(W,"archive.sqlite"),uc=!1});var mc={};xn(mc,{runArchive:()=>Yf});function Pr(e){Qt();let t=f(),n=Zt.replace(/'/g,"''");t.exec(`ATTACH DATABASE '${n}' AS archive`);try{return e(t)}finally{t.exec("DETACH DATABASE archive")}}function Bf(){return Pr(e=>{let t=e.prepare(`SELECT
712
712
  SUM(CASE WHEN archive_status = 'archived' THEN 1 ELSE 0 END) AS archived,
713
713
  SUM(CASE WHEN archive_status != 'archived' THEN 1 ELSE 0 END) AS live
714
714
  FROM sessions`).get(),n=e.prepare("SELECT COUNT(*) AS n FROM messages").get().n,s=e.prepare(`SELECT
@@ -717,15 +717,15 @@ CREATE INDEX IF NOT EXISTS idx_synth_results_created
717
717
  SELECT MAX(timestamp) AS t FROM main.messages_archive WHERE timestamp IS NOT NULL
718
718
  UNION ALL
719
719
  SELECT MAX(timestamp) AS t FROM archive.messages_archive WHERE timestamp IS NOT NULL
720
- )`).get();return{liveSessions:t.live??0,archivedSessions:t.archived??0,liveMessages:n,archivedMessages:s,oldestLiveTimestamp:r.t,newestArchivedTimestamp:o.t}})}function ac(e){return e?e.slice(0,10):"\u2014"}function jf(){let e=If();return console.log(we.dim("\u2014 Archive state \u2014")),console.log(` Live sessions ${e.liveSessions.toLocaleString()}`),console.log(` Archived sessions ${e.archivedSessions.toLocaleString()}`),console.log(` Live messages ${e.liveMessages.toLocaleString()}`),console.log(` Archived messages ${e.archivedMessages.toLocaleString()}`),console.log(` Oldest live ${ac(e.oldestLiveTimestamp)}`),console.log(` Newest archived ${ac(e.newestArchivedTimestamp)}`),console.log(""),console.log(we.dim(" recall archive run --before YYYY-MM-DD")),console.log(we.dim(" recall archive restore <session-id>")),0}function Mf(e){if(!/^\d{4}-\d{2}-\d{2}$/.test(e.before))return console.error("--before must be YYYY-MM-DD"),1;let n=f().prepare(`SELECT s.id, s.ended_at, s.message_count
720
+ )`).get();return{liveSessions:t.live??0,archivedSessions:t.archived??0,liveMessages:n,archivedMessages:s,oldestLiveTimestamp:r.t,newestArchivedTimestamp:o.t}})}function pc(e){return e?e.slice(0,10):"\u2014"}function Hf(){let e=Bf();return console.log(we.dim("\u2014 Archive state \u2014")),console.log(` Live sessions ${e.liveSessions.toLocaleString()}`),console.log(` Archived sessions ${e.archivedSessions.toLocaleString()}`),console.log(` Live messages ${e.liveMessages.toLocaleString()}`),console.log(` Archived messages ${e.archivedMessages.toLocaleString()}`),console.log(` Oldest live ${pc(e.oldestLiveTimestamp)}`),console.log(` Newest archived ${pc(e.newestArchivedTimestamp)}`),console.log(""),console.log(we.dim(" recall archive run --before YYYY-MM-DD")),console.log(we.dim(" recall archive restore <session-id>")),0}function Wf(e){if(!/^\d{4}-\d{2}-\d{2}$/.test(e.before))return console.error("--before must be YYYY-MM-DD"),1;let n=f().prepare(`SELECT s.id, s.ended_at, s.message_count
721
721
  FROM sessions s
722
722
  WHERE s.archive_status != 'archived'
723
- AND COALESCE(s.ended_at, s.started_at) < ?`).all(`${e.before}T00:00:00.000Z`);if(n.length===0)return console.log(`No sessions to archive (none older than ${e.before}).`),0;let s=n.reduce((c,u)=>c+(u.message_count??0),0);if(console.log(`${n.length.toLocaleString()} session(s), ${s.toLocaleString()} message(s) eligible.`),e.dryRun)return console.log(we.dim("Dry run \u2014 no rows moved. Re-run without --dry-run to apply.")),0;let r=n.map(c=>c.id),o=Date.now(),a=Fr(c=>c.transaction(d=>{let m=0,h=c.prepare(`INSERT OR IGNORE INTO archive.messages_archive
723
+ AND COALESCE(s.ended_at, s.started_at) < ?`).all(`${e.before}T00:00:00.000Z`);if(n.length===0)return console.log(`No sessions to archive (none older than ${e.before}).`),0;let s=n.reduce((c,u)=>c+(u.message_count??0),0);if(console.log(`${n.length.toLocaleString()} session(s), ${s.toLocaleString()} message(s) eligible.`),e.dryRun)return console.log(we.dim("Dry run \u2014 no rows moved. Re-run without --dry-run to apply.")),0;let r=n.map(c=>c.id),o=Date.now(),a=Pr(c=>c.transaction(d=>{let m=0,h=c.prepare(`INSERT OR IGNORE INTO archive.messages_archive
724
724
  (uuid, session_id, parent_uuid, type, role, timestamp,
725
725
  is_sidechain, content_text, tool_names, raw_json, archived_at)
726
726
  SELECT uuid, session_id, parent_uuid, type, role, timestamp,
727
727
  is_sidechain, content_text, tool_names, raw_json, datetime('now')
728
- FROM messages WHERE session_id = ?`),S=c.prepare("DELETE FROM messages WHERE session_id = ?"),b=c.prepare("UPDATE sessions SET archive_status = 'archived', archived_at = datetime('now') WHERE id = ?");for(let T of d){h.run(T);let R=S.run(T);m+=Number(R.changes??0),b.run(T)}return m})(r));return console.log(`Archived ${n.length.toLocaleString()} session(s), moved ${a.toLocaleString()} message(s) in ${Date.now()-o}ms.`),console.log(we.dim(" Run `recall optimize --vacuum` (with the daemon stopped) to reclaim disk pages from the moved rows.")),0}function Df(e){if(!e)return console.error("Usage: recall archive restore <session-id>"),1;let n=f().prepare("SELECT id, archive_status FROM sessions WHERE id = ?").get(e);if(!n)return console.error(`Session ${e} not found.`),1;if(n.archive_status!=="archived")return console.error(`Session ${e} is not archived (status=${n.archive_status}).`),1;let s=Fr(r=>r.transaction(()=>{let a=r.prepare(`INSERT OR IGNORE INTO messages
728
+ FROM messages WHERE session_id = ?`),b=c.prepare("DELETE FROM messages WHERE session_id = ?"),S=c.prepare("UPDATE sessions SET archive_status = 'archived', archived_at = datetime('now') WHERE id = ?");for(let T of d){h.run(T);let R=b.run(T);m+=Number(R.changes??0),S.run(T)}return m})(r));return console.log(`Archived ${n.length.toLocaleString()} session(s), moved ${a.toLocaleString()} message(s) in ${Date.now()-o}ms.`),console.log(we.dim(" Run `recall optimize --vacuum` (with the daemon stopped) to reclaim disk pages from the moved rows.")),0}function qf(e){if(!e)return console.error("Usage: recall archive restore <session-id>"),1;let n=f().prepare("SELECT id, archive_status FROM sessions WHERE id = ?").get(e);if(!n)return console.error(`Session ${e} not found.`),1;if(n.archive_status!=="archived")return console.error(`Session ${e} is not archived (status=${n.archive_status}).`),1;let s=Pr(r=>r.transaction(()=>{let a=r.prepare(`INSERT OR IGNORE INTO messages
729
729
  (uuid, session_id, parent_uuid, type, role, timestamp,
730
730
  is_sidechain, content_text, tool_names, raw_json)
731
731
  SELECT uuid, session_id, parent_uuid, type, role, timestamp,
@@ -735,32 +735,32 @@ CREATE INDEX IF NOT EXISTS idx_synth_results_created
735
735
  is_sidechain, content_text, tool_names, raw_json)
736
736
  SELECT uuid, session_id, parent_uuid, type, role, timestamp,
737
737
  is_sidechain, content_text, tool_names, raw_json
738
- FROM archive.messages_archive WHERE session_id = ?`),u=r.prepare("DELETE FROM main.messages_archive WHERE session_id = ?"),d=r.prepare("DELETE FROM archive.messages_archive WHERE session_id = ?"),m=Number(a.run(e).changes??0),h=Number(c.run(e).changes??0);return u.run(e),d.run(e),r.prepare("UPDATE sessions SET archive_status = 'live', archived_at = NULL WHERE id = ?").run(e),m+h})());return console.log(`Restored ${s.toLocaleString()} message(s) for session ${e}.`),0}function Ff(){let e=jr();return console.log(we.dim("\u2014 Auto-archive \u2014")),console.log(` Enabled ${e.autoArchiveEnabled?we.ok("YES"):"no"}`),console.log(` After ${e.autoArchiveAfterDays} days`),console.log(` Last run ${e.lastRunAt??"\u2014"}`),0}function Pf(e){if(e===void 0||!Number.isFinite(e))return console.error("Usage: recall archive auto on --after <days>"),1;let t=Math.floor(e);if(t<7||t>3650)return console.error("--after must be between 7 and 3650 days"),1;let n=Gn({autoArchiveEnabled:!0,autoArchiveAfterDays:t});return console.log(`Auto-archive: ENABLED (after ${n.autoArchiveAfterDays} days).`),console.log(we.dim(" The daemon will run a daily archive pass on the next tick.")),0}function $f(){return Gn({autoArchiveEnabled:!1}),console.log("Auto-archive: DISABLED. Existing archived sessions stay archived."),0}async function Uf(e){let t=e._action??"list";if(t==="list"||t==="stats")return jf();if(t==="run")return e.before?Mf({before:e.before,dryRun:e.dryRun===!0}):(console.error("Usage: recall archive run --before YYYY-MM-DD [--dry-run]"),1);if(t==="restore")return Df(e._sessionId??"");if(t==="auto"){let n=e._subAction??"status";return n==="status"?Ff():n==="on"||n==="enable"?Pf(e.after):n==="off"||n==="disable"?$f():(console.error("Usage: recall archive auto <status|on|off> [--after <days>]"),1)}return console.error(`Usage: recall archive <list|run|restore|auto> [args]
738
+ FROM archive.messages_archive WHERE session_id = ?`),u=r.prepare("DELETE FROM main.messages_archive WHERE session_id = ?"),d=r.prepare("DELETE FROM archive.messages_archive WHERE session_id = ?"),m=Number(a.run(e).changes??0),h=Number(c.run(e).changes??0);return u.run(e),d.run(e),r.prepare("UPDATE sessions SET archive_status = 'live', archived_at = NULL WHERE id = ?").run(e),m+h})());return console.log(`Restored ${s.toLocaleString()} message(s) for session ${e}.`),0}function Xf(){let e=Mr();return console.log(we.dim("\u2014 Auto-archive \u2014")),console.log(` Enabled ${e.autoArchiveEnabled?we.ok("YES"):"no"}`),console.log(` After ${e.autoArchiveAfterDays} days`),console.log(` Last run ${e.lastRunAt??"\u2014"}`),0}function Jf(e){if(e===void 0||!Number.isFinite(e))return console.error("Usage: recall archive auto on --after <days>"),1;let t=Math.floor(e);if(t<7||t>3650)return console.error("--after must be between 7 and 3650 days"),1;let n=zn({autoArchiveEnabled:!0,autoArchiveAfterDays:t});return console.log(`Auto-archive: ENABLED (after ${n.autoArchiveAfterDays} days).`),console.log(we.dim(" The daemon will run a daily archive pass on the next tick.")),0}function Gf(){return zn({autoArchiveEnabled:!1}),console.log("Auto-archive: DISABLED. Existing archived sessions stay archived."),0}async function Yf(e){let t=e._action??"list";if(t==="list"||t==="stats")return Hf();if(t==="run")return e.before?Wf({before:e.before,dryRun:e.dryRun===!0}):(console.error("Usage: recall archive run --before YYYY-MM-DD [--dry-run]"),1);if(t==="restore")return qf(e._sessionId??"");if(t==="auto"){let n=e._subAction??"status";return n==="status"?Xf():n==="on"||n==="enable"?Jf(e.after):n==="off"||n==="disable"?Gf():(console.error("Usage: recall archive auto <status|on|off> [--after <days>]"),1)}return console.error(`Usage: recall archive <list|run|restore|auto> [args]
739
739
  list \u2014 show archive counts
740
740
  run --before YYYY-MM-DD [--dry-run] \u2014 move sessions older than DATE
741
741
  restore <session-id> \u2014 pull a session back from archive
742
- auto <status|on|off> [--after N] \u2014 daemon auto-archives sessions older than N days`),1}var lc=ae(()=>{"use strict";zn();U();Dr();Mr()});import{cpus as Uw}from"node:os";import{Hono as uw}from"hono";import{serve as dw}from"@hono/node-server";ee();import{existsSync as Rm,readFileSync as km,writeFileSync as l0,unlinkSync as u0}from"node:fs";import{join as Am}from"node:path";var Ci=Am(H,"license.json");function Ht(){if(!Rm(Ci))return null;try{let e=km(Ci,"utf8"),t=JSON.parse(e);return typeof t.license_jwt!="string"||t.license_jwt.length===0?null:t}catch{return null}}import{jwtVerify as xm,importSPKI as Nm}from"jose";var vi=`-----BEGIN PUBLIC KEY-----
742
+ auto <status|on|off> [--after N] \u2014 daemon auto-archives sessions older than N days`),1}var gc=ae(()=>{"use strict";Kn();B();Fr();Dr()});import{cpus as c0}from"node:os";import{Hono as vw}from"hono";import{serve as Iw}from"@hono/node-server";ee();import{existsSync as Cm,readFileSync as vm,writeFileSync as C0,unlinkSync as v0}from"node:fs";import{join as Im}from"node:path";var Pi=Im(W,"license.json");function Ht(){if(!Cm(Pi))return null;try{let e=vm(Pi,"utf8"),t=JSON.parse(e);return typeof t.license_jwt!="string"||t.license_jwt.length===0?null:t}catch{return null}}import{jwtVerify as jm,importSPKI as Mm}from"jose";var $i=`-----BEGIN PUBLIC KEY-----
743
743
  MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZysO2FffTLdyxQnTmnt78/ayvqz9
744
744
  kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
745
745
  -----END PUBLIC KEY-----
746
- `,rr="ES256",Ii="clauderecall.com",ji="clauderecall-cli";var Nn=null;async function Om(){return Nn||(Nn=await Nm(vi,rr),Nn)}async function Mi(e){try{let t=await Om(),{payload:n}=await xm(e,t,{issuer:Ii,audience:ji,algorithms:[rr]});return{valid:!0,claims:n}}catch(t){return{valid:!1,reason:t instanceof Error?t.message:"verification failed"}}}import{createHash as Lm}from"node:crypto";import{hostname as Cm,userInfo as vm,platform as Im,arch as jm}from"node:os";function Di(){let e="unknown";try{e=vm().username}catch{}let t=[Cm(),e,Im(),jm()];return Lm("sha256").update(t.join("\0")).digest("hex")}ee();import{existsSync as Mm,readFileSync as Dm,writeFileSync as Fm}from"node:fs";import{join as Pm}from"node:path";function Fi(){let e=process.env.RECALL_API_BASE;if(e&&e.length>0){let t=e.replace(/\/$/,""),n;try{n=new URL(t)}catch{throw new Error(`RECALL_API_BASE is not a valid URL: ${t}`)}let s=n.hostname==="127.0.0.1"||n.hostname==="localhost"||n.hostname==="::1";if(n.protocol==="https:"||n.protocol==="http:"&&s)return t;throw new Error(`RECALL_API_BASE must be HTTPS, or HTTP with loopback hostname. Got: ${t}`)}return"https://clauderecall.com"}var or=Pm(H,"license-check.json"),$m=1440*60*1e3,Um=720*60*60*1e3,Bm=1e4;function Pi(){if(!Mm(or))return null;try{let e=JSON.parse(Dm(or,"utf8"));return typeof e.license_key!="string"||typeof e.last_checked_at!="string"||typeof e.revoked!="boolean"?null:e}catch{return null}}function Hm(e){z(),Fm(or,JSON.stringify(e,null,2)+`
747
- `,{mode:384})}async function Wm(e,t){let n=null,s=null;try{n=new AbortController,s=setTimeout(()=>n?.abort(),Bm);let r=await fetch(t,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({license_key:e}),signal:n.signal});if(!r.ok)return null;let o=await r.json();return typeof o?.revoked!="boolean"?null:o}catch{return null}finally{s&&clearTimeout(s)}}async function $i(e,t={}){let n=Pi(),s=t.apiUrl??`${Fi()}/api/license/check`,r=n?.license_key===e,o=!n||!r||Date.now()-new Date(n.last_checked_at).getTime()>=$m;if(!t.force&&!o)return n;let a=await Wm(e,s);if(!a)return r?n:null;let c={license_key:e,last_checked_at:new Date().toISOString(),revoked:a.revoked,reason:a.reason??null};return Hm(c),c}function Ui(e){let t=Pi();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()>Um?{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 qm=Date.UTC(2026,5,1,7,0,0);var Xm=1440*60*1e3,O0=60*Xm;async function Ke(){let e=Ht();if(!e)return{tier:"free"};let t=await Mi(e.license_jwt);if(!t.valid||!t.claims)return{tier:"free",invalid_reason:t.reason};if(t.claims.machine_fp&&t.claims.machine_fp!==Di())return{tier:"free",invalid_reason:"machine fingerprint mismatch \u2014 re-activate on this device"};let n=Ui(e.license_key);return n?.revoked?{tier:"free",invalid_reason:n.reason}:Jm(e,t.claims)}async function Bi(e){let t=Ht();if(!t)return{ran:!1,revoked:!1,reason:null,last_checked_at:null};let n=await $i(t.license_key,{force:e?.force??!1});return n?{ran:!0,revoked:n.revoked,reason:n.reason,last_checked_at:n.last_checked_at}:{ran:!0,revoked:!1,reason:null,last_checked_at:null}}function Jm(e,t){let n=t.test_mode===!0&&process.env.NODE_ENV==="production";return{tier:n?"free":"pro",key_short:e.key_short,customer_email:e.customer_email,activated_at:e.activated_at,test_mode:e.test_mode,...n?{test_mode_blocked:!0}:{},expires_at:typeof t.exp=="number"?new Date(t.exp*1e3).toISOString():null}}async function Hi(){return(await Ke()).tier==="pro"}U();U();import{createHash as pg}from"node:crypto";U();ee();import{writeFileSync as Vm,readFileSync as G0,existsSync as Zm,mkdirSync as Qm,readdirSync as z0,unlinkSync as K0}from"node:fs";import{join as zi}from"node:path";import{randomUUID as Ki}from"node:crypto";var cr=zi(H,"bug-patterns");function eg(){z(),Zm(cr)||Qm(cr,{recursive:!0})}function $e(e){return{id:e.id,signature_hash:e.signature_hash,example_message:e.example_message,occurrence_count:e.occurrence_count,first_seen_at:e.first_seen_at,last_seen_at:e.last_seen_at,resolved_in_session_id:e.resolved_in_session_id,fix_summary:e.fix_summary}}function Vi(e){return{cluster_id:e.cluster_id,session_id:e.session_id,matched_at:e.matched_at}}function Zi(e){if(!e.signature_hash)throw new Error("signature_hash is required");if(!e.example_message)throw new Error("example_message is required");if(!Array.isArray(e.member_session_ids)||e.member_session_ids.length===0)throw new Error("at least one member_session_id is required");let t=f(),n=new Date().toISOString(),s=e.id??Ki(),r=e.first_seen_at??n,o=e.last_seen_at??n,a=Array.from(new Set(e.member_session_ids));t.transaction(()=>{t.prepare(`INSERT INTO bug_pattern_clusters
746
+ `,or="ES256",Ui="clauderecall.com",Bi="clauderecall-cli";var Nn=null;async function Dm(){return Nn||(Nn=await Mm($i,or),Nn)}async function Hi(e){try{let t=await Dm(),{payload:n}=await jm(e,t,{issuer:Ui,audience:Bi,algorithms:[or]});return{valid:!0,claims:n}}catch(t){return{valid:!1,reason:t instanceof Error?t.message:"verification failed"}}}import{createHash as Fm}from"node:crypto";import{hostname as Pm,userInfo as $m,platform as Um,arch as Bm}from"node:os";function Wi(){let e="unknown";try{e=$m().username}catch{}let t=[Pm(),e,Um(),Bm()];return Fm("sha256").update(t.join("\0")).digest("hex")}ee();import{existsSync as Hm,readFileSync as Wm,writeFileSync as qm}from"node:fs";import{join as Xm}from"node:path";function qi(){let e=process.env.RECALL_API_BASE;if(e&&e.length>0){let t=e.replace(/\/$/,""),n;try{n=new URL(t)}catch{throw new Error(`RECALL_API_BASE is not a valid URL: ${t}`)}let s=n.hostname==="127.0.0.1"||n.hostname==="localhost"||n.hostname==="::1";if(n.protocol==="https:"||n.protocol==="http:"&&s)return t;throw new Error(`RECALL_API_BASE must be HTTPS, or HTTP with loopback hostname. Got: ${t}`)}return"https://clauderecall.com"}var ir=Xm(W,"license-check.json"),Jm=1440*60*1e3,Gm=720*60*60*1e3,Ym=1e4;function Xi(){if(!Hm(ir))return null;try{let e=JSON.parse(Wm(ir,"utf8"));return typeof e.license_key!="string"||typeof e.last_checked_at!="string"||typeof e.revoked!="boolean"?null:e}catch{return null}}function zm(e){z(),qm(ir,JSON.stringify(e,null,2)+`
747
+ `,{mode:384})}async function Km(e,t){let n=null,s=null;try{n=new AbortController,s=setTimeout(()=>n?.abort(),Ym);let r=await fetch(t,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({license_key:e}),signal:n.signal});if(!r.ok)return null;let o=await r.json();return typeof o?.revoked!="boolean"?null:o}catch{return null}finally{s&&clearTimeout(s)}}async function Ji(e,t={}){let n=Xi(),s=t.apiUrl??`${qi()}/api/license/check`,r=n?.license_key===e,o=!n||!r||Date.now()-new Date(n.last_checked_at).getTime()>=Jm;if(!t.force&&!o)return n;let a=await Km(e,s);if(!a)return r?n:null;let c={license_key:e,last_checked_at:new Date().toISOString(),revoked:a.revoked,reason:a.reason??null};return zm(c),c}function Gi(e){let t=Xi();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()>Gm?{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 Vm=Date.UTC(2026,5,1,7,0,0);var Zm=1440*60*1e3,V0=60*Zm;async function Ke(){let e=Ht();if(!e)return{tier:"free"};let t=await Hi(e.license_jwt);if(!t.valid||!t.claims)return{tier:"free",invalid_reason:t.reason};if(t.claims.machine_fp&&t.claims.machine_fp!==Wi())return{tier:"free",invalid_reason:"machine fingerprint mismatch \u2014 re-activate on this device"};let n=Gi(e.license_key);return n?.revoked?{tier:"free",invalid_reason:n.reason}:Qm(e,t.claims)}async function Yi(e){let t=Ht();if(!t)return{ran:!1,revoked:!1,reason:null,last_checked_at:null};let n=await Ji(t.license_key,{force:e?.force??!1});return n?{ran:!0,revoked:n.revoked,reason:n.reason,last_checked_at:n.last_checked_at}:{ran:!0,revoked:!1,reason:null,last_checked_at:null}}function Qm(e,t){let n=t.test_mode===!0&&process.env.NODE_ENV==="production";return{tier:n?"free":"pro",key_short:e.key_short,customer_email:e.customer_email,activated_at:e.activated_at,test_mode:e.test_mode,...n?{test_mode_blocked:!0}:{},expires_at:typeof t.exp=="number"?new Date(t.exp*1e3).toISOString():null}}async function zi(){return(await Ke()).tier==="pro"}B();B();import{createHash as Sg}from"node:crypto";B();ee();import{writeFileSync as rg,readFileSync as fR,existsSync as og,mkdirSync as ig,readdirSync as hR,unlinkSync as ER}from"node:fs";import{join as na}from"node:path";import{randomUUID as sa}from"node:crypto";var lr=na(W,"bug-patterns");function ag(){z(),og(lr)||ig(lr,{recursive:!0})}function $e(e){return{id:e.id,signature_hash:e.signature_hash,example_message:e.example_message,occurrence_count:e.occurrence_count,first_seen_at:e.first_seen_at,last_seen_at:e.last_seen_at,resolved_in_session_id:e.resolved_in_session_id,fix_summary:e.fix_summary}}function ra(e){return{cluster_id:e.cluster_id,session_id:e.session_id,matched_at:e.matched_at}}function oa(e){if(!e.signature_hash)throw new Error("signature_hash is required");if(!e.example_message)throw new Error("example_message is required");if(!Array.isArray(e.member_session_ids)||e.member_session_ids.length===0)throw new Error("at least one member_session_id is required");let t=f(),n=new Date().toISOString(),s=e.id??sa(),r=e.first_seen_at??n,o=e.last_seen_at??n,a=Array.from(new Set(e.member_session_ids));t.transaction(()=>{t.prepare(`INSERT INTO bug_pattern_clusters
748
748
  (id, signature_hash, example_message, occurrence_count,
749
749
  first_seen_at, last_seen_at, resolved_in_session_id, fix_summary)
750
750
  VALUES (?, ?, ?, ?, ?, ?, NULL, NULL)`).run(s,e.signature_hash,e.example_message,a.length,r,o);let u=t.prepare(`INSERT INTO bug_pattern_members (cluster_id, session_id, matched_at)
751
751
  VALUES (?, ?, ?)
752
- ON CONFLICT(cluster_id, session_id) DO NOTHING`);for(let d of a)u.run(s,d,n)})();let c=Qi(s);if(!c)throw new Error("createCluster succeeded but read-back failed");return Wt(s),c}function Qi(e){let t=f(),n=t.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);if(!n)return null;let s=t.prepare("SELECT * FROM bug_pattern_members WHERE cluster_id = ? ORDER BY matched_at ASC, session_id ASC").all(e);return{cluster:$e(n),members:s.map(Vi)}}function ea(e,t){if(!e)throw new Error("clusterId is required");if(!Array.isArray(t)||t.length===0)throw new Error("sessionIds must be a non-empty array");let n=f();if(!n.prepare("SELECT 1 FROM bug_pattern_clusters WHERE id = ?").get(e))throw new Error(`cluster ${e} not found`);let r=new Date().toISOString(),o=0;n.transaction(()=>{let c=n.prepare(`INSERT INTO bug_pattern_members (cluster_id, session_id, matched_at)
752
+ ON CONFLICT(cluster_id, session_id) DO NOTHING`);for(let d of a)u.run(s,d,n)})();let c=ia(s);if(!c)throw new Error("createCluster succeeded but read-back failed");return Wt(s),c}function ia(e){let t=f(),n=t.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);if(!n)return null;let s=t.prepare("SELECT * FROM bug_pattern_members WHERE cluster_id = ? ORDER BY matched_at ASC, session_id ASC").all(e);return{cluster:$e(n),members:s.map(ra)}}function aa(e,t){if(!e)throw new Error("clusterId is required");if(!Array.isArray(t)||t.length===0)throw new Error("sessionIds must be a non-empty array");let n=f();if(!n.prepare("SELECT 1 FROM bug_pattern_clusters WHERE id = ?").get(e))throw new Error(`cluster ${e} not found`);let r=new Date().toISOString(),o=0;n.transaction(()=>{let c=n.prepare(`INSERT INTO bug_pattern_members (cluster_id, session_id, matched_at)
753
753
  VALUES (?, ?, ?)
754
754
  ON CONFLICT(cluster_id, session_id) DO NOTHING`);for(let u of Array.from(new Set(t)))c.run(e,u,r).changes>0&&(o+=1);if(o>0){let u=n.prepare("SELECT COUNT(*) AS n FROM bug_pattern_members WHERE cluster_id = ?").get(e).n;n.prepare(`UPDATE bug_pattern_clusters
755
755
  SET occurrence_count = ?, last_seen_at = ?
756
- WHERE id = ?`).run(u,r,e)}})(),o>0&&Wt(e);let a=n.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);return{cluster:$e(a),added:o}}function ta(e={}){let t=f(),n=[],s=[];typeof e.minOccurrenceCount=="number"&&(n.push("c.occurrence_count >= ?"),s.push(Math.max(1,Math.floor(e.minOccurrenceCount)))),typeof e.hasResolved=="boolean"&&n.push(e.hasResolved?"c.resolved_in_session_id IS NOT NULL":"c.resolved_in_session_id IS NULL"),e.project&&(n.push(`EXISTS (
756
+ WHERE id = ?`).run(u,r,e)}})(),o>0&&Wt(e);let a=n.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);return{cluster:$e(a),added:o}}function ca(e={}){let t=f(),n=[],s=[];typeof e.minOccurrenceCount=="number"&&(n.push("c.occurrence_count >= ?"),s.push(Math.max(1,Math.floor(e.minOccurrenceCount)))),typeof e.hasResolved=="boolean"&&n.push(e.hasResolved?"c.resolved_in_session_id IS NOT NULL":"c.resolved_in_session_id IS NULL"),e.project&&(n.push(`EXISTS (
757
757
  SELECT 1 FROM bug_pattern_members m
758
758
  JOIN sessions s ON s.id = m.session_id
759
759
  JOIN projects p ON p.id = s.project_id
760
760
  WHERE m.cluster_id = c.id AND p.name = ?
761
761
  )`),s.push(e.project));let r=n.length>0?`WHERE ${n.join(" AND ")}`:"",o=t.prepare(`SELECT COUNT(*) AS n FROM bug_pattern_clusters c ${r}`).get(...s),a=Math.max(1,Math.min(5e3,e.limit??100)),c=Math.max(0,Math.floor(e.offset??0));return{clusters:t.prepare(`SELECT c.* FROM bug_pattern_clusters c ${r}
762
762
  ORDER BY c.occurrence_count DESC, c.last_seen_at DESC
763
- LIMIT ? OFFSET ?`).all(...s,a,c).map($e),total:o.n}}function tg(e){let t=e.first_user_message?e.first_user_message.slice(0,80):null,n=e.alias??e.auto_title??t??e.session_id.slice(0,8);return{cluster_id:e.cluster_id,session_id:e.session_id,matched_at:e.matched_at,title:n,alias:e.alias,auto_title:e.auto_title,project:e.project,started_at:e.started_at}}function na(e){let t=f(),n=t.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);if(!n)return null;let s=t.prepare(`SELECT m.cluster_id, m.session_id, m.matched_at,
763
+ LIMIT ? OFFSET ?`).all(...s,a,c).map($e),total:o.n}}function cg(e){let t=e.first_user_message?e.first_user_message.slice(0,80):null,n=e.alias??e.auto_title??t??e.session_id.slice(0,8);return{cluster_id:e.cluster_id,session_id:e.session_id,matched_at:e.matched_at,title:n,alias:e.alias,auto_title:e.auto_title,project:e.project,started_at:e.started_at}}function la(e){let t=f(),n=t.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);if(!n)return null;let s=t.prepare(`SELECT m.cluster_id, m.session_id, m.matched_at,
764
764
  NULLIF(sa.alias, '') AS alias,
765
765
  s.auto_title,
766
766
  s.first_user_message,
@@ -771,31 +771,31 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
771
771
  LEFT JOIN session_aliases sa ON sa.session_id = m.session_id
772
772
  LEFT JOIN projects p ON p.id = s.project_id
773
773
  WHERE m.cluster_id = ?
774
- ORDER BY COALESCE(s.started_at, ''), m.matched_at, m.session_id`).all(e);return{cluster:$e(n),members:s.map(tg)}}function sa(e,t,n){if(!e)throw new Error("clusterId is required");if(!t)throw new Error("sessionId is required");if(typeof n!="string"||!n.trim())throw new Error("fixSummary is required");let s=f();if(!s.prepare("SELECT 1 FROM bug_pattern_clusters WHERE id = ?").get(e))throw new Error(`cluster ${e} not found`);if(!s.prepare("SELECT 1 FROM bug_pattern_members WHERE cluster_id = ? AND session_id = ?").get(e,t))throw new Error(`session ${t} is not a member of cluster ${e}`);s.prepare(`UPDATE bug_pattern_clusters
774
+ ORDER BY COALESCE(s.started_at, ''), m.matched_at, m.session_id`).all(e);return{cluster:$e(n),members:s.map(cg)}}function ua(e,t,n){if(!e)throw new Error("clusterId is required");if(!t)throw new Error("sessionId is required");if(typeof n!="string"||!n.trim())throw new Error("fixSummary is required");let s=f();if(!s.prepare("SELECT 1 FROM bug_pattern_clusters WHERE id = ?").get(e))throw new Error(`cluster ${e} not found`);if(!s.prepare("SELECT 1 FROM bug_pattern_members WHERE cluster_id = ? AND session_id = ?").get(e,t))throw new Error(`session ${t} is not a member of cluster ${e}`);s.prepare(`UPDATE bug_pattern_clusters
775
775
  SET resolved_in_session_id = ?, fix_summary = ?
776
- WHERE id = ?`).run(t,n.trim(),e),Wt(e);let a=s.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);return{cluster:$e(a)}}function ra(e,t){if(!e)throw new Error("clusterId is required");if(!Array.isArray(t)||t.length===0)throw new Error("memberSessionIds must be a non-empty array");let n=f(),s=n.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);if(!s)throw new Error(`cluster ${e} not found`);let r=Array.from(new Set(t)),o=r.map(()=>"?").join(","),a=n.prepare(`SELECT session_id, matched_at FROM bug_pattern_members
777
- WHERE cluster_id = ? AND session_id IN (${o})`).all(e,...r);if(a.length===0)throw new Error(`none of the supplied session_ids are members of cluster ${e}`);let c=n.prepare("SELECT COUNT(*) AS n FROM bug_pattern_members WHERE cluster_id = ?").get(e).n;if(a.length>=c)throw new Error(`cannot split: would leave the original cluster empty (move ${a.length} of ${c})`);let u=Ki(),d=new Date().toISOString(),m=[];n.transaction(()=>{n.prepare(`INSERT INTO bug_pattern_clusters
776
+ WHERE id = ?`).run(t,n.trim(),e),Wt(e);let a=s.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);return{cluster:$e(a)}}function da(e,t){if(!e)throw new Error("clusterId is required");if(!Array.isArray(t)||t.length===0)throw new Error("memberSessionIds must be a non-empty array");let n=f(),s=n.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);if(!s)throw new Error(`cluster ${e} not found`);let r=Array.from(new Set(t)),o=r.map(()=>"?").join(","),a=n.prepare(`SELECT session_id, matched_at FROM bug_pattern_members
777
+ WHERE cluster_id = ? AND session_id IN (${o})`).all(e,...r);if(a.length===0)throw new Error(`none of the supplied session_ids are members of cluster ${e}`);let c=n.prepare("SELECT COUNT(*) AS n FROM bug_pattern_members WHERE cluster_id = ?").get(e).n;if(a.length>=c)throw new Error(`cannot split: would leave the original cluster empty (move ${a.length} of ${c})`);let u=sa(),d=new Date().toISOString(),m=[];n.transaction(()=>{n.prepare(`INSERT INTO bug_pattern_clusters
778
778
  (id, signature_hash, example_message, occurrence_count,
779
779
  first_seen_at, last_seen_at, resolved_in_session_id, fix_summary)
780
- VALUES (?, ?, ?, ?, ?, ?, NULL, NULL)`).run(u,s.signature_hash,s.example_message,a.length,s.first_seen_at,d);let b=n.prepare(`INSERT INTO bug_pattern_members (cluster_id, session_id, matched_at)
781
- VALUES (?, ?, ?)`),T=n.prepare("DELETE FROM bug_pattern_members WHERE cluster_id = ? AND session_id = ?");for(let w of a)b.run(u,w.session_id,w.matched_at),T.run(e,w.session_id);let R=c-a.length;n.prepare("UPDATE bug_pattern_clusters SET occurrence_count = ? WHERE id = ?").run(R,e),m=n.prepare("SELECT * FROM bug_pattern_members WHERE cluster_id = ?").all(u)})(),Wt(e),Wt(u);let h=n.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e),S=n.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(u);return{original:$e(h),split:$e(S),movedMembers:m.map(Vi)}}function Wt(e){try{eg();let t=Qi(e);if(!t)return;let n=zi(cr,`${e}.json`),s={schema:"claude-recall.bug-pattern-cluster.v1",cluster:t.cluster,members:t.members,backed_up_at:new Date().toISOString()};Vm(n,JSON.stringify(s,null,2))}catch(t){console.error("[bug-patterns] backup failed:",t)}}function oa(e){return e?f().prepare(`SELECT * FROM bug_pattern_clusters
780
+ VALUES (?, ?, ?, ?, ?, ?, NULL, NULL)`).run(u,s.signature_hash,s.example_message,a.length,s.first_seen_at,d);let S=n.prepare(`INSERT INTO bug_pattern_members (cluster_id, session_id, matched_at)
781
+ VALUES (?, ?, ?)`),T=n.prepare("DELETE FROM bug_pattern_members WHERE cluster_id = ? AND session_id = ?");for(let O of a)S.run(u,O.session_id,O.matched_at),T.run(e,O.session_id);let R=c-a.length;n.prepare("UPDATE bug_pattern_clusters SET occurrence_count = ? WHERE id = ?").run(R,e),m=n.prepare("SELECT * FROM bug_pattern_members WHERE cluster_id = ?").all(u)})(),Wt(e),Wt(u);let h=n.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e),b=n.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(u);return{original:$e(h),split:$e(b),movedMembers:m.map(ra)}}function Wt(e){try{ag();let t=ia(e);if(!t)return;let n=na(lr,`${e}.json`),s={schema:"claude-recall.bug-pattern-cluster.v1",cluster:t.cluster,members:t.members,backed_up_at:new Date().toISOString()};rg(n,JSON.stringify(s,null,2))}catch(t){console.error("[bug-patterns] backup failed:",t)}}function pa(e){return e?f().prepare(`SELECT * FROM bug_pattern_clusters
782
782
  WHERE signature_hash = ?
783
- ORDER BY last_seen_at DESC, id ASC`).all(e).map($e):[]}function ia(e){if(!e)return new Set;let n=f().prepare(`SELECT DISTINCT m.session_id
783
+ ORDER BY last_seen_at DESC, id ASC`).all(e).map($e):[]}function ma(e){if(!e)return new Set;let n=f().prepare(`SELECT DISTINCT m.session_id
784
784
  FROM bug_pattern_members m
785
785
  JOIN bug_pattern_clusters c ON c.id = m.cluster_id
786
- WHERE c.signature_hash = ?`).all(e);return new Set(n.map(s=>s.session_id))}var mg=/\b0x[0-9a-fA-F]+\b/g,gg=/\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\b/g,_g=/\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z?\b/g,fg=/:\d+:\d+/g,hg=/\bline\s+\d+\b/gi,Eg=/\bcolumn\s+\d+\b/gi,bg=/\b(?:pid|PID|process(?:\s+id)?)\s*[:=]?\s*\d+\b/gi,Sg=/\b(?:port|:)\s*[:=]?\s*\d{2,5}\b/gi,Tg=/\b\d{4,}\b/g,yg=/(['"`])[^'"`\n]{1,128}\1/g;function wg(e){if(!e)return"";let t=String(e);return t=t.replace(mg,"<hex>"),t=t.replace(gg,"<uuid>"),t=t.replace(_g,"<ts>"),t=t.replace(fg,":<line>:<col>"),t=t.replace(hg,"line <n>"),t=t.replace(Eg,"column <n>"),t=t.replace(bg,"pid <n>"),t=t.replace(Sg,"port <n>"),t=t.replace(Tg,"<num>"),t=t.replace(yg,"<arg>"),t=t.replace(/\s+/g," ").trim(),t.toLowerCase()}function Rg(e){let t=(e.error_type??"unknown").toLowerCase().trim(),n=wg(e.snippet??e.message_hash??""),s=`${t}|${n}`;return pg("sha256").update(s).digest("hex").slice(0,16)}function kg(e){let t=f(),n=["oi.bug_signatures IS NOT NULL"],s=[];e&&(n.push("p.name = ?"),s.push(e));let r=`WHERE ${n.join(" AND ")}`,o=t.prepare(`SELECT oi.session_id AS session_id,
786
+ WHERE c.signature_hash = ?`).all(e);return new Set(n.map(s=>s.session_id))}var Tg=/\b0x[0-9a-fA-F]+\b/g,yg=/\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\b/g,wg=/\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z?\b/g,Rg=/:\d+:\d+/g,kg=/\bline\s+\d+\b/gi,Ag=/\bcolumn\s+\d+\b/gi,xg=/\b(?:pid|PID|process(?:\s+id)?)\s*[:=]?\s*\d+\b/gi,Ng=/\b(?:port|:)\s*[:=]?\s*\d{2,5}\b/gi,Og=/\b\d{4,}\b/g,Lg=/(['"`])[^'"`\n]{1,128}\1/g;function Cg(e){if(!e)return"";let t=String(e);return t=t.replace(Tg,"<hex>"),t=t.replace(yg,"<uuid>"),t=t.replace(wg,"<ts>"),t=t.replace(Rg,":<line>:<col>"),t=t.replace(kg,"line <n>"),t=t.replace(Ag,"column <n>"),t=t.replace(xg,"pid <n>"),t=t.replace(Ng,"port <n>"),t=t.replace(Og,"<num>"),t=t.replace(Lg,"<arg>"),t=t.replace(/\s+/g," ").trim(),t.toLowerCase()}function vg(e){let t=(e.error_type??"unknown").toLowerCase().trim(),n=Cg(e.snippet??e.message_hash??""),s=`${t}|${n}`;return Sg("sha256").update(s).digest("hex").slice(0,16)}function Ig(e){let t=f(),n=["oi.bug_signatures IS NOT NULL"],s=[];e&&(n.push("p.name = ?"),s.push(e));let r=`WHERE ${n.join(" AND ")}`,o=t.prepare(`SELECT oi.session_id AS session_id,
787
787
  p.name AS project,
788
788
  s.started_at AS started_at,
789
789
  oi.bug_signatures AS bug_signatures
790
790
  FROM session_output_index oi
791
791
  LEFT JOIN sessions s ON s.id = oi.session_id
792
792
  LEFT JOIN projects p ON p.id = s.project_id
793
- ${r}`).all(...s),a=[];for(let c of o){if(!c.bug_signatures)continue;let u=[];try{let d=JSON.parse(c.bug_signatures);Array.isArray(d)&&(u=d)}catch{continue}for(let d of u){if(!d||typeof d!="object"||!(d.snippet??"").trim())continue;let h=Rg(d);a.push({session_id:c.session_id,project:c.project,started_at:c.started_at,signature:d,fingerprint:h})}}return a}function Ag(e){let t=new Map;for(let s of e){let r=t.get(s.fingerprint);r||(r=[],t.set(s.fingerprint,r)),r.push(s)}let n=[];for(let[s,r]of t){let o=new Set,a=[];for(let m of r)o.has(m.session_id)||(o.add(m.session_id),a.push(m));let c=[...a].sort((m,h)=>{let S=m.started_at??"",b=h.started_at??"";return S&&b?S<b?-1:S>b?1:0:S?-1:b?1:0}),u=c.find(m=>m.started_at),d=[...c].reverse().find(m=>m.started_at);n.push({fingerprint:s,example_message:a[0].signature.snippet??a[0].signature.message_hash??"",members:a,first_seen_at:u?.started_at??new Date().toISOString(),last_seen_at:d?.started_at??new Date().toISOString()})}return n}function xg(e,t){if(e.length!==t.length)return 0;let n=0,s=0,r=0;for(let a=0;a<e.length;a++)n+=e[a]*t[a],s+=e[a]*e[a],r+=t[a]*t[a];let o=Math.sqrt(s)*Math.sqrt(r);return o>0?n/o:0}function Ng(e){let{records:t,vectors:n,epsilon:s,minPts:r}=e,o=t.length;if(o===0)return[];let a=[];for(let m=0;m<o;m++){let h=[];for(let S=0;S<o;S++){if(m===S)continue;1-xg(n[m],n[S])<=s&&h.push(S)}a.push(h)}let c=new Array(o).fill(!1),u=new Array(o).fill(-1),d=[];for(let m=0;m<o;m++){if(c[m])continue;c[m]=!0;let h=a[m];if(h.length<r)continue;let S=d.length;d.push({members:[t[m]]}),u[m]=S;let b=[...h];for(;b.length>0;){let T=b.shift();if(!c[T]&&(c[T]=!0,a[T].length>=r))for(let R of a[T])(!c[R]||u[R]===-1)&&b.push(R);u[T]===-1&&(u[T]=S,d[S].members.push(t[T]))}}return d}async function Og(e,t,n,s){if(e.length===0)return[];let r=e.map(u=>{let d=u.signature.snippet??u.signature.message_hash??"";return`${u.signature.error_type??""}: ${d}`.trim()}),o=await t(r);if(o.length!==e.length)throw new Error(`embedder returned ${o.length} vectors for ${e.length} inputs`);let a=Ng({records:e,vectors:o,epsilon:n,minPts:s}),c=[];for(let u of a){if(u.members.length===0)continue;let d=new Set,m=[];for(let w of u.members)d.has(w.session_id)||(d.add(w.session_id),m.push(w));if(m.length===0)continue;let S=`sem:${[...m.map(w=>w.fingerprint)].sort()[0]}`,b=[...m].sort((w,j)=>{let M=w.started_at??"",W=j.started_at??"";return M<W?-1:M>W?1:0}),T=b.find(w=>w.started_at),R=[...b].reverse().find(w=>w.started_at);c.push({fingerprint:S,example_message:m[0].signature.snippet??m[0].signature.message_hash??"",members:m,first_seen_at:T?.started_at??new Date().toISOString(),last_seen_at:R?.started_at??new Date().toISOString()})}return c}function ga(e,t){let n={clusters_created:0,clusters_merged:0,members_added:0,cluster_ids:[]};for(let s of e){if(s.members.length<t)continue;let r=oa(s.fingerprint),o=ia(s.fingerprint),a=s.members.map(d=>d.session_id).filter(d=>!o.has(d));if(r.length===0){let d=Zi({signature_hash:s.fingerprint,example_message:s.example_message.slice(0,256),member_session_ids:s.members.map(m=>m.session_id),first_seen_at:s.first_seen_at,last_seen_at:s.last_seen_at});n.clusters_created+=1,n.members_added+=d.members.length,n.cluster_ids.push(d.cluster.id);continue}if(a.length===0){n.cluster_ids.push(r[0].id);continue}let c=r[0],u=ea(c.id,a);u.added>0&&(n.clusters_merged+=1,n.members_added+=u.added),n.cluster_ids.push(c.id)}return n}async function _a(e={}){let t=Math.max(2,Math.floor(e.minClusterSize??3)),n=Math.max(1,Math.min(5e3,Math.floor(e.limit??1e3))),s=e.semanticEpsilon??.15,r=Math.max(1,Math.floor(e.semanticMinPts??1)),o=kg(e.project),a=new Set(o.map(M=>M.session_id)),c=Ag(o),u=[],d=!1;if(e.semantic){let M=e.embedder??null;if(!M)try{M=await vg()}catch(W){let P=(W instanceof Error?W.message:String(W)).split(`
794
- `)[0];console.warn(`[bug-pattern] --semantic requested but the embedder is unavailable: ${P}
795
- Falling back to exact-match-only clustering. Run \`recall semantic install\` to enable the semantic pass.`),d=!0}if(M){let W=[];for(let x of c)x.members.length===1&&W.push(x.members[0]);W.length>=2&&(u=await Og(W,M,s,r))}}let m=c.filter(M=>M.members.length>=t),h=u.filter(M=>M.members.length>=t),S=ga(m,t),b=ga(h,t),T=[...S.cluster_ids,...b.cluster_ids],R=Array.from(new Set(T)),w=[];if(R.length>0){let M=f(),W=R.map(()=>"?").join(","),x=M.prepare(`SELECT * FROM bug_pattern_clusters
796
- WHERE id IN (${W})
793
+ ${r}`).all(...s),a=[];for(let c of o){if(!c.bug_signatures)continue;let u=[];try{let d=JSON.parse(c.bug_signatures);Array.isArray(d)&&(u=d)}catch{continue}for(let d of u){if(!d||typeof d!="object"||!(d.snippet??"").trim())continue;let h=vg(d);a.push({session_id:c.session_id,project:c.project,started_at:c.started_at,signature:d,fingerprint:h})}}return a}function jg(e){let t=new Map;for(let s of e){let r=t.get(s.fingerprint);r||(r=[],t.set(s.fingerprint,r)),r.push(s)}let n=[];for(let[s,r]of t){let o=new Set,a=[];for(let m of r)o.has(m.session_id)||(o.add(m.session_id),a.push(m));let c=[...a].sort((m,h)=>{let b=m.started_at??"",S=h.started_at??"";return b&&S?b<S?-1:b>S?1:0:b?-1:S?1:0}),u=c.find(m=>m.started_at),d=[...c].reverse().find(m=>m.started_at);n.push({fingerprint:s,example_message:a[0].signature.snippet??a[0].signature.message_hash??"",members:a,first_seen_at:u?.started_at??new Date().toISOString(),last_seen_at:d?.started_at??new Date().toISOString()})}return n}function Mg(e,t){if(e.length!==t.length)return 0;let n=0,s=0,r=0;for(let a=0;a<e.length;a++)n+=e[a]*t[a],s+=e[a]*e[a],r+=t[a]*t[a];let o=Math.sqrt(s)*Math.sqrt(r);return o>0?n/o:0}function Dg(e){let{records:t,vectors:n,epsilon:s,minPts:r}=e,o=t.length;if(o===0)return[];let a=[];for(let m=0;m<o;m++){let h=[];for(let b=0;b<o;b++){if(m===b)continue;1-Mg(n[m],n[b])<=s&&h.push(b)}a.push(h)}let c=new Array(o).fill(!1),u=new Array(o).fill(-1),d=[];for(let m=0;m<o;m++){if(c[m])continue;c[m]=!0;let h=a[m];if(h.length<r)continue;let b=d.length;d.push({members:[t[m]]}),u[m]=b;let S=[...h];for(;S.length>0;){let T=S.shift();if(!c[T]&&(c[T]=!0,a[T].length>=r))for(let R of a[T])(!c[R]||u[R]===-1)&&S.push(R);u[T]===-1&&(u[T]=b,d[b].members.push(t[T]))}}return d}async function Fg(e,t,n,s){if(e.length===0)return[];let r=e.map(u=>{let d=u.signature.snippet??u.signature.message_hash??"";return`${u.signature.error_type??""}: ${d}`.trim()}),o=await t(r);if(o.length!==e.length)throw new Error(`embedder returned ${o.length} vectors for ${e.length} inputs`);let a=Dg({records:e,vectors:o,epsilon:n,minPts:s}),c=[];for(let u of a){if(u.members.length===0)continue;let d=new Set,m=[];for(let O of u.members)d.has(O.session_id)||(d.add(O.session_id),m.push(O));if(m.length===0)continue;let b=`sem:${[...m.map(O=>O.fingerprint)].sort()[0]}`,S=[...m].sort((O,L)=>{let x=O.started_at??"",F=L.started_at??"";return x<F?-1:x>F?1:0}),T=S.find(O=>O.started_at),R=[...S].reverse().find(O=>O.started_at);c.push({fingerprint:b,example_message:m[0].signature.snippet??m[0].signature.message_hash??"",members:m,first_seen_at:T?.started_at??new Date().toISOString(),last_seen_at:R?.started_at??new Date().toISOString()})}return c}function ba(e,t){let n={clusters_created:0,clusters_merged:0,members_added:0,cluster_ids:[]};for(let s of e){if(s.members.length<t)continue;let r=pa(s.fingerprint),o=ma(s.fingerprint),a=s.members.map(d=>d.session_id).filter(d=>!o.has(d));if(r.length===0){let d=oa({signature_hash:s.fingerprint,example_message:s.example_message.slice(0,256),member_session_ids:s.members.map(m=>m.session_id),first_seen_at:s.first_seen_at,last_seen_at:s.last_seen_at});n.clusters_created+=1,n.members_added+=d.members.length,n.cluster_ids.push(d.cluster.id);continue}if(a.length===0){n.cluster_ids.push(r[0].id);continue}let c=r[0],u=aa(c.id,a);u.added>0&&(n.clusters_merged+=1,n.members_added+=u.added),n.cluster_ids.push(c.id)}return n}async function Sa(e={}){let t=Math.max(2,Math.floor(e.minClusterSize??3)),n=Math.max(1,Math.min(5e3,Math.floor(e.limit??1e3))),s=e.semanticEpsilon??.15,r=Math.max(1,Math.floor(e.semanticMinPts??1)),o=Ig(e.project),a=new Set(o.map(x=>x.session_id)),c=jg(o),u=[],d=!1;if(e.semantic){let x=e.embedder??null;if(!x)try{x=await Ug()}catch(F){let $=(F instanceof Error?F.message:String(F)).split(`
794
+ `)[0];console.warn(`[bug-pattern] --semantic requested but the embedder is unavailable: ${$}
795
+ Falling back to exact-match-only clustering. Run \`recall semantic install\` to enable the semantic pass.`),d=!0}if(x){let F=[];for(let A of c)A.members.length===1&&F.push(A.members[0]);F.length>=2&&(u=await Fg(F,x,s,r))}}let m=c.filter(x=>x.members.length>=t),h=u.filter(x=>x.members.length>=t),b=ba(m,t),S=ba(h,t),T=[...b.cluster_ids,...S.cluster_ids],R=Array.from(new Set(T)),O=[];if(R.length>0){let x=f(),F=R.map(()=>"?").join(","),A=x.prepare(`SELECT * FROM bug_pattern_clusters
796
+ WHERE id IN (${F})
797
797
  ORDER BY occurrence_count DESC, last_seen_at DESC
798
- LIMIT ?`).all(...R,n);for(let P of x)w.push({id:P.id,signature_hash:P.signature_hash,example_message:P.example_message,occurrence_count:P.occurrence_count,first_seen_at:P.first_seen_at,last_seen_at:P.last_seen_at,resolved_in_session_id:P.resolved_in_session_id,fix_summary:P.fix_summary})}return{progress:{total_sessions:a.size,total_signatures:o.length,exact_match_groups:m.length,semantic_groups:h.length,clusters_created:S.clusters_created+b.clusters_created,clusters_merged:S.clusters_merged+b.clusters_merged,members_added:S.members_added+b.members_added,semantic_skipped:d},clusters:w}}var Lg=async()=>{let{embed:e,loadEmbedder:t,getEmbedderStatus:n}=await Promise.resolve().then(()=>(Ve(),ma));return n().loaded||await t(),e},Cg=Lg;async function vg(){return Cg()}U();U();ee();import{writeFileSync as fa,readFileSync as hR,existsSync as ha,mkdirSync as Ea,readdirSync as ER}from"node:fs";import{join as vn}from"node:path";var Ig=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),ba=new Set(["regex","llm","embedding","manual","auto","citation","git","terminal-registry"]),jg=new Set(["pending","approved","rejected"]),Mg=new Set(["L1","L2","L3","L4","user"]),pr=vn(H,"links"),mr=vn(H,"suggestions"),Dg=vn(mr,"index.json");function Fg(){z(),ha(pr)||Ea(pr,{recursive:!0})}function Pg(){z(),ha(mr)||Ea(mr,{recursive:!0})}function Sa(e){try{return JSON.parse(e)}catch{return e}}function In(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:Sa(e.evidence),approved:e.approved===1,created_at:e.created_at,updated_at:e.updated_at}}function gr(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:Sa(e.evidence),status:e.status,inferred_by:e.inferred_by,created_at:e.created_at,decided_at:e.decided_at}}function Ta(e){if(!Number.isFinite(e)||e<0||e>1)throw new Error("confidence must be a number in [0, 1]")}function _r(e){if(!Ig.has(e))throw new Error(`invalid link_type: ${e}`)}function $g(e){if(!ba.has(e))throw new Error(`invalid source: ${e}`)}function ya(e){if(!Mg.has(e))throw new Error(`invalid inferred_by: ${e}`)}function wa(e,t){if(!e||!t)throw new Error("source_session_id and target_session_id are required");if(e===t)throw new Error("a session cannot link to itself")}function Ra(e){wa(e.source_session_id,e.target_session_id),_r(e.link_type),$g(e.source),Ta(e.confidence);let t=f(),n=new Date().toISOString(),s=JSON.stringify(e.evidence??null),r=e.approved?1:0;t.prepare(`INSERT INTO session_links
798
+ LIMIT ?`).all(...R,n);for(let $ of A)O.push({id:$.id,signature_hash:$.signature_hash,example_message:$.example_message,occurrence_count:$.occurrence_count,first_seen_at:$.first_seen_at,last_seen_at:$.last_seen_at,resolved_in_session_id:$.resolved_in_session_id,fix_summary:$.fix_summary})}return{progress:{total_sessions:a.size,total_signatures:o.length,exact_match_groups:m.length,semantic_groups:h.length,clusters_created:b.clusters_created+S.clusters_created,clusters_merged:b.clusters_merged+S.clusters_merged,members_added:b.members_added+S.members_added,semantic_skipped:d},clusters:O}}var Pg=async()=>{let{embed:e,loadEmbedder:t,getEmbedderStatus:n}=await Promise.resolve().then(()=>(ct(),Ea));return n().loaded||await t(),e},$g=Pg;async function Ug(){return $g()}B();B();ee();import{writeFileSync as Ta,readFileSync as $R,existsSync as ya,mkdirSync as wa,readdirSync as UR}from"node:fs";import{join as In}from"node:path";var Bg=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),Ra=new Set(["regex","llm","embedding","manual","auto","citation","git","terminal-registry"]),Hg=new Set(["pending","approved","rejected"]),Wg=new Set(["L1","L2","L3","L4","user"]),mr=In(W,"links"),gr=In(W,"suggestions"),qg=In(gr,"index.json");function Xg(){z(),ya(mr)||wa(mr,{recursive:!0})}function Jg(){z(),ya(gr)||wa(gr,{recursive:!0})}function ka(e){try{return JSON.parse(e)}catch{return e}}function jn(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:ka(e.evidence),approved:e.approved===1,created_at:e.created_at,updated_at:e.updated_at}}function _r(e){return{id:e.id,source_session_id:e.source_session_id,target_session_id:e.target_session_id,link_type:e.link_type,confidence:e.confidence,evidence:ka(e.evidence),status:e.status,inferred_by:e.inferred_by,created_at:e.created_at,decided_at:e.decided_at}}function Aa(e){if(!Number.isFinite(e)||e<0||e>1)throw new Error("confidence must be a number in [0, 1]")}function fr(e){if(!Bg.has(e))throw new Error(`invalid link_type: ${e}`)}function Gg(e){if(!Ra.has(e))throw new Error(`invalid source: ${e}`)}function xa(e){if(!Wg.has(e))throw new Error(`invalid inferred_by: ${e}`)}function Na(e,t){if(!e||!t)throw new Error("source_session_id and target_session_id are required");if(e===t)throw new Error("a session cannot link to itself")}function Oa(e){Na(e.source_session_id,e.target_session_id),fr(e.link_type),Gg(e.source),Aa(e.confidence);let t=f(),n=new Date().toISOString(),s=JSON.stringify(e.evidence??null),r=e.approved?1:0;t.prepare(`INSERT INTO session_links
799
799
  (source_session_id, target_session_id, link_type,
800
800
  confidence, source, evidence, approved,
801
801
  created_at, updated_at)
@@ -808,11 +808,11 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
808
808
  updated_at = excluded.updated_at`).run(e.source_session_id,e.target_session_id,e.link_type,e.confidence,e.source,s,r,n,n);let o=t.prepare(`SELECT * FROM session_links
809
809
  WHERE source_session_id = ?
810
810
  AND target_session_id = ?
811
- AND link_type = ?`).get(e.source_session_id,e.target_session_id,e.link_type);if(!o)throw new Error("createLink succeeded but read-back failed");return hr(e.source_session_id),In(o)}function jn(e={}){let t=f(),n=[],s=[];e.sourceSessionId&&(n.push("source_session_id = ?"),s.push(e.sourceSessionId)),e.targetSessionId&&(n.push("target_session_id = ?"),s.push(e.targetSessionId)),e.linkType&&(_r(e.linkType),n.push("link_type = ?"),s.push(e.linkType)),e.approvedOnly&&n.push("approved = 1");let r=n.length?`WHERE ${n.join(" AND ")}`:"",o=Math.max(1,Math.min(5e3,e.limit??1e3));return t.prepare(`SELECT * FROM session_links ${r}
811
+ AND link_type = ?`).get(e.source_session_id,e.target_session_id,e.link_type);if(!o)throw new Error("createLink succeeded but read-back failed");return Er(e.source_session_id),jn(o)}function Mn(e={}){let t=f(),n=[],s=[];e.sourceSessionId&&(n.push("source_session_id = ?"),s.push(e.sourceSessionId)),e.targetSessionId&&(n.push("target_session_id = ?"),s.push(e.targetSessionId)),e.linkType&&(fr(e.linkType),n.push("link_type = ?"),s.push(e.linkType)),e.approvedOnly&&n.push("approved = 1");let r=n.length?`WHERE ${n.join(" AND ")}`:"",o=Math.max(1,Math.min(5e3,e.limit??1e3));return t.prepare(`SELECT * FROM session_links ${r}
812
812
  ORDER BY confidence DESC, updated_at DESC
813
- LIMIT ?`).all(...s,o).map(In)}function Jt(e){return f().prepare(`SELECT * FROM session_links
813
+ LIMIT ?`).all(...s,o).map(jn)}function Jt(e){return f().prepare(`SELECT * FROM session_links
814
814
  WHERE source_session_id = ? OR target_session_id = ?
815
- ORDER BY confidence DESC, updated_at DESC`).all(e,e).map(In)}function ka(e){let t=f(),n=t.prepare("SELECT source_session_id FROM session_links WHERE id = ?").get(e);if(!n)return{removed:0,sourceSessionId:null};let s=t.prepare("DELETE FROM session_links WHERE id = ?").run(e);return s.changes>0&&hr(n.source_session_id),{removed:s.changes,sourceSessionId:n.source_session_id}}function Yt(e){wa(e.source_session_id,e.target_session_id),_r(e.link_type),Ta(e.confidence),ya(e.inferred_by);let t=f(),n=new Date().toISOString(),s=JSON.stringify(e.evidence??null);t.prepare(`INSERT INTO session_link_suggestions
815
+ ORDER BY confidence DESC, updated_at DESC`).all(e,e).map(jn)}function La(e){let t=f(),n=t.prepare("SELECT source_session_id FROM session_links WHERE id = ?").get(e);if(!n)return{removed:0,sourceSessionId:null};let s=t.prepare("DELETE FROM session_links WHERE id = ?").run(e);return s.changes>0&&Er(n.source_session_id),{removed:s.changes,sourceSessionId:n.source_session_id}}function Gt(e){Na(e.source_session_id,e.target_session_id),fr(e.link_type),Aa(e.confidence),xa(e.inferred_by);let t=f(),n=new Date().toISOString(),s=JSON.stringify(e.evidence??null);t.prepare(`INSERT INTO session_link_suggestions
816
816
  (source_session_id, target_session_id, link_type,
817
817
  confidence, evidence, status, inferred_by,
818
818
  created_at, decided_at)
@@ -832,9 +832,9 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
832
832
  WHERE source_session_id = ?
833
833
  AND target_session_id = ?
834
834
  AND link_type = ?
835
- AND inferred_by = ?`).get(e.source_session_id,e.target_session_id,e.link_type,e.inferred_by);if(!r)throw new Error("createSuggestion succeeded but read-back failed");return Aa(),gr(r)}function lt(e={}){let t=f(),n=[],s=[];if(e.status){if(!jg.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&&(ya(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}
835
+ AND inferred_by = ?`).get(e.source_session_id,e.target_session_id,e.link_type,e.inferred_by);if(!r)throw new Error("createSuggestion succeeded but read-back failed");return Ca(),_r(r)}function lt(e={}){let t=f(),n=[],s=[];if(e.status){if(!Hg.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&&(xa(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}
836
836
  ORDER BY confidence DESC, created_at DESC
837
- LIMIT ?`).all(...s,o).map(gr)}function fr(e,t,n={}){if(t!=="approved"&&t!=="rejected")throw new Error(`invalid decision: ${t}`);let s=n.source??"manual";if(!ba.has(s))throw new Error(`invalid source: ${s}`);let r=f(),o=r.prepare("SELECT * FROM session_link_suggestions WHERE id = ?").get(e);if(!o)throw new Error(`suggestion ${e} not found`);if(o.status!=="pending")throw new Error(`suggestion ${e} already decided as ${o.status}`);let a=new Date().toISOString(),c;r.transaction(()=>{r.prepare(`UPDATE session_link_suggestions
837
+ LIMIT ?`).all(...s,o).map(_r)}function hr(e,t,n={}){if(t!=="approved"&&t!=="rejected")throw new Error(`invalid decision: ${t}`);let s=n.source??"manual";if(!Ra.has(s))throw new Error(`invalid source: ${s}`);let r=f(),o=r.prepare("SELECT * FROM session_link_suggestions WHERE id = ?").get(e);if(!o)throw new Error(`suggestion ${e} not found`);if(o.status!=="pending")throw new Error(`suggestion ${e} already decided as ${o.status}`);let a=new Date().toISOString(),c;r.transaction(()=>{r.prepare(`UPDATE session_link_suggestions
838
838
  SET status = ?, decided_at = ?
839
839
  WHERE id = ?`).run(t,a,e),t==="approved"&&(r.prepare(`INSERT INTO session_links
840
840
  (source_session_id, target_session_id, link_type,
@@ -849,7 +849,7 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
849
849
  updated_at = excluded.updated_at`).run(o.source_session_id,o.target_session_id,o.link_type,o.confidence,s,o.evidence,a,a),c=r.prepare(`SELECT * FROM session_links
850
850
  WHERE source_session_id = ?
851
851
  AND target_session_id = ?
852
- AND link_type = ?`).get(o.source_session_id,o.target_session_id,o.link_type))})(),Aa(),t==="approved"&&hr(o.source_session_id);let u=r.prepare("SELECT * FROM session_link_suggestions WHERE id = ?").get(e);return{suggestion:gr(u),link:c?In(c):null}}function hr(e){try{Fg();let t=jn({sourceSessionId:e}),n=vn(pr,`${e}.json`);if(t.length===0)return;let s={schema:"claude-recall.session-links.v1",source_session_id:e,backed_up_at:new Date().toISOString(),links:t};fa(n,JSON.stringify(s,null,2))}catch(t){console.error("[session-links] backup failed:",t)}}function Aa(){try{Pg();let e=lt({limit:5e3}),t={schema:"claude-recall.session-link-suggestions.v1",backed_up_at:new Date().toISOString(),suggestions:e};fa(Dg,JSON.stringify(t,null,2))}catch(e){console.error("[session-links] suggestions backup failed:",e)}}U();ee();import{writeFileSync as Ug,readFileSync as RR,existsSync as Bg,mkdirSync as Hg,readdirSync as kR}from"node:fs";import{join as xa}from"node:path";var Er=xa(H,"output-index");function Wg(){z(),Bg(Er)||Hg(Er,{recursive:!0})}function Gt(e){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}function qg(e){if(!e)return null;try{return JSON.parse(e)}catch{return e}}function Na(e){return{session_id:e.session_id,files_written:Gt(e.files_written),brands_mentioned:Gt(e.brands_mentioned),terms_introduced:Gt(e.terms_introduced),plan_ids_referenced:Gt(e.plan_ids_referenced),bug_signatures:Gt(e.bug_signatures),raw_extraction:qg(e.raw_extraction),extracted_at:e.extracted_at,extractor_version:e.extractor_version}}function Oa(e){if(!e.session_id)throw new Error("session_id is required");let t=f(),n=new Date().toISOString(),s=JSON.stringify(e.files_written??[]),r=JSON.stringify(e.brands_mentioned??[]),o=JSON.stringify(e.terms_introduced??[]),a=JSON.stringify(e.plan_ids_referenced??[]),c=JSON.stringify(e.bug_signatures??[]),u=e.raw_extraction===void 0?null:JSON.stringify(e.raw_extraction),d=Math.max(1,Math.floor(e.extractor_version??1));t.prepare(`INSERT INTO session_output_index
852
+ AND link_type = ?`).get(o.source_session_id,o.target_session_id,o.link_type))})(),Ca(),t==="approved"&&Er(o.source_session_id);let u=r.prepare("SELECT * FROM session_link_suggestions WHERE id = ?").get(e);return{suggestion:_r(u),link:c?jn(c):null}}function Er(e){try{Xg();let t=Mn({sourceSessionId:e}),n=In(mr,`${e}.json`);if(t.length===0)return;let s={schema:"claude-recall.session-links.v1",source_session_id:e,backed_up_at:new Date().toISOString(),links:t};Ta(n,JSON.stringify(s,null,2))}catch(t){console.error("[session-links] backup failed:",t)}}function Ca(){try{Jg();let e=lt({limit:5e3}),t={schema:"claude-recall.session-link-suggestions.v1",backed_up_at:new Date().toISOString(),suggestions:e};Ta(qg,JSON.stringify(t,null,2))}catch(e){console.error("[session-links] suggestions backup failed:",e)}}B();ee();import{writeFileSync as Yg,readFileSync as JR,existsSync as zg,mkdirSync as Kg,readdirSync as GR}from"node:fs";import{join as va}from"node:path";var br=va(W,"output-index");function Vg(){z(),zg(br)||Kg(br,{recursive:!0})}function Yt(e){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}function Zg(e){if(!e)return null;try{return JSON.parse(e)}catch{return e}}function Ia(e){return{session_id:e.session_id,files_written:Yt(e.files_written),brands_mentioned:Yt(e.brands_mentioned),terms_introduced:Yt(e.terms_introduced),plan_ids_referenced:Yt(e.plan_ids_referenced),bug_signatures:Yt(e.bug_signatures),raw_extraction:Zg(e.raw_extraction),extracted_at:e.extracted_at,extractor_version:e.extractor_version}}function ja(e){if(!e.session_id)throw new Error("session_id is required");let t=f(),n=new Date().toISOString(),s=JSON.stringify(e.files_written??[]),r=JSON.stringify(e.brands_mentioned??[]),o=JSON.stringify(e.terms_introduced??[]),a=JSON.stringify(e.plan_ids_referenced??[]),c=JSON.stringify(e.bug_signatures??[]),u=e.raw_extraction===void 0?null:JSON.stringify(e.raw_extraction),d=Math.max(1,Math.floor(e.extractor_version??1));t.prepare(`INSERT INTO session_output_index
853
853
  (session_id, files_written, brands_mentioned, terms_introduced,
854
854
  plan_ids_referenced, bug_signatures, raw_extraction,
855
855
  extracted_at, extractor_version)
@@ -862,11 +862,11 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
862
862
  bug_signatures = excluded.bug_signatures,
863
863
  raw_extraction = excluded.raw_extraction,
864
864
  extracted_at = excluded.extracted_at,
865
- extractor_version = excluded.extractor_version`).run(e.session_id,s,r,o,a,c,u,n,d);let m=t.prepare("SELECT * FROM session_output_index WHERE session_id = ?").get(e.session_id);if(!m)throw new Error("setOutputIndex succeeded but read-back failed");let h=Na(m);return Xg(e.session_id),h}function Ze(e){let n=f().prepare("SELECT * FROM session_output_index WHERE session_id = ?").get(e);return n?Na(n):null}function Xg(e){try{Wg();let t=Ze(e);if(!t)return;let n=xa(Er,`${e}.json`),s={schema:"claude-recall.session-output-index.v1",backed_up_at:new Date().toISOString(),...t};Ug(n,JSON.stringify(s,null,2))}catch(t){console.error("[output-index] backup failed:",t)}}var br={citation:"same-project",similar:"same-project",skill_track:"same-project",bug_pattern:"cross-project",wiki_link:"cross-project",temporal_proximity:"same-project"},Jg=2,Yg=.25,Gg=5,zg=60,Kg=25;function Mn(e){return e.trim().toLowerCase()}function Vg(e){let t=new Set;for(let n of e.files_written)t.add(`file:${Mn(n)}`);for(let n of e.brands_mentioned)t.add(`brand:${Mn(n)}`);for(let n of e.terms_introduced)t.add(`term:${Mn(n)}`);for(let n of e.plan_ids_referenced)t.add(`plan:${Mn(n)}`);return t}function Zg(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/zg);return Math.max(.2,t)}function Qg(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 e_(e){let t=Ze(e);return t?{session_id:t.session_id,files_written:t.files_written,brands_mentioned:t.brands_mentioned,terms_introduced:t.terms_introduced.map(n=>n.term),plan_ids_referenced:t.plan_ids_referenced}:null}function t_(e){return f().prepare(`SELECT s.id AS id, s.project_id AS project_id, s.started_at AS started_at
865
+ extractor_version = excluded.extractor_version`).run(e.session_id,s,r,o,a,c,u,n,d);let m=t.prepare("SELECT * FROM session_output_index WHERE session_id = ?").get(e.session_id);if(!m)throw new Error("setOutputIndex succeeded but read-back failed");let h=Ia(m);return Qg(e.session_id),h}function Ve(e){let n=f().prepare("SELECT * FROM session_output_index WHERE session_id = ?").get(e);return n?Ia(n):null}function Qg(e){try{Vg();let t=Ve(e);if(!t)return;let n=va(br,`${e}.json`),s={schema:"claude-recall.session-output-index.v1",backed_up_at:new Date().toISOString(),...t};Yg(n,JSON.stringify(s,null,2))}catch(t){console.error("[output-index] backup failed:",t)}}var Sr={citation:"same-project",similar:"same-project",skill_track:"same-project",bug_pattern:"cross-project",wiki_link:"cross-project",temporal_proximity:"same-project"},e_=2,t_=.25,n_=5,s_=60,r_=25;function Dn(e){return e.trim().toLowerCase()}function o_(e){let t=new Set;for(let n of e.files_written)t.add(`file:${Dn(n)}`);for(let n of e.brands_mentioned)t.add(`brand:${Dn(n)}`);for(let n of e.terms_introduced)t.add(`term:${Dn(n)}`);for(let n of e.plan_ids_referenced)t.add(`plan:${Dn(n)}`);return t}function i_(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/s_);return Math.max(.2,t)}function a_(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 c_(e){let t=Ve(e);return t?{session_id:t.session_id,files_written:t.files_written,brands_mentioned:t.brands_mentioned,terms_introduced:t.terms_introduced.map(n=>n.term),plan_ids_referenced:t.plan_ids_referenced}:null}function l_(e){return f().prepare(`SELECT s.id AS id, s.project_id AS project_id, s.started_at AS started_at
866
866
  FROM sessions s
867
867
  JOIN session_output_index oi ON oi.session_id = s.id
868
868
  WHERE s.project_id = ?
869
- ORDER BY COALESCE(s.started_at, ''), s.id`).all(e)}function n_(e,t){let n=new Map,s=new Map,r=new Map;for(let o of e){r.set(o.id,o.started_at);let a=t.get(o.id);if(!a)continue;let c=Vg(a);if(c.size!==0){s.set(o.id,c);for(let u of c){let d=n.get(u);d?d.push(o.id):n.set(u,[o.id])}}}return{posting:n,vocab:s,startedAt:r}}function s_(e,t){let n=t.vocab.get(e),s=t.startedAt.get(e)??null;if(!n||!s)return[];let r=new Map;for(let a of n){let c=t.posting.get(a);if(c)for(let u of c){if(u===e)continue;let d=t.startedAt.get(u);if(!d||d>=s)continue;let m=r.get(u);m?m.push(a):r.set(u,[a])}}let o=[];for(let[a,c]of r){let u=c.length;if(u<Jg)continue;let d=t.startedAt.get(a)??null,m=Qg(s,d),h=Zg(m),S=Math.min(1,u/Gg*h);if(S<Yg)continue;let b=c.slice(0,12);o.push({target_session_id:a,matched_terms:b,overlap:u,days_apart:Math.round(m*10)/10,recency:Math.round(h*1e3)/1e3,confidence:Math.round(S*1e3)/1e3})}return o.sort((a,c)=>c.confidence-a.confidence),o.slice(0,Kg)}async function La(e){if(br.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project \u2014 refusing to run inference");let t=t_(e.projectId),n=new Map;for(let a of t){let c=e_(a.id);c&&n.set(a.id,c)}let s=n_(t,n),r={total_sessions:t.length,processed_sessions:0,suggestions_created:0,suggestions_skipped_existing:0,current_session_id:null};e.onProgress?.({...r});let o=[];for(let a of t){if(e.signal?.aborted)break;r.current_session_id=a.id,e.onProgress?.({...r});let c=s_(a.id,s);for(let u of c)try{let d=Yt({source_session_id:a.id,target_session_id:u.target_session_id,link_type:"citation",confidence:u.confidence,evidence:{matched_terms:u.matched_terms,overlap_count:u.overlap,recency:u.recency,days_apart:u.days_apart},inferred_by:"L2"});o.push(d.id),r.suggestions_created+=1}catch(d){console.error("[citation-inference] createSuggestion failed:",d)}r.processed_sessions+=1,e.onProgress?.({...r})}return r.current_session_id=null,e.onProgress?.({...r}),{progress:r,suggestion_ids:o}}U();var r_=/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/gi,o_=[/\bv\d+\.\d+(?:\.[A-Za-z]+)?\b/g,/\bPhase\s+[A-Ha-h]\b/g,/\bL\d+\b/g,/MASTER-PLAN-[A-Za-z-]+/g],i_=.95,a_=.85;var Sr=50;function c_(e){if(!e)return[];let t=new Set,n=[],s=e.match(r_);if(!s)return n;for(let r of s){let o=r.toLowerCase();if(!t.has(o)&&(t.add(o),n.push(o),n.length>=Sr))break}return n}function l_(e){if(!e)return[];let t=new Set,n=[];for(let s of o_){s.lastIndex=0;let r=e.match(s);if(r){for(let o of r){let a=o.trim().toLowerCase().replace(/\s+/g," ");if(!(!a||a.length>64)&&!t.has(a)&&(t.add(a),n.push(a),n.length>=Sr))break}if(n.length>=Sr)break}}return n}function Ca(e){let t=f();return typeof e=="number"?t.prepare("SELECT id, project_id FROM sessions WHERE project_id = ?").all(e):t.prepare("SELECT id, project_id FROM sessions").all()}function va(e){let t=f();return typeof e=="number"?t.prepare(`SELECT m.uuid AS message_uuid, m.session_id, m.content_text,
869
+ ORDER BY COALESCE(s.started_at, ''), s.id`).all(e)}function u_(e,t){let n=new Map,s=new Map,r=new Map;for(let o of e){r.set(o.id,o.started_at);let a=t.get(o.id);if(!a)continue;let c=o_(a);if(c.size!==0){s.set(o.id,c);for(let u of c){let d=n.get(u);d?d.push(o.id):n.set(u,[o.id])}}}return{posting:n,vocab:s,startedAt:r}}function d_(e,t){let n=t.vocab.get(e),s=t.startedAt.get(e)??null;if(!n||!s)return[];let r=new Map;for(let a of n){let c=t.posting.get(a);if(c)for(let u of c){if(u===e)continue;let d=t.startedAt.get(u);if(!d||d>=s)continue;let m=r.get(u);m?m.push(a):r.set(u,[a])}}let o=[];for(let[a,c]of r){let u=c.length;if(u<e_)continue;let d=t.startedAt.get(a)??null,m=a_(s,d),h=i_(m),b=Math.min(1,u/n_*h);if(b<t_)continue;let S=c.slice(0,12);o.push({target_session_id:a,matched_terms:S,overlap:u,days_apart:Math.round(m*10)/10,recency:Math.round(h*1e3)/1e3,confidence:Math.round(b*1e3)/1e3})}return o.sort((a,c)=>c.confidence-a.confidence),o.slice(0,r_)}async function Ma(e){if(Sr.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project \u2014 refusing to run inference");let t=l_(e.projectId),n=new Map;for(let a of t){let c=c_(a.id);c&&n.set(a.id,c)}let s=u_(t,n),r={total_sessions:t.length,processed_sessions:0,suggestions_created:0,suggestions_skipped_existing:0,current_session_id:null};e.onProgress?.({...r});let o=[];for(let a of t){if(e.signal?.aborted)break;r.current_session_id=a.id,e.onProgress?.({...r});let c=d_(a.id,s);for(let u of c)try{let d=Gt({source_session_id:a.id,target_session_id:u.target_session_id,link_type:"citation",confidence:u.confidence,evidence:{matched_terms:u.matched_terms,overlap_count:u.overlap,recency:u.recency,days_apart:u.days_apart},inferred_by:"L2"});o.push(d.id),r.suggestions_created+=1}catch(d){console.error("[citation-inference] createSuggestion failed:",d)}r.processed_sessions+=1,e.onProgress?.({...r})}return r.current_session_id=null,e.onProgress?.({...r}),{progress:r,suggestion_ids:o}}B();var p_=/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/gi,m_=[/\bv\d+\.\d+(?:\.[A-Za-z]+)?\b/g,/\bPhase\s+[A-Ha-h]\b/g,/\bL\d+\b/g,/MASTER-PLAN-[A-Za-z-]+/g],g_=.95,__=.85;var Tr=50;function f_(e){if(!e)return[];let t=new Set,n=[],s=e.match(p_);if(!s)return n;for(let r of s){let o=r.toLowerCase();if(!t.has(o)&&(t.add(o),n.push(o),n.length>=Tr))break}return n}function h_(e){if(!e)return[];let t=new Set,n=[];for(let s of m_){s.lastIndex=0;let r=e.match(s);if(r){for(let o of r){let a=o.trim().toLowerCase().replace(/\s+/g," ");if(!(!a||a.length>64)&&!t.has(a)&&(t.add(a),n.push(a),n.length>=Tr))break}if(n.length>=Tr)break}}return n}function Da(e){let t=f();return typeof e=="number"?t.prepare("SELECT id, project_id FROM sessions WHERE project_id = ?").all(e):t.prepare("SELECT id, project_id FROM sessions").all()}function Fa(e){let t=f();return typeof e=="number"?t.prepare(`SELECT m.uuid AS message_uuid, m.session_id, m.content_text,
870
870
  s.project_id
871
871
  FROM messages m
872
872
  JOIN sessions s ON s.id = m.session_id
@@ -879,13 +879,13 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
879
879
  JOIN sessions s ON s.id = m.session_id
880
880
  WHERE m.is_sidechain = 0
881
881
  AND m.content_text IS NOT NULL
882
- AND length(m.content_text) > 0`).all()}function u_(e){let t=f(),n=typeof e=="number"?"WHERE s.project_id = ?":"",s=typeof e=="number"?[e]:[];return t.prepare(`SELECT oi.session_id AS session_id,
882
+ AND length(m.content_text) > 0`).all()}function E_(e){let t=f(),n=typeof e=="number"?"WHERE s.project_id = ?":"",s=typeof e=="number"?[e]:[];return t.prepare(`SELECT oi.session_id AS session_id,
883
883
  s.project_id AS project_id,
884
884
  oi.plan_ids_referenced AS plan_ids_json
885
885
  FROM session_output_index oi
886
886
  JOIN sessions s ON s.id = oi.session_id
887
- ${n}`).all(...s)}function d_(e){if(!e)return[];try{let t=JSON.parse(e);if(Array.isArray(t))return t.filter(n=>typeof n=="string")}catch{}return[]}function Ia(e={}){if(br.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project");let t=Ca(e.projectId),n=new Set(t.map(o=>o.id)),s=new Map;for(let o of t)s.set(o.id,o.project_id);let r=0;for(let o of va(e.projectId)){if(e.signal?.aborted)break;let a=c_(o.content_text);if(a.length===0)continue;let c=s.get(o.session_id);if(c!==void 0)for(let u of a){if(u===o.session_id)continue;let d=s.get(u);if(!(d===void 0&&!n.has(u))&&!(d!==void 0&&c!==void 0&&d!==c))try{Yt({source_session_id:o.session_id,target_session_id:u,link_type:"citation",confidence:i_,evidence:{matched_uuid:u,source_message_uuid:o.message_uuid,scanner:"uuid-ref"},inferred_by:"L1"}),r+=1}catch{}}}return{created:r}}function ja(e={}){let t=u_(e.projectId);if(t.length===0)return{created:0};let n=new Map;for(let c of t){let u=d_(c.plan_ids_json);for(let d of u){let m=d.trim().toLowerCase();if(!m)continue;let h=n.get(m);h?h.push({id:c.session_id,project_id:c.project_id}):n.set(m,[{id:c.session_id,project_id:c.project_id}])}}if(n.size===0)return{created:0};let s=Ca(e.projectId),r=new Map;for(let c of s)r.set(c.id,c.project_id);let o=0,a=new Map;for(let c of va(e.projectId)){if(e.signal?.aborted)break;let u=l_(c.content_text);if(u.length===0)continue;let d=r.get(c.session_id);if(d!==void 0)for(let m of u){let h=n.get(m);if(h)for(let S of h){if(S.id===c.session_id||S.project_id!==d)continue;let b=a.get(c.session_id);b||(b=new Map,a.set(c.session_id,b));let T=b.get(S.id);T||(T=new Set,b.set(S.id,T)),T.add(m)}}}for(let[c,u]of a)for(let[d,m]of u)try{Yt({source_session_id:c,target_session_id:d,link_type:"citation",confidence:a_,evidence:{matched_plan_ids:Array.from(m).slice(0,12),scanner:"plan-ref"},inferred_by:"L1"}),o+=1}catch{}return{created:o}}U();ye();import{existsSync as q_,mkdirSync as X_,writeFileSync as J_}from"node:fs";import{homedir as Y_}from"node:os";import{join as xr}from"node:path";U();import{existsSync as Ha,mkdirSync as $_,readFileSync as U_,writeFileSync as B_}from"node:fs";import{homedir as H_}from"node:os";import{join as Wa}from"node:path";import{z as Ne}from"zod";function qa(){return process.env.RECALL_HOME??Wa(H_(),".recall")}function W_(){let e=qa();Ha(e)||$_(e,{recursive:!0})}function Xa(){return Wa(qa(),"config.json")}var Bn=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)}),Un={enabled:!1,ratePerMinute:30,lastProcessedSessionId:null,backfillPaused:!1,autoExtractEnabled:!1,autoExtractIntervalMinutes:60,autoExtractBatchSize:1,autoResumeWorker:!1};function Ja(){let e=Xa();if(!Ha(e))return{};try{return JSON.parse(U_(e,"utf8"))}catch(t){return console.error("[semantic-config] failed to parse config.json, using defaults:",t),{}}}function ce(){let e=Ja().semantic;if(!e)return{...Un};let t=Bn.safeParse({...Un,...e});return t.success?t.data:{...Un}}function Hn(e){W_();let t=Ja(),n=Bn.parse({...Un,...t.semantic??{},...e}),s={...t,semantic:n};return B_(Xa(),JSON.stringify(s,null,2)),Ar(n.enabled),n}function Ar(e){try{f().prepare(`INSERT INTO app_settings(key, value) VALUES ('semantic_enabled', ?)
888
- ON CONFLICT(key) DO UPDATE SET value = excluded.value`).run(e?"1":"0")}catch(t){let n=t instanceof Error?t.message:String(t);console.error(`[semantic-config] failed to sync semantic_enabled: ${n}`)}}var G_=1,z_=12e3,Ya=3,K_=[];function V_(){return process.env.RECALL_HOME??xr(Y_(),".recall")}function Ga(){return xr(V_(),"semantic")}function Z_(){let e=Ga();q_(e)||X_(e,{recursive:!0})}function Q_(e){let t=f(),n=t.prepare(`SELECT s.id, s.message_count, s.first_user_message,
887
+ ${n}`).all(...s)}function b_(e){if(!e)return[];try{let t=JSON.parse(e);if(Array.isArray(t))return t.filter(n=>typeof n=="string")}catch{}return[]}function Pa(e={}){if(Sr.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project");let t=Da(e.projectId),n=new Set(t.map(o=>o.id)),s=new Map;for(let o of t)s.set(o.id,o.project_id);let r=0;for(let o of Fa(e.projectId)){if(e.signal?.aborted)break;let a=f_(o.content_text);if(a.length===0)continue;let c=s.get(o.session_id);if(c!==void 0)for(let u of a){if(u===o.session_id)continue;let d=s.get(u);if(!(d===void 0&&!n.has(u))&&!(d!==void 0&&c!==void 0&&d!==c))try{Gt({source_session_id:o.session_id,target_session_id:u,link_type:"citation",confidence:g_,evidence:{matched_uuid:u,source_message_uuid:o.message_uuid,scanner:"uuid-ref"},inferred_by:"L1"}),r+=1}catch{}}}return{created:r}}function $a(e={}){let t=E_(e.projectId);if(t.length===0)return{created:0};let n=new Map;for(let c of t){let u=b_(c.plan_ids_json);for(let d of u){let m=d.trim().toLowerCase();if(!m)continue;let h=n.get(m);h?h.push({id:c.session_id,project_id:c.project_id}):n.set(m,[{id:c.session_id,project_id:c.project_id}])}}if(n.size===0)return{created:0};let s=Da(e.projectId),r=new Map;for(let c of s)r.set(c.id,c.project_id);let o=0,a=new Map;for(let c of Fa(e.projectId)){if(e.signal?.aborted)break;let u=h_(c.content_text);if(u.length===0)continue;let d=r.get(c.session_id);if(d!==void 0)for(let m of u){let h=n.get(m);if(h)for(let b of h){if(b.id===c.session_id||b.project_id!==d)continue;let S=a.get(c.session_id);S||(S=new Map,a.set(c.session_id,S));let T=S.get(b.id);T||(T=new Set,S.set(b.id,T)),T.add(m)}}}for(let[c,u]of a)for(let[d,m]of u)try{Gt({source_session_id:c,target_session_id:d,link_type:"citation",confidence:__,evidence:{matched_plan_ids:Array.from(m).slice(0,12),scanner:"plan-ref"},inferred_by:"L1"}),o+=1}catch{}return{created:o}}B();ye();import{existsSync as Z_,mkdirSync as Q_,writeFileSync as ef}from"node:fs";import{homedir as tf}from"node:os";import{join as Nr}from"node:path";B();import{existsSync as Ga,mkdirSync as G_,readFileSync as Y_,writeFileSync as z_}from"node:fs";import{homedir as K_}from"node:os";import{join as Ya}from"node:path";import{z as Ne}from"zod";function za(){return process.env.RECALL_HOME??Ya(K_(),".recall")}function V_(){let e=za();Ga(e)||G_(e,{recursive:!0})}function Ka(){return Ya(za(),"config.json")}var Hn=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)}),Bn={enabled:!1,ratePerMinute:30,lastProcessedSessionId:null,backfillPaused:!1,autoExtractEnabled:!1,autoExtractIntervalMinutes:60,autoExtractBatchSize:1,autoResumeWorker:!1};function Va(){let e=Ka();if(!Ga(e))return{};try{return JSON.parse(Y_(e,"utf8"))}catch(t){return console.error("[semantic-config] failed to parse config.json, using defaults:",t),{}}}function ce(){let e=Va().semantic;if(!e)return{...Bn};let t=Hn.safeParse({...Bn,...e});return t.success?t.data:{...Bn}}function Wn(e){V_();let t=Va(),n=Hn.parse({...Bn,...t.semantic??{},...e}),s={...t,semantic:n};return z_(Ka(),JSON.stringify(s,null,2)),xr(n.enabled),n}function xr(e){try{f().prepare(`INSERT INTO app_settings(key, value) VALUES ('semantic_enabled', ?)
888
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value`).run(e?"1":"0")}catch(t){let n=t instanceof Error?t.message:String(t);console.error(`[semantic-config] failed to sync semantic_enabled: ${n}`)}}var nf=1,sf=12e3,Za=3,rf=[];function of(){return process.env.RECALL_HOME??Nr(tf(),".recall")}function Qa(){return Nr(of(),"semantic")}function af(){let e=Qa();Z_(e)||Q_(e,{recursive:!0})}function cf(e){let t=f(),n=t.prepare(`SELECT s.id, s.message_count, s.first_user_message,
889
889
  p.name AS project,
890
890
  NULLIF(sa.alias, '') AS alias
891
891
  FROM sessions s
@@ -894,10 +894,10 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
894
894
  WHERE s.id = ?`).get(e);if(!n)return null;let s=t.prepare(`SELECT role, content_text
895
895
  FROM messages
896
896
  WHERE session_id = ? AND is_sidechain = 0
897
- ORDER BY COALESCE(timestamp, ''), rowid`).all(e),r=[],o=0;for(let a of s){if(!a.content_text)continue;let c=a.role??"system",u=a.content_text.replace(/```[\s\S]*?```/g,"[code]").replace(/<[^>]+>[\s\S]*?<\/[^>]+>/g,"").trim();if(!u)continue;let d=u.length>1500?u.slice(0,1500)+"\u2026":u,m=`${c}: ${d}`;if(o+m.length>z_)break;r.push(m),o+=m.length}return{id:n.id,alias:n.alias,project:n.project,firstUserMessage:n.first_user_message,excerpt:r.join(`
897
+ ORDER BY COALESCE(timestamp, ''), rowid`).all(e),r=[],o=0;for(let a of s){if(!a.content_text)continue;let c=a.role??"system",u=a.content_text.replace(/```[\s\S]*?```/g,"[code]").replace(/<[^>]+>[\s\S]*?<\/[^>]+>/g,"").trim();if(!u)continue;let d=u.length>1500?u.slice(0,1500)+"\u2026":u,m=`${c}: ${d}`;if(o+m.length>sf)break;r.push(m),o+=m.length}return{id:n.id,alias:n.alias,project:n.project,firstUserMessage:n.first_user_message,excerpt:r.join(`
898
898
 
899
- `),messageCount:n.message_count}}function ef(e){return["You are summarizing a Claude Code session for a local semantic-search index. The summary will be stored as plain text and matched against future natural-language queries.","",`Session: ${e.alias??e.id}`,`Project: ${e.project}`,e.firstUserMessage?`Opening prompt: ${e.firstUserMessage}`:"","","Transcript excerpt (truncated):","---",e.excerpt,"---","","Output a single JSON object on one line, with no Markdown fences and no commentary:",'{"summary": "<3 sentences describing what the user was trying to do, what was built or debugged, and the outcome>", "keywords": ["<concept>", "<technology>", "<problem>", ...]}',"","Constraints:","- summary: 3 sentences, plain prose, no bullet points",'- keywords: 10\u201315 lowercase tokens, multi-word entries hyphenated (e.g. "memory-leak"); no duplicates; no generic words like "code" or "session"',"- Output JSON only. Do not echo this prompt."].filter(Boolean).join(`
900
- `)}function tf(e){let t=e.trim();try{let o=JSON.parse(t);typeof o.result=="string"&&(t=o.result.trim())}catch{}t=t.replace(/^```(?:json)?\s*/i,"").replace(/```\s*$/i,"").trim();let n=t.indexOf("{"),s=t.lastIndexOf("}");if(n===-1||s===-1||s<=n)return null;let r=t.slice(n,s+1);try{let o=JSON.parse(r),a=typeof o.summary=="string"?o.summary.trim():"",u=(Array.isArray(o.keywords)?o.keywords:[]).filter(d=>typeof d=="string").map(d=>d.trim().toLowerCase()).filter(d=>d.length>0&&d.length<64);return!a||u.length===0?null:{summary:a,keywords:Array.from(new Set(u)).slice(0,20)}}catch{return null}}function nf(e){let t=f(),n=e.keywords.join(",");t.prepare(`INSERT INTO session_semantic
899
+ `),messageCount:n.message_count}}function lf(e){return["You are summarizing a Claude Code session for a local semantic-search index. The summary will be stored as plain text and matched against future natural-language queries.","",`Session: ${e.alias??e.id}`,`Project: ${e.project}`,e.firstUserMessage?`Opening prompt: ${e.firstUserMessage}`:"","","Transcript excerpt (truncated):","---",e.excerpt,"---","","Output a single JSON object on one line, with no Markdown fences and no commentary:",'{"summary": "<3 sentences describing what the user was trying to do, what was built or debugged, and the outcome>", "keywords": ["<concept>", "<technology>", "<problem>", ...]}',"","Constraints:","- summary: 3 sentences, plain prose, no bullet points",'- keywords: 10\u201315 lowercase tokens, multi-word entries hyphenated (e.g. "memory-leak"); no duplicates; no generic words like "code" or "session"',"- Output JSON only. Do not echo this prompt."].filter(Boolean).join(`
900
+ `)}function uf(e){let t=e.trim();try{let o=JSON.parse(t);typeof o.result=="string"&&(t=o.result.trim())}catch{}t=t.replace(/^```(?:json)?\s*/i,"").replace(/```\s*$/i,"").trim();let n=t.indexOf("{"),s=t.lastIndexOf("}");if(n===-1||s===-1||s<=n)return null;let r=t.slice(n,s+1);try{let o=JSON.parse(r),a=typeof o.summary=="string"?o.summary.trim():"",u=(Array.isArray(o.keywords)?o.keywords:[]).filter(d=>typeof d=="string").map(d=>d.trim().toLowerCase()).filter(d=>d.length>0&&d.length<64);return!a||u.length===0?null:{summary:a,keywords:Array.from(new Set(u)).slice(0,20)}}catch{return null}}function df(e){let t=f(),n=e.keywords.join(",");t.prepare(`INSERT INTO session_semantic
901
901
  (session_id, summary, keywords, model, source_message_count, generated_at)
902
902
  VALUES (@session_id, @summary, @keywords, @model, @source_message_count, @generated_at)
903
903
  ON CONFLICT(session_id) DO UPDATE SET
@@ -905,16 +905,16 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
905
905
  keywords = excluded.keywords,
906
906
  model = excluded.model,
907
907
  source_message_count = excluded.source_message_count,
908
- generated_at = excluded.generated_at`).run({session_id:e.sessionId,summary:e.summary,keywords:n,model:e.model,source_message_count:e.sourceMessageCount,generated_at:e.generatedAt}),Z_();let s=xr(Ga(),`${e.sessionId}.json`);J_(s,JSON.stringify({version:G_,session_id:e.sessionId,summary:e.summary,keywords:e.keywords,model:e.model,source_message_count:e.sourceMessageCount,generated_at:e.generatedAt},null,2))}var Wn=null;function sf(){let t=ce().ratePerMinute,n=t/6e4;return(!Wn||Wn.capacity!==t)&&(Wn={tokens:t,capacity:t,refillPerMs:n,lastRefill:Date.now()}),Wn}function rf(e){let t=Date.now(),n=t-e.lastRefill;n>0&&(e.tokens=Math.min(e.capacity,e.tokens+n*e.refillPerMs),e.lastRefill=t)}async function of(e){for(;;){if(e?.aborted)throw new Error("aborted");let t=sf();if(rf(t),t.tokens>=1){t.tokens-=1;return}let n=1-t.tokens,s=Math.max(50,Math.ceil(n/t.refillPerMs));await new Promise(r=>setTimeout(r,Math.min(s,5e3)))}}async function qn(e,t={}){let n=ce();if(!n.enabled)return{sessionId:e,ok:!1,reason:"disabled"};if(!pe())return{sessionId:e,ok:!1,reason:"claude-cli-missing"};let s=Q_(e);if(!s)return{sessionId:e,ok:!1,reason:"session-not-found"};if(s.messageCount<Ya)return{sessionId:e,ok:!1,reason:"too-short"};if(!s.excerpt.trim())return{sessionId:e,ok:!1,reason:"empty-excerpt"};await of(t.signal);let r=ef(s),o=await et(r,K_,{model:n.model});if(!o.success)return{sessionId:e,ok:!1,reason:`claude-cli-exit-${o.exitCode??"null"}`,model:n.model??null};let a=tf(o.stdout);return a?(nf({sessionId:s.id,summary:a.summary,keywords:a.keywords,model:n.model??null,sourceMessageCount:s.messageCount,generatedAt:new Date().toISOString()}),{sessionId:e,ok:!0,model:n.model??null}):{sessionId:e,ok:!1,reason:"parse-failed",model:n.model??null}}async function Xn(e={}){let t=ce();if(!t.enabled)return{total:0,processed:0,ok:0,failed:0,currentSessionId:null};let n=f(),r={limit:e.limit??1e3},o="s.message_count >= 3";e.force||(o+=" AND ss.session_id IS NULL"),typeof e.projectId=="number"&&(o+=" AND s.project_id = @projectId",r.projectId=e.projectId),t.lastProcessedSessionId&&e.force;let a=n.prepare(`SELECT s.id
908
+ generated_at = excluded.generated_at`).run({session_id:e.sessionId,summary:e.summary,keywords:n,model:e.model,source_message_count:e.sourceMessageCount,generated_at:e.generatedAt}),af();let s=Nr(Qa(),`${e.sessionId}.json`);ef(s,JSON.stringify({version:nf,session_id:e.sessionId,summary:e.summary,keywords:e.keywords,model:e.model,source_message_count:e.sourceMessageCount,generated_at:e.generatedAt},null,2))}var qn=null;function pf(){let t=ce().ratePerMinute,n=t/6e4;return(!qn||qn.capacity!==t)&&(qn={tokens:t,capacity:t,refillPerMs:n,lastRefill:Date.now()}),qn}function mf(e){let t=Date.now(),n=t-e.lastRefill;n>0&&(e.tokens=Math.min(e.capacity,e.tokens+n*e.refillPerMs),e.lastRefill=t)}async function gf(e){for(;;){if(e?.aborted)throw new Error("aborted");let t=pf();if(mf(t),t.tokens>=1){t.tokens-=1;return}let n=1-t.tokens,s=Math.max(50,Math.ceil(n/t.refillPerMs));await new Promise(r=>setTimeout(r,Math.min(s,5e3)))}}async function Xn(e,t={}){let n=ce();if(!n.enabled)return{sessionId:e,ok:!1,reason:"disabled"};if(!pe())return{sessionId:e,ok:!1,reason:"claude-cli-missing"};let s=cf(e);if(!s)return{sessionId:e,ok:!1,reason:"session-not-found"};if(s.messageCount<Za)return{sessionId:e,ok:!1,reason:"too-short"};if(!s.excerpt.trim())return{sessionId:e,ok:!1,reason:"empty-excerpt"};await gf(t.signal);let r=lf(s),o=await Qe(r,rf,{model:n.model});if(!o.success)return{sessionId:e,ok:!1,reason:`claude-cli-exit-${o.exitCode??"null"}`,model:n.model??null};let a=uf(o.stdout);return a?(df({sessionId:s.id,summary:a.summary,keywords:a.keywords,model:n.model??null,sourceMessageCount:s.messageCount,generatedAt:new Date().toISOString()}),{sessionId:e,ok:!0,model:n.model??null}):{sessionId:e,ok:!1,reason:"parse-failed",model:n.model??null}}async function Jn(e={}){let t=ce();if(!t.enabled)return{total:0,processed:0,ok:0,failed:0,currentSessionId:null};let n=f(),r={limit:e.limit??1e3},o="s.message_count >= 3";e.force||(o+=" AND ss.session_id IS NULL"),typeof e.projectId=="number"&&(o+=" AND s.project_id = @projectId",r.projectId=e.projectId),t.lastProcessedSessionId&&e.force;let a=n.prepare(`SELECT s.id
909
909
  FROM sessions s
910
910
  LEFT JOIN session_semantic ss ON ss.session_id = s.id
911
911
  WHERE ${o}
912
912
  ORDER BY COALESCE(s.started_at, '') ASC, s.id ASC
913
- LIMIT @limit`).all(r),c={total:a.length,processed:0,ok:0,failed:0,currentSessionId:null};e.onProgress?.(c);for(let{id:u}of a){if(e.signal?.aborted||ce().backfillPaused)break;c.currentSessionId=u,e.onProgress?.({...c});try{(await qn(u,{signal:e.signal})).ok?c.ok+=1:c.failed+=1}catch(m){c.failed+=1,console.error("[semantic.backfill] failed for",u,m)}c.processed+=1,Hn({lastProcessedSessionId:u}),e.onProgress?.({...c})}return c.currentSessionId=null,e.onProgress?.({...c}),c}async function za(e){if(!ce().enabled)return;let s=f().prepare(`SELECT s.message_count, s.ended_at,
913
+ LIMIT @limit`).all(r),c={total:a.length,processed:0,ok:0,failed:0,currentSessionId:null};e.onProgress?.(c);for(let{id:u}of a){if(e.signal?.aborted||ce().backfillPaused)break;c.currentSessionId=u,e.onProgress?.({...c});try{(await Xn(u,{signal:e.signal})).ok?c.ok+=1:c.failed+=1}catch(m){c.failed+=1,console.error("[semantic.backfill] failed for",u,m)}c.processed+=1,Wn({lastProcessedSessionId:u}),e.onProgress?.({...c})}return c.currentSessionId=null,e.onProgress?.({...c}),c}async function ec(e){if(!ce().enabled)return;let s=f().prepare(`SELECT s.message_count, s.ended_at,
914
914
  ss.generated_at, ss.source_message_count
915
915
  FROM sessions s
916
916
  LEFT JOIN session_semantic ss ON ss.session_id = s.id
917
- WHERE s.id = ?`).get(e);if(s&&!(s.message_count<Ya)&&!(s.generated_at&&s.source_message_count!=null&&s.source_message_count>=s.message_count))try{await qn(e)}catch(r){console.error("[semantic] processSession error for",e,r)}}function Nr(){let e=ce(),t=f(),n=t.prepare("SELECT COUNT(*) AS n FROM sessions WHERE message_count >= 3").get().n,s=t.prepare("SELECT COUNT(*) AS n FROM session_semantic").get().n;return{enabled:e.enabled,claudeCliAvailable:pe(),ratePerMinute:e.ratePerMinute,model:e.model??null,totalSessions:n,processedSessions:s,pendingSessions:Math.max(0,n-s),lastProcessedSessionId:e.lastProcessedSessionId,backfillPaused:e.backfillPaused}}U();import{createHash as uf}from"node:crypto";var af=[{name:"Anthropic API key",regex:/sk-ant-[a-zA-Z0-9_\-]{40,}/g,severity:"high"},{name:"OpenAI API key",regex:/sk-(?:proj-)?[a-zA-Z0-9]{32,}/g,severity:"high"},{name:"AWS access key ID",regex:/AKIA[0-9A-Z]{16}/g,severity:"high"},{name:"GitHub PAT",regex:/gh[pousr]_[A-Za-z0-9]{20,}/g,severity:"high"},{name:"Stripe live/test key",regex:/(?:sk|rk|pk)_(?:live|test)_[a-zA-Z0-9]{24,}/g,severity:"high"},{name:"Slack token",regex:/xox[abprs]-[A-Za-z0-9\-]{10,}/g,severity:"high"},{name:"Google API key",regex:/AIza[0-9A-Za-z_\-]{35}/g,severity:"high"},{name:"Private key block",regex:/-----BEGIN (?:RSA |DSA |EC |OPENSSH |ENCRYPTED )?PRIVATE KEY-----/g,severity:"high"},{name:"Apify token",regex:/apify_api_[A-Za-z0-9]{20,}/g,severity:"high"},{name:"Notion integration",regex:/(?:secret_|ntn_)[A-Za-z0-9]{40,}/g,severity:"high"},{name:"Vercel token",regex:/vercel_[A-Za-z0-9]{24,}/g,severity:"high"},{name:"Supabase service key",regex:/sbp_[A-Za-z0-9]{40,}/g,severity:"high"},{name:"SendGrid key",regex:/SG\.[A-Za-z0-9_\-]{20,}\.[A-Za-z0-9_\-]{20,}/g,severity:"high"},{name:"Mailgun key",regex:/key-[a-f0-9]{32}/g,severity:"high"},{name:"Twilio SID",regex:/AC[a-f0-9]{32}/g,severity:"high"},{name:"Discord bot token",regex:/[MN][A-Za-z\d]{23}\.[\w-]{6}\.[\w-]{27,38}/g,severity:"high"},{name:"npm token",regex:/npm_[A-Za-z0-9]{36}/g,severity:"high"},{name:"HuggingFace token",regex:/hf_[A-Za-z0-9]{30,}/g,severity:"high"},{name:"Replicate token",regex:/r8_[A-Za-z0-9]{32,}/g,severity:"high"},{name:"Figma token",regex:/figd_[A-Za-z0-9_\-]{30,}/g,severity:"high"},{name:"Linear key",regex:/lin_api_[A-Za-z0-9]{30,}/g,severity:"high"},{name:"DigitalOcean token",regex:/dop_v1_[a-f0-9]{64}/g,severity:"high"},{name:"Generic provider token",regex:/\b[a-z][a-z0-9]{2,20}_(?:api|pat|token|sk|pk|key|auth)_(?=[A-Za-z0-9_\-]*\d)[A-Za-z0-9_\-]{20,}\b/g,severity:"high"},{name:"Bearer token",regex:/\b[Bb]earer\s+[A-Za-z0-9_\-\.=]{24,}\b/g,severity:"medium"},{name:"Slack webhook URL",regex:/https:\/\/hooks\.slack\.com\/services\/T[A-Z0-9]+\/B[A-Z0-9]+\/[A-Za-z0-9]{20,}/g,severity:"high"},{name:"Discord webhook URL",regex:/https:\/\/(?:ptb\.|canary\.)?discord(?:app)?\.com\/api\/webhooks\/\d+\/[A-Za-z0-9_\-]{40,}/g,severity:"high"},{name:"Teams webhook URL",regex:/https:\/\/[a-zA-Z0-9.\-]+\.webhook\.office\.com\/webhookb2\/[A-Za-z0-9@_\-\/]{30,}/g,severity:"high"},{name:"Secret near keyword",regex:/\b(?:webhook[_\s\-]?secret|signing[_\s\-]?secret|webhook[_\s\-]?signing[_\s\-]?secret|api[_\s\-]?secret|client[_\s\-]?secret|private[_\s\-]?key|access[_\s\-]?token|auth[_\s\-]?token|api[_\s\-]?key)\b[\s\S]{0,200}?\b(?:[a-fA-F0-9]{32,}|[A-Za-z0-9+/_\-]{20,}(?:\.[A-Za-z0-9+/_\-]{10,}){1,2}|[A-Za-z0-9+/_\-]{40,}={0,2})\b/gi,severity:"high"},{name:"JWT",regex:/eyJ[a-zA-Z0-9_\-]{10,}\.[a-zA-Z0-9_\-]{10,}\.[a-zA-Z0-9_\-]{10,}/g,severity:"medium"},{name:"URL with password",regex:/https?:\/\/[^:\s/@]+:[^@\s]{6,}@[^\s/]+/g,severity:"high"},{name:"Password assignment",regex:/(?<![A-Za-z])(?:password|passwd|pwd|secret|token|api[_\-]?key|access[_\-]?key|auth[_\-]?token|webhook[_\-]?secret|client[_\-]?secret|private[_\-]?key)\b\s*[:=]\s*["']?[A-Za-z0-9_\-+/=]{16,}/gi,severity:"high"}];function cf(e){if(e.length<=8)return e.slice(0,2)+"\u2022".repeat(Math.max(0,e.length-4))+e.slice(-2);let t=e.slice(0,Math.min(6,Math.floor(e.length/3))),n=e.slice(-Math.min(4,Math.floor(e.length/4)));return`${t}${"\u2022".repeat(Math.max(3,e.length-t.length-n.length))}${n}`}function lf(e){let t=5381;for(let n=0;n<e.length;n++)t=(t<<5)+t+e.charCodeAt(n)|0;return(t>>>0).toString(36)}function Se(e){if(!e)return{redacted:e,count:0};let t=e,n=0,s=new Set;for(let r of af)r.regex.lastIndex=0,t=t.replace(r.regex,o=>{let a=`${r.name}::${lf(o)}`;return s.has(a)||(s.add(a),n+=1),`[REDACTED ${r.name}: ${cf(o)}]`});return{redacted:t,count:n}}ye();var Cr=1,nt="claude-haiku-4-5-20251001",df=3,pf=32e3,Ka=2e3,mf=30,gf=30,_f=30,ff=30;function hf(e){let n=f().prepare(`SELECT s.id,
917
+ WHERE s.id = ?`).get(e);if(s&&!(s.message_count<Za)&&!(s.generated_at&&s.source_message_count!=null&&s.source_message_count>=s.message_count))try{await Xn(e)}catch(r){console.error("[semantic] processSession error for",e,r)}}function Or(){let e=ce(),t=f(),n=t.prepare("SELECT COUNT(*) AS n FROM sessions WHERE message_count >= 3").get().n,s=t.prepare("SELECT COUNT(*) AS n FROM session_semantic").get().n;return{enabled:e.enabled,claudeCliAvailable:pe(),ratePerMinute:e.ratePerMinute,model:e.model??null,totalSessions:n,processedSessions:s,pendingSessions:Math.max(0,n-s),lastProcessedSessionId:e.lastProcessedSessionId,backfillPaused:e.backfillPaused}}B();import{createHash as Ef}from"node:crypto";var _f=[{name:"Anthropic API key",regex:/sk-ant-[a-zA-Z0-9_\-]{40,}/g,severity:"high"},{name:"OpenAI API key",regex:/sk-(?:proj-)?[a-zA-Z0-9]{32,}/g,severity:"high"},{name:"AWS access key ID",regex:/AKIA[0-9A-Z]{16}/g,severity:"high"},{name:"GitHub PAT",regex:/gh[pousr]_[A-Za-z0-9]{20,}/g,severity:"high"},{name:"Stripe live/test key",regex:/(?:sk|rk|pk)_(?:live|test)_[a-zA-Z0-9]{24,}/g,severity:"high"},{name:"Slack token",regex:/xox[abprs]-[A-Za-z0-9\-]{10,}/g,severity:"high"},{name:"Google API key",regex:/AIza[0-9A-Za-z_\-]{35}/g,severity:"high"},{name:"Private key block",regex:/-----BEGIN (?:RSA |DSA |EC |OPENSSH |ENCRYPTED )?PRIVATE KEY-----/g,severity:"high"},{name:"Apify token",regex:/apify_api_[A-Za-z0-9]{20,}/g,severity:"high"},{name:"Notion integration",regex:/(?:secret_|ntn_)[A-Za-z0-9]{40,}/g,severity:"high"},{name:"Vercel token",regex:/vercel_[A-Za-z0-9]{24,}/g,severity:"high"},{name:"Supabase service key",regex:/sbp_[A-Za-z0-9]{40,}/g,severity:"high"},{name:"SendGrid key",regex:/SG\.[A-Za-z0-9_\-]{20,}\.[A-Za-z0-9_\-]{20,}/g,severity:"high"},{name:"Mailgun key",regex:/key-[a-f0-9]{32}/g,severity:"high"},{name:"Twilio SID",regex:/AC[a-f0-9]{32}/g,severity:"high"},{name:"Discord bot token",regex:/[MN][A-Za-z\d]{23}\.[\w-]{6}\.[\w-]{27,38}/g,severity:"high"},{name:"npm token",regex:/npm_[A-Za-z0-9]{36}/g,severity:"high"},{name:"HuggingFace token",regex:/hf_[A-Za-z0-9]{30,}/g,severity:"high"},{name:"Replicate token",regex:/r8_[A-Za-z0-9]{32,}/g,severity:"high"},{name:"Figma token",regex:/figd_[A-Za-z0-9_\-]{30,}/g,severity:"high"},{name:"Linear key",regex:/lin_api_[A-Za-z0-9]{30,}/g,severity:"high"},{name:"DigitalOcean token",regex:/dop_v1_[a-f0-9]{64}/g,severity:"high"},{name:"Generic provider token",regex:/\b[a-z][a-z0-9]{2,20}_(?:api|pat|token|sk|pk|key|auth)_(?=[A-Za-z0-9_\-]*\d)[A-Za-z0-9_\-]{20,}\b/g,severity:"high"},{name:"Bearer token",regex:/\b[Bb]earer\s+[A-Za-z0-9_\-\.=]{24,}\b/g,severity:"medium"},{name:"Slack webhook URL",regex:/https:\/\/hooks\.slack\.com\/services\/T[A-Z0-9]+\/B[A-Z0-9]+\/[A-Za-z0-9]{20,}/g,severity:"high"},{name:"Discord webhook URL",regex:/https:\/\/(?:ptb\.|canary\.)?discord(?:app)?\.com\/api\/webhooks\/\d+\/[A-Za-z0-9_\-]{40,}/g,severity:"high"},{name:"Teams webhook URL",regex:/https:\/\/[a-zA-Z0-9.\-]+\.webhook\.office\.com\/webhookb2\/[A-Za-z0-9@_\-\/]{30,}/g,severity:"high"},{name:"Secret near keyword",regex:/\b(?:webhook[_\s\-]?secret|signing[_\s\-]?secret|webhook[_\s\-]?signing[_\s\-]?secret|api[_\s\-]?secret|client[_\s\-]?secret|private[_\s\-]?key|access[_\s\-]?token|auth[_\s\-]?token|api[_\s\-]?key)\b[\s\S]{0,200}?\b(?:[a-fA-F0-9]{32,}|[A-Za-z0-9+/_\-]{20,}(?:\.[A-Za-z0-9+/_\-]{10,}){1,2}|[A-Za-z0-9+/_\-]{40,}={0,2})\b/gi,severity:"high"},{name:"JWT",regex:/eyJ[a-zA-Z0-9_\-]{10,}\.[a-zA-Z0-9_\-]{10,}\.[a-zA-Z0-9_\-]{10,}/g,severity:"medium"},{name:"URL with password",regex:/https?:\/\/[^:\s/@]+:[^@\s]{6,}@[^\s/]+/g,severity:"high"},{name:"Password assignment",regex:/(?<![A-Za-z])(?:password|passwd|pwd|secret|token|api[_\-]?key|access[_\-]?key|auth[_\-]?token|webhook[_\-]?secret|client[_\-]?secret|private[_\-]?key)\b\s*[:=]\s*["']?[A-Za-z0-9_\-+/=]{16,}/gi,severity:"high"}];function ff(e){if(e.length<=8)return e.slice(0,2)+"\u2022".repeat(Math.max(0,e.length-4))+e.slice(-2);let t=e.slice(0,Math.min(6,Math.floor(e.length/3))),n=e.slice(-Math.min(4,Math.floor(e.length/4)));return`${t}${"\u2022".repeat(Math.max(3,e.length-t.length-n.length))}${n}`}function hf(e){let t=5381;for(let n=0;n<e.length;n++)t=(t<<5)+t+e.charCodeAt(n)|0;return(t>>>0).toString(36)}function Se(e){if(!e)return{redacted:e,count:0};let t=e,n=0,s=new Set;for(let r of _f)r.regex.lastIndex=0,t=t.replace(r.regex,o=>{let a=`${r.name}::${hf(o)}`;return s.has(a)||(s.add(a),n+=1),`[REDACTED ${r.name}: ${ff(o)}]`});return{redacted:t,count:n}}ye();var vr=1,tt="claude-haiku-4-5-20251001",bf=3,Sf=32e3,tc=2e3,Tf=30,yf=30,wf=30,Rf=30;function kf(e){let n=f().prepare(`SELECT s.id,
918
918
  NULLIF(sa.alias, '') AS alias,
919
919
  s.auto_title,
920
920
  s.auto_title_source,
@@ -925,15 +925,15 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
925
925
  FROM sessions s
926
926
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
927
927
  LEFT JOIN projects p ON p.id = s.project_id
928
- WHERE s.id = ?`).get(e);return n?{...n,alias_source:n.alias?"manual":null}:null}function Va(e,t={}){if(e.message_count<df)return{eligible:!1,reason:"too-short"};let n=e.title_quality;if(n==="programmatic"||n==="recursive_meta")return{eligible:!1,reason:"low-signal-title"};if(e.auto_title_source==="agent"&&!e.alias)return{eligible:!1,reason:"agent-titled-no-override"};if(!t.force){let s=Ze(e.id);if(s&&s.extractor_version>=Cr)return{eligible:!1,reason:"already-extracted"}}return{eligible:!0}}function Ef(e){let t=hf(e);if(!t)return null;let s=f().prepare(`SELECT role, content_text
928
+ WHERE s.id = ?`).get(e);return n?{...n,alias_source:n.alias?"manual":null}:null}function nc(e,t={}){if(e.message_count<bf)return{eligible:!1,reason:"too-short"};let n=e.title_quality;if(n==="programmatic"||n==="recursive_meta")return{eligible:!1,reason:"low-signal-title"};if(e.auto_title_source==="agent"&&!e.alias)return{eligible:!1,reason:"agent-titled-no-override"};if(!t.force){let s=Ve(e.id);if(s&&s.extractor_version>=vr)return{eligible:!1,reason:"already-extracted"}}return{eligible:!0}}function Af(e){let t=kf(e);if(!t)return null;let s=f().prepare(`SELECT role, content_text
929
929
  FROM messages
930
930
  WHERE session_id = ?
931
931
  AND is_sidechain = 0
932
932
  AND content_text IS NOT NULL
933
- ORDER BY COALESCE(timestamp, ''), rowid`).all(e),r=[],o=0;for(let a of s){let c=a.role??"system",u=a.content_text.trim();if(!u)continue;let d=u.length>Ka?u.slice(0,Ka)+"\u2026":u,m=`${c}: ${d}`;if(o+m.length>pf)break;r.push(m),o+=m.length}return{meta:t,excerpt:r.join(`
933
+ ORDER BY COALESCE(timestamp, ''), rowid`).all(e),r=[],o=0;for(let a of s){let c=a.role??"system",u=a.content_text.trim();if(!u)continue;let d=u.length>tc?u.slice(0,tc)+"\u2026":u,m=`${c}: ${d}`;if(o+m.length>Sf)break;r.push(m),o+=m.length}return{meta:t,excerpt:r.join(`
934
934
 
935
- `)}}function bf(e){let{meta:t}=e;return["You are extracting a structured Output Index from a Claude Code session for a local knowledge graph.","","Read the transcript and produce a single JSON object with EXACTLY these fields. Output JSON only \u2014 no Markdown fences, no commentary, no explanation.","","Fields (every field MUST appear; use [] for empty):","- files_written: array of strings. Relative or absolute file paths the assistant created, edited, or extensively discussed (Write/Edit tool calls or paths quoted verbatim).",'- brands_mentioned: array of strings. Distinct proper-noun company / product / brand names mentioned. Examples of valid: "Glaser Group", "Apollo", "TikTok", "Cloudflare R2". NOT generic terms like "the company" or "users".','- terms_introduced: array of objects { "term": "<lowercase phrase>", "freq": <int> }. Distinctive multi-word noun phrases the session introduced or extensively discussed. Skip generic words. Cap at 30 entries.','- plan_ids_referenced: array of strings. Planning identifiers like "v0.18.A", "Phase D", "L3", "MASTER-PLAN-cognitive-graph". Empty array if none.','- bug_signatures: array of objects { "error_type": "<class or null>", "snippet": "<first line of the error>", "file": "<path or null>" }. Errors actually encountered in the session (not hypothetical). The error_type is the exception class (e.g. "TypeError", "ReferenceError") or null if unspecified.',"","Hard constraints:","- Do NOT fabricate. If a field has no concrete content from the transcript, output an empty array.","- Output JSON ONLY. No backticks, no markdown, no preamble.","- terms_introduced \u2264 30 entries; brands_mentioned \u2264 30 distinct entries; plan_ids_referenced \u2264 30; bug_signatures \u2264 30.","",`Session: ${t.alias??t.id.slice(0,8)}`,`Project: ${t.project??"unknown"}`,t.first_user_message?`Opening prompt: ${t.first_user_message.slice(0,500)}`:"","","Transcript excerpt (may be truncated):","---",e.excerpt,"---"].filter(Boolean).join(`
936
- `)}function Sf(e){return Array.isArray(e)&&e.every(t=>typeof t=="string")}function Or(e,t,n=!1){if(!Array.isArray(e))return[];let s=new Set,r=[];for(let o of e){if(typeof o!="string")continue;let a=n?o.trim().toLowerCase():o.trim();if(!(!a||a.length>256)&&!s.has(a)&&(s.add(a),r.push(a),r.length>=t))break}return r}function Tf(e,t){if(!Array.isArray(e))return[];let n=new Set,s=[];for(let r of e){if(!r||typeof r!="object")continue;let o=r.term,a=r.freq;if(typeof o!="string")continue;let c=o.trim().toLowerCase();if(!c||c.length>128||n.has(c))continue;n.add(c);let u=typeof a=="number"&&Number.isFinite(a)&&a>0?Math.floor(a):1;if(s.push({term:c,frequency:u}),s.length>=t)break}return s}function yf(e,t){if(!Array.isArray(e))return[];let n=[];for(let s of e){if(!s||typeof s!="object")continue;let r=s.error_type,o=s.snippet,a=s.file,c=typeof r=="string"&&r.trim().length>0?r.trim().slice(0,64):"unknown",u=typeof o=="string"?o.trim().replace(/\s+/g," ").slice(0,256):"";if(!u)continue;let d=typeof a=="string"&&a.trim().length>0?a.trim().slice(0,256):null,m=uf("sha256").update(`${c}::${u}`).digest("hex").slice(0,12);if(n.push({error_type:c,message_hash:m,snippet:u,file:d}),n.length>=t)break}return n}function wf(e){let t=e.trim();try{let S=JSON.parse(t);typeof S.result=="string"&&(t=S.result.trim())}catch{}t=t.replace(/^```(?:json)?\s*/i,"").replace(/```\s*$/i,"").trim();let n=t.indexOf("{"),s=t.lastIndexOf("}");if(n===-1||s===-1||s<=n)return null;let r=t.slice(n,s+1),o;try{o=JSON.parse(r)}catch{return null}let a=Or(o.files_written,200),c=Or(o.brands_mentioned,gf),u=Tf(o.terms_introduced,mf),d=Or(o.plan_ids_referenced,_f),m=yf(o.bug_signatures,ff);return a.length===0&&c.length===0&&u.length===0&&d.length===0&&m.length===0&&!Sf(o.files_written)?null:{files_written:a,brands_mentioned:c,terms_introduced:u,plan_ids_referenced:d,bug_signatures:m}}var Lr=null;async function Rf(e,t){return Lr?Lr(e,t):et(e,[],{model:t})}async function vr(e,t={}){if(t.signal?.aborted)return{session_id:e,ok:!1,failed:"aborted"};let n=Ef(e);if(!n)return{session_id:e,ok:!1,skipped:"session-not-found"};let s=Va(n.meta,{force:t.force});if(!s.eligible)return{session_id:e,ok:!1,skipped:s.reason};if(!Lr&&!pe())return{session_id:e,ok:!1,failed:"claude-cli-missing"};let r=bf(n),o=t.model??nt,a=await Rf(r,o);if(!a.success){let m=(a.stderr||a.stdout||"").slice(0,400),h=m?Se(m).redacted:void 0;return{session_id:e,ok:!1,failed:"claude-cli-error",exit_code:a.exitCode,stderr_excerpt:h}}let c=wf(a.stdout);if(!c){let m=a.stdout.slice(0,400),h=m?Se(m).redacted:void 0;return{session_id:e,ok:!1,failed:"parse-failed",exit_code:a.exitCode,stderr_excerpt:h}}let u=kf(a.stdout),d=Oa({session_id:e,files_written:c.files_written,brands_mentioned:c.brands_mentioned,terms_introduced:c.terms_introduced,plan_ids_referenced:c.plan_ids_referenced,bug_signatures:c.bug_signatures,raw_extraction:{model:o,usage:u,raw_response_excerpt:a.stdout.slice(0,4e3)},extractor_version:Cr});return{session_id:e,ok:!0,index:d,usage:u}}function kf(e){try{let t=JSON.parse(e.trim());if(t&&typeof t=="object"&&t.usage){let n=t.usage,s={};return typeof n.input_tokens=="number"&&(s.input_tokens=n.input_tokens),typeof n.output_tokens=="number"&&(s.output_tokens=n.output_tokens),s}}catch{}return null}function ft(e={}){let t=f(),n=[],s=[];typeof e.projectId=="number"&&(n.push("s.project_id = ?"),s.push(e.projectId));let r=Math.max(1,Math.min(1e4,e.limit??1e3)),o=n.length?`WHERE ${n.join(" AND ")}`:"",a=t.prepare(`SELECT s.id,
935
+ `)}}function xf(e){let{meta:t}=e;return["You are extracting a structured Output Index from a Claude Code session for a local knowledge graph.","","Read the transcript and produce a single JSON object with EXACTLY these fields. Output JSON only \u2014 no Markdown fences, no commentary, no explanation.","","Fields (every field MUST appear; use [] for empty):","- files_written: array of strings. Relative or absolute file paths the assistant created, edited, or extensively discussed (Write/Edit tool calls or paths quoted verbatim).",'- brands_mentioned: array of strings. Distinct proper-noun company / product / brand names mentioned. Examples of valid: "Glaser Group", "Apollo", "TikTok", "Cloudflare R2". NOT generic terms like "the company" or "users".','- terms_introduced: array of objects { "term": "<lowercase phrase>", "freq": <int> }. Distinctive multi-word noun phrases the session introduced or extensively discussed. Skip generic words. Cap at 30 entries.','- plan_ids_referenced: array of strings. Planning identifiers like "v0.18.A", "Phase D", "L3", "MASTER-PLAN-cognitive-graph". Empty array if none.','- bug_signatures: array of objects { "error_type": "<class or null>", "snippet": "<first line of the error>", "file": "<path or null>" }. Errors actually encountered in the session (not hypothetical). The error_type is the exception class (e.g. "TypeError", "ReferenceError") or null if unspecified.',"","Hard constraints:","- Do NOT fabricate. If a field has no concrete content from the transcript, output an empty array.","- Output JSON ONLY. No backticks, no markdown, no preamble.","- terms_introduced \u2264 30 entries; brands_mentioned \u2264 30 distinct entries; plan_ids_referenced \u2264 30; bug_signatures \u2264 30.","",`Session: ${t.alias??t.id.slice(0,8)}`,`Project: ${t.project??"unknown"}`,t.first_user_message?`Opening prompt: ${t.first_user_message.slice(0,500)}`:"","","Transcript excerpt (may be truncated):","---",e.excerpt,"---"].filter(Boolean).join(`
936
+ `)}function Nf(e){return Array.isArray(e)&&e.every(t=>typeof t=="string")}function Lr(e,t,n=!1){if(!Array.isArray(e))return[];let s=new Set,r=[];for(let o of e){if(typeof o!="string")continue;let a=n?o.trim().toLowerCase():o.trim();if(!(!a||a.length>256)&&!s.has(a)&&(s.add(a),r.push(a),r.length>=t))break}return r}function Of(e,t){if(!Array.isArray(e))return[];let n=new Set,s=[];for(let r of e){if(!r||typeof r!="object")continue;let o=r.term,a=r.freq;if(typeof o!="string")continue;let c=o.trim().toLowerCase();if(!c||c.length>128||n.has(c))continue;n.add(c);let u=typeof a=="number"&&Number.isFinite(a)&&a>0?Math.floor(a):1;if(s.push({term:c,frequency:u}),s.length>=t)break}return s}function Lf(e,t){if(!Array.isArray(e))return[];let n=[];for(let s of e){if(!s||typeof s!="object")continue;let r=s.error_type,o=s.snippet,a=s.file,c=typeof r=="string"&&r.trim().length>0?r.trim().slice(0,64):"unknown",u=typeof o=="string"?o.trim().replace(/\s+/g," ").slice(0,256):"";if(!u)continue;let d=typeof a=="string"&&a.trim().length>0?a.trim().slice(0,256):null,m=Ef("sha256").update(`${c}::${u}`).digest("hex").slice(0,12);if(n.push({error_type:c,message_hash:m,snippet:u,file:d}),n.length>=t)break}return n}function Cf(e){let t=e.trim();try{let b=JSON.parse(t);typeof b.result=="string"&&(t=b.result.trim())}catch{}t=t.replace(/^```(?:json)?\s*/i,"").replace(/```\s*$/i,"").trim();let n=t.indexOf("{"),s=t.lastIndexOf("}");if(n===-1||s===-1||s<=n)return null;let r=t.slice(n,s+1),o;try{o=JSON.parse(r)}catch{return null}let a=Lr(o.files_written,200),c=Lr(o.brands_mentioned,yf),u=Of(o.terms_introduced,Tf),d=Lr(o.plan_ids_referenced,wf),m=Lf(o.bug_signatures,Rf);return a.length===0&&c.length===0&&u.length===0&&d.length===0&&m.length===0&&!Nf(o.files_written)?null:{files_written:a,brands_mentioned:c,terms_introduced:u,plan_ids_referenced:d,bug_signatures:m}}var Cr=null;async function vf(e,t){return Cr?Cr(e,t):Qe(e,[],{model:t})}async function Ir(e,t={}){if(t.signal?.aborted)return{session_id:e,ok:!1,failed:"aborted"};let n=Af(e);if(!n)return{session_id:e,ok:!1,skipped:"session-not-found"};let s=nc(n.meta,{force:t.force});if(!s.eligible)return{session_id:e,ok:!1,skipped:s.reason};if(!Cr&&!pe())return{session_id:e,ok:!1,failed:"claude-cli-missing"};let r=xf(n),o=t.model??tt,a=await vf(r,o);if(!a.success){let m=(a.stderr||a.stdout||"").slice(0,400),h=m?Se(m).redacted:void 0;return{session_id:e,ok:!1,failed:"claude-cli-error",exit_code:a.exitCode,stderr_excerpt:h}}let c=Cf(a.stdout);if(!c){let m=a.stdout.slice(0,400),h=m?Se(m).redacted:void 0;return{session_id:e,ok:!1,failed:"parse-failed",exit_code:a.exitCode,stderr_excerpt:h}}let u=If(a.stdout),d=ja({session_id:e,files_written:c.files_written,brands_mentioned:c.brands_mentioned,terms_introduced:c.terms_introduced,plan_ids_referenced:c.plan_ids_referenced,bug_signatures:c.bug_signatures,raw_extraction:{model:o,usage:u,raw_response_excerpt:a.stdout.slice(0,4e3)},extractor_version:vr});return{session_id:e,ok:!0,index:d,usage:u}}function If(e){try{let t=JSON.parse(e.trim());if(t&&typeof t=="object"&&t.usage){let n=t.usage,s={};return typeof n.input_tokens=="number"&&(s.input_tokens=n.input_tokens),typeof n.output_tokens=="number"&&(s.output_tokens=n.output_tokens),s}}catch{}return null}function ft(e={}){let t=f(),n=[],s=[];typeof e.projectId=="number"&&(n.push("s.project_id = ?"),s.push(e.projectId));let r=Math.max(1,Math.min(1e4,e.limit??1e3)),o=n.length?`WHERE ${n.join(" AND ")}`:"",a=t.prepare(`SELECT s.id,
937
937
  NULLIF(sa.alias, '') AS alias,
938
938
  s.auto_title,
939
939
  s.auto_title_source,
@@ -945,33 +945,33 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
945
945
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
946
946
  LEFT JOIN projects p ON p.id = s.project_id
947
947
  ${o}
948
- ORDER BY COALESCE(s.started_at, ''), s.id`).all(...s),c=[],u=new Map;for(let d of a){let m={...d,alias_source:d.alias?"manual":null},h=Va(m,{force:e.force});if(!h.eligible){let S=h.reason??"session-not-found";u.set(S,(u.get(S)??0)+1);continue}if(c.push(m),c.length>=r)break}return{eligible:c,skipped:u}}async function Za(e={}){let t=ft({projectId:e.projectId,limit:e.limit,force:e.force}),n={total:t.eligible.length,processed:0,ok:0,failed:0,skipped:0,current_session_id:null,total_input_tokens:0,total_output_tokens:0};for(let r of t.skipped.values())n.skipped+=r;e.onProgress?.({...n});let s=[];for(let r of t.eligible){if(e.signal?.aborted)break;n.current_session_id=r.id,e.onProgress?.({...n});let o=await vr(r.id,{model:e.model,force:e.force,signal:e.signal});s.push(o),e.onResult?.(o),o.ok?n.ok+=1:o.skipped?n.skipped+=1:n.failed+=1,o.usage?.input_tokens&&(n.total_input_tokens+=o.usage.input_tokens),o.usage?.output_tokens&&(n.total_output_tokens+=o.usage.output_tokens),n.processed+=1,e.onProgress?.({...n})}return n.current_session_id=null,e.onProgress?.({...n}),{progress:n,results:s}}ye();var ne="[daemon:inference]",Pr=!1,$r=!1,Ur=!1,Br=!1,Hr=!1,uc=0,Wr=!1,qr=!1,Kn=3,st=0,ht=!1,Vn=null,Et=null,dc=!1;function Bf(){return f().prepare("SELECT id, name FROM projects").all()}async function pc(){if(Pr)return;Pr=!0;let e=Date.now();try{let n=(await _a({minClusterSize:2})).progress;(n.clusters_created||n.clusters_merged||n.members_added)&&console.log(`${ne} bug-patterns: created=${n.clusters_created} merged=${n.clusters_merged} members_added=${n.members_added} (${Date.now()-e}ms)`)}catch(t){console.error(`${ne} bug-patterns failed:`,t)}finally{Pr=!1}}async function mc(){if($r)return;$r=!0;let e=Date.now();try{let t=0,n=0;for(let s of Bf())try{let r=await La({projectId:s.id});t+=r.progress.suggestions_created,n+=1}catch(r){console.error(`${ne} citations failed for project "${s.name}":`,r)}t>0&&console.log(`${ne} citations: ${t} suggestion(s) across ${n} project(s) (${Date.now()-e}ms)`)}catch(t){console.error(`${ne} citations failed:`,t)}finally{$r=!1}}function gc(){if(Ur)return;Ur=!0;let e=Date.now();try{let t=Ia({}),n=ja({});t.created+n.created>0&&console.log(`${ne} l1: uuid=${t.created} plan=${n.created} (${Date.now()-e}ms)`)}catch(t){console.error(`${ne} l1 failed:`,t)}finally{Ur=!1}}async function _c(){if(Br)return;let e=ce();if(!e.enabled||e.backfillPaused)return;Br=!0;let t=Date.now();try{let n=await Xn({limit:25});n.processed>0&&console.log(`${ne} backfill: processed=${n.processed} ok=${n.ok} failed=${n.failed} (${Date.now()-t}ms)`)}catch(n){console.error(`${ne} backfill failed:`,n)}finally{Br=!1}}async function fc(){if(Hr)return;let e=ce();if(e.autoExtractEnabled&&!dc&&ht&&(Hf(),console.log(`${ne} auto-extract: circuit breaker reset (config toggled on).`)),dc=e.autoExtractEnabled,!e.autoExtractEnabled||ht)return;let t=e.autoExtractIntervalMinutes*60*1e3;if(Date.now()-uc<t)return;if(!pe()){Wr||(console.log(`${ne} auto-extract: claude CLI not on PATH \u2014 pausing nibbler (will retry; install Claude Code or run \`recall semantic auto-extract off\` to silence)`),Wr=!0);return}if(Wr=!1,!await Hi().catch(()=>!1)){qr||(console.log(`${ne} auto-extract: Pro license required \u2014 pausing nibbler (run \`recall semantic auto-extract off\` to silence; upgrade unlocks)`),qr=!0);return}qr=!1,Hr=!0,uc=Date.now();let s=Date.now();try{let r=e.autoExtractBatchSize,{eligible:o}=ft({limit:r});if(o.length===0)return;let a=0,c=0,u=0,d=0,m=new Map,h=null;for(let T of o){let R=await vr(T.id,{model:nt});if(R.ok)a+=1;else if(!R.skipped){c+=1;let w=R.failed??"unknown";m.set(w,(m.get(w)??0)+1),!h&&R.stderr_excerpt&&(h=R.stderr_excerpt)}R.usage?.input_tokens&&(u+=R.usage.input_tokens),R.usage?.output_tokens&&(d+=R.usage.output_tokens)}let S=m.size>0?" reasons="+Array.from(m.entries()).map(([T,R])=>`${T}:${R}`).join(","):"";if(console.log(`${ne} auto-extract: processed=${o.length} ok=${a} failed=${c} tokens=${u}+${d} (${Date.now()-s}ms)${S}`),h){let R=Se(h).redacted.replace(/\s+/g," ").trim().slice(0,300);console.log(`${ne} auto-extract: first failure excerpt: ${R}`)}o.length>0&&u===0&&d===0?(st+=1,st>=Kn&&(ht=!0,Vn=Date.now(),Et=`${Kn} consecutive zero-token runs (claude CLI returning no usage)`,console.log(`${ne} auto-extract: CIRCUIT BREAKER tripped \u2014 ${Et}. Pausing nibbler. Run \`recall semantic auto-extract off\` then \`... on\` to reset, or restart the daemon.`))):(a>0||u>0||d>0)&&(st=0)}catch(r){console.error(`${ne} auto-extract failed:`,r),st+=1,st>=Kn&&(ht=!0,Vn=Date.now(),Et=`${Kn} consecutive thrown errors`,console.log(`${ne} auto-extract: CIRCUIT BREAKER tripped \u2014 ${Et}. Pausing nibbler.`))}finally{Hr=!1}}function Ec(){return{broken:ht,brokenAt:Vn,reason:Et,consecutiveZeroTokenRuns:st}}function Hf(){ht=!1,Vn=null,Et=null,st=0}var Xr=!1;async function hc(){if(Xr)return;let{readRetentionConfig:e,writeRetentionConfig:t}=await Promise.resolve().then(()=>(Mr(),rc)),n=e();if(!n.autoArchiveEnabled)return;let s=1380*60*1e3;if(n.lastRunAt&&Date.now()-Date.parse(n.lastRunAt)<s)return;Xr=!0;let r=Date.now();try{let a=new Date(Date.now()-n.autoArchiveAfterDays*24*60*60*1e3).toISOString().slice(0,10),{runArchive:c}=await Promise.resolve().then(()=>(lc(),cc)),u=await c({_action:"run",before:a,dryRun:!1});t({lastRunAt:new Date().toISOString()}),console.log(`${ne} auto-archive: cutoff=${a} exit=${u} (${Date.now()-r}ms)`)}catch(o){let a=o instanceof Error?o.message:String(o);console.error(`${ne} auto-archive failed: ${a}`)}finally{Xr=!1}}function bc(){let m=[],h=[];m.push(setTimeout(()=>{pc()},9e4)),h.push(setInterval(()=>{pc()},18e5)),m.push(setTimeout(()=>{mc()},18e4)),h.push(setInterval(()=>{mc()},36e5)),m.push(setTimeout(()=>gc(),12e4)),h.push(setInterval(()=>gc(),18e5)),m.push(setTimeout(()=>{_c()},24e4)),h.push(setInterval(()=>{_c()},9e5)),m.push(setTimeout(()=>{fc()},3e5)),h.push(setInterval(()=>{fc()},9e5));let S=3600*1e3,b=300*1e3;return m.push(setTimeout(()=>{hc()},b)),h.push(setInterval(()=>{hc()},S)),console.log(`${ne} scheduled: bug-patterns (30m), citations (60m), l1 (30m), backfill (15m, when enabled), auto-extract (60m, when enabled), auto-archive (24h, when enabled)`),{startupTimers:m,intervalTimers:h,stop:()=>{for(let T of m)clearTimeout(T);for(let T of h)clearInterval(T)}}}U();import{serveStatic as tm}from"@hono/node-server/serve-static";import{existsSync as pw,readFileSync as yi}from"node:fs";import{stat as mw,readFile as gw,realpath as _w}from"node:fs/promises";import{timingSafeEqual as fw}from"node:crypto";import{homedir as hw}from"node:os";import{dirname as ki,join as nr}from"node:path";import{fileURLToPath as Ai}from"node:url";import{existsSync as Px,readFileSync as $x,statSync as Ux,statfsSync as mb}from"node:fs";zn();U();ee();ee();U();import{watch as ZE}from"chokidar";import{readdirSync as QE,statSync as Eo}from"node:fs";import{createReadStream as Wf}from"node:fs";import{createInterface as qf}from"node:readline";function Zn(e){return typeof e=="number"&&Number.isFinite(e)?e:0}function Gr(e){let t=e?.usage;if(!t||typeof t!="object")return null;let n={inputTokens:Zn(t.input_tokens),outputTokens:Zn(t.output_tokens),cacheCreateTokens:Zn(t.cache_creation_input_tokens),cacheReadTokens:Zn(t.cache_read_input_tokens)};return n.inputTokens===0&&n.outputTokens===0&&n.cacheCreateTokens===0&&n.cacheReadTokens===0?null:n}var Xf=/\x1B\[[0-9;]*[a-zA-Z]/g;function Jr(e){return e.replace(Xf,"")}var Yr=12e3;function Sc(e,t){if(e.length<=Yr)return e;let n=e.slice(0,Yr),s=e.length-Yr;return`${n}
948
+ ORDER BY COALESCE(s.started_at, ''), s.id`).all(...s),c=[],u=new Map;for(let d of a){let m={...d,alias_source:d.alias?"manual":null},h=nc(m,{force:e.force});if(!h.eligible){let b=h.reason??"session-not-found";u.set(b,(u.get(b)??0)+1);continue}if(c.push(m),c.length>=r)break}return{eligible:c,skipped:u}}async function sc(e={}){let t=ft({projectId:e.projectId,limit:e.limit,force:e.force}),n={total:t.eligible.length,processed:0,ok:0,failed:0,skipped:0,current_session_id:null,total_input_tokens:0,total_output_tokens:0};for(let r of t.skipped.values())n.skipped+=r;e.onProgress?.({...n});let s=[];for(let r of t.eligible){if(e.signal?.aborted)break;n.current_session_id=r.id,e.onProgress?.({...n});let o=await Ir(r.id,{model:e.model,force:e.force,signal:e.signal});s.push(o),e.onResult?.(o),o.ok?n.ok+=1:o.skipped?n.skipped+=1:n.failed+=1,o.usage?.input_tokens&&(n.total_input_tokens+=o.usage.input_tokens),o.usage?.output_tokens&&(n.total_output_tokens+=o.usage.output_tokens),n.processed+=1,e.onProgress?.({...n})}return n.current_session_id=null,e.onProgress?.({...n}),{progress:n,results:s}}ye();var ne="[daemon:inference]",$r=!1,Ur=!1,Br=!1,Hr=!1,Wr=!1,_c=0,qr=!1,Xr=!1,Vn=3,nt=0,ht=!1,Zn=null,Et=null,fc=!1;function zf(){return f().prepare("SELECT id, name FROM projects").all()}async function hc(){if($r)return;$r=!0;let e=Date.now();try{let n=(await Sa({minClusterSize:2})).progress;(n.clusters_created||n.clusters_merged||n.members_added)&&console.log(`${ne} bug-patterns: created=${n.clusters_created} merged=${n.clusters_merged} members_added=${n.members_added} (${Date.now()-e}ms)`)}catch(t){console.error(`${ne} bug-patterns failed:`,t)}finally{$r=!1}}async function Ec(){if(Ur)return;Ur=!0;let e=Date.now();try{let t=0,n=0;for(let s of zf())try{let r=await Ma({projectId:s.id});t+=r.progress.suggestions_created,n+=1}catch(r){console.error(`${ne} citations failed for project "${s.name}":`,r)}t>0&&console.log(`${ne} citations: ${t} suggestion(s) across ${n} project(s) (${Date.now()-e}ms)`)}catch(t){console.error(`${ne} citations failed:`,t)}finally{Ur=!1}}function bc(){if(Br)return;Br=!0;let e=Date.now();try{let t=Pa({}),n=$a({});t.created+n.created>0&&console.log(`${ne} l1: uuid=${t.created} plan=${n.created} (${Date.now()-e}ms)`)}catch(t){console.error(`${ne} l1 failed:`,t)}finally{Br=!1}}async function Sc(){if(Hr)return;let e=ce();if(!e.enabled||e.backfillPaused)return;Hr=!0;let t=Date.now();try{let n=await Jn({limit:25});n.processed>0&&console.log(`${ne} backfill: processed=${n.processed} ok=${n.ok} failed=${n.failed} (${Date.now()-t}ms)`)}catch(n){console.error(`${ne} backfill failed:`,n)}finally{Hr=!1}}async function Tc(){if(Wr)return;let e=ce();if(e.autoExtractEnabled&&!fc&&ht&&(Kf(),console.log(`${ne} auto-extract: circuit breaker reset (config toggled on).`)),fc=e.autoExtractEnabled,!e.autoExtractEnabled||ht)return;let t=e.autoExtractIntervalMinutes*60*1e3;if(Date.now()-_c<t)return;if(!pe()){qr||(console.log(`${ne} auto-extract: claude CLI not on PATH \u2014 pausing nibbler (will retry; install Claude Code or run \`recall semantic auto-extract off\` to silence)`),qr=!0);return}if(qr=!1,!await zi().catch(()=>!1)){Xr||(console.log(`${ne} auto-extract: Pro license required \u2014 pausing nibbler (run \`recall semantic auto-extract off\` to silence; upgrade unlocks)`),Xr=!0);return}Xr=!1,Wr=!0,_c=Date.now();let s=Date.now();try{let r=e.autoExtractBatchSize,{eligible:o}=ft({limit:r});if(o.length===0)return;let a=0,c=0,u=0,d=0,m=new Map,h=null;for(let T of o){let R=await Ir(T.id,{model:tt});if(R.ok)a+=1;else if(!R.skipped){c+=1;let O=R.failed??"unknown";m.set(O,(m.get(O)??0)+1),!h&&R.stderr_excerpt&&(h=R.stderr_excerpt)}R.usage?.input_tokens&&(u+=R.usage.input_tokens),R.usage?.output_tokens&&(d+=R.usage.output_tokens)}let b=m.size>0?" reasons="+Array.from(m.entries()).map(([T,R])=>`${T}:${R}`).join(","):"";if(console.log(`${ne} auto-extract: processed=${o.length} ok=${a} failed=${c} tokens=${u}+${d} (${Date.now()-s}ms)${b}`),h){let R=Se(h).redacted.replace(/\s+/g," ").trim().slice(0,300);console.log(`${ne} auto-extract: first failure excerpt: ${R}`)}o.length>0&&u===0&&d===0?(nt+=1,nt>=Vn&&(ht=!0,Zn=Date.now(),Et=`${Vn} consecutive zero-token runs (claude CLI returning no usage)`,console.log(`${ne} auto-extract: CIRCUIT BREAKER tripped \u2014 ${Et}. Pausing nibbler. Run \`recall semantic auto-extract off\` then \`... on\` to reset, or restart the daemon.`))):(a>0||u>0||d>0)&&(nt=0)}catch(r){console.error(`${ne} auto-extract failed:`,r),nt+=1,nt>=Vn&&(ht=!0,Zn=Date.now(),Et=`${Vn} consecutive thrown errors`,console.log(`${ne} auto-extract: CIRCUIT BREAKER tripped \u2014 ${Et}. Pausing nibbler.`))}finally{Wr=!1}}function wc(){return{broken:ht,brokenAt:Zn,reason:Et,consecutiveZeroTokenRuns:nt}}function Kf(){ht=!1,Zn=null,Et=null,nt=0}var Jr=!1;async function yc(){if(Jr)return;let{readRetentionConfig:e,writeRetentionConfig:t}=await Promise.resolve().then(()=>(Dr(),lc)),n=e();if(!n.autoArchiveEnabled)return;let s=1380*60*1e3;if(n.lastRunAt&&Date.now()-Date.parse(n.lastRunAt)<s)return;Jr=!0;let r=Date.now();try{let a=new Date(Date.now()-n.autoArchiveAfterDays*24*60*60*1e3).toISOString().slice(0,10),{runArchive:c}=await Promise.resolve().then(()=>(gc(),mc)),u=await c({_action:"run",before:a,dryRun:!1});t({lastRunAt:new Date().toISOString()}),console.log(`${ne} auto-archive: cutoff=${a} exit=${u} (${Date.now()-r}ms)`)}catch(o){let a=o instanceof Error?o.message:String(o);console.error(`${ne} auto-archive failed: ${a}`)}finally{Jr=!1}}function Rc(){let m=[],h=[];m.push(setTimeout(()=>{hc()},9e4)),h.push(setInterval(()=>{hc()},18e5)),m.push(setTimeout(()=>{Ec()},18e4)),h.push(setInterval(()=>{Ec()},36e5)),m.push(setTimeout(()=>bc(),12e4)),h.push(setInterval(()=>bc(),18e5)),m.push(setTimeout(()=>{Sc()},24e4)),h.push(setInterval(()=>{Sc()},9e5)),m.push(setTimeout(()=>{Tc()},3e5)),h.push(setInterval(()=>{Tc()},9e5));let b=3600*1e3,S=300*1e3;return m.push(setTimeout(()=>{yc()},S)),h.push(setInterval(()=>{yc()},b)),console.log(`${ne} scheduled: bug-patterns (30m), citations (60m), l1 (30m), backfill (15m, when enabled), auto-extract (60m, when enabled), auto-archive (24h, when enabled)`),{startupTimers:m,intervalTimers:h,stop:()=>{for(let T of m)clearTimeout(T);for(let T of h)clearInterval(T)}}}B();import{serveStatic as cm}from"@hono/node-server/serve-static";import{existsSync as jw,readFileSync as Oi}from"node:fs";import{stat as Mw,readFile as Dw,realpath as Fw}from"node:fs/promises";import{timingSafeEqual as Pw}from"node:crypto";import{homedir as $w}from"node:os";import{dirname as vi,join as sr}from"node:path";import{fileURLToPath as Ii}from"node:url";import{existsSync as aN,readFileSync as cN,statSync as lN,statfsSync as Ob}from"node:fs";Kn();B();ee();ee();B();import{watch as ib}from"chokidar";import{readdirSync as ab,statSync as bo}from"node:fs";import{createReadStream as Vf}from"node:fs";import{createInterface as Zf}from"node:readline";function Qn(e){return typeof e=="number"&&Number.isFinite(e)?e:0}function zr(e){let t=e?.usage;if(!t||typeof t!="object")return null;let n={inputTokens:Qn(t.input_tokens),outputTokens:Qn(t.output_tokens),cacheCreateTokens:Qn(t.cache_creation_input_tokens),cacheReadTokens:Qn(t.cache_read_input_tokens)};return n.inputTokens===0&&n.outputTokens===0&&n.cacheCreateTokens===0&&n.cacheReadTokens===0?null:n}var Qf=/\x1B\[[0-9;]*[a-zA-Z]/g;function Gr(e){return e.replace(Qf,"")}var Yr=12e3;function kc(e,t){if(e.length<=Yr)return e;let n=e.slice(0,Yr),s=e.length-Yr;return`${n}
949
949
 
950
- \u27E8\u2026 ${s.toLocaleString()} more chars in ${t}; see raw JSONL for full content \u27E9`}function Jf(e){try{return JSON.stringify(e,null,2)}catch{return String(e)}}function Yf(e){if(typeof e.content=="string")return e.content;if(Array.isArray(e.content)){let t=[];for(let n of e.content)if(n&&typeof n=="object"){let s=n;s.type==="text"&&typeof s.text=="string"?t.push(s.text):s.type==="image"&&t.push("[image]")}return t.join(`
951
- `)}return""}function Gf(e){if(!e)return{text:"",toolNames:[]};if(typeof e.content=="string")return{text:Jr(e.content),toolNames:[]};if(!Array.isArray(e.content))return{text:"",toolNames:[]};let t=[],n=[];for(let s of e.content)if(!(!s||typeof s!="object")){if(s.type==="text"&&typeof s.text=="string"){t.push(Jr(s.text));continue}if(s.type==="tool_use"&&typeof s.name=="string"){n.push(s.name);let r=s.input!=null?Jf(s.input):"",o=Sc(r,"tool input");t.push(`\u26A1 **Tool call \xB7 \`${s.name}\`**
950
+ \u27E8\u2026 ${s.toLocaleString()} more chars in ${t}; see raw JSONL for full content \u27E9`}function eh(e){try{return JSON.stringify(e,null,2)}catch{return String(e)}}function th(e){if(typeof e.content=="string")return e.content;if(Array.isArray(e.content)){let t=[];for(let n of e.content)if(n&&typeof n=="object"){let s=n;s.type==="text"&&typeof s.text=="string"?t.push(s.text):s.type==="image"&&t.push("[image]")}return t.join(`
951
+ `)}return""}function nh(e){if(!e)return{text:"",toolNames:[]};if(typeof e.content=="string")return{text:Gr(e.content),toolNames:[]};if(!Array.isArray(e.content))return{text:"",toolNames:[]};let t=[],n=[];for(let s of e.content)if(!(!s||typeof s!="object")){if(s.type==="text"&&typeof s.text=="string"){t.push(Gr(s.text));continue}if(s.type==="tool_use"&&typeof s.name=="string"){n.push(s.name);let r=s.input!=null?eh(s.input):"",o=kc(r,"tool input");t.push(`\u26A1 **Tool call \xB7 \`${s.name}\`**
952
952
 
953
953
  \`\`\`json
954
954
  ${o}
955
- \`\`\``);continue}if(s.type==="tool_result"){let r=Jr(Yf(s));if(r){let o=Sc(r,"tool result");t.push(`**Tool result**
955
+ \`\`\``);continue}if(s.type==="tool_result"){let r=Gr(th(s));if(r){let o=kc(r,"tool result");t.push(`**Tool result**
956
956
 
957
957
  \`\`\`
958
958
  ${o}
959
959
  \`\`\``)}else t.push("_(tool result was empty or image-only)_");continue}if(s.type==="image"){t.push("_(image)_");continue}t.push(`_(unknown block: ${s.type})_`)}return{text:t.join(`
960
960
 
961
- `),toolNames:n}}async function*Tc(e){let t=Wf(e,{encoding:"utf8"}),n=qf({input:t,crlfDelay:1/0});for await(let s of n){if(!s.trim())continue;let r;try{r=JSON.parse(s)}catch{continue}if(!r.uuid||!r.sessionId)continue;let{text:o,toolNames:a}=Gf(r.message);yield{uuid:r.uuid,parentUuid:r.parentUuid??null,sessionId:r.sessionId,type:r.type??"unknown",role:r.message?.role??null,timestamp:r.timestamp??null,isSidechain:r.isSidechain===!0,cwd:r.cwd??null,gitBranch:r.gitBranch??null,version:r.version??null,contentText:o,toolNames:a,raw:s,usage:Gr(r.message),model:r.message?.model??null}}}import{basename as Al,join as eb}from"node:path";import{execFile as hh}from"node:child_process";import{promisify as Eh}from"node:util";import{existsSync as bh}from"node:fs";import{basename as Sh}from"node:path";ee();import{existsSync as zf,readFileSync as Kf,writeFileSync as Vf}from"node:fs";import{join as Zf}from"node:path";import{z as fe}from"zod";var zr=Zf(H,"terminals.json"),yc=1440*60*1e3,Qf=3e4,eh=6e4,th=fe.object({shell_pid:fe.number(),tab_name:fe.string(),cwd:fe.string().nullable().optional(),opened_at:fe.string(),last_seen_at:fe.string()}),nh=fe.object({schema:fe.string().optional(),saved_at:fe.string().optional(),terminals:fe.array(th).max(500).default([]),sessions_by_pid:fe.record(fe.string(),fe.array(fe.string()).max(50)).optional().default({})}),wc=/^[⠀-⣿✳\s]+/,Rc=/^\d+(\.\d+){1,3}$/;function le(e){let t=e.trim();return!!(!t||wc.test(t)||Rc.test(t))}function bt(e){let t=e.trim();if(!t||Rc.test(t))return null;let n=t.replace(wc,"").trim();return n.length>0?n:null}function Kr(e,t){if(!le(e))return e;let n=bt(e);return n||(t&&!le(t)?t:e)}function sh(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 Vr=class{entries=new Map;origins=new Map;sessionsByPid=new Map;pendingClaudeStarts=[];deferredLinks=new Map;pidOwnership=new Map;loaded=!1;ensureLoaded(){if(!this.loaded&&(this.loaded=!0,!!zf(zr)))try{let t=Kf(zr,"utf8"),n=JSON.parse(t),s=nh.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,a]of Object.entries(r.sessions_by_pid??{})){let c=Number(o);if(!Number.isFinite(c))continue;let u=new Set;for(let d of a)d.length>0&&u.add(d);u.size>0&&this.sessionsByPid.set(c,u)}this.gc()}catch{}}save(){try{z();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)]))};Vf(zr,JSON.stringify(t,null,2))}catch{}}upsert(t){this.ensureLoaded();let n=new Date().toISOString(),s=this.entries.get(t.shell_pid),r=Kr(t.tab_name,s?.tab_name),o=s?.opened_at??t.opened_at,a={...t,tab_name:r,opened_at:o,last_seen_at:n};return this.entries.set(t.shell_pid,a),this.gc(),this.save(),a}rename(t,n){this.ensureLoaded();let s=this.entries.get(t);if(!s)return null;let r=Kr(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>eh?(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 a=this.entries.get(o.shell_pid),c=Kr(o.tab_name,a?.tab_name),u=a?.opened_at??o.opened_at;this.entries.set(o.shell_pid,{...o,tab_name:c,opened_at:u,last_seen_at:n}),a?(a.tab_name!==c||a.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=sh({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()-Qf;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()-yc;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()-yc;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[a,c]of this.sessionsByPid){let u=this.entries.get(a);if(u){let d=Date.parse(u.last_seen_at);if(Number.isFinite(d)&&d>=s)continue}o+=c.size,this.sessionsByPid.delete(a),u&&(this.entries.delete(a),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(a){a.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}}},I=new Vr;U();ee();import{writeFileSync as rh}from"node:fs";import{join as oh}from"node:path";var ih=oh(H,"aliases.json");function Zr(e){try{let t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return[]}function Te(e){return f().prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(e)?.alias??null}function ah(){return f().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:Zr(t.previous_aliases)}))}function he(e,t){let n=t.trim();if(!n)throw new Error("alias must be non-empty");let s=f(),r=new Date().toISOString(),o=s.prepare("SELECT alias, previous_aliases FROM session_aliases WHERE session_id = ?").get(e),a=[];return o&&(a=Zr(o.previous_aliases),o.alias!==n&&a.push({alias:o.alias,replaced_at:r})),s.prepare(`INSERT INTO session_aliases (session_id, alias, updated_at, previous_aliases)
961
+ `),toolNames:n}}async function*Ac(e){let t=Vf(e,{encoding:"utf8"}),n=Zf({input:t,crlfDelay:1/0});for await(let s of n){if(!s.trim())continue;let r;try{r=JSON.parse(s)}catch{continue}if(!r.uuid||!r.sessionId)continue;let{text:o,toolNames:a}=nh(r.message);yield{uuid:r.uuid,parentUuid:r.parentUuid??null,sessionId:r.sessionId,type:r.type??"unknown",role:r.message?.role??null,timestamp:r.timestamp??null,isSidechain:r.isSidechain===!0,cwd:r.cwd??null,gitBranch:r.gitBranch??null,version:r.version??null,contentText:o,toolNames:a,raw:s,usage:zr(r.message),model:r.message?.model??null}}}import{basename as Cl,join as cb}from"node:path";import{execFile as kh}from"node:child_process";import{promisify as Ah}from"node:util";import{existsSync as xh}from"node:fs";import{basename as Nh}from"node:path";ee();import{existsSync as sh,readFileSync as rh,writeFileSync as oh}from"node:fs";import{join as ih}from"node:path";import{z as fe}from"zod";var Kr=ih(W,"terminals.json"),xc=1440*60*1e3,ah=3e4,ch=6e4,lh=fe.object({shell_pid:fe.number(),tab_name:fe.string(),cwd:fe.string().nullable().optional(),opened_at:fe.string(),last_seen_at:fe.string()}),uh=fe.object({schema:fe.string().optional(),saved_at:fe.string().optional(),terminals:fe.array(lh).max(500).default([]),sessions_by_pid:fe.record(fe.string(),fe.array(fe.string()).max(50)).optional().default({})}),Nc=/^[⠀-⣿✳\s]+/,Oc=/^\d+(\.\d+){1,3}$/;function le(e){let t=e.trim();return!!(!t||Nc.test(t)||Oc.test(t))}function bt(e){let t=e.trim();if(!t||Oc.test(t))return null;let n=t.replace(Nc,"").trim();return n.length>0?n:null}function Vr(e,t){if(!le(e))return e;let n=bt(e);return n||(t&&!le(t)?t:e)}function dh(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 Zr=class{entries=new Map;origins=new Map;sessionsByPid=new Map;pendingClaudeStarts=[];deferredLinks=new Map;pidOwnership=new Map;loaded=!1;ensureLoaded(){if(!this.loaded&&(this.loaded=!0,!!sh(Kr)))try{let t=rh(Kr,"utf8"),n=JSON.parse(t),s=uh.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,a]of Object.entries(r.sessions_by_pid??{})){let c=Number(o);if(!Number.isFinite(c))continue;let u=new Set;for(let d of a)d.length>0&&u.add(d);u.size>0&&this.sessionsByPid.set(c,u)}this.gc()}catch{}}save(){try{z();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)]))};oh(Kr,JSON.stringify(t,null,2))}catch{}}upsert(t){this.ensureLoaded();let n=new Date().toISOString(),s=this.entries.get(t.shell_pid),r=Vr(t.tab_name,s?.tab_name),o=s?.opened_at??t.opened_at,a={...t,tab_name:r,opened_at:o,last_seen_at:n};return this.entries.set(t.shell_pid,a),this.gc(),this.save(),a}rename(t,n){this.ensureLoaded();let s=this.entries.get(t);if(!s)return null;let r=Vr(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>ch?(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 a=this.entries.get(o.shell_pid),c=Vr(o.tab_name,a?.tab_name),u=a?.opened_at??o.opened_at;this.entries.set(o.shell_pid,{...o,tab_name:c,opened_at:u,last_seen_at:n}),a?(a.tab_name!==c||a.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=dh({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()-ah;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()-xc;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()-xc;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[a,c]of this.sessionsByPid){let u=this.entries.get(a);if(u){let d=Date.parse(u.last_seen_at);if(Number.isFinite(d)&&d>=s)continue}o+=c.size,this.sessionsByPid.delete(a),u&&(this.entries.delete(a),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(a){a.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}}},M=new Zr;B();ee();import{writeFileSync as ph}from"node:fs";import{join as mh}from"node:path";var gh=mh(W,"aliases.json");function Qr(e){try{let t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return[]}function Te(e){return f().prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(e)?.alias??null}function _h(){return f().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:Qr(t.previous_aliases)}))}function he(e,t){let n=t.trim();if(!n)throw new Error("alias must be non-empty");let s=f(),r=new Date().toISOString(),o=s.prepare("SELECT alias, previous_aliases FROM session_aliases WHERE session_id = ?").get(e),a=[];return o&&(a=Qr(o.previous_aliases),o.alias!==n&&a.push({alias:o.alias,replaced_at:r})),s.prepare(`INSERT INTO session_aliases (session_id, alias, updated_at, previous_aliases)
962
962
  VALUES (?, ?, ?, ?)
963
963
  ON CONFLICT(session_id) DO UPDATE SET
964
964
  alias = excluded.alias,
965
965
  updated_at = excluded.updated_at,
966
- previous_aliases = excluded.previous_aliases`).run(e,n,r,JSON.stringify(a)),kc(),{session_id:e,alias:n,updated_at:r,previous_aliases:a}}function Qn(e){let t=f(),n=new Date().toISOString(),s=t.prepare("SELECT alias, previous_aliases FROM session_aliases WHERE session_id = ?").get(e);if(!s)return;let r=Zr(s.previous_aliases);r.push({alias:s.alias,replaced_at:n}),t.prepare(`UPDATE session_aliases SET alias = '', updated_at = ?, previous_aliases = ?
967
- WHERE session_id = ?`).run(n,JSON.stringify(r),e),kc()}function kc(){try{z();let e=ah(),t={schema:"claude-recall.aliases.v1",backed_up_at:new Date().toISOString(),aliases:e};rh(ih,JSON.stringify(t,null,2))}catch(e){console.error("[aliases] backup failed:",e)}}U();import{execFile as ch}from"node:child_process";import{readFile as lh}from"node:fs/promises";import{promisify as uh}from"node:util";var dh=uh(ch),Ac=["CURSOR_TRACE_ID","VSCODE_PID","VSCODE_INJECTION","TERM_PROGRAM","TERM_PROGRAM_VERSION","TERM","WT_SESSION","KITTY_WINDOW_ID","ALACRITTY_SOCKET","WARP_HONOR_PS1"];function ph(e){let t={};for(let n of Ac){let s=e[n];typeof s=="string"&&s.length>0&&(t[n]=s)}return t}function mh(e){let t=Date.now();if(e.CURSOR_TRACE_ID)return{editor:"cursor",label:"Cursor",detectedAt:t};if(e.VSCODE_PID||e.VSCODE_INJECTION)return{editor:"vscode",label:"VS Code",detectedAt:t};let n=e.TERM_PROGRAM;return n==="WarpTerminal"?{editor:"warp",label:"Warp",detectedAt:t}:n==="iTerm.app"?{editor:"iterm",label:"iTerm",detectedAt:t}:n==="Apple_Terminal"?{editor:"apple-terminal",label:"Terminal",detectedAt:t}:n==="WezTerm"?{editor:"wezterm",label:"WezTerm",detectedAt:t}:e.WT_SESSION?{editor:"windows-terminal",label:"Windows Terminal",detectedAt:t}:e.KITTY_WINDOW_ID?{editor:"kitty",label:"Kitty",detectedAt:t}:e.TERM==="alacritty"||e.ALACRITTY_SOCKET?{editor:"alacritty",label:"Alacritty",detectedAt:t}:null}async function gh(e){if(process.platform==="linux")try{let t=await lh(`/proc/${e}/environ`,"utf8");return _h(t)}catch{return{}}try{let{stdout:t}=await dh("/bin/ps",["eww","-o","command=","-p",String(e)],{timeout:2e3,maxBuffer:1048576});return fh(t)}catch{return{}}}function _h(e){let t={};for(let n of e.split("\0")){if(!n)continue;let s=n.indexOf("=");if(s<=0)continue;let r=n.slice(0,s),o=n.slice(s+1);t[r]=o}return t}function fh(e){let t={},n=new Set(Ac),s=e.replace(/\s+/g," ").trim().split(" ");for(let r of s){let o=r.indexOf("=");if(o<=0)continue;let a=r.slice(0,o);n.has(a)&&(t[a]=r.slice(o+1))}return t}async function xc(e){if(!Number.isFinite(e)||e<=0)return null;try{let t=await gh(e),n=ph(t);return mh(n)}catch{return null}}var ts=Eh(hh),es;function Th(){if(es!==void 0)return es;let e=["/usr/sbin/lsof","/usr/bin/lsof","/opt/homebrew/bin/lsof"];for(let t of e)if(bh(t))return es=t,t;return es=null,null}var yh=3,wh=3600*1e3,en=new Map;function Lc(){let e=I.all(),t=e.map(n=>n.shell_pid).sort((n,s)=>n-s).join(",");return`${e.length}:${t}`}function Rh(e){let t=en.get(e);return t?Date.now()-t.lastAt>wh?(en.delete(e),!1):t.refusals<yh?!1:t.fingerprint===Lc():!1}function Nc(e){let t=Lc(),n=en.get(e);n&&n.fingerprint===t?(n.refusals+=1,n.lastAt=Date.now()):en.set(e,{refusals:1,fingerprint:t,lastAt:Date.now()})}function kh(e){en.delete(e)}async function Ah(e){let t=Th();if(!t)return null;try{let{stdout:n}=await ts(t,["-Fpc",e],{timeout:2e3}),s=n.split(`
968
- `),r=null,o=null,a=null;for(let c of s)c.startsWith("p")?(a=Number(c.slice(1)),Number.isFinite(a)&&a>0?r==null&&(r=a):a=null):c.startsWith("c")&&a!=null&&c.slice(1).trim()==="claude"&&o==null&&(o=a);return o??r}catch{return null}}async function Oc(e){try{let{stdout:t}=await ts("/bin/ps",["-o","ppid=","-p",String(e)],{timeout:2e3}),n=Number(t.trim());return Number.isFinite(n)&&n>0?n:null}catch{return null}}async function xh(e){try{let{stdout:t}=await ts("/bin/ps",["-o","lstart=","-p",String(e)],{timeout:2e3}),n=Date.parse(t.trim());return Number.isFinite(n)?n:null}catch{return null}}var Nh=new Set(["zsh","bash","fish","sh","dash","ksh","tcsh","csh","pwsh","powershell","cmd","nu","node","deno","bun","python","python3","ruby","ts-node","tsx","go","cargo","java","php","irb","pry","iex","terminal","shell","console"]);function de(e){let t=e.trim().toLowerCase();if(!t)return!0;let n=t.replace(/^[-/]+/,"").replace(/^.*\//,"").replace(/\s*\(\d+\)\s*$/,"").trim();return Nh.has(n)}function St(e){let t=e.tabName?.trim();return t&&!de(t)&&!le(t)?t:null}function Oh(e){try{return f().prepare("SELECT cwd, git_branch FROM sessions WHERE id = ?").get(e)??null}catch{return null}}async function ns(e){let t=Sh(e,".jsonl");if(Te(t)||Rh(t))return;let n=Oh(t),s=await Ah(e),r=s?await Oc(s):null,o=s?await xc(s):null;o&&I.setOrigin(t,o);let a=null,c=null,u=null,d=I.takePendingMatched({shellPid:r,cwd:n?.cwd??null,withinMs:3e4});if(d.kind==="ambiguous"){console.log(`[correlator] ambiguous pending for ${t.slice(0,8)} (${d.candidates.length} candidates in ${n?.cwd??"?"}) \u2014 refusing to guess; heuristic title will display`),Nc(t);return}if(d.kind==="pid-match"||d.kind==="singleton-cwd"){let T=d.entry;c=T.shell_pid,u=d.kind==="pid-match"?"pending-pid":"pending-cwd",a=I.get(T.shell_pid)??{shell_pid:T.shell_pid,tab_name:T.tab_name,cwd:T.cwd,opened_at:T.started_at,last_seen_at:T.started_at}}let m=null;if(!a&&s){let T=s;for(let R=0;R<4&&T!=null;R++){let w=await Oc(T);if(!w)break;let j=I.get(w);if(j){a=j,c=w,u="ppid";break}m==null&&(m=w),T=w}}if(!a&&n?.cwd){let T=n.cwd.replace(/\/+$/,""),R=I.all().filter(w=>w.cwd&&w.cwd.replace(/\/+$/,"")===T);R.length===1?(a=R[0],c=a.shell_pid,u="cwd"):R.length>=2&&(console.log(`[correlator] ${R.length} registered terminals in ${T} for ${t.slice(0,8)} \u2014 refusing to guess; heuristic title will display`),Nc(t))}let h=null;if(a?.tab_name&&!de(a.tab_name)&&!le(a.tab_name))h=a.tab_name;else if(a?.tab_name&&le(a.tab_name)){let T=bt(a.tab_name);T&&!de(T)&&(h=T)}if(!h&&!(u==="pending-pid"||u==="pending-cwd")&&a&&n?.cwd){let T=n.cwd.replace(/\/+$/,""),R=I.all().filter(w=>w.shell_pid!==c&&w.cwd&&w.cwd.replace(/\/+$/,"")===T&&!de(w.tab_name)&&!le(w.tab_name)).sort((w,j)=>Date.parse(j.last_seen_at)-Date.parse(w.last_seen_at))[0];R&&(h=R.tab_name)}let b=St({tabName:h,origin:o,cwd:n?.cwd??null,gitBranch:n?.git_branch??null});if(m!=null&&!c&&I.deferSessionLink(t,m,n?.cwd??null,n?.git_branch??null),!!b)try{he(t,b),kh(t);let T=!!h&&!de(h)&&!le(h)&&b===h.trim();c!=null&&I.linkSession(t,c);let R=u==="pending-pid"?"pending PID-exact match":u==="pending-cwd"?"pending cwd-singleton match":u??"unknown";console.log(`[correlator] auto-aliased ${t.slice(0,8)} \u2192 "${b}"`+(T?` (tab name via ${R}, shell pid ${c})`:a?` (generic shell name "${a.tab_name}" \u2192 ${o?.editor??"origin"} fallback, shell pid ${c})`:o?` (${o.editor} origin \u2014 no terminal match)`:""))}catch{}}async function Lh(){try{let{stdout:e}=await ts("/bin/ps",["-eo","pid=,ppid=,comm="],{timeout:2e3}),t=new Map;for(let n of e.split(`
969
- `)){let s=n.trim();if(!s)continue;let r=s.match(/^(\d+)\s+(\d+)\s+(.+)$/);if(!r)continue;let o=Number(r[1]),a=Number(r[2]),c=r[3].trim();(c==="claude"||c.endsWith("/claude")||c.endsWith("/bin/claude"))&&(!Number.isFinite(o)||!Number.isFinite(a)||t.set(o,a))}return t}catch{return new Map}}var Ch=9e4;function vh(e){let t=(Date.now()-Ch)/1e3,n=e.replace(/\/+$/,"");return f().prepare(`SELECT s.id, NULLIF(sa.alias, '') AS alias, s.started_at AS started_at
966
+ previous_aliases = excluded.previous_aliases`).run(e,n,r,JSON.stringify(a)),Lc(),{session_id:e,alias:n,updated_at:r,previous_aliases:a}}function es(e){let t=f(),n=new Date().toISOString(),s=t.prepare("SELECT alias, previous_aliases FROM session_aliases WHERE session_id = ?").get(e);if(!s)return;let r=Qr(s.previous_aliases);r.push({alias:s.alias,replaced_at:n}),t.prepare(`UPDATE session_aliases SET alias = '', updated_at = ?, previous_aliases = ?
967
+ WHERE session_id = ?`).run(n,JSON.stringify(r),e),Lc()}function Lc(){try{z();let e=_h(),t={schema:"claude-recall.aliases.v1",backed_up_at:new Date().toISOString(),aliases:e};ph(gh,JSON.stringify(t,null,2))}catch(e){console.error("[aliases] backup failed:",e)}}B();import{execFile as fh}from"node:child_process";import{readFile as hh}from"node:fs/promises";import{promisify as Eh}from"node:util";var bh=Eh(fh),Cc=["CURSOR_TRACE_ID","VSCODE_PID","VSCODE_INJECTION","TERM_PROGRAM","TERM_PROGRAM_VERSION","TERM","WT_SESSION","KITTY_WINDOW_ID","ALACRITTY_SOCKET","WARP_HONOR_PS1"];function Sh(e){let t={};for(let n of Cc){let s=e[n];typeof s=="string"&&s.length>0&&(t[n]=s)}return t}function Th(e){let t=Date.now();if(e.CURSOR_TRACE_ID)return{editor:"cursor",label:"Cursor",detectedAt:t};if(e.VSCODE_PID||e.VSCODE_INJECTION)return{editor:"vscode",label:"VS Code",detectedAt:t};let n=e.TERM_PROGRAM;return n==="WarpTerminal"?{editor:"warp",label:"Warp",detectedAt:t}:n==="iTerm.app"?{editor:"iterm",label:"iTerm",detectedAt:t}:n==="Apple_Terminal"?{editor:"apple-terminal",label:"Terminal",detectedAt:t}:n==="WezTerm"?{editor:"wezterm",label:"WezTerm",detectedAt:t}:e.WT_SESSION?{editor:"windows-terminal",label:"Windows Terminal",detectedAt:t}:e.KITTY_WINDOW_ID?{editor:"kitty",label:"Kitty",detectedAt:t}:e.TERM==="alacritty"||e.ALACRITTY_SOCKET?{editor:"alacritty",label:"Alacritty",detectedAt:t}:null}async function yh(e){if(process.platform==="linux")try{let t=await hh(`/proc/${e}/environ`,"utf8");return wh(t)}catch{return{}}try{let{stdout:t}=await bh("/bin/ps",["eww","-o","command=","-p",String(e)],{timeout:2e3,maxBuffer:1048576});return Rh(t)}catch{return{}}}function wh(e){let t={};for(let n of e.split("\0")){if(!n)continue;let s=n.indexOf("=");if(s<=0)continue;let r=n.slice(0,s),o=n.slice(s+1);t[r]=o}return t}function Rh(e){let t={},n=new Set(Cc),s=e.replace(/\s+/g," ").trim().split(" ");for(let r of s){let o=r.indexOf("=");if(o<=0)continue;let a=r.slice(0,o);n.has(a)&&(t[a]=r.slice(o+1))}return t}async function vc(e){if(!Number.isFinite(e)||e<=0)return null;try{let t=await yh(e),n=Sh(t);return Th(n)}catch{return null}}var ns=Ah(kh),ts;function Oh(){if(ts!==void 0)return ts;let e=["/usr/sbin/lsof","/usr/bin/lsof","/opt/homebrew/bin/lsof"];for(let t of e)if(xh(t))return ts=t,t;return ts=null,null}var Lh=3,Ch=3600*1e3,en=new Map;function Mc(){let e=M.all(),t=e.map(n=>n.shell_pid).sort((n,s)=>n-s).join(",");return`${e.length}:${t}`}function vh(e){let t=en.get(e);return t?Date.now()-t.lastAt>Ch?(en.delete(e),!1):t.refusals<Lh?!1:t.fingerprint===Mc():!1}function Ic(e){let t=Mc(),n=en.get(e);n&&n.fingerprint===t?(n.refusals+=1,n.lastAt=Date.now()):en.set(e,{refusals:1,fingerprint:t,lastAt:Date.now()})}function Ih(e){en.delete(e)}async function jh(e){let t=Oh();if(!t)return null;try{let{stdout:n}=await ns(t,["-Fpc",e],{timeout:2e3}),s=n.split(`
968
+ `),r=null,o=null,a=null;for(let c of s)c.startsWith("p")?(a=Number(c.slice(1)),Number.isFinite(a)&&a>0?r==null&&(r=a):a=null):c.startsWith("c")&&a!=null&&c.slice(1).trim()==="claude"&&o==null&&(o=a);return o??r}catch{return null}}async function jc(e){try{let{stdout:t}=await ns("/bin/ps",["-o","ppid=","-p",String(e)],{timeout:2e3}),n=Number(t.trim());return Number.isFinite(n)&&n>0?n:null}catch{return null}}async function Mh(e){try{let{stdout:t}=await ns("/bin/ps",["-o","lstart=","-p",String(e)],{timeout:2e3}),n=Date.parse(t.trim());return Number.isFinite(n)?n:null}catch{return null}}var Dh=new Set(["zsh","bash","fish","sh","dash","ksh","tcsh","csh","pwsh","powershell","cmd","nu","node","deno","bun","python","python3","ruby","ts-node","tsx","go","cargo","java","php","irb","pry","iex","terminal","shell","console"]);function de(e){let t=e.trim().toLowerCase();if(!t)return!0;let n=t.replace(/^[-/]+/,"").replace(/^.*\//,"").replace(/\s*\(\d+\)\s*$/,"").trim();return Dh.has(n)}function St(e){let t=e.tabName?.trim();return t&&!de(t)&&!le(t)?t:null}function Fh(e){try{return f().prepare("SELECT cwd, git_branch FROM sessions WHERE id = ?").get(e)??null}catch{return null}}async function ss(e){let t=Nh(e,".jsonl");if(Te(t)||vh(t))return;let n=Fh(t),s=await jh(e),r=s?await jc(s):null,o=s?await vc(s):null;o&&M.setOrigin(t,o);let a=null,c=null,u=null,d=M.takePendingMatched({shellPid:r,cwd:n?.cwd??null,withinMs:3e4});if(d.kind==="ambiguous"){console.log(`[correlator] ambiguous pending for ${t.slice(0,8)} (${d.candidates.length} candidates in ${n?.cwd??"?"}) \u2014 refusing to guess; heuristic title will display`),Ic(t);return}if(d.kind==="pid-match"||d.kind==="singleton-cwd"){let T=d.entry;c=T.shell_pid,u=d.kind==="pid-match"?"pending-pid":"pending-cwd",a=M.get(T.shell_pid)??{shell_pid:T.shell_pid,tab_name:T.tab_name,cwd:T.cwd,opened_at:T.started_at,last_seen_at:T.started_at}}let m=null;if(!a&&s){let T=s;for(let R=0;R<4&&T!=null;R++){let O=await jc(T);if(!O)break;let L=M.get(O);if(L){a=L,c=O,u="ppid";break}m==null&&(m=O),T=O}}if(!a&&n?.cwd){let T=n.cwd.replace(/\/+$/,""),R=M.all().filter(O=>O.cwd&&O.cwd.replace(/\/+$/,"")===T);R.length===1?(a=R[0],c=a.shell_pid,u="cwd"):R.length>=2&&(console.log(`[correlator] ${R.length} registered terminals in ${T} for ${t.slice(0,8)} \u2014 refusing to guess; heuristic title will display`),Ic(t))}let h=null;if(a?.tab_name&&!de(a.tab_name)&&!le(a.tab_name))h=a.tab_name;else if(a?.tab_name&&le(a.tab_name)){let T=bt(a.tab_name);T&&!de(T)&&(h=T)}if(!h&&!(u==="pending-pid"||u==="pending-cwd")&&a&&n?.cwd){let T=n.cwd.replace(/\/+$/,""),R=M.all().filter(O=>O.shell_pid!==c&&O.cwd&&O.cwd.replace(/\/+$/,"")===T&&!de(O.tab_name)&&!le(O.tab_name)).sort((O,L)=>Date.parse(L.last_seen_at)-Date.parse(O.last_seen_at))[0];R&&(h=R.tab_name)}let S=St({tabName:h,origin:o,cwd:n?.cwd??null,gitBranch:n?.git_branch??null});if(m!=null&&!c&&M.deferSessionLink(t,m,n?.cwd??null,n?.git_branch??null),!!S)try{he(t,S),Ih(t);let T=!!h&&!de(h)&&!le(h)&&S===h.trim();c!=null&&M.linkSession(t,c);let R=u==="pending-pid"?"pending PID-exact match":u==="pending-cwd"?"pending cwd-singleton match":u??"unknown";console.log(`[correlator] auto-aliased ${t.slice(0,8)} \u2192 "${S}"`+(T?` (tab name via ${R}, shell pid ${c})`:a?` (generic shell name "${a.tab_name}" \u2192 ${o?.editor??"origin"} fallback, shell pid ${c})`:o?` (${o.editor} origin \u2014 no terminal match)`:""))}catch{}}async function Ph(){try{let{stdout:e}=await ns("/bin/ps",["-eo","pid=,ppid=,comm="],{timeout:2e3}),t=new Map;for(let n of e.split(`
969
+ `)){let s=n.trim();if(!s)continue;let r=s.match(/^(\d+)\s+(\d+)\s+(.+)$/);if(!r)continue;let o=Number(r[1]),a=Number(r[2]),c=r[3].trim();(c==="claude"||c.endsWith("/claude")||c.endsWith("/bin/claude"))&&(!Number.isFinite(o)||!Number.isFinite(a)||t.set(o,a))}return t}catch{return new Map}}var $h=9e4;function Uh(e){let t=(Date.now()-$h)/1e3,n=e.replace(/\/+$/,"");return f().prepare(`SELECT s.id, NULLIF(sa.alias, '') AS alias, s.started_at AS started_at
970
970
  FROM sessions s
971
971
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
972
- WHERE s.cwd = ? AND s.file_mtime > ?`).all(n,t).map(r=>({id:r.id,alias:r.alias,started_at_ms:r.started_at?Date.parse(r.started_at):null}))}async function Ih(e){let t=await import("node:fs/promises"),n="";try{let r=await t.open(e,"r");try{let o=Buffer.alloc(32768),{bytesRead:a}=await r.read(o,0,o.length,0);n=o.toString("utf8",0,a)}finally{await r.close()}}catch{return[]}let s=[];for(let r of n.split(`
972
+ WHERE s.cwd = ? AND s.file_mtime > ?`).all(n,t).map(r=>({id:r.id,alias:r.alias,started_at_ms:r.started_at?Date.parse(r.started_at):null}))}async function Bh(e){let t=await import("node:fs/promises"),n="";try{let r=await t.open(e,"r");try{let o=Buffer.alloc(32768),{bytesRead:a}=await r.read(o,0,o.length,0);n=o.toString("utf8",0,a)}finally{await r.close()}}catch{return[]}let s=[];for(let r of n.split(`
973
973
  `)){if(!r.trim())continue;let o;try{o=JSON.parse(r)}catch{continue}let a=o;if(!a||a.type!=="user"&&a.type!=="assistant")continue;let c=a.message?.content,u="";if(typeof c=="string")u=c;else if(Array.isArray(c))for(let d of c)d&&typeof d=="object"&&"text"in d&&typeof d.text=="string"&&(u+=d.text+`
974
- `);if(u){for(let d of u.split(/\r?\n/)){let m=d.trim();m.length>=60&&m.length<=400&&s.push(m)}if(s.length>=8)break}}return s}async function Cc(e){if(Te(e))return null;let t=f().prepare("SELECT cwd, file_path FROM sessions WHERE id = ?").get(e);if(!t?.cwd||!t.file_path)return null;let n=await Ih(t.file_path);if(n.length===0)return null;let s=t.cwd.replace(/\/+$/,""),r=I.allOutputTails(),o=[];for(let[a,c]of r){let u=I.get(a);if(!u||!u.cwd||u.cwd.replace(/\/+$/,"")!==s||de(u.tab_name)||le(u.tab_name))continue;let d=0;for(let m of n)c.text.includes(m)&&d++;d>0&&o.push({shell_pid:a,tab_name:u.tab_name,matched_fingerprints:d})}return o.length===0||(o.sort((a,c)=>c.matched_fingerprints-a.matched_fingerprints),o.length>1&&o[0].matched_fingerprints===o[1].matched_fingerprints)?null:o[0]}var jh=3e4;function vc(){let e=Date.now(),t=I.all(),n=o=>{let a=Date.parse(o.last_seen_at);return!Number.isFinite(a)||e-a>jh},s=new Map;for(let o of t){if(n(o)||!o.cwd||de(o.tab_name)||le(o.tab_name))continue;let a=`${o.cwd.replace(/\/+$/,"")}::${o.tab_name}`,c=s.get(a);c||(c=[],s.set(a,c)),c.push({shell_pid:o.shell_pid,tab_name:o.tab_name,cwd:o.cwd})}let r={rebound:0,ghosts:0,ambiguous:0};for(let o of t){if(!n(o))continue;let a=I.sessionsFor(o.shell_pid);if(a.length!==0){r.ghosts++;for(let c of a){let u=Te(c);if(!u)continue;let d=f().prepare("SELECT cwd FROM sessions WHERE id = ?").get(c);if(!d?.cwd)continue;let m=`${d.cwd.replace(/\/+$/,"")}::${u}`,h=s.get(m)??[];if(h.length===0)continue;if(h.length>1){r.ambiguous++;continue}let S=h[0];S.shell_pid!==o.shell_pid&&(I.unlinkSession(c),I.linkSession(c,S.shell_pid),r.rebound++)}}}return r}function Ic(){let e={resolved:0,expired:0},t=I.allDeferredLinks();for(let n of t){let s=I.get(n.parent_shell_pid);if(!s||de(s.tab_name)||le(s.tab_name))continue;let r=Te(n.session_id);if(r&&!I.isSessionAutoLinked(n.session_id)){I.resolveDeferredLink(n.session_id);continue}let o=I.getOrigin(n.session_id),a=St({tabName:s.tab_name,origin:o??null,cwd:n.cwd,gitBranch:n.git_branch});if(!a){I.resolveDeferredLink(n.session_id);continue}r!==a&&he(n.session_id,a),I.linkSession(n.session_id,n.parent_shell_pid),I.resolveDeferredLink(n.session_id),e.resolved++}return e}var Mh=6e4;async function ss(){let e=await Lh(),t={scanned:e.size,linked:0,renamed:0,skipped_manual:0,ambiguous_cwd:0};if(e.size===0)return t;let n=[];for(let[a,c]of e){let u=I.get(c);if(!u||!u.cwd||de(u.tab_name)||le(u.tab_name))continue;let d=u.tab_name.trim();if(!d)continue;let m=await xh(a);n.push({claudePid:a,shellPid:c,cwd:u.cwd.replace(/\/+$/,""),target:d,startTimeMs:m})}let s=new Map,r=a=>{let c=s.get(a);if(c)return c;let u=vh(a);return s.set(a,u),u},o=new Set;for(let a of n){let c=r(a.cwd).filter(d=>!o.has(d.id));if(c.length===0)continue;let u=null;if(a.startTimeMs!=null){let d=Mh;for(let m of c){if(m.started_at_ms==null)continue;let h=Math.abs(m.started_at_ms-a.startTimeMs);h<d&&(d=h,u=m)}}if(!u&&c.length===1&&(u=c[0]),!u){t.ambiguous_cwd++;continue}if(o.add(u.id),u.alias&&!I.isSessionAutoLinked(u.id)){t.skipped_manual++;continue}if(u.alias===a.target){I.linkSession(u.id,a.shellPid);continue}try{he(u.id,a.target),I.linkSession(u.id,a.shellPid),u.alias?t.renamed++:t.linked++,console.log(`[correlator] linked ${u.id.slice(0,8)} \u2192 "${a.target}" (live sweep, claude pid ${a.claudePid}, shell pid ${a.shellPid})`)}catch{}}return t}function jc(e,t,n){e.prepare("DELETE FROM message_usage WHERE session_id = ?").run(t);let s=e.prepare(`
974
+ `);if(u){for(let d of u.split(/\r?\n/)){let m=d.trim();m.length>=60&&m.length<=400&&s.push(m)}if(s.length>=8)break}}return s}async function Dc(e){if(Te(e))return null;let t=f().prepare("SELECT cwd, file_path FROM sessions WHERE id = ?").get(e);if(!t?.cwd||!t.file_path)return null;let n=await Bh(t.file_path);if(n.length===0)return null;let s=t.cwd.replace(/\/+$/,""),r=M.allOutputTails(),o=[];for(let[a,c]of r){let u=M.get(a);if(!u||!u.cwd||u.cwd.replace(/\/+$/,"")!==s||de(u.tab_name)||le(u.tab_name))continue;let d=0;for(let m of n)c.text.includes(m)&&d++;d>0&&o.push({shell_pid:a,tab_name:u.tab_name,matched_fingerprints:d})}return o.length===0||(o.sort((a,c)=>c.matched_fingerprints-a.matched_fingerprints),o.length>1&&o[0].matched_fingerprints===o[1].matched_fingerprints)?null:o[0]}var Hh=3e4;function Fc(){let e=Date.now(),t=M.all(),n=o=>{let a=Date.parse(o.last_seen_at);return!Number.isFinite(a)||e-a>Hh},s=new Map;for(let o of t){if(n(o)||!o.cwd||de(o.tab_name)||le(o.tab_name))continue;let a=`${o.cwd.replace(/\/+$/,"")}::${o.tab_name}`,c=s.get(a);c||(c=[],s.set(a,c)),c.push({shell_pid:o.shell_pid,tab_name:o.tab_name,cwd:o.cwd})}let r={rebound:0,ghosts:0,ambiguous:0};for(let o of t){if(!n(o))continue;let a=M.sessionsFor(o.shell_pid);if(a.length!==0){r.ghosts++;for(let c of a){let u=Te(c);if(!u)continue;let d=f().prepare("SELECT cwd FROM sessions WHERE id = ?").get(c);if(!d?.cwd)continue;let m=`${d.cwd.replace(/\/+$/,"")}::${u}`,h=s.get(m)??[];if(h.length===0)continue;if(h.length>1){r.ambiguous++;continue}let b=h[0];b.shell_pid!==o.shell_pid&&(M.unlinkSession(c),M.linkSession(c,b.shell_pid),r.rebound++)}}}return r}function Pc(){let e={resolved:0,expired:0},t=M.allDeferredLinks();for(let n of t){let s=M.get(n.parent_shell_pid);if(!s||de(s.tab_name)||le(s.tab_name))continue;let r=Te(n.session_id);if(r&&!M.isSessionAutoLinked(n.session_id)){M.resolveDeferredLink(n.session_id);continue}let o=M.getOrigin(n.session_id),a=St({tabName:s.tab_name,origin:o??null,cwd:n.cwd,gitBranch:n.git_branch});if(!a){M.resolveDeferredLink(n.session_id);continue}r!==a&&he(n.session_id,a),M.linkSession(n.session_id,n.parent_shell_pid),M.resolveDeferredLink(n.session_id),e.resolved++}return e}var Wh=6e4;async function rs(){let e=await Ph(),t={scanned:e.size,linked:0,renamed:0,skipped_manual:0,ambiguous_cwd:0};if(e.size===0)return t;let n=[];for(let[a,c]of e){let u=M.get(c);if(!u||!u.cwd||de(u.tab_name)||le(u.tab_name))continue;let d=u.tab_name.trim();if(!d)continue;let m=await Mh(a);n.push({claudePid:a,shellPid:c,cwd:u.cwd.replace(/\/+$/,""),target:d,startTimeMs:m})}let s=new Map,r=a=>{let c=s.get(a);if(c)return c;let u=Uh(a);return s.set(a,u),u},o=new Set;for(let a of n){let c=r(a.cwd).filter(d=>!o.has(d.id));if(c.length===0)continue;let u=null;if(a.startTimeMs!=null){let d=Wh;for(let m of c){if(m.started_at_ms==null)continue;let h=Math.abs(m.started_at_ms-a.startTimeMs);h<d&&(d=h,u=m)}}if(!u&&c.length===1&&(u=c[0]),!u){t.ambiguous_cwd++;continue}if(o.add(u.id),u.alias&&!M.isSessionAutoLinked(u.id)){t.skipped_manual++;continue}if(u.alias===a.target){M.linkSession(u.id,a.shellPid);continue}try{he(u.id,a.target),M.linkSession(u.id,a.shellPid),u.alias?t.renamed++:t.linked++,console.log(`[correlator] linked ${u.id.slice(0,8)} \u2192 "${a.target}" (live sweep, claude pid ${a.claudePid}, shell pid ${a.shellPid})`)}catch{}}return t}function $c(e,t,n){e.prepare("DELETE FROM message_usage WHERE session_id = ?").run(t);let s=e.prepare(`
975
975
  INSERT INTO message_usage (
976
976
  message_uuid, session_id, model,
977
977
  input_tokens, output_tokens, cache_create_tokens, cache_read_tokens,
@@ -988,7 +988,7 @@ ${o}
988
988
  cache_create_tokens = excluded.cache_create_tokens,
989
989
  cache_read_tokens = excluded.cache_read_tokens,
990
990
  timestamp = excluded.timestamp
991
- `);for(let r of n)r.usage&&r.role==="assistant"&&s.run({uuid:r.uuid,session_id:t,model:r.model,input:r.usage.inputTokens,output:r.usage.outputTokens,cc:r.usage.cacheCreateTokens,cr:r.usage.cacheReadTokens,ts:r.timestamp})}function rs(e,t){let n=e.prepare(`SELECT
991
+ `);for(let r of n)r.usage&&r.role==="assistant"&&s.run({uuid:r.uuid,session_id:t,model:r.model,input:r.usage.inputTokens,output:r.usage.outputTokens,cc:r.usage.cacheCreateTokens,cr:r.usage.cacheReadTokens,ts:r.timestamp})}function os(e,t){let n=e.prepare(`SELECT
992
992
  COALESCE(SUM(input_tokens), 0) AS input_tokens,
993
993
  COALESCE(SUM(output_tokens), 0) AS output_tokens,
994
994
  COALESCE(SUM(cache_create_tokens), 0) AS cache_create_tokens,
@@ -1003,11 +1003,11 @@ ${o}
1003
1003
  total_cache_create_tokens = @cc,
1004
1004
  total_cache_read_tokens = @cr,
1005
1005
  primary_model = @model
1006
- WHERE id = @id`).run({id:t,input:n.input_tokens,output:n.output_tokens,cc:n.cache_create_tokens,cr:n.cache_read_tokens,model:s?.model??null})}U();import{execFile as Dh}from"node:child_process";import{promisify as Fh}from"node:util";import{stat as Ph}from"node:fs/promises";var Mc=Fh(Dh),Dc=1e4,$h="%H%x09%aI%x09%s";async function Uh(e){try{let{stdout:t}=await Mc("git",["rev-parse","--is-inside-work-tree"],{cwd:e,timeout:Dc});return t.trim()==="true"}catch{return!1}}async function Bh(e,t,n){let s=["--no-pager","log","--all","--no-color","--since",t,"--until",n,`--pretty=format:${$h}`],{stdout:r}=await Mc("git",s,{cwd:e,timeout:Dc,maxBuffer:8*1024*1024}),o=[],a=new Set;for(let c of r.split(`
1007
- `)){if(!c)continue;let[u,d,...m]=c.split(" ");!u||a.has(u)||(a.add(u),o.push({commit_sha:u,committed_at:d??null,subject:m.join(" ")||null}))}return o}function Hh(e){return f().prepare(`SELECT id, cwd, started_at, ended_at
1008
- FROM sessions WHERE id = ?`).get(e)??null}function Wh(e,t,n){if(n.length===0)return 0;let s=f(),r=new Date().toISOString(),o=s.prepare(`INSERT OR IGNORE INTO session_commits
1006
+ WHERE id = @id`).run({id:t,input:n.input_tokens,output:n.output_tokens,cc:n.cache_create_tokens,cr:n.cache_read_tokens,model:s?.model??null})}B();import{execFile as qh}from"node:child_process";import{promisify as Xh}from"node:util";import{stat as Jh}from"node:fs/promises";var Uc=Xh(qh),Bc=1e4,Gh="%H%x09%aI%x09%s";async function Yh(e){try{let{stdout:t}=await Uc("git",["rev-parse","--is-inside-work-tree"],{cwd:e,timeout:Bc});return t.trim()==="true"}catch{return!1}}async function zh(e,t,n){let s=["--no-pager","log","--all","--no-color","--since",t,"--until",n,`--pretty=format:${Gh}`],{stdout:r}=await Uc("git",s,{cwd:e,timeout:Bc,maxBuffer:8*1024*1024}),o=[],a=new Set;for(let c of r.split(`
1007
+ `)){if(!c)continue;let[u,d,...m]=c.split(" ");!u||a.has(u)||(a.add(u),o.push({commit_sha:u,committed_at:d??null,subject:m.join(" ")||null}))}return o}function Kh(e){return f().prepare(`SELECT id, cwd, started_at, ended_at
1008
+ FROM sessions WHERE id = ?`).get(e)??null}function Vh(e,t,n){if(n.length===0)return 0;let s=f(),r=new Date().toISOString(),o=s.prepare(`INSERT OR IGNORE INTO session_commits
1009
1009
  (session_id, commit_sha, committed_at, subject, cwd_snapshot, correlated_at)
1010
- VALUES (?, ?, ?, ?, ?, ?)`),a=0;return s.transaction(u=>{for(let d of u)o.run(e,d.commit_sha,d.committed_at,d.subject,t,r).changes>0&&(a+=1)})(n),a}async function Qr(e){let t=Hh(e);if(!t)return{sessionId:e,status:"error",commitsFound:0,commitsInserted:0,error:"session not found"};if(!t.cwd)return{sessionId:e,status:"no-cwd",commitsFound:0,commitsInserted:0};if(!t.started_at||!t.ended_at)return{sessionId:e,status:"no-window",commitsFound:0,commitsInserted:0};let n=t.started_at,s=t.ended_at===t.started_at?new Date(Date.parse(t.ended_at)+1e3).toISOString():t.ended_at;try{if(!(await Ph(t.cwd)).isDirectory())return{sessionId:e,status:"cwd-missing",commitsFound:0,commitsInserted:0}}catch{return{sessionId:e,status:"cwd-missing",commitsFound:0,commitsInserted:0}}if(!await Uh(t.cwd))return{sessionId:e,status:"not-a-repo",commitsFound:0,commitsInserted:0};try{let o=await Bh(t.cwd,n,s),a=Wh(e,t.cwd,o);return{sessionId:e,status:"ok",commitsFound:o.length,commitsInserted:a}}catch(o){return{sessionId:e,status:"error",commitsFound:0,commitsInserted:0,error:o.message}}}function os(e){let t=f(),n=e.trim();if(!/^[0-9a-fA-F]{4,40}$/.test(n))return[];let s=`${n.toLowerCase()}%`;return t.prepare(`SELECT sc.session_id AS sessionId,
1010
+ VALUES (?, ?, ?, ?, ?, ?)`),a=0;return s.transaction(u=>{for(let d of u)o.run(e,d.commit_sha,d.committed_at,d.subject,t,r).changes>0&&(a+=1)})(n),a}async function eo(e){let t=Kh(e);if(!t)return{sessionId:e,status:"error",commitsFound:0,commitsInserted:0,error:"session not found"};if(!t.cwd)return{sessionId:e,status:"no-cwd",commitsFound:0,commitsInserted:0};if(!t.started_at||!t.ended_at)return{sessionId:e,status:"no-window",commitsFound:0,commitsInserted:0};let n=t.started_at,s=t.ended_at===t.started_at?new Date(Date.parse(t.ended_at)+1e3).toISOString():t.ended_at;try{if(!(await Jh(t.cwd)).isDirectory())return{sessionId:e,status:"cwd-missing",commitsFound:0,commitsInserted:0}}catch{return{sessionId:e,status:"cwd-missing",commitsFound:0,commitsInserted:0}}if(!await Yh(t.cwd))return{sessionId:e,status:"not-a-repo",commitsFound:0,commitsInserted:0};try{let o=await zh(t.cwd,n,s),a=Vh(e,t.cwd,o);return{sessionId:e,status:"ok",commitsFound:o.length,commitsInserted:a}}catch(o){return{sessionId:e,status:"error",commitsFound:0,commitsInserted:0,error:o.message}}}function is(e){let t=f(),n=e.trim();if(!/^[0-9a-fA-F]{4,40}$/.test(n))return[];let s=`${n.toLowerCase()}%`;return t.prepare(`SELECT sc.session_id AS sessionId,
1011
1011
  NULLIF(sa.alias, '') AS alias,
1012
1012
  p.name AS project,
1013
1013
  s.started_at AS startedAt,
@@ -1021,18 +1021,18 @@ ${o}
1021
1021
  LEFT JOIN session_aliases sa ON sa.session_id = sc.session_id
1022
1022
  WHERE lower(sc.commit_sha) = lower(?)
1023
1023
  OR lower(sc.commit_sha) LIKE ?
1024
- ORDER BY COALESCE(sc.committed_at, s.started_at, '') DESC`).all(n,s)}function eo(e){return f().prepare(`SELECT commit_sha, committed_at, subject, correlated_at
1024
+ ORDER BY COALESCE(sc.committed_at, s.started_at, '') DESC`).all(n,s)}function to(e){return f().prepare(`SELECT commit_sha, committed_at, subject, correlated_at
1025
1025
  FROM session_commits
1026
1026
  WHERE session_id = ?
1027
- ORDER BY COALESCE(committed_at, correlated_at) ASC`).all(e)}var qh=3e4;function Fc(e){try{let n=f().prepare(`SELECT MAX(correlated_at) AS last_at
1028
- FROM session_commits WHERE session_id = ?`).get(e),s=n?.last_at?Date.parse(n.last_at):0;if(s&&Date.now()-s<qh)return}catch{}Qr(e).catch(t=>{console.error(`[git-correlator] ${e.slice(0,8)} failed:`,t)})}U();ee();import{writeFileSync as Vh,mkdirSync as Zh,existsSync as Qh}from"node:fs";import{join as Yc}from"node:path";U();var Pc=80;function $c(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(`
1029
- `)[0].trim();return n.length>Pc?n.slice(0,Pc)+"\u2026":n}function Xh(e){return f().prepare(`SELECT s.id AS id,
1027
+ ORDER BY COALESCE(committed_at, correlated_at) ASC`).all(e)}var Zh=3e4;function Hc(e){try{let n=f().prepare(`SELECT MAX(correlated_at) AS last_at
1028
+ FROM session_commits WHERE session_id = ?`).get(e),s=n?.last_at?Date.parse(n.last_at):0;if(s&&Date.now()-s<Zh)return}catch{}eo(e).catch(t=>{console.error(`[git-correlator] ${e.slice(0,8)} failed:`,t)})}B();ee();import{writeFileSync as oE,mkdirSync as iE,existsSync as aE}from"node:fs";import{join as Zc}from"node:path";B();var Wc=80;function qc(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(`
1029
+ `)[0].trim();return n.length>Wc?n.slice(0,Wc)+"\u2026":n}function Qh(e){return f().prepare(`SELECT s.id AS id,
1030
1030
  sa.alias AS alias,
1031
1031
  s.auto_title AS auto_title,
1032
1032
  s.first_user_message AS first_user_message
1033
1033
  FROM sessions s
1034
1034
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1035
- WHERE s.id = ?`).get(e)??null}function Jh(e){let t=Xh(e);return t?$c(t):e.slice(0,8)}function Uc(e){if(!e)return null;let t=f(),n=t.prepare(`SELECT e.thread_id AS thread_id,
1035
+ WHERE s.id = ?`).get(e)??null}function eE(e){let t=Qh(e);return t?qc(t):e.slice(0,8)}function Xc(e){if(!e)return null;let t=f(),n=t.prepare(`SELECT e.thread_id AS thread_id,
1036
1036
  t.name AS thread_name,
1037
1037
  e.parent_session_id AS parent_session_id,
1038
1038
  e.added_at AS added_at
@@ -1041,7 +1041,7 @@ ${o}
1041
1041
  WHERE e.session_id = ?
1042
1042
  AND t.archived = 0
1043
1043
  ORDER BY e.added_at DESC
1044
- LIMIT 1`).get(e);if(!n)return null;let s=n.parent_session_id?{id:n.parent_session_id,title:Jh(n.parent_session_id)}:null,r=n.parent_session_id?[e,n.parent_session_id]:[e],o=r.map(()=>"?").join(", "),c=t.prepare(`SELECT e.session_id AS session_id,
1044
+ LIMIT 1`).get(e);if(!n)return null;let s=n.parent_session_id?{id:n.parent_session_id,title:eE(n.parent_session_id)}:null,r=n.parent_session_id?[e,n.parent_session_id]:[e],o=r.map(()=>"?").join(", "),c=t.prepare(`SELECT e.session_id AS session_id,
1045
1045
  s.id AS id,
1046
1046
  sa.alias AS alias,
1047
1047
  s.auto_title AS auto_title,
@@ -1051,9 +1051,9 @@ ${o}
1051
1051
  LEFT JOIN session_aliases sa ON sa.session_id = e.session_id
1052
1052
  WHERE e.thread_id = ?
1053
1053
  AND e.session_id NOT IN (${o})
1054
- ORDER BY e.added_at ASC`).all(n.thread_id,...r).map(u=>({id:u.session_id,title:u.id?$c(u):u.session_id.slice(0,8)}));return{thread_id:n.thread_id,thread_name:n.thread_name,parent_session:s,siblings:c}}var Bc=[/^You will receive a sample of user messages from a Claude Cod/i,/^You will receive the first \d+ user messages from a Claude/i,/^Base directory for this skill:/i,/^You are Claude Code in a fresh terminal/i,/^You are extracting a structured Output Index from a Claude/i];function to(e){return Bc.some(t=>t.test(e))}var Yh=[/^You are summarizing a Claude Code session/i,/^You are extracting a structured Output Index from a Claude/i,/^You will receive a sample of user messages from a Claude Cod/i,/^You will receive the first \d+ user messages from a Claude/i,/^Thread context:\n- This session is part of thread/i];function Hc(e){return e?Yh.some(t=>t.test(e)):!1}var Gh=[/^Score this person'?s relevance/i,/^You are a [^\n.]{1,60}co-pilot/i,/^Return ONLY valid JSON/i,/^You are summarizing a Claude Code session/i],zh=[/^Draft (a|an|marketing) [a-z]/i,/^Read the file at /i,/^Read this and then begin/i,/^read this and then begin/i],Kh=20;function tn(e){if(e.auto_title_source==="agent"&&e.auto_title)return"agent";if(e.has_alias)return"manual_alias";if(e.auto_title&&e.auto_title.includes(" \xB7 "))return"fixed_v0.16.1";if(!e.auto_title||e.auto_title.length<Kh)return"low_signal";for(let t of Bc)if(t.test(e.auto_title))return"recursive_meta";for(let t of Gh)if(t.test(e.auto_title))return"programmatic";for(let t of zh)if(t.test(e.auto_title))return"template_pending";return"clean"}function is(e){if(!e)return"";let t=e.split("|")[0];return t=t.replace(/\s*\([^)]*\)\s*$/,""),t=t.replace(/\s+/g," ").trim(),t}function Wc(e){if(!e)return e;let t=e.lastIndexOf(" \xB7 ");if(t===-1)return e;let n=e.slice(0,t),s=e.slice(t+3),r=is(s);return!r||r===s?e:`${n} \xB7 ${r}`}var ro=Yc(H,"titles"),eE=80,tE=60,nE=100,sE=50,nn=5,as=15,rE=500;function Gc(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 yt(e){if(!e)return null;let t=e;if(t=t.replace(/```[\s\S]*?```/g," "),t=t.replace(/`[^`]+`/g," "),t=t.replace(/https?:\/\/\S+/g,"[url]"),t=t.replace(/\s+/g," ").trim(),!t)return null;let n=oE(t,e);if(n)return n;let s=t.match(/^[^.!?\n]{8,}?[.!?]/)?.[0]?.trim();return(s&&s.length<=eE?s:t.slice(0,tE)).trim()||null}function oE(e,t){let n=e.match(/^\/([A-Za-z0-9][A-Za-z0-9_-]*)\s+([\s\S]*)$/);if(n){let s=`/${n[1]}`,r=t.replace(/^\s*\/[A-Za-z0-9][A-Za-z0-9_-]*\s+/,""),o=oo(r);return o?Tt(`${s} \xB7 ${o}`):s}for(let s of iE){if(!e.match(s.match))continue;let o=s.prefix,a=s.extract?s.extract(e,t):oo(t);return a?s.completeFromExtract?Tt(a):Tt(`${o} \xB7 ${a}`):o}for(let s of lE){if(!e.match(s.match))continue;let o=s.extract?s.extract(e,t):cs(t);return o?s.completeFromExtract?Tt(o):Tt(`${s.prefix} \xB7 ${o}`):s.prefix}return null}var iE=[{match:/^Draft (?:a|an) brand brief\b/i,prefix:"Draft brand brief"},{match:/^Draft (?:a|an) sales brief\b/i,prefix:"Draft sales brief"},{match:/^Draft (?:a|an) leave-behind\b/i,prefix:"Draft leave-behind"},{match:/^Draft (?:a|an) audio identity brief\b/i,prefix:"Draft audio identity brief"},{match:/^Draft marketing ideas\b/i,prefix:"Draft marketing ideas"},{match:/^Draft (?:a|an) ([a-z]{3,30}(?:\s+[a-z]{3,30}){0,2})\b/i,prefix:"Draft",extract:(e,t)=>{let s=e.match(/^Draft (?:a|an) ([a-z]{3,30}(?:\s+[a-z]{3,30}){0,2})\b/i)?.[1]?.trim(),r=oo(t);return s&&r?`${s} \xB7 ${r}`:s||r}},{match:/^Read the file at /i,prefix:"Read",extract:e=>{let n=e.match(/^Read the file at\s+([^\s]+)/i)?.[1];return n?n.split("/").filter(Boolean).slice(-2).join("/")||n:null}},{match:/^(?:read|inspect) this and then begin\b/i,prefix:"Begin from preamble",completeFromExtract:!0,extract:(e,t)=>cE(t)},{match:/^Base directory for this skill:/i,prefix:"[skill]",completeFromExtract:!0,extract:(e,t)=>{let n=t.match(/\.claude\/skills\/([^/\s]+)/);return n?.[1]?`[skill] ${n[1]}`:null}},{match:/^You are extracting a structured Output Index/i,prefix:"[output-index]",completeFromExtract:!0,extract:(e,t)=>aE(t)},{match:/^You will receive a sample of user messages from a Claude Code session:/i,prefix:"[meta]",completeFromExtract:!0,extract:(e,t)=>qc(t,"[meta] auto-title (full-arc)")},{match:/^You will receive the first \d+ user messages from a Claude Code session/i,prefix:"[meta]",completeFromExtract:!0,extract:(e,t)=>qc(t,"[meta] auto-title (initial)")},{match:/^You are implementing v\d+\.\d+/i,prefix:"Implementing",completeFromExtract:!0,extract:e=>{let t=e.match(/^You are implementing (v\d+\.\d+\w*)\s*(?:\(([^)]+)\))?/i);if(!t)return null;let n=t[1],s=t[2]?.trim();return s?`Implementing ${n} \xB7 ${s}`:`Implementing ${n}`}}];function aE(e){if(!e)return"[output-index] extractor";let t=e.match(/^Session:\s*([0-9a-f]{8})\b/im),n=e.match(/^Opening prompt:\s*([^\n]{1,140})/im),s=t?.[1]?.trim(),r=n?.[1]?.trim().replace(/\s+/g," "),o=r&&r.length>70?r.slice(0,67)+"\u2026":r;return s&&o?`[output-index] \xB7 ${s} \xB7 ${o}`:s?`[output-index] \xB7 ${s}`:o?`[output-index] \xB7 ${o}`:"[output-index] extractor"}function qc(e,t){if(!e)return t;let n=e.indexOf("Messages:");if(n===-1)return t;let s=e.slice(n+9),r=/^\s*\d+\.\s*([^\n]+)/gm;for(let o of s.matchAll(r)){let a=o[1]?.trim()??"";if(!a)continue;let c=a.replace(/^<[^>]+>[\s\S]*?<\/[^>]+>\s*/g,"").replace(/^\[Pasted text[^\]]*\]\s*/i,"").trim();if(!c||/^<local-command-/.test(c))continue;let u=c.length>60?c.slice(0,57)+"\u2026":c;return`${t} \xB7 ${u}`}return t}function cE(e){if(!e)return null;let t=e.match(/([\/\w.\-]+\.(?:md|markdown|txt|json|yaml|yml|toml|ts|tsx|js|jsx|py|sql))(?=[\s,;:)\]"'`]|$)/i);if(!t)return null;let n=t[1].split("/").filter(Boolean);return(n[n.length-1]??"").replace(/\.[^.]+$/,"")||null}var lE=[{match:/^Score this person'?s relevance/i,prefix:"Score relevance",extract:(e,t)=>cs(t)},{match:/^You are a [^\n.]{1,60}co-pilot/i,prefix:"co-pilot",completeFromExtract:!0,extract:(e,t)=>{let s=e.match(/^You are a ([^\n.]{1,60}?)co-pilot/i)?.[1]?.trim(),r=s?`${s} co-pilot`:"co-pilot",o=cs(t);return o?`${r} \xB7 ${o}`:r}},{match:/^Return ONLY valid JSON/i,prefix:"JSON-only",extract:(e,t)=>cs(t)}];function cs(e){let t=/^\s*(Name|Company|Prospect|Author|Brand|Client)\s*:\s*([^\n]+)/gim,n;for(;(n=t.exec(e))!==null;){let s=n[2].trim();if(!s||/^(null|none|n\/a|—|-)$/i.test(s))continue;let r=s.replace(/\s+/g," ");return is(r)||r}return null}function Tt(e){return e.slice(0,nE).trim()}var uE=[/^deep research$/i,/^reference(?: spec)?$/i,/^canonical spec/i,/^product context/i,/^services?(?: overview)?$/i,/^overview$/i,/^(?:introduction|template|instructions|context)$/i],dE=[/^(?:brand|brand brief|brand summary)$/i,/^(?:known facts?|facts)$/i,/^(?:client|prospect|customer|account)$/i,/^(?:topic|subject|brief|task)$/i,/^(?:about|for|re)$/i];function no(e){let t=e.trim();return t.length<3?!0:uE.some(n=>n.test(t))}function pE(e){let t=e.trim().replace(/\s*\([^)]*\)\s*$/,"").trim();return dE.some(n=>n.test(t))}function oo(e){let t=mE(e);return t===null?null:is(t)||t}function mE(e){if(/^\s*Skill smoke test\b/i.test(e))return"smoke test";let t=/(^|\n)#{1,3}\s+([^\n]+?)\s+(?:—|–|-|:)\s+([^\n]{2,80})/g,n,s=[];for(;(n=t.exec(e))!==null;){let u=n[2].trim(),d=n[3].trim().replace(/\s+/g," ");if(!no(d)){if(pE(u))return d;s.push(d)}}if(s.length>0)return s[0];let r=e.match(/\b(?:Topic|Subject|Brand|About|Client|For|Re)\s*:\s*([^\n]{2,80})/i);if(r?.[1]&&!no(r[1]))return r[1].trim().replace(/\s+/g," ");let o=/===\s*([^=\n]{2,120}?)\s*===/g;for(;(n=o.exec(e))!==null;){let u=n[1].trim().replace(/\.(md|txt|json)$/i,""),d=u.replace(/\s*\([^)]*\)\s*$/,"").trim();if(d&&!no(d)&&!/product context|reference/i.test(u))return d}let a=e.replace(/^Context for this run[^:]*:\s*/i,"");if(a!==e){let u=a.split(`
1054
+ ORDER BY e.added_at ASC`).all(n.thread_id,...r).map(u=>({id:u.session_id,title:u.id?qc(u):u.session_id.slice(0,8)}));return{thread_id:n.thread_id,thread_name:n.thread_name,parent_session:s,siblings:c}}var Jc=[/^You will receive a sample of user messages from a Claude Cod/i,/^You will receive the first \d+ user messages from a Claude/i,/^Base directory for this skill:/i,/^You are Claude Code in a fresh terminal/i,/^You are extracting a structured Output Index from a Claude/i];function no(e){return Jc.some(t=>t.test(e))}var tE=[/^You are summarizing a Claude Code session/i,/^You are extracting a structured Output Index from a Claude/i,/^You will receive a sample of user messages from a Claude Cod/i,/^You will receive the first \d+ user messages from a Claude/i,/^Thread context:\n- This session is part of thread/i];function Gc(e){return e?tE.some(t=>t.test(e)):!1}var nE=[/^Score this person'?s relevance/i,/^You are a [^\n.]{1,60}co-pilot/i,/^Return ONLY valid JSON/i,/^You are summarizing a Claude Code session/i],sE=[/^Draft (a|an|marketing) [a-z]/i,/^Read the file at /i,/^Read this and then begin/i,/^read this and then begin/i],rE=20;function tn(e){if(e.auto_title_source==="agent"&&e.auto_title)return"agent";if(e.has_alias)return"manual_alias";if(e.auto_title&&e.auto_title.includes(" \xB7 "))return"fixed_v0.16.1";if(!e.auto_title||e.auto_title.length<rE)return"low_signal";for(let t of Jc)if(t.test(e.auto_title))return"recursive_meta";for(let t of nE)if(t.test(e.auto_title))return"programmatic";for(let t of sE)if(t.test(e.auto_title))return"template_pending";return"clean"}function as(e){if(!e)return"";let t=e.split("|")[0];return t=t.replace(/\s*\([^)]*\)\s*$/,""),t=t.replace(/\s+/g," ").trim(),t}function Yc(e){if(!e)return e;let t=e.lastIndexOf(" \xB7 ");if(t===-1)return e;let n=e.slice(0,t),s=e.slice(t+3),r=as(s);return!r||r===s?e:`${n} \xB7 ${r}`}var oo=Zc(W,"titles"),cE=80,lE=60,uE=100,dE=50,nn=5,cs=15,pE=500;function Qc(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 yt(e){if(!e)return null;let t=e;if(t=t.replace(/```[\s\S]*?```/g," "),t=t.replace(/`[^`]+`/g," "),t=t.replace(/https?:\/\/\S+/g,"[url]"),t=t.replace(/\s+/g," ").trim(),!t)return null;let n=mE(t,e);if(n)return n;let s=t.match(/^[^.!?\n]{8,}?[.!?]/)?.[0]?.trim();return(s&&s.length<=cE?s:t.slice(0,lE)).trim()||null}function mE(e,t){let n=e.match(/^\/([A-Za-z0-9][A-Za-z0-9_-]*)\s+([\s\S]*)$/);if(n){let s=`/${n[1]}`,r=t.replace(/^\s*\/[A-Za-z0-9][A-Za-z0-9_-]*\s+/,""),o=io(r);return o?Tt(`${s} \xB7 ${o}`):s}for(let s of gE){if(!e.match(s.match))continue;let o=s.prefix,a=s.extract?s.extract(e,t):io(t);return a?s.completeFromExtract?Tt(a):Tt(`${o} \xB7 ${a}`):o}for(let s of hE){if(!e.match(s.match))continue;let o=s.extract?s.extract(e,t):ls(t);return o?s.completeFromExtract?Tt(o):Tt(`${s.prefix} \xB7 ${o}`):s.prefix}return null}var gE=[{match:/^Draft (?:a|an) brand brief\b/i,prefix:"Draft brand brief"},{match:/^Draft (?:a|an) sales brief\b/i,prefix:"Draft sales brief"},{match:/^Draft (?:a|an) leave-behind\b/i,prefix:"Draft leave-behind"},{match:/^Draft (?:a|an) audio identity brief\b/i,prefix:"Draft audio identity brief"},{match:/^Draft marketing ideas\b/i,prefix:"Draft marketing ideas"},{match:/^Draft (?:a|an) ([a-z]{3,30}(?:\s+[a-z]{3,30}){0,2})\b/i,prefix:"Draft",extract:(e,t)=>{let s=e.match(/^Draft (?:a|an) ([a-z]{3,30}(?:\s+[a-z]{3,30}){0,2})\b/i)?.[1]?.trim(),r=io(t);return s&&r?`${s} \xB7 ${r}`:s||r}},{match:/^Read the file at /i,prefix:"Read",extract:e=>{let n=e.match(/^Read the file at\s+([^\s]+)/i)?.[1];return n?n.split("/").filter(Boolean).slice(-2).join("/")||n:null}},{match:/^(?:read|inspect) this and then begin\b/i,prefix:"Begin from preamble",completeFromExtract:!0,extract:(e,t)=>fE(t)},{match:/^Base directory for this skill:/i,prefix:"[skill]",completeFromExtract:!0,extract:(e,t)=>{let n=t.match(/\.claude\/skills\/([^/\s]+)/);return n?.[1]?`[skill] ${n[1]}`:null}},{match:/^You are extracting a structured Output Index/i,prefix:"[output-index]",completeFromExtract:!0,extract:(e,t)=>_E(t)},{match:/^You will receive a sample of user messages from a Claude Code session:/i,prefix:"[meta]",completeFromExtract:!0,extract:(e,t)=>zc(t,"[meta] auto-title (full-arc)")},{match:/^You will receive the first \d+ user messages from a Claude Code session/i,prefix:"[meta]",completeFromExtract:!0,extract:(e,t)=>zc(t,"[meta] auto-title (initial)")},{match:/^You are implementing v\d+\.\d+/i,prefix:"Implementing",completeFromExtract:!0,extract:e=>{let t=e.match(/^You are implementing (v\d+\.\d+\w*)\s*(?:\(([^)]+)\))?/i);if(!t)return null;let n=t[1],s=t[2]?.trim();return s?`Implementing ${n} \xB7 ${s}`:`Implementing ${n}`}}];function _E(e){if(!e)return"[output-index] extractor";let t=e.match(/^Session:\s*([0-9a-f]{8})\b/im),n=e.match(/^Opening prompt:\s*([^\n]{1,140})/im),s=t?.[1]?.trim(),r=n?.[1]?.trim().replace(/\s+/g," "),o=r&&r.length>70?r.slice(0,67)+"\u2026":r;return s&&o?`[output-index] \xB7 ${s} \xB7 ${o}`:s?`[output-index] \xB7 ${s}`:o?`[output-index] \xB7 ${o}`:"[output-index] extractor"}function zc(e,t){if(!e)return t;let n=e.indexOf("Messages:");if(n===-1)return t;let s=e.slice(n+9),r=/^\s*\d+\.\s*([^\n]+)/gm;for(let o of s.matchAll(r)){let a=o[1]?.trim()??"";if(!a)continue;let c=a.replace(/^<[^>]+>[\s\S]*?<\/[^>]+>\s*/g,"").replace(/^\[Pasted text[^\]]*\]\s*/i,"").trim();if(!c||/^<local-command-/.test(c))continue;let u=c.length>60?c.slice(0,57)+"\u2026":c;return`${t} \xB7 ${u}`}return t}function fE(e){if(!e)return null;let t=e.match(/([\/\w.\-]+\.(?:md|markdown|txt|json|yaml|yml|toml|ts|tsx|js|jsx|py|sql))(?=[\s,;:)\]"'`]|$)/i);if(!t)return null;let n=t[1].split("/").filter(Boolean);return(n[n.length-1]??"").replace(/\.[^.]+$/,"")||null}var hE=[{match:/^Score this person'?s relevance/i,prefix:"Score relevance",extract:(e,t)=>ls(t)},{match:/^You are a [^\n.]{1,60}co-pilot/i,prefix:"co-pilot",completeFromExtract:!0,extract:(e,t)=>{let s=e.match(/^You are a ([^\n.]{1,60}?)co-pilot/i)?.[1]?.trim(),r=s?`${s} co-pilot`:"co-pilot",o=ls(t);return o?`${r} \xB7 ${o}`:r}},{match:/^Return ONLY valid JSON/i,prefix:"JSON-only",extract:(e,t)=>ls(t)}];function ls(e){let t=/^\s*(Name|Company|Prospect|Author|Brand|Client)\s*:\s*([^\n]+)/gim,n;for(;(n=t.exec(e))!==null;){let s=n[2].trim();if(!s||/^(null|none|n\/a|—|-)$/i.test(s))continue;let r=s.replace(/\s+/g," ");return as(r)||r}return null}function Tt(e){return e.slice(0,uE).trim()}var EE=[/^deep research$/i,/^reference(?: spec)?$/i,/^canonical spec/i,/^product context/i,/^services?(?: overview)?$/i,/^overview$/i,/^(?:introduction|template|instructions|context)$/i],bE=[/^(?:brand|brand brief|brand summary)$/i,/^(?:known facts?|facts)$/i,/^(?:client|prospect|customer|account)$/i,/^(?:topic|subject|brief|task)$/i,/^(?:about|for|re)$/i];function so(e){let t=e.trim();return t.length<3?!0:EE.some(n=>n.test(t))}function SE(e){let t=e.trim().replace(/\s*\([^)]*\)\s*$/,"").trim();return bE.some(n=>n.test(t))}function io(e){let t=TE(e);return t===null?null:as(t)||t}function TE(e){if(/^\s*Skill smoke test\b/i.test(e))return"smoke test";let t=/(^|\n)#{1,3}\s+([^\n]+?)\s+(?:—|–|-|:)\s+([^\n]{2,80})/g,n,s=[];for(;(n=t.exec(e))!==null;){let u=n[2].trim(),d=n[3].trim().replace(/\s+/g," ");if(!so(d)){if(SE(u))return d;s.push(d)}}if(s.length>0)return s[0];let r=e.match(/\b(?:Topic|Subject|Brand|About|Client|For|Re)\s*:\s*([^\n]{2,80})/i);if(r?.[1]&&!so(r[1]))return r[1].trim().replace(/\s+/g," ");let o=/===\s*([^=\n]{2,120}?)\s*===/g;for(;(n=o.exec(e))!==null;){let u=n[1].trim().replace(/\.(md|txt|json)$/i,""),d=u.replace(/\s*\([^)]*\)\s*$/,"").trim();if(d&&!so(d)&&!/product context|reference/i.test(u))return d}let a=e.replace(/^Context for this run[^:]*:\s*/i,"");if(a!==e){let u=a.split(`
1055
1055
  `).map(d=>d.trim()).find(d=>d.length>=4);if(u)return u.slice(0,60)}let c=e.split(`
1056
- `).map(u=>u.trim()).find(u=>u.length>=4);return c?c.slice(0,60):null}function io(e){let t=f(),n=t.prepare(`SELECT rowid AS rid, content_text
1056
+ `).map(u=>u.trim()).find(u=>u.length>=4);return c?c.slice(0,60):null}function ao(e){let t=f(),n=t.prepare(`SELECT rowid AS rid, content_text
1057
1057
  FROM messages
1058
1058
  WHERE session_id = ? AND role = 'user' AND is_sidechain = 0
1059
1059
  AND content_text IS NOT NULL AND content_text != ''
@@ -1063,21 +1063,21 @@ ${o}
1063
1063
  WHERE session_id = ? AND role = 'user' AND is_sidechain = 0
1064
1064
  AND content_text IS NOT NULL AND content_text != ''
1065
1065
  ORDER BY COALESCE(timestamp, '') DESC, rowid DESC
1066
- LIMIT ?`).all(e,as),r=new Map;for(let m of n)r.set(m.rid,m.content_text);for(let m of s)r.set(m.rid,m.content_text);if(r.size===0)throw new Error("no user messages available to summarise");let o=Array.from(r.entries()).sort((m,h)=>m[0]-h[0]).map(([,m])=>({content_text:m})),a=n.length===nn&&s.length===as&&r.size===nn+as,c=o.map((m,h)=>{let S=(m.content_text??"").slice(0,rE);return a&&h===nn?`--- (middle of session omitted) ---
1067
- ${h+1}. ${S}`:`${h+1}. ${S}`}).join(`
1068
- `),u=null;try{u=Uc(e)}catch(m){console.error("[autoTitle] thread context resolution failed:",m),u=null}let d=[];return u&&(d.push(gE(u)),d.push("")),d.push(`You will receive a sample of user messages from a Claude Code session: the first ${nn}`,`messages (initial intent) and the last ${as} 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:",c),d.join(`
1069
- `)}var so=5;function gE(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,so).map(a=>`"${a.title}"`).join(", "),o=n>so?`, and ${n-so} 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(`
1070
- `)}async function zc(e){let t=io(e),{spawnClaudePrompt:n,isClaudeCliAvailable:s}=await Promise.resolve().then(()=>(ye(),tt));if(!s())throw new Error("claude CLI not found on PATH");let r=await n(t,[],{});if(!r.success)throw new Error(`claude CLI exited ${r.exitCode}: ${r.stderr.slice(-500)}`);let o=_E(r.stdout);if(!o)throw new Error("claude CLI returned an empty title");return o.slice(0,sE)}function _E(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 Xc(s)}}catch{}return Xc(t)}function Xc(e){return e.trim().replace(/^["'`]+|["'`]+$/g,"").replace(/\s+/g," ").replace(/[.!?]+$/g,"").trim()}function Ee(e,t,n){let s=t.trim();if(!s)return;let r=f(),o=r.prepare(`SELECT auto_title, auto_title_source, auto_title_generated_at, auto_title_history
1071
- 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 a=Gc(o.auto_title_history),c=new Date().toISOString();o.auto_title&&o.auto_title_source&&a.push({title:o.auto_title,source:o.auto_title_source,replaced_at:c}),r.prepare(`UPDATE sessions
1066
+ LIMIT ?`).all(e,cs),r=new Map;for(let m of n)r.set(m.rid,m.content_text);for(let m of s)r.set(m.rid,m.content_text);if(r.size===0)throw new Error("no user messages available to summarise");let o=Array.from(r.entries()).sort((m,h)=>m[0]-h[0]).map(([,m])=>({content_text:m})),a=n.length===nn&&s.length===cs&&r.size===nn+cs,c=o.map((m,h)=>{let b=(m.content_text??"").slice(0,pE);return a&&h===nn?`--- (middle of session omitted) ---
1067
+ ${h+1}. ${b}`:`${h+1}. ${b}`}).join(`
1068
+ `),u=null;try{u=Xc(e)}catch(m){console.error("[autoTitle] thread context resolution failed:",m),u=null}let d=[];return u&&(d.push(yE(u)),d.push("")),d.push(`You will receive a sample of user messages from a Claude Code session: the first ${nn}`,`messages (initial intent) and the last ${cs} 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:",c),d.join(`
1069
+ `)}var ro=5;function yE(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,ro).map(a=>`"${a.title}"`).join(", "),o=n>ro?`, and ${n-ro} 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(`
1070
+ `)}async function el(e){let t=ao(e),{spawnClaudePrompt:n,isClaudeCliAvailable:s}=await Promise.resolve().then(()=>(ye(),et));if(!s())throw new Error("claude CLI not found on PATH");let r=await n(t,[],{});if(!r.success)throw new Error(`claude CLI exited ${r.exitCode}: ${r.stderr.slice(-500)}`);let o=wE(r.stdout);if(!o)throw new Error("claude CLI returned an empty title");return o.slice(0,dE)}function wE(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 Kc(s)}}catch{}return Kc(t)}function Kc(e){return e.trim().replace(/^["'`]+|["'`]+$/g,"").replace(/\s+/g," ").replace(/[.!?]+$/g,"").trim()}function Ee(e,t,n){let s=t.trim();if(!s)return;let r=f(),o=r.prepare(`SELECT auto_title, auto_title_source, auto_title_generated_at, auto_title_history
1071
+ 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 a=Qc(o.auto_title_history),c=new Date().toISOString();o.auto_title&&o.auto_title_source&&a.push({title:o.auto_title,source:o.auto_title_source,replaced_at:c}),r.prepare(`UPDATE sessions
1072
1072
  SET auto_title = ?,
1073
1073
  auto_title_source = ?,
1074
1074
  auto_title_generated_at = ?,
1075
1075
  auto_title_history = ?
1076
- WHERE id = ?`).run(s,n,Date.now(),JSON.stringify(a),e),bE(e,s,n,c)}function Le(e){let t=f().prepare(`SELECT auto_title, auto_title_source, auto_title_generated_at, auto_title_history
1077
- 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:Gc(t.auto_title_history)}:null}function Kc(){let t=f().prepare(`SELECT id, first_user_message
1076
+ WHERE id = ?`).run(s,n,Date.now(),JSON.stringify(a),e),xE(e,s,n,c)}function Le(e){let t=f().prepare(`SELECT auto_title, auto_title_source, auto_title_generated_at, auto_title_history
1077
+ 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:Qc(t.auto_title_history)}:null}function tl(){let t=f().prepare(`SELECT id, first_user_message
1078
1078
  FROM sessions
1079
1079
  WHERE auto_title IS NULL
1080
- AND first_user_message IS NOT NULL`).all(),n=0;for(let s of t){let r=yt(s.first_user_message);r&&(Ee(s.id,r,"heuristic"),n+=1)}return{updated:n}}function Vc(e){let t=f(),n=e?.projectId?" AND s.project_id = ?":"",s=e?.projectId?[e.projectId,e.projectId]:[],r=t.prepare(`WITH dups AS (
1080
+ AND first_user_message IS NOT NULL`).all(),n=0;for(let s of t){let r=yt(s.first_user_message);r&&(Ee(s.id,r,"heuristic"),n+=1)}return{updated:n}}function nl(e){let t=f(),n=e?.projectId?" AND s.project_id = ?":"",s=e?.projectId?[e.projectId,e.projectId]:[],r=t.prepare(`WITH dups AS (
1081
1081
  SELECT auto_title, project_id
1082
1082
  FROM sessions
1083
1083
  WHERE auto_title IS NOT NULL
@@ -1130,7 +1130,7 @@ ${h+1}. ${S}`:`${h+1}. ${S}`}).join(`
1130
1130
  AND content_text IS NOT NULL
1131
1131
  AND content_text != ''
1132
1132
  ORDER BY COALESCE(timestamp, ''), rowid ASC
1133
- LIMIT 8`),a=0,c=0;for(let u of r){a+=1;let d=o.all(u.id),m=null;for(let h of d){let S=h.content_text.replace(/^(?:<[^>]+>[\s\S]*?<\/[^>]+>\s*)+/,"").trim();if(!S||/^<local-command-caveat>/.test(S))continue;let b=yt(S);if(b&&!Jc(b)){m=b;break}}if(!m){let h=d.map(b=>b.content_text.replace(/^(?:<[^>]+>[\s\S]*?<\/[^>]+>\s*)+/,"").trim()).find(b=>b.length>0&&!/^<local-command-caveat>/.test(b)),S=h?yt(h):null;S&&Jc(S)&&(m=`[vacuous] ${S}`)}m&&(Ee(u.id,m,"heuristic"),c+=1)}return{scanned:a,updated:c}}function Jc(e){let t=e.trim();return!t||/^\*\*Tool result\*\*$/i.test(t)?!0:[/^all right\.?$/i,/^alright\.?$/i,/^inspect this\.?$/i,/^resolve this\.?$/i,/^do it\.?$/i,/^go\.?$/i,/^continue\.?$/i,/^proceed\.?$/i,/^keep going\.?$/i,/^ok\.?$/i,/^okay\.?$/i,/^yes\.?$/i,/^yep\.?$/i].some(s=>s.test(t))}function Zc(e){let t=f(),n=e?.projectId?" AND s.project_id = ?":"",s=e?.projectId?[e.projectId]:[],r=t.prepare(`SELECT s.id, s.auto_title
1133
+ LIMIT 8`),a=0,c=0;for(let u of r){a+=1;let d=o.all(u.id),m=null;for(let h of d){let b=h.content_text.replace(/^(?:<[^>]+>[\s\S]*?<\/[^>]+>\s*)+/,"").trim();if(!b||/^<local-command-caveat>/.test(b))continue;let S=yt(b);if(S&&!Vc(S)){m=S;break}}if(!m){let h=d.map(S=>S.content_text.replace(/^(?:<[^>]+>[\s\S]*?<\/[^>]+>\s*)+/,"").trim()).find(S=>S.length>0&&!/^<local-command-caveat>/.test(S)),b=h?yt(h):null;b&&Vc(b)&&(m=`[vacuous] ${b}`)}m&&(Ee(u.id,m,"heuristic"),c+=1)}return{scanned:a,updated:c}}function Vc(e){let t=e.trim();return!t||/^\*\*Tool result\*\*$/i.test(t)?!0:[/^all right\.?$/i,/^alright\.?$/i,/^inspect this\.?$/i,/^resolve this\.?$/i,/^do it\.?$/i,/^go\.?$/i,/^continue\.?$/i,/^proceed\.?$/i,/^keep going\.?$/i,/^ok\.?$/i,/^okay\.?$/i,/^yes\.?$/i,/^yep\.?$/i].some(s=>s.test(t))}function sl(e){let t=f(),n=e?.projectId?" AND s.project_id = ?":"",s=e?.projectId?[e.projectId]:[],r=t.prepare(`SELECT s.id, s.auto_title
1134
1134
  FROM sessions s
1135
1135
  WHERE s.auto_title_source = 'heuristic'${n}
1136
1136
  AND (
@@ -1145,47 +1145,47 @@ ${h+1}. ${S}`:`${h+1}. ${S}`}).join(`
1145
1145
  AND content_text IS NOT NULL
1146
1146
  AND content_text != ''
1147
1147
  ORDER BY COALESCE(timestamp, ''), rowid ASC
1148
- LIMIT 10`),a=0,c=0;for(let u of r){a+=1;let d=o.all(u.id),m=fE(d,u.auto_title);m&&(Ee(u.id,m,"heuristic"),c+=1)}return{scanned:a,updated:c}}function fE(e,t){for(let n of e){let s=hE(n.content_text);if(!s||to(s))continue;let r=yt(s);if(r){if(r===t)return null;if(!to(r))return r}}return t.startsWith("[meta]")?null:Tt(`[meta] ${t}`)}function Qc(e){let t=f(),n=e?.projectId?" AND s.project_id = ?":"",s=e?.projectId?[e.projectId]:[],r=t.prepare(`SELECT s.id, s.auto_title
1148
+ LIMIT 10`),a=0,c=0;for(let u of r){a+=1;let d=o.all(u.id),m=RE(d,u.auto_title);m&&(Ee(u.id,m,"heuristic"),c+=1)}return{scanned:a,updated:c}}function RE(e,t){for(let n of e){let s=kE(n.content_text);if(!s||no(s))continue;let r=yt(s);if(r){if(r===t)return null;if(!no(r))return r}}return t.startsWith("[meta]")?null:Tt(`[meta] ${t}`)}function rl(e){let t=f(),n=e?.projectId?" AND s.project_id = ?":"",s=e?.projectId?[e.projectId]:[],r=t.prepare(`SELECT s.id, s.auto_title
1149
1149
  FROM sessions s
1150
1150
  WHERE s.auto_title_source = 'heuristic'${n}
1151
1151
  AND s.auto_title IS NOT NULL
1152
1152
  AND s.auto_title LIKE '% \xB7 %'
1153
- AND (s.auto_title LIKE '%|%' OR s.auto_title LIKE '%(%')`).all(...s),o=0,a=0;for(let c of r){o+=1;let u=Wc(c.auto_title);u!==c.auto_title&&(Ee(c.id,u,"heuristic"),a+=1)}return{scanned:o,updated:a}}function hE(e){return e.replace(/<command-(?:name|message|args|stdout|stderr)>[\s\S]*?<\/command-(?:name|message|args|stdout|stderr)>/g,"").replace(/<local-command-(?:stdout|stderr|caveat)>[\s\S]*?<\/local-command-(?:stdout|stderr|caveat)>/g,"").trim()}function EE(){z(),Qh(ro)||Zh(ro,{recursive:!0})}function bE(e,t,n,s){try{EE();let r=Yc(ro,`${e}.txt`),o=`# Claude Recall auto-title \xB7 session ${e} \xB7 source ${n} \xB7 updated ${s}
1154
- `;Vh(r,o+t+`
1155
- `)}catch(r){console.error("[autoTitle] mirror write failed:",r)}}import{existsSync as el,mkdirSync as SE,readFileSync as TE,writeFileSync as yE}from"node:fs";import{homedir as wE}from"node:os";import{join as tl}from"node:path";import{z as ao}from"zod";function nl(){return process.env.RECALL_HOME??tl(wE(),".recall")}function RE(){let e=nl();el(e)||SE(e,{recursive:!0})}function sl(){return tl(nl(),"config.json")}var us=ao.object({heuristicEnabled:ao.boolean().default(!0),agentEnabled:ao.boolean().default(!1)}),ls={heuristicEnabled:!0,agentEnabled:!1};function rl(){let e=sl();if(!el(e))return{};try{return JSON.parse(TE(e,"utf8"))}catch(t){return console.error("[auto-title-config] failed to parse config.json, using defaults:",t),{}}}function rt(){let e=rl().autoTitle;if(!e)return{...ls};let t=us.safeParse({...ls,...e});return t.success?t.data:{...ls}}function ol(e){RE();let t=rl(),n=us.parse({...ls,...t.autoTitle??{},...e}),s={...t,autoTitle:n};return yE(sl(),JSON.stringify(s,null,2)),n}U();ee();import{randomUUID as po}from"node:crypto";import{existsSync as CE,mkdirSync as vE,writeFileSync as gl}from"node:fs";import{homedir as IE}from"node:os";import{basename as jE,join as mo}from"node:path";U();ee();import{randomUUID as kE}from"node:crypto";import{writeFileSync as AE,readFileSync as zA,existsSync as KA}from"node:fs";import{join as xE}from"node:path";var NE=xE(H,"collections.json"),ds=8;function ps(e){return{...e}}function Re(e,t,n,s=null,r=new Date().toISOString()){f().prepare(`INSERT INTO collection_events (collection_id, session_id, action, payload, at)
1156
- VALUES (?, ?, ?, ?, ?)`).run(e,s,t,n?JSON.stringify(n):null,r)}function ms(e){let t=f().prepare("SELECT * FROM collections WHERE id = ?").get(e);if(!t)throw new Error(`collection not found: ${e}`);return t}function il(e){if(!e)return 0;let t=0,n=e,s=new Set,r=f();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 OE(e,t){let n=f(),s=e,r=new Set;for(;s;){if(r.has(s))return!1;if(r.add(s),s===t)return!0;let o=n.prepare("SELECT parent_id FROM collections WHERE id = ?").get(s);if(!o)return!1;s=o.parent_id}return!1}function al(e=!1){return f().prepare(`SELECT c.*,
1153
+ AND (s.auto_title LIKE '%|%' OR s.auto_title LIKE '%(%')`).all(...s),o=0,a=0;for(let c of r){o+=1;let u=Yc(c.auto_title);u!==c.auto_title&&(Ee(c.id,u,"heuristic"),a+=1)}return{scanned:o,updated:a}}function kE(e){return e.replace(/<command-(?:name|message|args|stdout|stderr)>[\s\S]*?<\/command-(?:name|message|args|stdout|stderr)>/g,"").replace(/<local-command-(?:stdout|stderr|caveat)>[\s\S]*?<\/local-command-(?:stdout|stderr|caveat)>/g,"").trim()}function AE(){z(),aE(oo)||iE(oo,{recursive:!0})}function xE(e,t,n,s){try{AE();let r=Zc(oo,`${e}.txt`),o=`# Claude Recall auto-title \xB7 session ${e} \xB7 source ${n} \xB7 updated ${s}
1154
+ `;oE(r,o+t+`
1155
+ `)}catch(r){console.error("[autoTitle] mirror write failed:",r)}}import{existsSync as ol,mkdirSync as NE,readFileSync as OE,writeFileSync as LE}from"node:fs";import{homedir as CE}from"node:os";import{join as il}from"node:path";import{z as co}from"zod";function al(){return process.env.RECALL_HOME??il(CE(),".recall")}function vE(){let e=al();ol(e)||NE(e,{recursive:!0})}function cl(){return il(al(),"config.json")}var ds=co.object({heuristicEnabled:co.boolean().default(!0),agentEnabled:co.boolean().default(!1)}),us={heuristicEnabled:!0,agentEnabled:!1};function ll(){let e=cl();if(!ol(e))return{};try{return JSON.parse(OE(e,"utf8"))}catch(t){return console.error("[auto-title-config] failed to parse config.json, using defaults:",t),{}}}function st(){let e=ll().autoTitle;if(!e)return{...us};let t=ds.safeParse({...us,...e});return t.success?t.data:{...us}}function ul(e){vE();let t=ll(),n=ds.parse({...us,...t.autoTitle??{},...e}),s={...t,autoTitle:n};return LE(cl(),JSON.stringify(s,null,2)),n}B();ee();import{randomUUID as mo}from"node:crypto";import{existsSync as $E,mkdirSync as UE,writeFileSync as bl}from"node:fs";import{homedir as BE}from"node:os";import{basename as HE,join as go}from"node:path";B();ee();import{randomUUID as IE}from"node:crypto";import{writeFileSync as jE,readFileSync as hx,existsSync as Ex}from"node:fs";import{join as ME}from"node:path";var DE=ME(W,"collections.json"),ps=8;function ms(e){return{...e}}function Re(e,t,n,s=null,r=new Date().toISOString()){f().prepare(`INSERT INTO collection_events (collection_id, session_id, action, payload, at)
1156
+ VALUES (?, ?, ?, ?, ?)`).run(e,s,t,n?JSON.stringify(n):null,r)}function gs(e){let t=f().prepare("SELECT * FROM collections WHERE id = ?").get(e);if(!t)throw new Error(`collection not found: ${e}`);return t}function dl(e){if(!e)return 0;let t=0,n=e,s=new Set,r=f();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 FE(e,t){let n=f(),s=e,r=new Set;for(;s;){if(r.has(s))return!1;if(r.add(s),s===t)return!0;let o=n.prepare("SELECT parent_id FROM collections WHERE id = ?").get(s);if(!o)return!1;s=o.parent_id}return!1}function pl(e=!1){return f().prepare(`SELECT c.*,
1157
1157
  (SELECT COUNT(*) FROM collection_sessions cs WHERE cs.collection_id = c.id) AS session_count
1158
1158
  FROM collections c
1159
1159
  ${e?"":"WHERE c.archived_at IS NULL"}
1160
- ORDER BY c.parent_id IS NOT NULL, c.parent_id, c.sort_key, LOWER(c.name)`).all().map(s=>({...ps(s),session_count:s.session_count}))}function Be(e){let t=f().prepare("SELECT * FROM collections WHERE id = ?").get(e);return t?ps(t):null}function cl(e,t=!0){let n=f(),s=t?co(e):[e];if(s.length===0)return[];let r=s.map(()=>"?").join(",");return n.prepare(`SELECT collection_id, session_id, added_at, note, source, rule_id
1160
+ ORDER BY c.parent_id IS NOT NULL, c.parent_id, c.sort_key, LOWER(c.name)`).all().map(s=>({...ms(s),session_count:s.session_count}))}function Be(e){let t=f().prepare("SELECT * FROM collections WHERE id = ?").get(e);return t?ms(t):null}function ml(e,t=!0){let n=f(),s=t?lo(e):[e];if(s.length===0)return[];let r=s.map(()=>"?").join(",");return n.prepare(`SELECT collection_id, session_id, added_at, note, source, rule_id
1161
1161
  FROM collection_sessions
1162
1162
  WHERE collection_id IN (${r})
1163
- ORDER BY added_at DESC`).all(...s)}function co(e){let t=f(),n=[e],s=[e],r=new Set([e]);for(;s.length>0;){let o=s.map(()=>"?").join(","),a=t.prepare(`SELECT id FROM collections WHERE parent_id IN (${o})`).all(...s),c=[];for(let u of a)r.has(u.id)||(r.add(u.id),n.push(u.id),c.push(u.id));s=c}return n}function ll(e){return f().prepare(`SELECT c.* FROM collections c
1163
+ ORDER BY added_at DESC`).all(...s)}function lo(e){let t=f(),n=[e],s=[e],r=new Set([e]);for(;s.length>0;){let o=s.map(()=>"?").join(","),a=t.prepare(`SELECT id FROM collections WHERE parent_id IN (${o})`).all(...s),c=[];for(let u of a)r.has(u.id)||(r.add(u.id),n.push(u.id),c.push(u.id));s=c}return n}function gl(e){return f().prepare(`SELECT c.* FROM collections c
1164
1164
  JOIN collection_sessions cs ON cs.collection_id = c.id
1165
1165
  WHERE cs.session_id = ? AND c.archived_at IS NULL
1166
- ORDER BY LOWER(c.name)`).all(e)}function sn(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=f(),s=new Date().toISOString(),r=kE();if(e.parent_id){if(!Be(e.parent_id))throw new Error("parent collection not found");if(il(e.parent_id)>=ds-1)throw new Error(`max collection depth is ${ds}`)}return n.transaction(()=>{n.prepare(`INSERT INTO collections
1166
+ ORDER BY LOWER(c.name)`).all(e)}function sn(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=f(),s=new Date().toISOString(),r=IE();if(e.parent_id){if(!Be(e.parent_id))throw new Error("parent collection not found");if(dl(e.parent_id)>=ps-1)throw new Error(`max collection depth is ${ps}`)}return n.transaction(()=>{n.prepare(`INSERT INTO collections
1167
1167
  (id, name, description, icon, color, parent_id, sort_key, created_at, updated_at, archived_at)
1168
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL)`).run(r,t,e.description??null,e.icon??null,e.color??null,e.parent_id??null,e.sort_key??"",s,s),Re(r,"create",{name:t,parent_id:e.parent_id??null,icon:e.icon??null,color:e.color??null},null,s)})(),ot(),Be(r)}function ul(e,t){let n=f(),s=ms(e),r=new Date().toISOString(),o={name:t.name!==void 0?t.name.trim():s.name,description:t.description!==void 0?t.description:s.description,icon:t.icon!==void 0?t.icon:s.icon,color:t.color!==void 0?t.color:s.color,parent_id:t.parent_id!==void 0?t.parent_id:s.parent_id,sort_key:t.sort_key!==void 0?t.sort_key:s.sort_key};if(!o.name)throw new Error("name required");if(o.name.length>120)throw new Error("name too long (max 120 chars)");if(t.parent_id!==void 0&&t.parent_id!==s.parent_id&&t.parent_id){if(t.parent_id===e)throw new Error("cannot set parent to self");if(!Be(t.parent_id))throw new Error("parent collection not found");if(OE(t.parent_id,e))throw new Error("cannot move collection into one of its descendants");if(il(t.parent_id)>=ds-1)throw new Error(`max collection depth is ${ds}`)}return n.transaction(()=>{n.prepare(`UPDATE collections
1168
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL)`).run(r,t,e.description??null,e.icon??null,e.color??null,e.parent_id??null,e.sort_key??"",s,s),Re(r,"create",{name:t,parent_id:e.parent_id??null,icon:e.icon??null,color:e.color??null},null,s)})(),rt(),Be(r)}function _l(e,t){let n=f(),s=gs(e),r=new Date().toISOString(),o={name:t.name!==void 0?t.name.trim():s.name,description:t.description!==void 0?t.description:s.description,icon:t.icon!==void 0?t.icon:s.icon,color:t.color!==void 0?t.color:s.color,parent_id:t.parent_id!==void 0?t.parent_id:s.parent_id,sort_key:t.sort_key!==void 0?t.sort_key:s.sort_key};if(!o.name)throw new Error("name required");if(o.name.length>120)throw new Error("name too long (max 120 chars)");if(t.parent_id!==void 0&&t.parent_id!==s.parent_id&&t.parent_id){if(t.parent_id===e)throw new Error("cannot set parent to self");if(!Be(t.parent_id))throw new Error("parent collection not found");if(FE(t.parent_id,e))throw new Error("cannot move collection into one of its descendants");if(dl(t.parent_id)>=ps-1)throw new Error(`max collection depth is ${ps}`)}return n.transaction(()=>{n.prepare(`UPDATE collections
1169
1169
  SET name = ?, description = ?, icon = ?, color = ?,
1170
1170
  parent_id = ?, sort_key = ?, updated_at = ?
1171
- WHERE id = ?`).run(o.name,o.description,o.icon,o.color,o.parent_id,o.sort_key,r,e),t.name!==void 0&&t.name!==s.name&&Re(e,"rename",{from:s.name,to:o.name},null,r),t.description!==void 0&&t.description!==s.description&&Re(e,"describe",{description:o.description},null,r),(t.icon!==void 0&&t.icon!==s.icon||t.color!==void 0&&t.color!==s.color)&&Re(e,"recolor",{icon:o.icon,color:o.color},null,r),t.parent_id!==void 0&&t.parent_id!==s.parent_id&&Re(e,"move",{from:s.parent_id,to:o.parent_id},null,r),t.sort_key!==void 0&&t.sort_key!==s.sort_key&&Re(e,"reorder",{from:s.sort_key,to:o.sort_key},null,r)})(),ot(),Be(e)}function dl(e){let t=f(),n=ms(e);if(n.archived_at)return ps(n);let s=new Date().toISOString();return t.transaction(()=>{t.prepare("UPDATE collections SET archived_at = ?, updated_at = ? WHERE id = ?").run(s,s,e),Re(e,"archive",{name:n.name},null,s)})(),ot(),Be(e)}function pl(e){let t=f(),n=ms(e);if(!n.archived_at)return ps(n);let s=new Date().toISOString();return t.transaction(()=>{t.prepare("UPDATE collections SET archived_at = NULL, updated_at = ? WHERE id = ?").run(s,e),Re(e,"restore",{name:n.name},null,s)})(),ot(),Be(e)}function rn(e,t,n=null,s={}){let r=f();if(ms(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 c=s.source??"manual",u=s.rule_id??null;if(c==="auto"&&!u)throw new Error("auto membership requires a rule_id");let d=new Date().toISOString();return r.transaction(()=>{r.prepare(`INSERT INTO collection_sessions (collection_id, session_id, added_at, note, source, rule_id)
1172
- VALUES (?, ?, ?, ?, ?, ?)`).run(e,t,d,n,c,u),Re(e,"add",{note:n,source:c,rule_id:u},t,d)})(),ot(),{added:!0}}function ml(e,t){let n=f();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),Re(e,"remove",null,t,r)})(),ot(),{removed:!0}}function gs(e){let t=f(),n=t.prepare(`SELECT collection_id, session_id FROM collection_sessions
1173
- WHERE rule_id = ?`).all(e);if(n.length===0)return{removed:0};let s=new Date().toISOString();return t.transaction(()=>{t.prepare("DELETE FROM collection_sessions WHERE rule_id = ?").run(e);for(let o of n)Re(o.collection_id,"remove",{rule_id:e},o.session_id,s)})(),ot(),{removed:n.length}}function LE(){return f().prepare(`SELECT id, collection_id, session_id, action, payload, at
1171
+ WHERE id = ?`).run(o.name,o.description,o.icon,o.color,o.parent_id,o.sort_key,r,e),t.name!==void 0&&t.name!==s.name&&Re(e,"rename",{from:s.name,to:o.name},null,r),t.description!==void 0&&t.description!==s.description&&Re(e,"describe",{description:o.description},null,r),(t.icon!==void 0&&t.icon!==s.icon||t.color!==void 0&&t.color!==s.color)&&Re(e,"recolor",{icon:o.icon,color:o.color},null,r),t.parent_id!==void 0&&t.parent_id!==s.parent_id&&Re(e,"move",{from:s.parent_id,to:o.parent_id},null,r),t.sort_key!==void 0&&t.sort_key!==s.sort_key&&Re(e,"reorder",{from:s.sort_key,to:o.sort_key},null,r)})(),rt(),Be(e)}function fl(e){let t=f(),n=gs(e);if(n.archived_at)return ms(n);let s=new Date().toISOString();return t.transaction(()=>{t.prepare("UPDATE collections SET archived_at = ?, updated_at = ? WHERE id = ?").run(s,s,e),Re(e,"archive",{name:n.name},null,s)})(),rt(),Be(e)}function hl(e){let t=f(),n=gs(e);if(!n.archived_at)return ms(n);let s=new Date().toISOString();return t.transaction(()=>{t.prepare("UPDATE collections SET archived_at = NULL, updated_at = ? WHERE id = ?").run(s,e),Re(e,"restore",{name:n.name},null,s)})(),rt(),Be(e)}function rn(e,t,n=null,s={}){let r=f();if(gs(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 c=s.source??"manual",u=s.rule_id??null;if(c==="auto"&&!u)throw new Error("auto membership requires a rule_id");let d=new Date().toISOString();return r.transaction(()=>{r.prepare(`INSERT INTO collection_sessions (collection_id, session_id, added_at, note, source, rule_id)
1172
+ VALUES (?, ?, ?, ?, ?, ?)`).run(e,t,d,n,c,u),Re(e,"add",{note:n,source:c,rule_id:u},t,d)})(),rt(),{added:!0}}function El(e,t){let n=f();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),Re(e,"remove",null,t,r)})(),rt(),{removed:!0}}function _s(e){let t=f(),n=t.prepare(`SELECT collection_id, session_id FROM collection_sessions
1173
+ WHERE rule_id = ?`).all(e);if(n.length===0)return{removed:0};let s=new Date().toISOString();return t.transaction(()=>{t.prepare("DELETE FROM collection_sessions WHERE rule_id = ?").run(e);for(let o of n)Re(o.collection_id,"remove",{rule_id:e},o.session_id,s)})(),rt(),{removed:n.length}}function PE(){return f().prepare(`SELECT id, collection_id, session_id, action, payload, at
1174
1174
  FROM collection_events
1175
- ORDER BY at ASC, id ASC`).all()}function ot(){try{z();let e=f(),t=e.prepare(`SELECT id, name, description, icon, color, parent_id, sort_key,
1175
+ ORDER BY at ASC, id ASC`).all()}function rt(){try{z();let e=f(),t=e.prepare(`SELECT id, name, description, icon, color, parent_id, sort_key,
1176
1176
  created_at, updated_at, archived_at
1177
1177
  FROM collections
1178
1178
  ORDER BY COALESCE(parent_id, ''), sort_key, LOWER(name)`).all(),n=e.prepare(`SELECT collection_id, session_id, added_at, note, source, rule_id
1179
1179
  FROM collection_sessions
1180
- ORDER BY collection_id, added_at`).all(),s=LE(),r={schema:"claude-recall.collections.v1",backed_up_at:new Date().toISOString(),collections:t,memberships:n,events:s};AE(NE,JSON.stringify(r,null,2))}catch(e){console.error("[collections] backup failed:",e)}}var _s=mo(H,"auto-rules"),ME=mo(_s,"rules.json"),DE=mo(_s,"suggestions.json"),lo="Repositories",FE="Topics",_l=3;var PE=5,$E=2,UE=[/\bROADMAP\.md\b/g,/\bPROJECT\.md\b/g,/\bdocs\/[A-Za-z0-9._-]+\.md\b/g,/\.planning\/[A-Za-z0-9._\-/]+/g];function go(e){return{id:e.id,name:e.name,type:e.type,pattern:e.pattern,collection_id:e.collection_id,priority:e.priority,enabled:e.enabled!==0,created_at:e.created_at,created_by:e.created_by}}function BE(e){return{id:e.id,type:e.type,pattern:e.pattern,suggested_name:e.suggested_name,suggested_parent_collection_id:e.suggested_parent_collection_id,session_count:e.session_count,detected_at:e.detected_at,dismissed:e.dismissed!==0}}function HE(e){switch(e){case"cwd-prefix":case"project-id":case"git-branch-prefix":return lo;case"tag":return FE;case"plan-file":return null}}function WE(e){let n=f().prepare("SELECT id FROM collections WHERE name = ? AND parent_id IS NULL AND archived_at IS NULL").get(e);if(n)return n.id;let o=sn({name:e,icon:e===lo?"\u{1F4E6}":"\u{1F3F7}",sort_key:e===lo?"0000-repos":"0001-topics"});return f().prepare(`INSERT INTO auto_collection_rules
1180
+ ORDER BY collection_id, added_at`).all(),s=PE(),r={schema:"claude-recall.collections.v1",backed_up_at:new Date().toISOString(),collections:t,memberships:n,events:s};jE(DE,JSON.stringify(r,null,2))}catch(e){console.error("[collections] backup failed:",e)}}var fs=go(W,"auto-rules"),WE=go(fs,"rules.json"),qE=go(fs,"suggestions.json"),uo="Repositories",XE="Topics",Sl=3;var JE=5,GE=2,YE=[/\bROADMAP\.md\b/g,/\bPROJECT\.md\b/g,/\bdocs\/[A-Za-z0-9._-]+\.md\b/g,/\.planning\/[A-Za-z0-9._\-/]+/g];function _o(e){return{id:e.id,name:e.name,type:e.type,pattern:e.pattern,collection_id:e.collection_id,priority:e.priority,enabled:e.enabled!==0,created_at:e.created_at,created_by:e.created_by}}function zE(e){return{id:e.id,type:e.type,pattern:e.pattern,suggested_name:e.suggested_name,suggested_parent_collection_id:e.suggested_parent_collection_id,session_count:e.session_count,detected_at:e.detected_at,dismissed:e.dismissed!==0}}function KE(e){switch(e){case"cwd-prefix":case"project-id":case"git-branch-prefix":return uo;case"tag":return XE;case"plan-file":return null}}function VE(e){let n=f().prepare("SELECT id FROM collections WHERE name = ? AND parent_id IS NULL AND archived_at IS NULL").get(e);if(n)return n.id;let o=sn({name:e,icon:e===uo?"\u{1F4E6}":"\u{1F3F7}",sort_key:e===uo?"0000-repos":"0001-topics"});return f().prepare(`INSERT INTO auto_collection_rules
1181
1181
  (id, name, type, pattern, collection_id, priority, enabled, created_at, created_by)
1182
- VALUES (?, ?, 'cwd-prefix', '__seed__', ?, 1000, 0, ?, 'seed')`).run(po(),`seed:${e}`,o.id,new Date().toISOString()),o.id}function qE(e,t,n){let s;if(n!==void 0)s=n;else{let o=HE(t);s=o?WE(o):null}return sn({name:e,parent_id:s}).id}function fs(e){let t=f().prepare("SELECT * FROM auto_collection_rules WHERE id = ?").get(e);return t?go(t):null}function XE(e){let t=f();switch(e.type){case"cwd-prefix":return t.prepare("SELECT id FROM sessions WHERE cwd IS NOT NULL AND cwd LIKE ? ESCAPE '\\'").all(hs(e.pattern)+"%").map(s=>s.id);case"git-branch-prefix":return t.prepare("SELECT id FROM sessions WHERE git_branch IS NOT NULL AND git_branch LIKE ? ESCAPE '\\'").all(hs(e.pattern)+"%").map(s=>s.id);case"project-id":{let n=Number(e.pattern);return Number.isFinite(n)?t.prepare("SELECT id FROM sessions WHERE project_id = ?").all(n).map(r=>r.id):[]}case"tag":return t.prepare("SELECT session_id FROM session_tags WHERE tag = ?").all(e.pattern).map(s=>s.session_id);case"plan-file":return t.prepare(`SELECT id, first_user_message FROM sessions
1183
- WHERE first_user_message IS NOT NULL AND first_user_message LIKE ?`).all("%"+e.pattern+"%").map(s=>s.id)}}function fl(e,t,n=3){let s=f(),r=`s.id AS id, s.cwd AS cwd, s.started_at AS started_at,
1182
+ VALUES (?, ?, 'cwd-prefix', '__seed__', ?, 1000, 0, ?, 'seed')`).run(mo(),`seed:${e}`,o.id,new Date().toISOString()),o.id}function ZE(e,t,n){let s;if(n!==void 0)s=n;else{let o=KE(t);s=o?VE(o):null}return sn({name:e,parent_id:s}).id}function hs(e){let t=f().prepare("SELECT * FROM auto_collection_rules WHERE id = ?").get(e);return t?_o(t):null}function QE(e){let t=f();switch(e.type){case"cwd-prefix":return t.prepare("SELECT id FROM sessions WHERE cwd IS NOT NULL AND cwd LIKE ? ESCAPE '\\'").all(Es(e.pattern)+"%").map(s=>s.id);case"git-branch-prefix":return t.prepare("SELECT id FROM sessions WHERE git_branch IS NOT NULL AND git_branch LIKE ? ESCAPE '\\'").all(Es(e.pattern)+"%").map(s=>s.id);case"project-id":{let n=Number(e.pattern);return Number.isFinite(n)?t.prepare("SELECT id FROM sessions WHERE project_id = ?").all(n).map(r=>r.id):[]}case"tag":return t.prepare("SELECT session_id FROM session_tags WHERE tag = ?").all(e.pattern).map(s=>s.session_id);case"plan-file":return t.prepare(`SELECT id, first_user_message FROM sessions
1183
+ WHERE first_user_message IS NOT NULL AND first_user_message LIKE ?`).all("%"+e.pattern+"%").map(s=>s.id)}}function Tl(e,t,n=3){let s=f(),r=`s.id AS id, s.cwd AS cwd, s.started_at AS started_at,
1184
1184
  sa.alias AS alias, s.auto_title AS auto_title, s.first_user_message AS first_user_message`,o="LEFT JOIN session_aliases sa ON sa.session_id = s.id",a=[];switch(e){case"cwd-prefix":a=s.prepare(`SELECT ${r} FROM sessions s ${o}
1185
1185
  WHERE s.cwd IS NOT NULL AND s.cwd LIKE ? ESCAPE '\\'
1186
- ORDER BY s.started_at DESC LIMIT ?`).all(hs(t)+"%",n);break;case"git-branch-prefix":a=s.prepare(`SELECT ${r} FROM sessions s ${o}
1186
+ ORDER BY s.started_at DESC LIMIT ?`).all(Es(t)+"%",n);break;case"git-branch-prefix":a=s.prepare(`SELECT ${r} FROM sessions s ${o}
1187
1187
  WHERE s.git_branch IS NOT NULL AND s.git_branch LIKE ? ESCAPE '\\'
1188
- ORDER BY s.started_at DESC LIMIT ?`).all(hs(t)+"%",n);break;case"project-id":{let c=Number(t);Number.isFinite(c)&&(a=s.prepare(`SELECT ${r} FROM sessions s ${o}
1188
+ ORDER BY s.started_at DESC LIMIT ?`).all(Es(t)+"%",n);break;case"project-id":{let c=Number(t);Number.isFinite(c)&&(a=s.prepare(`SELECT ${r} FROM sessions s ${o}
1189
1189
  WHERE s.project_id = ?
1190
1190
  ORDER BY s.started_at DESC LIMIT ?`).all(c,n));break}case"tag":a=s.prepare(`SELECT ${r} FROM sessions s ${o}
1191
1191
  JOIN session_tags st ON st.session_id = s.id
@@ -1193,19 +1193,19 @@ ${h+1}. ${S}`:`${h+1}. ${S}`}).join(`
1193
1193
  ORDER BY s.started_at DESC LIMIT ?`).all(t,n);break;case"plan-file":a=s.prepare(`SELECT ${r} FROM sessions s ${o}
1194
1194
  WHERE s.first_user_message IS NOT NULL
1195
1195
  AND s.first_user_message LIKE ?
1196
- ORDER BY s.started_at DESC LIMIT ?`).all("%"+t+"%",n);break}return a.map(c=>({id:c.id,title:JE(c),cwd:c.cwd,started_at:c.started_at}))}function JE(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`session ${e.id.slice(0,8)}`;let n=t.split(`
1197
- `)[0].trim();return n.length>80?n.slice(0,80)+"\u2026":n}function YE(e,t,n=f()){switch(e.type){case"cwd-prefix":return!!t.cwd&&t.cwd.startsWith(e.pattern);case"git-branch-prefix":return!!t.git_branch&&t.git_branch.startsWith(e.pattern);case"project-id":{let s=Number(e.pattern);return Number.isFinite(s)&&t.project_id===s}case"tag":return!!n.prepare("SELECT 1 FROM session_tags WHERE session_id = ? AND tag = ?").get(t.id,e.pattern);case"plan-file":return!!t.first_user_message&&t.first_user_message.includes(e.pattern)}}function hl(e){let t=f(),n=t.prepare("SELECT id, project_id, cwd, git_branch, first_user_message FROM sessions WHERE id = ?").get(e);if(!n)return{added:0};let s=t.prepare(`SELECT * FROM auto_collection_rules
1196
+ ORDER BY s.started_at DESC LIMIT ?`).all("%"+t+"%",n);break}return a.map(c=>({id:c.id,title:eb(c),cwd:c.cwd,started_at:c.started_at}))}function eb(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`session ${e.id.slice(0,8)}`;let n=t.split(`
1197
+ `)[0].trim();return n.length>80?n.slice(0,80)+"\u2026":n}function tb(e,t,n=f()){switch(e.type){case"cwd-prefix":return!!t.cwd&&t.cwd.startsWith(e.pattern);case"git-branch-prefix":return!!t.git_branch&&t.git_branch.startsWith(e.pattern);case"project-id":{let s=Number(e.pattern);return Number.isFinite(s)&&t.project_id===s}case"tag":return!!n.prepare("SELECT 1 FROM session_tags WHERE session_id = ? AND tag = ?").get(t.id,e.pattern);case"plan-file":return!!t.first_user_message&&t.first_user_message.includes(e.pattern)}}function yl(e){let t=f(),n=t.prepare("SELECT id, project_id, cwd, git_branch, first_user_message FROM sessions WHERE id = ?").get(e);if(!n)return{added:0};let s=t.prepare(`SELECT * FROM auto_collection_rules
1198
1198
  WHERE enabled = 1 AND created_by != 'seed'
1199
- ORDER BY priority, created_at`).all(),r=0;for(let o of s){let a=go(o);if(YE(a,n,t))try{rn(a.collection_id,e,null,{source:"auto",rule_id:a.id}).added&&(r+=1)}catch(c){console.error(`[auto-collections] failed to apply rule ${a.id} to session ${e}:`,c)}}return{added:r}}function uo(e){if(!e.enabled)return{added:0};let t=0;for(let n of XE(e))try{rn(e.collection_id,n,null,{source:"auto",rule_id:e.id}).added&&(t+=1)}catch(s){console.error(`[auto-collections] backfill failed for rule ${e.id} / session ${n}:`,s)}return{added:t}}function _o(e){let t=(e.name??"").trim();if(!t)throw new Error("name required");let n=(e.pattern??"").trim();if(!n)throw new Error("pattern required");let s=f(),r=new Date().toISOString(),o=po(),a=e.collection_id;a||(a=qE(t,e.type,e.parent_collection_id)),s.prepare(`INSERT INTO auto_collection_rules
1199
+ ORDER BY priority, created_at`).all(),r=0;for(let o of s){let a=_o(o);if(tb(a,n,t))try{rn(a.collection_id,e,null,{source:"auto",rule_id:a.id}).added&&(r+=1)}catch(c){console.error(`[auto-collections] failed to apply rule ${a.id} to session ${e}:`,c)}}return{added:r}}function po(e){if(!e.enabled)return{added:0};let t=0;for(let n of QE(e))try{rn(e.collection_id,n,null,{source:"auto",rule_id:e.id}).added&&(t+=1)}catch(s){console.error(`[auto-collections] backfill failed for rule ${e.id} / session ${n}:`,s)}return{added:t}}function fo(e){let t=(e.name??"").trim();if(!t)throw new Error("name required");let n=(e.pattern??"").trim();if(!n)throw new Error("pattern required");let s=f(),r=new Date().toISOString(),o=mo(),a=e.collection_id;a||(a=ZE(t,e.type,e.parent_collection_id)),s.prepare(`INSERT INTO auto_collection_rules
1200
1200
  (id, name, type, pattern, collection_id, priority, enabled, created_at, created_by)
1201
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(o,t,e.type,n,a,e.priority??100,e.enabled===!1?0:1,r,e.created_by??"user"),s.prepare("DELETE FROM auto_collection_suggestions WHERE type = ? AND pattern = ?").run(e.type,n);let c=fs(o);return uo(c),wt(),c}function El(e={}){let t=e.includeSeed?"SELECT * FROM auto_collection_rules ORDER BY priority, created_at":"SELECT * FROM auto_collection_rules WHERE created_by != 'seed' ORDER BY priority, created_at";return f().prepare(t).all().map(go)}function bl(e,t){let n=f(),s=fs(e);if(!s)throw new Error(`rule not found: ${e}`);let r={name:t.name!==void 0?t.name.trim():s.name,pattern:t.pattern!==void 0?t.pattern.trim():s.pattern,enabled:t.enabled!==void 0?t.enabled:s.enabled,priority:t.priority!==void 0?t.priority:s.priority};if(!r.name)throw new Error("name required");if(!r.pattern)throw new Error("pattern required");n.prepare(`UPDATE auto_collection_rules
1201
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(o,t,e.type,n,a,e.priority??100,e.enabled===!1?0:1,r,e.created_by??"user"),s.prepare("DELETE FROM auto_collection_suggestions WHERE type = ? AND pattern = ?").run(e.type,n);let c=hs(o);return po(c),wt(),c}function wl(e={}){let t=e.includeSeed?"SELECT * FROM auto_collection_rules ORDER BY priority, created_at":"SELECT * FROM auto_collection_rules WHERE created_by != 'seed' ORDER BY priority, created_at";return f().prepare(t).all().map(_o)}function Rl(e,t){let n=f(),s=hs(e);if(!s)throw new Error(`rule not found: ${e}`);let r={name:t.name!==void 0?t.name.trim():s.name,pattern:t.pattern!==void 0?t.pattern.trim():s.pattern,enabled:t.enabled!==void 0?t.enabled:s.enabled,priority:t.priority!==void 0?t.priority:s.priority};if(!r.name)throw new Error("name required");if(!r.pattern)throw new Error("pattern required");n.prepare(`UPDATE auto_collection_rules
1202
1202
  SET name = ?, pattern = ?, enabled = ?, priority = ?
1203
- WHERE id = ?`).run(r.name,r.pattern,r.enabled?1:0,r.priority,e);let o=fs(e);return t.pattern!==void 0&&t.pattern!==s.pattern?(gs(e),o.enabled&&uo(o)):t.enabled!==void 0&&t.enabled!==s.enabled&&(o.enabled?uo(o):gs(e)),wt(),o}function Sl(e){let t=f();if(!fs(e))return{removed:0};let s=gs(e);return t.prepare("DELETE FROM auto_collection_rules WHERE id = ?").run(e),wt(),s}function Es(e={}){let t=e.includeDismissed?"SELECT * FROM auto_collection_suggestions ORDER BY detected_at DESC":"SELECT * FROM auto_collection_suggestions WHERE dismissed = 0 ORDER BY detected_at DESC";return f().prepare(t).all().map(BE)}function Tl(e){f().prepare("UPDATE auto_collection_suggestions SET dismissed = 1 WHERE id = ?").run(e),wt()}function yl(e){let t=f(),n=t.prepare("SELECT * FROM auto_collection_suggestions WHERE id = ?").get(e);if(!n)throw new Error(`suggestion not found: ${e}`);if(n.dismissed)throw new Error(`suggestion already dismissed: ${e}`);let s=_o({name:n.suggested_name,type:n.type,pattern:n.pattern,parent_collection_id:n.suggested_parent_collection_id===null?void 0:n.suggested_parent_collection_id,created_by:"suggestion-accepted"});return t.prepare("DELETE FROM auto_collection_suggestions WHERE id = ?").run(e),wt(),s}function bs(){let e=f(),t=new Date().toISOString(),n=IE(),s=new Set(e.prepare("SELECT decoded_path FROM projects").all().map(c=>c.decoded_path)),r=[...GE(n,t).filter(c=>!s.has(c.pattern)),...zE(t),...KE(t)];if(e.prepare("DELETE FROM auto_collection_suggestions WHERE type = 'project-id'").run(),s.size>0){let c=Array.from(s).map(()=>"?").join(",");e.prepare(`DELETE FROM auto_collection_suggestions WHERE type = 'cwd-prefix' AND pattern IN (${c})`).run(...Array.from(s))}let o=e.prepare("SELECT type, pattern FROM auto_collection_rules").all(),a=new Set(o.map(c=>`${c.type}:${c.pattern}`));for(let c of r){let u=`${c.type}:${c.pattern}`;if(a.has(u))continue;let d=e.prepare("SELECT id FROM auto_collection_suggestions WHERE type = ? AND pattern = ?").get(c.type,c.pattern);d?e.prepare(`UPDATE auto_collection_suggestions
1203
+ WHERE id = ?`).run(r.name,r.pattern,r.enabled?1:0,r.priority,e);let o=hs(e);return t.pattern!==void 0&&t.pattern!==s.pattern?(_s(e),o.enabled&&po(o)):t.enabled!==void 0&&t.enabled!==s.enabled&&(o.enabled?po(o):_s(e)),wt(),o}function kl(e){let t=f();if(!hs(e))return{removed:0};let s=_s(e);return t.prepare("DELETE FROM auto_collection_rules WHERE id = ?").run(e),wt(),s}function bs(e={}){let t=e.includeDismissed?"SELECT * FROM auto_collection_suggestions ORDER BY detected_at DESC":"SELECT * FROM auto_collection_suggestions WHERE dismissed = 0 ORDER BY detected_at DESC";return f().prepare(t).all().map(zE)}function Al(e){f().prepare("UPDATE auto_collection_suggestions SET dismissed = 1 WHERE id = ?").run(e),wt()}function xl(e){let t=f(),n=t.prepare("SELECT * FROM auto_collection_suggestions WHERE id = ?").get(e);if(!n)throw new Error(`suggestion not found: ${e}`);if(n.dismissed)throw new Error(`suggestion already dismissed: ${e}`);let s=fo({name:n.suggested_name,type:n.type,pattern:n.pattern,parent_collection_id:n.suggested_parent_collection_id===null?void 0:n.suggested_parent_collection_id,created_by:"suggestion-accepted"});return t.prepare("DELETE FROM auto_collection_suggestions WHERE id = ?").run(e),wt(),s}function Ss(){let e=f(),t=new Date().toISOString(),n=BE(),s=new Set(e.prepare("SELECT decoded_path FROM projects").all().map(c=>c.decoded_path)),r=[...nb(n,t).filter(c=>!s.has(c.pattern)),...sb(t),...rb(t)];if(e.prepare("DELETE FROM auto_collection_suggestions WHERE type = 'project-id'").run(),s.size>0){let c=Array.from(s).map(()=>"?").join(",");e.prepare(`DELETE FROM auto_collection_suggestions WHERE type = 'cwd-prefix' AND pattern IN (${c})`).run(...Array.from(s))}let o=e.prepare("SELECT type, pattern FROM auto_collection_rules").all(),a=new Set(o.map(c=>`${c.type}:${c.pattern}`));for(let c of r){let u=`${c.type}:${c.pattern}`;if(a.has(u))continue;let d=e.prepare("SELECT id FROM auto_collection_suggestions WHERE type = ? AND pattern = ?").get(c.type,c.pattern);d?e.prepare(`UPDATE auto_collection_suggestions
1204
1204
  SET session_count = ?, detected_at = ?, suggested_name = ?, suggested_parent_collection_id = ?
1205
1205
  WHERE id = ?`).run(c.session_count,t,c.suggested_name,c.suggested_parent_collection_id,d.id):e.prepare(`INSERT INTO auto_collection_suggestions
1206
1206
  (id, type, pattern, suggested_name, suggested_parent_collection_id, session_count, detected_at, dismissed)
1207
- VALUES (?, ?, ?, ?, ?, ?, ?, 0)`).run(po(),c.type,c.pattern,c.suggested_name,c.suggested_parent_collection_id,c.session_count,t)}return wt(),Es()}function GE(e,t){let s=f().prepare("SELECT id, cwd FROM sessions WHERE cwd IS NOT NULL AND cwd != ''").all(),r=new Map;for(let a of s){let c=a.cwd.split("/").filter(Boolean),u="";for(let d of c){if(u=`${u}/${d}`,u===e||u==="/")continue;let m=r.get(u);m||(m=new Set,r.set(u,m)),m.add(a.id)}}let o=[];for(let[a,c]of r.entries()){if(c.size<_l)continue;let u=!1;for(let[d,m]of r.entries())if(d!==a&&d.startsWith(a+"/")&&m.size>=_l){u=!0;break}u||o.push({type:"cwd-prefix",pattern:a,suggested_name:jE(a)||a,suggested_parent_collection_id:null,session_count:c.size,detected_at:t,dismissed:!1})}return o}function zE(e){return f().prepare("SELECT tag, COUNT(*) AS n FROM session_tags GROUP BY tag HAVING n >= ?").all(PE).map(n=>({type:"tag",pattern:n.tag,suggested_name:n.tag,suggested_parent_collection_id:null,session_count:n.n,detected_at:e,dismissed:!1}))}function KE(e){let t=f().prepare(`SELECT id, first_user_message FROM sessions
1208
- WHERE first_user_message IS NOT NULL AND first_user_message != ''`).all(),n=new Map;for(let r of t)for(let o of UE){o.lastIndex=0;let a=r.first_user_message.match(o);if(a)for(let c of a){let u=n.get(c);u||(u=new Set,n.set(c,u)),u.add(r.id)}}let s=[];for(let[r,o]of n.entries())o.size<$E||s.push({type:"plan-file",pattern:r,suggested_name:r,suggested_parent_collection_id:null,session_count:o.size,detected_at:e,dismissed:!1});return s}function hs(e){return e.replace(/[\\%_]/g,"\\$&")}function wt(){try{z(),CE(_s)||vE(_s,{recursive:!0});let e=f(),t=e.prepare("SELECT * FROM auto_collection_rules ORDER BY created_at, id").all(),n=e.prepare("SELECT * FROM auto_collection_suggestions ORDER BY detected_at DESC, id").all();gl(ME,JSON.stringify({schema:"claude-recall.auto-rules.v1",backed_up_at:new Date().toISOString(),rules:t},null,2)),gl(DE,JSON.stringify({schema:"claude-recall.auto-suggestions.v1",backed_up_at:new Date().toISOString(),suggestions:n},null,2))}catch(e){console.error("[auto-collections] backup failed:",e)}}function wl(){let e=f().prepare("SELECT DISTINCT collection_id FROM auto_collection_rules").all();return new Set(e.map(t=>t.collection_id))}var VE=/^[ \t]*<!--\s*claude-recall-alias\s*:\s*([^\n]+?)\s*-->[ \t]*\n?/;function fo(e){if(e==null)return{alias:null,stripped:""};let t=e.match(VE);if(!t)return{alias:null,stripped:e};let n=t[1].trim();return n?{alias:n.length>200?n.slice(0,200):n,stripped:e.slice(t[0].length)}:{alias:null,stripped:e.slice(t[0].length)}}var Ss=new Map;function Rl(e,t){let s=(Ss.get(e)??Promise.resolve()).catch(()=>{}).then(t);return Ss.set(e,s),s.catch(()=>{}).finally(()=>{Ss.get(e)===s&&Ss.delete(e)}),s}var tb=1500,ho=new Map;function xl(e){let t=e.split(/[/\\]/),n=t.findIndex(s=>s==="projects");return n===-1||n+1>=t.length?null:t[n+1]??null}function Nl(e){return e.replace(/\\/g,"/").includes("/subagents/")}function nb(e){let s=f().prepare("SELECT COUNT(*) AS n FROM sessions WHERE file_path = ?").get(e).n;console.log(`[watcher] indexed ${Al(e)} (${s} session${s===1?"":"s"})`)}async function sb(e){let t=0;try{t=Eo(e).mtimeMs}catch{return}let n=xl(e);if(!n)return;let s=f(),r=s.prepare("SELECT id, file_mtime FROM sessions WHERE file_path = ? LIMIT 1").get(e);if(r&&r.file_mtime>=t)return;let o=new Map,a=null;for await(let R of Tc(e)){let w=o.get(R.sessionId);if(w||(w={sessionId:R.sessionId,entries:[],earliest:null,latest:null,firstUser:null,users:0,assistants:0,cwd:null,branch:null,version:null},o.set(R.sessionId,w)),w.entries.push(R),R.timestamp&&((!w.earliest||R.timestamp<w.earliest)&&(w.earliest=R.timestamp),(!w.latest||R.timestamp>w.latest)&&(w.latest=R.timestamp)),R.role==="user"&&!R.isSidechain){if(w.users+=1,!w.firstUser&&R.contentText){let j=R.contentText.replace(/^(?:<[^>]+>[\s\S]*?<\/[^>]+>\s*)+/,"").trim();j&&!/^<local-command-caveat>/.test(j)&&(w.firstUser=Se(j).redacted.slice(0,2e3))}}else R.role==="assistant"&&!R.isSidechain&&(w.assistants+=1);!w.cwd&&R.cwd&&(w.cwd=R.cwd),!w.branch&&R.gitBranch&&(w.branch=R.gitBranch),!w.version&&R.version&&(w.version=R.version),!a&&R.cwd&&(a=R.cwd)}let c=a?Al(a)||a:n,u=a??n.replace(/^-/,"/").replace(/-/g,"/"),d=s.prepare(`INSERT INTO projects (encoded_path, decoded_path, name)
1207
+ VALUES (?, ?, ?, ?, ?, ?, ?, 0)`).run(mo(),c.type,c.pattern,c.suggested_name,c.suggested_parent_collection_id,c.session_count,t)}return wt(),bs()}function nb(e,t){let s=f().prepare("SELECT id, cwd FROM sessions WHERE cwd IS NOT NULL AND cwd != ''").all(),r=new Map;for(let a of s){let c=a.cwd.split("/").filter(Boolean),u="";for(let d of c){if(u=`${u}/${d}`,u===e||u==="/")continue;let m=r.get(u);m||(m=new Set,r.set(u,m)),m.add(a.id)}}let o=[];for(let[a,c]of r.entries()){if(c.size<Sl)continue;let u=!1;for(let[d,m]of r.entries())if(d!==a&&d.startsWith(a+"/")&&m.size>=Sl){u=!0;break}u||o.push({type:"cwd-prefix",pattern:a,suggested_name:HE(a)||a,suggested_parent_collection_id:null,session_count:c.size,detected_at:t,dismissed:!1})}return o}function sb(e){return f().prepare("SELECT tag, COUNT(*) AS n FROM session_tags GROUP BY tag HAVING n >= ?").all(JE).map(n=>({type:"tag",pattern:n.tag,suggested_name:n.tag,suggested_parent_collection_id:null,session_count:n.n,detected_at:e,dismissed:!1}))}function rb(e){let t=f().prepare(`SELECT id, first_user_message FROM sessions
1208
+ WHERE first_user_message IS NOT NULL AND first_user_message != ''`).all(),n=new Map;for(let r of t)for(let o of YE){o.lastIndex=0;let a=r.first_user_message.match(o);if(a)for(let c of a){let u=n.get(c);u||(u=new Set,n.set(c,u)),u.add(r.id)}}let s=[];for(let[r,o]of n.entries())o.size<GE||s.push({type:"plan-file",pattern:r,suggested_name:r,suggested_parent_collection_id:null,session_count:o.size,detected_at:e,dismissed:!1});return s}function Es(e){return e.replace(/[\\%_]/g,"\\$&")}function wt(){try{z(),$E(fs)||UE(fs,{recursive:!0});let e=f(),t=e.prepare("SELECT * FROM auto_collection_rules ORDER BY created_at, id").all(),n=e.prepare("SELECT * FROM auto_collection_suggestions ORDER BY detected_at DESC, id").all();bl(WE,JSON.stringify({schema:"claude-recall.auto-rules.v1",backed_up_at:new Date().toISOString(),rules:t},null,2)),bl(qE,JSON.stringify({schema:"claude-recall.auto-suggestions.v1",backed_up_at:new Date().toISOString(),suggestions:n},null,2))}catch(e){console.error("[auto-collections] backup failed:",e)}}function Nl(){let e=f().prepare("SELECT DISTINCT collection_id FROM auto_collection_rules").all();return new Set(e.map(t=>t.collection_id))}var ob=/^[ \t]*<!--\s*claude-recall-alias\s*:\s*([^\n]+?)\s*-->[ \t]*\n?/;function ho(e){if(e==null)return{alias:null,stripped:""};let t=e.match(ob);if(!t)return{alias:null,stripped:e};let n=t[1].trim();return n?{alias:n.length>200?n.slice(0,200):n,stripped:e.slice(t[0].length)}:{alias:null,stripped:e.slice(t[0].length)}}var Ts=new Map;function Ol(e,t){let s=(Ts.get(e)??Promise.resolve()).catch(()=>{}).then(t);return Ts.set(e,s),s.catch(()=>{}).finally(()=>{Ts.get(e)===s&&Ts.delete(e)}),s}var lb=1500,Eo=new Map;function vl(e){let t=e.split(/[/\\]/),n=t.findIndex(s=>s==="projects");return n===-1||n+1>=t.length?null:t[n+1]??null}function Il(e){return e.replace(/\\/g,"/").includes("/subagents/")}function ub(e){let s=f().prepare("SELECT COUNT(*) AS n FROM sessions WHERE file_path = ?").get(e).n;console.log(`[watcher] indexed ${Cl(e)} (${s} session${s===1?"":"s"})`)}async function db(e){let t=0;try{t=bo(e).mtimeMs}catch{return}let n=vl(e);if(!n)return;let s=f(),r=s.prepare("SELECT id, file_mtime FROM sessions WHERE file_path = ? LIMIT 1").get(e);if(r&&r.file_mtime>=t)return;let o=new Map,a=null;for await(let L of Ac(e)){let x=o.get(L.sessionId);if(x||(x={sessionId:L.sessionId,entries:[],earliest:null,latest:null,firstUser:null,users:0,assistants:0,cwd:null,branch:null,version:null},o.set(L.sessionId,x)),x.entries.push(L),L.timestamp&&((!x.earliest||L.timestamp<x.earliest)&&(x.earliest=L.timestamp),(!x.latest||L.timestamp>x.latest)&&(x.latest=L.timestamp)),L.role==="user"&&!L.isSidechain){if(x.users+=1,!x.firstUser&&L.contentText){let F=L.contentText.replace(/^(?:<[^>]+>[\s\S]*?<\/[^>]+>\s*)+/,"").trim();F&&!/^<local-command-caveat>/.test(F)&&(x.firstUser=Se(F).redacted.slice(0,2e3))}}else L.role==="assistant"&&!L.isSidechain&&(x.assistants+=1);!x.cwd&&L.cwd&&(x.cwd=L.cwd),!x.branch&&L.gitBranch&&(x.branch=L.gitBranch),!x.version&&L.version&&(x.version=L.version),!a&&L.cwd&&(a=L.cwd)}let c=a?Cl(a)||a:n,u=a??n.replace(/^-/,"/").replace(/-/g,"/"),d=s.prepare(`INSERT INTO projects (encoded_path, decoded_path, name)
1209
1209
  VALUES (?, ?, ?)
1210
1210
  ON CONFLICT(encoded_path) DO UPDATE SET decoded_path = excluded.decoded_path, name = excluded.name
1211
1211
  RETURNING id`),m=s.prepare(`
@@ -1236,8 +1236,25 @@ ${h+1}. ${S}`:`${h+1}. ${S}`}).join(`
1236
1236
  VALUES (@uuid, @session_id, @parent_uuid, @type, @role, @timestamp,
1237
1237
  @is_sidechain, @content_text, @tool_names, @raw_json)
1238
1238
  ON CONFLICT(uuid) DO NOTHING
1239
- `),S=s.prepare("DELETE FROM messages WHERE session_id = ?"),b=new Date().toISOString();if(s.transaction(()=>{let{id:R}=d.get(n,u,c);for(let w of o.values()){if(Hc(w.firstUser)){console.log(`[watcher] skipping daemon-spawn phantom ${w.sessionId} (first message matches autonomous-spawn pattern)`);continue}let j=fo(w.firstUser),M=j.alias?j.stripped:w.firstUser;if(m.run({id:w.sessionId,project_id:R,file_path:e,file_mtime:t,started_at:w.earliest,ended_at:w.latest,message_count:w.entries.length,user_message_count:w.users,assistant_message_count:w.assistants,first_user_message:M,cwd:w.cwd,git_branch:w.branch,version:w.version,indexed_at:b}),j.alias&&!Te(w.sessionId))try{he(w.sessionId,j.alias)}catch(W){console.error(`[watcher] header-alias setAlias failed for ${w.sessionId}:`,W)}S.run(w.sessionId);for(let W of w.entries)h.run(rb(W));jc(s,w.sessionId,w.entries),rs(s,w.sessionId)}})(),rt().heuristicEnabled)for(let R of o.values()){let w=fo(R.firstUser).stripped,j=yt(w);j&&Ee(R.sessionId,j,"heuristic")}}function Ol(e){return Rl(e,()=>sb(e))}function rb(e){let t=Se(e.contentText).redacted,n=Se(e.raw).redacted;return{uuid:e.uuid,session_id:e.sessionId,parent_uuid:e.parentUuid,type:e.type,role:e.role,timestamp:e.timestamp,is_sidechain:e.isSidechain?1:0,content_text:t,tool_names:e.toolNames.join(","),raw_json:n}}function kl(e){let t=ho.get(e);t?.timer&&clearTimeout(t.timer);let n={timer:null};n.timer=setTimeout(()=>{ho.delete(e),Ol(e).then(async()=>{nb(e),ns(e);try{let r=f().prepare("SELECT id FROM sessions WHERE file_path = ?").all(e);for(let o of r){za(o.id),Fc(o.id);try{hl(o.id)}catch(a){console.error("[watcher] auto-collections apply failed:",a)}}}catch(s){console.error("[watcher] semantic dispatch failed:",s)}}).catch(s=>{console.error(`[watcher] reindex failed for ${e}:`,s)})},tb),ho.set(e,n)}function Ll(){let e=ZE(Ut,{depth:4,ignoreInitial:!0,persistent:!0,awaitWriteFinish:{stabilityThreshold:500,pollInterval:200},ignored:t=>{if(t.endsWith(".jsonl"))return!1;try{if(Eo(t).isDirectory())return!1}catch{}return!0}});return e.on("add",t=>t.endsWith(".jsonl")&&kl(t)),e.on("change",t=>t.endsWith(".jsonl")&&kl(t)),e.on("ready",()=>{console.log(`[watcher] ready, watching ${Ut}`)}),e.on("error",t=>{console.error("[watcher] chokidar error:",t)}),process.env.RECALL_WATCHER_DEBUG==="1"&&(e.on("add",t=>console.log(`[watcher.debug] add: ${t}`)),e.on("change",t=>console.log(`[watcher.debug] change: ${t}`)),e.on("unlink",t=>console.log(`[watcher.debug] unlink: ${t}`))),e}var ob=4;function*bo(e){let t;try{t=QE(e,{withFileTypes:!0,encoding:"utf8"})}catch{return}for(let n of t){if(n.isSymbolicLink())continue;let s=eb(e,n.name);n.isDirectory()?yield*bo(s):n.isFile()&&n.name.endsWith(".jsonl")&&(yield s)}}async function So(){let e=Date.now(),t={scanned:0,reindexed:0,upToDate:0,skipped:0,errors:0,durationMs:0},n=f(),s=[],r=n.prepare("SELECT file_mtime FROM sessions WHERE file_path = ? LIMIT 1");for(let d of bo(Ut)){if(t.scanned+=1,Nl(d)){t.skipped+=1;continue}let m;try{m=Eo(d).mtimeMs}catch{t.errors+=1;continue}let h=r.get(d);if(h&&h.file_mtime>=m){t.upToDate+=1;continue}s.push(d)}if(s.length===0)return t.durationMs=Date.now()-e,t;let o=s.slice(),a=async()=>{for(;o.length>0;){let d=o.shift();if(!d)break;try{await Ol(d),t.reindexed+=1}catch(m){t.errors+=1;let h=m instanceof Error?m.message:String(m);console.error(`[ingestion-sweep] failed for ${d}: ${h}`)}}},c=Math.min(ob,s.length),u=[];for(let d=0;d<c;d+=1)u.push(a());return await Promise.all(u),t.durationMs=Date.now()-e,t}async function Cl(){try{let e=await So();e.reindexed>0&&console.log(`[safety-sweep] reindexed ${e.reindexed} file(s) the watcher missed (scanned=${e.scanned}, upToDate=${e.upToDate})`)}catch(e){console.error("[safety-sweep] failed:",e)}}import{statSync as ib}from"node:fs";function To(e){if(e instanceof Error)return e.stack??e.message;try{return JSON.stringify(e)}catch{return String(e)}}var ab=6e4,cb=5*6e4,vl=1073741824,lb=5368709120,ub=6e4,db=100;function yo(e,t="PASSIVE",n){let s=Date.now(),r=e.pragma(`wal_checkpoint(${t})`),o=pb(r),a={busy:o.busy,log:o.log,moved:o.checkpointed,mode:t,durationMs:Date.now()-s};return n&&(t==="PASSIVE"&&a.log>=db&&a.moved===0?n(`[wal-maintenance] PASSIVE checkpoint blocked: log=${a.log} frames pending, moved=0 (readers holding snapshots)`):a.moved>0&&n(`[wal-maintenance] ${t} checkpoint: log=${a.log} moved=${a.moved} busy=${a.busy} (${a.durationMs}ms)`)),a}function Il(e){let t=e.db,n=e.walPath,s=e.checkpointEveryMs??ab,r=e.sizeCheckEveryMs??cb,o=e.warnBytes??vl,a=e.errorBytes??lb,c=e.forceRestartCooldownMs??ub,u=e.logger??(w=>{process.stderr.write(w+`
1240
- `)}),d=e.statFn??(w=>ib(w)),m=0,h=null,S=()=>{try{yo(t,"PASSIVE",u).moved>0&&(h=Date.now())}catch(w){u(`[wal-maintenance] PASSIVE checkpoint threw: ${To(w)}`)}},b=()=>{let w;try{w=d(n).size}catch(j){let M=j.code;if(M!=="ENOENT"){let W=j instanceof Error?j.message:String(j);u(`[wal-maintenance] WAL stat failed (${M??"unknown"}): ${W}`)}return}if(w>=a){u(`[wal-maintenance] ERROR: WAL ${Ts(w)} exceeds error threshold ${Ts(a)}`);let j=Date.now();if(j-m>=c){m=j;try{let M=yo(t,"RESTART",u);u(`[wal-maintenance] forced RESTART: moved=${M.moved} busy=${M.busy} log=${M.log} (${M.durationMs}ms)`),M.moved>0&&(h=Date.now())}catch(M){u(`[wal-maintenance] forced RESTART threw: ${To(M)}`)}}}else w>=o&&u(`[wal-maintenance] WARN: WAL ${Ts(w)} exceeds warn threshold ${Ts(o)}`)},T=setInterval(S,s),R=setInterval(b,r);return typeof T.unref=="function"&&T.unref(),typeof R.unref=="function"&&R.unref(),{stop:()=>{clearInterval(T),clearInterval(R)},checkpointNow:(w="PASSIVE")=>{let j=yo(t,w,u);return j.moved>0&&(h=Date.now()),j},walSizeBytes:()=>{try{return d(n).size}catch{return 0}},lastCheckpointAt:()=>h}}function pb(e){let t=Array.isArray(e)?e[0]??{}:e??{};return{busy:wo(t.busy),log:wo(t.log),checkpointed:wo(t.checkpointed)}}function wo(e){return typeof e=="number"&&Number.isFinite(e)?e:typeof e=="bigint"?Number(e):0}function Ts(e){return e>=1e9?`${(e/1e9).toFixed(2)} GB`:e>=1e6?`${(e/1e6).toFixed(0)} MB`:e>=1e3?`${(e/1e3).toFixed(0)} KB`:`${e} B`}var gb=["VS Code","VS Code Insiders","Cursor","Windsurf","Warp","iTerm","Terminal","WezTerm","Windows Terminal","Kitty","Alacritty"],Gx=new RegExp(`^(${gb.map(e=>e.replace(/ /g,"\\s")).join("|")})\\s\xB7\\s`);var zx=5*6e4;function Ro(){try{let e=mb(H);return Number(e.bavail)*Number(e.bsize)}catch{return 0}}function jl(e){let{projects:t,sessions:n,messages:s,port:r,version:o}=e;return`<!DOCTYPE html>
1239
+ `),b=s.prepare("DELETE FROM messages WHERE session_id = ?"),S=s.prepare(`
1240
+ INSERT INTO sessions (
1241
+ id, project_id, file_path, file_mtime,
1242
+ started_at, ended_at, message_count,
1243
+ user_message_count, assistant_message_count,
1244
+ first_user_message, cwd, git_branch, version, indexed_at,
1245
+ skipped_reason
1246
+ ) VALUES (@id, @project_id, @file_path, @file_mtime, @started_at, @ended_at, 0,
1247
+ 0, 0, NULL, @cwd, NULL, NULL, @indexed_at,
1248
+ 'daemon_spawn_phantom')
1249
+ ON CONFLICT(id) DO UPDATE SET
1250
+ file_path = excluded.file_path,
1251
+ file_mtime = excluded.file_mtime,
1252
+ indexed_at = excluded.indexed_at,
1253
+ skipped_reason = 'daemon_spawn_phantom'
1254
+ `),T=new Date().toISOString(),R=new Set;if(s.transaction(()=>{let{id:L}=d.get(n,u,c);for(let x of o.values()){if(Gc(x.firstUser)){console.log(`[watcher] skipping daemon-spawn phantom ${x.sessionId} (first message matches autonomous-spawn pattern)`),b.run(x.sessionId),S.run({id:x.sessionId,project_id:L,file_path:e,file_mtime:t,started_at:x.earliest,ended_at:x.latest,cwd:x.cwd,indexed_at:T}),R.add(x.sessionId);continue}let F=ho(x.firstUser),A=F.alias?F.stripped:x.firstUser;if(m.run({id:x.sessionId,project_id:L,file_path:e,file_mtime:t,started_at:x.earliest,ended_at:x.latest,message_count:x.entries.length,user_message_count:x.users,assistant_message_count:x.assistants,first_user_message:A,cwd:x.cwd,git_branch:x.branch,version:x.version,indexed_at:T}),F.alias&&!Te(x.sessionId))try{he(x.sessionId,F.alias)}catch($){console.error(`[watcher] header-alias setAlias failed for ${x.sessionId}:`,$)}b.run(x.sessionId);for(let $ of x.entries)h.run(pb($));$c(s,x.sessionId,x.entries),os(s,x.sessionId)}})(),st().heuristicEnabled)for(let L of o.values()){if(R.has(L.sessionId))continue;let x=ho(L.firstUser).stripped,F=yt(x);F&&Ee(L.sessionId,F,"heuristic")}}function jl(e){return Ol(e,()=>db(e))}function pb(e){let t=Se(e.contentText).redacted,n=Se(e.raw).redacted;return{uuid:e.uuid,session_id:e.sessionId,parent_uuid:e.parentUuid,type:e.type,role:e.role,timestamp:e.timestamp,is_sidechain:e.isSidechain?1:0,content_text:t,tool_names:e.toolNames.join(","),raw_json:n}}function Ll(e){let t=Eo.get(e);t?.timer&&clearTimeout(t.timer);let n={timer:null};n.timer=setTimeout(()=>{Eo.delete(e),jl(e).then(async()=>{ub(e),ss(e);try{let r=f().prepare("SELECT id FROM sessions WHERE file_path = ? AND skipped_reason IS NULL").all(e);for(let o of r){ec(o.id),Hc(o.id);try{yl(o.id)}catch(a){console.error("[watcher] auto-collections apply failed:",a)}}}catch(s){console.error("[watcher] semantic dispatch failed:",s)}}).catch(s=>{console.error(`[watcher] reindex failed for ${e}:`,s)})},lb),Eo.set(e,n)}function Ml(){let e=ib(Ut,{depth:4,ignoreInitial:!0,persistent:!0,awaitWriteFinish:{stabilityThreshold:500,pollInterval:200},ignored:t=>{if(t.endsWith(".jsonl"))return!1;try{if(bo(t).isDirectory())return!1}catch{}return!0}});return e.on("add",t=>t.endsWith(".jsonl")&&Ll(t)),e.on("change",t=>t.endsWith(".jsonl")&&Ll(t)),e.on("ready",()=>{console.log(`[watcher] ready, watching ${Ut}`)}),e.on("error",t=>{console.error("[watcher] chokidar error:",t)}),process.env.RECALL_WATCHER_DEBUG==="1"&&(e.on("add",t=>console.log(`[watcher.debug] add: ${t}`)),e.on("change",t=>console.log(`[watcher.debug] change: ${t}`)),e.on("unlink",t=>console.log(`[watcher.debug] unlink: ${t}`))),e}var mb=4;function*So(e){let t;try{t=ab(e,{withFileTypes:!0,encoding:"utf8"})}catch{return}for(let n of t){if(n.isSymbolicLink())continue;let s=cb(e,n.name);n.isDirectory()?yield*So(s):n.isFile()&&n.name.endsWith(".jsonl")&&(yield s)}}async function To(){let e=Date.now(),t={scanned:0,reindexed:0,upToDate:0,skipped:0,errors:0,durationMs:0},n=f(),s=[],r=n.prepare("SELECT file_mtime FROM sessions WHERE file_path = ? LIMIT 1");for(let d of So(Ut)){if(t.scanned+=1,Il(d)){t.skipped+=1;continue}let m;try{m=bo(d).mtimeMs}catch{t.errors+=1;continue}let h=r.get(d);if(h&&h.file_mtime>=m){t.upToDate+=1;continue}s.push(d)}if(s.length===0)return t.durationMs=Date.now()-e,t;let o=s.slice(),a=async()=>{for(;o.length>0;){let d=o.shift();if(!d)break;try{await jl(d),t.reindexed+=1}catch(m){t.errors+=1;let h=m instanceof Error?m.message:String(m);console.error(`[ingestion-sweep] failed for ${d}: ${h}`)}}},c=Math.min(mb,s.length),u=[];for(let d=0;d<c;d+=1)u.push(a());return await Promise.all(u),t.durationMs=Date.now()-e,t}async function Dl(){try{let e=await To();e.reindexed>0&&console.log(`[safety-sweep] reindexed ${e.reindexed} file(s) the watcher missed (scanned=${e.scanned}, upToDate=${e.upToDate})`)}catch(e){console.error("[safety-sweep] failed:",e)}}import{execFileSync as Pl}from"node:child_process";function yo(e={}){let t=e.psOutput??gb(),n=e.isProcessAlive??_b,s=e.getParentCommand??fb,r=[];for(let o of t.split(`
1255
+ `)){let a=o.trim();if(!a||!a.includes("dist/mcp/server.js")||hb(a))continue;let c=a.split(/\s+/);if(c.length<5)continue;let u=Number(c[0]),d=Number(c[1]),m=c[2],h=Number(c[3]);if(!Number.isFinite(u)||!Number.isFinite(d))continue;let b=d>1&&n(d);r.push({pid:u,ppid:d,parentAlive:b,etimeSeconds:Eb(m),pcpu:Number.isFinite(h)?h:0,orphan:!b,parentCommand:b?s(d):null})}return r}function gb(){try{return Pl("ps",["-eo","pid,ppid,etime,pcpu,command"],{encoding:"utf8",timeout:2e3,maxBuffer:5*1024*1024})}catch(e){let t=e instanceof Error?e.message:String(e);return process.stderr.write(`[mcp-processes] ps -eo failed: ${t}
1256
+ `),""}}function _b(e){if(!Number.isFinite(e)||e<=1)return!1;try{return process.kill(e,0),!0}catch{return!1}}function fb(e){if(!Number.isFinite(e)||e<=1)return null;try{let n=Pl("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 hb(e){let t=e.split(/\s+/);if(t.length<5)return!1;let n=t[4]??"";return n.endsWith("/grep")||n==="grep"||n.endsWith("/awk")||n==="awk"||n.endsWith("/rg")||n==="rg"}function Eb(e){if(!e)return 0;let t=0,n=e,s=e.indexOf("-");s>=0&&(t=Fl(e.slice(0,s)),n=e.slice(s+1));let r=n.split(":").map(Fl),o=0,a=0,c=0;return r.length===3?[o,a,c]=r:r.length===2?[a,c]=r:r.length===1&&(c=r[0]),t*86400+o*3600+a*60+c}function Fl(e){let t=Number(e);return Number.isFinite(t)?t:0}var bb=50,Sb=60;function wo(e){return e.pcpu>=bb&&e.etimeSeconds>=Sb}import{statSync as Tb}from"node:fs";function Ro(e){if(e instanceof Error)return e.stack??e.message;try{return JSON.stringify(e)}catch{return String(e)}}var yb=6e4,wb=5*6e4,$l=1073741824,Rb=5368709120,kb=6e4,Ab=100;function ko(e,t="PASSIVE",n){let s=Date.now(),r=e.pragma(`wal_checkpoint(${t})`),o=Nb(r),a={busy:o.busy,log:o.log,moved:o.checkpointed,mode:t,durationMs:Date.now()-s};return n&&(t==="PASSIVE"&&a.log>=Ab&&a.moved===0?n(`[wal-maintenance] PASSIVE checkpoint blocked: log=${a.log} frames pending, moved=0 (readers holding snapshots)`):a.moved>0&&n(`[wal-maintenance] ${t} checkpoint: log=${a.log} moved=${a.moved} busy=${a.busy} (${a.durationMs}ms)`)),a}function Ul(e){let t=e.db,n=e.walPath,s=e.checkpointEveryMs??yb,r=e.sizeCheckEveryMs??wb,o=e.warnBytes??$l,a=e.errorBytes??Rb,c=e.forceRestartCooldownMs??kb,u=e.logger??(L=>{process.stderr.write(L+`
1257
+ `)}),d=e.statFn??(L=>Tb(L)),m=e.describeSuspectsFn??xb,h=0,b=null,S=()=>{try{ko(t,"PASSIVE",u).moved>0&&(b=Date.now())}catch(L){u(`[wal-maintenance] PASSIVE checkpoint threw: ${Ro(L)}`)}},T=()=>{let L;try{L=d(n).size}catch(x){let F=x.code;if(F!=="ENOENT"){let A=x instanceof Error?x.message:String(x);u(`[wal-maintenance] WAL stat failed (${F??"unknown"}): ${A}`)}return}if(L>=a){u(`[wal-maintenance] ERROR: WAL ${ys(L)} exceeds error threshold ${ys(a)}`);let x=m();x&&u(`[wal-maintenance] ${x}`);let F=Date.now();if(F-h>=c){h=F;try{let A=ko(t,"RESTART",u);u(`[wal-maintenance] forced RESTART: moved=${A.moved} busy=${A.busy} log=${A.log} (${A.durationMs}ms)`),A.moved>0&&(b=Date.now())}catch(A){u(`[wal-maintenance] forced RESTART threw: ${Ro(A)}`)}}}else L>=o&&u(`[wal-maintenance] WARN: WAL ${ys(L)} exceeds warn threshold ${ys(o)}`)},R=setInterval(S,s),O=setInterval(T,r);return typeof R.unref=="function"&&R.unref(),typeof O.unref=="function"&&O.unref(),{stop:()=>{clearInterval(R),clearInterval(O)},checkpointNow:(L="PASSIVE")=>{let x=ko(t,L,u);return x.moved>0&&(b=Date.now()),x},walSizeBytes:()=>{try{return d(n).size}catch{return 0}},lastCheckpointAt:()=>b}}function xb(e={}){let n=(e.list??yo)();if(n.length===0)return null;let s=n.find(wo);if(s)return`pin suspect: pid ${s.pid} at ${s.pcpu.toFixed(0)}%cpu, elapsed ${s.etimeSeconds}s (parent ${s.parentCommand??s.ppid})`;let r=n.slice().sort((o,a)=>a.etimeSeconds-o.etimeSeconds)[0];return`pin suspect: pid ${r.pid}, elapsed ${r.etimeSeconds}s (parent ${r.parentCommand??r.ppid})`}function Nb(e){let t=Array.isArray(e)?e[0]??{}:e??{};return{busy:Ao(t.busy),log:Ao(t.log),checkpointed:Ao(t.checkpointed)}}function Ao(e){return typeof e=="number"&&Number.isFinite(e)?e:typeof e=="bigint"?Number(e):0}function ys(e){return e>=1e9?`${(e/1e9).toFixed(2)} GB`:e>=1e6?`${(e/1e6).toFixed(0)} MB`:e>=1e3?`${(e/1e3).toFixed(0)} KB`:`${e} B`}var Lb=["VS Code","VS Code Insiders","Cursor","Windsurf","Warp","iTerm","Terminal","WezTerm","Windows Terminal","Kitty","Alacritty"],hN=new RegExp(`^(${Lb.map(e=>e.replace(/ /g,"\\s")).join("|")})\\s\xB7\\s`);var EN=5*6e4;function xo(){try{let e=Ob(W);return Number(e.bavail)*Number(e.bsize)}catch{return 0}}function Bl(e){let{projects:t,sessions:n,messages:s,port:r,version:o}=e;return`<!DOCTYPE html>
1241
1258
  <html lang="en">
1242
1259
  <head>
1243
1260
  <meta charset="utf-8" />
@@ -1292,32 +1309,32 @@ ${h+1}. ${S}`:`${h+1}. ${S}`}).join(`
1292
1309
  </footer>
1293
1310
  </main>
1294
1311
  </body>
1295
- </html>`}var _b=/<(local-command-caveat|local-command-stdout|command-name|command-message|command-args|system-reminder|user-prompt-submit-hook|task-notification)[\s\S]*?<\/\1>/gi,fb=/⚡ \*\*Tool call · `[^`]+`\*\*\s*\n+```json\n[\s\S]*?\n```/g,hb=/\*\*Tool result\*\*\s*\n+```\n[\s\S]*?\n```/g;function Eb(e){return e.replace(_b,"").trim()}function bb(e){let t=e.replace(fb,"[tool call]");return t=t.replace(hb,"[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,`
1312
+ </html>`}var Cb=/<(local-command-caveat|local-command-stdout|command-name|command-message|command-args|system-reminder|user-prompt-submit-hook|task-notification)[\s\S]*?<\/\1>/gi,vb=/⚡ \*\*Tool call · `[^`]+`\*\*\s*\n+```json\n[\s\S]*?\n```/g,Ib=/\*\*Tool result\*\*\s*\n+```\n[\s\S]*?\n```/g;function jb(e){return e.replace(Cb,"").trim()}function Mb(e){let t=e.replace(vb,"[tool call]");return t=t.replace(Ib,"[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,`
1296
1313
 
1297
- `),t.trim()}function Sb(e){return e.role??e.type??"message"}function Ml(e,t,n={}){let s=n.mode??"condensed",r=n.includeSidechain===!0,o=n.since?Date.parse(n.since):0,a=t.filter(m=>!(!r&&m.is_sidechain===1||o&&m.timestamp&&Date.parse(m.timestamp)<o)),c=[];n.prelude&&(c.push(n.prelude.trim()),c.push("")),c.push(`# Claude Recall, past session context (${s})`),c.push(""),c.push(`- **Project**: ${e.project_name}`),e.decoded_path&&c.push(`- **Path**: \`${e.decoded_path}\``),c.push(`- **Session ID**: \`${e.id}\``),e.started_at&&c.push(`- **Started**: ${e.started_at}`),e.ended_at&&c.push(`- **Ended**: ${e.ended_at}`),e.git_branch&&c.push(`- **Branch**: \`${e.git_branch}\``),c.push(`- **Messages**: ${a.length}`),c.push(""),c.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."),c.push(""),c.push("---"),c.push("");let u=0,d=0;for(let m of a){let h=m.content_text??"",S=Eb(h);s==="condensed"&&(S=bb(S));let b=S.length>0,T=!!m.tool_names&&m.tool_names.length>0;if(!b&&!T){d+=1;continue}let R=Sb(m),w=m.timestamp?` \`${m.timestamp}\``:"";c.push(`## ${R}${w}`),c.push(""),T&&s==="condensed"&&(c.push(`_tools used: ${m.tool_names}_`),c.push("")),b&&(c.push(S),c.push("")),u+=1}return c.push("---"),c.push(""),c.push(`_${u} messages included_`+(d?`, ${d} empty skipped`:"")+(r?"":", subagent/sidechain hidden")+"."),c.join(`
1298
- `)}function on(e){if(!e.sessionStartedAt)return{allowed:!1,reason:"missing-session-started-at"};if(!e.terminalOpenedAt)return{allowed:!1,reason:"missing-terminal-opened-at"};let t=Date.parse(e.sessionStartedAt),n=Date.parse(e.terminalOpenedAt);return Number.isFinite(t)?Number.isFinite(n)?n-t>6e4?{allowed:!1,reason:"terminal-postdates-session"}:{allowed:!0}:{allowed:!1,reason:"missing-terminal-opened-at"}:{allowed:!1,reason:"missing-session-started-at"}}U();ee();import{writeFileSync as Tb,mkdirSync as yb,existsSync as wb}from"node:fs";import{join as Fl}from"node:path";var ko=Fl(H,"notes"),Dl=200,Rb=12e3,kb=800,Ab=8e3;function Pl(e){try{let t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return[]}function $l(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 xb(){z(),wb(ko)||yb(ko,{recursive:!0})}function Nb(e){return{session_id:e.session_id,content:e.content,updated_at:e.updated_at,previous_versions:Pl(e.previous_versions),auto_synopsis:e.auto_synopsis??null,auto_synopsis_generated_at:e.auto_synopsis_generated_at??null,auto_synopsis_history:$l(e.auto_synopsis_history)}}var Ob="session_id, content, updated_at, previous_versions, auto_synopsis, auto_synopsis_generated_at, auto_synopsis_history";function ys(e){let t=f().prepare(`SELECT ${Ob} FROM session_notes WHERE session_id = ?`).get(e);return t?Nb(t):null}function Ul(e,t){let n=f(),s=new Date().toISOString(),r=n.prepare("SELECT content, previous_versions FROM session_notes WHERE session_id = ?").get(e),o=[];return r&&(o=Pl(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)
1314
+ `),t.trim()}function Db(e){return e.role??e.type??"message"}function Hl(e,t,n={}){let s=n.mode??"condensed",r=n.includeSidechain===!0,o=n.since?Date.parse(n.since):0,a=t.filter(m=>!(!r&&m.is_sidechain===1||o&&m.timestamp&&Date.parse(m.timestamp)<o)),c=[];n.prelude&&(c.push(n.prelude.trim()),c.push("")),c.push(`# Claude Recall, past session context (${s})`),c.push(""),c.push(`- **Project**: ${e.project_name}`),e.decoded_path&&c.push(`- **Path**: \`${e.decoded_path}\``),c.push(`- **Session ID**: \`${e.id}\``),e.started_at&&c.push(`- **Started**: ${e.started_at}`),e.ended_at&&c.push(`- **Ended**: ${e.ended_at}`),e.git_branch&&c.push(`- **Branch**: \`${e.git_branch}\``),c.push(`- **Messages**: ${a.length}`),c.push(""),c.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."),c.push(""),c.push("---"),c.push("");let u=0,d=0;for(let m of a){let h=m.content_text??"",b=jb(h);s==="condensed"&&(b=Mb(b));let S=b.length>0,T=!!m.tool_names&&m.tool_names.length>0;if(!S&&!T){d+=1;continue}let R=Db(m),O=m.timestamp?` \`${m.timestamp}\``:"";c.push(`## ${R}${O}`),c.push(""),T&&s==="condensed"&&(c.push(`_tools used: ${m.tool_names}_`),c.push("")),S&&(c.push(b),c.push("")),u+=1}return c.push("---"),c.push(""),c.push(`_${u} messages included_`+(d?`, ${d} empty skipped`:"")+(r?"":", subagent/sidechain hidden")+"."),c.join(`
1315
+ `)}function on(e){if(!e.sessionStartedAt)return{allowed:!1,reason:"missing-session-started-at"};if(!e.terminalOpenedAt)return{allowed:!1,reason:"missing-terminal-opened-at"};let t=Date.parse(e.sessionStartedAt),n=Date.parse(e.terminalOpenedAt);return Number.isFinite(t)?Number.isFinite(n)?n-t>6e4?{allowed:!1,reason:"terminal-postdates-session"}:{allowed:!0}:{allowed:!1,reason:"missing-terminal-opened-at"}:{allowed:!1,reason:"missing-session-started-at"}}B();ee();import{writeFileSync as Fb,mkdirSync as Pb,existsSync as $b}from"node:fs";import{join as ql}from"node:path";var No=ql(W,"notes"),Wl=200,Ub=12e3,Bb=800,Hb=8e3;function Xl(e){try{let t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return[]}function Jl(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 Wb(){z(),$b(No)||Pb(No,{recursive:!0})}function qb(e){return{session_id:e.session_id,content:e.content,updated_at:e.updated_at,previous_versions:Xl(e.previous_versions),auto_synopsis:e.auto_synopsis??null,auto_synopsis_generated_at:e.auto_synopsis_generated_at??null,auto_synopsis_history:Jl(e.auto_synopsis_history)}}var Xb="session_id, content, updated_at, previous_versions, auto_synopsis, auto_synopsis_generated_at, auto_synopsis_history";function ws(e){let t=f().prepare(`SELECT ${Xb} FROM session_notes WHERE session_id = ?`).get(e);return t?qb(t):null}function Gl(e,t){let n=f(),s=new Date().toISOString(),r=n.prepare("SELECT content, previous_versions FROM session_notes WHERE session_id = ?").get(e),o=[];return r&&(o=Xl(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)
1299
1316
  VALUES (?, ?, ?, ?)
1300
1317
  ON CONFLICT(session_id) DO UPDATE SET
1301
1318
  content = excluded.content,
1302
1319
  updated_at = excluded.updated_at,
1303
- previous_versions = excluded.previous_versions`).run(e,t,s,JSON.stringify(o)),Cb(e,t,s),ys(e)??{session_id:e,content:t,updated_at:s,previous_versions:o,auto_synopsis:null,auto_synopsis_generated_at:null,auto_synopsis_history:[]}}async function Bl(e){let n=f().prepare(`SELECT rowid AS rid, role, content_text
1320
+ previous_versions = excluded.previous_versions`).run(e,t,s,JSON.stringify(o)),Gb(e,t,s),ws(e)??{session_id:e,content:t,updated_at:s,previous_versions:o,auto_synopsis:null,auto_synopsis_generated_at:null,auto_synopsis_history:[]}}async function Yl(e){let n=f().prepare(`SELECT rowid AS rid, role, content_text
1304
1321
  FROM messages
1305
1322
  WHERE session_id = ? AND is_sidechain = 0
1306
1323
  AND content_text IS NOT NULL AND content_text != ''
1307
1324
  AND role IN ('user', 'assistant')
1308
1325
  ORDER BY COALESCE(timestamp, '') DESC, rowid DESC
1309
- LIMIT ?`).all(e,Dl);if(n.length===0)throw new Error("no messages available to summarise");let s=Rb,r=[];for(let S of n){if(s<=0)break;let b=(S.content_text??"").slice(0,kb);r.push({rid:S.rid,role:S.role,content:b}),s-=b.length}r.reverse();let o=n.length===Dl||s<=0,a=r.map(S=>`**${S.role}**: ${S.content}`).join(`
1326
+ LIMIT ?`).all(e,Wl);if(n.length===0)throw new Error("no messages available to summarise");let s=Ub,r=[];for(let b of n){if(s<=0)break;let S=(b.content_text??"").slice(0,Bb);r.push({rid:b.rid,role:b.role,content:S}),s-=S.length}r.reverse();let o=n.length===Wl||s<=0,a=r.map(b=>`**${b.role}**: ${b.content}`).join(`
1310
1327
 
1311
1328
  `),c=["You will receive a sampled chronological transcript from a Claude Code session.",o?"The sample is the most recent slice that fits in the context budget; older messages were dropped.":"The full session is included.","","Write a clean markdown synopsis of the session. Use these sections \u2014 omit any that genuinely have nothing to say:","","## Goal","One sentence \u2014 what the user was trying to accomplish.","","## What was done","Bullet list \u2014 concrete actions, code changes, decisions. Skip pleasantries.","","## Key decisions","Bullet list \u2014 non-obvious choices and the reason behind them.","","## Files touched","Bullet list \u2014 file paths mentioned in the conversation. Omit the section if none.","","## Open follow-ups","Bullet list \u2014 anything left undone or flagged for later. Omit the section if none.","","Output ONLY the markdown \u2014 no surrounding prose, no code fences around the whole thing, no closing summary.","","---","",a].join(`
1312
- `),{spawnClaudePrompt:u,isClaudeCliAvailable:d}=await Promise.resolve().then(()=>(ye(),tt));if(!d())throw new Error("claude CLI not found on PATH");let m=await u(c,[],{});if(!m.success)throw new Error(`claude CLI exited ${m.exitCode}: ${m.stderr.slice(-500)}`);let h=Lb(m.stdout);if(!h)throw new Error("claude CLI returned an empty synopsis");return h.slice(0,Ab)}function Lb(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 s.trim()}}catch{}return t}function Hl(e,t){let n=f(),s=new Date().toISOString(),r=Date.now(),o=n.prepare("SELECT auto_synopsis, auto_synopsis_history, content, updated_at FROM session_notes WHERE session_id = ?").get(e),a=$l(o?.auto_synopsis_history??null);return o?.auto_synopsis&&o.auto_synopsis!==t&&o.auto_synopsis.length>0&&a.push({synopsis:o.auto_synopsis,replaced_at:s}),o?n.prepare(`UPDATE session_notes
1329
+ `),{spawnClaudePrompt:u,isClaudeCliAvailable:d}=await Promise.resolve().then(()=>(ye(),et));if(!d())throw new Error("claude CLI not found on PATH");let m=await u(c,[],{});if(!m.success)throw new Error(`claude CLI exited ${m.exitCode}: ${m.stderr.slice(-500)}`);let h=Jb(m.stdout);if(!h)throw new Error("claude CLI returned an empty synopsis");return h.slice(0,Hb)}function Jb(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 s.trim()}}catch{}return t}function zl(e,t){let n=f(),s=new Date().toISOString(),r=Date.now(),o=n.prepare("SELECT auto_synopsis, auto_synopsis_history, content, updated_at FROM session_notes WHERE session_id = ?").get(e),a=Jl(o?.auto_synopsis_history??null);return o?.auto_synopsis&&o.auto_synopsis!==t&&o.auto_synopsis.length>0&&a.push({synopsis:o.auto_synopsis,replaced_at:s}),o?n.prepare(`UPDATE session_notes
1313
1330
  SET auto_synopsis = ?,
1314
1331
  auto_synopsis_generated_at = ?,
1315
1332
  auto_synopsis_history = ?
1316
1333
  WHERE session_id = ?`).run(t,r,JSON.stringify(a),e):n.prepare(`INSERT INTO session_notes
1317
1334
  (session_id, content, updated_at, previous_versions, auto_synopsis,
1318
1335
  auto_synopsis_generated_at, auto_synopsis_history)
1319
- VALUES (?, '', ?, '[]', ?, ?, ?)`).run(e,s,t,r,JSON.stringify(a)),ys(e)}function Cb(e,t,n){try{xb();let s=Fl(ko,`${e}.md`),r=`<!-- Claude Recall note \xB7 session ${e} \xB7 updated ${n} -->
1320
- `;Tb(s,r+t)}catch(s){console.error("[notes] mirror write failed:",s)}}pt();U();ee();import{randomUUID as Wl}from"node:crypto";import{writeFileSync as ql,readFileSync as aN,existsSync as vb,mkdirSync as Ib}from"node:fs";import{join as Ao}from"node:path";var ws=Ao(H,"threads"),jb=Ao(ws,"index.json");function Xl(){z(),vb(ws)||Ib(ws,{recursive:!0})}function xo(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 Jl(e){let t=new Map;if(e.length===0)return t;let n=f(),s=e.map(()=>"?").join(","),r=n.prepare(`SELECT te.thread_id AS thread_id,
1336
+ VALUES (?, '', ?, '[]', ?, ?, ?)`).run(e,s,t,r,JSON.stringify(a)),ws(e)}function Gb(e,t,n){try{Wb();let s=ql(No,`${e}.md`),r=`<!-- Claude Recall note \xB7 session ${e} \xB7 updated ${n} -->
1337
+ `;Fb(s,r+t)}catch(s){console.error("[notes] mirror write failed:",s)}}pt();B();ee();import{randomUUID as Kl}from"node:crypto";import{writeFileSync as Vl,readFileSync as LN,existsSync as Yb,mkdirSync as zb}from"node:fs";import{join as Oo}from"node:path";var Rs=Oo(W,"threads"),Kb=Oo(Rs,"index.json");function Zl(){z(),Yb(Rs)||zb(Rs,{recursive:!0})}function Lo(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 Ql(e){let t=new Map;if(e.length===0)return t;let n=f(),s=e.map(()=>"?").join(","),r=n.prepare(`SELECT te.thread_id AS thread_id,
1321
1338
  p.name AS project,
1322
1339
  COUNT(*) AS n,
1323
1340
  SUM(CASE WHEN te.role = 'origin' THEN 1 ELSE 0 END) AS origin_n
@@ -1325,7 +1342,7 @@ ${h+1}. ${S}`:`${h+1}. ${S}`}).join(`
1325
1342
  LEFT JOIN sessions s ON s.id = te.session_id
1326
1343
  LEFT JOIN projects p ON p.id = s.project_id
1327
1344
  WHERE te.thread_id IN (${s})
1328
- GROUP BY te.thread_id, p.name`).all(...e),o=new Map;for(let a of r){let c=o.get(a.thread_id);c||(c=[],o.set(a.thread_id,c)),c.push(a)}for(let[a,c]of o){let u=c.filter(h=>h.project!==null),d=u.length,m=null;u.length>0&&(m=[...u].sort((S,b)=>b.n-S.n||b.origin_n-S.origin_n||(S.project??"").localeCompare(b.project??""))[0].project),t.set(a,{project:m,project_count:d})}return t}function Yl(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 Gl(e){let n=f().prepare(`SELECT NULLIF(sa.alias, '') AS alias,
1345
+ GROUP BY te.thread_id, p.name`).all(...e),o=new Map;for(let a of r){let c=o.get(a.thread_id);c||(c=[],o.set(a.thread_id,c)),c.push(a)}for(let[a,c]of o){let u=c.filter(h=>h.project!==null),d=u.length,m=null;u.length>0&&(m=[...u].sort((b,S)=>S.n-b.n||S.origin_n-b.origin_n||(b.project??"").localeCompare(S.project??""))[0].project),t.set(a,{project:m,project_count:d})}return t}function eu(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 tu(e){let n=f().prepare(`SELECT NULLIF(sa.alias, '') AS alias,
1329
1346
  s.auto_title AS auto_title,
1330
1347
  s.auto_title_source AS auto_title_source,
1331
1348
  s.first_user_message AS first_user_message,
@@ -1333,11 +1350,11 @@ ${h+1}. ${S}`:`${h+1}. ${S}`}).join(`
1333
1350
  FROM (SELECT ? AS sid) q
1334
1351
  LEFT JOIN sessions s ON s.id = q.sid
1335
1352
  LEFT JOIN session_aliases sa ON sa.session_id = q.sid
1336
- 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 No(e){let n=f().prepare(`SELECT
1353
+ 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 Co(e){let n=f().prepare(`SELECT
1337
1354
  COUNT(*) AS session_count,
1338
1355
  SUM(CASE WHEN role = 'origin' THEN 1 ELSE 0 END) AS origin_count
1339
- FROM thread_edges WHERE thread_id = ?`).get(e);return{session_count:n?.session_count??0,origin_count:n?.origin_count??0}}function ke(e){let t=ie(e);t&&(Xl(),ql(Ao(ws,`${e}.json`),JSON.stringify(t,null,2)),zl())}function zl(){Xl();let e=Oo({includeArchived:!0});ql(jb,JSON.stringify({threads:e},null,2))}function Rs(e){let t=e.name.trim();if(!t)throw new Error("thread name cannot be empty");let n=f(),s=Wl(),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)
1340
- VALUES (?, ?, NULL, 'origin', 1.0, 'manual', ?)`).run(s,e.originSessionId,r),ke(s);let o=ie(s);if(!o)throw new Error("thread creation succeeded but read-back failed");return o}function Oo(e={}){let t=f(),n=e.includeArchived?"":"WHERE archived = 0",s=t.prepare(`SELECT * FROM threads ${n} ORDER BY created_at DESC`).all(),r=Jl(s.map(o=>o.id));return s.map(o=>xo(o,No(o.id),r.get(o.id)))}function ie(e){let t=f(),n=t.prepare("SELECT * FROM threads WHERE id = ?").get(e);if(!n)return null;let s=t.prepare(`SELECT e.*,
1356
+ FROM thread_edges WHERE thread_id = ?`).get(e);return{session_count:n?.session_count??0,origin_count:n?.origin_count??0}}function ke(e){let t=ie(e);t&&(Zl(),Vl(Oo(Rs,`${e}.json`),JSON.stringify(t,null,2)),nu())}function nu(){Zl();let e=vo({includeArchived:!0});Vl(Kb,JSON.stringify({threads:e},null,2))}function ks(e){let t=e.name.trim();if(!t)throw new Error("thread name cannot be empty");let n=f(),s=Kl(),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)
1357
+ VALUES (?, ?, NULL, 'origin', 1.0, 'manual', ?)`).run(s,e.originSessionId,r),ke(s);let o=ie(s);if(!o)throw new Error("thread creation succeeded but read-back failed");return o}function vo(e={}){let t=f(),n=e.includeArchived?"":"WHERE archived = 0",s=t.prepare(`SELECT * FROM threads ${n} ORDER BY created_at DESC`).all(),r=Ql(s.map(o=>o.id));return s.map(o=>Lo(o,Co(o.id),r.get(o.id)))}function ie(e){let t=f(),n=t.prepare("SELECT * FROM threads WHERE id = ?").get(e);if(!n)return null;let s=t.prepare(`SELECT e.*,
1341
1358
  NULLIF(sa.alias, '') AS alias,
1342
1359
  s.auto_title AS auto_title,
1343
1360
  s.auto_title_source AS auto_title_source,
@@ -1348,10 +1365,10 @@ ${h+1}. ${S}`:`${h+1}. ${S}`}).join(`
1348
1365
  LEFT JOIN session_aliases sa ON sa.session_id = e.session_id
1349
1366
  LEFT JOIN projects p ON p.id = s.project_id
1350
1367
  WHERE e.thread_id = ?
1351
- ORDER BY e.added_at ASC`).all(e).map(Yl),r=Jl([e]).get(e);return{...xo(n,No(n.id),r),edges:s}}function Kl(e){return f().prepare(`SELECT t.* FROM threads t
1368
+ ORDER BY e.added_at ASC`).all(e).map(eu),r=Ql([e]).get(e);return{...Lo(n,Co(n.id),r),edges:s}}function su(e){return f().prepare(`SELECT t.* FROM threads t
1352
1369
  JOIN thread_edges e ON e.thread_id = t.id
1353
1370
  WHERE e.session_id = ? AND t.archived = 0
1354
- ORDER BY t.created_at DESC`).all(e).map(s=>xo(s,No(s.id)))}function ks(e){let t=f();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"),a=e.confidence??1,c=e.source??"manual";if(a<0||a>1)throw new Error("confidence must be 0..1");t.prepare(`INSERT INTO thread_edges
1371
+ ORDER BY t.created_at DESC`).all(e).map(s=>Lo(s,Co(s.id)))}function As(e){let t=f();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"),a=e.confidence??1,c=e.source??"manual";if(a<0||a>1)throw new Error("confidence must be 0..1");t.prepare(`INSERT INTO thread_edges
1355
1372
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
1356
1373
  VALUES (?, ?, ?, ?, ?, ?, ?)
1357
1374
  ON CONFLICT(thread_id, session_id) DO UPDATE SET
@@ -1359,22 +1376,22 @@ ${h+1}. ${S}`:`${h+1}. ${S}`}).join(`
1359
1376
  role = excluded.role,
1360
1377
  confidence = excluded.confidence,
1361
1378
  source = excluded.source,
1362
- added_at = excluded.added_at`).run(e.threadId,e.sessionId,r,o,a,c,s),ke(e.threadId);let u=Gl(e.sessionId);return{thread_id:e.threadId,session_id:e.sessionId,parent_session_id:r,role:o,confidence:a,source:c,added_at:s,alias:u.alias,auto_title:u.auto_title,auto_title_source:u.auto_title_source,alias_source:u.alias?"manual":null,first_user_message:u.first_user_message,project:u.project}}function Vl(e,t){let s=f().prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e,t);return s.changes>0&&ke(e),{removed:s.changes}}function an(e,t,n){let s=f(),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 c=s.prepare("SELECT parent_session_id FROM thread_edges WHERE thread_id = ? AND session_id = ?"),u=n,d=new Set;for(;u!==null;){if(u===t)throw new Error(`cycle detected: setting parent of ${t} to ${n} would create a loop`);if(d.has(u))break;d.add(u),u=c.get(e,u)?.parent_session_id??null}}let o=n?"child":"origin";s.prepare(`UPDATE thread_edges
1379
+ added_at = excluded.added_at`).run(e.threadId,e.sessionId,r,o,a,c,s),ke(e.threadId);let u=tu(e.sessionId);return{thread_id:e.threadId,session_id:e.sessionId,parent_session_id:r,role:o,confidence:a,source:c,added_at:s,alias:u.alias,auto_title:u.auto_title,auto_title_source:u.auto_title_source,alias_source:u.alias?"manual":null,first_user_message:u.first_user_message,project:u.project}}function ru(e,t){let s=f().prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e,t);return s.changes>0&&ke(e),{removed:s.changes}}function an(e,t,n){let s=f(),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 c=s.prepare("SELECT parent_session_id FROM thread_edges WHERE thread_id = ? AND session_id = ?"),u=n,d=new Set;for(;u!==null;){if(u===t)throw new Error(`cycle detected: setting parent of ${t} to ${n} would create a loop`);if(d.has(u))break;d.add(u),u=c.get(e,u)?.parent_session_id??null}}let o=n?"child":"origin";s.prepare(`UPDATE thread_edges
1363
1380
  SET parent_session_id = ?, role = ?, added_at = ?
1364
- WHERE thread_id = ? AND session_id = ?`).run(n,o,new Date().toISOString(),e,t),ke(e);let a=Gl(t);return Yl({...r,parent_session_id:n,role:o,added_at:new Date().toISOString(),alias:a.alias,auto_title:a.auto_title,auto_title_source:a.auto_title_source,first_user_message:a.first_user_message,project:a.project})}function Zl(e,t){let n=t.trim();if(!n)throw new Error("name cannot be empty");f().prepare("UPDATE threads SET name = ? WHERE id = ?").run(n,e),ke(e);let r=ie(e);if(!r)throw new Error(`thread ${e} not found`);return r}function Ql(e){f().prepare("UPDATE threads SET closed_at = ? WHERE id = ?").run(new Date().toISOString(),e),ke(e);let n=ie(e);if(!n)throw new Error(`thread ${e} not found`);return n}function eu(e){f().prepare("UPDATE threads SET closed_at = NULL WHERE id = ?").run(e),ke(e);let n=ie(e);if(!n)throw new Error(`thread ${e} not found`);return n}function tu(e){f().prepare("UPDATE threads SET archived = 1 WHERE id = ?").run(e),ke(e);let n=ie(e);if(!n)throw new Error(`thread ${e} not found`);return n}function nu(e,t){if(e===t)throw new Error("cannot merge a thread into itself");let n=f(),s=new Date().toISOString();n.transaction(()=>{let o=n.prepare("SELECT * FROM thread_edges WHERE thread_id = ?").all(e);for(let a of o)n.prepare(`INSERT INTO thread_edges
1381
+ WHERE thread_id = ? AND session_id = ?`).run(n,o,new Date().toISOString(),e,t),ke(e);let a=tu(t);return eu({...r,parent_session_id:n,role:o,added_at:new Date().toISOString(),alias:a.alias,auto_title:a.auto_title,auto_title_source:a.auto_title_source,first_user_message:a.first_user_message,project:a.project})}function ou(e,t){let n=t.trim();if(!n)throw new Error("name cannot be empty");f().prepare("UPDATE threads SET name = ? WHERE id = ?").run(n,e),ke(e);let r=ie(e);if(!r)throw new Error(`thread ${e} not found`);return r}function iu(e){f().prepare("UPDATE threads SET closed_at = ? WHERE id = ?").run(new Date().toISOString(),e),ke(e);let n=ie(e);if(!n)throw new Error(`thread ${e} not found`);return n}function au(e){f().prepare("UPDATE threads SET closed_at = NULL WHERE id = ?").run(e),ke(e);let n=ie(e);if(!n)throw new Error(`thread ${e} not found`);return n}function cu(e){f().prepare("UPDATE threads SET archived = 1 WHERE id = ?").run(e),ke(e);let n=ie(e);if(!n)throw new Error(`thread ${e} not found`);return n}function lu(e,t){if(e===t)throw new Error("cannot merge a thread into itself");let n=f(),s=new Date().toISOString();n.transaction(()=>{let o=n.prepare("SELECT * FROM thread_edges WHERE thread_id = ?").all(e);for(let a of o)n.prepare(`INSERT INTO thread_edges
1365
1382
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
1366
1383
  VALUES (?, ?, ?, ?, ?, ?, ?)
1367
1384
  ON CONFLICT(thread_id, session_id) DO UPDATE SET
1368
1385
  parent_session_id = COALESCE(thread_edges.parent_session_id, excluded.parent_session_id),
1369
1386
  role = CASE WHEN thread_edges.role = 'origin' OR excluded.role = 'origin' THEN 'origin' ELSE 'child' END,
1370
1387
  confidence = MAX(thread_edges.confidence, excluded.confidence),
1371
- source = thread_edges.source`).run(t,a.session_id,a.parent_session_id,a.role,a.confidence,a.source,s);n.prepare("DELETE FROM threads WHERE id = ?").run(e)})(),ke(t),zl();let r=ie(t);if(!r)throw new Error("merge destination disappeared");return r}function su(e){if(e.sessionIds.length===0)throw new Error("no sessions to split off");let t=f(),n=new Date().toISOString(),s=Wl();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 a=t.prepare("SELECT * FROM thread_edges WHERE thread_id = ? AND session_id = ?").get(e.threadId,o);a&&(t.prepare(`INSERT INTO thread_edges
1388
+ source = thread_edges.source`).run(t,a.session_id,a.parent_session_id,a.role,a.confidence,a.source,s);n.prepare("DELETE FROM threads WHERE id = ?").run(e)})(),ke(t),nu();let r=ie(t);if(!r)throw new Error("merge destination disappeared");return r}function uu(e){if(e.sessionIds.length===0)throw new Error("no sessions to split off");let t=f(),n=new Date().toISOString(),s=Kl();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 a=t.prepare("SELECT * FROM thread_edges WHERE thread_id = ? AND session_id = ?").get(e.threadId,o);a&&(t.prepare(`INSERT INTO thread_edges
1372
1389
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
1373
- VALUES (?, ?, ?, ?, ?, ?, ?)`).run(s,o,a.parent_session_id,a.role,a.confidence,a.source,n),t.prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e.threadId,o))}})(),ke(e.threadId),ke(s);let r=ie(s);if(!r)throw new Error("split destination disappeared");return r}U();import{execFile as zb}from"node:child_process";import{promisify as Kb}from"node:util";import{readlink as Vb,readFile as cu}from"node:fs/promises";import{platform as Ls}from"node:os";import{readFileSync as Mb,statSync as Db}from"node:fs";var Fb=200*1024*1024,xs=.7,Ns=.5,iu=Ns,Pb=[{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"}],$b=["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 ru(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 Ub(e,t){let n=t-e;if(n<0)return{weight:0,label:null};for(let s of Pb)if(n<=s.maxGapMs)return{weight:s.weight,label:s.label};return{weight:0,label:null}}function Bb(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 a of $b)if(o.includes(a))return{weight:t[s],matched:a,matchedIndex:s}}return{weight:0,matched:null,matchedIndex:-1}}function Lo(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 Hb(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=Lo(s,r);o>n&&(n=o)}return n}function Wb(e,t){let n=Lo(e.mean_embedding,t.mean_embedding),s=Lo(e.tail_pool,t.head_pool),r=Hb(e.sample_chunks,t.sample_chunks),o=0,a=null;if(n>o&&(o=n,a="mean"),s>o&&(o=s,a="asymmetric"),r>o&&(o=r,a="max_pool"),o<.65)return{weight:0,cosine:o,mode:null};if(o>=.85)return{weight:.3,cosine:o,mode:a};let c=(o-.65)/.2*.3;return{weight:Math.round(c*100)/100,cosine:o,mode:a}}function qb(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 Xb(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 Jb(e,t){let n=ru(e),s=ru(t);return n&&s&&n===s?{weight:.1,brand:n}:{weight:0,brand:null}}function ou(e){return e.replace(/\s+/g," ").trim().toLowerCase()}function Yb(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(`
1374
- `).toLowerCase();for(let a of e.authored_paths){let c=a.toLowerCase();if(t.touched_files.has(a)||o.includes(c)){n+=.5,s=a;break}}}if(e.authored_content.length>0&&t.recent_user_messages[0]){let o=ou(t.recent_user_messages[0]);if(o.length>=200)for(let a of e.authored_content){let c=ou(a);if(c.length<200)continue;let u=Math.min(c.length,240),d=c.slice(0,u);if(o.includes(d)){n+=.4,r=!0;break}}}return{weight:Math.min(.6,n),pathMatch:s,contentMatch:r}}function Gb(e,t,n=iu){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=Ub(s,t.started_at_ms),o=t.recent_user_messages.length>0?t.recent_user_messages:t.first_user_message?[t.first_user_message]:[],a=Bb(o),c=Xb(e.touched_files,t.touched_files),u=Jb(e.auto_title,t.auto_title),d=Wb(e,t),m=qb(e,t),h=Yb(e,t),S=r.weight+a.weight+c.weight+u.weight+d.weight+m.weight+h.weight;if(S<n)return null;let b=[];if(r.label&&b.push(`temporal ${r.label} (+${r.weight})`),a.matched){let T=a.matchedIndex===0?"opening message":`message #${a.matchedIndex+1}`;b.push(`continuation phrase "${a.matched}" in ${T} (+${a.weight})`)}if(c.count>0&&b.push(`${c.count} file${c.count===1?"":"s"} overlap (+${c.weight.toFixed(1)})`),u.brand&&b.push(`shared brand "${u.brand}" (+${u.weight})`),d.weight>0&&d.mode&&b.push(`semantic ${d.mode==="asymmetric"?"tail\u2192head":d.mode==="max_pool"?"best-chunk":"mean"} ${d.cosine.toFixed(2)} (+${d.weight.toFixed(2)})`),m.same&&b.push(`same cluster (+${m.weight})`),h.weight>0){let T=[];h.pathMatch&&T.push(`opened authored path "${h.pathMatch.split("/").pop()}"`),h.contentMatch&&T.push("verbatim-paste of authored content"),b.push(`doc-authorship: ${T.join(" + ")} (+${h.weight.toFixed(2)})`)}return{parent_id:e.id,child_id:t.id,confidence:Math.min(1,S),signals:{temporal:r.weight,continuation:a.weight,file_overlap:c.weight,same_brand:u.weight,semantic:d.weight,cluster:m.weight,doc_authorship:h.weight},reasons:b}}function Rt(e,t=iu){let n=[];for(let s=0;s<e.length;s++){let r=e[s],o=null;for(let a=0;a<s;a++){let c=e[a],u=Gb(c,r,t);u&&(!o||u.confidence>o.confidence)&&(o=u)}o&&n.push(o)}return n}function au(e,t){let n=new Map,s=c=>{let u=c;for(;n.get(u)!==u;)u=n.get(u);let d=c;for(;n.get(d)!==u;){let m=n.get(d);n.set(d,u),d=m}return u},r=(c,u)=>{let d=s(c),m=s(u);d!==m&&n.set(d,m)};for(let c of e)n.has(c.parent_id)||n.set(c.parent_id,c.parent_id),n.has(c.child_id)||n.set(c.child_id,c.child_id),r(c.parent_id,c.child_id);let o=new Map;for(let c of n.keys()){let u=s(c),d=o.get(u);d||(d=[],o.set(u,d)),d.push(c)}let a=new Map;for(let c of t)a.set(c.id,c.started_at_ms);return Array.from(o.values()).map(c=>(c.sort((u,d)=>(a.get(u)??0)-(a.get(d)??0)),{rootId:c[0],sessionIds:c}))}function Os(e,t={}){let n=t.maxUserMessages??5,s=t.userMessageMaxLen??2e3,r=new Set,o=[],a=new Set,c=[],u;try{if(Db(e).size>Fb)return{touched_files:r,recent_user_messages:o,authored_paths:a,authored_content:c};u=Mb(e,"utf8")}catch{return{touched_files:r,recent_user_messages:o,authored_paths:a,authored_content:c}}let d=0;for(;d<u.length;){let m=u.indexOf(`
1375
- `,d),h=m===-1?u.length:m,S=u.slice(d,h);if(d=m===-1?u.length:m+1,!S.trim())continue;let b;try{b=JSON.parse(S)}catch{continue}let T=b;if(T.type==="user"&&T.message?.role==="user"&&typeof T.message.content=="string"&&o.length<n){let w=T.message.content.trim();w&&o.push(w.length>s?w.slice(0,s):w)}let R=T.message?.content;if(Array.isArray(R))for(let w of R){if(!w||typeof w!="object")continue;let j=w;if(j.type!=="tool_use")continue;let M=j.input??{},W=typeof M.file_path=="string"?M.file_path:null;if(W){let x=As(W);x&&r.add(x)}if((j.name==="Write"||j.name==="Edit"||j.name==="MultiEdit")&&W){let x=As(W);x&&a.add(x);let P=typeof M.content=="string"?M.content:typeof M.new_string=="string"?M.new_string:null;P&&P.length>=200&&c.push(P.length>4096?P.slice(0,4096):P)}if(j.name==="Bash"&&typeof M.command=="string")for(let x of M.command.matchAll(/(?:^|[\s'"`(=])((?:\.\.?\/|\/|src\/|test\/|docs\/|site\/)[A-Za-z0-9_./-]+)/g)){let P=As(x[1]);P&&r.add(P)}if((j.name==="Glob"||j.name==="Grep")&&typeof M.pattern=="string"){let x=As(M.pattern);x&&!x.includes("*")&&r.add(x)}}}return{touched_files:r,recent_user_messages:o,authored_paths:a,authored_content:c}}function As(e){let t=e.trim().replace(/^['"]|['"]$/g,"");return!t||t.length<4||/[<>|;&\$`]/.test(t)?null:t}var vo=Kb(zb),Zb=6,lu="Active ",uu=" sessions \u2014 ",Qb=6e4;async function eS(){if(Ls()==="win32")return[];for(let t of["/bin/ps","/usr/bin/ps"])try{let{stdout:n}=await vo(t,["-eo","pid=,comm="],{timeout:2e3}),s=[];for(let r of n.split(`
1376
- `)){let o=r.trim().match(/^(\d+)\s+(.+)$/);if(!o)continue;let a=Number(o[1]),c=o[2].trim();(c==="claude"||c.endsWith("/claude")||c.endsWith("/bin/claude"))&&Number.isFinite(a)&&s.push(a)}return s}catch{continue}return[]}async function tS(e){let t=Ls();if(t==="linux")try{return(await Vb(`/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 vo(n,["-a","-p",String(e),"-d","cwd","-Fn"],{timeout:2e3});for(let r of s.split(`
1377
- `))if(r.startsWith("n"))return r.slice(1).replace(/\/+$/,"");return null}catch{continue}return null}async function nS(e){let t=Ls();if(t==="linux")try{let n=await cu(`/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 a=await cu("/proc/uptime","utf8"),c=Number(a.split(/\s+/)[0]);return Number.isFinite(c)?Date.now()-c*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 vo(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 sS(e,t){let n=await eS();if(n.length===0)return null;let s=e.replace(/\/+$/,""),r=[];for(let a of n){let c=await tS(a);if(c&&(c===s||c.startsWith(s+"/"))){let u=await nS(a);r.push({pid:a,startMs:u})}}if(r.length===0)return new Set;let o=new Set;for(let{startMs:a}of r){if(a==null)continue;let c=null,u=Qb;for(let d of t){if(o.has(d.session_id)||!d.started_at)continue;let m=Date.parse(d.started_at);if(!Number.isFinite(m))continue;let h=Math.abs(m-a);h<u&&(u=h,c=d)}c&&o.add(c.session_id)}return o}function rS(e){let n=f().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 oS(e,t){let n=f(),s=`${lu}${t}${uu}%`,r=n.prepare(`SELECT t.id
1390
+ VALUES (?, ?, ?, ?, ?, ?, ?)`).run(s,o,a.parent_session_id,a.role,a.confidence,a.source,n),t.prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e.threadId,o))}})(),ke(e.threadId),ke(s);let r=ie(s);if(!r)throw new Error("split destination disappeared");return r}B();import{execFile as dS}from"node:child_process";import{promisify as pS}from"node:util";import{readlink as mS,readFile as _u}from"node:fs/promises";import{platform as Cs}from"node:os";import{readFileSync as Vb,statSync as Zb}from"node:fs";var Qb=200*1024*1024,Ns=.7,Os=.5,mu=Os,eS=[{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"}],tS=["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 du(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 nS(e,t){let n=t-e;if(n<0)return{weight:0,label:null};for(let s of eS)if(n<=s.maxGapMs)return{weight:s.weight,label:s.label};return{weight:0,label:null}}function sS(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 a of tS)if(o.includes(a))return{weight:t[s],matched:a,matchedIndex:s}}return{weight:0,matched:null,matchedIndex:-1}}function Io(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 rS(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=Io(s,r);o>n&&(n=o)}return n}function oS(e,t){let n=Io(e.mean_embedding,t.mean_embedding),s=Io(e.tail_pool,t.head_pool),r=rS(e.sample_chunks,t.sample_chunks),o=0,a=null;if(n>o&&(o=n,a="mean"),s>o&&(o=s,a="asymmetric"),r>o&&(o=r,a="max_pool"),o<.65)return{weight:0,cosine:o,mode:null};if(o>=.85)return{weight:.3,cosine:o,mode:a};let c=(o-.65)/.2*.3;return{weight:Math.round(c*100)/100,cosine:o,mode:a}}function iS(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 aS(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 cS(e,t){let n=du(e),s=du(t);return n&&s&&n===s?{weight:.1,brand:n}:{weight:0,brand:null}}function pu(e){return e.replace(/\s+/g," ").trim().toLowerCase()}function lS(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(`
1391
+ `).toLowerCase();for(let a of e.authored_paths){let c=a.toLowerCase();if(t.touched_files.has(a)||o.includes(c)){n+=.5,s=a;break}}}if(e.authored_content.length>0&&t.recent_user_messages[0]){let o=pu(t.recent_user_messages[0]);if(o.length>=200)for(let a of e.authored_content){let c=pu(a);if(c.length<200)continue;let u=Math.min(c.length,240),d=c.slice(0,u);if(o.includes(d)){n+=.4,r=!0;break}}}return{weight:Math.min(.6,n),pathMatch:s,contentMatch:r}}function uS(e,t,n=mu){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=nS(s,t.started_at_ms),o=t.recent_user_messages.length>0?t.recent_user_messages:t.first_user_message?[t.first_user_message]:[],a=sS(o),c=aS(e.touched_files,t.touched_files),u=cS(e.auto_title,t.auto_title),d=oS(e,t),m=iS(e,t),h=lS(e,t),b=r.weight+a.weight+c.weight+u.weight+d.weight+m.weight+h.weight;if(b<n)return null;let S=[];if(r.label&&S.push(`temporal ${r.label} (+${r.weight})`),a.matched){let T=a.matchedIndex===0?"opening message":`message #${a.matchedIndex+1}`;S.push(`continuation phrase "${a.matched}" in ${T} (+${a.weight})`)}if(c.count>0&&S.push(`${c.count} file${c.count===1?"":"s"} overlap (+${c.weight.toFixed(1)})`),u.brand&&S.push(`shared brand "${u.brand}" (+${u.weight})`),d.weight>0&&d.mode&&S.push(`semantic ${d.mode==="asymmetric"?"tail\u2192head":d.mode==="max_pool"?"best-chunk":"mean"} ${d.cosine.toFixed(2)} (+${d.weight.toFixed(2)})`),m.same&&S.push(`same cluster (+${m.weight})`),h.weight>0){let T=[];h.pathMatch&&T.push(`opened authored path "${h.pathMatch.split("/").pop()}"`),h.contentMatch&&T.push("verbatim-paste of authored content"),S.push(`doc-authorship: ${T.join(" + ")} (+${h.weight.toFixed(2)})`)}return{parent_id:e.id,child_id:t.id,confidence:Math.min(1,b),signals:{temporal:r.weight,continuation:a.weight,file_overlap:c.weight,same_brand:u.weight,semantic:d.weight,cluster:m.weight,doc_authorship:h.weight},reasons:S}}function Rt(e,t=mu){let n=[];for(let s=0;s<e.length;s++){let r=e[s],o=null;for(let a=0;a<s;a++){let c=e[a],u=uS(c,r,t);u&&(!o||u.confidence>o.confidence)&&(o=u)}o&&n.push(o)}return n}function gu(e,t){let n=new Map,s=c=>{let u=c;for(;n.get(u)!==u;)u=n.get(u);let d=c;for(;n.get(d)!==u;){let m=n.get(d);n.set(d,u),d=m}return u},r=(c,u)=>{let d=s(c),m=s(u);d!==m&&n.set(d,m)};for(let c of e)n.has(c.parent_id)||n.set(c.parent_id,c.parent_id),n.has(c.child_id)||n.set(c.child_id,c.child_id),r(c.parent_id,c.child_id);let o=new Map;for(let c of n.keys()){let u=s(c),d=o.get(u);d||(d=[],o.set(u,d)),d.push(c)}let a=new Map;for(let c of t)a.set(c.id,c.started_at_ms);return Array.from(o.values()).map(c=>(c.sort((u,d)=>(a.get(u)??0)-(a.get(d)??0)),{rootId:c[0],sessionIds:c}))}function Ls(e,t={}){let n=t.maxUserMessages??5,s=t.userMessageMaxLen??2e3,r=new Set,o=[],a=new Set,c=[],u;try{if(Zb(e).size>Qb)return{touched_files:r,recent_user_messages:o,authored_paths:a,authored_content:c};u=Vb(e,"utf8")}catch{return{touched_files:r,recent_user_messages:o,authored_paths:a,authored_content:c}}let d=0;for(;d<u.length;){let m=u.indexOf(`
1392
+ `,d),h=m===-1?u.length:m,b=u.slice(d,h);if(d=m===-1?u.length:m+1,!b.trim())continue;let S;try{S=JSON.parse(b)}catch{continue}let T=S;if(T.type==="user"&&T.message?.role==="user"&&typeof T.message.content=="string"&&o.length<n){let O=T.message.content.trim();O&&o.push(O.length>s?O.slice(0,s):O)}let R=T.message?.content;if(Array.isArray(R))for(let O of R){if(!O||typeof O!="object")continue;let L=O;if(L.type!=="tool_use")continue;let x=L.input??{},F=typeof x.file_path=="string"?x.file_path:null;if(F){let A=xs(F);A&&r.add(A)}if((L.name==="Write"||L.name==="Edit"||L.name==="MultiEdit")&&F){let A=xs(F);A&&a.add(A);let $=typeof x.content=="string"?x.content:typeof x.new_string=="string"?x.new_string:null;$&&$.length>=200&&c.push($.length>4096?$.slice(0,4096):$)}if(L.name==="Bash"&&typeof x.command=="string")for(let A of x.command.matchAll(/(?:^|[\s'"`(=])((?:\.\.?\/|\/|src\/|test\/|docs\/|site\/)[A-Za-z0-9_./-]+)/g)){let $=xs(A[1]);$&&r.add($)}if((L.name==="Glob"||L.name==="Grep")&&typeof x.pattern=="string"){let A=xs(x.pattern);A&&!A.includes("*")&&r.add(A)}}}return{touched_files:r,recent_user_messages:o,authored_paths:a,authored_content:c}}function xs(e){let t=e.trim().replace(/^['"]|['"]$/g,"");return!t||t.length<4||/[<>|;&\$`]/.test(t)?null:t}var Mo=pS(dS),gS=6,fu="Active ",hu=" sessions \u2014 ",_S=6e4;async function fS(){if(Cs()==="win32")return[];for(let t of["/bin/ps","/usr/bin/ps"])try{let{stdout:n}=await Mo(t,["-eo","pid=,comm="],{timeout:2e3}),s=[];for(let r of n.split(`
1393
+ `)){let o=r.trim().match(/^(\d+)\s+(.+)$/);if(!o)continue;let a=Number(o[1]),c=o[2].trim();(c==="claude"||c.endsWith("/claude")||c.endsWith("/bin/claude"))&&Number.isFinite(a)&&s.push(a)}return s}catch{continue}return[]}async function hS(e){let t=Cs();if(t==="linux")try{return(await mS(`/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 Mo(n,["-a","-p",String(e),"-d","cwd","-Fn"],{timeout:2e3});for(let r of s.split(`
1394
+ `))if(r.startsWith("n"))return r.slice(1).replace(/\/+$/,"");return null}catch{continue}return null}async function ES(e){let t=Cs();if(t==="linux")try{let n=await _u(`/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 a=await _u("/proc/uptime","utf8"),c=Number(a.split(/\s+/)[0]);return Number.isFinite(c)?Date.now()-c*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 Mo(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 bS(e,t){let n=await fS();if(n.length===0)return null;let s=e.replace(/\/+$/,""),r=[];for(let a of n){let c=await hS(a);if(c&&(c===s||c.startsWith(s+"/"))){let u=await ES(a);r.push({pid:a,startMs:u})}}if(r.length===0)return new Set;let o=new Set;for(let{startMs:a}of r){if(a==null)continue;let c=null,u=_S;for(let d of t){if(o.has(d.session_id)||!d.started_at)continue;let m=Date.parse(d.started_at);if(!Number.isFinite(m))continue;let h=Math.abs(m-a);h<u&&(u=h,c=d)}c&&o.add(c.session_id)}return o}function SS(e){let n=f().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 TS(e,t){let n=f(),s=`${fu}${t}${hu}%`,r=n.prepare(`SELECT t.id
1378
1395
  FROM threads t
1379
1396
  WHERE t.archived = 0
1380
1397
  AND t.name LIKE ?
@@ -1385,7 +1402,7 @@ ${h+1}. ${S}`:`${h+1}. ${S}`}).join(`
1385
1402
  WHERE s.project_id = ?
1386
1403
  AND t.archived = 0
1387
1404
  AND t.name LIKE ?
1388
- LIMIT 1`).get(e,s);return o?ie(o.id):null}function du(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 Co(e,t){let n=f(),s=t>0,r=s?Date.now()-t*60*60*1e3:0;return s?n.prepare(`SELECT s.id AS session_id,
1405
+ LIMIT 1`).get(e,s);return o?ie(o.id):null}function Eu(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 jo(e,t){let n=f(),s=t>0,r=s?Date.now()-t*60*60*1e3:0;return s?n.prepare(`SELECT s.id AS session_id,
1389
1406
  sa.alias AS alias,
1390
1407
  s.auto_title AS auto_title,
1391
1408
  s.first_user_message AS first_user_message,
@@ -1405,19 +1422,19 @@ ${h+1}. ${S}`:`${h+1}. ${S}`}).join(`
1405
1422
  FROM sessions s
1406
1423
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1407
1424
  WHERE s.project_id = ?
1408
- ORDER BY s.started_at ASC`).all(e)}function iS(e){let t=f(),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 a=o.ended_at?Date.parse(o.ended_at):null,c=Os(o.file_path,{maxUserMessages:7});n.push({id:s.session_id,started_at_ms:r,ended_at_ms:Number.isFinite(a)?a:null,first_user_message:s.first_user_message,recent_user_messages:c.recent_user_messages,auto_title:s.auto_title,touched_files:c.touched_files,mean_embedding:null,head_pool:null,tail_pool:null,sample_chunks:[],cluster_id:null,authored_paths:c.authored_paths,authored_content:c.authored_content})}return n}function aS(e){let n=f().prepare(`SELECT session_id, parent_session_id, source
1425
+ ORDER BY s.started_at ASC`).all(e)}function yS(e){let t=f(),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 a=o.ended_at?Date.parse(o.ended_at):null,c=Ls(o.file_path,{maxUserMessages:7});n.push({id:s.session_id,started_at_ms:r,ended_at_ms:Number.isFinite(a)?a:null,first_user_message:s.first_user_message,recent_user_messages:c.recent_user_messages,auto_title:s.auto_title,touched_files:c.touched_files,mean_embedding:null,head_pool:null,tail_pool:null,sample_chunks:[],cluster_id:null,authored_paths:c.authored_paths,authored_content:c.authored_content})}return n}function wS(e){let n=f().prepare(`SELECT session_id, parent_session_id, source
1409
1426
  FROM thread_edges
1410
- 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 pu(e,t={}){let n=rS(e),s=t.windowHours??Zb,r=t.scoreThreshold??Ns,o=t.useLivePids??!0,a=[],c=[];if(o&&n.decoded_path){let R=Co(e,0),w=await sS(n.decoded_path,R);if(w===null){let M=Ls()==="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.";a.push(M),c=Co(e,s)}else w.size===0?(a.push(`No active terminals open in ${n.name} (cwd=${n.decoded_path}). Open a Claude terminal in this repo and re-run.`),c=[]):c=R.filter(j=>w.has(j.session_id))}else c=Co(e,s);c.length===0&&!a.length&&a.push(`No active sessions in ${n.name} within the last ${s}h.`);let u=oS(e,n.name),d=new Set(u?u.edges.map(R=>R.session_id):[]),m=c.filter(R=>!d.has(R.session_id)),h=iS(c);h.sort((R,w)=>R.started_at_ms-w.started_at_ms);let S=Rt(h,r),b=u?u.edges.filter(R=>R.source!=="auto-active"&&(R.parent_session_id||R.role==="origin")).map(R=>({session_id:R.session_id,parent_session_id:R.parent_session_id})):[],T=u?u.name:`${lu}${n.name}${uu}${du(t.todayIso)}`;return{project:n,thread:{id:u?.id??null,name:T,exists:!!u,existing_session_count:u?.edges.length??0},candidates:c,proposed_additions:m,proposed_edges:S,preserved_manual_edges:b,warnings:a}}function mu(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=Rs({name:e.thread.name,summary:`Auto-captured by sync-active on ${du()}. 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=aS(n);for(let a of e.candidates)s.has(a.session_id)||(ks({threadId:n,sessionId:a.session_id,source:"auto-active",confidence:.5}),t.added++,s.set(a.session_id,{parent_session_id:null,source:"auto-active"}));for(let a of e.proposed_edges){let c=s.get(a.child_id);if(c&&c.source==="auto-active"&&c.parent_session_id!==a.parent_id&&s.has(a.parent_id))try{an(n,a.child_id,a.parent_id),t.edges_set++,s.set(a.child_id,{parent_session_id:a.parent_id,source:c.source})}catch{}}let o=f().prepare(`SELECT session_id FROM thread_edges
1427
+ 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 bu(e,t={}){let n=SS(e),s=t.windowHours??gS,r=t.scoreThreshold??Os,o=t.useLivePids??!0,a=[],c=[];if(o&&n.decoded_path){let R=jo(e,0),O=await bS(n.decoded_path,R);if(O===null){let x=Cs()==="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.";a.push(x),c=jo(e,s)}else O.size===0?(a.push(`No active terminals open in ${n.name} (cwd=${n.decoded_path}). Open a Claude terminal in this repo and re-run.`),c=[]):c=R.filter(L=>O.has(L.session_id))}else c=jo(e,s);c.length===0&&!a.length&&a.push(`No active sessions in ${n.name} within the last ${s}h.`);let u=TS(e,n.name),d=new Set(u?u.edges.map(R=>R.session_id):[]),m=c.filter(R=>!d.has(R.session_id)),h=yS(c);h.sort((R,O)=>R.started_at_ms-O.started_at_ms);let b=Rt(h,r),S=u?u.edges.filter(R=>R.source!=="auto-active"&&(R.parent_session_id||R.role==="origin")).map(R=>({session_id:R.session_id,parent_session_id:R.parent_session_id})):[],T=u?u.name:`${fu}${n.name}${hu}${Eu(t.todayIso)}`;return{project:n,thread:{id:u?.id??null,name:T,exists:!!u,existing_session_count:u?.edges.length??0},candidates:c,proposed_additions:m,proposed_edges:b,preserved_manual_edges:S,warnings:a}}function Su(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=ks({name:e.thread.name,summary:`Auto-captured by sync-active on ${Eu()}. 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=wS(n);for(let a of e.candidates)s.has(a.session_id)||(As({threadId:n,sessionId:a.session_id,source:"auto-active",confidence:.5}),t.added++,s.set(a.session_id,{parent_session_id:null,source:"auto-active"}));for(let a of e.proposed_edges){let c=s.get(a.child_id);if(c&&c.source==="auto-active"&&c.parent_session_id!==a.parent_id&&s.has(a.parent_id))try{an(n,a.child_id,a.parent_id),t.edges_set++,s.set(a.child_id,{parent_session_id:a.parent_id,source:c.source})}catch{}}let o=f().prepare(`SELECT session_id FROM thread_edges
1411
1428
  WHERE thread_id = ?
1412
1429
  AND source = 'auto-active'
1413
1430
  AND parent_session_id IS NULL
1414
- AND role = 'child'`).all(n);for(let a of o)try{an(n,a.session_id,null)}catch{}return t}U();ee();import{randomUUID as cS}from"node:crypto";import{writeFileSync as lS}from"node:fs";import{join as uS}from"node:path";var dS=uS(H,"thread-folders.json");function gu(e){return{id:e.id,name:e.name,parent_folder_id:e.parent_folder_id,project_scope:e.project_scope,created_at:e.created_at,archived:e.archived===1,sort_order:e.sort_order}}function cn(){try{z();let e=Io({includeArchived:!0});lS(dS,JSON.stringify({folders:e},null,2))}catch{}}function Io(e={}){let t=e.includeArchived?"":"WHERE archived = 0";return f().prepare(`SELECT * FROM thread_folders ${t} ORDER BY sort_order, name`).all().map(gu)}function it(e){let t=f().prepare("SELECT * FROM thread_folders WHERE id = ?").get(e);return t?gu(t):null}function _u(e){let t=e.name.trim();if(!t)throw new Error("folder name cannot be empty");if(t.length>200)throw new Error("folder name too long (200 char max)");let n=e.parentFolderId??null,s=e.projectScope??null;if(n){let c=it(n);if(!c)throw new Error(`parent folder ${n} not found`);s=c.project_scope}let r=cS(),o=new Date().toISOString(),a=fu(n,s);return f().prepare(`INSERT INTO thread_folders (id, name, parent_folder_id, project_scope, created_at, archived, sort_order)
1415
- VALUES (?, ?, ?, ?, ?, 0, ?)`).run(r,t,n,s,o,a),cn(),{id:r,name:t,parent_folder_id:n,project_scope:s,created_at:o,archived:!1,sort_order:a}}function fu(e,t){return f().prepare(`SELECT COALESCE(MAX(sort_order), -100) + 100 AS next
1431
+ AND role = 'child'`).all(n);for(let a of o)try{an(n,a.session_id,null)}catch{}return t}B();ee();import{randomUUID as RS}from"node:crypto";import{writeFileSync as kS}from"node:fs";import{join as AS}from"node:path";var xS=AS(W,"thread-folders.json");function Tu(e){return{id:e.id,name:e.name,parent_folder_id:e.parent_folder_id,project_scope:e.project_scope,created_at:e.created_at,archived:e.archived===1,sort_order:e.sort_order}}function cn(){try{z();let e=Do({includeArchived:!0});kS(xS,JSON.stringify({folders:e},null,2))}catch{}}function Do(e={}){let t=e.includeArchived?"":"WHERE archived = 0";return f().prepare(`SELECT * FROM thread_folders ${t} ORDER BY sort_order, name`).all().map(Tu)}function ot(e){let t=f().prepare("SELECT * FROM thread_folders WHERE id = ?").get(e);return t?Tu(t):null}function yu(e){let t=e.name.trim();if(!t)throw new Error("folder name cannot be empty");if(t.length>200)throw new Error("folder name too long (200 char max)");let n=e.parentFolderId??null,s=e.projectScope??null;if(n){let c=ot(n);if(!c)throw new Error(`parent folder ${n} not found`);s=c.project_scope}let r=RS(),o=new Date().toISOString(),a=wu(n,s);return f().prepare(`INSERT INTO thread_folders (id, name, parent_folder_id, project_scope, created_at, archived, sort_order)
1432
+ VALUES (?, ?, ?, ?, ?, 0, ?)`).run(r,t,n,s,o,a),cn(),{id:r,name:t,parent_folder_id:n,project_scope:s,created_at:o,archived:!1,sort_order:a}}function wu(e,t){return f().prepare(`SELECT COALESCE(MAX(sort_order), -100) + 100 AS next
1416
1433
  FROM thread_folders
1417
1434
  WHERE parent_folder_id IS ?
1418
- AND project_scope IS ?`).get(e,t)?.next??0}function hu(e,t){let n=t.trim();if(!n)throw new Error("folder name cannot be empty");if(n.length>200)throw new Error("folder name too long (200 char max)");let s=it(e);if(!s)throw new Error(`folder ${e} not found`);return f().prepare("UPDATE thread_folders SET name = ? WHERE id = ?").run(n,e),cn(),{...s,name:n}}function Eu(e,t){let n=it(e);if(!n)throw new Error(`folder ${e} not found`);if(t===e)throw new Error("cannot move a folder under itself");let s=n.project_scope;if(t!==null){let o=it(t);if(!o)throw new Error(`parent folder ${t} not found`);let a=o.parent_folder_id,c=0;for(;a!==null&&c<1024;){if(a===e)throw new Error("cannot move a folder into one of its own descendants (cycle)");let u=it(a);if(!u)break;a=u.parent_folder_id,c++}s=o.project_scope}let r=fu(t,s);return f().prepare("UPDATE thread_folders SET parent_folder_id = ?, project_scope = ?, sort_order = ? WHERE id = ?").run(t,s,r,e),cn(),{...n,parent_folder_id:t,project_scope:s,sort_order:r}}function bu(e,t,n){if(!Array.isArray(n)||n.length===0)throw new Error("ordered_ids must be a non-empty array");let s=new Set;for(let d of n){if(typeof d!="string"||!d)throw new Error("ordered_ids must contain non-empty strings");if(s.has(d))throw new Error(`duplicate id in ordered_ids: ${d}`);s.add(d)}let r=f(),o=r.prepare(`SELECT id FROM thread_folders
1435
+ AND project_scope IS ?`).get(e,t)?.next??0}function Ru(e,t){let n=t.trim();if(!n)throw new Error("folder name cannot be empty");if(n.length>200)throw new Error("folder name too long (200 char max)");let s=ot(e);if(!s)throw new Error(`folder ${e} not found`);return f().prepare("UPDATE thread_folders SET name = ? WHERE id = ?").run(n,e),cn(),{...s,name:n}}function ku(e,t){let n=ot(e);if(!n)throw new Error(`folder ${e} not found`);if(t===e)throw new Error("cannot move a folder under itself");let s=n.project_scope;if(t!==null){let o=ot(t);if(!o)throw new Error(`parent folder ${t} not found`);let a=o.parent_folder_id,c=0;for(;a!==null&&c<1024;){if(a===e)throw new Error("cannot move a folder into one of its own descendants (cycle)");let u=ot(a);if(!u)break;a=u.parent_folder_id,c++}s=o.project_scope}let r=wu(t,s);return f().prepare("UPDATE thread_folders SET parent_folder_id = ?, project_scope = ?, sort_order = ? WHERE id = ?").run(t,s,r,e),cn(),{...n,parent_folder_id:t,project_scope:s,sort_order:r}}function Au(e,t,n){if(!Array.isArray(n)||n.length===0)throw new Error("ordered_ids must be a non-empty array");let s=new Set;for(let d of n){if(typeof d!="string"||!d)throw new Error("ordered_ids must contain non-empty strings");if(s.has(d))throw new Error(`duplicate id in ordered_ids: ${d}`);s.add(d)}let r=f(),o=r.prepare(`SELECT id FROM thread_folders
1419
1436
  WHERE parent_folder_id IS ?
1420
- AND project_scope IS ?`).all(e,t),a=new Set(o.map(d=>d.id));if(a.size!==n.length)throw new Error(`ordered_ids length ${n.length} does not match sibling count ${a.size}`);for(let d of n)if(!a.has(d))throw new Error(`folder ${d} is not in the named sibling bucket`);let c=r.prepare("UPDATE thread_folders SET sort_order = ? WHERE id = ?");r.transaction(d=>{d.forEach((m,h)=>c.run(h*100,m))})(n),cn()}function Su(e){if(!it(e))throw new Error(`folder ${e} not found`);f().prepare("DELETE FROM thread_folders WHERE id = ?").run(e),cn()}function Tu(e,t){if(t!==null&&!it(t))throw new Error(`folder ${t} not found`);if(f().prepare("UPDATE threads SET folder_id = ? WHERE id = ?").run(t,e).changes===0)throw new Error(`thread ${e} not found`)}function yu(e,t){let n=new Set,s=[];for(let r of t){if(n.has(r.id))continue;let o=null,a="";if(r.source_session_id===e)o="outbound",a=r.target_session_id;else if(r.target_session_id===e)o="inbound",a=r.source_session_id;else continue;n.add(r.id),s.push({linkId:r.id,otherSessionId:a,direction:o,updatedAt:r.updated_at,link:r})}return s.sort((r,o)=>r.updatedAt<o.updatedAt?1:r.updatedAt>o.updatedAt?-1:0),s}U();var pS=4e3,mS=2,gS=30,_S=.2,fS={citation:1,wiki_link:.9,similar:.7,skill_track:.5,bug_pattern:.4,temporal_proximity:.3};function Cs(e){return e?Math.ceil(e.length/4):0}function wu(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/gS);return Math.max(_S,t)}function Ru(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 ku(e){return f().prepare(`SELECT s.id,
1437
+ AND project_scope IS ?`).all(e,t),a=new Set(o.map(d=>d.id));if(a.size!==n.length)throw new Error(`ordered_ids length ${n.length} does not match sibling count ${a.size}`);for(let d of n)if(!a.has(d))throw new Error(`folder ${d} is not in the named sibling bucket`);let c=r.prepare("UPDATE thread_folders SET sort_order = ? WHERE id = ?");r.transaction(d=>{d.forEach((m,h)=>c.run(h*100,m))})(n),cn()}function xu(e){if(!ot(e))throw new Error(`folder ${e} not found`);f().prepare("DELETE FROM thread_folders WHERE id = ?").run(e),cn()}function Nu(e,t){if(t!==null&&!ot(t))throw new Error(`folder ${t} not found`);if(f().prepare("UPDATE threads SET folder_id = ? WHERE id = ?").run(t,e).changes===0)throw new Error(`thread ${e} not found`)}function Ou(e,t){let n=new Set,s=[];for(let r of t){if(n.has(r.id))continue;let o=null,a="";if(r.source_session_id===e)o="outbound",a=r.target_session_id;else if(r.target_session_id===e)o="inbound",a=r.source_session_id;else continue;n.add(r.id),s.push({linkId:r.id,otherSessionId:a,direction:o,updatedAt:r.updated_at,link:r})}return s.sort((r,o)=>r.updatedAt<o.updatedAt?1:r.updatedAt>o.updatedAt?-1:0),s}B();var NS=4e3,OS=2,LS=30,CS=.2,vS={citation:1,wiki_link:.9,similar:.7,skill_track:.5,bug_pattern:.4,temporal_proximity:.3};function vs(e){return e?Math.ceil(e.length/4):0}function Lu(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/LS);return Math.max(CS,t)}function Cu(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 vu(e){return f().prepare(`SELECT s.id,
1421
1438
  NULLIF(sa.alias, '') AS alias,
1422
1439
  s.auto_title,
1423
1440
  s.auto_title_source,
@@ -1428,72 +1445,72 @@ ${h+1}. ${S}`:`${h+1}. ${S}`}).join(`
1428
1445
  FROM sessions s
1429
1446
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1430
1447
  LEFT JOIN projects p ON p.id = s.project_id
1431
- WHERE s.id = ?`).get(e)??null}function Au(e){let n=f().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 xu(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 hS(e){let n=f().prepare(`SELECT id, auto_title, started_at
1448
+ WHERE s.id = ?`).get(e)??null}function Iu(e){let n=f().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 ju(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 IS(e){let n=f().prepare(`SELECT id, auto_title, started_at
1432
1449
  FROM sessions
1433
1450
  WHERE project_id = ?
1434
- ORDER BY COALESCE(started_at, ''), id`).all(e),s=new Set,r=new Set,o=[];for(let S of n){if(!S.auto_title||!S.auto_title.startsWith("/")){o.push({id:S.id,brand:null,skill:null});continue}let b=S.auto_title.split(" \xB7 "),T=b[0].trim(),R=b.length>1?b.slice(1).join(" \xB7 ").trim():null;o.push({id:S.id,brand:R||null,skill:T||null}),R&&s.add(R),T&&r.add(T)}let a=[...s].sort(),c=new Map;a.forEach((S,b)=>c.set(S,b));let u=[...r].sort(),d=new Map;u.forEach((S,b)=>d.set(S,b));let m=new Map,h=new Map;for(let S of o){if(!S.brand||!S.skill)continue;let b=c.get(S.brand),T=d.get(S.skill);if(b===void 0||T===void 0)continue;let R=`${b}.${T}`,w=(m.get(R)??0)+1;m.set(R,w),h.set(S.id,`${b}.${T}.${w}`)}return{byId:h}}function ES(e){return{table:e!==null?hS(e):null,originProjectId:e,cache:new Map}}function vs(e,t){let n=e.cache.get(t);if(n)return n;let s=ku(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:xu(s),decimal:r,summary:Au(s.id),project:s.project,started_at:s.started_at};return e.cache.set(t,o),o}function bS(e,t){let s=f().prepare(`SELECT DISTINCT te.parent_session_id AS pid
1451
+ ORDER BY COALESCE(started_at, ''), id`).all(e),s=new Set,r=new Set,o=[];for(let b of n){if(!b.auto_title||!b.auto_title.startsWith("/")){o.push({id:b.id,brand:null,skill:null});continue}let S=b.auto_title.split(" \xB7 "),T=S[0].trim(),R=S.length>1?S.slice(1).join(" \xB7 ").trim():null;o.push({id:b.id,brand:R||null,skill:T||null}),R&&s.add(R),T&&r.add(T)}let a=[...s].sort(),c=new Map;a.forEach((b,S)=>c.set(b,S));let u=[...r].sort(),d=new Map;u.forEach((b,S)=>d.set(b,S));let m=new Map,h=new Map;for(let b of o){if(!b.brand||!b.skill)continue;let S=c.get(b.brand),T=d.get(b.skill);if(S===void 0||T===void 0)continue;let R=`${S}.${T}`,O=(m.get(R)??0)+1;m.set(R,O),h.set(b.id,`${S}.${T}.${O}`)}return{byId:h}}function jS(e){return{table:e!==null?IS(e):null,originProjectId:e,cache:new Map}}function Is(e,t){let n=e.cache.get(t);if(n)return n;let s=vu(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:ju(s),decimal:r,summary:Iu(s.id),project:s.project,started_at:s.started_at};return e.cache.set(t,o),o}function MS(e,t){let s=f().prepare(`SELECT DISTINCT te.parent_session_id AS pid
1435
1452
  FROM thread_edges te
1436
1453
  WHERE te.session_id = ?
1437
- AND te.parent_session_id IS NOT NULL`).all(t),r=[];for(let o of s){if(!o.pid)continue;let a=vs(e,o.pid);a&&r.push(a)}return r}function SS(e,t){let s=f().prepare(`SELECT DISTINCT te.session_id AS sid
1454
+ AND te.parent_session_id IS NOT NULL`).all(t),r=[];for(let o of s){if(!o.pid)continue;let a=Is(e,o.pid);a&&r.push(a)}return r}function DS(e,t){let s=f().prepare(`SELECT DISTINCT te.session_id AS sid
1438
1455
  FROM thread_edges te
1439
- WHERE te.parent_session_id = ?`).all(t),r=[];for(let o of s){if(!o.sid)continue;let a=vs(e,o.sid);a&&r.push(a)}return r}function Nu(e){let t=fS[e.linkType]??.5,n=kt(e.confidence),s=t*n,r=wu(e.daysApart),o=e.embeddingCosine??.5,a=kt(e.pagerank);if(e.scoring==="pagerank")return kt(a);if(e.scoring==="embedding-rerank")return e.embeddingCosine===null?kt(s):kt(o);let c=.35*s+.2*r+.2*o+.25*a;return kt(c)}function kt(e){return!Number.isFinite(e)||e<0?0:e>1?1:e}function TS(e,t,n,s,r){let o=new Map;function a(c,u){if(c===u)return;let d=o.get(c);d||(d=new Set,o.set(c,d)),d.add(u)}for(let c of t)a(c.source_session_id,c.target_session_id),a(c.target_session_id,c.source_session_id);for(let c of n)a(e,c.session_id);for(let c of n)a(c.session_id,e);for(let c of s)a(e,c.session_id);for(let c of s)a(c.session_id,e);if(r>1){let c=new Set([e]),u=new Set([e]);for(let d=1;d<r;d++){let m=new Set;for(let h of c){let S=o.get(h);if(S)for(let b of S){if(u.has(b))continue;let T=Jt(b).filter(R=>R.approved);for(let R of T)a(R.source_session_id,R.target_session_id),a(R.target_session_id,R.source_session_id);u.add(b),m.add(b)}}if(m.size===0)break;for(let h of m)c.add(h)}}return{edges:o}}function yS(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,a=new Map(r.map(d=>[d,o]));for(let d=0;d<n;d++){let m=new Map(r.map(h=>[h,(1-s)/r.length]));for(let h of r){let S=e.edges.get(h);if(!S||S.size===0)continue;let b=(a.get(h)??0)/S.size;for(let T of S)m.set(T,(m.get(T)??0)+s*b)}a=m}let c=0;for(let d of a.values())d>c&&(c=d);if(c<=0)return a;let u=new Map;for(let[d,m]of a)u.set(d,m/c);return u}var Ou=240;function Lu(e,t){let n=e.replace(/\s+/g," ").trim();return n.length<=t?n:`${n.slice(0,t-1).trimEnd()}\u2026`}function wS(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=Lu(e.summary,Ou);return`${r}
1440
- ${o}`}return r}function RS(e,t,n){let s=[],r=[],o=0,a=e.decimal?`${e.decimal}: `:"",c=`# Neighborhood for ${e.session_id} (${a}${e.title})`;if(s.push(c),o+=Cs(c),e.summary){let u=Lu(e.summary,Ou*4);s.push(u),o+=Cs(u)}s.push("");for(let u of t){if(u.refs.length===0)continue;let d=`## ${u.heading}`,m=Cs(d),h=[],S=0;for(let b of u.refs){let T=wS(b),R=Cs(T);if(o+m+S+R>n){r.push({session_id:b.session_id,title:b.title,decimal:b.decimal,summary:b.summary,project:b.project,started_at:b.started_at});continue}h.push(T),S+=R}if(h.length>0){s.push(d);for(let b of h)s.push(b);s.push(""),o+=m+S}}for(;s.length>0&&s[s.length-1]==="";)s.pop();return{bundle:s.join(`
1456
+ WHERE te.parent_session_id = ?`).all(t),r=[];for(let o of s){if(!o.sid)continue;let a=Is(e,o.sid);a&&r.push(a)}return r}function Mu(e){let t=vS[e.linkType]??.5,n=kt(e.confidence),s=t*n,r=Lu(e.daysApart),o=e.embeddingCosine??.5,a=kt(e.pagerank);if(e.scoring==="pagerank")return kt(a);if(e.scoring==="embedding-rerank")return e.embeddingCosine===null?kt(s):kt(o);let c=.35*s+.2*r+.2*o+.25*a;return kt(c)}function kt(e){return!Number.isFinite(e)||e<0?0:e>1?1:e}function FS(e,t,n,s,r){let o=new Map;function a(c,u){if(c===u)return;let d=o.get(c);d||(d=new Set,o.set(c,d)),d.add(u)}for(let c of t)a(c.source_session_id,c.target_session_id),a(c.target_session_id,c.source_session_id);for(let c of n)a(e,c.session_id);for(let c of n)a(c.session_id,e);for(let c of s)a(e,c.session_id);for(let c of s)a(c.session_id,e);if(r>1){let c=new Set([e]),u=new Set([e]);for(let d=1;d<r;d++){let m=new Set;for(let h of c){let b=o.get(h);if(b)for(let S of b){if(u.has(S))continue;let T=Jt(S).filter(R=>R.approved);for(let R of T)a(R.source_session_id,R.target_session_id),a(R.target_session_id,R.source_session_id);u.add(S),m.add(S)}}if(m.size===0)break;for(let h of m)c.add(h)}}return{edges:o}}function PS(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,a=new Map(r.map(d=>[d,o]));for(let d=0;d<n;d++){let m=new Map(r.map(h=>[h,(1-s)/r.length]));for(let h of r){let b=e.edges.get(h);if(!b||b.size===0)continue;let S=(a.get(h)??0)/b.size;for(let T of b)m.set(T,(m.get(T)??0)+s*S)}a=m}let c=0;for(let d of a.values())d>c&&(c=d);if(c<=0)return a;let u=new Map;for(let[d,m]of a)u.set(d,m/c);return u}var Du=240;function Fu(e,t){let n=e.replace(/\s+/g," ").trim();return n.length<=t?n:`${n.slice(0,t-1).trimEnd()}\u2026`}function $S(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=Fu(e.summary,Du);return`${r}
1457
+ ${o}`}return r}function US(e,t,n){let s=[],r=[],o=0,a=e.decimal?`${e.decimal}: `:"",c=`# Neighborhood for ${e.session_id} (${a}${e.title})`;if(s.push(c),o+=vs(c),e.summary){let u=Fu(e.summary,Du*4);s.push(u),o+=vs(u)}s.push("");for(let u of t){if(u.refs.length===0)continue;let d=`## ${u.heading}`,m=vs(d),h=[],b=0;for(let S of u.refs){let T=$S(S),R=vs(T);if(o+m+b+R>n){r.push({session_id:S.session_id,title:S.title,decimal:S.decimal,summary:S.summary,project:S.project,started_at:S.started_at});continue}h.push(T),b+=R}if(h.length>0){s.push(d);for(let S of h)s.push(S);s.push(""),o+=m+b}}for(;s.length>0&&s[s.length-1]==="";)s.pop();return{bundle:s.join(`
1441
1458
  `)+`
1442
- `,budgetUsed:o,truncated:r}}function kS(e,t,n,s,r,o){let a=[];for(let c of n){if(s&&!s.has(c.link_type))continue;let u=null;if(c.source_session_id===t.session_id?u=c.target_session_id:c.target_session_id===t.session_id&&(u=c.source_session_id),!u)continue;let d=vs(e,u);if(!d)continue;let m=Ru(t.started_at,d.started_at),h=Nu({confidence:c.confidence,linkType:c.link_type,daysApart:m,embeddingCosine:null,pagerank:o.get(u)??0,scoring:r});a.push({...d,score:h,evidence:`(suggestion, ${c.inferred_by}) confidence=${c.confidence.toFixed(2)} ${Math.round(m)}d apart`,link_type:c.link_type})}return a}function Is(e,t={}){let n=Math.max(100,Math.floor(t.budget??pS)),s=t.scoring??"hybrid",r=Math.max(1,Math.min(5,t.maxDepth??mS)),o=t.includeWikiLinks??!0,a=t.includeSuggestions??!1,c=t.edgeTypes?new Set(t.edgeTypes):null,u=ku(e);if(!u)throw new Error(`session not found: ${e}`);let d=ES(u.project_id),m={session_id:u.id,title:xu(u),decimal:d.table?.byId.get(u.id)??null,summary:Au(u.id),project:u.project,started_at:u.started_at};d.cache.set(u.id,m);let h=bS(d,e),S=SS(d,e),b=Jt(e).filter(B=>B.approved).filter(B=>!c||c.has(B.link_type)).filter(B=>o||B.link_type!=="wiki_link"),T=TS(e,b,h,S,r),R=yS(T),w=[],j=[],M=[],W=[];for(let B of b){let se=B.source_session_id===e?B.target_session_id:B.source_session_id,i=vs(d,se);if(!i)continue;let l=Ru(m.started_at,i.started_at),p=Nu({confidence:B.confidence,linkType:B.link_type,daysApart:l,embeddingCosine:null,pagerank:R.get(se)??0,scoring:s}),g=wu(l),_=`${B.link_type} confidence=${B.confidence.toFixed(2)} recency=${g.toFixed(2)} (${Math.round(l)}d apart)`,E={...i,score:p,evidence:_,link_type:B.link_type};B.link_type==="citation"?w.push(E):B.link_type==="similar"?j.push(E):B.link_type==="wiki_link"?W.push(E):M.push(E)}if(a){let B=lt({sourceSessionId:e,status:"pending",limit:100}),se=lt({targetSessionId:e,status:"pending",limit:100}),i=[...B,...se],l=new Set,p=i.filter(_=>l.has(_.id)?!1:(l.add(_.id),!0)),g=kS(d,m,p,c,s,R);for(let _ of g)_.link_type==="citation"?w.push(_):_.link_type==="similar"?j.push(_):_.link_type==="wiki_link"?W.push(_):M.push(_)}let x=(B,se)=>se.score-B.score;w.sort(x),j.sort(x),M.sort(x),W.sort(x);let te=RS(m,[{heading:"Parents",refs:h},{heading:"Children",refs:S},{heading:"Citations (approved)",refs:w},{heading:"Similar sessions",refs:j},{heading:"Cousins (skill track + temporal)",refs:M},{heading:"Wiki links (manual)",refs:W}],n);return{origin:m,parents:h,children:S,citations:w,similar:j,cousins:M,wikiLinks:W,bundle:te.bundle,budgetUsed:te.budgetUsed,budgetRemaining:Math.max(0,n-te.budgetUsed),truncated:te.truncated}}import{randomUUID as vS}from"node:crypto";var AS=50;function xS(e){if(e.length===0)return[];let t=[...e].sort((u,d)=>u.added_at<d.added_at?-1:u.added_at>d.added_at?1:0),n=new Map,s=new Set,r=[];for(let u of t)if(u.parent_session_id){let d=n.get(u.parent_session_id)??[];d.push(u),n.set(u.parent_session_id,d)}let o=t.filter(u=>u.role==="origin"),c=[...o.length>0?o:t.filter(u=>!u.parent_session_id)];for(;c.length>0;){let u=c.shift();if(s.has(u.session_id))continue;s.add(u.session_id),r.push(u.session_id);let d=n.get(u.session_id)??[];for(let m of d)s.has(m.session_id)||c.push(m)}for(let u of t)s.has(u.session_id)||(s.add(u.session_id),r.push(u.session_id));return r}function NS(e){let t=io(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(`
1459
+ `,budgetUsed:o,truncated:r}}function BS(e,t,n,s,r,o){let a=[];for(let c of n){if(s&&!s.has(c.link_type))continue;let u=null;if(c.source_session_id===t.session_id?u=c.target_session_id:c.target_session_id===t.session_id&&(u=c.source_session_id),!u)continue;let d=Is(e,u);if(!d)continue;let m=Cu(t.started_at,d.started_at),h=Mu({confidence:c.confidence,linkType:c.link_type,daysApart:m,embeddingCosine:null,pagerank:o.get(u)??0,scoring:r});a.push({...d,score:h,evidence:`(suggestion, ${c.inferred_by}) confidence=${c.confidence.toFixed(2)} ${Math.round(m)}d apart`,link_type:c.link_type})}return a}function js(e,t={}){let n=Math.max(100,Math.floor(t.budget??NS)),s=t.scoring??"hybrid",r=Math.max(1,Math.min(5,t.maxDepth??OS)),o=t.includeWikiLinks??!0,a=t.includeSuggestions??!1,c=t.edgeTypes?new Set(t.edgeTypes):null,u=vu(e);if(!u)throw new Error(`session not found: ${e}`);let d=jS(u.project_id),m={session_id:u.id,title:ju(u),decimal:d.table?.byId.get(u.id)??null,summary:Iu(u.id),project:u.project,started_at:u.started_at};d.cache.set(u.id,m);let h=MS(d,e),b=DS(d,e),S=Jt(e).filter(H=>H.approved).filter(H=>!c||c.has(H.link_type)).filter(H=>o||H.link_type!=="wiki_link"),T=FS(e,S,h,b,r),R=PS(T),O=[],L=[],x=[],F=[];for(let H of S){let se=H.source_session_id===e?H.target_session_id:H.source_session_id,i=Is(d,se);if(!i)continue;let l=Cu(m.started_at,i.started_at),p=Mu({confidence:H.confidence,linkType:H.link_type,daysApart:l,embeddingCosine:null,pagerank:R.get(se)??0,scoring:s}),g=Lu(l),_=`${H.link_type} confidence=${H.confidence.toFixed(2)} recency=${g.toFixed(2)} (${Math.round(l)}d apart)`,E={...i,score:p,evidence:_,link_type:H.link_type};H.link_type==="citation"?O.push(E):H.link_type==="similar"?L.push(E):H.link_type==="wiki_link"?F.push(E):x.push(E)}if(a){let H=lt({sourceSessionId:e,status:"pending",limit:100}),se=lt({targetSessionId:e,status:"pending",limit:100}),i=[...H,...se],l=new Set,p=i.filter(_=>l.has(_.id)?!1:(l.add(_.id),!0)),g=BS(d,m,p,c,s,R);for(let _ of g)_.link_type==="citation"?O.push(_):_.link_type==="similar"?L.push(_):_.link_type==="wiki_link"?F.push(_):x.push(_)}let A=(H,se)=>se.score-H.score;O.sort(A),L.sort(A),x.sort(A),F.sort(A);let te=US(m,[{heading:"Parents",refs:h},{heading:"Children",refs:b},{heading:"Citations (approved)",refs:O},{heading:"Similar sessions",refs:L},{heading:"Cousins (skill track + temporal)",refs:x},{heading:"Wiki links (manual)",refs:F}],n);return{origin:m,parents:h,children:b,citations:O,similar:L,cousins:x,wikiLinks:F,bundle:te.bundle,budgetUsed:te.budgetUsed,budgetRemaining:Math.max(0,n-te.budgetUsed),truncated:te.truncated}}import{randomUUID as YS}from"node:crypto";var HS=50;function WS(e){if(e.length===0)return[];let t=[...e].sort((u,d)=>u.added_at<d.added_at?-1:u.added_at>d.added_at?1:0),n=new Map,s=new Set,r=[];for(let u of t)if(u.parent_session_id){let d=n.get(u.parent_session_id)??[];d.push(u),n.set(u.parent_session_id,d)}let o=t.filter(u=>u.role==="origin"),c=[...o.length>0?o:t.filter(u=>!u.parent_session_id)];for(;c.length>0;){let u=c.shift();if(s.has(u.session_id))continue;s.add(u.session_id),r.push(u.session_id);let d=n.get(u.session_id)??[];for(let m of d)s.has(m.session_id)||c.push(m)}for(let u of t)s.has(u.session_id)||(s.add(u.session_id),r.push(u.session_id));return r}function qS(e){let t=ao(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(`
1443
1460
  `);return`${t}
1444
- ${n}`}function OS(e){return Le(e)?.auto_title_source??null}async function LS(e){let{spawnClaudePrompt:t,isClaudeCliAvailable:n}=await Promise.resolve().then(()=>(ye(),tt));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=CS(s.stdout);if(!r)throw new Error("claude CLI returned an empty title");return r.slice(0,AS)}function CS(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 Cu(s)}}catch{}return Cu(t)}function Cu(e){return e.trim().replace(/^["'`]+|["'`]+$/g,"").replace(/\s+/g," ").replace(/[.!?]+$/g,"").trim()}async function Iu(e,t={}){let n=ie(e);if(!n)throw new Error(`thread not found: ${e}`);let s=xS(n.edges),r=s.length,o=t.force??!1,a=t.signal,c=[],u=[],d=[];for(let m=0;m<s.length;m++){let h=s[m],S=m+1;if(a?.aborted){let T={sessionId:h,reason:"cancelled"};u.push(T),t.onSkipped?.(T);continue}if(!o&&OS(h)==="agent"){let T={sessionId:h,reason:"already-titled"};u.push(T),t.onSkipped?.(T);continue}let b;try{if(vu)b=await vu({sessionId:h,current:S,total:r});else{let T=NS({sessionId:h,current:S,total:r});b=await LS({prompt:T,model:t.model})}}catch(T){let R=T instanceof Error?T.message:String(T??"unknown error"),w={sessionId:h,error:R};d.push(w),t.onFailed?.(w);continue}try{Ee(h,b,"agent")}catch(T){let R=T instanceof Error?T.message:String(T??"unknown error"),w={sessionId:h,error:`setAutoTitle failed: ${R}`};d.push(w),t.onFailed?.(w);continue}c.push(h),t.onProgress?.({current:S,total:r,sessionId:h,title:b})}return{generated:c,skipped:u,failed:d}}var vu=null;var un=new Map,IS=300*1e3;function ln(e,t,n){let s=e.events.length+1;e.events.push({id:s,kind:t,data:n});for(let r of e.waiters)r.resolve();e.waiters.clear()}function jS(e){e.cleanupTimer&&clearTimeout(e.cleanupTimer),e.cleanupTimer=setTimeout(()=>{un.delete(e.jobId)},IS)}function MS(e){let t=0,n=0,s=0;for(let r of e.events)r.kind==="progress"&&(t+=1),r.kind==="skipped"&&(n+=1),r.kind==="error"&&(s+=1);return{jobId:e.jobId,threadId:e.threadId,status:e.status,startedAt:e.startedAt,endedAt:e.endedAt,total:e.total,done:t,skipped:n,failed:s,result:e.result}}function ju(e){let t=vS(),n=new AbortController,s={jobId:t,threadId:e.threadId,status:"running",startedAt:new Date().toISOString(),endedAt:null,total:0,events:[],waiters:new Set,controller:n,result:null,cleanupTimer:null};return un.set(t,s),(async()=>{await Promise.resolve();try{let r=await Iu(e.threadId,{force:e.force??!1,signal:n.signal,model:e.model,onProgress:o=>{s.total=o.total,ln(s,"progress",o)},onSkipped:o=>{ln(s,"skipped",o)},onFailed:o=>{ln(s,"error",o)}});s.result=r,s.status=n.signal.aborted?"cancelled":"done",s.endedAt=new Date().toISOString(),ln(s,"done",r)}catch(r){let o=r instanceof Error?r.message:String(r??"unknown error");s.result={generated:[],skipped:[],failed:[{sessionId:e.threadId,error:o}]},s.status="failed",s.endedAt=new Date().toISOString(),ln(s,"done",s.result)}finally{jS(s)}})(),t}async function*Mu(e,t=0){let n=un.get(e);if(!n)return;let s=t;for(;;){for(;s<n.events.length;){let r=n.events[s];if(s+=1,yield r,r.kind==="done")return}if(n.endedAt)return;await new Promise(r=>{n.waiters.add({resolve:r})})}}function Du(e){let t=un.get(e);return!t||t.status!=="running"?!1:(t.controller.abort(),!0)}function jo(e){let t=un.get(e);return t?MS(t):null}import{existsSync as Fu,mkdirSync as DS,readFileSync as FS,writeFileSync as PS,chmodSync as $S}from"node:fs";import{homedir as US}from"node:os";import{join as Pu}from"node:path";import{z as He}from"zod";function $u(){return process.env.RECALL_HOME??Pu(US(),".recall")}function BS(){let e=$u();Fu(e)||DS(e,{recursive:!0})}function Uu(){return Pu($u(),"config.json")}var Ms=He.object({enabled:He.boolean().default(!1),backend:He.enum(["api","mcp"]).default("api"),apiKey:He.string().optional(),model:He.string().default("claude-opus-4-7"),maxTagsPerSession:He.number().int().min(1).max(10).default(4),minTagsPerSession:He.number().int().min(1).max(10).default(2),autopilot:He.boolean().default(!1)}),js={enabled:!1,backend:"api",model:"claude-opus-4-7",maxTagsPerSession:4,minTagsPerSession:2,autopilot:!1};function Bu(){let e=Uu();if(!Fu(e))return{};try{return JSON.parse(FS(e,"utf8"))}catch(t){return console.error("[auto-tag-config] failed to parse config.json, using defaults:",t),{}}}function Fe(){let e=Bu().autoTag;if(!e)return{...js};let t=Ms.safeParse({...js,...e});return t.success?t.data:{...js}}function Hu(e){BS();let t=Bu(),n=Ms.parse({...js,...t.autoTag??{},...e}),s={...t,autoTag:n},r=Uu();PS(r,JSON.stringify(s,null,2));try{$S(r,384)}catch(o){console.error("[auto-tag-config] chmod 0600 failed (continuing):",o)}return n}function Mo(e){let{apiKey:t,...n}=e;return{...n,apiKey:t?"sk-ant-\u2026":null,hasApiKey:!!t}}U();var Ds="claude-haiku-4-5-20251001",Wu=80,HS=2e3,At=class extends Error{sessionId;constructor(t){super(`no neighborhood context available for session ${t}`),this.name="NoContextAvailableError",this.sessionId=t}},qu=null;async function WS(e,t){if(qu)return qu(e,t);let{spawnClaudePrompt:n,isClaudeCliAvailable:s}=await Promise.resolve().then(()=>(ye(),tt));return s()?n(e,[],{model:t}):{success:!1,stdout:"",stderr:"claude CLI not found on PATH",exitCode:null}}function qS(e){let n=f().prepare(`SELECT s.id,
1461
+ ${n}`}function XS(e){return Le(e)?.auto_title_source??null}async function JS(e){let{spawnClaudePrompt:t,isClaudeCliAvailable:n}=await Promise.resolve().then(()=>(ye(),et));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=GS(s.stdout);if(!r)throw new Error("claude CLI returned an empty title");return r.slice(0,HS)}function GS(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 Pu(s)}}catch{}return Pu(t)}function Pu(e){return e.trim().replace(/^["'`]+|["'`]+$/g,"").replace(/\s+/g," ").replace(/[.!?]+$/g,"").trim()}async function Uu(e,t={}){let n=ie(e);if(!n)throw new Error(`thread not found: ${e}`);let s=WS(n.edges),r=s.length,o=t.force??!1,a=t.signal,c=[],u=[],d=[];for(let m=0;m<s.length;m++){let h=s[m],b=m+1;if(a?.aborted){let T={sessionId:h,reason:"cancelled"};u.push(T),t.onSkipped?.(T);continue}if(!o&&XS(h)==="agent"){let T={sessionId:h,reason:"already-titled"};u.push(T),t.onSkipped?.(T);continue}let S;try{if($u)S=await $u({sessionId:h,current:b,total:r});else{let T=qS({sessionId:h,current:b,total:r});S=await JS({prompt:T,model:t.model})}}catch(T){let R=T instanceof Error?T.message:String(T??"unknown error"),O={sessionId:h,error:R};d.push(O),t.onFailed?.(O);continue}try{Ee(h,S,"agent")}catch(T){let R=T instanceof Error?T.message:String(T??"unknown error"),O={sessionId:h,error:`setAutoTitle failed: ${R}`};d.push(O),t.onFailed?.(O);continue}c.push(h),t.onProgress?.({current:b,total:r,sessionId:h,title:S})}return{generated:c,skipped:u,failed:d}}var $u=null;var un=new Map,zS=300*1e3;function ln(e,t,n){let s=e.events.length+1;e.events.push({id:s,kind:t,data:n});for(let r of e.waiters)r.resolve();e.waiters.clear()}function KS(e){e.cleanupTimer&&clearTimeout(e.cleanupTimer),e.cleanupTimer=setTimeout(()=>{un.delete(e.jobId)},zS)}function VS(e){let t=0,n=0,s=0;for(let r of e.events)r.kind==="progress"&&(t+=1),r.kind==="skipped"&&(n+=1),r.kind==="error"&&(s+=1);return{jobId:e.jobId,threadId:e.threadId,status:e.status,startedAt:e.startedAt,endedAt:e.endedAt,total:e.total,done:t,skipped:n,failed:s,result:e.result}}function Bu(e){let t=YS(),n=new AbortController,s={jobId:t,threadId:e.threadId,status:"running",startedAt:new Date().toISOString(),endedAt:null,total:0,events:[],waiters:new Set,controller:n,result:null,cleanupTimer:null};return un.set(t,s),(async()=>{await Promise.resolve();try{let r=await Uu(e.threadId,{force:e.force??!1,signal:n.signal,model:e.model,onProgress:o=>{s.total=o.total,ln(s,"progress",o)},onSkipped:o=>{ln(s,"skipped",o)},onFailed:o=>{ln(s,"error",o)}});s.result=r,s.status=n.signal.aborted?"cancelled":"done",s.endedAt=new Date().toISOString(),ln(s,"done",r)}catch(r){let o=r instanceof Error?r.message:String(r??"unknown error");s.result={generated:[],skipped:[],failed:[{sessionId:e.threadId,error:o}]},s.status="failed",s.endedAt=new Date().toISOString(),ln(s,"done",s.result)}finally{KS(s)}})(),t}async function*Hu(e,t=0){let n=un.get(e);if(!n)return;let s=t;for(;;){for(;s<n.events.length;){let r=n.events[s];if(s+=1,yield r,r.kind==="done")return}if(n.endedAt)return;await new Promise(r=>{n.waiters.add({resolve:r})})}}function Wu(e){let t=un.get(e);return!t||t.status!=="running"?!1:(t.controller.abort(),!0)}function Fo(e){let t=un.get(e);return t?VS(t):null}import{existsSync as qu,mkdirSync as ZS,readFileSync as QS,writeFileSync as eT,chmodSync as tT}from"node:fs";import{homedir as nT}from"node:os";import{join as Xu}from"node:path";import{z as He}from"zod";function Ju(){return process.env.RECALL_HOME??Xu(nT(),".recall")}function sT(){let e=Ju();qu(e)||ZS(e,{recursive:!0})}function Gu(){return Xu(Ju(),"config.json")}var Ds=He.object({enabled:He.boolean().default(!1),backend:He.enum(["api","mcp"]).default("api"),apiKey:He.string().optional(),model:He.string().default("claude-opus-4-7"),maxTagsPerSession:He.number().int().min(1).max(10).default(4),minTagsPerSession:He.number().int().min(1).max(10).default(2),autopilot:He.boolean().default(!1)}),Ms={enabled:!1,backend:"api",model:"claude-opus-4-7",maxTagsPerSession:4,minTagsPerSession:2,autopilot:!1};function Yu(){let e=Gu();if(!qu(e))return{};try{return JSON.parse(QS(e,"utf8"))}catch(t){return console.error("[auto-tag-config] failed to parse config.json, using defaults:",t),{}}}function Fe(){let e=Yu().autoTag;if(!e)return{...Ms};let t=Ds.safeParse({...Ms,...e});return t.success?t.data:{...Ms}}function zu(e){sT();let t=Yu(),n=Ds.parse({...Ms,...t.autoTag??{},...e}),s={...t,autoTag:n},r=Gu();eT(r,JSON.stringify(s,null,2));try{tT(r,384)}catch(o){console.error("[auto-tag-config] chmod 0600 failed (continuing):",o)}return n}function Po(e){let{apiKey:t,...n}=e;return{...n,apiKey:t?"sk-ant-\u2026":null,hasApiKey:!!t}}B();var Fs="claude-haiku-4-5-20251001",Ku=80,rT=2e3,At=class extends Error{sessionId;constructor(t){super(`no neighborhood context available for session ${t}`),this.name="NoContextAvailableError",this.sessionId=t}},Vu=null;async function oT(e,t){if(Vu)return Vu(e,t);let{spawnClaudePrompt:n,isClaudeCliAvailable:s}=await Promise.resolve().then(()=>(ye(),et));return s()?n(e,[],{model:t}):{success:!1,stdout:"",stderr:"claude CLI not found on PATH",exitCode:null}}function iT(e){let n=f().prepare(`SELECT s.id,
1445
1462
  s.auto_title,
1446
1463
  s.auto_title_source,
1447
1464
  CASE WHEN sa.alias IS NOT NULL AND sa.alias != ''
1448
1465
  THEN 1 ELSE 0 END AS has_alias_int
1449
1466
  FROM sessions s
1450
1467
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1451
- WHERE s.id = ?`).get(e);return n?{id:n.id,auto_title:n.auto_title,auto_title_source:n.auto_title_source??null,has_alias:n.has_alias_int===1}:null}function XS(e){return e.parents.length===0&&e.children.length===0&&e.citations.length===0&&e.similar.length===0&&e.cousins.length===0&&e.wikiLinks.length===0}function JS(e,t){if(e.has_alias)return{eligible:!1,reason:"manual_alias"};let n=tn({auto_title:e.auto_title,auto_title_source:e.auto_title_source,has_alias:e.has_alias});if(t)return{eligible:!0};switch(n){case"low_signal":case"recursive_meta":case"programmatic":return{eligible:!0};case"agent":return{eligible:!1,reason:"agent_titled"};case"manual_alias":return{eligible:!1,reason:"manual_alias"};default:return{eligible:!1,reason:"clean"}}}function YS(e){return["You are renaming a Claude Code session. Below is its NEIGHBORHOOD: parent","sessions, child sessions, related sessions, and citations \u2014 assembled by","Claude Recall's cog-graph. The session itself has a low-signal or","self-referential title that needs replacement.","","Read the neighborhood, then mint a single descriptive title that","reflects this session's role in the surrounding work. Constraints:","","- Maximum 80 characters.","- No quotes, no trailing punctuation.","- Output ONLY a JSON object with two fields:",' { "title": "<\u226480 char title>", "evidence": "<one sentence why>" }',"- No markdown, no preface, no commentary outside the JSON.","","--- NEIGHBORHOOD BUNDLE ---",e,"--- END NEIGHBORHOOD BUNDLE ---"].join(`
1452
- `)}function GS(e){let t=e.trim();if(!t)return null;let n=t;try{let o=JSON.parse(t);if(o&&typeof o=="object"){let a=o;if(typeof a.result=="string")n=a.result.trim();else if(typeof a.title=="string")return Xu(a)}}catch{}let s=n.match(/```(?:json)?\s*\n([\s\S]*?)\n?```/i);s&&(n=s[1].trim());let r=null;try{r=JSON.parse(n)}catch{let o=n.indexOf("{"),a=n.lastIndexOf("}");if(o>=0&&a>o)try{r=JSON.parse(n.slice(o,a+1))}catch{return null}else return null}return!r||typeof r!="object"?null:Xu(r)}function Xu(e){let t=e.title;if(typeof t!="string")return null;let n=zS(t).trim();if(!n)return null;let s=e.evidence,r=typeof s=="string"?s.trim():"";return{title:n,evidence:r}}function zS(e){return e.replace(/^["'`]+|["'`]+$/g,"")}function KS(e){let t=e.replace(/\s+/g," ").trim().replace(/[.!?]+$/g,"").trim();return t.length<=Wu?t:t.slice(0,Wu)}function VS(e,t){let n=e.auto_title??"";return!n&&e.has_alias&&(n=f().prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(e.id)?.alias??""),{session_id:e.id,title:n,source:e.auto_title_source,confidence:0,evidence:`skipped: ${t}`,written:!1,skipped:t}}async function Do(e,t={}){if(t.signal?.aborted)return{session_id:e,title:"",source:null,confidence:0,evidence:"aborted before start",written:!1,skipped:"aborted"};let n=qS(e);if(!n)throw new Error(`session not found: ${e}`);let s=JS(n,t.force===!0);if(!s.eligible)return VS(n,s.reason);let r=t.budget??HS,o=Is(e,{budget:r});if(XS(o))throw new At(e);if(t.signal?.aborted)return{session_id:e,title:n.auto_title??"",source:n.auto_title_source,confidence:0,evidence:"aborted before CLI call",written:!1,skipped:"aborted"};let a=YS(o.bundle),c=t.model??Ds,u=await WS(a,c);if(!u.success){let b=u.stderr.slice(-300);throw new Error(`claude CLI exited ${u.exitCode}: ${b||"no stderr captured"}`)}let d=GS(u.stdout);if(!d)throw new Error("failed to parse regeneration output: not valid JSON {title, evidence}");if(!d.title||!d.title.trim())throw new Error("regeneration produced empty title");let m=KS(d.title);if(!m)throw new Error("regeneration produced empty title after clamp");Ee(e,m,"agent");let S=Le(e)?.auto_title??m;return{session_id:e,title:S,source:"agent",confidence:QS(o),evidence:d.evidence||`regenerated from neighborhood (${ZS(o)})`,written:!0}}function ZS(e){let t=[];return e.parents.length&&t.push(`${e.parents.length} parents`),e.children.length&&t.push(`${e.children.length} children`),e.citations.length&&t.push(`${e.citations.length} citations`),e.similar.length&&t.push(`${e.similar.length} similar`),e.cousins.length&&t.push(`${e.cousins.length} cousins`),e.wikiLinks.length&&t.push(`${e.wikiLinks.length} wiki-links`),t.join(", ")}function QS(e){let t=e.parents.length,n=e.children.length,s=e.citations.length,r=e.similar.length,o=e.cousins.length,a=e.wikiLinks.length,c=.25*Math.min(1,t)+.15*Math.min(1,n)+.2*Math.min(1,s/2)+.15*Math.min(1,r/3)+.1*Math.min(1,o/3)+.15*Math.min(1,a);return Math.min(.95,c)}import{streamSSE as Ge}from"hono/streaming";import{bodyLimit as Rw}from"hono/body-limit";import{z as D}from"zod";U();U();Ve();function dn(e){return f().prepare("SELECT id, name FROM projects WHERE name = ? LIMIT 1").get(e)??null}U();function Ju(e){let t=f(),n=new Date().toISOString();return t.prepare(`INSERT INTO bug_signature_resolutions
1468
+ WHERE s.id = ?`).get(e);return n?{id:n.id,auto_title:n.auto_title,auto_title_source:n.auto_title_source??null,has_alias:n.has_alias_int===1}:null}function aT(e){return e.parents.length===0&&e.children.length===0&&e.citations.length===0&&e.similar.length===0&&e.cousins.length===0&&e.wikiLinks.length===0}function cT(e,t){if(e.has_alias)return{eligible:!1,reason:"manual_alias"};let n=tn({auto_title:e.auto_title,auto_title_source:e.auto_title_source,has_alias:e.has_alias});if(t)return{eligible:!0};switch(n){case"low_signal":case"recursive_meta":case"programmatic":return{eligible:!0};case"agent":return{eligible:!1,reason:"agent_titled"};case"manual_alias":return{eligible:!1,reason:"manual_alias"};default:return{eligible:!1,reason:"clean"}}}function lT(e){return["You are renaming a Claude Code session. Below is its NEIGHBORHOOD: parent","sessions, child sessions, related sessions, and citations \u2014 assembled by","Claude Recall's cog-graph. The session itself has a low-signal or","self-referential title that needs replacement.","","Read the neighborhood, then mint a single descriptive title that","reflects this session's role in the surrounding work. Constraints:","","- Maximum 80 characters.","- No quotes, no trailing punctuation.","- Output ONLY a JSON object with two fields:",' { "title": "<\u226480 char title>", "evidence": "<one sentence why>" }',"- No markdown, no preface, no commentary outside the JSON.","","--- NEIGHBORHOOD BUNDLE ---",e,"--- END NEIGHBORHOOD BUNDLE ---"].join(`
1469
+ `)}function uT(e){let t=e.trim();if(!t)return null;let n=t;try{let o=JSON.parse(t);if(o&&typeof o=="object"){let a=o;if(typeof a.result=="string")n=a.result.trim();else if(typeof a.title=="string")return Zu(a)}}catch{}let s=n.match(/```(?:json)?\s*\n([\s\S]*?)\n?```/i);s&&(n=s[1].trim());let r=null;try{r=JSON.parse(n)}catch{let o=n.indexOf("{"),a=n.lastIndexOf("}");if(o>=0&&a>o)try{r=JSON.parse(n.slice(o,a+1))}catch{return null}else return null}return!r||typeof r!="object"?null:Zu(r)}function Zu(e){let t=e.title;if(typeof t!="string")return null;let n=dT(t).trim();if(!n)return null;let s=e.evidence,r=typeof s=="string"?s.trim():"";return{title:n,evidence:r}}function dT(e){return e.replace(/^["'`]+|["'`]+$/g,"")}function pT(e){let t=e.replace(/\s+/g," ").trim().replace(/[.!?]+$/g,"").trim();return t.length<=Ku?t:t.slice(0,Ku)}function mT(e,t){let n=e.auto_title??"";return!n&&e.has_alias&&(n=f().prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(e.id)?.alias??""),{session_id:e.id,title:n,source:e.auto_title_source,confidence:0,evidence:`skipped: ${t}`,written:!1,skipped:t}}async function $o(e,t={}){if(t.signal?.aborted)return{session_id:e,title:"",source:null,confidence:0,evidence:"aborted before start",written:!1,skipped:"aborted"};let n=iT(e);if(!n)throw new Error(`session not found: ${e}`);let s=cT(n,t.force===!0);if(!s.eligible)return mT(n,s.reason);let r=t.budget??rT,o=js(e,{budget:r});if(aT(o))throw new At(e);if(t.signal?.aborted)return{session_id:e,title:n.auto_title??"",source:n.auto_title_source,confidence:0,evidence:"aborted before CLI call",written:!1,skipped:"aborted"};let a=lT(o.bundle),c=t.model??Fs,u=await oT(a,c);if(!u.success){let S=u.stderr.slice(-300);throw new Error(`claude CLI exited ${u.exitCode}: ${S||"no stderr captured"}`)}let d=uT(u.stdout);if(!d)throw new Error("failed to parse regeneration output: not valid JSON {title, evidence}");if(!d.title||!d.title.trim())throw new Error("regeneration produced empty title");let m=pT(d.title);if(!m)throw new Error("regeneration produced empty title after clamp");Ee(e,m,"agent");let b=Le(e)?.auto_title??m;return{session_id:e,title:b,source:"agent",confidence:_T(o),evidence:d.evidence||`regenerated from neighborhood (${gT(o)})`,written:!0}}function gT(e){let t=[];return e.parents.length&&t.push(`${e.parents.length} parents`),e.children.length&&t.push(`${e.children.length} children`),e.citations.length&&t.push(`${e.citations.length} citations`),e.similar.length&&t.push(`${e.similar.length} similar`),e.cousins.length&&t.push(`${e.cousins.length} cousins`),e.wikiLinks.length&&t.push(`${e.wikiLinks.length} wiki-links`),t.join(", ")}function _T(e){let t=e.parents.length,n=e.children.length,s=e.citations.length,r=e.similar.length,o=e.cousins.length,a=e.wikiLinks.length,c=.25*Math.min(1,t)+.15*Math.min(1,n)+.2*Math.min(1,s/2)+.15*Math.min(1,r/3)+.1*Math.min(1,o/3)+.15*Math.min(1,a);return Math.min(.95,c)}import{streamSSE as Ye}from"hono/streaming";import{bodyLimit as Jw}from"hono/body-limit";import{z as D}from"zod";B();B();ct();function dn(e){return f().prepare("SELECT id, name FROM projects WHERE name = ? LIMIT 1").get(e)??null}B();function Qu(e){let t=f(),n=new Date().toISOString();return t.prepare(`INSERT INTO bug_signature_resolutions
1453
1470
  (message_hash, resolved_in_session_id, fix_summary, resolved_at, unresolved_at)
1454
1471
  VALUES (?, ?, ?, ?, NULL)
1455
1472
  ON CONFLICT(message_hash) DO UPDATE SET
1456
1473
  resolved_in_session_id = excluded.resolved_in_session_id,
1457
1474
  fix_summary = excluded.fix_summary,
1458
1475
  resolved_at = excluded.resolved_at,
1459
- unresolved_at = NULL`).run(e.messageHash,e.resolvedInSessionId??null,e.fixSummary??null,n),eT(e.messageHash)}function Yu(e){f().prepare(`UPDATE bug_signature_resolutions
1476
+ unresolved_at = NULL`).run(e.messageHash,e.resolvedInSessionId??null,e.fixSummary??null,n),fT(e.messageHash)}function ed(e){f().prepare(`UPDATE bug_signature_resolutions
1460
1477
  SET unresolved_at = ?
1461
- WHERE message_hash = ?`).run(new Date().toISOString(),e)}function eT(e){return f().prepare("SELECT * FROM bug_signature_resolutions WHERE message_hash = ?").get(e)??null}function Fo(e){if(e.length===0)return new Map;let t=f(),n=e.map(()=>"?").join(","),s=t.prepare(`SELECT * FROM bug_signature_resolutions
1462
- WHERE message_hash IN (${n})`).all(...e),r=new Map;for(let o of s)r.set(o.message_hash,o);return r}function Po(e){return!!e&&e.unresolved_at===null}U();function pn(){return new Date().toISOString()}function $o(){let e=f(),t=e.prepare(`SELECT id, name, description, created_at, updated_at
1478
+ WHERE message_hash = ?`).run(new Date().toISOString(),e)}function fT(e){return f().prepare("SELECT * FROM bug_signature_resolutions WHERE message_hash = ?").get(e)??null}function Uo(e){if(e.length===0)return new Map;let t=f(),n=e.map(()=>"?").join(","),s=t.prepare(`SELECT * FROM bug_signature_resolutions
1479
+ WHERE message_hash IN (${n})`).all(...e),r=new Map;for(let o of s)r.set(o.message_hash,o);return r}function Bo(e){return!!e&&e.unresolved_at===null}B();function pn(){return new Date().toISOString()}function Ho(){let e=f(),t=e.prepare(`SELECT id, name, description, created_at, updated_at
1463
1480
  FROM macro_repos
1464
1481
  ORDER BY name COLLATE NOCASE`).all();if(t.length===0)return[];let n=t.map(a=>a.id),s=n.map(()=>"?").join(","),r=e.prepare(`SELECT m.macro_repo_id, m.project_id, p.name AS project_name
1465
1482
  FROM macro_repo_members m
1466
1483
  JOIN projects p ON p.id = m.project_id
1467
1484
  WHERE m.macro_repo_id IN (${s})
1468
- ORDER BY p.name COLLATE NOCASE`).all(...n),o=new Map;for(let a of t)o.set(a.id,{...a,member_project_ids:[],member_project_names:[]});for(let a of r){let c=o.get(a.macro_repo_id);c&&(c.member_project_ids.push(a.project_id),c.member_project_names.push(a.project_name))}return Array.from(o.values())}function xt(e){return $o().find(n=>n.id===e)??null}function Gu(){return f().prepare(`SELECT p.id, p.name
1485
+ ORDER BY p.name COLLATE NOCASE`).all(...n),o=new Map;for(let a of t)o.set(a.id,{...a,member_project_ids:[],member_project_names:[]});for(let a of r){let c=o.get(a.macro_repo_id);c&&(c.member_project_ids.push(a.project_id),c.member_project_names.push(a.project_name))}return Array.from(o.values())}function xt(e){return Ho().find(n=>n.id===e)??null}function td(){return f().prepare(`SELECT p.id, p.name
1469
1486
  FROM projects p
1470
1487
  LEFT JOIN macro_repo_members m ON m.project_id = p.id
1471
1488
  WHERE m.project_id IS NULL
1472
- ORDER BY p.name COLLATE NOCASE`).all()}function zu(e){let t=e.name.trim();if(!t)throw new Error("macro repo name is required");let n=f(),s=pn(),r=n.prepare(`INSERT INTO macro_repos (name, description, created_at, updated_at)
1473
- VALUES (?, ?, ?, ?)`).run(t,e.description??null,s,s),o=Number(r.lastInsertRowid);return xt(o)}function Ku(e,t){let n=xt(e);if(!n)throw new Error(`macro repo ${e} not found`);let s=t.name!==void 0?t.name.trim():n.name;if(!s)throw new Error("macro repo name cannot be empty");let r=t.description!==void 0?t.description:n.description;return f().prepare(`UPDATE macro_repos
1489
+ ORDER BY p.name COLLATE NOCASE`).all()}function nd(e){let t=e.name.trim();if(!t)throw new Error("macro repo name is required");let n=f(),s=pn(),r=n.prepare(`INSERT INTO macro_repos (name, description, created_at, updated_at)
1490
+ VALUES (?, ?, ?, ?)`).run(t,e.description??null,s,s),o=Number(r.lastInsertRowid);return xt(o)}function sd(e,t){let n=xt(e);if(!n)throw new Error(`macro repo ${e} not found`);let s=t.name!==void 0?t.name.trim():n.name;if(!s)throw new Error("macro repo name cannot be empty");let r=t.description!==void 0?t.description:n.description;return f().prepare(`UPDATE macro_repos
1474
1491
  SET name = ?, description = ?, updated_at = ?
1475
- WHERE id = ?`).run(s,r,pn(),e),xt(e)}function Vu(e){f().prepare("DELETE FROM macro_repos WHERE id = ?").run(e)}function Zu(e,t){let n=f();if(!n.prepare("SELECT 1 FROM macro_repos WHERE id = ?").get(e))throw new Error(`macro repo ${e} not found`);if(!n.prepare("SELECT 1 FROM projects WHERE id = ?").get(t))throw new Error(`project ${t} not found`);n.prepare(`INSERT OR IGNORE INTO macro_repo_members (macro_repo_id, project_id, added_at)
1476
- VALUES (?, ?, ?)`).run(e,t,pn()),n.prepare("UPDATE macro_repos SET updated_at = ? WHERE id = ?").run(pn(),e)}function Qu(e,t){let n=f();n.prepare(`DELETE FROM macro_repo_members
1477
- WHERE macro_repo_id = ? AND project_id = ?`).run(e,t),n.prepare("UPDATE macro_repos SET updated_at = ? WHERE id = ?").run(pn(),e)}U();function ed(e){let t=f(),n=new Date().toISOString(),s=t.prepare(`INSERT INTO bug_synthesis_results
1492
+ WHERE id = ?`).run(s,r,pn(),e),xt(e)}function rd(e){f().prepare("DELETE FROM macro_repos WHERE id = ?").run(e)}function od(e,t){let n=f();if(!n.prepare("SELECT 1 FROM macro_repos WHERE id = ?").get(e))throw new Error(`macro repo ${e} not found`);if(!n.prepare("SELECT 1 FROM projects WHERE id = ?").get(t))throw new Error(`project ${t} not found`);n.prepare(`INSERT OR IGNORE INTO macro_repo_members (macro_repo_id, project_id, added_at)
1493
+ VALUES (?, ?, ?)`).run(e,t,pn()),n.prepare("UPDATE macro_repos SET updated_at = ? WHERE id = ?").run(pn(),e)}function id(e,t){let n=f();n.prepare(`DELETE FROM macro_repo_members
1494
+ WHERE macro_repo_id = ? AND project_id = ?`).run(e,t),n.prepare("UPDATE macro_repos SET updated_at = ? WHERE id = ?").run(pn(),e)}B();function ad(e){let t=f(),n=new Date().toISOString(),s=t.prepare(`INSERT INTO bug_synthesis_results
1478
1495
  (scope, target_id, mode, model, output_markdown, input_tokens, output_tokens, context_summary, created_at, job_id)
1479
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(e.scope,e.target_id,e.mode,e.model,e.output_markdown,e.input_tokens,e.output_tokens,JSON.stringify(e.context_summary??{}),n,e.job_id??null),r=Number(s.lastInsertRowid);return Uo(r)}function td(e){let t={};try{t=JSON.parse(e.context_summary)}catch{t={}}return{id:e.id,scope:e.scope,target_id:e.target_id,mode:e.mode,model:e.model,output_markdown:e.output_markdown,input_tokens:e.input_tokens,output_tokens:e.output_tokens,context_summary:t,created_at:e.created_at,job_id:e.job_id}}function Uo(e){let n=f().prepare("SELECT * FROM bug_synthesis_results WHERE id = ?").get(e);return n?td(n):null}function nd(e={}){let t=f(),n=[],s=[];e.scope&&(n.push("scope = ?"),s.push(e.scope)),e.target_id&&(n.push("target_id = ?"),s.push(e.target_id));let r=n.length?`WHERE ${n.join(" AND ")}`:"",o=Math.min(Math.max(1,e.limit??50),500);return t.prepare(`SELECT * FROM bug_synthesis_results
1496
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(e.scope,e.target_id,e.mode,e.model,e.output_markdown,e.input_tokens,e.output_tokens,JSON.stringify(e.context_summary??{}),n,e.job_id??null),r=Number(s.lastInsertRowid);return Wo(r)}function cd(e){let t={};try{t=JSON.parse(e.context_summary)}catch{t={}}return{id:e.id,scope:e.scope,target_id:e.target_id,mode:e.mode,model:e.model,output_markdown:e.output_markdown,input_tokens:e.input_tokens,output_tokens:e.output_tokens,context_summary:t,created_at:e.created_at,job_id:e.job_id}}function Wo(e){let n=f().prepare("SELECT * FROM bug_synthesis_results WHERE id = ?").get(e);return n?cd(n):null}function ld(e={}){let t=f(),n=[],s=[];e.scope&&(n.push("scope = ?"),s.push(e.scope)),e.target_id&&(n.push("target_id = ?"),s.push(e.target_id));let r=n.length?`WHERE ${n.join(" AND ")}`:"",o=Math.min(Math.max(1,e.limit??50),500);return t.prepare(`SELECT * FROM bug_synthesis_results
1480
1497
  ${r}
1481
1498
  ORDER BY created_at DESC
1482
- LIMIT ?`).all(...s,o).map(td)}function sd(e){let n=f().prepare(`SELECT target_id, COUNT(*) AS n
1499
+ LIMIT ?`).all(...s,o).map(cd)}function ud(e){let n=f().prepare(`SELECT target_id, COUNT(*) AS n
1483
1500
  FROM bug_synthesis_results
1484
1501
  WHERE scope = ?
1485
- GROUP BY target_id`).all(e),s=new Map;for(let r of n)s.set(r.target_id,r.n);return s}function rd(e){f().prepare("DELETE FROM bug_synthesis_results WHERE id = ?").run(e)}import{randomBytes as tT,timingSafeEqual as nT}from"node:crypto";var sT=6e4,rT=new Set(["127.0.0.1","localhost"]),mn=new Map;function Bo(){return Date.now()}function od(){let e=Bo();for(let[t,n]of mn)(n.expiresAt<=e||n.used)&&mn.delete(t)}function Ce(e){let t=e.req.header("origin")??"";if(t)try{let r=new URL(t);if(!rT.has(r.hostname))return e.json({error:"forbidden: cross-origin launcher request rejected"},403)}catch{return e.json({error:"forbidden: invalid Origin header"},403)}let n=e.req.header("sec-fetch-site");return n&&n!=="same-origin"&&n!=="none"?e.json({error:"forbidden: Sec-Fetch-Site indicates cross-origin"},403):e.req.header("x-recall-launcher")!=="1"?e.json({error:"forbidden: missing X-Recall-Launcher header (this endpoint is callable only from the Recall web UI)"},403):null}function Ho(e){od();let t=tT(32).toString("hex"),n=Bo()+sT;return mn.set(t,{token:t,intent:e,expiresAt:n,used:!1}),{token:t,expiresAt:n}}function Wo(e){if(od(),typeof e!="string"||e.length!==64)return null;let t;try{t=Buffer.from(e,"hex")}catch{return null}if(t.length!==32)return null;for(let n of mn.values()){if(n.used||n.expiresAt<=Bo())continue;let s;try{s=Buffer.from(n.token,"hex")}catch{continue}if(s.length===t.length&&nT(s,t))return n.used=!0,mn.delete(n.token),n.intent}return null}import{existsSync as uT,mkdirSync as gO,readFileSync as dT,writeFileSync as _O}from"node:fs";import{homedir as pT}from"node:os";import{join as pd}from"node:path";import{z as qo}from"zod";import{appendFileSync as oT,existsSync as id,mkdirSync as iT,readFileSync as aT}from"node:fs";import{homedir as cT}from"node:os";import{join as ad}from"node:path";function cd(){return process.env.RECALL_HOME??ad(cT(),".recall")}function lT(){let e=cd();id(e)||iT(e,{recursive:!0})}function ld(){return ad(cd(),"launcher-audit.log")}function re(e){lT();let t={ts:new Date().toISOString(),...e};try{oT(ld(),JSON.stringify(t)+`
1486
- `,"utf8")}catch(n){console.error("[launcher-audit] failed to append:",n)}}function ud(e){let t=ld();if(!id(t))return{input_tokens:0,output_tokens:0,records_counted:0};let n=Date.now()-e,s=0,r=0,o=0,a;try{a=aT(t,"utf8")}catch{return{input_tokens:0,output_tokens:0,records_counted:0}}for(let c of a.split(`
1487
- `)){if(!c.trim())continue;let u;try{u=JSON.parse(c)}catch{continue}if(u.kind!=="run-completed"&&u.kind!=="synth-completed")continue;let d=Date.parse(u.ts);!Number.isFinite(d)||d<n||(s+=Number(u.input_tokens??0),r+=Number(u.output_tokens??0),o+=1)}return{input_tokens:s,output_tokens:r,records_counted:o}}var mT=1440*60*1e3,gT=qo.object({dailyTokenBudget:qo.number().int().nonnegative().default(1e6),sessionCeiling:qo.number().int().positive().max(1e4).default(500)}),Xo={dailyTokenBudget:1e6,sessionCeiling:500};function _T(){return process.env.RECALL_HOME??pd(pT(),".recall")}function fT(){return pd(_T(),"config.json")}function hT(){let e=fT();if(!uT(e))return{};try{return JSON.parse(dT(e,"utf8"))}catch(t){return console.error("[launcher-budget] failed to parse config.json, using defaults:",t),{}}}function Jo(){let e=hT().launcher;if(!e)return{...Xo};let t=gT.safeParse({...Xo,...e});return t.success?t.data:{...Xo}}function Nt(){let e=Jo(),t=ud(mT),n=t.input_tokens+t.output_tokens,s=Math.max(0,e.dailyTokenBudget-n);return{daily_token_budget:e.dailyTokenBudget,session_ceiling:e.sessionCeiling,spent_input_tokens_24h:t.input_tokens,spent_output_tokens_24h:t.output_tokens,spent_total_tokens_24h:n,remaining_tokens_24h:s}}function Yo(e){return{estimated_input_tokens_max:e*2e4,estimated_output_tokens_max:e*1e3}}function Go(e){let t=e.mode==="root_cause"?800:2e3;if(e.scope==="cluster")return{estimated_input_tokens_max:5e3+Math.min(8,Math.max(1,e.member_session_count??1))*3e3,estimated_output_tokens_max:t};let n=Math.max(1,e.cluster_count??1);return{estimated_input_tokens_max:Math.min(5e4,1e3*n),estimated_output_tokens_max:t}}var dd={pro:45,"max-5x":225,"max-20x":900};function ET(e){let t=e.toLowerCase();return t.includes("haiku")?1:t.includes("sonnet")?5:t.includes("opus")?10:5}var bT=4e3;function md(e){return Math.max(1,Math.ceil(e/bT))}function We(e,t){let n=ET(t),s=e*n,r=Object.keys(dd).map(o=>{let a=s/dd[o];return{plan:o,fraction:a,pct:Math.round(a*1e3)/10,would_exhaust_window:a>1}});return{model:t,model_multiplier:n,per_plan:r,caveat:"Estimates use Anthropic\u2019s public approximate caps and assume a multiplier of ~1x for Haiku, ~5x for Sonnet, ~10x for Opus. Anthropic adjusts these limits without notice; actual consumption depends on session size. Treat as planning guidance, not a contract."}}import{randomUUID as ST}from"node:crypto";var Ot=new Map,gn=new Map,TT=300*1e3;function Fs(e,t,n){e.events.push({id:e.events.length+1,kind:t,data:n});for(let s of e.waiters)s();e.waiters.clear()}function yT(e){e.cleanupTimer||(e.cleanupTimer=setTimeout(()=>{Ot.delete(e.jobId),gn.get(e.project)===e.jobId&&gn.delete(e.project)},TT),e.cleanupTimer.unref?.())}function zo(e){return{jobId:e.jobId,project:e.project,model:e.model,status:e.status,startedAt:e.startedAt,endedAt:e.endedAt,total:e.progress.total,processed:e.progress.processed,ok:e.progress.ok,failed:e.progress.failed,skipped:e.progress.skipped,total_input_tokens:e.progress.total_input_tokens,total_output_tokens:e.progress.total_output_tokens,current_session_id:e.progress.current_session_id,error:e.error}}function gd(e){let t=dn(e.project);if(!t)return{error:`project "${e.project}" not found`};let n=gn.get(t.name);if(n){let m=Ot.get(n);if(m&&m.status==="running")return{jobId:n,reused:!0};gn.delete(t.name)}let s=ST(),r=e.model??nt,o=Math.max(1,e.limit??200),a=e.force??!1,c=new AbortController,u=new Date().toISOString(),d={jobId:s,project:t.name,projectId:t.id,model:r,limit:o,force:a,status:"running",startedAt:u,endedAt:null,events:[],waiters:new Set,controller:c,progress:{total:0,processed:0,ok:0,failed:0,skipped:0,current_session_id:null,total_input_tokens:0,total_output_tokens:0},error:null,cleanupTimer:null};return Ot.set(s,d),gn.set(t.name,s),re({kind:"run-launched",job_id:s,project:t.name,model:r,limit:o,origin:e.origin??null}),(async()=>{await Promise.resolve();try{await Za({projectId:t.id,limit:o,force:a,model:r,signal:c.signal,onProgress:m=>{d.progress=m,Fs(d,"progress",m)},onResult:m=>{!m.ok&&!m.skipped&&Fs(d,"error",{session_id:m.session_id,reason:m.failed??"unknown"})}}),d.status=c.signal.aborted?"cancelled":"done",d.endedAt=new Date().toISOString(),Fs(d,"done",zo(d)),re({kind:d.status==="cancelled"?"run-cancelled":"run-completed",job_id:s,project:t.name,model:r,limit:o,origin:e.origin??null,input_tokens:d.progress.total_input_tokens,output_tokens:d.progress.total_output_tokens,sessions_processed:d.progress.processed})}catch(m){let h=m instanceof Error?m.message:String(m??"unknown error");d.status="failed",d.endedAt=new Date().toISOString(),d.error=h,Fs(d,"done",zo(d)),re({kind:"run-failed",job_id:s,project:t.name,model:r,limit:o,origin:e.origin??null,reason:h,input_tokens:d.progress.total_input_tokens,output_tokens:d.progress.total_output_tokens})}finally{yT(d)}})(),{jobId:s,reused:!1}}async function*_d(e,t=0){let n=Ot.get(e);if(!n)return;let s=t;for(;;){for(;s<n.events.length;){let r=n.events[s];if(!r)break;if(s+=1,yield r,r.kind==="done")return}if(n.status!=="running")return;await new Promise(r=>n.waiters.add(r))}}function fd(e){let t=Ot.get(e);return!t||t.status!=="running"?!1:(t.controller.abort(),!0)}function Ko(e){let t=Ot.get(e);return t?zo(t):null}U();import{randomUUID as wT}from"node:crypto";import{spawn as RT}from"node:child_process";$n();var hd="claude-haiku-4-5-20251001",Ct=new Map,hn=new Map,kT=300*1e3;function Ed(e){return`${e.scope}:${e.target_id}:${e.mode}`}function _n(e,t,n){e.events.push({id:e.events.length+1,kind:t,data:n});for(let s of e.waiters)s();e.waiters.clear()}function AT(e){e.cleanupTimer||(e.cleanupTimer=setTimeout(()=>{Ct.delete(e.jobId);let t=Ed(e.intent);hn.get(t)===e.jobId&&hn.delete(t)},kT),e.cleanupTimer.unref?.())}function Lt(e){return{jobId:e.jobId,scope:e.intent.scope,target_id:e.intent.target_id,mode:e.intent.mode,model:e.intent.model,status:e.status,output_markdown:e.output_markdown,input_tokens:e.input_tokens,output_tokens:e.output_tokens,startedAt:e.startedAt,endedAt:e.endedAt,error:e.error,context_summary:e.context_summary}}function bd(){return f().prepare(`SELECT s.id AS session_id, p.name AS project, s.auto_title,
1502
+ GROUP BY target_id`).all(e),s=new Map;for(let r of n)s.set(r.target_id,r.n);return s}function dd(e){f().prepare("DELETE FROM bug_synthesis_results WHERE id = ?").run(e)}import{randomBytes as hT,timingSafeEqual as ET}from"node:crypto";var bT=6e4,ST=new Set(["127.0.0.1","localhost"]),mn=new Map;function qo(){return Date.now()}function pd(){let e=qo();for(let[t,n]of mn)(n.expiresAt<=e||n.used)&&mn.delete(t)}function Ce(e){let t=e.req.header("origin")??"";if(t)try{let r=new URL(t);if(!ST.has(r.hostname))return e.json({error:"forbidden: cross-origin launcher request rejected"},403)}catch{return e.json({error:"forbidden: invalid Origin header"},403)}let n=e.req.header("sec-fetch-site");return n&&n!=="same-origin"&&n!=="none"?e.json({error:"forbidden: Sec-Fetch-Site indicates cross-origin"},403):e.req.header("x-recall-launcher")!=="1"?e.json({error:"forbidden: missing X-Recall-Launcher header (this endpoint is callable only from the Recall web UI)"},403):null}function Xo(e){pd();let t=hT(32).toString("hex"),n=qo()+bT;return mn.set(t,{token:t,intent:e,expiresAt:n,used:!1}),{token:t,expiresAt:n}}function Jo(e){if(pd(),typeof e!="string"||e.length!==64)return null;let t;try{t=Buffer.from(e,"hex")}catch{return null}if(t.length!==32)return null;for(let n of mn.values()){if(n.used||n.expiresAt<=qo())continue;let s;try{s=Buffer.from(n.token,"hex")}catch{continue}if(s.length===t.length&&ET(s,t))return n.used=!0,mn.delete(n.token),n.intent}return null}import{existsSync as AT,mkdirSync as FO,readFileSync as xT,writeFileSync as PO}from"node:fs";import{homedir as NT}from"node:os";import{join as bd}from"node:path";import{z as Go}from"zod";import{appendFileSync as TT,existsSync as md,mkdirSync as yT,readFileSync as wT}from"node:fs";import{homedir as RT}from"node:os";import{join as gd}from"node:path";function _d(){return process.env.RECALL_HOME??gd(RT(),".recall")}function kT(){let e=_d();md(e)||yT(e,{recursive:!0})}function fd(){return gd(_d(),"launcher-audit.log")}function re(e){kT();let t={ts:new Date().toISOString(),...e};try{TT(fd(),JSON.stringify(t)+`
1503
+ `,"utf8")}catch(n){console.error("[launcher-audit] failed to append:",n)}}function hd(e){let t=fd();if(!md(t))return{input_tokens:0,output_tokens:0,records_counted:0};let n=Date.now()-e,s=0,r=0,o=0,a;try{a=wT(t,"utf8")}catch{return{input_tokens:0,output_tokens:0,records_counted:0}}for(let c of a.split(`
1504
+ `)){if(!c.trim())continue;let u;try{u=JSON.parse(c)}catch{continue}if(u.kind!=="run-completed"&&u.kind!=="synth-completed")continue;let d=Date.parse(u.ts);!Number.isFinite(d)||d<n||(s+=Number(u.input_tokens??0),r+=Number(u.output_tokens??0),o+=1)}return{input_tokens:s,output_tokens:r,records_counted:o}}var OT=1440*60*1e3,LT=Go.object({dailyTokenBudget:Go.number().int().nonnegative().default(1e6),sessionCeiling:Go.number().int().positive().max(1e4).default(500)}),Yo={dailyTokenBudget:1e6,sessionCeiling:500};function CT(){return process.env.RECALL_HOME??bd(NT(),".recall")}function vT(){return bd(CT(),"config.json")}function IT(){let e=vT();if(!AT(e))return{};try{return JSON.parse(xT(e,"utf8"))}catch(t){return console.error("[launcher-budget] failed to parse config.json, using defaults:",t),{}}}function zo(){let e=IT().launcher;if(!e)return{...Yo};let t=LT.safeParse({...Yo,...e});return t.success?t.data:{...Yo}}function Nt(){let e=zo(),t=hd(OT),n=t.input_tokens+t.output_tokens,s=Math.max(0,e.dailyTokenBudget-n);return{daily_token_budget:e.dailyTokenBudget,session_ceiling:e.sessionCeiling,spent_input_tokens_24h:t.input_tokens,spent_output_tokens_24h:t.output_tokens,spent_total_tokens_24h:n,remaining_tokens_24h:s}}function Ko(e){return{estimated_input_tokens_max:e*2e4,estimated_output_tokens_max:e*1e3}}function Vo(e){let t=e.mode==="root_cause"?800:2e3;if(e.scope==="cluster")return{estimated_input_tokens_max:5e3+Math.min(8,Math.max(1,e.member_session_count??1))*3e3,estimated_output_tokens_max:t};let n=Math.max(1,e.cluster_count??1);return{estimated_input_tokens_max:Math.min(5e4,1e3*n),estimated_output_tokens_max:t}}var Ed={pro:45,"max-5x":225,"max-20x":900};function jT(e){let t=e.toLowerCase();return t.includes("haiku")?1:t.includes("sonnet")?5:t.includes("opus")?10:5}var MT=4e3;function Sd(e){return Math.max(1,Math.ceil(e/MT))}function We(e,t){let n=jT(t),s=e*n,r=Object.keys(Ed).map(o=>{let a=s/Ed[o];return{plan:o,fraction:a,pct:Math.round(a*1e3)/10,would_exhaust_window:a>1}});return{model:t,model_multiplier:n,per_plan:r,caveat:"Estimates use Anthropic\u2019s public approximate caps and assume a multiplier of ~1x for Haiku, ~5x for Sonnet, ~10x for Opus. Anthropic adjusts these limits without notice; actual consumption depends on session size. Treat as planning guidance, not a contract."}}import{randomUUID as DT}from"node:crypto";var Ot=new Map,gn=new Map,FT=300*1e3;function Ps(e,t,n){e.events.push({id:e.events.length+1,kind:t,data:n});for(let s of e.waiters)s();e.waiters.clear()}function PT(e){e.cleanupTimer||(e.cleanupTimer=setTimeout(()=>{Ot.delete(e.jobId),gn.get(e.project)===e.jobId&&gn.delete(e.project)},FT),e.cleanupTimer.unref?.())}function Zo(e){return{jobId:e.jobId,project:e.project,model:e.model,status:e.status,startedAt:e.startedAt,endedAt:e.endedAt,total:e.progress.total,processed:e.progress.processed,ok:e.progress.ok,failed:e.progress.failed,skipped:e.progress.skipped,total_input_tokens:e.progress.total_input_tokens,total_output_tokens:e.progress.total_output_tokens,current_session_id:e.progress.current_session_id,error:e.error}}function Td(e){let t=dn(e.project);if(!t)return{error:`project "${e.project}" not found`};let n=gn.get(t.name);if(n){let m=Ot.get(n);if(m&&m.status==="running")return{jobId:n,reused:!0};gn.delete(t.name)}let s=DT(),r=e.model??tt,o=Math.max(1,e.limit??200),a=e.force??!1,c=new AbortController,u=new Date().toISOString(),d={jobId:s,project:t.name,projectId:t.id,model:r,limit:o,force:a,status:"running",startedAt:u,endedAt:null,events:[],waiters:new Set,controller:c,progress:{total:0,processed:0,ok:0,failed:0,skipped:0,current_session_id:null,total_input_tokens:0,total_output_tokens:0},error:null,cleanupTimer:null};return Ot.set(s,d),gn.set(t.name,s),re({kind:"run-launched",job_id:s,project:t.name,model:r,limit:o,origin:e.origin??null}),(async()=>{await Promise.resolve();try{await sc({projectId:t.id,limit:o,force:a,model:r,signal:c.signal,onProgress:m=>{d.progress=m,Ps(d,"progress",m)},onResult:m=>{!m.ok&&!m.skipped&&Ps(d,"error",{session_id:m.session_id,reason:m.failed??"unknown"})}}),d.status=c.signal.aborted?"cancelled":"done",d.endedAt=new Date().toISOString(),Ps(d,"done",Zo(d)),re({kind:d.status==="cancelled"?"run-cancelled":"run-completed",job_id:s,project:t.name,model:r,limit:o,origin:e.origin??null,input_tokens:d.progress.total_input_tokens,output_tokens:d.progress.total_output_tokens,sessions_processed:d.progress.processed})}catch(m){let h=m instanceof Error?m.message:String(m??"unknown error");d.status="failed",d.endedAt=new Date().toISOString(),d.error=h,Ps(d,"done",Zo(d)),re({kind:"run-failed",job_id:s,project:t.name,model:r,limit:o,origin:e.origin??null,reason:h,input_tokens:d.progress.total_input_tokens,output_tokens:d.progress.total_output_tokens})}finally{PT(d)}})(),{jobId:s,reused:!1}}async function*yd(e,t=0){let n=Ot.get(e);if(!n)return;let s=t;for(;;){for(;s<n.events.length;){let r=n.events[s];if(!r)break;if(s+=1,yield r,r.kind==="done")return}if(n.status!=="running")return;await new Promise(r=>n.waiters.add(r))}}function wd(e){let t=Ot.get(e);return!t||t.status!=="running"?!1:(t.controller.abort(),!0)}function Qo(e){let t=Ot.get(e);return t?Zo(t):null}B();import{randomUUID as $T}from"node:crypto";import{spawn as UT}from"node:child_process";Un();var Rd="claude-haiku-4-5-20251001",Ct=new Map,hn=new Map,BT=300*1e3;function kd(e){return`${e.scope}:${e.target_id}:${e.mode}`}function _n(e,t,n){e.events.push({id:e.events.length+1,kind:t,data:n});for(let s of e.waiters)s();e.waiters.clear()}function HT(e){e.cleanupTimer||(e.cleanupTimer=setTimeout(()=>{Ct.delete(e.jobId);let t=kd(e.intent);hn.get(t)===e.jobId&&hn.delete(t)},BT),e.cleanupTimer.unref?.())}function Lt(e){return{jobId:e.jobId,scope:e.intent.scope,target_id:e.intent.target_id,mode:e.intent.mode,model:e.intent.model,status:e.status,output_markdown:e.output_markdown,input_tokens:e.input_tokens,output_tokens:e.output_tokens,startedAt:e.startedAt,endedAt:e.endedAt,error:e.error,context_summary:e.context_summary}}function Ad(){return f().prepare(`SELECT s.id AS session_id, p.name AS project, s.auto_title,
1488
1505
  oi.bug_signatures
1489
1506
  FROM session_output_index oi
1490
1507
  JOIN sessions s ON s.id = oi.session_id
1491
1508
  JOIN projects p ON p.id = s.project_id
1492
1509
  WHERE oi.bug_signatures IS NOT NULL
1493
- AND oi.bug_signatures != '[]'`).all()}function Sd(e){try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}function xT(e){let t=bd(),n=[];for(let a of t)for(let c of Sd(a.bug_signatures)){let u=c.message_hash??`nohash:${(c.snippet??"").slice(0,64)}`;(c.message_hash===e||u===e)&&n.push({sig:c,session_id:a.session_id,project:a.project,auto_title:a.auto_title})}if(n.length===0)return null;let s=n[0],r=Array.from(new Set(n.map(a=>a.session_id))),o=Array.from(new Set(n.map(a=>a.project))).sort();return{message_hash:s.sig.message_hash??null,error_type:s.sig.error_type??null,snippet:(s.sig.snippet??"").slice(0,400),file:s.sig.file??null,occurrence_count:n.length,projects:o,member_session_ids:r}}function NT(e){let t=bd().filter(o=>o.project===e),n=new Map;for(let o of t)for(let a of Sd(o.bug_signatures)){let c=a.message_hash??`nohash:${(a.snippet??"").slice(0,64)}`,u=n.get(c);u?(u.sigs.push(a),u.sessions.add(o.session_id)):n.set(c,{sigs:[a],first:a,sessions:new Set([o.session_id])})}let s=new Map;try{let o=Array.from(n.keys()).filter(a=>!a.startsWith("nohash:"));if(o.length>0){let a=f(),c=o.map(()=>"?").join(","),u=a.prepare(`SELECT message_hash, fix_summary
1510
+ AND oi.bug_signatures != '[]'`).all()}function xd(e){try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}function WT(e){let t=Ad(),n=[];for(let a of t)for(let c of xd(a.bug_signatures)){let u=c.message_hash??`nohash:${(c.snippet??"").slice(0,64)}`;(c.message_hash===e||u===e)&&n.push({sig:c,session_id:a.session_id,project:a.project,auto_title:a.auto_title})}if(n.length===0)return null;let s=n[0],r=Array.from(new Set(n.map(a=>a.session_id))),o=Array.from(new Set(n.map(a=>a.project))).sort();return{message_hash:s.sig.message_hash??null,error_type:s.sig.error_type??null,snippet:(s.sig.snippet??"").slice(0,400),file:s.sig.file??null,occurrence_count:n.length,projects:o,member_session_ids:r}}function qT(e){let t=Ad().filter(o=>o.project===e),n=new Map;for(let o of t)for(let a of xd(o.bug_signatures)){let c=a.message_hash??`nohash:${(a.snippet??"").slice(0,64)}`,u=n.get(c);u?(u.sigs.push(a),u.sessions.add(o.session_id)):n.set(c,{sigs:[a],first:a,sessions:new Set([o.session_id])})}let s=new Map;try{let o=Array.from(n.keys()).filter(a=>!a.startsWith("nohash:"));if(o.length>0){let a=f(),c=o.map(()=>"?").join(","),u=a.prepare(`SELECT message_hash, fix_summary
1494
1511
  FROM bug_signature_resolutions
1495
1512
  WHERE message_hash IN (${c})
1496
- AND unresolved_at IS NULL`).all(...o);for(let d of u)s.set(d.message_hash,{fix_summary:d.fix_summary})}}catch{}let r=[];for(let[o,a]of n){let c=a.first.message_hash??null,u=c?s.get(c)??null:null;r.push({cluster_id:c??o,error_type:a.first.error_type??null,snippet:(a.first.snippet??"").slice(0,200),file:a.first.file??null,occurrence_count:a.sessions.size,resolved:u!==null,fix_summary:u?.fix_summary??null})}return r.sort((o,a)=>a.occurrence_count-o.occurrence_count),r}function OT(e){let t=e.replace(/\s+/g," ").trim();return t.length===0?"":t.slice(0,Math.min(30,t.length))}function LT(e,t){let n=f(),s=OT(t),r=[];for(let o of e.slice(0,8)){let a=n.prepare(`SELECT s.id, p.name AS project, s.auto_title
1513
+ AND unresolved_at IS NULL`).all(...o);for(let d of u)s.set(d.message_hash,{fix_summary:d.fix_summary})}}catch{}let r=[];for(let[o,a]of n){let c=a.first.message_hash??null,u=c?s.get(c)??null:null;r.push({cluster_id:c??o,error_type:a.first.error_type??null,snippet:(a.first.snippet??"").slice(0,200),file:a.first.file??null,occurrence_count:a.sessions.size,resolved:u!==null,fix_summary:u?.fix_summary??null})}return r.sort((o,a)=>a.occurrence_count-o.occurrence_count),r}function XT(e){let t=e.replace(/\s+/g," ").trim();return t.length===0?"":t.slice(0,Math.min(30,t.length))}function JT(e,t){let n=f(),s=XT(t),r=[];for(let o of e.slice(0,8)){let a=n.prepare(`SELECT s.id, p.name AS project, s.auto_title
1497
1514
  FROM sessions s
1498
1515
  JOIN projects p ON p.id = s.project_id
1499
1516
  WHERE s.id = ?`).get(o);if(!a)continue;let c=[];if(s.length>0){let u=n.prepare(`SELECT rowid FROM messages
@@ -1501,13 +1518,13 @@ ${n}`}function OS(e){return Le(e)?.auto_title_source??null}async function LS(e){
1501
1518
  AND is_sidechain = 0
1502
1519
  AND content_text LIKE ?
1503
1520
  ORDER BY rowid
1504
- LIMIT 5`).all(o,`%${s}%`),d=new Set,m=0;for(let h of u){let S=n.prepare(`SELECT rowid, role, content_text FROM messages
1521
+ LIMIT 5`).all(o,`%${s}%`),d=new Set,m=0;for(let h of u){let b=n.prepare(`SELECT rowid, role, content_text FROM messages
1505
1522
  WHERE session_id = ?
1506
1523
  AND is_sidechain = 0
1507
1524
  AND rowid BETWEEN ? AND ?
1508
- ORDER BY rowid`).all(o,h.rowid-2,h.rowid+2);for(let b of S){if(d.has(b.rowid))continue;d.add(b.rowid);let T=(b.content_text??"").slice(0,800);if(m+T.length>4e3)break;m+=T.length,c.push({role:b.role??"unknown",content:T})}if(m>=4e3)break}}r.push({session_id:o,short_id:o.slice(0,8),project:a.project,auto_title:a.auto_title,excerpts:c})}return r}var CT="You are analyzing extracted bug findings from a developer's past Claude Code sessions. You are NOT being asked to fix code. You are being asked to synthesize patterns, identify likely root causes, or prioritize concerns based ONLY on the structured findings you are given. Output Markdown only, no preamble, no apologies, no questions.";function vT(e,t){let n=[];n.push("[CONTEXT]"),n.push("Bug fingerprint:"),n.push(`- error_type: ${e.error_type??"unknown"}`),n.push(`- description: ${e.snippet||"(no snippet)"}`),n.push(`- file: ${e.file??"(no file recorded)"}`),n.push(`- occurrences: ${e.occurrence_count} sessions`),n.push(`- projects: ${e.projects.join(", ")}`),n.push(`- finding_id: ${e.message_hash??"(no hash)"}`),n.push(""),n.push("Member session excerpts:");for(let s of t){let r=s.auto_title??"(untitled)";if(n.push(`=== Session ${s.short_id} | ${s.project} | "${r}" ===`),s.excerpts.length===0)n.push("(no surrounding messages found for this snippet)");else for(let o of s.excerpts)n.push(`${o.role}: ${o.content}`);n.push("")}return n.join(`
1509
- `)}function IT(e,t,n){let s=[];s.push("[CONTEXT]"),s.push(`Project: ${e}`),s.push(`Total clusters: ${n}`),s.push(""),s.push("Clusters (sorted by occurrence_count desc):");for(let r of t)s.push(`- cluster_id: ${r.cluster_id}`),s.push(` error_type: ${r.error_type??"unknown"}`),s.push(` snippet: ${r.snippet||"(none)"}`),r.file&&s.push(` file: ${r.file}`),s.push(` occurrence_count: ${r.occurrence_count}`),s.push(` resolved: ${r.resolved?"true":"false"}`),r.fix_summary&&s.push(` fix_summary: ${r.fix_summary}`),s.push("");return t.length<n&&s.push(`(Showing top ${t.length} of ${n} clusters by occurrence.)`),s.join(`
1510
- `)}var jT=`[TASK]
1525
+ ORDER BY rowid`).all(o,h.rowid-2,h.rowid+2);for(let S of b){if(d.has(S.rowid))continue;d.add(S.rowid);let T=(S.content_text??"").slice(0,800);if(m+T.length>4e3)break;m+=T.length,c.push({role:S.role??"unknown",content:T})}if(m>=4e3)break}}r.push({session_id:o,short_id:o.slice(0,8),project:a.project,auto_title:a.auto_title,excerpts:c})}return r}var GT="You are analyzing extracted bug findings from a developer's past Claude Code sessions. You are NOT being asked to fix code. You are being asked to synthesize patterns, identify likely root causes, or prioritize concerns based ONLY on the structured findings you are given. Output Markdown only, no preamble, no apologies, no questions.";function YT(e,t){let n=[];n.push("[CONTEXT]"),n.push("Bug fingerprint:"),n.push(`- error_type: ${e.error_type??"unknown"}`),n.push(`- description: ${e.snippet||"(no snippet)"}`),n.push(`- file: ${e.file??"(no file recorded)"}`),n.push(`- occurrences: ${e.occurrence_count} sessions`),n.push(`- projects: ${e.projects.join(", ")}`),n.push(`- finding_id: ${e.message_hash??"(no hash)"}`),n.push(""),n.push("Member session excerpts:");for(let s of t){let r=s.auto_title??"(untitled)";if(n.push(`=== Session ${s.short_id} | ${s.project} | "${r}" ===`),s.excerpts.length===0)n.push("(no surrounding messages found for this snippet)");else for(let o of s.excerpts)n.push(`${o.role}: ${o.content}`);n.push("")}return n.join(`
1526
+ `)}function zT(e,t,n){let s=[];s.push("[CONTEXT]"),s.push(`Project: ${e}`),s.push(`Total clusters: ${n}`),s.push(""),s.push("Clusters (sorted by occurrence_count desc):");for(let r of t)s.push(`- cluster_id: ${r.cluster_id}`),s.push(` error_type: ${r.error_type??"unknown"}`),s.push(` snippet: ${r.snippet||"(none)"}`),r.file&&s.push(` file: ${r.file}`),s.push(` occurrence_count: ${r.occurrence_count}`),s.push(` resolved: ${r.resolved?"true":"false"}`),r.fix_summary&&s.push(` fix_summary: ${r.fix_summary}`),s.push("");return t.length<n&&s.push(`(Showing top ${t.length} of ${n} clusters by occurrence.)`),s.join(`
1527
+ `)}var KT=`[TASK]
1511
1528
  Output a Markdown synopsis with these sections:
1512
1529
 
1513
1530
  ## What this bug is
@@ -1529,7 +1546,7 @@ prefer "consider <pattern>" over "do <action>" unless the evidence
1529
1546
  is overwhelming.
1530
1547
 
1531
1548
  ## Confidence
1532
- One of: high / medium / low. With one sentence justifying the level.`,MT=`[TASK]
1549
+ One of: high / medium / low. With one sentence justifying the level.`,VT=`[TASK]
1533
1550
  Output a Markdown response with these sections:
1534
1551
 
1535
1552
  ## Most likely root cause
@@ -1546,7 +1563,7 @@ list is acceptable but explicitly say "(none found)".
1546
1563
  At most 2 alternatives, each with one sentence why it is less likely.
1547
1564
 
1548
1565
  ## Confidence
1549
- high / medium / low + one-sentence justification.`,DT=`[TASK]
1566
+ high / medium / low + one-sentence justification.`,ZT=`[TASK]
1550
1567
  Output a Markdown response with these sections:
1551
1568
 
1552
1569
  ## Top 5 recurring concerns
@@ -1564,20 +1581,20 @@ Clusters that look small + high-confidence-fix. Empty list is fine.
1564
1581
  Clusters that suggest deeper issues (multiple files, repeated patterns).
1565
1582
 
1566
1583
  ## Confidence
1567
- high / medium / low.`;function FT(e,t){let n;return e.scope==="cluster"?n=e.mode==="root_cause"?MT:jT:n=DT,[CT,"",t,"",n].join(`
1568
- `)}var PT=null;var fn;function $T(){return fn!==void 0||(fn=gt("claude")??"claude"),fn}function UT(e){let t="";return n=>{t+=n.toString("utf8");let s=t.indexOf(`
1584
+ high / medium / low.`;function QT(e,t){let n;return e.scope==="cluster"?n=e.mode==="root_cause"?VT:KT:n=ZT,[GT,"",t,"",n].join(`
1585
+ `)}var ey=null;var fn;function ty(){return fn!==void 0||(fn=gt("claude")??"claude"),fn}function ny(e){let t="";return n=>{t+=n.toString("utf8");let s=t.indexOf(`
1569
1586
  `);for(;s!==-1;){let r=t.slice(0,s);t=t.slice(s+1),r.length>0&&e(r),s=t.indexOf(`
1570
- `)}}}function BT(e){return new Promise(t=>{let n=["-p",e.prompt,"--output-format","stream-json","--verbose","--allowedTools","","--permission-mode","bypassPermissions","--model",e.model],s="",r=0,o=0,a=null,c=$T(),u=RT(c,n,{stdio:["ignore","pipe","pipe"],shell:Pn(c)||process.platform==="win32"&&fn==="claude"}),d=()=>{try{u.kill("SIGTERM")}catch{}};e.signal.addEventListener("abort",d,{once:!0});let h=UT(b=>{let T=b.trim();if(!T.startsWith("{"))return;let R;try{R=JSON.parse(T)}catch{return}if(!R||typeof R!="object")return;let w=R;if(w.type==="assistant"&&w.message?.content){for(let M of w.message.content)M?.type==="text"&&typeof M.text=="string"&&(s+=M.text,e.onPartial(M.text,s));let j=w.message?.usage;j&&(typeof j.input_tokens=="number"&&(r=Math.max(r,j.input_tokens)),typeof j.output_tokens=="number"&&(o=Math.max(o,j.output_tokens)))}});u.stdout.on("data",b=>h(b)),u.stderr.on("data",b=>{let T=b.toString("utf8");T.trim()&&(a=(a??"")+T)});let S=setTimeout(()=>{try{u.kill("SIGKILL")}catch{}},1800*1e3);u.on("close",b=>{clearTimeout(S),e.signal.removeEventListener("abort",d);let T=b===0?null:a&&a.trim()||(e.signal.aborted?null:`claude CLI exited with code ${b}`);t({output_markdown:s,input_tokens:r,output_tokens:o,error:T})}),u.on("error",b=>{clearTimeout(S),e.signal.removeEventListener("abort",d),t({output_markdown:s,input_tokens:r,output_tokens:o,error:b instanceof Error?b.message:String(b)})})})}function Ps(e){if(e.scope==="cluster"){let r=xT(e.target_id);return r?{cluster:r,context_summary:{cluster_count:1,session_count:r.member_session_ids.length,findings_count:r.occurrence_count}}:null}let t=NT(e.target_id);if(t.length===0)return null;let n=t.slice(0,30),s=t.reduce((r,o)=>r+o.occurrence_count,0);return{project_clusters:n,total_project_clusters:t.length,context_summary:{cluster_count:t.length,session_count:0,findings_count:s}}}function Td(e){let t=Ps(e.intent);if(!t)return{error:e.intent.scope==="cluster"?`cluster "${e.intent.target_id}" not found in any extracted findings`:`project "${e.intent.target_id}" has no extracted findings to synthesize`};let n=Ed(e.intent),s=hn.get(n);if(s){let u=Ct.get(s);if(u&&u.status==="running")return{jobId:s,reused:!0};hn.delete(n)}let r=wT(),o=new AbortController,a=new Date().toISOString(),c={jobId:r,intent:e.intent,status:"running",startedAt:a,endedAt:null,events:[],waiters:new Set,controller:o,output_markdown:"",input_tokens:0,output_tokens:0,error:null,context_summary:t.context_summary,cleanupTimer:null};return Ct.set(r,c),hn.set(n,r),re({kind:"synth-launched",job_id:r,project:e.intent.scope==="project"?e.intent.target_id:null,model:e.intent.model,limit:null,origin:e.origin??null,reason:`${e.intent.scope}/${e.intent.mode}/${e.intent.target_id}`}),(async()=>{await Promise.resolve();try{let u;if(e.intent.scope==="cluster"&&t.cluster){let S=LT(t.cluster.member_session_ids,t.cluster.snippet);u=vT(t.cluster,S)}else if(e.intent.scope==="project"&&t.project_clusters)u=IT(e.intent.target_id,t.project_clusters,t.total_project_clusters??t.project_clusters.length);else throw new Error("inconsistent prepared context");let d=FT(e.intent,u),h=await(PT??BT)({prompt:d,model:e.intent.model,signal:o.signal,onPartial:(S,b)=>{c.output_markdown=b,_n(c,"partial",Lt(c))}});if(c.output_markdown=h.output_markdown,c.input_tokens=h.input_tokens,c.output_tokens=h.output_tokens,o.signal.aborted)c.status="cancelled",c.endedAt=new Date().toISOString(),_n(c,"done",Lt(c)),re({kind:"synth-cancelled",job_id:r,project:e.intent.scope==="project"?e.intent.target_id:null,model:e.intent.model,limit:null,origin:e.origin??null,input_tokens:c.input_tokens,output_tokens:c.output_tokens});else if(h.error)c.status="failed",c.endedAt=new Date().toISOString(),c.error=h.error,_n(c,"done",Lt(c)),re({kind:"synth-failed",job_id:r,project:e.intent.scope==="project"?e.intent.target_id:null,model:e.intent.model,limit:null,origin:e.origin??null,reason:h.error,input_tokens:c.input_tokens,output_tokens:c.output_tokens});else{c.status="done",c.endedAt=new Date().toISOString(),_n(c,"done",Lt(c)),re({kind:"synth-completed",job_id:r,project:e.intent.scope==="project"?e.intent.target_id:null,model:e.intent.model,limit:null,origin:e.origin??null,input_tokens:c.input_tokens,output_tokens:c.output_tokens});try{ed({scope:e.intent.scope,target_id:e.intent.target_id,mode:e.intent.mode,model:e.intent.model,output_markdown:c.output_markdown,input_tokens:c.input_tokens,output_tokens:c.output_tokens,job_id:r})}catch(S){console.error("[synthesize-jobs] failed to persist synthesis result:",S)}}}catch(u){let d=u instanceof Error?u.message:String(u??"unknown error");c.status="failed",c.endedAt=new Date().toISOString(),c.error=d,_n(c,"done",Lt(c)),re({kind:"synth-failed",job_id:r,project:e.intent.scope==="project"?e.intent.target_id:null,model:e.intent.model,limit:null,origin:e.origin??null,reason:d,input_tokens:c.input_tokens,output_tokens:c.output_tokens})}finally{AT(c)}})(),{jobId:r,reused:!1}}async function*yd(e,t=0){let n=Ct.get(e);if(!n)return;let s=t;for(;;){for(;s<n.events.length;){let r=n.events[s];if(!r)break;if(s+=1,yield r,r.kind==="done")return}if(n.status!=="running")return;await new Promise(r=>n.waiters.add(r))}}function wd(e){let t=Ct.get(e);return!t||t.status!=="running"?!1:(t.controller.abort(),!0)}function Vo(e){let t=Ct.get(e);return t?Lt(t):null}import{randomUUID as ey}from"node:crypto";U();zn();import{randomUUID as KT}from"node:crypto";U();var Rd=10,kd=20;function HT(e){if(!e)return!1;let t=e.split(`
1571
- `);if(t.length<4)return!1;let n=0,s=0;for(let r of t)/^\s*\d{1,5}\t/.test(r)?n++:/^\s*\/[A-Za-z0-9_./-]+/.test(r.trim())&&s++;return n/t.length>.7||s/t.length>.5}function WT(e){let t=e.byteLength/4;if(!Number.isInteger(t)||t<=0)return null;let n=new Float32Array(t),s=new Float32Array(e.buffer,e.byteOffset,t);return n.set(s),n}function Ad(e){let t=0;for(let s=0;s<e.length;s++)t+=e[s]*e[s];if(t<=0)return!1;let n=1/Math.sqrt(t);for(let s=0;s<e.length;s++)e[s]*=n;return!0}function Zo(e){if(e.length===0)return null;let t=e[0].length,n=new Float32Array(t);for(let s of e)if(s.length===t)for(let r=0;r<t;r++)n[r]+=s[r];for(let s=0;s<t;s++)n[s]/=e.length;return Ad(n)?n:null}function xd(e){let t=new Map;if(e.length===0)return t;let n=f(),s=e.map(()=>"?").join(","),r=[];try{r=n.prepare(`SELECT cm.rowid AS rowid, cm.session_id AS session_id,
1587
+ `)}}}function sy(e){return new Promise(t=>{let n=["-p",e.prompt,"--output-format","stream-json","--verbose","--allowedTools","","--permission-mode","bypassPermissions","--model",e.model],s="",r=0,o=0,a=null,c=ty(),u=UT(c,n,{stdio:["ignore","pipe","pipe"],shell:$n(c)||process.platform==="win32"&&fn==="claude"}),d=()=>{try{u.kill("SIGTERM")}catch{}};e.signal.addEventListener("abort",d,{once:!0});let h=ny(S=>{let T=S.trim();if(!T.startsWith("{"))return;let R;try{R=JSON.parse(T)}catch{return}if(!R||typeof R!="object")return;let O=R;if(O.type==="assistant"&&O.message?.content){for(let x of O.message.content)x?.type==="text"&&typeof x.text=="string"&&(s+=x.text,e.onPartial(x.text,s));let L=O.message?.usage;L&&(typeof L.input_tokens=="number"&&(r=Math.max(r,L.input_tokens)),typeof L.output_tokens=="number"&&(o=Math.max(o,L.output_tokens)))}});u.stdout.on("data",S=>h(S)),u.stderr.on("data",S=>{let T=S.toString("utf8");T.trim()&&(a=(a??"")+T)});let b=setTimeout(()=>{try{u.kill("SIGKILL")}catch{}},1800*1e3);u.on("close",S=>{clearTimeout(b),e.signal.removeEventListener("abort",d);let T=S===0?null:a&&a.trim()||(e.signal.aborted?null:`claude CLI exited with code ${S}`);t({output_markdown:s,input_tokens:r,output_tokens:o,error:T})}),u.on("error",S=>{clearTimeout(b),e.signal.removeEventListener("abort",d),t({output_markdown:s,input_tokens:r,output_tokens:o,error:S instanceof Error?S.message:String(S)})})})}function $s(e){if(e.scope==="cluster"){let r=WT(e.target_id);return r?{cluster:r,context_summary:{cluster_count:1,session_count:r.member_session_ids.length,findings_count:r.occurrence_count}}:null}let t=qT(e.target_id);if(t.length===0)return null;let n=t.slice(0,30),s=t.reduce((r,o)=>r+o.occurrence_count,0);return{project_clusters:n,total_project_clusters:t.length,context_summary:{cluster_count:t.length,session_count:0,findings_count:s}}}function Nd(e){let t=$s(e.intent);if(!t)return{error:e.intent.scope==="cluster"?`cluster "${e.intent.target_id}" not found in any extracted findings`:`project "${e.intent.target_id}" has no extracted findings to synthesize`};let n=kd(e.intent),s=hn.get(n);if(s){let u=Ct.get(s);if(u&&u.status==="running")return{jobId:s,reused:!0};hn.delete(n)}let r=$T(),o=new AbortController,a=new Date().toISOString(),c={jobId:r,intent:e.intent,status:"running",startedAt:a,endedAt:null,events:[],waiters:new Set,controller:o,output_markdown:"",input_tokens:0,output_tokens:0,error:null,context_summary:t.context_summary,cleanupTimer:null};return Ct.set(r,c),hn.set(n,r),re({kind:"synth-launched",job_id:r,project:e.intent.scope==="project"?e.intent.target_id:null,model:e.intent.model,limit:null,origin:e.origin??null,reason:`${e.intent.scope}/${e.intent.mode}/${e.intent.target_id}`}),(async()=>{await Promise.resolve();try{let u;if(e.intent.scope==="cluster"&&t.cluster){let b=JT(t.cluster.member_session_ids,t.cluster.snippet);u=YT(t.cluster,b)}else if(e.intent.scope==="project"&&t.project_clusters)u=zT(e.intent.target_id,t.project_clusters,t.total_project_clusters??t.project_clusters.length);else throw new Error("inconsistent prepared context");let d=QT(e.intent,u),h=await(ey??sy)({prompt:d,model:e.intent.model,signal:o.signal,onPartial:(b,S)=>{c.output_markdown=S,_n(c,"partial",Lt(c))}});if(c.output_markdown=h.output_markdown,c.input_tokens=h.input_tokens,c.output_tokens=h.output_tokens,o.signal.aborted)c.status="cancelled",c.endedAt=new Date().toISOString(),_n(c,"done",Lt(c)),re({kind:"synth-cancelled",job_id:r,project:e.intent.scope==="project"?e.intent.target_id:null,model:e.intent.model,limit:null,origin:e.origin??null,input_tokens:c.input_tokens,output_tokens:c.output_tokens});else if(h.error)c.status="failed",c.endedAt=new Date().toISOString(),c.error=h.error,_n(c,"done",Lt(c)),re({kind:"synth-failed",job_id:r,project:e.intent.scope==="project"?e.intent.target_id:null,model:e.intent.model,limit:null,origin:e.origin??null,reason:h.error,input_tokens:c.input_tokens,output_tokens:c.output_tokens});else{c.status="done",c.endedAt=new Date().toISOString(),_n(c,"done",Lt(c)),re({kind:"synth-completed",job_id:r,project:e.intent.scope==="project"?e.intent.target_id:null,model:e.intent.model,limit:null,origin:e.origin??null,input_tokens:c.input_tokens,output_tokens:c.output_tokens});try{ad({scope:e.intent.scope,target_id:e.intent.target_id,mode:e.intent.mode,model:e.intent.model,output_markdown:c.output_markdown,input_tokens:c.input_tokens,output_tokens:c.output_tokens,job_id:r})}catch(b){console.error("[synthesize-jobs] failed to persist synthesis result:",b)}}}catch(u){let d=u instanceof Error?u.message:String(u??"unknown error");c.status="failed",c.endedAt=new Date().toISOString(),c.error=d,_n(c,"done",Lt(c)),re({kind:"synth-failed",job_id:r,project:e.intent.scope==="project"?e.intent.target_id:null,model:e.intent.model,limit:null,origin:e.origin??null,reason:d,input_tokens:c.input_tokens,output_tokens:c.output_tokens})}finally{HT(c)}})(),{jobId:r,reused:!1}}async function*Od(e,t=0){let n=Ct.get(e);if(!n)return;let s=t;for(;;){for(;s<n.events.length;){let r=n.events[s];if(!r)break;if(s+=1,yield r,r.kind==="done")return}if(n.status!=="running")return;await new Promise(r=>n.waiters.add(r))}}function Ld(e){let t=Ct.get(e);return!t||t.status!=="running"?!1:(t.controller.abort(),!0)}function ei(e){let t=Ct.get(e);return t?Lt(t):null}import{randomUUID as fy}from"node:crypto";B();Kn();import{randomUUID as py}from"node:crypto";B();var Cd=10,vd=20;function ry(e){if(!e)return!1;let t=e.split(`
1588
+ `);if(t.length<4)return!1;let n=0,s=0;for(let r of t)/^\s*\d{1,5}\t/.test(r)?n++:/^\s*\/[A-Za-z0-9_./-]+/.test(r.trim())&&s++;return n/t.length>.7||s/t.length>.5}function oy(e){let t=e.byteLength/4;if(!Number.isInteger(t)||t<=0)return null;let n=new Float32Array(t),s=new Float32Array(e.buffer,e.byteOffset,t);return n.set(s),n}function Id(e){let t=0;for(let s=0;s<e.length;s++)t+=e[s]*e[s];if(t<=0)return!1;let n=1/Math.sqrt(t);for(let s=0;s<e.length;s++)e[s]*=n;return!0}function ti(e){if(e.length===0)return null;let t=e[0].length,n=new Float32Array(t);for(let s of e)if(s.length===t)for(let r=0;r<t;r++)n[r]+=s[r];for(let s=0;s<t;s++)n[s]/=e.length;return Id(n)?n:null}function jd(e){let t=new Map;if(e.length===0)return t;let n=f(),s=e.map(()=>"?").join(","),r=[];try{r=n.prepare(`SELECT cm.rowid AS rowid, cm.session_id AS session_id,
1572
1589
  cm.text AS text, v.embedding AS embedding
1573
1590
  FROM chunk_meta cm
1574
1591
  JOIN vec_chunks v ON v.rowid = cm.rowid
1575
1592
  WHERE cm.stale = 0
1576
1593
  AND cm.session_id IN (${s})
1577
- ORDER BY cm.session_id, cm.rowid ASC`).all(...e)}catch{return t}if(r.length===0)return t;let o=new Map;for(let a of r){let c=o.get(a.session_id);c||(c=[],o.set(a.session_id,c)),c.push(a)}for(let[a,c]of o){let u=c.filter(x=>!HT(x.text)),d=u.length>0?u:c,m=[];for(let x of d){let P=WT(x.embedding);P&&Ad(P)&&m.push(P)}if(m.length===0)continue;let h=Math.min(Rd,m.length),S=Math.max(0,m.length-Rd),b=m.slice(0,h),T=m.slice(S),R=Zo(b),w=Zo(T),j=Zo(m),M=new Map;for(let x=0;x<b.length&&M.size<kd;x++)M.set(x,b[x]);for(let x=0;x<T.length&&M.size<kd;x++)M.set(S+x,T[x]);let W=Array.from(M.values());t.set(a,{session_id:a,full_mean:j,head_pool:R,tail_pool:w,sample_chunks:W})}return t}function qT(e,t){if(e.length!==t.length)return 0;let n=0;for(let s=0;s<e.length;s++)n+=e[s]*t[s];return n<-1?-1:n>1?1:n}function Nd(e,t=.8){let n=new Map,s=[],r=[];for(let[d,m]of e)m.full_mean&&(s.push(d),r.push(m.full_mean));if(s.length===0)return n;let o=new Int32Array(s.length);for(let d=0;d<o.length;d++)o[d]=d;let a=d=>{let m=d;for(;o[m]!==m;)m=o[m];let h=d;for(;o[h]!==m;){let S=o[h];o[h]=m,h=S}return m},c=(d,m)=>{let h=a(d),S=a(m);h!==S&&(o[h]=S)};for(let d=0;d<s.length;d++)for(let m=d+1;m<s.length;m++)qT(r[d],r[m])>=t&&c(d,m);let u=new Map;for(let d=0;d<s.length;d++){let m=a(d),h=u.get(m);h===void 0&&(h=u.size,u.set(m,h)),n.set(s[d],h)}return n}var Pe={lo:.4,hi:.7},vt="claude-haiku-4-5-20251001",It=50,Od=1500,Ld=50,XT={same_workflow:.15,unrelated:-.2,unsure:0};function Cd(e,t,n=Pe){if(n.lo>n.hi)throw new Error(`borderline band invalid: lo=${n.lo} > hi=${n.hi}`);let s=[];for(let r of e){if(r.confidence<n.lo||r.confidence>n.hi)continue;let o=t.get(r.parent_id),a=t.get(r.child_id);!o||!a||s.push({parent:o,child:a,step1:r})}return s.sort((r,o)=>r.child.started_at_ms-o.child.started_at_ms),s}function vd(e,t=Pe){let n=0;for(let s of e)s.confidence>=t.lo&&s.confidence<=t.hi&&n++;return n}function JT(e,t){let n=e.replace(/\s+/g," ").trim();return n.length>t?n.slice(0,t-1)+"\u2026":n}function YT(e,t){if(e===null)return"unknown";let n=t-e;if(n<0)return"overlap";let s=Math.round(n/6e4);if(s<60)return`${s}m`;let r=Math.round(n/36e5);return r<24?`${r}h`:`${Math.round(n/864e5)}d`}function GT(e){let n=e.parent.recent_user_messages,s=e.child.recent_user_messages,r=n.slice(0,3),o=n.length>3?n.slice(-3):[],a=s.slice(0,3),c=d=>d.length===0?" (none captured)":d.map(m=>` - ${JT(m,500)}`).join(`
1578
- `),u=YT(e.parent.ended_at_ms??e.parent.started_at_ms,e.child.started_at_ms);return["You are evaluating whether two Claude Code sessions belong to the same continuous workflow.","","A deterministic scorer rated this pair in the borderline band. Its signals:",e.step1.reasons.length===0?" (no signals fired strongly)":e.step1.reasons.map(d=>` - ${d}`).join(`
1594
+ ORDER BY cm.session_id, cm.rowid ASC`).all(...e)}catch{return t}if(r.length===0)return t;let o=new Map;for(let a of r){let c=o.get(a.session_id);c||(c=[],o.set(a.session_id,c)),c.push(a)}for(let[a,c]of o){let u=c.filter(A=>!ry(A.text)),d=u.length>0?u:c,m=[];for(let A of d){let $=oy(A.embedding);$&&Id($)&&m.push($)}if(m.length===0)continue;let h=Math.min(Cd,m.length),b=Math.max(0,m.length-Cd),S=m.slice(0,h),T=m.slice(b),R=ti(S),O=ti(T),L=ti(m),x=new Map;for(let A=0;A<S.length&&x.size<vd;A++)x.set(A,S[A]);for(let A=0;A<T.length&&x.size<vd;A++)x.set(b+A,T[A]);let F=Array.from(x.values());t.set(a,{session_id:a,full_mean:L,head_pool:R,tail_pool:O,sample_chunks:F})}return t}function iy(e,t){if(e.length!==t.length)return 0;let n=0;for(let s=0;s<e.length;s++)n+=e[s]*t[s];return n<-1?-1:n>1?1:n}function Md(e,t=.8){let n=new Map,s=[],r=[];for(let[d,m]of e)m.full_mean&&(s.push(d),r.push(m.full_mean));if(s.length===0)return n;let o=new Int32Array(s.length);for(let d=0;d<o.length;d++)o[d]=d;let a=d=>{let m=d;for(;o[m]!==m;)m=o[m];let h=d;for(;o[h]!==m;){let b=o[h];o[h]=m,h=b}return m},c=(d,m)=>{let h=a(d),b=a(m);h!==b&&(o[h]=b)};for(let d=0;d<s.length;d++)for(let m=d+1;m<s.length;m++)iy(r[d],r[m])>=t&&c(d,m);let u=new Map;for(let d=0;d<s.length;d++){let m=a(d),h=u.get(m);h===void 0&&(h=u.size,u.set(m,h)),n.set(s[d],h)}return n}var Pe={lo:.4,hi:.7},vt="claude-haiku-4-5-20251001",It=50,Dd=1500,Fd=50,ay={same_workflow:.15,unrelated:-.2,unsure:0};function Pd(e,t,n=Pe){if(n.lo>n.hi)throw new Error(`borderline band invalid: lo=${n.lo} > hi=${n.hi}`);let s=[];for(let r of e){if(r.confidence<n.lo||r.confidence>n.hi)continue;let o=t.get(r.parent_id),a=t.get(r.child_id);!o||!a||s.push({parent:o,child:a,step1:r})}return s.sort((r,o)=>r.child.started_at_ms-o.child.started_at_ms),s}function $d(e,t=Pe){let n=0;for(let s of e)s.confidence>=t.lo&&s.confidence<=t.hi&&n++;return n}function cy(e,t){let n=e.replace(/\s+/g," ").trim();return n.length>t?n.slice(0,t-1)+"\u2026":n}function ly(e,t){if(e===null)return"unknown";let n=t-e;if(n<0)return"overlap";let s=Math.round(n/6e4);if(s<60)return`${s}m`;let r=Math.round(n/36e5);return r<24?`${r}h`:`${Math.round(n/864e5)}d`}function uy(e){let n=e.parent.recent_user_messages,s=e.child.recent_user_messages,r=n.slice(0,3),o=n.length>3?n.slice(-3):[],a=s.slice(0,3),c=d=>d.length===0?" (none captured)":d.map(m=>` - ${cy(m,500)}`).join(`
1595
+ `),u=ly(e.parent.ended_at_ms??e.parent.started_at_ms,e.child.started_at_ms);return["You are evaluating whether two Claude Code sessions belong to the same continuous workflow.","","A deterministic scorer rated this pair in the borderline band. Its signals:",e.step1.reasons.length===0?" (no signals fired strongly)":e.step1.reasons.map(d=>` - ${d}`).join(`
1579
1596
  `),` step1_confidence: ${e.step1.confidence.toFixed(2)}`,"","PARENT SESSION","First user messages:",c(r),"Last user messages:",c(o),"",`CHILD SESSION (gap from parent: ${u})`,"First user messages:",c(a),"","Reply with EXACTLY one JSON object on a single line, no prose, no markdown:",'{"verdict":"same_workflow"|"unrelated"|"unsure","reason":"<one short sentence>"}',"","Guidance:",'- "same_workflow" = the child is clearly continuing what the parent was doing.','- "unrelated" = different problem, different files, different intent.','- "unsure" = could go either way; do not force a verdict.'].join(`
1580
- `)}function zT(e){if(!e)return null;let t=e.trim();if(!t)return null;let n=t;try{let u=JSON.parse(t);typeof u.result=="string"&&(n=u.result.trim())}catch{}let s=n.match(/\{[\s\S]*\}/);if(!s)return null;let r;try{r=JSON.parse(s[0])}catch{return null}if(!r||typeof r!="object")return null;let o=r,a=typeof o.verdict=="string"?o.verdict.toLowerCase():"";if(a!=="same_workflow"&&a!=="unrelated"&&a!=="unsure")return null;let c=typeof o.reason=="string"&&o.reason.trim()?o.reason.trim():"";return{verdict:a,reason:c,delta:XT[a]}}async function Id(e,t={}){if(t.signal?.aborted)return null;let n=t.model??vt,s=GT(e),r=t.spawn;if(!r)try{let a=await Promise.resolve().then(()=>(ye(),tt));if(!a.isClaudeCliAvailable())return null;r=(c,u)=>a.spawnClaudePrompt(c,[],u)}catch{return null}let o;try{o=await Promise.race([r(s,{model:n}),new Promise(a=>{t.signal&&t.signal.addEventListener("abort",()=>a({success:!1,stdout:""}),{once:!0})})])}catch{return null}return!o.success||!o.stdout?null:zT(o.stdout)}function jd(e){let t=[];for(let n of e.proposals){let s=`${n.parent_id}::${n.child_id}`,r=e.rescored.get(s);if(!r){t.push(n);continue}let o=Math.max(0,Math.min(1,n.confidence+r.delta));if(o<e.applyThreshold)continue;let a=`LLM: ${r.verdict}${r.reason?` \u2014 ${r.reason}`:""} (${r.delta>=0?"+":""}${r.delta.toFixed(2)})`;t.push({...n,confidence:o,reasons:[...n.reasons,a]})}return t}function Md(e){return`${e.parent_id}::${e.child_id}`}async function VT(e){if(e.signal?.aborted)return null;let t,n;try{({spawnClaudePrompt:t,isClaudeCliAvailable:n}=await Promise.resolve().then(()=>(ye(),tt)))}catch{return null}if(!n())return null;let s=[];for(let o of e.sessionIds){let a=e.rowById.get(o);if(!a)continue;let c=a.alias||a.auto_title||(a.first_user_message?a.first_user_message.slice(0,120).replace(/\n/g," "):"(no title)");s.push(`- ${c}`)}let r=`Below is a chronological list of related Claude Code sessions that form one continuous workflow. Generate a single short descriptive name for the workflow as a whole. Requirements:
1597
+ `)}function dy(e){if(!e)return null;let t=e.trim();if(!t)return null;let n=t;try{let u=JSON.parse(t);typeof u.result=="string"&&(n=u.result.trim())}catch{}let s=n.match(/\{[\s\S]*\}/);if(!s)return null;let r;try{r=JSON.parse(s[0])}catch{return null}if(!r||typeof r!="object")return null;let o=r,a=typeof o.verdict=="string"?o.verdict.toLowerCase():"";if(a!=="same_workflow"&&a!=="unrelated"&&a!=="unsure")return null;let c=typeof o.reason=="string"&&o.reason.trim()?o.reason.trim():"";return{verdict:a,reason:c,delta:ay[a]}}async function Ud(e,t={}){if(t.signal?.aborted)return null;let n=t.model??vt,s=uy(e),r=t.spawn;if(!r)try{let a=await Promise.resolve().then(()=>(ye(),et));if(!a.isClaudeCliAvailable())return null;r=(c,u)=>a.spawnClaudePrompt(c,[],u)}catch{return null}let o;try{o=await Promise.race([r(s,{model:n}),new Promise(a=>{t.signal&&t.signal.addEventListener("abort",()=>a({success:!1,stdout:""}),{once:!0})})])}catch{return null}return!o.success||!o.stdout?null:dy(o.stdout)}function Bd(e){let t=[];for(let n of e.proposals){let s=`${n.parent_id}::${n.child_id}`,r=e.rescored.get(s);if(!r){t.push(n);continue}let o=Math.max(0,Math.min(1,n.confidence+r.delta));if(o<e.applyThreshold)continue;let a=`LLM: ${r.verdict}${r.reason?` \u2014 ${r.reason}`:""} (${r.delta>=0?"+":""}${r.delta.toFixed(2)})`;t.push({...n,confidence:o,reasons:[...n.reasons,a]})}return t}function Hd(e){return`${e.parent_id}::${e.child_id}`}async function my(e){if(e.signal?.aborted)return null;let t,n;try{({spawnClaudePrompt:t,isClaudeCliAvailable:n}=await Promise.resolve().then(()=>(ye(),et)))}catch{return null}if(!n())return null;let s=[];for(let o of e.sessionIds){let a=e.rowById.get(o);if(!a)continue;let c=a.alias||a.auto_title||(a.first_user_message?a.first_user_message.slice(0,120).replace(/\n/g," "):"(no title)");s.push(`- ${c}`)}let r=`Below is a chronological list of related Claude Code sessions that form one continuous workflow. Generate a single short descriptive name for the workflow as a whole. Requirements:
1581
1598
  - 4 to 8 words
1582
1599
  - Title-case, no trailing punctuation
1583
1600
  - Capture the WORKFLOW (e.g., "Update Remotion deps + lint cleanup"), not any one session
@@ -1588,12 +1605,12 @@ Sessions:
1588
1605
  `+s.join(`
1589
1606
  `)+`
1590
1607
 
1591
- Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model:e.model}:{}),a=null,c=new Promise(h=>{e.signal&&(a=()=>h(null),e.signal.addEventListener("abort",a,{once:!0}))}),u=await Promise.race([o,c]);if(a&&e.signal&&e.signal.removeEventListener("abort",a),!u||!u.success)return null;let d=u.stdout.trim();if(!d)return null;let m;try{let h=JSON.parse(d);m=typeof h.result=="string"?h.result:d}catch{m=d}return m=m.trim().replace(/^["'`]+|["'`]+$/g,"").replace(/[.!?]+$/g,"").trim(),m?m.length>80?m.slice(0,77)+"...":m:null}catch{return null}}function Qo(e){return ZT(e)}function ei(e){let t=new Map;for(let o of e){let a=t.get(o.project);a||(a=[],t.set(o.project,a)),a.push(o)}let n=e.map(o=>o.id),s=new Map;try{s=xd(n)}catch{s=new Map}let r=new Map;for(let[o,a]of t){let c=new Map;for(let m of a){let h=s.get(m.id);h&&c.set(m.id,h)}let u=Nd(c,.8),d=[];for(let m of a){let h=QT(m,s,u);h&&d.push(h)}r.set(o,d)}return{byProject:t,scannablesByProject:r}}function Fd(e){return f().prepare(`SELECT COUNT(DISTINCT t.id) AS n
1608
+ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model:e.model}:{}),a=null,c=new Promise(h=>{e.signal&&(a=()=>h(null),e.signal.addEventListener("abort",a,{once:!0}))}),u=await Promise.race([o,c]);if(a&&e.signal&&e.signal.removeEventListener("abort",a),!u||!u.success)return null;let d=u.stdout.trim();if(!d)return null;let m;try{let h=JSON.parse(d);m=typeof h.result=="string"?h.result:d}catch{m=d}return m=m.trim().replace(/^["'`]+|["'`]+$/g,"").replace(/[.!?]+$/g,"").trim(),m?m.length>80?m.slice(0,77)+"...":m:null}catch{return null}}function ni(e){return gy(e)}function si(e){let t=new Map;for(let o of e){let a=t.get(o.project);a||(a=[],t.set(o.project,a)),a.push(o)}let n=e.map(o=>o.id),s=new Map;try{s=jd(n)}catch{s=new Map}let r=new Map;for(let[o,a]of t){let c=new Map;for(let m of a){let h=s.get(m.id);h&&c.set(m.id,h)}let u=Md(c,.8),d=[];for(let m of a){let h=_y(m,s,u);h&&d.push(h)}r.set(o,d)}return{byProject:t,scannablesByProject:r}}function qd(e){return f().prepare(`SELECT COUNT(DISTINCT t.id) AS n
1592
1609
  FROM threads t
1593
1610
  JOIN thread_edges te ON te.thread_id = t.id
1594
1611
  JOIN sessions s ON s.id = te.session_id
1595
1612
  JOIN projects p ON p.id = s.project_id
1596
- WHERE t.id LIKE 'auto-scan-%' AND p.name = ?`).get(e)?.n??0}function ZT(e){let t=f(),n={},s="1=1 AND s.message_count > 2";return s+=" AND COALESCE(s.auto_title, '') NOT LIKE '[meta]%' AND COALESCE(s.auto_title, '') NOT LIKE '[output-index]%' AND COALESCE(s.auto_title, '') NOT LIKE '[skill]%'",e.project&&(s+=" AND p.name = @project",n.project=e.project),t.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
1613
+ WHERE t.id LIKE 'auto-scan-%' AND p.name = ?`).get(e)?.n??0}function gy(e){let t=f(),n={},s="1=1 AND s.message_count > 2";return s+=" AND COALESCE(s.auto_title, '') NOT LIKE '[meta]%' AND COALESCE(s.auto_title, '') NOT LIKE '[output-index]%' AND COALESCE(s.auto_title, '') NOT LIKE '[skill]%'",e.project&&(s+=" AND p.name = @project",n.project=e.project),t.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
1597
1614
  s.first_user_message, s.auto_title,
1598
1615
  NULLIF(sa.alias, '') AS alias,
1599
1616
  s.file_path
@@ -1601,21 +1618,21 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1601
1618
  JOIN projects p ON p.id = s.project_id
1602
1619
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1603
1620
  WHERE ${s}
1604
- ORDER BY p.name ASC, s.started_at ASC`).all(n)}function QT(e,t,n){if(!e.started_at)return null;let s=Date.parse(e.started_at);if(!Number.isFinite(s))return null;let r=e.ended_at?Date.parse(e.ended_at):null,o=Os(e.file_path,{maxUserMessages:7}),a=t?.get(e.id);return{id:e.id,started_at_ms:s,ended_at_ms:Number.isFinite(r)?r:null,first_user_message:e.first_user_message,recent_user_messages:o.recent_user_messages,auto_title:e.auto_title,touched_files:o.touched_files,mean_embedding:a?.full_mean??null,head_pool:a?.head_pool??null,tail_pool:a?.tail_pool??null,sample_chunks:a?.sample_chunks??[],cluster_id:n?.get(e.id)??null,authored_paths:o.authored_paths,authored_content:o.authored_content}}function Dd(e){let t=e.alias||e.auto_title||(e.first_user_message?e.first_user_message.slice(0,60).replace(/\n/g," ").trim():`thread from ${e.id.slice(0,8)}`);return t.length>80?t.slice(0,77)+"...":t}async function Pd(e){if(!e.rescore.enabled)return{proposals:e.proposals,ran:!1,considered:0,promoted:0,demoted:0,unsure:0,failed:0,capped:!1};let t=e.rescore.band??Pe,n=e.rescore.cap??It,s=e.rescore.model??vt,r=new Map(e.scannables.map(S=>[S.id,S])),o=Cd(e.proposals,r,t);if(o.length===0)return{proposals:e.proposals,ran:!0,considered:0,promoted:0,demoted:0,unsure:0,failed:0,capped:!1};if(o.length>n)return{proposals:e.proposals,ran:!1,considered:o.length,promoted:0,demoted:0,unsure:0,failed:0,capped:!0};let a=new Map,c=0,u=0,d=0,m=0;for(let S=0;S<o.length&&!e.signal?.aborted;S++){let b=o[S],T=await Id(b,{model:s,signal:e.signal});T?(a.set(Md(b.step1),T),T.verdict==="same_workflow"?c++:T.verdict==="unrelated"?u++:d++):m++,e.onProgress?.({phase:"rescoring",current:S+1,total:o.length,verdict:T?.verdict??"failed"})}return{proposals:jd({proposals:e.proposals,rescored:a,applyThreshold:e.applyThreshold}),ran:!0,considered:o.length,promoted:c,demoted:u,unsure:d,failed:m,capped:!1}}async function $d(e){let t=f(),n=new Map(e.rows.map(d=>[d.id,d])),s=au(e.edges,e.scannables),r=new Date().toISOString(),o=[],a=new Map,c=0;for(let d of s){if(c++,e.signal?.aborted)break;let m=n.get(d.rootId),h=Dd(m);if(!e.llmNames){a.set(d.rootId,h),e.onProgress?.({phase:"naming",current:c,total:s.length,thread_name:h});continue}let b=await VT({rootRow:m,sessionIds:d.sessionIds,rowById:n,signal:e.signal,model:e.model})??h;a.set(d.rootId,b),e.onProgress?.({phase:"naming",current:c,total:s.length,thread_name:b})}return t.transaction(()=>{for(let d of s){if(!a.has(d.rootId))continue;let m=n.get(d.rootId),h=`auto-scan-${KT()}`,S=a.get(d.rootId)??Dd(m),b=`Auto-detected workflow chain (${d.sessionIds.length} sessions). Source: auto-scan-v1.`;t.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, ?, ?)").run(h,S,b,r),t.prepare(`INSERT INTO thread_edges
1621
+ ORDER BY p.name ASC, s.started_at ASC`).all(n)}function _y(e,t,n){if(!e.started_at)return null;let s=Date.parse(e.started_at);if(!Number.isFinite(s))return null;let r=e.ended_at?Date.parse(e.ended_at):null,o=Ls(e.file_path,{maxUserMessages:7}),a=t?.get(e.id);return{id:e.id,started_at_ms:s,ended_at_ms:Number.isFinite(r)?r:null,first_user_message:e.first_user_message,recent_user_messages:o.recent_user_messages,auto_title:e.auto_title,touched_files:o.touched_files,mean_embedding:a?.full_mean??null,head_pool:a?.head_pool??null,tail_pool:a?.tail_pool??null,sample_chunks:a?.sample_chunks??[],cluster_id:n?.get(e.id)??null,authored_paths:o.authored_paths,authored_content:o.authored_content}}function Wd(e){let t=e.alias||e.auto_title||(e.first_user_message?e.first_user_message.slice(0,60).replace(/\n/g," ").trim():`thread from ${e.id.slice(0,8)}`);return t.length>80?t.slice(0,77)+"...":t}async function Xd(e){if(!e.rescore.enabled)return{proposals:e.proposals,ran:!1,considered:0,promoted:0,demoted:0,unsure:0,failed:0,capped:!1};let t=e.rescore.band??Pe,n=e.rescore.cap??It,s=e.rescore.model??vt,r=new Map(e.scannables.map(b=>[b.id,b])),o=Pd(e.proposals,r,t);if(o.length===0)return{proposals:e.proposals,ran:!0,considered:0,promoted:0,demoted:0,unsure:0,failed:0,capped:!1};if(o.length>n)return{proposals:e.proposals,ran:!1,considered:o.length,promoted:0,demoted:0,unsure:0,failed:0,capped:!0};let a=new Map,c=0,u=0,d=0,m=0;for(let b=0;b<o.length&&!e.signal?.aborted;b++){let S=o[b],T=await Ud(S,{model:s,signal:e.signal});T?(a.set(Hd(S.step1),T),T.verdict==="same_workflow"?c++:T.verdict==="unrelated"?u++:d++):m++,e.onProgress?.({phase:"rescoring",current:b+1,total:o.length,verdict:T?.verdict??"failed"})}return{proposals:Bd({proposals:e.proposals,rescored:a,applyThreshold:e.applyThreshold}),ran:!0,considered:o.length,promoted:c,demoted:u,unsure:d,failed:m,capped:!1}}async function Jd(e){let t=f(),n=new Map(e.rows.map(d=>[d.id,d])),s=gu(e.edges,e.scannables),r=new Date().toISOString(),o=[],a=new Map,c=0;for(let d of s){if(c++,e.signal?.aborted)break;let m=n.get(d.rootId),h=Wd(m);if(!e.llmNames){a.set(d.rootId,h),e.onProgress?.({phase:"naming",current:c,total:s.length,thread_name:h});continue}let S=await my({rootRow:m,sessionIds:d.sessionIds,rowById:n,signal:e.signal,model:e.model})??h;a.set(d.rootId,S),e.onProgress?.({phase:"naming",current:c,total:s.length,thread_name:S})}return t.transaction(()=>{for(let d of s){if(!a.has(d.rootId))continue;let m=n.get(d.rootId),h=`auto-scan-${py()}`,b=a.get(d.rootId)??Wd(m),S=`Auto-detected workflow chain (${d.sessionIds.length} sessions). Source: auto-scan-v1.`;t.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, ?, ?)").run(h,b,S,r),t.prepare(`INSERT INTO thread_edges
1605
1622
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
1606
- VALUES (?, ?, NULL, 'origin', 1.0, 'auto-scan-v1', ?)`).run(h,d.rootId,r);let T=new Map;for(let R of e.edges)d.sessionIds.includes(R.child_id)&&T.set(R.child_id,R);for(let R of d.sessionIds){if(R===d.rootId)continue;let w=T.get(R);w&&t.prepare(`INSERT INTO thread_edges
1623
+ VALUES (?, ?, NULL, 'origin', 1.0, 'auto-scan-v1', ?)`).run(h,d.rootId,r);let T=new Map;for(let R of e.edges)d.sessionIds.includes(R.child_id)&&T.set(R.child_id,R);for(let R of d.sessionIds){if(R===d.rootId)continue;let O=T.get(R);O&&t.prepare(`INSERT INTO thread_edges
1607
1624
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
1608
- VALUES (?, ?, ?, 'child', ?, 'auto-scan-v1', ?)`).run(h,R,w.parent_id,w.confidence,r)}o.push({thread_id:h,name:S,session_count:d.sessionIds.length})}})(),{project:e.project,threads:o}}var Mt=new Map,En=new Map,ty=300*1e3;function jt(e,t,n){e.events.push({id:e.events.length+1,kind:t,data:n});for(let s of e.waiters)s();e.waiters.clear()}function ny(e){e.cleanupTimer||(e.cleanupTimer=setTimeout(()=>{Mt.delete(e.jobId),En.get(e.project)===e.jobId&&En.delete(e.project)},ty),e.cleanupTimer.unref?.())}function $s(e){return{jobId:e.jobId,project:e.project,threshold:e.threshold,llm_names:e.llmNames,status:e.status,startedAt:e.startedAt,endedAt:e.endedAt,total_threads:e.totalThreads,threads_named:e.threadsNamed,edges_written:e.edgesWritten,threads_created:e.threadsCreated,current_thread_name:e.currentThreadName,error:e.error,rescore:e.rescore}}var sy=500,ry=30,ti="claude-haiku-4-5-20251001",Ud={"claude-haiku-4-5-20251001":{in:1,out:5,label:"Haiku 4.5"},"claude-sonnet-4-6":{in:3,out:15,label:"Sonnet 4.6"},"claude-opus-4-7":{in:15,out:75,label:"Opus 4.7"}};function Bd(e){return Ud[e]??Ud[ti]}function Hd(e){let t=typeof e.threshold=="number"?e.threshold:xs;if(!Number.isFinite(t)||t<0||t>1)return{error:"threshold must be a number in [0, 1]"};let n=e.model??ti,s="",r=!!e.llm_rescore?.enabled,o={lo:e.llm_rescore?.band_lo??Pe.lo,hi:e.llm_rescore?.band_hi??Pe.hi};if(r&&(!Number.isFinite(o.lo)||!Number.isFinite(o.hi)||o.lo<0||o.hi>1||o.lo>o.hi))return{error:"rescore band must satisfy 0 \u2264 lo \u2264 hi \u2264 1"};let a=e.llm_rescore?.model??vt,c=Qo({project:e.project});if(c.length===0)return{eligible_sessions:0,proposed_edges:0,estimated_threads:0,estimated_llm_calls:0,estimated_input_tokens_max:0,estimated_output_tokens_max:0,estimated_cost_usd_max:0,existing_auto_scan_threads:0,plan_window_estimate:We(0,n),accuracy_caveat:s,model:n,llm_rescore:r?{enabled:!0,band:o,cap:It,estimated_borderline_pairs:0,estimated_input_tokens_max:0,estimated_output_tokens_max:0,estimated_cost_usd_max:0,plan_window_estimate:We(0,a),exceeds_cap:!1,model:a}:null};let{byProject:u,scannablesByProject:d}=ei(c),m=u.get(e.project)??[],h=d.get(e.project)??[],S=r?Math.min(t,o.lo):t,b=Rt(h,S),T=r?b.filter(i=>i.confidence>=t):b,R=Wd(T),w=R*sy,j=R*ry,M=Bd(n),W=w/1e6*M.in,x=j/1e6*M.out,P=W+x,te=We(R,n),B=Fd(e.project),se=null;if(r){let i=vd(b,o),l=Bd(a),p=i*Od,g=i*Ld,_=p/1e6*l.in+g/1e6*l.out;se={enabled:!0,band:o,cap:It,estimated_borderline_pairs:i,estimated_input_tokens_max:p,estimated_output_tokens_max:g,estimated_cost_usd_max:Math.round(_*1e4)/1e4,plan_window_estimate:We(i,a),exceeds_cap:i>It,model:a}}return{eligible_sessions:m.length,proposed_edges:T.length,estimated_threads:R,estimated_llm_calls:R,estimated_input_tokens_max:w,estimated_output_tokens_max:j,estimated_cost_usd_max:Math.round(P*1e4)/1e4,existing_auto_scan_threads:B,plan_window_estimate:te,accuracy_caveat:s,model:n,llm_rescore:se}}function Wd(e){let t=new Map,n=o=>{let a=o;for(;t.get(a)!==a;)a=t.get(a);return a},s=(o,a)=>{let c=n(o),u=n(a);c!==u&&t.set(c,u)};for(let o of e)t.has(o.parent_id)||t.set(o.parent_id,o.parent_id),t.has(o.child_id)||t.set(o.child_id,o.child_id),s(o.parent_id,o.child_id);let r=new Set;for(let o of t.keys())r.add(n(o));return r.size}function qd(e){let t=typeof e.threshold=="number"?e.threshold:xs;if(!Number.isFinite(t)||t<0||t>1)return{error:"threshold must be a number in [0, 1]"};let n=e.llm_names??!0,s=e.model??ti,r=!!e.llm_rescore?.enabled,o={lo:e.llm_rescore?.band_lo??Pe.lo,hi:e.llm_rescore?.band_hi??Pe.hi};if(r&&(!Number.isFinite(o.lo)||!Number.isFinite(o.hi)||o.lo<0||o.hi>1||o.lo>o.hi))return{error:"rescore band must satisfy 0 \u2264 lo \u2264 hi \u2264 1"};let a=e.llm_rescore?.model??vt,c=En.get(e.project);if(c){let P=Mt.get(c);if(P&&P.status==="running")return{jobId:c,reused:!0};En.delete(e.project)}let u=Qo({project:e.project});if(u.length===0)return{error:`no eligible sessions in project "${e.project}"`};let{byProject:d,scannablesByProject:m}=ei(u),h=d.get(e.project),S=m.get(e.project);if(!h||!S)return{error:`project "${e.project}" not found`};let b=r?Math.min(t,o.lo):t,T=Rt(S,b),R=r?T.filter(P=>P.confidence>=t):T;if(T.length===0||R.length===0&&!r)return{error:"no edges above threshold; nothing to apply"};let w=ey(),j=new AbortController,M=Wd(R),W=new Date().toISOString(),x={jobId:w,project:e.project,threshold:t,llmNames:n,status:"running",startedAt:W,endedAt:null,events:[],waiters:new Set,controller:j,totalThreads:M,threadsNamed:0,edgesWritten:0,threadsCreated:0,currentThreadName:null,error:null,cleanupTimer:null,rescore:r?{enabled:!0,considered:0,promoted:0,demoted:0,unsure:0,failed:0,capped:!1}:null};return Mt.set(w,x),En.set(e.project,w),(async()=>{await Promise.resolve();try{jt(x,"progress",{phase:"linking",edges_proposed:T.length,estimated_threads:M});let P=T;if(r){let B=await Pd({proposals:T,scannables:S,applyThreshold:t,rescore:{enabled:!0,band:o,model:a},signal:j.signal,onProgress:se=>{se.phase==="rescoring"&&jt(x,"progress",{phase:"rescoring",current:se.current,total:se.total,verdict:se.verdict})}});P=B.proposals,x.rescore={enabled:!0,considered:B.considered,promoted:B.promoted,demoted:B.demoted,unsure:B.unsure,failed:B.failed,capped:B.capped}}else P=T.filter(B=>B.confidence>=t);if(P.length===0){x.status=j.signal.aborted?"cancelled":"done",x.endedAt=new Date().toISOString(),jt(x,"done",{...$s(x),threads:[]});return}let te=await $d({project:e.project,rows:h,edges:P,scannables:S,llmNames:n,model:s,signal:j.signal,onProgress:B=>{B.phase==="naming"&&(x.threadsNamed=B.current,x.currentThreadName=B.thread_name??null,jt(x,"progress",{phase:"naming",current:B.current,total:B.total,thread_name:B.thread_name}))}});x.threadsCreated=te.threads.length,x.edgesWritten=P.length+te.threads.length,x.status=j.signal.aborted?"cancelled":"done",x.endedAt=new Date().toISOString(),jt(x,"done",{...$s(x),threads:te.threads})}catch(P){x.status="failed",x.endedAt=new Date().toISOString(),x.error=P instanceof Error?P.message:String(P??"unknown error"),jt(x,"done",$s(x))}finally{ny(x)}})(),{jobId:w,reused:!1}}async function*Xd(e,t=0){let n=Mt.get(e);if(!n)return;let s=t;for(;;){for(;s<n.events.length;){let r=n.events[s];if(!r)break;if(s+=1,yield r,r.kind==="done")return}if(n.status!=="running")return;await new Promise(r=>n.waiters.add(r))}}function Jd(e){let t=Mt.get(e);return!t||t.status!=="running"?!1:(t.controller.abort(),!0)}function ni(e){let t=Mt.get(e);return t?$s(t):null}Dn();import{randomUUID as oy}from"node:crypto";var Us=new Map;function Yd(e){let t={id:oy(),status:"pending",createdAt:new Date().toISOString(),finishedAt:null,total:e,completed:0,results:[],error:null,controller:new AbortController,listeners:new Set};return Us.set(t.id,t),t}function Bs(e){return Us.get(e)}function Dt(e,t){for(let n of e.listeners)n(t)}function Gd(e,t){return e.listeners.add(t),()=>{e.listeners.delete(t)}}function zd(e){let t=Us.get(e);return t?(t.controller.abort(),t.status="cancelled",t.finishedAt=new Date().toISOString(),Dt(t,{type:"status",status:"cancelled"}),!0):!1}function Kd(e){return Us.delete(e)}pt();function Hs(e){let{session:t,knownTags:n,minTags:s,maxTags:r}=e,o=n.slice(0,50).map(c=>c.tag).join(", "),a=t.current_tags.length>0?`already applied, do not repeat: [${t.current_tags.join(", ")}]`:"currently has no tags";return[`You are tagging a software engineering session. Produce ${s}-${r} concise, lowercase, hyphen-separated tags that describe:`," - the domain or subsystem touched (auth, db, frontend, ...)"," - the kind of work (bugfix, feature, refactor, research, ...)"," - any specific tool, library, or product if prominent","","Prefer tags from the known-tags list below when applicable \u2014 consistency over creativity. Never invent marketing-sounding labels. Never tag based on speculation; only on observed work.","",`known tags (most used first, up to 50): ${o||"(none yet)"}`,"","Session:",` project: ${t.project}`,t.alias?` alias: ${JSON.stringify(t.alias)}`:" alias: (none)",t.git_branch?` git_branch: ${t.git_branch}`:"",` ${a}`," first_user_message:",Vd(t.first_user_message," ")," message_sample:",Vd(t.message_sample," "),"","Return a single JSON object matching this schema exactly, with no prose before or after:",`{"tags": string[] length ${s}-${r}, "confidence": number 0-1, "rationale": string one short sentence}`].filter(Boolean).join(`
1609
- `)}function Vd(e,t){return e.split(`
1625
+ VALUES (?, ?, ?, 'child', ?, 'auto-scan-v1', ?)`).run(h,R,O.parent_id,O.confidence,r)}o.push({thread_id:h,name:b,session_count:d.sessionIds.length})}})(),{project:e.project,threads:o}}var Mt=new Map,En=new Map,hy=300*1e3;function jt(e,t,n){e.events.push({id:e.events.length+1,kind:t,data:n});for(let s of e.waiters)s();e.waiters.clear()}function Ey(e){e.cleanupTimer||(e.cleanupTimer=setTimeout(()=>{Mt.delete(e.jobId),En.get(e.project)===e.jobId&&En.delete(e.project)},hy),e.cleanupTimer.unref?.())}function Us(e){return{jobId:e.jobId,project:e.project,threshold:e.threshold,llm_names:e.llmNames,status:e.status,startedAt:e.startedAt,endedAt:e.endedAt,total_threads:e.totalThreads,threads_named:e.threadsNamed,edges_written:e.edgesWritten,threads_created:e.threadsCreated,current_thread_name:e.currentThreadName,error:e.error,rescore:e.rescore}}var by=500,Sy=30,ri="claude-haiku-4-5-20251001",Gd={"claude-haiku-4-5-20251001":{in:1,out:5,label:"Haiku 4.5"},"claude-sonnet-4-6":{in:3,out:15,label:"Sonnet 4.6"},"claude-opus-4-7":{in:15,out:75,label:"Opus 4.7"}};function Yd(e){return Gd[e]??Gd[ri]}function zd(e){let t=typeof e.threshold=="number"?e.threshold:Ns;if(!Number.isFinite(t)||t<0||t>1)return{error:"threshold must be a number in [0, 1]"};let n=e.model??ri,s="",r=!!e.llm_rescore?.enabled,o={lo:e.llm_rescore?.band_lo??Pe.lo,hi:e.llm_rescore?.band_hi??Pe.hi};if(r&&(!Number.isFinite(o.lo)||!Number.isFinite(o.hi)||o.lo<0||o.hi>1||o.lo>o.hi))return{error:"rescore band must satisfy 0 \u2264 lo \u2264 hi \u2264 1"};let a=e.llm_rescore?.model??vt,c=ni({project:e.project});if(c.length===0)return{eligible_sessions:0,proposed_edges:0,estimated_threads:0,estimated_llm_calls:0,estimated_input_tokens_max:0,estimated_output_tokens_max:0,estimated_cost_usd_max:0,existing_auto_scan_threads:0,plan_window_estimate:We(0,n),accuracy_caveat:s,model:n,llm_rescore:r?{enabled:!0,band:o,cap:It,estimated_borderline_pairs:0,estimated_input_tokens_max:0,estimated_output_tokens_max:0,estimated_cost_usd_max:0,plan_window_estimate:We(0,a),exceeds_cap:!1,model:a}:null};let{byProject:u,scannablesByProject:d}=si(c),m=u.get(e.project)??[],h=d.get(e.project)??[],b=r?Math.min(t,o.lo):t,S=Rt(h,b),T=r?S.filter(i=>i.confidence>=t):S,R=Kd(T),O=R*by,L=R*Sy,x=Yd(n),F=O/1e6*x.in,A=L/1e6*x.out,$=F+A,te=We(R,n),H=qd(e.project),se=null;if(r){let i=$d(S,o),l=Yd(a),p=i*Dd,g=i*Fd,_=p/1e6*l.in+g/1e6*l.out;se={enabled:!0,band:o,cap:It,estimated_borderline_pairs:i,estimated_input_tokens_max:p,estimated_output_tokens_max:g,estimated_cost_usd_max:Math.round(_*1e4)/1e4,plan_window_estimate:We(i,a),exceeds_cap:i>It,model:a}}return{eligible_sessions:m.length,proposed_edges:T.length,estimated_threads:R,estimated_llm_calls:R,estimated_input_tokens_max:O,estimated_output_tokens_max:L,estimated_cost_usd_max:Math.round($*1e4)/1e4,existing_auto_scan_threads:H,plan_window_estimate:te,accuracy_caveat:s,model:n,llm_rescore:se}}function Kd(e){let t=new Map,n=o=>{let a=o;for(;t.get(a)!==a;)a=t.get(a);return a},s=(o,a)=>{let c=n(o),u=n(a);c!==u&&t.set(c,u)};for(let o of e)t.has(o.parent_id)||t.set(o.parent_id,o.parent_id),t.has(o.child_id)||t.set(o.child_id,o.child_id),s(o.parent_id,o.child_id);let r=new Set;for(let o of t.keys())r.add(n(o));return r.size}function Vd(e){let t=typeof e.threshold=="number"?e.threshold:Ns;if(!Number.isFinite(t)||t<0||t>1)return{error:"threshold must be a number in [0, 1]"};let n=e.llm_names??!0,s=e.model??ri,r=!!e.llm_rescore?.enabled,o={lo:e.llm_rescore?.band_lo??Pe.lo,hi:e.llm_rescore?.band_hi??Pe.hi};if(r&&(!Number.isFinite(o.lo)||!Number.isFinite(o.hi)||o.lo<0||o.hi>1||o.lo>o.hi))return{error:"rescore band must satisfy 0 \u2264 lo \u2264 hi \u2264 1"};let a=e.llm_rescore?.model??vt,c=En.get(e.project);if(c){let $=Mt.get(c);if($&&$.status==="running")return{jobId:c,reused:!0};En.delete(e.project)}let u=ni({project:e.project});if(u.length===0)return{error:`no eligible sessions in project "${e.project}"`};let{byProject:d,scannablesByProject:m}=si(u),h=d.get(e.project),b=m.get(e.project);if(!h||!b)return{error:`project "${e.project}" not found`};let S=r?Math.min(t,o.lo):t,T=Rt(b,S),R=r?T.filter($=>$.confidence>=t):T;if(T.length===0||R.length===0&&!r)return{error:"no edges above threshold; nothing to apply"};let O=fy(),L=new AbortController,x=Kd(R),F=new Date().toISOString(),A={jobId:O,project:e.project,threshold:t,llmNames:n,status:"running",startedAt:F,endedAt:null,events:[],waiters:new Set,controller:L,totalThreads:x,threadsNamed:0,edgesWritten:0,threadsCreated:0,currentThreadName:null,error:null,cleanupTimer:null,rescore:r?{enabled:!0,considered:0,promoted:0,demoted:0,unsure:0,failed:0,capped:!1}:null};return Mt.set(O,A),En.set(e.project,O),(async()=>{await Promise.resolve();try{jt(A,"progress",{phase:"linking",edges_proposed:T.length,estimated_threads:x});let $=T;if(r){let H=await Xd({proposals:T,scannables:b,applyThreshold:t,rescore:{enabled:!0,band:o,model:a},signal:L.signal,onProgress:se=>{se.phase==="rescoring"&&jt(A,"progress",{phase:"rescoring",current:se.current,total:se.total,verdict:se.verdict})}});$=H.proposals,A.rescore={enabled:!0,considered:H.considered,promoted:H.promoted,demoted:H.demoted,unsure:H.unsure,failed:H.failed,capped:H.capped}}else $=T.filter(H=>H.confidence>=t);if($.length===0){A.status=L.signal.aborted?"cancelled":"done",A.endedAt=new Date().toISOString(),jt(A,"done",{...Us(A),threads:[]});return}let te=await Jd({project:e.project,rows:h,edges:$,scannables:b,llmNames:n,model:s,signal:L.signal,onProgress:H=>{H.phase==="naming"&&(A.threadsNamed=H.current,A.currentThreadName=H.thread_name??null,jt(A,"progress",{phase:"naming",current:H.current,total:H.total,thread_name:H.thread_name}))}});A.threadsCreated=te.threads.length,A.edgesWritten=$.length+te.threads.length,A.status=L.signal.aborted?"cancelled":"done",A.endedAt=new Date().toISOString(),jt(A,"done",{...Us(A),threads:te.threads})}catch($){A.status="failed",A.endedAt=new Date().toISOString(),A.error=$ instanceof Error?$.message:String($??"unknown error"),jt(A,"done",Us(A))}finally{Ey(A)}})(),{jobId:O,reused:!1}}async function*Zd(e,t=0){let n=Mt.get(e);if(!n)return;let s=t;for(;;){for(;s<n.events.length;){let r=n.events[s];if(!r)break;if(s+=1,yield r,r.kind==="done")return}if(n.status!=="running")return;await new Promise(r=>n.waiters.add(r))}}function Qd(e){let t=Mt.get(e);return!t||t.status!=="running"?!1:(t.controller.abort(),!0)}function oi(e){let t=Mt.get(e);return t?Us(t):null}Fn();import{randomUUID as Ty}from"node:crypto";var Bs=new Map;function ep(e){let t={id:Ty(),status:"pending",createdAt:new Date().toISOString(),finishedAt:null,total:e,completed:0,results:[],error:null,controller:new AbortController,listeners:new Set};return Bs.set(t.id,t),t}function Hs(e){return Bs.get(e)}function Dt(e,t){for(let n of e.listeners)n(t)}function tp(e,t){return e.listeners.add(t),()=>{e.listeners.delete(t)}}function np(e){let t=Bs.get(e);return t?(t.controller.abort(),t.status="cancelled",t.finishedAt=new Date().toISOString(),Dt(t,{type:"status",status:"cancelled"}),!0):!1}function sp(e){return Bs.delete(e)}pt();function Ws(e){let{session:t,knownTags:n,minTags:s,maxTags:r}=e,o=n.slice(0,50).map(c=>c.tag).join(", "),a=t.current_tags.length>0?`already applied, do not repeat: [${t.current_tags.join(", ")}]`:"currently has no tags";return[`You are tagging a software engineering session. Produce ${s}-${r} concise, lowercase, hyphen-separated tags that describe:`," - the domain or subsystem touched (auth, db, frontend, ...)"," - the kind of work (bugfix, feature, refactor, research, ...)"," - any specific tool, library, or product if prominent","","Prefer tags from the known-tags list below when applicable \u2014 consistency over creativity. Never invent marketing-sounding labels. Never tag based on speculation; only on observed work.","",`known tags (most used first, up to 50): ${o||"(none yet)"}`,"","Session:",` project: ${t.project}`,t.alias?` alias: ${JSON.stringify(t.alias)}`:" alias: (none)",t.git_branch?` git_branch: ${t.git_branch}`:"",` ${a}`," first_user_message:",rp(t.first_user_message," ")," message_sample:",rp(t.message_sample," "),"","Return a single JSON object matching this schema exactly, with no prose before or after:",`{"tags": string[] length ${s}-${r}, "confidence": number 0-1, "rationale": string one short sentence}`].filter(Boolean).join(`
1626
+ `)}function rp(e,t){return e.split(`
1610
1627
  `).map(n=>t+n).join(`
1611
- `)}pt();import{z as bn}from"zod";var iy=bn.object({tags:bn.array(bn.string()).min(1),confidence:bn.number().min(0).max(1),rationale:bn.string().min(1).max(500)});function ay(e){let t=e.trim();return t.startsWith("```")?t.replace(/^```(?:json)?\s*/i,"").replace(/```$/i,"").trim():t}function Ws(e,t={}){let n=t.maxTags??10,s;try{s=JSON.parse(ay(e))}catch{return{ok:!1,reason:"not valid JSON"}}let r=iy.safeParse(s);if(!r.success)return{ok:!1,reason:r.error.issues.map(c=>c.message).join("; ")};let o=r.data.tags.map(c=>Qe(c)).filter(c=>c.length>0),a=Array.from(new Set(o)).slice(0,n);return a.length===0?{ok:!1,reason:"no usable tags after normalization"}:{ok:!0,data:{tags:a,confidence:r.data.confidence,rationale:r.data.rationale}}}import cy from"@anthropic-ai/sdk";async function qs(e){let s=(await new cy({apiKey:e.apiKey}).messages.create({model:e.model,max_tokens:512,temperature:.2,messages:[{role:"user",content:e.prompt}]},e.signal?{signal:e.signal}:void 0)).content.find(r=>r.type==="text");if(!s||s.type!=="text")throw new Error("Anthropic response contained no text block");return s.text}function ly(e){if(!(e instanceof Error))return!1;let t=e;return t.status===429||t.status===502||t.status===503||t.status===504}async function Xs(e,t={}){let n=t.maxAttempts??3,s=t.baseDelayMs??500,r;for(let o=0;o<n;o++)try{return await e()}catch(a){if(r=a,!ly(a)||o===n-1)throw a;await new Promise(c=>setTimeout(c,s*Math.pow(2,o)))}throw r}async function Zd(e,t){e.status="running",Dt(e,{type:"status",status:"running"});let n=dt();for(let s of t.sessions){if(e.controller.signal.aborted)break;let r=Hs({session:s,knownTags:n,minTags:t.minTags,maxTags:t.maxTags}),o={sessionId:s.id,project:s.project,alias:s.alias,first_user_message:s.first_user_message,current_tags:s.current_tags,suggestion:null,error:null,applied:!1};try{let a=await Xs(()=>qs({apiKey:t.apiKey,model:t.model,prompt:r,signal:e.controller.signal})),c=Ws(a,{maxTags:t.maxTags});c.ok?o.suggestion=c.data:o.error=c.reason}catch(a){o.error=a instanceof Error?a.message:String(a)}e.results.push(o),e.completed+=1,Dt(e,{type:"result",result:o}),Dt(e,{type:"progress",completed:e.completed,total:e.total})}if(!e.controller.signal.aborted){e.status="completed",e.finishedAt=new Date().toISOString();let s=e.results.filter(o=>o.suggestion&&!o.error).length,r=e.results.filter(o=>o.error).length;Dt(e,{type:"done",summary:{ok:s,failed:r}})}}function Qd(e,t){let n=0,s=0;for(let r of t){let o=e.results.find(a=>a.sessionId===r.sessionId);if(o){for(let a of r.tags)try{let{added:c}=ut(r.sessionId,a);c&&(n+=1)}catch(c){console.error("[scanner] apply failed:",r.sessionId,a,c),s+=1}o.applied=!0}}return{applied:n,failed:s}}pt();Dn();var Z={running:!1,status:"idle",processed:0,total:0,currentSessionId:null,lastError:null,lastRunAt:null,controller:null},si=new Set;function Tn(){return{status:Z.status,processed:Z.processed,total:Z.total,currentSessionId:Z.currentSessionId,lastError:Z.lastError,lastRunAt:Z.lastRunAt}}function ep(e){return si.add(e),()=>{si.delete(e)}}function Sn(){let e=Tn();for(let t of si)t(e)}async function Js(){let e=Fe();if(!(!e.enabled||!e.autopilot)&&!(e.backend!=="api"||!e.apiKey)&&!Z.running){Z.running=!0,Z.status="scanning",Z.processed=0,Z.total=0,Z.currentSessionId=null,Z.lastError=null,Z.controller=new AbortController,Sn();try{let t=mt({untaggedOnly:!0,limit:200});if(Z.total=t.length,Sn(),t.length===0){Z.status="idle",Z.lastRunAt=new Date().toISOString();return}let n=dt();for(let s of t){if(Z.controller.signal.aborted)break;let r=Fe();if(!r.autopilot||!r.enabled||r.backend!=="api"||!r.apiKey)break;Z.currentSessionId=s.id,Sn();let o=Hs({session:s,knownTags:n,minTags:r.minTagsPerSession,maxTags:r.maxTagsPerSession});try{let a=await Xs(()=>qs({apiKey:r.apiKey,model:r.model,prompt:o,signal:Z.controller.signal})),c=Ws(a,{maxTags:r.maxTagsPerSession});if(c.ok)for(let u of c.data.tags)try{ut(s.id,u)}catch(d){console.error("[autopilot] addTag failed:",s.id,u,d)}}catch(a){console.error("[autopilot] scan failed for",s.id,a)}Z.processed+=1,Sn(),await new Promise(a=>setTimeout(a,1500))}Z.status="idle",Z.lastRunAt=new Date().toISOString()}catch(t){Z.status="error",Z.lastError=t instanceof Error?t.message:String(t),console.error("[autopilot] fatal:",t)}finally{Z.running=!1,Z.currentSessionId=null,Z.controller=null,Sn()}}}$n();import{existsSync as np,readFileSync as uy,writeFileSync as sp}from"node:fs";import{homedir as dy}from"node:os";import{dirname as py,join as my,resolve as gy}from"node:path";import{fileURLToPath as _y}from"node:url";var Ft=my(dy(),".claude.json"),fy=py(_y(import.meta.url)),hy=gy(fy,"..","mcp","server.js");function ri(){if(!np(Ft))return{};try{let e=uy(Ft,"utf8"),t=JSON.parse(e);return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}catch(e){return console.error("[mcp-installer] failed to parse ~/.claude.json:",e),{}}}var tp=new Map;function Ey(e){let t=tp.get(e);if(t!==void 0)return t;let n=gt(e)!==null;return tp.set(e,n),n}function by(){return Ey("claude-recall-mcp")?{command:"claude-recall-mcp",args:[]}:{command:process.execPath,args:[hy]}}function qe(){let t=ri().mcpServers?.recall;return{configPath:Ft,configExists:np(Ft),installed:!!(t&&typeof t.command=="string"),command:t?.command??null,args:t?.args??null}}function rp(){let e=ri(),t=e.mcpServers??{},n=by(),s=t.recall;if(s?.command===n.command&&JSON.stringify(s?.args??[])===JSON.stringify(n.args))return qe();let o={command:n.command};n.args.length>0&&(o.args=n.args);let a={...e,mcpServers:{...t,recall:o}};return sp(Ft,JSON.stringify(a,null,2)),qe()}function op(){let e=ri(),t=e.mcpServers??{};if(!t.recall)return qe();let{recall:n,...s}=t,r={...e,mcpServers:s};return sp(Ft,JSON.stringify(r,null,2)),qe()}import{existsSync as ip,mkdirSync as Sy,readFileSync as Ty,writeFileSync as ap}from"node:fs";import{homedir as yy}from"node:os";import{join as cp}from"node:path";import{z as Xe}from"zod";function lp(){return process.env.RECALL_HOME??cp(yy(),".recall")}function up(){let e=lp();ip(e)||Sy(e,{recursive:!0})}function ii(){return cp(lp(),"onboarding.json")}var Ys=Xe.object({version:Xe.literal(1).default(1),completed:Xe.boolean().default(!1),skipped:Xe.boolean().default(!1),finishedAt:Xe.string().nullable().default(null),completedSteps:Xe.array(Xe.string().max(100)).max(50).default([]),threadsIntroSeen:Xe.boolean().default(!1)}),oi={version:1,completed:!1,skipped:!1,finishedAt:null,completedSteps:[],threadsIntroSeen:!1};function Gs(){let e=ii();if(!ip(e))return{...oi};try{let t=JSON.parse(Ty(e,"utf8")),n=Ys.safeParse(t);return n.success?n.data:{...oi}}catch(t){return console.error("[onboarding-state] failed to parse onboarding.json, using defaults:",t),{...oi}}}function dp(e){up();let t=Gs(),n=Ys.parse({...t,...e,completedSteps:wy([...t.completedSteps??[],...e.completedSteps??[]]),version:1});return ap(ii(),JSON.stringify(n,null,2)),n}function pp(){up();let e=Gs(),t={version:1,completed:!1,skipped:!1,finishedAt:null,completedSteps:e.completedSteps,threadsIntroSeen:e.threadsIntroSeen};return ap(ii(),JSON.stringify(t,null,2)),t}function wy(e){let t=new Set,n=[];for(let s of e)t.has(s)||(t.add(s),n.push(s));return n}ye();Rr();wr();U();U();var Ry=500,zs=new Set,mp=null,Ks=!1;function gp(){return zs.size}function ky(){return`
1628
+ `)}pt();import{z as bn}from"zod";var yy=bn.object({tags:bn.array(bn.string()).min(1),confidence:bn.number().min(0).max(1),rationale:bn.string().min(1).max(500)});function wy(e){let t=e.trim();return t.startsWith("```")?t.replace(/^```(?:json)?\s*/i,"").replace(/```$/i,"").trim():t}function qs(e,t={}){let n=t.maxTags??10,s;try{s=JSON.parse(wy(e))}catch{return{ok:!1,reason:"not valid JSON"}}let r=yy.safeParse(s);if(!r.success)return{ok:!1,reason:r.error.issues.map(c=>c.message).join("; ")};let o=r.data.tags.map(c=>Ze(c)).filter(c=>c.length>0),a=Array.from(new Set(o)).slice(0,n);return a.length===0?{ok:!1,reason:"no usable tags after normalization"}:{ok:!0,data:{tags:a,confidence:r.data.confidence,rationale:r.data.rationale}}}import Ry from"@anthropic-ai/sdk";async function Xs(e){let s=(await new Ry({apiKey:e.apiKey}).messages.create({model:e.model,max_tokens:512,temperature:.2,messages:[{role:"user",content:e.prompt}]},e.signal?{signal:e.signal}:void 0)).content.find(r=>r.type==="text");if(!s||s.type!=="text")throw new Error("Anthropic response contained no text block");return s.text}function ky(e){if(!(e instanceof Error))return!1;let t=e;return t.status===429||t.status===502||t.status===503||t.status===504}async function Js(e,t={}){let n=t.maxAttempts??3,s=t.baseDelayMs??500,r;for(let o=0;o<n;o++)try{return await e()}catch(a){if(r=a,!ky(a)||o===n-1)throw a;await new Promise(c=>setTimeout(c,s*Math.pow(2,o)))}throw r}async function op(e,t){e.status="running",Dt(e,{type:"status",status:"running"});let n=dt();for(let s of t.sessions){if(e.controller.signal.aborted)break;let r=Ws({session:s,knownTags:n,minTags:t.minTags,maxTags:t.maxTags}),o={sessionId:s.id,project:s.project,alias:s.alias,first_user_message:s.first_user_message,current_tags:s.current_tags,suggestion:null,error:null,applied:!1};try{let a=await Js(()=>Xs({apiKey:t.apiKey,model:t.model,prompt:r,signal:e.controller.signal})),c=qs(a,{maxTags:t.maxTags});c.ok?o.suggestion=c.data:o.error=c.reason}catch(a){o.error=a instanceof Error?a.message:String(a)}e.results.push(o),e.completed+=1,Dt(e,{type:"result",result:o}),Dt(e,{type:"progress",completed:e.completed,total:e.total})}if(!e.controller.signal.aborted){e.status="completed",e.finishedAt=new Date().toISOString();let s=e.results.filter(o=>o.suggestion&&!o.error).length,r=e.results.filter(o=>o.error).length;Dt(e,{type:"done",summary:{ok:s,failed:r}})}}function ip(e,t){let n=0,s=0;for(let r of t){let o=e.results.find(a=>a.sessionId===r.sessionId);if(o){for(let a of r.tags)try{let{added:c}=ut(r.sessionId,a);c&&(n+=1)}catch(c){console.error("[scanner] apply failed:",r.sessionId,a,c),s+=1}o.applied=!0}}return{applied:n,failed:s}}pt();Fn();var Z={running:!1,status:"idle",processed:0,total:0,currentSessionId:null,lastError:null,lastRunAt:null,controller:null},ii=new Set;function Tn(){return{status:Z.status,processed:Z.processed,total:Z.total,currentSessionId:Z.currentSessionId,lastError:Z.lastError,lastRunAt:Z.lastRunAt}}function ap(e){return ii.add(e),()=>{ii.delete(e)}}function Sn(){let e=Tn();for(let t of ii)t(e)}async function Gs(){let e=Fe();if(!(!e.enabled||!e.autopilot)&&!(e.backend!=="api"||!e.apiKey)&&!Z.running){Z.running=!0,Z.status="scanning",Z.processed=0,Z.total=0,Z.currentSessionId=null,Z.lastError=null,Z.controller=new AbortController,Sn();try{let t=mt({untaggedOnly:!0,limit:200});if(Z.total=t.length,Sn(),t.length===0){Z.status="idle",Z.lastRunAt=new Date().toISOString();return}let n=dt();for(let s of t){if(Z.controller.signal.aborted)break;let r=Fe();if(!r.autopilot||!r.enabled||r.backend!=="api"||!r.apiKey)break;Z.currentSessionId=s.id,Sn();let o=Ws({session:s,knownTags:n,minTags:r.minTagsPerSession,maxTags:r.maxTagsPerSession});try{let a=await Js(()=>Xs({apiKey:r.apiKey,model:r.model,prompt:o,signal:Z.controller.signal})),c=qs(a,{maxTags:r.maxTagsPerSession});if(c.ok)for(let u of c.data.tags)try{ut(s.id,u)}catch(d){console.error("[autopilot] addTag failed:",s.id,u,d)}}catch(a){console.error("[autopilot] scan failed for",s.id,a)}Z.processed+=1,Sn(),await new Promise(a=>setTimeout(a,1500))}Z.status="idle",Z.lastRunAt=new Date().toISOString()}catch(t){Z.status="error",Z.lastError=t instanceof Error?t.message:String(t),console.error("[autopilot] fatal:",t)}finally{Z.running=!1,Z.currentSessionId=null,Z.controller=null,Sn()}}}Un();import{existsSync as lp,readFileSync as Ay,writeFileSync as up}from"node:fs";import{homedir as xy}from"node:os";import{dirname as Ny,join as Oy,resolve as Ly}from"node:path";import{fileURLToPath as Cy}from"node:url";var Ft=Oy(xy(),".claude.json"),vy=Ny(Cy(import.meta.url)),Iy=Ly(vy,"..","mcp","server.js");function ai(){if(!lp(Ft))return{};try{let e=Ay(Ft,"utf8"),t=JSON.parse(e);return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}catch(e){return console.error("[mcp-installer] failed to parse ~/.claude.json:",e),{}}}var cp=new Map;function jy(e){let t=cp.get(e);if(t!==void 0)return t;let n=gt(e)!==null;return cp.set(e,n),n}function My(){return jy("claude-recall-mcp")?{command:"claude-recall-mcp",args:[]}:{command:process.execPath,args:[Iy]}}function qe(){let t=ai().mcpServers?.recall;return{configPath:Ft,configExists:lp(Ft),installed:!!(t&&typeof t.command=="string"),command:t?.command??null,args:t?.args??null}}function dp(){let e=ai(),t=e.mcpServers??{},n=My(),s=t.recall;if(s?.command===n.command&&JSON.stringify(s?.args??[])===JSON.stringify(n.args))return qe();let o={command:n.command};n.args.length>0&&(o.args=n.args);let a={...e,mcpServers:{...t,recall:o}};return up(Ft,JSON.stringify(a,null,2)),qe()}function pp(){let e=ai(),t=e.mcpServers??{};if(!t.recall)return qe();let{recall:n,...s}=t,r={...e,mcpServers:s};return up(Ft,JSON.stringify(r,null,2)),qe()}import{existsSync as mp,mkdirSync as Dy,readFileSync as Fy,writeFileSync as gp}from"node:fs";import{homedir as Py}from"node:os";import{join as _p}from"node:path";import{z as Xe}from"zod";function fp(){return process.env.RECALL_HOME??_p(Py(),".recall")}function hp(){let e=fp();mp(e)||Dy(e,{recursive:!0})}function li(){return _p(fp(),"onboarding.json")}var Ys=Xe.object({version:Xe.literal(1).default(1),completed:Xe.boolean().default(!1),skipped:Xe.boolean().default(!1),finishedAt:Xe.string().nullable().default(null),completedSteps:Xe.array(Xe.string().max(100)).max(50).default([]),threadsIntroSeen:Xe.boolean().default(!1)}),ci={version:1,completed:!1,skipped:!1,finishedAt:null,completedSteps:[],threadsIntroSeen:!1};function zs(){let e=li();if(!mp(e))return{...ci};try{let t=JSON.parse(Fy(e,"utf8")),n=Ys.safeParse(t);return n.success?n.data:{...ci}}catch(t){return console.error("[onboarding-state] failed to parse onboarding.json, using defaults:",t),{...ci}}}function Ep(e){hp();let t=zs(),n=Ys.parse({...t,...e,completedSteps:$y([...t.completedSteps??[],...e.completedSteps??[]]),version:1});return gp(li(),JSON.stringify(n,null,2)),n}function bp(){hp();let e=zs(),t={version:1,completed:!1,skipped:!1,finishedAt:null,completedSteps:e.completedSteps,threadsIntroSeen:e.threadsIntroSeen};return gp(li(),JSON.stringify(t,null,2)),t}function $y(e){let t=new Set,n=[];for(let s of e)t.has(s)||(t.add(s),n.push(s));return n}ye();kr();Rr();B();B();var Uy=500,Ks=new Set,Sp=null,Vs=!1;function Tp(){return Ks.size}function By(){return`
1612
1629
  SELECT m.uuid, m.session_id, m.timestamp, m.raw_json
1613
1630
  FROM messages m
1614
1631
  LEFT JOIN message_usage mu ON mu.message_uuid = m.uuid
1615
1632
  WHERE m.role = 'assistant' AND mu.message_uuid IS NULL
1616
1633
  AND m.uuid NOT IN (SELECT value FROM json_each(?))
1617
1634
  LIMIT ?
1618
- `}function _p(e,t){let n=t.limit??Number.MAX_SAFE_INTEGER,s=Math.max(1,t.chunkSize??Ry),r=e.prepare(ky()),o=e.prepare(`
1635
+ `}function yp(e,t){let n=t.limit??Number.MAX_SAFE_INTEGER,s=Math.max(1,t.chunkSize??Uy),r=e.prepare(By()),o=e.prepare(`
1619
1636
  INSERT INTO message_usage (
1620
1637
  message_uuid, session_id, model,
1621
1638
  input_tokens, output_tokens, cache_create_tokens, cache_read_tokens,
@@ -1625,7 +1642,7 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1625
1642
  @input, @output, @cc, @cr, @ts
1626
1643
  )
1627
1644
  ON CONFLICT(message_uuid) DO NOTHING
1628
- `),a=0,c=0,u=new Set;for(;a<n;){let d=Math.min(s,n-a),m=JSON.stringify([...zs]),h=r.all(m,d);if(h.length===0)break;let S=new Set;if(e.transaction(()=>{for(let T of h){let R;try{R=JSON.parse(T.raw_json)}catch{zs.add(T.uuid);continue}let w=Gr(R.message);if(!w){zs.add(T.uuid);continue}o.run({uuid:T.uuid,session_id:T.session_id,model:R.message?.model??null,input:w.inputTokens,output:w.outputTokens,cc:w.cacheCreateTokens,cr:w.cacheReadTokens,ts:T.timestamp}),c+=1,S.add(T.session_id)}for(let T of S)rs(e,T),u.add(T)})(),a+=h.length,t.onProgress?.({scanned:a,inserted:c,sessionsTouched:u.size,done:h.length<d}),h.length<d)break}return{scanned:a,inserted:c,sessionsTouched:u.size,done:!0}}function fp(e={}){return _p(f(),e)}function hp(e={}){return Ks?!1:(Ks=!0,queueMicrotask(()=>{try{let t=_p(f(),e);mp={scanned:t.scanned,inserted:t.inserted,sessionsTouched:t.sessionsTouched,finishedAt:new Date().toISOString()}}catch(t){console.error("[stats.backfill] failed:",t)}finally{Ks=!1}}),!0)}function Ep(){return Ks}function ai(){return mp}var Ay=[[/opus[-_ ]?4[-_. ]?7/i,{label:"Opus 4.7",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/opus[-_ ]?4[-_. ]?6/i,{label:"Opus 4.6",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/sonnet[-_ ]?4[-_. ]?6/i,{label:"Sonnet 4.6",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/sonnet[-_ ]?4[-_. ]?5/i,{label:"Sonnet 4.5",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/haiku[-_ ]?4[-_. ]?5/i,{label:"Haiku 4.5",inputCentsPerMtok:100,outputCentsPerMtok:500,cacheCreateCentsPerMtok:125,cacheReadCentsPerMtok:10}],[/opus[-_ ]?4(?!.*[5-9])/i,{label:"Opus 4",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/sonnet[-_ ]?4(?!.*[5-9])/i,{label:"Sonnet 4",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/3[-_. ]?7[-_ ]?sonnet|sonnet[-_ ]?3[-_. ]?7/i,{label:"Sonnet 3.7",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/3[-_. ]?5[-_ ]?sonnet|sonnet[-_ ]?3[-_. ]?5/i,{label:"Sonnet 3.5",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/3[-_. ]?5[-_ ]?haiku|haiku[-_ ]?3[-_. ]?5/i,{label:"Haiku 3.5",inputCentsPerMtok:80,outputCentsPerMtok:400,cacheCreateCentsPerMtok:100,cacheReadCentsPerMtok:8}],[/3[-_ ]?opus|opus[-_ ]?3/i,{label:"Opus 3",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/3[-_ ]?haiku|haiku(?!.*3[-_. ]?5)/i,{label:"Haiku 3",inputCentsPerMtok:25,outputCentsPerMtok:125,cacheCreateCentsPerMtok:30,cacheReadCentsPerMtok:3}],[/opus/i,{label:"Opus",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/sonnet/i,{label:"Sonnet",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/haiku/i,{label:"Haiku",inputCentsPerMtok:100,outputCentsPerMtok:500,cacheCreateCentsPerMtok:125,cacheReadCentsPerMtok:10}]],bp={label:"unknown",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30};function Je(e){if(!e)return bp;for(let[t,n]of Ay)if(t.test(e))return n;return bp}function Ae(e,t){if(e.byModel&&Object.keys(e.byModel).length>0){let a={input:0,output:0,cacheCreate:0,cacheRead:0},c=0;for(let[d,m]of Object.entries(e.byModel)){let h=Je(d);a.input+=m.inputTokens/1e6*h.inputCentsPerMtok,a.output+=m.outputTokens/1e6*h.outputCentsPerMtok,a.cacheCreate+=m.cacheCreateTokens/1e6*h.cacheCreateCentsPerMtok,a.cacheRead+=m.cacheReadTokens/1e6*h.cacheReadCentsPerMtok,c+=m.inputTokens+m.outputTokens+m.cacheCreateTokens+m.cacheReadTokens}let u=a.input+a.output+a.cacheCreate+a.cacheRead;return{cents:u,dollars:u/100,totalTokens:c,parts:a}}let n=Je(t),s={input:e.inputTokens/1e6*n.inputCentsPerMtok,output:e.outputTokens/1e6*n.outputCentsPerMtok,cacheCreate:e.cacheCreateTokens/1e6*n.cacheCreateCentsPerMtok,cacheRead:e.cacheReadTokens/1e6*n.cacheReadCentsPerMtok},r=s.input+s.output+s.cacheCreate+s.cacheRead,o=e.inputTokens+e.outputTokens+e.cacheCreateTokens+e.cacheReadTokens;return{cents:r,dollars:r/100,totalTokens:o,parts:s}}function Pt(e){let t=e/100;return t===0?"$0.00":t<.01?"<$0.01":t<1?`$${t.toFixed(2)}`:t<100?`$${t.toFixed(2)}`:t<1e4?`$${t.toFixed(0)}`:`$${(t/1e3).toFixed(1)}k`}function $t(e){return!Number.isFinite(e)||e<0?"0":e<1e3?String(Math.round(e)):e<1e6?`${(e/1e3).toFixed(1)}k`:e<1e9?`${(e/1e6).toFixed(2)}M`:e<1e12?`${(e/1e9).toFixed(2)}B`:`${(e/1e12).toFixed(2)}T`}function ci(e){let t=new Map;for(let s of e){let r=s.model??null,o=t.get(r)??{inputTokens:0,outputTokens:0,cacheCreateTokens:0,cacheReadTokens:0,messageCount:0};o.inputTokens+=s.input_tokens,o.outputTokens+=s.output_tokens,o.cacheCreateTokens+=s.cache_create_tokens,o.cacheReadTokens+=s.cache_read_tokens,o.messageCount+=s.n,t.set(r,o)}let n=[];for(let[s,r]of t.entries()){let o=Ae({inputTokens:r.inputTokens,outputTokens:r.outputTokens,cacheCreateTokens:r.cacheCreateTokens,cacheReadTokens:r.cacheReadTokens},s);n.push({model:s,modelLabel:Je(s).label,inputTokens:r.inputTokens,outputTokens:r.outputTokens,cacheCreateTokens:r.cacheCreateTokens,cacheReadTokens:r.cacheReadTokens,messageCount:r.messageCount,cost:o})}return n.sort((s,r)=>r.cost.cents-s.cost.cents)}function li(e){let t={};for(let n of e)t[n.model??"__unknown__"]={inputTokens:n.inputTokens,outputTokens:n.outputTokens,cacheCreateTokens:n.cacheCreateTokens,cacheReadTokens:n.cacheReadTokens};return{byModel:t}}function Sp(e){let t=f(),n=t.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
1645
+ `),a=0,c=0,u=new Set;for(;a<n;){let d=Math.min(s,n-a),m=JSON.stringify([...Ks]),h=r.all(m,d);if(h.length===0)break;let b=new Set;if(e.transaction(()=>{for(let T of h){let R;try{R=JSON.parse(T.raw_json)}catch{Ks.add(T.uuid);continue}let O=zr(R.message);if(!O){Ks.add(T.uuid);continue}o.run({uuid:T.uuid,session_id:T.session_id,model:R.message?.model??null,input:O.inputTokens,output:O.outputTokens,cc:O.cacheCreateTokens,cr:O.cacheReadTokens,ts:T.timestamp}),c+=1,b.add(T.session_id)}for(let T of b)os(e,T),u.add(T)})(),a+=h.length,t.onProgress?.({scanned:a,inserted:c,sessionsTouched:u.size,done:h.length<d}),h.length<d)break}return{scanned:a,inserted:c,sessionsTouched:u.size,done:!0}}function wp(e={}){return yp(f(),e)}function Rp(e={}){return Vs?!1:(Vs=!0,queueMicrotask(()=>{try{let t=yp(f(),e);Sp={scanned:t.scanned,inserted:t.inserted,sessionsTouched:t.sessionsTouched,finishedAt:new Date().toISOString()}}catch(t){console.error("[stats.backfill] failed:",t)}finally{Vs=!1}}),!0)}function kp(){return Vs}function ui(){return Sp}var Hy=[[/opus[-_ ]?4[-_. ]?7/i,{label:"Opus 4.7",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/opus[-_ ]?4[-_. ]?6/i,{label:"Opus 4.6",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/sonnet[-_ ]?4[-_. ]?6/i,{label:"Sonnet 4.6",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/sonnet[-_ ]?4[-_. ]?5/i,{label:"Sonnet 4.5",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/haiku[-_ ]?4[-_. ]?5/i,{label:"Haiku 4.5",inputCentsPerMtok:100,outputCentsPerMtok:500,cacheCreateCentsPerMtok:125,cacheReadCentsPerMtok:10}],[/opus[-_ ]?4(?!.*[5-9])/i,{label:"Opus 4",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/sonnet[-_ ]?4(?!.*[5-9])/i,{label:"Sonnet 4",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/3[-_. ]?7[-_ ]?sonnet|sonnet[-_ ]?3[-_. ]?7/i,{label:"Sonnet 3.7",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/3[-_. ]?5[-_ ]?sonnet|sonnet[-_ ]?3[-_. ]?5/i,{label:"Sonnet 3.5",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/3[-_. ]?5[-_ ]?haiku|haiku[-_ ]?3[-_. ]?5/i,{label:"Haiku 3.5",inputCentsPerMtok:80,outputCentsPerMtok:400,cacheCreateCentsPerMtok:100,cacheReadCentsPerMtok:8}],[/3[-_ ]?opus|opus[-_ ]?3/i,{label:"Opus 3",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/3[-_ ]?haiku|haiku(?!.*3[-_. ]?5)/i,{label:"Haiku 3",inputCentsPerMtok:25,outputCentsPerMtok:125,cacheCreateCentsPerMtok:30,cacheReadCentsPerMtok:3}],[/opus/i,{label:"Opus",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/sonnet/i,{label:"Sonnet",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/haiku/i,{label:"Haiku",inputCentsPerMtok:100,outputCentsPerMtok:500,cacheCreateCentsPerMtok:125,cacheReadCentsPerMtok:10}]],Ap={label:"unknown",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30};function Je(e){if(!e)return Ap;for(let[t,n]of Hy)if(t.test(e))return n;return Ap}function Ae(e,t){if(e.byModel&&Object.keys(e.byModel).length>0){let a={input:0,output:0,cacheCreate:0,cacheRead:0},c=0;for(let[d,m]of Object.entries(e.byModel)){let h=Je(d);a.input+=m.inputTokens/1e6*h.inputCentsPerMtok,a.output+=m.outputTokens/1e6*h.outputCentsPerMtok,a.cacheCreate+=m.cacheCreateTokens/1e6*h.cacheCreateCentsPerMtok,a.cacheRead+=m.cacheReadTokens/1e6*h.cacheReadCentsPerMtok,c+=m.inputTokens+m.outputTokens+m.cacheCreateTokens+m.cacheReadTokens}let u=a.input+a.output+a.cacheCreate+a.cacheRead;return{cents:u,dollars:u/100,totalTokens:c,parts:a}}let n=Je(t),s={input:e.inputTokens/1e6*n.inputCentsPerMtok,output:e.outputTokens/1e6*n.outputCentsPerMtok,cacheCreate:e.cacheCreateTokens/1e6*n.cacheCreateCentsPerMtok,cacheRead:e.cacheReadTokens/1e6*n.cacheReadCentsPerMtok},r=s.input+s.output+s.cacheCreate+s.cacheRead,o=e.inputTokens+e.outputTokens+e.cacheCreateTokens+e.cacheReadTokens;return{cents:r,dollars:r/100,totalTokens:o,parts:s}}function Pt(e){let t=e/100;return t===0?"$0.00":t<.01?"<$0.01":t<1?`$${t.toFixed(2)}`:t<100?`$${t.toFixed(2)}`:t<1e4?`$${t.toFixed(0)}`:`$${(t/1e3).toFixed(1)}k`}function $t(e){return!Number.isFinite(e)||e<0?"0":e<1e3?String(Math.round(e)):e<1e6?`${(e/1e3).toFixed(1)}k`:e<1e9?`${(e/1e6).toFixed(2)}M`:e<1e12?`${(e/1e9).toFixed(2)}B`:`${(e/1e12).toFixed(2)}T`}function di(e){let t=new Map;for(let s of e){let r=s.model??null,o=t.get(r)??{inputTokens:0,outputTokens:0,cacheCreateTokens:0,cacheReadTokens:0,messageCount:0};o.inputTokens+=s.input_tokens,o.outputTokens+=s.output_tokens,o.cacheCreateTokens+=s.cache_create_tokens,o.cacheReadTokens+=s.cache_read_tokens,o.messageCount+=s.n,t.set(r,o)}let n=[];for(let[s,r]of t.entries()){let o=Ae({inputTokens:r.inputTokens,outputTokens:r.outputTokens,cacheCreateTokens:r.cacheCreateTokens,cacheReadTokens:r.cacheReadTokens},s);n.push({model:s,modelLabel:Je(s).label,inputTokens:r.inputTokens,outputTokens:r.outputTokens,cacheCreateTokens:r.cacheCreateTokens,cacheReadTokens:r.cacheReadTokens,messageCount:r.messageCount,cost:o})}return n.sort((s,r)=>r.cost.cents-s.cost.cents)}function pi(e){let t={};for(let n of e)t[n.model??"__unknown__"]={inputTokens:n.inputTokens,outputTokens:n.outputTokens,cacheCreateTokens:n.cacheCreateTokens,cacheReadTokens:n.cacheReadTokens};return{byModel:t}}function xp(e){let t=f(),n=t.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
1629
1646
  s.message_count,
1630
1647
  s.total_input_tokens, s.total_output_tokens,
1631
1648
  s.total_cache_create_tokens, s.total_cache_read_tokens,
@@ -1640,7 +1657,7 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1640
1657
  COUNT(*) AS n
1641
1658
  FROM message_usage
1642
1659
  WHERE session_id = ?
1643
- GROUP BY model`).all(e),r=ci(s),o=n.total_input_tokens??0,a=n.total_output_tokens??0,c=n.total_cache_create_tokens??0,u=n.total_cache_read_tokens??0,d=Ae({inputTokens:o,outputTokens:a,cacheCreateTokens:c,cacheReadTokens:u,...li(r)},n.primary_model);return{sessionId:n.id,project:n.project,startedAt:n.started_at,endedAt:n.ended_at,messageCount:n.message_count,primaryModel:n.primary_model,primaryModelLabel:Je(n.primary_model).label,inputTokens:o,outputTokens:a,cacheCreateTokens:c,cacheReadTokens:u,totalTokens:d.totalTokens,cost:d,byModel:r,display:{dollars:Pt(d.cents),tokens:$t(d.totalTokens),model:Je(n.primary_model).label}}}function Tp(e){let t=f(),n=t.prepare("SELECT id, name FROM projects WHERE name = ?").get(e);if(!n)return null;let s=t.prepare(`SELECT mu.model,
1660
+ GROUP BY model`).all(e),r=di(s),o=n.total_input_tokens??0,a=n.total_output_tokens??0,c=n.total_cache_create_tokens??0,u=n.total_cache_read_tokens??0,d=Ae({inputTokens:o,outputTokens:a,cacheCreateTokens:c,cacheReadTokens:u,...pi(r)},n.primary_model);return{sessionId:n.id,project:n.project,startedAt:n.started_at,endedAt:n.ended_at,messageCount:n.message_count,primaryModel:n.primary_model,primaryModelLabel:Je(n.primary_model).label,inputTokens:o,outputTokens:a,cacheCreateTokens:c,cacheReadTokens:u,totalTokens:d.totalTokens,cost:d,byModel:r,display:{dollars:Pt(d.cents),tokens:$t(d.totalTokens),model:Je(n.primary_model).label}}}function Np(e){let t=f(),n=t.prepare("SELECT id, name FROM projects WHERE name = ?").get(e);if(!n)return null;let s=t.prepare(`SELECT mu.model,
1644
1661
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
1645
1662
  COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
1646
1663
  COALESCE(SUM(mu.cache_create_tokens), 0) AS cache_create_tokens,
@@ -1649,12 +1666,12 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1649
1666
  FROM message_usage mu
1650
1667
  JOIN sessions s ON s.id = mu.session_id
1651
1668
  WHERE s.project_id = ?
1652
- GROUP BY mu.model`).all(n.id),r=ci(s),o=t.prepare(`SELECT COALESCE(SUM(total_input_tokens), 0) AS input_tokens,
1669
+ GROUP BY mu.model`).all(n.id),r=di(s),o=t.prepare(`SELECT COALESCE(SUM(total_input_tokens), 0) AS input_tokens,
1653
1670
  COALESCE(SUM(total_output_tokens), 0) AS output_tokens,
1654
1671
  COALESCE(SUM(total_cache_create_tokens), 0) AS cache_create_tokens,
1655
1672
  COALESCE(SUM(total_cache_read_tokens), 0) AS cache_read_tokens,
1656
1673
  COUNT(*) AS session_count
1657
- FROM sessions WHERE project_id = ?`).get(n.id),a=Ae({inputTokens:o.input_tokens,outputTokens:o.output_tokens,cacheCreateTokens:o.cache_create_tokens,cacheReadTokens:o.cache_read_tokens,...li(r)},null),u=t.prepare(`SELECT s.id, sa.alias, s.started_at,
1674
+ FROM sessions WHERE project_id = ?`).get(n.id),a=Ae({inputTokens:o.input_tokens,outputTokens:o.output_tokens,cacheCreateTokens:o.cache_create_tokens,cacheReadTokens:o.cache_read_tokens,...pi(r)},null),u=t.prepare(`SELECT s.id, sa.alias, s.started_at,
1658
1675
  s.total_input_tokens, s.total_output_tokens,
1659
1676
  s.total_cache_create_tokens, s.total_cache_read_tokens,
1660
1677
  s.primary_model
@@ -1665,7 +1682,7 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1665
1682
  + COALESCE(s.total_output_tokens,0)
1666
1683
  + COALESCE(s.total_cache_create_tokens,0)
1667
1684
  + COALESCE(s.total_cache_read_tokens,0)) DESC
1668
- LIMIT 10`).all(n.id).map(d=>{let m=Ae({inputTokens:d.total_input_tokens??0,outputTokens:d.total_output_tokens??0,cacheCreateTokens:d.total_cache_create_tokens??0,cacheReadTokens:d.total_cache_read_tokens??0},d.primary_model);return{sessionId:d.id,alias:d.alias,startedAt:d.started_at,totalTokens:m.totalTokens,cost:m}});return{project:n.name,sessionCount:o.session_count,inputTokens:o.input_tokens,outputTokens:o.output_tokens,cacheCreateTokens:o.cache_create_tokens,cacheReadTokens:o.cache_read_tokens,totalTokens:a.totalTokens,cost:a,byModel:r,topSessions:u,display:{dollars:Pt(a.cents),tokens:$t(a.totalTokens)}}}function yp(e="all"){let t=f(),n=e==="7d"?new Date(Date.now()-7*864e5).toISOString():e==="30d"?new Date(Date.now()-30*864e5).toISOString():null,s=n?"WHERE mu.timestamp >= @since OR (mu.timestamp IS NULL AND s.started_at >= @since)":"",r=n?"WHERE m.timestamp >= @since OR (m.timestamp IS NULL AND s2.started_at >= @since)":"",o=n?{since:n}:{},a=l=>n?t.prepare(l).get(o):t.prepare(l).get(),c=l=>n?t.prepare(l).all(o):t.prepare(l).all(),u=c(`SELECT mu.model,
1685
+ LIMIT 10`).all(n.id).map(d=>{let m=Ae({inputTokens:d.total_input_tokens??0,outputTokens:d.total_output_tokens??0,cacheCreateTokens:d.total_cache_create_tokens??0,cacheReadTokens:d.total_cache_read_tokens??0},d.primary_model);return{sessionId:d.id,alias:d.alias,startedAt:d.started_at,totalTokens:m.totalTokens,cost:m}});return{project:n.name,sessionCount:o.session_count,inputTokens:o.input_tokens,outputTokens:o.output_tokens,cacheCreateTokens:o.cache_create_tokens,cacheReadTokens:o.cache_read_tokens,totalTokens:a.totalTokens,cost:a,byModel:r,topSessions:u,display:{dollars:Pt(a.cents),tokens:$t(a.totalTokens)}}}function Op(e="all"){let t=f(),n=e==="7d"?new Date(Date.now()-7*864e5).toISOString():e==="30d"?new Date(Date.now()-30*864e5).toISOString():null,s=n?"WHERE mu.timestamp >= @since OR (mu.timestamp IS NULL AND s.started_at >= @since)":"",r=n?"WHERE m.timestamp >= @since OR (m.timestamp IS NULL AND s2.started_at >= @since)":"",o=n?{since:n}:{},a=l=>n?t.prepare(l).get(o):t.prepare(l).get(),c=l=>n?t.prepare(l).all(o):t.prepare(l).all(),u=c(`SELECT mu.model,
1669
1686
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
1670
1687
  COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
1671
1688
  COALESCE(SUM(mu.cache_create_tokens), 0) AS cache_create_tokens,
@@ -1674,7 +1691,7 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1674
1691
  FROM message_usage mu
1675
1692
  JOIN sessions s ON s.id = mu.session_id
1676
1693
  ${s}
1677
- GROUP BY mu.model`),d=ci(u),m=0,h=0,S=0,b=0;for(let l of d)m+=l.inputTokens,h+=l.outputTokens,S+=l.cacheCreateTokens,b+=l.cacheReadTokens;let T=Ae({inputTokens:m,outputTokens:h,cacheCreateTokens:S,cacheReadTokens:b,...li(d)},null),R=n?a(`SELECT
1694
+ GROUP BY mu.model`),d=di(u),m=0,h=0,b=0,S=0;for(let l of d)m+=l.inputTokens,h+=l.outputTokens,b+=l.cacheCreateTokens,S+=l.cacheReadTokens;let T=Ae({inputTokens:m,outputTokens:h,cacheCreateTokens:b,cacheReadTokens:S,...pi(d)},null),R=n?a(`SELECT
1678
1695
  (SELECT COUNT(DISTINCT m.session_id)
1679
1696
  FROM messages m
1680
1697
  JOIN sessions s2 ON s2.id = m.session_id
@@ -1688,7 +1705,7 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1688
1705
  WHERE (COALESCE(total_input_tokens,0)
1689
1706
  +COALESCE(total_output_tokens,0)
1690
1707
  +COALESCE(total_cache_create_tokens,0)
1691
- +COALESCE(total_cache_read_tokens,0)) > 0) AS sessions_with_usage`).get(),w=c(`SELECT substr(datetime(COALESCE(mu.timestamp, s.started_at, ''), 'localtime'), 1, 10) AS day,
1708
+ +COALESCE(total_cache_read_tokens,0)) > 0) AS sessions_with_usage`).get(),O=c(`SELECT substr(datetime(COALESCE(mu.timestamp, s.started_at, ''), 'localtime'), 1, 10) AS day,
1692
1709
  mu.model,
1693
1710
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
1694
1711
  COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
@@ -1698,7 +1715,7 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1698
1715
  JOIN sessions s ON s.id = mu.session_id
1699
1716
  ${s}
1700
1717
  GROUP BY day, mu.model
1701
- ORDER BY day ASC`),j=new Map;for(let l of w){if(!l.day)continue;let p=Ae({inputTokens:l.input_tokens,outputTokens:l.output_tokens,cacheCreateTokens:l.cache_create_tokens,cacheReadTokens:l.cache_read_tokens},l.model),g=j.get(l.day)??{tokens:0,cents:0};g.tokens+=p.totalTokens,g.cents+=p.cents,j.set(l.day,g)}let M=[...j.entries()].map(([l,p])=>({day:l,tokens:p.tokens,cents:p.cents})).sort((l,p)=>l.day.localeCompare(p.day)),x=c(`SELECT s.id, p.name AS project, sa.alias, s.started_at,
1718
+ ORDER BY day ASC`),L=new Map;for(let l of O){if(!l.day)continue;let p=Ae({inputTokens:l.input_tokens,outputTokens:l.output_tokens,cacheCreateTokens:l.cache_create_tokens,cacheReadTokens:l.cache_read_tokens},l.model),g=L.get(l.day)??{tokens:0,cents:0};g.tokens+=p.totalTokens,g.cents+=p.cents,L.set(l.day,g)}let x=[...L.entries()].map(([l,p])=>({day:l,tokens:p.tokens,cents:p.cents})).sort((l,p)=>l.day.localeCompare(p.day)),A=c(`SELECT s.id, p.name AS project, sa.alias, s.started_at,
1702
1719
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
1703
1720
  COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
1704
1721
  COALESCE(SUM(mu.cache_create_tokens), 0) AS cache_create_tokens,
@@ -1714,7 +1731,7 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1714
1731
  + COALESCE(SUM(mu.output_tokens),0)
1715
1732
  + COALESCE(SUM(mu.cache_create_tokens),0)
1716
1733
  + COALESCE(SUM(mu.cache_read_tokens),0)) DESC
1717
- LIMIT 10`).map(l=>{let p=Ae({inputTokens:l.input_tokens,outputTokens:l.output_tokens,cacheCreateTokens:l.cache_create_tokens,cacheReadTokens:l.cache_read_tokens},l.primary_model);return{sessionId:l.id,project:l.project,alias:l.alias,startedAt:l.started_at,totalTokens:p.totalTokens,cost:p}}),P=c(`SELECT p.id AS project_id,
1734
+ LIMIT 10`).map(l=>{let p=Ae({inputTokens:l.input_tokens,outputTokens:l.output_tokens,cacheCreateTokens:l.cache_create_tokens,cacheReadTokens:l.cache_read_tokens},l.primary_model);return{sessionId:l.id,project:l.project,alias:l.alias,startedAt:l.started_at,totalTokens:p.totalTokens,cost:p}}),$=c(`SELECT p.id AS project_id,
1718
1735
  p.name AS project,
1719
1736
  mu.model,
1720
1737
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
@@ -1726,29 +1743,29 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1726
1743
  JOIN sessions s ON s.id = mu.session_id
1727
1744
  LEFT JOIN projects p ON p.id = s.project_id
1728
1745
  ${s}
1729
- GROUP BY p.id, mu.model`),te=new Map;for(let l of P){let p=l.project_id??"__none__",g=te.get(p);g||(g={project:l.project??"(no project)",sessionIds:new Set,sessionsApprox:0,byModel:{}},te.set(p,g)),l.sessions>g.sessionsApprox&&(g.sessionsApprox=l.sessions),g.byModel[l.model??"__unknown__"]={inputTokens:l.input_tokens,outputTokens:l.output_tokens,cacheCreateTokens:l.cache_create_tokens,cacheReadTokens:l.cache_read_tokens}}let B=[...te.values()].map(l=>{let p=0,g=0,_=0,E=0;for(let k of Object.values(l.byModel))p+=k.inputTokens,g+=k.outputTokens,_+=k.cacheCreateTokens,E+=k.cacheReadTokens;let y=Ae({inputTokens:p,outputTokens:g,cacheCreateTokens:_,cacheReadTokens:E,byModel:l.byModel},null);return{project:l.project,sessions:l.sessionsApprox,totalTokens:y.totalTokens,cost:y}});B.sort((l,p)=>p.totalTokens-l.totalTokens);let se=B.slice(0,20),i=t.prepare(`SELECT
1746
+ GROUP BY p.id, mu.model`),te=new Map;for(let l of $){let p=l.project_id??"__none__",g=te.get(p);g||(g={project:l.project??"(no project)",sessionIds:new Set,sessionsApprox:0,byModel:{}},te.set(p,g)),l.sessions>g.sessionsApprox&&(g.sessionsApprox=l.sessions),g.byModel[l.model??"__unknown__"]={inputTokens:l.input_tokens,outputTokens:l.output_tokens,cacheCreateTokens:l.cache_create_tokens,cacheReadTokens:l.cache_read_tokens}}let H=[...te.values()].map(l=>{let p=0,g=0,_=0,E=0;for(let w of Object.values(l.byModel))p+=w.inputTokens,g+=w.outputTokens,_+=w.cacheCreateTokens,E+=w.cacheReadTokens;let y=Ae({inputTokens:p,outputTokens:g,cacheCreateTokens:_,cacheReadTokens:E,byModel:l.byModel},null);return{project:l.project,sessions:l.sessionsApprox,totalTokens:y.totalTokens,cost:y}});H.sort((l,p)=>p.totalTokens-l.totalTokens);let se=H.slice(0,20),i=t.prepare(`SELECT
1730
1747
  (SELECT COUNT(*) FROM messages WHERE role='assistant') AS assistant_messages,
1731
- (SELECT COUNT(*) FROM message_usage) AS messages_with_usage`).get();return{range:e,totalSessions:R.total_sessions,sessionsWithUsage:R.sessions_with_usage,inputTokens:m,outputTokens:h,cacheCreateTokens:S,cacheReadTokens:b,totalTokens:T.totalTokens,cost:T,daily:M,byModel:d,topSessions:x,topRepos:se,backfill:{assistantMessages:i.assistant_messages,messagesWithUsage:i.messages_with_usage,pending:Math.max(0,i.assistant_messages-i.messages_with_usage),unrecoverable:Math.min(gp(),Math.max(0,i.assistant_messages-i.messages_with_usage))},display:{dollars:Pt(T.cents),tokens:$t(T.totalTokens)}}}U();function yn(e){return Math.max(0,Math.min(1,e))}function ui(e){let t=f(),n=t.prepare("SELECT id, name FROM projects WHERE id = ?").get(e);if(!n)return null;let s=t.prepare(`SELECT COUNT(*) AS cnt,
1748
+ (SELECT COUNT(*) FROM message_usage) AS messages_with_usage`).get();return{range:e,totalSessions:R.total_sessions,sessionsWithUsage:R.sessions_with_usage,inputTokens:m,outputTokens:h,cacheCreateTokens:b,cacheReadTokens:S,totalTokens:T.totalTokens,cost:T,daily:x,byModel:d,topSessions:A,topRepos:se,backfill:{assistantMessages:i.assistant_messages,messagesWithUsage:i.messages_with_usage,pending:Math.max(0,i.assistant_messages-i.messages_with_usage),unrecoverable:Math.min(Tp(),Math.max(0,i.assistant_messages-i.messages_with_usage))},display:{dollars:Pt(T.cents),tokens:$t(T.totalTokens)}}}B();function yn(e){return Math.max(0,Math.min(1,e))}function mi(e){let t=f(),n=t.prepare("SELECT id, name FROM projects WHERE id = ?").get(e);if(!n)return null;let s=t.prepare(`SELECT COUNT(*) AS cnt,
1732
1749
  MAX(started_at) AS latest
1733
1750
  FROM sessions WHERE project_id = ?`).get(e),r=s.cnt;if(r===0)return{projectId:e,projectName:n.name,score:0,breakdown:{sessionCount:{raw:0,score:0,weight:.2},recency:{daysSinceLastSession:1/0,score:0,weight:.25},fragmentation:{avgMessages:0,score:0,weight:.15},searchCoverage:{ratio:0,score:0,weight:.2},tagCoverage:{ratio:0,score:0,weight:.2}}};let o=yn(r/10),a=s.latest?(Date.now()-new Date(s.latest).getTime())/(1e3*60*60*24):90,c=yn(1-a/90),d=t.prepare(`SELECT AVG(message_count) AS avg_msgs
1734
1751
  FROM sessions WHERE project_id = ?`).get(e).avg_msgs??0,m=yn((d-2)/3),h=t.prepare(`SELECT COUNT(*) AS total,
1735
1752
  SUM(CASE WHEN m.content_text IS NOT NULL AND m.content_text != '' THEN 1 ELSE 0 END) AS covered
1736
1753
  FROM messages m
1737
1754
  JOIN sessions s ON s.id = m.session_id
1738
- WHERE s.project_id = ?`).get(e),S=h.total>0?h.covered/h.total:.5,b=yn(S),T=t.prepare(`SELECT COUNT(DISTINCT s.id) AS total,
1755
+ WHERE s.project_id = ?`).get(e),b=h.total>0?h.covered/h.total:.5,S=yn(b),T=t.prepare(`SELECT COUNT(DISTINCT s.id) AS total,
1739
1756
  COUNT(DISTINCT st.session_id) AS tagged
1740
1757
  FROM sessions s
1741
1758
  LEFT JOIN session_tags st ON st.session_id = s.id
1742
- WHERE s.project_id = ?`).get(e),R=T.total>0?T.tagged/T.total:0,w=yn(R),j=Math.round((o*.2+c*.25+m*.15+b*.2+w*.2)*100);return{projectId:e,projectName:n.name,score:j,breakdown:{sessionCount:{raw:r,score:o,weight:.2},recency:{daysSinceLastSession:Math.round(a),score:c,weight:.25},fragmentation:{avgMessages:Math.round(d*10)/10,score:m,weight:.15},searchCoverage:{ratio:Math.round(S*100)/100,score:b,weight:.2},tagCoverage:{ratio:Math.round(R*100)/100,score:w,weight:.2}}}}function wp(){let t=f().prepare("SELECT id FROM projects ORDER BY name").all(),n=[];for(let s of t){let r=ui(s.id);r&&n.push(r)}return n}U();import{execFile as xy}from"node:child_process";import{promisify as Ny}from"node:util";import{stat as Oy}from"node:fs/promises";var Ly=Ny(xy),Cy=60,vy=7,Iy=7,jy=5e3;function My(){let e=f(),t=n=>{try{return!!e.prepare(n).get()}catch{return!1}};return{semantic:t("SELECT 1 FROM session_semantic LIMIT 1"),cost:t(`SELECT 1 FROM sessions
1759
+ WHERE s.project_id = ?`).get(e),R=T.total>0?T.tagged/T.total:0,O=yn(R),L=Math.round((o*.2+c*.25+m*.15+S*.2+O*.2)*100);return{projectId:e,projectName:n.name,score:L,breakdown:{sessionCount:{raw:r,score:o,weight:.2},recency:{daysSinceLastSession:Math.round(a),score:c,weight:.25},fragmentation:{avgMessages:Math.round(d*10)/10,score:m,weight:.15},searchCoverage:{ratio:Math.round(b*100)/100,score:S,weight:.2},tagCoverage:{ratio:Math.round(R*100)/100,score:O,weight:.2}}}}function Lp(){let t=f().prepare("SELECT id FROM projects ORDER BY name").all(),n=[];for(let s of t){let r=mi(s.id);r&&n.push(r)}return n}B();import{execFile as Wy}from"node:child_process";import{promisify as qy}from"node:util";import{stat as Xy}from"node:fs/promises";var Jy=qy(Wy),Gy=60,Yy=7,zy=7,Ky=5e3;function Vy(){let e=f(),t=n=>{try{return!!e.prepare(n).get()}catch{return!1}};return{semantic:t("SELECT 1 FROM session_semantic LIMIT 1"),cost:t(`SELECT 1 FROM sessions
1743
1760
  WHERE (COALESCE(total_input_tokens,0)
1744
1761
  + COALESCE(total_output_tokens,0)
1745
1762
  + COALESCE(total_cache_create_tokens,0)
1746
1763
  + COALESCE(total_cache_read_tokens,0)) > 0
1747
- LIMIT 1`),git:t("SELECT 1 FROM session_commits LIMIT 1")}}function di(e){if(!e)return[];let t=new Set,n=[];for(let s of e.split(",")){let r=s.trim().toLowerCase();!r||t.has(r)||(t.add(r),n.push(r))}return n}function Rp(e){return{sessionId:e.session_id,project:e.project,alias:e.alias,startedAt:e.started_at,endedAt:e.ended_at,firstUserMessage:e.first_user_message}}function Dy(){let e=f(),t=e.prepare(`SELECT ss.keywords
1764
+ LIMIT 1`),git:t("SELECT 1 FROM session_commits LIMIT 1")}}function gi(e){if(!e)return[];let t=new Set,n=[];for(let s of e.split(",")){let r=s.trim().toLowerCase();!r||t.has(r)||(t.add(r),n.push(r))}return n}function Cp(e){return{sessionId:e.session_id,project:e.project,alias:e.alias,startedAt:e.started_at,endedAt:e.ended_at,firstUserMessage:e.first_user_message}}function Zy(){let e=f(),t=e.prepare(`SELECT ss.keywords
1748
1765
  FROM session_semantic ss
1749
1766
  JOIN sessions s ON s.id = ss.session_id
1750
1767
  WHERE s.started_at IS NOT NULL
1751
- AND julianday('now') - julianday(s.started_at) <= @windowDays`).all({windowDays:vy});if(t.length===0)return null;let n=new Set;for(let o of t)for(let a of di(o.keywords))n.add(a);if(n.size===0)return null;let s=e.prepare(`SELECT ss.session_id AS session_id,
1768
+ AND julianday('now') - julianday(s.started_at) <= @windowDays`).all({windowDays:Yy});if(t.length===0)return null;let n=new Set;for(let o of t)for(let a of gi(o.keywords))n.add(a);if(n.size===0)return null;let s=e.prepare(`SELECT ss.session_id AS session_id,
1752
1769
  ss.summary AS summary,
1753
1770
  ss.keywords AS keywords,
1754
1771
  p.name AS project,
@@ -1764,7 +1781,7 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1764
1781
  WHERE s.started_at IS NOT NULL
1765
1782
  AND s.message_count > 2
1766
1783
  AND julianday('now') - julianday(s.started_at) >= @ageDays
1767
- ORDER BY s.started_at ASC`).all({ageDays:Cy});if(s.length===0)return null;let r=null;for(let o of s){let c=di(o.keywords).filter(u=>n.has(u));c.length!==0&&(!r||c.length>r.overlap.length)&&(r={row:o,overlap:c})}return r?{...Rp(r.row),summary:r.row.summary,keywords:di(r.row.keywords),matchedKeywords:r.overlap,daysAgo:Math.max(0,Math.round(r.row.days_old))}:null}function Fy(){let t=f().prepare(`SELECT s.id AS session_id,
1784
+ ORDER BY s.started_at ASC`).all({ageDays:Gy});if(s.length===0)return null;let r=null;for(let o of s){let c=gi(o.keywords).filter(u=>n.has(u));c.length!==0&&(!r||c.length>r.overlap.length)&&(r={row:o,overlap:c})}return r?{...Cp(r.row),summary:r.row.summary,keywords:gi(r.row.keywords),matchedKeywords:r.overlap,daysAgo:Math.max(0,Math.round(r.row.days_old))}:null}function Qy(){let t=f().prepare(`SELECT s.id AS session_id,
1768
1785
  p.name AS project,
1769
1786
  NULLIF(sa.alias, '') AS alias,
1770
1787
  s.started_at AS started_at,
@@ -1783,28 +1800,25 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1783
1800
  AND (COALESCE(s.total_input_tokens, 0)
1784
1801
  + COALESCE(s.total_output_tokens, 0)
1785
1802
  + COALESCE(s.total_cache_create_tokens, 0)
1786
- + COALESCE(s.total_cache_read_tokens, 0)) > 0`).all({windowDays:Iy});if(t.length===0)return null;let n=null;for(let s of t){let r=Ae({inputTokens:s.input_tokens,outputTokens:s.output_tokens,cacheCreateTokens:s.cache_create_tokens,cacheReadTokens:s.cache_read_tokens},s.primary_model);r.cents<=0||(!n||r.cents>n.cents)&&(n={row:s,cents:r.cents,totalTokens:r.totalTokens})}return n?{...Rp(n.row),totalTokens:n.totalTokens,costCents:n.cents,costDisplay:Pt(n.cents),tokensDisplay:$t(n.totalTokens),primaryModel:n.row.primary_model,primaryModelLabel:Je(n.row.primary_model).label}:null}async function Py(e){try{if(!(await Oy(e)).isDirectory())return null}catch{return null}try{let{stdout:t}=await Ly("git",["rev-parse","HEAD"],{cwd:e,timeout:jy}),n=t.trim();return/^[0-9a-f]{40}$/.test(n)?n:null}catch{return null}}async function $y(){let e=f(),t=e.prepare(`SELECT s.id AS id, s.cwd AS cwd
1803
+ + COALESCE(s.total_cache_read_tokens, 0)) > 0`).all({windowDays:zy});if(t.length===0)return null;let n=null;for(let s of t){let r=Ae({inputTokens:s.input_tokens,outputTokens:s.output_tokens,cacheCreateTokens:s.cache_create_tokens,cacheReadTokens:s.cache_read_tokens},s.primary_model);r.cents<=0||(!n||r.cents>n.cents)&&(n={row:s,cents:r.cents,totalTokens:r.totalTokens})}return n?{...Cp(n.row),totalTokens:n.totalTokens,costCents:n.cents,costDisplay:Pt(n.cents),tokensDisplay:$t(n.totalTokens),primaryModel:n.row.primary_model,primaryModelLabel:Je(n.row.primary_model).label}:null}async function ew(e){try{if(!(await Xy(e)).isDirectory())return null}catch{return null}try{let{stdout:t}=await Jy("git",["rev-parse","HEAD"],{cwd:e,timeout:Ky}),n=t.trim();return/^[0-9a-f]{40}$/.test(n)?n:null}catch{return null}}async function tw(){let e=f(),t=e.prepare(`SELECT s.id AS id, s.cwd AS cwd
1787
1804
  FROM sessions s
1788
1805
  WHERE s.cwd IS NOT NULL AND s.started_at IS NOT NULL
1789
1806
  ORDER BY COALESCE(s.ended_at, s.started_at, '') DESC
1790
- LIMIT 1`).get();if(!t?.cwd)return null;let n=await Py(t.cwd);if(!n)return null;let s=os(n);if(s.length===0)return null;let r=s[0],o=e.prepare(`SELECT s.first_user_message AS first_user_message, s.ended_at AS ended_at
1807
+ LIMIT 1`).get();if(!t?.cwd)return null;let n=await ew(t.cwd);if(!n)return null;let s=is(n);if(s.length===0)return null;let r=s[0],o=e.prepare(`SELECT s.first_user_message AS first_user_message, s.ended_at AS ended_at
1791
1808
  FROM sessions s
1792
- WHERE s.id = ?`).get(r.sessionId);return{sessionId:r.sessionId,project:r.project,alias:r.alias,startedAt:r.startedAt,endedAt:o?.ended_at??r.endedAt,firstUserMessage:o?.first_user_message??null,commitSha:r.commitSha,shortSha:r.commitSha.slice(0,7),subject:r.subject,committedAt:r.committedAt,cwd:t.cwd}}async function kp(){let e=My(),t=e.semantic?Promise.resolve().then(()=>{try{return Dy()}catch(c){return console.error("[discover.rediscovered]",c),null}}):Promise.resolve(null),n=e.cost?Promise.resolve().then(()=>{try{return Fy()}catch(c){return console.error("[discover.expensive]",c),null}}):Promise.resolve(null),s=e.git?$y().catch(c=>(console.error("[discover.authored]",c),null)):Promise.resolve(null),[r,o,a]=await Promise.all([t,n,s]);return{rediscovered:r,expensive:o,authored:a,availability:e,generatedAt:new Date().toISOString()}}Ve();U();Ve();async function Ap(e,t=50){let n=await dr(e),s=f(),r=Buffer.from(n.buffer,n.byteOffset,n.byteLength);return s.prepare(`SELECT v.rowid, v.distance, cm.session_id, cm.text, cm.message_uuids
1793
- FROM vec_chunks v JOIN chunk_meta cm ON cm.rowid = v.rowid
1794
- WHERE v.embedding MATCH ? AND k = ? ORDER BY v.distance`).all(r,t).map(a=>({sessionId:a.session_id,chunkRowid:a.rowid,distance:a.distance,text:a.text,messageUuids:JSON.parse(a.message_uuids)}))}async function xp(e,t=10,n=.65){let s=f(),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 a=s.prepare(`SELECT v.rowid, v.distance, cm.session_id FROM vec_chunks v JOIN chunk_meta cm ON cm.rowid = v.rowid
1795
- WHERE v.embedding MATCH ? AND k = ? ORDER BY v.distance`).all(o.embedding,t*5),c=new Map;for(let d of a){if(d.session_id===e)continue;let m=c.get(d.session_id);(m===void 0||d.distance<m)&&c.set(d.session_id,d.distance)}let u=[];for(let[d,m]of c){let h=1-m;h>=n&&u.push({sessionId:d,similarity:h})}return u.sort((d,m)=>m.similarity-d.similarity),u.slice(0,t)}function Uy(){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 Np(e){let t=Uy(),n=new Map;for(let r of e)for(let o=0;o<r.length;o++){let a=r[o],c=1/(t+o+1),u=n.get(a.id);u?(u.score+=c,u.lanes.push(a.lane),o+1<u.bestRank&&(u.bestRank=o+1,u.bestData=a.data)):n.set(a.id,{score:c,lanes:[a.lane],bestRank:o+1,bestData:a.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}U();Ve();U();function Op(e){return e.replace(/```json[\s\S]*?```/g,"[tool-call]").replace(/\{[\s\S]{200,}?\}/g,"[json-object]")}function By(e){let t=[],o=0;for(;o<e.length;){let a=[],c=0;for(;a.length<5&&o<e.length;){let d=e[o],m=Op(d.content_text??"");if(c+m.length>2e3&&a.length>=3)break;a.push(d),c+=m.length,o++}if(a.length===0)break;let u=a.map(d=>{let m=d.role??"system",h=Op(d.content_text??"");return`[${m}] ${h}`}).join(`
1809
+ WHERE s.id = ?`).get(r.sessionId);return{sessionId:r.sessionId,project:r.project,alias:r.alias,startedAt:r.startedAt,endedAt:o?.ended_at??r.endedAt,firstUserMessage:o?.first_user_message??null,commitSha:r.commitSha,shortSha:r.commitSha.slice(0,7),subject:r.subject,committedAt:r.committedAt,cwd:t.cwd}}async function vp(){let e=Vy(),t=e.semantic?Promise.resolve().then(()=>{try{return Zy()}catch(c){return console.error("[discover.rediscovered]",c),null}}):Promise.resolve(null),n=e.cost?Promise.resolve().then(()=>{try{return Qy()}catch(c){return console.error("[discover.expensive]",c),null}}):Promise.resolve(null),s=e.git?tw().catch(c=>(console.error("[discover.authored]",c),null)):Promise.resolve(null),[r,o,a]=await Promise.all([t,n,s]);return{rediscovered:r,expensive:o,authored:a,availability:e,generatedAt:new Date().toISOString()}}ct();B();var _i=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 fi(e,t={}){let n=t.limit??nw()??75e3,r=e.prepare("SELECT COUNT(*) AS n FROM vec_chunks").get()?.n??0;if(r>n)throw new _i(r,n)}function nw(){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)}ur();import{Worker as sw}from"node:worker_threads";import{join as rw}from"node:path";var hi=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"},ow=1e4;function iw(){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 Ei(e){let t=e.timeoutMs??iw()??ow,n=(e.workerFactory??aw)();return new Promise((s,r)=>{let o=setTimeout(()=>{n.terminate().catch(()=>{}),r(new hi(t))},t);n.once("message",a=>{clearTimeout(o);let c=a;c&&c.ok===!0&&Array.isArray(c.hits)?s(c.hits):r(new Error(c?.error??"worker returned malformed reply")),n.terminate().catch(()=>{})}),n.once("error",a=>{clearTimeout(o),n.terminate().catch(()=>{}),r(a)}),n.postMessage({query:e.query,precomputedVector:e.precomputedVector,limit:e.limit})})}function aw(){let e=rw(Ln(),"dist","daemon","query-worker.js");return new sw(e)}async function Ip(e,t=50){return fi(f()),Ei({query:e,limit:t})}async function jp(e,t=10,n=.65){let s=f();fi(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 a=await Ei({precomputedVector:o.embedding,limit:t*5}),c=new Map;for(let d of a){if(d.sessionId===e)continue;let m=c.get(d.sessionId);(m===void 0||d.distance<m)&&c.set(d.sessionId,d.distance)}let u=[];for(let[d,m]of c){let h=1-m;h>=n&&u.push({sessionId:d,similarity:h})}return u.sort((d,m)=>m.similarity-d.similarity),u.slice(0,t)}function cw(){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 Mp(e){let t=cw(),n=new Map;for(let r of e)for(let o=0;o<r.length;o++){let a=r[o],c=1/(t+o+1),u=n.get(a.id);u?(u.score+=c,u.lanes.push(a.lane),o+1<u.bestRank&&(u.bestRank=o+1,u.bestData=a.data)):n.set(a.id,{score:c,lanes:[a.lane],bestRank:o+1,bestData:a.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}B();ct();B();function Dp(e){return e.replace(/```json[\s\S]*?```/g,"[tool-call]").replace(/\{[\s\S]{200,}?\}/g,"[json-object]")}function lw(e){let t=[],o=0;for(;o<e.length;){let a=[],c=0;for(;a.length<5&&o<e.length;){let d=e[o],m=Dp(d.content_text??"");if(c+m.length>2e3&&a.length>=3)break;a.push(d),c+=m.length,o++}if(a.length===0)break;let u=a.map(d=>{let m=d.role??"system",h=Dp(d.content_text??"");return`[${m}] ${h}`}).join(`
1796
1810
 
1797
- `);t.push({messageUuids:a.map(d=>d.uuid),text:u}),o<e.length&&a.length>=3&&(o=Math.max(o-1,o-1))}return t}function Lp(e){let n=f().prepare("SELECT uuid, role, content_text FROM messages WHERE session_id = ? AND is_sidechain = 0 AND content_text IS NOT NULL ORDER BY rowid").all(e);return By(n)}var Mp=2e3,Hy=1e4,at=null,Vs=!1,Dp=null,pi=0;function Fp(e){pi=Math.max(0,Math.floor(e))}var ve=new Set,Pp=-1;function $p(e){ve.add(e)}function Up(){ve.add(Pp)}function Cp(e){if(ve.has(Pp))return!0;if(ve.size===0)return!1;let t=f().prepare("SELECT project_id FROM sessions WHERE id = ?").get(e);return t?ve.has(t.project_id):!1}var vp=10,Wy=200,qy=2e3;function Xy(){let e=Number(process.env.RECALL_VECTOR_HARD_CAP??"");return Number.isFinite(e)&&e>0?Math.min(qy,Math.floor(e)):Wy}var Jy=3,Ip=1e3,wn=new Map,mi=new Set;function jp(e,t,n,s){if(e.size>=Ip&&(e instanceof Map,!e.has(t))){let r=e.keys().next();r.done||(e.delete(r.value),console.warn(`[vector-worker] ${s??"tracking-map"} hit ${Ip}-entry cap; evicted oldest entry`))}e instanceof Map?e.set(t,n):e.add(t)}var Rn=[],Yy=50;function gi(){if(Rn.length<8)return null;let e=Rn.slice(-30),t=e.reduce((s,r)=>s+r.chunks,0),n=e.reduce((s,r)=>s+r.durationMs,0);return n<=0||t===0?null:{samples:e.length,chunksPerSec:t/(n/1e3),sessionsPerSec:e.length/(n/1e3),avgChunksPerSession:t/e.length}}function Gy(){return f().prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}async function zy(){let e=f(),t=e.prepare("SELECT DISTINCT session_id FROM chunk_queue ORDER BY id LIMIT 1").get();if(!t)return ve.size>0&&ve.clear(),!1;if(Cp(t.session_id)||mi.has(t.session_id))return e.prepare("DELETE FROM chunk_queue WHERE session_id = ?").run(t.session_id),!0;let n=t.session_id,s=Date.now();try{e.prepare("DELETE FROM vec_chunks WHERE rowid IN (SELECT rowid FROM chunk_meta WHERE session_id = ?)").run(n),e.prepare("DELETE FROM chunk_meta WHERE session_id = ?").run(n);let r=Lp(n),o=pi>0?pi:1/0,a=Math.min(o,Xy()),c=a<r.length?r.slice(0,a):r;if(c.length===0)return e.prepare("DELETE FROM chunk_queue WHERE session_id = ?").run(n),!0;let u=e.prepare("INSERT INTO chunk_meta(session_id, message_uuids, text, embedding_model_id, embedding_dim, stale, generated_at) VALUES (?, ?, ?, 'bge-base-en-v1.5', 768, 0, datetime('now'))"),d=e.prepare("INSERT INTO vec_chunks(rowid, embedding) VALUES (?, ?)"),m=0,h=!1;for(let S=0;S<c.length;S+=vp){if(Cp(n)){h=!0;break}let b=Math.min(c.length,S+vp),T=c.slice(S,b),R=T.map(M=>M.text),w=await ct(R);e.transaction(()=>{for(let M=0;M<T.length;M++){let W=u.run(n,JSON.stringify(T[M].messageUuids),T[M].text),x=Buffer.from(w[M].buffer,w[M].byteOffset,w[M].byteLength);d.run(BigInt(W.lastInsertRowid),x)}})(),m+=T.length,await new Promise(M=>setImmediate(M))}h&&(e.prepare("DELETE FROM vec_chunks WHERE rowid IN (SELECT rowid FROM chunk_meta WHERE session_id = ?)").run(n),e.prepare("DELETE FROM chunk_meta WHERE session_id = ?").run(n)),e.prepare("DELETE FROM chunk_queue WHERE session_id = ?").run(n),Dp=new Date().toISOString(),Rn.push({ts:Date.now(),chunks:m,durationMs:Date.now()-s}),Rn.length>Yy&&Rn.shift(),wn.has(n)&&wn.delete(n)}catch(r){console.error("[vector-worker] failed for session",n,r);let o=(wn.get(n)??0)+1;jp(wn,n,o,"failureCounts"),o>=Jy&&(jp(mi,n,void 0,"blacklist"),wn.delete(n),console.error(`[vector-worker] blacklisted session ${n} after ${o} failures \u2014 will not retry until daemon restart`)),e.prepare("DELETE FROM chunk_queue WHERE session_id = ?").run(n)}finally{if(ve.size>0)try{let r=e.prepare("SELECT project_id FROM sessions WHERE id = ?").get(n);r!==void 0&&ve.has(r.project_id)&&(e.prepare("SELECT 1 FROM chunk_queue cq JOIN sessions s ON s.id = cq.session_id WHERE s.project_id = ? LIMIT 1").get(r.project_id)||ve.delete(r.project_id))}catch(r){console.error("[vector-worker] cancelledProjects cleanup failed:",r)}}return!0}async function Bp(){if(!_e().loaded)return;let e=await zy();at!==null&&clearTimeout(at),at=setTimeout(()=>{Bp()},e?Mp:Hy)}function kn(){if(!Vs){if(!_e().loaded){console.error("[vector-worker] cannot start: embedder not loaded");return}Vs=!0,at=setTimeout(()=>{Bp()},Mp)}}function Hp(){Vs=!1,at!==null&&(clearTimeout(at),at=null)}function Ie(){return{running:Vs,queueDepth:Gy(),lastProcessedAt:Dp,blacklistedCount:mi.size}}ee();import{existsSync as Xp,mkdirSync as Wp,rmSync as qp,createWriteStream as Ky,statSync as Vy}from"node:fs";import{join as Zs}from"node:path";import{createHash as Zy}from"node:crypto";import{readFile as Qy}from"node:fs/promises";var ew="https://huggingface.co/BAAI/bge-base-en-v1.5/resolve/main/",Jp=[{path:"config.json",sha256:"bc00af31a4a31b74040d73370aa83b62da34c90b75eb77bfa7db039d90abd591"},{path:"tokenizer.json",sha256:"d241a60d5e8f04cc1b2b3e9ef7a4921b27bf526d9f6050ab90f9267a1f9e5c66"},{path:"tokenizer_config.json",sha256:"9261e7d79b44c8195c1cada2b453e55b00aeb81e907a6664974b4d7776172ab3"},{path:"onnx/model.onnx",sha256:"9bc579acdba21c253c62a9bf866891355a63ffa3442b52c8a37d75b2ccb91848"}];function Yp(){return Zs(H,"models","BAAI","bge-base-en-v1.5")}function Ye(){let e=Yp();return Jp.every(t=>Xp(Zs(e,t.path)))}async function Gp(e){let t=Yp();Wp(t,{recursive:!0}),Wp(Zs(t,"onnx"),{recursive:!0});for(let n of Jp){let s=Zs(t,n.path),r=ew+n.path,o=0;Xp(s)&&(o=Vy(s).size);let a={};o>0&&(a.Range=`bytes=${o}-`);let c=await fetch(r,{headers:a});if(!c.ok&&c.status!==206)throw new Error(`Failed to download ${n.path}: HTTP ${c.status}`);let u=c.headers.get("content-length"),d=u?o+Number(u):0,m=c.body;if(!m)throw new Error(`No response body for ${n.path}`);let h=Ky(s,{flags:o>0?"a":"w"}),S=m.getReader(),b=o;for(;;){let{done:w,value:j}=await S.read();if(w)break;h.write(Buffer.from(j)),b+=j.byteLength,e?.(n.path,b,d)}if(h.end(),await new Promise((w,j)=>{h.on("finish",w),h.on("error",j)}),n.sha256==="TODO_PLACEHOLDER")throw qp(s),new Error(`Refusing to install: SHA-256 not pinned for ${n.path}. Update model-download.ts.`);let T=await Qy(s);if(Zy("sha256").update(T).digest("hex")!==n.sha256)throw qp(s),new Error(`SHA-256 mismatch for ${n.path}`)}}U();var tw=[/\btask\s+complete/i,/\bdone\b/i,/\bfinished\b/i,/\bimplemented\b/i,/\bcompleted\b/i,/\bshipped\b/i,/\ball\s+(?:tests?\s+)?pass/i,/\bsuccessfully\b/i],nw=1440*60*1e3;function sw(e){let t=f(),n=t.prepare(`SELECT content_text, tool_names FROM messages
1811
+ `);t.push({messageUuids:a.map(d=>d.uuid),text:u}),o<e.length&&a.length>=3&&(o=Math.max(o-1,o-1))}return t}function Fp(e){let n=f().prepare("SELECT uuid, role, content_text FROM messages WHERE session_id = ? AND is_sidechain = 0 AND content_text IS NOT NULL ORDER BY rowid").all(e);return lw(n)}var Hp=2e3,uw=1e4,it=null,Zs=!1,Wp=null,bi=0;function qp(e){bi=Math.max(0,Math.floor(e))}var ve=new Set,Xp=-1;function Jp(e){ve.add(e)}function Gp(){ve.add(Xp)}function Pp(e){if(ve.has(Xp))return!0;if(ve.size===0)return!1;let t=f().prepare("SELECT project_id FROM sessions WHERE id = ?").get(e);return t?ve.has(t.project_id):!1}var $p=10,dw=200,pw=2e3;function mw(){let e=Number(process.env.RECALL_VECTOR_HARD_CAP??"");return Number.isFinite(e)&&e>0?Math.min(pw,Math.floor(e)):dw}var gw=3,Up=1e3,wn=new Map,Si=new Set;function Bp(e,t,n,s){if(e.size>=Up&&(e instanceof Map,!e.has(t))){let r=e.keys().next();r.done||(e.delete(r.value),console.warn(`[vector-worker] ${s??"tracking-map"} hit ${Up}-entry cap; evicted oldest entry`))}e instanceof Map?e.set(t,n):e.add(t)}var Rn=[],_w=50;function Ti(){if(Rn.length<8)return null;let e=Rn.slice(-30),t=e.reduce((s,r)=>s+r.chunks,0),n=e.reduce((s,r)=>s+r.durationMs,0);return n<=0||t===0?null:{samples:e.length,chunksPerSec:t/(n/1e3),sessionsPerSec:e.length/(n/1e3),avgChunksPerSession:t/e.length}}function fw(){return f().prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}async function hw(){let e=f(),t=e.prepare("SELECT DISTINCT session_id FROM chunk_queue ORDER BY id LIMIT 1").get();if(!t)return ve.size>0&&ve.clear(),!1;if(Pp(t.session_id)||Si.has(t.session_id))return e.prepare("DELETE FROM chunk_queue WHERE session_id = ?").run(t.session_id),!0;let n=t.session_id,s=Date.now();try{e.prepare("DELETE FROM vec_chunks WHERE rowid IN (SELECT rowid FROM chunk_meta WHERE session_id = ?)").run(n),e.prepare("DELETE FROM chunk_meta WHERE session_id = ?").run(n);let r=Fp(n),o=bi>0?bi:1/0,a=Math.min(o,mw()),c=a<r.length?r.slice(0,a):r;if(c.length===0)return e.prepare("DELETE FROM chunk_queue WHERE session_id = ?").run(n),!0;let u=e.prepare("INSERT INTO chunk_meta(session_id, message_uuids, text, embedding_model_id, embedding_dim, stale, generated_at) VALUES (?, ?, ?, 'bge-base-en-v1.5', 768, 0, datetime('now'))"),d=e.prepare("INSERT INTO vec_chunks(rowid, embedding) VALUES (?, ?)"),m=0,h=!1;for(let b=0;b<c.length;b+=$p){if(Pp(n)){h=!0;break}let S=Math.min(c.length,b+$p),T=c.slice(b,S),R=T.map(x=>x.text),O=await at(R);e.transaction(()=>{for(let x=0;x<T.length;x++){let F=u.run(n,JSON.stringify(T[x].messageUuids),T[x].text),A=Buffer.from(O[x].buffer,O[x].byteOffset,O[x].byteLength);d.run(BigInt(F.lastInsertRowid),A)}})(),m+=T.length,await new Promise(x=>setImmediate(x))}h&&(e.prepare("DELETE FROM vec_chunks WHERE rowid IN (SELECT rowid FROM chunk_meta WHERE session_id = ?)").run(n),e.prepare("DELETE FROM chunk_meta WHERE session_id = ?").run(n)),e.prepare("DELETE FROM chunk_queue WHERE session_id = ?").run(n),Wp=new Date().toISOString(),Rn.push({ts:Date.now(),chunks:m,durationMs:Date.now()-s}),Rn.length>_w&&Rn.shift(),wn.has(n)&&wn.delete(n)}catch(r){console.error("[vector-worker] failed for session",n,r);let o=(wn.get(n)??0)+1;Bp(wn,n,o,"failureCounts"),o>=gw&&(Bp(Si,n,void 0,"blacklist"),wn.delete(n),console.error(`[vector-worker] blacklisted session ${n} after ${o} failures \u2014 will not retry until daemon restart`)),e.prepare("DELETE FROM chunk_queue WHERE session_id = ?").run(n)}finally{if(ve.size>0)try{let r=e.prepare("SELECT project_id FROM sessions WHERE id = ?").get(n);r!==void 0&&ve.has(r.project_id)&&(e.prepare("SELECT 1 FROM chunk_queue cq JOIN sessions s ON s.id = cq.session_id WHERE s.project_id = ? LIMIT 1").get(r.project_id)||ve.delete(r.project_id))}catch(r){console.error("[vector-worker] cancelledProjects cleanup failed:",r)}}return!0}async function Yp(){if(!_e().loaded)return;let e=await hw();it!==null&&clearTimeout(it),it=setTimeout(()=>{Yp()},e?Hp:uw)}function kn(){if(!Zs){if(!_e().loaded){console.error("[vector-worker] cannot start: embedder not loaded");return}Zs=!0,it=setTimeout(()=>{Yp()},Hp)}}function zp(){Zs=!1,it!==null&&(clearTimeout(it),it=null)}function Ie(){return{running:Zs,queueDepth:fw(),lastProcessedAt:Wp,blacklistedCount:Si.size}}ee();import{existsSync as Zp,mkdirSync as Kp,rmSync as Vp,createWriteStream as Ew,statSync as bw}from"node:fs";import{join as Qs}from"node:path";import{createHash as Sw}from"node:crypto";import{readFile as Tw}from"node:fs/promises";var yw="https://huggingface.co/BAAI/bge-base-en-v1.5/resolve/main/",Qp=[{path:"config.json",sha256:"bc00af31a4a31b74040d73370aa83b62da34c90b75eb77bfa7db039d90abd591"},{path:"tokenizer.json",sha256:"d241a60d5e8f04cc1b2b3e9ef7a4921b27bf526d9f6050ab90f9267a1f9e5c66"},{path:"tokenizer_config.json",sha256:"9261e7d79b44c8195c1cada2b453e55b00aeb81e907a6664974b4d7776172ab3"},{path:"onnx/model.onnx",sha256:"9bc579acdba21c253c62a9bf866891355a63ffa3442b52c8a37d75b2ccb91848"}];function em(){return Qs(W,"models","BAAI","bge-base-en-v1.5")}function Ge(){let e=em();return Qp.every(t=>Zp(Qs(e,t.path)))}async function tm(e){let t=em();Kp(t,{recursive:!0}),Kp(Qs(t,"onnx"),{recursive:!0});for(let n of Qp){let s=Qs(t,n.path),r=yw+n.path,o=0;Zp(s)&&(o=bw(s).size);let a={};o>0&&(a.Range=`bytes=${o}-`);let c=await fetch(r,{headers:a});if(!c.ok&&c.status!==206)throw new Error(`Failed to download ${n.path}: HTTP ${c.status}`);let u=c.headers.get("content-length"),d=u?o+Number(u):0,m=c.body;if(!m)throw new Error(`No response body for ${n.path}`);let h=Ew(s,{flags:o>0?"a":"w"}),b=m.getReader(),S=o;for(;;){let{done:O,value:L}=await b.read();if(O)break;h.write(Buffer.from(L)),S+=L.byteLength,e?.(n.path,S,d)}if(h.end(),await new Promise((O,L)=>{h.on("finish",O),h.on("error",L)}),n.sha256==="TODO_PLACEHOLDER")throw Vp(s),new Error(`Refusing to install: SHA-256 not pinned for ${n.path}. Update model-download.ts.`);let T=await Tw(s);if(Sw("sha256").update(T).digest("hex")!==n.sha256)throw Vp(s),new Error(`SHA-256 mismatch for ${n.path}`)}}B();var ww=[/\btask\s+complete/i,/\bdone\b/i,/\bfinished\b/i,/\bimplemented\b/i,/\bcompleted\b/i,/\bshipped\b/i,/\ball\s+(?:tests?\s+)?pass/i,/\bsuccessfully\b/i],Rw=1440*60*1e3;function kw(e){let t=f(),n=t.prepare(`SELECT content_text, tool_names FROM messages
1798
1812
  WHERE session_id = ? AND role = 'assistant'
1799
- ORDER BY timestamp DESC LIMIT 5`).all(e),s=!1;for(let u of n)if(u.content_text&&tw.some(d=>d.test(u.content_text))){s=!0;break}let r=t.prepare(`SELECT content_text, tool_names FROM messages
1800
- WHERE session_id = ?`).all(e),o={fileWrites:!1,testRuns:!1,commits:!1,buildSuccess:!1};for(let u of r){let d=u.tool_names??"",m=u.content_text??"";/\bWrite\b|\bEdit\b/.test(d)&&(o.fileWrites=!0),/\b(?:jest|pytest|vitest|mocha|test|spec)\b/i.test(m)&&/pass|ok|✓/i.test(m)&&(o.testRuns=!0),/\bgit\s+commit\b/i.test(m)&&(o.commits=!0),(/\bbuild\s+(?:succeeded|success|passed)\b/i.test(m)||/tsc.*(?:0 errors|no errors)/i.test(m))&&(o.buildSuccess=!0)}return s?{status:[o.fileWrites,o.testRuns,o.commits,o.buildSuccess].filter(Boolean).length>=2?"verified":"unverified",evidence:o,claimFound:s}:{status:"neutral",evidence:o,claimFound:s}}function rw(e){let t=sw(e);return f().prepare("UPDATE sessions SET verification_status = ?, verification_computed_at = ? WHERE id = ?").run(t.status,Date.now(),e),t}function zp(e){let n=f().prepare("SELECT verification_status, verification_computed_at FROM sessions WHERE id = ?").get(e);if(n?.verification_status&&n.verification_computed_at&&Date.now()-n.verification_computed_at<nw){let s={fileWrites:!1,testRuns:!1,commits:!1,buildSuccess:!1};return{status:n.verification_status,evidence:s,claimFound:n.verification_status!=="neutral"}}return rw(e)}import{readFileSync as ow,writeFileSync as iw,mkdirSync as aw,chmodSync as cw}from"node:fs";import{join as Kp}from"node:path";import{homedir as Vp}from"node:os";function Zp(){return Kp(Vp(),".recall","config.json")}function Qp(){try{return JSON.parse(ow(Zp(),"utf-8"))}catch{return{}}}function lw(e){let t=Zp();aw(Kp(Vp(),".recall"),{recursive:!0}),iw(t,JSON.stringify(e,null,2)+`
1801
- `,"utf-8"),cw(t,384)}function _i(){let t=Qp().verification;return typeof t=="object"&&t!==null&&"enabled"in t?!!t.enabled:!1}function em(e){let t=Qp();t.verification={...typeof t.verification=="object"&&t.verification!==null?t.verification:{},enabled:e},lw(t)}var Ew=5e3,wi={scanned:0,linked:0,renamed:0,skipped_manual:0,ambiguous_cwd:0},fi=0,hi=wi,Ei=null;async function bw(){return Date.now()-fi>=Ew&&!Ei&&(Ei=ss().then(n=>(hi=n,fi=Date.now(),n)).catch(()=>(fi=Date.now(),hi=wi,wi)).finally(()=>{Ei=null})),hi}var Sw=2e3,Tw=6,tr=new Map;function An(e){return e.replace(/[\\%_]/g,t=>"\\"+t)}function yw(e,t){let n=Date.now(),s=(tr.get(e)??[]).filter(a=>n-a.ts<Sw);return tr.set(e,s),s.length<2||s[s.length-1].name===t?!1:s.slice(0,-1).some(a=>a.name===t)}function ww(e,t){let n=tr.get(e)??[];for(n.push({name:t,ts:Date.now()});n.length>Tw;)n.shift();tr.set(e,n)}function nm(e,t){let n=t.trim();if(!n)return 0;if(le(n)){let o=bt(n);if(!o)return 0;n=o}if(de(n))return 0;if(yw(e,n))return console.log(`[terminal] dropping rename of pid ${e} \u2192 "${n}", flap signature (competing editor sync sources)`),0;ww(e,n);let s=I.sessionsFor(e),r=0;for(let o of s)try{if(Te(o)===n)continue;he(o,n),r++}catch{}return r>0&&console.log(`[terminal] rename of pid ${e} \u2192 "${n}" propagated to ${r} session(s)`),r}var sm=(()=>{try{let e=nr(ki(Ai(import.meta.url)),"..","..","package.json");return JSON.parse(yi(e,"utf8")).version??"0.0.0"}catch{return"0.0.0"}})(),bi=!1,Si=!1,Ti=!1,kw=ki(Ai(import.meta.url)),Ri=nr(kw,"..","web"),im=nr(Ri,"index.html"),Aw=pw(im);function rm(){return f().prepare(`SELECT
1813
+ ORDER BY timestamp DESC LIMIT 5`).all(e),s=!1;for(let u of n)if(u.content_text&&ww.some(d=>d.test(u.content_text))){s=!0;break}let r=t.prepare(`SELECT content_text, tool_names FROM messages
1814
+ WHERE session_id = ?`).all(e),o={fileWrites:!1,testRuns:!1,commits:!1,buildSuccess:!1};for(let u of r){let d=u.tool_names??"",m=u.content_text??"";/\bWrite\b|\bEdit\b/.test(d)&&(o.fileWrites=!0),/\b(?:jest|pytest|vitest|mocha|test|spec)\b/i.test(m)&&/pass|ok|✓/i.test(m)&&(o.testRuns=!0),/\bgit\s+commit\b/i.test(m)&&(o.commits=!0),(/\bbuild\s+(?:succeeded|success|passed)\b/i.test(m)||/tsc.*(?:0 errors|no errors)/i.test(m))&&(o.buildSuccess=!0)}return s?{status:[o.fileWrites,o.testRuns,o.commits,o.buildSuccess].filter(Boolean).length>=2?"verified":"unverified",evidence:o,claimFound:s}:{status:"neutral",evidence:o,claimFound:s}}function Aw(e){let t=kw(e);return f().prepare("UPDATE sessions SET verification_status = ?, verification_computed_at = ? WHERE id = ?").run(t.status,Date.now(),e),t}function nm(e){let n=f().prepare("SELECT verification_status, verification_computed_at FROM sessions WHERE id = ?").get(e);if(n?.verification_status&&n.verification_computed_at&&Date.now()-n.verification_computed_at<Rw){let s={fileWrites:!1,testRuns:!1,commits:!1,buildSuccess:!1};return{status:n.verification_status,evidence:s,claimFound:n.verification_status!=="neutral"}}return Aw(e)}import{readFileSync as xw,writeFileSync as Nw,mkdirSync as Ow,chmodSync as Lw}from"node:fs";import{join as sm}from"node:path";import{homedir as rm}from"node:os";function om(){return sm(rm(),".recall","config.json")}function im(){try{return JSON.parse(xw(om(),"utf-8"))}catch{return{}}}function Cw(e){let t=om();Ow(sm(rm(),".recall"),{recursive:!0}),Nw(t,JSON.stringify(e,null,2)+`
1815
+ `,"utf-8"),Lw(t,384)}function yi(){let t=im().verification;return typeof t=="object"&&t!==null&&"enabled"in t?!!t.enabled:!1}function am(e){let t=im();t.verification={...typeof t.verification=="object"&&t.verification!==null?t.verification:{},enabled:e},Cw(t)}var Uw=5e3,Li={scanned:0,linked:0,renamed:0,skipped_manual:0,ambiguous_cwd:0},wi=0,Ri=Li,ki=null;async function Bw(){return Date.now()-wi>=Uw&&!ki&&(ki=rs().then(n=>(Ri=n,wi=Date.now(),n)).catch(()=>(wi=Date.now(),Ri=Li,Li)).finally(()=>{ki=null})),Ri}var Hw=2e3,Ww=6,nr=new Map;function An(e){return e.replace(/[\\%_]/g,t=>"\\"+t)}function qw(e,t){let n=Date.now(),s=(nr.get(e)??[]).filter(a=>n-a.ts<Hw);return nr.set(e,s),s.length<2||s[s.length-1].name===t?!1:s.slice(0,-1).some(a=>a.name===t)}function Xw(e,t){let n=nr.get(e)??[];for(n.push({name:t,ts:Date.now()});n.length>Ww;)n.shift();nr.set(e,n)}function lm(e,t){let n=t.trim();if(!n)return 0;if(le(n)){let o=bt(n);if(!o)return 0;n=o}if(de(n))return 0;if(qw(e,n))return console.log(`[terminal] dropping rename of pid ${e} \u2192 "${n}", flap signature (competing editor sync sources)`),0;Xw(e,n);let s=M.sessionsFor(e),r=0;for(let o of s)try{if(Te(o)===n)continue;he(o,n),r++}catch{}return r>0&&console.log(`[terminal] rename of pid ${e} \u2192 "${n}" propagated to ${r} session(s)`),r}var um=(()=>{try{let e=sr(vi(Ii(import.meta.url)),"..","..","package.json");return JSON.parse(Oi(e,"utf8")).version??"0.0.0"}catch{return"0.0.0"}})(),Ai=!1,xi=!1,Ni=!1,Gw=vi(Ii(import.meta.url)),Ci=sr(Gw,"..","web"),mm=sr(Ci,"index.html"),Yw=jw(mm);function dm(){return f().prepare(`SELECT
1802
1816
  (SELECT COUNT(*) FROM projects) AS projects,
1803
1817
  (SELECT COUNT(*) FROM sessions) AS sessions,
1804
1818
  (SELECT COUNT(*) FROM messages) AS messages,
1805
1819
  (SELECT MIN(started_at) FROM sessions WHERE started_at IS NOT NULL) AS earliest,
1806
- (SELECT MAX(started_at) FROM sessions WHERE started_at IS NOT NULL) AS latest`).get()}var xw=/^(127\.0\.0\.1|localhost|\[::1\])(:\d+)?$/i,Nw=/^https?:\/\/(127\.0\.0\.1|localhost|\[::1\])(:\d+)?$/i;async function je(e,t){if((await Ke()).tier!=="pro")return e.json({error:"pro_required",message:"This feature requires a Claude Recall Pro license.",upgrade_url:"https://clauderecall.com/pricing",activate_command:"recall activate <license-key>"},402);await t()}var Qs=new Map,am=0,om=0,cm=null,Ow=6e4;function Lw(){am+=1;let e=Date.now();e-om<Ow||(om=e,console.warn("[auth] /api/terminal/* request rejected without a valid X-Recall-Token. The VS Code / Cursor extension is likely outdated relative to the daemon \u2014 tab names will not flow through, and session titles will fall back to the heuristic first-message snippet. Reinstall: `code --install-extension extensions/vscode/clauderecall-vscode-*.vsix` and restart the extension host. Run `recall doctor` for a full pipeline view."))}function Cw(){cm=new Date().toISOString()}function vw(){let e=Ec();return{silentTerminalRejections:am,lastTerminalSyncAt:cm,autoExtract:{circuitBroken:e.broken,brokenAt:e.brokenAt,reason:e.reason,consecutiveZeroTokenRuns:e.consecutiveZeroTokenRuns}}}function er(e,t){if(t)return"";let n=e;return` AND COALESCE(${n}.auto_title, '') NOT LIKE '[meta]%' AND COALESCE(${n}.auto_title, '') NOT LIKE '[output-index]%' AND COALESCE(${n}.auto_title, '') NOT LIKE '[skill]%' AND COALESCE(${n}.auto_title, '') NOT LIKE 'You are summarizing a Claude Code session%' AND COALESCE(${n}.auto_title, '') NOT LIKE 'You are extracting a structured Output Index%' AND COALESCE(${n}.title_quality, '') != 'programmatic'`}function Iw(e){let t=new uw;if(t.use("*",Rw({maxSize:1*1024*1024})),t.use("*",async(i,l)=>{let p=i.req.raw.headers.get("host")??"";if(!xw.test(p))return i.text("Forbidden: invalid Host header",403);let g=i.req.raw.headers.get("origin");if(g&&!Nw.test(g))return i.text("Forbidden: cross-origin request rejected",403);await l()}),e){let i=Buffer.from(e,"utf8");t.use("/api/*",async(l,p)=>{if(l.req.method==="GET"&&l.req.path==="/api/health")return p();let g=l.req.raw.headers.get("x-recall-token")??"";!g&&l.req.method==="GET"&&(g=new URL(l.req.url).searchParams.get("token")??"");let _=!1;if(g.length===e.length)try{_=fw(Buffer.from(g,"utf8"),i)}catch{_=!1}return _?p():(l.req.path.startsWith("/api/terminal/")&&Lw(),l.json({error:"unauthorized"},401))})}t.use("*",async(i,l)=>{await l(),i.res.headers.set("Content-Security-Policy","default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https://clauderecall.com; font-src 'self' data:; connect-src 'self' data: https://clauderecall.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'"),i.res.headers.set("X-Content-Type-Options","nosniff"),i.res.headers.set("X-Frame-Options","DENY"),i.res.headers.set("Referrer-Policy","no-referrer"),i.res.headers.set("Cross-Origin-Resource-Policy","same-origin")}),t.get("/api/health",i=>i.json({status:"ok",version:sm,uptimeSeconds:Math.round(process.uptime()),pipeline:vw()})),t.get("/api/stats",i=>i.json(rm())),t.get("/api/stats/session/:id",i=>{let l=Sp(i.req.param("id"));return l?i.json(l):i.json({error:"session not found"},404)}),t.get("/api/stats/project/:name",i=>{let l=Tp(i.req.param("name"));return l?i.json(l):i.json({error:"project not found"},404)}),t.get("/api/stats/overview",i=>{let l=i.req.query("range"),p=l==="7d"?"7d":l==="30d"?"30d":"all";return i.json(yp(p))}),t.post("/api/stats/backfill",async i=>{let l=await i.req.json().catch(()=>({})),p=l.limit?Math.max(1,Math.min(1e5,Number(l.limit))):5e3;if(p>5e3){let _=hp({limit:p});return i.json({mode:"background",started:_,alreadyRunning:!_&&Ep(),limit:p,lastRun:ai()})}let g=fp({limit:p});return i.json({mode:"sync",started:!1,alreadyRunning:!1,limit:p,result:g,lastRun:ai()})}),t.get("/api/stats/health",i=>i.json(wp())),t.get("/api/stats/health/:projectId",i=>{let l=Number(i.req.param("projectId")),p=ui(l);return p?i.json(p):i.json({error:"project not found"},404)}),t.get("/api/config/verification",i=>i.json({enabled:_i()})),t.put("/api/config/verification",async i=>{let l=await i.req.json();return typeof l.enabled=="boolean"&&em(l.enabled),i.json({enabled:_i()})}),t.get("/api/sessions/:id/verification",i=>{let l=i.req.param("id"),p=zp(l);return i.json(p)}),t.get("/api/sessions/:id/share-stats",i=>{let l=i.req.param("id"),g=f().prepare(`SELECT tool_names, raw_json FROM messages
1807
- WHERE session_id = ? AND tool_names IS NOT NULL AND tool_names != ''`).all(l),_=g.length,E=new Set;for(let y of g){if(!/Read|Write|Edit/.test(y.tool_names))continue;let k=y.raw_json.match(/"(?:file_path|path)":\s*"([^"]+)"/g);if(k)for(let N of k){let A=N.match(/":\s*"([^"]+)"/);A&&E.add(A[1])}}return i.json({filesReferenced:E.size,toolCallCount:_})}),t.get("/api/sessions/:id/commits",async i=>{let l=i.req.param("id"),p=eo(l);if(p.length>0||i.req.query("refresh")!=="1")return i.json({commits:p});let g=await Qr(l);return i.json({commits:eo(l),status:g.status})}),t.get("/api/commits/:sha/session",i=>{let l=i.req.param("sha");return/^[0-9a-fA-F]{4,40}$/.test(l)?i.json({sessions:os(l)}):i.json({error:"invalid sha format"},400)}),t.get("/api/license/status",async i=>{let l=await Ke();return i.json(l)}),t.post("/api/feedback",async i=>{let l;try{l=await i.req.json()}catch{return i.json({error:"invalid json"},400)}if(!l||typeof l!="object")return i.json({error:"invalid body"},400);let p=process.env.RECALL_FEEDBACK_API??"https://clauderecall.com/api/feedback",g=p==="https://clauderecall.com/api/feedback",_=await Ke(),E=Ht(),y=g&&_.tier==="pro"&&E?E.license_jwt:null,k=(()=>{try{let O=nr(ki(Ai(import.meta.url)),"..","..","package.json");return JSON.parse(yi(O,"utf8")).version}catch{return"unknown"}})(),N=l,A={score:N.score,comment:N.comment??null,surface:"web",version:typeof N.version=="string"?N.version:k,os:typeof N.os=="string"?N.os:process.platform,trigger_kind:typeof N.trigger_kind=="string"?N.trigger_kind:"manual",license_jwt:y};try{let O=await fetch(p,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(A)}),C=await O.json().catch(()=>({}));return i.json(C,O.status)}catch(O){let C=O instanceof Error?O.message:"network error";return i.json({error:"upstream_unreachable",detail:C},502)}}),t.get("/api/discover/today",je,async i=>{try{return i.json(await kp())}catch(l){return console.error("[discover.today]",l),i.json({rediscovered:null,expensive:null,authored:null,availability:{semantic:!1,cost:!1,git:!1},generatedAt:new Date().toISOString(),error:l.message},500)}}),t.get("/api/macro-repos",i=>i.json({macro_repos:$o(),orphan_projects:Gu()})),t.get("/api/bug-synthesis",i=>{let l=i.req.query("scope"),p=i.req.query("target_id"),g=i.req.query("limit"),_=l==="cluster"||l==="project"?l:void 0,E=g?Math.max(1,Number(g)):50,y=nd({scope:_,target_id:p??void 0,limit:E});return i.json({results:y})}),t.get("/api/bug-synthesis/counts",i=>{let l=i.req.query("scope");if(l!=="cluster"&&l!=="project")return i.json({error:'scope must be "cluster" or "project"'},400);let p=sd(l);return i.json({counts:Array.from(p.entries()).map(([g,_])=>({target_id:g,count:_}))})}),t.get("/api/bug-synthesis/:id",i=>{let l=Number(i.req.param("id"));if(!Number.isFinite(l))return i.json({error:"invalid id"},400);let p=Uo(l);return p?i.json({result:p}):i.json({error:"not found"},404)}),t.delete("/api/bug-synthesis/:id",i=>{let l=Number(i.req.param("id"));return Number.isFinite(l)?(rd(l),i.json({ok:!0})):i.json({error:"invalid id"},400)});let n=D.object({name:D.string().min(1).max(100),description:D.string().max(500).nullable().optional()});t.post("/api/macro-repos",async i=>{let l=await i.req.json().catch(()=>null),p=n.safeParse(l);if(!p.success)return i.json({error:"invalid request body",details:p.error.format()},400);try{let g=zu({name:p.data.name,description:p.data.description??null});return i.json({macro_repo:g},201)}catch(g){let _=g instanceof Error?g.message:String(g);return _.includes("UNIQUE constraint")?i.json({error:`a macro repo named "${p.data.name}" already exists`},409):i.json({error:_},400)}});let s=D.object({name:D.string().min(1).max(100).optional(),description:D.string().max(500).nullable().optional()});t.patch("/api/macro-repos/:id",async i=>{let l=Number(i.req.param("id"));if(!Number.isFinite(l))return i.json({error:"invalid id"},400);let p=await i.req.json().catch(()=>null),g=s.safeParse(p);if(!g.success)return i.json({error:"invalid request body"},400);try{let _=Ku(l,g.data);return i.json({macro_repo:_})}catch(_){let E=_ instanceof Error?_.message:String(_);return E.includes("not found")?i.json({error:E},404):E.includes("UNIQUE constraint")?i.json({error:"another macro repo already has that name"},409):i.json({error:E},400)}}),t.delete("/api/macro-repos/:id",i=>{let l=Number(i.req.param("id"));return Number.isFinite(l)?(Vu(l),i.json({ok:!0})):i.json({error:"invalid id"},400)});let r=D.object({project_id:D.number().int().positive()});t.post("/api/macro-repos/:id/members",async i=>{let l=Number(i.req.param("id"));if(!Number.isFinite(l))return i.json({error:"invalid id"},400);let p=await i.req.json().catch(()=>null),g=r.safeParse(p);if(!g.success)return i.json({error:"invalid request body"},400);try{return Zu(l,g.data.project_id),i.json({macro_repo:xt(l)})}catch(_){let E=_ instanceof Error?_.message:String(_);return i.json({error:E},E.includes("not found")?404:400)}}),t.delete("/api/macro-repos/:id/members/:projectId",i=>{let l=Number(i.req.param("id")),p=Number(i.req.param("projectId"));return!Number.isFinite(l)||!Number.isFinite(p)?i.json({error:"invalid id"},400):(Qu(l,p),i.json({macro_repo:xt(l)}))}),t.get("/api/projects",i=>{let l=f(),p=i.req.query("system")==="1"||i.req.query("system")==="true",g=er("s",p),_=l.prepare(`SELECT p.id, p.name, p.decoded_path,
1820
+ (SELECT MAX(started_at) FROM sessions WHERE started_at IS NOT NULL) AS latest`).get()}var zw=/^(127\.0\.0\.1|localhost|\[::1\])(:\d+)?$/i,Kw=/^https?:\/\/(127\.0\.0\.1|localhost|\[::1\])(:\d+)?$/i;async function je(e,t){if((await Ke()).tier!=="pro")return e.json({error:"pro_required",message:"This feature requires a Claude Recall Pro license.",upgrade_url:"https://clauderecall.com/pricing",activate_command:"recall activate <license-key>"},402);await t()}var er=new Map,gm=0,pm=0,_m=null,Vw=6e4;function Zw(){gm+=1;let e=Date.now();e-pm<Vw||(pm=e,console.warn("[auth] /api/terminal/* request rejected without a valid X-Recall-Token. The VS Code / Cursor extension is likely outdated relative to the daemon \u2014 tab names will not flow through, and session titles will fall back to the heuristic first-message snippet. Reinstall: `code --install-extension extensions/vscode/clauderecall-vscode-*.vsix` and restart the extension host. Run `recall doctor` for a full pipeline view."))}function Qw(){_m=new Date().toISOString()}function e0(){let e=wc();return{silentTerminalRejections:gm,lastTerminalSyncAt:_m,autoExtract:{circuitBroken:e.broken,brokenAt:e.brokenAt,reason:e.reason,consecutiveZeroTokenRuns:e.consecutiveZeroTokenRuns}}}function tr(e,t){if(t)return"";let n=e;return` AND COALESCE(${n}.auto_title, '') NOT LIKE '[meta]%' AND COALESCE(${n}.auto_title, '') NOT LIKE '[output-index]%' AND COALESCE(${n}.auto_title, '') NOT LIKE '[skill]%' AND COALESCE(${n}.auto_title, '') NOT LIKE 'You are summarizing a Claude Code session%' AND COALESCE(${n}.auto_title, '') NOT LIKE 'You are extracting a structured Output Index%' AND COALESCE(${n}.title_quality, '') != 'programmatic'`}function t0(e){let t=new vw;if(t.use("*",Jw({maxSize:1*1024*1024})),t.use("*",async(i,l)=>{let p=i.req.raw.headers.get("host")??"";if(!zw.test(p))return i.text("Forbidden: invalid Host header",403);let g=i.req.raw.headers.get("origin");if(g&&!Kw.test(g))return i.text("Forbidden: cross-origin request rejected",403);await l()}),e){let i=Buffer.from(e,"utf8");t.use("/api/*",async(l,p)=>{if(l.req.method==="GET"&&l.req.path==="/api/health")return p();let g=l.req.raw.headers.get("x-recall-token")??"";!g&&l.req.method==="GET"&&(g=new URL(l.req.url).searchParams.get("token")??"");let _=!1;if(g.length===e.length)try{_=Pw(Buffer.from(g,"utf8"),i)}catch{_=!1}return _?p():(l.req.path.startsWith("/api/terminal/")&&Zw(),l.json({error:"unauthorized"},401))})}t.use("*",async(i,l)=>{await l(),i.res.headers.set("Content-Security-Policy","default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https://clauderecall.com; font-src 'self' data:; connect-src 'self' data: https://clauderecall.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'"),i.res.headers.set("X-Content-Type-Options","nosniff"),i.res.headers.set("X-Frame-Options","DENY"),i.res.headers.set("Referrer-Policy","no-referrer"),i.res.headers.set("Cross-Origin-Resource-Policy","same-origin")}),t.get("/api/health",i=>i.json({status:"ok",version:um,uptimeSeconds:Math.round(process.uptime()),pipeline:e0()})),t.get("/api/stats",i=>i.json(dm())),t.get("/api/stats/session/:id",i=>{let l=xp(i.req.param("id"));return l?i.json(l):i.json({error:"session not found"},404)}),t.get("/api/stats/project/:name",i=>{let l=Np(i.req.param("name"));return l?i.json(l):i.json({error:"project not found"},404)}),t.get("/api/stats/overview",i=>{let l=i.req.query("range"),p=l==="7d"?"7d":l==="30d"?"30d":"all";return i.json(Op(p))}),t.post("/api/stats/backfill",async i=>{let l=await i.req.json().catch(()=>({})),p=l.limit?Math.max(1,Math.min(1e5,Number(l.limit))):5e3;if(p>5e3){let _=Rp({limit:p});return i.json({mode:"background",started:_,alreadyRunning:!_&&kp(),limit:p,lastRun:ui()})}let g=wp({limit:p});return i.json({mode:"sync",started:!1,alreadyRunning:!1,limit:p,result:g,lastRun:ui()})}),t.get("/api/stats/health",i=>i.json(Lp())),t.get("/api/stats/health/:projectId",i=>{let l=Number(i.req.param("projectId")),p=mi(l);return p?i.json(p):i.json({error:"project not found"},404)}),t.get("/api/config/verification",i=>i.json({enabled:yi()})),t.put("/api/config/verification",async i=>{let l=await i.req.json();return typeof l.enabled=="boolean"&&am(l.enabled),i.json({enabled:yi()})}),t.get("/api/sessions/:id/verification",i=>{let l=i.req.param("id"),p=nm(l);return i.json(p)}),t.get("/api/sessions/:id/share-stats",i=>{let l=i.req.param("id"),g=f().prepare(`SELECT tool_names, raw_json FROM messages
1821
+ WHERE session_id = ? AND tool_names IS NOT NULL AND tool_names != ''`).all(l),_=g.length,E=new Set;for(let y of g){if(!/Read|Write|Edit/.test(y.tool_names))continue;let w=y.raw_json.match(/"(?:file_path|path)":\s*"([^"]+)"/g);if(w)for(let N of w){let k=N.match(/":\s*"([^"]+)"/);k&&E.add(k[1])}}return i.json({filesReferenced:E.size,toolCallCount:_})}),t.get("/api/sessions/:id/commits",async i=>{let l=i.req.param("id"),p=to(l);if(p.length>0||i.req.query("refresh")!=="1")return i.json({commits:p});let g=await eo(l);return i.json({commits:to(l),status:g.status})}),t.get("/api/commits/:sha/session",i=>{let l=i.req.param("sha");return/^[0-9a-fA-F]{4,40}$/.test(l)?i.json({sessions:is(l)}):i.json({error:"invalid sha format"},400)}),t.get("/api/license/status",async i=>{let l=await Ke();return i.json(l)}),t.post("/api/feedback",async i=>{let l;try{l=await i.req.json()}catch{return i.json({error:"invalid json"},400)}if(!l||typeof l!="object")return i.json({error:"invalid body"},400);let p=process.env.RECALL_FEEDBACK_API??"https://clauderecall.com/api/feedback",g=p==="https://clauderecall.com/api/feedback",_=await Ke(),E=Ht(),y=g&&_.tier==="pro"&&E?E.license_jwt:null,w=(()=>{try{let C=sr(vi(Ii(import.meta.url)),"..","..","package.json");return JSON.parse(Oi(C,"utf8")).version}catch{return"unknown"}})(),N=l,k={score:N.score,comment:N.comment??null,surface:"web",version:typeof N.version=="string"?N.version:w,os:typeof N.os=="string"?N.os:process.platform,trigger_kind:typeof N.trigger_kind=="string"?N.trigger_kind:"manual",license_jwt:y};try{let C=await fetch(p,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(k)}),I=await C.json().catch(()=>({}));return i.json(I,C.status)}catch(C){let I=C instanceof Error?C.message:"network error";return i.json({error:"upstream_unreachable",detail:I},502)}}),t.get("/api/discover/today",je,async i=>{try{return i.json(await vp())}catch(l){return console.error("[discover.today]",l),i.json({rediscovered:null,expensive:null,authored:null,availability:{semantic:!1,cost:!1,git:!1},generatedAt:new Date().toISOString(),error:l.message},500)}}),t.get("/api/macro-repos",i=>i.json({macro_repos:Ho(),orphan_projects:td()})),t.get("/api/bug-synthesis",i=>{let l=i.req.query("scope"),p=i.req.query("target_id"),g=i.req.query("limit"),_=l==="cluster"||l==="project"?l:void 0,E=g?Math.max(1,Number(g)):50,y=ld({scope:_,target_id:p??void 0,limit:E});return i.json({results:y})}),t.get("/api/bug-synthesis/counts",i=>{let l=i.req.query("scope");if(l!=="cluster"&&l!=="project")return i.json({error:'scope must be "cluster" or "project"'},400);let p=ud(l);return i.json({counts:Array.from(p.entries()).map(([g,_])=>({target_id:g,count:_}))})}),t.get("/api/bug-synthesis/:id",i=>{let l=Number(i.req.param("id"));if(!Number.isFinite(l))return i.json({error:"invalid id"},400);let p=Wo(l);return p?i.json({result:p}):i.json({error:"not found"},404)}),t.delete("/api/bug-synthesis/:id",i=>{let l=Number(i.req.param("id"));return Number.isFinite(l)?(dd(l),i.json({ok:!0})):i.json({error:"invalid id"},400)});let n=D.object({name:D.string().min(1).max(100),description:D.string().max(500).nullable().optional()});t.post("/api/macro-repos",async i=>{let l=await i.req.json().catch(()=>null),p=n.safeParse(l);if(!p.success)return i.json({error:"invalid request body",details:p.error.format()},400);try{let g=nd({name:p.data.name,description:p.data.description??null});return i.json({macro_repo:g},201)}catch(g){let _=g instanceof Error?g.message:String(g);return _.includes("UNIQUE constraint")?i.json({error:`a macro repo named "${p.data.name}" already exists`},409):i.json({error:_},400)}});let s=D.object({name:D.string().min(1).max(100).optional(),description:D.string().max(500).nullable().optional()});t.patch("/api/macro-repos/:id",async i=>{let l=Number(i.req.param("id"));if(!Number.isFinite(l))return i.json({error:"invalid id"},400);let p=await i.req.json().catch(()=>null),g=s.safeParse(p);if(!g.success)return i.json({error:"invalid request body"},400);try{let _=sd(l,g.data);return i.json({macro_repo:_})}catch(_){let E=_ instanceof Error?_.message:String(_);return E.includes("not found")?i.json({error:E},404):E.includes("UNIQUE constraint")?i.json({error:"another macro repo already has that name"},409):i.json({error:E},400)}}),t.delete("/api/macro-repos/:id",i=>{let l=Number(i.req.param("id"));return Number.isFinite(l)?(rd(l),i.json({ok:!0})):i.json({error:"invalid id"},400)});let r=D.object({project_id:D.number().int().positive()});t.post("/api/macro-repos/:id/members",async i=>{let l=Number(i.req.param("id"));if(!Number.isFinite(l))return i.json({error:"invalid id"},400);let p=await i.req.json().catch(()=>null),g=r.safeParse(p);if(!g.success)return i.json({error:"invalid request body"},400);try{return od(l,g.data.project_id),i.json({macro_repo:xt(l)})}catch(_){let E=_ instanceof Error?_.message:String(_);return i.json({error:E},E.includes("not found")?404:400)}}),t.delete("/api/macro-repos/:id/members/:projectId",i=>{let l=Number(i.req.param("id")),p=Number(i.req.param("projectId"));return!Number.isFinite(l)||!Number.isFinite(p)?i.json({error:"invalid id"},400):(id(l,p),i.json({macro_repo:xt(l)}))}),t.get("/api/projects",i=>{let l=f(),p=i.req.query("system")==="1"||i.req.query("system")==="true",g=tr("s",p),_=l.prepare(`SELECT p.id, p.name, p.decoded_path,
1808
1822
  COUNT(CASE WHEN s.id IS NOT NULL${g} THEN 1 END) AS session_count,
1809
1823
  COALESCE(SUM(CASE WHEN s.id IS NOT NULL${g} THEN s.message_count ELSE 0 END), 0) AS message_count,
1810
1824
  MAX(COALESCE(s.ended_at, s.started_at)) AS latest
@@ -1822,12 +1836,12 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1822
1836
  sa.alias AS alias
1823
1837
  FROM sessions s
1824
1838
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1825
- WHERE s.project_id = ?${er("s",_)}
1826
- ORDER BY s.started_at`).all(g.id),y=E.map(A=>A.id),k=[];if(y.length>0){let A=y.map(()=>"?").join(",");k=l.prepare(`SELECT thread_id, session_id, parent_session_id, role
1839
+ WHERE s.project_id = ?${tr("s",_)}
1840
+ ORDER BY s.started_at`).all(g.id),y=E.map(k=>k.id),w=[];if(y.length>0){let k=y.map(()=>"?").join(",");w=l.prepare(`SELECT thread_id, session_id, parent_session_id, role
1827
1841
  FROM thread_edges
1828
- WHERE session_id IN (${A})
1842
+ WHERE session_id IN (${k})
1829
1843
  AND (parent_session_id IS NULL
1830
- OR parent_session_id IN (${A}))`).all(...y,...y)}let N=E.map(A=>{let O=A.alias??A.auto_title??A.first_user_message??A.id.slice(0,8),C=null,v=null;if(A.auto_title?.startsWith("/")){let L=A.auto_title.split(" \xB7 ");C=L[0],v=L.length>1?L.slice(1).join(" \xB7 "):null}return{id:A.id.slice(0,8),full_id:A.id,title:O,alias:A.alias,auto_title:A.auto_title,auto_title_source:A.auto_title_source,title_quality:A.title_quality,started_at:A.started_at,msgs:A.message_count,skill:C,brand:v}});return i.json({project:g,sessions:N,thread_edges:k})});let o=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),a=new Set(["pending","approved","rejected"]),c=new Set(["L1","L2","L3","L4","user"]);t.get("/api/links",i=>{let l=i.req.query("source_id")??void 0,p=i.req.query("target_id")??void 0,g=i.req.query("type"),_=i.req.query("approved"),E=i.req.query("limit"),y;if(g){if(!o.has(g))return i.json({error:`invalid type: ${g}`},400);y=g}let k=_==="1"||_==="true",N=E?Number(E):void 0;if(N!==void 0&&(!Number.isFinite(N)||N<1))return i.json({error:"invalid limit"},400);try{let A=jn({sourceSessionId:l,targetSessionId:p,linkType:y,approvedOnly:k,limit:N});return i.json({links:A})}catch(A){return i.json({error:A.message},400)}}),t.get("/api/links/suggestions",i=>{let l=i.req.query("status"),p=i.req.query("source_id")??void 0,g=i.req.query("target_id")??void 0,_=i.req.query("inferred_by"),E=i.req.query("limit"),y;if(l){if(!a.has(l))return i.json({error:`invalid status: ${l}`},400);y=l}let k;if(_){if(!c.has(_))return i.json({error:`invalid inferred_by: ${_}`},400);k=_}let N=E?Number(E):void 0;if(N!==void 0&&(!Number.isFinite(N)||N<1))return i.json({error:"invalid limit"},400);try{let A=lt({status:y,sourceSessionId:p,targetSessionId:g,inferredBy:k,limit:N}),O=new Set;for(let L of A)O.add(L.source_session_id),O.add(L.target_session_id);let C=new Map;if(O.size>0){let L=Array.from(O),F=L.map(()=>"?").join(","),K=f().prepare(`SELECT s.id,
1844
+ OR parent_session_id IN (${k}))`).all(...y,...y)}let N=E.map(k=>{let C=k.alias??k.auto_title??k.first_user_message??k.id.slice(0,8),I=null,j=null;if(k.auto_title?.startsWith("/")){let v=k.auto_title.split(" \xB7 ");I=v[0],j=v.length>1?v.slice(1).join(" \xB7 "):null}return{id:k.id.slice(0,8),full_id:k.id,title:C,alias:k.alias,auto_title:k.auto_title,auto_title_source:k.auto_title_source,title_quality:k.title_quality,started_at:k.started_at,msgs:k.message_count,skill:I,brand:j}});return i.json({project:g,sessions:N,thread_edges:w})});let o=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),a=new Set(["pending","approved","rejected"]),c=new Set(["L1","L2","L3","L4","user"]);t.get("/api/links",i=>{let l=i.req.query("source_id")??void 0,p=i.req.query("target_id")??void 0,g=i.req.query("type"),_=i.req.query("approved"),E=i.req.query("limit"),y;if(g){if(!o.has(g))return i.json({error:`invalid type: ${g}`},400);y=g}let w=_==="1"||_==="true",N=E?Number(E):void 0;if(N!==void 0&&(!Number.isFinite(N)||N<1))return i.json({error:"invalid limit"},400);try{let k=Mn({sourceSessionId:l,targetSessionId:p,linkType:y,approvedOnly:w,limit:N});return i.json({links:k})}catch(k){return i.json({error:k.message},400)}}),t.get("/api/links/suggestions",i=>{let l=i.req.query("status"),p=i.req.query("source_id")??void 0,g=i.req.query("target_id")??void 0,_=i.req.query("inferred_by"),E=i.req.query("limit"),y;if(l){if(!a.has(l))return i.json({error:`invalid status: ${l}`},400);y=l}let w;if(_){if(!c.has(_))return i.json({error:`invalid inferred_by: ${_}`},400);w=_}let N=E?Number(E):void 0;if(N!==void 0&&(!Number.isFinite(N)||N<1))return i.json({error:"invalid limit"},400);try{let k=lt({status:y,sourceSessionId:p,targetSessionId:g,inferredBy:w,limit:N}),C=new Set;for(let v of k)C.add(v.source_session_id),C.add(v.target_session_id);let I=new Map;if(C.size>0){let v=Array.from(C),P=v.map(()=>"?").join(","),K=f().prepare(`SELECT s.id,
1831
1845
  NULLIF(sa.alias, '') AS alias,
1832
1846
  s.auto_title,
1833
1847
  s.first_user_message,
@@ -1835,7 +1849,7 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1835
1849
  FROM sessions s
1836
1850
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1837
1851
  LEFT JOIN projects p ON p.id = s.project_id
1838
- WHERE s.id IN (${F})`).all(...L);for(let Y of K){let $=Y.first_user_message?Y.first_user_message.slice(0,80):null,X=Y.alias??Y.auto_title??$??Y.id.slice(0,8);C.set(Y.id,{title:X,project:Y.project})}}let v=A.map(L=>{let F=C.get(L.source_session_id),q=C.get(L.target_session_id);return{...L,source_title:F?.title??L.source_session_id.slice(0,8),source_project:F?.project??null,target_title:q?.title??L.target_session_id.slice(0,8),target_project:q?.project??null}});return i.json({suggestions:v})}catch(A){return i.json({error:A.message},400)}}),t.get("/api/output-index/:sessionId",i=>{let l=i.req.param("sessionId");if(!l)return i.json({error:"sessionId required"},400);let p=Ze(l);return p?i.json(p):i.json({error:`no output index for session ${l}`},404)});let u=new Set(["pagerank","embedding-rerank","hybrid"]);t.get("/api/neighborhood/:sessionId",i=>{let l=i.req.param("sessionId");if(!l)return i.json({error:"sessionId required"},400);let p=i.req.query("budget"),g=p!==void 0?Number(p):4e3;if(!Number.isFinite(g)||g<100)return i.json({error:"budget must be a number \u2265 100"},400);let _=i.req.query("scoring")??"hybrid";if(!u.has(_))return i.json({error:`invalid scoring: ${_}; valid: pagerank, embedding-rerank, hybrid`},400);let E=_,y=i.req.query("max_depth"),k=y!==void 0?Number(y):2;if(!Number.isFinite(k)||k<1)return i.json({error:"max_depth must be a number \u2265 1"},400);let N,A=i.req.query("edge_types");if(A){let F=A.split(",").map(q=>q.trim()).filter(Boolean);for(let q of F)if(!o.has(q))return i.json({error:`invalid edge_type: ${q}`},400);N=F}let O=i.req.query("include_wiki_links"),C=O===void 0?!0:!(O==="0"||O==="false"),v=i.req.query("include_suggestions"),L=v==="1"||v==="true";try{let F=Is(l,{budget:g,scoring:E,maxDepth:k,edgeTypes:N,includeWikiLinks:C,includeSuggestions:L});return i.json(F)}catch(F){let q=F instanceof Error?F.message:"unknown error",K=/not found/.test(q)?404:500;return i.json({error:q},K)}}),t.get("/api/bug-patterns",i=>{let l=i.req.query("min_count"),p=i.req.query("status"),g=i.req.query("project")??void 0,_=i.req.query("limit"),E=i.req.query("offset"),y=l?Number(l):void 0;if(y!==void 0&&(!Number.isFinite(y)||y<1))return i.json({error:"min_count must be a positive integer"},400);let k;if(p==="open")k=!1;else if(p==="resolved")k=!0;else if(p&&p!=="all")return i.json({error:`invalid status: ${p}; valid: open, resolved, all`},400);let N=_?Number(_):void 0;if(N!==void 0&&(!Number.isFinite(N)||N<1))return i.json({error:"invalid limit"},400);let A=E?Number(E):void 0;if(A!==void 0&&(!Number.isFinite(A)||A<0))return i.json({error:"invalid offset"},400);try{let O=ta({minOccurrenceCount:y,hasResolved:k,project:g,limit:N,offset:A});return i.json(O)}catch(O){return i.json({error:O.message},400)}}),t.get("/api/bug-patterns/setup-status",i=>{let l=f(),g=l.prepare(`SELECT p.name AS project,
1852
+ WHERE s.id IN (${P})`).all(...v);for(let G of K){let U=G.first_user_message?G.first_user_message.slice(0,80):null,X=G.alias??G.auto_title??U??G.id.slice(0,8);I.set(G.id,{title:X,project:G.project})}}let j=k.map(v=>{let P=I.get(v.source_session_id),q=I.get(v.target_session_id);return{...v,source_title:P?.title??v.source_session_id.slice(0,8),source_project:P?.project??null,target_title:q?.title??v.target_session_id.slice(0,8),target_project:q?.project??null}});return i.json({suggestions:j})}catch(k){return i.json({error:k.message},400)}}),t.get("/api/output-index/:sessionId",i=>{let l=i.req.param("sessionId");if(!l)return i.json({error:"sessionId required"},400);let p=Ve(l);return p?i.json(p):i.json({error:`no output index for session ${l}`},404)});let u=new Set(["pagerank","embedding-rerank","hybrid"]);t.get("/api/neighborhood/:sessionId",i=>{let l=i.req.param("sessionId");if(!l)return i.json({error:"sessionId required"},400);let p=i.req.query("budget"),g=p!==void 0?Number(p):4e3;if(!Number.isFinite(g)||g<100)return i.json({error:"budget must be a number \u2265 100"},400);let _=i.req.query("scoring")??"hybrid";if(!u.has(_))return i.json({error:`invalid scoring: ${_}; valid: pagerank, embedding-rerank, hybrid`},400);let E=_,y=i.req.query("max_depth"),w=y!==void 0?Number(y):2;if(!Number.isFinite(w)||w<1)return i.json({error:"max_depth must be a number \u2265 1"},400);let N,k=i.req.query("edge_types");if(k){let P=k.split(",").map(q=>q.trim()).filter(Boolean);for(let q of P)if(!o.has(q))return i.json({error:`invalid edge_type: ${q}`},400);N=P}let C=i.req.query("include_wiki_links"),I=C===void 0?!0:!(C==="0"||C==="false"),j=i.req.query("include_suggestions"),v=j==="1"||j==="true";try{let P=js(l,{budget:g,scoring:E,maxDepth:w,edgeTypes:N,includeWikiLinks:I,includeSuggestions:v});return i.json(P)}catch(P){let q=P instanceof Error?P.message:"unknown error",K=/not found/.test(q)?404:500;return i.json({error:q},K)}}),t.get("/api/bug-patterns",i=>{let l=i.req.query("min_count"),p=i.req.query("status"),g=i.req.query("project")??void 0,_=i.req.query("limit"),E=i.req.query("offset"),y=l?Number(l):void 0;if(y!==void 0&&(!Number.isFinite(y)||y<1))return i.json({error:"min_count must be a positive integer"},400);let w;if(p==="open")w=!1;else if(p==="resolved")w=!0;else if(p&&p!=="all")return i.json({error:`invalid status: ${p}; valid: open, resolved, all`},400);let N=_?Number(_):void 0;if(N!==void 0&&(!Number.isFinite(N)||N<1))return i.json({error:"invalid limit"},400);let k=E?Number(E):void 0;if(k!==void 0&&(!Number.isFinite(k)||k<0))return i.json({error:"invalid offset"},400);try{let C=ca({minOccurrenceCount:y,hasResolved:w,project:g,limit:N,offset:k});return i.json(C)}catch(C){return i.json({error:C.message},400)}}),t.get("/api/bug-patterns/setup-status",i=>{let l=f(),g=l.prepare(`SELECT p.name AS project,
1839
1853
  COUNT(s.id) AS total_sessions,
1840
1854
  SUM(CASE WHEN oi.session_id IS NOT NULL THEN 1 ELSE 0 END) AS extracted_sessions,
1841
1855
  MAX(oi.extracted_at) AS last_extracted_at
@@ -1843,20 +1857,20 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1843
1857
  LEFT JOIN sessions s ON s.project_id = p.id
1844
1858
  LEFT JOIN session_output_index oi ON oi.session_id = s.id
1845
1859
  GROUP BY p.id
1846
- ORDER BY total_sessions DESC`).all().map(y=>({project:y.project,total_sessions:y.total_sessions??0,extracted_sessions:y.extracted_sessions??0,remaining_sessions:(y.total_sessions??0)-(y.extracted_sessions??0),last_extracted_at:y.last_extracted_at})),_=g.reduce((y,k)=>(y.total_sessions+=k.total_sessions,y.extracted_sessions+=k.extracted_sessions,y.remaining_sessions+=k.remaining_sessions,y),{total_sessions:0,extracted_sessions:0,remaining_sessions:0}),E=l.prepare("SELECT COUNT(*) AS n FROM bug_pattern_clusters").get();return i.json({projects:g,totals:{..._,cluster_count:E.n}})});let d=D.object({project:D.string().min(1),model:D.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional(),limit:D.number().int().positive().optional(),force:D.boolean().optional()});t.post("/api/extract-outputs/preflight",async i=>{let l=Ce(i);if(l)return l;let p=Ro();if(p>0&&p<1*1024**3)return i.json({error:"insufficient-disk-space",message:`${(p/1024**3).toFixed(2)} GB free \u2014 extract-outputs needs at least 1 GB headroom. Free up disk and retry.`,freeBytes:p},507);let g=await i.req.json().catch(()=>null),_=d.safeParse(g);if(!_.success)return i.json({error:"invalid request body",details:_.error.format()},400);let E={project:_.data.project,model:_.data.model??nt,limit:_.data.limit??200,force:_.data.force??!1},y=Jo();if(E.limit>y.sessionCeiling)return re({kind:"run-rejected",job_id:null,project:E.project,model:E.model,limit:E.limit,origin:i.req.header("origin")??null,reason:`limit ${E.limit} exceeds session ceiling ${y.sessionCeiling}`}),i.json({error:`requested limit ${E.limit} exceeds session ceiling ${y.sessionCeiling}. Lower the limit or edit launcher.sessionCeiling in ~/.recall/config.json.`},400);let k=dn(E.project);if(!k)return i.json({error:`project "${E.project}" not found`},404);let A=ft({projectId:k.id,limit:E.limit,force:E.force}).eligible.length,O=Yo(A),C=We(A,E.model),v=Nt(),L=O.estimated_input_tokens_max+O.estimated_output_tokens_max>v.remaining_tokens_24h;if(re({kind:"preflight",job_id:null,project:E.project,model:E.model,limit:E.limit,origin:i.req.header("origin")??null,sessions_eligible:A}),A===0)return i.json({eligible_session_count:0,...O,plan_window_estimate:C,budget:v,would_exceed_budget:!1,preflight_token:null,expires_at:null,message:"No eligible sessions to extract. Pass force=true to re-extract sessions already at the current extractor version."});let{token:F,expiresAt:q}=Ho(E);return i.json({preflight_token:F,expires_at:new Date(q).toISOString(),eligible_session_count:A,...O,plan_window_estimate:C,budget:v,would_exceed_budget:L})});let m=D.object({preflight_token:D.string().length(64)});t.post("/api/extract-outputs/run",async i=>{let l=Ce(i);if(l)return l;let p=await i.req.json().catch(()=>null),g=m.safeParse(p);if(!g.success)return i.json({error:"invalid request body"},400);let _=Wo(g.data.preflight_token);if(!_)return re({kind:"run-rejected",job_id:null,project:null,model:null,limit:null,origin:i.req.header("origin")??null,reason:"preflight token invalid, expired, or already used"}),i.json({error:"preflight token invalid, expired, or already used"},400);let E=Nt(),k=(()=>{let C=dn(_.project);return C?ft({projectId:C.id,limit:_.limit,force:_.force}):null})()?.eligible.length??0,N=Yo(k),A=N.estimated_input_tokens_max+N.estimated_output_tokens_max;if(A>E.remaining_tokens_24h)return re({kind:"run-rejected",job_id:null,project:_.project,model:_.model,limit:_.limit,origin:i.req.header("origin")??null,reason:`projected spend ${A} exceeds remaining 24h budget ${E.remaining_tokens_24h}`}),i.json({error:"daily token budget would be exceeded. Wait for the rolling 24h window to clear, or raise launcher.dailyTokenBudget in ~/.recall/config.json.",budget:E,projected_spend:A},429);let O=gd({project:_.project,model:_.model,limit:_.limit,force:_.force,origin:i.req.header("origin")??null});return"error"in O?i.json({error:O.error},400):i.json({jobId:O.jobId,reused:O.reused},O.reused?409:200)}),t.get("/api/extract-outputs/jobs/:jobId/stream",i=>{let l=i.req.param("jobId");if(!Ko(l))return i.json({error:"job not found"},404);let g=Number(i.req.header("Last-Event-ID")??0);return Ge(i,async _=>{let E=!1,y=setInterval(()=>{E||_.writeSSE({event:"heartbeat",data:""}).catch(()=>{E=!0})},15e3);try{for await(let k of _d(l,g))if(E||(await _.writeSSE({id:String(k.id),event:k.kind,data:JSON.stringify(k.data)}),k.kind==="done"))break}finally{E=!0,clearInterval(y)}})}),t.get("/api/extract-outputs/jobs/:jobId",i=>{let l=Ko(i.req.param("jobId"));return l?i.json(l):i.json({error:"job not found"},404)}),t.delete("/api/extract-outputs/jobs/:jobId",i=>{let l=Ce(i);return l||(fd(i.req.param("jobId"))?i.json({ok:!0}):i.json({error:"job not found or already done"},404))}),t.get("/api/extract-outputs/budget",i=>i.json(Nt()));let h=D.object({scope:D.enum(["cluster","project"]),target_id:D.string().min(1),mode:D.enum(["synopsis","priorities","root_cause"]),model:D.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional()});t.post("/api/bug-patterns/synthesize/preflight",async i=>{{let q=Ro();if(q>0&&q<1*1024**3)return i.json({error:"insufficient-disk-space",message:`${(q/1024**3).toFixed(2)} GB free \u2014 bug synthesis needs at least 1 GB headroom. Free up disk and retry.`,freeBytes:q},507)}let l=Ce(i);if(l)return l;let p=await i.req.json().catch(()=>null),g=h.safeParse(p);if(!g.success)return i.json({error:"invalid request body",details:g.error.format()},400);let _={scope:g.data.scope,target_id:g.data.target_id,mode:g.data.mode,model:g.data.model??hd},E=Ps(_);if(!E)return re({kind:"synth-rejected",job_id:null,project:_.scope==="project"?_.target_id:null,model:_.model,limit:null,origin:i.req.header("origin")??null,reason:"target not found"}),i.json({error:_.scope==="cluster"?`cluster "${_.target_id}" not found in any extracted findings`:`project "${_.target_id}" has no extracted findings to synthesize`},404);let y=Go({scope:_.scope,mode:_.mode,member_session_count:E.context_summary.session_count,cluster_count:E.context_summary.cluster_count}),k=y.estimated_input_tokens_max+y.estimated_output_tokens_max,N=md(k),A=We(N,_.model),O=Nt(),v=y.estimated_input_tokens_max+y.estimated_output_tokens_max>O.remaining_tokens_24h;re({kind:"synth-preflight",job_id:null,project:_.scope==="project"?_.target_id:null,model:_.model,limit:null,origin:i.req.header("origin")??null,reason:`${_.scope}/${_.mode}/${_.target_id}`});let{token:L,expiresAt:F}=Ho({project:_.target_id,model:_.model,limit:1,force:!1});return Qs.set(L,_),setTimeout(()=>Qs.delete(L),9e4).unref?.(),i.json({preflight_token:L,expires_at:new Date(F).toISOString(),estimated_input_tokens_max:y.estimated_input_tokens_max,estimated_output_tokens_max:y.estimated_output_tokens_max,plan_window_estimate:A,budget:O,would_exceed_budget:v,context_summary:E.context_summary})});let S=D.object({preflight_token:D.string().length(64)});t.post("/api/bug-patterns/synthesize/run",async i=>{let l=Ce(i);if(l)return l;let p=await i.req.json().catch(()=>null),g=S.safeParse(p);if(!g.success)return i.json({error:"invalid request body"},400);let _=Wo(g.data.preflight_token),E=Qs.get(g.data.preflight_token)??null;if(Qs.delete(g.data.preflight_token),!E||!_)return re({kind:"synth-rejected",job_id:null,project:null,model:null,limit:null,origin:i.req.header("origin")??null,reason:"preflight token invalid, expired, or already used"}),i.json({error:"preflight token invalid, expired, or already used"},400);let y=Nt(),k=Ps(E);if(!k)return i.json({error:E.scope==="cluster"?`cluster "${E.target_id}" no longer exists`:`project "${E.target_id}" has no findings`},404);let N=Go({scope:E.scope,mode:E.mode,member_session_count:k.context_summary.session_count,cluster_count:k.context_summary.cluster_count}),A=N.estimated_input_tokens_max+N.estimated_output_tokens_max;if(A>y.remaining_tokens_24h)return re({kind:"synth-rejected",job_id:null,project:E.scope==="project"?E.target_id:null,model:E.model,limit:null,origin:i.req.header("origin")??null,reason:`projected spend ${A} exceeds remaining 24h budget ${y.remaining_tokens_24h}`}),i.json({error:"daily token budget would be exceeded. Wait for the rolling 24h window to clear, or raise launcher.dailyTokenBudget in ~/.recall/config.json.",budget:y,projected_spend:A},429);let O=Td({intent:E,origin:i.req.header("origin")??null});return"error"in O?i.json({error:O.error},400):i.json({jobId:O.jobId,reused:O.reused},O.reused?409:200)}),t.get("/api/bug-patterns/synthesize/jobs/:jobId/stream",i=>{let l=i.req.param("jobId");if(!Vo(l))return i.json({error:"job not found"},404);let g=Number(i.req.header("Last-Event-ID")??0);return Ge(i,async _=>{let E=!1,y=setInterval(()=>{E||_.writeSSE({event:"heartbeat",data:""}).catch(()=>{E=!0})},15e3);try{for await(let k of yd(l,g))if(E||(await _.writeSSE({id:String(k.id),event:k.kind,data:JSON.stringify(k.data)}),k.kind==="done"))break}finally{E=!0,clearInterval(y)}})}),t.get("/api/bug-patterns/synthesize/jobs/:jobId",i=>{let l=Vo(i.req.param("jobId"));return l?i.json(l):i.json({error:"job not found"},404)}),t.delete("/api/bug-patterns/synthesize/jobs/:jobId",i=>{let l=Ce(i);return l||(wd(i.req.param("jobId"))?i.json({ok:!0}):i.json({error:"job not found or already done"},404))}),t.get("/api/bug-signatures",i=>{let l=i.req.query("project")??null,p=Math.min(Math.max(1,Number(i.req.query("limit")??100)),500),g=f(),_=["oi.bug_signatures IS NOT NULL"],E=[];l&&(_.push("p.name = ?"),E.push(l));let k=g.prepare(`SELECT s.id AS session_id, p.name AS project, s.auto_title,
1860
+ ORDER BY total_sessions DESC`).all().map(y=>({project:y.project,total_sessions:y.total_sessions??0,extracted_sessions:y.extracted_sessions??0,remaining_sessions:(y.total_sessions??0)-(y.extracted_sessions??0),last_extracted_at:y.last_extracted_at})),_=g.reduce((y,w)=>(y.total_sessions+=w.total_sessions,y.extracted_sessions+=w.extracted_sessions,y.remaining_sessions+=w.remaining_sessions,y),{total_sessions:0,extracted_sessions:0,remaining_sessions:0}),E=l.prepare("SELECT COUNT(*) AS n FROM bug_pattern_clusters").get();return i.json({projects:g,totals:{..._,cluster_count:E.n}})});let d=D.object({project:D.string().min(1),model:D.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional(),limit:D.number().int().positive().optional(),force:D.boolean().optional()});t.post("/api/extract-outputs/preflight",async i=>{let l=Ce(i);if(l)return l;let p=xo();if(p>0&&p<1*1024**3)return i.json({error:"insufficient-disk-space",message:`${(p/1024**3).toFixed(2)} GB free \u2014 extract-outputs needs at least 1 GB headroom. Free up disk and retry.`,freeBytes:p},507);let g=await i.req.json().catch(()=>null),_=d.safeParse(g);if(!_.success)return i.json({error:"invalid request body",details:_.error.format()},400);let E={project:_.data.project,model:_.data.model??tt,limit:_.data.limit??200,force:_.data.force??!1},y=zo();if(E.limit>y.sessionCeiling)return re({kind:"run-rejected",job_id:null,project:E.project,model:E.model,limit:E.limit,origin:i.req.header("origin")??null,reason:`limit ${E.limit} exceeds session ceiling ${y.sessionCeiling}`}),i.json({error:`requested limit ${E.limit} exceeds session ceiling ${y.sessionCeiling}. Lower the limit or edit launcher.sessionCeiling in ~/.recall/config.json.`},400);let w=dn(E.project);if(!w)return i.json({error:`project "${E.project}" not found`},404);let k=ft({projectId:w.id,limit:E.limit,force:E.force}).eligible.length,C=Ko(k),I=We(k,E.model),j=Nt(),v=C.estimated_input_tokens_max+C.estimated_output_tokens_max>j.remaining_tokens_24h;if(re({kind:"preflight",job_id:null,project:E.project,model:E.model,limit:E.limit,origin:i.req.header("origin")??null,sessions_eligible:k}),k===0)return i.json({eligible_session_count:0,...C,plan_window_estimate:I,budget:j,would_exceed_budget:!1,preflight_token:null,expires_at:null,message:"No eligible sessions to extract. Pass force=true to re-extract sessions already at the current extractor version."});let{token:P,expiresAt:q}=Xo(E);return i.json({preflight_token:P,expires_at:new Date(q).toISOString(),eligible_session_count:k,...C,plan_window_estimate:I,budget:j,would_exceed_budget:v})});let m=D.object({preflight_token:D.string().length(64)});t.post("/api/extract-outputs/run",async i=>{let l=Ce(i);if(l)return l;let p=await i.req.json().catch(()=>null),g=m.safeParse(p);if(!g.success)return i.json({error:"invalid request body"},400);let _=Jo(g.data.preflight_token);if(!_)return re({kind:"run-rejected",job_id:null,project:null,model:null,limit:null,origin:i.req.header("origin")??null,reason:"preflight token invalid, expired, or already used"}),i.json({error:"preflight token invalid, expired, or already used"},400);let E=Nt(),w=(()=>{let I=dn(_.project);return I?ft({projectId:I.id,limit:_.limit,force:_.force}):null})()?.eligible.length??0,N=Ko(w),k=N.estimated_input_tokens_max+N.estimated_output_tokens_max;if(k>E.remaining_tokens_24h)return re({kind:"run-rejected",job_id:null,project:_.project,model:_.model,limit:_.limit,origin:i.req.header("origin")??null,reason:`projected spend ${k} exceeds remaining 24h budget ${E.remaining_tokens_24h}`}),i.json({error:"daily token budget would be exceeded. Wait for the rolling 24h window to clear, or raise launcher.dailyTokenBudget in ~/.recall/config.json.",budget:E,projected_spend:k},429);let C=Td({project:_.project,model:_.model,limit:_.limit,force:_.force,origin:i.req.header("origin")??null});return"error"in C?i.json({error:C.error},400):i.json({jobId:C.jobId,reused:C.reused},C.reused?409:200)}),t.get("/api/extract-outputs/jobs/:jobId/stream",i=>{let l=i.req.param("jobId");if(!Qo(l))return i.json({error:"job not found"},404);let g=Number(i.req.header("Last-Event-ID")??0);return Ye(i,async _=>{let E=!1,y=setInterval(()=>{E||_.writeSSE({event:"heartbeat",data:""}).catch(()=>{E=!0})},15e3);try{for await(let w of yd(l,g))if(E||(await _.writeSSE({id:String(w.id),event:w.kind,data:JSON.stringify(w.data)}),w.kind==="done"))break}finally{E=!0,clearInterval(y)}})}),t.get("/api/extract-outputs/jobs/:jobId",i=>{let l=Qo(i.req.param("jobId"));return l?i.json(l):i.json({error:"job not found"},404)}),t.delete("/api/extract-outputs/jobs/:jobId",i=>{let l=Ce(i);return l||(wd(i.req.param("jobId"))?i.json({ok:!0}):i.json({error:"job not found or already done"},404))}),t.get("/api/extract-outputs/budget",i=>i.json(Nt()));let h=D.object({scope:D.enum(["cluster","project"]),target_id:D.string().min(1),mode:D.enum(["synopsis","priorities","root_cause"]),model:D.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional()});t.post("/api/bug-patterns/synthesize/preflight",async i=>{{let q=xo();if(q>0&&q<1*1024**3)return i.json({error:"insufficient-disk-space",message:`${(q/1024**3).toFixed(2)} GB free \u2014 bug synthesis needs at least 1 GB headroom. Free up disk and retry.`,freeBytes:q},507)}let l=Ce(i);if(l)return l;let p=await i.req.json().catch(()=>null),g=h.safeParse(p);if(!g.success)return i.json({error:"invalid request body",details:g.error.format()},400);let _={scope:g.data.scope,target_id:g.data.target_id,mode:g.data.mode,model:g.data.model??Rd},E=$s(_);if(!E)return re({kind:"synth-rejected",job_id:null,project:_.scope==="project"?_.target_id:null,model:_.model,limit:null,origin:i.req.header("origin")??null,reason:"target not found"}),i.json({error:_.scope==="cluster"?`cluster "${_.target_id}" not found in any extracted findings`:`project "${_.target_id}" has no extracted findings to synthesize`},404);let y=Vo({scope:_.scope,mode:_.mode,member_session_count:E.context_summary.session_count,cluster_count:E.context_summary.cluster_count}),w=y.estimated_input_tokens_max+y.estimated_output_tokens_max,N=Sd(w),k=We(N,_.model),C=Nt(),j=y.estimated_input_tokens_max+y.estimated_output_tokens_max>C.remaining_tokens_24h;re({kind:"synth-preflight",job_id:null,project:_.scope==="project"?_.target_id:null,model:_.model,limit:null,origin:i.req.header("origin")??null,reason:`${_.scope}/${_.mode}/${_.target_id}`});let{token:v,expiresAt:P}=Xo({project:_.target_id,model:_.model,limit:1,force:!1});return er.set(v,_),setTimeout(()=>er.delete(v),9e4).unref?.(),i.json({preflight_token:v,expires_at:new Date(P).toISOString(),estimated_input_tokens_max:y.estimated_input_tokens_max,estimated_output_tokens_max:y.estimated_output_tokens_max,plan_window_estimate:k,budget:C,would_exceed_budget:j,context_summary:E.context_summary})});let b=D.object({preflight_token:D.string().length(64)});t.post("/api/bug-patterns/synthesize/run",async i=>{let l=Ce(i);if(l)return l;let p=await i.req.json().catch(()=>null),g=b.safeParse(p);if(!g.success)return i.json({error:"invalid request body"},400);let _=Jo(g.data.preflight_token),E=er.get(g.data.preflight_token)??null;if(er.delete(g.data.preflight_token),!E||!_)return re({kind:"synth-rejected",job_id:null,project:null,model:null,limit:null,origin:i.req.header("origin")??null,reason:"preflight token invalid, expired, or already used"}),i.json({error:"preflight token invalid, expired, or already used"},400);let y=Nt(),w=$s(E);if(!w)return i.json({error:E.scope==="cluster"?`cluster "${E.target_id}" no longer exists`:`project "${E.target_id}" has no findings`},404);let N=Vo({scope:E.scope,mode:E.mode,member_session_count:w.context_summary.session_count,cluster_count:w.context_summary.cluster_count}),k=N.estimated_input_tokens_max+N.estimated_output_tokens_max;if(k>y.remaining_tokens_24h)return re({kind:"synth-rejected",job_id:null,project:E.scope==="project"?E.target_id:null,model:E.model,limit:null,origin:i.req.header("origin")??null,reason:`projected spend ${k} exceeds remaining 24h budget ${y.remaining_tokens_24h}`}),i.json({error:"daily token budget would be exceeded. Wait for the rolling 24h window to clear, or raise launcher.dailyTokenBudget in ~/.recall/config.json.",budget:y,projected_spend:k},429);let C=Nd({intent:E,origin:i.req.header("origin")??null});return"error"in C?i.json({error:C.error},400):i.json({jobId:C.jobId,reused:C.reused},C.reused?409:200)}),t.get("/api/bug-patterns/synthesize/jobs/:jobId/stream",i=>{let l=i.req.param("jobId");if(!ei(l))return i.json({error:"job not found"},404);let g=Number(i.req.header("Last-Event-ID")??0);return Ye(i,async _=>{let E=!1,y=setInterval(()=>{E||_.writeSSE({event:"heartbeat",data:""}).catch(()=>{E=!0})},15e3);try{for await(let w of Od(l,g))if(E||(await _.writeSSE({id:String(w.id),event:w.kind,data:JSON.stringify(w.data)}),w.kind==="done"))break}finally{E=!0,clearInterval(y)}})}),t.get("/api/bug-patterns/synthesize/jobs/:jobId",i=>{let l=ei(i.req.param("jobId"));return l?i.json(l):i.json({error:"job not found"},404)}),t.delete("/api/bug-patterns/synthesize/jobs/:jobId",i=>{let l=Ce(i);return l||(Ld(i.req.param("jobId"))?i.json({ok:!0}):i.json({error:"job not found or already done"},404))}),t.get("/api/bug-signatures",i=>{let l=i.req.query("project")??null,p=Math.min(Math.max(1,Number(i.req.query("limit")??100)),500),g=f(),_=["oi.bug_signatures IS NOT NULL"],E=[];l&&(_.push("p.name = ?"),E.push(l));let w=g.prepare(`SELECT s.id AS session_id, p.name AS project, s.auto_title,
1847
1861
  s.started_at, oi.extracted_at, oi.bug_signatures
1848
1862
  FROM session_output_index oi
1849
1863
  JOIN sessions s ON s.id = oi.session_id
1850
1864
  JOIN projects p ON p.id = s.project_id
1851
1865
  WHERE ${_.join(" AND ")}
1852
1866
  ORDER BY oi.extracted_at DESC
1853
- LIMIT ?`).all(...E,p).map(v=>{let L=[];try{let F=JSON.parse(v.bug_signatures);Array.isArray(F)&&(L=F)}catch{L=[]}return{session_id:v.session_id,project:v.project,auto_title:v.auto_title,started_at:v.started_at,extracted_at:v.extracted_at,rawSignatures:L}}),N=k.flatMap(v=>v.rawSignatures.map(L=>L.message_hash).filter(L=>typeof L=="string")),A=Fo(N),O=k.map(v=>({session_id:v.session_id,project:v.project,auto_title:v.auto_title,started_at:v.started_at,extracted_at:v.extracted_at,signatures:v.rawSignatures.map(L=>{let F=L.message_hash?A.get(L.message_hash)??null:null;return{...L,resolved:Po(F),resolution:F}}),signature_count:v.rawSignatures.length})),C=O.reduce((v,L)=>(v.sessions_total+=1,L.signature_count>0?(v.sessions_with_findings+=1,v.total_findings+=L.signature_count):v.sessions_empty+=1,v),{sessions_total:0,sessions_with_findings:0,sessions_empty:0,total_findings:0});return i.json({sessions:O,totals:C})}),t.post("/api/bug-signatures/:hash/resolve",async i=>{let l=i.req.param("hash");if(!l||l.length<4)return i.json({error:"invalid message hash"},400);let p=await i.req.json().catch(()=>({})),g=Ju({messageHash:l,resolvedInSessionId:p.resolved_in_session_id??null,fixSummary:p.fix_summary??null});return i.json({resolution:g})}),t.post("/api/bug-signatures/:hash/unresolve",i=>{let l=i.req.param("hash");return!l||l.length<4?i.json({error:"invalid message hash"},400):(Yu(l),i.json({ok:!0}))}),t.get("/api/bug-patterns/graph",i=>{let l=i.req.query("project")??null,p=i.req.query("include_resolved")!=="0",g=f(),_=["oi.bug_signatures IS NOT NULL","oi.bug_signatures != '[]'"],E=[];l&&(_.push("p.name = ?"),E.push(l));let y=g.prepare(`SELECT s.id AS session_id, p.name AS project, s.auto_title,
1867
+ LIMIT ?`).all(...E,p).map(j=>{let v=[];try{let P=JSON.parse(j.bug_signatures);Array.isArray(P)&&(v=P)}catch{v=[]}return{session_id:j.session_id,project:j.project,auto_title:j.auto_title,started_at:j.started_at,extracted_at:j.extracted_at,rawSignatures:v}}),N=w.flatMap(j=>j.rawSignatures.map(v=>v.message_hash).filter(v=>typeof v=="string")),k=Uo(N),C=w.map(j=>({session_id:j.session_id,project:j.project,auto_title:j.auto_title,started_at:j.started_at,extracted_at:j.extracted_at,signatures:j.rawSignatures.map(v=>{let P=v.message_hash?k.get(v.message_hash)??null:null;return{...v,resolved:Bo(P),resolution:P}}),signature_count:j.rawSignatures.length})),I=C.reduce((j,v)=>(j.sessions_total+=1,v.signature_count>0?(j.sessions_with_findings+=1,j.total_findings+=v.signature_count):j.sessions_empty+=1,j),{sessions_total:0,sessions_with_findings:0,sessions_empty:0,total_findings:0});return i.json({sessions:C,totals:I})}),t.post("/api/bug-signatures/:hash/resolve",async i=>{let l=i.req.param("hash");if(!l||l.length<4)return i.json({error:"invalid message hash"},400);let p=await i.req.json().catch(()=>({})),g=Qu({messageHash:l,resolvedInSessionId:p.resolved_in_session_id??null,fixSummary:p.fix_summary??null});return i.json({resolution:g})}),t.post("/api/bug-signatures/:hash/unresolve",i=>{let l=i.req.param("hash");return!l||l.length<4?i.json({error:"invalid message hash"},400):(ed(l),i.json({ok:!0}))}),t.get("/api/bug-patterns/graph",i=>{let l=i.req.query("project")??null,p=i.req.query("include_resolved")!=="0",g=f(),_=["oi.bug_signatures IS NOT NULL","oi.bug_signatures != '[]'"],E=[];l&&(_.push("p.name = ?"),E.push(l));let y=g.prepare(`SELECT s.id AS session_id, p.name AS project, s.auto_title,
1854
1868
  s.started_at, oi.extracted_at, oi.bug_signatures
1855
1869
  FROM session_output_index oi
1856
1870
  JOIN sessions s ON s.id = oi.session_id
1857
1871
  JOIN projects p ON p.id = s.project_id
1858
1872
  WHERE ${_.join(" AND ")}
1859
- ORDER BY oi.extracted_at DESC`).all(...E),k=[];for(let $ of y){let X=[];try{let G=JSON.parse($.bug_signatures);Array.isArray(G)&&(X=G)}catch{continue}for(let G of X)k.push({sig:G,session_id:$.session_id,project:$.project,auto_title:$.auto_title})}let N=new Map;for(let $ of k){let X=$.sig.message_hash??`nohash:${($.sig.snippet??"").slice(0,64)}`,G=N.get(X);G?G.push($):N.set(X,[$])}let A=Array.from(N.keys()).filter($=>!$.startsWith("nohash:")),O=Fo(A),C=[],v=new Map,L=[];for(let[$,X]of N){let G=X[0],Q=G.sig.message_hash??null,V=Q?O.get(Q)??null:null,J=Po(V);if(!p&&J)continue;let oe=Array.from(new Set(X.map(me=>me.project))).sort(),ze=Array.from(new Set(X.map(me=>me.session_id))),Me={id:Q??$,message_hash:Q,error_type:G.sig.error_type??null,snippet:(G.sig.snippet??"").slice(0,200),file:G.sig.file??null,occurrence_count:X.length,projects:oe,resolved:J,fix_summary:V?.fix_summary??null,member_session_ids:ze};C.push(Me);for(let me of X)v.has(me.session_id)||v.set(me.session_id,{session_id:me.session_id,project:me.project,auto_title:me.auto_title}),L.push({cluster_id:Me.id,session_id:me.session_id})}let F=[],q=4,K=new Map;function Y($){let X=K.get($)??0;return X>=q?!1:(K.set($,X+1),!0)}for(let $=0;$<C.length;$+=1)for(let X=$+1;X<C.length;X+=1){let G=C[$],Q=C[X],V=null;G.error_type&&G.error_type!=="unknown"&&G.error_type===Q.error_type?V="same_error_type":G.file&&Q.file&&G.file===Q.file&&(V="same_file"),V&&(!Y(G.id)||!Y(Q.id)||F.push({a:G.id,b:Q.id,reason:V}))}return i.json({clusters:C,sessions:Array.from(v.values()),member_edges:L,related_edges:F,totals:{cluster_count:C.length,singleton_count:C.filter($=>$.occurrence_count===1).length,recurring_count:C.filter($=>$.occurrence_count>1).length,session_count:v.size,resolved_count:C.filter($=>$.resolved).length}})}),t.get("/api/bug-patterns/:clusterId",i=>{let l=i.req.param("clusterId");if(!l)return i.json({error:"clusterId required"},400);let p=na(l);return p?i.json(p):i.json({error:`cluster ${l} not found`},404)}),t.post("/api/bug-patterns/:clusterId/resolve",async i=>{let l=i.req.param("clusterId");if(!l)return i.json({error:"clusterId required"},400);let p=await i.req.json().catch(()=>null);if(!p)return i.json({error:"body required"},400);let g=p.resolved_in_session_id,_=p.fix_summary;if(typeof g!="string"||g.length===0)return i.json({error:"resolved_in_session_id required"},400);if(typeof _!="string"||_.trim().length===0)return i.json({error:"fix_summary required"},400);try{let E=sa(l,g,_);return i.json(E)}catch(E){let y=E instanceof Error?E.message:"unknown error",k=/not found/.test(y)?404:(/not a member/.test(y),400);return i.json({error:y},k)}}),t.post("/api/bug-patterns/:clusterId/split",async i=>{let l=i.req.param("clusterId");if(!l)return i.json({error:"clusterId required"},400);let p=await i.req.json().catch(()=>null);if(!p)return i.json({error:"body required"},400);let g=p.member_session_ids;if(!Array.isArray(g)||g.length===0)return i.json({error:"member_session_ids must be a non-empty array of strings"},400);let _=[];for(let E of g){if(typeof E!="string"||E.length===0)return i.json({error:"member_session_ids must contain only non-empty strings"},400);_.push(E)}try{let E=ra(l,_);return i.json(E)}catch(E){let y=E instanceof Error?E.message:"unknown error",k=/not found/.test(y)?404:(/cannot split|none of the supplied/.test(y),400);return i.json({error:y},k)}}),t.post("/api/links",async i=>{let l=await i.req.json().catch(()=>null);if(!l)return i.json({error:"body required"},400);let p=l.source_session_id,g=l.target_session_id,_=l.link_type;if(typeof p!="string"||p.length===0)return i.json({error:"source_session_id required"},400);if(typeof g!="string"||g.length===0)return i.json({error:"target_session_id required"},400);if(typeof _!="string")return i.json({error:"link_type required"},400);if(!o.has(_))return i.json({error:`invalid link_type: ${_}`},400);if(_!=="wiki_link")return i.json({error:`link_type '${_}' is not user-writable; only wiki_link is exposed via this endpoint. Other types must go through the suggestions-queue review flow.`},403);if(p===g)return i.json({error:"a session cannot link to itself"},400);let E=f();if(!E.prepare("SELECT 1 FROM sessions WHERE id = ?").get(p))return i.json({error:`source session not found: ${p}`},404);if(!E.prepare("SELECT 1 FROM sessions WHERE id = ?").get(g))return i.json({error:`target session not found: ${g}`},404);let N=jn({sourceSessionId:g,targetSessionId:p,linkType:"wiki_link"});if(N.length>0)return i.json({link:N[0]});try{let A=Ra({source_session_id:p,target_session_id:g,link_type:"wiki_link",confidence:1,source:"manual",evidence:l.evidence??{created_via:"context_menu"},approved:!0});return i.json({link:A})}catch(A){return i.json({error:A.message},400)}}),t.delete("/api/links/:id",i=>{let l=i.req.param("id"),p=Number(l);if(!Number.isInteger(p)||p<=0)return i.json({error:"id must be a positive integer"},400);let g=ka(p);return g.removed===0?i.json({error:`link ${p} not found`},404):i.json(g)}),t.get("/api/sessions/:id/links",i=>{let l=i.req.param("id");if(!l)return i.json({error:"sessionId required"},400);let p=f();if(!p.prepare("SELECT 1 FROM sessions WHERE id = ?").get(l))return i.json({error:`session not found: ${l}`},404);let _=i.req.query("type")??"wiki_link";if(!o.has(_))return i.json({error:`invalid type: ${_}`},400);let E=_,y=Jt(l).filter(v=>v.link_type===E),k=yu(l,y);if(k.length===0)return i.json({links:[]});let N=k.map(v=>v.otherSessionId),A=N.map(()=>"?").join(","),O=p.prepare(`SELECT s.id,
1873
+ ORDER BY oi.extracted_at DESC`).all(...E),w=[];for(let U of y){let X=[];try{let Y=JSON.parse(U.bug_signatures);Array.isArray(Y)&&(X=Y)}catch{continue}for(let Y of X)w.push({sig:Y,session_id:U.session_id,project:U.project,auto_title:U.auto_title})}let N=new Map;for(let U of w){let X=U.sig.message_hash??`nohash:${(U.sig.snippet??"").slice(0,64)}`,Y=N.get(X);Y?Y.push(U):N.set(X,[U])}let k=Array.from(N.keys()).filter(U=>!U.startsWith("nohash:")),C=Uo(k),I=[],j=new Map,v=[];for(let[U,X]of N){let Y=X[0],Q=Y.sig.message_hash??null,V=Q?C.get(Q)??null:null,J=Bo(V);if(!p&&J)continue;let oe=Array.from(new Set(X.map(me=>me.project))).sort(),ze=Array.from(new Set(X.map(me=>me.session_id))),Me={id:Q??U,message_hash:Q,error_type:Y.sig.error_type??null,snippet:(Y.sig.snippet??"").slice(0,200),file:Y.sig.file??null,occurrence_count:X.length,projects:oe,resolved:J,fix_summary:V?.fix_summary??null,member_session_ids:ze};I.push(Me);for(let me of X)j.has(me.session_id)||j.set(me.session_id,{session_id:me.session_id,project:me.project,auto_title:me.auto_title}),v.push({cluster_id:Me.id,session_id:me.session_id})}let P=[],q=4,K=new Map;function G(U){let X=K.get(U)??0;return X>=q?!1:(K.set(U,X+1),!0)}for(let U=0;U<I.length;U+=1)for(let X=U+1;X<I.length;X+=1){let Y=I[U],Q=I[X],V=null;Y.error_type&&Y.error_type!=="unknown"&&Y.error_type===Q.error_type?V="same_error_type":Y.file&&Q.file&&Y.file===Q.file&&(V="same_file"),V&&(!G(Y.id)||!G(Q.id)||P.push({a:Y.id,b:Q.id,reason:V}))}return i.json({clusters:I,sessions:Array.from(j.values()),member_edges:v,related_edges:P,totals:{cluster_count:I.length,singleton_count:I.filter(U=>U.occurrence_count===1).length,recurring_count:I.filter(U=>U.occurrence_count>1).length,session_count:j.size,resolved_count:I.filter(U=>U.resolved).length}})}),t.get("/api/bug-patterns/:clusterId",i=>{let l=i.req.param("clusterId");if(!l)return i.json({error:"clusterId required"},400);let p=la(l);return p?i.json(p):i.json({error:`cluster ${l} not found`},404)}),t.post("/api/bug-patterns/:clusterId/resolve",async i=>{let l=i.req.param("clusterId");if(!l)return i.json({error:"clusterId required"},400);let p=await i.req.json().catch(()=>null);if(!p)return i.json({error:"body required"},400);let g=p.resolved_in_session_id,_=p.fix_summary;if(typeof g!="string"||g.length===0)return i.json({error:"resolved_in_session_id required"},400);if(typeof _!="string"||_.trim().length===0)return i.json({error:"fix_summary required"},400);try{let E=ua(l,g,_);return i.json(E)}catch(E){let y=E instanceof Error?E.message:"unknown error",w=/not found/.test(y)?404:(/not a member/.test(y),400);return i.json({error:y},w)}}),t.post("/api/bug-patterns/:clusterId/split",async i=>{let l=i.req.param("clusterId");if(!l)return i.json({error:"clusterId required"},400);let p=await i.req.json().catch(()=>null);if(!p)return i.json({error:"body required"},400);let g=p.member_session_ids;if(!Array.isArray(g)||g.length===0)return i.json({error:"member_session_ids must be a non-empty array of strings"},400);let _=[];for(let E of g){if(typeof E!="string"||E.length===0)return i.json({error:"member_session_ids must contain only non-empty strings"},400);_.push(E)}try{let E=da(l,_);return i.json(E)}catch(E){let y=E instanceof Error?E.message:"unknown error",w=/not found/.test(y)?404:(/cannot split|none of the supplied/.test(y),400);return i.json({error:y},w)}}),t.post("/api/links",async i=>{let l=await i.req.json().catch(()=>null);if(!l)return i.json({error:"body required"},400);let p=l.source_session_id,g=l.target_session_id,_=l.link_type;if(typeof p!="string"||p.length===0)return i.json({error:"source_session_id required"},400);if(typeof g!="string"||g.length===0)return i.json({error:"target_session_id required"},400);if(typeof _!="string")return i.json({error:"link_type required"},400);if(!o.has(_))return i.json({error:`invalid link_type: ${_}`},400);if(_!=="wiki_link")return i.json({error:`link_type '${_}' is not user-writable; only wiki_link is exposed via this endpoint. Other types must go through the suggestions-queue review flow.`},403);if(p===g)return i.json({error:"a session cannot link to itself"},400);let E=f();if(!E.prepare("SELECT 1 FROM sessions WHERE id = ?").get(p))return i.json({error:`source session not found: ${p}`},404);if(!E.prepare("SELECT 1 FROM sessions WHERE id = ?").get(g))return i.json({error:`target session not found: ${g}`},404);let N=Mn({sourceSessionId:g,targetSessionId:p,linkType:"wiki_link"});if(N.length>0)return i.json({link:N[0]});try{let k=Oa({source_session_id:p,target_session_id:g,link_type:"wiki_link",confidence:1,source:"manual",evidence:l.evidence??{created_via:"context_menu"},approved:!0});return i.json({link:k})}catch(k){return i.json({error:k.message},400)}}),t.delete("/api/links/:id",i=>{let l=i.req.param("id"),p=Number(l);if(!Number.isInteger(p)||p<=0)return i.json({error:"id must be a positive integer"},400);let g=La(p);return g.removed===0?i.json({error:`link ${p} not found`},404):i.json(g)}),t.get("/api/sessions/:id/links",i=>{let l=i.req.param("id");if(!l)return i.json({error:"sessionId required"},400);let p=f();if(!p.prepare("SELECT 1 FROM sessions WHERE id = ?").get(l))return i.json({error:`session not found: ${l}`},404);let _=i.req.query("type")??"wiki_link";if(!o.has(_))return i.json({error:`invalid type: ${_}`},400);let E=_,y=Jt(l).filter(j=>j.link_type===E),w=Ou(l,y);if(w.length===0)return i.json({links:[]});let N=w.map(j=>j.otherSessionId),k=N.map(()=>"?").join(","),C=p.prepare(`SELECT s.id,
1860
1874
  NULLIF(sa.alias, '') AS alias,
1861
1875
  s.auto_title,
1862
1876
  s.first_user_message,
@@ -1864,7 +1878,7 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1864
1878
  FROM sessions s
1865
1879
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1866
1880
  LEFT JOIN projects p ON p.id = s.project_id
1867
- WHERE s.id IN (${A})`).all(...N),C=new Map(O.map(v=>[v.id,v]));return i.json({links:k.map(v=>{let L=C.get(v.otherSessionId),F=L?.alias?.trim()||L?.auto_title?.trim()||(L?.first_user_message?L.first_user_message.slice(0,80):"")||v.otherSessionId.slice(0,8);return{linkId:v.linkId,otherSessionId:v.otherSessionId,direction:v.direction,updatedAt:v.updatedAt,title:F,project:L?.project??null}})})}),t.patch("/api/links/suggestions/:id",async i=>{let l=i.req.param("id"),p=Number(l);if(!Number.isInteger(p)||p<=0)return i.json({error:"id must be a positive integer"},400);let g=await i.req.json().catch(()=>null);if(!g||typeof g.status!="string")return i.json({error:"status required (approved|rejected)"},400);if(g.status!=="approved"&&g.status!=="rejected")return i.json({error:`invalid status: ${g.status}`},400);try{let _=fr(p,g.status);return i.json(_)}catch(_){let E=_.message,y=/already decided/.test(E)?409:/not found/.test(E)?404:400;return i.json({error:E},y)}}),t.post("/api/links/suggestions/bulk-decide",async i=>{let l=await i.req.json().catch(()=>null);if(!l)return i.json({error:"body required"},400);let p=Array.isArray(l.ids)?l.ids:null;if(!p||p.length===0)return i.json({error:"ids must be a non-empty array"},400);if(p.length>1e3)return i.json({error:"bulk-decide capped at 1000 ids per call"},400);if(l.status!=="approved"&&l.status!=="rejected")return i.json({error:`invalid status: ${l.status}`},400);let g=l.status,_=0,E=0,y=[];for(let k of p){let N=Number(k);if(!Number.isInteger(N)||N<=0){y.push({id:Number.isFinite(Number(k))?Number(k):-1,error:"invalid id"});continue}try{fr(N,g),_+=1}catch(A){let O=A.message;/already decided/.test(O)?E+=1:y.push({id:N,error:O})}}return i.json({decided:_,skipped:E,errors:y})}),t.get("/api/sessions",i=>{let l=f(),p=i.req.query("project"),g=i.req.query("since"),_=i.req.query("until"),E=i.req.queries("tag")??[],y=i.req.query("collection"),k=Math.max(1,Math.min(500,Number(i.req.query("limit")??100))),N=i.req.query("cursor"),A=null;if(N)try{let K=Buffer.from(N,"base64url").toString("utf8"),Y=JSON.parse(K);typeof Y.ts=="string"&&typeof Y.id=="string"&&(A={ts:Y.ts,id:Y.id})}catch{}let O=i.req.query("system")==="1"||i.req.query("system")==="true",C={limit:k},v="s.message_count > 2"+er("s",O);if(p&&(v+=" AND (p.name LIKE @proj ESCAPE '\\' OR p.decoded_path LIKE @proj ESCAPE '\\')",C.proj=`%${An(p)}%`),g&&(v+=" AND s.started_at >= @since",C.since=g),_&&(v+=" AND s.started_at <= @until",/^\d{4}-\d{2}-\d{2}$/.test(_)?C.until=`${_}T23:59:59.999Z`:C.until=_),E.length>0&&E.map(Y=>Qe(Y)).filter(Boolean).forEach((Y,$)=>{v+=` AND s.id IN (SELECT session_id FROM session_tags WHERE tag = @tag_${$})`,C[`tag_${$}`]=Y}),y){let K=co(y);if(K.length===0)return i.json({items:[],nextCursor:null});let Y=K.map(($,X)=>`@col_${X}`).join(",");v+=` AND s.id IN (SELECT session_id FROM collection_sessions WHERE collection_id IN (${Y}))`,K.forEach(($,X)=>{C[`col_${X}`]=$})}A&&(v+=" AND (COALESCE(s.ended_at, s.started_at, '') < @cursor_ts OR (COALESCE(s.ended_at, s.started_at, '') = @cursor_ts AND s.id < @cursor_id))",C.cursor_ts=A.ts,C.cursor_id=A.id);let L=l.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
1881
+ WHERE s.id IN (${k})`).all(...N),I=new Map(C.map(j=>[j.id,j]));return i.json({links:w.map(j=>{let v=I.get(j.otherSessionId),P=v?.alias?.trim()||v?.auto_title?.trim()||(v?.first_user_message?v.first_user_message.slice(0,80):"")||j.otherSessionId.slice(0,8);return{linkId:j.linkId,otherSessionId:j.otherSessionId,direction:j.direction,updatedAt:j.updatedAt,title:P,project:v?.project??null}})})}),t.patch("/api/links/suggestions/:id",async i=>{let l=i.req.param("id"),p=Number(l);if(!Number.isInteger(p)||p<=0)return i.json({error:"id must be a positive integer"},400);let g=await i.req.json().catch(()=>null);if(!g||typeof g.status!="string")return i.json({error:"status required (approved|rejected)"},400);if(g.status!=="approved"&&g.status!=="rejected")return i.json({error:`invalid status: ${g.status}`},400);try{let _=hr(p,g.status);return i.json(_)}catch(_){let E=_.message,y=/already decided/.test(E)?409:/not found/.test(E)?404:400;return i.json({error:E},y)}}),t.post("/api/links/suggestions/bulk-decide",async i=>{let l=await i.req.json().catch(()=>null);if(!l)return i.json({error:"body required"},400);let p=Array.isArray(l.ids)?l.ids:null;if(!p||p.length===0)return i.json({error:"ids must be a non-empty array"},400);if(p.length>1e3)return i.json({error:"bulk-decide capped at 1000 ids per call"},400);if(l.status!=="approved"&&l.status!=="rejected")return i.json({error:`invalid status: ${l.status}`},400);let g=l.status,_=0,E=0,y=[];for(let w of p){let N=Number(w);if(!Number.isInteger(N)||N<=0){y.push({id:Number.isFinite(Number(w))?Number(w):-1,error:"invalid id"});continue}try{hr(N,g),_+=1}catch(k){let C=k.message;/already decided/.test(C)?E+=1:y.push({id:N,error:C})}}return i.json({decided:_,skipped:E,errors:y})}),t.get("/api/sessions",i=>{let l=f(),p=i.req.query("project"),g=i.req.query("since"),_=i.req.query("until"),E=i.req.queries("tag")??[],y=i.req.query("collection"),w=Math.max(1,Math.min(500,Number(i.req.query("limit")??100))),N=i.req.query("cursor"),k=null;if(N)try{let K=Buffer.from(N,"base64url").toString("utf8"),G=JSON.parse(K);typeof G.ts=="string"&&typeof G.id=="string"&&(k={ts:G.ts,id:G.id})}catch{}let C=i.req.query("system")==="1"||i.req.query("system")==="true",I={limit:w},j="s.message_count > 2"+tr("s",C);if(p&&(j+=" AND (p.name LIKE @proj ESCAPE '\\' OR p.decoded_path LIKE @proj ESCAPE '\\')",I.proj=`%${An(p)}%`),g&&(j+=" AND s.started_at >= @since",I.since=g),_&&(j+=" AND s.started_at <= @until",/^\d{4}-\d{2}-\d{2}$/.test(_)?I.until=`${_}T23:59:59.999Z`:I.until=_),E.length>0&&E.map(G=>Ze(G)).filter(Boolean).forEach((G,U)=>{j+=` AND s.id IN (SELECT session_id FROM session_tags WHERE tag = @tag_${U})`,I[`tag_${U}`]=G}),y){let K=lo(y);if(K.length===0)return i.json({items:[],nextCursor:null});let G=K.map((U,X)=>`@col_${X}`).join(",");j+=` AND s.id IN (SELECT session_id FROM collection_sessions WHERE collection_id IN (${G}))`,K.forEach((U,X)=>{I[`col_${X}`]=U})}k&&(j+=" AND (COALESCE(s.ended_at, s.started_at, '') < @cursor_ts OR (COALESCE(s.ended_at, s.started_at, '') = @cursor_ts AND s.id < @cursor_id))",I.cursor_ts=k.ts,I.cursor_id=k.id);let v=l.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
1868
1882
  s.message_count, s.first_user_message, s.git_branch,
1869
1883
  s.auto_title, s.auto_title_source, s.verification_status,
1870
1884
  COALESCE(s.ended_at, s.started_at, '') AS _cursor_ts,
@@ -1883,17 +1897,17 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1883
1897
  JOIN projects p ON p.id = s.project_id
1884
1898
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1885
1899
  LEFT JOIN session_notes sn ON sn.session_id = s.id
1886
- WHERE ${v}
1900
+ WHERE ${j}
1887
1901
  ORDER BY COALESCE(s.ended_at, s.started_at, '') DESC, s.id DESC
1888
- LIMIT @limit`).all(C),F=L.map(({tags_csv:K,_cursor_ts:Y,...$})=>{let X=$.id,G=I.getOrigin(X),Q=$.alias,V=Q==null?null:I.isSessionAutoLinked(X)?"auto":"manual",J=tn({auto_title:$.auto_title,auto_title_source:$.auto_title_source??null,has_alias:Q!=null&&V==="manual"});return{...$,tags:K?K.split(","):[],origin:G?{editor:G.editor,label:G.label}:null,alias_source:V,title_quality:J}}),q=null;if(L.length===k&&L.length>0){let K=L[L.length-1],Y=JSON.stringify({ts:K._cursor_ts??"",id:K.id});q=Buffer.from(Y,"utf8").toString("base64url")}return i.json({items:F,nextCursor:q})}),t.get("/api/sessions/:id",i=>{let l=f(),p=i.req.param("id"),g=l.prepare(`SELECT s.*, p.name AS project_name, p.decoded_path,
1902
+ LIMIT @limit`).all(I),P=v.map(({tags_csv:K,_cursor_ts:G,...U})=>{let X=U.id,Y=M.getOrigin(X),Q=U.alias,V=Q==null?null:M.isSessionAutoLinked(X)?"auto":"manual",J=tn({auto_title:U.auto_title,auto_title_source:U.auto_title_source??null,has_alias:Q!=null&&V==="manual"});return{...U,tags:K?K.split(","):[],origin:Y?{editor:Y.editor,label:Y.label}:null,alias_source:V,title_quality:J}}),q=null;if(v.length===w&&v.length>0){let K=v[v.length-1],G=JSON.stringify({ts:K._cursor_ts??"",id:K.id});q=Buffer.from(G,"utf8").toString("base64url")}return i.json({items:P,nextCursor:q})}),t.get("/api/sessions/:id",i=>{let l=f(),p=i.req.param("id"),g=l.prepare(`SELECT s.*, p.name AS project_name, p.decoded_path,
1889
1903
  NULLIF(sa.alias, '') AS alias
1890
1904
  FROM sessions s
1891
1905
  JOIN projects p ON p.id = s.project_id
1892
1906
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1893
- WHERE s.id = ?`).get(p);if(!g)return i.json({error:"not found"},404);let _=zt(p),E=I.getOrigin(p),y=E?{editor:E.editor,label:E.label}:null,k=g.alias==null?null:I.isSessionAutoLinked(p)?"auto":"manual",N=l.prepare(`SELECT uuid, type, role, timestamp, is_sidechain, content_text, tool_names
1907
+ WHERE s.id = ?`).get(p);if(!g)return i.json({error:"not found"},404);let _=zt(p),E=M.getOrigin(p),y=E?{editor:E.editor,label:E.label}:null,w=g.alias==null?null:M.isSessionAutoLinked(p)?"auto":"manual",N=l.prepare(`SELECT uuid, type, role, timestamp, is_sidechain, content_text, tool_names
1894
1908
  FROM messages
1895
1909
  WHERE session_id = ?
1896
- ORDER BY COALESCE(timestamp, ''), rowid`).all(p);return i.json({session:{...g,tags:_,origin:y,alias_source:k},messages:N})}),t.get("/api/tags",i=>i.json(dt())),t.get("/api/sessions/:id/tags",i=>i.json({tags:zt(i.req.param("id"))})),t.post("/api/sessions/:id/tags",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>null);if(!p||typeof p.tag!="string")return i.json({error:"tag required"},400);try{let g=ut(l,p.tag);return i.json(g)}catch(g){return i.json({error:g.message},400)}}),t.delete("/api/sessions/:id/tags/:tag",i=>{let l=i.req.param("id"),p=i.req.param("tag");return i.json(Ma(l,p))}),t.get("/api/config/auto-tag",i=>i.json(Mo(Fe()))),t.put("/api/config/auto-tag",async i=>{let l=await i.req.json().catch(()=>({})),p=Ms.partial().safeParse(l);if(!p.success)return i.json({error:"invalid config",issues:p.error.issues},400);let g=p.data;g.apiKey===void 0&&delete g.apiKey;let _=Hu(g);return _.autopilot&&_.enabled&&_.backend==="api"&&_.apiKey&&Js(),i.json(Mo(_))}),t.get("/api/onboarding",i=>{let p=f().prepare(`SELECT s.id,
1910
+ ORDER BY COALESCE(timestamp, ''), rowid`).all(p);return i.json({session:{...g,tags:_,origin:y,alias_source:w},messages:N})}),t.get("/api/tags",i=>i.json(dt())),t.get("/api/sessions/:id/tags",i=>i.json({tags:zt(i.req.param("id"))})),t.post("/api/sessions/:id/tags",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>null);if(!p||typeof p.tag!="string")return i.json({error:"tag required"},400);try{let g=ut(l,p.tag);return i.json(g)}catch(g){return i.json({error:g.message},400)}}),t.delete("/api/sessions/:id/tags/:tag",i=>{let l=i.req.param("id"),p=i.req.param("tag");return i.json(Ua(l,p))}),t.get("/api/config/auto-tag",i=>i.json(Po(Fe()))),t.put("/api/config/auto-tag",async i=>{let l=await i.req.json().catch(()=>({})),p=Ds.partial().safeParse(l);if(!p.success)return i.json({error:"invalid config",issues:p.error.issues},400);let g=p.data;g.apiKey===void 0&&delete g.apiKey;let _=zu(g);return _.autopilot&&_.enabled&&_.backend==="api"&&_.apiKey&&Gs(),i.json(Po(_))}),t.get("/api/onboarding",i=>{let p=f().prepare(`SELECT s.id,
1897
1911
  p.name AS project,
1898
1912
  s.started_at,
1899
1913
  s.ended_at,
@@ -1905,7 +1919,7 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1905
1919
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1906
1920
  WHERE s.message_count > 2
1907
1921
  ORDER BY COALESCE(s.ended_at, s.started_at, '') DESC
1908
- LIMIT 1`).get();return i.json({state:Gs(),mostRecentSession:p??null})}),t.put("/api/onboarding",async i=>{let l=await i.req.json().catch(()=>({})),p=Ys.partial().safeParse(l);return p.success?i.json(dp(p.data)):i.json({error:"invalid onboarding state",issues:p.error.issues},400)}),t.post("/api/onboarding/reset",i=>i.json(pp())),t.get("/api/config/mcp-install",i=>i.json({...qe(),claudeCliAvailable:pe()})),t.post("/api/config/mcp-install",i=>i.json({...rp(),claudeCliAvailable:pe()})),t.delete("/api/config/mcp-install",i=>i.json({...op(),claudeCliAvailable:pe()}));let b=D.object({scope:D.object({untaggedOnly:D.boolean().optional(),project:D.string().optional(),collectionId:D.string().optional(),sessionIds:D.array(D.string()).optional(),limit:D.number().int().min(1).max(500).optional()}).default({}),model:D.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional(),scanId:D.string().min(1).max(100).optional()});t.post("/api/tags/scan/claude-cli",async i=>{if(bi)return i.json({error:"a scan is already running"},409);if(!pe())return i.json({error:"claude CLI not found on PATH. Install Claude Code locally, then reload."},400);if(!qe().installed)return i.json({error:"Recall MCP is not installed in Claude Code yet, run the one-click install first."},400);let p=await i.req.json().catch(()=>({})),g=b.safeParse(p);if(!g.success)return i.json({error:"invalid scope",issues:g.error.issues},400);let _=g.data.scope,E=Fe(),y=g.data.model??E.model,k=f(),N=()=>k.prepare("SELECT COUNT(*) AS n FROM session_tags").get().n,A=N();bi=!0;let O;try{let C=g.data.scanId;O=await kr(_,{model:y,scanId:C});let v=N(),L=Math.max(0,v-A);return C&&Fn(C,{type:"done",result:{success:O.success,exitCode:O.exitCode,tagsAdded:L}}),i.json({success:O.success,exitCode:O.exitCode,tagsAdded:L,model:y,stdout:Se(O.stdout.slice(0,2e3)).redacted,stderrTail:Se(O.stderr.slice(-2e3)).redacted})}finally{bi=!1}}),t.get("/api/claude-cli/scan/:scanId/progress",i=>{let l=i.req.param("scanId");return Ge(i,async p=>{let g=[],_={resolve:()=>{}},E=new Promise(A=>{_.resolve=A}),y=Pa(l,A=>{g.push(A);let O=_.resolve;E=new Promise(C=>{_.resolve=C}),O()}),k=!1,N=setInterval(()=>{k||p.writeSSE({event:"heartbeat",data:""}).catch(()=>{k=!0})},15e3);try{for(;!k;){g.length===0&&await E;let A=g.shift();if(A&&(await p.writeSSE({event:A.type,data:JSON.stringify(A)}),A.type==="done"))break}}finally{k=!0,clearInterval(N),y()}})}),t.get("/api/prompts",i=>i.json({prompts:yr.map(l=>({name:l.name,title:l.title,description:l.description})),claudeCliAvailable:pe()})),t.post("/api/prompts/run",async i=>{if(!pe())return i.json({error:"claude CLI not found on PATH. Install Claude Code locally, then reload."},400);if(!qe().installed)return i.json({error:"Recall MCP is not installed in Claude Code yet, run the one-click install first."},400);let p=await i.req.json().catch(()=>({})),_=D.object({name:D.string(),args:D.record(D.string(),D.unknown()).optional(),model:D.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional()}).safeParse(p);if(!_.success)return i.json({error:"invalid request",issues:_.error.issues},400);let E=Fa(_.data.name);if(!E)return i.json({error:`unknown prompt: ${_.data.name}`},404);let y=E.build(_.data.args??{}),k=Fe(),N=_.data.model??k.model,A=await et(y,E.allowedTools,{model:N});return i.json({success:A.success,exitCode:A.exitCode,promptName:E.name,model:N,stdout:A.stdout,stderrTail:A.stderr.slice(-4e3)})}),t.get("/api/autopilot/status",i=>i.json(Tn())),t.get("/api/autopilot/events",i=>Ge(i,async l=>{await l.writeSSE({event:"state",data:JSON.stringify(Tn())});let p=[],g=()=>{},_=new Promise(y=>g=y),E=ep(y=>{p.push(y);let k=g;_=new Promise(N=>g=N),k()});try{for(;;){if(p.length===0){let k=new Promise(A=>setTimeout(()=>A("tick"),3e4));if(await Promise.race([_.then(()=>"event"),k])==="tick"){await l.writeSSE({event:"heartbeat",data:"1"});continue}}let y=p.shift();y&&await l.writeSSE({event:"state",data:JSON.stringify(y)})}}finally{E()}})),t.post("/api/autopilot/kick",i=>(Js(),i.json({ok:!0,snapshot:Tn()})));let T=D.object({scope:D.object({untaggedOnly:D.boolean().optional(),project:D.string().optional(),collectionId:D.string().optional(),sessionIds:D.array(D.string()).optional(),limit:D.number().int().min(1).max(500).optional()}).default({})});t.post("/api/tags/scan",async i=>{let l=Fe();if(!l.enabled)return i.json({error:"auto-tagging is disabled"},403);if(l.backend!=="api")return i.json({error:"api-backend scan requires backend=api in config"},400);if(!l.apiKey)return i.json({error:"no api key configured"},400);let p=await i.req.json().catch(()=>({})),g=T.safeParse(p);if(!g.success)return i.json({error:"invalid scope",issues:g.error.issues},400);let _=mt(g.data.scope);if(_.length===0)return i.json({error:"no sessions match scope"},400);let E=Yd(_.length);return Zd(E,{apiKey:l.apiKey,model:l.model,minTags:l.minTagsPerSession,maxTags:l.maxTagsPerSession,sessions:_}),i.json({scanId:E.id,total:E.total})}),t.get("/api/tags/scan/:id",i=>{let l=Bs(i.req.param("id"));if(!l)return i.json({error:"scan not found"},404);let{controller:p,listeners:g,..._}=l;return i.json(_)}),t.get("/api/tags/scan/:id/events",i=>{let l=Bs(i.req.param("id"));return l?Ge(i,async p=>{await p.writeSSE({event:"state",data:JSON.stringify({completed:l.completed,total:l.total,status:l.status})});for(let k of l.results)await p.writeSSE({event:"result",data:JSON.stringify(k)});let g=[],_={resolve:()=>{}},E=new Promise(k=>{_.resolve=k}),y=Gd(l,k=>{g.push(k);let N=_.resolve;E=new Promise(A=>{_.resolve=A}),N()});try{for(;l.status==="running"||l.status==="pending";){g.length===0&&await E;let k=g.shift();if(k&&(await p.writeSSE({event:k.type,data:JSON.stringify(k)}),k.type==="done"||k.type==="status"&&(k.status==="cancelled"||k.status==="failed")))break}}finally{y()}}):i.json({error:"scan not found"},404)});let R=D.object({selection:D.array(D.object({sessionId:D.string(),tags:D.array(D.string()).min(1)}))});t.post("/api/tags/scan/:id/apply",async i=>{let l=Bs(i.req.param("id"));if(!l)return i.json({error:"scan not found"},404);let p=await i.req.json().catch(()=>({})),g=R.safeParse(p);if(!g.success)return i.json({error:"invalid selection"},400);let _=Qd(l,g.data.selection);return i.json(_)}),t.delete("/api/tags/scan/:id",i=>{let l=i.req.param("id");return zd(l),Kd(l),i.json({ok:!0})}),t.put("/api/sessions/:id/alias",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>null);if(!p||typeof p.alias!="string")return i.json({error:"alias required"},400);try{let g=he(l,p.alias);if(p.pin===!0)I.unlinkSession(l);else{let _=f().prepare("SELECT cwd, started_at FROM sessions WHERE id = ?").get(l),E=_?.cwd?_.cwd.replace(/\/+$/,""):null,y=!1;if(E&&_?.started_at){let k=Date.parse(_.started_at),N=_.started_at,A=I.all().filter(O=>O.cwd&&O.cwd.replace(/\/+$/,"")===E&&on({sessionStartedAt:N,terminalOpenedAt:O.opened_at??null}).allowed);if(Number.isFinite(k)&&A.length>0){let C=A.map(v=>({t:v,gap:k-Date.parse(v.opened_at??"")})).filter(v=>Number.isFinite(v.gap)).sort((v,L)=>v.gap-L.gap)[0];C&&(I.linkSession(l,C.t.shell_pid),y=!0)}}y||I.unlinkSession(l)}return i.json(g)}catch(g){return i.json({error:g.message},400)}}),t.delete("/api/sessions/:id/alias",i=>{let l=i.req.param("id");return Qn(l),I.unlinkSession(l),i.json({ok:!0})}),t.get("/api/sessions/:id/alias",i=>{let l=i.req.param("id");return i.json({alias:Te(l)})}),t.get("/api/config/auto-title",i=>i.json(rt())),t.put("/api/config/auto-title",async i=>{let l=await i.req.json().catch(()=>({})),p=us.partial().safeParse(l);return p.success?i.json(ol(p.data)):i.json({error:"invalid config",issues:p.error.issues},400)}),t.get("/api/sessions/:id/auto-title",i=>{let l=i.req.param("id"),p=Le(l);return p?i.json(p):i.json({error:"session not found"},404)}),t.post("/api/sessions/:id/auto-title",async i=>{let l=i.req.param("id");if(!rt().agentEnabled)return i.json({error:"autoTitle.agentEnabled is false"},403);if(!f().prepare("SELECT 1 FROM sessions WHERE id = ?").get(l))return i.json({error:"session not found"},404);try{let E=await zc(l);return Ee(l,E,"agent"),i.json(Le(l))}catch(E){return i.json({error:E.message,code:"agent-title-failed"},500)}}),t.post("/api/sessions/:id/auto-title/revert",i=>{let l=i.req.param("id"),p=Le(l);if(!p)return i.json({error:"session not found"},404);let g=p.auto_title_history;if(!g||g.length===0)return i.json({error:"no prior title to revert to",code:"no-history"},422);let _=g[g.length-1];return Ee(l,_.title,"agent"),i.json(Le(l))}),t.post("/api/sessions/:id/regenerate-title",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>({})),g=p.model??Ds;try{let _=await Do(l,{model:g,force:p.force===!0,budget:typeof p.budget=="number"?p.budget:void 0,signal:i.req.raw.signal}),E=Le(l),y=E?.auto_title_history&&E.auto_title_history.length>0?E.auto_title_history[E.auto_title_history.length-1].title:null;return i.json({..._,previous_title:y})}catch(_){if(_ instanceof At)return i.json({error:_.message,code:"no-context-available",session_id:_.sessionId},422);let E=_ instanceof Error?_.message:"unknown error",y=/not found|unknown/i.test(E)?404:500;return i.json({error:E,code:"regenerate-failed"},y)}}),t.post("/api/sessions/regenerate-titles-batch",async i=>{let l=await i.req.json().catch(()=>null);if(!l)return i.json({error:"body required"},400);let p=l.project;if(typeof p!="string"||p.length===0)return i.json({error:"project (string) required"},400);let g=l.quality_filter;if(!Array.isArray(g)||g.length===0)return i.json({error:"quality_filter (non-empty array) required"},400);let _=new Set(["low_signal","recursive_meta","programmatic"]),E=[];for(let L of g){if(typeof L!="string")return i.json({error:`invalid quality_filter entry: ${L}`},400);if(!_.has(L))return i.json({error:`quality_filter must be a subset of ${[..._].join(",")}; got ${L}`},400);E.push(L)}let y=typeof l.model=="string"&&l.model.length>0?l.model:Ds,k=typeof l.limit=="number"&&l.limit>0?Math.min(2e3,Math.floor(l.limit)):500,N=typeof l.budget=="number"&&l.budget>=100?Math.floor(l.budget):void 0,O=f().prepare(`SELECT s.id,
1922
+ LIMIT 1`).get();return i.json({state:zs(),mostRecentSession:p??null})}),t.put("/api/onboarding",async i=>{let l=await i.req.json().catch(()=>({})),p=Ys.partial().safeParse(l);return p.success?i.json(Ep(p.data)):i.json({error:"invalid onboarding state",issues:p.error.issues},400)}),t.post("/api/onboarding/reset",i=>i.json(bp())),t.get("/api/config/mcp-install",i=>i.json({...qe(),claudeCliAvailable:pe()})),t.post("/api/config/mcp-install",i=>i.json({...dp(),claudeCliAvailable:pe()})),t.delete("/api/config/mcp-install",i=>i.json({...pp(),claudeCliAvailable:pe()}));let S=D.object({scope:D.object({untaggedOnly:D.boolean().optional(),project:D.string().optional(),collectionId:D.string().optional(),sessionIds:D.array(D.string()).optional(),limit:D.number().int().min(1).max(500).optional()}).default({}),model:D.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional(),scanId:D.string().min(1).max(100).optional()});t.post("/api/tags/scan/claude-cli",async i=>{if(Ai)return i.json({error:"a scan is already running"},409);if(!pe())return i.json({error:"claude CLI not found on PATH. Install Claude Code locally, then reload."},400);if(!qe().installed)return i.json({error:"Recall MCP is not installed in Claude Code yet, run the one-click install first."},400);let p=await i.req.json().catch(()=>({})),g=S.safeParse(p);if(!g.success)return i.json({error:"invalid scope",issues:g.error.issues},400);let _=g.data.scope,E=Fe(),y=g.data.model??E.model,w=f(),N=()=>w.prepare("SELECT COUNT(*) AS n FROM session_tags").get().n,k=N();Ai=!0;let C;try{let I=g.data.scanId;C=await Ar(_,{model:y,scanId:I});let j=N(),v=Math.max(0,j-k);return I&&Pn(I,{type:"done",result:{success:C.success,exitCode:C.exitCode,tagsAdded:v}}),i.json({success:C.success,exitCode:C.exitCode,tagsAdded:v,model:y,stdout:Se(C.stdout.slice(0,2e3)).redacted,stderrTail:Se(C.stderr.slice(-2e3)).redacted})}finally{Ai=!1}}),t.get("/api/claude-cli/scan/:scanId/progress",i=>{let l=i.req.param("scanId");return Ye(i,async p=>{let g=[],_={resolve:()=>{}},E=new Promise(k=>{_.resolve=k}),y=Wa(l,k=>{g.push(k);let C=_.resolve;E=new Promise(I=>{_.resolve=I}),C()}),w=!1,N=setInterval(()=>{w||p.writeSSE({event:"heartbeat",data:""}).catch(()=>{w=!0})},15e3);try{for(;!w;){g.length===0&&await E;let k=g.shift();if(k&&(await p.writeSSE({event:k.type,data:JSON.stringify(k)}),k.type==="done"))break}}finally{w=!0,clearInterval(N),y()}})}),t.get("/api/prompts",i=>i.json({prompts:wr.map(l=>({name:l.name,title:l.title,description:l.description})),claudeCliAvailable:pe()})),t.post("/api/prompts/run",async i=>{if(!pe())return i.json({error:"claude CLI not found on PATH. Install Claude Code locally, then reload."},400);if(!qe().installed)return i.json({error:"Recall MCP is not installed in Claude Code yet, run the one-click install first."},400);let p=await i.req.json().catch(()=>({})),_=D.object({name:D.string(),args:D.record(D.string(),D.unknown()).optional(),model:D.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional()}).safeParse(p);if(!_.success)return i.json({error:"invalid request",issues:_.error.issues},400);let E=Ha(_.data.name);if(!E)return i.json({error:`unknown prompt: ${_.data.name}`},404);let y=E.build(_.data.args??{}),w=Fe(),N=_.data.model??w.model,k=await Qe(y,E.allowedTools,{model:N});return i.json({success:k.success,exitCode:k.exitCode,promptName:E.name,model:N,stdout:k.stdout,stderrTail:k.stderr.slice(-4e3)})}),t.get("/api/autopilot/status",i=>i.json(Tn())),t.get("/api/autopilot/events",i=>Ye(i,async l=>{await l.writeSSE({event:"state",data:JSON.stringify(Tn())});let p=[],g=()=>{},_=new Promise(y=>g=y),E=ap(y=>{p.push(y);let w=g;_=new Promise(N=>g=N),w()});try{for(;;){if(p.length===0){let w=new Promise(k=>setTimeout(()=>k("tick"),3e4));if(await Promise.race([_.then(()=>"event"),w])==="tick"){await l.writeSSE({event:"heartbeat",data:"1"});continue}}let y=p.shift();y&&await l.writeSSE({event:"state",data:JSON.stringify(y)})}}finally{E()}})),t.post("/api/autopilot/kick",i=>(Gs(),i.json({ok:!0,snapshot:Tn()})));let T=D.object({scope:D.object({untaggedOnly:D.boolean().optional(),project:D.string().optional(),collectionId:D.string().optional(),sessionIds:D.array(D.string()).optional(),limit:D.number().int().min(1).max(500).optional()}).default({})});t.post("/api/tags/scan",async i=>{let l=Fe();if(!l.enabled)return i.json({error:"auto-tagging is disabled"},403);if(l.backend!=="api")return i.json({error:"api-backend scan requires backend=api in config"},400);if(!l.apiKey)return i.json({error:"no api key configured"},400);let p=await i.req.json().catch(()=>({})),g=T.safeParse(p);if(!g.success)return i.json({error:"invalid scope",issues:g.error.issues},400);let _=mt(g.data.scope);if(_.length===0)return i.json({error:"no sessions match scope"},400);let E=ep(_.length);return op(E,{apiKey:l.apiKey,model:l.model,minTags:l.minTagsPerSession,maxTags:l.maxTagsPerSession,sessions:_}),i.json({scanId:E.id,total:E.total})}),t.get("/api/tags/scan/:id",i=>{let l=Hs(i.req.param("id"));if(!l)return i.json({error:"scan not found"},404);let{controller:p,listeners:g,..._}=l;return i.json(_)}),t.get("/api/tags/scan/:id/events",i=>{let l=Hs(i.req.param("id"));return l?Ye(i,async p=>{await p.writeSSE({event:"state",data:JSON.stringify({completed:l.completed,total:l.total,status:l.status})});for(let w of l.results)await p.writeSSE({event:"result",data:JSON.stringify(w)});let g=[],_={resolve:()=>{}},E=new Promise(w=>{_.resolve=w}),y=tp(l,w=>{g.push(w);let N=_.resolve;E=new Promise(k=>{_.resolve=k}),N()});try{for(;l.status==="running"||l.status==="pending";){g.length===0&&await E;let w=g.shift();if(w&&(await p.writeSSE({event:w.type,data:JSON.stringify(w)}),w.type==="done"||w.type==="status"&&(w.status==="cancelled"||w.status==="failed")))break}}finally{y()}}):i.json({error:"scan not found"},404)});let R=D.object({selection:D.array(D.object({sessionId:D.string(),tags:D.array(D.string()).min(1)}))});t.post("/api/tags/scan/:id/apply",async i=>{let l=Hs(i.req.param("id"));if(!l)return i.json({error:"scan not found"},404);let p=await i.req.json().catch(()=>({})),g=R.safeParse(p);if(!g.success)return i.json({error:"invalid selection"},400);let _=ip(l,g.data.selection);return i.json(_)}),t.delete("/api/tags/scan/:id",i=>{let l=i.req.param("id");return np(l),sp(l),i.json({ok:!0})}),t.put("/api/sessions/:id/alias",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>null);if(!p||typeof p.alias!="string")return i.json({error:"alias required"},400);try{let g=he(l,p.alias);if(p.pin===!0)M.unlinkSession(l);else{let _=f().prepare("SELECT cwd, started_at FROM sessions WHERE id = ?").get(l),E=_?.cwd?_.cwd.replace(/\/+$/,""):null,y=!1;if(E&&_?.started_at){let w=Date.parse(_.started_at),N=_.started_at,k=M.all().filter(C=>C.cwd&&C.cwd.replace(/\/+$/,"")===E&&on({sessionStartedAt:N,terminalOpenedAt:C.opened_at??null}).allowed);if(Number.isFinite(w)&&k.length>0){let I=k.map(j=>({t:j,gap:w-Date.parse(j.opened_at??"")})).filter(j=>Number.isFinite(j.gap)).sort((j,v)=>j.gap-v.gap)[0];I&&(M.linkSession(l,I.t.shell_pid),y=!0)}}y||M.unlinkSession(l)}return i.json(g)}catch(g){return i.json({error:g.message},400)}}),t.delete("/api/sessions/:id/alias",i=>{let l=i.req.param("id");return es(l),M.unlinkSession(l),i.json({ok:!0})}),t.get("/api/sessions/:id/alias",i=>{let l=i.req.param("id");return i.json({alias:Te(l)})}),t.get("/api/config/auto-title",i=>i.json(st())),t.put("/api/config/auto-title",async i=>{let l=await i.req.json().catch(()=>({})),p=ds.partial().safeParse(l);return p.success?i.json(ul(p.data)):i.json({error:"invalid config",issues:p.error.issues},400)}),t.get("/api/sessions/:id/auto-title",i=>{let l=i.req.param("id"),p=Le(l);return p?i.json(p):i.json({error:"session not found"},404)}),t.post("/api/sessions/:id/auto-title",async i=>{let l=i.req.param("id");if(!st().agentEnabled)return i.json({error:"autoTitle.agentEnabled is false"},403);if(!f().prepare("SELECT 1 FROM sessions WHERE id = ?").get(l))return i.json({error:"session not found"},404);try{let E=await el(l);return Ee(l,E,"agent"),i.json(Le(l))}catch(E){return i.json({error:E.message,code:"agent-title-failed"},500)}}),t.post("/api/sessions/:id/auto-title/revert",i=>{let l=i.req.param("id"),p=Le(l);if(!p)return i.json({error:"session not found"},404);let g=p.auto_title_history;if(!g||g.length===0)return i.json({error:"no prior title to revert to",code:"no-history"},422);let _=g[g.length-1];return Ee(l,_.title,"agent"),i.json(Le(l))}),t.post("/api/sessions/:id/regenerate-title",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>({})),g=p.model??Fs;try{let _=await $o(l,{model:g,force:p.force===!0,budget:typeof p.budget=="number"?p.budget:void 0,signal:i.req.raw.signal}),E=Le(l),y=E?.auto_title_history&&E.auto_title_history.length>0?E.auto_title_history[E.auto_title_history.length-1].title:null;return i.json({..._,previous_title:y})}catch(_){if(_ instanceof At)return i.json({error:_.message,code:"no-context-available",session_id:_.sessionId},422);let E=_ instanceof Error?_.message:"unknown error",y=/not found|unknown/i.test(E)?404:500;return i.json({error:E,code:"regenerate-failed"},y)}}),t.post("/api/sessions/regenerate-titles-batch",async i=>{let l=await i.req.json().catch(()=>null);if(!l)return i.json({error:"body required"},400);let p=l.project;if(typeof p!="string"||p.length===0)return i.json({error:"project (string) required"},400);let g=l.quality_filter;if(!Array.isArray(g)||g.length===0)return i.json({error:"quality_filter (non-empty array) required"},400);let _=new Set(["low_signal","recursive_meta","programmatic"]),E=[];for(let v of g){if(typeof v!="string")return i.json({error:`invalid quality_filter entry: ${v}`},400);if(!_.has(v))return i.json({error:`quality_filter must be a subset of ${[..._].join(",")}; got ${v}`},400);E.push(v)}let y=typeof l.model=="string"&&l.model.length>0?l.model:Fs,w=typeof l.limit=="number"&&l.limit>0?Math.min(2e3,Math.floor(l.limit)):500,N=typeof l.budget=="number"&&l.budget>=100?Math.floor(l.budget):void 0,C=f().prepare(`SELECT s.id,
1909
1923
  s.auto_title,
1910
1924
  s.auto_title_source,
1911
1925
  NULLIF(sa.alias, '') AS alias
@@ -1914,14 +1928,14 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1914
1928
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1915
1929
  WHERE p.name LIKE @proj ESCAPE '\\' OR p.decoded_path LIKE @proj ESCAPE '\\'
1916
1930
  ORDER BY COALESCE(s.ended_at, s.started_at, '') DESC
1917
- LIMIT @limit`).all({proj:`%${An(p)}%`,limit:k}),C=new Set(E),v=O.filter(L=>{let F=L.alias==null?null:I.isSessionAutoLinked(L.id)?"auto":"manual",q=tn({auto_title:L.auto_title,auto_title_source:L.auto_title_source??null,has_alias:L.alias!=null&&F==="manual"});return C.has(q)});return Ge(i,async L=>{let F=v.length,q=[],K=[],Y=[],$=0,X=async(Q,V)=>{$+=1;try{await L.writeSSE({id:String($),event:Q,data:JSON.stringify(V)})}catch{}};await X("start",{total:F,model:y});let G=0;for(let Q of v){if(i.req.raw.signal.aborted)break;G+=1;try{let V=await Do(Q.id,{model:y,budget:N,signal:i.req.raw.signal});V.written?(q.push(Q.id),await X("progress",{sessionId:Q.id,title:V.title,evidence:V.evidence,confidence:V.confidence,current:G,total:F})):(K.push({sessionId:Q.id,reason:V.skipped??"unknown"}),await X("skipped",{sessionId:Q.id,reason:V.skipped??"unknown",current:G,total:F}))}catch(V){let J=V instanceof Error?V.message:String(V),oe=V instanceof At?"no-context-available":"failed";Y.push({sessionId:Q.id,error:J}),await X("error",{sessionId:Q.id,error:J,code:oe,current:G,total:F})}}await X("done",{generated:q,skipped:K,failed:Y,cancelled:i.req.raw.signal.aborted})})}),t.get("/api/sessions/:id/notes",i=>{let l=i.req.param("id"),p=ys(l);return p?i.json(p):i.body(null,204)}),t.put("/api/sessions/:id/notes",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>null);if(!p||typeof p.content!="string")return i.json({error:"content required (string)"},400);try{let g=Ul(l,p.content);return i.json(g)}catch(g){return console.error("[notes] failed to save note for session",l,g),i.json({error:"failed to save note"},500)}}),t.post("/api/sessions/:id/generate-note",async i=>{let l=i.req.param("id");if(!rt().agentEnabled)return i.json({error:"autoTitle.agentEnabled is false"},403);try{let g=await Bl(l),_=Hl(l,g);return i.json(_)}catch(g){let _=g.message,E=/no messages available/i.test(_)?404:500;return i.json({error:_},E)}}),t.get("/api/semantic/status",i=>i.json(Nr())),t.put("/api/semantic/config",async i=>{let l=await i.req.json().catch(()=>({})),p=Bn.partial().safeParse(l);return p.success?(Hn(p.data),i.json(Nr())):i.json({error:"invalid semantic config",issues:p.error.issues},400)}),t.get("/api/semantic/config",i=>i.json(ce())),t.post("/api/semantic/backfill",je,async i=>{if(Ti)return i.json({error:"a scan is already running"},409);if(!ce().enabled)return i.json({error:"semantic search is disabled"},400);let p=await i.req.json().catch(()=>({})),g=Math.max(1,Math.min(5e3,Number(p.limit??200)));return Ti=!0,Xn({limit:g,force:!!p.force}).catch(_=>console.error("[semantic.backfill] error:",_)).finally(()=>{Ti=!1}),i.json({ok:!0,limit:g})}),t.post("/api/semantic/sessions/:id",je,async i=>{if(!ce().enabled)return i.json({error:"semantic search is disabled"},400);let p=i.req.param("id");if(!p)return i.json({error:"session id required"},400);let g=await qn(p);return i.json(g)}),t.get("/api/semantic/vector-status",i=>{let l=_e(),p=Ie(),g=Ye(),_=(i.req.query("project")??"").trim(),E=_.length>512?"":_,y=null,k=0;if(E){let C=f(),v=C.prepare("SELECT id FROM projects WHERE name = ? OR decoded_path = ? LIMIT 1").get(E,E);v?y=C.prepare("SELECT COUNT(*) AS n FROM chunk_queue WHERE session_id IN (SELECT id FROM sessions WHERE project_id = ?)").get(v.id).n:y=0}let N=gi(),A=N?.chunksPerSec??0,O=A>0?Math.ceil(p.queueDepth/A):0;return A>0&&y!==null&&(k=Math.ceil(y/A)),i.json({embedder:l,worker:p,modelInstalled:g,project:E||null,queueDepthForProject:y,etaForProject:k,throughput:{chunksPerSec:A,samples:N?.samples??0,source:N?"local-measured":"no-samples-yet"},etaSeconds:O})}),t.post("/api/semantic/install",je,async i=>{if(Ye())return i.json({ok:!0,status:"already_installed"});if(Si)return i.json({error:"a scan is already running"},409);Si=!0;try{return await Gp(),await Ue(),kn(),i.json({ok:!0,status:"installed"})}catch(l){let p=l instanceof Error?l.message:"unknown error";return i.json({ok:!1,error:p},500)}finally{Si=!1}}),t.get("/api/semantic/reindex-preview",je,async i=>{let l=(i.req.query("project")??"").trim();if(!l)return i.json({error:"project name required"},400);let p=f(),g=p.prepare("SELECT id, name FROM projects WHERE name = ? OR decoded_path = ? LIMIT 1").get(l,l);if(!g)return i.json({error:`project not found: ${l}`},404);let _=p.prepare(`SELECT
1931
+ LIMIT @limit`).all({proj:`%${An(p)}%`,limit:w}),I=new Set(E),j=C.filter(v=>{let P=v.alias==null?null:M.isSessionAutoLinked(v.id)?"auto":"manual",q=tn({auto_title:v.auto_title,auto_title_source:v.auto_title_source??null,has_alias:v.alias!=null&&P==="manual"});return I.has(q)});return Ye(i,async v=>{let P=j.length,q=[],K=[],G=[],U=0,X=async(Q,V)=>{U+=1;try{await v.writeSSE({id:String(U),event:Q,data:JSON.stringify(V)})}catch{}};await X("start",{total:P,model:y});let Y=0;for(let Q of j){if(i.req.raw.signal.aborted)break;Y+=1;try{let V=await $o(Q.id,{model:y,budget:N,signal:i.req.raw.signal});V.written?(q.push(Q.id),await X("progress",{sessionId:Q.id,title:V.title,evidence:V.evidence,confidence:V.confidence,current:Y,total:P})):(K.push({sessionId:Q.id,reason:V.skipped??"unknown"}),await X("skipped",{sessionId:Q.id,reason:V.skipped??"unknown",current:Y,total:P}))}catch(V){let J=V instanceof Error?V.message:String(V),oe=V instanceof At?"no-context-available":"failed";G.push({sessionId:Q.id,error:J}),await X("error",{sessionId:Q.id,error:J,code:oe,current:Y,total:P})}}await X("done",{generated:q,skipped:K,failed:G,cancelled:i.req.raw.signal.aborted})})}),t.get("/api/sessions/:id/notes",i=>{let l=i.req.param("id"),p=ws(l);return p?i.json(p):i.body(null,204)}),t.put("/api/sessions/:id/notes",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>null);if(!p||typeof p.content!="string")return i.json({error:"content required (string)"},400);try{let g=Gl(l,p.content);return i.json(g)}catch(g){return console.error("[notes] failed to save note for session",l,g),i.json({error:"failed to save note"},500)}}),t.post("/api/sessions/:id/generate-note",async i=>{let l=i.req.param("id");if(!st().agentEnabled)return i.json({error:"autoTitle.agentEnabled is false"},403);try{let g=await Yl(l),_=zl(l,g);return i.json(_)}catch(g){let _=g.message,E=/no messages available/i.test(_)?404:500;return i.json({error:_},E)}}),t.get("/api/semantic/status",i=>i.json(Or())),t.put("/api/semantic/config",async i=>{let l=await i.req.json().catch(()=>({})),p=Hn.partial().safeParse(l);return p.success?(Wn(p.data),i.json(Or())):i.json({error:"invalid semantic config",issues:p.error.issues},400)}),t.get("/api/semantic/config",i=>i.json(ce())),t.post("/api/semantic/backfill",je,async i=>{if(Ni)return i.json({error:"a scan is already running"},409);if(!ce().enabled)return i.json({error:"semantic search is disabled"},400);let p=await i.req.json().catch(()=>({})),g=Math.max(1,Math.min(5e3,Number(p.limit??200)));return Ni=!0,Jn({limit:g,force:!!p.force}).catch(_=>console.error("[semantic.backfill] error:",_)).finally(()=>{Ni=!1}),i.json({ok:!0,limit:g})}),t.post("/api/semantic/sessions/:id",je,async i=>{if(!ce().enabled)return i.json({error:"semantic search is disabled"},400);let p=i.req.param("id");if(!p)return i.json({error:"session id required"},400);let g=await Xn(p);return i.json(g)}),t.get("/api/semantic/vector-status",i=>{let l=_e(),p=Ie(),g=Ge(),_=(i.req.query("project")??"").trim(),E=_.length>512?"":_,y=null,w=0;if(E){let I=f(),j=I.prepare("SELECT id FROM projects WHERE name = ? OR decoded_path = ? LIMIT 1").get(E,E);j?y=I.prepare("SELECT COUNT(*) AS n FROM chunk_queue WHERE session_id IN (SELECT id FROM sessions WHERE project_id = ?)").get(j.id).n:y=0}let N=Ti(),k=N?.chunksPerSec??0,C=k>0?Math.ceil(p.queueDepth/k):0;return k>0&&y!==null&&(w=Math.ceil(y/k)),i.json({embedder:l,worker:p,modelInstalled:g,project:E||null,queueDepthForProject:y,etaForProject:w,throughput:{chunksPerSec:k,samples:N?.samples??0,source:N?"local-measured":"no-samples-yet"},etaSeconds:C})}),t.post("/api/semantic/install",je,async i=>{if(Ge())return i.json({ok:!0,status:"already_installed"});if(xi)return i.json({error:"a scan is already running"},409);xi=!0;try{return await tm(),await Ue(),kn(),i.json({ok:!0,status:"installed"})}catch(l){let p=l instanceof Error?l.message:"unknown error";return i.json({ok:!1,error:p},500)}finally{xi=!1}}),t.get("/api/semantic/reindex-preview",je,async i=>{let l=(i.req.query("project")??"").trim();if(!l)return i.json({error:"project name required"},400);let p=f(),g=p.prepare("SELECT id, name FROM projects WHERE name = ? OR decoded_path = ? LIMIT 1").get(l,l);if(!g)return i.json({error:`project not found: ${l}`},404);let _=p.prepare(`SELECT
1918
1932
  COUNT(*) AS total,
1919
1933
  SUM(CASE WHEN s.message_count >= 3 THEN 1 ELSE 0 END) AS eligible,
1920
1934
  SUM(CASE WHEN s.message_count >= 3 AND EXISTS
1921
1935
  (SELECT 1 FROM chunk_meta cm WHERE cm.session_id = s.id) THEN 1 ELSE 0 END)
1922
1936
  AS indexed
1923
- FROM sessions s WHERE s.project_id = ?`).get(g.id),E=_.eligible??0,y=_.indexed??0,k=Math.max(0,E-y),N=p.prepare(`SELECT COUNT(*) AS n FROM chunk_queue
1924
- WHERE session_id NOT IN (SELECT id FROM sessions WHERE project_id = ?)`).get(g.id).n,A=gi(),O=2,C=30,v=O,L=C,F=O*C,q="fallback-baseline",K=0;if(A)v=A.sessionsPerSec,L=A.avgChunksPerSession,F=A.chunksPerSec,q="local-measured",K=A.samples;else if(Ye()){if(!_e().loaded)try{await Ue()}catch{}try{let G=["[user] benchmark probe one \u2014 typical session opening turn","[assistant] benchmark probe two \u2014 typical assistant response with code reference","[user] benchmark probe three \u2014 typical follow-up clarification"],Q=Date.now();await ct(G);let V=Date.now()-Q;V>0&&(F=G.length*1e3/V,v=F/C,q="live-benchmark")}catch{}}let Y=G=>p.prepare(`SELECT
1937
+ FROM sessions s WHERE s.project_id = ?`).get(g.id),E=_.eligible??0,y=_.indexed??0,w=Math.max(0,E-y),N=p.prepare(`SELECT COUNT(*) AS n FROM chunk_queue
1938
+ WHERE session_id NOT IN (SELECT id FROM sessions WHERE project_id = ?)`).get(g.id).n,k=Ti(),C=2,I=30,j=C,v=I,P=C*I,q="fallback-baseline",K=0;if(k)j=k.sessionsPerSec,v=k.avgChunksPerSession,P=k.chunksPerSec,q="local-measured",K=k.samples;else if(Ge()){if(!_e().loaded)try{await Ue()}catch{}try{let Y=["[user] benchmark probe one \u2014 typical session opening turn","[assistant] benchmark probe two \u2014 typical assistant response with code reference","[user] benchmark probe three \u2014 typical follow-up clarification"],Q=Date.now();await at(Y);let V=Date.now()-Q;V>0&&(P=Y.length*1e3/V,j=P/I,q="live-benchmark")}catch{}}let G=Y=>p.prepare(`SELECT
1925
1939
  COALESCE(SUM(CASE WHEN ec > 5 THEN 5 ELSE ec END), 0) AS total_quick,
1926
1940
  COALESCE(SUM(CASE WHEN ec > 80 THEN 80 ELSE ec END), 0) AS total_standard,
1927
1941
  COALESCE(SUM(CASE WHEN ec > 200 THEN 200 ELSE ec END), 0) AS total_full,
@@ -1933,10 +1947,10 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1933
1947
  ELSE (s.message_count + 3) / 4
1934
1948
  END AS ec
1935
1949
  FROM sessions s
1936
- WHERE s.project_id = ? AND s.message_count >= 3 ${G}
1937
- )`).get(g.id),$=Y("AND NOT EXISTS (SELECT 1 FROM chunk_meta cm WHERE cm.session_id = s.id)"),X=Y("");return i.json({project:g.name,total:_.total??0,eligible:E,indexed:y,pendingNew:k,pendingForce:E,modelInstalled:Ye(),modelName:"BAAI/bge-base-en-v1.5",embedderLoaded:_e().loaded,workerRunning:Ie().running,queueDepthOther:N,sessionsPerSec:v,avgChunksPerSession:L,chunksPerSec:F,throughputSource:q,throughputSamples:K,estimatedChunksByDepth:{new:{quick:$.total_quick,standard:$.total_standard,full:$.total_full,uncapped:$.total_uncapped},force:{quick:X.total_quick,standard:X.total_standard,full:X.total_full,uncapped:X.total_uncapped}}})}),t.post("/api/semantic/cancel-reindex",je,async i=>{let l={};try{l=await i.req.json()}catch{}let p=(l.project??"").trim(),g=f(),_=0,E=null;if(p){let y=g.prepare("SELECT id FROM projects WHERE name = ? OR decoded_path = ? LIMIT 1").get(p,p);if(!y)return i.json({error:`project not found: ${p}`},404);let k=g.prepare("SELECT COUNT(*) AS n FROM chunk_queue WHERE session_id IN (SELECT id FROM sessions WHERE project_id = ?)").get(y.id).n;g.prepare("DELETE FROM chunk_queue WHERE session_id IN (SELECT id FROM sessions WHERE project_id = ?)").run(y.id),_=k,E=y.id}else{let y=g.prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n;g.prepare("DELETE FROM chunk_queue").run(),_=y}return E!==null?$p(E):Up(),Ie().queueDepth===0&&Hp(),i.json({cleared:_,project:p||null,queueDepth:Ie().queueDepth})}),t.post("/api/semantic/reindex-project",je,async i=>{if(!Ye())return i.json({error:"embedder not installed \u2014 run `recall semantic install` first"},503);let l={};try{l=await i.req.json()}catch{}let p=(l.project??"").trim();if(!p)return i.json({error:"project name required"},400);let g=!!l.force,_=Math.max(0,Math.floor(Number(l.maxChunks??0)));Fp(_);let E=f(),y=E.prepare("SELECT id FROM projects WHERE name = ? OR decoded_path = ? LIMIT 1").get(p,p);if(!y)return i.json({error:`project not found: ${p}`},404);let k=g?"SELECT id FROM sessions WHERE project_id = ? AND message_count >= 3":`SELECT s.id FROM sessions s
1950
+ WHERE s.project_id = ? AND s.message_count >= 3 ${Y}
1951
+ )`).get(g.id),U=G("AND NOT EXISTS (SELECT 1 FROM chunk_meta cm WHERE cm.session_id = s.id)"),X=G("");return i.json({project:g.name,total:_.total??0,eligible:E,indexed:y,pendingNew:w,pendingForce:E,modelInstalled:Ge(),modelName:"BAAI/bge-base-en-v1.5",embedderLoaded:_e().loaded,workerRunning:Ie().running,queueDepthOther:N,sessionsPerSec:j,avgChunksPerSession:v,chunksPerSec:P,throughputSource:q,throughputSamples:K,estimatedChunksByDepth:{new:{quick:U.total_quick,standard:U.total_standard,full:U.total_full,uncapped:U.total_uncapped},force:{quick:X.total_quick,standard:X.total_standard,full:X.total_full,uncapped:X.total_uncapped}}})}),t.post("/api/semantic/cancel-reindex",je,async i=>{let l={};try{l=await i.req.json()}catch{}let p=(l.project??"").trim(),g=f(),_=0,E=null;if(p){let y=g.prepare("SELECT id FROM projects WHERE name = ? OR decoded_path = ? LIMIT 1").get(p,p);if(!y)return i.json({error:`project not found: ${p}`},404);let w=g.prepare("SELECT COUNT(*) AS n FROM chunk_queue WHERE session_id IN (SELECT id FROM sessions WHERE project_id = ?)").get(y.id).n;g.prepare("DELETE FROM chunk_queue WHERE session_id IN (SELECT id FROM sessions WHERE project_id = ?)").run(y.id),_=w,E=y.id}else{let y=g.prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n;g.prepare("DELETE FROM chunk_queue").run(),_=y}return E!==null?Jp(E):Gp(),Ie().queueDepth===0&&zp(),i.json({cleared:_,project:p||null,queueDepth:Ie().queueDepth})}),t.post("/api/semantic/reindex-project",je,async i=>{if(!Ge())return i.json({error:"embedder not installed \u2014 run `recall semantic install` first"},503);let l={};try{l=await i.req.json()}catch{}let p=(l.project??"").trim();if(!p)return i.json({error:"project name required"},400);let g=!!l.force,_=Math.max(0,Math.floor(Number(l.maxChunks??0)));qp(_);let E=f(),y=E.prepare("SELECT id FROM projects WHERE name = ? OR decoded_path = ? LIMIT 1").get(p,p);if(!y)return i.json({error:`project not found: ${p}`},404);let w=g?"SELECT id FROM sessions WHERE project_id = ? AND message_count >= 3":`SELECT s.id FROM sessions s
1938
1952
  WHERE s.project_id = ? AND s.message_count >= 3
1939
- AND NOT EXISTS (SELECT 1 FROM chunk_meta cm WHERE cm.session_id = s.id)`,N=E.prepare(k).all(y.id);if(N.length===0)return i.json({enqueued:0,queueDepth:Ie().queueDepth,message:"nothing to do \u2014 every session in this project is already vectorized (use force:true to re-embed)"});let A=E.prepare("INSERT INTO chunk_queue(session_id, action) VALUES (?, 'embed')");if(E.transaction(()=>{for(let C of N)A.run(C.id)})(),!_e().loaded)try{await Ue()}catch(C){let v=C instanceof Error?C.message:"unknown error";return i.json({error:`embedder load failed: ${v}`},500)}return Ie().running||kn(),i.json({enqueued:N.length,queueDepth:Ie().queueDepth,project:p,appliedMaxChunks:_})}),t.get("/api/sessions/:id/similar",je,async i=>{if(!_e().loaded)return i.json({error:"vector model not loaded"},503);let l=i.req.param("id"),p=Math.max(1,Math.min(50,Number(i.req.query("limit")??10)));try{let g=await xp(l,p);return i.json({sessionId:l,similar:g})}catch(g){let _=g instanceof Error?g.message:"unknown error";return i.json({error:_},500)}}),t.get("/api/search",je,async i=>{let l=f(),p=i.req.query("q")?.trim();if(!p)return i.json({query:"",hits:[],tags:[]});if(p.length>500)return i.json({error:"query too long (max 500 chars)"},400);let g=i.req.query("project"),_=p.split(/\s+/).filter(J=>J.length>0),E=_.filter(J=>J.startsWith("#")).map(J=>Qe(J)).filter(Boolean),y=_.filter(J=>!J.startsWith("#")),k=y.length>20,A=(k?y.slice(0,20):y).map(J=>`"${J.replace(/"/g,"")}"`),O=A.join(" "),C=Math.max(1,Math.min(200,Number(i.req.query("limit")??30))),v=i.req.query("system")==="1"||i.req.query("system")==="true",L=er("s",v);if(A.length===0&&E.length>0){let J=`
1953
+ AND NOT EXISTS (SELECT 1 FROM chunk_meta cm WHERE cm.session_id = s.id)`,N=E.prepare(w).all(y.id);if(N.length===0)return i.json({enqueued:0,queueDepth:Ie().queueDepth,message:"nothing to do \u2014 every session in this project is already vectorized (use force:true to re-embed)"});let k=E.prepare("INSERT INTO chunk_queue(session_id, action) VALUES (?, 'embed')");if(E.transaction(()=>{for(let I of N)k.run(I.id)})(),!_e().loaded)try{await Ue()}catch(I){let j=I instanceof Error?I.message:"unknown error";return i.json({error:`embedder load failed: ${j}`},500)}return Ie().running||kn(),i.json({enqueued:N.length,queueDepth:Ie().queueDepth,project:p,appliedMaxChunks:_})}),t.get("/api/sessions/:id/similar",je,async i=>{if(!_e().loaded)return i.json({error:"vector model not loaded"},503);let l=i.req.param("id"),p=Math.max(1,Math.min(50,Number(i.req.query("limit")??10)));try{let g=await jp(l,p);return i.json({sessionId:l,similar:g})}catch(g){let _=g instanceof Error?g.message:"unknown error";return i.json({error:_},500)}}),t.get("/api/search",je,async i=>{let l=f(),p=i.req.query("q")?.trim();if(!p)return i.json({query:"",hits:[],tags:[]});if(p.length>500)return i.json({error:"query too long (max 500 chars)"},400);let g=i.req.query("project"),_=p.split(/\s+/).filter(J=>J.length>0),E=_.filter(J=>J.startsWith("#")).map(J=>Ze(J)).filter(Boolean),y=_.filter(J=>!J.startsWith("#")),w=y.length>20,k=(w?y.slice(0,20):y).map(J=>`"${J.replace(/"/g,"")}"`),C=k.join(" "),I=Math.max(1,Math.min(200,Number(i.req.query("limit")??30))),j=i.req.query("system")==="1"||i.req.query("system")==="true",v=tr("s",j);if(k.length===0&&E.length>0){let J=`
1940
1954
  SELECT s.id AS session_id,
1941
1955
  s.id AS message_uuid,
1942
1956
  p.name AS project,
@@ -1948,8 +1962,8 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1948
1962
  FROM sessions s
1949
1963
  JOIN projects p ON p.id = s.project_id
1950
1964
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1951
- WHERE 1=1${L}
1952
- `,oe={limit:C};g&&(J+=" AND (p.name LIKE @proj ESCAPE '\\' OR p.decoded_path LIKE @proj ESCAPE '\\')",oe.proj=`%${An(g)}%`),E.forEach((Me,me)=>{J+=` AND s.id IN (SELECT session_id FROM session_tags WHERE tag = @tag_${me})`,oe[`tag_${me}`]=Me}),J+=" ORDER BY COALESCE(s.started_at, '') DESC LIMIT @limit";let ze=l.prepare(J).all(oe);return i.json({query:p,hits:ze,tags:E,truncated:k})}let F=`
1965
+ WHERE 1=1${v}
1966
+ `,oe={limit:I};g&&(J+=" AND (p.name LIKE @proj ESCAPE '\\' OR p.decoded_path LIKE @proj ESCAPE '\\')",oe.proj=`%${An(g)}%`),E.forEach((Me,me)=>{J+=` AND s.id IN (SELECT session_id FROM session_tags WHERE tag = @tag_${me})`,oe[`tag_${me}`]=Me}),J+=" ORDER BY COALESCE(s.started_at, '') DESC LIMIT @limit";let ze=l.prepare(J).all(oe);return i.json({query:p,hits:ze,tags:E,truncated:w})}let P=`
1953
1967
  SELECT m.session_id AS session_id,
1954
1968
  m.uuid AS message_uuid,
1955
1969
  p.name AS project,
@@ -1963,8 +1977,8 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1963
1977
  JOIN sessions s ON s.id = m.session_id
1964
1978
  JOIN projects p ON p.id = s.project_id
1965
1979
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1966
- WHERE messages_fts MATCH @fts${L}
1967
- `,q={fts:O,limit:C};g&&(F+=" AND (p.name LIKE @proj ESCAPE '\\' OR p.decoded_path LIKE @proj ESCAPE '\\')",q.proj=`%${An(g)}%`),E.forEach((J,oe)=>{F+=` AND s.id IN (SELECT session_id FROM session_tags WHERE tag = @tag_${oe})`,q[`tag_${oe}`]=J}),F+=" ORDER BY bm25(messages_fts) LIMIT @limit";let Y=l.prepare(F).all(q).map(J=>({...J,matched_via:"fts"}));if(i.req.query("mode")!=="semantic")return i.json({query:p,hits:Y,tags:E,truncated:k});let X=[];try{let J=`
1980
+ WHERE messages_fts MATCH @fts${v}
1981
+ `,q={fts:C,limit:I};g&&(P+=" AND (p.name LIKE @proj ESCAPE '\\' OR p.decoded_path LIKE @proj ESCAPE '\\')",q.proj=`%${An(g)}%`),E.forEach((J,oe)=>{P+=` AND s.id IN (SELECT session_id FROM session_tags WHERE tag = @tag_${oe})`,q[`tag_${oe}`]=J}),P+=" ORDER BY bm25(messages_fts) LIMIT @limit";let G=l.prepare(P).all(q).map(J=>({...J,matched_via:"fts"}));if(i.req.query("mode")!=="semantic")return i.json({query:p,hits:G,tags:E,truncated:w});let X=[];try{let J=`
1968
1982
  SELECT s.id AS session_id,
1969
1983
  s.id AS message_uuid,
1970
1984
  p.name AS project,
@@ -1979,16 +1993,16 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1979
1993
  JOIN sessions s ON s.id = ss.session_id
1980
1994
  JOIN projects p ON p.id = s.project_id
1981
1995
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1982
- WHERE sessions_fts MATCH @fts${L}
1983
- `,oe={fts:O,limit:C};g&&(J+=" AND (p.name LIKE @proj ESCAPE '\\' OR p.decoded_path LIKE @proj ESCAPE '\\')",oe.proj=`%${An(g)}%`),E.forEach((ze,Me)=>{J+=` AND s.id IN (SELECT session_id FROM session_tags WHERE tag = @tag_${Me})`,oe[`tag_${Me}`]=ze}),J+=" ORDER BY rank LIMIT @limit",X=l.prepare(J).all(oe)}catch(J){console.error("[search.semantic] failed:",J)}if(_e().loaded)try{let J=await Ap(p,C),oe=Y.map(ue=>({id:String(ue.session_id),data:ue,lane:"bm25"})),ze=X.map(ue=>({id:String(ue.session_id),data:ue,lane:"summary"})),Me=J.map(ue=>({id:ue.sessionId,data:{session_id:ue.sessionId,snippet:ue.text,matched_via:"vector"},lane:"vector"})),bm=Np([oe,ze,Me]).slice(0,C).map(ue=>({...ue.data,session_id:ue.id,rrf_score:ue.score,lanes:ue.lanes,matched_via:ue.lanes.length>1?"fused":ue.lanes[0]}));return i.json({query:p,hits:bm,tags:E,mode:"semantic",fusion:"rrf",truncated:k})}catch(J){console.error("[search.vector] failed, falling back:",J)}let G=new Set(Y.map(J=>String(J.session_id))),Q=X.filter(J=>!G.has(String(J.session_id))).map(({rank:J,...oe})=>({...oe,matched_via:"semantic"})),V=[...Y,...Q].slice(0,C);return i.json({query:p,hits:V,tags:E,mode:"semantic",truncated:k})}),t.get("/api/sessions/:id/context",je,i=>{let l=f(),p=i.req.param("id"),g=i.req.query("mode")==="full"?"full":"condensed",_=i.req.query("subagents")==="1",E=i.req.query("prelude")??null,y=l.prepare(`SELECT s.id, p.name AS project_name, p.decoded_path,
1996
+ WHERE sessions_fts MATCH @fts${v}
1997
+ `,oe={fts:C,limit:I};g&&(J+=" AND (p.name LIKE @proj ESCAPE '\\' OR p.decoded_path LIKE @proj ESCAPE '\\')",oe.proj=`%${An(g)}%`),E.forEach((ze,Me)=>{J+=` AND s.id IN (SELECT session_id FROM session_tags WHERE tag = @tag_${Me})`,oe[`tag_${Me}`]=ze}),J+=" ORDER BY rank LIMIT @limit",X=l.prepare(J).all(oe)}catch(J){console.error("[search.semantic] failed:",J)}if(_e().loaded)try{let J=await Ip(p,I),oe=G.map(ue=>({id:String(ue.session_id),data:ue,lane:"bm25"})),ze=X.map(ue=>({id:String(ue.session_id),data:ue,lane:"summary"})),Me=J.map(ue=>({id:ue.sessionId,data:{session_id:ue.sessionId,snippet:ue.text,matched_via:"vector"},lane:"vector"})),Am=Mp([oe,ze,Me]).slice(0,I).map(ue=>({...ue.data,session_id:ue.id,rrf_score:ue.score,lanes:ue.lanes,matched_via:ue.lanes.length>1?"fused":ue.lanes[0]}));return i.json({query:p,hits:Am,tags:E,mode:"semantic",fusion:"rrf",truncated:w})}catch(J){console.error("[search.vector] failed, falling back:",J)}let Y=new Set(G.map(J=>String(J.session_id))),Q=X.filter(J=>!Y.has(String(J.session_id))).map(({rank:J,...oe})=>({...oe,matched_via:"semantic"})),V=[...G,...Q].slice(0,I);return i.json({query:p,hits:V,tags:E,mode:"semantic",truncated:w})}),t.get("/api/sessions/:id/context",je,i=>{let l=f(),p=i.req.param("id"),g=i.req.query("mode")==="full"?"full":"condensed",_=i.req.query("subagents")==="1",E=i.req.query("prelude")??null,y=l.prepare(`SELECT s.id, p.name AS project_name, p.decoded_path,
1984
1998
  s.started_at, s.ended_at, s.message_count, s.git_branch
1985
1999
  FROM sessions s JOIN projects p ON p.id = s.project_id
1986
- WHERE s.id = ?`).get(p);if(!y)return i.json({error:"not found"},404);let k=l.prepare(`SELECT uuid, type, role, timestamp, is_sidechain, content_text, tool_names
2000
+ WHERE s.id = ?`).get(p);if(!y)return i.json({error:"not found"},404);let w=l.prepare(`SELECT uuid, type, role, timestamp, is_sidechain, content_text, tool_names
1987
2001
  FROM messages
1988
2002
  WHERE session_id = ?
1989
- ORDER BY COALESCE(timestamp, ''), rowid`).all(p),N=Ml(y,k,{mode:g,includeSidechain:_,prelude:E});return i.text(N)}),t.get("/api/collections",i=>{let l=i.req.query("archived")==="1";return i.json({collections:al(l)})}),t.get("/api/collections/:id",i=>{let l=i.req.param("id"),p=Be(l);if(!p)return i.json({error:"not found"},404);let g=cl(l,!0);return i.json({collection:p,members:g})}),t.post("/api/collections",async i=>{let l=await i.req.json().catch(()=>null);if(!l||typeof l.name!="string")return i.json({error:"name required"},400);try{let p=sn({name:l.name,description:l.description??null,icon:l.icon??null,color:l.color??null,parent_id:l.parent_id??null,sort_key:l.sort_key});return i.json(p,201)}catch(p){return i.json({error:p.message},400)}}),t.patch("/api/collections/:id",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>null);if(!p)return i.json({error:"body required"},400);try{let g=ul(l,p);return i.json(g)}catch(g){return i.json({error:g.message},400)}}),t.post("/api/collections/:id/archive",i=>{let l=i.req.param("id");try{let p=dl(l);return i.json(p)}catch(p){return i.json({error:p.message},404)}}),t.post("/api/collections/:id/restore",i=>{let l=i.req.param("id");try{let p=pl(l);return i.json(p)}catch(p){return i.json({error:p.message},404)}}),t.post("/api/collections/:id/members",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>null);if(!p||typeof p.session_id!="string")return i.json({error:"session_id required"},400);try{let g=rn(l,p.session_id,p.note??null);return i.json(g)}catch(g){return i.json({error:g.message},400)}}),t.delete("/api/collections/:id/members/:sid",i=>{let l=i.req.param("id"),p=i.req.param("sid");try{let g=ml(l,p);return i.json(g)}catch(g){return i.json({error:g.message},400)}}),t.get("/api/sessions/:id/collections",i=>{let l=i.req.param("id");return i.json({collections:ll(l)})});let w=["cwd-prefix","project-id","tag","plan-file","git-branch-prefix"];t.get("/api/auto-collections/rules",i=>i.json({rules:El()})),t.post("/api/auto-collections/rules",async i=>{let l=await i.req.json().catch(()=>null);if(!l||typeof l.name!="string"||typeof l.pattern!="string"||!l.type||!w.includes(l.type))return i.json({error:"name, type, pattern required (type must be a known matcher)"},400);try{let p=_o({name:l.name,type:l.type,pattern:l.pattern,collection_id:l.collection_id,parent_collection_id:l.parent_collection_id,priority:l.priority,enabled:l.enabled});return i.json(p,201)}catch(p){return i.json({error:p.message},400)}}),t.patch("/api/auto-collections/rules/:id",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>null);if(!p)return i.json({error:"body required"},400);try{let g=bl(l,p);return i.json(g)}catch(g){return i.json({error:g.message},400)}}),t.delete("/api/auto-collections/rules/:id",i=>{let l=i.req.param("id");try{let p=Sl(l);return i.json(p)}catch(p){return i.json({error:p.message},400)}}),t.get("/api/auto-collections/suggestions",i=>{let l=i.req.query("dismissed")==="1";return i.json({suggestions:Es({includeDismissed:l})})}),t.post("/api/auto-collections/suggestions/:id/accept",i=>{let l=i.req.param("id");try{let p=yl(l);return i.json({rule:p})}catch(p){return i.json({error:p.message},400)}}),t.post("/api/auto-collections/suggestions/:id/dismiss",i=>{let l=i.req.param("id");try{return Tl(l),i.json({ok:!0})}catch(p){return i.json({error:p.message},400)}}),t.post("/api/auto-collections/detect",i=>{let l=bs();return i.json({suggestions:l})}),t.get("/api/auto-collections/suggestions/:id/preview",i=>{let l=i.req.param("id"),p=Math.max(1,Math.min(20,Number(i.req.query("limit"))||3)),_=Es({includeDismissed:!1}).find(y=>y.id===l);if(!_)return i.json({error:"suggestion not found"},404);let E=fl(_.type,_.pattern,p);return i.json({sessions:E})}),t.get("/api/auto-collections/parents",i=>{let l=Array.from(wl());return i.json({auto_collection_ids:l})}),t.get("/api/threads",i=>{let l=i.req.query("archived")==="1";return i.json({threads:Oo({includeArchived:l})})}),t.get("/api/threads/:id",i=>{let l=i.req.param("id"),p=ie(l);if(!p)return i.json({error:"thread not found"},404);let g=p.edges.map(_=>({..._,alias_source:_.alias==null?null:I.isSessionAutoLinked(_.session_id)?"auto":"manual"}));return i.json({thread:{...p,edges:g}})}),t.post("/api/threads",async i=>{let l=await i.req.json().catch(()=>({}));if(!l.name)return i.json({error:"name required"},400);try{let p=Rs({name:l.name,summary:l.summary??null,originSessionId:l.originSessionId});return i.json({thread:p})}catch(p){return i.json({error:p.message},400)}}),t.patch("/api/threads/:id",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>({}));try{p.name&&Zl(l,p.name),p.close&&Ql(l),p.reopen&&eu(l),p.archive&&tu(l),"folder_id"in p&&Tu(l,p.folder_id??null);let g=ie(l);return g?i.json({thread:g}):i.json({error:"thread not found"},404)}catch(g){return i.json({error:g.message},400)}}),t.get("/api/thread-folders",i=>i.json({folders:Io()})),t.post("/api/thread-folders",async i=>{let l=await i.req.json().catch(()=>({}));if(!l.name||typeof l.name!="string")return i.json({error:"name required"},400);try{let p=_u({name:l.name,parentFolderId:l.parent_folder_id??null,projectScope:l.project_scope??null});return i.json({folder:p})}catch(p){return i.json({error:p.message},400)}}),t.patch("/api/thread-folders/:id",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>({}));try{let g;return p.name&&(g=hu(l,p.name)),"parent_folder_id"in p&&(g=Eu(l,p.parent_folder_id??null)),g?i.json({folder:g}):i.json({error:"no patch fields"},400)}catch(g){return i.json({error:g.message},400)}}),t.delete("/api/thread-folders/:id",i=>{let l=i.req.param("id");try{return Su(l),i.json({ok:!0})}catch(p){return i.json({error:p.message},400)}}),t.post("/api/thread-folders/reorder",async i=>{let l=await i.req.json().catch(()=>({})),p=l.ordered_ids;if(!Array.isArray(p))return i.json({error:"ordered_ids must be an array"},400);try{return bu(l.parent_folder_id??null,l.project_scope??null,p),i.json({ok:!0})}catch(g){return i.json({error:g.message},400)}}),t.post("/api/threads/:id/sessions",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>({}));if(!p.sessionId)return i.json({error:"sessionId required"},400);try{let g=ks({threadId:l,sessionId:p.sessionId,parentSessionId:p.parentSessionId??null,role:p.role});return i.json({edge:g})}catch(g){return i.json({error:g.message},400)}}),t.delete("/api/threads/:id/sessions/:sessionId",i=>{let l=i.req.param("id"),p=i.req.param("sessionId"),g=Vl(l,p);return i.json(g)}),t.patch("/api/threads/:id/sessions/:sessionId",async i=>{let l=i.req.param("id"),p=i.req.param("sessionId"),g=await i.req.json().catch(()=>({}));try{let _=an(l,p,g.parentSessionId??null);return i.json({edge:_})}catch(_){return i.json({error:_.message},400)}}),t.post("/api/threads/:id/merge",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>({}));if(!p.sourceId)return i.json({error:"sourceId required"},400);try{let g=nu(p.sourceId,l);return i.json({thread:g})}catch(g){return i.json({error:g.message},400)}}),t.post("/api/threads/:id/split",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>({}));if(!p.sessionIds?.length||!p.newThreadName)return i.json({error:"sessionIds and newThreadName required"},400);try{let g=su({threadId:l,sessionIds:p.sessionIds,newThreadName:p.newThreadName});return i.json({thread:g})}catch(g){return i.json({error:g.message},400)}}),t.get("/api/sessions/:id/threads",i=>{let l=i.req.param("id");return i.json({threads:Kl(l)})});let j=D.object({enabled:D.boolean(),band_lo:D.number().min(0).max(1).optional(),band_hi:D.number().min(0).max(1).optional(),model:D.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional()}).optional(),M=D.object({project:D.string().min(1),threshold:D.number().min(0).max(1).optional(),model:D.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional(),llm_rescore:j});t.post("/api/threads/scan/preflight",async i=>{let l=Ce(i);if(l)return l;let p=await i.req.json().catch(()=>null),g=M.safeParse(p);if(!g.success)return i.json({error:"invalid request body",details:g.error.format()},400);let _=Hd({project:g.data.project,threshold:g.data.threshold,model:g.data.model,llm_rescore:g.data.llm_rescore});return"error"in _?i.json({error:_.error},400):i.json(_)});let W=D.object({project:D.string().min(1),threshold:D.number().min(0).max(1).optional(),llm_names:D.boolean().optional(),model:D.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional(),llm_rescore:j});t.post("/api/threads/scan/apply",async i=>{let l=Ce(i);if(l)return l;let p=await i.req.json().catch(()=>null),g=W.safeParse(p);if(!g.success)return i.json({error:"invalid request body",details:g.error.format()},400);let _=qd({project:g.data.project,threshold:g.data.threshold,llm_names:g.data.llm_names,model:g.data.model,llm_rescore:g.data.llm_rescore});return"error"in _?i.json({error:_.error},400):i.json({jobId:_.jobId,reused:_.reused},_.reused?409:200)}),t.get("/api/threads/scan/jobs/:jobId/stream",i=>{let l=i.req.param("jobId");if(!ni(l))return i.json({error:"job not found"},404);let g=Number(i.req.header("Last-Event-ID")??0);return Ge(i,async _=>{let E=!1,y=setInterval(()=>{E||_.writeSSE({event:"heartbeat",data:""}).catch(()=>{E=!0})},15e3);try{for await(let k of Xd(l,g))if(E||(await _.writeSSE({id:String(k.id),event:k.kind,data:JSON.stringify(k.data)}),k.kind==="done"))break}finally{E=!0,clearInterval(y)}})}),t.get("/api/threads/scan/jobs/:jobId",i=>{let l=ni(i.req.param("jobId"));return l?i.json(l):i.json({error:"job not found"},404)}),t.delete("/api/threads/scan/jobs/:jobId",i=>{let l=Ce(i);return l||(Jd(i.req.param("jobId"))?i.json({ok:!0}):i.json({error:"job not found or already done"},404))});let x=D.object({project_id:D.number().int().positive(),mode:D.enum(["preflight","apply"]),window_hours:D.number().min(.5).max(168).optional(),score_threshold:D.number().min(0).max(1).optional(),use_live_pids:D.boolean().optional()});t.post("/api/threads/sync-active",async i=>{let l=await i.req.json().catch(()=>null),p=x.safeParse(l);if(!p.success)return i.json({error:"invalid request body",details:p.error.format()},400);try{let g=await pu(p.data.project_id,{windowHours:p.data.window_hours,scoreThreshold:p.data.score_threshold,useLivePids:p.data.use_live_pids});if(p.data.mode==="preflight")return i.json({plan:g});let _=mu(g);return i.json({plan:g,result:_})}catch(g){return i.json({error:g.message},400)}}),t.get("/api/threads/:id/titles/preflight",i=>{let l=i.req.param("id"),p=ie(l);if(!p)return i.json({error:"thread not found"},404);let g=f(),_=0;for(let E of p.edges)g.prepare("SELECT auto_title_source FROM sessions WHERE id = ?").get(E.session_id)?.auto_title_source==="agent"&&(_+=1);return i.json({total:p.edges.length,alreadyTitled:_,untitled:p.edges.length-_})}),t.post("/api/threads/:id/titles/generate",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>({})),g=ie(l);if(!g)return i.json({error:"thread not found"},404);if(g.edges.length===0)return i.json({error:"thread has no sessions"},400);let _=Fe(),E=p.model??_.model,y=ju({threadId:l,force:p.force??!1,model:E});return i.json({jobId:y})}),t.get("/api/jobs/:jobId/stream",i=>{let l=i.req.param("jobId");if(!jo(l))return i.json({error:"job not found"},404);let g=Number(i.req.header("Last-Event-ID")??0);return Ge(i,async _=>{let E=!1,y=setInterval(()=>{E||_.writeSSE({event:"heartbeat",data:""}).catch(()=>{E=!0})},15e3);try{for await(let k of Mu(l,g))if(E||(await _.writeSSE({id:String(k.id),event:k.kind,data:JSON.stringify(k.data)}),k.kind==="done"))break}finally{E=!0,clearInterval(y)}})}),t.get("/api/jobs/:jobId",i=>{let l=jo(i.req.param("jobId"));return l?i.json(l):i.json({error:"job not found"},404)}),t.delete("/api/jobs/:jobId",i=>Du(i.req.param("jobId"))?i.json({ok:!0}):i.json({error:"job not found or already done"},404)),t.post("/api/terminal/opened",async i=>{let l=await i.req.json().catch(()=>null);if(!l||typeof l.shell_pid!="number"||typeof l.tab_name!="string")return i.json({error:"shell_pid and tab_name required"},400);let p=I.claimPidOwnership(l.shell_pid,l.extension_instance_id??null);if(p==="rejected")return i.json({ok:!0,rejected:!0,reason:"pid-owned-by-other-extension-instance",count:I.size()});let g=I.upsert({shell_pid:l.shell_pid,tab_name:l.tab_name,cwd:l.cwd??null,opened_at:l.opened_at??new Date().toISOString()});return i.json({ok:!0,ownership:p,count:I.size(),entry:g})}),t.post("/api/terminal/renamed",async i=>{let l=await i.req.json().catch(()=>null);if(!l||typeof l.shell_pid!="number"||typeof l.tab_name!="string")return i.json({error:"shell_pid and tab_name required"},400);let p=I.claimPidOwnership(l.shell_pid,l.extension_instance_id??null);if(p==="rejected")return i.json({ok:!0,rejected:!0,reason:"pid-owned-by-other-extension-instance"});let g=I.rename(l.shell_pid,l.tab_name);if(!g)return i.json({error:"unknown shell_pid"},404);let _=nm(l.shell_pid,l.tab_name);return i.json({ok:!0,ownership:p,entry:g,propagated:_})}),t.post("/api/terminal/closed",async i=>{let l=await i.req.json().catch(()=>null);if(!l||typeof l.shell_pid!="number")return i.json({error:"shell_pid required"},400);let p=I.remove(l.shell_pid);return i.json({ok:!0,removed:p,count:I.size()})}),t.post("/api/terminal/claude-started",async i=>{let l=await i.req.json().catch(()=>null);return!l||typeof l.shell_pid!="number"?i.json({error:"shell_pid required"},400):(I.pushPending({shell_pid:l.shell_pid,tab_name:typeof l.tab_name=="string"?l.tab_name:"",cwd:typeof l.cwd=="string"?l.cwd:null,started_at:typeof l.started_at=="string"?l.started_at:new Date().toISOString()}),i.json({ok:!0,pending:I.pendingSize()}))}),t.post("/api/terminal/output",async i=>{let l=await i.req.json().catch(()=>null);if(!l||typeof l.shell_pid!="number"||typeof l.text!="string")return i.json({error:"shell_pid and text required"},400);let p=l.text.length>8192?l.text.slice(-8192):l.text,g=typeof l.captured_at=="string"?l.captured_at:new Date().toISOString();return I.setOutputTail(l.shell_pid,p,g),i.json({ok:!0})}),t.post("/api/terminal/sync",async i=>{let l=await i.req.json().catch(()=>null);if(!l||!Array.isArray(l.terminals))return i.json({error:"terminals array required"},400);let p=new Map;for(let L of I.all())p.set(L.shell_pid,L.tab_name);let g=l.terminals.filter(L=>!!L&&typeof L.shell_pid=="number"&&typeof L.tab_name=="string").map(L=>({shell_pid:L.shell_pid,tab_name:L.tab_name,cwd:L.cwd??null,opened_at:L.opened_at??new Date().toISOString()})),_=l.extension_instance_id??null,E=[],y=g.filter(L=>{let F=I.claimPidOwnership(L.shell_pid,_);return E.push({shell_pid:L.shell_pid,ownership:F}),F!=="rejected"}),k=I.sync(y),N=0;for(let L of y){let F=p.get(L.shell_pid),q=I.get(L.shell_pid)?.tab_name??L.tab_name,Y=!!q&&!de(q)&&!le(q)?q:L.tab_name;F!==void 0&&F!==Y&&(N+=nm(L.shell_pid,Y))}let A=E.filter(L=>L.ownership==="rejected").length;A>0&&console.log(`[terminal/sync] dropped ${A} tab_name update(s), pid(s) owned by a different extension instance`);let O=await bw(),C={resolved:0,expired:0};try{C=Ic()}catch{}let v={rebound:0,ghosts:0,ambiguous:0};try{v=vc()}catch{}return Cw(),i.json({ok:!0,count:I.size(),diff:k,propagated:N,live_sweep:O,deferred_resolved:C,rebound:v})}),t.get("/api/terminal/registry",i=>i.json({terminals:I.all(),count:I.size()})),t.get("/api/terminal/sessions/:shellPid",i=>{let l=i.req.param("shellPid"),p=Number(l);if(!Number.isInteger(p)||p<=0)return i.json({error:"shellPid must be a positive integer"},400);let g=I.sessionsFor(p);return i.json({shell_pid:p,sessions:g})}),t.get("/api/sessions/:id/linked-terminal",i=>{let l=i.req.param("id"),p=I.all().find(_=>I.sessionsFor(_.shell_pid).includes(l)),g=[];if(!p){let _=f().prepare("SELECT cwd, started_at FROM sessions WHERE id = ?").get(l);if(_?.cwd&&_.started_at){let E=Date.parse(_.started_at);if(Number.isFinite(E)){let y=_.cwd.replace(/\/+$/,""),k=300*1e3;for(let N of I.all()){if(!N.cwd||N.cwd.replace(/\/+$/,"")!==y||de(N.tab_name))continue;let A=Date.parse(N.opened_at),O=Date.parse(N.last_seen_at);!Number.isFinite(A)||!Number.isFinite(O)||A>E||O+k<E||g.push({shell_pid:N.shell_pid,tab_name:N.tab_name,cwd:N.cwd,opened_at:N.opened_at,last_seen_at:N.last_seen_at,reason:"time-overlap"})}g.sort((N,A)=>Date.parse(A.last_seen_at)-Date.parse(N.last_seen_at))}}}return p?i.json({linked:{shell_pid:p.shell_pid,tab_name:p.tab_name,cwd:p.cwd},suggested:[]}):i.json({linked:null,suggested:g})}),t.post("/api/sessions/:id/auto-relink",async i=>{let l=i.req.param("id");if(Te(l))return i.json({applied:!1,reason:"has-alias"});if(I.all().some(y=>I.sessionsFor(y.shell_pid).includes(l)))return i.json({applied:!1,reason:"already-linked"});let g=f().prepare("SELECT cwd, git_branch, started_at FROM sessions WHERE id = ?").get(l);if(!g?.cwd)return i.json({applied:!1,reason:"no-cwd"});let _=g.cwd.replace(/\/+$/,""),E=I.all().filter(y=>y.cwd&&y.cwd.replace(/\/+$/,"")===_&&!de(y.tab_name));if(E.length===1){let y=E[0],k=on({sessionStartedAt:g.started_at??null,terminalOpenedAt:y.opened_at??null});if(!k.allowed)return i.json({applied:!1,reason:"temporal-guard",guard_reason:k.reason});let N=I.getOrigin(l),A=St({tabName:y.tab_name,origin:N??null,cwd:g.cwd??null,gitBranch:g.git_branch??null});return A?(he(l,A),I.linkSession(l,y.shell_pid),i.json({applied:!0,alias:A,linked_pid:y.shell_pid,linked_tab_name:y.tab_name,method:"cwd-singleton"})):i.json({applied:!1,reason:"no-usable-name"})}if(E.length>1){let y=await Cc(l);if(y){let N=I.get(y.shell_pid),A=on({sessionStartedAt:g.started_at??null,terminalOpenedAt:N?.opened_at??null});if(!A.allowed)return i.json({applied:!1,reason:"temporal-guard",guard_reason:A.reason});let O=I.getOrigin(l),C=St({tabName:y.tab_name,origin:O??null,cwd:g.cwd??null,gitBranch:g.git_branch??null});if(C)return he(l,C),I.linkSession(l,y.shell_pid),i.json({applied:!0,alias:C,linked_pid:y.shell_pid,linked_tab_name:y.tab_name,matched_fingerprints:y.matched_fingerprints,method:"content-match"})}let k=6e4;if(g.started_at){let N=Date.parse(g.started_at);if(Number.isFinite(N)){let A=E.filter(C=>on({sessionStartedAt:g.started_at,terminalOpenedAt:C.opened_at??null}).allowed).map(C=>({t:C,gap:N-Date.parse(C.opened_at??"")})).filter(C=>Number.isFinite(C.gap)&&C.gap>=0&&C.gap<=k);if(A.length>=2)return i.json({applied:!1,reason:"ambiguous-temporal",candidate_count:A.length});let O=A[0];if(O){let C=I.getOrigin(l),v=St({tabName:O.t.tab_name,origin:C??null,cwd:g.cwd??null,gitBranch:g.git_branch??null});if(v)return he(l,v),I.linkSession(l,O.t.shell_pid),i.json({applied:!0,alias:v,linked_pid:O.t.shell_pid,linked_tab_name:O.t.tab_name,method:"closest-before-temporal",gap_ms:O.gap})}}}return i.json({applied:!1,reason:"ambiguous",candidate_count:E.length})}return i.json({applied:!1,reason:"no-candidates"})}),t.post("/api/sessions/:id/relink",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>null);if(p?.clear)return I.unlinkSession(l),Qn(l),i.json({ok:!0,alias:null,linked_pid:null});if(!p||typeof p.shell_pid!="number")return i.json({error:"shell_pid required"},400);let g=I.get(p.shell_pid);if(!g)return i.json({error:"terminal not registered"},404);let _=I.getOrigin(l),E=f().prepare("SELECT cwd, git_branch FROM sessions WHERE id = ?").get(l),y=null,k=g.tab_name?.trim()??"";if(k&&!de(k)&&!le(k))y=k;else if(k&&le(k)){let N=bt(k);N&&!de(N)&&(y=N)}return y?(I.unlinkSession(l),he(l,y),i.json({ok:!0,alias:y,linked_pid:p.shell_pid,linked_tab_name:g.tab_name})):i.json({error:"terminal has no usable name, name the tab in your editor first, then retry the relink"},422)}),t.post("/api/sessions/:id/recorrelate",async i=>{let l=i.req.param("id"),p=f().prepare("SELECT file_path FROM sessions WHERE id = ?").get(l);if(!p?.file_path)return i.json({error:"session not found"},404);I.unlinkSession(l),Qn(l),await ns(p.file_path);let g=Te(l);return i.json({ok:!0,alias:g,linked_pid:I.all().find(_=>I.sessionsFor(_.shell_pid).includes(l))?.shell_pid??null})}),t.get("/api/paste-expand",async i=>{let l=i.req.query("session"),p=i.req.query("message"),g=i.req.query("path");if(!l||!p||!g)return i.json({error:"session, message and path are required"},400);let _=f(),E=_.prepare("SELECT rowid, content_text FROM messages WHERE uuid = ? AND session_id = ?").get(p,l);if(!E)return i.json({error:"message not found in session"},404);let y=g.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");if(!new RegExp(`\\[Pasted text #\\d+ \\+\\d+ lines\\]\\s*${y}`).test(E.content_text??""))return i.json({error:"path not referenced by this message"},403);let N=_.prepare(`SELECT content_text FROM messages
2003
+ ORDER BY COALESCE(timestamp, ''), rowid`).all(p),N=Hl(y,w,{mode:g,includeSidechain:_,prelude:E});return i.text(N)}),t.get("/api/collections",i=>{let l=i.req.query("archived")==="1";return i.json({collections:pl(l)})}),t.get("/api/collections/:id",i=>{let l=i.req.param("id"),p=Be(l);if(!p)return i.json({error:"not found"},404);let g=ml(l,!0);return i.json({collection:p,members:g})}),t.post("/api/collections",async i=>{let l=await i.req.json().catch(()=>null);if(!l||typeof l.name!="string")return i.json({error:"name required"},400);try{let p=sn({name:l.name,description:l.description??null,icon:l.icon??null,color:l.color??null,parent_id:l.parent_id??null,sort_key:l.sort_key});return i.json(p,201)}catch(p){return i.json({error:p.message},400)}}),t.patch("/api/collections/:id",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>null);if(!p)return i.json({error:"body required"},400);try{let g=_l(l,p);return i.json(g)}catch(g){return i.json({error:g.message},400)}}),t.post("/api/collections/:id/archive",i=>{let l=i.req.param("id");try{let p=fl(l);return i.json(p)}catch(p){return i.json({error:p.message},404)}}),t.post("/api/collections/:id/restore",i=>{let l=i.req.param("id");try{let p=hl(l);return i.json(p)}catch(p){return i.json({error:p.message},404)}}),t.post("/api/collections/:id/members",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>null);if(!p||typeof p.session_id!="string")return i.json({error:"session_id required"},400);try{let g=rn(l,p.session_id,p.note??null);return i.json(g)}catch(g){return i.json({error:g.message},400)}}),t.delete("/api/collections/:id/members/:sid",i=>{let l=i.req.param("id"),p=i.req.param("sid");try{let g=El(l,p);return i.json(g)}catch(g){return i.json({error:g.message},400)}}),t.get("/api/sessions/:id/collections",i=>{let l=i.req.param("id");return i.json({collections:gl(l)})});let O=["cwd-prefix","project-id","tag","plan-file","git-branch-prefix"];t.get("/api/auto-collections/rules",i=>i.json({rules:wl()})),t.post("/api/auto-collections/rules",async i=>{let l=await i.req.json().catch(()=>null);if(!l||typeof l.name!="string"||typeof l.pattern!="string"||!l.type||!O.includes(l.type))return i.json({error:"name, type, pattern required (type must be a known matcher)"},400);try{let p=fo({name:l.name,type:l.type,pattern:l.pattern,collection_id:l.collection_id,parent_collection_id:l.parent_collection_id,priority:l.priority,enabled:l.enabled});return i.json(p,201)}catch(p){return i.json({error:p.message},400)}}),t.patch("/api/auto-collections/rules/:id",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>null);if(!p)return i.json({error:"body required"},400);try{let g=Rl(l,p);return i.json(g)}catch(g){return i.json({error:g.message},400)}}),t.delete("/api/auto-collections/rules/:id",i=>{let l=i.req.param("id");try{let p=kl(l);return i.json(p)}catch(p){return i.json({error:p.message},400)}}),t.get("/api/auto-collections/suggestions",i=>{let l=i.req.query("dismissed")==="1";return i.json({suggestions:bs({includeDismissed:l})})}),t.post("/api/auto-collections/suggestions/:id/accept",i=>{let l=i.req.param("id");try{let p=xl(l);return i.json({rule:p})}catch(p){return i.json({error:p.message},400)}}),t.post("/api/auto-collections/suggestions/:id/dismiss",i=>{let l=i.req.param("id");try{return Al(l),i.json({ok:!0})}catch(p){return i.json({error:p.message},400)}}),t.post("/api/auto-collections/detect",i=>{let l=Ss();return i.json({suggestions:l})}),t.get("/api/auto-collections/suggestions/:id/preview",i=>{let l=i.req.param("id"),p=Math.max(1,Math.min(20,Number(i.req.query("limit"))||3)),_=bs({includeDismissed:!1}).find(y=>y.id===l);if(!_)return i.json({error:"suggestion not found"},404);let E=Tl(_.type,_.pattern,p);return i.json({sessions:E})}),t.get("/api/auto-collections/parents",i=>{let l=Array.from(Nl());return i.json({auto_collection_ids:l})}),t.get("/api/threads",i=>{let l=i.req.query("archived")==="1";return i.json({threads:vo({includeArchived:l})})}),t.get("/api/threads/:id",i=>{let l=i.req.param("id"),p=ie(l);if(!p)return i.json({error:"thread not found"},404);let g=p.edges.map(_=>({..._,alias_source:_.alias==null?null:M.isSessionAutoLinked(_.session_id)?"auto":"manual"}));return i.json({thread:{...p,edges:g}})}),t.post("/api/threads",async i=>{let l=await i.req.json().catch(()=>({}));if(!l.name)return i.json({error:"name required"},400);try{let p=ks({name:l.name,summary:l.summary??null,originSessionId:l.originSessionId});return i.json({thread:p})}catch(p){return i.json({error:p.message},400)}}),t.patch("/api/threads/:id",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>({}));try{p.name&&ou(l,p.name),p.close&&iu(l),p.reopen&&au(l),p.archive&&cu(l),"folder_id"in p&&Nu(l,p.folder_id??null);let g=ie(l);return g?i.json({thread:g}):i.json({error:"thread not found"},404)}catch(g){return i.json({error:g.message},400)}}),t.get("/api/thread-folders",i=>i.json({folders:Do()})),t.post("/api/thread-folders",async i=>{let l=await i.req.json().catch(()=>({}));if(!l.name||typeof l.name!="string")return i.json({error:"name required"},400);try{let p=yu({name:l.name,parentFolderId:l.parent_folder_id??null,projectScope:l.project_scope??null});return i.json({folder:p})}catch(p){return i.json({error:p.message},400)}}),t.patch("/api/thread-folders/:id",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>({}));try{let g;return p.name&&(g=Ru(l,p.name)),"parent_folder_id"in p&&(g=ku(l,p.parent_folder_id??null)),g?i.json({folder:g}):i.json({error:"no patch fields"},400)}catch(g){return i.json({error:g.message},400)}}),t.delete("/api/thread-folders/:id",i=>{let l=i.req.param("id");try{return xu(l),i.json({ok:!0})}catch(p){return i.json({error:p.message},400)}}),t.post("/api/thread-folders/reorder",async i=>{let l=await i.req.json().catch(()=>({})),p=l.ordered_ids;if(!Array.isArray(p))return i.json({error:"ordered_ids must be an array"},400);try{return Au(l.parent_folder_id??null,l.project_scope??null,p),i.json({ok:!0})}catch(g){return i.json({error:g.message},400)}}),t.post("/api/threads/:id/sessions",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>({}));if(!p.sessionId)return i.json({error:"sessionId required"},400);try{let g=As({threadId:l,sessionId:p.sessionId,parentSessionId:p.parentSessionId??null,role:p.role});return i.json({edge:g})}catch(g){return i.json({error:g.message},400)}}),t.delete("/api/threads/:id/sessions/:sessionId",i=>{let l=i.req.param("id"),p=i.req.param("sessionId"),g=ru(l,p);return i.json(g)}),t.patch("/api/threads/:id/sessions/:sessionId",async i=>{let l=i.req.param("id"),p=i.req.param("sessionId"),g=await i.req.json().catch(()=>({}));try{let _=an(l,p,g.parentSessionId??null);return i.json({edge:_})}catch(_){return i.json({error:_.message},400)}}),t.post("/api/threads/:id/merge",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>({}));if(!p.sourceId)return i.json({error:"sourceId required"},400);try{let g=lu(p.sourceId,l);return i.json({thread:g})}catch(g){return i.json({error:g.message},400)}}),t.post("/api/threads/:id/split",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>({}));if(!p.sessionIds?.length||!p.newThreadName)return i.json({error:"sessionIds and newThreadName required"},400);try{let g=uu({threadId:l,sessionIds:p.sessionIds,newThreadName:p.newThreadName});return i.json({thread:g})}catch(g){return i.json({error:g.message},400)}}),t.get("/api/sessions/:id/threads",i=>{let l=i.req.param("id");return i.json({threads:su(l)})});let L=D.object({enabled:D.boolean(),band_lo:D.number().min(0).max(1).optional(),band_hi:D.number().min(0).max(1).optional(),model:D.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional()}).optional(),x=D.object({project:D.string().min(1),threshold:D.number().min(0).max(1).optional(),model:D.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional(),llm_rescore:L});t.post("/api/threads/scan/preflight",async i=>{let l=Ce(i);if(l)return l;let p=await i.req.json().catch(()=>null),g=x.safeParse(p);if(!g.success)return i.json({error:"invalid request body",details:g.error.format()},400);let _=zd({project:g.data.project,threshold:g.data.threshold,model:g.data.model,llm_rescore:g.data.llm_rescore});return"error"in _?i.json({error:_.error},400):i.json(_)});let F=D.object({project:D.string().min(1),threshold:D.number().min(0).max(1).optional(),llm_names:D.boolean().optional(),model:D.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional(),llm_rescore:L});t.post("/api/threads/scan/apply",async i=>{let l=Ce(i);if(l)return l;let p=await i.req.json().catch(()=>null),g=F.safeParse(p);if(!g.success)return i.json({error:"invalid request body",details:g.error.format()},400);let _=Vd({project:g.data.project,threshold:g.data.threshold,llm_names:g.data.llm_names,model:g.data.model,llm_rescore:g.data.llm_rescore});return"error"in _?i.json({error:_.error},400):i.json({jobId:_.jobId,reused:_.reused},_.reused?409:200)}),t.get("/api/threads/scan/jobs/:jobId/stream",i=>{let l=i.req.param("jobId");if(!oi(l))return i.json({error:"job not found"},404);let g=Number(i.req.header("Last-Event-ID")??0);return Ye(i,async _=>{let E=!1,y=setInterval(()=>{E||_.writeSSE({event:"heartbeat",data:""}).catch(()=>{E=!0})},15e3);try{for await(let w of Zd(l,g))if(E||(await _.writeSSE({id:String(w.id),event:w.kind,data:JSON.stringify(w.data)}),w.kind==="done"))break}finally{E=!0,clearInterval(y)}})}),t.get("/api/threads/scan/jobs/:jobId",i=>{let l=oi(i.req.param("jobId"));return l?i.json(l):i.json({error:"job not found"},404)}),t.delete("/api/threads/scan/jobs/:jobId",i=>{let l=Ce(i);return l||(Qd(i.req.param("jobId"))?i.json({ok:!0}):i.json({error:"job not found or already done"},404))});let A=D.object({project_id:D.number().int().positive(),mode:D.enum(["preflight","apply"]),window_hours:D.number().min(.5).max(168).optional(),score_threshold:D.number().min(0).max(1).optional(),use_live_pids:D.boolean().optional()});t.post("/api/threads/sync-active",async i=>{let l=await i.req.json().catch(()=>null),p=A.safeParse(l);if(!p.success)return i.json({error:"invalid request body",details:p.error.format()},400);try{let g=await bu(p.data.project_id,{windowHours:p.data.window_hours,scoreThreshold:p.data.score_threshold,useLivePids:p.data.use_live_pids});if(p.data.mode==="preflight")return i.json({plan:g});let _=Su(g);return i.json({plan:g,result:_})}catch(g){return i.json({error:g.message},400)}}),t.get("/api/threads/:id/titles/preflight",i=>{let l=i.req.param("id"),p=ie(l);if(!p)return i.json({error:"thread not found"},404);let g=f(),_=0;for(let E of p.edges)g.prepare("SELECT auto_title_source FROM sessions WHERE id = ?").get(E.session_id)?.auto_title_source==="agent"&&(_+=1);return i.json({total:p.edges.length,alreadyTitled:_,untitled:p.edges.length-_})}),t.post("/api/threads/:id/titles/generate",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>({})),g=ie(l);if(!g)return i.json({error:"thread not found"},404);if(g.edges.length===0)return i.json({error:"thread has no sessions"},400);let _=Fe(),E=p.model??_.model,y=Bu({threadId:l,force:p.force??!1,model:E});return i.json({jobId:y})}),t.get("/api/jobs/:jobId/stream",i=>{let l=i.req.param("jobId");if(!Fo(l))return i.json({error:"job not found"},404);let g=Number(i.req.header("Last-Event-ID")??0);return Ye(i,async _=>{let E=!1,y=setInterval(()=>{E||_.writeSSE({event:"heartbeat",data:""}).catch(()=>{E=!0})},15e3);try{for await(let w of Hu(l,g))if(E||(await _.writeSSE({id:String(w.id),event:w.kind,data:JSON.stringify(w.data)}),w.kind==="done"))break}finally{E=!0,clearInterval(y)}})}),t.get("/api/jobs/:jobId",i=>{let l=Fo(i.req.param("jobId"));return l?i.json(l):i.json({error:"job not found"},404)}),t.delete("/api/jobs/:jobId",i=>Wu(i.req.param("jobId"))?i.json({ok:!0}):i.json({error:"job not found or already done"},404)),t.post("/api/terminal/opened",async i=>{let l=await i.req.json().catch(()=>null);if(!l||typeof l.shell_pid!="number"||typeof l.tab_name!="string")return i.json({error:"shell_pid and tab_name required"},400);let p=M.claimPidOwnership(l.shell_pid,l.extension_instance_id??null);if(p==="rejected")return i.json({ok:!0,rejected:!0,reason:"pid-owned-by-other-extension-instance",count:M.size()});let g=M.upsert({shell_pid:l.shell_pid,tab_name:l.tab_name,cwd:l.cwd??null,opened_at:l.opened_at??new Date().toISOString()});return i.json({ok:!0,ownership:p,count:M.size(),entry:g})}),t.post("/api/terminal/renamed",async i=>{let l=await i.req.json().catch(()=>null);if(!l||typeof l.shell_pid!="number"||typeof l.tab_name!="string")return i.json({error:"shell_pid and tab_name required"},400);let p=M.claimPidOwnership(l.shell_pid,l.extension_instance_id??null);if(p==="rejected")return i.json({ok:!0,rejected:!0,reason:"pid-owned-by-other-extension-instance"});let g=M.rename(l.shell_pid,l.tab_name);if(!g)return i.json({error:"unknown shell_pid"},404);let _=lm(l.shell_pid,l.tab_name);return i.json({ok:!0,ownership:p,entry:g,propagated:_})}),t.post("/api/terminal/closed",async i=>{let l=await i.req.json().catch(()=>null);if(!l||typeof l.shell_pid!="number")return i.json({error:"shell_pid required"},400);let p=M.remove(l.shell_pid);return i.json({ok:!0,removed:p,count:M.size()})}),t.post("/api/terminal/claude-started",async i=>{let l=await i.req.json().catch(()=>null);return!l||typeof l.shell_pid!="number"?i.json({error:"shell_pid required"},400):(M.pushPending({shell_pid:l.shell_pid,tab_name:typeof l.tab_name=="string"?l.tab_name:"",cwd:typeof l.cwd=="string"?l.cwd:null,started_at:typeof l.started_at=="string"?l.started_at:new Date().toISOString()}),i.json({ok:!0,pending:M.pendingSize()}))}),t.post("/api/terminal/output",async i=>{let l=await i.req.json().catch(()=>null);if(!l||typeof l.shell_pid!="number"||typeof l.text!="string")return i.json({error:"shell_pid and text required"},400);let p=l.text.length>8192?l.text.slice(-8192):l.text,g=typeof l.captured_at=="string"?l.captured_at:new Date().toISOString();return M.setOutputTail(l.shell_pid,p,g),i.json({ok:!0})}),t.post("/api/terminal/sync",async i=>{let l=await i.req.json().catch(()=>null);if(!l||!Array.isArray(l.terminals))return i.json({error:"terminals array required"},400);let p=new Map;for(let v of M.all())p.set(v.shell_pid,v.tab_name);let g=l.terminals.filter(v=>!!v&&typeof v.shell_pid=="number"&&typeof v.tab_name=="string").map(v=>({shell_pid:v.shell_pid,tab_name:v.tab_name,cwd:v.cwd??null,opened_at:v.opened_at??new Date().toISOString()})),_=l.extension_instance_id??null,E=[],y=g.filter(v=>{let P=M.claimPidOwnership(v.shell_pid,_);return E.push({shell_pid:v.shell_pid,ownership:P}),P!=="rejected"}),w=M.sync(y),N=0;for(let v of y){let P=p.get(v.shell_pid),q=M.get(v.shell_pid)?.tab_name??v.tab_name,G=!!q&&!de(q)&&!le(q)?q:v.tab_name;P!==void 0&&P!==G&&(N+=lm(v.shell_pid,G))}let k=E.filter(v=>v.ownership==="rejected").length;k>0&&console.log(`[terminal/sync] dropped ${k} tab_name update(s), pid(s) owned by a different extension instance`);let C=await Bw(),I={resolved:0,expired:0};try{I=Pc()}catch{}let j={rebound:0,ghosts:0,ambiguous:0};try{j=Fc()}catch{}return Qw(),i.json({ok:!0,count:M.size(),diff:w,propagated:N,live_sweep:C,deferred_resolved:I,rebound:j})}),t.get("/api/terminal/registry",i=>i.json({terminals:M.all(),count:M.size()})),t.get("/api/terminal/sessions/:shellPid",i=>{let l=i.req.param("shellPid"),p=Number(l);if(!Number.isInteger(p)||p<=0)return i.json({error:"shellPid must be a positive integer"},400);let g=M.sessionsFor(p);return i.json({shell_pid:p,sessions:g})}),t.get("/api/sessions/:id/linked-terminal",i=>{let l=i.req.param("id"),p=M.all().find(_=>M.sessionsFor(_.shell_pid).includes(l)),g=[];if(!p){let _=f().prepare("SELECT cwd, started_at FROM sessions WHERE id = ?").get(l);if(_?.cwd&&_.started_at){let E=Date.parse(_.started_at);if(Number.isFinite(E)){let y=_.cwd.replace(/\/+$/,""),w=300*1e3;for(let N of M.all()){if(!N.cwd||N.cwd.replace(/\/+$/,"")!==y||de(N.tab_name))continue;let k=Date.parse(N.opened_at),C=Date.parse(N.last_seen_at);!Number.isFinite(k)||!Number.isFinite(C)||k>E||C+w<E||g.push({shell_pid:N.shell_pid,tab_name:N.tab_name,cwd:N.cwd,opened_at:N.opened_at,last_seen_at:N.last_seen_at,reason:"time-overlap"})}g.sort((N,k)=>Date.parse(k.last_seen_at)-Date.parse(N.last_seen_at))}}}return p?i.json({linked:{shell_pid:p.shell_pid,tab_name:p.tab_name,cwd:p.cwd},suggested:[]}):i.json({linked:null,suggested:g})}),t.post("/api/sessions/:id/auto-relink",async i=>{let l=i.req.param("id");if(Te(l))return i.json({applied:!1,reason:"has-alias"});if(M.all().some(y=>M.sessionsFor(y.shell_pid).includes(l)))return i.json({applied:!1,reason:"already-linked"});let g=f().prepare("SELECT cwd, git_branch, started_at FROM sessions WHERE id = ?").get(l);if(!g?.cwd)return i.json({applied:!1,reason:"no-cwd"});let _=g.cwd.replace(/\/+$/,""),E=M.all().filter(y=>y.cwd&&y.cwd.replace(/\/+$/,"")===_&&!de(y.tab_name));if(E.length===1){let y=E[0],w=on({sessionStartedAt:g.started_at??null,terminalOpenedAt:y.opened_at??null});if(!w.allowed)return i.json({applied:!1,reason:"temporal-guard",guard_reason:w.reason});let N=M.getOrigin(l),k=St({tabName:y.tab_name,origin:N??null,cwd:g.cwd??null,gitBranch:g.git_branch??null});return k?(he(l,k),M.linkSession(l,y.shell_pid),i.json({applied:!0,alias:k,linked_pid:y.shell_pid,linked_tab_name:y.tab_name,method:"cwd-singleton"})):i.json({applied:!1,reason:"no-usable-name"})}if(E.length>1){let y=await Dc(l);if(y){let N=M.get(y.shell_pid),k=on({sessionStartedAt:g.started_at??null,terminalOpenedAt:N?.opened_at??null});if(!k.allowed)return i.json({applied:!1,reason:"temporal-guard",guard_reason:k.reason});let C=M.getOrigin(l),I=St({tabName:y.tab_name,origin:C??null,cwd:g.cwd??null,gitBranch:g.git_branch??null});if(I)return he(l,I),M.linkSession(l,y.shell_pid),i.json({applied:!0,alias:I,linked_pid:y.shell_pid,linked_tab_name:y.tab_name,matched_fingerprints:y.matched_fingerprints,method:"content-match"})}let w=6e4;if(g.started_at){let N=Date.parse(g.started_at);if(Number.isFinite(N)){let k=E.filter(I=>on({sessionStartedAt:g.started_at,terminalOpenedAt:I.opened_at??null}).allowed).map(I=>({t:I,gap:N-Date.parse(I.opened_at??"")})).filter(I=>Number.isFinite(I.gap)&&I.gap>=0&&I.gap<=w);if(k.length>=2)return i.json({applied:!1,reason:"ambiguous-temporal",candidate_count:k.length});let C=k[0];if(C){let I=M.getOrigin(l),j=St({tabName:C.t.tab_name,origin:I??null,cwd:g.cwd??null,gitBranch:g.git_branch??null});if(j)return he(l,j),M.linkSession(l,C.t.shell_pid),i.json({applied:!0,alias:j,linked_pid:C.t.shell_pid,linked_tab_name:C.t.tab_name,method:"closest-before-temporal",gap_ms:C.gap})}}}return i.json({applied:!1,reason:"ambiguous",candidate_count:E.length})}return i.json({applied:!1,reason:"no-candidates"})}),t.post("/api/sessions/:id/relink",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>null);if(p?.clear)return M.unlinkSession(l),es(l),i.json({ok:!0,alias:null,linked_pid:null});if(!p||typeof p.shell_pid!="number")return i.json({error:"shell_pid required"},400);let g=M.get(p.shell_pid);if(!g)return i.json({error:"terminal not registered"},404);let _=M.getOrigin(l),E=f().prepare("SELECT cwd, git_branch FROM sessions WHERE id = ?").get(l),y=null,w=g.tab_name?.trim()??"";if(w&&!de(w)&&!le(w))y=w;else if(w&&le(w)){let N=bt(w);N&&!de(N)&&(y=N)}return y?(M.unlinkSession(l),he(l,y),i.json({ok:!0,alias:y,linked_pid:p.shell_pid,linked_tab_name:g.tab_name})):i.json({error:"terminal has no usable name, name the tab in your editor first, then retry the relink"},422)}),t.post("/api/sessions/:id/recorrelate",async i=>{let l=i.req.param("id"),p=f().prepare("SELECT file_path FROM sessions WHERE id = ?").get(l);if(!p?.file_path)return i.json({error:"session not found"},404);M.unlinkSession(l),es(l),await ss(p.file_path);let g=Te(l);return i.json({ok:!0,alias:g,linked_pid:M.all().find(_=>M.sessionsFor(_.shell_pid).includes(l))?.shell_pid??null})}),t.get("/api/paste-expand",async i=>{let l=i.req.query("session"),p=i.req.query("message"),g=i.req.query("path");if(!l||!p||!g)return i.json({error:"session, message and path are required"},400);let _=f(),E=_.prepare("SELECT rowid, content_text FROM messages WHERE uuid = ? AND session_id = ?").get(p,l);if(!E)return i.json({error:"message not found in session"},404);let y=g.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");if(!new RegExp(`\\[Pasted text #\\d+ \\+\\d+ lines\\]\\s*${y}`).test(E.content_text??""))return i.json({error:"path not referenced by this message"},403);let N=_.prepare(`SELECT content_text FROM messages
1990
2004
  WHERE session_id = ? AND rowid > ?
1991
- ORDER BY rowid ASC LIMIT 10`).all(l,E.rowid);for(let A of N){let O=A.content_text??"";if(O.includes("**Tool result**")&&O.includes(g))return i.json({source:"tool-result",content:O});if(/^\s*1\t/.test(O)&&O.length>200)return i.json({source:"tool-result",content:O})}try{let A=await _w(g),O=hw();if(!A.startsWith(O+"/")&&!A.startsWith(O+"\\"))return i.json({error:"path outside allowed root"},403);let C=[".ssh",".gnupg",".gpg",".aws",".kube",".docker",".password-store"],L=A.slice(O.length+1).split("/")[0].split("\\")[0];if(C.includes(L))return i.json({error:"path inside sensitive directory"},403);let F=await mw(A),q=2*1024*1024;if(F.size>q)return i.json({error:"file too large",size:F.size,max:q},413);let K=await gw(A,"utf8");return i.json({source:"disk",content:K})}catch(A){return i.json({source:"missing",error:A.message})}}),t.get("/api/projects/:name/stats",i=>{let l=f(),p=i.req.param("name"),g=l.prepare(`SELECT
2005
+ ORDER BY rowid ASC LIMIT 10`).all(l,E.rowid);for(let k of N){let C=k.content_text??"";if(C.includes("**Tool result**")&&C.includes(g))return i.json({source:"tool-result",content:C});if(/^\s*1\t/.test(C)&&C.length>200)return i.json({source:"tool-result",content:C})}try{let k=await Fw(g),C=$w();if(!k.startsWith(C+"/")&&!k.startsWith(C+"\\"))return i.json({error:"path outside allowed root"},403);let I=[".ssh",".gnupg",".gpg",".aws",".kube",".docker",".password-store"],v=k.slice(C.length+1).split("/")[0].split("\\")[0];if(I.includes(v))return i.json({error:"path inside sensitive directory"},403);let P=await Mw(k),q=2*1024*1024;if(P.size>q)return i.json({error:"file too large",size:P.size,max:q},413);let K=await Dw(k,"utf8");return i.json({source:"disk",content:K})}catch(k){return i.json({source:"missing",error:k.message})}}),t.get("/api/projects/:name/stats",i=>{let l=f(),p=i.req.param("name"),g=l.prepare(`SELECT
1992
2006
  (SELECT COUNT(*) FROM sessions s JOIN projects p ON p.id=s.project_id WHERE p.name=? AND s.message_count > 2) AS sessions,
1993
2007
  (SELECT COALESCE(SUM(s.message_count), 0) FROM sessions s JOIN projects p ON p.id=s.project_id WHERE p.name=?) AS messages,
1994
2008
  (SELECT MIN(s.started_at) FROM sessions s JOIN projects p ON p.id=s.project_id WHERE p.name=? AND s.started_at IS NOT NULL) AS earliest,
@@ -1996,4 +2010,4 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1996
2010
  JOIN projects p ON p.id = s.project_id
1997
2011
  WHERE p.name = ? AND s.git_branch IS NOT NULL
1998
2012
  ORDER BY s.git_branch
1999
- LIMIT 20`).all(p).map(E=>E.git_branch);return i.json({...g,branches:_})});function P(i){return i.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function te(i){if(!e)return i;let l=`<meta name="recall-token" content="${P(e)}" />`,p=i.indexOf("</head>");return p!==-1?i.slice(0,p)+l+i.slice(p):l+i}function B(i){let l=rm();return i.html(jl({projects:l.projects,sessions:l.sessions,messages:l.messages,port:Number(i.req.raw.headers.get("host")?.split(":")[1]??0),version:sm}))}function se(){try{return yi(im,"utf8")}catch{return null}}return Aw?(t.use("/assets/*",tm({root:Ri})),t.get("/favicon.svg",tm({root:Ri})),t.get("/",i=>{i.header("cache-control","no-cache, no-store, must-revalidate"),i.header("pragma","no-cache"),i.header("expires","0");let l=se();return l===null?B(i):i.html(te(l))}),t.get("*",i=>{if(i.req.path.startsWith("/api/"))return i.notFound();i.header("cache-control","no-cache, no-store, must-revalidate"),i.header("pragma","no-cache"),i.header("expires","0");let l=se();return l===null?B(i):i.html(te(l))})):t.get("/",i=>B(i)),t}function jw(){if(Js(),!!rt().heuristicEnabled){try{let{updated:e}=Kc();e>0&&console.log(`[auto-title] backfilled heuristic title on ${e} sessions`)}catch(e){console.error("[auto-title] backfill failed:",e)}try{let{scanned:e,updated:t}=Vc();t>0&&console.log(`[auto-title] refreshed templated heuristic title on ${t}/${e} sessions`)}catch(e){console.error("[auto-title] templated-title refresh failed:",e)}try{let{scanned:e,updated:t}=Zc();t>0&&console.log(`[auto-title] refreshed recursive_meta title on ${t}/${e} sessions`)}catch(e){console.error("[auto-title] recursive_meta refresh failed:",e)}try{let{scanned:e,updated:t}=Qc();t>0&&console.log(`[auto-title] canonicalized brand on ${t}/${e} session titles`)}catch(e){console.error("[auto-title] brand canonicalization failed:",e)}}}async function lm(e,t){let n=Iw(t);return new Promise((s,r)=>{try{let o=dw({fetch:n.fetch,port:e,hostname:"127.0.0.1"},()=>{s(o),setImmediate(()=>{try{jw()}catch(a){console.error("[daemon] startup maintenance crashed:",a)}})})}catch(o){r(o)}})}import{createServer as dm}from"node:net";function um(e){return new Promise(t=>{let n=dm();n.once("error",()=>t(!1)),n.once("listening",()=>{n.close(()=>t(!0))}),n.listen(e,"127.0.0.1")})}async function pm(){let e=new Set([3e3,3001,4200,5e3,5173,8e3,8080,8888,9e3]),t=51370;if(!e.has(t)&&await um(t))return t;for(let n=0;n<50;n++){let s=49152+Math.floor(Math.random()*16383);if(!e.has(s)&&await um(s))return s}return new Promise((n,s)=>{let r=dm();r.once("error",s),r.listen(0,"127.0.0.1",()=>{let o=r.address();if(o&&typeof o=="object"){let a=o.port;r.close(()=>n(a))}else r.close(),s(new Error("could not determine a free port"))})})}ee();import{existsSync as Pw,readFileSync as Yv,writeFileSync as gm,unlinkSync as $w}from"node:fs";import{join as Ni}from"node:path";ee();import{randomBytes as Mw}from"node:crypto";import{writeFileSync as Dw,readFileSync as Bv,existsSync as Hv}from"node:fs";import{join as Fw}from"node:path";var xi=Fw(H,"daemon.token");function mm(){z();let e=Mw(32).toString("hex");return Dw(xi,e,{encoding:"utf8",mode:384}),e}var _m=Ni(H,"daemon.pid"),fm=Ni(H,"daemon.port"),Vv=Ni(H,"daemon.log");function hm(e){z(),gm(_m,JSON.stringify(e),{encoding:"utf8",mode:384}),gm(fm,String(e.port),{encoding:"utf8",mode:384})}function Oi(){for(let e of[_m,fm,xi])if(Pw(e))try{$w(e)}catch{}}Dr();U();ee();Ve();var Bw=Math.max(1,Uw().length),Em=String(Math.max(2,Math.floor(Bw/2)));process.env.OMP_NUM_THREADS||(process.env.OMP_NUM_THREADS=Em);process.env.ORT_NUM_THREADS||(process.env.ORT_NUM_THREADS=Em);var Hw=360*60*1e3,Ww=60*1e3,qw=1440*60*1e3,Xw=300*1e3,Jw=300*1e3,Yw=10*1e3,Gw=1440*60*1e3,zw=30*1e3,Kw=500,Vw=1500,Zw=6e4;async function Qw(){let e=await pm(),t=mm();(!t||t.length<32)&&(console.error("[daemon] FATAL: daemon token init returned empty or undersized \u2014 refusing to start"),process.exit(1));let n=await lm(e,t);hm({pid:process.pid,port:e,startedAt:new Date().toISOString()}),Ar(ce().enabled);try{Qt();let x=ic();x>0&&console.log(`[daemon] archive: migrated ${x} hot row(s) into archive.sqlite`)}catch(x){let P=x instanceof Error?x.message:String(x);console.error(`[daemon] archive migration failed: ${P}`)}let s=Il({db:f(),walPath:`${Bt}-wal`}),r=Ll(),o=setInterval(()=>{Cl()},Zw),a=()=>{try{bs()}catch(x){console.error("[daemon] suggestion scan failed:",x)}},c=setTimeout(a,Ww),u=setInterval(a,Hw),d=()=>{try{let x=I.reapStaleLinks();(x.pruned_pids||x.pruned_sessions)&&console.log(`[daemon] reaper: pruned ${x.pruned_pids} pid${x.pruned_pids===1?"":"s"}, ${x.pruned_sessions} session link${x.pruned_sessions===1?"":"s"}`)}catch(x){console.error("[daemon] stale-link reaper failed:",x)}},m=setTimeout(d,Xw),h=setInterval(d,qw),S=()=>{try{let x=I.gcDeadPids();(x.pruned_pids||x.pruned_sessions)&&console.log(`[daemon] dead-pid gc: pruned ${x.pruned_pids} pid${x.pruned_pids===1?"":"s"}, ${x.pruned_sessions} session link${x.pruned_sessions===1?"":"s"}`)}catch(x){console.error("[daemon] dead-pid gc failed:",x)}},b=setTimeout(S,Yw),T=setInterval(S,Jw),R=()=>{Bi().then(x=>{x.ran&&x.revoked&&console.log(`[daemon] license check: REVOKED${x.reason?` (${x.reason})`:""}`)}).catch(x=>{console.error("[daemon] license check failed:",x)})},w=setTimeout(R,zw),j=setInterval(R,Gw),M=bc();(async()=>{try{if(!Ye())return;let x=f().prepare("SELECT COUNT(*) AS n FROM chunk_queue").get();if(x.n===0)return;if(!ce().autoResumeWorker){console.log(`[daemon] vector-worker dormant: ${x.n} chunk(s) pending in queue. Run \`recall vectorize\` or click Start in the web UI to drain. To restore auto-resume, set semantic.autoResumeWorker=true in ~/.recall/config.json.`);return}let te=await Ke();if(te.tier!=="pro"){console.log(`[daemon] vector-worker auto-resume skipped: ${x.n} chunk(s) pending but license tier is ${te.tier}`);return}_e().loaded||await Ue(),Ie().running||(kn(),console.log(`[daemon] vector-worker auto-resumed: ${x.n} chunk(s) pending`))}catch(x){let P=x instanceof Error?x.message:String(x);console.error(`[daemon] vector-worker auto-resume failed: ${P}`)}})();let W=x=>{console.log(`[daemon] received ${x}, shutting down`),clearTimeout(c),clearInterval(u),clearTimeout(m),clearInterval(h),clearTimeout(b),clearInterval(T),clearTimeout(w),clearInterval(j),clearInterval(o),M.stop(),s.stop(),r.close(),n.close(),Oi(),process.exit(0)};process.on("SIGTERM",()=>W("SIGTERM")),process.on("SIGINT",()=>W("SIGINT")),process.on("SIGHUP",()=>W("SIGHUP")),console.log(`[daemon] ready on http://127.0.0.1:${e} pid=${process.pid}`),setTimeout(()=>{ss().then(x=>{console.log(`[daemon] boot sweep: scanned ${x.scanned} live claude(s), linked ${x.linked}, renamed ${x.renamed}, ambiguous_cwd ${x.ambiguous_cwd}`)}).catch(x=>{console.error("[daemon] boot sweep failed:",x)})},Kw),setTimeout(()=>{So().then(x=>{console.log(`[daemon] ingestion sweep: scanned=${x.scanned} reindexed=${x.reindexed} up-to-date=${x.upToDate} skipped=${x.skipped} errors=${x.errors} (${x.durationMs}ms)`)}).catch(x=>{console.error("[daemon] ingestion sweep failed:",x)})},Vw)}Qw().catch(e=>{console.error("[daemon] fatal:",e),Oi(),process.exit(1)});
2013
+ LIMIT 20`).all(p).map(E=>E.git_branch);return i.json({...g,branches:_})});function $(i){return i.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function te(i){if(!e)return i;let l=`<meta name="recall-token" content="${$(e)}" />`,p=i.indexOf("</head>");return p!==-1?i.slice(0,p)+l+i.slice(p):l+i}function H(i){let l=dm();return i.html(Bl({projects:l.projects,sessions:l.sessions,messages:l.messages,port:Number(i.req.raw.headers.get("host")?.split(":")[1]??0),version:um}))}function se(){try{return Oi(mm,"utf8")}catch{return null}}return Yw?(t.use("/assets/*",cm({root:Ci})),t.get("/favicon.svg",cm({root:Ci})),t.get("/",i=>{i.header("cache-control","no-cache, no-store, must-revalidate"),i.header("pragma","no-cache"),i.header("expires","0");let l=se();return l===null?H(i):i.html(te(l))}),t.get("*",i=>{if(i.req.path.startsWith("/api/"))return i.notFound();i.header("cache-control","no-cache, no-store, must-revalidate"),i.header("pragma","no-cache"),i.header("expires","0");let l=se();return l===null?H(i):i.html(te(l))})):t.get("/",i=>H(i)),t}function n0(){if(Gs(),!!st().heuristicEnabled){try{let{updated:e}=tl();e>0&&console.log(`[auto-title] backfilled heuristic title on ${e} sessions`)}catch(e){console.error("[auto-title] backfill failed:",e)}try{let{scanned:e,updated:t}=nl();t>0&&console.log(`[auto-title] refreshed templated heuristic title on ${t}/${e} sessions`)}catch(e){console.error("[auto-title] templated-title refresh failed:",e)}try{let{scanned:e,updated:t}=sl();t>0&&console.log(`[auto-title] refreshed recursive_meta title on ${t}/${e} sessions`)}catch(e){console.error("[auto-title] recursive_meta refresh failed:",e)}try{let{scanned:e,updated:t}=rl();t>0&&console.log(`[auto-title] canonicalized brand on ${t}/${e} session titles`)}catch(e){console.error("[auto-title] brand canonicalization failed:",e)}}}async function fm(e,t){let n=t0(t);return new Promise((s,r)=>{try{let o=Iw({fetch:n.fetch,port:e,hostname:"127.0.0.1"},()=>{s(o),setImmediate(()=>{try{n0()}catch(a){console.error("[daemon] startup maintenance crashed:",a)}})})}catch(o){r(o)}})}import{createServer as Em}from"node:net";function hm(e){return new Promise(t=>{let n=Em();n.once("error",()=>t(!1)),n.once("listening",()=>{n.close(()=>t(!0))}),n.listen(e,"127.0.0.1")})}async function bm(){let e=new Set([3e3,3001,4200,5e3,5173,8e3,8080,8888,9e3]),t=51370;if(!e.has(t)&&await hm(t))return t;for(let n=0;n<50;n++){let s=49152+Math.floor(Math.random()*16383);if(!e.has(s)&&await hm(s))return s}return new Promise((n,s)=>{let r=Em();r.once("error",s),r.listen(0,"127.0.0.1",()=>{let o=r.address();if(o&&typeof o=="object"){let a=o.port;r.close(()=>n(a))}else r.close(),s(new Error("could not determine a free port"))})})}ee();import{existsSync as i0,readFileSync as yI,writeFileSync as Tm,unlinkSync as a0}from"node:fs";import{join as Mi}from"node:path";ee();import{randomBytes as s0}from"node:crypto";import{writeFileSync as r0,readFileSync as fI,existsSync as hI}from"node:fs";import{join as o0}from"node:path";var ji=o0(W,"daemon.token");function Sm(){z();let e=s0(32).toString("hex");return r0(ji,e,{encoding:"utf8",mode:384}),e}var ym=Mi(W,"daemon.pid"),wm=Mi(W,"daemon.port"),AI=Mi(W,"daemon.log");function Rm(e){z(),Tm(ym,JSON.stringify(e),{encoding:"utf8",mode:384}),Tm(wm,String(e.port),{encoding:"utf8",mode:384})}function Di(){for(let e of[ym,wm,ji])if(i0(e))try{a0(e)}catch{}}Fr();B();ee();ct();var l0=Math.max(1,c0().length),km=String(Math.max(2,Math.floor(l0/2)));process.env.OMP_NUM_THREADS||(process.env.OMP_NUM_THREADS=km);process.env.ORT_NUM_THREADS||(process.env.ORT_NUM_THREADS=km);var u0=360*60*1e3,d0=60*1e3,p0=1440*60*1e3,m0=300*1e3,g0=300*1e3,_0=10*1e3,f0=1440*60*1e3,h0=30*1e3,E0=500,b0=1500,S0=6e4;async function T0(){let e=await bm(),t=Sm();(!t||t.length<32)&&(console.error("[daemon] FATAL: daemon token init returned empty or undersized \u2014 refusing to start"),process.exit(1));let n=await fm(e,t);Rm({pid:process.pid,port:e,startedAt:new Date().toISOString()}),xr(ce().enabled);try{Qt();let A=dc();A>0&&console.log(`[daemon] archive: migrated ${A} hot row(s) into archive.sqlite`)}catch(A){let $=A instanceof Error?A.message:String(A);console.error(`[daemon] archive migration failed: ${$}`)}let s=Ul({db:f(),walPath:`${Bt}-wal`}),r=Ml(),o=setInterval(()=>{Dl()},S0),a=()=>{try{Ss()}catch(A){console.error("[daemon] suggestion scan failed:",A)}},c=setTimeout(a,d0),u=setInterval(a,u0),d=()=>{try{let A=M.reapStaleLinks();(A.pruned_pids||A.pruned_sessions)&&console.log(`[daemon] reaper: pruned ${A.pruned_pids} pid${A.pruned_pids===1?"":"s"}, ${A.pruned_sessions} session link${A.pruned_sessions===1?"":"s"}`)}catch(A){console.error("[daemon] stale-link reaper failed:",A)}},m=setTimeout(d,m0),h=setInterval(d,p0),b=()=>{try{let A=M.gcDeadPids();(A.pruned_pids||A.pruned_sessions)&&console.log(`[daemon] dead-pid gc: pruned ${A.pruned_pids} pid${A.pruned_pids===1?"":"s"}, ${A.pruned_sessions} session link${A.pruned_sessions===1?"":"s"}`)}catch(A){console.error("[daemon] dead-pid gc failed:",A)}},S=setTimeout(b,_0),T=setInterval(b,g0),R=()=>{Yi().then(A=>{A.ran&&A.revoked&&console.log(`[daemon] license check: REVOKED${A.reason?` (${A.reason})`:""}`)}).catch(A=>{console.error("[daemon] license check failed:",A)})},O=setTimeout(R,h0),L=setInterval(R,f0),x=Rc();(async()=>{try{if(!Ge())return;let A=f().prepare("SELECT COUNT(*) AS n FROM chunk_queue").get();if(A.n===0)return;if(!ce().autoResumeWorker){console.log(`[daemon] vector-worker dormant: ${A.n} chunk(s) pending in queue. Run \`recall vectorize\` or click Start in the web UI to drain. To restore auto-resume, set semantic.autoResumeWorker=true in ~/.recall/config.json.`);return}let te=await Ke();if(te.tier!=="pro"){console.log(`[daemon] vector-worker auto-resume skipped: ${A.n} chunk(s) pending but license tier is ${te.tier}`);return}_e().loaded||await Ue(),Ie().running||(kn(),console.log(`[daemon] vector-worker auto-resumed: ${A.n} chunk(s) pending`))}catch(A){let $=A instanceof Error?A.message:String(A);console.error(`[daemon] vector-worker auto-resume failed: ${$}`)}})();let F=A=>{console.log(`[daemon] received ${A}, shutting down`),clearTimeout(c),clearInterval(u),clearTimeout(m),clearInterval(h),clearTimeout(S),clearInterval(T),clearTimeout(O),clearInterval(L),clearInterval(o),x.stop(),s.stop(),r.close(),n.close(),Di(),process.exit(0)};process.on("SIGTERM",()=>F("SIGTERM")),process.on("SIGINT",()=>F("SIGINT")),process.on("SIGHUP",()=>F("SIGHUP")),console.log(`[daemon] ready on http://127.0.0.1:${e} pid=${process.pid}`),setTimeout(()=>{rs().then(A=>{console.log(`[daemon] boot sweep: scanned ${A.scanned} live claude(s), linked ${A.linked}, renamed ${A.renamed}, ambiguous_cwd ${A.ambiguous_cwd}`)}).catch(A=>{console.error("[daemon] boot sweep failed:",A)})},E0),setTimeout(()=>{To().then(A=>{console.log(`[daemon] ingestion sweep: scanned=${A.scanned} reindexed=${A.reindexed} up-to-date=${A.upToDate} skipped=${A.skipped} errors=${A.errors} (${A.durationMs}ms)`)}).catch(A=>{console.error("[daemon] ingestion sweep failed:",A)})},b0)}T0().catch(e=>{console.error("[daemon] fatal:",e),Di(),process.exit(1)});