@hanzo/build 0.2.80 → 0.2.82
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/lib/activity.d.ts +3 -7
- package/lib/activity.js +18 -5
- package/lib/api/agents.d.ts +1 -20
- package/lib/api/agents.js +16 -8
- package/lib/api/auto.d.ts +3 -23
- package/lib/api/auto.js +39 -22
- package/lib/api/billing.d.ts +0 -35
- package/lib/api/billing.js +6 -5
- package/lib/api/call.d.ts +16 -8
- package/lib/api/call.js +32 -1
- package/lib/api/capabilities.d.ts +0 -11
- package/lib/api/capabilities.js +2 -1
- package/lib/api/codebases.d.ts +0 -10
- package/lib/api/codebases.js +3 -2
- package/lib/api/coding.d.ts +3 -32
- package/lib/api/coding.js +13 -7
- package/lib/api/connectors.d.ts +1 -17
- package/lib/api/connectors.js +5 -4
- package/lib/api/environment.d.ts +6 -20
- package/lib/api/environment.js +22 -19
- package/lib/api/github.d.ts +0 -22
- package/lib/api/github.js +3 -2
- package/lib/api/keys.d.ts +0 -14
- package/lib/api/keys.js +4 -3
- package/lib/api/library.d.ts +3 -17
- package/lib/api/library.js +23 -22
- package/lib/api/links.d.ts +1 -1
- package/lib/api/links.js +1 -1
- package/lib/api/machines.d.ts +0 -15
- package/lib/api/machines.js +6 -5
- package/lib/api/mcp.d.ts +0 -9
- package/lib/api/mcp.js +3 -2
- package/lib/api/members.d.ts +0 -15
- package/lib/api/members.js +4 -3
- package/lib/api/memory.d.ts +0 -11
- package/lib/api/memory.js +2 -1
- package/lib/api/places.d.ts +1 -9
- package/lib/api/places.js +12 -1
- package/lib/api/plugins.d.ts +1 -16
- package/lib/api/plugins.js +4 -3
- package/lib/api/profile.d.ts +0 -10
- package/lib/api/profile.js +5 -4
- package/lib/api/projects.d.ts +0 -14
- package/lib/api/projects.js +11 -10
- package/lib/api/provider.d.ts +2 -14
- package/lib/api/provider.js +12 -10
- package/lib/api/sandbox.d.ts +0 -17
- package/lib/api/sandbox.js +5 -4
- package/lib/api/sessions.d.ts +0 -17
- package/lib/api/sessions.js +5 -4
- package/lib/api/skills.d.ts +1 -15
- package/lib/api/skills.js +5 -4
- package/lib/api/studio.d.ts +0 -14
- package/lib/api/studio.js +6 -5
- package/lib/api/turn.d.ts +6 -28
- package/lib/api/turn.js +105 -49
- package/lib/api/verdict.d.ts +0 -9
- package/lib/api/verdict.js +2 -1
- package/lib/api/webhooks.d.ts +1 -14
- package/lib/api/webhooks.js +5 -4
- package/lib/ask.js +7 -4
- package/lib/automations.d.ts +5 -4
- package/lib/automations.js +95 -74
- package/lib/back.js +10 -4
- package/lib/builder.js +7 -5
- package/lib/carry.js +20 -16
- package/lib/customize/agents.js +78 -31
- package/lib/customize/connectors.js +62 -48
- package/lib/customize/index.js +43 -10
- package/lib/customize/plugins.js +34 -22
- package/lib/customize/say.d.ts +13 -1
- package/lib/customize/say.js +15 -21
- package/lib/customize/skills.js +31 -22
- package/lib/customize/ui.d.ts +5 -9
- package/lib/customize/ui.js +26 -16
- package/lib/data.d.ts +1 -1
- package/lib/data.js +3 -2
- package/lib/desk.js +45 -33
- package/lib/door.js +35 -10
- package/lib/environment.js +25 -19
- package/lib/files.js +43 -34
- package/lib/find.js +12 -9
- package/lib/foot.js +7 -4
- package/lib/forge.js +61 -40
- package/lib/gear.d.ts +2 -1
- package/lib/gear.js +6 -4
- package/lib/git.js +29 -19
- package/lib/landing.d.ts +5 -5
- package/lib/landing.js +52 -44
- package/lib/library.js +73 -51
- package/lib/merge.d.ts +2 -2
- package/lib/meter.d.ts +1 -1
- package/lib/meter.js +14 -5
- package/lib/mic.js +12 -5
- package/lib/mind.d.ts +1 -0
- package/lib/mind.js +5 -3
- package/lib/nav.d.ts +6 -5
- package/lib/nav.js +37 -30
- package/lib/panel.d.ts +2 -1
- package/lib/panel.js +52 -36
- package/lib/plan.d.ts +4 -20
- package/lib/plan.js +26 -10
- package/lib/plans.js +49 -30
- package/lib/plugins/design.js +3 -2
- package/lib/plugins/index.d.ts +23 -4
- package/lib/plugins/index.js +11 -26
- package/lib/plugins/pdf.js +2 -1
- package/lib/plugins/project.js +7 -4
- package/lib/plugins/research.js +3 -2
- package/lib/plugins/sketch.js +6 -3
- package/lib/plugins/slides.js +3 -2
- package/lib/plugins/template.js +6 -3
- package/lib/plus.js +25 -13
- package/lib/prefs.d.ts +0 -14
- package/lib/prefs.js +2 -1
- package/lib/project.js +69 -62
- package/lib/prompt.d.ts +12 -11
- package/lib/prompt.js +38 -20
- package/lib/publish.js +17 -12
- package/lib/reply.js +6 -3
- package/lib/run.js +72 -54
- package/lib/say.d.ts +2 -0
- package/lib/say.js +7 -0
- package/lib/scheduled.js +54 -43
- package/lib/section.d.ts +1 -0
- package/lib/section.js +8 -2
- package/lib/settings/account.d.ts +1 -0
- package/lib/settings/account.js +31 -21
- package/lib/settings/billing.js +55 -28
- package/lib/settings/capabilities.js +26 -15
- package/lib/settings/card.js +19 -12
- package/lib/settings/code.js +22 -11
- package/lib/settings/credits.d.ts +4 -4
- package/lib/settings/credits.js +34 -21
- package/lib/settings/environments.js +21 -14
- package/lib/settings/general.js +26 -14
- package/lib/settings/index.js +6 -3
- package/lib/settings/integrations.js +42 -28
- package/lib/settings/keys.js +37 -19
- package/lib/settings/list.d.ts +0 -5
- package/lib/settings/list.js +24 -15
- package/lib/settings/machines.d.ts +3 -0
- package/lib/settings/machines.js +63 -38
- package/lib/settings/members.js +23 -14
- package/lib/settings/memory.js +12 -6
- package/lib/settings/notifications.js +32 -19
- package/lib/settings/plan.d.ts +1 -1
- package/lib/settings/plan.js +40 -17
- package/lib/settings/privacy.js +26 -13
- package/lib/settings/ui.d.ts +3 -2
- package/lib/settings/ui.js +9 -3
- package/lib/settings/usage.js +7 -3
- package/lib/shelf.js +20 -17
- package/lib/side.d.ts +1 -26
- package/lib/side.js +11 -5
- package/lib/standing.d.ts +2 -10
- package/lib/standing.js +5 -3
- package/lib/suggest.d.ts +8 -28
- package/lib/suggest.js +39 -4
- package/lib/suggestions.js +14 -5
- package/lib/summary.d.ts +1 -1
- package/lib/summary.js +4 -1
- package/lib/sync.js +22 -12
- package/lib/tools.d.ts +4 -3
- package/lib/tools.js +10 -7
- package/lib/transcript.js +10 -8
- package/package.json +4 -2
package/lib/merge.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ export interface Project {
|
|
|
42
42
|
synced: string;
|
|
43
43
|
/** Its link's state: `synced`, `conflict`, `pending`, `paused`, `linked` when its forge copy could not be read; '' with no link. */
|
|
44
44
|
status: string;
|
|
45
|
-
/** The org's project (GET /v1/
|
|
45
|
+
/** The org's project (GET /v1/project) that builds from it, by slug, or ''. */
|
|
46
46
|
slug: string;
|
|
47
47
|
/** The name GitHub's listing says it takes on the forge once brought there, or ''. */
|
|
48
48
|
codebase: string;
|
|
@@ -124,7 +124,7 @@ export interface Linked {
|
|
|
124
124
|
status: string;
|
|
125
125
|
branch: string;
|
|
126
126
|
}
|
|
127
|
-
/** One of the org's projects (GET /v1/
|
|
127
|
+
/** One of the org's projects (GET /v1/project) that builds from a repository. */
|
|
128
128
|
export interface Site {
|
|
129
129
|
slug: string;
|
|
130
130
|
/** Its clone address. */
|
package/lib/meter.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export declare const INK: {
|
|
|
7
7
|
readonly near: '$yellow10';
|
|
8
8
|
readonly limited: '$red10';
|
|
9
9
|
};
|
|
10
|
-
/** A plan's name with its rung beside it, small: `Max` `20x`. */
|
|
10
|
+
/** A plan's name with its rung beside it, small: `Max` `20x`. A family's name is a name; Free and the like are words. */
|
|
11
11
|
export declare function Title({ label, size }: {
|
|
12
12
|
label: Label;
|
|
13
13
|
size?: '$3' | '$5' | '$6';
|
package/lib/meter.js
CHANGED
|
@@ -13,14 +13,19 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
13
13
|
* balance, because that balance is what it spends.
|
|
14
14
|
*/
|
|
15
15
|
import { SizableText, XStack, YStack } from '@hanzo/gui';
|
|
16
|
+
import { phrase } from '@hanzo/i18n';
|
|
17
|
+
import { useI18n } from '@hanzo/i18n/react';
|
|
16
18
|
import { money } from './api/billing.js';
|
|
17
19
|
import { left, rows } from './standing.js';
|
|
18
20
|
import { when } from './plan.js';
|
|
19
21
|
/** The ink a share is said in: quiet until it is close, and the one red when it is used. */
|
|
20
22
|
export const INK = { ok: '$soft', near: '$yellow10', limited: '$red10' };
|
|
21
|
-
/** A
|
|
23
|
+
/** A window's name, in English; drawn through `t`. */
|
|
24
|
+
const WINDOW = { Session: phrase('Session'), Today: phrase('Today'), Month: phrase('Month') };
|
|
25
|
+
/** A plan's name with its rung beside it, small: `Max` `20x`. A family's name is a name; Free and the like are words. */
|
|
22
26
|
export function Title({ label, size = '$3' }) {
|
|
23
|
-
|
|
27
|
+
const { t } = useI18n();
|
|
28
|
+
return (_jsxs(XStack, { items: "baseline", gap: "$1.5", minW: 0, "data-slot": "plan-name", children: [_jsx(SizableText, { size: size, color: "$ink", style: { fontWeight: 600 }, numberOfLines: 1, children: t(label.name) }), label.tag ? (_jsx(SizableText, { size: "$1", color: "$soft", px: "$1.5", rounded: "$2", borderWidth: 1, borderColor: "$borderColor", "data-slot": "plan-tag", children: t(label.tag) })) : null] }));
|
|
24
29
|
}
|
|
25
30
|
/** A quiet text button. */
|
|
26
31
|
function Act({ label, onPress }) {
|
|
@@ -28,10 +33,13 @@ function Act({ label, onPress }) {
|
|
|
28
33
|
}
|
|
29
34
|
/** The standing, drawn: what `Meter` shows once it has read. */
|
|
30
35
|
export function Reading({ s, onPlans, onBilling, now }) {
|
|
31
|
-
const
|
|
36
|
+
const { t } = useI18n();
|
|
37
|
+
const windows = s.kind === 'plan' ? rows(s.limits, now, t) : [];
|
|
32
38
|
const share = s.kind === 'free' ? left(s.allowance) : null;
|
|
33
39
|
const resets = s.allowance ? when(s.allowance.resets, now) : '';
|
|
34
|
-
return (_jsxs(YStack, { px: "$2", py: "$1.5", gap: "$1", "data-slot": "meter", "data-kind": s.kind, children: [_jsxs(XStack, { items: "center", gap: "$2", minW: 0, children: [_jsx(XStack, { flex: 1, minW: 0, children: s.label ? _jsx(Title, { label: s.label }) : null }), s.kind === 'free' ? _jsx(Act, { label:
|
|
40
|
+
return (_jsxs(YStack, { px: "$2", py: "$1.5", gap: "$1", "data-slot": "meter", "data-kind": s.kind, children: [_jsxs(XStack, { items: "center", gap: "$2", minW: 0, children: [_jsx(XStack, { flex: 1, minW: 0, children: s.label ? _jsx(Title, { label: s.label }) : null }), s.kind === 'free' ? _jsx(Act, { label: t('Upgrade'), onPress: onPlans }) : s.kind === 'credits' ? _jsx(Act, { label: t('Add funds'), onPress: onBilling }) : null] }), windows.map((w) => (_jsxs(XStack, { items: "baseline", gap: "$2", "data-slot": "meter-window", "data-state": w.state, children: [_jsx(SizableText, { size: "$1", color: "$soft", width: 56, shrink: 0, children: t(WINDOW[w.name]) }), _jsxs(SizableText, { size: "$1", color: INK[w.state], style: { fontVariantNumeric: 'tabular-nums' }, shrink: 0, children: [w.percent, "%"] }), _jsx(SizableText, { size: "$1", color: "$soft", flex: 1, minW: 0, numberOfLines: 1, text: "right", children: w.resets })] }, w.name))), s.kind === 'free' && share !== null ? (_jsx(SizableText, { size: "$1", color: share === 0 ? '$red10' : '$soft', "data-slot": "meter-free", children: resets
|
|
41
|
+
? `${t('{n}% of today’s free usage left', { n: share })} · ${t('Resets {time}', { time: resets })}`
|
|
42
|
+
: t('{n}% of today’s free usage left', { n: share }) })) : null, s.kind === 'credits' && s.balance !== null ? (_jsx(SizableText, { size: "$1", color: "$soft", "data-slot": "meter-balance", children: t('{amount} in credits', { amount: money(s.balance) }) })) : null] }));
|
|
35
43
|
}
|
|
36
44
|
/**
|
|
37
45
|
* The block an account menu leads with: `read` is `useStanding`, asked while
|
|
@@ -39,7 +47,8 @@ export function Reading({ s, onPlans, onBilling, now }) {
|
|
|
39
47
|
* live on; the host says where each is.
|
|
40
48
|
*/
|
|
41
49
|
export function Meter({ read, onPlans, onBilling }) {
|
|
50
|
+
const { t } = useI18n();
|
|
42
51
|
if (read.value)
|
|
43
52
|
return _jsx(Reading, { s: read.value, onPlans: onPlans, onBilling: onBilling });
|
|
44
|
-
return (_jsx(SizableText, { size: "$1", color: "$soft", px: "$2", py: "$1.5", "data-slot": "meter", children: read.error ? 'Your plan could not be read.' : 'Reading your plan…' }));
|
|
53
|
+
return (_jsx(SizableText, { size: "$1", color: "$soft", px: "$2", py: "$1.5", "data-slot": "meter", children: read.error ? t('Your plan could not be read.') : t('Reading your plan…') }));
|
|
45
54
|
}
|
package/lib/mic.js
CHANGED
|
@@ -9,10 +9,14 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
9
9
|
* every capture opens it; unchosen, the system's own input. The meter listens
|
|
10
10
|
* only while the menu is open, and only where the person has already let the
|
|
11
11
|
* page use a microphone: opening a menu never asks for permission.
|
|
12
|
+
*
|
|
13
|
+
* Its words are the reader's language (@hanzo/i18n `t`); a microphone's name
|
|
14
|
+
* is the device's and a language's is its own, drawn as given.
|
|
12
15
|
*/
|
|
13
16
|
import { SizableText, XStack, YStack } from '@hanzo/gui';
|
|
14
17
|
import { Check, ChevronDown, Mic as MicIcon } from '@hanzogui/lucide-icons-2';
|
|
15
18
|
import { Control } from '@hanzo/composer';
|
|
19
|
+
import { useI18n } from '@hanzo/i18n/react';
|
|
16
20
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, } from '@hanzo/ui';
|
|
17
21
|
import { choose, Voice } from '@hanzo/voice';
|
|
18
22
|
import { useEffect, useRef, useState } from 'react';
|
|
@@ -69,6 +73,8 @@ function useInputs(open) {
|
|
|
69
73
|
}
|
|
70
74
|
/** The chosen microphone's level while the menu is open, drawn without re-rendering. */
|
|
71
75
|
function Meter({ device, on }) {
|
|
76
|
+
// The level grows from the line's start: the right edge in a right-to-left language.
|
|
77
|
+
const { dir } = useI18n();
|
|
72
78
|
const bar = useRef(null);
|
|
73
79
|
useEffect(() => {
|
|
74
80
|
if (!on)
|
|
@@ -108,11 +114,12 @@ function Meter({ device, on }) {
|
|
|
108
114
|
};
|
|
109
115
|
}, [device, on]);
|
|
110
116
|
return (_jsxs(XStack, { items: "center", gap: 10, px: 8, py: 8, "data-slot": "mic-meter", "aria-hidden": true, children: [_jsx(MicIcon, { size: 14, color: "$hint" }), _jsx(YStack, { flex: 1, height: 4, rounded: 2, bg: "$hover", overflow: "hidden", children: _jsx(YStack, { ref: bar, height: 4, width: "100%", bg: "$ink",
|
|
111
|
-
//
|
|
112
|
-
|
|
117
|
+
// Empty at rest; the level is written per frame onto the node's transform, so no class is minted per value.
|
|
118
|
+
scaleX: 0, transformOrigin: dir === 'rtl' ? 'right' : 'left' }) })] }));
|
|
113
119
|
}
|
|
114
120
|
/** The mic and its chevron, one control on the composer's row. */
|
|
115
121
|
export function Dictation({ voice, disabled = false, narrow = false, language = null, onLanguage }) {
|
|
122
|
+
const { t } = useI18n();
|
|
116
123
|
const [open, setOpen] = useState(false);
|
|
117
124
|
// The Language list, drawn only while open (see plus.tsx).
|
|
118
125
|
const [lang, setLang] = useState(false);
|
|
@@ -122,11 +129,11 @@ export function Dictation({ voice, disabled = false, narrow = false, language =
|
|
|
122
129
|
// The chevron is drawn while the mic is reached for (pointer, keyboard, menu open); at rest the row is the mic alone.
|
|
123
130
|
const [near, setNear] = useState(false);
|
|
124
131
|
const shown = open || near;
|
|
125
|
-
return (_jsxs(XStack, { "data-slot": "dictation", items: "center", rounded: 8, borderWidth: 1, borderColor: open ? '$borderColor' : 'transparent', hoverStyle: { borderColor: '$borderColor' }, shrink: 0, onPointerEnter: () => setNear(true), onPointerLeave: () => setNear(false), onFocus: () => setNear(true), onBlur: () => setNear(false), children: [_jsx(Control, { asChild: true, size: narrow ? 44 : 30, ...PLAIN, children: _jsx(Voice, { voice: voice, disabled: disabled, says: { idle: 'Dictate', listening: 'Dictating — click to stop' }, children: (state) => _jsx(MicIcon, { size: 16, color: "var(--foreground)", fill: state === 'idle' ? 'none' : 'var(--foreground)' }) }) }), _jsxs(DropdownMenu, { open: open, onOpenChange: setOpen, children: [_jsx(DropdownMenuTrigger, { asChild: true, disabled: disabled, children: _jsx(XStack, { render: "button", "aria-label":
|
|
132
|
+
return (_jsxs(XStack, { "data-slot": "dictation", items: "center", rounded: 8, borderWidth: 1, borderColor: open ? '$borderColor' : 'transparent', hoverStyle: { borderColor: '$borderColor' }, shrink: 0, onPointerEnter: () => setNear(true), onPointerLeave: () => setNear(false), onFocus: () => setNear(true), onBlur: () => setNear(false), children: [_jsx(Control, { asChild: true, size: narrow ? 44 : 30, ...PLAIN, children: _jsx(Voice, { voice: voice, disabled: disabled, says: { idle: t('Dictate'), listening: t('Dictating — click to stop') }, children: (state) => _jsx(MicIcon, { size: 16, color: "var(--foreground)", fill: state === 'idle' ? 'none' : 'var(--foreground)' }) }) }), _jsxs(DropdownMenu, { open: open, onOpenChange: setOpen, children: [_jsx(DropdownMenuTrigger, { asChild: true, disabled: disabled, children: _jsx(XStack, { render: "button", "aria-label": t('Dictation settings'), "data-slot": "dictation-menu", width: 16, height: 30, items: "center", justify: "center", rounded: 6, cursor: "pointer", bg: open ? '$hover' : 'transparent', hoverStyle: { bg: '$hover' }, ...(narrow ? { width: 44, height: 44 } : null), children: _jsx(ChevronDown, { size: 14, color: "$soft", opacity: shown || narrow ? 1 : 0 }) }) }), _jsxs(DropdownMenuContent, { align: "end", minW: 200, "data-slot": "dictation-panel", children: [_jsx(Meter, { device: device, on: open && allowed }), inputs.length === 0 ? (_jsx(DropdownMenuLabel, { children: _jsx(SizableText, { fontSize: 14, color: "$hint", children: t('No devices found') }) })) : (inputs.map((d, i) => {
|
|
126
133
|
const on = device ? d.deviceId === device : d.groupId === using;
|
|
127
134
|
return (_jsx(DropdownMenuItem, { preventCloseOnSelect: true, onSelect: () => {
|
|
128
135
|
setDevice(d.deviceId);
|
|
129
136
|
keep(d.deviceId);
|
|
130
|
-
}, children: _jsxs(XStack, { flex: 1, items: "center", gap: 8, children: [_jsx(SizableText, { fontSize: 14, color: "$ink", numberOfLines: 1, flex: 1, children: d.label ||
|
|
131
|
-
})), onLanguage ? (_jsxs(_Fragment, { children: [_jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuLabel, { children: _jsx(SizableText, { fontSize: 13, color: "$hint", children:
|
|
137
|
+
}, children: _jsxs(XStack, { flex: 1, items: "center", gap: 8, children: [_jsx(SizableText, { fontSize: 14, color: "$ink", numberOfLines: 1, flex: 1, children: d.label || t('Microphone {n}', { n: i + 1 }) }), on ? _jsx(Check, { size: 14, color: "var(--primary)", "aria-hidden": true }) : null] }) }, d.deviceId || i));
|
|
138
|
+
})), onLanguage ? (_jsxs(_Fragment, { children: [_jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuLabel, { children: _jsx(SizableText, { fontSize: 13, color: "$hint", children: t('Dictation settings') }) }), _jsxs(DropdownMenuSub, { open: lang, onOpenChange: setLang, children: [_jsx(DropdownMenuSubTrigger, { "data-slot": "dictation-language", onPress: () => setLang(true), children: _jsxs(XStack, { flex: 1, items: "center", gap: 8, children: [_jsx(SizableText, { fontSize: 14, color: "$ink", flex: 1, children: t('Language') }), _jsx(SizableText, { fontSize: 14, color: "$hint", children: spoken?.label ?? t('Auto') })] }) }), lang ? (_jsx(DropdownMenuSubContent, { minW: 160, pointerEvents: "auto", children: [{ id: '', label: t('Auto') }, ...LANGUAGES].map((l) => (_jsx(DropdownMenuItem, { onSelect: () => onLanguage(l.id || null), children: _jsxs(XStack, { flex: 1, items: "center", gap: 8, children: [_jsx(SizableText, { fontSize: 14, color: "$ink", flex: 1, children: l.label }), (language ?? '') === l.id ? _jsx(Check, { size: 14, color: "var(--primary)", "aria-hidden": true }) : null] }) }, l.id || 'auto'))) })) : null] })] })) : null] })] })] }));
|
|
132
139
|
}
|
package/lib/mind.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type Target } from './api/call.ts';
|
|
2
2
|
import { type Model } from './api/models.ts';
|
|
3
3
|
export type Effort = 'low' | 'medium' | 'high';
|
|
4
|
+
/** The efforts, in English and marked (`phrase`): the composer draws each word through `t`. */
|
|
4
5
|
export declare const EFFORTS: readonly {
|
|
5
6
|
id: Effort;
|
|
6
7
|
label: string;
|
package/lib/mind.js
CHANGED
|
@@ -16,15 +16,17 @@
|
|
|
16
16
|
* lists as not reasoning offers none; Enso and a model the catalog does not
|
|
17
17
|
* describe offer all three.
|
|
18
18
|
*/
|
|
19
|
+
import { phrase } from '@hanzo/i18n';
|
|
19
20
|
import { parseModels } from '@hanzo/ui/models/catalog';
|
|
20
21
|
import { useEffect, useState, useSyncExternalStore } from 'react';
|
|
21
22
|
import { Refusal } from './api/call.js';
|
|
22
23
|
import { ENSO, models as read } from './api/models.js';
|
|
23
24
|
import { usePick } from './pick.js';
|
|
25
|
+
/** The efforts, in English and marked (`phrase`): the composer draws each word through `t`. */
|
|
24
26
|
export const EFFORTS = [
|
|
25
|
-
{ id: 'low', label: 'Low', note: 'A quick pass' },
|
|
26
|
-
{ id: 'medium', label: 'Medium', note: 'Thinks before it answers' },
|
|
27
|
-
{ id: 'high', label: 'High', note: 'Slow and careful, for hard problems' },
|
|
27
|
+
{ id: 'low', label: phrase('Low'), note: phrase('A quick pass') },
|
|
28
|
+
{ id: 'medium', label: phrase('Medium'), note: phrase('Thinks before it answers') },
|
|
29
|
+
{ id: 'high', label: phrase('High'), note: phrase('Slow and careful, for hard problems') },
|
|
28
30
|
];
|
|
29
31
|
export const FIRST = { model: ENSO, effort: 'medium' };
|
|
30
32
|
/** What Free answers on: the catalog's free lane, Enso's first. `free` is an alias of it. */
|
package/lib/nav.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Say } from '@hanzo/i18n/react';
|
|
1
2
|
import type { RailLink } from '@hanzo/ui/chat';
|
|
2
3
|
import type { Host } from './host.tsx';
|
|
3
4
|
/** A run of places under one quiet label; '' draws none. */
|
|
@@ -8,20 +9,20 @@ export interface Group {
|
|
|
8
9
|
}
|
|
9
10
|
/** The id of the row that starts a new run: a rail with a New control of its own draws that instead. */
|
|
10
11
|
export declare const NEW = "new";
|
|
11
|
-
export declare function nav(host: Host, go: (path: string) => void): Group[];
|
|
12
|
+
export declare function nav(host: Host, go: (path: string) => void, t?: Say): Group[];
|
|
12
13
|
/** Dev's own places: what a host whose rail holds the rest (Library, Scheduled tasks, Customize) lists in Dev's sidebar. */
|
|
13
|
-
export declare const own: (host: Host, go: (path: string) => void) => Group[];
|
|
14
|
+
export declare const own: (host: Host, go: (path: string) => void, t?: Say) => Group[];
|
|
14
15
|
/**
|
|
15
16
|
* Settings' sections as a host's sidebar lists them: one group per part, a
|
|
16
17
|
* part's label drawn only where it is not its first row's name (Code leads
|
|
17
18
|
* Code's part, so the part is not labelled twice).
|
|
18
19
|
*/
|
|
19
|
-
export declare function sections(host: Host, go: (path: string) => void): Group[];
|
|
20
|
+
export declare function sections(host: Host, go: (path: string) => void, t?: Say): Group[];
|
|
20
21
|
/** Customize's tabs as a host's sidebar lists them, Agents first; an agent's profile lights Agents. */
|
|
21
|
-
export declare function tabs(host: Host, go: (path: string) => void): Group[];
|
|
22
|
+
export declare function tabs(host: Host, go: (path: string) => void, t?: Say): Group[];
|
|
22
23
|
/** Fired on `window` once the sidebar's Upload has kept its files, for the Library to read again. */
|
|
23
24
|
export declare const KEPT = "hanzo:library:kept";
|
|
24
25
|
/** The Library's sidebar: Upload, then every kind it narrows to, the one in the address lit. */
|
|
25
|
-
export declare function library(host: Host, go: (path: string) => void): Group[];
|
|
26
|
+
export declare function library(host: Host, go: (path: string) => void, t?: Say): Group[];
|
|
26
27
|
/** Scheduled tasks' sidebar: New task, then each of the person's tasks, the one open lit. Read only while `on`. */
|
|
27
28
|
export declare function useScheduled(host: Host, go: (path: string) => void, on: boolean): Group[];
|
package/lib/nav.js
CHANGED
|
@@ -8,8 +8,13 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
8
8
|
*
|
|
9
9
|
* Every row moves the builder through `go` with the address `path` writes, so
|
|
10
10
|
* where a place lives is said here and in route.ts and nowhere else.
|
|
11
|
+
*
|
|
12
|
+
* The rows' words are the reader's language when the caller hands in its
|
|
13
|
+
* @hanzo/i18n `t` (English without one); a task's name is the person's own.
|
|
11
14
|
*/
|
|
12
15
|
import { AudioLines, Bell, BookOpen, Bot, Box, Brain, CircleDot, Clock, Code, Container, Cpu, CreditCard, File, FileText, FolderGit2, Gauge, Image, Key, LayoutTemplate, Library, Plug, Plus, Presentation, Puzzle, Settings, Shield, SlidersHorizontal, Sparkles, SquarePen, Upload, User, Users, Video } from '@hanzogui/lucide-icons-2';
|
|
16
|
+
import { phrase } from '@hanzo/i18n';
|
|
17
|
+
import { useI18n } from '@hanzo/i18n/react';
|
|
13
18
|
import { useMemo } from 'react';
|
|
14
19
|
import { automations } from './api/auto.js';
|
|
15
20
|
import { KINDS, upload } from './api/library.js';
|
|
@@ -17,10 +22,11 @@ import { pinBoard } from './choice.js';
|
|
|
17
22
|
import { useRead } from './data.js';
|
|
18
23
|
import { DOCS } from './foot.js';
|
|
19
24
|
import { path, route, TABS } from './route.js';
|
|
25
|
+
import { english } from './say.js';
|
|
20
26
|
import { GROUPS, heading, LIST } from './settings/list.js';
|
|
21
27
|
/** The id of the row that starts a new run: a rail with a New control of its own draws that instead. */
|
|
22
28
|
export const NEW = 'new';
|
|
23
|
-
export function nav(host, go) {
|
|
29
|
+
export function nav(host, go, t = english) {
|
|
24
30
|
const r = route(host.path);
|
|
25
31
|
const screen = r.kind === 'screen' ? r.screen : '';
|
|
26
32
|
const section = r.kind === 'settings' ? r.section : '';
|
|
@@ -28,20 +34,20 @@ export function nav(host, go) {
|
|
|
28
34
|
return [
|
|
29
35
|
{
|
|
30
36
|
id: 'work',
|
|
31
|
-
label: 'Work',
|
|
37
|
+
label: t('Work'),
|
|
32
38
|
links: [
|
|
33
|
-
{ id: NEW, label: 'New run', icon: _jsx(SquarePen, { size: 16 }), onPress: to(''), active: r.kind === 'new' },
|
|
39
|
+
{ id: NEW, label: t('New run'), icon: _jsx(SquarePen, { size: 16 }), onPress: to(''), active: r.kind === 'new' },
|
|
34
40
|
// A project is a repository: its list, linking one from GitHub, and one's workspace.
|
|
35
41
|
{
|
|
36
42
|
id: 'projects',
|
|
37
|
-
label: 'Projects',
|
|
43
|
+
label: t('Projects'),
|
|
38
44
|
icon: _jsx(FolderGit2, { size: 16 }),
|
|
39
45
|
onPress: to(path({ kind: 'screen', screen: 'projects' })),
|
|
40
46
|
active: screen === 'projects' || screen === 'sync' || r.kind === 'repo',
|
|
41
47
|
},
|
|
42
48
|
{
|
|
43
49
|
id: 'issues',
|
|
44
|
-
label: 'Issues',
|
|
50
|
+
label: t('Issues'),
|
|
45
51
|
icon: _jsx(CircleDot, { size: 16 }),
|
|
46
52
|
onPress: () => {
|
|
47
53
|
pinBoard(host.org, '');
|
|
@@ -49,61 +55,61 @@ export function nav(host, go) {
|
|
|
49
55
|
},
|
|
50
56
|
active: screen === 'issues',
|
|
51
57
|
},
|
|
52
|
-
{ id: 'templates', label: 'Templates', icon: _jsx(LayoutTemplate, { size: 16 }), onPress: to(path({ kind: 'screen', screen: 'templates' })), active: screen === 'templates' },
|
|
58
|
+
{ id: 'templates', label: t('Templates'), icon: _jsx(LayoutTemplate, { size: 16 }), onPress: to(path({ kind: 'screen', screen: 'templates' })), active: screen === 'templates' },
|
|
53
59
|
],
|
|
54
60
|
},
|
|
55
61
|
{
|
|
56
62
|
id: 'make',
|
|
57
|
-
label: 'Make',
|
|
63
|
+
label: t('Make'),
|
|
58
64
|
links: [
|
|
59
|
-
{ id: 'artifacts', label: 'Library', icon: _jsx(Library, { size: 16 }), onPress: to(path({ kind: 'screen', screen: 'artifacts' })), active: screen === 'artifacts' },
|
|
60
|
-
{ id: 'automations', label: 'Scheduled tasks', icon: _jsx(Clock, { size: 16 }), onPress: to(path({ kind: 'screen', screen: 'automations' })), active: screen === 'automations' || r.kind === 'automation' },
|
|
65
|
+
{ id: 'artifacts', label: t('Library'), icon: _jsx(Library, { size: 16 }), onPress: to(path({ kind: 'screen', screen: 'artifacts' })), active: screen === 'artifacts' },
|
|
66
|
+
{ id: 'automations', label: t('Scheduled tasks'), icon: _jsx(Clock, { size: 16 }), onPress: to(path({ kind: 'screen', screen: 'automations' })), active: screen === 'automations' || r.kind === 'automation' },
|
|
61
67
|
],
|
|
62
68
|
},
|
|
63
69
|
{
|
|
64
70
|
id: 'run',
|
|
65
|
-
label: 'Run',
|
|
71
|
+
label: t('Run'),
|
|
66
72
|
links: [
|
|
67
|
-
{ id: 'machines', label: 'Machines', icon: _jsx(Cpu, { size: 16 }), onPress: to(path({ kind: 'settings', section: 'machines' })), active: section === 'machines' },
|
|
68
|
-
{ id: 'environments', label: 'Environments', icon: _jsx(Container, { size: 16 }), onPress: to(path({ kind: 'settings', section: 'environments' })), active: section === 'environments' },
|
|
73
|
+
{ id: 'machines', label: t('Machines'), icon: _jsx(Cpu, { size: 16 }), onPress: to(path({ kind: 'settings', section: 'machines' })), active: section === 'machines' },
|
|
74
|
+
{ id: 'environments', label: t('Environments'), icon: _jsx(Container, { size: 16 }), onPress: to(path({ kind: 'settings', section: 'environments' })), active: section === 'environments' },
|
|
69
75
|
],
|
|
70
76
|
},
|
|
71
77
|
{
|
|
72
78
|
id: 'setup',
|
|
73
|
-
label: 'Setup',
|
|
79
|
+
label: t('Setup'),
|
|
74
80
|
links: [
|
|
75
|
-
{ id: 'customize', label: 'Customize', icon: _jsx(SlidersHorizontal, { size: 16 }), onPress: to(path({ kind: 'customize', tab: 'agents' })), active: r.kind === 'customize' || r.kind === 'agent' || screen === 'mcp' },
|
|
76
|
-
{ id: 'docs', label: 'Docs', icon: _jsx(BookOpen, { size: 16 }), onPress: () => window.open(DOCS, '_blank', 'noopener,noreferrer') },
|
|
81
|
+
{ id: 'customize', label: t('Customize'), icon: _jsx(SlidersHorizontal, { size: 16 }), onPress: to(path({ kind: 'customize', tab: 'agents' })), active: r.kind === 'customize' || r.kind === 'agent' || screen === 'mcp' },
|
|
82
|
+
{ id: 'docs', label: t('Docs'), icon: _jsx(BookOpen, { size: 16 }), onPress: () => window.open(DOCS, '_blank', 'noopener,noreferrer') },
|
|
77
83
|
],
|
|
78
84
|
},
|
|
79
85
|
];
|
|
80
86
|
}
|
|
81
87
|
/** Dev's own places: what a host whose rail holds the rest (Library, Scheduled tasks, Customize) lists in Dev's sidebar. */
|
|
82
|
-
export const own = (host, go) => nav(host, go).filter((g) => g.id === 'work');
|
|
88
|
+
export const own = (host, go, t = english) => nav(host, go, t).filter((g) => g.id === 'work');
|
|
83
89
|
/**
|
|
84
90
|
* Settings' sections as a host's sidebar lists them: one group per part, a
|
|
85
91
|
* part's label drawn only where it is not its first row's name (Code leads
|
|
86
92
|
* Code's part, so the part is not labelled twice).
|
|
87
93
|
*/
|
|
88
|
-
export function sections(host, go) {
|
|
94
|
+
export function sections(host, go, t = english) {
|
|
89
95
|
const r = route(host.path);
|
|
90
96
|
const at = r.kind === 'settings' ? r.section : '';
|
|
91
97
|
return GROUPS.map((g) => {
|
|
92
98
|
const rows = LIST.filter((e) => e.group === g);
|
|
93
99
|
return {
|
|
94
100
|
id: g,
|
|
95
|
-
label: heading(g),
|
|
96
|
-
links: rows.map((e) => ({ id: e.id, label: e.label, icon: SECTION_ICON[e.id], onPress: () => go(path({ kind: 'settings', section: e.id })), active: e.id === at })),
|
|
101
|
+
label: t(heading(g)),
|
|
102
|
+
links: rows.map((e) => ({ id: e.id, label: t(e.label), icon: SECTION_ICON[e.id], onPress: () => go(path({ kind: 'settings', section: e.id })), active: e.id === at })),
|
|
97
103
|
};
|
|
98
104
|
});
|
|
99
105
|
}
|
|
100
106
|
/** Customize's tabs as a host's sidebar lists them, Agents first; an agent's profile lights Agents. */
|
|
101
|
-
export function tabs(host, go) {
|
|
107
|
+
export function tabs(host, go, t = english) {
|
|
102
108
|
const r = route(host.path);
|
|
103
109
|
const at = r.kind === 'customize' ? r.tab : r.kind === 'agent' ? 'agents' : '';
|
|
104
|
-
return [{ id: 'customize', label: '', links: TABS.map((
|
|
110
|
+
return [{ id: 'customize', label: '', links: TABS.map((tab) => ({ id: tab, label: t(TAB_LABEL[tab]), icon: TAB_ICON[tab], onPress: () => go(path({ kind: 'customize', tab })), active: tab === at })) }];
|
|
105
111
|
}
|
|
106
|
-
const TAB_LABEL = { agents: 'Agents', skills: 'Skills', connectors: 'Connectors', plugins: 'Plugins' };
|
|
112
|
+
const TAB_LABEL = { agents: phrase('Agents'), skills: phrase('Skills'), connectors: phrase('Connectors'), plugins: phrase('Plugins') };
|
|
107
113
|
const TAB_ICON = { agents: _jsx(Bot, { size: 16 }), skills: _jsx(BookOpen, { size: 16 }), connectors: _jsx(Plug, { size: 16 }), plugins: _jsx(Puzzle, { size: 16 }) };
|
|
108
114
|
const SECTION_ICON = {
|
|
109
115
|
general: _jsx(Settings, { size: 16 }),
|
|
@@ -135,7 +141,7 @@ const KIND_ICON = {
|
|
|
135
141
|
/** Fired on `window` once the sidebar's Upload has kept its files, for the Library to read again. */
|
|
136
142
|
export const KEPT = 'hanzo:library:kept';
|
|
137
143
|
/** Asks for files and keeps each in the Library; a refusal is said in the page's own words. */
|
|
138
|
-
function keep(host) {
|
|
144
|
+
function keep(host, say) {
|
|
139
145
|
const input = document.createElement('input');
|
|
140
146
|
input.type = 'file';
|
|
141
147
|
input.multiple = true;
|
|
@@ -146,7 +152,7 @@ function keep(host) {
|
|
|
146
152
|
await upload(t, { name: f.name, type: f.type, bytes: new Uint8Array(await f.arrayBuffer()) }, { source: 'chat' });
|
|
147
153
|
}
|
|
148
154
|
catch (e) {
|
|
149
|
-
window.alert(e instanceof Error ? e.message :
|
|
155
|
+
window.alert(e instanceof Error ? e.message : say('{file} was not kept', { file: f.name }));
|
|
150
156
|
}
|
|
151
157
|
}
|
|
152
158
|
window.dispatchEvent(new Event(KEPT));
|
|
@@ -154,17 +160,17 @@ function keep(host) {
|
|
|
154
160
|
input.click();
|
|
155
161
|
}
|
|
156
162
|
/** The Library's sidebar: Upload, then every kind it narrows to, the one in the address lit. */
|
|
157
|
-
export function library(host, go) {
|
|
163
|
+
export function library(host, go, t = english) {
|
|
158
164
|
const r = route(host.path);
|
|
159
165
|
const at = r.kind === 'screen' && r.screen === 'artifacts' ? (r.of ?? '') : null;
|
|
160
166
|
return [
|
|
161
|
-
{ id: 'library-do', label: '', links: [{ id: 'upload', label: 'Upload', icon: _jsx(Upload, { size: 16 }), onPress: () => keep(host) }] },
|
|
167
|
+
{ id: 'library-do', label: '', links: [{ id: 'upload', label: t('Upload'), icon: _jsx(Upload, { size: 16 }), onPress: () => keep(host, t) }] },
|
|
162
168
|
{
|
|
163
169
|
id: 'library-kinds',
|
|
164
170
|
label: '',
|
|
165
171
|
links: KINDS.map((k) => ({
|
|
166
172
|
id: `kind-${k.id || 'all'}`,
|
|
167
|
-
label: k.label,
|
|
173
|
+
label: t(k.label),
|
|
168
174
|
icon: KIND_ICON[k.id],
|
|
169
175
|
onPress: () => go(path({ kind: 'screen', screen: 'artifacts', ...(k.id ? { of: k.id } : {}) })),
|
|
170
176
|
active: at === k.id,
|
|
@@ -174,6 +180,7 @@ export function library(host, go) {
|
|
|
174
180
|
}
|
|
175
181
|
/** Scheduled tasks' sidebar: New task, then each of the person's tasks, the one open lit. Read only while `on`. */
|
|
176
182
|
export function useScheduled(host, go, on) {
|
|
183
|
+
const { t: say } = useI18n();
|
|
177
184
|
const t = useMemo(() => ({ api: host.api, token: host.token, org: host.org }), [host.api, host.token, host.org]);
|
|
178
185
|
const list = useRead(on && host.person ? () => automations(t) : null, [], [t, on, host.path]);
|
|
179
186
|
const r = route(host.path);
|
|
@@ -182,12 +189,12 @@ export function useScheduled(host, go, on) {
|
|
|
182
189
|
{
|
|
183
190
|
id: 'scheduled-do',
|
|
184
191
|
label: '',
|
|
185
|
-
links: [{ id: 'new-task', label: 'New task', icon: _jsx(Plus, { size: 16 }), onPress: () => go(path({ kind: 'automation', id: 'new' })), active: at === 'new' }],
|
|
192
|
+
links: [{ id: 'new-task', label: say('New task'), icon: _jsx(Plus, { size: 16 }), onPress: () => go(path({ kind: 'automation', id: 'new' })), active: at === 'new' }],
|
|
186
193
|
},
|
|
187
194
|
{
|
|
188
195
|
id: 'scheduled-tasks',
|
|
189
|
-
label: list.value.length ? 'Tasks' : '',
|
|
190
|
-
links: list.value.map((a) => ({ id: a.id, label: a.name || 'Untitled task', icon: _jsx(Clock, { size: 16 }), onPress: () => go(path({ kind: 'automation', id: a.id })), active: at === a.id })),
|
|
196
|
+
label: list.value.length ? say('Tasks') : '',
|
|
197
|
+
links: list.value.map((a) => ({ id: a.id, label: a.name || say('Untitled task'), icon: _jsx(Clock, { size: 16 }), onPress: () => go(path({ kind: 'automation', id: a.id })), active: at === a.id })),
|
|
191
198
|
},
|
|
192
199
|
];
|
|
193
200
|
}
|
package/lib/panel.d.ts
CHANGED
|
@@ -20,7 +20,8 @@ export interface Suggestion {
|
|
|
20
20
|
/**
|
|
21
21
|
* The header's control for the tabs, while they are hidden: an icon among the
|
|
22
22
|
* header's icons. Open, the strip's own toggle stands at the panel's end and
|
|
23
|
-
* this one is not drawn, so the page carries one toggle at a time.
|
|
23
|
+
* this one is not drawn, so the page carries one toggle at a time. Its words
|
|
24
|
+
* are the reader's language; the key chord is an argument, as this platform writes it.
|
|
24
25
|
*/
|
|
25
26
|
export declare function PanelToggle({ open, onToggle }: {
|
|
26
27
|
open: boolean;
|