@sofer_agent/cli 0.3.7 → 0.3.8

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/dist/tui.d.ts CHANGED
@@ -16,7 +16,8 @@ export declare class SoferTui {
16
16
  private columns;
17
17
  private rows;
18
18
  private chatW;
19
- private chatH;
19
+ private sideW;
20
+ private bodyH;
20
21
  private scrollOff;
21
22
  private status;
22
23
  private spinnerFrame;
@@ -32,7 +33,6 @@ export declare class SoferTui {
32
33
  setInfo(info: Partial<TuiInfo>): void;
33
34
  private startSpinner;
34
35
  private stopSpinner;
35
- /** Start the interactive TUI loop. */
36
36
  run(onLine: (line: string, signal?: AbortSignal) => Promise<void>): Promise<void>;
37
37
  private shutdown;
38
38
  private handleInput;
@@ -42,8 +42,6 @@ export declare class SoferTui {
42
42
  private buildFrame;
43
43
  private wrapMessage;
44
44
  private roleLabel;
45
- private pad;
46
- private sidebarRow;
47
45
  private buildSidebar;
48
46
  }
49
47
  //# sourceMappingURL=tui.d.ts.map
package/dist/tui.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAUjE,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IAC3C,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,OAAO;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,QAAQ;IAuBjB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAvBzB,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,OAAO,CAAM;IACrB,OAAO,CAAC,IAAI,CAAM;IAClB,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,SAAS,CAAK;IAEtB,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,YAAY,CAA+C;IACnE,OAAO,CAAC,aAAa,CAAK;IAE1B,OAAO,CAAC,SAAS,CAAgC;IAEjD,OAAO,CAAC,IAAI,CAA8C;IAE1D,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,MAAM,CAAwE;gBAGnE,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,WAAW;IAGtC,OAAO,CAAC,OAAO;IAOf,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAItD,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI;IAIrC,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,WAAW;IASnB,sCAAsC;IAChC,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAevF,OAAO,CAAC,QAAQ;IAahB,OAAO,CAAC,WAAW,CA4CjB;YAEY,MAAM;IA2BpB,OAAO,CAAC,YAAY,CAGlB;IAEF,MAAM,IAAI,IAAI;IASd,OAAO,CAAC,UAAU;IAsDlB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,SAAS;IAajB,OAAO,CAAC,GAAG;IAQX,OAAO,CAAC,UAAU;IAalB,OAAO,CAAC,YAAY;CAgCrB"}
1
+ {"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAiBjE,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IAC3C,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,OAAO;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,QAAQ;IAwBjB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAxBzB,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,OAAO,CAAM;IACrB,OAAO,CAAC,IAAI,CAAM;IAClB,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,SAAS,CAAK;IAEtB,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,YAAY,CAA+C;IACnE,OAAO,CAAC,aAAa,CAAK;IAE1B,OAAO,CAAC,SAAS,CAAgC;IAEjD,OAAO,CAAC,IAAI,CAA8C;IAE1D,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,MAAM,CAAwE;gBAGnE,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,WAAW;IAGtC,OAAO,CAAC,OAAO;IAQf,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAItD,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI;IAIrC,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,WAAW;IASb,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAWvF,OAAO,CAAC,QAAQ;IAahB,OAAO,CAAC,WAAW,CA6BjB;YAEY,MAAM;IAmBpB,OAAO,CAAC,YAAY,CAAkD;IAEtE,MAAM,IAAI,IAAI;IAKd,OAAO,CAAC,UAAU;IAqElB,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,YAAY;CAyBrB"}
package/dist/tui.js CHANGED
@@ -1,20 +1,27 @@
1
- const SIDEBAR_W = 26;
2
- const MIN_CHAT_W = 30;
1
+ const SIDEBAR_W = 28;
2
+ const MIN_CHAT_W = 34;
3
3
  const GUTTER = " ";
4
4
  const LABEL_W = 6;
5
5
  const INDENT = `${GUTTER}${" ".repeat(LABEL_W + 1)}`;
6
6
  const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
7
7
  const SPINNER_MS = 80;
8
+ // Box-drawing: ╭ ─ ╮ │ ╰ ╯ ├ ┤ ┬ ┴ ┼
9
+ const B = {
10
+ tl: "╭", tr: "╮", bl: "╰", br: "╯",
11
+ h: "─", v: "│",
12
+ lt: "├", rt: "┤", tt: "┬", bt: "┴",
13
+ };
8
14
  export class SoferTui {
9
15
  agent;
10
16
  config;
11
17
  state = [];
12
18
  inputBuf = "";
13
19
  cursor = 0;
14
- columns = 80;
15
- rows = 24;
16
- chatW = 50;
17
- chatH = 20;
20
+ columns = 90;
21
+ rows = 28;
22
+ chatW = 58;
23
+ sideW = 26;
24
+ bodyH = 22;
18
25
  scrollOff = 0;
19
26
  // spinner
20
27
  status = "idle";
@@ -23,7 +30,7 @@ export class SoferTui {
23
30
  turnStartedAt = 0;
24
31
  // interrupt
25
32
  abortCtrl = null;
26
- // sidebar info
33
+ // sidebar
27
34
  info = { lastTurnIn: 0, lastTurnOut: 0 };
28
35
  // callbacks
29
36
  resolve = null;
@@ -33,10 +40,11 @@ export class SoferTui {
33
40
  this.config = config;
34
41
  }
35
42
  measure() {
36
- this.columns = process.stdout.columns ?? 80;
37
- this.rows = process.stdout.rows ?? 24;
38
- this.chatW = Math.max(MIN_CHAT_W, this.columns - SIDEBAR_W - 1);
39
- this.chatH = this.rows - 3;
43
+ this.columns = Math.max(80, process.stdout.columns ?? 80);
44
+ this.rows = Math.max(24, process.stdout.rows ?? 24);
45
+ this.chatW = Math.max(MIN_CHAT_W, this.columns - SIDEBAR_W - 3);
46
+ this.sideW = this.columns - this.chatW - 3;
47
+ this.bodyH = this.rows - 5; // top border, input box(3), footer(1)
40
48
  }
41
49
  addMessage(role, text) {
42
50
  this.state.push({ role, text });
@@ -63,7 +71,6 @@ export class SoferTui {
63
71
  this.spinnerTimer = null;
64
72
  }
65
73
  }
66
- /** Start the interactive TUI loop. */
67
74
  async run(onLine) {
68
75
  this.onLine = onLine;
69
76
  this.measure();
@@ -73,9 +80,7 @@ export class SoferTui {
73
80
  process.stdout.on("resize", this.handleResize);
74
81
  process.on("SIGWINCH", this.handleResize);
75
82
  this.render();
76
- return new Promise((resolve) => {
77
- this.resolve = resolve;
78
- });
83
+ return new Promise((resolve) => { this.resolve = resolve; });
79
84
  }
80
85
  shutdown() {
81
86
  this.stopSpinner();
@@ -95,33 +100,30 @@ export class SoferTui {
95
100
  if (code === 3) {
96
101
  this.shutdown();
97
102
  return;
98
- } // Ctrl-C
103
+ }
99
104
  if (code === 4 && this.inputBuf.length === 0) {
100
105
  this.shutdown();
101
106
  return;
102
- } // Ctrl-D
107
+ }
103
108
  if (code === 27) {
104
- // Escape
105
109
  if (this.status === "thinking" && this.abortCtrl) {
106
110
  this.abortCtrl.abort();
107
111
  return;
108
112
  }
109
- this.inputBuf = ""; // clear input on Esc when idle
113
+ this.inputBuf = "";
110
114
  this.cursor = 0;
111
115
  this.render();
112
116
  return;
113
117
  }
114
118
  if (this.status === "thinking")
115
- continue; // reject input while thinking
119
+ continue;
116
120
  if (code === 13) {
117
121
  this.submit();
118
122
  return;
119
- } // Enter
123
+ }
120
124
  if (code === 127) {
121
- // Backspace
122
125
  if (this.cursor > 0) {
123
- this.inputBuf =
124
- this.inputBuf.slice(0, this.cursor - 1) + this.inputBuf.slice(this.cursor);
126
+ this.inputBuf = this.inputBuf.slice(0, this.cursor - 1) + this.inputBuf.slice(this.cursor);
125
127
  this.cursor--;
126
128
  }
127
129
  this.render();
@@ -157,140 +159,106 @@ export class SoferTui {
157
159
  this.render();
158
160
  }
159
161
  // ── Rendering ───────────────────────────────────────────────────────────
160
- handleResize = () => {
161
- this.measure();
162
- this.render();
163
- };
162
+ handleResize = () => { this.measure(); this.render(); };
164
163
  render() {
165
164
  this.measure();
166
- const out = process.stdout;
167
- out.write("\x1b[?25l");
168
- out.write("\x1b[H");
169
- out.write(this.buildFrame());
170
- out.write("\x1b[?25h");
165
+ process.stdout.write("\x1b[?25l\x1b[H" + this.buildFrame() + "\x1b[?25h");
171
166
  }
172
167
  buildFrame() {
173
- const { chatW, chatH } = this;
174
- const rightW = this.columns - chatW - 1;
168
+ const { columns, chatW, sideW, bodyH } = this;
169
+ const innerSideW = sideW - 2;
170
+ const sep = `${B.lt}${B.h.repeat(chatW)}${B.bt}${B.h.repeat(sideW)}${B.rt}`;
171
+ const inputW = columns - 2; // inside border
175
172
  let buf = "";
176
- // ── Chat body ─────────────────────────────────────────────────────────
173
+ // ── Top border ────────────────────────────────────────────────────────
174
+ buf += `${B.tl}${B.h.repeat(chatW)}${B.tt}${B.h.repeat(sideW)}${B.tr}\n`;
175
+ // ── Body ──────────────────────────────────────────────────────────────
177
176
  const wrapped = this.state.flatMap((m) => this.wrapMessage(m, chatW));
178
- const maxScroll = Math.max(0, wrapped.length - chatH);
177
+ const maxScroll = Math.max(0, wrapped.length - bodyH);
179
178
  if (this.scrollOff > maxScroll)
180
179
  this.scrollOff = maxScroll;
181
180
  if (this.scrollOff < 0)
182
181
  this.scrollOff = 0;
183
- const visible = wrapped.slice(this.scrollOff, this.scrollOff + chatH);
184
- for (let r = 0; r < chatH; r++) {
185
- const line = visible[r];
186
- if (line)
187
- buf += this.pad(line, chatW);
188
- else
189
- buf += " ".repeat(chatW);
190
- if (r === 0)
191
- buf += "";
192
- else if (r === chatH - 1)
193
- buf += "┴";
194
- else
195
- buf += "│";
196
- buf += this.sidebarRow(r, chatH, rightW);
197
- buf += "\n";
182
+ const visible = wrapped.slice(this.scrollOff, this.scrollOff + bodyH);
183
+ const sidebarLines = this.buildSidebar(innerSideW);
184
+ const sbTop = Math.max(0, Math.floor((bodyH - sidebarLines.length) / 2));
185
+ for (let r = 0; r < bodyH; r++) {
186
+ buf += B.v;
187
+ buf += visible[r] ? padTrunc(visible[r], chatW) : " ".repeat(chatW);
188
+ buf += B.v;
189
+ const sbIdx = r - sbTop;
190
+ const sbLine = (sbIdx >= 0 && sbIdx < sidebarLines.length) ? sidebarLines[sbIdx] : "";
191
+ buf += ` ${padRight(sbLine, innerSideW)} `;
192
+ buf += `${B.v}\n`;
198
193
  }
199
- // ── Divider ───────────────────────────────────────────────────────────
200
- buf += `${"─".repeat(chatW)}┴${"─".repeat(rightW)}\n`;
194
+ // ── Separator ─────────────────────────────────────────────────────────
195
+ buf += `${sep}\n`;
201
196
  // ── Spinner row ───────────────────────────────────────────────────────
202
197
  if (this.status === "thinking") {
203
198
  const frame = SPINNER_FRAMES[this.spinnerFrame];
204
199
  const elapsed = this.turnStartedAt ? formatElapsed(Date.now() - this.turnStartedAt) : "";
205
- buf += `\x1b[36m${frame} thinking…${elapsed ? ` ${elapsed}` : ""} (esc to interrupt)\x1b[0m\x1b[K\n`;
200
+ buf += `${B.v} \x1b[36m${frame} thinking…${elapsed ? ` ${elapsed}` : ""} (esc to interrupt)\x1b[0m${" ".repeat(Math.max(0, inputW - 28 - elapsed.length))}${B.v}\n`;
206
201
  }
207
- // ── Input bar ─────────────────────────────────────────────────────────
208
- const prefix = "\x1b[36m> \x1b[0m";
209
- const cursorChar = this.status === "idle" ? "\x1b[5m▋\x1b[25m" : "";
210
- buf += `${prefix}${this.inputBuf}${cursorChar}\x1b[K`;
211
- // Footer
202
+ // ── Input bar (bordered box) ─────────────────────────────────────────
203
+ buf += `${B.tl}${B.h.repeat(inputW)}${B.tr}\n`;
204
+ const cursorCh = this.status === "idle" ? "\x1b[5m▋\x1b[25m" : "";
205
+ const inputMaxW = inputW - 3; // "> " prefix + 1 padding
206
+ const visibleInput = this.inputBuf.length > inputMaxW
207
+ ? this.inputBuf.slice(this.inputBuf.length - inputMaxW)
208
+ : this.inputBuf;
209
+ const inputPad = inputMaxW - visibleInput.length;
210
+ buf += `${B.v} \x1b[36m>\x1b[0m ${visibleInput}${cursorCh}${" ".repeat(Math.max(0, inputPad))} ${B.v}\n`;
211
+ buf += `${B.bl}${B.h.repeat(inputW)}${B.br}\n`;
212
+ // ── Footer ────────────────────────────────────────────────────────────
212
213
  const totalIn = this.agent.usage.tokens.inputTokens;
213
214
  const totalOut = this.agent.usage.tokens.outputTokens;
214
215
  const cost = this.agent.usage.costUsd.toFixed(4);
215
- const footer = `\x1b[90m${this.agent.address.slice(0, 10)}… · tokens ${totalIn}/${totalOut} · $${cost} · /exit to quit\x1b[0m`;
216
- buf += `\n${this.pad(footer, this.columns)}`;
217
- // Place cursor at input position
218
- const cursorCol = 2 + Math.min(this.cursor, this.columns - 5);
219
- buf += `\x1b[${this.chatH + 2 + (this.status === "thinking" ? 1 : 0)};${cursorCol}H`;
216
+ const ft = `\x1b[90m${this.agent.address.slice(0, 10)}… · in ${totalIn} out ${totalOut} $${cost} /exit\x1b[0m`;
217
+ buf += `${padTrunc(ft, columns)}\n`;
218
+ // ── Cursor position ───────────────────────────────────────────────────
219
+ const cursorRow = bodyH + 1 + (this.status === "thinking" ? 1 : 0) + 1; // body + sep + spinner? + input
220
+ const cursorCol = 4 + Math.min(this.cursor, inputMaxW);
221
+ buf += `\x1b[${cursorRow};${cursorCol}H`;
220
222
  return buf;
221
223
  }
222
- // ── Message wrapping with gutter ────────────────────────────────────────
224
+ // ── Messages ────────────────────────────────────────────────────────────
223
225
  wrapMessage(msg, width) {
224
226
  const label = this.roleLabel(msg.role);
225
- const bodyWidth = width - GUTTER.length - LABEL_W - 1;
227
+ const bodyWidth = Math.max(10, width - GUTTER.length - LABEL_W - 1);
226
228
  const lines = wrapText(msg.text, bodyWidth);
227
- return lines.map((l, i) => {
228
- if (i === 0)
229
- return `${GUTTER}${label} ${l}`;
230
- return `${INDENT}${l}`;
231
- });
229
+ return lines.map((l, i) => i === 0 ? `${GUTTER}${label} ${l}` : `${INDENT}${l}`);
232
230
  }
233
231
  roleLabel(role) {
234
232
  switch (role) {
235
- case "you":
236
- return "\x1b[36myou \x1b[0m"; // cyan "you", padded to LABEL_W
237
- case "agent":
238
- return `\x1b[32m${this.agent.name.toLowerCase().slice(0, LABEL_W).padEnd(LABEL_W)}\x1b[0m`;
239
- case "system":
240
- return "\x1b[90msys \x1b[0m";
241
- case "error":
242
- return "\x1b[31merr \x1b[0m";
233
+ case "you": return "\x1b[36myou \x1b[0m";
234
+ case "agent": return `\x1b[32m${this.agent.name.toLowerCase().padEnd(LABEL_W)}\x1b[0m`;
235
+ case "system": return "\x1b[90msys \x1b[0m";
236
+ case "error": return "\x1b[31merr \x1b[0m";
243
237
  }
244
238
  }
245
- pad(s, w) {
246
- const stripped = stripAnsi(s);
247
- const padW = Math.max(0, w - visibleLen(stripped));
248
- return s + " ".repeat(padW);
249
- }
250
239
  // ── Sidebar ─────────────────────────────────────────────────────────────
251
- sidebarRow(row, total, width) {
252
- const innerW = width - 2;
253
- const lines = this.buildSidebar(innerW);
254
- const gap = Math.max(0, total - lines.length);
255
- const topPad = Math.floor(gap / 2);
256
- const idx = row - topPad;
257
- if (idx < 0 || idx >= lines.length)
258
- return " ".repeat(width);
259
- const line = lines[idx];
260
- if (!line)
261
- return " ".repeat(width);
262
- const padded = padRight(line, innerW);
263
- return ` ${padded} `;
264
- }
265
240
  buildSidebar(width) {
266
241
  const { agent, config, info } = this;
267
242
  const addr = `${agent.address.slice(0, 6)}…${agent.address.slice(-4)}`;
268
- const hbar = "─".repeat(width);
269
- const thinBar = "·".repeat(width);
270
243
  const totalIn = agent.usage.tokens.inputTokens;
271
244
  const totalOut = agent.usage.tokens.outputTokens;
272
- const cost = agent.usage.costUsd.toFixed(4);
245
+ const cost = agent.usage.costUsd.toFixed(6);
273
246
  return [
274
- hbar,
275
247
  `\x1b[1;36m${agent.name}\x1b[0m`,
276
248
  `\x1b[90m${addr}\x1b[0m`,
277
249
  "",
250
+ `${B.h.repeat(width)}`,
278
251
  `\x1b[90mnetwork\x1b[0m ${config.network}`,
279
252
  `\x1b[90mmodel\x1b[0m ${shortModel(config.brain.model)}`,
280
- thinBar,
281
- `\x1b[90mlast turn\x1b[0m`,
282
- ` in ${info.lastTurnIn}`,
283
- ` out ${info.lastTurnOut}`,
284
- `\x1b[90mtotal\x1b[0m`,
285
- ` in ${totalIn}`,
286
- ` out ${totalOut}`,
287
- `\x1b[90mcost\x1b[0m \x1b[33m$${cost}\x1b[0m`,
288
- thinBar,
289
- `\x1b[90maddress\x1b[0m`,
290
- ` ${agent.address.slice(0, 16)}`,
291
- ` ${agent.address.slice(16, 32)}`,
292
- ` ${agent.address.slice(32)}`,
293
- hbar,
253
+ "",
254
+ `\x1b[90m▸ last turn\x1b[0m`,
255
+ ` in ${info.lastTurnIn}`,
256
+ ` out ${info.lastTurnOut}`,
257
+ "",
258
+ `\x1b[90m▸ total\x1b[0m`,
259
+ ` in ${totalIn}`,
260
+ ` out ${totalOut}`,
261
+ ` \x1b[33m$${cost}\x1b[0m`,
294
262
  ];
295
263
  }
296
264
  }
@@ -300,18 +268,17 @@ function wrapText(text, width) {
300
268
  return [""];
301
269
  const lines = [];
302
270
  const words = text.split(" ");
303
- let current = "";
304
- for (const word of words) {
305
- if (current && current.length + 1 + word.length > width) {
306
- lines.push(current);
307
- current = word;
308
- }
309
- else {
310
- current = current ? `${current} ${word}` : word;
271
+ let cur = "";
272
+ for (const w of words) {
273
+ if (cur && cur.length + 1 + w.length > width) {
274
+ lines.push(cur);
275
+ cur = w;
311
276
  }
277
+ else
278
+ cur = cur ? `${cur} ${w}` : w;
312
279
  }
313
- if (current)
314
- lines.push(current);
280
+ if (cur)
281
+ lines.push(cur);
315
282
  return lines.length > 0 ? lines : [""];
316
283
  }
317
284
  function stripAnsi(s) {
@@ -320,31 +287,33 @@ function stripAnsi(s) {
320
287
  }
321
288
  function visibleLen(s) {
322
289
  // biome-ignore lint/suspicious/noControlCharactersInRegex: ANSI escape stripping
323
- const ansiRe = /\x1b\[\d*;?\d*m/g;
290
+ const re = /\x1b\[\d*;?\d*m/g;
324
291
  let len = 0;
325
- let lastIdx = 0;
326
- let match = ansiRe.exec(s);
327
- while (match !== null) {
328
- len += match.index - lastIdx;
329
- lastIdx = match.index + match[0].length;
330
- match = ansiRe.exec(s);
292
+ let last = 0;
293
+ let m = re.exec(s);
294
+ while (m !== null) {
295
+ len += m.index - last;
296
+ last = m.index + m[0].length;
297
+ m = re.exec(s);
331
298
  }
332
- len += s.length - lastIdx;
333
- return len;
299
+ return len + s.length - last;
300
+ }
301
+ function padRight(s, w) {
302
+ const vl = visibleLen(s);
303
+ return vl >= w ? s : s + " ".repeat(w - vl);
334
304
  }
335
- function padRight(s, width) {
336
- const len = visibleLen(s);
337
- if (len >= width)
338
- return s;
339
- return s + " ".repeat(width - len);
305
+ function padTrunc(s, w) {
306
+ const stripped = stripAnsi(s);
307
+ if (stripped.length <= w)
308
+ return s + " ".repeat(w - stripped.length);
309
+ return stripped.slice(0, w);
340
310
  }
341
311
  function formatElapsed(ms) {
342
312
  const sec = Math.floor(ms / 1000);
343
313
  if (sec < 60)
344
314
  return `${sec}s`;
345
315
  const m = Math.floor(sec / 60);
346
- const s = sec % 60;
347
- return `${m}m${String(s).padStart(2, "0")}s`;
316
+ return `${m}m${String(sec % 60).padStart(2, "0")}s`;
348
317
  }
349
318
  function shortModel(model) {
350
319
  const m = model.toLowerCase();
package/dist/tui.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tui.js","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tui.js","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sofer_agent/cli",
3
- "version": "0.3.7",
3
+ "version": "0.3.8",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "sofer": "./dist/bin.js"
package/src/tui.ts CHANGED
@@ -1,13 +1,20 @@
1
1
  import type { SoferAgent, SoferConfig } from "@sofer_agent/core";
2
2
 
3
- const SIDEBAR_W = 26;
4
- const MIN_CHAT_W = 30;
3
+ const SIDEBAR_W = 28;
4
+ const MIN_CHAT_W = 34;
5
5
  const GUTTER = " ";
6
6
  const LABEL_W = 6;
7
7
  const INDENT = `${GUTTER}${" ".repeat(LABEL_W + 1)}`;
8
8
  const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
9
9
  const SPINNER_MS = 80;
10
10
 
11
+ // Box-drawing: ╭ ─ ╮ │ ╰ ╯ ├ ┤ ┬ ┴ ┼
12
+ const B = {
13
+ tl: "╭", tr: "╮", bl: "╰", br: "╯",
14
+ h: "─", v: "│",
15
+ lt: "├", rt: "┤", tt: "┬", bt: "┴",
16
+ };
17
+
11
18
  export interface ChatLine {
12
19
  role: "you" | "agent" | "system" | "error";
13
20
  text: string;
@@ -22,10 +29,11 @@ export class SoferTui {
22
29
  private state: ChatLine[] = [];
23
30
  private inputBuf = "";
24
31
  private cursor = 0;
25
- private columns = 80;
26
- private rows = 24;
27
- private chatW = 50;
28
- private chatH = 20;
32
+ private columns = 90;
33
+ private rows = 28;
34
+ private chatW = 58;
35
+ private sideW = 26;
36
+ private bodyH = 22;
29
37
  private scrollOff = 0;
30
38
  // spinner
31
39
  private status: "idle" | "thinking" = "idle";
@@ -34,7 +42,7 @@ export class SoferTui {
34
42
  private turnStartedAt = 0;
35
43
  // interrupt
36
44
  private abortCtrl: AbortController | null = null;
37
- // sidebar info
45
+ // sidebar
38
46
  private info: TuiInfo = { lastTurnIn: 0, lastTurnOut: 0 };
39
47
  // callbacks
40
48
  private resolve: (() => void) | null = null;
@@ -46,10 +54,11 @@ export class SoferTui {
46
54
  ) {}
47
55
 
48
56
  private measure(): void {
49
- this.columns = process.stdout.columns ?? 80;
50
- this.rows = process.stdout.rows ?? 24;
51
- this.chatW = Math.max(MIN_CHAT_W, this.columns - SIDEBAR_W - 1);
52
- this.chatH = this.rows - 3;
57
+ this.columns = Math.max(80, process.stdout.columns ?? 80);
58
+ this.rows = Math.max(24, process.stdout.rows ?? 24);
59
+ this.chatW = Math.max(MIN_CHAT_W, this.columns - SIDEBAR_W - 3);
60
+ this.sideW = this.columns - this.chatW - 3;
61
+ this.bodyH = this.rows - 5; // top border, input box(3), footer(1)
53
62
  }
54
63
 
55
64
  addMessage(role: ChatLine["role"], text: string): void {
@@ -80,20 +89,15 @@ export class SoferTui {
80
89
  }
81
90
  }
82
91
 
83
- /** Start the interactive TUI loop. */
84
92
  async run(onLine: (line: string, signal?: AbortSignal) => Promise<void>): Promise<void> {
85
93
  this.onLine = onLine;
86
94
  this.measure();
87
-
88
95
  if (process.stdin.isTTY) process.stdin.setRawMode?.(true);
89
96
  process.stdin.on("data", this.handleInput);
90
97
  process.stdout.on("resize", this.handleResize);
91
98
  process.on("SIGWINCH", this.handleResize);
92
-
93
99
  this.render();
94
- return new Promise<void>((resolve) => {
95
- this.resolve = resolve;
96
- });
100
+ return new Promise<void>((resolve) => { this.resolve = resolve; });
97
101
  }
98
102
 
99
103
  private shutdown(): void {
@@ -113,35 +117,20 @@ export class SoferTui {
113
117
  const str = data.toString();
114
118
  for (const ch of str) {
115
119
  const code = ch.charCodeAt(0);
116
- if (code === 3) {
117
- this.shutdown();
118
- return;
119
- } // Ctrl-C
120
- if (code === 4 && this.inputBuf.length === 0) {
121
- this.shutdown();
122
- return;
123
- } // Ctrl-D
120
+ if (code === 3) { this.shutdown(); return; }
121
+ if (code === 4 && this.inputBuf.length === 0) { this.shutdown(); return; }
124
122
  if (code === 27) {
125
- // Escape
126
- if (this.status === "thinking" && this.abortCtrl) {
127
- this.abortCtrl.abort();
128
- return;
129
- }
130
- this.inputBuf = ""; // clear input on Esc when idle
123
+ if (this.status === "thinking" && this.abortCtrl) { this.abortCtrl.abort(); return; }
124
+ this.inputBuf = "";
131
125
  this.cursor = 0;
132
126
  this.render();
133
127
  return;
134
128
  }
135
- if (this.status === "thinking") continue; // reject input while thinking
136
- if (code === 13) {
137
- this.submit();
138
- return;
139
- } // Enter
129
+ if (this.status === "thinking") continue;
130
+ if (code === 13) { this.submit(); return; }
140
131
  if (code === 127) {
141
- // Backspace
142
132
  if (this.cursor > 0) {
143
- this.inputBuf =
144
- this.inputBuf.slice(0, this.cursor - 1) + this.inputBuf.slice(this.cursor);
133
+ this.inputBuf = this.inputBuf.slice(0, this.cursor - 1) + this.inputBuf.slice(this.cursor);
145
134
  this.cursor--;
146
135
  }
147
136
  this.render();
@@ -159,171 +148,140 @@ export class SoferTui {
159
148
  const line = this.inputBuf.trim();
160
149
  this.inputBuf = "";
161
150
  this.cursor = 0;
162
- if (!line) {
163
- this.render();
164
- return;
165
- }
166
- if (line === "/exit" || line === "/quit") {
167
- this.shutdown();
168
- return;
169
- }
170
-
151
+ if (!line) { this.render(); return; }
152
+ if (line === "/exit" || line === "/quit") { this.shutdown(); return; }
171
153
  this.addMessage("you", line);
172
154
  this.scrollOff = 0;
173
155
  this.abortCtrl = new AbortController();
174
156
  this.startSpinner();
175
157
  this.render();
176
-
177
158
  await this.onLine?.(line, this.abortCtrl.signal);
178
-
179
159
  this.abortCtrl = null;
180
160
  this.stopSpinner();
181
161
  this.render();
182
162
  }
183
163
 
184
164
  // ── Rendering ───────────────────────────────────────────────────────────
185
- private handleResize = (): void => {
186
- this.measure();
187
- this.render();
188
- };
165
+
166
+ private handleResize = (): void => { this.measure(); this.render(); };
189
167
 
190
168
  render(): void {
191
169
  this.measure();
192
- const out = process.stdout;
193
- out.write("\x1b[?25l");
194
- out.write("\x1b[H");
195
- out.write(this.buildFrame());
196
- out.write("\x1b[?25h");
170
+ process.stdout.write("\x1b[?25l\x1b[H" + this.buildFrame() + "\x1b[?25h");
197
171
  }
198
172
 
199
173
  private buildFrame(): string {
200
- const { chatW, chatH } = this;
201
- const rightW = this.columns - chatW - 1;
174
+ const { columns, chatW, sideW, bodyH } = this;
175
+ const innerSideW = sideW - 2;
176
+ const sep = `${B.lt}${B.h.repeat(chatW)}${B.bt}${B.h.repeat(sideW)}${B.rt}`;
177
+ const inputW = columns - 2; // inside border
178
+
202
179
  let buf = "";
203
180
 
204
- // ── Chat body ─────────────────────────────────────────────────────────
181
+ // ── Top border ────────────────────────────────────────────────────────
182
+ buf += `${B.tl}${B.h.repeat(chatW)}${B.tt}${B.h.repeat(sideW)}${B.tr}\n`;
183
+
184
+ // ── Body ──────────────────────────────────────────────────────────────
205
185
  const wrapped = this.state.flatMap((m) => this.wrapMessage(m, chatW));
206
- const maxScroll = Math.max(0, wrapped.length - chatH);
186
+ const maxScroll = Math.max(0, wrapped.length - bodyH);
207
187
  if (this.scrollOff > maxScroll) this.scrollOff = maxScroll;
208
188
  if (this.scrollOff < 0) this.scrollOff = 0;
209
- const visible = wrapped.slice(this.scrollOff, this.scrollOff + chatH);
210
-
211
- for (let r = 0; r < chatH; r++) {
212
- const line = visible[r];
213
- if (line) buf += this.pad(line, chatW);
214
- else buf += " ".repeat(chatW);
215
- if (r === 0) buf += "┬";
216
- else if (r === chatH - 1) buf += "┴";
217
- else buf += "│";
218
- buf += this.sidebarRow(r, chatH, rightW);
219
- buf += "\n";
189
+ const visible = wrapped.slice(this.scrollOff, this.scrollOff + bodyH);
190
+
191
+ const sidebarLines = this.buildSidebar(innerSideW);
192
+ const sbTop = Math.max(0, Math.floor((bodyH - sidebarLines.length) / 2));
193
+
194
+ for (let r = 0; r < bodyH; r++) {
195
+ buf += B.v;
196
+ buf += visible[r] ? padTrunc(visible[r]!, chatW) : " ".repeat(chatW);
197
+ buf += B.v;
198
+ const sbIdx = r - sbTop;
199
+ const sbLine = (sbIdx >= 0 && sbIdx < sidebarLines.length) ? sidebarLines[sbIdx]! : "";
200
+ buf += ` ${padRight(sbLine, innerSideW)} `;
201
+ buf += `${B.v}\n`;
220
202
  }
221
203
 
222
- // ── Divider ───────────────────────────────────────────────────────────
223
- buf += `${"─".repeat(chatW)}┴${"─".repeat(rightW)}\n`;
204
+ // ── Separator ─────────────────────────────────────────────────────────
205
+ buf += `${sep}\n`;
224
206
 
225
207
  // ── Spinner row ───────────────────────────────────────────────────────
226
208
  if (this.status === "thinking") {
227
- const frame = SPINNER_FRAMES[this.spinnerFrame];
209
+ const frame = SPINNER_FRAMES[this.spinnerFrame]!;
228
210
  const elapsed = this.turnStartedAt ? formatElapsed(Date.now() - this.turnStartedAt) : "";
229
- buf += `\x1b[36m${frame} thinking…${elapsed ? ` ${elapsed}` : ""} (esc to interrupt)\x1b[0m\x1b[K\n`;
211
+ buf += `${B.v} \x1b[36m${frame} thinking…${elapsed ? ` ${elapsed}` : ""} (esc to interrupt)\x1b[0m${" ".repeat(Math.max(0, inputW - 28 - elapsed.length))}${B.v}\n`;
230
212
  }
231
213
 
232
- // ── Input bar ─────────────────────────────────────────────────────────
233
- const prefix = "\x1b[36m> \x1b[0m";
234
- const cursorChar = this.status === "idle" ? "\x1b[5m▋\x1b[25m" : "";
235
- buf += `${prefix}${this.inputBuf}${cursorChar}\x1b[K`;
236
-
237
- // Footer
214
+ // ── Input bar (bordered box) ─────────────────────────────────────────
215
+ buf += `${B.tl}${B.h.repeat(inputW)}${B.tr}\n`;
216
+ const cursorCh = this.status === "idle" ? "\x1b[5m▋\x1b[25m" : "";
217
+ const inputMaxW = inputW - 3; // "> " prefix + 1 padding
218
+ const visibleInput = this.inputBuf.length > inputMaxW
219
+ ? this.inputBuf.slice(this.inputBuf.length - inputMaxW)
220
+ : this.inputBuf;
221
+ const inputPad = inputMaxW - visibleInput.length;
222
+ buf += `${B.v} \x1b[36m>\x1b[0m ${visibleInput}${cursorCh}${" ".repeat(Math.max(0, inputPad))} ${B.v}\n`;
223
+ buf += `${B.bl}${B.h.repeat(inputW)}${B.br}\n`;
224
+
225
+ // ── Footer ────────────────────────────────────────────────────────────
238
226
  const totalIn = this.agent.usage.tokens.inputTokens;
239
227
  const totalOut = this.agent.usage.tokens.outputTokens;
240
228
  const cost = this.agent.usage.costUsd.toFixed(4);
241
- const footer = `\x1b[90m${this.agent.address.slice(0, 10)}… · tokens ${totalIn}/${totalOut} · $${cost} · /exit to quit\x1b[0m`;
242
- buf += `\n${this.pad(footer, this.columns)}`;
229
+ const ft = `\x1b[90m${this.agent.address.slice(0, 10)}… · in ${totalIn} out ${totalOut} $${cost} /exit\x1b[0m`;
230
+ buf += `${padTrunc(ft, columns)}\n`;
243
231
 
244
- // Place cursor at input position
245
- const cursorCol = 2 + Math.min(this.cursor, this.columns - 5);
246
- buf += `\x1b[${this.chatH + 2 + (this.status === "thinking" ? 1 : 0)};${cursorCol}H`;
232
+ // ── Cursor position ───────────────────────────────────────────────────
233
+ const cursorRow = bodyH + 1 + (this.status === "thinking" ? 1 : 0) + 1; // body + sep + spinner? + input
234
+ const cursorCol = 4 + Math.min(this.cursor, inputMaxW);
235
+ buf += `\x1b[${cursorRow};${cursorCol}H`;
247
236
 
248
237
  return buf;
249
238
  }
250
239
 
251
- // ── Message wrapping with gutter ────────────────────────────────────────
240
+ // ── Messages ────────────────────────────────────────────────────────────
252
241
 
253
242
  private wrapMessage(msg: ChatLine, width: number): string[] {
254
243
  const label = this.roleLabel(msg.role);
255
- const bodyWidth = width - GUTTER.length - LABEL_W - 1;
244
+ const bodyWidth = Math.max(10, width - GUTTER.length - LABEL_W - 1);
256
245
  const lines = wrapText(msg.text, bodyWidth);
257
- return lines.map((l, i) => {
258
- if (i === 0) return `${GUTTER}${label} ${l}`;
259
- return `${INDENT}${l}`;
260
- });
246
+ return lines.map((l, i) =>
247
+ i === 0 ? `${GUTTER}${label} ${l}` : `${INDENT}${l}`,
248
+ );
261
249
  }
262
250
 
263
251
  private roleLabel(role: ChatLine["role"]): string {
264
252
  switch (role) {
265
- case "you":
266
- return "\x1b[36myou \x1b[0m"; // cyan "you", padded to LABEL_W
267
- case "agent":
268
- return `\x1b[32m${this.agent.name.toLowerCase().slice(0, LABEL_W).padEnd(LABEL_W)}\x1b[0m`;
269
- case "system":
270
- return "\x1b[90msys \x1b[0m";
271
- case "error":
272
- return "\x1b[31merr \x1b[0m";
253
+ case "you": return "\x1b[36myou \x1b[0m";
254
+ case "agent": return `\x1b[32m${this.agent.name.toLowerCase().padEnd(LABEL_W)}\x1b[0m`;
255
+ case "system": return "\x1b[90msys \x1b[0m";
256
+ case "error": return "\x1b[31merr \x1b[0m";
273
257
  }
274
258
  }
275
259
 
276
- private pad(s: string, w: number): string {
277
- const stripped = stripAnsi(s);
278
- const padW = Math.max(0, w - visibleLen(stripped));
279
- return s + " ".repeat(padW);
280
- }
281
-
282
260
  // ── Sidebar ─────────────────────────────────────────────────────────────
283
261
 
284
- private sidebarRow(row: number, total: number, width: number): string {
285
- const innerW = width - 2;
286
- const lines = this.buildSidebar(innerW);
287
- const gap = Math.max(0, total - lines.length);
288
- const topPad = Math.floor(gap / 2);
289
- const idx = row - topPad;
290
- if (idx < 0 || idx >= lines.length) return " ".repeat(width);
291
- const line = lines[idx];
292
- if (!line) return " ".repeat(width);
293
- const padded = padRight(line, innerW);
294
- return ` ${padded} `;
295
- }
296
-
297
262
  private buildSidebar(width: number): string[] {
298
263
  const { agent, config, info } = this;
299
264
  const addr = `${agent.address.slice(0, 6)}…${agent.address.slice(-4)}`;
300
- const hbar = "─".repeat(width);
301
- const thinBar = "·".repeat(width);
302
265
  const totalIn = agent.usage.tokens.inputTokens;
303
266
  const totalOut = agent.usage.tokens.outputTokens;
304
- const cost = agent.usage.costUsd.toFixed(4);
267
+ const cost = agent.usage.costUsd.toFixed(6);
305
268
 
306
269
  return [
307
- hbar,
308
270
  `\x1b[1;36m${agent.name}\x1b[0m`,
309
271
  `\x1b[90m${addr}\x1b[0m`,
310
272
  "",
273
+ `${B.h.repeat(width)}`,
311
274
  `\x1b[90mnetwork\x1b[0m ${config.network}`,
312
275
  `\x1b[90mmodel\x1b[0m ${shortModel(config.brain.model)}`,
313
- thinBar,
314
- `\x1b[90mlast turn\x1b[0m`,
315
- ` in ${info.lastTurnIn}`,
316
- ` out ${info.lastTurnOut}`,
317
- `\x1b[90mtotal\x1b[0m`,
318
- ` in ${totalIn}`,
319
- ` out ${totalOut}`,
320
- `\x1b[90mcost\x1b[0m \x1b[33m$${cost}\x1b[0m`,
321
- thinBar,
322
- `\x1b[90maddress\x1b[0m`,
323
- ` ${agent.address.slice(0, 16)}`,
324
- ` ${agent.address.slice(16, 32)}`,
325
- ` ${agent.address.slice(32)}`,
326
- hbar,
276
+ "",
277
+ `\x1b[90m▸ last turn\x1b[0m`,
278
+ ` in ${info.lastTurnIn}`,
279
+ ` out ${info.lastTurnOut}`,
280
+ "",
281
+ `\x1b[90m▸ total\x1b[0m`,
282
+ ` in ${totalIn}`,
283
+ ` out ${totalOut}`,
284
+ ` \x1b[33m$${cost}\x1b[0m`,
327
285
  ];
328
286
  }
329
287
  }
@@ -334,16 +292,12 @@ function wrapText(text: string, width: number): string[] {
334
292
  if (!text) return [""];
335
293
  const lines: string[] = [];
336
294
  const words = text.split(" ");
337
- let current = "";
338
- for (const word of words) {
339
- if (current && current.length + 1 + word.length > width) {
340
- lines.push(current);
341
- current = word;
342
- } else {
343
- current = current ? `${current} ${word}` : word;
344
- }
295
+ let cur = "";
296
+ for (const w of words) {
297
+ if (cur && cur.length + 1 + w.length > width) { lines.push(cur); cur = w; }
298
+ else cur = cur ? `${cur} ${w}` : w;
345
299
  }
346
- if (current) lines.push(current);
300
+ if (cur) lines.push(cur);
347
301
  return lines.length > 0 ? lines : [""];
348
302
  }
349
303
 
@@ -354,31 +308,34 @@ function stripAnsi(s: string): string {
354
308
 
355
309
  function visibleLen(s: string): number {
356
310
  // biome-ignore lint/suspicious/noControlCharactersInRegex: ANSI escape stripping
357
- const ansiRe = /\x1b\[\d*;?\d*m/g;
311
+ const re = /\x1b\[\d*;?\d*m/g;
358
312
  let len = 0;
359
- let lastIdx = 0;
360
- let match = ansiRe.exec(s);
361
- while (match !== null) {
362
- len += match.index - lastIdx;
363
- lastIdx = match.index + match[0].length;
364
- match = ansiRe.exec(s);
313
+ let last = 0;
314
+ let m = re.exec(s);
315
+ while (m !== null) {
316
+ len += m.index - last;
317
+ last = m.index + m[0].length;
318
+ m = re.exec(s);
365
319
  }
366
- len += s.length - lastIdx;
367
- return len;
320
+ return len + s.length - last;
321
+ }
322
+
323
+ function padRight(s: string, w: number): string {
324
+ const vl = visibleLen(s);
325
+ return vl >= w ? s : s + " ".repeat(w - vl);
368
326
  }
369
327
 
370
- function padRight(s: string, width: number): string {
371
- const len = visibleLen(s);
372
- if (len >= width) return s;
373
- return s + " ".repeat(width - len);
328
+ function padTrunc(s: string, w: number): string {
329
+ const stripped = stripAnsi(s);
330
+ if (stripped.length <= w) return s + " ".repeat(w - stripped.length);
331
+ return stripped.slice(0, w);
374
332
  }
375
333
 
376
334
  function formatElapsed(ms: number): string {
377
335
  const sec = Math.floor(ms / 1000);
378
336
  if (sec < 60) return `${sec}s`;
379
337
  const m = Math.floor(sec / 60);
380
- const s = sec % 60;
381
- return `${m}m${String(s).padStart(2, "0")}s`;
338
+ return `${m}m${String(sec % 60).padStart(2, "0")}s`;
382
339
  }
383
340
 
384
341
  function shortModel(model: string): string {