@hanzo/build 0.2.79 → 0.2.81
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 +22 -4
- package/lib/activity.d.ts +3 -7
- package/lib/activity.js +18 -5
- package/lib/api/agents.d.ts +36 -35
- package/lib/api/agents.js +66 -29
- 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/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 +2 -1
- 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.d.ts +3 -0
- package/lib/customize/agents.js +152 -55
- package/lib/customize/connectors.js +62 -48
- package/lib/customize/index.js +45 -14
- 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/host.d.ts +3 -1
- package/lib/landing.d.ts +5 -5
- package/lib/landing.js +52 -44
- package/lib/library.js +73 -51
- 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 +6 -3
- 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 +18 -15
- 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/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
|
}
|
package/lib/api/turn.d.ts
CHANGED
|
@@ -1,26 +1,4 @@
|
|
|
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 of the
|
|
14
|
-
* run itself, `event` for one line of the agent's own structured narration (the
|
|
15
|
-
* harness's JSON stream: its messages, reasoning, commands, edits, tool calls and
|
|
16
|
-
* plan), and `log` for raw output, which only the Terminal's log shows. A
|
|
17
|
-
* person's steering is a `control` {command, message}. A run on a project with a
|
|
18
|
-
* site ends `done` with `live` when it published what it pushed, or `unpublished`
|
|
19
|
-
* saying why it did not.
|
|
20
|
-
*
|
|
21
|
-
* `cards` is the transcript as it is drawn: the run's steps and the agent's
|
|
22
|
-
* items, never its log.
|
|
23
|
-
*/
|
|
1
|
+
import type { Say } from '@hanzo/i18n/react';
|
|
24
2
|
import type { Event } from './sessions.ts';
|
|
25
3
|
/** The payload as an object. A live frame may carry it as a JSON string. */
|
|
26
4
|
export declare function decode(payload: unknown): Record<string, unknown> | string | null;
|
|
@@ -32,17 +10,17 @@ export declare function decode(payload: unknown): Record<string, unknown> | stri
|
|
|
32
10
|
*/
|
|
33
11
|
export declare function vendor(error: string): boolean;
|
|
34
12
|
/** An error as the run page may show it: its own words, or the plain line when they are a vendor's. */
|
|
35
|
-
export declare const scrub: (error: string) => string;
|
|
13
|
+
export declare const scrub: (error: string, t?: Say) => string;
|
|
36
14
|
/**
|
|
37
15
|
* A run's error as one plain line with what to do, never the log it came from:
|
|
38
16
|
* that goes in the Error step beside it (cards), unless it is a vendor's.
|
|
39
17
|
*/
|
|
40
|
-
export declare function plain(error: string): string;
|
|
18
|
+
export declare function plain(error: string, t?: Say): string;
|
|
41
19
|
/**
|
|
42
20
|
* One event's sentence, or '' when it says nothing a person needs. `mode` is
|
|
43
21
|
* the run's, from its record: a plan run's final status says the plan.
|
|
44
22
|
*/
|
|
45
|
-
export declare function said(e: Pick<Event, 'kind' | 'payload'>, mode?: string): string;
|
|
23
|
+
export declare function said(e: Pick<Event, 'kind' | 'payload'>, mode?: string, t?: Say): string;
|
|
46
24
|
/** One line of the shell: a command the run started, or output that followed it. */
|
|
47
25
|
export interface ShellLine {
|
|
48
26
|
role: 'cmd' | 'out';
|
|
@@ -89,7 +67,7 @@ export interface Outcome {
|
|
|
89
67
|
*/
|
|
90
68
|
export declare function outcome(events: Pick<Event, 'kind' | 'payload' | 'seq'>[]): Outcome;
|
|
91
69
|
/** Why the run failed, as its last status says it, or '' when that status is not a failure. */
|
|
92
|
-
export declare function failure(events: Pick<Event, 'kind' | 'payload' | 'seq'>[]): string;
|
|
70
|
+
export declare function failure(events: Pick<Event, 'kind' | 'payload' | 'seq'>[], t?: Say): string;
|
|
93
71
|
/** The turns, ordered and deduped: a recorded read and the live feed overlap. */
|
|
94
72
|
export declare function merge<T extends Pick<Event, 'id' | 'seq'>>(...lists: T[][]): T[];
|
|
95
73
|
/** The actor, short enough to label a block: `hanzo/2d4d67ab`, not the whole subject. */
|
|
@@ -176,7 +154,7 @@ export type Card = {
|
|
|
176
154
|
* is drawn only if the turn then fails. The final status carries the agent's
|
|
177
155
|
* answer, drawn once. `log` is never drawn here.
|
|
178
156
|
*/
|
|
179
|
-
export declare function cards(events: Pick<Event, 'kind' | 'payload' | 'seq'>[], mode?: string): Card[];
|
|
157
|
+
export declare function cards(events: Pick<Event, 'kind' | 'payload' | 'seq'>[], mode?: string, t?: Say): Card[];
|
|
180
158
|
/** The plan a plan run answered with, from its final status, or ''. */
|
|
181
159
|
export declare function answer(events: Pick<Event, 'kind' | 'payload' | 'seq'>[]): string;
|
|
182
160
|
export interface Settled {
|
package/lib/api/turn.js
CHANGED
|
@@ -1,3 +1,34 @@
|
|
|
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 of the
|
|
14
|
+
* run itself, `event` for one line of the agent's own structured narration (the
|
|
15
|
+
* harness's JSON stream: its messages, reasoning, commands, edits, tool calls and
|
|
16
|
+
* plan), and `log` for raw output, which only the Terminal's log shows. A
|
|
17
|
+
* person's steering is a `control` {command, message}. A run on a project with a
|
|
18
|
+
* site ends `done` with `live` when it published what it pushed, or `unpublished`
|
|
19
|
+
* saying why it did not.
|
|
20
|
+
*
|
|
21
|
+
* `cards` is the transcript as it is drawn: the run's steps and the agent's
|
|
22
|
+
* items, never its log.
|
|
23
|
+
*
|
|
24
|
+
* The sentences are this client's, said in the language of the `t` a caller
|
|
25
|
+
* hands (@hanzo/i18n; English without one); what the run and the agent said
|
|
26
|
+
* is drawn as given. A step's name is a name the transcript keys on (`Error`
|
|
27
|
+
* opens itself), so it stays English, marked (`phrase`), and the transcript
|
|
28
|
+
* draws it through `t`.
|
|
29
|
+
*/
|
|
30
|
+
import { phrase } from '@hanzo/i18n';
|
|
31
|
+
import { english } from '../say.js';
|
|
1
32
|
const str = (v) => (typeof v === 'string' ? v : '');
|
|
2
33
|
const obj = (v) => (v && typeof v === 'object' ? v : {});
|
|
3
34
|
/** The payload as an object. A live frame may carry it as a JSON string. */
|
|
@@ -22,40 +53,65 @@ const base = (path) => {
|
|
|
22
53
|
const cut = path.replace(/\/+$/, '');
|
|
23
54
|
return cut.slice(cut.lastIndexOf('/') + 1);
|
|
24
55
|
};
|
|
25
|
-
|
|
56
|
+
/**
|
|
57
|
+
* A finished run's line, by whether it pushed a branch (Done when it did not),
|
|
58
|
+
* its pull request (none, one that could not be opened, its address) and its
|
|
59
|
+
* site (none, not published and why, published): each a whole line, so a
|
|
60
|
+
* language puts the parts in its own order.
|
|
61
|
+
*/
|
|
62
|
+
const FINISHED = {
|
|
63
|
+
pushed: {
|
|
64
|
+
none: { none: phrase('Pushed {branch}'), out: phrase('Pushed {branch} — not published: {why}'), live: phrase('Pushed {branch} — published') },
|
|
65
|
+
broke: {
|
|
66
|
+
none: phrase('Pushed {branch} — the pull request could not be opened'),
|
|
67
|
+
out: phrase('Pushed {branch} — the pull request could not be opened — not published: {why}'),
|
|
68
|
+
live: phrase('Pushed {branch} — the pull request could not be opened — published'),
|
|
69
|
+
},
|
|
70
|
+
pr: { none: phrase('Pushed {branch} — {pr}'), out: phrase('Pushed {branch} — {pr} — not published: {why}'), live: phrase('Pushed {branch} — {pr} — published') },
|
|
71
|
+
},
|
|
72
|
+
done: {
|
|
73
|
+
none: { none: phrase('Done'), out: phrase('Done — not published: {why}'), live: phrase('Done — published') },
|
|
74
|
+
broke: {
|
|
75
|
+
none: phrase('Done — the pull request could not be opened'),
|
|
76
|
+
out: phrase('Done — the pull request could not be opened — not published: {why}'),
|
|
77
|
+
live: phrase('Done — the pull request could not be opened — published'),
|
|
78
|
+
},
|
|
79
|
+
pr: { none: phrase('Done — {pr}'), out: phrase('Done — {pr} — not published: {why}'), live: phrase('Done — {pr} — published') },
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
function status(b, mode, t) {
|
|
26
83
|
const branch = str(b.branch);
|
|
27
84
|
switch (str(b.status)) {
|
|
28
85
|
case 'started':
|
|
29
|
-
return branch ?
|
|
86
|
+
return branch ? t('Started on {branch}', { branch }) : t('Started');
|
|
30
87
|
case 'routed':
|
|
31
|
-
return 'Sent to a machine';
|
|
88
|
+
return t('Sent to a machine');
|
|
32
89
|
case 'done': {
|
|
33
90
|
// A plan's answer IS its final status: the run read and wrote nothing.
|
|
34
91
|
// Whether the run planned is the RECORD's word — any member of the org
|
|
35
92
|
// can append an event saying `mode: plan`, and its text is not an answer.
|
|
36
93
|
// A setup is a plan put to one question, and answers the same way.
|
|
37
94
|
if (mode === 'plan')
|
|
38
|
-
return str(b.plan) || 'Planned — the run answered with no plan';
|
|
95
|
+
return str(b.plan) || t('Planned — the run answered with no plan');
|
|
39
96
|
if (mode === 'setup')
|
|
40
|
-
return str(b.plan) || 'Set up — the run answered with no environment';
|
|
97
|
+
return str(b.plan) || t('Set up — the run answered with no environment');
|
|
41
98
|
if (b.changed === false)
|
|
42
|
-
return 'Done — nothing to change';
|
|
99
|
+
return t('Done — nothing to change');
|
|
43
100
|
const pr = str(b.pr);
|
|
44
|
-
const tail = str(b.prError) ? ' — the pull request could not be opened' : pr ? ` — ${pr}` : '';
|
|
45
101
|
// A run on a project with a site publishes what it pushed, or says why not.
|
|
46
102
|
const why = str(b.unpublished);
|
|
47
|
-
const
|
|
48
|
-
return
|
|
103
|
+
const line = FINISHED[branch ? 'pushed' : 'done'][str(b.prError) ? 'broke' : pr ? 'pr' : 'none'][why ? 'out' : str(b.live) ? 'live' : 'none'];
|
|
104
|
+
return t(line, { branch, pr, why });
|
|
49
105
|
}
|
|
50
106
|
case 'error':
|
|
51
|
-
return plain(str(b.error));
|
|
107
|
+
return plain(str(b.error), t);
|
|
52
108
|
case 'stopped':
|
|
53
|
-
return branch && b.changed ?
|
|
109
|
+
return branch && b.changed ? t('Stopped — work kept on {branch}', { branch }) : t('Stopped');
|
|
54
110
|
case 'paused':
|
|
55
|
-
return branch && b.changed ?
|
|
111
|
+
return branch && b.changed ? t('Paused — work kept on {branch}', { branch }) : t('Paused');
|
|
56
112
|
case 'followed':
|
|
57
113
|
// A run redirected from a chat thread is carried on by a follow-up (apps/coding steer.go).
|
|
58
|
-
return str(b.next) ? 'Continued in a follow-up run' : 'The follow-up run could not start';
|
|
114
|
+
return str(b.next) ? t('Continued in a follow-up run') : t('The follow-up run could not start');
|
|
59
115
|
}
|
|
60
116
|
return str(b.status);
|
|
61
117
|
}
|
|
@@ -69,35 +125,35 @@ export function vendor(error) {
|
|
|
69
125
|
return /open\s?router|anthropic|openai|azure|bedrock|vertex|gemini|mistral|cohere|deepinfra|fireworks|together\.ai|groq|x-ratelimit|upstream|\bprovider\b|\bsk-[A-Za-z0-9_-]{6,}|"(error|code|message)"\s*:/i.test(error);
|
|
70
126
|
}
|
|
71
127
|
/** An error as the run page may show it: its own words, or the plain line when they are a vendor's. */
|
|
72
|
-
export const scrub = (error) => (vendor(error) ? plain(error) : error);
|
|
128
|
+
export const scrub = (error, t = english) => (vendor(error) ? plain(error, t) : error);
|
|
73
129
|
/**
|
|
74
130
|
* A run's error as one plain line with what to do, never the log it came from:
|
|
75
131
|
* that goes in the Error step beside it (cards), unless it is a vendor's.
|
|
76
132
|
*/
|
|
77
|
-
export function plain(error) {
|
|
133
|
+
export function plain(error, t = english) {
|
|
78
134
|
if (!error)
|
|
79
|
-
return 'The run hit an error';
|
|
135
|
+
return t('The run hit an error');
|
|
80
136
|
const ours = /providers_exhausted|every provider refused|temporarily unavailable/i.test(error);
|
|
81
137
|
if (/free sandboxes .*are used/i.test(error))
|
|
82
|
-
return 'This plan’s free sandboxes are used for now. Add credit to keep building, or try again later.';
|
|
138
|
+
return t('This plan’s free sandboxes are used for now. Add credit to keep building, or try again later.');
|
|
83
139
|
if (!ours && /\b402 Payment Required|insufficient (credit|balance)|top up/i.test(error))
|
|
84
|
-
return 'Your balance is out of credit. Add credit, then try again.';
|
|
140
|
+
return t('Your balance is out of credit. Add credit, then try again.');
|
|
85
141
|
if (ours || /\b(429 Too Many Requests|503 Service Unavailable)|stream disconnected|retries exhausted|rate limit/i.test(error))
|
|
86
|
-
return 'The model did not answer. Try again in a moment, or pick another model.';
|
|
87
|
-
return 'The run stopped with an error. Try again, or follow up with what to change.';
|
|
142
|
+
return t('The model did not answer. Try again in a moment, or pick another model.');
|
|
143
|
+
return t('The run stopped with an error. Try again, or follow up with what to change.');
|
|
88
144
|
}
|
|
89
145
|
/**
|
|
90
146
|
* One event's sentence, or '' when it says nothing a person needs. `mode` is
|
|
91
147
|
* the run's, from its record: a plan run's final status says the plan.
|
|
92
148
|
*/
|
|
93
|
-
export function said(e, mode = '') {
|
|
149
|
+
export function said(e, mode = '', t = english) {
|
|
94
150
|
const body = decode(e.payload);
|
|
95
151
|
if (typeof body === 'string')
|
|
96
152
|
return body;
|
|
97
153
|
if (!body)
|
|
98
154
|
return '';
|
|
99
155
|
if (e.kind === 'status')
|
|
100
|
-
return status(body, mode);
|
|
156
|
+
return status(body, mode, t);
|
|
101
157
|
for (const key of ['message', 'text', 'content', 'result', 'command']) {
|
|
102
158
|
const v = body[key];
|
|
103
159
|
if (typeof v === 'string' && v)
|
|
@@ -106,13 +162,13 @@ export function said(e, mode = '') {
|
|
|
106
162
|
if (str(body.type) === 'done' && Array.isArray(body.changed)) {
|
|
107
163
|
const names = body.changed.map((f) => base(str(f))).filter(Boolean);
|
|
108
164
|
return names.length === 0
|
|
109
|
-
? 'Done — no files changed'
|
|
165
|
+
? t('Done — no files changed')
|
|
110
166
|
: names.length <= 3
|
|
111
|
-
?
|
|
112
|
-
:
|
|
167
|
+
? t('Done — changed {files}', { files: names.join(', ') })
|
|
168
|
+
: t('Done — changed {n} files', { n: names.length });
|
|
113
169
|
}
|
|
114
170
|
if (str(body.type) === 'error')
|
|
115
|
-
return scrub(str(body.error)) || 'The run hit an error';
|
|
171
|
+
return scrub(str(body.error), t) || t('The run hit an error');
|
|
116
172
|
return str(body.step) || str(body.name);
|
|
117
173
|
}
|
|
118
174
|
/**
|
|
@@ -200,7 +256,7 @@ export function outcome(events) {
|
|
|
200
256
|
return out;
|
|
201
257
|
}
|
|
202
258
|
/** Why the run failed, as its last status says it, or '' when that status is not a failure. */
|
|
203
|
-
export function failure(events) {
|
|
259
|
+
export function failure(events, t = english) {
|
|
204
260
|
let out = '';
|
|
205
261
|
for (const e of [...events].sort((a, b) => a.seq - b.seq)) {
|
|
206
262
|
if (e.kind !== 'status')
|
|
@@ -208,7 +264,7 @@ export function failure(events) {
|
|
|
208
264
|
const b = decode(e.payload);
|
|
209
265
|
if (!b || typeof b === 'string' || !str(b.status))
|
|
210
266
|
continue;
|
|
211
|
-
out = str(b.status) === 'error' ? scrub(str(b.error)) || 'The run hit an error' : '';
|
|
267
|
+
out = str(b.status) === 'error' ? scrub(str(b.error), t) || t('The run hit an error') : '';
|
|
212
268
|
}
|
|
213
269
|
return out;
|
|
214
270
|
}
|
|
@@ -242,19 +298,19 @@ export function pull(url, repo) {
|
|
|
242
298
|
return { href: '', label: '' };
|
|
243
299
|
return { href: url, label: `#${m[3]}` };
|
|
244
300
|
}
|
|
245
|
-
/** What the run's own steps are called on a card
|
|
301
|
+
/** What the run's own steps are called on a card: English, marked (`phrase`); the transcript draws them through `t`. */
|
|
246
302
|
const NAMES = {
|
|
247
|
-
lease: 'Sandbox',
|
|
248
|
-
workspace: 'Workspace',
|
|
249
|
-
clone: 'Clone',
|
|
250
|
-
branch: 'Branch',
|
|
251
|
-
secrets: 'Secrets',
|
|
252
|
-
install: 'Install',
|
|
253
|
-
start: 'Start',
|
|
254
|
-
skills: 'Skills',
|
|
255
|
-
artifacts: 'Save artifacts',
|
|
256
|
-
push: 'Push',
|
|
257
|
-
kept: 'Keep the sandbox',
|
|
303
|
+
lease: phrase('Sandbox'),
|
|
304
|
+
workspace: phrase('Workspace'),
|
|
305
|
+
clone: phrase('Clone'),
|
|
306
|
+
branch: phrase('Branch'),
|
|
307
|
+
secrets: phrase('Secrets'),
|
|
308
|
+
install: phrase('Install'),
|
|
309
|
+
start: phrase('Start'),
|
|
310
|
+
skills: phrase('Skills'),
|
|
311
|
+
artifacts: phrase('Save artifacts'),
|
|
312
|
+
push: phrase('Push'),
|
|
313
|
+
kept: phrase('Keep the sandbox'),
|
|
258
314
|
};
|
|
259
315
|
/** Steps another card already says: `leased` finishes the lease, `done` is the final status, `ended` and `exit` are housekeeping. */
|
|
260
316
|
const QUIET = new Set(['leased', 'done', 'ended', 'exit']);
|
|
@@ -290,9 +346,9 @@ function item(it, key) {
|
|
|
290
346
|
return { kind: 'edit', key, files: changes.map((c) => rel(str(obj(c).path))).filter(Boolean), ran: itemRan(it) };
|
|
291
347
|
}
|
|
292
348
|
case 'mcp_tool_call':
|
|
293
|
-
return { kind: 'step', key, name: str(it.tool) || 'Tool', detail: str(it.server), output: '', ran: itemRan(it) };
|
|
349
|
+
return { kind: 'step', key, name: str(it.tool) || phrase('Tool'), detail: str(it.server), output: '', ran: itemRan(it) };
|
|
294
350
|
case 'web_search':
|
|
295
|
-
return { kind: 'step', key, name: 'Search', detail: str(it.query), output: '', ran: 'done' };
|
|
351
|
+
return { kind: 'step', key, name: phrase('Search'), detail: str(it.query), output: '', ran: 'done' };
|
|
296
352
|
case 'todo_list': {
|
|
297
353
|
const items = Array.isArray(it.items) ? it.items : [];
|
|
298
354
|
return { kind: 'todo', key, items: items.map((x) => ({ text: str(obj(x).text), done: obj(x).completed === true })).filter((x) => x.text) };
|
|
@@ -313,7 +369,7 @@ function item(it, key) {
|
|
|
313
369
|
* is drawn only if the turn then fails. The final status carries the agent's
|
|
314
370
|
* answer, drawn once. `log` is never drawn here.
|
|
315
371
|
*/
|
|
316
|
-
export function cards(events, mode = '') {
|
|
372
|
+
export function cards(events, mode = '', t = english) {
|
|
317
373
|
const out = [];
|
|
318
374
|
let seq = 0;
|
|
319
375
|
let n = 0;
|
|
@@ -334,10 +390,10 @@ export function cards(events, mode = '') {
|
|
|
334
390
|
if (failures.has(message))
|
|
335
391
|
return;
|
|
336
392
|
failures.add(message);
|
|
337
|
-
out.push({ kind: 'note', key: mint(), text: plain(message) });
|
|
393
|
+
out.push({ kind: 'note', key: mint(), text: plain(message, t) });
|
|
338
394
|
// The reason, read whole, when it is the run's own; a vendor's words stay off the page.
|
|
339
395
|
if (message && !vendor(message))
|
|
340
|
-
out.push({ kind: 'step', key: mint(), name: 'Error', detail: '', output: message, ran: 'error' });
|
|
396
|
+
out.push({ kind: 'step', key: mint(), name: phrase('Error'), detail: '', output: message, ran: 'error' });
|
|
341
397
|
};
|
|
342
398
|
for (const e of [...events].sort((a, b) => a.seq - b.seq)) {
|
|
343
399
|
seq = e.seq;
|
|
@@ -421,7 +477,7 @@ export function cards(events, mode = '') {
|
|
|
421
477
|
failed(str(b.error));
|
|
422
478
|
break;
|
|
423
479
|
}
|
|
424
|
-
const line = status(b, mode);
|
|
480
|
+
const line = status(b, mode, t);
|
|
425
481
|
if (line)
|
|
426
482
|
out.push({ kind: 'note', key: mint(), text: line });
|
|
427
483
|
break;
|
|
@@ -434,11 +490,11 @@ export function cards(events, mode = '') {
|
|
|
434
490
|
if (command === 'message' && said)
|
|
435
491
|
steered.add(person(said));
|
|
436
492
|
else if (command === 'pause')
|
|
437
|
-
out.push({ kind: 'note', key: mint(), text: 'Pause asked' });
|
|
493
|
+
out.push({ kind: 'note', key: mint(), text: t('Pause asked') });
|
|
438
494
|
else if (command === 'resume')
|
|
439
|
-
out.push({ kind: 'note', key: mint(), text: 'Resume asked' });
|
|
495
|
+
out.push({ kind: 'note', key: mint(), text: t('Resume asked') });
|
|
440
496
|
else if (command === 'stop')
|
|
441
|
-
out.push({ kind: 'note', key: mint(), text: 'Stop asked' });
|
|
497
|
+
out.push({ kind: 'note', key: mint(), text: t('Stop asked') });
|
|
442
498
|
break;
|
|
443
499
|
}
|
|
444
500
|
case 'message': {
|
package/lib/api/verdict.d.ts
CHANGED
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A person's verdict on what a run said, recorded on the platform's own event
|
|
3
|
-
* bus in the org it was said in.
|
|
4
|
-
*
|
|
5
|
-
* POST /v1/event {type: 'track', event: 'build.verdict', sessionId, properties}
|
|
6
|
-
*
|
|
7
|
-
* The receipt says whether it landed; a verdict that did not is reported, not
|
|
8
|
-
* shown as recorded.
|
|
9
|
-
*/
|
|
10
1
|
import { type Target } from './call.ts';
|
|
11
2
|
export type Verdict = 'up' | 'down' | null;
|
|
12
3
|
export declare function verdict(t: Target, session: string, project: string, v: Verdict): Promise<void>;
|
package/lib/api/verdict.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* The receipt says whether it landed; a verdict that did not is reported, not
|
|
8
8
|
* shown as recorded.
|
|
9
9
|
*/
|
|
10
|
+
import { phrase } from '@hanzo/i18n';
|
|
10
11
|
import { call } from './call.js';
|
|
11
12
|
export async function verdict(t, session, project, v) {
|
|
12
13
|
const out = await call(t, 'POST', '/v1/event', {
|
|
@@ -16,5 +17,5 @@ export async function verdict(t, session, project, v) {
|
|
|
16
17
|
properties: { verdict: v ?? 'cleared', project },
|
|
17
18
|
});
|
|
18
19
|
if (!out || !out.accepted)
|
|
19
|
-
throw new Error('The verdict was not recorded');
|
|
20
|
+
throw new Error(phrase('The verdict was not recorded'));
|
|
20
21
|
}
|
package/lib/api/webhooks.d.ts
CHANGED
|
@@ -1,16 +1,3 @@
|
|
|
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
1
|
import { type Target } from './call.ts';
|
|
15
2
|
export interface Endpoint {
|
|
16
3
|
id: string;
|
|
@@ -36,7 +23,7 @@ export interface Draft {
|
|
|
36
23
|
events: string[];
|
|
37
24
|
description: string;
|
|
38
25
|
}
|
|
39
|
-
/** Why a draft cannot be sent, or ''. The platform refuses the same things. */
|
|
26
|
+
/** Why a draft cannot be sent, or ''. The platform refuses the same things. English, marked (`phrase`): a screen says it through `t`. */
|
|
40
27
|
export declare function refuse(d: Draft): string;
|
|
41
28
|
export declare function add(t: Target, d: Draft): Promise<Endpoint>;
|
|
42
29
|
export declare function remove(t: Target, id: string): Promise<void>;
|
package/lib/api/webhooks.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* The org is the caller's; an endpoint another org owns reads as not found.
|
|
12
12
|
* Events are subject patterns (`commerce.order.>`); none means every event.
|
|
13
13
|
*/
|
|
14
|
+
import { phrase } from '@hanzo/i18n';
|
|
14
15
|
import { call, query, seg } from './call.js';
|
|
15
16
|
const str = (v) => (typeof v === 'string' ? v : '');
|
|
16
17
|
const num = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : 0);
|
|
@@ -38,19 +39,19 @@ export async function endpoints(t) {
|
|
|
38
39
|
export function patterns(typed) {
|
|
39
40
|
return [...new Set(typed.split(/[\s,]+/).map((s) => s.trim()).filter(Boolean))];
|
|
40
41
|
}
|
|
41
|
-
/** Why a draft cannot be sent, or ''. The platform refuses the same things. */
|
|
42
|
+
/** Why a draft cannot be sent, or ''. The platform refuses the same things. English, marked (`phrase`): a screen says it through `t`. */
|
|
42
43
|
export function refuse(d) {
|
|
43
44
|
let u;
|
|
44
45
|
try {
|
|
45
46
|
u = new URL(d.url.trim());
|
|
46
47
|
}
|
|
47
48
|
catch {
|
|
48
|
-
return 'Enter the https address to deliver to';
|
|
49
|
+
return phrase('Enter the https address to deliver to');
|
|
49
50
|
}
|
|
50
51
|
if (u.protocol !== 'https:')
|
|
51
|
-
return 'A webhook is delivered over https only';
|
|
52
|
+
return phrase('A webhook is delivered over https only');
|
|
52
53
|
if (d.events.length > 64)
|
|
53
|
-
return 'At most 64 event patterns';
|
|
54
|
+
return phrase('At most 64 event patterns');
|
|
54
55
|
return '';
|
|
55
56
|
}
|
|
56
57
|
export async function add(t, d) {
|
package/lib/ask.js
CHANGED
|
@@ -5,6 +5,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
5
5
|
* the reason is read where the act was asked for.
|
|
6
6
|
*/
|
|
7
7
|
import { SizableText, XStack } from '@hanzo/gui';
|
|
8
|
+
import { useI18n } from '@hanzo/i18n/react';
|
|
8
9
|
import { Button, Dialog, DialogContent, DialogTitle, Input } from '@hanzo/ui';
|
|
9
10
|
import { useEffect, useState } from 'react';
|
|
10
11
|
/** One act in flight, and what refused it. */
|
|
@@ -32,6 +33,7 @@ function Said({ note }) {
|
|
|
32
33
|
return (_jsx(SizableText, { size: "$1", color: "$soft", role: "status", children: note }));
|
|
33
34
|
}
|
|
34
35
|
export function Confirm({ open, onOpenChange, title, says, act, run, }) {
|
|
36
|
+
const { t } = useI18n();
|
|
35
37
|
const { working, note, setNote, go } = useAct(() => onOpenChange(false));
|
|
36
38
|
const close = (o) => {
|
|
37
39
|
if (working)
|
|
@@ -39,9 +41,10 @@ export function Confirm({ open, onOpenChange, title, says, act, run, }) {
|
|
|
39
41
|
setNote('');
|
|
40
42
|
onOpenChange(o);
|
|
41
43
|
};
|
|
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:
|
|
44
|
+
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: t('Cancel') }), _jsx(Button, { size: "sm", variant: "destructive", disabled: working, onPress: () => void go(run), children: act })] })] }) }));
|
|
43
45
|
}
|
|
44
46
|
export function Rename({ open, onOpenChange, title, name, run, }) {
|
|
47
|
+
const { t } = useI18n();
|
|
45
48
|
const [value, setValue] = useState(name);
|
|
46
49
|
const { working, note, setNote, go } = useAct(() => onOpenChange(false));
|
|
47
50
|
useEffect(() => {
|
|
@@ -57,13 +60,13 @@ export function Rename({ open, onOpenChange, title, name, run, }) {
|
|
|
57
60
|
const save = () => {
|
|
58
61
|
const next = value.trim();
|
|
59
62
|
if (!next)
|
|
60
|
-
return setNote('It needs a name');
|
|
63
|
+
return setNote(t('It needs a name'));
|
|
61
64
|
if (next === name)
|
|
62
65
|
return close(false);
|
|
63
66
|
void go(() => run(next));
|
|
64
67
|
};
|
|
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":
|
|
68
|
+
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": t('Name'), onKeyDown: (e) => {
|
|
66
69
|
if (e.key === 'Enter')
|
|
67
70
|
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:
|
|
71
|
+
} }), _jsx(Said, { note: note }), _jsxs(XStack, { gap: "$2", justify: "flex-end", children: [_jsx(Button, { size: "sm", variant: "ghost", disabled: working, onPress: () => close(false), children: t('Cancel') }), _jsx(Button, { size: "sm", disabled: working, onPress: save, children: t('Save') })] })] }) }));
|
|
69
72
|
}
|