opencode-metis 0.2.4 → 0.2.5
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/mcp-server.cjs +14 -14
- package/dist/plugin.cjs +6 -6
- package/dist/worker.cjs +1 -1
- package/package.json +1 -1
package/dist/plugin.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
"use strict";var _=Object.defineProperty;var
|
|
2
|
-
`;try{let o=(0,R.dirname)(G);(0,S.existsSync)(o)||(0,S.mkdirSync)(o,{recursive:!0}),(0,S.appendFileSync)(G,r,"utf-8")}catch{}}var xe=5e3,
|
|
3
|
-
`)}async function $e(e,t,n){let r=`${e}/api/context/inject?project=${encodeURIComponent(n)}`,o={};t!==null&&(o.Authorization=`Bearer ${t}`);let a=await fetch(r,{headers:o,signal:AbortSignal.timeout(xe)});return a.ok?(await a.json()).context??null:null}function _e(e){let t=Re(e);if(!(0,T.existsSync)(t))return null;try{let n=(0,T.readFileSync)(t,"utf-8"),r=JSON.parse(n);return(0,T.unlinkSync)(t),r}catch{return null}}function z(e,t){e.messages=e.messages??[],e.messages.push({role:"user",content:t})}async function
|
|
4
|
-
`)}async function K(e,t,n,r,o){c(g,"Session compacting - fetching memories..."),c(g,`workerUrl=${t}, token=${n?"present":"null"}`),c(g,`input=${JSON.stringify(r).slice(0,300)}`);let a=
|
|
5
|
-
`)}async function Z(e,t,n,r,o){if(c(E,`Session idle: ${r.sessionId}`),!Ge(r)){c(E,"no meaningful context to save");return}let a={"Content-Type":"application/json"};n!==null&&(a.Authorization=`Bearer ${n}`);try{let s=`${t}/api/memory/save`;c(E,`POST ${s}`);let i=await fetch(s,{method:"POST",headers:a,body:JSON.stringify({type:"session-summary",title:`Session Summary: ${r.sessionId}`,text:ze(r),project:e.project.name}),signal:AbortSignal.timeout(Be)});c(E,`response.status=${i.status}`),i.ok||e.client.app.log("warn","Failed to save session summary",{status:i.status})}catch(s){c(E,`error: ${s instanceof Error?s.message:String(s)}`),e.client.app.log("warn","Session summary save failed",{error:s instanceof Error?s.message:String(s)})}}var
|
|
6
|
-
`)}function
|
|
1
|
+
"use strict";var _=Object.defineProperty;var pe=Object.getOwnPropertyDescriptor;var de=Object.getOwnPropertyNames;var me=Object.prototype.hasOwnProperty;var fe=(e,t)=>{for(var n in t)_(e,n,{get:t[n],enumerable:!0})},ye=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of de(t))!me.call(e,o)&&o!==n&&_(e,o,{get:()=>t[o],enumerable:!(r=pe(t,o))||r.enumerable});return e};var he=e=>ye(_({},"__esModule",{value:!0}),e);var ft={};fe(ft,{default:()=>le});module.exports=he(ft);var P=require("node:fs");var k=require("node:os"),p=require("node:path"),L=41777,U="127.0.0.1",Se=(0,p.join)((0,k.homedir)(),".config","opencode"),ht=(0,p.join)(Se,"opencode.json"),h=(0,p.join)((0,k.homedir)(),".config","opencode","memory"),Te="memory.db",Ee="settings.json",x=(0,p.join)(h,"worker.pid");var St=(0,p.join)(h,Te),O=(0,p.join)(h,Ee),Tt=(0,p.join)(h,"logs");var I={workerPort:L,workerBind:U,chromaDbUrl:"http://localhost:8000",chromaDbEnabled:!0,recencyWindowDays:90,retentionDays:365,tddEnabled:!0,fileLengthWarn:300,fileLengthCritical:500,testFilePatterns:["*.test.ts","*.spec.ts","*_test.go","test_*.py"],toolRedirectRules:[],aiProvider:null,aiModel:null,aiCompressionTimeoutMs:15e3,aiCompressionMaxRetries:3,aiSkipTools:[],secretDetectionEnabled:!0,secretPatterns:[],contextTokenBudget:2e3,notificationsEnabled:!1,debugEnabled:!1},d=null;function y(){if(d!==null)return d;if(!(0,P.existsSync)(O))return d={...I},d;try{let e=(0,P.readFileSync)(O,"utf-8"),t=JSON.parse(e);return d={...I,...t},d}catch{return d={...I},d}}function B(){let e=y();return`http://${e.workerBind}:${e.workerPort}`}var T=require("node:fs"),W=require("node:os"),w=require("node:path");var S=require("node:fs"),R=require("node:path");var G=(0,R.join)(h,"plugin-debug.log"),v=null;function be(){return v===null&&(v=y().debugEnabled),v}function c(e,t){if(!be())return;let r=`[${new Date().toISOString()}] [${e}] ${t}
|
|
2
|
+
`;try{let o=(0,R.dirname)(G);(0,S.existsSync)(o)||(0,S.mkdirSync)(o,{recursive:!0}),(0,S.appendFileSync)(G,r,"utf-8")}catch{}}var xe=5e3,m="compacted";function Pe(){return process.env.OPENCODE_SESSIONS_DIR??(0,w.join)((0,W.homedir)(),".config","opencode","sessions")}function Re(e){return(0,w.join)(Pe(),"sessions",e,"pre-compact-state.json")}function Ce(e){let t=["[Memory Context Restored After Compaction]"];return e.activePlan&&t.push(`Active plan: ${e.activePlan}`),e.currentTask&&t.push(`Current task: ${e.currentTask}`),e.status&&t.push(`Status: ${e.status}`),e.summary&&t.push(`Recent context: ${e.summary}`),t.join(`
|
|
3
|
+
`)}async function $e(e,t,n){let r=`${e}/api/context/inject?project=${encodeURIComponent(n)}`,o={};t!==null&&(o.Authorization=`Bearer ${t}`);let a=await fetch(r,{headers:o,signal:AbortSignal.timeout(xe)});return a.ok?(await a.json()).context??null:null}function _e(e){let t=Re(e);if(!(0,T.existsSync)(t))return null;try{let n=(0,T.readFileSync)(t,"utf-8"),r=JSON.parse(n);return(0,T.unlinkSync)(t),r}catch{return null}}function z(e,t){e.messages=e.messages??[],e.messages.push({role:"user",content:t})}async function H(e,t,n,r,o){c(m,`Session compacted: ${r.sessionId}`);try{let a=null;try{let i=`${t}/api/context/inject?project=${encodeURIComponent(e.project.name)}`;c(m,`GET ${i}`),a=await $e(t,n,e.project.name),c(m,a?`got context (${a.length} chars)`:"no context from worker")}catch(i){if(i instanceof TypeError)throw i;c(m,`worker fetch failed: ${i instanceof Error?i.message:String(i)}`)}if(a){z(o,a),c(m,"injected worker context");return}let s=_e(r.sessionId);if(s){let i=Ce(s);z(o,i),c(m,"injected fallback state from file")}else c(m,"no context available")}catch(a){c(m,`error: ${a instanceof Error?a.message:String(a)}`),e.client.app.log("warn","Compacted state restore failed",{error:a instanceof Error?a.message:String(a),sessionId:r.sessionId})}}var A=require("node:path");var ke=5e3,Oe=5,g="compacting";function Ie(e){if(e?.project?.name&&e.project.name!=="undefined")return e.project.name;if(e?.directory){let t=(0,A.basename)(e.directory);if(t&&t!=="."&&t!=="/")return t}if(e?.worktree){let t=(0,A.basename)(e.worktree);if(t&&t!=="."&&t!=="/")return t}}async function ve(e,t,n){try{let r={};t!==null&&(r.Authorization=`Bearer ${t}`);let o="decisions context observations",a=new URLSearchParams({query:o,limit:String(Oe)});n!==void 0&&n!=="undefined"&&n.length>0&&a.set("project",n);let s=`${e}/api/search?${a.toString()}`;c(g,`GET ${s}`);let i=await fetch(s,{method:"GET",headers:r,signal:AbortSignal.timeout(ke)});if(c(g,`response.ok=${i.ok}, status=${i.status}`),!i.ok)return[];let l=await i.json();return c(g,`found ${l.results.length} memories`),l.results}catch(r){return c(g,`fetch error: ${r instanceof Error?r.message:String(r)}`),[]}}function we(e){if(e.length===0)return"";let t=["## Relevant Context from Memory"];t.push(""),t.push("The following information was retrieved from long-term memory and may be relevant:"),t.push("");for(let n of e){let r=n.title||"Observation",o=n.relevanceScore!==null?` (relevance: ${Math.abs(n.relevanceScore*100).toFixed(0)}%)`:"";t.push(`### ${r}${o}`),t.push(n.summary),t.push("")}return t.join(`
|
|
4
|
+
`)}async function K(e,t,n,r,o){c(g,"Session compacting - fetching memories..."),c(g,`workerUrl=${t}, token=${n?"present":"null"}`),c(g,`input=${JSON.stringify(r).slice(0,300)}`);let a=Ie(e);c(g,`project=${a??"none"} (dir=${e?.directory??"unknown"})`);let s=await ve(t,n,a);if(s.length>0){let i=we(s);o.context.push(i),c(g,`injected ${s.length} memories into compaction context`)}else c(g,"no memories found to inject")}var J=require("node:fs"),u=require("node:path");var Ae=300,je=500,Fe=["*.test.ts","*.spec.ts","*_test.go","test_*.py"],j="file-edited";function Me(e,t){let n=t.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*");return new RegExp(`^${n}$`).test(e)}function De(e,t){let n=(0,u.basename)(e);return t.some(r=>Me(n,r))}function Ne(e,t){let n=(0,u.dirname)(e),r=(0,u.extname)(e),o=(0,u.basename)(e,r),a=[];for(let s of t)if(s.startsWith("*.")){let i=s.slice(1);a.push((0,u.join)(n,`${o}${i}`))}else if(s.endsWith("*")){let i=s.slice(0,-1);a.push((0,u.join)(n,`${i}${o}${r}`))}return a}function F(e,t){e.messages=e.messages??[],e.messages.push({role:"system",content:t})}function Le(e,t,n,r){if(De(t,n))return;let o=Ne(t,n),a=e.project.root;o.some(i=>{let l=i.startsWith("/")?i:(0,u.join)(a,i);return(0,J.existsSync)(l)})||F(r,`\u26A0\uFE0F TDD Warning: No test file found for ${t}. Consider writing tests first (Red-Green-Refactor).`)}function Ue(e,t,n,r,o){if(t>r){F(o,`\u{1F6A8} File Length Critical: ${e} has ${t} lines. This file should be refactored.`);return}t>n&&F(o,`\u26A0\uFE0F File Length Warning: ${e} has ${t} lines. Consider splitting this file.`)}async function q(e,t,n,r){try{c(j,`File edited: ${n.filePath}`);let o=y(),a=n.testFilePatterns??o.testFilePatterns??Fe,s=n.fileLengthWarn??o.fileLengthWarn??Ae,i=n.fileLengthCritical??o.fileLengthCritical??je;Le(e,n.filePath,a,r);let l=n.lineCount??0;Ue(n.filePath,l,s,i,r),c(j,`checks complete for ${n.filePath} (${l} lines)`)}catch(o){c(j,`error: ${o instanceof Error?o.message:String(o)}`),e.client.app.log("warn","File edited check failed",{error:o instanceof Error?o.message:String(o),filePath:n.filePath})}}var Be=15e3,E="session-idle";function Ge(e){let{context:t}=e;return t?!!(t.requested||t.investigated||t.learned||t.completed):!1}function ze(e){let t=e.context??{};return["Session Summary:",`Requested: ${t.requested??"Not specified"}`,`Investigated: ${t.investigated??"Not specified"}`,`Learned: ${t.learned??"Not specified"}`,`Completed: ${t.completed??"Not specified"}`].join(`
|
|
5
|
+
`)}async function Z(e,t,n,r,o){if(c(E,`Session idle: ${r.sessionId}`),!Ge(r)){c(E,"no meaningful context to save");return}let a={"Content-Type":"application/json"};n!==null&&(a.Authorization=`Bearer ${n}`);try{let s=`${t}/api/memory/save`;c(E,`POST ${s}`);let i=await fetch(s,{method:"POST",headers:a,body:JSON.stringify({type:"session-summary",title:`Session Summary: ${r.sessionId}`,text:ze(r),project:e.project.name}),signal:AbortSignal.timeout(Be)});c(E,`response.status=${i.status}`),i.ok||e.client.app.log("warn","Failed to save session summary",{status:i.status})}catch(s){c(E,`error: ${s instanceof Error?s.message:String(s)}`),e.client.app.log("warn","Session summary save failed",{error:s instanceof Error?s.message:String(s)})}}var We=3e3,f="session-start";function He(e){let t={};return e!==null&&(t.Authorization=`Bearer ${e}`),t}async function Y(e,t){return fetch(e,{headers:He(t),signal:AbortSignal.timeout(We)})}async function V(e,t,n,r,o,a){c(f,"Session started");let s=`${t}/api/context/inject?project=${encodeURIComponent(e.project.name)}`;c(f,`GET ${s}`);try{let i=await Y(s,n);if(c(f,`response.status=${i.status}`),i.status===401&&a!==void 0){c(f,"Token expired, refreshing...");let $=a();i=await Y(s,$),c(f,`retry response.status=${i.status}`)}if(!i.ok){e.client.app.log("warn","Failed to load memory context",{status:i.status});return}let l=await i.json();l.context?(o.messages=o.messages??[],o.messages.push({role:"system",content:l.context}),c(f,`injected context (${l.context.length} chars)`)):c(f,"no context returned from worker")}catch(i){c(f,`error: ${i instanceof Error?i.message:String(i)}`),e.client.app.log("warn","Memory context injection failed",{error:i instanceof Error?i.message:String(i)})}}var Ke=15e3,Je=200,X="tool-after";async function ee(e,t,n,r,o,a,s){c(X,`Tool completed: ${o.tool}`),qe(e,t,n,r,o,a,s).catch(i=>{c(X,`error: ${i instanceof Error?i.message:String(i)}`),e.client.app.log("warn","Observation capture failed",{error:i instanceof Error?i.message:String(i)})})}async function qe(e,t,n,r,o,a,s){let i=`Tool ${o.tool}: ${Ye(o,a)}`,l=`${o.tool} execution`,$=Ze(o.input),ue=a.output??a.error??"",D={text:r.sanitize(i),title:r.sanitize(l),project:e.project.name,toolName:o.tool,toolInput:r.sanitize($),toolOutput:r.sanitize(ue)},N=`${t}/api/memory/save`,b=await Q(N,D,n);if(b.status===401&&s!==void 0){let ge=s();b=await Q(N,D,ge)}b.ok||e.client.app.log("warn","Observation save failed",{status:b.status})}async function Q(e,t,n){let r={"Content-Type":"application/json"};return n!==null&&(r.Authorization=`Bearer ${n}`),fetch(e,{method:"POST",headers:r,body:JSON.stringify(t),signal:AbortSignal.timeout(Ke)})}function Ze(e){try{return JSON.stringify(e)}catch{return String(e)}}function Ye(e,t){let n=t.output??t.error??"",r=Ve(e.input),o=n.slice(0,Je).trim();return r&&o?`${r} -> ${o}`:r||o||"(no details)"}function Ve(e){let t=Object.entries(e);return t.length===0?"":t.map(([n,r])=>`${n}=${String(r).slice(0,80)}`).join(", ")}var C="tool-before";function Xe(){let e=process.env.MEMORY_TOOL_REDIRECT_RULES;if(e!==void 0)try{return JSON.parse(e)}catch{return[]}return y().toolRedirectRules}function Qe(e){if(typeof e!="object"||e===null)return!1;let t=e;return typeof t.tool=="string"&&(t.action==="deny"||t.action==="redirect")}function et(e){return e.message??`Tool '${e.tool}' is blocked by project configuration.`}function tt(e){let t=e.message??`Tool '${e.tool}' has been redirected.`;return e.alternative?`${t} Suggested alternative: ${e.alternative}.`:t}function nt(e,t){t.blocked=!0,t.messages=[{role:"user",content:et(e)}]}function rt(e,t){t.messages=[{role:"user",content:tt(e)}]}async function te(e,t,n,r){c(C,`Tool executing: ${n.tool}`);let o=Xe();for(let a of o)try{if(!Qe(a))throw new Error("Invalid rule: tool must be a string and action must be 'deny' or 'redirect'");if(a.tool!==n.tool)continue;a.action==="deny"?(nt(a,r),c(C,`blocked tool ${n.tool} (deny rule)`)):(rt(a,r),c(C,`redirected tool ${n.tool}`));return}catch(s){c(C,`rule error: ${s instanceof Error?s.message:String(s)}`),e.client.app.log("warn","Tool redirect rule evaluation failed",{error:s instanceof Error?s.message:String(s),rule:JSON.stringify(a)})}}var ne=require("node:fs");function ot(e){return typeof e=="object"&&e!==null&&"token"in e&&typeof e.token=="string"&&"pid"in e&&typeof e.pid=="number"}function it(e){try{return process.kill(e,0),!0}catch{return!1}}function M(e){try{let t=(0,ne.readFileSync)(e,"utf-8");if(t.trim().length===0)return null;let n=JSON.parse(t);return!ot(n)||!it(n.pid)?null:n.token}catch{return null}}var re=[{name:"aws_access_key",pattern:/AKIA[0-9A-Z]{16}/g},{name:"github_pat",pattern:/ghp_[a-zA-Z0-9]{36}/g},{name:"github_oauth",pattern:/gho_[a-zA-Z0-9]{36}/g},{name:"anthropic_key",pattern:/sk-ant-[a-zA-Z0-9\-_]{20,}/g},{name:"openai_key",pattern:/sk-[a-zA-Z0-9]{20,}/g},{name:"jwt_token",pattern:/eyJ[a-zA-Z0-9_-]+\.eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+/g},{name:"pem_private_key",pattern:/-----BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY-----/g},{name:"generic_api_key",pattern:/(?:api[_-]?key|token|secret|password)\s*[:=]\s*['"]?([a-zA-Z0-9\-_]{20,})['"]?/gi}];function st(e,t=re){if(!e)return e;let n=e;for(let{pattern:r}of t)r.lastIndex=0,n=n.replace(r,"[REDACTED]");return n}function oe(e=[]){let t=[...re,...e];return n=>st(n,t)}var at=/<private>[\s\S]*?<\/private>/gi;function ie(e){return e.replace(at,"")}function se(e={}){let{additionalSecretPatterns:t=[],secretDetectionEnabled:n=!0}=e,r=oe(t);return{sanitize(o){let a=ie(o);return n?r(a):a}}}function ae(e,t,n){return[ct(e,t,n),lt(e,t,n)]}function ct(e,t,n){return{name:"memory_search",description:"Search memory observations by topic or keyword",parameters:{query:{type:"string",description:"The search query or topic to look up in memory",required:!0},limit:{type:"number",description:"Maximum number of results to return (default 20)"},project:{type:"string",description:"Filter results to a specific project name"}},execute:r=>ut(e,t,n,r)}}function lt(e,t,n){return{name:"memory_save",description:"Save an observation to memory for future reference",parameters:{text:{type:"string",description:"The observation text to save to memory",required:!0},title:{type:"string",description:"Optional short title summarising the observation"}},execute:r=>gt(e,t,n,r)}}function ce(e){return e===null?{}:{Authorization:`Bearer ${e}`}}async function ut(e,t,n,r){try{let o=pt(t,r),a=await fetch(o,{headers:ce(n()),signal:AbortSignal.timeout(1e4)});if(!a.ok)return{result:`Error: Worker returned status ${a.status}`};let s=await a.json();return{result:dt(s.results??[])}}catch(o){return e.client.app.log("warn","memory_search failed",{error:o instanceof Error?o.message:String(o)}),{result:`Error: ${o instanceof Error?o.message:String(o)}`}}}async function gt(e,t,n,r){try{let o={text:r.text};r.title!==void 0&&(o.title=r.title);let a={"Content-Type":"application/json",...ce(n())},s=await fetch(`${t}/api/memory/save`,{method:"POST",headers:a,body:JSON.stringify(o),signal:AbortSignal.timeout(1e4)});if(!s.ok)return{result:`Error: Worker returned status ${s.status}`};let i=await s.json();return{result:mt(i)}}catch(o){return e.client.app.log("warn","memory_save failed",{error:o instanceof Error?o.message:String(o)}),{result:`Error: ${o instanceof Error?o.message:String(o)}`}}}function pt(e,t){let n=new URLSearchParams;return n.set("query",String(t.query??"")),t.limit!==void 0&&n.set("limit",String(t.limit)),t.project!==void 0&&n.set("project",String(t.project)),`${e}/api/search?${n.toString()}`}function dt(e){return e.length===0?"No results found for the given query.":e.map(t=>`[${t.id}] ${t.title} (${t.type}, ${t.project}) \u2014 ${t.summary}`).join(`
|
|
6
|
+
`)}function mt(e){let t=e.id??"unknown",n=e.title??"(untitled)";return`Saved observation #${t}: "${n}"`}async function le(e){let t=B(),n=se(),r=M(x);r===null&&e.client.app.log("warn","Auth token not found in PID file \u2014 requests will be unauthenticated",{pidFilePath:x});function o(){return r=M(x),r}return ae(e,t,()=>r),{"session.created":(s,i)=>V(e,t,r,s,i,o),"tool.execute.after":(s,i)=>ee(e,t,r,n,s,i,o),"tool.execute.before":(s,i)=>te(e,t,s,i),"session.idle":(s,i)=>Z(e,t,r,s,i),"experimental.session.compacting":(s,i)=>K(e,t,o(),s,i),"session.compacted":(s,i)=>H(e,t,r,s,i),"file.edited":(s,i)=>q(e,t,s,i)}}
|
package/dist/worker.cjs
CHANGED
|
@@ -319,4 +319,4 @@ END`;function Dm(t,e){for(let r of e.split(";")){let n=r.trim();n.length>0&&t.ru
|
|
|
319
319
|
`)}function OS(t,e){t.get("/api/context/inject",async r=>{if(!await Lq(e))return ym({context:""});let s=PS(r),o=IS(e,s,24),i=NS(e,s),a=Zq(o,i);return ym({context:a})}),t.get("/api/context/recent",r=>{let n=PS(r),o=new URL(r.url).searchParams.get("hours"),i=o!==null?parseInt(o,10):24,a=IS(e,n,i),c=NS(e,n);return ym({observations:a,summaries:c})})}var Uq=process.env.npm_package_version??"0.1.0",Fq=Date.now();function Vq(t){return t==="core-ready"||t==="ready"}function Hq(t){return t==="ready"}function Cs(t,e=200){return new Response(JSON.stringify(t),{status:e,headers:{"Content-Type":"application/json"}})}function zS(t,e){t.get("/api/health",()=>Cs({build:Uq,initState:e.initState,pid:process.pid,uptime:Math.floor((Date.now()-Fq)/1e3)})),t.get("/api/core-ready",()=>Vq(e.initState)?Cs({ready:!0}):Cs({ready:!1,initState:e.initState},503)),t.get("/api/readiness",()=>Hq(e.initState)?Cs({ready:!0}):Cs({ready:!1,initState:e.initState},503)),t.get("/api/process-stats",()=>{let r=process.memoryUsage();return Cs({rss:r.rss,heapUsed:r.heapUsed,uptime:process.uptime()})})}var CS=ae.object({text:ae.string().min(1),title:ae.string().optional(),project:ae.string().optional(),toolName:ae.string().optional(),toolInput:ae.string().optional(),toolOutput:ae.string().optional(),skipAiCompression:ae.boolean().optional()}),AS=ae.object({query:ae.string().optional(),limit:ae.number().int().min(1).max(100).default(20),type:ae.string().optional(),project:ae.string().optional(),dateStart:ae.string().optional(),dateEnd:ae.string().optional()}),jS=ae.object({query:ae.string().min(1)}),MS=ae.object({anchor:ae.string().min(1),depth_before:ae.number().int().min(0).default(5),depth_after:ae.number().int().min(0).default(5)}),vm=ae.object({ids:ae.array(ae.number().int()).min(1)}),aB=ae.object({contentSessionId:ae.string().min(1),project:ae.string().min(1),memorySessionId:ae.string().optional()});var Bq="default";function DS(t,e=200){return new Response(JSON.stringify(t),{status:e,headers:{"Content-Type":"application/json"}})}function Wc(t,e){return DS({error:t},e)}function qS(t,e){t.post("/api/memory/save",async r=>{let{observationWriter:n,sessionManager:s}=e;if(n===void 0||s===void 0)return Wc("Service unavailable",503);let o;try{o=await r.json()}catch{return Wc("Invalid JSON body",400)}let i=CS.safeParse(o);if(!i.success)return Wc(i.error.issues[0]?.message??"Validation error",400);let{text:a,title:c,project:u=Bq,toolName:l,toolInput:d,toolOutput:f,skipAiCompression:m}=i.data;try{let p=s.createSession({contentSessionId:crypto.randomUUID(),project:u}),h={memorySessionId:p.memorySessionId,sessionDbId:p.id,contentSessionId:p.contentSessionId,project:u,text:a,...c!==void 0?{title:c}:{},...l!==void 0?{rawToolName:l}:{},...d!==void 0?{rawToolInput:d}:{},...f!==void 0?{rawToolOutput:f}:{},...m!==void 0?{skipAiCompression:m}:{}},g=await n.write(h);return DS({success:!0,id:g.id,title:g.title??c??"",project:g.project,message:"Observation saved"})}catch(p){let h=p instanceof Error?p.message:"Failed to save observation";return Wc(h,500)}})}function Jc(t,e=200){return new Response(JSON.stringify(t),{status:e,headers:{"Content-Type":"application/json"}})}function qt(t,e){return Jc({error:t},e)}function LS(t,e){t.post("/api/observations/batch",async r=>{let{searchManager:n}=e;if(n===void 0)return qt("Service unavailable",503);let s;try{s=await r.json()}catch{return qt("Invalid JSON body",400)}let o=vm.safeParse(s);if(!o.success)return qt(o.error.issues[0]?.message??"Validation error",400);try{let i=n.batchFetch(o.data.ids);return Jc({observations:i})}catch(i){let a=i instanceof Error?i.message:"Batch fetch failed";return qt(a,500)}}),t.delete("/api/observation/:id",(r,n)=>{let{observationWriter:s}=e;if(s===void 0)return qt("Service unavailable",503);let o=parseInt(n.id??"",10);if(Number.isNaN(o))return qt("Invalid observation id",400);try{return s.delete(o),Jc({deleted:!0})}catch(i){let a=i instanceof Error?i.message:"Delete failed";return qt(a,500)}}),t.post("/api/observations/delete",async r=>{let{observationWriter:n}=e;if(n===void 0)return qt("Service unavailable",503);let s;try{s=await r.json()}catch{return qt("Invalid JSON body",400)}let o=vm.safeParse(s);if(!o.success)return qt(o.error.issues[0]?.message??"Validation error",400);try{let i=n.bulkDelete(o.data.ids);return Jc({deleted:i})}catch(i){let a=i instanceof Error?i.message:"Bulk delete failed";return qt(a,500)}})}function Xc(t,e=200){return new Response(JSON.stringify(t),{status:e,headers:{"Content-Type":"application/json"}})}function vi(t,e){return Xc({error:t},e)}function ZS(t,e){t.post("/api/retention/purge-age",async r=>{if(e.retentionManager===void 0)return vi("Retention manager not available",503);let n={};try{n=await r.json()}catch{}let s=typeof n.retentionDays=="number"?n.retentionDays:365,o=e.retentionManager.purgeByAge(s);return Xc({deleted:o.deleted})}),t.post("/api/retention/purge-project",async r=>{if(e.retentionManager===void 0)return vi("Retention manager not available",503);let n;try{n=await r.json()}catch{return vi("Invalid JSON body",400)}let s=n.project;if(typeof s!="string"||s.length===0)return vi("project is required",400);let o=e.retentionManager.purgeByProject(s);return Xc({deleted:o.deleted})}),t.post("/api/retention/vacuum",()=>e.retentionManager===void 0?vi("Retention manager not available",503):(e.retentionManager.vacuum(),Xc({success:!0})))}function bm(t,e=200){return new Response(JSON.stringify(t),{status:e,headers:{"Content-Type":"application/json"}})}function As(t,e){return bm({error:t},e)}function Kq(t){let e={},r=t.searchParams.get("query");r!==null&&(e.query=r);let n=t.searchParams.get("limit");if(n!==null){let c=Number(n);e.limit=Number.isNaN(c)?n:c}let s=t.searchParams.get("type");s!==null&&(e.type=s);let o=t.searchParams.get("project");o!==null&&(e.project=o);let i=t.searchParams.get("dateStart");i!==null&&(e.dateStart=i);let a=t.searchParams.get("dateEnd");return a!==null&&(e.dateEnd=a),e}function US(t,e){t.get("/api/search",async r=>{let{searchManager:n}=e;if(n===void 0)return As("Service unavailable",503);let s=new URL(r.url),o=Kq(s),i=AS.safeParse(o);if(!i.success)return As(i.error.issues[0]?.message??"Validation error",400);let{query:a,limit:c,type:u,project:l,dateStart:d,dateEnd:f}=i.data;try{let m={limit:c,...a!==void 0?{query:a}:{},...u!==void 0?{type:u}:{},...l!==void 0?{project:l}:{},...d!==void 0?{dateStart:d}:{},...f!==void 0?{dateEnd:f}:{}},p=await n.search(m);return bm({results:p.results,total:p.total,mode:p.mode})}catch(m){let p=m instanceof Error?m.message:"Search failed";return As(p,500)}}),t.get("/api/search/semantic",async r=>{let{searchManager:n}=e;if(n===void 0)return As("Service unavailable",503);let o=new URL(r.url).searchParams.get("query")??"",i=jS.safeParse({query:o});if(!i.success)return As(i.error.issues[0]?.message??"Validation error",400);try{let a=await n.searchSemantic(i.data.query);return bm({results:a})}catch(a){let c=a instanceof Error?a.message:"Semantic search failed";return As(c,500)}})}function bi(t,e=200){return new Response(JSON.stringify(t),{status:e,headers:{"Content-Type":"application/json"}})}function Ur(t,e){return bi({error:t},e)}function FS(t,e){t.get("/api/sessions/active",()=>{if(e.sessionManager===void 0)return Ur("Session manager not available",503);let r=e.sessionManager.getActiveSessions();return bi({sessions:r})}),t.get("/api/sessions/count",r=>{if(e.sessionManager===void 0)return Ur("Session manager not available",503);let s=new URL(r.url).searchParams.get("project")??void 0,o=e.sessionManager.getSessionCount(s);return bi({count:o})}),t.post("/api/sessions/create",async r=>{if(e.sessionManager===void 0)return Ur("Session manager not available",503);let n;try{n=await r.json()}catch{return Ur("Invalid JSON body",400)}let s=n.contentSessionId,o=n.project;if(typeof s!="string"||s.length===0)return Ur("contentSessionId is required",400);if(typeof o!="string"||o.length===0)return Ur("project is required",400);let i={contentSessionId:s,project:o};typeof n.memorySessionId=="string"&&(i.memorySessionId=n.memorySessionId),typeof n.workerPort=="number"&&(i.workerPort=n.workerPort);let a=e.sessionManager.createSession(i);return bi({session:a})}),t.post("/api/sessions/:id/complete",(r,n)=>{if(e.sessionManager===void 0)return Ur("Session manager not available",503);let s=n.id;return s===void 0||s.length===0?Ur("Session ID is required",400):(e.sessionManager.completeSession(s),bi({success:!0}))})}function VS(t,e=200){return new Response(JSON.stringify(t),{status:e,headers:{"Content-Type":"application/json"}})}function $m(t,e){return VS({error:t},e)}function Gq(t){let e={},r=t.searchParams.get("anchor");r!==null&&(e.anchor=r);let n=t.searchParams.get("depth_before");if(n!==null){let o=Number(n);e.depth_before=Number.isNaN(o)?n:o}let s=t.searchParams.get("depth_after");if(s!==null){let o=Number(s);e.depth_after=Number.isNaN(o)?s:o}return e}function HS(t,e){t.get("/api/timeline",r=>{let{searchManager:n}=e;if(n===void 0)return $m("Service unavailable",503);let s=new URL(r.url),o=Gq(s),i=MS.safeParse(o);if(!i.success)return $m(i.error.issues[0]?.message??"Validation error",400);let{anchor:a,depth_before:c,depth_after:u}=i.data;try{let l=n.timeline({anchor:a,depthBefore:c,depthAfter:u});return VS({entries:l.entries})}catch(l){let d=l instanceof Error?l.message:"Timeline query failed";return $m(d,500)}})}function Wq(){return`${Date.now()}-${Math.random().toString(36).slice(2,9)}`}function BS(t,e){return`event: ${t}
|
|
320
320
|
data: ${JSON.stringify(e)}
|
|
321
321
|
|
|
322
|
-
`}var Yc=class{clients=new Set;connect(){let e,r=new ReadableStream({start:n=>{e=n,this.clients.add(e),this.sendToController(e,"connected",{clientId:Wq(),timestamp:new Date().toISOString()})},cancel:()=>{this.clients.delete(e)}});return new Response(r,{headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}})}broadcast(e,r){let n=BS(e,r),s=new TextEncoder().encode(n);for(let o of this.clients)try{o.enqueue(s)}catch{this.clients.delete(o)}}getClientCount(){return this.clients.size}disconnectAll(){for(let e of this.clients)try{e.close()}catch{}this.clients.clear()}sendToController(e,r,n){let s=BS(r,n);e.enqueue(new TextEncoder().encode(s))}};function KS(t,e){t.get("/stream",()=>e.connect())}var Qc=require("node:fs");function GS(){try{(0,Qc.unlinkSync)(Ui)}catch{}}var lL={},Sm=(0,wi.join)((0,wm.homedir)(),".config","opencode","memory"),Jq="memory.db",Xq=(0,wi.join)(Sm,"backups"),Yq=1440*60*1e3,JS={"Access-Control-Allow-Methods":"GET, POST, DELETE, OPTIONS","Access-Control-Allow-Headers":"Content-Type, Authorization"};function WS(t){let e=new Headers(t.headers);for(let[r,n]of Object.entries(JS))e.set(r,n);return new Response(t.body,{status:t.status,statusText:t.statusText,headers:e})}function Qq(t){return t==="/api/health"}function eL(t,e,r,n){return Bun.serve({port:t,hostname:e,async fetch(s){let o=new URL(s.url),i=s.method.toUpperCase();if(i==="OPTIONS")return new Response(null,{status:204,headers:JS});if(!Qq(o.pathname)&&!n(s))return WS(new Response(JSON.stringify({error:"Unauthorized"}),{status:401,headers:{"Content-Type":"application/json"}}));let a;try{a=await r.handle(s)}catch(c){let u=c instanceof Error?c.message:"Internal server error";console.error(`[worker] Error handling ${i} ${o.pathname}:`,c),a=new Response(JSON.stringify({error:u}),{status:500,headers:{"Content-Type":"application/json"}})}return WS(a)}})}function tL(t,e,r,n){zS(t,e),qS(t,e),US(t,e),LS(t,e),HS(t,e),OS(t,e),FS(t,e),ES(t,e,n),ZS(t,e),xS(t,e),KS(t,r)}async function rL(){let t=new Vc;try{return await t.start(),t}catch{return console.warn("[worker] chroma-mcp start failed, falling back to NoopVectorSync"),null}}function nL(t,e){return setInterval(()=>{t.retentionManager!==void 0&&t.retentionManager.purgeByAge(e)},Yq)}async function sL(t,e,r,n){(0,$i.mkdirSync)(Sm,{recursive:!0});let s=Mm(e.dbPath);Um(s),t.db=s;let o=new Ai(s);t.pendingQueue=o;let i=new Zi(s);t.sessionManager=i;let a;if(e.chromaDbEnabled){let $=await rL();$!==null&&(n.chromaMcpManager=$),a=bS($)}else a=new gr;t.vectorSync=a;let c=new Ci(s,o,a);t.observationWriter=c;let u=new Di(s,a);t.searchManager=u,t.initState="core-ready";let l=new ji(s,a);t.retentionManager=l;let d=new zi(e.dbPath,Xq);t.backupManager=d;let f=o.recover();r.pendingQueueRecoveryRan=!0,f>0;let m=i.recoverOrphaned(e.workerPort);r.orphanedSessionRecoveryRan=!0,m>0;let p=fu(),h={...p.aiProvider!==null?{provider:p.aiProvider}:{},...p.aiModel!==null?{model:p.aiModel}:{},timeoutMs:p.aiCompressionTimeoutMs},g=new Pi(h),_=new Oi(s,o,g,c,p);_.start(),n.aiQueue=_,t.aiCompressionQueue=_,t.initState="ready"}function oL(t,e,r,n,s){return()=>{let o=s();o.aiQueue!==void 0&&o.aiQueue.stop(),o.chromaMcpManager!==void 0&&o.chromaMcpManager.stop();let i=n();if(i!==void 0&&clearInterval(i),r.disconnectAll(),t.stop(!0),e.db!==void 0)try{e.db.close()}catch{}}}function iL(t){(0,$i.mkdirSync)((0,wi.join)((0,wm.homedir)(),".config","opencode","memory"),{recursive:!0}),(0,$i.writeFileSync)(Ui,JSON.stringify({token:t,pid:process.pid}),"utf-8")}async function Em(t={}){let e=fu(),r=t.port??e.workerPort,n=t.bind??e.workerBind,s=t.dbPath??(0,wi.join)(Sm,Jq),o=t.chromaDbEnabled??e.chromaDbEnabled,i=e.retentionDays,a=$S(),c=gm(a),u=wS(c),l={initState:"starting"},d=new Yc;l.sse=d;let f=new Gc,m,p=eL(r,n,f,u),h=p.port??r;iL(a);let g={},_=oL(p,l,d,()=>m,()=>g);tL(f,l,d,_);let $={pendingQueueRecoveryRan:!1,orphanedSessionRecoveryRan:!1},w=sL(l,{dbPath:s,chromaDbEnabled:o,workerPort:h,retentionDays:i},$,g).then(()=>{m=nL(l,i)}).catch(E=>{l.initState="error",console.error("[worker] Phase 2 initialization failed:",E)}),x=()=>{_(),GS(),process.exit(0)};return process.on("SIGTERM",x),process.on("SIGINT",x),{server:p,stop:_,phaseTwoPromise:w,tracking:$,token:a}}async function aL(t={}){let e={port:0,dbPath:":memory:",chromaDbEnabled:!1,...t},{server:r,stop:n,phaseTwoPromise:s,tracking:o,token:i}=await Em(e),a=r.port??0,c=`http://127.0.0.1:${a}`;return{port:a,baseUrl:c,authToken:i,shutdown:async()=>{await s.catch(()=>{}),n()},waitForReady:async()=>{await s},get pendingQueueRecoveryRan(){return o.pendingQueueRecoveryRan},get orphanedSessionRecoveryRan(){return o.orphanedSessionRecoveryRan}}}var cL=typeof require<"u"?require.main===module:lL.main;cL&&Em().then(t=>{}).catch(t=>{console.error("[worker] Failed to start:",t),process.exit(1)});0&&(module.exports={createTestWorker,startWorker});
|
|
322
|
+
`}var Yc=class{clients=new Set;connect(){let e,r=new ReadableStream({start:n=>{e=n,this.clients.add(e),this.sendToController(e,"connected",{clientId:Wq(),timestamp:new Date().toISOString()})},cancel:()=>{this.clients.delete(e)}});return new Response(r,{headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}})}broadcast(e,r){let n=BS(e,r),s=new TextEncoder().encode(n);for(let o of this.clients)try{o.enqueue(s)}catch{this.clients.delete(o)}}getClientCount(){return this.clients.size}disconnectAll(){for(let e of this.clients)try{e.close()}catch{}this.clients.clear()}sendToController(e,r,n){let s=BS(r,n);e.enqueue(new TextEncoder().encode(s))}};function KS(t,e){t.get("/stream",()=>e.connect())}var Qc=require("node:fs");function GS(){try{(0,Qc.unlinkSync)(Ui)}catch{}}var lL={},Sm=(0,wi.join)((0,wm.homedir)(),".config","opencode","memory"),Jq="memory.db",Xq=(0,wi.join)(Sm,"backups"),Yq=1440*60*1e3,JS={"Access-Control-Allow-Methods":"GET, POST, DELETE, OPTIONS","Access-Control-Allow-Headers":"Content-Type, Authorization"};function WS(t){let e=new Headers(t.headers);for(let[r,n]of Object.entries(JS))e.set(r,n);return new Response(t.body,{status:t.status,statusText:t.statusText,headers:e})}function Qq(t){return t==="/api/health"}function eL(t,e,r,n){return Bun.serve({port:t,hostname:e,async fetch(s){let o=new URL(s.url),i=s.method.toUpperCase();if(i==="OPTIONS")return new Response(null,{status:204,headers:JS});if(!Qq(o.pathname)&&!n(s))return WS(new Response(JSON.stringify({error:"Unauthorized"}),{status:401,headers:{"Content-Type":"application/json"}}));let a;try{a=await r.handle(s)}catch(c){let u=c instanceof Error?c.message:"Internal server error";console.error(`[worker] Error handling ${i} ${o.pathname}:`,c),a=new Response(JSON.stringify({error:u}),{status:500,headers:{"Content-Type":"application/json"}})}return WS(a)}})}function tL(t,e,r,n){zS(t,e),qS(t,e),US(t,e),LS(t,e),HS(t,e),OS(t,e),FS(t,e),ES(t,e,n),ZS(t,e),xS(t,e),KS(t,r)}async function rL(){let t=new Vc;try{return await t.start(),t}catch{return console.warn("[worker] chroma-mcp start failed, falling back to NoopVectorSync"),null}}function nL(t,e){return setInterval(()=>{t.retentionManager!==void 0&&t.retentionManager.purgeByAge(e)},Yq)}async function sL(t,e,r,n){(0,$i.mkdirSync)(Sm,{recursive:!0});let s=Mm(e.dbPath);Um(s),t.db=s;let o=new Ai(s);t.pendingQueue=o;let i=new Zi(s);t.sessionManager=i;let a;if(e.chromaDbEnabled){let $=await rL();$!==null&&(n.chromaMcpManager=$),a=bS($)}else a=new gr;t.vectorSync=a;let c=new Ci(s,o,a);t.observationWriter=c;let u=new Di(s,a);t.searchManager=u,t.initState="core-ready";let l=new ji(s,a);t.retentionManager=l;let d=new zi(e.dbPath,Xq);t.backupManager=d;let f=o.recover();r.pendingQueueRecoveryRan=!0,f>0;let m=i.recoverOrphaned(e.workerPort);r.orphanedSessionRecoveryRan=!0,m>0;let p=fu(),h={...p.aiProvider!==null?{provider:p.aiProvider}:{},...p.aiModel!==null?{model:p.aiModel}:{},timeoutMs:p.aiCompressionTimeoutMs},g=new Pi(h),_=new Oi(s,o,g,c,p);_.start(),n.aiQueue=_,t.aiCompressionQueue=_,t.initState="ready"}function oL(t,e,r,n,s){return()=>{let o=s();o.aiQueue!==void 0&&o.aiQueue.stop(),o.chromaMcpManager!==void 0&&o.chromaMcpManager.stop();let i=n();if(i!==void 0&&clearInterval(i),r.disconnectAll(),t.stop(!0),e.db!==void 0)try{e.db.close()}catch{}}}function iL(t,e){(0,$i.mkdirSync)((0,wi.join)((0,wm.homedir)(),".config","opencode","memory"),{recursive:!0}),(0,$i.writeFileSync)(Ui,JSON.stringify({token:t,pid:process.pid,port:e}),"utf-8")}async function Em(t={}){let e=fu(),r=t.port??e.workerPort,n=t.bind??e.workerBind,s=t.dbPath??(0,wi.join)(Sm,Jq),o=t.chromaDbEnabled??e.chromaDbEnabled,i=e.retentionDays,a=$S(),c=gm(a),u=wS(c),l={initState:"starting"},d=new Yc;l.sse=d;let f=new Gc,m,p=eL(r,n,f,u),h=p.port??r;iL(a,h);let g={},_=oL(p,l,d,()=>m,()=>g);tL(f,l,d,_);let $={pendingQueueRecoveryRan:!1,orphanedSessionRecoveryRan:!1},w=sL(l,{dbPath:s,chromaDbEnabled:o,workerPort:h,retentionDays:i},$,g).then(()=>{m=nL(l,i)}).catch(E=>{l.initState="error",console.error("[worker] Phase 2 initialization failed:",E)}),x=()=>{_(),GS(),process.exit(0)};return process.on("SIGTERM",x),process.on("SIGINT",x),{server:p,stop:_,phaseTwoPromise:w,tracking:$,token:a}}async function aL(t={}){let e={port:0,dbPath:":memory:",chromaDbEnabled:!1,...t},{server:r,stop:n,phaseTwoPromise:s,tracking:o,token:i}=await Em(e),a=r.port??0,c=`http://127.0.0.1:${a}`;return{port:a,baseUrl:c,authToken:i,shutdown:async()=>{await s.catch(()=>{}),n()},waitForReady:async()=>{await s},get pendingQueueRecoveryRan(){return o.pendingQueueRecoveryRan},get orphanedSessionRecoveryRan(){return o.orphanedSessionRecoveryRan}}}var cL=typeof require<"u"?require.main===module:lL.main;cL&&Em().then(t=>{}).catch(t=>{console.error("[worker] Failed to start:",t),process.exit(1)});0&&(module.exports={createTestWorker,startWorker});
|