@fui-org/fui-cli 1.0.3 → 1.0.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.
- package/README.md +33 -2
- package/dist/fui.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,13 +15,44 @@ Design: [docs/specs/2026-09-28-fui-cli-v1-design.md](docs/specs/2026-09-28-fui-c
|
|
|
15
15
|
|
|
16
16
|
## Install
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
### 1. Install Bun
|
|
19
|
+
|
|
20
|
+
`fui` runs on [Bun](https://bun.com) 1.4 or later. Skip this step if `bun --version` already prints 1.4 or later.
|
|
21
|
+
|
|
22
|
+
macOS and Linux:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
curl -fsSL https://bun.sh/install | bash
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
On macOS you can use Homebrew instead:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
brew install oven-sh/bun/bun
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Windows (PowerShell):
|
|
35
|
+
|
|
36
|
+
```powershell
|
|
37
|
+
powershell -c "irm bun.sh/install.ps1 | iex"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Open a new terminal so `PATH` picks up Bun, then check it:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
bun --version
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
To upgrade an older Bun, run `bun upgrade`.
|
|
47
|
+
|
|
48
|
+
### 2. Install fui
|
|
19
49
|
|
|
20
50
|
```bash
|
|
21
51
|
bun add -g @fui-org/fui-cli
|
|
52
|
+
fui --version
|
|
22
53
|
```
|
|
23
54
|
|
|
24
|
-
This puts `fui` on your `PATH
|
|
55
|
+
This puts `fui` on your `PATH`, in `~/.bun/bin` on macOS and Linux and in `%USERPROFILE%\.bun\bin` on Windows. To run it once without installing:
|
|
25
56
|
|
|
26
57
|
```bash
|
|
27
58
|
bunx --package @fui-org/fui-cli fui --help
|
package/dist/fui.js
CHANGED
|
@@ -74,7 +74,7 @@ ${t}`,e.severity==="block"?"hard":"soft")}function zi(e,t){let n=Di(t.schema),o=
|
|
|
74
74
|
${u.message}
|
|
75
75
|
likely the login borrowed from ${a} has no access to this database (other group); pass --borrow-from <project/alias> or use fui db add`)}let l=await _n(e,n,{alias:t.apiName,dbToken:c,apiDomain:o.apiDomain,sqlServer:r.SQLServer,database:r.DatabaseName,userToken:o.userToken,makeDefault:t.makeDefault,test:!1});return{notes:[...o.note?[o.note]:[],...l.notes,`sql server: ${r.SQLServer} database: ${r.DatabaseName} login borrowed from ${a} (not printed)`]}}async function ma(e,t){let n=await Dn(e),o=await cr(e.store,n,t),{apiDomain:s,userToken:r}=o.config;return{projectId:n,call:(i,a)=>Pn(s,r,i,a),target:{ModuleID:0,APIName:t??o.alias}}}async function ha(e,t,n){let{projectId:o,call:s,target:r}=await ma(e,n),a=(await s(t==="system"?"SM_SystemRight_Select":"SM_FunctionRight_Select",r)).data??[];return await ur(e.store.paths,o,r.APIName,t==="system"?{system:a}:{functions:a}),{apiName:r.APIName,rows:a}}async function fa(e,t,n){let{projectId:o,call:s,target:r}=await ma(e,n),i=t.kind==="system"?"SM_SystemRight_Select":"SM_FunctionRight_Select",a;if(t.kind==="system"){if(t.mode==="new"){let d=((await s(i,r)).data??[]).find((p)=>Number(p.SysRight)===t.sysRight);if(d)throw new h(`SystemRight ${t.sysRight} of "${r.APIName}" is already defined ("${String(d.Note??"")}"); edit: fui right system update ${t.sysRight} --note ...; remove: fui right system delete ${t.sysRight}`)}await s("SM_SystemRight_Update",{...r,SysRight:t.sysRight,Note:t.note??null,Delete:t.mode==="delete"?1:0});let u=`SystemRight ${t.sysRight}${t.note&&t.mode!=="delete"?` (${t.note})`:""}`;a=`ok ${t.mode==="new"?"created":t.mode==="update"?"saved":"deleted"} ${u} of "${r.APIName}"`}else await s("SM_FunctionRight_Update",{...r,FunctionID:t.functionId,FunctionCode:t.functionCode,FunctionName:t.functionName??null,Delete:t.mode==="delete"?1:0}),a=t.mode==="new"?`ok created FunctionRight code ${t.functionCode}${t.functionName?` (${t.functionName})`:""} for "${r.APIName}"`:t.mode==="update"?`ok saved FunctionRight ID ${t.functionId}: code ${t.functionCode}${t.functionName?` (${t.functionName})`:""} for "${r.APIName}"`:`ok deleted FunctionRight ID ${t.functionId} and its user assignments`;let c=await s(i,r).catch(()=>null),l=c?.data??[];if(c)await ur(e.store.paths,o,r.APIName,t.kind==="system"?{system:l}:{functions:l});return{apiName:r.APIName,notes:[a,`current list (${l.length}):`],rows:l}}var Dr={"api-domain":{type:"string"},"user-token":{type:"string"},"user-token-env":{type:"string"}};async function xr(e){return{apiDomain:f(e.values,"api-domain"),userToken:await Pe(f(e.values,"user-token"),f(e.values,"user-token-env"),"--user-token")}}function xn(e){k(`${e.join(`
|
|
76
76
|
`)}
|
|
77
|
-
`)}var lp={name:"db user-token",mcpName:"db_user_token_set",usage:"fui db user-token [--db ref] (--from <project/alias> | --token - | --token-env VAR) no source: list fingerprints",summary:"Save a userToken (Bearer for spAPI_* calls) into one connection; never prints tokens",options:{from:{type:"string"},token:{type:"string"},"token-env":{type:"string"}},async run(e){let t=await Pe(f(e.values,"token"),f(e.values,"token-env"),"--token"),n=f(e.values,"from");if(n&&t)throw new h("pass --from or --token/--token-env, not both");let o=await la(await z(e),{db:f(e.values,"db"),userToken:t,tokenSource:n});xn(o.notes)}},up={name:"db token-rebuild",mcpName:"db_token_rebuild",usage:"fui db token-rebuild [--db ref] --uid <login> (--pwd - | --pwd-env VAR)",summary:"Rebuild a connection's dbToken after a UID/PWD change (sqlServer/database from the saved connection), test, save",options:{uid:{type:"string"},pwd:{type:"string"},"pwd-env":{type:"string"}},async run(e){let t=f(e.values,"uid");if(!t)throw new h("missing --uid");let n=await Pe(f(e.values,"pwd"),f(e.values,"pwd-env"),"--pwd");if(!n)throw new h("missing --pwd - or --pwd-env VAR");xn((await ca(await z(e),{db:f(e.values,"db"),uid:t,password:n})).notes)}},dp={name:"db alias list",mcpName:"db_alias_list",usage:"fui db alias list [--search text] [--api-domain host] [--user-token-env VAR]",summary:"Databases you may manage on the acc system (APIName, SQLServer, DatabaseName); read-only",options:{search:{type:"string"},...Dr},async run(e){let t=await ua(await z(e),{...await xr(e),search:f(e.values,"search")});for(let n of t.notes)T(`# ${n}`);if(t.rows.length>0)k(X(t.rows,e.render))}},pp={name:"db alias new",mcpName:"db_alias_new",usage:"fui db alias new <apiName> --module-name N --sql-server S --database D --username U (--password - | --password-env VAR) [--module-id N]",summary:"Register a new database as a tAPI alias on acc (ask the user first; app login, never db_owner)",options:{"module-name":{type:"string"},"sql-server":{type:"string"},database:{type:"string"},username:{type:"string"},password:{type:"string"},"password-env":{type:"string"},"module-id":{type:"string"},...Dr},async run(e){let{values:t}=e,n=e.positionals[0],o=f(t,"module-name"),s=f(t,"sql-server"),r=f(t,"database"),i=f(t,"username");if(!n||!o||!s||!r||!i)throw new h("need <apiName>, --module-name, --sql-server, --database and --username");let a=await Pe(f(t,"password"),f(t,"password-env"),"--password");if(!a)throw new h("missing --password - or --password-env VAR");let c=f(t,"module-id"),l=c===void 0?void 0:Number(c);if(l!==void 0&&!Number.isInteger(l))throw new h("--module-id must be an integer");let u=await da(await z(e),{...await xr(e),apiName:n,moduleName:o,sqlServer:s,database:r,username:i,password:a,moduleId:l});xn(u.notes)}},mp={name:"db add-by-name",mcpName:"db_connect_by_name",usage:"fui db add-by-name <apiName> [-p P] [--borrow-from <project/alias>] [--default] [--api-domain host] [--user-token-env VAR]",summary:"Connect by alias: look up SQLServer/Database on acc, borrow a SQL login, test, save, fetch schema",options:{"borrow-from":{type:"string"},default:{type:"boolean"},...Dr},async run(e){let t=e.positionals[0];if(!t)throw new h("missing <apiName>; see: fui db alias list");let n=await pa(await z(e),{...await xr(e),apiName:t,borrowFrom:f(e.values,"borrow-from"),makeDefault:e.values.default===!0});xn(n.notes)}};function ya(e){return e.map((t)=>({sysRight:String(t.SysRight??""),note:String(t.Note??"")}))}function ba(e){return e.map((t)=>({functionId:String(t.FunctionID??""),code:String(t.FunctionCode??""),name:String(t.FunctionName??""),enabled:t.Enable===!1||t.Enable===0?"no":"yes"}))}var ka={"api-name":{type:"string"}};function _r(e,t,n,o){let s=e===void 0?Number.NaN:Number(e);if(!Number.isInteger(s)||!n(s))throw new h(`${t} must be ${o}`);return s}function ga(e,t,n){if(e!==void 0&&e.length>t)throw new h(`${n} is at most ${t} characters`);return e}function wa(e){return{name:`right ${e} list`,mcpName:`right_${e}_list`,usage:`fui right ${e} list [-p P] [--api-name alias]`,summary:e==="system"?"SystemRight levels (0-9, 9 = Project Admin) of a project on acc; refreshes _db/rights.json":"FunctionRight codes of a project on acc (vueData.user.FunctionRight); refreshes _db/rights.json",options:ka,async run(t){let{apiName:n,rows:o}=await ha(await z(t),e,f(t.values,"api-name"));if(T(`# ${e==="system"?"SystemRight":"FunctionRight"} of "${n}": ${o.length}`),o.length===0){T(`# none defined; create one: fui right ${e} new ...`);return}k(X(e==="system"?ya(o):ba(o),t.render))}}}function Qt(e,t){let n=e==="system"?`fui right system ${t} <0-9>${t==="delete"?"":" [--note text]"} [--api-name alias]`:t==="new"?"fui right function new --code N [--name text] [--api-name alias]":t==="update"?"fui right function update <functionId> --code N [--name text] [--api-name alias]":"fui right function delete <functionId> [--code N] [--api-name alias]",o={system:{new:"Define a SystemRight level that does not exist yet (server pre-check; 9 is always Project Admin)",update:"Change the note of an existing SystemRight level",delete:"DELETE a SystemRight level (ask the user first; the server refuses while users hold it)"},function:{new:"Create a FunctionRight code (the server assigns FunctionID; duplicates rejected)",update:"Edit an existing FunctionRight by its FunctionID",delete:"DELETE a FunctionRight and every user assignment of it (ask the user first)"}};return{name:`right ${e} ${t}`,mcpName:`right_${e}_${t}`,usage:n,summary:o[e][t],options:{...ka,note:{type:"string"},code:{type:"string"},name:{type:"string"}},async run(s){let{values:r,positionals:i}=s,a;if(e==="system")a={kind:e,mode:t,sysRight:_r(i[0],"<level>",(l)=>l>=0&&l<=9,"an integer 0-9"),note:t==="delete"?void 0:ga(f(r,"note"),50,"--note")};else{let l=f(r,"code");a={kind:e,mode:t,functionId:t==="new"?0:_r(i[0],"<functionId>",(u)=>u>0,"a positive integer"),functionCode:t==="delete"&&l===void 0?0:_r(l,"--code",()=>!0,"an integer"),functionName:t==="delete"?void 0:ga(f(r,"name"),100,"--name")}}let c=await fa(await z(s),a,f(r,"api-name"));xn(c.notes),k(X(e==="system"?ya(c.rows):ba(c.rows),s.render))}}}var va=[lp,up,dp,pp,mp,wa("system"),Qt("system","new"),Qt("system","update"),Qt("system","delete"),wa("function"),Qt("function","new"),Qt("function","update"),Qt("function","delete")];import{mkdir as kp}from"fs/promises";import{realpathSync as fp}from"fs";import{join as gp,sep as Zt}from"path";var je="1.0.
|
|
77
|
+
`)}var lp={name:"db user-token",mcpName:"db_user_token_set",usage:"fui db user-token [--db ref] (--from <project/alias> | --token - | --token-env VAR) no source: list fingerprints",summary:"Save a userToken (Bearer for spAPI_* calls) into one connection; never prints tokens",options:{from:{type:"string"},token:{type:"string"},"token-env":{type:"string"}},async run(e){let t=await Pe(f(e.values,"token"),f(e.values,"token-env"),"--token"),n=f(e.values,"from");if(n&&t)throw new h("pass --from or --token/--token-env, not both");let o=await la(await z(e),{db:f(e.values,"db"),userToken:t,tokenSource:n});xn(o.notes)}},up={name:"db token-rebuild",mcpName:"db_token_rebuild",usage:"fui db token-rebuild [--db ref] --uid <login> (--pwd - | --pwd-env VAR)",summary:"Rebuild a connection's dbToken after a UID/PWD change (sqlServer/database from the saved connection), test, save",options:{uid:{type:"string"},pwd:{type:"string"},"pwd-env":{type:"string"}},async run(e){let t=f(e.values,"uid");if(!t)throw new h("missing --uid");let n=await Pe(f(e.values,"pwd"),f(e.values,"pwd-env"),"--pwd");if(!n)throw new h("missing --pwd - or --pwd-env VAR");xn((await ca(await z(e),{db:f(e.values,"db"),uid:t,password:n})).notes)}},dp={name:"db alias list",mcpName:"db_alias_list",usage:"fui db alias list [--search text] [--api-domain host] [--user-token-env VAR]",summary:"Databases you may manage on the acc system (APIName, SQLServer, DatabaseName); read-only",options:{search:{type:"string"},...Dr},async run(e){let t=await ua(await z(e),{...await xr(e),search:f(e.values,"search")});for(let n of t.notes)T(`# ${n}`);if(t.rows.length>0)k(X(t.rows,e.render))}},pp={name:"db alias new",mcpName:"db_alias_new",usage:"fui db alias new <apiName> --module-name N --sql-server S --database D --username U (--password - | --password-env VAR) [--module-id N]",summary:"Register a new database as a tAPI alias on acc (ask the user first; app login, never db_owner)",options:{"module-name":{type:"string"},"sql-server":{type:"string"},database:{type:"string"},username:{type:"string"},password:{type:"string"},"password-env":{type:"string"},"module-id":{type:"string"},...Dr},async run(e){let{values:t}=e,n=e.positionals[0],o=f(t,"module-name"),s=f(t,"sql-server"),r=f(t,"database"),i=f(t,"username");if(!n||!o||!s||!r||!i)throw new h("need <apiName>, --module-name, --sql-server, --database and --username");let a=await Pe(f(t,"password"),f(t,"password-env"),"--password");if(!a)throw new h("missing --password - or --password-env VAR");let c=f(t,"module-id"),l=c===void 0?void 0:Number(c);if(l!==void 0&&!Number.isInteger(l))throw new h("--module-id must be an integer");let u=await da(await z(e),{...await xr(e),apiName:n,moduleName:o,sqlServer:s,database:r,username:i,password:a,moduleId:l});xn(u.notes)}},mp={name:"db add-by-name",mcpName:"db_connect_by_name",usage:"fui db add-by-name <apiName> [-p P] [--borrow-from <project/alias>] [--default] [--api-domain host] [--user-token-env VAR]",summary:"Connect by alias: look up SQLServer/Database on acc, borrow a SQL login, test, save, fetch schema",options:{"borrow-from":{type:"string"},default:{type:"boolean"},...Dr},async run(e){let t=e.positionals[0];if(!t)throw new h("missing <apiName>; see: fui db alias list");let n=await pa(await z(e),{...await xr(e),apiName:t,borrowFrom:f(e.values,"borrow-from"),makeDefault:e.values.default===!0});xn(n.notes)}};function ya(e){return e.map((t)=>({sysRight:String(t.SysRight??""),note:String(t.Note??"")}))}function ba(e){return e.map((t)=>({functionId:String(t.FunctionID??""),code:String(t.FunctionCode??""),name:String(t.FunctionName??""),enabled:t.Enable===!1||t.Enable===0?"no":"yes"}))}var ka={"api-name":{type:"string"}};function _r(e,t,n,o){let s=e===void 0?Number.NaN:Number(e);if(!Number.isInteger(s)||!n(s))throw new h(`${t} must be ${o}`);return s}function ga(e,t,n){if(e!==void 0&&e.length>t)throw new h(`${n} is at most ${t} characters`);return e}function wa(e){return{name:`right ${e} list`,mcpName:`right_${e}_list`,usage:`fui right ${e} list [-p P] [--api-name alias]`,summary:e==="system"?"SystemRight levels (0-9, 9 = Project Admin) of a project on acc; refreshes _db/rights.json":"FunctionRight codes of a project on acc (vueData.user.FunctionRight); refreshes _db/rights.json",options:ka,async run(t){let{apiName:n,rows:o}=await ha(await z(t),e,f(t.values,"api-name"));if(T(`# ${e==="system"?"SystemRight":"FunctionRight"} of "${n}": ${o.length}`),o.length===0){T(`# none defined; create one: fui right ${e} new ...`);return}k(X(e==="system"?ya(o):ba(o),t.render))}}}function Qt(e,t){let n=e==="system"?`fui right system ${t} <0-9>${t==="delete"?"":" [--note text]"} [--api-name alias]`:t==="new"?"fui right function new --code N [--name text] [--api-name alias]":t==="update"?"fui right function update <functionId> --code N [--name text] [--api-name alias]":"fui right function delete <functionId> [--code N] [--api-name alias]",o={system:{new:"Define a SystemRight level that does not exist yet (server pre-check; 9 is always Project Admin)",update:"Change the note of an existing SystemRight level",delete:"DELETE a SystemRight level (ask the user first; the server refuses while users hold it)"},function:{new:"Create a FunctionRight code (the server assigns FunctionID; duplicates rejected)",update:"Edit an existing FunctionRight by its FunctionID",delete:"DELETE a FunctionRight and every user assignment of it (ask the user first)"}};return{name:`right ${e} ${t}`,mcpName:`right_${e}_${t}`,usage:n,summary:o[e][t],options:{...ka,note:{type:"string"},code:{type:"string"},name:{type:"string"}},async run(s){let{values:r,positionals:i}=s,a;if(e==="system")a={kind:e,mode:t,sysRight:_r(i[0],"<level>",(l)=>l>=0&&l<=9,"an integer 0-9"),note:t==="delete"?void 0:ga(f(r,"note"),50,"--note")};else{let l=f(r,"code");a={kind:e,mode:t,functionId:t==="new"?0:_r(i[0],"<functionId>",(u)=>u>0,"a positive integer"),functionCode:t==="delete"&&l===void 0?0:_r(l,"--code",()=>!0,"an integer"),functionName:t==="delete"?void 0:ga(f(r,"name"),100,"--name")}}let c=await fa(await z(s),a,f(r,"api-name"));xn(c.notes),k(X(e==="system"?ya(c.rows):ba(c.rows),s.render))}}}var va=[lp,up,dp,pp,mp,wa("system"),Qt("system","new"),Qt("system","update"),Qt("system","delete"),wa("function"),Qt("function","new"),Qt("function","update"),Qt("function","delete")];import{mkdir as kp}from"fs/promises";import{realpathSync as fp}from"fs";import{join as gp,sep as Zt}from"path";var je="1.0.4";var On="@fui-org/fui-cli",wp=3600000,yp=5000;function Sa(e=Bun.env){return gp(et(e),"..","update.json")}async function $a(e=Bun.env){try{let t=await Bun.file(Sa(e)).json();if(t&&typeof t==="object"&&!Array.isArray(t))return t}catch{}return{}}async function Nt(e,t=Bun.env){await Bun.write(Sa(t),`${JSON.stringify(e,null,2)}
|
|
78
78
|
`)}function ja(e=Bun.main){let t;try{t=fp(e)}catch{return null}let n=`${Zt}install${Zt}global${Zt}node_modules${Zt}@fui-org${Zt}fui-cli${Zt}`,o=t.indexOf(n);return o<0?null:t.slice(0,o+n.length-1)}async function Or(e=Bun.env){let t=e.FUI_AUTO_UPDATE?.trim().toLowerCase();if(t)return!["0","off","false","no"].includes(t);try{return(await dt(e))["auto-update"]!=="off"}catch{return!0}}async function Mr(e=Bun.env){let t=(e.FUI_UPDATE_REGISTRY||"https://registry.npmjs.org").replace(/\/+$/,""),n=await fetch(`${t}/${On.replace("/","%2F")}/latest`,{signal:AbortSignal.timeout(yp),headers:{accept:"application/json"}});if(!n.ok)throw Error(`registry answered HTTP ${n.status}`);let o=await n.json();if(typeof o.version!=="string")throw Error("registry answer has no version");return o.version}function Fr(e,t=je){return Bun.semver.order(e,t)===1}async function bp(e){let t=await Bun.$`${process.execPath} add -g ${`${On}@${e}`}`.quiet().nothrow();return{ok:t.exitCode===0,output:`${t.stdout}${t.stderr}`.trim()}}async function Lr(e=Bun.env){let t=await $a(e),n=new Date().toISOString(),o;try{o=await Mr(e)}catch(r){throw await Nt({...t,checkedAt:n,error:r.message},e),r}if(!Fr(o))return await Nt({...t,checkedAt:n,latest:o,error:void 0},e),{latest:o,action:"current"};if(!ja())return await Nt({...t,checkedAt:n,latest:o,error:void 0},e),{latest:o,action:"manual",detail:`bun add -g ${On}@${o}`};let s=await bp(o);if(!s.ok)return await Nt({...t,checkedAt:n,latest:o,error:s.output.slice(-500)},e),{latest:o,action:"failed",detail:s.output};return await Nt({checkedAt:n,latest:o,updatedFrom:je,updatedTo:o,noticeShown:!1},e),{latest:o,action:"installed"}}async function Ia(e=Bun.env){if(!ja()||!await Or(e))return null;let t=await $a(e),n=null;if(t.updatedTo===je&&t.noticeShown===!1)n=`# fui updated ${t.updatedFrom} -> ${je}; refresh installed skills: fui skill install`,t.noticeShown=!0,await Nt(t,e);let o=t.checkedAt?Date.parse(t.checkedAt):0;if(Date.now()-o<wp)return n;return await Nt({...t,checkedAt:new Date().toISOString()},e),Bun.spawn([process.execPath,Bun.main,"update","--background"],{stdio:["ignore","ignore","ignore"],env:{...e,FUI_AUTO_UPDATE:"off"}}).unref(),n}function Ca(e){let t=e[0];if(!t)throw new h(`missing <key>; keys: ${no.join(", ")}`);if(!no.includes(t))throw new h(`unknown key "${t}"; keys: ${no.join(", ")}`);return t}async function vp(){let e=await Or(),t=Bun.env.FUI_AUTO_UPDATE?.trim(),n=(await dt())["auto-update"],o=t?"env":n?"config":"default",s=t?"FUI_AUTO_UPDATE":n?et():"built-in (global bun installs only)";return{key:"auto-update",value:e?"on":"off",source:o,from:s}}var Sp={name:"config",usage:"fui config",summary:"Show settings with their effective value and source",async run({workdir:e,render:t}){let{base:n,token:o}=await oo();T(`# config file: ${et()}`),k(X([{key:"workdir",value:e.path,source:e.source,from:e.detail},{key:"api-base",value:n.value??"",source:n.source,from:n.detail},{key:"api-token",value:o.value?"(set)":"",source:o.source,from:o.detail},await vp()],t))}},$p={name:"config set",usage:"fui config set workdir <path> | api-base <url> | api-token - | auto-update on|off",summary:"Save a setting to the fui config file (api-token only from stdin)",async run({positionals:e}){let t=Ca(e),n=e[1];if(!n)throw new h(`missing <value> for ${t}`);let o;if(t==="workdir")o=qt(n),await kp(o,{recursive:!0});else if(t==="auto-update"){if(n!=="on"&&n!=="off")throw new h("auto-update takes on or off");o=n}else if(t==="api-token")o=await Pe(n,void 0,"api-token");else o=n.trim().replace(/\/+$/,"");let s=await dt();s[t]=o;let r=await Go(s),i={workdir:"FUI_MCP_WORKDIR","api-base":"FUI_API_BASE","api-token":"FUI_API_TOKEN","auto-update":"FUI_AUTO_UPDATE"}[t];if(Bun.env[i])T(`# note: ${i} is set in this shell and overrides the config file`);k(`set ${t}${t==="api-token"?"":`=${o}`} in ${r}
|
|
79
79
|
`)}},jp={name:"config unset",usage:"fui config unset <workdir|api-base|api-token|auto-update>",summary:"Remove a setting from the fui config file",async run({positionals:e}){let t=Ca(e),n=await dt();delete n[t];let o=await Go(n);k(`unset ${t} in ${o}
|
|
80
80
|
`)}},Ra=[Sp,$p,jp];var Ip={name:"db list",mcpName:"db_config_read",usage:"fui db list [-p project]",summary:"List connections across the workspace (no secrets)",async run({store:e,values:t,render:n}){let o=f(t,"project"),s=o?[or(o)]:[...new Set([...await e.listProjects(),...await e.listLegacyProjects()])].sort(),r=[];for(let i of s){let a=await e.load(i),c=await e.loadLegacy(i),l=c?.apiName??"legacy";if(c&&!me(a,l))r.push({db:`${i}/${l}`,engine:"legacy",default:"",apiDomain:c.apiDomain??"",database:c.database??"",userToken:c.userToken?"yes":"no"}),T(`# ${i}: _db/config.json is the pre-1.4 format and unused; run: fui db import-legacy -p ${i}`);for(let[u,d]of Object.entries(a.connections)){let p="invalid",m=d.database??"";try{if(d.dbToken){let w=io(d.dbToken);p=w.engine,m||=w.database}}catch{}r.push({db:`${i}/${u}`,engine:p,default:a.default===u?"*":"",apiDomain:d.apiDomain??"",database:m,userToken:d.userToken?"yes":"no"})}}if(r.length===0){T("no connections; add one: fui db add <alias> -p <project> --token -");return}k(X(r,n))}},Cp={name:"db add",mcpName:"db_connect",usage:`fui db add <alias> -p <project> (--token - | --token-env VAR | --conn - | --conn-env VAR)
|