wizards 0.5.12 → 0.5.13

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.
Files changed (68) hide show
  1. package/apps/runtime/dist/db/control-schema.js +10 -0
  2. package/apps/runtime/dist/db/migrations/control/0010_tan_snowbird.sql +6 -0
  3. package/apps/runtime/dist/db/migrations/control/meta/0010_snapshot.json +600 -0
  4. package/apps/runtime/dist/db/migrations/control/meta/_journal.json +7 -0
  5. package/apps/runtime/dist/db/migrations/tenant/0016_even_trish_tilby.sql +12 -0
  6. package/apps/runtime/dist/db/migrations/tenant/meta/0016_snapshot.json +3326 -0
  7. package/apps/runtime/dist/db/migrations/tenant/meta/_journal.json +7 -0
  8. package/apps/runtime/dist/db/schema.js +20 -0
  9. package/apps/runtime/dist/engine/runner.js +19 -3
  10. package/apps/runtime/dist/engine/steps.js +15 -4
  11. package/apps/runtime/dist/model-errors.js +20 -7
  12. package/apps/runtime/dist/routes/runs.js +170 -23
  13. package/apps/runtime/dist/routes/studio.js +41 -3
  14. package/apps/runtime/dist/services/cloud.js +1 -0
  15. package/apps/runtime/dist/services/spaces.js +1 -0
  16. package/apps/runtime/dist/services/translations.js +303 -0
  17. package/apps/runtime/dist/services/wizards.js +3 -1
  18. package/apps/runtime/dist/texts.js +2 -0
  19. package/apps/web/dist/assets/{AboutDialog-DvkE9J4h.js → AboutDialog-CkE7uZNL.js} +1 -1
  20. package/apps/web/dist/assets/{ChangelogDialog-BZ8i3wt_.js → ChangelogDialog-BCS3WIRA.js} +1 -1
  21. package/apps/web/dist/assets/ChatView-DClGzMte.js +10 -0
  22. package/apps/web/dist/assets/EditorPage-Dg27sIZ7.js +3 -0
  23. package/apps/web/dist/assets/{FlowPreview-DG23aI89.js → FlowPreview-D2haAZwo.js} +1 -1
  24. package/apps/web/dist/assets/{Harness-CFh04TZ3.js → Harness-CGI6ZMTA.js} +2 -2
  25. package/apps/web/dist/assets/{NewWizardChannels-Bmo5yRCv.js → NewWizardChannels-C4b_phHw.js} +1 -1
  26. package/apps/web/dist/assets/{NewWizardPage-4n9-ZmHt.js → NewWizardPage-DhDXrjKX.js} +2 -2
  27. package/apps/web/dist/assets/OnboardingPage-DgySdBgo.js +1 -0
  28. package/apps/web/dist/assets/ProjectPage-dvtJn_3c.js +1 -0
  29. package/apps/web/dist/assets/PublicRunner-lP4sVF1q.js +1 -0
  30. package/apps/web/dist/assets/{ReadOnly-C_jD7KjW.js → ReadOnly-B-4l3bVt.js} +1 -1
  31. package/apps/web/dist/assets/RunDrawer-B2bsB9Z6.js +4 -0
  32. package/apps/web/dist/assets/RunnerView-BZ83HUnO.js +1 -0
  33. package/apps/web/dist/assets/SettingsPage-C0_wAa_j.js +1 -0
  34. package/apps/web/dist/assets/SetupPage-kuvBk0G0.js +1 -0
  35. package/apps/web/dist/assets/{SharePage-k2OMGOWU.js → SharePage-COLVxXMI.js} +1 -1
  36. package/apps/web/dist/assets/changelog-CIYdRaa5.js +1 -0
  37. package/apps/web/dist/assets/{esm-Dzqe3TT4.js → esm-BqbWrbsa.js} +1 -1
  38. package/apps/web/dist/assets/index-Da9Pvzpj.js +14 -0
  39. package/apps/web/dist/assets/{lock-a8rDnyg5.js → lock-BkN0Fai6.js} +1 -1
  40. package/apps/web/dist/assets/{phone-CitA6oZn.js → phone-Dip_wSUZ.js} +1 -1
  41. package/apps/web/dist/assets/{settings-menu-COgM8CgB.js → settings-menu-B7eXkvba.js} +1 -1
  42. package/apps/web/dist/assets/ui-B9AOCT0v.js +134 -0
  43. package/apps/web/dist/assets/{upload-CcKFwoPd.js → upload-DPQ4pwnl.js} +1 -1
  44. package/apps/web/dist/index.html +2 -2
  45. package/apps/web/dist/mcp/flow.html +53 -53
  46. package/node_modules/@engenty-wizards/shared/dist/definition.d.ts +19 -0
  47. package/node_modules/@engenty-wizards/shared/dist/definition.js +51 -0
  48. package/node_modules/@engenty-wizards/shared/dist/run.d.ts +46 -4
  49. package/node_modules/@engenty-wizards/shared/dist/run.js +23 -8
  50. package/node_modules/@engenty-wizards/shared/dist/runner-texts.d.ts +506 -0
  51. package/node_modules/@engenty-wizards/shared/dist/runner-texts.js +483 -0
  52. package/node_modules/@engenty-wizards/shared/dist/texts.d.ts +11 -2
  53. package/node_modules/@engenty-wizards/shared/dist/texts.js +16 -8
  54. package/node_modules/@engenty-wizards/shared/dist/translation.d.ts +23 -0
  55. package/node_modules/@engenty-wizards/shared/dist/translation.js +154 -0
  56. package/package.json +1 -1
  57. package/apps/web/dist/assets/ChatView-DIDIR0mb.js +0 -10
  58. package/apps/web/dist/assets/EditorPage-BYysznX3.js +0 -3
  59. package/apps/web/dist/assets/OnboardingPage-DpZv9qEO.js +0 -1
  60. package/apps/web/dist/assets/ProjectPage-IQb9RFlm.js +0 -1
  61. package/apps/web/dist/assets/PublicRunner-Da0klKj-.js +0 -1
  62. package/apps/web/dist/assets/RunDrawer-FwLK67Yn.js +0 -4
  63. package/apps/web/dist/assets/RunnerView-BBuphCkK.js +0 -1
  64. package/apps/web/dist/assets/SettingsPage-CZx52Ubk.js +0 -1
  65. package/apps/web/dist/assets/SetupPage-B-o7VhbI.js +0 -1
  66. package/apps/web/dist/assets/changelog-9oSWVuP-.js +0 -1
  67. package/apps/web/dist/assets/index-93fPRTxr.js +0 -14
  68. package/apps/web/dist/assets/ui-CeZNNuaK.js +0 -134
