@anmol-srv/sigil 0.10.3 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +18 -12
- package/README.md +90 -82
- package/dist/cli.js +701 -508
- package/dist/daemon.js +647 -0
- package/dist/hooks/post-tool-use.js +20 -22
- package/dist/hooks/session-end.js +63 -61
- package/dist/hooks/stop.js +76 -74
- package/dist/hooks/user-prompt-submit.js +55 -47
- package/dist/server.js +45 -554
- package/integrations/hermes/README.md +4 -4
- package/integrations/hermes/plugin/README.md +8 -8
- package/knexfile.js +29 -8
- package/package.json +11 -5
- package/src/db/migrations/20260601000000_create-device-table.cjs +34 -0
- package/src/db/migrations/20260601000001_create-pairing-code-table.cjs +27 -0
- package/src/db/migrations/20260601000002_add-fact-provenance.cjs +31 -0
- package/src/db/migrations/20260601000003_add-device-revoked-reason.cjs +19 -0
- package/src/db/migrations/20260601000004_create-trace-event-table.cjs +35 -0
- package/src/db/migrations/20260601000005_add-fact-agent-provenance.cjs +25 -0
- package/src/gui/web/app.css +883 -0
- package/src/gui/web/app.js +1118 -0
- package/src/gui/web/index.html +524 -0
- package/src/gui/web/sigil.svg +31 -0
|
@@ -1,42 +1,43 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
import { createRequire as __sigilCreateRequire } from 'node:module'; const require = __sigilCreateRequire(import.meta.url);
|
|
3
|
+
var wo=Object.defineProperty;var m=(e,t)=>()=>(e&&(t=e(e=0)),t);var w=(e,t)=>{for(var o in t)wo(e,o,{get:t[o],enumerable:!0})};function N(e){if(!e||typeof e!="string")return e;let t=e;for(let o of yo)t=t.replace(o,k);return t=t.replace(Io,(o,n)=>`${n}=${k}`),t=t.replace(So,(o,n)=>`${n}${k}:${k}@`),t=t.replace(Ao,(o,n)=>`${n}=${k}`),t}var k,yo,Io,So,Oo,Ao,$=m(()=>{k="***MASKED***",yo=[/\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],Io=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,Oo=["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(${Oo.join("|")})\\s*[=:]\\s*["']?([^\\s"']+)["']?`,"gi")});import{fileURLToPath as To}from"node:url";import{dirname as Ae,join as h}from"node:path";import{existsSync as Te}from"node:fs";import{homedir as bo}from"node:os";function Do(){let e=Ae(To(import.meta.url));for(let t=0;t<10;t++){if(Te(h(e,"package.json"))&&Te(h(e,"prompts")))return e;let o=Ae(e);if(o===e)break;e=o}return process.cwd()}var H,be,Vr,De,y,K,Jr,qr,Zr,Re,Le,Ne,zr,ve,Xr,Qr,es,ts,os,ns,rs,ss,Pe,is,as,v=m(()=>{H=Do(),be=h(H,"prompts"),Vr=h(H,"src","db","migrations"),De=bo(),y=h(De,".sigil"),K=h(y,".env"),Jr=h(y,"db"),qr=h(y,"CLAUDE.md"),Zr=h(y,"schemas"),Re=h(y,".hook-errors.log"),Le=h(y,".last-clean-doctor"),Ne=h(y,".active-session.json"),zr=h(y,".stop-cursor.json"),ve=h(y,".hook-dedup.json"),Xr=h(y,"sock"),Qr=h(y,"sigild.pid"),es=h(y,"sigild.log"),ts=h(y,"gui.token"),os=h(H,"dist","gui"),ns=h(H,"src","gui","web"),rs=h(y,"iroh"),ss=h(y,"identity.key"),Pe=h(De,".claude"),is=h(Pe,"settings.json"),as=h(Pe,"CLAUDE.md")});var Ue={};w(Ue,{default:()=>c});var _,ke,Lo,c,I=m(()=>{_=(e,t)=>process.env[e]??t,ke=_("SIGIL_DB_TYPE","postgres");if(ke!=="postgres")throw new Error(`SIGIL_DB_TYPE=${ke} is no longer supported. Sigil 0.10.0+ is Postgres-only.
|
|
3
4
|
PGlite was deprecated; existing PGlite data at ~/.sigil/db is preserved but unreachable from this version.
|
|
4
5
|
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.`);
|
|
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
|
|
7
|
-
`,"utf8")}catch{}}async function
|
|
8
|
-
`).filter(Boolean),n=[];for(let r of o.slice(-e))try{n.push(JSON.parse(r))}catch{}return n}async function
|
|
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
|
|
6
|
+
Run \`sigil init\` for an interactive setup.`);Lo={db:{type:"postgres",get url(){return _("SIGIL_DATABASE_URL",_("DATABASE_URL",""))||null},get host(){return _("SIGIL_DB_HOST","localhost")},get port(){return Number(_("SIGIL_DB_PORT",5432))},get database(){return _("SIGIL_DB_NAME","sigil")},get user(){return _("SIGIL_DB_USER","sigil_app")},get password(){return _("SIGIL_DB_PASSWORD","")}},embedding:{get provider(){return process.env.EMBEDDING_PROVIDER||""},get model(){return process.env.EMBEDDING_MODEL||"nomic-embed-text"},get dimensions(){return Number(process.env.EMBEDDING_DIMENSIONS)||768},get ollamaHost(){return process.env.OLLAMA_HOST||"http://localhost:11434"},get openaiApiKey(){return process.env.OPENAI_API_KEY||""},get voyageApiKey(){return 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"},http:{enabled:_("SIGIL_HTTP_ENABLED","true")!=="false",host:_("SIGIL_HTTP_HOST","127.0.0.1"),port:Number(_("SIGIL_HTTP_PORT",7777))},network:{mode:_("SIGIL_MODE","solo"),enabled:_("SIGIL_NETWORK_ENABLED",null)===null?_("SIGIL_MODE","solo")!=="solo":_("SIGIL_NETWORK_ENABLED","false")!=="false",masterNodeId:_("SIGIL_MASTER_NODE_ID","")||null},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,injectionFloor:Number(process.env.MEMORY_INJECTION_FLOOR)||.6},search:{synthesize:_("SIGIL_SYNTHESIZE","true")!=="false",synthesizeModel:_("SIGIL_SYNTH_MODEL","")},ingest:{eagerExtract:_("SIGIL_EAGER_EXTRACT","true")!=="false"},hebbian:{entity:{enabled:_("SIGIL_HEBBIAN_ENTITY_ENABLED",null,"true")!=="false",eta:Number(_("SIGIL_HEBBIAN_ENTITY_ETA",null,1)),cap:Number(_("SIGIL_HEBBIAN_ENTITY_CAP",null,50)),halfLifeDays:Number(_("SIGIL_HEBBIAN_ENTITY_HALF_LIFE_DAYS",null,30)),minEffective:Number(_("SIGIL_HEBBIAN_ENTITY_MIN_EFFECTIVE",null,.5)),rrfWeight:Number(_("SIGIL_HEBBIAN_ENTITY_RRF_WEIGHT",null,.3)),maxWriteEntities:Number(_("SIGIL_HEBBIAN_ENTITY_MAX_WRITE",null,12)),expandPerSeed:Number(_("SIGIL_HEBBIAN_ENTITY_EXPAND_PER_SEED",null,3))}}},c=Lo});function Be(e){return{host:e.db.host,port:e.db.port,database:e.db.database,user:e.db.user,password:e.db.password}}var Ge=m(()=>{});function He(e){if(!e)throw new Error("url driver: SIGIL_DATABASE_URL is empty");let t;try{t=new URL(e)}catch(s){throw new Error(`url driver: invalid URL \u2014 ${s.message}`)}if(!/^postgres(ql)?:$/i.test(t.protocol))throw new Error(`url driver: expected postgres:// or postgresql:// scheme, got ${t.protocol}`);let o=t.searchParams.get("sslmode"),n=vo(t.hostname,o),r={host:t.hostname,port:t.port?Number(t.port):5432,database:t.pathname.replace(/^\//,"")||"postgres",user:decodeURIComponent(t.username),password:decodeURIComponent(t.password)};return n!==void 0&&(r.ssl=n),t.searchParams.get("application_name")||(r.application_name="sigil"),r}function vo(e,t){if(t==="disable")return!1;if(t==="require"||t==="verify-full"||t==="verify-ca")return{rejectUnauthorized:!0};if(t==="no-verify"||t==="prefer")return{rejectUnauthorized:!1};if(!$e.some(o=>o.test(e)))return No.some(o=>o.test(e))?{rejectUnauthorized:!0}:{rejectUnauthorized:!1}}function Ke(e){try{let t=new URL(e).hostname;return/\.neon\.tech$/i.test(t)?"neon":/\.pooler\.supabase\.com$/i.test(t)?"supabase-pooler":/\.supabase\.co$/i.test(t)||/\.supabase\.com$/i.test(t)?"supabase":/\.rds\.amazonaws\.com$/i.test(t)?"aws-rds":/\.render\.com$/i.test(t)?"render":/\.railway\.app$/i.test(t)?"railway":/\.cockroachlabs\.cloud$/i.test(t)?"cockroachdb":$e.some(o=>o.test(t))?"local":"unknown"}catch{return"unknown"}}var No,$e,Fe=m(()=>{No=[/\.neon\.tech$/i,/\.supabase\.co$/i,/\.supabase\.com$/i,/\.pooler\.supabase\.com$/i,/\.rds\.amazonaws\.com$/i,/\.render\.com$/i,/\.railway\.app$/i,/\.cockroachlabs\.cloud$/i],$e=[/^localhost$/i,/^127\.0\.0\.1$/,/^::1$/,/\.local$/i]});function Ye(e){let t=e.db.url;return t?{kind:"url",provider:Ke(t),connection:He(t)}:{kind:"local",provider:"local",connection:Be(e)}}var je=m(()=>{Ge();Fe()});var F={};w(F,{default:()=>d});import Po from"knex";function Co(e){return Array.isArray(e)?e.map(te):e&&typeof e=="object"?te(e):e}function Mo(e,t){return t(xo(e))}function te(e){if(!e||typeof e!="object"||e instanceof Date)return e;if(Array.isArray(e))return e.map(te);let t={};for(let[o,n]of Object.entries(e))t[o.replace(/_([a-z])/g,(r,s)=>s.toUpperCase())]=n;return t}function xo(e){return e.replace(/[A-Z]/g,t=>`_${t.toLowerCase()}`)}var We,Ve,d,R=m(()=>{I();je();We=Ye(c),Ve=Po({client:"pg",connection:We.connection,pool:{min:2,max:10},postProcessResponse:Co,wrapIdentifier:Mo});Ve.__sigilDriver=We;d=Ve});var Xe={};w(Xe,{validateConfig:()=>ze,validateConfigDeep:()=>ko});function ze(){let e=[];return Uo(e),Bo(e),Go(e),e}async function ko(){let e=ze();if(c.db.type==="postgres"&&!e.some(t=>t.code.startsWith("DB_")))try{await(await Promise.resolve().then(()=>(R(),F))).default.raw("SELECT 1")}catch(t){e.push({level:"fail",code:"DB_UNREACHABLE",message:`Postgres at ${c.db.host}:${c.db.port}/${c.db.database} unreachable: ${t.message.split(`
|
|
7
|
+
`)[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 Uo(e){let{provider:t,model:o}=c.embedding;if(t&&o){let n=Object.keys(Je).find(r=>Je[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:$o(t,o,n)})}if(t&&Ze[t]){let n=Ze[t];c.embedding[n]||e.push({level:"fail",code:"EMBEDDING_PROVIDER_MISSING_KEY",message:`EMBEDDING_PROVIDER=${t} but no ${Y(n)} found.`,fix:`Set ${Y(n)} in ~/.sigil/.env, or run 'sigil init' to reconfigure.`})}}function Bo(e){let{provider:t}=c.llm;if(t&&qe[t]){let o=qe[t];c.llm[o]||e.push({level:"fail",code:"LLM_PROVIDER_MISSING_KEY",message:`LLM_PROVIDER=${t} but no ${Y(o)} found.`,fix:`Set ${Y(o)} in ~/.sigil/.env, or run 'sigil init' to reconfigure.`})}t==="openrouter"&&c.llm.openrouterModel&&(c.llm.openrouterModel.includes("/")||e.push({level:"warn",code:"OPENROUTER_MODEL_FORMAT",message:`LLM_OPENROUTER_MODEL=${c.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 Go(e){c.db.type==="postgres"&&(!c.db.host||!c.db.database||!c.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 Y(e){return{openaiApiKey:"OPENAI_API_KEY",apiKey:"ANTHROPIC_API_KEY",openrouterApiKey:"OPENROUTER_API_KEY",voyageApiKey:"VOYAGE_API_KEY"}[e]||e}function $o(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 Je,qe,Ze,Qe=m(()=>{I();Je={voyage:[/^voyage-/],openai:[/^text-embedding-/],ollama:[/^nomic-embed/,/^mxbai-embed/,/^all-minilm/,/^bge-/,/^snowflake-/,/^granite-embedding/]},qe={openai:"openaiApiKey",anthropic:"apiKey",openrouter:"openrouterApiKey"},Ze={openai:"openaiApiKey",voyage:"voyageApiKey",openrouter:"openrouterApiKey"}});var ne={};w(ne,{HOOK_ERROR_LOG:()=>j,LAST_CLEAN_DOCTOR_PATH:()=>W,clearLastCleanDoctor:()=>qo,failClosedOnBadConfig:()=>jo,getUnackedErrorCount:()=>Vo,markDoctorClean:()=>Jo,readRecentHookErrors:()=>Wo,recordHookError:()=>et});import{appendFile as Ho,readFile as oe,writeFile as Ko,unlink as Fo}from"node:fs/promises";import{createHash as Yo}from"node:crypto";async function et(e,t,o=null){try{let n={ts:new Date().toISOString(),hook:e,error:N(t?.message||String(t)),input_hash:o?Zo(o):null};await Ho(j,JSON.stringify(n)+`
|
|
8
|
+
`,"utf8")}catch{}}async function jo(e,t=null){try{let{validateConfig:o}=await Promise.resolve().then(()=>(Qe(),Xe)),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 et(e,s,t)}return!0}catch{return!1}}async function Wo(e=10){let t;try{t=await oe(j,"utf8")}catch{return[]}let o=t.split(`
|
|
9
|
+
`).filter(Boolean),n=[];for(let r of o.slice(-e))try{n.push(JSON.parse(r))}catch{}return n}async function Vo(){let e=0;try{let n=await oe(W,"utf8");e=new Date(n.trim()).getTime()}catch{}let t;try{t=await oe(j,"utf8")}catch{return 0}let o=0;for(let n of t.split(`
|
|
10
|
+
`))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 Jo(){try{await Ko(W,new Date().toISOString(),"utf8")}catch{}}async function qo(){try{await Fo(W)}catch{}}function Zo(e){try{let t=typeof e=="string"?e:JSON.stringify(e);return Yo("sha256").update(t).digest("hex").slice(0,12)}catch{return null}}var j,W,re=m(()=>{v();$();j=Re,W=Le});var tt,ot=m(()=>{tt="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict"});import{webcrypto as nt}from"node:crypto";function Xo(e){if(e<0||e>1024)throw new RangeError("Wrong ID size");!L||L.length<e?(L=Buffer.allocUnsafe(e*zo),nt.getRandomValues(L),P=0):P+e>L.length&&(nt.getRandomValues(L),P=0),P+=e}function V(e=21){Xo(e|=0);let t="";for(let o=P-e;o<P;o++)t+=tt[L[o]&63];return t}var zo,L,P,se=m(()=>{ot();zo=128});var rt={};w(rt,{chat:()=>Qo,meta:()=>en,setup:()=>tn});async function Qo(e,{model:t,jsonMode:o=!1}={}){let n=t||c.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 i=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${c.llm.openaiApiKey}`},body:JSON.stringify(s)});if(!i.ok){let f=await i.text();throw new Error(`OpenAI error ${i.status}: ${f}`)}let a=await i.json(),u=a.choices[0].message.content.trim(),l=a.usage||{};return{text:u,inputTokens:l.prompt_tokens||0,outputTokens:l.completion_tokens||0,model:n}}async function tn({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 en,st=m(()=>{I();en={id:"openai",label:"OpenAI",hint:"gpt-4o-mini"}});function T(e){return Math.ceil((e||"").length/4)}function it(e,t,o){let n=on[e];return n?(t*n.input+o*n.output)/1e6:0}function ie({provider:e,model:t,caller:o,input:n,response:r,inputTokens:s,outputTokens:i,cost:a,durationMs:u,status:l,error:f}){d("llm_log").insert({provider:e,model:t,caller:o,input:n?.slice(0,1e4),response:r?.slice(0,1e4),inputTokens:s,outputTokens:i,cost:a,durationMs:u,status:l,error:f?.slice(0,2e3)}).catch(p=>console.error("[llm-log] Write failed:",p.message))}async function at(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 on,U=m(()=>{R();on={"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 ct={};w(ct,{chat:()=>rn,meta:()=>sn,setup:()=>an});async function nn(){if(!ae){let{default:e}=await import("@anthropic-ai/sdk");ae=new e({apiKey:c.llm.apiKey})}return ae}async function rn(e,{model:t,jsonMode:o=!1}={}){let n=t||"claude-haiku-4-5-20251001",r=await nn(),s=[{role:"user",content:e}],i=o?"Respond with valid JSON only. No explanation or wrapping.":void 0,a=await r.messages.create({model:n,max_tokens:4096,messages:s,...i&&{system:i}});return{text:a.content[0].text.trim(),inputTokens:a.usage?.input_tokens||T(e),outputTokens:a.usage?.output_tokens||T(a.content[0].text),model:n}}async function an({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 ae,sn,ut=m(()=>{I();U();ae=null;sn={id:"anthropic",label:"Anthropic",hint:"Claude Haiku \u2014 requires API key"}});var dt={};w(dt,{chat:()=>un,meta:()=>ln,setup:()=>dn});async function un(e,{model:t,jsonMode:o=!1}={}){let n=t||c.llm.openrouterModel;if(!c.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 i=(c.llm.openrouterBaseUrl||cn).replace(/\/+$/,""),a={"Content-Type":"application/json",Authorization:`Bearer ${c.llm.openrouterApiKey}`};c.llm.openrouterReferer&&(a["HTTP-Referer"]=c.llm.openrouterReferer),c.llm.openrouterTitle&&(a["X-Title"]=c.llm.openrouterTitle);let u=await fetch(`${i}/chat/completions`,{method:"POST",headers:a,body:JSON.stringify(s)});if(!u.ok){let E=await u.text();throw new Error(`OpenRouter error ${u.status}: ${E}`)}let l=await u.json(),p=(l.choices?.[0]?.message?.content||"").trim(),g=l.usage||{};return{text:p,inputTokens:g.prompt_tokens||0,outputTokens:g.completion_tokens||0,model:l.model||n}}async function dn({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||"",i=await t.text({message:"OpenRouter model (vendor/model)",placeholder:s||lt,validate:u=>{if(u&&!u.includes("/"))return'OpenRouter models are "vendor/model" \u2014 e.g. google/gemini-flash-latest'}});if(t.isCancel(i))return null;o.LLM_OPENROUTER_MODEL=i||s||lt;let a=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(a))return null;if(a==="yes"){let u=await t.text({message:"Extraction model (high-volume; cheap matters)",placeholder:e.LLM_EXTRACTION_MODEL||C.extraction});if(t.isCancel(u))return null;o.LLM_EXTRACTION_MODEL=u||e.LLM_EXTRACTION_MODEL||C.extraction;let l=await t.text({message:"Decision model (AUDM; smart matters)",placeholder:e.LLM_DECISION_MODEL||C.decision});if(t.isCancel(l))return null;o.LLM_DECISION_MODEL=l||e.LLM_DECISION_MODEL||C.decision;let f=await t.text({message:"Synthesis model (read-time answer composition)",placeholder:e.SIGIL_SYNTH_MODEL||C.synthesis});if(t.isCancel(f))return null;o.SIGIL_SYNTH_MODEL=f||e.SIGIL_SYNTH_MODEL||C.synthesis}return t.note(`OpenRouter can drive both LLM calls and embeddings.
|
|
10
11
|
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
|
|
12
|
+
or you can use a direct provider (Ollama / OpenAI / Voyage) for embeddings.`,"OpenRouter scope"),{env:o}}var cn,ln,lt,C,pt=m(()=>{I();cn="https://openrouter.ai/api/v1";ln={id:"openrouter",label:"OpenRouter",hint:"one key, many models (Anthropic / OpenAI / Meta / ...)"},lt="google/gemini-flash-latest",C={extraction:"openrouter:qwen/qwen3.5-flash",decision:"openrouter:anthropic/claude-sonnet-latest",synthesis:"openrouter:anthropic/claude-sonnet-latest"}});var mt={};w(mt,{chat:()=>En,meta:()=>hn,setup:()=>gn});import{spawn as pn}from"node:child_process";function _n(e,t){let o=c.llm.cliTimeout||12e4;return new Promise((n,r)=>{let s=pn("claude",e,{stdio:["pipe","pipe","pipe"]}),i=setTimeout(()=>{s.kill("SIGTERM"),r(new Error(`claude CLI timed out after ${o}ms`))},o),a="",u="";s.stdout.on("data",l=>{a+=l}),s.stderr.on("data",l=>{u+=l}),s.on("error",l=>{clearTimeout(i),r(new Error(`Failed to spawn claude CLI: ${l.message}`))}),s.on("close",l=>{clearTimeout(i),n({stdout:a,stderr:u,code:l})}),s.stdin.write(t),s.stdin.end()})}async function En(e,{model:t,jsonMode:o=!1}={}){let n=t||c.llm.cliModel||"haiku",r=mn[n]||n,s=["-p","--model",r,"--output-format","json"];o&&s.push("--json-schema",fn);let{stdout:i,stderr:a,code:u}=await _n(s,e);if(u!==0)throw new Error(`claude CLI exited ${u}: ${(a||i).slice(0,500)}`);let l;try{l=JSON.parse(i)}catch{return{text:i.trim(),inputTokens:T(e),outputTokens:T(i),model:r}}if(l.is_error)throw new Error(`claude CLI error: ${l.result||"unknown error"}`);let f=o&&l.structured_output?JSON.stringify(l.structured_output):(l.result||"").trim(),p=l.usage||{};return{text:f,inputTokens:p.input_tokens||T(e),outputTokens:p.output_tokens||T(f),model:r,cost:l.total_cost_usd||0}}async function gn(){return{env:{}}}var mn,fn,hn,ft=m(()=>{I();U();mn={"claude-haiku-4-5-20251001":"haiku","claude-sonnet-4-6":"sonnet","claude-opus-4-6":"opus"},fn=JSON.stringify({type:"object",additionalProperties:!0});hn={id:"claude-cli",label:"Claude Code",hint:"uses your existing subscription \u2014 no extra API key"}});var _t={};w(_t,{chat:()=>wn,meta:()=>yn,setup:()=>In});async function wn(e,{model:t,jsonMode:o=!1}={}){let n=t||c.llm.ollamaModel,r=`${c.llm.ollamaHost}/api/chat`,s={model:n,messages:[{role:"user",content:e}],stream:!1};o&&(s.format="json");let i=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!i.ok){let u=await i.text();throw new Error(`Ollama error ${i.status}: ${u}`)}let a=await i.json();return{text:a.message.content.trim(),inputTokens:a.prompt_eval_count||T(e),outputTokens:a.eval_count||T(a.message.content),model:n}}async function In({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 yn,Et=m(()=>{I();U();yn={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 ce=m(()=>{});var ht={};w(ht,{embedBatch:()=>On});async function On(e,{model:t,ollamaHost:o}){let n=J(e,Sn),r=[];for(let s of n){let i=await fetch(`${o}/api/embed`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:t,input:s})});if(!i.ok)throw new Error(`Ollama embed failed: ${i.status} ${await i.text()}`);let a=await i.json();r.push(...a.embeddings)}return r}var Sn,gt=m(()=>{ce();Sn=50});var wt={};w(wt,{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(a=>a.embedding)}var yt=m(()=>{});var It={};w(It,{embedBatch:()=>bn});async function bn(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,Tn),i=[];for(let a of s){let u={input:a,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 g=await l.text();throw new Error(`Voyage embed failed: ${l.status} ${g}`)}let p=[...(await l.json()).data].sort((g,E)=>g.index-E.index);i.push(...p.map(g=>g.embedding))}return i}var Tn,St=m(()=>{ce();Tn=50});var Ot={};w(Ot,{embedBatch:()=>Rn});async function Rn(e,{model:t,openrouterApiKey:o,openrouterBaseUrl:n,openrouterReferer:r,openrouterTitle:s,dimensions:i}={}){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 a={model:t,input:e};i&&/(^|\/)text-embedding-3/.test(t)&&(a.dimensions=i);let u=(n||Dn).replace(/\/+$/,""),l={"Content-Type":"application/json",Authorization:`Bearer ${o}`};r&&(l["HTTP-Referer"]=r),s&&(l["X-Title"]=s);let f=await fetch(`${u}/embeddings`,{method:"POST",headers:l,body:JSON.stringify(a)});if(!f.ok)throw new Error(`OpenRouter embed failed: ${f.status} ${await f.text()}`);return[...(await f.json()).data].sort((E,S)=>E.index-S.index).map(E=>E.embedding)}var Dn,At=m(()=>{Dn="https://openrouter.ai/api/v1"});import{spawn as Ln}from"node:child_process";async function bt(e){if(!ue[e]){let t=de[e];if(!t)throw new Error(`Unknown LLM provider: "${e}". Available: ${Object.keys(de).join(", ")}`);let o=await t();ue[e]=o.chat}return ue[e]}async function Dt(e){if(!le[e]){let t=Tt[e];if(!t)throw new Error(`Unknown embedding provider: "${e}". Available: ${Object.keys(Tt).join(", ")}`);let o=await t();le[e]=o.embedBatch}return le[e]}function Rt(e,t){if(!e)return{provider:t,model:null};let o=e.indexOf(":");return o>0&&de[e.slice(0,o)]?{provider:e.slice(0,o),model:e.slice(o+1)}:{provider:t,model:e}}async function Lt(){let e=c.llm.ollamaHost||c.embedding.ollamaHost||"http://localhost:11434";try{return(await fetch(`${e}/api/tags`,{signal:AbortSignal.timeout(2e3)})).ok}catch{return!1}}function Nn(){return new Promise(e=>{let t=Ln("claude",["--version"],{stdio:"pipe"});t.on("error",()=>e(!1)),t.on("close",o=>e(o===0)),setTimeout(()=>{t.kill(),e(!1)},3e3)})}async function Nt(){if(O)return O;if(c.llm.provider)return O=c.llm.provider,O;if(c.llm.openrouterApiKey)return O="openrouter",O;if(c.llm.apiKey)return O="anthropic",O;if(c.llm.openaiApiKey)return O="openai",O;if(await Lt())return O="ollama",O;if(await Nn())return O="claude-cli",O;throw new Error(`No LLM provider available. Either:
|
|
12
13
|
- Set LLM_PROVIDER (openai, anthropic, openrouter, ollama, claude-cli)
|
|
13
14
|
- Set ANTHROPIC_API_KEY, OPENAI_API_KEY, or OPENROUTER_API_KEY
|
|
14
15
|
- Start Ollama locally
|
|
15
|
-
- Install the Claude CLI (claude)`)}async function
|
|
16
|
+
- Install the Claude CLI (claude)`)}async function vt(){if(A)return A;if(c.embedding.provider)return A=c.embedding.provider,A;if(c.embedding.voyageApiKey)return A="voyage",A;if(await Lt())return A="ollama",A;if(c.embedding.openaiApiKey)return A="openai",A;if(c.embedding.openrouterApiKey)return A="openrouter",A;throw new Error(`No embedding provider available. Either:
|
|
16
17
|
- Set EMBEDDING_PROVIDER (voyage, ollama, openai, openrouter)
|
|
17
18
|
- Set VOYAGE_API_KEY (recommended \u2014 best quality)
|
|
18
19
|
- Start Ollama locally
|
|
19
20
|
- Set OPENAI_API_KEY
|
|
20
|
-
- Set OPENROUTER_API_KEY (and EMBEDDING_MODEL like "openai/text-embedding-3-large")`)}var
|
|
21
|
+
- Set OPENROUTER_API_KEY (and EMBEDDING_MODEL like "openai/text-embedding-3-large")`)}var de,Tt,ue,le,O,A,pe=m(()=>{I();de={openai:()=>Promise.resolve().then(()=>(st(),rt)),anthropic:()=>Promise.resolve().then(()=>(ut(),ct)),openrouter:()=>Promise.resolve().then(()=>(pt(),dt)),"claude-cli":()=>Promise.resolve().then(()=>(ft(),mt)),ollama:()=>Promise.resolve().then(()=>(Et(),_t))},Tt={ollama:()=>Promise.resolve().then(()=>(gt(),ht)),openai:()=>Promise.resolve().then(()=>(yt(),wt)),voyage:()=>Promise.resolve().then(()=>(St(),It)),openrouter:()=>Promise.resolve().then(()=>(At(),Ot))},ue={},le={};O=null,A=null});function B(e){return e?`[${e.join(",")}]`:null}function Pt(){let e=Number(c.embedding.dimensions)||768;if(!Number.isInteger(e)||e<=0)throw new Error(`Invalid EMBEDDING_DIMENSIONS: ${c.embedding.dimensions}`);return e}function Ct(e="embedding"){return`(${e}::halfvec(${Pt()}))`}function Mt(){return`?::halfvec(${Pt()})`}var me=m(()=>{I()});import{createHash as vn}from"node:crypto";function Cn(e,t,o,n="document"){let r=vn("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 Mn(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,xn(o.embedding)]))}function xn(e){return Array.isArray(e)||typeof e!="string"?e:(e.startsWith("[")?e.slice(1,-1):e).split(",").map(Number)}async function kn(e){e.length&&await d("embedding_cache").whereIn("key",e).update({hits:d.raw("hits + 1"),lastUsedAt:d.fn.now()})}async function Un(e,t,o){if(e.length){for(let{key:n,embedding:r}of e)await d.raw(`
|
|
21
22
|
INSERT INTO embedding_cache (key, provider, model, embedding, hits, created_at, last_used_at)
|
|
22
23
|
VALUES (?, ?, ?, ?, 0, NOW(), NOW())
|
|
23
24
|
ON CONFLICT (key) DO UPDATE
|
|
24
25
|
SET last_used_at = NOW(),
|
|
25
26
|
hits = embedding_cache.hits + 1
|
|
26
|
-
`,[n,t,o,
|
|
27
|
+
`,[n,t,o,B(r)]);await Gn()}}async function Gn(){let e=Date.now();if(e-kt<Bn)return;kt=e;let[{count:t}]=await d("embedding_cache").count("key as count"),o=Number(t);if(o<=xt)return;let n=Math.min(o-xt,Pn);await d.raw(`
|
|
27
28
|
DELETE FROM embedding_cache WHERE key IN (
|
|
28
29
|
SELECT key FROM embedding_cache ORDER BY last_used_at ASC LIMIT ?
|
|
29
30
|
)
|
|
30
|
-
`,[n])}async function
|
|
31
|
-
`)})}let
|
|
31
|
+
`,[n])}async function Ut(e,t,o,n,r,s={}){if(!e.length)return[];let i=s.inputType||r?.inputType||"document",a=e.map(E=>Cn(t,o,E,i)),u=await Mn(a),l=[],f=[],p=new Array(e.length);for(let E=0;E<e.length;E++){let S=u.get(a[E]);S?p[E]=S:(l.push(e[E]),f.push(E))}if(l.length){let E=await n(l,r),S=[];for(let b=0;b<l.length;b++){let D=f[b];p[D]=E[b],S.push({key:a[D],embedding:E[b]})}Un(S,t,o).catch(b=>{process.stderr.write(`[embedding-cache] store failed: ${b.message}
|
|
32
|
+
`)})}let g=a.filter(E=>u.has(E));return g.length&&kn(g).catch(()=>{}),p}var xt,Pn,kt,Bn,Bt=m(()=>{me();R();xt=1e4,Pn=500;kt=0,Bn=6e4});var $t={};w($t,{dimensions:()=>$n,embed:()=>fe,embedBatch:()=>Gt});async function fe(e,t={}){let[o]=await Gt([e],t);return o}async function Gt(e,{inputType:t="document"}={}){if(!e.length)return[];let o=await vt(),n=await Dt(o),r=c.embedding.model,s={...c.embedding,inputType:t};return Ut(e,o,r,n,s,{inputType:t})}var $n,_e=m(()=>{I();pe();Bt();({dimensions:$n}=c.embedding)});async function Hn(e){let t=await Nt();return Rt(e,t)}async function Ht(e,{model:t,caller:o}={}){let{provider:n,model:r}=await Hn(t),s=await bt(n),i=Date.now();try{let a=await at(()=>s(e,{model:r,jsonMode:!1}),c.llm.maxRetries),u=a.cost||it(a.model,a.inputTokens,a.outputTokens);return ie({provider:n,model:a.model,caller:o,input:e,response:a.text,inputTokens:a.inputTokens,outputTokens:a.outputTokens,cost:u,durationMs:Date.now()-i,status:"success"}),a.text}catch(a){throw ie({provider:n,model:r,caller:o,input:e,response:null,inputTokens:0,outputTokens:0,cost:0,durationMs:Date.now()-i,status:"error",error:a.message}),a}}var Kt=m(()=>{I();pe();U()});var Ft={};w(Ft,{currentAgent:()=>Wn,currentDeviceId:()=>jn,currentRequestContext:()=>Yn,runWithRequestContext:()=>Fn});import{AsyncLocalStorage as Kn}from"node:async_hooks";function Fn(e,t){return q.run(e,t)}function Yn(){return q.getStore()||null}function jn(){return q.getStore()?.device?.id??null}function Wn(){return q.getStore()?.agent??process.env.SIGIL_AGENT??null}var q,Yt=m(()=>{q=new Kn});var qt={};w(qt,{deleteFact:()=>sr,deleteNamespace:()=>ar,findByUid:()=>Xn,findSimilar:()=>Jt,getFactCount:()=>rr,getHotFacts:()=>or,insertFact:()=>M,listByCategory:()=>Qn,listByDocument:()=>Wt,listFacts:()=>nr,listNamespaces:()=>ir,markContradicted:()=>Vt,markSuperseded:()=>ge,recordAccess:()=>tr,saveFact:()=>Zn,supersedeStaleDocFacts:()=>er});import{readFile as Vn}from"node:fs/promises";import Jn from"node:path";async function Zn({content:e,category:t,confidence:o,importance:n,namespace:r,sourceDocumentIds:s,sourceSection:i,embedding:a}){e=N(e);let u=a||await fe(e),l=await Jt(u,{namespace:r}),f={skip:jt,ambiguous:Ee};if(!l.length)return{action:"ADD",fact:await M({content:e,category:t,confidence:o,importance:n,namespace:r,sourceDocumentIds:s,sourceSection:i,embedding:u}),audm:{topSimilarity:null,matchCount:0,decision:"no-match",thresholds:f}};let p=l[0],g={topSimilarity:Number(p.similarity),matchCount:l.length,existingId:p.id,existingContent:p.content,thresholds:f};if(p.similarity>=jt)return{action:"SKIP",existing:p,audm:{...g,decision:"skip-duplicate"}};if(p.similarity>=Ee){let S=await zn(e,p.content);if(S==="UPDATE"){let D=await M({content:e,category:t,confidence:o,importance:n,namespace:r,sourceDocumentIds:s,sourceSection:i,embedding:u});return await ge(p.id,D.id),await he({targetType:"fact",targetId:p.id,event:"UPDATE",oldContent:p.content,newContent:e,triggeredBy:`audm:sim=${p.similarity.toFixed(3)}`}),{action:"UPDATE",fact:D,supersededId:p.id,audm:{...g,decision:"llm:UPDATE"}}}if(S==="CONTRADICT"){let D=await M({content:e,category:t,confidence:o,importance:n,namespace:r,sourceDocumentIds:s,sourceSection:i,embedding:u});return await Vt(p.id,D.id),await he({targetType:"fact",targetId:p.id,event:"CONTRADICT",oldContent:p.content,newContent:e,triggeredBy:`audm:sim=${p.similarity.toFixed(3)}`}),{action:"CONTRADICT",fact:D,contradictedId:p.id,audm:{...g,decision:"llm:CONTRADICT"}}}return{action:"ADD",fact:await M({content:e,category:t,confidence:o,importance:n,namespace:r,sourceDocumentIds:s,sourceSection:i,embedding:u}),audm:{...g,decision:"llm:ADD"}}}return{action:"ADD",fact:await M({content:e,category:t,confidence:o,importance:n,namespace:r,sourceDocumentIds:s,sourceSection:i,embedding:u}),audm:{...g,decision:"below-ambiguous"}}}async function zn(e,t){let n=`${await Vn(qn,"utf8")}
|
|
32
33
|
|
|
33
34
|
**EXISTING FACT:** ${t}
|
|
34
35
|
|
|
35
|
-
**NEW FACT:** ${e}`,s=(await
|
|
36
|
+
**NEW FACT:** ${e}`,s=(await Ht(n,{model:c.llm.decisionModel,caller:"audm"})).trim().toUpperCase();return s.includes("UPDATE")?"UPDATE":s.includes("CONTRADICT")?"CONTRADICT":"ADD"}async function M({content:e,category:t,confidence:o,importance:n,namespace:r,sourceDocumentIds:s,sourceSection:i,embedding:a}){let u=`fact-${V(16)}`,l=null,f=null;try{let{currentDeviceId:g,currentAgent:E}=await Promise.resolve().then(()=>(Yt(),Ft));l=g(),f=E()}catch{}let[p]=await d("fact").insert({uid:u,content:e,category:t,confidence:o||"medium",importance:n||"supplementary",namespace:r,status:"active",sourceDocumentIds:s||[],sourceSection:i||null,embedding:B(a),validFrom:new Date,embeddingModel:c.embedding.model||null,embeddingDim:Number(c.embedding.dimensions)||null,createdByDeviceId:l,createdByAgent:f}).returning("*");return await d.raw(`
|
|
36
37
|
UPDATE fact
|
|
37
38
|
SET search_vector = to_tsvector('english', content)
|
|
38
39
|
WHERE id = ?
|
|
39
|
-
`,[
|
|
40
|
+
`,[p.id]),p}async function Xn(e){let[t]=await d("fact").where({uid:e});return t||null}async function Qn(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 Wt(e){return d("fact").whereRaw("? = ANY(source_document_ids)",[e]).where({status:"active"}).orderBy("createdAt","desc")}async function Vt(e,t){await d("fact").where({id:e}).update({status:"contradicted",contradictedById:t,validUntil:d.fn.now()})}async function ge(e,t){await d("fact").where({id:e}).update({status:"superseded",supersededById:t,validUntil:d.fn.now()})}async function er(e,t=[]){let o=new Set((t||[]).filter(i=>i!=null)),n=await Wt(e),r=0,s=0;for(let i of n){if(o.has(i.id))continue;(Array.isArray(i.sourceDocumentIds)?i.sourceDocumentIds:[]).length<=1?(await ge(i.id,null),await he({targetType:"fact",targetId:i.id,event:"SUPERSEDE",oldContent:i.content,newContent:null,triggeredBy:`reingest:doc=${e}`}),r++):(await d("fact").where({id:i.id}).update({sourceDocumentIds:d.raw("array_remove(source_document_ids, ?)",[e])}),s++)}return{superseded:r,dissociated:s}}async function Jt(e,{namespace:t,threshold:o=Ee,limit:n=5}){let r=B(e),s=`${Ct("embedding")} <=> ${Mt()}`;return d.transaction(async i=>{await i.raw("SET LOCAL hnsw.ef_search = 40");let{rows:a}=await i.raw(`
|
|
40
41
|
SELECT id, uid, content, category, status,
|
|
41
42
|
1 - (${s}) as similarity
|
|
42
43
|
FROM fact
|
|
@@ -46,25 +47,22 @@ or you can use a direct provider (Ollama / OpenAI / Voyage) for embeddings.`,"Op
|
|
|
46
47
|
AND 1 - (${s}) >= ?
|
|
47
48
|
ORDER BY ${s}
|
|
48
49
|
LIMIT ?
|
|
49
|
-
`,[r,t,r,o,r,n]);return
|
|
50
|
+
`,[r,t,r,o,r,n]);return a})}async function he({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 tr(e){e.length&&await d.raw(`UPDATE fact_lifecycle
|
|
50
51
|
SET access_count = access_count + 1,
|
|
51
52
|
last_accessed_at = NOW(),
|
|
52
53
|
stage = CASE WHEN stage = 'stable' THEN 'editing' ELSE stage END,
|
|
53
54
|
stage_entered_at = CASE WHEN stage = 'stable' THEN NOW() ELSE stage_entered_at END
|
|
54
|
-
WHERE fact_id = ANY(?)`,[e])}async function
|
|
55
|
+
WHERE fact_id = ANY(?)`,[e])}async function or(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 nr({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 rr(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 sr(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 ir(){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 ar(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 qn,jt,Ee,Zt=m(()=>{se();R();_e();Kt();me();$();I();v();qn=Jn.join(be,"audm-decision.md"),jt=c.memory.skipThreshold,Ee=c.memory.ambiguousThreshold});async function Z({podType:e,externalId:t,name:o,namespace:n,attrs:r={},entityId:s=null,connectionId:i=null,startedAt:a=null}){if(!t)throw new Error("upsertPod requires externalId; use insertPod for custom pods");let u=`pod-${V(16)}`,l=n||c.defaults.namespace,{rows:[f]}=await d.raw(`
|
|
55
56
|
INSERT INTO pod (uid, pod_type, name, namespace, attrs, entity_id, connection_id, external_id, started_at, created_at, updated_at)
|
|
56
57
|
VALUES (?, ?, ?, ?, ?::jsonb, ?, ?, ?, ?, NOW(), NOW())
|
|
57
58
|
ON CONFLICT (pod_type, external_id, namespace) WHERE external_id IS NOT NULL DO UPDATE SET
|
|
58
59
|
attrs = pod.attrs || EXCLUDED.attrs,
|
|
59
60
|
updated_at = NOW()
|
|
60
61
|
RETURNING *, (xmax = 0) AS "isNew"
|
|
61
|
-
`,[u,e,o,l,JSON.stringify(r),s,
|
|
62
|
+
`,[u,e,o,l,JSON.stringify(r),s,i,t,a]);return{pod:f,isNew:f.isNew}}async function zt(e){return d("pod").where({uid:e}).first()||null}async function Xt(e,t){await d.raw("UPDATE pod SET attrs = attrs || ?::jsonb, updated_at = NOW() WHERE id = ?",[JSON.stringify(t),e])}async function G(e,{docs:t=0,facts:o=0}){!t&&!o||await d.raw(`UPDATE pod
|
|
62
63
|
SET member_doc_count = member_doc_count + ?,
|
|
63
64
|
member_fact_count = member_fact_count + ?,
|
|
64
65
|
updated_at = NOW()
|
|
65
|
-
WHERE id = ?`,[t,o,e])}var
|
|
66
|
+
WHERE id = ?`,[t,o,e])}var z=m(()=>{se();R();I()});function to({sessionId:e,transcriptPath:t=null,cwd:o=null,turnCount:n=0,model:r=null,conclusion:s=null,summary:i=null}){return{session_id:e,transcript_path:t,cwd:o,turn_count:n,model:r,conclusion:s,summary:i}}function oo({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 eo,no=m(()=>{we();eo="claude_session"});import{writeFile as ur,readFile as lr,unlink as Ti}from"node:fs/promises";import{existsSync as dr,mkdirSync as pr}from"node:fs";import{dirname as ro}from"node:path";async function mr(){try{let e=await lr(X,"utf8");return JSON.parse(e)}catch{return null}}async function so(e){dr(ro(X))||pr(ro(X),{recursive:!0}),await ur(X,JSON.stringify(e,null,2),"utf8")}async function io({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||c.defaults.namespace,i=await mr();if(i&&i.session_id===e&&i.namespace===s){let l=await zt(i.pod_uid);if(l)return await Xt(l.id,{turn_count:(_r(l.attrs)||0)+1}),await fr(i),l}let a=new Date,{pod:u}=await Z({podType:eo,externalId:e,name:oo({sessionId:e,startedAt:a}),namespace:s,attrs:to({sessionId:e,transcriptPath:t,cwd:o,turnCount:1,model:n}),startedAt:a});return await so({session_id:e,pod_uid:u.uid,namespace:s,started_at:u.startedAt??a.toISOString(),last_seen_at:new Date().toISOString()}),u}async function fr(e){await so({...e,last_seen_at:new Date().toISOString()})}function _r(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 X,Ni,we=m(()=>{z();no();I();v();X=Ne,Ni=360*60*1e3});var ye={};w(ye,{attach:()=>Q,attachDocument:()=>hr,attachEntity:()=>gr,attachFact:()=>Er,detach:()=>wr,factIdsInPod:()=>Sr,listMembers:()=>yr,listPodsForMember:()=>Ir});async function Q(e,t,o,n="primary"){let{rowCount:r}=await d.raw(`INSERT INTO pod_membership (pod_id, member_type, member_id, role)
|
|
66
67
|
VALUES (?, ?, ?, ?)
|
|
67
|
-
ON CONFLICT (pod_id, member_type, member_id) DO NOTHING`,[e,t,o,n]);return r>0&&(t==="fact"?await
|
|
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();
|
|
68
|
+
ON CONFLICT (pod_id, member_type, member_id) DO NOTHING`,[e,t,o,n]);return r>0&&(t==="fact"?await G(e,{facts:1}):t==="document"&&await G(e,{docs:1})),{attached:r>0}}async function wr(e,t,o){let n=await d("pod_membership").where({podId:e,memberType:t,memberId:o}).del();return n>0&&(t==="fact"?await G(e,{facts:-1}):t==="document"&&await G(e,{docs:-1})),{detached:n>0}}async function yr(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 Ir(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 Sr(e){return await d("pod_membership").where({podId:e,memberType:"fact"}).pluck("memberId")}var Er,hr,gr,Ie=m(()=>{R();z();Er=(e,t,o)=>Q(e,"fact",t,o),hr=(e,t,o)=>Q(e,"document",t,o),gr=(e,t,o)=>Q(e,"entity",t,o)});import{execFileSync as Or}from"node:child_process";import{basename as ao}from"node:path";async function co({cwd:e,namespace:t=null}){if(!e)return null;let o=Tr(e),n=t||c.defaults.namespace,s=(o!==e?!1:Se(e)===e)?o:Se(e),{pod:i}=await Z({podType:Ar,externalId:o,name:ao(o)||o,namespace:n,attrs:{root_path:o,git_root:s||null,display_name:ao(o)||o,discovered_at:new Date().toISOString()},startedAt:new Date});return i}function Tr(e){return Se(e)||e}function Se(e){try{return Or("git",["rev-parse","--show-toplevel"],{cwd:e,encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim()||null}catch{return null}}var Ar,uo=m(()=>{z();Ie();I();Ar="project"});var lo={};w(lo,{ensureActivePodsForHook:()=>br});async function br({sessionId:e,cwd:t=null,transcriptPath:o=null,model:n=null,namespace:r=null}){let s=null;if(e)try{s=await io({sessionId:e,transcriptPath:o,cwd:t,model:n,namespace:r})}catch{s=null}let i=null;if(t)try{i=await co({cwd:t,namespace:r})}catch{i=null}let a=[s,i].filter(Boolean).map(u=>u.uid);return{sessionPod:s,projectPod:i,podUids:a}}var po=m(()=>{we();uo()});$();import{readFileSync as Dr,writeFileSync as Rr,mkdirSync as Lr}from"node:fs";import{createHash as Nr}from"node:crypto";v();import{resolve as Ro}from"node:path";import{existsSync as Ce}from"node:fs";import{config as Me}from"dotenv";function xe(){let e=Ro(process.cwd(),".env");Ce(e)&&Me({path:e,quiet:!0}),Ce(K)&&K!==e&&Me({path:K,quiet:!0}),process.env.SIGIL_AGENT||(process.env.SIGIL_AGENT="claude-code")}v();xe();var vr=new Set(["Read","Glob","Grep","WebFetch","WebSearch","TaskCreate","TaskUpdate","TaskList","TaskGet","TaskOutput","ToolSearch","Skill","Agent"]),Pr=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"]),Cr=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"]),xr=["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"],fo=300*1e3,_o=ve;function kr(){try{let e=JSON.parse(Dr(_o,"utf8")),t=Date.now();for(let o of Object.keys(e))t-e[o]>fo&&delete e[o];return e}catch{return{}}}function mo(e){try{Lr(y,{recursive:!0}),Rr(_o,JSON.stringify(e),"utf8")}catch{}}function Ur(e){let t=kr(),o=t[e],n=Date.now();return o&&n-o<fo?(t[e]=n,mo(t),!0):(t[e]=n,mo(t),!1)}function Br(e){return(e.replace(/^(\w+=\S+\s+)+/,"").trim().split(/\s+/)[0]||"").split("/").pop()}function Gr(e,t){if(vr.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=Br(o);if(Pr.has(n))return null;if(n==="git"||n==="gh"){let a=o.replace(/^(git|gh)\s+/,"").split(/\s+/)[0];if(Mr.has(a))return null;if(Cr.has(a))return{content:`Ran: ${o.slice(0,200)}`,dedupKey:`Bash:${n} ${a}`}}if(["npm","pnpm","yarn"].includes(n)){let a=o.replace(/^\S+\s+/,"").split(/\s+/)[0];if(["test","run","start","lint"].includes(a))return null}let r=o.toLowerCase();return xr.some(a=>r.includes(a))?{content:`Ran: ${o.slice(0,200)}`,dedupKey:`Bash:${n}:${Nr("md5").update(o).digest("hex").slice(0,8)}`}:null}return null}async function $r(){let e=[];for await(let u of process.stdin)e.push(u);let t=Buffer.concat(e).toString("utf8").trim();return x()}function x(){let e={hookSpecificOutput:{hookEventName:"PostToolUse"}};process.stdout.write(JSON.stringify(e))}$r();
|