@hyperez/regna-code 0.2.4 → 0.2.5
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 +3 -7
- package/dist/bin/regna.mjs +23 -25
- package/dist/extensions/provider.js +1 -1
- package/package.json +1 -1
- package/dist/extensions/model.js +0 -1
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ Then just run it. On first launch it asks how you want to connect:
|
|
|
23
23
|
2) Offline - air-gapped / self-hosted gateway
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
- **Online**: opens https://regnax.ai/console, you paste an API key once.
|
|
26
|
+
- **Online**: opens https://regnax.ai/console, you paste an API key once. The cloud serves a single model, `regna-1`.
|
|
27
27
|
- **Offline**: you enter your internal gateway URL (OpenAI-compatible `/v1`) and key, then pick a default model from whatever the gateway serves. Offline runs with no engine self-network and the egress guard enforced.
|
|
28
28
|
|
|
29
29
|
Your choice and credentials are stored at `~/.regna/auth.json`. After that:
|
|
@@ -49,10 +49,8 @@ For CI or scripted use, set `REGNA_API_KEY` directly; it takes priority over the
|
|
|
49
49
|
|---|---|---|
|
|
50
50
|
| `REGNA_API_KEY` | (none) | Regna API key. Optional once you have run `regna login`. When set, it overrides the stored credential (use for CI). |
|
|
51
51
|
| `REGNA_BASE_URL` | `https://regnax.ai/v1` | Regna API base URL (OpenAI-compatible). Point this at a self-hosted endpoint for on-premise use. |
|
|
52
|
-
| `REGNA_MODEL` |
|
|
53
|
-
| `
|
|
54
|
-
| `REGNA_GENERAL_MODEL` | (none) | Exact model id that `/regna-general` selects. |
|
|
55
|
-
| `REGNA_EXPOSE_ALIASES` | (unset) | `1` also exposes path-style (slash) model ids. Hidden by default. Ids pinned via `REGNA_MODEL`/`REGNA_CODER_MODEL`/`REGNA_GENERAL_MODEL` are always shown. |
|
|
52
|
+
| `REGNA_MODEL` | (auto) | Starting model. By default the current single cloud model is detected from the gateway automatically; set this to pin a specific id. |
|
|
53
|
+
| `REGNA_EXPOSE_ALIASES` | (unset) | `1` also exposes path-style (slash) model ids. Hidden by default. The id pinned via `REGNA_MODEL` is always shown. |
|
|
56
54
|
| `REGNA_POLICY` | `off` | Network egress guard: `off` / `warn` (notify, allow) / `enforce` (block external network tools). Set `enforce` for locked-down or air-gapped use. |
|
|
57
55
|
| `REGNA_OFFLINE` | (unset) | `1` runs fully offline: the runtime skips all self-network, including the one-time download of search helpers (`fd`/`ripgrep`). They fall back to the built-in search. Use for air-gapped installs. |
|
|
58
56
|
| `REGNA_ALLOW_HOSTS` | (none) | Extra allowed hosts (comma-separated) when the policy is on. URL or `host:port` accepted. |
|
|
@@ -70,8 +68,6 @@ For CI or scripted use, set `REGNA_API_KEY` directly; it takes priority over the
|
|
|
70
68
|
| `regna logout` | Remove stored credentials. |
|
|
71
69
|
| `/exit` | Exit Regna Code from inside a session. |
|
|
72
70
|
| `/compact` | Compact the session context (also runs automatically as it fills). |
|
|
73
|
-
| `/regna-coder` | Switch to a coding model (prefers an id containing `coder`, else default). |
|
|
74
|
-
| `/regna-general` | Switch to a general model (prefers `instruct`, else default). |
|
|
75
71
|
| `/regna-brand` | Toggle the Regna Code header/title branding. |
|
|
76
72
|
| `/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`. |
|
|
77
73
|
|
package/dist/bin/regna.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{spawn as
|
|
2
|
+
import{spawn as $}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 I,writeFileSync as j,mkdirSync as b,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"),x=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"),P=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(I(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
|
|
@@ -13,8 +13,6 @@ Auth:
|
|
|
13
13
|
regna logout remove stored credentials
|
|
14
14
|
|
|
15
15
|
In-session commands:
|
|
16
|
-
/regna-coder switch to a coding model
|
|
17
|
-
/regna-general switch to a general model
|
|
18
16
|
/regna-brand toggle the Regna Code branding
|
|
19
17
|
/regna-docs <q> document-grounded query (requires REGNA_DOCS_ENABLED=1)
|
|
20
18
|
/exit exit Regna Code
|
|
@@ -23,46 +21,46 @@ In-session commands:
|
|
|
23
21
|
Environment:
|
|
24
22
|
REGNA_API_KEY Regna API key (optional once logged in)
|
|
25
23
|
REGNA_BASE_URL Regna API base URL (default https://regnax.ai/v1)
|
|
26
|
-
REGNA_MODEL starting model (
|
|
24
|
+
REGNA_MODEL starting model (overrides the auto-detected gateway model)
|
|
27
25
|
REGNA_POLICY network egress guard: off | warn | enforce
|
|
28
26
|
|
|
29
27
|
Docs: https://github.com/HyperEZ/regna-code
|
|
30
|
-
`;function
|
|
31
|
-
`);try{
|
|
32
|
-
Regna Code ${
|
|
28
|
+
`;function V(){try{let e=JSON.parse(I(E,"utf8"));return e&&typeof e.apiKey=="string"?e:null}catch{return null}}function W(e){b(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]];$(t,n,{stdio:"ignore",detached:!0}).unref()}catch{}}async function G(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
|
+
Regna Code ${_()}
|
|
33
31
|
Choose how to connect:
|
|
34
32
|
|
|
35
33
|
1) Online - Regna cloud (regnax.ai)
|
|
36
34
|
2) Offline - air-gapped / self-hosted gateway
|
|
37
35
|
|
|
38
|
-
`),(await e(" Select [1]: ")||"").trim()==="2"?"offline":"online"}async function
|
|
36
|
+
`),(await e(" Select [1]: ")||"").trim()==="2"?"offline":"online"}async function se(e){let t=k,n=Q(t);process.stdout.write(`
|
|
39
37
|
Online mode (Regna cloud).
|
|
40
38
|
1) Get an API key at ${n}
|
|
41
39
|
2) Paste it below.
|
|
42
40
|
|
|
43
|
-
`),
|
|
44
|
-
`),process.exit(1));let{status:s}=await
|
|
45
|
-
`),process.exit(1)),{mode:"online",baseUrl:t,apiKey:r}}async function
|
|
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 G(t,r);return s==="invalid"&&(process.stderr.write(` That key was rejected. Run: regna login
|
|
43
|
+
`),process.exit(1)),{mode:"online",baseUrl:t,apiKey:r}}async function re(e){process.stdout.write(`
|
|
46
44
|
Offline mode (air-gapped).
|
|
47
45
|
Point Regna Code at your internal gateway (OpenAI-compatible /v1).
|
|
48
46
|
|
|
49
|
-
`);let t=(await e(" Gateway URL [http://localhost:8077/v1]: ")||"").trim(),n=
|
|
50
|
-
`),process.exit(1));let{status:s,ids:o}=await
|
|
51
|
-
`),process.exit(1));let
|
|
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 G(n,r);s==="invalid"&&(process.stderr.write(` That key was rejected by the gateway. Run: regna login
|
|
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(`
|
|
52
50
|
Models served by the gateway:
|
|
53
|
-
`),
|
|
54
|
-
`));let
|
|
55
|
-
Default model [1]: `)||"").trim(),
|
|
56
|
-
`);return{mode:"offline",baseUrl:n,apiKey:r,model:
|
|
51
|
+
`),c.forEach((D,F)=>process.stdout.write(` ${F+1}) ${D}
|
|
52
|
+
`));let y=(await e(`
|
|
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 O(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(`
|
|
57
55
|
Saved. Mode: ${s.mode}${s.model?`, default model: ${s.model}`:""}.
|
|
58
56
|
|
|
59
|
-
`),s}finally{n()}}(h("--help","-h")||
|
|
60
|
-
`),process.exit(0));if(
|
|
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 O(e),process.exit(0)}u[0]==="logout"&&(process.stdout.write(Z()?`Logged out.
|
|
61
59
|
`:`Not logged in.
|
|
62
|
-
`),process.exit(0));var
|
|
63
|
-
`),process.exit(1)));var
|
|
64
|
-
`),process.exit(1));for(let[,s]of n)
|
|
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 O(),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",S=(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(S,f)||l?.model||H);process.env.REGNA_API_KEY=f;process.env.REGNA_BASE_URL=S;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"],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(x)&&p.push("--theme",x);h("--system-prompt")||(m(R)||(process.stderr.write(`[regna] Missing required prompt: APPEND_SYSTEM.md (${R}). Install is corrupted. Aborting.
|
|
65
63
|
(To set the prompt yourself on purpose, run with --system-prompt.)
|
|
66
|
-
`),process.exit(1)),
|
|
64
|
+
`),process.exit(1)),p.push("--append-system-prompt",`@${R}`));h("--model","-m")||p.push("--model",w);p.push(...u);try{b(P,{recursive:!0})}catch{}var C={...process.env,PI_CODING_AGENT_DIR:P};process.env.REGNA_OFFLINE==="1"&&(C.PI_OFFLINE="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=$(le,[...de,...p],{stdio:"inherit",env:C});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.
|
|
67
65
|
`),process.exit(127)),process.stderr.write(`[regna] Failed to start the runtime: ${e?.message??String(e)}
|
|
68
|
-
`),process.exit(1)});
|
|
66
|
+
`),process.exit(1)});T.on("exit",(e,t)=>{if(t){process.kill(process.pid,t);return}process.exit(e??0)});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var E="regna",_="https://regnax.ai/v1";var p=/^regna-\d+$/,A=["regna-1"],R={"regna-1":"Regna 1"},m={"regna-1":1e6},h={"regna-1":32768},v=1e6,x=32768;function M(o){let s=/^regna-(\d+)$/.exec(o.toLowerCase());return s?`Regna ${s[1]}`:`Regna \xB7 ${o}`}var T=512*1024,I=24,L=200;function P(){let o=(process.env.REGNA_BASE_URL??"").trim(),s=o===""?_:o,n;try{n=new URL(s)}catch{return _}if(n.protocol!=="http:"&&n.protocol!=="https:")return _;let c=`${n.origin}${n.pathname}`.replace(/\/+$/,"");return/\/v\d+$/.test(c)?c:`${c}/v1`}function S(o){try{return/(^|\.)regnax\.ai$/i.test(new URL(o).hostname)}catch{return!1}}function N(o){let s=o.id,n=s.toLowerCase(),c=n==="default"||n==="current"||n==="auto",a=p.test(n),u=/qwq|qwen3|think|reason/.test(n),t=parseInt((process.env.REGNA_CONTEXT_WINDOW??"").trim(),10),d=typeof o.contextWindow=="number"&&o.contextWindow>0?o.contextWindow:void 0,g=Number.isFinite(t)&&t>0?t:d??m[n]??(a?v:32768),l=h[n]??(a?x:8192);return{id:s,name:R[n]??(a?M(s):c?"Regna (active model)":`Regna \xB7 ${s}`),reasoning:u,input:["text"],cost:{input:0,output:0,cacheRead:0,cacheWrite:0},contextWindow:g,maxTokens:l}}async function y(o,s){let n=new AbortController,c=setTimeout(()=>n.abort(),4e3);try{let a=await fetch(`${o}/models`,{headers:{Authorization:`Bearer ${s}`},signal:n.signal});if(!a.ok)return[];let u=await a.text();if(u.length>T)return[];let t;try{t=JSON.parse(u)}catch{return[]}let d=Array.isArray(t.data)?t.data:[],g=new Set,l=[];for(let i of d){let r=i&&typeof i.id=="string"?i.id:"";if(r.length===0||r.length>L||g.has(r))continue;g.add(r);let w=i&&typeof i.context_window=="number"&&i.context_window>0?i.context_window:void 0;if(l.push({id:r,contextWindow:w}),l.length>=I)break}return l}catch{return[]}finally{clearTimeout(c)}}async function O(o){let s=P(),n=(process.env.REGNA_API_KEY??"").trim(),c=(process.env.REGNA_EXPOSE_ALIASES??"").trim()==="1",a=n?await y(s,n):[],u=new Map(a.map(e=>[e.id,e.contextWindow])),t=a.map(e=>e.id),d=new Set;(e=>{let f=(e??"").trim();f&&d.add(f.startsWith(`${E}/`)?f.slice(E.length+1):f)})(process.env.REGNA_MODEL),c||(t=t.filter(e=>e==="default"||!e.includes("/")||d.has(e)));let l=S(s),i=t.filter(e=>p.test(e)).sort(),r;if(l){r=i.length>0?i.slice():[...A];for(let e of d)t.includes(e)&&!r.includes(e)&&r.push(e)}else if(i.length>0){r=i.slice();for(let e of d)t.includes(e)&&!r.includes(e)&&r.push(e)}else t.includes("default")||t.unshift("default"),r=t;!t.some(e=>e!=="default")&&!l&&console.warn(`[regna] Model discovery failed or REGNA_API_KEY is unset. Set REGNA_API_KEY and run /reload. (base=${s})`),o.registerProvider(E,{name:"Regna",baseUrl:s,apiKey:"$REGNA_API_KEY",api:"openai-completions",models:r.map(e=>N({id:e,contextWindow:u.get(e)}))})}export{O as default};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperez/regna-code",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
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,
|
package/dist/extensions/model.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
var l="regna",f={coder:["regna-max","regna-pro","regna-basic"],general:["regna-pro","regna-basic","regna-max"]};function u(r,c,i){if(r.length===0)return;if(i&&r.includes(i))return i;for(let n of f[c])if(r.includes(n))return n;let d=(n,s)=>n.toLowerCase().includes(s),o=r.find(n=>d(n,"coder"));if(c==="coder")return o??(r.includes("default")?"default":r[0]);let e=r.find(n=>d(n,"instruct")&&!d(n,"coder"));return e||(r.includes("default")?"default":r.find(n=>n!==o)??r[0])}function E(r){let c={coder:process.env.REGNA_CODER_MODEL?.trim()||void 0,general:process.env.REGNA_GENERAL_MODEL?.trim()||void 0},i=!1,d=async(o,e)=>{let n=e.modelRegistry.getAll().filter(t=>t.provider===l).map(t=>t.id);if(n.length===0){e.ui.notify("No regna provider models. Check the provider extension and REGNA_API_KEY.","warning");return}let s=c[o];if(s&&!n.includes(s)){let t=o==="coder"?"REGNA_CODER_MODEL":"REGNA_GENERAL_MODEL";e.ui.notify(`${t}='${s}' is not in the registered list; ignoring. Available: ${n.join(", ")}`,"warning")}let a=u(n,o,s),g=a?e.modelRegistry.find(l,a):void 0;if(!g){e.ui.notify(`Could not find a ${o} model (${l}/${a??"?"}).`,"warning");return}if(i=!0,!await r.setModel(g))i=!1,e.ui.notify(`Switch failed (API key may be missing): ${l}/${a}`,"warning");else{let t=a==="default"?" (active model)":"";e.ui.notify(`Model set: ${l}/${a}${t}`,"info")}};r.registerCommand("regna-coder",{description:"Switch to a Regna coding model (/regna-coder)",handler:async(o,e)=>d("coder",e)}),r.registerCommand("regna-general",{description:"Switch to a Regna general model (/regna-general)",handler:async(o,e)=>d("general",e)}),r.on("model_select",async(o,e)=>{if(i){i=!1;return}o.source!=="restore"&&o.model.provider===l&&e.ui.notify(`Regna model: ${o.model.id}`,"info")})}export{E as default,u as pickRegnaModelId};
|