@yusukeshib/pi-babysit 0.6.22 → 0.6.24

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/README.md CHANGED
@@ -50,10 +50,13 @@ at every depth.
50
50
  Because sessions are real PTYs, the agent can also **drive interactive
51
51
  programs** (installers, wizards, REPLs): type with `babysit_send`
52
52
  (text or named keys) and read the rendered screen with
53
- `babysit_check { screen: true }` — a capability neither retired extension had.
53
+ `babysit_check { description, screen: true }` — a capability neither retired extension had.
54
54
 
55
55
  ## Tools (LLM-callable)
56
56
 
57
+ All five tools require a short, non-blank `description` explaining the purpose
58
+ of that call.
59
+
57
60
  | Tool | What it does |
58
61
  | ---- | ------------ |
59
62
  | `babysit_run` | Run any command (`description` + `command`, optional `name`/`pty`/`timeout`/`idleTimeout`/`retryOnWorkerDeath`/`notificationGroup`/`lifecycle`). Set `foreground: true` for one process or subagent whose result is needed in the same tool call; use `returnPattern`/`returnLines`/`maxBytes` to keep noisy process output bounded. Foreground and non-interactive process waits default to lifecycle `attached`, which terminates the process tree if that owning tool call is interrupted; background starts default to `detached`. Or start a named background subagent (`description`, `profile: "subagent"`, `task`, optional `name`/`agent`/`model`/`tools`/`maxDepth` and budget fields), then always collect it with `babysit_wait`. `maxDepth` defaults to 1. Subagent `continueAfterStart: true` is accepted as a compatibility alias for this default background behavior. Quick commands return inline; longer process runs notify in the background |
@@ -71,26 +74,35 @@ calls if another extension or preset re-enables `bash`, including shell
71
74
  backgrounding (`… &`, `nohup`, `setsid`, `disown`). Set
72
75
  `PI_BABYSIT_ALLOW_BASH=1` to retain direct `bash` explicitly.
73
76
 
74
- ## Describe every run
77
+ ## Describe every operation
75
78
 
76
- Every `babysit_run` requires a non-blank `description`, for both commands and
77
- subagents. Explain the purpose briefly in language the user can understand;
78
- `name` remains a stable session identifier, while `command` / `task` contains
79
- the actual execution instructions. Descriptions are trimmed before saving and
80
- are display metadata, not shell code or instructions sent to the subagent.
79
+ Every babysit tool call requires a non-blank `description`. Explain the purpose
80
+ briefly in language the user can understand. For `babysit_run`, `name` remains
81
+ a stable session identifier, while `command` / `task` contains the execution
82
+ instructions. Its description is trimmed and saved with the session. For
83
+ `babysit_check`, `babysit_send`, `babysit_wait`, and `babysit_kill`, the description
84
+ explains only that operation and never overwrites the session description.
85
+ Descriptions are display metadata, not shell code, stdin, or instructions sent
86
+ to the subagent.
81
87
 
82
88
  ```text
83
89
  babysit_run { description: "Run regression tests", command: "bun test", foreground: true }
84
90
  babysit_run { description: "Review the authentication changes", profile: "subagent", task: "Review the authentication diff for security regressions", maxTurns: 5 }
91
+ babysit_check { description: "Inspect build errors", id: "build", pattern: "ERROR" }
92
+ babysit_wait { description: "Wait for the build to finish", id: "build" }
93
+ babysit_send { description: "Ask the reviewer to check authorization too", id: "review", text: "Also check authorization." }
94
+ babysit_kill { description: "Stop the unused development server", id: "dev-server" }
85
95
  ```
86
96
 
87
97
  In Pi's main transcript the description is the prominent yellow heading, with
88
- the execution kind in muted gray. The full command or task is always visible
98
+ the tool name and execution kind in muted gray. The full command or task (or
99
+ all other operation arguments, including target IDs and input) is always visible
89
100
  in gray beneath it, even when tool results are collapsed. Session lists, the
90
- widget, and completion notifications also show the description. Older saved sessions and tool calls
91
- without one remain readable, falling back to their command or task. Callers
92
- must supply a description for new runs; blank or missing values are rejected
93
- before launch.
101
+ widget, and completion notifications show the session's original description.
102
+ Older saved sessions and tool calls without descriptions remain readable,
103
+ falling back to their command, task, or other arguments. Callers must supply a
104
+ description for every new call; blank or missing values are rejected before
105
+ execution.
94
106
 
95
107
  ## Remote processes over SSH
96
108
 
