@fugood/buttress-server 2.26.0-beta.4 → 2.26.0-beta.9
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/lib/agent/client.d.ts +12 -0
- package/lib/cli-DrbWX4ea.mjs +22 -0
- package/lib/client-BCBBen9i.mjs +8 -0
- package/lib/index.mjs +59 -59
- package/lib/tui-7B7x6A08.mjs +2 -0
- package/package.json +2 -2
- package/lib/cli-w1S7I0HL.mjs +0 -22
- package/lib/client-Dk7Dx_vo.mjs +0 -8
- package/lib/tui-Ca5GU7rB.mjs +0 -2
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{a as e,t}from"./client-BCBBen9i.mjs";import{Container as n,Editor as r,Loader as i,Markdown as a,ProcessTerminal as o,Text as s,TuiMainScreen as c}from"@earendil-works/pi-tui";const l=e=>t=>`\x1b[${e}m${t}\x1b[0m`,u=l(`2`),d=l(`1`),f=l(`36`),p=l(`33`),m=l(`31`),h=l(`32`),g=l(`35`),_={heading:e=>d(f(e)),link:f,linkUrl:e=>u(f(e)),code:p,codeBlock:p,codeBlockBorder:u,quote:u,quoteBorder:u,hr:u,listBullet:f,bold:d,italic:l(`3`),strikethrough:l(`9`),underline:l(`4`)},v={borderColor:u,selectList:{selectedPrefix:f,selectedText:d,description:u,scrollInfo:u,noMatch:u}},y=(e,t)=>e.length>t?`${e.slice(0,t)}…`:e;var b=class{tui;chat;thinking=null;thinkingBuffer=``;answer=null;answerBuffer=``;constructor(e,t){this.tui=e,this.chat=t}touch(){this.tui.requestRender()}appendThinking(e){this.thinking||(this.thinking=new s(``,0,0),this.chat.addChild(this.thinking)),this.thinkingBuffer+=e,this.thinking.setText(u(this.thinkingBuffer.trimEnd())),this.touch()}appendAnswer(e){this.answer||(this.answer=new a(``,0,0,_),this.chat.addChild(this.answer)),this.answerBuffer+=e,this.answer.setText(this.answerBuffer),this.touch()}addLine(e){this.answer=null,this.answerBuffer=``,this.chat.addChild(new s(e,0,0)),this.touch()}};const x=async({connection:a,agentName:l,sessionId:_,fork:x})=>{let S=new o,C=new c(S);S.setTitle(`buttress agent · ${l}`);let w=new n,T=new s(``,0,0),E=new r(C,v);C.addChild(w),C.addChild(T),C.addChild(E),C.setFocus(E);let D=_,O=x,k=null,A=null,j=e=>{T.setText(e),C.requestRender()},M=()=>{A||(A=new i(C,f,u,`thinking…`),w.addChild(A),C.requestRender())},N=()=>{A&&(w.removeChild(A),A=null,C.requestRender())},P=`${d(l)} ${u(`@ ${a.baseUrl}`)}`+(D?` ${u(`(${O?`forking`:`continuing`} ${D})`)}`:``);w.addChild(new s(P,0,0)),j(u(`Enter to send · /new fresh session · /exit or Ctrl+C to quit`));let F=async()=>{C.stop(),await S.drainInput().catch(()=>{}),process.exit(0)};C.addInputListener(e=>{if(e===``)return k?(k.abort(),k=null,{consume:!0}):(F(),{consume:!0})});let I=async n=>{w.addChild(new s(`${f(`>`)} ${n}`,0,0));let r=new b(C,w),i=D;k=new AbortController,M(),j(u(`running · Ctrl+C aborts this turn`));let o;try{o=await e(a,l,{prompt:n,sessionId:D??void 0,fork:O},{signal:k.signal,onFrame:({event:e,payload:t})=>{if(e===`session`&&t?.sessionId){t.sessionId!==D&&(D=t.sessionId,w.addChild(new s(u(`session ${D}`),0,0)));return}if(e!==`agent`)return;N();let n=t?.event;if(t?.type===`message_update`&&n)n.type===`thinking_delta`?r.appendThinking(n.delta??``):n.type===`text_delta`&&r.appendAnswer(n.delta??``);else if(t?.type===`tool_execution_start`){let e=JSON.stringify(t.args??{});r.addLine(`${p(`⚙ ${t.toolName}`)}${u(`(${y(e,120)})`)}`)}else t?.type===`tool_execution_end`?r.addLine(t.isError?m(`✗ ${t.toolName} failed`):u(`✓ ${t.toolName}`)):t?.type===`tool_emit`&&r.addLine(u(` ${t.toolName} → ${t.event}`))}})}catch(e){o={kind:`error`,message:e?.message||String(e),sessionId:D}}if(N(),k=null,o.kind===`result`){let{result:e}=o;D=e.sessionId??D;let t=e.usage||{};w.addChild(new s(u(`— ${e.stopReason} · ${t.totalTurns??`?`} turn(s) · ${t.input??0} in / ${t.output??0} out · session ${D}`),0,0))}else o.kind===`aborted`?(D=o.sessionId??D,w.addChild(new s(p(`(aborted — session is continuable)`),0,0))):o.kind===`error`?(D=o.sessionId??D,w.addChild(new s(m(`Run failed: ${o.message}`),0,0))):w.addChild(new s(m(`Connection lost mid-run.`),0,0));t(i,D)&&(O=!1),j(u(`Enter to send · /new fresh session · /exit or Ctrl+C to quit`)),C.requestRender()};E.onSubmit=e=>{let t=e.trim();if(E.setText(``),t){if(k){j(p(`A turn is still running — Ctrl+C aborts it.`));return}if(t===`/exit`||t===`/quit`){F();return}if(t===`/new`){D=null,O=!1,w.addChild(new s(`${h(`•`)} ${u(`started a fresh session`)}`,0,0)),C.requestRender();return}if(t===`/session`){w.addChild(new s(u(D?`session ${D}`:`no session yet`),0,0)),C.requestRender();return}I(t)}},w.addChild(new s(u(g(`ready`)),0,0)),C.start(),await new Promise(()=>{})};export{x as runAgentTui};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fugood/buttress-server",
|
|
3
|
-
"version": "2.26.0-beta.
|
|
3
|
+
"version": "2.26.0-beta.9",
|
|
4
4
|
"main": "lib/index.mjs",
|
|
5
5
|
"types": "lib/index.d.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -72,5 +72,5 @@
|
|
|
72
72
|
"tsdown": "^0.22.4",
|
|
73
73
|
"typescript": "^7.0.2"
|
|
74
74
|
},
|
|
75
|
-
"gitHead": "
|
|
75
|
+
"gitHead": "7c3ac2bf5cec7760bae076451979ceebf0175448"
|
|
76
76
|
}
|
package/lib/cli-w1S7I0HL.mjs
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import{i as e,n as t,r as n,t as r}from"./client-Dk7Dx_vo.mjs";import i from"node:readline";const a=`\x1B[2m`,o=`\x1B[33m`,s=`\x1B[31m`,c=`\x1B[0m`,l=e=>{let t={name:null,configArg:null,url:null,token:null,sessionId:null,fork:!1,listSessions:!1,plain:!1};for(let n=0;n<e.length;n+=1){let r=e[n];r===`-h`||r===`--help`?(console.log(`
|
|
3
|
-
bricks-buttress agent — chat with a configured agent on a running server
|
|
4
|
-
|
|
5
|
-
Usage:
|
|
6
|
-
bricks-buttress agent [name] [options]
|
|
7
|
-
|
|
8
|
-
Options:
|
|
9
|
-
-c, --config <path|toml> Config file (finds server port + local token)
|
|
10
|
-
--url <url> Server base URL (default from config, else http://127.0.0.1:2080)
|
|
11
|
-
--token <token> Access token (default: the config's runtime token file)
|
|
12
|
-
--session <id> Continue an existing session
|
|
13
|
-
--fork <id> Fork a session, then continue the fork
|
|
14
|
-
--sessions List the agent's sessions and exit
|
|
15
|
-
--plain Line-based output (default when not a TTY)
|
|
16
|
-
-h, --help Show this help
|
|
17
|
-
|
|
18
|
-
In the chat: /exit quits, /new starts a fresh session, Ctrl+C aborts the
|
|
19
|
-
current run (a second Ctrl+C quits).
|
|
20
|
-
`),process.exit(0)):r===`-c`||r===`--config`?t.configArg=e[++n]??null:r===`--url`?t.url=e[++n]??null:r===`--token`?t.token=e[++n]??null:r===`--session`?t.sessionId=e[++n]??null:r===`--fork`?(t.sessionId=e[++n]??null,t.fork=!0):r===`--sessions`?t.listSessions=!0:r===`--plain`?t.plain=!0:!r.startsWith(`-`)&&!t.name?t.name=r:(console.error(`Unknown argument: ${r}`),process.exit(1))}return t},u=e=>{console.error(`${s}${e}${c}`),process.exit(1)},d=async(t,n,r,i,l,u)=>{let d=i,f=!1,p=!1,m=()=>{f&&=(process.stdout.write(`${c}\n`),!1)},h=await e(t,n,{prompt:r,sessionId:i??void 0,fork:l},{signal:u,onFrame:({event:e,payload:t})=>{if(e===`session`){t.sessionId&&t.sessionId!==d&&(d=t.sessionId,i||console.log(`${a}session ${d}${c}`));return}if(e!==`agent`)return;let n=t?.event;if(t?.type===`message_update`&&n)n.type===`thinking_delta`?(f||=(process.stdout.write(`${a}`),!0),process.stdout.write(n.delta??``),p=!0):n.type===`text_delta`&&(m(),process.stdout.write(n.delta??``),p=!0);else if(t?.type===`tool_execution_start`){m(),p&&process.stdout.write(`
|
|
21
|
-
`);let e=JSON.stringify(t.args??{});console.log(`${o}⚙ ${t.toolName}${c}${a}(${e.length>160?`${e.slice(0,160)}…`:e})${c}`),p=!1}else t?.type===`tool_execution_end`?console.log(t.isError?`${s}✗ ${t.toolName} failed${c}`:`${a}✓ ${t.toolName}${c}`):t?.type===`tool_emit`&&console.log(`${a} ${t.toolName} → ${t.event}${c}`)}});if(m(),h.kind===`result`){let e=h.result;d=e.sessionId??d;let t=e.usage||{};return process.stdout.write(`
|
|
22
|
-
`),console.log(`${a}— ${e.stopReason} · ${t.totalTurns??`?`} turn(s) · ${t.input??0} in / ${t.output??0} out · session ${d}${c}`),{sessionId:d,ok:!0}}return h.kind===`aborted`?(console.log(`\n${o}(aborted)${c}`),{sessionId:h.sessionId??d,ok:!1}):h.kind===`error`?(console.error(`\n${s}Run failed: ${h.message}${c}`),{sessionId:h.sessionId??d,ok:!1}):(console.error(`\n${s}Connection lost mid-run.${c}`),{sessionId:h.sessionId??d,ok:!1})},f=async(e,t,n,r)=>{let o=n,l=r;console.log(`[1m${t}${c} @ ${e.baseUrl}`+(o?` ${a}(${l?`forking`:`continuing`} ${o})${c}`:``)),console.log(`${a}/exit to quit, /new for a fresh session, Ctrl+C aborts a running turn${c}`);let u=i.createInterface({input:process.stdin,output:process.stdout}),f=!1;u.on(`close`,()=>{f=!0});let p=e=>new Promise(t=>{if(f){t(null);return}u.question(e,t),u.once(`close`,()=>t(null))}),m=null;for(u.on(`SIGINT`,()=>{m?(m.abort(),m=null):(u.close(),process.exit(0))});;){let n=await p(`[36m> ${c}`);if(n==null)break;let r=n.trim();if(r){if(r===`/exit`||r===`/quit`)break;if(r===`/new`){o=null,l=!1,console.log(`${a}Started a fresh session.${c}`);continue}m=new AbortController;try{let n=await d(e,t,r,o,l,m.signal);n.sessionId&&(o=n.sessionId),l=!1}catch(e){console.error(`${s}${e?.message||e}${c}`)}finally{m=null}}}u.close()},p=async e=>{let i=l(e),{config:o,agentsConfig:s}=r(i.configArg),d=o.server.port||2080,p=(i.url||`http://127.0.0.1:${d}`).replace(/\/$/,``),m={baseUrl:p,token:i.token||(s?t(s.runtimeTokenFile):null)||process.env.BUTTRESS_AGENT_TOKEN||null},h=await n(m,`/agents`).catch(e=>u(`Cannot reach ${p}: ${e?.message||e} (is the server running?)`));if(!h.ok){let e=await h.text().catch(()=>``);u(`Server rejected the request (${h.status}): ${e.slice(0,300)}`)}let{agents:g}=await h.json();if(!i.name){console.log(`Configured agents on ${p}:`);for(let e of g)console.log(`- ${e}`);g.length===0&&console.log(`(none — add [[agents]] to the server config)`);return}if(g.includes(i.name)||u(`Unknown agent "${i.name}" (configured: ${g.join(`, `)||`none`})`),i.listSessions){let{sessions:e}=await(await n(m,`/agents/${encodeURIComponent(i.name)}/sessions`)).json();if(!e?.length){console.log(`No sessions yet.`);return}for(let t of e)console.log(`${t.sessionId} ${a}${t.updatedAt}${c}${t.parentSession?` ${a}(fork of ${t.parentSession})${c}`:``}`),t.preview&&console.log(` ${a}${t.preview}${c}`);return}if(process.stdin.isTTY&&process.stdout.isTTY&&!i.plain){let{runAgentTui:e}=await import(`./tui-Ca5GU7rB.mjs`);await e({connection:m,agentName:i.name,sessionId:i.sessionId,fork:i.fork});return}await f(m,i.name,i.sessionId,i.fork)};export{p as runAgentCommand};
|
package/lib/client-Dk7Dx_vo.mjs
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import{a as e,n as t}from"./config-lP89VahD.mjs";import n from"node:path";import r from"node:fs";import i from"@iarna/toml";const a=a=>{let o={},s=process.cwd();a&&(r.existsSync(a)?(o=i.parse(r.readFileSync(a,`utf8`)),s=n.dirname(n.resolve(a))):o=i.parse(a));let c=e(o);return{config:c,configDir:s,agentsConfig:t(c,{configDir:s})}},o=e=>{try{return r.readFileSync(e,`utf8`).trim()||null}catch{return null}},s=async(e,t,n)=>fetch(`${e.baseUrl}${t}`,{...n,headers:{"content-type":`application/json`,...e.token?{authorization:`Bearer ${e.token}`}:{},...n?.headers}});async function*c(e){let t=e.getReader(),n=new TextDecoder,r=``;try{for(;;){let{done:e,value:i}=await t.read();if(e)break;r+=n.decode(i,{stream:!0});let a=r.indexOf(`
|
|
3
|
-
|
|
4
|
-
`);for(;a!==-1;){let e=r.slice(0,a);r=r.slice(a+2),a=r.indexOf(`
|
|
5
|
-
|
|
6
|
-
`);let t=`message`,n=[];for(let r of e.split(`
|
|
7
|
-
`))r.startsWith(`event:`)?t=r.slice(6).trim():r.startsWith(`data:`)&&n.push(r.slice(5).trimStart());n.length>0&&(yield{event:t,data:n.join(`
|
|
8
|
-
`)})}}}finally{t.releaseLock()}}const l=async(e,t,n,{signal:r,onFrame:i})=>{let a=n.sessionId??null,o;try{o=await s(e,`/agents/${encodeURIComponent(t)}/run?stream=1`,{method:`POST`,body:JSON.stringify({prompt:n.prompt,...n.sessionId?{sessionId:n.sessionId}:{},...n.fork?{fork:!0}:{}}),signal:r})}catch(e){if(r?.aborted)return{kind:`aborted`,sessionId:a};throw e}if(!o.ok||!o.body){let e=await o.text().catch(()=>``);return{kind:`error`,message:`Run request failed (${o.status}): ${e.slice(0,400)}`,sessionId:a}}try{for await(let e of c(o.body)){let t;try{t=JSON.parse(e.data)}catch{continue}if(e.event===`session`&&t?.sessionId&&(a=t.sessionId),e.event===`result`)return i({event:e.event,payload:t}),{kind:`result`,result:t};if(e.event===`error`)return i({event:e.event,payload:t}),{kind:`error`,message:t?.message||`run failed`,sessionId:t?.sessionId??a};i({event:e.event,payload:t})}}catch(e){if(r?.aborted)return{kind:`aborted`,sessionId:a};throw e}return r?.aborted?{kind:`aborted`,sessionId:a}:{kind:`disconnected`,sessionId:a}};export{l as i,o as n,s as r,a as t};
|
package/lib/tui-Ca5GU7rB.mjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import{i as e}from"./client-Dk7Dx_vo.mjs";import{Container as t,Editor as n,Loader as r,Markdown as i,ProcessTerminal as a,Text as o,TuiMainScreen as s}from"@earendil-works/pi-tui";const c=e=>t=>`\x1b[${e}m${t}\x1b[0m`,l=c(`2`),u=c(`1`),d=c(`36`),f=c(`33`),p=c(`31`),m=c(`32`),h=c(`35`),g={heading:e=>u(d(e)),link:d,linkUrl:e=>l(d(e)),code:f,codeBlock:f,codeBlockBorder:l,quote:l,quoteBorder:l,hr:l,listBullet:d,bold:u,italic:c(`3`),strikethrough:c(`9`),underline:c(`4`)},_={borderColor:l,selectList:{selectedPrefix:d,selectedText:u,description:l,scrollInfo:l,noMatch:l}},v=(e,t)=>e.length>t?`${e.slice(0,t)}…`:e;var y=class{tui;chat;thinking=null;thinkingBuffer=``;answer=null;answerBuffer=``;constructor(e,t){this.tui=e,this.chat=t}touch(){this.tui.requestRender()}appendThinking(e){this.thinking||(this.thinking=new o(``,0,0),this.chat.addChild(this.thinking)),this.thinkingBuffer+=e,this.thinking.setText(l(this.thinkingBuffer.trimEnd())),this.touch()}appendAnswer(e){this.answer||(this.answer=new i(``,0,0,g),this.chat.addChild(this.answer)),this.answerBuffer+=e,this.answer.setText(this.answerBuffer),this.touch()}addLine(e){this.answer=null,this.answerBuffer=``,this.chat.addChild(new o(e,0,0)),this.touch()}};const b=async({connection:i,agentName:c,sessionId:g,fork:b})=>{let x=new a,S=new s(x);x.setTitle(`buttress agent · ${c}`);let C=new t,w=new o(``,0,0),T=new n(S,_);S.addChild(C),S.addChild(w),S.addChild(T),S.setFocus(T);let E=g,D=b,O=null,k=null,A=e=>{w.setText(e),S.requestRender()},j=()=>{k||(k=new r(S,d,l,`thinking…`),C.addChild(k),S.requestRender())},M=()=>{k&&(C.removeChild(k),k=null,S.requestRender())},N=`${u(c)} ${l(`@ ${i.baseUrl}`)}`+(E?` ${l(`(${D?`forking`:`continuing`} ${E})`)}`:``);C.addChild(new o(N,0,0)),A(l(`Enter to send · /new fresh session · /exit or Ctrl+C to quit`));let P=async()=>{S.stop(),await x.drainInput().catch(()=>{}),process.exit(0)};S.addInputListener(e=>{if(e===``)return O?(O.abort(),O=null,{consume:!0}):(P(),{consume:!0})});let F=async t=>{C.addChild(new o(`${d(`>`)} ${t}`,0,0));let n=new y(S,C);O=new AbortController,j(),A(l(`running · Ctrl+C aborts this turn`));let r;try{r=await e(i,c,{prompt:t,sessionId:E??void 0,fork:D},{signal:O.signal,onFrame:({event:e,payload:t})=>{if(e===`session`&&t?.sessionId){t.sessionId!==E&&(E=t.sessionId,C.addChild(new o(l(`session ${E}`),0,0)));return}if(e!==`agent`)return;M();let r=t?.event;if(t?.type===`message_update`&&r)r.type===`thinking_delta`?n.appendThinking(r.delta??``):r.type===`text_delta`&&n.appendAnswer(r.delta??``);else if(t?.type===`tool_execution_start`){let e=JSON.stringify(t.args??{});n.addLine(`${f(`⚙ ${t.toolName}`)}${l(`(${v(e,120)})`)}`)}else t?.type===`tool_execution_end`?n.addLine(t.isError?p(`✗ ${t.toolName} failed`):l(`✓ ${t.toolName}`)):t?.type===`tool_emit`&&n.addLine(l(` ${t.toolName} → ${t.event}`))}})}catch(e){r={kind:`error`,message:e?.message||String(e),sessionId:E}}if(M(),O=null,D=!1,r.kind===`result`){let{result:e}=r;E=e.sessionId??E;let t=e.usage||{};C.addChild(new o(l(`— ${e.stopReason} · ${t.totalTurns??`?`} turn(s) · ${t.input??0} in / ${t.output??0} out · session ${E}`),0,0))}else r.kind===`aborted`?(E=r.sessionId??E,C.addChild(new o(f(`(aborted — session is continuable)`),0,0))):r.kind===`error`?(E=r.sessionId??E,C.addChild(new o(p(`Run failed: ${r.message}`),0,0))):C.addChild(new o(p(`Connection lost mid-run.`),0,0));A(l(`Enter to send · /new fresh session · /exit or Ctrl+C to quit`)),S.requestRender()};T.onSubmit=e=>{let t=e.trim();if(T.setText(``),t){if(O){A(f(`A turn is still running — Ctrl+C aborts it.`));return}if(t===`/exit`||t===`/quit`){P();return}if(t===`/new`){E=null,D=!1,C.addChild(new o(`${m(`•`)} ${l(`started a fresh session`)}`,0,0)),S.requestRender();return}if(t===`/session`){C.addChild(new o(l(E?`session ${E}`:`no session yet`),0,0)),S.requestRender();return}F(t)}},C.addChild(new o(l(h(`ready`)),0,0)),S.start(),await new Promise(()=>{})};export{b as runAgentTui};
|