@hanzo/build 0.2.18 → 0.2.19
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 +1 -1
- package/lib/builder.d.ts +10 -0
- package/lib/builder.js +23 -13
- package/lib/index.d.ts +8 -4
- package/lib/index.js +8 -4
- package/lib/landing.js +12 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -193,7 +193,7 @@ picker and open-in-tab; Share and Publish; the console dock under it.
|
|
|
193
193
|
|
|
194
194
|
| call | what |
|
|
195
195
|
|---|---|
|
|
196
|
-
| `POST /v1/agent/coding` | start a run → 202 `{sessionId, …}` |
|
|
196
|
+
| `POST /v1/agent/coding` | start a run → 202 `{sessionId, …}`; with no `repo` the platform starts a new project named from the ask |
|
|
197
197
|
| `GET /v1/agent/sessions?kind=coding` | Recents, and a project's runs |
|
|
198
198
|
| `GET /v1/agent/sessions/{id}` · `GET /v1/agent/sessions/stream?root=` | a run, and its live feed (SSE over fetch) |
|
|
199
199
|
| `POST /v1/agent/sessions/{id}/message` · `/pause` · `/resume` · `/stop` | steer, pause, resume a machine's run, stop |
|
package/lib/builder.d.ts
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
|
+
import { type RailLink } from '@hanzo/ui/chat';
|
|
1
2
|
import { type Host } from './host.tsx';
|
|
3
|
+
/**
|
|
4
|
+
* The builder's places, as a rail draws them: four in view and the rest under
|
|
5
|
+
* More. Every one moves the builder through `go`, so a host that draws its own
|
|
6
|
+
* rail lists the same places, in the same words, as the builder's rail does.
|
|
7
|
+
*/
|
|
8
|
+
export declare function nav(host: Host, go: (path: string) => void): {
|
|
9
|
+
links: RailLink[];
|
|
10
|
+
more: RailLink[];
|
|
11
|
+
};
|
|
2
12
|
/**
|
|
3
13
|
* The builder. Mount it under a gui root (`<Hanzo>`), in a box with a height.
|
|
4
14
|
*
|
package/lib/builder.js
CHANGED
|
@@ -24,8 +24,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
24
24
|
* bar and panes — and its mark leads back here.
|
|
25
25
|
*
|
|
26
26
|
* A host with a rail of its own mounts `<Builder rail={false}>` and draws the
|
|
27
|
-
* builder's places and runs in that rail
|
|
28
|
-
* left column, never two.
|
|
27
|
+
* builder's places (`nav`) and runs in that rail (`useSessions`, or `DevSection`,
|
|
28
|
+
* section.tsx): one left column, never two.
|
|
29
29
|
*/
|
|
30
30
|
import { SizableText, XStack, YStack } from '@hanzo/gui';
|
|
31
31
|
import { Blocks, BookOpen, CircleDot, Cpu, FolderGit2, Kanban, LayoutTemplate, Menu, Search, SlidersHorizontal, Workflow } from '@hanzogui/lucide-icons-2';
|
|
@@ -72,12 +72,31 @@ function Shell() {
|
|
|
72
72
|
list.sort((a, b) => Number(b.status === 'running') - Number(a.status === 'running'));
|
|
73
73
|
return list;
|
|
74
74
|
}, [recents.value, order]);
|
|
75
|
-
const screen = r.kind === 'screen' ? r.screen : '';
|
|
76
75
|
// The top left, as on claude.ai: the builder's name, which leads to New, and under
|
|
77
76
|
// it the search that finds a run. The organization is the account's, so it is
|
|
78
77
|
// switched from the account menu at the foot. Beside the rail from md up, beside
|
|
79
78
|
// the drawer's button below it — one place at a time.
|
|
80
79
|
const name = _jsx(Name, { onPress: () => go('') });
|
|
80
|
+
const { links, more } = nav(host, go);
|
|
81
|
+
return (_jsxs(XStack, { flex: 1, minH: 0, minW: 0, bg: "$background", children: [_jsxs(YStack, { position: "relative", shrink: 0, children: [_jsx(SessionRail, { onNew: () => go(''), fresh: r.kind === 'new', links: links, more: more, recents: rows, active: r.kind === 'run' ? r.id : null, onOpen: (id) => go(id), onSort: () => setOrder(order === 'newest' ? 'running' : 'newest'), sortLabel: order === 'newest' ? 'Show running first' : 'Show newest first', empty: _jsx(SizableText, { size: "$1", color: "$soft", px: "$2", children: !host.person ? 'Sign in to see your runs.' : recents.error ? recents.error.message : recents.loading ? 'Reading…' : 'No runs yet.' }), notice: host.person && !slack ? (_jsx(Slack, { onOpen: () => go(path({ kind: 'settings', section: 'integrations' })), onDismiss: () => setSlack(true) })) : undefined, account: host.person
|
|
82
|
+
? {
|
|
83
|
+
// Who, and in which organization, as claude.ai says who and on which plan.
|
|
84
|
+
name: [host.person.name || host.person.email, host.org].filter(Boolean).join(' · '),
|
|
85
|
+
onPress: () => {
|
|
86
|
+
setDrawer(false);
|
|
87
|
+
setMenu(true);
|
|
88
|
+
},
|
|
89
|
+
}
|
|
90
|
+
: { name: 'Sign in', onPress: () => host.signIn?.() }, collapsed: collapsed, onCollapse: setCollapsed, mark: _jsx(Brand, { org: host.org }), pt: collapsed ? undefined : 92, open: drawer, onOpenChange: setDrawer, label: "Runs" }), collapsed ? null : (_jsxs(YStack, { position: "absolute", t: 10, l: 8, r: 8, z: 2, gap: "$2.5", "$max-md": { display: 'none' }, children: [_jsx(XStack, { px: "$2.5", children: name }), _jsxs(XStack, { render: "button", "aria-label": "Search runs", onPress: () => setFinding(true), items: "center", gap: "$2", px: "$2.5", height: 34, rounded: "$3", borderWidth: 1, borderColor: "$borderColor", bg: "$panel", hoverStyle: { bg: '$hover' }, children: [_jsx(Search, { size: 15, color: "$soft" }), _jsx(SizableText, { size: "$2", color: "$soft", children: "Search" })] })] })), host.person ? _jsx(Who, { open: menu, onOpenChange: setMenu, narrow: collapsed }) : null] }), _jsxs(YStack, { flex: 1, minW: 0, minH: 0, position: "relative", children: [_jsxs(XStack, { height: 44, px: "$2", gap: "$2", items: "center", shrink: 0, $md: { display: 'none' }, children: [_jsx(Button, { variant: "ghost", size: "icon-sm", onPress: () => setDrawer(true), "aria-label": "Open runs", children: _jsx(Menu, { size: 18 }) }), name, _jsx(XStack, { flex: 1 }), _jsx(Button, { variant: "ghost", size: "icon-sm", onPress: () => setFinding(true), "aria-label": "Search runs", children: _jsx(Search, { size: 18 }) })] }), _jsx(Pane, { onStarted: () => recents.reload() })] }), _jsx(Find, { open: finding, onOpenChange: setFinding, recents: rows, onOpen: (id) => { setFinding(false); go(id); } })] }));
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* The builder's places, as a rail draws them: four in view and the rest under
|
|
94
|
+
* More. Every one moves the builder through `go`, so a host that draws its own
|
|
95
|
+
* rail lists the same places, in the same words, as the builder's rail does.
|
|
96
|
+
*/
|
|
97
|
+
export function nav(host, go) {
|
|
98
|
+
const r = route(host.path);
|
|
99
|
+
const screen = r.kind === 'screen' ? r.screen : '';
|
|
81
100
|
const links = [
|
|
82
101
|
{ id: 'projects', label: 'Projects', icon: _jsx(Kanban, { size: 16 }), onPress: () => go(path({ kind: 'screen', screen: 'projects' })), active: screen === 'projects' },
|
|
83
102
|
{ id: 'artifacts', label: 'Artifacts', icon: _jsx(Blocks, { size: 16 }), onPress: () => go(path({ kind: 'screen', screen: 'artifacts' })), active: screen === 'artifacts' },
|
|
@@ -106,16 +125,7 @@ function Shell() {
|
|
|
106
125
|
},
|
|
107
126
|
{ id: 'docs', label: 'Docs', icon: _jsx(BookOpen, { size: 16 }), onPress: () => window.open(DOCS, '_blank', 'noopener,noreferrer') },
|
|
108
127
|
];
|
|
109
|
-
return
|
|
110
|
-
? {
|
|
111
|
-
// Who, and in which organization, as claude.ai says who and on which plan.
|
|
112
|
-
name: [host.person.name || host.person.email, host.org].filter(Boolean).join(' · '),
|
|
113
|
-
onPress: () => {
|
|
114
|
-
setDrawer(false);
|
|
115
|
-
setMenu(true);
|
|
116
|
-
},
|
|
117
|
-
}
|
|
118
|
-
: { name: 'Sign in', onPress: () => host.signIn?.() }, collapsed: collapsed, onCollapse: setCollapsed, mark: _jsx(Brand, { org: host.org }), pt: collapsed ? undefined : 92, open: drawer, onOpenChange: setDrawer, label: "Runs" }), collapsed ? null : (_jsxs(YStack, { position: "absolute", t: 10, l: 8, r: 8, z: 2, gap: "$2.5", "$max-md": { display: 'none' }, children: [_jsx(XStack, { px: "$2.5", children: name }), _jsxs(XStack, { render: "button", "aria-label": "Search runs", onPress: () => setFinding(true), items: "center", gap: "$2", px: "$2.5", height: 34, rounded: "$3", borderWidth: 1, borderColor: "$borderColor", bg: "$panel", hoverStyle: { bg: '$hover' }, children: [_jsx(Search, { size: 15, color: "$soft" }), _jsx(SizableText, { size: "$2", color: "$soft", children: "Search" })] })] })), host.person ? _jsx(Who, { open: menu, onOpenChange: setMenu, narrow: collapsed }) : null] }), _jsxs(YStack, { flex: 1, minW: 0, minH: 0, position: "relative", children: [_jsxs(XStack, { height: 44, px: "$2", gap: "$2", items: "center", shrink: 0, $md: { display: 'none' }, children: [_jsx(Button, { variant: "ghost", size: "icon-sm", onPress: () => setDrawer(true), "aria-label": "Open runs", children: _jsx(Menu, { size: 18 }) }), name, _jsx(XStack, { flex: 1 }), _jsx(Button, { variant: "ghost", size: "icon-sm", onPress: () => setFinding(true), "aria-label": "Search runs", children: _jsx(Search, { size: 18 }) })] }), _jsx(Pane, { onStarted: () => recents.reload() })] }), _jsx(Find, { open: finding, onOpenChange: setFinding, recents: rows, onOpen: (id) => { setFinding(false); go(id); } })] }));
|
|
128
|
+
return { links, more };
|
|
119
129
|
}
|
|
120
130
|
/** The wordmark: the product's name, as its host calls it, which leads to New. */
|
|
121
131
|
function Name({ onPress }) {
|
package/lib/index.d.ts
CHANGED
|
@@ -3,12 +3,16 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Mount `<Builder host={…} />` under a gui root in a box with a height. The
|
|
5
5
|
* host says where the platform is, who is signed in, and how to move; the
|
|
6
|
-
* builder does everything else. hanzo.build hosts it whole
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* builder does everything else. hanzo.build hosts it whole. A host with a rail
|
|
7
|
+
* of its own mounts it with `rail={false}` and draws the builder's parts in that
|
|
8
|
+
* rail: its places (`nav`), its runs (`useSessions`, or `DevSection` for both),
|
|
9
|
+
* and at the foot the Slack card and the account menu (`Slack`, `Who`), under
|
|
10
|
+
* `HostProvider`.
|
|
9
11
|
*/
|
|
10
|
-
export { Builder } from './builder.tsx';
|
|
12
|
+
export { Builder, nav } from './builder.tsx';
|
|
11
13
|
export { DevSection, DOTS, useSessions } from './section.tsx';
|
|
14
|
+
export { HostProvider } from './host.tsx';
|
|
15
|
+
export { Slack, Who } from './foot.tsx';
|
|
12
16
|
export { administers } from './claims.ts';
|
|
13
17
|
export type { Host, Person } from './host.tsx';
|
|
14
18
|
export type { Session, Status } from './api/sessions.ts';
|
package/lib/index.js
CHANGED
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Mount `<Builder host={…} />` under a gui root in a box with a height. The
|
|
5
5
|
* host says where the platform is, who is signed in, and how to move; the
|
|
6
|
-
* builder does everything else. hanzo.build hosts it whole
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* builder does everything else. hanzo.build hosts it whole. A host with a rail
|
|
7
|
+
* of its own mounts it with `rail={false}` and draws the builder's parts in that
|
|
8
|
+
* rail: its places (`nav`), its runs (`useSessions`, or `DevSection` for both),
|
|
9
|
+
* and at the foot the Slack card and the account menu (`Slack`, `Who`), under
|
|
10
|
+
* `HostProvider`.
|
|
9
11
|
*/
|
|
10
|
-
export { Builder } from './builder.js';
|
|
12
|
+
export { Builder, nav } from './builder.js';
|
|
11
13
|
export { DevSection, DOTS, useSessions } from './section.js';
|
|
14
|
+
export { HostProvider } from './host.js';
|
|
15
|
+
export { Slack, Who } from './foot.js';
|
|
12
16
|
export { administers } from './claims.js';
|
|
13
17
|
export { path, route, SESSION, SLUG } from './route.js';
|
package/lib/landing.js
CHANGED
|
@@ -6,8 +6,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
6
6
|
* which repository and branch it starts from, and the ask itself.
|
|
7
7
|
* Under it: attach, dictate, the mode, and the model and effort on the right.
|
|
8
8
|
*
|
|
9
|
-
* Sending starts a coding run and opens it. The
|
|
10
|
-
*
|
|
9
|
+
* Sending starts a coding run and opens it. The codebase is optional: in the
|
|
10
|
+
* sandbox a run with none starts a new project named from the ask, as the
|
|
11
|
+
* platform does for a run that names no repository; a machine works in its own
|
|
12
|
+
* checkout, so a run there names one. The choices a person made here are kept in
|
|
13
|
+
* this browser, per org, so the next New starts where the last one did.
|
|
11
14
|
*/
|
|
12
15
|
import { SizableText, XStack, YStack } from '@hanzo/gui';
|
|
13
16
|
import { Cloud, Monitor } from '@hanzogui/lucide-icons-2';
|
|
@@ -105,8 +108,9 @@ export function Landing({ onStarted }) {
|
|
|
105
108
|
host.signIn?.();
|
|
106
109
|
return;
|
|
107
110
|
}
|
|
108
|
-
|
|
109
|
-
|
|
111
|
+
const repo = isForge(kept.repo) ? kept.repo : null;
|
|
112
|
+
if (!repo && place.id) {
|
|
113
|
+
setNote(`A run on ${place.label} works in its own checkout: choose the codebase, or run it in Cloud.`);
|
|
110
114
|
return;
|
|
111
115
|
}
|
|
112
116
|
setBusy(true);
|
|
@@ -115,9 +119,10 @@ export function Landing({ onStarted }) {
|
|
|
115
119
|
const run = await start(t, {
|
|
116
120
|
prompt: compose(draft.trim(), files),
|
|
117
121
|
// The name alone. The org rides the request, and a slash is not a repo name.
|
|
122
|
+
// No codebase is not sent, and the run starts a new project.
|
|
118
123
|
// An empty base or place is not sent: the default branch, and the sandbox.
|
|
119
|
-
repo:
|
|
120
|
-
base: kept.branch,
|
|
124
|
+
repo: repo?.name,
|
|
125
|
+
base: repo ? kept.branch : undefined,
|
|
121
126
|
targetId: place.id,
|
|
122
127
|
mode: kept.mode,
|
|
123
128
|
model: kept.model === ENSO ? undefined : kept.model,
|
|
@@ -172,7 +177,7 @@ export function Landing({ onStarted }) {
|
|
|
172
177
|
name: r.name,
|
|
173
178
|
});
|
|
174
179
|
},
|
|
175
|
-
}, placeholder: "
|
|
180
|
+
}, placeholder: "New project", disabled: !signed }, round), isForge(kept.repo) ? _jsx(BranchSelect, { value: branch, onChange: (b) => set({ branch: b }), load: loadBranches }) : null, _jsx(Files, { files: files, onFiles: setFiles })] }));
|
|
176
181
|
const foot = (_jsxs(XStack, { flex: 1, items: "center", gap: "$2", flexWrap: "wrap", rowGap: "$1", children: [_jsx(Attach, { files: files, onFiles: setFiles, onNote: setNote }), _jsx(Dictate, { onText: (said) => setDraft((d) => (d ? `${d} ${said}` : said)), onNote: setNote }), _jsx(ModeSelect, { modes: MODES, value: kept.mode, onChange: (m) => set({ mode: m }), bg: "transparent", minH: 24, px: "$1.5", self: "center" }), _jsx(XStack, { flex: 1 }), _jsx(ChipSelect, { quiet: true, name: "Model", label: catalog.value.find((m) => m.id === kept.model)?.label ?? 'Enso', chosen: catalog.value.find((m) => m.id === kept.model) ?? null, items: catalog.value, onChange: (m) => set({ model: m.id }), placeholder: "Search models\u2026", placement: "top-end", loading: catalog.loading, error: catalog.error?.message ?? null }), _jsx(ChipSelect, { quiet: true, name: "Effort", label: EFFORTS.find((e) => e.id === kept.effort)?.label ?? 'Medium', chosen: EFFORTS.find((e) => e.id === kept.effort) ?? null, items: EFFORTS, onChange: (e) => set({ effort: e.id }), placement: "top-end", width: 180 })] }));
|
|
177
182
|
return (_jsxs(YStack, { flex: 1, minH: 0, minW: 0, items: "center", justify: "center", px: "$4", pb: "$10", overflow: "scroll", children: [_jsxs(YStack, { width: "100%", maxW: COLUMN, gap: "$5", children: [_jsxs(XStack, { role: "heading", "aria-level": 1, justify: "center", items: "center", gap: "$3", flexWrap: "wrap", children: [_jsx(HanzoMark, { size: 26 }), _jsx(SizableText, { size: "$8", color: "$ink", style: { textAlign: 'center' }, children: prefs.callName ? `What’s up next, ${prefs.callName}?` : 'What’s up next?' })] }), _jsxs(YStack, { gap: "$2", children: [env.value && env.value.state !== 'ready' && !place.id ? (_jsxs(XStack, { items: "center", justify: "space-between", gap: "$3", px: "$3", py: "$2", rounded: "$10", borderWidth: 1, borderColor: "$borderColor", children: [_jsx(SizableText, { size: "$2", color: "$ink", flex: 1, minW: 0, children: env.value.state === 'proposed'
|
|
178
183
|
? `A proposed environment for ${codebase} is waiting for review.`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzo/build",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.19",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0 OR MIT",
|
|
6
6
|
"description": "Hanzo Build — say what you want, watch it built, deployed and running. The builder as a page (hanzo.build) and as a component (hanzo.ai/dev).",
|