oharness 0.1.0
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/bin/sync.d.ts +3 -0
- package/dist/bin/sync.js +4 -0
- package/dist/bin/sync.js.map +1 -0
- package/dist/bin/web.d.ts +10 -0
- package/dist/bin/web.js +11 -0
- package/dist/bin/web.js.map +1 -0
- package/dist/headless/main.d.ts +2 -0
- package/dist/headless/main.js +133 -0
- package/dist/headless/main.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/providers.d.ts +2 -0
- package/dist/providers.js +3 -0
- package/dist/providers.js.map +1 -0
- package/dist/tools.d.ts +2 -0
- package/dist/tools.js +3 -0
- package/dist/tools.js.map +1 -0
- package/dist/ui/artifact.d.ts +32 -0
- package/dist/ui/artifact.js +49 -0
- package/dist/ui/artifact.js.map +1 -0
- package/dist/ui/auth.d.ts +14 -0
- package/dist/ui/auth.js +177 -0
- package/dist/ui/auth.js.map +1 -0
- package/dist/ui/colors.d.ts +21 -0
- package/dist/ui/colors.js +28 -0
- package/dist/ui/colors.js.map +1 -0
- package/dist/ui/ink/app.d.ts +13 -0
- package/dist/ui/ink/app.js +418 -0
- package/dist/ui/ink/app.js.map +1 -0
- package/dist/ui/ink/logo.d.ts +6 -0
- package/dist/ui/ink/logo.js +20 -0
- package/dist/ui/ink/logo.js.map +1 -0
- package/dist/ui/ink/main.d.ts +2 -0
- package/dist/ui/ink/main.js +55 -0
- package/dist/ui/ink/main.js.map +1 -0
- package/dist/ui/ink/screen.d.ts +15 -0
- package/dist/ui/ink/screen.js +76 -0
- package/dist/ui/ink/screen.js.map +1 -0
- package/dist/ui/ink/select.d.ts +24 -0
- package/dist/ui/ink/select.js +74 -0
- package/dist/ui/ink/select.js.map +1 -0
- package/dist/ui/main.d.ts +2 -0
- package/dist/ui/main.js +1062 -0
- package/dist/ui/main.js.map +1 -0
- package/dist/ui/render.d.ts +15 -0
- package/dist/ui/render.js +130 -0
- package/dist/ui/render.js.map +1 -0
- package/dist/ui/select.d.ts +26 -0
- package/dist/ui/select.js +107 -0
- package/dist/ui/select.js.map +1 -0
- package/dist/ui/tui/app.d.ts +96 -0
- package/dist/ui/tui/app.js +476 -0
- package/dist/ui/tui/app.js.map +1 -0
- package/dist/ui/tui/editor.d.ts +40 -0
- package/dist/ui/tui/editor.js +124 -0
- package/dist/ui/tui/editor.js.map +1 -0
- package/dist/ui/tui/keys.d.ts +25 -0
- package/dist/ui/tui/keys.js +133 -0
- package/dist/ui/tui/keys.js.map +1 -0
- package/dist/ui/tui/layout.d.ts +63 -0
- package/dist/ui/tui/layout.js +202 -0
- package/dist/ui/tui/layout.js.map +1 -0
- package/dist/ui/tui/logo.d.ts +18 -0
- package/dist/ui/tui/logo.js +33 -0
- package/dist/ui/tui/logo.js.map +1 -0
- package/dist/ui/tui/screen.d.ts +48 -0
- package/dist/ui/tui/screen.js +150 -0
- package/dist/ui/tui/screen.js.map +1 -0
- package/dist/ui/tui/width.d.ts +30 -0
- package/dist/ui/tui/width.js +197 -0
- package/dist/ui/tui/width.js.map +1 -0
- package/dist/ui/wordmark.d.ts +30 -0
- package/dist/ui/wordmark.js +63 -0
- package/dist/ui/wordmark.js.map +1 -0
- package/package.json +49 -0
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Box, Text, useApp, useInput, useStdout } from "ink";
|
|
3
|
+
import { MODE_DESCRIPTIONS, MODE_LABELS, PERMISSION_MODES, } from "@oharness/engine/agent/permissions.ts";
|
|
4
|
+
import { errorMessage } from "@oharness/engine/core/errors.ts";
|
|
5
|
+
import { previewJson } from "@oharness/engine/util/json.ts";
|
|
6
|
+
import { Select } from "./select.js";
|
|
7
|
+
import { useTerminalSize } from "./screen.js";
|
|
8
|
+
import { Logo } from "./logo.js";
|
|
9
|
+
/**
|
|
10
|
+
* The terminal interface, rendered with Ink.
|
|
11
|
+
*
|
|
12
|
+
* Written with `React.createElement` rather than JSX. Node's native TypeScript
|
|
13
|
+
* support strips types but does not transform JSX, and every command in this
|
|
14
|
+
* repo runs the source directly — `node src/ui/ink/main.ts`, `node --test`.
|
|
15
|
+
* JSX would mean adding a bundler to development and giving that up. `h` is
|
|
16
|
+
* verbose; a build step is worse.
|
|
17
|
+
*
|
|
18
|
+
* The dialog structure follows opencode: one filterable select behind every
|
|
19
|
+
* picker, and a command palette as the way to find them. Slash commands still
|
|
20
|
+
* work, but nothing depends on remembering them.
|
|
21
|
+
*/
|
|
22
|
+
const h = React.createElement;
|
|
23
|
+
/** Entries kept in memory. Ink re-renders the tree, so this bounds the work. */
|
|
24
|
+
const WINDOW = 300;
|
|
25
|
+
export function App({ harness, session, agent, bindPrompt }) {
|
|
26
|
+
const { exit } = useApp();
|
|
27
|
+
const { rows, columns } = useTerminalSize();
|
|
28
|
+
const [entries, setEntries] = React.useState([]);
|
|
29
|
+
const [input, setInput] = React.useState("");
|
|
30
|
+
const [busy, setBusy] = React.useState(false);
|
|
31
|
+
const [label, setLabel] = React.useState("Thinking");
|
|
32
|
+
const [elapsed, setElapsed] = React.useState(0);
|
|
33
|
+
const [dialog, setDialog] = React.useState();
|
|
34
|
+
const [model, setModel] = React.useState(session.model.id);
|
|
35
|
+
const [mode, setMode] = React.useState(session.permissions.getMode());
|
|
36
|
+
const [sessions, setSessions] = React.useState([]);
|
|
37
|
+
const abort = React.useRef(undefined);
|
|
38
|
+
const history = React.useRef([]);
|
|
39
|
+
const historyAt = React.useRef(0);
|
|
40
|
+
const push = React.useCallback((entry) => {
|
|
41
|
+
setEntries((current) => [...current, entry].slice(-WINDOW));
|
|
42
|
+
}, []);
|
|
43
|
+
// Approval arrives from the engine on a different stack, so it is handed in
|
|
44
|
+
// as a promise the dialog resolves.
|
|
45
|
+
React.useEffect(() => {
|
|
46
|
+
bindPrompt((request) => new Promise((resolve) => {
|
|
47
|
+
setDialog({ kind: "permission", request, resolve });
|
|
48
|
+
}));
|
|
49
|
+
}, [bindPrompt]);
|
|
50
|
+
// Elapsed seconds answer "is it stuck?", which is the only question a user
|
|
51
|
+
// has while nothing is streaming.
|
|
52
|
+
React.useEffect(() => {
|
|
53
|
+
if (!busy)
|
|
54
|
+
return setElapsed(0);
|
|
55
|
+
const started = Date.now();
|
|
56
|
+
const timer = setInterval(() => setElapsed(Math.round((Date.now() - started) / 1000)), 1000);
|
|
57
|
+
return () => clearInterval(timer);
|
|
58
|
+
}, [busy]);
|
|
59
|
+
const run = React.useCallback(async (prompt) => {
|
|
60
|
+
setBusy(true);
|
|
61
|
+
setLabel("Thinking");
|
|
62
|
+
abort.current = new AbortController();
|
|
63
|
+
let streaming = false;
|
|
64
|
+
try {
|
|
65
|
+
for await (const event of agent.run(prompt, { signal: abort.current.signal })) {
|
|
66
|
+
switch (event.type) {
|
|
67
|
+
case "text_delta":
|
|
68
|
+
setLabel("Thinking");
|
|
69
|
+
// Appended to the open assistant entry: one row per token would
|
|
70
|
+
// make the transcript unreadable and the diff expensive.
|
|
71
|
+
setEntries((current) => {
|
|
72
|
+
const last = current.at(-1);
|
|
73
|
+
if (streaming && last && last.kind === "assistant") {
|
|
74
|
+
return [...current.slice(0, -1), { ...last, text: last.text + event.text }];
|
|
75
|
+
}
|
|
76
|
+
streaming = true;
|
|
77
|
+
const next = { kind: "assistant", text: event.text };
|
|
78
|
+
return [...current, next].slice(-WINDOW);
|
|
79
|
+
});
|
|
80
|
+
break;
|
|
81
|
+
case "thinking_delta":
|
|
82
|
+
setEntries((current) => {
|
|
83
|
+
const last = current.at(-1);
|
|
84
|
+
if (last && last.kind === "thinking") {
|
|
85
|
+
return [...current.slice(0, -1), { ...last, text: last.text + event.text }];
|
|
86
|
+
}
|
|
87
|
+
const next = { kind: "thinking", text: event.text };
|
|
88
|
+
return [...current, next].slice(-WINDOW);
|
|
89
|
+
});
|
|
90
|
+
break;
|
|
91
|
+
case "assistant_message":
|
|
92
|
+
streaming = false;
|
|
93
|
+
break;
|
|
94
|
+
case "tool_start":
|
|
95
|
+
streaming = false;
|
|
96
|
+
setLabel(event.toolName);
|
|
97
|
+
push({ kind: "tool", title: event.title, done: false });
|
|
98
|
+
break;
|
|
99
|
+
case "tool_end":
|
|
100
|
+
setLabel("Thinking");
|
|
101
|
+
setEntries((current) => {
|
|
102
|
+
const at = current.findLastIndex((entry) => entry.kind === "tool" && !entry.done);
|
|
103
|
+
if (at === -1)
|
|
104
|
+
return current;
|
|
105
|
+
const updated = [...current];
|
|
106
|
+
updated[at] = {
|
|
107
|
+
...updated[at],
|
|
108
|
+
done: true,
|
|
109
|
+
ms: event.durationMs,
|
|
110
|
+
failed: Boolean(event.result.isError),
|
|
111
|
+
};
|
|
112
|
+
return updated;
|
|
113
|
+
});
|
|
114
|
+
break;
|
|
115
|
+
case "permission_result":
|
|
116
|
+
if (!event.allowed)
|
|
117
|
+
push({ kind: "error", text: event.reason ?? "denied" });
|
|
118
|
+
break;
|
|
119
|
+
case "compacted":
|
|
120
|
+
push({
|
|
121
|
+
kind: "notice",
|
|
122
|
+
text: `compacted ${event.droppedMessages} messages (${event.tokensBefore} → ${event.tokensAfter} tokens)`,
|
|
123
|
+
});
|
|
124
|
+
break;
|
|
125
|
+
case "model_changed":
|
|
126
|
+
setModel(event.to);
|
|
127
|
+
push({ kind: "notice", text: `${event.from} → ${event.to}` });
|
|
128
|
+
break;
|
|
129
|
+
case "notice":
|
|
130
|
+
push({ kind: "notice", text: event.message });
|
|
131
|
+
break;
|
|
132
|
+
case "error":
|
|
133
|
+
streaming = false;
|
|
134
|
+
push({ kind: "error", text: event.error });
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
push({ kind: "error", text: errorMessage(err) });
|
|
141
|
+
}
|
|
142
|
+
finally {
|
|
143
|
+
setBusy(false);
|
|
144
|
+
abort.current = undefined;
|
|
145
|
+
}
|
|
146
|
+
}, [agent, push]);
|
|
147
|
+
const submit = React.useCallback((text) => {
|
|
148
|
+
history.current = [...history.current.filter((entry) => entry !== text), text];
|
|
149
|
+
historyAt.current = history.current.length;
|
|
150
|
+
if (text.startsWith("/")) {
|
|
151
|
+
const command = text.slice(1).trim();
|
|
152
|
+
if (command === "exit" || command === "quit")
|
|
153
|
+
return exit();
|
|
154
|
+
if (command === "model")
|
|
155
|
+
return setDialog({ kind: "model" });
|
|
156
|
+
if (command === "mode")
|
|
157
|
+
return setDialog({ kind: "mode" });
|
|
158
|
+
if (command === "sessions")
|
|
159
|
+
return void openSessions();
|
|
160
|
+
if (command === "clear")
|
|
161
|
+
return setEntries([]);
|
|
162
|
+
push({ kind: "error", text: `unknown command: /${command}` });
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
push({ kind: "user", text });
|
|
166
|
+
void run(text);
|
|
167
|
+
}, [exit, push, run]);
|
|
168
|
+
const openSessions = React.useCallback(async () => {
|
|
169
|
+
const list = await harness.listSessions(30);
|
|
170
|
+
setSessions(list.map((meta) => ({ id: meta.id, ...(meta.title ? { title: meta.title } : {}) })));
|
|
171
|
+
setDialog({ kind: "session" });
|
|
172
|
+
}, [harness]);
|
|
173
|
+
useInput((char, key) => {
|
|
174
|
+
if (key.ctrl && char === "c") {
|
|
175
|
+
// Interrupt while working; quit when idle — what a shell does.
|
|
176
|
+
if (busy) {
|
|
177
|
+
abort.current?.abort();
|
|
178
|
+
push({ kind: "notice", text: "(interrupted)" });
|
|
179
|
+
}
|
|
180
|
+
else
|
|
181
|
+
exit();
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (key.ctrl && char === "d" && !input)
|
|
185
|
+
return exit();
|
|
186
|
+
// The palette is how everything is reached, so it works while busy.
|
|
187
|
+
if (key.ctrl && char === "k")
|
|
188
|
+
return setDialog({ kind: "palette" });
|
|
189
|
+
if (busy)
|
|
190
|
+
return;
|
|
191
|
+
if (key.return) {
|
|
192
|
+
const text = input.trim();
|
|
193
|
+
if (!text)
|
|
194
|
+
return;
|
|
195
|
+
setInput("");
|
|
196
|
+
submit(text);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (key.upArrow) {
|
|
200
|
+
if (historyAt.current === 0)
|
|
201
|
+
return;
|
|
202
|
+
historyAt.current -= 1;
|
|
203
|
+
return setInput(history.current[historyAt.current] ?? "");
|
|
204
|
+
}
|
|
205
|
+
if (key.downArrow) {
|
|
206
|
+
if (historyAt.current >= history.current.length)
|
|
207
|
+
return;
|
|
208
|
+
historyAt.current += 1;
|
|
209
|
+
return setInput(history.current[historyAt.current] ?? "");
|
|
210
|
+
}
|
|
211
|
+
if (key.backspace || key.delete) {
|
|
212
|
+
return setInput((value) => [...value].slice(0, -1).join(""));
|
|
213
|
+
}
|
|
214
|
+
if (key.escape || key.leftArrow || key.rightArrow || key.tab)
|
|
215
|
+
return;
|
|
216
|
+
if (char && !key.ctrl && !key.meta)
|
|
217
|
+
setInput((value) => value + char);
|
|
218
|
+
},
|
|
219
|
+
// Ink delivers input to every hook; the dialog owns the keyboard while open.
|
|
220
|
+
{ isActive: !dialog });
|
|
221
|
+
const width = columns;
|
|
222
|
+
const close = () => setDialog(undefined);
|
|
223
|
+
const empty = entries.length === 0;
|
|
224
|
+
/*
|
|
225
|
+
* One root box the height of the terminal, so flexbox distributes the space
|
|
226
|
+
* instead of the app growing down the scrollback. The transcript takes what
|
|
227
|
+
* is left; the composer and the status bar keep their own rows.
|
|
228
|
+
*/
|
|
229
|
+
return h(Box, { flexDirection: "column", width, height: rows }, dialog
|
|
230
|
+
? h(Box, { flexDirection: "column", flexGrow: 1, justifyContent: "center", paddingX: 2 }, h(DialogView, {
|
|
231
|
+
dialog,
|
|
232
|
+
harness,
|
|
233
|
+
session,
|
|
234
|
+
model,
|
|
235
|
+
mode,
|
|
236
|
+
sessions,
|
|
237
|
+
close,
|
|
238
|
+
setDialog,
|
|
239
|
+
setModel,
|
|
240
|
+
setMode,
|
|
241
|
+
push,
|
|
242
|
+
exit,
|
|
243
|
+
}))
|
|
244
|
+
: empty
|
|
245
|
+
? h(Home, { columns: width, cwd: session.cwd })
|
|
246
|
+
: h(Box, { flexDirection: "column", flexGrow: 1, overflow: "hidden", paddingX: 2 }, h(Transcript, { entries: entries.slice(-Math.max(1, rows - 8)) })), h(Box, { flexDirection: "column", paddingX: 2 }, h(Box, { borderStyle: "round", borderDimColor: true, paddingX: 1, flexDirection: "column" }, h(Box, null, h(Text, { color: "cyan" }, "› "), input
|
|
247
|
+
? h(Text, null, input)
|
|
248
|
+
: h(Text, { dimColor: true }, "Ask anything… \"Where is the build entry?\"")), h(Box, { height: 1 }),
|
|
249
|
+
// One line, never wrapped. A discovered id like
|
|
250
|
+
// openrouter/inclusionai/ling-3.0-tiny:free is longer than the box, and
|
|
251
|
+
// letting it wrap broke the row apart — splitting even the mode label
|
|
252
|
+
// across two lines.
|
|
253
|
+
h(Box, { flexWrap: "nowrap" }, busy
|
|
254
|
+
? h(Text, { color: "yellow", wrap: "truncate-end" }, `${label}…${elapsed > 1 ? ` ${elapsed}s` : ""}`)
|
|
255
|
+
: h(React.Fragment, null,
|
|
256
|
+
// The short labels never shrink. Letting flex compress them
|
|
257
|
+
// alongside the model id turned "Manual" into "Manua" — losing
|
|
258
|
+
// a character from a word that has no room to lose one.
|
|
259
|
+
h(Box, { flexShrink: 0 }, h(Text, { color: "cyan" }, MODE_LABELS[mode]), h(Text, { dimColor: true }, " · ")),
|
|
260
|
+
// Only the model id gives way, and from the front: the tail is
|
|
261
|
+
// what identifies it, the namespace is what can go.
|
|
262
|
+
h(Box, { flexShrink: 1, minWidth: 0 }, h(Text, { wrap: "truncate-start" }, model)), h(Box, { flexShrink: 0 }, h(Text, { dimColor: true }, ` ${session.model.provider}`))))), h(Box, { paddingX: 1 }, h(Text, null, "^K"), h(Text, { dimColor: true }, " commands "), h(Text, null, "^C"), h(Text, { dimColor: true }, busy ? " interrupt " : " quit "), h(Text, null, "↑"), h(Text, { dimColor: true }, " history"))),
|
|
263
|
+
// Pinned to the last row: the working directory is the one piece of
|
|
264
|
+
// context that stays true no matter what is on screen above it.
|
|
265
|
+
h(Box, { paddingX: 2, justifyContent: "space-between" }, h(Text, { dimColor: true, wrap: "truncate-start" }, session.cwd.replace(process.env["HOME"] ?? "", "~")), h(Text, { dimColor: true }, busy ? "working" : "ready")));
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* The home screen.
|
|
269
|
+
*
|
|
270
|
+
* A wordmark, one line saying what this is, and nothing else. The screen a
|
|
271
|
+
* user meets before they have asked anything should not be a control panel:
|
|
272
|
+
* everything reachable is one keystroke away and listed under the input.
|
|
273
|
+
*/
|
|
274
|
+
function Home({ columns, cwd }) {
|
|
275
|
+
return h(Box, { flexDirection: "column", flexGrow: 1, justifyContent: "center", alignItems: "center" }, h(Logo, { columns }), h(Box, { height: 1 }), h(Text, { dimColor: true }, `a model-agnostic agent harness · ${short(cwd)}`));
|
|
276
|
+
}
|
|
277
|
+
// --- transcript ------------------------------------------------------------
|
|
278
|
+
function Transcript({ entries }) {
|
|
279
|
+
return h(Box, { flexDirection: "column", flexGrow: 1 }, ...entries.map((entry, i) => h(Row, { key: i, entry })));
|
|
280
|
+
}
|
|
281
|
+
function Row({ entry }) {
|
|
282
|
+
switch (entry.kind) {
|
|
283
|
+
case "user":
|
|
284
|
+
return h(Text, { bold: true }, `› ${entry.text}`);
|
|
285
|
+
case "assistant":
|
|
286
|
+
return h(Text, null, entry.text);
|
|
287
|
+
case "thinking":
|
|
288
|
+
return h(Text, { dimColor: true, italic: true }, entry.text);
|
|
289
|
+
case "tool":
|
|
290
|
+
return h(Text, { dimColor: true }, `${entry.done ? (entry.failed ? "✗" : "●") : "◐"} ${entry.title}` +
|
|
291
|
+
(entry.ms !== undefined ? ` ${entry.ms}ms` : ""));
|
|
292
|
+
case "notice":
|
|
293
|
+
return h(Text, { dimColor: true }, entry.text);
|
|
294
|
+
case "error":
|
|
295
|
+
return h(Text, { color: "red" }, `✗ ${entry.text}`);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function DialogView(props) {
|
|
299
|
+
const { dialog, harness, session, model, mode, sessions, close, setDialog } = props;
|
|
300
|
+
if (dialog.kind === "palette") {
|
|
301
|
+
const commands = [
|
|
302
|
+
{ value: "model", label: "Switch model", hint: model },
|
|
303
|
+
{ value: "mode", label: "Permission mode", hint: MODE_LABELS[mode] },
|
|
304
|
+
{ value: "sessions", label: "Open a session" },
|
|
305
|
+
{ value: "clear", label: "Clear the transcript" },
|
|
306
|
+
{ value: "exit", label: "Quit", hint: "^D" },
|
|
307
|
+
];
|
|
308
|
+
return h((Select), {
|
|
309
|
+
title: "Commands",
|
|
310
|
+
options: commands,
|
|
311
|
+
onCancel: close,
|
|
312
|
+
onPick: (value) => {
|
|
313
|
+
close();
|
|
314
|
+
if (value === "model")
|
|
315
|
+
return setDialog({ kind: "model" });
|
|
316
|
+
if (value === "mode")
|
|
317
|
+
return setDialog({ kind: "mode" });
|
|
318
|
+
if (value === "sessions")
|
|
319
|
+
return void openSessionList(props);
|
|
320
|
+
if (value === "clear")
|
|
321
|
+
return props.push({ kind: "notice", text: "(cleared)" });
|
|
322
|
+
if (value === "exit")
|
|
323
|
+
return props.exit();
|
|
324
|
+
},
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
if (dialog.kind === "model") {
|
|
328
|
+
const options = harness.listModels().map((spec) => ({
|
|
329
|
+
value: spec.id,
|
|
330
|
+
label: spec.id,
|
|
331
|
+
group: spec.provider,
|
|
332
|
+
...(spec.contextWindow ? { hint: `${Math.round(spec.contextWindow / 1000)}k` } : {}),
|
|
333
|
+
current: spec.id === model,
|
|
334
|
+
}));
|
|
335
|
+
return h((Select), {
|
|
336
|
+
title: "Model",
|
|
337
|
+
options,
|
|
338
|
+
onCancel: close,
|
|
339
|
+
onPick: (id) => {
|
|
340
|
+
close();
|
|
341
|
+
try {
|
|
342
|
+
const change = session.setModel(id);
|
|
343
|
+
props.setModel(change.to.id);
|
|
344
|
+
props.push({ kind: "notice", text: `${change.from.id} → ${change.to.id}` });
|
|
345
|
+
}
|
|
346
|
+
catch (err) {
|
|
347
|
+
props.push({ kind: "error", text: errorMessage(err) });
|
|
348
|
+
}
|
|
349
|
+
},
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
if (dialog.kind === "mode") {
|
|
353
|
+
return h((Select), {
|
|
354
|
+
title: "Mode",
|
|
355
|
+
options: PERMISSION_MODES.map((value) => ({
|
|
356
|
+
value,
|
|
357
|
+
label: MODE_LABELS[value],
|
|
358
|
+
hint: MODE_DESCRIPTIONS[value],
|
|
359
|
+
current: value === mode,
|
|
360
|
+
})),
|
|
361
|
+
onCancel: close,
|
|
362
|
+
onPick: (value) => {
|
|
363
|
+
close();
|
|
364
|
+
session.permissions.setMode(value);
|
|
365
|
+
props.setMode(value);
|
|
366
|
+
props.push({ kind: "notice", text: `mode → ${MODE_LABELS[value]}` });
|
|
367
|
+
},
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
if (dialog.kind === "session") {
|
|
371
|
+
return h((Select), {
|
|
372
|
+
title: "Sessions",
|
|
373
|
+
options: sessions.map((entry) => ({
|
|
374
|
+
value: entry.id,
|
|
375
|
+
label: entry.title ?? entry.id,
|
|
376
|
+
hint: entry.id,
|
|
377
|
+
current: entry.id === session.id,
|
|
378
|
+
})),
|
|
379
|
+
onCancel: close,
|
|
380
|
+
onPick: (id) => {
|
|
381
|
+
close();
|
|
382
|
+
// Switching sessions needs a new agent; that belongs in main, so for
|
|
383
|
+
// now this reports rather than pretending to have done it.
|
|
384
|
+
props.push({ kind: "notice", text: `resume ${id} — not wired yet` });
|
|
385
|
+
},
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
const { request, resolve } = dialog;
|
|
389
|
+
return h((Select), {
|
|
390
|
+
title: `? ${request.title}`,
|
|
391
|
+
detail: [request.reason, previewJson(request.input, 160)].filter(Boolean),
|
|
392
|
+
filterFrom: 99,
|
|
393
|
+
options: [
|
|
394
|
+
{ value: true, label: "Yes", hint: "just this once" },
|
|
395
|
+
{ value: false, label: "No", hint: "tell the model what to do instead" },
|
|
396
|
+
],
|
|
397
|
+
onCancel: () => {
|
|
398
|
+
// Cancelling is a refusal. Falling through to the highlighted row would
|
|
399
|
+
// approve something on a stray Escape.
|
|
400
|
+
close();
|
|
401
|
+
resolve(false);
|
|
402
|
+
},
|
|
403
|
+
onPick: (allow) => {
|
|
404
|
+
close();
|
|
405
|
+
resolve(allow);
|
|
406
|
+
},
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
async function openSessionList(props) {
|
|
410
|
+
const list = await props.harness.listSessions(30);
|
|
411
|
+
props.setDialog({ kind: "session" });
|
|
412
|
+
void list;
|
|
413
|
+
}
|
|
414
|
+
function short(dir) {
|
|
415
|
+
const parts = dir.replace(/\/+$/, "").split("/");
|
|
416
|
+
return parts[parts.length - 1] ?? dir;
|
|
417
|
+
}
|
|
418
|
+
//# sourceMappingURL=app.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../../src/ui/ink/app.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
import { MARK, MARK_GAP, NAME, wordmark } from "../wordmark.js";
|
|
4
|
+
/**
|
|
5
|
+
* The mark and the name.
|
|
6
|
+
*
|
|
7
|
+
* Both live in `../wordmark.ts`, shared with the hand-written frontend; this
|
|
8
|
+
* module only decides how Ink paints them.
|
|
9
|
+
*/
|
|
10
|
+
const h = React.createElement;
|
|
11
|
+
export function Logo({ columns }) {
|
|
12
|
+
const { rows, width } = wordmark();
|
|
13
|
+
// A wordmark wider than the terminal wraps into meaningless fragments, so
|
|
14
|
+
// below that it becomes the name in ordinary type.
|
|
15
|
+
if (columns < width + 4) {
|
|
16
|
+
return h(Box, { flexDirection: "column", alignItems: "center" }, h(Text, null, h(Text, { bold: true }, `● ${NAME}`)));
|
|
17
|
+
}
|
|
18
|
+
return h(Box, { flexDirection: "column", alignItems: "center" }, ...[0, 1, 2].map((row) => h(Box, { key: row }, h(Text, { bold: true }, MARK[row]), h(Text, null, " ".repeat(MARK_GAP)), h(Text, { bold: true }, rows[row]))));
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=logo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logo.js","sourceRoot":"","sources":["../../../src/ui/ink/logo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAEhE;;;;;GAKG;AACH,MAAM,CAAC,GAAG,KAAK,CAAC,aAAa,CAAC;AAO9B,MAAM,UAAU,IAAI,CAAC,EAAE,OAAO,EAAa;IACzC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,QAAQ,EAAE,CAAC;IAEnC,0EAA0E;IAC1E,mDAAmD;IACnD,IAAI,OAAO,GAAG,KAAK,GAAG,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,CACN,GAAG,EACH,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,EACjD,CAAC,CACC,IAAI,EACJ,IAAI,EACJ,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,KAAK,IAAI,EAAE,CAAC,CACrC,CACF,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,CACN,GAAG,EACH,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,EACjD,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CACvB,CAAC,CACC,GAAG,EACH,EAAE,GAAG,EAAE,GAAG,EAAE,EACZ,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,GAAG,CAAE,CAAC,EACnC,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,EACnC,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CACnC,CACF,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { render } from "ink";
|
|
4
|
+
import { Harness } from "@oharness/engine/harness.ts";
|
|
5
|
+
import { errorMessage } from "@oharness/engine/core/errors.ts";
|
|
6
|
+
import { App } from "./app.js";
|
|
7
|
+
import { enterFullScreen } from "./screen.js";
|
|
8
|
+
/**
|
|
9
|
+
* The Ink terminal frontend.
|
|
10
|
+
*
|
|
11
|
+
* A second terminal entry point rather than a replacement, so the hand-written
|
|
12
|
+
* one stays runnable while this is judged. Both consume the same AgentEvent
|
|
13
|
+
* stream and neither required an engine change — which is the property that
|
|
14
|
+
* made trying this cheap.
|
|
15
|
+
*/
|
|
16
|
+
async function main() {
|
|
17
|
+
if (!process.stdout.isTTY) {
|
|
18
|
+
console.error("oharness-ink needs a terminal; use --print or the headless runner");
|
|
19
|
+
process.exitCode = 1;
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
// The component registers its dialog here once mounted. Until then there is
|
|
23
|
+
// nobody to ask, and defaulting to allow would make the startup window the
|
|
24
|
+
// weakest point in the whole permission system.
|
|
25
|
+
let ask;
|
|
26
|
+
const harness = await Harness.create({
|
|
27
|
+
permissionPrompt: async (request) => (ask ? ask(request) : false),
|
|
28
|
+
});
|
|
29
|
+
const session = await harness.createSession({});
|
|
30
|
+
const agent = harness.agent(session);
|
|
31
|
+
// Taken before the first frame, so nothing is written into the scrollback.
|
|
32
|
+
const screen = enterFullScreen();
|
|
33
|
+
const app = render(React.createElement(App, {
|
|
34
|
+
harness,
|
|
35
|
+
session,
|
|
36
|
+
agent,
|
|
37
|
+
bindPrompt: (prompt) => {
|
|
38
|
+
ask = prompt;
|
|
39
|
+
},
|
|
40
|
+
}),
|
|
41
|
+
// Ink installs its own exit handling; letting it own Ctrl-C would bypass
|
|
42
|
+
// the interrupt-then-quit behaviour the app implements.
|
|
43
|
+
{ exitOnCtrlC: false });
|
|
44
|
+
await app.waitUntilExit();
|
|
45
|
+
// Restored before anything else prints, or the teardown messages land on a
|
|
46
|
+
// screen the user is about to lose.
|
|
47
|
+
screen.close();
|
|
48
|
+
await agent.end();
|
|
49
|
+
await harness.close();
|
|
50
|
+
}
|
|
51
|
+
main().catch((err) => {
|
|
52
|
+
console.error(`fatal: ${errorMessage(err)}`);
|
|
53
|
+
process.exitCode = 1;
|
|
54
|
+
});
|
|
55
|
+
//# sourceMappingURL=main.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../../src/ui/ink/main.ts"],"names":[],"mappings":";AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAEtD,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAC/D,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C;;;;;;;GAOG;AAEH,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAC1B,OAAO,CAAC,KAAK,CAAC,mEAAmE,CAAC,CAAC;QACnF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,4EAA4E;IAC5E,2EAA2E;IAC3E,gDAAgD;IAChD,IAAI,GAAmE,CAAC;IAExE,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC;QACnC,gBAAgB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;KAClE,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAErC,2EAA2E;IAC3E,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IAEjC,MAAM,GAAG,GAAG,MAAM,CAChB,KAAK,CAAC,aAAa,CAAC,GAAG,EAAE;QACvB,OAAO;QACP,OAAO;QACP,KAAK;QACL,UAAU,EAAE,CAAC,MAAM,EAAE,EAAE;YACrB,GAAG,GAAG,MAAM,CAAC;QACf,CAAC;KACF,CAAC;IACF,yEAAyE;IACzE,wDAAwD;IACxD,EAAE,WAAW,EAAE,KAAK,EAAE,CACvB,CAAC;IAEF,MAAM,GAAG,CAAC,aAAa,EAAE,CAAC;IAC1B,2EAA2E;IAC3E,oCAAoC;IACpC,MAAM,CAAC,KAAK,EAAE,CAAC;IACf,MAAM,KAAK,CAAC,GAAG,EAAE,CAAC;IAClB,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;AACxB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,UAAU,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC7C,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface FullScreen {
|
|
2
|
+
close(): void;
|
|
3
|
+
}
|
|
4
|
+
export declare function enterFullScreen(out?: NodeJS.WriteStream): FullScreen;
|
|
5
|
+
/**
|
|
6
|
+
* The terminal's size, kept current.
|
|
7
|
+
*
|
|
8
|
+
* The root box is sized in rows so flexbox can distribute the space — which
|
|
9
|
+
* means a resize has to re-measure, or the layout keeps the old height and
|
|
10
|
+
* either clips or leaves a band of dead screen.
|
|
11
|
+
*/
|
|
12
|
+
export declare function useTerminalSize(): {
|
|
13
|
+
rows: number;
|
|
14
|
+
columns: number;
|
|
15
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Full-screen mode for an Ink application.
|
|
4
|
+
*
|
|
5
|
+
* Ink writes into the scrollback by default: the app grows downward and the
|
|
6
|
+
* shell's history stays above it. A full-screen interface needs the alternate
|
|
7
|
+
* buffer instead, which Ink does not manage — so it is entered here, and, more
|
|
8
|
+
* importantly, left again on every exit path.
|
|
9
|
+
*
|
|
10
|
+
* Leaving it is the part that matters. A process that dies in the alternate
|
|
11
|
+
* buffer leaves the user staring at a frozen screen with their shell hidden
|
|
12
|
+
* behind it, and the only recovery is to type reset blind.
|
|
13
|
+
*/
|
|
14
|
+
const ESC = "\u001b";
|
|
15
|
+
const ALT_ON = ESC + "[?1049h";
|
|
16
|
+
const ALT_OFF = ESC + "[?1049l";
|
|
17
|
+
const CURSOR_HIDE = ESC + "[?25l";
|
|
18
|
+
const CURSOR_SHOW = ESC + "[?25h";
|
|
19
|
+
const CLEAR = ESC + "[2J" + ESC + "[H";
|
|
20
|
+
export function enterFullScreen(out = process.stdout) {
|
|
21
|
+
let closed = false;
|
|
22
|
+
const close = () => {
|
|
23
|
+
if (closed)
|
|
24
|
+
return;
|
|
25
|
+
closed = true;
|
|
26
|
+
out.write(CURSOR_SHOW + ALT_OFF);
|
|
27
|
+
process.off("exit", close);
|
|
28
|
+
process.off("SIGINT", onSignal);
|
|
29
|
+
process.off("SIGTERM", onSignal);
|
|
30
|
+
process.off("SIGHUP", onSignal);
|
|
31
|
+
};
|
|
32
|
+
const onSignal = () => {
|
|
33
|
+
close();
|
|
34
|
+
// The conventional code for "ended by a signal", so a supervisor reading
|
|
35
|
+
// the status can tell this apart from a clean exit.
|
|
36
|
+
process.exit(130);
|
|
37
|
+
};
|
|
38
|
+
out.write(ALT_ON + CURSOR_HIDE + CLEAR);
|
|
39
|
+
process.on("exit", close);
|
|
40
|
+
process.on("SIGINT", onSignal);
|
|
41
|
+
process.on("SIGTERM", onSignal);
|
|
42
|
+
process.on("SIGHUP", onSignal);
|
|
43
|
+
process.on("uncaughtException", (err) => {
|
|
44
|
+
close();
|
|
45
|
+
console.error(err);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
});
|
|
48
|
+
process.on("unhandledRejection", (err) => {
|
|
49
|
+
close();
|
|
50
|
+
console.error(err);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
});
|
|
53
|
+
return { close };
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The terminal's size, kept current.
|
|
57
|
+
*
|
|
58
|
+
* The root box is sized in rows so flexbox can distribute the space — which
|
|
59
|
+
* means a resize has to re-measure, or the layout keeps the old height and
|
|
60
|
+
* either clips or leaves a band of dead screen.
|
|
61
|
+
*/
|
|
62
|
+
export function useTerminalSize() {
|
|
63
|
+
const [size, setSize] = React.useState(() => ({
|
|
64
|
+
rows: process.stdout.rows || 24,
|
|
65
|
+
columns: process.stdout.columns || 80,
|
|
66
|
+
}));
|
|
67
|
+
React.useEffect(() => {
|
|
68
|
+
const onResize = () => setSize({ rows: process.stdout.rows || 24, columns: process.stdout.columns || 80 });
|
|
69
|
+
process.stdout.on("resize", onResize);
|
|
70
|
+
return () => {
|
|
71
|
+
process.stdout.off("resize", onResize);
|
|
72
|
+
};
|
|
73
|
+
}, []);
|
|
74
|
+
return size;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=screen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screen.js","sourceRoot":"","sources":["../../../src/ui/ink/screen.ts"],"names":[],"mappings":"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"}
|