@hanzo/build 0.2.9 → 0.2.11
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 +126 -23
- package/lib/api/agents.d.ts +80 -0
- package/lib/api/agents.js +148 -0
- package/lib/api/billing.d.ts +205 -0
- package/lib/api/billing.js +300 -0
- package/lib/api/call.d.ts +6 -0
- package/lib/api/call.js +11 -0
- package/lib/api/capabilities.d.ts +25 -0
- package/lib/api/capabilities.js +40 -0
- package/lib/api/changes.d.ts +56 -0
- package/lib/api/changes.js +63 -0
- package/lib/api/coding.d.ts +42 -4
- package/lib/api/coding.js +62 -3
- package/lib/api/connectors.d.ts +90 -0
- package/lib/api/connectors.js +109 -0
- package/lib/api/consent.d.ts +22 -0
- package/lib/api/consent.js +28 -0
- package/lib/api/environment.d.ts +57 -0
- package/lib/api/environment.js +85 -0
- package/lib/api/git.d.ts +6 -2
- package/lib/api/git.js +13 -5
- package/lib/api/github.d.ts +13 -0
- package/lib/api/github.js +9 -0
- package/lib/api/harness.d.ts +44 -0
- package/lib/api/harness.js +348 -0
- package/lib/api/keys.d.ts +41 -0
- package/lib/api/keys.js +55 -0
- package/lib/api/machines.d.ts +56 -0
- package/lib/api/machines.js +84 -0
- package/lib/api/members.d.ts +47 -0
- package/lib/api/members.js +88 -0
- package/lib/api/memory.d.ts +25 -0
- package/lib/api/memory.js +34 -0
- package/lib/api/places.d.ts +2 -2
- package/lib/api/places.js +3 -26
- package/lib/api/plugins.d.ts +55 -0
- package/lib/api/plugins.js +62 -0
- package/lib/api/pref.d.ts +49 -0
- package/lib/api/pref.js +68 -0
- package/lib/api/profile.d.ts +21 -0
- package/lib/api/profile.js +40 -0
- package/lib/api/projects.d.ts +19 -2
- package/lib/api/projects.js +29 -4
- package/lib/api/provider.d.ts +42 -0
- package/lib/api/provider.js +58 -0
- package/lib/api/sandbox.d.ts +30 -0
- package/lib/api/sandbox.js +49 -0
- package/lib/api/sessions.d.ts +39 -4
- package/lib/api/sessions.js +58 -6
- package/lib/api/skills.d.ts +70 -0
- package/lib/api/skills.js +90 -0
- package/lib/api/tools.d.ts +34 -0
- package/lib/api/tools.js +37 -0
- package/lib/api/turn.d.ts +84 -16
- package/lib/api/turn.js +224 -4
- package/lib/api/webhooks.d.ts +60 -0
- package/lib/api/webhooks.js +81 -0
- package/lib/ask.d.ts +18 -0
- package/lib/ask.js +69 -0
- package/lib/builder.js +39 -19
- package/lib/customize/agents.d.ts +2 -0
- package/lib/customize/agents.js +125 -0
- package/lib/customize/connectors.d.ts +2 -0
- package/lib/customize/connectors.js +197 -0
- package/lib/customize/index.d.ts +6 -0
- package/lib/customize/index.js +50 -0
- package/lib/customize/plugins.d.ts +2 -0
- package/lib/customize/plugins.js +93 -0
- package/lib/customize/skills.d.ts +2 -0
- package/lib/customize/skills.js +125 -0
- package/lib/customize/ui.d.ts +110 -0
- package/lib/customize/ui.js +99 -0
- package/lib/desk.d.ts +8 -1
- package/lib/desk.js +29 -35
- package/lib/door.d.ts +7 -0
- package/lib/door.js +89 -0
- package/lib/environment.d.ts +15 -0
- package/lib/environment.js +132 -0
- package/lib/files.d.ts +14 -0
- package/lib/files.js +111 -0
- package/lib/find.d.ts +7 -0
- package/lib/find.js +77 -0
- package/lib/foot.d.ts +16 -0
- package/lib/foot.js +36 -0
- package/lib/forge.js +8 -4
- package/lib/git.d.ts +9 -0
- package/lib/git.js +74 -0
- package/lib/host.d.ts +5 -0
- package/lib/landing.d.ts +10 -0
- package/lib/landing.js +47 -14
- package/lib/markdown.d.ts +49 -0
- package/lib/markdown.js +123 -0
- package/lib/plans.d.ts +1 -0
- package/lib/plans.js +113 -0
- package/lib/prefs.d.ts +30 -0
- package/lib/prefs.js +83 -0
- package/lib/prose.d.ts +4 -0
- package/lib/prose.js +53 -0
- package/lib/route.d.ts +16 -1
- package/lib/route.js +32 -1
- package/lib/run.js +207 -28
- package/lib/section.js +2 -2
- package/lib/settings/account.d.ts +5 -0
- package/lib/settings/account.js +111 -0
- package/lib/settings/billing.d.ts +1 -0
- package/lib/settings/billing.js +104 -0
- package/lib/settings/capabilities.d.ts +1 -0
- package/lib/settings/capabilities.js +55 -0
- package/lib/settings/card.d.ts +31 -0
- package/lib/settings/card.js +105 -0
- package/lib/settings/code.d.ts +1 -0
- package/lib/settings/code.js +51 -0
- package/lib/settings/environments.d.ts +1 -0
- package/lib/settings/environments.js +53 -0
- package/lib/settings/general.d.ts +1 -0
- package/lib/settings/general.js +44 -0
- package/lib/settings/index.d.ts +4 -0
- package/lib/settings/index.js +22 -0
- package/lib/settings/integrations.d.ts +1 -0
- package/lib/settings/integrations.js +81 -0
- package/lib/settings/keys.d.ts +1 -0
- package/lib/settings/keys.js +102 -0
- package/lib/settings/machines.d.ts +1 -0
- package/lib/settings/machines.js +118 -0
- package/lib/settings/members.d.ts +1 -0
- package/lib/settings/members.js +67 -0
- package/lib/settings/memory.d.ts +1 -0
- package/lib/settings/memory.js +56 -0
- package/lib/settings/notifications.d.ts +1 -0
- package/lib/settings/notifications.js +97 -0
- package/lib/settings/privacy.d.ts +1 -0
- package/lib/settings/privacy.js +63 -0
- package/lib/settings/sections.d.ts +16 -0
- package/lib/settings/sections.js +32 -0
- package/lib/settings/ui.d.ts +49 -0
- package/lib/settings/ui.js +47 -0
- package/lib/settings/usage.d.ts +1 -0
- package/lib/settings/usage.js +114 -0
- package/lib/shelf.d.ts +6 -0
- package/lib/shelf.js +86 -16
- package/lib/switch.js +1 -2
- package/lib/transcript.d.ts +12 -0
- package/lib/transcript.js +56 -0
- package/lib/voice.d.ts +3 -1
- package/lib/voice.js +10 -4
- package/package.json +1 -1
- package/lib/account.d.ts +0 -14
- package/lib/account.js +0 -38
- package/lib/e2e/site.spec.d.ts +0 -1
- package/lib/e2e/site.spec.js +0 -125
- package/lib/mcp.d.ts +0 -1
- package/lib/mcp.js +0 -28
package/lib/api/turn.js
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a run's events SAY, as text a person reads.
|
|
3
|
+
*
|
|
4
|
+
* A curated projection, never a dump: an event carries the machinery a run
|
|
5
|
+
* happened on — hosts, paths, whole file bodies — and printing it would put
|
|
6
|
+
* someone's filesystem in front of anyone who can read the run. Each kind gets a
|
|
7
|
+
* sentence built from the few fields that describe the outcome; the rest is
|
|
8
|
+
* dropped by omission, because a projection cannot leak a field it never reads.
|
|
9
|
+
*
|
|
10
|
+
* Every string here is rendered as TEXT by the transcript. Nothing is HTML.
|
|
11
|
+
*
|
|
12
|
+
* The coding plane's vocabulary (apps/coding): `status` for a lifecycle move
|
|
13
|
+
* (started, routed, done, error, stopped, paused), `tool-call` for a step,
|
|
14
|
+
* `log` for a free line. A person's steering is a `control` {command, message}.
|
|
15
|
+
*
|
|
16
|
+
* `cards` is the transcript as it is drawn: the run's steps, and the agent's own
|
|
17
|
+
* output read by what each part is (harness.ts). The output a card shows is what
|
|
18
|
+
* the run's Terminal log already prints; a command's working directory, which is
|
|
19
|
+
* the sandbox's layout, is dropped.
|
|
20
|
+
*/
|
|
21
|
+
import { harness } from './harness.js';
|
|
1
22
|
const str = (v) => (typeof v === 'string' ? v : '');
|
|
2
23
|
/** The payload as an object. A live frame may carry it as a JSON string. */
|
|
3
24
|
export function decode(payload) {
|
|
@@ -34,8 +55,11 @@ function status(b, mode) {
|
|
|
34
55
|
// A plan's answer IS its final status: the run read and wrote nothing.
|
|
35
56
|
// Whether the run planned is the RECORD's word — any member of the org
|
|
36
57
|
// can append an event saying `mode: plan`, and its text is not an answer.
|
|
58
|
+
// A setup is a plan put to one question, and answers the same way.
|
|
37
59
|
if (mode === 'plan')
|
|
38
60
|
return str(b.plan) || 'Planned — the run answered with no plan';
|
|
61
|
+
if (mode === 'setup')
|
|
62
|
+
return str(b.plan) || 'Set up — the run answered with no environment';
|
|
39
63
|
if (b.changed === false)
|
|
40
64
|
return 'Done — nothing to change';
|
|
41
65
|
const pr = str(b.pr);
|
|
@@ -47,7 +71,10 @@ function status(b, mode) {
|
|
|
47
71
|
case 'stopped':
|
|
48
72
|
return branch && b.changed ? `Stopped — work kept on ${branch}` : 'Stopped';
|
|
49
73
|
case 'paused':
|
|
50
|
-
return 'Paused';
|
|
74
|
+
return branch && b.changed ? `Paused — work kept on ${branch}` : 'Paused';
|
|
75
|
+
case 'followed':
|
|
76
|
+
// A run redirected from a chat thread is carried on by a follow-up (apps/coding steer.go).
|
|
77
|
+
return str(b.next) ? 'Continued in a follow-up run' : 'The follow-up run could not start';
|
|
51
78
|
}
|
|
52
79
|
return str(b.status);
|
|
53
80
|
}
|
|
@@ -120,7 +147,12 @@ export function shell(events) {
|
|
|
120
147
|
}
|
|
121
148
|
return out.slice(-400);
|
|
122
149
|
}
|
|
123
|
-
/**
|
|
150
|
+
/**
|
|
151
|
+
* Tool calls, in the order they were first named. A later status for the same
|
|
152
|
+
* step wins, and a run's steps follow one another, so a step another has
|
|
153
|
+
* followed is over. `exit` is not a step: it is how the sandbox says one command
|
|
154
|
+
* in it ended (apps/sandbox work.go).
|
|
155
|
+
*/
|
|
124
156
|
export function steps(events) {
|
|
125
157
|
const order = [];
|
|
126
158
|
const done = new Map();
|
|
@@ -131,14 +163,14 @@ export function steps(events) {
|
|
|
131
163
|
if (!body || typeof body === 'string')
|
|
132
164
|
continue;
|
|
133
165
|
const name = str(body.step);
|
|
134
|
-
if (!name)
|
|
166
|
+
if (!name || name === 'exit')
|
|
135
167
|
continue;
|
|
136
168
|
if (!done.has(name))
|
|
137
169
|
order.push(name);
|
|
138
170
|
const status = str(body.status);
|
|
139
171
|
done.set(name, status === 'ok' || status === 'done' || status === 'error');
|
|
140
172
|
}
|
|
141
|
-
return order.map((name) => ({ name, done: done.get(name) === true }));
|
|
173
|
+
return order.map((name, i) => ({ name, done: i < order.length - 1 || done.get(name) === true }));
|
|
142
174
|
}
|
|
143
175
|
/**
|
|
144
176
|
* What the run narrated about how it ended, latest winning. Status text only:
|
|
@@ -187,3 +219,191 @@ export function pull(url, repo) {
|
|
|
187
219
|
return { href: '', label: '' };
|
|
188
220
|
return { href: url, label: `#${m[3]}` };
|
|
189
221
|
}
|
|
222
|
+
/** The platform's own words for the step that starts the agent (apps/coding sandboxrunner.go). */
|
|
223
|
+
const TASK = 'running the task';
|
|
224
|
+
/** What the run's own steps are called on a card. */
|
|
225
|
+
const NAMES = {
|
|
226
|
+
lease: 'Sandbox',
|
|
227
|
+
clone: 'Clone',
|
|
228
|
+
secrets: 'Secrets',
|
|
229
|
+
install: 'Install',
|
|
230
|
+
start: 'Start',
|
|
231
|
+
push: 'Push',
|
|
232
|
+
keep: 'Keep the work',
|
|
233
|
+
};
|
|
234
|
+
/** Steps another card already says: `leased` finishes the lease, `done` is the final status, `ended` is housekeeping. */
|
|
235
|
+
const QUIET = new Set(['leased', 'done', 'ended']);
|
|
236
|
+
const ranOf = (status) => (status === 'ok' || status === 'done' ? 'done' : status === 'error' ? 'error' : 'running');
|
|
237
|
+
/**
|
|
238
|
+
* A run's events, as the cards its transcript draws. `mode` is the run's, from
|
|
239
|
+
* its record: a plan's final status is its plan, and nothing else draws a plan.
|
|
240
|
+
*
|
|
241
|
+
* The run's own steps arrive as `tool-call` {step, message, status}; each
|
|
242
|
+
* command in the sandbox narrates its output as `log` {message} chunks and ends
|
|
243
|
+
* with `tool-call` {step: "exit"}. The output after the step that starts the
|
|
244
|
+
* agent is the agent's, read by its harness's grammar (harness.ts); after any
|
|
245
|
+
* other step it is that step's. Once the agent has exited, the commands the run
|
|
246
|
+
* runs before it pushes commit its work.
|
|
247
|
+
*/
|
|
248
|
+
export function cards(events, mode = '') {
|
|
249
|
+
const out = [];
|
|
250
|
+
let seq = 0;
|
|
251
|
+
let n = 0;
|
|
252
|
+
const mint = () => `${seq}.${n++}`;
|
|
253
|
+
let phase = null;
|
|
254
|
+
let agent = null;
|
|
255
|
+
// The agent has run and exited: output with no step of its own is the run's.
|
|
256
|
+
let exited = false;
|
|
257
|
+
const settle = () => {
|
|
258
|
+
agent?.end();
|
|
259
|
+
agent = null;
|
|
260
|
+
phase = null;
|
|
261
|
+
};
|
|
262
|
+
const answers = new Set();
|
|
263
|
+
for (const e of [...events].sort((a, b) => a.seq - b.seq)) {
|
|
264
|
+
seq = e.seq;
|
|
265
|
+
n = 0;
|
|
266
|
+
const body = decode(e.payload);
|
|
267
|
+
const b = body && typeof body === 'object' ? body : null;
|
|
268
|
+
switch (e.kind) {
|
|
269
|
+
case 'log': {
|
|
270
|
+
const text = typeof body === 'string' ? body : str(b?.message) || str(b?.text);
|
|
271
|
+
if (!text)
|
|
272
|
+
break;
|
|
273
|
+
if (!agent && !phase && exited) {
|
|
274
|
+
phase = { kind: 'step', key: mint(), name: 'Commit', detail: 'committing the work', output: '', ran: 'running' };
|
|
275
|
+
out.push(phase);
|
|
276
|
+
}
|
|
277
|
+
if (!agent && !phase)
|
|
278
|
+
agent = harness(out, mint);
|
|
279
|
+
if (agent)
|
|
280
|
+
agent.feed(text);
|
|
281
|
+
else if (phase)
|
|
282
|
+
phase.output += text;
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
case 'tool-call': {
|
|
286
|
+
if (!b)
|
|
287
|
+
break;
|
|
288
|
+
const step = str(b.step);
|
|
289
|
+
const message = str(b.message);
|
|
290
|
+
if (step === 'exit') {
|
|
291
|
+
// One command in the sandbox ended: `exit 0`, `exit 1`, or `ended: …`.
|
|
292
|
+
if (agent) {
|
|
293
|
+
settle();
|
|
294
|
+
exited = true;
|
|
295
|
+
}
|
|
296
|
+
else if (phase && phase.ran === 'running')
|
|
297
|
+
phase.ran = message === 'exit 0' ? 'done' : 'error';
|
|
298
|
+
break;
|
|
299
|
+
}
|
|
300
|
+
if (message === TASK) {
|
|
301
|
+
settle();
|
|
302
|
+
exited = false;
|
|
303
|
+
agent = harness(out, mint);
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
if (step === 'leased') {
|
|
307
|
+
const lease = out.find((c) => c.kind === 'step' && c.name === NAMES.lease);
|
|
308
|
+
if (lease)
|
|
309
|
+
lease.ran = 'done';
|
|
310
|
+
}
|
|
311
|
+
if (!step || QUIET.has(step))
|
|
312
|
+
break;
|
|
313
|
+
const name = NAMES[step] ?? step.charAt(0).toUpperCase() + step.slice(1);
|
|
314
|
+
if (phase && phase.name === name) {
|
|
315
|
+
phase.ran = ranOf(str(b.status));
|
|
316
|
+
if (message)
|
|
317
|
+
phase.detail = message;
|
|
318
|
+
break;
|
|
319
|
+
}
|
|
320
|
+
settle();
|
|
321
|
+
phase = { kind: 'step', key: mint(), name, detail: message, output: '', ran: ranOf(str(b.status)) };
|
|
322
|
+
out.push(phase);
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
case 'status': {
|
|
326
|
+
settle();
|
|
327
|
+
if (!b)
|
|
328
|
+
break;
|
|
329
|
+
const text = str(b.plan);
|
|
330
|
+
if (str(b.status) === 'done' && (mode === 'plan' || mode === 'setup') && text) {
|
|
331
|
+
answers.add(text.trim());
|
|
332
|
+
out.push(mode === 'plan' ? { kind: 'plan', key: mint(), text } : { kind: 'said', key: mint(), who: 'agent', text });
|
|
333
|
+
break;
|
|
334
|
+
}
|
|
335
|
+
const line = status(b, mode);
|
|
336
|
+
if (line)
|
|
337
|
+
out.push({ kind: 'note', key: mint(), text: line });
|
|
338
|
+
break;
|
|
339
|
+
}
|
|
340
|
+
case 'control': {
|
|
341
|
+
if (!b)
|
|
342
|
+
break;
|
|
343
|
+
const command = str(b.command);
|
|
344
|
+
const said = str(b.message);
|
|
345
|
+
if (command === 'message' && said)
|
|
346
|
+
out.push({ kind: 'said', key: mint(), who: 'person', text: said });
|
|
347
|
+
else if (command === 'pause')
|
|
348
|
+
out.push({ kind: 'note', key: mint(), text: 'Pause asked' });
|
|
349
|
+
else if (command === 'resume')
|
|
350
|
+
out.push({ kind: 'note', key: mint(), text: 'Resume asked' });
|
|
351
|
+
else if (command === 'stop')
|
|
352
|
+
out.push({ kind: 'note', key: mint(), text: 'Stop asked' });
|
|
353
|
+
break;
|
|
354
|
+
}
|
|
355
|
+
case 'message': {
|
|
356
|
+
const text = typeof body === 'string' ? body : str(b?.text) || str(b?.content) || str(b?.message);
|
|
357
|
+
if (text)
|
|
358
|
+
out.push({ kind: 'said', key: mint(), who: str(b?.role) === 'user' ? 'person' : 'agent', text });
|
|
359
|
+
break;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
settle();
|
|
364
|
+
// The answer the final status carries is also the agent's last message: draw it once, as the answer.
|
|
365
|
+
let kept = false;
|
|
366
|
+
for (let i = out.length - 1; i >= 0; i--) {
|
|
367
|
+
const c = out[i];
|
|
368
|
+
if (!((c.kind === 'said' && c.who === 'agent') || c.kind === 'plan') || !answers.has(c.text.trim()))
|
|
369
|
+
continue;
|
|
370
|
+
if (kept)
|
|
371
|
+
out.splice(i, 1);
|
|
372
|
+
kept = true;
|
|
373
|
+
}
|
|
374
|
+
return out;
|
|
375
|
+
}
|
|
376
|
+
/** The plan a plan run answered with, from its final status, or ''. */
|
|
377
|
+
export function answer(events) {
|
|
378
|
+
let out = '';
|
|
379
|
+
for (const e of [...events].sort((a, b) => a.seq - b.seq)) {
|
|
380
|
+
if (e.kind !== 'status')
|
|
381
|
+
continue;
|
|
382
|
+
const b = decode(e.payload);
|
|
383
|
+
if (b && typeof b === 'object' && str(b.status) === 'done')
|
|
384
|
+
out = str(b.plan);
|
|
385
|
+
}
|
|
386
|
+
return out;
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Whether the run has kept its work yet, and whether that work is on its
|
|
390
|
+
* branch. A stop or a pause commits and pushes AFTER it is asked, and says so
|
|
391
|
+
* in its status (apps/coding coding.go interrupted): until then a follow-up
|
|
392
|
+
* would clone a branch the push has not reached.
|
|
393
|
+
*/
|
|
394
|
+
export function settled(events) {
|
|
395
|
+
const out = { settled: false, pushed: false };
|
|
396
|
+
for (const e of [...events].sort((a, b) => a.seq - b.seq)) {
|
|
397
|
+
if (e.kind !== 'status')
|
|
398
|
+
continue;
|
|
399
|
+
const b = decode(e.payload);
|
|
400
|
+
if (!b || typeof b === 'string')
|
|
401
|
+
continue;
|
|
402
|
+
const s = str(b.status);
|
|
403
|
+
if (s === 'done' || s === 'error' || s === 'stopped' || s === 'paused') {
|
|
404
|
+
out.settled = true;
|
|
405
|
+
out.pushed = b.changed === true;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
return out;
|
|
409
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The organization's webhooks: https endpoints that each matching platform event
|
|
3
|
+
* is POSTed to, signed.
|
|
4
|
+
*
|
|
5
|
+
* GET /v1/webhook {data: [endpoint]}, newest first, secrets withheld
|
|
6
|
+
* POST /v1/webhook {url, events, description} → 201, the secret shown this once
|
|
7
|
+
* DELETE /v1/webhook/{id} 204
|
|
8
|
+
* POST /v1/webhook/{id}/test one signed test event, sent now → {delivered, httpStatus, durationMs, error}
|
|
9
|
+
* GET /v1/webhook/{id}/deliveries {data: [attempt]}, newest first
|
|
10
|
+
*
|
|
11
|
+
* The org is the caller's; an endpoint another org owns reads as not found.
|
|
12
|
+
* Events are subject patterns (`commerce.order.>`); none means every event.
|
|
13
|
+
*/
|
|
14
|
+
import { type Target } from './call.ts';
|
|
15
|
+
export interface Endpoint {
|
|
16
|
+
id: string;
|
|
17
|
+
url: string;
|
|
18
|
+
/** Subject patterns; empty is every event. */
|
|
19
|
+
events: string[];
|
|
20
|
+
description: string;
|
|
21
|
+
/** active | disabled */
|
|
22
|
+
status: string;
|
|
23
|
+
/** The signing secret: present only in the answer to a create. */
|
|
24
|
+
secret: string;
|
|
25
|
+
created: string;
|
|
26
|
+
/** Settled in the last seven days, and how many of those failed. */
|
|
27
|
+
deliveries: number;
|
|
28
|
+
failures: number;
|
|
29
|
+
}
|
|
30
|
+
export declare function endpoint(raw: unknown): Endpoint;
|
|
31
|
+
export declare function endpoints(t: Target): Promise<Endpoint[]>;
|
|
32
|
+
/** The patterns in what a person typed: comma or space separated. */
|
|
33
|
+
export declare function patterns(typed: string): string[];
|
|
34
|
+
export interface Draft {
|
|
35
|
+
url: string;
|
|
36
|
+
events: string[];
|
|
37
|
+
description: string;
|
|
38
|
+
}
|
|
39
|
+
/** Why a draft cannot be sent, or ''. The platform refuses the same things. */
|
|
40
|
+
export declare function refuse(d: Draft): string;
|
|
41
|
+
export declare function add(t: Target, d: Draft): Promise<Endpoint>;
|
|
42
|
+
export declare function remove(t: Target, id: string): Promise<void>;
|
|
43
|
+
export interface Trial {
|
|
44
|
+
delivered: boolean;
|
|
45
|
+
/** 0 when the endpoint never answered. */
|
|
46
|
+
status: number;
|
|
47
|
+
ms: number;
|
|
48
|
+
error: string;
|
|
49
|
+
}
|
|
50
|
+
export declare function test(t: Target, id: string): Promise<Trial>;
|
|
51
|
+
export interface Attempt {
|
|
52
|
+
subject: string;
|
|
53
|
+
/** ok | retrying | failed */
|
|
54
|
+
status: string;
|
|
55
|
+
code: number;
|
|
56
|
+
attempt: number;
|
|
57
|
+
error: string;
|
|
58
|
+
at: string;
|
|
59
|
+
}
|
|
60
|
+
export declare function deliveries(t: Target, id: string, limit?: number): Promise<Attempt[]>;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The organization's webhooks: https endpoints that each matching platform event
|
|
3
|
+
* is POSTed to, signed.
|
|
4
|
+
*
|
|
5
|
+
* GET /v1/webhook {data: [endpoint]}, newest first, secrets withheld
|
|
6
|
+
* POST /v1/webhook {url, events, description} → 201, the secret shown this once
|
|
7
|
+
* DELETE /v1/webhook/{id} 204
|
|
8
|
+
* POST /v1/webhook/{id}/test one signed test event, sent now → {delivered, httpStatus, durationMs, error}
|
|
9
|
+
* GET /v1/webhook/{id}/deliveries {data: [attempt]}, newest first
|
|
10
|
+
*
|
|
11
|
+
* The org is the caller's; an endpoint another org owns reads as not found.
|
|
12
|
+
* Events are subject patterns (`commerce.order.>`); none means every event.
|
|
13
|
+
*/
|
|
14
|
+
import { call, query, seg } from './call.js';
|
|
15
|
+
const str = (v) => (typeof v === 'string' ? v : '');
|
|
16
|
+
const num = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : 0);
|
|
17
|
+
const obj = (v) => (v && typeof v === 'object' ? v : {});
|
|
18
|
+
const arr = (v) => (Array.isArray(v) ? v : []);
|
|
19
|
+
export function endpoint(raw) {
|
|
20
|
+
const e = obj(raw);
|
|
21
|
+
return {
|
|
22
|
+
id: str(e.id),
|
|
23
|
+
url: str(e.url),
|
|
24
|
+
events: arr(e.events).filter((s) => typeof s === 'string' && s !== ''),
|
|
25
|
+
description: str(e.description),
|
|
26
|
+
status: str(e.status) || 'active',
|
|
27
|
+
secret: str(e.secret),
|
|
28
|
+
created: str(e.created),
|
|
29
|
+
deliveries: num(e.deliveries7d),
|
|
30
|
+
failures: num(e.failures7d),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export async function endpoints(t) {
|
|
34
|
+
const raw = obj(await call(t, 'GET', '/v1/webhook'));
|
|
35
|
+
return arr(raw.data).map(endpoint).filter((e) => e.id);
|
|
36
|
+
}
|
|
37
|
+
/** The patterns in what a person typed: comma or space separated. */
|
|
38
|
+
export function patterns(typed) {
|
|
39
|
+
return [...new Set(typed.split(/[\s,]+/).map((s) => s.trim()).filter(Boolean))];
|
|
40
|
+
}
|
|
41
|
+
/** Why a draft cannot be sent, or ''. The platform refuses the same things. */
|
|
42
|
+
export function refuse(d) {
|
|
43
|
+
let u;
|
|
44
|
+
try {
|
|
45
|
+
u = new URL(d.url.trim());
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return 'Enter the https address to deliver to';
|
|
49
|
+
}
|
|
50
|
+
if (u.protocol !== 'https:')
|
|
51
|
+
return 'A webhook is delivered over https only';
|
|
52
|
+
if (d.events.length > 64)
|
|
53
|
+
return 'At most 64 event patterns';
|
|
54
|
+
return '';
|
|
55
|
+
}
|
|
56
|
+
export async function add(t, d) {
|
|
57
|
+
const why = refuse(d);
|
|
58
|
+
if (why)
|
|
59
|
+
throw new Error(why);
|
|
60
|
+
return endpoint(await call(t, 'POST', '/v1/webhook', { url: d.url.trim(), events: d.events, description: d.description.trim() }));
|
|
61
|
+
}
|
|
62
|
+
export async function remove(t, id) {
|
|
63
|
+
await call(t, 'DELETE', `/v1/webhook/${seg(id)}`);
|
|
64
|
+
}
|
|
65
|
+
export async function test(t, id) {
|
|
66
|
+
const r = obj(await call(t, 'POST', `/v1/webhook/${seg(id)}/test`, {}));
|
|
67
|
+
return { delivered: r.delivered === true, status: num(r.httpStatus), ms: num(r.durationMs), error: str(r.error) };
|
|
68
|
+
}
|
|
69
|
+
export async function deliveries(t, id, limit = 10) {
|
|
70
|
+
const raw = obj(await call(t, 'GET', `/v1/webhook/${seg(id)}/deliveries${query({ limit })}`));
|
|
71
|
+
return arr(raw.data)
|
|
72
|
+
.map(obj)
|
|
73
|
+
.map((a) => ({
|
|
74
|
+
subject: str(a.subject),
|
|
75
|
+
status: str(a.status),
|
|
76
|
+
code: num(a.httpStatus),
|
|
77
|
+
attempt: num(a.attempt),
|
|
78
|
+
error: str(a.error),
|
|
79
|
+
at: str(a.created),
|
|
80
|
+
}));
|
|
81
|
+
}
|
package/lib/ask.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare function Confirm({ open, onOpenChange, title, says, act, run, }: {
|
|
2
|
+
open: boolean;
|
|
3
|
+
onOpenChange: (o: boolean) => void;
|
|
4
|
+
title: string;
|
|
5
|
+
/** The whole consequence, stated plainly. */
|
|
6
|
+
says: string;
|
|
7
|
+
/** The button's word: Delete, Remove, Forget. */
|
|
8
|
+
act: string;
|
|
9
|
+
run: () => Promise<void>;
|
|
10
|
+
}): import("react").JSX.Element;
|
|
11
|
+
export declare function Rename({ open, onOpenChange, title, name, run, }: {
|
|
12
|
+
open: boolean;
|
|
13
|
+
onOpenChange: (o: boolean) => void;
|
|
14
|
+
title: string;
|
|
15
|
+
/** The name it has now. */
|
|
16
|
+
name: string;
|
|
17
|
+
run: (next: string) => Promise<void>;
|
|
18
|
+
}): import("react").JSX.Element;
|
package/lib/ask.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Asking one thing before an act: to confirm one that cannot be undone, or the
|
|
4
|
+
* new name for something. A refusal is said in the dialog, which stays open, so
|
|
5
|
+
* the reason is read where the act was asked for.
|
|
6
|
+
*/
|
|
7
|
+
import { SizableText, XStack } from '@hanzo/gui';
|
|
8
|
+
import { Button, Dialog, DialogContent, DialogTitle, Input } from '@hanzo/ui';
|
|
9
|
+
import { useEffect, useState } from 'react';
|
|
10
|
+
/** One act in flight, and what refused it. */
|
|
11
|
+
function useAct(onDone) {
|
|
12
|
+
const [working, setWorking] = useState(false);
|
|
13
|
+
const [note, setNote] = useState('');
|
|
14
|
+
const go = async (run) => {
|
|
15
|
+
setWorking(true);
|
|
16
|
+
setNote('');
|
|
17
|
+
try {
|
|
18
|
+
await run();
|
|
19
|
+
setWorking(false);
|
|
20
|
+
onDone();
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
setNote(e instanceof Error ? e.message : 'That did not work');
|
|
24
|
+
setWorking(false);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
return { working, note, setNote, go };
|
|
28
|
+
}
|
|
29
|
+
function Said({ note }) {
|
|
30
|
+
if (!note)
|
|
31
|
+
return null;
|
|
32
|
+
return (_jsx(SizableText, { size: "$1", color: "$soft", role: "status", children: note }));
|
|
33
|
+
}
|
|
34
|
+
export function Confirm({ open, onOpenChange, title, says, act, run, }) {
|
|
35
|
+
const { working, note, setNote, go } = useAct(() => onOpenChange(false));
|
|
36
|
+
const close = (o) => {
|
|
37
|
+
if (working)
|
|
38
|
+
return;
|
|
39
|
+
setNote('');
|
|
40
|
+
onOpenChange(o);
|
|
41
|
+
};
|
|
42
|
+
return (_jsx(Dialog, { open: open, onOpenChange: close, children: _jsxs(DialogContent, { maxW: 420, showCloseButton: false, children: [_jsx(DialogTitle, { children: title }), _jsx(SizableText, { size: "$2", color: "$soft", children: says }), _jsx(Said, { note: note }), _jsxs(XStack, { gap: "$2", justify: "flex-end", children: [_jsx(Button, { size: "sm", variant: "ghost", disabled: working, onPress: () => close(false), children: "Cancel" }), _jsx(Button, { size: "sm", variant: "destructive", disabled: working, onPress: () => void go(run), children: act })] })] }) }));
|
|
43
|
+
}
|
|
44
|
+
export function Rename({ open, onOpenChange, title, name, run, }) {
|
|
45
|
+
const [value, setValue] = useState(name);
|
|
46
|
+
const { working, note, setNote, go } = useAct(() => onOpenChange(false));
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
if (open)
|
|
49
|
+
setValue(name);
|
|
50
|
+
}, [open, name]);
|
|
51
|
+
const close = (o) => {
|
|
52
|
+
if (working)
|
|
53
|
+
return;
|
|
54
|
+
setNote('');
|
|
55
|
+
onOpenChange(o);
|
|
56
|
+
};
|
|
57
|
+
const save = () => {
|
|
58
|
+
const next = value.trim();
|
|
59
|
+
if (!next)
|
|
60
|
+
return setNote('It needs a name');
|
|
61
|
+
if (next === name)
|
|
62
|
+
return close(false);
|
|
63
|
+
void go(() => run(next));
|
|
64
|
+
};
|
|
65
|
+
return (_jsx(Dialog, { open: open, onOpenChange: close, children: _jsxs(DialogContent, { maxW: 420, showCloseButton: false, children: [_jsx(DialogTitle, { children: title }), _jsx(Input, { autoFocus: true, value: value, onChangeText: setValue, "aria-label": "Name", onKeyDown: (e) => {
|
|
66
|
+
if ((e.key ?? e.nativeEvent?.key) === 'Enter')
|
|
67
|
+
save();
|
|
68
|
+
} }), _jsx(Said, { note: note }), _jsxs(XStack, { gap: "$2", justify: "flex-end", children: [_jsx(Button, { size: "sm", variant: "ghost", disabled: working, onPress: () => close(false), children: "Cancel" }), _jsx(Button, { size: "sm", disabled: working, onPress: save, children: "Save" })] })] }) }));
|
|
69
|
+
}
|
package/lib/builder.js
CHANGED
|
@@ -11,12 +11,14 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
11
11
|
* /-/issues the forge's issues
|
|
12
12
|
* /-/artifacts what this org has built
|
|
13
13
|
* /-/templates the public starters
|
|
14
|
-
* /-/
|
|
14
|
+
* /-/customize skills, connectors, plugins and agents
|
|
15
15
|
* /<slug> a deployed project's workspace, in this same window
|
|
16
16
|
*
|
|
17
17
|
* The rail is the sessions rail every Hanzo surface shares: New, the builder's
|
|
18
|
-
* places, the org's coding runs newest first with a
|
|
19
|
-
*
|
|
18
|
+
* places with the rest under More, the org's coding runs newest first with a
|
|
19
|
+
* live status dot, and at the foot the offer of Hanzo in Slack and the account,
|
|
20
|
+
* whose menu opens Settings, Usage, the plans, help and logging out (foot.tsx).
|
|
21
|
+
* Its collapse is an explicit toggle kept per browser.
|
|
20
22
|
*
|
|
21
23
|
* A project's workspace takes the whole window — it has its own chat column,
|
|
22
24
|
* bar and panes — and its mark leads back here.
|
|
@@ -26,22 +28,27 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
26
28
|
* left column, never two.
|
|
27
29
|
*/
|
|
28
30
|
import { SizableText, XStack, YStack } from '@hanzo/gui';
|
|
29
|
-
import { Blocks, BookOpen, CircleDot, Cpu, FolderGit2, Kanban, LayoutTemplate, Menu,
|
|
31
|
+
import { Blocks, BookOpen, CircleDot, Cpu, FolderGit2, Kanban, LayoutTemplate, Menu, SlidersHorizontal, Workflow } from '@hanzogui/lucide-icons-2';
|
|
30
32
|
import { Button } from '@hanzo/ui';
|
|
31
33
|
import { SessionRail } from '@hanzo/ui/chat';
|
|
32
34
|
import { HanzoMark } from '@hanzo/ui/product';
|
|
33
|
-
import {
|
|
35
|
+
import { useMemo, useState } from 'react';
|
|
34
36
|
import { pinBoard } from './choice.js';
|
|
37
|
+
import { Customize } from './customize/index.js';
|
|
35
38
|
import { useKept, useRecents } from './data.js';
|
|
36
39
|
import { Forge } from './forge.js';
|
|
37
40
|
import { HostProvider, useHost, useTarget } from './host.js';
|
|
38
41
|
import { Landing } from './landing.js';
|
|
42
|
+
import { PrefsProvider } from './prefs.js';
|
|
39
43
|
import { Project } from './project.js';
|
|
44
|
+
import { Plans } from './plans.js';
|
|
40
45
|
import { path, route } from './route.js';
|
|
41
46
|
import { Run } from './run.js';
|
|
42
47
|
import { DOTS } from './section.js';
|
|
43
48
|
import { Artifacts, Templates } from './shelf.js';
|
|
44
|
-
import {
|
|
49
|
+
import { Find } from './find.js';
|
|
50
|
+
import { DOCS, Slack, Who } from './foot.js';
|
|
51
|
+
import { Settings } from './settings/index.js';
|
|
45
52
|
import { Where } from './switch.js';
|
|
46
53
|
function Shell() {
|
|
47
54
|
const host = useHost();
|
|
@@ -51,9 +58,9 @@ function Shell() {
|
|
|
51
58
|
const [collapsed, setCollapsed] = useKept('hanzo.build.rail', false);
|
|
52
59
|
const [drawer, setDrawer] = useState(false);
|
|
53
60
|
const [order, setOrder] = useState('newest');
|
|
54
|
-
const [account, setAccount] = useState(false);
|
|
55
61
|
const [finding, setFinding] = useState(false);
|
|
56
|
-
|
|
62
|
+
const [menu, setMenu] = useState(false);
|
|
63
|
+
const [slack, setSlack] = useKept('hanzo.build.slack', false);
|
|
57
64
|
const go = (p) => {
|
|
58
65
|
setDrawer(false);
|
|
59
66
|
host.go(p);
|
|
@@ -70,9 +77,13 @@ function Shell() {
|
|
|
70
77
|
const switcher = Boolean(host.person && (host.org || (host.memberships?.length ?? 0) > 0));
|
|
71
78
|
const top = switcher ? (_jsx(Where, {})) : (_jsx(XStack, { render: "button", "aria-label": "Hanzo", items: "center", onPress: () => go(''), children: _jsx(HanzoMark, { size: 18 }) }));
|
|
72
79
|
const links = [
|
|
80
|
+
{ id: 'projects', label: 'Projects', icon: _jsx(Kanban, { size: 16 }), onPress: () => go(path({ kind: 'screen', screen: 'projects' })), active: screen === 'projects' },
|
|
81
|
+
{ id: 'artifacts', label: 'Artifacts', icon: _jsx(Blocks, { size: 16 }), onPress: () => go(path({ kind: 'screen', screen: 'artifacts' })), active: screen === 'artifacts' },
|
|
82
|
+
{ id: 'customize', label: 'Customize', icon: _jsx(SlidersHorizontal, { size: 16 }), onPress: () => go(path({ kind: 'customize', tab: 'skills' })), active: r.kind === 'customize' || screen === 'mcp' },
|
|
73
83
|
{ id: 'automations', label: 'Automations', icon: _jsx(Workflow, { size: 16 }), onPress: () => go(path({ kind: 'screen', screen: 'automations' })), active: screen === 'automations' },
|
|
84
|
+
];
|
|
85
|
+
const more = [
|
|
74
86
|
{ id: 'codebases', label: 'Codebase', icon: _jsx(FolderGit2, { size: 16 }), onPress: () => go(path({ kind: 'screen', screen: 'codebases' })), active: screen === 'codebases' },
|
|
75
|
-
{ id: 'projects', label: 'Projects', icon: _jsx(Kanban, { size: 16 }), onPress: () => go(path({ kind: 'screen', screen: 'projects' })), active: screen === 'projects' },
|
|
76
87
|
{
|
|
77
88
|
id: 'issues',
|
|
78
89
|
label: 'Issues',
|
|
@@ -83,22 +94,25 @@ function Shell() {
|
|
|
83
94
|
},
|
|
84
95
|
active: screen === 'issues',
|
|
85
96
|
},
|
|
86
|
-
{ id: 'artifacts', label: 'Artifacts', icon: _jsx(Blocks, { size: 16 }), onPress: () => go(path({ kind: 'screen', screen: 'artifacts' })), active: screen === 'artifacts' },
|
|
87
|
-
{ id: 'mcp', label: 'MCP', icon: _jsx(Puzzle, { size: 16 }), onPress: () => go(path({ kind: 'screen', screen: 'mcp' })), active: screen === 'mcp' },
|
|
88
|
-
];
|
|
89
|
-
const more = [
|
|
90
97
|
{ id: 'templates', label: 'Templates', icon: _jsx(LayoutTemplate, { size: 16 }), onPress: () => go(path({ kind: 'screen', screen: 'templates' })), active: screen === 'templates' },
|
|
91
98
|
{
|
|
92
99
|
id: 'machines',
|
|
93
100
|
label: 'Machines',
|
|
94
101
|
icon: _jsx(Cpu, { size: 16 }),
|
|
95
|
-
onPress: () =>
|
|
102
|
+
onPress: () => go(path({ kind: 'settings', section: 'machines' })),
|
|
103
|
+
active: r.kind === 'settings' && r.section === 'machines',
|
|
96
104
|
},
|
|
97
|
-
{ id: 'docs', label: 'Docs', icon: _jsx(BookOpen, { size: 16 }), onPress: () => window.open(
|
|
105
|
+
{ id: 'docs', label: 'Docs', icon: _jsx(BookOpen, { size: 16 }), onPress: () => window.open(DOCS, '_blank', 'noopener,noreferrer') },
|
|
98
106
|
];
|
|
99
|
-
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.' }), account: host.person
|
|
100
|
-
? {
|
|
101
|
-
|
|
107
|
+
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
|
|
108
|
+
? {
|
|
109
|
+
name: host.person.email || host.person.name,
|
|
110
|
+
onPress: () => {
|
|
111
|
+
setDrawer(false);
|
|
112
|
+
setMenu(true);
|
|
113
|
+
},
|
|
114
|
+
}
|
|
115
|
+
: { name: 'Sign in', onPress: () => host.signIn?.() }, onSettings: () => go(path({ kind: 'settings', section: 'general' })), onSearch: () => setFinding(true), collapsed: collapsed, onCollapse: setCollapsed, mark: _jsx(Brand, { org: host.org }), pt: collapsed ? undefined : switcher ? 80 : 40, open: drawer, onOpenChange: setDrawer, label: "Runs" }), collapsed ? null : (_jsx(XStack, { position: "absolute", t: 8, l: 8, r: 8, z: 2, items: "center", "$max-md": { display: 'none' }, children: top })), 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 }) }), top] }), _jsx(Pane, { onStarted: () => recents.reload() })] }), _jsx(Find, { open: finding, onOpenChange: setFinding, recents: rows, onOpen: (id) => { setFinding(false); go(id); } })] }));
|
|
102
116
|
}
|
|
103
117
|
/** Whichever pane the address names, beside a rail — the builder's or the host's. */
|
|
104
118
|
function Pane({ onStarted }) {
|
|
@@ -106,11 +120,17 @@ function Pane({ onStarted }) {
|
|
|
106
120
|
const r = route(host.path);
|
|
107
121
|
if (r.kind === 'run')
|
|
108
122
|
return _jsx(Run, { id: r.id }, r.id);
|
|
123
|
+
if (r.kind === 'settings')
|
|
124
|
+
return _jsx(Settings, { section: r.section });
|
|
125
|
+
if (r.kind === 'customize')
|
|
126
|
+
return _jsx(Customize, { tab: r.tab });
|
|
109
127
|
if (r.kind === 'screen') {
|
|
110
128
|
if (r.screen === 'artifacts')
|
|
111
129
|
return _jsx(Artifacts, {});
|
|
112
130
|
if (r.screen === 'templates')
|
|
113
131
|
return _jsx(Templates, {});
|
|
132
|
+
if (r.screen === 'plans')
|
|
133
|
+
return _jsx(Plans, {});
|
|
114
134
|
return _jsx(Forge, { screen: r.screen }, r.screen);
|
|
115
135
|
}
|
|
116
136
|
return (_jsx(Landing, { onStarted: (id) => {
|
|
@@ -139,5 +159,5 @@ function Screens({ rail }) {
|
|
|
139
159
|
* places and runs in its own rail with `DevSection`.
|
|
140
160
|
*/
|
|
141
161
|
export function Builder({ host, rail = true }) {
|
|
142
|
-
return (_jsx(HostProvider, { host: host, children: _jsx(YStack, { flex: 1, minH: 0, minW: 0, height: "100%", bg: "$background", children: _jsx(Screens, { rail: rail }) }) }));
|
|
162
|
+
return (_jsx(HostProvider, { host: host, children: _jsx(PrefsProvider, { children: _jsx(YStack, { flex: 1, minH: 0, minW: 0, height: "100%", bg: "$background", children: _jsx(Screens, { rail: rail }) }) }) }));
|
|
143
163
|
}
|