@mrdrmccoy/xerj-opencode-plugin 0.4.2 → 0.4.3
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/tui.js +6 -0
- package/package.json +15 -17
- package/src/rpc.ts +1 -1
package/dist/tui.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{Plugin as W}from"@opencode/plugin/tui";import{Rpc as O}from"@opencode/plugin/rpc";function c(e){return{type:"object",properties:e,required:Object.keys(e),additionalProperties:!1}}function y(e){return c(e)}function V(e){return c(e)}var H={id:"xerj",methods:{status:{input:y({}),output:y({pluginVersion:{type:"string"},updatedAt:{type:"number"},node:c({phase:{type:"string",enum:["starting","ready","error","disabled"]},baseUrl:{type:["string","null"]},serverVersion:{type:["string","null"]},spawned:{type:"boolean"},error:{type:["string","null"]}}),binary:c({version:{type:["string","null"]},path:{type:["string","null"]},upgraded:{type:"boolean"},target:{type:["string","null"]}}),index:c({prefix:{type:"string"},docs:{type:"number"},bytes:{type:"number"},indices:{type:"number"},state:{type:"string",enum:["disabled","starting","watching","idle","error"]},lastRunAt:{type:["number","null"]},lastGeneration:{type:["number","null"]},lastRecords:{type:["number","null"]},restarts:{type:"number"},lastError:{type:["string","null"]},datasets:{type:"array",items:c({name:{type:"string"},docs:{type:"number"},bytes:{type:"number"}})}}),config:c({indexRoot:{type:"string"},brain:{type:"array",items:{type:"string"}},watch:{type:"boolean"},contextEnabled:{type:"boolean"}}),usage:c({queries:{type:"number"},hits:{type:"number"},hitRate:{type:"number"},bytesReturned:{type:"number"},bytesRead:{type:"number"},baselineBytes:{type:"number"},savedBytes:{type:"number"},tokensSaved:{type:"number"},topFiles:{type:"array",items:c({path:{type:"string"},citations:{type:"number"},bytes:{type:"number"}})}}),memory:c({namespace:{type:"string"},count:{type:"number"}}),brains:{type:"array",items:c({name:{type:"string"},prefix:{type:"string"},docs:{type:"number"},edges:{type:"number"},lastRunAt:{type:["number","null"]},error:{type:["string","null"]}})},counters:c({rpcCalls:{type:"number"},injectedTurns:{type:"number"},nodeSpawns:{type:"number"},http429:{type:"number"},indexRuns:{type:"number"}}),recent:{type:"array",items:{type:"string"}},warnings:{type:"array",items:{type:"string"}},errors:{type:"array",items:{type:"string"}}})},reindex:{input:y({}),output:y({queued:{type:"boolean"}})},remember:{input:y({text:{type:"string"}}),output:y({id:{type:"string"},created:{type:"boolean"}})},search:{input:y({query:{type:"string"}}),output:y({text:{type:"string"},hits:{type:"number"},bytes:{type:"number"}})}},events:{updated:{schema:V({updatedAt:{type:"number"}})}}},B=O.define(H);var N=["B","KB","MB","GB","TB"];function p(e){if(!Number.isFinite(e)||e<=0)return"0 B";let n=e,t=0;while(n>=1024&&t<N.length-1)n/=1024,t+=1;let l=t===0||n>=100?0:1;return`${n.toFixed(l)} ${N[t]}`}function d(e){if(!Number.isFinite(e))return"0";return Math.round(e).toLocaleString("en-US")}function k(e){if(!Number.isFinite(e)||e<=0)return"~0";if(e<1000)return`~${Math.round(e)}`;if(e<1e6)return`~${(e/1000).toFixed(1)}K`;return`~${(e/1e6).toFixed(1)}M`}function T(e){if(!Number.isFinite(e)||e<=0)return"0%";return`${Math.round(e*100)}%`}function v(e,n){if(n===null||!Number.isFinite(n))return"never";let t=Math.max(0,Math.round((e-n)/1000));if(t<10)return"just now";if(t<60)return`${t}s ago`;let l=Math.floor(t/60);if(l<60)return`${l}m ago`;let i=Math.floor(l/60);if(i<24)return`${i}h ago`;return`${Math.floor(i/24)}d ago`}function C(e,n){let{index:t,usage:l}=e,i=t.lastRecords===null?"no runs":`${d(t.lastRecords)} records`;return[`XERJ ${_(e)} ${G(e)}`,[`q ${d(l.queries)}`,`hit ${T(l.hitRate)}`,`${k(l.tokensSaved)} tok saved`].join(" "),`idx ${v(n,t.lastRunAt)} \xB7 ${i}`,"\u25B8 /xerj for details"]}function E(e,n){let{node:t,binary:l,index:i,memory:b,usage:u}=e;return[{title:"Node",lines:[[t.phase,t.spawned?"spawned":"attached",t.baseUrl??"no address"].join(" \xB7 "),t.serverVersion===null?"server unknown":`server ${t.serverVersion}`]},{title:"Binary",lines:[`${l.version??"not installed"}${K(l.target)}`,l.path??"managed download"]},{title:"Index",lines:[`${i.state} \xB7 ${i.prefix}`,[`${d(i.docs)} docs`,p(i.bytes),`${i.indices} ${w(i.indices,"index","indices")}`].join(" \xB7 "),[`last run ${v(n,i.lastRunAt)}`,`generation ${i.lastGeneration??"\u2014"}`,`${i.lastRecords??0} records`].join(" \xB7 ")]},{title:"Datasets",lines:i.datasets.length===0?["none yet"]:i.datasets.map((o)=>`${o.name} ${d(o.docs)} docs \xB7 `+`${p(o.bytes)}`)},...e.brains.length===0?[]:[{title:"Brains",lines:e.brains.map((o)=>[`${o.name} ${d(o.docs)} docs`,`${o.edges} ${w(o.edges,"edge","edges")}`,v(n,o.lastRunAt),o.error??""].filter((g)=>g.length>0).join(" \xB7 "))}],{title:"Memory",lines:[[`${d(b.count)} ${w(b.count,"entry","entries")}`,b.namespace].join(" \xB7 ")]},{title:"Usage",lines:[[`${d(u.queries)} queries`,`${T(u.hitRate)} hit`,`${d(u.hits)} hits`].join(" \xB7 "),[`${k(u.tokensSaved)} tokens saved`,`${p(u.savedBytes)} of ${p(u.baselineBytes)} baseline`].join(" \xB7 "),`${p(u.bytesReturned)} returned \xB7 ${p(u.bytesRead)} read`]},{title:"Counters",lines:[`${d(e.counters.indexRuns)} index runs \xB7 `+`${d(e.counters.injectedTurns)} injections`,`${d(e.counters.nodeSpawns)} spawns \xB7 `+`${d(e.counters.http429)} rate-limited \xB7 `+`${d(e.counters.rpcCalls)} rpc calls`]},{title:"Top cited",lines:u.topFiles.length===0?["none yet"]:u.topFiles.map((o)=>`${o.path} \xD7${o.citations} \xB7 ${p(o.bytes)}`)},{title:"Health",lines:I(e)}]}function I(e){let n=[...e.warnings.map((t)=>`warn: ${t}`),...e.recent,...e.errors.map((t)=>`error: ${t}`)];return n.length===0?["no warnings"]:n.slice(-6)}function _(e){return e.node.phase==="ready"?"\u25CF":"\u25CB"}function G(e){let n=e.index;if(e.node.phase!=="ready")return e.node.phase==="starting"?"starting":e.node.phase;if(n.docs===0)return"ready \xB7 not indexed yet";return`ready \xB7 ${d(n.docs)} docs \xB7 ${p(n.bytes)}`}function K(e){return e===null?"":` \xB7 ${e}`}function w(e,n,t){return e===1?n:t}import{jsx as m,jsxs as R}from"@opentui/solid/jsx-runtime";var S="xerj.stats",Q=30000,P=6000,oe=W.define({id:"xerj.tui",setup(e){let n=()=>e.client.rpc(B),[t,l]=e.storage.memory("status",{initial:{lines:["XERJ \u25CB starting"],ready:!1,snapshot:null,reason:null}}),i=()=>e.location?{location:e.location}:void 0,b=new AbortController,u=!1,o=!1,g=null,U=()=>{if(o||g)return;g=Y(n(),()=>void h(),b.signal)},j=()=>{g?.(),g=null},h=async()=>{if(o||u)return;u=!0;try{let r=await n().status({},i());l((s)=>{s.snapshot=r,s.lines=C(r,Date.now()),s.ready=r.node.phase==="ready",s.reason=null}),U()}catch(r){let s=Z(r);j(),l((a)=>{a.snapshot=null,a.reason=s,a.lines=["XERJ \u25CB offline",s],a.ready=!1})}finally{u=!1}},F=async()=>{if(await h(),e.ui.panel.current()?.name===S){e.ui.panel.close();return}if(e.ui.panel.open(S))return;await e.ui.dialog.alert({title:"XERJ",message:z(t.snapshot,t.lines)})},A=async()=>{try{let r=await n().reindex({},i());e.ui.toast.show({message:r.queued?"XERJ reindex queued":"XERJ indexing is disabled",variant:r.queued?"success":"info"})}catch{e.ui.toast.show({message:"XERJ is not available",variant:"error"})}},X=async(r,s)=>(await e.ui.dialog.prompt({title:r,description:s}))?.trim()??"",J=async(r)=>{let s=r?.trim()||await X("Remember in XERJ","Durable fact or decision");if(!s)return;try{let a=await n().remember({text:s},i());e.ui.toast.show({message:a.created?`Remembered as ${a.id}`:`Already remembered as ${a.id}`,variant:a.created?"success":"info"})}catch{e.ui.toast.show({message:"XERJ memory is not available",variant:"error"})}},D=async(r)=>{let s=r?.trim()||await X("Search XERJ","What to look for");if(!s)return;try{let a=await n().search({query:s},i());await e.ui.dialog.alert({title:["XERJ search",`${a.hits} ${a.hits===1?"hit":"hits"}`].join(" \xB7 "),message:a.hits===0?"No passages matched.":ee(a.text)})}catch{e.ui.toast.show({message:"XERJ search is not available",variant:"error"})}};h();let M=setInterval(()=>void h(),Q);e.keymap.layer(()=>({mode:"global",commands:[{id:"xerj.status",title:"XERJ status",description:"Open the XERJ details panel",group:"XERJ",palette:!0,slash:{name:"xerj",arguments:!0},run:async(r)=>{let s=(r??"").trim();if(s.length===0||s==="status")return F();let[a,...f]=s.split(/\s+/),x=f.join(" ").trim();if(a==="reindex")return A();if(a==="remember")return J(x);if(a==="search")return D(x);e.ui.toast.show({message:`Unknown XERJ command: ${a}`,variant:"warning"})}},{id:"xerj.close",title:"Close XERJ panel",description:"Close the XERJ details panel",group:"XERJ",bind:"escape",enabled:()=>e.ui.panel.current()?.name===S,run:()=>e.ui.panel.close()},{id:"xerj.reindex",title:"XERJ reindex",description:"Queue an incremental reindex of this project",group:"XERJ",palette:!0,slash:{name:"xerj-reindex"},enabled:()=>t.ready,run:()=>A()},{id:"xerj.remember",title:"XERJ remember",description:"Store a durable project fact in XERJ memory",group:"XERJ",palette:!0,slash:{name:"xerj-remember",arguments:!0},enabled:()=>t.ready,run:(r)=>J(r)},{id:"xerj.search",title:"XERJ search",description:"Search the project index and show cited passages",group:"XERJ",palette:!0,slash:{name:"xerj-search",arguments:!0},enabled:()=>t.ready,run:(r)=>D(r)}]}));let q=e.ui.slot({append:"sidebar.content",render:()=>m("box",{flexDirection:"column",children:t.lines.map((r)=>{let s=r.startsWith("XERJ")?e.theme.text.base:e.theme.text.muted;return m("text",{fg:s,children:r})})})}),L=e.ui.slot({append:"session.panel",render:(r)=>{if(r.name!==S)return null;let s=t.snapshot,a=s?E(s,Date.now()):[];return R("box",{flexDirection:"column",children:[R("scrollbox",{flexDirection:"column",children:[a.map((f)=>R("box",{flexDirection:"column",marginBottom:1,children:[m("text",{fg:e.theme.text.base,children:f.title}),f.lines.map((x)=>m("text",{fg:e.theme.text.muted,children:x}))]})),a.length===0?m("text",{fg:e.theme.text.faint,children:t.reason??"waiting for the XERJ server part"}):null]}),R("box",{flexDirection:"row",justifyContent:"space-between",marginTop:1,children:[m("text",{fg:e.theme.text.faint,children:"esc or /xerj closes"}),m("box",{border:!0,borderColor:e.theme.border.base,paddingLeft:1,paddingRight:1,onMouseDown:()=>r.close(),children:m("text",{fg:e.theme.text.base,children:"\u2715 close"})})]})]})}});return()=>{o=!0,b.abort(),clearInterval(M),j(),L(),q()}}});function Y(e,n,t){try{return e.events?.on?.("updated",n,{signal:t})??(()=>{})}catch{return()=>{}}}function z(e,n){if(!e)return n.join(`
|
|
3
|
+
`);return E(e,Date.now()).flatMap((t)=>[t.title,...t.lines]).join(`
|
|
4
|
+
`)}function Z(e){let t=(e instanceof Error?e.message:String(e)).split(`
|
|
5
|
+
`)[0]?.trim();if(!t)return"the XERJ server part did not answer";return t.length>72?`${t.slice(0,71)}\u2026`:t}function ee(e){if(e.length<=P)return e;return`${e.slice(0,P)}
|
|
6
|
+
\u2026`}export{oe as default};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrdrmccoy/xerj-opencode-plugin",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"description": "XERJ integration for OpenCode: local code and docs search, agent memory, and retrieval accounting.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -23,20 +23,20 @@
|
|
|
23
23
|
"exports": {
|
|
24
24
|
".": "./src/index.ts",
|
|
25
25
|
"./rpc": "./src/rpc.ts",
|
|
26
|
-
"./tui": "./
|
|
26
|
+
"./tui": "./dist/tui.js"
|
|
27
27
|
},
|
|
28
28
|
"files": [
|
|
29
29
|
"src",
|
|
30
|
+
"dist",
|
|
30
31
|
"tsconfig.json"
|
|
31
32
|
],
|
|
32
33
|
"scripts": {
|
|
33
34
|
"typecheck": "tsc --noEmit",
|
|
34
35
|
"test": "bun test test/unit",
|
|
35
36
|
"test:unit": "bun test test/unit",
|
|
36
|
-
"test:integration": "bun test test/integration"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"@opencode/plugin": "^2.2.5"
|
|
37
|
+
"test:integration": "bun test test/integration",
|
|
38
|
+
"build:tui": "bun build src/tui.tsx --outdir dist --target bun --packages external --production",
|
|
39
|
+
"prepack": "bun run build:tui"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@opencode/theme": "^2.2.5",
|
|
@@ -45,22 +45,20 @@
|
|
|
45
45
|
"@types/bun": "^1.4.3",
|
|
46
46
|
"@types/node": "^22.10.0",
|
|
47
47
|
"solid-js": "^1.9.17",
|
|
48
|
-
"typescript": "^5.7.0"
|
|
48
|
+
"typescript": "^5.7.0",
|
|
49
|
+
"@opencode/plugin": "^2.2.5"
|
|
49
50
|
},
|
|
50
51
|
"peerDependencies": {
|
|
51
|
-
"@
|
|
52
|
-
"@opentui/solid": ">=0.8.0",
|
|
53
|
-
"solid-js": ">=1.9.0"
|
|
52
|
+
"@opencode/plugin": ">=2.2.5"
|
|
54
53
|
},
|
|
55
54
|
"peerDependenciesMeta": {
|
|
56
|
-
"@
|
|
57
|
-
"optional": true
|
|
58
|
-
},
|
|
59
|
-
"@opentui/solid": {
|
|
60
|
-
"optional": true
|
|
61
|
-
},
|
|
62
|
-
"solid-js": {
|
|
55
|
+
"@opencode/plugin": {
|
|
63
56
|
"optional": true
|
|
64
57
|
}
|
|
58
|
+
},
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"@opentui/core": "^0.8.0",
|
|
61
|
+
"@opentui/solid": "^0.8.0",
|
|
62
|
+
"solid-js": "^1.9.17"
|
|
65
63
|
}
|
|
66
64
|
}
|
package/src/rpc.ts
CHANGED