wizards 0.2.26 → 0.2.28

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 (108) hide show
  1. package/apps/runtime/dist/agents/project-assistant.js +10 -1
  2. package/apps/runtime/dist/authoring/guide.js +7 -3
  3. package/apps/runtime/dist/connectors/plugin-connections.js +248 -0
  4. package/apps/runtime/dist/db/migrations/tenant/0010_plugin_connection.sql +15 -0
  5. package/apps/runtime/dist/db/migrations/tenant/meta/0010_snapshot.json +2942 -0
  6. package/apps/runtime/dist/db/migrations/tenant/meta/_journal.json +7 -0
  7. package/apps/runtime/dist/db/schema.js +21 -0
  8. package/apps/runtime/dist/engenty/connections-google/connectors/calendar.js +25 -3
  9. package/apps/runtime/dist/engenty/connections-microsoft/outlook.js +29 -1
  10. package/apps/runtime/dist/engine/input.js +10 -1
  11. package/apps/runtime/dist/mcp/tools.js +5 -2
  12. package/apps/runtime/dist/plugins/loader.js +22 -1
  13. package/apps/runtime/dist/plugins/registry.js +10 -0
  14. package/apps/runtime/dist/routes/marketplace.js +2 -1
  15. package/apps/runtime/dist/routes/runs.js +11 -3
  16. package/apps/runtime/dist/routes/studio.js +3 -1
  17. package/apps/runtime/dist/services/marketplace.js +167 -5
  18. package/apps/runtime/dist/services/runs.js +43 -15
  19. package/apps/runtime/dist/services/wizards.js +4 -2
  20. package/apps/runtime/dist/tools/plugin.js +29 -1
  21. package/apps/web/dist/assets/Account-CVMSZTCv.js +1 -0
  22. package/apps/web/dist/assets/{ChangelogDialog-CdtQWq0m.js → ChangelogDialog-3N1CgtWP.js} +1 -1
  23. package/apps/web/dist/assets/CreditsDialog-BW-RETl-.js +1 -0
  24. package/apps/web/dist/assets/EditorPage-DnuHM3nW.js +3 -0
  25. package/apps/web/dist/assets/{FlowPreview-IZcNrBJi.js → FlowPreview-Ds6ul7-N.js} +1 -1
  26. package/apps/web/dist/assets/{Harness-Cj-k02TA.js → Harness-D-QoXcSe.js} +2 -2
  27. package/apps/web/dist/assets/HomePage-Ch0HlwVX.js +1 -0
  28. package/apps/web/dist/assets/ImportWizard-DVcYcB6l.js +1 -0
  29. package/apps/web/dist/assets/LocalRuntime-D7bzT40S.js +1 -0
  30. package/apps/web/dist/assets/NewWizardPage-DvA6AX7D.js +2 -0
  31. package/apps/web/dist/assets/ProjectPage-BWAISSfX.js +2 -0
  32. package/apps/web/dist/assets/PublicRunner-D2bd95TR.js +1 -0
  33. package/apps/web/dist/assets/RunDrawer-DkOCgXAR.js +4 -0
  34. package/apps/web/dist/assets/RunnerView-DF5uW_95.js +2 -0
  35. package/apps/web/dist/assets/SettingsPage-CMTGFXit.js +1 -0
  36. package/apps/web/dist/assets/SetupPage-BaT-VqIc.js +1 -0
  37. package/apps/web/dist/assets/{SharePage-70niRKaO.js → SharePage-COKOsuvD.js} +1 -1
  38. package/apps/web/dist/assets/arrow-right-hy38IBRU.js +1 -0
  39. package/apps/web/dist/assets/changelog-C8wFW63z.js +1 -0
  40. package/apps/web/dist/assets/circle-alert-BG9P3ewL.js +1 -0
  41. package/apps/web/dist/assets/definition-BiUSuZN5.js +1 -0
  42. package/apps/web/dist/assets/esm-0rdZWuyu.js +7 -0
  43. package/apps/web/dist/assets/external-link-BwCtn1nW.js +1 -0
  44. package/apps/web/dist/assets/image-DG4q2P1H.js +1 -0
  45. package/apps/web/dist/assets/index-BOp2fz-2.css +1 -0
  46. package/apps/web/dist/assets/index-DHM9S48l.js +78 -0
  47. package/apps/web/dist/assets/lock-DH_BntP_.js +1 -0
  48. package/apps/web/dist/assets/meta-DI0ahJ_z.js +1 -0
  49. package/apps/web/dist/assets/pen-line-B1dsy3Sr.js +1 -0
  50. package/apps/web/dist/assets/refresh-cw-B9M1g3SH.js +1 -0
  51. package/apps/web/dist/assets/settings-menu-DOjgaq6J.js +1 -0
  52. package/apps/web/dist/assets/star-axQV_3EC.js +1 -0
  53. package/apps/web/dist/assets/surface-BE-3Z1DP.js +56 -0
  54. package/apps/web/dist/assets/trash-3S1_XpVa.js +1 -0
  55. package/apps/web/dist/assets/ui-BZ01zr3i.js +9 -0
  56. package/apps/web/dist/assets/upload-U0i8fAW3.js +1 -0
  57. package/apps/web/dist/assets/video-Db4o719f.js +1 -0
  58. package/apps/web/dist/assets/volume-2-6f7qN_LM.js +1 -0
  59. package/apps/web/dist/assets/wand-sparkles-MelvBtiK.js +1 -0
  60. package/apps/web/dist/index.html +4 -5
  61. package/apps/web/dist/mcp/flow.html +57 -57
  62. package/node_modules/@engenty-wizards/plugin-sdk/dist/index.d.ts +85 -0
  63. package/node_modules/@engenty-wizards/plugin-sdk/dist/studio.d.ts +23 -0
  64. package/node_modules/@engenty-wizards/shared/dist/definition.d.ts +28 -1
  65. package/node_modules/@engenty-wizards/shared/dist/definition.js +85 -5
  66. package/node_modules/@engenty-wizards/shared/dist/marketplace-search.js +4 -1
  67. package/node_modules/@engenty-wizards/shared/dist/marketplace.d.ts +43 -1
  68. package/node_modules/@engenty-wizards/shared/dist/marketplace.js +27 -0
  69. package/package.json +1 -1
  70. package/apps/web/dist/assets/Account-Cnksw5Ea.js +0 -1
  71. package/apps/web/dist/assets/CreditsDialog-Ti43boCN.js +0 -1
  72. package/apps/web/dist/assets/EditorPage-N7EzlRSj.js +0 -3
  73. package/apps/web/dist/assets/HomePage-bjdKkt84.js +0 -1
  74. package/apps/web/dist/assets/ImportWizard-DagFXYPM.js +0 -1
  75. package/apps/web/dist/assets/LocalRuntime-Boi_zqQJ.js +0 -1
  76. package/apps/web/dist/assets/NewWizardPage-DO5J8OpZ.js +0 -2
  77. package/apps/web/dist/assets/ProjectPage-DdG9wYsd.js +0 -2
  78. package/apps/web/dist/assets/PublicRunner-B4ts9rT6.js +0 -1
  79. package/apps/web/dist/assets/RunDrawer-LnVfCiYO.js +0 -4
  80. package/apps/web/dist/assets/RunnerView-DwffK7AA.js +0 -70
  81. package/apps/web/dist/assets/SettingsPage-Cyx_jTlp.js +0 -1
  82. package/apps/web/dist/assets/SetupPage-CBDD4rpC.js +0 -1
  83. package/apps/web/dist/assets/api-C4M6cbpW.js +0 -10
  84. package/apps/web/dist/assets/arrow-right-6FyN3e7D.js +0 -1
  85. package/apps/web/dist/assets/changelog-COyL1B5X.js +0 -1
  86. package/apps/web/dist/assets/check-CUpby_J9.js +0 -1
  87. package/apps/web/dist/assets/chevron-down-DymW-2BP.js +0 -1
  88. package/apps/web/dist/assets/circle-alert-D2SCwFT-.js +0 -1
  89. package/apps/web/dist/assets/createLucideIcon-q3MZMmnf.js +0 -1
  90. package/apps/web/dist/assets/definition-DoCLtZZL.js +0 -55
  91. package/apps/web/dist/assets/esm-CfW8Rmtq.js +0 -7
  92. package/apps/web/dist/assets/external-link-MAL7vJYj.js +0 -1
  93. package/apps/web/dist/assets/image-CC_2mJd6.js +0 -1
  94. package/apps/web/dist/assets/index-CJ0YJ5HC.css +0 -1
  95. package/apps/web/dist/assets/index-DMKXnSf-.js +0 -10
  96. package/apps/web/dist/assets/lock-DZL2N67v.js +0 -1
  97. package/apps/web/dist/assets/meta-6jZygxJq.js +0 -1
  98. package/apps/web/dist/assets/pen-line-NK46C_nG.js +0 -1
  99. package/apps/web/dist/assets/plus-Du-Jx8aI.js +0 -1
  100. package/apps/web/dist/assets/refresh-cw-BNtHis1x.js +0 -1
  101. package/apps/web/dist/assets/settings-menu-Dph4yXbO.js +0 -1
  102. package/apps/web/dist/assets/star-UHmZXpjA.js +0 -1
  103. package/apps/web/dist/assets/trash-0IafyhZB.js +0 -1
  104. package/apps/web/dist/assets/ui-BS348L4M.js +0 -1
  105. package/apps/web/dist/assets/upload-DNRENWzQ.js +0 -1
  106. package/apps/web/dist/assets/video-9fDPRPCv.js +0 -1
  107. package/apps/web/dist/assets/volume-2-DE67_rue.js +0 -1
  108. package/apps/web/dist/assets/wand-sparkles-IEd4jkyn.js +0 -1
