@hanzo/ui 8.14.0 → 8.14.2

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.
Files changed (53) hide show
  1. package/dist/agents/Board.cjs +119 -0
  2. package/dist/agents/Board.d.ts +98 -0
  3. package/dist/agents/Board.d.ts.map +1 -0
  4. package/dist/agents/Board.js +115 -0
  5. package/dist/agents/Board.js.map +1 -0
  6. package/dist/agents/Pane.cjs +74 -0
  7. package/dist/agents/Pane.d.ts +84 -0
  8. package/dist/agents/Pane.d.ts.map +1 -0
  9. package/dist/agents/Pane.js +68 -0
  10. package/dist/agents/Pane.js.map +1 -0
  11. package/dist/agents/Progress.cjs +130 -0
  12. package/dist/agents/Progress.d.ts +67 -0
  13. package/dist/agents/Progress.d.ts.map +1 -0
  14. package/dist/agents/Progress.js +127 -0
  15. package/dist/agents/Progress.js.map +1 -0
  16. package/dist/agents/Screen.cjs +91 -0
  17. package/dist/agents/Screen.d.ts +53 -0
  18. package/dist/agents/Screen.d.ts.map +1 -0
  19. package/dist/agents/Screen.js +89 -0
  20. package/dist/agents/Screen.js.map +1 -0
  21. package/dist/agents/Steer.cjs +42 -0
  22. package/dist/agents/Steer.d.ts +54 -0
  23. package/dist/agents/Steer.d.ts.map +1 -0
  24. package/dist/agents/Steer.js +39 -0
  25. package/dist/agents/Steer.js.map +1 -0
  26. package/dist/agents/Transcript.cjs +59 -0
  27. package/dist/agents/Transcript.d.ts +50 -0
  28. package/dist/agents/Transcript.d.ts.map +1 -0
  29. package/dist/agents/Transcript.js +56 -0
  30. package/dist/agents/Transcript.js.map +1 -0
  31. package/dist/agents/index.cjs +45 -0
  32. package/dist/agents/index.d.ts +28 -0
  33. package/dist/agents/index.d.ts.map +1 -0
  34. package/dist/agents/index.js +28 -0
  35. package/dist/agents/index.js.map +1 -0
  36. package/dist/box.cjs +19 -0
  37. package/dist/box.d.ts.map +1 -1
  38. package/dist/box.js +19 -0
  39. package/dist/box.js.map +1 -1
  40. package/dist/css.cjs +17 -0
  41. package/dist/css.d.ts +30 -0
  42. package/dist/css.d.ts.map +1 -0
  43. package/dist/css.js +14 -0
  44. package/dist/css.js.map +1 -0
  45. package/dist/gallery.html +1 -1
  46. package/dist/index.cjs +3 -1
  47. package/dist/index.d.ts +1 -0
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +1 -0
  50. package/dist/index.js.map +1 -1
  51. package/dist/index.node.js +1 -0
  52. package/dist/next.cjs +6 -0
  53. package/package.json +8 -2
