-
Notifications
You must be signed in to change notification settings - Fork 23
Expand file tree
/
Copy pathhelp.zig
More file actions
381 lines (376 loc) · 13.5 KB
/
Copy pathhelp.zig
File metadata and controls
381 lines (376 loc) · 13.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
//! All user-facing help text: the overview, per-command help, and
//! topic pages. Kept in one place so the CLI surface reads as a whole
//! and stays consistent.
pub const Entry = struct {
/// Primary command or topic name.
name: []const u8,
/// Optional short alias (e.g. `at` for `attach`).
alias: ?[]const u8 = null,
/// Full help text printed by `boo help <name>`.
body: []const u8,
};
pub const overview =
\\boo: sessions that haunt your terminal
\\
\\A terminal multiplexer in the spirit of GNU screen, built on
\\libghostty. Sessions keep running when you disconnect; reattach
\\and the screen, scrollback, and title come back exactly as a
\\human would see them.
\\
\\usage:
\\ boo <command> [arguments]
\\
\\ With no arguments, boo prints this overview.
\\
\\commands:
\\ new [name] [-d] [-- cmd...] start a session (attach unless -d)
\\ attach, at <name> attach a session (steals politely)
\\ ui manage sessions in a full-screen UI
\\ ls [--json] list sessions
\\ send <name> [flags] type into a session
\\ peek <name> print the session's screen
\\ wait <name> block until output matches or settles
\\ kill <name | --all> end a session, or all of them
\\ rename <name> <new-name> rename a session
\\ version print the version
\\ help [command | topic] this overview, or detailed help
\\
\\topics:
\\ keys the C-a key bindings inside a session
\\ automation driving boo from scripts and AI agents
\\
\\Run 'boo help <command>' for flags and examples, or
\\'boo help --all' to print every page at once.
\\
\\session selection:
\\ Commands taking <name> accept a unique prefix of the session
\\ name (e.g. 'boo attach bu' for "build").
\\
\\environment:
\\ BOO_DIR socket directory
\\ (default: $XDG_RUNTIME_DIR/boo, else /tmp/boo-<uid>)
\\ BOO_LOG append daemon logs to this file (debugging)
\\
\\exit codes:
\\ 0 success 1 error 2 usage error
\\ 3 no such session 4 wait timed out
\\
;
pub const commands = [_]Entry{
.{
.name = "new",
.body =
\\usage: boo new [name] [-d|--detached] [-- cmd...]
\\
\\Start a session running cmd (default: $SHELL) and attach to
\\it. The session keeps running after you detach (C-a d) or
\\lose the connection.
\\
\\Names may contain letters, digits, '.', '_', and '-'. The
\\default name is the name of the current directory, or the
\\process id when that name is taken or unusable. Everything
\\after '--' is the command to run in the session.
\\
\\flags:
\\ -d, --detached start without attaching and print the
\\ session name on stdout
\\
\\examples:
\\ boo new interactive shell, attach now
\\ boo new work named session
\\ boo new build -d -- make -j background a build
\\
,
},
.{
.name = "attach",
.alias = "at",
.body =
\\usage: boo attach <name>
\\ boo at <name>
\\
\\Attach this terminal to a session. The screen, scrollback,
\\cursor, and title are restored from terminal state. If the
\\session is attached elsewhere, the other client is detached
\\(the session is stolen).
\\
\\A unique prefix of the name is accepted.
\\
\\Inside the session, press C-a d to detach. See 'boo help
\\keys' for all bindings.
\\
\\examples:
\\ boo attach build reattach "build"
\\ boo at bu the same, by prefix
\\
,
},
.{
.name = "ui",
.body =
\\usage: boo ui
\\
\\Manage sessions in a full-screen interface: a sidebar lists
\\every session (window title underneath) and the focused
\\session runs in a viewport on the right, rendered live from
\\terminal state. Prompts and confirmations open as modals
\\over the screen.
\\
\\mouse:
\\ click a session focus it (steals politely, like attach)
\\ click its 'x' kill it (opens a confirmation modal)
\\ click + new session open the new-session modal
\\ click on a modal close it
\\ scroll the sidebar scroll the session list
\\ in the viewport forwarded to the application when it
\\ asked for mouse reporting; otherwise
\\ dragging selects text and copies it on
\\ release (OSC 52)
\\
\\keys (prefix C-a):
\\ C-a open the palette: fuzzy-find a session or run
\\ a command (new, kill, rename, quit, ...)
\\ C-a C-c open the new-session modal
\\ C-a C-k kill the focused session (confirmation modal)
\\ C-a C-r rename the focused session
\\ C-a C-n focus the next session
\\ C-a C-p focus the previous session
\\ C-a C-a focus the previously focused session
\\ C-a C-d quit the UI (sessions keep running)
\\ C-a C-l redraw
\\ C-a Esc close the palette / cancel the prefix
\\
\\In the palette, type to filter, move with up/down (or C-n/
\\C-p), run the selection with enter, and close with esc.
\\Printable keys after C-a feed the filter, so C-a k searches
\\for "k"; the single-letter screen bindings live on as
\\palette commands and as the control variants above. A
\\literal C-a is sent with the palette's "send a literal
\\C-a" command.
\\
\\The new-session modal creates a session running $SHELL;
\\leave the name empty to pick one automatically, like
\\'boo new'.
\\
\\Everything else is typed into the focused session. Unlike a
\\plain attach, pasted text may contain C-a bytes safely
\\(bracketed paste).
\\
,
},
.{
.name = "ls",
.alias = "list",
.body =
\\usage: boo ls [--json]
\\
\\List sessions: name, attach state, idle time (time since the
\\last output or client input), and the session's title. Stale
\\sockets left by crashed daemons are cleaned up.
\\
\\flags:
\\ --json emit a JSON array:
\\ [{"name","attached","idle_ms","title"}]
\\
,
},
.{
.name = "send",
.body =
\\usage: boo send <name> [--text <text>] [--key <list>] [flags]
\\
\\Type into a session, exactly as if the text had been typed
\\at the keyboard. --text is sent literally: no escape
\\processing and no implicit newline, so there is never a
\\quoting layer to fight. With neither --text nor --key,
\\bytes are read from stdin (binary safe, NUL excluded).
\\
\\flags:
\\ --text <text> the text to type
\\ --enter append Enter after everything else
\\ --key <list> send named keys, comma separated:
\\ Enter, Tab, Escape, Space, Backspace,
\\ Up, Down, Left, Right, Home, End, C-a..C-z.
\\ Cannot be combined with --text; use two calls.
\\ --stdin force reading from stdin
\\
\\examples:
\\ boo send build --text 'make test' --enter run a command
\\ boo send build --key C-c interrupt it
\\ printf 'y\n' | boo send build pipe bytes in
\\
,
},
.{
.name = "peek",
.body =
\\usage: boo peek <name> [--scrollback] [--json]
\\
\\Print the session's rendered screen: what a human attached
\\right now would see, reconstructed from terminal state (not
\\a raw byte log). Safe to run while attached.
\\
\\flags:
\\ --scrollback include the full scrollback history
\\ --json emit {"session","title","rows","cols",
\\ "cursor":{"row","col"},"screen"}
\\
\\examples:
\\ boo peek build | tail -20
\\ boo peek build --scrollback | grep -n error
\\
,
},
.{
.name = "wait",
.body =
\\usage: boo wait <name> (--text <text> | --idle) [--timeout <dur>]
\\
\\Block until something happens in the session, then exit 0.
\\Replaces sleep-and-poll loops in scripts.
\\
\\flags:
\\ --text <text> until the rendered screen contains <text>
\\ (plain substring match)
\\ --idle until the session has produced no output
\\ for 2 seconds
\\ --timeout <dur> give up and exit 4 (default: 30s)
\\
\\Durations are an integer with a unit: 500ms, 2s, 1m, 4h
\\(or 4hr), 1d. Flags also accept --flag=value.
\\
\\examples:
\\ boo wait build --text 'PASS' --timeout 2m
\\ boo wait build --idle && boo peek build
\\
,
},
.{
.name = "kill",
.body =
\\usage: boo kill <name | --all>
\\
\\End a session: its process receives SIGHUP and the daemon
\\exits. --all ends every session and sweeps stale sockets.
\\
\\examples:
\\ boo kill build
\\ boo kill --all
\\
,
},
.{
.name = "rename",
.body =
\\usage: boo rename <name> <new-name>
\\
\\Rename a session. The running program is unaffected and an
\\attached client stays attached. The old name accepts a
\\unique prefix, like attach.
\\
\\example:
\\ boo rename work api-server
\\
,
},
.{
.name = "version",
.body =
\\usage: boo version
\\
\\Print the boo version. Also available as -V or --version.
\\
,
},
.{
.name = "help",
.body =
\\usage: boo help [command | topic] [--all]
\\
\\Show the overview, a command's detailed help, or a topic
\\page ('keys', 'automation'). --all prints every page in one
\\pass, which is handy for piping into a pager or for tools
\\that want to learn the whole CLI in one call.
\\
,
},
};
pub const topics = [_]Entry{
.{
.name = "keys",
.body =
\\Key bindings inside an attached session (prefix C-a)
\\
\\ C-a d detach
\\ C-a l redraw
\\ C-a a send a literal C-a
\\
\\Control variants match GNU screen: C-a C-d detaches and
\\C-a C-l redraws. Detaching leaves the session running;
\\'boo attach' brings it back.
\\
\\'boo ui' adds bindings for managing sessions; see
\\'boo help ui'.
\\
,
},
.{
.name = "automation",
.body =
\\Driving boo from scripts and AI agents
\\
\\Everything except 'attach' works without a terminal. The
\\canonical loop:
\\
\\ boo new build -d -- bash # 1. headless session
\\ boo send build --text 'make' --enter # 2. type into it
\\ boo wait build --idle # 3. let output settle
\\ boo peek build --scrollback # 4. read the screen
\\ boo kill build # 5. clean up
\\
\\reading state:
\\ peek prints the rendered screen, not a raw byte stream:
\\ ordered, fully redrawn, and stable. --scrollback includes
\\ history; --json adds size, cursor, and title.
\\
\\waiting (instead of sleep):
\\ boo wait <name> --text <text> screen contains <text>
\\ boo wait <name> --idle output quiet for 2 seconds
\\ boo wait <name> ... --timeout <dur> exit 4 on timeout
\\
\\sending input:
\\ send is literal: no escapes, no implicit newline, no
\\ quoting layer. --enter submits; --key Enter,C-c,Up names
\\ control keys; stdin mode is binary safe.
\\
\\machine-readable output:
\\ boo ls --json [{"name","attached","idle_ms","title"}]
\\ boo peek --json {"session","title","rows","cols",
\\ "cursor":{"row","col"},"screen"}
\\
\\exit codes:
\\ 0 success 1 error 2 usage error
\\ 3 no such session 4 wait timed out
\\
\\tips:
\\ - Sessions are cheap; use one session per task.
\\ - 'boo new -d' prints the session name on stdout.
\\ - Pick unique session names so [name] prefixes stay
\\ unambiguous.
\\
,
},
};
pub fn find(name: []const u8) ?*const Entry {
const eql = @import("std").mem.eql;
for (&commands) |*entry| {
if (eql(u8, entry.name, name)) return entry;
if (entry.alias) |alias| {
if (eql(u8, alias, name)) return entry;
}
}
for (&topics) |*entry| {
if (eql(u8, entry.name, name)) return entry;
}
return null;
}