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