@@ -25,6 +25,25 @@ export declare function langOf(tag: string | null | undefined): Lang | null;
25
25
  * in; null where neither names one.
26
26
  */
27
27
  export declare function localLang(languages: readonly string[], timeZone?: string | null): Lang | null;
28
+ /**
29
+ * A language a wizard can be translated into: any language, by its two- or three-letter code
30
+ * ("fr", "it", "pl"), not only those of `LANGS`.
31
+ */
32
+ export declare const LANG_CODE: RegExp;
33
+ /** The code of a tag such as "fr-CA" or "pt_BR"; null where it names no language. */
34
+ export declare function langCodeOf(tag: string | null | undefined): string | null;
35
+ /**
36
+ * The language the person reads, for a wizard translated on request: the first of their
37
+ * languages (the browser's, in its order), else the main language of the country their time
38
+ * zone lies in. Any language, not only one engenty's own strings are written in.
39
+ */
40
+ export declare function viewerLang(languages: readonly string[], timeZone?: string | null): string | null;
41
+ /** A language's name in that language, as a switch shows it: "Italiano", "Polski". */
42
+ export declare function langName(code: string): string;
43
+ /** A language's name in English, for a model told what to write in: "Italian". */
44
+ export declare function langNameEn(code: string): string;
45
+ /** The locale amounts, dates and plural forms are written in for any language. */
46
+ export declare function localeOf(code: string): string;
28
47
  export declare const FIELD_KINDS: readonly ["text", "textarea", "number", "select", "multiselect", "date", "email", "url", "toggle", "color", "image", "file", "items", "connection", "list", "location", "audio", "signature", "slot"];
