@hyperez/regna-code 0.2.5 → 0.2.6
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/README.md +34 -0
- package/dist/bin/regna.mjs +11 -11
- package/dist/extensions/mcp.js +5 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -59,6 +59,9 @@ For CI or scripted use, set `REGNA_API_KEY` directly; it takes priority over the
|
|
|
59
59
|
| `REGNA_DOCS_ENABLED` | (unset) | `1` enables the document search tool (`regna_docs_search`) and the `/regna-docs` skill. Only turn this on when the backend's retrieval endpoint is available. |
|
|
60
60
|
| `REGNA_RETRIEVAL_PATH` | `/api/retrieval/search` | Override the retrieval endpoint path. |
|
|
61
61
|
| `REGNA_DOCS_TIMEOUT_MS` | `15000` | Retrieval timeout (clamped 1000~120000). |
|
|
62
|
+
| `REGNA_MCP_ENABLED` | (unset) | `0` disables MCP entirely. Default on, but with no `mcp.json` config it does nothing. |
|
|
63
|
+
| `REGNA_MCP_TIMEOUT_MS` | `30000` | MCP server connect/list-tools timeout (clamped 5000~180000). |
|
|
64
|
+
| `REGNA_MCP_CALL_TIMEOUT_MS` | `120000` | MCP tool-call timeout (clamped 5000~600000). |
|
|
62
65
|
|
|
63
66
|
## Commands
|
|
64
67
|
|
|
@@ -70,6 +73,37 @@ For CI or scripted use, set `REGNA_API_KEY` directly; it takes priority over the
|
|
|
70
73
|
| `/compact` | Compact the session context (also runs automatically as it fills). |
|
|
71
74
|
| `/regna-brand` | Toggle the Regna Code header/title branding. |
|
|
72
75
|
| `/regna-docs <question>` | Document-grounded query. Searches indexed documents with `regna_docs_search`, answers using only retrieved evidence with `[source n]` citations, and says it does not know when there is no evidence. Requires `REGNA_DOCS_ENABLED=1`. |
|
|
76
|
+
| `/mcp` | List configured MCP servers, their connection status, and tool counts. |
|
|
77
|
+
|
|
78
|
+
## MCP servers
|
|
79
|
+
|
|
80
|
+
Regna Code connects to [Model Context Protocol](https://modelcontextprotocol.io) servers and exposes their tools to the agent, named `mcp__<server>__<tool>`. This gives you the whole MCP ecosystem (filesystem, GitHub, databases, browsers, and more) on top of the built-in `read`/`write`/`edit`/`bash`/`grep`/`find`/`ls` tools.
|
|
81
|
+
|
|
82
|
+
Configure servers in either file (same schema as other MCP clients; a project file overrides a same-named global server):
|
|
83
|
+
|
|
84
|
+
- Global: `~/.regna/mcp.json`
|
|
85
|
+
- Project: `./.mcp.json`
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"mcpServers": {
|
|
90
|
+
"filesystem": {
|
|
91
|
+
"command": "npx",
|
|
92
|
+
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/project"]
|
|
93
|
+
},
|
|
94
|
+
"github": {
|
|
95
|
+
"type": "http",
|
|
96
|
+
"url": "https://api.githubcopilot.com/mcp/",
|
|
97
|
+
"headers": { "Authorization": "Bearer ${GITHUB_MCP_TOKEN}" }
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
- **stdio** servers use `command` (+ optional `args`, `env`, `cwd`). **Remote** servers use `url` with `type` `http` (default, Streamable HTTP) or `sse`.
|
|
104
|
+
- `${VAR}` inside any value is substituted from the environment, so secrets stay out of the config file.
|
|
105
|
+
- A failing server is skipped (its error is shown in `/mcp`); the rest keep working.
|
|
106
|
+
- Controls: `REGNA_MCP_ENABLED=0` disables MCP; `REGNA_MCP_TIMEOUT_MS` / `REGNA_MCP_CALL_TIMEOUT_MS` tune timeouts. In air-gapped mode (`REGNA_OFFLINE=1`) remote servers are skipped and stdio servers still run.
|
|
73
107
|
|
|
74
108
|
## Document search (`REGNA_DOCS_ENABLED=1`)
|
|
75
109
|
|
package/dist/bin/regna.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{spawn as
|
|
2
|
+
import{spawn as I}from"node:child_process";import{fileURLToPath as M}from"node:url";import{dirname as v,join as a}from"node:path";import{existsSync as m,readFileSync as b,writeFileSync as j,mkdirSync as P,unlinkSync as B,chmodSync as K}from"node:fs";import{homedir as Y}from"node:os";import{createInterface as q}from"node:readline";var z=v(M(import.meta.url)),g=v(z),A=a(g,"extensions"),$=a(g,"themes","regna.json"),R=a(g,"APPEND_SYSTEM.md"),k="https://regnax.ai/v1",H="regna/regna-1",N=a(Y(),".regna"),E=a(N,"auth.json"),O=a(N,"engine"),u=process.argv.slice(2),h=(...e)=>u.some(t=>e.some(n=>!!(t===n||t.startsWith(`${n}=`)||/^-[a-z]$/i.test(n)&&t.startsWith(n)&&t.length>n.length)));function _(){for(let e of[a(g,"package.json"),a(g,"..","package.json")])try{let t=JSON.parse(b(e,"utf8")).version;if(t)return`v${t}`}catch{}return""}var J=`Regna Code ${_()} - a terminal coding agent on Regna
|
|
3
3
|
|
|
4
4
|
Usage:
|
|
5
5
|
regna [message...] start interactive, optionally with a first message
|
|
@@ -25,8 +25,8 @@ Environment:
|
|
|
25
25
|
REGNA_POLICY network egress guard: off | warn | enforce
|
|
26
26
|
|
|
27
27
|
Docs: https://github.com/HyperEZ/regna-code
|
|
28
|
-
`;function V(){try{let e=JSON.parse(
|
|
29
|
-
`);try{K(E,384)}catch{}}function Z(){try{return B(E),!0}catch{return!1}}function Q(e){try{return`${new URL(e).origin}/console`}catch{return"https://regnax.ai/console"}}function X(e){try{let[t,n]=process.platform==="darwin"?["open",[e]]:process.platform==="win32"?["cmd",["/c","start","",e]]:["xdg-open",[e]]
|
|
28
|
+
`;function V(){try{let e=JSON.parse(b(E,"utf8"));return e&&typeof e.apiKey=="string"?e:null}catch{return null}}function W(e){P(N,{recursive:!0}),j(E,`${JSON.stringify(e,null,2)}
|
|
29
|
+
`);try{K(E,384)}catch{}}function Z(){try{return B(E),!0}catch{return!1}}function Q(e){try{return`${new URL(e).origin}/console`}catch{return"https://regnax.ai/console"}}function X(e){try{let[t,n]=process.platform==="darwin"?["open",[e]]:process.platform==="win32"?["cmd",["/c","start","",e]]:["xdg-open",[e]];I(t,n,{stdio:"ignore",detached:!0}).unref()}catch{}}async function S(e,t){try{let n=new AbortController,r=setTimeout(()=>n.abort(),8e3),s=await fetch(`${e.replace(/\/+$/,"")}/models`,{headers:{Authorization:`Bearer ${t}`},signal:n.signal});if(clearTimeout(r),s.status===401||s.status===403)return{status:"invalid",ids:[]};if(!s.ok)return{status:"unknown",ids:[]};let o=await s.json().catch(()=>({}));return{status:"ok",ids:Array.isArray(o?.data)?o.data.map(d=>d&&typeof d.id=="string"?d.id:"").filter(Boolean):[]}}catch{return{status:"unknown",ids:[]}}}function ee(e){let t=(e||"").trim();if(!t)return"";/^https?:\/\//i.test(t)||(t=`http://${t}`);try{let n=new URL(t),r=`${n.origin}${n.pathname}`.replace(/\/+$/,"");return/\/v\d+$/.test(r)||(r=`${r}/v1`),r}catch{return""}}function te(){let e=q({input:process.stdin}),t=[],n=[],r=!1;return e.on("line",o=>{n.length?n.shift()(o):t.push(o)}),e.on("close",()=>{for(r=!0;n.length;)n.shift()(null)}),{ask:o=>(process.stdout.write(o),new Promise(i=>{t.length?i(t.shift()):r?i(null):n.push(i)})),close:()=>e.close()}}async function ne(e){return process.stdout.write(`
|
|
30
30
|
Regna Code ${_()}
|
|
31
31
|
Choose how to connect:
|
|
32
32
|
|
|
@@ -39,28 +39,28 @@ Docs: https://github.com/HyperEZ/regna-code
|
|
|
39
39
|
2) Paste it below.
|
|
40
40
|
|
|
41
41
|
`),X(n);let r=(await e(" API key: ")||"").trim();r||(process.stderr.write(` No key entered. Aborting.
|
|
42
|
-
`),process.exit(1));let{status:s}=await
|
|
42
|
+
`),process.exit(1));let{status:s}=await S(t,r);return s==="invalid"&&(process.stderr.write(` That key was rejected. Run: regna login
|
|
43
43
|
`),process.exit(1)),{mode:"online",baseUrl:t,apiKey:r}}async function re(e){process.stdout.write(`
|
|
44
44
|
Offline mode (air-gapped).
|
|
45
45
|
Point Regna Code at your internal gateway (OpenAI-compatible /v1).
|
|
46
46
|
|
|
47
47
|
`);let t=(await e(" Gateway URL [http://localhost:8077/v1]: ")||"").trim(),n=ee(t)||"http://localhost:8077/v1",r=(await e(" API key: ")||"").trim();r||(process.stderr.write(` No key entered. Aborting.
|
|
48
|
-
`),process.exit(1));let{status:s,ids:o}=await
|
|
48
|
+
`),process.exit(1));let{status:s,ids:o}=await S(n,r);s==="invalid"&&(process.stderr.write(` That key was rejected by the gateway. Run: regna login
|
|
49
49
|
`),process.exit(1));let i="regna/default";if(s==="ok"&&o.length>0){let d=o.filter(y=>y==="default"||!y.includes("/")),c=d.length?d:o;if(c.length===1)i=`regna/${c[0]}`;else{process.stdout.write(`
|
|
50
50
|
Models served by the gateway:
|
|
51
51
|
`),c.forEach((D,F)=>process.stdout.write(` ${F+1}) ${D}
|
|
52
52
|
`));let y=(await e(`
|
|
53
53
|
Default model [1]: `)||"").trim(),U=Math.max(1,Math.min(c.length,parseInt(y||"1",10)||1))-1;i=`regna/${c[U]}`}}else process.stdout.write(` (Could not list models now; will use the gateway's active model.)
|
|
54
|
-
`);return{mode:"offline",baseUrl:n,apiKey:r,model:i}}async function
|
|
54
|
+
`);return{mode:"offline",baseUrl:n,apiKey:r,model:i}}async function G(e){let{ask:t,close:n}=te();try{let s=(e||await ne(t))==="offline"?await re(t):await se(t);return W(s),process.stdout.write(`
|
|
55
55
|
Saved. Mode: ${s.mode}${s.model?`, default model: ${s.model}`:""}.
|
|
56
56
|
|
|
57
57
|
`),s}finally{n()}}(h("--help","-h")||u[0]==="help")&&(process.stdout.write(J),process.exit(0));(h("--version")||u[0]==="version")&&(process.stdout.write(`Regna Code ${_()}
|
|
58
|
-
`),process.exit(0));if(u[0]==="login"){let e=u[1]==="online"||u[1]==="offline"?u[1]:void 0;await
|
|
58
|
+
`),process.exit(0));if(u[0]==="login"){let e=u[1]==="online"||u[1]==="offline"?u[1]:void 0;await G(e),process.exit(0)}u[0]==="logout"&&(process.stdout.write(Z()?`Logged out.
|
|
59
59
|
`:`Not logged in.
|
|
60
|
-
`),process.exit(0));var l=null,f=(process.env.REGNA_API_KEY||"").trim();f?l={mode:process.env.REGNA_OFFLINE==="1"?"offline":"online",apiKey:f}:(l=V(),l?.apiKey?f=l.apiKey.trim():process.stdin.isTTY&&process.stdout.isTTY?(l=await
|
|
61
|
-
`),process.exit(1)));async function oe(e,t){try{let n=new AbortController,r=setTimeout(()=>n.abort(),4e3),s;try{s=await fetch(`${e.replace(/\/+$/,"")}/models`,{headers:{Authorization:`Bearer ${t}`},signal:n.signal})}finally{clearTimeout(r)}if(!s.ok)return null;let o=await s.json(),d=(Array.isArray(o?.data)?o.data:[]).map(c=>c&&typeof c.id=="string"?c.id:"").filter(c=>/^regna-\d+$/.test(c)).sort();return d.length>0?`regna/${d[0]}`:null}catch{return null}}var L=process.env.REGNA_OFFLINE==="1"||l?.mode==="offline",
|
|
62
|
-
`),process.exit(1));for(let[,s]of n)p.push("-e",s)}!h("--theme")&&m(
|
|
60
|
+
`),process.exit(0));var l=null,f=(process.env.REGNA_API_KEY||"").trim();f?l={mode:process.env.REGNA_OFFLINE==="1"?"offline":"online",apiKey:f}:(l=V(),l?.apiKey?f=l.apiKey.trim():process.stdin.isTTY&&process.stdout.isTTY?(l=await G(),f=l.apiKey.trim()):(process.stderr.write(`[regna] Not logged in. Run: regna login
|
|
61
|
+
`),process.exit(1)));async function oe(e,t){try{let n=new AbortController,r=setTimeout(()=>n.abort(),4e3),s;try{s=await fetch(`${e.replace(/\/+$/,"")}/models`,{headers:{Authorization:`Bearer ${t}`},signal:n.signal})}finally{clearTimeout(r)}if(!s.ok)return null;let o=await s.json(),d=(Array.isArray(o?.data)?o.data:[]).map(c=>c&&typeof c.id=="string"?c.id:"").filter(c=>/^regna-\d+$/.test(c)).sort();return d.length>0?`regna/${d[0]}`:null}catch{return null}}var L=process.env.REGNA_OFFLINE==="1"||l?.mode==="offline",C=(process.env.REGNA_BASE_URL||"").trim()||l?.baseUrl||k,w=(process.env.REGNA_MODEL||"").trim();w||(L?w=l?.model||"regna/default":w=await oe(C,f)||l?.model||H);process.env.REGNA_API_KEY=f;process.env.REGNA_BASE_URL=C;L&&(process.env.REGNA_OFFLINE||(process.env.REGNA_OFFLINE="1"),process.env.REGNA_POLICY||(process.env.REGNA_POLICY="enforce"));var p=[],ie=process.env.REGNA_DISCOVER==="1";if(!ie){p.push("--no-extensions");let e=["provider","policy","branding","context","exit","docs-search","docs-analysis","mcp"],t=s=>{let o=a(A,`${s}.js`);if(m(o))return o;let i=a(A,`${s}.ts`);return m(i)?i:null},n=e.map(s=>[s,t(s)]),r=n.filter(([,s])=>!s).map(([s])=>s);r.length>0&&(process.stderr.write(`[regna] Missing required extensions: ${r.join(", ")} (in ${A}). Install is corrupted. Aborting.
|
|
62
|
+
`),process.exit(1));for(let[,s]of n)p.push("-e",s)}!h("--theme")&&m($)&&p.push("--theme",$);h("--system-prompt")||(m(R)||(process.stderr.write(`[regna] Missing required prompt: APPEND_SYSTEM.md (${R}). Install is corrupted. Aborting.
|
|
63
63
|
(To set the prompt yourself on purpose, run with --system-prompt.)
|
|
64
|
-
`),process.exit(1)),p.push("--append-system-prompt",`@${R}`));h("--model","-m")||p.push("--model",w);p.push(...u);try{
|
|
64
|
+
`),process.exit(1)),p.push("--append-system-prompt",`@${R}`));h("--model","-m")||p.push("--model",w);p.push(...u);try{P(O,{recursive:!0})}catch{}var x={...process.env,PI_CODING_AGENT_DIR:O};process.env.REGNA_OFFLINE==="1"&&(x.PI_OFFLINE="1");x.PI_SKIP_VERSION_CHECK="1";function ae(){let e=a("node_modules","@earendil-works","pi-coding-agent","dist","cli.js"),t=g;for(let n=0;n<10;n++){let r=a(t,e);if(m(r))return r;let s=v(t);if(s===t)break;t=s}return null}function ce(){let e=process.env.REGNA_ENGINE;if(e)return{cmd:e,prefix:[],label:e};let t=ae();return t?{cmd:process.execPath,prefix:[t],label:t}:{cmd:"pi",prefix:[],label:"runtime (PATH)"}}var{cmd:le,prefix:de,label:ue}=ce(),T=I(le,[...de,...p],{stdio:"inherit",env:x});T.on("error",e=>{e&&e.code==="ENOENT"&&(process.stderr.write(`[regna] Runtime executable not found (${ue}). Reinstall (npm i -g @hyperez/regna-code) or set REGNA_ENGINE.
|
|
65
65
|
`),process.exit(127)),process.stderr.write(`[regna] Failed to start the runtime: ${e?.message??String(e)}
|
|
66
66
|
`),process.exit(1)});T.on("exit",(e,t)=>{if(t){process.kill(process.pid,t);return}process.exit(e??0)});
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{Type as L}from"typebox";import{Client as k}from"@modelcontextprotocol/sdk/client/index.js";import{StdioClientTransport as O,getDefaultEnvironment as U}from"@modelcontextprotocol/sdk/client/stdio.js";import{StreamableHTTPClientTransport as j}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{SSEClientTransport as F}from"@modelcontextprotocol/sdk/client/sse.js";import{createHash as X}from"node:crypto";import{readFileSync as G}from"node:fs";import{join as v}from"node:path";import{homedir as z}from"node:os";var D="regna-code",H="1.0.0",J=3e4,Z=5e3,q=18e4,B=12e4,V=5e3,K=6e5,w=64,M=2e5,S=512e3,x=10;function C(t,n=process.env){return t.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g,(s,o)=>n[o]??"")}function A(t,n=process.env){let s={};for(let[o,i]of Object.entries(t??{}))s[o]=C(String(i),n);return s}function $(t,n,s,o){let i=Number(t);return!Number.isFinite(i)||i<=0?n:Math.min(o,Math.max(s,i))}function Q(t){return X("sha1").update(t).digest("hex").slice(0,8)}function W(t,n,s){let o=e=>e.replace(/[^a-zA-Z0-9_-]/g,"_"),i=`mcp__${o(t)}__${o(n)}`,r=i.length>w?`${i.slice(0,w-9)}_${Q(`${t}\0${n}`)}`:i;if(s){let e=r,u=1;for(;s.has(e);){let m=`_${u++}`;e=`${r.slice(0,w-m.length)}${m}`}s.add(e),r=e}return r}function Y(t){let n=new Map,s=t?.mcpServers;if(!s||typeof s!="object")return n;for(let[o,i]of Object.entries(s)){if(!i||typeof i!="object")continue;let r=i;typeof r.url=="string"&&r.url.trim()?n.set(o,{type:r.type==="sse"?"sse":"http",url:r.url,headers:r.headers}):typeof r.command=="string"&&r.command.trim()&&n.set(o,{command:r.command,args:Array.isArray(r.args)?r.args.map(String):void 0,env:r.env,cwd:typeof r.cwd=="string"?r.cwd:void 0})}return n}function tt(t){try{return JSON.parse(G(t,"utf8"))}catch{return null}}function et(t,n=z()){let s=new Map;for(let o of[v(n,".regna","mcp.json"),v(t,".mcp.json")]){let i=Y(tt(o));for(let[r,e]of i)s.set(r,e)}return s}function P(t){return typeof t.url=="string"}function nt(t,n){if(P(t)){if(n)throw new Error("remote MCP disabled by REGNA_OFFLINE");let o=new URL(C(t.url));if(o.protocol!=="http:"&&o.protocol!=="https:")throw new Error(`invalid url scheme: ${o.protocol}`);let r={requestInit:{headers:A(t.headers)}};return t.type==="sse"?new F(o,r):new j(o,r)}let s=C(t.command);if(!s.trim())throw new Error("empty command");return new O({command:s,args:(t.args??[]).map(o=>C(o)),env:{...U(),...A(t.env)},cwd:t.cwd?C(t.cwd):void 0,stderr:"ignore"})}async function N(t,n,s){t.catch(()=>{});let o,i=new Promise((r,e)=>{o=setTimeout(()=>e(new Error(`${s} timed out after ${n}ms`)),n)});try{return await Promise.race([t,i])}finally{clearTimeout(o)}}async function E(t){try{await t.close()}catch{}}function rt(t){let n=[],s=0,o=0,i=r=>{if(s>=S)return;let e=r;e.length>M&&(e=`${e.slice(0,M)}
|
|
2
|
+
[... truncated ${r.length-M} chars]`),s+e.length>S&&(e=`${e.slice(0,S-s)}
|
|
3
|
+
[... output truncated]`),s+=e.length,n.push({type:"text",text:e})};for(let r of Array.isArray(t)?t:[]){let e=r;if(e.type==="text"&&typeof e.text=="string")i(e.text);else if(e.type==="image"&&typeof e.data=="string")o<x?(n.push({type:"image",data:e.data,mimeType:typeof e.mimeType=="string"?e.mimeType:"image/png"}),o++):i(`[image omitted: exceeded ${x}-image limit]`);else if(e.type==="resource"&&e.resource){let u=e.resource;typeof u.text=="string"?i(u.text):i(`[resource ${u.uri??""} (${u.mimeType??"binary"}) omitted]`)}else e.type==="audio"?i(`[audio content (${typeof e.mimeType=="string"?e.mimeType:"?"}) omitted]`):i(`[unsupported MCP content: ${JSON.stringify(r).slice(0,500)}]`)}return n.length===0&&n.push({type:"text",text:"(tool returned no content)"}),n}async function ot(t,n,s,o,i,r,e,u){let m=nt(s,o),d=new k({name:D,version:H},{capabilities:{}});try{await N(d.connect(m),i,`MCP "${n}" connect`)}catch(c){throw await E(d),c}e.push({name:n,client:d});let p;try{p=await N(d.listTools(),i,`MCP "${n}" listTools`)}catch(c){throw await E(d),c}let f=p?.tools??[],g=0;for(let c of f)if(!(!c?.name||typeof c.name!="string"))try{let a=c.inputSchema&&typeof c.inputSchema=="object"?c.inputSchema:{type:"object",properties:{}},l=c.name,T=W(n,l,u);t.registerTool({name:T,label:`${n}: ${l}`,description:(c.description?.trim()||`MCP tool "${l}" from server "${n}".`)+` (MCP server: ${n})`,promptSnippet:`${T}: MCP tool from ${n}`,parameters:L.Unsafe(a),async execute(st,R,b,it,ct){let h={name:n,status:"connected",toolCount:0};try{let _=await d.callTool({name:l,arguments:R??{}},void 0,{signal:b??void 0,timeout:r}),y=rt(_.content);return _.isError?{content:[{type:"text",text:`MCP tool "${l}" reported an error:`},...y],details:h}:{content:y,details:h}}catch(_){let y=_,I=y?.name==="AbortError"?"cancelled":y?.message||"call failed";return{content:[{type:"text",text:`MCP tool "${l}" failed: ${I}.`}],details:h}}}}),g++}catch{}return g}async function Ct(t){if((process.env.REGNA_MCP_ENABLED??"").trim()==="0")return;let n=process.cwd(),s=et(n);if(s.size===0)return;let o=(process.env.REGNA_OFFLINE??"").trim()==="1",i=$(process.env.REGNA_MCP_TIMEOUT_MS,J,Z,q),r=$(process.env.REGNA_MCP_CALL_TIMEOUT_MS,B,V,K),e=[],u=new Set,m=[];await Promise.all([...s.entries()].map(async([p,f])=>{if(o&&P(f)){m.push({name:p,status:"skipped",toolCount:0,detail:"offline"});return}try{let g=await ot(t,p,f,o,i,r,e,u);m.push({name:p,status:"connected",toolCount:g})}catch(g){m.push({name:p,status:"failed",toolCount:0,detail:g?.message||"connect failed"})}}));let d=!1;t.on("session_shutdown",async()=>{d||(d=!0,await Promise.all(e.map(({client:p})=>E(p))))}),t.registerCommand("mcp",{description:"List configured MCP servers, their connection status, and tool counts.",handler:async(p,f)=>{if(m.length===0){f.ui.notify("No MCP servers configured. Add ~/.regna/mcp.json or ./.mcp.json (mcpServers).","info");return}let g=m.slice().sort((a,l)=>a.name.localeCompare(l.name)).map(a=>{let l=a.status==="connected"?"\u2713":a.status==="skipped"?"-":"\u2717",T=a.status==="connected"?`${a.toolCount} tools`:a.detail||a.status;return`${l} ${a.name}: ${T}`}),c=m.some(a=>a.status==="failed");f.ui.notify(`MCP servers:
|
|
4
|
+
${g.join(`
|
|
5
|
+
`)}`,c?"warning":"info")}})}export{Ct as default,C as expandEnv,et as loadServerConfigs,rt as mapToolContent,$ as normalizeMs,Y as parseServers,W as toolName};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperez/regna-code",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"description": "Regna Code. A terminal coding agent on Regna. Install with `npm i -g @hyperez/regna-code` and run `regna`. Works with the Regna cloud API and on-premise deployments.",
|
|
5
5
|
"license": "PolyForm-Noncommercial-1.0.0",
|
|
6
6
|
"private": false,
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@earendil-works/pi-coding-agent": "0.80.2",
|
|
36
36
|
"@earendil-works/pi-tui": "0.80.2",
|
|
37
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
37
38
|
"typebox": "^1.3.1"
|
|
38
39
|
},
|
|
39
40
|
"engines": {
|