@@ -102,9 +114,9 @@ pi-babysit does not install remote software or copy credentials.
102
114
  ```text
103
115
  babysit_run { description: "Run tests on Linux", host: "yusuke-t4", cwd: "/home/yusuke/project", command: "bun test", foreground: true, returnLines: 30 }
104
116
  babysit_run { description: "Open a remote Python REPL", host: "user@server", command: "python3 -i", name: "remote-repl", continueAfterStart: true }
105
- babysit_check { id: "remote-repl", screen: true }
106
- babysit_send { id: "remote-repl", text: "print(42)" }
107
- babysit_kill { id: "remote-repl" }
117
+ babysit_check { description: "Read the remote REPL screen", id: "remote-repl", screen: true }
118
+ babysit_send { description: "Evaluate a value in the remote REPL", id: "remote-repl", text: "print(42)" }
119
+ babysit_kill { description: "Close the remote REPL", id: "remote-repl" }
108
120
  ```
109
121
 
110
122
  `host` omitted (or `"local"`) preserves local behavior. `cwd` is process-only:
@@ -155,9 +167,11 @@ sessions, and click again to return to running-only. Both modes show newest firs
155
167
  ten per page; `< 1/4 >` shows the current/total page when needed. Click the
156
168
  arrows to page. Rows occupy one line, previewing the description (or the command
157
169
  for older processes and task for older agents), with `…` when clipped. Click an
158
- AGENT or PROCESS row to replace the list with a tall **log viewer in the same widget area**, not an
159
- overlay or separate screen. `Esc` or the right-hand **Close** button restores
160
- the list, preserving its mode and page. The viewer uses Pi's `ScrollView` for
170
+ AGENT or PROCESS row to replace the list with a **log viewer in the same widget area**, not an
171
+ overlay or separate screen. The viewer is capped at ten lines including its header
172
+ and footer; all saved history remains available by scrolling. Click anywhere on
173
+ the viewer's header row to restore the list, preserving its mode and page.
174
+ There is no separate Close button or Esc binding. The viewer uses Pi's `ScrollView` for
161
175
  scroll position and follow behavior, with a widget-local scrollbar styled using
162
176
  Pi's scrollbar theme. Wheel, scrollbar drag/track clicks, and ↑/↓ navigate the
163
177
  log without requiring any Pi core changes. Home/End and PageUp/PageDown remain
@@ -204,8 +218,8 @@ pending for the next poll. Larger output stays out of model context. Inspect it
204
218
  through the session id without creating another shell session:
205
219
 
206
220
  ```text
207
- babysit_check { id: "cargo-test", lines: 50 }
208
- babysit_check { id: "cargo-test", pattern: "FAIL|ERROR", lines: 50 }
221
+ babysit_check { description: "Inspect the recent test output", id: "cargo-test", lines: 50 }
222
+ babysit_check { description: "Find test failures", id: "cargo-test", pattern: "FAIL|ERROR", lines: 50 }
209
223
  ```
210
224
 
211
225
  Tail and search results are capped at 200 lines and default to a 4 KB total
package/index.ts CHANGED
@@ -51,6 +51,18 @@ import { Type, type TSchema } from "typebox";
51
51
  import { StringEnum } from "@earendil-works/pi-ai";
52
52
  import { type AgentConfig, type AgentScope, discoverAgents } from "./agents";
53
53
 
54
+ const descriptionSchema = Type.String({
55
+ minLength: 1,
56
+ pattern: "\\S",
57
+ description: "Required short human-readable purpose for this operation. Explain what it does and why; shown prominently to the user.",
58
+ });
59
+
60
+ function requireDescription(value: unknown): void {
61
+ if (typeof value !== "string" || !value.trim()) {
62
+ throw new Error("`description` is required and must be a non-blank string for every babysit tool call.");
63
+ }
64
+ }
65
+
54
66
  // Dedicated babysit state root so pi-managed sessions never collide with the
55
67
  // user's own manual `babysit` sessions. The base is namespaced per pi session
56
68
  // on session_start (BABYSIT_DIR=<base>/<session-id>), so each pi session only
@@ -1373,6 +1385,17 @@ function escapeCommandForDisplay(command: string): string {
1373
1385
  );
1374
1386
  }
1375
1387
 
