opencode-metis 0.2.6 → 0.2.7

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/plugin.cjs CHANGED
@@ -1,6 +1,6 @@
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)}}
1
+ "use strict";var k=Object.defineProperty;var me=Object.getOwnPropertyDescriptor;var fe=Object.getOwnPropertyNames;var ye=Object.prototype.hasOwnProperty;var he=(e,t)=>{for(var r in t)k(e,r,{get:t[r],enumerable:!0})},Se=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of fe(t))!ye.call(e,n)&&n!==r&&k(e,n,{get:()=>t[n],enumerable:!(o=me(t,n))||o.enumerable});return e};var Te=e=>Se(k({},"__esModule",{value:!0}),e);var yt={};he(yt,{default:()=>ge});module.exports=Te(yt);var R=require("node:fs");var v=require("node:os"),d=require("node:path"),U=41777,W="127.0.0.1",Ee=(0,d.join)((0,v.homedir)(),".config","opencode"),St=(0,d.join)(Ee,"opencode.json"),h=(0,d.join)((0,v.homedir)(),".config","opencode","memory"),be="memory.db",xe="settings.json",P=(0,d.join)(h,"worker.pid");var Tt=(0,d.join)(h,be),I=(0,d.join)(h,xe),Et=(0,d.join)(h,"logs");var O={workerPort:U,workerBind:W,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},p=null;function y(){if(p!==null)return p;if(!(0,R.existsSync)(I))return p={...O},p;try{let e=(0,R.readFileSync)(I,"utf-8"),t=JSON.parse(e);return p={...O,...t},p}catch{return p={...O},p}}function B(){let e=y();return`http://${e.workerBind}:${e.workerPort}`}var T=require("node:fs"),H=require("node:os"),A=require("node:path");var S=require("node:fs"),_=require("node:path");var G=(0,_.join)(h,"plugin-debug.log"),w=null;function Pe(){return w===null&&(w=y().debugEnabled),w}function c(e,t){if(!Pe())return;let o=`[${new Date().toISOString()}] [${e}] ${t}
2
+ `;try{let n=(0,_.dirname)(G);(0,S.existsSync)(n)||(0,S.mkdirSync)(n,{recursive:!0}),(0,S.appendFileSync)(G,o,"utf-8")}catch{}}var Re=5e3,m="compacted";function _e(){return process.env.OPENCODE_SESSIONS_DIR??(0,A.join)((0,H.homedir)(),".config","opencode","sessions")}function $e(e){return(0,A.join)(_e(),"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 ke(e,t,r){let o=`${e}/api/context/inject?project=${encodeURIComponent(r)}`,n={};t!==null&&(n.Authorization=`Bearer ${t}`);let s=await fetch(o,{headers:n,signal:AbortSignal.timeout(Re)});return s.ok?(await s.json()).context??null:null}function ve(e){let t=$e(e);if(!(0,T.existsSync)(t))return null;try{let r=(0,T.readFileSync)(t,"utf-8"),o=JSON.parse(r);return(0,T.unlinkSync)(t),o}catch{return null}}function z(e,t){e.messages=e.messages??[],e.messages.push({role:"user",content:t})}async function K(e,t,r,o,n){c(m,`Session compacted: ${o.sessionId}`);try{let s=null;try{let i=`${t}/api/context/inject?project=${encodeURIComponent(e.project.name)}`;c(m,`GET ${i}`),s=await ke(t,r,e.project.name),c(m,s?`got context (${s.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(s){z(n,s),c(m,"injected worker context");return}let a=ve(o.sessionId);if(a){let i=Ce(a);z(n,i),c(m,"injected fallback state from file")}else c(m,"no context available")}catch(s){c(m,`error: ${s instanceof Error?s.message:String(s)}`),e.client.app.log("warn","Compacted state restore failed",{error:s instanceof Error?s.message:String(s),sessionId:o.sessionId})}}var F=require("node:path");var Ie=5e3,Oe=5,g="compacting";function we(e){if(e?.project?.name&&e.project.name!=="undefined")return e.project.name;if(e?.directory){let t=(0,F.basename)(e.directory);if(t&&t!=="."&&t!=="/")return t}if(e?.worktree){let t=(0,F.basename)(e.worktree);if(t&&t!=="."&&t!=="/")return t}}async function Ae(e,t,r){try{let o={};t!==null&&(o.Authorization=`Bearer ${t}`);let n="decisions context observations",s=new URLSearchParams({query:n,limit:String(Oe)});r!==void 0&&r!=="undefined"&&r.length>0&&s.set("project",r);let a=`${e}/api/search?${s.toString()}`;c(g,`GET ${a}`);let i=await fetch(a,{method:"GET",headers:o,signal:AbortSignal.timeout(Ie)});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(o){return c(g,`fetch error: ${o instanceof Error?o.message:String(o)}`),[]}}function Fe(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 r of e){let o=r.title||"Observation",n=r.relevanceScore!==null?` (relevance: ${Math.abs(r.relevanceScore*100).toFixed(0)}%)`:"";t.push(`### ${o}${n}`),t.push(r.summary),t.push("")}return t.join(`
4
+ `)}async function J(e,t,r,o,n){c(g,"Session compacting - fetching memories..."),c(g,`workerUrl=${t}, token=${r?"present":"null"}`),c(g,`input=${JSON.stringify(o).slice(0,300)}`);let s=we(e);c(g,`project=${s??"none"} (dir=${e?.directory??"unknown"})`);let a=await Ae(t,r,s);if(a.length>0){let i=Fe(a);n.context.push(i),c(g,`injected ${a.length} memories into compaction context`)}else c(g,"no memories found to inject")}var q=require("node:fs"),u=require("node:path");var je=300,Me=500,De=["*.test.ts","*.spec.ts","*_test.go","test_*.py"],j="file-edited";function Ne(e,t){let r=t.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*");return new RegExp(`^${r}$`).test(e)}function Le(e,t){let r=(0,u.basename)(e);return t.some(o=>Ne(r,o))}function Ue(e,t){let r=(0,u.dirname)(e),o=(0,u.extname)(e),n=(0,u.basename)(e,o),s=[];for(let a of t)if(a.startsWith("*.")){let i=a.slice(1);s.push((0,u.join)(r,`${n}${i}`))}else if(a.endsWith("*")){let i=a.slice(0,-1);s.push((0,u.join)(r,`${i}${n}${o}`))}return s}function M(e,t){e.messages=e.messages??[],e.messages.push({role:"system",content:t})}function We(e,t,r,o){if(Le(t,r))return;let n=Ue(t,r),s=e.project.root;n.some(i=>{let l=i.startsWith("/")?i:(0,u.join)(s,i);return(0,q.existsSync)(l)})||M(o,`\u26A0\uFE0F TDD Warning: No test file found for ${t}. Consider writing tests first (Red-Green-Refactor).`)}function Be(e,t,r,o,n){if(t>o){M(n,`\u{1F6A8} File Length Critical: ${e} has ${t} lines. This file should be refactored.`);return}t>r&&M(n,`\u26A0\uFE0F File Length Warning: ${e} has ${t} lines. Consider splitting this file.`)}async function Z(e,t,r,o){try{c(j,`File edited: ${r.filePath}`);let n=y(),s=r.testFilePatterns??n.testFilePatterns??De,a=r.fileLengthWarn??n.fileLengthWarn??je,i=r.fileLengthCritical??n.fileLengthCritical??Me;We(e,r.filePath,s,o);let l=r.lineCount??0;Be(r.filePath,l,a,i,o),c(j,`checks complete for ${r.filePath} (${l} lines)`)}catch(n){c(j,`error: ${n instanceof Error?n.message:String(n)}`),e.client.app.log("warn","File edited check failed",{error:n instanceof Error?n.message:String(n),filePath:r.filePath})}}var Ge=15e3,b="session-idle";function ze(e){let{context:t}=e;return t?!!(t.requested||t.investigated||t.learned||t.completed):!1}function He(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 Y(e,t,r,o,n){if(c(b,`Session idle: ${o.sessionId}`),!ze(o)){c(b,"no meaningful context to save");return}let s={"Content-Type":"application/json"};r!==null&&(s.Authorization=`Bearer ${r}`);try{let a=`${t}/api/memory/save`;c(b,`POST ${a}`);let i=await fetch(a,{method:"POST",headers:s,body:JSON.stringify({type:"session-summary",title:`Session Summary: ${o.sessionId}`,text:He(o),project:e.project.name}),signal:AbortSignal.timeout(Ge)});c(b,`response.status=${i.status}`),i.ok||e.client.app.log("warn","Failed to save session summary",{status:i.status})}catch(a){c(b,`error: ${a instanceof Error?a.message:String(a)}`),e.client.app.log("warn","Session summary save failed",{error:a instanceof Error?a.message:String(a)})}}var Ke=3e3,f="session-start";function Je(e){let t={};return e!==null&&(t.Authorization=`Bearer ${e}`),t}async function V(e,t){return fetch(e,{headers:Je(t),signal:AbortSignal.timeout(Ke)})}async function X(e,t,r,o,n,s){c(f,"Session started");let a=`${t}/api/context/inject?project=${encodeURIComponent(e.project.name)}`;c(f,`GET ${a}`);try{let i=await V(a,r);if(c(f,`response.status=${i.status}`),i.status===401&&s!==void 0){c(f,"Token expired, refreshing...");let C=s();i=await V(a,C),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?(n.messages=n.messages??[],n.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 qe=15e3,Ze=200,Q="tool-after";async function te(e,t,r,o,n,s,a){c(Q,`Tool completed: ${n.tool}`),Ye(e,t,r,o,n,s,a).catch(i=>{c(Q,`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 Ye(e,t,r,o,n,s,a){let i=`Tool ${n.tool}: ${Xe(n,s)}`,l=`${n.tool} execution`,C=Ve(n.input),de=s.output??s.error??"",N={text:o.sanitize(i),title:o.sanitize(l),project:e.project.name,toolName:n.tool,toolInput:o.sanitize(C),toolOutput:o.sanitize(de)},L=`${t}/api/memory/save`,x=await ee(L,N,r);if(x.status===401&&a!==void 0){let pe=a();x=await ee(L,N,pe)}x.ok||e.client.app.log("warn","Observation save failed",{status:x.status})}async function ee(e,t,r){let o={"Content-Type":"application/json"};return r!==null&&(o.Authorization=`Bearer ${r}`),fetch(e,{method:"POST",headers:o,body:JSON.stringify(t),signal:AbortSignal.timeout(qe)})}function Ve(e){try{return JSON.stringify(e)}catch{return String(e)}}function Xe(e,t){let r=t.output??t.error??"",o=Qe(e.input),n=r.slice(0,Ze).trim();return o&&n?`${o} -> ${n}`:o||n||"(no details)"}function Qe(e){let t=Object.entries(e);return t.length===0?"":t.map(([r,o])=>`${r}=${String(o).slice(0,80)}`).join(", ")}var $="tool-before";function et(){let e=process.env.MEMORY_TOOL_REDIRECT_RULES;if(e!==void 0)try{return JSON.parse(e)}catch{return[]}return y().toolRedirectRules}function tt(e){if(typeof e!="object"||e===null)return!1;let t=e;return typeof t.tool=="string"&&(t.action==="deny"||t.action==="redirect")}function rt(e){return e.message??`Tool '${e.tool}' is blocked by project configuration.`}function nt(e){let t=e.message??`Tool '${e.tool}' has been redirected.`;return e.alternative?`${t} Suggested alternative: ${e.alternative}.`:t}function ot(e,t){t.blocked=!0,t.messages=[{role:"user",content:rt(e)}]}function it(e,t){t.messages=[{role:"user",content:nt(e)}]}async function re(e,t,r,o){c($,`Tool executing: ${r.tool}`);let n=et();for(let s of n)try{if(!tt(s))throw new Error("Invalid rule: tool must be a string and action must be 'deny' or 'redirect'");if(s.tool!==r.tool)continue;s.action==="deny"?(ot(s,o),c($,`blocked tool ${r.tool} (deny rule)`)):(it(s,o),c($,`redirected tool ${r.tool}`));return}catch(a){c($,`rule error: ${a instanceof Error?a.message:String(a)}`),e.client.app.log("warn","Tool redirect rule evaluation failed",{error:a instanceof Error?a.message:String(a),rule:JSON.stringify(s)})}}var E=require("node:fs");function st(e){try{return process.kill(e,0),!0}catch{return!1}}function D(e){if(!(0,E.existsSync)(e))return{success:!1,errorType:"not_found",message:`PID file not found at ${e}`};let t=(0,E.statSync)(e);if((t.mode&63)!==0){let i=`0o${(t.mode&511).toString(8)}`;return{success:!1,errorType:"bad_permissions",message:`PID file at ${e} has permissions ${i} \u2014 expected 0o600`}}let r;try{r=JSON.parse((0,E.readFileSync)(e,"utf-8"))}catch{return{success:!1,errorType:"invalid_format",message:`PID file at ${e} contains invalid JSON`}}if(typeof r!="object"||r===null||typeof r.token!="string"||typeof r.pid!="number")return{success:!1,errorType:"invalid_format",message:`PID file at ${e} is missing required fields (token, pid)`};let o=r;if(o.port!==void 0&&typeof o.port!="number")return{success:!1,errorType:"invalid_format",message:`PID file at ${e} has invalid port field`};let{token:n,pid:s,port:a}=o;return st(s)?{success:!0,info:a!==void 0?{token:n,pid:s,port:a}:{token:n,pid:s}}:{success:!1,errorType:"dead_pid",message:`Worker process ${s} is not running`}}function ne(e){let t=D(e);return t.success?t.info.token:null}function oe(e){switch(e.errorType){case"not_found":return"Worker not running \u2014 PID file not found. Start it with `opencode worker start`.";case"bad_permissions":return"PID file has unsafe permissions (expected 0o600). Fix with `chmod 600 <pid-file>` then restart the worker.";case"dead_pid":return"Worker process is no longer running. Restart it with `opencode worker start`.";case"invalid_format":return"PID file is corrupted or has invalid format. Delete it and restart the worker."}}var ie=[{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 at(e,t=ie){if(!e)return e;let r=e;for(let{pattern:o}of t)o.lastIndex=0,r=r.replace(o,"[REDACTED]");return r}function se(e=[]){let t=[...ie,...e];return r=>at(r,t)}var ct=/<private>[\s\S]*?<\/private>/gi;function ae(e){return e.replace(ct,"")}function ce(e={}){let{additionalSecretPatterns:t=[],secretDetectionEnabled:r=!0}=e,o=se(t);return{sanitize(n){let s=ae(n);return r?o(s):s}}}function le(e,t,r){return[lt(e,t,r),ut(e,t,r)]}function lt(e,t,r){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:o=>gt(e,t,r,o)}}function ut(e,t,r){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:o=>dt(e,t,r,o)}}function ue(e){return e===null?{}:{Authorization:`Bearer ${e}`}}async function gt(e,t,r,o){try{let n=pt(t,o),s=await fetch(n,{headers:ue(r()),signal:AbortSignal.timeout(1e4)});if(!s.ok)return{result:`Error: Worker returned status ${s.status}`};let a=await s.json();return{result:mt(a.results??[])}}catch(n){return e.client.app.log("warn","memory_search failed",{error:n instanceof Error?n.message:String(n)}),{result:`Error: ${n instanceof Error?n.message:String(n)}`}}}async function dt(e,t,r,o){try{let n={text:o.text};o.title!==void 0&&(n.title=o.title);let s={"Content-Type":"application/json",...ue(r())},a=await fetch(`${t}/api/memory/save`,{method:"POST",headers:s,body:JSON.stringify(n),signal:AbortSignal.timeout(1e4)});if(!a.ok)return{result:`Error: Worker returned status ${a.status}`};let i=await a.json();return{result:ft(i)}}catch(n){return e.client.app.log("warn","memory_save failed",{error:n instanceof Error?n.message:String(n)}),{result:`Error: ${n instanceof Error?n.message:String(n)}`}}}function pt(e,t){let r=new URLSearchParams;return r.set("query",String(t.query??"")),t.limit!==void 0&&r.set("limit",String(t.limit)),t.project!==void 0&&r.set("project",String(t.project)),`${e}/api/search?${r.toString()}`}function mt(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 ft(e){let t=e.id??"unknown",r=e.title??"(untitled)";return`Saved observation #${t}: "${r}"`}async function ge(e){let t=B(),r=ce(),o=D(P),n;o.success?n=o.info.token:(n=null,e.client.app.log("warn",oe(o),{errorType:o.errorType,pidFilePath:P}));function s(){return n=ne(P),n}let a=()=>n;return le(e,t,a),{"session.created":(i,l)=>X(e,t,a(),i,l,s),"tool.execute.after":(i,l)=>te(e,t,a(),r,i,l,s),"tool.execute.before":(i,l)=>re(e,t,i,l),"session.idle":(i,l)=>Y(e,t,a(),i,l),"experimental.session.compacting":(i,l)=>J(e,t,a(),i,l),"session.compacted":(i,l)=>K(e,t,a(),i,l),"file.edited":(i,l)=>Z(e,t,i,l)}}