@@ -0,0 +1,130 @@
1
+ 'use client';"use strict";
2
+ 'use client';
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.ProgressBlock = ProgressBlock;
5
+ exports.steps = steps;
6
+ const jsx_runtime_1 = require("react/jsx-runtime");
7
+ /**
8
+ * ProgressBlock — an agent's turn, as the steps it took.
9
+ *
10
+ * A run emits one event per token and per tool call, and printed flat that is a
11
+ * wall. What a reader wants is the SHAPE of the work: it thought, it searched,
12
+ * it read two files, it finished — each one line, each openable for the detail,
13
+ * and the answer underneath at full size.
14
+ *
15
+ * So a step is a LABEL plus DETAIL, and the detail is closed by default. The
16
+ * label is the claim ("Read 2 files"); the detail is the evidence
17
+ * ("BuyNowButton.tsx", "styles.css"). A reader skims labels and opens the one
18
+ * they doubt — which is the whole reason this beats a transcript.
19
+ *
20
+ * `done` is a state of the BLOCK, not a step: a run that is still working shows
21
+ * no tick, and a tick that appears before the work stops is a lie a reader will
22
+ * only catch once.
23
+ *
24
+ * Presentational. `steps()` maps session events to this shape and is exported
25
+ * beside it, because every surface reading the same stream should group it the
26
+ * same way.
27
+ */
28
+ const gui_1 = require("@hanzo/gui");
29
+ const lucide_icons_2_1 = require("@hanzogui/lucide-icons-2");
30
+ const react_1 = require("react");
31
+ const slot_1 = require("../backends/gui/slot.cjs");
32
+ const ICON = {
33
+ think: lucide_icons_2_1.Lightbulb,
34
+ search: lucide_icons_2_1.Sparkles,
35
+ read: lucide_icons_2_1.FileText,
36
+ run: lucide_icons_2_1.Terminal,
37
+ write: lucide_icons_2_1.FileText,
38
+ error: lucide_icons_2_1.TriangleAlert,
39
+ step: lucide_icons_2_1.CircleDot,
40
+ };
41
+ function Row({ step }) {
42
+ const [open, setOpen] = (0, react_1.useState)(step.open ?? false);
43
+ const Icon = ICON[step.kind];
44
+ const has = !!step.detail?.length;
45
+ return ((0, jsx_runtime_1.jsxs)(gui_1.YStack, { gap: "$0.5", children: [(0, jsx_runtime_1.jsxs)(gui_1.XStack, { items: "center", gap: "$1.5", cursor: has ? 'pointer' : 'default', role: has ? 'button' : undefined, tabIndex: has ? 0 : undefined, "aria-expanded": has ? open : undefined, onPress: () => has && setOpen((v) => !v), children: [(0, jsx_runtime_1.jsx)(Icon, { size: 13, opacity: 0.55 }), (0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$2", color: "$quiet", children: step.label }), has ? (open ? ((0, jsx_runtime_1.jsx)(lucide_icons_2_1.ChevronDown, { size: 12, opacity: 0.5 })) : ((0, jsx_runtime_1.jsx)(lucide_icons_2_1.ChevronRight, { size: 12, opacity: 0.5 }))) : null] }), has && open ? ((0, jsx_runtime_1.jsx)(gui_1.YStack, { pl: "$4", ml: "$1", gap: "$0.5", borderLeftWidth: 1, borderColor: "$borderColor", children: step.detail.map((line, i) => ((0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$2", color: "$soft", pl: "$2", children: line }, `${step.key}-${i}`))) })) : null] }));
46
+ }
47
+ function ProgressBlock({ steps, done = false, doneLabel = 'Done', children, ...rest }) {
48
+ return ((0, jsx_runtime_1.jsxs)(gui_1.YStack, { ...(0, slot_1.slot)('progress-block'), gap: "$1.5", ...rest, children: [steps.map((step) => ((0, jsx_runtime_1.jsx)(Row, { step: step }, step.key))), done ? ((0, jsx_runtime_1.jsxs)(gui_1.XStack, { items: "center", gap: "$1.5", children: [(0, jsx_runtime_1.jsx)(lucide_icons_2_1.Check, { size: 13, opacity: 0.75 }), (0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$2", color: "$quiet", children: doneLabel })] })) : null, children ? (0, jsx_runtime_1.jsx)(gui_1.YStack, { pt: "$1", children: children }) : null] }));
49
+ }
50
+ /** Map an event's kind onto a step kind. Unknown kinds stay generic rather than
51
+ * being forced into the nearest icon, which would misreport what happened. */
52
+ function kindOf(kind) {
53
+ const k = kind.toLowerCase();
54
+ if (k.includes('think') || k.includes('reason'))
55
+ return 'think';
56
+ if (k.includes('search') || k.includes('grep'))
57
+ return 'search';
58
+ if (k.includes('read') || k.includes('file'))
59
+ return 'read';
60
+ if (k.includes('tool') || k.includes('exec') || k.includes('command'))
61
+ return 'run';
62
+ if (k.includes('write') || k.includes('edit') || k.includes('patch'))
63
+ return 'write';
64
+ if (k.includes('error') || k.includes('fail'))
65
+ return 'error';
66
+ return 'step';
67
+ }
68
+ /** One readable line out of whatever a payload turned out to be. */
69
+ function say(payload) {
70
+ if (payload == null)
71
+ return '';
72
+ if (typeof payload === 'string')
73
+ return payload;
74
+ if (typeof payload !== 'object')
75
+ return String(payload);
76
+ const bag = payload;
77
+ for (const key of ['text', 'message', 'preview', 'content', 'name', 'command', 'path']) {
78
+ const found = bag[key];
79
+ if (typeof found === 'string' && found.trim())
80
+ return found;
81
+ }
82
+ try {
83
+ return JSON.stringify(payload);
84
+ }
85
+ catch {
86
+ return '';
87
+ }
88
+ }
89
+ /**
90
+ * Group a run's events into steps.
91
+ *
92
+ * Consecutive events of the same kind become ONE step whose detail is their
93
+ * lines — that is what turns twelve `tool-call` events into "Read 2 files" with
94
+ * two names under it. `message` events are NOT steps: they are the answer, and
95
+ * the caller renders them as `children`.
96
+ */
97
+ function steps(events) {
98
+ const out = [];
99
+ const said = [];
100
+ events.forEach((event, i) => {
101
+ const kind = event.kind ?? 'step';
102
+ const line = say(event.payload).trim();
103
+ if (kind === 'message') {
104
+ if (line)
105
+ said.push(line);
106
+ return;
107
+ }
108
+ const step = kindOf(kind);
109
+ const last = out[out.length - 1];
110
+ if (last && last.kind === step) {
111
+ if (line)
112
+ (last.detail ??= []).push(line);
113
+ return;
114
+ }
115
+ out.push({
116
+ key: `${event.seq ?? event.id ?? i}`,
117
+ kind: step,
118
+ label: kind,
119
+ detail: line ? [line] : undefined,
120
+ });
121
+ });
122
+ // A step's label counts what it did, once the run is grouped — "Read 2 files"
123
+ // rather than "read". The verb is the event's own; the number is ours.
124
+ for (const step of out) {
125
+ const n = step.detail?.length ?? 0;
126
+ if (n > 1)
127
+ step.label = `${step.label} ${n}`;
128
+ }
129
+ return { steps: out, message: said.join('') };
130
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * ProgressBlock — an agent's turn, as the steps it took.
3
+ *
4
+ * A run emits one event per token and per tool call, and printed flat that is a
5
+ * wall. What a reader wants is the SHAPE of the work: it thought, it searched,
6
+ * it read two files, it finished — each one line, each openable for the detail,
7
+ * and the answer underneath at full size.
8
+ *
9
+ * So a step is a LABEL plus DETAIL, and the detail is closed by default. The
10
+ * label is the claim ("Read 2 files"); the detail is the evidence
11
+ * ("BuyNowButton.tsx", "styles.css"). A reader skims labels and opens the one
12
+ * they doubt — which is the whole reason this beats a transcript.
13
+ *
14
+ * `done` is a state of the BLOCK, not a step: a run that is still working shows
15
+ * no tick, and a tick that appears before the work stops is a lie a reader will
16
+ * only catch once.
17
+ *
18
+ * Presentational. `steps()` maps session events to this shape and is exported
19
+ * beside it, because every surface reading the same stream should group it the
20
+ * same way.
21
+ */
22
+ import { YStack } from '@hanzo/gui';
23
+ import { type ComponentProps, type ReactNode } from 'react';
24
+ type Col = Omit<ComponentProps<typeof YStack>, 'children'>;
25
+ /** What a step was. Chooses the icon, and nothing else. */
26
+ export type StepKind = 'think' | 'search' | 'read' | 'run' | 'write' | 'error' | 'step';
27
+ export interface Step {
28
+ key: string;
29
+ kind: StepKind;
30
+ /** The claim — one line, always visible. */
31
+ label: string;
32
+ /** The evidence, one line each. Absent means nothing to open. */
33
+ detail?: string[];
34
+ /** Open on first render — for the step being worked on right now. */
35
+ open?: boolean;
36
+ }
37
+ export interface ProgressBlockProps extends Col {
38
+ steps: Step[];
39
+ /** The work has stopped. Draws the tick. */
40
+ done?: boolean;
41
+ doneLabel?: string;
42
+ /** The agent's message, at full size under the steps. */
43
+ children?: ReactNode;
44
+ }
45
+ export declare function ProgressBlock({ steps, done, doneLabel, children, ...rest }: ProgressBlockProps): import("react/jsx-runtime").JSX.Element;
46
+ /** The shape `steps()` reads. A session event, or anything that looks like one. */
47
+ export interface Event {
48
+ seq?: number;
49
+ id?: string;
50
+ kind?: string;
51
+ actor?: string;
52
+ payload?: unknown;
53
+ }
54
+ /**
55
+ * Group a run's events into steps.
56
+ *
57
+ * Consecutive events of the same kind become ONE step whose detail is their
58
+ * lines — that is what turns twelve `tool-call` events into "Read 2 files" with
59
+ * two names under it. `message` events are NOT steps: they are the answer, and
60
+ * the caller renders them as `children`.
61
+ */
62
+ export declare function steps(events: Event[]): {
63
+ steps: Step[];
64
+ message: string;
65
+ };
66
+ export {};
67
+ //# sourceMappingURL=Progress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Progress.d.ts","sourceRoot":"","sources":["../../src/agents/Progress.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAuB,MAAM,EAAE,MAAM,YAAY,CAAA;AAaxD,OAAO,EAAY,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAIrE,KAAK,GAAG,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,MAAM,CAAC,EAAE,UAAU,CAAC,CAAA;AAE1D,2DAA2D;AAC3D,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,CAAA;AAYvF,MAAM,WAAW,IAAI;IACnB,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,QAAQ,CAAA;IACd,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAA;IACb,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB,qEAAqE;IACrE,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AA8CD,MAAM,WAAW,kBAAmB,SAAQ,GAAG;IAC7C,KAAK,EAAE,IAAI,EAAE,CAAA;IACb,4CAA4C;IAC5C,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,SAAS,CAAA;CACrB;AAED,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,IAAY,EACZ,SAAkB,EAClB,QAAQ,EACR,GAAG,IAAI,EACR,EAAE,kBAAkB,2CAmBpB;AAED,mFAAmF;AACnF,MAAM,WAAW,KAAK;IACpB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAgCD;;;;;;;GAOG;AACH,wBAAgB,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG;IAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAiCzE"}
@@ -0,0 +1,127 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ /**
4
+ * ProgressBlock — an agent's turn, as the steps it took.
5
+ *
6
+ * A run emits one event per token and per tool call, and printed flat that is a
7
+ * wall. What a reader wants is the SHAPE of the work: it thought, it searched,
8
+ * it read two files, it finished — each one line, each openable for the detail,
9
+ * and the answer underneath at full size.
10
+ *
11
+ * So a step is a LABEL plus DETAIL, and the detail is closed by default. The
12
+ * label is the claim ("Read 2 files"); the detail is the evidence
13
+ * ("BuyNowButton.tsx", "styles.css"). A reader skims labels and opens the one
14
+ * they doubt — which is the whole reason this beats a transcript.
15
+ *
16
+ * `done` is a state of the BLOCK, not a step: a run that is still working shows
17
+ * no tick, and a tick that appears before the work stops is a lie a reader will
18
+ * only catch once.
19
+ *
20
+ * Presentational. `steps()` maps session events to this shape and is exported
21
+ * beside it, because every surface reading the same stream should group it the
22
+ * same way.
23
+ */
24
+ import { SizableText, XStack, YStack } from '@hanzo/gui';
25
+ import { Check, ChevronDown, ChevronRight, CircleDot, FileText, Lightbulb, Sparkles, Terminal, TriangleAlert, } from '@hanzogui/lucide-icons-2';
26
+ import { useState } from 'react';
27
+ import { slot } from '../backends/gui/slot.js';
28
+ const ICON = {
29
+ think: Lightbulb,
30
+ search: Sparkles,
31
+ read: FileText,
32
+ run: Terminal,
33
+ write: FileText,
34
+ error: TriangleAlert,
35
+ step: CircleDot,
36
+ };
37
+ function Row({ step }) {
38
+ const [open, setOpen] = useState(step.open ?? false);
39
+ const Icon = ICON[step.kind];
40
+ const has = !!step.detail?.length;
41
+ return (_jsxs(YStack, { gap: "$0.5", children: [_jsxs(XStack, { items: "center", gap: "$1.5", cursor: has ? 'pointer' : 'default', role: has ? 'button' : undefined, tabIndex: has ? 0 : undefined, "aria-expanded": has ? open : undefined, onPress: () => has && setOpen((v) => !v), children: [_jsx(Icon, { size: 13, opacity: 0.55 }), _jsx(SizableText, { size: "$2", color: "$quiet", children: step.label }), has ? (open ? (_jsx(ChevronDown, { size: 12, opacity: 0.5 })) : (_jsx(ChevronRight, { size: 12, opacity: 0.5 }))) : null] }), has && open ? (_jsx(YStack, { pl: "$4", ml: "$1", gap: "$0.5", borderLeftWidth: 1, borderColor: "$borderColor", children: step.detail.map((line, i) => (_jsx(SizableText, { size: "$2", color: "$soft", pl: "$2", children: line }, `${step.key}-${i}`))) })) : null] }));
42
+ }
43
+ export function ProgressBlock({ steps, done = false, doneLabel = 'Done', children, ...rest }) {
44
+ return (_jsxs(YStack, { ...slot('progress-block'), gap: "$1.5", ...rest, children: [steps.map((step) => (_jsx(Row, { step: step }, step.key))), done ? (_jsxs(XStack, { items: "center", gap: "$1.5", children: [_jsx(Check, { size: 13, opacity: 0.75 }), _jsx(SizableText, { size: "$2", color: "$quiet", children: doneLabel })] })) : null, children ? _jsx(YStack, { pt: "$1", children: children }) : null] }));
45
+ }
46
+ /** Map an event's kind onto a step kind. Unknown kinds stay generic rather than
47
+ * being forced into the nearest icon, which would misreport what happened. */
48
+ function kindOf(kind) {
49
+ const k = kind.toLowerCase();
50
+ if (k.includes('think') || k.includes('reason'))
51
+ return 'think';
52
+ if (k.includes('search') || k.includes('grep'))
53
+ return 'search';
54
+ if (k.includes('read') || k.includes('file'))
55
+ return 'read';
56
+ if (k.includes('tool') || k.includes('exec') || k.includes('command'))
57
+ return 'run';
58
+ if (k.includes('write') || k.includes('edit') || k.includes('patch'))
59
+ return 'write';
60
+ if (k.includes('error') || k.includes('fail'))
61
+ return 'error';
62
+ return 'step';
63
+ }
64
+ /** One readable line out of whatever a payload turned out to be. */
65
+ function say(payload) {
66
+ if (payload == null)
67
+ return '';
68
+ if (typeof payload === 'string')
69
+ return payload;
70
+ if (typeof payload !== 'object')
71
+ return String(payload);
72
+ const bag = payload;
73
+ for (const key of ['text', 'message', 'preview', 'content', 'name', 'command', 'path']) {
74
+ const found = bag[key];
75
+ if (typeof found === 'string' && found.trim())
76
+ return found;
77
+ }
78
+ try {
79
+ return JSON.stringify(payload);
80
+ }
81
+ catch {
82
+ return '';
83
+ }
84
+ }
85
+ /**
86
+ * Group a run's events into steps.
87
+ *
88
+ * Consecutive events of the same kind become ONE step whose detail is their
89
+ * lines — that is what turns twelve `tool-call` events into "Read 2 files" with
90
+ * two names under it. `message` events are NOT steps: they are the answer, and
91
+ * the caller renders them as `children`.
92
+ */
93
+ export function steps(events) {
94
+ const out = [];
95
+ const said = [];
96
+ events.forEach((event, i) => {
97
+ const kind = event.kind ?? 'step';
98
+ const line = say(event.payload).trim();
99
+ if (kind === 'message') {
100
+ if (line)
101
+ said.push(line);
102
+ return;
103
+ }
104
+ const step = kindOf(kind);
105
+ const last = out[out.length - 1];
106
+ if (last && last.kind === step) {
107
+ if (line)
108
+ (last.detail ??= []).push(line);
109
+ return;
110
+ }
111
+ out.push({
112
+ key: `${event.seq ?? event.id ?? i}`,
113
+ kind: step,
114
+ label: kind,
115
+ detail: line ? [line] : undefined,
116
+ });
117
+ });
118
+ // A step's label counts what it did, once the run is grouped — "Read 2 files"
119
+ // rather than "read". The verb is the event's own; the number is ours.
120
+ for (const step of out) {
121
+ const n = step.detail?.length ?? 0;
122
+ if (n > 1)
123
+ step.label = `${step.label} ${n}`;
124
+ }
125
+ return { steps: out, message: said.join('') };
126
+ }
127
+ //# sourceMappingURL=Progress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Progress.js","sourceRoot":"","sources":["../../src/agents/Progress.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,91 @@
1
+ 'use client';"use strict";
2
+ 'use client';
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.Screen = Screen;
5
+ const jsx_runtime_1 = require("react/jsx-runtime");
6
+ /**
7
+ * Screen — watching a run while it works.
8
+ *
9
+ * Some runs have something to look at: a sandbox serving an interactive page, a
10
+ * headful browser a person can watch over VNC. Most have nothing, and this
11
+ * component's first job is to say which it is, honestly — a viewer that draws a
12
+ * black rectangle for a run with no screen has told the reader the run is
13
+ * broken.
14
+ *
15
+ * THE CREDENTIAL NEVER OUTLIVES THE VIEW. A watchable surface is authorized by
16
+ * a short-lived TICKET the caller mints per view; this component asks for one
17
+ * when it mounts, embeds the page the ticket names, and asks for another if the
18
+ * viewer stays past its life. It does NOT take a URL with a long-lived token in
19
+ * it, and there is no prop to pass one — an embed URL ends up in browser
20
+ * history, in a screenshot, and in whatever the parent frame can read.
21
+ *
22
+ * The mint is a PROP, not an import, because who may watch is the surface's
23
+ * question and the answer lives in `@hanzo/ai` on one deployment and behind a
24
+ * BFF on another. This file owns the frame, the states and the refresh.
25
+ */
26
+ const gui_1 = require("@hanzo/gui");
27
+ const react_1 = require("react");
28
+ const slot_1 = require("../backends/gui/slot.cjs");
29
+ const NAMES = {
30
+ sandbox: 'sandbox',
31
+ browser: 'browser',
32
+ };
33
+ /** Re-mint at 80% of a ticket's life — early enough that the frame never blinks. */
34
+ const EARLY = 0.8;
35
+ function Screen({ sessionId, kind, mint, empty, title, ...rest }) {
36
+ const [state, setState] = (0, react_1.useState)({ phase: 'idle' });
37
+ const timer = (0, react_1.useRef)(null);
38
+ const live = (0, react_1.useRef)(true);
39
+ const open = (0, react_1.useCallback)(async () => {
40
+ if (!mint || !kind)
41
+ return;
42
+ setState({ phase: 'minting' });
43
+ try {
44
+ const ticket = await mint(sessionId);
45
+ if (!live.current)
46
+ return;
47
+ setState({ phase: 'watching', url: ticket.url });
48
+ if (ticket.expiresIn && ticket.expiresIn > 0) {
49
+ if (timer.current)
50
+ clearTimeout(timer.current);
51
+ timer.current = setTimeout(() => void open(), ticket.expiresIn * 1000 * EARLY);
52
+ }
53
+ }
54
+ catch (err) {
55
+ if (!live.current)
56
+ return;
57
+ setState({
58
+ phase: 'failed',
59
+ message: err instanceof Error ? err.message : 'Could not open this screen.',
60
+ });
61
+ }
62
+ }, [mint, kind, sessionId]);
63
+ (0, react_1.useEffect)(() => {
64
+ live.current = true;
65
+ void open();
66
+ return () => {
67
+ live.current = false;
68
+ if (timer.current)
69
+ clearTimeout(timer.current);
70
+ };
71
+ }, [open]);
72
+ if (!kind) {
73
+ return ((0, jsx_runtime_1.jsx)(Frame, { title: title, ...rest, children: empty ?? ((0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$2", color: "$soft", children: "This run has no screen." })) }));
74
+ }
75
+ if (!mint) {
76
+ return ((0, jsx_runtime_1.jsx)(Frame, { title: title, ...rest, children: (0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$2", color: "$soft", children: "Watching is not wired up on this surface." }) }));
77
+ }
78
+ if (state.phase === 'failed') {
79
+ return ((0, jsx_runtime_1.jsx)(Frame, { title: title, ...rest, children: (0, jsx_runtime_1.jsxs)(gui_1.YStack, { gap: "$2", items: "center", children: [(0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$2", color: "$soft", children: state.message }), (0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$2", color: "$color", cursor: "pointer", role: "button", tabIndex: 0, onPress: () => void open(), children: "Try again" })] }) }));
80
+ }
81
+ if (state.phase !== 'watching') {
82
+ return ((0, jsx_runtime_1.jsx)(Frame, { title: title, ...rest, children: (0, jsx_runtime_1.jsxs)(gui_1.SizableText, { size: "$2", color: "$soft", children: ["Opening the ", NAMES[kind], "\u2026"] }) }));
83
+ }
84
+ return ((0, jsx_runtime_1.jsxs)(gui_1.YStack, { ...(0, slot_1.slot)('screen'), flex: 1, minH: 0, bg: "$panel", rounded: "$4", overflow: "hidden", ...rest, children: [title ? (0, jsx_runtime_1.jsx)(Caption, { children: title }) : null, (0, jsx_runtime_1.jsx)("iframe", { src: state.url, title: title ?? `Live ${NAMES[kind]}`, sandbox: "allow-scripts allow-same-origin allow-forms", referrerPolicy: "no-referrer", allow: "clipboard-read; clipboard-write", style: { border: 0, width: '100%', height: '100%', flex: 1, display: 'block' } })] }));
85
+ }
86
+ function Caption({ children }) {
87
+ return ((0, jsx_runtime_1.jsx)(gui_1.XStack, { px: "$3", py: "$2", borderBottomWidth: 1, borderColor: "$borderColor", children: (0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$1", color: "$soft", numberOfLines: 1, children: children }) }));
88
+ }
89
+ function Frame({ title, children, ...rest }) {
90
+ return ((0, jsx_runtime_1.jsxs)(gui_1.YStack, { ...(0, slot_1.slot)('screen'), flex: 1, minH: 0, bg: "$panel", rounded: "$4", overflow: "hidden", ...rest, children: [title ? (0, jsx_runtime_1.jsx)(Caption, { children: title }) : null, (0, jsx_runtime_1.jsx)(gui_1.YStack, { flex: 1, items: "center", justify: "center", p: "$4", children: children })] }));
91
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Screen — watching a run while it works.
3
+ *
4
+ * Some runs have something to look at: a sandbox serving an interactive page, a
5
+ * headful browser a person can watch over VNC. Most have nothing, and this
6
+ * component's first job is to say which it is, honestly — a viewer that draws a
7
+ * black rectangle for a run with no screen has told the reader the run is
8
+ * broken.
9
+ *
10
+ * THE CREDENTIAL NEVER OUTLIVES THE VIEW. A watchable surface is authorized by
11
+ * a short-lived TICKET the caller mints per view; this component asks for one
12
+ * when it mounts, embeds the page the ticket names, and asks for another if the
13
+ * viewer stays past its life. It does NOT take a URL with a long-lived token in
14
+ * it, and there is no prop to pass one — an embed URL ends up in browser
15
+ * history, in a screenshot, and in whatever the parent frame can read.
16
+ *
17
+ * The mint is a PROP, not an import, because who may watch is the surface's
18
+ * question and the answer lives in `@hanzo/ai` on one deployment and behind a
19
+ * BFF on another. This file owns the frame, the states and the refresh.
20
+ */
21
+ import { YStack } from '@hanzo/gui';
22
+ import { type ComponentProps, type ReactNode } from 'react';
23
+ type Col = Omit<ComponentProps<typeof YStack>, 'children'>;
24
+ /** What a mint answers with: where to look, and for how long. */
25
+ export interface Ticket {
26
+ /** The page to embed. Already carries whatever the grant put in it. */
27
+ url: string;
28
+ /** Seconds until it stops working. Absent, the view is not refreshed. */
29
+ expiresIn?: number;
30
+ }
31
+ /** How a run's screen is served, for the label a viewer reads. */
32
+ export type ScreenKind = 'sandbox' | 'browser';
33
+ export interface ScreenProps extends Col {
34
+ /** The run being watched. Changing it re-mints. */
35
+ sessionId: string;
36
+ /**
37
+ * What this run has to look at. `null` means nothing does — the honest empty
38
+ * state, and the common case. The caller decides; this component never guesses
39
+ * from a session's shape.
40
+ */
41
+ kind?: ScreenKind | null;
42
+ /**
43
+ * Mint a view. Called on mount, on `sessionId` change, and shortly before the
44
+ * previous ticket expires. Throwing renders the failure with a retry.
45
+ */
46
+ mint?: (sessionId: string) => Promise<Ticket>;
47
+ /** Shown when `kind` is null. */
48
+ empty?: ReactNode;
49
+ title?: string;
50
+ }
51
+ export declare function Screen({ sessionId, kind, mint, empty, title, ...rest }: ScreenProps): import("react/jsx-runtime").JSX.Element;
52
+ export {};
53
+ //# sourceMappingURL=Screen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Screen.d.ts","sourceRoot":"","sources":["../../src/agents/Screen.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAuB,MAAM,EAAE,MAAM,YAAY,CAAA;AACxD,OAAO,EAA4C,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAIrG,KAAK,GAAG,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,MAAM,CAAC,EAAE,UAAU,CAAC,CAAA;AAE1D,iEAAiE;AACjE,MAAM,WAAW,MAAM;IACrB,uEAAuE;IACvE,GAAG,EAAE,MAAM,CAAA;IACX,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,kEAAkE;AAClE,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,SAAS,CAAA;AAO9C,MAAM,WAAW,WAAY,SAAQ,GAAG;IACtC,mDAAmD;IACnD,SAAS,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;IACxB;;;OAGG;IACH,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAC7C,iCAAiC;IACjC,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAWD,wBAAgB,MAAM,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,EAAE,WAAW,2CA2GnF"}
@@ -0,0 +1,89 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ /**
4
+ * Screen — watching a run while it works.
5
+ *
6
+ * Some runs have something to look at: a sandbox serving an interactive page, a
7
+ * headful browser a person can watch over VNC. Most have nothing, and this
8
+ * component's first job is to say which it is, honestly — a viewer that draws a
9
+ * black rectangle for a run with no screen has told the reader the run is
10
+ * broken.
11
+ *
12
+ * THE CREDENTIAL NEVER OUTLIVES THE VIEW. A watchable surface is authorized by
13
+ * a short-lived TICKET the caller mints per view; this component asks for one
14
+ * when it mounts, embeds the page the ticket names, and asks for another if the
15
+ * viewer stays past its life. It does NOT take a URL with a long-lived token in
16
+ * it, and there is no prop to pass one — an embed URL ends up in browser
17
+ * history, in a screenshot, and in whatever the parent frame can read.
18
+ *
19
+ * The mint is a PROP, not an import, because who may watch is the surface's
20
+ * question and the answer lives in `@hanzo/ai` on one deployment and behind a
21
+ * BFF on another. This file owns the frame, the states and the refresh.
22
+ */
23
+ import { SizableText, XStack, YStack } from '@hanzo/gui';
24
+ import { useCallback, useEffect, useRef, useState } from 'react';
25
+ import { slot } from '../backends/gui/slot.js';
26
+ const NAMES = {
27
+ sandbox: 'sandbox',
28
+ browser: 'browser',
29
+ };
30
+ /** Re-mint at 80% of a ticket's life — early enough that the frame never blinks. */
31
+ const EARLY = 0.8;
32
+ export function Screen({ sessionId, kind, mint, empty, title, ...rest }) {
33
+ const [state, setState] = useState({ phase: 'idle' });
34
+ const timer = useRef(null);
35
+ const live = useRef(true);
36
+ const open = useCallback(async () => {
37
+ if (!mint || !kind)
38
+ return;
39
+ setState({ phase: 'minting' });
40
+ try {
41
+ const ticket = await mint(sessionId);
42
+ if (!live.current)
43
+ return;
44
+ setState({ phase: 'watching', url: ticket.url });
45
+ if (ticket.expiresIn && ticket.expiresIn > 0) {
46
+ if (timer.current)
47
+ clearTimeout(timer.current);
48
+ timer.current = setTimeout(() => void open(), ticket.expiresIn * 1000 * EARLY);
49
+ }
50
+ }
51
+ catch (err) {
52
+ if (!live.current)
53
+ return;
54
+ setState({
55
+ phase: 'failed',
56
+ message: err instanceof Error ? err.message : 'Could not open this screen.',
57
+ });
58
+ }
59
+ }, [mint, kind, sessionId]);
60
+ useEffect(() => {
61
+ live.current = true;
62
+ void open();
63
+ return () => {
64
+ live.current = false;
65
+ if (timer.current)
66
+ clearTimeout(timer.current);
67
+ };
68
+ }, [open]);
69
+ if (!kind) {
70
+ return (_jsx(Frame, { title: title, ...rest, children: empty ?? (_jsx(SizableText, { size: "$2", color: "$soft", children: "This run has no screen." })) }));
71
+ }
72
+ if (!mint) {
73
+ return (_jsx(Frame, { title: title, ...rest, children: _jsx(SizableText, { size: "$2", color: "$soft", children: "Watching is not wired up on this surface." }) }));
74
+ }
75
+ if (state.phase === 'failed') {
76
+ return (_jsx(Frame, { title: title, ...rest, children: _jsxs(YStack, { gap: "$2", items: "center", children: [_jsx(SizableText, { size: "$2", color: "$soft", children: state.message }), _jsx(SizableText, { size: "$2", color: "$color", cursor: "pointer", role: "button", tabIndex: 0, onPress: () => void open(), children: "Try again" })] }) }));
77
+ }
78
+ if (state.phase !== 'watching') {
79
+ return (_jsx(Frame, { title: title, ...rest, children: _jsxs(SizableText, { size: "$2", color: "$soft", children: ["Opening the ", NAMES[kind], "\u2026"] }) }));
80
+ }
81
+ return (_jsxs(YStack, { ...slot('screen'), flex: 1, minH: 0, bg: "$panel", rounded: "$4", overflow: "hidden", ...rest, children: [title ? _jsx(Caption, { children: title }) : null, _jsx("iframe", { src: state.url, title: title ?? `Live ${NAMES[kind]}`, sandbox: "allow-scripts allow-same-origin allow-forms", referrerPolicy: "no-referrer", allow: "clipboard-read; clipboard-write", style: { border: 0, width: '100%', height: '100%', flex: 1, display: 'block' } })] }));
82
+ }
83
+ function Caption({ children }) {
84
+ return (_jsx(XStack, { px: "$3", py: "$2", borderBottomWidth: 1, borderColor: "$borderColor", children: _jsx(SizableText, { size: "$1", color: "$soft", numberOfLines: 1, children: children }) }));
85
+ }
86
+ function Frame({ title, children, ...rest }) {
87
+ return (_jsxs(YStack, { ...slot('screen'), flex: 1, minH: 0, bg: "$panel", rounded: "$4", overflow: "hidden", ...rest, children: [title ? _jsx(Caption, { children: title }) : null, _jsx(YStack, { flex: 1, items: "center", justify: "center", p: "$4", children: children })] }));
88
+ }
89
+ //# sourceMappingURL=Screen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Screen.js","sourceRoot":"","sources":["../../src/agents/Screen.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ 'use client';"use strict";
2
+ 'use client';
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.Steer = Steer;
5
+ exports.MemberRow = MemberRow;
6
+ const jsx_runtime_1 = require("react/jsx-runtime");
7
+ /**
8
+ * Steer — the controls that reach a run mid-flight, and the roster row.
9
+ *
10
+ * A command is QUEUED, not applied: an agent reads it between turns, so the
11
+ * label a person sees after pressing has to say that. A control that reports
12
+ * "stopped" the instant it is pressed is lying for however long the current
13
+ * turn takes.
14
+ *
15
+ * Presentational: the verbs go out through `onCommand` and the surface decides
16
+ * what they mean. `@hanzo/ai`'s `sessions.steer(id, command)` is the one it
17
+ * wants, but this row does not import it — a channel workspace steering through
18
+ * a BFF composes the same control.
19
+ */
20
+ const gui_1 = require("@hanzo/gui");
21
+ const lucide_icons_2_1 = require("@hanzogui/lucide-icons-2");
22
+ const slot_1 = require("../backends/gui/slot.cjs");
23
+ const CONTROLS = [
24
+ { command: 'pause', label: 'Pause', icon: lucide_icons_2_1.Pause },
25
+ { command: 'resume', label: 'Resume', icon: lucide_icons_2_1.Play },
26
+ { command: 'stop', label: 'Stop', icon: lucide_icons_2_1.Square },
27
+ ];
28
+ function Steer({ onCommand, withhold = [], note, ...rest }) {
29
+ return ((0, jsx_runtime_1.jsxs)(gui_1.YStack, { ...(0, slot_1.slot)('steer'), gap: "$1", children: [(0, jsx_runtime_1.jsx)(gui_1.XStack, { gap: "$1", items: "center", ...rest, children: CONTROLS.map(({ command, label, icon: Icon }) => {
30
+ const off = withhold.includes(command);
31
+ return ((0, jsx_runtime_1.jsxs)(gui_1.XStack, { items: "center", gap: "$1.5", px: "$2", py: "$1", rounded: "$3", opacity: off ? 0.4 : 0.8, cursor: off ? 'default' : 'pointer', role: "button", tabIndex: off ? -1 : 0, "aria-disabled": off, "aria-label": label, ...(0, slot_1.tip)(label), hoverStyle: off ? undefined : { bg: '$hover', opacity: 1 }, pressStyle: off ? undefined : { bg: '$raised' }, onPress: () => !off && onCommand?.(command), children: [(0, jsx_runtime_1.jsx)(Icon, { size: 13 }), (0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$1", children: label })] }, command));
32
+ }) }), note ? ((0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$1", color: "$soft", children: note })) : null] }));
33
+ }
34
+ const KIND = {
35
+ agent: { icon: lucide_icons_2_1.Zap, says: 'agent' },
36
+ bot: { icon: lucide_icons_2_1.Bot, says: 'always on' },
37
+ human: { icon: lucide_icons_2_1.User, says: 'person' },
38
+ };
39
+ function MemberRow({ name, kind, detail, onPress, ...rest }) {
40
+ const { icon: Icon, says } = KIND[kind];
41
+ return ((0, jsx_runtime_1.jsxs)(gui_1.XStack, { ...(0, slot_1.slot)('member-row'), items: "center", gap: "$2", px: "$2", py: "$1.5", rounded: "$3", cursor: onPress ? 'pointer' : 'default', role: onPress ? 'button' : undefined, tabIndex: onPress ? 0 : undefined, hoverStyle: onPress ? { bg: '$hover' } : undefined, onPress: onPress, ...rest, children: [(0, jsx_runtime_1.jsx)(gui_1.XStack, { width: 22, height: 22, rounded: 9999, items: "center", justify: "center", bg: "$raised", shrink: 0, children: (0, jsx_runtime_1.jsx)(Icon, { size: 12 }) }), (0, jsx_runtime_1.jsxs)(gui_1.YStack, { flex: 1, shrink: 1, children: [(0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$2", numberOfLines: 1, children: name }), detail ? ((0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$1", color: "$soft", numberOfLines: 1, children: detail })) : null] }), (0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$1", color: "$color8", children: says })] }));
42
+ }