@kykiles/opencode-mem 13.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +429 -0
- package/dist/npx-cli/index.js +9798 -0
- package/dist/opencode-plugin/index.js +70 -0
- package/package.json +187 -0
- package/plugin/.mcp.json +12 -0
- package/plugin/bun.lock +160 -0
- package/plugin/hooks/bugfixes-2026-01-10.md +92 -0
- package/plugin/hooks/hooks.json +87 -0
- package/plugin/modes/code--ar.json +24 -0
- package/plugin/modes/code--bn.json +24 -0
- package/plugin/modes/code--chill.json +8 -0
- package/plugin/modes/code--cs.json +24 -0
- package/plugin/modes/code--da.json +24 -0
- package/plugin/modes/code--de.json +24 -0
- package/plugin/modes/code--el.json +24 -0
- package/plugin/modes/code--es.json +24 -0
- package/plugin/modes/code--fi.json +24 -0
- package/plugin/modes/code--fr.json +24 -0
- package/plugin/modes/code--he.json +24 -0
- package/plugin/modes/code--hi.json +24 -0
- package/plugin/modes/code--hu.json +24 -0
- package/plugin/modes/code--id.json +24 -0
- package/plugin/modes/code--it.json +24 -0
- package/plugin/modes/code--ja.json +24 -0
- package/plugin/modes/code--ko.json +24 -0
- package/plugin/modes/code--nl.json +24 -0
- package/plugin/modes/code--no.json +24 -0
- package/plugin/modes/code--pl.json +24 -0
- package/plugin/modes/code--pt-br.json +24 -0
- package/plugin/modes/code--ro.json +24 -0
- package/plugin/modes/code--ru.json +24 -0
- package/plugin/modes/code--sv.json +24 -0
- package/plugin/modes/code--th.json +24 -0
- package/plugin/modes/code--tr.json +24 -0
- package/plugin/modes/code--uk.json +24 -0
- package/plugin/modes/code--ur.json +25 -0
- package/plugin/modes/code--vi.json +24 -0
- package/plugin/modes/code--zh.json +24 -0
- package/plugin/modes/code.json +139 -0
- package/plugin/modes/email-investigation.json +120 -0
- package/plugin/modes/law-study--chill.json +7 -0
- package/plugin/modes/law-study-CLAUDE.md +85 -0
- package/plugin/modes/law-study.json +120 -0
- package/plugin/modes/meme-tokens.json +125 -0
- package/plugin/package.json +45 -0
- package/plugin/scripts/bun-runner.js +238 -0
- package/plugin/scripts/context-generator.cjs +825 -0
- package/plugin/scripts/mcp-server.cjs +249 -0
- package/plugin/scripts/server-service.cjs +9939 -0
- package/plugin/scripts/statusline-counts.js +40 -0
- package/plugin/scripts/transcript-watcher.cjs +29 -0
- package/plugin/scripts/version-check.js +193 -0
- package/plugin/scripts/worker-service.cjs +2238 -0
- package/plugin/scripts/worker-wrapper.cjs +2 -0
- package/plugin/skills/babysit/SKILL.md +87 -0
- package/plugin/skills/design-is/SKILL.md +312 -0
- package/plugin/skills/do/SKILL.md +45 -0
- package/plugin/skills/how-it-works/SKILL.md +22 -0
- package/plugin/skills/how-it-works/onboarding-explainer.md +17 -0
- package/plugin/skills/knowledge-agent/SKILL.md +80 -0
- package/plugin/skills/learn-codebase/SKILL.md +21 -0
- package/plugin/skills/make-plan/SKILL.md +67 -0
- package/plugin/skills/mem-search/SKILL.md +131 -0
- package/plugin/skills/oh-my-issues/SKILL.md +226 -0
- package/plugin/skills/pathfinder/SKILL.md +111 -0
- package/plugin/skills/smart-explore/SKILL.md +193 -0
- package/plugin/skills/standup/SKILL.md +142 -0
- package/plugin/skills/standup/agent-brief.md +47 -0
- package/plugin/skills/standup/standup.mjs +662 -0
- package/plugin/skills/timeline-report/SKILL.md +211 -0
- package/plugin/skills/version-bump/SKILL.md +74 -0
- package/plugin/skills/version-bump/scripts/generate_changelog.js +34 -0
- package/plugin/skills/weekly-digests/SKILL.md +262 -0
- package/plugin/skills/what-the/SKILL.md +6 -0
- package/plugin/skills/wowerpoint/SKILL.md +205 -0
- package/plugin/sqlite/SessionStore.js +764 -0
- package/plugin/sqlite/observations/files.js +10 -0
- package/plugin/ui/assets/fonts/monaspace-radon-var.woff +0 -0
- package/plugin/ui/assets/fonts/monaspace-radon-var.woff2 +0 -0
- package/plugin/ui/claude-mem-logo-for-dark-mode.webp +0 -0
- package/plugin/ui/claude-mem-logo-stylized.png +0 -0
- package/plugin/ui/claude-mem-logomark.webp +0 -0
- package/plugin/ui/icon-thick-completed.svg +8 -0
- package/plugin/ui/icon-thick-investigated.svg +8 -0
- package/plugin/ui/icon-thick-learned.svg +12 -0
- package/plugin/ui/icon-thick-next-steps.svg +8 -0
- package/plugin/ui/viewer-bundle.js +65 -0
- package/plugin/ui/viewer.html +2402 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { Database } from "bun:sqlite";
|
|
3
|
+
import { existsSync, readFileSync } from "fs";
|
|
4
|
+
import { homedir } from "os";
|
|
5
|
+
import { join, basename } from "path";
|
|
6
|
+
|
|
7
|
+
const cwd = process.argv[2] || process.env.CLAUDE_CWD || process.cwd();
|
|
8
|
+
const project = basename(cwd);
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
let dataDir = process.env.OPENCODE_MEM_DATA_DIR || join(homedir(), ".opencode-mem");
|
|
12
|
+
if (!process.env.OPENCODE_MEM_DATA_DIR) {
|
|
13
|
+
const settingsPath = join(dataDir, "settings.json");
|
|
14
|
+
if (existsSync(settingsPath)) {
|
|
15
|
+
try {
|
|
16
|
+
const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
17
|
+
if (settings.OPENCODE_MEM_DATA_DIR) dataDir = settings.OPENCODE_MEM_DATA_DIR;
|
|
18
|
+
} catch { /* use default */ }
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const dbPath = join(dataDir, "opencode-mem.db");
|
|
23
|
+
if (!existsSync(dbPath)) {
|
|
24
|
+
console.log(JSON.stringify({ observations: 0, prompts: 0, project }));
|
|
25
|
+
process.exit(0);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const db = new Database(dbPath, { readonly: true });
|
|
29
|
+
|
|
30
|
+
const obs = db.query("SELECT COUNT(*) as c FROM observations WHERE project = ?").get(project);
|
|
31
|
+
const prompts = db.query(
|
|
32
|
+
`SELECT COUNT(*) as c FROM user_prompts up
|
|
33
|
+
JOIN sdk_sessions s ON s.content_session_id = up.content_session_id
|
|
34
|
+
WHERE s.project = ?`
|
|
35
|
+
).get(project);
|
|
36
|
+
console.log(JSON.stringify({ observations: obs.c, prompts: prompts.c, project }));
|
|
37
|
+
db.close();
|
|
38
|
+
} catch (e) {
|
|
39
|
+
console.log(JSON.stringify({ observations: 0, prompts: 0, project, error: e.message }));
|
|
40
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
"use strict";var en=Object.create;var Rt=Object.defineProperty;var tn=Object.getOwnPropertyDescriptor;var rn=Object.getOwnPropertyNames;var nn=Object.getPrototypeOf,on=Object.prototype.hasOwnProperty;var me=(r,e,t)=>()=>{if(t)throw t[0];try{return r&&(e=r(r=0)),e}catch(n){throw t=[n],n}};var sn=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of rn(e))!on.call(r,o)&&o!==t&&Rt(r,o,{get:()=>e[o],enumerable:!(n=tn(e,o))||n.enumerable});return r};var K=(r,e,t)=>(t=r!=null?en(nn(r)):{},sn(e||!r||!r.__esModule?Rt(t,"default",{value:r,enumerable:!0}):t,r));function Ve(r){return(an??process.stderr.write.bind(process.stderr))(r)}function Z(r){Ve(r)}function Ct(r,e={}){ge&&ge.length>0&&(Ve(ge.join("")),ge=[]),Ve(r.endsWith(`
|
|
3
|
+
`)?r:`${r}
|
|
4
|
+
`),e.skipExit||process.exit(2)}var an,ge,Se=me(()=>{"use strict";an=null;ge=null});function un(r){return r.replace(/^\uFEFF/,"")}function ee(r){return JSON.parse(un(r))}function ln(r){(0,p.existsSync)(r)||(0,p.mkdirSync)(r,{recursive:!0})}function Xe(r,e){let t=r;try{if((0,p.lstatSync)(r).isSymbolicLink())try{t=(0,p.realpathSync)(r)}catch(d){let l=d instanceof Error?d:new Error(String(d));Z(`opencode-mem: realpathSync failed for ${r}, resolving symlink manually: ${l.message}
|
|
5
|
+
`);let _=(0,p.readlinkSync)(r);t=(0,D.resolve)((0,D.dirname)(r),_)}}catch(d){let l=d.code;if(l!=="ENOENT"&&l!=="ENOTDIR")throw d}ln((0,D.dirname)(t));let n=(0,D.dirname)(t),o=(0,D.basename)(t),i=(0,D.join)(n,`.${o}.${process.pid}.${(0,kt.randomBytes)(6).toString("hex")}.tmp`),s=Buffer.from(JSON.stringify(e,null,2)+`
|
|
6
|
+
`,"utf-8"),c;try{c=(0,p.statSync)(t).mode&511}catch{}let u;try{u=c!==void 0?(0,p.openSync)(i,"w",c):(0,p.openSync)(i,"w");let d=0;for(;d<s.length;){let l=(0,p.writeSync)(u,s,d,s.length-d);if(l===0)throw new Error(`writeSync stalled at ${d}/${s.length} bytes`);d+=l}if((0,p.fsyncSync)(u),(0,p.closeSync)(u),u=void 0,(0,p.renameSync)(i,t),!cn){let l;try{l=(0,p.openSync)(n,"r"),(0,p.fsyncSync)(l)}catch(_){let m=_ instanceof Error?_:new Error(String(_));Z(`opencode-mem: directory fsync failed for ${n}: ${m.message}
|
|
7
|
+
`)}finally{if(l!==void 0)try{(0,p.closeSync)(l)}catch{}}}}catch(d){if(u!==void 0)try{(0,p.closeSync)(u)}catch{}try{(0,p.unlinkSync)(i)}catch{}throw d}}var p,kt,D,cn,_e=me(()=>{"use strict";p=require("fs"),kt=require("crypto"),D=require("path");Se();cn=process.platform==="win32"});function dn(){return typeof __dirname<"u"?__dirname:(0,E.dirname)((0,bt.fileURLToPath)(mn.url))}function te(){if(process.env.OPENCODE_MEM_DATA_DIR)return process.env.OPENCODE_MEM_DATA_DIR;let r=(0,E.join)((0,qe.homedir)(),".opencode-mem"),e=(0,E.join)(r,"settings.json");try{if((0,ce.existsSync)(e)){let t=ee((0,ce.readFileSync)(e,"utf-8")),n=t.env??t;if(n.OPENCODE_MEM_DATA_DIR)return n.OPENCODE_MEM_DATA_DIR}}catch{}return r}var E,qe,ce,bt,mn,Jo,S,pn,ue,fn,re,Vo,ze,En,O,T=me(()=>{"use strict";E=require("path"),qe=require("os"),ce=require("fs"),bt=require("url");_e();mn={};Jo=dn();S=te(),pn=process.env.CLAUDE_CONFIG_DIR||(0,E.join)((0,qe.homedir)(),".claude"),ue=(0,E.join)(pn,"plugins","marketplaces","thedotmack"),fn=(0,E.join)(S,"logs"),re=(0,E.join)(S,"settings.json"),Vo=(0,E.join)(S,"opencode-mem.db"),ze=(0,E.join)(S,"observer-sessions"),En=(0,E.basename)(ze),O={dataDir:()=>S,workerPid:()=>(0,E.join)(S,"worker.pid"),serverPid:()=>(0,E.join)(S,".server-beta.pid"),serverPort:()=>(0,E.join)(S,".server-beta.port"),serverRuntime:()=>(0,E.join)(S,".server-beta.runtime.json"),settings:()=>(0,E.join)(S,"settings.json"),database:()=>(0,E.join)(S,"opencode-mem.db"),chroma:()=>(0,E.join)(S,"chroma"),combinedCerts:()=>(0,E.join)(S,"combined_certs.pem"),transcriptsConfig:()=>(0,E.join)(S,"transcript-watch.json"),transcriptsState:()=>(0,E.join)(S,"transcript-watch-state.json"),corpora:()=>(0,E.join)(S,"corpora"),supervisorRegistry:()=>(0,E.join)(S,"supervisor.json"),envFile:()=>(0,E.join)(S,".env"),logsDir:()=>fn}});var F,Dt,et,Ze,tt,a,f=me(()=>{"use strict";F=require("fs"),Dt=require("path");T();Se();_e();et=(i=>(i[i.DEBUG=0]="DEBUG",i[i.INFO=1]="INFO",i[i.WARN=2]="WARN",i[i.ERROR=3]="ERROR",i[i.SILENT=4]="SILENT",i))(et||{}),Ze=null,tt=class{level=null;useColor;logFilePath=null;logFileInitialized=!1;constructor(){this.useColor=process.stdout.isTTY??!1}ensureLogFileInitialized(){if(!this.logFileInitialized){this.logFileInitialized=!0;try{let e=O.logsDir();(0,F.existsSync)(e)||(0,F.mkdirSync)(e,{recursive:!0});let t=new Date().toISOString().split("T")[0];this.logFilePath=(0,Dt.join)(e,`opencode-mem-${t}.log`)}catch(e){console.error("[LOGGER] Failed to initialize log file:",e instanceof Error?e.message:String(e)),this.logFilePath=null}}}getLevel(){if(this.level===null)try{let e=O.settings();if((0,F.existsSync)(e)){let t=(0,F.readFileSync)(e,"utf-8"),o=(ee(t).OPENCODE_MEM_LOG_LEVEL||"INFO").toUpperCase();this.level=et[o]??1}else this.level=1}catch(e){console.error("[LOGGER] Failed to load log level from settings:",e instanceof Error?e.message:String(e)),this.level=1}return this.level}formatData(e){if(e==null)return"";if(typeof e=="string")return e;if(typeof e=="number"||typeof e=="boolean")return e.toString();if(typeof e=="object"){if(e instanceof Error)return this.getLevel()===0?`${e.message}
|
|
8
|
+
${e.stack}`:e.message;if(Array.isArray(e))return`[${e.length} items]`;let t=Object.keys(e);return t.length===0?"{}":t.length<=3?JSON.stringify(e):`{${t.length} keys: ${t.slice(0,3).join(", ")}...}`}return String(e)}formatTool(e,t){if(!t)return e;let n=t;if(typeof t=="string")try{n=JSON.parse(t)}catch{n=t}if(e==="Bash"&&n.command)return`${e}(${n.command})`;if(n.file_path)return`${e}(${n.file_path})`;if(n.notebook_path)return`${e}(${n.notebook_path})`;if(e==="Glob"&&n.pattern)return`${e}(${n.pattern})`;if(e==="Grep"&&n.pattern)return`${e}(${n.pattern})`;if(n.url)return`${e}(${n.url})`;if(n.query)return`${e}(${n.query})`;if(e==="Task"){if(n.subagent_type)return`${e}(${n.subagent_type})`;if(n.description)return`${e}(${n.description})`}return e==="Skill"&&n.skill?`${e}(${n.skill})`:e==="LSP"&&n.operation?`${e}(${n.operation})`:e}formatTimestamp(e){let t=e.getFullYear(),n=String(e.getMonth()+1).padStart(2,"0"),o=String(e.getDate()).padStart(2,"0"),i=String(e.getHours()).padStart(2,"0"),s=String(e.getMinutes()).padStart(2,"0"),c=String(e.getSeconds()).padStart(2,"0"),u=String(e.getMilliseconds()).padStart(3,"0");return`${t}-${n}-${o} ${i}:${s}:${c}.${u}`}log(e,t,n,o,i){if(e<this.getLevel())return;this.ensureLogFileInitialized();let s=this.formatTimestamp(new Date),c=et[e].padEnd(5),u=t.padEnd(6),d="";o?.correlationId?d=`[${o.correlationId}] `:o?.sessionId&&(d=`[session-${o.sessionId}] `);let l="";if(i!=null)if(i instanceof Error)l=this.getLevel()===0?`
|
|
9
|
+
${i.message}
|
|
10
|
+
${i.stack}`:` ${i.message}`;else if(this.getLevel()===0&&typeof i=="object")try{l=`
|
|
11
|
+
`+JSON.stringify(i,null,2)}catch{l=" "+this.formatData(i)}else l=" "+this.formatData(i);let _="";if(o){let{sessionId:y,memorySessionId:g,correlationId:G,...Ee}=o;Object.keys(Ee).length>0&&(_=` {${Object.entries(Ee).map(([V,Zr])=>`${V}=${Zr}`).join(", ")}}`)}let m=`[${s}] [${c}] [${u}] ${d}${n}${_}${l}`;if(this.logFilePath)try{(0,F.appendFileSync)(this.logFilePath,m+`
|
|
12
|
+
`,"utf8")}catch(y){let g=y instanceof Error?y:new Error(String(y));Z(`[LOGGER] Failed to write to log file: ${g.message}
|
|
13
|
+
${g.stack??""}
|
|
14
|
+
`)}else Z(m+`
|
|
15
|
+
`)}debug(e,t,n,o){this.log(0,e,t,n,o)}info(e,t,n,o){this.log(1,e,t,n,o)}warn(e,t,n,o){this.log(2,e,t,n,o)}setErrorSink(e){Ze=e}error(e,t,n,o){this.log(3,e,t,n,o),this.routeErrorToSink(t,n,o)}routeErrorToSink(e,t,n){try{if(!Ze||!(n instanceof Error))return;Ze(n)}catch{}}dataIn(e,t,n,o){this.info(e,`\u2192 ${t}`,n,o)}dataOut(e,t,n,o){this.info(e,`\u2190 ${t}`,n,o)}success(e,t,n,o){this.info(e,`\u2713 ${t}`,n,o)}failure(e,t,n,o){this.error(e,`\u2717 ${t}`,n,o)}},a=new tt});var L=require("fs"),Qe=require("os"),le=require("path");T();var ne=O.transcriptsConfig(),he=O.transcriptsState(),gn={version:1,schemas:{},watches:[],stateFile:he};function Sn(r){let e=typeof r.schema=="string"?r.schema:r.schema?.name;if(!(r.name==="codex"||e==="codex")||!r.path)return!1;let n=P(r.path).replace(/\\/g,"/"),o=(0,le.join)((0,Qe.homedir)(),".codex","sessions").replace(/\\/g,"/");return n===`${o}/**/*.jsonl`}function It(r){let e=typeof r.schema=="string"?r.schema:r.schema?.name,t=r.name==="codex"&&(!e||e==="codex");return r.context?.mode==="agents"&&t&&Sn(r)}function P(r){return r&&(r.startsWith("~")?(0,le.join)((0,Qe.homedir)(),r.slice(1)):r)}function de(r=ne){let e=P(r);if(!(0,L.existsSync)(e))throw new Error(`Transcript watch config not found: ${e}`);let t=(0,L.readFileSync)(e,"utf-8"),n=JSON.parse(t);if(!n.version||!n.watches)throw new Error(`Invalid transcript watch config: ${e}`);return n.stateFile||(n.stateFile=he),n}function Oe(r=ne){let e=P(r),t=(0,le.dirname)(e);(0,L.existsSync)(t)||(0,L.mkdirSync)(t,{recursive:!0}),(0,L.writeFileSync)(e,JSON.stringify(gn,null,2))}var w=require("fs"),I=require("path");f();var W=require("fs"),Nt=require("path");f();function At(r){try{if(!(0,W.existsSync)(r))return{offsets:{}};let e=(0,W.readFileSync)(r,"utf-8"),t=JSON.parse(e);return t.offsets?t:{offsets:{}}}catch(e){return a.warn("TRANSCRIPT","Failed to load watch state, starting fresh",{statePath:r,error:e instanceof Error?e.message:String(e)}),{offsets:{}}}}function xt(r,e){try{let t=(0,Nt.dirname)(r);(0,W.existsSync)(t)||(0,W.mkdirSync)(t,{recursive:!0}),(0,W.writeFileSync)(r,JSON.stringify(e,null,2))}catch(t){a.warn("TRANSCRIPT","Failed to save watch state",{statePath:r,error:t instanceof Error?t.message:String(t)})}}var fe=K(require("path"),1);var M=K(require("path"),1),h=require("fs");var rt=require("node:child_process");function Te(r,e,t){return(0,rt.spawn)(r,e??[],{windowsHide:!0,...t})}var _n=new Set([".cmd",".bat"]),hn=new Set([".exe",".com"]),os=new Set([...hn,..._n]);f();var k={HEALTH_CHECK:3e3,API_REQUEST:3e4,HOOK_READINESS_WAIT:1e4,POST_SPAWN_WAIT:15e3,READINESS_WAIT:3e4,PORT_IN_USE_WAIT:3e3,POWERSHELL_COMMAND:1e4,WINDOWS_MULTIPLIER:1.5},Y={SUCCESS:0,BLOCKING_ERROR:2};function B(r){return process.platform==="win32"?Math.round(r*k.WINDOWS_MULTIPLIER):r}var ye=require("fs"),nt=require("path"),ot=require("os");_e();var v=class{static DEFAULTS={OPENCODE_MEM_MODEL:"claude-haiku-4-5-20251001",OPENCODE_MEM_CONTEXT_OBSERVATIONS:"50",OPENCODE_MEM_WORKER_PORT:String(37700+(process.getuid?.()??77)%100),OPENCODE_MEM_WORKER_HOST:"127.0.0.1",OPENCODE_MEM_API_TIMEOUT_MS:String(B(k.API_REQUEST)),OPENCODE_MEM_SKIP_TOOLS:"ListMcpResourcesTool,SlashCommand,Skill,TodoWrite,AskUserQuestion",OPENCODE_MEM_PROVIDER:"claude",OPENCODE_MEM_CLAUDE_AUTH_METHOD:"subscription",OPENCODE_MEM_GEMINI_API_KEY:"",OPENCODE_MEM_GEMINI_MODEL:"gemini-2.5-flash-lite",OPENCODE_MEM_GEMINI_RATE_LIMITING_ENABLED:"true",OPENCODE_MEM_OPENROUTER_API_KEY:"",OPENCODE_MEM_OPENROUTER_MODEL:"xiaomi/mimo-v2-flash:free",OPENCODE_MEM_OPENROUTER_BASE_URL:"",OPENCODE_MEM_OPENROUTER_SITE_URL:"",OPENCODE_MEM_OPENROUTER_APP_NAME:"opencode-mem",OPENCODE_MEM_DATA_DIR:(0,nt.join)((0,ot.homedir)(),".opencode-mem"),OPENCODE_MEM_LOG_LEVEL:"INFO",OPENCODE_MEM_PYTHON_VERSION:"3.13",CLAUDE_CODE_PATH:"",OPENCODE_MEM_MODE:"code",OPENCODE_MEM_CONTEXT_SHOW_READ_TOKENS:"false",OPENCODE_MEM_CONTEXT_SHOW_WORK_TOKENS:"false",OPENCODE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT:"false",OPENCODE_MEM_CONTEXT_SHOW_SAVINGS_PERCENT:"true",OPENCODE_MEM_CONTEXT_FULL_COUNT:"0",OPENCODE_MEM_CONTEXT_FULL_FIELD:"narrative",OPENCODE_MEM_CONTEXT_SESSION_COUNT:"10",OPENCODE_MEM_CONTEXT_SHOW_LAST_SUMMARY:"true",OPENCODE_MEM_CONTEXT_SHOW_LAST_MESSAGE:"false",OPENCODE_MEM_CONTEXT_SHOW_TERMINAL_OUTPUT:"true",OPENCODE_MEM_WELCOME_HINT_ENABLED:"true",OPENCODE_MEM_FOLDER_CLAUDEMD_ENABLED:"false",OPENCODE_MEM_FOLDER_USE_LOCAL_MD:"false",OPENCODE_MEM_TRANSCRIPTS_ENABLED:"true",OPENCODE_MEM_TRANSCRIPTS_CONFIG_PATH:(0,nt.join)((0,ot.homedir)(),".opencode-mem","transcript-watch.json"),OPENCODE_MEM_CODEX_TRANSCRIPT_INGESTION:"false",OPENCODE_MEM_MAX_CONCURRENT_AGENTS:"2",OPENCODE_MEM_HOOK_FAIL_LOUD_THRESHOLD:"3",OPENCODE_MEM_EXCLUDED_PROJECTS:"",OPENCODE_MEM_FOLDER_MD_EXCLUDE:"[]",OPENCODE_MEM_FOLDER_MD_SKELETON_DENYLIST:"[]",OPENCODE_MEM_SEMANTIC_INJECT:"false",OPENCODE_MEM_SEMANTIC_INJECT_LIMIT:"5",OPENCODE_MEM_TIER_ROUTING_ENABLED:"true",OPENCODE_MEM_TIER_SIMPLE_MODEL:"haiku",OPENCODE_MEM_TIER_SUMMARY_MODEL:"",OPENCODE_MEM_TIER_FAST_MODEL:"haiku",OPENCODE_MEM_TIER_SMART_MODEL:"sonnet",OPENCODE_MEM_CHROMA_ENABLED:"true",OPENCODE_MEM_CHROMA_MODE:"local",OPENCODE_MEM_CHROMA_HOST:"127.0.0.1",OPENCODE_MEM_CHROMA_PORT:"8000",OPENCODE_MEM_CHROMA_SSL:"false",OPENCODE_MEM_CHROMA_API_KEY:"",OPENCODE_MEM_CHROMA_TENANT:"default_tenant",OPENCODE_MEM_CHROMA_DATABASE:"default_database",OPENCODE_MEM_CHROMA_PREWARM_TIMEOUT_MS:"120000",OPENCODE_MEM_TELEGRAM_ENABLED:"true",OPENCODE_MEM_TELEGRAM_BOT_TOKEN:"",OPENCODE_MEM_TELEGRAM_CHAT_ID:"",OPENCODE_MEM_TELEGRAM_TRIGGER_TYPES:"security_alert",OPENCODE_MEM_TELEGRAM_TRIGGER_CONCEPTS:"",OPENCODE_MEM_QUEUE_ENGINE:"sqlite",OPENCODE_MEM_REDIS_URL:"",OPENCODE_MEM_REDIS_HOST:"127.0.0.1",OPENCODE_MEM_REDIS_PORT:"6379",OPENCODE_MEM_REDIS_MODE:"external",OPENCODE_MEM_QUEUE_REDIS_PREFIX:`opencode_mem_${process.env.OPENCODE_MEM_WORKER_PORT??String(37700+(process.getuid?.()??77)%100)}`,OPENCODE_MEM_AUTH_MODE:"api-key",OPENCODE_MEM_RUNTIME:"worker",OPENCODE_MEM_SERVER_URL:`http://127.0.0.1:${process.env.OPENCODE_MEM_SERVER_PORT??String(37877+(process.getuid?.()??77)%100)}`,OPENCODE_MEM_SERVER_API_KEY:"",OPENCODE_MEM_SERVER_PROJECT_ID:"",OPENCODE_MEM_SERVER_BETA_URL:`http://127.0.0.1:${process.env.OPENCODE_MEM_SERVER_PORT??String(37877+(process.getuid?.()??77)%100)}`,OPENCODE_MEM_SERVER_BETA_API_KEY:"",OPENCODE_MEM_SERVER_BETA_PROJECT_ID:""};static getAllDefaults(){return{...this.DEFAULTS}}static get(e){return process.env[e]??this.DEFAULTS[e]}static getInt(e){let t=this.get(e);return parseInt(t,10)}static applyEnvOverrides(e){let t={...e};for(let n of Object.keys(this.DEFAULTS))process.env[n]!==void 0&&(t[n]=process.env[n]);return t}static loadFromFile(e,t=!0){try{if(!(0,ye.existsSync)(e)){let c=this.getAllDefaults();try{Xe(e,c),console.warn("[SETTINGS] Created settings file with defaults:",e)}catch(u){console.warn("[SETTINGS] Failed to create settings file, using in-memory defaults:",e,u instanceof Error?u.message:String(u))}return t?this.applyEnvOverrides(c):c}let n=(0,ye.readFileSync)(e,"utf-8"),o=ee(n),i=o;if(o.env&&typeof o.env=="object"){i=o.env;try{Xe(e,i),console.warn("[SETTINGS] Migrated settings file from nested to flat schema:",e)}catch(c){console.warn("[SETTINGS] Failed to auto-migrate settings file:",e,c instanceof Error?c.message:String(c))}}let s={...this.DEFAULTS};for(let c of Object.keys(this.DEFAULTS))i[c]!==void 0&&(s[c]=i[c]);return t?this.applyEnvOverrides(s):s}catch(n){console.warn("[SETTINGS] Failed to load settings, using defaults:",e,n instanceof Error?n.message:String(n));let o=this.getAllDefaults();return t?this.applyEnvOverrides(o):o}}};T();T();var we=null;function H(){return we!==null||(we=v.loadFromFile(re)),we}var X=require("fs");f();var ut=require("child_process");var A=require("fs"),at=K(require("path"),1);f();var On=["CLAUDECODE_","CLAUDE_CODE_"],Tn=new Set(["CLAUDECODE","CLAUDE_CODE_SESSION","CLAUDE_CODE_ENTRYPOINT","MCP_SESSION_ID"]),yn=new Set(["HTTP_PROXY","HTTPS_PROXY","ALL_PROXY","NO_PROXY","http_proxy","https_proxy","all_proxy","no_proxy","npm_config_proxy","npm_config_https_proxy","npm_config_noproxy"]),wn=new Set(["CLAUDE_CODE_OAUTH_TOKEN","CLAUDE_CODE_GIT_BASH_PATH","CLAUDE_CODE_USE_BEDROCK","CLAUDE_CODE_USE_VERTEX","CLAUDE_CODE_SKIP_BEDROCK_AUTH","CLAUDE_CODE_SKIP_VERTEX_AUTH","ANTHROPIC_BEDROCK_BASE_URL","AWS_REGION","AWS_PROFILE","AWS_ACCESS_KEY_ID","AWS_SECRET_ACCESS_KEY","AWS_SESSION_TOKEN","ANTHROPIC_VERTEX_PROJECT_ID","CLOUD_ML_REGION","GOOGLE_APPLICATION_CREDENTIALS",...yn]);function Pe(r=process.env){let e={};for(let[t,n]of Object.entries(r))if(n!==void 0){if(wn.has(t)){e[t]=n;continue}Tn.has(t)||On.some(o=>t.startsWith(o))||(e[t]=n)}return e}T();var Pn=5e3,Mn=1e3,vn=O.supervisorRegistry();function N(r){if(!Number.isInteger(r)||r<0||r===0)return!1;try{return process.kill(r,0),!0}catch(e){if(e instanceof Error){let t=e.code;return t==="EPERM"?!0:(a.debug("SYSTEM","PID check failed",{pid:r,code:t}),!1)}return a.warn("SYSTEM","PID check threw non-Error",{pid:r,error:String(e)}),!1}}async function Me(r,e){let t=Date.now()+e;for(;Date.now()<t;){if(r.every(n=>!N(n.pid)))return;await new Promise(n=>setTimeout(n,100))}}var Rn=5e3,Lt=new Map;function Cn(r){let e=(0,ut.spawnSync)("powershell.exe",["-NoProfile","-NonInteractive","-Command",`(Get-CimInstance Win32_Process -Filter "ProcessId=${r}").CreationDate.ToString('yyyyMMddHHmmss.ffffff')`],{encoding:"utf-8",timeout:5e3,windowsHide:!0,env:{...Pe(process.env),LC_ALL:"C",LANG:"C"}});if(e.status===0){let t=e.stdout.trim();return t.length>0?t:null}return null}function kn(r){let e=Lt.get(r);if(e&&Date.now()-e.capturedAtMs<Rn)return e.token;let t=null;try{t=Cn(r)}catch(n){a.debug("SYSTEM","captureProcessStartToken: powershell CIM lookup failed",{pid:r,error:n instanceof Error?n.message:String(n)}),t=null}return Lt.set(r,{token:t,capturedAtMs:Date.now()}),t}function Ft(r){if(!Number.isInteger(r)||r<=0)return null;if(process.platform==="linux")try{let e=(0,A.readFileSync)(`/proc/${r}/stat`,"utf-8"),t=e.lastIndexOf(") ");if(t<0)return null;let o=e.slice(t+2).split(" ")[19];return o&&/^\d+$/.test(o)?o:null}catch(e){return a.debug("SYSTEM","captureProcessStartToken: /proc read failed",{pid:r,error:e instanceof Error?e.message:String(e)}),null}if(process.platform==="win32")return kn(r);try{let e=(0,ut.spawnSync)("ps",["-p",String(r),"-o","lstart="],{encoding:"utf-8",timeout:2e3,env:{...Pe(process.env),LC_ALL:"C",LANG:"C"}});if(e.status!==0)return null;let t=e.stdout.trim();return t.length>0?t:null}catch(e){return a.debug("SYSTEM","captureProcessStartToken: ps exec failed",{pid:r,error:e instanceof Error?e.message:String(e)}),null}}function lt(r){if(!r||!N(r.pid))return!1;if(!r.startToken)return!0;let e=Ft(r.pid);if(e===null)return!0;let t=e===r.startToken;return t||a.debug("SYSTEM","verifyPidFileOwnership: start-token mismatch (PID reused)",{pid:r.pid,stored:r.startToken,current:e}),t}var ct=class{registryPath;entries=new Map;runtimeProcesses=new Map;initialized=!1;constructor(e=vn){this.registryPath=e}initialize(){if(this.initialized)return;if(this.initialized=!0,(0,A.mkdirSync)(at.default.dirname(this.registryPath),{recursive:!0}),!(0,A.existsSync)(this.registryPath)){this.persist();return}try{let n=JSON.parse((0,A.readFileSync)(this.registryPath,"utf-8")).processes??{};for(let[o,i]of Object.entries(n))this.entries.set(o,i)}catch(t){t instanceof Error?a.warn("SYSTEM","Failed to parse supervisor registry, rebuilding",{path:this.registryPath},t):a.warn("SYSTEM","Failed to parse supervisor registry, rebuilding",{path:this.registryPath,error:String(t)}),this.entries.clear()}let e=this.pruneDeadEntries();e>0&&a.info("SYSTEM","Removed dead processes from supervisor registry",{removed:e}),this.persist()}register(e,t,n){this.initialize(),this.entries.set(e,t),n&&this.runtimeProcesses.set(e,n),this.persist()}unregister(e){this.initialize();let t=this.entries.get(e);this.entries.delete(e),this.runtimeProcesses.delete(e),this.persist(),t?.type==="sdk"&&it()}clear(){this.entries.clear(),this.runtimeProcesses.clear(),this.persist()}getAll(){return this.initialize(),Array.from(this.entries.entries()).map(([e,t])=>({id:e,...t})).sort((e,t)=>{let n=Date.parse(e.startedAt),o=Date.parse(t.startedAt);return(Number.isNaN(n)?0:n)-(Number.isNaN(o)?0:o)})}getBySession(e){let t=String(e);return this.getAll().filter(n=>n.sessionId!==void 0&&String(n.sessionId)===t)}getRuntimeProcess(e){return this.runtimeProcesses.get(e)}pruneDeadEntries(){this.initialize();let e=0,t=0;for(let[n,o]of this.entries)N(o.pid)||(this.entries.delete(n),this.runtimeProcesses.delete(n),e+=1,o.type==="sdk"&&(t+=1));e>0&&this.persist();for(let n=0;n<t;n+=1)it();return e}async reapSession(e){this.initialize();let t=this.getBySession(e);if(t.length===0)return 0;let n=typeof e=="number"?e:Number(e)||void 0;a.info("SYSTEM",`Reaping ${t.length} process(es) for session ${e}`,{sessionId:n,pids:t.map(s=>s.pid)});let o=t.filter(s=>N(s.pid));for(let s of o)try{typeof s.pgid=="number"&&process.platform!=="win32"?process.kill(-s.pgid,"SIGTERM"):process.kill(s.pid,"SIGTERM")}catch(c){c instanceof Error?c.code!=="ESRCH"&&a.debug("SYSTEM",`Failed to SIGTERM session process PID ${s.pid}`,{pid:s.pid,pgid:s.pgid},c):a.warn("SYSTEM",`Failed to SIGTERM session process PID ${s.pid} (non-Error)`,{pid:s.pid,pgid:s.pgid,error:String(c)})}await Me(o,Pn);let i=o.filter(s=>N(s.pid));for(let s of i){a.warn("SYSTEM",`Session process PID ${s.pid} did not exit after SIGTERM, sending SIGKILL`,{pid:s.pid,pgid:s.pgid,sessionId:n});try{typeof s.pgid=="number"&&process.platform!=="win32"?process.kill(-s.pgid,"SIGKILL"):process.kill(s.pid,"SIGKILL")}catch(c){c instanceof Error?c.code!=="ESRCH"&&a.debug("SYSTEM",`Failed to SIGKILL session process PID ${s.pid}`,{pid:s.pid,pgid:s.pgid},c):a.warn("SYSTEM",`Failed to SIGKILL session process PID ${s.pid} (non-Error)`,{pid:s.pid,pgid:s.pgid,error:String(c)})}}if(i.length>0){let s=Date.now()+Mn;for(;Date.now()<s&&i.filter(u=>N(u.pid)).length!==0;)await new Promise(u=>setTimeout(u,100))}for(let s of t)this.entries.delete(s.id),this.runtimeProcesses.delete(s.id);this.persist();for(let s of t)s.type==="sdk"&&it();return a.info("SYSTEM",`Reaped ${t.length} process(es) for session ${e}`,{sessionId:n,reaped:t.length}),t.length}persist(){let e={processes:Object.fromEntries(this.entries.entries())};(0,A.mkdirSync)(at.default.dirname(this.registryPath),{recursive:!0}),(0,A.writeFileSync)(this.registryPath,JSON.stringify(e,null,2))}},st=null;function ve(){return st||(st=new ct),st}var bn=[];function it(){let r=bn.shift();r&&r()}var Ht=require("child_process"),oe=require("fs"),Ut=require("util");f();T();var In=(0,Ut.promisify)(Ht.execFile),Dn=O.workerPid();async function $t(r){let e=r.currentPid??process.pid,t=r.pidFilePath??Dn,n=r.registry.getAll(),o=[...n].filter(s=>s.pid!==e).sort((s,c)=>Date.parse(c.startedAt)-Date.parse(s.startedAt));for(let s of o){if(!N(s.pid)){r.registry.unregister(s.id);continue}try{await Wt(s,"SIGTERM")}catch(c){c instanceof Error?a.debug("SYSTEM","Failed to send SIGTERM to child process",{pid:s.pid,pgid:s.pgid,type:s.type},c):a.warn("SYSTEM","Failed to send SIGTERM to child process (non-Error)",{pid:s.pid,pgid:s.pgid,type:s.type,error:String(c)})}}await Me(o,5e3);let i=o.filter(s=>N(s.pid));for(let s of i)try{await Wt(s,"SIGKILL")}catch(c){c instanceof Error?a.debug("SYSTEM","Failed to force kill child process",{pid:s.pid,pgid:s.pgid,type:s.type},c):a.warn("SYSTEM","Failed to force kill child process (non-Error)",{pid:s.pid,pgid:s.pgid,type:s.type,error:String(c)})}await Me(i,1e3);for(let s of o)r.registry.unregister(s.id);for(let s of n.filter(c=>c.pid===e))r.registry.unregister(s.id);jt(t,e),r.registry.pruneDeadEntries()}function jt(r,e,t=!1){if(!(0,oe.existsSync)(r))return;let n=null;try{let s=JSON.parse((0,oe.readFileSync)(r,"utf-8"));n=typeof s.pid=="number"?s.pid:null}catch(s){a.debug("SYSTEM","PID file unreadable \u2014 leaving it (cannot prove ownership)",{pidFilePath:r,error:s instanceof Error?s.message:String(s)});return}let o=e!==null&&n===e,i=n===null||!N(n);if(!o&&!(t&&i)){a.debug("SYSTEM","PID file not owned by this process \u2014 leaving it for its owner (restart successor?)",{pidFilePath:r,recordedPid:n,currentPid:e});return}try{(0,oe.rmSync)(r,{force:!0})}catch(s){s instanceof Error?a.debug("SYSTEM","Failed to remove PID file",{pidFilePath:r},s):a.warn("SYSTEM","Failed to remove PID file (non-Error)",{pidFilePath:r,error:String(s)})}}async function Wt(r,e){let{pid:t,pgid:n}=r;if(process.platform!=="win32"){if(typeof n=="number")try{process.kill(-n,e);return}catch(i){if((i instanceof Error?i.code:void 0)!=="ESRCH")throw i}try{process.kill(t,e)}catch(i){if((i instanceof Error?i.code:void 0)!=="ESRCH")throw i}return}if(e==="SIGTERM"){try{process.kill(t,e)}catch(i){if(i instanceof Error&&i.code==="ESRCH")return;throw i}return}let o=["/PID",String(t),"/T"];e==="SIGKILL"&&o.push("/F"),await In("taskkill",o,{timeout:k.POWERSHELL_COMMAND,windowsHide:!0})}f();var Gt=3e4,se=null;function Nn(){let e=ve().pruneDeadEntries();e>0&&a.info("SYSTEM",`Health check: pruned ${e} dead process(es) from registry`)}function Kt(){se===null&&(se=setInterval(Nn,Gt),se.unref(),a.debug("SYSTEM","Health checker started",{intervalMs:Gt}))}function Yt(){se!==null&&(clearInterval(se),se=null,a.debug("SYSTEM","Health checker stopped"))}T();var An=O.workerPid(),dt=class{registry;started=!1;stopPromise=null;signalHandlersRegistered=!1;shutdownInitiated=!1;shutdownHandler=null;constructor(e){this.registry=e}async start(){if(this.started)return;if(this.registry.initialize(),Re({logAlive:!1})==="alive")throw new Error("Worker already running");this.started=!0,Kt()}configureSignalHandlers(e){if(this.shutdownHandler=e,this.signalHandlersRegistered)return;this.signalHandlersRegistered=!0;let t=async n=>{if(this.shutdownInitiated){a.warn("SYSTEM",`Received ${n} but shutdown already in progress`);return}this.shutdownInitiated=!0,a.info("SYSTEM",`Received ${n}, shutting down...`);try{this.shutdownHandler?await this.shutdownHandler():await this.stop()}catch(o){o instanceof Error?a.error("SYSTEM","Error during shutdown",{},o):a.error("SYSTEM","Error during shutdown (non-Error)",{error:String(o)});try{await this.stop()}catch(i){i instanceof Error?a.debug("SYSTEM","Supervisor shutdown fallback failed",{},i):a.debug("SYSTEM","Supervisor shutdown fallback failed",{error:String(i)})}}process.exit(0)};process.on("SIGTERM",()=>{t("SIGTERM")}),process.on("SIGINT",()=>{t("SIGINT")}),process.platform!=="win32"&&(process.argv.includes("--daemon")?process.on("SIGHUP",()=>{a.debug("SYSTEM","Ignoring SIGHUP in daemon mode")}):process.on("SIGHUP",()=>{t("SIGHUP")}))}async stop(){if(this.stopPromise){await this.stopPromise;return}Yt(),this.stopPromise=$t({registry:this.registry,currentPid:process.pid}).finally(()=>{this.started=!1,this.stopPromise=null}),await this.stopPromise}assertCanSpawn(e){if(this.stopPromise!==null)throw new Error(`Supervisor is shutting down, refusing to spawn ${e}`)}registerProcess(e,t,n){this.registry.register(e,t,n)}unregisterProcess(e){this.registry.unregister(e)}getRegistry(){return this.registry}},Ns=new dt(ve());function Re(r={}){let e=r.pidFilePath??An;if(!(0,X.existsSync)(e))return"missing";let t=null;try{t=JSON.parse((0,X.readFileSync)(e,"utf-8"))}catch(o){return o instanceof Error?a.warn("SYSTEM","Failed to parse worker PID file, removing it",{path:e},o):a.warn("SYSTEM","Failed to parse worker PID file, removing it",{path:e,error:String(o)}),(0,X.rmSync)(e,{force:!0}),"invalid"}return lt(t)&&t?((r.logAlive??!0)&&a.info("SYSTEM","Worker already running (PID alive)",{existingPid:t.pid,existingPort:t.port,startedAt:t.startedAt}),"alive"):(a.info("SYSTEM","Removing stale PID file (worker process is dead or PID has been reused)",{pid:t?.pid,port:t?.port,startedAt:t?.startedAt}),(0,X.rmSync)(e,{force:!0}),"stale")}Se();var pt=require("path"),ke=require("fs"),Jt=require("crypto");T();var Ce=require("fs");function Bt(r,e){if(!(0,Ce.existsSync)(r))return e;try{return JSON.parse((0,Ce.readFileSync)(r,"utf-8"))}catch(t){throw new Error(`Corrupt JSON file, refusing to overwrite: ${r}: ${t instanceof Error?t.message:String(t)}`)}}f();var Vt="telemetry.json";function xn(r){let e=r.DO_NOT_TRACK;return e===void 0||e===""?!1:e!=="0"&&e!=="false"}function Ln(r,e){if(xn(r))return{enabled:!1,source:"DO_NOT_TRACK"};let t=r.OPENCODE_MEM_TELEMETRY?.toLowerCase();return t==="0"||t==="false"||t==="off"?{enabled:!1,source:"env"}:t==="1"||t==="true"||t==="on"?{enabled:!0,source:"env"}:e?.enabled===!0?{enabled:!0,source:"config"}:e?.enabled===!1?{enabled:!1,source:"config"}:{enabled:!0,source:"default"}}function Xt(r,e){return Ln(r,e).enabled}function Fn(){return(0,pt.join)(te(),Vt)}function ft(){let r;try{r=Bt(Fn(),null)}catch(e){let t=e instanceof Error?e:new Error(String(e));return a.warn("SYSTEM","Telemetry: corrupt telemetry.json; treating as no recorded consent",void 0,t),null}return!r||typeof r!="object"||typeof r.installId!="string"||r.enabled!==void 0&&typeof r.enabled!="boolean"?null:{enabled:r.enabled,installId:r.installId,decidedAt:typeof r.decidedAt=="string"?r.decidedAt:""}}function Wn(r){let e=te();(0,ke.mkdirSync)(e,{recursive:!0}),(0,ke.writeFileSync)((0,pt.join)(e,Vt),JSON.stringify(r,null,2)+`
|
|
16
|
+
`)}function qt(){let r=ft();if(r?.installId)return r.installId;let e=(0,Jt.randomUUID)();return Wn({installId:e,decidedAt:""}),e}var Hn=new Set(["version","os","os_version","is_wsl","arch","runtime","runtime_version","node_version","duration_ms","outcome","error_category","locale","is_ci","endpoint","ide","provider","runtime_mode","trigger","count","has_summary","is_update","install_method","interactive","bun_version","uv_version","claude_code_version","observation_count","session_count","timeline_depth_days","has_session_summary","obs_type_bugfix","obs_type_discovery","obs_type_decision","obs_type_refactor","obs_type_other","tokens_injected","tokens_saved_vs_naive","mode","search_strategy","observation_type","hook","compression_ms","tokens_input","tokens_output","compression_ratio","model","cost_usd","endpoint_class","db_observation_count","db_session_count","db_summary_count","db_project_count","db_size_mb","install_age_days","obs_count_7d","obs_count_30d","days_since_last_obs","result_count","chroma_available","fallback_reason","invalid_output_class","consecutive_invalid_outputs","respawn_triggered","abort_reason","previous_shutdown","previous_uptime_seconds","uptime_seconds","shutdown_reason","process_rss_mb","heap_used_mb","hook_type","error_mode","consecutive_failures","threshold_tripped","discovery_tokens","read_tokens","summary_count","prompt_count","project_count","backfilled","first_active_date","session_completed_count","session_failed_count","sessions_claude_count","sessions_codex_count","sessions_gemini_count","sessions_other_platform_count","subagent_obs_count","total_tokens_input","total_tokens_output","total_cost_usd","avg_duration_ms","avg_compression_ms","outcomes_ok","outcomes_error","outcomes_aborted","outcomes_invalid_output","top_model","window_start_ts","rollup_reason","window_seq","total_tokens","avg_tokens","observations_created","total_observations_injected","total_tokens_saved_vs_naive"]),zt=200;function Un(r,e){if(!(!r||typeof r!="object"))for(let t of Object.keys(r)){if(!Hn.has(t))continue;let n=r[t];typeof n=="string"?e[t]=n.length>zt?n.slice(0,zt):n:(typeof n=="number"&&Number.isFinite(n)||typeof n=="boolean")&&(e[t]=n)}}function Qt(r){let e={};try{Un(r,e)}catch{}return e}var Et=K(require("os"),1);f();var $n="13.10.2",jn="phc_BKJAeNbpj932N9qEiU6qhutZEiu6LLfRpXfTbLM9MLaG",Gn="https://us.i.posthog.com";function Zt(){return process.env.OPENCODE_MEM_TELEMETRY_KEY||jn}function er(){return process.env.OPENCODE_MEM_TELEMETRY_HOST||Gn}var Kn=["version","os","os_version","is_wsl","arch","runtime","locale","ide","provider","runtime_mode","install_method","claude_code_version","first_active_date","db_observation_count","db_session_count","db_summary_count","db_project_count","db_size_mb","install_age_days","obs_count_7d","obs_count_30d","days_since_last_obs"];function tr(r){let e={};for(let t of Kn)r[t]!==void 0&&(e[t]=r[t]);return e}function Yn(){if(process.platform!=="linux")return!1;try{return!!process.env.WSL_DISTRO_NAME||Et.default.release().toLowerCase().includes("microsoft")}catch(r){let e=r instanceof Error?r:new Error(String(r));return a.warn("SYSTEM","Telemetry: WSL detection failed; reporting is_wsl=false",void 0,e),!1}}function rr(){return{version:$n,os:process.platform,os_version:Et.default.release(),is_wsl:Yn(),arch:process.arch,runtime:process.versions.bun?"bun":"node",runtime_version:process.versions.bun??process.versions.node,node_version:process.versions.node,is_ci:!!process.env.CI,locale:Intl.DateTimeFormat().resolvedOptions().locale}}var Bn=2e3;async function nr(r,e,t){try{if(!Xt(process.env,ft()))return;let n=Qt({...rr(),...e??{}});if(t?.person?n.$set=tr(n):n.$process_person_profile=!1,process.env.OPENCODE_MEM_TELEMETRY_DEBUG==="1"){process.stderr.write("[telemetry] "+JSON.stringify({event:r,properties:n})+`
|
|
17
|
+
`);return}let o=Zt(),i=new AbortController,s=setTimeout(()=>i.abort(),Bn);try{await Jn(o,r,n,i.signal)}finally{clearTimeout(s)}}catch{}}async function Jn(r,e,t,n){await fetch(`${er()}/capture/`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({api_key:r,event:e,distinct_id:qt(),properties:t}),signal:n})}var q=K(require("path"),1),sr=require("os"),U=require("fs"),gt=require("child_process");f();T();var Zs=O.dataDir(),ei=O.workerPid();function or(r){return r?/(^|[\\/])bun(\.exe)?$/i.test(r.trim()):!1}function Xn(r,e){let t=e==="win32"?`where ${r}`:`which ${r}`,n;try{n=(0,gt.execSync)(t,{stdio:["ignore","pipe","ignore"],encoding:"utf-8",windowsHide:!0})}catch(i){return i instanceof Error?a.debug("SYSTEM",`Binary lookup failed for ${r}`,{command:t},i):a.debug("SYSTEM",`Binary lookup failed for ${r}`,{command:t},new Error(String(i))),null}return n.split(/\r?\n/).map(i=>i.trim()).find(i=>i.length>0)||null}var mt;function ir(r={}){let e=Object.keys(r).length===0;if(e&&mt!==void 0)return mt;let t=qn(r);return e&&t!==null&&(mt=t),t}function qn(r){let e=r.platform??process.platform,t=r.execPath??process.execPath;if(or(t))return t;let n=r.env??process.env,o=r.homeDirectory??(0,sr.homedir)(),i=r.pathExists??U.existsSync,s=r.lookupInPath??Xn,c=e==="win32"?[n.BUN,n.BUN_PATH,q.default.join(o,".bun","bin","bun.exe"),q.default.join(o,".bun","bin","bun"),n.USERPROFILE?q.default.join(n.USERPROFILE,".bun","bin","bun.exe"):void 0,n.LOCALAPPDATA?q.default.join(n.LOCALAPPDATA,"bun","bun.exe"):void 0,n.LOCALAPPDATA?q.default.join(n.LOCALAPPDATA,"bun","bin","bun.exe"):void 0]:[n.BUN,n.BUN_PATH,q.default.join(o,".bun","bin","bun"),"/usr/local/bin/bun","/opt/homebrew/bin/bun","/home/linuxbrew/.linuxbrew/bin/bun","/usr/bin/bun","/snap/bin/bun"];for(let u of c){let d=u?.trim();if(d&&(or(d)&&i(d)||d.toLowerCase()==="bun"))return d}return s("bun",e)}var ar=K(require("path"),1);var cr=require("fs");f();T();function zn(){return v.loadFromFile(re).OPENCODE_MEM_WORKER_HOST}function Qn(r){return r.startsWith("[")&&r.endsWith("]")?r:r.includes(":")?`[${r}]`:r}async function Zn(r,e,t="GET"){let n=await fetch(`http://${Qn(zn())}:${r}${e}`,{method:t}),o="";try{o=await n.text()}catch{}return{ok:n.ok,statusCode:n.status,body:o}}function eo(){try{let r=ar.default.join(ue,"package.json");return JSON.parse((0,cr.readFileSync)(r,"utf-8")).version}catch(r){if(r instanceof Error){let e=r.code;if(e==="ENOENT"||e==="EBUSY")return a.debug("SYSTEM","Could not read plugin version (shutdown race)",{code:e}),"unknown";throw r}throw r}}async function to(r){try{let e=await Zn(r,"/api/health");return e.ok?JSON.parse(e.body).version:null}catch{return a.debug("SYSTEM","Could not fetch worker version",{}),null}}async function ur(r){let e=eo(),t=await to(r);return!t||e==="unknown"?{matches:!0,pluginVersion:e,workerVersion:t}:{matches:e===t,pluginVersion:e,workerVersion:t}}f();var be=require("path"),R=require("fs");T();f();var ro=6e4;function lr(){return(0,be.join)(te(),"spawn.lock")}function dr(){let r=lr(),e=JSON.stringify({pid:process.pid,startedAt:new Date().toISOString()});for(let t=0;t<2;t++)try{return(0,R.mkdirSync)((0,be.dirname)(r),{recursive:!0}),(0,R.writeFileSync)(r,e,{flag:"wx"}),!0}catch(n){let o=n instanceof Error?n:new Error(String(n)),i=o.code;if(i!=="EEXIST")return a.warn("SYSTEM","Spawn lock write failed for a non-contention reason; failing open (spawning unlocked)",{lockPath:r,code:i},o),!0;if(t>0)return!1;let s;try{s=(0,R.statSync)(r).mtimeMs}catch{continue}if(Date.now()-s<=ro)return!1;let c;try{c=(0,R.statSync)(r).mtimeMs}catch{continue}if(c!==s)return!1;try{(0,R.unlinkSync)(r)}catch{return!1}}return!1}function pr(){let r=lr();try{if(JSON.parse((0,R.readFileSync)(r,"utf-8")).pid!==process.pid)return;(0,R.unlinkSync)(r)}catch{}}function Sr(r,e,t){let n=process.env[r];if(n){let o=parseInt(n,10);if(Number.isFinite(o)&&o>=t.min&&o<=t.max)return o;a.warn("SYSTEM",`Invalid ${r}, using default`,{value:n,min:t.min,max:t.max})}return e}var Le=Sr("OPENCODE_MEM_HEALTH_TIMEOUT_MS",B(k.HEALTH_CHECK),{min:500,max:3e5}),_r=Sr("OPENCODE_MEM_HOOK_READINESS_TIMEOUT_MS",B(k.HOOK_READINESS_WAIT),{min:0,max:3e5}),no={min:500,max:3e5};async function Ot(r,e={},t){try{return await fetch(r,{...e,signal:AbortSignal.timeout(t)})}catch(n){throw n instanceof DOMException&&n.name==="TimeoutError"?new Error(`Request timed out after ${t}ms`):n}}var Ie=null,De=null,Ne=null,Ae=null;function oo(){return M.default.join(v.get("OPENCODE_MEM_DATA_DIR"),"settings.json")}function Tt(){return Ne!==null||(Ne=v.loadFromFile(oo())),Ne}function fr(r,e){if(!r)return null;let t=parseInt(r,10);return Number.isFinite(t)&&t>=e.min&&t<=e.max?t:null}function so(r,e,t){let n=process.env[r];if(n!==void 0){let s=fr(n,t);return s!==null?s:(a.warn("SYSTEM",`Invalid ${r}, using default`,{value:n,min:t.min,max:t.max}),e)}let o=Tt()[r],i=fr(o,t);return i!==null?i:(a.warn("SYSTEM",`Invalid ${r} in settings.json, using default`,{value:o,min:t.min,max:t.max}),e)}function hr(){if(Ie!==null)return Ie;let r=Tt();return Ie=parseInt(r.OPENCODE_MEM_WORKER_PORT,10),Ie}function io(){return De!==null||(De=Tt().OPENCODE_MEM_WORKER_HOST),De}function ao(){return Ae!==null||(Ae=so("OPENCODE_MEM_API_TIMEOUT_MS",B(k.API_REQUEST),no)),Ae}function co(r){return r.startsWith("[")&&r.endsWith("]")?r:r.includes(":")?`[${r}]`:r}function uo(r){return`http://${co(io())}:${hr()}${r}`}function $(r,e={}){let t=e.method??"GET",n=e.timeoutMs??ao(),o=uo(r),i={method:t};return e.headers&&(i.headers=e.headers),e.body&&(i.body=e.body),n>0?Ot(o,i,n):fetch(o,i)}async function lo(){return(await $("/api/health",{timeoutMs:Le})).ok}async function Er(){return(await $("/api/readiness",{timeoutMs:Le})).ok}function Or(r){let e=(0,h.existsSync)(M.default.join(r,"plugin","scripts"))?M.default.join(r,"plugin"):r;return M.default.join(e,"scripts","worker-service.cjs")}function po(){let r=M.default.dirname(M.default.dirname(ue)),e=M.default.join(r,"cache","thedotmack","opencode-mem");try{return(0,h.readdirSync)(e).filter(t=>/^\d/.test(t)).map(t=>M.default.join(e,t)).filter(t=>{try{return(0,h.statSync)(t).isDirectory()}catch{return!1}}).sort((t,n)=>(0,h.statSync)(n).mtimeMs-(0,h.statSync)(t).mtimeMs).map(Or)}catch{return[]}}function fo(){let r=process.env.OPENCODE_MEM_WORKER_SCRIPT_PATH?.trim();if(r){if((0,h.existsSync)(r))return r;a.debug("SYSTEM","Ignoring missing OPENCODE_MEM_WORKER_SCRIPT_PATH override",{override:r})}let e=[...po(),Or(M.default.join(ue,"plugin")),M.default.join(process.cwd(),"plugin","scripts","worker-service.cjs")];for(let t of e)if((0,h.existsSync)(t))return t;return null}async function Eo(r){let e=r.backoffMs;for(let t=1;t<=r.attempts;t++){if(await yr())return!0;t<r.attempts&&(await new Promise(n=>setTimeout(n,e)),e*=2)}return!1}async function St(r=_r){if(r<=0)try{return await Er()}catch(t){let n=t instanceof Error?t:new Error(String(t));return a.debug("SYSTEM","Worker readiness check threw",{},n),!1}let e=Date.now();for(;Date.now()-e<r;){try{if(await Er())return!0}catch(n){a.debug("SYSTEM","Worker readiness check threw",{error:n instanceof Error?n.message:String(n)})}let t=r-(Date.now()-e);if(t<=0)break;await new Promise(n=>setTimeout(n,Math.min(250,t)))}return!1}async function Tr(){try{let e=await(await $("/api/health",{timeoutMs:Le})).json();return typeof e.version=="string"?e.version:null}catch(r){let e=r instanceof Error?r:new Error(String(r));return a.debug("SYSTEM","Worker health-version fetch failed",{},e),null}}async function mo(r,e=_r){let t=Date.now();for(;Date.now()-t<e;){if(await Tr()===r)return!0;let o=e-(Date.now()-t);if(o<=0)break;await new Promise(i=>setTimeout(i,Math.min(500,o)))}return!1}async function _t(r){let e=await Tr();e!==null&&e!==r&&a.warn("SYSTEM","Worker is ready but still reports a stale version; not recycling again in this hook invocation (one recycle per hook event)",{pluginVersion:r,workerVersion:e})}async function yr(){let r;try{r=await lo()}catch(t){return a.debug("SYSTEM","Worker health check threw",{error:t instanceof Error?t.message:String(t)}),!1}if(!r)return!1;let e=Re({logAlive:!1});return e==="missing"||e==="alive"}async function Fe(){let r=null;if(await yr()){let{matches:i,pluginVersion:s,workerVersion:c}=await ur(hr());if(s!=="unknown"&&(r=s),i)return await St()?(r!==null&&await _t(r),!0):(a.warn("SYSTEM","Worker is healthy but not ready; skipping hook API call"),!1);a.info("SYSTEM","Worker version mismatch \u2014 recycling stale worker",{pluginVersion:s,workerVersion:c});let u=!1;try{await $("/api/admin/restart",{method:"POST",timeoutMs:Le}),u=!0}catch(d){let l=d instanceof Error?d:new Error(String(d));a.debug("SYSTEM","Worker restart request failed; falling through to lazy-spawn",{},l)}if(u){if(await mo(s))return await St()?(r!==null&&await _t(r),!0):(a.warn("SYSTEM","Recycled worker appeared but did not become ready; skipping hook API call"),!1);a.warn("SYSTEM","No successor worker appeared after recycle; falling through to lazy-spawn",{pluginVersion:s,workerVersion:c})}}let e=ir(),t=fo();if(!e)return a.warn("SYSTEM","Cannot lazy-spawn worker: Bun runtime not found on PATH"),!1;if(!t)return a.warn("SYSTEM","Cannot lazy-spawn worker: worker-service.cjs not found in plugin/scripts"),!1;let n=dr();try{if(n){a.info("SYSTEM","Worker not running \u2014 lazy-spawning",{runtimePath:e,scriptPath:t});try{Te(e,[t,"--daemon"],{detached:!0,stdio:["ignore","ignore","ignore"]}).unref()}catch(s){return s instanceof Error?a.error("SYSTEM","Lazy-spawn of worker failed",{runtimePath:e,scriptPath:t},s):a.error("SYSTEM","Lazy-spawn of worker failed (non-Error)",{runtimePath:e,scriptPath:t,error:String(s)}),!1}}else a.info("SYSTEM","Another launcher holds the spawn lock \u2014 skipping lazy-spawn and waiting for its worker");if(!await Eo({attempts:6,backoffMs:500}))return a.warn("SYSTEM",n?"Worker port did not open after lazy-spawn within the cold-boot wait (~15s)":"Spawn-lock holder's worker port did not open within the cold-boot wait (~15s)"),!1}finally{n&&pr()}return await St()?(r!==null&&await _t(r),!0):(a.warn("SYSTEM","Worker lazy-spawned but did not become ready before hook readiness timeout"),!1)}var xe=null;async function go(){return xe!==null||(xe=await Fe()),xe}var So=3;function wr(){return M.default.join(S,"state")}function Pr(){return M.default.join(wr(),"hook-failures.json")}function _o(r){let e=JSON.parse(r);return{consecutiveFailures:typeof e.consecutiveFailures=="number"&&Number.isFinite(e.consecutiveFailures)?Math.max(0,Math.floor(e.consecutiveFailures)):0,lastFailureAt:typeof e.lastFailureAt=="number"&&Number.isFinite(e.lastFailureAt)?e.lastFailureAt:0}}function Mr(){try{return _o((0,h.readFileSync)(Pr(),"utf-8"))}catch{return{consecutiveFailures:0,lastFailureAt:0}}}function vr(r){let e=wr(),t=Pr(),n=`${t}.tmp`;try{(0,h.existsSync)(e)||(0,h.mkdirSync)(e,{recursive:!0}),(0,h.writeFileSync)(n,JSON.stringify(r),"utf-8"),(0,h.renameSync)(n,t)}catch(o){a.debug("SYSTEM","Failed to persist hook-failure counter",{error:o instanceof Error?o.message:String(o)})}}function ho(){try{let e=H().OPENCODE_MEM_HOOK_FAIL_LOUD_THRESHOLD,t=parseInt(e,10);if(Number.isFinite(t)&&t>=1)return t}catch{}return So}var mr=null;async function Oo(){let e={consecutiveFailures:Mr().consecutiveFailures+1,lastFailureAt:Date.now()};vr(e);let t=ho();return e.consecutiveFailures>=t&&(e.consecutiveFailures===t&&await nr("hook_failed",{...mr!==null?{hook_type:mr}:{},error_mode:"worker_unavailable",consecutive_failures:e.consecutiveFailures,threshold_tripped:!0}),Ct(`opencode-mem worker unreachable for ${e.consecutiveFailures} consecutive hooks.`)),e.consecutiveFailures}function gr(){Mr().consecutiveFailures!==0&&vr({consecutiveFailures:0,lastFailureAt:0})}var ht=Symbol.for("opencode-mem/worker-fallback");function We(r){return typeof r=="object"&&r!==null&&r[ht]===!0}async function He(r,e,t,n={}){if(!await go())return await Oo(),{continue:!0,reason:"worker_unreachable",[ht]:!0};let i={method:e};t!==void 0&&(i.headers={"Content-Type":"application/json"},i.body=JSON.stringify(t)),n.timeoutMs!==void 0&&(i.timeoutMs=n.timeoutMs);let s=await $(r,i);if(!s.ok){let u=await s.text().catch(()=>"");if(gr(),s.status===429||s.status>=500)return a.warn("SYSTEM",`Worker API ${e} ${r} returned ${s.status}; skipping hook API call`,{body:u.substring(0,200)}),{continue:!0,reason:`worker_api_${s.status}`,[ht]:!0};let d=u;try{d=JSON.parse(u)}catch{}return d}gr();let c=await s.text();if(c.length!==0)try{return JSON.parse(c)}catch{return c}}var Cr=require("os"),kr=K(require("path"),1),br=require("child_process");f();var Ue=require("fs"),ie=K(require("path"),1);f();var pe={isWorktree:!1,worktreeName:null,parentRepoPath:null,parentProjectName:null};function Rr(r){let e=ie.default.join(r,".git"),t;try{t=(0,Ue.statSync)(e)}catch(l){return l instanceof Error&&l.code!=="ENOENT"&&a.warn("GIT","Unexpected error checking .git",{error:l instanceof Error?l.message:String(l)}),pe}if(!t.isFile())return pe;let n;try{n=(0,Ue.readFileSync)(e,"utf-8").trim()}catch(l){return a.warn("GIT","Failed to read .git file",{error:l instanceof Error?l.message:String(l)}),pe}let o=n.match(/^gitdir:\s*(.+)$/);if(!o)return pe;let s=ie.default.resolve(ie.default.dirname(e),o[1]).match(/^(.+)[/\\]\.git[/\\]worktrees[/\\]([^/\\]+)$/);if(!s)return pe;let c=s[1],u=ie.default.basename(r),d=ie.default.basename(c);return{isWorktree:!0,worktreeName:u,parentRepoPath:c,parentProjectName:d}}function Ir(r){return r==="~"||r.startsWith("~/")?r.replace(/^~/,(0,Cr.homedir)()):r}function To(r){try{return(0,br.execFileSync)("git",["rev-parse","--show-toplevel"],{cwd:r,encoding:"utf-8",stdio:["ignore","pipe","ignore"]}).trim()||null}catch(e){let t=e instanceof Error?e:new Error(String(e));return a.debug("PROJECT_NAME","git rev-parse failed, falling back to basename",{dir:r},t),null}}function yo(r){if(!r||r.trim()==="")return a.warn("PROJECT_NAME","Empty cwd provided, using fallback",{cwd:r}),"unknown-project";let e=Ir(r),n=To(e)??e,o=kr.default.basename(n);if(o===""){if(process.platform==="win32"){let s=r.match(/^([A-Z]):\\/i);if(s){let u=`drive-${s[1].toUpperCase()}`;return a.info("PROJECT_NAME","Drive root detected",{cwd:r,projectName:u}),u}}return a.warn("PROJECT_NAME","Root directory detected, using fallback",{cwd:r}),"unknown-project"}return o}function z(r){let e=yo(r);if(!r)return{primary:e,parent:null,isWorktree:!1,allProjects:[e]};let t=Ir(r),n=Rr(t);if(n.isWorktree&&n.parentProjectName){let o=`${n.parentProjectName}/${e}`;return{primary:o,parent:n.parentProjectName,isWorktree:!0,allProjects:[n.parentProjectName,o]}}return{primary:e,parent:null,isWorktree:!1,allProjects:[e]}}f();var Q=require("path");var Dr=require("os"),Nr=require("path");f();function wo(r){let e=r.startsWith("~")?(0,Dr.homedir)()+r.slice(1):r;e=e.replace(/\\/g,"/");let t=e.replace(/[.+^${}()|[\]\\]/g,"\\$&");return t=t.replace(/\*\*/g,"<<<GLOBSTAR>>>").replace(/\*/g,"[^/]*").replace(/\?/g,"[^/]").replace(/<<<GLOBSTAR>>>/g,".*"),new RegExp(`^${t}$`)}function $e(r,e){if(!e||!e.trim())return!1;let t=r.replace(/\\/g,"/"),n=(0,Nr.basename)(t),o=e.split(",").map(i=>i.trim()).filter(Boolean);for(let i of o)try{let s=wo(i);if(s.test(t)||s.test(n))return!0}catch(s){a.warn("PROJECT_NAME","Invalid exclusion pattern",{pattern:i,error:s instanceof Error?s.message:String(s)});continue}return!1}T();function Po(r,e){let t=(0,Q.normalize)(r),n=(0,Q.normalize)(e);if(t===n)return!0;let o=(0,Q.relative)(n,t);return o.length>0&&!o.startsWith("..")&&!(0,Q.isAbsolute)(o)}function je(r){if(process.env.OPENCODE_MEM_INTERNAL==="1")return!1;if(!r)return!0;if(Po(r,ze))return!1;let e=H();return!$e(r,e.OPENCODE_MEM_EXCLUDED_PROJECTS)}var Ar="claude";function Mo(r){return r.trim().toLowerCase().replace(/\s+/g,"-")}function x(r){if(!r)return Ar;let e=Mo(r);return e?e==="transcript"||e.includes("codex")?"codex":e.includes("cursor")?"cursor":e.includes("claude")?"claude":e:Ar}f();var Fr=["private","opencode-mem-context","system_instruction","system-instruction","persisted-output","system-reminder"],xr=new RegExp(`<(${Fr.join("|")})\\b[^>]*>[\\s\\S]*?</\\1>`,"g");var Lr=100;function vo(r){let e=Object.fromEntries(Fr.map(o=>[o,0]));xr.lastIndex=0;let t=0,n=r.replace(xr,(o,i)=>(e[i]=(e[i]??0)+1,t+=1,""));return t>Lr&&a.warn("SYSTEM","tag count exceeds limit",void 0,{tagCount:t,maxAllowed:Lr,contentLength:r.length}),{stripped:n.trim(),counts:e}}function yt(r){return vo(r).stripped}var Ro=["task-notification"],Co=new RegExp(`^\\s*<(${Ro.join("|")})\\b[^>]*>(?:(?!<\\1\\b|</\\1\\b)[\\s\\S])*</\\1>\\s*$`),ko=256*1024;function Wr(r){return!r||r.length>ko?!1:Co.test(r)}f();var bo=B(k.API_REQUEST),j=class extends Error{kind;status;cause;constructor(e,t,n={}){super(t),this.name="ServerClientError",this.kind=e,this.status=n.status??null,this.cause=n.cause}isFallbackEligible(){return this.kind==="transport"||this.kind==="timeout"||this.kind==="missing_api_key"||this.kind==="http_error"&&(this.status!==null&&this.status>=500||this.status===429)}},Ge=class{baseUrl;apiKey;timeoutMs;constructor(e){this.baseUrl=Io(e.serverBaseUrl),this.apiKey=e.apiKey,this.timeoutMs=e.timeoutMs??bo}async startSession(e){let t=this.buildStartSessionPayload(e);return this.request("POST","/v1/sessions/start",t)}async recordEvent(e){let t=this.buildEventPayload(e),n=e.generate===!1?"/v1/events?generate=false":"/v1/events";return this.request("POST",n,t)}async endSession(e){if(!e.sessionId)throw new j("invalid_response","sessionId is required for endSession");return this.request("POST",`/v1/sessions/${encodeURIComponent(e.sessionId)}/end`,{})}async addObservation(e){return this.request("POST","/v1/memories",this.buildAddObservationPayload(e))}async searchObservations(e){return this.request("POST","/v1/search",this.buildSearchPayload(e))}async contextObservations(e){return this.request("POST","/v1/context",this.buildSearchPayload(e))}async getJobStatus(e){if(!e)throw new j("invalid_response","jobId is required for getJobStatus");return this.request("GET",`/v1/jobs/${encodeURIComponent(e)}`)}buildAddObservationPayload(e){let t=e.content,n=e.kind??"manual",o=typeof e.metadata?.title=="string"?e.metadata.title:void 0;return{projectId:e.projectId,kind:n,type:n,narrative:t,...o?{title:o}:{},...e.serverSessionId!==void 0?{serverSessionId:e.serverSessionId}:{},...e.metadata!==void 0?{metadata:e.metadata}:{}}}buildSearchPayload(e){return{projectId:e.projectId,query:e.query,...e.limit!==void 0?{limit:e.limit}:{},...e.platformSource!==void 0?{platformSource:wt(e.platformSource)}:{}}}buildStartSessionPayload(e){return{projectId:e.projectId,...e.externalSessionId!==void 0?{externalSessionId:e.externalSessionId}:{},...e.contentSessionId!==void 0?{contentSessionId:e.contentSessionId}:{},...e.agentId!==void 0?{agentId:e.agentId}:{},...e.agentType!==void 0?{agentType:e.agentType}:{},...e.platformSource!==void 0?{platformSource:wt(e.platformSource)}:{},...e.metadata!==void 0?{metadata:e.metadata}:{}}}buildEventPayload(e){return{projectId:e.projectId,sourceType:e.sourceType,eventType:e.eventType,occurredAtEpoch:e.occurredAtEpoch,...e.serverSessionId!==void 0?{serverSessionId:e.serverSessionId}:{},...e.contentSessionId!==void 0?{contentSessionId:e.contentSessionId}:{},...e.memorySessionId!==void 0?{memorySessionId:e.memorySessionId}:{},...e.platformSource!==void 0?{platformSource:wt(e.platformSource)}:{},...e.payload!==void 0?{payload:e.payload}:{}}}async request(e,t,n){if(!this.apiKey||!this.apiKey.trim())throw new j("missing_api_key","Server API key is not configured (OPENCODE_MEM_SERVER_API_KEY).");let o=`${this.baseUrl}${t}`,i={method:e,headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`}};n!==void 0&&(i.body=JSON.stringify(n));let s;try{s=await Ot(o,i,this.timeoutMs)}catch(u){let d=u instanceof Error?u.message:String(u),l=/timed out|timeout/i.test(d);throw new j(l?"timeout":"transport",`Server ${e} ${t} failed: ${d}`,{cause:u})}if(!s.ok){let u=await s.text().catch(()=>"");throw new j("http_error",`Server ${e} ${t} returned ${s.status}: ${Do(u,200)}`,{status:s.status})}let c=await s.text();if(!c||c.length===0)return{};try{return JSON.parse(c)}catch(u){let d=u instanceof Error?u:new Error(String(u));throw new j("invalid_response",`Server ${e} ${t} returned non-JSON response`,{cause:d})}}};function Hr(r){return r instanceof j}function Io(r){return r.replace(/\/+$/,"")}function wt(r){return typeof r=="string"?x(r):null}function Do(r,e){return r.length<=e?r:`${r.slice(0,e)}\u2026`}function No(){let e=(H().OPENCODE_MEM_RUNTIME??"worker").trim().toLowerCase();return e==="server"||e==="server-beta"?"server":"worker"}function Ao(){let r=H(),e=(...s)=>{for(let c of s){let u=(c??"").trim();if(u.length>0)return u}return""},t=e(r.OPENCODE_MEM_SERVER_URL,r.OPENCODE_MEM_SERVER_BETA_URL),n=e(r.OPENCODE_MEM_SERVER_API_KEY,r.OPENCODE_MEM_SERVER_BETA_API_KEY),o=e(r.OPENCODE_MEM_SERVER_PROJECT_ID,r.OPENCODE_MEM_SERVER_BETA_PROJECT_ID);if(!t)return a.warn("HOOK","[server-fallback] reason=missing_base_url"),null;if(!n)return a.warn("HOOK","[server-fallback] reason=missing_api_key"),null;if(!o)return a.warn("HOOK","[server-fallback] reason=missing_project_id"),null;let i={serverBaseUrl:t,apiKey:n};return{runtime:"server",client:new Ge(i),projectId:o,serverBaseUrl:t}}function Ur(){if(No()!=="server")return{runtime:"worker"};let r=Ao();return r||{runtime:"worker"}}function $r(r,e){a.warn("HOOK",`[server-fallback] reason=${r}`,e??{})}var xo={executeWithWorkerFallback:He,isWorkerFallback:We,loadFromFileOnce:H,resolveRuntimeContext:Ur,logServerFallback:$r,shouldTrackProject:je},J=xo;var jr={async execute(r){let{sessionId:e,prompt:t}=r,n=r.cwd??process.cwd();if(!e)return a.warn("HOOK","session-init: No sessionId provided, skipping (Codex CLI or unknown platform)"),{continue:!0,suppressOutput:!0,exitCode:Y.SUCCESS};if(!J.shouldTrackProject(n))return a.info("HOOK","Project excluded from tracking",{cwd:n}),{continue:!0,suppressOutput:!0};if(t&&Wr(t))return a.debug("HOOK","session-init: skipping internal protocol payload",{preview:t.slice(0,80)}),{continue:!0,suppressOutput:!0};let o=!t||!t.trim()?"[media prompt]":t,i=z(n).primary,s=x(r.platform),c=J.loadFromFileOnce(),u=String(c.OPENCODE_MEM_SEMANTIC_INJECT).toLowerCase()==="true",d=J.resolveRuntimeContext();if(d.runtime==="server")try{return await Lo(d,r,e,s,i,o),{continue:!0,suppressOutput:!0}}catch(g){if(Hr(g)&&g.isFallbackEligible())J.logServerFallback(g.kind,{status:g.status,message:g.message,route:"/v1/sessions/start"});else return a.error("HOOK","Server session-start failed (non-recoverable)",{error:g instanceof Error?g.message:String(g)}),{continue:!0,suppressOutput:!0,exitCode:Y.SUCCESS}}a.debug("HOOK","session-init: Calling /api/sessions/init",{contentSessionId:e,project:i});let l=await J.executeWithWorkerFallback("/api/sessions/init","POST",{contentSessionId:e,project:i,prompt:o,platformSource:s});if(J.isWorkerFallback(l))return{continue:!0,suppressOutput:!0,exitCode:Y.SUCCESS};if(typeof l?.sessionDbId!="number")return a.failure("HOOK","Session initialization returned malformed response",{contentSessionId:e,project:i}),{continue:!0,suppressOutput:!0,exitCode:Y.SUCCESS};let _=l.sessionDbId,m=l.promptNumber;if(a.debug("HOOK","session-init: Received from /api/sessions/init",{sessionDbId:_,promptNumber:m,skipped:l.skipped,contextInjected:l.contextInjected}),a.debug("HOOK",`[ALIGNMENT] Hook Entry | contentSessionId=${e} | prompt#=${m} | sessionDbId=${_}`),l.skipped&&l.reason==="private")return a.info("HOOK",`INIT_COMPLETE | sessionDbId=${_} | promptNumber=${m} | skipped=true | reason=private`,{sessionId:_}),{continue:!0,suppressOutput:!0};let y="";if(u&&o&&o.length>=20&&o!=="[media prompt]"){let g=c.OPENCODE_MEM_SEMANTIC_INJECT_LIMIT||"5",G=await J.executeWithWorkerFallback("/api/context/semantic","POST",{q:o,project:i,limit:g,platformSource:s});!J.isWorkerFallback(G)&&G?.context&&(a.debug("HOOK",`Semantic injection: ${G.count} observations for prompt`,{sessionId:_,count:G.count}),y=G.context)}return a.info("HOOK",`INIT_COMPLETE | sessionDbId=${_} | promptNumber=${m} | project=${i}`,{sessionId:_}),y?{continue:!0,suppressOutput:!0,hookSpecificOutput:{hookEventName:"UserPromptSubmit",additionalContext:y}}:{continue:!0,suppressOutput:!0}}};async function Lo(r,e,t,n,o,i){await r.client.startSession({projectId:r.projectId,externalSessionId:t,contentSessionId:t,agentId:e.agentId??null,agentType:e.agentType??null,platformSource:n,metadata:{project:o,prompt:i}}),a.info("HOOK","session-init: server session started",{contentSessionId:t,project:o})}f();var Gr={async execute(r){let{sessionId:e,cwd:t,filePath:n,edits:o}=r,i=x(r.platform);if(!n)throw new Error("fileEditHandler requires filePath");if(a.dataIn("HOOK",`FileEdit: ${n}`,{editCount:o?.length??0}),!t)throw new Error(`Missing cwd in FileEdit hook input for session ${e}, file ${n}`);if(!je(t))return a.debug("HOOK","Project excluded from tracking, skipping file edit observation",{cwd:t,filePath:n}),{continue:!0,suppressOutput:!0,exitCode:Y.SUCCESS};let s=await He("/api/sessions/observations","POST",{contentSessionId:e,platformSource:i,tool_name:"write_file",tool_input:{filePath:n,edits:o},tool_response:{success:!0},cwd:t});return We(s)?{continue:!0,suppressOutput:!0,exitCode:Y.SUCCESS}:(a.debug("HOOK","File edit observation sent successfully",{filePath:n}),{continue:!0,suppressOutput:!0})}};T();f();var b=require("fs"),Ke=require("path");f();f();T();var ka=O.settings();function Kr(r,e){let t="<opencode-mem-context>",n="</opencode-mem-context>";if(!r)return`${t}
|
|
18
|
+
${e}
|
|
19
|
+
${n}`;let o=r.indexOf(t),i=r.indexOf(n);return o!==-1&&i!==-1?r.substring(0,o)+`${t}
|
|
20
|
+
${e}
|
|
21
|
+
${n}`+r.substring(i+n.length):r+`
|
|
22
|
+
|
|
23
|
+
${t}
|
|
24
|
+
${e}
|
|
25
|
+
${n}`}f();function Yr(r,e){if(!r)return;let t=(0,Ke.resolve)(r);if(t.includes("/.git/")||t.includes("\\.git\\")||t.endsWith("/.git")||t.endsWith("\\.git"))return;let n=(0,Ke.dirname)(r);(0,b.existsSync)(n)||(0,b.mkdirSync)(n,{recursive:!0});let o="";(0,b.existsSync)(r)&&(o=(0,b.readFileSync)(r,"utf-8"));let i=`# Memory Context
|
|
26
|
+
|
|
27
|
+
${e}`,s=Kr(o,i),c=`${r}.tmp`;try{(0,b.writeFileSync)(c,s),(0,b.renameSync)(c,r)}catch(u){a.error("AGENTS_MD","Failed to write AGENTS.md",{agentsPath:r},u instanceof Error?u:new Error(String(u)))}}f();function Fo(r){let e=r.trim().replace(/^\$\.?/,"");if(!e)return[];let t=[],n=e.split(".");for(let o of n){let i=/([^[\]]+)|\[(\d+)\]/g,s;for(;(s=i.exec(o))!==null;)s[1]?t.push(s[1]):s[2]&&t.push(parseInt(s[2],10))}return t}function Pt(r,e){if(!e)return;let t=Fo(e),n=r;for(let o of t){if(n==null)return;n=n[o]}return n}function Br(r){return r==null||r===""}function Jr(r,e){if(r.startsWith("$watch.")){let t=r.slice(7);return e.watch[t]}if(r.startsWith("$schema.")){let t=r.slice(8);return e.schema[t]}if(r.startsWith("$session.")){let t=r.slice(9);return e.session?e.session[t]:void 0}if(r==="$cwd")return e.watch.workspace;if(r==="$project")return e.watch.project}function ae(r,e,t){if(r!==void 0){if(typeof r=="string"){let n=Jr(r,t);return n!==void 0?n:Pt(e,r)}if(r.coalesce&&Array.isArray(r.coalesce))for(let n of r.coalesce){let o=ae(n,e,t);if(!Br(o))return o}if(r.path){let n=Jr(r.path,t);if(n!==void 0)return n;let o=Pt(e,r.path);if(!Br(o))return o}if(r.value!==void 0)return r.value;if(r.default!==void 0)return r.default}}function Vr(r,e,t){let n={};if(!r)return n;for(let[o,i]of Object.entries(r))n[o]=ae(i,e,t);return n}function Xr(r,e,t){if(!e)return!0;let n=e.path||t.eventTypePath||"type",o=n?Pt(r,n):void 0,i=o==null||o==="";if(e.exists!==void 0&&(e.exists&&i||!e.exists&&!i)||e.equals!==void 0&&o!==e.equals||e.not_equals!==void 0&&o===e.not_equals||e.in&&Array.isArray(e.in)&&!e.in.includes(o)||e.not_in&&Array.isArray(e.not_in)&&e.not_in.includes(o)||e.contains!==void 0&&(typeof o!="string"||!o.includes(e.contains))||e.not_contains!==void 0&&typeof o=="string"&&o.includes(e.not_contains))return!1;if(e.regex)try{if(!new RegExp(e.regex).test(String(o??"")))return!1}catch(s){return a.debug("WORKER","Invalid regex in match rule",{regex:e.regex},s instanceof Error?s:void 0),!1}return!0}f();T();f();var Ye=class{static checkUserPromptPrivacy(e,t,n,o,i,s){let c=e.getUserPrompt(t,n,i);return c===null?(a.warn("HOOK",`${o}: no user_prompts row for prompt #${n} \u2014 ingesting anyway (session-init likely raced worker boot; see #2794/#2795)`,{sessionId:i,contentSessionId:t,promptNumber:n,...s}),{allow:!0,prompt:""}):c.trim()===""?(a.debug("HOOK",`Skipping ${o} - user prompt was entirely private`,{sessionId:i,promptNumber:n,...s}),{allow:!1,reason:"private"}):{allow:!0,prompt:c}}};var qr=null;function Wo(){if(!qr)throw new Error("ingest helpers used before setIngestContext() \u2014 wiring bug");return qr}async function zr(r){let{sessionManager:e,dbManager:t,eventBroadcaster:n,ensureGeneratorRunning:o}=Wo(),i=x(r.platformSource),s=typeof r.cwd=="string"?r.cwd:"",c=s.trim()?z(s).primary:"",u=v.loadFromFile(re);if(s&&$e(s,u.OPENCODE_MEM_EXCLUDED_PROJECTS))return{ok:!0,status:"skipped",reason:"project_excluded"};if(new Set(u.OPENCODE_MEM_SKIP_TOOLS.split(",").map(C=>C.trim()).filter(Boolean)).has(r.toolName))return{ok:!0,status:"skipped",reason:"tool_excluded"};if(new Set(["Edit","Write","Read","NotebookEdit"]).has(r.toolName)&&r.toolInput&&typeof r.toolInput=="object"){let C=r.toolInput,V=C.file_path||C.notebook_path;if(V&&V.includes("session-memory"))return{ok:!0,status:"skipped",reason:"session_memory_meta"}}let _=t.getSessionStore(),m,y;try{m=_.createSDKSession(r.contentSessionId,c,"",void 0,i),y=_.getPromptNumberFromUserPrompts(r.contentSessionId,m)}catch(C){let V=C instanceof Error?C.message:String(C);return a.error("INGEST","Observation session resolution failed",{contentSessionId:r.contentSessionId,toolName:r.toolName},C instanceof Error?C:new Error(V)),{ok:!1,reason:V,status:500}}if(!Ye.checkUserPromptPrivacy(_,r.contentSessionId,y,"observation",m,{tool_name:r.toolName}).allow)return{ok:!0,status:"skipped",reason:"private"};let G=r.toolInput!==void 0?yt(JSON.stringify(r.toolInput)):"{}",Ee=r.toolResponse!==void 0?yt(JSON.stringify(r.toolResponse)):"{}";return await e.queueObservation(m,{tool_name:r.toolName,tool_input:G,tool_response:Ee,prompt_number:y,cwd:s||(a.error("INGEST","Missing cwd when ingesting observation",{sessionId:m,toolName:r.toolName}),""),agentId:typeof r.agentId=="string"?r.agentId:void 0,agentType:typeof r.agentType=="string"?r.agentType:void 0,toolUseId:typeof r.toolUseId=="string"?r.toolUseId:void 0}),await o?.(m,"observation"),n.broadcastObservationQueued(m),{ok:!0,sessionDbId:m}}var Be=class{sessions=new Map;async processEntry(e,t,n,o){for(let i of n.events)Xr(e,i.match,n)&&await this.handleEvent(e,t,n,i,o??void 0)}getSessionKey(e,t){return`${e.name}:${t}`}getOrCreateSession(e,t){let n=this.getSessionKey(e,t),o=this.sessions.get(n);return o||(o={sessionId:t,platformSource:x(e.name)},this.sessions.set(n,o)),o}resolveSessionId(e,t,n,o,i){let s={watch:t,schema:n},c=o.fields?.sessionId??(n.sessionIdPath?{path:n.sessionIdPath}:void 0),u=ae(c,e,s);return typeof u=="string"&&u.trim()?u:typeof u=="number"?String(u):i&&i.trim()?i:null}resolveCwd(e,t,n,o,i){let s={watch:t,schema:n,session:i},c=o.fields?.cwd??(n.cwdPath?{path:n.cwdPath}:void 0),u=ae(c,e,s);return typeof u=="string"&&u.trim()?u:t.workspace?t.workspace:i.cwd}resolveProject(e,t,n,o,i){let s={watch:t,schema:n,session:i},c=o.fields?.project??(n.projectPath?{path:n.projectPath}:void 0),u=ae(c,e,s);return typeof u=="string"&&u.trim()?u:t.project?t.project:i.cwd?z(i.cwd).primary:i.project}async handleEvent(e,t,n,o,i){let s=this.resolveSessionId(e,t,n,o,i);if(!s){a.debug("TRANSCRIPT","Skipping event without sessionId",{event:o.name,watch:t.name});return}let c=this.getOrCreateSession(t,s),u=this.resolveCwd(e,t,n,o,c);u&&(c.cwd=u);let d=this.resolveProject(e,t,n,o,c);d&&(c.project=d);let l=Vr(o.fields,e,{watch:t,schema:n,session:c});switch(o.action){case"session_context":this.applySessionContext(c,l);break;case"session_init":await this.handleSessionInit(c,l),t.context?.updateOn?.includes("session_start")&&await this.updateContext(c,t);break;case"user_message":typeof l.message=="string"&&(c.lastUserMessage=l.message),typeof l.prompt=="string"&&(c.lastUserMessage=l.prompt);break;case"assistant_message":typeof l.message=="string"&&(c.lastAssistantMessage=l.message);break;case"tool_use":await this.handleToolUse(c,l);break;case"tool_result":await this.handleToolResult(c,l);break;case"observation":await this.sendObservation(c,l);break;case"file_edit":await this.sendFileEdit(c,l);break;case"session_end":await this.handleSessionEnd(c,t);break;default:break}}applySessionContext(e,t){let n=typeof t.cwd=="string"?t.cwd:void 0,o=typeof t.project=="string"?t.project:void 0;n&&(e.cwd=n),o&&(e.project=o)}async handleSessionInit(e,t){let n=typeof t.prompt=="string"?t.prompt:"",o=e.cwd??process.cwd();n&&(e.lastUserMessage=n),await jr.execute({sessionId:e.sessionId,cwd:o,prompt:n,platform:e.platformSource})}async handleToolUse(e,t){let n=typeof t.toolId=="string"?t.toolId:void 0,o=typeof t.toolName=="string"?t.toolName:void 0,i=this.maybeParseJson(t.toolInput),s=this.maybeParseJson(t.toolResponse);if(o==="apply_patch"&&typeof i=="string"){let c=this.parseApplyPatchFiles(i);for(let u of c)await this.sendFileEdit(e,{filePath:u,edits:[{type:"apply_patch",patch:i}]})}o&&s!==void 0?await this.sendObservation(e,{toolName:o,toolInput:i,toolResponse:s,toolUseId:n}):o&&n&&(e.pendingTools||(e.pendingTools=new Map),e.pendingTools.set(n,{toolName:o,toolInput:i}))}async handleToolResult(e,t){let n=typeof t.toolId=="string"?t.toolId:void 0,o=typeof t.toolName=="string"?t.toolName:void 0,i=this.maybeParseJson(t.toolResponse),s=this.maybeParseJson(t.toolInput);if(n&&e.pendingTools){let c=e.pendingTools.get(n);c&&(o||(o=c.toolName),s===void 0&&(s=c.toolInput),e.pendingTools.delete(n))}o?await this.sendObservation(e,{toolName:o,toolInput:s,toolResponse:i,toolUseId:n}):a.debug("TRANSCRIPT","Dropping tool_result with no resolvable toolName",{sessionId:e.sessionId,toolId:n})}async sendObservation(e,t){let n=typeof t.toolName=="string"?t.toolName:void 0;if(!n)return;let o=await zr({contentSessionId:e.sessionId,cwd:e.cwd??process.cwd(),toolName:n,toolInput:this.maybeParseJson(t.toolInput),toolResponse:this.maybeParseJson(t.toolResponse),platformSource:e.platformSource,toolUseId:typeof t.toolUseId=="string"?t.toolUseId:void 0});if(!o.ok)throw new Error(`ingestObservation failed: ${o.reason}`)}async sendFileEdit(e,t){let n=typeof t.filePath=="string"?t.filePath:void 0;n&&await Gr.execute({sessionId:e.sessionId,cwd:e.cwd??process.cwd(),filePath:n,edits:Array.isArray(t.edits)?t.edits:void 0,platform:e.platformSource})}maybeParseJson(e){if(typeof e!="string")return e;let t=e.trim();if(!t||!(t.startsWith("{")||t.startsWith("[")))return e;try{return JSON.parse(t)}catch(n){return a.debug("TRANSCRIPT","Field looked like JSON but did not parse; using raw string",{preview:t.slice(0,120)},n instanceof Error?n:void 0),e}}parseApplyPatchFiles(e){let t=[],n=e.split(`
|
|
28
|
+
`);for(let o of n){let i=o.trim();if(i.startsWith("*** Update File: "))t.push(i.replace("*** Update File: ","").trim());else if(i.startsWith("*** Add File: "))t.push(i.replace("*** Add File: ","").trim());else if(i.startsWith("*** Delete File: "))t.push(i.replace("*** Delete File: ","").trim());else if(i.startsWith("*** Move to: "))t.push(i.replace("*** Move to: ","").trim());else if(i.startsWith("+++ ")){let s=i.replace("+++ ","").replace(/^b\//,"").trim();s&&s!=="/dev/null"&&t.push(s)}}return Array.from(new Set(t))}async handleSessionEnd(e,t){await this.queueSummary(e),await this.updateContext(e,t),e.pendingTools?.clear();let n=this.getSessionKey(t,e.sessionId);this.sessions.delete(n)}async queueSummary(e){if(!await Fe())return;let n=e.lastAssistantMessage??"",o=JSON.stringify({contentSessionId:e.sessionId,last_assistant_message:n,platformSource:e.platformSource});try{await $("/api/sessions/summarize",{method:"POST",headers:{"Content-Type":"application/json"},body:o})}catch(i){a.warn("TRANSCRIPT","Summary request failed",{error:i instanceof Error?i.message:String(i)})}}async updateContext(e,t){if(!t.context||t.context.mode!=="agents"||It(t)||!await Fe())return;let o=e.cwd??t.workspace;if(!o)return;let s=z(o).allProjects.join(","),c=`/api/context/inject?projects=${encodeURIComponent(s)}&platformSource=${encodeURIComponent(e.platformSource)}`,u=P(t.context.path??`${o}/AGENTS.md`),d=fe.default.resolve(u),l=[fe.default.resolve(o),fe.default.resolve(S)];if(!l.some(g=>d.startsWith(g+fe.default.sep)||d===g)){a.warn("SECURITY","Rejected path traversal attempt in watch.context.path",{original:t.context.path,resolved:d,allowedRoots:l});return}let m;try{m=await $(c)}catch(g){a.warn("TRANSCRIPT","Failed to fetch AGENTS.md context",{error:g instanceof Error?g.message:String(g)});return}if(!m.ok)return;let y=(await m.text()).trim();y&&(Yr(u,y),a.debug("TRANSCRIPT","Updated AGENTS.md context",{agentsPath:u,watch:t.name}))}};var Mt=class{constructor(e,t,n,o){this.filePath=e;this.onLine=n;this.onOffset=o;this.tailState={offset:t,partial:""}}filePath;onLine;onOffset;watcher=null;tailState;start(){this.readNewData().catch(()=>{}),this.watcher=(0,w.watch)(this.filePath,{persistent:!0},()=>{this.readNewData().catch(()=>{})})}close(){this.watcher?.close(),this.watcher=null}poke(){this.readNewData().catch(()=>{})}async readNewData(){if(!(0,w.existsSync)(this.filePath))return;let e=0;try{e=(0,w.statSync)(this.filePath).size}catch(s){a.debug("WORKER","Failed to stat transcript file",{file:this.filePath},s instanceof Error?s:void 0);return}if(e<this.tailState.offset&&(this.tailState.offset=0),e===this.tailState.offset)return;let t=(0,w.createReadStream)(this.filePath,{start:this.tailState.offset,end:e-1,encoding:"utf8"}),n="";for await(let s of t)n+=s;this.tailState.offset=e,this.onOffset(this.tailState.offset);let i=(this.tailState.partial+n).split(`
|
|
29
|
+
`);this.tailState.partial=i.pop()??"";for(let s of i){let c=s.trim();c&&await this.onLine(c)}}},Je=class{constructor(e,t){this.config=e;this.statePath=t;this.state=At(t)}config;statePath;processor=new Be;tailers=new Map;state;rootWatchers=[];async start(){for(let e of this.config.watches)await this.setupWatch(e)}stop(){for(let e of this.tailers.values())e.close();this.tailers.clear();for(let e of this.rootWatchers)e.close();this.rootWatchers=[]}async setupWatch(e){let t=this.resolveSchema(e);if(!t){a.warn("TRANSCRIPT","Missing schema for watch",{watch:e.name});return}let n=P(e.path),o=this.resolveWatchFiles(n);for(let s of o)await this.addTailer(s,e,t);let i=this.deepestNonGlobAncestor(n);if(!i||!(0,w.existsSync)(i)){a.debug("TRANSCRIPT","Watch root does not exist, skipping fs.watch",{watch:e.name,watchRoot:i});return}try{let s=(0,w.watch)(i,{recursive:!0,persistent:!0},(c,u)=>{this.handleRootWatchEvent(i,n,e,t,u)});this.rootWatchers.push(s),a.info("TRANSCRIPT","Watching transcript root recursively",{watch:e.name,watchRoot:i})}catch(s){a.warn("TRANSCRIPT","Failed to start recursive fs.watch on transcript root",{watch:e.name,watchRoot:i},s instanceof Error?s:void 0)}}handleRootWatchEvent(e,t,n,o,i){if(!i)return;let s=(0,I.resolve)(e,i).replace(/\\/g,"/"),c=this.tailers.get(s);if(c){c.poke();return}let u=this.resolveWatchFiles(t);for(let d of u)this.tailers.has(d)||this.addTailer(d,n,o)}deepestNonGlobAncestor(e){if(!this.hasGlob(e)){if((0,w.existsSync)(e))try{return(0,w.statSync)(e).isDirectory()?e:(0,I.resolve)(e,"..")}catch(o){return a.debug("TRANSCRIPT","Failed to stat watch path ancestor, falling back to parent directory",{path:e},o instanceof Error?o:new Error(String(o))),(0,I.resolve)(e,"..")}return e}let t=e.split(/[/\\]/),n=[];for(let o of t){if(/[*?[\]{}()]/.test(o))break;n.push(o)}return n.length===0||n.length===1&&n[0]===""?"":n.join(I.sep)}resolveSchema(e){return typeof e.schema=="string"?this.config.schemas?.[e.schema]??null:e.schema}resolveWatchFiles(e){if(this.hasGlob(e))return this.scanGlob(this.normalizeGlobPattern(e));if((0,w.existsSync)(e))try{if((0,w.statSync)(e).isDirectory()){let n=(0,I.join)(e,"**","*.jsonl");return this.scanGlob(this.normalizeGlobPattern(n))}return[e]}catch(t){return a.debug("WORKER","Failed to stat watch path",{path:e},t instanceof Error?t:void 0),[]}return[]}scanGlob(e){return Array.from(new Bun.Glob(e).scanSync({absolute:!0,onlyFiles:!0}))}normalizeGlobPattern(e){return e.replace(/\\/g,"/")}hasGlob(e){return/[*?[\]{}()]/.test(e)}async addTailer(e,t,n){if(this.tailers.has(e))return;let o=this.extractSessionIdFromPath(e),i=this.state.offsets[e]??0;if(i===0&&t.startAtEnd)try{i=(0,w.statSync)(e).size}catch(c){a.debug("WORKER","Failed to stat file for startAtEnd offset",{file:e},c instanceof Error?c:void 0),i=0}let s=new Mt(e,i,async c=>{await this.handleLine(c,t,n,e,o)},c=>{this.state.offsets[e]=c,xt(this.statePath,this.state)});s.start(),this.tailers.set(e,s),a.info("TRANSCRIPT","Watching transcript file",{file:e,watch:t.name,schema:n.name})}async handleLine(e,t,n,o,i){try{let s=JSON.parse(e);await this.processor.processEntry(s,t,n,i??void 0)}catch(s){s instanceof Error?a.debug("TRANSCRIPT","Failed to parse transcript line",{watch:t.name,file:(0,I.basename)(o)},s):a.warn("TRANSCRIPT","Failed to parse transcript line (non-Error thrown)",{watch:t.name,file:(0,I.basename)(o),error:String(s)})}}extractSessionIdFromPath(e){let t=e.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i);return t?t[0]:null}};function vt(r,e){let t=r.indexOf(e);return t===-1?null:r[t+1]??null}async function Qr(r,e){switch(r){case"init":{let t=vt(e,"--config")??ne;return Oe(t),console.log(`Created sample config: ${P(t)}`),0}case"watch":{let t=vt(e,"--config")??ne,n;try{n=de(t)}catch(c){if(c instanceof Error&&c.message.includes("not found"))Oe(t),console.log(`Created sample config: ${P(t)}`),n=de(t);else throw c}let o=P(n.stateFile??he),i=new Je(n,o);await i.start(),console.log("Transcript watcher running. Press Ctrl+C to stop.");let s=()=>{i.stop(),process.exit(0)};return process.on("SIGINT",s),process.on("SIGTERM",s),await new Promise(()=>{})}case"validate":{let t=vt(e,"--config")??ne;try{de(t)}catch(n){if(n instanceof Error&&n.message.includes("not found"))Oe(t),console.log(`Created sample config: ${P(t)}`),de(t);else throw n}return console.log(`Config OK: ${P(t)}`),0}default:return console.log("Usage: opencode-mem transcript <init|watch|validate> [--config <path>]"),1}}var Ho=process.argv[2],Uo=process.argv.slice(3);Qr(Ho,Uo).then(r=>{process.exit(r)}).catch(r=>{console.error(r),process.exit(1)});
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from 'child_process';
|
|
3
|
+
import { existsSync, readFileSync, rmSync } from 'fs';
|
|
4
|
+
import { homedir } from 'os';
|
|
5
|
+
import { join, dirname } from 'path';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
|
|
8
|
+
const IS_WINDOWS = process.platform === 'win32';
|
|
9
|
+
const VERSION_CHECK_LOG_PREFIX = '[version-check]';
|
|
10
|
+
const BUN_INSTALL_ARGS = Object.freeze(['install', '--production']);
|
|
11
|
+
const BUN_INSTALL_TIMEOUT_MS = 120_000;
|
|
12
|
+
const NODE_MODULES_DIRNAME = 'node_modules';
|
|
13
|
+
|
|
14
|
+
function findBun() {
|
|
15
|
+
const pathCheck = IS_WINDOWS
|
|
16
|
+
? spawnSync('where', ['bun'], { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true })
|
|
17
|
+
: spawnSync('which', ['bun'], { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
|
|
18
|
+
|
|
19
|
+
if (pathCheck.status === 0 && pathCheck.stdout.trim()) {
|
|
20
|
+
if (IS_WINDOWS) {
|
|
21
|
+
const bunCmdPath = pathCheck.stdout.split('\n').find((line) => line.trim().endsWith('bun.cmd'));
|
|
22
|
+
if (bunCmdPath) return bunCmdPath.trim();
|
|
23
|
+
}
|
|
24
|
+
return 'bun';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const bunPaths = IS_WINDOWS
|
|
28
|
+
? [join(homedir(), '.bun', 'bin', 'bun.exe')]
|
|
29
|
+
: [
|
|
30
|
+
join(homedir(), '.bun', 'bin', 'bun'),
|
|
31
|
+
'/usr/local/bin/bun',
|
|
32
|
+
'/opt/homebrew/bin/bun',
|
|
33
|
+
'/home/linuxbrew/.linuxbrew/bin/bun',
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
for (const bunPath of bunPaths) {
|
|
37
|
+
if (existsSync(bunPath)) return bunPath;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Setup-phase auto-install of plugin runtime dependencies.
|
|
44
|
+
//
|
|
45
|
+
// The plugin marketplace extracts files into ~/.claude/plugins/cache/...
|
|
46
|
+
// but does not run `bun install`. On fresh installs the worker crashes
|
|
47
|
+
// with `Cannot find module 'zod/v3'` on the very first hook invocation
|
|
48
|
+
// (gh #2640, #2637). The previous defense-in-depth fix (gh #2644) ran
|
|
49
|
+
// the install on the SessionStart / UserPromptSubmit hot path; review
|
|
50
|
+
// (gh #2649 — YOMXXX) flagged that as the wrong architectural home
|
|
51
|
+
// because it makes proxy / offline / OOM failures land on the user's
|
|
52
|
+
// first prompt instead of at install time.
|
|
53
|
+
//
|
|
54
|
+
// Running it here at Setup keeps the install off the hot path: Setup
|
|
55
|
+
// has a 300s timeout (vs 60s for SessionStart), runs once per Claude
|
|
56
|
+
// Code launch, and is the only standalone hook script — the natural
|
|
57
|
+
// place to materialise plugin runtime state.
|
|
58
|
+
function ensurePluginDependencies(pluginRoot) {
|
|
59
|
+
if (!existsSync(join(pluginRoot, 'package.json'))) return;
|
|
60
|
+
|
|
61
|
+
// Guard on node_modules (package-manager marker) rather than a specific
|
|
62
|
+
// package, so the check stays correct if dependencies are later renamed.
|
|
63
|
+
if (existsSync(join(pluginRoot, NODE_MODULES_DIRNAME))) return;
|
|
64
|
+
|
|
65
|
+
const bunPath = findBun();
|
|
66
|
+
if (!bunPath) {
|
|
67
|
+
console.error(`${VERSION_CHECK_LOG_PREFIX} bun not found on PATH; cannot auto-install plugin dependencies`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Progress diagnostic so users understand the (one-time) Setup hang.
|
|
72
|
+
console.error(`${VERSION_CHECK_LOG_PREFIX} installing plugin dependencies (first run, one-time)...`);
|
|
73
|
+
|
|
74
|
+
let result;
|
|
75
|
+
try {
|
|
76
|
+
result = spawnSync(bunPath, BUN_INSTALL_ARGS, {
|
|
77
|
+
cwd: pluginRoot,
|
|
78
|
+
encoding: 'utf-8',
|
|
79
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
80
|
+
timeout: BUN_INSTALL_TIMEOUT_MS,
|
|
81
|
+
windowsHide: true,
|
|
82
|
+
});
|
|
83
|
+
} catch (err) {
|
|
84
|
+
const reason = err && err.message ? err.message : String(err);
|
|
85
|
+
console.error(`${VERSION_CHECK_LOG_PREFIX} bun install threw (${reason}); worker may crash with missing module errors`);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// spawnSync does NOT throw on a failed child. Three distinct failure
|
|
90
|
+
// modes must be surfaced explicitly:
|
|
91
|
+
// 1. result.error set (ENOENT / ETIMEDOUT / ...)
|
|
92
|
+
// 2. non-zero exit code
|
|
93
|
+
// 3. signal-killed (OOM SIGKILL, SIGTERM, ...) where result.status is
|
|
94
|
+
// null AND result.error is undefined — only result.signal is set.
|
|
95
|
+
const killedBySignal = result.status === null && !!result.signal;
|
|
96
|
+
const nonZeroExit = result.status !== null && result.status !== 0;
|
|
97
|
+
if (result.error || nonZeroExit || killedBySignal) {
|
|
98
|
+
let reason;
|
|
99
|
+
if (result.error) {
|
|
100
|
+
reason = result.error.message;
|
|
101
|
+
} else if (killedBySignal) {
|
|
102
|
+
reason = `killed by ${result.signal}`;
|
|
103
|
+
} else {
|
|
104
|
+
reason = `exit ${result.status}`;
|
|
105
|
+
}
|
|
106
|
+
console.error(`${VERSION_CHECK_LOG_PREFIX} bun install failed (${reason}); worker may crash with missing module errors`);
|
|
107
|
+
// `bun install` often creates `node_modules/` BEFORE the failure point
|
|
108
|
+
// (network timeout mid-fetch, OOM kill, registry 5xx after partial
|
|
109
|
+
// resolution). The existence guard above would then permanently skip
|
|
110
|
+
// retry on every subsequent Setup run, leaving the plugin broken with
|
|
111
|
+
// no recovery path short of manual `rm -rf node_modules`. Remove the
|
|
112
|
+
// partial dir so the next Setup invocation can retry automatically
|
|
113
|
+
// (gh #2650 review).
|
|
114
|
+
try {
|
|
115
|
+
rmSync(join(pluginRoot, NODE_MODULES_DIRNAME), { recursive: true, force: true });
|
|
116
|
+
} catch (rmErr) {
|
|
117
|
+
const rmReason = rmErr && rmErr.message ? rmErr.message : String(rmErr);
|
|
118
|
+
console.error(`${VERSION_CHECK_LOG_PREFIX} failed to clean up partial node_modules (${rmReason}); next Setup run may skip retry`);
|
|
119
|
+
}
|
|
120
|
+
} else {
|
|
121
|
+
// Close the diagnostic loop: a Setup hook that can block for up to
|
|
122
|
+
// 120s needs an explicit completion line so users can distinguish a
|
|
123
|
+
// hung install from one that finished silently (gh #2650 review).
|
|
124
|
+
console.error(`${VERSION_CHECK_LOG_PREFIX} plugin dependencies installed successfully`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function resolveRoot() {
|
|
129
|
+
if (process.env.CLAUDE_PLUGIN_ROOT) {
|
|
130
|
+
const root = process.env.CLAUDE_PLUGIN_ROOT;
|
|
131
|
+
if (existsSync(join(root, 'package.json'))) return root;
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
const scriptDir = dirname(fileURLToPath(import.meta.url));
|
|
135
|
+
const candidate = dirname(scriptDir);
|
|
136
|
+
if (existsSync(join(candidate, 'package.json'))) return candidate;
|
|
137
|
+
} catch {}
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const ROOT = resolveRoot();
|
|
142
|
+
if (!ROOT) process.exit(0);
|
|
143
|
+
|
|
144
|
+
ensurePluginDependencies(ROOT);
|
|
145
|
+
|
|
146
|
+
function emitUpgradeHint(message) {
|
|
147
|
+
if (process.env.OPENCODE_MEM_CODEX_HOOK === '1') {
|
|
148
|
+
console.log(JSON.stringify({
|
|
149
|
+
hookSpecificOutput: {
|
|
150
|
+
hookEventName: 'SessionStart',
|
|
151
|
+
additionalContext: message,
|
|
152
|
+
},
|
|
153
|
+
}));
|
|
154
|
+
} else {
|
|
155
|
+
console.error(message);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const LEGACY_VERSION_MARKER_RE =
|
|
160
|
+
/^v?\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
161
|
+
|
|
162
|
+
function readInstallMarkerVersion(markerPath) {
|
|
163
|
+
const content = readFileSync(markerPath, 'utf-8');
|
|
164
|
+
try {
|
|
165
|
+
const marker = JSON.parse(content);
|
|
166
|
+
return marker && typeof marker === 'object' && typeof marker.version === 'string'
|
|
167
|
+
? marker.version
|
|
168
|
+
: null;
|
|
169
|
+
} catch {
|
|
170
|
+
const legacyVersion = content.trim();
|
|
171
|
+
return LEGACY_VERSION_MARKER_RE.test(legacyVersion)
|
|
172
|
+
? legacyVersion.replace(/^v/i, '')
|
|
173
|
+
: null;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
try {
|
|
178
|
+
const pkg = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf-8'));
|
|
179
|
+
const markerPath = join(ROOT, '.install-version');
|
|
180
|
+
if (!existsSync(markerPath)) {
|
|
181
|
+
emitUpgradeHint('opencode-mem: runtime not yet set up - run: npx opencode-mem@latest install');
|
|
182
|
+
process.exit(0);
|
|
183
|
+
}
|
|
184
|
+
const markerVersion = readInstallMarkerVersion(markerPath);
|
|
185
|
+
if (!markerVersion) {
|
|
186
|
+
emitUpgradeHint('opencode-mem: install marker unreadable - run: npx opencode-mem@latest install');
|
|
187
|
+
} else if (markerVersion !== pkg.version) {
|
|
188
|
+
emitUpgradeHint(`opencode-mem: upgraded to v${pkg.version} - run: npx opencode-mem@latest install`);
|
|
189
|
+
}
|
|
190
|
+
} catch {
|
|
191
|
+
emitUpgradeHint('opencode-mem: install marker unreadable - run: npx opencode-mem@latest install');
|
|
192
|
+
}
|
|
193
|
+
process.exit(0);
|