@sigrun/tui 0.1.1 → 0.2.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/CHANGELOG.md +6 -0
- package/package.json +2 -2
- package/dist/actions.d.ts +0 -119
- package/dist/actions.js +0 -12
- package/dist/api.d.ts +0 -152
- package/dist/api.js +0 -189
- package/dist/blocks/braille.d.ts +0 -41
- package/dist/blocks/braille.js +0 -131
- package/dist/blocks/chart.d.ts +0 -20
- package/dist/blocks/chart.js +0 -397
- package/dist/blocks/collection/calendar.d.ts +0 -28
- package/dist/blocks/collection/calendar.js +0 -232
- package/dist/blocks/collection/card.d.ts +0 -36
- package/dist/blocks/collection/card.js +0 -128
- package/dist/blocks/collection/collection.d.ts +0 -9
- package/dist/blocks/collection/collection.js +0 -26
- package/dist/blocks/collection/grid.d.ts +0 -18
- package/dist/blocks/collection/grid.js +0 -72
- package/dist/blocks/collection/lanes.d.ts +0 -32
- package/dist/blocks/collection/lanes.js +0 -320
- package/dist/blocks/collection/list.d.ts +0 -30
- package/dist/blocks/collection/list.js +0 -273
- package/dist/blocks/collection/move.d.ts +0 -67
- package/dist/blocks/collection/move.js +0 -96
- package/dist/blocks/collection/shared.d.ts +0 -87
- package/dist/blocks/collection/shared.js +0 -177
- package/dist/blocks/collection/table.d.ts +0 -26
- package/dist/blocks/collection/table.js +0 -221
- package/dist/blocks/content.d.ts +0 -48
- package/dist/blocks/content.js +0 -253
- package/dist/blocks/context.d.ts +0 -96
- package/dist/blocks/context.js +0 -65
- package/dist/blocks/diff.d.ts +0 -21
- package/dist/blocks/diff.js +0 -25
- package/dist/blocks/ext-transport.d.ts +0 -70
- package/dist/blocks/ext-transport.js +0 -165
- package/dist/blocks/form/choice.d.ts +0 -54
- package/dist/blocks/form/choice.js +0 -175
- package/dist/blocks/form/fields.d.ts +0 -56
- package/dist/blocks/form/fields.js +0 -136
- package/dist/blocks/form/file.d.ts +0 -61
- package/dist/blocks/form/file.js +0 -121
- package/dist/blocks/form/form.d.ts +0 -53
- package/dist/blocks/form/form.js +0 -703
- package/dist/blocks/form/list.d.ts +0 -37
- package/dist/blocks/form/list.js +0 -70
- package/dist/blocks/form/values.d.ts +0 -20
- package/dist/blocks/form/values.js +0 -104
- package/dist/blocks/icons.d.ts +0 -14
- package/dist/blocks/icons.js +0 -74
- package/dist/blocks/image.d.ts +0 -39
- package/dist/blocks/image.js +0 -82
- package/dist/blocks/layout.d.ts +0 -31
- package/dist/blocks/layout.js +0 -155
- package/dist/blocks/log.d.ts +0 -24
- package/dist/blocks/log.js +0 -111
- package/dist/blocks/meter.d.ts +0 -16
- package/dist/blocks/meter.js +0 -50
- package/dist/blocks/page.d.ts +0 -54
- package/dist/blocks/page.js +0 -355
- package/dist/blocks/render.d.ts +0 -31
- package/dist/blocks/render.js +0 -145
- package/dist/blocks/surface-view.d.ts +0 -33
- package/dist/blocks/surface-view.js +0 -86
- package/dist/blocks/surface.d.ts +0 -75
- package/dist/blocks/surface.js +0 -468
- package/dist/blocks/tones.d.ts +0 -23
- package/dist/blocks/tones.js +0 -63
- package/dist/blocks/treeview.d.ts +0 -22
- package/dist/blocks/treeview.js +0 -121
- package/dist/blocks/width.d.ts +0 -32
- package/dist/blocks/width.js +0 -70
- package/dist/clipboard.d.ts +0 -20
- package/dist/clipboard.js +0 -19
- package/dist/editor-launch.d.ts +0 -34
- package/dist/editor-launch.js +0 -70
- package/dist/keymaps/emacs.d.ts +0 -18
- package/dist/keymaps/emacs.js +0 -172
- package/dist/keymaps/standard.d.ts +0 -17
- package/dist/keymaps/standard.js +0 -175
- package/dist/keymaps/types.d.ts +0 -43
- package/dist/keymaps/types.js +0 -28
- package/dist/keymaps/vim.d.ts +0 -48
- package/dist/keymaps/vim.js +0 -291
- package/dist/launch.d.ts +0 -149
- package/dist/launch.js +0 -446
- package/dist/sse.d.ts +0 -109
- package/dist/sse.js +0 -401
- package/dist/theme.d.ts +0 -51
- package/dist/theme.js +0 -119
- package/dist/ui/ambient.d.ts +0 -81
- package/dist/ui/ambient.js +0 -301
- package/dist/ui/app.d.ts +0 -245
- package/dist/ui/app.js +0 -1325
- package/dist/ui/composer.d.ts +0 -66
- package/dist/ui/composer.js +0 -125
- package/dist/ui/conversation-pane.d.ts +0 -123
- package/dist/ui/conversation-pane.js +0 -463
- package/dist/ui/help.d.ts +0 -15
- package/dist/ui/help.js +0 -80
- package/dist/ui/interactions.d.ts +0 -90
- package/dist/ui/interactions.js +0 -330
- package/dist/ui/picker.d.ts +0 -26
- package/dist/ui/picker.js +0 -130
- package/dist/ui/sidebar.d.ts +0 -99
- package/dist/ui/sidebar.js +0 -269
- package/dist/ui/status-bar.d.ts +0 -77
- package/dist/ui/status-bar.js +0 -146
package/dist/blocks/content.js
DELETED
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The simple content blocks (UI-blocks spec §5.3): `markdown`,
|
|
3
|
-
* `fields`, `stat`, `callout`, `diff`, `details`.
|
|
4
|
-
*
|
|
5
|
-
* - `markdown` rides pi-tui's `Markdown` (the same renderer as chat)
|
|
6
|
-
* with the TuiTheme-mapped markdown theme.
|
|
7
|
-
* - `fields` aligns labels by display width.
|
|
8
|
-
* - `stat` is `label: value unit` plus an optional caption line (its
|
|
9
|
-
* `sparkline` becomes a real drawing in Task 2).
|
|
10
|
-
* - `callout` leads with the tone marker (colour + the NO_COLOR
|
|
11
|
-
* fallback), its body renders as markdown, and its actions render as
|
|
12
|
-
* `[1] label` buttons with the confirm flow and the OSC 52 copy.
|
|
13
|
-
* - `diff` reuses the interaction diff renderer (blocks/diff.ts).
|
|
14
|
-
* - `details` is one collapsed JSON line (the TUI's existing details
|
|
15
|
-
* primitive; a later task may add an expandable pretty view).
|
|
16
|
-
*/
|
|
17
|
-
import { Markdown, hyperlink, getCapabilities, visibleWidth } from "@earendil-works/pi-tui";
|
|
18
|
-
import { formatValue } from "@sigrun/shared/blocks";
|
|
19
|
-
import { bindRaw, bindText, bindTone } from "./context.js";
|
|
20
|
-
import { truncate } from "./width.js";
|
|
21
|
-
import { iconGlyph } from "./icons.js";
|
|
22
|
-
import { toneFg, toneMarker } from "./tones.js";
|
|
23
|
-
import { blockDiff, diffLines } from "./diff.js";
|
|
24
|
-
import { Lines } from "./layout.js";
|
|
25
|
-
import { copyToTerminal } from "../clipboard.js";
|
|
26
|
-
/** The markdown theme rides the TuiTheme's token colours. */
|
|
27
|
-
function markdownTheme(theme) {
|
|
28
|
-
return {
|
|
29
|
-
heading: (text) => theme.bold(theme.fg("accent")(text)),
|
|
30
|
-
link: theme.fg("accent"),
|
|
31
|
-
linkUrl: theme.dim,
|
|
32
|
-
code: theme.fg("code"),
|
|
33
|
-
codeBlock: theme.fg("code"),
|
|
34
|
-
codeBlockBorder: theme.fg("border"),
|
|
35
|
-
quote: theme.italic,
|
|
36
|
-
quoteBorder: theme.fg("border"),
|
|
37
|
-
hr: theme.fg("border"),
|
|
38
|
-
listBullet: theme.fg("accent"),
|
|
39
|
-
bold: theme.bold,
|
|
40
|
-
italic: theme.italic,
|
|
41
|
-
strikethrough: (text) => text,
|
|
42
|
-
underline: (text) => text,
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
/** `markdown`: the same renderer as chat. */
|
|
46
|
-
export function renderMarkdown(block, ctx) {
|
|
47
|
-
return new Markdown(bindText(block.text, ctx), 0, 0, markdownTheme(ctx.theme));
|
|
48
|
-
}
|
|
49
|
-
/** Read `fields.rows` into label/value/tone/icon rows (each slot binds). */
|
|
50
|
-
function fieldRows(block, ctx) {
|
|
51
|
-
const raw = bindRaw(block.rows, ctx);
|
|
52
|
-
if (!Array.isArray(raw))
|
|
53
|
-
return [];
|
|
54
|
-
const rows = [];
|
|
55
|
-
for (const entry of raw) {
|
|
56
|
-
if (entry === null || typeof entry !== "object" || Array.isArray(entry))
|
|
57
|
-
continue;
|
|
58
|
-
const record = entry;
|
|
59
|
-
const label = bindText(record.label, ctx);
|
|
60
|
-
const value = formatValue((bindRaw(record.value, ctx) ?? null), undefined, ctx.locale);
|
|
61
|
-
const tone = bindRaw(record.tone, ctx);
|
|
62
|
-
const icon = bindRaw(record.icon, ctx);
|
|
63
|
-
rows.push({
|
|
64
|
-
label,
|
|
65
|
-
value,
|
|
66
|
-
tone: tone === undefined ? undefined : bindTone(tone, ctx),
|
|
67
|
-
icon: icon === undefined ? undefined : icon,
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
return rows;
|
|
71
|
-
}
|
|
72
|
-
/** `fields`: `label: value` rows, labels aligned by display width. */
|
|
73
|
-
export function renderFields(block, ctx) {
|
|
74
|
-
return new Lines(() => {
|
|
75
|
-
const rows = fieldRows(block, ctx);
|
|
76
|
-
const labelWidth = Math.max(0, ...rows.map((row) => visibleWidth(row.label)));
|
|
77
|
-
return rows.map((row) => {
|
|
78
|
-
const padded = row.label + " ".repeat(Math.max(0, labelWidth - visibleWidth(row.label)));
|
|
79
|
-
const text = row.tone === undefined ? row.value : toneFg(ctx.theme, row.tone)(row.value);
|
|
80
|
-
const glyph = row.icon === undefined ? "" : `${iconGlyph(row.icon, !ctx.unicode)} `;
|
|
81
|
-
return `${ctx.theme.dim(padded)} ${glyph}${text}`;
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
/** `stat`: `label: value unit` plus an optional caption line. */
|
|
86
|
-
export function renderStat(block, ctx) {
|
|
87
|
-
return new Lines((width) => {
|
|
88
|
-
const value = formatValue((bindRaw(block.value, ctx) ?? null), block.format, ctx.locale);
|
|
89
|
-
const unit = bindText(block.unit, ctx);
|
|
90
|
-
const text = unit === "" ? value : `${value} ${unit}`;
|
|
91
|
-
const tone = bindRaw(block.tone, ctx);
|
|
92
|
-
const toneName = tone === undefined ? undefined : bindTone(tone, ctx);
|
|
93
|
-
const icon = bindRaw(block.icon, ctx);
|
|
94
|
-
const label = bindText(block.label, ctx);
|
|
95
|
-
const head = typeof icon === "string" ? `${iconGlyph(icon, !ctx.unicode)} ${label}` : label;
|
|
96
|
-
const painted = toneName === undefined ? text : toneFg(ctx.theme, toneName)(text);
|
|
97
|
-
const out = [truncate(`${ctx.theme.dim(`${head}:`)} ${painted}`, width)];
|
|
98
|
-
const caption = bindText(block.caption, ctx);
|
|
99
|
-
if (caption !== "")
|
|
100
|
-
out.push(ctx.theme.dim(caption));
|
|
101
|
-
return out;
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
/** `details`: one collapsed JSON line. */
|
|
105
|
-
export function renderDetails(block) {
|
|
106
|
-
return new Lines(() => [JSON.stringify(block.value)]);
|
|
107
|
-
}
|
|
108
|
-
/** `diff`: the interaction diff renderer (blocks/diff.ts). */
|
|
109
|
-
export function renderDiff(block) {
|
|
110
|
-
return new Lines(() => diffLines(blockDiff(block)));
|
|
111
|
-
}
|
|
112
|
-
/** The actions a block offers: read access keeps the view-only kinds
|
|
113
|
-
* (§6.5 — copy/open/navigate never edit or answer; twin of the webui's
|
|
114
|
-
* `isViewOnly`). */
|
|
115
|
-
export function visibleActions(actions, ctx) {
|
|
116
|
-
if (ctx.access === "read") {
|
|
117
|
-
return (actions ?? []).filter((button) => button.action.type === "copy" ||
|
|
118
|
-
button.action.type === "open" ||
|
|
119
|
-
button.action.type === "navigate");
|
|
120
|
-
}
|
|
121
|
-
return [...(actions ?? [])];
|
|
122
|
-
}
|
|
123
|
-
/** The URL schemes an `open` action may carry (§15: https/http/mailto). */
|
|
124
|
-
const OPEN_SCHEMES = new Set(["https", "http", "mailto"]);
|
|
125
|
-
/** Clean an `open` URL the way a browser would, then allowlist the scheme. */
|
|
126
|
-
function openUrl(url) {
|
|
127
|
-
const cleaned = url
|
|
128
|
-
.replace(/[\t\n\r]/g, "")
|
|
129
|
-
.replace(/[\u0000-\u0020]+$/, "")
|
|
130
|
-
.replace(/^[\u0000-\u0020]+/, "");
|
|
131
|
-
const scheme = /^([a-zA-Z][a-zA-Z0-9+.-]*):/.exec(cleaned)?.[1];
|
|
132
|
-
if (scheme === undefined)
|
|
133
|
-
return "";
|
|
134
|
-
return OPEN_SCHEMES.has(scheme.toLowerCase()) ? cleaned : "";
|
|
135
|
-
}
|
|
136
|
-
/** `open`: channel-local (§6.2 view-only) — print the URL as an OSC 8
|
|
137
|
-
* hyperlink when the terminal supports them, else as plain text. */
|
|
138
|
-
function runOpen(button, action, ctx) {
|
|
139
|
-
const url = openUrl(action.url);
|
|
140
|
-
if (url === "")
|
|
141
|
-
return; // disallowed scheme: nothing opens, nothing dispatches
|
|
142
|
-
const terminal = ctx.terminal ?? { write: (data) => process.stdout.write(data) };
|
|
143
|
-
const label = bindText(button.label, ctx);
|
|
144
|
-
const shown = getCapabilities().hyperlinks
|
|
145
|
-
? hyperlink(label, url)
|
|
146
|
-
: `${label} — ${url}`;
|
|
147
|
-
terminal.write(`${shown}\n`);
|
|
148
|
-
}
|
|
149
|
-
/** Run a button's action (copy/open resolve locally; the rest dispatch). */
|
|
150
|
-
function runAction(button, ctx) {
|
|
151
|
-
const action = button.action;
|
|
152
|
-
if (action.type === "copy") {
|
|
153
|
-
const raw = bindRaw(action.text, ctx);
|
|
154
|
-
const text = typeof raw === "string" ? raw : "";
|
|
155
|
-
copyToTerminal(ctx.terminal ?? { write: (data) => process.stdout.write(data) }, text);
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
if (action.type === "open") {
|
|
159
|
-
runOpen(button, action, ctx);
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
ctx.dispatch(action, null);
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* `callout`: tone-marked title, wrapped markdown body, action buttons.
|
|
166
|
-
* `handleInput` picks a button by digit; a `confirm` action gates its
|
|
167
|
-
* dispatch behind a `y/N` prompt (anything but `y`/`Y` cancels and
|
|
168
|
-
* dispatches nothing).
|
|
169
|
-
*/
|
|
170
|
-
export class CalloutComponent {
|
|
171
|
-
#block;
|
|
172
|
-
#ctx;
|
|
173
|
-
#confirm;
|
|
174
|
-
constructor(block, ctx) {
|
|
175
|
-
this.#block = block;
|
|
176
|
-
this.#ctx = ctx;
|
|
177
|
-
}
|
|
178
|
-
render(width) {
|
|
179
|
-
const theme = this.#ctx.theme;
|
|
180
|
-
const tone = bindTone(this.#block.tone, this.#ctx);
|
|
181
|
-
const title = bindText(this.#block.title, this.#ctx);
|
|
182
|
-
const lines = [
|
|
183
|
-
truncate(`${toneFg(theme, tone)(toneMarker(tone, !this.#ctx.unicode))} ${title}`, width),
|
|
184
|
-
];
|
|
185
|
-
const body = bindText(this.#block.body, this.#ctx);
|
|
186
|
-
if (body !== "") {
|
|
187
|
-
// The body is markdown (§5.3); ride the same renderer as chat.
|
|
188
|
-
lines.push(...new Markdown(body, 0, 0, markdownTheme(theme)).render(width));
|
|
189
|
-
}
|
|
190
|
-
if (this.#confirm !== undefined) {
|
|
191
|
-
const { confirm, action } = this.#confirm;
|
|
192
|
-
const label = confirm.confirmLabel ??
|
|
193
|
-
(action.type === "restart" ? "Restart" : "Confirm");
|
|
194
|
-
lines.push("");
|
|
195
|
-
lines.push(truncate(`${toneFg(theme, confirm.tone ?? "warn")(toneMarker(confirm.tone ?? "warn", !this.#ctx.unicode))} ${confirm.title}`, width));
|
|
196
|
-
if (confirm.body !== undefined && confirm.body !== "") {
|
|
197
|
-
lines.push(...new Markdown(confirm.body, 0, 0, markdownTheme(theme)).render(width));
|
|
198
|
-
}
|
|
199
|
-
lines.push(truncate(`${label}? y/N`, width));
|
|
200
|
-
return lines;
|
|
201
|
-
}
|
|
202
|
-
const actions = visibleActions(this.#block.actions, this.#ctx);
|
|
203
|
-
if (actions.length > 0) {
|
|
204
|
-
lines.push("");
|
|
205
|
-
lines.push(truncate(actions
|
|
206
|
-
.map((button, index) => `[${index + 1}] ${bindText(button.label, this.#ctx)}`)
|
|
207
|
-
.join(" "), width));
|
|
208
|
-
}
|
|
209
|
-
return lines;
|
|
210
|
-
}
|
|
211
|
-
handleInput(data) {
|
|
212
|
-
if (this.#confirm !== undefined) {
|
|
213
|
-
const { action } = this.#confirm;
|
|
214
|
-
this.#confirm = undefined;
|
|
215
|
-
if (data === "y" || data === "Y")
|
|
216
|
-
this.#ctx.dispatch(action, null);
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
const actions = visibleActions(this.#block.actions, this.#ctx);
|
|
220
|
-
const button = actions[Number(data) - 1];
|
|
221
|
-
if (button === undefined)
|
|
222
|
-
return;
|
|
223
|
-
const action = button.action;
|
|
224
|
-
if ((action.type === "submit" || action.type === "restart") &&
|
|
225
|
-
action.confirm !== undefined) {
|
|
226
|
-
this.#confirm = { confirm: action.confirm, action };
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
runAction(button, this.#ctx);
|
|
230
|
-
}
|
|
231
|
-
invalidate() {
|
|
232
|
-
// Stateless render; the confirm gate is the only mutable state.
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
/** Render a Task-1 content block by type; the caller routes unknowns. */
|
|
236
|
-
export function renderContent(block, ctx) {
|
|
237
|
-
switch (block.type) {
|
|
238
|
-
case "markdown":
|
|
239
|
-
return renderMarkdown(block, ctx);
|
|
240
|
-
case "fields":
|
|
241
|
-
return renderFields(block, ctx);
|
|
242
|
-
case "stat":
|
|
243
|
-
return renderStat(block, ctx);
|
|
244
|
-
case "details":
|
|
245
|
-
return renderDetails(block);
|
|
246
|
-
case "diff":
|
|
247
|
-
return renderDiff(block);
|
|
248
|
-
case "callout":
|
|
249
|
-
return new CalloutComponent(block, ctx);
|
|
250
|
-
default:
|
|
251
|
-
return undefined;
|
|
252
|
-
}
|
|
253
|
-
}
|
package/dist/blocks/context.d.ts
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The block render context (UI-blocks U2 Task 1): everything a block
|
|
3
|
-
* component reads while rendering — the surface's data, the theme, the
|
|
4
|
-
* locale, the principal's access, the dispatch seam and the channel's
|
|
5
|
-
* view state — plus the binding/text resolution helpers every block
|
|
6
|
-
* renderer shares.
|
|
7
|
-
*
|
|
8
|
-
* `view` is the channel-owned view-state branch (spec §6.2): sort,
|
|
9
|
-
* filter, expansion, selection. Task 5 (forms) widened the seam with
|
|
10
|
-
* `setView` (the `/view/` writer a live form bound under `/view/` calls
|
|
11
|
-
* so sibling blocks reading `/view/...` bindings update — mirroring
|
|
12
|
-
* U1's `SurfaceActionsCtx.setView`) and `serverErrors` (a rejected
|
|
13
|
-
* action's `{error: {field}}` surfaces under that field, §5.6).
|
|
14
|
-
* `bindRaw` routes `/view/`-rooted pointers to `view.values` so EVERY
|
|
15
|
-
* block (not only the writing form) reads the branch.
|
|
16
|
-
*/
|
|
17
|
-
import type { Action, Binding, JsonObject, JsonValue, Tone } from "@sigrun/shared/blocks";
|
|
18
|
-
import type { TuiTheme } from "../theme.js";
|
|
19
|
-
/** The channel-owned view state a render reads (spec §6.2). */
|
|
20
|
-
export interface ViewState {
|
|
21
|
-
/** Values written by view-only actions (live forms bound `/view/`). */
|
|
22
|
-
values: JsonObject;
|
|
23
|
-
}
|
|
24
|
-
/** The render context {@link renderBlock} threads to every component. */
|
|
25
|
-
export interface BlockCtx {
|
|
26
|
-
/** The surface's confirmed data model (bindings resolve against it). */
|
|
27
|
-
data: JsonObject;
|
|
28
|
-
/** The current item, inside a collection's card template (`./` pointers). */
|
|
29
|
-
item?: JsonValue;
|
|
30
|
-
theme: TuiTheme;
|
|
31
|
-
locale: string;
|
|
32
|
-
/**
|
|
33
|
-
* Time zone for `Intl` time formats (chart axes, log timestamps);
|
|
34
|
-
* absent means the runtime's local zone. Tests pass `UTC` for
|
|
35
|
-
* byte-stable output (`formatValue`'s fourth argument).
|
|
36
|
-
*/
|
|
37
|
-
timeZone?: string;
|
|
38
|
-
access: "read" | "write";
|
|
39
|
-
/**
|
|
40
|
-
* Whether the terminal renders Unicode glyphs (spec §10.2): false
|
|
41
|
-
* selects the ASCII fallbacks — `icons.ts` glyphs and `tones.ts`
|
|
42
|
-
* markers — so an ASCII terminal never shows mojibake.
|
|
43
|
-
*/
|
|
44
|
-
unicode: boolean;
|
|
45
|
-
/** Route an action to the surface (view-only ones never reach this). */
|
|
46
|
-
dispatch(action: Action, payload: JsonValue): void;
|
|
47
|
-
view: ViewState;
|
|
48
|
-
/**
|
|
49
|
-
* Write the channel-owned `/view/` branch (spec §6.2): `path` is a
|
|
50
|
-
* JSON pointer under the branch (no leading `/view/` — the writer
|
|
51
|
-
* roots at the branch, as U1's `setView` does). A live form bound
|
|
52
|
-
* under `/view/` calls this after its 300 ms debounce; the write
|
|
53
|
-
* never reaches the server.
|
|
54
|
-
*/
|
|
55
|
-
setView?(path: string, value: JsonValue): void;
|
|
56
|
-
/**
|
|
57
|
-
* Server-side field errors, keyed by field name (spec §5.6: a
|
|
58
|
-
* rejected action's `{error: {field}}` surfaces under that field).
|
|
59
|
-
*/
|
|
60
|
-
readonly serverErrors?: Readonly<Record<string, string>>;
|
|
61
|
-
/** The host's edit-in-$EDITOR seam (longtext with `syntax: code`;
|
|
62
|
-
* spec §5.6). The form calls it with the current text; it returns
|
|
63
|
-
* the new text (the TUI suspends while the editor owns the
|
|
64
|
-
* terminal, as the composer's vim flow does). */
|
|
65
|
-
openEditor?(text: string): {
|
|
66
|
-
ok: true;
|
|
67
|
-
text: string;
|
|
68
|
-
} | {
|
|
69
|
-
ok: false;
|
|
70
|
-
reason: string;
|
|
71
|
-
};
|
|
72
|
-
/** The surface's upload seam (§7.2): a file field hands the bytes
|
|
73
|
-
* here after dispatching `onUpload`. Optional — without it the
|
|
74
|
-
* bytes ride the dispatch payload as base64. */
|
|
75
|
-
uploadBytes?(field: string, name: string, bytes: Uint8Array): void;
|
|
76
|
-
/** The terminal copy writes to (OSC 52); defaults to process.stdout. */
|
|
77
|
-
terminal?: {
|
|
78
|
-
write(data: string): void;
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
/** Is `value` a binding (spec §4.2: `{ $: pointer }`)? */
|
|
82
|
-
export declare function isBinding(value: unknown): value is Binding;
|
|
83
|
-
/** Resolve a bindable of any shape to its raw JSON value (untyped).
|
|
84
|
-
* A `/view/`-rooted pointer resolves against the channel-owned view
|
|
85
|
-
* branch (spec §6.2 — the sibling-read half of the setView seam: a
|
|
86
|
-
* block bound `{$: "/view/..."}` sees what a view-bound live form
|
|
87
|
-
* wrote); everything else resolves against ctx.data. */
|
|
88
|
-
export declare function bindRaw(value: unknown, ctx: BlockCtx): JsonValue | undefined;
|
|
89
|
-
/** Resolve a bindable to text: empty string for missing or non-string values. */
|
|
90
|
-
export declare function bindText(value: unknown, ctx: BlockCtx): string;
|
|
91
|
-
/** Resolve a bindable tone: `neutral` when absent or not a tone name. */
|
|
92
|
-
export declare function bindTone(value: unknown, ctx: BlockCtx): Tone;
|
|
93
|
-
/** True when a block's `visibleAt` hides it at the rendered width class. */
|
|
94
|
-
export declare function hiddenAtCompact(block: {
|
|
95
|
-
readonly visibleAt?: string;
|
|
96
|
-
}, width: number): boolean;
|
package/dist/blocks/context.js
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The block render context (UI-blocks U2 Task 1): everything a block
|
|
3
|
-
* component reads while rendering — the surface's data, the theme, the
|
|
4
|
-
* locale, the principal's access, the dispatch seam and the channel's
|
|
5
|
-
* view state — plus the binding/text resolution helpers every block
|
|
6
|
-
* renderer shares.
|
|
7
|
-
*
|
|
8
|
-
* `view` is the channel-owned view-state branch (spec §6.2): sort,
|
|
9
|
-
* filter, expansion, selection. Task 5 (forms) widened the seam with
|
|
10
|
-
* `setView` (the `/view/` writer a live form bound under `/view/` calls
|
|
11
|
-
* so sibling blocks reading `/view/...` bindings update — mirroring
|
|
12
|
-
* U1's `SurfaceActionsCtx.setView`) and `serverErrors` (a rejected
|
|
13
|
-
* action's `{error: {field}}` surfaces under that field, §5.6).
|
|
14
|
-
* `bindRaw` routes `/view/`-rooted pointers to `view.values` so EVERY
|
|
15
|
-
* block (not only the writing form) reads the branch.
|
|
16
|
-
*/
|
|
17
|
-
import { resolvePointer } from "@sigrun/shared/blocks";
|
|
18
|
-
/** Is `value` a binding (spec §4.2: `{ $: pointer }`)? */
|
|
19
|
-
export function isBinding(value) {
|
|
20
|
-
return (typeof value === "object" &&
|
|
21
|
-
value !== null &&
|
|
22
|
-
typeof value.$ === "string");
|
|
23
|
-
}
|
|
24
|
-
/** The tone names (the `bindTone` guard's set). */
|
|
25
|
-
const TONES = new Set([
|
|
26
|
-
"neutral",
|
|
27
|
-
"accent",
|
|
28
|
-
"good",
|
|
29
|
-
"warn",
|
|
30
|
-
"bad",
|
|
31
|
-
"info",
|
|
32
|
-
]);
|
|
33
|
-
/** Resolve a bindable of any shape to its raw JSON value (untyped).
|
|
34
|
-
* A `/view/`-rooted pointer resolves against the channel-owned view
|
|
35
|
-
* branch (spec §6.2 — the sibling-read half of the setView seam: a
|
|
36
|
-
* block bound `{$: "/view/..."}` sees what a view-bound live form
|
|
37
|
-
* wrote); everything else resolves against ctx.data. */
|
|
38
|
-
export function bindRaw(value, ctx) {
|
|
39
|
-
if (!isBinding(value))
|
|
40
|
-
return value;
|
|
41
|
-
if (value.$.startsWith("/view/") || value.$ === "/view") {
|
|
42
|
-
const pointer = value.$.replace(/^\/view\/?/, "/");
|
|
43
|
-
const resolved = resolvePointer(ctx.view.values, pointer);
|
|
44
|
-
if (resolved !== undefined)
|
|
45
|
-
return resolved;
|
|
46
|
-
return undefined;
|
|
47
|
-
}
|
|
48
|
-
return resolvePointer(ctx.data, value.$, ctx.item);
|
|
49
|
-
}
|
|
50
|
-
/** Resolve a bindable to text: empty string for missing or non-string values. */
|
|
51
|
-
export function bindText(value, ctx) {
|
|
52
|
-
const resolved = bindRaw(value, ctx);
|
|
53
|
-
return typeof resolved === "string" ? resolved : "";
|
|
54
|
-
}
|
|
55
|
-
/** Resolve a bindable tone: `neutral` when absent or not a tone name. */
|
|
56
|
-
export function bindTone(value, ctx) {
|
|
57
|
-
const resolved = bindRaw(value, ctx);
|
|
58
|
-
return TONES.has(typeof resolved === "string" ? resolved : "")
|
|
59
|
-
? resolved
|
|
60
|
-
: "neutral";
|
|
61
|
-
}
|
|
62
|
-
/** True when a block's `visibleAt` hides it at the rendered width class. */
|
|
63
|
-
export function hiddenAtCompact(block, width) {
|
|
64
|
-
return block.visibleAt === "atLeast:regular" && width < 80;
|
|
65
|
-
}
|
package/dist/blocks/diff.d.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The interaction diff renderer, extracted (UI-blocks U2 Task 1): the
|
|
3
|
-
* prompt strip's before/after lines — `[diff] path` then `- `/`+ `
|
|
4
|
-
* prefixed lines — reused VERBATIM by the `diff` block so chat diffs
|
|
5
|
-
* and interaction diffs render identically.
|
|
6
|
-
*
|
|
7
|
-
* The extraction is byte-identical to the lines
|
|
8
|
-
* `InteractionPrompter.render` produced inline (tui/src/ui/interactions.ts);
|
|
9
|
-
* that component now calls {@link diffLines}.
|
|
10
|
-
*/
|
|
11
|
-
import type { DiffBlock } from "@sigrun/shared/blocks";
|
|
12
|
-
/** The shape the interaction seam's diff primitive carries. */
|
|
13
|
-
export interface InteractionDiff {
|
|
14
|
-
before: string;
|
|
15
|
-
after: string;
|
|
16
|
-
path?: string;
|
|
17
|
-
}
|
|
18
|
-
/** Render a diff as `[diff] path` plus `- `/`+ ` lines. */
|
|
19
|
-
export declare function diffLines(diff: InteractionDiff): string[];
|
|
20
|
-
/** The `diff` block's diff (same wire fields). */
|
|
21
|
-
export declare function blockDiff(block: DiffBlock): InteractionDiff;
|
package/dist/blocks/diff.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The interaction diff renderer, extracted (UI-blocks U2 Task 1): the
|
|
3
|
-
* prompt strip's before/after lines — `[diff] path` then `- `/`+ `
|
|
4
|
-
* prefixed lines — reused VERBATIM by the `diff` block so chat diffs
|
|
5
|
-
* and interaction diffs render identically.
|
|
6
|
-
*
|
|
7
|
-
* The extraction is byte-identical to the lines
|
|
8
|
-
* `InteractionPrompter.render` produced inline (tui/src/ui/interactions.ts);
|
|
9
|
-
* that component now calls {@link diffLines}.
|
|
10
|
-
*/
|
|
11
|
-
/** Render a diff as `[diff] path` plus `- `/`+ ` lines. */
|
|
12
|
-
export function diffLines(diff) {
|
|
13
|
-
const lines = [
|
|
14
|
-
diff.path === undefined ? "[diff]" : `[diff] ${diff.path}`,
|
|
15
|
-
];
|
|
16
|
-
for (const line of diff.before.split("\n"))
|
|
17
|
-
lines.push(`- ${line}`);
|
|
18
|
-
for (const line of diff.after.split("\n"))
|
|
19
|
-
lines.push(`+ ${line}`);
|
|
20
|
-
return lines;
|
|
21
|
-
}
|
|
22
|
-
/** The `diff` block's diff (same wire fields). */
|
|
23
|
-
export function blockDiff(block) {
|
|
24
|
-
return { before: block.before, after: block.after, path: block.path };
|
|
25
|
-
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The TUI's extension-surface transport (UI-blocks U3 Task 5): implements
|
|
3
|
-
* the shared `SurfaceTransport` contract over the U3 routes (spec §7.2)
|
|
4
|
-
* as the TUI's remote client. One transport = one surface instance
|
|
5
|
-
* (slug + id + params); the wire `k` (hashed instance key) keys the
|
|
6
|
-
* change-event routing in {@link ExtSurfaceHub}.
|
|
7
|
-
*
|
|
8
|
-
* Like the webui twin, every fetch carries `X-Sigrun-Stream` once the
|
|
9
|
-
* launcher hands the stream id in (the watcher entry's stream);
|
|
10
|
-
* `image()` rejects until U7 ships the route. The channel owns
|
|
11
|
-
* refreshMs cadence, the keepalive, and visibility gating (U2).
|
|
12
|
-
*/
|
|
13
|
-
import type { JsonObject, SurfaceTransport } from "@sigrun/shared/blocks";
|
|
14
|
-
export interface ExtSurfaceTransportOptions {
|
|
15
|
-
/** The extension slug (the `/v1/ext/<slug>/` prefix segment). */
|
|
16
|
-
readonly slug: string;
|
|
17
|
-
/** The surface id within the extension. */
|
|
18
|
-
readonly id: string;
|
|
19
|
-
/** The instance params; absent → `{}` (the route's default). */
|
|
20
|
-
readonly params?: JsonObject;
|
|
21
|
-
/** The current `/v1/events` stream id (the watcher entry's stream). */
|
|
22
|
-
readonly streamId?: string;
|
|
23
|
-
/** The server's origin (the launcher that constructs the client owns it). */
|
|
24
|
-
readonly baseUrl: string;
|
|
25
|
-
readonly user?: string;
|
|
26
|
-
readonly token?: string;
|
|
27
|
-
readonly fetch?: typeof globalThis.fetch;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* The TUI's transport handle (U3 Task 5 fix round): the `SurfaceTransport`
|
|
31
|
-
* plus `setStreamId` — a `/v1/events` reconnect hands the OPEN view the
|
|
32
|
-
* new stream id without re-creating the transport (the next fetch
|
|
33
|
-
* carries it, re-registering the watcher entry, spec §7.3).
|
|
34
|
-
*/
|
|
35
|
-
export interface ExtSurfaceTransportHandle {
|
|
36
|
-
readonly transport: SurfaceTransport;
|
|
37
|
-
/** Update the watcher stream id (a reconnect's hello); subsequent
|
|
38
|
-
* fetches carry the new id. */
|
|
39
|
-
setStreamId(streamId: string | undefined): void;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* The wire `k` for one surface instance (spec §7.3), Node flavor:
|
|
43
|
-
* `sha256(slug + "\0" + id + "\0" + key)` hex. The TUI's transport
|
|
44
|
-
* computes it synchronously (the WebCrypto twin in `@sigrun/shared/
|
|
45
|
-
* blocks` is async — DOM-only).
|
|
46
|
-
*/
|
|
47
|
-
export declare function surfaceKeyHash(slug: string, id: string, key: string): string;
|
|
48
|
-
/** The instance key for one transport's params (the default rule). */
|
|
49
|
-
export declare function transportKey(options: ExtSurfaceTransportOptions): string;
|
|
50
|
-
/** Create the TUI's extension-surface transport. */
|
|
51
|
-
export declare function createExtSurfaceTransport(options: ExtSurfaceTransportOptions): ExtSurfaceTransportHandle;
|
|
52
|
-
/**
|
|
53
|
-
* The change-event router (the launcher's dispatch seam): `attach`
|
|
54
|
-
* creates a transport whose `onChanged` subscribes into the hub under
|
|
55
|
-
* the instance's (slug, id, k); `dispatch` fans a `surface.changed`
|
|
56
|
-
* event out to the matching subscriptions only.
|
|
57
|
-
*/
|
|
58
|
-
export declare class ExtSurfaceHub {
|
|
59
|
-
#private;
|
|
60
|
-
/** Create a transport whose `onChanged` subscribes into this hub. */
|
|
61
|
-
attach(options: ExtSurfaceTransportOptions, keyHash: string): ExtSurfaceTransportHandle;
|
|
62
|
-
/** Fire every subscription matching the event's (slug, id, k). */
|
|
63
|
-
dispatch(event: {
|
|
64
|
-
readonly slug: string;
|
|
65
|
-
readonly id: string;
|
|
66
|
-
readonly k: string;
|
|
67
|
-
readonly rev: number;
|
|
68
|
-
readonly treeRev: number;
|
|
69
|
-
}): void;
|
|
70
|
-
}
|