@sofer_agent/cli 0.3.16 → 0.3.18

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/bin/sofer ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bun
2
+ import "@opentui/solid/preload";
3
+ import "../src/bin.ts";
package/dist/bin.js CHANGED
File without changes
@@ -1 +1 @@
1
- {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../src/chat.ts"],"names":[],"mappings":"AA+CA,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAwCjD"}
1
+ {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../src/chat.ts"],"names":[],"mappings":"AAsCA,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAwCjD"}
package/dist/chat.js CHANGED
@@ -2,7 +2,7 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { dirname } from "node:path";
3
3
  import { agentPaths, loadConfig, shortAgentId, SoferAgent, } from "@sofer_agent/core";
4
4
  import { loadSecrets } from "./env.js";
5
- import { SoferTui } from "./tui.js";
5
+ import { createTuiState, runTui } from "./tui.jsx";
6
6
  function sessionPath(config) {
7
7
  if (config.agentObjectId)
8
8
  return agentPaths.agent(shortAgentId(config.agentObjectId)).activityLog;
@@ -28,17 +28,6 @@ function saveSession(path, messages) {
28
28
  mkdirSync(dirname(path), { recursive: true });
29
29
  writeFileSync(path, messages.map((m) => JSON.stringify(m)).join("\n") + "\n", "utf8");
30
30
  }
31
- function cleanError(raw) {
32
- try {
33
- const obj = JSON.parse(raw);
34
- if (obj?.error?.type === "overloaded_error")
35
- return "Claude is overloaded — try again in a moment.";
36
- if (obj?.error?.message)
37
- return obj.error.message;
38
- }
39
- catch { /* not JSON */ }
40
- return raw;
41
- }
42
31
  export async function chatCommand() {
43
32
  const config = loadConfig();
44
33
  const secrets = loadSecrets();
@@ -56,28 +45,39 @@ export async function chatCommand() {
56
45
  if (history.length > 0)
57
46
  agent.loadHistory(history);
58
47
  }
59
- const tui = new SoferTui(agent, config);
60
- agent.getBalance().then((bal) => tui.setInfo({ balance: (Number(bal) / 1e9).toFixed(4) })).catch(() => { });
61
- await tui.run(async (line, signal) => {
48
+ const tuiState = createTuiState();
49
+ const [, setRows] = tuiState.rows;
50
+ const [, setInfo] = tuiState.info;
51
+ agent.getBalance().then((bal) => setInfo((prev) => ({ ...prev, balance: (Number(bal) / 1e9).toFixed(4) }))).catch(() => { });
52
+ await runTui(tuiState, agent, config, async (line, signal) => {
62
53
  try {
63
54
  const { text, turnUsage } = await agent.chat(line, signal);
64
- tui.addMessage("agent", text);
65
- tui.setInfo({ lastTurnIn: turnUsage.inputTokens, lastTurnOut: turnUsage.outputTokens });
55
+ setRows((prev) => [...prev, { role: "agent", text }]);
56
+ setInfo((prev) => ({ ...prev, lastTurnIn: turnUsage.inputTokens, lastTurnOut: turnUsage.outputTokens }));
66
57
  }
67
58
  catch (e) {
68
- if (signal?.aborted) {
69
- tui.addMessage("system", "turn interrupted (esc).");
59
+ if (signal.aborted) {
60
+ setRows((prev) => [...prev, { role: "system", text: "turn interrupted." }]);
70
61
  }
71
62
  else {
72
63
  const raw = e instanceof Error ? e.message : String(e);
73
- const clean = cleanError(raw);
74
- tui.addMessage("error", clean);
64
+ setRows((prev) => [...prev, { role: "error", text: cleanError(raw) }]);
75
65
  }
76
66
  }
77
- agent.getBalance().then((bal) => tui.setInfo({ balance: (Number(bal) / 1e9).toFixed(4) })).catch(() => { });
67
+ agent.getBalance().then((bal) => setInfo((prev) => ({ ...prev, balance: (Number(bal) / 1e9).toFixed(4) }))).catch(() => { });
78
68
  if (sp)
79
69
  saveSession(sp, agent.getHistory());
80
- tui.render();
81
70
  });
82
71
  }
72
+ function cleanError(raw) {
73
+ try {
74
+ const obj = JSON.parse(raw);
75
+ if (obj?.error?.type === "overloaded_error")
76
+ return "Claude is overloaded — try again in a moment.";
77
+ if (obj?.error?.message)
78
+ return obj.error.message;
79
+ }
80
+ catch { /* not JSON */ }
81
+ return raw;
82
+ }
83
83
  //# sourceMappingURL=chat.js.map
package/dist/chat.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"chat.js","sourceRoot":"","sources":["../src/chat.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chat.js","sourceRoot":"","sources":["../src/chat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EACL,UAAU,EAEV,UAAU,EACV,YAAY,EACZ,UAAU,GACX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAOnD,SAAS,WAAW,CAAC,MAAmB;IACtC,IAAI,MAAM,CAAC,aAAa;QAAE,OAAO,UAAU,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,WAAW,CAAC;IAClG,IAAI,MAAM,CAAC,MAAM,CAAC,SAAS;QAAE,OAAO,UAAU,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC;IACxG,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,WAAW,CAAC,IAAY;IAC/B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACjC,MAAM,QAAQ,GAAqB,EAAE,CAAC;IACtC,KAAK,MAAM,IAAI,IAAI,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1D,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE,SAAS;QAC3B,IAAI,CAAC;YAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAmB,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,WAAW,CAAC,IAAY,EAAE,QAA0B;IAC3D,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;AACxF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;IAC9B,IAAI,CAAC,OAAO,CAAC,YAAY,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;QACtD,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE;QAC5C,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,eAAe,EAAE,OAAO,CAAC,eAAe;KACzC,CAAC,CAAC;IAEH,MAAM,EAAE,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IAC/B,IAAI,EAAE,EAAE,CAAC;QACP,MAAM,OAAO,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;QAChC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;YAAE,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAC;IAClC,MAAM,CAAC,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC;IAClC,MAAM,CAAC,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC;IAElC,KAAK,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAE5H,MAAM,MAAM,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE;QAC3D,IAAI,CAAC;YACH,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAC3D,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YACtD,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,UAAU,EAAE,SAAS,CAAC,WAAW,EAAE,WAAW,EAAE,SAAS,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;QAC3G,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnB,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,mBAAmB,EAAE,CAAC,CAAC,CAAC;YAC9E,CAAC;iBAAM,CAAC;gBACN,MAAM,GAAG,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;gBACvD,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;YACzE,CAAC;QACH,CAAC;QACD,KAAK,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC5H,IAAI,EAAE;YAAE,WAAW,CAAC,EAAE,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,UAAU,CAAC,GAAW;IAC7B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,GAAG,EAAE,KAAK,EAAE,IAAI,KAAK,kBAAkB;YAAE,OAAO,+CAA+C,CAAC;QACpG,IAAI,GAAG,EAAE,KAAK,EAAE,OAAO;YAAE,OAAO,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC,CAAC,cAAc,CAAC,CAAC;IAC1B,OAAO,GAAG,CAAC;AACb,CAAC"}
package/dist/tui.d.ts CHANGED
@@ -1,4 +1,14 @@
1
1
  import type { SoferAgent, SoferConfig } from "@sofer_agent/core";
2
+ import { createSignal } from "solid-js";
3
+ export interface TuiState {
4
+ rows: ReturnType<typeof createSignal<ChatLine[]>>;
5
+ status: ReturnType<typeof createSignal<"idle" | "thinking">>;
6
+ input: ReturnType<typeof createSignal<string>>;
7
+ info: ReturnType<typeof createSignal<TuiInfo>>;
8
+ spinnerFrame: ReturnType<typeof createSignal<number>>;
9
+ turnStartedAt: ReturnType<typeof createSignal<number | null>>;
10
+ activeAbort: ReturnType<typeof createSignal<AbortController | null>>;
11
+ }
2
12
  export interface ChatLine {
3
13
  role: "you" | "agent" | "system" | "error";
4
14
  text: string;
@@ -8,41 +18,6 @@ export interface TuiInfo {
8
18
  lastTurnOut: number;
9
19
  balance?: string;
10
20
  }
11
- export declare class SoferTui {
12
- private readonly agent;
13
- private readonly config;
14
- private state;
15
- private inputBuf;
16
- private cursor;
17
- private columns;
18
- private rows;
19
- private chatW;
20
- private sideW;
21
- private bodyH;
22
- private scrollOff;
23
- private status;
24
- private spinnerFrame;
25
- private spinnerTimer;
26
- private turnStartedAt;
27
- private abortCtrl;
28
- private info;
29
- private resolve;
30
- private onLine;
31
- constructor(agent: SoferAgent, config: SoferConfig);
32
- private measure;
33
- addMessage(role: ChatLine["role"], text: string): void;
34
- setInfo(info: Partial<TuiInfo>): void;
35
- private startSpinner;
36
- private stopSpinner;
37
- run(onLine: (line: string, signal?: AbortSignal) => Promise<void>): Promise<void>;
38
- private shutdown;
39
- private handleInput;
40
- private submit;
41
- private handleResize;
42
- render(): void;
43
- private buildFrame;
44
- private wrapMessage;
45
- private roleLabel;
46
- private buildSidebar;
47
- }
21
+ export declare function createTuiState(): TuiState;
22
+ export declare function runTui(state: TuiState, agent: SoferAgent, config: SoferConfig, onSubmit: (line: string, signal: AbortSignal) => Promise<void>): Promise<void>;
48
23
  //# 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;AAgBjE,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;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,QAAQ;IAoBjB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM;IApBzB,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,CAA2B;IAC5C,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,YAAY,CAA+C;IACnE,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,IAAI,CAA8C;IAC1D,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;IAKtD,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;IAWhB,OAAO,CAAC,WAAW,CA6BjB;YAEY,MAAM;IAgBpB,OAAO,CAAC,YAAY,CAAkD;IAEtE,MAAM,IAAI,IAAI;IAKd,OAAO,CAAC,UAAU;IA8DlB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,SAAS;IASjB,OAAO,CAAC,YAAY;CA8BrB"}
1
+ {"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAqB,YAAY,EAAa,MAAM,UAAU,CAAC;AAKtE,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;IAClD,MAAM,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC;IAC7D,KAAK,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;IAC/C,IAAI,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/C,YAAY,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;IACtD,aAAa,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IAC9D,WAAW,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC,CAAC;CACtE;AAED,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;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AA+LD,wBAAgB,cAAc,IAAI,QAAQ,CAUzC;AAED,wBAAsB,MAAM,CAC1B,KAAK,EAAE,QAAQ,EACf,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,GAC7D,OAAO,CAAC,IAAI,CAAC,CAYf"}
package/dist/tui.jsx ADDED
@@ -0,0 +1,182 @@
1
+ import { render, useKeyboard, useTerminalDimensions } from "@opentui/solid";
2
+ import { For, createEffect, createSignal, onCleanup } from "solid-js";
3
+ const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
4
+ const SPINNER_MS = 80;
5
+ function formatElapsed(startedAt) {
6
+ if (!startedAt)
7
+ return "";
8
+ const sec = Math.floor((Date.now() - startedAt) / 1000);
9
+ if (sec < 60)
10
+ return `${sec}s`;
11
+ const m = Math.floor(sec / 60);
12
+ return `${m}m${String(sec % 60).padStart(2, "0")}s`;
13
+ }
14
+ function shortModel(model) {
15
+ const m = model.toLowerCase();
16
+ if (m.includes("sonnet"))
17
+ return "sonnet-4";
18
+ if (m.includes("haiku"))
19
+ return "haiku";
20
+ if (m.includes("opus"))
21
+ return "opus-4";
22
+ return model.length > 14 ? `${model.slice(0, 13)}…` : model;
23
+ }
24
+ function App(props) {
25
+ const { state, agent, config } = props;
26
+ const dims = useTerminalDimensions();
27
+ const [rows] = state.rows;
28
+ const [status] = state.status;
29
+ const [input, setInput] = state.input;
30
+ const [info] = state.info;
31
+ const [spinnerFrame, setSpinnerFrame] = state.spinnerFrame;
32
+ const [turnStartedAt] = state.turnStartedAt;
33
+ const [, setActiveAbort] = state.activeAbort;
34
+ const [activeAbort] = state.activeAbort;
35
+ createEffect(() => {
36
+ if (status() !== "thinking") {
37
+ setSpinnerFrame(0);
38
+ return;
39
+ }
40
+ const id = setInterval(() => setSpinnerFrame((f) => (f + 1) % SPINNER_FRAMES.length), SPINNER_MS);
41
+ onCleanup(() => clearInterval(id));
42
+ });
43
+ useKeyboard((evt) => {
44
+ if (evt.ctrl && evt.name === "c") {
45
+ evt.preventDefault();
46
+ props.onExit();
47
+ return;
48
+ }
49
+ if (evt.name === "escape") {
50
+ const ab = activeAbort();
51
+ if (ab && !ab.signal.aborted)
52
+ ab.abort();
53
+ return;
54
+ }
55
+ if (status() === "thinking")
56
+ return;
57
+ if (evt.name === "return") {
58
+ const text = input().trim();
59
+ if (!text)
60
+ return;
61
+ if (text === "/exit" || text === "/quit") {
62
+ props.onExit();
63
+ return;
64
+ }
65
+ const ctrl = new AbortController();
66
+ setActiveAbort(ctrl);
67
+ state.rows[1](prev => [...prev, { role: "you", text }]);
68
+ setInput("");
69
+ state.status[1]("thinking");
70
+ state.turnStartedAt[1](Date.now());
71
+ props.onSubmit(text, ctrl.signal).finally(() => {
72
+ state.status[1]("idle");
73
+ state.turnStartedAt[1](null);
74
+ setActiveAbort(null);
75
+ });
76
+ return;
77
+ }
78
+ if (evt.name === "backspace" || evt.name === "delete") {
79
+ setInput((p) => p.slice(0, -1));
80
+ return;
81
+ }
82
+ if (evt.sequence && !evt.ctrl && !evt.meta && !evt.option) {
83
+ setInput((p) => p + evt.sequence);
84
+ }
85
+ });
86
+ const sidebarW = Math.min(30, Math.floor(dims().width * 0.22));
87
+ const chatW = dims().width - sidebarW;
88
+ const addr = () => `${agent.address.slice(0, 6)}…${agent.address.slice(-4)}`;
89
+ return (<box flexDirection="row" width={dims().width} height={dims().height}>
90
+ {/* Chat area */}
91
+ <box flexDirection="column" width={chatW} height={dims().height}>
92
+ <scrollbox flexGrow={1} flexShrink={1} stickyScroll stickyStart="bottom" contentOptions={{ flexDirection: "column", paddingLeft: 1, paddingRight: 1, paddingTop: 1, paddingBottom: 1 }}>
93
+ <For each={rows()}>
94
+ {(line) => {
95
+ const color = line.role === "you" ? "#67e8f9"
96
+ : line.role === "agent" ? "#86efac"
97
+ : line.role === "error" ? "#fca5a5"
98
+ : "#9ca3af";
99
+ const label = line.role === "you" ? "you"
100
+ : line.role === "agent" ? agent.name.toLowerCase().slice(0, 5)
101
+ : line.role === "error" ? "err"
102
+ : "sys";
103
+ return (<box flexDirection="row">
104
+ <text fg={color} flexShrink={0}>{` ${label.padEnd(5)} `}</text>
105
+ <text wrapMode="word" flexGrow={1} fg="#e5e7eb">
106
+ {line.text}
107
+ </text>
108
+ </box>);
109
+ }}
110
+ </For>
111
+ </scrollbox>
112
+
113
+ <box flexDirection="row" flexShrink={0} paddingLeft={3} paddingRight={2} marginTop={1}>
114
+ <text fg="#67e8f9" flexGrow={1}>
115
+ {(() => {
116
+ if (status() !== "thinking")
117
+ return " ";
118
+ const frame = SPINNER_FRAMES[spinnerFrame()];
119
+ const elapsed = formatElapsed(turnStartedAt());
120
+ return elapsed
121
+ ? `${frame} thinking… ${elapsed} (esc to interrupt)`
122
+ : `${frame} thinking… (esc to interrupt)`;
123
+ })()}
124
+ </text>
125
+ </box>
126
+
127
+ <box flexDirection="row" flexShrink={0} minHeight={3} maxHeight={8} borderStyle="rounded" borderColor="#374151" paddingLeft={1} paddingRight={1} marginLeft={2} marginRight={2}>
128
+ <text fg="#67e8f9" flexShrink={0}>{"› "}</text>
129
+ <text wrapMode="word" flexGrow={1} fg="#e5e7eb">
130
+ {`${input()}${status() === "idle" ? "▋" : ""}`}
131
+ </text>
132
+ </box>
133
+
134
+ <box flexDirection="row" flexShrink={0} paddingLeft={2} paddingRight={2}>
135
+ <text fg="#9ca3af">
136
+ {[
137
+ addr(),
138
+ config.network,
139
+ shortModel(config.brain.model),
140
+ info().balance ? `${info().balance} SUI` : null,
141
+ `in ${agent.usage.tokens.inputTokens} out ${agent.usage.tokens.outputTokens} $${agent.usage.costUsd.toFixed(4)}`,
142
+ "/exit",
143
+ ].filter(Boolean).join(" · ")}
144
+ </text>
145
+ </box>
146
+ </box>
147
+
148
+ {/* Sidebar */}
149
+ <box flexDirection="column" width={sidebarW} borderStyle="single" borderColor="#374151" paddingLeft={2} paddingRight={1}>
150
+ <text fg="#86efac">{agent.name}</text>
151
+ <text fg="#9ca3af">{addr()}</text>
152
+ <text>{" "}</text>
153
+ <text fg="#6b7280">{"─".repeat(sidebarW - 4)}</text>
154
+ <text fg="#9ca3af">{`network ${config.network}`}</text>
155
+ <text fg="#9ca3af">{`model ${shortModel(config.brain.model)}`}</text>
156
+ {info().balance ? <text fg="#fbbf24">{`balance ${info().balance} SUI`}</text> : null}
157
+ <text>{" "}</text>
158
+ <text fg="#6b7280">{"─".repeat(sidebarW - 4)}</text>
159
+ <text fg="#9ca3af">{`last in ${info().lastTurnIn} out ${info().lastTurnOut}`}</text>
160
+ <text fg="#9ca3af">{`total in ${agent.usage.tokens.inputTokens}`}</text>
161
+ <text fg="#9ca3af">{` out ${agent.usage.tokens.outputTokens}`}</text>
162
+ <text fg="#fbbf24">{` $${agent.usage.costUsd.toFixed(6)}`}</text>
163
+ </box>
164
+ </box>);
165
+ }
166
+ export function createTuiState() {
167
+ return {
168
+ rows: createSignal([]),
169
+ status: createSignal("idle"),
170
+ input: createSignal(""),
171
+ info: createSignal({ lastTurnIn: 0, lastTurnOut: 0 }),
172
+ spinnerFrame: createSignal(0),
173
+ turnStartedAt: createSignal(null),
174
+ activeAbort: createSignal(null),
175
+ };
176
+ }
177
+ export async function runTui(state, agent, config, onSubmit) {
178
+ return new Promise((resolve) => {
179
+ render(() => (<App state={state} agent={agent} config={config} onSubmit={onSubmit} onExit={resolve}/>));
180
+ });
181
+ }
182
+ //# sourceMappingURL=tui.jsx.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui.jsx","sourceRoot":"","sources":["../src/tui.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@sofer_agent/cli",
3
- "version": "0.3.16",
3
+ "version": "0.3.18",
4
4
  "type": "module",
5
5
  "bin": {
6
- "sofer": "./dist/bin.js"
6
+ "sofer": "./bin/sofer"
7
7
  },
8
8
  "files": [
9
+ "bin",
9
10
  "dist",
10
11
  "src"
11
12
  ],
@@ -26,14 +27,17 @@
26
27
  ],
27
28
  "dependencies": {
28
29
  "@clack/prompts": "^1.5.1",
29
- "@sofer_agent/core": "0.3.3"
30
+ "@opentui/core": "^0.1.97",
31
+ "@opentui/solid": "^0.1.97",
32
+ "@sofer_agent/core": "0.3.3",
33
+ "solid-js": "^1.9.12"
30
34
  },
31
35
  "devDependencies": {
32
36
  "@types/node": "^22.10.2",
33
37
  "typescript": "^5.7.2"
34
38
  },
35
39
  "scripts": {
36
- "build": "tsc -b && chmod +x dist/bin.js",
40
+ "build": "tsc -b && chmod +x bin/sofer",
37
41
  "typecheck": "tsc --noEmit"
38
42
  }
39
43
  }
package/src/chat.ts CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  SoferAgent,
9
9
  } from "@sofer_agent/core";
10
10
  import { loadSecrets } from "./env.js";
11
- import { SoferTui } from "./tui.js";
11
+ import { createTuiState, runTui } from "./tui.jsx";
12
12
 
13
13
  interface SessionMessage {
14
14
  role: string;
@@ -36,15 +36,6 @@ function saveSession(path: string, messages: SessionMessage[]): void {
36
36
  writeFileSync(path, messages.map((m) => JSON.stringify(m)).join("\n") + "\n", "utf8");
37
37
  }
38
38
 
39
- function cleanError(raw: string): string {
40
- try {
41
- const obj = JSON.parse(raw);
42
- if (obj?.error?.type === "overloaded_error") return "Claude is overloaded — try again in a moment.";
43
- if (obj?.error?.message) return obj.error.message;
44
- } catch { /* not JSON */ }
45
- return raw;
46
- }
47
-
48
39
  export async function chatCommand(): Promise<void> {
49
40
  const config = loadConfig();
50
41
  const secrets = loadSecrets();
@@ -63,26 +54,35 @@ export async function chatCommand(): Promise<void> {
63
54
  if (history.length > 0) agent.loadHistory(history);
64
55
  }
65
56
 
66
- const tui = new SoferTui(agent, config);
57
+ const tuiState = createTuiState();
58
+ const [, setRows] = tuiState.rows;
59
+ const [, setInfo] = tuiState.info;
67
60
 
68
- agent.getBalance().then((bal) => tui.setInfo({ balance: (Number(bal) / 1e9).toFixed(4) })).catch(() => {});
61
+ agent.getBalance().then((bal) => setInfo((prev) => ({ ...prev, balance: (Number(bal) / 1e9).toFixed(4) }))).catch(() => {});
69
62
 
70
- await tui.run(async (line, signal) => {
63
+ await runTui(tuiState, agent, config, async (line, signal) => {
71
64
  try {
72
65
  const { text, turnUsage } = await agent.chat(line, signal);
73
- tui.addMessage("agent", text);
74
- tui.setInfo({ lastTurnIn: turnUsage.inputTokens, lastTurnOut: turnUsage.outputTokens });
66
+ setRows((prev) => [...prev, { role: "agent", text }]);
67
+ setInfo((prev) => ({ ...prev, lastTurnIn: turnUsage.inputTokens, lastTurnOut: turnUsage.outputTokens }));
75
68
  } catch (e) {
76
- if (signal?.aborted) {
77
- tui.addMessage("system", "turn interrupted (esc).");
69
+ if (signal.aborted) {
70
+ setRows((prev) => [...prev, { role: "system", text: "turn interrupted." }]);
78
71
  } else {
79
72
  const raw = e instanceof Error ? e.message : String(e);
80
- const clean = cleanError(raw);
81
- tui.addMessage("error", clean);
73
+ setRows((prev) => [...prev, { role: "error", text: cleanError(raw) }]);
82
74
  }
83
75
  }
84
- agent.getBalance().then((bal) => tui.setInfo({ balance: (Number(bal) / 1e9).toFixed(4) })).catch(() => {});
76
+ agent.getBalance().then((bal) => setInfo((prev) => ({ ...prev, balance: (Number(bal) / 1e9).toFixed(4) }))).catch(() => {});
85
77
  if (sp) saveSession(sp, agent.getHistory());
86
- tui.render();
87
78
  });
88
79
  }
80
+
81
+ function cleanError(raw: string): string {
82
+ try {
83
+ const obj = JSON.parse(raw);
84
+ if (obj?.error?.type === "overloaded_error") return "Claude is overloaded — try again in a moment.";
85
+ if (obj?.error?.message) return obj.error.message;
86
+ } catch { /* not JSON */ }
87
+ return raw;
88
+ }