@loompad/cli 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/ARCHITECTURE.md +211 -0
- package/CHANGELOG.md +470 -0
- package/LICENSE +21 -0
- package/README.md +630 -0
- package/dist/adapters/base.d.ts +71 -0
- package/dist/adapters/base.js +187 -0
- package/dist/adapters/base.js.map +1 -0
- package/dist/adapters/bridges/antigravity.d.ts +53 -0
- package/dist/adapters/bridges/antigravity.js +106 -0
- package/dist/adapters/bridges/antigravity.js.map +1 -0
- package/dist/adapters/bridges/cdp.d.ts +82 -0
- package/dist/adapters/bridges/cdp.js +222 -0
- package/dist/adapters/bridges/cdp.js.map +1 -0
- package/dist/adapters/bridges/gui-chat.d.ts +113 -0
- package/dist/adapters/bridges/gui-chat.js +498 -0
- package/dist/adapters/bridges/gui-chat.js.map +1 -0
- package/dist/adapters/bridges/kiro.d.ts +19 -0
- package/dist/adapters/bridges/kiro.js +22 -0
- package/dist/adapters/bridges/kiro.js.map +1 -0
- package/dist/adapters/bridges/profiles.d.ts +82 -0
- package/dist/adapters/bridges/profiles.js +125 -0
- package/dist/adapters/bridges/profiles.js.map +1 -0
- package/dist/adapters/claude-code.d.ts +26 -0
- package/dist/adapters/claude-code.js +209 -0
- package/dist/adapters/claude-code.js.map +1 -0
- package/dist/adapters/codex.d.ts +51 -0
- package/dist/adapters/codex.js +291 -0
- package/dist/adapters/codex.js.map +1 -0
- package/dist/adapters/echo.d.ts +20 -0
- package/dist/adapters/echo.js +79 -0
- package/dist/adapters/echo.js.map +1 -0
- package/dist/adapters/grok.d.ts +61 -0
- package/dist/adapters/grok.js +217 -0
- package/dist/adapters/grok.js.map +1 -0
- package/dist/adapters/index.d.ts +9 -0
- package/dist/adapters/index.js +33 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/opencode.d.ts +64 -0
- package/dist/adapters/opencode.js +426 -0
- package/dist/adapters/opencode.js.map +1 -0
- package/dist/cli/common.d.ts +11 -0
- package/dist/cli/common.js +40 -0
- package/dist/cli/common.js.map +1 -0
- package/dist/cli/doctor.d.ts +12 -0
- package/dist/cli/doctor.js +181 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.js +641 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/tui-model.d.ts +73 -0
- package/dist/cli/tui-model.js +312 -0
- package/dist/cli/tui-model.js.map +1 -0
- package/dist/cli/tui.d.ts +15 -0
- package/dist/cli/tui.js +451 -0
- package/dist/cli/tui.js.map +1 -0
- package/dist/cli/ui.d.ts +10 -0
- package/dist/cli/ui.js +135 -0
- package/dist/cli/ui.js.map +1 -0
- package/dist/core/ades.d.ts +79 -0
- package/dist/core/ades.js +130 -0
- package/dist/core/ades.js.map +1 -0
- package/dist/core/baton.d.ts +37 -0
- package/dist/core/baton.js +92 -0
- package/dist/core/baton.js.map +1 -0
- package/dist/core/brain-extract.d.ts +111 -0
- package/dist/core/brain-extract.js +248 -0
- package/dist/core/brain-extract.js.map +1 -0
- package/dist/core/brain-index.d.ts +128 -0
- package/dist/core/brain-index.js +338 -0
- package/dist/core/brain-index.js.map +1 -0
- package/dist/core/brain.d.ts +214 -0
- package/dist/core/brain.js +425 -0
- package/dist/core/brain.js.map +1 -0
- package/dist/core/claude-cli.d.ts +12 -0
- package/dist/core/claude-cli.js +47 -0
- package/dist/core/claude-cli.js.map +1 -0
- package/dist/core/distill.d.ts +19 -0
- package/dist/core/distill.js +88 -0
- package/dist/core/distill.js.map +1 -0
- package/dist/core/eventlog.d.ts +43 -0
- package/dist/core/eventlog.js +211 -0
- package/dist/core/eventlog.js.map +1 -0
- package/dist/core/git.d.ts +203 -0
- package/dist/core/git.js +460 -0
- package/dist/core/git.js.map +1 -0
- package/dist/core/logbook.d.ts +59 -0
- package/dist/core/logbook.js +118 -0
- package/dist/core/logbook.js.map +1 -0
- package/dist/core/memory.d.ts +34 -0
- package/dist/core/memory.js +124 -0
- package/dist/core/memory.js.map +1 -0
- package/dist/core/notify.d.ts +11 -0
- package/dist/core/notify.js +30 -0
- package/dist/core/notify.js.map +1 -0
- package/dist/core/projection.d.ts +20 -0
- package/dist/core/projection.js +96 -0
- package/dist/core/projection.js.map +1 -0
- package/dist/core/registry.d.ts +76 -0
- package/dist/core/registry.js +147 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/router.d.ts +42 -0
- package/dist/core/router.js +99 -0
- package/dist/core/router.js.map +1 -0
- package/dist/core/routes.d.ts +93 -0
- package/dist/core/routes.js +399 -0
- package/dist/core/routes.js.map +1 -0
- package/dist/core/search.d.ts +63 -0
- package/dist/core/search.js +0 -0
- package/dist/core/search.js.map +1 -0
- package/dist/core/setup.d.ts +70 -0
- package/dist/core/setup.js +250 -0
- package/dist/core/setup.js.map +1 -0
- package/dist/core/suggestions.d.ts +15 -0
- package/dist/core/suggestions.js +38 -0
- package/dist/core/suggestions.js.map +1 -0
- package/dist/core/worktree.d.ts +32 -0
- package/dist/core/worktree.js +83 -0
- package/dist/core/worktree.js.map +1 -0
- package/dist/daemon/app-page.d.ts +32 -0
- package/dist/daemon/app-page.js +6363 -0
- package/dist/daemon/app-page.js.map +1 -0
- package/dist/daemon/auth.d.ts +51 -0
- package/dist/daemon/auth.js +135 -0
- package/dist/daemon/auth.js.map +1 -0
- package/dist/daemon/board.d.ts +117 -0
- package/dist/daemon/board.js +202 -0
- package/dist/daemon/board.js.map +1 -0
- package/dist/daemon/brand-icons.d.ts +29 -0
- package/dist/daemon/brand-icons.js +44 -0
- package/dist/daemon/brand-icons.js.map +1 -0
- package/dist/daemon/client.d.ts +127 -0
- package/dist/daemon/client.js +237 -0
- package/dist/daemon/client.js.map +1 -0
- package/dist/daemon/geist-font.d.ts +10 -0
- package/dist/daemon/geist-font.js +783 -0
- package/dist/daemon/geist-font.js.map +1 -0
- package/dist/daemon/guards.d.ts +18 -0
- package/dist/daemon/guards.js +40 -0
- package/dist/daemon/guards.js.map +1 -0
- package/dist/daemon/linear.d.ts +59 -0
- package/dist/daemon/linear.js +117 -0
- package/dist/daemon/linear.js.map +1 -0
- package/dist/daemon/push.d.ts +22 -0
- package/dist/daemon/push.js +58 -0
- package/dist/daemon/push.js.map +1 -0
- package/dist/daemon/runtime.d.ts +299 -0
- package/dist/daemon/runtime.js +1016 -0
- package/dist/daemon/runtime.js.map +1 -0
- package/dist/daemon/server.d.ts +125 -0
- package/dist/daemon/server.js +1728 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/daemon/tasks.d.ts +153 -0
- package/dist/daemon/tasks.js +264 -0
- package/dist/daemon/tasks.js.map +1 -0
- package/dist/daemon/terminals.d.ts +82 -0
- package/dist/daemon/terminals.js +372 -0
- package/dist/daemon/terminals.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/sdk.d.ts +17 -0
- package/dist/sdk.js +17 -0
- package/dist/sdk.js.map +1 -0
- package/dist/types.d.ts +236 -0
- package/dist/types.js +18 -0
- package/dist/types.js.map +1 -0
- package/docs/SETUP.md +265 -0
- package/docs/adapters.md +132 -0
- package/docs/design-system.md +245 -0
- package/docs/img/board-linear.png +0 -0
- package/docs/img/board-projects.png +0 -0
- package/docs/img/brain.png +0 -0
- package/docs/img/settings.png +0 -0
- package/docs/img/workspace.png +0 -0
- package/docs/integration-notes.md +76 -0
- package/docs/proposals/brain.md +262 -0
- package/package.json +84 -0
package/dist/cli/tui.js
ADDED
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* The Loom TUI — the default face of `loom`. A tabbed, full-screen workspace
|
|
4
|
+
* over every agent in the project:
|
|
5
|
+
*
|
|
6
|
+
* Thread — the conversation, streamed; tab shifts the active agent, the
|
|
7
|
+
* handoff happens when you send.
|
|
8
|
+
* Board — agents, your cards, issues and PRs, in four columns.
|
|
9
|
+
* Brain — the memory the project has learned, grouped by kind.
|
|
10
|
+
* Diff — the working tree: changed files and a colourised patch.
|
|
11
|
+
*
|
|
12
|
+
* shift+tab cycles the views; ctrl+p is the command palette; /route runs a
|
|
13
|
+
* pipeline across agents; /pair drops a QR to pair your phone — all without
|
|
14
|
+
* leaving the screen.
|
|
15
|
+
*/
|
|
16
|
+
import { useApp, useInput, useStdout, render, Box, Text } from "ink";
|
|
17
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
18
|
+
import pc from "picocolors";
|
|
19
|
+
import qrcode from "qrcode-terminal";
|
|
20
|
+
import { readProjectConfig } from "../core/registry.js";
|
|
21
|
+
import { DaemonError, ensureDaemon } from "../daemon/client.js";
|
|
22
|
+
import { resolveCurrentProject, NoProjectError, currentProjectDir } from "./common.js";
|
|
23
|
+
import { HELP_LINES, SPINNER_FRAMES, cycleAgent, cycleView, filterPalette, formatBoard, formatBrain, formatDiff, logoLines, paletteItems, parseSlash, renderInput, renderTabs, switchableAgents, VIEWS, } from "./tui-model.js";
|
|
24
|
+
import { formatAgentRow, formatEvent } from "./ui.js";
|
|
25
|
+
const PLACEHOLDER = 'Ask anything… "/route ship: add dark mode"';
|
|
26
|
+
function App({ client, initial }) {
|
|
27
|
+
const { exit } = useApp();
|
|
28
|
+
const { stdout } = useStdout();
|
|
29
|
+
// Terminal size, kept live so the viewport tracks a resize.
|
|
30
|
+
const [dims, setDims] = useState({ cols: stdout?.columns ?? 80, rows: stdout?.rows ?? 24 });
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (!stdout)
|
|
33
|
+
return;
|
|
34
|
+
const onResize = () => setDims({ cols: stdout.columns ?? 80, rows: stdout.rows ?? 24 });
|
|
35
|
+
stdout.on("resize", onResize);
|
|
36
|
+
return () => void stdout.off("resize", onResize);
|
|
37
|
+
}, [stdout]);
|
|
38
|
+
const { cols, rows } = dims;
|
|
39
|
+
const [view, setView] = useState("thread");
|
|
40
|
+
const [thread, setThread] = useState(() => [...logoLines(cols), ""]);
|
|
41
|
+
const [board, setBoard] = useState(null);
|
|
42
|
+
const [brain, setBrain] = useState(null);
|
|
43
|
+
const [diff, setDiff] = useState(null);
|
|
44
|
+
const [viewErr, setViewErr] = useState(null);
|
|
45
|
+
const [scroll, setScroll] = useState(0);
|
|
46
|
+
const [project, setProject] = useState(initial);
|
|
47
|
+
const [selected, setSelected] = useState(initial.holder ?? switchableAgents(initial.agents)[0]?.id ?? null);
|
|
48
|
+
const [value, setValue] = useState("");
|
|
49
|
+
const [cursor, setCursor] = useState(0);
|
|
50
|
+
const [notice, setNotice] = useState(null);
|
|
51
|
+
const [frame, setFrame] = useState(0);
|
|
52
|
+
const [palette, setPalette] = useState({
|
|
53
|
+
open: false,
|
|
54
|
+
query: "",
|
|
55
|
+
index: 0,
|
|
56
|
+
});
|
|
57
|
+
const lastId = useRef(0);
|
|
58
|
+
const history = useRef([]);
|
|
59
|
+
const histIdx = useRef(-1);
|
|
60
|
+
const routeNames = useRef([]);
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
const dir = currentProjectDir();
|
|
63
|
+
routeNames.current = Object.keys((dir && readProjectConfig(dir)?.routes) || {});
|
|
64
|
+
}, []);
|
|
65
|
+
const push = useCallback((...added) => {
|
|
66
|
+
const real = added.filter((l) => l !== null && l !== undefined);
|
|
67
|
+
if (real.length)
|
|
68
|
+
setThread((prev) => [...prev, ...real]);
|
|
69
|
+
}, []);
|
|
70
|
+
// Recent history, then live events over the websocket.
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
let closed = false;
|
|
73
|
+
void client
|
|
74
|
+
.events(project.id, undefined, 30)
|
|
75
|
+
.then(({ events }) => {
|
|
76
|
+
if (closed)
|
|
77
|
+
return;
|
|
78
|
+
lastId.current = events[events.length - 1]?.id ?? 0;
|
|
79
|
+
push(...events.map(formatEvent));
|
|
80
|
+
})
|
|
81
|
+
.catch(() => { });
|
|
82
|
+
const unsubscribe = client.subscribe((pid, e) => {
|
|
83
|
+
if (pid !== project.id || e.id <= lastId.current)
|
|
84
|
+
return;
|
|
85
|
+
lastId.current = e.id;
|
|
86
|
+
push(formatEvent(e));
|
|
87
|
+
}, project.id);
|
|
88
|
+
return () => {
|
|
89
|
+
closed = true;
|
|
90
|
+
unsubscribe();
|
|
91
|
+
};
|
|
92
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
93
|
+
}, []);
|
|
94
|
+
// Light status poll: holder, busy flags, route progress.
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
const timer = setInterval(() => {
|
|
97
|
+
void client
|
|
98
|
+
.project(project.id)
|
|
99
|
+
.then(({ project: fresh }) => setProject(fresh))
|
|
100
|
+
.catch(() => { });
|
|
101
|
+
}, 1500);
|
|
102
|
+
return () => clearInterval(timer);
|
|
103
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
104
|
+
}, []);
|
|
105
|
+
// Load the active view's data (and keep it fresh) — the thread streams itself.
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
if (view === "thread")
|
|
108
|
+
return;
|
|
109
|
+
let alive = true;
|
|
110
|
+
const load = () => {
|
|
111
|
+
const done = () => alive && setViewErr(null);
|
|
112
|
+
const fail = (e) => alive && setViewErr(e instanceof Error ? e.message : String(e));
|
|
113
|
+
if (view === "board")
|
|
114
|
+
client.board(project.id).then((b) => { if (alive) {
|
|
115
|
+
setBoard(b);
|
|
116
|
+
done();
|
|
117
|
+
} }).catch(fail);
|
|
118
|
+
else if (view === "brain")
|
|
119
|
+
client.brain(project.id, { limit: 200 }).then((r) => { if (alive) {
|
|
120
|
+
setBrain(r);
|
|
121
|
+
done();
|
|
122
|
+
} }).catch(fail);
|
|
123
|
+
else
|
|
124
|
+
client.tree(project.id).then((r) => { if (alive) {
|
|
125
|
+
setDiff(r.tree);
|
|
126
|
+
done();
|
|
127
|
+
} }).catch(fail);
|
|
128
|
+
};
|
|
129
|
+
load();
|
|
130
|
+
const timer = setInterval(load, 2500);
|
|
131
|
+
return () => {
|
|
132
|
+
alive = false;
|
|
133
|
+
clearInterval(timer);
|
|
134
|
+
};
|
|
135
|
+
}, [view, project.id, client]);
|
|
136
|
+
// A fresh view starts at its natural edge (thread at the newest, others at the top).
|
|
137
|
+
useEffect(() => setScroll(0), [view]);
|
|
138
|
+
const busyAgent = project.agents.find((a) => a.busy);
|
|
139
|
+
// Spinner while anyone is working.
|
|
140
|
+
useEffect(() => {
|
|
141
|
+
if (!busyAgent)
|
|
142
|
+
return;
|
|
143
|
+
const timer = setInterval(() => setFrame((f) => f + 1), 120);
|
|
144
|
+
return () => clearInterval(timer);
|
|
145
|
+
}, [Boolean(busyAgent)]);
|
|
146
|
+
// Smoke hook: render one real frame, then leave (used by CI/smoke tests).
|
|
147
|
+
useEffect(() => {
|
|
148
|
+
if (!process.env.LOOM_TUI_SMOKE)
|
|
149
|
+
return;
|
|
150
|
+
const timer = setTimeout(() => exit(), 900);
|
|
151
|
+
return () => clearTimeout(timer);
|
|
152
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
153
|
+
}, []);
|
|
154
|
+
const runCommand = useCallback(async (text) => {
|
|
155
|
+
const slash = parseSlash(text);
|
|
156
|
+
if (!slash)
|
|
157
|
+
return;
|
|
158
|
+
const { cmd, args, rest } = slash;
|
|
159
|
+
// Local view jumps never touch the daemon.
|
|
160
|
+
if (VIEWS.includes(cmd)) {
|
|
161
|
+
setView(cmd);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
// Everything else produces thread output or a thread effect — show it.
|
|
165
|
+
setView("thread");
|
|
166
|
+
try {
|
|
167
|
+
switch (cmd) {
|
|
168
|
+
case "help":
|
|
169
|
+
push("", ...HELP_LINES, "");
|
|
170
|
+
break;
|
|
171
|
+
case "agents": {
|
|
172
|
+
const { project: fresh } = await client.project(project.id);
|
|
173
|
+
push("", ...fresh.agents.map(formatAgentRow), "");
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
case "handoff": {
|
|
177
|
+
if (!args[0])
|
|
178
|
+
return setNotice("usage: /handoff <agent>");
|
|
179
|
+
await client.handoff(project.id, args[0]);
|
|
180
|
+
setSelected(args[0]);
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
case "route": {
|
|
184
|
+
if (args.length < 2)
|
|
185
|
+
return setNotice("usage: /route <name|a,b,c> <task>");
|
|
186
|
+
const [spec, ...taskWords] = args;
|
|
187
|
+
await client.startRoute(project.id, taskWords.join(" "), spec);
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
case "routes": {
|
|
191
|
+
const dir = currentProjectDir();
|
|
192
|
+
const routes = (dir && readProjectConfig(dir)?.routes) || {};
|
|
193
|
+
const entries = Object.entries(routes);
|
|
194
|
+
push("", ...(entries.length
|
|
195
|
+
? entries.map(([name, steps]) => ` ${pc.cyan(pc.bold(name))} ${steps
|
|
196
|
+
.map((s) => (typeof s === "string" ? s : s.step))
|
|
197
|
+
.join(" → ")}`)
|
|
198
|
+
: [pc.dim(" no named routes — add them under \"routes\" in .loom/config.json")]), "");
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
case "abort":
|
|
202
|
+
await client.abortRoute(project.id);
|
|
203
|
+
break;
|
|
204
|
+
case "decision": {
|
|
205
|
+
if (!rest)
|
|
206
|
+
return setNotice("usage: /decision <text>");
|
|
207
|
+
await client.decision(project.id, rest);
|
|
208
|
+
setNotice("pinned to shared memory");
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
case "interrupt": {
|
|
212
|
+
const { interrupted } = await client.interrupt(project.id);
|
|
213
|
+
setNotice(interrupted ? `interrupted ${interrupted}` : "nothing running");
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
case "pair": {
|
|
217
|
+
const { token, url } = await client.newPairingToken();
|
|
218
|
+
const link = `${url}/app#pair=${token}`;
|
|
219
|
+
qrcode.generate(link, { small: true }, (qr) => {
|
|
220
|
+
const warn = /127\.0\.0\.1|localhost/.test(url)
|
|
221
|
+
? [pc.yellow(" ⚠ daemon is on localhost — phones can't reach this QR. Run: loom up --restart --tailnet")]
|
|
222
|
+
: [];
|
|
223
|
+
push("", ...qr.split("\n"), pc.bold(` ${link}`), pc.dim(" scan with your phone camera · single use · 10 min"), ...warn, "");
|
|
224
|
+
});
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
case "quit":
|
|
228
|
+
case "exit":
|
|
229
|
+
exit();
|
|
230
|
+
break;
|
|
231
|
+
default:
|
|
232
|
+
setNotice(`unknown command /${cmd} — try /help`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
catch (err) {
|
|
236
|
+
setNotice(err instanceof Error ? err.message : String(err));
|
|
237
|
+
}
|
|
238
|
+
}, [client, project.id, push, exit]);
|
|
239
|
+
const onSubmit = useCallback(async () => {
|
|
240
|
+
const text = value.trim();
|
|
241
|
+
setValue("");
|
|
242
|
+
setCursor(0);
|
|
243
|
+
setNotice(null);
|
|
244
|
+
if (!text)
|
|
245
|
+
return;
|
|
246
|
+
history.current.push(text);
|
|
247
|
+
histIdx.current = history.current.length;
|
|
248
|
+
if (text.startsWith("/"))
|
|
249
|
+
return runCommand(text);
|
|
250
|
+
setView("thread"); // a reply is coming — watch it land
|
|
251
|
+
try {
|
|
252
|
+
if (selected && selected !== project.holder) {
|
|
253
|
+
push(pc.dim(` ⟶ shifting baton to ${selected}`));
|
|
254
|
+
await client.handoff(project.id, selected);
|
|
255
|
+
}
|
|
256
|
+
await client.send(project.id, text, selected ?? undefined);
|
|
257
|
+
}
|
|
258
|
+
catch (err) {
|
|
259
|
+
if (err instanceof DaemonError && err.status === 409) {
|
|
260
|
+
setNotice(String(err.body?.message ?? err.message));
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
setNotice(err instanceof Error ? err.message : String(err));
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}, [value, selected, project.holder, project.id, client, push, runCommand]);
|
|
267
|
+
const runPaletteItem = useCallback((item) => {
|
|
268
|
+
setPalette({ open: false, query: "", index: 0 });
|
|
269
|
+
if (!item)
|
|
270
|
+
return;
|
|
271
|
+
const action = item.action;
|
|
272
|
+
if (action.type === "shift") {
|
|
273
|
+
setSelected(action.agentId);
|
|
274
|
+
}
|
|
275
|
+
else if (action.type === "insert") {
|
|
276
|
+
setValue(action.text);
|
|
277
|
+
setCursor(action.text.length);
|
|
278
|
+
}
|
|
279
|
+
else if (action.type === "view") {
|
|
280
|
+
setView(action.view);
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
void runCommand(`/${action.cmd}`);
|
|
284
|
+
}
|
|
285
|
+
}, [runCommand]);
|
|
286
|
+
// Viewport geometry: chrome is the tab bar + input box + hints + status.
|
|
287
|
+
const CHROME = 9;
|
|
288
|
+
const vh = Math.max(6, rows - CHROME);
|
|
289
|
+
const viewLines = useMemo(() => {
|
|
290
|
+
if (view === "thread")
|
|
291
|
+
return thread;
|
|
292
|
+
if (viewErr)
|
|
293
|
+
return ["", pc.red(` ${viewErr}`)];
|
|
294
|
+
if (view === "board")
|
|
295
|
+
return board ? formatBoard(board, cols) : [pc.dim(" loading board…")];
|
|
296
|
+
if (view === "brain")
|
|
297
|
+
return brain ? formatBrain(brain.memories, brain.stats, cols) : [pc.dim(" loading brain…")];
|
|
298
|
+
return diff ? formatDiff(diff, cols) : [pc.dim(" loading diff…")];
|
|
299
|
+
}, [view, thread, board, brain, diff, viewErr, cols]);
|
|
300
|
+
const total = viewLines.length;
|
|
301
|
+
const maxScroll = Math.max(0, total - vh);
|
|
302
|
+
const clamped = Math.min(Math.max(0, scroll), maxScroll);
|
|
303
|
+
// Thread hangs off the bottom (newest visible); the others read from the top.
|
|
304
|
+
const visible = view === "thread"
|
|
305
|
+
? viewLines.slice(Math.max(0, total - vh - clamped), total - clamped)
|
|
306
|
+
: viewLines.slice(clamped, clamped + vh);
|
|
307
|
+
const hiddenAbove = view === "thread" ? Math.max(0, total - vh - clamped) : clamped;
|
|
308
|
+
const hiddenBelow = view === "thread" ? clamped : Math.max(0, total - vh - clamped);
|
|
309
|
+
useInput((input, key) => {
|
|
310
|
+
if (key.ctrl && input === "c")
|
|
311
|
+
return exit();
|
|
312
|
+
// ctrl+p — command palette
|
|
313
|
+
if (key.ctrl && input === "p") {
|
|
314
|
+
setPalette((p) => ({ open: !p.open, query: "", index: 0 }));
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
if (palette.open) {
|
|
318
|
+
const matches = filterPalette(paletteItems(project.agents, routeNames.current, selected), palette.query);
|
|
319
|
+
if (key.escape)
|
|
320
|
+
return setPalette({ open: false, query: "", index: 0 });
|
|
321
|
+
if (key.return)
|
|
322
|
+
return runPaletteItem(matches[Math.min(palette.index, matches.length - 1)]);
|
|
323
|
+
if (key.upArrow)
|
|
324
|
+
return setPalette((p) => ({ ...p, index: Math.max(0, p.index - 1) }));
|
|
325
|
+
if (key.downArrow)
|
|
326
|
+
return setPalette((p) => ({ ...p, index: Math.min(Math.max(matches.length - 1, 0), p.index + 1) }));
|
|
327
|
+
if (key.tab)
|
|
328
|
+
return;
|
|
329
|
+
if (key.backspace || key.delete) {
|
|
330
|
+
setPalette((p) => ({ ...p, query: p.query.slice(0, -1), index: 0 }));
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
if (input && !key.ctrl && !key.meta) {
|
|
334
|
+
setPalette((p) => ({ ...p, query: p.query + input, index: 0 }));
|
|
335
|
+
}
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
// shift+tab cycles views; tab cycles the active agent.
|
|
339
|
+
if (key.tab && key.shift)
|
|
340
|
+
return setView((v) => cycleView(v, 1));
|
|
341
|
+
if (key.tab) {
|
|
342
|
+
setSelected((s) => cycleAgent(project.agents, s, 1) ?? s);
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
// Scroll the viewport.
|
|
346
|
+
if (key.pageUp)
|
|
347
|
+
return setScroll((s) => Math.min(maxScroll, s + Math.max(1, vh - 2)));
|
|
348
|
+
if (key.pageDown)
|
|
349
|
+
return setScroll((s) => Math.max(0, s - Math.max(1, vh - 2)));
|
|
350
|
+
// esc — leave a side view first, otherwise interrupt the running turn.
|
|
351
|
+
if (key.escape) {
|
|
352
|
+
if (view !== "thread")
|
|
353
|
+
return setView("thread");
|
|
354
|
+
void client
|
|
355
|
+
.interrupt(project.id)
|
|
356
|
+
.then(({ interrupted }) => setNotice(interrupted ? `interrupted ${interrupted}` : "nothing running"))
|
|
357
|
+
.catch(() => { });
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
if (key.return)
|
|
361
|
+
return void onSubmit();
|
|
362
|
+
if (key.upArrow) {
|
|
363
|
+
if (!history.current.length)
|
|
364
|
+
return;
|
|
365
|
+
histIdx.current = Math.max(0, histIdx.current - 1);
|
|
366
|
+
const recalled = history.current[histIdx.current] ?? "";
|
|
367
|
+
setValue(recalled);
|
|
368
|
+
setCursor(recalled.length);
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
if (key.downArrow) {
|
|
372
|
+
histIdx.current = Math.min(history.current.length, histIdx.current + 1);
|
|
373
|
+
const recalled = history.current[histIdx.current] ?? "";
|
|
374
|
+
setValue(recalled);
|
|
375
|
+
setCursor(recalled.length);
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
if (key.leftArrow)
|
|
379
|
+
return setCursor((c) => Math.max(0, c - 1));
|
|
380
|
+
if (key.rightArrow)
|
|
381
|
+
return setCursor((c) => Math.min(value.length, c + 1));
|
|
382
|
+
if (key.ctrl && input === "a")
|
|
383
|
+
return setCursor(0);
|
|
384
|
+
if (key.ctrl && input === "e")
|
|
385
|
+
return setCursor(value.length);
|
|
386
|
+
if (key.ctrl && input === "u") {
|
|
387
|
+
setValue("");
|
|
388
|
+
setCursor(0);
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
if (key.backspace || key.delete) {
|
|
392
|
+
if (cursor > 0) {
|
|
393
|
+
setValue((v) => v.slice(0, cursor - 1) + v.slice(cursor));
|
|
394
|
+
setCursor((c) => c - 1);
|
|
395
|
+
}
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
if (input && !key.ctrl && !key.meta) {
|
|
399
|
+
setValue((v) => v.slice(0, cursor) + input + v.slice(cursor));
|
|
400
|
+
setCursor((c) => c + input.length);
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
const selectedStatus = project.agents.find((a) => a.id === selected);
|
|
404
|
+
const holdsBaton = selected !== null && project.holder === selected;
|
|
405
|
+
const route = project.route;
|
|
406
|
+
const routeActive = route && (route.status === "running" || route.status === "waiting_human");
|
|
407
|
+
const routeBadge = routeActive
|
|
408
|
+
? ` ${pc.cyan(`➤ ${route.name ?? "route"} ${route.current + 1}/${route.steps.length}${route.status === "waiting_human" ? " ⏸" : ""}`)}`
|
|
409
|
+
: "";
|
|
410
|
+
const spinner = busyAgent
|
|
411
|
+
? `${pc.yellow(SPINNER_FRAMES[frame % SPINNER_FRAMES.length])} ${pc.dim(`${busyAgent.id} working…`)}`
|
|
412
|
+
: "";
|
|
413
|
+
const paletteMatches = palette.open
|
|
414
|
+
? filterPalette(paletteItems(project.agents, routeNames.current, selected), palette.query)
|
|
415
|
+
: [];
|
|
416
|
+
const scrollHint = hiddenAbove > 0 || hiddenBelow > 0
|
|
417
|
+
? pc.dim(`${hiddenAbove > 0 ? `↑${hiddenAbove}` : " "} ${hiddenBelow > 0 ? `↓${hiddenBelow}` : ""} pgup/pgdn`)
|
|
418
|
+
: "";
|
|
419
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsx(Text, { children: renderTabs(view) }), _jsx(Text, { children: scrollHint || pc.dim("loom 0.1.0 ") })] }), _jsx(Box, { height: vh, flexDirection: "column", children: visible.map((line, i) => (_jsx(Text, { wrap: "truncate-end", children: line || " " }, i))) }), notice ? _jsx(Text, { color: "yellow", children: ` ${notice}` }) : null, palette.open ? (_jsxs(Box, { borderStyle: "round", borderColor: "cyan", paddingX: 1, flexDirection: "column", children: [_jsxs(Text, { children: [pc.cyan("⌘ "), renderInput(palette.query, palette.query.length, "type to filter commands…")] }), paletteMatches.slice(0, 8).map((item, i) => {
|
|
420
|
+
const active = i === Math.min(palette.index, paletteMatches.length - 1);
|
|
421
|
+
const label = `${item.label}${item.hint ? pc.dim(` ${item.hint}`) : ""}`;
|
|
422
|
+
return _jsx(Text, { children: active ? pc.cyan(`› ${label}`) : ` ${label}` }, item.id);
|
|
423
|
+
}), !paletteMatches.length ? _jsx(Text, { dimColor: true, children: " no matches" }) : null] })) : null, _jsxs(Box, { borderStyle: "round", borderDimColor: true, paddingX: 1, flexDirection: "column", children: [_jsxs(Text, { children: [pc.cyan("› "), renderInput(value, cursor, PLACEHOLDER)] }), _jsxs(Text, { dimColor: true, children: [selected ?? "no agent", selectedStatus ? ` · ${selectedStatus.role}` : "", holdsBaton ? pc.magenta(" ⟵ baton") : pc.dim(" (send = shift baton)"), spinner ? ` ${spinner}` : ""] })] }), _jsx(Box, { justifyContent: "space-between", children: _jsx(Text, { dimColor: true, children: " shift+tab view · tab agent · ctrl+p palette · esc back/interrupt · ctrl+c quit" }) }), _jsxs(Box, { justifyContent: "space-between", children: [_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: ` ~ ${project.name} · baton ${project.holder ?? "—"}` +
|
|
424
|
+
(project.costUsd && project.costUsd > 0
|
|
425
|
+
? ` · ${project.costUsd >= 0.01 ? `$${project.costUsd.toFixed(2)}` : `$${project.costUsd.toFixed(4)}`}`
|
|
426
|
+
: "") }), _jsx(Text, { children: routeBadge })] }), _jsx(Text, { dimColor: true, children: project.needsInput ? pc.yellow("● needs input ") : "" })] })] }));
|
|
427
|
+
}
|
|
428
|
+
export async function runTui() {
|
|
429
|
+
const client = await ensureDaemon();
|
|
430
|
+
let project;
|
|
431
|
+
try {
|
|
432
|
+
project = await resolveCurrentProject(client);
|
|
433
|
+
}
|
|
434
|
+
catch (err) {
|
|
435
|
+
if (err instanceof NoProjectError) {
|
|
436
|
+
for (const line of logoLines(process.stdout.columns ?? 80))
|
|
437
|
+
console.log(line);
|
|
438
|
+
console.log();
|
|
439
|
+
console.log(pc.dim(" no Loom project here — run ") + pc.bold("loom init") + pc.dim(" first"));
|
|
440
|
+
process.exitCode = 1;
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
throw err;
|
|
444
|
+
}
|
|
445
|
+
const { waitUntilExit } = render(_jsx(App, { client: client, initial: project }), {
|
|
446
|
+
exitOnCtrlC: false,
|
|
447
|
+
});
|
|
448
|
+
await waitUntilExit();
|
|
449
|
+
process.exit(0);
|
|
450
|
+
}
|
|
451
|
+
//# sourceMappingURL=tui.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tui.js","sourceRoot":"","sources":["../../src/cli/tui.tsx"],"names":[],"mappings":"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"}
|
package/dist/cli/ui.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI rendering — one place that turns log events into terminal lines.
|
|
3
|
+
*/
|
|
4
|
+
import type { LoomEvent, ProjectStatus } from "../types.js";
|
|
5
|
+
export declare function agentColor(id: string): (s: string) => string;
|
|
6
|
+
export declare function timeShort(ts: number): string;
|
|
7
|
+
export declare function fmtUsd(usd: number): string;
|
|
8
|
+
export declare function formatEvent(e: LoomEvent): string | null;
|
|
9
|
+
export declare function formatProjectRow(p: ProjectStatus): string;
|
|
10
|
+
export declare function formatAgentRow(a: ProjectStatus["agents"][number]): string;
|
package/dist/cli/ui.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI rendering — one place that turns log events into terminal lines.
|
|
3
|
+
*/
|
|
4
|
+
import pc from "picocolors";
|
|
5
|
+
const AGENT_COLORS = [pc.cyan, pc.green, pc.yellow, pc.blue, pc.magenta];
|
|
6
|
+
const colorCache = new Map();
|
|
7
|
+
export function agentColor(id) {
|
|
8
|
+
let fn = colorCache.get(id);
|
|
9
|
+
if (!fn) {
|
|
10
|
+
fn = AGENT_COLORS[colorCache.size % AGENT_COLORS.length];
|
|
11
|
+
colorCache.set(id, fn);
|
|
12
|
+
}
|
|
13
|
+
return fn;
|
|
14
|
+
}
|
|
15
|
+
export function timeShort(ts) {
|
|
16
|
+
return new Date(ts).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
|
17
|
+
}
|
|
18
|
+
export function fmtUsd(usd) {
|
|
19
|
+
if (usd >= 0.01)
|
|
20
|
+
return `$${usd.toFixed(2)}`;
|
|
21
|
+
return `$${usd.toFixed(4)}`;
|
|
22
|
+
}
|
|
23
|
+
export function formatEvent(e) {
|
|
24
|
+
const who = e.agentId ?? String(e.payload.author ?? "");
|
|
25
|
+
const paint = agentColor(who || "system");
|
|
26
|
+
switch (e.kind) {
|
|
27
|
+
case "message": {
|
|
28
|
+
const text = String(e.payload.text ?? "");
|
|
29
|
+
if (!e.agentId) {
|
|
30
|
+
const author = String(e.payload.author ?? "you");
|
|
31
|
+
if (author === "loom") {
|
|
32
|
+
// Route-generated instructions: show compactly, not as the human.
|
|
33
|
+
return pc.dim(`${timeShort(e.ts)} loom ⟶ ${text.split("\n")[0] ?? ""}`);
|
|
34
|
+
}
|
|
35
|
+
return `${pc.dim(timeShort(e.ts))} ${pc.bold("you")} ${text}`;
|
|
36
|
+
}
|
|
37
|
+
return `${pc.dim(timeShort(e.ts))} ${paint(pc.bold(who))} ${text}`;
|
|
38
|
+
}
|
|
39
|
+
case "tool_call":
|
|
40
|
+
return pc.dim(` ⚙ ${String(e.payload.summary ?? e.payload.tool ?? "tool")}`);
|
|
41
|
+
case "file_edit":
|
|
42
|
+
return pc.dim(` ✎ ${String(e.payload.path ?? "")}`);
|
|
43
|
+
case "turn_diff": {
|
|
44
|
+
const files = e.payload.files ?? [];
|
|
45
|
+
const added = Number(e.payload.added ?? 0);
|
|
46
|
+
const removed = Number(e.payload.removed ?? 0);
|
|
47
|
+
const names = files.slice(0, 3).map((f) => f.path).join(", ");
|
|
48
|
+
const more = files.length > 3 ? ` +${files.length - 3} more` : "";
|
|
49
|
+
return pc.dim(` ✎ this prompt changed ${files.length} file${files.length === 1 ? "" : "s"} (+${added} −${removed}): ${names}${more}`);
|
|
50
|
+
}
|
|
51
|
+
case "handoff": {
|
|
52
|
+
const from = e.payload.from ?? "—";
|
|
53
|
+
const to = e.payload.to ?? "—";
|
|
54
|
+
const dirty = e.payload.dirty ? pc.dim(" · uncommitted changes in tree") : "";
|
|
55
|
+
return pc.magenta(` ⟶ baton: ${from} → ${to}`) + dirty;
|
|
56
|
+
}
|
|
57
|
+
case "suggestion":
|
|
58
|
+
return pc.yellow(` 💡 ${String(e.payload.reason ?? "handoff suggested")} ${pc.dim(`(/handoff ${String(e.payload.to)})`)}`);
|
|
59
|
+
case "needs_input":
|
|
60
|
+
return pc.yellow(` ⏸ ${who} needs input: ${String(e.payload.question ?? "")}`);
|
|
61
|
+
case "run_complete": {
|
|
62
|
+
const ms = Number(e.payload.durationMs ?? 0);
|
|
63
|
+
const cost = e.payload.costUsd !== undefined ? ` · $${Number(e.payload.costUsd).toFixed(4)}` : "";
|
|
64
|
+
return pc.dim(` ✓ ${who} done (${(ms / 1000).toFixed(1)}s${cost})`);
|
|
65
|
+
}
|
|
66
|
+
case "decision":
|
|
67
|
+
return pc.blue(` ★ decision: ${String(e.payload.text ?? "")}`);
|
|
68
|
+
case "memory_import":
|
|
69
|
+
return pc.blue(` 🧠 memory: imported ${String(e.payload.file ?? "")} from ${who} into the shared brain`);
|
|
70
|
+
case "route_started": {
|
|
71
|
+
const steps = e.payload.steps ?? [];
|
|
72
|
+
const name = e.payload.name ? ` "${String(e.payload.name)}"` : "";
|
|
73
|
+
return pc.cyan(` ➤ route${name} started: ${steps.join(" → ")}`);
|
|
74
|
+
}
|
|
75
|
+
case "route_step": {
|
|
76
|
+
const n = Number(e.payload.step) + 1;
|
|
77
|
+
const of = e.payload.of ? `/${Number(e.payload.of)}` : "";
|
|
78
|
+
const reason = e.payload.reason ? pc.dim(` (${String(e.payload.reason)})`) : "";
|
|
79
|
+
return pc.cyan(` ➤ ${e.payload.of ? "step" : "hop"} ${n}${of} → ${String(e.payload.agent)}`) + reason;
|
|
80
|
+
}
|
|
81
|
+
case "route_paused":
|
|
82
|
+
return pc.yellow(` ⏸ route paused — ${String(e.payload.agent)} asks: ${String(e.payload.question ?? "")}` +
|
|
83
|
+
pc.dim(" (answer with loom send / chat; route resumes automatically)"));
|
|
84
|
+
case "route_resumed":
|
|
85
|
+
return pc.cyan(` ➤ route resumed`);
|
|
86
|
+
case "route_completed": {
|
|
87
|
+
const cost = Number(e.payload.costUsd ?? 0);
|
|
88
|
+
const costNote = cost > 0 ? pc.dim(` · ${fmtUsd(cost)}`) : "";
|
|
89
|
+
return pc.green(` ✔ route completed (${Number(e.payload.steps)} steps)`) + costNote;
|
|
90
|
+
}
|
|
91
|
+
case "route_failed":
|
|
92
|
+
return e.payload.aborted
|
|
93
|
+
? pc.yellow(` ⊘ route stopped: ${String(e.payload.reason ?? "")}`)
|
|
94
|
+
: pc.red(` ✗ route failed: ${String(e.payload.reason ?? "")}`);
|
|
95
|
+
case "error":
|
|
96
|
+
return pc.red(` ✗ ${who}: ${String(e.payload.message ?? "error")}`);
|
|
97
|
+
case "status": {
|
|
98
|
+
const state = String(e.payload.state ?? "");
|
|
99
|
+
if (["interrupted", "unreachable", "wait_failed"].includes(state)) {
|
|
100
|
+
return pc.dim(` · ${who} ${state}`);
|
|
101
|
+
}
|
|
102
|
+
if (state === "turn_cost") {
|
|
103
|
+
return pc.dim(` · cost $${Number(e.payload.costUsd ?? 0).toFixed(4)}`);
|
|
104
|
+
}
|
|
105
|
+
if (state === "projection") {
|
|
106
|
+
return pc.dim(` · shared memory distilled by llm (${Number(e.payload.ms ?? 0)}ms)`);
|
|
107
|
+
}
|
|
108
|
+
return null; // lifecycle noise stays out of the chat
|
|
109
|
+
}
|
|
110
|
+
default:
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
export function formatProjectRow(p) {
|
|
115
|
+
const flag = p.needsInput ? pc.yellow("● needs input") : pc.dim("○ idle");
|
|
116
|
+
const holder = p.holder ? agentColor(p.holder)(p.holder) : pc.dim("—");
|
|
117
|
+
const last = p.lastEvent
|
|
118
|
+
? pc.dim(`${timeShort(p.lastEvent.ts)} ${p.lastEvent.kind}`)
|
|
119
|
+
: pc.dim("no activity");
|
|
120
|
+
const route = p.route && (p.route.status === "running" || p.route.status === "waiting_human")
|
|
121
|
+
? pc.cyan(` ➤ ${p.route.name ?? "route"} ${p.route.current + 1}/${p.route.steps.length}` +
|
|
122
|
+
(p.route.status === "waiting_human" ? " ⏸" : ""))
|
|
123
|
+
: "";
|
|
124
|
+
const cost = p.costUsd && p.costUsd > 0 ? pc.dim(` ${fmtUsd(p.costUsd)}`) : "";
|
|
125
|
+
return `${flag} ${pc.bold(p.name)} ${pc.dim(`(${p.id})`)} baton: ${holder}${route}${cost} ${last}`;
|
|
126
|
+
}
|
|
127
|
+
export function formatAgentRow(a) {
|
|
128
|
+
const paint = agentColor(a.id);
|
|
129
|
+
const baton = a.holdsBaton ? pc.magenta(" ⟵ baton") : "";
|
|
130
|
+
const avail = a.available ? pc.green("●") : pc.red("○");
|
|
131
|
+
const busy = a.busy ? pc.yellow(" (busy)") : "";
|
|
132
|
+
const tier = a.tier === "bridge" ? pc.dim(" [bridge]") : "";
|
|
133
|
+
return ` ${avail} ${paint(pc.bold(a.id))} ${pc.dim(a.kind)} — ${a.role}${tier}${busy}${baton}`;
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=ui.js.map
|