@anmol-srv/sigil 0.11.0 → 0.12.1
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/dist/cli.js +397 -339
- package/dist/daemon.js +198 -121
- package/dist/hooks/post-tool-use.js +18 -18
- package/dist/hooks/session-end.js +28 -28
- package/dist/hooks/stop.js +36 -36
- package/dist/hooks/user-prompt-submit.js +17 -17
- package/dist/server.js +26 -26
- package/package.json +1 -1
- package/src/gui/web/api.js +37 -0
- package/src/gui/web/app.css +114 -50
- package/src/gui/web/app.js +244 -92
- package/src/gui/web/components.js +90 -0
- package/src/gui/web/design/colors_and_type.css +178 -0
- package/src/gui/web/design/sigil-mark-mono.svg +8 -0
- package/src/gui/web/design/sigil-mark.svg +26 -0
- package/src/gui/web/index.html +64 -42
- package/src/gui/web/toast.js +62 -0
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire as __sigilCreateRequire } from 'node:module'; const require = __sigilCreateRequire(import.meta.url);
|
|
3
|
-
var
|
|
3
|
+
var wn=Object.defineProperty;var m=(e,t)=>()=>(e&&(t=e(e=0)),t);var y=(e,t)=>{for(var n in t)wn(e,n,{get:t[n],enumerable:!0})};function N(e){if(!e||typeof e!="string")return e;let t=e;for(let n of yn)t=t.replace(n,k);return t=t.replace(In,(n,o)=>`${o}=${k}`),t=t.replace(Sn,(n,o)=>`${o}${k}:${k}@`),t=t.replace(An,(n,o)=>`${o}=${k}`),t}var k,yn,In,Sn,On,An,$=m(()=>{k="***MASKED***",yn=[/\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],In=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"),Sn=/(\w+:\/\/)([^:/\s]+):([^@\s]{3,})@/g,On=["DATABASE_URL","REDIS_URL","MONGODB_URI","MONGO_URI","POSTGRES_URL","DSN","CONNECTION_STRING","ENCRYPTION_KEY","JWT_SECRET","SIGIL_ENCRYPTION_KEY","SESSION_SECRET","WEBHOOK_SECRET"],An=new RegExp(`\\b(${On.join("|")})\\s*[=:]\\s*["']?([^\\s"']+)["']?`,"gi")});import{fileURLToPath as Tn}from"node:url";import{dirname as Ae,join as _}from"node:path";import{existsSync as Te}from"node:fs";import{homedir as bn}from"node:os";function Dn(){let e=Ae(Tn(import.meta.url));for(let t=0;t<10;t++){if(Te(_(e,"package.json"))&&Te(_(e,"prompts")))return e;let n=Ae(e);if(n===e)break;e=n}return process.cwd()}var H,be,Vr,De,w,K,Jr,qr,Zr,Re,Le,Ne,zr,ve,Xr,Qr,es,ts,ns,os,rs,ss,is,as,Pe,cs,us,v=m(()=>{H=Dn(),be=_(H,"prompts"),Vr=_(H,"src","db","migrations"),De=bn(),w=_(De,".sigil"),K=_(w,".env"),Jr=_(w,"db"),qr=_(w,"CLAUDE.md"),Zr=_(w,"schemas"),Re=_(w,".hook-errors.log"),Le=_(w,".last-clean-doctor"),Ne=_(w,".active-session.json"),zr=_(w,".stop-cursor.json"),ve=_(w,".hook-dedup.json"),Xr=_(w,"sock"),Qr=_(w,"sigild.pid"),es=_(w,"sigild.log"),ts=_(w,"heartbeat.json"),ns=_(w,"onboarding-state.json"),os=_(w,"gui.token"),rs=_(H,"dist","gui"),ss=_(H,"src","gui","web"),is=_(w,"iroh"),as=_(w,"identity.key"),Pe=_(De,".claude"),cs=_(Pe,"settings.json"),us=_(Pe,"CLAUDE.md")});var Ue={};y(Ue,{default:()=>c});var E,ke,Ln,c,I=m(()=>{E=(e,t)=>process.env[e]??t,ke=E("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.
|
|
4
4
|
PGlite was deprecated; existing PGlite data at ~/.sigil/db is preserved but unreachable from this version.
|
|
5
5
|
Set SIGIL_DB_TYPE=postgres in ~/.sigil/.env and configure SIGIL_DB_HOST / PORT / NAME / USER / PASSWORD.
|
|
6
|
-
Run \`sigil init\` for an interactive setup.`);
|
|
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
|
|
8
|
-
`,"utf8")}catch{}}async function
|
|
9
|
-
`).filter(Boolean),
|
|
10
|
-
`))if(
|
|
6
|
+
Run \`sigil init\` for an interactive setup.`);Ln={db:{type:"postgres",get url(){return E("SIGIL_DATABASE_URL",E("DATABASE_URL",""))||null},get host(){return E("SIGIL_DB_HOST","localhost")},get port(){return Number(E("SIGIL_DB_PORT",5432))},get database(){return E("SIGIL_DB_NAME","sigil")},get user(){return E("SIGIL_DB_USER","sigil_app")},get password(){return E("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:{get provider(){return process.env.LLM_PROVIDER||""},get openaiApiKey(){return process.env.OPENAI_API_KEY||""},get openaiModel(){return process.env.LLM_OPENAI_MODEL||"gpt-4o-mini"},get ollamaHost(){return process.env.LLM_OLLAMA_HOST||process.env.OLLAMA_HOST||"http://localhost:11434"},get ollamaModel(){return process.env.LLM_OLLAMA_MODEL||"qwen2.5:7b"},get cliModel(){return process.env.LLM_CLI_MODEL||"haiku"},get apiKey(){return process.env.ANTHROPIC_API_KEY||""},get openrouterApiKey(){return process.env.OPENROUTER_API_KEY||""},get openrouterModel(){return process.env.LLM_OPENROUTER_MODEL||"google/gemini-flash-latest"},get openrouterBaseUrl(){return process.env.LLM_OPENROUTER_BASE_URL||""},get openrouterReferer(){return process.env.LLM_OPENROUTER_REFERER||"https://github.com/Anmol-Srv/sigil"},get openrouterTitle(){return process.env.LLM_OPENROUTER_TITLE||"Sigil"},get extractionModel(){return process.env.LLM_EXTRACTION_MODEL||""},get decisionModel(){return process.env.LLM_DECISION_MODEL||""},get entityModel(){return process.env.LLM_ENTITY_MODEL||""},get maxRetries(){return Number(process.env.LLM_MAX_RETRIES)||3},get cliTimeout(){return 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:E("SIGIL_HTTP_ENABLED","true")!=="false",host:E("SIGIL_HTTP_HOST","127.0.0.1"),port:Number(E("SIGIL_HTTP_PORT",7777))},network:{mode:E("SIGIL_MODE","solo"),enabled:E("SIGIL_NETWORK_ENABLED",null)===null?E("SIGIL_MODE","solo")!=="solo":E("SIGIL_NETWORK_ENABLED","false")!=="false",masterNodeId:E("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:E("SIGIL_SYNTHESIZE","true")!=="false",synthesizeModel:E("SIGIL_SYNTH_MODEL","")},ingest:{eagerExtract:E("SIGIL_EAGER_EXTRACT","true")!=="false"},hebbian:{entity:{enabled:E("SIGIL_HEBBIAN_ENTITY_ENABLED",null,"true")!=="false",eta:Number(E("SIGIL_HEBBIAN_ENTITY_ETA",null,1)),cap:Number(E("SIGIL_HEBBIAN_ENTITY_CAP",null,50)),halfLifeDays:Number(E("SIGIL_HEBBIAN_ENTITY_HALF_LIFE_DAYS",null,30)),minEffective:Number(E("SIGIL_HEBBIAN_ENTITY_MIN_EFFECTIVE",null,.5)),rrfWeight:Number(E("SIGIL_HEBBIAN_ENTITY_RRF_WEIGHT",null,.3)),maxWriteEntities:Number(E("SIGIL_HEBBIAN_ENTITY_MAX_WRITE",null,12)),expandPerSeed:Number(E("SIGIL_HEBBIAN_ENTITY_EXPAND_PER_SEED",null,3))}}},c=Ln});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 n=t.searchParams.get("sslmode"),o=vn(t.hostname,n),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 o!==void 0&&(r.ssl=o),t.searchParams.get("application_name")||(r.application_name="sigil"),r}function vn(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(n=>n.test(e)))return Nn.some(n=>n.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(n=>n.test(t))?"local":"unknown"}catch{return"unknown"}}var Nn,$e,Fe=m(()=>{Nn=[/\.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={};y(F,{default:()=>d});import Pn from"knex";function Cn(e){return Array.isArray(e)?e.map(te):e&&typeof e=="object"?te(e):e}function xn(e,t){return t(Mn(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[n,o]of Object.entries(e))t[n.replace(/_([a-z])/g,(r,s)=>s.toUpperCase())]=o;return t}function Mn(e){return e.replace(/[A-Z]/g,t=>`_${t.toLowerCase()}`)}var We,Ve,d,R=m(()=>{I();je();We=Ye(c),Ve=Pn({client:"pg",connection:We.connection,pool:{min:2,max:10},postProcessResponse:Cn,wrapIdentifier:xn});Ve.__sigilDriver=We;d=Ve});var Xe={};y(Xe,{validateConfig:()=>ze,validateConfigDeep:()=>kn});function ze(){let e=[];return Un(e),Bn(e),Gn(e),e}async function kn(){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 Un(e){let{provider:t,model:n}=c.embedding;if(t&&n){let o=Object.keys(Je).find(r=>Je[r].some(s=>s.test(n)));o&&o!==t&&e.push({level:"fail",code:"EMBEDDING_PROVIDER_MODEL_MISMATCH",message:`EMBEDDING_PROVIDER=${t} but EMBEDDING_MODEL=${n} is a ${o} model.`,fix:$n(t,n,o)})}if(t&&Ze[t]){let o=Ze[t];c.embedding[o]||e.push({level:"fail",code:"EMBEDDING_PROVIDER_MISSING_KEY",message:`EMBEDDING_PROVIDER=${t} but no ${Y(o)} found.`,fix:`Set ${Y(o)} in ~/.sigil/.env, or run 'sigil init' to reconfigure.`})}}function Bn(e){let{provider:t}=c.llm;if(t&&qe[t]){let n=qe[t];c.llm[n]||e.push({level:"fail",code:"LLM_PROVIDER_MISSING_KEY",message:`LLM_PROVIDER=${t} but no ${Y(n)} found.`,fix:`Set ${Y(n)} 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 Gn(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 $n(e,t,n){let o={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=${n} (matches your current model), or change EMBEDDING_MODEL to one of: ${o}`}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 oe={};y(oe,{HOOK_ERROR_LOG:()=>j,LAST_CLEAN_DOCTOR_PATH:()=>W,clearLastCleanDoctor:()=>qn,failClosedOnBadConfig:()=>jn,getUnackedErrorCount:()=>Vn,markDoctorClean:()=>Jn,readRecentHookErrors:()=>Wn,recordHookError:()=>et});import{appendFile as Hn,readFile as ne,writeFile as Kn,unlink as Fn}from"node:fs/promises";import{createHash as Yn}from"node:crypto";async function et(e,t,n=null){try{let o={ts:new Date().toISOString(),hook:e,error:N(t?.message||String(t)),input_hash:n?Zn(n):null};await Hn(j,JSON.stringify(o)+`
|
|
8
|
+
`,"utf8")}catch{}}async function jn(e,t=null){try{let{validateConfig:n}=await Promise.resolve().then(()=>(Qe(),Xe)),o=n().filter(r=>r.level==="fail");if(o.length===0)return!1;for(let r of o){let s=new Error(`${r.code}: ${r.message} \u2014 fix: ${r.fix}`);await et(e,s,t)}return!0}catch{return!1}}async function Wn(e=10){let t;try{t=await ne(j,"utf8")}catch{return[]}let n=t.split(`
|
|
9
|
+
`).filter(Boolean),o=[];for(let r of n.slice(-e))try{o.push(JSON.parse(r))}catch{}return o}async function Vn(){let e=0;try{let o=await ne(W,"utf8");e=new Date(o.trim()).getTime()}catch{}let t;try{t=await ne(j,"utf8")}catch{return 0}let n=0;for(let o of t.split(`
|
|
10
|
+
`))if(o.trim())try{let r=JSON.parse(o);(r.ts?new Date(r.ts).getTime():0)>e&&(n+=1)}catch{}return n}async function Jn(){try{await Kn(W,new Date().toISOString(),"utf8")}catch{}}async function qn(){try{await Fn(W)}catch{}}function Zn(e){try{let t=typeof e=="string"?e:JSON.stringify(e);return Yn("sha256").update(t).digest("hex").slice(0,12)}catch{return null}}var j,W,re=m(()=>{v();$();j=Re,W=Le});var tt,nt=m(()=>{tt="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict"});import{webcrypto as ot}from"node:crypto";function Xn(e){if(e<0||e>1024)throw new RangeError("Wrong ID size");!L||L.length<e?(L=Buffer.allocUnsafe(e*zn),ot.getRandomValues(L),P=0):P+e>L.length&&(ot.getRandomValues(L),P=0),P+=e}function V(e=21){Xn(e|=0);let t="";for(let n=P-e;n<P;n++)t+=tt[L[n]&63];return t}var zn,L,P,se=m(()=>{nt();zn=128});var rt={};y(rt,{chat:()=>Qn,meta:()=>eo,setup:()=>to});async function Qn(e,{model:t,jsonMode:n=!1}={}){let o=t||c.llm.openaiModel,r=[{role:"user",content:e}];n&&!e.toLowerCase().includes("json")&&r.unshift({role:"system",content:"Respond with valid JSON."});let s={model:o,messages:r};n&&(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:o}}async function to({existing:e,clack:t}){let n=e.OPENAI_API_KEY||"",o=await t.text({message:"OpenAI API key (paste, then Enter)",placeholder:n?"(keep existing \u2014 press Enter)":"sk-proj-...",validate:r=>{if(!r&&!n)return"API key is required";if(r&&!r.startsWith("sk-"))return'OpenAI keys start with "sk-" \u2014 check paste'}});return t.isCancel(o)?null:{env:{OPENAI_API_KEY:o||n}}}var eo,st=m(()=>{I();eo={id:"openai",label:"OpenAI",hint:"gpt-4o-mini"}});function T(e){return Math.ceil((e||"").length/4)}function it(e,t,n){let o=no[e];return o?(t*o.input+n*o.output)/1e6:0}function ie({provider:e,model:t,caller:n,input:o,response:r,inputTokens:s,outputTokens:i,cost:a,durationMs:u,status:l,error:f}){d("llm_log").insert({provider:e,model:t,caller:n,input:o?.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 n=1;n<=t;n++)try{return await e()}catch(o){if(n===t)throw o;let r=Math.min(1e3*2**(n-1),1e4);await new Promise(s=>setTimeout(s,r))}}var no,U=m(()=>{R();no={"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={};y(ct,{chat:()=>ro,meta:()=>so,setup:()=>io});async function oo(){if(!ae){let{default:e}=await import("@anthropic-ai/sdk");ae=new e({apiKey:c.llm.apiKey})}return ae}async function ro(e,{model:t,jsonMode:n=!1}={}){let o=t||"claude-haiku-4-5-20251001",r=await oo(),s=[{role:"user",content:e}],i=n?"Respond with valid JSON only. No explanation or wrapping.":void 0,a=await r.messages.create({model:o,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:o}}async function io({existing:e,clack:t}){let n=e.ANTHROPIC_API_KEY||"",o=await t.text({message:"Anthropic API key (paste, then Enter)",placeholder:n?"(keep existing \u2014 press Enter)":"sk-ant-...",validate:r=>{if(!r&&!n)return"API key is required";if(r&&!r.startsWith("sk-ant-"))return'Anthropic keys start with "sk-ant-" \u2014 check paste'}});return t.isCancel(o)?null:{env:{ANTHROPIC_API_KEY:o||n}}}var ae,so,ut=m(()=>{I();U();ae=null;so={id:"anthropic",label:"Anthropic",hint:"Claude Haiku \u2014 requires API key"}});var dt={};y(dt,{chat:()=>co,meta:()=>uo,setup:()=>lo});async function co(e,{model:t,jsonMode:n=!1}={}){let o=t||c.llm.openrouterModel;if(!c.llm.openrouterApiKey)throw new Error("OPENROUTER_API_KEY is not set");if(!o)throw new Error("No OpenRouter model resolved. Set LLM_OPENROUTER_MODEL or pass `model`.");let r=[{role:"user",content:e}];n&&!e.toLowerCase().includes("json")&&r.unshift({role:"system",content:"Respond with valid JSON."});let s={model:o,messages:r};n&&(s.response_format={type:"json_object"});let i=(c.llm.openrouterBaseUrl||ao).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 h=await u.text();throw new Error(`OpenRouter error ${u.status}: ${h}`)}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||o}}async function lo({existing:e,clack:t}){let n={},o=e.OPENROUTER_API_KEY||"",r=await t.text({message:"OpenRouter API key (paste, then Enter)",placeholder:o?"(keep existing \u2014 press Enter)":"sk-or-v1-...",validate:u=>{if(!u&&!o)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;n.OPENROUTER_API_KEY=r||o;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;n.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;n.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;n.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;n.SIGIL_SYNTH_MODEL=f||e.SIGIL_SYNTH_MODEL||C.synthesis}return t.note(`OpenRouter can drive both LLM calls and embeddings.
|
|
11
11
|
You will pick an embedding provider in the next step \u2014 "openrouter" is an option,
|
|
12
|
-
or you can use a direct provider (Ollama / OpenAI / Voyage) for embeddings.`,"OpenRouter scope"),{env:
|
|
12
|
+
or you can use a direct provider (Ollama / OpenAI / Voyage) for embeddings.`,"OpenRouter scope"),{env:n}}var ao,uo,lt,C,pt=m(()=>{I();ao="https://openrouter.ai/api/v1";uo={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={};y(mt,{chat:()=>Eo,meta:()=>ho,setup:()=>go});import{spawn as po}from"node:child_process";function _o(e,t){let n=c.llm.cliTimeout||12e4;return new Promise((o,r)=>{let s=po("claude",e,{stdio:["pipe","pipe","pipe"]}),i=setTimeout(()=>{s.kill("SIGTERM"),r(new Error(`claude CLI timed out after ${n}ms`))},n),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),o({stdout:a,stderr:u,code:l})}),s.stdin.write(t),s.stdin.end()})}async function Eo(e,{model:t,jsonMode:n=!1}={}){let o=t||c.llm.cliModel||"haiku",r=mo[o]||o,s=["-p","--model",r,"--output-format","json"];n&&s.push("--json-schema",fo);let{stdout:i,stderr:a,code:u}=await _o(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=n&&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 go(){return{env:{}}}var mo,fo,ho,ft=m(()=>{I();U();mo={"claude-haiku-4-5-20251001":"haiku","claude-sonnet-4-6":"sonnet","claude-opus-4-6":"opus"},fo=JSON.stringify({type:"object",additionalProperties:!0});ho={id:"claude-cli",label:"Claude Code",hint:"uses your existing subscription \u2014 no extra API key"}});var _t={};y(_t,{chat:()=>wo,meta:()=>yo,setup:()=>Io});async function wo(e,{model:t,jsonMode:n=!1}={}){let o=t||c.llm.ollamaModel,r=`${c.llm.ollamaHost}/api/chat`,s={model:o,messages:[{role:"user",content:e}],stream:!1};n&&(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:o}}async function Io({existing:e,clack:t}){let n=e.OLLAMA_HOST||"http://localhost:11434",o=await t.text({message:"Ollama host",placeholder:n,initialValue:n,validate:r=>{if(r&&!/^https?:\/\//.test(r))return"Must start with http:// or https://"}});return t.isCancel(o)?null:{env:{OLLAMA_HOST:o||n}}}var yo,Et=m(()=>{I();U();yo={id:"ollama",label:"Ollama",hint:"local models \u2014 no API cost"}});function J(e,t){if(t<1)return[];let n=[];for(let o=0;o<e.length;o+=t)n.push(e.slice(o,o+t));return n}var ce=m(()=>{});var ht={};y(ht,{embedBatch:()=>Oo});async function Oo(e,{model:t,ollamaHost:n}){let o=J(e,So),r=[];for(let s of o){let i=await fetch(`${n}/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 So,gt=m(()=>{ce();So=50});var wt={};y(wt,{embedBatch:()=>Ao});async function Ao(e,{model:t,openaiApiKey:n,dimensions:o}={}){let r={model:t,input:e};o&&/^text-embedding-3/.test(t)&&(r.dimensions=o);let s=await fetch("https://api.openai.com/v1/embeddings",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},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={};y(It,{embedBatch:()=>bo});async function bo(e,{model:t,voyageApiKey:n,inputType:o="document",dimensions:r}={}){if(!n)throw new Error("VOYAGE_API_KEY is not set. Get one at dashboard.voyageai.com.");let s=J(e,To),i=[];for(let a of s){let u={input:a,model:t||"voyage-3-large",input_type:o==="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 ${n}`},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,h)=>g.index-h.index);i.push(...p.map(g=>g.embedding))}return i}var To,St=m(()=>{ce();To=50});var Ot={};y(Ot,{embedBatch:()=>Ro});async function Ro(e,{model:t,openrouterApiKey:n,openrouterBaseUrl:o,openrouterReferer:r,openrouterTitle:s,dimensions:i}={}){if(!n)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=(o||Do).replace(/\/+$/,""),l={"Content-Type":"application/json",Authorization:`Bearer ${n}`};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((h,S)=>h.index-S.index).map(h=>h.embedding)}var Do,At=m(()=>{Do="https://openrouter.ai/api/v1"});import{spawn as Lo}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 n=await t();ue[e]=n.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 n=await t();le[e]=n.embedBatch}return le[e]}function Rt(e,t){if(!e)return{provider:t,model:null};let n=e.indexOf(":");return n>0&&de[e.slice(0,n)]?{provider:e.slice(0,n),model:e.slice(n+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 No(){return new Promise(e=>{let t=Lo("claude",["--version"],{stdio:"pipe"});t.on("error",()=>e(!1)),t.on("close",n=>e(n===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 No())return O="claude-cli",O;throw new Error(`No LLM provider available. Either:
|
|
13
13
|
- Set LLM_PROVIDER (openai, anthropic, openrouter, ollama, claude-cli)
|
|
14
14
|
- Set ANTHROPIC_API_KEY, OPENAI_API_KEY, or OPENROUTER_API_KEY
|
|
15
15
|
- Start Ollama locally
|
|
@@ -18,26 +18,26 @@ or you can use a direct provider (Ollama / OpenAI / Voyage) for embeddings.`,"Op
|
|
|
18
18
|
- Set VOYAGE_API_KEY (recommended \u2014 best quality)
|
|
19
19
|
- Start Ollama locally
|
|
20
20
|
- Set OPENAI_API_KEY
|
|
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
|
|
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 xt(){return`?::halfvec(${Pt()})`}var me=m(()=>{I()});import{createHash as vo}from"node:crypto";function Co(e,t,n,o="document"){let r=vo("sha256");return r.update(e),r.update("\0"),r.update(t),r.update("\0"),r.update(o),r.update("\0"),r.update(n),r.digest("hex")}async function xo(e){if(!e.length)return new Map;let t=await d("embedding_cache").whereIn("key",e).select("key","embedding");return new Map(t.map(n=>[n.key,Mo(n.embedding)]))}function Mo(e){return Array.isArray(e)||typeof e!="string"?e:(e.startsWith("[")?e.slice(1,-1):e).split(",").map(Number)}async function ko(e){e.length&&await d("embedding_cache").whereIn("key",e).update({hits:d.raw("hits + 1"),lastUsedAt:d.fn.now()})}async function Uo(e,t,n){if(e.length){for(let{key:o,embedding:r}of e)await d.raw(`
|
|
22
22
|
INSERT INTO embedding_cache (key, provider, model, embedding, hits, created_at, last_used_at)
|
|
23
23
|
VALUES (?, ?, ?, ?, 0, NOW(), NOW())
|
|
24
24
|
ON CONFLICT (key) DO UPDATE
|
|
25
25
|
SET last_used_at = NOW(),
|
|
26
26
|
hits = embedding_cache.hits + 1
|
|
27
|
-
`,[
|
|
27
|
+
`,[o,t,n,B(r)]);await Go()}}async function Go(){let e=Date.now();if(e-kt<Bo)return;kt=e;let[{count:t}]=await d("embedding_cache").count("key as count"),n=Number(t);if(n<=Mt)return;let o=Math.min(n-Mt,Po);await d.raw(`
|
|
28
28
|
DELETE FROM embedding_cache WHERE key IN (
|
|
29
29
|
SELECT key FROM embedding_cache ORDER BY last_used_at ASC LIMIT ?
|
|
30
30
|
)
|
|
31
|
-
`,[
|
|
32
|
-
`)})}let g=a.filter(
|
|
31
|
+
`,[o])}async function Ut(e,t,n,o,r,s={}){if(!e.length)return[];let i=s.inputType||r?.inputType||"document",a=e.map(h=>Co(t,n,h,i)),u=await xo(a),l=[],f=[],p=new Array(e.length);for(let h=0;h<e.length;h++){let S=u.get(a[h]);S?p[h]=S:(l.push(e[h]),f.push(h))}if(l.length){let h=await o(l,r),S=[];for(let b=0;b<l.length;b++){let D=f[b];p[D]=h[b],S.push({key:a[D],embedding:h[b]})}Uo(S,t,n).catch(b=>{process.stderr.write(`[embedding-cache] store failed: ${b.message}
|
|
32
|
+
`)})}let g=a.filter(h=>u.has(h));return g.length&&ko(g).catch(()=>{}),p}var Mt,Po,kt,Bo,Bt=m(()=>{me();R();Mt=1e4,Po=500;kt=0,Bo=6e4});var $t={};y($t,{dimensions:()=>$o,embed:()=>fe,embedBatch:()=>Gt});async function fe(e,t={}){let[n]=await Gt([e],t);return n}async function Gt(e,{inputType:t="document"}={}){if(!e.length)return[];let n=await vt(),o=await Dt(n),r=c.embedding.model,s={...c.embedding,inputType:t};return Ut(e,n,r,o,s,{inputType:t})}var $o,_e=m(()=>{I();pe();Bt();({dimensions:$o}=c.embedding)});async function Ho(e){let t=await Nt();return Rt(e,t)}async function Ht(e,{model:t,caller:n}={}){let{provider:o,model:r}=await Ho(t),s=await bt(o),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:o,model:a.model,caller:n,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:o,model:r,caller:n,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={};y(Ft,{currentAgent:()=>Wo,currentDeviceId:()=>jo,currentRequestContext:()=>Yo,runWithRequestContext:()=>Fo});import{AsyncLocalStorage as Ko}from"node:async_hooks";function Fo(e,t){return q.run(e,t)}function Yo(){return q.getStore()||null}function jo(){return q.getStore()?.device?.id??null}function Wo(){return q.getStore()?.agent??process.env.SIGIL_AGENT??null}var q,Yt=m(()=>{q=new Ko});var qt={};y(qt,{deleteFact:()=>sr,deleteNamespace:()=>ar,findByUid:()=>Xo,findSimilar:()=>Jt,getFactCount:()=>rr,getHotFacts:()=>nr,insertFact:()=>x,listByCategory:()=>Qo,listByDocument:()=>Wt,listFacts:()=>or,listNamespaces:()=>ir,markContradicted:()=>Vt,markSuperseded:()=>ge,recordAccess:()=>tr,saveFact:()=>Zo,supersedeStaleDocFacts:()=>er});import{readFile as Vo}from"node:fs/promises";import Jo from"node:path";async function Zo({content:e,category:t,confidence:n,importance:o,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 x({content:e,category:t,confidence:n,importance:o,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 zo(e,p.content);if(S==="UPDATE"){let D=await x({content:e,category:t,confidence:n,importance:o,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 x({content:e,category:t,confidence:n,importance:o,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 x({content:e,category:t,confidence:n,importance:o,namespace:r,sourceDocumentIds:s,sourceSection:i,embedding:u}),audm:{...g,decision:"llm:ADD"}}}return{action:"ADD",fact:await x({content:e,category:t,confidence:n,importance:o,namespace:r,sourceDocumentIds:s,sourceSection:i,embedding:u}),audm:{...g,decision:"below-ambiguous"}}}async function zo(e,t){let o=`${await Vo(qo,"utf8")}
|
|
33
33
|
|
|
34
34
|
**EXISTING FACT:** ${t}
|
|
35
35
|
|
|
36
|
-
**NEW FACT:** ${e}`,s=(await Ht(
|
|
36
|
+
**NEW FACT:** ${e}`,s=(await Ht(o,{model:c.llm.decisionModel,caller:"audm"})).trim().toUpperCase();return s.includes("UPDATE")?"UPDATE":s.includes("CONTRADICT")?"CONTRADICT":"ADD"}async function x({content:e,category:t,confidence:n,importance:o,namespace:r,sourceDocumentIds:s,sourceSection:i,embedding:a}){let u=`fact-${V(16)}`,l=null,f=null;try{let{currentDeviceId:g,currentAgent:h}=await Promise.resolve().then(()=>(Yt(),Ft));l=g(),f=h()}catch{}let[p]=await d("fact").insert({uid:u,content:e,category:t,confidence:n||"medium",importance:o||"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(`
|
|
37
37
|
UPDATE fact
|
|
38
38
|
SET search_vector = to_tsvector('english', content)
|
|
39
39
|
WHERE id = ?
|
|
40
|
-
`,[p.id]),p}async function
|
|
40
|
+
`,[p.id]),p}async function Xo(e){let[t]=await d("fact").where({uid:e});return t||null}async function Qo(e,{namespace:t,limit:n=50}={}){let o=d("fact").where({category:e,status:"active"}).orderBy("createdAt","desc").limit(n);return t&&o.where({namespace:t}),o}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 n=new Set((t||[]).filter(i=>i!=null)),o=await Wt(e),r=0,s=0;for(let i of o){if(n.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:n=Ee,limit:o=5}){let r=B(e),s=`${Ct("embedding")} <=> ${xt()}`;return d.transaction(async i=>{await i.raw("SET LOCAL hnsw.ef_search = 40");let{rows:a}=await i.raw(`
|
|
41
41
|
SELECT id, uid, content, category, status,
|
|
42
42
|
1 - (${s}) as similarity
|
|
43
43
|
FROM fact
|
|
@@ -47,22 +47,22 @@ or you can use a direct provider (Ollama / OpenAI / Voyage) for embeddings.`,"Op
|
|
|
47
47
|
AND 1 - (${s}) >= ?
|
|
48
48
|
ORDER BY ${s}
|
|
49
49
|
LIMIT ?
|
|
50
|
-
`,[r,t,r,
|
|
50
|
+
`,[r,t,r,n,r,o]);return a})}async function he({targetType:e,targetId:t,event:n,oldContent:o,newContent:r,triggeredBy:s}){await d("history").insert({targetType:e,targetId:t,event:n,oldContent:o||null,newContent:r||null,triggeredBy:s||null})}async function tr(e){e.length&&await d.raw(`UPDATE fact_lifecycle
|
|
51
51
|
SET access_count = access_count + 1,
|
|
52
52
|
last_accessed_at = NOW(),
|
|
53
53
|
stage = CASE WHEN stage = 'stable' THEN 'editing' ELSE stage END,
|
|
54
54
|
stage_entered_at = CASE WHEN stage = 'stable' THEN NOW() ELSE stage_entered_at END
|
|
55
|
-
WHERE fact_id = ANY(?)`,[e])}async function
|
|
55
|
+
WHERE fact_id = ANY(?)`,[e])}async function nr(e,{limit:t=10,since:n}={}){let o=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&&o.where({"f.namespace":e}),n&&o.where("fl.last_accessed_at",">=",n),o}async function or({namespace:e,limit:t=50,offset:n=0,category:o}={}){let r=d("fact").where({status:"active"}).select("id","uid","content","category","confidence","importance","createdAt","namespace").orderBy("createdAt","desc").limit(t).offset(n);return e&&r.where({namespace:e}),o&&r.where({category:o}),r}async function rr(e){let t=d("fact").where({status:"active"});e&&t.where({namespace:e});let[{count:n}]=await t.count("id as count");return Number(n)}async function sr(e){let n=typeof e=="string"&&e.length>8?{uid:e}:{id:Number(e)},o=await d("fact").where(n).first();return o?(await d("fact_entity").where({factId:o.id}).del(),await d("fact").where({id:o.id}).del(),o):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(),n=await d("chunk").where({namespace:e}).del(),o=await d("document").where({namespace:e}).del(),r=await d("entity").where({namespace:e}).del();return{factsDeleted:t,chunksDeleted:n,docsDeleted:o,entitiesDeleted:r}}var qo,jt,Ee,Zt=m(()=>{se();R();_e();Kt();me();$();I();v();qo=Jo.join(be,"audm-decision.md"),jt=c.memory.skipThreshold,Ee=c.memory.ambiguousThreshold});async function Z({podType:e,externalId:t,name:n,namespace:o,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=o||c.defaults.namespace,{rows:[f]}=await d.raw(`
|
|
56
56
|
INSERT INTO pod (uid, pod_type, name, namespace, attrs, entity_id, connection_id, external_id, started_at, created_at, updated_at)
|
|
57
57
|
VALUES (?, ?, ?, ?, ?::jsonb, ?, ?, ?, ?, NOW(), NOW())
|
|
58
58
|
ON CONFLICT (pod_type, external_id, namespace) WHERE external_id IS NOT NULL DO UPDATE SET
|
|
59
59
|
attrs = pod.attrs || EXCLUDED.attrs,
|
|
60
60
|
updated_at = NOW()
|
|
61
61
|
RETURNING *, (xmax = 0) AS "isNew"
|
|
62
|
-
`,[u,e,
|
|
62
|
+
`,[u,e,n,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:n=0}){!t&&!n||await d.raw(`UPDATE pod
|
|
63
63
|
SET member_doc_count = member_doc_count + ?,
|
|
64
64
|
member_fact_count = member_fact_count + ?,
|
|
65
65
|
updated_at = NOW()
|
|
66
|
-
WHERE id = ?`,[t,
|
|
66
|
+
WHERE id = ?`,[t,n,e])}var z=m(()=>{se();R();I()});function tn({sessionId:e,transcriptPath:t=null,cwd:n=null,turnCount:o=0,model:r=null,conclusion:s=null,summary:i=null}){return{session_id:e,transcript_path:t,cwd:n,turn_count:o,model:r,conclusion:s,summary:i}}function nn({sessionId:e,startedAt:t=new Date}={}){let o=(t instanceof Date?t:new Date(t)).toISOString().replace("T"," ").slice(0,16),r=e?e.slice(0,8):"unknown";return`claude-session ${o} (${r})`}var en,on=m(()=>{we();en="claude_session"});import{writeFile as ur,readFile as lr,unlink as Di}from"node:fs/promises";import{existsSync as dr,mkdirSync as pr}from"node:fs";import{dirname as rn}from"node:path";async function mr(){try{let e=await lr(X,"utf8");return JSON.parse(e)}catch{return null}}async function sn(e){dr(rn(X))||pr(rn(X),{recursive:!0}),await ur(X,JSON.stringify(e,null,2),"utf8")}async function an({sessionId:e,transcriptPath:t=null,cwd:n=null,model:o=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:en,externalId:e,name:nn({sessionId:e,startedAt:a}),namespace:s,attrs:tn({sessionId:e,transcriptPath:t,cwd:n,turnCount:1,model:o}),startedAt:a});return await sn({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 sn({...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,Pi,we=m(()=>{z();on();I();v();X=Ne,Pi=360*60*1e3});var ye={};y(ye,{attach:()=>Q,attachDocument:()=>hr,attachEntity:()=>gr,attachFact:()=>Er,detach:()=>wr,factIdsInPod:()=>Sr,listMembers:()=>yr,listPodsForMember:()=>Ir});async function Q(e,t,n,o="primary"){let{rowCount:r}=await d.raw(`INSERT INTO pod_membership (pod_id, member_type, member_id, role)
|
|
67
67
|
VALUES (?, ?, ?, ?)
|
|
68
|
-
ON CONFLICT (pod_id, member_type, member_id) DO NOTHING`,[e,t,o
|
|
68
|
+
ON CONFLICT (pod_id, member_type, member_id) DO NOTHING`,[e,t,n,o]);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,n){let o=await d("pod_membership").where({podId:e,memberType:t,memberId:n}).del();return o>0&&(t==="fact"?await G(e,{facts:-1}):t==="document"&&await G(e,{docs:-1})),{detached:o>0}}async function yr(e,{memberType:t,limit:n=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(n).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,n)=>Q(e,"fact",t,n),hr=(e,t,n)=>Q(e,"document",t,n),gr=(e,t,n)=>Q(e,"entity",t,n)});import{execFileSync as Or}from"node:child_process";import{basename as cn}from"node:path";async function un({cwd:e,namespace:t=null}){if(!e)return null;let n=Tr(e),o=t||c.defaults.namespace,s=(n!==e?!1:Se(e)===e)?n:Se(e),{pod:i}=await Z({podType:Ar,externalId:n,name:cn(n)||n,namespace:o,attrs:{root_path:n,git_root:s||null,display_name:cn(n)||n,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,ln=m(()=>{z();Ie();I();Ar="project"});var dn={};y(dn,{ensureActivePodsForHook:()=>br});async function br({sessionId:e,cwd:t=null,transcriptPath:n=null,model:o=null,namespace:r=null}){let s=null;if(e)try{s=await an({sessionId:e,transcriptPath:n,cwd:t,model:o,namespace:r})}catch{s=null}let i=null;if(t)try{i=await un({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 pn=m(()=>{we();ln()});$();import{readFileSync as Dr,writeFileSync as Rr,mkdirSync as Lr}from"node:fs";import{createHash as Nr}from"node:crypto";v();import{resolve as Rn}from"node:path";import{existsSync as Ce}from"node:fs";import{config as xe}from"dotenv";function Me(){let e=Rn(process.cwd(),".env");Ce(e)&&xe({path:e,quiet:!0}),Ce(K)&&K!==e&&xe({path:K,quiet:!0}),process.env.SIGIL_AGENT||(process.env.SIGIL_AGENT="claude-code")}v();Me();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"]),xr=new Set(["add","status","diff","log","show","branch","checkout","switch","fetch","pull","stash","blame","config"]),Mr=["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"],fn=300*1e3,_n=ve;function kr(){try{let e=JSON.parse(Dr(_n,"utf8")),t=Date.now();for(let n of Object.keys(e))t-e[n]>fn&&delete e[n];return e}catch{return{}}}function mn(e){try{Lr(w,{recursive:!0}),Rr(_n,JSON.stringify(e),"utf8")}catch{}}function Ur(e){let t=kr(),n=t[e],o=Date.now();return n&&o-n<fn?(t[e]=o,mn(t),!0):(t[e]=o,mn(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 n=t.file_path||"unknown file";return{content:`${e==="Write"?"Created":"Edited"} ${n}`,dedupKey:`${e}:${n}`}}if(e==="NotebookEdit"){let n=t.notebook_path||"unknown notebook";return{content:`Edited notebook ${n}`,dedupKey:`NotebookEdit:${n}`}}if(e==="Bash"){let n=(t.command||"").trim();if(!n)return null;let o=Br(n);if(Pr.has(o))return null;if(o==="git"||o==="gh"){let a=n.replace(/^(git|gh)\s+/,"").split(/\s+/)[0];if(xr.has(a))return null;if(Cr.has(a))return{content:`Ran: ${n.slice(0,200)}`,dedupKey:`Bash:${o} ${a}`}}if(["npm","pnpm","yarn"].includes(o)){let a=n.replace(/^\S+\s+/,"").split(/\s+/)[0];if(["test","run","start","lint"].includes(a))return null}let r=n.toLowerCase();return Mr.some(a=>r.includes(a))?{content:`Ran: ${n.slice(0,200)}`,dedupKey:`Bash:${o}:${Nr("md5").update(n).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 M()}function M(){let e={hookSpecificOutput:{hookEventName:"PostToolUse"}};process.stdout.write(JSON.stringify(e))}$r();
|