@hanzo/rooms 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-APACHE +205 -0
- package/LICENSE-MIT +21 -0
- package/README.md +23 -0
- package/dist/Account.d.ts +8 -0
- package/dist/Account.js +58 -0
- package/dist/Beluga.d.ts +12 -0
- package/dist/Beluga.js +152 -0
- package/dist/Billing.d.ts +1 -0
- package/dist/Billing.js +31 -0
- package/dist/Board.d.ts +9 -0
- package/dist/Board.js +447 -0
- package/dist/Boxes.d.ts +1 -0
- package/dist/Boxes.js +173 -0
- package/dist/CalScheduler.d.ts +15 -0
- package/dist/CalScheduler.js +196 -0
- package/dist/Chat.d.ts +35 -0
- package/dist/Chat.js +1049 -0
- package/dist/Column.d.ts +15 -0
- package/dist/Column.js +88 -0
- package/dist/Contacts.d.ts +1 -0
- package/dist/Contacts.js +301 -0
- package/dist/Directory.d.ts +24 -0
- package/dist/Directory.js +356 -0
- package/dist/Drive.d.ts +2 -0
- package/dist/Drive.js +466 -0
- package/dist/Find.d.ts +7 -0
- package/dist/Find.js +82 -0
- package/dist/Guide.d.ts +6 -0
- package/dist/Guide.js +272 -0
- package/dist/Home.d.ts +39 -0
- package/dist/Home.js +306 -0
- package/dist/Inbox.d.ts +9 -0
- package/dist/Inbox.js +193 -0
- package/dist/Market.d.ts +3 -0
- package/dist/Market.js +149 -0
- package/dist/Me.d.ts +27 -0
- package/dist/Me.js +251 -0
- package/dist/Meet.d.ts +9 -0
- package/dist/Meet.js +370 -0
- package/dist/ModeMark.d.ts +8 -0
- package/dist/ModeMark.js +18 -0
- package/dist/OrgSwitcher.d.ts +31 -0
- package/dist/OrgSwitcher.js +120 -0
- package/dist/Orgs.d.ts +10 -0
- package/dist/Orgs.js +582 -0
- package/dist/Profile.d.ts +4 -0
- package/dist/Profile.js +67 -0
- package/dist/Prose.d.ts +5 -0
- package/dist/Prose.js +111 -0
- package/dist/ProviderMark.d.ts +17 -0
- package/dist/ProviderMark.js +277 -0
- package/dist/Recents.d.ts +10 -0
- package/dist/Recents.js +91 -0
- package/dist/RightPane.d.ts +13 -0
- package/dist/RightPane.js +426 -0
- package/dist/Room.d.ts +8 -0
- package/dist/Room.js +50 -0
- package/dist/Scene.d.ts +12 -0
- package/dist/Scene.js +105 -0
- package/dist/Settings.d.ts +46 -0
- package/dist/Settings.js +321 -0
- package/dist/Setup.d.ts +1 -0
- package/dist/Setup.js +36 -0
- package/dist/Share.d.ts +3 -0
- package/dist/Share.js +130 -0
- package/dist/Shared.d.ts +1 -0
- package/dist/Shared.js +113 -0
- package/dist/Shell.d.ts +63 -0
- package/dist/Shell.js +1225 -0
- package/dist/Start.d.ts +1 -0
- package/dist/Start.js +96 -0
- package/dist/Support.d.ts +14 -0
- package/dist/Support.js +122 -0
- package/dist/Talk.d.ts +4 -0
- package/dist/Talk.js +107 -0
- package/dist/Upgrade.d.ts +11 -0
- package/dist/Upgrade.js +75 -0
- package/dist/Usage.d.ts +1 -0
- package/dist/Usage.js +21 -0
- package/dist/Vibe.d.ts +2 -0
- package/dist/Vibe.js +188 -0
- package/dist/Work.d.ts +12 -0
- package/dist/Work.js +256 -0
- package/dist/bots/Bots.d.ts +2 -0
- package/dist/bots/Bots.js +456 -0
- package/dist/bots/Lights.d.ts +8 -0
- package/dist/bots/Lights.js +13 -0
- package/dist/bots/api.d.ts +120 -0
- package/dist/bots/api.js +75 -0
- package/dist/bots/face.d.ts +5 -0
- package/dist/bots/face.js +13 -0
- package/dist/bots/ink.d.ts +7 -0
- package/dist/bots/ink.js +29 -0
- package/dist/bots/kit.d.ts +113 -0
- package/dist/bots/kit.js +43 -0
- package/dist/bots/runtime.d.ts +4 -0
- package/dist/bots/runtime.js +326 -0
- package/dist/card.d.ts +52 -0
- package/dist/card.js +52 -0
- package/dist/cast.d.ts +143 -0
- package/dist/cast.js +251 -0
- package/dist/connect.d.ts +29 -0
- package/dist/connect.js +64 -0
- package/dist/contacts-store.d.ts +111 -0
- package/dist/contacts-store.js +276 -0
- package/dist/conversations.d.ts +54 -0
- package/dist/conversations.js +98 -0
- package/dist/copy.d.ts +23 -0
- package/dist/copy.js +39 -0
- package/dist/crew.d.ts +36 -0
- package/dist/crew.js +304 -0
- package/dist/dev.d.ts +3 -0
- package/dist/dev.js +102 -0
- package/dist/enso.d.ts +70 -0
- package/dist/enso.js +112 -0
- package/dist/failure.d.ts +57 -0
- package/dist/failure.js +143 -0
- package/dist/ground.d.ts +32 -0
- package/dist/ground.js +32 -0
- package/dist/host.d.ts +76 -0
- package/dist/host.js +76 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +12 -0
- package/dist/kept.d.ts +5 -0
- package/dist/kept.js +27 -0
- package/dist/lib/account.d.ts +49 -0
- package/dist/lib/account.js +229 -0
- package/dist/lib/ai.d.ts +46 -0
- package/dist/lib/ai.js +140 -0
- package/dist/lib/api.d.ts +43 -0
- package/dist/lib/api.js +62 -0
- package/dist/lib/bare.d.ts +9 -0
- package/dist/lib/bare.js +7 -0
- package/dist/lib/coding.d.ts +105 -0
- package/dist/lib/coding.js +87 -0
- package/dist/lib/destination.d.ts +102 -0
- package/dist/lib/destination.js +260 -0
- package/dist/lib/durable.d.ts +66 -0
- package/dist/lib/durable.js +107 -0
- package/dist/lib/first.d.ts +11 -0
- package/dist/lib/first.js +23 -0
- package/dist/lib/home.d.ts +61 -0
- package/dist/lib/home.js +54 -0
- package/dist/lib/host.d.ts +104 -0
- package/dist/lib/host.js +132 -0
- package/dist/lib/hostname.d.ts +1 -0
- package/dist/lib/hostname.js +14 -0
- package/dist/lib/hydrated.d.ts +1 -0
- package/dist/lib/hydrated.js +20 -0
- package/dist/lib/integrations.d.ts +21 -0
- package/dist/lib/integrations.js +1 -0
- package/dist/lib/intent.d.ts +6 -0
- package/dist/lib/intent.js +71 -0
- package/dist/lib/invite.d.ts +155 -0
- package/dist/lib/invite.js +245 -0
- package/dist/lib/limits.d.ts +55 -0
- package/dist/lib/limits.js +119 -0
- package/dist/lib/list.d.ts +9 -0
- package/dist/lib/list.js +11 -0
- package/dist/lib/mark.d.ts +13 -0
- package/dist/lib/mark.js +85 -0
- package/dist/lib/mix.d.ts +22 -0
- package/dist/lib/mix.js +22 -0
- package/dist/lib/models.d.ts +27 -0
- package/dist/lib/models.js +106 -0
- package/dist/lib/org.d.ts +109 -0
- package/dist/lib/org.js +140 -0
- package/dist/lib/path.d.ts +9 -0
- package/dist/lib/path.js +29 -0
- package/dist/lib/plans.d.ts +193 -0
- package/dist/lib/plans.js +310 -0
- package/dist/lib/prose.d.ts +13 -0
- package/dist/lib/prose.js +62 -0
- package/dist/lib/reach.d.ts +17 -0
- package/dist/lib/reach.js +70 -0
- package/dist/lib/rooms.json +23 -0
- package/dist/lib/served.d.ts +20 -0
- package/dist/lib/served.js +92 -0
- package/dist/lib/session.d.ts +211 -0
- package/dist/lib/session.js +493 -0
- package/dist/lib/share.d.ts +131 -0
- package/dist/lib/share.js +216 -0
- package/dist/lib/signout.d.ts +14 -0
- package/dist/lib/signout.js +40 -0
- package/dist/lib/tags.d.ts +27 -0
- package/dist/lib/tags.js +46 -0
- package/dist/lib/tap.d.ts +17 -0
- package/dist/lib/tap.js +9 -0
- package/dist/lib/tier.d.ts +115 -0
- package/dist/lib/tier.js +207 -0
- package/dist/lib/tiers.d.ts +9 -0
- package/dist/lib/tiers.js +141 -0
- package/dist/lib/todo.d.ts +125 -0
- package/dist/lib/todo.js +379 -0
- package/dist/look.d.ts +1 -0
- package/dist/look.js +21 -0
- package/dist/meters.d.ts +8 -0
- package/dist/meters.js +31 -0
- package/dist/model.d.ts +4 -0
- package/dist/model.js +44 -0
- package/dist/network.d.ts +64 -0
- package/dist/network.js +216 -0
- package/dist/open.d.ts +81 -0
- package/dist/open.js +149 -0
- package/dist/pane.d.ts +92 -0
- package/dist/pane.js +231 -0
- package/dist/progress.d.ts +46 -0
- package/dist/progress.js +51 -0
- package/dist/recent.d.ts +67 -0
- package/dist/recent.js +161 -0
- package/dist/rooms.d.ts +131 -0
- package/dist/rooms.js +195 -0
- package/dist/roster.d.ts +28 -0
- package/dist/roster.js +70 -0
- package/dist/span.d.ts +14 -0
- package/dist/span.js +50 -0
- package/dist/speech.d.ts +44 -0
- package/dist/speech.js +229 -0
- package/dist/stars.d.ts +16 -0
- package/dist/stars.js +75 -0
- package/dist/tabs.d.ts +26 -0
- package/dist/tabs.js +25 -0
- package/dist/team.d.ts +11 -0
- package/dist/team.gen.d.ts +10 -0
- package/dist/team.gen.js +11 -0
- package/dist/team.js +30 -0
- package/dist/tools.d.ts +35 -0
- package/dist/tools.js +143 -0
- package/dist/tours.d.ts +24 -0
- package/dist/tours.js +311 -0
- package/dist/waiting.d.ts +15 -0
- package/dist/waiting.js +17 -0
- package/dist/where.d.ts +54 -0
- package/dist/where.js +14 -0
- package/package.json +108 -0
package/dist/Boxes.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
// The compute an org is HOLDING: every sandbox lease, what it costs by the
|
|
4
|
+
// hour, and the two things you can do to one.
|
|
5
|
+
//
|
|
6
|
+
// A LEASE IS MONEY RUNNING. It is billed per hour of being held, at the price of
|
|
7
|
+
// the envelope it holds — so the rate is on the row rather than in a pricing page
|
|
8
|
+
// nobody has open, and the total is stated before anything is taken. A surface
|
|
9
|
+
// that hides the meter is how a $0.96 hour becomes a surprise.
|
|
10
|
+
//
|
|
11
|
+
// RESUMING IS LEASING WITH AN ID. There is no separate verb: `lease({ id })`
|
|
12
|
+
// answers the same sandbox if it is still there and a NEW one if the lease
|
|
13
|
+
// expired while you were reading, which is the honest answer to resuming
|
|
14
|
+
// something that is gone. So the button says Resume and the id it returns is
|
|
15
|
+
// what a later call must use.
|
|
16
|
+
//
|
|
17
|
+
// ENDING IS NOT STOPPING. `stop` interrupts what is running and KEEPS the lease
|
|
18
|
+
// — the meter keeps going. `end` releases it, which is what stops the charge.
|
|
19
|
+
// Both are drawn, because a runaway command and an unwanted box are different
|
|
20
|
+
// problems and one control for both would do the wrong one half the time.
|
|
21
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
22
|
+
import { say } from './failure.js';
|
|
23
|
+
import { Play, Plus, Square, X } from 'lucide-react';
|
|
24
|
+
import { ChannelHeader } from '@hanzo/ui/agents';
|
|
25
|
+
import { Box, Text, XStack, YStack } from '@hanzo/ui';
|
|
26
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@hanzo/ui';
|
|
27
|
+
import { useIam } from '@hanzo/iam/react';
|
|
28
|
+
import { hasSession } from './lib/session.js';
|
|
29
|
+
import { useAi } from './lib/ai.js';
|
|
30
|
+
/**
|
|
31
|
+
* The LIST price of an hour of each class, in micro-USD.
|
|
32
|
+
*
|
|
33
|
+
* The platform is the authority — it prices `agents/runtime-hour-<class>` and an
|
|
34
|
+
* operator retunes it there — and the surface cannot read it: the rate rows live
|
|
35
|
+
* behind `GET /v1/commerce/rates/entries`, which is SuperAdmin only and answers
|
|
36
|
+
* 403 to the reader holding this lease. Nothing else in the contract publishes a
|
|
37
|
+
* rate; a sandbox row carries none either.
|
|
38
|
+
*
|
|
39
|
+
* So the table stays — a control that spends money without naming the price is
|
|
40
|
+
* the defect this file exists to avoid — and both places that draw it say LIST,
|
|
41
|
+
* because a number nobody asked the platform for must not read as a live quote.
|
|
42
|
+
* If the two ever disagree, the invoice is right and this is stale.
|
|
43
|
+
*/
|
|
44
|
+
const HOURLY = {
|
|
45
|
+
exec: 80_000,
|
|
46
|
+
dev: 80_000,
|
|
47
|
+
desktop: 80_000,
|
|
48
|
+
// Twelve times the memory of the default envelope, and a node packs sixteen
|
|
49
|
+
// of those — so an android lease displaces twelve and is charged for twelve.
|
|
50
|
+
android: 960_000,
|
|
51
|
+
};
|
|
52
|
+
/** Micro-USD as money. Two places, because that is how an hourly rate reads. */
|
|
53
|
+
const usd = (micros) => `$${(micros / 1_000_000).toFixed(2)}`;
|
|
54
|
+
/** Unix seconds to how long is left, or the fact that it is over. */
|
|
55
|
+
const remaining = (expiresAt) => {
|
|
56
|
+
if (!expiresAt)
|
|
57
|
+
return '';
|
|
58
|
+
const left = expiresAt - Math.floor(Date.now() / 1000);
|
|
59
|
+
if (left <= 0)
|
|
60
|
+
return 'expired';
|
|
61
|
+
if (left < 3600)
|
|
62
|
+
return `${Math.ceil(left / 60)}m left`;
|
|
63
|
+
return `${Math.floor(left / 3600)}h ${Math.ceil((left % 3600) / 60)}m left`;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Take a new lease.
|
|
67
|
+
*
|
|
68
|
+
* THE PROJECT IS THE DISK, and that is the whole reason this control asks for
|
|
69
|
+
* one. A volume is named per (org, project) and the name is deterministic, so
|
|
70
|
+
* leasing the same project again finds the SAME disk without a lookup — which is
|
|
71
|
+
* how a conversation continues across a lease that ended. `exec` keeps nothing
|
|
72
|
+
* and takes no project; every other class requires one, so the field appears
|
|
73
|
+
* exactly where it decides something.
|
|
74
|
+
*
|
|
75
|
+
* The rate is stated on the button because taking this lease starts a meter.
|
|
76
|
+
*/
|
|
77
|
+
function Start({ onDone }) {
|
|
78
|
+
const { client } = useAi();
|
|
79
|
+
const [klass, setKlass] = useState('exec');
|
|
80
|
+
const [project, setProject] = useState('');
|
|
81
|
+
const [busy, setBusy] = useState(false);
|
|
82
|
+
const [failed, setFailed] = useState(null);
|
|
83
|
+
const keeps = klass !== 'exec';
|
|
84
|
+
const take = useCallback(async () => {
|
|
85
|
+
if (!client || busy)
|
|
86
|
+
return;
|
|
87
|
+
if (keeps && !project.trim()) {
|
|
88
|
+
setFailed(`A ${klass} sandbox keeps a disk, so it needs a project to name it.`);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
setBusy(true);
|
|
92
|
+
setFailed(null);
|
|
93
|
+
try {
|
|
94
|
+
await client.sandboxes.lease({
|
|
95
|
+
class: klass,
|
|
96
|
+
...(keeps ? { project: project.trim() } : {}),
|
|
97
|
+
});
|
|
98
|
+
onDone();
|
|
99
|
+
}
|
|
100
|
+
catch (e) {
|
|
101
|
+
setFailed(e.message);
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
setBusy(false);
|
|
105
|
+
}
|
|
106
|
+
}, [client, busy, keeps, klass, project, onDone]);
|
|
107
|
+
return (_jsxs(YStack, { gap: "$2", p: "$4", borderBottomWidth: 1, borderColor: "$borderColor", children: [_jsxs(XStack, { gap: "$2", items: "center", flexWrap: "wrap", children: [_jsxs(Select, { value: klass, onValueChange: (v) => setKlass(v), children: [_jsx(SelectTrigger, { "aria-label": "Sandbox class", width: 200, children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: Object.keys(HOURLY).map((c) => (_jsxs(SelectItem, { value: c, children: [c, " \u2014 ", usd(HOURLY[c]), "/hr list"] }, c))) })] }), keeps ? (_jsx(XStack, { flex: 1, minW: 160, height: 34, items: "center", px: "$3", rounded: "$3", borderWidth: 1, borderColor: "$borderColor", children: _jsx(Text, { render: _jsx("input", { value: project, onChange: (e) => setProject(e.target.value), onKeyDown: (e) => e.key === 'Enter' && void take(), placeholder: "Project \u2014 the disk it keeps" }), flex: 1, bg: "transparent", borderWidth: 0, outlineStyle: "none", color: "inherit" }) })) : (_jsx(Text, { fontSize: "$1", color: "$soft", flex: 1, children: "Keeps nothing \u2014 an exec sandbox has no disk." })), _jsx(Box, { render: "button", onClick: () => void take(), px: "$3", py: "$2", rounded: "$3", borderWidth: 1, borderColor: "$borderColor", hoverStyle: { bg: '$hover' }, children: _jsxs(XStack, { items: "center", gap: "$1", children: [_jsx(Plus, { size: 13, "aria-hidden": true }), _jsx(Text, { fontSize: "$2", color: "$ink", children: busy ? 'Leasing' : 'Lease' })] }) })] }), failed ? (_jsx(Text, { fontSize: "$1", color: "$soft", numberOfLines: 2, children: failed })) : null] }));
|
|
108
|
+
}
|
|
109
|
+
function Empty({ children }) {
|
|
110
|
+
return (_jsx(YStack, { flex: 1, items: "center", justify: "center", p: "$6", children: _jsx(Text, { fontSize: "$3", color: "$soft", text: "center", children: children }) }));
|
|
111
|
+
}
|
|
112
|
+
function Act({ icon: Icon, label, onPress, busy, }) {
|
|
113
|
+
return (_jsx(Box, { render: "button", onClick: onPress, "aria-label": label, px: "$2", py: "$1", rounded: "$2", hoverStyle: { bg: '$hover' }, children: _jsxs(XStack, { items: "center", gap: "$1", children: [_jsx(Icon, { size: 13, "aria-hidden": true }), _jsx(Text, { fontSize: "$1", color: "$soft", children: busy ? '…' : label })] }) }));
|
|
114
|
+
}
|
|
115
|
+
function Row({ box, onResume, onStop, onEnd, busy, }) {
|
|
116
|
+
const rate = HOURLY[(box.class ?? 'exec')] ?? HOURLY.exec;
|
|
117
|
+
return (_jsxs(YStack, { gap: "$2", p: "$3", borderWidth: 1, borderColor: "$borderColor", rounded: "$3", children: [_jsxs(XStack, { items: "center", gap: "$2", children: [_jsxs(Text, { fontSize: "$3", color: "$ink", flex: 1, numberOfLines: 1, children: [box.class ?? 'exec', box.project ? ` · ${box.project}` : ''] }), _jsxs(Text, { fontSize: "$1", color: "$soft", children: [usd(rate), "/hr list"] })] }), _jsxs(XStack, { gap: "$2", items: "baseline", flexWrap: "wrap", children: [_jsxs(Text, { fontSize: "$1", color: "$soft", children: [box.status ?? 'unknown', box.runtime ? ` · ${box.runtime}` : ''] }), _jsx(Text, { fontSize: "$1", color: "$soft", children: remaining(box.expiresAt) })] }), box.status === 'error' && box.error ? (_jsx(Text, { fontSize: "$1", color: "$soft", numberOfLines: 2, children: box.error })) : null, _jsxs(XStack, { gap: "$1", children: [_jsx(Act, { icon: Play, label: "Resume", onPress: onResume, busy: busy === 'resume' }), _jsx(Act, { icon: Square, label: "Stop", onPress: onStop, busy: busy === 'stop' }), _jsx(Act, { icon: X, label: "End", onPress: onEnd, busy: busy === 'end' })] })] }));
|
|
118
|
+
}
|
|
119
|
+
export function Boxes() {
|
|
120
|
+
const { client } = useAi();
|
|
121
|
+
// SIGNED IN IS THE CREDENTIAL, NOT THE PROFILE. This gated on `user`, which is
|
|
122
|
+
// the answer to a userinfo REQUEST — and `IamProvider` swallows that request's
|
|
123
|
+
// failure, so a blip or a slow reply left `isAuthenticated` true and `user`
|
|
124
|
+
// null, and this pane told somebody holding a perfectly good token to sign in.
|
|
125
|
+
// The token is what the API accepts; the profile is decoration on top of it.
|
|
126
|
+
const { isAuthenticated, isLoading } = useIam();
|
|
127
|
+
const [boxes, setBoxes] = useState(null);
|
|
128
|
+
const [busy, setBusy] = useState({});
|
|
129
|
+
const [failed, setFailed] = useState(null);
|
|
130
|
+
const ready = Boolean(client && isAuthenticated);
|
|
131
|
+
const reload = useCallback(() => {
|
|
132
|
+
if (!ready || !client)
|
|
133
|
+
return;
|
|
134
|
+
client.sandboxes
|
|
135
|
+
.list()
|
|
136
|
+
.then(setBoxes)
|
|
137
|
+
.catch((e) => setFailed(e.message));
|
|
138
|
+
}, [client, ready]);
|
|
139
|
+
useEffect(reload, [reload]);
|
|
140
|
+
const act = useCallback(async (id, what) => {
|
|
141
|
+
if (!client)
|
|
142
|
+
return;
|
|
143
|
+
setBusy((b) => ({ ...b, [id]: what }));
|
|
144
|
+
try {
|
|
145
|
+
if (what === 'resume')
|
|
146
|
+
await client.sandboxes.lease({ id });
|
|
147
|
+
if (what === 'stop')
|
|
148
|
+
await client.sandboxes.stop({ id });
|
|
149
|
+
if (what === 'end')
|
|
150
|
+
await client.sandboxes.end({ id });
|
|
151
|
+
reload();
|
|
152
|
+
}
|
|
153
|
+
catch (e) {
|
|
154
|
+
setFailed(e.message);
|
|
155
|
+
}
|
|
156
|
+
finally {
|
|
157
|
+
setBusy((b) => {
|
|
158
|
+
const { [id]: _gone, ...rest } = b;
|
|
159
|
+
return rest;
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}, [client, reload]);
|
|
163
|
+
const signedIn = isAuthenticated || hasSession();
|
|
164
|
+
if (isLoading)
|
|
165
|
+
return _jsx(Empty, { children: "\u00A0" });
|
|
166
|
+
if (!signedIn)
|
|
167
|
+
return _jsx(Empty, { children: "Sign in to see the compute your org is holding." });
|
|
168
|
+
if (failed)
|
|
169
|
+
return _jsx(Empty, { children: say(failed, 'this list') });
|
|
170
|
+
if (!boxes)
|
|
171
|
+
return _jsx(Empty, { children: "Reading your leases." });
|
|
172
|
+
return (_jsxs(YStack, { flex: 1, minH: 0, children: [_jsx(ChannelHeader, { name: "Sandboxes", children: _jsxs(Text, { fontSize: "$2", color: "$soft", children: ["from ", usd(HOURLY.exec), "/hr"] }) }), _jsx(Start, { onDone: reload }), boxes.length === 0 ? (_jsx(Empty, { children: "Nothing is running. A sandbox is leased when an agent needs somewhere to work, and billed for the hours it is held." })) : (_jsx(YStack, { flex: 1, minH: 0, overflow: "scroll", p: "$4", gap: "$3", children: boxes.map((box) => (_jsx(Row, { box: box, busy: busy[box.id], onResume: () => void act(box.id, 'resume'), onStop: () => void act(box.id, 'stop'), onEnd: () => void act(box.id, 'end') }, box.id))) }))] }));
|
|
173
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface CalendarEvent {
|
|
3
|
+
id: string;
|
|
4
|
+
title: string;
|
|
5
|
+
type: 'meeting' | 'bot_automation' | 'agent_query';
|
|
6
|
+
date: string;
|
|
7
|
+
time: string;
|
|
8
|
+
duration: string;
|
|
9
|
+
botName?: string;
|
|
10
|
+
meetUrl?: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
cronPattern?: string;
|
|
13
|
+
status: 'scheduled' | 'running' | 'completed';
|
|
14
|
+
}
|
|
15
|
+
export declare function CalScheduler(): React.JSX.Element;
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useEffect } from 'react';
|
|
4
|
+
import { Calendar as CalendarIcon, Plus, Bot, Video, ExternalLink, Zap, Trash2, X, } from 'lucide-react';
|
|
5
|
+
import { Text, View, XStack, YStack } from '@hanzo/gui';
|
|
6
|
+
import { Button } from '@hanzo/ui';
|
|
7
|
+
const DEFAULT_EVENTS = [
|
|
8
|
+
{
|
|
9
|
+
id: 'evt-1',
|
|
10
|
+
title: 'Daily Morning AI Intelligence Digest',
|
|
11
|
+
type: 'bot_automation',
|
|
12
|
+
date: '2026-09-04',
|
|
13
|
+
time: '09:00',
|
|
14
|
+
duration: '15m',
|
|
15
|
+
botName: 'Chief',
|
|
16
|
+
cronPattern: '0 9 * * 1-5',
|
|
17
|
+
description: 'Scrape breaking frontier AI papers, benchmark shifts, and repo PRs into team Slack.',
|
|
18
|
+
status: 'scheduled',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: 'evt-2',
|
|
22
|
+
title: 'Platform Architecture & Inference Sync',
|
|
23
|
+
type: 'meeting',
|
|
24
|
+
date: '2026-09-04',
|
|
25
|
+
time: '18:00',
|
|
26
|
+
duration: '45m',
|
|
27
|
+
meetUrl: 'https://meet.hanzo.ai/platform-architecture',
|
|
28
|
+
botName: 'Hanzo Coder (Bot Co-pilot)',
|
|
29
|
+
description: 'Sync on port 9005 drive server performance and ingress routing.',
|
|
30
|
+
status: 'scheduled',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: 'evt-3',
|
|
34
|
+
title: 'Autonomous Outbound Prospecting Run',
|
|
35
|
+
type: 'bot_automation',
|
|
36
|
+
date: '2026-09-04',
|
|
37
|
+
time: '11:00',
|
|
38
|
+
duration: '60m',
|
|
39
|
+
botName: 'Sales Outbound',
|
|
40
|
+
cronPattern: '0 11 * * 1-5',
|
|
41
|
+
description: 'Extract 50 lookalike enterprise leads and prepare personalized drafts.',
|
|
42
|
+
status: 'scheduled',
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: 'evt-4',
|
|
46
|
+
title: 'Hourly GitHub PR & Typecheck Review',
|
|
47
|
+
type: 'agent_query',
|
|
48
|
+
date: '2026-09-04',
|
|
49
|
+
time: '14:00',
|
|
50
|
+
duration: '20m',
|
|
51
|
+
botName: 'Hanzo Coder',
|
|
52
|
+
cronPattern: '0 * * * *',
|
|
53
|
+
description: 'Verify type safety and lint across all open PRs in hanzoai organization.',
|
|
54
|
+
status: 'scheduled',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: 'evt-5',
|
|
58
|
+
title: 'Research Review',
|
|
59
|
+
type: 'meeting',
|
|
60
|
+
date: '2026-09-04',
|
|
61
|
+
time: '20:00',
|
|
62
|
+
duration: '60m',
|
|
63
|
+
meetUrl: 'https://meet.hanzo.ai/research-review',
|
|
64
|
+
botName: 'Hanzo Researcher',
|
|
65
|
+
description: 'Review datasets and proofs for the week’s research runs.',
|
|
66
|
+
status: 'scheduled',
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
/** The public booking pages, one card each on the Booker tab. */
|
|
70
|
+
const BOOKINGS = [
|
|
71
|
+
{
|
|
72
|
+
title: 'Quick Sync',
|
|
73
|
+
duration: '15m',
|
|
74
|
+
slug: '15min',
|
|
75
|
+
description: 'Fast 15-minute alignment or triage call on Hanzo Meet.',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
title: 'Technical Deep Dive',
|
|
79
|
+
duration: '30m',
|
|
80
|
+
slug: '30min',
|
|
81
|
+
description: 'In-depth architectural review, bug diagnosis, or sprint planning.',
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
title: 'AI Pair Programming',
|
|
85
|
+
duration: '45m',
|
|
86
|
+
slug: 'pair-ai',
|
|
87
|
+
description: 'Interactive coding session with Hanzo Coder assisting in the terminal.',
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
title: 'Executive & Strategy Sync',
|
|
91
|
+
duration: '60m',
|
|
92
|
+
slug: '60min',
|
|
93
|
+
description: 'Quarterly roadmap sync, partnerships, and leadership decision forum.',
|
|
94
|
+
},
|
|
95
|
+
];
|
|
96
|
+
/** design's smallest rung (`--text-floor`, 10px), below gui's `$1`; gui's font size takes a rung or a number. */
|
|
97
|
+
const FLOOR = 10;
|
|
98
|
+
const MODAL = 'var(--z-modal)';
|
|
99
|
+
/** One field of the dialog: the box every input, select and textarea in it draws. */
|
|
100
|
+
const FIELD = {
|
|
101
|
+
width: '100%',
|
|
102
|
+
py: 8,
|
|
103
|
+
bg: '$background',
|
|
104
|
+
borderWidth: 1,
|
|
105
|
+
borderColor: 'var(--border-control)',
|
|
106
|
+
rounded: 6,
|
|
107
|
+
color: '$ink',
|
|
108
|
+
fontSize: '$2',
|
|
109
|
+
};
|
|
110
|
+
/** A dialog label. */
|
|
111
|
+
const LABEL = { render: 'label', fontSize: '$1', color: '$soft', mb: 4, display: 'block' };
|
|
112
|
+
export function CalScheduler() {
|
|
113
|
+
const [events, setEvents] = useState(() => {
|
|
114
|
+
if (typeof window !== 'undefined') {
|
|
115
|
+
try {
|
|
116
|
+
const stored = localStorage.getItem('hanzo_calendar_events_v1');
|
|
117
|
+
if (stored)
|
|
118
|
+
return JSON.parse(stored);
|
|
119
|
+
}
|
|
120
|
+
catch { }
|
|
121
|
+
}
|
|
122
|
+
return DEFAULT_EVENTS;
|
|
123
|
+
});
|
|
124
|
+
const [activeTab, setActiveTab] = useState('scheduler');
|
|
125
|
+
const [filterType, setFilterType] = useState('all');
|
|
126
|
+
const [showModal, setShowModal] = useState(false);
|
|
127
|
+
const [newEvent, setNewEvent] = useState({
|
|
128
|
+
title: '',
|
|
129
|
+
type: 'bot_automation',
|
|
130
|
+
date: '2026-09-04',
|
|
131
|
+
time: '10:00',
|
|
132
|
+
duration: '30m',
|
|
133
|
+
botName: 'Chief',
|
|
134
|
+
description: '',
|
|
135
|
+
});
|
|
136
|
+
useEffect(() => {
|
|
137
|
+
try {
|
|
138
|
+
localStorage.setItem('hanzo_calendar_events_v1', JSON.stringify(events));
|
|
139
|
+
}
|
|
140
|
+
catch { }
|
|
141
|
+
}, [events]);
|
|
142
|
+
const filteredEvents = events.filter((e) => {
|
|
143
|
+
if (filterType === 'all')
|
|
144
|
+
return true;
|
|
145
|
+
return e.type === filterType;
|
|
146
|
+
});
|
|
147
|
+
const handleCreateEvent = (e) => {
|
|
148
|
+
e.preventDefault();
|
|
149
|
+
if (!newEvent.title.trim())
|
|
150
|
+
return;
|
|
151
|
+
const created = {
|
|
152
|
+
id: `evt-${Date.now()}`,
|
|
153
|
+
title: newEvent.title.trim(),
|
|
154
|
+
type: newEvent.type,
|
|
155
|
+
date: newEvent.date,
|
|
156
|
+
time: newEvent.time,
|
|
157
|
+
duration: newEvent.duration,
|
|
158
|
+
botName: newEvent.botName,
|
|
159
|
+
description: newEvent.description,
|
|
160
|
+
meetUrl: newEvent.type === 'meeting'
|
|
161
|
+
? `https://meet.hanzo.ai/${newEvent.title.toLowerCase().replace(/[^a-z0-9]/g, '-')}`
|
|
162
|
+
: undefined,
|
|
163
|
+
status: 'scheduled',
|
|
164
|
+
};
|
|
165
|
+
setEvents((prev) => [created, ...prev]);
|
|
166
|
+
setShowModal(false);
|
|
167
|
+
setNewEvent({
|
|
168
|
+
title: '',
|
|
169
|
+
type: 'bot_automation',
|
|
170
|
+
date: '2026-09-04',
|
|
171
|
+
time: '10:00',
|
|
172
|
+
duration: '30m',
|
|
173
|
+
botName: 'Chief',
|
|
174
|
+
description: '',
|
|
175
|
+
});
|
|
176
|
+
};
|
|
177
|
+
const handleDeleteEvent = (id) => {
|
|
178
|
+
setEvents((prev) => prev.filter((e) => e.id !== id));
|
|
179
|
+
};
|
|
180
|
+
return (_jsxs(YStack, { width: "100%", height: "100%", bg: "$background", overflowX: "auto", overflowY: "auto", children: [_jsxs(XStack, { minH: 56, px: 24, py: 8, gap: 10, flexWrap: "wrap", bg: "$panel", borderBottomWidth: 1, borderBottomColor: "$borderColor", items: "center", justify: "space-between", children: [_jsxs(XStack, { items: "center", gap: 12, shrink: 1, minW: "auto", children: [_jsx(XStack, { width: 32, height: 32, rounded: 8, bg: "$raised", items: "center", justify: "center", shrink: 1, minW: "auto", children: _jsx(CalendarIcon, { size: 18, color: "var(--foreground)" }) }), _jsxs(YStack, { shrink: 1, minW: "auto", children: [_jsxs(XStack, { items: "center", gap: 8, children: [_jsx(Text, { fontSize: "$4", fontWeight: "700", color: "$ink", children: "Hanzo Calendar & Scheduler" }), _jsx(Text, { fontSize: FLOOR, fontWeight: "700", bg: "$hover", color: "$soft", borderWidth: 1, borderColor: "$borderColor", px: 6, py: 1, rounded: 4, children: "cal.hanzo.ai" })] }), _jsx(Text, { fontSize: "$1", color: "$soft", children: "Full unified scheduler across meetings, bot routines, automated crons, and query triggers" })] })] }), _jsxs(XStack, { items: "center", gap: 10, shrink: 1, minW: "auto", flexWrap: "wrap", children: [_jsx(XStack, { items: "center", gap: 2, bg: "$hover", rounded: 8, p: 2, borderWidth: 1, borderColor: "$borderColor", shrink: 1, minW: "auto", children: [
|
|
181
|
+
{ id: 'scheduler', label: 'Master Schedule' },
|
|
182
|
+
{ id: 'automations', label: 'Bot Crons' },
|
|
183
|
+
{ id: 'booker', label: 'Public Booker' },
|
|
184
|
+
].map((tab) => (_jsx(Button, { size: "sm", variant: activeTab === tab.id ? 'primary' : 'ghost', ...(activeTab === tab.id ? null : { color: '$soft' }), "aria-pressed": activeTab === tab.id, onClick: () => setActiveTab(tab.id), children: tab.label }, tab.id))) }), _jsxs(Button, { variant: "primary", size: "sm", onClick: () => setShowModal(true), children: [_jsx(Plus, { size: 14 }), "Schedule Event / Routine"] })] })] }), activeTab === 'booker' ? (_jsxs(YStack, { flex: 1, p: 28, overflowY: "auto", gap: 20, children: [_jsxs(YStack, { gap: 4, children: [_jsx(Text, { fontSize: "$7", fontWeight: "800", color: "$ink", children: "Public Booking Pages" }), _jsxs(Text, { fontSize: "$2", color: "$soft", children: ["Shareable links powered by the Cal.com fork at ", _jsx(Text, { render: _jsx("a", { href: "https://cal.hanzo.ai", target: "_blank", rel: "noopener noreferrer" }), color: "$ink", textDecorationLine: "underline", children: "cal.hanzo.ai" }), ". Allows teammates, clients, and automated agents to book dedicated time slots."] })] }), _jsx(View, { display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(300px, 1fr))", gap: 16, children: BOOKINGS.map((card) => (_jsxs(YStack, { bg: "$panel", borderWidth: 1, borderColor: "$borderColor", rounded: 10, p: 18, gap: 12, children: [_jsxs(XStack, { items: "center", justify: "space-between", children: [_jsx(Text, { fontSize: "$4", fontWeight: "700", color: "$ink", children: card.title }), _jsx(Text, { fontSize: "$1", fontWeight: "700", bg: "$hover", px: 8, py: 2, rounded: 4, color: "$soft", children: card.duration })] }), _jsx(Text, { fontSize: "$2", color: "$soft", lineHeight: "$2", children: card.description }), _jsxs(Text, { px: 10, py: 8, bg: "$sunken", rounded: 6, fontSize: "$1", fontFamily: "$mono", color: "$soft", children: ["https://cal.hanzo.ai/alex/", card.slug] }), _jsxs(XStack, { gap: 8, mt: 4, children: [_jsx(Button, { size: "sm", flex: 1, onClick: () => {
|
|
185
|
+
navigator.clipboard.writeText(`https://cal.hanzo.ai/alex/${card.slug}`);
|
|
186
|
+
}, children: "Copy Link" }), _jsx(Button, { asChild: true, variant: "primary", size: "sm", children: _jsxs("a", { href: `https://cal.hanzo.ai/alex/${card.slug}`, target: "_blank", rel: "noopener noreferrer", children: ["Open", _jsx(ExternalLink, { size: 12 })] }) })] })] }, card.slug))) })] })) : (_jsxs(YStack, { flex: 1, overflow: "hidden", children: [_jsxs(XStack, { px: 24, py: 12, bg: "$panel", borderBottomWidth: 1, borderBottomColor: "$borderColor", items: "center", justify: "space-between", flexWrap: "wrap", gap: 8, children: [_jsxs(XStack, { items: "center", gap: 8, shrink: 1, minW: "auto", flexWrap: "wrap", children: [_jsx(Text, { fontSize: "$2", fontWeight: "600", color: "$soft", children: "Filter:" }), [
|
|
187
|
+
{ id: 'all', label: 'All Items' },
|
|
188
|
+
{ id: 'meeting', label: 'Human Meetings', icon: Video },
|
|
189
|
+
{ id: 'bot_automation', label: 'Bot Routines', icon: Bot },
|
|
190
|
+
{ id: 'agent_query', label: 'Agent Queries', icon: Zap },
|
|
191
|
+
].map((f) => (_jsxs(Button, { size: "sm", variant: filterType === f.id ? 'secondary' : 'ghost', color: filterType === f.id ? '$ink' : '$soft', "aria-pressed": filterType === f.id, onClick: () => setFilterType(f.id), children: ['icon' in f ? _jsx(f.icon, { size: 13, "aria-hidden": true }) : null, f.label] }, f.id)))] }), _jsxs(Text, { fontSize: "$1", color: "$faint", children: ["Showing ", filteredEvents.length, " scheduled events & routines"] })] }), _jsx(YStack, { flex: 1, overflowY: "auto", px: 24, py: 20, gap: 10, children: filteredEvents.map((evt) => {
|
|
192
|
+
const isMeeting = evt.type === 'meeting';
|
|
193
|
+
const isAutomation = evt.type === 'bot_automation';
|
|
194
|
+
return (_jsxs(XStack, { bg: "$panel", borderWidth: 1, borderColor: "$borderColor", rounded: 10, px: 20, py: 16, items: "center", justify: "space-between", flexWrap: "wrap", gap: 16, children: [_jsxs(XStack, { items: "center", gap: 16, minW: 180, shrink: 1, children: [_jsx(XStack, { width: 40, height: 40, rounded: 8, bg: "$raised", items: "center", justify: "center", children: isMeeting ? _jsx(Video, { size: 20, color: "var(--foreground)" }) : isAutomation ? _jsx(Bot, { size: 20, color: "var(--foreground)" }) : _jsx(Zap, { size: 20, color: "var(--foreground)" }) }), _jsxs(YStack, { shrink: 1, minW: "auto", children: [_jsx(Text, { fontSize: "$3", fontWeight: "700", color: "$ink", children: evt.time }), _jsxs(Text, { fontSize: "$1", color: "$faint", children: [evt.date, " \u00B7 ", evt.duration] })] })] }), _jsxs(View, { flex: 1, minW: 240, display: "block", children: [_jsxs(XStack, { items: "center", gap: 8, mb: 2, children: [_jsx(Text, { fontSize: "$3", fontWeight: "600", color: "$ink", children: evt.title }), _jsx(Text, { fontSize: FLOOR, fontWeight: "700", bg: "$hover", color: "$soft", px: 6, py: 1, rounded: 4, textTransform: "uppercase", children: evt.type.replace('_', ' ') })] }), _jsx(Text, { display: "block", fontSize: "$2", color: "$soft", mb: 4, children: evt.description }), _jsxs(XStack, { items: "center", gap: 12, children: [evt.botName ? _jsxs(Text, { fontSize: "$1", color: "$faint", children: ["Bot: ", _jsx(Text, { render: "strong", fontSize: "$1", color: "$quiet", children: evt.botName })] }) : null, evt.cronPattern ? _jsxs(Text, { fontSize: "$1", color: "$faint", children: ["Cron: ", _jsx(Text, { render: "code", color: "$ink", children: evt.cronPattern })] }) : null, evt.meetUrl ? _jsxs(Text, { fontSize: "$1", color: "$faint", children: ["Link: ", _jsx(Text, { render: "code", color: "$ink", children: evt.meetUrl })] }) : null] })] }), _jsxs(XStack, { items: "center", gap: 8, shrink: 1, minW: "auto", children: [isMeeting ? (_jsx(Button, { asChild: true, variant: "primary", size: "sm", children: _jsxs("a", { href: "/meet", children: [_jsx(Video, { size: 13 }), "Join /meet"] }) })) : (_jsx(Button, { asChild: true, variant: "primary", size: "sm", children: _jsxs("a", { href: "/bots", children: [_jsx(Bot, { size: 13 }), "View /bots"] }) })), _jsx(Button, { variant: "ghost", size: "icon-sm", color: "$soft", onClick: () => handleDeleteEvent(evt.id), "aria-label": "Remove schedule", title: "Remove schedule", children: _jsx(Trash2, { size: 14 }) })] })] }, evt.id));
|
|
195
|
+
}) })] })), showModal ? (_jsx(XStack, { position: "fixed", inset: 0, bg: "var(--surface-scrim)", backdropFilter: "blur(8px)", items: "center", justify: "center", z: MODAL, children: _jsxs(YStack, { width: "100%", maxW: 460, bg: "var(--popover)", borderWidth: 1, borderColor: "var(--border-control)", rounded: 12, p: 24, gap: 16, boxShadow: "var(--shadow-floating)", children: [_jsxs(XStack, { items: "center", justify: "space-between", children: [_jsx(Text, { fontSize: "$4", fontWeight: "700", color: "$ink", children: "Schedule Event or Bot Routine" }), _jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", mr: -8, onClick: () => setShowModal(false), "aria-label": "Close", children: _jsx(X, { size: 16, "aria-hidden": true }) })] }), _jsxs(YStack, { render: "form", onSubmit: handleCreateEvent, gap: 12, children: [_jsxs(View, { display: "block", children: [_jsx(Text, { ...LABEL, children: "Title" }), _jsx(Text, { render: _jsx("input", { type: "text", value: newEvent.title, onChange: (e) => setNewEvent({ ...newEvent, title: e.target.value }), placeholder: "e.g. Daily Security Audit / Team Sync", required: true }), ...FIELD, px: 12 })] }), _jsxs(View, { display: "block", children: [_jsx(Text, { ...LABEL, children: "Schedule Type" }), _jsxs(Text, { render: _jsx("select", { value: newEvent.type, onChange: (e) => setNewEvent({ ...newEvent, type: e.target.value }) }), ...FIELD, px: 12, children: [_jsx("option", { value: "bot_automation", children: "Automated Bot Cron Routine" }), _jsx("option", { value: "meeting", children: "Human Video Meeting (/meet)" }), _jsx("option", { value: "agent_query", children: "Recurring Agent Query" })] })] }), _jsxs(View, { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10, children: [_jsxs(View, { display: "block", children: [_jsx(Text, { ...LABEL, children: "Date" }), _jsx(Text, { render: _jsx("input", { type: "date", value: newEvent.date, onChange: (e) => setNewEvent({ ...newEvent, date: e.target.value }) }), ...FIELD, px: 8 })] }), _jsxs(View, { display: "block", children: [_jsx(Text, { ...LABEL, children: "Time" }), _jsx(Text, { render: _jsx("input", { type: "time", value: newEvent.time, onChange: (e) => setNewEvent({ ...newEvent, time: e.target.value }) }), ...FIELD, px: 8 })] })] }), _jsxs(View, { display: "block", children: [_jsx(Text, { ...LABEL, children: "Assigned Bot" }), _jsxs(Text, { render: _jsx("select", { value: newEvent.botName, onChange: (e) => setNewEvent({ ...newEvent, botName: e.target.value }) }), ...FIELD, px: 12, children: [_jsx("option", { value: "Chief", children: "Chief" }), _jsx("option", { value: "Sales Outbound", children: "Sales Outbound" }), _jsx("option", { value: "Inbox Manager", children: "Inbox Manager" }), _jsx("option", { value: "Account Manager", children: "Account Manager" }), _jsx("option", { value: "Talent Scout", children: "Talent Scout" }), _jsx("option", { value: "Expense Manager", children: "Expense Manager" }), _jsx("option", { value: "Offsite crew", children: "Offsite crew" })] })] }), _jsxs(View, { display: "block", children: [_jsx(Text, { ...LABEL, children: "Description / Instruction" }), _jsx(Text, { render: _jsx("textarea", { value: newEvent.description, onChange: (e) => setNewEvent({ ...newEvent, description: e.target.value }), placeholder: "Details or cron automation prompt...", rows: 3 }), ...FIELD, px: 12, "$platform-web": { resize: 'none' } })] }), _jsxs(XStack, { justify: "flex-end", gap: 8, mt: 8, children: [_jsx(Button, { type: "button", onClick: () => setShowModal(false), children: "Cancel" }), _jsx(Button, { type: "submit", variant: "primary", children: "Save Schedule" })] })] })] }) })) : null] }));
|
|
196
|
+
}
|
package/dist/Chat.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export declare function Chat(): import("react").JSX.Element;
|
|
2
|
+
/**
|
|
3
|
+
* The same conversation, embedded in a page that is not /chat.
|
|
4
|
+
*
|
|
5
|
+
* R8: there were TWO live chat surfaces with different consent semantics — this
|
|
6
|
+
* one asks at SEND and fails closed, the other gated on ARRIVAL through a
|
|
7
|
+
* separate copy of the consent code. Two answers to one question is how they
|
|
8
|
+
* drift, so /models mounts this and the second surface is gone. It carries no
|
|
9
|
+
* heading of its own: the host page already has one, and a second `<h1>` is the
|
|
10
|
+
* defect that took the landings off /chat and /dev.
|
|
11
|
+
*
|
|
12
|
+
* The host supplies the `AiProvider`, because the host is what knows whether it
|
|
13
|
+
* already has one.
|
|
14
|
+
*/
|
|
15
|
+
export declare function Ask({ placeholder, idle, }: {
|
|
16
|
+
placeholder?: string;
|
|
17
|
+
idle?: React.ReactNode;
|
|
18
|
+
}): import("react").JSX.Element;
|
|
19
|
+
/**
|
|
20
|
+
* The agents a question speaks to: those it names, or the whole room when it
|
|
21
|
+
* names nobody — the rule the room's brief gives the model (cast.tsx `brief`).
|
|
22
|
+
*/
|
|
23
|
+
export declare function addressed(question: string, room: string[]): string[];
|
|
24
|
+
/**
|
|
25
|
+
* Which kind of refusal a failed turn met, read off the platform's own codes:
|
|
26
|
+
* the caller's wallet (`insufficient_balance`, the ai service's spend check), a visitor's
|
|
27
|
+
* spent free messages (`public_allowance_spent`), or a model provider that did
|
|
28
|
+
* not answer (`providers_exhausted`, or any 5xx that is not the balance lookup).
|
|
29
|
+
*/
|
|
30
|
+
export declare function refusalOf(error: Error): {
|
|
31
|
+
wallet: boolean;
|
|
32
|
+
visitor: boolean;
|
|
33
|
+
provider: boolean;
|
|
34
|
+
};
|
|
35
|
+
/** The agreement free asks for, in @hanzo/ai's words so every surface says one thing. */
|