@hanzo/build 0.2.80 → 0.2.82
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/lib/activity.d.ts +3 -7
- package/lib/activity.js +18 -5
- package/lib/api/agents.d.ts +1 -20
- package/lib/api/agents.js +16 -8
- package/lib/api/auto.d.ts +3 -23
- package/lib/api/auto.js +39 -22
- package/lib/api/billing.d.ts +0 -35
- package/lib/api/billing.js +6 -5
- package/lib/api/call.d.ts +16 -8
- package/lib/api/call.js +32 -1
- package/lib/api/capabilities.d.ts +0 -11
- package/lib/api/capabilities.js +2 -1
- package/lib/api/codebases.d.ts +0 -10
- package/lib/api/codebases.js +3 -2
- package/lib/api/coding.d.ts +3 -32
- package/lib/api/coding.js +13 -7
- package/lib/api/connectors.d.ts +1 -17
- package/lib/api/connectors.js +5 -4
- package/lib/api/environment.d.ts +6 -20
- package/lib/api/environment.js +22 -19
- package/lib/api/github.d.ts +0 -22
- package/lib/api/github.js +3 -2
- package/lib/api/keys.d.ts +0 -14
- package/lib/api/keys.js +4 -3
- package/lib/api/library.d.ts +3 -17
- package/lib/api/library.js +23 -22
- package/lib/api/links.d.ts +1 -1
- package/lib/api/links.js +1 -1
- package/lib/api/machines.d.ts +0 -15
- package/lib/api/machines.js +6 -5
- package/lib/api/mcp.d.ts +0 -9
- package/lib/api/mcp.js +3 -2
- package/lib/api/members.d.ts +0 -15
- package/lib/api/members.js +4 -3
- package/lib/api/memory.d.ts +0 -11
- package/lib/api/memory.js +2 -1
- package/lib/api/places.d.ts +1 -9
- package/lib/api/places.js +12 -1
- package/lib/api/plugins.d.ts +1 -16
- package/lib/api/plugins.js +4 -3
- package/lib/api/profile.d.ts +0 -10
- package/lib/api/profile.js +5 -4
- package/lib/api/projects.d.ts +0 -14
- package/lib/api/projects.js +11 -10
- package/lib/api/provider.d.ts +2 -14
- package/lib/api/provider.js +12 -10
- package/lib/api/sandbox.d.ts +0 -17
- package/lib/api/sandbox.js +5 -4
- package/lib/api/sessions.d.ts +0 -17
- package/lib/api/sessions.js +5 -4
- package/lib/api/skills.d.ts +1 -15
- package/lib/api/skills.js +5 -4
- package/lib/api/studio.d.ts +0 -14
- package/lib/api/studio.js +6 -5
- package/lib/api/turn.d.ts +6 -28
- package/lib/api/turn.js +105 -49
- package/lib/api/verdict.d.ts +0 -9
- package/lib/api/verdict.js +2 -1
- package/lib/api/webhooks.d.ts +1 -14
- package/lib/api/webhooks.js +5 -4
- package/lib/ask.js +7 -4
- package/lib/automations.d.ts +5 -4
- package/lib/automations.js +95 -74
- package/lib/back.js +10 -4
- package/lib/builder.js +7 -5
- package/lib/carry.js +20 -16
- package/lib/customize/agents.js +78 -31
- package/lib/customize/connectors.js +62 -48
- package/lib/customize/index.js +43 -10
- package/lib/customize/plugins.js +34 -22
- package/lib/customize/say.d.ts +13 -1
- package/lib/customize/say.js +15 -21
- package/lib/customize/skills.js +31 -22
- package/lib/customize/ui.d.ts +5 -9
- package/lib/customize/ui.js +26 -16
- package/lib/data.d.ts +1 -1
- package/lib/data.js +3 -2
- package/lib/desk.js +45 -33
- package/lib/door.js +35 -10
- package/lib/environment.js +25 -19
- package/lib/files.js +43 -34
- package/lib/find.js +12 -9
- package/lib/foot.js +7 -4
- package/lib/forge.js +61 -40
- package/lib/gear.d.ts +2 -1
- package/lib/gear.js +6 -4
- package/lib/git.js +29 -19
- package/lib/landing.d.ts +5 -5
- package/lib/landing.js +52 -44
- package/lib/library.js +73 -51
- package/lib/merge.d.ts +2 -2
- package/lib/meter.d.ts +1 -1
- package/lib/meter.js +14 -5
- package/lib/mic.js +12 -5
- package/lib/mind.d.ts +1 -0
- package/lib/mind.js +5 -3
- package/lib/nav.d.ts +6 -5
- package/lib/nav.js +37 -30
- package/lib/panel.d.ts +2 -1
- package/lib/panel.js +52 -36
- package/lib/plan.d.ts +4 -20
- package/lib/plan.js +26 -10
- package/lib/plans.js +49 -30
- package/lib/plugins/design.js +3 -2
- package/lib/plugins/index.d.ts +23 -4
- package/lib/plugins/index.js +11 -26
- package/lib/plugins/pdf.js +2 -1
- package/lib/plugins/project.js +7 -4
- package/lib/plugins/research.js +3 -2
- package/lib/plugins/sketch.js +6 -3
- package/lib/plugins/slides.js +3 -2
- package/lib/plugins/template.js +6 -3
- package/lib/plus.js +25 -13
- package/lib/prefs.d.ts +0 -14
- package/lib/prefs.js +2 -1
- package/lib/project.js +69 -62
- package/lib/prompt.d.ts +12 -11
- package/lib/prompt.js +38 -20
- package/lib/publish.js +17 -12
- package/lib/reply.js +6 -3
- package/lib/run.js +72 -54
- package/lib/say.d.ts +2 -0
- package/lib/say.js +7 -0
- package/lib/scheduled.js +54 -43
- package/lib/section.d.ts +1 -0
- package/lib/section.js +8 -2
- package/lib/settings/account.d.ts +1 -0
- package/lib/settings/account.js +31 -21
- package/lib/settings/billing.js +55 -28
- package/lib/settings/capabilities.js +26 -15
- package/lib/settings/card.js +19 -12
- package/lib/settings/code.js +22 -11
- package/lib/settings/credits.d.ts +4 -4
- package/lib/settings/credits.js +34 -21
- package/lib/settings/environments.js +21 -14
- package/lib/settings/general.js +26 -14
- package/lib/settings/index.js +6 -3
- package/lib/settings/integrations.js +42 -28
- package/lib/settings/keys.js +37 -19
- package/lib/settings/list.d.ts +0 -5
- package/lib/settings/list.js +24 -15
- package/lib/settings/machines.d.ts +3 -0
- package/lib/settings/machines.js +63 -38
- package/lib/settings/members.js +23 -14
- package/lib/settings/memory.js +12 -6
- package/lib/settings/notifications.js +32 -19
- package/lib/settings/plan.d.ts +1 -1
- package/lib/settings/plan.js +40 -17
- package/lib/settings/privacy.js +26 -13
- package/lib/settings/ui.d.ts +3 -2
- package/lib/settings/ui.js +9 -3
- package/lib/settings/usage.js +7 -3
- package/lib/shelf.js +20 -17
- package/lib/side.d.ts +1 -26
- package/lib/side.js +11 -5
- package/lib/standing.d.ts +2 -10
- package/lib/standing.js +5 -3
- package/lib/suggest.d.ts +8 -28
- package/lib/suggest.js +39 -4
- package/lib/suggestions.js +14 -5
- package/lib/summary.d.ts +1 -1
- package/lib/summary.js +4 -1
- package/lib/sync.js +22 -12
- package/lib/tools.d.ts +4 -3
- package/lib/tools.js +10 -7
- package/lib/transcript.js +10 -8
- package/package.json +4 -2
package/lib/api/members.js
CHANGED
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
* An invitation is a code IAM redeems when someone signs up with it; IAM sends
|
|
14
14
|
* no email of its own.
|
|
15
15
|
*/
|
|
16
|
-
import {
|
|
16
|
+
import { phrase } from '@hanzo/i18n';
|
|
17
|
+
import { call, query, seg, Sentence } from './call.js';
|
|
17
18
|
const str = (v) => (typeof v === 'string' ? v : '');
|
|
18
19
|
const num = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : 0);
|
|
19
20
|
const obj = (v) => (v && typeof v === 'object' ? v : {});
|
|
@@ -34,7 +35,7 @@ export function member(raw) {
|
|
|
34
35
|
export async function roster(t, org) {
|
|
35
36
|
const raw = obj(await call(t, 'GET', `/v1/iam/memberships${query({ org })}`));
|
|
36
37
|
if (raw.status === 'error')
|
|
37
|
-
throw new Error(str(raw.msg) || 'IAM refused the roster');
|
|
38
|
+
throw new Error(str(raw.msg) || phrase('IAM refused the roster'));
|
|
38
39
|
const rank = (r) => ROLES.indexOf(r);
|
|
39
40
|
return arr(raw.data)
|
|
40
41
|
.map(obj)
|
|
@@ -71,7 +72,7 @@ function hex(bytes) {
|
|
|
71
72
|
export async function invite(t, org, email) {
|
|
72
73
|
const address = email.trim().toLowerCase();
|
|
73
74
|
if (!EMAIL.test(address))
|
|
74
|
-
throw new
|
|
75
|
+
throw email.trim() ? new Sentence(phrase('{email} is not an email address'), { email: email.trim() }) : new Error(phrase('That is not an email address'));
|
|
75
76
|
const local = address.slice(0, address.indexOf('@')).replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 24);
|
|
76
77
|
return invitation(await call(t, 'POST', '/v1/iam/invitations', {
|
|
77
78
|
owner: org,
|
package/lib/api/memory.d.ts
CHANGED
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* What Hanzo remembers about the signed-in person, in the org they act in.
|
|
3
|
-
*
|
|
4
|
-
* GET /v1/ai/memory/list?limit= {status, data: [memory]}, newest first
|
|
5
|
-
* POST /v1/ai/memory/remember {content} → {status, data: memory}
|
|
6
|
-
* POST /v1/ai/memory/delete {id: "<owner>/<name>"}
|
|
7
|
-
*
|
|
8
|
-
* The platform keys every memory on the validated caller and org, never on the
|
|
9
|
-
* request, so these read and change the caller's own and nobody else's. A
|
|
10
|
-
* refusal arrives in the envelope, usually under a 200.
|
|
11
|
-
*/
|
|
12
1
|
import { type Target } from './call.ts';
|
|
13
2
|
export interface Memory {
|
|
14
3
|
/** `<owner>/<name>`, what a delete names. */
|
package/lib/api/memory.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* request, so these read and change the caller's own and nobody else's. A
|
|
10
10
|
* refusal arrives in the envelope, usually under a 200.
|
|
11
11
|
*/
|
|
12
|
+
import { phrase } from '@hanzo/i18n';
|
|
12
13
|
import { call, query, unwrap } from './call.js';
|
|
13
14
|
const str = (v) => (typeof v === 'string' ? v : '');
|
|
14
15
|
export function memoryOf(raw) {
|
|
@@ -26,7 +27,7 @@ export async function memories(t, limit = 100) {
|
|
|
26
27
|
export async function remember(t, content) {
|
|
27
28
|
const said = content.trim();
|
|
28
29
|
if (!said)
|
|
29
|
-
throw new Error('Say what Hanzo should remember');
|
|
30
|
+
throw new Error(phrase('Say what Hanzo should remember'));
|
|
30
31
|
return memoryOf(unwrap(await call(t, 'POST', '/v1/ai/memory/remember', { content: said })));
|
|
31
32
|
}
|
|
32
33
|
export async function forget(t, id) {
|
package/lib/api/places.d.ts
CHANGED
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Where a run can run: the platform's sandbox, or one of the org's machines.
|
|
3
|
-
*
|
|
4
|
-
* GET /v1/agent/targets → {targets: [...]}, newest first (machines.ts)
|
|
5
|
-
*
|
|
6
|
-
* The sandbox is not a row the platform lists — it is what a run gets when it
|
|
7
|
-
* names no target — so it is the first place here and carries no id. A machine
|
|
8
|
-
* can take a run only while it is online.
|
|
9
|
-
*/
|
|
10
1
|
import type { Target } from './call.ts';
|
|
11
2
|
export interface Place {
|
|
12
3
|
/** `tgt_…`, or '' for the sandbox. */
|
|
@@ -19,6 +10,7 @@ export interface Place {
|
|
|
19
10
|
/** "10 vCPU / 122G / 1× GB10", when the machine reported one. */
|
|
20
11
|
capacity: string;
|
|
21
12
|
}
|
|
13
|
+
/** The sandbox, named in English and marked (`phrase`): a screen draws its label through `t`. */
|
|
22
14
|
export declare const SANDBOX: Place;
|
|
23
15
|
export declare function places(t: Target): Promise<Place[]>;
|
|
24
16
|
/** Whether a run sent here now would be taken. */
|
package/lib/api/places.js
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a run can run: the platform's sandbox, or one of the org's machines.
|
|
3
|
+
*
|
|
4
|
+
* GET /v1/agent/targets → {targets: [...]}, newest first (machines.ts)
|
|
5
|
+
*
|
|
6
|
+
* The sandbox is not a row the platform lists — it is what a run gets when it
|
|
7
|
+
* names no target — so it is the first place here and carries no id. A machine
|
|
8
|
+
* can take a run only while it is online.
|
|
9
|
+
*/
|
|
10
|
+
import { phrase } from '@hanzo/i18n';
|
|
1
11
|
import { machines, state } from './machines.js';
|
|
2
|
-
|
|
12
|
+
/** The sandbox, named in English and marked (`phrase`): a screen draws its label through `t`. */
|
|
13
|
+
export const SANDBOX = { id: '', label: phrase('Hanzo sandbox'), kind: 'sandbox', status: 'online', capacity: '' };
|
|
3
14
|
export async function places(t) {
|
|
4
15
|
const list = await machines(t);
|
|
5
16
|
return [SANDBOX, ...list.map((m) => ({ id: m.id, label: m.label, kind: m.kind, status: state(m), capacity: m.capacity }))];
|
package/lib/api/plugins.d.ts
CHANGED
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plugins: TypeScript connectors an org builds, and what this deployment mounts.
|
|
3
|
-
*
|
|
4
|
-
* GET /v1/tool/plugins/authored {plugins: [plugin]}, newest first, each with its source
|
|
5
|
-
* POST /v1/tool/plugins/build {name, provider?, source | spec} → 201 {bytes, generated, plugin}
|
|
6
|
-
* DELETE /v1/tool/plugins/authored/{id} {deleted}
|
|
7
|
-
* GET /v1/tool/plugins {plugins: [{name, enabled, prefixes}]}
|
|
8
|
-
*
|
|
9
|
-
* Building is the gate: the platform bundles the source and compiles it in the
|
|
10
|
-
* runtime that will run it, and keeps it only if both succeed — a failure is a
|
|
11
|
-
* 422 whose reason is the bundler's. A spec (an OpenAPI document or prose) has a
|
|
12
|
-
* model write the source, which comes back to be read. A plugin never carries a
|
|
13
|
-
* credential: it names the connectors provider whose credential it reads when it
|
|
14
|
-
* runs. The mounted list is the deployment's own subsystems, read-only.
|
|
15
|
-
*/
|
|
16
1
|
import { type Target } from './call.ts';
|
|
17
2
|
export interface Plugin {
|
|
18
3
|
/** What a delete addresses. */
|
|
@@ -49,7 +34,7 @@ export interface Build {
|
|
|
49
34
|
source: string;
|
|
50
35
|
spec: string;
|
|
51
36
|
}
|
|
52
|
-
/** Why a plugin cannot be built as it stands, or '' when it can. */
|
|
37
|
+
/** Why a plugin cannot be built as it stands, or '' when it can. English, marked (`phrase`): a screen says it through `t`. */
|
|
53
38
|
export declare function refuse(b: Build): string;
|
|
54
39
|
export declare function build(t: Target, b: Build): Promise<Built>;
|
|
55
40
|
export declare function remove(t: Target, id: string): Promise<void>;
|
package/lib/api/plugins.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* credential: it names the connectors provider whose credential it reads when it
|
|
14
14
|
* runs. The mounted list is the deployment's own subsystems, read-only.
|
|
15
15
|
*/
|
|
16
|
+
import { phrase } from '@hanzo/i18n';
|
|
16
17
|
import { call, seg } from './call.js';
|
|
17
18
|
/** A plugin's name: one lowercase path segment, the id it runs by. */
|
|
18
19
|
export const NAME = /^[a-z0-9][a-z0-9_-]{0,63}$/;
|
|
@@ -35,12 +36,12 @@ export async function mounted(t) {
|
|
|
35
36
|
})
|
|
36
37
|
.filter((m) => m.name);
|
|
37
38
|
}
|
|
38
|
-
/** Why a plugin cannot be built as it stands, or '' when it can. */
|
|
39
|
+
/** Why a plugin cannot be built as it stands, or '' when it can. English, marked (`phrase`): a screen says it through `t`. */
|
|
39
40
|
export function refuse(b) {
|
|
40
41
|
if (!NAME.test(b.name))
|
|
41
|
-
return 'A name is one lowercase word: letters, digits, _ or -';
|
|
42
|
+
return phrase('A name is one lowercase word: letters, digits, _ or -');
|
|
42
43
|
if (!b.source.trim() === !b.spec.trim())
|
|
43
|
-
return 'Give the TypeScript or the API it calls, one of the two';
|
|
44
|
+
return phrase('Give the TypeScript or the API it calls, one of the two');
|
|
44
45
|
return '';
|
|
45
46
|
}
|
|
46
47
|
export async function build(t, b) {
|
package/lib/api/profile.d.ts
CHANGED
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The signed-in person's own profile on Hanzo IAM: the name they are shown by
|
|
3
|
-
* and their photo.
|
|
4
|
-
*
|
|
5
|
-
* PUT /v1/iam/account {displayName} → {status, data: {owner, name, displayName, avatar, …}}
|
|
6
|
-
* POST /v1/account/avatar multipart `file` → {avatar} the photo, also written to IAM
|
|
7
|
-
*
|
|
8
|
-
* Both act on the caller alone: neither request names a person. The email is a
|
|
9
|
-
* sign-in identifier and changes only through IAM's verification, never here.
|
|
10
|
-
*/
|
|
11
1
|
import { type Target } from './call.ts';
|
|
12
2
|
export interface Profile {
|
|
13
3
|
displayName: string;
|
package/lib/api/profile.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* Both act on the caller alone: neither request names a person. The email is a
|
|
9
9
|
* sign-in identifier and changes only through IAM's verification, never here.
|
|
10
10
|
*/
|
|
11
|
+
import { phrase } from '@hanzo/i18n';
|
|
11
12
|
import { call, headers, reason, Refusal, unwrap } from './call.js';
|
|
12
13
|
const str = (v) => (typeof v === 'string' ? v : '');
|
|
13
14
|
const obj = (v) => (v && typeof v === 'object' ? v : {});
|
|
@@ -15,7 +16,7 @@ const obj = (v) => (v && typeof v === 'object' ? v : {});
|
|
|
15
16
|
export async function rename(t, name) {
|
|
16
17
|
const displayName = name.trim();
|
|
17
18
|
if (!displayName)
|
|
18
|
-
throw new Error('A name cannot be empty');
|
|
19
|
+
throw new Error(phrase('A name cannot be empty'));
|
|
19
20
|
const p = obj(unwrap(await call(t, 'PUT', '/v1/iam/account', { displayName })));
|
|
20
21
|
return { displayName: str(p.displayName), avatar: str(p.avatar) };
|
|
21
22
|
}
|
|
@@ -25,9 +26,9 @@ const LIMIT = 8 << 20;
|
|
|
25
26
|
/** Store a new photo and answer its address. */
|
|
26
27
|
export async function photo(t, file) {
|
|
27
28
|
if (!file.size)
|
|
28
|
-
throw new Error('That file is empty');
|
|
29
|
+
throw new Error(phrase('That file is empty'));
|
|
29
30
|
if (file.size > LIMIT)
|
|
30
|
-
throw new Error('A photo is at most 8 MB');
|
|
31
|
+
throw new Error(phrase('A photo is at most 8 MB'));
|
|
31
32
|
const form = new FormData();
|
|
32
33
|
form.append('file', file);
|
|
33
34
|
const res = await fetch(`${t.api}/v1/account/avatar`, { method: 'POST', headers: headers(t), body: form, cache: 'no-store' });
|
|
@@ -35,6 +36,6 @@ export async function photo(t, file) {
|
|
|
35
36
|
throw new Refusal(res.status, (await reason(res)) || `POST /v1/account/avatar answered ${res.status}`);
|
|
36
37
|
const url = str(obj(await res.json()).avatar);
|
|
37
38
|
if (!url.startsWith('https://'))
|
|
38
|
-
throw new Refusal(502, 'The photo was stored without an address this page can show');
|
|
39
|
+
throw new Refusal(502, phrase('The photo was stored without an address this page can show'));
|
|
39
40
|
return url;
|
|
40
41
|
}
|
package/lib/api/projects.d.ts
CHANGED
|
@@ -1,17 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The org's projects: what it has built, and where each one is served.
|
|
3
|
-
*
|
|
4
|
-
* GET /v1/projects → Project[]
|
|
5
|
-
* PATCH /v1/projects/{slug} rename it, or make it public or private
|
|
6
|
-
* DELETE /v1/projects/{slug} delete it and take its site down
|
|
7
|
-
* GET /v1/projects/{slug}/deployments → Deployment[], newest first
|
|
8
|
-
*
|
|
9
|
-
* `slug` is the one key every surface shares — the address under /dev, the
|
|
10
|
-
* site's name, the `project` a run is tagged with. A project belongs to the org,
|
|
11
|
-
* not to a person: the record names no author, so any member lists, changes and
|
|
12
|
-
* deletes it. Private is paid, and an unfunded org is refused rather than left
|
|
13
|
-
* public without being told.
|
|
14
|
-
*/
|
|
15
1
|
import { type Target } from './call.ts';
|
|
16
2
|
export interface Project {
|
|
17
3
|
slug: string;
|
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,
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* deletes it. Private is paid, and an unfunded org is refused rather than left
|
|
13
13
|
* public without being told.
|
|
14
14
|
*/
|
|
15
|
+
import { phrase } from '@hanzo/i18n';
|
|
15
16
|
import { call, seg } from './call.js';
|
|
16
17
|
const str = (v) => (typeof v === 'string' ? v : '');
|
|
17
18
|
const num = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : 0);
|
|
@@ -51,7 +52,7 @@ export function project(raw) {
|
|
|
51
52
|
};
|
|
52
53
|
}
|
|
53
54
|
export async function projects(t) {
|
|
54
|
-
const raw = await call(t, 'GET', '/v1/
|
|
55
|
+
const raw = await call(t, 'GET', '/v1/project');
|
|
55
56
|
const rows = Array.isArray(raw) ? raw : Array.isArray(raw?.data) ? raw.data : [];
|
|
56
57
|
return rows
|
|
57
58
|
.map(project)
|
|
@@ -64,16 +65,16 @@ export async function change(t, slug, what) {
|
|
|
64
65
|
if (what.name !== undefined) {
|
|
65
66
|
const n = what.name.trim();
|
|
66
67
|
if (!n)
|
|
67
|
-
throw new Error('A project needs a name');
|
|
68
|
+
throw new Error(phrase('A project needs a name'));
|
|
68
69
|
body.name = n;
|
|
69
70
|
}
|
|
70
71
|
if (what.visibility !== undefined)
|
|
71
72
|
body.visibility = what.visibility;
|
|
72
|
-
return project(await call(t, 'PATCH', `/v1/
|
|
73
|
+
return project(await call(t, 'PATCH', `/v1/project/${seg(slug)}`, body));
|
|
73
74
|
}
|
|
74
75
|
/** Delete a project. Its site stops answering and its slug is free again. */
|
|
75
76
|
export async function remove(t, slug) {
|
|
76
|
-
await call(t, 'DELETE', `/v1/
|
|
77
|
+
await call(t, 'DELETE', `/v1/project/${seg(slug)}`);
|
|
77
78
|
}
|
|
78
79
|
export function deployment(raw) {
|
|
79
80
|
const d = (raw && typeof raw === 'object' ? raw : {});
|
|
@@ -89,7 +90,7 @@ export function deployment(raw) {
|
|
|
89
90
|
}
|
|
90
91
|
/** A project's deployments, newest first: the first says how its latest build went. */
|
|
91
92
|
export async function deployments(t, slug) {
|
|
92
|
-
const raw = await call(t, 'GET', `/v1/
|
|
93
|
+
const raw = await call(t, 'GET', `/v1/project/${seg(slug)}/deployments`);
|
|
93
94
|
return (Array.isArray(raw) ? raw : [])
|
|
94
95
|
.map(deployment)
|
|
95
96
|
.filter((d) => d.id)
|
|
@@ -126,7 +127,7 @@ export async function templates(t) {
|
|
|
126
127
|
* once, and answers `building` until it is `live` or its build failed.
|
|
127
128
|
*/
|
|
128
129
|
export async function fork(t, slug) {
|
|
129
|
-
return project(await call(t, 'POST', '/v1/
|
|
130
|
+
return project(await call(t, 'POST', '/v1/project/fork', { slug }));
|
|
130
131
|
}
|
|
131
132
|
/** `owner/name` from a clone URL — its last two path segments, without `.git`. */
|
|
132
133
|
export function address(clone) {
|
package/lib/api/provider.d.ts
CHANGED
|
@@ -1,16 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The organization's connectors: a Slack workspace, the GitHub accounts the
|
|
3
|
-
* platform's GitHub App is installed on, and the social accounts automations
|
|
4
|
-
* post to.
|
|
5
|
-
*
|
|
6
|
-
* GET /v1/provider/{id} one connector and this org's connection to it
|
|
7
|
-
* POST /v1/provider/{id}/connect {return} → {authorizeUrl}: the provider's own consent page (org admin)
|
|
8
|
-
* POST /v1/provider/{id}/disconnect forget the org's connection (org admin)
|
|
9
|
-
* GET /v1/provider/slack/channels the connected workspace's channels, a page at a time
|
|
10
|
-
*
|
|
11
|
-
* Connecting leaves this page once, for the provider's consent screen, and only
|
|
12
|
-
* for that provider's own host.
|
|
13
|
-
*/
|
|
14
1
|
import { type Target } from './call.ts';
|
|
15
2
|
export interface Connector {
|
|
16
3
|
id: string;
|
|
@@ -30,7 +17,8 @@ export declare function read(t: Target, id: string): Promise<Connector>;
|
|
|
30
17
|
* The social accounts an organization connects. An automation posts text to
|
|
31
18
|
* the ones that take it; Instagram and TikTok take only images and video, and
|
|
32
19
|
* say so. `needs` is what connecting waits on while Hanzo's app with the
|
|
33
|
-
* platform is not set up.
|
|
20
|
+
* platform is not set up. Its sentences are English and marked (`phrase`):
|
|
21
|
+
* a screen draws them through `t`.
|
|
34
22
|
*/
|
|
35
23
|
export declare const SOCIAL: readonly {
|
|
36
24
|
id: string;
|
package/lib/api/provider.js
CHANGED
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
* Connecting leaves this page once, for the provider's consent screen, and only
|
|
12
12
|
* for that provider's own host.
|
|
13
13
|
*/
|
|
14
|
-
import {
|
|
14
|
+
import { phrase } from '@hanzo/i18n';
|
|
15
|
+
import { call, query, seg, Sentence } from './call.js';
|
|
15
16
|
const str = (v) => (typeof v === 'string' ? v : '');
|
|
16
17
|
const obj = (v) => (v && typeof v === 'object' ? v : {});
|
|
17
18
|
const arr = (v) => (Array.isArray(v) ? v : []);
|
|
@@ -45,25 +46,26 @@ const CONSENT = {
|
|
|
45
46
|
* The social accounts an organization connects. An automation posts text to
|
|
46
47
|
* the ones that take it; Instagram and TikTok take only images and video, and
|
|
47
48
|
* say so. `needs` is what connecting waits on while Hanzo's app with the
|
|
48
|
-
* platform is not set up.
|
|
49
|
+
* platform is not set up. Its sentences are English and marked (`phrase`):
|
|
50
|
+
* a screen draws them through `t`.
|
|
49
51
|
*/
|
|
50
52
|
export const SOCIAL = [
|
|
51
|
-
{ id: 'x', name: 'X', posts: true, needs: 'X posting needs Hanzo’s X developer app with paid API access; it is not set up yet.' },
|
|
52
|
-
{ id: 'linkedin', name: 'LinkedIn', posts: true, needs: 'LinkedIn posting needs Hanzo’s LinkedIn app with Share on LinkedIn; it is not set up yet.' },
|
|
53
|
-
{ id: 'facebook', name: 'Facebook', posts: true, needs: 'Facebook Page posting needs Hanzo’s Meta app, approved by Meta App Review to publish to Pages; it is not set up yet.' },
|
|
53
|
+
{ id: 'x', name: 'X', posts: true, needs: phrase('X posting needs Hanzo’s X developer app with paid API access; it is not set up yet.') },
|
|
54
|
+
{ id: 'linkedin', name: 'LinkedIn', posts: true, needs: phrase('LinkedIn posting needs Hanzo’s LinkedIn app with Share on LinkedIn; it is not set up yet.') },
|
|
55
|
+
{ id: 'facebook', name: 'Facebook', posts: true, needs: phrase('Facebook Page posting needs Hanzo’s Meta app, approved by Meta App Review to publish to Pages; it is not set up yet.') },
|
|
54
56
|
{
|
|
55
57
|
id: 'instagram',
|
|
56
58
|
name: 'Instagram',
|
|
57
59
|
posts: false,
|
|
58
|
-
needs: 'Instagram posting needs Hanzo’s Meta app, approved by Meta App Review; it is not set up yet.',
|
|
59
|
-
takes: 'Instagram takes photos and reels, not text, so automations do not post to it.',
|
|
60
|
+
needs: phrase('Instagram posting needs Hanzo’s Meta app, approved by Meta App Review; it is not set up yet.'),
|
|
61
|
+
takes: phrase('Instagram takes photos and reels, not text, so automations do not post to it.'),
|
|
60
62
|
},
|
|
61
63
|
{
|
|
62
64
|
id: 'tiktok',
|
|
63
65
|
name: 'TikTok',
|
|
64
66
|
posts: false,
|
|
65
|
-
needs: 'TikTok posting needs TikTok’s audit of Hanzo’s app; it is not set up yet.',
|
|
66
|
-
takes: 'TikTok takes videos and photos, not text, so automations do not post to it.',
|
|
67
|
+
needs: phrase('TikTok posting needs TikTok’s audit of Hanzo’s app; it is not set up yet.'),
|
|
68
|
+
takes: phrase('TikTok takes videos and photos, not text, so automations do not post to it.'),
|
|
67
69
|
},
|
|
68
70
|
];
|
|
69
71
|
/** The provider's consent page for this org; its return lands on `back` when that is a Hanzo app page. */
|
|
@@ -71,7 +73,7 @@ export async function authorize(t, id, back) {
|
|
|
71
73
|
const url = str(obj(await call(t, 'POST', `/v1/provider/${seg(id)}/connect`, back ? { return: back } : {})).authorizeUrl);
|
|
72
74
|
const host = CONSENT[id];
|
|
73
75
|
if (!host || !host.test(url))
|
|
74
|
-
throw new
|
|
76
|
+
throw new Sentence(phrase('The platform did not name a {provider} address to connect at'), { provider: id });
|
|
75
77
|
return url;
|
|
76
78
|
}
|
|
77
79
|
export async function disconnect(t, id) {
|
package/lib/api/sandbox.d.ts
CHANGED
|
@@ -1,20 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A run's sandbox. It outlives the run: kept after the run ends, parked (its pod
|
|
3
|
-
* stopped, its disk and working tree kept) while nobody watches, and retired a
|
|
4
|
-
* day after it parks; a free plan's sandbox is not parked, and ends within the
|
|
5
|
-
* hour. Resume gives a parked one a pod again under the same id and tree.
|
|
6
|
-
*
|
|
7
|
-
* GET /v1/sandbox/{id} its status and when its lease ends
|
|
8
|
-
* POST /v1/sandbox/{id}/pause park it: stop the pod, keep the disk
|
|
9
|
-
* POST /v1/sandbox/{id}/resume a pod again, same id and /work
|
|
10
|
-
* POST /v1/sandbox/{id}/{screen|terminal}/ticket one ticket, spent when the page's socket opens (30 s)
|
|
11
|
-
* GET /v1/sandbox/{id}/ports what listens in it, each with its preview host
|
|
12
|
-
* POST /v1/sandbox/{id}/preview {port} an address that opens that port in a browser
|
|
13
|
-
* POST /v1/sandbox/read {id, path} a directory's names, or a file's bytes
|
|
14
|
-
*
|
|
15
|
-
* A door or a preview asked of a sandbox that stopped as it was asked is 409: it
|
|
16
|
-
* is resumed, and asked again once.
|
|
17
|
-
*/
|
|
18
1
|
import { type Target } from './call.ts';
|
|
19
2
|
export type Door = 'screen' | 'terminal';
|
|
20
3
|
/** Where a sandbox is in its life. */
|
package/lib/api/sandbox.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* A door or a preview asked of a sandbox that stopped as it was asked is 409: it
|
|
16
16
|
* is resumed, and asked again once.
|
|
17
17
|
*/
|
|
18
|
+
import { phrase } from '@hanzo/i18n';
|
|
18
19
|
import { call, Refusal, seg } from './call.js';
|
|
19
20
|
const STATES = ['pending', 'running', 'parked', 'error'];
|
|
20
21
|
function box(raw, id) {
|
|
@@ -54,7 +55,7 @@ async function up(t, id) {
|
|
|
54
55
|
b = await sandbox(t, id);
|
|
55
56
|
}
|
|
56
57
|
if (b.state !== 'running')
|
|
57
|
-
throw new Refusal(503, b.error || 'The sandbox did not start again. Try again.');
|
|
58
|
+
throw new Refusal(503, b.error || phrase('The sandbox did not start again. Try again.'));
|
|
58
59
|
}
|
|
59
60
|
/** Asks what needs a running sandbox; a parked one is resumed first. */
|
|
60
61
|
async function running(t, id, ask) {
|
|
@@ -75,7 +76,7 @@ export async function door(t, id, which, session = '') {
|
|
|
75
76
|
const r = await running(t, id, () => call(t, 'POST', `/v1/sandbox/${seg(id)}/${which}/ticket`));
|
|
76
77
|
const path = typeof r?.url === 'string' ? r.url : '';
|
|
77
78
|
if (!path.startsWith('/v1/'))
|
|
78
|
-
throw new Refusal(502, 'The sandbox answered with no address to open');
|
|
79
|
+
throw new Refusal(502, phrase('The sandbox answered with no address to open'));
|
|
79
80
|
const arg = which === 'terminal' && NAME.test(session) ? `&arg=${session}` : '';
|
|
80
81
|
return `${t.api}${path}${arg}`;
|
|
81
82
|
}
|
|
@@ -104,10 +105,10 @@ export async function preview(t, id, port) {
|
|
|
104
105
|
url = new URL(typeof r?.url === 'string' ? r.url : '');
|
|
105
106
|
}
|
|
106
107
|
catch {
|
|
107
|
-
throw new Refusal(502, 'The sandbox answered with no address to open');
|
|
108
|
+
throw new Refusal(502, phrase('The sandbox answered with no address to open'));
|
|
108
109
|
}
|
|
109
110
|
if (url.protocol !== 'https:')
|
|
110
|
-
throw new Refusal(502, 'The sandbox answered with no address to open');
|
|
111
|
+
throw new Refusal(502, phrase('The sandbox answered with no address to open'));
|
|
111
112
|
return url.href;
|
|
112
113
|
}
|
|
113
114
|
/** What a file shows at most. */
|
package/lib/api/sessions.d.ts
CHANGED
|
@@ -1,20 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Runs, as the platform records them: one session per run.
|
|
3
|
-
*
|
|
4
|
-
* GET /v1/agent/sessions?kind=&project=&status=&limit=&after= newest first, {sessions, next}
|
|
5
|
-
* GET /v1/agent/sessions/{id} + the 50 most recent events
|
|
6
|
-
* PATCH /v1/agent/sessions/{id} {title}|{published} rename it; open its story to the public build route
|
|
7
|
-
* POST /v1/agent/sessions/{id}/message {message} steer a running run
|
|
8
|
-
* POST /v1/agent/sessions/{id}/pause pause it; a sandbox run keeps its work on its branch
|
|
9
|
-
* POST /v1/agent/sessions/{id}/resume ask a paused run to go on
|
|
10
|
-
* POST /v1/agent/sessions/{id}/stop {message} end it, work kept
|
|
11
|
-
* GET /v1/agent/sessions/stream?root={id} SSE: `session` and `event` frames,
|
|
12
|
-
* each wrapped: {"session":{…}}, {"event":{…}}
|
|
13
|
-
*
|
|
14
|
-
* The stream is best-effort by the platform's own statement: a subscriber that
|
|
15
|
-
* falls 256 frames behind is dropped. So `watch` reconnects, and every
|
|
16
|
-
* reconnect is reported, which is the caller's cue to re-read the detail.
|
|
17
|
-
*/
|
|
18
1
|
import { type Target } from './call.ts';
|
|
19
2
|
export type Status = 'running' | 'paused' | 'done' | 'error' | 'stopped' | string;
|
|
20
3
|
export interface Session {
|
package/lib/api/sessions.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* falls 256 frames behind is dropped. So `watch` reconnects, and every
|
|
16
16
|
* reconnect is reported, which is the caller's cue to re-read the detail.
|
|
17
17
|
*/
|
|
18
|
+
import { phrase } from '@hanzo/i18n';
|
|
18
19
|
import { call, headers, query, Refusal, seg } from './call.js';
|
|
19
20
|
import { read } from './sse.js';
|
|
20
21
|
const str = (v) => (typeof v === 'string' ? v : '');
|
|
@@ -93,7 +94,7 @@ export async function get(t, id) {
|
|
|
93
94
|
export async function message(t, id, text) {
|
|
94
95
|
const m = text.trim();
|
|
95
96
|
if (!m)
|
|
96
|
-
throw new Refusal(400, 'Say something to the run');
|
|
97
|
+
throw new Refusal(400, phrase('Say something to the run'));
|
|
97
98
|
await call(t, 'POST', `/v1/agent/sessions/${seg(id)}/message`, { message: m });
|
|
98
99
|
}
|
|
99
100
|
export async function stop(t, id, why = 'Stopped from the builder') {
|
|
@@ -109,9 +110,9 @@ export async function resume(t, id) {
|
|
|
109
110
|
export async function rename(t, id, title) {
|
|
110
111
|
const name = title.trim();
|
|
111
112
|
if (!name)
|
|
112
|
-
throw new Refusal(400, 'Give the run a name');
|
|
113
|
+
throw new Refusal(400, phrase('Give the run a name'));
|
|
113
114
|
if (name.length > 512)
|
|
114
|
-
throw new Refusal(400, 'A run’s name is at most 512 characters');
|
|
115
|
+
throw new Refusal(400, phrase('A run’s name is at most 512 characters'));
|
|
115
116
|
return session(await call(t, 'PATCH', `/v1/agent/sessions/${seg(id)}`, { title: name }));
|
|
116
117
|
}
|
|
117
118
|
/**
|
|
@@ -139,7 +140,7 @@ export async function watch(t, root, on, signal) {
|
|
|
139
140
|
signal,
|
|
140
141
|
});
|
|
141
142
|
if (res.status === 401 || res.status === 403)
|
|
142
|
-
throw new Refusal(res.status, 'This account cannot follow this run');
|
|
143
|
+
throw new Refusal(res.status, phrase('This account cannot follow this run'));
|
|
143
144
|
if (!res.ok || !res.body)
|
|
144
145
|
throw new Error(`stream answered ${res.status}`);
|
|
145
146
|
on.open?.(opened++);
|
package/lib/api/skills.d.ts
CHANGED
|
@@ -1,17 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Skills: what an agent knows how to do, as a SKILL.md it reads.
|
|
3
|
-
*
|
|
4
|
-
* GET /v1/tool/skills?activated=true {tools: [Tool]} the org's skills that are on, brand and own
|
|
5
|
-
* GET /v1/tool/skills/authored {skills: [skill]} the org's own, with their SKILL.md
|
|
6
|
-
* POST /v1/tool/skills {name, description, content} → 201 {skill}; the same name revises it
|
|
7
|
-
* DELETE /v1/tool/skills/{id} {deleted}
|
|
8
|
-
* GET /.well-known/agent-skills/index.json the brand's catalogue, public
|
|
9
|
-
* GET /.well-known/agent-skills/{name}/SKILL.md one of its documents, public
|
|
10
|
-
*
|
|
11
|
-
* A skill is on when its tool name, `skill_<name>`, is activated (tools.ts):
|
|
12
|
-
* that is how a catalogue skill is added to an org and how an org's own skill is
|
|
13
|
-
* switched off. The brand's skill wins a name an org's own skill also takes.
|
|
14
|
-
*/
|
|
15
1
|
import { type Target } from './call.ts';
|
|
16
2
|
import { type Tool } from './tools.ts';
|
|
17
3
|
/** An org's own skill. */
|
|
@@ -56,7 +42,7 @@ export declare function catalogue(raw: unknown): Catalogue;
|
|
|
56
42
|
/** The org's skills that are on, brand and own. */
|
|
57
43
|
export declare function active(t: Target): Promise<Tool[]>;
|
|
58
44
|
export declare function authored(t: Target): Promise<Skill[]>;
|
|
59
|
-
/** Why a skill cannot be written as it stands, or '' when it can. */
|
|
45
|
+
/** Why a skill cannot be written as it stands, or '' when it can. English, marked (`phrase`): a screen says it through `t`. */
|
|
60
46
|
export declare function refuse(s: {
|
|
61
47
|
name: string;
|
|
62
48
|
content: string;
|
package/lib/api/skills.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* that is how a catalogue skill is added to an org and how an org's own skill is
|
|
13
13
|
* switched off. The brand's skill wins a name an org's own skill also takes.
|
|
14
14
|
*/
|
|
15
|
+
import { phrase } from '@hanzo/i18n';
|
|
15
16
|
import { call, reason, Refusal, seg } from './call.js';
|
|
16
17
|
import { toolsOf } from './tools.js';
|
|
17
18
|
/** A skill's name: one lowercase path segment, as the handler takes it. */
|
|
@@ -63,14 +64,14 @@ export async function active(t) {
|
|
|
63
64
|
export async function authored(t) {
|
|
64
65
|
return rows(obj(await call(t, 'GET', '/v1/tool/skills/authored')).skills).map(skill).filter((s) => s.name);
|
|
65
66
|
}
|
|
66
|
-
/** Why a skill cannot be written as it stands, or '' when it can. */
|
|
67
|
+
/** Why a skill cannot be written as it stands, or '' when it can. English, marked (`phrase`): a screen says it through `t`. */
|
|
67
68
|
export function refuse(s) {
|
|
68
69
|
if (!NAME.test(s.name))
|
|
69
|
-
return 'A name is one lowercase word: letters, digits, _ or -';
|
|
70
|
+
return phrase('A name is one lowercase word: letters, digits, _ or -');
|
|
70
71
|
if (!s.content.trim())
|
|
71
|
-
return 'A skill needs its SKILL.md';
|
|
72
|
+
return phrase('A skill needs its SKILL.md');
|
|
72
73
|
if (new TextEncoder().encode(s.content).length > MAX)
|
|
73
|
-
return 'A SKILL.md is at most 256 KB';
|
|
74
|
+
return phrase('A SKILL.md is at most 256 KB');
|
|
74
75
|
return '';
|
|
75
76
|
}
|
|
76
77
|
export async function write(t, s) {
|
package/lib/api/studio.d.ts
CHANGED
|
@@ -1,17 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hanzo Studio: a creation is a run of a template, its files kept in the Library.
|
|
3
|
-
*
|
|
4
|
-
* GET /v1/studio/templates {data: [template]} the public catalog, then the org's own
|
|
5
|
-
* POST /v1/studio/runs {template, input, title?, parent?} → 201 run, queued
|
|
6
|
-
* GET /v1/studio/runs/{id} the run: status, text, outputs
|
|
7
|
-
* POST /v1/studio/runs/{id}/cancel stop it; what it reserved is released
|
|
8
|
-
*
|
|
9
|
-
* A run is priced and its estimate reserved against the org's wallet before it
|
|
10
|
-
* is queued (402 when the wallet cannot cover it). `parent` makes the run the
|
|
11
|
-
* next version of that one. Its outputs are Library items: their `url` is
|
|
12
|
-
* signed and expires, their `origin` is the app path that opens the run in
|
|
13
|
-
* Studio and does not.
|
|
14
|
-
*/
|
|
15
1
|
import { type Target } from './call.ts';
|
|
16
2
|
import { type Item } from './library.ts';
|
|
17
3
|
export interface Run {
|
package/lib/api/studio.js
CHANGED
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
* signed and expires, their `origin` is the app path that opens the run in
|
|
13
13
|
* Studio and does not.
|
|
14
14
|
*/
|
|
15
|
-
import {
|
|
15
|
+
import { phrase } from '@hanzo/i18n';
|
|
16
|
+
import { call, Refusal, seg, Sentence } from './call.js';
|
|
16
17
|
import { item } from './library.js';
|
|
17
18
|
export function brandOf(raw) {
|
|
18
19
|
const o = obj(raw);
|
|
@@ -65,10 +66,10 @@ const pause = (ms, signal) => new Promise((done, fail) => {
|
|
|
65
66
|
*/
|
|
66
67
|
export async function make(t, s, signal) {
|
|
67
68
|
let r = run(await call(t, 'POST', '/v1/studio/runs', s, { signal }).catch((e) => {
|
|
68
|
-
throw e instanceof Refusal && e.status === 402 ? new Error('Your balance does not cover it. Add credit in Settings › Billing.') : e;
|
|
69
|
+
throw e instanceof Refusal && e.status === 402 ? new Error(phrase('Your balance does not cover it. Add credit in Settings › Billing.')) : e;
|
|
69
70
|
}));
|
|
70
71
|
if (!r.id)
|
|
71
|
-
throw new Error('Studio started the run and named no id');
|
|
72
|
+
throw new Error(phrase('Studio started the run and named no id'));
|
|
72
73
|
const id = r.id;
|
|
73
74
|
const stop = () => void call(t, 'POST', `/v1/studio/runs/${seg(id)}/cancel`, {}).catch(() => undefined);
|
|
74
75
|
signal?.addEventListener('abort', stop, { once: true });
|
|
@@ -76,7 +77,7 @@ export async function make(t, s, signal) {
|
|
|
76
77
|
const until = Date.now() + LONGEST;
|
|
77
78
|
while (!ended(r)) {
|
|
78
79
|
if (Date.now() > until)
|
|
79
|
-
throw new Error('Studio is still making it. It will be in your Library when it is done.');
|
|
80
|
+
throw new Error(phrase('Studio is still making it. It will be in your Library when it is done.'));
|
|
80
81
|
await pause(EVERY, signal);
|
|
81
82
|
r = run(await call(t, 'GET', `/v1/studio/runs/${seg(id)}`, undefined, { signal }));
|
|
82
83
|
}
|
|
@@ -85,6 +86,6 @@ export async function make(t, s, signal) {
|
|
|
85
86
|
signal?.removeEventListener('abort', stop);
|
|
86
87
|
}
|
|
87
88
|
if (r.status !== 'succeeded')
|
|
88
|
-
throw new Error(r.error
|
|
89
|
+
throw r.error ? new Error(r.error) : new Sentence(phrase('Studio could not make it ({status})'), { status: r.status });
|
|
89
90
|
return r;
|
|
90
91
|
}
|