@hanzo/build 0.2.81 → 0.2.83
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 +11 -7
- package/lib/api/links.d.ts +1 -1
- package/lib/api/links.js +1 -1
- package/lib/api/projects.js +9 -9
- package/lib/host.d.ts +2 -0
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/landing.js +4 -4
- package/lib/merge.d.ts +2 -2
- package/lib/mind.d.ts +5 -5
- package/lib/mind.js +24 -23
- package/lib/plugins/index.d.ts +1 -1
- package/lib/plugins/project.js +1 -1
- package/lib/project.js +3 -3
- package/lib/prompt.d.ts +8 -5
- package/lib/prompt.js +11 -12
- package/lib/run.js +3 -3
- package/lib/settings/code.js +1 -1
- package/lib/shelf.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -118,9 +118,12 @@ French and right to left in Arabic.
|
|
|
118
118
|
One of each, shared with Chat (@hanzo/rooms imports them):
|
|
119
119
|
|
|
120
120
|
- `useMind` — the model and effort: `GET /v1/models` read once per platform,
|
|
121
|
-
and the choice kept in this browser (`hanzo.mind`, Enso and
|
|
122
|
-
changed). `Tune` is the
|
|
123
|
-
|
|
121
|
+
and the choice kept in this browser (`hanzo.mind`, Enso and Auto until
|
|
122
|
+
changed). `Tune` is the row that changes it: the effort (Auto, High, XHigh,
|
|
123
|
+
Max) always, the model chip only where the host shows it (`Host.models`, a
|
|
124
|
+
composer's `model`) — on hanzo.ai, Settings' model selector. Settings → Code
|
|
125
|
+
writes the same choice. `@hanzo/build/mind` serves the store alone, without
|
|
126
|
+
the builder.
|
|
124
127
|
- `prompt` / `Prompt` — the composer, as wide as the text above it (`measure`).
|
|
125
128
|
- `Reply` — copy, Listen and Open under an answer.
|
|
126
129
|
- `Panel` over `useDeck` — the side panel and its kept tabs.
|
|
@@ -255,8 +258,8 @@ machines follow under remote control, each linked with `hanzo link`), the
|
|
|
255
258
|
codebase and the branch — the forge's repositories, filtered as you type, read
|
|
256
259
|
again with Refresh list, and a way to Sync for a GitHub repository that is not
|
|
257
260
|
there yet — then the ask, in the composer Chat draws too (`prompt`): the paperclip
|
|
258
|
-
and Build or Plan at its start; the model
|
|
259
|
-
send at its end. A codebase can be added to a project. Opening a codebase or an
|
|
261
|
+
and Build or Plan at its start; the effort, the model where the host shows it
|
|
262
|
+
(`Tune`), dictation and send at its end. A codebase can be added to a project. Opening a codebase or an
|
|
260
263
|
issue from its own screen lands here with that choice already made.
|
|
261
264
|
|
|
262
265
|
**A run.** The transcript as it streams, drawn by what each part is: what the
|
|
@@ -351,7 +354,8 @@ picker and open-in-tab; Share and Publish; the console dock under it.
|
|
|
351
354
|
`mode`, `model` and `effort` are sent with a run as asked — Enso as
|
|
352
355
|
`enso-auto`, never left out — and `issue`, the number a run started from an
|
|
353
356
|
issue closes; the platform honours them where it does and nothing here
|
|
354
|
-
simulates them.
|
|
357
|
+
simulates them. A run takes `low`, `medium` or `high`, so Auto names `medium`
|
|
358
|
+
and High, XHigh and Max name `high` (`level`).
|
|
355
359
|
|
|
356
360
|
## Layout
|
|
357
361
|
|
|
@@ -369,7 +373,7 @@ src/
|
|
|
369
373
|
prose.tsx markdown, drawn as text (markdown.ts reads it)
|
|
370
374
|
desk.tsx the pane beside a run
|
|
371
375
|
mind.ts the model and effort, one choice with Chat
|
|
372
|
-
prompt.tsx the composer, and Tune, the
|
|
376
|
+
prompt.tsx the composer, and Tune, the effort and model row
|
|
373
377
|
reply.tsx the row under an answer
|
|
374
378
|
panel.tsx the side panel; tabs.ts its kept tabs
|
|
375
379
|
side.tsx the column it stands in: width, the middle column, full screen
|
package/lib/api/links.d.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* `conflict`, `pending` (not on the forge yet) or `paused` — and is absent when
|
|
13
13
|
* the forge could not be read, which is not reported as healthy.
|
|
14
14
|
*
|
|
15
|
-
* Every link the sync app holds is also a row of GET /v1/
|
|
15
|
+
* Every link the sync app holds is also a row of GET /v1/project (apps/sync
|
|
16
16
|
* project.go), so this list is the org's linked projects and not a copy of them.
|
|
17
17
|
*/
|
|
18
18
|
import { type Target } from './call.ts';
|
package/lib/api/links.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* `conflict`, `pending` (not on the forge yet) or `paused` — and is absent when
|
|
13
13
|
* the forge could not be read, which is not reported as healthy.
|
|
14
14
|
*
|
|
15
|
-
* Every link the sync app holds is also a row of GET /v1/
|
|
15
|
+
* Every link the sync app holds is also a row of GET /v1/project (apps/sync
|
|
16
16
|
* project.go), so this list is the org's linked projects and not a copy of them.
|
|
17
17
|
*/
|
|
18
18
|
import { call } from './call.js';
|
package/lib/api/projects.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The org's projects: what it has built, and where each one is served.
|
|
3
3
|
*
|
|
4
|
-
* GET /v1/
|
|
5
|
-
* PATCH /v1/
|
|
6
|
-
* DELETE /v1/
|
|
7
|
-
* GET /v1/
|
|
4
|
+
* GET /v1/project → Project[]
|
|
5
|
+
* PATCH /v1/project/{slug} rename it, or make it public or private
|
|
6
|
+
* DELETE /v1/project/{slug} delete it and take its site down
|
|
7
|
+
* GET /v1/project/{slug}/deployments → Deployment[], newest first
|
|
8
8
|
*
|
|
9
9
|
* `slug` is the one key every surface shares — the address under /dev, the
|
|
10
10
|
* site's name, the `project` a run is tagged with. A project belongs to the org,
|
|
@@ -52,7 +52,7 @@ export function project(raw) {
|
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
54
|
export async function projects(t) {
|
|
55
|
-
const raw = await call(t, 'GET', '/v1/
|
|
55
|
+
const raw = await call(t, 'GET', '/v1/project');
|
|
56
56
|
const rows = Array.isArray(raw) ? raw : Array.isArray(raw?.data) ? raw.data : [];
|
|
57
57
|
return rows
|
|
58
58
|
.map(project)
|
|
@@ -70,11 +70,11 @@ export async function change(t, slug, what) {
|
|
|
70
70
|
}
|
|
71
71
|
if (what.visibility !== undefined)
|
|
72
72
|
body.visibility = what.visibility;
|
|
73
|
-
return project(await call(t, 'PATCH', `/v1/
|
|
73
|
+
return project(await call(t, 'PATCH', `/v1/project/${seg(slug)}`, body));
|
|
74
74
|
}
|
|
75
75
|
/** Delete a project. Its site stops answering and its slug is free again. */
|
|
76
76
|
export async function remove(t, slug) {
|
|
77
|
-
await call(t, 'DELETE', `/v1/
|
|
77
|
+
await call(t, 'DELETE', `/v1/project/${seg(slug)}`);
|
|
78
78
|
}
|
|
79
79
|
export function deployment(raw) {
|
|
80
80
|
const d = (raw && typeof raw === 'object' ? raw : {});
|
|
@@ -90,7 +90,7 @@ export function deployment(raw) {
|
|
|
90
90
|
}
|
|
91
91
|
/** A project's deployments, newest first: the first says how its latest build went. */
|
|
92
92
|
export async function deployments(t, slug) {
|
|
93
|
-
const raw = await call(t, 'GET', `/v1/
|
|
93
|
+
const raw = await call(t, 'GET', `/v1/project/${seg(slug)}/deployments`);
|
|
94
94
|
return (Array.isArray(raw) ? raw : [])
|
|
95
95
|
.map(deployment)
|
|
96
96
|
.filter((d) => d.id)
|
|
@@ -127,7 +127,7 @@ export async function templates(t) {
|
|
|
127
127
|
* once, and answers `building` until it is `live` or its build failed.
|
|
128
128
|
*/
|
|
129
129
|
export async function fork(t, slug) {
|
|
130
|
-
return project(await call(t, 'POST', '/v1/
|
|
130
|
+
return project(await call(t, 'POST', '/v1/project/fork', { slug }));
|
|
131
131
|
}
|
|
132
132
|
/** `owner/name` from a clone URL — its last two path segments, without `.git`. */
|
|
133
133
|
export function address(clone) {
|
package/lib/host.d.ts
CHANGED
|
@@ -107,6 +107,8 @@ export interface Host {
|
|
|
107
107
|
browser?: Browser;
|
|
108
108
|
/** The host's sidebar lists Settings' sections and Customize's tabs, so the pages draw neither. */
|
|
109
109
|
sections?: boolean;
|
|
110
|
+
/** The composer names the model and offers its picker beside the effort: the person turned the model selector on in the host's settings. Absent, the effort alone. */
|
|
111
|
+
models?: boolean;
|
|
110
112
|
/** The default agents Customize › Agents offers to start from. Absent, none. */
|
|
111
113
|
cast?: readonly Cast[];
|
|
112
114
|
/** Every persona Customize › Agents offers to start from, read when Browse opens. Absent, none. */
|
package/lib/index.d.ts
CHANGED
|
@@ -49,7 +49,7 @@ export { href, parse, path, PLACES, route, SESSION, SLUG, type Route, type Scree
|
|
|
49
49
|
* (`prompt`), the row under an answer (`Reply`), and the side panel (`Panel`
|
|
50
50
|
* over a `Deck` of tabs).
|
|
51
51
|
*/
|
|
52
|
-
export { catalog, EFFORTS, FIRST, FREE, grants, isFree, keep, kept, nameOf,
|
|
52
|
+
export { catalog, EFFORTS, FIRST, FREE, grants, isFree, keep, kept, nameOf, useCatalog, useChoice, useMind, type Choice, type Effort, type Mind } from './mind.ts';
|
|
53
53
|
export { ASK, cut, GAP, MEASURE, measure, Prompt, prompt, ROUND, trigger, Tune, useEar, useMention, useUpload, type Chip, type PromptOptions } from './prompt.tsx';
|
|
54
54
|
export { Plus, type Link, type PlusProps, type Row as ShelfRow, type Shelf, type Switch } from './plus.tsx';
|
|
55
55
|
export { BARE, CHAT_MODES, DEV_MODES, gearOf, MODES, useGear, useLanguage, type Gear, type GearState, type Mode as GearMode } from './gear.ts';
|
package/lib/index.js
CHANGED
|
@@ -44,7 +44,7 @@ export { href, parse, path, PLACES, route, SESSION, SLUG } from './route.js';
|
|
|
44
44
|
* (`prompt`), the row under an answer (`Reply`), and the side panel (`Panel`
|
|
45
45
|
* over a `Deck` of tabs).
|
|
46
46
|
*/
|
|
47
|
-
export { catalog, EFFORTS, FIRST, FREE, grants, isFree, keep, kept, nameOf,
|
|
47
|
+
export { catalog, EFFORTS, FIRST, FREE, grants, isFree, keep, kept, nameOf, useCatalog, useChoice, useMind } from './mind.js';
|
|
48
48
|
export { ASK, cut, GAP, MEASURE, measure, Prompt, prompt, ROUND, trigger, Tune, useEar, useMention, useUpload } from './prompt.js';
|
|
49
49
|
export { Plus } from './plus.js';
|
|
50
50
|
export { BARE, CHAT_MODES, DEV_MODES, gearOf, MODES, useGear, useLanguage } from './gear.js';
|
package/lib/landing.js
CHANGED
|
@@ -36,7 +36,7 @@ import { ready, SANDBOX } from './api/places.js';
|
|
|
36
36
|
import { asHub, isForge, isHub, settle } from './choice.js';
|
|
37
37
|
import { useCached, useKept, usePlaces, useRead } from './data.js';
|
|
38
38
|
import { useHost, useTarget } from './host.js';
|
|
39
|
-
import { useMind } from './mind.js';
|
|
39
|
+
import { level, useMind } from './mind.js';
|
|
40
40
|
import { usePrefs } from './prefs.js';
|
|
41
41
|
import { Publish } from './publish.js';
|
|
42
42
|
import { path } from './route.js';
|
|
@@ -231,7 +231,7 @@ export function Landing({ onStarted }) {
|
|
|
231
231
|
targetId: place.id,
|
|
232
232
|
mode,
|
|
233
233
|
model: mind.model,
|
|
234
|
-
effort: mind.effort,
|
|
234
|
+
effort: level(mind.effort),
|
|
235
235
|
issue,
|
|
236
236
|
});
|
|
237
237
|
setDraft('');
|
|
@@ -297,7 +297,7 @@ export function Landing({ onStarted }) {
|
|
|
297
297
|
};
|
|
298
298
|
/** Start the agent that finds a codebase's environment, and open it: its run is the progress. A refusal is the dialog's to say. */
|
|
299
299
|
const setup = async (repo) => {
|
|
300
|
-
const run = await start(target, { prompt: SETUP, repo, mode: 'setup', model: mind.model, effort: mind.effort });
|
|
300
|
+
const run = await start(target, { prompt: SETUP, repo, mode: 'setup', model: mind.model, effort: level(mind.effort) });
|
|
301
301
|
onStarted(run.session);
|
|
302
302
|
};
|
|
303
303
|
/** The codebase a dialog chose, chosen here too. */
|
|
@@ -367,7 +367,7 @@ export function Landing({ onStarted }) {
|
|
|
367
367
|
plugins: carry.plugins,
|
|
368
368
|
devices,
|
|
369
369
|
memory: { on: carry.gear.gear.memory, set: (on) => carry.gear.set({ memory: on }) },
|
|
370
|
-
}, on: carry.on, slash: carry.skills, at: carry.plugins, mode: carry.mode, where: where, below: _jsx(Suggestions, { rows: hints.rows, onAct: act, onDismiss: hints.dismiss }), mind: mind, limits: limits, onUpgrade: () => host.go(path({ kind: 'screen', screen: 'plans' })), voice: voice, language: prefs.language ?? null, onLanguage: (id) => void savePrefs({ language: id }), talk: talk })] })] }), _jsx(Publish, { source: adding, onClose: () => setAdding(null) }), carry.dialog, codebase ? (_jsx(SetupDialog, { repo: codebase, homes: homes, open: offering, onOpenChange: setOffering, onStart: setup, onRepo: choose, onSaved: () => {
|
|
370
|
+
}, on: carry.on, slash: carry.skills, at: carry.plugins, mode: carry.mode, where: where, below: _jsx(Suggestions, { rows: hints.rows, onAct: act, onDismiss: hints.dismiss }), model: host.models ? mind : null, effort: mind, limits: limits, onUpgrade: () => host.go(path({ kind: 'screen', screen: 'plans' })), voice: voice, language: prefs.language ?? null, onLanguage: (id) => void savePrefs({ language: id }), talk: talk })] })] }), _jsx(Publish, { source: adding, onClose: () => setAdding(null) }), carry.dialog, codebase ? (_jsx(SetupDialog, { repo: codebase, homes: homes, open: offering, onOpenChange: setOffering, onStart: setup, onRepo: choose, onSaved: () => {
|
|
371
371
|
setOffering(false);
|
|
372
372
|
env.reload();
|
|
373
373
|
} })) : null] }));
|
package/lib/merge.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ export interface Project {
|
|
|
42
42
|
synced: string;
|
|
43
43
|
/** Its link's state: `synced`, `conflict`, `pending`, `paused`, `linked` when its forge copy could not be read; '' with no link. */
|
|
44
44
|
status: string;
|
|
45
|
-
/** The org's project (GET /v1/
|
|
45
|
+
/** The org's project (GET /v1/project) that builds from it, by slug, or ''. */
|
|
46
46
|
slug: string;
|
|
47
47
|
/** The name GitHub's listing says it takes on the forge once brought there, or ''. */
|
|
48
48
|
codebase: string;
|
|
@@ -124,7 +124,7 @@ export interface Linked {
|
|
|
124
124
|
status: string;
|
|
125
125
|
branch: string;
|
|
126
126
|
}
|
|
127
|
-
/** One of the org's projects (GET /v1/
|
|
127
|
+
/** One of the org's projects (GET /v1/project) that builds from a repository. */
|
|
128
128
|
export interface Site {
|
|
129
129
|
slug: string;
|
|
130
130
|
/** Its clone address. */
|
package/lib/mind.d.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { type Target } from './api/call.ts';
|
|
2
2
|
import { type Model } from './api/models.ts';
|
|
3
|
-
export type Effort = '
|
|
4
|
-
/** The efforts, in English and marked (`phrase`): the composer draws each word through `t`. */
|
|
3
|
+
export type Effort = 'auto' | 'high' | 'xhigh' | 'max';
|
|
4
|
+
/** The efforts, in order, in English and marked (`phrase`): the composer draws each word through `t`. */
|
|
5
5
|
export declare const EFFORTS: readonly {
|
|
6
6
|
id: Effort;
|
|
7
7
|
label: string;
|
|
8
8
|
note: string;
|
|
9
9
|
}[];
|
|
10
|
+
/** The effort a coding run names (apps/coding takes low, medium or high): medium for Auto, high for the rest. */
|
|
11
|
+
export declare const level: (effort: Effort) => 'medium' | 'high';
|
|
10
12
|
/** What a person chose: the model (Enso routes) and the effort. */
|
|
11
13
|
export interface Choice {
|
|
12
14
|
model: string;
|
|
@@ -17,14 +19,12 @@ export declare const FIRST: Choice;
|
|
|
17
19
|
export declare const FREE = "enso-free";
|
|
18
20
|
/** Whether a plan grants only the free lane. An unknown plan is not taken for Free. */
|
|
19
21
|
export declare const isFree: (plan: string | null | undefined) => boolean;
|
|
20
|
-
/** The kept choice, Enso and
|
|
22
|
+
/** The kept choice, Enso and Auto where nothing is kept. Stable while the stored text is. Low and Medium, offered once, read as Auto. */
|
|
21
23
|
export declare function kept(): Choice;
|
|
22
24
|
/** Keep a change, in this browser, for every surface that reads it. */
|
|
23
25
|
export declare function keep(patch: Partial<Choice>): void;
|
|
24
26
|
/** The kept choice and the way to change it. The server and the first render read the default. */
|
|
25
27
|
export declare function useChoice(): readonly [Choice, (patch: Partial<Choice>) => void];
|
|
26
|
-
/** Whether `model` takes an effort: the router and an undescribed model do, a listed one only if it reasons. */
|
|
27
|
-
export declare function reasons(model: string, catalog: readonly Model[]): boolean;
|
|
28
28
|
/** A model's name as the catalog spells it; Enso for the router. */
|
|
29
29
|
export declare function nameOf(model: string, catalog: readonly Model[]): string;
|
|
30
30
|
/** An id said as a name: its last path part, each word capitalised (`enso-flash` → Enso Flash). */
|
package/lib/mind.js
CHANGED
|
@@ -5,16 +5,20 @@
|
|
|
5
5
|
* GET /v1/models the catalog, read once per platform and shared
|
|
6
6
|
* hanzo.mind the person's choice, in this browser: {model, effort}
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
8
|
+
* The effort is always under the composer; the model chip only where the host
|
|
9
|
+
* shows it (Hanzo's Advanced settings › model selector, `Host.models`). Enso
|
|
10
|
+
* routes every ask — a message in Chat, a step in Dev — so naming a model is an
|
|
11
|
+
* override, and the panel says so before it offers one. A premium model is
|
|
12
|
+
* picked for the screen it was picked on (`usePick`) and never kept, so the next
|
|
13
|
+
* conversation or run opens on what was kept, Enso until something else is.
|
|
13
14
|
*
|
|
14
|
-
* The efforts are
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* The efforts are Auto, High, XHigh and Max, Chat's words (Hanzo's
|
|
16
|
+
* ThinkingEffort), Auto until another is chosen. A coding run takes low, medium
|
|
17
|
+
* or high (apps/coding `efforts`), so `level` is what a run names: medium for
|
|
18
|
+
* Auto, what a run took before anyone chose, and high for the rest, the most it
|
|
19
|
+
* takes. Auto names one rather than none, because a run that names none takes
|
|
20
|
+
* an effort the person saved to their account once (apps/coding start.go) and
|
|
21
|
+
* no screen shows any more.
|
|
18
22
|
*/
|
|
19
23
|
import { phrase } from '@hanzo/i18n';
|
|
20
24
|
import { parseModels } from '@hanzo/ui/models/catalog';
|
|
@@ -22,13 +26,16 @@ import { useEffect, useState, useSyncExternalStore } from 'react';
|
|
|
22
26
|
import { Refusal } from './api/call.js';
|
|
23
27
|
import { ENSO, models as read } from './api/models.js';
|
|
24
28
|
import { usePick } from './pick.js';
|
|
25
|
-
/** The efforts, in English and marked (`phrase`): the composer draws each word through `t`. */
|
|
29
|
+
/** The efforts, in order, in English and marked (`phrase`): the composer draws each word through `t`. */
|
|
26
30
|
export const EFFORTS = [
|
|
27
|
-
{ id: '
|
|
28
|
-
{ id: '
|
|
29
|
-
{ id: '
|
|
31
|
+
{ id: 'auto', label: phrase('Auto'), note: phrase('Adaptive reasoning based on task complexity') },
|
|
32
|
+
{ id: 'high', label: phrase('High'), note: phrase('Deep reasoning for complex problems') },
|
|
33
|
+
{ id: 'xhigh', label: phrase('XHigh'), note: phrase('Extended multi-step reasoning for hard tasks') },
|
|
34
|
+
{ id: 'max', label: phrase('Max'), note: phrase('Maximum compute and exhaustive verification') },
|
|
30
35
|
];
|
|
31
|
-
|
|
36
|
+
/** The effort a coding run names (apps/coding takes low, medium or high): medium for Auto, high for the rest. */
|
|
37
|
+
export const level = (effort) => (effort === 'auto' ? 'medium' : 'high');
|
|
38
|
+
export const FIRST = { model: ENSO, effort: 'auto' };
|
|
32
39
|
/** What Free answers on: the catalog's free lane, Enso's first. `free` is an alias of it. */
|
|
33
40
|
export const FREE = 'enso-free';
|
|
34
41
|
/** Whether a plan grants only the free lane. An unknown plan is not taken for Free. */
|
|
@@ -49,7 +56,7 @@ let raw;
|
|
|
49
56
|
let held = FIRST;
|
|
50
57
|
/** A choice the browser would not store, held for the page. */
|
|
51
58
|
let memo = null;
|
|
52
|
-
/** The kept choice, Enso and
|
|
59
|
+
/** The kept choice, Enso and Auto where nothing is kept. Stable while the stored text is. Low and Medium, offered once, read as Auto. */
|
|
53
60
|
export function kept() {
|
|
54
61
|
if (memo)
|
|
55
62
|
return memo;
|
|
@@ -74,7 +81,8 @@ export function kept() {
|
|
|
74
81
|
}
|
|
75
82
|
/** Keep a change, in this browser, for every surface that reads it. */
|
|
76
83
|
export function keep(patch) {
|
|
77
|
-
const
|
|
84
|
+
const was = kept();
|
|
85
|
+
const next = { ...was, ...patch, effort: patch.effort === undefined ? was.effort : effortOf(patch.effort) };
|
|
78
86
|
try {
|
|
79
87
|
store()?.setItem(KEY, JSON.stringify(next));
|
|
80
88
|
memo = null;
|
|
@@ -98,13 +106,6 @@ function subscribe(change) {
|
|
|
98
106
|
export function useChoice() {
|
|
99
107
|
return [useSyncExternalStore(subscribe, kept, () => FIRST), keep];
|
|
100
108
|
}
|
|
101
|
-
/** Whether `model` takes an effort: the router and an undescribed model do, a listed one only if it reasons. */
|
|
102
|
-
export function reasons(model, catalog) {
|
|
103
|
-
if (model === ENSO)
|
|
104
|
-
return true;
|
|
105
|
-
const row = catalog.find((m) => m.id === model);
|
|
106
|
-
return !row || row.supports_reasoning === true;
|
|
107
|
-
}
|
|
108
109
|
/** A model's name as the catalog spells it; Enso for the router. */
|
|
109
110
|
export function nameOf(model, catalog) {
|
|
110
111
|
if (model === ENSO)
|
package/lib/plugins/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* The plugins the composer offers, from `+` › Plugins and by typing `@`: only
|
|
3
3
|
* those that run for this person, each on Hanzo's own services.
|
|
4
4
|
*
|
|
5
|
-
* Work in a project the org has a project (GET /v1/
|
|
5
|
+
* Work in a project the org has a project (GET /v1/project)
|
|
6
6
|
* Deep research signed in: web search, page reading and a Hanzo model, as the person
|
|
7
7
|
* Sketch always: it draws in the page
|
|
8
8
|
* Template Creator an org admin: only an admin writes the org's skills
|
package/lib/plugins/project.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
/**
|
|
3
|
-
* Work in a project: pick one of the org's projects (GET /v1/
|
|
3
|
+
* Work in a project: pick one of the org's projects (GET /v1/project). A
|
|
4
4
|
* conversation does not belong to a project — work in one is a Dev run tagged
|
|
5
5
|
* with it — so a message in the composer starts a Dev run on the picked project
|
|
6
6
|
* (POST /v1/agent/coding, the person's saved model) and opens it; with nothing
|
package/lib/project.js
CHANGED
|
@@ -64,7 +64,7 @@ import { useKept, useProjects, useRead, useRun } from './data.js';
|
|
|
64
64
|
import { Merge } from './git.js';
|
|
65
65
|
import { Gutter } from './gutter.js';
|
|
66
66
|
import { useHost, useTarget } from './host.js';
|
|
67
|
-
import { useMind } from './mind.js';
|
|
67
|
+
import { level, useMind } from './mind.js';
|
|
68
68
|
import { Out } from './out.js';
|
|
69
69
|
import { Prompt, useEar } from './prompt.js';
|
|
70
70
|
import { useSpoken } from './voice.js';
|
|
@@ -353,7 +353,7 @@ export function Project({ at }) {
|
|
|
353
353
|
mode,
|
|
354
354
|
// Enso named as itself: a run that names none takes the person's saved coding default.
|
|
355
355
|
model: mind.model,
|
|
356
|
-
effort: mind.effort,
|
|
356
|
+
effort: level(mind.effort),
|
|
357
357
|
});
|
|
358
358
|
setDraft('');
|
|
359
359
|
setPicked([]);
|
|
@@ -424,7 +424,7 @@ export function Project({ at }) {
|
|
|
424
424
|
? t('{repo} is open on {branch}. Say what to change and it gets built there.', { repo: `${named.org}/${named.name}`, branch: home })
|
|
425
425
|
: t('{name} is loaded. Say what to change and it gets built.', { name: slug }) })) : (ordered.map((r) => (_jsxs(YStack, { gap: "$2", children: [_jsx(Turn, { run: r, open: r.id === current, onOpen: () => setChosen(r.id), project: slug }), r.id === current ? (_jsxs(YStack, { gap: "$1", paddingInlineStart: "$2", borderInlineStartWidth: 1, borderColor: "$borderColor", children: [fold(run.events.map((e) => ({ kind: e.kind, actor: who(e.actor), seq: e.seq, id: e.id, text: said(e, run.record?.mode, t) })).filter((b) => b.text)).map((b) => (_jsx(SizableText, { size: "$1", color: "$soft", children: b.text }, b.key))), pr.href ? (_jsxs(XStack, { items: "center", gap: "$2", flexWrap: "wrap", children: [_jsxs(Out, { href: pr.href, label: t('Open pull request {pr}', { pr: pr.label }), children: [_jsx(SizableText, { size: "$1", color: "$ink", textDecorationLine: "underline", children: t('Pull request {pr}', { pr: pr.label }) }), _jsx(ExternalLink, { size: 11 })] }), _jsx(Merge, { session: r.id, open: proposing, onMerged: merged })] })) : null] })) : null] }, r.id)))) }), _jsxs(YStack, { "data-slot": "project-ask", px: "$3", pb: "$3", gap: "$2", minW: 0, $md: { pr: 0 }, children: [note ? (_jsx(SizableText, { size: "$1", color: "$soft", role: "status", children: note })) : null, picked.length ? _jsx(Attachments, { items: picked, onRemove: () => setPicked([]) }) : null, attached.length ? (_jsx(XStack, { gap: 6, flexWrap: "wrap", children: _jsx(Files, { files: attached, onFiles: setAttached }) })) : null, _jsx(Prompt, { framed: true, value: draft, onChange: setDraft, onSend: () => void (current && running ? steer(current) : send()), onStop: current
|
|
426
426
|
? () => void stop(target, current).then(() => setNote(t('Stop requested — the run keeps its work on its branch')), (e) => setNote(e.message))
|
|
427
|
-
: undefined, busy: busy || (running && !draft.trim()), placeholder: running ? t('Steer this run') : t('Ask Hanzo for edits'), label: t('Ask Hanzo for edits'), plus: { upload: () => pick(attached, setAttached, setNote, t) }, mode: running ? null : { value: mode === 'plan' ? 'plan' : 'auto', set: (m) => setMode(m === 'plan' ? 'plan' : 'build'), items: ['auto', 'plan'] }, mind: running ? null : mind, voice: voice })] }), wide && !shut ? (_jsx(Gutter, { side: "left", span: across, floor: CHAT_FLOOR, ceil: most, reset: CHAT_WIDTH, onSpan: setSplit, label: t('Resize the chat'), gap: GUTTER })) : null] }));
|
|
427
|
+
: undefined, busy: busy || (running && !draft.trim()), placeholder: running ? t('Steer this run') : t('Ask Hanzo for edits'), label: t('Ask Hanzo for edits'), plus: { upload: () => pick(attached, setAttached, setNote, t) }, mode: running ? null : { value: mode === 'plan' ? 'plan' : 'auto', set: (m) => setMode(m === 'plan' ? 'plan' : 'build'), items: ['auto', 'plan'] }, model: running || !host.models ? null : mind, effort: running ? null : mind, voice: voice })] }), wide && !shut ? (_jsx(Gutter, { side: "left", span: across, floor: CHAT_FLOOR, ceil: most, reset: CHAT_WIDTH, onSpan: setSplit, label: t('Resize the chat'), gap: GUTTER })) : null] }));
|
|
428
428
|
// The preview stays loaded while another view is open, so coming back to it
|
|
429
429
|
// is the page as it was left.
|
|
430
430
|
const preview = (_jsxs(YStack, { "data-slot": "preview", flex: 1, minH: 0, minW: 0, gap: "$2", display: view === 'preview' ? 'flex' : 'none', children: [_jsxs(XStack, { "data-slot": "preview-bar", items: "center", gap: "$1.5", minW: 0, shrink: 0, "$max-md": { px: '$2' }, children: [_jsx(XStack, { render: "button", "aria-label": t('Reload the preview'), onPress: () => frame.current?.reload(), p: "$1.5", rounded: "$3", hoverStyle: { bg: '$hover' }, children: _jsx(RefreshCcw, { size: 16 }) }), _jsx(PageSelect, { pages: pages, value: page, onChange: setPage, shrink: 1 }), _jsx(XStack, { flex: 1 }), _jsx(Views, { views: DEVICES, value: device, onChange: (d) => setDevice(d), label: t('Device'), labels: "none" }), src ? (_jsx(Out, { href: src, label: t('Open in a new tab'), children: _jsx(XStack, { p: "$1.5", rounded: "$3", hoverStyle: { bg: '$hover' }, children: _jsx(ExternalLink, { size: 16 }) }) })) : null] }), _jsx(PreviewFrame, { ref: frame, src: src, title: t('{title} preview', { title }), device: device, onBridge: onBridge, empty: _jsxs(YStack, { items: "center", gap: "$2", p: "$6", children: [_jsx(SizableText, { size: "$3", color: "$ink", children: stalled
|
package/lib/prompt.d.ts
CHANGED
|
@@ -57,8 +57,10 @@ export interface PromptOptions {
|
|
|
57
57
|
/** Above the frame, at its width: what the draft is sent with. */
|
|
58
58
|
head?: ReactNode;
|
|
59
59
|
field?: ComposerProps['field'];
|
|
60
|
-
/** The model
|
|
61
|
-
|
|
60
|
+
/** The model chip: given only where the person turned the model selector on (the host's setting). Absent, no model is named. */
|
|
61
|
+
model?: Mind | null;
|
|
62
|
+
/** The effort selector (Auto, High, XHigh, Max). Null where the next send takes none (steering a run). */
|
|
63
|
+
effort?: Mind | null;
|
|
62
64
|
limits?: PauseSource | null;
|
|
63
65
|
/** A model the plan does not grant was asked for: the way to the plan that does. */
|
|
64
66
|
onUpgrade?: (model: string) => void;
|
|
@@ -94,9 +96,10 @@ export interface PromptOptions {
|
|
|
94
96
|
/** A phone: suggestions go above the frame and every target is 44px. */
|
|
95
97
|
narrow?: boolean;
|
|
96
98
|
}
|
|
97
|
-
/** The row under the frame: where (Dev), then the model, the effort and the mode. */
|
|
98
|
-
export declare function Tune({
|
|
99
|
-
|
|
99
|
+
/** The row under the frame: where (Dev), then the model where the host shows it, the effort and the mode. */
|
|
100
|
+
export declare function Tune({ model, effort, mode, where, onUpgrade, limits, }: {
|
|
101
|
+
model?: Mind | null;
|
|
102
|
+
effort?: Mind | null;
|
|
100
103
|
mode?: PromptOptions['mode'];
|
|
101
104
|
where?: ReactNode;
|
|
102
105
|
onUpgrade?: (model: string) => void;
|
package/lib/prompt.js
CHANGED
|
@@ -6,10 +6,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
6
6
|
* one round button that is voice mode while the draft is empty, send once it
|
|
7
7
|
* has words, and stop while a turn runs. Nothing else is in the frame.
|
|
8
8
|
*
|
|
9
|
-
* Under the frame, at its end, one quiet row: the model
|
|
10
|
-
* the mode as a pill, each opening its choices;
|
|
11
|
-
* and its repository at the row's start (`where`).
|
|
12
|
-
* suggestions (`below`; above the frame on a phone).
|
|
9
|
+
* Under the frame, at its end, one quiet row: the model (only where the host
|
|
10
|
+
* shows it), the effort (dim) and the mode as a pill, each opening its choices;
|
|
11
|
+
* Dev puts where the run goes and its repository at the row's start (`where`).
|
|
12
|
+
* Under that, the person's suggestions (`below`; above the frame on a phone).
|
|
13
13
|
*
|
|
14
14
|
* `/` opens the skills and `@` the plugins, in a list just above the frame.
|
|
15
15
|
*
|
|
@@ -37,7 +37,7 @@ import { useEffect, useMemo, useRef, useState } from 'react';
|
|
|
37
37
|
import { ENSO } from './api/models.js';
|
|
38
38
|
import { MODES } from './gear.js';
|
|
39
39
|
import { Dictation } from './mic.js';
|
|
40
|
-
import { EFFORTS, grants, nameOf,
|
|
40
|
+
import { EFFORTS, grants, nameOf, ROUTER_IDS } from './mind.js';
|
|
41
41
|
import { Plus } from './plus.js';
|
|
42
42
|
import { english } from './say.js';
|
|
43
43
|
/** The reading measure: @hanzo/design's prose width, which Width (appearance) retunes. */
|
|
@@ -119,15 +119,14 @@ function Model({ mind, onUpgrade, limits }) {
|
|
|
119
119
|
return (_jsx(DropdownMenuItem, { "data-slot": "model-row", "data-model": m.id, "data-paused": paused ? 'true' : undefined, onSelect: () => (ok ? mind.pick(m.id) : onUpgrade?.(m.id)), children: _jsxs(XStack, { flex: 1, items: "center", gap: 8, children: [_jsx(SizableText, { fontSize: 14, color: ok ? '$ink' : '$hint', numberOfLines: 1, flex: 1, children: nameOf(m.id, mind.models) }), ok ? null : (_jsx(SizableText, { fontSize: 12, color: "$hint", px: 6, py: 1, rounded: 6, borderWidth: 1, borderColor: "$borderColor", children: t('Upgrade') })), ok && paused ? (_jsx(SizableText, { fontSize: 12, color: "$hint", children: t('Paused') })) : null, m.id === mind.model ? _jsx(Check, { size: 14, color: "var(--primary)", "aria-hidden": true }) : null] }) }, m.id));
|
|
120
120
|
})] }, g.key))), more > 0 ? (_jsx(SizableText, { fontSize: 12, color: "$hint", px: 8, py: 8, children: t('Type to search {count} more models', { count: more }) })) : null] })] })] }));
|
|
121
121
|
}
|
|
122
|
-
/** The row under the frame: where (Dev), then the model, the effort and the mode. */
|
|
123
|
-
export function Tune({
|
|
122
|
+
/** The row under the frame: where (Dev), then the model where the host shows it, the effort and the mode. */
|
|
123
|
+
export function Tune({ model, effort, mode, where, onUpgrade, limits, }) {
|
|
124
124
|
const { t } = useI18n();
|
|
125
|
-
const
|
|
126
|
-
const pace = mind ? EFFORTS.find((e) => e.id === mind.effort) : null;
|
|
125
|
+
const pace = effort ? EFFORTS.find((e) => e.id === effort.effort) : null;
|
|
127
126
|
const now = mode ? MODES.find((m) => m.id === mode.value) : undefined;
|
|
128
127
|
const way = now ? t(now.label) : '';
|
|
129
|
-
return (_jsxs(XStack, { "data-slot": "tune", width: "100%", items: "center", gap: 2, flexWrap: "wrap", rowGap: 4, children: [where ? (_jsx(XStack, { items: "center", gap: 2, flexWrap: "wrap", minW: 0, "$max-sm": { width: '100%' }, children: where })) : null, _jsx(XStack, { flex: 1, "$max-sm": { display: 'none' } }), _jsxs(XStack, { items: "center", gap: 2, marginInlineStart: "auto", shrink: 0, children: [
|
|
130
|
-
|
|
128
|
+
return (_jsxs(XStack, { "data-slot": "tune", width: "100%", items: "center", gap: 2, flexWrap: "wrap", rowGap: 4, children: [where ? (_jsx(XStack, { items: "center", gap: 2, flexWrap: "wrap", minW: 0, "$max-sm": { width: '100%' }, children: where })) : null, _jsx(XStack, { flex: 1, "$max-sm": { display: 'none' } }), _jsxs(XStack, { items: "center", gap: 2, marginInlineStart: "auto", shrink: 0, children: [model ? _jsx(Model, { mind: model, onUpgrade: onUpgrade, limits: limits }) : null, effort && pace ? (_jsx(Opens, { label: t('Effort: {level}', { level: t(pace.label) }), word: t(pace.label), dim: true, children: (close) => (_jsx(Choices, { title: t('Effort'), items: EFFORTS, value: effort.effort, onPick: (e) => {
|
|
129
|
+
effort.pace(e);
|
|
131
130
|
close();
|
|
132
131
|
} })) })) : null, mode ? (_jsxs(Popover, { allowFlip: true, placement: "top-end", children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(XStack, { render: "button", "data-slot": "mode", "aria-label": t('Mode: {mode}', { mode: way }), items: "center", height: 24, px: 8, marginInlineStart: 4, rounded: 6, bg: "$hover", cursor: "pointer", hoverStyle: { bg: '$raised' }, focusVisibleStyle: { outlineColor: '$outlineColor', outlineWidth: 2, outlineStyle: 'solid' }, "$max-sm": { height: 44, px: 12 }, children: _jsx(SizableText, { fontSize: 14, color: "$ink", children: way }) }) }), _jsx(PopoverContent, { solid: true, p: 6, width: 288, maxW: "calc(100vw - 24px)", children: _jsx(Choices, { title: t('Mode'), items: mode.items ? MODES.filter((m) => mode.items.includes(m.id)) : MODES, value: mode.value, onPick: mode.set }) })] })) : null] })] }));
|
|
133
132
|
}
|
|
@@ -163,7 +162,7 @@ export function prompt(o, state) {
|
|
|
163
162
|
};
|
|
164
163
|
const mention = listed && shelf && typed ? (_jsx(Mention, { shelf: shelf, rows: listed, index: index, onPick: choose, skills: typed.char === '/' })) : null;
|
|
165
164
|
const head = o.head || o.note || mention || (narrow && o.below) ? (_jsxs(YStack, { ...measure, gap: "$1.5", "data-slot": "prompt-head", children: [narrow ? o.below : null, o.head, mention, o.note ? (_jsx(SizableText, { "data-slot": "prompt-note", fontSize: 12, color: "$soft", text: "center", self: "center", children: o.note })) : null] })) : undefined;
|
|
166
|
-
const foot = o.
|
|
165
|
+
const foot = o.model || o.effort || o.mode || o.where || (!narrow && o.below) ? (_jsxs(YStack, { ...measure, gap: 10, "data-slot": "prompt-foot", children: [_jsx(Tune, { model: o.model, effort: o.effort, mode: o.mode, where: o.where, onUpgrade: o.onUpgrade, limits: o.limits }), narrow ? null : o.below] })) : undefined;
|
|
167
166
|
const round = (_jsx(Control, { type: "button", size: narrow ? TAP : ROUND, fill: true, rounded: 999, "data-slot": "composer-send", "aria-label": t(busy ? 'Stop' : 'Send'), "aria-disabled": !live || undefined, opacity: live ? 1 : 0.4, onClick: () => {
|
|
168
167
|
if (!live)
|
|
169
168
|
return;
|
package/lib/run.js
CHANGED
|
@@ -41,7 +41,7 @@ import { verdict } from './api/verdict.js';
|
|
|
41
41
|
import { useKept, useProjects, useRead, useRun } from './data.js';
|
|
42
42
|
import { Desk, SEED } from './desk.js';
|
|
43
43
|
import { useHost, useTarget } from './host.js';
|
|
44
|
-
import { useMind } from './mind.js';
|
|
44
|
+
import { level, useMind } from './mind.js';
|
|
45
45
|
import { Out } from './out.js';
|
|
46
46
|
import { Gutter } from './gutter.js';
|
|
47
47
|
import { gap, pane } from './pane.js';
|
|
@@ -206,7 +206,7 @@ export function Run({ id }) {
|
|
|
206
206
|
* itself: a run that names none takes the person's saved coding default
|
|
207
207
|
* (apps/coding start.go), which is not what the composer shows.
|
|
208
208
|
*/
|
|
209
|
-
const tuned = (a) => ({ ...a, model: mind.model, effort: mind.effort });
|
|
209
|
+
const tuned = (a) => ({ ...a, model: mind.model, effort: level(mind.effort) });
|
|
210
210
|
// A setup run's work IS its environment: the panel opens on it.
|
|
211
211
|
useEffect(() => {
|
|
212
212
|
if (mode === 'setup')
|
|
@@ -386,7 +386,7 @@ export function Run({ id }) {
|
|
|
386
386
|
...(busy || waiting ? ['pause', 'resume', 'stop'] : []),
|
|
387
387
|
] }), _jsx(Button, { size: "sm", disabled: notify, onPress: () => void ask(), children: notify ? say('You will be notified') : say('Notify me') })] })) : null] }), _jsx(Prompt, { framed: true, value: draft, onChange: setDraft, onSend: send, ready: Boolean(draft.trim()), disabled: !signed || busy || waiting || !(running || finished), placeholder: placeholder, label: steering ? say('Steer this run') : say('Follow up on this run'), head: files.length ? _jsx(XStack, { gap: "$1.5", flexWrap: "wrap", children: _jsx(Files, { files: files, onFiles: setFiles }) }) : undefined, plus: { upload: () => pick(files, setFiles, setNote, say) },
|
|
388
388
|
// What a new run from here is made with; words that steer this run use neither.
|
|
389
|
-
mind: signed && !steering ? mind : null, limits: limits, voice: voice })] })] }), desk && !wide ? desk_(true) : null, desk && wide ? (_jsxs(YStack, { "data-slot": "desk", ref: split.aside, ...pane,
|
|
389
|
+
model: signed && !steering && host.models ? mind : null, effort: signed && !steering ? mind : null, limits: limits, voice: voice })] })] }), desk && !wide ? desk_(true) : null, desk && wide ? (_jsxs(YStack, { "data-slot": "desk", ref: split.aside, ...pane,
|
|
390
390
|
// A pane of its own beside the run's, the gutter between them (useSplit reads it as the inline-start margin).
|
|
391
391
|
marginInlineStart: gap, position: "relative", shrink: 0, minH: 0, style: split.asideStyle, children: [split.grip ? (_jsx(Gutter, { ...split.grip, label: say('Resize the side panel'), inset: pane.borderWidth })) : null, _jsx(SideProvider, { value: split.side, children: desk_(false) })] })) : null, _jsx(Dialog, { open: naming, onOpenChange: setNaming, children: _jsxs(DialogContent, { maxW: 480, children: [_jsx(DialogTitle, { children: say('Rename this run') }), _jsx(Input, { autoFocus: true, value: name, onChangeText: setName, "aria-label": say('The run’s name'), maxLength: 512, onKeyDown: (e) => {
|
|
392
392
|
if (e.key === 'Enter')
|
package/lib/settings/code.js
CHANGED
|
@@ -60,7 +60,7 @@ export function Code() {
|
|
|
60
60
|
// The choices in the reader's words, kept by id.
|
|
61
61
|
const efforts = EFFORTS.map((e) => ({ ...e, label: t(e.label) }));
|
|
62
62
|
const modes = MODES.map((m) => ({ ...m, label: t(m.label), hint: t(m.hint) }));
|
|
63
|
-
const effort = efforts.find((e) => e.id === choice.effort);
|
|
63
|
+
const effort = efforts.find((e) => e.id === choice.effort) ?? efforts[0];
|
|
64
64
|
const mode = modes.find((m) => m.id === now.mode);
|
|
65
65
|
return (_jsxs(YStack, { gap: "$6", children: [_jsx(Heading, { title: t('Code'), detail: t('How a new run starts. The model and effort are the ones Chat uses too.') }), _jsxs(Group, { title: t('Defaults'), children: [_jsxs(Card, { children: [_jsx(Row, { first: true, title: t('Model'), detail: t('Enso picks one for each step; any other model runs them all.'), trailing: _jsx(ModelPicker, { size: "sm", name: t('Default model'), models: offered, scope: "chat", value: choice.model || ENSO, onChange: (id) => choose({ model: id }), loading: catalog.loading, error: catalog.error }) }), _jsx(Row, { title: t('Effort'), detail: t('How long the agent thinks before it acts.'), trailing: _jsx(ChipSelect, { name: t('Default effort'), label: effort.label, chosen: effort, items: efforts, onChange: (e) => choose({ effort: e.id }), placement: "bottom-end", width: 180 }) }), _jsx(Row, { title: t('Mode'), detail: mode.hint, trailing: _jsx(ChipSelect, { name: t('Default mode'), label: mode.label, chosen: mode, items: modes, onChange: (m) => keep({ mode: m.id }), placement: "bottom-end", width: 260 }) }), _jsx(Row, { title: t('Where it runs'), detail: t('The Hanzo sandbox, or one of your organization’s machines.'), trailing: _jsx(ChipSelect, { name: t('Default place'), label: place.label, chosen: place, items: where, onChange: (w) => keep({ place: w.place }), placeholder: t('Search machines…'), placement: "bottom-end", loading: places.loading, error: places.error ? told(places.error, t) : null }) })] }), _jsx(Note, { children: unhonoured(now.mode, now.place, t) })] }), _jsx(Group, { title: t('Workspace'), children: _jsxs(Card, { children: [_jsx(Row, { first: true, title: t('Environments'), detail: t('What a run installs and starts in each codebase, and the secrets it exports.'), trailing: _jsx(Link, { label: t('Open Environments'), onPress: () => go('environments') }) }), _jsx(Row, { title: t('Machines'), detail: t('Your organization’s own computers that take runs.'), trailing: _jsx(Link, { label: t('Open Machines'), onPress: () => go('machines') }) })] }) }), _jsx(Note, { children: note })] }));
|
|
66
66
|
}
|
package/lib/shelf.js
CHANGED
|
@@ -3,9 +3,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
* Two shelves: the sites this org has deployed (Sites, drawn at the foot of the
|
|
4
4
|
* Library — library.tsx), and the public starters (Templates).
|
|
5
5
|
*
|
|
6
|
-
* A project is a real row — `/v1/
|
|
6
|
+
* A project is a real row — `/v1/project`, the same one a deployed site is
|
|
7
7
|
* served from — so opening one opens its workspace at its own address. A
|
|
8
|
-
* starter is taken as a COPY of its own repository (`POST /v1/
|
|
8
|
+
* starter is taken as a COPY of its own repository (`POST /v1/project/fork`),
|
|
9
9
|
* so what opens is that template, not a model's imitation of it.
|
|
10
10
|
*/
|
|
11
11
|
import { SizableText, XStack, YStack } from '@hanzo/gui';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzo/build",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.83",
|
|
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 component, mounted by the Hanzo app at hanzo.ai.",
|