@hanzo/rooms 0.1.84 → 0.1.85
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/dist/App.js +11 -2
- package/dist/Chat.js +8 -9
- package/dist/Column.d.ts +3 -1
- package/dist/Column.js +13 -12
- package/dist/Me.js +16 -2
- package/dist/Rail.d.ts +18 -1
- package/dist/Rail.js +47 -16
- package/dist/Shell.js +4 -15
- package/dist/agents.d.ts +11 -12
- package/dist/agents.js +14 -9
- package/dist/crew.js +1 -0
- package/dist/dev.js +4 -0
- package/package.json +3 -3
package/dist/App.js
CHANGED
|
@@ -69,7 +69,7 @@ import { isPlans, leave, useDevHost } from './dev.js';
|
|
|
69
69
|
import { Orgs } from './Orgs.js';
|
|
70
70
|
import { useRooms } from './host.js';
|
|
71
71
|
import { useKept } from './kept.js';
|
|
72
|
-
import { Mark, Rail, Toggle } from './Rail.js';
|
|
72
|
+
import { Mark, Rail, spot, Toggle } from './Rail.js';
|
|
73
73
|
import { empty, openThread, useOpen } from './open.js';
|
|
74
74
|
import { Paned } from './Shell.js';
|
|
75
75
|
import { Palette } from './Palette.js';
|
|
@@ -191,6 +191,14 @@ function Window({ bar }) {
|
|
|
191
191
|
last[mode] = `${window.location.pathname}${window.location.search}`;
|
|
192
192
|
setDrawer(false);
|
|
193
193
|
}, [mode, here]);
|
|
194
|
+
// Where the reader was before a place that takes the sidebar (Library, Scheduled
|
|
195
|
+
// tasks, Customize, Settings): its Back returns there, Chat or Dev alike.
|
|
196
|
+
const away = useRef('');
|
|
197
|
+
const inPlace = mode === 'dev' && spot(where) !== null;
|
|
198
|
+
useEffect(() => {
|
|
199
|
+
if (!inPlace)
|
|
200
|
+
away.current = `${window.location.pathname}${window.location.search}`;
|
|
201
|
+
}, [inPlace, here]);
|
|
194
202
|
/** A move of the app's own: the drawer away, then the address. */
|
|
195
203
|
const move = useCallback((address) => {
|
|
196
204
|
shut();
|
|
@@ -227,6 +235,7 @@ function Window({ bar }) {
|
|
|
227
235
|
window.addEventListener('keydown', key);
|
|
228
236
|
return () => window.removeEventListener('keydown', key);
|
|
229
237
|
}, [bar, router, move]);
|
|
238
|
+
const back = () => move(away.current || app(''));
|
|
230
239
|
const toChat = () => move(last.chat || talk());
|
|
231
240
|
const toDev = () => move(last.dev || app(''));
|
|
232
241
|
const toStudio = () => move(last.studio || studio(''));
|
|
@@ -241,5 +250,5 @@ function Window({ bar }) {
|
|
|
241
250
|
shut();
|
|
242
251
|
setFinding(true);
|
|
243
252
|
};
|
|
244
|
-
return (_jsx(AiProvider, { client: client ?? undefined, children: _jsx(HostProvider, { host: host, children: _jsx(PrefsProvider, { children: _jsxs(YStack, { ref: view, "data-slot": "window", ...(bar ? floor : null), flex: 1, minW: 0, height: "100dvh", overflow: "hidden", "$max-md": { position: 'fixed', t: TOP, l: 0, r: 0, height: HEIGHT }, children: [bar ? (_jsxs(XStack, { "data-slot": "title-bar", height: BAR, shrink: 0, items: "center", gap: 2, pl: (bar.inset ?? 0) + 6, pr: "$2", ...bar.drag, children: [_jsx(XStack, { "$max-md": { display: 'none' }, children: _jsx(Toggle, { open: !closed, onPress: flip }) }), _jsx(XStack, { $md: { display: 'none' }, children: _jsx(Toggle, { open: drawer, onPress: () => setDrawer(true), label: "Open sidebar" }) }), _jsx(Mark, { label: "Back", "data-slot": "back", onPress: () => router.back(), children: _jsx(ArrowLeft, { size: 18, "aria-hidden": true }) }), _jsx(Mark, { label: "Forward", "data-slot": "forward", onPress: () => router.forward(), children: _jsx(ArrowRight, { size: 18, "aria-hidden": true }) }), _jsx(XStack, { flex: 1, self: "stretch", ...bar.drag })] })) : null, _jsxs(XStack, { "data-room": "", "data-app": mode, "data-slot": "frame", ...(bar ? null : floor), flex: 1, minW: 0, minH: 0, pr: "var(--pane-gap)", pb: "var(--pane-gap)", pt: bar ? 0 : 'var(--pane-gap)', "$max-md": { p: 0 }, children: [_jsx(YStack, { height: "100%", "$max-md": { display: 'none' }, children: _jsx(Rail, { host: host, mode: mode, open: !closed, toggle: bar ? undefined : flip, onChat: toChat, onDev: toDev, onStudio: toStudio, onOrg: org }) }), closed ? null : (_jsx(YStack, { "$max-md": { display: 'none' }, children: _jsx(Column, { host: host, mode: mode, thread: thread, go: move, onShut: () => setClosed(true), onSeek: seek, places: sidebar }) })), _jsxs(YStack, { "data-slot": "stage", flex: 1, minW: 0, minH: 0, ml: "var(--pane-gap)", "$max-md": { ml: 0, pb: FOOT }, children: [bar ? null : _jsx(Top, { host: host, mode: mode, places: sidebar, go: move, onMenu: () => setDrawer(true), onChat: toChat, onDev: toDev }), _jsx(XStack, { "data-slot": "panes", flex: 1, minW: 0, minH: 0, children: mode === 'chat' ? (_jsx(Paned, { framed: true, children: _jsx(Chat, {}) })) : mode === 'studio' ? (_jsx(YStack, { render: "main", "data-slot": "pane", ...pane(), overflow: "hidden", flex: 1, minW: 0, minH: 0, children: _jsx(YStack, { flex: 1, minH: 0, height: "100%", children: _jsx(Suspense, { fallback: null, children: _jsx(Studio, { host: maker, rail: false }) }) }) })) : (_jsx(YStack, { render: "main", "data-slot": "pane", ...(run ? null : { ...pane(), overflow: 'hidden' }), flex: 1, minW: 0, minH: 0, children: plans ? null : _jsx(Builder, { host: host, rail: false }) })) })] })] }), drawer ? (_jsxs(_Fragment, { children: [_jsx(YStack, { render: "button", "aria-label": "Close sidebar", onPress: () => setDrawer(false), bg: DIM, position: "absolute", t: 0, r: 0, b: 0, l: 0, z: "var(--z-overlay)", $md: { display: 'none' } }), _jsx(YStack, { "data-slot": "drawer", position: "absolute", t: INSET.top, b: INSET.bottom, l: INSET.left, width: "min(320px, calc(100% - 2 * var(--pane-gap) - 48px))", z: "var(--z-modal)", $md: { display: 'none' }, children: _jsx(Column, { host: host, mode: mode, thread: thread, go: move, onShut: shut, onSeek: seek, drawer: true, places: sidebar, foot: _jsx(Rail, { host: host, mode: mode, open: true, flat: true, onChat: toChat, onDev: toDev, onStudio: toStudio, onOrg: org }) }) })] })) : null, finding ? _jsx(Palette, { go: move, onClose: found, mode: mode, host: host }) : null] }) }) }) }));
|
|
253
|
+
return (_jsx(AiProvider, { client: client ?? undefined, children: _jsx(HostProvider, { host: host, children: _jsx(PrefsProvider, { children: _jsxs(YStack, { ref: view, "data-slot": "window", ...(bar ? floor : null), flex: 1, minW: 0, height: "100dvh", overflow: "hidden", "$max-md": { position: 'fixed', t: TOP, l: 0, r: 0, height: HEIGHT }, children: [bar ? (_jsxs(XStack, { "data-slot": "title-bar", height: BAR, shrink: 0, items: "center", gap: 2, pl: (bar.inset ?? 0) + 6, pr: "$2", ...bar.drag, children: [_jsx(XStack, { "$max-md": { display: 'none' }, children: _jsx(Toggle, { open: !closed, onPress: flip }) }), _jsx(XStack, { $md: { display: 'none' }, children: _jsx(Toggle, { open: drawer, onPress: () => setDrawer(true), label: "Open sidebar" }) }), _jsx(Mark, { label: "Back", "data-slot": "back", onPress: () => router.back(), children: _jsx(ArrowLeft, { size: 18, "aria-hidden": true }) }), _jsx(Mark, { label: "Forward", "data-slot": "forward", onPress: () => router.forward(), children: _jsx(ArrowRight, { size: 18, "aria-hidden": true }) }), _jsx(XStack, { flex: 1, self: "stretch", ...bar.drag })] })) : null, _jsxs(XStack, { "data-room": "", "data-app": mode, "data-slot": "frame", ...(bar ? null : floor), flex: 1, minW: 0, minH: 0, pr: "var(--pane-gap)", pb: "var(--pane-gap)", pt: bar ? 0 : 'var(--pane-gap)', "$max-md": { p: 0 }, children: [_jsx(YStack, { height: "100%", "$max-md": { display: 'none' }, children: _jsx(Rail, { host: host, mode: mode, at: where, open: !closed, toggle: bar ? undefined : flip, onChat: toChat, onDev: toDev, onStudio: toStudio, go: move, onOrg: org }) }), closed ? null : (_jsx(YStack, { "$max-md": { display: 'none' }, children: _jsx(Column, { host: host, mode: mode, thread: thread, go: move, onShut: () => setClosed(true), onSeek: seek, onBack: back, places: sidebar }) })), _jsxs(YStack, { "data-slot": "stage", flex: 1, minW: 0, minH: 0, ml: "var(--pane-gap)", "$max-md": { ml: 0, pb: FOOT }, children: [bar ? null : _jsx(Top, { host: host, mode: mode, places: sidebar, go: move, onMenu: () => setDrawer(true), onChat: toChat, onDev: toDev }), _jsx(XStack, { "data-slot": "panes", flex: 1, minW: 0, minH: 0, children: mode === 'chat' ? (_jsx(Paned, { framed: true, children: _jsx(Chat, {}) })) : mode === 'studio' ? (_jsx(YStack, { render: "main", "data-slot": "pane", ...pane(), overflow: "hidden", flex: 1, minW: 0, minH: 0, children: _jsx(YStack, { flex: 1, minH: 0, height: "100%", children: _jsx(Suspense, { fallback: null, children: _jsx(Studio, { host: maker, rail: false }) }) }) })) : (_jsx(YStack, { render: "main", "data-slot": "pane", ...(run ? null : { ...pane(), overflow: 'hidden' }), flex: 1, minW: 0, minH: 0, children: plans ? null : _jsx(Builder, { host: host, rail: false }) })) })] })] }), drawer ? (_jsxs(_Fragment, { children: [_jsx(YStack, { render: "button", "aria-label": "Close sidebar", onPress: () => setDrawer(false), bg: DIM, position: "absolute", t: 0, r: 0, b: 0, l: 0, z: "var(--z-overlay)", $md: { display: 'none' } }), _jsx(YStack, { "data-slot": "drawer", position: "absolute", t: INSET.top, b: INSET.bottom, l: INSET.left, width: "min(320px, calc(100% - 2 * var(--pane-gap) - 48px))", z: "var(--z-modal)", $md: { display: 'none' }, children: _jsx(Column, { host: host, mode: mode, thread: thread, go: move, onShut: shut, onSeek: seek, onBack: back, drawer: true, places: sidebar, foot: _jsx(Rail, { host: host, mode: mode, at: where, open: true, flat: true, onChat: toChat, onDev: toDev, onStudio: toStudio, go: move, onOrg: org }) }) })] })) : null, finding ? _jsx(Palette, { go: move, onClose: found, mode: mode, host: host }) : null] }) }) }) }));
|
|
245
254
|
}
|
package/dist/Chat.js
CHANGED
|
@@ -44,7 +44,7 @@ import { Anchor, Box, Button, Text, View, XStack, YStack } from "@hanzo/ui";
|
|
|
44
44
|
import { useMedia } from "@hanzo/gui";
|
|
45
45
|
import { tidy } from "./lib/title.js";
|
|
46
46
|
import { useIam, useIamToken } from "@hanzo/iam/react";
|
|
47
|
-
import { bearer, hasSession, org } from "./lib/session.js";
|
|
47
|
+
import { bearer, hasSession, named, org } from "./lib/session.js";
|
|
48
48
|
import { api } from "./lib/api.js";
|
|
49
49
|
import { app, dev, go } from "./lib/host.js";
|
|
50
50
|
import { useRooms } from "./host.js";
|
|
@@ -64,7 +64,7 @@ import { Share } from "./Share.js";
|
|
|
64
64
|
import { ConversationMenu, ThreadMore, useThreadList } from "./thread.js";
|
|
65
65
|
import { Schedule } from "./Schedule.js";
|
|
66
66
|
import { keepFile, useAttach, useKeep } from "./keep.js";
|
|
67
|
-
import { artifacts, lead, nameOf, PAGE, Panel, PanelToggle, prompt, renders, Reply, Served, Summary, useDeck, useKey, Suggestions, useCarry, useLanguage, useMention, useMind, useSuggestions, usePanel, frames, name as tabName, } from "@hanzo/build";
|
|
67
|
+
import { artifacts, lead, nameOf, PAGE, Panel, PanelToggle, prompt, renders, Reply, Served, Summary, useDeck, useKey, Suggestions, useCarry, useLanguage, useMention, useMind, useSuggestions, CHAT_MODES, usePanel, frames, name as tabName, } from "@hanzo/build";
|
|
68
68
|
import { checkoutUrl } from './lib/pay.js';
|
|
69
69
|
import { Upgrade, useFree } from './Upgrade.js';
|
|
70
70
|
import { enter, LOGIN } from './lib/destination.js';
|
|
@@ -224,8 +224,6 @@ export function Ask({ placeholder, idle, }) {
|
|
|
224
224
|
* accessible name does not move when the placeholder does.
|
|
225
225
|
*/
|
|
226
226
|
const message = () => `Ask ${brand()}`;
|
|
227
|
-
/** The line every answer is sent under, above the composer, as the reference sets it. */
|
|
228
|
-
const caution = () => `${brand()} can make mistakes. Check important info.`;
|
|
229
227
|
/** The panel offers no kinds of its own in Chat: its tabs are pages. */
|
|
230
228
|
const NONE = [];
|
|
231
229
|
/** The id the room's system turn is held under in the thread. */
|
|
@@ -527,8 +525,10 @@ function Thread({ placeholder = message(), initial, anonymous = false, heading,
|
|
|
527
525
|
setDraft: (x) => lent.current.setDraft(x),
|
|
528
526
|
attach: (f) => lent.current.attach(f),
|
|
529
527
|
go: (href) => (/^https?:/.test(href) ? void window.open(href, "_blank", "noopener,noreferrer") : go(href)),
|
|
530
|
-
});
|
|
528
|
+
}, CHAT_MODES);
|
|
531
529
|
const agentShelf = useAgentShelf();
|
|
530
|
+
// The opening greets the person by their first name, as their account spells it.
|
|
531
|
+
const firstName = useMemo(() => (anonymous ? "" : ((named()?.name ?? "").trim().split(/\s+/)[0] ?? "")), [anonymous]);
|
|
532
532
|
// Up to three things worth doing next, from the person's own activity (@hanzo/build).
|
|
533
533
|
const hints = useSuggestions(target);
|
|
534
534
|
// THE HEADER'S ⋯ IS THE ROW'S MENU (thread.tsx): rename, pin, share, its
|
|
@@ -1362,7 +1362,6 @@ function Thread({ placeholder = message(), initial, anonymous = false, heading,
|
|
|
1362
1362
|
ready: Boolean(draft.trim() || files.length),
|
|
1363
1363
|
// `label` keeps the accessible name constant; the placeholder is the composer's own.
|
|
1364
1364
|
label: ASK,
|
|
1365
|
-
note: caution(),
|
|
1366
1365
|
// A phone's pill is the tall one: the field across the top, the controls under it.
|
|
1367
1366
|
narrow: !media.sm,
|
|
1368
1367
|
// In the app's frame the composer floats on the pane as a pane of its own.
|
|
@@ -1411,7 +1410,7 @@ function Thread({ placeholder = message(), initial, anonymous = false, heading,
|
|
|
1411
1410
|
],
|
|
1412
1411
|
slash: anonymous ? undefined : carry.skills,
|
|
1413
1412
|
at: anonymous ? undefined : carry.plugins,
|
|
1414
|
-
mode: anonymous ? null :
|
|
1413
|
+
mode: anonymous ? null : carry.mode,
|
|
1415
1414
|
// The model, the effort and the mode under the frame (@hanzo/build).
|
|
1416
1415
|
mind,
|
|
1417
1416
|
limits,
|
|
@@ -1530,10 +1529,10 @@ function Thread({ placeholder = message(), initial, anonymous = false, heading,
|
|
|
1530
1529
|
// with it when it did. `Ask` passes its own, because the page embedding
|
|
1531
1530
|
// it already has an `<h1>` and a second is the defect that took the
|
|
1532
1531
|
// landings off /chat and /dev.
|
|
1533
|
-
empty: heading === null ? undefined : (_jsxs(YStack, { "data-slot": "opening", items: "center", width: "100%",
|
|
1532
|
+
empty: heading === null ? undefined : (_jsxs(YStack, { "data-slot": "opening", items: "center", width: "100%", pt: "$6", pb: "$2", ...(media.sm ? null : { flex: 1, justify: "center" }), children: [room.length > 1 ? (_jsx(XStack, { items: "center", justify: "center", mb: "$4", children: room.map((name, i) => (_jsx(Box, { ml: i ? -16 : 0, rounded: 40, borderWidth: 2, borderColor: "$background", z: room.length - i, children: _jsx(Face, { src: faces[name]?.avatar, emoji: faces[name]?.emoji, name: name, size: 72 }) }, name))) })) : portrait ? (_jsx(Box, { width: 160, height: 160, rounded: 24, overflow: "hidden", borderWidth: 2, borderColor: "var(--white-15)", boxShadow: "0 10px 24px color-mix(in srgb, var(--pure-black) 70%, transparent)", mb: "$4", bg: "var(--neutral-900)", children: _jsx(View, { render: _jsx("img", { src: portrait, alt: withWhom }), width: "100%", height: "100%", objectFit: "cover" }) })) : null, room.length === 1 && !portrait ? (_jsx(Box, { mb: "$3", children: _jsx(Face, { emoji: mate?.emoji ?? persona?.emoji, name: withWhom, size: 72 }) })) : null, _jsx(Text, { render: "h1", fontSize: "$7", lineHeight: "$7", fontWeight: "700", color: "$ink", text: "center", mb: "$1", children: join(room) || heading || (firstName ? `What’s up, ${firstName}?` : "What’s up?") }), room.length === 1 && (mate?.description ?? persona?.description) ? (_jsx(Text, { fontSize: "$3", color: "$soft", text: "center", maxW: 500, mb: "$4", lineHeight: "$4", children: mate?.description ?? persona?.description })) : null] })),
|
|
1534
1533
|
// The transcript reads at the same measure. `Thread` defaults to 768
|
|
1535
1534
|
// itself; handing it the column here is what lets Width reach it.
|
|
1536
|
-
column: { maxW: MEASURE }, composer: prompt({ ...composing, field: mention.field }, mention.state) }), _jsx(AgentMaker, {}), carry.dialog,
|
|
1535
|
+
column: { maxW: MEASURE }, composer: prompt({ ...composing, field: mention.field }, mention.state) }), _jsx(AgentMaker, {}), carry.dialog, _jsx(XStack, { items: "center", justify: "center", py: "$1", px: "$3", gap: "$2", children: isFree(model) ? (_jsxs(Text, { fontSize: "$1", color: "$soft", children: ["Free chat is data-shared to train models.", " ", _jsx(Anchor, { href: site("/legal/privacy"), fontSize: "$1", color: "$ink", children: "Privacy" })] })) : (_jsxs(_Fragment, { children: [_jsx(Anchor, { href: site("/legal/terms"), fontSize: "$1", color: "$soft", children: "Terms" }), _jsx(Text, { fontSize: "$1", color: "$soft", children: "\u00B7" }), _jsx(Anchor, { href: site("/legal/privacy"), fontSize: "$1", color: "$soft", children: "Privacy" })] })) }), consent, _jsx(Upgrade, { ask: ask, onClose: () => setAsk(null) })] }));
|
|
1537
1536
|
}
|
|
1538
1537
|
/** The agreement free asks for, in @hanzo/ai's words so every surface says one thing. */
|
|
1539
1538
|
function Consent({ question, onAgree, onCancel, }) {
|
package/dist/Column.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { type Host } from '@hanzo/build';
|
|
|
2
2
|
import { type RailLink } from '@hanzo/ui/chat';
|
|
3
3
|
import { type ReactNode } from 'react';
|
|
4
4
|
import { type Place } from './lib/host.js';
|
|
5
|
-
export declare function Column({ host, mode, thread, go, onShut, onSeek, drawer, foot, places, }: {
|
|
5
|
+
export declare function Column({ host, mode, thread, go, onShut, onSeek, onBack, drawer, foot, places, }: {
|
|
6
6
|
host: Host;
|
|
7
7
|
mode: Place['mode'];
|
|
8
8
|
/** The Chat conversation the pane holds, or null. */
|
|
@@ -13,6 +13,8 @@ export declare function Column({ host, mode, thread, go, onShut, onSeek, drawer,
|
|
|
13
13
|
onShut: () => void;
|
|
14
14
|
/** Opens the palette. */
|
|
15
15
|
onSeek?: () => void;
|
|
16
|
+
/** Leaves a place that took the sidebar, for where the reader was before it. */
|
|
17
|
+
onBack: () => void;
|
|
16
18
|
/** Drawn in the phone's drawer: no edge, cut as a floating pane. */
|
|
17
19
|
drawer?: boolean;
|
|
18
20
|
/** What stands at its foot: the drawer's rail, laid flat. */
|
package/dist/Column.js
CHANGED
|
@@ -12,21 +12,24 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
12
12
|
// that moved last, each one press from its page, and Notifications in Settings.
|
|
13
13
|
// The search opens the palette (Palette.tsx; ⌘K / Ctrl+K from anywhere).
|
|
14
14
|
//
|
|
15
|
-
// Dev's places are @hanzo/build's `
|
|
16
|
-
//
|
|
15
|
+
// Dev's places are @hanzo/build's `own`: New run, Projects, Issues, Templates.
|
|
16
|
+
// A place the rail holds (Library, Scheduled tasks, Customize) and Settings
|
|
17
|
+
// each take the sidebar instead (Rail.tsx `spot`): Back, the place's name, and
|
|
18
|
+
// its own rows (Settings' sections, Customize's tabs), never Dev's beside them.
|
|
17
19
|
//
|
|
18
20
|
// Its width is the edge's in the gutter to its right: dragged, keyed or
|
|
19
21
|
// double-clicked back (@hanzo/build's `Grip`), kept per browser. Pulled in past
|
|
20
22
|
// its floor it shuts (`onShut`), as the sidebar's toggle shuts it.
|
|
21
23
|
import { Text, XStack, YStack } from '@hanzo/gui';
|
|
22
|
-
import { Bell, Search, Settings2, SquarePen } from 'lucide-react';
|
|
23
|
-
import { DOTS,
|
|
24
|
+
import { ArrowLeft, Bell, Search, Settings2, SquarePen } from 'lucide-react';
|
|
25
|
+
import { DOTS, Gutter, NEW, own, path as written, sections, tabs, useSessions } from '@hanzo/build';
|
|
24
26
|
import { tidy } from './lib/title.js';
|
|
25
27
|
import { DropdownMenu } from '@hanzo/ui';
|
|
26
28
|
import { Sidebar, SidebarIconButton, SidebarItem, StatusDot } from '@hanzo/ui/chat';
|
|
27
29
|
import { useId } from 'react';
|
|
28
30
|
import { Made } from './Me.js';
|
|
29
31
|
import { Recents } from './Recents.js';
|
|
32
|
+
import { spot } from './Rail.js';
|
|
30
33
|
import { Setup } from './Setup.js';
|
|
31
34
|
import { ago } from './recent.js';
|
|
32
35
|
import { empty } from './open.js';
|
|
@@ -34,9 +37,6 @@ import { useSpan } from './span.js';
|
|
|
34
37
|
import { pane } from './ground.js';
|
|
35
38
|
import { talk } from './lib/host.js';
|
|
36
39
|
import { brand, wordmark } from './where.js';
|
|
37
|
-
/** The grip stands in the gutter between the sidebar and the panel. gui carries a `calc()` to the page unchanged; its
|
|
38
|
-
* types only name custom properties. */
|
|
39
|
-
const GUTTER_END = 'calc(-1 * var(--pane-gap))';
|
|
40
40
|
/** The sidebar fills the column. Its `width` is typed in px alone, though its frame takes any gui size — the type is
|
|
41
41
|
* @hanzo/ui's to widen. */
|
|
42
42
|
const FILL = { width: '100%' };
|
|
@@ -69,6 +69,8 @@ const keys = (press) => ({
|
|
|
69
69
|
const ROW = { rounded: '$4', minH: 31, py: 0, px: '$2' };
|
|
70
70
|
/** The run activity behind the bell: the runs that moved last, newest first. */
|
|
71
71
|
const RECENT = 6;
|
|
72
|
+
/** What a place that takes the sidebar is called at its head. */
|
|
73
|
+
const TITLE = { library: 'Library', scheduled: 'Scheduled tasks', customize: 'Customize', settings: 'Settings' };
|
|
72
74
|
/** A header mark: a 16px glyph in a 32px target. */
|
|
73
75
|
const HEAD = { width: 32, height: 32, rounded: '$3' };
|
|
74
76
|
function Activity({ host }) {
|
|
@@ -90,12 +92,13 @@ function Activity({ host }) {
|
|
|
90
92
|
];
|
|
91
93
|
return (_jsx(DropdownMenu, { minWidth: 280, trigger: _jsx(XStack, { render: "button", "aria-label": "Activity", ...{ title: 'Activity' }, ...HEAD, items: "center", justify: "center", cursor: "pointer", opacity: 0.7, hoverStyle: { bg: '$hover', opacity: 1 }, focusVisibleStyle: { outlineWidth: 2, outlineStyle: 'solid', outlineColor: '$outlineColor' }, children: _jsx(Bell, { size: 16, "aria-hidden": true }) }), items: items }));
|
|
92
94
|
}
|
|
93
|
-
export function Column({ host, mode, thread, go, onShut, onSeek, drawer = false, foot, places, }) {
|
|
95
|
+
export function Column({ host, mode, thread, go, onShut, onSeek, onBack, drawer = false, foot, places, }) {
|
|
94
96
|
// The desktop sidebar and a phone's drawer can both be in the page: each names its own group labels.
|
|
95
97
|
const uid = useId();
|
|
96
98
|
const span = useSpan(SPAN, WIDTH, FLOOR, CEIL);
|
|
97
99
|
const dev = (p) => host.go(p);
|
|
98
|
-
const
|
|
100
|
+
const at = mode === 'dev' ? spot(host.path) : null;
|
|
101
|
+
const groups = places ?? (at === 'settings' ? sections(host, dev) : at === 'customize' ? tabs(host, dev) : at ? [] : own(host, dev));
|
|
99
102
|
const open = (row) => (row.kind === 'chat' ? go(talk(row.id)) : dev(row.id));
|
|
100
103
|
// Chat's New; Dev's is the first of its places.
|
|
101
104
|
const create = () => {
|
|
@@ -104,7 +107,5 @@ export function Column({ host, mode, thread, go, onShut, onSeek, drawer = false,
|
|
|
104
107
|
};
|
|
105
108
|
return (_jsxs(YStack, { "data-slot": "app-column", ref: drawer ? undefined : span.ref,
|
|
106
109
|
// inline-style: `--span`, the width a drag rewrites on the element itself (span.ts); no prop sets a variable.
|
|
107
|
-
style: drawer ? undefined : span.style, position: "relative", flex: drawer ? 1 : undefined, shrink: drawer ? 1 : 0, minW: 0, height: "100%", width: drawer ? undefined : 'var(--span)', children: [_jsxs(Sidebar, { "data-slot": "app-rail", role: "navigation", "aria-label": brand(), ...(drawer ? { ...pane(), ...FLOAT } : { bg: 'transparent', borderWidth: 0 }), ...FILL, px: "$2", pt: drawer ? '$2' : 0, pb: "$2", gap: "$0", children: [_jsxs(XStack, { "data-slot": "app-head", items: "center", gap: "$1", pl: "$2", pr: 2, height: 52, shrink: 0, minW: 0, children: [_jsx(Text, { flex: 1, minW: 0, fontSize: 18, lineHeight: 24, fontWeight: "600", color: "$ink", numberOfLines: 1, children: wordmark(mode) }), _jsx(Activity, { host: host }), _jsx(SidebarIconButton, { label: "Search", onPress: onSeek, "aria-haspopup": "dialog", ...HEAD, children: _jsx(Search, { size: 16, "aria-hidden": true }) })] }), mode === 'chat' ? (_jsx(YStack, { role: "list", gap: 2, shrink: 0, children: _jsx(YStack, { role: "listitem", children: _jsx(SidebarItem, { "data-slot": "app-new", ...ROW, active: !thread, bg: "transparent", hoverStyle: { bg: '$hover' }, icon: _jsx(SquarePen, { size: 16, "aria-hidden": true }), onPress: create, ...keys(create), children: _jsx(Text, { fontSize: "$3", color: "$ink", children: "New chat" }) }) }) })) : (_jsx(YStack, { "data-slot": "app-places", shrink: 0, children: groups.map((g, i) => (_jsxs(YStack, { pt: i ? '$2' : 0, children: [i ? (_jsx(Text, { id: `${uid}-${g.id}`, pl: "$2", pb: 2, fontSize: "$3", color: "$soft", children: g.label })) : null, _jsx(YStack, { role: "list", "aria-labelledby": i ? `${uid}-${g.id}` : undefined, "aria-label": i ? undefined : g.label, gap: 1, children: g.links.map((link) => (_jsx(YStack, { role: "listitem", children: _jsx(SidebarItem, { ...ROW, ...(link.id === NEW ? { 'data-slot': 'app-new' } : {}), active: link.active, icon: link.id === NEW ? _jsx(SquarePen, { size: 16, "aria-hidden": true }) : link.icon, onPress: link.onPress, ...keys(() => link.onPress?.()), children: _jsx(Text, { fontSize: "$3", color: link.active ? '$ink' : '$quiet', children: link.label }) }) }, link.id))) })] }, g.id))) })), mode === 'studio' ? null : _jsx(Recents, { host: host, mode: mode, thread: thread, onOpen: open, onNew: create }), _jsxs(YStack, { gap: "$2", pt: "$2", shrink: 0, children: [_jsx(Made, {}), _jsx(Setup, {})] }), foot] }), drawer ? null : (_jsx(
|
|
108
|
-
// In the gutter between the sidebar and the panel, not over the sidebar's own rows.
|
|
109
|
-
r: GUTTER_END, width: "var(--pane-gap)" }))] }));
|
|
110
|
+
style: drawer ? undefined : span.style, position: "relative", flex: drawer ? 1 : undefined, shrink: drawer ? 1 : 0, minW: 0, height: "100%", width: drawer ? undefined : 'var(--span)', children: [_jsxs(Sidebar, { "data-slot": "app-rail", role: "navigation", "aria-label": brand(), ...(drawer ? { ...pane(), ...FLOAT } : { bg: 'transparent', borderWidth: 0 }), ...FILL, px: "$2", pt: drawer ? '$2' : 0, pb: "$2", gap: "$0", children: [at ? (_jsxs(XStack, { "data-slot": "app-head", items: "center", gap: "$1", pl: 2, pr: 2, height: 52, shrink: 0, minW: 0, children: [_jsx(SidebarIconButton, { label: "Back", "data-slot": "place-back", onPress: onBack, ...HEAD, children: _jsx(ArrowLeft, { size: 16, "aria-hidden": true }) }), _jsx(Text, { flex: 1, minW: 0, fontSize: 18, lineHeight: 24, fontWeight: "600", color: "$ink", numberOfLines: 1, "data-slot": "place-name", children: TITLE[at] })] })) : (_jsxs(XStack, { "data-slot": "app-head", items: "center", gap: "$1", pl: "$2", pr: 2, height: 52, shrink: 0, minW: 0, children: [_jsx(Text, { flex: 1, minW: 0, fontSize: 18, lineHeight: 24, fontWeight: "600", color: "$ink", numberOfLines: 1, children: wordmark(mode) }), _jsx(Activity, { host: host }), _jsx(SidebarIconButton, { label: "Search", onPress: onSeek, "aria-haspopup": "dialog", ...HEAD, children: _jsx(Search, { size: 16, "aria-hidden": true }) })] })), mode === 'chat' ? (_jsx(YStack, { role: "list", gap: 2, shrink: 0, children: _jsx(YStack, { role: "listitem", children: _jsx(SidebarItem, { "data-slot": "app-new", ...ROW, active: !thread, bg: "transparent", hoverStyle: { bg: '$hover' }, icon: _jsx(SquarePen, { size: 16, "aria-hidden": true }), onPress: create, ...keys(create), children: _jsx(Text, { fontSize: "$3", color: "$ink", children: "New chat" }) }) }) })) : (_jsx(YStack, { "data-slot": "app-places", shrink: 0, children: groups.map((g, i) => (_jsxs(YStack, { pt: i ? '$2' : 0, children: [i && g.label ? (_jsx(Text, { id: `${uid}-${g.id}`, pl: "$2", pb: 2, fontSize: "$3", color: "$soft", children: g.label })) : null, _jsx(YStack, { role: "list", "aria-labelledby": i && g.label ? `${uid}-${g.id}` : undefined, "aria-label": i && g.label ? undefined : g.label || (at ? TITLE[at] : g.id), gap: 1, children: g.links.map((link) => (_jsx(YStack, { role: "listitem", children: _jsx(SidebarItem, { ...ROW, ...(link.id === NEW ? { 'data-slot': 'app-new' } : {}), active: link.active, icon: link.id === NEW ? _jsx(SquarePen, { size: 16, "aria-hidden": true }) : link.icon, onPress: link.onPress, ...keys(() => link.onPress?.()), children: _jsx(Text, { fontSize: "$3", color: link.active ? '$ink' : '$quiet', children: link.label }) }) }, link.id))) })] }, g.id))) })), mode === 'studio' || at ? null : _jsx(Recents, { host: host, mode: mode, thread: thread, onOpen: open, onNew: create }), at ? null : (_jsxs(YStack, { gap: "$2", pt: "$2", shrink: 0, children: [_jsx(Made, {}), _jsx(Setup, {})] })), foot] }), drawer ? null : (_jsx(Gutter, { side: "left", span: span.span, floor: FLOOR, ceil: CEIL, reset: WIDTH, onSpan: span.move, onKeep: span.keep, onShut: onShut, label: "Resize sidebar" }))] }));
|
|
110
111
|
}
|
package/dist/Me.js
CHANGED
|
@@ -39,6 +39,7 @@ import { list } from './lib/list.js';
|
|
|
39
39
|
import { choose, org as current, orgs, pick, renew, scope, superAdmin } from './lib/session.js';
|
|
40
40
|
import { ENTRY } from './lib/host.js';
|
|
41
41
|
import { leave } from './dev.js';
|
|
42
|
+
import { payUrl } from './lib/pay.js';
|
|
42
43
|
import { asked, KEYS, legal, out, pages } from './help.js';
|
|
43
44
|
import { showSettings } from './open.js';
|
|
44
45
|
import { site, where } from './where.js';
|
|
@@ -146,9 +147,20 @@ export function Me({ host, narrow = false, above = false, onOrg, }) {
|
|
|
146
147
|
const target = useMemo(() => ({ api: host.api, token: host.token, org: host.org }), [host.api, host.token, host.org]);
|
|
147
148
|
const read = useStanding(target, open);
|
|
148
149
|
const other = usePlan(personal && personal.name !== current ? personal.name : null, open);
|
|
150
|
+
// THE TWO ACCOUNTS, apart: the organization's plan (hanzo · Enterprise) and the
|
|
151
|
+
// person's own (Personal · Pro, or none and the way to one). A business plan is
|
|
152
|
+
// the organization's; a personal plan is held beside it, never instead of it.
|
|
153
|
+
const team = here && !here.personal ? here : (all.find((o) => !o.personal) ?? null);
|
|
154
|
+
const teamOther = usePlan(team && team.name !== current ? team.name : null, open);
|
|
149
155
|
const planFor = (o) => (o.name === current ? spoken(read.value?.label ?? null) : o.personal ? other : '');
|
|
150
156
|
const who = host.person?.name || host.person?.email || '';
|
|
151
157
|
const plan = spoken(read.value?.label ?? null);
|
|
158
|
+
const teamPlan = team ? (team.name === current ? plan : teamOther) : '';
|
|
159
|
+
const ownPlan = personal ? (personal.name === current ? plan : other) : '';
|
|
160
|
+
// Where the reader works, and on what: "hanzo · Enterprise", "Personal · Pro".
|
|
161
|
+
const working = [here ? (here.personal ? 'Personal' : here.display) : current, plan].filter(Boolean).join(' · ');
|
|
162
|
+
// A personal plan is bought for the personal organization, beside any business one.
|
|
163
|
+
const getPro = () => personal && window.location.assign(payUrl('/cart', { plan: 'pro', org: personal.name, returnUrl: window.location.href }));
|
|
152
164
|
const apple = mac();
|
|
153
165
|
useEffect(() => {
|
|
154
166
|
if (above)
|
|
@@ -180,9 +192,11 @@ export function Me({ host, narrow = false, above = false, onOrg, }) {
|
|
|
180
192
|
return;
|
|
181
193
|
setAccount(false);
|
|
182
194
|
setHelp(false);
|
|
183
|
-
}, placement: narrow && !above ? 'right-end' : above ? 'top-end' : 'top-start',
|
|
195
|
+
}, placement: narrow && !above ? 'right-end' : above ? 'top-end' : 'top-start',
|
|
196
|
+
// Clear of the rail's mark (or the row) it opens from, and flush with its foot.
|
|
197
|
+
offset: 8, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(XStack, { ref: (el) => {
|
|
184
198
|
row.current = el instanceof HTMLElement ? el : null;
|
|
185
|
-
}, render: "button", "data-slot": "me", "aria-label": `Account: ${[who, current].filter(Boolean).join(' · ')}`, ...{ title: who }, width: narrow ? 36 : '100%', minH: narrow ? 36 : 48, px: narrow ? 0 : '$2', gap: "$2.5", rounded: narrow ? 999 : '$5', items: "center", justify: narrow ? 'center' : 'flex-start', hoverStyle: { bg: '$hover' }, focusVisibleStyle: { outlineWidth: 2, outlineStyle: 'solid', outlineColor: '$outlineColor' }, cursor: "pointer", children: [_jsx(Face, { host: host, size: narrow ? 26 : 32 }), narrow ? null : (_jsxs(_Fragment, { children: [_jsxs(YStack, { flex: 1, minW: 0, children: [_jsx(SizableText, { size: "$3", fontWeight: "600", color: "$ink", numberOfLines: 1, text: "left", children: who }),
|
|
199
|
+
}, render: "button", "data-slot": "me", "aria-label": `Account: ${[who, current].filter(Boolean).join(' · ')}`, ...{ title: who }, width: narrow ? 36 : '100%', minH: narrow ? 36 : 48, px: narrow ? 0 : '$2', gap: "$2.5", rounded: narrow ? 999 : '$5', items: "center", justify: narrow ? 'center' : 'flex-start', hoverStyle: { bg: '$hover' }, focusVisibleStyle: { outlineWidth: 2, outlineStyle: 'solid', outlineColor: '$outlineColor' }, cursor: "pointer", children: [_jsx(Face, { host: host, size: narrow ? 26 : 32 }), narrow ? null : (_jsxs(_Fragment, { children: [_jsxs(YStack, { flex: 1, minW: 0, children: [_jsx(SizableText, { size: "$3", fontWeight: "600", color: "$ink", numberOfLines: 1, text: "left", children: who }), working ? (_jsx(SizableText, { size: "$1", color: "$soft", numberOfLines: 1, text: "left", children: working })) : null] }), _jsx(ChevronsUpDown, { size: 14, "aria-hidden": true, opacity: 0.6 })] }))] }) }), _jsxs(DropdownMenuContent, { minW: 260, maxW: "calc(100vw - 16px)", "aria-labelledby": undefined, "aria-label": "Account", onCloseAutoFocus: back, children: [_jsxs(DropdownMenuSub, { open: account, onOpenChange: setAccount, children: [_jsxs(DropdownMenuSubTrigger, { minH: 48, gap: "$2.5", children: [_jsx(Face, { host: host, size: 28 }), _jsxs(YStack, { flex: 1, minW: 0, children: [_jsx(SizableText, { size: "$2", fontWeight: "600", color: "$ink", numberOfLines: 1, children: who }), _jsx(SizableText, { size: "$1", color: "$soft", numberOfLines: 1, children: host.person.email || working })] })] }), account ? (_jsxs(DropdownMenuSubContent, { minW: 260, maxW: "calc(100vw - 16px)", pointerEvents: "auto", children: [_jsx(Meter, { read: read, onPlans: () => leave('here'), onBilling: () => (setOpen(false), showSettings('billing')) }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuLabel, { children: "Organizations" }), all.map((o) => (_jsx(DropdownMenuItem, { onSelect: () => o.name !== current && onOrg(o.name), children: _jsx(Line, { icon: _jsx(Mark, { org: o }), sub: [o.personal ? 'Personal' : said(o.role), planFor(o)].filter(Boolean).join(' · '), trail: o.name === current ? _jsx(Check, { size: 16, "aria-label": "Current" }) : null, children: o.display }) }, o.name))), _jsx(DropdownMenuItem, { onSelect: () => setCreating(true), children: _jsx(Line, { icon: _jsx(Plus, { size: 16, "aria-hidden": true }), children: "Create organization" }) }), _jsx(DropdownMenuItem, { onSelect: () => window.location.assign(site(ORG_SETTINGS)), children: _jsx(Line, { icon: _jsx(Settings, { size: 16, "aria-hidden": true }), children: "Organization settings" }) }), where().team ? null : here && !here.personal ? (_jsx(DropdownMenuItem, { onSelect: () => out(`${ENTRY}&org=${encodeURIComponent(here.name)}`), children: _jsx(Line, { icon: _jsx(Users, { size: 16, "aria-hidden": true }), trail: _jsx(ArrowUpRight, { size: 14, "aria-hidden": true, opacity: 0.6 }), children: "Open in Hanzo Team" }) })) : (_jsx(DropdownMenuItem, { onSelect: () => setCreating(true), children: _jsx(Line, { icon: _jsx(Users, { size: 16, "aria-hidden": true }), children: "Create a team" }) })), superAdmin() ? (_jsx(DropdownMenuItem, { onSelect: choose, children: _jsx(Line, { icon: _jsx(Building2, { size: 16, "aria-hidden": true }), children: "All organizations" }) })) : null] })) : null] }), team ? (_jsx(DropdownMenuItem, { "data-slot": "me-team", onSelect: () => team.name !== current && onOrg(team.name), children: _jsx(Line, { icon: _jsx(Mark, { org: team }), trail: team.name === current ? _jsx(Check, { size: 16, "aria-label": "Current" }) : null, children: `${team.display} · ${teamPlan || 'No plan'}` }) })) : null, personal ? (_jsx(DropdownMenuItem, { "data-slot": "me-personal", onSelect: () => personal.name !== current && onOrg(personal.name), actionsVisibility: "always", actions: ownPlan ? undefined : (_jsx(Button, { size: "xs", variant: "outline", onPress: getPro, children: "Get Pro" })), children: _jsx(Line, { icon: _jsx(CircleUserRound, { size: 16, "aria-hidden": true }), trail: personal.name === current ? _jsx(Check, { size: 16, "aria-label": "Current" }) : null, children: `Personal · ${ownPlan || 'No plan'}` }) })) : null, _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuItem, { onSelect: () => leave('here'), children: _jsx(Line, { icon: _jsx(Sparkles, { size: 16, "aria-hidden": true }), children: upgrade(read.value?.label?.name) }) }), _jsx(DropdownMenuItem, { onSelect: () => showSettings('general'), children: _jsx(Line, { icon: _jsx(Palette, { size: 16, "aria-hidden": true }), children: "Personalization" }) }), _jsx(DropdownMenuItem, { onSelect: () => showSettings('account'), children: _jsx(Line, { icon: _jsx(CircleUserRound, { size: 16, "aria-hidden": true }), children: "Profile" }) }), _jsx(DropdownMenuItem, { "aria-keyshortcuts": "Control+, Meta+,", onSelect: () => showSettings('general'), children: _jsx(Line, { icon: _jsx(Settings, { size: 16, "aria-hidden": true }), trail: _jsx(DropdownMenuShortcut, { "aria-hidden": true, children: apple ? '⌘,' : 'Ctrl+,' }), children: "Settings" }) }), _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuSub, { open: help, onOpenChange: setHelp, children: [_jsx(DropdownMenuSubTrigger, { children: _jsx(Line, { icon: _jsx(LifeBuoy, { size: 16, "aria-hidden": true }), children: "Help" }) }), help ? (_jsxs(DropdownMenuSubContent, { minW: 240, maxW: "calc(100vw - 16px)", pointerEvents: "auto", children: [pages().map((p) => (_jsx(DropdownMenuItem, { onSelect: () => out(p.href), children: _jsx(Line, { icon: ICONS[p.key], trail: p.key === 'help' ? _jsx(ArrowUpRight, { size: 14, "aria-hidden": true, opacity: 0.6 }) : null, children: p.label }) }, p.key))), _jsx(DropdownMenuItem, { "aria-keyshortcuts": "Control+/ Meta+/", onSelect: () => setKeys(true), children: _jsx(Line, { icon: _jsx(Keyboard, { size: 16, "aria-hidden": true }), trail: _jsx(DropdownMenuShortcut, { "aria-hidden": true, children: apple ? '⌘/' : 'Ctrl+/' }), children: "Keyboard shortcuts" }) }), _jsx(DropdownMenuSeparator, {}), legal().map((p) => (_jsx(DropdownMenuItem, { onSelect: () => out(p.href), children: _jsx(Line, { icon: ICONS[p.key], children: p.label }) }, p.key)))] })) : null] }), host.signOut ? (_jsx(DropdownMenuItem, { onSelect: () => host.signOut?.(), children: _jsx(Line, { icon: _jsx(LogOut, { size: 16, "aria-hidden": true }), children: "Log out" }) })) : null] })] }), _jsx(Create, { open: creating, onOpenChange: setCreating }), _jsx(Shortcuts, { open: keys, onOpenChange: setKeys, apple: apple })] }));
|
|
186
200
|
}
|
|
187
201
|
/** The app's keys (help.ts `KEYS`), one row each, spelled for this platform. */
|
|
188
202
|
function Shortcuts({ open, onOpenChange, apple }) {
|
package/dist/Rail.d.ts
CHANGED
|
@@ -3,6 +3,19 @@ import { type Host } from '@hanzo/build';
|
|
|
3
3
|
import { type Place } from './lib/host.js';
|
|
4
4
|
/** The rail's width, px. */
|
|
5
5
|
export declare const RAIL = 48;
|
|
6
|
+
/** The places the rail holds beside the products, by the builder address each opens. */
|
|
7
|
+
export declare const RAISED: {
|
|
8
|
+
readonly library: '-/artifacts';
|
|
9
|
+
readonly scheduled: '-/automations';
|
|
10
|
+
readonly customize: '-/customize';
|
|
11
|
+
};
|
|
12
|
+
export type Raised = keyof typeof RAISED;
|
|
13
|
+
/** A place that takes the sidebar: one of the rail's, or Settings (the account menu's). */
|
|
14
|
+
export type Spot = Raised | 'settings';
|
|
15
|
+
/** The place a builder address stands on, if it is one that takes the sidebar. */
|
|
16
|
+
export declare const spot: (at: string | null) => Spot | null;
|
|
17
|
+
/** Which of them a builder address stands on, if any: an agent's page is Customize's, an automation Scheduled tasks'. */
|
|
18
|
+
export declare function raised(at: string | null): Raised | null;
|
|
6
19
|
/** One mark: an icon button named for where it goes, its name its tooltip, lit where the reader is. */
|
|
7
20
|
export declare function Mark({ label, on, onPress, children, ...rest }: {
|
|
8
21
|
label: string;
|
|
@@ -18,9 +31,11 @@ export declare function Toggle({ open, onPress, label }: {
|
|
|
18
31
|
onPress: () => void;
|
|
19
32
|
label?: string;
|
|
20
33
|
}): import("react").JSX.Element;
|
|
21
|
-
export declare function Rail({ host, mode, open, toggle, flat, onChat, onDev, onStudio, onOrg, }: {
|
|
34
|
+
export declare function Rail({ host, mode, at, open, toggle, flat, onChat, onDev, onStudio, go, onOrg, }: {
|
|
22
35
|
host: Host;
|
|
23
36
|
mode: Place['mode'];
|
|
37
|
+
/** Dev's builder address, or null outside Dev. */
|
|
38
|
+
at: string | null;
|
|
24
39
|
/** The sidebar beside the rail is open. */
|
|
25
40
|
open: boolean;
|
|
26
41
|
/** Lead with the sidebar's toggle; absent where the host's bar holds it. */
|
|
@@ -31,6 +46,8 @@ export declare function Rail({ host, mode, open, toggle, flat, onChat, onDev, on
|
|
|
31
46
|
onChat: () => void;
|
|
32
47
|
onDev: () => void;
|
|
33
48
|
onStudio: () => void;
|
|
49
|
+
/** Moves the app to an address of this page. */
|
|
50
|
+
go: (address: string) => void;
|
|
34
51
|
/** Work in another organization. */
|
|
35
52
|
onOrg: (org: string) => void;
|
|
36
53
|
}): import("react").JSX.Element;
|
package/dist/Rail.js
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
// The app's rail: its products as marks down the window's left edge, in one
|
|
4
|
-
// order — Chat, Dev, Studio — then More, a
|
|
5
|
-
// their own, and the account at the foot. It
|
|
6
|
-
// products; a phone, which has no rail,
|
|
7
|
-
// (Top.tsx).
|
|
4
|
+
// order — Chat, Dev, Studio, Library, Scheduled tasks, Customize — then More, a
|
|
5
|
+
// menu of the products on hosts of their own, and the account at the foot. It
|
|
6
|
+
// is how the app moves between its products; a phone, which has no rail,
|
|
7
|
+
// switches Chat and Dev in its bar (Top.tsx).
|
|
8
8
|
//
|
|
9
9
|
// Studio is the app's third mode (@hanzo/studio at /studio), each of the three
|
|
10
10
|
// opened where the reader left it.
|
|
11
11
|
//
|
|
12
|
-
// A mark is a
|
|
13
|
-
// conversations, Dev its places (@hanzo/build
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
12
|
+
// A mark is a place, and a place owns the sidebar beside the rail: Chat its
|
|
13
|
+
// conversations, Dev its own places (@hanzo/build `own`: New run, Projects,
|
|
14
|
+
// Issues, Templates) and its runs, Studio its own; Library, Scheduled tasks and
|
|
15
|
+
// Customize (@hanzo/build's Artifacts, Automations and Customize) each their
|
|
16
|
+
// own, and Settings its sections (Column.tsx). Nothing on the rail is listed
|
|
17
|
+
// inside Dev: one level of the app a place, each lit while the reader is on it.
|
|
17
18
|
//
|
|
18
19
|
// It stands on the frame's floor, never cut as a pane (ground.ts): the rail and
|
|
19
20
|
// the sidebar beside it are the window, and the content is the panel inset in
|
|
@@ -22,17 +23,37 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
22
23
|
// The sidebar's toggle leads it (`toggle`) where the host has no bar of its own:
|
|
23
24
|
// a browser tab. A host that is a window draws the toggle in its bar beside Back
|
|
24
25
|
// and Forward (App.tsx `bar`), and its rail starts with Chat. On a phone the
|
|
25
|
-
// rail lies along the foot of the drawer (`flat`), the account at its end
|
|
26
|
-
|
|
26
|
+
// rail lies along the foot of the drawer (`flat`), the account at its end; the
|
|
27
|
+
// drawer is too narrow for every mark, so Library, Scheduled tasks and
|
|
28
|
+
// Customize lead More there.
|
|
29
|
+
import { Clock, Code2, Ellipsis, Library, MessageSquare, PanelLeft, Puzzle, SquareTerminal, Users, WandSparkles } from 'lucide-react';
|
|
27
30
|
import { XStack, YStack } from '@hanzo/gui';
|
|
31
|
+
import { route } from '@hanzo/build';
|
|
28
32
|
import { DropdownMenu } from '@hanzo/ui';
|
|
29
33
|
import { out } from './help.js';
|
|
30
34
|
import { Me } from './Me.js';
|
|
31
|
-
import { TABS, WORKSPACE } from './lib/host.js';
|
|
35
|
+
import { app, TABS, WORKSPACE } from './lib/host.js';
|
|
32
36
|
/** The rail's width, px. */
|
|
33
37
|
export const RAIL = 48;
|
|
34
38
|
/** A mark, px: a 36px square on a 44px pitch. */
|
|
35
39
|
const MARK = 36;
|
|
40
|
+
/** The places the rail holds beside the products, by the builder address each opens. */
|
|
41
|
+
export const RAISED = { library: '-/artifacts', scheduled: '-/automations', customize: '-/customize' };
|
|
42
|
+
/** The place a builder address stands on, if it is one that takes the sidebar. */
|
|
43
|
+
export const spot = (at) => (at !== null && route(at).kind === 'settings' ? 'settings' : raised(at));
|
|
44
|
+
/** Which of them a builder address stands on, if any: an agent's page is Customize's, an automation Scheduled tasks'. */
|
|
45
|
+
export function raised(at) {
|
|
46
|
+
if (at === null)
|
|
47
|
+
return null;
|
|
48
|
+
const r = route(at);
|
|
49
|
+
if (r.kind === 'screen' && r.screen === 'artifacts')
|
|
50
|
+
return 'library';
|
|
51
|
+
if ((r.kind === 'screen' && r.screen === 'automations') || r.kind === 'automation')
|
|
52
|
+
return 'scheduled';
|
|
53
|
+
if (r.kind === 'customize' || r.kind === 'agent' || (r.kind === 'screen' && r.screen === 'mcp'))
|
|
54
|
+
return 'customize';
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
36
57
|
/** One mark: an icon button named for where it goes, its name its tooltip, lit where the reader is. */
|
|
37
58
|
export function Mark({ label, on = false, onPress, children, ...rest }) {
|
|
38
59
|
return (_jsx(XStack, { render: "button", "aria-label": label, ...{ title: label }, "aria-current": on ? 'page' : undefined, onPress: onPress, width: MARK, height: MARK, rounded: "$4", items: "center", justify: "center", shrink: 0, cursor: "pointer", opacity: on ? 1 : 0.62, bg: on ? '$edge' : 'transparent', hoverStyle: { bg: on ? '$edge' : '$hover', opacity: 1 }, pressStyle: { bg: '$raised' }, focusVisibleStyle: { outlineWidth: 2, outlineStyle: 'solid', outlineColor: '$outlineColor' },
|
|
@@ -43,12 +64,22 @@ export function Mark({ label, on = false, onPress, children, ...rest }) {
|
|
|
43
64
|
export function Toggle({ open, onPress, label }) {
|
|
44
65
|
return (_jsx(Mark, { label: label ?? (open ? 'Close sidebar' : 'Open sidebar'), "data-slot": "sidebar-toggle", "aria-expanded": open, onPress: onPress, children: _jsx(PanelLeft, { size: 18, "aria-hidden": true }) }));
|
|
45
66
|
}
|
|
46
|
-
export function Rail({ host, mode, open, toggle, flat = false, onChat, onDev, onStudio, onOrg, }) {
|
|
47
|
-
|
|
67
|
+
export function Rail({ host, mode, at, open, toggle, flat = false, onChat, onDev, onStudio, go, onOrg, }) {
|
|
68
|
+
const here = mode === 'dev' ? spot(at) : null;
|
|
69
|
+
const to = (p) => () => go(app(p));
|
|
70
|
+
// The products on hosts of their own, behind More; on a phone the raised places lead it.
|
|
48
71
|
const rest = [
|
|
72
|
+
...(flat
|
|
73
|
+
? [
|
|
74
|
+
{ key: 'library', label: 'Library', icon: _jsx(Library, { size: 16, "aria-hidden": true }), onSelect: to(RAISED.library) },
|
|
75
|
+
{ key: 'scheduled', label: 'Scheduled tasks', icon: _jsx(Clock, { size: 16, "aria-hidden": true }), onSelect: to(RAISED.scheduled) },
|
|
76
|
+
{ key: 'customize', label: 'Customize', icon: _jsx(Puzzle, { size: 16, "aria-hidden": true }), onSelect: to(RAISED.customize) },
|
|
77
|
+
{ type: 'separator', key: 'raised' },
|
|
78
|
+
]
|
|
79
|
+
: []),
|
|
49
80
|
{ key: 'tabs', label: 'Tabs', icon: _jsx(SquareTerminal, { size: 16, "aria-hidden": true }), onSelect: () => out(TABS) },
|
|
50
81
|
{ key: 'team', label: 'Team', icon: _jsx(Users, { size: 16, "aria-hidden": true }), onSelect: () => out(WORKSPACE) },
|
|
51
82
|
];
|
|
52
83
|
const Stack = flat ? XStack : YStack;
|
|
53
|
-
return (_jsxs(Stack, { "data-slot": "rail", render: "nav", "aria-label": "Products", ...(flat ? { pt: '$2', mt: '$2', borderTopWidth: 1, borderColor: '$borderColor', gap: '$1' } : { width: RAIL, flex: 1, pt: '$2', pb: '$2', gap: 8 }), shrink: 0, items: "center", children: [toggle ? (_jsx(YStack, { pb: 8, children: _jsx(Toggle, { open: open, onPress: toggle }) })) : null, _jsx(Mark, { label: "Chat", on: mode === 'chat', onPress: onChat, "data-slot": "rail-chat", children: _jsx(MessageSquare, { size: 18, "aria-hidden": true }) }), _jsx(Mark, { label: "Dev", on: mode === 'dev', onPress: onDev, "data-slot": "rail-dev", children: _jsx(Code2, { size: 18, "aria-hidden": true }) }), _jsx(Mark, { label: "Studio", on: mode === 'studio', onPress: onStudio, "data-slot": "rail-studio", children: _jsx(WandSparkles, { size: 18, "aria-hidden": true }) }), _jsx(DropdownMenu, { placement: flat ? 'top-start' : 'right-start', minWidth: 220, trigger: _jsx(XStack, { render: "button", "aria-label": "More", ...{ title: 'More' }, "data-slot": "rail-more", width: MARK, height: MARK, rounded: "$4", items: "center", justify: "center", cursor: "pointer", opacity: 0.62, hoverStyle: { bg: '$hover', opacity: 1 }, pressStyle: { bg: '$raised' }, focusVisibleStyle: { outlineWidth: 2, outlineStyle: 'solid', outlineColor: '$outlineColor' }, $touchable: { width: 44, height: 44 }, children: _jsx(Ellipsis, { size: 18, "aria-hidden": true }) }), items: rest }), _jsx(YStack, { flex: 1 }), _jsx(Me, { host: host, narrow: true, above: flat, onOrg: onOrg })] }));
|
|
84
|
+
return (_jsxs(Stack, { "data-slot": "rail", render: "nav", "aria-label": "Products", ...(flat ? { pt: '$2', mt: '$2', borderTopWidth: 1, borderColor: '$borderColor', gap: '$1' } : { width: RAIL, flex: 1, pt: '$2', pb: '$2', gap: 8 }), shrink: 0, items: "center", children: [toggle ? (_jsx(YStack, { pb: 8, children: _jsx(Toggle, { open: open, onPress: toggle }) })) : null, _jsx(Mark, { label: "Chat", on: mode === 'chat', onPress: onChat, "data-slot": "rail-chat", children: _jsx(MessageSquare, { size: 18, "aria-hidden": true }) }), _jsx(Mark, { label: "Dev", on: mode === 'dev' && !here, onPress: onDev, "data-slot": "rail-dev", children: _jsx(Code2, { size: 18, "aria-hidden": true }) }), _jsx(Mark, { label: "Studio", on: mode === 'studio', onPress: onStudio, "data-slot": "rail-studio", children: _jsx(WandSparkles, { size: 18, "aria-hidden": true }) }), flat ? null : (_jsxs(_Fragment, { children: [_jsx(Mark, { label: "Library", on: here === 'library', onPress: to(RAISED.library), "data-slot": "rail-library", children: _jsx(Library, { size: 18, "aria-hidden": true }) }), _jsx(Mark, { label: "Scheduled tasks", on: here === 'scheduled', onPress: to(RAISED.scheduled), "data-slot": "rail-scheduled", children: _jsx(Clock, { size: 18, "aria-hidden": true }) }), _jsx(Mark, { label: "Customize", on: here === 'customize', onPress: to(RAISED.customize), "data-slot": "rail-customize", children: _jsx(Puzzle, { size: 18, "aria-hidden": true }) })] })), _jsx(DropdownMenu, { placement: flat ? 'top-start' : 'right-start', minWidth: 220, trigger: _jsx(XStack, { render: "button", "aria-label": "More", ...{ title: 'More' }, "data-slot": "rail-more", width: MARK, height: MARK, rounded: "$4", items: "center", justify: "center", cursor: "pointer", opacity: 0.62, hoverStyle: { bg: '$hover', opacity: 1 }, pressStyle: { bg: '$raised' }, focusVisibleStyle: { outlineWidth: 2, outlineStyle: 'solid', outlineColor: '$outlineColor' }, $touchable: { width: 44, height: 44 }, children: _jsx(Ellipsis, { size: 18, "aria-hidden": true }) }), items: rest }), _jsx(YStack, { flex: 1 }), _jsx(Me, { host: host, narrow: true, above: flat, onOrg: onOrg })] }));
|
|
54
85
|
}
|
package/dist/Shell.js
CHANGED
|
@@ -27,8 +27,7 @@ import { Box, Shortcut, XStack, YStack, Text } from "@hanzo/ui";
|
|
|
27
27
|
import { scrim, sheet } from "@hanzo/ui/glass";
|
|
28
28
|
import { Sidebar, SidebarIconButton, SidebarNewChat, SidebarScroll, SidebarSection, SidebarItem, SidebarFolder, } from "@hanzo/ui/chat";
|
|
29
29
|
import { OrgProjectSwitcher, useIam, useOrganizations, } from "@hanzo/iam/react";
|
|
30
|
-
import { SideProvider, useSplit } from "@hanzo/build";
|
|
31
|
-
import { Grip } from "@hanzo/ui";
|
|
30
|
+
import { Gutter, SideProvider, useSplit } from "@hanzo/build";
|
|
32
31
|
import { HanzoMark, } from "@hanzogui/shell";
|
|
33
32
|
import { useHydrated } from "./lib/hydrated.js";
|
|
34
33
|
import { useHost } from "./lib/hostname.js";
|
|
@@ -58,12 +57,8 @@ const FIELD = {
|
|
|
58
57
|
color: "inherit",
|
|
59
58
|
fontSize: "$2",
|
|
60
59
|
};
|
|
61
|
-
/** The
|
|
62
|
-
* home indicator on a phone. gui carries a `calc()`, `max()` or `env()` to the page unchanged; its types only name
|
|
60
|
+
/** The rail clears the home indicator on a phone. gui carries an `env()` to the page unchanged; its types only name
|
|
63
61
|
* custom properties. */
|
|
64
|
-
const GUTTER_START = "calc(-1 * var(--pane-gap, 0px))";
|
|
65
|
-
const GUTTER = "max(8px, var(--pane-gap, 8px))";
|
|
66
|
-
const TOUCH_START = "calc(-22px - var(--pane-gap, 0px) / 2)";
|
|
67
62
|
const HOME_INDICATOR = "env(safe-area-inset-bottom)";
|
|
68
63
|
import { invite } from "./lib/home.js";
|
|
69
64
|
import { reach } from "./lib/reach.js";
|
|
@@ -910,13 +905,7 @@ export function Paned({ children, swap, framed = false, bare = false, }) {
|
|
|
910
905
|
// In the frame the gutter stands between the pane and this column.
|
|
911
906
|
ml: framed ? "var(--pane-gap)" : undefined, ref: split.aside,
|
|
912
907
|
// inline-style: the width a drag rewrites on the element itself, and full screen (useSplit).
|
|
913
|
-
style: split.asideStyle, position: "relative", shrink: 0, minH: 0, display: "none", $lg: { display: "flex" }, children: [split.grip ? (_jsx(
|
|
914
|
-
// The handle halfway down the edge, where a hand looks for it.
|
|
915
|
-
justify: "center",
|
|
916
|
-
// In the gutter the frame leaves between the panes; a room has none.
|
|
917
|
-
l: GUTTER_START, width: GUTTER,
|
|
918
|
-
// A finger's band, centred on the gutter.
|
|
919
|
-
$touchable: { l: TOUCH_START, width: 44 } })) : null, _jsx(YStack, { flex: 1, minH: 0, overflowY: "auto", overflowX: "hidden", rounded: "var(--pane-round)", ref: (el) => setSlot(el instanceof HTMLElement ? el : null) })] })) : null] }));
|
|
908
|
+
style: split.asideStyle, position: "relative", shrink: 0, minH: 0, display: "none", $lg: { display: "flex" }, children: [split.grip ? (_jsx(Gutter, { ...split.grip, label: "Resize side panel", inset: 1 })) : null, _jsx(YStack, { flex: 1, minH: 0, overflowY: "auto", overflowX: "hidden", rounded: "var(--pane-round)", ref: (el) => setSlot(el instanceof HTMLElement ? el : null) })] })) : null] }));
|
|
920
909
|
}
|
|
921
910
|
/**
|
|
922
911
|
* THE RAIL: where you can go, as marks with their names under them. It is the
|
|
@@ -1229,7 +1218,7 @@ function Frame({ mode, children, navigate, back, forward, }) {
|
|
|
1229
1218
|
const list = (_jsxs(Sidebar, { ref: side.ref,
|
|
1230
1219
|
// A phone's sheet is never wider than 280, whatever the laptop kept.
|
|
1231
1220
|
// inline-style: `--span`, the width a drag rewrites on the element itself (span.ts); no prop sets a variable.
|
|
1232
|
-
style: side.style, $md: { width: "var(--span)" }, "$max-md": { width: "100%", maxW: 280 }, ...sheet(0), borderRightWidth: 1, borderColor: "var(--edge, var(--white-06))", position: "relative", children: [_jsx(
|
|
1221
|
+
style: side.style, $md: { width: "var(--span)" }, "$max-md": { width: "100%", maxW: 280 }, ...sheet(0), borderRightWidth: 1, borderColor: "var(--edge, var(--white-06))", position: "relative", children: [_jsx(Gutter, { side: "left", span: side.span, floor: FLOOR, ceil: CEIL, reset: SIDEBAR_WIDTH, onSpan: side.move, onKeep: side.keep, onShut: () => setAsked(false), label: "Resize sidebar" }), _jsx(XStack, { "data-slot": "mode-name", items: "center", px: "$2", pt: "$2", minW: 0, children: _jsx(Text, { fontSize: "$4", fontWeight: "600", color: "$ink", numberOfLines: 1, children: wordmark(mode === "dev" ? "dev" : "chat") }) }), _jsxs(XStack, { "data-slot": "workspace-switcher", items: "center", gap: "$2", px: "$2", pt: "$1", pb: "$1", minW: 0, children: [_jsx(Text, { render: _jsx("a", { href: "/", onClick: (e) => {
|
|
1233
1222
|
if (!navigate || e.metaKey || e.ctrlKey || e.shiftKey || e.button !== 0)
|
|
1234
1223
|
return;
|
|
1235
1224
|
e.preventDefault();
|
package/dist/agents.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Host } from '@hanzo/build';
|
|
1
2
|
export type { Link, Shelf, ShelfRow as Row } from '@hanzo/build';
|
|
2
3
|
/**
|
|
3
4
|
* The model that draws an agent's face: Hanzo's own image SKU (hanzo-inc/zen
|
|
@@ -7,22 +8,20 @@ export type { Link, Shelf, ShelfRow as Row } from '@hanzo/build';
|
|
|
7
8
|
export declare const PAINTER = "zen-image";
|
|
8
9
|
/** The words every drawn face is asked for after its description. */
|
|
9
10
|
export declare const MEMOJI = "memoji style 3D emoji portrait, head and shoulders, centered, plain background";
|
|
10
|
-
/** A core member, drawn for an org that keeps no row of its own for them. */
|
|
11
|
-
export interface House {
|
|
12
|
-
id: string;
|
|
13
|
-
name: string;
|
|
14
|
-
avatar: string;
|
|
15
|
-
}
|
|
16
|
-
/** The default cast: the core team @hanzo/personas publishes, in the crew's order. */
|
|
17
|
-
export declare const CORE: readonly House[];
|
|
18
11
|
/**
|
|
19
|
-
* The
|
|
20
|
-
*
|
|
21
|
-
*
|
|
12
|
+
* The default agents an org adds in one press (Customize › Agents, @hanzo/build
|
|
13
|
+
* `hire`): the core team, each as its persona writes it, then QA, Ops and
|
|
14
|
+
* Support. An org starts with none of them and loads none until it adds them.
|
|
15
|
+
*/
|
|
16
|
+
export declare const CAST: NonNullable<Host['cast']>;
|
|
17
|
+
/**
|
|
18
|
+
* The org's own agents, the core team's first in the crew's order, then the
|
|
19
|
+
* rest as listed. Nothing stands in for a member the org has not added: an org
|
|
20
|
+
* with no agents has none to show.
|
|
22
21
|
*/
|
|
23
22
|
export declare function ordered<T extends {
|
|
24
23
|
name: string;
|
|
25
|
-
}>(agents: readonly T[] | null | undefined):
|
|
24
|
+
}>(agents: readonly T[] | null | undefined): T[];
|
|
26
25
|
/**
|
|
27
26
|
* One figure of @hanzo/personas' roster, as assets/personas/index.json lists it
|
|
28
27
|
* (scripts/team.mjs). `called`, `about` and `based` are its PERSONA.md's
|
package/dist/agents.js
CHANGED
|
@@ -10,20 +10,25 @@ import { TEAM } from './team.js';
|
|
|
10
10
|
export const PAINTER = 'zen-image';
|
|
11
11
|
/** The words every drawn face is asked for after its description. */
|
|
12
12
|
export const MEMOJI = 'memoji style 3D emoji portrait, head and shoulders, centered, plain background';
|
|
13
|
-
/**
|
|
14
|
-
|
|
13
|
+
/**
|
|
14
|
+
* The default agents an org adds in one press (Customize › Agents, @hanzo/build
|
|
15
|
+
* `hire`): the core team, each as its persona writes it, then QA, Ops and
|
|
16
|
+
* Support. An org starts with none of them and loads none until it adds them.
|
|
17
|
+
*/
|
|
18
|
+
export const CAST = [
|
|
19
|
+
...TEAM.map((one) => ({ name: one.id, description: `${one.name} — ${one.role}`, model: one.model, instructions: one.instructions, avatar: `/agents/${one.id}.png` })),
|
|
20
|
+
{ name: 'qa', description: 'QA — Automated Testing & Verification', model: 'enso-auto', instructions: '' },
|
|
21
|
+
{ name: 'ops', description: 'Ops — Site Reliability & Cloud Infrastructure', model: 'enso-auto', instructions: '' },
|
|
22
|
+
{ name: 'support', description: 'Support — Customer Support & Triage Specialist', model: 'enso-auto', instructions: '' },
|
|
23
|
+
];
|
|
15
24
|
const RANK = new Map(TEAM.map((one, i) => [one.id, i]));
|
|
16
25
|
/**
|
|
17
|
-
* The org's agents
|
|
18
|
-
*
|
|
19
|
-
*
|
|
26
|
+
* The org's own agents, the core team's first in the crew's order, then the
|
|
27
|
+
* rest as listed. Nothing stands in for a member the org has not added: an org
|
|
28
|
+
* with no agents has none to show.
|
|
20
29
|
*/
|
|
21
30
|
export function ordered(agents) {
|
|
22
31
|
const list = Array.isArray(agents) ? [...agents] : [];
|
|
23
|
-
const names = new Set(list.map((one) => one.name?.toLowerCase()));
|
|
24
|
-
for (const one of CORE)
|
|
25
|
-
if (!names.has(one.name.toLowerCase()))
|
|
26
|
-
list.push(one);
|
|
27
32
|
const rank = (one) => RANK.get(one.name?.toLowerCase() ?? '') ?? Infinity;
|
|
28
33
|
return list.sort((a, b) => rank(a) - rank(b));
|
|
29
34
|
}
|
package/dist/crew.js
CHANGED
|
@@ -115,6 +115,7 @@ export function useAgentShelf() {
|
|
|
115
115
|
loading,
|
|
116
116
|
error: error ? reach(error) : null,
|
|
117
117
|
search: 'Search agents',
|
|
118
|
+
empty: 'No agents yet. Add the default team from Manage agents.',
|
|
118
119
|
create: { label: 'Create agent', onPress: () => make('new') },
|
|
119
120
|
// Dev's Customize › Agents: a move inside the app where the host reads the
|
|
120
121
|
// path (hanzo.ai), else Dev on hanzo.ai, as Chat's Create file or site goes.
|
package/dist/dev.js
CHANGED
|
@@ -35,6 +35,7 @@ import { administers, path, route } from '@hanzo/build';
|
|
|
35
35
|
import { bearer, named, org, orgs, pick } from './lib/session.js';
|
|
36
36
|
import { enter } from './lib/destination.js';
|
|
37
37
|
import { api } from './lib/api.js';
|
|
38
|
+
import { CAST } from './agents.js';
|
|
38
39
|
import { app, go, place } from './lib/host.js';
|
|
39
40
|
import { link } from './lib/tags.js';
|
|
40
41
|
import { payUrl } from './lib/pay.js';
|
|
@@ -117,6 +118,9 @@ export function useDevHost() {
|
|
|
117
118
|
path: here,
|
|
118
119
|
go: (to, how) => (isPlans(to) ? leave('here') : go(app(to), how?.replace)),
|
|
119
120
|
links: LINKS,
|
|
121
|
+
// The sidebar lists Settings' sections and Customize's tabs (Column.tsx), and Customize › Agents offers the cast.
|
|
122
|
+
sections: true,
|
|
123
|
+
cast: CAST,
|
|
120
124
|
// An address of the app moves the app, another of this site moves in the
|
|
121
125
|
// router, and another origin is left in this tab. platform.hanzo.ai is
|
|
122
126
|
// another product, and a click that names it stays here — everything the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzo/rooms",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.85",
|
|
4
4
|
"description": "The workspace rooms — Home, Chat, Inbox, Contacts, Meet, Cal, Drive, Board, Work, Bots — and the frame that holds them, once, for every Hanzo surface.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"@hanzo/ai": ">=0.6.23",
|
|
51
51
|
"@hanzo/appearance": ">=0.2.6",
|
|
52
|
-
"@hanzo/build": ">=0.2.
|
|
52
|
+
"@hanzo/build": ">=0.2.73",
|
|
53
53
|
"@hanzo/composer": ">=0.2.0",
|
|
54
54
|
"@hanzo/event": ">=0.3.56",
|
|
55
55
|
"@hanzo/gui": "^8.3.5",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"devDependencies": {
|
|
68
68
|
"@hanzo/ai": "0.6.23",
|
|
69
69
|
"@hanzo/appearance": "0.2.8",
|
|
70
|
-
"@hanzo/build": "0.2.
|
|
70
|
+
"@hanzo/build": "0.2.73",
|
|
71
71
|
"@hanzo/composer": "0.2.0",
|
|
72
72
|
"@hanzo/design": "0.5.34",
|
|
73
73
|
"@hanzo/event": "0.3.56",
|