@hanzo/build 0.2.80 → 0.2.81
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/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 +2 -1
- 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/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 +6 -3
- 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 +18 -15
- 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/customize/index.js
CHANGED
|
@@ -9,8 +9,12 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
9
9
|
* Skills and connectors ride into every run in the org, so adding, switching
|
|
10
10
|
* and removing them is an org admin's and a member reads them; plugins and
|
|
11
11
|
* agents are any member's.
|
|
12
|
+
*
|
|
13
|
+
* Its words are the reader's language (@hanzo/i18n `t`).
|
|
12
14
|
*/
|
|
13
15
|
import { SizableText, XStack, YStack } from '@hanzo/gui';
|
|
16
|
+
import { phrase } from '@hanzo/i18n';
|
|
17
|
+
import { useI18n } from '@hanzo/i18n/react';
|
|
14
18
|
import { BookOpen, Bot, Plug, Plus, Puzzle } from '@hanzogui/lucide-icons-2';
|
|
15
19
|
import { Button, Input } from '@hanzo/ui';
|
|
16
20
|
import { useCallback, useState } from 'react';
|
|
@@ -23,13 +27,42 @@ import { Skills } from './skills.js';
|
|
|
23
27
|
import { Choice } from './ui.js';
|
|
24
28
|
/** What every run in the org loads: an org admin's to add to, a member's to read. */
|
|
25
29
|
export const ORG_KIT = ['skills', 'connectors'];
|
|
30
|
+
/**
|
|
31
|
+
* Each tab's words, English and marked (`phrase`), drawn through `t`: its name,
|
|
32
|
+
* its line, its add control, its search and the search's hint, and, for a tab
|
|
33
|
+
* an org admin keeps (ORG_KIT), what a member is told.
|
|
34
|
+
*/
|
|
26
35
|
const LABEL = {
|
|
27
|
-
skills: {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
36
|
+
skills: {
|
|
37
|
+
title: phrase('Skills'),
|
|
38
|
+
says: phrase('Know-how an agent reads before it works.'),
|
|
39
|
+
add: phrase('New skill'),
|
|
40
|
+
find: phrase('Search skills'),
|
|
41
|
+
typing: phrase('Search skills…'),
|
|
42
|
+
admin: phrase('Only an org admin can add or change skills. You can see what is on.'),
|
|
43
|
+
icon: _jsx(BookOpen, { size: 15 }),
|
|
44
|
+
},
|
|
45
|
+
connectors: {
|
|
46
|
+
title: phrase('Connectors'),
|
|
47
|
+
says: phrase('Apps and tools an agent can call.'),
|
|
48
|
+
add: phrase('Add by URL'),
|
|
49
|
+
find: phrase('Search connectors'),
|
|
50
|
+
typing: phrase('Search connectors…'),
|
|
51
|
+
admin: phrase('Only an org admin can add or change connectors. You can see what is on.'),
|
|
52
|
+
icon: _jsx(Plug, { size: 15 }),
|
|
53
|
+
},
|
|
54
|
+
plugins: { title: phrase('Plugins'), says: phrase('Connectors you build in TypeScript.'), add: phrase('Build plugin'), find: phrase('Search plugins'), typing: phrase('Search plugins…'), icon: _jsx(Puzzle, { size: 15 }) },
|
|
55
|
+
agents: {
|
|
56
|
+
title: phrase('Agents'),
|
|
57
|
+
says: phrase('Agents with their own model, instructions and budget.'),
|
|
58
|
+
add: phrase('New agent'),
|
|
59
|
+
find: phrase('Search agents'),
|
|
60
|
+
typing: phrase('Search agents…'),
|
|
61
|
+
icon: _jsx(Bot, { size: 15 }),
|
|
62
|
+
},
|
|
31
63
|
};
|
|
32
64
|
export function Customize({ tab, view: first }) {
|
|
65
|
+
const { t } = useI18n();
|
|
33
66
|
const host = useHost();
|
|
34
67
|
const [view, setView] = useState(first ?? 'discover');
|
|
35
68
|
const [q, setQ] = useState('');
|
|
@@ -46,11 +79,11 @@ export function Customize({ tab, view: first }) {
|
|
|
46
79
|
const pane = { view, q, adding, onAdding: setAdding, onView: setView, onCount };
|
|
47
80
|
const kit = ORG_KIT.includes(tab);
|
|
48
81
|
const may = Boolean(host.person) && (host.admin || !kit);
|
|
49
|
-
return (_jsx(YStack, { flex: 1, minH: 0, overflow: "scroll", px: "$6", py: "$6", "$max-md": { px: '$4', py: '$4' }, children: _jsxs(YStack, { width: "100%", maxW: 1080, mx: "auto", gap: "$4", children: [_jsxs(YStack, { gap: "$1", children: [_jsx(SizableText, { render: "h1", size: "$6", color: "$ink", children: host.sections ? LABEL[tab].title : 'Customize' }), _jsx(SizableText, { size: "$2", color: "$soft", children: host.sections ? LABEL[tab].says : 'What your agent can use in every run.' })] }), host.sections ? null : (_jsx(XStack, { role: "tablist", "aria-label":
|
|
82
|
+
return (_jsx(YStack, { flex: 1, minH: 0, overflow: "scroll", px: "$6", py: "$6", "$max-md": { px: '$4', py: '$4' }, children: _jsxs(YStack, { width: "100%", maxW: 1080, mx: "auto", gap: "$4", children: [_jsxs(YStack, { gap: "$1", children: [_jsx(SizableText, { render: "h1", size: "$6", color: "$ink", children: host.sections ? t(LABEL[tab].title) : t('Customize') }), _jsx(SizableText, { size: "$2", color: "$soft", children: host.sections ? t(LABEL[tab].says) : t('What your agent can use in every run.') })] }), host.sections ? null : (_jsx(XStack, { role: "tablist", "aria-label": t('Customize'), gap: "$4", borderBottomWidth: 1, borderColor: "$borderColor", "$max-md": { gap: '$3' }, children: TABS.map((id) => {
|
|
50
83
|
const on = id === tab;
|
|
51
|
-
return (_jsxs(XStack, { role: "tab", render: "button", "aria-selected": on, onPress: () => pick(id), items: "center", gap: "$1.5", pb: "$2", mb: -1, borderBottomWidth: 2, borderColor: on ? '$ink' : 'transparent', hoverStyle: { borderColor: on ? '$ink' : '$edge' }, children: [_jsx(XStack, { opacity: on ? 1 : 0.6, "$max-md": { display: 'none' }, children: LABEL[id].icon }), _jsx(SizableText, { size: "$3", color: on ? '$ink' : '$soft', children: LABEL[id].title })] }, id));
|
|
52
|
-
}) })), host.sections ? null : (_jsx(SizableText, { size: "$2", color: "$soft", children: LABEL[tab].says })), _jsxs(XStack, { items: "center", gap: "$2", children: [_jsx(Choice, { label:
|
|
53
|
-
{ id: 'discover', label: 'Browse' },
|
|
54
|
-
{ id: 'yours', label: 'Yours', count },
|
|
55
|
-
], onChange: setView }), _jsx(XStack, { flex: 1 }), may ? (_jsxs(Button, { size: "sm", onPress: () => setAdding(true), children: [_jsx(Plus, { size: 14 }), " ", LABEL[tab].add] })) : null] }), _jsx(Input, { value: q, onChangeText: setQ, placeholder:
|
|
84
|
+
return (_jsxs(XStack, { role: "tab", render: "button", "aria-selected": on, onPress: () => pick(id), items: "center", gap: "$1.5", pb: "$2", mb: -1, borderBottomWidth: 2, borderColor: on ? '$ink' : 'transparent', hoverStyle: { borderColor: on ? '$ink' : '$edge' }, children: [_jsx(XStack, { opacity: on ? 1 : 0.6, "$max-md": { display: 'none' }, children: LABEL[id].icon }), _jsx(SizableText, { size: "$3", color: on ? '$ink' : '$soft', children: t(LABEL[id].title) })] }, id));
|
|
85
|
+
}) })), host.sections ? null : (_jsx(SizableText, { size: "$2", color: "$soft", children: t(LABEL[tab].says) })), _jsxs(XStack, { items: "center", gap: "$2", children: [_jsx(Choice, { label: t('Show'), value: view, options: [
|
|
86
|
+
{ id: 'discover', label: t('Browse') },
|
|
87
|
+
{ id: 'yours', label: t('Yours'), count },
|
|
88
|
+
], onChange: setView }), _jsx(XStack, { flex: 1 }), may ? (_jsxs(Button, { size: "sm", onPress: () => setAdding(true), children: [_jsx(Plus, { size: 14 }), " ", t(LABEL[tab].add)] })) : null] }), _jsx(Input, { value: q, onChangeText: setQ, placeholder: t(LABEL[tab].typing), "aria-label": t(LABEL[tab].find) }), host.person && kit && !host.admin && LABEL[tab].admin ? (_jsx(SizableText, { size: "$1", color: "$soft", children: t(LABEL[tab].admin) })) : null, tab === 'skills' ? (_jsx(Skills, { ...pane })) : tab === 'connectors' ? (_jsx(Connectors, { ...pane })) : tab === 'plugins' ? (_jsx(Plugins, { ...pane })) : (_jsx(Agents, { ...pane }))] }) }));
|
|
56
89
|
}
|
package/lib/customize/plugins.js
CHANGED
|
@@ -9,8 +9,12 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
9
9
|
* Describe an API instead of writing the TypeScript and a model writes it; the
|
|
10
10
|
* result opens to be read. A plugin carries no credential: it names the
|
|
11
11
|
* connector whose credential it reads when it runs.
|
|
12
|
+
*
|
|
13
|
+
* Its words are the reader's language (@hanzo/i18n `t`); a plugin's name, its
|
|
14
|
+
* source and the bundler's reasons are drawn as given.
|
|
12
15
|
*/
|
|
13
16
|
import { SizableText, XStack, YStack } from '@hanzo/gui';
|
|
17
|
+
import { useI18n } from '@hanzo/i18n/react';
|
|
14
18
|
import { Puzzle } from '@hanzogui/lucide-icons-2';
|
|
15
19
|
import { Button, Input, Textarea } from '@hanzo/ui';
|
|
16
20
|
import { Code } from '@hanzo/ui/chat';
|
|
@@ -22,11 +26,12 @@ import { say } from './say.js';
|
|
|
22
26
|
import { Choice, Confirm, day, Empty, Failed, Field, Grid, Line, Mark, matches, mono, Part, Sheet, Soft, Tile, useCount, Visitor } from './ui.js';
|
|
23
27
|
const kb = (n) => (n < 1024 ? `${n} B` : `${(n / 1024).toFixed(1)} KB`);
|
|
24
28
|
export function Plugins({ view, q, adding, onAdding, onView, onCount }) {
|
|
29
|
+
const { t } = useI18n();
|
|
25
30
|
const host = useHost();
|
|
26
|
-
const
|
|
31
|
+
const target = useTarget();
|
|
27
32
|
const signed = Boolean(host.person);
|
|
28
|
-
const mine = useLoad(signed ? () => authored(
|
|
29
|
-
const mounts = useLoad(signed && view === 'discover' ? () => mounted(
|
|
33
|
+
const mine = useLoad(signed ? () => authored(target) : null, [], [target, signed]);
|
|
34
|
+
const mounts = useLoad(signed && view === 'discover' ? () => mounted(target) : null, [], [target, signed, view]);
|
|
30
35
|
const [opened, setOpened] = useState(null);
|
|
31
36
|
const [note, setNote] = useState('');
|
|
32
37
|
useCount(mine.value.length, onCount);
|
|
@@ -37,27 +42,24 @@ export function Plugins({ view, q, adding, onAdding, onView, onCount }) {
|
|
|
37
42
|
setNote(said);
|
|
38
43
|
setOpened(p);
|
|
39
44
|
} })) : null, opened ? (_jsx(Source, { plugin: opened, onClose: () => setOpened(null), onDeleted: () => {
|
|
40
|
-
setNote(
|
|
45
|
+
setNote(t('{name} is deleted', { name: opened.name }));
|
|
41
46
|
setOpened(null);
|
|
42
47
|
mine.reload();
|
|
43
48
|
} })) : null] }));
|
|
44
49
|
if (!signed) {
|
|
45
|
-
return _jsx(Visitor, { children: view === 'discover' ? 'Sign in to browse plugins.' : 'Sign in to see your plugins.' });
|
|
50
|
+
return _jsx(Visitor, { children: view === 'discover' ? t('Sign in to browse plugins.') : t('Sign in to see your plugins.') });
|
|
46
51
|
}
|
|
47
52
|
if (view === 'discover') {
|
|
48
53
|
const shown = mounts.value.filter((m) => matches(q, m.name, ...m.prefixes));
|
|
49
|
-
return (_jsxs(YStack, { gap: "$6", children: [_jsx(Line, { children: note }), _jsx(Part, { title:
|
|
54
|
+
return (_jsxs(YStack, { gap: "$6", children: [_jsx(Line, { children: note }), _jsx(Part, { title: t('Build your own'), detail: t('Write a connector in TypeScript, or describe an API and Hanzo writes it.'), children: _jsx(XStack, { children: _jsx(Button, { size: "sm", onPress: () => onAdding(true), children: t('Build a plugin') }) }) }), _jsx(Part, { title: t('Built in'), detail: t('Part of Hanzo. Always on, nothing to add.'), children: mounts.error && !mounts.value.length ? (_jsx(Failed, { error: mounts.error, onRetry: mounts.reload })) : mounts.loading && !mounts.value.length ? (_jsx(Soft, { children: t('Loading built-in plugins…') })) : !shown.length ? (_jsx(Soft, { children: mounts.value.length ? t('Nothing built in matches “{q}”.', { q: q.trim() }) : t('Nothing built in is listed.') })) : (_jsxs(_Fragment, { children: [_jsx(SizableText, { size: "$1", color: "$soft", children: t('{n} built in', { n: shown.length }) }), _jsx(Grid, { label: t('Mounted subsystems'), children: shown.map((m) => (_jsx(Tile, { title: m.name, detail: m.prefixes.join(' '), meta: m.enabled ? t('On') : t('Off'), mark: _jsx(Mark, { name: m.name, icon: _jsx(Puzzle, { size: 15 }) }) }, m.name))) })] })) }), sheets] }));
|
|
50
55
|
}
|
|
51
56
|
const shown = mine.value.filter((p) => matches(q, p.name, p.provider));
|
|
52
|
-
return (_jsxs(YStack, { gap: "$3", children: [_jsx(Line, { children: note }), mine.error && !mine.value.length ? (_jsx(Failed, { error: mine.error, onRetry: mine.reload })) : mine.loading && !mine.value.length ? (_jsx(Soft, { children:
|
|
57
|
+
return (_jsxs(YStack, { gap: "$3", children: [_jsx(Line, { children: note }), mine.error && !mine.value.length ? (_jsx(Failed, { error: mine.error, onRetry: mine.reload })) : mine.loading && !mine.value.length ? (_jsx(Soft, { children: t('Loading your plugins…') })) : !mine.value.length ? (_jsx(Empty, { title: t('No plugins yet'), detail: t('Write a connector in TypeScript, or describe an API and Hanzo writes it.'), children: _jsx(Button, { size: "sm", onPress: () => onAdding(true), children: t('Build a plugin') }) })) : !shown.length ? (_jsx(Soft, { children: t('No plugin of yours matches “{q}”.', { q: q.trim() }) })) : (_jsx(Grid, { label: t('Your plugins'), children: shown.map((p) => (_jsx(Tile, { title: p.name, detail: p.provider ? t('Reads the {provider} connector’s credential when it runs.', { provider: p.provider }) : t('Needs no credential.'), meta: day(p.built) ? t('Built {date}', { date: day(p.built) }) : undefined, mark: _jsx(Mark, { name: p.name }), onOpen: () => setOpened(p) }, p.id))) })), sheets] }));
|
|
53
58
|
}
|
|
54
|
-
const WAYS = [
|
|
55
|
-
{ id: 'source', label: 'TypeScript' },
|
|
56
|
-
{ id: 'spec', label: 'Describe an API' },
|
|
57
|
-
];
|
|
58
59
|
/** Build a plugin from its TypeScript, or from a description of the API it calls. */
|
|
59
60
|
function Build({ onClose, onBuilt }) {
|
|
60
|
-
const t =
|
|
61
|
+
const { t } = useI18n();
|
|
62
|
+
const target = useTarget();
|
|
61
63
|
const [name, setName] = useState('');
|
|
62
64
|
const [provider, setProvider] = useState('');
|
|
63
65
|
const [way, setWay] = useState('source');
|
|
@@ -68,28 +70,38 @@ function Build({ onClose, onBuilt }) {
|
|
|
68
70
|
const [note, setNote] = useState('');
|
|
69
71
|
const go = async () => {
|
|
70
72
|
setWorking(true);
|
|
71
|
-
setNote(way === 'spec' ? 'Writing and building it…' : 'Building it…');
|
|
73
|
+
setNote(way === 'spec' ? t('Writing and building it…') : t('Building it…'));
|
|
72
74
|
try {
|
|
73
|
-
const out = await build(
|
|
74
|
-
|
|
75
|
+
const out = await build(target, { name: name.trim(), provider, source: way === 'source' ? source : '', spec: way === 'spec' ? spec : '' });
|
|
76
|
+
const built = { name: out.plugin.name, size: kb(out.bytes) };
|
|
77
|
+
onBuilt(out.plugin, out.generated ? t('{name} built: {size}, written from your description — read it below.', built) : t('{name} built: {size}.', built));
|
|
75
78
|
}
|
|
76
79
|
catch (e) {
|
|
77
|
-
setNote(say(e));
|
|
80
|
+
setNote(say(e, t));
|
|
78
81
|
}
|
|
79
82
|
finally {
|
|
80
83
|
setWorking(false);
|
|
81
84
|
}
|
|
82
85
|
};
|
|
83
|
-
return (_jsxs(Sheet, { title:
|
|
84
|
-
|
|
85
|
-
|
|
86
|
+
return (_jsxs(Sheet, { title: t('Build a plugin'), open: true, onOpenChange: (o) => !o && onClose(), width: 680, children: [_jsx(Field, { label: t('Name'), hint: t('One lowercase word: letters, digits, _ or -.'), children: _jsx(Input, { value: name, onChangeText: setName, "aria-label": t('Name'), autoCapitalize: "none" }) }), _jsx(Field, { label: t('Connector'), hint: t('Optional. The connector whose key it uses when it runs; a plugin never holds a key itself.'), children: _jsx(Input, { value: provider, onChangeText: setProvider, "aria-label": t('Connector'), autoCapitalize: "none" }) }), _jsx(Choice, { label: t('Build from'), value: way, options: [
|
|
87
|
+
{ id: 'source', label: 'TypeScript' },
|
|
88
|
+
{ id: 'spec', label: t('Describe an API') },
|
|
89
|
+
], onChange: setWay }), _jsx(Field, { label: way === 'source' ? t('Source') : t('The API'), hint: way === 'source'
|
|
90
|
+
? t('Kept only if it builds. A failed build says why.')
|
|
91
|
+
: t('An OpenAPI document, or the endpoints in plain words. You read the TypeScript before it runs.'), children: _jsx(Textarea, { value: way === 'source' ? source : spec, onChangeText: way === 'source' ? setSource : setSpec, "aria-label": way === 'source' ? t('Source') : t('The API'), placeholder: way === 'source' ? 'export const acme = createProvider({ … })' : t('POST /v1/things creates a thing…'), rows: 14, style: mono }) }), _jsx(Line, { children: note }), _jsxs(XStack, { gap: "$2", justify: "flex-end", children: [_jsx(Button, { size: "sm", variant: "ghost", onPress: onClose, children: t('Cancel') }), _jsx(Button, { size: "sm", disabled: working, onPress: () => void go(), children: t('Build') })] })] }));
|
|
86
92
|
}
|
|
87
93
|
/** A built plugin's source, as the runtime will run it, and deleting it. */
|
|
88
94
|
function Source({ plugin, onClose, onDeleted }) {
|
|
89
|
-
const t =
|
|
95
|
+
const { t } = useI18n();
|
|
96
|
+
const target = useTarget();
|
|
90
97
|
const [asking, setAsking] = useState(false);
|
|
91
|
-
return (_jsxs(Sheet, { title: plugin.name, open: true, onOpenChange: (o) => !o && onClose(), width: 760, children: [
|
|
92
|
-
|
|
98
|
+
return (_jsxs(Sheet, { title: plugin.name, open: true, onOpenChange: (o) => !o && onClose(), width: 760, children: [_jsx(SizableText, { size: "$2", color: "$soft", children: [
|
|
99
|
+
plugin.provider ? t('Reads the {provider} connector’s credential when it runs.', { provider: plugin.provider }) : t('Needs no credential.'),
|
|
100
|
+
day(plugin.built) ? t('Built {date}.', { date: day(plugin.built) }) : '',
|
|
101
|
+
]
|
|
102
|
+
.filter(Boolean)
|
|
103
|
+
.join(' ') }), _jsx(Code, { language: "TypeScript", value: plugin.source, children: _jsx(SizableText, { size: "$1", color: "$ink", style: { ...mono, whiteSpace: 'pre' }, children: plugin.source }) }), _jsx(YStack, { items: "flex-start", children: _jsx(Button, { size: "sm", variant: "ghost", onPress: () => setAsking(true), children: t('Delete plugin') }) }), _jsx(Confirm, { what: plugin.name, says: t('The runtime can no longer load it.'), open: asking, onOpenChange: setAsking, onYes: async () => {
|
|
104
|
+
await remove(target, plugin.id);
|
|
93
105
|
onDeleted();
|
|
94
106
|
} })] }));
|
|
95
107
|
}
|
package/lib/customize/say.d.ts
CHANGED
|
@@ -1 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* What a read or a write that failed tells a person: plain words, never the
|
|
3
|
+
* platform's internals. A refusal is read by its status; only a 400, 409 or
|
|
4
|
+
* 422 carries the platform's own sentence, because those name what was wrong
|
|
5
|
+
* with what was sent (a name taken, a build that failed and why). A sentence
|
|
6
|
+
* this client wrote itself (a name that does not fit) is said as written.
|
|
7
|
+
*
|
|
8
|
+
* Said in the reader's language: the screen hands its `t` (English without
|
|
9
|
+
* one). A sentence a module wrote is English and marked, so it goes through
|
|
10
|
+
* `t`; the platform's own words are no key and come back from it as given.
|
|
11
|
+
*/
|
|
12
|
+
import type { Say } from '@hanzo/i18n/react';
|
|
13
|
+
export declare function say(e: unknown, t?: Say): string;
|
package/lib/customize/say.js
CHANGED
|
@@ -1,38 +1,32 @@
|
|
|
1
|
-
|
|
2
|
-
* What a read or a write that failed tells a person: plain words, never the
|
|
3
|
-
* platform's internals. A refusal is read by its status; only a 400, 409 or
|
|
4
|
-
* 422 carries the platform's own sentence, because those name what was wrong
|
|
5
|
-
* with what was sent (a name taken, a build that failed and why). A sentence
|
|
6
|
-
* this client wrote itself (a name that does not fit) is said as written.
|
|
7
|
-
*/
|
|
8
|
-
import { Refusal } from '../api/call.js';
|
|
1
|
+
import { Refusal, told } from '../api/call.js';
|
|
9
2
|
import { Slow } from '../data.js';
|
|
3
|
+
import { english } from '../say.js';
|
|
10
4
|
/** The line call.ts writes when the platform gave no reason: a method, a path and a status. */
|
|
11
5
|
const BARE = /^(GET|POST|PUT|PATCH|DELETE) \S* answered \d+$/;
|
|
12
|
-
export function say(e) {
|
|
6
|
+
export function say(e, t = english) {
|
|
13
7
|
if (e instanceof Slow)
|
|
14
|
-
return 'Hanzo is taking too long to answer. Try again.';
|
|
8
|
+
return t('Hanzo is taking too long to answer. Try again.');
|
|
15
9
|
if (e instanceof Refusal) {
|
|
16
10
|
if (e.status === 401)
|
|
17
|
-
return 'Your sign-in has expired. Sign in again.';
|
|
11
|
+
return t('Your sign-in has expired. Sign in again.');
|
|
18
12
|
if (e.status === 403)
|
|
19
|
-
return 'Your account can’t do this here. Ask an org admin.';
|
|
13
|
+
return t('Your account can’t do this here. Ask an org admin.');
|
|
20
14
|
if (e.status === 404)
|
|
21
|
-
return 'Not found. It may have been removed.';
|
|
15
|
+
return t('Not found. It may have been removed.');
|
|
22
16
|
if (e.status === 429)
|
|
23
|
-
return 'Too many requests. Wait a moment and try again.';
|
|
17
|
+
return t('Too many requests. Wait a moment and try again.');
|
|
24
18
|
if (e.status >= 500)
|
|
25
|
-
return 'Hanzo could not answer just now. Try again.';
|
|
19
|
+
return t('Hanzo could not answer just now. Try again.');
|
|
26
20
|
if ((e.status === 400 || e.status === 409 || e.status === 422) && e.message && !BARE.test(e.message))
|
|
27
|
-
return e.message;
|
|
28
|
-
return 'Hanzo could not do that. Try again.';
|
|
21
|
+
return t(e.message);
|
|
22
|
+
return t('Hanzo could not do that. Try again.');
|
|
29
23
|
}
|
|
30
24
|
// fetch rejects with a TypeError when the network does; a body that is not JSON is a SyntaxError.
|
|
31
25
|
if (e instanceof TypeError)
|
|
32
|
-
return 'Could not reach Hanzo. Check your connection and try again.';
|
|
26
|
+
return t('Could not reach Hanzo. Check your connection and try again.');
|
|
33
27
|
if (e instanceof SyntaxError)
|
|
34
|
-
return 'Hanzo answered with something unreadable. Try again.';
|
|
28
|
+
return t('Hanzo answered with something unreadable. Try again.');
|
|
35
29
|
if (e instanceof Error && e.message)
|
|
36
|
-
return e
|
|
37
|
-
return 'Something went wrong. Try again.';
|
|
30
|
+
return told(e, t);
|
|
31
|
+
return t('Something went wrong. Try again.');
|
|
38
32
|
}
|
package/lib/customize/skills.js
CHANGED
|
@@ -7,8 +7,12 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
7
7
|
* all adding is: the platform keeps no copy. Yours is the org's own skills —
|
|
8
8
|
* written here, each with its switch — and the catalogue's skills it has added.
|
|
9
9
|
* A skill written here is switched on when it is saved.
|
|
10
|
+
*
|
|
11
|
+
* Its words are the reader's language (@hanzo/i18n `t`); a skill's name,
|
|
12
|
+
* description and SKILL.md are the platform's or the org's, drawn as given.
|
|
10
13
|
*/
|
|
11
14
|
import { SizableText, XStack, YStack } from '@hanzo/gui';
|
|
15
|
+
import { useI18n } from '@hanzo/i18n/react';
|
|
12
16
|
import { BookOpen } from '@hanzogui/lucide-icons-2';
|
|
13
17
|
import { Button, Input, Switch, Textarea } from '@hanzo/ui';
|
|
14
18
|
import { Code } from '@hanzo/ui/chat';
|
|
@@ -21,14 +25,15 @@ import { say } from './say.js';
|
|
|
21
25
|
import { Add, Confirm, day, Empty, Failed, Field, Grid, Line, Mark, matches, mono, Part, Sheet, Soft, Tile, useCount, Visitor } from './ui.js';
|
|
22
26
|
const PAGE = 60;
|
|
23
27
|
export function Skills({ view, q, adding, onAdding, onView, onCount }) {
|
|
28
|
+
const { t } = useI18n();
|
|
24
29
|
const host = useHost();
|
|
25
|
-
const
|
|
30
|
+
const target = useTarget();
|
|
26
31
|
const signed = Boolean(host.person);
|
|
27
32
|
// What every run in the org loads is an org admin's to change; a member reads it.
|
|
28
33
|
const may = signed && host.admin;
|
|
29
|
-
const own = useLoad(signed ? () => authored(
|
|
30
|
-
const on = useLoad(signed ? () => active(
|
|
31
|
-
const shelf = useLoad(view === 'discover' ? () => brand(
|
|
34
|
+
const own = useLoad(signed ? () => authored(target) : null, [], [target, signed]);
|
|
35
|
+
const on = useLoad(signed ? () => active(target) : null, [], [target, signed]);
|
|
36
|
+
const shelf = useLoad(view === 'discover' ? () => brand(target) : null, null, [target.api, view]);
|
|
32
37
|
const [editing, setEditing] = useState(null);
|
|
33
38
|
const [reading, setReading] = useState(null);
|
|
34
39
|
const [busy, setBusy] = useState('');
|
|
@@ -43,12 +48,12 @@ export function Skills({ view, q, adding, onAdding, onView, onCount }) {
|
|
|
43
48
|
setBusy(name);
|
|
44
49
|
setNote('');
|
|
45
50
|
try {
|
|
46
|
-
await toggle(
|
|
51
|
+
await toggle(target, next ? [tool(name)] : [], next ? [] : [tool(name)]);
|
|
47
52
|
on.reload();
|
|
48
|
-
setNote(next ?
|
|
53
|
+
setNote(next ? t('{name} is on', { name }) : t('{name} is off', { name }));
|
|
49
54
|
}
|
|
50
55
|
catch (e) {
|
|
51
|
-
setNote(say(e));
|
|
56
|
+
setNote(say(e, t));
|
|
52
57
|
}
|
|
53
58
|
finally {
|
|
54
59
|
setBusy('');
|
|
@@ -64,20 +69,20 @@ export function Skills({ view, q, adding, onAdding, onView, onCount }) {
|
|
|
64
69
|
own.reload();
|
|
65
70
|
on.reload();
|
|
66
71
|
onView('yours');
|
|
67
|
-
setNote(fresh ?
|
|
72
|
+
setNote(fresh ? t('{name} is saved and on', { name: s.name }) : t('{name} is saved', { name: s.name }));
|
|
68
73
|
}, onDeleted: (name) => {
|
|
69
74
|
setEditing(null);
|
|
70
75
|
own.reload();
|
|
71
76
|
on.reload();
|
|
72
|
-
setNote(
|
|
77
|
+
setNote(t('{name} is deleted', { name }));
|
|
73
78
|
} })) : null;
|
|
74
79
|
if (view === 'discover') {
|
|
75
80
|
const all = shelf.value?.skills ?? [];
|
|
76
81
|
const found = all.filter((e) => matches(q, e.name, e.description, e.product));
|
|
77
|
-
return (_jsxs(YStack, { gap: "$3", children: [_jsx(Line, { children: note }), _jsx(Part, { title:
|
|
82
|
+
return (_jsxs(YStack, { gap: "$3", children: [_jsx(Line, { children: note }), _jsx(Part, { title: t('From Hanzo'), detail: t('Add one and every run in your organization can use it.'), children: shelf.error && !shelf.value ? (_jsx(Failed, { error: shelf.error, onRetry: shelf.reload })) : !shelf.value ? (_jsx(Soft, { children: t('Loading skills…') })) : !found.length ? (_jsx(Soft, { children: all.length ? t('No skill matches “{q}”.', { q: q.trim() }) : t('There are no skills to add yet.') })) : (_jsxs(_Fragment, { children: [_jsx(SizableText, { size: "$1", color: "$soft", children: found.length === all.length ? t('{n} skills', { n: all.length }) : t('{found} of {n} skills', { found: found.length, n: all.length }) }), _jsx(Grid, { label: t('Skills to add'), children: found.slice(0, shown).map((e) => (_jsx(Tile, { title: e.name, detail: e.description, meta: e.product, mark: _jsx(Mark, { name: e.name, icon: _jsx(BookOpen, { size: 15 }) }), onOpen: () => setReading(e), action: may ? _jsx(Add, { name: e.name, added: lit.has(tool(e.name)), busy: busy === e.name, onPress: () => void flip(e.name, true) }) : undefined }, e.name))) }), found.length > shown ? (_jsx(XStack, { justify: "center", children: _jsx(Button, { size: "sm", variant: "outline", onPress: () => setShown(shown + PAGE), children: t('Show more') }) })) : null] })) }), reader, editor] }));
|
|
78
83
|
}
|
|
79
84
|
if (!signed) {
|
|
80
|
-
return _jsx(Visitor, { children:
|
|
85
|
+
return _jsx(Visitor, { children: t('Sign in to see your skills.') });
|
|
81
86
|
}
|
|
82
87
|
const ownShown = own.value.filter((s) => matches(q, s.name, s.description));
|
|
83
88
|
const addedShown = added.filter((x) => matches(q, nameOf(x.name), x.description));
|
|
@@ -85,9 +90,11 @@ export function Skills({ view, q, adding, onAdding, onView, onCount }) {
|
|
|
85
90
|
return (_jsxs(YStack, { gap: "$5", children: [_jsx(Line, { children: note }), error && !own.value.length && !on.value.length ? (_jsx(Failed, { error: error, onRetry: () => {
|
|
86
91
|
own.reload();
|
|
87
92
|
on.reload();
|
|
88
|
-
} })) : (own.loading || on.loading) && !own.value.length && !on.value.length ? (_jsx(Soft, { children:
|
|
93
|
+
} })) : (own.loading || on.loading) && !own.value.length && !on.value.length ? (_jsx(Soft, { children: t('Loading your skills…') })) : !own.value.length && !added.length ? (_jsxs(Empty, { title: t('No skills yet'), detail: may ? t('Add one from Hanzo, or write your own.') : t('An org admin adds skills. Browse what there is.'), children: [_jsx(Button, { size: "sm", variant: "outline", onPress: () => onView('discover'), children: t('Browse skills') }), may ? (_jsx(Button, { size: "sm", onPress: () => onAdding(true), children: t('Write a skill') })) : null] })) : !ownShown.length && !addedShown.length ? (_jsx(Soft, { children: t('No skill of yours matches “{q}”.', { q: q.trim() }) })) : (_jsxs(_Fragment, { children: [ownShown.length ? (_jsx(Part, { title: t('Made by your team'), detail: t('Off keeps a skill but leaves it out of every run.'), children: _jsx(Grid, { label: t('Your skills'), children: ownShown.map((s) => (_jsx(Tile, { title: s.name, detail: s.description || firstLine(s.content), meta: [s.source ? t('From {source}', { source: s.source }) : day(s.created) ? t('Saved {date}', { date: day(s.created) }) : '', s.admitted ? '' : t('Not in runs until an admin saves it')]
|
|
94
|
+
.filter(Boolean)
|
|
95
|
+
.join(' · ') || undefined, mark: _jsx(Mark, { name: s.name }), onOpen: () => setEditing(s), action: may ? (_jsx(Switch, { checked: lit.has(tool(s.name)), disabled: busy === s.name, onCheckedChange: (v) => void flip(s.name, v), "aria-label": t('{name} on', { name: s.name }) })) : (_jsx(SizableText, { size: "$1", color: "$soft", children: lit.has(tool(s.name)) ? t('On') : t('Off') })) }, s.id))) }) })) : null, addedShown.length ? (_jsx(Part, { title: t('Added from Hanzo'), detail: t('On for every run in your organization.'), children: _jsx(Grid, { label: t('Added skills'), children: addedShown.map((x) => {
|
|
89
96
|
const name = nameOf(x.name);
|
|
90
|
-
return (_jsx(Tile, { title: name, detail: x.description, mark: _jsx(Mark, { name: name, icon: _jsx(BookOpen, { size: 15 }) }), onOpen: () => setReading({ name, description: x.description, product: '' }), action: may ? (_jsx(Button, { size: "sm", variant: "ghost", disabled: busy === name, onPress: () => void flip(name, false), "aria-label":
|
|
97
|
+
return (_jsx(Tile, { title: name, detail: x.description, mark: _jsx(Mark, { name: name, icon: _jsx(BookOpen, { size: 15 }) }), onOpen: () => setReading({ name, description: x.description, product: '' }), action: may ? (_jsx(Button, { size: "sm", variant: "ghost", disabled: busy === name, onPress: () => void flip(name, false), "aria-label": t('Remove {name}', { name }), children: t('Remove') })) : undefined }, x.name));
|
|
91
98
|
}) }) })) : null] })), reader, editor] }));
|
|
92
99
|
}
|
|
93
100
|
const firstLine = (md) => md
|
|
@@ -96,13 +103,15 @@ const firstLine = (md) => md
|
|
|
96
103
|
.find(Boolean) ?? '';
|
|
97
104
|
/** One catalogue skill: what it is, its SKILL.md, and adding or removing it. */
|
|
98
105
|
function Reader({ skill, added, signed, busy, onFlip, onClose, }) {
|
|
99
|
-
const t =
|
|
100
|
-
const
|
|
101
|
-
|
|
106
|
+
const { t } = useI18n();
|
|
107
|
+
const target = useTarget();
|
|
108
|
+
const doc = useLoad(() => document(target, skill.name), '', [target.api, skill.name]);
|
|
109
|
+
return (_jsxs(Sheet, { title: skill.name, open: true, onOpenChange: (o) => !o && onClose(), width: 720, children: [skill.description ? (_jsx(SizableText, { size: "$2", color: "$soft", children: skill.description })) : null, signed ? (_jsxs(XStack, { gap: "$2", items: "center", children: [_jsx(Button, { size: "sm", variant: added ? 'outline' : 'default', disabled: busy, onPress: () => onFlip(!added), children: added ? t('Remove') : t('Add to your skills') }), _jsx(SizableText, { size: "$1", color: "$soft", flex: 1, children: added ? t('On for your organization.') : t('Every run in your organization can use it once added.') })] })) : null, doc.error ? (_jsx(Failed, { error: doc.error, onRetry: doc.reload })) : doc.loading && !doc.value ? (_jsx(Soft, { children: t('Loading SKILL.md…') })) : (_jsx(Code, { language: "SKILL.md", value: doc.value, children: _jsx(SizableText, { size: "$1", color: "$ink", style: { ...mono, whiteSpace: 'pre-wrap' }, children: doc.value }) }))] }));
|
|
102
110
|
}
|
|
103
111
|
/** Write a skill, or revise one of the org's own. Its name is its id, so a saved skill keeps its name. */
|
|
104
112
|
function Editor({ skill, may, onClose, onSaved, onDeleted, }) {
|
|
105
|
-
const t =
|
|
113
|
+
const { t } = useI18n();
|
|
114
|
+
const target = useTarget();
|
|
106
115
|
const [name, setName] = useState(skill?.name ?? '');
|
|
107
116
|
const [description, setDescription] = useState(skill?.description ?? '');
|
|
108
117
|
const [content, setContent] = useState(skill?.content ?? '');
|
|
@@ -113,21 +122,21 @@ function Editor({ skill, may, onClose, onSaved, onDeleted, }) {
|
|
|
113
122
|
setWorking(true);
|
|
114
123
|
setNote('');
|
|
115
124
|
try {
|
|
116
|
-
const saved = await write(
|
|
125
|
+
const saved = await write(target, { name: name.trim(), description: description.trim(), content });
|
|
117
126
|
// A new skill is switched on as it is saved; a revised one keeps its switch.
|
|
118
127
|
if (!skill)
|
|
119
|
-
await toggle(
|
|
128
|
+
await toggle(target, [tool(saved.name)]);
|
|
120
129
|
onSaved(saved, !skill);
|
|
121
130
|
}
|
|
122
131
|
catch (e) {
|
|
123
|
-
setNote(say(e));
|
|
132
|
+
setNote(say(e, t));
|
|
124
133
|
}
|
|
125
134
|
finally {
|
|
126
135
|
setWorking(false);
|
|
127
136
|
}
|
|
128
137
|
};
|
|
129
|
-
return (_jsxs(Sheet, { title: skill ? skill.name : 'New skill', open: true, onOpenChange: (o) => !o && onClose(), width: 680, children: [skill?.source ? (
|
|
130
|
-
await remove(
|
|
138
|
+
return (_jsxs(Sheet, { title: skill ? skill.name : t('New skill'), open: true, onOpenChange: (o) => !o && onClose(), width: 680, children: [skill?.source ? (_jsx(SizableText, { size: "$2", color: "$soft", children: t('Read from {source}. The next push of that repository replaces what is saved here.', { source: skill.source }) })) : null, _jsx(Field, { label: t('Name'), hint: skill ? t('A skill keeps its name. Save under another name to make a new one.') : t('One lowercase word: letters, digits, _ or -.'), children: _jsx(Input, { value: name, onChangeText: setName, "aria-label": t('Name'), disabled: Boolean(skill), autoCapitalize: "none" }) }), _jsx(Field, { label: t('Description'), hint: t('One line. An agent reads it to decide whether it needs the skill.'), children: _jsx(Input, { value: description, onChangeText: setDescription, placeholder: t('How we triage an incoming issue'), "aria-label": t('Description') }) }), _jsx(Field, { label: "SKILL.md", hint: t('Markdown: what it is for, when to use it, and the steps.'), children: _jsx(Textarea, { value: content, onChangeText: setContent, placeholder: t('# Triage\n\n1. Read the issue…'), "aria-label": "SKILL.md", rows: 14, fontFamily: "$mono" }) }), _jsx(Line, { children: note || (may ? '' : t('Only an org admin can write or delete skills.')) }), _jsxs(XStack, { gap: "$2", items: "center", children: [skill && may ? (_jsx(Button, { size: "sm", variant: "ghost", onPress: () => setAsking(true), children: t('Delete') })) : null, _jsx(XStack, { flex: 1 }), _jsx(Button, { size: "sm", variant: "ghost", onPress: onClose, children: may ? t('Cancel') : t('Close') }), may ? (_jsx(Button, { size: "sm", disabled: working, onPress: () => void save(), children: t('Save') })) : null] }), skill ? (_jsx(Confirm, { what: skill.name, says: t('The skill leaves your organization and every agent that names it.'), open: asking, onOpenChange: setAsking, onYes: async () => {
|
|
139
|
+
await remove(target, skill.id);
|
|
131
140
|
onDeleted(skill.name);
|
|
132
141
|
} })) : null] }));
|
|
133
142
|
}
|
package/lib/customize/ui.d.ts
CHANGED
|
@@ -2,10 +2,6 @@ import { type ReactNode } from 'react';
|
|
|
2
2
|
export declare const mono: {
|
|
3
3
|
fontFamily: string;
|
|
4
4
|
};
|
|
5
|
-
/** A button that holds a card's text reads from the left, not from the middle a button centres it in. */
|
|
6
|
-
export declare const left: {
|
|
7
|
-
readonly textAlign: 'left';
|
|
8
|
-
};
|
|
9
5
|
/** Which half of a tab: what there is to browse and add (first), or what the org already has. */
|
|
10
6
|
export type View = 'discover' | 'yours';
|
|
11
7
|
/** What the shell hands a tab: which half, the search, the Add dialog's state, and where to say how many are yours. */
|
|
@@ -55,13 +51,13 @@ export declare function Featured({ title, detail, meta, mark, action, onOpen }:
|
|
|
55
51
|
action?: ReactNode;
|
|
56
52
|
onOpen: () => void;
|
|
57
53
|
}): import("react").JSX.Element;
|
|
58
|
-
/** A card's add control: Add while it is not yours, Added once it is. */
|
|
59
|
-
export declare function Add({ name, added, busy, onPress,
|
|
54
|
+
/** A card's add control: Add (Use, for a template one is made from) while it is not yours, Added once it is. */
|
|
55
|
+
export declare function Add({ name, added, busy, onPress, use }: {
|
|
60
56
|
name: string;
|
|
61
57
|
added: boolean;
|
|
62
58
|
busy?: boolean;
|
|
63
59
|
onPress: () => void;
|
|
64
|
-
|
|
60
|
+
use?: boolean;
|
|
65
61
|
}): import("react").JSX.Element;
|
|
66
62
|
/** A dialog with a title, a close control and a body that scrolls inside the window. */
|
|
67
63
|
export declare function Sheet({ title, open, onOpenChange, width, children }: {
|
|
@@ -71,7 +67,7 @@ export declare function Sheet({ title, open, onOpenChange, width, children }: {
|
|
|
71
67
|
width?: number;
|
|
72
68
|
children: ReactNode;
|
|
73
69
|
}): import("react").JSX.Element;
|
|
74
|
-
/** Asks before a delete; says what goes with it. */
|
|
70
|
+
/** Asks before a delete; says what goes with it. `what` is the thing's name, `says` comes already said. */
|
|
75
71
|
export declare function Confirm({ what, says, open, onOpenChange, onYes }: {
|
|
76
72
|
what: string;
|
|
77
73
|
says: string;
|
|
@@ -116,7 +112,7 @@ export declare function Field({ label, hint, children }: {
|
|
|
116
112
|
hint?: string;
|
|
117
113
|
children: ReactNode;
|
|
118
114
|
}): import("react").JSX.Element;
|
|
119
|
-
/** Two or three choices side by side; the chosen one is filled. A count, when one is given, follows its label. */
|
|
115
|
+
/** Two or three choices side by side; the chosen one is filled. A count, when one is given, follows its label. Labels come already said. */
|
|
120
116
|
export declare function Choice<T extends string>({ value, options, onChange, label, }: {
|
|
121
117
|
value: T;
|
|
122
118
|
options: readonly {
|