@clauderecallhq/cli 0.64.0 → 0.64.2

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 Fu=Object.defineProperty;var we=(e,t)=>()=>(e&&(t=e(e=0)),t);var Oo=(e,t)=>{for(var s in t)Fu(e,s,{get:t[s],enumerable:!0})};import{homedir as Lo}from"node:os";import{join as bn,basename as RT}from"node:path";import{existsSync as Pu,mkdirSync as Uu,chmodSync as $u,readdirSync as AT,statSync as NT}from"node:fs";function J(){Pu($)||Uu($,{recursive:!0,mode:448}),process.platform!=="win32"&&$u($,448)}var Co,$,Sn,Z=we(()=>{"use strict";Co=bn(Lo(),".claude","projects"),$=process.env.RECALL_HOME?process.env.RECALL_HOME:bn(Lo(),".recall"),Sn=bn($,"db.sqlite")});function Jo(e){let t=e.prepare("PRAGMA table_info(sessions)").all(),s=new Set(t.map(S=>S.name)),n=[["total_input_tokens","INTEGER"],["total_output_tokens","INTEGER"],["total_cache_create_tokens","INTEGER"],["total_cache_read_tokens","INTEGER"],["primary_model","TEXT"],["auto_title","TEXT"],["auto_title_source","TEXT"],["auto_title_generated_at","INTEGER"],["auto_title_history","TEXT"],["verification_status","TEXT"],["verification_computed_at","INTEGER"],["title_quality","TEXT"],["title_quality_computed_at","INTEGER"]];for(let[S,y]of n)s.has(S)||e.exec(`ALTER TABLE sessions ADD COLUMN ${S} ${y}`);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,y]of a)o.has(S)||e.exec(`ALTER TABLE collection_sessions ADD COLUMN ${S} ${y}`);let c=e.prepare("PRAGMA table_info(session_notes)").all(),d=new Set(c.map(S=>S.name)),u=[["auto_synopsis","TEXT"],["auto_synopsis_generated_at","INTEGER"],["auto_synopsis_history","TEXT"]];for(let[S,y]of u)d.has(S)||e.exec(`ALTER TABLE session_notes ADD COLUMN ${S} ${y}`);let g=e.prepare("PRAGMA table_info(threads)").all();new Set(g.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(`
3
+ var Fu=Object.defineProperty;var we=(e,t)=>()=>(e&&(t=e(e=0)),t);var Co=(e,t)=>{for(var s in t)Fu(e,s,{get:t[s],enumerable:!0})};import{homedir as Io}from"node:os";import{join as Tn,basename as RT}from"node:path";import{existsSync as Pu,mkdirSync as Uu,chmodSync as $u,readdirSync as AT,statSync as NT}from"node:fs";function J(){Pu($)||Uu($,{recursive:!0,mode:448}),process.platform!=="win32"&&$u($,448)}var vo,$,yn,Z=we(()=>{"use strict";vo=Tn(Io(),".claude","projects"),$=process.env.RECALL_HOME?process.env.RECALL_HOME:Tn(Io(),".recall"),yn=Tn($,"db.sqlite")});function Go(e){let t=e.prepare("PRAGMA table_info(sessions)").all(),s=new Set(t.map(S=>S.name)),n=[["total_input_tokens","INTEGER"],["total_output_tokens","INTEGER"],["total_cache_create_tokens","INTEGER"],["total_cache_read_tokens","INTEGER"],["primary_model","TEXT"],["auto_title","TEXT"],["auto_title_source","TEXT"],["auto_title_generated_at","INTEGER"],["auto_title_history","TEXT"],["verification_status","TEXT"],["verification_computed_at","INTEGER"],["title_quality","TEXT"],["title_quality_computed_at","INTEGER"]];for(let[S,y]of n)s.has(S)||e.exec(`ALTER TABLE sessions ADD COLUMN ${S} ${y}`);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,y]of a)o.has(S)||e.exec(`ALTER TABLE collection_sessions ADD COLUMN ${S} ${y}`);let c=e.prepare("PRAGMA table_info(session_notes)").all(),d=new Set(c.map(S=>S.name)),u=[["auto_synopsis","TEXT"],["auto_synopsis_generated_at","INTEGER"],["auto_synopsis_history","TEXT"]];for(let[S,y]of u)d.has(S)||e.exec(`ALTER TABLE session_notes ADD COLUMN ${S} ${y}`);let g=e.prepare("PRAGMA table_info(threads)").all();new Set(g.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 Fu=Object.defineProperty;var we=(e,t)=>()=>(e&&(t=e(e=0)),t);var Oo=(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 qo,Xo=we(()=>{"use strict";qo=`
15
+ `)}var Xo,Yo=we(()=>{"use strict";Xo=`
16
16
  PRAGMA journal_mode = WAL;
17
17
  PRAGMA synchronous = NORMAL;
18
18
  PRAGMA foreign_keys = ON;
@@ -618,8 +618,8 @@ CREATE INDEX IF NOT EXISTS idx_synth_results_target
618
618
  ON bug_synthesis_results(scope, target_id, created_at DESC);
619
619
  CREATE INDEX IF NOT EXISTS idx_synth_results_created
620
620
  ON bug_synthesis_results(created_at DESC);
621
- `});import dp from"better-sqlite3";import*as Go from"sqlite-vec";function f(){if(ie)return ie;J(),ie=new dp(Sn),Go.load(ie),ie.pragma("cache_size = -64000"),ie.pragma("mmap_size = 268435456"),ie.pragma("temp_store = MEMORY"),ie.pragma("busy_timeout = 5000"),ie.pragma("journal_size_limit = 67108864"),ie.pragma("wal_autocheckpoint = 1000"),ie.exec(qo),Jo(ie);try{ie.exec("PRAGMA optimize")}catch{}return ie}var ie,H=we(()=>{"use strict";Z();Xo();ie=null});import{writeFileSync as wp}from"node:fs";import{join as Rp}from"node:path";function De(e){return e.trim().toLowerCase().replace(/^#+/,"").replace(/[\s/\\]+/g,"-").replace(/[^a-z0-9\-._]/g,"").slice(0,40)}function Je(e,t){let s=De(t);if(!s)throw new Error("tag must contain at least one alphanumeric character");let n=f(),r=new Date().toISOString();return n.prepare("SELECT 1 FROM session_tags WHERE session_id = ? AND tag = ?").get(e,s)?{tag:s,added:!1}:(n.transaction(()=>{n.prepare("INSERT INTO session_tags (session_id, tag, created_at) VALUES (?, ?, ?)").run(e,s,r),n.prepare("INSERT INTO tag_events (session_id, tag, action, at) VALUES (?, ?, 'add', ?)").run(e,s,r)})(),Qo(),{tag:s,added:!0})}function Zo(e,t){let s=De(t);if(!s)return{tag:"",removed:!1};let n=f(),r=new Date().toISOString();return n.prepare("SELECT 1 FROM session_tags WHERE session_id = ? AND tag = ?").get(e,s)?(n.transaction(()=>{n.prepare("DELETE FROM session_tags WHERE session_id = ? AND tag = ?").run(e,s),n.prepare("INSERT INTO tag_events (session_id, tag, action, at) VALUES (?, ?, 'remove', ?)").run(e,s,r)})(),Qo(),{tag:s,removed:!0}):{tag:s,removed:!1}}function wt(e){return f().prepare("SELECT tag FROM session_tags WHERE session_id = ? ORDER BY tag").all(e).map(t=>t.tag)}function Xe(){return f().prepare(`SELECT tag, COUNT(*) AS count FROM session_tags
622
- GROUP BY tag ORDER BY count DESC, tag ASC`).all()}function Qo(){try{J();let e=f(),t=e.prepare("SELECT session_id, tag, created_at FROM session_tags ORDER BY session_id, tag").all(),s=e.prepare("SELECT id, session_id, tag, action, at FROM tag_events ORDER BY at ASC, id ASC").all(),n={schema:"claude-recall.tags.v1",backed_up_at:new Date().toISOString(),current:t,events:s};wp(kp,JSON.stringify(n,null,2))}catch(e){console.error("[tags] backup failed:",e)}}var kp,Ge=we(()=>{"use strict";H();Z();kp=Rp($,"tags.json")});function Ap(e,t){let s=e.filter(o=>o.content_text&&o.content_text.trim().length>0);if(s.length<=t)return s;let n=new Set;n.add(0),n.add(s.length-1);let r=(s.length-2)/Math.max(1,t-2);for(let o=1;o<t-1;o++)n.add(Math.floor(o*r));return Array.from(n).sort((o,a)=>o-a).slice(0,t).map(o=>s[o])}function Ye(e){let t=f(),s={limit:e.limit??500},n=e.sessionIds&&e.sessionIds.length>0,r=n?"1=1":"s.message_count > 2";if(n){let a=e.sessionIds.map((c,d)=>`@sid_${d}`).join(", ");r+=` AND s.id IN (${a})`,e.sessionIds.forEach((c,d)=>{s[`sid_${d}`]=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",s.project=e.project),e.collectionId&&(r+=" AND s.id IN (SELECT session_id FROM collection_sessions WHERE collection_id = @col)",s.col=e.collectionId),t.prepare(`SELECT s.id, p.name AS project, s.git_branch,
621
+ `});import dp from"better-sqlite3";import*as Ko from"sqlite-vec";function f(){if(ie)return ie;J(),ie=new dp(yn),Ko.load(ie),ie.pragma("cache_size = -64000"),ie.pragma("mmap_size = 268435456"),ie.pragma("temp_store = MEMORY"),ie.pragma("busy_timeout = 5000"),ie.pragma("journal_size_limit = 67108864"),ie.pragma("wal_autocheckpoint = 1000"),ie.exec(Xo),Go(ie);try{ie.exec("PRAGMA optimize")}catch{}return ie}var ie,H=we(()=>{"use strict";Z();Yo();ie=null});import{writeFileSync as wp}from"node:fs";import{join as Rp}from"node:path";function De(e){return e.trim().toLowerCase().replace(/^#+/,"").replace(/[\s/\\]+/g,"-").replace(/[^a-z0-9\-._]/g,"").slice(0,40)}function Je(e,t){let s=De(t);if(!s)throw new Error("tag must contain at least one alphanumeric character");let n=f(),r=new Date().toISOString();return n.prepare("SELECT 1 FROM session_tags WHERE session_id = ? AND tag = ?").get(e,s)?{tag:s,added:!1}:(n.transaction(()=>{n.prepare("INSERT INTO session_tags (session_id, tag, created_at) VALUES (?, ?, ?)").run(e,s,r),n.prepare("INSERT INTO tag_events (session_id, tag, action, at) VALUES (?, ?, 'add', ?)").run(e,s,r)})(),ti(),{tag:s,added:!0})}function ei(e,t){let s=De(t);if(!s)return{tag:"",removed:!1};let n=f(),r=new Date().toISOString();return n.prepare("SELECT 1 FROM session_tags WHERE session_id = ? AND tag = ?").get(e,s)?(n.transaction(()=>{n.prepare("DELETE FROM session_tags WHERE session_id = ? AND tag = ?").run(e,s),n.prepare("INSERT INTO tag_events (session_id, tag, action, at) VALUES (?, ?, 'remove', ?)").run(e,s,r)})(),ti(),{tag:s,removed:!0}):{tag:s,removed:!1}}function wt(e){return f().prepare("SELECT tag FROM session_tags WHERE session_id = ? ORDER BY tag").all(e).map(t=>t.tag)}function Xe(){return f().prepare(`SELECT tag, COUNT(*) AS count FROM session_tags
622
+ GROUP BY tag ORDER BY count DESC, tag ASC`).all()}function ti(){try{J();let e=f(),t=e.prepare("SELECT session_id, tag, created_at FROM session_tags ORDER BY session_id, tag").all(),s=e.prepare("SELECT id, session_id, tag, action, at FROM tag_events ORDER BY at ASC, id ASC").all(),n={schema:"claude-recall.tags.v1",backed_up_at:new Date().toISOString(),current:t,events:s};wp(kp,JSON.stringify(n,null,2))}catch(e){console.error("[tags] backup failed:",e)}}var kp,Ge=we(()=>{"use strict";H();Z();kp=Rp($,"tags.json")});function Ap(e,t){let s=e.filter(o=>o.content_text&&o.content_text.trim().length>0);if(s.length<=t)return s;let n=new Set;n.add(0),n.add(s.length-1);let r=(s.length-2)/Math.max(1,t-2);for(let o=1;o<t-1;o++)n.add(Math.floor(o*r));return Array.from(n).sort((o,a)=>o-a).slice(0,t).map(o=>s[o])}function Ye(e){let t=f(),s={limit:e.limit??500},n=e.sessionIds&&e.sessionIds.length>0,r=n?"1=1":"s.message_count > 2";if(n){let a=e.sessionIds.map((c,d)=>`@sid_${d}`).join(", ");r+=` AND s.id IN (${a})`,e.sessionIds.forEach((c,d)=>{s[`sid_${d}`]=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",s.project=e.project),e.collectionId&&(r+=" AND s.id IN (SELECT session_id FROM collection_sessions WHERE collection_id = @col)",s.col=e.collectionId),t.prepare(`SELECT s.id, p.name AS project, s.git_branch,
623
623
  NULLIF(sa.alias, '') AS alias,
624
624
  COALESCE(s.first_user_message, '') AS first_user_message
625
625
  FROM sessions s
@@ -631,19 +631,19 @@ CREATE INDEX IF NOT EXISTS idx_synth_results_created
631
631
  FROM messages WHERE session_id = ?
632
632
  ORDER BY COALESCE(timestamp, ''), rowid`).all(a.id),u=Ap(c,5).map(g=>`${g.role}: ${g.content_text.slice(0,400)}`).join(`
633
633
  ---
634
- `);return{id:a.id,project:a.project,git_branch:a.git_branch,alias:a.alias,first_user_message:a.first_user_message,message_sample:u,current_tags:wt(a.id)}})}var rs=we(()=>{"use strict";H();Ge()});import{z as ue}from"zod";function kn(e){let t=e.minTags??2,s=e.maxTags??4,n=e.untaggedOnly??!e.sessionId,r=["Auto-tag my Claude Recall sessions using the MCP tools available to you.","","1. Call `list_tags` first to see which tags I already use (prefer those for consistency over inventing new ones).","2. Call `list_sessions_to_tag` with these filters:"],o=[];return e.sessionId?(o.push("limit: 1"),r.push(` ${o.join(", ")}`),r.push(` Then match the session id ${e.sessionId} from the returned list.`)):(n&&o.push("untaggedOnly: true"),e.project&&o.push(`project: "${e.project}"`),e.collectionId&&o.push(`collectionId: "${e.collectionId}"`),o.push(`limit: ${e.limit??100}`),r.push(` ${o.join(", ")}`)),r.push(""),r.push(`3. For each session returned, look at the alias, first user message, git branch, and sampled messages. Pick ${t}-${s} concise, lowercase, hyphen-separated tags describing:`),r.push(" - domain/subsystem (auth, db, frontend, billing, etc.)"),r.push(" - kind of work (bugfix, feature, refactor, research)"),r.push(" - prominent tools or libraries if relevant"),r.push(""),r.push("4. Call `apply_tags` once per session to write the tags."),r.push(""),r.push("Work through EVERY session returned \u2014 do not stop partway. When done, reply with a short summary of how many sessions were tagged. Do not ask clarifying questions; just do the work."),r.join(`
634
+ `);return{id:a.id,project:a.project,git_branch:a.git_branch,alias:a.alias,first_user_message:a.first_user_message,message_sample:u,current_tags:wt(a.id)}})}var rs=we(()=>{"use strict";H();Ge()});import{z as ue}from"zod";function Nn(e){let t=e.minTags??2,s=e.maxTags??4,n=e.untaggedOnly??!e.sessionId,r=["Auto-tag my Claude Recall sessions using the MCP tools available to you.","","1. Call `list_tags` first to see which tags I already use (prefer those for consistency over inventing new ones).","2. Call `list_sessions_to_tag` with these filters:"],o=[];return e.sessionId?(o.push("limit: 1"),r.push(` ${o.join(", ")}`),r.push(` Then match the session id ${e.sessionId} from the returned list.`)):(n&&o.push("untaggedOnly: true"),e.project&&o.push(`project: "${e.project}"`),e.collectionId&&o.push(`collectionId: "${e.collectionId}"`),o.push(`limit: ${e.limit??100}`),r.push(` ${o.join(", ")}`)),r.push(""),r.push(`3. For each session returned, look at the alias, first user message, git branch, and sampled messages. Pick ${t}-${s} concise, lowercase, hyphen-separated tags describing:`),r.push(" - domain/subsystem (auth, db, frontend, billing, etc.)"),r.push(" - kind of work (bugfix, feature, refactor, research)"),r.push(" - prominent tools or libraries if relevant"),r.push(""),r.push("4. Call `apply_tags` once per session to write the tags."),r.push(""),r.push("Work through EVERY session returned \u2014 do not stop partway. When done, reply with a short summary of how many sessions were tagged. Do not ask clarifying questions; just do the work."),r.join(`
635
635
  `)}function Op(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(`
636
636
  `)}function Cp(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(`
637
637
  `)}function vp(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(`
638
- `)}function ei(e){return An.find(t=>t.name===e)}var Np,xp,Lp,Ip,jp,Mp,Dp,Fp,An,Nn=we(()=>{"use strict";Np={project:ue.string().optional().describe("Exact project name match (optional)."),collectionId:ue.string().optional().describe("Restrict to sessions in this collection (optional)."),sessionId:ue.string().optional().describe("Full session UUID to tag just one session (optional)."),untaggedOnly:ue.boolean().optional().describe("Skip sessions that already have any tag (default: true)."),limit:ue.number().int().min(1).max(500).optional().describe("Max sessions to process (default: 100)."),minTags:ue.number().int().min(1).max(10).optional().describe("Minimum tags per session (default: 2)."),maxTags:ue.number().int().min(1).max(10).optional().describe("Maximum tags per session (default: 4).")};xp={sessionId:ue.string().describe("Session UUID (or 8+-char prefix) to summarize."),mode:ue.enum(["brief","detailed"]).optional().describe("brief = 3-5 bullets; detailed = paragraph + bullets. Default: brief.")};Lp={sessionId:ue.string().describe("Session UUID (or 8+-char prefix) to extract decisions from.")};Ip={sessionId:ue.string().describe("Session UUID (or 8+-char prefix) to find similar sessions to."),limit:ue.number().int().min(1).max(20).optional().describe("How many similar sessions to surface (default: 5).")};jp={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:Np,build:kn,allowedTools:["mcp__recall__list_tags","mcp__recall__list_sessions_to_tag","mcp__recall__apply_tags"]},Mp={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:xp,build:Op,allowedTools:["mcp__recall__get_session","mcp__recall__context_for_session"]},Dp={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:Lp,build:Cp,allowedTools:["mcp__recall__get_session","mcp__recall__context_for_session"]},Fp={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:Ip,build:vp,allowedTools:["mcp__recall__get_session","mcp__recall__search","mcp__recall__list_sessions","mcp__recall__list_tags"]},An=[jp,Mp,Dp,Fp]});function os(e,t){let s=Rt.get(e);if(!(!s||s.size===0))for(let n of s)try{n(t)}catch{}}function ti(e,t){let s=Rt.get(e);return s||(s=new Set,Rt.set(e,s)),s.add(t),()=>{let n=Rt.get(e);n&&(n.delete(t),n.size===0&&Rt.delete(e))}}var Rt,xn=we(()=>{"use strict";Rt=new Map});var Pe={};Oo(Pe,{buildScanPrompt:()=>si,isClaudeCliAvailable:()=>oe,runClaudeCliScan:()=>On,spawnClaudePrompt:()=>Fe});import{execFileSync as Pp,execSync as Up,spawn as $p}from"node:child_process";function Hp(){if(kt)return kt;try{kt=Up("which claude",{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim()}catch{kt="claude"}return kt}function oe(){try{return Pp("command",["-v","claude"],{stdio:"ignore"}),!0}catch{return!1}}function si(e){return kn({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 Wp(e,t){let s=t.get(e);return s||e.slice(0,8)}function qp(e){try{return Ye(e).map(s=>({id:s.id,label:s.alias&&s.alias.trim().length>0?s.alias:s.first_user_message&&s.first_user_message.trim().length>0?s.first_user_message.slice(0,60):s.id.slice(0,8)}))}catch{return[]}}function Jp(e){let{scanId:t,total:s,labelTable:n}=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 d=c;if(!(d.type!=="assistant"||!d.message?.content))for(let u of d.message.content){if(u?.type!=="tool_use"||u.name!=="mcp__recall__apply_tags")continue;let g=u.input,h=typeof g?.sessionId=="string"?g.sessionId:null;!h||r.has(h)||(r.add(h),os(t,{type:"progress",current:r.size,total:s,sessionId:h,sessionLabel:Wp(h,n)}))}}}function Xp(e){let t="";return s=>{t+=s.toString("utf8");let n=t.indexOf(`
638
+ `)}function si(e){return xn.find(t=>t.name===e)}var Np,xp,Lp,Ip,jp,Mp,Dp,Fp,xn,On=we(()=>{"use strict";Np={project:ue.string().optional().describe("Exact project name match (optional)."),collectionId:ue.string().optional().describe("Restrict to sessions in this collection (optional)."),sessionId:ue.string().optional().describe("Full session UUID to tag just one session (optional)."),untaggedOnly:ue.boolean().optional().describe("Skip sessions that already have any tag (default: true)."),limit:ue.number().int().min(1).max(500).optional().describe("Max sessions to process (default: 100)."),minTags:ue.number().int().min(1).max(10).optional().describe("Minimum tags per session (default: 2)."),maxTags:ue.number().int().min(1).max(10).optional().describe("Maximum tags per session (default: 4).")};xp={sessionId:ue.string().describe("Session UUID (or 8+-char prefix) to summarize."),mode:ue.enum(["brief","detailed"]).optional().describe("brief = 3-5 bullets; detailed = paragraph + bullets. Default: brief.")};Lp={sessionId:ue.string().describe("Session UUID (or 8+-char prefix) to extract decisions from.")};Ip={sessionId:ue.string().describe("Session UUID (or 8+-char prefix) to find similar sessions to."),limit:ue.number().int().min(1).max(20).optional().describe("How many similar sessions to surface (default: 5).")};jp={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:Np,build:Nn,allowedTools:["mcp__recall__list_tags","mcp__recall__list_sessions_to_tag","mcp__recall__apply_tags"]},Mp={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:xp,build:Op,allowedTools:["mcp__recall__get_session","mcp__recall__context_for_session"]},Dp={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:Lp,build:Cp,allowedTools:["mcp__recall__get_session","mcp__recall__context_for_session"]},Fp={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:Ip,build:vp,allowedTools:["mcp__recall__get_session","mcp__recall__search","mcp__recall__list_sessions","mcp__recall__list_tags"]},xn=[jp,Mp,Dp,Fp]});function os(e,t){let s=Rt.get(e);if(!(!s||s.size===0))for(let n of s)try{n(t)}catch{}}function ni(e,t){let s=Rt.get(e);return s||(s=new Set,Rt.set(e,s)),s.add(t),()=>{let n=Rt.get(e);n&&(n.delete(t),n.size===0&&Rt.delete(e))}}var Rt,Ln=we(()=>{"use strict";Rt=new Map});var Pe={};Co(Pe,{buildScanPrompt:()=>ri,isClaudeCliAvailable:()=>oe,runClaudeCliScan:()=>Cn,spawnClaudePrompt:()=>Fe});import{execFileSync as Pp,execSync as Up,spawn as $p}from"node:child_process";function Hp(){if(kt)return kt;try{kt=Up("which claude",{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim()}catch{kt="claude"}return kt}function oe(){try{return Pp("command",["-v","claude"],{stdio:"ignore"}),!0}catch{return!1}}function ri(e){return Nn({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 Wp(e,t){let s=t.get(e);return s||e.slice(0,8)}function qp(e){try{return Ye(e).map(s=>({id:s.id,label:s.alias&&s.alias.trim().length>0?s.alias:s.first_user_message&&s.first_user_message.trim().length>0?s.first_user_message.slice(0,60):s.id.slice(0,8)}))}catch{return[]}}function Jp(e){let{scanId:t,total:s,labelTable:n}=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 d=c;if(!(d.type!=="assistant"||!d.message?.content))for(let u of d.message.content){if(u?.type!=="tool_use"||u.name!=="mcp__recall__apply_tags")continue;let g=u.input,h=typeof g?.sessionId=="string"?g.sessionId:null;!h||r.has(h)||(r.add(h),os(t,{type:"progress",current:r.size,total:s,sessionId:h,sessionLabel:Wp(h,n)}))}}}function Xp(e){let t="";return s=>{t+=s.toString("utf8");let n=t.indexOf(`
639
639
  `);for(;n!==-1;){let r=t.slice(0,n);t=t.slice(n+1),r.length>0&&e(r),n=t.indexOf(`
640
- `)}}}async function On(e,t={},s){let n=!!t.scanId,r=n?qp(e):[],o=new Map(r.map(d=>[d.id,d.label])),a=r.length,c;return n&&t.scanId&&(c=Jp({scanId:t.scanId,total:a,labelTable:o})),ni({prompt:si(e),allowedTools:Bp.split(","),opts:t,onProgress:s,onStdoutLine:c,outputFormat:n?"stream-json":"json"})}async function Fe(e,t,s={},n){return ni({prompt:e,allowedTools:t,opts:s,onProgress:n,outputFormat:"json"})}function ni(e){let{prompt:t,allowedTools:s,opts:n,onProgress:r,onStdoutLine:o,outputFormat:a}=e,c=["-p",t,"--output-format",a,"--allowedTools",s.join(","),"--permission-mode","bypassPermissions"];return a==="stream-json"&&c.push("--verbose"),n.model&&c.push("--model",n.model),new Promise(d=>{let u=$p(Hp(),c,{stdio:["ignore","pipe","pipe"]}),g=[],h=[],b=o?Xp(o):void 0;u.stdout.on("data",y=>{g.push(y),b&&b(y)}),u.stderr.on("data",y=>{if(h.push(y),r){let k=y.toString("utf8").trim();k&&r(k)}});let S=setTimeout(()=>{u.kill("SIGKILL")},1800*1e3);u.on("close",y=>{clearTimeout(S),d({success:y===0,stdout:Buffer.concat(g).toString("utf8"),stderr:Buffer.concat(h).toString("utf8"),exitCode:y})}),u.on("error",y=>{clearTimeout(S),d({success:!1,stdout:"",stderr:String(y),exitCode:null})})})}var Bp,kt,ge=we(()=>{"use strict";rs();Nn();xn();Bp=["mcp__recall__list_tags","mcp__recall__list_sessions_to_tag","mcp__recall__apply_tags"].join(",")});var $c={};Oo($c,{EmbedderUnavailableError:()=>Ut,embed:()=>$t,embedQuery:()=>hr,getEmbedderStatus:()=>ke,loadEmbedder:()=>Ws,unloadEmbedder:()=>Yf});import{join as Pc}from"node:path";function Gf(){return Pc($,"models","bge-base-en-v1.5")}async function Ws(){if(Hs&&Pt)return;let e;try{e=await import("@huggingface/transformers")}catch(n){throw new Ut(n)}let{pipeline:t,env:s}=e;s.localModelPath=Pc($,"models"),s.allowRemoteModels=!1;try{Pt=await t("feature-extraction",Uc,{local_files_only:!0,cache_dir:Gf()}),Hs=!0}catch(n){throw n instanceof Error&&/Cannot find module|onnxruntime_binding/.test(n.message)?new Ut(n):n}}function ke(){return{loaded:Hs,modelId:Uc,dim:Jf}}async function $t(e){if(!Pt)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");let t=[];for(let s=0;s<e.length;s+=Fc){let n=e.slice(s,s+Fc),o=(await Pt(n,{pooling:"cls",normalize:!0})).tolist();for(let a=0;a<n.length;a++){let c=o[a],d=Array.isArray(c[0])?c[0]:c;t.push(new Float32Array(d))}}return t}async function hr(e){let t=Xf+e,[s]=await $t([t]);return s}function Yf(){Pt=null,Hs=!1}var Uc,Jf,Fc,Xf,Pt,Hs,Ut,ot=we(()=>{"use strict";Z();Uc="BAAI/bge-base-en-v1.5",Jf=768,Fc=16,Xf="Represent this sentence for searching relevant passages: ",Pt=null,Hs=!1;Ut=class extends Error{cause;constructor(t){let s=t instanceof Error?t.message:String(t);super(["Semantic search is unavailable on this platform.","",`Reason: ${s}`,"",`Platform: ${process.platform}/${process.arch}, Node ${process.version}`,"","Claude Recall supports macOS (arm64/x64), Linux (x64/arm64), and Windows (x64).","Core CLI features (search, list, context, daemon) work everywhere.","Only `recall semantic *` requires the on-device embedder.","","See: https://clauderecall.com/docs (Supported platforms) \u2014 or file an issue at","https://gitlab.com/clauderecallhq/clauderecallhq/-/issues with the platform line above."].join(`
641
- `)),this.name="EmbedderUnavailableError",this.cause=t}}});import{Hono as Bb}from"hono";import{serve as Hb}from"@hono/node-server";Z();import{existsSync as Bu,readFileSync as Hu,writeFileSync as LT,unlinkSync as CT}from"node:fs";import{join as Wu}from"node:path";var Io=Wu($,"license.json");function St(){if(!Bu(Io))return null;try{let e=Hu(Io,"utf8"),t=JSON.parse(e);return typeof t.license_jwt!="string"||t.license_jwt.length===0?null:t}catch{return null}}import{jwtVerify as qu,importSPKI as Ju}from"jose";var vo=`-----BEGIN PUBLIC KEY-----
640
+ `)}}}async function Cn(e,t={},s){let n=!!t.scanId,r=n?qp(e):[],o=new Map(r.map(d=>[d.id,d.label])),a=r.length,c;return n&&t.scanId&&(c=Jp({scanId:t.scanId,total:a,labelTable:o})),oi({prompt:ri(e),allowedTools:Bp.split(","),opts:t,onProgress:s,onStdoutLine:c,outputFormat:n?"stream-json":"json"})}async function Fe(e,t,s={},n){return oi({prompt:e,allowedTools:t,opts:s,onProgress:n,outputFormat:"json"})}function oi(e){let{prompt:t,allowedTools:s,opts:n,onProgress:r,onStdoutLine:o,outputFormat:a}=e,c=["-p",t,"--output-format",a,"--allowedTools",s.join(","),"--permission-mode","bypassPermissions"];return a==="stream-json"&&c.push("--verbose"),n.model&&c.push("--model",n.model),new Promise(d=>{let u=$p(Hp(),c,{stdio:["ignore","pipe","pipe"]}),g=[],h=[],b=o?Xp(o):void 0;u.stdout.on("data",y=>{g.push(y),b&&b(y)}),u.stderr.on("data",y=>{if(h.push(y),r){let k=y.toString("utf8").trim();k&&r(k)}});let S=setTimeout(()=>{u.kill("SIGKILL")},1800*1e3);u.on("close",y=>{clearTimeout(S),d({success:y===0,stdout:Buffer.concat(g).toString("utf8"),stderr:Buffer.concat(h).toString("utf8"),exitCode:y})}),u.on("error",y=>{clearTimeout(S),d({success:!1,stdout:"",stderr:String(y),exitCode:null})})})}var Bp,kt,ge=we(()=>{"use strict";rs();On();Ln();Bp=["mcp__recall__list_tags","mcp__recall__list_sessions_to_tag","mcp__recall__apply_tags"].join(",")});var Hc={};Co(Hc,{EmbedderUnavailableError:()=>Ut,embed:()=>$t,embedQuery:()=>br,getEmbedderStatus:()=>ke,loadEmbedder:()=>Ws,unloadEmbedder:()=>Yf});import{join as $c}from"node:path";function Gf(){return $c($,"models","bge-base-en-v1.5")}async function Ws(){if(Hs&&Pt)return;let e;try{e=await import("@huggingface/transformers")}catch(n){throw new Ut(n)}let{pipeline:t,env:s}=e;s.localModelPath=$c($,"models"),s.allowRemoteModels=!1;try{Pt=await t("feature-extraction",Bc,{local_files_only:!0,cache_dir:Gf()}),Hs=!0}catch(n){throw n instanceof Error&&/Cannot find module|onnxruntime_binding/.test(n.message)?new Ut(n):n}}function ke(){return{loaded:Hs,modelId:Bc,dim:Jf}}async function $t(e){if(!Pt)throw new Error("[embedder] Model not loaded. Call loadEmbedder() before embedding.");let t=[];for(let s=0;s<e.length;s+=Uc){let n=e.slice(s,s+Uc),o=(await Pt(n,{pooling:"cls",normalize:!0})).tolist();for(let a=0;a<n.length;a++){let c=o[a],d=Array.isArray(c[0])?c[0]:c;t.push(new Float32Array(d))}}return t}async function br(e){let t=Xf+e,[s]=await $t([t]);return s}function Yf(){Pt=null,Hs=!1}var Bc,Jf,Uc,Xf,Pt,Hs,Ut,ot=we(()=>{"use strict";Z();Bc="BAAI/bge-base-en-v1.5",Jf=768,Uc=16,Xf="Represent this sentence for searching relevant passages: ",Pt=null,Hs=!1;Ut=class extends Error{cause;constructor(t){let s=t instanceof Error?t.message:String(t);super(["Semantic search is unavailable on this platform.","",`Reason: ${s}`,"",`Platform: ${process.platform}/${process.arch}, Node ${process.version}`,"","Claude Recall supports macOS (arm64/x64), Linux (x64/arm64), and Windows (x64).","Core CLI features (search, list, context, daemon) work everywhere.","Only `recall semantic *` requires the on-device embedder.","","See: https://clauderecall.com/docs (Supported platforms) \u2014 or file an issue at","https://gitlab.com/clauderecallhq/clauderecallhq/-/issues with the platform line above."].join(`
641
+ `)),this.name="EmbedderUnavailableError",this.cause=t}}});import{Hono as Bb}from"hono";import{serve as Hb}from"@hono/node-server";Z();import{existsSync as Bu,readFileSync as Hu,writeFileSync as LT,unlinkSync as CT}from"node:fs";import{join as Wu}from"node:path";var jo=Wu($,"license.json");function St(){if(!Bu(jo))return null;try{let e=Hu(jo,"utf8"),t=JSON.parse(e);return typeof t.license_jwt!="string"||t.license_jwt.length===0?null:t}catch{return null}}import{jwtVerify as qu,importSPKI as Ju}from"jose";var Mo=`-----BEGIN PUBLIC KEY-----
642
642
  MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZysO2FffTLdyxQnTmnt78/ayvqz9
643
643
  kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
644
644
  -----END PUBLIC KEY-----
645
- `,Tn="ES256",jo="clauderecall.com",Mo="clauderecall-cli";var ss=null;async function Xu(){return ss||(ss=await Ju(vo,Tn),ss)}async function Do(e){try{let t=await Xu(),{payload:s}=await qu(e,t,{issuer:jo,audience:Mo,algorithms:[Tn]});return{valid:!0,claims:s}}catch(t){return{valid:!1,reason:t instanceof Error?t.message:"verification failed"}}}import{createHash as Gu}from"node:crypto";import{hostname as Yu,userInfo as Ku,platform as zu,arch as Vu}from"node:os";function Fo(){let e="unknown";try{e=Ku().username}catch{}let t=[Yu(),e,zu(),Vu()];return Gu("sha256").update(t.join("\0")).digest("hex")}Z();import{existsSync as Zu,readFileSync as Qu,writeFileSync as ep}from"node:fs";import{join as tp}from"node:path";function Po(){let e=process.env.RECALL_API_BASE;if(e&&e.length>0){let t=e.replace(/\/$/,""),s;try{s=new URL(t)}catch{throw new Error(`RECALL_API_BASE is not a valid URL: ${t}`)}let n=s.hostname==="127.0.0.1"||s.hostname==="localhost"||s.hostname==="::1";if(s.protocol==="https:"||s.protocol==="http:"&&n)return t;throw new Error(`RECALL_API_BASE must be HTTPS, or HTTP with loopback hostname. Got: ${t}`)}return"https://clauderecall.com"}var yn=tp($,"license-check.json"),sp=1440*60*1e3,np=720*60*60*1e3,rp=1e4;function Uo(){if(!Zu(yn))return null;try{let e=JSON.parse(Qu(yn,"utf8"));return typeof e.license_key!="string"||typeof e.last_checked_at!="string"||typeof e.revoked!="boolean"?null:e}catch{return null}}function op(e){J(),ep(yn,JSON.stringify(e,null,2)+`
646
- `,{mode:384})}async function ip(e,t){let s=null,n=null;try{s=new AbortController,n=setTimeout(()=>s?.abort(),rp);let r=await fetch(t,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({license_key:e}),signal:s.signal});if(!r.ok)return null;let o=await r.json();return typeof o?.revoked!="boolean"?null:o}catch{return null}finally{n&&clearTimeout(n)}}async function $o(e,t={}){let s=Uo(),n=t.apiUrl??`${Po()}/api/license/check`,r=s?.license_key===e,o=!s||!r||Date.now()-new Date(s.last_checked_at).getTime()>=sp;if(!t.force&&!o)return s;let a=await ip(e,n);if(!a)return r?s:null;let c={license_key:e,last_checked_at:new Date().toISOString(),revoked:a.revoked,reason:a.reason??null};return op(c),c}function Bo(e){let t=Uo();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()>np?{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 ap=Date.UTC(2026,5,1,7,0,0);var cp=1440*60*1e3,zT=60*cp;async function Tt(){let e=St();if(!e)return{tier:"free"};let t=await Do(e.license_jwt);if(!t.valid||!t.claims)return{tier:"free",invalid_reason:t.reason};if(t.claims.machine_fp&&t.claims.machine_fp!==Fo())return{tier:"free",invalid_reason:"machine fingerprint mismatch \u2014 re-activate on this device"};let s=Bo(e.license_key);return s?.revoked?{tier:"free",invalid_reason:s.reason}:lp(e,t.claims)}async function Ho(e){let t=St();if(!t)return{ran:!1,revoked:!1,reason:null,last_checked_at:null};let s=await $o(t.license_key,{force:e?.force??!1});return s?{ran:!0,revoked:s.revoked,reason:s.reason,last_checked_at:s.last_checked_at}:{ran:!0,revoked:!1,reason:null,last_checked_at:null}}function lp(e,t){let s=t.test_mode===!0&&process.env.NODE_ENV==="production";return{tier:s?"free":"pro",key_short:e.key_short,customer_email:e.customer_email,activated_at:e.activated_at,test_mode:e.test_mode,...s?{test_mode_blocked:!0}:{},expires_at:typeof t.exp=="number"?new Date(t.exp*1e3).toISOString():null}}async function Wo(){return(await Tt()).tier==="pro"}H();import{serveStatic as su}from"@hono/node-server/serve-static";import{existsSync as Wb,readFileSync as ro}from"node:fs";import{stat as qb,readFile as Jb,realpath as Xb}from"node:fs/promises";import{timingSafeEqual as Gb}from"node:crypto";import{homedir as Yb}from"node:os";import{dirname as au,join as _o}from"node:path";import{fileURLToPath as cu}from"node:url";import{existsSync as Ey,readFileSync as by,statSync as Sy,statfsSync as up}from"node:fs";import be from"chalk";import{formatDistanceToNowStrict as gy,parseISO as _y}from"date-fns";var Yo={dim:be.gray,bold:be.bold,project:be.cyan,user:be.blue,assistant:be.green,tool:be.magenta,warn:be.yellow,err:be.red,ok:be.green,accent:be.hex("#f97316")};H();Z();var pp=["VS Code","VS Code Insiders","Cursor","Windsurf","Warp","iTerm","Terminal","WezTerm","Windows Terminal","Kitty","Alacritty"],Ry=new RegExp(`^(${pp.map(e=>e.replace(/ /g,"\\s")).join("|")})\\s\xB7\\s`);var ky=5*6e4;function wn(){try{let e=up($);return Number(e.bavail)*Number(e.bsize)}catch{return 0}}function Ko(e){let{projects:t,sessions:s,messages:n,port:r,version:o}=e;return`<!DOCTYPE html>
645
+ `,wn="ES256",Do="clauderecall.com",Fo="clauderecall-cli";var ss=null;async function Xu(){return ss||(ss=await Ju(Mo,wn),ss)}async function Po(e){try{let t=await Xu(),{payload:s}=await qu(e,t,{issuer:Do,audience:Fo,algorithms:[wn]});return{valid:!0,claims:s}}catch(t){return{valid:!1,reason:t instanceof Error?t.message:"verification failed"}}}import{createHash as Gu}from"node:crypto";import{hostname as Yu,userInfo as Ku,platform as zu,arch as Vu}from"node:os";function Uo(){let e="unknown";try{e=Ku().username}catch{}let t=[Yu(),e,zu(),Vu()];return Gu("sha256").update(t.join("\0")).digest("hex")}Z();import{existsSync as Zu,readFileSync as Qu,writeFileSync as ep}from"node:fs";import{join as tp}from"node:path";function $o(){let e=process.env.RECALL_API_BASE;if(e&&e.length>0){let t=e.replace(/\/$/,""),s;try{s=new URL(t)}catch{throw new Error(`RECALL_API_BASE is not a valid URL: ${t}`)}let n=s.hostname==="127.0.0.1"||s.hostname==="localhost"||s.hostname==="::1";if(s.protocol==="https:"||s.protocol==="http:"&&n)return t;throw new Error(`RECALL_API_BASE must be HTTPS, or HTTP with loopback hostname. Got: ${t}`)}return"https://clauderecall.com"}var Rn=tp($,"license-check.json"),sp=1440*60*1e3,np=720*60*60*1e3,rp=1e4;function Bo(){if(!Zu(Rn))return null;try{let e=JSON.parse(Qu(Rn,"utf8"));return typeof e.license_key!="string"||typeof e.last_checked_at!="string"||typeof e.revoked!="boolean"?null:e}catch{return null}}function op(e){J(),ep(Rn,JSON.stringify(e,null,2)+`
646
+ `,{mode:384})}async function ip(e,t){let s=null,n=null;try{s=new AbortController,n=setTimeout(()=>s?.abort(),rp);let r=await fetch(t,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({license_key:e}),signal:s.signal});if(!r.ok)return null;let o=await r.json();return typeof o?.revoked!="boolean"?null:o}catch{return null}finally{n&&clearTimeout(n)}}async function Ho(e,t={}){let s=Bo(),n=t.apiUrl??`${$o()}/api/license/check`,r=s?.license_key===e,o=!s||!r||Date.now()-new Date(s.last_checked_at).getTime()>=sp;if(!t.force&&!o)return s;let a=await ip(e,n);if(!a)return r?s:null;let c={license_key:e,last_checked_at:new Date().toISOString(),revoked:a.revoked,reason:a.reason??null};return op(c),c}function Wo(e){let t=Bo();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()>np?{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 ap=Date.UTC(2026,5,1,7,0,0);var cp=1440*60*1e3,zT=60*cp;async function Tt(){let e=St();if(!e)return{tier:"free"};let t=await Po(e.license_jwt);if(!t.valid||!t.claims)return{tier:"free",invalid_reason:t.reason};if(t.claims.machine_fp&&t.claims.machine_fp!==Uo())return{tier:"free",invalid_reason:"machine fingerprint mismatch \u2014 re-activate on this device"};let s=Wo(e.license_key);return s?.revoked?{tier:"free",invalid_reason:s.reason}:lp(e,t.claims)}async function qo(e){let t=St();if(!t)return{ran:!1,revoked:!1,reason:null,last_checked_at:null};let s=await Ho(t.license_key,{force:e?.force??!1});return s?{ran:!0,revoked:s.revoked,reason:s.reason,last_checked_at:s.last_checked_at}:{ran:!0,revoked:!1,reason:null,last_checked_at:null}}function lp(e,t){let s=t.test_mode===!0&&process.env.NODE_ENV==="production";return{tier:s?"free":"pro",key_short:e.key_short,customer_email:e.customer_email,activated_at:e.activated_at,test_mode:e.test_mode,...s?{test_mode_blocked:!0}:{},expires_at:typeof t.exp=="number"?new Date(t.exp*1e3).toISOString():null}}async function Jo(){return(await Tt()).tier==="pro"}H();import{serveStatic as ru}from"@hono/node-server/serve-static";import{existsSync as Wb,readFileSync as hn}from"node:fs";import{stat as qb,readFile as Jb,realpath as Xb}from"node:fs/promises";import{timingSafeEqual as Gb}from"node:crypto";import{homedir as Yb}from"node:os";import{dirname as fo,join as bn}from"node:path";import{fileURLToPath as ho}from"node:url";import{existsSync as Ey,readFileSync as by,statSync as Sy,statfsSync as up}from"node:fs";import be from"chalk";import{formatDistanceToNowStrict as gy,parseISO as _y}from"date-fns";var zo={dim:be.gray,bold:be.bold,project:be.cyan,user:be.blue,assistant:be.green,tool:be.magenta,warn:be.yellow,err:be.red,ok:be.green,accent:be.hex("#f97316")};H();Z();var pp=["VS Code","VS Code Insiders","Cursor","Windsurf","Warp","iTerm","Terminal","WezTerm","Windows Terminal","Kitty","Alacritty"],Ry=new RegExp(`^(${pp.map(e=>e.replace(/ /g,"\\s")).join("|")})\\s\xB7\\s`);var ky=5*6e4;function kn(){try{let e=up($);return Number(e.bavail)*Number(e.bsize)}catch{return 0}}function Vo(e){let{projects:t,sessions:s,messages:n,port:r,version:o}=e;return`<!DOCTYPE html>
647
647
  <html lang="en">
648
648
  <head>
649
649
  <meta charset="utf-8" />
@@ -700,53 +700,53 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
700
700
  </body>
701
701
  </html>`}var mp=/<(local-command-caveat|local-command-stdout|command-name|command-message|command-args|system-reminder|user-prompt-submit-hook|task-notification)[\s\S]*?<\/\1>/gi,gp=/⚡ \*\*Tool call · `[^`]+`\*\*\s*\n+```json\n[\s\S]*?\n```/g,_p=/\*\*Tool result\*\*\s*\n+```\n[\s\S]*?\n```/g;function fp(e){return e.replace(mp,"").trim()}function hp(e){let t=e.replace(gp,"[tool call]");return t=t.replace(_p,"[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,`
702
702
 
703
- `),t.trim()}function Ep(e){return e.role??e.type??"message"}function zo(e,t,s={}){let n=s.mode??"condensed",r=s.includeSidechain===!0,o=s.since?Date.parse(s.since):0,a=t.filter(g=>!(!r&&g.is_sidechain===1||o&&g.timestamp&&Date.parse(g.timestamp)<o)),c=[];s.prelude&&(c.push(s.prelude.trim()),c.push("")),c.push(`# Claude Recall, past session context (${n})`),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 d=0,u=0;for(let g of a){let h=g.content_text??"",b=fp(h);n==="condensed"&&(b=hp(b));let S=b.length>0,y=!!g.tool_names&&g.tool_names.length>0;if(!S&&!y){u+=1;continue}let k=Ep(g),w=g.timestamp?` \`${g.timestamp}\``:"";c.push(`## ${k}${w}`),c.push(""),y&&n==="condensed"&&(c.push(`_tools used: ${g.tool_names}_`),c.push("")),S&&(c.push(b),c.push("")),d+=1}return c.push("---"),c.push(""),c.push(`_${d} messages included_`+(u?`, ${u} empty skipped`:"")+(r?"":", subagent/sidechain hidden")+"."),c.join(`
704
- `)}H();Z();import{writeFileSync as bp}from"node:fs";import{join as Sp}from"node:path";var Tp=Sp($,"aliases.json");function Rn(e){try{let t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return[]}function Se(e){return f().prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(e)?.alias??null}function yp(){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:Rn(t.previous_aliases)}))}function me(e,t){let s=t.trim();if(!s)throw new Error("alias must be non-empty");let n=f(),r=new Date().toISOString(),o=n.prepare("SELECT alias, previous_aliases FROM session_aliases WHERE session_id = ?").get(e),a=[];return o&&(a=Rn(o.previous_aliases),o.alias!==s&&a.push({alias:o.alias,replaced_at:r})),n.prepare(`INSERT INTO session_aliases (session_id, alias, updated_at, previous_aliases)
703
+ `),t.trim()}function Ep(e){return e.role??e.type??"message"}function Zo(e,t,s={}){let n=s.mode??"condensed",r=s.includeSidechain===!0,o=s.since?Date.parse(s.since):0,a=t.filter(g=>!(!r&&g.is_sidechain===1||o&&g.timestamp&&Date.parse(g.timestamp)<o)),c=[];s.prelude&&(c.push(s.prelude.trim()),c.push("")),c.push(`# Claude Recall, past session context (${n})`),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 d=0,u=0;for(let g of a){let h=g.content_text??"",b=fp(h);n==="condensed"&&(b=hp(b));let S=b.length>0,y=!!g.tool_names&&g.tool_names.length>0;if(!S&&!y){u+=1;continue}let k=Ep(g),w=g.timestamp?` \`${g.timestamp}\``:"";c.push(`## ${k}${w}`),c.push(""),y&&n==="condensed"&&(c.push(`_tools used: ${g.tool_names}_`),c.push("")),S&&(c.push(b),c.push("")),d+=1}return c.push("---"),c.push(""),c.push(`_${d} messages included_`+(u?`, ${u} empty skipped`:"")+(r?"":", subagent/sidechain hidden")+"."),c.join(`
704
+ `)}H();Z();import{writeFileSync as bp}from"node:fs";import{join as Sp}from"node:path";var Tp=Sp($,"aliases.json");function An(e){try{let t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return[]}function Se(e){return f().prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(e)?.alias??null}function yp(){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:An(t.previous_aliases)}))}function me(e,t){let s=t.trim();if(!s)throw new Error("alias must be non-empty");let n=f(),r=new Date().toISOString(),o=n.prepare("SELECT alias, previous_aliases FROM session_aliases WHERE session_id = ?").get(e),a=[];return o&&(a=An(o.previous_aliases),o.alias!==s&&a.push({alias:o.alias,replaced_at:r})),n.prepare(`INSERT INTO session_aliases (session_id, alias, updated_at, previous_aliases)
705
705
  VALUES (?, ?, ?, ?)
706
706
  ON CONFLICT(session_id) DO UPDATE SET
707
707
  alias = excluded.alias,
708
708
  updated_at = excluded.updated_at,
709
- previous_aliases = excluded.previous_aliases`).run(e,s,r,JSON.stringify(a)),Vo(),{session_id:e,alias:s,updated_at:r,previous_aliases:a}}function ns(e){let t=f(),s=new Date().toISOString(),n=t.prepare("SELECT alias, previous_aliases FROM session_aliases WHERE session_id = ?").get(e);if(!n)return;let r=Rn(n.previous_aliases);r.push({alias:n.alias,replaced_at:s}),t.prepare(`UPDATE session_aliases SET alias = '', updated_at = ?, previous_aliases = ?
710
- WHERE session_id = ?`).run(s,JSON.stringify(r),e),Vo()}function Vo(){try{J();let e=yp(),t={schema:"claude-recall.aliases.v1",backed_up_at:new Date().toISOString(),aliases:e};bp(Tp,JSON.stringify(t,null,2))}catch(e){console.error("[aliases] backup failed:",e)}}function yt(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),s=Date.parse(e.terminalOpenedAt);return Number.isFinite(t)?Number.isFinite(s)?s-t>6e4?{allowed:!1,reason:"terminal-postdates-session"}:{allowed:!0}:{allowed:!1,reason:"missing-terminal-opened-at"}:{allowed:!1,reason:"missing-session-started-at"}}H();Z();import{writeFileSync as Gp,mkdirSync as Yp,existsSync as Kp}from"node:fs";import{join as oi}from"node:path";var Ln=oi($,"notes"),ri=200,zp=12e3,Vp=800,Zp=8e3;function ii(e){try{let t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return[]}function ai(e){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t.filter(s=>!!s&&typeof s=="object"&&typeof s.synopsis=="string"&&typeof s.replaced_at=="string"):[]}catch{return[]}}function Qp(){J(),Kp(Ln)||Yp(Ln,{recursive:!0})}function em(e){return{session_id:e.session_id,content:e.content,updated_at:e.updated_at,previous_versions:ii(e.previous_versions),auto_synopsis:e.auto_synopsis??null,auto_synopsis_generated_at:e.auto_synopsis_generated_at??null,auto_synopsis_history:ai(e.auto_synopsis_history)}}var tm="session_id, content, updated_at, previous_versions, auto_synopsis, auto_synopsis_generated_at, auto_synopsis_history";function is(e){let t=f().prepare(`SELECT ${tm} FROM session_notes WHERE session_id = ?`).get(e);return t?em(t):null}function ci(e,t){let s=f(),n=new Date().toISOString(),r=s.prepare("SELECT content, previous_versions FROM session_notes WHERE session_id = ?").get(e),o=[];return r&&(o=ii(r.previous_versions),r.content!==t&&r.content.length>0&&o.push({content:r.content,replaced_at:n})),s.prepare(`INSERT INTO session_notes (session_id, content, updated_at, previous_versions)
709
+ previous_aliases = excluded.previous_aliases`).run(e,s,r,JSON.stringify(a)),Qo(),{session_id:e,alias:s,updated_at:r,previous_aliases:a}}function ns(e){let t=f(),s=new Date().toISOString(),n=t.prepare("SELECT alias, previous_aliases FROM session_aliases WHERE session_id = ?").get(e);if(!n)return;let r=An(n.previous_aliases);r.push({alias:n.alias,replaced_at:s}),t.prepare(`UPDATE session_aliases SET alias = '', updated_at = ?, previous_aliases = ?
710
+ WHERE session_id = ?`).run(s,JSON.stringify(r),e),Qo()}function Qo(){try{J();let e=yp(),t={schema:"claude-recall.aliases.v1",backed_up_at:new Date().toISOString(),aliases:e};bp(Tp,JSON.stringify(t,null,2))}catch(e){console.error("[aliases] backup failed:",e)}}function yt(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),s=Date.parse(e.terminalOpenedAt);return Number.isFinite(t)?Number.isFinite(s)?s-t>6e4?{allowed:!1,reason:"terminal-postdates-session"}:{allowed:!0}:{allowed:!1,reason:"missing-terminal-opened-at"}:{allowed:!1,reason:"missing-session-started-at"}}H();Z();import{writeFileSync as Gp,mkdirSync as Yp,existsSync as Kp}from"node:fs";import{join as ai}from"node:path";var In=ai($,"notes"),ii=200,zp=12e3,Vp=800,Zp=8e3;function ci(e){try{let t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return[]}function li(e){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t.filter(s=>!!s&&typeof s=="object"&&typeof s.synopsis=="string"&&typeof s.replaced_at=="string"):[]}catch{return[]}}function Qp(){J(),Kp(In)||Yp(In,{recursive:!0})}function em(e){return{session_id:e.session_id,content:e.content,updated_at:e.updated_at,previous_versions:ci(e.previous_versions),auto_synopsis:e.auto_synopsis??null,auto_synopsis_generated_at:e.auto_synopsis_generated_at??null,auto_synopsis_history:li(e.auto_synopsis_history)}}var tm="session_id, content, updated_at, previous_versions, auto_synopsis, auto_synopsis_generated_at, auto_synopsis_history";function is(e){let t=f().prepare(`SELECT ${tm} FROM session_notes WHERE session_id = ?`).get(e);return t?em(t):null}function di(e,t){let s=f(),n=new Date().toISOString(),r=s.prepare("SELECT content, previous_versions FROM session_notes WHERE session_id = ?").get(e),o=[];return r&&(o=ci(r.previous_versions),r.content!==t&&r.content.length>0&&o.push({content:r.content,replaced_at:n})),s.prepare(`INSERT INTO session_notes (session_id, content, updated_at, previous_versions)
711
711
  VALUES (?, ?, ?, ?)
712
712
  ON CONFLICT(session_id) DO UPDATE SET
713
713
  content = excluded.content,
714
714
  updated_at = excluded.updated_at,
715
- previous_versions = excluded.previous_versions`).run(e,t,n,JSON.stringify(o)),nm(e,t,n),is(e)??{session_id:e,content:t,updated_at:n,previous_versions:o,auto_synopsis:null,auto_synopsis_generated_at:null,auto_synopsis_history:[]}}async function li(e){let s=f().prepare(`SELECT rowid AS rid, role, content_text
715
+ previous_versions = excluded.previous_versions`).run(e,t,n,JSON.stringify(o)),nm(e,t,n),is(e)??{session_id:e,content:t,updated_at:n,previous_versions:o,auto_synopsis:null,auto_synopsis_generated_at:null,auto_synopsis_history:[]}}async function ui(e){let s=f().prepare(`SELECT rowid AS rid, role, content_text
716
716
  FROM messages
717
717
  WHERE session_id = ? AND is_sidechain = 0
718
718
  AND content_text IS NOT NULL AND content_text != ''
719
719
  AND role IN ('user', 'assistant')
720
720
  ORDER BY COALESCE(timestamp, '') DESC, rowid DESC
721
- LIMIT ?`).all(e,ri);if(s.length===0)throw new Error("no messages available to summarise");let n=zp,r=[];for(let b of s){if(n<=0)break;let S=(b.content_text??"").slice(0,Vp);r.push({rid:b.rid,role:b.role,content:S}),n-=S.length}r.reverse();let o=s.length===ri||n<=0,a=r.map(b=>`**${b.role}**: ${b.content}`).join(`
721
+ LIMIT ?`).all(e,ii);if(s.length===0)throw new Error("no messages available to summarise");let n=zp,r=[];for(let b of s){if(n<=0)break;let S=(b.content_text??"").slice(0,Vp);r.push({rid:b.rid,role:b.role,content:S}),n-=S.length}r.reverse();let o=s.length===ii||n<=0,a=r.map(b=>`**${b.role}**: ${b.content}`).join(`
722
722
 
723
723
  `),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(`
724
- `),{spawnClaudePrompt:d,isClaudeCliAvailable:u}=await Promise.resolve().then(()=>(ge(),Pe));if(!u())throw new Error("claude CLI not found on PATH");let g=await d(c,[],{});if(!g.success)throw new Error(`claude CLI exited ${g.exitCode}: ${g.stderr.slice(-500)}`);let h=sm(g.stdout);if(!h)throw new Error("claude CLI returned an empty synopsis");return h.slice(0,Zp)}function sm(e){let t=e.trim();if(!t)return"";try{let s=JSON.parse(t);if(s&&typeof s=="object"){let n=s.result;if(typeof n=="string")return n.trim()}}catch{}return t}function di(e,t){let s=f(),n=new Date().toISOString(),r=Date.now(),o=s.prepare("SELECT auto_synopsis, auto_synopsis_history, content, updated_at FROM session_notes WHERE session_id = ?").get(e),a=ai(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:n}),o?s.prepare(`UPDATE session_notes
724
+ `),{spawnClaudePrompt:d,isClaudeCliAvailable:u}=await Promise.resolve().then(()=>(ge(),Pe));if(!u())throw new Error("claude CLI not found on PATH");let g=await d(c,[],{});if(!g.success)throw new Error(`claude CLI exited ${g.exitCode}: ${g.stderr.slice(-500)}`);let h=sm(g.stdout);if(!h)throw new Error("claude CLI returned an empty synopsis");return h.slice(0,Zp)}function sm(e){let t=e.trim();if(!t)return"";try{let s=JSON.parse(t);if(s&&typeof s=="object"){let n=s.result;if(typeof n=="string")return n.trim()}}catch{}return t}function pi(e,t){let s=f(),n=new Date().toISOString(),r=Date.now(),o=s.prepare("SELECT auto_synopsis, auto_synopsis_history, content, updated_at FROM session_notes WHERE session_id = ?").get(e),a=li(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:n}),o?s.prepare(`UPDATE session_notes
725
725
  SET auto_synopsis = ?,
726
726
  auto_synopsis_generated_at = ?,
727
727
  auto_synopsis_history = ?
728
728
  WHERE session_id = ?`).run(t,r,JSON.stringify(a),e):s.prepare(`INSERT INTO session_notes
729
729
  (session_id, content, updated_at, previous_versions, auto_synopsis,
730
730
  auto_synopsis_generated_at, auto_synopsis_history)
731
- VALUES (?, '', ?, '[]', ?, ?, ?)`).run(e,n,t,r,JSON.stringify(a)),is(e)}function nm(e,t,s){try{Qp();let n=oi(Ln,`${e}.md`),r=`<!-- Claude Recall note \xB7 session ${e} \xB7 updated ${s} -->
731
+ VALUES (?, '', ?, '[]', ?, ?, ?)`).run(e,n,t,r,JSON.stringify(a)),is(e)}function nm(e,t,s){try{Qp();let n=ai(In,`${e}.md`),r=`<!-- Claude Recall note \xB7 session ${e} \xB7 updated ${s} -->
732
732
  `;Gp(n,r+t)}catch(n){console.error("[notes] mirror write failed:",n)}}Ge();H();Z();import{randomUUID as rm}from"node:crypto";import{writeFileSync as om,readFileSync as nw,existsSync as rw}from"node:fs";import{join as im}from"node:path";var am=im($,"collections.json"),as=8;function cs(e){return{...e}}function _e(e,t,s,n=null,r=new Date().toISOString()){f().prepare(`INSERT INTO collection_events (collection_id, session_id, action, payload, at)
733
- VALUES (?, ?, ?, ?, ?)`).run(e,n,t,s?JSON.stringify(s):null,r)}function ls(e){let t=f().prepare("SELECT * FROM collections WHERE id = ?").get(e);if(!t)throw new Error(`collection not found: ${e}`);return t}function ui(e){if(!e)return 0;let t=0,s=e,n=new Set,r=f();for(;s;){if(n.has(s))throw new Error("collection cycle detected");n.add(s);let o=r.prepare("SELECT parent_id FROM collections WHERE id = ?").get(s);if(!o)break;t+=1,s=o.parent_id}return t}function cm(e,t){let s=f(),n=e,r=new Set;for(;n;){if(r.has(n))return!1;if(r.add(n),n===t)return!0;let o=s.prepare("SELECT parent_id FROM collections WHERE id = ?").get(n);if(!o)return!1;n=o.parent_id}return!1}function pi(e=!1){return f().prepare(`SELECT c.*,
733
+ VALUES (?, ?, ?, ?, ?)`).run(e,n,t,s?JSON.stringify(s):null,r)}function ls(e){let t=f().prepare("SELECT * FROM collections WHERE id = ?").get(e);if(!t)throw new Error(`collection not found: ${e}`);return t}function mi(e){if(!e)return 0;let t=0,s=e,n=new Set,r=f();for(;s;){if(n.has(s))throw new Error("collection cycle detected");n.add(s);let o=r.prepare("SELECT parent_id FROM collections WHERE id = ?").get(s);if(!o)break;t+=1,s=o.parent_id}return t}function cm(e,t){let s=f(),n=e,r=new Set;for(;n;){if(r.has(n))return!1;if(r.add(n),n===t)return!0;let o=s.prepare("SELECT parent_id FROM collections WHERE id = ?").get(n);if(!o)return!1;n=o.parent_id}return!1}function gi(e=!1){return f().prepare(`SELECT c.*,
734
734
  (SELECT COUNT(*) FROM collection_sessions cs WHERE cs.collection_id = c.id) AS session_count
735
735
  FROM collections c
736
736
  ${e?"":"WHERE c.archived_at IS NULL"}
737
- ORDER BY c.parent_id IS NOT NULL, c.parent_id, c.sort_key, LOWER(c.name)`).all().map(n=>({...cs(n),session_count:n.session_count}))}function xe(e){let t=f().prepare("SELECT * FROM collections WHERE id = ?").get(e);return t?cs(t):null}function mi(e,t=!0){let s=f(),n=t?Cn(e):[e];if(n.length===0)return[];let r=n.map(()=>"?").join(",");return s.prepare(`SELECT collection_id, session_id, added_at, note, source, rule_id
737
+ ORDER BY c.parent_id IS NOT NULL, c.parent_id, c.sort_key, LOWER(c.name)`).all().map(n=>({...cs(n),session_count:n.session_count}))}function xe(e){let t=f().prepare("SELECT * FROM collections WHERE id = ?").get(e);return t?cs(t):null}function _i(e,t=!0){let s=f(),n=t?vn(e):[e];if(n.length===0)return[];let r=n.map(()=>"?").join(",");return s.prepare(`SELECT collection_id, session_id, added_at, note, source, rule_id
738
738
  FROM collection_sessions
739
739
  WHERE collection_id IN (${r})
740
- ORDER BY added_at DESC`).all(...n)}function Cn(e){let t=f(),s=[e],n=[e],r=new Set([e]);for(;n.length>0;){let o=n.map(()=>"?").join(","),a=t.prepare(`SELECT id FROM collections WHERE parent_id IN (${o})`).all(...n),c=[];for(let d of a)r.has(d.id)||(r.add(d.id),s.push(d.id),c.push(d.id));n=c}return s}function gi(e){return f().prepare(`SELECT c.* FROM collections c
740
+ ORDER BY added_at DESC`).all(...n)}function vn(e){let t=f(),s=[e],n=[e],r=new Set([e]);for(;n.length>0;){let o=n.map(()=>"?").join(","),a=t.prepare(`SELECT id FROM collections WHERE parent_id IN (${o})`).all(...n),c=[];for(let d of a)r.has(d.id)||(r.add(d.id),s.push(d.id),c.push(d.id));n=c}return s}function fi(e){return f().prepare(`SELECT c.* FROM collections c
741
741
  JOIN collection_sessions cs ON cs.collection_id = c.id
742
742
  WHERE cs.session_id = ? AND c.archived_at IS NULL
743
- ORDER BY LOWER(c.name)`).all(e)}function At(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 s=f(),n=new Date().toISOString(),r=rm();if(e.parent_id){if(!xe(e.parent_id))throw new Error("parent collection not found");if(ui(e.parent_id)>=as-1)throw new Error(`max collection depth is ${as}`)}return s.transaction(()=>{s.prepare(`INSERT INTO collections
743
+ ORDER BY LOWER(c.name)`).all(e)}function At(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 s=f(),n=new Date().toISOString(),r=rm();if(e.parent_id){if(!xe(e.parent_id))throw new Error("parent collection not found");if(mi(e.parent_id)>=as-1)throw new Error(`max collection depth is ${as}`)}return s.transaction(()=>{s.prepare(`INSERT INTO collections
744
744
  (id, name, description, icon, color, parent_id, sort_key, created_at, updated_at, archived_at)
745
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL)`).run(r,t,e.description??null,e.icon??null,e.color??null,e.parent_id??null,e.sort_key??"",n,n),_e(r,"create",{name:t,parent_id:e.parent_id??null,icon:e.icon??null,color:e.color??null},null,n)})(),Ue(),xe(r)}function _i(e,t){let s=f(),n=ls(e),r=new Date().toISOString(),o={name:t.name!==void 0?t.name.trim():n.name,description:t.description!==void 0?t.description:n.description,icon:t.icon!==void 0?t.icon:n.icon,color:t.color!==void 0?t.color:n.color,parent_id:t.parent_id!==void 0?t.parent_id:n.parent_id,sort_key:t.sort_key!==void 0?t.sort_key:n.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!==n.parent_id&&t.parent_id){if(t.parent_id===e)throw new Error("cannot set parent to self");if(!xe(t.parent_id))throw new Error("parent collection not found");if(cm(t.parent_id,e))throw new Error("cannot move collection into one of its descendants");if(ui(t.parent_id)>=as-1)throw new Error(`max collection depth is ${as}`)}return s.transaction(()=>{s.prepare(`UPDATE collections
745
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL)`).run(r,t,e.description??null,e.icon??null,e.color??null,e.parent_id??null,e.sort_key??"",n,n),_e(r,"create",{name:t,parent_id:e.parent_id??null,icon:e.icon??null,color:e.color??null},null,n)})(),Ue(),xe(r)}function hi(e,t){let s=f(),n=ls(e),r=new Date().toISOString(),o={name:t.name!==void 0?t.name.trim():n.name,description:t.description!==void 0?t.description:n.description,icon:t.icon!==void 0?t.icon:n.icon,color:t.color!==void 0?t.color:n.color,parent_id:t.parent_id!==void 0?t.parent_id:n.parent_id,sort_key:t.sort_key!==void 0?t.sort_key:n.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!==n.parent_id&&t.parent_id){if(t.parent_id===e)throw new Error("cannot set parent to self");if(!xe(t.parent_id))throw new Error("parent collection not found");if(cm(t.parent_id,e))throw new Error("cannot move collection into one of its descendants");if(mi(t.parent_id)>=as-1)throw new Error(`max collection depth is ${as}`)}return s.transaction(()=>{s.prepare(`UPDATE collections
746
746
  SET name = ?, description = ?, icon = ?, color = ?,
747
747
  parent_id = ?, sort_key = ?, updated_at = ?
748
- 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!==n.name&&_e(e,"rename",{from:n.name,to:o.name},null,r),t.description!==void 0&&t.description!==n.description&&_e(e,"describe",{description:o.description},null,r),(t.icon!==void 0&&t.icon!==n.icon||t.color!==void 0&&t.color!==n.color)&&_e(e,"recolor",{icon:o.icon,color:o.color},null,r),t.parent_id!==void 0&&t.parent_id!==n.parent_id&&_e(e,"move",{from:n.parent_id,to:o.parent_id},null,r),t.sort_key!==void 0&&t.sort_key!==n.sort_key&&_e(e,"reorder",{from:n.sort_key,to:o.sort_key},null,r)})(),Ue(),xe(e)}function fi(e){let t=f(),s=ls(e);if(s.archived_at)return cs(s);let n=new Date().toISOString();return t.transaction(()=>{t.prepare("UPDATE collections SET archived_at = ?, updated_at = ? WHERE id = ?").run(n,n,e),_e(e,"archive",{name:s.name},null,n)})(),Ue(),xe(e)}function hi(e){let t=f(),s=ls(e);if(!s.archived_at)return cs(s);let n=new Date().toISOString();return t.transaction(()=>{t.prepare("UPDATE collections SET archived_at = NULL, updated_at = ? WHERE id = ?").run(n,e),_e(e,"restore",{name:s.name},null,n)})(),Ue(),xe(e)}function Nt(e,t,s=null,n={}){let r=f();if(ls(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=n.source??"manual",d=n.rule_id??null;if(c==="auto"&&!d)throw new Error("auto membership requires a rule_id");let u=new Date().toISOString();return r.transaction(()=>{r.prepare(`INSERT INTO collection_sessions (collection_id, session_id, added_at, note, source, rule_id)
749
- VALUES (?, ?, ?, ?, ?, ?)`).run(e,t,u,s,c,d),_e(e,"add",{note:s,source:c,rule_id:d},t,u)})(),Ue(),{added:!0}}function Ei(e,t){let s=f();if(!s.prepare("SELECT 1 FROM collection_sessions WHERE collection_id = ? AND session_id = ?").get(e,t))return{removed:!1};let r=new Date().toISOString();return s.transaction(()=>{s.prepare("DELETE FROM collection_sessions WHERE collection_id = ? AND session_id = ?").run(e,t),_e(e,"remove",null,t,r)})(),Ue(),{removed:!0}}function ds(e){let t=f(),s=t.prepare(`SELECT collection_id, session_id FROM collection_sessions
748
+ 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!==n.name&&_e(e,"rename",{from:n.name,to:o.name},null,r),t.description!==void 0&&t.description!==n.description&&_e(e,"describe",{description:o.description},null,r),(t.icon!==void 0&&t.icon!==n.icon||t.color!==void 0&&t.color!==n.color)&&_e(e,"recolor",{icon:o.icon,color:o.color},null,r),t.parent_id!==void 0&&t.parent_id!==n.parent_id&&_e(e,"move",{from:n.parent_id,to:o.parent_id},null,r),t.sort_key!==void 0&&t.sort_key!==n.sort_key&&_e(e,"reorder",{from:n.sort_key,to:o.sort_key},null,r)})(),Ue(),xe(e)}function Ei(e){let t=f(),s=ls(e);if(s.archived_at)return cs(s);let n=new Date().toISOString();return t.transaction(()=>{t.prepare("UPDATE collections SET archived_at = ?, updated_at = ? WHERE id = ?").run(n,n,e),_e(e,"archive",{name:s.name},null,n)})(),Ue(),xe(e)}function bi(e){let t=f(),s=ls(e);if(!s.archived_at)return cs(s);let n=new Date().toISOString();return t.transaction(()=>{t.prepare("UPDATE collections SET archived_at = NULL, updated_at = ? WHERE id = ?").run(n,e),_e(e,"restore",{name:s.name},null,n)})(),Ue(),xe(e)}function Nt(e,t,s=null,n={}){let r=f();if(ls(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=n.source??"manual",d=n.rule_id??null;if(c==="auto"&&!d)throw new Error("auto membership requires a rule_id");let u=new Date().toISOString();return r.transaction(()=>{r.prepare(`INSERT INTO collection_sessions (collection_id, session_id, added_at, note, source, rule_id)
749
+ VALUES (?, ?, ?, ?, ?, ?)`).run(e,t,u,s,c,d),_e(e,"add",{note:s,source:c,rule_id:d},t,u)})(),Ue(),{added:!0}}function Si(e,t){let s=f();if(!s.prepare("SELECT 1 FROM collection_sessions WHERE collection_id = ? AND session_id = ?").get(e,t))return{removed:!1};let r=new Date().toISOString();return s.transaction(()=>{s.prepare("DELETE FROM collection_sessions WHERE collection_id = ? AND session_id = ?").run(e,t),_e(e,"remove",null,t,r)})(),Ue(),{removed:!0}}function ds(e){let t=f(),s=t.prepare(`SELECT collection_id, session_id FROM collection_sessions
750
750
  WHERE rule_id = ?`).all(e);if(s.length===0)return{removed:0};let n=new Date().toISOString();return t.transaction(()=>{t.prepare("DELETE FROM collection_sessions WHERE rule_id = ?").run(e);for(let o of s)_e(o.collection_id,"remove",{rule_id:e},o.session_id,n)})(),Ue(),{removed:s.length}}function lm(){return f().prepare(`SELECT id, collection_id, session_id, action, payload, at
751
751
  FROM collection_events
752
752
  ORDER BY at ASC, id ASC`).all()}function Ue(){try{J();let e=f(),t=e.prepare(`SELECT id, name, description, icon, color, parent_id, sort_key,
@@ -754,10 +754,10 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
754
754
  FROM collections
755
755
  ORDER BY COALESCE(parent_id, ''), sort_key, LOWER(name)`).all(),s=e.prepare(`SELECT collection_id, session_id, added_at, note, source, rule_id
756
756
  FROM collection_sessions
757
- ORDER BY collection_id, added_at`).all(),n=lm(),r={schema:"claude-recall.collections.v1",backed_up_at:new Date().toISOString(),collections:t,memberships:s,events:n};om(am,JSON.stringify(r,null,2))}catch(e){console.error("[collections] backup failed:",e)}}H();Z();import{randomUUID as jn}from"node:crypto";import{existsSync as dm,mkdirSync as um,writeFileSync as bi}from"node:fs";import{homedir as pm}from"node:os";import{basename as mm,join as Mn}from"node:path";var us=Mn($,"auto-rules"),gm=Mn(us,"rules.json"),_m=Mn(us,"suggestions.json"),In="Repositories",fm="Topics",Si=3;var hm=5,Em=2,bm=[/\bROADMAP\.md\b/g,/\bPROJECT\.md\b/g,/\bdocs\/[A-Za-z0-9._-]+\.md\b/g,/\.planning\/[A-Za-z0-9._\-/]+/g];function Dn(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 Sm(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 Tm(e){switch(e){case"cwd-prefix":case"project-id":case"git-branch-prefix":return In;case"tag":return fm;case"plan-file":return null}}function ym(e){let s=f().prepare("SELECT id FROM collections WHERE name = ? AND parent_id IS NULL AND archived_at IS NULL").get(e);if(s)return s.id;let o=At({name:e,icon:e===In?"\u{1F4E6}":"\u{1F3F7}",sort_key:e===In?"0000-repos":"0001-topics"});return f().prepare(`INSERT INTO auto_collection_rules
757
+ ORDER BY collection_id, added_at`).all(),n=lm(),r={schema:"claude-recall.collections.v1",backed_up_at:new Date().toISOString(),collections:t,memberships:s,events:n};om(am,JSON.stringify(r,null,2))}catch(e){console.error("[collections] backup failed:",e)}}H();Z();import{randomUUID as Dn}from"node:crypto";import{existsSync as dm,mkdirSync as um,writeFileSync as Ti}from"node:fs";import{homedir as pm}from"node:os";import{basename as mm,join as Fn}from"node:path";var us=Fn($,"auto-rules"),gm=Fn(us,"rules.json"),_m=Fn(us,"suggestions.json"),jn="Repositories",fm="Topics",yi=3;var hm=5,Em=2,bm=[/\bROADMAP\.md\b/g,/\bPROJECT\.md\b/g,/\bdocs\/[A-Za-z0-9._-]+\.md\b/g,/\.planning\/[A-Za-z0-9._\-/]+/g];function Pn(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 Sm(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 Tm(e){switch(e){case"cwd-prefix":case"project-id":case"git-branch-prefix":return jn;case"tag":return fm;case"plan-file":return null}}function ym(e){let s=f().prepare("SELECT id FROM collections WHERE name = ? AND parent_id IS NULL AND archived_at IS NULL").get(e);if(s)return s.id;let o=At({name:e,icon:e===jn?"\u{1F4E6}":"\u{1F3F7}",sort_key:e===jn?"0000-repos":"0001-topics"});return f().prepare(`INSERT INTO auto_collection_rules
758
758
  (id, name, type, pattern, collection_id, priority, enabled, created_at, created_by)
759
- VALUES (?, ?, 'cwd-prefix', '__seed__', ?, 1000, 0, ?, 'seed')`).run(jn(),`seed:${e}`,o.id,new Date().toISOString()),o.id}function wm(e,t,s){let n;if(s!==void 0)n=s;else{let o=Tm(t);n=o?ym(o):null}return At({name:e,parent_id:n}).id}function ps(e){let t=f().prepare("SELECT * FROM auto_collection_rules WHERE id = ?").get(e);return t?Dn(t):null}function Rm(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(ms(e.pattern)+"%").map(n=>n.id);case"git-branch-prefix":return t.prepare("SELECT id FROM sessions WHERE git_branch IS NOT NULL AND git_branch LIKE ? ESCAPE '\\'").all(ms(e.pattern)+"%").map(n=>n.id);case"project-id":{let s=Number(e.pattern);return Number.isFinite(s)?t.prepare("SELECT id FROM sessions WHERE project_id = ?").all(s).map(r=>r.id):[]}case"tag":return t.prepare("SELECT session_id FROM session_tags WHERE tag = ?").all(e.pattern).map(n=>n.session_id);case"plan-file":return t.prepare(`SELECT id, first_user_message FROM sessions
760
- WHERE first_user_message IS NOT NULL AND first_user_message LIKE ?`).all("%"+e.pattern+"%").map(n=>n.id)}}function Ti(e,t,s=3){let n=f(),r=`s.id AS id, s.cwd AS cwd, s.started_at AS started_at,
759
+ VALUES (?, ?, 'cwd-prefix', '__seed__', ?, 1000, 0, ?, 'seed')`).run(Dn(),`seed:${e}`,o.id,new Date().toISOString()),o.id}function wm(e,t,s){let n;if(s!==void 0)n=s;else{let o=Tm(t);n=o?ym(o):null}return At({name:e,parent_id:n}).id}function ps(e){let t=f().prepare("SELECT * FROM auto_collection_rules WHERE id = ?").get(e);return t?Pn(t):null}function Rm(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(ms(e.pattern)+"%").map(n=>n.id);case"git-branch-prefix":return t.prepare("SELECT id FROM sessions WHERE git_branch IS NOT NULL AND git_branch LIKE ? ESCAPE '\\'").all(ms(e.pattern)+"%").map(n=>n.id);case"project-id":{let s=Number(e.pattern);return Number.isFinite(s)?t.prepare("SELECT id FROM sessions WHERE project_id = ?").all(s).map(r=>r.id):[]}case"tag":return t.prepare("SELECT session_id FROM session_tags WHERE tag = ?").all(e.pattern).map(n=>n.session_id);case"plan-file":return t.prepare(`SELECT id, first_user_message FROM sessions
760
+ WHERE first_user_message IS NOT NULL AND first_user_message LIKE ?`).all("%"+e.pattern+"%").map(n=>n.id)}}function wi(e,t,s=3){let n=f(),r=`s.id AS id, s.cwd AS cwd, s.started_at AS started_at,
761
761
  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=n.prepare(`SELECT ${r} FROM sessions s ${o}
762
762
  WHERE s.cwd IS NOT NULL AND s.cwd LIKE ? ESCAPE '\\'
763
763
  ORDER BY s.started_at DESC LIMIT ?`).all(ms(t)+"%",s);break;case"git-branch-prefix":a=n.prepare(`SELECT ${r} FROM sessions s ${o}
@@ -771,18 +771,18 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
771
771
  WHERE s.first_user_message IS NOT NULL
772
772
  AND s.first_user_message LIKE ?
773
773
  ORDER BY s.started_at DESC LIMIT ?`).all("%"+t+"%",s);break}return a.map(c=>({id:c.id,title:km(c),cwd:c.cwd,started_at:c.started_at}))}function km(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 s=t.split(`
774
- `)[0].trim();return s.length>80?s.slice(0,80)+"\u2026":s}function Am(e,t,s=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 n=Number(e.pattern);return Number.isFinite(n)&&t.project_id===n}case"tag":return!!s.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 yi(e){let t=f(),s=t.prepare("SELECT id, project_id, cwd, git_branch, first_user_message FROM sessions WHERE id = ?").get(e);if(!s)return{added:0};let n=t.prepare(`SELECT * FROM auto_collection_rules
774
+ `)[0].trim();return s.length>80?s.slice(0,80)+"\u2026":s}function Am(e,t,s=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 n=Number(e.pattern);return Number.isFinite(n)&&t.project_id===n}case"tag":return!!s.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 Ri(e){let t=f(),s=t.prepare("SELECT id, project_id, cwd, git_branch, first_user_message FROM sessions WHERE id = ?").get(e);if(!s)return{added:0};let n=t.prepare(`SELECT * FROM auto_collection_rules
775
775
  WHERE enabled = 1 AND created_by != 'seed'
776
- ORDER BY priority, created_at`).all(),r=0;for(let o of n){let a=Dn(o);if(Am(a,s,t))try{Nt(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 vn(e){if(!e.enabled)return{added:0};let t=0;for(let s of Rm(e))try{Nt(e.collection_id,s,null,{source:"auto",rule_id:e.id}).added&&(t+=1)}catch(n){console.error(`[auto-collections] backfill failed for rule ${e.id} / session ${s}:`,n)}return{added:t}}function Fn(e){let t=(e.name??"").trim();if(!t)throw new Error("name required");let s=(e.pattern??"").trim();if(!s)throw new Error("pattern required");let n=f(),r=new Date().toISOString(),o=jn(),a=e.collection_id;a||(a=wm(t,e.type,e.parent_collection_id)),n.prepare(`INSERT INTO auto_collection_rules
776
+ ORDER BY priority, created_at`).all(),r=0;for(let o of n){let a=Pn(o);if(Am(a,s,t))try{Nt(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 Mn(e){if(!e.enabled)return{added:0};let t=0;for(let s of Rm(e))try{Nt(e.collection_id,s,null,{source:"auto",rule_id:e.id}).added&&(t+=1)}catch(n){console.error(`[auto-collections] backfill failed for rule ${e.id} / session ${s}:`,n)}return{added:t}}function Un(e){let t=(e.name??"").trim();if(!t)throw new Error("name required");let s=(e.pattern??"").trim();if(!s)throw new Error("pattern required");let n=f(),r=new Date().toISOString(),o=Dn(),a=e.collection_id;a||(a=wm(t,e.type,e.parent_collection_id)),n.prepare(`INSERT INTO auto_collection_rules
777
777
  (id, name, type, pattern, collection_id, priority, enabled, created_at, created_by)
778
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(o,t,e.type,s,a,e.priority??100,e.enabled===!1?0:1,r,e.created_by??"user"),n.prepare("DELETE FROM auto_collection_suggestions WHERE type = ? AND pattern = ?").run(e.type,s);let c=ps(o);return vn(c),Ke(),c}function wi(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(Dn)}function Ri(e,t){let s=f(),n=ps(e);if(!n)throw new Error(`rule not found: ${e}`);let r={name:t.name!==void 0?t.name.trim():n.name,pattern:t.pattern!==void 0?t.pattern.trim():n.pattern,enabled:t.enabled!==void 0?t.enabled:n.enabled,priority:t.priority!==void 0?t.priority:n.priority};if(!r.name)throw new Error("name required");if(!r.pattern)throw new Error("pattern required");s.prepare(`UPDATE auto_collection_rules
778
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(o,t,e.type,s,a,e.priority??100,e.enabled===!1?0:1,r,e.created_by??"user"),n.prepare("DELETE FROM auto_collection_suggestions WHERE type = ? AND pattern = ?").run(e.type,s);let c=ps(o);return Mn(c),Ke(),c}function ki(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(Pn)}function Ai(e,t){let s=f(),n=ps(e);if(!n)throw new Error(`rule not found: ${e}`);let r={name:t.name!==void 0?t.name.trim():n.name,pattern:t.pattern!==void 0?t.pattern.trim():n.pattern,enabled:t.enabled!==void 0?t.enabled:n.enabled,priority:t.priority!==void 0?t.priority:n.priority};if(!r.name)throw new Error("name required");if(!r.pattern)throw new Error("pattern required");s.prepare(`UPDATE auto_collection_rules
779
779
  SET name = ?, pattern = ?, enabled = ?, priority = ?
780
- WHERE id = ?`).run(r.name,r.pattern,r.enabled?1:0,r.priority,e);let o=ps(e);return t.pattern!==void 0&&t.pattern!==n.pattern?(ds(e),o.enabled&&vn(o)):t.enabled!==void 0&&t.enabled!==n.enabled&&(o.enabled?vn(o):ds(e)),Ke(),o}function ki(e){let t=f();if(!ps(e))return{removed:0};let n=ds(e);return t.prepare("DELETE FROM auto_collection_rules WHERE id = ?").run(e),Ke(),n}function gs(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(Sm)}function Ai(e){f().prepare("UPDATE auto_collection_suggestions SET dismissed = 1 WHERE id = ?").run(e),Ke()}function Ni(e){let t=f(),s=t.prepare("SELECT * FROM auto_collection_suggestions WHERE id = ?").get(e);if(!s)throw new Error(`suggestion not found: ${e}`);if(s.dismissed)throw new Error(`suggestion already dismissed: ${e}`);let n=Fn({name:s.suggested_name,type:s.type,pattern:s.pattern,parent_collection_id:s.suggested_parent_collection_id===null?void 0:s.suggested_parent_collection_id,created_by:"suggestion-accepted"});return t.prepare("DELETE FROM auto_collection_suggestions WHERE id = ?").run(e),Ke(),n}function _s(){let e=f(),t=new Date().toISOString(),s=pm(),n=new Set(e.prepare("SELECT decoded_path FROM projects").all().map(c=>c.decoded_path)),r=[...Nm(s,t).filter(c=>!n.has(c.pattern)),...xm(t),...Om(t)];if(e.prepare("DELETE FROM auto_collection_suggestions WHERE type = 'project-id'").run(),n.size>0){let c=Array.from(n).map(()=>"?").join(",");e.prepare(`DELETE FROM auto_collection_suggestions WHERE type = 'cwd-prefix' AND pattern IN (${c})`).run(...Array.from(n))}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 d=`${c.type}:${c.pattern}`;if(a.has(d))continue;let u=e.prepare("SELECT id FROM auto_collection_suggestions WHERE type = ? AND pattern = ?").get(c.type,c.pattern);u?e.prepare(`UPDATE auto_collection_suggestions
780
+ WHERE id = ?`).run(r.name,r.pattern,r.enabled?1:0,r.priority,e);let o=ps(e);return t.pattern!==void 0&&t.pattern!==n.pattern?(ds(e),o.enabled&&Mn(o)):t.enabled!==void 0&&t.enabled!==n.enabled&&(o.enabled?Mn(o):ds(e)),Ke(),o}function Ni(e){let t=f();if(!ps(e))return{removed:0};let n=ds(e);return t.prepare("DELETE FROM auto_collection_rules WHERE id = ?").run(e),Ke(),n}function gs(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(Sm)}function xi(e){f().prepare("UPDATE auto_collection_suggestions SET dismissed = 1 WHERE id = ?").run(e),Ke()}function Oi(e){let t=f(),s=t.prepare("SELECT * FROM auto_collection_suggestions WHERE id = ?").get(e);if(!s)throw new Error(`suggestion not found: ${e}`);if(s.dismissed)throw new Error(`suggestion already dismissed: ${e}`);let n=Un({name:s.suggested_name,type:s.type,pattern:s.pattern,parent_collection_id:s.suggested_parent_collection_id===null?void 0:s.suggested_parent_collection_id,created_by:"suggestion-accepted"});return t.prepare("DELETE FROM auto_collection_suggestions WHERE id = ?").run(e),Ke(),n}function _s(){let e=f(),t=new Date().toISOString(),s=pm(),n=new Set(e.prepare("SELECT decoded_path FROM projects").all().map(c=>c.decoded_path)),r=[...Nm(s,t).filter(c=>!n.has(c.pattern)),...xm(t),...Om(t)];if(e.prepare("DELETE FROM auto_collection_suggestions WHERE type = 'project-id'").run(),n.size>0){let c=Array.from(n).map(()=>"?").join(",");e.prepare(`DELETE FROM auto_collection_suggestions WHERE type = 'cwd-prefix' AND pattern IN (${c})`).run(...Array.from(n))}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 d=`${c.type}:${c.pattern}`;if(a.has(d))continue;let u=e.prepare("SELECT id FROM auto_collection_suggestions WHERE type = ? AND pattern = ?").get(c.type,c.pattern);u?e.prepare(`UPDATE auto_collection_suggestions
781
781
  SET session_count = ?, detected_at = ?, suggested_name = ?, suggested_parent_collection_id = ?
782
782
  WHERE id = ?`).run(c.session_count,t,c.suggested_name,c.suggested_parent_collection_id,u.id):e.prepare(`INSERT INTO auto_collection_suggestions
783
783
  (id, type, pattern, suggested_name, suggested_parent_collection_id, session_count, detected_at, dismissed)
784
- VALUES (?, ?, ?, ?, ?, ?, ?, 0)`).run(jn(),c.type,c.pattern,c.suggested_name,c.suggested_parent_collection_id,c.session_count,t)}return Ke(),gs()}function Nm(e,t){let n=f().prepare("SELECT id, cwd FROM sessions WHERE cwd IS NOT NULL AND cwd != ''").all(),r=new Map;for(let a of n){let c=a.cwd.split("/").filter(Boolean),d="";for(let u of c){if(d=`${d}/${u}`,d===e||d==="/")continue;let g=r.get(d);g||(g=new Set,r.set(d,g)),g.add(a.id)}}let o=[];for(let[a,c]of r.entries()){if(c.size<Si)continue;let d=!1;for(let[u,g]of r.entries())if(u!==a&&u.startsWith(a+"/")&&g.size>=Si){d=!0;break}d||o.push({type:"cwd-prefix",pattern:a,suggested_name:mm(a)||a,suggested_parent_collection_id:null,session_count:c.size,detected_at:t,dismissed:!1})}return o}function xm(e){return f().prepare("SELECT tag, COUNT(*) AS n FROM session_tags GROUP BY tag HAVING n >= ?").all(hm).map(s=>({type:"tag",pattern:s.tag,suggested_name:s.tag,suggested_parent_collection_id:null,session_count:s.n,detected_at:e,dismissed:!1}))}function Om(e){let t=f().prepare(`SELECT id, first_user_message FROM sessions
785
- WHERE first_user_message IS NOT NULL AND first_user_message != ''`).all(),s=new Map;for(let r of t)for(let o of bm){o.lastIndex=0;let a=r.first_user_message.match(o);if(a)for(let c of a){let d=s.get(c);d||(d=new Set,s.set(c,d)),d.add(r.id)}}let n=[];for(let[r,o]of s.entries())o.size<Em||n.push({type:"plan-file",pattern:r,suggested_name:r,suggested_parent_collection_id:null,session_count:o.size,detected_at:e,dismissed:!1});return n}function ms(e){return e.replace(/[\\%_]/g,"\\$&")}function Ke(){try{J(),dm(us)||um(us,{recursive:!0});let e=f(),t=e.prepare("SELECT * FROM auto_collection_rules ORDER BY created_at, id").all(),s=e.prepare("SELECT * FROM auto_collection_suggestions ORDER BY detected_at DESC, id").all();bi(gm,JSON.stringify({schema:"claude-recall.auto-rules.v1",backed_up_at:new Date().toISOString(),rules:t},null,2)),bi(_m,JSON.stringify({schema:"claude-recall.auto-suggestions.v1",backed_up_at:new Date().toISOString(),suggestions:s},null,2))}catch(e){console.error("[auto-collections] backup failed:",e)}}function xi(){let e=f().prepare("SELECT DISTINCT collection_id FROM auto_collection_rules").all();return new Set(e.map(t=>t.collection_id))}H();Z();import{randomUUID as Oi}from"node:crypto";import{writeFileSync as Li,readFileSync as bw,existsSync as Lm,mkdirSync as Cm}from"node:fs";import{join as Pn}from"node:path";var fs=Pn($,"threads"),Im=Pn(fs,"index.json");function Ci(){J(),Lm(fs)||Cm(fs,{recursive:!0})}function Un(e,t,s){return{id:e.id,name:e.name,summary:e.summary,created_at:e.created_at,closed_at:e.closed_at,archived:e.archived===1,session_count:t.session_count,origin_count:t.origin_count,project:s?.project??null,project_count:s?.project_count??0,folder_id:e.folder_id??null}}function Ii(e){let t=new Map;if(e.length===0)return t;let s=f(),n=e.map(()=>"?").join(","),r=s.prepare(`SELECT te.thread_id AS thread_id,
784
+ VALUES (?, ?, ?, ?, ?, ?, ?, 0)`).run(Dn(),c.type,c.pattern,c.suggested_name,c.suggested_parent_collection_id,c.session_count,t)}return Ke(),gs()}function Nm(e,t){let n=f().prepare("SELECT id, cwd FROM sessions WHERE cwd IS NOT NULL AND cwd != ''").all(),r=new Map;for(let a of n){let c=a.cwd.split("/").filter(Boolean),d="";for(let u of c){if(d=`${d}/${u}`,d===e||d==="/")continue;let g=r.get(d);g||(g=new Set,r.set(d,g)),g.add(a.id)}}let o=[];for(let[a,c]of r.entries()){if(c.size<yi)continue;let d=!1;for(let[u,g]of r.entries())if(u!==a&&u.startsWith(a+"/")&&g.size>=yi){d=!0;break}d||o.push({type:"cwd-prefix",pattern:a,suggested_name:mm(a)||a,suggested_parent_collection_id:null,session_count:c.size,detected_at:t,dismissed:!1})}return o}function xm(e){return f().prepare("SELECT tag, COUNT(*) AS n FROM session_tags GROUP BY tag HAVING n >= ?").all(hm).map(s=>({type:"tag",pattern:s.tag,suggested_name:s.tag,suggested_parent_collection_id:null,session_count:s.n,detected_at:e,dismissed:!1}))}function Om(e){let t=f().prepare(`SELECT id, first_user_message FROM sessions
785
+ WHERE first_user_message IS NOT NULL AND first_user_message != ''`).all(),s=new Map;for(let r of t)for(let o of bm){o.lastIndex=0;let a=r.first_user_message.match(o);if(a)for(let c of a){let d=s.get(c);d||(d=new Set,s.set(c,d)),d.add(r.id)}}let n=[];for(let[r,o]of s.entries())o.size<Em||n.push({type:"plan-file",pattern:r,suggested_name:r,suggested_parent_collection_id:null,session_count:o.size,detected_at:e,dismissed:!1});return n}function ms(e){return e.replace(/[\\%_]/g,"\\$&")}function Ke(){try{J(),dm(us)||um(us,{recursive:!0});let e=f(),t=e.prepare("SELECT * FROM auto_collection_rules ORDER BY created_at, id").all(),s=e.prepare("SELECT * FROM auto_collection_suggestions ORDER BY detected_at DESC, id").all();Ti(gm,JSON.stringify({schema:"claude-recall.auto-rules.v1",backed_up_at:new Date().toISOString(),rules:t},null,2)),Ti(_m,JSON.stringify({schema:"claude-recall.auto-suggestions.v1",backed_up_at:new Date().toISOString(),suggestions:s},null,2))}catch(e){console.error("[auto-collections] backup failed:",e)}}function Li(){let e=f().prepare("SELECT DISTINCT collection_id FROM auto_collection_rules").all();return new Set(e.map(t=>t.collection_id))}H();Z();import{randomUUID as Ci}from"node:crypto";import{writeFileSync as Ii,readFileSync as bw,existsSync as Lm,mkdirSync as Cm}from"node:fs";import{join as $n}from"node:path";var fs=$n($,"threads"),Im=$n(fs,"index.json");function vi(){J(),Lm(fs)||Cm(fs,{recursive:!0})}function Bn(e,t,s){return{id:e.id,name:e.name,summary:e.summary,created_at:e.created_at,closed_at:e.closed_at,archived:e.archived===1,session_count:t.session_count,origin_count:t.origin_count,project:s?.project??null,project_count:s?.project_count??0,folder_id:e.folder_id??null}}function ji(e){let t=new Map;if(e.length===0)return t;let s=f(),n=e.map(()=>"?").join(","),r=s.prepare(`SELECT te.thread_id AS thread_id,
786
786
  p.name AS project,
787
787
  COUNT(*) AS n,
788
788
  SUM(CASE WHEN te.role = 'origin' THEN 1 ELSE 0 END) AS origin_n
@@ -790,7 +790,7 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
790
790
  LEFT JOIN sessions s ON s.id = te.session_id
791
791
  LEFT JOIN projects p ON p.id = s.project_id
792
792
  WHERE te.thread_id IN (${n})
793
- 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 d=c.filter(h=>h.project!==null),u=d.length,g=null;d.length>0&&(g=[...d].sort((b,S)=>S.n-b.n||S.origin_n-b.origin_n||(b.project??"").localeCompare(S.project??""))[0].project),t.set(a,{project:g,project_count:u})}return t}function vi(e){let t=e.auto_title_source;return{thread_id:e.thread_id,session_id:e.session_id,parent_session_id:e.parent_session_id,role:e.role,confidence:e.confidence,source:e.source,added_at:e.added_at,alias:e.alias,auto_title:e.auto_title,auto_title_source:t==="agent"||t==="heuristic"?t:null,alias_source:e.alias?"manual":null,first_user_message:e.first_user_message,project:e.project}}function ji(e){let s=f().prepare(`SELECT NULLIF(sa.alias, '') AS alias,
793
+ 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 d=c.filter(h=>h.project!==null),u=d.length,g=null;d.length>0&&(g=[...d].sort((b,S)=>S.n-b.n||S.origin_n-b.origin_n||(b.project??"").localeCompare(S.project??""))[0].project),t.set(a,{project:g,project_count:u})}return t}function Mi(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 Di(e){let s=f().prepare(`SELECT NULLIF(sa.alias, '') AS alias,
794
794
  s.auto_title AS auto_title,
795
795
  s.auto_title_source AS auto_title_source,
796
796
  s.first_user_message AS first_user_message,
@@ -798,11 +798,11 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
798
798
  FROM (SELECT ? AS sid) q
799
799
  LEFT JOIN sessions s ON s.id = q.sid
800
800
  LEFT JOIN session_aliases sa ON sa.session_id = q.sid
801
- LEFT JOIN projects p ON p.id = s.project_id`).get(e),n=s?.auto_title_source??null;return{alias:s?.alias??null,auto_title:s?.auto_title??null,auto_title_source:n==="agent"||n==="heuristic"?n:null,first_user_message:s?.first_user_message??null,project:s?.project??null}}function $n(e){let s=f().prepare(`SELECT
801
+ LEFT JOIN projects p ON p.id = s.project_id`).get(e),n=s?.auto_title_source??null;return{alias:s?.alias??null,auto_title:s?.auto_title??null,auto_title_source:n==="agent"||n==="heuristic"?n:null,first_user_message:s?.first_user_message??null,project:s?.project??null}}function Hn(e){let s=f().prepare(`SELECT
802
802
  COUNT(*) AS session_count,
803
803
  SUM(CASE WHEN role = 'origin' THEN 1 ELSE 0 END) AS origin_count
804
- FROM thread_edges WHERE thread_id = ?`).get(e);return{session_count:s?.session_count??0,origin_count:s?.origin_count??0}}function fe(e){let t=te(e);t&&(Ci(),Li(Pn(fs,`${e}.json`),JSON.stringify(t,null,2)),Mi())}function Mi(){Ci();let e=Bn({includeArchived:!0});Li(Im,JSON.stringify({threads:e},null,2))}function hs(e){let t=e.name.trim();if(!t)throw new Error("thread name cannot be empty");let s=f(),n=Oi(),r=new Date().toISOString();s.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, ?, ?)").run(n,t,e.summary?.trim()||null,r),e.originSessionId&&s.prepare(`INSERT INTO thread_edges (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
805
- VALUES (?, ?, NULL, 'origin', 1.0, 'manual', ?)`).run(n,e.originSessionId,r),fe(n);let o=te(n);if(!o)throw new Error("thread creation succeeded but read-back failed");return o}function Bn(e={}){let t=f(),s=e.includeArchived?"":"WHERE archived = 0",n=t.prepare(`SELECT * FROM threads ${s} ORDER BY created_at DESC`).all(),r=Ii(n.map(o=>o.id));return n.map(o=>Un(o,$n(o.id),r.get(o.id)))}function te(e){let t=f(),s=t.prepare("SELECT * FROM threads WHERE id = ?").get(e);if(!s)return null;let n=t.prepare(`SELECT e.*,
804
+ FROM thread_edges WHERE thread_id = ?`).get(e);return{session_count:s?.session_count??0,origin_count:s?.origin_count??0}}function fe(e){let t=te(e);t&&(vi(),Ii($n(fs,`${e}.json`),JSON.stringify(t,null,2)),Fi())}function Fi(){vi();let e=Wn({includeArchived:!0});Ii(Im,JSON.stringify({threads:e},null,2))}function hs(e){let t=e.name.trim();if(!t)throw new Error("thread name cannot be empty");let s=f(),n=Ci(),r=new Date().toISOString();s.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, ?, ?)").run(n,t,e.summary?.trim()||null,r),e.originSessionId&&s.prepare(`INSERT INTO thread_edges (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
805
+ VALUES (?, ?, NULL, 'origin', 1.0, 'manual', ?)`).run(n,e.originSessionId,r),fe(n);let o=te(n);if(!o)throw new Error("thread creation succeeded but read-back failed");return o}function Wn(e={}){let t=f(),s=e.includeArchived?"":"WHERE archived = 0",n=t.prepare(`SELECT * FROM threads ${s} ORDER BY created_at DESC`).all(),r=ji(n.map(o=>o.id));return n.map(o=>Bn(o,Hn(o.id),r.get(o.id)))}function te(e){let t=f(),s=t.prepare("SELECT * FROM threads WHERE id = ?").get(e);if(!s)return null;let n=t.prepare(`SELECT e.*,
806
806
  NULLIF(sa.alias, '') AS alias,
807
807
  s.auto_title AS auto_title,
808
808
  s.auto_title_source AS auto_title_source,
@@ -813,10 +813,10 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
813
813
  LEFT JOIN session_aliases sa ON sa.session_id = e.session_id
814
814
  LEFT JOIN projects p ON p.id = s.project_id
815
815
  WHERE e.thread_id = ?
816
- ORDER BY e.added_at ASC`).all(e).map(vi),r=Ii([e]).get(e);return{...Un(s,$n(s.id),r),edges:n}}function Di(e){return f().prepare(`SELECT t.* FROM threads t
816
+ ORDER BY e.added_at ASC`).all(e).map(Mi),r=ji([e]).get(e);return{...Bn(s,Hn(s.id),r),edges:n}}function Pi(e){return f().prepare(`SELECT t.* FROM threads t
817
817
  JOIN thread_edges e ON e.thread_id = t.id
818
818
  WHERE e.session_id = ? AND t.archived = 0
819
- ORDER BY t.created_at DESC`).all(e).map(n=>Un(n,$n(n.id)))}function Es(e){let t=f();if(!t.prepare("SELECT * FROM threads WHERE id = ?").get(e.threadId))throw new Error(`thread ${e.threadId} not found`);let n=new Date().toISOString(),r=e.parentSessionId??null,o=e.role??(r?"child":"origin"),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
819
+ ORDER BY t.created_at DESC`).all(e).map(n=>Bn(n,Hn(n.id)))}function Es(e){let t=f();if(!t.prepare("SELECT * FROM threads WHERE id = ?").get(e.threadId))throw new Error(`thread ${e.threadId} not found`);let n=new Date().toISOString(),r=e.parentSessionId??null,o=e.role??(r?"child":"origin"),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
820
820
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
821
821
  VALUES (?, ?, ?, ?, ?, ?, ?)
822
822
  ON CONFLICT(thread_id, session_id) DO UPDATE SET
@@ -824,22 +824,22 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
824
824
  role = excluded.role,
825
825
  confidence = excluded.confidence,
826
826
  source = excluded.source,
827
- added_at = excluded.added_at`).run(e.threadId,e.sessionId,r,o,a,c,n),fe(e.threadId);let d=ji(e.sessionId);return{thread_id:e.threadId,session_id:e.sessionId,parent_session_id:r,role:o,confidence:a,source:c,added_at:n,alias:d.alias,auto_title:d.auto_title,auto_title_source:d.auto_title_source,alias_source:d.alias?"manual":null,first_user_message:d.first_user_message,project:d.project}}function Fi(e,t){let n=f().prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e,t);return n.changes>0&&fe(e),{removed:n.changes}}function xt(e,t,s){let n=f(),r=n.prepare("SELECT * FROM thread_edges WHERE thread_id = ? AND session_id = ?").get(e,t);if(!r)throw new Error("edge not found; add the session first");if(s!==null){if(s===t)throw new Error("cycle detected: session cannot be its own parent");let c=n.prepare("SELECT parent_session_id FROM thread_edges WHERE thread_id = ? AND session_id = ?"),d=s,u=new Set;for(;d!==null;){if(d===t)throw new Error(`cycle detected: setting parent of ${t} to ${s} would create a loop`);if(u.has(d))break;u.add(d),d=c.get(e,d)?.parent_session_id??null}}let o=s?"child":"origin";n.prepare(`UPDATE thread_edges
827
+ added_at = excluded.added_at`).run(e.threadId,e.sessionId,r,o,a,c,n),fe(e.threadId);let d=Di(e.sessionId);return{thread_id:e.threadId,session_id:e.sessionId,parent_session_id:r,role:o,confidence:a,source:c,added_at:n,alias:d.alias,auto_title:d.auto_title,auto_title_source:d.auto_title_source,alias_source:d.alias?"manual":null,first_user_message:d.first_user_message,project:d.project}}function Ui(e,t){let n=f().prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e,t);return n.changes>0&&fe(e),{removed:n.changes}}function xt(e,t,s){let n=f(),r=n.prepare("SELECT * FROM thread_edges WHERE thread_id = ? AND session_id = ?").get(e,t);if(!r)throw new Error("edge not found; add the session first");if(s!==null){if(s===t)throw new Error("cycle detected: session cannot be its own parent");let c=n.prepare("SELECT parent_session_id FROM thread_edges WHERE thread_id = ? AND session_id = ?"),d=s,u=new Set;for(;d!==null;){if(d===t)throw new Error(`cycle detected: setting parent of ${t} to ${s} would create a loop`);if(u.has(d))break;u.add(d),d=c.get(e,d)?.parent_session_id??null}}let o=s?"child":"origin";n.prepare(`UPDATE thread_edges
828
828
  SET parent_session_id = ?, role = ?, added_at = ?
829
- WHERE thread_id = ? AND session_id = ?`).run(s,o,new Date().toISOString(),e,t),fe(e);let a=ji(t);return vi({...r,parent_session_id:s,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 Pi(e,t){let s=t.trim();if(!s)throw new Error("name cannot be empty");f().prepare("UPDATE threads SET name = ? WHERE id = ?").run(s,e),fe(e);let r=te(e);if(!r)throw new Error(`thread ${e} not found`);return r}function Ui(e){f().prepare("UPDATE threads SET closed_at = ? WHERE id = ?").run(new Date().toISOString(),e),fe(e);let s=te(e);if(!s)throw new Error(`thread ${e} not found`);return s}function $i(e){f().prepare("UPDATE threads SET closed_at = NULL WHERE id = ?").run(e),fe(e);let s=te(e);if(!s)throw new Error(`thread ${e} not found`);return s}function Bi(e){f().prepare("UPDATE threads SET archived = 1 WHERE id = ?").run(e),fe(e);let s=te(e);if(!s)throw new Error(`thread ${e} not found`);return s}function Hi(e,t){if(e===t)throw new Error("cannot merge a thread into itself");let s=f(),n=new Date().toISOString();s.transaction(()=>{let o=s.prepare("SELECT * FROM thread_edges WHERE thread_id = ?").all(e);for(let a of o)s.prepare(`INSERT INTO thread_edges
829
+ WHERE thread_id = ? AND session_id = ?`).run(s,o,new Date().toISOString(),e,t),fe(e);let a=Di(t);return Mi({...r,parent_session_id:s,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 $i(e,t){let s=t.trim();if(!s)throw new Error("name cannot be empty");f().prepare("UPDATE threads SET name = ? WHERE id = ?").run(s,e),fe(e);let r=te(e);if(!r)throw new Error(`thread ${e} not found`);return r}function Bi(e){f().prepare("UPDATE threads SET closed_at = ? WHERE id = ?").run(new Date().toISOString(),e),fe(e);let s=te(e);if(!s)throw new Error(`thread ${e} not found`);return s}function Hi(e){f().prepare("UPDATE threads SET closed_at = NULL WHERE id = ?").run(e),fe(e);let s=te(e);if(!s)throw new Error(`thread ${e} not found`);return s}function Wi(e){f().prepare("UPDATE threads SET archived = 1 WHERE id = ?").run(e),fe(e);let s=te(e);if(!s)throw new Error(`thread ${e} not found`);return s}function qi(e,t){if(e===t)throw new Error("cannot merge a thread into itself");let s=f(),n=new Date().toISOString();s.transaction(()=>{let o=s.prepare("SELECT * FROM thread_edges WHERE thread_id = ?").all(e);for(let a of o)s.prepare(`INSERT INTO thread_edges
830
830
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
831
831
  VALUES (?, ?, ?, ?, ?, ?, ?)
832
832
  ON CONFLICT(thread_id, session_id) DO UPDATE SET
833
833
  parent_session_id = COALESCE(thread_edges.parent_session_id, excluded.parent_session_id),
834
834
  role = CASE WHEN thread_edges.role = 'origin' OR excluded.role = 'origin' THEN 'origin' ELSE 'child' END,
835
835
  confidence = MAX(thread_edges.confidence, excluded.confidence),
836
- source = thread_edges.source`).run(t,a.session_id,a.parent_session_id,a.role,a.confidence,a.source,n);s.prepare("DELETE FROM threads WHERE id = ?").run(e)})(),fe(t),Mi();let r=te(t);if(!r)throw new Error("merge destination disappeared");return r}function Wi(e){if(e.sessionIds.length===0)throw new Error("no sessions to split off");let t=f(),s=new Date().toISOString(),n=Oi();t.transaction(()=>{t.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, NULL, ?)").run(n,e.newThreadName.trim(),s);for(let o of e.sessionIds){let a=t.prepare("SELECT * FROM thread_edges WHERE thread_id = ? AND session_id = ?").get(e.threadId,o);a&&(t.prepare(`INSERT INTO thread_edges
836
+ source = thread_edges.source`).run(t,a.session_id,a.parent_session_id,a.role,a.confidence,a.source,n);s.prepare("DELETE FROM threads WHERE id = ?").run(e)})(),fe(t),Fi();let r=te(t);if(!r)throw new Error("merge destination disappeared");return r}function Ji(e){if(e.sessionIds.length===0)throw new Error("no sessions to split off");let t=f(),s=new Date().toISOString(),n=Ci();t.transaction(()=>{t.prepare("INSERT INTO threads (id, name, summary, created_at) VALUES (?, ?, NULL, ?)").run(n,e.newThreadName.trim(),s);for(let o of e.sessionIds){let a=t.prepare("SELECT * FROM thread_edges WHERE thread_id = ? AND session_id = ?").get(e.threadId,o);a&&(t.prepare(`INSERT INTO thread_edges
837
837
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
838
- VALUES (?, ?, ?, ?, ?, ?, ?)`).run(n,o,a.parent_session_id,a.role,a.confidence,a.source,s),t.prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e.threadId,o))}})(),fe(e.threadId),fe(n);let r=te(n);if(!r)throw new Error("split destination disappeared");return r}H();import{execFile as Gm}from"node:child_process";import{promisify as Ym}from"node:util";import{readlink as Km,readFile as Yi}from"node:fs/promises";import{platform as ws}from"node:os";import{readFileSync as vm,statSync as jm}from"node:fs";var Mm=200*1024*1024,Ss=.7,Ts=.5,Xi=Ts,Dm=[{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"}],Fm=["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 qi(e){if(!e)return null;if(e.startsWith("/")){let s=e.split(" \xB7 ");if(s.length>1)return s[1].trim().toLowerCase()}let t=e.split(" \xB7 ");return t.length>1?t[t.length-1].trim().toLowerCase():null}function Pm(e,t){let s=t-e;if(s<0)return{weight:0,label:null};for(let n of Dm)if(s<=n.maxGapMs)return{weight:n.weight,label:n.label};return{weight:0,label:null}}function Um(e){if(e.length===0)return{weight:0,matched:null,matchedIndex:-1};let t=[.4,.35,.3,.25,.2,.15,.1],s=Math.min(e.length,t.length);for(let n=0;n<s;n++){let r=e[n];if(!r)continue;let o=r.toLowerCase();for(let a of Fm)if(o.includes(a))return{weight:t[n],matched:a,matchedIndex:n}}return{weight:0,matched:null,matchedIndex:-1}}function Hn(e,t){if(!e||!t||e.length!==t.length)return 0;let s=0;for(let n=0;n<e.length;n++)s+=e[n]*t[n];return s<-1?-1:s>1?1:s}function $m(e,t){if(e.length===0||t.length===0)return 0;let s=0;for(let n of e)for(let r of t){let o=Hn(n,r);o>s&&(s=o)}return s}function Bm(e,t){let s=Hn(e.mean_embedding,t.mean_embedding),n=Hn(e.tail_pool,t.head_pool),r=$m(e.sample_chunks,t.sample_chunks),o=0,a=null;if(s>o&&(o=s,a="mean"),n>o&&(o=n,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 Hm(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 Wm(e,t){if(e.size===0||t.size===0)return{weight:0,count:0};let s=0;for(let r of t)e.has(r)&&s++;return s===0?{weight:0,count:0}:{weight:Math.min(.4,s*.1),count:s}}function qm(e,t){let s=qi(e),n=qi(t);return s&&n&&s===n?{weight:.1,brand:s}:{weight:0,brand:null}}function Ji(e){return e.replace(/\s+/g," ").trim().toLowerCase()}function Jm(e,t){let s=0,n=null,r=!1;if(e.authored_paths.size>0){let o=t.recent_user_messages.slice(0,3).join(`
839
- `).toLowerCase();for(let a of e.authored_paths){let c=a.toLowerCase();if(t.touched_files.has(a)||o.includes(c)){s+=.5,n=a;break}}}if(e.authored_content.length>0&&t.recent_user_messages[0]){let o=Ji(t.recent_user_messages[0]);if(o.length>=200)for(let a of e.authored_content){let c=Ji(a);if(c.length<200)continue;let d=Math.min(c.length,240),u=c.slice(0,d);if(o.includes(u)){s+=.4,r=!0;break}}}return{weight:Math.min(.6,s),pathMatch:n,contentMatch:r}}function Xm(e,t,s=Xi){if(t.started_at_ms<=e.started_at_ms)return null;let n=e.ended_at_ms??e.started_at_ms;if(t.started_at_ms<n)return null;let r=Pm(n,t.started_at_ms),o=t.recent_user_messages.length>0?t.recent_user_messages:t.first_user_message?[t.first_user_message]:[],a=Um(o),c=Wm(e.touched_files,t.touched_files),d=qm(e.auto_title,t.auto_title),u=Bm(e,t),g=Hm(e,t),h=Jm(e,t),b=r.weight+a.weight+c.weight+d.weight+u.weight+g.weight+h.weight;if(b<s)return null;let S=[];if(r.label&&S.push(`temporal ${r.label} (+${r.weight})`),a.matched){let y=a.matchedIndex===0?"opening message":`message #${a.matchedIndex+1}`;S.push(`continuation phrase "${a.matched}" in ${y} (+${a.weight})`)}if(c.count>0&&S.push(`${c.count} file${c.count===1?"":"s"} overlap (+${c.weight.toFixed(1)})`),d.brand&&S.push(`shared brand "${d.brand}" (+${d.weight})`),u.weight>0&&u.mode&&S.push(`semantic ${u.mode==="asymmetric"?"tail\u2192head":u.mode==="max_pool"?"best-chunk":"mean"} ${u.cosine.toFixed(2)} (+${u.weight.toFixed(2)})`),g.same&&S.push(`same cluster (+${g.weight})`),h.weight>0){let y=[];h.pathMatch&&y.push(`opened authored path "${h.pathMatch.split("/").pop()}"`),h.contentMatch&&y.push("verbatim-paste of authored content"),S.push(`doc-authorship: ${y.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:d.weight,semantic:u.weight,cluster:g.weight,doc_authorship:h.weight},reasons:S}}function ze(e,t=Xi){let s=[];for(let n=0;n<e.length;n++){let r=e[n],o=null;for(let a=0;a<n;a++){let c=e[a],d=Xm(c,r,t);d&&(!o||d.confidence>o.confidence)&&(o=d)}o&&s.push(o)}return s}function Gi(e,t){let s=new Map,n=c=>{let d=c;for(;s.get(d)!==d;)d=s.get(d);let u=c;for(;s.get(u)!==d;){let g=s.get(u);s.set(u,d),u=g}return d},r=(c,d)=>{let u=n(c),g=n(d);u!==g&&s.set(u,g)};for(let c of e)s.has(c.parent_id)||s.set(c.parent_id,c.parent_id),s.has(c.child_id)||s.set(c.child_id,c.child_id),r(c.parent_id,c.child_id);let o=new Map;for(let c of s.keys()){let d=n(c),u=o.get(d);u||(u=[],o.set(d,u)),u.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((d,u)=>(a.get(d)??0)-(a.get(u)??0)),{rootId:c[0],sessionIds:c}))}function ys(e,t={}){let s=t.maxUserMessages??5,n=t.userMessageMaxLen??2e3,r=new Set,o=[],a=new Set,c=[],d;try{if(jm(e).size>Mm)return{touched_files:r,recent_user_messages:o,authored_paths:a,authored_content:c};d=vm(e,"utf8")}catch{return{touched_files:r,recent_user_messages:o,authored_paths:a,authored_content:c}}let u=0;for(;u<d.length;){let g=d.indexOf(`
840
- `,u),h=g===-1?d.length:g,b=d.slice(u,h);if(u=g===-1?d.length:g+1,!b.trim())continue;let S;try{S=JSON.parse(b)}catch{continue}let y=S;if(y.type==="user"&&y.message?.role==="user"&&typeof y.message.content=="string"&&o.length<s){let w=y.message.content.trim();w&&o.push(w.length>n?w.slice(0,n):w)}let k=y.message?.content;if(Array.isArray(k))for(let w of k){if(!w||typeof w!="object")continue;let D=w;if(D.type!=="tool_use")continue;let L=D.input??{},X=typeof L.file_path=="string"?L.file_path:null;if(X){let M=bs(X);M&&r.add(M)}if((D.name==="Write"||D.name==="Edit"||D.name==="MultiEdit")&&X){let M=bs(X);M&&a.add(M);let B=typeof L.content=="string"?L.content:typeof L.new_string=="string"?L.new_string:null;B&&B.length>=200&&c.push(B.length>4096?B.slice(0,4096):B)}if(D.name==="Bash"&&typeof L.command=="string")for(let M of L.command.matchAll(/(?:^|[\s'"`(=])((?:\.\.?\/|\/|src\/|test\/|docs\/|site\/)[A-Za-z0-9_./-]+)/g)){let B=bs(M[1]);B&&r.add(B)}if((D.name==="Glob"||D.name==="Grep")&&typeof L.pattern=="string"){let M=bs(L.pattern);M&&!M.includes("*")&&r.add(M)}}}return{touched_files:r,recent_user_messages:o,authored_paths:a,authored_content:c}}function bs(e){let t=e.trim().replace(/^['"]|['"]$/g,"");return!t||t.length<4||/[<>|;&\$`]/.test(t)?null:t}var qn=Ym(Gm),zm=6,Ki="Active ",zi=" sessions \u2014 ",Vm=6e4;async function Zm(){if(ws()==="win32")return[];for(let t of["/bin/ps","/usr/bin/ps"])try{let{stdout:s}=await qn(t,["-eo","pid=,comm="],{timeout:2e3}),n=[];for(let r of s.split(`
841
- `)){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)&&n.push(a)}return n}catch{continue}return[]}async function Qm(e){let t=ws();if(t==="linux")try{return(await Km(`/proc/${e}/cwd`)).replace(/\/+$/,"")}catch{return null}if(t==="darwin"||t==="freebsd"||t==="openbsd")for(let s of["/usr/sbin/lsof","/usr/bin/lsof"])try{let{stdout:n}=await qn(s,["-a","-p",String(e),"-d","cwd","-Fn"],{timeout:2e3});for(let r of n.split(`
842
- `))if(r.startsWith("n"))return r.slice(1).replace(/\/+$/,"");return null}catch{continue}return null}async function eg(e){let t=ws();if(t==="linux")try{let s=await Yi(`/proc/${e}/stat`,"utf8"),n=s.lastIndexOf(")");if(n===-1)return null;let r=s.slice(n+1).trim().split(/\s+/),o=Number(r[19]);if(!Number.isFinite(o))return null;let a=await Yi("/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 s of["/bin/ps","/usr/bin/ps"])try{let{stdout:n}=await qn(s,["-o","lstart=","-p",String(e)],{timeout:2e3}),r=Date.parse(n.trim());return Number.isFinite(r)?r:null}catch{continue}return null}async function tg(e,t){let s=await Zm();if(s.length===0)return null;let n=e.replace(/\/+$/,""),r=[];for(let a of s){let c=await Qm(a);if(c&&(c===n||c.startsWith(n+"/"))){let d=await eg(a);r.push({pid:a,startMs:d})}}if(r.length===0)return new Set;let o=new Set;for(let{startMs:a}of r){if(a==null)continue;let c=null,d=Vm;for(let u of t){if(o.has(u.session_id)||!u.started_at)continue;let g=Date.parse(u.started_at);if(!Number.isFinite(g))continue;let h=Math.abs(g-a);h<d&&(d=h,c=u)}c&&o.add(c.session_id)}return o}function sg(e){let s=f().prepare("SELECT id, name, decoded_path FROM projects WHERE id = ? LIMIT 1").get(e);if(!s)throw new Error(`project ${e} not found`);return s}function ng(e,t){let s=f(),n=`${Ki}${t}${zi}%`,r=s.prepare(`SELECT t.id
838
+ VALUES (?, ?, ?, ?, ?, ?, ?)`).run(n,o,a.parent_session_id,a.role,a.confidence,a.source,s),t.prepare("DELETE FROM thread_edges WHERE thread_id = ? AND session_id = ?").run(e.threadId,o))}})(),fe(e.threadId),fe(n);let r=te(n);if(!r)throw new Error("split destination disappeared");return r}H();import{execFile as Gm}from"node:child_process";import{promisify as Ym}from"node:util";import{readlink as Km,readFile as zi}from"node:fs/promises";import{platform as ws}from"node:os";import{readFileSync as vm,statSync as jm}from"node:fs";var Mm=200*1024*1024,Ss=.7,Ts=.5,Yi=Ts,Dm=[{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"}],Fm=["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 Xi(e){if(!e)return null;if(e.startsWith("/")){let s=e.split(" \xB7 ");if(s.length>1)return s[1].trim().toLowerCase()}let t=e.split(" \xB7 ");return t.length>1?t[t.length-1].trim().toLowerCase():null}function Pm(e,t){let s=t-e;if(s<0)return{weight:0,label:null};for(let n of Dm)if(s<=n.maxGapMs)return{weight:n.weight,label:n.label};return{weight:0,label:null}}function Um(e){if(e.length===0)return{weight:0,matched:null,matchedIndex:-1};let t=[.4,.35,.3,.25,.2,.15,.1],s=Math.min(e.length,t.length);for(let n=0;n<s;n++){let r=e[n];if(!r)continue;let o=r.toLowerCase();for(let a of Fm)if(o.includes(a))return{weight:t[n],matched:a,matchedIndex:n}}return{weight:0,matched:null,matchedIndex:-1}}function qn(e,t){if(!e||!t||e.length!==t.length)return 0;let s=0;for(let n=0;n<e.length;n++)s+=e[n]*t[n];return s<-1?-1:s>1?1:s}function $m(e,t){if(e.length===0||t.length===0)return 0;let s=0;for(let n of e)for(let r of t){let o=qn(n,r);o>s&&(s=o)}return s}function Bm(e,t){let s=qn(e.mean_embedding,t.mean_embedding),n=qn(e.tail_pool,t.head_pool),r=$m(e.sample_chunks,t.sample_chunks),o=0,a=null;if(s>o&&(o=s,a="mean"),n>o&&(o=n,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 Hm(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 Wm(e,t){if(e.size===0||t.size===0)return{weight:0,count:0};let s=0;for(let r of t)e.has(r)&&s++;return s===0?{weight:0,count:0}:{weight:Math.min(.4,s*.1),count:s}}function qm(e,t){let s=Xi(e),n=Xi(t);return s&&n&&s===n?{weight:.1,brand:s}:{weight:0,brand:null}}function Gi(e){return e.replace(/\s+/g," ").trim().toLowerCase()}function Jm(e,t){let s=0,n=null,r=!1;if(e.authored_paths.size>0){let o=t.recent_user_messages.slice(0,3).join(`
839
+ `).toLowerCase();for(let a of e.authored_paths){let c=a.toLowerCase();if(t.touched_files.has(a)||o.includes(c)){s+=.5,n=a;break}}}if(e.authored_content.length>0&&t.recent_user_messages[0]){let o=Gi(t.recent_user_messages[0]);if(o.length>=200)for(let a of e.authored_content){let c=Gi(a);if(c.length<200)continue;let d=Math.min(c.length,240),u=c.slice(0,d);if(o.includes(u)){s+=.4,r=!0;break}}}return{weight:Math.min(.6,s),pathMatch:n,contentMatch:r}}function Xm(e,t,s=Yi){if(t.started_at_ms<=e.started_at_ms)return null;let n=e.ended_at_ms??e.started_at_ms;if(t.started_at_ms<n)return null;let r=Pm(n,t.started_at_ms),o=t.recent_user_messages.length>0?t.recent_user_messages:t.first_user_message?[t.first_user_message]:[],a=Um(o),c=Wm(e.touched_files,t.touched_files),d=qm(e.auto_title,t.auto_title),u=Bm(e,t),g=Hm(e,t),h=Jm(e,t),b=r.weight+a.weight+c.weight+d.weight+u.weight+g.weight+h.weight;if(b<s)return null;let S=[];if(r.label&&S.push(`temporal ${r.label} (+${r.weight})`),a.matched){let y=a.matchedIndex===0?"opening message":`message #${a.matchedIndex+1}`;S.push(`continuation phrase "${a.matched}" in ${y} (+${a.weight})`)}if(c.count>0&&S.push(`${c.count} file${c.count===1?"":"s"} overlap (+${c.weight.toFixed(1)})`),d.brand&&S.push(`shared brand "${d.brand}" (+${d.weight})`),u.weight>0&&u.mode&&S.push(`semantic ${u.mode==="asymmetric"?"tail\u2192head":u.mode==="max_pool"?"best-chunk":"mean"} ${u.cosine.toFixed(2)} (+${u.weight.toFixed(2)})`),g.same&&S.push(`same cluster (+${g.weight})`),h.weight>0){let y=[];h.pathMatch&&y.push(`opened authored path "${h.pathMatch.split("/").pop()}"`),h.contentMatch&&y.push("verbatim-paste of authored content"),S.push(`doc-authorship: ${y.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:d.weight,semantic:u.weight,cluster:g.weight,doc_authorship:h.weight},reasons:S}}function ze(e,t=Yi){let s=[];for(let n=0;n<e.length;n++){let r=e[n],o=null;for(let a=0;a<n;a++){let c=e[a],d=Xm(c,r,t);d&&(!o||d.confidence>o.confidence)&&(o=d)}o&&s.push(o)}return s}function Ki(e,t){let s=new Map,n=c=>{let d=c;for(;s.get(d)!==d;)d=s.get(d);let u=c;for(;s.get(u)!==d;){let g=s.get(u);s.set(u,d),u=g}return d},r=(c,d)=>{let u=n(c),g=n(d);u!==g&&s.set(u,g)};for(let c of e)s.has(c.parent_id)||s.set(c.parent_id,c.parent_id),s.has(c.child_id)||s.set(c.child_id,c.child_id),r(c.parent_id,c.child_id);let o=new Map;for(let c of s.keys()){let d=n(c),u=o.get(d);u||(u=[],o.set(d,u)),u.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((d,u)=>(a.get(d)??0)-(a.get(u)??0)),{rootId:c[0],sessionIds:c}))}function ys(e,t={}){let s=t.maxUserMessages??5,n=t.userMessageMaxLen??2e3,r=new Set,o=[],a=new Set,c=[],d;try{if(jm(e).size>Mm)return{touched_files:r,recent_user_messages:o,authored_paths:a,authored_content:c};d=vm(e,"utf8")}catch{return{touched_files:r,recent_user_messages:o,authored_paths:a,authored_content:c}}let u=0;for(;u<d.length;){let g=d.indexOf(`
840
+ `,u),h=g===-1?d.length:g,b=d.slice(u,h);if(u=g===-1?d.length:g+1,!b.trim())continue;let S;try{S=JSON.parse(b)}catch{continue}let y=S;if(y.type==="user"&&y.message?.role==="user"&&typeof y.message.content=="string"&&o.length<s){let w=y.message.content.trim();w&&o.push(w.length>n?w.slice(0,n):w)}let k=y.message?.content;if(Array.isArray(k))for(let w of k){if(!w||typeof w!="object")continue;let D=w;if(D.type!=="tool_use")continue;let L=D.input??{},X=typeof L.file_path=="string"?L.file_path:null;if(X){let M=bs(X);M&&r.add(M)}if((D.name==="Write"||D.name==="Edit"||D.name==="MultiEdit")&&X){let M=bs(X);M&&a.add(M);let B=typeof L.content=="string"?L.content:typeof L.new_string=="string"?L.new_string:null;B&&B.length>=200&&c.push(B.length>4096?B.slice(0,4096):B)}if(D.name==="Bash"&&typeof L.command=="string")for(let M of L.command.matchAll(/(?:^|[\s'"`(=])((?:\.\.?\/|\/|src\/|test\/|docs\/|site\/)[A-Za-z0-9_./-]+)/g)){let B=bs(M[1]);B&&r.add(B)}if((D.name==="Glob"||D.name==="Grep")&&typeof L.pattern=="string"){let M=bs(L.pattern);M&&!M.includes("*")&&r.add(M)}}}return{touched_files:r,recent_user_messages:o,authored_paths:a,authored_content:c}}function bs(e){let t=e.trim().replace(/^['"]|['"]$/g,"");return!t||t.length<4||/[<>|;&\$`]/.test(t)?null:t}var Xn=Ym(Gm),zm=6,Vi="Active ",Zi=" sessions \u2014 ",Vm=6e4;async function Zm(){if(ws()==="win32")return[];for(let t of["/bin/ps","/usr/bin/ps"])try{let{stdout:s}=await Xn(t,["-eo","pid=,comm="],{timeout:2e3}),n=[];for(let r of s.split(`
841
+ `)){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)&&n.push(a)}return n}catch{continue}return[]}async function Qm(e){let t=ws();if(t==="linux")try{return(await Km(`/proc/${e}/cwd`)).replace(/\/+$/,"")}catch{return null}if(t==="darwin"||t==="freebsd"||t==="openbsd")for(let s of["/usr/sbin/lsof","/usr/bin/lsof"])try{let{stdout:n}=await Xn(s,["-a","-p",String(e),"-d","cwd","-Fn"],{timeout:2e3});for(let r of n.split(`
842
+ `))if(r.startsWith("n"))return r.slice(1).replace(/\/+$/,"");return null}catch{continue}return null}async function eg(e){let t=ws();if(t==="linux")try{let s=await zi(`/proc/${e}/stat`,"utf8"),n=s.lastIndexOf(")");if(n===-1)return null;let r=s.slice(n+1).trim().split(/\s+/),o=Number(r[19]);if(!Number.isFinite(o))return null;let a=await zi("/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 s of["/bin/ps","/usr/bin/ps"])try{let{stdout:n}=await Xn(s,["-o","lstart=","-p",String(e)],{timeout:2e3}),r=Date.parse(n.trim());return Number.isFinite(r)?r:null}catch{continue}return null}async function tg(e,t){let s=await Zm();if(s.length===0)return null;let n=e.replace(/\/+$/,""),r=[];for(let a of s){let c=await Qm(a);if(c&&(c===n||c.startsWith(n+"/"))){let d=await eg(a);r.push({pid:a,startMs:d})}}if(r.length===0)return new Set;let o=new Set;for(let{startMs:a}of r){if(a==null)continue;let c=null,d=Vm;for(let u of t){if(o.has(u.session_id)||!u.started_at)continue;let g=Date.parse(u.started_at);if(!Number.isFinite(g))continue;let h=Math.abs(g-a);h<d&&(d=h,c=u)}c&&o.add(c.session_id)}return o}function sg(e){let s=f().prepare("SELECT id, name, decoded_path FROM projects WHERE id = ? LIMIT 1").get(e);if(!s)throw new Error(`project ${e} not found`);return s}function ng(e,t){let s=f(),n=`${Vi}${t}${Zi}%`,r=s.prepare(`SELECT t.id
843
843
  FROM threads t
844
844
  WHERE t.archived = 0
845
845
  AND t.name LIKE ?
@@ -850,7 +850,7 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
850
850
  WHERE s.project_id = ?
851
851
  AND t.archived = 0
852
852
  AND t.name LIKE ?
853
- LIMIT 1`).get(e,n);return o?te(o.id):null}function Vi(e){let t=e?new Date(e):new Date,s=t.getFullYear(),n=String(t.getMonth()+1).padStart(2,"0"),r=String(t.getDate()).padStart(2,"0");return`${s}-${n}-${r}`}function Wn(e,t){let s=f(),n=t>0,r=n?Date.now()-t*60*60*1e3:0;return n?s.prepare(`SELECT s.id AS session_id,
853
+ LIMIT 1`).get(e,n);return o?te(o.id):null}function Qi(e){let t=e?new Date(e):new Date,s=t.getFullYear(),n=String(t.getMonth()+1).padStart(2,"0"),r=String(t.getDate()).padStart(2,"0");return`${s}-${n}-${r}`}function Jn(e,t){let s=f(),n=t>0,r=n?Date.now()-t*60*60*1e3:0;return n?s.prepare(`SELECT s.id AS session_id,
854
854
  sa.alias AS alias,
855
855
  s.auto_title AS auto_title,
856
856
  s.first_user_message AS first_user_message,
@@ -872,17 +872,17 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
872
872
  WHERE s.project_id = ?
873
873
  ORDER BY s.started_at ASC`).all(e)}function rg(e){let t=f(),s=[];for(let n of e){if(!n.started_at)continue;let r=Date.parse(n.started_at);if(!Number.isFinite(r))continue;let o=t.prepare("SELECT file_path, ended_at FROM sessions WHERE id = ?").get(n.session_id);if(!o?.file_path)continue;let a=o.ended_at?Date.parse(o.ended_at):null,c=ys(o.file_path,{maxUserMessages:7});s.push({id:n.session_id,started_at_ms:r,ended_at_ms:Number.isFinite(a)?a:null,first_user_message:n.first_user_message,recent_user_messages:c.recent_user_messages,auto_title:n.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 s}function og(e){let s=f().prepare(`SELECT session_id, parent_session_id, source
874
874
  FROM thread_edges
875
- WHERE thread_id = ?`).all(e),n=new Map;for(let r of s)n.set(r.session_id,{parent_session_id:r.parent_session_id,source:r.source});return n}async function Zi(e,t={}){let s=sg(e),n=t.windowHours??zm,r=t.scoreThreshold??Ts,o=t.useLivePids??!0,a=[],c=[];if(o&&s.decoded_path){let k=Wn(e,0),w=await tg(s.decoded_path,k);if(w===null){let L=ws()==="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(L),c=Wn(e,n)}else w.size===0?(a.push(`No active terminals open in ${s.name} (cwd=${s.decoded_path}). Open a Claude terminal in this repo and re-run.`),c=[]):c=k.filter(D=>w.has(D.session_id))}else c=Wn(e,n);c.length===0&&!a.length&&a.push(`No active sessions in ${s.name} within the last ${n}h.`);let d=ng(e,s.name),u=new Set(d?d.edges.map(k=>k.session_id):[]),g=c.filter(k=>!u.has(k.session_id)),h=rg(c);h.sort((k,w)=>k.started_at_ms-w.started_at_ms);let b=ze(h,r),S=d?d.edges.filter(k=>k.source!=="auto-active"&&(k.parent_session_id||k.role==="origin")).map(k=>({session_id:k.session_id,parent_session_id:k.parent_session_id})):[],y=d?d.name:`${Ki}${s.name}${zi}${Vi(t.todayIso)}`;return{project:s,thread:{id:d?.id??null,name:y,exists:!!d,existing_session_count:d?.edges.length??0},candidates:c,proposed_additions:g,proposed_edges:b,preserved_manual_edges:S,warnings:a}}function Qi(e){let t={thread_id:"",added:0,edges_set:0,preserved_manual:e.preserved_manual_edges.length},s;e.thread.exists&&e.thread.id?s=e.thread.id:s=hs({name:e.thread.name,summary:`Auto-captured by sync-active on ${Vi()}. 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=s;let n=og(s);for(let a of e.candidates)n.has(a.session_id)||(Es({threadId:s,sessionId:a.session_id,source:"auto-active",confidence:.5}),t.added++,n.set(a.session_id,{parent_session_id:null,source:"auto-active"}));for(let a of e.proposed_edges){let c=n.get(a.child_id);if(c&&c.source==="auto-active"&&c.parent_session_id!==a.parent_id&&n.has(a.parent_id))try{xt(s,a.child_id,a.parent_id),t.edges_set++,n.set(a.child_id,{parent_session_id:a.parent_id,source:c.source})}catch{}}let o=f().prepare(`SELECT session_id FROM thread_edges
875
+ WHERE thread_id = ?`).all(e),n=new Map;for(let r of s)n.set(r.session_id,{parent_session_id:r.parent_session_id,source:r.source});return n}async function ea(e,t={}){let s=sg(e),n=t.windowHours??zm,r=t.scoreThreshold??Ts,o=t.useLivePids??!0,a=[],c=[];if(o&&s.decoded_path){let k=Jn(e,0),w=await tg(s.decoded_path,k);if(w===null){let L=ws()==="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(L),c=Jn(e,n)}else w.size===0?(a.push(`No active terminals open in ${s.name} (cwd=${s.decoded_path}). Open a Claude terminal in this repo and re-run.`),c=[]):c=k.filter(D=>w.has(D.session_id))}else c=Jn(e,n);c.length===0&&!a.length&&a.push(`No active sessions in ${s.name} within the last ${n}h.`);let d=ng(e,s.name),u=new Set(d?d.edges.map(k=>k.session_id):[]),g=c.filter(k=>!u.has(k.session_id)),h=rg(c);h.sort((k,w)=>k.started_at_ms-w.started_at_ms);let b=ze(h,r),S=d?d.edges.filter(k=>k.source!=="auto-active"&&(k.parent_session_id||k.role==="origin")).map(k=>({session_id:k.session_id,parent_session_id:k.parent_session_id})):[],y=d?d.name:`${Vi}${s.name}${Zi}${Qi(t.todayIso)}`;return{project:s,thread:{id:d?.id??null,name:y,exists:!!d,existing_session_count:d?.edges.length??0},candidates:c,proposed_additions:g,proposed_edges:b,preserved_manual_edges:S,warnings:a}}function ta(e){let t={thread_id:"",added:0,edges_set:0,preserved_manual:e.preserved_manual_edges.length},s;e.thread.exists&&e.thread.id?s=e.thread.id:s=hs({name:e.thread.name,summary:`Auto-captured by sync-active on ${Qi()}. 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=s;let n=og(s);for(let a of e.candidates)n.has(a.session_id)||(Es({threadId:s,sessionId:a.session_id,source:"auto-active",confidence:.5}),t.added++,n.set(a.session_id,{parent_session_id:null,source:"auto-active"}));for(let a of e.proposed_edges){let c=n.get(a.child_id);if(c&&c.source==="auto-active"&&c.parent_session_id!==a.parent_id&&n.has(a.parent_id))try{xt(s,a.child_id,a.parent_id),t.edges_set++,n.set(a.child_id,{parent_session_id:a.parent_id,source:c.source})}catch{}}let o=f().prepare(`SELECT session_id FROM thread_edges
876
876
  WHERE thread_id = ?
877
877
  AND source = 'auto-active'
878
878
  AND parent_session_id IS NULL
879
- AND role = 'child'`).all(s);for(let a of o)try{xt(s,a.session_id,null)}catch{}return t}H();Z();import{randomUUID as ig}from"node:crypto";import{writeFileSync as ag}from"node:fs";import{join as cg}from"node:path";var lg=cg($,"thread-folders.json");function ea(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 Ot(){try{J();let e=Jn({includeArchived:!0});ag(lg,JSON.stringify({folders:e},null,2))}catch{}}function Jn(e={}){let t=e.includeArchived?"":"WHERE archived = 0";return f().prepare(`SELECT * FROM thread_folders ${t} ORDER BY sort_order, name`).all().map(ea)}function $e(e){let t=f().prepare("SELECT * FROM thread_folders WHERE id = ?").get(e);return t?ea(t):null}function ta(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 s=e.parentFolderId??null,n=e.projectScope??null;if(s){let c=$e(s);if(!c)throw new Error(`parent folder ${s} not found`);n=c.project_scope}let r=ig(),o=new Date().toISOString(),a=sa(s,n);return f().prepare(`INSERT INTO thread_folders (id, name, parent_folder_id, project_scope, created_at, archived, sort_order)
880
- VALUES (?, ?, ?, ?, ?, 0, ?)`).run(r,t,s,n,o,a),Ot(),{id:r,name:t,parent_folder_id:s,project_scope:n,created_at:o,archived:!1,sort_order:a}}function sa(e,t){return f().prepare(`SELECT COALESCE(MAX(sort_order), -100) + 100 AS next
879
+ AND role = 'child'`).all(s);for(let a of o)try{xt(s,a.session_id,null)}catch{}return t}H();Z();import{randomUUID as ig}from"node:crypto";import{writeFileSync as ag}from"node:fs";import{join as cg}from"node:path";var lg=cg($,"thread-folders.json");function sa(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 Ot(){try{J();let e=Gn({includeArchived:!0});ag(lg,JSON.stringify({folders:e},null,2))}catch{}}function Gn(e={}){let t=e.includeArchived?"":"WHERE archived = 0";return f().prepare(`SELECT * FROM thread_folders ${t} ORDER BY sort_order, name`).all().map(sa)}function $e(e){let t=f().prepare("SELECT * FROM thread_folders WHERE id = ?").get(e);return t?sa(t):null}function na(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 s=e.parentFolderId??null,n=e.projectScope??null;if(s){let c=$e(s);if(!c)throw new Error(`parent folder ${s} not found`);n=c.project_scope}let r=ig(),o=new Date().toISOString(),a=ra(s,n);return f().prepare(`INSERT INTO thread_folders (id, name, parent_folder_id, project_scope, created_at, archived, sort_order)
880
+ VALUES (?, ?, ?, ?, ?, 0, ?)`).run(r,t,s,n,o,a),Ot(),{id:r,name:t,parent_folder_id:s,project_scope:n,created_at:o,archived:!1,sort_order:a}}function ra(e,t){return f().prepare(`SELECT COALESCE(MAX(sort_order), -100) + 100 AS next
881
881
  FROM thread_folders
882
882
  WHERE parent_folder_id IS ?
883
- AND project_scope IS ?`).get(e,t)?.next??0}function na(e,t){let s=t.trim();if(!s)throw new Error("folder name cannot be empty");if(s.length>200)throw new Error("folder name too long (200 char max)");let n=$e(e);if(!n)throw new Error(`folder ${e} not found`);return f().prepare("UPDATE thread_folders SET name = ? WHERE id = ?").run(s,e),Ot(),{...n,name:s}}function ra(e,t){let s=$e(e);if(!s)throw new Error(`folder ${e} not found`);if(t===e)throw new Error("cannot move a folder under itself");let n=s.project_scope;if(t!==null){let o=$e(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 d=$e(a);if(!d)break;a=d.parent_folder_id,c++}n=o.project_scope}let r=sa(t,n);return f().prepare("UPDATE thread_folders SET parent_folder_id = ?, project_scope = ?, sort_order = ? WHERE id = ?").run(t,n,r,e),Ot(),{...s,parent_folder_id:t,project_scope:n,sort_order:r}}function oa(e,t,s){if(!Array.isArray(s)||s.length===0)throw new Error("ordered_ids must be a non-empty array");let n=new Set;for(let u of s){if(typeof u!="string"||!u)throw new Error("ordered_ids must contain non-empty strings");if(n.has(u))throw new Error(`duplicate id in ordered_ids: ${u}`);n.add(u)}let r=f(),o=r.prepare(`SELECT id FROM thread_folders
883
+ AND project_scope IS ?`).get(e,t)?.next??0}function oa(e,t){let s=t.trim();if(!s)throw new Error("folder name cannot be empty");if(s.length>200)throw new Error("folder name too long (200 char max)");let n=$e(e);if(!n)throw new Error(`folder ${e} not found`);return f().prepare("UPDATE thread_folders SET name = ? WHERE id = ?").run(s,e),Ot(),{...n,name:s}}function ia(e,t){let s=$e(e);if(!s)throw new Error(`folder ${e} not found`);if(t===e)throw new Error("cannot move a folder under itself");let n=s.project_scope;if(t!==null){let o=$e(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 d=$e(a);if(!d)break;a=d.parent_folder_id,c++}n=o.project_scope}let r=ra(t,n);return f().prepare("UPDATE thread_folders SET parent_folder_id = ?, project_scope = ?, sort_order = ? WHERE id = ?").run(t,n,r,e),Ot(),{...s,parent_folder_id:t,project_scope:n,sort_order:r}}function aa(e,t,s){if(!Array.isArray(s)||s.length===0)throw new Error("ordered_ids must be a non-empty array");let n=new Set;for(let u of s){if(typeof u!="string"||!u)throw new Error("ordered_ids must contain non-empty strings");if(n.has(u))throw new Error(`duplicate id in ordered_ids: ${u}`);n.add(u)}let r=f(),o=r.prepare(`SELECT id FROM thread_folders
884
884
  WHERE parent_folder_id IS ?
885
- AND project_scope IS ?`).all(e,t),a=new Set(o.map(u=>u.id));if(a.size!==s.length)throw new Error(`ordered_ids length ${s.length} does not match sibling count ${a.size}`);for(let u of s)if(!a.has(u))throw new Error(`folder ${u} is not in the named sibling bucket`);let c=r.prepare("UPDATE thread_folders SET sort_order = ? WHERE id = ?");r.transaction(u=>{u.forEach((g,h)=>c.run(h*100,g))})(s),Ot()}function ia(e){if(!$e(e))throw new Error(`folder ${e} not found`);f().prepare("DELETE FROM thread_folders WHERE id = ?").run(e),Ot()}function aa(e,t){if(t!==null&&!$e(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`)}H();Z();import{writeFileSync as ca,readFileSync as Bw,existsSync as la,mkdirSync as da,readdirSync as Hw}from"node:fs";import{join as Rs}from"node:path";var dg=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),ua=new Set(["regex","llm","embedding","manual","auto","citation","git","terminal-registry"]),ug=new Set(["pending","approved","rejected"]),pg=new Set(["L1","L2","L3","L4","user"]),Xn=Rs($,"links"),Gn=Rs($,"suggestions"),mg=Rs(Gn,"index.json");function gg(){J(),la(Xn)||da(Xn,{recursive:!0})}function _g(){J(),la(Gn)||da(Gn,{recursive:!0})}function pa(e){try{return JSON.parse(e)}catch{return e}}function ks(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:pa(e.evidence),approved:e.approved===1,created_at:e.created_at,updated_at:e.updated_at}}function Yn(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:pa(e.evidence),status:e.status,inferred_by:e.inferred_by,created_at:e.created_at,decided_at:e.decided_at}}function ma(e){if(!Number.isFinite(e)||e<0||e>1)throw new Error("confidence must be a number in [0, 1]")}function Kn(e){if(!dg.has(e))throw new Error(`invalid link_type: ${e}`)}function fg(e){if(!ua.has(e))throw new Error(`invalid source: ${e}`)}function ga(e){if(!pg.has(e))throw new Error(`invalid inferred_by: ${e}`)}function _a(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 fa(e){_a(e.source_session_id,e.target_session_id),Kn(e.link_type),fg(e.source),ma(e.confidence);let t=f(),s=new Date().toISOString(),n=JSON.stringify(e.evidence??null),r=e.approved?1:0;t.prepare(`INSERT INTO session_links
885
+ AND project_scope IS ?`).all(e,t),a=new Set(o.map(u=>u.id));if(a.size!==s.length)throw new Error(`ordered_ids length ${s.length} does not match sibling count ${a.size}`);for(let u of s)if(!a.has(u))throw new Error(`folder ${u} is not in the named sibling bucket`);let c=r.prepare("UPDATE thread_folders SET sort_order = ? WHERE id = ?");r.transaction(u=>{u.forEach((g,h)=>c.run(h*100,g))})(s),Ot()}function ca(e){if(!$e(e))throw new Error(`folder ${e} not found`);f().prepare("DELETE FROM thread_folders WHERE id = ?").run(e),Ot()}function la(e,t){if(t!==null&&!$e(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`)}H();Z();import{writeFileSync as da,readFileSync as Bw,existsSync as ua,mkdirSync as pa,readdirSync as Hw}from"node:fs";import{join as Rs}from"node:path";var dg=new Set(["citation","similar","skill_track","bug_pattern","wiki_link","temporal_proximity"]),ma=new Set(["regex","llm","embedding","manual","auto","citation","git","terminal-registry"]),ug=new Set(["pending","approved","rejected"]),pg=new Set(["L1","L2","L3","L4","user"]),Yn=Rs($,"links"),Kn=Rs($,"suggestions"),mg=Rs(Kn,"index.json");function gg(){J(),ua(Yn)||pa(Yn,{recursive:!0})}function _g(){J(),ua(Kn)||pa(Kn,{recursive:!0})}function ga(e){try{return JSON.parse(e)}catch{return e}}function ks(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:ga(e.evidence),approved:e.approved===1,created_at:e.created_at,updated_at:e.updated_at}}function zn(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:ga(e.evidence),status:e.status,inferred_by:e.inferred_by,created_at:e.created_at,decided_at:e.decided_at}}function _a(e){if(!Number.isFinite(e)||e<0||e>1)throw new Error("confidence must be a number in [0, 1]")}function Vn(e){if(!dg.has(e))throw new Error(`invalid link_type: ${e}`)}function fg(e){if(!ma.has(e))throw new Error(`invalid source: ${e}`)}function fa(e){if(!pg.has(e))throw new Error(`invalid inferred_by: ${e}`)}function ha(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 Ea(e){ha(e.source_session_id,e.target_session_id),Vn(e.link_type),fg(e.source),_a(e.confidence);let t=f(),s=new Date().toISOString(),n=JSON.stringify(e.evidence??null),r=e.approved?1:0;t.prepare(`INSERT INTO session_links
886
886
  (source_session_id, target_session_id, link_type,
887
887
  confidence, source, evidence, approved,
888
888
  created_at, updated_at)
@@ -895,11 +895,11 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
895
895
  updated_at = excluded.updated_at`).run(e.source_session_id,e.target_session_id,e.link_type,e.confidence,e.source,n,r,s,s);let o=t.prepare(`SELECT * FROM session_links
896
896
  WHERE source_session_id = ?
897
897
  AND target_session_id = ?
898
- 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 Vn(e.source_session_id),ks(o)}function As(e={}){let t=f(),s=[],n=[];e.sourceSessionId&&(s.push("source_session_id = ?"),n.push(e.sourceSessionId)),e.targetSessionId&&(s.push("target_session_id = ?"),n.push(e.targetSessionId)),e.linkType&&(Kn(e.linkType),s.push("link_type = ?"),n.push(e.linkType)),e.approvedOnly&&s.push("approved = 1");let r=s.length?`WHERE ${s.join(" AND ")}`:"",o=Math.max(1,Math.min(5e3,e.limit??1e3));return t.prepare(`SELECT * FROM session_links ${r}
898
+ 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 Qn(e.source_session_id),ks(o)}function As(e={}){let t=f(),s=[],n=[];e.sourceSessionId&&(s.push("source_session_id = ?"),n.push(e.sourceSessionId)),e.targetSessionId&&(s.push("target_session_id = ?"),n.push(e.targetSessionId)),e.linkType&&(Vn(e.linkType),s.push("link_type = ?"),n.push(e.linkType)),e.approvedOnly&&s.push("approved = 1");let r=s.length?`WHERE ${s.join(" AND ")}`:"",o=Math.max(1,Math.min(5e3,e.limit??1e3));return t.prepare(`SELECT * FROM session_links ${r}
899
899
  ORDER BY confidence DESC, updated_at DESC
900
900
  LIMIT ?`).all(...n,o).map(ks)}function Lt(e){return f().prepare(`SELECT * FROM session_links
901
901
  WHERE source_session_id = ? OR target_session_id = ?
902
- ORDER BY confidence DESC, updated_at DESC`).all(e,e).map(ks)}function ha(e){let t=f(),s=t.prepare("SELECT source_session_id FROM session_links WHERE id = ?").get(e);if(!s)return{removed:0,sourceSessionId:null};let n=t.prepare("DELETE FROM session_links WHERE id = ?").run(e);return n.changes>0&&Vn(s.source_session_id),{removed:n.changes,sourceSessionId:s.source_session_id}}function Ct(e){_a(e.source_session_id,e.target_session_id),Kn(e.link_type),ma(e.confidence),ga(e.inferred_by);let t=f(),s=new Date().toISOString(),n=JSON.stringify(e.evidence??null);t.prepare(`INSERT INTO session_link_suggestions
902
+ ORDER BY confidence DESC, updated_at DESC`).all(e,e).map(ks)}function ba(e){let t=f(),s=t.prepare("SELECT source_session_id FROM session_links WHERE id = ?").get(e);if(!s)return{removed:0,sourceSessionId:null};let n=t.prepare("DELETE FROM session_links WHERE id = ?").run(e);return n.changes>0&&Qn(s.source_session_id),{removed:n.changes,sourceSessionId:s.source_session_id}}function Ct(e){ha(e.source_session_id,e.target_session_id),Vn(e.link_type),_a(e.confidence),fa(e.inferred_by);let t=f(),s=new Date().toISOString(),n=JSON.stringify(e.evidence??null);t.prepare(`INSERT INTO session_link_suggestions
903
903
  (source_session_id, target_session_id, link_type,
904
904
  confidence, evidence, status, inferred_by,
905
905
  created_at, decided_at)
@@ -919,9 +919,9 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
919
919
  WHERE source_session_id = ?
920
920
  AND target_session_id = ?
921
921
  AND link_type = ?
922
- 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 Ea(),Yn(r)}function Ve(e={}){let t=f(),s=[],n=[];if(e.status){if(!ug.has(e.status))throw new Error(`invalid status: ${e.status}`);s.push("status = ?"),n.push(e.status)}e.sourceSessionId&&(s.push("source_session_id = ?"),n.push(e.sourceSessionId)),e.targetSessionId&&(s.push("target_session_id = ?"),n.push(e.targetSessionId)),e.inferredBy&&(ga(e.inferredBy),s.push("inferred_by = ?"),n.push(e.inferredBy));let r=s.length?`WHERE ${s.join(" AND ")}`:"",o=Math.max(1,Math.min(5e3,e.limit??1e3));return t.prepare(`SELECT * FROM session_link_suggestions ${r}
922
+ 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 Sa(),zn(r)}function Ve(e={}){let t=f(),s=[],n=[];if(e.status){if(!ug.has(e.status))throw new Error(`invalid status: ${e.status}`);s.push("status = ?"),n.push(e.status)}e.sourceSessionId&&(s.push("source_session_id = ?"),n.push(e.sourceSessionId)),e.targetSessionId&&(s.push("target_session_id = ?"),n.push(e.targetSessionId)),e.inferredBy&&(fa(e.inferredBy),s.push("inferred_by = ?"),n.push(e.inferredBy));let r=s.length?`WHERE ${s.join(" AND ")}`:"",o=Math.max(1,Math.min(5e3,e.limit??1e3));return t.prepare(`SELECT * FROM session_link_suggestions ${r}
923
923
  ORDER BY confidence DESC, created_at DESC
924
- LIMIT ?`).all(...n,o).map(Yn)}function zn(e,t,s={}){if(t!=="approved"&&t!=="rejected")throw new Error(`invalid decision: ${t}`);let n=s.source??"manual";if(!ua.has(n))throw new Error(`invalid source: ${n}`);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
924
+ LIMIT ?`).all(...n,o).map(zn)}function Zn(e,t,s={}){if(t!=="approved"&&t!=="rejected")throw new Error(`invalid decision: ${t}`);let n=s.source??"manual";if(!ma.has(n))throw new Error(`invalid source: ${n}`);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
925
925
  SET status = ?, decided_at = ?
926
926
  WHERE id = ?`).run(t,a,e),t==="approved"&&(r.prepare(`INSERT INTO session_links
927
927
  (source_session_id, target_session_id, link_type,
@@ -936,7 +936,7 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
936
936
  updated_at = excluded.updated_at`).run(o.source_session_id,o.target_session_id,o.link_type,o.confidence,n,o.evidence,a,a),c=r.prepare(`SELECT * FROM session_links
937
937
  WHERE source_session_id = ?
938
938
  AND target_session_id = ?
939
- AND link_type = ?`).get(o.source_session_id,o.target_session_id,o.link_type))})(),Ea(),t==="approved"&&Vn(o.source_session_id);let d=r.prepare("SELECT * FROM session_link_suggestions WHERE id = ?").get(e);return{suggestion:Yn(d),link:c?ks(c):null}}function Vn(e){try{gg();let t=As({sourceSessionId:e}),s=Rs(Xn,`${e}.json`);if(t.length===0)return;let n={schema:"claude-recall.session-links.v1",source_session_id:e,backed_up_at:new Date().toISOString(),links:t};ca(s,JSON.stringify(n,null,2))}catch(t){console.error("[session-links] backup failed:",t)}}function Ea(){try{_g();let e=Ve({limit:5e3}),t={schema:"claude-recall.session-link-suggestions.v1",backed_up_at:new Date().toISOString(),suggestions:e};ca(mg,JSON.stringify(t,null,2))}catch(e){console.error("[session-links] suggestions backup failed:",e)}}function ba(e,t){let s=new Set,n=[];for(let r of t){if(s.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;s.add(r.id),n.push({linkId:r.id,otherSessionId:a,direction:o,updatedAt:r.updated_at,link:r})}return n.sort((r,o)=>r.updatedAt<o.updatedAt?1:r.updatedAt>o.updatedAt?-1:0),n}H();Z();import{writeFileSync as hg,readFileSync as Kw,existsSync as Eg,mkdirSync as bg,readdirSync as zw}from"node:fs";import{join as Sa}from"node:path";var Zn=Sa($,"output-index");function Sg(){J(),Eg(Zn)||bg(Zn,{recursive:!0})}function It(e){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}function Tg(e){if(!e)return null;try{return JSON.parse(e)}catch{return e}}function Ta(e){return{session_id:e.session_id,files_written:It(e.files_written),brands_mentioned:It(e.brands_mentioned),terms_introduced:It(e.terms_introduced),plan_ids_referenced:It(e.plan_ids_referenced),bug_signatures:It(e.bug_signatures),raw_extraction:Tg(e.raw_extraction),extracted_at:e.extracted_at,extractor_version:e.extractor_version}}function ya(e){if(!e.session_id)throw new Error("session_id is required");let t=f(),s=new Date().toISOString(),n=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??[]),d=e.raw_extraction===void 0?null:JSON.stringify(e.raw_extraction),u=Math.max(1,Math.floor(e.extractor_version??1));t.prepare(`INSERT INTO session_output_index
939
+ AND link_type = ?`).get(o.source_session_id,o.target_session_id,o.link_type))})(),Sa(),t==="approved"&&Qn(o.source_session_id);let d=r.prepare("SELECT * FROM session_link_suggestions WHERE id = ?").get(e);return{suggestion:zn(d),link:c?ks(c):null}}function Qn(e){try{gg();let t=As({sourceSessionId:e}),s=Rs(Yn,`${e}.json`);if(t.length===0)return;let n={schema:"claude-recall.session-links.v1",source_session_id:e,backed_up_at:new Date().toISOString(),links:t};da(s,JSON.stringify(n,null,2))}catch(t){console.error("[session-links] backup failed:",t)}}function Sa(){try{_g();let e=Ve({limit:5e3}),t={schema:"claude-recall.session-link-suggestions.v1",backed_up_at:new Date().toISOString(),suggestions:e};da(mg,JSON.stringify(t,null,2))}catch(e){console.error("[session-links] suggestions backup failed:",e)}}function Ta(e,t){let s=new Set,n=[];for(let r of t){if(s.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;s.add(r.id),n.push({linkId:r.id,otherSessionId:a,direction:o,updatedAt:r.updated_at,link:r})}return n.sort((r,o)=>r.updatedAt<o.updatedAt?1:r.updatedAt>o.updatedAt?-1:0),n}H();Z();import{writeFileSync as hg,readFileSync as Kw,existsSync as Eg,mkdirSync as bg,readdirSync as zw}from"node:fs";import{join as ya}from"node:path";var er=ya($,"output-index");function Sg(){J(),Eg(er)||bg(er,{recursive:!0})}function It(e){if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}function Tg(e){if(!e)return null;try{return JSON.parse(e)}catch{return e}}function wa(e){return{session_id:e.session_id,files_written:It(e.files_written),brands_mentioned:It(e.brands_mentioned),terms_introduced:It(e.terms_introduced),plan_ids_referenced:It(e.plan_ids_referenced),bug_signatures:It(e.bug_signatures),raw_extraction:Tg(e.raw_extraction),extracted_at:e.extracted_at,extractor_version:e.extractor_version}}function Ra(e){if(!e.session_id)throw new Error("session_id is required");let t=f(),s=new Date().toISOString(),n=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??[]),d=e.raw_extraction===void 0?null:JSON.stringify(e.raw_extraction),u=Math.max(1,Math.floor(e.extractor_version??1));t.prepare(`INSERT INTO session_output_index
940
940
  (session_id, files_written, brands_mentioned, terms_introduced,
941
941
  plan_ids_referenced, bug_signatures, raw_extraction,
942
942
  extracted_at, extractor_version)
@@ -949,7 +949,7 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
949
949
  bug_signatures = excluded.bug_signatures,
950
950
  raw_extraction = excluded.raw_extraction,
951
951
  extracted_at = excluded.extracted_at,
952
- extractor_version = excluded.extractor_version`).run(e.session_id,n,r,o,a,c,d,s,u);let g=t.prepare("SELECT * FROM session_output_index WHERE session_id = ?").get(e.session_id);if(!g)throw new Error("setOutputIndex succeeded but read-back failed");let h=Ta(g);return yg(e.session_id),h}function Be(e){let s=f().prepare("SELECT * FROM session_output_index WHERE session_id = ?").get(e);return s?Ta(s):null}function yg(e){try{Sg();let t=Be(e);if(!t)return;let s=Sa(Zn,`${e}.json`),n={schema:"claude-recall.session-output-index.v1",backed_up_at:new Date().toISOString(),...t};hg(s,JSON.stringify(n,null,2))}catch(t){console.error("[output-index] backup failed:",t)}}H();var wg=4e3,Rg=2,kg=30,Ag=.2,Ng={citation:1,wiki_link:.9,similar:.7,skill_track:.5,bug_pattern:.4,temporal_proximity:.3};function Ns(e){return e?Math.ceil(e.length/4):0}function wa(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/kg);return Math.max(Ag,t)}function Ra(e,t){if(!e||!t)return 0;let s=Date.parse(e),n=Date.parse(t);return!Number.isFinite(s)||!Number.isFinite(n)?0:Math.abs(n-s)/(1e3*60*60*24)}function ka(e){return f().prepare(`SELECT s.id,
952
+ extractor_version = excluded.extractor_version`).run(e.session_id,n,r,o,a,c,d,s,u);let g=t.prepare("SELECT * FROM session_output_index WHERE session_id = ?").get(e.session_id);if(!g)throw new Error("setOutputIndex succeeded but read-back failed");let h=wa(g);return yg(e.session_id),h}function Be(e){let s=f().prepare("SELECT * FROM session_output_index WHERE session_id = ?").get(e);return s?wa(s):null}function yg(e){try{Sg();let t=Be(e);if(!t)return;let s=ya(er,`${e}.json`),n={schema:"claude-recall.session-output-index.v1",backed_up_at:new Date().toISOString(),...t};hg(s,JSON.stringify(n,null,2))}catch(t){console.error("[output-index] backup failed:",t)}}H();var wg=4e3,Rg=2,kg=30,Ag=.2,Ng={citation:1,wiki_link:.9,similar:.7,skill_track:.5,bug_pattern:.4,temporal_proximity:.3};function Ns(e){return e?Math.ceil(e.length/4):0}function ka(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/kg);return Math.max(Ag,t)}function Aa(e,t){if(!e||!t)return 0;let s=Date.parse(e),n=Date.parse(t);return!Number.isFinite(s)||!Number.isFinite(n)?0:Math.abs(n-s)/(1e3*60*60*24)}function Na(e){return f().prepare(`SELECT s.id,
953
953
  NULLIF(sa.alias, '') AS alias,
954
954
  s.auto_title,
955
955
  s.auto_title_source,
@@ -960,34 +960,34 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
960
960
  FROM sessions s
961
961
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
962
962
  LEFT JOIN projects p ON p.id = s.project_id
963
- WHERE s.id = ?`).get(e)??null}function Aa(e){let s=f().prepare("SELECT summary FROM session_semantic WHERE session_id = ?").get(e);if(!s||!s.summary)return null;let n=s.summary.trim();return n.length>0?n:null}function Na(e){let t=e.alias?.trim(),s=e.auto_title?.trim(),n=e.first_user_message?.trim();return s&&e.auto_title_source==="agent"?s:t||s||(n?n.slice(0,80):e.id.slice(0,8))}function xg(e){let s=f().prepare(`SELECT id, auto_title, started_at
963
+ WHERE s.id = ?`).get(e)??null}function xa(e){let s=f().prepare("SELECT summary FROM session_semantic WHERE session_id = ?").get(e);if(!s||!s.summary)return null;let n=s.summary.trim();return n.length>0?n:null}function Oa(e){let t=e.alias?.trim(),s=e.auto_title?.trim(),n=e.first_user_message?.trim();return s&&e.auto_title_source==="agent"?s:t||s||(n?n.slice(0,80):e.id.slice(0,8))}function xg(e){let s=f().prepare(`SELECT id, auto_title, started_at
964
964
  FROM sessions
965
965
  WHERE project_id = ?
966
- ORDER BY COALESCE(started_at, ''), id`).all(e),n=new Set,r=new Set,o=[];for(let b of s){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 "),y=S[0].trim(),k=S.length>1?S.slice(1).join(" \xB7 ").trim():null;o.push({id:b.id,brand:k||null,skill:y||null}),k&&n.add(k),y&&r.add(y)}let a=[...n].sort(),c=new Map;a.forEach((b,S)=>c.set(b,S));let d=[...r].sort(),u=new Map;d.forEach((b,S)=>u.set(b,S));let g=new Map,h=new Map;for(let b of o){if(!b.brand||!b.skill)continue;let S=c.get(b.brand),y=u.get(b.skill);if(S===void 0||y===void 0)continue;let k=`${S}.${y}`,w=(g.get(k)??0)+1;g.set(k,w),h.set(b.id,`${S}.${y}.${w}`)}return{byId:h}}function Og(e){return{table:e!==null?xg(e):null,originProjectId:e,cache:new Map}}function xs(e,t){let s=e.cache.get(t);if(s)return s;let n=ka(t);if(!n)return null;let r=e.table&&n.project_id===e.originProjectId?e.table.byId.get(t)??null:null,o={session_id:n.id,title:Na(n),decimal:r,summary:Aa(n.id),project:n.project,started_at:n.started_at};return e.cache.set(t,o),o}function Lg(e,t){let n=f().prepare(`SELECT DISTINCT te.parent_session_id AS pid
966
+ ORDER BY COALESCE(started_at, ''), id`).all(e),n=new Set,r=new Set,o=[];for(let b of s){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 "),y=S[0].trim(),k=S.length>1?S.slice(1).join(" \xB7 ").trim():null;o.push({id:b.id,brand:k||null,skill:y||null}),k&&n.add(k),y&&r.add(y)}let a=[...n].sort(),c=new Map;a.forEach((b,S)=>c.set(b,S));let d=[...r].sort(),u=new Map;d.forEach((b,S)=>u.set(b,S));let g=new Map,h=new Map;for(let b of o){if(!b.brand||!b.skill)continue;let S=c.get(b.brand),y=u.get(b.skill);if(S===void 0||y===void 0)continue;let k=`${S}.${y}`,w=(g.get(k)??0)+1;g.set(k,w),h.set(b.id,`${S}.${y}.${w}`)}return{byId:h}}function Og(e){return{table:e!==null?xg(e):null,originProjectId:e,cache:new Map}}function xs(e,t){let s=e.cache.get(t);if(s)return s;let n=Na(t);if(!n)return null;let r=e.table&&n.project_id===e.originProjectId?e.table.byId.get(t)??null:null,o={session_id:n.id,title:Oa(n),decimal:r,summary:xa(n.id),project:n.project,started_at:n.started_at};return e.cache.set(t,o),o}function Lg(e,t){let n=f().prepare(`SELECT DISTINCT te.parent_session_id AS pid
967
967
  FROM thread_edges te
968
968
  WHERE te.session_id = ?
969
969
  AND te.parent_session_id IS NOT NULL`).all(t),r=[];for(let o of n){if(!o.pid)continue;let a=xs(e,o.pid);a&&r.push(a)}return r}function Cg(e,t){let n=f().prepare(`SELECT DISTINCT te.session_id AS sid
970
970
  FROM thread_edges te
971
- WHERE te.parent_session_id = ?`).all(t),r=[];for(let o of n){if(!o.sid)continue;let a=xs(e,o.sid);a&&r.push(a)}return r}function xa(e){let t=Ng[e.linkType]??.5,s=Ze(e.confidence),n=t*s,r=wa(e.daysApart),o=e.embeddingCosine??.5,a=Ze(e.pagerank);if(e.scoring==="pagerank")return Ze(a);if(e.scoring==="embedding-rerank")return e.embeddingCosine===null?Ze(n):Ze(o);let c=.35*n+.2*r+.2*o+.25*a;return Ze(c)}function Ze(e){return!Number.isFinite(e)||e<0?0:e>1?1:e}function Ig(e,t,s,n,r){let o=new Map;function a(c,d){if(c===d)return;let u=o.get(c);u||(u=new Set,o.set(c,u)),u.add(d)}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 s)a(e,c.session_id);for(let c of s)a(c.session_id,e);for(let c of n)a(e,c.session_id);for(let c of n)a(c.session_id,e);if(r>1){let c=new Set([e]),d=new Set([e]);for(let u=1;u<r;u++){let g=new Set;for(let h of c){let b=o.get(h);if(b)for(let S of b){if(d.has(S))continue;let y=Lt(S).filter(k=>k.approved);for(let k of y)a(k.source_session_id,k.target_session_id),a(k.target_session_id,k.source_session_id);d.add(S),g.add(S)}}if(g.size===0)break;for(let h of g)c.add(h)}}return{edges:o}}function vg(e,t={}){let s=t.iterations??12,n=t.damping??.85,r=Array.from(e.edges.keys());if(r.length===0)return new Map;let o=1/r.length,a=new Map(r.map(u=>[u,o]));for(let u=0;u<s;u++){let g=new Map(r.map(h=>[h,(1-n)/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 y of b)g.set(y,(g.get(y)??0)+n*S)}a=g}let c=0;for(let u of a.values())u>c&&(c=u);if(c<=0)return a;let d=new Map;for(let[u,g]of a)d.set(u,g/c);return d}var Oa=240;function La(e,t){let s=e.replace(/\s+/g," ").trim();return s.length<=t?s:`${s.slice(0,t-1).trimEnd()}\u2026`}function jg(e){let t=e.decimal?`${e.decimal} `:"",s=e.session_id.slice(0,8),n="evidence"in e&&e.evidence?` \u2014 ${e.evidence}`:"",r=`- ${t}${e.title} (${s})${n}`;if(e.summary){let o=La(e.summary,Oa);return`${r}
972
- ${o}`}return r}function Mg(e,t,s){let n=[],r=[],o=0,a=e.decimal?`${e.decimal}: `:"",c=`# Neighborhood for ${e.session_id} (${a}${e.title})`;if(n.push(c),o+=Ns(c),e.summary){let d=La(e.summary,Oa*4);n.push(d),o+=Ns(d)}n.push("");for(let d of t){if(d.refs.length===0)continue;let u=`## ${d.heading}`,g=Ns(u),h=[],b=0;for(let S of d.refs){let y=jg(S),k=Ns(y);if(o+g+b+k>s){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(y),b+=k}if(h.length>0){n.push(u);for(let S of h)n.push(S);n.push(""),o+=g+b}}for(;n.length>0&&n[n.length-1]==="";)n.pop();return{bundle:n.join(`
971
+ WHERE te.parent_session_id = ?`).all(t),r=[];for(let o of n){if(!o.sid)continue;let a=xs(e,o.sid);a&&r.push(a)}return r}function La(e){let t=Ng[e.linkType]??.5,s=Ze(e.confidence),n=t*s,r=ka(e.daysApart),o=e.embeddingCosine??.5,a=Ze(e.pagerank);if(e.scoring==="pagerank")return Ze(a);if(e.scoring==="embedding-rerank")return e.embeddingCosine===null?Ze(n):Ze(o);let c=.35*n+.2*r+.2*o+.25*a;return Ze(c)}function Ze(e){return!Number.isFinite(e)||e<0?0:e>1?1:e}function Ig(e,t,s,n,r){let o=new Map;function a(c,d){if(c===d)return;let u=o.get(c);u||(u=new Set,o.set(c,u)),u.add(d)}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 s)a(e,c.session_id);for(let c of s)a(c.session_id,e);for(let c of n)a(e,c.session_id);for(let c of n)a(c.session_id,e);if(r>1){let c=new Set([e]),d=new Set([e]);for(let u=1;u<r;u++){let g=new Set;for(let h of c){let b=o.get(h);if(b)for(let S of b){if(d.has(S))continue;let y=Lt(S).filter(k=>k.approved);for(let k of y)a(k.source_session_id,k.target_session_id),a(k.target_session_id,k.source_session_id);d.add(S),g.add(S)}}if(g.size===0)break;for(let h of g)c.add(h)}}return{edges:o}}function vg(e,t={}){let s=t.iterations??12,n=t.damping??.85,r=Array.from(e.edges.keys());if(r.length===0)return new Map;let o=1/r.length,a=new Map(r.map(u=>[u,o]));for(let u=0;u<s;u++){let g=new Map(r.map(h=>[h,(1-n)/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 y of b)g.set(y,(g.get(y)??0)+n*S)}a=g}let c=0;for(let u of a.values())u>c&&(c=u);if(c<=0)return a;let d=new Map;for(let[u,g]of a)d.set(u,g/c);return d}var Ca=240;function Ia(e,t){let s=e.replace(/\s+/g," ").trim();return s.length<=t?s:`${s.slice(0,t-1).trimEnd()}\u2026`}function jg(e){let t=e.decimal?`${e.decimal} `:"",s=e.session_id.slice(0,8),n="evidence"in e&&e.evidence?` \u2014 ${e.evidence}`:"",r=`- ${t}${e.title} (${s})${n}`;if(e.summary){let o=Ia(e.summary,Ca);return`${r}
972
+ ${o}`}return r}function Mg(e,t,s){let n=[],r=[],o=0,a=e.decimal?`${e.decimal}: `:"",c=`# Neighborhood for ${e.session_id} (${a}${e.title})`;if(n.push(c),o+=Ns(c),e.summary){let d=Ia(e.summary,Ca*4);n.push(d),o+=Ns(d)}n.push("");for(let d of t){if(d.refs.length===0)continue;let u=`## ${d.heading}`,g=Ns(u),h=[],b=0;for(let S of d.refs){let y=jg(S),k=Ns(y);if(o+g+b+k>s){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(y),b+=k}if(h.length>0){n.push(u);for(let S of h)n.push(S);n.push(""),o+=g+b}}for(;n.length>0&&n[n.length-1]==="";)n.pop();return{bundle:n.join(`
973
973
  `)+`
974
- `,budgetUsed:o,truncated:r}}function Dg(e,t,s,n,r,o){let a=[];for(let c of s){if(n&&!n.has(c.link_type))continue;let d=null;if(c.source_session_id===t.session_id?d=c.target_session_id:c.target_session_id===t.session_id&&(d=c.source_session_id),!d)continue;let u=xs(e,d);if(!u)continue;let g=Ra(t.started_at,u.started_at),h=xa({confidence:c.confidence,linkType:c.link_type,daysApart:g,embeddingCosine:null,pagerank:o.get(d)??0,scoring:r});a.push({...u,score:h,evidence:`(suggestion, ${c.inferred_by}) confidence=${c.confidence.toFixed(2)} ${Math.round(g)}d apart`,link_type:c.link_type})}return a}function Os(e,t={}){let s=Math.max(100,Math.floor(t.budget??wg)),n=t.scoring??"hybrid",r=Math.max(1,Math.min(5,t.maxDepth??Rg)),o=t.includeWikiLinks??!0,a=t.includeSuggestions??!1,c=t.edgeTypes?new Set(t.edgeTypes):null,d=ka(e);if(!d)throw new Error(`session not found: ${e}`);let u=Og(d.project_id),g={session_id:d.id,title:Na(d),decimal:u.table?.byId.get(d.id)??null,summary:Aa(d.id),project:d.project,started_at:d.started_at};u.cache.set(d.id,g);let h=Lg(u,e),b=Cg(u,e),S=Lt(e).filter(i=>i.approved).filter(i=>!c||c.has(i.link_type)).filter(i=>o||i.link_type!=="wiki_link"),y=Ig(e,S,h,b,r),k=vg(y),w=[],D=[],L=[],X=[];for(let i of S){let l=i.source_session_id===e?i.target_session_id:i.source_session_id,p=xs(u,l);if(!p)continue;let m=Ra(g.started_at,p.started_at),_=xa({confidence:i.confidence,linkType:i.link_type,daysApart:m,embeddingCosine:null,pagerank:k.get(l)??0,scoring:n}),E=wa(m),T=`${i.link_type} confidence=${i.confidence.toFixed(2)} recency=${E.toFixed(2)} (${Math.round(m)}d apart)`,R={...p,score:_,evidence:T,link_type:i.link_type};i.link_type==="citation"?w.push(R):i.link_type==="similar"?D.push(R):i.link_type==="wiki_link"?X.push(R):L.push(R)}if(a){let i=Ve({sourceSessionId:e,status:"pending",limit:100}),l=Ve({targetSessionId:e,status:"pending",limit:100}),p=[...i,...l],m=new Set,_=p.filter(T=>m.has(T.id)?!1:(m.add(T.id),!0)),E=Dg(u,g,_,c,n,k);for(let T of E)T.link_type==="citation"?w.push(T):T.link_type==="similar"?D.push(T):T.link_type==="wiki_link"?X.push(T):L.push(T)}let M=(i,l)=>l.score-i.score;w.sort(M),D.sort(M),L.sort(M),X.sort(M);let se=Mg(g,[{heading:"Parents",refs:h},{heading:"Children",refs:b},{heading:"Citations (approved)",refs:w},{heading:"Similar sessions",refs:D},{heading:"Cousins (skill track + temporal)",refs:L},{heading:"Wiki links (manual)",refs:X}],s);return{origin:g,parents:h,children:b,citations:w,similar:D,cousins:L,wikiLinks:X,bundle:se.bundle,budgetUsed:se.budgetUsed,budgetRemaining:Math.max(0,s-se.budgetUsed),truncated:se.truncated}}H();Z();import{writeFileSync as Fg,readFileSync as o0,existsSync as Pg,mkdirSync as Ug,readdirSync as i0,unlinkSync as a0}from"node:fs";import{join as Ca}from"node:path";import{randomUUID as Ia}from"node:crypto";var Qn=Ca($,"bug-patterns");function $g(){J(),Pg(Qn)||Ug(Qn,{recursive:!0})}function Oe(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 va(e){return{cluster_id:e.cluster_id,session_id:e.session_id,matched_at:e.matched_at}}function ja(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(),s=new Date().toISOString(),n=e.id??Ia(),r=e.first_seen_at??s,o=e.last_seen_at??s,a=Array.from(new Set(e.member_session_ids));t.transaction(()=>{t.prepare(`INSERT INTO bug_pattern_clusters
974
+ `,budgetUsed:o,truncated:r}}function Dg(e,t,s,n,r,o){let a=[];for(let c of s){if(n&&!n.has(c.link_type))continue;let d=null;if(c.source_session_id===t.session_id?d=c.target_session_id:c.target_session_id===t.session_id&&(d=c.source_session_id),!d)continue;let u=xs(e,d);if(!u)continue;let g=Aa(t.started_at,u.started_at),h=La({confidence:c.confidence,linkType:c.link_type,daysApart:g,embeddingCosine:null,pagerank:o.get(d)??0,scoring:r});a.push({...u,score:h,evidence:`(suggestion, ${c.inferred_by}) confidence=${c.confidence.toFixed(2)} ${Math.round(g)}d apart`,link_type:c.link_type})}return a}function Os(e,t={}){let s=Math.max(100,Math.floor(t.budget??wg)),n=t.scoring??"hybrid",r=Math.max(1,Math.min(5,t.maxDepth??Rg)),o=t.includeWikiLinks??!0,a=t.includeSuggestions??!1,c=t.edgeTypes?new Set(t.edgeTypes):null,d=Na(e);if(!d)throw new Error(`session not found: ${e}`);let u=Og(d.project_id),g={session_id:d.id,title:Oa(d),decimal:u.table?.byId.get(d.id)??null,summary:xa(d.id),project:d.project,started_at:d.started_at};u.cache.set(d.id,g);let h=Lg(u,e),b=Cg(u,e),S=Lt(e).filter(i=>i.approved).filter(i=>!c||c.has(i.link_type)).filter(i=>o||i.link_type!=="wiki_link"),y=Ig(e,S,h,b,r),k=vg(y),w=[],D=[],L=[],X=[];for(let i of S){let l=i.source_session_id===e?i.target_session_id:i.source_session_id,p=xs(u,l);if(!p)continue;let m=Aa(g.started_at,p.started_at),_=La({confidence:i.confidence,linkType:i.link_type,daysApart:m,embeddingCosine:null,pagerank:k.get(l)??0,scoring:n}),E=ka(m),T=`${i.link_type} confidence=${i.confidence.toFixed(2)} recency=${E.toFixed(2)} (${Math.round(m)}d apart)`,R={...p,score:_,evidence:T,link_type:i.link_type};i.link_type==="citation"?w.push(R):i.link_type==="similar"?D.push(R):i.link_type==="wiki_link"?X.push(R):L.push(R)}if(a){let i=Ve({sourceSessionId:e,status:"pending",limit:100}),l=Ve({targetSessionId:e,status:"pending",limit:100}),p=[...i,...l],m=new Set,_=p.filter(T=>m.has(T.id)?!1:(m.add(T.id),!0)),E=Dg(u,g,_,c,n,k);for(let T of E)T.link_type==="citation"?w.push(T):T.link_type==="similar"?D.push(T):T.link_type==="wiki_link"?X.push(T):L.push(T)}let M=(i,l)=>l.score-i.score;w.sort(M),D.sort(M),L.sort(M),X.sort(M);let se=Mg(g,[{heading:"Parents",refs:h},{heading:"Children",refs:b},{heading:"Citations (approved)",refs:w},{heading:"Similar sessions",refs:D},{heading:"Cousins (skill track + temporal)",refs:L},{heading:"Wiki links (manual)",refs:X}],s);return{origin:g,parents:h,children:b,citations:w,similar:D,cousins:L,wikiLinks:X,bundle:se.bundle,budgetUsed:se.budgetUsed,budgetRemaining:Math.max(0,s-se.budgetUsed),truncated:se.truncated}}H();Z();import{writeFileSync as Fg,readFileSync as o0,existsSync as Pg,mkdirSync as Ug,readdirSync as i0,unlinkSync as a0}from"node:fs";import{join as va}from"node:path";import{randomUUID as ja}from"node:crypto";var tr=va($,"bug-patterns");function $g(){J(),Pg(tr)||Ug(tr,{recursive:!0})}function Oe(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 Ma(e){return{cluster_id:e.cluster_id,session_id:e.session_id,matched_at:e.matched_at}}function Da(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(),s=new Date().toISOString(),n=e.id??ja(),r=e.first_seen_at??s,o=e.last_seen_at??s,a=Array.from(new Set(e.member_session_ids));t.transaction(()=>{t.prepare(`INSERT INTO bug_pattern_clusters
975
975
  (id, signature_hash, example_message, occurrence_count,
976
976
  first_seen_at, last_seen_at, resolved_in_session_id, fix_summary)
977
977
  VALUES (?, ?, ?, ?, ?, ?, NULL, NULL)`).run(n,e.signature_hash,e.example_message,a.length,r,o);let d=t.prepare(`INSERT INTO bug_pattern_members (cluster_id, session_id, matched_at)
978
978
  VALUES (?, ?, ?)
979
- ON CONFLICT(cluster_id, session_id) DO NOTHING`);for(let u of a)d.run(n,u,s)})();let c=Ma(n);if(!c)throw new Error("createCluster succeeded but read-back failed");return vt(n),c}function Ma(e){let t=f(),s=t.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);if(!s)return null;let n=t.prepare("SELECT * FROM bug_pattern_members WHERE cluster_id = ? ORDER BY matched_at ASC, session_id ASC").all(e);return{cluster:Oe(s),members:n.map(va)}}function Da(e,t){if(!e)throw new Error("clusterId is required");if(!Array.isArray(t)||t.length===0)throw new Error("sessionIds must be a non-empty array");let s=f();if(!s.prepare("SELECT 1 FROM bug_pattern_clusters WHERE id = ?").get(e))throw new Error(`cluster ${e} not found`);let r=new Date().toISOString(),o=0;s.transaction(()=>{let c=s.prepare(`INSERT INTO bug_pattern_members (cluster_id, session_id, matched_at)
979
+ ON CONFLICT(cluster_id, session_id) DO NOTHING`);for(let u of a)d.run(n,u,s)})();let c=Fa(n);if(!c)throw new Error("createCluster succeeded but read-back failed");return vt(n),c}function Fa(e){let t=f(),s=t.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);if(!s)return null;let n=t.prepare("SELECT * FROM bug_pattern_members WHERE cluster_id = ? ORDER BY matched_at ASC, session_id ASC").all(e);return{cluster:Oe(s),members:n.map(Ma)}}function Pa(e,t){if(!e)throw new Error("clusterId is required");if(!Array.isArray(t)||t.length===0)throw new Error("sessionIds must be a non-empty array");let s=f();if(!s.prepare("SELECT 1 FROM bug_pattern_clusters WHERE id = ?").get(e))throw new Error(`cluster ${e} not found`);let r=new Date().toISOString(),o=0;s.transaction(()=>{let c=s.prepare(`INSERT INTO bug_pattern_members (cluster_id, session_id, matched_at)
980
980
  VALUES (?, ?, ?)
981
981
  ON CONFLICT(cluster_id, session_id) DO NOTHING`);for(let d of Array.from(new Set(t)))c.run(e,d,r).changes>0&&(o+=1);if(o>0){let d=s.prepare("SELECT COUNT(*) AS n FROM bug_pattern_members WHERE cluster_id = ?").get(e).n;s.prepare(`UPDATE bug_pattern_clusters
982
982
  SET occurrence_count = ?, last_seen_at = ?
983
- WHERE id = ?`).run(d,r,e)}})(),o>0&&vt(e);let a=s.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);return{cluster:Oe(a),added:o}}function Fa(e={}){let t=f(),s=[],n=[];typeof e.minOccurrenceCount=="number"&&(s.push("c.occurrence_count >= ?"),n.push(Math.max(1,Math.floor(e.minOccurrenceCount)))),typeof e.hasResolved=="boolean"&&s.push(e.hasResolved?"c.resolved_in_session_id IS NOT NULL":"c.resolved_in_session_id IS NULL"),e.project&&(s.push(`EXISTS (
983
+ WHERE id = ?`).run(d,r,e)}})(),o>0&&vt(e);let a=s.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);return{cluster:Oe(a),added:o}}function Ua(e={}){let t=f(),s=[],n=[];typeof e.minOccurrenceCount=="number"&&(s.push("c.occurrence_count >= ?"),n.push(Math.max(1,Math.floor(e.minOccurrenceCount)))),typeof e.hasResolved=="boolean"&&s.push(e.hasResolved?"c.resolved_in_session_id IS NOT NULL":"c.resolved_in_session_id IS NULL"),e.project&&(s.push(`EXISTS (
984
984
  SELECT 1 FROM bug_pattern_members m
985
985
  JOIN sessions s ON s.id = m.session_id
986
986
  JOIN projects p ON p.id = s.project_id
987
987
  WHERE m.cluster_id = c.id AND p.name = ?
988
988
  )`),n.push(e.project));let r=s.length>0?`WHERE ${s.join(" AND ")}`:"",o=t.prepare(`SELECT COUNT(*) AS n FROM bug_pattern_clusters c ${r}`).get(...n),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}
989
989
  ORDER BY c.occurrence_count DESC, c.last_seen_at DESC
990
- LIMIT ? OFFSET ?`).all(...n,a,c).map(Oe),total:o.n}}function Bg(e){let t=e.first_user_message?e.first_user_message.slice(0,80):null,s=e.alias??e.auto_title??t??e.session_id.slice(0,8);return{cluster_id:e.cluster_id,session_id:e.session_id,matched_at:e.matched_at,title:s,alias:e.alias,auto_title:e.auto_title,project:e.project,started_at:e.started_at}}function Pa(e){let t=f(),s=t.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);if(!s)return null;let n=t.prepare(`SELECT m.cluster_id, m.session_id, m.matched_at,
990
+ LIMIT ? OFFSET ?`).all(...n,a,c).map(Oe),total:o.n}}function Bg(e){let t=e.first_user_message?e.first_user_message.slice(0,80):null,s=e.alias??e.auto_title??t??e.session_id.slice(0,8);return{cluster_id:e.cluster_id,session_id:e.session_id,matched_at:e.matched_at,title:s,alias:e.alias,auto_title:e.auto_title,project:e.project,started_at:e.started_at}}function $a(e){let t=f(),s=t.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);if(!s)return null;let n=t.prepare(`SELECT m.cluster_id, m.session_id, m.matched_at,
991
991
  NULLIF(sa.alias, '') AS alias,
992
992
  s.auto_title,
993
993
  s.first_user_message,
@@ -998,26 +998,26 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
998
998
  LEFT JOIN session_aliases sa ON sa.session_id = m.session_id
999
999
  LEFT JOIN projects p ON p.id = s.project_id
1000
1000
  WHERE m.cluster_id = ?
1001
- ORDER BY COALESCE(s.started_at, ''), m.matched_at, m.session_id`).all(e);return{cluster:Oe(s),members:n.map(Bg)}}function Ua(e,t,s){if(!e)throw new Error("clusterId is required");if(!t)throw new Error("sessionId is required");if(typeof s!="string"||!s.trim())throw new Error("fixSummary is required");let n=f();if(!n.prepare("SELECT 1 FROM bug_pattern_clusters WHERE id = ?").get(e))throw new Error(`cluster ${e} not found`);if(!n.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}`);n.prepare(`UPDATE bug_pattern_clusters
1001
+ ORDER BY COALESCE(s.started_at, ''), m.matched_at, m.session_id`).all(e);return{cluster:Oe(s),members:n.map(Bg)}}function Ba(e,t,s){if(!e)throw new Error("clusterId is required");if(!t)throw new Error("sessionId is required");if(typeof s!="string"||!s.trim())throw new Error("fixSummary is required");let n=f();if(!n.prepare("SELECT 1 FROM bug_pattern_clusters WHERE id = ?").get(e))throw new Error(`cluster ${e} not found`);if(!n.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}`);n.prepare(`UPDATE bug_pattern_clusters
1002
1002
  SET resolved_in_session_id = ?, fix_summary = ?
1003
- WHERE id = ?`).run(t,s.trim(),e),vt(e);let a=n.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);return{cluster:Oe(a)}}function $a(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 s=f(),n=s.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);if(!n)throw new Error(`cluster ${e} not found`);let r=Array.from(new Set(t)),o=r.map(()=>"?").join(","),a=s.prepare(`SELECT session_id, matched_at FROM bug_pattern_members
1004
- 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=s.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 d=Ia(),u=new Date().toISOString(),g=[];s.transaction(()=>{s.prepare(`INSERT INTO bug_pattern_clusters
1003
+ WHERE id = ?`).run(t,s.trim(),e),vt(e);let a=n.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);return{cluster:Oe(a)}}function Ha(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 s=f(),n=s.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e);if(!n)throw new Error(`cluster ${e} not found`);let r=Array.from(new Set(t)),o=r.map(()=>"?").join(","),a=s.prepare(`SELECT session_id, matched_at FROM bug_pattern_members
1004
+ 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=s.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 d=ja(),u=new Date().toISOString(),g=[];s.transaction(()=>{s.prepare(`INSERT INTO bug_pattern_clusters
1005
1005
  (id, signature_hash, example_message, occurrence_count,
1006
1006
  first_seen_at, last_seen_at, resolved_in_session_id, fix_summary)
1007
1007
  VALUES (?, ?, ?, ?, ?, ?, NULL, NULL)`).run(d,n.signature_hash,n.example_message,a.length,n.first_seen_at,u);let S=s.prepare(`INSERT INTO bug_pattern_members (cluster_id, session_id, matched_at)
1008
- VALUES (?, ?, ?)`),y=s.prepare("DELETE FROM bug_pattern_members WHERE cluster_id = ? AND session_id = ?");for(let w of a)S.run(d,w.session_id,w.matched_at),y.run(e,w.session_id);let k=c-a.length;s.prepare("UPDATE bug_pattern_clusters SET occurrence_count = ? WHERE id = ?").run(k,e),g=s.prepare("SELECT * FROM bug_pattern_members WHERE cluster_id = ?").all(d)})(),vt(e),vt(d);let h=s.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e),b=s.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(d);return{original:Oe(h),split:Oe(b),movedMembers:g.map(va)}}function vt(e){try{$g();let t=Ma(e);if(!t)return;let s=Ca(Qn,`${e}.json`),n={schema:"claude-recall.bug-pattern-cluster.v1",cluster:t.cluster,members:t.members,backed_up_at:new Date().toISOString()};Fg(s,JSON.stringify(n,null,2))}catch(t){console.error("[bug-patterns] backup failed:",t)}}function Ba(e){return e?f().prepare(`SELECT * FROM bug_pattern_clusters
1008
+ VALUES (?, ?, ?)`),y=s.prepare("DELETE FROM bug_pattern_members WHERE cluster_id = ? AND session_id = ?");for(let w of a)S.run(d,w.session_id,w.matched_at),y.run(e,w.session_id);let k=c-a.length;s.prepare("UPDATE bug_pattern_clusters SET occurrence_count = ? WHERE id = ?").run(k,e),g=s.prepare("SELECT * FROM bug_pattern_members WHERE cluster_id = ?").all(d)})(),vt(e),vt(d);let h=s.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(e),b=s.prepare("SELECT * FROM bug_pattern_clusters WHERE id = ?").get(d);return{original:Oe(h),split:Oe(b),movedMembers:g.map(Ma)}}function vt(e){try{$g();let t=Fa(e);if(!t)return;let s=va(tr,`${e}.json`),n={schema:"claude-recall.bug-pattern-cluster.v1",cluster:t.cluster,members:t.members,backed_up_at:new Date().toISOString()};Fg(s,JSON.stringify(n,null,2))}catch(t){console.error("[bug-patterns] backup failed:",t)}}function Wa(e){return e?f().prepare(`SELECT * FROM bug_pattern_clusters
1009
1009
  WHERE signature_hash = ?
1010
- ORDER BY last_seen_at DESC, id ASC`).all(e).map(Oe):[]}function Ha(e){if(!e)return new Set;let s=f().prepare(`SELECT DISTINCT m.session_id
1010
+ ORDER BY last_seen_at DESC, id ASC`).all(e).map(Oe):[]}function qa(e){if(!e)return new Set;let s=f().prepare(`SELECT DISTINCT m.session_id
1011
1011
  FROM bug_pattern_members m
1012
1012
  JOIN bug_pattern_clusters c ON c.id = m.cluster_id
1013
- WHERE c.signature_hash = ?`).all(e);return new Set(s.map(n=>n.session_id))}import{randomUUID as y_}from"node:crypto";H();Z();import{writeFileSync as Gg,mkdirSync as Yg,existsSync as Kg}from"node:fs";import{join as Va}from"node:path";H();var Wa=80;function qa(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 s=t.split(`
1014
- `)[0].trim();return s.length>Wa?s.slice(0,Wa)+"\u2026":s}function Hg(e){return f().prepare(`SELECT s.id AS id,
1013
+ WHERE c.signature_hash = ?`).all(e);return new Set(s.map(n=>n.session_id))}import{randomUUID as y_}from"node:crypto";H();Z();import{writeFileSync as Gg,mkdirSync as Yg,existsSync as Kg}from"node:fs";import{join as Qa}from"node:path";H();var Ja=80;function Xa(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 s=t.split(`
1014
+ `)[0].trim();return s.length>Ja?s.slice(0,Ja)+"\u2026":s}function Hg(e){return f().prepare(`SELECT s.id AS id,
1015
1015
  sa.alias AS alias,
1016
1016
  s.auto_title AS auto_title,
1017
1017
  s.first_user_message AS first_user_message
1018
1018
  FROM sessions s
1019
1019
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1020
- WHERE s.id = ?`).get(e)??null}function Wg(e){let t=Hg(e);return t?qa(t):e.slice(0,8)}function Ja(e){if(!e)return null;let t=f(),s=t.prepare(`SELECT e.thread_id AS thread_id,
1020
+ WHERE s.id = ?`).get(e)??null}function Wg(e){let t=Hg(e);return t?Xa(t):e.slice(0,8)}function Ga(e){if(!e)return null;let t=f(),s=t.prepare(`SELECT e.thread_id AS thread_id,
1021
1021
  t.name AS thread_name,
1022
1022
  e.parent_session_id AS parent_session_id,
1023
1023
  e.added_at AS added_at
@@ -1036,9 +1036,9 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
1036
1036
  LEFT JOIN session_aliases sa ON sa.session_id = e.session_id
1037
1037
  WHERE e.thread_id = ?
1038
1038
  AND e.session_id NOT IN (${o})
1039
- ORDER BY e.added_at ASC`).all(s.thread_id,...r).map(d=>({id:d.session_id,title:d.id?qa(d):d.session_id.slice(0,8)}));return{thread_id:s.thread_id,thread_name:s.thread_name,parent_session:n,siblings:c}}var Xa=[/^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 er(e){return Xa.some(t=>t.test(e))}var qg=[/^Score this person'?s relevance/i,/^You are a [^\n.]{1,60}co-pilot/i,/^Return ONLY valid JSON/i],Jg=[/^Draft (a|an|marketing) [a-z]/i,/^Read the file at /i,/^Read this and then begin/i,/^read this and then begin/i],Xg=20;function jt(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<Xg)return"low_signal";for(let t of Xa)if(t.test(e.auto_title))return"recursive_meta";for(let t of qg)if(t.test(e.auto_title))return"programmatic";for(let t of Jg)if(t.test(e.auto_title))return"template_pending";return"clean"}function Ls(e){if(!e)return"";let t=e.split("|")[0];return t=t.replace(/\s*\([^)]*\)\s*$/,""),t=t.replace(/\s+/g," ").trim(),t}function Ga(e){if(!e)return e;let t=e.lastIndexOf(" \xB7 ");if(t===-1)return e;let s=e.slice(0,t),n=e.slice(t+3),r=Ls(n);return!r||r===n?e:`${s} \xB7 ${r}`}var nr=Va($,"titles"),zg=80,Vg=60,Zg=100,Qg=50,Mt=5,Cs=15,e_=500;function Za(e){if(!e)return[];try{let t=JSON.parse(e);if(Array.isArray(t))return t.filter(s=>!!s&&typeof s=="object"&&typeof s.title=="string"&&typeof s.replaced_at=="string")}catch{}return[]}function et(e){if(!e)return null;let t=e;if(t=t.replace(/```[\s\S]*?```/g," "),t=t.replace(/`[^`]+`/g," "),t=t.replace(/https?:\/\/\S+/g,"[url]"),t=t.replace(/\s+/g," ").trim(),!t)return null;let s=t_(t,e);if(s)return s;let n=t.match(/^[^.!?\n]{8,}?[.!?]/)?.[0]?.trim();return(n&&n.length<=zg?n:t.slice(0,Vg)).trim()||null}function t_(e,t){let s=e.match(/^\/([A-Za-z0-9][A-Za-z0-9_-]*)\s+([\s\S]*)$/);if(s){let n=`/${s[1]}`,r=t.replace(/^\s*\/[A-Za-z0-9][A-Za-z0-9_-]*\s+/,""),o=rr(r);return o?Qe(`${n} \xB7 ${o}`):n}for(let n of s_){if(!e.match(n.match))continue;let o=n.prefix,a=n.extract?n.extract(e,t):rr(t);return a?n.completeFromExtract?Qe(a):Qe(`${o} \xB7 ${a}`):o}for(let n of o_){if(!e.match(n.match))continue;let o=n.extract?n.extract(e,t):Is(t);return o?n.completeFromExtract?Qe(o):Qe(`${n.prefix} \xB7 ${o}`):n.prefix}return null}var s_=[{match:/^Draft (?:a|an) brand brief\b/i,prefix:"Draft brand brief"},{match:/^Draft (?:a|an) sales brief\b/i,prefix:"Draft sales brief"},{match:/^Draft (?:a|an) leave-behind\b/i,prefix:"Draft leave-behind"},{match:/^Draft (?:a|an) audio identity brief\b/i,prefix:"Draft audio identity brief"},{match:/^Draft marketing ideas\b/i,prefix:"Draft marketing ideas"},{match:/^Draft (?:a|an) ([a-z]{3,30}(?:\s+[a-z]{3,30}){0,2})\b/i,prefix:"Draft",extract:(e,t)=>{let n=e.match(/^Draft (?:a|an) ([a-z]{3,30}(?:\s+[a-z]{3,30}){0,2})\b/i)?.[1]?.trim(),r=rr(t);return n&&r?`${n} \xB7 ${r}`:n||r}},{match:/^Read the file at /i,prefix:"Read",extract:e=>{let s=e.match(/^Read the file at\s+([^\s]+)/i)?.[1];return s?s.split("/").filter(Boolean).slice(-2).join("/")||s:null}},{match:/^(?:read|inspect) this and then begin\b/i,prefix:"Begin from preamble",completeFromExtract:!0,extract:(e,t)=>r_(t)},{match:/^Base directory for this skill:/i,prefix:"[skill]",completeFromExtract:!0,extract:(e,t)=>{let s=t.match(/\.claude\/skills\/([^/\s]+)/);return s?.[1]?`[skill] ${s[1]}`:null}},{match:/^You are extracting a structured Output Index/i,prefix:"[output-index]",completeFromExtract:!0,extract:(e,t)=>n_(t)},{match:/^You will receive a sample of user messages from a Claude Code session:/i,prefix:"[meta]",completeFromExtract:!0,extract:(e,t)=>Ya(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)=>Ya(t,"[meta] auto-title (initial)")},{match:/^You are implementing v\d+\.\d+/i,prefix:"Implementing",completeFromExtract:!0,extract:e=>{let t=e.match(/^You are implementing (v\d+\.\d+\w*)\s*(?:\(([^)]+)\))?/i);if(!t)return null;let s=t[1],n=t[2]?.trim();return n?`Implementing ${s} \xB7 ${n}`:`Implementing ${s}`}}];function n_(e){if(!e)return"[output-index] extractor";let t=e.match(/^Session:\s*([0-9a-f]{8})\b/im),s=e.match(/^Opening prompt:\s*([^\n]{1,140})/im),n=t?.[1]?.trim(),r=s?.[1]?.trim().replace(/\s+/g," "),o=r&&r.length>70?r.slice(0,67)+"\u2026":r;return n&&o?`[output-index] \xB7 ${n} \xB7 ${o}`:n?`[output-index] \xB7 ${n}`:o?`[output-index] \xB7 ${o}`:"[output-index] extractor"}function Ya(e,t){if(!e)return t;let s=e.indexOf("Messages:");if(s===-1)return t;let n=e.slice(s+9),r=/^\s*\d+\.\s*([^\n]+)/gm;for(let o of n.matchAll(r)){let 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 d=c.length>60?c.slice(0,57)+"\u2026":c;return`${t} \xB7 ${d}`}return t}function r_(e){if(!e)return null;let t=e.match(/([\/\w.\-]+\.(?:md|markdown|txt|json|yaml|yml|toml|ts|tsx|js|jsx|py|sql))(?=[\s,;:)\]"'`]|$)/i);if(!t)return null;let s=t[1].split("/").filter(Boolean);return(s[s.length-1]??"").replace(/\.[^.]+$/,"")||null}var o_=[{match:/^Score this person'?s relevance/i,prefix:"Score relevance",extract:(e,t)=>Is(t)},{match:/^You are a [^\n.]{1,60}co-pilot/i,prefix:"co-pilot",completeFromExtract:!0,extract:(e,t)=>{let n=e.match(/^You are a ([^\n.]{1,60}?)co-pilot/i)?.[1]?.trim(),r=n?`${n} co-pilot`:"co-pilot",o=Is(t);return o?`${r} \xB7 ${o}`:r}},{match:/^Return ONLY valid JSON/i,prefix:"JSON-only",extract:(e,t)=>Is(t)}];function Is(e){let t=/^\s*(Name|Company|Prospect|Author|Brand|Client)\s*:\s*([^\n]+)/gim,s;for(;(s=t.exec(e))!==null;){let n=s[2].trim();if(!n||/^(null|none|n\/a|—|-)$/i.test(n))continue;let r=n.replace(/\s+/g," ");return Ls(r)||r}return null}function Qe(e){return e.slice(0,Zg).trim()}var i_=[/^deep research$/i,/^reference(?: spec)?$/i,/^canonical spec/i,/^product context/i,/^services?(?: overview)?$/i,/^overview$/i,/^(?:introduction|template|instructions|context)$/i],a_=[/^(?: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 tr(e){let t=e.trim();return t.length<3?!0:i_.some(s=>s.test(t))}function c_(e){let t=e.trim().replace(/\s*\([^)]*\)\s*$/,"").trim();return a_.some(s=>s.test(t))}function rr(e){let t=l_(e);return t===null?null:Ls(t)||t}function l_(e){if(/^\s*Skill smoke test\b/i.test(e))return"smoke test";let t=/(^|\n)#{1,3}\s+([^\n]+?)\s+(?:—|–|-|:)\s+([^\n]{2,80})/g,s,n=[];for(;(s=t.exec(e))!==null;){let d=s[2].trim(),u=s[3].trim().replace(/\s+/g," ");if(!tr(u)){if(c_(d))return u;n.push(u)}}if(n.length>0)return n[0];let r=e.match(/\b(?:Topic|Subject|Brand|About|Client|For|Re)\s*:\s*([^\n]{2,80})/i);if(r?.[1]&&!tr(r[1]))return r[1].trim().replace(/\s+/g," ");let o=/===\s*([^=\n]{2,120}?)\s*===/g;for(;(s=o.exec(e))!==null;){let d=s[1].trim().replace(/\.(md|txt|json)$/i,""),u=d.replace(/\s*\([^)]*\)\s*$/,"").trim();if(u&&!tr(u)&&!/product context|reference/i.test(d))return u}let a=e.replace(/^Context for this run[^:]*:\s*/i,"");if(a!==e){let d=a.split(`
1039
+ ORDER BY e.added_at ASC`).all(s.thread_id,...r).map(d=>({id:d.session_id,title:d.id?Xa(d):d.session_id.slice(0,8)}));return{thread_id:s.thread_id,thread_name:s.thread_name,parent_session:n,siblings:c}}var Ya=[/^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 sr(e){return Ya.some(t=>t.test(e))}var qg=[/^Score this person'?s relevance/i,/^You are a [^\n.]{1,60}co-pilot/i,/^Return ONLY valid JSON/i],Jg=[/^Draft (a|an|marketing) [a-z]/i,/^Read the file at /i,/^Read this and then begin/i,/^read this and then begin/i],Xg=20;function jt(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<Xg)return"low_signal";for(let t of Ya)if(t.test(e.auto_title))return"recursive_meta";for(let t of qg)if(t.test(e.auto_title))return"programmatic";for(let t of Jg)if(t.test(e.auto_title))return"template_pending";return"clean"}function Ls(e){if(!e)return"";let t=e.split("|")[0];return t=t.replace(/\s*\([^)]*\)\s*$/,""),t=t.replace(/\s+/g," ").trim(),t}function Ka(e){if(!e)return e;let t=e.lastIndexOf(" \xB7 ");if(t===-1)return e;let s=e.slice(0,t),n=e.slice(t+3),r=Ls(n);return!r||r===n?e:`${s} \xB7 ${r}`}var or=Qa($,"titles"),zg=80,Vg=60,Zg=100,Qg=50,Mt=5,Cs=15,e_=500;function ec(e){if(!e)return[];try{let t=JSON.parse(e);if(Array.isArray(t))return t.filter(s=>!!s&&typeof s=="object"&&typeof s.title=="string"&&typeof s.replaced_at=="string")}catch{}return[]}function et(e){if(!e)return null;let t=e;if(t=t.replace(/```[\s\S]*?```/g," "),t=t.replace(/`[^`]+`/g," "),t=t.replace(/https?:\/\/\S+/g,"[url]"),t=t.replace(/\s+/g," ").trim(),!t)return null;let s=t_(t,e);if(s)return s;let n=t.match(/^[^.!?\n]{8,}?[.!?]/)?.[0]?.trim();return(n&&n.length<=zg?n:t.slice(0,Vg)).trim()||null}function t_(e,t){let s=e.match(/^\/([A-Za-z0-9][A-Za-z0-9_-]*)\s+([\s\S]*)$/);if(s){let n=`/${s[1]}`,r=t.replace(/^\s*\/[A-Za-z0-9][A-Za-z0-9_-]*\s+/,""),o=ir(r);return o?Qe(`${n} \xB7 ${o}`):n}for(let n of s_){if(!e.match(n.match))continue;let o=n.prefix,a=n.extract?n.extract(e,t):ir(t);return a?n.completeFromExtract?Qe(a):Qe(`${o} \xB7 ${a}`):o}for(let n of o_){if(!e.match(n.match))continue;let o=n.extract?n.extract(e,t):Is(t);return o?n.completeFromExtract?Qe(o):Qe(`${n.prefix} \xB7 ${o}`):n.prefix}return null}var s_=[{match:/^Draft (?:a|an) brand brief\b/i,prefix:"Draft brand brief"},{match:/^Draft (?:a|an) sales brief\b/i,prefix:"Draft sales brief"},{match:/^Draft (?:a|an) leave-behind\b/i,prefix:"Draft leave-behind"},{match:/^Draft (?:a|an) audio identity brief\b/i,prefix:"Draft audio identity brief"},{match:/^Draft marketing ideas\b/i,prefix:"Draft marketing ideas"},{match:/^Draft (?:a|an) ([a-z]{3,30}(?:\s+[a-z]{3,30}){0,2})\b/i,prefix:"Draft",extract:(e,t)=>{let n=e.match(/^Draft (?:a|an) ([a-z]{3,30}(?:\s+[a-z]{3,30}){0,2})\b/i)?.[1]?.trim(),r=ir(t);return n&&r?`${n} \xB7 ${r}`:n||r}},{match:/^Read the file at /i,prefix:"Read",extract:e=>{let s=e.match(/^Read the file at\s+([^\s]+)/i)?.[1];return s?s.split("/").filter(Boolean).slice(-2).join("/")||s:null}},{match:/^(?:read|inspect) this and then begin\b/i,prefix:"Begin from preamble",completeFromExtract:!0,extract:(e,t)=>r_(t)},{match:/^Base directory for this skill:/i,prefix:"[skill]",completeFromExtract:!0,extract:(e,t)=>{let s=t.match(/\.claude\/skills\/([^/\s]+)/);return s?.[1]?`[skill] ${s[1]}`:null}},{match:/^You are extracting a structured Output Index/i,prefix:"[output-index]",completeFromExtract:!0,extract:(e,t)=>n_(t)},{match:/^You will receive a sample of user messages from a Claude Code session:/i,prefix:"[meta]",completeFromExtract:!0,extract:(e,t)=>za(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)=>za(t,"[meta] auto-title (initial)")},{match:/^You are implementing v\d+\.\d+/i,prefix:"Implementing",completeFromExtract:!0,extract:e=>{let t=e.match(/^You are implementing (v\d+\.\d+\w*)\s*(?:\(([^)]+)\))?/i);if(!t)return null;let s=t[1],n=t[2]?.trim();return n?`Implementing ${s} \xB7 ${n}`:`Implementing ${s}`}}];function n_(e){if(!e)return"[output-index] extractor";let t=e.match(/^Session:\s*([0-9a-f]{8})\b/im),s=e.match(/^Opening prompt:\s*([^\n]{1,140})/im),n=t?.[1]?.trim(),r=s?.[1]?.trim().replace(/\s+/g," "),o=r&&r.length>70?r.slice(0,67)+"\u2026":r;return n&&o?`[output-index] \xB7 ${n} \xB7 ${o}`:n?`[output-index] \xB7 ${n}`:o?`[output-index] \xB7 ${o}`:"[output-index] extractor"}function za(e,t){if(!e)return t;let s=e.indexOf("Messages:");if(s===-1)return t;let n=e.slice(s+9),r=/^\s*\d+\.\s*([^\n]+)/gm;for(let o of n.matchAll(r)){let 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 d=c.length>60?c.slice(0,57)+"\u2026":c;return`${t} \xB7 ${d}`}return t}function r_(e){if(!e)return null;let t=e.match(/([\/\w.\-]+\.(?:md|markdown|txt|json|yaml|yml|toml|ts|tsx|js|jsx|py|sql))(?=[\s,;:)\]"'`]|$)/i);if(!t)return null;let s=t[1].split("/").filter(Boolean);return(s[s.length-1]??"").replace(/\.[^.]+$/,"")||null}var o_=[{match:/^Score this person'?s relevance/i,prefix:"Score relevance",extract:(e,t)=>Is(t)},{match:/^You are a [^\n.]{1,60}co-pilot/i,prefix:"co-pilot",completeFromExtract:!0,extract:(e,t)=>{let n=e.match(/^You are a ([^\n.]{1,60}?)co-pilot/i)?.[1]?.trim(),r=n?`${n} co-pilot`:"co-pilot",o=Is(t);return o?`${r} \xB7 ${o}`:r}},{match:/^Return ONLY valid JSON/i,prefix:"JSON-only",extract:(e,t)=>Is(t)}];function Is(e){let t=/^\s*(Name|Company|Prospect|Author|Brand|Client)\s*:\s*([^\n]+)/gim,s;for(;(s=t.exec(e))!==null;){let n=s[2].trim();if(!n||/^(null|none|n\/a|—|-)$/i.test(n))continue;let r=n.replace(/\s+/g," ");return Ls(r)||r}return null}function Qe(e){return e.slice(0,Zg).trim()}var i_=[/^deep research$/i,/^reference(?: spec)?$/i,/^canonical spec/i,/^product context/i,/^services?(?: overview)?$/i,/^overview$/i,/^(?:introduction|template|instructions|context)$/i],a_=[/^(?: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 nr(e){let t=e.trim();return t.length<3?!0:i_.some(s=>s.test(t))}function c_(e){let t=e.trim().replace(/\s*\([^)]*\)\s*$/,"").trim();return a_.some(s=>s.test(t))}function ir(e){let t=l_(e);return t===null?null:Ls(t)||t}function l_(e){if(/^\s*Skill smoke test\b/i.test(e))return"smoke test";let t=/(^|\n)#{1,3}\s+([^\n]+?)\s+(?:—|–|-|:)\s+([^\n]{2,80})/g,s,n=[];for(;(s=t.exec(e))!==null;){let d=s[2].trim(),u=s[3].trim().replace(/\s+/g," ");if(!nr(u)){if(c_(d))return u;n.push(u)}}if(n.length>0)return n[0];let r=e.match(/\b(?:Topic|Subject|Brand|About|Client|For|Re)\s*:\s*([^\n]{2,80})/i);if(r?.[1]&&!nr(r[1]))return r[1].trim().replace(/\s+/g," ");let o=/===\s*([^=\n]{2,120}?)\s*===/g;for(;(s=o.exec(e))!==null;){let d=s[1].trim().replace(/\.(md|txt|json)$/i,""),u=d.replace(/\s*\([^)]*\)\s*$/,"").trim();if(u&&!nr(u)&&!/product context|reference/i.test(d))return u}let a=e.replace(/^Context for this run[^:]*:\s*/i,"");if(a!==e){let d=a.split(`
1040
1040
  `).map(u=>u.trim()).find(u=>u.length>=4);if(d)return d.slice(0,60)}let c=e.split(`
1041
- `).map(d=>d.trim()).find(d=>d.length>=4);return c?c.slice(0,60):null}function or(e){let t=f(),s=t.prepare(`SELECT rowid AS rid, content_text
1041
+ `).map(d=>d.trim()).find(d=>d.length>=4);return c?c.slice(0,60):null}function ar(e){let t=f(),s=t.prepare(`SELECT rowid AS rid, content_text
1042
1042
  FROM messages
1043
1043
  WHERE session_id = ? AND role = 'user' AND is_sidechain = 0
1044
1044
  AND content_text IS NOT NULL AND content_text != ''
@@ -1050,19 +1050,19 @@ kEgDDGWLdQN7jrx/W+Nxz9yOJbwTPDI4jv24IztWSEtJuqH+0KvrDbdfFA==
1050
1050
  ORDER BY COALESCE(timestamp, '') DESC, rowid DESC
1051
1051
  LIMIT ?`).all(e,Cs),r=new Map;for(let g of s)r.set(g.rid,g.content_text);for(let g of n)r.set(g.rid,g.content_text);if(r.size===0)throw new Error("no user messages available to summarise");let o=Array.from(r.entries()).sort((g,h)=>g[0]-h[0]).map(([,g])=>({content_text:g})),a=s.length===Mt&&n.length===Cs&&r.size===Mt+Cs,c=o.map((g,h)=>{let b=(g.content_text??"").slice(0,e_);return a&&h===Mt?`--- (middle of session omitted) ---
1052
1052
  ${h+1}. ${b}`:`${h+1}. ${b}`}).join(`
1053
- `),d=null;try{d=Ja(e)}catch(g){console.error("[autoTitle] thread context resolution failed:",g),d=null}let u=[];return d&&(u.push(d_(d)),u.push("")),u.push(`You will receive a sample of user messages from a Claude Code session: the first ${Mt}`,`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),u.join(`
1054
- `)}var sr=5;function d_(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 s=e.siblings.length;if(s>0){let r=e.siblings.slice(0,sr).map(a=>`"${a.title}"`).join(", "),o=s>sr?`, and ${s-sr} more`:"";t.push(`- Sibling sessions (${s}): ${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(`
1055
- `)}async function Qa(e){let t=or(e),{spawnClaudePrompt:s,isClaudeCliAvailable:n}=await Promise.resolve().then(()=>(ge(),Pe));if(!n())throw new Error("claude CLI not found on PATH");let r=await s(t,[],{});if(!r.success)throw new Error(`claude CLI exited ${r.exitCode}: ${r.stderr.slice(-500)}`);let o=u_(r.stdout);if(!o)throw new Error("claude CLI returned an empty title");return o.slice(0,Qg)}function u_(e){let t=e.trim();if(!t)return"";try{let s=JSON.parse(t);if(s&&typeof s=="object"){let n=s.result;if(typeof n=="string")return Ka(n)}}catch{}return Ka(t)}function Ka(e){return e.trim().replace(/^["'`]+|["'`]+$/g,"").replace(/\s+/g," ").replace(/[.!?]+$/g,"").trim()}function de(e,t,s){let n=t.trim();if(!n)return;let r=f(),o=r.prepare(`SELECT auto_title, auto_title_source, auto_title_generated_at, auto_title_history
1056
- FROM sessions WHERE id = ?`).get(e);if(!o||s==="heuristic"&&o.auto_title_source==="agent"&&o.auto_title||o.auto_title===n&&o.auto_title_source===s)return;let a=Za(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
1053
+ `),d=null;try{d=Ga(e)}catch(g){console.error("[autoTitle] thread context resolution failed:",g),d=null}let u=[];return d&&(u.push(d_(d)),u.push("")),u.push(`You will receive a sample of user messages from a Claude Code session: the first ${Mt}`,`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),u.join(`
1054
+ `)}var rr=5;function d_(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 s=e.siblings.length;if(s>0){let r=e.siblings.slice(0,rr).map(a=>`"${a.title}"`).join(", "),o=s>rr?`, and ${s-rr} more`:"";t.push(`- Sibling sessions (${s}): ${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(`
1055
+ `)}async function tc(e){let t=ar(e),{spawnClaudePrompt:s,isClaudeCliAvailable:n}=await Promise.resolve().then(()=>(ge(),Pe));if(!n())throw new Error("claude CLI not found on PATH");let r=await s(t,[],{});if(!r.success)throw new Error(`claude CLI exited ${r.exitCode}: ${r.stderr.slice(-500)}`);let o=u_(r.stdout);if(!o)throw new Error("claude CLI returned an empty title");return o.slice(0,Qg)}function u_(e){let t=e.trim();if(!t)return"";try{let s=JSON.parse(t);if(s&&typeof s=="object"){let n=s.result;if(typeof n=="string")return Va(n)}}catch{}return Va(t)}function Va(e){return e.trim().replace(/^["'`]+|["'`]+$/g,"").replace(/\s+/g," ").replace(/[.!?]+$/g,"").trim()}function de(e,t,s){let n=t.trim();if(!n)return;let r=f(),o=r.prepare(`SELECT auto_title, auto_title_source, auto_title_generated_at, auto_title_history
1056
+ FROM sessions WHERE id = ?`).get(e);if(!o||s==="heuristic"&&o.auto_title_source==="agent"&&o.auto_title||o.auto_title===n&&o.auto_title_source===s)return;let a=ec(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
1057
1057
  SET auto_title = ?,
1058
1058
  auto_title_source = ?,
1059
1059
  auto_title_generated_at = ?,
1060
1060
  auto_title_history = ?
1061
1061
  WHERE id = ?`).run(n,s,Date.now(),JSON.stringify(a),e),__(e,n,s,c)}function Te(e){let t=f().prepare(`SELECT auto_title, auto_title_source, auto_title_generated_at, auto_title_history
1062
- 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:Za(t.auto_title_history)}:null}function ec(){let t=f().prepare(`SELECT id, first_user_message
1062
+ 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:ec(t.auto_title_history)}:null}function sc(){let t=f().prepare(`SELECT id, first_user_message
1063
1063
  FROM sessions
1064
1064
  WHERE auto_title IS NULL
1065
- AND first_user_message IS NOT NULL`).all(),s=0;for(let n of t){let r=et(n.first_user_message);r&&(de(n.id,r,"heuristic"),s+=1)}return{updated:s}}function tc(e){let t=f(),s=e?.projectId?" AND s.project_id = ?":"",n=e?.projectId?[e.projectId,e.projectId]:[],r=t.prepare(`WITH dups AS (
1065
+ AND first_user_message IS NOT NULL`).all(),s=0;for(let n of t){let r=et(n.first_user_message);r&&(de(n.id,r,"heuristic"),s+=1)}return{updated:s}}function nc(e){let t=f(),s=e?.projectId?" AND s.project_id = ?":"",n=e?.projectId?[e.projectId,e.projectId]:[],r=t.prepare(`WITH dups AS (
1066
1066
  SELECT auto_title, project_id
1067
1067
  FROM sessions
1068
1068
  WHERE auto_title IS NOT NULL
@@ -1115,7 +1115,7 @@ ${h+1}. ${b}`:`${h+1}. ${b}`}).join(`
1115
1115
  AND content_text IS NOT NULL
1116
1116
  AND content_text != ''
1117
1117
  ORDER BY COALESCE(timestamp, ''), rowid ASC
1118
- LIMIT 8`),a=0,c=0;for(let d of r){a+=1;let u=o.all(d.id),g=null;for(let h of u){let b=h.content_text.replace(/^(?:<[^>]+>[\s\S]*?<\/[^>]+>\s*)+/,"").trim();if(!b||/^<local-command-caveat>/.test(b))continue;let S=et(b);if(S&&!za(S)){g=S;break}}if(!g){let h=u.map(S=>S.content_text.replace(/^(?:<[^>]+>[\s\S]*?<\/[^>]+>\s*)+/,"").trim()).find(S=>S.length>0&&!/^<local-command-caveat>/.test(S)),b=h?et(h):null;b&&za(b)&&(g=`[vacuous] ${b}`)}g&&(de(d.id,g,"heuristic"),c+=1)}return{scanned:a,updated:c}}function za(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(n=>n.test(t))}function sc(e){let t=f(),s=e?.projectId?" AND s.project_id = ?":"",n=e?.projectId?[e.projectId]:[],r=t.prepare(`SELECT s.id, s.auto_title
1118
+ LIMIT 8`),a=0,c=0;for(let d of r){a+=1;let u=o.all(d.id),g=null;for(let h of u){let b=h.content_text.replace(/^(?:<[^>]+>[\s\S]*?<\/[^>]+>\s*)+/,"").trim();if(!b||/^<local-command-caveat>/.test(b))continue;let S=et(b);if(S&&!Za(S)){g=S;break}}if(!g){let h=u.map(S=>S.content_text.replace(/^(?:<[^>]+>[\s\S]*?<\/[^>]+>\s*)+/,"").trim()).find(S=>S.length>0&&!/^<local-command-caveat>/.test(S)),b=h?et(h):null;b&&Za(b)&&(g=`[vacuous] ${b}`)}g&&(de(d.id,g,"heuristic"),c+=1)}return{scanned:a,updated:c}}function Za(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(n=>n.test(t))}function rc(e){let t=f(),s=e?.projectId?" AND s.project_id = ?":"",n=e?.projectId?[e.projectId]:[],r=t.prepare(`SELECT s.id, s.auto_title
1119
1119
  FROM sessions s
1120
1120
  WHERE s.auto_title_source = 'heuristic'${s}
1121
1121
  AND (
@@ -1130,23 +1130,23 @@ ${h+1}. ${b}`:`${h+1}. ${b}`}).join(`
1130
1130
  AND content_text IS NOT NULL
1131
1131
  AND content_text != ''
1132
1132
  ORDER BY COALESCE(timestamp, ''), rowid ASC
1133
- LIMIT 10`),a=0,c=0;for(let d of r){a+=1;let u=o.all(d.id),g=p_(u,d.auto_title);g&&(de(d.id,g,"heuristic"),c+=1)}return{scanned:a,updated:c}}function p_(e,t){for(let s of e){let n=m_(s.content_text);if(!n||er(n))continue;let r=et(n);if(r){if(r===t)return null;if(!er(r))return r}}return t.startsWith("[meta]")?null:Qe(`[meta] ${t}`)}function nc(e){let t=f(),s=e?.projectId?" AND s.project_id = ?":"",n=e?.projectId?[e.projectId]:[],r=t.prepare(`SELECT s.id, s.auto_title
1133
+ LIMIT 10`),a=0,c=0;for(let d of r){a+=1;let u=o.all(d.id),g=p_(u,d.auto_title);g&&(de(d.id,g,"heuristic"),c+=1)}return{scanned:a,updated:c}}function p_(e,t){for(let s of e){let n=m_(s.content_text);if(!n||sr(n))continue;let r=et(n);if(r){if(r===t)return null;if(!sr(r))return r}}return t.startsWith("[meta]")?null:Qe(`[meta] ${t}`)}function oc(e){let t=f(),s=e?.projectId?" AND s.project_id = ?":"",n=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'${s}
1136
1136
  AND s.auto_title IS NOT NULL
1137
1137
  AND s.auto_title LIKE '% \xB7 %'
1138
- AND (s.auto_title LIKE '%|%' OR s.auto_title LIKE '%(%')`).all(...n),o=0,a=0;for(let c of r){o+=1;let d=Ga(c.auto_title);d!==c.auto_title&&(de(c.id,d,"heuristic"),a+=1)}return{scanned:o,updated:a}}function m_(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 g_(){J(),Kg(nr)||Yg(nr,{recursive:!0})}function __(e,t,s,n){try{g_();let r=Va(nr,`${e}.txt`),o=`# Claude Recall auto-title \xB7 session ${e} \xB7 source ${s} \xB7 updated ${n}
1138
+ AND (s.auto_title LIKE '%|%' OR s.auto_title LIKE '%(%')`).all(...n),o=0,a=0;for(let c of r){o+=1;let d=Ka(c.auto_title);d!==c.auto_title&&(de(c.id,d,"heuristic"),a+=1)}return{scanned:o,updated:a}}function m_(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 g_(){J(),Kg(or)||Yg(or,{recursive:!0})}function __(e,t,s,n){try{g_();let r=Qa(or,`${e}.txt`),o=`# Claude Recall auto-title \xB7 session ${e} \xB7 source ${s} \xB7 updated ${n}
1139
1139
  `;Gg(r,o+t+`
1140
- `)}catch(r){console.error("[autoTitle] mirror write failed:",r)}}var f_=50;function h_(e){if(e.length===0)return[];let t=[...e].sort((d,u)=>d.added_at<u.added_at?-1:d.added_at>u.added_at?1:0),s=new Map,n=new Set,r=[];for(let d of t)if(d.parent_session_id){let u=s.get(d.parent_session_id)??[];u.push(d),s.set(d.parent_session_id,u)}let o=t.filter(d=>d.role==="origin"),c=[...o.length>0?o:t.filter(d=>!d.parent_session_id)];for(;c.length>0;){let d=c.shift();if(n.has(d.session_id))continue;n.add(d.session_id),r.push(d.session_id);let u=s.get(d.session_id)??[];for(let g of u)n.has(g.session_id)||c.push(g)}for(let d of t)n.has(d.session_id)||(n.add(d.session_id),r.push(d.session_id));return r}function E_(e){let t=or(e.sessionId),s=["",`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(`
1140
+ `)}catch(r){console.error("[autoTitle] mirror write failed:",r)}}var f_=50;function h_(e){if(e.length===0)return[];let t=[...e].sort((d,u)=>d.added_at<u.added_at?-1:d.added_at>u.added_at?1:0),s=new Map,n=new Set,r=[];for(let d of t)if(d.parent_session_id){let u=s.get(d.parent_session_id)??[];u.push(d),s.set(d.parent_session_id,u)}let o=t.filter(d=>d.role==="origin"),c=[...o.length>0?o:t.filter(d=>!d.parent_session_id)];for(;c.length>0;){let d=c.shift();if(n.has(d.session_id))continue;n.add(d.session_id),r.push(d.session_id);let u=s.get(d.session_id)??[];for(let g of u)n.has(g.session_id)||c.push(g)}for(let d of t)n.has(d.session_id)||(n.add(d.session_id),r.push(d.session_id));return r}function E_(e){let t=ar(e.sessionId),s=["",`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(`
1141
1141
  `);return`${t}
1142
- ${s}`}function b_(e){return Te(e)?.auto_title_source??null}async function S_(e){let{spawnClaudePrompt:t,isClaudeCliAvailable:s}=await Promise.resolve().then(()=>(ge(),Pe));if(!s())throw new Error("claude CLI not found on PATH");let n=await t(e.prompt,[],{model:e.model});if(!n.success)throw new Error(`claude CLI exited ${n.exitCode}: ${n.stderr.slice(-500)}`);let r=T_(n.stdout);if(!r)throw new Error("claude CLI returned an empty title");return r.slice(0,f_)}function T_(e){let t=e.trim();if(!t)return"";try{let s=JSON.parse(t);if(s&&typeof s=="object"){let n=s.result;if(typeof n=="string")return rc(n)}}catch{}return rc(t)}function rc(e){return e.trim().replace(/^["'`]+|["'`]+$/g,"").replace(/\s+/g," ").replace(/[.!?]+$/g,"").trim()}async function ic(e,t={}){let s=te(e);if(!s)throw new Error(`thread not found: ${e}`);let n=h_(s.edges),r=n.length,o=t.force??!1,a=t.signal,c=[],d=[],u=[];for(let g=0;g<n.length;g++){let h=n[g],b=g+1;if(a?.aborted){let y={sessionId:h,reason:"cancelled"};d.push(y),t.onSkipped?.(y);continue}if(!o&&b_(h)==="agent"){let y={sessionId:h,reason:"already-titled"};d.push(y),t.onSkipped?.(y);continue}let S;try{if(oc)S=await oc({sessionId:h,current:b,total:r});else{let y=E_({sessionId:h,current:b,total:r});S=await S_({prompt:y,model:t.model})}}catch(y){let k=y instanceof Error?y.message:String(y??"unknown error"),w={sessionId:h,error:k};u.push(w),t.onFailed?.(w);continue}try{de(h,S,"agent")}catch(y){let k=y instanceof Error?y.message:String(y??"unknown error"),w={sessionId:h,error:`setAutoTitle failed: ${k}`};u.push(w),t.onFailed?.(w);continue}c.push(h),t.onProgress?.({current:b,total:r,sessionId:h,title:S})}return{generated:c,skipped:d,failed:u}}var oc=null;var Ft=new Map,w_=300*1e3;function Dt(e,t,s){let n=e.events.length+1;e.events.push({id:n,kind:t,data:s});for(let r of e.waiters)r.resolve();e.waiters.clear()}function R_(e){e.cleanupTimer&&clearTimeout(e.cleanupTimer),e.cleanupTimer=setTimeout(()=>{Ft.delete(e.jobId)},w_)}function k_(e){let t=0,s=0,n=0;for(let r of e.events)r.kind==="progress"&&(t+=1),r.kind==="skipped"&&(s+=1),r.kind==="error"&&(n+=1);return{jobId:e.jobId,threadId:e.threadId,status:e.status,startedAt:e.startedAt,endedAt:e.endedAt,total:e.total,done:t,skipped:s,failed:n,result:e.result}}function ac(e){let t=y_(),s=new AbortController,n={jobId:t,threadId:e.threadId,status:"running",startedAt:new Date().toISOString(),endedAt:null,total:0,events:[],waiters:new Set,controller:s,result:null,cleanupTimer:null};return Ft.set(t,n),(async()=>{await Promise.resolve();try{let r=await ic(e.threadId,{force:e.force??!1,signal:s.signal,model:e.model,onProgress:o=>{n.total=o.total,Dt(n,"progress",o)},onSkipped:o=>{Dt(n,"skipped",o)},onFailed:o=>{Dt(n,"error",o)}});n.result=r,n.status=s.signal.aborted?"cancelled":"done",n.endedAt=new Date().toISOString(),Dt(n,"done",r)}catch(r){let o=r instanceof Error?r.message:String(r??"unknown error");n.result={generated:[],skipped:[],failed:[{sessionId:e.threadId,error:o}]},n.status="failed",n.endedAt=new Date().toISOString(),Dt(n,"done",n.result)}finally{R_(n)}})(),t}async function*cc(e,t=0){let s=Ft.get(e);if(!s)return;let n=t;for(;;){for(;n<s.events.length;){let r=s.events[n];if(n+=1,yield r,r.kind==="done")return}if(s.endedAt)return;await new Promise(r=>{s.waiters.add({resolve:r})})}}function lc(e){let t=Ft.get(e);return!t||t.status!=="running"?!1:(t.controller.abort(),!0)}function ir(e){let t=Ft.get(e);return t?k_(t):null}Z();import{existsSync as A_,readFileSync as N_,writeFileSync as x_}from"node:fs";import{join as O_}from"node:path";import{z as ae}from"zod";var ar=O_($,"terminals.json"),dc=1440*60*1e3,L_=3e4,C_=6e4,I_=ae.object({shell_pid:ae.number(),tab_name:ae.string(),cwd:ae.string().nullable().optional(),opened_at:ae.string(),last_seen_at:ae.string()}),v_=ae.object({schema:ae.string().optional(),saved_at:ae.string().optional(),terminals:ae.array(I_).max(500).default([]),sessions_by_pid:ae.record(ae.string(),ae.array(ae.string()).max(50)).optional().default({})}),uc=/^[⠀-⣿✳\s]+/,pc=/^\d+(\.\d+){1,3}$/;function ne(e){let t=e.trim();return!!(!t||uc.test(t)||pc.test(t))}function tt(e){let t=e.trim();if(!t||pc.test(t))return null;let s=t.replace(uc,"").trim();return s.length>0?s:null}function cr(e,t){if(!ne(e))return e;let s=tt(e);return s||(t&&!ne(t)?t:e)}function j_(e){let t=e.now-e.withinMs,s=e.pending.filter(n=>{let r=Date.parse(n.started_at);return Number.isFinite(r)&&r>=t});if(s.length===0)return{kind:"none"};if(e.shellPid!=null){let n=s.find(r=>r.shell_pid===e.shellPid);if(n)return{kind:"pid-match",entry:n}}if(e.cwd){let n=e.cwd.replace(/\/+$/,""),r=s.filter(o=>o.cwd&&o.cwd.replace(/\/+$/,"")===n);if(r.length===1)return{kind:"singleton-cwd",entry:r[0]};if(r.length>=2)return{kind:"ambiguous",candidates:r}}return{kind:"none"}}var lr=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,!!A_(ar)))try{let t=N_(ar,"utf8"),s=JSON.parse(t),n=v_.safeParse(s);if(!n.success){console.warn("[terminal-registry] terminals.json failed validation, starting with empty registry:",n.error.issues);return}let r=n.data;for(let o of r.terminals)this.entries.set(o.shell_pid,{shell_pid:o.shell_pid,tab_name:o.tab_name,cwd:o.cwd??null,opened_at:o.opened_at,last_seen_at:o.last_seen_at});for(let[o,a]of Object.entries(r.sessions_by_pid??{})){let c=Number(o);if(!Number.isFinite(c))continue;let d=new Set;for(let u of a)u.length>0&&d.add(u);d.size>0&&this.sessionsByPid.set(c,d)}this.gc()}catch{}}save(){try{J();let t={schema:"claude-recall.terminals.v1",saved_at:new Date().toISOString(),terminals:Array.from(this.entries.values()),sessions_by_pid:Object.fromEntries(Array.from(this.sessionsByPid.entries()).map(([s,n])=>[String(s),Array.from(n)]))};x_(ar,JSON.stringify(t,null,2))}catch{}}upsert(t){this.ensureLoaded();let s=new Date().toISOString(),n=this.entries.get(t.shell_pid),r=cr(t.tab_name,n?.tab_name),o=n?.opened_at??t.opened_at,a={...t,tab_name:r,opened_at:o,last_seen_at:s};return this.entries.set(t.shell_pid,a),this.gc(),this.save(),a}rename(t,s){this.ensureLoaded();let n=this.entries.get(t);if(!n)return null;let r=cr(s,n.tab_name),o={...n,tab_name:r,last_seen_at:new Date().toISOString()};return this.entries.set(t,o),this.save(),o}remove(t){this.ensureLoaded();let s=this.entries.delete(t),n=this.sessionsByPid.delete(t);return this.outputTails.delete(t),this.pidOwnership.delete(t),(s||n)&&this.save(),s}claimPidOwnership(t,s,n=Date.now()){if(this.ensureLoaded(),!s)return"anonymous";let r=this.pidOwnership.get(t);return r?r.instance_id===s?(r.last_claim_at=n,"refreshed"):n-r.last_claim_at>C_?(this.pidOwnership.set(t,{instance_id:s,last_claim_at:n}),"claimed"):"rejected":(this.pidOwnership.set(t,{instance_id:s,last_claim_at:n}),"claimed")}pidOwnershipSnapshot(){return this.ensureLoaded(),Array.from(this.pidOwnership.entries()).map(([t,s])=>({shell_pid:t,instance_id:s.instance_id,last_claim_at:s.last_claim_at}))}sync(t){this.ensureLoaded();let s=new Date().toISOString(),n=0,r=0;for(let o of t){let a=this.entries.get(o.shell_pid),c=cr(o.tab_name,a?.tab_name),d=a?.opened_at??o.opened_at;this.entries.set(o.shell_pid,{...o,tab_name:c,opened_at:d,last_seen_at:s}),a?(a.tab_name!==c||a.cwd!==o.cwd)&&r++:n++}return this.gc(),this.save(),{added:n,updated:r,removed:0}}get(t){return this.ensureLoaded(),this.entries.get(t)??null}all(){return this.ensureLoaded(),this.gc(),Array.from(this.entries.values())}size(){return this.ensureLoaded(),this.entries.size}linkSession(t,s){this.ensureLoaded();let n=this.sessionsByPid.get(s);n||(n=new Set,this.sessionsByPid.set(s,n)),n.has(t)||(n.add(t),this.save())}sessionsFor(t){return this.ensureLoaded(),Array.from(this.sessionsByPid.get(t)??[])}isSessionAutoLinked(t){this.ensureLoaded();for(let s of this.sessionsByPid.values())if(s.has(t))return!0;return!1}unlinkSession(t){this.ensureLoaded();let s=!1;for(let[n,r]of this.sessionsByPid)r.delete(t)&&(s=!0,r.size===0&&this.sessionsByPid.delete(n));return s&&this.save(),s}pushPending(t){this.ensureLoaded(),this.gcPending(),this.pendingClaudeStarts.push({...t})}takePendingMatched(t){this.ensureLoaded(),this.gcPending();let s=j_({pending:this.pendingClaudeStarts,shellPid:t.shellPid,cwd:t.cwd,withinMs:t.withinMs,now:Date.now()});if(s.kind==="pid-match"||s.kind==="singleton-cwd"){let n=this.pendingClaudeStarts.indexOf(s.entry);n>=0&&this.pendingClaudeStarts.splice(n,1)}return s}pendingSize(){return this.ensureLoaded(),this.gcPending(),this.pendingClaudeStarts.length}deferSessionLink(t,s,n,r){this.ensureLoaded(),this.gcDeferredLinks(),this.deferredLinks.set(t,{parent_shell_pid:s,queued_at:Date.now(),cwd:n,git_branch:r})}allDeferredLinks(){return this.ensureLoaded(),this.gcDeferredLinks(),Array.from(this.deferredLinks.entries()).map(([t,s])=>({session_id:t,...s}))}resolveDeferredLink(t){return this.deferredLinks.delete(t)}deferredLinkSize(){return this.ensureLoaded(),this.gcDeferredLinks(),this.deferredLinks.size}gcDeferredLinks(){let t=Date.now()-9e4;for(let[s,n]of this.deferredLinks)n.queued_at<t&&this.deferredLinks.delete(s)}gcPending(){let t=Date.now()-L_;this.pendingClaudeStarts.length!==0&&(this.pendingClaudeStarts=this.pendingClaudeStarts.filter(s=>{let n=Date.parse(s.started_at);return Number.isFinite(n)&&n>=t}))}outputTails=new Map;setOutputTail(t,s,n){this.ensureLoaded(),this.outputTails.set(t,{text:s,captured_at:n})}getOutputTail(t){return this.ensureLoaded(),this.outputTails.get(t)??null}allOutputTails(){return this.ensureLoaded(),new Map(this.outputTails)}removeOutputTail(t){return this.outputTails.delete(t)}setOrigin(t,s){this.ensureLoaded(),this.origins.set(t,s),this.gcOrigins()}getOrigin(t){return this.ensureLoaded(),this.origins.get(t)??null}removeOrigin(t){return this.ensureLoaded(),this.origins.delete(t)}allOrigins(){return this.ensureLoaded(),this.gcOrigins(),new Map(this.origins)}originSize(){return this.ensureLoaded(),this.origins.size}gc(){let t=Date.now()-dc;for(let[s,n]of this.entries){let r=Date.parse(n.last_seen_at);!Number.isNaN(r)&&r<t&&this.entries.delete(s)}}gcOrigins(){let t=Date.now()-dc;for(let[s,n]of this.origins)n.detectedAt<t&&this.origins.delete(s)}reapStaleLinks(t=10080*60*1e3){this.ensureLoaded();let n=Date.now()-t,r=0,o=0;for(let[a,c]of this.sessionsByPid){let d=this.entries.get(a);if(d){let u=Date.parse(d.last_seen_at);if(Number.isFinite(u)&&u>=n)continue}o+=c.size,this.sessionsByPid.delete(a),d&&(this.entries.delete(a),r++)}return(r||o)&&this.save(),{pruned_pids:r,pruned_sessions:o}}gcDeadPids(){this.ensureLoaded();let t=0,s=0;for(let n of[...this.entries.keys()]){let r=!0;try{process.kill(n,0)}catch(a){a.code==="ESRCH"&&(r=!1)}if(r)continue;this.entries.delete(n),t++;let o=this.sessionsByPid.get(n);o&&(s+=o.size,this.sessionsByPid.delete(n)),this.outputTails.delete(n),this.pidOwnership.delete(n)}return(t||s)&&this.save(),{pruned_pids:t,pruned_sessions:s}}},I=new lr;import{execFile as q_}from"node:child_process";import{promisify as J_}from"node:util";import{existsSync as X_}from"node:fs";import{basename as G_}from"node:path";H();import{execFile as M_}from"node:child_process";import{readFile as D_}from"node:fs/promises";import{promisify as F_}from"node:util";var P_=F_(M_),mc=["CURSOR_TRACE_ID","VSCODE_PID","VSCODE_INJECTION","TERM_PROGRAM","TERM_PROGRAM_VERSION","TERM","WT_SESSION","KITTY_WINDOW_ID","ALACRITTY_SOCKET","WARP_HONOR_PS1"];function U_(e){let t={};for(let s of mc){let n=e[s];typeof n=="string"&&n.length>0&&(t[s]=n)}return t}function $_(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 s=e.TERM_PROGRAM;return s==="WarpTerminal"?{editor:"warp",label:"Warp",detectedAt:t}:s==="iTerm.app"?{editor:"iterm",label:"iTerm",detectedAt:t}:s==="Apple_Terminal"?{editor:"apple-terminal",label:"Terminal",detectedAt:t}:s==="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 B_(e){if(process.platform==="linux")try{let t=await D_(`/proc/${e}/environ`,"utf8");return H_(t)}catch{return{}}try{let{stdout:t}=await P_("/bin/ps",["eww","-o","command=","-p",String(e)],{timeout:2e3,maxBuffer:1048576});return W_(t)}catch{return{}}}function H_(e){let t={};for(let s of e.split("\0")){if(!s)continue;let n=s.indexOf("=");if(n<=0)continue;let r=s.slice(0,n),o=s.slice(n+1);t[r]=o}return t}function W_(e){let t={},s=new Set(mc),n=e.replace(/\s+/g," ").trim().split(" ");for(let r of n){let o=r.indexOf("=");if(o<=0)continue;let a=r.slice(0,o);s.has(a)&&(t[a]=r.slice(o+1))}return t}async function gc(e){if(!Number.isFinite(e)||e<=0)return null;try{let t=await B_(e),s=U_(t);return $_(s)}catch{return null}}var js=J_(q_),vs;function Y_(){if(vs!==void 0)return vs;let e=["/usr/sbin/lsof","/usr/bin/lsof","/opt/homebrew/bin/lsof"];for(let t of e)if(X_(t))return vs=t,t;return vs=null,null}async function K_(e){let t=Y_();if(!t)return null;try{let{stdout:s}=await js(t,["-Fpc",e],{timeout:2e3}),n=s.split(`
1143
- `),r=null,o=null,a=null;for(let c of n)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 _c(e){try{let{stdout:t}=await js("/bin/ps",["-o","ppid=","-p",String(e)],{timeout:2e3}),s=Number(t.trim());return Number.isFinite(s)&&s>0?s:null}catch{return null}}async function z_(e){try{let{stdout:t}=await js("/bin/ps",["-o","lstart=","-p",String(e)],{timeout:2e3}),s=Date.parse(t.trim());return Number.isFinite(s)?s:null}catch{return null}}var V_=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 re(e){let t=e.trim().toLowerCase();if(!t)return!0;let s=t.replace(/^[-/]+/,"").replace(/^.*\//,"").replace(/\s*\(\d+\)\s*$/,"").trim();return V_.has(s)}function st(e){let t=e.tabName?.trim();return t&&!re(t)&&!ne(t)?t:null}function Z_(e){try{return f().prepare("SELECT cwd, git_branch FROM sessions WHERE id = ?").get(e)??null}catch{return null}}async function Ms(e){let t=G_(e,".jsonl");if(Se(t))return;let s=Z_(t),n=await K_(e),r=n?await _c(n):null,o=n?await gc(n):null;o&&I.setOrigin(t,o);let a=null,c=null,d=null,u=I.takePendingMatched({shellPid:r,cwd:s?.cwd??null,withinMs:3e4});if(u.kind==="ambiguous"){console.log(`[correlator] ambiguous pending for ${t.slice(0,8)} (${u.candidates.length} candidates in ${s?.cwd??"?"}) \u2014 refusing to guess; heuristic title will display`);return}if(u.kind==="pid-match"||u.kind==="singleton-cwd"){let y=u.entry;c=y.shell_pid,d=u.kind==="pid-match"?"pending-pid":"pending-cwd",a=I.get(y.shell_pid)??{shell_pid:y.shell_pid,tab_name:y.tab_name,cwd:y.cwd,opened_at:y.started_at,last_seen_at:y.started_at}}let g=null;if(!a&&n){let y=n;for(let k=0;k<4&&y!=null;k++){let w=await _c(y);if(!w)break;let D=I.get(w);if(D){a=D,c=w,d="ppid";break}g==null&&(g=w),y=w}}if(!a&&s?.cwd){let y=s.cwd.replace(/\/+$/,""),k=I.all().filter(w=>w.cwd&&w.cwd.replace(/\/+$/,"")===y);k.length===1?(a=k[0],c=a.shell_pid,d="cwd"):k.length>=2&&console.log(`[correlator] ${k.length} registered terminals in ${y} for ${t.slice(0,8)} \u2014 refusing to guess; heuristic title will display`)}let h=null;if(a?.tab_name&&!re(a.tab_name)&&!ne(a.tab_name))h=a.tab_name;else if(a?.tab_name&&ne(a.tab_name)){let y=tt(a.tab_name);y&&!re(y)&&(h=y)}if(!h&&!(d==="pending-pid"||d==="pending-cwd")&&a&&s?.cwd){let y=s.cwd.replace(/\/+$/,""),k=I.all().filter(w=>w.shell_pid!==c&&w.cwd&&w.cwd.replace(/\/+$/,"")===y&&!re(w.tab_name)&&!ne(w.tab_name)).sort((w,D)=>Date.parse(D.last_seen_at)-Date.parse(w.last_seen_at))[0];k&&(h=k.tab_name)}let S=st({tabName:h,origin:o,cwd:s?.cwd??null,gitBranch:s?.git_branch??null});if(g!=null&&!c&&I.deferSessionLink(t,g,s?.cwd??null,s?.git_branch??null),!!S)try{me(t,S);let y=!!h&&!re(h)&&!ne(h)&&S===h.trim();c!=null&&I.linkSession(t,c);let k=d==="pending-pid"?"pending PID-exact match":d==="pending-cwd"?"pending cwd-singleton match":d??"unknown";console.log(`[correlator] auto-aliased ${t.slice(0,8)} \u2192 "${S}"`+(y?` (tab name via ${k}, 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 Q_(){try{let{stdout:e}=await js("/bin/ps",["-eo","pid=,ppid=,comm="],{timeout:2e3}),t=new Map;for(let s of e.split(`
1142
+ ${s}`}function b_(e){return Te(e)?.auto_title_source??null}async function S_(e){let{spawnClaudePrompt:t,isClaudeCliAvailable:s}=await Promise.resolve().then(()=>(ge(),Pe));if(!s())throw new Error("claude CLI not found on PATH");let n=await t(e.prompt,[],{model:e.model});if(!n.success)throw new Error(`claude CLI exited ${n.exitCode}: ${n.stderr.slice(-500)}`);let r=T_(n.stdout);if(!r)throw new Error("claude CLI returned an empty title");return r.slice(0,f_)}function T_(e){let t=e.trim();if(!t)return"";try{let s=JSON.parse(t);if(s&&typeof s=="object"){let n=s.result;if(typeof n=="string")return ic(n)}}catch{}return ic(t)}function ic(e){return e.trim().replace(/^["'`]+|["'`]+$/g,"").replace(/\s+/g," ").replace(/[.!?]+$/g,"").trim()}async function cc(e,t={}){let s=te(e);if(!s)throw new Error(`thread not found: ${e}`);let n=h_(s.edges),r=n.length,o=t.force??!1,a=t.signal,c=[],d=[],u=[];for(let g=0;g<n.length;g++){let h=n[g],b=g+1;if(a?.aborted){let y={sessionId:h,reason:"cancelled"};d.push(y),t.onSkipped?.(y);continue}if(!o&&b_(h)==="agent"){let y={sessionId:h,reason:"already-titled"};d.push(y),t.onSkipped?.(y);continue}let S;try{if(ac)S=await ac({sessionId:h,current:b,total:r});else{let y=E_({sessionId:h,current:b,total:r});S=await S_({prompt:y,model:t.model})}}catch(y){let k=y instanceof Error?y.message:String(y??"unknown error"),w={sessionId:h,error:k};u.push(w),t.onFailed?.(w);continue}try{de(h,S,"agent")}catch(y){let k=y instanceof Error?y.message:String(y??"unknown error"),w={sessionId:h,error:`setAutoTitle failed: ${k}`};u.push(w),t.onFailed?.(w);continue}c.push(h),t.onProgress?.({current:b,total:r,sessionId:h,title:S})}return{generated:c,skipped:d,failed:u}}var ac=null;var Ft=new Map,w_=300*1e3;function Dt(e,t,s){let n=e.events.length+1;e.events.push({id:n,kind:t,data:s});for(let r of e.waiters)r.resolve();e.waiters.clear()}function R_(e){e.cleanupTimer&&clearTimeout(e.cleanupTimer),e.cleanupTimer=setTimeout(()=>{Ft.delete(e.jobId)},w_)}function k_(e){let t=0,s=0,n=0;for(let r of e.events)r.kind==="progress"&&(t+=1),r.kind==="skipped"&&(s+=1),r.kind==="error"&&(n+=1);return{jobId:e.jobId,threadId:e.threadId,status:e.status,startedAt:e.startedAt,endedAt:e.endedAt,total:e.total,done:t,skipped:s,failed:n,result:e.result}}function lc(e){let t=y_(),s=new AbortController,n={jobId:t,threadId:e.threadId,status:"running",startedAt:new Date().toISOString(),endedAt:null,total:0,events:[],waiters:new Set,controller:s,result:null,cleanupTimer:null};return Ft.set(t,n),(async()=>{await Promise.resolve();try{let r=await cc(e.threadId,{force:e.force??!1,signal:s.signal,model:e.model,onProgress:o=>{n.total=o.total,Dt(n,"progress",o)},onSkipped:o=>{Dt(n,"skipped",o)},onFailed:o=>{Dt(n,"error",o)}});n.result=r,n.status=s.signal.aborted?"cancelled":"done",n.endedAt=new Date().toISOString(),Dt(n,"done",r)}catch(r){let o=r instanceof Error?r.message:String(r??"unknown error");n.result={generated:[],skipped:[],failed:[{sessionId:e.threadId,error:o}]},n.status="failed",n.endedAt=new Date().toISOString(),Dt(n,"done",n.result)}finally{R_(n)}})(),t}async function*dc(e,t=0){let s=Ft.get(e);if(!s)return;let n=t;for(;;){for(;n<s.events.length;){let r=s.events[n];if(n+=1,yield r,r.kind==="done")return}if(s.endedAt)return;await new Promise(r=>{s.waiters.add({resolve:r})})}}function uc(e){let t=Ft.get(e);return!t||t.status!=="running"?!1:(t.controller.abort(),!0)}function cr(e){let t=Ft.get(e);return t?k_(t):null}Z();import{existsSync as A_,readFileSync as N_,writeFileSync as x_}from"node:fs";import{join as O_}from"node:path";import{z as ae}from"zod";var lr=O_($,"terminals.json"),pc=1440*60*1e3,L_=3e4,C_=6e4,I_=ae.object({shell_pid:ae.number(),tab_name:ae.string(),cwd:ae.string().nullable().optional(),opened_at:ae.string(),last_seen_at:ae.string()}),v_=ae.object({schema:ae.string().optional(),saved_at:ae.string().optional(),terminals:ae.array(I_).max(500).default([]),sessions_by_pid:ae.record(ae.string(),ae.array(ae.string()).max(50)).optional().default({})}),mc=/^[⠀-⣿✳\s]+/,gc=/^\d+(\.\d+){1,3}$/;function ne(e){let t=e.trim();return!!(!t||mc.test(t)||gc.test(t))}function tt(e){let t=e.trim();if(!t||gc.test(t))return null;let s=t.replace(mc,"").trim();return s.length>0?s:null}function dr(e,t){if(!ne(e))return e;let s=tt(e);return s||(t&&!ne(t)?t:e)}function j_(e){let t=e.now-e.withinMs,s=e.pending.filter(n=>{let r=Date.parse(n.started_at);return Number.isFinite(r)&&r>=t});if(s.length===0)return{kind:"none"};if(e.shellPid!=null){let n=s.find(r=>r.shell_pid===e.shellPid);if(n)return{kind:"pid-match",entry:n}}if(e.cwd){let n=e.cwd.replace(/\/+$/,""),r=s.filter(o=>o.cwd&&o.cwd.replace(/\/+$/,"")===n);if(r.length===1)return{kind:"singleton-cwd",entry:r[0]};if(r.length>=2)return{kind:"ambiguous",candidates:r}}return{kind:"none"}}var ur=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,!!A_(lr)))try{let t=N_(lr,"utf8"),s=JSON.parse(t),n=v_.safeParse(s);if(!n.success){console.warn("[terminal-registry] terminals.json failed validation, starting with empty registry:",n.error.issues);return}let r=n.data;for(let o of r.terminals)this.entries.set(o.shell_pid,{shell_pid:o.shell_pid,tab_name:o.tab_name,cwd:o.cwd??null,opened_at:o.opened_at,last_seen_at:o.last_seen_at});for(let[o,a]of Object.entries(r.sessions_by_pid??{})){let c=Number(o);if(!Number.isFinite(c))continue;let d=new Set;for(let u of a)u.length>0&&d.add(u);d.size>0&&this.sessionsByPid.set(c,d)}this.gc()}catch{}}save(){try{J();let t={schema:"claude-recall.terminals.v1",saved_at:new Date().toISOString(),terminals:Array.from(this.entries.values()),sessions_by_pid:Object.fromEntries(Array.from(this.sessionsByPid.entries()).map(([s,n])=>[String(s),Array.from(n)]))};x_(lr,JSON.stringify(t,null,2))}catch{}}upsert(t){this.ensureLoaded();let s=new Date().toISOString(),n=this.entries.get(t.shell_pid),r=dr(t.tab_name,n?.tab_name),o=n?.opened_at??t.opened_at,a={...t,tab_name:r,opened_at:o,last_seen_at:s};return this.entries.set(t.shell_pid,a),this.gc(),this.save(),a}rename(t,s){this.ensureLoaded();let n=this.entries.get(t);if(!n)return null;let r=dr(s,n.tab_name),o={...n,tab_name:r,last_seen_at:new Date().toISOString()};return this.entries.set(t,o),this.save(),o}remove(t){this.ensureLoaded();let s=this.entries.delete(t),n=this.sessionsByPid.delete(t);return this.outputTails.delete(t),this.pidOwnership.delete(t),(s||n)&&this.save(),s}claimPidOwnership(t,s,n=Date.now()){if(this.ensureLoaded(),!s)return"anonymous";let r=this.pidOwnership.get(t);return r?r.instance_id===s?(r.last_claim_at=n,"refreshed"):n-r.last_claim_at>C_?(this.pidOwnership.set(t,{instance_id:s,last_claim_at:n}),"claimed"):"rejected":(this.pidOwnership.set(t,{instance_id:s,last_claim_at:n}),"claimed")}pidOwnershipSnapshot(){return this.ensureLoaded(),Array.from(this.pidOwnership.entries()).map(([t,s])=>({shell_pid:t,instance_id:s.instance_id,last_claim_at:s.last_claim_at}))}sync(t){this.ensureLoaded();let s=new Date().toISOString(),n=0,r=0;for(let o of t){let a=this.entries.get(o.shell_pid),c=dr(o.tab_name,a?.tab_name),d=a?.opened_at??o.opened_at;this.entries.set(o.shell_pid,{...o,tab_name:c,opened_at:d,last_seen_at:s}),a?(a.tab_name!==c||a.cwd!==o.cwd)&&r++:n++}return this.gc(),this.save(),{added:n,updated:r,removed:0}}get(t){return this.ensureLoaded(),this.entries.get(t)??null}all(){return this.ensureLoaded(),this.gc(),Array.from(this.entries.values())}size(){return this.ensureLoaded(),this.entries.size}linkSession(t,s){this.ensureLoaded();let n=this.sessionsByPid.get(s);n||(n=new Set,this.sessionsByPid.set(s,n)),n.has(t)||(n.add(t),this.save())}sessionsFor(t){return this.ensureLoaded(),Array.from(this.sessionsByPid.get(t)??[])}isSessionAutoLinked(t){this.ensureLoaded();for(let s of this.sessionsByPid.values())if(s.has(t))return!0;return!1}unlinkSession(t){this.ensureLoaded();let s=!1;for(let[n,r]of this.sessionsByPid)r.delete(t)&&(s=!0,r.size===0&&this.sessionsByPid.delete(n));return s&&this.save(),s}pushPending(t){this.ensureLoaded(),this.gcPending(),this.pendingClaudeStarts.push({...t})}takePendingMatched(t){this.ensureLoaded(),this.gcPending();let s=j_({pending:this.pendingClaudeStarts,shellPid:t.shellPid,cwd:t.cwd,withinMs:t.withinMs,now:Date.now()});if(s.kind==="pid-match"||s.kind==="singleton-cwd"){let n=this.pendingClaudeStarts.indexOf(s.entry);n>=0&&this.pendingClaudeStarts.splice(n,1)}return s}pendingSize(){return this.ensureLoaded(),this.gcPending(),this.pendingClaudeStarts.length}deferSessionLink(t,s,n,r){this.ensureLoaded(),this.gcDeferredLinks(),this.deferredLinks.set(t,{parent_shell_pid:s,queued_at:Date.now(),cwd:n,git_branch:r})}allDeferredLinks(){return this.ensureLoaded(),this.gcDeferredLinks(),Array.from(this.deferredLinks.entries()).map(([t,s])=>({session_id:t,...s}))}resolveDeferredLink(t){return this.deferredLinks.delete(t)}deferredLinkSize(){return this.ensureLoaded(),this.gcDeferredLinks(),this.deferredLinks.size}gcDeferredLinks(){let t=Date.now()-9e4;for(let[s,n]of this.deferredLinks)n.queued_at<t&&this.deferredLinks.delete(s)}gcPending(){let t=Date.now()-L_;this.pendingClaudeStarts.length!==0&&(this.pendingClaudeStarts=this.pendingClaudeStarts.filter(s=>{let n=Date.parse(s.started_at);return Number.isFinite(n)&&n>=t}))}outputTails=new Map;setOutputTail(t,s,n){this.ensureLoaded(),this.outputTails.set(t,{text:s,captured_at:n})}getOutputTail(t){return this.ensureLoaded(),this.outputTails.get(t)??null}allOutputTails(){return this.ensureLoaded(),new Map(this.outputTails)}removeOutputTail(t){return this.outputTails.delete(t)}setOrigin(t,s){this.ensureLoaded(),this.origins.set(t,s),this.gcOrigins()}getOrigin(t){return this.ensureLoaded(),this.origins.get(t)??null}removeOrigin(t){return this.ensureLoaded(),this.origins.delete(t)}allOrigins(){return this.ensureLoaded(),this.gcOrigins(),new Map(this.origins)}originSize(){return this.ensureLoaded(),this.origins.size}gc(){let t=Date.now()-pc;for(let[s,n]of this.entries){let r=Date.parse(n.last_seen_at);!Number.isNaN(r)&&r<t&&this.entries.delete(s)}}gcOrigins(){let t=Date.now()-pc;for(let[s,n]of this.origins)n.detectedAt<t&&this.origins.delete(s)}reapStaleLinks(t=10080*60*1e3){this.ensureLoaded();let n=Date.now()-t,r=0,o=0;for(let[a,c]of this.sessionsByPid){let d=this.entries.get(a);if(d){let u=Date.parse(d.last_seen_at);if(Number.isFinite(u)&&u>=n)continue}o+=c.size,this.sessionsByPid.delete(a),d&&(this.entries.delete(a),r++)}return(r||o)&&this.save(),{pruned_pids:r,pruned_sessions:o}}gcDeadPids(){this.ensureLoaded();let t=0,s=0;for(let n of[...this.entries.keys()]){let r=!0;try{process.kill(n,0)}catch(a){a.code==="ESRCH"&&(r=!1)}if(r)continue;this.entries.delete(n),t++;let o=this.sessionsByPid.get(n);o&&(s+=o.size,this.sessionsByPid.delete(n)),this.outputTails.delete(n),this.pidOwnership.delete(n)}return(t||s)&&this.save(),{pruned_pids:t,pruned_sessions:s}}},I=new ur;import{execFile as q_}from"node:child_process";import{promisify as J_}from"node:util";import{existsSync as X_}from"node:fs";import{basename as G_}from"node:path";H();import{execFile as M_}from"node:child_process";import{readFile as D_}from"node:fs/promises";import{promisify as F_}from"node:util";var P_=F_(M_),_c=["CURSOR_TRACE_ID","VSCODE_PID","VSCODE_INJECTION","TERM_PROGRAM","TERM_PROGRAM_VERSION","TERM","WT_SESSION","KITTY_WINDOW_ID","ALACRITTY_SOCKET","WARP_HONOR_PS1"];function U_(e){let t={};for(let s of _c){let n=e[s];typeof n=="string"&&n.length>0&&(t[s]=n)}return t}function $_(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 s=e.TERM_PROGRAM;return s==="WarpTerminal"?{editor:"warp",label:"Warp",detectedAt:t}:s==="iTerm.app"?{editor:"iterm",label:"iTerm",detectedAt:t}:s==="Apple_Terminal"?{editor:"apple-terminal",label:"Terminal",detectedAt:t}:s==="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 B_(e){if(process.platform==="linux")try{let t=await D_(`/proc/${e}/environ`,"utf8");return H_(t)}catch{return{}}try{let{stdout:t}=await P_("/bin/ps",["eww","-o","command=","-p",String(e)],{timeout:2e3,maxBuffer:1048576});return W_(t)}catch{return{}}}function H_(e){let t={};for(let s of e.split("\0")){if(!s)continue;let n=s.indexOf("=");if(n<=0)continue;let r=s.slice(0,n),o=s.slice(n+1);t[r]=o}return t}function W_(e){let t={},s=new Set(_c),n=e.replace(/\s+/g," ").trim().split(" ");for(let r of n){let o=r.indexOf("=");if(o<=0)continue;let a=r.slice(0,o);s.has(a)&&(t[a]=r.slice(o+1))}return t}async function fc(e){if(!Number.isFinite(e)||e<=0)return null;try{let t=await B_(e),s=U_(t);return $_(s)}catch{return null}}var js=J_(q_),vs;function Y_(){if(vs!==void 0)return vs;let e=["/usr/sbin/lsof","/usr/bin/lsof","/opt/homebrew/bin/lsof"];for(let t of e)if(X_(t))return vs=t,t;return vs=null,null}async function K_(e){let t=Y_();if(!t)return null;try{let{stdout:s}=await js(t,["-Fpc",e],{timeout:2e3}),n=s.split(`
1143
+ `),r=null,o=null,a=null;for(let c of n)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 hc(e){try{let{stdout:t}=await js("/bin/ps",["-o","ppid=","-p",String(e)],{timeout:2e3}),s=Number(t.trim());return Number.isFinite(s)&&s>0?s:null}catch{return null}}async function z_(e){try{let{stdout:t}=await js("/bin/ps",["-o","lstart=","-p",String(e)],{timeout:2e3}),s=Date.parse(t.trim());return Number.isFinite(s)?s:null}catch{return null}}var V_=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 re(e){let t=e.trim().toLowerCase();if(!t)return!0;let s=t.replace(/^[-/]+/,"").replace(/^.*\//,"").replace(/\s*\(\d+\)\s*$/,"").trim();return V_.has(s)}function st(e){let t=e.tabName?.trim();return t&&!re(t)&&!ne(t)?t:null}function Z_(e){try{return f().prepare("SELECT cwd, git_branch FROM sessions WHERE id = ?").get(e)??null}catch{return null}}async function Ms(e){let t=G_(e,".jsonl");if(Se(t))return;let s=Z_(t),n=await K_(e),r=n?await hc(n):null,o=n?await fc(n):null;o&&I.setOrigin(t,o);let a=null,c=null,d=null,u=I.takePendingMatched({shellPid:r,cwd:s?.cwd??null,withinMs:3e4});if(u.kind==="ambiguous"){console.log(`[correlator] ambiguous pending for ${t.slice(0,8)} (${u.candidates.length} candidates in ${s?.cwd??"?"}) \u2014 refusing to guess; heuristic title will display`);return}if(u.kind==="pid-match"||u.kind==="singleton-cwd"){let y=u.entry;c=y.shell_pid,d=u.kind==="pid-match"?"pending-pid":"pending-cwd",a=I.get(y.shell_pid)??{shell_pid:y.shell_pid,tab_name:y.tab_name,cwd:y.cwd,opened_at:y.started_at,last_seen_at:y.started_at}}let g=null;if(!a&&n){let y=n;for(let k=0;k<4&&y!=null;k++){let w=await hc(y);if(!w)break;let D=I.get(w);if(D){a=D,c=w,d="ppid";break}g==null&&(g=w),y=w}}if(!a&&s?.cwd){let y=s.cwd.replace(/\/+$/,""),k=I.all().filter(w=>w.cwd&&w.cwd.replace(/\/+$/,"")===y);k.length===1?(a=k[0],c=a.shell_pid,d="cwd"):k.length>=2&&console.log(`[correlator] ${k.length} registered terminals in ${y} for ${t.slice(0,8)} \u2014 refusing to guess; heuristic title will display`)}let h=null;if(a?.tab_name&&!re(a.tab_name)&&!ne(a.tab_name))h=a.tab_name;else if(a?.tab_name&&ne(a.tab_name)){let y=tt(a.tab_name);y&&!re(y)&&(h=y)}if(!h&&!(d==="pending-pid"||d==="pending-cwd")&&a&&s?.cwd){let y=s.cwd.replace(/\/+$/,""),k=I.all().filter(w=>w.shell_pid!==c&&w.cwd&&w.cwd.replace(/\/+$/,"")===y&&!re(w.tab_name)&&!ne(w.tab_name)).sort((w,D)=>Date.parse(D.last_seen_at)-Date.parse(w.last_seen_at))[0];k&&(h=k.tab_name)}let S=st({tabName:h,origin:o,cwd:s?.cwd??null,gitBranch:s?.git_branch??null});if(g!=null&&!c&&I.deferSessionLink(t,g,s?.cwd??null,s?.git_branch??null),!!S)try{me(t,S);let y=!!h&&!re(h)&&!ne(h)&&S===h.trim();c!=null&&I.linkSession(t,c);let k=d==="pending-pid"?"pending PID-exact match":d==="pending-cwd"?"pending cwd-singleton match":d??"unknown";console.log(`[correlator] auto-aliased ${t.slice(0,8)} \u2192 "${S}"`+(y?` (tab name via ${k}, 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 Q_(){try{let{stdout:e}=await js("/bin/ps",["-eo","pid=,ppid=,comm="],{timeout:2e3}),t=new Map;for(let s of e.split(`
1144
1144
  `)){let n=s.trim();if(!n)continue;let r=n.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 ef=9e4;function tf(e){let t=(Date.now()-ef)/1e3,s=e.replace(/\/+$/,"");return f().prepare(`SELECT s.id, NULLIF(sa.alias, '') AS alias, s.started_at AS started_at
1145
1145
  FROM sessions s
1146
1146
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1147
1147
  WHERE s.cwd = ? AND s.file_mtime > ?`).all(s,t).map(r=>({id:r.id,alias:r.alias,started_at_ms:r.started_at?Date.parse(r.started_at):null}))}async function sf(e){let t=await import("node:fs/promises"),s="";try{let r=await t.open(e,"r");try{let o=Buffer.alloc(32768),{bytesRead:a}=await r.read(o,0,o.length,0);s=o.toString("utf8",0,a)}finally{await r.close()}}catch{return[]}let n=[];for(let r of s.split(`
1148
1148
  `)){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,d="";if(typeof c=="string")d=c;else if(Array.isArray(c))for(let u of c)u&&typeof u=="object"&&"text"in u&&typeof u.text=="string"&&(d+=u.text+`
1149
- `);if(d){for(let u of d.split(/\r?\n/)){let g=u.trim();g.length>=60&&g.length<=400&&n.push(g)}if(n.length>=8)break}}return n}async function fc(e){if(Se(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 s=await sf(t.file_path);if(s.length===0)return null;let n=t.cwd.replace(/\/+$/,""),r=I.allOutputTails(),o=[];for(let[a,c]of r){let d=I.get(a);if(!d||!d.cwd||d.cwd.replace(/\/+$/,"")!==n||re(d.tab_name)||ne(d.tab_name))continue;let u=0;for(let g of s)c.text.includes(g)&&u++;u>0&&o.push({shell_pid:a,tab_name:d.tab_name,matched_fingerprints:u})}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 nf=3e4;function hc(){let e=Date.now(),t=I.all(),s=o=>{let a=Date.parse(o.last_seen_at);return!Number.isFinite(a)||e-a>nf},n=new Map;for(let o of t){if(s(o)||!o.cwd||re(o.tab_name)||ne(o.tab_name))continue;let a=`${o.cwd.replace(/\/+$/,"")}::${o.tab_name}`,c=n.get(a);c||(c=[],n.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(!s(o))continue;let a=I.sessionsFor(o.shell_pid);if(a.length!==0){r.ghosts++;for(let c of a){let d=Se(c);if(!d)continue;let u=f().prepare("SELECT cwd FROM sessions WHERE id = ?").get(c);if(!u?.cwd)continue;let g=`${u.cwd.replace(/\/+$/,"")}::${d}`,h=n.get(g)??[];if(h.length===0)continue;if(h.length>1){r.ambiguous++;continue}let b=h[0];b.shell_pid!==o.shell_pid&&(I.unlinkSession(c),I.linkSession(c,b.shell_pid),r.rebound++)}}}return r}function Ec(){let e={resolved:0,expired:0},t=I.allDeferredLinks();for(let s of t){let n=I.get(s.parent_shell_pid);if(!n||re(n.tab_name)||ne(n.tab_name))continue;let r=Se(s.session_id);if(r&&!I.isSessionAutoLinked(s.session_id)){I.resolveDeferredLink(s.session_id);continue}let o=I.getOrigin(s.session_id),a=st({tabName:n.tab_name,origin:o??null,cwd:s.cwd,gitBranch:s.git_branch});if(!a){I.resolveDeferredLink(s.session_id);continue}r!==a&&me(s.session_id,a),I.linkSession(s.session_id,s.parent_shell_pid),I.resolveDeferredLink(s.session_id),e.resolved++}return e}var rf=6e4;async function Ds(){let e=await Q_(),t={scanned:e.size,linked:0,renamed:0,skipped_manual:0,ambiguous_cwd:0};if(e.size===0)return t;let s=[];for(let[a,c]of e){let d=I.get(c);if(!d||!d.cwd||re(d.tab_name)||ne(d.tab_name))continue;let u=d.tab_name.trim();if(!u)continue;let g=await z_(a);s.push({claudePid:a,shellPid:c,cwd:d.cwd.replace(/\/+$/,""),target:u,startTimeMs:g})}let n=new Map,r=a=>{let c=n.get(a);if(c)return c;let d=tf(a);return n.set(a,d),d},o=new Set;for(let a of s){let c=r(a.cwd).filter(u=>!o.has(u.id));if(c.length===0)continue;let d=null;if(a.startTimeMs!=null){let u=rf;for(let g of c){if(g.started_at_ms==null)continue;let h=Math.abs(g.started_at_ms-a.startTimeMs);h<u&&(u=h,d=g)}}if(!d&&c.length===1&&(d=c[0]),!d){t.ambiguous_cwd++;continue}if(o.add(d.id),d.alias&&!I.isSessionAutoLinked(d.id)){t.skipped_manual++;continue}if(d.alias===a.target){I.linkSession(d.id,a.shellPid);continue}try{me(d.id,a.target),I.linkSession(d.id,a.shellPid),d.alias?t.renamed++:t.linked++,console.log(`[correlator] linked ${d.id.slice(0,8)} \u2192 "${a.target}" (live sweep, claude pid ${a.claudePid}, shell pid ${a.shellPid})`)}catch{}}return t}import{existsSync as bc,mkdirSync as of,readFileSync as af,writeFileSync as cf,chmodSync as lf}from"node:fs";import{homedir as df}from"node:os";import{join as Sc}from"node:path";import{z as Le}from"zod";function Tc(){return process.env.RECALL_HOME??Sc(df(),".recall")}function uf(){let e=Tc();bc(e)||of(e,{recursive:!0})}function yc(){return Sc(Tc(),"config.json")}var Ps=Le.object({enabled:Le.boolean().default(!1),backend:Le.enum(["api","mcp"]).default("api"),apiKey:Le.string().optional(),model:Le.string().default("claude-opus-4-7"),maxTagsPerSession:Le.number().int().min(1).max(10).default(4),minTagsPerSession:Le.number().int().min(1).max(10).default(2),autopilot:Le.boolean().default(!1)}),Fs={enabled:!1,backend:"api",model:"claude-opus-4-7",maxTagsPerSession:4,minTagsPerSession:2,autopilot:!1};function wc(){let e=yc();if(!bc(e))return{};try{return JSON.parse(af(e,"utf8"))}catch(t){return console.error("[auto-tag-config] failed to parse config.json, using defaults:",t),{}}}function Re(){let e=wc().autoTag;if(!e)return{...Fs};let t=Ps.safeParse({...Fs,...e});return t.success?t.data:{...Fs}}function Rc(e){uf();let t=wc(),s=Ps.parse({...Fs,...t.autoTag??{},...e}),n={...t,autoTag:s},r=yc();cf(r,JSON.stringify(n,null,2));try{lf(r,384)}catch(o){console.error("[auto-tag-config] chmod 0600 failed (continuing):",o)}return s}function dr(e){let{apiKey:t,...s}=e;return{...s,apiKey:t?"sk-ant-\u2026":null,hasApiKey:!!t}}import{existsSync as kc,mkdirSync as pf,readFileSync as mf,writeFileSync as gf}from"node:fs";import{homedir as _f}from"node:os";import{join as Ac}from"node:path";import{z as ur}from"zod";function Nc(){return process.env.RECALL_HOME??Ac(_f(),".recall")}function ff(){let e=Nc();kc(e)||pf(e,{recursive:!0})}function xc(){return Ac(Nc(),"config.json")}var $s=ur.object({heuristicEnabled:ur.boolean().default(!0),agentEnabled:ur.boolean().default(!1)}),Us={heuristicEnabled:!0,agentEnabled:!1};function Oc(){let e=xc();if(!kc(e))return{};try{return JSON.parse(mf(e,"utf8"))}catch(t){return console.error("[auto-title-config] failed to parse config.json, using defaults:",t),{}}}function He(){let e=Oc().autoTitle;if(!e)return{...Us};let t=$s.safeParse({...Us,...e});return t.success?t.data:{...Us}}function Lc(e){ff();let t=Oc(),s=$s.parse({...Us,...t.autoTitle??{},...e}),n={...t,autoTitle:s};return gf(xc(),JSON.stringify(n,null,2)),s}H();var Bs="claude-haiku-4-5-20251001",Cc=80,hf=2e3,nt=class extends Error{sessionId;constructor(t){super(`no neighborhood context available for session ${t}`),this.name="NoContextAvailableError",this.sessionId=t}},Ic=null;async function Ef(e,t){if(Ic)return Ic(e,t);let{spawnClaudePrompt:s,isClaudeCliAvailable:n}=await Promise.resolve().then(()=>(ge(),Pe));return n()?s(e,[],{model:t}):{success:!1,stdout:"",stderr:"claude CLI not found on PATH",exitCode:null}}function bf(e){let s=f().prepare(`SELECT s.id,
1149
+ `);if(d){for(let u of d.split(/\r?\n/)){let g=u.trim();g.length>=60&&g.length<=400&&n.push(g)}if(n.length>=8)break}}return n}async function Ec(e){if(Se(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 s=await sf(t.file_path);if(s.length===0)return null;let n=t.cwd.replace(/\/+$/,""),r=I.allOutputTails(),o=[];for(let[a,c]of r){let d=I.get(a);if(!d||!d.cwd||d.cwd.replace(/\/+$/,"")!==n||re(d.tab_name)||ne(d.tab_name))continue;let u=0;for(let g of s)c.text.includes(g)&&u++;u>0&&o.push({shell_pid:a,tab_name:d.tab_name,matched_fingerprints:u})}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 nf=3e4;function bc(){let e=Date.now(),t=I.all(),s=o=>{let a=Date.parse(o.last_seen_at);return!Number.isFinite(a)||e-a>nf},n=new Map;for(let o of t){if(s(o)||!o.cwd||re(o.tab_name)||ne(o.tab_name))continue;let a=`${o.cwd.replace(/\/+$/,"")}::${o.tab_name}`,c=n.get(a);c||(c=[],n.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(!s(o))continue;let a=I.sessionsFor(o.shell_pid);if(a.length!==0){r.ghosts++;for(let c of a){let d=Se(c);if(!d)continue;let u=f().prepare("SELECT cwd FROM sessions WHERE id = ?").get(c);if(!u?.cwd)continue;let g=`${u.cwd.replace(/\/+$/,"")}::${d}`,h=n.get(g)??[];if(h.length===0)continue;if(h.length>1){r.ambiguous++;continue}let b=h[0];b.shell_pid!==o.shell_pid&&(I.unlinkSession(c),I.linkSession(c,b.shell_pid),r.rebound++)}}}return r}function Sc(){let e={resolved:0,expired:0},t=I.allDeferredLinks();for(let s of t){let n=I.get(s.parent_shell_pid);if(!n||re(n.tab_name)||ne(n.tab_name))continue;let r=Se(s.session_id);if(r&&!I.isSessionAutoLinked(s.session_id)){I.resolveDeferredLink(s.session_id);continue}let o=I.getOrigin(s.session_id),a=st({tabName:n.tab_name,origin:o??null,cwd:s.cwd,gitBranch:s.git_branch});if(!a){I.resolveDeferredLink(s.session_id);continue}r!==a&&me(s.session_id,a),I.linkSession(s.session_id,s.parent_shell_pid),I.resolveDeferredLink(s.session_id),e.resolved++}return e}var rf=6e4;async function Ds(){let e=await Q_(),t={scanned:e.size,linked:0,renamed:0,skipped_manual:0,ambiguous_cwd:0};if(e.size===0)return t;let s=[];for(let[a,c]of e){let d=I.get(c);if(!d||!d.cwd||re(d.tab_name)||ne(d.tab_name))continue;let u=d.tab_name.trim();if(!u)continue;let g=await z_(a);s.push({claudePid:a,shellPid:c,cwd:d.cwd.replace(/\/+$/,""),target:u,startTimeMs:g})}let n=new Map,r=a=>{let c=n.get(a);if(c)return c;let d=tf(a);return n.set(a,d),d},o=new Set;for(let a of s){let c=r(a.cwd).filter(u=>!o.has(u.id));if(c.length===0)continue;let d=null;if(a.startTimeMs!=null){let u=rf;for(let g of c){if(g.started_at_ms==null)continue;let h=Math.abs(g.started_at_ms-a.startTimeMs);h<u&&(u=h,d=g)}}if(!d&&c.length===1&&(d=c[0]),!d){t.ambiguous_cwd++;continue}if(o.add(d.id),d.alias&&!I.isSessionAutoLinked(d.id)){t.skipped_manual++;continue}if(d.alias===a.target){I.linkSession(d.id,a.shellPid);continue}try{me(d.id,a.target),I.linkSession(d.id,a.shellPid),d.alias?t.renamed++:t.linked++,console.log(`[correlator] linked ${d.id.slice(0,8)} \u2192 "${a.target}" (live sweep, claude pid ${a.claudePid}, shell pid ${a.shellPid})`)}catch{}}return t}import{existsSync as Tc,mkdirSync as of,readFileSync as af,writeFileSync as cf,chmodSync as lf}from"node:fs";import{homedir as df}from"node:os";import{join as yc}from"node:path";import{z as Le}from"zod";function wc(){return process.env.RECALL_HOME??yc(df(),".recall")}function uf(){let e=wc();Tc(e)||of(e,{recursive:!0})}function Rc(){return yc(wc(),"config.json")}var Ps=Le.object({enabled:Le.boolean().default(!1),backend:Le.enum(["api","mcp"]).default("api"),apiKey:Le.string().optional(),model:Le.string().default("claude-opus-4-7"),maxTagsPerSession:Le.number().int().min(1).max(10).default(4),minTagsPerSession:Le.number().int().min(1).max(10).default(2),autopilot:Le.boolean().default(!1)}),Fs={enabled:!1,backend:"api",model:"claude-opus-4-7",maxTagsPerSession:4,minTagsPerSession:2,autopilot:!1};function kc(){let e=Rc();if(!Tc(e))return{};try{return JSON.parse(af(e,"utf8"))}catch(t){return console.error("[auto-tag-config] failed to parse config.json, using defaults:",t),{}}}function Re(){let e=kc().autoTag;if(!e)return{...Fs};let t=Ps.safeParse({...Fs,...e});return t.success?t.data:{...Fs}}function Ac(e){uf();let t=kc(),s=Ps.parse({...Fs,...t.autoTag??{},...e}),n={...t,autoTag:s},r=Rc();cf(r,JSON.stringify(n,null,2));try{lf(r,384)}catch(o){console.error("[auto-tag-config] chmod 0600 failed (continuing):",o)}return s}function pr(e){let{apiKey:t,...s}=e;return{...s,apiKey:t?"sk-ant-\u2026":null,hasApiKey:!!t}}import{existsSync as Nc,mkdirSync as pf,readFileSync as mf,writeFileSync as gf}from"node:fs";import{homedir as _f}from"node:os";import{join as xc}from"node:path";import{z as mr}from"zod";function Oc(){return process.env.RECALL_HOME??xc(_f(),".recall")}function ff(){let e=Oc();Nc(e)||pf(e,{recursive:!0})}function Lc(){return xc(Oc(),"config.json")}var $s=mr.object({heuristicEnabled:mr.boolean().default(!0),agentEnabled:mr.boolean().default(!1)}),Us={heuristicEnabled:!0,agentEnabled:!1};function Cc(){let e=Lc();if(!Nc(e))return{};try{return JSON.parse(mf(e,"utf8"))}catch(t){return console.error("[auto-title-config] failed to parse config.json, using defaults:",t),{}}}function He(){let e=Cc().autoTitle;if(!e)return{...Us};let t=$s.safeParse({...Us,...e});return t.success?t.data:{...Us}}function Ic(e){ff();let t=Cc(),s=$s.parse({...Us,...t.autoTitle??{},...e}),n={...t,autoTitle:s};return gf(Lc(),JSON.stringify(n,null,2)),s}H();var Bs="claude-haiku-4-5-20251001",vc=80,hf=2e3,nt=class extends Error{sessionId;constructor(t){super(`no neighborhood context available for session ${t}`),this.name="NoContextAvailableError",this.sessionId=t}},jc=null;async function Ef(e,t){if(jc)return jc(e,t);let{spawnClaudePrompt:s,isClaudeCliAvailable:n}=await Promise.resolve().then(()=>(ge(),Pe));return n()?s(e,[],{model:t}):{success:!1,stdout:"",stderr:"claude CLI not found on PATH",exitCode:null}}function bf(e){let s=f().prepare(`SELECT s.id,
1150
1150
  s.auto_title,
1151
1151
  s.auto_title_source,
1152
1152
  CASE WHEN sa.alias IS NOT NULL AND sa.alias != ''
@@ -1154,7 +1154,7 @@ ${s}`}function b_(e){return Te(e)?.auto_title_source??null}async function S_(e){
1154
1154
  FROM sessions s
1155
1155
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1156
1156
  WHERE s.id = ?`).get(e);return s?{id:s.id,auto_title:s.auto_title,auto_title_source:s.auto_title_source??null,has_alias:s.has_alias_int===1}:null}function Sf(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 Tf(e,t){if(e.has_alias)return{eligible:!1,reason:"manual_alias"};let s=jt({auto_title:e.auto_title,auto_title_source:e.auto_title_source,has_alias:e.has_alias});if(t)return{eligible:!0};switch(s){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 yf(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(`
1157
- `)}function wf(e){let t=e.trim();if(!t)return null;let s=t;try{let o=JSON.parse(t);if(o&&typeof o=="object"){let a=o;if(typeof a.result=="string")s=a.result.trim();else if(typeof a.title=="string")return vc(a)}}catch{}let n=s.match(/```(?:json)?\s*\n([\s\S]*?)\n?```/i);n&&(s=n[1].trim());let r=null;try{r=JSON.parse(s)}catch{let o=s.indexOf("{"),a=s.lastIndexOf("}");if(o>=0&&a>o)try{r=JSON.parse(s.slice(o,a+1))}catch{return null}else return null}return!r||typeof r!="object"?null:vc(r)}function vc(e){let t=e.title;if(typeof t!="string")return null;let s=Rf(t).trim();if(!s)return null;let n=e.evidence,r=typeof n=="string"?n.trim():"";return{title:s,evidence:r}}function Rf(e){return e.replace(/^["'`]+|["'`]+$/g,"")}function kf(e){let t=e.replace(/\s+/g," ").trim().replace(/[.!?]+$/g,"").trim();return t.length<=Cc?t:t.slice(0,Cc)}function Af(e,t){let s=e.auto_title??"";return!s&&e.has_alias&&(s=f().prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(e.id)?.alias??""),{session_id:e.id,title:s,source:e.auto_title_source,confidence:0,evidence:`skipped: ${t}`,written:!1,skipped:t}}async function pr(e,t={}){if(t.signal?.aborted)return{session_id:e,title:"",source:null,confidence:0,evidence:"aborted before start",written:!1,skipped:"aborted"};let s=bf(e);if(!s)throw new Error(`session not found: ${e}`);let n=Tf(s,t.force===!0);if(!n.eligible)return Af(s,n.reason);let r=t.budget??hf,o=Os(e,{budget:r});if(Sf(o))throw new nt(e);if(t.signal?.aborted)return{session_id:e,title:s.auto_title??"",source:s.auto_title_source,confidence:0,evidence:"aborted before CLI call",written:!1,skipped:"aborted"};let a=yf(o.bundle),c=t.model??Bs,d=await Ef(a,c);if(!d.success){let S=d.stderr.slice(-300);throw new Error(`claude CLI exited ${d.exitCode}: ${S||"no stderr captured"}`)}let u=wf(d.stdout);if(!u)throw new Error("failed to parse regeneration output: not valid JSON {title, evidence}");if(!u.title||!u.title.trim())throw new Error("regeneration produced empty title");let g=kf(u.title);if(!g)throw new Error("regeneration produced empty title after clamp");de(e,g,"agent");let b=Te(e)?.auto_title??g;return{session_id:e,title:b,source:"agent",confidence:xf(o),evidence:u.evidence||`regenerated from neighborhood (${Nf(o)})`,written:!0}}function Nf(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 xf(e){let t=e.parents.length,s=e.children.length,n=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,s)+.2*Math.min(1,n/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 Me}from"hono/streaming";import{bodyLimit as tS}from"hono/body-limit";import{z as j}from"zod";H();ge();import{createHash as Of}from"node:crypto";var _r=1,We="claude-haiku-4-5-20251001",Lf=3,Cf=32e3,jc=2e3,If=30,vf=30,jf=30,Mf=30;function Df(e){let s=f().prepare(`SELECT s.id,
1157
+ `)}function wf(e){let t=e.trim();if(!t)return null;let s=t;try{let o=JSON.parse(t);if(o&&typeof o=="object"){let a=o;if(typeof a.result=="string")s=a.result.trim();else if(typeof a.title=="string")return Mc(a)}}catch{}let n=s.match(/```(?:json)?\s*\n([\s\S]*?)\n?```/i);n&&(s=n[1].trim());let r=null;try{r=JSON.parse(s)}catch{let o=s.indexOf("{"),a=s.lastIndexOf("}");if(o>=0&&a>o)try{r=JSON.parse(s.slice(o,a+1))}catch{return null}else return null}return!r||typeof r!="object"?null:Mc(r)}function Mc(e){let t=e.title;if(typeof t!="string")return null;let s=Rf(t).trim();if(!s)return null;let n=e.evidence,r=typeof n=="string"?n.trim():"";return{title:s,evidence:r}}function Rf(e){return e.replace(/^["'`]+|["'`]+$/g,"")}function kf(e){let t=e.replace(/\s+/g," ").trim().replace(/[.!?]+$/g,"").trim();return t.length<=vc?t:t.slice(0,vc)}function Af(e,t){let s=e.auto_title??"";return!s&&e.has_alias&&(s=f().prepare("SELECT alias FROM session_aliases WHERE session_id = ?").get(e.id)?.alias??""),{session_id:e.id,title:s,source:e.auto_title_source,confidence:0,evidence:`skipped: ${t}`,written:!1,skipped:t}}async function gr(e,t={}){if(t.signal?.aborted)return{session_id:e,title:"",source:null,confidence:0,evidence:"aborted before start",written:!1,skipped:"aborted"};let s=bf(e);if(!s)throw new Error(`session not found: ${e}`);let n=Tf(s,t.force===!0);if(!n.eligible)return Af(s,n.reason);let r=t.budget??hf,o=Os(e,{budget:r});if(Sf(o))throw new nt(e);if(t.signal?.aborted)return{session_id:e,title:s.auto_title??"",source:s.auto_title_source,confidence:0,evidence:"aborted before CLI call",written:!1,skipped:"aborted"};let a=yf(o.bundle),c=t.model??Bs,d=await Ef(a,c);if(!d.success){let S=d.stderr.slice(-300);throw new Error(`claude CLI exited ${d.exitCode}: ${S||"no stderr captured"}`)}let u=wf(d.stdout);if(!u)throw new Error("failed to parse regeneration output: not valid JSON {title, evidence}");if(!u.title||!u.title.trim())throw new Error("regeneration produced empty title");let g=kf(u.title);if(!g)throw new Error("regeneration produced empty title after clamp");de(e,g,"agent");let b=Te(e)?.auto_title??g;return{session_id:e,title:b,source:"agent",confidence:xf(o),evidence:u.evidence||`regenerated from neighborhood (${Nf(o)})`,written:!0}}function Nf(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 xf(e){let t=e.parents.length,s=e.children.length,n=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,s)+.2*Math.min(1,n/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 Me}from"hono/streaming";import{bodyLimit as tS}from"hono/body-limit";import{z as j}from"zod";H();ge();import{createHash as Of}from"node:crypto";var hr=1,We="claude-haiku-4-5-20251001",Lf=3,Cf=32e3,Dc=2e3,If=30,vf=30,jf=30,Mf=30;function Df(e){let s=f().prepare(`SELECT s.id,
1158
1158
  NULLIF(sa.alias, '') AS alias,
1159
1159
  s.auto_title,
1160
1160
  s.auto_title_source,
@@ -1165,15 +1165,15 @@ ${s}`}function b_(e){return Te(e)?.auto_title_source??null}async function S_(e){
1165
1165
  FROM sessions s
1166
1166
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1167
1167
  LEFT JOIN projects p ON p.id = s.project_id
1168
- WHERE s.id = ?`).get(e);return s?{...s,alias_source:s.alias?"manual":null}:null}function Mc(e,t={}){if(e.message_count<Lf)return{eligible:!1,reason:"too-short"};let s=e.title_quality;if(s==="programmatic"||s==="recursive_meta")return{eligible:!1,reason:"low-signal-title"};if(e.auto_title_source==="agent"&&!e.alias)return{eligible:!1,reason:"agent-titled-no-override"};if(!t.force){let n=Be(e.id);if(n&&n.extractor_version>=_r)return{eligible:!1,reason:"already-extracted"}}return{eligible:!0}}function Ff(e){let t=Df(e);if(!t)return null;let n=f().prepare(`SELECT role, content_text
1168
+ WHERE s.id = ?`).get(e);return s?{...s,alias_source:s.alias?"manual":null}:null}function Fc(e,t={}){if(e.message_count<Lf)return{eligible:!1,reason:"too-short"};let s=e.title_quality;if(s==="programmatic"||s==="recursive_meta")return{eligible:!1,reason:"low-signal-title"};if(e.auto_title_source==="agent"&&!e.alias)return{eligible:!1,reason:"agent-titled-no-override"};if(!t.force){let n=Be(e.id);if(n&&n.extractor_version>=hr)return{eligible:!1,reason:"already-extracted"}}return{eligible:!0}}function Ff(e){let t=Df(e);if(!t)return null;let n=f().prepare(`SELECT role, content_text
1169
1169
  FROM messages
1170
1170
  WHERE session_id = ?
1171
1171
  AND is_sidechain = 0
1172
1172
  AND content_text IS NOT NULL
1173
- ORDER BY COALESCE(timestamp, ''), rowid`).all(e),r=[],o=0;for(let a of n){let c=a.role??"system",d=a.content_text.trim();if(!d)continue;let u=d.length>jc?d.slice(0,jc)+"\u2026":d,g=`${c}: ${u}`;if(o+g.length>Cf)break;r.push(g),o+=g.length}return{meta:t,excerpt:r.join(`
1173
+ ORDER BY COALESCE(timestamp, ''), rowid`).all(e),r=[],o=0;for(let a of n){let c=a.role??"system",d=a.content_text.trim();if(!d)continue;let u=d.length>Dc?d.slice(0,Dc)+"\u2026":d,g=`${c}: ${u}`;if(o+g.length>Cf)break;r.push(g),o+=g.length}return{meta:t,excerpt:r.join(`
1174
1174
 
1175
1175
  `)}}function Pf(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(`
1176
- `)}function Uf(e){return Array.isArray(e)&&e.every(t=>typeof t=="string")}function mr(e,t,s=!1){if(!Array.isArray(e))return[];let n=new Set,r=[];for(let o of e){if(typeof o!="string")continue;let a=s?o.trim().toLowerCase():o.trim();if(!(!a||a.length>256)&&!n.has(a)&&(n.add(a),r.push(a),r.length>=t))break}return r}function $f(e,t){if(!Array.isArray(e))return[];let s=new Set,n=[];for(let r of e){if(!r||typeof r!="object")continue;let o=r.term,a=r.freq;if(typeof o!="string")continue;let c=o.trim().toLowerCase();if(!c||c.length>128||s.has(c))continue;s.add(c);let d=typeof a=="number"&&Number.isFinite(a)&&a>0?Math.floor(a):1;if(n.push({term:c,frequency:d}),n.length>=t)break}return n}function Bf(e,t){if(!Array.isArray(e))return[];let s=[];for(let n of e){if(!n||typeof n!="object")continue;let r=n.error_type,o=n.snippet,a=n.file,c=typeof r=="string"&&r.trim().length>0?r.trim().slice(0,64):"unknown",d=typeof o=="string"?o.trim().replace(/\s+/g," ").slice(0,256):"";if(!d)continue;let u=typeof a=="string"&&a.trim().length>0?a.trim().slice(0,256):null,g=Of("sha256").update(`${c}::${d}`).digest("hex").slice(0,12);if(s.push({error_type:c,message_hash:g,snippet:d,file:u}),s.length>=t)break}return s}function Hf(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 s=t.indexOf("{"),n=t.lastIndexOf("}");if(s===-1||n===-1||n<=s)return null;let r=t.slice(s,n+1),o;try{o=JSON.parse(r)}catch{return null}let a=mr(o.files_written,200),c=mr(o.brands_mentioned,vf),d=$f(o.terms_introduced,If),u=mr(o.plan_ids_referenced,jf),g=Bf(o.bug_signatures,Mf);return a.length===0&&c.length===0&&d.length===0&&u.length===0&&g.length===0&&!Uf(o.files_written)?null:{files_written:a,brands_mentioned:c,terms_introduced:d,plan_ids_referenced:u,bug_signatures:g}}var gr=null;async function Wf(e,t){return gr?gr(e,t):Fe(e,[],{model:t})}async function fr(e,t={}){if(t.signal?.aborted)return{session_id:e,ok:!1,failed:"aborted"};let s=Ff(e);if(!s)return{session_id:e,ok:!1,skipped:"session-not-found"};let n=Mc(s.meta,{force:t.force});if(!n.eligible)return{session_id:e,ok:!1,skipped:n.reason};if(!gr&&!oe())return{session_id:e,ok:!1,failed:"claude-cli-missing"};let r=Pf(s),o=t.model??We,a=await Wf(r,o);if(!a.success)return{session_id:e,ok:!1,failed:"claude-cli-error",exit_code:a.exitCode};let c=Hf(a.stdout);if(!c)return{session_id:e,ok:!1,failed:"parse-failed",exit_code:a.exitCode};let d=qf(a.stdout),u=ya({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:d,raw_response_excerpt:a.stdout.slice(0,4e3)},extractor_version:_r});return{session_id:e,ok:!0,index:u,usage:d}}function qf(e){try{let t=JSON.parse(e.trim());if(t&&typeof t=="object"&&t.usage){let s=t.usage,n={};return typeof s.input_tokens=="number"&&(n.input_tokens=s.input_tokens),typeof s.output_tokens=="number"&&(n.output_tokens=s.output_tokens),n}}catch{}return null}function rt(e={}){let t=f(),s=[],n=[];typeof e.projectId=="number"&&(s.push("s.project_id = ?"),n.push(e.projectId));let r=Math.max(1,Math.min(1e4,e.limit??1e3)),o=s.length?`WHERE ${s.join(" AND ")}`:"",a=t.prepare(`SELECT s.id,
1176
+ `)}function Uf(e){return Array.isArray(e)&&e.every(t=>typeof t=="string")}function _r(e,t,s=!1){if(!Array.isArray(e))return[];let n=new Set,r=[];for(let o of e){if(typeof o!="string")continue;let a=s?o.trim().toLowerCase():o.trim();if(!(!a||a.length>256)&&!n.has(a)&&(n.add(a),r.push(a),r.length>=t))break}return r}function $f(e,t){if(!Array.isArray(e))return[];let s=new Set,n=[];for(let r of e){if(!r||typeof r!="object")continue;let o=r.term,a=r.freq;if(typeof o!="string")continue;let c=o.trim().toLowerCase();if(!c||c.length>128||s.has(c))continue;s.add(c);let d=typeof a=="number"&&Number.isFinite(a)&&a>0?Math.floor(a):1;if(n.push({term:c,frequency:d}),n.length>=t)break}return n}function Bf(e,t){if(!Array.isArray(e))return[];let s=[];for(let n of e){if(!n||typeof n!="object")continue;let r=n.error_type,o=n.snippet,a=n.file,c=typeof r=="string"&&r.trim().length>0?r.trim().slice(0,64):"unknown",d=typeof o=="string"?o.trim().replace(/\s+/g," ").slice(0,256):"";if(!d)continue;let u=typeof a=="string"&&a.trim().length>0?a.trim().slice(0,256):null,g=Of("sha256").update(`${c}::${d}`).digest("hex").slice(0,12);if(s.push({error_type:c,message_hash:g,snippet:d,file:u}),s.length>=t)break}return s}function Hf(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 s=t.indexOf("{"),n=t.lastIndexOf("}");if(s===-1||n===-1||n<=s)return null;let r=t.slice(s,n+1),o;try{o=JSON.parse(r)}catch{return null}let a=_r(o.files_written,200),c=_r(o.brands_mentioned,vf),d=$f(o.terms_introduced,If),u=_r(o.plan_ids_referenced,jf),g=Bf(o.bug_signatures,Mf);return a.length===0&&c.length===0&&d.length===0&&u.length===0&&g.length===0&&!Uf(o.files_written)?null:{files_written:a,brands_mentioned:c,terms_introduced:d,plan_ids_referenced:u,bug_signatures:g}}var fr=null;async function Wf(e,t){return fr?fr(e,t):Fe(e,[],{model:t})}async function Er(e,t={}){if(t.signal?.aborted)return{session_id:e,ok:!1,failed:"aborted"};let s=Ff(e);if(!s)return{session_id:e,ok:!1,skipped:"session-not-found"};let n=Fc(s.meta,{force:t.force});if(!n.eligible)return{session_id:e,ok:!1,skipped:n.reason};if(!fr&&!oe())return{session_id:e,ok:!1,failed:"claude-cli-missing"};let r=Pf(s),o=t.model??We,a=await Wf(r,o);if(!a.success)return{session_id:e,ok:!1,failed:"claude-cli-error",exit_code:a.exitCode};let c=Hf(a.stdout);if(!c)return{session_id:e,ok:!1,failed:"parse-failed",exit_code:a.exitCode};let d=qf(a.stdout),u=Ra({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:d,raw_response_excerpt:a.stdout.slice(0,4e3)},extractor_version:hr});return{session_id:e,ok:!0,index:u,usage:d}}function qf(e){try{let t=JSON.parse(e.trim());if(t&&typeof t=="object"&&t.usage){let s=t.usage,n={};return typeof s.input_tokens=="number"&&(n.input_tokens=s.input_tokens),typeof s.output_tokens=="number"&&(n.output_tokens=s.output_tokens),n}}catch{}return null}function rt(e={}){let t=f(),s=[],n=[];typeof e.projectId=="number"&&(s.push("s.project_id = ?"),n.push(e.projectId));let r=Math.max(1,Math.min(1e4,e.limit??1e3)),o=s.length?`WHERE ${s.join(" AND ")}`:"",a=t.prepare(`SELECT s.id,
1177
1177
  NULLIF(sa.alias, '') AS alias,
1178
1178
  s.auto_title,
1179
1179
  s.auto_title_source,
@@ -1185,48 +1185,48 @@ ${s}`}function b_(e){return Te(e)?.auto_title_source??null}async function S_(e){
1185
1185
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1186
1186
  LEFT JOIN projects p ON p.id = s.project_id
1187
1187
  ${o}
1188
- ORDER BY COALESCE(s.started_at, ''), s.id`).all(...n),c=[],d=new Map;for(let u of a){let g={...u,alias_source:u.alias?"manual":null},h=Mc(g,{force:e.force});if(!h.eligible){let b=h.reason??"session-not-found";d.set(b,(d.get(b)??0)+1);continue}if(c.push(g),c.length>=r)break}return{eligible:c,skipped:d}}async function Dc(e={}){let t=rt({projectId:e.projectId,limit:e.limit,force:e.force}),s={total:t.eligible.length,processed:0,ok:0,failed:0,skipped:0,current_session_id:null,total_input_tokens:0,total_output_tokens:0};for(let r of t.skipped.values())s.skipped+=r;e.onProgress?.({...s});let n=[];for(let r of t.eligible){if(e.signal?.aborted)break;s.current_session_id=r.id,e.onProgress?.({...s});let o=await fr(r.id,{model:e.model,force:e.force,signal:e.signal});n.push(o),e.onResult?.(o),o.ok?s.ok+=1:o.skipped?s.skipped+=1:s.failed+=1,o.usage?.input_tokens&&(s.total_input_tokens+=o.usage.input_tokens),o.usage?.output_tokens&&(s.total_output_tokens+=o.usage.output_tokens),s.processed+=1,e.onProgress?.({...s})}return s.current_session_id=null,e.onProgress?.({...s}),{progress:s,results:n}}H();H();ot();function Bt(e){return f().prepare("SELECT id, name FROM projects WHERE name = ? LIMIT 1").get(e)??null}H();function Bc(e){let t=f(),s=new Date().toISOString();return t.prepare(`INSERT INTO bug_signature_resolutions
1188
+ ORDER BY COALESCE(s.started_at, ''), s.id`).all(...n),c=[],d=new Map;for(let u of a){let g={...u,alias_source:u.alias?"manual":null},h=Fc(g,{force:e.force});if(!h.eligible){let b=h.reason??"session-not-found";d.set(b,(d.get(b)??0)+1);continue}if(c.push(g),c.length>=r)break}return{eligible:c,skipped:d}}async function Pc(e={}){let t=rt({projectId:e.projectId,limit:e.limit,force:e.force}),s={total:t.eligible.length,processed:0,ok:0,failed:0,skipped:0,current_session_id:null,total_input_tokens:0,total_output_tokens:0};for(let r of t.skipped.values())s.skipped+=r;e.onProgress?.({...s});let n=[];for(let r of t.eligible){if(e.signal?.aborted)break;s.current_session_id=r.id,e.onProgress?.({...s});let o=await Er(r.id,{model:e.model,force:e.force,signal:e.signal});n.push(o),e.onResult?.(o),o.ok?s.ok+=1:o.skipped?s.skipped+=1:s.failed+=1,o.usage?.input_tokens&&(s.total_input_tokens+=o.usage.input_tokens),o.usage?.output_tokens&&(s.total_output_tokens+=o.usage.output_tokens),s.processed+=1,e.onProgress?.({...s})}return s.current_session_id=null,e.onProgress?.({...s}),{progress:s,results:n}}H();H();ot();function Bt(e){return f().prepare("SELECT id, name FROM projects WHERE name = ? LIMIT 1").get(e)??null}H();function Wc(e){let t=f(),s=new Date().toISOString();return t.prepare(`INSERT INTO bug_signature_resolutions
1189
1189
  (message_hash, resolved_in_session_id, fix_summary, resolved_at, unresolved_at)
1190
1190
  VALUES (?, ?, ?, ?, NULL)
1191
1191
  ON CONFLICT(message_hash) DO UPDATE SET
1192
1192
  resolved_in_session_id = excluded.resolved_in_session_id,
1193
1193
  fix_summary = excluded.fix_summary,
1194
1194
  resolved_at = excluded.resolved_at,
1195
- unresolved_at = NULL`).run(e.messageHash,e.resolvedInSessionId??null,e.fixSummary??null,s),Kf(e.messageHash)}function Hc(e){f().prepare(`UPDATE bug_signature_resolutions
1195
+ unresolved_at = NULL`).run(e.messageHash,e.resolvedInSessionId??null,e.fixSummary??null,s),Kf(e.messageHash)}function qc(e){f().prepare(`UPDATE bug_signature_resolutions
1196
1196
  SET unresolved_at = ?
1197
- WHERE message_hash = ?`).run(new Date().toISOString(),e)}function Kf(e){return f().prepare("SELECT * FROM bug_signature_resolutions WHERE message_hash = ?").get(e)??null}function Er(e){if(e.length===0)return new Map;let t=f(),s=e.map(()=>"?").join(","),n=t.prepare(`SELECT * FROM bug_signature_resolutions
1198
- WHERE message_hash IN (${s})`).all(...e),r=new Map;for(let o of n)r.set(o.message_hash,o);return r}function br(e){return!!e&&e.unresolved_at===null}H();function Ht(){return new Date().toISOString()}function Sr(){let e=f(),t=e.prepare(`SELECT id, name, description, created_at, updated_at
1197
+ WHERE message_hash = ?`).run(new Date().toISOString(),e)}function Kf(e){return f().prepare("SELECT * FROM bug_signature_resolutions WHERE message_hash = ?").get(e)??null}function Sr(e){if(e.length===0)return new Map;let t=f(),s=e.map(()=>"?").join(","),n=t.prepare(`SELECT * FROM bug_signature_resolutions
1198
+ WHERE message_hash IN (${s})`).all(...e),r=new Map;for(let o of n)r.set(o.message_hash,o);return r}function Tr(e){return!!e&&e.unresolved_at===null}H();function Ht(){return new Date().toISOString()}function yr(){let e=f(),t=e.prepare(`SELECT id, name, description, created_at, updated_at
1199
1199
  FROM macro_repos
1200
1200
  ORDER BY name COLLATE NOCASE`).all();if(t.length===0)return[];let s=t.map(a=>a.id),n=s.map(()=>"?").join(","),r=e.prepare(`SELECT m.macro_repo_id, m.project_id, p.name AS project_name
1201
1201
  FROM macro_repo_members m
1202
1202
  JOIN projects p ON p.id = m.project_id
1203
1203
  WHERE m.macro_repo_id IN (${n})
1204
- ORDER BY p.name COLLATE NOCASE`).all(...s),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 it(e){return Sr().find(s=>s.id===e)??null}function Wc(){return f().prepare(`SELECT p.id, p.name
1204
+ ORDER BY p.name COLLATE NOCASE`).all(...s),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 it(e){return yr().find(s=>s.id===e)??null}function Jc(){return f().prepare(`SELECT p.id, p.name
1205
1205
  FROM projects p
1206
1206
  LEFT JOIN macro_repo_members m ON m.project_id = p.id
1207
1207
  WHERE m.project_id IS NULL
1208
- ORDER BY p.name COLLATE NOCASE`).all()}function qc(e){let t=e.name.trim();if(!t)throw new Error("macro repo name is required");let s=f(),n=Ht(),r=s.prepare(`INSERT INTO macro_repos (name, description, created_at, updated_at)
1209
- VALUES (?, ?, ?, ?)`).run(t,e.description??null,n,n),o=Number(r.lastInsertRowid);return it(o)}function Jc(e,t){let s=it(e);if(!s)throw new Error(`macro repo ${e} not found`);let n=t.name!==void 0?t.name.trim():s.name;if(!n)throw new Error("macro repo name cannot be empty");let r=t.description!==void 0?t.description:s.description;return f().prepare(`UPDATE macro_repos
1208
+ ORDER BY p.name COLLATE NOCASE`).all()}function Xc(e){let t=e.name.trim();if(!t)throw new Error("macro repo name is required");let s=f(),n=Ht(),r=s.prepare(`INSERT INTO macro_repos (name, description, created_at, updated_at)
1209
+ VALUES (?, ?, ?, ?)`).run(t,e.description??null,n,n),o=Number(r.lastInsertRowid);return it(o)}function Gc(e,t){let s=it(e);if(!s)throw new Error(`macro repo ${e} not found`);let n=t.name!==void 0?t.name.trim():s.name;if(!n)throw new Error("macro repo name cannot be empty");let r=t.description!==void 0?t.description:s.description;return f().prepare(`UPDATE macro_repos
1210
1210
  SET name = ?, description = ?, updated_at = ?
1211
- WHERE id = ?`).run(n,r,Ht(),e),it(e)}function Xc(e){f().prepare("DELETE FROM macro_repos WHERE id = ?").run(e)}function Gc(e,t){let s=f();if(!s.prepare("SELECT 1 FROM macro_repos WHERE id = ?").get(e))throw new Error(`macro repo ${e} not found`);if(!s.prepare("SELECT 1 FROM projects WHERE id = ?").get(t))throw new Error(`project ${t} not found`);s.prepare(`INSERT OR IGNORE INTO macro_repo_members (macro_repo_id, project_id, added_at)
1212
- VALUES (?, ?, ?)`).run(e,t,Ht()),s.prepare("UPDATE macro_repos SET updated_at = ? WHERE id = ?").run(Ht(),e)}function Yc(e,t){let s=f();s.prepare(`DELETE FROM macro_repo_members
1213
- WHERE macro_repo_id = ? AND project_id = ?`).run(e,t),s.prepare("UPDATE macro_repos SET updated_at = ? WHERE id = ?").run(Ht(),e)}H();function Kc(e){let t=f(),s=new Date().toISOString(),n=t.prepare(`INSERT INTO bug_synthesis_results
1211
+ WHERE id = ?`).run(n,r,Ht(),e),it(e)}function Yc(e){f().prepare("DELETE FROM macro_repos WHERE id = ?").run(e)}function Kc(e,t){let s=f();if(!s.prepare("SELECT 1 FROM macro_repos WHERE id = ?").get(e))throw new Error(`macro repo ${e} not found`);if(!s.prepare("SELECT 1 FROM projects WHERE id = ?").get(t))throw new Error(`project ${t} not found`);s.prepare(`INSERT OR IGNORE INTO macro_repo_members (macro_repo_id, project_id, added_at)
1212
+ VALUES (?, ?, ?)`).run(e,t,Ht()),s.prepare("UPDATE macro_repos SET updated_at = ? WHERE id = ?").run(Ht(),e)}function zc(e,t){let s=f();s.prepare(`DELETE FROM macro_repo_members
1213
+ WHERE macro_repo_id = ? AND project_id = ?`).run(e,t),s.prepare("UPDATE macro_repos SET updated_at = ? WHERE id = ?").run(Ht(),e)}H();function Vc(e){let t=f(),s=new Date().toISOString(),n=t.prepare(`INSERT INTO bug_synthesis_results
1214
1214
  (scope, target_id, mode, model, output_markdown, input_tokens, output_tokens, context_summary, created_at, job_id)
1215
- 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??{}),s,e.job_id??null),r=Number(n.lastInsertRowid);return Tr(r)}function zc(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 Tr(e){let s=f().prepare("SELECT * FROM bug_synthesis_results WHERE id = ?").get(e);return s?zc(s):null}function Vc(e={}){let t=f(),s=[],n=[];e.scope&&(s.push("scope = ?"),n.push(e.scope)),e.target_id&&(s.push("target_id = ?"),n.push(e.target_id));let r=s.length?`WHERE ${s.join(" AND ")}`:"",o=Math.min(Math.max(1,e.limit??50),500);return t.prepare(`SELECT * FROM bug_synthesis_results
1215
+ 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??{}),s,e.job_id??null),r=Number(n.lastInsertRowid);return wr(r)}function Zc(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 wr(e){let s=f().prepare("SELECT * FROM bug_synthesis_results WHERE id = ?").get(e);return s?Zc(s):null}function Qc(e={}){let t=f(),s=[],n=[];e.scope&&(s.push("scope = ?"),n.push(e.scope)),e.target_id&&(s.push("target_id = ?"),n.push(e.target_id));let r=s.length?`WHERE ${s.join(" AND ")}`:"",o=Math.min(Math.max(1,e.limit??50),500);return t.prepare(`SELECT * FROM bug_synthesis_results
1216
1216
  ${r}
1217
1217
  ORDER BY created_at DESC
1218
- LIMIT ?`).all(...n,o).map(zc)}function Zc(e){let s=f().prepare(`SELECT target_id, COUNT(*) AS n
1218
+ LIMIT ?`).all(...n,o).map(Zc)}function el(e){let s=f().prepare(`SELECT target_id, COUNT(*) AS n
1219
1219
  FROM bug_synthesis_results
1220
1220
  WHERE scope = ?
1221
- GROUP BY target_id`).all(e),n=new Map;for(let r of s)n.set(r.target_id,r.n);return n}function Qc(e){f().prepare("DELETE FROM bug_synthesis_results WHERE id = ?").run(e)}import{randomBytes as zf,timingSafeEqual as Vf}from"node:crypto";var Zf=6e4,Qf=new Set(["127.0.0.1","localhost"]),Wt=new Map;function yr(){return Date.now()}function el(){let e=yr();for(let[t,s]of Wt)(s.expiresAt<=e||s.used)&&Wt.delete(t)}function ye(e){let t=e.req.header("origin")??"";if(t)try{let r=new URL(t);if(!Qf.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 s=e.req.header("sec-fetch-site");return s&&s!=="same-origin"&&s!=="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 wr(e){el();let t=zf(32).toString("hex"),s=yr()+Zf;return Wt.set(t,{token:t,intent:e,expiresAt:s,used:!1}),{token:t,expiresAt:s}}function Rr(e){if(el(),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 s of Wt.values()){if(s.used||s.expiresAt<=yr())continue;let n;try{n=Buffer.from(s.token,"hex")}catch{continue}if(n.length===t.length&&Vf(n,t))return s.used=!0,Wt.delete(s.token),s.intent}return null}import{existsSync as oh,mkdirSync as FR,readFileSync as ih,writeFileSync as PR}from"node:fs";import{homedir as ah}from"node:os";import{join as al}from"node:path";import{z as kr}from"zod";import{appendFileSync as eh,existsSync as tl,mkdirSync as th,readFileSync as sh}from"node:fs";import{homedir as nh}from"node:os";import{join as sl}from"node:path";function nl(){return process.env.RECALL_HOME??sl(nh(),".recall")}function rh(){let e=nl();tl(e)||th(e,{recursive:!0})}function rl(){return sl(nl(),"launcher-audit.log")}function ee(e){rh();let t={ts:new Date().toISOString(),...e};try{eh(rl(),JSON.stringify(t)+`
1222
- `,"utf8")}catch(s){console.error("[launcher-audit] failed to append:",s)}}function ol(e){let t=rl();if(!tl(t))return{input_tokens:0,output_tokens:0,records_counted:0};let s=Date.now()-e,n=0,r=0,o=0,a;try{a=sh(t,"utf8")}catch{return{input_tokens:0,output_tokens:0,records_counted:0}}for(let c of a.split(`
1223
- `)){if(!c.trim())continue;let d;try{d=JSON.parse(c)}catch{continue}if(d.kind!=="run-completed"&&d.kind!=="synth-completed")continue;let u=Date.parse(d.ts);!Number.isFinite(u)||u<s||(n+=Number(d.input_tokens??0),r+=Number(d.output_tokens??0),o+=1)}return{input_tokens:n,output_tokens:r,records_counted:o}}var ch=1440*60*1e3,lh=kr.object({dailyTokenBudget:kr.number().int().nonnegative().default(1e6),sessionCeiling:kr.number().int().positive().max(1e4).default(500)}),Ar={dailyTokenBudget:1e6,sessionCeiling:500};function dh(){return process.env.RECALL_HOME??al(ah(),".recall")}function uh(){return al(dh(),"config.json")}function ph(){let e=uh();if(!oh(e))return{};try{return JSON.parse(ih(e,"utf8"))}catch(t){return console.error("[launcher-budget] failed to parse config.json, using defaults:",t),{}}}function Nr(){let e=ph().launcher;if(!e)return{...Ar};let t=lh.safeParse({...Ar,...e});return t.success?t.data:{...Ar}}function at(){let e=Nr(),t=ol(ch),s=t.input_tokens+t.output_tokens,n=Math.max(0,e.dailyTokenBudget-s);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:s,remaining_tokens_24h:n}}function xr(e){return{estimated_input_tokens_max:e*2e4,estimated_output_tokens_max:e*1e3}}function Or(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 s=Math.max(1,e.cluster_count??1);return{estimated_input_tokens_max:Math.min(5e4,1e3*s),estimated_output_tokens_max:t}}var il={pro:45,"max-5x":225,"max-20x":900};function mh(e){let t=e.toLowerCase();return t.includes("haiku")?1:t.includes("sonnet")?5:t.includes("opus")?10:5}var gh=4e3;function cl(e){return Math.max(1,Math.ceil(e/gh))}function Ce(e,t){let s=mh(t),n=e*s,r=Object.keys(il).map(o=>{let a=n/il[o];return{plan:o,fraction:a,pct:Math.round(a*1e3)/10,would_exhaust_window:a>1}});return{model:t,model_multiplier:s,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 _h}from"node:crypto";var ct=new Map,qt=new Map,fh=300*1e3;function qs(e,t,s){e.events.push({id:e.events.length+1,kind:t,data:s});for(let n of e.waiters)n();e.waiters.clear()}function hh(e){e.cleanupTimer||(e.cleanupTimer=setTimeout(()=>{ct.delete(e.jobId),qt.get(e.project)===e.jobId&&qt.delete(e.project)},fh),e.cleanupTimer.unref?.())}function Lr(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 ll(e){let t=Bt(e.project);if(!t)return{error:`project "${e.project}" not found`};let s=qt.get(t.name);if(s){let g=ct.get(s);if(g&&g.status==="running")return{jobId:s,reused:!0};qt.delete(t.name)}let n=_h(),r=e.model??We,o=Math.max(1,e.limit??200),a=e.force??!1,c=new AbortController,d=new Date().toISOString(),u={jobId:n,project:t.name,projectId:t.id,model:r,limit:o,force:a,status:"running",startedAt:d,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 ct.set(n,u),qt.set(t.name,n),ee({kind:"run-launched",job_id:n,project:t.name,model:r,limit:o,origin:e.origin??null}),(async()=>{await Promise.resolve();try{await Dc({projectId:t.id,limit:o,force:a,model:r,signal:c.signal,onProgress:g=>{u.progress=g,qs(u,"progress",g)},onResult:g=>{!g.ok&&!g.skipped&&qs(u,"error",{session_id:g.session_id,reason:g.failed??"unknown"})}}),u.status=c.signal.aborted?"cancelled":"done",u.endedAt=new Date().toISOString(),qs(u,"done",Lr(u)),ee({kind:u.status==="cancelled"?"run-cancelled":"run-completed",job_id:n,project:t.name,model:r,limit:o,origin:e.origin??null,input_tokens:u.progress.total_input_tokens,output_tokens:u.progress.total_output_tokens,sessions_processed:u.progress.processed})}catch(g){let h=g instanceof Error?g.message:String(g??"unknown error");u.status="failed",u.endedAt=new Date().toISOString(),u.error=h,qs(u,"done",Lr(u)),ee({kind:"run-failed",job_id:n,project:t.name,model:r,limit:o,origin:e.origin??null,reason:h,input_tokens:u.progress.total_input_tokens,output_tokens:u.progress.total_output_tokens})}finally{hh(u)}})(),{jobId:n,reused:!1}}async function*dl(e,t=0){let s=ct.get(e);if(!s)return;let n=t;for(;;){for(;n<s.events.length;){let r=s.events[n];if(!r)break;if(n+=1,yield r,r.kind==="done")return}if(s.status!=="running")return;await new Promise(r=>s.waiters.add(r))}}function ul(e){let t=ct.get(e);return!t||t.status!=="running"?!1:(t.controller.abort(),!0)}function Cr(e){let t=ct.get(e);return t?Lr(t):null}H();import{randomUUID as Eh}from"node:crypto";import{spawn as bh}from"node:child_process";import{execSync as Sh}from"node:child_process";var pl="claude-haiku-4-5-20251001",dt=new Map,Gt=new Map,Th=300*1e3;function ml(e){return`${e.scope}:${e.target_id}:${e.mode}`}function Jt(e,t,s){e.events.push({id:e.events.length+1,kind:t,data:s});for(let n of e.waiters)n();e.waiters.clear()}function yh(e){e.cleanupTimer||(e.cleanupTimer=setTimeout(()=>{dt.delete(e.jobId);let t=ml(e.intent);Gt.get(t)===e.jobId&&Gt.delete(t)},Th),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 gl(){return f().prepare(`SELECT s.id AS session_id, p.name AS project, s.auto_title,
1221
+ GROUP BY target_id`).all(e),n=new Map;for(let r of s)n.set(r.target_id,r.n);return n}function tl(e){f().prepare("DELETE FROM bug_synthesis_results WHERE id = ?").run(e)}import{randomBytes as zf,timingSafeEqual as Vf}from"node:crypto";var Zf=6e4,Qf=new Set(["127.0.0.1","localhost"]),Wt=new Map;function Rr(){return Date.now()}function sl(){let e=Rr();for(let[t,s]of Wt)(s.expiresAt<=e||s.used)&&Wt.delete(t)}function ye(e){let t=e.req.header("origin")??"";if(t)try{let r=new URL(t);if(!Qf.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 s=e.req.header("sec-fetch-site");return s&&s!=="same-origin"&&s!=="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 kr(e){sl();let t=zf(32).toString("hex"),s=Rr()+Zf;return Wt.set(t,{token:t,intent:e,expiresAt:s,used:!1}),{token:t,expiresAt:s}}function Ar(e){if(sl(),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 s of Wt.values()){if(s.used||s.expiresAt<=Rr())continue;let n;try{n=Buffer.from(s.token,"hex")}catch{continue}if(n.length===t.length&&Vf(n,t))return s.used=!0,Wt.delete(s.token),s.intent}return null}import{existsSync as oh,mkdirSync as FR,readFileSync as ih,writeFileSync as PR}from"node:fs";import{homedir as ah}from"node:os";import{join as ll}from"node:path";import{z as Nr}from"zod";import{appendFileSync as eh,existsSync as nl,mkdirSync as th,readFileSync as sh}from"node:fs";import{homedir as nh}from"node:os";import{join as rl}from"node:path";function ol(){return process.env.RECALL_HOME??rl(nh(),".recall")}function rh(){let e=ol();nl(e)||th(e,{recursive:!0})}function il(){return rl(ol(),"launcher-audit.log")}function ee(e){rh();let t={ts:new Date().toISOString(),...e};try{eh(il(),JSON.stringify(t)+`
1222
+ `,"utf8")}catch(s){console.error("[launcher-audit] failed to append:",s)}}function al(e){let t=il();if(!nl(t))return{input_tokens:0,output_tokens:0,records_counted:0};let s=Date.now()-e,n=0,r=0,o=0,a;try{a=sh(t,"utf8")}catch{return{input_tokens:0,output_tokens:0,records_counted:0}}for(let c of a.split(`
1223
+ `)){if(!c.trim())continue;let d;try{d=JSON.parse(c)}catch{continue}if(d.kind!=="run-completed"&&d.kind!=="synth-completed")continue;let u=Date.parse(d.ts);!Number.isFinite(u)||u<s||(n+=Number(d.input_tokens??0),r+=Number(d.output_tokens??0),o+=1)}return{input_tokens:n,output_tokens:r,records_counted:o}}var ch=1440*60*1e3,lh=Nr.object({dailyTokenBudget:Nr.number().int().nonnegative().default(1e6),sessionCeiling:Nr.number().int().positive().max(1e4).default(500)}),xr={dailyTokenBudget:1e6,sessionCeiling:500};function dh(){return process.env.RECALL_HOME??ll(ah(),".recall")}function uh(){return ll(dh(),"config.json")}function ph(){let e=uh();if(!oh(e))return{};try{return JSON.parse(ih(e,"utf8"))}catch(t){return console.error("[launcher-budget] failed to parse config.json, using defaults:",t),{}}}function Or(){let e=ph().launcher;if(!e)return{...xr};let t=lh.safeParse({...xr,...e});return t.success?t.data:{...xr}}function at(){let e=Or(),t=al(ch),s=t.input_tokens+t.output_tokens,n=Math.max(0,e.dailyTokenBudget-s);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:s,remaining_tokens_24h:n}}function Lr(e){return{estimated_input_tokens_max:e*2e4,estimated_output_tokens_max:e*1e3}}function Cr(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 s=Math.max(1,e.cluster_count??1);return{estimated_input_tokens_max:Math.min(5e4,1e3*s),estimated_output_tokens_max:t}}var cl={pro:45,"max-5x":225,"max-20x":900};function mh(e){let t=e.toLowerCase();return t.includes("haiku")?1:t.includes("sonnet")?5:t.includes("opus")?10:5}var gh=4e3;function dl(e){return Math.max(1,Math.ceil(e/gh))}function Ce(e,t){let s=mh(t),n=e*s,r=Object.keys(cl).map(o=>{let a=n/cl[o];return{plan:o,fraction:a,pct:Math.round(a*1e3)/10,would_exhaust_window:a>1}});return{model:t,model_multiplier:s,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 _h}from"node:crypto";var ct=new Map,qt=new Map,fh=300*1e3;function qs(e,t,s){e.events.push({id:e.events.length+1,kind:t,data:s});for(let n of e.waiters)n();e.waiters.clear()}function hh(e){e.cleanupTimer||(e.cleanupTimer=setTimeout(()=>{ct.delete(e.jobId),qt.get(e.project)===e.jobId&&qt.delete(e.project)},fh),e.cleanupTimer.unref?.())}function Ir(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 ul(e){let t=Bt(e.project);if(!t)return{error:`project "${e.project}" not found`};let s=qt.get(t.name);if(s){let g=ct.get(s);if(g&&g.status==="running")return{jobId:s,reused:!0};qt.delete(t.name)}let n=_h(),r=e.model??We,o=Math.max(1,e.limit??200),a=e.force??!1,c=new AbortController,d=new Date().toISOString(),u={jobId:n,project:t.name,projectId:t.id,model:r,limit:o,force:a,status:"running",startedAt:d,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 ct.set(n,u),qt.set(t.name,n),ee({kind:"run-launched",job_id:n,project:t.name,model:r,limit:o,origin:e.origin??null}),(async()=>{await Promise.resolve();try{await Pc({projectId:t.id,limit:o,force:a,model:r,signal:c.signal,onProgress:g=>{u.progress=g,qs(u,"progress",g)},onResult:g=>{!g.ok&&!g.skipped&&qs(u,"error",{session_id:g.session_id,reason:g.failed??"unknown"})}}),u.status=c.signal.aborted?"cancelled":"done",u.endedAt=new Date().toISOString(),qs(u,"done",Ir(u)),ee({kind:u.status==="cancelled"?"run-cancelled":"run-completed",job_id:n,project:t.name,model:r,limit:o,origin:e.origin??null,input_tokens:u.progress.total_input_tokens,output_tokens:u.progress.total_output_tokens,sessions_processed:u.progress.processed})}catch(g){let h=g instanceof Error?g.message:String(g??"unknown error");u.status="failed",u.endedAt=new Date().toISOString(),u.error=h,qs(u,"done",Ir(u)),ee({kind:"run-failed",job_id:n,project:t.name,model:r,limit:o,origin:e.origin??null,reason:h,input_tokens:u.progress.total_input_tokens,output_tokens:u.progress.total_output_tokens})}finally{hh(u)}})(),{jobId:n,reused:!1}}async function*pl(e,t=0){let s=ct.get(e);if(!s)return;let n=t;for(;;){for(;n<s.events.length;){let r=s.events[n];if(!r)break;if(n+=1,yield r,r.kind==="done")return}if(s.status!=="running")return;await new Promise(r=>s.waiters.add(r))}}function ml(e){let t=ct.get(e);return!t||t.status!=="running"?!1:(t.controller.abort(),!0)}function vr(e){let t=ct.get(e);return t?Ir(t):null}H();import{randomUUID as Eh}from"node:crypto";import{spawn as bh}from"node:child_process";import{execSync as Sh}from"node:child_process";var gl="claude-haiku-4-5-20251001",dt=new Map,Gt=new Map,Th=300*1e3;function _l(e){return`${e.scope}:${e.target_id}:${e.mode}`}function Jt(e,t,s){e.events.push({id:e.events.length+1,kind:t,data:s});for(let n of e.waiters)n();e.waiters.clear()}function yh(e){e.cleanupTimer||(e.cleanupTimer=setTimeout(()=>{dt.delete(e.jobId);let t=_l(e.intent);Gt.get(t)===e.jobId&&Gt.delete(t)},Th),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 fl(){return f().prepare(`SELECT s.id AS session_id, p.name AS project, s.auto_title,
1224
1224
  oi.bug_signatures
1225
1225
  FROM session_output_index oi
1226
1226
  JOIN sessions s ON s.id = oi.session_id
1227
1227
  JOIN projects p ON p.id = s.project_id
1228
1228
  WHERE oi.bug_signatures IS NOT NULL
1229
- AND oi.bug_signatures != '[]'`).all()}function _l(e){try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}function wh(e){let t=gl(),s=[];for(let a of t)for(let c of _l(a.bug_signatures)){let d=c.message_hash??`nohash:${(c.snippet??"").slice(0,64)}`;(c.message_hash===e||d===e)&&s.push({sig:c,session_id:a.session_id,project:a.project,auto_title:a.auto_title})}if(s.length===0)return null;let n=s[0],r=Array.from(new Set(s.map(a=>a.session_id))),o=Array.from(new Set(s.map(a=>a.project))).sort();return{message_hash:n.sig.message_hash??null,error_type:n.sig.error_type??null,snippet:(n.sig.snippet??"").slice(0,400),file:n.sig.file??null,occurrence_count:s.length,projects:o,member_session_ids:r}}function Rh(e){let t=gl().filter(o=>o.project===e),s=new Map;for(let o of t)for(let a of _l(o.bug_signatures)){let c=a.message_hash??`nohash:${(a.snippet??"").slice(0,64)}`,d=s.get(c);d?(d.sigs.push(a),d.sessions.add(o.session_id)):s.set(c,{sigs:[a],first:a,sessions:new Set([o.session_id])})}let n=new Map;try{let o=Array.from(s.keys()).filter(a=>!a.startsWith("nohash:"));if(o.length>0){let a=f(),c=o.map(()=>"?").join(","),d=a.prepare(`SELECT message_hash, fix_summary
1229
+ AND oi.bug_signatures != '[]'`).all()}function hl(e){try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}function wh(e){let t=fl(),s=[];for(let a of t)for(let c of hl(a.bug_signatures)){let d=c.message_hash??`nohash:${(c.snippet??"").slice(0,64)}`;(c.message_hash===e||d===e)&&s.push({sig:c,session_id:a.session_id,project:a.project,auto_title:a.auto_title})}if(s.length===0)return null;let n=s[0],r=Array.from(new Set(s.map(a=>a.session_id))),o=Array.from(new Set(s.map(a=>a.project))).sort();return{message_hash:n.sig.message_hash??null,error_type:n.sig.error_type??null,snippet:(n.sig.snippet??"").slice(0,400),file:n.sig.file??null,occurrence_count:s.length,projects:o,member_session_ids:r}}function Rh(e){let t=fl().filter(o=>o.project===e),s=new Map;for(let o of t)for(let a of hl(o.bug_signatures)){let c=a.message_hash??`nohash:${(a.snippet??"").slice(0,64)}`,d=s.get(c);d?(d.sigs.push(a),d.sessions.add(o.session_id)):s.set(c,{sigs:[a],first:a,sessions:new Set([o.session_id])})}let n=new Map;try{let o=Array.from(s.keys()).filter(a=>!a.startsWith("nohash:"));if(o.length>0){let a=f(),c=o.map(()=>"?").join(","),d=a.prepare(`SELECT message_hash, fix_summary
1230
1230
  FROM bug_signature_resolutions
1231
1231
  WHERE message_hash IN (${c})
1232
1232
  AND unresolved_at IS NULL`).all(...o);for(let u of d)n.set(u.message_hash,{fix_summary:u.fix_summary})}}catch{}let r=[];for(let[o,a]of s){let c=a.first.message_hash??null,d=c?n.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:d!==null,fix_summary:d?.fix_summary??null})}return r.sort((o,a)=>a.occurrence_count-o.occurrence_count),r}function kh(e){let t=e.replace(/\s+/g," ").trim();return t.length===0?"":t.slice(0,Math.min(30,t.length))}function Ah(e,t){let s=f(),n=kh(t),r=[];for(let o of e.slice(0,8)){let a=s.prepare(`SELECT s.id, p.name AS project, s.auto_title
@@ -1303,17 +1303,17 @@ Clusters that suggest deeper issues (multiple files, repeated patterns).
1303
1303
  high / medium / low.`;function vh(e,t){let s;return e.scope==="cluster"?s=e.mode==="root_cause"?Ch:Lh:s=Ih,[Nh,"",t,"",s].join(`
1304
1304
  `)}var jh=null;var Xt;function Mh(){if(Xt)return Xt;try{Xt=Sh("which claude",{encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim()}catch{Xt="claude"}return Xt}function Dh(e){let t="";return s=>{t+=s.toString("utf8");let n=t.indexOf(`
1305
1305
  `);for(;n!==-1;){let r=t.slice(0,n);t=t.slice(n+1),r.length>0&&e(r),n=t.indexOf(`
1306
- `)}}}function Fh(e){return new Promise(t=>{let s=["-p",e.prompt,"--output-format","stream-json","--verbose","--allowedTools","","--permission-mode","bypassPermissions","--model",e.model],n="",r=0,o=0,a=null,c=bh(Mh(),s,{stdio:["ignore","pipe","pipe"]}),d=()=>{try{c.kill("SIGTERM")}catch{}};e.signal.addEventListener("abort",d,{once:!0});let g=Dh(b=>{let S=b.trim();if(!S.startsWith("{"))return;let y;try{y=JSON.parse(S)}catch{return}if(!y||typeof y!="object")return;let k=y;if(k.type==="assistant"&&k.message?.content){for(let D of k.message.content)D?.type==="text"&&typeof D.text=="string"&&(n+=D.text,e.onPartial(D.text,n));let w=k.message?.usage;w&&(typeof w.input_tokens=="number"&&(r=Math.max(r,w.input_tokens)),typeof w.output_tokens=="number"&&(o=Math.max(o,w.output_tokens)))}});c.stdout.on("data",b=>g(b)),c.stderr.on("data",b=>{let S=b.toString("utf8");S.trim()&&(a=(a??"")+S)});let h=setTimeout(()=>{try{c.kill("SIGKILL")}catch{}},1800*1e3);c.on("close",b=>{clearTimeout(h),e.signal.removeEventListener("abort",d);let S=b===0?null:a&&a.trim()||(e.signal.aborted?null:`claude CLI exited with code ${b}`);t({output_markdown:n,input_tokens:r,output_tokens:o,error:S})}),c.on("error",b=>{clearTimeout(h),e.signal.removeEventListener("abort",d),t({output_markdown:n,input_tokens:r,output_tokens:o,error:b instanceof Error?b.message:String(b)})})})}function Js(e){if(e.scope==="cluster"){let r=wh(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=Rh(e.target_id);if(t.length===0)return null;let s=t.slice(0,30),n=t.reduce((r,o)=>r+o.occurrence_count,0);return{project_clusters:s,total_project_clusters:t.length,context_summary:{cluster_count:t.length,session_count:0,findings_count:n}}}function fl(e){let t=Js(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 s=ml(e.intent),n=Gt.get(s);if(n){let d=dt.get(n);if(d&&d.status==="running")return{jobId:n,reused:!0};Gt.delete(s)}let r=Eh(),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 dt.set(r,c),Gt.set(s,r),ee({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 d;if(e.intent.scope==="cluster"&&t.cluster){let b=Ah(t.cluster.member_session_ids,t.cluster.snippet);d=xh(t.cluster,b)}else if(e.intent.scope==="project"&&t.project_clusters)d=Oh(e.intent.target_id,t.project_clusters,t.total_project_clusters??t.project_clusters.length);else throw new Error("inconsistent prepared context");let u=vh(e.intent,d),h=await(jh??Fh)({prompt:u,model:e.intent.model,signal:o.signal,onPartial:(b,S)=>{c.output_markdown=S,Jt(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(),Jt(c,"done",lt(c)),ee({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,Jt(c,"done",lt(c)),ee({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(),Jt(c,"done",lt(c)),ee({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{Kc({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(d){let u=d instanceof Error?d.message:String(d??"unknown error");c.status="failed",c.endedAt=new Date().toISOString(),c.error=u,Jt(c,"done",lt(c)),ee({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:u,input_tokens:c.input_tokens,output_tokens:c.output_tokens})}finally{yh(c)}})(),{jobId:r,reused:!1}}async function*hl(e,t=0){let s=dt.get(e);if(!s)return;let n=t;for(;;){for(;n<s.events.length;){let r=s.events[n];if(!r)break;if(n+=1,yield r,r.kind==="done")return}if(s.status!=="running")return;await new Promise(r=>s.waiters.add(r))}}function El(e){let t=dt.get(e);return!t||t.status!=="running"?!1:(t.controller.abort(),!0)}function Ir(e){let t=dt.get(e);return t?lt(t):null}import{randomUUID as zh}from"node:crypto";H();import{randomUUID as Xh}from"node:crypto";H();var bl=10,Sl=20;function Ph(e){if(!e)return!1;let t=e.split(`
1307
- `);if(t.length<4)return!1;let s=0,n=0;for(let r of t)/^\s*\d{1,5}\t/.test(r)?s++:/^\s*\/[A-Za-z0-9_./-]+/.test(r.trim())&&n++;return s/t.length>.7||n/t.length>.5}function Uh(e){let t=e.byteLength/4;if(!Number.isInteger(t)||t<=0)return null;let s=new Float32Array(t),n=new Float32Array(e.buffer,e.byteOffset,t);return s.set(n),s}function Tl(e){let t=0;for(let n=0;n<e.length;n++)t+=e[n]*e[n];if(t<=0)return!1;let s=1/Math.sqrt(t);for(let n=0;n<e.length;n++)e[n]*=s;return!0}function vr(e){if(e.length===0)return null;let t=e[0].length,s=new Float32Array(t);for(let n of e)if(n.length===t)for(let r=0;r<t;r++)s[r]+=n[r];for(let n=0;n<t;n++)s[n]/=e.length;return Tl(s)?s:null}function yl(e){let t=new Map;if(e.length===0)return t;let s=f(),n=e.map(()=>"?").join(","),r=[];try{r=s.prepare(`SELECT cm.rowid AS rowid, cm.session_id AS session_id,
1306
+ `)}}}function Fh(e){return new Promise(t=>{let s=["-p",e.prompt,"--output-format","stream-json","--verbose","--allowedTools","","--permission-mode","bypassPermissions","--model",e.model],n="",r=0,o=0,a=null,c=bh(Mh(),s,{stdio:["ignore","pipe","pipe"]}),d=()=>{try{c.kill("SIGTERM")}catch{}};e.signal.addEventListener("abort",d,{once:!0});let g=Dh(b=>{let S=b.trim();if(!S.startsWith("{"))return;let y;try{y=JSON.parse(S)}catch{return}if(!y||typeof y!="object")return;let k=y;if(k.type==="assistant"&&k.message?.content){for(let D of k.message.content)D?.type==="text"&&typeof D.text=="string"&&(n+=D.text,e.onPartial(D.text,n));let w=k.message?.usage;w&&(typeof w.input_tokens=="number"&&(r=Math.max(r,w.input_tokens)),typeof w.output_tokens=="number"&&(o=Math.max(o,w.output_tokens)))}});c.stdout.on("data",b=>g(b)),c.stderr.on("data",b=>{let S=b.toString("utf8");S.trim()&&(a=(a??"")+S)});let h=setTimeout(()=>{try{c.kill("SIGKILL")}catch{}},1800*1e3);c.on("close",b=>{clearTimeout(h),e.signal.removeEventListener("abort",d);let S=b===0?null:a&&a.trim()||(e.signal.aborted?null:`claude CLI exited with code ${b}`);t({output_markdown:n,input_tokens:r,output_tokens:o,error:S})}),c.on("error",b=>{clearTimeout(h),e.signal.removeEventListener("abort",d),t({output_markdown:n,input_tokens:r,output_tokens:o,error:b instanceof Error?b.message:String(b)})})})}function Js(e){if(e.scope==="cluster"){let r=wh(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=Rh(e.target_id);if(t.length===0)return null;let s=t.slice(0,30),n=t.reduce((r,o)=>r+o.occurrence_count,0);return{project_clusters:s,total_project_clusters:t.length,context_summary:{cluster_count:t.length,session_count:0,findings_count:n}}}function El(e){let t=Js(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 s=_l(e.intent),n=Gt.get(s);if(n){let d=dt.get(n);if(d&&d.status==="running")return{jobId:n,reused:!0};Gt.delete(s)}let r=Eh(),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 dt.set(r,c),Gt.set(s,r),ee({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 d;if(e.intent.scope==="cluster"&&t.cluster){let b=Ah(t.cluster.member_session_ids,t.cluster.snippet);d=xh(t.cluster,b)}else if(e.intent.scope==="project"&&t.project_clusters)d=Oh(e.intent.target_id,t.project_clusters,t.total_project_clusters??t.project_clusters.length);else throw new Error("inconsistent prepared context");let u=vh(e.intent,d),h=await(jh??Fh)({prompt:u,model:e.intent.model,signal:o.signal,onPartial:(b,S)=>{c.output_markdown=S,Jt(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(),Jt(c,"done",lt(c)),ee({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,Jt(c,"done",lt(c)),ee({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(),Jt(c,"done",lt(c)),ee({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{Vc({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(d){let u=d instanceof Error?d.message:String(d??"unknown error");c.status="failed",c.endedAt=new Date().toISOString(),c.error=u,Jt(c,"done",lt(c)),ee({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:u,input_tokens:c.input_tokens,output_tokens:c.output_tokens})}finally{yh(c)}})(),{jobId:r,reused:!1}}async function*bl(e,t=0){let s=dt.get(e);if(!s)return;let n=t;for(;;){for(;n<s.events.length;){let r=s.events[n];if(!r)break;if(n+=1,yield r,r.kind==="done")return}if(s.status!=="running")return;await new Promise(r=>s.waiters.add(r))}}function Sl(e){let t=dt.get(e);return!t||t.status!=="running"?!1:(t.controller.abort(),!0)}function jr(e){let t=dt.get(e);return t?lt(t):null}import{randomUUID as zh}from"node:crypto";H();import{randomUUID as Xh}from"node:crypto";H();var Tl=10,yl=20;function Ph(e){if(!e)return!1;let t=e.split(`
1307
+ `);if(t.length<4)return!1;let s=0,n=0;for(let r of t)/^\s*\d{1,5}\t/.test(r)?s++:/^\s*\/[A-Za-z0-9_./-]+/.test(r.trim())&&n++;return s/t.length>.7||n/t.length>.5}function Uh(e){let t=e.byteLength/4;if(!Number.isInteger(t)||t<=0)return null;let s=new Float32Array(t),n=new Float32Array(e.buffer,e.byteOffset,t);return s.set(n),s}function wl(e){let t=0;for(let n=0;n<e.length;n++)t+=e[n]*e[n];if(t<=0)return!1;let s=1/Math.sqrt(t);for(let n=0;n<e.length;n++)e[n]*=s;return!0}function Mr(e){if(e.length===0)return null;let t=e[0].length,s=new Float32Array(t);for(let n of e)if(n.length===t)for(let r=0;r<t;r++)s[r]+=n[r];for(let n=0;n<t;n++)s[n]/=e.length;return wl(s)?s:null}function Rl(e){let t=new Map;if(e.length===0)return t;let s=f(),n=e.map(()=>"?").join(","),r=[];try{r=s.prepare(`SELECT cm.rowid AS rowid, cm.session_id AS session_id,
1308
1308
  cm.text AS text, v.embedding AS embedding
1309
1309
  FROM chunk_meta cm
1310
1310
  JOIN vec_chunks v ON v.rowid = cm.rowid
1311
1311
  WHERE cm.stale = 0
1312
1312
  AND cm.session_id IN (${n})
1313
- 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 d=c.filter(M=>!Ph(M.text)),u=d.length>0?d:c,g=[];for(let M of u){let B=Uh(M.embedding);B&&Tl(B)&&g.push(B)}if(g.length===0)continue;let h=Math.min(bl,g.length),b=Math.max(0,g.length-bl),S=g.slice(0,h),y=g.slice(b),k=vr(S),w=vr(y),D=vr(g),L=new Map;for(let M=0;M<S.length&&L.size<Sl;M++)L.set(M,S[M]);for(let M=0;M<y.length&&L.size<Sl;M++)L.set(b+M,y[M]);let X=Array.from(L.values());t.set(a,{session_id:a,full_mean:D,head_pool:k,tail_pool:w,sample_chunks:X})}return t}function $h(e,t){if(e.length!==t.length)return 0;let s=0;for(let n=0;n<e.length;n++)s+=e[n]*t[n];return s<-1?-1:s>1?1:s}function wl(e,t=.8){let s=new Map,n=[],r=[];for(let[u,g]of e)g.full_mean&&(n.push(u),r.push(g.full_mean));if(n.length===0)return s;let o=new Int32Array(n.length);for(let u=0;u<o.length;u++)o[u]=u;let a=u=>{let g=u;for(;o[g]!==g;)g=o[g];let h=u;for(;o[h]!==g;){let b=o[h];o[h]=g,h=b}return g},c=(u,g)=>{let h=a(u),b=a(g);h!==b&&(o[h]=b)};for(let u=0;u<n.length;u++)for(let g=u+1;g<n.length;g++)$h(r[u],r[g])>=t&&c(u,g);let d=new Map;for(let u=0;u<n.length;u++){let g=a(u),h=d.get(g);h===void 0&&(h=d.size,d.set(g,h)),s.set(n[u],h)}return s}var Ae={lo:.4,hi:.7},ut="claude-haiku-4-5-20251001",pt=50,Rl=1500,kl=50,Bh={same_workflow:.15,unrelated:-.2,unsure:0};function Al(e,t,s=Ae){if(s.lo>s.hi)throw new Error(`borderline band invalid: lo=${s.lo} > hi=${s.hi}`);let n=[];for(let r of e){if(r.confidence<s.lo||r.confidence>s.hi)continue;let o=t.get(r.parent_id),a=t.get(r.child_id);!o||!a||n.push({parent:o,child:a,step1:r})}return n.sort((r,o)=>r.child.started_at_ms-o.child.started_at_ms),n}function Nl(e,t=Ae){let s=0;for(let n of e)n.confidence>=t.lo&&n.confidence<=t.hi&&s++;return s}function Hh(e,t){let s=e.replace(/\s+/g," ").trim();return s.length>t?s.slice(0,t-1)+"\u2026":s}function Wh(e,t){if(e===null)return"unknown";let s=t-e;if(s<0)return"overlap";let n=Math.round(s/6e4);if(n<60)return`${n}m`;let r=Math.round(s/36e5);return r<24?`${r}h`:`${Math.round(s/864e5)}d`}function qh(e){let s=e.parent.recent_user_messages,n=e.child.recent_user_messages,r=s.slice(0,3),o=s.length>3?s.slice(-3):[],a=n.slice(0,3),c=u=>u.length===0?" (none captured)":u.map(g=>` - ${Hh(g,500)}`).join(`
1313
+ 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 d=c.filter(M=>!Ph(M.text)),u=d.length>0?d:c,g=[];for(let M of u){let B=Uh(M.embedding);B&&wl(B)&&g.push(B)}if(g.length===0)continue;let h=Math.min(Tl,g.length),b=Math.max(0,g.length-Tl),S=g.slice(0,h),y=g.slice(b),k=Mr(S),w=Mr(y),D=Mr(g),L=new Map;for(let M=0;M<S.length&&L.size<yl;M++)L.set(M,S[M]);for(let M=0;M<y.length&&L.size<yl;M++)L.set(b+M,y[M]);let X=Array.from(L.values());t.set(a,{session_id:a,full_mean:D,head_pool:k,tail_pool:w,sample_chunks:X})}return t}function $h(e,t){if(e.length!==t.length)return 0;let s=0;for(let n=0;n<e.length;n++)s+=e[n]*t[n];return s<-1?-1:s>1?1:s}function kl(e,t=.8){let s=new Map,n=[],r=[];for(let[u,g]of e)g.full_mean&&(n.push(u),r.push(g.full_mean));if(n.length===0)return s;let o=new Int32Array(n.length);for(let u=0;u<o.length;u++)o[u]=u;let a=u=>{let g=u;for(;o[g]!==g;)g=o[g];let h=u;for(;o[h]!==g;){let b=o[h];o[h]=g,h=b}return g},c=(u,g)=>{let h=a(u),b=a(g);h!==b&&(o[h]=b)};for(let u=0;u<n.length;u++)for(let g=u+1;g<n.length;g++)$h(r[u],r[g])>=t&&c(u,g);let d=new Map;for(let u=0;u<n.length;u++){let g=a(u),h=d.get(g);h===void 0&&(h=d.size,d.set(g,h)),s.set(n[u],h)}return s}var Ae={lo:.4,hi:.7},ut="claude-haiku-4-5-20251001",pt=50,Al=1500,Nl=50,Bh={same_workflow:.15,unrelated:-.2,unsure:0};function xl(e,t,s=Ae){if(s.lo>s.hi)throw new Error(`borderline band invalid: lo=${s.lo} > hi=${s.hi}`);let n=[];for(let r of e){if(r.confidence<s.lo||r.confidence>s.hi)continue;let o=t.get(r.parent_id),a=t.get(r.child_id);!o||!a||n.push({parent:o,child:a,step1:r})}return n.sort((r,o)=>r.child.started_at_ms-o.child.started_at_ms),n}function Ol(e,t=Ae){let s=0;for(let n of e)n.confidence>=t.lo&&n.confidence<=t.hi&&s++;return s}function Hh(e,t){let s=e.replace(/\s+/g," ").trim();return s.length>t?s.slice(0,t-1)+"\u2026":s}function Wh(e,t){if(e===null)return"unknown";let s=t-e;if(s<0)return"overlap";let n=Math.round(s/6e4);if(n<60)return`${n}m`;let r=Math.round(s/36e5);return r<24?`${r}h`:`${Math.round(s/864e5)}d`}function qh(e){let s=e.parent.recent_user_messages,n=e.child.recent_user_messages,r=s.slice(0,3),o=s.length>3?s.slice(-3):[],a=n.slice(0,3),c=u=>u.length===0?" (none captured)":u.map(g=>` - ${Hh(g,500)}`).join(`
1314
1314
  `),d=Wh(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(u=>` - ${u}`).join(`
1315
1315
  `),` step1_confidence: ${e.step1.confidence.toFixed(2)}`,"","PARENT SESSION","First user messages:",c(r),"Last user messages:",c(o),"",`CHILD SESSION (gap from parent: ${d})`,"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(`
1316
- `)}function Jh(e){if(!e)return null;let t=e.trim();if(!t)return null;let s=t;try{let d=JSON.parse(t);typeof d.result=="string"&&(s=d.result.trim())}catch{}let n=s.match(/\{[\s\S]*\}/);if(!n)return null;let r;try{r=JSON.parse(n[0])}catch{return null}if(!r||typeof r!="object")return null;let o=r,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:Bh[a]}}async function xl(e,t={}){if(t.signal?.aborted)return null;let s=t.model??ut,n=qh(e),r=t.spawn;if(!r)try{let a=await Promise.resolve().then(()=>(ge(),Pe));if(!a.isClaudeCliAvailable())return null;r=(c,d)=>a.spawnClaudePrompt(c,[],d)}catch{return null}let o;try{o=await Promise.race([r(n,{model:s}),new Promise(a=>{t.signal&&t.signal.addEventListener("abort",()=>a({success:!1,stdout:""}),{once:!0})})])}catch{return null}return!o.success||!o.stdout?null:Jh(o.stdout)}function Ol(e){let t=[];for(let s of e.proposals){let n=`${s.parent_id}::${s.child_id}`,r=e.rescored.get(n);if(!r){t.push(s);continue}let o=Math.max(0,Math.min(1,s.confidence+r.delta));if(o<e.applyThreshold)continue;let a=`LLM: ${r.verdict}${r.reason?` \u2014 ${r.reason}`:""} (${r.delta>=0?"+":""}${r.delta.toFixed(2)})`;t.push({...s,confidence:o,reasons:[...s.reasons,a]})}return t}function Ll(e){return`${e.parent_id}::${e.child_id}`}async function Gh(e){if(e.signal?.aborted)return null;let t,s;try{({spawnClaudePrompt:t,isClaudeCliAvailable:s}=await Promise.resolve().then(()=>(ge(),Pe)))}catch{return null}if(!s())return null;let n=[];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)");n.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:
1316
+ `)}function Jh(e){if(!e)return null;let t=e.trim();if(!t)return null;let s=t;try{let d=JSON.parse(t);typeof d.result=="string"&&(s=d.result.trim())}catch{}let n=s.match(/\{[\s\S]*\}/);if(!n)return null;let r;try{r=JSON.parse(n[0])}catch{return null}if(!r||typeof r!="object")return null;let o=r,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:Bh[a]}}async function Ll(e,t={}){if(t.signal?.aborted)return null;let s=t.model??ut,n=qh(e),r=t.spawn;if(!r)try{let a=await Promise.resolve().then(()=>(ge(),Pe));if(!a.isClaudeCliAvailable())return null;r=(c,d)=>a.spawnClaudePrompt(c,[],d)}catch{return null}let o;try{o=await Promise.race([r(n,{model:s}),new Promise(a=>{t.signal&&t.signal.addEventListener("abort",()=>a({success:!1,stdout:""}),{once:!0})})])}catch{return null}return!o.success||!o.stdout?null:Jh(o.stdout)}function Cl(e){let t=[];for(let s of e.proposals){let n=`${s.parent_id}::${s.child_id}`,r=e.rescored.get(n);if(!r){t.push(s);continue}let o=Math.max(0,Math.min(1,s.confidence+r.delta));if(o<e.applyThreshold)continue;let a=`LLM: ${r.verdict}${r.reason?` \u2014 ${r.reason}`:""} (${r.delta>=0?"+":""}${r.delta.toFixed(2)})`;t.push({...s,confidence:o,reasons:[...s.reasons,a]})}return t}function Il(e){return`${e.parent_id}::${e.child_id}`}async function Gh(e){if(e.signal?.aborted)return null;let t,s;try{({spawnClaudePrompt:t,isClaudeCliAvailable:s}=await Promise.resolve().then(()=>(ge(),Pe)))}catch{return null}if(!s())return null;let n=[];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)");n.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:
1317
1317
  - 4 to 8 words
1318
1318
  - Title-case, no trailing punctuation
1319
1319
  - Capture the WORKFLOW (e.g., "Update Remotion deps + lint cleanup"), not any one session
@@ -1324,7 +1324,7 @@ Sessions:
1324
1324
  `+n.join(`
1325
1325
  `)+`
1326
1326
 
1327
- 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}))}),d=await Promise.race([o,c]);if(a&&e.signal&&e.signal.removeEventListener("abort",a),!d||!d.success)return null;let u=d.stdout.trim();if(!u)return null;let g;try{let h=JSON.parse(u);g=typeof h.result=="string"?h.result:u}catch{g=u}return g=g.trim().replace(/^["'`]+|["'`]+$/g,"").replace(/[.!?]+$/g,"").trim(),g?g.length>80?g.slice(0,77)+"...":g:null}catch{return null}}function jr(e){return Yh(e)}function Mr(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 s=e.map(o=>o.id),n=new Map;try{n=yl(s)}catch{n=new Map}let r=new Map;for(let[o,a]of t){let c=new Map;for(let g of a){let h=n.get(g.id);h&&c.set(g.id,h)}let d=wl(c,.8),u=[];for(let g of a){let h=Kh(g,n,d);h&&u.push(h)}r.set(o,u)}return{byProject:t,scannablesByProject:r}}function Il(e){return f().prepare(`SELECT COUNT(DISTINCT t.id) AS n
1327
+ 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}))}),d=await Promise.race([o,c]);if(a&&e.signal&&e.signal.removeEventListener("abort",a),!d||!d.success)return null;let u=d.stdout.trim();if(!u)return null;let g;try{let h=JSON.parse(u);g=typeof h.result=="string"?h.result:u}catch{g=u}return g=g.trim().replace(/^["'`]+|["'`]+$/g,"").replace(/[.!?]+$/g,"").trim(),g?g.length>80?g.slice(0,77)+"...":g:null}catch{return null}}function Dr(e){return Yh(e)}function Fr(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 s=e.map(o=>o.id),n=new Map;try{n=Rl(s)}catch{n=new Map}let r=new Map;for(let[o,a]of t){let c=new Map;for(let g of a){let h=n.get(g.id);h&&c.set(g.id,h)}let d=kl(c,.8),u=[];for(let g of a){let h=Kh(g,n,d);h&&u.push(h)}r.set(o,u)}return{byProject:t,scannablesByProject:r}}function jl(e){return f().prepare(`SELECT COUNT(DISTINCT t.id) AS n
1328
1328
  FROM threads t
1329
1329
  JOIN thread_edges te ON te.thread_id = t.id
1330
1330
  JOIN sessions s ON s.id = te.session_id
@@ -1337,14 +1337,14 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1337
1337
  JOIN projects p ON p.id = s.project_id
1338
1338
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1339
1339
  WHERE ${n}
1340
- ORDER BY p.name ASC, s.started_at ASC`).all(s)}function Kh(e,t,s){if(!e.started_at)return null;let n=Date.parse(e.started_at);if(!Number.isFinite(n))return null;let r=e.ended_at?Date.parse(e.ended_at):null,o=ys(e.file_path,{maxUserMessages:7}),a=t?.get(e.id);return{id:e.id,started_at_ms:n,ended_at_ms:Number.isFinite(r)?r:null,first_user_message:e.first_user_message,recent_user_messages:o.recent_user_messages,auto_title:e.auto_title,touched_files:o.touched_files,mean_embedding:a?.full_mean??null,head_pool:a?.head_pool??null,tail_pool:a?.tail_pool??null,sample_chunks:a?.sample_chunks??[],cluster_id:s?.get(e.id)??null,authored_paths:o.authored_paths,authored_content:o.authored_content}}function Cl(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 vl(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??Ae,s=e.rescore.cap??pt,n=e.rescore.model??ut,r=new Map(e.scannables.map(b=>[b.id,b])),o=Al(e.proposals,r,t);if(o.length===0)return{proposals:e.proposals,ran:!0,considered:0,promoted:0,demoted:0,unsure:0,failed:0,capped:!1};if(o.length>s)return{proposals:e.proposals,ran:!1,considered:o.length,promoted:0,demoted:0,unsure:0,failed:0,capped:!0};let a=new Map,c=0,d=0,u=0,g=0;for(let b=0;b<o.length&&!e.signal?.aborted;b++){let S=o[b],y=await xl(S,{model:n,signal:e.signal});y?(a.set(Ll(S.step1),y),y.verdict==="same_workflow"?c++:y.verdict==="unrelated"?d++:u++):g++,e.onProgress?.({phase:"rescoring",current:b+1,total:o.length,verdict:y?.verdict??"failed"})}return{proposals:Ol({proposals:e.proposals,rescored:a,applyThreshold:e.applyThreshold}),ran:!0,considered:o.length,promoted:c,demoted:d,unsure:u,failed:g,capped:!1}}async function jl(e){let t=f(),s=new Map(e.rows.map(u=>[u.id,u])),n=Gi(e.edges,e.scannables),r=new Date().toISOString(),o=[],a=new Map,c=0;for(let u of n){if(c++,e.signal?.aborted)break;let g=s.get(u.rootId),h=Cl(g);if(!e.llmNames){a.set(u.rootId,h),e.onProgress?.({phase:"naming",current:c,total:n.length,thread_name:h});continue}let S=await Gh({rootRow:g,sessionIds:u.sessionIds,rowById:s,signal:e.signal,model:e.model})??h;a.set(u.rootId,S),e.onProgress?.({phase:"naming",current:c,total:n.length,thread_name:S})}return t.transaction(()=>{for(let u of n){if(!a.has(u.rootId))continue;let g=s.get(u.rootId),h=`auto-scan-${Xh()}`,b=a.get(u.rootId)??Cl(g),S=`Auto-detected workflow chain (${u.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
1340
+ ORDER BY p.name ASC, s.started_at ASC`).all(s)}function Kh(e,t,s){if(!e.started_at)return null;let n=Date.parse(e.started_at);if(!Number.isFinite(n))return null;let r=e.ended_at?Date.parse(e.ended_at):null,o=ys(e.file_path,{maxUserMessages:7}),a=t?.get(e.id);return{id:e.id,started_at_ms:n,ended_at_ms:Number.isFinite(r)?r:null,first_user_message:e.first_user_message,recent_user_messages:o.recent_user_messages,auto_title:e.auto_title,touched_files:o.touched_files,mean_embedding:a?.full_mean??null,head_pool:a?.head_pool??null,tail_pool:a?.tail_pool??null,sample_chunks:a?.sample_chunks??[],cluster_id:s?.get(e.id)??null,authored_paths:o.authored_paths,authored_content:o.authored_content}}function vl(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 Ml(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??Ae,s=e.rescore.cap??pt,n=e.rescore.model??ut,r=new Map(e.scannables.map(b=>[b.id,b])),o=xl(e.proposals,r,t);if(o.length===0)return{proposals:e.proposals,ran:!0,considered:0,promoted:0,demoted:0,unsure:0,failed:0,capped:!1};if(o.length>s)return{proposals:e.proposals,ran:!1,considered:o.length,promoted:0,demoted:0,unsure:0,failed:0,capped:!0};let a=new Map,c=0,d=0,u=0,g=0;for(let b=0;b<o.length&&!e.signal?.aborted;b++){let S=o[b],y=await Ll(S,{model:n,signal:e.signal});y?(a.set(Il(S.step1),y),y.verdict==="same_workflow"?c++:y.verdict==="unrelated"?d++:u++):g++,e.onProgress?.({phase:"rescoring",current:b+1,total:o.length,verdict:y?.verdict??"failed"})}return{proposals:Cl({proposals:e.proposals,rescored:a,applyThreshold:e.applyThreshold}),ran:!0,considered:o.length,promoted:c,demoted:d,unsure:u,failed:g,capped:!1}}async function Dl(e){let t=f(),s=new Map(e.rows.map(u=>[u.id,u])),n=Ki(e.edges,e.scannables),r=new Date().toISOString(),o=[],a=new Map,c=0;for(let u of n){if(c++,e.signal?.aborted)break;let g=s.get(u.rootId),h=vl(g);if(!e.llmNames){a.set(u.rootId,h),e.onProgress?.({phase:"naming",current:c,total:n.length,thread_name:h});continue}let S=await Gh({rootRow:g,sessionIds:u.sessionIds,rowById:s,signal:e.signal,model:e.model})??h;a.set(u.rootId,S),e.onProgress?.({phase:"naming",current:c,total:n.length,thread_name:S})}return t.transaction(()=>{for(let u of n){if(!a.has(u.rootId))continue;let g=s.get(u.rootId),h=`auto-scan-${Xh()}`,b=a.get(u.rootId)??vl(g),S=`Auto-detected workflow chain (${u.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
1341
1341
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
1342
1342
  VALUES (?, ?, NULL, 'origin', 1.0, 'auto-scan-v1', ?)`).run(h,u.rootId,r);let y=new Map;for(let k of e.edges)u.sessionIds.includes(k.child_id)&&y.set(k.child_id,k);for(let k of u.sessionIds){if(k===u.rootId)continue;let w=y.get(k);w&&t.prepare(`INSERT INTO thread_edges
1343
1343
  (thread_id, session_id, parent_session_id, role, confidence, source, added_at)
1344
- VALUES (?, ?, ?, 'child', ?, 'auto-scan-v1', ?)`).run(h,k,w.parent_id,w.confidence,r)}o.push({thread_id:h,name:b,session_count:u.sessionIds.length})}})(),{project:e.project,threads:o}}var gt=new Map,Yt=new Map,Vh=300*1e3;function mt(e,t,s){e.events.push({id:e.events.length+1,kind:t,data:s});for(let n of e.waiters)n();e.waiters.clear()}function Zh(e){e.cleanupTimer||(e.cleanupTimer=setTimeout(()=>{gt.delete(e.jobId),Yt.get(e.project)===e.jobId&&Yt.delete(e.project)},Vh),e.cleanupTimer.unref?.())}function Xs(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 Qh=500,eE=30,Dr="claude-haiku-4-5-20251001",Ml={"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 Dl(e){return Ml[e]??Ml[Dr]}function Fl(e){let t=typeof e.threshold=="number"?e.threshold:Ss;if(!Number.isFinite(t)||t<0||t>1)return{error:"threshold must be a number in [0, 1]"};let s=e.model??Dr,n="",r=!!e.llm_rescore?.enabled,o={lo:e.llm_rescore?.band_lo??Ae.lo,hi:e.llm_rescore?.band_hi??Ae.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??ut,c=jr({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:Ce(0,s),accuracy_caveat:n,model:s,llm_rescore:r?{enabled:!0,band:o,cap:pt,estimated_borderline_pairs:0,estimated_input_tokens_max:0,estimated_output_tokens_max:0,estimated_cost_usd_max:0,plan_window_estimate:Ce(0,a),exceeds_cap:!1,model:a}:null};let{byProject:d,scannablesByProject:u}=Mr(c),g=d.get(e.project)??[],h=u.get(e.project)??[],b=r?Math.min(t,o.lo):t,S=ze(h,b),y=r?S.filter(p=>p.confidence>=t):S,k=Pl(y),w=k*Qh,D=k*eE,L=Dl(s),X=w/1e6*L.in,M=D/1e6*L.out,B=X+M,se=Ce(k,s),i=Il(e.project),l=null;if(r){let p=Nl(S,o),m=Dl(a),_=p*Rl,E=p*kl,T=_/1e6*m.in+E/1e6*m.out;l={enabled:!0,band:o,cap:pt,estimated_borderline_pairs:p,estimated_input_tokens_max:_,estimated_output_tokens_max:E,estimated_cost_usd_max:Math.round(T*1e4)/1e4,plan_window_estimate:Ce(p,a),exceeds_cap:p>pt,model:a}}return{eligible_sessions:g.length,proposed_edges:y.length,estimated_threads:k,estimated_llm_calls:k,estimated_input_tokens_max:w,estimated_output_tokens_max:D,estimated_cost_usd_max:Math.round(B*1e4)/1e4,existing_auto_scan_threads:i,plan_window_estimate:se,accuracy_caveat:n,model:s,llm_rescore:l}}function Pl(e){let t=new Map,s=o=>{let a=o;for(;t.get(a)!==a;)a=t.get(a);return a},n=(o,a)=>{let c=s(o),d=s(a);c!==d&&t.set(c,d)};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),n(o.parent_id,o.child_id);let r=new Set;for(let o of t.keys())r.add(s(o));return r.size}function Ul(e){let t=typeof e.threshold=="number"?e.threshold:Ss;if(!Number.isFinite(t)||t<0||t>1)return{error:"threshold must be a number in [0, 1]"};let s=e.llm_names??!0,n=e.model??Dr,r=!!e.llm_rescore?.enabled,o={lo:e.llm_rescore?.band_lo??Ae.lo,hi:e.llm_rescore?.band_hi??Ae.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??ut,c=Yt.get(e.project);if(c){let B=gt.get(c);if(B&&B.status==="running")return{jobId:c,reused:!0};Yt.delete(e.project)}let d=jr({project:e.project});if(d.length===0)return{error:`no eligible sessions in project "${e.project}"`};let{byProject:u,scannablesByProject:g}=Mr(d),h=u.get(e.project),b=g.get(e.project);if(!h||!b)return{error:`project "${e.project}" not found`};let S=r?Math.min(t,o.lo):t,y=ze(b,S),k=r?y.filter(B=>B.confidence>=t):y;if(y.length===0||k.length===0&&!r)return{error:"no edges above threshold; nothing to apply"};let w=zh(),D=new AbortController,L=Pl(k),X=new Date().toISOString(),M={jobId:w,project:e.project,threshold:t,llmNames:s,status:"running",startedAt:X,endedAt:null,events:[],waiters:new Set,controller:D,totalThreads:L,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 gt.set(w,M),Yt.set(e.project,w),(async()=>{await Promise.resolve();try{mt(M,"progress",{phase:"linking",edges_proposed:y.length,estimated_threads:L});let B=y;if(r){let i=await vl({proposals:y,scannables:b,applyThreshold:t,rescore:{enabled:!0,band:o,model:a},signal:D.signal,onProgress:l=>{l.phase==="rescoring"&&mt(M,"progress",{phase:"rescoring",current:l.current,total:l.total,verdict:l.verdict})}});B=i.proposals,M.rescore={enabled:!0,considered:i.considered,promoted:i.promoted,demoted:i.demoted,unsure:i.unsure,failed:i.failed,capped:i.capped}}else B=y.filter(i=>i.confidence>=t);if(B.length===0){M.status=D.signal.aborted?"cancelled":"done",M.endedAt=new Date().toISOString(),mt(M,"done",{...Xs(M),threads:[]});return}let se=await jl({project:e.project,rows:h,edges:B,scannables:b,llmNames:s,model:n,signal:D.signal,onProgress:i=>{i.phase==="naming"&&(M.threadsNamed=i.current,M.currentThreadName=i.thread_name??null,mt(M,"progress",{phase:"naming",current:i.current,total:i.total,thread_name:i.thread_name}))}});M.threadsCreated=se.threads.length,M.edgesWritten=B.length+se.threads.length,M.status=D.signal.aborted?"cancelled":"done",M.endedAt=new Date().toISOString(),mt(M,"done",{...Xs(M),threads:se.threads})}catch(B){M.status="failed",M.endedAt=new Date().toISOString(),M.error=B instanceof Error?B.message:String(B??"unknown error"),mt(M,"done",Xs(M))}finally{Zh(M)}})(),{jobId:w,reused:!1}}async function*$l(e,t=0){let s=gt.get(e);if(!s)return;let n=t;for(;;){for(;n<s.events.length;){let r=s.events[n];if(!r)break;if(n+=1,yield r,r.kind==="done")return}if(s.status!=="running")return;await new Promise(r=>s.waiters.add(r))}}function Bl(e){let t=gt.get(e);return!t||t.status!=="running"?!1:(t.controller.abort(),!0)}function Fr(e){let t=gt.get(e);return t?Xs(t):null}rs();import{randomUUID as tE}from"node:crypto";var Gs=new Map;function Hl(e){let t={id:tE(),status:"pending",createdAt:new Date().toISOString(),finishedAt:null,total:e,completed:0,results:[],error:null,controller:new AbortController,listeners:new Set};return Gs.set(t.id,t),t}function Ys(e){return Gs.get(e)}function _t(e,t){for(let s of e.listeners)s(t)}function Wl(e,t){return e.listeners.add(t),()=>{e.listeners.delete(t)}}function ql(e){let t=Gs.get(e);return t?(t.controller.abort(),t.status="cancelled",t.finishedAt=new Date().toISOString(),_t(t,{type:"status",status:"cancelled"}),!0):!1}function Jl(e){return Gs.delete(e)}Ge();function Ks(e){let{session:t,knownTags:s,minTags:n,maxTags:r}=e,o=s.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 ${n}-${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:",Xl(t.first_user_message," ")," message_sample:",Xl(t.message_sample," "),"","Return a single JSON object matching this schema exactly, with no prose before or after:",`{"tags": string[] length ${n}-${r}, "confidence": number 0-1, "rationale": string one short sentence}`].filter(Boolean).join(`
1345
- `)}function Xl(e,t){return e.split(`
1344
+ VALUES (?, ?, ?, 'child', ?, 'auto-scan-v1', ?)`).run(h,k,w.parent_id,w.confidence,r)}o.push({thread_id:h,name:b,session_count:u.sessionIds.length})}})(),{project:e.project,threads:o}}var gt=new Map,Yt=new Map,Vh=300*1e3;function mt(e,t,s){e.events.push({id:e.events.length+1,kind:t,data:s});for(let n of e.waiters)n();e.waiters.clear()}function Zh(e){e.cleanupTimer||(e.cleanupTimer=setTimeout(()=>{gt.delete(e.jobId),Yt.get(e.project)===e.jobId&&Yt.delete(e.project)},Vh),e.cleanupTimer.unref?.())}function Xs(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 Qh=500,eE=30,Pr="claude-haiku-4-5-20251001",Fl={"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 Pl(e){return Fl[e]??Fl[Pr]}function Ul(e){let t=typeof e.threshold=="number"?e.threshold:Ss;if(!Number.isFinite(t)||t<0||t>1)return{error:"threshold must be a number in [0, 1]"};let s=e.model??Pr,n="",r=!!e.llm_rescore?.enabled,o={lo:e.llm_rescore?.band_lo??Ae.lo,hi:e.llm_rescore?.band_hi??Ae.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??ut,c=Dr({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:Ce(0,s),accuracy_caveat:n,model:s,llm_rescore:r?{enabled:!0,band:o,cap:pt,estimated_borderline_pairs:0,estimated_input_tokens_max:0,estimated_output_tokens_max:0,estimated_cost_usd_max:0,plan_window_estimate:Ce(0,a),exceeds_cap:!1,model:a}:null};let{byProject:d,scannablesByProject:u}=Fr(c),g=d.get(e.project)??[],h=u.get(e.project)??[],b=r?Math.min(t,o.lo):t,S=ze(h,b),y=r?S.filter(p=>p.confidence>=t):S,k=$l(y),w=k*Qh,D=k*eE,L=Pl(s),X=w/1e6*L.in,M=D/1e6*L.out,B=X+M,se=Ce(k,s),i=jl(e.project),l=null;if(r){let p=Ol(S,o),m=Pl(a),_=p*Al,E=p*Nl,T=_/1e6*m.in+E/1e6*m.out;l={enabled:!0,band:o,cap:pt,estimated_borderline_pairs:p,estimated_input_tokens_max:_,estimated_output_tokens_max:E,estimated_cost_usd_max:Math.round(T*1e4)/1e4,plan_window_estimate:Ce(p,a),exceeds_cap:p>pt,model:a}}return{eligible_sessions:g.length,proposed_edges:y.length,estimated_threads:k,estimated_llm_calls:k,estimated_input_tokens_max:w,estimated_output_tokens_max:D,estimated_cost_usd_max:Math.round(B*1e4)/1e4,existing_auto_scan_threads:i,plan_window_estimate:se,accuracy_caveat:n,model:s,llm_rescore:l}}function $l(e){let t=new Map,s=o=>{let a=o;for(;t.get(a)!==a;)a=t.get(a);return a},n=(o,a)=>{let c=s(o),d=s(a);c!==d&&t.set(c,d)};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),n(o.parent_id,o.child_id);let r=new Set;for(let o of t.keys())r.add(s(o));return r.size}function Bl(e){let t=typeof e.threshold=="number"?e.threshold:Ss;if(!Number.isFinite(t)||t<0||t>1)return{error:"threshold must be a number in [0, 1]"};let s=e.llm_names??!0,n=e.model??Pr,r=!!e.llm_rescore?.enabled,o={lo:e.llm_rescore?.band_lo??Ae.lo,hi:e.llm_rescore?.band_hi??Ae.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??ut,c=Yt.get(e.project);if(c){let B=gt.get(c);if(B&&B.status==="running")return{jobId:c,reused:!0};Yt.delete(e.project)}let d=Dr({project:e.project});if(d.length===0)return{error:`no eligible sessions in project "${e.project}"`};let{byProject:u,scannablesByProject:g}=Fr(d),h=u.get(e.project),b=g.get(e.project);if(!h||!b)return{error:`project "${e.project}" not found`};let S=r?Math.min(t,o.lo):t,y=ze(b,S),k=r?y.filter(B=>B.confidence>=t):y;if(y.length===0||k.length===0&&!r)return{error:"no edges above threshold; nothing to apply"};let w=zh(),D=new AbortController,L=$l(k),X=new Date().toISOString(),M={jobId:w,project:e.project,threshold:t,llmNames:s,status:"running",startedAt:X,endedAt:null,events:[],waiters:new Set,controller:D,totalThreads:L,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 gt.set(w,M),Yt.set(e.project,w),(async()=>{await Promise.resolve();try{mt(M,"progress",{phase:"linking",edges_proposed:y.length,estimated_threads:L});let B=y;if(r){let i=await Ml({proposals:y,scannables:b,applyThreshold:t,rescore:{enabled:!0,band:o,model:a},signal:D.signal,onProgress:l=>{l.phase==="rescoring"&&mt(M,"progress",{phase:"rescoring",current:l.current,total:l.total,verdict:l.verdict})}});B=i.proposals,M.rescore={enabled:!0,considered:i.considered,promoted:i.promoted,demoted:i.demoted,unsure:i.unsure,failed:i.failed,capped:i.capped}}else B=y.filter(i=>i.confidence>=t);if(B.length===0){M.status=D.signal.aborted?"cancelled":"done",M.endedAt=new Date().toISOString(),mt(M,"done",{...Xs(M),threads:[]});return}let se=await Dl({project:e.project,rows:h,edges:B,scannables:b,llmNames:s,model:n,signal:D.signal,onProgress:i=>{i.phase==="naming"&&(M.threadsNamed=i.current,M.currentThreadName=i.thread_name??null,mt(M,"progress",{phase:"naming",current:i.current,total:i.total,thread_name:i.thread_name}))}});M.threadsCreated=se.threads.length,M.edgesWritten=B.length+se.threads.length,M.status=D.signal.aborted?"cancelled":"done",M.endedAt=new Date().toISOString(),mt(M,"done",{...Xs(M),threads:se.threads})}catch(B){M.status="failed",M.endedAt=new Date().toISOString(),M.error=B instanceof Error?B.message:String(B??"unknown error"),mt(M,"done",Xs(M))}finally{Zh(M)}})(),{jobId:w,reused:!1}}async function*Hl(e,t=0){let s=gt.get(e);if(!s)return;let n=t;for(;;){for(;n<s.events.length;){let r=s.events[n];if(!r)break;if(n+=1,yield r,r.kind==="done")return}if(s.status!=="running")return;await new Promise(r=>s.waiters.add(r))}}function Wl(e){let t=gt.get(e);return!t||t.status!=="running"?!1:(t.controller.abort(),!0)}function Ur(e){let t=gt.get(e);return t?Xs(t):null}rs();import{randomUUID as tE}from"node:crypto";var Gs=new Map;function ql(e){let t={id:tE(),status:"pending",createdAt:new Date().toISOString(),finishedAt:null,total:e,completed:0,results:[],error:null,controller:new AbortController,listeners:new Set};return Gs.set(t.id,t),t}function Ys(e){return Gs.get(e)}function _t(e,t){for(let s of e.listeners)s(t)}function Jl(e,t){return e.listeners.add(t),()=>{e.listeners.delete(t)}}function Xl(e){let t=Gs.get(e);return t?(t.controller.abort(),t.status="cancelled",t.finishedAt=new Date().toISOString(),_t(t,{type:"status",status:"cancelled"}),!0):!1}function Gl(e){return Gs.delete(e)}Ge();function Ks(e){let{session:t,knownTags:s,minTags:n,maxTags:r}=e,o=s.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 ${n}-${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:",Yl(t.first_user_message," ")," message_sample:",Yl(t.message_sample," "),"","Return a single JSON object matching this schema exactly, with no prose before or after:",`{"tags": string[] length ${n}-${r}, "confidence": number 0-1, "rationale": string one short sentence}`].filter(Boolean).join(`
1345
+ `)}function Yl(e,t){return e.split(`
1346
1346
  `).map(s=>t+s).join(`
1347
- `)}Ge();import{z as Kt}from"zod";var sE=Kt.object({tags:Kt.array(Kt.string()).min(1),confidence:Kt.number().min(0).max(1),rationale:Kt.string().min(1).max(500)});function nE(e){let t=e.trim();return t.startsWith("```")?t.replace(/^```(?:json)?\s*/i,"").replace(/```$/i,"").trim():t}function zs(e,t={}){let s=t.maxTags??10,n;try{n=JSON.parse(nE(e))}catch{return{ok:!1,reason:"not valid JSON"}}let r=sE.safeParse(n);if(!r.success)return{ok:!1,reason:r.error.issues.map(c=>c.message).join("; ")};let o=r.data.tags.map(c=>De(c)).filter(c=>c.length>0),a=Array.from(new Set(o)).slice(0,s);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 rE from"@anthropic-ai/sdk";async function Vs(e){let n=(await new rE({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(!n||n.type!=="text")throw new Error("Anthropic response contained no text block");return n.text}function oE(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 Zs(e,t={}){let s=t.maxAttempts??3,n=t.baseDelayMs??500,r;for(let o=0;o<s;o++)try{return await e()}catch(a){if(r=a,!oE(a)||o===s-1)throw a;await new Promise(c=>setTimeout(c,n*Math.pow(2,o)))}throw r}async function Gl(e,t){e.status="running",_t(e,{type:"status",status:"running"});let s=Xe();for(let n of t.sessions){if(e.controller.signal.aborted)break;let r=Ks({session:n,knownTags:s,minTags:t.minTags,maxTags:t.maxTags}),o={sessionId:n.id,project:n.project,alias:n.alias,first_user_message:n.first_user_message,current_tags:n.current_tags,suggestion:null,error:null,applied:!1};try{let a=await Zs(()=>Vs({apiKey:t.apiKey,model:t.model,prompt:r,signal:e.controller.signal})),c=zs(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,_t(e,{type:"result",result:o}),_t(e,{type:"progress",completed:e.completed,total:e.total})}if(!e.controller.signal.aborted){e.status="completed",e.finishedAt=new Date().toISOString();let n=e.results.filter(o=>o.suggestion&&!o.error).length,r=e.results.filter(o=>o.error).length;_t(e,{type:"done",summary:{ok:n,failed:r}})}}function Yl(e,t){let s=0,n=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}=Je(r.sessionId,a);c&&(s+=1)}catch(c){console.error("[scanner] apply failed:",r.sessionId,a,c),n+=1}o.applied=!0}}return{applied:s,failed:n}}Ge();rs();var Y={running:!1,status:"idle",processed:0,total:0,currentSessionId:null,lastError:null,lastRunAt:null,controller:null},Pr=new Set;function Vt(){return{status:Y.status,processed:Y.processed,total:Y.total,currentSessionId:Y.currentSessionId,lastError:Y.lastError,lastRunAt:Y.lastRunAt}}function Kl(e){return Pr.add(e),()=>{Pr.delete(e)}}function zt(){let e=Vt();for(let t of Pr)t(e)}async function Qs(){let e=Re();if(!(!e.enabled||!e.autopilot)&&!(e.backend!=="api"||!e.apiKey)&&!Y.running){Y.running=!0,Y.status="scanning",Y.processed=0,Y.total=0,Y.currentSessionId=null,Y.lastError=null,Y.controller=new AbortController,zt();try{let t=Ye({untaggedOnly:!0,limit:200});if(Y.total=t.length,zt(),t.length===0){Y.status="idle",Y.lastRunAt=new Date().toISOString();return}let s=Xe();for(let n of t){if(Y.controller.signal.aborted)break;let r=Re();if(!r.autopilot||!r.enabled||r.backend!=="api"||!r.apiKey)break;Y.currentSessionId=n.id,zt();let o=Ks({session:n,knownTags:s,minTags:r.minTagsPerSession,maxTags:r.maxTagsPerSession});try{let a=await Zs(()=>Vs({apiKey:r.apiKey,model:r.model,prompt:o,signal:Y.controller.signal})),c=zs(a,{maxTags:r.maxTagsPerSession});if(c.ok)for(let d of c.data.tags)try{Je(n.id,d)}catch(u){console.error("[autopilot] addTag failed:",n.id,d,u)}}catch(a){console.error("[autopilot] scan failed for",n.id,a)}Y.processed+=1,zt(),await new Promise(a=>setTimeout(a,1500))}Y.status="idle",Y.lastRunAt=new Date().toISOString()}catch(t){Y.status="error",Y.lastError=t instanceof Error?t.message:String(t),console.error("[autopilot] fatal:",t)}finally{Y.running=!1,Y.currentSessionId=null,Y.controller=null,zt()}}}import{execFileSync as iE}from"node:child_process";import{existsSync as zl,readFileSync as aE,writeFileSync as Vl}from"node:fs";import{homedir as cE}from"node:os";import{dirname as lE,join as dE,resolve as uE}from"node:path";import{fileURLToPath as pE}from"node:url";var ft=dE(cE(),".claude.json"),mE=lE(pE(import.meta.url)),gE=uE(mE,"..","mcp","server.js");function $r(){if(!zl(ft))return{};try{let e=aE(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 Ur=new Map;function _E(e){let t=Ur.get(e);if(t!==void 0)return t;try{return iE("command",["-v",e],{stdio:"ignore"}),Ur.set(e,!0),!0}catch{return Ur.set(e,!1),!1}}function fE(){return _E("claude-recall-mcp")?{command:"claude-recall-mcp",args:[]}:{command:process.execPath,args:[gE]}}function Ie(){let t=$r().mcpServers?.recall;return{configPath:ft,configExists:zl(ft),installed:!!(t&&typeof t.command=="string"),command:t?.command??null,args:t?.args??null}}function Zl(){let e=$r(),t=e.mcpServers??{},s=fE(),n=t.recall;if(n?.command===s.command&&JSON.stringify(n?.args??[])===JSON.stringify(s.args))return Ie();let o={command:s.command};s.args.length>0&&(o.args=s.args);let a={...e,mcpServers:{...t,recall:o}};return Vl(ft,JSON.stringify(a,null,2)),Ie()}function Ql(){let e=$r(),t=e.mcpServers??{};if(!t.recall)return Ie();let{recall:s,...n}=t,r={...e,mcpServers:n};return Vl(ft,JSON.stringify(r,null,2)),Ie()}import{existsSync as ed,mkdirSync as hE,readFileSync as EE,writeFileSync as td}from"node:fs";import{homedir as bE}from"node:os";import{join as sd}from"node:path";import{z as ve}from"zod";function nd(){return process.env.RECALL_HOME??sd(bE(),".recall")}function rd(){let e=nd();ed(e)||hE(e,{recursive:!0})}function Hr(){return sd(nd(),"onboarding.json")}var en=ve.object({version:ve.literal(1).default(1),completed:ve.boolean().default(!1),skipped:ve.boolean().default(!1),finishedAt:ve.string().nullable().default(null),completedSteps:ve.array(ve.string().max(100)).max(50).default([]),threadsIntroSeen:ve.boolean().default(!1)}),Br={version:1,completed:!1,skipped:!1,finishedAt:null,completedSteps:[],threadsIntroSeen:!1};function tn(){let e=Hr();if(!ed(e))return{...Br};try{let t=JSON.parse(EE(e,"utf8")),s=en.safeParse(t);return s.success?s.data:{...Br}}catch(t){return console.error("[onboarding-state] failed to parse onboarding.json, using defaults:",t),{...Br}}}function od(e){rd();let t=tn(),s=en.parse({...t,...e,completedSteps:SE([...t.completedSteps??[],...e.completedSteps??[]]),version:1});return td(Hr(),JSON.stringify(s,null,2)),s}function id(){rd();let e=tn(),t={version:1,completed:!1,skipped:!1,finishedAt:null,completedSteps:e.completedSteps,threadsIntroSeen:e.threadsIntroSeen};return td(Hr(),JSON.stringify(t,null,2)),t}function SE(e){let t=new Set,s=[];for(let n of e)t.has(n)||(t.add(n),s.push(n));return s}ge();xn();Nn();import{existsSync as ad,mkdirSync as TE,readFileSync as yE,writeFileSync as wE}from"node:fs";import{homedir as RE}from"node:os";import{join as cd}from"node:path";import{z as Ne}from"zod";function ld(){return process.env.RECALL_HOME??cd(RE(),".recall")}function kE(){let e=ld();ad(e)||TE(e,{recursive:!0})}function dd(){return cd(ld(),"config.json")}var nn=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)}),sn={enabled:!1,ratePerMinute:30,lastProcessedSessionId:null,backfillPaused:!1,autoExtractEnabled:!1,autoExtractIntervalMinutes:60,autoExtractBatchSize:1};function ud(){let e=dd();if(!ad(e))return{};try{return JSON.parse(yE(e,"utf8"))}catch(t){return console.error("[semantic-config] failed to parse config.json, using defaults:",t),{}}}function ce(){let e=ud().semantic;if(!e)return{...sn};let t=nn.safeParse({...sn,...e});return t.success?t.data:{...sn}}function rn(e){kE();let t=ud(),s=nn.parse({...sn,...t.semantic??{},...e}),n={...t,semantic:s};return wE(dd(),JSON.stringify(n,null,2)),s}H();ge();import{existsSync as AE,mkdirSync as NE,writeFileSync as xE}from"node:fs";import{homedir as OE}from"node:os";import{join as Wr}from"node:path";var LE=1,CE=12e3,pd=3,IE=[];function vE(){return process.env.RECALL_HOME??Wr(OE(),".recall")}function md(){return Wr(vE(),"semantic")}function jE(){let e=md();AE(e)||NE(e,{recursive:!0})}function ME(e){let t=f(),s=t.prepare(`SELECT s.id, s.message_count, s.first_user_message,
1347
+ `)}Ge();import{z as Kt}from"zod";var sE=Kt.object({tags:Kt.array(Kt.string()).min(1),confidence:Kt.number().min(0).max(1),rationale:Kt.string().min(1).max(500)});function nE(e){let t=e.trim();return t.startsWith("```")?t.replace(/^```(?:json)?\s*/i,"").replace(/```$/i,"").trim():t}function zs(e,t={}){let s=t.maxTags??10,n;try{n=JSON.parse(nE(e))}catch{return{ok:!1,reason:"not valid JSON"}}let r=sE.safeParse(n);if(!r.success)return{ok:!1,reason:r.error.issues.map(c=>c.message).join("; ")};let o=r.data.tags.map(c=>De(c)).filter(c=>c.length>0),a=Array.from(new Set(o)).slice(0,s);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 rE from"@anthropic-ai/sdk";async function Vs(e){let n=(await new rE({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(!n||n.type!=="text")throw new Error("Anthropic response contained no text block");return n.text}function oE(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 Zs(e,t={}){let s=t.maxAttempts??3,n=t.baseDelayMs??500,r;for(let o=0;o<s;o++)try{return await e()}catch(a){if(r=a,!oE(a)||o===s-1)throw a;await new Promise(c=>setTimeout(c,n*Math.pow(2,o)))}throw r}async function Kl(e,t){e.status="running",_t(e,{type:"status",status:"running"});let s=Xe();for(let n of t.sessions){if(e.controller.signal.aborted)break;let r=Ks({session:n,knownTags:s,minTags:t.minTags,maxTags:t.maxTags}),o={sessionId:n.id,project:n.project,alias:n.alias,first_user_message:n.first_user_message,current_tags:n.current_tags,suggestion:null,error:null,applied:!1};try{let a=await Zs(()=>Vs({apiKey:t.apiKey,model:t.model,prompt:r,signal:e.controller.signal})),c=zs(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,_t(e,{type:"result",result:o}),_t(e,{type:"progress",completed:e.completed,total:e.total})}if(!e.controller.signal.aborted){e.status="completed",e.finishedAt=new Date().toISOString();let n=e.results.filter(o=>o.suggestion&&!o.error).length,r=e.results.filter(o=>o.error).length;_t(e,{type:"done",summary:{ok:n,failed:r}})}}function zl(e,t){let s=0,n=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}=Je(r.sessionId,a);c&&(s+=1)}catch(c){console.error("[scanner] apply failed:",r.sessionId,a,c),n+=1}o.applied=!0}}return{applied:s,failed:n}}Ge();rs();var Y={running:!1,status:"idle",processed:0,total:0,currentSessionId:null,lastError:null,lastRunAt:null,controller:null},$r=new Set;function Vt(){return{status:Y.status,processed:Y.processed,total:Y.total,currentSessionId:Y.currentSessionId,lastError:Y.lastError,lastRunAt:Y.lastRunAt}}function Vl(e){return $r.add(e),()=>{$r.delete(e)}}function zt(){let e=Vt();for(let t of $r)t(e)}async function Qs(){let e=Re();if(!(!e.enabled||!e.autopilot)&&!(e.backend!=="api"||!e.apiKey)&&!Y.running){Y.running=!0,Y.status="scanning",Y.processed=0,Y.total=0,Y.currentSessionId=null,Y.lastError=null,Y.controller=new AbortController,zt();try{let t=Ye({untaggedOnly:!0,limit:200});if(Y.total=t.length,zt(),t.length===0){Y.status="idle",Y.lastRunAt=new Date().toISOString();return}let s=Xe();for(let n of t){if(Y.controller.signal.aborted)break;let r=Re();if(!r.autopilot||!r.enabled||r.backend!=="api"||!r.apiKey)break;Y.currentSessionId=n.id,zt();let o=Ks({session:n,knownTags:s,minTags:r.minTagsPerSession,maxTags:r.maxTagsPerSession});try{let a=await Zs(()=>Vs({apiKey:r.apiKey,model:r.model,prompt:o,signal:Y.controller.signal})),c=zs(a,{maxTags:r.maxTagsPerSession});if(c.ok)for(let d of c.data.tags)try{Je(n.id,d)}catch(u){console.error("[autopilot] addTag failed:",n.id,d,u)}}catch(a){console.error("[autopilot] scan failed for",n.id,a)}Y.processed+=1,zt(),await new Promise(a=>setTimeout(a,1500))}Y.status="idle",Y.lastRunAt=new Date().toISOString()}catch(t){Y.status="error",Y.lastError=t instanceof Error?t.message:String(t),console.error("[autopilot] fatal:",t)}finally{Y.running=!1,Y.currentSessionId=null,Y.controller=null,zt()}}}import{execFileSync as iE}from"node:child_process";import{existsSync as Zl,readFileSync as aE,writeFileSync as Ql}from"node:fs";import{homedir as cE}from"node:os";import{dirname as lE,join as dE,resolve as uE}from"node:path";import{fileURLToPath as pE}from"node:url";var ft=dE(cE(),".claude.json"),mE=lE(pE(import.meta.url)),gE=uE(mE,"..","mcp","server.js");function Hr(){if(!Zl(ft))return{};try{let e=aE(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 Br=new Map;function _E(e){let t=Br.get(e);if(t!==void 0)return t;try{return iE("command",["-v",e],{stdio:"ignore"}),Br.set(e,!0),!0}catch{return Br.set(e,!1),!1}}function fE(){return _E("claude-recall-mcp")?{command:"claude-recall-mcp",args:[]}:{command:process.execPath,args:[gE]}}function Ie(){let t=Hr().mcpServers?.recall;return{configPath:ft,configExists:Zl(ft),installed:!!(t&&typeof t.command=="string"),command:t?.command??null,args:t?.args??null}}function ed(){let e=Hr(),t=e.mcpServers??{},s=fE(),n=t.recall;if(n?.command===s.command&&JSON.stringify(n?.args??[])===JSON.stringify(s.args))return Ie();let o={command:s.command};s.args.length>0&&(o.args=s.args);let a={...e,mcpServers:{...t,recall:o}};return Ql(ft,JSON.stringify(a,null,2)),Ie()}function td(){let e=Hr(),t=e.mcpServers??{};if(!t.recall)return Ie();let{recall:s,...n}=t,r={...e,mcpServers:n};return Ql(ft,JSON.stringify(r,null,2)),Ie()}import{existsSync as sd,mkdirSync as hE,readFileSync as EE,writeFileSync as nd}from"node:fs";import{homedir as bE}from"node:os";import{join as rd}from"node:path";import{z as ve}from"zod";function od(){return process.env.RECALL_HOME??rd(bE(),".recall")}function id(){let e=od();sd(e)||hE(e,{recursive:!0})}function qr(){return rd(od(),"onboarding.json")}var en=ve.object({version:ve.literal(1).default(1),completed:ve.boolean().default(!1),skipped:ve.boolean().default(!1),finishedAt:ve.string().nullable().default(null),completedSteps:ve.array(ve.string().max(100)).max(50).default([]),threadsIntroSeen:ve.boolean().default(!1)}),Wr={version:1,completed:!1,skipped:!1,finishedAt:null,completedSteps:[],threadsIntroSeen:!1};function tn(){let e=qr();if(!sd(e))return{...Wr};try{let t=JSON.parse(EE(e,"utf8")),s=en.safeParse(t);return s.success?s.data:{...Wr}}catch(t){return console.error("[onboarding-state] failed to parse onboarding.json, using defaults:",t),{...Wr}}}function ad(e){id();let t=tn(),s=en.parse({...t,...e,completedSteps:SE([...t.completedSteps??[],...e.completedSteps??[]]),version:1});return nd(qr(),JSON.stringify(s,null,2)),s}function cd(){id();let e=tn(),t={version:1,completed:!1,skipped:!1,finishedAt:null,completedSteps:e.completedSteps,threadsIntroSeen:e.threadsIntroSeen};return nd(qr(),JSON.stringify(t,null,2)),t}function SE(e){let t=new Set,s=[];for(let n of e)t.has(n)||(t.add(n),s.push(n));return s}ge();Ln();On();import{existsSync as ld,mkdirSync as TE,readFileSync as yE,writeFileSync as wE}from"node:fs";import{homedir as RE}from"node:os";import{join as dd}from"node:path";import{z as Ne}from"zod";function ud(){return process.env.RECALL_HOME??dd(RE(),".recall")}function kE(){let e=ud();ld(e)||TE(e,{recursive:!0})}function pd(){return dd(ud(),"config.json")}var nn=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)}),sn={enabled:!1,ratePerMinute:30,lastProcessedSessionId:null,backfillPaused:!1,autoExtractEnabled:!1,autoExtractIntervalMinutes:60,autoExtractBatchSize:1};function md(){let e=pd();if(!ld(e))return{};try{return JSON.parse(yE(e,"utf8"))}catch(t){return console.error("[semantic-config] failed to parse config.json, using defaults:",t),{}}}function ce(){let e=md().semantic;if(!e)return{...sn};let t=nn.safeParse({...sn,...e});return t.success?t.data:{...sn}}function rn(e){kE();let t=md(),s=nn.parse({...sn,...t.semantic??{},...e}),n={...t,semantic:s};return wE(pd(),JSON.stringify(n,null,2)),s}H();ge();import{existsSync as AE,mkdirSync as NE,writeFileSync as xE}from"node:fs";import{homedir as OE}from"node:os";import{join as Jr}from"node:path";var LE=1,CE=12e3,gd=3,IE=[];function vE(){return process.env.RECALL_HOME??Jr(OE(),".recall")}function _d(){return Jr(vE(),"semantic")}function jE(){let e=_d();AE(e)||NE(e,{recursive:!0})}function ME(e){let t=f(),s=t.prepare(`SELECT s.id, s.message_count, s.first_user_message,
1348
1348
  p.name AS project,
1349
1349
  NULLIF(sa.alias, '') AS alias
1350
1350
  FROM sessions s
@@ -1364,29 +1364,29 @@ Return ONLY the workflow name on a single line.`;try{let o=t(r,[],e.model?{model
1364
1364
  keywords = excluded.keywords,
1365
1365
  model = excluded.model,
1366
1366
  source_message_count = excluded.source_message_count,
1367
- generated_at = excluded.generated_at`).run({session_id:e.sessionId,summary:e.summary,keywords:s,model:e.model,source_message_count:e.sourceMessageCount,generated_at:e.generatedAt}),jE();let n=Wr(md(),`${e.sessionId}.json`);xE(n,JSON.stringify({version:LE,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 on=null;function UE(){let t=ce().ratePerMinute,s=t/6e4;return(!on||on.capacity!==t)&&(on={tokens:t,capacity:t,refillPerMs:s,lastRefill:Date.now()}),on}function $E(e){let t=Date.now(),s=t-e.lastRefill;s>0&&(e.tokens=Math.min(e.capacity,e.tokens+s*e.refillPerMs),e.lastRefill=t)}async function BE(e){for(;;){if(e?.aborted)throw new Error("aborted");let t=UE();if($E(t),t.tokens>=1){t.tokens-=1;return}let s=1-t.tokens,n=Math.max(50,Math.ceil(s/t.refillPerMs));await new Promise(r=>setTimeout(r,Math.min(n,5e3)))}}async function an(e,t={}){let s=ce();if(!s.enabled)return{sessionId:e,ok:!1,reason:"disabled"};if(!oe())return{sessionId:e,ok:!1,reason:"claude-cli-missing"};let n=ME(e);if(!n)return{sessionId:e,ok:!1,reason:"session-not-found"};if(n.messageCount<pd)return{sessionId:e,ok:!1,reason:"too-short"};if(!n.excerpt.trim())return{sessionId:e,ok:!1,reason:"empty-excerpt"};await BE(t.signal);let r=DE(n),o=await Fe(r,IE,{model:s.model});if(!o.success)return{sessionId:e,ok:!1,reason:`claude-cli-exit-${o.exitCode??"null"}`,model:s.model??null};let a=FE(o.stdout);return a?(PE({sessionId:n.id,summary:a.summary,keywords:a.keywords,model:s.model??null,sourceMessageCount:n.messageCount,generatedAt:new Date().toISOString()}),{sessionId:e,ok:!0,model:s.model??null}):{sessionId:e,ok:!1,reason:"parse-failed",model:s.model??null}}async function cn(e={}){let t=ce();if(!t.enabled)return{total:0,processed:0,ok:0,failed:0,currentSessionId:null};let s=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=s.prepare(`SELECT s.id
1367
+ generated_at = excluded.generated_at`).run({session_id:e.sessionId,summary:e.summary,keywords:s,model:e.model,source_message_count:e.sourceMessageCount,generated_at:e.generatedAt}),jE();let n=Jr(_d(),`${e.sessionId}.json`);xE(n,JSON.stringify({version:LE,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 on=null;function UE(){let t=ce().ratePerMinute,s=t/6e4;return(!on||on.capacity!==t)&&(on={tokens:t,capacity:t,refillPerMs:s,lastRefill:Date.now()}),on}function $E(e){let t=Date.now(),s=t-e.lastRefill;s>0&&(e.tokens=Math.min(e.capacity,e.tokens+s*e.refillPerMs),e.lastRefill=t)}async function BE(e){for(;;){if(e?.aborted)throw new Error("aborted");let t=UE();if($E(t),t.tokens>=1){t.tokens-=1;return}let s=1-t.tokens,n=Math.max(50,Math.ceil(s/t.refillPerMs));await new Promise(r=>setTimeout(r,Math.min(n,5e3)))}}async function an(e,t={}){let s=ce();if(!s.enabled)return{sessionId:e,ok:!1,reason:"disabled"};if(!oe())return{sessionId:e,ok:!1,reason:"claude-cli-missing"};let n=ME(e);if(!n)return{sessionId:e,ok:!1,reason:"session-not-found"};if(n.messageCount<gd)return{sessionId:e,ok:!1,reason:"too-short"};if(!n.excerpt.trim())return{sessionId:e,ok:!1,reason:"empty-excerpt"};await BE(t.signal);let r=DE(n),o=await Fe(r,IE,{model:s.model});if(!o.success)return{sessionId:e,ok:!1,reason:`claude-cli-exit-${o.exitCode??"null"}`,model:s.model??null};let a=FE(o.stdout);return a?(PE({sessionId:n.id,summary:a.summary,keywords:a.keywords,model:s.model??null,sourceMessageCount:n.messageCount,generatedAt:new Date().toISOString()}),{sessionId:e,ok:!0,model:s.model??null}):{sessionId:e,ok:!1,reason:"parse-failed",model:s.model??null}}async function cn(e={}){let t=ce();if(!t.enabled)return{total:0,processed:0,ok:0,failed:0,currentSessionId:null};let s=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=s.prepare(`SELECT s.id
1368
1368
  FROM sessions s
1369
1369
  LEFT JOIN session_semantic ss ON ss.session_id = s.id
1370
1370
  WHERE ${o}
1371
1371
  ORDER BY COALESCE(s.started_at, '') ASC, s.id ASC
1372
- LIMIT @limit`).all(r),c={total:a.length,processed:0,ok:0,failed:0,currentSessionId:null};e.onProgress?.(c);for(let{id:d}of a){if(e.signal?.aborted||ce().backfillPaused)break;c.currentSessionId=d,e.onProgress?.({...c});try{(await an(d,{signal:e.signal})).ok?c.ok+=1:c.failed+=1}catch(g){c.failed+=1,console.error("[semantic.backfill] failed for",d,g)}c.processed+=1,rn({lastProcessedSessionId:d}),e.onProgress?.({...c})}return c.currentSessionId=null,e.onProgress?.({...c}),c}async function gd(e){if(!ce().enabled)return;let n=f().prepare(`SELECT s.message_count, s.ended_at,
1372
+ LIMIT @limit`).all(r),c={total:a.length,processed:0,ok:0,failed:0,currentSessionId:null};e.onProgress?.(c);for(let{id:d}of a){if(e.signal?.aborted||ce().backfillPaused)break;c.currentSessionId=d,e.onProgress?.({...c});try{(await an(d,{signal:e.signal})).ok?c.ok+=1:c.failed+=1}catch(g){c.failed+=1,console.error("[semantic.backfill] failed for",d,g)}c.processed+=1,rn({lastProcessedSessionId:d}),e.onProgress?.({...c})}return c.currentSessionId=null,e.onProgress?.({...c}),c}async function fd(e){if(!ce().enabled)return;let n=f().prepare(`SELECT s.message_count, s.ended_at,
1373
1373
  ss.generated_at, ss.source_message_count
1374
1374
  FROM sessions s
1375
1375
  LEFT JOIN session_semantic ss ON ss.session_id = s.id
1376
- WHERE s.id = ?`).get(e);if(n&&!(n.message_count<pd)&&!(n.generated_at&&n.source_message_count!=null&&n.source_message_count>=n.message_count))try{await an(e)}catch(r){console.error("[semantic] processSession error for",e,r)}}function qr(){let e=ce(),t=f(),s=t.prepare("SELECT COUNT(*) AS n FROM sessions WHERE message_count >= 3").get().n,n=t.prepare("SELECT COUNT(*) AS n FROM session_semantic").get().n;return{enabled:e.enabled,claudeCliAvailable:oe(),ratePerMinute:e.ratePerMinute,model:e.model??null,totalSessions:s,processedSessions:n,pendingSessions:Math.max(0,s-n),lastProcessedSessionId:e.lastProcessedSessionId,backfillPaused:e.backfillPaused}}H();H();import{createReadStream as HE}from"node:fs";import{createInterface as WE}from"node:readline";function ln(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 s={inputTokens:ln(t.input_tokens),outputTokens:ln(t.output_tokens),cacheCreateTokens:ln(t.cache_creation_input_tokens),cacheReadTokens:ln(t.cache_read_input_tokens)};return s.inputTokens===0&&s.outputTokens===0&&s.cacheCreateTokens===0&&s.cacheReadTokens===0?null:s}var qE=/\x1B\[[0-9;]*[a-zA-Z]/g;function Jr(e){return e.replace(qE,"")}var Xr=12e3;function _d(e,t){if(e.length<=Xr)return e;let s=e.slice(0,Xr),n=e.length-Xr;return`${s}
1376
+ WHERE s.id = ?`).get(e);if(n&&!(n.message_count<gd)&&!(n.generated_at&&n.source_message_count!=null&&n.source_message_count>=n.message_count))try{await an(e)}catch(r){console.error("[semantic] processSession error for",e,r)}}function Xr(){let e=ce(),t=f(),s=t.prepare("SELECT COUNT(*) AS n FROM sessions WHERE message_count >= 3").get().n,n=t.prepare("SELECT COUNT(*) AS n FROM session_semantic").get().n;return{enabled:e.enabled,claudeCliAvailable:oe(),ratePerMinute:e.ratePerMinute,model:e.model??null,totalSessions:s,processedSessions:n,pendingSessions:Math.max(0,s-n),lastProcessedSessionId:e.lastProcessedSessionId,backfillPaused:e.backfillPaused}}H();H();import{createReadStream as HE}from"node:fs";import{createInterface as WE}from"node:readline";function ln(e){return typeof e=="number"&&Number.isFinite(e)?e:0}function Kr(e){let t=e?.usage;if(!t||typeof t!="object")return null;let s={inputTokens:ln(t.input_tokens),outputTokens:ln(t.output_tokens),cacheCreateTokens:ln(t.cache_creation_input_tokens),cacheReadTokens:ln(t.cache_read_input_tokens)};return s.inputTokens===0&&s.outputTokens===0&&s.cacheCreateTokens===0&&s.cacheReadTokens===0?null:s}var qE=/\x1B\[[0-9;]*[a-zA-Z]/g;function Gr(e){return e.replace(qE,"")}var Yr=12e3;function hd(e,t){if(e.length<=Yr)return e;let s=e.slice(0,Yr),n=e.length-Yr;return`${s}
1377
1377
 
1378
1378
  \u27E8\u2026 ${n.toLocaleString()} more chars in ${t}; see raw JSONL for full content \u27E9`}function JE(e){try{return JSON.stringify(e,null,2)}catch{return String(e)}}function XE(e){if(typeof e.content=="string")return e.content;if(Array.isArray(e.content)){let t=[];for(let s of e.content)if(s&&typeof s=="object"){let n=s;n.type==="text"&&typeof n.text=="string"?t.push(n.text):n.type==="image"&&t.push("[image]")}return t.join(`
1379
- `)}return""}function GE(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=[],s=[];for(let n of e.content)if(!(!n||typeof n!="object")){if(n.type==="text"&&typeof n.text=="string"){t.push(Jr(n.text));continue}if(n.type==="tool_use"&&typeof n.name=="string"){s.push(n.name);let r=n.input!=null?JE(n.input):"",o=_d(r,"tool input");t.push(`\u26A1 **Tool call \xB7 \`${n.name}\`**
1379
+ `)}return""}function GE(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=[],s=[];for(let n of e.content)if(!(!n||typeof n!="object")){if(n.type==="text"&&typeof n.text=="string"){t.push(Gr(n.text));continue}if(n.type==="tool_use"&&typeof n.name=="string"){s.push(n.name);let r=n.input!=null?JE(n.input):"",o=hd(r,"tool input");t.push(`\u26A1 **Tool call \xB7 \`${n.name}\`**
1380
1380
 
1381
1381
  \`\`\`json
1382
1382
  ${o}
1383
- \`\`\``);continue}if(n.type==="tool_result"){let r=Jr(XE(n));if(r){let o=_d(r,"tool result");t.push(`**Tool result**
1383
+ \`\`\``);continue}if(n.type==="tool_result"){let r=Gr(XE(n));if(r){let o=hd(r,"tool result");t.push(`**Tool result**
1384
1384
 
1385
1385
  \`\`\`
1386
1386
  ${o}
1387
1387
  \`\`\``)}else t.push("_(tool result was empty or image-only)_");continue}if(n.type==="image"){t.push("_(image)_");continue}t.push(`_(unknown block: ${n.type})_`)}return{text:t.join(`
1388
1388
 
1389
- `),toolNames:s}}async function*fd(e){let t=HE(e,{encoding:"utf8"}),s=WE({input:t,crlfDelay:1/0});for await(let n of s){if(!n.trim())continue;let r;try{r=JSON.parse(n)}catch{continue}if(!r.uuid||!r.sessionId)continue;let{text:o,toolNames:a}=GE(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:n,usage:Gr(r.message),model:r.message?.model??null}}}function hd(e,t,s){e.prepare("DELETE FROM message_usage WHERE session_id = ?").run(t);let n=e.prepare(`
1389
+ `),toolNames:s}}async function*Ed(e){let t=HE(e,{encoding:"utf8"}),s=WE({input:t,crlfDelay:1/0});for await(let n of s){if(!n.trim())continue;let r;try{r=JSON.parse(n)}catch{continue}if(!r.uuid||!r.sessionId)continue;let{text:o,toolNames:a}=GE(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:n,usage:Kr(r.message),model:r.message?.model??null}}}function bd(e,t,s){e.prepare("DELETE FROM message_usage WHERE session_id = ?").run(t);let n=e.prepare(`
1390
1390
  INSERT INTO message_usage (
1391
1391
  message_uuid, session_id, model,
1392
1392
  input_tokens, output_tokens, cache_create_tokens, cache_read_tokens,
@@ -1418,14 +1418,14 @@ ${o}
1418
1418
  total_cache_create_tokens = @cc,
1419
1419
  total_cache_read_tokens = @cr,
1420
1420
  primary_model = @model
1421
- WHERE id = @id`).run({id:t,input:s.input_tokens,output:s.output_tokens,cc:s.cache_create_tokens,cr:s.cache_read_tokens,model:n?.model??null})}var YE=500,un=new Set,Ed=null,pn=!1;function bd(){return un.size}function KE(){return`
1421
+ WHERE id = @id`).run({id:t,input:s.input_tokens,output:s.output_tokens,cc:s.cache_create_tokens,cr:s.cache_read_tokens,model:n?.model??null})}var YE=500,un=new Set,Sd=null,pn=!1;function Td(){return un.size}function KE(){return`
1422
1422
  SELECT m.uuid, m.session_id, m.timestamp, m.raw_json
1423
1423
  FROM messages m
1424
1424
  LEFT JOIN message_usage mu ON mu.message_uuid = m.uuid
1425
1425
  WHERE m.role = 'assistant' AND mu.message_uuid IS NULL
1426
1426
  AND m.uuid NOT IN (SELECT value FROM json_each(?))
1427
1427
  LIMIT ?
1428
- `}function Sd(e,t){let s=t.limit??Number.MAX_SAFE_INTEGER,n=Math.max(1,t.chunkSize??YE),r=e.prepare(KE()),o=e.prepare(`
1428
+ `}function yd(e,t){let s=t.limit??Number.MAX_SAFE_INTEGER,n=Math.max(1,t.chunkSize??YE),r=e.prepare(KE()),o=e.prepare(`
1429
1429
  INSERT INTO message_usage (
1430
1430
  message_uuid, session_id, model,
1431
1431
  input_tokens, output_tokens, cache_create_tokens, cache_read_tokens,
@@ -1435,7 +1435,7 @@ ${o}
1435
1435
  @input, @output, @cc, @cr, @ts
1436
1436
  )
1437
1437
  ON CONFLICT(message_uuid) DO NOTHING
1438
- `),a=0,c=0,d=new Set;for(;a<s;){let u=Math.min(n,s-a),g=JSON.stringify([...un]),h=r.all(g,u);if(h.length===0)break;let b=new Set;if(e.transaction(()=>{for(let y of h){let k;try{k=JSON.parse(y.raw_json)}catch{un.add(y.uuid);continue}let w=Gr(k.message);if(!w){un.add(y.uuid);continue}o.run({uuid:y.uuid,session_id:y.session_id,model:k.message?.model??null,input:w.inputTokens,output:w.outputTokens,cc:w.cacheCreateTokens,cr:w.cacheReadTokens,ts:y.timestamp}),c+=1,b.add(y.session_id)}for(let y of b)dn(e,y),d.add(y)})(),a+=h.length,t.onProgress?.({scanned:a,inserted:c,sessionsTouched:d.size,done:h.length<u}),h.length<u)break}return{scanned:a,inserted:c,sessionsTouched:d.size,done:!0}}function Td(e={}){return Sd(f(),e)}function yd(e={}){return pn?!1:(pn=!0,queueMicrotask(()=>{try{let t=Sd(f(),e);Ed={scanned:t.scanned,inserted:t.inserted,sessionsTouched:t.sessionsTouched,finishedAt:new Date().toISOString()}}catch(t){console.error("[stats.backfill] failed:",t)}finally{pn=!1}}),!0)}function wd(){return pn}function Yr(){return Ed}var zE=[[/opus[-_ ]?4[-_. ]?7/i,{label:"Opus 4.7",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/opus[-_ ]?4[-_. ]?6/i,{label:"Opus 4.6",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/sonnet[-_ ]?4[-_. ]?6/i,{label:"Sonnet 4.6",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/sonnet[-_ ]?4[-_. ]?5/i,{label:"Sonnet 4.5",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/haiku[-_ ]?4[-_. ]?5/i,{label:"Haiku 4.5",inputCentsPerMtok:100,outputCentsPerMtok:500,cacheCreateCentsPerMtok:125,cacheReadCentsPerMtok:10}],[/opus[-_ ]?4(?!.*[5-9])/i,{label:"Opus 4",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/sonnet[-_ ]?4(?!.*[5-9])/i,{label:"Sonnet 4",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/3[-_. ]?7[-_ ]?sonnet|sonnet[-_ ]?3[-_. ]?7/i,{label:"Sonnet 3.7",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/3[-_. ]?5[-_ ]?sonnet|sonnet[-_ ]?3[-_. ]?5/i,{label:"Sonnet 3.5",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/3[-_. ]?5[-_ ]?haiku|haiku[-_ ]?3[-_. ]?5/i,{label:"Haiku 3.5",inputCentsPerMtok:80,outputCentsPerMtok:400,cacheCreateCentsPerMtok:100,cacheReadCentsPerMtok:8}],[/3[-_ ]?opus|opus[-_ ]?3/i,{label:"Opus 3",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/3[-_ ]?haiku|haiku(?!.*3[-_. ]?5)/i,{label:"Haiku 3",inputCentsPerMtok:25,outputCentsPerMtok:125,cacheCreateCentsPerMtok:30,cacheReadCentsPerMtok:3}],[/opus/i,{label:"Opus",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/sonnet/i,{label:"Sonnet",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/haiku/i,{label:"Haiku",inputCentsPerMtok:100,outputCentsPerMtok:500,cacheCreateCentsPerMtok:125,cacheReadCentsPerMtok:10}]],Rd={label:"unknown",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30};function je(e){if(!e)return Rd;for(let[t,s]of zE)if(t.test(e))return s;return Rd}function he(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[u,g]of Object.entries(e.byModel)){let h=je(u);a.input+=g.inputTokens/1e6*h.inputCentsPerMtok,a.output+=g.outputTokens/1e6*h.outputCentsPerMtok,a.cacheCreate+=g.cacheCreateTokens/1e6*h.cacheCreateCentsPerMtok,a.cacheRead+=g.cacheReadTokens/1e6*h.cacheReadCentsPerMtok,c+=g.inputTokens+g.outputTokens+g.cacheCreateTokens+g.cacheReadTokens}let d=a.input+a.output+a.cacheCreate+a.cacheRead;return{cents:d,dollars:d/100,totalTokens:c,parts:a}}let s=je(t),n={input:e.inputTokens/1e6*s.inputCentsPerMtok,output:e.outputTokens/1e6*s.outputCentsPerMtok,cacheCreate:e.cacheCreateTokens/1e6*s.cacheCreateCentsPerMtok,cacheRead:e.cacheReadTokens/1e6*s.cacheReadCentsPerMtok},r=n.input+n.output+n.cacheCreate+n.cacheRead,o=e.inputTokens+e.outputTokens+e.cacheCreateTokens+e.cacheReadTokens;return{cents:r,dollars:r/100,totalTokens:o,parts:n}}function ht(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 Et(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 Kr(e){let t=new Map;for(let n of e){let r=n.model??null,o=t.get(r)??{inputTokens:0,outputTokens:0,cacheCreateTokens:0,cacheReadTokens:0,messageCount:0};o.inputTokens+=n.input_tokens,o.outputTokens+=n.output_tokens,o.cacheCreateTokens+=n.cache_create_tokens,o.cacheReadTokens+=n.cache_read_tokens,o.messageCount+=n.n,t.set(r,o)}let s=[];for(let[n,r]of t.entries()){let o=he({inputTokens:r.inputTokens,outputTokens:r.outputTokens,cacheCreateTokens:r.cacheCreateTokens,cacheReadTokens:r.cacheReadTokens},n);s.push({model:n,modelLabel:je(n).label,inputTokens:r.inputTokens,outputTokens:r.outputTokens,cacheCreateTokens:r.cacheCreateTokens,cacheReadTokens:r.cacheReadTokens,messageCount:r.messageCount,cost:o})}return s.sort((n,r)=>r.cost.cents-n.cost.cents)}function zr(e){let t={};for(let s of e)t[s.model??"__unknown__"]={inputTokens:s.inputTokens,outputTokens:s.outputTokens,cacheCreateTokens:s.cacheCreateTokens,cacheReadTokens:s.cacheReadTokens};return{byModel:t}}function kd(e){let t=f(),s=t.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
1438
+ `),a=0,c=0,d=new Set;for(;a<s;){let u=Math.min(n,s-a),g=JSON.stringify([...un]),h=r.all(g,u);if(h.length===0)break;let b=new Set;if(e.transaction(()=>{for(let y of h){let k;try{k=JSON.parse(y.raw_json)}catch{un.add(y.uuid);continue}let w=Kr(k.message);if(!w){un.add(y.uuid);continue}o.run({uuid:y.uuid,session_id:y.session_id,model:k.message?.model??null,input:w.inputTokens,output:w.outputTokens,cc:w.cacheCreateTokens,cr:w.cacheReadTokens,ts:y.timestamp}),c+=1,b.add(y.session_id)}for(let y of b)dn(e,y),d.add(y)})(),a+=h.length,t.onProgress?.({scanned:a,inserted:c,sessionsTouched:d.size,done:h.length<u}),h.length<u)break}return{scanned:a,inserted:c,sessionsTouched:d.size,done:!0}}function wd(e={}){return yd(f(),e)}function Rd(e={}){return pn?!1:(pn=!0,queueMicrotask(()=>{try{let t=yd(f(),e);Sd={scanned:t.scanned,inserted:t.inserted,sessionsTouched:t.sessionsTouched,finishedAt:new Date().toISOString()}}catch(t){console.error("[stats.backfill] failed:",t)}finally{pn=!1}}),!0)}function kd(){return pn}function zr(){return Sd}var zE=[[/opus[-_ ]?4[-_. ]?7/i,{label:"Opus 4.7",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/opus[-_ ]?4[-_. ]?6/i,{label:"Opus 4.6",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/sonnet[-_ ]?4[-_. ]?6/i,{label:"Sonnet 4.6",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/sonnet[-_ ]?4[-_. ]?5/i,{label:"Sonnet 4.5",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/haiku[-_ ]?4[-_. ]?5/i,{label:"Haiku 4.5",inputCentsPerMtok:100,outputCentsPerMtok:500,cacheCreateCentsPerMtok:125,cacheReadCentsPerMtok:10}],[/opus[-_ ]?4(?!.*[5-9])/i,{label:"Opus 4",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/sonnet[-_ ]?4(?!.*[5-9])/i,{label:"Sonnet 4",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/3[-_. ]?7[-_ ]?sonnet|sonnet[-_ ]?3[-_. ]?7/i,{label:"Sonnet 3.7",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/3[-_. ]?5[-_ ]?sonnet|sonnet[-_ ]?3[-_. ]?5/i,{label:"Sonnet 3.5",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/3[-_. ]?5[-_ ]?haiku|haiku[-_ ]?3[-_. ]?5/i,{label:"Haiku 3.5",inputCentsPerMtok:80,outputCentsPerMtok:400,cacheCreateCentsPerMtok:100,cacheReadCentsPerMtok:8}],[/3[-_ ]?opus|opus[-_ ]?3/i,{label:"Opus 3",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/3[-_ ]?haiku|haiku(?!.*3[-_. ]?5)/i,{label:"Haiku 3",inputCentsPerMtok:25,outputCentsPerMtok:125,cacheCreateCentsPerMtok:30,cacheReadCentsPerMtok:3}],[/opus/i,{label:"Opus",inputCentsPerMtok:1500,outputCentsPerMtok:7500,cacheCreateCentsPerMtok:1875,cacheReadCentsPerMtok:150}],[/sonnet/i,{label:"Sonnet",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30}],[/haiku/i,{label:"Haiku",inputCentsPerMtok:100,outputCentsPerMtok:500,cacheCreateCentsPerMtok:125,cacheReadCentsPerMtok:10}]],Ad={label:"unknown",inputCentsPerMtok:300,outputCentsPerMtok:1500,cacheCreateCentsPerMtok:375,cacheReadCentsPerMtok:30};function je(e){if(!e)return Ad;for(let[t,s]of zE)if(t.test(e))return s;return Ad}function he(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[u,g]of Object.entries(e.byModel)){let h=je(u);a.input+=g.inputTokens/1e6*h.inputCentsPerMtok,a.output+=g.outputTokens/1e6*h.outputCentsPerMtok,a.cacheCreate+=g.cacheCreateTokens/1e6*h.cacheCreateCentsPerMtok,a.cacheRead+=g.cacheReadTokens/1e6*h.cacheReadCentsPerMtok,c+=g.inputTokens+g.outputTokens+g.cacheCreateTokens+g.cacheReadTokens}let d=a.input+a.output+a.cacheCreate+a.cacheRead;return{cents:d,dollars:d/100,totalTokens:c,parts:a}}let s=je(t),n={input:e.inputTokens/1e6*s.inputCentsPerMtok,output:e.outputTokens/1e6*s.outputCentsPerMtok,cacheCreate:e.cacheCreateTokens/1e6*s.cacheCreateCentsPerMtok,cacheRead:e.cacheReadTokens/1e6*s.cacheReadCentsPerMtok},r=n.input+n.output+n.cacheCreate+n.cacheRead,o=e.inputTokens+e.outputTokens+e.cacheCreateTokens+e.cacheReadTokens;return{cents:r,dollars:r/100,totalTokens:o,parts:n}}function ht(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 Et(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 Vr(e){let t=new Map;for(let n of e){let r=n.model??null,o=t.get(r)??{inputTokens:0,outputTokens:0,cacheCreateTokens:0,cacheReadTokens:0,messageCount:0};o.inputTokens+=n.input_tokens,o.outputTokens+=n.output_tokens,o.cacheCreateTokens+=n.cache_create_tokens,o.cacheReadTokens+=n.cache_read_tokens,o.messageCount+=n.n,t.set(r,o)}let s=[];for(let[n,r]of t.entries()){let o=he({inputTokens:r.inputTokens,outputTokens:r.outputTokens,cacheCreateTokens:r.cacheCreateTokens,cacheReadTokens:r.cacheReadTokens},n);s.push({model:n,modelLabel:je(n).label,inputTokens:r.inputTokens,outputTokens:r.outputTokens,cacheCreateTokens:r.cacheCreateTokens,cacheReadTokens:r.cacheReadTokens,messageCount:r.messageCount,cost:o})}return s.sort((n,r)=>r.cost.cents-n.cost.cents)}function Zr(e){let t={};for(let s of e)t[s.model??"__unknown__"]={inputTokens:s.inputTokens,outputTokens:s.outputTokens,cacheCreateTokens:s.cacheCreateTokens,cacheReadTokens:s.cacheReadTokens};return{byModel:t}}function Nd(e){let t=f(),s=t.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
1439
1439
  s.message_count,
1440
1440
  s.total_input_tokens, s.total_output_tokens,
1441
1441
  s.total_cache_create_tokens, s.total_cache_read_tokens,
@@ -1450,7 +1450,7 @@ ${o}
1450
1450
  COUNT(*) AS n
1451
1451
  FROM message_usage
1452
1452
  WHERE session_id = ?
1453
- GROUP BY model`).all(e),r=Kr(n),o=s.total_input_tokens??0,a=s.total_output_tokens??0,c=s.total_cache_create_tokens??0,d=s.total_cache_read_tokens??0,u=he({inputTokens:o,outputTokens:a,cacheCreateTokens:c,cacheReadTokens:d,...zr(r)},s.primary_model);return{sessionId:s.id,project:s.project,startedAt:s.started_at,endedAt:s.ended_at,messageCount:s.message_count,primaryModel:s.primary_model,primaryModelLabel:je(s.primary_model).label,inputTokens:o,outputTokens:a,cacheCreateTokens:c,cacheReadTokens:d,totalTokens:u.totalTokens,cost:u,byModel:r,display:{dollars:ht(u.cents),tokens:Et(u.totalTokens),model:je(s.primary_model).label}}}function Ad(e){let t=f(),s=t.prepare("SELECT id, name FROM projects WHERE name = ?").get(e);if(!s)return null;let n=t.prepare(`SELECT mu.model,
1453
+ GROUP BY model`).all(e),r=Vr(n),o=s.total_input_tokens??0,a=s.total_output_tokens??0,c=s.total_cache_create_tokens??0,d=s.total_cache_read_tokens??0,u=he({inputTokens:o,outputTokens:a,cacheCreateTokens:c,cacheReadTokens:d,...Zr(r)},s.primary_model);return{sessionId:s.id,project:s.project,startedAt:s.started_at,endedAt:s.ended_at,messageCount:s.message_count,primaryModel:s.primary_model,primaryModelLabel:je(s.primary_model).label,inputTokens:o,outputTokens:a,cacheCreateTokens:c,cacheReadTokens:d,totalTokens:u.totalTokens,cost:u,byModel:r,display:{dollars:ht(u.cents),tokens:Et(u.totalTokens),model:je(s.primary_model).label}}}function xd(e){let t=f(),s=t.prepare("SELECT id, name FROM projects WHERE name = ?").get(e);if(!s)return null;let n=t.prepare(`SELECT mu.model,
1454
1454
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
1455
1455
  COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
1456
1456
  COALESCE(SUM(mu.cache_create_tokens), 0) AS cache_create_tokens,
@@ -1459,12 +1459,12 @@ ${o}
1459
1459
  FROM message_usage mu
1460
1460
  JOIN sessions s ON s.id = mu.session_id
1461
1461
  WHERE s.project_id = ?
1462
- GROUP BY mu.model`).all(s.id),r=Kr(n),o=t.prepare(`SELECT COALESCE(SUM(total_input_tokens), 0) AS input_tokens,
1462
+ GROUP BY mu.model`).all(s.id),r=Vr(n),o=t.prepare(`SELECT COALESCE(SUM(total_input_tokens), 0) AS input_tokens,
1463
1463
  COALESCE(SUM(total_output_tokens), 0) AS output_tokens,
1464
1464
  COALESCE(SUM(total_cache_create_tokens), 0) AS cache_create_tokens,
1465
1465
  COALESCE(SUM(total_cache_read_tokens), 0) AS cache_read_tokens,
1466
1466
  COUNT(*) AS session_count
1467
- FROM sessions WHERE project_id = ?`).get(s.id),a=he({inputTokens:o.input_tokens,outputTokens:o.output_tokens,cacheCreateTokens:o.cache_create_tokens,cacheReadTokens:o.cache_read_tokens,...zr(r)},null),d=t.prepare(`SELECT s.id, sa.alias, s.started_at,
1467
+ FROM sessions WHERE project_id = ?`).get(s.id),a=he({inputTokens:o.input_tokens,outputTokens:o.output_tokens,cacheCreateTokens:o.cache_create_tokens,cacheReadTokens:o.cache_read_tokens,...Zr(r)},null),d=t.prepare(`SELECT s.id, sa.alias, s.started_at,
1468
1468
  s.total_input_tokens, s.total_output_tokens,
1469
1469
  s.total_cache_create_tokens, s.total_cache_read_tokens,
1470
1470
  s.primary_model
@@ -1475,7 +1475,7 @@ ${o}
1475
1475
  + COALESCE(s.total_output_tokens,0)
1476
1476
  + COALESCE(s.total_cache_create_tokens,0)
1477
1477
  + COALESCE(s.total_cache_read_tokens,0)) DESC
1478
- LIMIT 10`).all(s.id).map(u=>{let g=he({inputTokens:u.total_input_tokens??0,outputTokens:u.total_output_tokens??0,cacheCreateTokens:u.total_cache_create_tokens??0,cacheReadTokens:u.total_cache_read_tokens??0},u.primary_model);return{sessionId:u.id,alias:u.alias,startedAt:u.started_at,totalTokens:g.totalTokens,cost:g}});return{project:s.name,sessionCount:o.session_count,inputTokens:o.input_tokens,outputTokens:o.output_tokens,cacheCreateTokens:o.cache_create_tokens,cacheReadTokens:o.cache_read_tokens,totalTokens:a.totalTokens,cost:a,byModel:r,topSessions:d,display:{dollars:ht(a.cents),tokens:Et(a.totalTokens)}}}function Nd(e="all"){let t=f(),s=e==="7d"?new Date(Date.now()-7*864e5).toISOString():e==="30d"?new Date(Date.now()-30*864e5).toISOString():null,n=s?"WHERE mu.timestamp >= @since OR (mu.timestamp IS NULL AND s.started_at >= @since)":"",r=s?"WHERE m.timestamp >= @since OR (m.timestamp IS NULL AND s2.started_at >= @since)":"",o=s?{since:s}:{},a=m=>s?t.prepare(m).get(o):t.prepare(m).get(),c=m=>s?t.prepare(m).all(o):t.prepare(m).all(),d=c(`SELECT mu.model,
1478
+ LIMIT 10`).all(s.id).map(u=>{let g=he({inputTokens:u.total_input_tokens??0,outputTokens:u.total_output_tokens??0,cacheCreateTokens:u.total_cache_create_tokens??0,cacheReadTokens:u.total_cache_read_tokens??0},u.primary_model);return{sessionId:u.id,alias:u.alias,startedAt:u.started_at,totalTokens:g.totalTokens,cost:g}});return{project:s.name,sessionCount:o.session_count,inputTokens:o.input_tokens,outputTokens:o.output_tokens,cacheCreateTokens:o.cache_create_tokens,cacheReadTokens:o.cache_read_tokens,totalTokens:a.totalTokens,cost:a,byModel:r,topSessions:d,display:{dollars:ht(a.cents),tokens:Et(a.totalTokens)}}}function Od(e="all"){let t=f(),s=e==="7d"?new Date(Date.now()-7*864e5).toISOString():e==="30d"?new Date(Date.now()-30*864e5).toISOString():null,n=s?"WHERE mu.timestamp >= @since OR (mu.timestamp IS NULL AND s.started_at >= @since)":"",r=s?"WHERE m.timestamp >= @since OR (m.timestamp IS NULL AND s2.started_at >= @since)":"",o=s?{since:s}:{},a=m=>s?t.prepare(m).get(o):t.prepare(m).get(),c=m=>s?t.prepare(m).all(o):t.prepare(m).all(),d=c(`SELECT mu.model,
1479
1479
  COALESCE(SUM(mu.input_tokens), 0) AS input_tokens,
1480
1480
  COALESCE(SUM(mu.output_tokens), 0) AS output_tokens,
1481
1481
  COALESCE(SUM(mu.cache_create_tokens), 0) AS cache_create_tokens,
@@ -1484,7 +1484,7 @@ ${o}
1484
1484
  FROM message_usage mu
1485
1485
  JOIN sessions s ON s.id = mu.session_id
1486
1486
  ${n}
1487
- GROUP BY mu.model`),u=Kr(d),g=0,h=0,b=0,S=0;for(let m of u)g+=m.inputTokens,h+=m.outputTokens,b+=m.cacheCreateTokens,S+=m.cacheReadTokens;let y=he({inputTokens:g,outputTokens:h,cacheCreateTokens:b,cacheReadTokens:S,...zr(u)},null),k=s?a(`SELECT
1487
+ GROUP BY mu.model`),u=Vr(d),g=0,h=0,b=0,S=0;for(let m of u)g+=m.inputTokens,h+=m.outputTokens,b+=m.cacheCreateTokens,S+=m.cacheReadTokens;let y=he({inputTokens:g,outputTokens:h,cacheCreateTokens:b,cacheReadTokens:S,...Zr(u)},null),k=s?a(`SELECT
1488
1488
  (SELECT COUNT(DISTINCT m.session_id)
1489
1489
  FROM messages m
1490
1490
  JOIN sessions s2 ON s2.id = m.session_id
@@ -1538,7 +1538,7 @@ ${o}
1538
1538
  ${n}
1539
1539
  GROUP BY p.id, mu.model`),se=new Map;for(let m of B){let _=m.project_id??"__none__",E=se.get(_);E||(E={project:m.project??"(no project)",sessionIds:new Set,sessionsApprox:0,byModel:{}},se.set(_,E)),m.sessions>E.sessionsApprox&&(E.sessionsApprox=m.sessions),E.byModel[m.model??"__unknown__"]={inputTokens:m.input_tokens,outputTokens:m.output_tokens,cacheCreateTokens:m.cache_create_tokens,cacheReadTokens:m.cache_read_tokens}}let i=[...se.values()].map(m=>{let _=0,E=0,T=0,R=0;for(let N of Object.values(m.byModel))_+=N.inputTokens,E+=N.outputTokens,T+=N.cacheCreateTokens,R+=N.cacheReadTokens;let A=he({inputTokens:_,outputTokens:E,cacheCreateTokens:T,cacheReadTokens:R,byModel:m.byModel},null);return{project:m.project,sessions:m.sessionsApprox,totalTokens:A.totalTokens,cost:A}});i.sort((m,_)=>_.totalTokens-m.totalTokens);let l=i.slice(0,20),p=t.prepare(`SELECT
1540
1540
  (SELECT COUNT(*) FROM messages WHERE role='assistant') AS assistant_messages,
1541
- (SELECT COUNT(*) FROM message_usage) AS messages_with_usage`).get();return{range:e,totalSessions:k.total_sessions,sessionsWithUsage:k.sessions_with_usage,inputTokens:g,outputTokens:h,cacheCreateTokens:b,cacheReadTokens:S,totalTokens:y.totalTokens,cost:y,daily:L,byModel:u,topSessions:M,topRepos:l,backfill:{assistantMessages:p.assistant_messages,messagesWithUsage:p.messages_with_usage,pending:Math.max(0,p.assistant_messages-p.messages_with_usage),unrecoverable:Math.min(bd(),Math.max(0,p.assistant_messages-p.messages_with_usage))},display:{dollars:ht(y.cents),tokens:Et(y.totalTokens)}}}H();function Zt(e){return Math.max(0,Math.min(1,e))}function Vr(e){let t=f(),s=t.prepare("SELECT id, name FROM projects WHERE id = ?").get(e);if(!s)return null;let n=t.prepare(`SELECT COUNT(*) AS cnt,
1541
+ (SELECT COUNT(*) FROM message_usage) AS messages_with_usage`).get();return{range:e,totalSessions:k.total_sessions,sessionsWithUsage:k.sessions_with_usage,inputTokens:g,outputTokens:h,cacheCreateTokens:b,cacheReadTokens:S,totalTokens:y.totalTokens,cost:y,daily:L,byModel:u,topSessions:M,topRepos:l,backfill:{assistantMessages:p.assistant_messages,messagesWithUsage:p.messages_with_usage,pending:Math.max(0,p.assistant_messages-p.messages_with_usage),unrecoverable:Math.min(Td(),Math.max(0,p.assistant_messages-p.messages_with_usage))},display:{dollars:ht(y.cents),tokens:Et(y.totalTokens)}}}H();function Zt(e){return Math.max(0,Math.min(1,e))}function Qr(e){let t=f(),s=t.prepare("SELECT id, name FROM projects WHERE id = ?").get(e);if(!s)return null;let n=t.prepare(`SELECT COUNT(*) AS cnt,
1542
1542
  MAX(started_at) AS latest
1543
1543
  FROM sessions WHERE project_id = ?`).get(e),r=n.cnt;if(r===0)return{projectId:e,projectName:s.name,score:0,breakdown:{sessionCount:{raw:0,score:0,weight:.2},recency:{daysSinceLastSession:1/0,score:0,weight:.25},fragmentation:{avgMessages:0,score:0,weight:.15},searchCoverage:{ratio:0,score:0,weight:.2},tagCoverage:{ratio:0,score:0,weight:.2}}};let o=Zt(r/10),a=n.latest?(Date.now()-new Date(n.latest).getTime())/(1e3*60*60*24):90,c=Zt(1-a/90),u=t.prepare(`SELECT AVG(message_count) AS avg_msgs
1544
1544
  FROM sessions WHERE project_id = ?`).get(e).avg_msgs??0,g=Zt((u-2)/3),h=t.prepare(`SELECT COUNT(*) AS total,
@@ -1549,11 +1549,11 @@ ${o}
1549
1549
  COUNT(DISTINCT st.session_id) AS tagged
1550
1550
  FROM sessions s
1551
1551
  LEFT JOIN session_tags st ON st.session_id = s.id
1552
- WHERE s.project_id = ?`).get(e),k=y.total>0?y.tagged/y.total:0,w=Zt(k),D=Math.round((o*.2+c*.25+g*.15+S*.2+w*.2)*100);return{projectId:e,projectName:s.name,score:D,breakdown:{sessionCount:{raw:r,score:o,weight:.2},recency:{daysSinceLastSession:Math.round(a),score:c,weight:.25},fragmentation:{avgMessages:Math.round(u*10)/10,score:g,weight:.15},searchCoverage:{ratio:Math.round(b*100)/100,score:S,weight:.2},tagCoverage:{ratio:Math.round(k*100)/100,score:w,weight:.2}}}}function xd(){let t=f().prepare("SELECT id FROM projects ORDER BY name").all(),s=[];for(let n of t){let r=Vr(n.id);r&&s.push(r)}return s}H();import{execFile as VE}from"node:child_process";import{promisify as ZE}from"node:util";import{stat as QE}from"node:fs/promises";var Od=ZE(VE),Ld=1e4,eb="%H%x09%aI%x09%s";async function tb(e){try{let{stdout:t}=await Od("git",["rev-parse","--is-inside-work-tree"],{cwd:e,timeout:Ld});return t.trim()==="true"}catch{return!1}}async function sb(e,t,s){let n=["--no-pager","log","--all","--no-color","--since",t,"--until",s,`--pretty=format:${eb}`],{stdout:r}=await Od("git",n,{cwd:e,timeout:Ld,maxBuffer:8*1024*1024}),o=[],a=new Set;for(let c of r.split(`
1552
+ WHERE s.project_id = ?`).get(e),k=y.total>0?y.tagged/y.total:0,w=Zt(k),D=Math.round((o*.2+c*.25+g*.15+S*.2+w*.2)*100);return{projectId:e,projectName:s.name,score:D,breakdown:{sessionCount:{raw:r,score:o,weight:.2},recency:{daysSinceLastSession:Math.round(a),score:c,weight:.25},fragmentation:{avgMessages:Math.round(u*10)/10,score:g,weight:.15},searchCoverage:{ratio:Math.round(b*100)/100,score:S,weight:.2},tagCoverage:{ratio:Math.round(k*100)/100,score:w,weight:.2}}}}function Ld(){let t=f().prepare("SELECT id FROM projects ORDER BY name").all(),s=[];for(let n of t){let r=Qr(n.id);r&&s.push(r)}return s}H();import{execFile as VE}from"node:child_process";import{promisify as ZE}from"node:util";import{stat as QE}from"node:fs/promises";var Cd=ZE(VE),Id=1e4,eb="%H%x09%aI%x09%s";async function tb(e){try{let{stdout:t}=await Cd("git",["rev-parse","--is-inside-work-tree"],{cwd:e,timeout:Id});return t.trim()==="true"}catch{return!1}}async function sb(e,t,s){let n=["--no-pager","log","--all","--no-color","--since",t,"--until",s,`--pretty=format:${eb}`],{stdout:r}=await Cd("git",n,{cwd:e,timeout:Id,maxBuffer:8*1024*1024}),o=[],a=new Set;for(let c of r.split(`
1553
1553
  `)){if(!c)continue;let[d,u,...g]=c.split(" ");!d||a.has(d)||(a.add(d),o.push({commit_sha:d,committed_at:u??null,subject:g.join(" ")||null}))}return o}function nb(e){return f().prepare(`SELECT id, cwd, started_at, ended_at
1554
1554
  FROM sessions WHERE id = ?`).get(e)??null}function rb(e,t,s){if(s.length===0)return 0;let n=f(),r=new Date().toISOString(),o=n.prepare(`INSERT OR IGNORE INTO session_commits
1555
1555
  (session_id, commit_sha, committed_at, subject, cwd_snapshot, correlated_at)
1556
- VALUES (?, ?, ?, ?, ?, ?)`),a=0;return n.transaction(d=>{for(let u of d)o.run(e,u.commit_sha,u.committed_at,u.subject,t,r).changes>0&&(a+=1)})(s),a}async function Zr(e){let t=nb(e);if(!t)return{sessionId:e,status:"error",commitsFound:0,commitsInserted:0,error:"session not found"};if(!t.cwd)return{sessionId:e,status:"no-cwd",commitsFound:0,commitsInserted:0};if(!t.started_at||!t.ended_at)return{sessionId:e,status:"no-window",commitsFound:0,commitsInserted:0};let s=t.started_at,n=t.ended_at===t.started_at?new Date(Date.parse(t.ended_at)+1e3).toISOString():t.ended_at;try{if(!(await QE(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 tb(t.cwd))return{sessionId:e,status:"not-a-repo",commitsFound:0,commitsInserted:0};try{let o=await sb(t.cwd,s,n),a=rb(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 mn(e){let t=f(),s=e.trim();if(!/^[0-9a-fA-F]{4,40}$/.test(s))return[];let n=`${s.toLowerCase()}%`;return t.prepare(`SELECT sc.session_id AS sessionId,
1556
+ VALUES (?, ?, ?, ?, ?, ?)`),a=0;return n.transaction(d=>{for(let u of d)o.run(e,u.commit_sha,u.committed_at,u.subject,t,r).changes>0&&(a+=1)})(s),a}async function eo(e){let t=nb(e);if(!t)return{sessionId:e,status:"error",commitsFound:0,commitsInserted:0,error:"session not found"};if(!t.cwd)return{sessionId:e,status:"no-cwd",commitsFound:0,commitsInserted:0};if(!t.started_at||!t.ended_at)return{sessionId:e,status:"no-window",commitsFound:0,commitsInserted:0};let s=t.started_at,n=t.ended_at===t.started_at?new Date(Date.parse(t.ended_at)+1e3).toISOString():t.ended_at;try{if(!(await QE(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 tb(t.cwd))return{sessionId:e,status:"not-a-repo",commitsFound:0,commitsInserted:0};try{let o=await sb(t.cwd,s,n),a=rb(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 mn(e){let t=f(),s=e.trim();if(!/^[0-9a-fA-F]{4,40}$/.test(s))return[];let n=`${s.toLowerCase()}%`;return t.prepare(`SELECT sc.session_id AS sessionId,
1557
1557
  NULLIF(sa.alias, '') AS alias,
1558
1558
  p.name AS project,
1559
1559
  s.started_at AS startedAt,
@@ -1567,20 +1567,20 @@ ${o}
1567
1567
  LEFT JOIN session_aliases sa ON sa.session_id = sc.session_id
1568
1568
  WHERE lower(sc.commit_sha) = lower(?)
1569
1569
  OR lower(sc.commit_sha) LIKE ?
1570
- ORDER BY COALESCE(sc.committed_at, s.started_at, '') DESC`).all(s,n)}function Qr(e){return f().prepare(`SELECT commit_sha, committed_at, subject, correlated_at
1570
+ ORDER BY COALESCE(sc.committed_at, s.started_at, '') DESC`).all(s,n)}function to(e){return f().prepare(`SELECT commit_sha, committed_at, subject, correlated_at
1571
1571
  FROM session_commits
1572
1572
  WHERE session_id = ?
1573
- ORDER BY COALESCE(committed_at, correlated_at) ASC`).all(e)}var ob=3e4;function Cd(e){try{let s=f().prepare(`SELECT MAX(correlated_at) AS last_at
1574
- FROM session_commits WHERE session_id = ?`).get(e),n=s?.last_at?Date.parse(s.last_at):0;if(n&&Date.now()-n<ob)return}catch{}Zr(e).catch(t=>{console.error(`[git-correlator] ${e.slice(0,8)} failed:`,t)})}H();import{execFile as ib}from"node:child_process";import{promisify as ab}from"node:util";import{stat as cb}from"node:fs/promises";var lb=ab(ib),db=60,ub=7,pb=7,mb=5e3;function gb(){let e=f(),t=s=>{try{return!!e.prepare(s).get()}catch{return!1}};return{semantic:t("SELECT 1 FROM session_semantic LIMIT 1"),cost:t(`SELECT 1 FROM sessions
1573
+ ORDER BY COALESCE(committed_at, correlated_at) ASC`).all(e)}var ob=3e4;function vd(e){try{let s=f().prepare(`SELECT MAX(correlated_at) AS last_at
1574
+ FROM session_commits WHERE session_id = ?`).get(e),n=s?.last_at?Date.parse(s.last_at):0;if(n&&Date.now()-n<ob)return}catch{}eo(e).catch(t=>{console.error(`[git-correlator] ${e.slice(0,8)} failed:`,t)})}H();import{execFile as ib}from"node:child_process";import{promisify as ab}from"node:util";import{stat as cb}from"node:fs/promises";var lb=ab(ib),db=60,ub=7,pb=7,mb=5e3;function gb(){let e=f(),t=s=>{try{return!!e.prepare(s).get()}catch{return!1}};return{semantic:t("SELECT 1 FROM session_semantic LIMIT 1"),cost:t(`SELECT 1 FROM sessions
1575
1575
  WHERE (COALESCE(total_input_tokens,0)
1576
1576
  + COALESCE(total_output_tokens,0)
1577
1577
  + COALESCE(total_cache_create_tokens,0)
1578
1578
  + COALESCE(total_cache_read_tokens,0)) > 0
1579
- LIMIT 1`),git:t("SELECT 1 FROM session_commits LIMIT 1")}}function eo(e){if(!e)return[];let t=new Set,s=[];for(let n of e.split(",")){let r=n.trim().toLowerCase();!r||t.has(r)||(t.add(r),s.push(r))}return s}function Id(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 _b(){let e=f(),t=e.prepare(`SELECT ss.keywords
1579
+ LIMIT 1`),git:t("SELECT 1 FROM session_commits LIMIT 1")}}function so(e){if(!e)return[];let t=new Set,s=[];for(let n of e.split(",")){let r=n.trim().toLowerCase();!r||t.has(r)||(t.add(r),s.push(r))}return s}function jd(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 _b(){let e=f(),t=e.prepare(`SELECT ss.keywords
1580
1580
  FROM session_semantic ss
1581
1581
  JOIN sessions s ON s.id = ss.session_id
1582
1582
  WHERE s.started_at IS NOT NULL
1583
- AND julianday('now') - julianday(s.started_at) <= @windowDays`).all({windowDays:ub});if(t.length===0)return null;let s=new Set;for(let o of t)for(let a of eo(o.keywords))s.add(a);if(s.size===0)return null;let n=e.prepare(`SELECT ss.session_id AS session_id,
1583
+ AND julianday('now') - julianday(s.started_at) <= @windowDays`).all({windowDays:ub});if(t.length===0)return null;let s=new Set;for(let o of t)for(let a of so(o.keywords))s.add(a);if(s.size===0)return null;let n=e.prepare(`SELECT ss.session_id AS session_id,
1584
1584
  ss.summary AS summary,
1585
1585
  ss.keywords AS keywords,
1586
1586
  p.name AS project,
@@ -1596,7 +1596,7 @@ ${o}
1596
1596
  WHERE s.started_at IS NOT NULL
1597
1597
  AND s.message_count > 2
1598
1598
  AND julianday('now') - julianday(s.started_at) >= @ageDays
1599
- ORDER BY s.started_at ASC`).all({ageDays:db});if(n.length===0)return null;let r=null;for(let o of n){let c=eo(o.keywords).filter(d=>s.has(d));c.length!==0&&(!r||c.length>r.overlap.length)&&(r={row:o,overlap:c})}return r?{...Id(r.row),summary:r.row.summary,keywords:eo(r.row.keywords),matchedKeywords:r.overlap,daysAgo:Math.max(0,Math.round(r.row.days_old))}:null}function fb(){let t=f().prepare(`SELECT s.id AS session_id,
1599
+ ORDER BY s.started_at ASC`).all({ageDays:db});if(n.length===0)return null;let r=null;for(let o of n){let c=so(o.keywords).filter(d=>s.has(d));c.length!==0&&(!r||c.length>r.overlap.length)&&(r={row:o,overlap:c})}return r?{...jd(r.row),summary:r.row.summary,keywords:so(r.row.keywords),matchedKeywords:r.overlap,daysAgo:Math.max(0,Math.round(r.row.days_old))}:null}function fb(){let t=f().prepare(`SELECT s.id AS session_id,
1600
1600
  p.name AS project,
1601
1601
  NULLIF(sa.alias, '') AS alias,
1602
1602
  s.started_at AS started_at,
@@ -1615,28 +1615,28 @@ ${o}
1615
1615
  AND (COALESCE(s.total_input_tokens, 0)
1616
1616
  + COALESCE(s.total_output_tokens, 0)
1617
1617
  + COALESCE(s.total_cache_create_tokens, 0)
1618
- + COALESCE(s.total_cache_read_tokens, 0)) > 0`).all({windowDays:pb});if(t.length===0)return null;let s=null;for(let n of t){let r=he({inputTokens:n.input_tokens,outputTokens:n.output_tokens,cacheCreateTokens:n.cache_create_tokens,cacheReadTokens:n.cache_read_tokens},n.primary_model);r.cents<=0||(!s||r.cents>s.cents)&&(s={row:n,cents:r.cents,totalTokens:r.totalTokens})}return s?{...Id(s.row),totalTokens:s.totalTokens,costCents:s.cents,costDisplay:ht(s.cents),tokensDisplay:Et(s.totalTokens),primaryModel:s.row.primary_model,primaryModelLabel:je(s.row.primary_model).label}:null}async function hb(e){try{if(!(await cb(e)).isDirectory())return null}catch{return null}try{let{stdout:t}=await lb("git",["rev-parse","HEAD"],{cwd:e,timeout:mb}),s=t.trim();return/^[0-9a-f]{40}$/.test(s)?s:null}catch{return null}}async function Eb(){let e=f(),t=e.prepare(`SELECT s.id AS id, s.cwd AS cwd
1618
+ + COALESCE(s.total_cache_read_tokens, 0)) > 0`).all({windowDays:pb});if(t.length===0)return null;let s=null;for(let n of t){let r=he({inputTokens:n.input_tokens,outputTokens:n.output_tokens,cacheCreateTokens:n.cache_create_tokens,cacheReadTokens:n.cache_read_tokens},n.primary_model);r.cents<=0||(!s||r.cents>s.cents)&&(s={row:n,cents:r.cents,totalTokens:r.totalTokens})}return s?{...jd(s.row),totalTokens:s.totalTokens,costCents:s.cents,costDisplay:ht(s.cents),tokensDisplay:Et(s.totalTokens),primaryModel:s.row.primary_model,primaryModelLabel:je(s.row.primary_model).label}:null}async function hb(e){try{if(!(await cb(e)).isDirectory())return null}catch{return null}try{let{stdout:t}=await lb("git",["rev-parse","HEAD"],{cwd:e,timeout:mb}),s=t.trim();return/^[0-9a-f]{40}$/.test(s)?s:null}catch{return null}}async function Eb(){let e=f(),t=e.prepare(`SELECT s.id AS id, s.cwd AS cwd
1619
1619
  FROM sessions s
1620
1620
  WHERE s.cwd IS NOT NULL AND s.started_at IS NOT NULL
1621
1621
  ORDER BY COALESCE(s.ended_at, s.started_at, '') DESC
1622
1622
  LIMIT 1`).get();if(!t?.cwd)return null;let s=await hb(t.cwd);if(!s)return null;let n=mn(s);if(n.length===0)return null;let r=n[0],o=e.prepare(`SELECT s.first_user_message AS first_user_message, s.ended_at AS ended_at
1623
1623
  FROM sessions s
1624
- 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 vd(){let e=gb(),t=e.semantic?Promise.resolve().then(()=>{try{return _b()}catch(c){return console.error("[discover.rediscovered]",c),null}}):Promise.resolve(null),s=e.cost?Promise.resolve().then(()=>{try{return fb()}catch(c){return console.error("[discover.expensive]",c),null}}):Promise.resolve(null),n=e.git?Eb().catch(c=>(console.error("[discover.authored]",c),null)):Promise.resolve(null),[r,o,a]=await Promise.all([t,s,n]);return{rediscovered:r,expensive:o,authored:a,availability:e,generatedAt:new Date().toISOString()}}ot();H();ot();async function jd(e,t=50){let s=await hr(e),n=f(),r=Buffer.from(s.buffer,s.byteOffset,s.byteLength);return n.prepare(`SELECT v.rowid, v.distance, cm.session_id, cm.text, cm.message_uuids
1624
+ 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 Md(){let e=gb(),t=e.semantic?Promise.resolve().then(()=>{try{return _b()}catch(c){return console.error("[discover.rediscovered]",c),null}}):Promise.resolve(null),s=e.cost?Promise.resolve().then(()=>{try{return fb()}catch(c){return console.error("[discover.expensive]",c),null}}):Promise.resolve(null),n=e.git?Eb().catch(c=>(console.error("[discover.authored]",c),null)):Promise.resolve(null),[r,o,a]=await Promise.all([t,s,n]);return{rediscovered:r,expensive:o,authored:a,availability:e,generatedAt:new Date().toISOString()}}ot();H();ot();async function Dd(e,t=50){let s=await br(e),n=f(),r=Buffer.from(s.buffer,s.byteOffset,s.byteLength);return n.prepare(`SELECT v.rowid, v.distance, cm.session_id, cm.text, cm.message_uuids
1625
1625
  FROM vec_chunks v JOIN chunk_meta cm ON cm.rowid = v.rowid
1626
- 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 Md(e,t=10,s=.65){let n=f(),r=n.prepare("SELECT rowid FROM chunk_meta WHERE session_id = ? ORDER BY rowid LIMIT 1").get(e);if(!r)return[];let o=n.prepare("SELECT embedding FROM vec_chunks WHERE rowid = ?").get(r.rowid);if(!o)return[];let a=n.prepare(`SELECT v.rowid, v.distance, cm.session_id FROM vec_chunks v JOIN chunk_meta cm ON cm.rowid = v.rowid
1627
- WHERE v.embedding MATCH ? AND k = ? ORDER BY v.distance`).all(o.embedding,t*5),c=new Map;for(let u of a){if(u.session_id===e)continue;let g=c.get(u.session_id);(g===void 0||u.distance<g)&&c.set(u.session_id,u.distance)}let d=[];for(let[u,g]of c){let h=1-g;h>=s&&d.push({sessionId:u,similarity:h})}return d.sort((u,g)=>g.similarity-u.similarity),d.slice(0,t)}function bb(){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 Dd(e){let t=bb(),s=new Map;for(let r of e)for(let o=0;o<r.length;o++){let a=r[o],c=1/(t+o+1),d=s.get(a.id);d?(d.score+=c,d.lanes.push(a.lane),o+1<d.bestRank&&(d.bestRank=o+1,d.bestData=a.data)):s.set(a.id,{score:c,lanes:[a.lane],bestRank:o+1,bestData:a.data})}let n=[];for(let[r,o]of s)n.push({id:r,score:o.score,lanes:o.lanes,data:o.bestData});return n.sort((r,o)=>o.score-r.score),n}H();ot();H();function Fd(e){return e.replace(/```json[\s\S]*?```/g,"[tool-call]").replace(/\{[\s\S]{200,}?\}/g,"[json-object]")}function Sb(e){let t=[],o=0;for(;o<e.length;){let a=[],c=0;for(;a.length<5&&o<e.length;){let u=e[o],g=Fd(u.content_text??"");if(c+g.length>2e3&&a.length>=3)break;a.push(u),c+=g.length,o++}if(a.length===0)break;let d=a.map(u=>{let g=u.role??"system",h=Fd(u.content_text??"");return`[${g}] ${h}`}).join(`
1626
+ 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 Fd(e,t=10,s=.65){let n=f(),r=n.prepare("SELECT rowid FROM chunk_meta WHERE session_id = ? ORDER BY rowid LIMIT 1").get(e);if(!r)return[];let o=n.prepare("SELECT embedding FROM vec_chunks WHERE rowid = ?").get(r.rowid);if(!o)return[];let a=n.prepare(`SELECT v.rowid, v.distance, cm.session_id FROM vec_chunks v JOIN chunk_meta cm ON cm.rowid = v.rowid
1627
+ WHERE v.embedding MATCH ? AND k = ? ORDER BY v.distance`).all(o.embedding,t*5),c=new Map;for(let u of a){if(u.session_id===e)continue;let g=c.get(u.session_id);(g===void 0||u.distance<g)&&c.set(u.session_id,u.distance)}let d=[];for(let[u,g]of c){let h=1-g;h>=s&&d.push({sessionId:u,similarity:h})}return d.sort((u,g)=>g.similarity-u.similarity),d.slice(0,t)}function bb(){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 Pd(e){let t=bb(),s=new Map;for(let r of e)for(let o=0;o<r.length;o++){let a=r[o],c=1/(t+o+1),d=s.get(a.id);d?(d.score+=c,d.lanes.push(a.lane),o+1<d.bestRank&&(d.bestRank=o+1,d.bestData=a.data)):s.set(a.id,{score:c,lanes:[a.lane],bestRank:o+1,bestData:a.data})}let n=[];for(let[r,o]of s)n.push({id:r,score:o.score,lanes:o.lanes,data:o.bestData});return n.sort((r,o)=>o.score-r.score),n}H();ot();H();function Ud(e){return e.replace(/```json[\s\S]*?```/g,"[tool-call]").replace(/\{[\s\S]{200,}?\}/g,"[json-object]")}function Sb(e){let t=[],o=0;for(;o<e.length;){let a=[],c=0;for(;a.length<5&&o<e.length;){let u=e[o],g=Ud(u.content_text??"");if(c+g.length>2e3&&a.length>=3)break;a.push(u),c+=g.length,o++}if(a.length===0)break;let d=a.map(u=>{let g=u.role??"system",h=Ud(u.content_text??"");return`[${g}] ${h}`}).join(`
1628
1628
 
1629
- `);t.push({messageUuids:a.map(u=>u.uuid),text:d}),o<e.length&&a.length>=3&&(o=Math.max(o-1,o-1))}return t}function Pd(e){let s=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 Sb(s)}var Ud=2e3,Tb=1e4,gn=null,to=!1,$d=null;function yb(){return f().prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}async function wb(){let e=f(),t=e.prepare("SELECT DISTINCT session_id FROM chunk_queue ORDER BY id LIMIT 1").get();if(!t)return!1;let s=t.session_id;try{e.prepare("DELETE FROM vec_chunks WHERE rowid IN (SELECT rowid FROM chunk_meta WHERE session_id = ?)").run(s),e.prepare("DELETE FROM chunk_meta WHERE session_id = ?").run(s);let n=Pd(s);if(n.length===0)return e.prepare("DELETE FROM chunk_queue WHERE session_id = ?").run(s),!0;let r=n.map(u=>u.text),o=await $t(r),a=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'))"),c=e.prepare("INSERT INTO vec_chunks(rowid, embedding) VALUES (?, ?)");e.transaction(()=>{for(let u=0;u<n.length;u++){let g=a.run(s,JSON.stringify(n[u].messageUuids),n[u].text),h=Buffer.from(o[u].buffer,o[u].byteOffset,o[u].byteLength);c.run(g.lastInsertRowid,h)}e.prepare("DELETE FROM chunk_queue WHERE session_id = ?").run(s)})(),$d=new Date().toISOString()}catch(n){console.error("[vector-worker] failed for session",s,n),e.prepare("DELETE FROM chunk_queue WHERE session_id = ?").run(s)}return!0}async function Bd(){if(!ke().loaded)return;let e=await wb();gn!==null&&clearTimeout(gn),gn=setTimeout(()=>{Bd()},e?Ud:Tb)}function Hd(){if(!to){if(!ke().loaded){console.error("[vector-worker] cannot start: embedder not loaded");return}to=!0,gn=setTimeout(()=>{Bd()},Ud)}}function Wd(){return{running:to,queueDepth:yb(),lastProcessedAt:$d}}Z();import{existsSync as Xd,mkdirSync as qd,rmSync as Jd,createWriteStream as Rb,statSync as kb}from"node:fs";import{join as _n}from"node:path";import{createHash as Ab}from"node:crypto";import{readFile as Nb}from"node:fs/promises";var xb="https://huggingface.co/BAAI/bge-base-en-v1.5/resolve/main/",Gd=[{path:"config.json",sha256:"bc00af31a4a31b74040d73370aa83b62da34c90b75eb77bfa7db039d90abd591"},{path:"tokenizer.json",sha256:"d241a60d5e8f04cc1b2b3e9ef7a4921b27bf526d9f6050ab90f9267a1f9e5c66"},{path:"tokenizer_config.json",sha256:"9261e7d79b44c8195c1cada2b453e55b00aeb81e907a6664974b4d7776172ab3"},{path:"onnx/model.onnx",sha256:"9bc579acdba21c253c62a9bf866891355a63ffa3442b52c8a37d75b2ccb91848"}];function Yd(){return _n($,"models","BAAI","bge-base-en-v1.5")}function so(){let e=Yd();return Gd.every(t=>Xd(_n(e,t.path)))}async function Kd(e){let t=Yd();qd(t,{recursive:!0}),qd(_n(t,"onnx"),{recursive:!0});for(let s of Gd){let n=_n(t,s.path),r=xb+s.path,o=0;Xd(n)&&(o=kb(n).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 ${s.path}: HTTP ${c.status}`);let d=c.headers.get("content-length"),u=d?o+Number(d):0,g=c.body;if(!g)throw new Error(`No response body for ${s.path}`);let h=Rb(n,{flags:o>0?"a":"w"}),b=g.getReader(),S=o;for(;;){let{done:w,value:D}=await b.read();if(w)break;h.write(Buffer.from(D)),S+=D.byteLength,e?.(s.path,S,u)}if(h.end(),await new Promise((w,D)=>{h.on("finish",w),h.on("error",D)}),s.sha256==="TODO_PLACEHOLDER")throw Jd(n),new Error(`Refusing to install: SHA-256 not pinned for ${s.path}. Update model-download.ts.`);let y=await Nb(n);if(Ab("sha256").update(y).digest("hex")!==s.sha256)throw Jd(n),new Error(`SHA-256 mismatch for ${s.path}`)}}H();var Ob=[/\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],Lb=1440*60*1e3;function Cb(e){let t=f(),s=t.prepare(`SELECT content_text, tool_names FROM messages
1629
+ `);t.push({messageUuids:a.map(u=>u.uuid),text:d}),o<e.length&&a.length>=3&&(o=Math.max(o-1,o-1))}return t}function $d(e){let s=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 Sb(s)}var Bd=2e3,Tb=1e4,gn=null,no=!1,Hd=null;function yb(){return f().prepare("SELECT COUNT(*) AS n FROM chunk_queue").get().n}async function wb(){let e=f(),t=e.prepare("SELECT DISTINCT session_id FROM chunk_queue ORDER BY id LIMIT 1").get();if(!t)return!1;let s=t.session_id;try{e.prepare("DELETE FROM vec_chunks WHERE rowid IN (SELECT rowid FROM chunk_meta WHERE session_id = ?)").run(s),e.prepare("DELETE FROM chunk_meta WHERE session_id = ?").run(s);let n=$d(s);if(n.length===0)return e.prepare("DELETE FROM chunk_queue WHERE session_id = ?").run(s),!0;let r=n.map(u=>u.text),o=await $t(r),a=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'))"),c=e.prepare("INSERT INTO vec_chunks(rowid, embedding) VALUES (?, ?)");e.transaction(()=>{for(let u=0;u<n.length;u++){let g=a.run(s,JSON.stringify(n[u].messageUuids),n[u].text),h=Buffer.from(o[u].buffer,o[u].byteOffset,o[u].byteLength);c.run(g.lastInsertRowid,h)}e.prepare("DELETE FROM chunk_queue WHERE session_id = ?").run(s)})(),Hd=new Date().toISOString()}catch(n){console.error("[vector-worker] failed for session",s,n),e.prepare("DELETE FROM chunk_queue WHERE session_id = ?").run(s)}return!0}async function Wd(){if(!ke().loaded)return;let e=await wb();gn!==null&&clearTimeout(gn),gn=setTimeout(()=>{Wd()},e?Bd:Tb)}function qd(){if(!no){if(!ke().loaded){console.error("[vector-worker] cannot start: embedder not loaded");return}no=!0,gn=setTimeout(()=>{Wd()},Bd)}}function Jd(){return{running:no,queueDepth:yb(),lastProcessedAt:Hd}}Z();import{existsSync as Yd,mkdirSync as Xd,rmSync as Gd,createWriteStream as Rb,statSync as kb}from"node:fs";import{join as _n}from"node:path";import{createHash as Ab}from"node:crypto";import{readFile as Nb}from"node:fs/promises";var xb="https://huggingface.co/BAAI/bge-base-en-v1.5/resolve/main/",Kd=[{path:"config.json",sha256:"bc00af31a4a31b74040d73370aa83b62da34c90b75eb77bfa7db039d90abd591"},{path:"tokenizer.json",sha256:"d241a60d5e8f04cc1b2b3e9ef7a4921b27bf526d9f6050ab90f9267a1f9e5c66"},{path:"tokenizer_config.json",sha256:"9261e7d79b44c8195c1cada2b453e55b00aeb81e907a6664974b4d7776172ab3"},{path:"onnx/model.onnx",sha256:"9bc579acdba21c253c62a9bf866891355a63ffa3442b52c8a37d75b2ccb91848"}];function zd(){return _n($,"models","BAAI","bge-base-en-v1.5")}function ro(){let e=zd();return Kd.every(t=>Yd(_n(e,t.path)))}async function Vd(e){let t=zd();Xd(t,{recursive:!0}),Xd(_n(t,"onnx"),{recursive:!0});for(let s of Kd){let n=_n(t,s.path),r=xb+s.path,o=0;Yd(n)&&(o=kb(n).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 ${s.path}: HTTP ${c.status}`);let d=c.headers.get("content-length"),u=d?o+Number(d):0,g=c.body;if(!g)throw new Error(`No response body for ${s.path}`);let h=Rb(n,{flags:o>0?"a":"w"}),b=g.getReader(),S=o;for(;;){let{done:w,value:D}=await b.read();if(w)break;h.write(Buffer.from(D)),S+=D.byteLength,e?.(s.path,S,u)}if(h.end(),await new Promise((w,D)=>{h.on("finish",w),h.on("error",D)}),s.sha256==="TODO_PLACEHOLDER")throw Gd(n),new Error(`Refusing to install: SHA-256 not pinned for ${s.path}. Update model-download.ts.`);let y=await Nb(n);if(Ab("sha256").update(y).digest("hex")!==s.sha256)throw Gd(n),new Error(`SHA-256 mismatch for ${s.path}`)}}H();var Ob=[/\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],Lb=1440*60*1e3;function Cb(e){let t=f(),s=t.prepare(`SELECT content_text, tool_names FROM messages
1630
1630
  WHERE session_id = ? AND role = 'assistant'
1631
1631
  ORDER BY timestamp DESC LIMIT 5`).all(e),n=!1;for(let d of s)if(d.content_text&&Ob.some(u=>u.test(d.content_text))){n=!0;break}let r=t.prepare(`SELECT content_text, tool_names FROM messages
1632
- WHERE session_id = ?`).all(e),o={fileWrites:!1,testRuns:!1,commits:!1,buildSuccess:!1};for(let d of r){let u=d.tool_names??"",g=d.content_text??"";/\bWrite\b|\bEdit\b/.test(u)&&(o.fileWrites=!0),/\b(?:jest|pytest|vitest|mocha|test|spec)\b/i.test(g)&&/pass|ok|✓/i.test(g)&&(o.testRuns=!0),/\bgit\s+commit\b/i.test(g)&&(o.commits=!0),(/\bbuild\s+(?:succeeded|success|passed)\b/i.test(g)||/tsc.*(?:0 errors|no errors)/i.test(g))&&(o.buildSuccess=!0)}return n?{status:[o.fileWrites,o.testRuns,o.commits,o.buildSuccess].filter(Boolean).length>=2?"verified":"unverified",evidence:o,claimFound:n}:{status:"neutral",evidence:o,claimFound:n}}function Ib(e){let t=Cb(e);return f().prepare("UPDATE sessions SET verification_status = ?, verification_computed_at = ? WHERE id = ?").run(t.status,Date.now(),e),t}function zd(e){let s=f().prepare("SELECT verification_status, verification_computed_at FROM sessions WHERE id = ?").get(e);if(s?.verification_status&&s.verification_computed_at&&Date.now()-s.verification_computed_at<Lb){let n={fileWrites:!1,testRuns:!1,commits:!1,buildSuccess:!1};return{status:s.verification_status,evidence:n,claimFound:s.verification_status!=="neutral"}}return Ib(e)}import{readFileSync as vb,writeFileSync as jb,mkdirSync as Mb,chmodSync as Db}from"node:fs";import{join as Vd}from"node:path";import{homedir as Zd}from"node:os";function Qd(){return Vd(Zd(),".recall","config.json")}function eu(){try{return JSON.parse(vb(Qd(),"utf-8"))}catch{return{}}}function Fb(e){let t=Qd();Mb(Vd(Zd(),".recall"),{recursive:!0}),jb(t,JSON.stringify(e,null,2)+`
1633
- `,"utf-8"),Db(t,384)}function no(){let t=eu().verification;return typeof t=="object"&&t!==null&&"enabled"in t?!!t.enabled:!1}function tu(e){let t=eu();t.verification={...typeof t.verification=="object"&&t.verification!==null?t.verification:{},enabled:e},Fb(t)}var Pb=[{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 Ub(e){if(e.length<=8)return e.slice(0,2)+"\u2022".repeat(Math.max(0,e.length-4))+e.slice(-2);let t=e.slice(0,Math.min(6,Math.floor(e.length/3))),s=e.slice(-Math.min(4,Math.floor(e.length/4)));return`${t}${"\u2022".repeat(Math.max(3,e.length-t.length-s.length))}${s}`}function $b(e){let t=5381;for(let s=0;s<e.length;s++)t=(t<<5)+t+e.charCodeAt(s)|0;return(t>>>0).toString(36)}function qe(e){if(!e)return{redacted:e,count:0};let t=e,s=0,n=new Set;for(let r of Pb)r.regex.lastIndex=0,t=t.replace(r.regex,o=>{let a=`${r.name}::${$b(o)}`;return n.has(a)||(n.add(a),s+=1),`[REDACTED ${r.name}: ${Ub(o)}]`});return{redacted:t,count:s}}var Kb=5e3,po={scanned:0,linked:0,renamed:0,skipped_manual:0,ambiguous_cwd:0},oo=0,io=po,ao=null;async function zb(){return Date.now()-oo>=Kb&&!ao&&(ao=Ds().then(s=>(io=s,oo=Date.now(),s)).catch(()=>(oo=Date.now(),io=po,po)).finally(()=>{ao=null})),io}var Vb=2e3,Zb=6,hn=new Map;function Qt(e){return e.replace(/[\\%_]/g,t=>"\\"+t)}function Qb(e,t){let s=Date.now(),n=(hn.get(e)??[]).filter(a=>s-a.ts<Vb);return hn.set(e,n),n.length<2||n[n.length-1].name===t?!1:n.slice(0,-1).some(a=>a.name===t)}function eS(e,t){let s=hn.get(e)??[];for(s.push({name:t,ts:Date.now()});s.length>Zb;)s.shift();hn.set(e,s)}function nu(e,t){let s=t.trim();if(!s)return 0;if(ne(s)){let o=tt(s);if(!o)return 0;s=o}if(re(s))return 0;if(Qb(e,s))return console.log(`[terminal] dropping rename of pid ${e} \u2192 "${s}", flap signature (competing editor sync sources)`),0;eS(e,s);let n=I.sessionsFor(e),r=0;for(let o of n)try{if(Se(o)===s)continue;me(o,s),r++}catch{}return r>0&&console.log(`[terminal] rename of pid ${e} \u2192 "${s}" propagated to ${r} session(s)`),r}var ru="0.53.2",co=!1,lo=!1,uo=!1,sS=au(cu(import.meta.url)),mo=_o(sS,"..","web"),go=_o(mo,"index.html"),nS=Wb(go);function ou(){return f().prepare(`SELECT
1632
+ WHERE session_id = ?`).all(e),o={fileWrites:!1,testRuns:!1,commits:!1,buildSuccess:!1};for(let d of r){let u=d.tool_names??"",g=d.content_text??"";/\bWrite\b|\bEdit\b/.test(u)&&(o.fileWrites=!0),/\b(?:jest|pytest|vitest|mocha|test|spec)\b/i.test(g)&&/pass|ok|✓/i.test(g)&&(o.testRuns=!0),/\bgit\s+commit\b/i.test(g)&&(o.commits=!0),(/\bbuild\s+(?:succeeded|success|passed)\b/i.test(g)||/tsc.*(?:0 errors|no errors)/i.test(g))&&(o.buildSuccess=!0)}return n?{status:[o.fileWrites,o.testRuns,o.commits,o.buildSuccess].filter(Boolean).length>=2?"verified":"unverified",evidence:o,claimFound:n}:{status:"neutral",evidence:o,claimFound:n}}function Ib(e){let t=Cb(e);return f().prepare("UPDATE sessions SET verification_status = ?, verification_computed_at = ? WHERE id = ?").run(t.status,Date.now(),e),t}function Zd(e){let s=f().prepare("SELECT verification_status, verification_computed_at FROM sessions WHERE id = ?").get(e);if(s?.verification_status&&s.verification_computed_at&&Date.now()-s.verification_computed_at<Lb){let n={fileWrites:!1,testRuns:!1,commits:!1,buildSuccess:!1};return{status:s.verification_status,evidence:n,claimFound:s.verification_status!=="neutral"}}return Ib(e)}import{readFileSync as vb,writeFileSync as jb,mkdirSync as Mb,chmodSync as Db}from"node:fs";import{join as Qd}from"node:path";import{homedir as eu}from"node:os";function tu(){return Qd(eu(),".recall","config.json")}function su(){try{return JSON.parse(vb(tu(),"utf-8"))}catch{return{}}}function Fb(e){let t=tu();Mb(Qd(eu(),".recall"),{recursive:!0}),jb(t,JSON.stringify(e,null,2)+`
1633
+ `,"utf-8"),Db(t,384)}function oo(){let t=su().verification;return typeof t=="object"&&t!==null&&"enabled"in t?!!t.enabled:!1}function nu(e){let t=su();t.verification={...typeof t.verification=="object"&&t.verification!==null?t.verification:{},enabled:e},Fb(t)}var Pb=[{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 Ub(e){if(e.length<=8)return e.slice(0,2)+"\u2022".repeat(Math.max(0,e.length-4))+e.slice(-2);let t=e.slice(0,Math.min(6,Math.floor(e.length/3))),s=e.slice(-Math.min(4,Math.floor(e.length/4)));return`${t}${"\u2022".repeat(Math.max(3,e.length-t.length-s.length))}${s}`}function $b(e){let t=5381;for(let s=0;s<e.length;s++)t=(t<<5)+t+e.charCodeAt(s)|0;return(t>>>0).toString(36)}function qe(e){if(!e)return{redacted:e,count:0};let t=e,s=0,n=new Set;for(let r of Pb)r.regex.lastIndex=0,t=t.replace(r.regex,o=>{let a=`${r.name}::${$b(o)}`;return n.has(a)||(n.add(a),s+=1),`[REDACTED ${r.name}: ${Ub(o)}]`});return{redacted:t,count:s}}var Kb=5e3,mo={scanned:0,linked:0,renamed:0,skipped_manual:0,ambiguous_cwd:0},io=0,ao=mo,co=null;async function zb(){return Date.now()-io>=Kb&&!co&&(co=Ds().then(s=>(ao=s,io=Date.now(),s)).catch(()=>(io=Date.now(),ao=mo,mo)).finally(()=>{co=null})),ao}var Vb=2e3,Zb=6,En=new Map;function Qt(e){return e.replace(/[\\%_]/g,t=>"\\"+t)}function Qb(e,t){let s=Date.now(),n=(En.get(e)??[]).filter(a=>s-a.ts<Vb);return En.set(e,n),n.length<2||n[n.length-1].name===t?!1:n.slice(0,-1).some(a=>a.name===t)}function eS(e,t){let s=En.get(e)??[];for(s.push({name:t,ts:Date.now()});s.length>Zb;)s.shift();En.set(e,s)}function ou(e,t){let s=t.trim();if(!s)return 0;if(ne(s)){let o=tt(s);if(!o)return 0;s=o}if(re(s))return 0;if(Qb(e,s))return console.log(`[terminal] dropping rename of pid ${e} \u2192 "${s}", flap signature (competing editor sync sources)`),0;eS(e,s);let n=I.sessionsFor(e),r=0;for(let o of n)try{if(Se(o)===s)continue;me(o,s),r++}catch{}return r>0&&console.log(`[terminal] rename of pid ${e} \u2192 "${s}" propagated to ${r} session(s)`),r}var iu=(()=>{try{let e=bn(fo(ho(import.meta.url)),"..","..","package.json");return JSON.parse(hn(e,"utf8")).version??"0.0.0"}catch{return"0.0.0"}})(),lo=!1,uo=!1,po=!1,sS=fo(ho(import.meta.url)),go=bn(sS,"..","web"),_o=bn(go,"index.html"),nS=Wb(_o);function au(){return f().prepare(`SELECT
1634
1634
  (SELECT COUNT(*) FROM projects) AS projects,
1635
1635
  (SELECT COUNT(*) FROM sessions) AS sessions,
1636
1636
  (SELECT COUNT(*) FROM messages) AS messages,
1637
1637
  (SELECT MIN(started_at) FROM sessions WHERE started_at IS NOT NULL) AS earliest,
1638
- (SELECT MAX(started_at) FROM sessions WHERE started_at IS NOT NULL) AS latest`).get()}var rS=/^(127\.0\.0\.1|localhost|\[::1\])(:\d+)?$/i,oS=/^https?:\/\/(127\.0\.0\.1|localhost|\[::1\])(:\d+)?$/i;async function es(e,t){if((await Tt()).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 fn=new Map,lu=0,iu=0,du=null,iS=6e4;function aS(){lu+=1;let e=Date.now();e-iu<iS||(iu=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 cS(){du=new Date().toISOString()}function lS(){return{silentTerminalRejections:lu,lastTerminalSyncAt:du}}function dS(e){let t=new Bb;if(t.use("*",tS({maxSize:1*1024*1024})),t.use("*",async(i,l)=>{let p=i.req.raw.headers.get("host")??"";if(!rS.test(p))return i.text("Forbidden: invalid Host header",403);let m=i.req.raw.headers.get("origin");if(m&&!oS.test(m))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 m=l.req.raw.headers.get("x-recall-token")??"",_=!1;if(m.length===e.length)try{_=Gb(Buffer.from(m,"utf8"),i)}catch{_=!1}return _?p():(l.req.path.startsWith("/api/terminal/")&&aS(),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:ru,uptimeSeconds:Math.round(process.uptime()),pipeline:lS()})),t.get("/api/stats",i=>i.json(ou())),t.get("/api/stats/session/:id",i=>{let l=kd(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=Ad(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(Nd(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 _=yd({limit:p});return i.json({mode:"background",started:_,alreadyRunning:!_&&wd(),limit:p,lastRun:Yr()})}let m=Td({limit:p});return i.json({mode:"sync",started:!1,alreadyRunning:!1,limit:p,result:m,lastRun:Yr()})}),t.get("/api/stats/health",i=>i.json(xd())),t.get("/api/stats/health/:projectId",i=>{let l=Number(i.req.param("projectId")),p=Vr(l);return p?i.json(p):i.json({error:"project not found"},404)}),t.get("/api/config/verification",i=>i.json({enabled:no()})),t.put("/api/config/verification",async i=>{let l=await i.req.json();return typeof l.enabled=="boolean"&&tu(l.enabled),i.json({enabled:no()})}),t.get("/api/sessions/:id/verification",i=>{let l=i.req.param("id"),p=zd(l);return i.json(p)}),t.get("/api/sessions/:id/share-stats",i=>{let l=i.req.param("id"),m=f().prepare(`SELECT tool_names, raw_json FROM messages
1639
- WHERE session_id = ? AND tool_names IS NOT NULL AND tool_names != ''`).all(l),_=m.length,E=new Set;for(let T of m){if(!/Read|Write|Edit/.test(T.tool_names))continue;let R=T.raw_json.match(/"(?:file_path|path)":\s*"([^"]+)"/g);if(R)for(let A of R){let N=A.match(/":\s*"([^"]+)"/);N&&E.add(N[1])}}return i.json({filesReferenced:E.size,toolCallCount:_})}),t.get("/api/sessions/:id/commits",async i=>{let l=i.req.param("id"),p=Qr(l);if(p.length>0||i.req.query("refresh")!=="1")return i.json({commits:p});let m=await Zr(l);return i.json({commits:Qr(l),status:m.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:mn(l)}):i.json({error:"invalid sha format"},400)}),t.get("/api/license/status",async i=>{let l=await Tt();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",m=p==="https://clauderecall.com/api/feedback",_=await Tt(),E=St(),T=m&&_.tier==="pro"&&E?E.license_jwt:null,R=(()=>{try{let x=_o(au(cu(import.meta.url)),"..","..","package.json");return JSON.parse(ro(x,"utf8")).version}catch{return"unknown"}})(),A=l,N={score:A.score,comment:A.comment??null,surface:"web",version:typeof A.version=="string"?A.version:R,os:typeof A.os=="string"?A.os:process.platform,trigger_kind:typeof A.trigger_kind=="string"?A.trigger_kind:"manual",license_jwt:T};try{let x=await fetch(p,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(N)}),v=await x.json().catch(()=>({}));return i.json(v,x.status)}catch(x){let v=x instanceof Error?x.message:"network error";return i.json({error:"upstream_unreachable",detail:v},502)}}),t.get("/api/discover/today",es,async i=>{try{return i.json(await vd())}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:Sr(),orphan_projects:Wc()})),t.get("/api/bug-synthesis",i=>{let l=i.req.query("scope"),p=i.req.query("target_id"),m=i.req.query("limit"),_=l==="cluster"||l==="project"?l:void 0,E=m?Math.max(1,Number(m)):50,T=Vc({scope:_,target_id:p??void 0,limit:E});return i.json({results:T})}),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=Zc(l);return i.json({counts:Array.from(p.entries()).map(([m,_])=>({target_id:m,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=Tr(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)?(Qc(l),i.json({ok:!0})):i.json({error:"invalid id"},400)});let s=j.object({name:j.string().min(1).max(100),description:j.string().max(500).nullable().optional()});t.post("/api/macro-repos",async i=>{let l=await i.req.json().catch(()=>null),p=s.safeParse(l);if(!p.success)return i.json({error:"invalid request body",details:p.error.format()},400);try{let m=qc({name:p.data.name,description:p.data.description??null});return i.json({macro_repo:m},201)}catch(m){let _=m instanceof Error?m.message:String(m);return _.includes("UNIQUE constraint")?i.json({error:`a macro repo named "${p.data.name}" already exists`},409):i.json({error:_},400)}});let n=j.object({name:j.string().min(1).max(100).optional(),description:j.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),m=n.safeParse(p);if(!m.success)return i.json({error:"invalid request body"},400);try{let _=Jc(l,m.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)?(Xc(l),i.json({ok:!0})):i.json({error:"invalid id"},400)});let r=j.object({project_id:j.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),m=r.safeParse(p);if(!m.success)return i.json({error:"invalid request body"},400);try{return Gc(l,m.data.project_id),i.json({macro_repo:it(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):(Yc(l,p),i.json({macro_repo:it(l)}))}),t.get("/api/projects",i=>{let l=f(),m=i.req.query("system")==="1"||i.req.query("system")==="true"?"":" 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]%'",_=l.prepare(`SELECT p.id, p.name, p.decoded_path,
1638
+ (SELECT MAX(started_at) FROM sessions WHERE started_at IS NOT NULL) AS latest`).get()}var rS=/^(127\.0\.0\.1|localhost|\[::1\])(:\d+)?$/i,oS=/^https?:\/\/(127\.0\.0\.1|localhost|\[::1\])(:\d+)?$/i;async function es(e,t){if((await Tt()).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 fn=new Map,lu=0,cu=0,du=null,iS=6e4;function aS(){lu+=1;let e=Date.now();e-cu<iS||(cu=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 cS(){du=new Date().toISOString()}function lS(){return{silentTerminalRejections:lu,lastTerminalSyncAt:du}}function dS(e){let t=new Bb;if(t.use("*",tS({maxSize:1*1024*1024})),t.use("*",async(i,l)=>{let p=i.req.raw.headers.get("host")??"";if(!rS.test(p))return i.text("Forbidden: invalid Host header",403);let m=i.req.raw.headers.get("origin");if(m&&!oS.test(m))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 m=l.req.raw.headers.get("x-recall-token")??"",_=!1;if(m.length===e.length)try{_=Gb(Buffer.from(m,"utf8"),i)}catch{_=!1}return _?p():(l.req.path.startsWith("/api/terminal/")&&aS(),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:iu,uptimeSeconds:Math.round(process.uptime()),pipeline:lS()})),t.get("/api/stats",i=>i.json(au())),t.get("/api/stats/session/:id",i=>{let l=Nd(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=xd(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(Od(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 _=Rd({limit:p});return i.json({mode:"background",started:_,alreadyRunning:!_&&kd(),limit:p,lastRun:zr()})}let m=wd({limit:p});return i.json({mode:"sync",started:!1,alreadyRunning:!1,limit:p,result:m,lastRun:zr()})}),t.get("/api/stats/health",i=>i.json(Ld())),t.get("/api/stats/health/:projectId",i=>{let l=Number(i.req.param("projectId")),p=Qr(l);return p?i.json(p):i.json({error:"project not found"},404)}),t.get("/api/config/verification",i=>i.json({enabled:oo()})),t.put("/api/config/verification",async i=>{let l=await i.req.json();return typeof l.enabled=="boolean"&&nu(l.enabled),i.json({enabled:oo()})}),t.get("/api/sessions/:id/verification",i=>{let l=i.req.param("id"),p=Zd(l);return i.json(p)}),t.get("/api/sessions/:id/share-stats",i=>{let l=i.req.param("id"),m=f().prepare(`SELECT tool_names, raw_json FROM messages
1639
+ WHERE session_id = ? AND tool_names IS NOT NULL AND tool_names != ''`).all(l),_=m.length,E=new Set;for(let T of m){if(!/Read|Write|Edit/.test(T.tool_names))continue;let R=T.raw_json.match(/"(?:file_path|path)":\s*"([^"]+)"/g);if(R)for(let A of R){let N=A.match(/":\s*"([^"]+)"/);N&&E.add(N[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 m=await eo(l);return i.json({commits:to(l),status:m.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:mn(l)}):i.json({error:"invalid sha format"},400)}),t.get("/api/license/status",async i=>{let l=await Tt();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",m=p==="https://clauderecall.com/api/feedback",_=await Tt(),E=St(),T=m&&_.tier==="pro"&&E?E.license_jwt:null,R=(()=>{try{let x=bn(fo(ho(import.meta.url)),"..","..","package.json");return JSON.parse(hn(x,"utf8")).version}catch{return"unknown"}})(),A=l,N={score:A.score,comment:A.comment??null,surface:"web",version:typeof A.version=="string"?A.version:R,os:typeof A.os=="string"?A.os:process.platform,trigger_kind:typeof A.trigger_kind=="string"?A.trigger_kind:"manual",license_jwt:T};try{let x=await fetch(p,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(N)}),v=await x.json().catch(()=>({}));return i.json(v,x.status)}catch(x){let v=x instanceof Error?x.message:"network error";return i.json({error:"upstream_unreachable",detail:v},502)}}),t.get("/api/discover/today",es,async i=>{try{return i.json(await Md())}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:yr(),orphan_projects:Jc()})),t.get("/api/bug-synthesis",i=>{let l=i.req.query("scope"),p=i.req.query("target_id"),m=i.req.query("limit"),_=l==="cluster"||l==="project"?l:void 0,E=m?Math.max(1,Number(m)):50,T=Qc({scope:_,target_id:p??void 0,limit:E});return i.json({results:T})}),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=el(l);return i.json({counts:Array.from(p.entries()).map(([m,_])=>({target_id:m,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=wr(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)?(tl(l),i.json({ok:!0})):i.json({error:"invalid id"},400)});let s=j.object({name:j.string().min(1).max(100),description:j.string().max(500).nullable().optional()});t.post("/api/macro-repos",async i=>{let l=await i.req.json().catch(()=>null),p=s.safeParse(l);if(!p.success)return i.json({error:"invalid request body",details:p.error.format()},400);try{let m=Xc({name:p.data.name,description:p.data.description??null});return i.json({macro_repo:m},201)}catch(m){let _=m instanceof Error?m.message:String(m);return _.includes("UNIQUE constraint")?i.json({error:`a macro repo named "${p.data.name}" already exists`},409):i.json({error:_},400)}});let n=j.object({name:j.string().min(1).max(100).optional(),description:j.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),m=n.safeParse(p);if(!m.success)return i.json({error:"invalid request body"},400);try{let _=Gc(l,m.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)?(Yc(l),i.json({ok:!0})):i.json({error:"invalid id"},400)});let r=j.object({project_id:j.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),m=r.safeParse(p);if(!m.success)return i.json({error:"invalid request body"},400);try{return Kc(l,m.data.project_id),i.json({macro_repo:it(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):(zc(l,p),i.json({macro_repo:it(l)}))}),t.get("/api/projects",i=>{let l=f(),m=i.req.query("system")==="1"||i.req.query("system")==="true"?"":" 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]%'",_=l.prepare(`SELECT p.id, p.name, p.decoded_path,
1640
1640
  COUNT(CASE WHEN s.id IS NOT NULL${m} THEN 1 END) AS session_count,
1641
1641
  COALESCE(SUM(CASE WHEN s.id IS NOT NULL${m} THEN s.message_count ELSE 0 END), 0) AS message_count,
1642
1642
  MAX(COALESCE(s.ended_at, s.started_at)) AS latest
@@ -1667,7 +1667,7 @@ ${o}
1667
1667
  FROM sessions s
1668
1668
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1669
1669
  LEFT JOIN projects p ON p.id = s.project_id
1670
- WHERE s.id IN (${F})`).all(...O);for(let V of Q){let W=V.first_user_message?V.first_user_message.slice(0,80):null,G=V.alias??V.auto_title??W??V.id.slice(0,8);v.set(V.id,{title:G,project:V.project})}}let C=N.map(O=>{let F=v.get(O.source_session_id),U=v.get(O.target_session_id);return{...O,source_title:F?.title??O.source_session_id.slice(0,8),source_project:F?.project??null,target_title:U?.title??O.target_session_id.slice(0,8),target_project:U?.project??null}});return i.json({suggestions:C})}catch(N){return i.json({error:N.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=Be(l);return p?i.json(p):i.json({error:`no output index for session ${l}`},404)});let d=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"),m=p!==void 0?Number(p):4e3;if(!Number.isFinite(m)||m<100)return i.json({error:"budget must be a number \u2265 100"},400);let _=i.req.query("scoring")??"hybrid";if(!d.has(_))return i.json({error:`invalid scoring: ${_}; valid: pagerank, embedding-rerank, hybrid`},400);let E=_,T=i.req.query("max_depth"),R=T!==void 0?Number(T):2;if(!Number.isFinite(R)||R<1)return i.json({error:"max_depth must be a number \u2265 1"},400);let A,N=i.req.query("edge_types");if(N){let F=N.split(",").map(U=>U.trim()).filter(Boolean);for(let U of F)if(!o.has(U))return i.json({error:`invalid edge_type: ${U}`},400);A=F}let x=i.req.query("include_wiki_links"),v=x===void 0?!0:!(x==="0"||x==="false"),C=i.req.query("include_suggestions"),O=C==="1"||C==="true";try{let F=Os(l,{budget:m,scoring:E,maxDepth:R,edgeTypes:A,includeWikiLinks:v,includeSuggestions:O});return i.json(F)}catch(F){let U=F instanceof Error?F.message:"unknown error",Q=/not found/.test(U)?404:500;return i.json({error:U},Q)}}),t.get("/api/bug-patterns",i=>{let l=i.req.query("min_count"),p=i.req.query("status"),m=i.req.query("project")??void 0,_=i.req.query("limit"),E=i.req.query("offset"),T=l?Number(l):void 0;if(T!==void 0&&(!Number.isFinite(T)||T<1))return i.json({error:"min_count must be a positive integer"},400);let R;if(p==="open")R=!1;else if(p==="resolved")R=!0;else if(p&&p!=="all")return i.json({error:`invalid status: ${p}; valid: open, resolved, all`},400);let A=_?Number(_):void 0;if(A!==void 0&&(!Number.isFinite(A)||A<1))return i.json({error:"invalid limit"},400);let N=E?Number(E):void 0;if(N!==void 0&&(!Number.isFinite(N)||N<0))return i.json({error:"invalid offset"},400);try{let x=Fa({minOccurrenceCount:T,hasResolved:R,project:m,limit:A,offset:N});return i.json(x)}catch(x){return i.json({error:x.message},400)}}),t.get("/api/bug-patterns/setup-status",i=>{let l=f(),m=l.prepare(`SELECT p.name AS project,
1670
+ WHERE s.id IN (${F})`).all(...O);for(let V of Q){let W=V.first_user_message?V.first_user_message.slice(0,80):null,G=V.alias??V.auto_title??W??V.id.slice(0,8);v.set(V.id,{title:G,project:V.project})}}let C=N.map(O=>{let F=v.get(O.source_session_id),U=v.get(O.target_session_id);return{...O,source_title:F?.title??O.source_session_id.slice(0,8),source_project:F?.project??null,target_title:U?.title??O.target_session_id.slice(0,8),target_project:U?.project??null}});return i.json({suggestions:C})}catch(N){return i.json({error:N.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=Be(l);return p?i.json(p):i.json({error:`no output index for session ${l}`},404)});let d=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"),m=p!==void 0?Number(p):4e3;if(!Number.isFinite(m)||m<100)return i.json({error:"budget must be a number \u2265 100"},400);let _=i.req.query("scoring")??"hybrid";if(!d.has(_))return i.json({error:`invalid scoring: ${_}; valid: pagerank, embedding-rerank, hybrid`},400);let E=_,T=i.req.query("max_depth"),R=T!==void 0?Number(T):2;if(!Number.isFinite(R)||R<1)return i.json({error:"max_depth must be a number \u2265 1"},400);let A,N=i.req.query("edge_types");if(N){let F=N.split(",").map(U=>U.trim()).filter(Boolean);for(let U of F)if(!o.has(U))return i.json({error:`invalid edge_type: ${U}`},400);A=F}let x=i.req.query("include_wiki_links"),v=x===void 0?!0:!(x==="0"||x==="false"),C=i.req.query("include_suggestions"),O=C==="1"||C==="true";try{let F=Os(l,{budget:m,scoring:E,maxDepth:R,edgeTypes:A,includeWikiLinks:v,includeSuggestions:O});return i.json(F)}catch(F){let U=F instanceof Error?F.message:"unknown error",Q=/not found/.test(U)?404:500;return i.json({error:U},Q)}}),t.get("/api/bug-patterns",i=>{let l=i.req.query("min_count"),p=i.req.query("status"),m=i.req.query("project")??void 0,_=i.req.query("limit"),E=i.req.query("offset"),T=l?Number(l):void 0;if(T!==void 0&&(!Number.isFinite(T)||T<1))return i.json({error:"min_count must be a positive integer"},400);let R;if(p==="open")R=!1;else if(p==="resolved")R=!0;else if(p&&p!=="all")return i.json({error:`invalid status: ${p}; valid: open, resolved, all`},400);let A=_?Number(_):void 0;if(A!==void 0&&(!Number.isFinite(A)||A<1))return i.json({error:"invalid limit"},400);let N=E?Number(E):void 0;if(N!==void 0&&(!Number.isFinite(N)||N<0))return i.json({error:"invalid offset"},400);try{let x=Ua({minOccurrenceCount:T,hasResolved:R,project:m,limit:A,offset:N});return i.json(x)}catch(x){return i.json({error:x.message},400)}}),t.get("/api/bug-patterns/setup-status",i=>{let l=f(),m=l.prepare(`SELECT p.name AS project,
1671
1671
  COUNT(s.id) AS total_sessions,
1672
1672
  SUM(CASE WHEN oi.session_id IS NOT NULL THEN 1 ELSE 0 END) AS extracted_sessions,
1673
1673
  MAX(oi.extracted_at) AS last_extracted_at
@@ -1675,20 +1675,20 @@ ${o}
1675
1675
  LEFT JOIN sessions s ON s.project_id = p.id
1676
1676
  LEFT JOIN session_output_index oi ON oi.session_id = s.id
1677
1677
  GROUP BY p.id
1678
- ORDER BY total_sessions DESC`).all().map(T=>({project:T.project,total_sessions:T.total_sessions??0,extracted_sessions:T.extracted_sessions??0,remaining_sessions:(T.total_sessions??0)-(T.extracted_sessions??0),last_extracted_at:T.last_extracted_at})),_=m.reduce((T,R)=>(T.total_sessions+=R.total_sessions,T.extracted_sessions+=R.extracted_sessions,T.remaining_sessions+=R.remaining_sessions,T),{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:m,totals:{..._,cluster_count:E.n}})});let u=j.object({project:j.string().min(1),model:j.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional(),limit:j.number().int().positive().optional(),force:j.boolean().optional()});t.post("/api/extract-outputs/preflight",async i=>{let l=ye(i);if(l)return l;let p=wn();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 m=await i.req.json().catch(()=>null),_=u.safeParse(m);if(!_.success)return i.json({error:"invalid request body",details:_.error.format()},400);let E={project:_.data.project,model:_.data.model??We,limit:_.data.limit??200,force:_.data.force??!1},T=Nr();if(E.limit>T.sessionCeiling)return ee({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 ${T.sessionCeiling}`}),i.json({error:`requested limit ${E.limit} exceeds session ceiling ${T.sessionCeiling}. Lower the limit or edit launcher.sessionCeiling in ~/.recall/config.json.`},400);let R=Bt(E.project);if(!R)return i.json({error:`project "${E.project}" not found`},404);let N=rt({projectId:R.id,limit:E.limit,force:E.force}).eligible.length,x=xr(N),v=Ce(N,E.model),C=at(),O=x.estimated_input_tokens_max+x.estimated_output_tokens_max>C.remaining_tokens_24h;if(ee({kind:"preflight",job_id:null,project:E.project,model:E.model,limit:E.limit,origin:i.req.header("origin")??null,sessions_eligible:N}),N===0)return i.json({eligible_session_count:0,...x,plan_window_estimate:v,budget:C,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:U}=wr(E);return i.json({preflight_token:F,expires_at:new Date(U).toISOString(),eligible_session_count:N,...x,plan_window_estimate:v,budget:C,would_exceed_budget:O})});let g=j.object({preflight_token:j.string().length(64)});t.post("/api/extract-outputs/run",async i=>{let l=ye(i);if(l)return l;let p=await i.req.json().catch(()=>null),m=g.safeParse(p);if(!m.success)return i.json({error:"invalid request body"},400);let _=Rr(m.data.preflight_token);if(!_)return ee({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=at(),R=(()=>{let v=Bt(_.project);return v?rt({projectId:v.id,limit:_.limit,force:_.force}):null})()?.eligible.length??0,A=xr(R),N=A.estimated_input_tokens_max+A.estimated_output_tokens_max;if(N>E.remaining_tokens_24h)return ee({kind:"run-rejected",job_id:null,project:_.project,model:_.model,limit:_.limit,origin:i.req.header("origin")??null,reason:`projected spend ${N} 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:N},429);let x=ll({project:_.project,model:_.model,limit:_.limit,force:_.force,origin:i.req.header("origin")??null});return"error"in x?i.json({error:x.error},400):i.json({jobId:x.jobId,reused:x.reused},x.reused?409:200)}),t.get("/api/extract-outputs/jobs/:jobId/stream",i=>{let l=i.req.param("jobId");if(!Cr(l))return i.json({error:"job not found"},404);let m=Number(i.req.header("Last-Event-ID")??0);return Me(i,async _=>{let E=!1,T=setInterval(()=>{E||_.writeSSE({event:"heartbeat",data:""}).catch(()=>{E=!0})},15e3);try{for await(let R of dl(l,m))if(E||(await _.writeSSE({id:String(R.id),event:R.kind,data:JSON.stringify(R.data)}),R.kind==="done"))break}finally{E=!0,clearInterval(T)}})}),t.get("/api/extract-outputs/jobs/:jobId",i=>{let l=Cr(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=ye(i);return l||(ul(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(at()));let h=j.object({scope:j.enum(["cluster","project"]),target_id:j.string().min(1),mode:j.enum(["synopsis","priorities","root_cause"]),model:j.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional()});t.post("/api/bug-patterns/synthesize/preflight",async i=>{{let U=wn();if(U>0&&U<1*1024**3)return i.json({error:"insufficient-disk-space",message:`${(U/1024**3).toFixed(2)} GB free \u2014 bug synthesis needs at least 1 GB headroom. Free up disk and retry.`,freeBytes:U},507)}let l=ye(i);if(l)return l;let p=await i.req.json().catch(()=>null),m=h.safeParse(p);if(!m.success)return i.json({error:"invalid request body",details:m.error.format()},400);let _={scope:m.data.scope,target_id:m.data.target_id,mode:m.data.mode,model:m.data.model??pl},E=Js(_);if(!E)return ee({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 T=Or({scope:_.scope,mode:_.mode,member_session_count:E.context_summary.session_count,cluster_count:E.context_summary.cluster_count}),R=T.estimated_input_tokens_max+T.estimated_output_tokens_max,A=cl(R),N=Ce(A,_.model),x=at(),C=T.estimated_input_tokens_max+T.estimated_output_tokens_max>x.remaining_tokens_24h;ee({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:O,expiresAt:F}=wr({project:_.target_id,model:_.model,limit:1,force:!1});return fn.set(O,_),setTimeout(()=>fn.delete(O),9e4).unref?.(),i.json({preflight_token:O,expires_at:new Date(F).toISOString(),estimated_input_tokens_max:T.estimated_input_tokens_max,estimated_output_tokens_max:T.estimated_output_tokens_max,plan_window_estimate:N,budget:x,would_exceed_budget:C,context_summary:E.context_summary})});let b=j.object({preflight_token:j.string().length(64)});t.post("/api/bug-patterns/synthesize/run",async i=>{let l=ye(i);if(l)return l;let p=await i.req.json().catch(()=>null),m=b.safeParse(p);if(!m.success)return i.json({error:"invalid request body"},400);let _=Rr(m.data.preflight_token),E=fn.get(m.data.preflight_token)??null;if(fn.delete(m.data.preflight_token),!E||!_)return ee({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 T=at(),R=Js(E);if(!R)return i.json({error:E.scope==="cluster"?`cluster "${E.target_id}" no longer exists`:`project "${E.target_id}" has no findings`},404);let A=Or({scope:E.scope,mode:E.mode,member_session_count:R.context_summary.session_count,cluster_count:R.context_summary.cluster_count}),N=A.estimated_input_tokens_max+A.estimated_output_tokens_max;if(N>T.remaining_tokens_24h)return ee({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 ${N} exceeds remaining 24h budget ${T.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:T,projected_spend:N},429);let x=fl({intent:E,origin:i.req.header("origin")??null});return"error"in x?i.json({error:x.error},400):i.json({jobId:x.jobId,reused:x.reused},x.reused?409:200)}),t.get("/api/bug-patterns/synthesize/jobs/:jobId/stream",i=>{let l=i.req.param("jobId");if(!Ir(l))return i.json({error:"job not found"},404);let m=Number(i.req.header("Last-Event-ID")??0);return Me(i,async _=>{let E=!1,T=setInterval(()=>{E||_.writeSSE({event:"heartbeat",data:""}).catch(()=>{E=!0})},15e3);try{for await(let R of hl(l,m))if(E||(await _.writeSSE({id:String(R.id),event:R.kind,data:JSON.stringify(R.data)}),R.kind==="done"))break}finally{E=!0,clearInterval(T)}})}),t.get("/api/bug-patterns/synthesize/jobs/:jobId",i=>{let l=Ir(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=ye(i);return l||(El(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),m=f(),_=["oi.bug_signatures IS NOT NULL"],E=[];l&&(_.push("p.name = ?"),E.push(l));let R=m.prepare(`SELECT s.id AS session_id, p.name AS project, s.auto_title,
1678
+ ORDER BY total_sessions DESC`).all().map(T=>({project:T.project,total_sessions:T.total_sessions??0,extracted_sessions:T.extracted_sessions??0,remaining_sessions:(T.total_sessions??0)-(T.extracted_sessions??0),last_extracted_at:T.last_extracted_at})),_=m.reduce((T,R)=>(T.total_sessions+=R.total_sessions,T.extracted_sessions+=R.extracted_sessions,T.remaining_sessions+=R.remaining_sessions,T),{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:m,totals:{..._,cluster_count:E.n}})});let u=j.object({project:j.string().min(1),model:j.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional(),limit:j.number().int().positive().optional(),force:j.boolean().optional()});t.post("/api/extract-outputs/preflight",async i=>{let l=ye(i);if(l)return l;let p=kn();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 m=await i.req.json().catch(()=>null),_=u.safeParse(m);if(!_.success)return i.json({error:"invalid request body",details:_.error.format()},400);let E={project:_.data.project,model:_.data.model??We,limit:_.data.limit??200,force:_.data.force??!1},T=Or();if(E.limit>T.sessionCeiling)return ee({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 ${T.sessionCeiling}`}),i.json({error:`requested limit ${E.limit} exceeds session ceiling ${T.sessionCeiling}. Lower the limit or edit launcher.sessionCeiling in ~/.recall/config.json.`},400);let R=Bt(E.project);if(!R)return i.json({error:`project "${E.project}" not found`},404);let N=rt({projectId:R.id,limit:E.limit,force:E.force}).eligible.length,x=Lr(N),v=Ce(N,E.model),C=at(),O=x.estimated_input_tokens_max+x.estimated_output_tokens_max>C.remaining_tokens_24h;if(ee({kind:"preflight",job_id:null,project:E.project,model:E.model,limit:E.limit,origin:i.req.header("origin")??null,sessions_eligible:N}),N===0)return i.json({eligible_session_count:0,...x,plan_window_estimate:v,budget:C,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:U}=kr(E);return i.json({preflight_token:F,expires_at:new Date(U).toISOString(),eligible_session_count:N,...x,plan_window_estimate:v,budget:C,would_exceed_budget:O})});let g=j.object({preflight_token:j.string().length(64)});t.post("/api/extract-outputs/run",async i=>{let l=ye(i);if(l)return l;let p=await i.req.json().catch(()=>null),m=g.safeParse(p);if(!m.success)return i.json({error:"invalid request body"},400);let _=Ar(m.data.preflight_token);if(!_)return ee({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=at(),R=(()=>{let v=Bt(_.project);return v?rt({projectId:v.id,limit:_.limit,force:_.force}):null})()?.eligible.length??0,A=Lr(R),N=A.estimated_input_tokens_max+A.estimated_output_tokens_max;if(N>E.remaining_tokens_24h)return ee({kind:"run-rejected",job_id:null,project:_.project,model:_.model,limit:_.limit,origin:i.req.header("origin")??null,reason:`projected spend ${N} 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:N},429);let x=ul({project:_.project,model:_.model,limit:_.limit,force:_.force,origin:i.req.header("origin")??null});return"error"in x?i.json({error:x.error},400):i.json({jobId:x.jobId,reused:x.reused},x.reused?409:200)}),t.get("/api/extract-outputs/jobs/:jobId/stream",i=>{let l=i.req.param("jobId");if(!vr(l))return i.json({error:"job not found"},404);let m=Number(i.req.header("Last-Event-ID")??0);return Me(i,async _=>{let E=!1,T=setInterval(()=>{E||_.writeSSE({event:"heartbeat",data:""}).catch(()=>{E=!0})},15e3);try{for await(let R of pl(l,m))if(E||(await _.writeSSE({id:String(R.id),event:R.kind,data:JSON.stringify(R.data)}),R.kind==="done"))break}finally{E=!0,clearInterval(T)}})}),t.get("/api/extract-outputs/jobs/:jobId",i=>{let l=vr(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=ye(i);return l||(ml(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(at()));let h=j.object({scope:j.enum(["cluster","project"]),target_id:j.string().min(1),mode:j.enum(["synopsis","priorities","root_cause"]),model:j.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional()});t.post("/api/bug-patterns/synthesize/preflight",async i=>{{let U=kn();if(U>0&&U<1*1024**3)return i.json({error:"insufficient-disk-space",message:`${(U/1024**3).toFixed(2)} GB free \u2014 bug synthesis needs at least 1 GB headroom. Free up disk and retry.`,freeBytes:U},507)}let l=ye(i);if(l)return l;let p=await i.req.json().catch(()=>null),m=h.safeParse(p);if(!m.success)return i.json({error:"invalid request body",details:m.error.format()},400);let _={scope:m.data.scope,target_id:m.data.target_id,mode:m.data.mode,model:m.data.model??gl},E=Js(_);if(!E)return ee({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 T=Cr({scope:_.scope,mode:_.mode,member_session_count:E.context_summary.session_count,cluster_count:E.context_summary.cluster_count}),R=T.estimated_input_tokens_max+T.estimated_output_tokens_max,A=dl(R),N=Ce(A,_.model),x=at(),C=T.estimated_input_tokens_max+T.estimated_output_tokens_max>x.remaining_tokens_24h;ee({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:O,expiresAt:F}=kr({project:_.target_id,model:_.model,limit:1,force:!1});return fn.set(O,_),setTimeout(()=>fn.delete(O),9e4).unref?.(),i.json({preflight_token:O,expires_at:new Date(F).toISOString(),estimated_input_tokens_max:T.estimated_input_tokens_max,estimated_output_tokens_max:T.estimated_output_tokens_max,plan_window_estimate:N,budget:x,would_exceed_budget:C,context_summary:E.context_summary})});let b=j.object({preflight_token:j.string().length(64)});t.post("/api/bug-patterns/synthesize/run",async i=>{let l=ye(i);if(l)return l;let p=await i.req.json().catch(()=>null),m=b.safeParse(p);if(!m.success)return i.json({error:"invalid request body"},400);let _=Ar(m.data.preflight_token),E=fn.get(m.data.preflight_token)??null;if(fn.delete(m.data.preflight_token),!E||!_)return ee({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 T=at(),R=Js(E);if(!R)return i.json({error:E.scope==="cluster"?`cluster "${E.target_id}" no longer exists`:`project "${E.target_id}" has no findings`},404);let A=Cr({scope:E.scope,mode:E.mode,member_session_count:R.context_summary.session_count,cluster_count:R.context_summary.cluster_count}),N=A.estimated_input_tokens_max+A.estimated_output_tokens_max;if(N>T.remaining_tokens_24h)return ee({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 ${N} exceeds remaining 24h budget ${T.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:T,projected_spend:N},429);let x=El({intent:E,origin:i.req.header("origin")??null});return"error"in x?i.json({error:x.error},400):i.json({jobId:x.jobId,reused:x.reused},x.reused?409:200)}),t.get("/api/bug-patterns/synthesize/jobs/:jobId/stream",i=>{let l=i.req.param("jobId");if(!jr(l))return i.json({error:"job not found"},404);let m=Number(i.req.header("Last-Event-ID")??0);return Me(i,async _=>{let E=!1,T=setInterval(()=>{E||_.writeSSE({event:"heartbeat",data:""}).catch(()=>{E=!0})},15e3);try{for await(let R of bl(l,m))if(E||(await _.writeSSE({id:String(R.id),event:R.kind,data:JSON.stringify(R.data)}),R.kind==="done"))break}finally{E=!0,clearInterval(T)}})}),t.get("/api/bug-patterns/synthesize/jobs/:jobId",i=>{let l=jr(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=ye(i);return l||(Sl(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),m=f(),_=["oi.bug_signatures IS NOT NULL"],E=[];l&&(_.push("p.name = ?"),E.push(l));let R=m.prepare(`SELECT s.id AS session_id, p.name AS project, s.auto_title,
1679
1679
  s.started_at, oi.extracted_at, oi.bug_signatures
1680
1680
  FROM session_output_index oi
1681
1681
  JOIN sessions s ON s.id = oi.session_id
1682
1682
  JOIN projects p ON p.id = s.project_id
1683
1683
  WHERE ${_.join(" AND ")}
1684
1684
  ORDER BY oi.extracted_at DESC
1685
- LIMIT ?`).all(...E,p).map(C=>{let O=[];try{let F=JSON.parse(C.bug_signatures);Array.isArray(F)&&(O=F)}catch{O=[]}return{session_id:C.session_id,project:C.project,auto_title:C.auto_title,started_at:C.started_at,extracted_at:C.extracted_at,rawSignatures:O}}),A=R.flatMap(C=>C.rawSignatures.map(O=>O.message_hash).filter(O=>typeof O=="string")),N=Er(A),x=R.map(C=>({session_id:C.session_id,project:C.project,auto_title:C.auto_title,started_at:C.started_at,extracted_at:C.extracted_at,signatures:C.rawSignatures.map(O=>{let F=O.message_hash?N.get(O.message_hash)??null:null;return{...O,resolved:br(F),resolution:F}}),signature_count:C.rawSignatures.length})),v=x.reduce((C,O)=>(C.sessions_total+=1,O.signature_count>0?(C.sessions_with_findings+=1,C.total_findings+=O.signature_count):C.sessions_empty+=1,C),{sessions_total:0,sessions_with_findings:0,sessions_empty:0,total_findings:0});return i.json({sessions:x,totals:v})}),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(()=>({})),m=Bc({messageHash:l,resolvedInSessionId:p.resolved_in_session_id??null,fixSummary:p.fix_summary??null});return i.json({resolution:m})}),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):(Hc(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",m=f(),_=["oi.bug_signatures IS NOT NULL","oi.bug_signatures != '[]'"],E=[];l&&(_.push("p.name = ?"),E.push(l));let T=m.prepare(`SELECT s.id AS session_id, p.name AS project, s.auto_title,
1685
+ LIMIT ?`).all(...E,p).map(C=>{let O=[];try{let F=JSON.parse(C.bug_signatures);Array.isArray(F)&&(O=F)}catch{O=[]}return{session_id:C.session_id,project:C.project,auto_title:C.auto_title,started_at:C.started_at,extracted_at:C.extracted_at,rawSignatures:O}}),A=R.flatMap(C=>C.rawSignatures.map(O=>O.message_hash).filter(O=>typeof O=="string")),N=Sr(A),x=R.map(C=>({session_id:C.session_id,project:C.project,auto_title:C.auto_title,started_at:C.started_at,extracted_at:C.extracted_at,signatures:C.rawSignatures.map(O=>{let F=O.message_hash?N.get(O.message_hash)??null:null;return{...O,resolved:Tr(F),resolution:F}}),signature_count:C.rawSignatures.length})),v=x.reduce((C,O)=>(C.sessions_total+=1,O.signature_count>0?(C.sessions_with_findings+=1,C.total_findings+=O.signature_count):C.sessions_empty+=1,C),{sessions_total:0,sessions_with_findings:0,sessions_empty:0,total_findings:0});return i.json({sessions:x,totals:v})}),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(()=>({})),m=Wc({messageHash:l,resolvedInSessionId:p.resolved_in_session_id??null,fixSummary:p.fix_summary??null});return i.json({resolution:m})}),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):(qc(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",m=f(),_=["oi.bug_signatures IS NOT NULL","oi.bug_signatures != '[]'"],E=[];l&&(_.push("p.name = ?"),E.push(l));let T=m.prepare(`SELECT s.id AS session_id, p.name AS project, s.auto_title,
1686
1686
  s.started_at, oi.extracted_at, oi.bug_signatures
1687
1687
  FROM session_output_index oi
1688
1688
  JOIN sessions s ON s.id = oi.session_id
1689
1689
  JOIN projects p ON p.id = s.project_id
1690
1690
  WHERE ${_.join(" AND ")}
1691
- ORDER BY oi.extracted_at DESC`).all(...E),R=[];for(let W of T){let G=[];try{let K=JSON.parse(W.bug_signatures);Array.isArray(K)&&(G=K)}catch{continue}for(let K of G)R.push({sig:K,session_id:W.session_id,project:W.project,auto_title:W.auto_title})}let A=new Map;for(let W of R){let G=W.sig.message_hash??`nohash:${(W.sig.snippet??"").slice(0,64)}`,K=A.get(G);K?K.push(W):A.set(G,[W])}let N=Array.from(A.keys()).filter(W=>!W.startsWith("nohash:")),x=Er(N),v=[],C=new Map,O=[];for(let[W,G]of A){let K=G[0],P=K.sig.message_hash??null,q=P?x.get(P)??null:null,pe=br(q);if(!p&&pe)continue;let Ee=Array.from(new Set(G.map(z=>z.project))).sort(),bt=Array.from(new Set(G.map(z=>z.session_id))),ts={id:P??W,message_hash:P,error_type:K.sig.error_type??null,snippet:(K.sig.snippet??"").slice(0,200),file:K.sig.file??null,occurrence_count:G.length,projects:Ee,resolved:pe,fix_summary:q?.fix_summary??null,member_session_ids:bt};v.push(ts);for(let z of G)C.has(z.session_id)||C.set(z.session_id,{session_id:z.session_id,project:z.project,auto_title:z.auto_title}),O.push({cluster_id:ts.id,session_id:z.session_id})}let F=[],U=4,Q=new Map;function V(W){let G=Q.get(W)??0;return G>=U?!1:(Q.set(W,G+1),!0)}for(let W=0;W<v.length;W+=1)for(let G=W+1;G<v.length;G+=1){let K=v[W],P=v[G],q=null;K.error_type&&K.error_type!=="unknown"&&K.error_type===P.error_type?q="same_error_type":K.file&&P.file&&K.file===P.file&&(q="same_file"),q&&(!V(K.id)||!V(P.id)||F.push({a:K.id,b:P.id,reason:q}))}return i.json({clusters:v,sessions:Array.from(C.values()),member_edges:O,related_edges:F,totals:{cluster_count:v.length,singleton_count:v.filter(W=>W.occurrence_count===1).length,recurring_count:v.filter(W=>W.occurrence_count>1).length,session_count:C.size,resolved_count:v.filter(W=>W.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=Pa(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 m=p.resolved_in_session_id,_=p.fix_summary;if(typeof m!="string"||m.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,m,_);return i.json(E)}catch(E){let T=E instanceof Error?E.message:"unknown error",R=/not found/.test(T)?404:(/not a member/.test(T),400);return i.json({error:T},R)}}),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 m=p.member_session_ids;if(!Array.isArray(m)||m.length===0)return i.json({error:"member_session_ids must be a non-empty array of strings"},400);let _=[];for(let E of m){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=$a(l,_);return i.json(E)}catch(E){let T=E instanceof Error?E.message:"unknown error",R=/not found/.test(T)?404:(/cannot split|none of the supplied/.test(T),400);return i.json({error:T},R)}}),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,m=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 m!="string"||m.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===m)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(m))return i.json({error:`target session not found: ${m}`},404);let A=As({sourceSessionId:m,targetSessionId:p,linkType:"wiki_link"});if(A.length>0)return i.json({link:A[0]});try{let N=fa({source_session_id:p,target_session_id:m,link_type:"wiki_link",confidence:1,source:"manual",evidence:l.evidence??{created_via:"context_menu"},approved:!0});return i.json({link:N})}catch(N){return i.json({error:N.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 m=ha(p);return m.removed===0?i.json({error:`link ${p} not found`},404):i.json(m)}),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=_,T=Lt(l).filter(C=>C.link_type===E),R=ba(l,T);if(R.length===0)return i.json({links:[]});let A=R.map(C=>C.otherSessionId),N=A.map(()=>"?").join(","),x=p.prepare(`SELECT s.id,
1691
+ ORDER BY oi.extracted_at DESC`).all(...E),R=[];for(let W of T){let G=[];try{let K=JSON.parse(W.bug_signatures);Array.isArray(K)&&(G=K)}catch{continue}for(let K of G)R.push({sig:K,session_id:W.session_id,project:W.project,auto_title:W.auto_title})}let A=new Map;for(let W of R){let G=W.sig.message_hash??`nohash:${(W.sig.snippet??"").slice(0,64)}`,K=A.get(G);K?K.push(W):A.set(G,[W])}let N=Array.from(A.keys()).filter(W=>!W.startsWith("nohash:")),x=Sr(N),v=[],C=new Map,O=[];for(let[W,G]of A){let K=G[0],P=K.sig.message_hash??null,q=P?x.get(P)??null:null,pe=Tr(q);if(!p&&pe)continue;let Ee=Array.from(new Set(G.map(z=>z.project))).sort(),bt=Array.from(new Set(G.map(z=>z.session_id))),ts={id:P??W,message_hash:P,error_type:K.sig.error_type??null,snippet:(K.sig.snippet??"").slice(0,200),file:K.sig.file??null,occurrence_count:G.length,projects:Ee,resolved:pe,fix_summary:q?.fix_summary??null,member_session_ids:bt};v.push(ts);for(let z of G)C.has(z.session_id)||C.set(z.session_id,{session_id:z.session_id,project:z.project,auto_title:z.auto_title}),O.push({cluster_id:ts.id,session_id:z.session_id})}let F=[],U=4,Q=new Map;function V(W){let G=Q.get(W)??0;return G>=U?!1:(Q.set(W,G+1),!0)}for(let W=0;W<v.length;W+=1)for(let G=W+1;G<v.length;G+=1){let K=v[W],P=v[G],q=null;K.error_type&&K.error_type!=="unknown"&&K.error_type===P.error_type?q="same_error_type":K.file&&P.file&&K.file===P.file&&(q="same_file"),q&&(!V(K.id)||!V(P.id)||F.push({a:K.id,b:P.id,reason:q}))}return i.json({clusters:v,sessions:Array.from(C.values()),member_edges:O,related_edges:F,totals:{cluster_count:v.length,singleton_count:v.filter(W=>W.occurrence_count===1).length,recurring_count:v.filter(W=>W.occurrence_count>1).length,session_count:C.size,resolved_count:v.filter(W=>W.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=$a(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 m=p.resolved_in_session_id,_=p.fix_summary;if(typeof m!="string"||m.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=Ba(l,m,_);return i.json(E)}catch(E){let T=E instanceof Error?E.message:"unknown error",R=/not found/.test(T)?404:(/not a member/.test(T),400);return i.json({error:T},R)}}),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 m=p.member_session_ids;if(!Array.isArray(m)||m.length===0)return i.json({error:"member_session_ids must be a non-empty array of strings"},400);let _=[];for(let E of m){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=Ha(l,_);return i.json(E)}catch(E){let T=E instanceof Error?E.message:"unknown error",R=/not found/.test(T)?404:(/cannot split|none of the supplied/.test(T),400);return i.json({error:T},R)}}),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,m=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 m!="string"||m.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===m)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(m))return i.json({error:`target session not found: ${m}`},404);let A=As({sourceSessionId:m,targetSessionId:p,linkType:"wiki_link"});if(A.length>0)return i.json({link:A[0]});try{let N=Ea({source_session_id:p,target_session_id:m,link_type:"wiki_link",confidence:1,source:"manual",evidence:l.evidence??{created_via:"context_menu"},approved:!0});return i.json({link:N})}catch(N){return i.json({error:N.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 m=ba(p);return m.removed===0?i.json({error:`link ${p} not found`},404):i.json(m)}),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=_,T=Lt(l).filter(C=>C.link_type===E),R=Ta(l,T);if(R.length===0)return i.json({links:[]});let A=R.map(C=>C.otherSessionId),N=A.map(()=>"?").join(","),x=p.prepare(`SELECT s.id,
1692
1692
  NULLIF(sa.alias, '') AS alias,
1693
1693
  s.auto_title,
1694
1694
  s.first_user_message,
@@ -1696,7 +1696,7 @@ ${o}
1696
1696
  FROM sessions s
1697
1697
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1698
1698
  LEFT JOIN projects p ON p.id = s.project_id
1699
- WHERE s.id IN (${N})`).all(...A),v=new Map(x.map(C=>[C.id,C]));return i.json({links:R.map(C=>{let O=v.get(C.otherSessionId),F=O?.alias?.trim()||O?.auto_title?.trim()||(O?.first_user_message?O.first_user_message.slice(0,80):"")||C.otherSessionId.slice(0,8);return{linkId:C.linkId,otherSessionId:C.otherSessionId,direction:C.direction,updatedAt:C.updatedAt,title:F,project:O?.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 m=await i.req.json().catch(()=>null);if(!m||typeof m.status!="string")return i.json({error:"status required (approved|rejected)"},400);if(m.status!=="approved"&&m.status!=="rejected")return i.json({error:`invalid status: ${m.status}`},400);try{let _=zn(p,m.status);return i.json(_)}catch(_){let E=_.message,T=/already decided/.test(E)?409:/not found/.test(E)?404:400;return i.json({error:E},T)}}),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 m=l.status,_=0,E=0,T=[];for(let R of p){let A=Number(R);if(!Number.isInteger(A)||A<=0){T.push({id:Number.isFinite(Number(R))?Number(R):-1,error:"invalid id"});continue}try{zn(A,m),_+=1}catch(N){let x=N.message;/already decided/.test(x)?E+=1:T.push({id:A,error:x})}}return i.json({decided:_,skipped:E,errors:T})}),t.get("/api/sessions",i=>{let l=f(),p=i.req.query("project"),m=i.req.query("since"),_=i.req.query("until"),E=i.req.queries("tag")??[],T=i.req.query("collection"),R=Math.max(1,Math.min(500,Number(i.req.query("limit")??100))),A=i.req.query("system")==="1"||i.req.query("system")==="true",N={limit:R},x="s.message_count > 2";if(A||(x+=" 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]%'"),p&&(x+=" AND (p.name LIKE @proj ESCAPE '\\' OR p.decoded_path LIKE @proj ESCAPE '\\')",N.proj=`%${Qt(p)}%`),m&&(x+=" AND s.started_at >= @since",N.since=m),_&&(x+=" AND s.started_at <= @until",/^\d{4}-\d{2}-\d{2}$/.test(_)?N.until=`${_}T23:59:59.999Z`:N.until=_),E.length>0&&E.map(F=>De(F)).filter(Boolean).forEach((F,U)=>{x+=` AND s.id IN (SELECT session_id FROM session_tags WHERE tag = @tag_${U})`,N[`tag_${U}`]=F}),T){let O=Cn(T);if(O.length===0)return i.json([]);let F=O.map((U,Q)=>`@col_${Q}`).join(",");x+=` AND s.id IN (SELECT session_id FROM collection_sessions WHERE collection_id IN (${F}))`,O.forEach((U,Q)=>{N[`col_${Q}`]=U})}let C=l.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
1699
+ WHERE s.id IN (${N})`).all(...A),v=new Map(x.map(C=>[C.id,C]));return i.json({links:R.map(C=>{let O=v.get(C.otherSessionId),F=O?.alias?.trim()||O?.auto_title?.trim()||(O?.first_user_message?O.first_user_message.slice(0,80):"")||C.otherSessionId.slice(0,8);return{linkId:C.linkId,otherSessionId:C.otherSessionId,direction:C.direction,updatedAt:C.updatedAt,title:F,project:O?.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 m=await i.req.json().catch(()=>null);if(!m||typeof m.status!="string")return i.json({error:"status required (approved|rejected)"},400);if(m.status!=="approved"&&m.status!=="rejected")return i.json({error:`invalid status: ${m.status}`},400);try{let _=Zn(p,m.status);return i.json(_)}catch(_){let E=_.message,T=/already decided/.test(E)?409:/not found/.test(E)?404:400;return i.json({error:E},T)}}),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 m=l.status,_=0,E=0,T=[];for(let R of p){let A=Number(R);if(!Number.isInteger(A)||A<=0){T.push({id:Number.isFinite(Number(R))?Number(R):-1,error:"invalid id"});continue}try{Zn(A,m),_+=1}catch(N){let x=N.message;/already decided/.test(x)?E+=1:T.push({id:A,error:x})}}return i.json({decided:_,skipped:E,errors:T})}),t.get("/api/sessions",i=>{let l=f(),p=i.req.query("project"),m=i.req.query("since"),_=i.req.query("until"),E=i.req.queries("tag")??[],T=i.req.query("collection"),R=Math.max(1,Math.min(500,Number(i.req.query("limit")??100))),A=i.req.query("system")==="1"||i.req.query("system")==="true",N={limit:R},x="s.message_count > 2";if(A||(x+=" 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]%'"),p&&(x+=" AND (p.name LIKE @proj ESCAPE '\\' OR p.decoded_path LIKE @proj ESCAPE '\\')",N.proj=`%${Qt(p)}%`),m&&(x+=" AND s.started_at >= @since",N.since=m),_&&(x+=" AND s.started_at <= @until",/^\d{4}-\d{2}-\d{2}$/.test(_)?N.until=`${_}T23:59:59.999Z`:N.until=_),E.length>0&&E.map(F=>De(F)).filter(Boolean).forEach((F,U)=>{x+=` AND s.id IN (SELECT session_id FROM session_tags WHERE tag = @tag_${U})`,N[`tag_${U}`]=F}),T){let O=vn(T);if(O.length===0)return i.json([]);let F=O.map((U,Q)=>`@col_${Q}`).join(",");x+=` AND s.id IN (SELECT session_id FROM collection_sessions WHERE collection_id IN (${F}))`,O.forEach((U,Q)=>{N[`col_${Q}`]=U})}let C=l.prepare(`SELECT s.id, p.name AS project, s.started_at, s.ended_at,
1700
1700
  s.message_count, s.first_user_message, s.git_branch,
1701
1701
  s.auto_title, s.auto_title_source, s.verification_status,
1702
1702
  NULLIF(sa.alias, '') AS alias,
@@ -1724,7 +1724,7 @@ ${o}
1724
1724
  WHERE s.id = ?`).get(p);if(!m)return i.json({error:"not found"},404);let _=wt(p),E=I.getOrigin(p),T=E?{editor:E.editor,label:E.label}:null,R=m.alias==null?null:I.isSessionAutoLinked(p)?"auto":"manual",A=l.prepare(`SELECT uuid, type, role, timestamp, is_sidechain, content_text, tool_names
1725
1725
  FROM messages
1726
1726
  WHERE session_id = ?
1727
- ORDER BY COALESCE(timestamp, ''), rowid`).all(p);return i.json({session:{...m,tags:_,origin:T,alias_source:R},messages:A})}),t.get("/api/tags",i=>i.json(Xe())),t.get("/api/sessions/:id/tags",i=>i.json({tags:wt(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 m=Je(l,p.tag);return i.json(m)}catch(m){return i.json({error:m.message},400)}}),t.delete("/api/sessions/:id/tags/:tag",i=>{let l=i.req.param("id"),p=i.req.param("tag");return i.json(Zo(l,p))}),t.get("/api/config/auto-tag",i=>i.json(dr(Re()))),t.put("/api/config/auto-tag",async i=>{let l=await i.req.json().catch(()=>({})),p=Ps.partial().safeParse(l);if(!p.success)return i.json({error:"invalid config",issues:p.error.issues},400);let m=p.data;m.apiKey===void 0&&delete m.apiKey;let _=Rc(m);return _.autopilot&&_.enabled&&_.backend==="api"&&_.apiKey&&Qs(),i.json(dr(_))}),t.get("/api/onboarding",i=>{let p=f().prepare(`SELECT s.id,
1727
+ ORDER BY COALESCE(timestamp, ''), rowid`).all(p);return i.json({session:{...m,tags:_,origin:T,alias_source:R},messages:A})}),t.get("/api/tags",i=>i.json(Xe())),t.get("/api/sessions/:id/tags",i=>i.json({tags:wt(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 m=Je(l,p.tag);return i.json(m)}catch(m){return i.json({error:m.message},400)}}),t.delete("/api/sessions/:id/tags/:tag",i=>{let l=i.req.param("id"),p=i.req.param("tag");return i.json(ei(l,p))}),t.get("/api/config/auto-tag",i=>i.json(pr(Re()))),t.put("/api/config/auto-tag",async i=>{let l=await i.req.json().catch(()=>({})),p=Ps.partial().safeParse(l);if(!p.success)return i.json({error:"invalid config",issues:p.error.issues},400);let m=p.data;m.apiKey===void 0&&delete m.apiKey;let _=Ac(m);return _.autopilot&&_.enabled&&_.backend==="api"&&_.apiKey&&Qs(),i.json(pr(_))}),t.get("/api/onboarding",i=>{let p=f().prepare(`SELECT s.id,
1728
1728
  p.name AS project,
1729
1729
  s.started_at,
1730
1730
  s.ended_at,
@@ -1736,7 +1736,7 @@ ${o}
1736
1736
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1737
1737
  WHERE s.message_count > 2
1738
1738
  ORDER BY COALESCE(s.ended_at, s.started_at, '') DESC
1739
- LIMIT 1`).get();return i.json({state:tn(),mostRecentSession:p??null})}),t.put("/api/onboarding",async i=>{let l=await i.req.json().catch(()=>({})),p=en.partial().safeParse(l);return p.success?i.json(od(p.data)):i.json({error:"invalid onboarding state",issues:p.error.issues},400)}),t.post("/api/onboarding/reset",i=>i.json(id())),t.get("/api/config/mcp-install",i=>i.json({...Ie(),claudeCliAvailable:oe()})),t.post("/api/config/mcp-install",i=>i.json({...Zl(),claudeCliAvailable:oe()})),t.delete("/api/config/mcp-install",i=>i.json({...Ql(),claudeCliAvailable:oe()}));let S=j.object({scope:j.object({untaggedOnly:j.boolean().optional(),project:j.string().optional(),collectionId:j.string().optional(),sessionIds:j.array(j.string()).optional(),limit:j.number().int().min(1).max(500).optional()}).default({}),model:j.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional(),scanId:j.string().min(1).max(100).optional()});t.post("/api/tags/scan/claude-cli",async i=>{if(co)return i.json({error:"a scan is already running"},409);if(!oe())return i.json({error:"claude CLI not found on PATH. Install Claude Code locally, then reload."},400);if(!Ie().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(()=>({})),m=S.safeParse(p);if(!m.success)return i.json({error:"invalid scope",issues:m.error.issues},400);let _=m.data.scope,E=Re(),T=m.data.model??E.model,R=f(),A=()=>R.prepare("SELECT COUNT(*) AS n FROM session_tags").get().n,N=A();co=!0;let x;try{let v=m.data.scanId;x=await On(_,{model:T,scanId:v});let C=A(),O=Math.max(0,C-N);return v&&os(v,{type:"done",result:{success:x.success,exitCode:x.exitCode,tagsAdded:O}}),i.json({success:x.success,exitCode:x.exitCode,tagsAdded:O,model:T,stdout:qe(x.stdout.slice(0,2e3)).redacted,stderrTail:qe(x.stderr.slice(-2e3)).redacted})}finally{co=!1}}),t.get("/api/claude-cli/scan/:scanId/progress",i=>{let l=i.req.param("scanId");return Me(i,async p=>{let m=[],_={resolve:()=>{}},E=new Promise(N=>{_.resolve=N}),T=ti(l,N=>{m.push(N);let x=_.resolve;E=new Promise(v=>{_.resolve=v}),x()}),R=!1,A=setInterval(()=>{R||p.writeSSE({event:"heartbeat",data:""}).catch(()=>{R=!0})},15e3);try{for(;!R;){m.length===0&&await E;let N=m.shift();if(N&&(await p.writeSSE({event:N.type,data:JSON.stringify(N)}),N.type==="done"))break}}finally{R=!0,clearInterval(A),T()}})}),t.get("/api/prompts",i=>i.json({prompts:An.map(l=>({name:l.name,title:l.title,description:l.description})),claudeCliAvailable:oe()})),t.post("/api/prompts/run",async i=>{if(!oe())return i.json({error:"claude CLI not found on PATH. Install Claude Code locally, then reload."},400);if(!Ie().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(()=>({})),_=j.object({name:j.string(),args:j.record(j.string(),j.unknown()).optional(),model:j.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=ei(_.data.name);if(!E)return i.json({error:`unknown prompt: ${_.data.name}`},404);let T=E.build(_.data.args??{}),R=Re(),A=_.data.model??R.model,N=await Fe(T,E.allowedTools,{model:A});return i.json({success:N.success,exitCode:N.exitCode,promptName:E.name,model:A,stdout:N.stdout,stderrTail:N.stderr.slice(-4e3)})}),t.get("/api/autopilot/status",i=>i.json(Vt())),t.get("/api/autopilot/events",i=>Me(i,async l=>{await l.writeSSE({event:"state",data:JSON.stringify(Vt())});let p=[],m=()=>{},_=new Promise(T=>m=T),E=Kl(T=>{p.push(T);let R=m;_=new Promise(A=>m=A),R()});try{for(;;){if(p.length===0){let R=new Promise(N=>setTimeout(()=>N("tick"),3e4));if(await Promise.race([_.then(()=>"event"),R])==="tick"){await l.writeSSE({event:"heartbeat",data:"1"});continue}}let T=p.shift();T&&await l.writeSSE({event:"state",data:JSON.stringify(T)})}}finally{E()}})),t.post("/api/autopilot/kick",i=>(Qs(),i.json({ok:!0,snapshot:Vt()})));let y=j.object({scope:j.object({untaggedOnly:j.boolean().optional(),project:j.string().optional(),collectionId:j.string().optional(),sessionIds:j.array(j.string()).optional(),limit:j.number().int().min(1).max(500).optional()}).default({})});t.post("/api/tags/scan",async i=>{let l=Re();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(()=>({})),m=y.safeParse(p);if(!m.success)return i.json({error:"invalid scope",issues:m.error.issues},400);let _=Ye(m.data.scope);if(_.length===0)return i.json({error:"no sessions match scope"},400);let E=Hl(_.length);return Gl(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=Ys(i.req.param("id"));if(!l)return i.json({error:"scan not found"},404);let{controller:p,listeners:m,..._}=l;return i.json(_)}),t.get("/api/tags/scan/:id/events",i=>{let l=Ys(i.req.param("id"));return l?Me(i,async p=>{await p.writeSSE({event:"state",data:JSON.stringify({completed:l.completed,total:l.total,status:l.status})});for(let R of l.results)await p.writeSSE({event:"result",data:JSON.stringify(R)});let m=[],_={resolve:()=>{}},E=new Promise(R=>{_.resolve=R}),T=Wl(l,R=>{m.push(R);let A=_.resolve;E=new Promise(N=>{_.resolve=N}),A()});try{for(;l.status==="running"||l.status==="pending";){m.length===0&&await E;let R=m.shift();if(R&&(await p.writeSSE({event:R.type,data:JSON.stringify(R)}),R.type==="done"||R.type==="status"&&(R.status==="cancelled"||R.status==="failed")))break}}finally{T()}}):i.json({error:"scan not found"},404)});let k=j.object({selection:j.array(j.object({sessionId:j.string(),tags:j.array(j.string()).min(1)}))});t.post("/api/tags/scan/:id/apply",async i=>{let l=Ys(i.req.param("id"));if(!l)return i.json({error:"scan not found"},404);let p=await i.req.json().catch(()=>({})),m=k.safeParse(p);if(!m.success)return i.json({error:"invalid selection"},400);let _=Yl(l,m.data.selection);return i.json(_)}),t.delete("/api/tags/scan/:id",i=>{let l=i.req.param("id");return ql(l),Jl(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 m=me(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,T=!1;if(E&&_?.started_at){let R=Date.parse(_.started_at),A=_.started_at,N=I.all().filter(x=>x.cwd&&x.cwd.replace(/\/+$/,"")===E&&yt({sessionStartedAt:A,terminalOpenedAt:x.opened_at??null}).allowed);if(Number.isFinite(R)&&N.length>0){let v=N.map(C=>({t:C,gap:R-Date.parse(C.opened_at??"")})).filter(C=>Number.isFinite(C.gap)).sort((C,O)=>C.gap-O.gap)[0];v&&(I.linkSession(l,v.t.shell_pid),T=!0)}}T||I.unlinkSession(l)}return i.json(m)}catch(m){return i.json({error:m.message},400)}}),t.delete("/api/sessions/:id/alias",i=>{let l=i.req.param("id");return ns(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:Se(l)})}),t.get("/api/config/auto-title",i=>i.json(He())),t.put("/api/config/auto-title",async i=>{let l=await i.req.json().catch(()=>({})),p=$s.partial().safeParse(l);return p.success?i.json(Lc(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=Te(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(!He().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 Qa(l);return de(l,E,"agent"),i.json(Te(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=Te(l);if(!p)return i.json({error:"session not found"},404);let m=p.auto_title_history;if(!m||m.length===0)return i.json({error:"no prior title to revert to",code:"no-history"},422);let _=m[m.length-1];return de(l,_.title,"agent"),i.json(Te(l))}),t.post("/api/sessions/:id/regenerate-title",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>({})),m=p.model??Bs;try{let _=await pr(l,{model:m,force:p.force===!0,budget:typeof p.budget=="number"?p.budget:void 0,signal:i.req.raw.signal}),E=Te(l),T=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:T})}catch(_){if(_ instanceof nt)return i.json({error:_.message,code:"no-context-available",session_id:_.sessionId},422);let E=_ instanceof Error?_.message:"unknown error",T=/not found|unknown/i.test(E)?404:500;return i.json({error:E,code:"regenerate-failed"},T)}}),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 m=l.quality_filter;if(!Array.isArray(m)||m.length===0)return i.json({error:"quality_filter (non-empty array) required"},400);let _=new Set(["low_signal","recursive_meta","programmatic"]),E=[];for(let O of m){if(typeof O!="string")return i.json({error:`invalid quality_filter entry: ${O}`},400);if(!_.has(O))return i.json({error:`quality_filter must be a subset of ${[..._].join(",")}; got ${O}`},400);E.push(O)}let T=typeof l.model=="string"&&l.model.length>0?l.model:Bs,R=typeof l.limit=="number"&&l.limit>0?Math.min(2e3,Math.floor(l.limit)):500,A=typeof l.budget=="number"&&l.budget>=100?Math.floor(l.budget):void 0,x=f().prepare(`SELECT s.id,
1739
+ LIMIT 1`).get();return i.json({state:tn(),mostRecentSession:p??null})}),t.put("/api/onboarding",async i=>{let l=await i.req.json().catch(()=>({})),p=en.partial().safeParse(l);return p.success?i.json(ad(p.data)):i.json({error:"invalid onboarding state",issues:p.error.issues},400)}),t.post("/api/onboarding/reset",i=>i.json(cd())),t.get("/api/config/mcp-install",i=>i.json({...Ie(),claudeCliAvailable:oe()})),t.post("/api/config/mcp-install",i=>i.json({...ed(),claudeCliAvailable:oe()})),t.delete("/api/config/mcp-install",i=>i.json({...td(),claudeCliAvailable:oe()}));let S=j.object({scope:j.object({untaggedOnly:j.boolean().optional(),project:j.string().optional(),collectionId:j.string().optional(),sessionIds:j.array(j.string()).optional(),limit:j.number().int().min(1).max(500).optional()}).default({}),model:j.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional(),scanId:j.string().min(1).max(100).optional()});t.post("/api/tags/scan/claude-cli",async i=>{if(lo)return i.json({error:"a scan is already running"},409);if(!oe())return i.json({error:"claude CLI not found on PATH. Install Claude Code locally, then reload."},400);if(!Ie().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(()=>({})),m=S.safeParse(p);if(!m.success)return i.json({error:"invalid scope",issues:m.error.issues},400);let _=m.data.scope,E=Re(),T=m.data.model??E.model,R=f(),A=()=>R.prepare("SELECT COUNT(*) AS n FROM session_tags").get().n,N=A();lo=!0;let x;try{let v=m.data.scanId;x=await Cn(_,{model:T,scanId:v});let C=A(),O=Math.max(0,C-N);return v&&os(v,{type:"done",result:{success:x.success,exitCode:x.exitCode,tagsAdded:O}}),i.json({success:x.success,exitCode:x.exitCode,tagsAdded:O,model:T,stdout:qe(x.stdout.slice(0,2e3)).redacted,stderrTail:qe(x.stderr.slice(-2e3)).redacted})}finally{lo=!1}}),t.get("/api/claude-cli/scan/:scanId/progress",i=>{let l=i.req.param("scanId");return Me(i,async p=>{let m=[],_={resolve:()=>{}},E=new Promise(N=>{_.resolve=N}),T=ni(l,N=>{m.push(N);let x=_.resolve;E=new Promise(v=>{_.resolve=v}),x()}),R=!1,A=setInterval(()=>{R||p.writeSSE({event:"heartbeat",data:""}).catch(()=>{R=!0})},15e3);try{for(;!R;){m.length===0&&await E;let N=m.shift();if(N&&(await p.writeSSE({event:N.type,data:JSON.stringify(N)}),N.type==="done"))break}}finally{R=!0,clearInterval(A),T()}})}),t.get("/api/prompts",i=>i.json({prompts:xn.map(l=>({name:l.name,title:l.title,description:l.description})),claudeCliAvailable:oe()})),t.post("/api/prompts/run",async i=>{if(!oe())return i.json({error:"claude CLI not found on PATH. Install Claude Code locally, then reload."},400);if(!Ie().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(()=>({})),_=j.object({name:j.string(),args:j.record(j.string(),j.unknown()).optional(),model:j.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=si(_.data.name);if(!E)return i.json({error:`unknown prompt: ${_.data.name}`},404);let T=E.build(_.data.args??{}),R=Re(),A=_.data.model??R.model,N=await Fe(T,E.allowedTools,{model:A});return i.json({success:N.success,exitCode:N.exitCode,promptName:E.name,model:A,stdout:N.stdout,stderrTail:N.stderr.slice(-4e3)})}),t.get("/api/autopilot/status",i=>i.json(Vt())),t.get("/api/autopilot/events",i=>Me(i,async l=>{await l.writeSSE({event:"state",data:JSON.stringify(Vt())});let p=[],m=()=>{},_=new Promise(T=>m=T),E=Vl(T=>{p.push(T);let R=m;_=new Promise(A=>m=A),R()});try{for(;;){if(p.length===0){let R=new Promise(N=>setTimeout(()=>N("tick"),3e4));if(await Promise.race([_.then(()=>"event"),R])==="tick"){await l.writeSSE({event:"heartbeat",data:"1"});continue}}let T=p.shift();T&&await l.writeSSE({event:"state",data:JSON.stringify(T)})}}finally{E()}})),t.post("/api/autopilot/kick",i=>(Qs(),i.json({ok:!0,snapshot:Vt()})));let y=j.object({scope:j.object({untaggedOnly:j.boolean().optional(),project:j.string().optional(),collectionId:j.string().optional(),sessionIds:j.array(j.string()).optional(),limit:j.number().int().min(1).max(500).optional()}).default({})});t.post("/api/tags/scan",async i=>{let l=Re();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(()=>({})),m=y.safeParse(p);if(!m.success)return i.json({error:"invalid scope",issues:m.error.issues},400);let _=Ye(m.data.scope);if(_.length===0)return i.json({error:"no sessions match scope"},400);let E=ql(_.length);return Kl(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=Ys(i.req.param("id"));if(!l)return i.json({error:"scan not found"},404);let{controller:p,listeners:m,..._}=l;return i.json(_)}),t.get("/api/tags/scan/:id/events",i=>{let l=Ys(i.req.param("id"));return l?Me(i,async p=>{await p.writeSSE({event:"state",data:JSON.stringify({completed:l.completed,total:l.total,status:l.status})});for(let R of l.results)await p.writeSSE({event:"result",data:JSON.stringify(R)});let m=[],_={resolve:()=>{}},E=new Promise(R=>{_.resolve=R}),T=Jl(l,R=>{m.push(R);let A=_.resolve;E=new Promise(N=>{_.resolve=N}),A()});try{for(;l.status==="running"||l.status==="pending";){m.length===0&&await E;let R=m.shift();if(R&&(await p.writeSSE({event:R.type,data:JSON.stringify(R)}),R.type==="done"||R.type==="status"&&(R.status==="cancelled"||R.status==="failed")))break}}finally{T()}}):i.json({error:"scan not found"},404)});let k=j.object({selection:j.array(j.object({sessionId:j.string(),tags:j.array(j.string()).min(1)}))});t.post("/api/tags/scan/:id/apply",async i=>{let l=Ys(i.req.param("id"));if(!l)return i.json({error:"scan not found"},404);let p=await i.req.json().catch(()=>({})),m=k.safeParse(p);if(!m.success)return i.json({error:"invalid selection"},400);let _=zl(l,m.data.selection);return i.json(_)}),t.delete("/api/tags/scan/:id",i=>{let l=i.req.param("id");return Xl(l),Gl(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 m=me(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,T=!1;if(E&&_?.started_at){let R=Date.parse(_.started_at),A=_.started_at,N=I.all().filter(x=>x.cwd&&x.cwd.replace(/\/+$/,"")===E&&yt({sessionStartedAt:A,terminalOpenedAt:x.opened_at??null}).allowed);if(Number.isFinite(R)&&N.length>0){let v=N.map(C=>({t:C,gap:R-Date.parse(C.opened_at??"")})).filter(C=>Number.isFinite(C.gap)).sort((C,O)=>C.gap-O.gap)[0];v&&(I.linkSession(l,v.t.shell_pid),T=!0)}}T||I.unlinkSession(l)}return i.json(m)}catch(m){return i.json({error:m.message},400)}}),t.delete("/api/sessions/:id/alias",i=>{let l=i.req.param("id");return ns(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:Se(l)})}),t.get("/api/config/auto-title",i=>i.json(He())),t.put("/api/config/auto-title",async i=>{let l=await i.req.json().catch(()=>({})),p=$s.partial().safeParse(l);return p.success?i.json(Ic(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=Te(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(!He().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 tc(l);return de(l,E,"agent"),i.json(Te(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=Te(l);if(!p)return i.json({error:"session not found"},404);let m=p.auto_title_history;if(!m||m.length===0)return i.json({error:"no prior title to revert to",code:"no-history"},422);let _=m[m.length-1];return de(l,_.title,"agent"),i.json(Te(l))}),t.post("/api/sessions/:id/regenerate-title",async i=>{let l=i.req.param("id"),p=await i.req.json().catch(()=>({})),m=p.model??Bs;try{let _=await gr(l,{model:m,force:p.force===!0,budget:typeof p.budget=="number"?p.budget:void 0,signal:i.req.raw.signal}),E=Te(l),T=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:T})}catch(_){if(_ instanceof nt)return i.json({error:_.message,code:"no-context-available",session_id:_.sessionId},422);let E=_ instanceof Error?_.message:"unknown error",T=/not found|unknown/i.test(E)?404:500;return i.json({error:E,code:"regenerate-failed"},T)}}),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 m=l.quality_filter;if(!Array.isArray(m)||m.length===0)return i.json({error:"quality_filter (non-empty array) required"},400);let _=new Set(["low_signal","recursive_meta","programmatic"]),E=[];for(let O of m){if(typeof O!="string")return i.json({error:`invalid quality_filter entry: ${O}`},400);if(!_.has(O))return i.json({error:`quality_filter must be a subset of ${[..._].join(",")}; got ${O}`},400);E.push(O)}let T=typeof l.model=="string"&&l.model.length>0?l.model:Bs,R=typeof l.limit=="number"&&l.limit>0?Math.min(2e3,Math.floor(l.limit)):500,A=typeof l.budget=="number"&&l.budget>=100?Math.floor(l.budget):void 0,x=f().prepare(`SELECT s.id,
1740
1740
  s.auto_title,
1741
1741
  s.auto_title_source,
1742
1742
  NULLIF(sa.alias, '') AS alias
@@ -1745,7 +1745,7 @@ ${o}
1745
1745
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1746
1746
  WHERE p.name LIKE @proj ESCAPE '\\' OR p.decoded_path LIKE @proj ESCAPE '\\'
1747
1747
  ORDER BY COALESCE(s.ended_at, s.started_at, '') DESC
1748
- LIMIT @limit`).all({proj:`%${Qt(p)}%`,limit:R}),v=new Set(E),C=x.filter(O=>{let F=O.alias==null?null:I.isSessionAutoLinked(O.id)?"auto":"manual",U=jt({auto_title:O.auto_title,auto_title_source:O.auto_title_source??null,has_alias:O.alias!=null&&F==="manual"});return v.has(U)});return Me(i,async O=>{let F=C.length,U=[],Q=[],V=[],W=0,G=async(P,q)=>{W+=1;try{await O.writeSSE({id:String(W),event:P,data:JSON.stringify(q)})}catch{}};await G("start",{total:F,model:T});let K=0;for(let P of C){if(i.req.raw.signal.aborted)break;K+=1;try{let q=await pr(P.id,{model:T,budget:A,signal:i.req.raw.signal});q.written?(U.push(P.id),await G("progress",{sessionId:P.id,title:q.title,evidence:q.evidence,confidence:q.confidence,current:K,total:F})):(Q.push({sessionId:P.id,reason:q.skipped??"unknown"}),await G("skipped",{sessionId:P.id,reason:q.skipped??"unknown",current:K,total:F}))}catch(q){let pe=q instanceof Error?q.message:String(q),Ee=q instanceof nt?"no-context-available":"failed";V.push({sessionId:P.id,error:pe}),await G("error",{sessionId:P.id,error:pe,code:Ee,current:K,total:F})}}await G("done",{generated:U,skipped:Q,failed:V,cancelled:i.req.raw.signal.aborted})})}),t.get("/api/sessions/:id/notes",i=>{let l=i.req.param("id"),p=is(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 m=ci(l,p.content);return i.json(m)}catch(m){return console.error("[notes] failed to save note for session",l,m),i.json({error:"failed to save note"},500)}}),t.post("/api/sessions/:id/generate-note",async i=>{let l=i.req.param("id");if(!He().agentEnabled)return i.json({error:"autoTitle.agentEnabled is false"},403);try{let m=await li(l),_=di(l,m);return i.json(_)}catch(m){let _=m.message,E=/no messages available/i.test(_)?404:500;return i.json({error:_},E)}}),t.get("/api/semantic/status",i=>i.json(qr())),t.put("/api/semantic/config",async i=>{let l=await i.req.json().catch(()=>({})),p=nn.partial().safeParse(l);return p.success?(rn(p.data),i.json(qr())):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",async i=>{if(uo)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(()=>({})),m=Math.max(1,Math.min(5e3,Number(p.limit??200)));return uo=!0,cn({limit:m,force:!!p.force}).catch(_=>console.error("[semantic.backfill] error:",_)).finally(()=>{uo=!1}),i.json({ok:!0,limit:m})}),t.post("/api/semantic/sessions/:id",async i=>{if(!ce().enabled)return i.json({error:"semantic search is disabled"},400);let p=i.req.param("id"),m=await an(p);return i.json(m)}),t.get("/api/semantic/vector-status",i=>{let l=ke(),p=Wd(),m=so();return i.json({embedder:l,worker:p,modelInstalled:m})}),t.post("/api/semantic/install",es,async i=>{if(so())return i.json({ok:!0,status:"already_installed"});if(lo)return i.json({error:"a scan is already running"},409);lo=!0;try{return await Kd(),await Ws(),Hd(),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{lo=!1}}),t.get("/api/sessions/:id/similar",es,async i=>{if(!ke().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 m=await Md(l,p);return i.json({sessionId:l,similar:m})}catch(m){let _=m instanceof Error?m.message:"unknown error";return i.json({error:_},500)}}),t.get("/api/search",es,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 m=i.req.query("project"),_=p.split(/\s+/).filter(P=>P.length>0),E=_.filter(P=>P.startsWith("#")).map(P=>De(P)).filter(Boolean),T=_.filter(P=>!P.startsWith("#")),R=T.length>20,N=(R?T.slice(0,20):T).map(P=>`"${P.replace(/"/g,"")}"`),x=N.join(" "),v=Math.max(1,Math.min(200,Number(i.req.query("limit")??30)));if(N.length===0&&E.length>0){let P=`
1748
+ LIMIT @limit`).all({proj:`%${Qt(p)}%`,limit:R}),v=new Set(E),C=x.filter(O=>{let F=O.alias==null?null:I.isSessionAutoLinked(O.id)?"auto":"manual",U=jt({auto_title:O.auto_title,auto_title_source:O.auto_title_source??null,has_alias:O.alias!=null&&F==="manual"});return v.has(U)});return Me(i,async O=>{let F=C.length,U=[],Q=[],V=[],W=0,G=async(P,q)=>{W+=1;try{await O.writeSSE({id:String(W),event:P,data:JSON.stringify(q)})}catch{}};await G("start",{total:F,model:T});let K=0;for(let P of C){if(i.req.raw.signal.aborted)break;K+=1;try{let q=await gr(P.id,{model:T,budget:A,signal:i.req.raw.signal});q.written?(U.push(P.id),await G("progress",{sessionId:P.id,title:q.title,evidence:q.evidence,confidence:q.confidence,current:K,total:F})):(Q.push({sessionId:P.id,reason:q.skipped??"unknown"}),await G("skipped",{sessionId:P.id,reason:q.skipped??"unknown",current:K,total:F}))}catch(q){let pe=q instanceof Error?q.message:String(q),Ee=q instanceof nt?"no-context-available":"failed";V.push({sessionId:P.id,error:pe}),await G("error",{sessionId:P.id,error:pe,code:Ee,current:K,total:F})}}await G("done",{generated:U,skipped:Q,failed:V,cancelled:i.req.raw.signal.aborted})})}),t.get("/api/sessions/:id/notes",i=>{let l=i.req.param("id"),p=is(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 m=di(l,p.content);return i.json(m)}catch(m){return console.error("[notes] failed to save note for session",l,m),i.json({error:"failed to save note"},500)}}),t.post("/api/sessions/:id/generate-note",async i=>{let l=i.req.param("id");if(!He().agentEnabled)return i.json({error:"autoTitle.agentEnabled is false"},403);try{let m=await ui(l),_=pi(l,m);return i.json(_)}catch(m){let _=m.message,E=/no messages available/i.test(_)?404:500;return i.json({error:_},E)}}),t.get("/api/semantic/status",i=>i.json(Xr())),t.put("/api/semantic/config",async i=>{let l=await i.req.json().catch(()=>({})),p=nn.partial().safeParse(l);return p.success?(rn(p.data),i.json(Xr())):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",async i=>{if(po)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(()=>({})),m=Math.max(1,Math.min(5e3,Number(p.limit??200)));return po=!0,cn({limit:m,force:!!p.force}).catch(_=>console.error("[semantic.backfill] error:",_)).finally(()=>{po=!1}),i.json({ok:!0,limit:m})}),t.post("/api/semantic/sessions/:id",async i=>{if(!ce().enabled)return i.json({error:"semantic search is disabled"},400);let p=i.req.param("id"),m=await an(p);return i.json(m)}),t.get("/api/semantic/vector-status",i=>{let l=ke(),p=Jd(),m=ro();return i.json({embedder:l,worker:p,modelInstalled:m})}),t.post("/api/semantic/install",es,async i=>{if(ro())return i.json({ok:!0,status:"already_installed"});if(uo)return i.json({error:"a scan is already running"},409);uo=!0;try{return await Vd(),await Ws(),qd(),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{uo=!1}}),t.get("/api/sessions/:id/similar",es,async i=>{if(!ke().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 m=await Fd(l,p);return i.json({sessionId:l,similar:m})}catch(m){let _=m instanceof Error?m.message:"unknown error";return i.json({error:_},500)}}),t.get("/api/search",es,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 m=i.req.query("project"),_=p.split(/\s+/).filter(P=>P.length>0),E=_.filter(P=>P.startsWith("#")).map(P=>De(P)).filter(Boolean),T=_.filter(P=>!P.startsWith("#")),R=T.length>20,N=(R?T.slice(0,20):T).map(P=>`"${P.replace(/"/g,"")}"`),x=N.join(" "),v=Math.max(1,Math.min(200,Number(i.req.query("limit")??30)));if(N.length===0&&E.length>0){let P=`
1749
1749
  SELECT s.id AS session_id,
1750
1750
  s.id AS message_uuid,
1751
1751
  p.name AS project,
@@ -1789,13 +1789,13 @@ ${o}
1789
1789
  JOIN projects p ON p.id = s.project_id
1790
1790
  LEFT JOIN session_aliases sa ON sa.session_id = s.id
1791
1791
  WHERE sessions_fts MATCH @fts
1792
- `,q={fts:x,limit:v};m&&(P+=" AND (p.name LIKE @proj ESCAPE '\\' OR p.decoded_path LIKE @proj ESCAPE '\\')",q.proj=`%${Qt(m)}%`),E.forEach((pe,Ee)=>{P+=` AND s.id IN (SELECT session_id FROM session_tags WHERE tag = @tag_${Ee})`,q[`tag_${Ee}`]=pe}),P+=" ORDER BY rank LIMIT @limit",V=l.prepare(P).all(q)}catch(P){console.error("[search.semantic] failed:",P)}if(ke().loaded)try{let P=await jd(p,v),q=U.map(z=>({id:String(z.session_id),data:z,lane:"bm25"})),pe=V.map(z=>({id:String(z.session_id),data:z,lane:"summary"})),Ee=P.map(z=>({id:z.sessionId,data:{session_id:z.sessionId,snippet:z.text,matched_via:"vector"},lane:"vector"})),ts=Dd([q,pe,Ee]).slice(0,v).map(z=>({...z.data,session_id:z.id,rrf_score:z.score,lanes:z.lanes,matched_via:z.lanes.length>1?"fused":z.lanes[0]}));return i.json({query:p,hits:ts,tags:E,mode:"semantic",fusion:"rrf",truncated:R})}catch(P){console.error("[search.vector] failed, falling back:",P)}let W=new Set(U.map(P=>String(P.session_id))),G=V.filter(P=>!W.has(String(P.session_id))).map(({rank:P,...q})=>({...q,matched_via:"semantic"})),K=[...U,...G].slice(0,v);return i.json({query:p,hits:K,tags:E,mode:"semantic",truncated:R})}),t.get("/api/sessions/:id/context",es,i=>{let l=f(),p=i.req.param("id"),m=i.req.query("mode")==="full"?"full":"condensed",_=i.req.query("subagents")==="1",E=i.req.query("prelude")??null,T=l.prepare(`SELECT s.id, p.name AS project_name, p.decoded_path,
1792
+ `,q={fts:x,limit:v};m&&(P+=" AND (p.name LIKE @proj ESCAPE '\\' OR p.decoded_path LIKE @proj ESCAPE '\\')",q.proj=`%${Qt(m)}%`),E.forEach((pe,Ee)=>{P+=` AND s.id IN (SELECT session_id FROM session_tags WHERE tag = @tag_${Ee})`,q[`tag_${Ee}`]=pe}),P+=" ORDER BY rank LIMIT @limit",V=l.prepare(P).all(q)}catch(P){console.error("[search.semantic] failed:",P)}if(ke().loaded)try{let P=await Dd(p,v),q=U.map(z=>({id:String(z.session_id),data:z,lane:"bm25"})),pe=V.map(z=>({id:String(z.session_id),data:z,lane:"summary"})),Ee=P.map(z=>({id:z.sessionId,data:{session_id:z.sessionId,snippet:z.text,matched_via:"vector"},lane:"vector"})),ts=Pd([q,pe,Ee]).slice(0,v).map(z=>({...z.data,session_id:z.id,rrf_score:z.score,lanes:z.lanes,matched_via:z.lanes.length>1?"fused":z.lanes[0]}));return i.json({query:p,hits:ts,tags:E,mode:"semantic",fusion:"rrf",truncated:R})}catch(P){console.error("[search.vector] failed, falling back:",P)}let W=new Set(U.map(P=>String(P.session_id))),G=V.filter(P=>!W.has(String(P.session_id))).map(({rank:P,...q})=>({...q,matched_via:"semantic"})),K=[...U,...G].slice(0,v);return i.json({query:p,hits:K,tags:E,mode:"semantic",truncated:R})}),t.get("/api/sessions/:id/context",es,i=>{let l=f(),p=i.req.param("id"),m=i.req.query("mode")==="full"?"full":"condensed",_=i.req.query("subagents")==="1",E=i.req.query("prelude")??null,T=l.prepare(`SELECT s.id, p.name AS project_name, p.decoded_path,
1793
1793
  s.started_at, s.ended_at, s.message_count, s.git_branch
1794
1794
  FROM sessions s JOIN projects p ON p.id = s.project_id
1795
1795
  WHERE s.id = ?`).get(p);if(!T)return i.json({error:"not found"},404);let R=l.prepare(`SELECT uuid, type, role, timestamp, is_sidechain, content_text, tool_names
1796
1796
  FROM messages
1797
1797
  WHERE session_id = ?
1798
- ORDER BY COALESCE(timestamp, ''), rowid`).all(p),A=zo(T,R,{mode:m,includeSidechain:_,prelude:E});return i.text(A)}),t.get("/api/collections",i=>{let l=i.req.query("archived")==="1";return i.json({collections:pi(l)})}),t.get("/api/collections/:id",i=>{let l=i.req.param("id"),p=xe(l);if(!p)return i.json({error:"not found"},404);let m=mi(l,!0);return i.json({collection:p,members:m})}),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=At({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 m=_i(l,p);return i.json(m)}catch(m){return i.json({error:m.message},400)}}),t.post("/api/collections/:id/archive",i=>{let l=i.req.param("id");try{let p=fi(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=hi(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 m=Nt(l,p.session_id,p.note??null);return i.json(m)}catch(m){return i.json({error:m.message},400)}}),t.delete("/api/collections/:id/members/:sid",i=>{let l=i.req.param("id"),p=i.req.param("sid");try{let m=Ei(l,p);return i.json(m)}catch(m){return i.json({error:m.message},400)}}),t.get("/api/sessions/:id/collections",i=>{let l=i.req.param("id");return i.json({collections:gi(l)})});let w=["cwd-prefix","project-id","tag","plan-file","git-branch-prefix"];t.get("/api/auto-collections/rules",i=>i.json({rules:wi()})),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=Fn({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 m=Ri(l,p);return i.json(m)}catch(m){return i.json({error:m.message},400)}}),t.delete("/api/auto-collections/rules/:id",i=>{let l=i.req.param("id");try{let p=ki(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:gs({includeDismissed:l})})}),t.post("/api/auto-collections/suggestions/:id/accept",i=>{let l=i.req.param("id");try{let p=Ni(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 Ai(l),i.json({ok:!0})}catch(p){return i.json({error:p.message},400)}}),t.post("/api/auto-collections/detect",i=>{let l=_s();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)),_=gs({includeDismissed:!1}).find(T=>T.id===l);if(!_)return i.json({error:"suggestion not found"},404);let E=Ti(_.type,_.pattern,p);return i.json({sessions:E})}),t.get("/api/auto-collections/parents",i=>{let l=Array.from(xi());return i.json({auto_collection_ids:l})}),t.get("/api/threads",i=>{let l=i.req.query("archived")==="1";return i.json({threads:Bn({includeArchived:l})})}),t.get("/api/threads/:id",i=>{let l=i.req.param("id"),p=te(l);if(!p)return i.json({error:"thread not found"},404);let m=p.edges.map(_=>({..._,alias_source:_.alias==null?null:I.isSessionAutoLinked(_.session_id)?"auto":"manual"}));return i.json({thread:{...p,edges:m}})}),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=hs({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&&Pi(l,p.name),p.close&&Ui(l),p.reopen&&$i(l),p.archive&&Bi(l),"folder_id"in p&&aa(l,p.folder_id??null);let m=te(l);return m?i.json({thread:m}):i.json({error:"thread not found"},404)}catch(m){return i.json({error:m.message},400)}}),t.get("/api/thread-folders",i=>i.json({folders:Jn()})),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=ta({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 m;return p.name&&(m=na(l,p.name)),"parent_folder_id"in p&&(m=ra(l,p.parent_folder_id??null)),m?i.json({folder:m}):i.json({error:"no patch fields"},400)}catch(m){return i.json({error:m.message},400)}}),t.delete("/api/thread-folders/:id",i=>{let l=i.req.param("id");try{return ia(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 oa(l.parent_folder_id??null,l.project_scope??null,p),i.json({ok:!0})}catch(m){return i.json({error:m.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 m=Es({threadId:l,sessionId:p.sessionId,parentSessionId:p.parentSessionId??null,role:p.role});return i.json({edge:m})}catch(m){return i.json({error:m.message},400)}}),t.delete("/api/threads/:id/sessions/:sessionId",i=>{let l=i.req.param("id"),p=i.req.param("sessionId"),m=Fi(l,p);return i.json(m)}),t.patch("/api/threads/:id/sessions/:sessionId",async i=>{let l=i.req.param("id"),p=i.req.param("sessionId"),m=await i.req.json().catch(()=>({}));try{let _=xt(l,p,m.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 m=Hi(p.sourceId,l);return i.json({thread:m})}catch(m){return i.json({error:m.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 m=Wi({threadId:l,sessionIds:p.sessionIds,newThreadName:p.newThreadName});return i.json({thread:m})}catch(m){return i.json({error:m.message},400)}}),t.get("/api/sessions/:id/threads",i=>{let l=i.req.param("id");return i.json({threads:Di(l)})});let D=j.object({enabled:j.boolean(),band_lo:j.number().min(0).max(1).optional(),band_hi:j.number().min(0).max(1).optional(),model:j.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional()}).optional(),L=j.object({project:j.string().min(1),threshold:j.number().min(0).max(1).optional(),model:j.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional(),llm_rescore:D});t.post("/api/threads/scan/preflight",async i=>{let l=ye(i);if(l)return l;let p=await i.req.json().catch(()=>null),m=L.safeParse(p);if(!m.success)return i.json({error:"invalid request body",details:m.error.format()},400);let _=Fl({project:m.data.project,threshold:m.data.threshold,model:m.data.model,llm_rescore:m.data.llm_rescore});return"error"in _?i.json({error:_.error},400):i.json(_)});let X=j.object({project:j.string().min(1),threshold:j.number().min(0).max(1).optional(),llm_names:j.boolean().optional(),model:j.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional(),llm_rescore:D});t.post("/api/threads/scan/apply",async i=>{let l=ye(i);if(l)return l;let p=await i.req.json().catch(()=>null),m=X.safeParse(p);if(!m.success)return i.json({error:"invalid request body",details:m.error.format()},400);let _=Ul({project:m.data.project,threshold:m.data.threshold,llm_names:m.data.llm_names,model:m.data.model,llm_rescore:m.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(!Fr(l))return i.json({error:"job not found"},404);let m=Number(i.req.header("Last-Event-ID")??0);return Me(i,async _=>{let E=!1,T=setInterval(()=>{E||_.writeSSE({event:"heartbeat",data:""}).catch(()=>{E=!0})},15e3);try{for await(let R of $l(l,m))if(E||(await _.writeSSE({id:String(R.id),event:R.kind,data:JSON.stringify(R.data)}),R.kind==="done"))break}finally{E=!0,clearInterval(T)}})}),t.get("/api/threads/scan/jobs/:jobId",i=>{let l=Fr(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=ye(i);return l||(Bl(i.req.param("jobId"))?i.json({ok:!0}):i.json({error:"job not found or already done"},404))});let M=j.object({project_id:j.number().int().positive(),mode:j.enum(["preflight","apply"]),window_hours:j.number().min(.5).max(168).optional(),score_threshold:j.number().min(0).max(1).optional(),use_live_pids:j.boolean().optional()});t.post("/api/threads/sync-active",async i=>{let l=await i.req.json().catch(()=>null),p=M.safeParse(l);if(!p.success)return i.json({error:"invalid request body",details:p.error.format()},400);try{let m=await Zi(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:m});let _=Qi(m);return i.json({plan:m,result:_})}catch(m){return i.json({error:m.message},400)}}),t.get("/api/threads/:id/titles/preflight",i=>{let l=i.req.param("id"),p=te(l);if(!p)return i.json({error:"thread not found"},404);let m=f(),_=0;for(let E of p.edges)m.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(()=>({})),m=te(l);if(!m)return i.json({error:"thread not found"},404);if(m.edges.length===0)return i.json({error:"thread has no sessions"},400);let _=Re(),E=p.model??_.model,T=ac({threadId:l,force:p.force??!1,model:E});return i.json({jobId:T})}),t.get("/api/jobs/:jobId/stream",i=>{let l=i.req.param("jobId");if(!ir(l))return i.json({error:"job not found"},404);let m=Number(i.req.header("Last-Event-ID")??0);return Me(i,async _=>{let E=!1,T=setInterval(()=>{E||_.writeSSE({event:"heartbeat",data:""}).catch(()=>{E=!0})},15e3);try{for await(let R of cc(l,m))if(E||(await _.writeSSE({id:String(R.id),event:R.kind,data:JSON.stringify(R.data)}),R.kind==="done"))break}finally{E=!0,clearInterval(T)}})}),t.get("/api/jobs/:jobId",i=>{let l=ir(i.req.param("jobId"));return l?i.json(l):i.json({error:"job not found"},404)}),t.delete("/api/jobs/:jobId",i=>lc(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 m=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:m})}),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 m=I.rename(l.shell_pid,l.tab_name);if(!m)return i.json({error:"unknown shell_pid"},404);let _=nu(l.shell_pid,l.tab_name);return i.json({ok:!0,ownership:p,entry:m,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,m=typeof l.captured_at=="string"?l.captured_at:new Date().toISOString();return I.setOutputTail(l.shell_pid,p,m),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 O of I.all())p.set(O.shell_pid,O.tab_name);let m=l.terminals.filter(O=>!!O&&typeof O.shell_pid=="number"&&typeof O.tab_name=="string").map(O=>({shell_pid:O.shell_pid,tab_name:O.tab_name,cwd:O.cwd??null,opened_at:O.opened_at??new Date().toISOString()})),_=l.extension_instance_id??null,E=[],T=m.filter(O=>{let F=I.claimPidOwnership(O.shell_pid,_);return E.push({shell_pid:O.shell_pid,ownership:F}),F!=="rejected"}),R=I.sync(T),A=0;for(let O of T){let F=p.get(O.shell_pid),U=I.get(O.shell_pid)?.tab_name??O.tab_name,V=!!U&&!re(U)&&!ne(U)?U:O.tab_name;F!==void 0&&F!==V&&(A+=nu(O.shell_pid,V))}let N=E.filter(O=>O.ownership==="rejected").length;N>0&&console.log(`[terminal/sync] dropped ${N} tab_name update(s), pid(s) owned by a different extension instance`);let x=await zb(),v={resolved:0,expired:0};try{v=Ec()}catch{}let C={rebound:0,ghosts:0,ambiguous:0};try{C=hc()}catch{}return cS(),i.json({ok:!0,count:I.size(),diff:R,propagated:A,live_sweep:x,deferred_resolved:v,rebound:C})}),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 m=I.sessionsFor(p);return i.json({shell_pid:p,sessions:m})}),t.get("/api/sessions/:id/linked-terminal",i=>{let l=i.req.param("id"),p=I.all().find(_=>I.sessionsFor(_.shell_pid).includes(l)),m=[];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 T=_.cwd.replace(/\/+$/,""),R=300*1e3;for(let A of I.all()){if(!A.cwd||A.cwd.replace(/\/+$/,"")!==T||re(A.tab_name))continue;let N=Date.parse(A.opened_at),x=Date.parse(A.last_seen_at);!Number.isFinite(N)||!Number.isFinite(x)||N>E||x+R<E||m.push({shell_pid:A.shell_pid,tab_name:A.tab_name,cwd:A.cwd,opened_at:A.opened_at,last_seen_at:A.last_seen_at,reason:"time-overlap"})}m.sort((A,N)=>Date.parse(N.last_seen_at)-Date.parse(A.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:m})}),t.post("/api/sessions/:id/auto-relink",async i=>{let l=i.req.param("id");if(Se(l))return i.json({applied:!1,reason:"has-alias"});if(I.all().some(T=>I.sessionsFor(T.shell_pid).includes(l)))return i.json({applied:!1,reason:"already-linked"});let m=f().prepare("SELECT cwd, git_branch, started_at FROM sessions WHERE id = ?").get(l);if(!m?.cwd)return i.json({applied:!1,reason:"no-cwd"});let _=m.cwd.replace(/\/+$/,""),E=I.all().filter(T=>T.cwd&&T.cwd.replace(/\/+$/,"")===_&&!re(T.tab_name));if(E.length===1){let T=E[0],R=yt({sessionStartedAt:m.started_at??null,terminalOpenedAt:T.opened_at??null});if(!R.allowed)return i.json({applied:!1,reason:"temporal-guard",guard_reason:R.reason});let A=I.getOrigin(l),N=st({tabName:T.tab_name,origin:A??null,cwd:m.cwd??null,gitBranch:m.git_branch??null});return N?(me(l,N),I.linkSession(l,T.shell_pid),i.json({applied:!0,alias:N,linked_pid:T.shell_pid,linked_tab_name:T.tab_name,method:"cwd-singleton"})):i.json({applied:!1,reason:"no-usable-name"})}if(E.length>1){let T=await fc(l);if(T){let A=I.get(T.shell_pid),N=yt({sessionStartedAt:m.started_at??null,terminalOpenedAt:A?.opened_at??null});if(!N.allowed)return i.json({applied:!1,reason:"temporal-guard",guard_reason:N.reason});let x=I.getOrigin(l),v=st({tabName:T.tab_name,origin:x??null,cwd:m.cwd??null,gitBranch:m.git_branch??null});if(v)return me(l,v),I.linkSession(l,T.shell_pid),i.json({applied:!0,alias:v,linked_pid:T.shell_pid,linked_tab_name:T.tab_name,matched_fingerprints:T.matched_fingerprints,method:"content-match"})}let R=6e4;if(m.started_at){let A=Date.parse(m.started_at);if(Number.isFinite(A)){let N=E.filter(v=>yt({sessionStartedAt:m.started_at,terminalOpenedAt:v.opened_at??null}).allowed).map(v=>({t:v,gap:A-Date.parse(v.opened_at??"")})).filter(v=>Number.isFinite(v.gap)&&v.gap>=0&&v.gap<=R);if(N.length>=2)return i.json({applied:!1,reason:"ambiguous-temporal",candidate_count:N.length});let x=N[0];if(x){let v=I.getOrigin(l),C=st({tabName:x.t.tab_name,origin:v??null,cwd:m.cwd??null,gitBranch:m.git_branch??null});if(C)return me(l,C),I.linkSession(l,x.t.shell_pid),i.json({applied:!0,alias:C,linked_pid:x.t.shell_pid,linked_tab_name:x.t.tab_name,method:"closest-before-temporal",gap_ms:x.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),ns(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 m=I.get(p.shell_pid);if(!m)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),T=null,R=m.tab_name?.trim()??"";if(R&&!re(R)&&!ne(R))T=R;else if(R&&ne(R)){let A=tt(R);A&&!re(A)&&(T=A)}return T?(I.unlinkSession(l),me(l,T),i.json({ok:!0,alias:T,linked_pid:p.shell_pid,linked_tab_name:m.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),ns(l),await Ms(p.file_path);let m=Se(l);return i.json({ok:!0,alias:m,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"),m=i.req.query("path");if(!l||!p||!m)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 T=m.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");if(!new RegExp(`\\[Pasted text #\\d+ \\+\\d+ lines\\]\\s*${T}`).test(E.content_text??""))return i.json({error:"path not referenced by this message"},403);let A=_.prepare(`SELECT content_text FROM messages
1798
+ ORDER BY COALESCE(timestamp, ''), rowid`).all(p),A=Zo(T,R,{mode:m,includeSidechain:_,prelude:E});return i.text(A)}),t.get("/api/collections",i=>{let l=i.req.query("archived")==="1";return i.json({collections:gi(l)})}),t.get("/api/collections/:id",i=>{let l=i.req.param("id"),p=xe(l);if(!p)return i.json({error:"not found"},404);let m=_i(l,!0);return i.json({collection:p,members:m})}),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=At({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 m=hi(l,p);return i.json(m)}catch(m){return i.json({error:m.message},400)}}),t.post("/api/collections/:id/archive",i=>{let l=i.req.param("id");try{let p=Ei(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=bi(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 m=Nt(l,p.session_id,p.note??null);return i.json(m)}catch(m){return i.json({error:m.message},400)}}),t.delete("/api/collections/:id/members/:sid",i=>{let l=i.req.param("id"),p=i.req.param("sid");try{let m=Si(l,p);return i.json(m)}catch(m){return i.json({error:m.message},400)}}),t.get("/api/sessions/:id/collections",i=>{let l=i.req.param("id");return i.json({collections:fi(l)})});let w=["cwd-prefix","project-id","tag","plan-file","git-branch-prefix"];t.get("/api/auto-collections/rules",i=>i.json({rules:ki()})),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=Un({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 m=Ai(l,p);return i.json(m)}catch(m){return i.json({error:m.message},400)}}),t.delete("/api/auto-collections/rules/:id",i=>{let l=i.req.param("id");try{let p=Ni(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:gs({includeDismissed:l})})}),t.post("/api/auto-collections/suggestions/:id/accept",i=>{let l=i.req.param("id");try{let p=Oi(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 xi(l),i.json({ok:!0})}catch(p){return i.json({error:p.message},400)}}),t.post("/api/auto-collections/detect",i=>{let l=_s();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)),_=gs({includeDismissed:!1}).find(T=>T.id===l);if(!_)return i.json({error:"suggestion not found"},404);let E=wi(_.type,_.pattern,p);return i.json({sessions:E})}),t.get("/api/auto-collections/parents",i=>{let l=Array.from(Li());return i.json({auto_collection_ids:l})}),t.get("/api/threads",i=>{let l=i.req.query("archived")==="1";return i.json({threads:Wn({includeArchived:l})})}),t.get("/api/threads/:id",i=>{let l=i.req.param("id"),p=te(l);if(!p)return i.json({error:"thread not found"},404);let m=p.edges.map(_=>({..._,alias_source:_.alias==null?null:I.isSessionAutoLinked(_.session_id)?"auto":"manual"}));return i.json({thread:{...p,edges:m}})}),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=hs({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&&$i(l,p.name),p.close&&Bi(l),p.reopen&&Hi(l),p.archive&&Wi(l),"folder_id"in p&&la(l,p.folder_id??null);let m=te(l);return m?i.json({thread:m}):i.json({error:"thread not found"},404)}catch(m){return i.json({error:m.message},400)}}),t.get("/api/thread-folders",i=>i.json({folders:Gn()})),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=na({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 m;return p.name&&(m=oa(l,p.name)),"parent_folder_id"in p&&(m=ia(l,p.parent_folder_id??null)),m?i.json({folder:m}):i.json({error:"no patch fields"},400)}catch(m){return i.json({error:m.message},400)}}),t.delete("/api/thread-folders/:id",i=>{let l=i.req.param("id");try{return ca(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 aa(l.parent_folder_id??null,l.project_scope??null,p),i.json({ok:!0})}catch(m){return i.json({error:m.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 m=Es({threadId:l,sessionId:p.sessionId,parentSessionId:p.parentSessionId??null,role:p.role});return i.json({edge:m})}catch(m){return i.json({error:m.message},400)}}),t.delete("/api/threads/:id/sessions/:sessionId",i=>{let l=i.req.param("id"),p=i.req.param("sessionId"),m=Ui(l,p);return i.json(m)}),t.patch("/api/threads/:id/sessions/:sessionId",async i=>{let l=i.req.param("id"),p=i.req.param("sessionId"),m=await i.req.json().catch(()=>({}));try{let _=xt(l,p,m.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 m=qi(p.sourceId,l);return i.json({thread:m})}catch(m){return i.json({error:m.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 m=Ji({threadId:l,sessionIds:p.sessionIds,newThreadName:p.newThreadName});return i.json({thread:m})}catch(m){return i.json({error:m.message},400)}}),t.get("/api/sessions/:id/threads",i=>{let l=i.req.param("id");return i.json({threads:Pi(l)})});let D=j.object({enabled:j.boolean(),band_lo:j.number().min(0).max(1).optional(),band_hi:j.number().min(0).max(1).optional(),model:j.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional()}).optional(),L=j.object({project:j.string().min(1),threshold:j.number().min(0).max(1).optional(),model:j.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional(),llm_rescore:D});t.post("/api/threads/scan/preflight",async i=>{let l=ye(i);if(l)return l;let p=await i.req.json().catch(()=>null),m=L.safeParse(p);if(!m.success)return i.json({error:"invalid request body",details:m.error.format()},400);let _=Ul({project:m.data.project,threshold:m.data.threshold,model:m.data.model,llm_rescore:m.data.llm_rescore});return"error"in _?i.json({error:_.error},400):i.json(_)});let X=j.object({project:j.string().min(1),threshold:j.number().min(0).max(1).optional(),llm_names:j.boolean().optional(),model:j.string().regex(/^[a-zA-Z0-9._-]{1,100}$/).optional(),llm_rescore:D});t.post("/api/threads/scan/apply",async i=>{let l=ye(i);if(l)return l;let p=await i.req.json().catch(()=>null),m=X.safeParse(p);if(!m.success)return i.json({error:"invalid request body",details:m.error.format()},400);let _=Bl({project:m.data.project,threshold:m.data.threshold,llm_names:m.data.llm_names,model:m.data.model,llm_rescore:m.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(!Ur(l))return i.json({error:"job not found"},404);let m=Number(i.req.header("Last-Event-ID")??0);return Me(i,async _=>{let E=!1,T=setInterval(()=>{E||_.writeSSE({event:"heartbeat",data:""}).catch(()=>{E=!0})},15e3);try{for await(let R of Hl(l,m))if(E||(await _.writeSSE({id:String(R.id),event:R.kind,data:JSON.stringify(R.data)}),R.kind==="done"))break}finally{E=!0,clearInterval(T)}})}),t.get("/api/threads/scan/jobs/:jobId",i=>{let l=Ur(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=ye(i);return l||(Wl(i.req.param("jobId"))?i.json({ok:!0}):i.json({error:"job not found or already done"},404))});let M=j.object({project_id:j.number().int().positive(),mode:j.enum(["preflight","apply"]),window_hours:j.number().min(.5).max(168).optional(),score_threshold:j.number().min(0).max(1).optional(),use_live_pids:j.boolean().optional()});t.post("/api/threads/sync-active",async i=>{let l=await i.req.json().catch(()=>null),p=M.safeParse(l);if(!p.success)return i.json({error:"invalid request body",details:p.error.format()},400);try{let m=await ea(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:m});let _=ta(m);return i.json({plan:m,result:_})}catch(m){return i.json({error:m.message},400)}}),t.get("/api/threads/:id/titles/preflight",i=>{let l=i.req.param("id"),p=te(l);if(!p)return i.json({error:"thread not found"},404);let m=f(),_=0;for(let E of p.edges)m.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(()=>({})),m=te(l);if(!m)return i.json({error:"thread not found"},404);if(m.edges.length===0)return i.json({error:"thread has no sessions"},400);let _=Re(),E=p.model??_.model,T=lc({threadId:l,force:p.force??!1,model:E});return i.json({jobId:T})}),t.get("/api/jobs/:jobId/stream",i=>{let l=i.req.param("jobId");if(!cr(l))return i.json({error:"job not found"},404);let m=Number(i.req.header("Last-Event-ID")??0);return Me(i,async _=>{let E=!1,T=setInterval(()=>{E||_.writeSSE({event:"heartbeat",data:""}).catch(()=>{E=!0})},15e3);try{for await(let R of dc(l,m))if(E||(await _.writeSSE({id:String(R.id),event:R.kind,data:JSON.stringify(R.data)}),R.kind==="done"))break}finally{E=!0,clearInterval(T)}})}),t.get("/api/jobs/:jobId",i=>{let l=cr(i.req.param("jobId"));return l?i.json(l):i.json({error:"job not found"},404)}),t.delete("/api/jobs/:jobId",i=>uc(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 m=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:m})}),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 m=I.rename(l.shell_pid,l.tab_name);if(!m)return i.json({error:"unknown shell_pid"},404);let _=ou(l.shell_pid,l.tab_name);return i.json({ok:!0,ownership:p,entry:m,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,m=typeof l.captured_at=="string"?l.captured_at:new Date().toISOString();return I.setOutputTail(l.shell_pid,p,m),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 O of I.all())p.set(O.shell_pid,O.tab_name);let m=l.terminals.filter(O=>!!O&&typeof O.shell_pid=="number"&&typeof O.tab_name=="string").map(O=>({shell_pid:O.shell_pid,tab_name:O.tab_name,cwd:O.cwd??null,opened_at:O.opened_at??new Date().toISOString()})),_=l.extension_instance_id??null,E=[],T=m.filter(O=>{let F=I.claimPidOwnership(O.shell_pid,_);return E.push({shell_pid:O.shell_pid,ownership:F}),F!=="rejected"}),R=I.sync(T),A=0;for(let O of T){let F=p.get(O.shell_pid),U=I.get(O.shell_pid)?.tab_name??O.tab_name,V=!!U&&!re(U)&&!ne(U)?U:O.tab_name;F!==void 0&&F!==V&&(A+=ou(O.shell_pid,V))}let N=E.filter(O=>O.ownership==="rejected").length;N>0&&console.log(`[terminal/sync] dropped ${N} tab_name update(s), pid(s) owned by a different extension instance`);let x=await zb(),v={resolved:0,expired:0};try{v=Sc()}catch{}let C={rebound:0,ghosts:0,ambiguous:0};try{C=bc()}catch{}return cS(),i.json({ok:!0,count:I.size(),diff:R,propagated:A,live_sweep:x,deferred_resolved:v,rebound:C})}),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 m=I.sessionsFor(p);return i.json({shell_pid:p,sessions:m})}),t.get("/api/sessions/:id/linked-terminal",i=>{let l=i.req.param("id"),p=I.all().find(_=>I.sessionsFor(_.shell_pid).includes(l)),m=[];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 T=_.cwd.replace(/\/+$/,""),R=300*1e3;for(let A of I.all()){if(!A.cwd||A.cwd.replace(/\/+$/,"")!==T||re(A.tab_name))continue;let N=Date.parse(A.opened_at),x=Date.parse(A.last_seen_at);!Number.isFinite(N)||!Number.isFinite(x)||N>E||x+R<E||m.push({shell_pid:A.shell_pid,tab_name:A.tab_name,cwd:A.cwd,opened_at:A.opened_at,last_seen_at:A.last_seen_at,reason:"time-overlap"})}m.sort((A,N)=>Date.parse(N.last_seen_at)-Date.parse(A.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:m})}),t.post("/api/sessions/:id/auto-relink",async i=>{let l=i.req.param("id");if(Se(l))return i.json({applied:!1,reason:"has-alias"});if(I.all().some(T=>I.sessionsFor(T.shell_pid).includes(l)))return i.json({applied:!1,reason:"already-linked"});let m=f().prepare("SELECT cwd, git_branch, started_at FROM sessions WHERE id = ?").get(l);if(!m?.cwd)return i.json({applied:!1,reason:"no-cwd"});let _=m.cwd.replace(/\/+$/,""),E=I.all().filter(T=>T.cwd&&T.cwd.replace(/\/+$/,"")===_&&!re(T.tab_name));if(E.length===1){let T=E[0],R=yt({sessionStartedAt:m.started_at??null,terminalOpenedAt:T.opened_at??null});if(!R.allowed)return i.json({applied:!1,reason:"temporal-guard",guard_reason:R.reason});let A=I.getOrigin(l),N=st({tabName:T.tab_name,origin:A??null,cwd:m.cwd??null,gitBranch:m.git_branch??null});return N?(me(l,N),I.linkSession(l,T.shell_pid),i.json({applied:!0,alias:N,linked_pid:T.shell_pid,linked_tab_name:T.tab_name,method:"cwd-singleton"})):i.json({applied:!1,reason:"no-usable-name"})}if(E.length>1){let T=await Ec(l);if(T){let A=I.get(T.shell_pid),N=yt({sessionStartedAt:m.started_at??null,terminalOpenedAt:A?.opened_at??null});if(!N.allowed)return i.json({applied:!1,reason:"temporal-guard",guard_reason:N.reason});let x=I.getOrigin(l),v=st({tabName:T.tab_name,origin:x??null,cwd:m.cwd??null,gitBranch:m.git_branch??null});if(v)return me(l,v),I.linkSession(l,T.shell_pid),i.json({applied:!0,alias:v,linked_pid:T.shell_pid,linked_tab_name:T.tab_name,matched_fingerprints:T.matched_fingerprints,method:"content-match"})}let R=6e4;if(m.started_at){let A=Date.parse(m.started_at);if(Number.isFinite(A)){let N=E.filter(v=>yt({sessionStartedAt:m.started_at,terminalOpenedAt:v.opened_at??null}).allowed).map(v=>({t:v,gap:A-Date.parse(v.opened_at??"")})).filter(v=>Number.isFinite(v.gap)&&v.gap>=0&&v.gap<=R);if(N.length>=2)return i.json({applied:!1,reason:"ambiguous-temporal",candidate_count:N.length});let x=N[0];if(x){let v=I.getOrigin(l),C=st({tabName:x.t.tab_name,origin:v??null,cwd:m.cwd??null,gitBranch:m.git_branch??null});if(C)return me(l,C),I.linkSession(l,x.t.shell_pid),i.json({applied:!0,alias:C,linked_pid:x.t.shell_pid,linked_tab_name:x.t.tab_name,method:"closest-before-temporal",gap_ms:x.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),ns(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 m=I.get(p.shell_pid);if(!m)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),T=null,R=m.tab_name?.trim()??"";if(R&&!re(R)&&!ne(R))T=R;else if(R&&ne(R)){let A=tt(R);A&&!re(A)&&(T=A)}return T?(I.unlinkSession(l),me(l,T),i.json({ok:!0,alias:T,linked_pid:p.shell_pid,linked_tab_name:m.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),ns(l),await Ms(p.file_path);let m=Se(l);return i.json({ok:!0,alias:m,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"),m=i.req.query("path");if(!l||!p||!m)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 T=m.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");if(!new RegExp(`\\[Pasted text #\\d+ \\+\\d+ lines\\]\\s*${T}`).test(E.content_text??""))return i.json({error:"path not referenced by this message"},403);let A=_.prepare(`SELECT content_text FROM messages
1799
1799
  WHERE session_id = ? AND rowid > ?
1800
1800
  ORDER BY rowid ASC LIMIT 10`).all(l,E.rowid);for(let N of A){let x=N.content_text??"";if(x.includes("**Tool result**")&&x.includes(m))return i.json({source:"tool-result",content:x});if(/^\s*1\t/.test(x)&&x.length>200)return i.json({source:"tool-result",content:x})}try{let N=await Xb(m),x=Yb();if(!N.startsWith(x+"/")&&!N.startsWith(x+"\\"))return i.json({error:"path outside allowed root"},403);let v=[".ssh",".gnupg",".gpg",".aws",".kube",".docker",".password-store"],O=N.slice(x.length+1).split("/")[0].split("\\")[0];if(v.includes(O))return i.json({error:"path inside sensitive directory"},403);let F=await qb(N),U=2*1024*1024;if(F.size>U)return i.json({error:"file too large",size:F.size,max:U},413);let Q=await Jb(N,"utf8");return i.json({source:"disk",content:Q})}catch(N){return i.json({source:"missing",error:N.message})}}),t.get("/api/projects/:name/stats",i=>{let l=f(),p=i.req.param("name"),m=l.prepare(`SELECT
1801
1801
  (SELECT COUNT(*) FROM sessions s JOIN projects p ON p.id=s.project_id WHERE p.name=? AND s.message_count > 2) AS sessions,
@@ -1805,7 +1805,7 @@ ${o}
1805
1805
  JOIN projects p ON p.id = s.project_id
1806
1806
  WHERE p.name = ? AND s.git_branch IS NOT NULL
1807
1807
  ORDER BY s.git_branch
1808
- LIMIT 20`).all(p).map(E=>E.git_branch);return i.json({...m,branches:_})});function B(i){return i.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function se(i){if(!e)return i;let l=`<meta name="recall-token" content="${B(e)}" />`,p=i.indexOf("</head>");return p!==-1?i.slice(0,p)+l+i.slice(p):l+i}return nS?(t.use("/assets/*",su({root:mo})),t.get("/favicon.svg",su({root:mo})),t.get("/",i=>(i.header("cache-control","no-cache, no-store, must-revalidate"),i.header("pragma","no-cache"),i.header("expires","0"),i.html(se(ro(go,"utf8"))))),t.get("*",i=>i.req.path.startsWith("/api/")?i.notFound():(i.header("cache-control","no-cache, no-store, must-revalidate"),i.header("pragma","no-cache"),i.header("expires","0"),i.html(se(ro(go,"utf8")))))):t.get("/",i=>{let l=ou();return i.html(Ko({projects:l.projects,sessions:l.sessions,messages:l.messages,port:Number(i.req.raw.headers.get("host")?.split(":")[1]??0),version:ru}))}),t}function uS(){if(Qs(),!!He().heuristicEnabled){try{let{updated:e}=ec();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}=tc();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}=sc();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}=nc();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 uu(e,t){let s=dS(t);return new Promise((n,r)=>{try{let o=Hb({fetch:s.fetch,port:e,hostname:"127.0.0.1"},()=>{n(o),setImmediate(()=>{try{uS()}catch(a){console.error("[daemon] startup maintenance crashed:",a)}})})}catch(o){r(o)}})}Z();H();import{watch as pS}from"chokidar";import{statSync as mu}from"node:fs";import{basename as mS}from"node:path";var gS=1500,fo=new Map;function _S(e){let t=e.split("/"),s=t.findIndex(n=>n==="projects");return s===-1||s+1>=t.length?null:t[s+1]??null}async function fS(e){let t=0;try{t=mu(e).mtimeMs}catch{return}let s=_S(e);if(!s)return;let n=f(),r=n.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 k of fd(e)){let w=o.get(k.sessionId);if(w||(w={sessionId:k.sessionId,entries:[],earliest:null,latest:null,firstUser:null,users:0,assistants:0,cwd:null,branch:null,version:null},o.set(k.sessionId,w)),w.entries.push(k),k.timestamp&&((!w.earliest||k.timestamp<w.earliest)&&(w.earliest=k.timestamp),(!w.latest||k.timestamp>w.latest)&&(w.latest=k.timestamp)),k.role==="user"&&!k.isSidechain){if(w.users+=1,!w.firstUser&&k.contentText){let D=k.contentText.replace(/^(?:<[^>]+>[\s\S]*?<\/[^>]+>\s*)+/,"").trim();D&&!/^<local-command-caveat>/.test(D)&&(w.firstUser=qe(D).redacted.slice(0,2e3))}}else k.role==="assistant"&&!k.isSidechain&&(w.assistants+=1);!w.cwd&&k.cwd&&(w.cwd=k.cwd),!w.branch&&k.gitBranch&&(w.branch=k.gitBranch),!w.version&&k.version&&(w.version=k.version),!a&&k.cwd&&(a=k.cwd)}let c=a?mS(a)||a:s,d=a??s.replace(/^-/,"/").replace(/-/g,"/"),u=n.prepare(`INSERT INTO projects (encoded_path, decoded_path, name)
1808
+ LIMIT 20`).all(p).map(E=>E.git_branch);return i.json({...m,branches:_})});function B(i){return i.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function se(i){if(!e)return i;let l=`<meta name="recall-token" content="${B(e)}" />`,p=i.indexOf("</head>");return p!==-1?i.slice(0,p)+l+i.slice(p):l+i}return nS?(t.use("/assets/*",ru({root:go})),t.get("/favicon.svg",ru({root:go})),t.get("/",i=>(i.header("cache-control","no-cache, no-store, must-revalidate"),i.header("pragma","no-cache"),i.header("expires","0"),i.html(se(hn(_o,"utf8"))))),t.get("*",i=>i.req.path.startsWith("/api/")?i.notFound():(i.header("cache-control","no-cache, no-store, must-revalidate"),i.header("pragma","no-cache"),i.header("expires","0"),i.html(se(hn(_o,"utf8")))))):t.get("/",i=>{let l=au();return i.html(Vo({projects:l.projects,sessions:l.sessions,messages:l.messages,port:Number(i.req.raw.headers.get("host")?.split(":")[1]??0),version:iu}))}),t}function uS(){if(Qs(),!!He().heuristicEnabled){try{let{updated:e}=sc();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}=nc();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}=rc();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}=oc();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 uu(e,t){let s=dS(t);return new Promise((n,r)=>{try{let o=Hb({fetch:s.fetch,port:e,hostname:"127.0.0.1"},()=>{n(o),setImmediate(()=>{try{uS()}catch(a){console.error("[daemon] startup maintenance crashed:",a)}})})}catch(o){r(o)}})}Z();H();import{watch as pS}from"chokidar";import{statSync as mu}from"node:fs";import{basename as mS}from"node:path";var gS=1500,Eo=new Map;function _S(e){let t=e.split("/"),s=t.findIndex(n=>n==="projects");return s===-1||s+1>=t.length?null:t[s+1]??null}async function fS(e){let t=0;try{t=mu(e).mtimeMs}catch{return}let s=_S(e);if(!s)return;let n=f(),r=n.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 k of Ed(e)){let w=o.get(k.sessionId);if(w||(w={sessionId:k.sessionId,entries:[],earliest:null,latest:null,firstUser:null,users:0,assistants:0,cwd:null,branch:null,version:null},o.set(k.sessionId,w)),w.entries.push(k),k.timestamp&&((!w.earliest||k.timestamp<w.earliest)&&(w.earliest=k.timestamp),(!w.latest||k.timestamp>w.latest)&&(w.latest=k.timestamp)),k.role==="user"&&!k.isSidechain){if(w.users+=1,!w.firstUser&&k.contentText){let D=k.contentText.replace(/^(?:<[^>]+>[\s\S]*?<\/[^>]+>\s*)+/,"").trim();D&&!/^<local-command-caveat>/.test(D)&&(w.firstUser=qe(D).redacted.slice(0,2e3))}}else k.role==="assistant"&&!k.isSidechain&&(w.assistants+=1);!w.cwd&&k.cwd&&(w.cwd=k.cwd),!w.branch&&k.gitBranch&&(w.branch=k.gitBranch),!w.version&&k.version&&(w.version=k.version),!a&&k.cwd&&(a=k.cwd)}let c=a?mS(a)||a:s,d=a??s.replace(/^-/,"/").replace(/-/g,"/"),u=n.prepare(`INSERT INTO projects (encoded_path, decoded_path, name)
1809
1809
  VALUES (?, ?, ?)
1810
1810
  ON CONFLICT(encoded_path) DO UPDATE SET decoded_path = excluded.decoded_path, name = excluded.name
1811
1811
  RETURNING id`),g=n.prepare(`
@@ -1836,23 +1836,23 @@ ${o}
1836
1836
  VALUES (@uuid, @session_id, @parent_uuid, @type, @role, @timestamp,
1837
1837
  @is_sidechain, @content_text, @tool_names, @raw_json)
1838
1838
  ON CONFLICT(uuid) DO NOTHING
1839
- `),b=n.prepare("DELETE FROM messages WHERE session_id = ?"),S=new Date().toISOString();if(n.transaction(()=>{let{id:k}=u.get(s,d,c);for(let w of o.values()){g.run({id:w.sessionId,project_id:k,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:w.firstUser,cwd:w.cwd,git_branch:w.branch,version:w.version,indexed_at:S}),b.run(w.sessionId);for(let D of w.entries)h.run(hS(D));hd(n,w.sessionId,w.entries),dn(n,w.sessionId)}})(),He().heuristicEnabled)for(let k of o.values()){let w=et(k.firstUser);w&&de(k.sessionId,w,"heuristic")}}function hS(e){let t=qe(e.contentText).redacted,s=qe(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:s}}function pu(e){let t=fo.get(e);t?.timer&&clearTimeout(t.timer);let s={timer:null};s.timer=setTimeout(()=>{fo.delete(e),fS(e).then(async()=>{Ms(e);try{let r=f().prepare("SELECT id FROM sessions WHERE file_path = ?").all(e);for(let o of r){gd(o.id),Cd(o.id);try{yi(o.id)}catch(a){console.error("[watcher] auto-collections apply failed:",a)}}}catch(n){console.error("[watcher] semantic dispatch failed:",n)}}).catch(n=>{console.error(`[watcher] reindex failed for ${e}:`,n)})},gS),fo.set(e,s)}function gu(){let e=pS(Co,{depth:4,ignoreInitial:!0,persistent:!0,awaitWriteFinish:{stabilityThreshold:500,pollInterval:200},ignored:t=>{if(t.endsWith(".jsonl"))return!1;try{if(mu(t).isDirectory())return!1}catch{}return!0}});return e.on("add",t=>t.endsWith(".jsonl")&&pu(t)),e.on("change",t=>t.endsWith(".jsonl")&&pu(t)),e}import{createServer as fu}from"node:net";function _u(e){return new Promise(t=>{let s=fu();s.once("error",()=>t(!1)),s.once("listening",()=>{s.close(()=>t(!0))}),s.listen(e,"127.0.0.1")})}async function hu(){let e=new Set([3e3,3001,4200,5e3,5173,8e3,8080,8888,9e3]),t=51370;if(!e.has(t)&&await _u(t))return t;for(let s=0;s<50;s++){let n=49152+Math.floor(Math.random()*16383);if(!e.has(n)&&await _u(n))return n}return new Promise((s,n)=>{let r=fu();r.once("error",n),r.listen(0,"127.0.0.1",()=>{let o=r.address();if(o&&typeof o=="object"){let a=o.port;r.close(()=>s(a))}else r.close(),n(new Error("could not determine a free port"))})})}Z();import{existsSync as TS,readFileSync as Qx,writeFileSync as bu,unlinkSync as yS}from"node:fs";import{join as Eo}from"node:path";Z();import{randomBytes as ES}from"node:crypto";import{writeFileSync as bS,readFileSync as Gx,existsSync as Yx}from"node:fs";import{join as SS}from"node:path";var ho=SS($,"daemon.token");function Eu(){J();let e=ES(32).toString("hex");return bS(ho,e,{encoding:"utf8",mode:384}),e}var Su=Eo($,"daemon.pid"),Tu=Eo($,"daemon.port"),nO=Eo($,"daemon.log");function yu(e){J(),bu(Su,JSON.stringify(e),{encoding:"utf8",mode:384}),bu(Tu,String(e.port),{encoding:"utf8",mode:384})}function bo(){for(let e of[Su,Tu,ho])if(TS(e))try{yS(e)}catch{}}H();H();import{createHash as wS}from"node:crypto";var RS=/\b0x[0-9a-fA-F]+\b/g,kS=/\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,AS=/\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z?\b/g,NS=/:\d+:\d+/g,xS=/\bline\s+\d+\b/gi,OS=/\bcolumn\s+\d+\b/gi,LS=/\b(?:pid|PID|process(?:\s+id)?)\s*[:=]?\s*\d+\b/gi,CS=/\b(?:port|:)\s*[:=]?\s*\d{2,5}\b/gi,IS=/\b\d{4,}\b/g,vS=/(['"`])[^'"`\n]{1,128}\1/g;function jS(e){if(!e)return"";let t=String(e);return t=t.replace(RS,"<hex>"),t=t.replace(kS,"<uuid>"),t=t.replace(AS,"<ts>"),t=t.replace(NS,":<line>:<col>"),t=t.replace(xS,"line <n>"),t=t.replace(OS,"column <n>"),t=t.replace(LS,"pid <n>"),t=t.replace(CS,"port <n>"),t=t.replace(IS,"<num>"),t=t.replace(vS,"<arg>"),t=t.replace(/\s+/g," ").trim(),t.toLowerCase()}function MS(e){let t=(e.error_type??"unknown").toLowerCase().trim(),s=jS(e.snippet??e.message_hash??""),n=`${t}|${s}`;return wS("sha256").update(n).digest("hex").slice(0,16)}function DS(e){let t=f(),s=["oi.bug_signatures IS NOT NULL"],n=[];e&&(s.push("p.name = ?"),n.push(e));let r=`WHERE ${s.join(" AND ")}`,o=t.prepare(`SELECT oi.session_id AS session_id,
1839
+ `),b=n.prepare("DELETE FROM messages WHERE session_id = ?"),S=new Date().toISOString();if(n.transaction(()=>{let{id:k}=u.get(s,d,c);for(let w of o.values()){g.run({id:w.sessionId,project_id:k,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:w.firstUser,cwd:w.cwd,git_branch:w.branch,version:w.version,indexed_at:S}),b.run(w.sessionId);for(let D of w.entries)h.run(hS(D));bd(n,w.sessionId,w.entries),dn(n,w.sessionId)}})(),He().heuristicEnabled)for(let k of o.values()){let w=et(k.firstUser);w&&de(k.sessionId,w,"heuristic")}}function hS(e){let t=qe(e.contentText).redacted,s=qe(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:s}}function pu(e){let t=Eo.get(e);t?.timer&&clearTimeout(t.timer);let s={timer:null};s.timer=setTimeout(()=>{Eo.delete(e),fS(e).then(async()=>{Ms(e);try{let r=f().prepare("SELECT id FROM sessions WHERE file_path = ?").all(e);for(let o of r){fd(o.id),vd(o.id);try{Ri(o.id)}catch(a){console.error("[watcher] auto-collections apply failed:",a)}}}catch(n){console.error("[watcher] semantic dispatch failed:",n)}}).catch(n=>{console.error(`[watcher] reindex failed for ${e}:`,n)})},gS),Eo.set(e,s)}function gu(){let e=pS(vo,{depth:4,ignoreInitial:!0,persistent:!0,awaitWriteFinish:{stabilityThreshold:500,pollInterval:200},ignored:t=>{if(t.endsWith(".jsonl"))return!1;try{if(mu(t).isDirectory())return!1}catch{}return!0}});return e.on("add",t=>t.endsWith(".jsonl")&&pu(t)),e.on("change",t=>t.endsWith(".jsonl")&&pu(t)),e}import{createServer as fu}from"node:net";function _u(e){return new Promise(t=>{let s=fu();s.once("error",()=>t(!1)),s.once("listening",()=>{s.close(()=>t(!0))}),s.listen(e,"127.0.0.1")})}async function hu(){let e=new Set([3e3,3001,4200,5e3,5173,8e3,8080,8888,9e3]),t=51370;if(!e.has(t)&&await _u(t))return t;for(let s=0;s<50;s++){let n=49152+Math.floor(Math.random()*16383);if(!e.has(n)&&await _u(n))return n}return new Promise((s,n)=>{let r=fu();r.once("error",n),r.listen(0,"127.0.0.1",()=>{let o=r.address();if(o&&typeof o=="object"){let a=o.port;r.close(()=>s(a))}else r.close(),n(new Error("could not determine a free port"))})})}Z();import{existsSync as TS,readFileSync as Qx,writeFileSync as bu,unlinkSync as yS}from"node:fs";import{join as So}from"node:path";Z();import{randomBytes as ES}from"node:crypto";import{writeFileSync as bS,readFileSync as Gx,existsSync as Yx}from"node:fs";import{join as SS}from"node:path";var bo=SS($,"daemon.token");function Eu(){J();let e=ES(32).toString("hex");return bS(bo,e,{encoding:"utf8",mode:384}),e}var Su=So($,"daemon.pid"),Tu=So($,"daemon.port"),nO=So($,"daemon.log");function yu(e){J(),bu(Su,JSON.stringify(e),{encoding:"utf8",mode:384}),bu(Tu,String(e.port),{encoding:"utf8",mode:384})}function To(){for(let e of[Su,Tu,bo])if(TS(e))try{yS(e)}catch{}}H();H();import{createHash as wS}from"node:crypto";var RS=/\b0x[0-9a-fA-F]+\b/g,kS=/\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,AS=/\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z?\b/g,NS=/:\d+:\d+/g,xS=/\bline\s+\d+\b/gi,OS=/\bcolumn\s+\d+\b/gi,LS=/\b(?:pid|PID|process(?:\s+id)?)\s*[:=]?\s*\d+\b/gi,CS=/\b(?:port|:)\s*[:=]?\s*\d{2,5}\b/gi,IS=/\b\d{4,}\b/g,vS=/(['"`])[^'"`\n]{1,128}\1/g;function jS(e){if(!e)return"";let t=String(e);return t=t.replace(RS,"<hex>"),t=t.replace(kS,"<uuid>"),t=t.replace(AS,"<ts>"),t=t.replace(NS,":<line>:<col>"),t=t.replace(xS,"line <n>"),t=t.replace(OS,"column <n>"),t=t.replace(LS,"pid <n>"),t=t.replace(CS,"port <n>"),t=t.replace(IS,"<num>"),t=t.replace(vS,"<arg>"),t=t.replace(/\s+/g," ").trim(),t.toLowerCase()}function MS(e){let t=(e.error_type??"unknown").toLowerCase().trim(),s=jS(e.snippet??e.message_hash??""),n=`${t}|${s}`;return wS("sha256").update(n).digest("hex").slice(0,16)}function DS(e){let t=f(),s=["oi.bug_signatures IS NOT NULL"],n=[];e&&(s.push("p.name = ?"),n.push(e));let r=`WHERE ${s.join(" AND ")}`,o=t.prepare(`SELECT oi.session_id AS session_id,
1840
1840
  p.name AS project,
1841
1841
  s.started_at AS started_at,
1842
1842
  oi.bug_signatures AS bug_signatures
1843
1843
  FROM session_output_index oi
1844
1844
  LEFT JOIN sessions s ON s.id = oi.session_id
1845
1845
  LEFT JOIN projects p ON p.id = s.project_id
1846
- ${r}`).all(...n),a=[];for(let c of o){if(!c.bug_signatures)continue;let d=[];try{let u=JSON.parse(c.bug_signatures);Array.isArray(u)&&(d=u)}catch{continue}for(let u of d){if(!u||typeof u!="object"||!(u.snippet??"").trim())continue;let h=MS(u);a.push({session_id:c.session_id,project:c.project,started_at:c.started_at,signature:u,fingerprint:h})}}return a}function FS(e){let t=new Map;for(let n of e){let r=t.get(n.fingerprint);r||(r=[],t.set(n.fingerprint,r)),r.push(n)}let s=[];for(let[n,r]of t){let o=new Set,a=[];for(let g of r)o.has(g.session_id)||(o.add(g.session_id),a.push(g));let c=[...a].sort((g,h)=>{let b=g.started_at??"",S=h.started_at??"";return b&&S?b<S?-1:b>S?1:0:b?-1:S?1:0}),d=c.find(g=>g.started_at),u=[...c].reverse().find(g=>g.started_at);s.push({fingerprint:n,example_message:a[0].signature.snippet??a[0].signature.message_hash??"",members:a,first_seen_at:d?.started_at??new Date().toISOString(),last_seen_at:u?.started_at??new Date().toISOString()})}return s}function PS(e,t){if(e.length!==t.length)return 0;let s=0,n=0,r=0;for(let a=0;a<e.length;a++)s+=e[a]*t[a],n+=e[a]*e[a],r+=t[a]*t[a];let o=Math.sqrt(n)*Math.sqrt(r);return o>0?s/o:0}function US(e){let{records:t,vectors:s,epsilon:n,minPts:r}=e,o=t.length;if(o===0)return[];let a=[];for(let g=0;g<o;g++){let h=[];for(let b=0;b<o;b++){if(g===b)continue;1-PS(s[g],s[b])<=n&&h.push(b)}a.push(h)}let c=new Array(o).fill(!1),d=new Array(o).fill(-1),u=[];for(let g=0;g<o;g++){if(c[g])continue;c[g]=!0;let h=a[g];if(h.length<r)continue;let b=u.length;u.push({members:[t[g]]}),d[g]=b;let S=[...h];for(;S.length>0;){let y=S.shift();if(!c[y]&&(c[y]=!0,a[y].length>=r))for(let k of a[y])(!c[k]||d[k]===-1)&&S.push(k);d[y]===-1&&(d[y]=b,u[b].members.push(t[y]))}}return u}async function $S(e,t,s,n){if(e.length===0)return[];let r=e.map(d=>{let u=d.signature.snippet??d.signature.message_hash??"";return`${d.signature.error_type??""}: ${u}`.trim()}),o=await t(r);if(o.length!==e.length)throw new Error(`embedder returned ${o.length} vectors for ${e.length} inputs`);let a=US({records:e,vectors:o,epsilon:s,minPts:n}),c=[];for(let d of a){if(d.members.length===0)continue;let u=new Set,g=[];for(let w of d.members)u.has(w.session_id)||(u.add(w.session_id),g.push(w));if(g.length===0)continue;let b=`sem:${[...g.map(w=>w.fingerprint)].sort()[0]}`,S=[...g].sort((w,D)=>{let L=w.started_at??"",X=D.started_at??"";return L<X?-1:L>X?1:0}),y=S.find(w=>w.started_at),k=[...S].reverse().find(w=>w.started_at);c.push({fingerprint:b,example_message:g[0].signature.snippet??g[0].signature.message_hash??"",members:g,first_seen_at:y?.started_at??new Date().toISOString(),last_seen_at:k?.started_at??new Date().toISOString()})}return c}function wu(e,t){let s={clusters_created:0,clusters_merged:0,members_added:0,cluster_ids:[]};for(let n of e){if(n.members.length<t)continue;let r=Ba(n.fingerprint),o=Ha(n.fingerprint),a=n.members.map(u=>u.session_id).filter(u=>!o.has(u));if(r.length===0){let u=ja({signature_hash:n.fingerprint,example_message:n.example_message.slice(0,256),member_session_ids:n.members.map(g=>g.session_id),first_seen_at:n.first_seen_at,last_seen_at:n.last_seen_at});s.clusters_created+=1,s.members_added+=u.members.length,s.cluster_ids.push(u.cluster.id);continue}if(a.length===0){s.cluster_ids.push(r[0].id);continue}let c=r[0],d=Da(c.id,a);d.added>0&&(s.clusters_merged+=1,s.members_added+=d.added),s.cluster_ids.push(c.id)}return s}async function Ru(e={}){let t=Math.max(2,Math.floor(e.minClusterSize??3)),s=Math.max(1,Math.min(5e3,Math.floor(e.limit??1e3))),n=e.semanticEpsilon??.15,r=Math.max(1,Math.floor(e.semanticMinPts??1)),o=DS(e.project),a=new Set(o.map(L=>L.session_id)),c=FS(o),d=[],u=!1;if(e.semantic){let L=e.embedder??null;if(!L)try{L=await WS()}catch(X){let B=(X instanceof Error?X.message:String(X)).split(`
1846
+ ${r}`).all(...n),a=[];for(let c of o){if(!c.bug_signatures)continue;let d=[];try{let u=JSON.parse(c.bug_signatures);Array.isArray(u)&&(d=u)}catch{continue}for(let u of d){if(!u||typeof u!="object"||!(u.snippet??"").trim())continue;let h=MS(u);a.push({session_id:c.session_id,project:c.project,started_at:c.started_at,signature:u,fingerprint:h})}}return a}function FS(e){let t=new Map;for(let n of e){let r=t.get(n.fingerprint);r||(r=[],t.set(n.fingerprint,r)),r.push(n)}let s=[];for(let[n,r]of t){let o=new Set,a=[];for(let g of r)o.has(g.session_id)||(o.add(g.session_id),a.push(g));let c=[...a].sort((g,h)=>{let b=g.started_at??"",S=h.started_at??"";return b&&S?b<S?-1:b>S?1:0:b?-1:S?1:0}),d=c.find(g=>g.started_at),u=[...c].reverse().find(g=>g.started_at);s.push({fingerprint:n,example_message:a[0].signature.snippet??a[0].signature.message_hash??"",members:a,first_seen_at:d?.started_at??new Date().toISOString(),last_seen_at:u?.started_at??new Date().toISOString()})}return s}function PS(e,t){if(e.length!==t.length)return 0;let s=0,n=0,r=0;for(let a=0;a<e.length;a++)s+=e[a]*t[a],n+=e[a]*e[a],r+=t[a]*t[a];let o=Math.sqrt(n)*Math.sqrt(r);return o>0?s/o:0}function US(e){let{records:t,vectors:s,epsilon:n,minPts:r}=e,o=t.length;if(o===0)return[];let a=[];for(let g=0;g<o;g++){let h=[];for(let b=0;b<o;b++){if(g===b)continue;1-PS(s[g],s[b])<=n&&h.push(b)}a.push(h)}let c=new Array(o).fill(!1),d=new Array(o).fill(-1),u=[];for(let g=0;g<o;g++){if(c[g])continue;c[g]=!0;let h=a[g];if(h.length<r)continue;let b=u.length;u.push({members:[t[g]]}),d[g]=b;let S=[...h];for(;S.length>0;){let y=S.shift();if(!c[y]&&(c[y]=!0,a[y].length>=r))for(let k of a[y])(!c[k]||d[k]===-1)&&S.push(k);d[y]===-1&&(d[y]=b,u[b].members.push(t[y]))}}return u}async function $S(e,t,s,n){if(e.length===0)return[];let r=e.map(d=>{let u=d.signature.snippet??d.signature.message_hash??"";return`${d.signature.error_type??""}: ${u}`.trim()}),o=await t(r);if(o.length!==e.length)throw new Error(`embedder returned ${o.length} vectors for ${e.length} inputs`);let a=US({records:e,vectors:o,epsilon:s,minPts:n}),c=[];for(let d of a){if(d.members.length===0)continue;let u=new Set,g=[];for(let w of d.members)u.has(w.session_id)||(u.add(w.session_id),g.push(w));if(g.length===0)continue;let b=`sem:${[...g.map(w=>w.fingerprint)].sort()[0]}`,S=[...g].sort((w,D)=>{let L=w.started_at??"",X=D.started_at??"";return L<X?-1:L>X?1:0}),y=S.find(w=>w.started_at),k=[...S].reverse().find(w=>w.started_at);c.push({fingerprint:b,example_message:g[0].signature.snippet??g[0].signature.message_hash??"",members:g,first_seen_at:y?.started_at??new Date().toISOString(),last_seen_at:k?.started_at??new Date().toISOString()})}return c}function wu(e,t){let s={clusters_created:0,clusters_merged:0,members_added:0,cluster_ids:[]};for(let n of e){if(n.members.length<t)continue;let r=Wa(n.fingerprint),o=qa(n.fingerprint),a=n.members.map(u=>u.session_id).filter(u=>!o.has(u));if(r.length===0){let u=Da({signature_hash:n.fingerprint,example_message:n.example_message.slice(0,256),member_session_ids:n.members.map(g=>g.session_id),first_seen_at:n.first_seen_at,last_seen_at:n.last_seen_at});s.clusters_created+=1,s.members_added+=u.members.length,s.cluster_ids.push(u.cluster.id);continue}if(a.length===0){s.cluster_ids.push(r[0].id);continue}let c=r[0],d=Pa(c.id,a);d.added>0&&(s.clusters_merged+=1,s.members_added+=d.added),s.cluster_ids.push(c.id)}return s}async function Ru(e={}){let t=Math.max(2,Math.floor(e.minClusterSize??3)),s=Math.max(1,Math.min(5e3,Math.floor(e.limit??1e3))),n=e.semanticEpsilon??.15,r=Math.max(1,Math.floor(e.semanticMinPts??1)),o=DS(e.project),a=new Set(o.map(L=>L.session_id)),c=FS(o),d=[],u=!1;if(e.semantic){let L=e.embedder??null;if(!L)try{L=await WS()}catch(X){let B=(X instanceof Error?X.message:String(X)).split(`
1847
1847
  `)[0];console.warn(`[bug-pattern] --semantic requested but the embedder is unavailable: ${B}
1848
1848
  Falling back to exact-match-only clustering. Run \`recall semantic install\` to enable the semantic pass.`),u=!0}if(L){let X=[];for(let M of c)M.members.length===1&&X.push(M.members[0]);X.length>=2&&(d=await $S(X,L,n,r))}}let g=c.filter(L=>L.members.length>=t),h=d.filter(L=>L.members.length>=t),b=wu(g,t),S=wu(h,t),y=[...b.cluster_ids,...S.cluster_ids],k=Array.from(new Set(y)),w=[];if(k.length>0){let L=f(),X=k.map(()=>"?").join(","),M=L.prepare(`SELECT * FROM bug_pattern_clusters
1849
1849
  WHERE id IN (${X})
1850
1850
  ORDER BY occurrence_count DESC, last_seen_at DESC
1851
- LIMIT ?`).all(...k,s);for(let B of M)w.push({id:B.id,signature_hash:B.signature_hash,example_message:B.example_message,occurrence_count:B.occurrence_count,first_seen_at:B.first_seen_at,last_seen_at:B.last_seen_at,resolved_in_session_id:B.resolved_in_session_id,fix_summary:B.fix_summary})}return{progress:{total_sessions:a.size,total_signatures:o.length,exact_match_groups:g.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:u},clusters:w}}var BS=async()=>{let{embed:e,loadEmbedder:t,getEmbedderStatus:s}=await Promise.resolve().then(()=>(ot(),$c));return s().loaded||await t(),e},HS=BS;async function WS(){return HS()}H();var So={citation:"same-project",similar:"same-project",skill_track:"same-project",bug_pattern:"cross-project",wiki_link:"cross-project",temporal_proximity:"same-project"},qS=2,JS=.25,XS=5,GS=60,YS=25;function En(e){return e.trim().toLowerCase()}function KS(e){let t=new Set;for(let s of e.files_written)t.add(`file:${En(s)}`);for(let s of e.brands_mentioned)t.add(`brand:${En(s)}`);for(let s of e.terms_introduced)t.add(`term:${En(s)}`);for(let s of e.plan_ids_referenced)t.add(`plan:${En(s)}`);return t}function zS(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/GS);return Math.max(.2,t)}function VS(e,t){if(!e||!t)return 0;let s=Date.parse(e),n=Date.parse(t);return!Number.isFinite(s)||!Number.isFinite(n)?0:Math.abs(n-s)/(1e3*60*60*24)}function ZS(e){let t=Be(e);return t?{session_id:t.session_id,files_written:t.files_written,brands_mentioned:t.brands_mentioned,terms_introduced:t.terms_introduced.map(s=>s.term),plan_ids_referenced:t.plan_ids_referenced}:null}function QS(e){return f().prepare(`SELECT s.id AS id, s.project_id AS project_id, s.started_at AS started_at
1851
+ LIMIT ?`).all(...k,s);for(let B of M)w.push({id:B.id,signature_hash:B.signature_hash,example_message:B.example_message,occurrence_count:B.occurrence_count,first_seen_at:B.first_seen_at,last_seen_at:B.last_seen_at,resolved_in_session_id:B.resolved_in_session_id,fix_summary:B.fix_summary})}return{progress:{total_sessions:a.size,total_signatures:o.length,exact_match_groups:g.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:u},clusters:w}}var BS=async()=>{let{embed:e,loadEmbedder:t,getEmbedderStatus:s}=await Promise.resolve().then(()=>(ot(),Hc));return s().loaded||await t(),e},HS=BS;async function WS(){return HS()}H();var yo={citation:"same-project",similar:"same-project",skill_track:"same-project",bug_pattern:"cross-project",wiki_link:"cross-project",temporal_proximity:"same-project"},qS=2,JS=.25,XS=5,GS=60,YS=25;function Sn(e){return e.trim().toLowerCase()}function KS(e){let t=new Set;for(let s of e.files_written)t.add(`file:${Sn(s)}`);for(let s of e.brands_mentioned)t.add(`brand:${Sn(s)}`);for(let s of e.terms_introduced)t.add(`term:${Sn(s)}`);for(let s of e.plan_ids_referenced)t.add(`plan:${Sn(s)}`);return t}function zS(e){if(!Number.isFinite(e)||e<0)return 1;let t=Math.exp(-e/GS);return Math.max(.2,t)}function VS(e,t){if(!e||!t)return 0;let s=Date.parse(e),n=Date.parse(t);return!Number.isFinite(s)||!Number.isFinite(n)?0:Math.abs(n-s)/(1e3*60*60*24)}function ZS(e){let t=Be(e);return t?{session_id:t.session_id,files_written:t.files_written,brands_mentioned:t.brands_mentioned,terms_introduced:t.terms_introduced.map(s=>s.term),plan_ids_referenced:t.plan_ids_referenced}:null}function QS(e){return f().prepare(`SELECT s.id AS id, s.project_id AS project_id, s.started_at AS started_at
1852
1852
  FROM sessions s
1853
1853
  JOIN session_output_index oi ON oi.session_id = s.id
1854
1854
  WHERE s.project_id = ?
1855
- ORDER BY COALESCE(s.started_at, ''), s.id`).all(e)}function eT(e,t){let s=new Map,n=new Map,r=new Map;for(let o of e){r.set(o.id,o.started_at);let a=t.get(o.id);if(!a)continue;let c=KS(a);if(c.size!==0){n.set(o.id,c);for(let d of c){let u=s.get(d);u?u.push(o.id):s.set(d,[o.id])}}}return{posting:s,vocab:n,startedAt:r}}function tT(e,t){let s=t.vocab.get(e),n=t.startedAt.get(e)??null;if(!s||!n)return[];let r=new Map;for(let a of s){let c=t.posting.get(a);if(c)for(let d of c){if(d===e)continue;let u=t.startedAt.get(d);if(!u||u>=n)continue;let g=r.get(d);g?g.push(a):r.set(d,[a])}}let o=[];for(let[a,c]of r){let d=c.length;if(d<qS)continue;let u=t.startedAt.get(a)??null,g=VS(n,u),h=zS(g),b=Math.min(1,d/XS*h);if(b<JS)continue;let S=c.slice(0,12);o.push({target_session_id:a,matched_terms:S,overlap:d,days_apart:Math.round(g*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,YS)}async function ku(e){if(So.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project \u2014 refusing to run inference");let t=QS(e.projectId),s=new Map;for(let a of t){let c=ZS(a.id);c&&s.set(a.id,c)}let n=eT(t,s),r={total_sessions:t.length,processed_sessions:0,suggestions_created:0,suggestions_skipped_existing:0,current_session_id:null};e.onProgress?.({...r});let o=[];for(let a of t){if(e.signal?.aborted)break;r.current_session_id=a.id,e.onProgress?.({...r});let c=tT(a.id,n);for(let d of c)try{let u=Ct({source_session_id:a.id,target_session_id:d.target_session_id,link_type:"citation",confidence:d.confidence,evidence:{matched_terms:d.matched_terms,overlap_count:d.overlap,recency:d.recency,days_apart:d.days_apart},inferred_by:"L2"});o.push(u.id),r.suggestions_created+=1}catch(u){console.error("[citation-inference] createSuggestion failed:",u)}r.processed_sessions+=1,e.onProgress?.({...r})}return r.current_session_id=null,e.onProgress?.({...r}),{progress:r,suggestion_ids:o}}H();var sT=/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/gi,nT=[/\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],rT=.95,oT=.85;var To=50;function iT(e){if(!e)return[];let t=new Set,s=[],n=e.match(sT);if(!n)return s;for(let r of n){let o=r.toLowerCase();if(!t.has(o)&&(t.add(o),s.push(o),s.length>=To))break}return s}function aT(e){if(!e)return[];let t=new Set,s=[];for(let n of nT){n.lastIndex=0;let r=e.match(n);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),s.push(a),s.length>=To))break}if(s.length>=To)break}}return s}function Au(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 Nu(e){let t=f();return typeof e=="number"?t.prepare(`SELECT m.uuid AS message_uuid, m.session_id, m.content_text,
1855
+ ORDER BY COALESCE(s.started_at, ''), s.id`).all(e)}function eT(e,t){let s=new Map,n=new Map,r=new Map;for(let o of e){r.set(o.id,o.started_at);let a=t.get(o.id);if(!a)continue;let c=KS(a);if(c.size!==0){n.set(o.id,c);for(let d of c){let u=s.get(d);u?u.push(o.id):s.set(d,[o.id])}}}return{posting:s,vocab:n,startedAt:r}}function tT(e,t){let s=t.vocab.get(e),n=t.startedAt.get(e)??null;if(!s||!n)return[];let r=new Map;for(let a of s){let c=t.posting.get(a);if(c)for(let d of c){if(d===e)continue;let u=t.startedAt.get(d);if(!u||u>=n)continue;let g=r.get(d);g?g.push(a):r.set(d,[a])}}let o=[];for(let[a,c]of r){let d=c.length;if(d<qS)continue;let u=t.startedAt.get(a)??null,g=VS(n,u),h=zS(g),b=Math.min(1,d/XS*h);if(b<JS)continue;let S=c.slice(0,12);o.push({target_session_id:a,matched_terms:S,overlap:d,days_apart:Math.round(g*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,YS)}async function ku(e){if(yo.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project \u2014 refusing to run inference");let t=QS(e.projectId),s=new Map;for(let a of t){let c=ZS(a.id);c&&s.set(a.id,c)}let n=eT(t,s),r={total_sessions:t.length,processed_sessions:0,suggestions_created:0,suggestions_skipped_existing:0,current_session_id:null};e.onProgress?.({...r});let o=[];for(let a of t){if(e.signal?.aborted)break;r.current_session_id=a.id,e.onProgress?.({...r});let c=tT(a.id,n);for(let d of c)try{let u=Ct({source_session_id:a.id,target_session_id:d.target_session_id,link_type:"citation",confidence:d.confidence,evidence:{matched_terms:d.matched_terms,overlap_count:d.overlap,recency:d.recency,days_apart:d.days_apart},inferred_by:"L2"});o.push(u.id),r.suggestions_created+=1}catch(u){console.error("[citation-inference] createSuggestion failed:",u)}r.processed_sessions+=1,e.onProgress?.({...r})}return r.current_session_id=null,e.onProgress?.({...r}),{progress:r,suggestion_ids:o}}H();var sT=/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/gi,nT=[/\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],rT=.95,oT=.85;var wo=50;function iT(e){if(!e)return[];let t=new Set,s=[],n=e.match(sT);if(!n)return s;for(let r of n){let o=r.toLowerCase();if(!t.has(o)&&(t.add(o),s.push(o),s.length>=wo))break}return s}function aT(e){if(!e)return[];let t=new Set,s=[];for(let n of nT){n.lastIndex=0;let r=e.match(n);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),s.push(a),s.length>=wo))break}if(s.length>=wo)break}}return s}function Au(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 Nu(e){let t=f();return typeof e=="number"?t.prepare(`SELECT m.uuid AS message_uuid, m.session_id, m.content_text,
1856
1856
  s.project_id
1857
1857
  FROM messages m
1858
1858
  JOIN sessions s ON s.id = m.session_id
@@ -1870,4 +1870,4 @@ ${o}
1870
1870
  oi.plan_ids_referenced AS plan_ids_json
1871
1871
  FROM session_output_index oi
1872
1872
  JOIN sessions s ON s.id = oi.session_id
1873
- ${s}`).all(...n)}function lT(e){if(!e)return[];try{let t=JSON.parse(e);if(Array.isArray(t))return t.filter(s=>typeof s=="string")}catch{}return[]}function xu(e={}){if(So.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project");let t=Au(e.projectId),s=new Set(t.map(o=>o.id)),n=new Map;for(let o of t)n.set(o.id,o.project_id);let r=0;for(let o of Nu(e.projectId)){if(e.signal?.aborted)break;let a=iT(o.content_text);if(a.length===0)continue;let c=n.get(o.session_id);if(c!==void 0)for(let d of a){if(d===o.session_id)continue;let u=n.get(d);if(!(u===void 0&&!s.has(d))&&!(u!==void 0&&c!==void 0&&u!==c))try{Ct({source_session_id:o.session_id,target_session_id:d,link_type:"citation",confidence:rT,evidence:{matched_uuid:d,source_message_uuid:o.message_uuid,scanner:"uuid-ref"},inferred_by:"L1"}),r+=1}catch{}}}return{created:r}}function Ou(e={}){let t=cT(e.projectId);if(t.length===0)return{created:0};let s=new Map;for(let c of t){let d=lT(c.plan_ids_json);for(let u of d){let g=u.trim().toLowerCase();if(!g)continue;let h=s.get(g);h?h.push({id:c.session_id,project_id:c.project_id}):s.set(g,[{id:c.session_id,project_id:c.project_id}])}}if(s.size===0)return{created:0};let n=Au(e.projectId),r=new Map;for(let c of n)r.set(c.id,c.project_id);let o=0,a=new Map;for(let c of Nu(e.projectId)){if(e.signal?.aborted)break;let d=aT(c.content_text);if(d.length===0)continue;let u=r.get(c.session_id);if(u!==void 0)for(let g of d){let h=s.get(g);if(h)for(let b of h){if(b.id===c.session_id||b.project_id!==u)continue;let S=a.get(c.session_id);S||(S=new Map,a.set(c.session_id,S));let y=S.get(b.id);y||(y=new Set,S.set(b.id,y)),y.add(g)}}}for(let[c,d]of a)for(let[u,g]of d)try{Ct({source_session_id:c,target_session_id:u,link_type:"citation",confidence:oT,evidence:{matched_plan_ids:Array.from(g).slice(0,12),scanner:"plan-ref"},inferred_by:"L1"}),o+=1}catch{}return{created:o}}ge();var le="[daemon:inference]",yo=!1,wo=!1,Ro=!1,ko=!1,Ao=!1,Lu=0,No=!1,xo=!1;function dT(){return f().prepare("SELECT id, name FROM projects").all()}async function Cu(){if(yo)return;yo=!0;let e=Date.now();try{let s=(await Ru({minClusterSize:2})).progress;(s.clusters_created||s.clusters_merged||s.members_added)&&console.log(`${le} bug-patterns: created=${s.clusters_created} merged=${s.clusters_merged} members_added=${s.members_added} (${Date.now()-e}ms)`)}catch(t){console.error(`${le} bug-patterns failed:`,t)}finally{yo=!1}}async function Iu(){if(wo)return;wo=!0;let e=Date.now();try{let t=0,s=0;for(let n of dT())try{let r=await ku({projectId:n.id});t+=r.progress.suggestions_created,s+=1}catch(r){console.error(`${le} citations failed for project "${n.name}":`,r)}t>0&&console.log(`${le} citations: ${t} suggestion(s) across ${s} project(s) (${Date.now()-e}ms)`)}catch(t){console.error(`${le} citations failed:`,t)}finally{wo=!1}}function vu(){if(Ro)return;Ro=!0;let e=Date.now();try{let t=xu({}),s=Ou({});t.created+s.created>0&&console.log(`${le} l1: uuid=${t.created} plan=${s.created} (${Date.now()-e}ms)`)}catch(t){console.error(`${le} l1 failed:`,t)}finally{Ro=!1}}async function ju(){if(ko)return;let e=ce();if(!e.enabled||e.backfillPaused)return;ko=!0;let t=Date.now();try{let s=await cn({limit:25});s.processed>0&&console.log(`${le} backfill: processed=${s.processed} ok=${s.ok} failed=${s.failed} (${Date.now()-t}ms)`)}catch(s){console.error(`${le} backfill failed:`,s)}finally{ko=!1}}async function Mu(){if(Ao)return;let e=ce();if(!e.autoExtractEnabled)return;let t=e.autoExtractIntervalMinutes*60*1e3;if(Date.now()-Lu<t)return;if(!oe()){No||(console.log(`${le} auto-extract: claude CLI not on PATH \u2014 pausing nibbler (will retry; install Claude Code or run \`recall semantic auto-extract off\` to silence)`),No=!0);return}if(No=!1,!await Wo().catch(()=>!1)){xo||(console.log(`${le} auto-extract: Pro license required \u2014 pausing nibbler (run \`recall semantic auto-extract off\` to silence; upgrade unlocks)`),xo=!0);return}xo=!1,Ao=!0,Lu=Date.now();let n=Date.now();try{let r=e.autoExtractBatchSize,{eligible:o}=rt({limit:r});if(o.length===0)return;let a=0,c=0,d=0,u=0;for(let g of o){let h=await fr(g.id,{model:We});h.ok?a+=1:h.skipped||(c+=1),h.usage?.input_tokens&&(d+=h.usage.input_tokens),h.usage?.output_tokens&&(u+=h.usage.output_tokens)}console.log(`${le} auto-extract: processed=${o.length} ok=${a} failed=${c} tokens=${d}+${u} (${Date.now()-n}ms)`)}catch(r){console.error(`${le} auto-extract failed:`,r)}finally{Ao=!1}}function Du(){let g=[],h=[];return g.push(setTimeout(()=>{Cu()},9e4)),h.push(setInterval(()=>{Cu()},18e5)),g.push(setTimeout(()=>{Iu()},18e4)),h.push(setInterval(()=>{Iu()},36e5)),g.push(setTimeout(()=>vu(),12e4)),h.push(setInterval(()=>vu(),18e5)),g.push(setTimeout(()=>{ju()},24e4)),h.push(setInterval(()=>{ju()},9e5)),g.push(setTimeout(()=>{Mu()},3e5)),h.push(setInterval(()=>{Mu()},9e5)),console.log(`${le} scheduled: bug-patterns (30m), citations (60m), l1 (30m), backfill (15m, when enabled), auto-extract (60m, when enabled)`),{startupTimers:g,intervalTimers:h,stop:()=>{for(let b of g)clearTimeout(b);for(let b of h)clearInterval(b)}}}var uT=360*60*1e3,pT=60*1e3,mT=1440*60*1e3,gT=300*1e3,_T=300*1e3,fT=10*1e3,hT=1440*60*1e3,ET=30*1e3,bT=500;async function ST(){let e=await hu(),t=Eu(),s=await uu(e,t);yu({pid:process.pid,port:e,startedAt:new Date().toISOString()});let n=gu(),r=()=>{try{_s()}catch(L){console.error("[daemon] suggestion scan failed:",L)}},o=setTimeout(r,pT),a=setInterval(r,uT),c=()=>{try{let L=I.reapStaleLinks();(L.pruned_pids||L.pruned_sessions)&&console.log(`[daemon] reaper: pruned ${L.pruned_pids} pid${L.pruned_pids===1?"":"s"}, ${L.pruned_sessions} session link${L.pruned_sessions===1?"":"s"}`)}catch(L){console.error("[daemon] stale-link reaper failed:",L)}},d=setTimeout(c,gT),u=setInterval(c,mT),g=()=>{try{let L=I.gcDeadPids();(L.pruned_pids||L.pruned_sessions)&&console.log(`[daemon] dead-pid gc: pruned ${L.pruned_pids} pid${L.pruned_pids===1?"":"s"}, ${L.pruned_sessions} session link${L.pruned_sessions===1?"":"s"}`)}catch(L){console.error("[daemon] dead-pid gc failed:",L)}},h=setTimeout(g,fT),b=setInterval(g,_T),S=()=>{Ho().then(L=>{L.ran&&L.revoked&&console.log(`[daemon] license check: REVOKED${L.reason?` (${L.reason})`:""}`)}).catch(L=>{console.error("[daemon] license check failed:",L)})},y=setTimeout(S,ET),k=setInterval(S,hT),w=Du(),D=L=>{console.log(`[daemon] received ${L}, shutting down`),clearTimeout(o),clearInterval(a),clearTimeout(d),clearInterval(u),clearTimeout(h),clearInterval(b),clearTimeout(y),clearInterval(k),w.stop(),n.close(),s.close(),bo(),process.exit(0)};process.on("SIGTERM",()=>D("SIGTERM")),process.on("SIGINT",()=>D("SIGINT")),process.on("SIGHUP",()=>D("SIGHUP")),console.log(`[daemon] ready on http://127.0.0.1:${e} pid=${process.pid}`),setTimeout(()=>{Ds().then(L=>{console.log(`[daemon] boot sweep: scanned ${L.scanned} live claude(s), linked ${L.linked}, renamed ${L.renamed}, ambiguous_cwd ${L.ambiguous_cwd}`)}).catch(L=>{console.error("[daemon] boot sweep failed:",L)})},bT)}ST().catch(e=>{console.error("[daemon] fatal:",e),bo(),process.exit(1)});
1873
+ ${s}`).all(...n)}function lT(e){if(!e)return[];try{let t=JSON.parse(e);if(Array.isArray(t))return t.filter(s=>typeof s=="string")}catch{}return[]}function xu(e={}){if(yo.citation!=="same-project")throw new Error("citation policy unexpectedly not same-project");let t=Au(e.projectId),s=new Set(t.map(o=>o.id)),n=new Map;for(let o of t)n.set(o.id,o.project_id);let r=0;for(let o of Nu(e.projectId)){if(e.signal?.aborted)break;let a=iT(o.content_text);if(a.length===0)continue;let c=n.get(o.session_id);if(c!==void 0)for(let d of a){if(d===o.session_id)continue;let u=n.get(d);if(!(u===void 0&&!s.has(d))&&!(u!==void 0&&c!==void 0&&u!==c))try{Ct({source_session_id:o.session_id,target_session_id:d,link_type:"citation",confidence:rT,evidence:{matched_uuid:d,source_message_uuid:o.message_uuid,scanner:"uuid-ref"},inferred_by:"L1"}),r+=1}catch{}}}return{created:r}}function Ou(e={}){let t=cT(e.projectId);if(t.length===0)return{created:0};let s=new Map;for(let c of t){let d=lT(c.plan_ids_json);for(let u of d){let g=u.trim().toLowerCase();if(!g)continue;let h=s.get(g);h?h.push({id:c.session_id,project_id:c.project_id}):s.set(g,[{id:c.session_id,project_id:c.project_id}])}}if(s.size===0)return{created:0};let n=Au(e.projectId),r=new Map;for(let c of n)r.set(c.id,c.project_id);let o=0,a=new Map;for(let c of Nu(e.projectId)){if(e.signal?.aborted)break;let d=aT(c.content_text);if(d.length===0)continue;let u=r.get(c.session_id);if(u!==void 0)for(let g of d){let h=s.get(g);if(h)for(let b of h){if(b.id===c.session_id||b.project_id!==u)continue;let S=a.get(c.session_id);S||(S=new Map,a.set(c.session_id,S));let y=S.get(b.id);y||(y=new Set,S.set(b.id,y)),y.add(g)}}}for(let[c,d]of a)for(let[u,g]of d)try{Ct({source_session_id:c,target_session_id:u,link_type:"citation",confidence:oT,evidence:{matched_plan_ids:Array.from(g).slice(0,12),scanner:"plan-ref"},inferred_by:"L1"}),o+=1}catch{}return{created:o}}ge();var le="[daemon:inference]",Ro=!1,ko=!1,Ao=!1,No=!1,xo=!1,Lu=0,Oo=!1,Lo=!1;function dT(){return f().prepare("SELECT id, name FROM projects").all()}async function Cu(){if(Ro)return;Ro=!0;let e=Date.now();try{let s=(await Ru({minClusterSize:2})).progress;(s.clusters_created||s.clusters_merged||s.members_added)&&console.log(`${le} bug-patterns: created=${s.clusters_created} merged=${s.clusters_merged} members_added=${s.members_added} (${Date.now()-e}ms)`)}catch(t){console.error(`${le} bug-patterns failed:`,t)}finally{Ro=!1}}async function Iu(){if(ko)return;ko=!0;let e=Date.now();try{let t=0,s=0;for(let n of dT())try{let r=await ku({projectId:n.id});t+=r.progress.suggestions_created,s+=1}catch(r){console.error(`${le} citations failed for project "${n.name}":`,r)}t>0&&console.log(`${le} citations: ${t} suggestion(s) across ${s} project(s) (${Date.now()-e}ms)`)}catch(t){console.error(`${le} citations failed:`,t)}finally{ko=!1}}function vu(){if(Ao)return;Ao=!0;let e=Date.now();try{let t=xu({}),s=Ou({});t.created+s.created>0&&console.log(`${le} l1: uuid=${t.created} plan=${s.created} (${Date.now()-e}ms)`)}catch(t){console.error(`${le} l1 failed:`,t)}finally{Ao=!1}}async function ju(){if(No)return;let e=ce();if(!e.enabled||e.backfillPaused)return;No=!0;let t=Date.now();try{let s=await cn({limit:25});s.processed>0&&console.log(`${le} backfill: processed=${s.processed} ok=${s.ok} failed=${s.failed} (${Date.now()-t}ms)`)}catch(s){console.error(`${le} backfill failed:`,s)}finally{No=!1}}async function Mu(){if(xo)return;let e=ce();if(!e.autoExtractEnabled)return;let t=e.autoExtractIntervalMinutes*60*1e3;if(Date.now()-Lu<t)return;if(!oe()){Oo||(console.log(`${le} auto-extract: claude CLI not on PATH \u2014 pausing nibbler (will retry; install Claude Code or run \`recall semantic auto-extract off\` to silence)`),Oo=!0);return}if(Oo=!1,!await Jo().catch(()=>!1)){Lo||(console.log(`${le} auto-extract: Pro license required \u2014 pausing nibbler (run \`recall semantic auto-extract off\` to silence; upgrade unlocks)`),Lo=!0);return}Lo=!1,xo=!0,Lu=Date.now();let n=Date.now();try{let r=e.autoExtractBatchSize,{eligible:o}=rt({limit:r});if(o.length===0)return;let a=0,c=0,d=0,u=0;for(let g of o){let h=await Er(g.id,{model:We});h.ok?a+=1:h.skipped||(c+=1),h.usage?.input_tokens&&(d+=h.usage.input_tokens),h.usage?.output_tokens&&(u+=h.usage.output_tokens)}console.log(`${le} auto-extract: processed=${o.length} ok=${a} failed=${c} tokens=${d}+${u} (${Date.now()-n}ms)`)}catch(r){console.error(`${le} auto-extract failed:`,r)}finally{xo=!1}}function Du(){let g=[],h=[];return g.push(setTimeout(()=>{Cu()},9e4)),h.push(setInterval(()=>{Cu()},18e5)),g.push(setTimeout(()=>{Iu()},18e4)),h.push(setInterval(()=>{Iu()},36e5)),g.push(setTimeout(()=>vu(),12e4)),h.push(setInterval(()=>vu(),18e5)),g.push(setTimeout(()=>{ju()},24e4)),h.push(setInterval(()=>{ju()},9e5)),g.push(setTimeout(()=>{Mu()},3e5)),h.push(setInterval(()=>{Mu()},9e5)),console.log(`${le} scheduled: bug-patterns (30m), citations (60m), l1 (30m), backfill (15m, when enabled), auto-extract (60m, when enabled)`),{startupTimers:g,intervalTimers:h,stop:()=>{for(let b of g)clearTimeout(b);for(let b of h)clearInterval(b)}}}var uT=360*60*1e3,pT=60*1e3,mT=1440*60*1e3,gT=300*1e3,_T=300*1e3,fT=10*1e3,hT=1440*60*1e3,ET=30*1e3,bT=500;async function ST(){let e=await hu(),t=Eu(),s=await uu(e,t);yu({pid:process.pid,port:e,startedAt:new Date().toISOString()});let n=gu(),r=()=>{try{_s()}catch(L){console.error("[daemon] suggestion scan failed:",L)}},o=setTimeout(r,pT),a=setInterval(r,uT),c=()=>{try{let L=I.reapStaleLinks();(L.pruned_pids||L.pruned_sessions)&&console.log(`[daemon] reaper: pruned ${L.pruned_pids} pid${L.pruned_pids===1?"":"s"}, ${L.pruned_sessions} session link${L.pruned_sessions===1?"":"s"}`)}catch(L){console.error("[daemon] stale-link reaper failed:",L)}},d=setTimeout(c,gT),u=setInterval(c,mT),g=()=>{try{let L=I.gcDeadPids();(L.pruned_pids||L.pruned_sessions)&&console.log(`[daemon] dead-pid gc: pruned ${L.pruned_pids} pid${L.pruned_pids===1?"":"s"}, ${L.pruned_sessions} session link${L.pruned_sessions===1?"":"s"}`)}catch(L){console.error("[daemon] dead-pid gc failed:",L)}},h=setTimeout(g,fT),b=setInterval(g,_T),S=()=>{qo().then(L=>{L.ran&&L.revoked&&console.log(`[daemon] license check: REVOKED${L.reason?` (${L.reason})`:""}`)}).catch(L=>{console.error("[daemon] license check failed:",L)})},y=setTimeout(S,ET),k=setInterval(S,hT),w=Du(),D=L=>{console.log(`[daemon] received ${L}, shutting down`),clearTimeout(o),clearInterval(a),clearTimeout(d),clearInterval(u),clearTimeout(h),clearInterval(b),clearTimeout(y),clearInterval(k),w.stop(),n.close(),s.close(),To(),process.exit(0)};process.on("SIGTERM",()=>D("SIGTERM")),process.on("SIGINT",()=>D("SIGINT")),process.on("SIGHUP",()=>D("SIGHUP")),console.log(`[daemon] ready on http://127.0.0.1:${e} pid=${process.pid}`),setTimeout(()=>{Ds().then(L=>{console.log(`[daemon] boot sweep: scanned ${L.scanned} live claude(s), linked ${L.linked}, renamed ${L.renamed}, ambiguous_cwd ${L.ambiguous_cwd}`)}).catch(L=>{console.error("[daemon] boot sweep failed:",L)})},bT)}ST().catch(e=>{console.error("[daemon] fatal:",e),To(),process.exit(1)});