@anmol-srv/sigil 0.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +15 -0
- package/README.md +417 -0
- package/dist/cli.js +1019 -0
- package/dist/hooks/post-tool-use.js +70 -0
- package/dist/hooks/session-end.js +222 -0
- package/dist/hooks/stop.js +259 -0
- package/dist/hooks/user-prompt-submit.js +279 -0
- package/dist/server.js +573 -0
- package/integrations/hermes/README.md +41 -0
- package/integrations/hermes/plugin/README.md +72 -0
- package/integrations/hermes/plugin/__init__.py +353 -0
- package/integrations/hermes/plugin/plugin.yaml +10 -0
- package/knexfile.js +15 -0
- package/package.json +100 -0
- package/prompts/audm-decision.md +31 -0
- package/prompts/chunk-context.md +23 -0
- package/prompts/default-extraction.md +35 -0
- package/prompts/entity-extraction.md +37 -0
- package/prompts/input-classifier.md +23 -0
- package/prompts/query-router.md +18 -0
- package/src/db/migrations/20260310120000_create-cortex-document-table.cjs +21 -0
- package/src/db/migrations/20260310120001_create-cortex-chunk-table.cjs +37 -0
- package/src/db/migrations/20260310120002_create-cortex-fact-table.cjs +37 -0
- package/src/db/migrations/20260310120003_create-cortex-entity-table.cjs +26 -0
- package/src/db/migrations/20260310120004_create-cortex-relation-table.cjs +27 -0
- package/src/db/migrations/20260310120005_create-cortex-history-table.cjs +16 -0
- package/src/db/migrations/20260311120000_add-entity-namespace-and-relation-indexes.cjs +32 -0
- package/src/db/migrations/20260312120000_add-fact-entity-linking.cjs +22 -0
- package/src/db/migrations/20260313093130_create-api-key-table.cjs +15 -0
- package/src/db/migrations/20260313120000_add-entity-dedup-support.cjs +13 -0
- package/src/db/migrations/20260313150000_create-connector-tables.cjs +46 -0
- package/src/db/migrations/20260318120000_add-contextual-chunk-prefix.cjs +11 -0
- package/src/db/migrations/20260318120001_add-fact-temporal-validity.cjs +15 -0
- package/src/db/migrations/20260318120002_add-fact-importance.cjs +11 -0
- package/src/db/migrations/20260318120003_add-fact-access-tracking.cjs +13 -0
- package/src/db/migrations/20260405120000_add-unique-constraints.cjs +58 -0
- package/src/db/migrations/20260405140000_create-llm-log-table.cjs +21 -0
- package/src/db/migrations/20260424120000_split-fact-lifecycle.cjs +86 -0
- package/src/db/migrations/20260424120002_create-embedding-cache.cjs +26 -0
- package/src/db/migrations/20260429120000_halfvec-index-compression.cjs +34 -0
- package/src/db/migrations/20260429120100_create-hebbian-edge-table.cjs +37 -0
- package/src/db/migrations/20260429120200_upgrade-embedding-dim-1024.cjs +68 -0
- package/src/db/migrations/20260504120000_scope-document-source-path-uniqueness.cjs +45 -0
- package/src/db/migrations/20260508001733_add-entity-aliases.cjs +42 -0
- package/src/db/migrations/20260512120000_create-entity-hebbian-edge.cjs +42 -0
- package/src/db/migrations/20260512120000_create-pod-tables.cjs +71 -0
- package/src/db/migrations/20260512120100_create-pod-membership.cjs +50 -0
- package/src/db/migrations/20260512120200_add-document-source-metadata.cjs +32 -0
- package/src/db/migrations/20260514023428_rewrite-session-pods-and-add-fact-attribution-columns.cjs +86 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var oo=Object.defineProperty;var m=(e,t)=>()=>(e&&(t=e(e=0)),t);var E=(e,t)=>{for(var o in t)oo(e,o,{get:t[o],enumerable:!0})};import{fileURLToPath as co}from"node:url";import{dirname as ge,join as h}from"node:path";import{existsSync as ye}from"node:fs";import{homedir as uo}from"node:os";function lo(){let e=ge(co(import.meta.url));for(let t=0;t<10;t++){if(ye(h(e,"package.json"))&&ye(h(e,"prompts")))return e;let o=ge(e);if(o===e)break;e=o}return process.cwd()}var we,Oe,br,Ie,T,H,Rr,Dr,Lr,Se,Te,Ae,Nr,be,Re,vr,Pr,L=m(()=>{we=lo(),Oe=h(we,"prompts"),br=h(we,"src","db","migrations"),Ie=uo(),T=h(Ie,".sigil"),H=h(T,".env"),Rr=h(T,"db"),Dr=h(T,"CLAUDE.md"),Lr=h(T,"schemas"),Se=h(T,".hook-errors.log"),Te=h(T,".last-clean-doctor"),Ae=h(T,".active-session.json"),Nr=h(T,".stop-cursor.json"),be=h(T,".hook-dedup.json"),Re=h(Ie,".claude"),vr=h(Re,"settings.json"),Pr=h(Re,"CLAUDE.md")});var Pe={};E(Pe,{default:()=>a});var g,ve,mo,a,y=m(()=>{g=(e,t)=>process.env[e]??t,ve=g("SIGIL_DB_TYPE","postgres");if(ve!=="postgres")throw new Error(`SIGIL_DB_TYPE=${ve} is no longer supported. Sigil 0.10.0+ is Postgres-only.
|
|
3
|
+
PGlite was deprecated; existing PGlite data at ~/.sigil/db is preserved but unreachable from this version.
|
|
4
|
+
Set SIGIL_DB_TYPE=postgres in ~/.sigil/.env and configure SIGIL_DB_HOST / PORT / NAME / USER / PASSWORD.
|
|
5
|
+
Run \`sigil init\` for an interactive setup.`);mo={db:{type:"postgres",host:g("SIGIL_DB_HOST","localhost"),port:Number(g("SIGIL_DB_PORT",5432)),database:g("SIGIL_DB_NAME","sigil"),user:g("SIGIL_DB_USER","sigil_app"),password:g("SIGIL_DB_PASSWORD","")},embedding:{provider:process.env.EMBEDDING_PROVIDER||"",model:process.env.EMBEDDING_MODEL||"nomic-embed-text",dimensions:Number(process.env.EMBEDDING_DIMENSIONS)||768,ollamaHost:process.env.OLLAMA_HOST||"http://localhost:11434",openaiApiKey:process.env.OPENAI_API_KEY||"",voyageApiKey:process.env.VOYAGE_API_KEY||"",openrouterApiKey:process.env.OPENROUTER_API_KEY||"",openrouterBaseUrl:process.env.EMBEDDING_OPENROUTER_BASE_URL||process.env.LLM_OPENROUTER_BASE_URL||"",openrouterReferer:process.env.EMBEDDING_OPENROUTER_REFERER||process.env.LLM_OPENROUTER_REFERER||"https://github.com/Anmol-Srv/sigil",openrouterTitle:process.env.EMBEDDING_OPENROUTER_TITLE||process.env.LLM_OPENROUTER_TITLE||"Sigil"},llm:{provider:process.env.LLM_PROVIDER||"",openaiApiKey:process.env.OPENAI_API_KEY||"",openaiModel:process.env.LLM_OPENAI_MODEL||"gpt-4o-mini",ollamaHost:process.env.LLM_OLLAMA_HOST||process.env.OLLAMA_HOST||"http://localhost:11434",ollamaModel:process.env.LLM_OLLAMA_MODEL||"qwen2.5:7b",cliModel:process.env.LLM_CLI_MODEL||"haiku",apiKey:process.env.ANTHROPIC_API_KEY||"",openrouterApiKey:process.env.OPENROUTER_API_KEY||"",openrouterModel:process.env.LLM_OPENROUTER_MODEL||"google/gemini-flash-latest",openrouterBaseUrl:process.env.LLM_OPENROUTER_BASE_URL||"",openrouterReferer:process.env.LLM_OPENROUTER_REFERER||"https://github.com/Anmol-Srv/sigil",openrouterTitle:process.env.LLM_OPENROUTER_TITLE||"Sigil",extractionModel:process.env.LLM_EXTRACTION_MODEL||"",decisionModel:process.env.LLM_DECISION_MODEL||"",entityModel:process.env.LLM_ENTITY_MODEL||"",maxRetries:Number(process.env.LLM_MAX_RETRIES)||3,cliTimeout:Number(process.env.LLM_CLI_TIMEOUT)||12e4},output:{storage:process.env.OUTPUT_STORAGE||"local",dir:process.env.OUTPUT_DIR||"./output",s3:{endpoint:process.env.S3_ENDPOINT||"",bucket:process.env.S3_BUCKET||"",region:process.env.S3_REGION||"us-east-1",accessKey:process.env.S3_ACCESS_KEY||"",secretKey:process.env.S3_SECRET_KEY||"",publicUrl:process.env.S3_PUBLIC_URL||""}},server:{port:Number(process.env.PORT)||4e3,host:process.env.HOST||"0.0.0.0",logLevel:process.env.LOG_LEVEL||"info"},defaults:{namespace:process.env.DEFAULT_NAMESPACE||"default"},memory:{skipThreshold:Number(process.env.MEMORY_SKIP_THRESHOLD)||.88,ambiguousThreshold:Number(process.env.MEMORY_AMBIGUOUS_THRESHOLD)||.78,minFactSimilarity:Number(process.env.MEMORY_MIN_FACT_SIMILARITY)||.45},search:{synthesize:g("SIGIL_SYNTHESIZE","true")!=="false",synthesizeModel:g("SIGIL_SYNTH_MODEL","")},ingest:{eagerExtract:g("SIGIL_EAGER_EXTRACT","true")!=="false"},hebbian:{entity:{enabled:g("SIGIL_HEBBIAN_ENTITY_ENABLED",null,"true")!=="false",eta:Number(g("SIGIL_HEBBIAN_ENTITY_ETA",null,1)),cap:Number(g("SIGIL_HEBBIAN_ENTITY_CAP",null,50)),halfLifeDays:Number(g("SIGIL_HEBBIAN_ENTITY_HALF_LIFE_DAYS",null,30)),minEffective:Number(g("SIGIL_HEBBIAN_ENTITY_MIN_EFFECTIVE",null,.5)),rrfWeight:Number(g("SIGIL_HEBBIAN_ENTITY_RRF_WEIGHT",null,.3)),maxWriteEntities:Number(g("SIGIL_HEBBIAN_ENTITY_MAX_WRITE",null,12)),expandPerSeed:Number(g("SIGIL_HEBBIAN_ENTITY_EXPAND_PER_SEED",null,3))}}},a=mo});var G={};E(G,{default:()=>d});import fo from"knex";function Eo(e){return Array.isArray(e)?e.map(z):e&&typeof e=="object"?z(e):e}function ho(e,t){return t(go(e))}function z(e){if(!e||typeof e!="object"||e instanceof Date)return e;if(Array.isArray(e))return e.map(z);let t={};for(let[o,n]of Object.entries(e))t[o.replace(/_([a-z])/g,(r,s)=>s.toUpperCase())]=n;return t}function go(e){return e.replace(/[A-Z]/g,t=>`_${t.toLowerCase()}`)}var _o,d,R=m(()=>{y();_o=fo({client:"pg",connection:{host:a.db.host,port:a.db.port,database:a.db.database,user:a.db.user,password:a.db.password},pool:{min:2,max:10},postProcessResponse:Eo,wrapIdentifier:ho});d=_o});var Be={};E(Be,{validateConfig:()=>ke,validateConfigDeep:()=>yo});function ke(){let e=[];return wo(e),Oo(e),Io(e),e}async function yo(){let e=ke();if(a.db.type==="postgres"&&!e.some(t=>t.code.startsWith("DB_")))try{await(await Promise.resolve().then(()=>(R(),G))).default.raw("SELECT 1")}catch(t){e.push({level:"fail",code:"DB_UNREACHABLE",message:`Postgres at ${a.db.host}:${a.db.port}/${a.db.database} unreachable: ${t.message.split(`
|
|
6
|
+
`)[0]}`,fix:"Start Postgres (e.g. `docker start sigil-pg` or your equivalent) and verify SIGIL_DB_HOST/PORT/NAME/USER/PASSWORD in ~/.sigil/.env"})}return e}function wo(e){let{provider:t,model:o}=a.embedding;if(t&&o){let n=Object.keys(Ce).find(r=>Ce[r].some(s=>s.test(o)));n&&n!==t&&e.push({level:"fail",code:"EMBEDDING_PROVIDER_MODEL_MISMATCH",message:`EMBEDDING_PROVIDER=${t} but EMBEDDING_MODEL=${o} is a ${n} model.`,fix:So(t,o,n)})}if(t&&xe[t]){let n=xe[t];a.embedding[n]||e.push({level:"fail",code:"EMBEDDING_PROVIDER_MISSING_KEY",message:`EMBEDDING_PROVIDER=${t} but no ${$(n)} found.`,fix:`Set ${$(n)} in ~/.sigil/.env, or run 'sigil init' to reconfigure.`})}}function Oo(e){let{provider:t}=a.llm;if(t&&Me[t]){let o=Me[t];a.llm[o]||e.push({level:"fail",code:"LLM_PROVIDER_MISSING_KEY",message:`LLM_PROVIDER=${t} but no ${$(o)} found.`,fix:`Set ${$(o)} in ~/.sigil/.env, or run 'sigil init' to reconfigure.`})}t==="openrouter"&&a.llm.openrouterModel&&(a.llm.openrouterModel.includes("/")||e.push({level:"warn",code:"OPENROUTER_MODEL_FORMAT",message:`LLM_OPENROUTER_MODEL=${a.llm.openrouterModel} doesn't look like vendor/model format.`,fix:'Use format like "anthropic/claude-haiku-4-5" or "google/gemini-2.5-flash".'}))}function Io(e){a.db.type==="postgres"&&(!a.db.host||!a.db.database||!a.db.user)&&e.push({level:"fail",code:"DB_CONFIG_INCOMPLETE",message:"SIGIL_DB_TYPE=postgres but host/database/user missing.",fix:"Set SIGIL_DB_HOST, SIGIL_DB_NAME, SIGIL_DB_USER, SIGIL_DB_PASSWORD in ~/.sigil/.env. Run `sigil init` for an interactive setup."})}function $(e){return{openaiApiKey:"OPENAI_API_KEY",apiKey:"ANTHROPIC_API_KEY",openrouterApiKey:"OPENROUTER_API_KEY",voyageApiKey:"VOYAGE_API_KEY"}[e]||e}function So(e,t,o){let n={voyage:"voyage-3.5, voyage-3-large, voyage-code-3.5",openai:"text-embedding-3-large, text-embedding-3-small",ollama:"nomic-embed-text, mxbai-embed-large"}[e]||"(see provider docs)";return`Either set EMBEDDING_PROVIDER=${o} (matches your current model), or change EMBEDDING_MODEL to one of: ${n}`}var Ce,Me,xe,Ue=m(()=>{y();Ce={voyage:[/^voyage-/],openai:[/^text-embedding-/],ollama:[/^nomic-embed/,/^mxbai-embed/,/^all-minilm/,/^bge-/,/^snowflake-/,/^granite-embedding/]},Me={openai:"openaiApiKey",anthropic:"apiKey",openrouter:"openrouterApiKey"},xe={openai:"openaiApiKey",voyage:"voyageApiKey",openrouter:"openrouterApiKey"}});var Q={};E(Q,{HOOK_ERROR_LOG:()=>K,LAST_CLEAN_DOCTOR_PATH:()=>F,clearLastCleanDoctor:()=>Po,failClosedOnBadConfig:()=>Do,getUnackedErrorCount:()=>No,markDoctorClean:()=>vo,readRecentHookErrors:()=>Lo,recordHookError:()=>He});import{appendFile as To,readFile as X,writeFile as Ao,unlink as bo}from"node:fs/promises";import{createHash as Ro}from"node:crypto";async function He(e,t,o=null){try{let n={ts:new Date().toISOString(),hook:e,error:t?.message||String(t),input_hash:o?Co(o):null};await To(K,JSON.stringify(n)+`
|
|
7
|
+
`,"utf8")}catch{}}async function Do(e,t=null){try{let{validateConfig:o}=await Promise.resolve().then(()=>(Ue(),Be)),n=o().filter(r=>r.level==="fail");if(n.length===0)return!1;for(let r of n){let s=new Error(`${r.code}: ${r.message} \u2014 fix: ${r.fix}`);await He(e,s,t)}return!0}catch{return!1}}async function Lo(e=10){let t;try{t=await X(K,"utf8")}catch{return[]}let o=t.split(`
|
|
8
|
+
`).filter(Boolean),n=[];for(let r of o.slice(-e))try{n.push(JSON.parse(r))}catch{}return n}async function No(){let e=0;try{let n=await X(F,"utf8");e=new Date(n.trim()).getTime()}catch{}let t;try{t=await X(K,"utf8")}catch{return 0}let o=0;for(let n of t.split(`
|
|
9
|
+
`))if(n.trim())try{let r=JSON.parse(n);(r.ts?new Date(r.ts).getTime():0)>e&&(o+=1)}catch{}return o}async function vo(){try{await Ao(F,new Date().toISOString(),"utf8")}catch{}}async function Po(){try{await bo(F)}catch{}}function Co(e){try{let t=typeof e=="string"?e:JSON.stringify(e);return Ro("sha256").update(t).digest("hex").slice(0,12)}catch{return null}}var K,F,ee=m(()=>{L();K=Se,F=Te});var Ge,$e=m(()=>{Ge="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict"});import{webcrypto as Ke}from"node:crypto";function xo(e){!D||D.length<e?(D=Buffer.allocUnsafe(e*Mo),Ke.getRandomValues(D),N=0):N+e>D.length&&(Ke.getRandomValues(D),N=0),N+=e}function Y(e=21){xo(e|=0);let t="";for(let o=N-e;o<N;o++)t+=Ge[D[o]&63];return t}var Mo,D,N,te=m(()=>{$e();Mo=128});var Fe={};E(Fe,{chat:()=>ko,meta:()=>Bo,setup:()=>Uo});async function ko(e,{model:t,jsonMode:o=!1}={}){let n=t||a.llm.openaiModel,r=[{role:"user",content:e}];o&&!e.toLowerCase().includes("json")&&r.unshift({role:"system",content:"Respond with valid JSON."});let s={model:n,messages:r};o&&(s.response_format={type:"json_object"});let c=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${a.llm.openaiApiKey}`},body:JSON.stringify(s)});if(!c.ok){let p=await c.text();throw new Error(`OpenAI error ${c.status}: ${p}`)}let i=await c.json(),u=i.choices[0].message.content.trim(),l=i.usage||{};return{text:u,inputTokens:l.prompt_tokens||0,outputTokens:l.completion_tokens||0,model:n}}async function Uo({existing:e,clack:t}){let o=e.OPENAI_API_KEY||"",n=await t.text({message:"OpenAI API key (paste, then Enter)",placeholder:o?"(keep existing \u2014 press Enter)":"sk-proj-...",validate:r=>{if(!r&&!o)return"API key is required";if(r&&!r.startsWith("sk-"))return'OpenAI keys start with "sk-" \u2014 check paste'}});return t.isCancel(n)?null:{env:{OPENAI_API_KEY:n||o}}}var Bo,Ye=m(()=>{y();Bo={id:"openai",label:"OpenAI",hint:"gpt-4o-mini"}});function A(e){return Math.ceil((e||"").length/4)}function je(e,t,o){let n=Ho[e];return n?(t*n.input+o*n.output)/1e6:0}function oe({provider:e,model:t,caller:o,input:n,response:r,inputTokens:s,outputTokens:c,cost:i,durationMs:u,status:l,error:p}){d("llm_log").insert({provider:e,model:t,caller:o,input:n?.slice(0,1e4),response:r?.slice(0,1e4),inputTokens:s,outputTokens:c,cost:i,durationMs:u,status:l,error:p?.slice(0,2e3)}).catch(w=>console.error("[llm-log] Write failed:",w.message))}async function We(e,t=3){for(let o=1;o<=t;o++)try{return await e()}catch(n){if(o===t)throw n;let r=Math.min(1e3*2**(o-1),1e4);await new Promise(s=>setTimeout(s,r))}}var Ho,C=m(()=>{R();Ho={"gpt-4o-mini":{input:.15,output:.6},"gpt-4o":{input:2.5,output:10},"gpt-4.1-nano":{input:.1,output:.4},"gpt-4.1-mini":{input:.4,output:1.6},"claude-haiku-4-5-20251001":{input:.8,output:4},"claude-sonnet-4-6":{input:3,output:15},"claude-opus-4-6":{input:15,output:75}}});var Ve={};E(Ve,{chat:()=>$o,meta:()=>Ko,setup:()=>Fo});async function Go(){if(!ne){let{default:e}=await import("@anthropic-ai/sdk");ne=new e({apiKey:a.llm.apiKey})}return ne}async function $o(e,{model:t,jsonMode:o=!1}={}){let n=t||"claude-haiku-4-5-20251001",r=await Go(),s=[{role:"user",content:e}],c=o?"Respond with valid JSON only. No explanation or wrapping.":void 0,i=await r.messages.create({model:n,max_tokens:4096,messages:s,...c&&{system:c}});return{text:i.content[0].text.trim(),inputTokens:i.usage?.input_tokens||A(e),outputTokens:i.usage?.output_tokens||A(i.content[0].text),model:n}}async function Fo({existing:e,clack:t}){let o=e.ANTHROPIC_API_KEY||"",n=await t.text({message:"Anthropic API key (paste, then Enter)",placeholder:o?"(keep existing \u2014 press Enter)":"sk-ant-...",validate:r=>{if(!r&&!o)return"API key is required";if(r&&!r.startsWith("sk-ant-"))return'Anthropic keys start with "sk-ant-" \u2014 check paste'}});return t.isCancel(n)?null:{env:{ANTHROPIC_API_KEY:n||o}}}var ne,Ko,Je=m(()=>{y();C();ne=null;Ko={id:"anthropic",label:"Anthropic",hint:"Claude Haiku \u2014 requires API key"}});var qe={};E(qe,{chat:()=>jo,meta:()=>Wo,setup:()=>Vo});async function jo(e,{model:t,jsonMode:o=!1}={}){let n=t||a.llm.openrouterModel;if(!a.llm.openrouterApiKey)throw new Error("OPENROUTER_API_KEY is not set");if(!n)throw new Error("No OpenRouter model resolved. Set LLM_OPENROUTER_MODEL or pass `model`.");let r=[{role:"user",content:e}];o&&!e.toLowerCase().includes("json")&&r.unshift({role:"system",content:"Respond with valid JSON."});let s={model:n,messages:r};o&&(s.response_format={type:"json_object"});let c=(a.llm.openrouterBaseUrl||Yo).replace(/\/+$/,""),i={"Content-Type":"application/json",Authorization:`Bearer ${a.llm.openrouterApiKey}`};a.llm.openrouterReferer&&(i["HTTP-Referer"]=a.llm.openrouterReferer),a.llm.openrouterTitle&&(i["X-Title"]=a.llm.openrouterTitle);let u=await fetch(`${c}/chat/completions`,{method:"POST",headers:i,body:JSON.stringify(s)});if(!u.ok){let f=await u.text();throw new Error(`OpenRouter error ${u.status}: ${f}`)}let l=await u.json(),w=(l.choices?.[0]?.message?.content||"").trim(),_=l.usage||{};return{text:w,inputTokens:_.prompt_tokens||0,outputTokens:_.completion_tokens||0,model:l.model||n}}async function Vo({existing:e,clack:t}){let o={},n=e.OPENROUTER_API_KEY||"",r=await t.text({message:"OpenRouter API key (paste, then Enter)",placeholder:n?"(keep existing \u2014 press Enter)":"sk-or-v1-...",validate:u=>{if(!u&&!n)return"API key is required";if(u&&!u.startsWith("sk-or-"))return'OpenRouter keys start with "sk-or-" \u2014 check paste'}});if(t.isCancel(r))return null;o.OPENROUTER_API_KEY=r||n;let s=e.LLM_OPENROUTER_MODEL||"",c=await t.text({message:"OpenRouter model (vendor/model)",placeholder:s||Ze,validate:u=>{if(u&&!u.includes("/"))return'OpenRouter models are "vendor/model" \u2014 e.g. google/gemini-flash-latest'}});if(t.isCancel(c))return null;o.LLM_OPENROUTER_MODEL=c||s||Ze;let i=await t.select({message:"Configure per-task model overrides? (advanced \u2014 better quality / cost)",options:[{value:"no",label:"No, use one model everywhere",hint:"simpler \u2014 debug one model"},{value:"yes",label:"Yes, configure smart split",hint:"~5\xD7 cheaper extraction + better AUDM/synthesis"}],initialValue:"no"});if(t.isCancel(i))return null;if(i==="yes"){let u=await t.text({message:"Extraction model (high-volume; cheap matters)",placeholder:e.LLM_EXTRACTION_MODEL||v.extraction});if(t.isCancel(u))return null;o.LLM_EXTRACTION_MODEL=u||e.LLM_EXTRACTION_MODEL||v.extraction;let l=await t.text({message:"Decision model (AUDM; smart matters)",placeholder:e.LLM_DECISION_MODEL||v.decision});if(t.isCancel(l))return null;o.LLM_DECISION_MODEL=l||e.LLM_DECISION_MODEL||v.decision;let p=await t.text({message:"Synthesis model (read-time answer composition)",placeholder:e.SIGIL_SYNTH_MODEL||v.synthesis});if(t.isCancel(p))return null;o.SIGIL_SYNTH_MODEL=p||e.SIGIL_SYNTH_MODEL||v.synthesis}return t.note(`OpenRouter can drive both LLM calls and embeddings.
|
|
10
|
+
You will pick an embedding provider in the next step \u2014 "openrouter" is an option,
|
|
11
|
+
or you can use a direct provider (Ollama / OpenAI / Voyage) for embeddings.`,"OpenRouter scope"),{env:o}}var Yo,Wo,Ze,v,ze=m(()=>{y();Yo="https://openrouter.ai/api/v1";Wo={id:"openrouter",label:"OpenRouter",hint:"one key, many models (Anthropic / OpenAI / Meta / ...)"},Ze="google/gemini-flash-latest",v={extraction:"openrouter:qwen/qwen3.5-flash",decision:"openrouter:anthropic/claude-sonnet-latest",synthesis:"openrouter:anthropic/claude-sonnet-latest"}});var Xe={};E(Xe,{chat:()=>Xo,meta:()=>Qo,setup:()=>en});import{spawn as Jo}from"node:child_process";function zo(e,t){let o=a.llm.cliTimeout||12e4;return new Promise((n,r)=>{let s=Jo("claude",e,{stdio:["pipe","pipe","pipe"]}),c=setTimeout(()=>{s.kill("SIGTERM"),r(new Error(`claude CLI timed out after ${o}ms`))},o),i="",u="";s.stdout.on("data",l=>{i+=l}),s.stderr.on("data",l=>{u+=l}),s.on("error",l=>{clearTimeout(c),r(new Error(`Failed to spawn claude CLI: ${l.message}`))}),s.on("close",l=>{clearTimeout(c),n({stdout:i,stderr:u,code:l})}),s.stdin.write(t),s.stdin.end()})}async function Xo(e,{model:t,jsonMode:o=!1}={}){let n=t||a.llm.cliModel||"haiku",r=Zo[n]||n,s=["-p","--model",r,"--output-format","json"];o&&s.push("--json-schema",qo);let{stdout:c,stderr:i,code:u}=await zo(s,e);if(u!==0)throw new Error(`claude CLI exited ${u}: ${(i||c).slice(0,500)}`);let l;try{l=JSON.parse(c)}catch{return{text:c.trim(),inputTokens:A(e),outputTokens:A(c),model:r}}if(l.is_error)throw new Error(`claude CLI error: ${l.result||"unknown error"}`);let p=o&&l.structured_output?JSON.stringify(l.structured_output):(l.result||"").trim(),w=l.usage||{};return{text:p,inputTokens:w.input_tokens||A(e),outputTokens:w.output_tokens||A(p),model:r,cost:l.total_cost_usd||0}}async function en(){return{env:{}}}var Zo,qo,Qo,Qe=m(()=>{y();C();Zo={"claude-haiku-4-5-20251001":"haiku","claude-sonnet-4-6":"sonnet","claude-opus-4-6":"opus"},qo=JSON.stringify({type:"object",additionalProperties:!0});Qo={id:"claude-cli",label:"Claude Code",hint:"uses your existing subscription \u2014 no extra API key"}});var et={};E(et,{chat:()=>tn,meta:()=>on,setup:()=>nn});async function tn(e,{model:t,jsonMode:o=!1}={}){let n=t||a.llm.ollamaModel,r=`${a.llm.ollamaHost}/api/chat`,s={model:n,messages:[{role:"user",content:e}],stream:!1};o&&(s.format="json");let c=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!c.ok){let u=await c.text();throw new Error(`Ollama error ${c.status}: ${u}`)}let i=await c.json();return{text:i.message.content.trim(),inputTokens:i.prompt_eval_count||A(e),outputTokens:i.eval_count||A(i.message.content),model:n}}async function nn({existing:e,clack:t}){let o=e.OLLAMA_HOST||"http://localhost:11434",n=await t.text({message:"Ollama host",placeholder:o,initialValue:o,validate:r=>{if(r&&!/^https?:\/\//.test(r))return"Must start with http:// or https://"}});return t.isCancel(n)?null:{env:{OLLAMA_HOST:n||o}}}var on,tt=m(()=>{y();C();on={id:"ollama",label:"Ollama",hint:"local models \u2014 no API cost"}});function j(e,t){if(t<1)return[];let o=[];for(let n=0;n<e.length;n+=t)o.push(e.slice(n,n+t));return o}var re=m(()=>{});var ot={};E(ot,{embedBatch:()=>sn});async function sn(e,{model:t,ollamaHost:o}){let n=j(e,rn),r=[];for(let s of n){let c=await fetch(`${o}/api/embed`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:t,input:s})});if(!c.ok)throw new Error(`Ollama embed failed: ${c.status} ${await c.text()}`);let i=await c.json();r.push(...i.embeddings)}return r}var rn,nt=m(()=>{re();rn=50});var rt={};E(rt,{embedBatch:()=>an});async function an(e,{model:t,openaiApiKey:o,dimensions:n}={}){let r={model:t,input:e};n&&/^text-embedding-3/.test(t)&&(r.dimensions=n);let s=await fetch("https://api.openai.com/v1/embeddings",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify(r)});if(!s.ok)throw new Error(`OpenAI embed failed: ${s.status} ${await s.text()}`);return(await s.json()).data.map(i=>i.embedding)}var st=m(()=>{});var it={};E(it,{embedBatch:()=>un});async function un(e,{model:t,voyageApiKey:o,inputType:n="document",dimensions:r}={}){if(!o)throw new Error("VOYAGE_API_KEY is not set. Get one at dashboard.voyageai.com.");let s=j(e,cn),c=[];for(let i of s){let u={input:i,model:t||"voyage-3-large",input_type:n==="query"?"query":"document"};r&&(u.output_dimension=r);let l=await fetch("https://api.voyageai.com/v1/embeddings",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify(u)});if(!l.ok){let _=await l.text();throw new Error(`Voyage embed failed: ${l.status} ${_}`)}let w=[...(await l.json()).data].sort((_,f)=>_.index-f.index);c.push(...w.map(_=>_.embedding))}return c}var cn,at=m(()=>{re();cn=50});var ct={};E(ct,{embedBatch:()=>dn});async function dn(e,{model:t,openrouterApiKey:o,openrouterBaseUrl:n,openrouterReferer:r,openrouterTitle:s,dimensions:c}={}){if(!o)throw new Error("OPENROUTER_API_KEY is not set");if(!t)throw new Error('No OpenRouter embedding model resolved. Set EMBEDDING_MODEL (e.g. "openai/text-embedding-3-large").');let i={model:t,input:e};c&&/(^|\/)text-embedding-3/.test(t)&&(i.dimensions=c);let u=(n||ln).replace(/\/+$/,""),l={"Content-Type":"application/json",Authorization:`Bearer ${o}`};r&&(l["HTTP-Referer"]=r),s&&(l["X-Title"]=s);let p=await fetch(`${u}/embeddings`,{method:"POST",headers:l,body:JSON.stringify(i)});if(!p.ok)throw new Error(`OpenRouter embed failed: ${p.status} ${await p.text()}`);return[...(await p.json()).data].sort((f,S)=>f.index-S.index).map(f=>f.embedding)}var ln,ut=m(()=>{ln="https://openrouter.ai/api/v1"});import{spawn as pn}from"node:child_process";async function dt(e){if(!se[e]){let t=ae[e];if(!t)throw new Error(`Unknown LLM provider: "${e}". Available: ${Object.keys(ae).join(", ")}`);let o=await t();se[e]=o.chat}return se[e]}async function pt(e){if(!ie[e]){let t=lt[e];if(!t)throw new Error(`Unknown embedding provider: "${e}". Available: ${Object.keys(lt).join(", ")}`);let o=await t();ie[e]=o.embedBatch}return ie[e]}function mt(e,t){if(!e)return{provider:t,model:null};let o=e.indexOf(":");return o>0&&ae[e.slice(0,o)]?{provider:e.slice(0,o),model:e.slice(o+1)}:{provider:t,model:e}}async function ft(){let e=a.llm.ollamaHost||a.embedding.ollamaHost||"http://localhost:11434";try{return(await fetch(`${e}/api/tags`,{signal:AbortSignal.timeout(2e3)})).ok}catch{return!1}}function mn(){return new Promise(e=>{let t=pn("claude",["--version"],{stdio:"pipe"});t.on("error",()=>e(!1)),t.on("close",o=>e(o===0)),setTimeout(()=>{t.kill(),e(!1)},3e3)})}async function _t(){if(O)return O;if(a.llm.provider)return O=a.llm.provider,O;if(a.llm.openrouterApiKey)return O="openrouter",O;if(a.llm.apiKey)return O="anthropic",O;if(a.llm.openaiApiKey)return O="openai",O;if(await ft())return O="ollama",O;if(await mn())return O="claude-cli",O;throw new Error(`No LLM provider available. Either:
|
|
12
|
+
- Set LLM_PROVIDER (openai, anthropic, openrouter, ollama, claude-cli)
|
|
13
|
+
- Set ANTHROPIC_API_KEY, OPENAI_API_KEY, or OPENROUTER_API_KEY
|
|
14
|
+
- Start Ollama locally
|
|
15
|
+
- Install the Claude CLI (claude)`)}async function Et(){if(I)return I;if(a.embedding.provider)return I=a.embedding.provider,I;if(a.embedding.voyageApiKey)return I="voyage",I;if(await ft())return I="ollama",I;if(a.embedding.openaiApiKey)return I="openai",I;if(a.embedding.openrouterApiKey)return I="openrouter",I;throw new Error(`No embedding provider available. Either:
|
|
16
|
+
- Set EMBEDDING_PROVIDER (voyage, ollama, openai, openrouter)
|
|
17
|
+
- Set VOYAGE_API_KEY (recommended \u2014 best quality)
|
|
18
|
+
- Start Ollama locally
|
|
19
|
+
- Set OPENAI_API_KEY
|
|
20
|
+
- Set OPENROUTER_API_KEY (and EMBEDDING_MODEL like "openai/text-embedding-3-large")`)}var ae,lt,se,ie,O,I,ce=m(()=>{y();ae={openai:()=>Promise.resolve().then(()=>(Ye(),Fe)),anthropic:()=>Promise.resolve().then(()=>(Je(),Ve)),openrouter:()=>Promise.resolve().then(()=>(ze(),qe)),"claude-cli":()=>Promise.resolve().then(()=>(Qe(),Xe)),ollama:()=>Promise.resolve().then(()=>(tt(),et))},lt={ollama:()=>Promise.resolve().then(()=>(nt(),ot)),openai:()=>Promise.resolve().then(()=>(st(),rt)),voyage:()=>Promise.resolve().then(()=>(at(),it)),openrouter:()=>Promise.resolve().then(()=>(ut(),ct))},se={},ie={};O=null,I=null});function M(e){return e?`[${e.join(",")}]`:null}function ht(){let e=Number(a.embedding.dimensions)||768;if(!Number.isInteger(e)||e<=0)throw new Error(`Invalid EMBEDDING_DIMENSIONS: ${a.embedding.dimensions}`);return e}function gt(e="embedding"){return`(${e}::halfvec(${ht()}))`}function yt(){return`?::halfvec(${ht()})`}var ue=m(()=>{y()});import{createHash as fn}from"node:crypto";function En(e,t,o,n="document"){let r=fn("sha256");return r.update(e),r.update("\0"),r.update(t),r.update("\0"),r.update(n),r.update("\0"),r.update(o),r.digest("hex")}async function hn(e){if(!e.length)return new Map;let t=await d("embedding_cache").whereIn("key",e).select("key","embedding");return new Map(t.map(o=>[o.key,gn(o.embedding)]))}function gn(e){return Array.isArray(e)||typeof e!="string"?e:(e.startsWith("[")?e.slice(1,-1):e).split(",").map(Number)}async function yn(e){e.length&&await d("embedding_cache").whereIn("key",e).update({hits:d.raw("hits + 1"),lastUsedAt:d.fn.now()})}async function wn(e,t,o){if(e.length){for(let{key:n,embedding:r}of e)await d.raw(`
|
|
21
|
+
INSERT INTO embedding_cache (key, provider, model, embedding, hits, created_at, last_used_at)
|
|
22
|
+
VALUES (?, ?, ?, ?, 0, NOW(), NOW())
|
|
23
|
+
ON CONFLICT (key) DO UPDATE
|
|
24
|
+
SET last_used_at = NOW(),
|
|
25
|
+
hits = embedding_cache.hits + 1
|
|
26
|
+
`,[n,t,o,M(r)]);await In()}}async function In(){let e=Date.now();if(e-Ot<On)return;Ot=e;let[{count:t}]=await d("embedding_cache").count("key as count"),o=Number(t);if(o<=wt)return;let n=Math.min(o-wt,_n);await d.raw(`
|
|
27
|
+
DELETE FROM embedding_cache WHERE key IN (
|
|
28
|
+
SELECT key FROM embedding_cache ORDER BY last_used_at ASC LIMIT ?
|
|
29
|
+
)
|
|
30
|
+
`,[n])}async function It(e,t,o,n,r,s={}){if(!e.length)return[];let c=s.inputType||r?.inputType||"document",i=e.map(f=>En(t,o,f,c)),u=await hn(i),l=[],p=[],w=new Array(e.length);for(let f=0;f<e.length;f++){let S=u.get(i[f]);S?w[f]=S:(l.push(e[f]),p.push(f))}if(l.length){let f=await n(l,r),S=[];for(let b=0;b<l.length;b++){let U=p[b];w[U]=f[b],S.push({key:i[U],embedding:f[b]})}wn(S,t,o).catch(b=>{process.stderr.write(`[embedding-cache] store failed: ${b.message}
|
|
31
|
+
`)})}let _=i.filter(f=>u.has(f));return _.length&&yn(_).catch(()=>{}),w}var wt,_n,Ot,On,St=m(()=>{ue();R();wt=1e4,_n=500;Ot=0,On=6e4});var At={};E(At,{dimensions:()=>Sn,embed:()=>le,embedBatch:()=>Tt});async function le(e,t={}){let[o]=await Tt([e],t);return o}async function Tt(e,{inputType:t="document"}={}){if(!e.length)return[];let o=await Et(),n=await pt(o),r=a.embedding.model,s={...a.embedding,inputType:t};return It(e,o,r,n,s,{inputType:t})}var Sn,de=m(()=>{y();ce();St();({dimensions:Sn}=a.embedding)});async function Tn(e){let t=await _t();return mt(e,t)}async function bt(e,{model:t,caller:o}={}){let{provider:n,model:r}=await Tn(t),s=await dt(n),c=Date.now();try{let i=await We(()=>s(e,{model:r,jsonMode:!1}),a.llm.maxRetries),u=i.cost||je(i.model,i.inputTokens,i.outputTokens);return oe({provider:n,model:i.model,caller:o,input:e,response:i.text,inputTokens:i.inputTokens,outputTokens:i.outputTokens,cost:u,durationMs:Date.now()-c,status:"success"}),i.text}catch(i){throw oe({provider:n,model:r,caller:o,input:e,response:null,inputTokens:0,outputTokens:0,cost:0,durationMs:Date.now()-c,status:"error",error:i.message}),i}}var Rt=m(()=>{y();ce();C()});var Ct={};E(Ct,{deleteFact:()=>Un,deleteNamespace:()=>Gn,findByUid:()=>vn,findSimilar:()=>Pt,getFactCount:()=>Bn,getHotFacts:()=>xn,insertFact:()=>x,listByCategory:()=>Pn,listByDocument:()=>Cn,listFacts:()=>kn,listNamespaces:()=>Hn,markContradicted:()=>Nt,markSuperseded:()=>vt,recordAccess:()=>Mn,saveFact:()=>Ln});import{readFile as An}from"node:fs/promises";import bn from"node:path";async function Ln({content:e,category:t,confidence:o,importance:n,namespace:r,sourceDocumentIds:s,sourceSection:c,embedding:i}){let u=i||await le(e),l=await Pt(u,{namespace:r});if(!l.length)return{action:"ADD",fact:await x({content:e,category:t,confidence:o,importance:n,namespace:r,sourceDocumentIds:s,sourceSection:c,embedding:u})};let p=l[0];if(p.similarity>=Dn)return{action:"SKIP",existing:p};if(p.similarity>=Lt){let _=await Nn(e,p.content);if(_==="UPDATE"){let f=await x({content:e,category:t,confidence:o,importance:n,namespace:r,sourceDocumentIds:s,sourceSection:c,embedding:u});return await vt(p.id,f.id),await Dt({targetType:"fact",targetId:p.id,event:"UPDATE",oldContent:p.content,newContent:e,triggeredBy:`audm:sim=${p.similarity.toFixed(3)}`}),{action:"UPDATE",fact:f,supersededId:p.id}}if(_==="CONTRADICT"){let f=await x({content:e,category:t,confidence:o,importance:n,namespace:r,sourceDocumentIds:s,sourceSection:c,embedding:u});return await Nt(p.id,f.id),await Dt({targetType:"fact",targetId:p.id,event:"CONTRADICT",oldContent:p.content,newContent:e,triggeredBy:`audm:sim=${p.similarity.toFixed(3)}`}),{action:"CONTRADICT",fact:f,contradictedId:p.id}}}return{action:"ADD",fact:await x({content:e,category:t,confidence:o,importance:n,namespace:r,sourceDocumentIds:s,sourceSection:c,embedding:u})}}async function Nn(e,t){let n=`${await An(Rn,"utf8")}
|
|
32
|
+
|
|
33
|
+
**EXISTING FACT:** ${t}
|
|
34
|
+
|
|
35
|
+
**NEW FACT:** ${e}`,s=(await bt(n,{model:a.llm.decisionModel,caller:"audm"})).trim().toUpperCase();return s.includes("UPDATE")?"UPDATE":s.includes("CONTRADICT")?"CONTRADICT":"ADD"}async function x({content:e,category:t,confidence:o,importance:n,namespace:r,sourceDocumentIds:s,sourceSection:c,embedding:i}){let u=`fact-${Y(16)}`,[l]=await d("fact").insert({uid:u,content:e,category:t,confidence:o||"medium",importance:n||"supplementary",namespace:r,status:"active",sourceDocumentIds:s||[],sourceSection:c||null,embedding:M(i),validFrom:new Date}).returning("*");return await d.raw(`
|
|
36
|
+
UPDATE fact
|
|
37
|
+
SET search_vector = to_tsvector('english', content)
|
|
38
|
+
WHERE id = ?
|
|
39
|
+
`,[l.id]),l}async function vn(e){let[t]=await d("fact").where({uid:e});return t||null}async function Pn(e,{namespace:t,limit:o=50}={}){let n=d("fact").where({category:e,status:"active"}).orderBy("createdAt","desc").limit(o);return t&&n.where({namespace:t}),n}async function Cn(e){return d("fact").whereRaw("? = ANY(source_document_ids)",[e]).where({status:"active"}).orderBy("createdAt","desc")}async function Nt(e,t){await d("fact").where({id:e}).update({status:"contradicted",contradictedById:t,validUntil:d.fn.now()})}async function vt(e,t){await d("fact").where({id:e}).update({status:"superseded",supersededById:t,validUntil:d.fn.now()})}async function Pt(e,{namespace:t,threshold:o=Lt,limit:n=5}){let r=M(e),s=`${gt("embedding")} <=> ${yt()}`;return d.transaction(async c=>{await c.raw("SET LOCAL hnsw.ef_search = 40");let{rows:i}=await c.raw(`
|
|
40
|
+
SELECT id, uid, content, category, status,
|
|
41
|
+
1 - (${s}) as similarity
|
|
42
|
+
FROM fact
|
|
43
|
+
WHERE namespace = ?
|
|
44
|
+
AND status = 'active'
|
|
45
|
+
AND embedding IS NOT NULL
|
|
46
|
+
AND 1 - (${s}) >= ?
|
|
47
|
+
ORDER BY ${s}
|
|
48
|
+
LIMIT ?
|
|
49
|
+
`,[r,t,r,o,r,n]);return i})}async function Dt({targetType:e,targetId:t,event:o,oldContent:n,newContent:r,triggeredBy:s}){await d("history").insert({targetType:e,targetId:t,event:o,oldContent:n||null,newContent:r||null,triggeredBy:s||null})}async function Mn(e){e.length&&await d.raw(`UPDATE fact_lifecycle
|
|
50
|
+
SET access_count = access_count + 1,
|
|
51
|
+
last_accessed_at = NOW(),
|
|
52
|
+
stage = CASE WHEN stage = 'stable' THEN 'editing' ELSE stage END,
|
|
53
|
+
stage_entered_at = CASE WHEN stage = 'stable' THEN NOW() ELSE stage_entered_at END
|
|
54
|
+
WHERE fact_id = ANY(?)`,[e])}async function xn(e,{limit:t=10,since:o}={}){let n=d("fact as f").join("fact_lifecycle as fl","fl.fact_id","f.id").where({"f.status":"active"}).where("fl.access_count",">",0).orderBy("fl.access_count","desc").limit(t).select("f.*");return e&&n.where({"f.namespace":e}),o&&n.where("fl.last_accessed_at",">=",o),n}async function kn({namespace:e,limit:t=50,offset:o=0,category:n}={}){let r=d("fact").where({status:"active"}).select("id","uid","content","category","confidence","importance","createdAt","namespace").orderBy("createdAt","desc").limit(t).offset(o);return e&&r.where({namespace:e}),n&&r.where({category:n}),r}async function Bn(e){let t=d("fact").where({status:"active"});e&&t.where({namespace:e});let[{count:o}]=await t.count("id as count");return Number(o)}async function Un(e){let o=typeof e=="string"&&e.length>8?{uid:e}:{id:Number(e)},n=await d("fact").where(o).first();return n?(await d("fact_entity").where({factId:n.id}).del(),await d("fact").where({id:n.id}).del(),n):null}async function Hn(){return(await d("fact").where({status:"active"}).select("namespace").count("id as factCount").groupBy("namespace").orderBy("namespace")).map(t=>({namespace:t.namespace,factCount:Number(t.factCount)}))}async function Gn(e){await d.raw("DELETE FROM relation WHERE source_fact_id IN (SELECT id FROM fact WHERE namespace = ?)",[e]),await d.raw("DELETE FROM fact_entity WHERE fact_id IN (SELECT id FROM fact WHERE namespace = ?)",[e]),await d.raw("DELETE FROM relation WHERE source_id IN (SELECT id FROM entity WHERE namespace = ?) OR target_id IN (SELECT id FROM entity WHERE namespace = ?)",[e,e]);let t=await d("fact").where({namespace:e}).del(),o=await d("chunk").where({namespace:e}).del(),n=await d("document").where({namespace:e}).del(),r=await d("entity").where({namespace:e}).del();return{factsDeleted:t,chunksDeleted:o,docsDeleted:n,entitiesDeleted:r}}var Rn,Dn,Lt,Mt=m(()=>{te();R();de();Rt();ue();y();L();Rn=bn.join(Oe,"audm-decision.md"),Dn=a.memory.skipThreshold,Lt=a.memory.ambiguousThreshold});async function W({podType:e,externalId:t,name:o,namespace:n,attrs:r={},entityId:s=null,connectionId:c=null,startedAt:i=null}){if(!t)throw new Error("upsertPod requires externalId; use insertPod for custom pods");let u=`pod-${Y(16)}`,l=n||a.defaults.namespace,{rows:[p]}=await d.raw(`
|
|
55
|
+
INSERT INTO pod (uid, pod_type, name, namespace, attrs, entity_id, connection_id, external_id, started_at, created_at, updated_at)
|
|
56
|
+
VALUES (?, ?, ?, ?, ?::jsonb, ?, ?, ?, ?, NOW(), NOW())
|
|
57
|
+
ON CONFLICT (pod_type, external_id, namespace) WHERE external_id IS NOT NULL DO UPDATE SET
|
|
58
|
+
attrs = pod.attrs || EXCLUDED.attrs,
|
|
59
|
+
updated_at = NOW()
|
|
60
|
+
RETURNING *, (xmax = 0) AS "isNew"
|
|
61
|
+
`,[u,e,o,l,JSON.stringify(r),s,c,t,i]);return{pod:p,isNew:p.isNew}}async function xt(e){return d("pod").where({uid:e}).first()||null}async function kt(e,t){await d.raw("UPDATE pod SET attrs = attrs || ?::jsonb, updated_at = NOW() WHERE id = ?",[JSON.stringify(t),e])}async function k(e,{docs:t=0,facts:o=0}){!t&&!o||await d.raw(`UPDATE pod
|
|
62
|
+
SET member_doc_count = member_doc_count + ?,
|
|
63
|
+
member_fact_count = member_fact_count + ?,
|
|
64
|
+
updated_at = NOW()
|
|
65
|
+
WHERE id = ?`,[t,o,e])}var V=m(()=>{te();R();y()});function Ht({sessionId:e,transcriptPath:t=null,cwd:o=null,turnCount:n=0,model:r=null,conclusion:s=null,summary:c=null}){return{session_id:e,transcript_path:t,cwd:o,turn_count:n,model:r,conclusion:s,summary:c}}function Gt({sessionId:e,startedAt:t=new Date}={}){let n=(t instanceof Date?t:new Date(t)).toISOString().replace("T"," ").slice(0,16),r=e?e.slice(0,8):"unknown";return`claude-session ${n} (${r})`}var Ut,$t=m(()=>{pe();Ut="claude_session"});import{writeFile as Kn,readFile as Fn,unlink as $s}from"node:fs/promises";import{existsSync as Yn,mkdirSync as jn}from"node:fs";import{dirname as Kt}from"node:path";async function Wn(){try{let e=await Fn(J,"utf8");return JSON.parse(e)}catch{return null}}async function Ft(e){Yn(Kt(J))||jn(Kt(J),{recursive:!0}),await Kn(J,JSON.stringify(e,null,2),"utf8")}async function Yt({sessionId:e,transcriptPath:t=null,cwd:o=null,model:n=null,namespace:r=null}){if(!e)throw new Error("ensureActiveSession requires sessionId from hook stdin");let s=r||a.defaults.namespace,c=await Wn();if(c&&c.session_id===e&&c.namespace===s){let l=await xt(c.pod_uid);if(l)return await kt(l.id,{turn_count:(Jn(l.attrs)||0)+1}),await Vn(c),l}let i=new Date,{pod:u}=await W({podType:Ut,externalId:e,name:Gt({sessionId:e,startedAt:i}),namespace:s,attrs:Ht({sessionId:e,transcriptPath:t,cwd:o,turnCount:1,model:n}),startedAt:i});return await Ft({session_id:e,pod_uid:u.uid,namespace:s,started_at:u.startedAt??i.toISOString(),last_seen_at:new Date().toISOString()}),u}async function Vn(e){await Ft({...e,last_seen_at:new Date().toISOString()})}function Jn(e){if(!e)return 0;if(typeof e=="object")return e.turn_count??0;try{return JSON.parse(e).turn_count??0}catch{return 0}}var J,Ws,pe=m(()=>{V();$t();y();L();J=Ae,Ws=360*60*1e3});var me={};E(me,{attach:()=>Z,attachDocument:()=>qn,attachEntity:()=>zn,attachFact:()=>Zn,detach:()=>Xn,factIdsInPod:()=>tr,listMembers:()=>Qn,listPodsForMember:()=>er});async function Z(e,t,o,n="primary"){let{rowCount:r}=await d.raw(`INSERT INTO pod_membership (pod_id, member_type, member_id, role)
|
|
66
|
+
VALUES (?, ?, ?, ?)
|
|
67
|
+
ON CONFLICT (pod_id, member_type, member_id) DO NOTHING`,[e,t,o,n]);return r>0&&(t==="fact"?await k(e,{facts:1}):t==="document"&&await k(e,{docs:1})),{attached:r>0}}async function Xn(e,t,o){let n=await d("pod_membership").where({podId:e,memberType:t,memberId:o}).del();return n>0&&(t==="fact"?await k(e,{facts:-1}):t==="document"&&await k(e,{docs:-1})),{detached:n>0}}async function Qn(e,{memberType:t,limit:o=20}={}){if(!t)throw new Error("listMembers requires a memberType filter");return d(`${t} as t`).join("pod_membership as pm",function(){this.on("pm.member_id","=","t.id").andOnVal("pm.member_type","=",t)}).where("pm.pod_id",e).orderBy("pm.createdAt","desc").limit(o).select("t.*","pm.role as podRole","pm.createdAt as attachedAt")}async function er(e,t){return d("pod as p").join("pod_membership as pm","pm.pod_id","p.id").where("pm.memberType",e).where("pm.memberId",t).select("p.*","pm.role as podRole")}async function tr(e){return await d("pod_membership").where({podId:e,memberType:"fact"}).pluck("memberId")}var Zn,qn,zn,fe=m(()=>{R();V();Zn=(e,t,o)=>Z(e,"fact",t,o),qn=(e,t,o)=>Z(e,"document",t,o),zn=(e,t,o)=>Z(e,"entity",t,o)});import{execFileSync as or}from"node:child_process";import{basename as jt}from"node:path";async function Wt({cwd:e,namespace:t=null}){if(!e)return null;let o=rr(e),n=t||a.defaults.namespace,s=(o!==e?!1:_e(e)===e)?o:_e(e),{pod:c}=await W({podType:nr,externalId:o,name:jt(o)||o,namespace:n,attrs:{root_path:o,git_root:s||null,display_name:jt(o)||o,discovered_at:new Date().toISOString()},startedAt:new Date});return c}function rr(e){return _e(e)||e}function _e(e){try{return or("git",["rev-parse","--show-toplevel"],{cwd:e,encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim()||null}catch{return null}}var nr,Vt=m(()=>{V();fe();y();nr="project"});var Jt={};E(Jt,{ensureActivePodsForHook:()=>sr});async function sr({sessionId:e,cwd:t=null,transcriptPath:o=null,model:n=null,namespace:r=null}){let s=null;if(e)try{s=await Yt({sessionId:e,transcriptPath:o,cwd:t,model:n,namespace:r})}catch{s=null}let c=null;if(t)try{c=await Wt({cwd:t,namespace:r})}catch{c=null}let i=[s,c].filter(Boolean).map(u=>u.uid);return{sessionPod:s,projectPod:c,podUids:i}}var Zt=m(()=>{pe();Vt()});import{readFileSync as ir,writeFileSync as ar,mkdirSync as cr}from"node:fs";import{createHash as ur}from"node:crypto";var P="***MASKED***",no=[/\b(sk-(?:proj-|ant-)?[A-Za-z0-9_\-]{20,})\b/g,/\b(ghp_[A-Za-z0-9]{36,})\b/g,/\b(github_pat_[A-Za-z0-9_]{20,})\b/g,/\b(gho_[A-Za-z0-9]{36,})\b/g,/\b(glpat-[A-Za-z0-9_\-]{20,})\b/g,/\b(xox[baprs]-[A-Za-z0-9\-]{10,})\b/g,/\b(whsec_[A-Za-z0-9]{20,})\b/g,/\b(rk_(?:live|test)_[A-Za-z0-9]{20,})\b/g,/\b(AKIA[A-Z0-9]{16})\b/g,/\b(ASIA[A-Z0-9]{16})\b/g,/\b(eyJ[A-Za-z0-9_\-]{20,}\.[A-Za-z0-9_\-]{10,}\.[A-Za-z0-9_\-]{10,})\b/g,/\b([A-Za-z0-9]{24}\.[A-Za-z0-9_\-]{6}\.[A-Za-z0-9_\-]{27})\b/g,/\b(\d{8,12}:[A-Za-z0-9_\-]{35})\b/g],ro=new RegExp(`\\b(api[_-]?key|api[_-]?secret|secret[_-]?key|secret|token|password|passwd|pwd|auth[_-]?token|access[_-]?token|refresh[_-]?token|bearer|private[_-]?key|client[_-]?secret)\\s*[=:]\\s*["']?([^\\s"']{8,})["']?`,"gi"),so=/(\w+:\/\/)([^:/\s]+):([^@\s]{3,})@/g,io=["DATABASE_URL","REDIS_URL","MONGODB_URI","MONGO_URI","POSTGRES_URL","DSN","CONNECTION_STRING","ENCRYPTION_KEY","JWT_SECRET","SIGIL_ENCRYPTION_KEY","SESSION_SECRET","WEBHOOK_SECRET"],ao=new RegExp(`\\b(${io.join("|")})\\s*[=:]\\s*["']?([^\\s"']+)["']?`,"gi");function he(e){if(!e||typeof e!="string")return e;let t=e;for(let o of no)t=t.replace(o,P);return t=t.replace(ro,(o,n)=>`${n}=${P}`),t=t.replace(so,(o,n)=>`${n}${P}:${P}@`),t=t.replace(ao,(o,n)=>`${n}=${P}`),t}L();import{resolve as po}from"node:path";import{existsSync as De}from"node:fs";import{config as Le}from"dotenv";function Ne(){let e=po(process.cwd(),".env");De(e)&&Le({path:e,quiet:!0}),De(H)&&H!==e&&Le({path:H,quiet:!0})}L();Ne();var lr=new Set(["Read","Glob","Grep","WebFetch","WebSearch","TaskCreate","TaskUpdate","TaskList","TaskGet","TaskOutput","ToolSearch","Skill","Agent"]),dr=new Set(["ls","pwd","cd","cat","head","tail","wc","echo","date","whoami","which","type","clear","history","find","grep","rg","file","stat","diff","man","sigil","vitest"]),pr=new Set(["commit","push","merge","rebase","tag","release","reset","revert","cherry-pick"]),mr=new Set(["add","status","diff","log","show","branch","checkout","switch","fetch","pull","stash","blame","config"]),fr=["error","fail","fix","decided","refactor","migrate","deploy","docker","kubernetes","kubectl","k8s","pip install","npm install","yarn add","pnpm add","brew install","apt install","rm -rf","sudo","systemctl","launchctl"],zt=300*1e3,Xt=be;function _r(){try{let e=JSON.parse(ir(Xt,"utf8")),t=Date.now();for(let o of Object.keys(e))t-e[o]>zt&&delete e[o];return e}catch{return{}}}function qt(e){try{cr(T,{recursive:!0}),ar(Xt,JSON.stringify(e),"utf8")}catch{}}function Er(e){let t=_r(),o=t[e],n=Date.now();return o&&n-o<zt?(t[e]=n,qt(t),!0):(t[e]=n,qt(t),!1)}function hr(e){return(e.replace(/^(\w+=\S+\s+)+/,"").trim().split(/\s+/)[0]||"").split("/").pop()}function gr(e,t){if(lr.has(e))return null;if(e==="Edit"||e==="Write"){let o=t.file_path||"unknown file";return{content:`${e==="Write"?"Created":"Edited"} ${o}`,dedupKey:`${e}:${o}`}}if(e==="NotebookEdit"){let o=t.notebook_path||"unknown notebook";return{content:`Edited notebook ${o}`,dedupKey:`NotebookEdit:${o}`}}if(e==="Bash"){let o=(t.command||"").trim();if(!o)return null;let n=hr(o);if(dr.has(n))return null;if(n==="git"||n==="gh"){let i=o.replace(/^(git|gh)\s+/,"").split(/\s+/)[0];if(mr.has(i))return null;if(pr.has(i))return{content:`Ran: ${o.slice(0,200)}`,dedupKey:`Bash:${n} ${i}`}}if(["npm","pnpm","yarn"].includes(n)){let i=o.replace(/^\S+\s+/,"").split(/\s+/)[0];if(["test","run","start","lint"].includes(i))return null}let r=o.toLowerCase();return fr.some(i=>r.includes(i))?{content:`Ran: ${o.slice(0,200)}`,dedupKey:`Bash:${n}:${ur("md5").update(o).digest("hex").slice(0,8)}`}:null}return null}async function yr(){let e=[];for await(let u of process.stdin)e.push(u);let t=Buffer.concat(e).toString("utf8").trim();if(!t)return B();let o=JSON.parse(t),n=o.tool_name||"",r=o.tool_input||{},s=gr(n,r);if(!s||Er(s.dedupKey))return B();let{failClosedOnBadConfig:c}=await Promise.resolve().then(()=>(ee(),Q));if(await c("post-tool-use",t))return B();let i=he(s.content);try{let{saveFact:u}=await Promise.resolve().then(()=>(Mt(),Ct)),{embed:l}=await Promise.resolve().then(()=>(de(),At)),p=(await Promise.resolve().then(()=>(y(),Pe))).default,w=await l(i),_=await u({content:i,category:"observation",confidence:"medium",importance:"supplementary",namespace:p.defaults.namespace,sourceDocumentIds:[],sourceSection:"session",embedding:w});try{let{ensureActivePodsForHook:S}=await Promise.resolve().then(()=>(Zt(),Jt)),b=await Promise.resolve().then(()=>(fe(),me)),{sessionPod:U,projectPod:Qt}=await S({sessionId:o.session_id,cwd:o.cwd||null,transcriptPath:o.transcript_path||null}),Ee=_?.fact?.id??_?.existing?.id,eo=_?.action==="SKIP"?"mention":"primary";if(Ee){for(let q of[U,Qt])if(q)try{await b.attachFact(q.id,Ee,eo)}catch(to){process.stderr.write(`[sigil:post-tool-use] attach to ${q.uid} failed: ${to.message}
|
|
68
|
+
`)}}}catch(S){process.stderr.write(`[sigil:post-tool-use] pod dispatch failed: ${S.message}
|
|
69
|
+
`)}await(await Promise.resolve().then(()=>(R(),G))).default.destroy()}catch(u){process.stderr.write(`[sigil:post-tool-use] ${u.message}
|
|
70
|
+
`);try{let{recordHookError:l}=await Promise.resolve().then(()=>(ee(),Q));await l("post-tool-use",u,o)}catch{}try{await(await Promise.resolve().then(()=>(R(),G))).default.destroy()}catch{}}return B()}function B(){let e={hookSpecificOutput:{hookEventName:"PostToolUse"}};process.stdout.write(JSON.stringify(e))}yr();
|