@@ -77,8 +77,11 @@ export interface PluginStepContext {
77
77
  name: string;
78
78
  };
79
79
  wizard: {
80
+ id: string;
80
81
  title: string;
81
82
  };
83
+ /** "test": a test run from the studio. Keep what it makes apart from what real runs make. */
84
+ mode: "test" | "live";
82
85
  /** Aborted when the run is cancelled. */
83
86
  signal: AbortSignal;
84
87
  /** Tells the person what the step is doing right now. */
@@ -453,6 +456,82 @@ export interface PluginPublicRoute {
453
456
  path: string;
454
457
  handler(request: PluginPublicRequest): unknown | Promise<unknown>;
455
458
  }
459
+ /** An account a plugin connected for a space: a calendar, a mailbox. */
460
+ export interface PluginConnection {
461
+ id: string;
462
+ /** The space it was connected for. */
463
+ space: string;
464
+ /** The built-in connector behind it: `google-calendar`, `microsoft-outlook`. */
465
+ connector: string;
466
+ /** The account, as the provider names it: an e-mail address. */
467
+ label: string;
468
+ /** The actions it was connected for; the provider granted what they need. */
469
+ actions: string[];
470
+ createdAt: string;
471
+ }
472
+ /**
473
+ * Accounts a plugin connects on its own, for a space rather than for a wizard's run: the
474
+ * runtime's built-in connectors (Google, Microsoft, …), signed in with OAuth. The runtime keeps
475
+ * the tokens sealed, refreshes them, and on a local install connects Google through the linked
476
+ * account's Manage-App, as it does for wizards.
477
+ */
478
+ export interface PluginConnections {
479
+ /** Of these connector ids, the ones a person can connect on this runtime now, with their names. */
480
+ available(connectors: string[]): Promise<{
481
+ id: string;
482
+ name: string;
483
+ }[]>;
484
+ /**
485
+ * The provider's sign-in page. Open it in a window: when the person is done, the window posts
486
+ * `{ type: "wizards:connected", ok }` to the studio and closes. `actions` are the connector's
487
+ * actions the plugin will call; only the rights they need are asked for.
488
+ */
489
+ start(input: {
490
+ space: string;
491
+ connector: string;
492
+ actions: string[];
493
+ }): Promise<{
494
+ url: string;
495
+ }>;
496
+ /** What is connected for the space, the newest first. */
497
+ list(space: string): Promise<PluginConnection[]>;
498
+ /** One connection by its id, or null. */
499
+ get(connectionId: string): Promise<PluginConnection | null>;
500
+ /**
501
+ * Runs one of the connector's actions with the connection's account. Throws when the action
502
+ * is not one the connection was made for, or when the provider refuses (the account was
503
+ * disconnected there: connect again).
504
+ */
505
+ call<T = unknown>(connectionId: string, action: string, input: Record<string, unknown>): Promise<T>;
506
+ /** Forgets the connection and its tokens. */
507
+ remove(connectionId: string): Promise<void>;
508
+ }
509
+ /**
510
+ * A wizard a plugin brings as a template: offered beside the marketplace's starters when a
511
+ * wizard is made, and to the assistant and AI apps as an example to copy.
512
+ */
513
+ export interface PluginStarter {
514
+ /** Lower case, digits and `-`; the starter is known as `<plugin id>.<id>`. */
515
+ id: string;
516
+ title: string;
517
+ /** What it makes, in one or two sentences. */
518
+ description: string;
519
+ /** The language its texts are in. Default: German. */
520
+ language?: "de" | "en";
521
+ /** A complete wizard definition. Checked when it is registered. */
522
+ definition: unknown;
523
+ /** Workspace files it needs (widgets, sample data), by path. */
524
+ files?: Record<string, string | Uint8Array>;
525
+ }
526
+ /**
527
+ * What the space assistant is told when the admin talks to it from the plugin's own page (the
528
+ * studio half's `studio.Assistant`): what the page holds now, so it can change it with the
529
+ * plugin's assistant tools.
530
+ */
531
+ export interface PluginAssistantPage {
532
+ /** Text for the assistant: the state of the page, in a few lines. Cut at 8,000 characters. */
533
+ block(space: PluginSpace): string | null | Promise<string | null>;
534
+ }
456
535
  export interface PluginServerApi {
457
536
  registerHttpRoute(route: PluginRoute): void;
458
537
  registerTool<S extends z.ZodType>(tool: PluginTool<S>): void;
@@ -460,6 +539,8 @@ export interface PluginServerApi {
460
539
  registerSpaceContext(context: PluginSpaceContext): void;
461
540
  /** A tool of the space assistant. */
462
541
  registerAssistantTool<S extends z.ZodType>(tool: PluginAssistantTool<S>): void;
542
+ /** What the space assistant is told when the admin talks to it from the plugin's own page. */
543
+ registerAssistantContext(context: PluginAssistantPage): void;
463
544
  registerPublicRoute(route: PluginPublicRoute): void;
464
545
  /** The full address of a public route for the current tenant: what to hand to whoever calls it. */
465
546
  publicUrl(path: string): Promise<string>;
@@ -491,6 +572,10 @@ export interface PluginServerApi {
491
572
  * status 503 and the code `no_model`, which a route passes on as it is.
492
573
  */
493
574
  generate<T = undefined>(request: PluginGenerateRequest<T>): Promise<PluginGenerateResult<T>>;
575
+ /** Accounts the plugin connects for a space, through the runtime's built-in connectors. */
576
+ connections: PluginConnections;
577
+ /** A wizard the plugin brings as a template. */
578
+ registerStarter(starter: PluginStarter): void;
494
579
  /** Something to undo when the plugin unloads or reloads: a timer, a socket. */
495
580
  onUnload(dispose: () => void | Promise<void>): void;
496
581
  }
@@ -80,6 +80,15 @@ export interface StudioSpace {
80
80
  /** Synced from a local install, or on a runtime where nothing is built: shown, not changed. */
81
81
  readOnly: boolean;
82
82
  }
83
+ /** The space assistant on a plugin's page: what it says before the first message. */
84
+ export interface StudioAssistantProps {
85
+ title?: string;
86
+ hello?: string;
87
+ /** The input's placeholder: an example of what to ask. */
88
+ placeholder?: string;
89
+ /** The assistant changed something: read the page's data again. */
90
+ onChanged?: () => void;
91
+ }
83
92
  export interface StudioMe {
84
93
  user: {
85
94
  id: string;
@@ -109,6 +118,20 @@ export interface StudioPluginContext {
109
118
  * again when the person picks another space.
110
119
  */
111
120
  useSpace(): StudioSpace | null;
121
+ /**
122
+ * A hook: where the page stands, as the trail after the logo in the top bar ("Termine /
123
+ * Kalender"), said there instead of a heading of the page's own. Set while the page is shown.
124
+ */
125
+ useCrumbs(items: {
126
+ label: string;
127
+ to?: string;
128
+ }[]): void;
129
+ /**
130
+ * The space assistant, docked at the lower edge of a page of the plugin, as on the space page.
131
+ * It talks from the plugin's page: it gets what the server half's `registerAssistantContext`
132
+ * says and uses the plugin's assistant tools first. Place it once, anywhere in the page.
133
+ */
134
+ Assistant: ComponentType<StudioAssistantProps>;
112
135
  i18n: {
113
136
  /** Takes the plugin's words and gives the function that reads them in the language in effect. */
114
137
  register<M extends StudioMessages>(messages: M): (key: keyof M["de"] & string, vars?: Record<string, string | number>) => string;
@@ -3,7 +3,7 @@ import { type SurfaceComponent } from "./surface.js";
3
3
  /** The engenty avatars a wizard can wear. Same cast as engenty's ui-core. */
4
4
  export declare const ENGENTY_KINDS: readonly ["round", "drop", "dome", "flame", "oval", "bean", "pebble", "sprout", "tower", "wedge"];
5
5
  export type EngentyKind = (typeof ENGENTY_KINDS)[number];
6
- export declare const FIELD_KINDS: readonly ["text", "textarea", "number", "select", "multiselect", "date", "email", "url", "toggle", "color", "image", "file", "items", "connection", "list", "location", "audio", "signature"];
6
+ 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"];
7
7
  export type FieldKind = (typeof FIELD_KINDS)[number];
8
8
  /**
9
9
  * What a `location` field holds: where the person stands (from the device), a place they typed,
@@ -143,6 +143,7 @@ export declare const fieldSchema: z.ZodObject<{
143
143
  location: "location";
144
144
  audio: "audio";
145
145
  signature: "signature";
146
+ slot: "slot";
146
147
  }>;
147
148
  required: z.ZodOptional<z.ZodBoolean>;
148
149
  placeholder: z.ZodOptional<z.ZodString>;
@@ -282,6 +283,7 @@ export declare const pageStepSchema: z.ZodObject<{
282
283
  location: "location";
283
284
  audio: "audio";
284
285
  signature: "signature";
286
+ slot: "slot";
285
287
  }>;
286
288
  required: z.ZodOptional<z.ZodBoolean>;
287
289
  placeholder: z.ZodOptional<z.ZodString>;
@@ -952,6 +954,7 @@ export declare const stepSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
952
954
  location: "location";
953
955
  audio: "audio";
954
956
  signature: "signature";
957
+ slot: "slot";
955
958
  }>;
956
959
  required: z.ZodOptional<z.ZodBoolean>;
957
960
  placeholder: z.ZodOptional<z.ZodString>;
@@ -1873,6 +1876,7 @@ export declare const wizardSchema: z.ZodObject<{
1873
1876
  location: "location";
1874
1877
  audio: "audio";
1875
1878
  signature: "signature";
1879
+ slot: "slot";
1876
1880
  }>;
1877
1881
  required: z.ZodOptional<z.ZodBoolean>;
1878
1882
  placeholder: z.ZodOptional<z.ZodString>;
@@ -2563,6 +2567,29 @@ export declare function optionsFromData(ref: string, outputs: Record<string, {
2563
2567
  cells: Record<string, unknown>;
2564
2568
  }[];
2565
2569
  }>): string[];
2570
+ /** An offered appointment time read on its own clock: the offset it was written with. */
2571
+ export interface SlotTime {
2572
+ /** The calendar day there: "2026-10-12". */
2573
+ day: string;
2574
+ /** The time of day there: "09:00". */
2575
+ time: string;
2576
+ /** That day and time as if it were UTC — to name the weekday and month without moving it. */
2577
+ wall: Date;
2578
+ }
2579
+ /**
2580
+ * A slot option as day and time in its own offset (the business's time zone, not the reader's).
2581
+ * Null when it is not an ISO 8601 date-time with an offset.
2582
+ */
2583
+ export declare function slotTime(iso: string): SlotTime | null;
2584
+ /** The weekday and date of a slot's day: "Montag, 12. Oktober" / "Monday, 12 October". */
2585
+ export declare function slotDayText(iso: string, lang?: "de" | "en"): string;
2586
+ /** A chosen slot as a person reads it back: "Di 13.10.2026, 10:30" / "Tue 13/10/2026, 10:30". */
2587
+ export declare function slotText(iso: string, lang?: "de" | "en"): string;
2588
+ /**
2589
+ * The slot among `options` that is the same moment as `value`, written as offered — so an answer
2590
+ * in another offset ("…T07:00:00Z" for "…T09:00:00+02:00") picks the offered time.
2591
+ */
2592
+ export declare function offeredSlot(value: string, options: string[]): string | undefined;
2566
2593
  export interface ItemsTotals {
2567
2594
  rows: Record<string, unknown>[];
2568
2595
  net: number;
@@ -34,6 +34,7 @@ export const FIELD_KINDS = [
34
34
  "location",
35
35
  "audio",
36
36
  "signature",
37
+ "slot",
37
38
  ];
38
39
  export function isLocationValue(v) {
39
40
  if (!v || typeof v !== "object" || Array.isArray(v)) {
@@ -146,7 +147,10 @@ export const fieldSchema = z.object({
146
147
  required: z.boolean().optional(),
147
148
  placeholder: z.string().optional(),
148
149
  help: z.string().optional(),
149
- /** Choices for select / multiselect. */
150
+ /**
151
+ * Choices for select / multiselect. slot: the appointment times offered, as ISO 8601 date-times
152
+ * with their offset ("2026-10-12T09:00:00+02:00").
153
+ */
150
154
  options: z.array(z.string()).optional(),
151
155
  default: z.union([z.string(), z.number(), z.boolean(), z.array(z.string())]).optional(),
152
156
  /** Line-item columns for `items`. A row's amount is the product of its number and money columns. */
@@ -185,7 +189,7 @@ export const fieldSchema = z.object({
185
189
  */
186
190
  when: whenSchema.optional(),
187
191
  /**
188
- * select / multiselect: the choices come from earlier data — a list output
192
+ * select / multiselect / slot: the choices come from earlier data — a list output
189
193
  * ("steps.<id>.<key>"), a column of a table output ("steps.<id>.<key>.<column>") or a column
190
194
  * of a stored list ("lists.<id>.<column>"). `options` stand in while that data is empty.
191
195
  */
@@ -659,11 +663,20 @@ export function validateWizard(def, files) {
659
663
  issues.push({ stepId: step.id, message: `Duplicate field id "${field.id}".` });
660
664
  }
661
665
  fieldIds.add(field.id);
662
- if ((field.kind === "select" || field.kind === "multiselect") &&
666
+ if ((field.kind === "select" || field.kind === "multiselect" || field.kind === "slot") &&
663
667
  !field.options?.length &&
664
668
  !field.optionsFrom) {
665
669
  issues.push({ stepId: step.id, message: `Field "${field.id}" needs options.` });
666
670
  }
671
+ if (field.kind === "slot") {
672
+ const wrong = (field.options ?? []).find((o) => !slotTime(o));
673
+ if (wrong !== undefined) {
674
+ issues.push({
675
+ stepId: step.id,
676
+ message: `Field "${field.id}": "${wrong}" is not a date and time with its offset, like "2026-10-12T09:00:00+02:00".`,
677
+ });
678
+ }
679
+ }
667
680
  if (field.kind === "items" && !field.columns?.length) {
668
681
  issues.push({ stepId: step.id, message: `Field "${field.id}" needs columns.` });
669
682
  }
@@ -880,8 +893,8 @@ export function validateWizard(def, files) {
880
893
  issues.push(...conditionIssues(step.id, c));
881
894
  }
882
895
  if (field.optionsFrom) {
883
- const problem = field.kind !== "select" && field.kind !== "multiselect"
884
- ? `"optionsFrom" fills the choices of a select or multiselect; kind is "${field.kind}".`
896
+ const problem = field.kind !== "select" && field.kind !== "multiselect" && field.kind !== "slot"
897
+ ? `"optionsFrom" fills the choices of a select, multiselect or slot; kind is "${field.kind}".`
885
898
  : optionsFromProblem(field.optionsFrom);
886
899
  if (problem) {
887
900
  issues.push({ stepId: step.id, message: `Field "${field.id}": ${problem}` });
@@ -1333,6 +1346,73 @@ export function optionsFromData(ref, outputs, lists = {}) {
1333
1346
  }
1334
1347
  return [...seen];
1335
1348
  }
1349
+ // ---------------------------------------------------------------------------
1350
+ // Appointment times
1351
+ const SLOT_RE = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2})(?:\.\d+)?)?(Z|[+-]\d{2}:\d{2})$/;
1352
+ /**
1353
+ * A slot option as day and time in its own offset (the business's time zone, not the reader's).
1354
+ * Null when it is not an ISO 8601 date-time with an offset.
1355
+ */
1356
+ export function slotTime(iso) {
1357
+ const m = SLOT_RE.exec(iso.trim());
1358
+ if (!m) {
1359
+ return null;
1360
+ }
1361
+ const [, y, mo, d, h, mi] = m.map(Number);
1362
+ const wall = new Date(Date.UTC(y, mo - 1, d, h, mi));
1363
+ if (wall.getUTCMonth() !== mo - 1 ||
1364
+ wall.getUTCDate() !== d ||
1365
+ h > 23 ||
1366
+ mi > 59 ||
1367
+ !Number.isFinite(Date.parse(iso))) {
1368
+ return null;
1369
+ }
1370
+ return { day: `${m[1]}-${m[2]}-${m[3]}`, time: `${m[4]}:${m[5]}`, wall };
1371
+ }
1372
+ /** The weekday and date of a slot's day: "Montag, 12. Oktober" / "Monday, 12 October". */
1373
+ export function slotDayText(iso, lang = "de") {
1374
+ const slot = slotTime(iso);
1375
+ if (!slot) {
1376
+ return iso;
1377
+ }
1378
+ const locale = LOCALES[lang];
1379
+ const weekday = slot.wall.toLocaleDateString(locale, { weekday: "long", timeZone: "UTC" });
1380
+ const date = slot.wall.toLocaleDateString(locale, {
1381
+ day: "numeric",
1382
+ month: "long",
1383
+ timeZone: "UTC",
1384
+ });
1385
+ return `${weekday}, ${date}`;
1386
+ }
1387
+ /** A chosen slot as a person reads it back: "Di 13.10.2026, 10:30" / "Tue 13/10/2026, 10:30". */
1388
+ export function slotText(iso, lang = "de") {
1389
+ const slot = slotTime(iso);
1390
+ if (!slot) {
1391
+ return iso;
1392
+ }
1393
+ const locale = LOCALES[lang];
1394
+ const weekday = slot.wall
1395
+ .toLocaleDateString(locale, { weekday: "short", timeZone: "UTC" })
1396
+ .replace(/\.$/, "");
1397
+ const date = slot.wall.toLocaleDateString(locale, {
1398
+ day: "2-digit",
1399
+ month: "2-digit",
1400
+ year: "numeric",
1401
+ timeZone: "UTC",
1402
+ });
1403
+ return `${weekday} ${date}, ${slot.time}`;
1404
+ }
1405
+ /**
1406
+ * The slot among `options` that is the same moment as `value`, written as offered — so an answer
1407
+ * in another offset ("…T07:00:00Z" for "…T09:00:00+02:00") picks the offered time.
1408
+ */
1409
+ export function offeredSlot(value, options) {
1410
+ if (options.includes(value)) {
1411
+ return value;
1412
+ }
1413
+ const at = slotTime(value) ? Date.parse(value) : Number.NaN;
1414
+ return Number.isFinite(at) ? options.find((o) => slotTime(o) && Date.parse(o) === at) : undefined;
1415
+ }
1336
1416
  export function itemsTotals(field, value, values) {
1337
1417
  const rows = Array.isArray(value) ? value : [];
1338
1418
  const numeric = (field.columns ?? []).filter((c) => c.kind !== "text");
@@ -85,13 +85,15 @@ export function matchesFilters(e, f) {
85
85
  e.industries.includes(f.industry) ||
86
86
  (f.industry !== "any" && e.industries.includes("any"))) &&
87
87
  (!f.format || e.formats.includes(f.format)) &&
88
- (!f.capability || e.capabilities.includes(f.capability)));
88
+ (!f.capability || e.capabilities.includes(f.capability)) &&
89
+ (!f.plan || (e.plan ?? "free") === f.plan));
89
90
  }
90
91
  const FACETS = {
91
92
  useCase: (e) => e.useCases,
92
93
  industry: (e) => e.industries,
93
94
  format: (e) => e.formats,
94
95
  capability: (e) => e.capabilities,
96
+ plan: (e) => [e.plan ?? "free"],
95
97
  };
96
98
  /**
97
99
  * Per option of each filter, the found entries it would leave with the other filters as they
@@ -103,6 +105,7 @@ function facetsOf(all, found, filters) {
103
105
  industry: {},
104
106
  format: {},
105
107
  capability: {},
108
+ plan: {},
106
109
  };
107
110
  for (const key of Object.keys(FACETS)) {
108
111
  const options = new Set(all.flatMap(FACETS[key]));
@@ -1,4 +1,4 @@
1
- import type { WizardDefinition } from "./definition.js";
1
+ import { type WizardDefinition } from "./definition.js";
2
2
  /**
3
3
  * The marketplace: wizards anyone can start from. What an entry is sorted by — formats, industry,
4
4
  * use case — and what follows from its definition: the AI capabilities it needs, how much a
@@ -196,14 +196,34 @@ export declare const COST_TIERS: {
196
196
  };
197
197
  };
198
198
  export type CostTier = keyof typeof COST_TIERS;
199
+ /**
200
+ * The plan a wizard needs. Free runs on what every runtime has; Pro needs plugins, which come
201
+ * with the Pro and Team plans of engenty.ai.
202
+ */
203
+ export declare const MARKETPLACE_PLANS: {
204
+ free: {
205
+ de: string;
206
+ en: string;
207
+ };
208
+ pro: {
209
+ de: string;
210
+ en: string;
211
+ };
212
+ };
213
+ export type MarketplacePlan = keyof typeof MARKETPLACE_PLANS;
199
214
  export declare const ITEM_FORMAT_IDS: ("text" | "image" | "audio" | "video" | "document" | "dashboard" | "table")[];
200
215
  export declare const INDUSTRY_IDS: ("any" | "trades" | "gastronomy" | "hospitality" | "realEstate" | "retail" | "health" | "professional" | "agency" | "events" | "publicSector")[];
201
216
  export declare const USE_CASE_IDS: ("marketing" | "sales" | "accounting" | "service" | "research" | "hr" | "operations" | "website" | "visuals" | "inquiries" | "advice")[];
202
217
  export declare const CAPABILITY_IDS: ("code" | "text" | "image" | "browser" | "video" | "speech" | "film" | "web" | "documents" | "listening" | "connectors")[];
218
+ export declare const MARKETPLACE_PLAN_IDS: ("free" | "pro")[];
203
219
  /** The formats a run hands over, read from what the result step offers. */
204
220
  export declare function formatsOf(def: WizardDefinition): ItemFormat[];
205
221
  /** The capabilities a definition needs, read from its steps. */
206
222
  export declare function capabilitiesOf(def: WizardDefinition): Capability[];
223
+ /** The plugins a definition's steps use, by id: a runtime without one of them cannot run it. */
224
+ export declare function pluginsOf(def: WizardDefinition): string[];
225
+ /** The plan a wizard needs: Pro as soon as it uses a plugin. */
226
+ export declare const planOf: (plugins: readonly string[]) => MarketplacePlan;
207
227
  /** What a person does in a run, and about how long the whole run takes. */
208
228
  export interface Effort {
209
229
  /** Fields to fill in, the required ones of them. */
@@ -249,6 +269,18 @@ export interface MarketplaceSummary {
249
269
  steps: number;
250
270
  /** The definition version the entry's wizard is written in (`DEFINITION_VERSION`). */
251
271
  version: number;
272
+ /**
273
+ * The plugins its wizard uses, by id (`pluginsOf`). A marketplace older than this field leaves
274
+ * it out: read it as none.
275
+ */
276
+ plugins?: string[];
277
+ /** The plan it needs (`planOf`); left out by an older marketplace: free. */
278
+ plan?: MarketplacePlan;
279
+ /**
280
+ * The plugin's own starter this entry shows in the catalog, `<plugin id>.<starter id>`: a
281
+ * runtime with that plugin lists the plugin's starter instead.
282
+ */
283
+ pluginStarter?: string;
252
284
  }
253
285
  /** What a search narrows by, besides its words. */
254
286
  export interface MarketplaceFilters {
@@ -256,6 +288,7 @@ export interface MarketplaceFilters {
256
288
  industry?: Industry;
257
289
  format?: ItemFormat;
258
290
  capability?: Capability;
291
+ plan?: MarketplacePlan;
259
292
  }
260
293
  /** Per option of a filter: the entries it would leave, with the other filters as they are. */
261
294
  export interface MarketplaceFacets {
@@ -264,6 +297,8 @@ export interface MarketplaceFacets {
264
297
  format: Partial<Record<ItemFormat, number>>;
265
298
  /** Optional: a marketplace older than this filter leaves it out. */
266
299
  capability?: Partial<Record<Capability, number>>;
300
+ /** Optional: a marketplace older than this filter leaves it out. */
301
+ plan?: Partial<Record<MarketplacePlan, number>>;
267
302
  }
268
303
  /** A page of a search: the entries, best first, how many there are, and the filters' counts. */
269
304
  export interface MarketplacePage<T extends MarketplaceSummary = MarketplaceSummary> {
@@ -314,4 +349,11 @@ export interface MarketplaceEntry extends MarketplaceSummary {
314
349
  missing: Capability[];
315
350
  /** What only some of its paths need and this runtime has no model for: it runs the other ways. */
316
351
  optional: Capability[];
352
+ /** It comes with a plugin of this app, not from the marketplace: the plugin's id and name. */
353
+ plugin?: {
354
+ id: string;
355
+ name: string;
356
+ };
357
+ /** The plugins it needs that this app does not have: a wizard made from it would not run. */
358
+ needs?: string[];
317
359
  }
@@ -1,3 +1,4 @@
1
+ import { pluginToolOf } from "./definition.js";
1
2
  /**
2
3
  * The marketplace: wizards anyone can start from. What an entry is sorted by — formats, industry,
3
4
  * use case — and what follows from its definition: the AI capabilities it needs, how much a
@@ -63,11 +64,20 @@ export const COST_TIERS = {
63
64
  medium: { de: "mittel", en: "medium cost" },
64
65
  high: { de: "teuer", en: "high cost" },
65
66
  };
67
+ /**
68
+ * The plan a wizard needs. Free runs on what every runtime has; Pro needs plugins, which come
69
+ * with the Pro and Team plans of engenty.ai.
70
+ */
71
+ export const MARKETPLACE_PLANS = {
72
+ free: { de: "Kostenlos", en: "Free" },
73
+ pro: { de: "Pro", en: "Pro" },
74
+ };
66
75
  const keys = (o) => Object.keys(o);
67
76
  export const ITEM_FORMAT_IDS = keys(ITEM_FORMATS);
68
77
  export const INDUSTRY_IDS = keys(INDUSTRIES);
69
78
  export const USE_CASE_IDS = keys(USE_CASES);
70
79
  export const CAPABILITY_IDS = keys(CAPABILITIES);
80
+ export const MARKETPLACE_PLAN_IDS = keys(MARKETPLACE_PLANS);
71
81
  const FORMAT_OF = {
72
82
  pdf: "document",
73
83
  docx: "document",
@@ -164,6 +174,23 @@ export function capabilitiesOf(def) {
164
174
  }
165
175
  return CAPABILITY_IDS.filter((c) => found.has(c));
166
176
  }
177
+ /** The plugins a definition's steps use, by id: a runtime without one of them cannot run it. */
178
+ export function pluginsOf(def) {
179
+ const found = new Set();
180
+ for (const step of def.steps) {
181
+ if (step.type === "agent") {
182
+ for (const tool of step.tools) {
183
+ const of = pluginToolOf(tool);
184
+ if (of) {
185
+ found.add(of.plugin);
186
+ }
187
+ }
188
+ }
189
+ }
190
+ return [...found].sort();
191
+ }
192
+ /** The plan a wizard needs: Pro as soon as it uses a plugin. */
193
+ export const planOf = (plugins) => plugins.length ? "pro" : "free";
167
194
  const WORK_SECONDS = { agent: 25, tools: 70, browser: 150, image: 30, video: 120, voice: 20 };
168
195
  export function effortOf(def) {
169
196
  let fields = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wizards",
3
- "version": "0.2.26",
3
+ "version": "0.2.28",
4
4
  "description": "Make a wish. Get your wizard. It guides you step by step. Let AI do the work. Runs on your machine, on the AI subscription you already have.",
5
5
  "license": "FSL-1.1-MIT",
6
6
  "homepage": "https://engenty.ai",
@@ -1 +0,0 @@
1
- import{a as e,n as t,t as n}from"./jsx-runtime-D3jfb0Ew.js";import{c as r,j as i,n as a,nt as o}from"./api-C4M6cbpW.js";import{t as s}from"./createLucideIcon-q3MZMmnf.js";import{t as c}from"./check-CUpby_J9.js";import{n as l,r as u}from"./upload-DNRENWzQ.js";import{t as d}from"./external-link-MAL7vJYj.js";import{c as f,f as p,g as m,h,n as g,o as ee,r as _,s as v,t as y,x as b,y as x}from"./ui-BS348L4M.js";import{F as te,K as S,V as C,f as w,o as T,p as E,u as D,x as O}from"./index-DMKXnSf-.js";import{n as k}from"./LocalRuntime-Boi_zqQJ.js";var A={name:`hard-drive`,size:24,node:[[`path`,{d:`M10 16h.01`,key:`1bzywj`}],[`path`,{d:`M2.212 11.577a2 2 0 0 0-.212.896V18a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-5.527a2 2 0 0 0-.212-.896L18.55 5.11A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z`,key:`18tbho`}],[`path`,{d:`M21.946 12.013H2.054`,key:`zqlbp7`}],[`path`,{d:`M6 16h.01`,key:`1pmjb7`}]]};A.node;var j=s(A),M={name:`layout-grid`,size:24,node:[[`rect`,{width:`7`,height:`7`,x:`3`,y:`3`,rx:`1`,key:`1g98yp`}],[`rect`,{width:`7`,height:`7`,x:`14`,y:`3`,rx:`1`,key:`6d4xhi`}],[`rect`,{width:`7`,height:`7`,x:`14`,y:`14`,rx:`1`,key:`nxv5o0`}],[`rect`,{width:`7`,height:`7`,x:`3`,y:`14`,rx:`1`,key:`1bb6yr`}]]};M.node;var N=s(M),P={name:`list`,size:24,node:[[`path`,{d:`M3 5h.01`,key:`18ugdj`}],[`path`,{d:`M3 12h.01`,key:`nlz23k`}],[`path`,{d:`M3 19h.01`,key:`noohij`}],[`path`,{d:`M8 5h13`,key:`1pao27`}],[`path`,{d:`M8 12h13`,key:`1za7za`}],[`path`,{d:`M8 19h13`,key:`m83p4d`}]]};P.node;var F=s(P),I=e(t(),1),L=e=>[`project-files`,e];function R(e){return i({queryKey:L(e),queryFn:()=>a.get(`/api/studio/projects/${e}/files`),refetchInterval:e=>e.state.data?.files.some(e=>e.status===`pending`)?2e3:!1})}function z(e,t){return r(`/api/studio/projects/${e}/files/${t}/content`)}function B(e,t=!1){let n=o(),[r,i]=(0,I.useState)(!1),[s,c]=(0,I.useState)(null),l=()=>n.invalidateQueries({queryKey:L(e)}),u=async e=>{c(null);try{await e()}catch(e){c(e.message)}finally{await l()}};return{busy:r,error:s,readOnly:t,upload:async(t,n)=>{i(!0),await u(async()=>{for(let r of n)await a.upload(`/api/studio/projects/${e}/files?kind=${t}`,r),await l()}),i(!1)},describe:(t,n)=>u(()=>a.patch(`/api/studio/projects/${e}/files/${t}`,{description:n})),remove:t=>u(()=>a.del(`/api/studio/projects/${e}/files/${t}`)),reindex:t=>u(()=>a.post(`/api/studio/projects/${e}/files/${t}/reindex`)),order:(t,n)=>u(()=>a.put(`/api/studio/projects/${e}/files/order`,{kind:t,ids:n}))}}function V(e,t){let n=`wz.layout.${e}`,[r,i]=(0,I.useState)(()=>{try{let e=localStorage.getItem(n);return e===`list`||e===`cards`?e:t}catch{return t}});return[r,()=>i(e=>{let t=e===`list`?`cards`:`list`;try{localStorage.setItem(n,t)}catch{}return t})]}function H(e,t,n=700){let[r,i]=(0,I.useState)(`idle`),[a,o]=(0,I.useState)(null),s=JSON.stringify(e),c=(0,I.useRef)(s),l=(0,I.useRef)({value:e,json:s,save:t});l.current={value:e,json:s,save:t};let u=(0,I.useRef)(Promise.resolve()),d=(0,I.useCallback)(()=>{let e=l.current;e.json!==c.current&&(c.current=e.json,i(`saving`),u.current=u.current.then(async()=>{try{await e.save(e.value),o(null),i(`saved`)}catch(e){c.current=``,o(e.message),i(`error`)}}))},[]);return(0,I.useEffect)(()=>{if(s===c.current)return;let e=setTimeout(d,n);return()=>clearTimeout(e)},[s,n,d]),(0,I.useEffect)(()=>d,[d]),{state:r,error:a}}function U(e){return e<1e6?`${Math.max(1,Math.round(e/1e3))} KB`:`${(e/1e6).toFixed(1)} MB`}var W=e(n(),1);function G({id:e,children:t}){return(0,W.jsx)(`div`,{id:e,className:`scroll-mt-24 max-md:scroll-mt-36`,children:t})}function K({title:e,hint:t,save:n,action:r,locked:i,plain:a,children:o}){return(0,W.jsxs)(`section`,{className:`flex flex-col gap-2.5`,children:[(0,W.jsxs)(`div`,{className:`flex items-start justify-between gap-4 px-1`,children:[(0,W.jsxs)(`div`,{className:`min-w-0`,children:[(0,W.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,W.jsx)(`h2`,{className:`font-display font-semibold text-lg leading-tight`,children:e}),n?.state===`saving`?(0,W.jsxs)(`span`,{className:`inline-flex items-center gap-1.5 text-[0.75rem] text-ink-3`,children:[(0,W.jsx)(p,{className:`size-3`}),` `,b(`project.saving`)]}):n?.state===`saved`?(0,W.jsxs)(`span`,{className:`inline-flex items-center gap-1 text-[0.75rem] text-moss`,children:[(0,W.jsx)(c,{className:`size-3.5`}),` `,b(`settings.saved`)]}):null]}),t?(0,W.jsx)(`p`,{className:`mt-1 text-[0.875rem] text-ink-3 leading-snug`,children:t}):null]}),r?(0,W.jsx)(`div`,{className:`shrink-0`,children:r}):null]}),a?o:(0,W.jsxs)(g,{className:`p-3.5 sm:p-5`,children:[i?(0,W.jsx)(`fieldset`,{disabled:!0,className:`min-w-0`,children:o}):o,n?.state===`error`&&n.error?(0,W.jsx)(`p`,{className:`mt-4 text-[0.875rem] text-rose`,children:n.error}):null]})]})}function q({children:e,layout:t,onToggle:n}){return(0,W.jsxs)(`div`,{className:`mb-3 flex items-start gap-2`,children:[(0,W.jsx)(`div`,{className:`min-w-0 flex-1`,children:(0,W.jsx)(`div`,{className:`w-56 max-w-full transition-[width] duration-200 focus-within:w-full has-[input:not(:placeholder-shown)]:w-full`,children:e})}),(0,W.jsx)(ee,{label:b(t===`list`?`project.viewCards`:`project.viewList`),onClick:n,children:t===`list`?(0,W.jsx)(N,{className:`size-4`}):(0,W.jsx)(F,{className:`size-4`})})]})}function J({value:e,onChange:t,onEnter:n,placeholder:r,busy:i}){return(0,W.jsxs)(`div`,{className:`relative`,children:[(0,W.jsx)(l,{className:`-translate-y-1/2 pointer-events-none absolute top-1/2 left-3 size-4 text-ink-4`}),(0,W.jsx)(`input`,{type:`search`,value:e,placeholder:r,onChange:e=>t(e.target.value),onKeyDown:e=>e.key===`Enter`&&n?.(),className:`h-9 w-full rounded-lg border border-input bg-card pr-3 pl-9 text-[0.875rem] text-ink outline-none transition placeholder:text-ink-4 focus:border-focus focus:ring-4 focus:ring-focus-glow`}),i?(0,W.jsx)(p,{className:`-translate-y-1/2 absolute top-1/2 right-3 size-4 text-ink-3`}):null]})}function Y({onFiles:e,accept:t,multiple:n=!0,className:r,children:i}){return(0,W.jsxs)(`label`,{onDragOver:e=>{e.preventDefault(),e.currentTarget.dataset.over=`1`},onDragLeave:e=>{delete e.currentTarget.dataset.over},onDrop:t=>{t.preventDefault(),delete t.currentTarget.dataset.over;let r=Array.from(t.dataTransfer.files);r.length&&e(n?r:r.slice(0,1))},className:m(`flex cursor-pointer items-center justify-center gap-2 rounded-lg border border-input border-dashed text-[0.875rem] text-ink-3 transition focus-within:border-focus focus-within:ring-4 focus-within:ring-focus-glow hover:border-ink-4 hover:text-ink data-[over]:border-focus data-[over]:bg-paper-2 data-[over]:text-ink`,r),children:[i,(0,W.jsx)(`input`,{className:`sr-only`,type:`file`,accept:t,multiple:n,onChange:t=>{let n=Array.from(t.target.files??[]);t.target.value=``,n.length&&e(n)}})]})}var X=`mt-1.5 text-[0.8125rem] text-ink-3`;function Z(e){let t=o(),[n,r]=(0,I.useState)(!1),i=S({mutationFn:e=>a.post(`/api/studio/account/link`,e),onSuccess:({url:e})=>{k(e),r(!0)}});return(0,I.useEffect)(()=>{if(!n)return;let e=setInterval(()=>void t.invalidateQueries({queryKey:[`me`]}),2e3),i=setTimeout(()=>r(!1),3e5);return()=>{clearInterval(e),clearTimeout(i)}},[n,t]),(0,I.useEffect)(()=>{e&&r(!1)},[e]),{link:i,waiting:n}}function Q({link:e,waiting:t}){return e.isError?(0,W.jsx)(`p`,{className:`text-[0.8125rem] text-rose`,children:b(`local.accountFailed`)}):t?(0,W.jsxs)(`p`,{className:`flex items-center gap-2 text-[0.8125rem] text-ink-3`,children:[(0,W.jsx)(p,{className:`size-3.5`}),` `,b(`local.accountWaiting`)]}):null}function ne(){let e=Z(!1),{link:t}=e,[n,r]=(0,I.useState)(``);return(0,W.jsxs)(`div`,{className:`flex flex-col divide-y divide-border-soft`,children:[(0,W.jsxs)(`div`,{className:`flex items-start gap-4 py-5 first:pt-0 last:pb-0`,children:[(0,W.jsx)(`div`,{className:`flex size-11 shrink-0 items-center justify-center rounded-full bg-paper-2 text-ink-2`,children:(0,W.jsx)(j,{className:`size-5`})}),(0,W.jsxs)(`div`,{className:`min-w-0`,children:[(0,W.jsx)(`div`,{className:`font-medium text-[0.9375rem]`,children:b(`account.local`)}),(0,W.jsx)(`p`,{className:`mt-1 text-[0.875rem] text-ink-3 leading-relaxed`,children:b(`account.localText`)})]})]}),E.account?(0,W.jsxs)(`div`,{className:`flex flex-col gap-4 py-5 last:pb-0`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(`div`,{className:`font-medium text-[0.9375rem]`,children:b(`account.with`)}),(0,W.jsxs)(`ul`,{className:`mt-2 flex flex-col gap-2 text-[0.875rem] text-ink-2 leading-snug`,children:[(0,W.jsxs)(`li`,{className:`flex items-start gap-2.5`,children:[(0,W.jsx)(u,{className:`mt-0.5 size-4 shrink-0 text-amber`}),b(`account.withCredits`)]}),(0,W.jsxs)(`li`,{className:`flex items-start gap-2.5`,children:[(0,W.jsx)(C,{className:`mt-0.5 size-4 shrink-0 text-cobalt`}),b(`account.withCloud`)]})]})]}),(0,W.jsx)(`div`,{children:(0,W.jsx)(y,{busy:t.isPending&&!t.variables?.signup,onClick:()=>t.mutate({}),children:b(`account.signIn`)})})]}):null,E.account?(0,W.jsxs)(`form`,{className:`flex flex-col gap-3 py-5 last:pb-0`,onSubmit:e=>{e.preventDefault(),t.mutate({signup:!0,code:n.trim()||void 0})},children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(`div`,{className:`font-medium text-[0.9375rem]`,children:b(`account.new`)}),(0,W.jsx)(`p`,{className:`mt-1 text-[0.875rem] text-ink-3 leading-relaxed`,children:b(`account.newHint`)})]}),(0,W.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,W.jsx)(v,{value:n,maxLength:64,autoComplete:`off`,spellCheck:!1,placeholder:b(`account.code`),"aria-label":b(`account.code`),onChange:e=>r(e.target.value),className:`w-56 font-mono text-[0.875rem]`}),(0,W.jsx)(y,{type:`submit`,variant:`secondary`,className:`h-11`,busy:t.isPending&&!!t.variables?.signup,children:b(`account.create`)})]}),(0,W.jsx)(Q,{...e})]}):null]})}var $={start:`account.kind.start`,monthly:`account.kind.monthly`,gift:`account.kind.gift`};function re({account:e}){let t=o(),n=Z(e.signedIn),r=S({mutationFn:()=>a.del(`/api/studio/account`),onSuccess:()=>t.invalidateQueries({queryKey:[`me`]})}),i=new Intl.DateTimeFormat(x,{dateStyle:`medium`});return(0,W.jsxs)(`div`,{className:`flex flex-col divide-y divide-border-soft`,children:[(0,W.jsxs)(`div`,{className:`flex flex-wrap items-center gap-x-4 gap-y-3 py-5 first:pt-0`,children:[(0,W.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,W.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,W.jsx)(`span`,{className:`truncate font-medium text-[0.9375rem]`,children:e.name||e.email}),e.signedIn?(0,W.jsx)(_,{tone:`live`,children:b(`account.linked`)}):null]}),(0,W.jsx)(`div`,{className:`truncate text-[0.875rem] text-ink-3`,children:e.email})]}),(0,W.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,W.jsxs)(y,{variant:`secondary`,onClick:()=>k(e.url),children:[b(`setup.openAccount`),` `,(0,W.jsx)(d,{className:`size-4`})]}),(0,W.jsxs)(y,{variant:`ghost`,busy:r.isPending,onClick:()=>r.mutate(),children:[(0,W.jsx)(te,{className:`size-4`}),` `,b(`nav.logout`)]})]})]}),e.signedIn?null:(0,W.jsxs)(`div`,{className:`flex flex-col gap-3 py-5`,children:[(0,W.jsx)(`p`,{className:`text-[0.875rem] text-ink-2`,children:b(`local.accountExpired`)}),(0,W.jsx)(`div`,{children:(0,W.jsx)(y,{busy:n.link.isPending,onClick:()=>n.link.mutate({}),children:b(`account.signInAgain`)})}),(0,W.jsx)(Q,{...n})]}),e.credits===null?null:(0,W.jsxs)(`div`,{className:`py-5`,children:[(0,W.jsxs)(`div`,{className:`flex flex-wrap items-center gap-x-4 gap-y-3`,children:[(0,W.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,W.jsx)(`div`,{className:`text-[0.8125rem] text-ink-3`,children:b(`account.credits`)}),(0,W.jsx)(`div`,{className:`font-display font-semibold text-[1.375rem] tabular-nums leading-tight`,children:b(`nav.credits`,{n:Math.floor(e.credits).toLocaleString()})})]}),(0,W.jsxs)(y,{variant:`secondary`,onClick:()=>k(`${e.url}/billing`),children:[b(`account.topUp`),` `,(0,W.jsx)(d,{className:`size-4`})]})]}),e.expiring.length?(0,W.jsx)(`ul`,{className:`mt-3 flex flex-col gap-1 text-[0.8125rem] text-ink-3 tabular-nums`,children:e.expiring.map(e=>(0,W.jsxs)(`li`,{children:[b(`account.expires`,{n:Math.floor(e.credits).toLocaleString(),date:i.format(new Date(e.expiresAt))}),$[e.kind]?(0,W.jsxs)(`span`,{className:`text-ink-4`,children:[` · `,b($[e.kind])]}):null]},`${e.kind}:${e.expiresAt}`))}):null]}),(0,W.jsxs)(`div`,{className:`flex items-start gap-2.5 py-5 text-[0.875rem] text-ink-2 leading-snug last:pb-0`,children:[(0,W.jsx)(C,{className:`mt-0.5 size-4 shrink-0 text-cobalt`}),(0,W.jsx)(`p`,{children:b(`account.cloud`,{host:T(e.cloudUrl)})})]})]})}function ie({me:e,fromAccount:t}){let n=o(),[r,i]=(0,I.useState)(e.profile),s=e=>i(t=>({...t,...e})),c=H(r,async e=>{await a.put(`/api/studio/profile`,e),await n.invalidateQueries({queryKey:[`me`]})});return(0,W.jsx)(K,{title:b(`account.profile`),hint:b(`account.hint`),save:c,children:(0,W.jsxs)(`div`,{className:`flex flex-col gap-6 sm:flex-row sm:gap-8`,children:[(0,W.jsxs)(`div`,{className:`flex shrink-0 flex-col items-center gap-2 sm:w-32`,children:[(0,W.jsx)(`div`,{className:`flex size-20 items-center justify-center overflow-hidden rounded-full bg-ember-tint font-semibold text-[1.75rem] text-ember-strong ring-1 ring-border-soft`,children:e.user.image?(0,W.jsx)(`img`,{src:e.user.image,alt:``,className:`size-full object-cover`}):O(r.name)||`?`}),(0,W.jsx)(`p`,{className:`text-center text-[0.75rem] text-ink-3 leading-snug`,children:b(`account.initials`)})]}),(0,W.jsxs)(`div`,{className:`flex min-w-0 flex-1 flex-col gap-5`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(f,{children:b(`account.name`)}),(0,W.jsx)(v,{value:r.name,maxLength:80,disabled:t,onChange:e=>s({name:e.target.value})}),(0,W.jsx)(`p`,{className:X,children:b(t?`account.fromAccount`:`account.nameHint`)})]}),(0,W.jsxs)(`div`,{children:[(0,W.jsx)(f,{children:b(`account.about`)}),(0,W.jsx)(h,{minRows:3,maxLength:2e3,value:r.about,onChange:e=>s({about:e.target.value})}),(0,W.jsx)(`p`,{className:X,children:b(`account.aboutHint`)})]}),(0,W.jsxs)(`div`,{className:`grid gap-5 sm:grid-cols-2`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(f,{children:b(`account.email`)}),(0,W.jsx)(v,{type:`email`,value:r.email,maxLength:200,disabled:t,onChange:e=>s({email:e.target.value})})]}),(0,W.jsxs)(`div`,{children:[(0,W.jsx)(f,{children:b(`account.phone`)}),(0,W.jsx)(v,{type:`tel`,value:r.phone,maxLength:40,onChange:e=>s({phone:e.target.value})})]})]})]})]})})}function ae({me:e}){let t=e.mode===`managed`,n=t||!!e.account;return(0,W.jsxs)(`div`,{className:`flex flex-col gap-9`,children:[(0,W.jsx)(K,{title:b(`account.connection`),hint:b(`account.connectionHint`),children:t?(0,W.jsxs)(`div`,{className:`flex flex-wrap items-center gap-4`,children:[(0,W.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,W.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,W.jsx)(`span`,{className:`truncate font-medium text-[0.9375rem]`,children:e.user.name}),(0,W.jsx)(_,{tone:`live`,children:b(`account.linked`)})]}),(0,W.jsx)(`div`,{className:`truncate text-[0.875rem] text-ink-3`,children:e.user.email})]}),e.manageUrl?(0,W.jsxs)(y,{variant:`secondary`,onClick:()=>k(`${e.manageUrl}/account`),children:[b(`setup.openAccount`),` `,(0,W.jsx)(d,{className:`size-4`})]}):null]}):e.account?(0,W.jsx)(re,{account:e.account}):(0,W.jsx)(ne,{})}),(0,W.jsx)(ie,{me:e,fromAccount:n},n?`account`:`own`),(0,W.jsx)(K,{title:b(`account.look`),hint:b(`account.lookHint`),children:(0,W.jsxs)(`div`,{className:`flex flex-col divide-y divide-border-soft`,children:[(0,W.jsxs)(`div`,{className:`flex items-center justify-between gap-4 pb-4`,children:[(0,W.jsx)(`span`,{className:`font-medium text-[0.875rem]`,children:b(`nav.language`)}),(0,W.jsx)(w,{tone:`surface`})]}),(0,W.jsxs)(`div`,{className:`flex items-center justify-between gap-4 pt-4`,children:[(0,W.jsx)(`span`,{className:`font-medium text-[0.875rem]`,children:b(`nav.theme`)}),(0,W.jsx)(D,{})]})]})})]})}export{Y as a,K as c,H as d,B as f,N as h,G as i,U as l,R as m,Q as n,q as o,V as p,Z as r,J as s,ae as t,z as u};
@@ -1 +0,0 @@
1
- import{a as e,n as t,t as n}from"./jsx-runtime-D3jfb0Ew.js";import{t as r}from"./preload-helper-CNEI7N0N.js";import{t as i}from"./external-link-MAL7vJYj.js";import{a,f as o,i as s,s as c,x as l,y as u}from"./ui-BS348L4M.js";var d=e(t(),1),f=[{name:`engenty wizards`,description:{de:`KI-Wizards aus einer Beschreibung, mit einem Link geteilt.`,en:`AI wizards built from a description, shared with a link.`},homepage:`https://github.com/engenty/engenty-wizards`,license:`FSL-1.1-MIT`},{name:`engenty`,description:{de:`Konnektoren, Datentabellen, Suche und die Engenties stammen aus dem engenty-Framework.`,en:`Connectors, data tables, search and the engenties come from the engenty framework.`},homepage:`https://github.com/engenty/engenty`,license:`FSL-1.1-MIT`}],p=[{name:`Mastra`,description:{de:`Agent-Framework hinter den KI-Schritten.`,en:`Agent framework behind the AI steps.`},homepage:`https://github.com/mastra-ai/mastra`,license:`Apache-2.0`},{name:`AI SDK`,description:{de:`Modell-Aufrufe für Text, Bild, Video und Sprache.`,en:`Model calls for text, image, video and speech.`},homepage:`https://github.com/vercel/ai`,license:`Apache-2.0`},{name:`Model Context Protocol`,description:{de:`MCP-Server zum Bauen von Wizards, MCP-Client für Werkzeuge der Schritte.`,en:`MCP server for building wizards, MCP client for the steps' tools.`},homepage:`https://github.com/modelcontextprotocol/typescript-sdk`,license:`MIT`},{name:`Hono`,description:{de:`HTTP-API der Runtime.`,en:`The runtime's HTTP API.`},homepage:`https://github.com/honojs/hono`,license:`MIT`},{name:`Drizzle ORM`,description:{de:`Schema und Migrationen der Datenbanken.`,en:`Schema and migrations of the databases.`},homepage:`https://github.com/drizzle-team/drizzle-orm`,license:`Apache-2.0`},{name:`libSQL`,description:{de:`Eine Datenbank je Mandant, lokal als Datei oder bei Turso.`,en:`One database per tenant, a local file or at Turso.`},homepage:`https://github.com/tursodatabase/libsql`,license:`MIT`},{name:`Playwright`,description:{de:`Browser-Schritte sowie PDF- und PNG-Export.`,en:`Browser steps and the PDF and PNG export.`},homepage:`https://github.com/microsoft/playwright`,license:`Apache-2.0`},{name:`agentOS`,description:{de:`Sandbox für Code-Schritte ohne Docker.`,en:`Sandbox for code steps without Docker.`},homepage:`https://github.com/rivet-dev/agentos`,license:`Apache-2.0`},{name:`React`,description:{de:`UI-Bibliothek der Web-App.`,en:`UI library of the web app.`},homepage:`https://github.com/facebook/react`,license:`MIT`},{name:`Vite`,description:{de:`Build-Werkzeug der Web-App.`,en:`Build tool of the web app.`},homepage:`https://github.com/vitejs/vite`,license:`MIT`},{name:`Tailwind CSS`,description:{de:`Styling der Oberfläche.`,en:`Styling of the interface.`},homepage:`https://github.com/tailwindlabs/tailwindcss`,license:`MIT`},{name:`React Flow`,description:{de:`Das Diagramm der Schritte im Editor.`,en:`The diagram of steps in the editor.`},homepage:`https://github.com/xyflow/xyflow`,license:`MIT`},{name:`TanStack Query`,description:{de:`Server-Daten in der Web-App.`,en:`Server data in the web app.`},homepage:`https://github.com/TanStack/query`,license:`MIT`},{name:`xterm.js`,description:{de:`Das Terminal auf der Seite, in dem sich KI-Clients anmelden.`,en:`The terminal on the page where AI clients sign in.`},homepage:`https://github.com/xtermjs/xterm.js`,license:`MIT`},{name:`Lucide`,description:{de:`Icons.`,en:`Icons.`},homepage:`https://github.com/lucide-icons/lucide`,license:`ISC`},{name:`Geist & Geist Mono`,description:{de:`Schrift der Oberfläche.`,en:`Typeface of the interface.`},homepage:`https://github.com/vercel/geist-font`,license:`OFL-1.1`},{name:`Space Grotesk`,description:{de:`Schrift der Überschriften.`,en:`Typeface of the headings.`},homepage:`https://github.com/floriankarsten/space-grotesk`,license:`OFL-1.1`},{name:`git-cliff`,description:{de:`Erzeugt den Changelog aus den Commits.`,en:`Generates the changelog from the commits.`},homepage:`https://github.com/orhun/git-cliff`,license:`MIT OR Apache-2.0`}],m=e(n(),1),h=(e,...t)=>t.some(t=>t?.toLowerCase().includes(e));function g({name:e,homepage:t,version:n,license:r,description:a}){return(0,m.jsxs)(`li`,{className:`py-2.5`,children:[(0,m.jsxs)(`div`,{className:`flex flex-wrap items-baseline gap-x-2.5 gap-y-0.5`,children:[t?(0,m.jsxs)(`a`,{href:t,target:`_blank`,rel:`noreferrer`,className:`inline-flex items-center gap-1 font-medium text-[0.875rem] text-ink underline-offset-4 hover:underline`,children:[e,(0,m.jsx)(i,{"aria-hidden":!0,className:`size-3 text-ink-4`})]}):(0,m.jsx)(`span`,{className:`font-medium text-[0.875rem] text-ink`,children:e}),n?(0,m.jsx)(`span`,{className:`text-[0.75rem] text-ink-3 tabular-nums`,children:n}):null,(0,m.jsx)(`span`,{className:`text-[0.75rem] text-ink-3`,children:r})]}),a?(0,m.jsx)(`p`,{className:`mt-0.5 text-[0.8125rem] text-ink-3`,children:a}):null]})}function _({title:e,hint:t,children:n}){return(0,m.jsxs)(`section`,{className:`mt-6`,children:[(0,m.jsx)(`h3`,{className:`border-border-soft border-b pb-2 font-display font-semibold text-[1rem]`,children:e}),t?(0,m.jsx)(`p`,{className:`mt-2 text-[0.8125rem] text-ink-3`,children:t}):null,n]})}function v({credits:e}){return(0,m.jsx)(`ul`,{className:`divide-y divide-border-soft`,children:e.map(e=>(0,m.jsx)(g,{name:e.name,homepage:e.homepage,license:e.license,description:e.description[u]},e.name))})}function y({label:e,packages:t}){return(0,m.jsxs)(`div`,{className:`mt-4`,children:[(0,m.jsx)(`h4`,{className:`font-medium text-[0.75rem] text-ink-3 tracking-wide`,children:e}),(0,m.jsx)(`ul`,{className:`divide-y divide-border-soft`,children:t.map(e=>(0,m.jsx)(g,{...e},e.name))})]})}function b({open:e,onClose:t}){let[n,i]=(0,d.useState)(null),[u,g]=(0,d.useState)(``);(0,d.useEffect)(()=>{if(!e||n)return;let t=!1;return r(()=>import(`./oss-credits-CIxnNZor.js`).then(e=>{t||i(e.default)}),[]),()=>{t=!0}},[e,n]),(0,d.useEffect)(()=>{e||g(``)},[e]);let b=u.trim().toLowerCase(),x=e=>b?e.filter(e=>h(b,e.name,e.license,e.description.de,e.description.en)):e,S=e=>b?e.filter(e=>h(b,e.name,e.license,e.version)):e,C=x(f),w=x(p),T=n?[{id:`shared`,label:l(`about.creditsShared`),packages:S(n.shared)},...n.groups.map(e=>({id:e.id,label:e.label,packages:S(e.packages)}))].filter(e=>e.packages.length>0):[],E=C.length===0&&w.length===0&&T.length===0;return(0,m.jsxs)(s,{open:e,onClose:t,title:l(`about.credits`),wide:!0,children:[(0,m.jsx)(`p`,{className:`-mt-3 mb-4 text-[0.875rem] text-ink-3`,children:l(`about.creditsHint`)}),(0,m.jsx)(c,{type:`search`,value:u,placeholder:l(`about.search`),onChange:e=>g(e.target.value)}),C.length>0?(0,m.jsx)(_,{title:l(`about.creditsProduct`),children:(0,m.jsx)(v,{credits:C})}):null,w.length>0?(0,m.jsx)(_,{title:l(`about.creditsBuiltWith`),children:(0,m.jsx)(v,{credits:w})}):null,n===null?(0,m.jsx)(`div`,{className:`flex justify-center py-10 text-ink-3`,children:(0,m.jsx)(o,{})}):T.length>0?(0,m.jsx)(_,{title:l(`about.creditsDeps`),hint:b?void 0:l(`about.creditsDepsHint`),children:T.map(e=>(0,m.jsx)(y,{label:e.label,packages:e.packages},e.id))}):null,n!==null&&E?(0,m.jsx)(a,{children:l(`about.noMatches`)}):null]})}export{b as CreditsDialog};