@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.
@@ -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.4",
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": "13b0d97e181e2d090b6df915b446c4f7673af04f"
75
+ "gitHead": "7c3ac2bf5cec7760bae076451979ceebf0175448"
76
76
  }
@@ -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(`${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(`> ${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};
@@ -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};
@@ -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};