@mrdrmccoy/xerj-opencode-plugin 0.4.2 → 0.4.4

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.
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ var t="opentui:runtime-module:"+encodeURIComponent("@opentui/solid/jsx-runtime");async function e(){try{return await import(t)}catch{return await import("@opentui/solid/jsx-runtime")}}var n=await e(),{jsx:o,jsxs:s,jsxDEV:r,Fragment:a}=n;export{a as Fragment,o as jsx,r as jsxDEV,s as jsxs};
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"./tui-jsx.js";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.2",
3
+ "version": "0.4.4",
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": "./src/tui.tsx"
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
- "dependencies": {
39
- "@opencode/plugin": "^2.2.5"
37
+ "test:integration": "bun test test/integration",
38
+ "build:tui": "bun scripts/build-tui.ts",
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
- "@opentui/core": ">=0.8.0",
52
- "@opentui/solid": ">=0.8.0",
53
- "solid-js": ">=1.9.0"
52
+ "@opencode/plugin": ">=2.2.5"
54
53
  },
55
54
  "peerDependenciesMeta": {
56
- "@opentui/core": {
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
@@ -247,4 +247,4 @@ const definition = {
247
247
 
248
248
  export const XerjRpc = Rpc.define(definition);
249
249
 
250
- export const PLUGIN_VERSION = "0.4.2";
250
+ export const PLUGIN_VERSION = "0.4.4";
package/src/tui-jsx.ts ADDED
@@ -0,0 +1,32 @@
1
+ // JSX runtime shim for the TUI entry.
2
+ //
3
+ // The host publishes its single OpenTUI/Solid runtime as a virtual module. A
4
+ // plugin that imports the bare package instead loads a second copy whose JSX
5
+ // factory has no renderer, which throws "No renderer found" on first render.
6
+ // Prefer the host runtime; fall back to the local package for a bare Bun run
7
+ // where the virtual registry does not exist.
8
+
9
+ const VIRTUAL_JSX_RUNTIME =
10
+ "opentui:runtime-module:" + encodeURIComponent("@opentui/solid/jsx-runtime");
11
+
12
+ interface JsxRuntime {
13
+ readonly jsx: unknown;
14
+ readonly jsxs: unknown;
15
+ readonly jsxDEV?: unknown;
16
+ readonly Fragment: unknown;
17
+ }
18
+
19
+ async function loadRuntime(): Promise<JsxRuntime> {
20
+ try {
21
+ return (await import(VIRTUAL_JSX_RUNTIME)) as JsxRuntime;
22
+ } catch {
23
+ return (await import("@opentui/solid/jsx-runtime")) as JsxRuntime;
24
+ }
25
+ }
26
+
27
+ const runtime = await loadRuntime();
28
+
29
+ export const jsx = runtime.jsx;
30
+ export const jsxs = runtime.jsxs;
31
+ export const jsxDEV = runtime.jsxDEV;
32
+ export const Fragment = runtime.Fragment;