1388
+ function renderOperationCall(name: string, args: Record<string, unknown> | undefined, theme: Theme) {
1389
+ const { description, ...operationArgs } = args ?? {};
1390
+ const purpose = typeof description === "string" ? description.trim() : "";
1391
+ const title = theme.fg("muted", theme.bold(name));
1392
+ const heading = purpose
1393
+ ? `${title} ${theme.fg("warning", theme.bold(escapeCommandForDisplay(purpose)))}`
1394
+ : title;
1395
+ const raw = Object.keys(operationArgs).length ? JSON.stringify(operationArgs) : "";
1396
+ return new Text(heading + (raw ? `\n${theme.fg("muted", escapeCommandForDisplay(raw))}` : ""), 0, 0);
1397
+ }
1398
+
1376
1399
  export function readableLaunchCommand(command: string): string {
1377
1400
  // Older sessions quoted every argv element, including safe paths and flags.
1378
1401
  if (!command.startsWith("'") || !command.endsWith("'") || !command.includes("' '")) return command;
@@ -2577,6 +2600,7 @@ function renderWidgetSessionHeader(
2577
2600
  // How many trailing output lines to show per session in the widget.
2578
2601
  const WIDGET_COLLAPSED_TAIL_LINES = 1;
2579
2602
  const WIDGET_SESSION_PAGE_SIZE = 10;
2603
+ const WIDGET_VIEWER_MAX_LINES = 10;
2580
2604
 
2581
2605
  export interface WidgetSessionListState {
2582
2606
  mode: "running" | "all";
@@ -2732,7 +2756,11 @@ export function createSessionWidget(options: {
2732
2756
  viewer?.dispose();
2733
2757
  source = undefined;
2734
2758
  selectedId = id;
2735
- viewer = createLogViewer({ ...options, onClose: close });
2759
+ viewer = createLogViewer({
2760
+ ...options,
2761
+ getHeight: () => Math.min(WIDGET_VIEWER_MAX_LINES, options.getHeight()),
2762
+ onClose: close,
2763
+ });
2736
2764
  refreshViewer();
2737
2765
  options.requestRender();
2738
2766
  }
@@ -3286,7 +3314,7 @@ async function waitForTask(
3286
3314
  ok: completed.ok,
3287
3315
  text:
3288
3316
  `Subagent ${id} finished its task (${stats}).\n` +
3289
- `${subagentReuseHint(readMeta(id)?.reapAfter)} Follow-up: babysit_send { id: "${id}" }, ` +
3317
+ `${subagentReuseHint(readMeta(id)?.reapAfter)} Follow-up: babysit_send { description: "Assign a follow-up task", id: "${id}" }, ` +
3290
3318
  `or babysit_kill when done.\n\n${completed.body}`,
3291
3319
  status: st,
3292
3320
  progress: prog,
@@ -3714,7 +3742,14 @@ export default function (pi: ExtensionAPI) {
3714
3742
  const execute = tool.execute;
3715
3743
  pi.registerTool({
3716
3744
  ...tool,
3745
+ description: tool.description + " Always provide a short human-readable `description` explaining the purpose of this operation.",
3746
+ promptGuidelines: [
3747
+ "Every babysit tool call requires a short description explaining its purpose for the user. Operation descriptions for check/send/wait/kill do not change the session's original description.",
3748
+ ...(tool.promptGuidelines ?? []),
3749
+ ],
3750
+ renderCall: tool.renderCall ?? ((args, theme) => renderOperationCall(tool.name, args as Record<string, unknown>, theme)),
3717
3751
  async execute(toolCallId, params, signal, onUpdate, ctx) {
3752
+ requireDescription((params as { description?: unknown }).description);
3718
3753
  const result = await execute(toolCallId, params, signal, onUpdate, ctx);
3719
3754
  if ((result as typeof result & { isError?: boolean }).isError === true) {
3720
3755
  declaredToolErrors.add(toolCallId);
@@ -4156,7 +4191,7 @@ export default function (pi: ExtensionAPI) {
4156
4191
  : d.count && d.count > 1
4157
4192
  ? theme.fg("muted", `×${d.count}`)
4158
4193
  : "";
4159
- const header = theme.fg("muted", theme.bold("babysit_run COMMAND")) + (payload ? ` ${payload}` : "");
4194
+ const header = theme.fg("muted", theme.bold("babysit_run PROCESS")) + (payload ? ` ${payload}` : "");
4160
4195
  const box = new Box(1, 1, (t) => theme.bg("toolSuccessBg", t));
4161
4196
  box.addChild(new Text(header, 0, 0));
4162
4197
  box.addChild(new Text(renderStatus(status, theme), 0, 0));
@@ -4319,7 +4354,7 @@ export default function (pi: ExtensionAPI) {
4319
4354
  block: true,
4320
4355
  reason:
4321
4356
  "Use babysit_run for shell commands so output is supervised and captured outside model context. " +
4322
- "Inspect an existing session log with babysit_check { id, lines, pattern? }. " +
4357
+ "Inspect an existing session log with babysit_check { description, id, lines, pattern? }. " +
4323
4358
  `Retry with a short purpose description as babysit_run({ description: "Explain the purpose of this command", command: ${JSON.stringify(command)} }).`,
4324
4359
  };
4325
4360
  });
@@ -4330,13 +4365,11 @@ export default function (pi: ExtensionAPI) {
4330
4365
  label: "Babysit: run",
4331
4366
  description:
4332
4367
  "Run a supervised shell command, or start a reusable pi subagent with `profile: \"subagent\"`. " +
4333
- "Always provide a short human-readable `description` of what this run does and why. " +
4334
4368
  "Use `foreground` for results needed now; otherwise long commands notify on exit. Full logs stay on disk. " +
4335
4369
  "`returnPattern`/`returnLines` bound foreground output. Sessions support check, wait, send, and kill.",
4336
4370
  promptSnippet: "Run supervised commands or bounded pi subagents with context-safe logs",
4337
4371
  promptGuidelines: [
4338
4372
  "Use babysit_run for shell commands and give meaningful sessions a stable name; bundle tiny related read-only observations into one command.",
4339
- "Every babysit_run requires a short description explaining its purpose for the user, for both commands and subagents. Describe the actual work, not a generic 'run command' or 'start agent'.",
4340
4373
  "Use babysit_run foreground mode for one process or subagent whose result is needed now; never issue sibling foreground runs in parallel. For parallel process checks, start background runs with continueAfterStart and collect them with one multi-session babysit_wait.",
4341
4374
  "Use returnPattern/returnLines for noisy commands. During edit/fix loops run targeted checks first and one full validation suite at the end instead of repeating every full gate.",
4342
4375
  "After a background process starts, stop the turn for its automatic notification; never poll or sleep. Use continueAfterStart only for specific non-polling process work.",
@@ -4350,11 +4383,7 @@ export default function (pi: ExtensionAPI) {
4350
4383
  return prepareBabysitRunArguments(args) as never;
4351
4384
  },
4352
4385
  parameters: Type.Object({
4353
- description: Type.String({
4354
- minLength: 1,
4355
- pattern: "\\S",
4356
- description: "Required short human-readable purpose for this command or subagent. Explain what it does and why; shown prominently to the user.",
4357
- }),
4386
+ description: descriptionSchema,
4358
4387
  host: Type.Optional(Type.String({ description: "Process SSH destination/config alias (default local). Remote subagents are unsupported." })),
4359
4388
  cwd: Type.Optional(Type.String({ description: "Process working directory. Remote default is login home; never inferred from local cwd." })),
4360
4389
  command: Type.Optional(
@@ -4485,9 +4514,6 @@ export default function (pi: ExtensionAPI) {
4485
4514
 
4486
4515
  }),
4487
4516
  async execute(_id, params, _signal, _onUpdate, ctx) {
4488
- if (typeof params.description !== "string" || !params.description.trim()) {
4489
- throw new Error("`description` is required and must be a non-blank string for both commands and subagents.");
4490
- }
4491
4517
  const description = params.description.trim();
4492
4518
  await requireBabysit();
4493
4519
  const isSubagent = params.profile === "subagent";
@@ -4702,8 +4728,8 @@ export default function (pi: ExtensionAPI) {
4702
4728
  text:
4703
4729
  `${retried ? "Retried once after external worker death.\n" : ""}` +
4704
4730
  `Process started (id: ${res.id}). ${NOTIFY_MARKER}\nDescription: ${escapeCommandForDisplay(description)}\nLog: ${logPath(res.id)}\n${nextStep}\n` +
4705
- `Inspect: babysit_check { id: "${res.id}" } (screen: true for TUIs) · ` +
4706
- `Wait: babysit_wait { id: "${res.id}" } · Kill: babysit_kill { id: "${res.id}" }\n` +
4731
+ `Inspect: babysit_check { description: "Inspect session output", id: "${res.id}" } (screen: true for TUIs) · ` +
4732
+ `Wait: babysit_wait { description: "Wait for completion", id: "${res.id}" } · Kill: babysit_kill { description: "Stop this session", id: "${res.id}" }\n` +
4707
4733
  `Human can watch/take over: /babysit`,
4708
4734
  },
4709
4735
  ],
@@ -4810,8 +4836,8 @@ export default function (pi: ExtensionAPI) {
4810
4836
  text:
4811
4837
  `Subagent started (id: ${res.id})${agent ? ` [agent: ${agent.name}]` : ""}${res.model ? ` [model: ${res.model}]` : ""} [depth: ${subagentNesting.childDepth}/${subagentNesting.maxDepth}].\n` +
4812
4838
  `Description: ${escapeCommandForDisplay(description)}\nTask accepted — running in the background. You MUST collect it with babysit_wait before finishing the parent task; use foreground: true next time when no independent work is available.\n` +
4813
- `Progress: babysit_check { id: "${res.id}" } (only when inspection is needed)\n` +
4814
- `Collect: babysit_wait { id: "${res.id}" }\n` +
4839
+ `Progress: babysit_check { description: "Inspect agent progress", id: "${res.id}" } (only when inspection is needed)\n` +
4840
+ `Collect: babysit_wait { description: "Collect the agent result", id: "${res.id}" }\n` +
4815
4841
  `Human can watch/steer: /babysit (pick ${res.id})`,
4816
4842
  },
4817
4843
  ],
@@ -4833,7 +4859,7 @@ export default function (pi: ExtensionAPI) {
4833
4859
  // Legacy calls without descriptions still render their original payload safely.
4834
4860
  renderCall(args, theme) {
4835
4861
  const isSubagent = args.profile === "subagent";
4836
- const kind = isSubagent ? "AGENT" : "COMMAND";
4862
+ const kind = isSubagent ? "AGENT" : "PROCESS";
4837
4863
  const payload = isSubagent ? args.task : args.command;
4838
4864
  const agent = isSubagent && args.agent ? ` [${escapeCommandForDisplay(args.agent)}]` : "";
4839
4865
  const title = theme.fg("muted", `${theme.bold(`babysit_run ${kind}`)}${agent}`);
@@ -4895,6 +4921,7 @@ export default function (pi: ExtensionAPI) {
4895
4921
  "Do NOT poll this while merely waiting for a process to end — the exit notification is automatic.",
4896
4922
  promptSnippet: "Check status/progress of babysit sessions (processes and subagents)",
4897
4923
  parameters: Type.Object({
4924
+ description: descriptionSchema,
4898
4925
  id: Type.Optional(Type.String({ description: "Session id. Omit to list sessions." })),
4899
4926
  state: Type.Optional(
4900
4927
  StringEnum(["running", "terminal", "all"] as const, {
@@ -5135,11 +5162,12 @@ export default function (pi: ExtensionAPI) {
5135
5162
  description:
5136
5163
  "Send input to a babysit session. Process: `text` types a line into its stdin (PTY), " +
5137
5164
  "`keys` presses named keys (Enter, Tab, Esc, Up/Down/Left/Right, C-c, F1…) — use with " +
5138
- "babysit_check { screen: true } to drive interactive programs. Subagent: `text` is " +
5165
+ "babysit_check { description, screen: true } to drive interactive programs. Subagent: `text` is " +
5139
5166
  "STEERING while it works, or a NEW TASK after the current task settles (mode: auto/steer/task) — this " +
5140
5167
  "is how you resume a finished subagent with full context.",
5141
5168
  promptSnippet: "Send text/keys to a process, or steering/follow-up tasks to a subagent",
5142
5169
  parameters: Type.Object({
5170
+ description: descriptionSchema,
5143
5171
  id: Type.String({ description: "Session id." }),
5144
5172
  text: Type.Optional(
5145
5173
  Type.String({ description: "Text to send (a line for processes; a message for subagents)." }),
@@ -5211,7 +5239,7 @@ export default function (pi: ExtensionAPI) {
5211
5239
  content: [
5212
5240
  {
5213
5241
  type: "text",
5214
- text: `Sent to ${params.id}. Read the reaction with babysit_check { id: "${params.id}"${params.keys?.length ? ", screen: true" : ""} } — don't expect the echo of your own input.`,
5242
+ text: `Sent to ${params.id}. Read the reaction with babysit_check { description: "Inspect the response to input", id: "${params.id}"${params.keys?.length ? ", screen: true" : ""} } — don't expect the echo of your own input.`,
5215
5243
  },
5216
5244
  ],
5217
5245
  details: { kind: "process" },
@@ -5328,6 +5356,11 @@ export default function (pi: ExtensionAPI) {
5328
5356
  // New task → new bookkeeping window, so check/wait track THIS task.
5329
5357
  writeMeta(params.id, {
5330
5358
  kind: "subagent",
5359
+ name: meta?.name,
5360
+ description: meta?.description,
5361
+ launchCommand: meta?.launchCommand,
5362
+ reapAfter: meta?.reapAfter,
5363
+ startedAt: meta?.startedAt,
5331
5364
  task: params.text,
5332
5365
  // Start after the prompt-acceptance response. This excludes a
5333
5366
  // preceding run that settled between `send` and RPC acceptance.
@@ -5389,6 +5422,7 @@ export default function (pi: ExtensionAPI) {
5389
5422
  "the exit notification will resume you.",
5390
5423
  promptSnippet: "Block until session(s) finish — process exit / output pattern / subagent task done",
5391
5424
  parameters: Type.Object({
5425
+ description: descriptionSchema,
5392
5426
  id: Type.Optional(Type.String({ description: "Session id (single wait)." })),
5393
5427
  ids: Type.Optional(
5394
5428
  Type.Array(Type.String(), {
@@ -5535,7 +5569,10 @@ export default function (pi: ExtensionAPI) {
5535
5569
  label: "Babysit: kill",
5536
5570
  description: "Terminate a babysit session (process or subagent).",
5537
5571
  promptSnippet: "Terminate a babysit session",
5538
- parameters: Type.Object({ id: Type.String({ description: "Session id." }) }),
5572
+ parameters: Type.Object({
5573
+ description: descriptionSchema,
5574
+ id: Type.String({ description: "Session id." }),
5575
+ }),
5539
5576
  async execute(_id, params, _signal, _onUpdate, ctx) {
5540
5577
  await requireBabysit();
5541
5578
  // Prevent the exit poller racing a requested kill, but restore delivery
package/log-viewer.ts CHANGED
@@ -244,21 +244,18 @@ export function createLogViewer(options: LogViewerOptions) {
244
244
  const heading = {
245
245
  invalidate() {},
246
246
  render(width: number) {
247
- const close = truncateToWidth("[Close]", width);
248
- const room = Math.max(0, width - visibleWidth(close) - 1);
249
- const title = truncateToWidth(sanitize(header).replace(/\n/g, " "), room);
247
+ const title = truncateToWidth(sanitize(header).replace(/\n/g, " "), width);
250
248
  return [
251
249
  options.getTheme().fg("accent", title) +
252
250
  " ".repeat(
253
- Math.max(0, width - visibleWidth(title) - visibleWidth(close)),
254
- ) +
255
- options.getTheme().fg("muted", close),
251
+ Math.max(0, width - visibleWidth(title)),
252
+ ),
256
253
  ];
257
254
  },
258
255
  handleMouse(e: TuiMouseEvent) {
259
256
  if (
260
257
  e.button !== "left" ||
261
- e.x < Math.max(0, e.width - 7) ||
258
+ e.x < 0 ||
262
259
  e.x >= e.width
263
260
  )
264
261
  return;
@@ -272,7 +269,7 @@ export function createLogViewer(options: LogViewerOptions) {
272
269
  const footer: Component = {
273
270
  invalidate() {},
274
271
  render: (width) => [
275
- options.getTheme().fg("dim", truncateToWidth(source ? `↑↓ · bytes ${pages[0]?.start ?? 0}–${pages.at(-1)?.end ?? 0}/${source.size} (window) · Esc close` : "↑↓ · Esc close", width)),
272
+ options.getTheme().fg("dim", truncateToWidth(source ? `↑↓ · bytes ${pages[0]?.start ?? 0}–${pages.at(-1)?.end ?? 0}/${source.size} (window)` : "↑↓", width)),
276
273
  ],
277
274
  };
278
275
  let geometry = {
@@ -489,10 +486,6 @@ export function createLogViewer(options: LogViewerOptions) {
489
486
  options.requestRender();
490
487
  },
491
488
  handleKey(data: string): boolean {
492
- if (matchesKey(data, Key.escape)) {
493
- options.onClose();
494
- return true;
495
- }
496
489
  if (matchesKey(data, Key.up)) scrollView.scrollBy(-1);
497
490
  else if (matchesKey(data, Key.down)) scrollView.scrollBy(1);
498
491
  else return false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yusukeshib/pi-babysit",
3
- "version": "0.6.22",
3
+ "version": "0.6.24",
4
4
  "description": "Run any shell command and pi subagents under babysit, with context-safe captured output.",
5
5
  "keywords": [
6
6
  "pi-package",