29
48
  export type FieldKind = (typeof FIELD_KINDS)[number];
30
49
  /**
@@ -140,6 +140,57 @@ export function localLang(languages, timeZone) {
140
140
  const found = country ? langOf(COUNTRY_LANGUAGE[country]) : null;
141
141
  return found === "en" ? null : found;
142
142
  }
143
+ /**
144
+ * A language a wizard can be translated into: any language, by its two- or three-letter code
145
+ * ("fr", "it", "pl"), not only those of `LANGS`.
146
+ */
147
+ export const LANG_CODE = /^[a-z]{2,3}$/;
148
+ /** The code of a tag such as "fr-CA" or "pt_BR"; null where it names no language. */
149
+ export function langCodeOf(tag) {
150
+ const code = tag?.trim().toLowerCase().split(/[-_]/)[0] ?? "";
151
+ return LANG_CODE.test(code) ? code : null;
152
+ }
153
+ /**
154
+ * The language the person reads, for a wizard translated on request: the first of their
155
+ * languages (the browser's, in its order), else the main language of the country their time
156
+ * zone lies in. Any language, not only one engenty's own strings are written in.
157
+ */
158
+ export function viewerLang(languages, timeZone) {
159
+ for (const tag of languages) {
160
+ const code = langCodeOf(tag);
161
+ if (code) {
162
+ return code;
163
+ }
164
+ }
165
+ const country = timeZone ? ZONE_COUNTRY[timeZone] : undefined;
166
+ return country ? langCodeOf(COUNTRY_LANGUAGE[country]) : null;
167
+ }
168
+ /** A language's name in that language, as a switch shows it: "Italiano", "Polski". */
169
+ export function langName(code) {
170
+ if (isLang(code)) {
171
+ return LANG_NAMES[code];
172
+ }
173
+ try {
174
+ const name = new Intl.DisplayNames([code], { type: "language" }).of(code) ?? code;
175
+ return name.charAt(0).toLocaleUpperCase(code) + name.slice(1);
176
+ }
177
+ catch {
178
+ return code.toUpperCase();
179
+ }
180
+ }
181
+ /** A language's name in English, for a model told what to write in: "Italian". */
182
+ export function langNameEn(code) {
183
+ try {
184
+ return new Intl.DisplayNames(["en"], { type: "language" }).of(code) ?? code;
185
+ }
186
+ catch {
187
+ return code;
188
+ }
189
+ }
190
+ /** The locale amounts, dates and plural forms are written in for any language. */
191
+ export function localeOf(code) {
192
+ return isLang(code) ? LOCALES[code] : code;
193
+ }
143
194
  export const FIELD_KINDS = [
144
195
  "text",
145
196
  "textarea",
@@ -1,7 +1,7 @@
1
- import type { CardOption, Format, Lang, ModelClass, Step, WizardDefinition } from "./definition.js";
1
+ import { type CardOption, type Format, type Lang, type ModelClass, type Step, type WizardDefinition } from "./definition.js";
2
2
  import type { ConnectionView, ListDef, ListRow } from "./store.js";
3
3
  import type { Surface } from "./surface.js";
4
- import { type Gap, type Texts } from "./texts.js";
4
+ import { type Gap, type Texts, type TextTable } from "./texts.js";
5
5
  export type RunStatus = "waiting_input" | "running" | "done" | "failed" | "cancelled";
6
6
  export interface AssetRef {
7
7
  id: string;
@@ -61,6 +61,11 @@ export interface RunState {
61
61
  * pages stay as they are; the copy goes with the run.
62
62
  */
63
63
  memory?: Record<string, string>;
64
+ /**
65
+ * Finished results translated on request, by language and step: the text the person reads in
66
+ * place of the step's own (`StepOutput.text`); the step's output stays as it was made.
67
+ */
68
+ translated?: Record<string, Record<string, string>>;
64
69
  }
65
70
  /** What a decision over a step's `ask` branches found. */
66
71
  export interface BranchDecision {
@@ -225,6 +230,9 @@ declare const NOTES_EN: {
225
230
  readonly filmFix: "The film didn’t render – Claude Code is fixing it";
226
231
  readonly filmResume: "Picking the film up where it stopped";
227
232
  readonly wizardUnavailable: "This wizard isn’t available right now.";
233
+ readonly translationFailed: "This wizard can’t be translated right now. It’s shown as it was written.";
234
+ readonly translationOff: "This wizard is only offered as it was written.";
235
+ readonly translationPlaceholder: "The translation of “{text}” needs every placeholder in curly brackets the original has.";
228
236
  readonly wizardLimit: "This wizard has reached its limit for today. Try again tomorrow.";
229
237
  readonly confirmHuman: "Confirm that you’re a person.";
230
238
  readonly tooManyRuns: "You’ve started a lot of runs just now. Try again in an hour.";
@@ -465,8 +473,11 @@ export type Said = string | RunNote;
465
473
  export declare function note(code: RunNoteCode, params?: Record<string, NoteGap | undefined>): RunNote;
466
474
  /** What is said, in a language. */
467
475
  export declare function saidText(said: Said, lang: Lang): string;
468
- /** A note in a language, its gaps filled; English where the language lacks the line. */
469
- export declare function noteText(note: RunNote, lang: Lang): string;
476
+ /**
477
+ * A note in a language, its gaps filled; English where the language lacks the line. A language
478
+ * outside `LANGS` reads its lines from `table`, the notes translated on request.
479
+ */
480
+ export declare function noteText(note: RunNote, lang: string, table?: TextTable): string;
470
481
  export interface RunEvent {
471
482
  id: number;
472
483
  at: string;
@@ -486,6 +497,12 @@ export interface RunView {
486
497
  wizard: Pick<WizardDefinition, "title" | "description" | "avatar" | "intro">;
487
498
  /** The language the wizard speaks: what is read aloud, and in which voice. */
488
499
  lang: Lang;
500
+ /**
501
+ * The run in the viewer's language (a wizard translated on request): every text of the view
502
+ * is written in it, the choices keep their values and show `labels[value]`. Null: the
503
+ * wizard's own words.
504
+ */
505
+ translation: RunTranslation | null;
489
506
  /** A live conversation can be started on this run: the runtime has a model for it and the wizard has live voice or video on (always in a test). */
490
507
  talk: boolean;
491
508
  /** The step the person is on (interactive) or the one running. */
@@ -539,6 +556,17 @@ export interface RunView {
539
556
  /** When the run and its shared link are deleted; null = kept. */
540
557
  expiresAt: string | null;
541
558
  }
559
+ /** How a run in the viewer's language shows. */
560
+ export interface RunTranslation {
561
+ /** The language, by its code ("fr"): any language, not only one of `LANGS`. */
562
+ lang: string;
563
+ /** What a choice shows, by its value. */
564
+ labels: Record<string, string>;
565
+ /** A model wrote some of it; false where the author wrote every text by hand. */
566
+ machine: boolean;
567
+ /** Results shown in this language, by step (`RunState.translated`). */
568
+ results: Record<string, string>;
569
+ }
542
570
  /** A shared result: what `/s/<token>` shows. Never the person's answers. */
543
571
  export interface ShareView {
544
572
  token: string;
@@ -577,6 +605,20 @@ export interface PublicWizard {
577
605
  kind: "page" | "channel";
578
606
  url: string | null;
579
607
  }[];
608
+ /** The language the wizard is written in: the page opens in it. */
609
+ lang: Lang;
610
+ /** The author offers the wizard in the viewer's language, translated on request. */
611
+ translatable: boolean;
612
+ /** The page in the viewer's language, where it was asked for (`?lang=`); null: the original. */
613
+ translation: Omit<RunTranslation, "results"> | null;
614
+ }
615
+ /** The runner's own words in a language outside `LANGS`: `GET /api/public/texts/:lang`. */
616
+ export interface UiTexts {
617
+ lang: string;
618
+ /** The runner's table (`packages/shared/src/runner-texts.ts`). */
619
+ runner: TextTable;
620
+ /** The run notes (`RUN_NOTES`). */
621
+ notes: TextTable;
580
622
  }
581
623
  /** What a step is expected to cost, in credits. `high` is the 90th percentile once measured. */
582
624
  export interface StepEstimate {
@@ -1,4 +1,6 @@
1
- import { textOf } from "./texts.js";
1
+ // SPDX-License-Identifier: FSL-1.1-MIT OR MIT
2
+ import { isLang, } from "./definition.js";
3
+ import { lineText, textOf } from "./texts.js";
2
4
  /**
3
5
  * What a step reports while it works, in words for each language: the runtime writes the English
4
6
  * line into the run's log, a runner shows it in the language the person reads. The runtime's
@@ -65,6 +67,9 @@ const NOTES_EN = {
65
67
  filmFix: "The film didn’t render – Claude Code is fixing it",
66
68
  filmResume: "Picking the film up where it stopped",
67
69
  wizardUnavailable: "This wizard isn’t available right now.",
70
+ translationFailed: "This wizard can’t be translated right now. It’s shown as it was written.",
71
+ translationOff: "This wizard is only offered as it was written.",
72
+ translationPlaceholder: "The translation of “{text}” needs every placeholder in curly brackets the original has.",
68
73
  wizardLimit: "This wizard has reached its limit for today. Try again tomorrow.",
69
74
  confirmHuman: "Confirm that you’re a person.",
70
75
  tooManyRuns: "You’ve started a lot of runs just now. Try again in an hour.",
@@ -350,6 +355,9 @@ const NOTES_DE = {
350
355
  filmFix: "Der Film ließ sich nicht rendern – Claude Code bessert nach",
351
356
  filmResume: "Macht dort weiter, wo der Film stehen geblieben ist",
352
357
  wizardUnavailable: "Dieser Wizard ist gerade nicht verfügbar.",
358
+ translationFailed: "Dieser Wizard lässt sich gerade nicht übersetzen. Du siehst ihn so, wie er geschrieben wurde.",
359
+ translationOff: "Diesen Wizard gibt es nur so, wie er geschrieben wurde.",
360
+ translationPlaceholder: "Die Übersetzung von „{text}“ braucht jeden Platzhalter in geschweiften Klammern, den das Original hat.",
353
361
  wizardLimit: "Für heute ist das Limit dieses Wizards erreicht. Versuch es morgen wieder.",
354
362
  confirmHuman: "Bestätige kurz, dass du ein Mensch bist.",
355
363
  tooManyRuns: "Du hast gerade viele Läufe gestartet. Versuch es in einer Stunde wieder.",
@@ -578,23 +586,30 @@ export function note(code, params) {
578
586
  export function saidText(said, lang) {
579
587
  return typeof said === "string" ? said : noteText(said, lang);
580
588
  }
581
- function gapIn(value, lang) {
589
+ function gapIn(value, lang, table) {
582
590
  if (Array.isArray(value)) {
583
- return value.map((item) => gapIn(item, lang));
591
+ return value.map((item) => gapIn(item, lang, table));
584
592
  }
585
593
  if (typeof value === "object" && value !== null && "code" in value) {
586
- return noteText(value, lang);
594
+ return noteText(value, lang, table);
587
595
  }
588
596
  return value;
589
597
  }
590
- /** A note in a language, its gaps filled; English where the language lacks the line. */
591
- export function noteText(note, lang) {
598
+ /**
599
+ * A note in a language, its gaps filled; English where the language lacks the line. A language
600
+ * outside `LANGS` reads its lines from `table`, the notes translated on request.
601
+ */
602
+ export function noteText(note, lang, table) {
592
603
  if (!(note.code in NOTES_EN)) {
593
604
  return "";
594
605
  }
595
606
  const params = {};
596
607
  for (const [key, value] of Object.entries(note.params ?? {})) {
597
- params[key] = value === undefined ? undefined : gapIn(value, lang);
608
+ params[key] = value === undefined ? undefined : gapIn(value, lang, table);
609
+ }
610
+ const own = table?.[note.code];
611
+ if (own !== undefined) {
612
+ return lineText(own, lang, params);
598
613
  }
599
- return textOf(RUN_NOTES, note.code, lang, params);
614
+ return textOf(RUN_NOTES, note.code, isLang(lang) ? lang : "en", params);
600
615
  }