pi-chassis 0.0.0-stage → 0.7.1
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/CHANGELOG.md +118 -0
- package/LICENSE +21 -0
- package/README.md +51 -2
- package/THIRD_PARTY_NOTICES +30 -0
- package/dist/chassis/alert.d.ts +50 -0
- package/dist/chassis/alert.js +107 -0
- package/dist/chassis/api.d.ts +411 -0
- package/dist/chassis/api.js +676 -0
- package/dist/chassis/bash-output.d.ts +89 -0
- package/dist/chassis/bash-output.js +157 -0
- package/dist/chassis/brand.d.ts +99 -0
- package/dist/chassis/brand.js +79 -0
- package/dist/chassis/client.d.ts +87 -0
- package/dist/chassis/client.js +271 -0
- package/dist/chassis/commands.d.ts +60 -0
- package/dist/chassis/commands.js +211 -0
- package/dist/chassis/editor.d.ts +70 -0
- package/dist/chassis/editor.js +213 -0
- package/dist/chassis/footer.d.ts +14 -0
- package/dist/chassis/footer.js +136 -0
- package/dist/chassis/header.d.ts +12 -0
- package/dist/chassis/header.js +38 -0
- package/dist/chassis/home.d.ts +48 -0
- package/dist/chassis/home.js +184 -0
- package/dist/chassis/icons.d.ts +203 -0
- package/dist/chassis/icons.js +190 -0
- package/dist/chassis/index.d.ts +21 -0
- package/dist/chassis/index.js +582 -0
- package/dist/chassis/layout.d.ts +40 -0
- package/dist/chassis/layout.js +264 -0
- package/dist/chassis/message-modes.d.ts +21 -0
- package/dist/chassis/message-modes.js +49 -0
- package/dist/chassis/messages.d.ts +75 -0
- package/dist/chassis/messages.js +392 -0
- package/dist/chassis/modes.d.ts +21 -0
- package/dist/chassis/modes.js +99 -0
- package/dist/chassis/palette.d.ts +84 -0
- package/dist/chassis/palette.js +235 -0
- package/dist/chassis/peek.d.ts +61 -0
- package/dist/chassis/peek.js +156 -0
- package/dist/chassis/prompt-row.d.ts +42 -0
- package/dist/chassis/prompt-row.js +68 -0
- package/dist/chassis/provider-view.d.ts +34 -0
- package/dist/chassis/provider-view.js +107 -0
- package/dist/chassis/provider.d.ts +69 -0
- package/dist/chassis/provider.js +73 -0
- package/dist/chassis/readonly-command.d.ts +19 -0
- package/dist/chassis/readonly-command.js +454 -0
- package/dist/chassis/sanitize.d.ts +42 -0
- package/dist/chassis/sanitize.js +103 -0
- package/dist/chassis/session-info.d.ts +39 -0
- package/dist/chassis/session-info.js +107 -0
- package/dist/chassis/sidebar.d.ts +48 -0
- package/dist/chassis/sidebar.js +273 -0
- package/dist/chassis/state.d.ts +38 -0
- package/dist/chassis/state.js +19 -0
- package/dist/chassis/telemetry.d.ts +60 -0
- package/dist/chassis/telemetry.js +191 -0
- package/dist/chassis/tools.d.ts +112 -0
- package/dist/chassis/tools.js +588 -0
- package/dist/chassis/version.d.ts +2 -0
- package/dist/chassis/version.js +20 -0
- package/dist/diff/git-diff.d.ts +71 -0
- package/dist/diff/git-diff.js +325 -0
- package/dist/diff/host.d.ts +34 -0
- package/dist/diff/host.js +50 -0
- package/dist/diff/index.d.ts +13 -0
- package/dist/diff/index.js +86 -0
- package/dist/diff/render.d.ts +67 -0
- package/dist/diff/render.js +196 -0
- package/dist/diff/types.d.ts +60 -0
- package/dist/diff/types.js +4 -0
- package/dist/diff/view.d.ts +118 -0
- package/dist/diff/view.js +528 -0
- package/dist/git/flows.d.ts +92 -0
- package/dist/git/flows.js +415 -0
- package/dist/git/forge.d.ts +26 -0
- package/dist/git/forge.js +41 -0
- package/dist/git/index.d.ts +20 -0
- package/dist/git/index.js +121 -0
- package/dist/git/repo.d.ts +64 -0
- package/dist/git/repo.js +186 -0
- package/dist/git/run.d.ts +38 -0
- package/dist/git/run.js +127 -0
- package/dist/git/settings.d.ts +8 -0
- package/dist/git/settings.js +38 -0
- package/dist/git/text.d.ts +51 -0
- package/dist/git/text.js +109 -0
- package/dist/widgets/container/detect.d.ts +23 -0
- package/dist/widgets/container/detect.js +67 -0
- package/dist/widgets/container/index.d.ts +9 -0
- package/dist/widgets/container/index.js +26 -0
- package/dist/widgets/mcp/index.d.ts +13 -0
- package/dist/widgets/mcp/index.js +50 -0
- package/dist/widgets/mcp/status.d.ts +50 -0
- package/dist/widgets/mcp/status.js +70 -0
- package/dist/widgets/session-todos/index.d.ts +12 -0
- package/dist/widgets/session-todos/index.js +52 -0
- package/dist/widgets/subagents/index.d.ts +16 -0
- package/dist/widgets/subagents/index.js +173 -0
- package/dist/widgets/subagents/status.d.ts +61 -0
- package/dist/widgets/subagents/status.js +198 -0
- package/dist/widgets/todo/index.d.ts +13 -0
- package/dist/widgets/todo/index.js +65 -0
- package/dist/widgets/todo/parse.d.ts +29 -0
- package/dist/widgets/todo/parse.js +122 -0
- package/docs/branding.md +25 -0
- package/docs/development.md +22 -0
- package/docs/diff-api.md +18 -0
- package/docs/git.md +23 -0
- package/docs/internals.md +13 -0
- package/docs/provider-status.md +23 -0
- package/docs/status-widgets.md +157 -0
- package/docs/tool-rows.md +50 -0
- package/docs/usage.md +62 -0
- package/docs/widgets.md +113 -0
- package/extensions/chassis/alert.ts +127 -0
- package/extensions/chassis/api.ts +967 -0
- package/extensions/chassis/bash-output.ts +186 -0
- package/extensions/chassis/brand.ts +151 -0
- package/extensions/chassis/client.ts +284 -0
- package/extensions/chassis/commands.ts +244 -0
- package/extensions/chassis/editor.ts +253 -0
- package/extensions/chassis/footer.ts +131 -0
- package/extensions/chassis/header.ts +43 -0
- package/extensions/chassis/home.ts +186 -0
- package/extensions/chassis/icons.ts +220 -0
- package/extensions/chassis/index.ts +605 -0
- package/extensions/chassis/layout.ts +298 -0
- package/extensions/chassis/message-modes.ts +48 -0
- package/extensions/chassis/messages.ts +403 -0
- package/extensions/chassis/modes.ts +108 -0
- package/extensions/chassis/palette.ts +258 -0
- package/extensions/chassis/peek.ts +167 -0
- package/extensions/chassis/prompt-row.ts +86 -0
- package/extensions/chassis/provider-view.ts +118 -0
- package/extensions/chassis/provider.ts +115 -0
- package/extensions/chassis/readonly-command.ts +440 -0
- package/extensions/chassis/sanitize.ts +108 -0
- package/extensions/chassis/session-info.ts +127 -0
- package/extensions/chassis/sidebar.ts +285 -0
- package/extensions/chassis/state.ts +50 -0
- package/extensions/chassis/telemetry.ts +222 -0
- package/extensions/chassis/tools.ts +618 -0
- package/extensions/chassis/version.ts +20 -0
- package/extensions/diff/git-diff.ts +365 -0
- package/extensions/diff/host.ts +58 -0
- package/extensions/diff/index.ts +101 -0
- package/extensions/diff/render.ts +217 -0
- package/extensions/diff/types.ts +67 -0
- package/extensions/diff/view.ts +523 -0
- package/extensions/git/flows.ts +485 -0
- package/extensions/git/forge.ts +54 -0
- package/extensions/git/index.ts +117 -0
- package/extensions/git/repo.ts +200 -0
- package/extensions/git/run.ts +143 -0
- package/extensions/git/settings.ts +38 -0
- package/extensions/git/text.ts +133 -0
- package/extensions/widgets/container/detect.ts +81 -0
- package/extensions/widgets/container/index.ts +29 -0
- package/extensions/widgets/mcp/index.ts +53 -0
- package/extensions/widgets/mcp/status.ts +94 -0
- package/extensions/widgets/session-todos/index.ts +55 -0
- package/extensions/widgets/subagents/index.ts +170 -0
- package/extensions/widgets/subagents/status.ts +237 -0
- package/extensions/widgets/todo/index.ts +66 -0
- package/extensions/widgets/todo/parse.ts +119 -0
- package/package.json +91 -4
- package/scripts/link-pi.mjs +76 -0
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Widget registry: the one place info and status widgets are declared.
|
|
3
|
+
*
|
|
4
|
+
* A widget is a small object with an id and a render function. The TUI decides where it shows up
|
|
5
|
+
* (sidebar section, footer segment, or both) from its `slots`, orders it by `order`, and refreshes
|
|
6
|
+
* it on `refreshMs` or when the widget calls `handle.refresh()`.
|
|
7
|
+
*
|
|
8
|
+
* import { registerWidget } from "../chassis/api.ts";
|
|
9
|
+
*
|
|
10
|
+
* registerWidget(pi, {
|
|
11
|
+
* id: "deploy",
|
|
12
|
+
* title: "Deploy",
|
|
13
|
+
* slots: ["footer", "sidebar"],
|
|
14
|
+
* order: 10,
|
|
15
|
+
* refreshMs: 30_000,
|
|
16
|
+
* render: () => ({ icon: "\uF0E7", text: "staging·v42", color: "brand" }),
|
|
17
|
+
* detail: () => ["Last deploy 12m ago"],
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* The registry lives on globalThis because pi loads every extension file in its own module scope
|
|
21
|
+
* (jiti, moduleCache off), so a plain module-level Map would give each extension its own copy.
|
|
22
|
+
* Widgets registered before chassis loads are kept and shown once it starts.
|
|
23
|
+
*
|
|
24
|
+
* Plain `ctx.ui.setStatus()` from other extensions still works: the TUI shows those statuses as
|
|
25
|
+
* footer segments too, unless a registered widget claims the same key (`statusKey`).
|
|
26
|
+
*/
|
|
27
|
+
import type { ExtensionAPI, ExtensionContext, Theme } from "@earendil-works/pi-coding-agent";
|
|
28
|
+
import type { IconLike } from "./icons.ts";
|
|
29
|
+
/** A render or detail call slower than this counts as a strike against the widget. */
|
|
30
|
+
export declare const SLOW_RENDER_MS = 50;
|
|
31
|
+
/** This many slow calls in a row suspend the widget until `/widgets enable ID`. */
|
|
32
|
+
export declare const SLOW_RENDER_STRIKES = 3;
|
|
33
|
+
/** An `update` that has not settled after this long is abandoned and reported as an error. */
|
|
34
|
+
export declare const DEFAULT_UPDATE_TIMEOUT_MS = 10000;
|
|
35
|
+
/** Where a widget can appear. */
|
|
36
|
+
export type WidgetSlot = "sidebar" | "footer";
|
|
37
|
+
/**
|
|
38
|
+
* Colours a widget can ask for: theme tokens, the brand colours (`brand`, `brandDark`, `plan`; see
|
|
39
|
+
* brand.ts), or any `#RRGGBB` value.
|
|
40
|
+
*/
|
|
41
|
+
export type WidgetColor = "text" | "muted" | "dim" | "accent" | "success" | "warning" | "error" | "brand" | "brandDark" | "plan" | `#${string}`;
|
|
42
|
+
/** Status level: drives the dot colour in the sidebar heading when no colour is given. */
|
|
43
|
+
export type WidgetLevel = "ok" | "warn" | "error" | "off" | "info";
|
|
44
|
+
/** What a widget renders: one short line for the footer and the sidebar heading row. */
|
|
45
|
+
export interface WidgetView {
|
|
46
|
+
/** Optional leading glyph. A string is used as given with a Nerd Font and dropped (private-use characters removed) without one; `{ nerd, plain }` gives one for each set. */
|
|
47
|
+
icon?: IconLike;
|
|
48
|
+
/**
|
|
49
|
+
* Short status text, e.g. "staging·v42". Plain text: the TUI applies the colour. May be omitted by
|
|
50
|
+
* a `sidebar: "section"` widget that only has detail lines.
|
|
51
|
+
*/
|
|
52
|
+
text?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Footer-only label shown between icon and text (e.g. "Deploy" gives "<icon> Deploy staging·v42").
|
|
55
|
+
* The sidebar shows the widget title in its own column instead.
|
|
56
|
+
*/
|
|
57
|
+
label?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Sidebar row only: already-styled text drawn after `text`, separated by a space, in its own
|
|
60
|
+
* colours (e.g. a role name coloured by what it allows). Not shown in the footer.
|
|
61
|
+
*/
|
|
62
|
+
tag?: string;
|
|
63
|
+
/** Colour for icon and text. Defaults from `level`, else "text". */
|
|
64
|
+
color?: WidgetColor;
|
|
65
|
+
/** Status level, used for colour defaults and the sidebar dot. */
|
|
66
|
+
level?: WidgetLevel;
|
|
67
|
+
}
|
|
68
|
+
/** Something the user can run from the command palette (ctrl+p), shown as "<title>: <label>". */
|
|
69
|
+
export interface WidgetAction {
|
|
70
|
+
/** Unique within the widget. */
|
|
71
|
+
id: string;
|
|
72
|
+
label: string;
|
|
73
|
+
description?: string;
|
|
74
|
+
/** A thrown error or rejection is shown as a notification and recorded on the widget. */
|
|
75
|
+
run: (ctx: ExtensionContext) => void | Promise<void>;
|
|
76
|
+
}
|
|
77
|
+
export interface WidgetRenderContext {
|
|
78
|
+
theme: Theme;
|
|
79
|
+
/** The latest session context, if a session is running. */
|
|
80
|
+
ctx: ExtensionContext | undefined;
|
|
81
|
+
/** Width available to this widget's line(s), in terminal columns. */
|
|
82
|
+
width: number;
|
|
83
|
+
}
|
|
84
|
+
export interface WidgetSpec {
|
|
85
|
+
/** Unique id; registering the same id again replaces the widget. */
|
|
86
|
+
id: string;
|
|
87
|
+
/** Sidebar section heading. Defaults to the id. */
|
|
88
|
+
title?: string;
|
|
89
|
+
/**
|
|
90
|
+
* Glyph in front of the widget in the sidebar: before a `sidebar: "section"` heading, or, for a
|
|
91
|
+
* row, as its marker in place of the bullet (and of the level marker). A row then leaves
|
|
92
|
+
* `view.icon` out of the value; the footer still draws it. A string is used as given with a Nerd
|
|
93
|
+
* Font and dropped without one; `{ nerd, plain }` gives one for each icon set. With no icon in
|
|
94
|
+
* the current set, a row shows its level marker or the bullet and a section shows no glyph.
|
|
95
|
+
*/
|
|
96
|
+
icon?: IconLike;
|
|
97
|
+
/** Where it shows. Default ["footer", "sidebar"]. */
|
|
98
|
+
slots?: WidgetSlot[];
|
|
99
|
+
/** Lower comes first. Default 100. Built-ins: container 0, mcp 30, subagents 35, todo 40 and session-todos 50. */
|
|
100
|
+
order?: number;
|
|
101
|
+
/** Re-render interval while a session runs. Omit for event-driven widgets. */
|
|
102
|
+
refreshMs?: number;
|
|
103
|
+
/** Give up on a slow `update` after this many ms (default 10000). The widget shows the error. */
|
|
104
|
+
updateTimeoutMs?: number;
|
|
105
|
+
/**
|
|
106
|
+
* Called on each refresh tick (and on `handle.refresh()`), before rendering. Use it to poll
|
|
107
|
+
* slow sources; rendering itself should be cheap and synchronous.
|
|
108
|
+
*/
|
|
109
|
+
update?: (ctx: ExtensionContext) => void | Promise<void>;
|
|
110
|
+
/**
|
|
111
|
+
* Opt in to caching: `render` and `detail` then run again only when this string, the registry
|
|
112
|
+
* version (any widget update or refresh), the width, the theme or the context changes. Use it
|
|
113
|
+
* for widgets that read session state (return something that changes with it) and are costly
|
|
114
|
+
* to compute. Do not use it when the output depends on the clock.
|
|
115
|
+
*/
|
|
116
|
+
cacheKey?: (rc: WidgetRenderContext) => string;
|
|
117
|
+
/** Return the one-line view, or undefined to hide the widget. */
|
|
118
|
+
render: (rc: WidgetRenderContext) => WidgetView | undefined;
|
|
119
|
+
/**
|
|
120
|
+
* Extra sidebar lines under the heading (plain or themed strings). A line can also be a list of
|
|
121
|
+
* pieces, each a string or a `{ text, url }` link, for a line that links part of its text; see
|
|
122
|
+
* `DetailLine`. A link shows as its label alone where the terminal cannot show links, and is
|
|
123
|
+
* left out unless `url` is a plain https URL.
|
|
124
|
+
*/
|
|
125
|
+
detail?: (rc: WidgetRenderContext) => DetailLine[] | undefined;
|
|
126
|
+
/**
|
|
127
|
+
* Called when the user clicks a line returned by `detail`, with that line's index. Only the
|
|
128
|
+
* lines `detail` returned are clickable, not the heading or an error line. A thrown error or
|
|
129
|
+
* rejection is shown as a notification.
|
|
130
|
+
*/
|
|
131
|
+
onDetailClick?: (index: number, ctx: ExtensionContext) => void | Promise<void>;
|
|
132
|
+
/** Palette actions, listed while the widget is enabled and not suspended. */
|
|
133
|
+
actions?: WidgetAction[];
|
|
134
|
+
/** A setStatus() key this widget replaces, so the raw status isn't shown twice. Default: the id. */
|
|
135
|
+
statusKey?: string;
|
|
136
|
+
/** More setStatus() keys this widget replaces, for a widget that covers several raw statuses. */
|
|
137
|
+
statusKeys?: string[];
|
|
138
|
+
/**
|
|
139
|
+
* Sidebar layout. "row" (default): one "• Title value" line in the status list, detail lines
|
|
140
|
+
* indented under it. "section": its own sidebar section, with a bold title, the value beside
|
|
141
|
+
* it, and the detail lines as the section body (plain or themed strings, shown as given).
|
|
142
|
+
*/
|
|
143
|
+
sidebar?: "row" | "section";
|
|
144
|
+
}
|
|
145
|
+
/** A link inside a detail line: the visible `text`, and the https `url` it opens. */
|
|
146
|
+
export interface DetailLink {
|
|
147
|
+
text: string;
|
|
148
|
+
url: string;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* One detail line: a string, or a list of pieces. A piece is a string or a `DetailLink`. Links only
|
|
152
|
+
* work as pieces: chassis removes every escape sequence from text, so a link written into a string
|
|
153
|
+
* is shown as its label alone. That keeps text that came from outside (a ticket summary, an
|
|
154
|
+
* incident title) from drawing a link of its own.
|
|
155
|
+
*/
|
|
156
|
+
export type DetailLine = string | Array<string | DetailLink>;
|
|
157
|
+
export interface WidgetHandle {
|
|
158
|
+
/** Run `update` (if any) and re-render now. */
|
|
159
|
+
refresh(): void;
|
|
160
|
+
/** Remove the widget. */
|
|
161
|
+
dispose(): void;
|
|
162
|
+
}
|
|
163
|
+
/** The last failure of a widget, kept for the sidebar and `/widgets`. */
|
|
164
|
+
export interface WidgetError {
|
|
165
|
+
phase: "update" | "render" | "detail" | "action";
|
|
166
|
+
message: string;
|
|
167
|
+
at: number;
|
|
168
|
+
}
|
|
169
|
+
interface RegistryEntry {
|
|
170
|
+
spec: WidgetSpec;
|
|
171
|
+
timer?: ReturnType<typeof setInterval>;
|
|
172
|
+
/** Unsubscribe functions for the pi.on handlers this widget added. */
|
|
173
|
+
offs: Array<() => void>;
|
|
174
|
+
/** An `update` is running; ticks are skipped until it settles or times out. */
|
|
175
|
+
inflight?: boolean;
|
|
176
|
+
lastUpdateAt?: number;
|
|
177
|
+
lastDurationMs?: number;
|
|
178
|
+
error?: WidgetError;
|
|
179
|
+
/** Cached output for widgets with `cacheKey`. */
|
|
180
|
+
cache?: {
|
|
181
|
+
key: string;
|
|
182
|
+
theme: unknown;
|
|
183
|
+
ctx: unknown;
|
|
184
|
+
width: number;
|
|
185
|
+
version: number;
|
|
186
|
+
view?: {
|
|
187
|
+
value: WidgetView | undefined;
|
|
188
|
+
};
|
|
189
|
+
lines?: {
|
|
190
|
+
value: string[];
|
|
191
|
+
};
|
|
192
|
+
};
|
|
193
|
+
/** Consecutive slow render/detail calls. */
|
|
194
|
+
strikes: number;
|
|
195
|
+
/** Set after too many slow calls; cleared by `/widgets enable`. */
|
|
196
|
+
suspended?: boolean;
|
|
197
|
+
lastRenderMs?: number;
|
|
198
|
+
}
|
|
199
|
+
/** The result of a tool call as a tool row spec sees it. Anything in it can be influenced from outside. */
|
|
200
|
+
export interface ToolRowResult {
|
|
201
|
+
content?: Array<{
|
|
202
|
+
type: string;
|
|
203
|
+
text?: string;
|
|
204
|
+
}>;
|
|
205
|
+
details?: any;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* How chassis draws the rows of a tool that belongs to another extension: one line per call
|
|
209
|
+
* ("<icon> <title> <describe>" on the left, `summarize` on the right) and, when the row is opened
|
|
210
|
+
* with ctrl+o, the lines `expand` returns.
|
|
211
|
+
*
|
|
212
|
+
* `args` and `result` come from the model and the tool, so treat them as untrusted and possibly
|
|
213
|
+
* partial: a call is drawn while its arguments are still streaming. Every string a spec returns is
|
|
214
|
+
* cleaned before it is drawn (escape sequences, control characters and bidi controls removed, line
|
|
215
|
+
* breaks turned into spaces; SGR colour from `theme` is kept), and a spec that throws makes chassis
|
|
216
|
+
* draw that call with the tool's own renderer instead.
|
|
217
|
+
*/
|
|
218
|
+
export interface ToolRowSpec {
|
|
219
|
+
/**
|
|
220
|
+
* Glyph in front of the row. A string is used as given in the Nerd Font set; in the plain set
|
|
221
|
+
* its private-use (Nerd Font) characters are dropped, so a string of ordinary characters such as
|
|
222
|
+
* "#" is kept in both and a bare Nerd Font glyph shows nothing. `{ nerd, plain }` gives one for
|
|
223
|
+
* each icon set. Omit for no glyph.
|
|
224
|
+
*/
|
|
225
|
+
icon?: IconLike;
|
|
226
|
+
/** Short verb or noun before the description, drawn in the text colour. May be empty. */
|
|
227
|
+
title: string;
|
|
228
|
+
/** What the call is about, from its arguments: a path, a query, an id. One line. */
|
|
229
|
+
describe: (args: any, cwd: string, theme: Theme) => string;
|
|
230
|
+
/** The right-aligned outcome of a finished call, for example "3 matches". `isError` is whether the tool reported an error. One line. */
|
|
231
|
+
summarize: (result: ToolRowResult, args: any, theme: Theme, isError: boolean) => string;
|
|
232
|
+
/** Body lines shown when the row is opened (ctrl+o or a click). More than 120 lines are cut. */
|
|
233
|
+
expand?: (result: ToolRowResult, args: any, theme: Theme) => string[];
|
|
234
|
+
}
|
|
235
|
+
/** Tool row specs by tool name. */
|
|
236
|
+
export type ToolRowSpecs = Record<string, ToolRowSpec>;
|
|
237
|
+
/** Options for `registerToolRows`. */
|
|
238
|
+
export interface ToolRowsOptions {
|
|
239
|
+
/**
|
|
240
|
+
* Names the registrant. Registering again with the same id replaces that registrant's earlier
|
|
241
|
+
* group, so a package that registers on every `session_start` (and again after /reload) never
|
|
242
|
+
* piles up groups. Without an id each call adds a group that lives until its remover is called.
|
|
243
|
+
*/
|
|
244
|
+
id?: string;
|
|
245
|
+
}
|
|
246
|
+
/** One registration: the specs of one `registerToolRows` call. */
|
|
247
|
+
export interface ToolRowGroup {
|
|
248
|
+
id?: string;
|
|
249
|
+
specs: Map<string, ToolRowSpec>;
|
|
250
|
+
}
|
|
251
|
+
/** Shared state between chassis and widget extensions. */
|
|
252
|
+
export interface Registry {
|
|
253
|
+
widgets: Map<string, RegistryEntry>;
|
|
254
|
+
/** Set by chassis while a session runs. */
|
|
255
|
+
ctx: ExtensionContext | undefined;
|
|
256
|
+
/** Set by chassis: asks the TUI to repaint. */
|
|
257
|
+
requestRender: () => void;
|
|
258
|
+
/** Subscribers to registry changes (chassis's renderers). */
|
|
259
|
+
listeners: Set<() => void>;
|
|
260
|
+
/** Bumped on every change, so renderers can cache. */
|
|
261
|
+
version: number;
|
|
262
|
+
/** Widget ids the user switched off (persisted, see `/widgets`). */
|
|
263
|
+
disabled: Set<string>;
|
|
264
|
+
/** Set by chassis's `installHost()`: the version of this API. Absent when chassis isn't loaded. */
|
|
265
|
+
apiVersion?: number;
|
|
266
|
+
/**
|
|
267
|
+
* Set by `installHost()`: what client.ts calls to register a widget with the host. `ctx` is
|
|
268
|
+
* optional: a caller inside a `session_start` handler passes the handler's context, so the
|
|
269
|
+
* widget's first `update` and its timer start even if chassis's own handler has not run yet.
|
|
270
|
+
*/
|
|
271
|
+
register?: (pi: ExtensionAPI, spec: WidgetSpec, ctx?: ExtensionContext) => WidgetHandle;
|
|
272
|
+
/** Set by `installHost()`: the version of the tool row API. Absent when the host predates it, so a client can feature-detect. */
|
|
273
|
+
toolRowsVersion?: number;
|
|
274
|
+
/** Set by `installHost()`: registers tool row specs and returns a function that removes them. */
|
|
275
|
+
registerToolRows?: (specs: ToolRowSpecs, options?: ToolRowsOptions) => () => void;
|
|
276
|
+
/** Registered tool row groups, oldest first. Absent until the first registration; read through `toolRowGroups`. */
|
|
277
|
+
toolRows?: ToolRowGroup[];
|
|
278
|
+
}
|
|
279
|
+
/** Bumped on a breaking change to the registry or WidgetSpec; client.ts checks it. */
|
|
280
|
+
export declare const API_VERSION = 1;
|
|
281
|
+
/** Version of the tool row API (`registerToolRows`). Bumped on a breaking change to it or to ToolRowSpec. */
|
|
282
|
+
export declare const TOOL_ROWS_VERSION = 1;
|
|
283
|
+
/** A registration made (through client.ts) before chassis had loaded. */
|
|
284
|
+
export interface PendingRegistration {
|
|
285
|
+
pi: ExtensionAPI;
|
|
286
|
+
spec: WidgetSpec;
|
|
287
|
+
/** Hands the real handle back to the client once the host has registered the widget. */
|
|
288
|
+
attach(handle: WidgetHandle): void;
|
|
289
|
+
}
|
|
290
|
+
/** Tool rows registered (through client.ts or the raw protocol) before chassis had loaded. */
|
|
291
|
+
export interface PendingToolRows {
|
|
292
|
+
specs: ToolRowSpecs;
|
|
293
|
+
/** The registrant's id, as in `ToolRowsOptions`. */
|
|
294
|
+
id?: string;
|
|
295
|
+
/** Hands the host's unregister function back to the registrant once the host has taken the rows. */
|
|
296
|
+
attach(unregister: () => void): void;
|
|
297
|
+
}
|
|
298
|
+
/** Register everything that client.ts queued before the host loaded. */
|
|
299
|
+
export declare function drainPending(): void;
|
|
300
|
+
/**
|
|
301
|
+
* Called once by chassis when it loads: announces the host (so client.ts registers straight into
|
|
302
|
+
* the registry) and takes over widgets that were queued before it loaded.
|
|
303
|
+
*/
|
|
304
|
+
export declare function installHost(): void;
|
|
305
|
+
/** Where the settings file is stored. PI_CHASSIS_STATE overrides it (used by tests). */
|
|
306
|
+
export declare function statePath(): string;
|
|
307
|
+
export declare function getRegistry(): Registry;
|
|
308
|
+
/** The registered tool row groups, oldest first (created on first use, so an older registry works). */
|
|
309
|
+
export declare function toolRowGroups(): ToolRowGroup[];
|
|
310
|
+
/** A spec that failed this many finished calls is no longer used until it is registered again. */
|
|
311
|
+
export declare const TOOL_ROW_FAILURE_LIMIT = 3;
|
|
312
|
+
/** Count a failure of `spec` on a finished call (not while arguments or output were still arriving). */
|
|
313
|
+
export declare function noteToolRowFailure(spec: ToolRowSpec): void;
|
|
314
|
+
/** Whether `spec` failed too many finished calls to be used for new ones. */
|
|
315
|
+
export declare function toolRowBroken(spec: ToolRowSpec): boolean;
|
|
316
|
+
/**
|
|
317
|
+
* Register chassis-styled rows for tools that belong to another extension, by tool name. Returns a
|
|
318
|
+
* function that removes them (calling it twice is harmless).
|
|
319
|
+
*
|
|
320
|
+
* The rows are looked up when a call is drawn, so it does not matter whether the extension that
|
|
321
|
+
* owns the tool, the one registering the rows or chassis loads first. A call already on screen keeps
|
|
322
|
+
* the renderer it was created with.
|
|
323
|
+
*
|
|
324
|
+
* chassis's own rows for pi's built-in tools (read, write, edit, bash, grep, find, ls) always win: a
|
|
325
|
+
* spec registered under one of those names is never used. For any other name the most recently
|
|
326
|
+
* registered spec wins, and removing it brings back the one before it. An entry is used only if
|
|
327
|
+
* it has a string `title`, function `describe` and `summarize`, and `expand` is a function when
|
|
328
|
+
* given; any other entry is skipped.
|
|
329
|
+
*
|
|
330
|
+
* Pass `{ id }` when the registrant can run more than once in a process (an extension that
|
|
331
|
+
* registers on every `session_start`, or is loaded again by /reload): registering again with the
|
|
332
|
+
* same id replaces its earlier group instead of adding another. Without an id, call the returned
|
|
333
|
+
* remover (for example on `session_shutdown`) before registering again.
|
|
334
|
+
*/
|
|
335
|
+
export declare function registerToolRows(specs: ToolRowSpecs, options?: ToolRowsOptions): () => void;
|
|
336
|
+
/** The registered row spec for a tool, newest registration first, or undefined. */
|
|
337
|
+
export declare function toolRowFor(toolName: string): ToolRowSpec | undefined;
|
|
338
|
+
/** Make every widget render again (an icon set change, say), dropping cached output. */
|
|
339
|
+
export declare function invalidateWidgets(): void;
|
|
340
|
+
/**
|
|
341
|
+
* Register (or replace) a widget. Returns a handle for on-demand refresh and removal.
|
|
342
|
+
*
|
|
343
|
+
* Pass `pi` so the widget's timers follow the session lifecycle: they start on session_start and
|
|
344
|
+
* stop on session_shutdown. The widget itself stays registered across /reload of chassis.
|
|
345
|
+
*
|
|
346
|
+
* Registering from inside a `session_start` handler (as a package that does not import chassis does)
|
|
347
|
+
* misses that session's own `session_start` event for the widget, so pass the handler's `ctx`.
|
|
348
|
+
*/
|
|
349
|
+
export declare function registerWidget(pi: ExtensionAPI, spec: WidgetSpec, ctx?: ExtensionContext): WidgetHandle;
|
|
350
|
+
/** Widgets for a slot, sorted by order then id. */
|
|
351
|
+
export declare function widgetsFor(slot: WidgetSlot): WidgetSpec[];
|
|
352
|
+
/** setStatus() keys claimed by registered widgets. */
|
|
353
|
+
export declare function claimedStatusKeys(): Set<string>;
|
|
354
|
+
/**
|
|
355
|
+
* Render a widget without letting it throw: a failure is recorded on the widget and returned as
|
|
356
|
+
* an "error" view. Returns undefined when the widget itself returns undefined (hidden).
|
|
357
|
+
* Widgets with `cacheKey` are only re-rendered when the key, width, theme, context or registry
|
|
358
|
+
* version changes; a widget that renders slowly several times in a row is suspended.
|
|
359
|
+
*/
|
|
360
|
+
export declare function renderWidget(spec: WidgetSpec, rc: WidgetRenderContext): WidgetView | undefined;
|
|
361
|
+
/** Detail lines of a widget; a failure is recorded and yields no lines. Cached like `renderWidget`. */
|
|
362
|
+
export declare function detailWidget(spec: WidgetSpec, rc: WidgetRenderContext): string[];
|
|
363
|
+
/** The last recorded failure of a widget, if any. */
|
|
364
|
+
export declare function widgetError(id: string): WidgetError | undefined;
|
|
365
|
+
/** Turn a widget off or on. The choice is saved and survives restarts. */
|
|
366
|
+
export declare function setWidgetDisabled(id: string, disabled: boolean): boolean;
|
|
367
|
+
/** Run a widget's update now, even outside its timer. */
|
|
368
|
+
export declare function refreshWidget(id: string): boolean;
|
|
369
|
+
export interface WidgetInfo {
|
|
370
|
+
id: string;
|
|
371
|
+
title: string;
|
|
372
|
+
slots: WidgetSlot[];
|
|
373
|
+
disabled: boolean;
|
|
374
|
+
refreshMs?: number;
|
|
375
|
+
lastUpdateAt?: number;
|
|
376
|
+
lastDurationMs?: number;
|
|
377
|
+
inflight: boolean;
|
|
378
|
+
suspended: boolean;
|
|
379
|
+
lastRenderMs?: number;
|
|
380
|
+
error?: WidgetError;
|
|
381
|
+
}
|
|
382
|
+
/** Snapshot of every registered widget, for `/widgets`. */
|
|
383
|
+
export declare function widgetInfo(): WidgetInfo[];
|
|
384
|
+
/** Plain-text table for `/widgets list`. */
|
|
385
|
+
export declare function formatWidgetList(list: WidgetInfo[], now?: number): string;
|
|
386
|
+
export interface WidgetActionInfo {
|
|
387
|
+
widgetId: string;
|
|
388
|
+
widgetTitle: string;
|
|
389
|
+
id: string;
|
|
390
|
+
label: string;
|
|
391
|
+
description?: string;
|
|
392
|
+
}
|
|
393
|
+
/** Palette actions of every enabled, non-suspended widget, in widget order. */
|
|
394
|
+
export declare function widgetActions(): WidgetActionInfo[];
|
|
395
|
+
/** Palette value for an action: ids are encoded, so they may contain any character. */
|
|
396
|
+
export declare function widgetActionValue(widgetId: string, actionId: string): string;
|
|
397
|
+
export declare function parseWidgetActionValue(value: string): {
|
|
398
|
+
widgetId: string;
|
|
399
|
+
actionId: string;
|
|
400
|
+
} | undefined;
|
|
401
|
+
/**
|
|
402
|
+
* Run a widget's `onDetailClick` for the clicked detail line. Resolves to undefined on success, or
|
|
403
|
+
* to a short message when it failed (also recorded on the widget as an "action" error).
|
|
404
|
+
*/
|
|
405
|
+
export declare function runWidgetClick(widgetId: string, index: number, ctx: ExtensionContext): Promise<string | undefined>;
|
|
406
|
+
/**
|
|
407
|
+
* Run a widget action. Resolves to undefined on success, or to a short message when the action
|
|
408
|
+
* is unknown or failed (the failure is also recorded on the widget).
|
|
409
|
+
*/
|
|
410
|
+
export declare function runWidgetAction(widgetId: string, actionId: string, ctx: ExtensionContext): Promise<string | undefined>;
|
|
411
|
+
export {};
|