wizards 0.1.11 → 0.2.1

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 (113) hide show
  1. package/README.md +3 -0
  2. package/apps/runtime/dist/agents/architect.js +6 -4
  3. package/apps/runtime/dist/app.js +38 -4
  4. package/apps/runtime/dist/auth/local-ticket.js +8 -5
  5. package/apps/runtime/dist/authoring/guide.js +10 -2
  6. package/apps/runtime/dist/cli/connect.js +531 -0
  7. package/apps/runtime/dist/cli/environment.js +8 -1
  8. package/apps/runtime/dist/cli/home.js +1 -0
  9. package/apps/runtime/dist/cli/main.js +17 -0
  10. package/apps/runtime/dist/cli/mcp.js +175 -0
  11. package/apps/runtime/dist/cli/setup.js +49 -0
  12. package/apps/runtime/dist/db/client.js +13 -0
  13. package/apps/runtime/dist/engine/runner.js +3 -0
  14. package/apps/runtime/dist/env.js +18 -4
  15. package/apps/runtime/dist/index.js +3 -0
  16. package/apps/runtime/dist/mcp/auth.js +26 -0
  17. package/apps/runtime/dist/mcp/flow-app.js +94 -0
  18. package/apps/runtime/dist/mcp/handler.js +15 -5
  19. package/apps/runtime/dist/mcp/seen.js +65 -0
  20. package/apps/runtime/dist/mcp/tools.js +158 -5
  21. package/apps/runtime/dist/plugins/discovery.js +144 -0
  22. package/apps/runtime/dist/plugins/events.js +40 -0
  23. package/apps/runtime/dist/plugins/loader.js +277 -0
  24. package/apps/runtime/dist/plugins/migrations.js +69 -0
  25. package/apps/runtime/dist/plugins/registry.js +105 -0
  26. package/apps/runtime/dist/routes/plugins.js +160 -0
  27. package/apps/runtime/dist/routes/runs.js +7 -3
  28. package/apps/runtime/dist/routes/studio.js +20 -0
  29. package/apps/runtime/dist/secrets/signing.js +21 -3
  30. package/apps/runtime/dist/services/runs.js +190 -28
  31. package/apps/runtime/dist/services/wizards.js +30 -4
  32. package/apps/runtime/dist/tools/index.js +2 -0
  33. package/apps/runtime/dist/tools/plugin.js +43 -0
  34. package/apps/web/dist/assets/ChangelogDialog-Co_9fs61.js +1 -0
  35. package/apps/web/dist/assets/ChatPanel-Br3nYkUc.js +1 -0
  36. package/apps/web/dist/assets/CreditsDialog-D3fZRqXH.js +1 -0
  37. package/apps/web/dist/assets/EditorPage-BSjQC6FE.js +2 -0
  38. package/apps/web/dist/assets/FlowPreview-CjUK5046.js +1 -0
  39. package/apps/web/dist/assets/HomePage-8v4HqIbP.js +1 -0
  40. package/apps/web/dist/assets/ImportWizard-DiV62Uno.js +1 -0
  41. package/apps/web/dist/assets/{LocalRuntime-DKqEzptp.js → LocalRuntime-CTyLGC98.js} +2 -2
  42. package/apps/web/dist/assets/NewWizardPage-BBL2yenw.js +2 -0
  43. package/apps/web/dist/assets/PublicRunner-BwtoEVlE.js +1 -0
  44. package/apps/web/dist/assets/RunnerView-DOizlTad.js +2 -0
  45. package/apps/web/dist/assets/SettingsPage-CBDv04YS.js +2 -0
  46. package/apps/web/dist/assets/SetupPage-CfXTOaIm.js +1 -0
  47. package/apps/web/dist/assets/SharePage-CgByqrAF.js +1 -0
  48. package/apps/web/dist/assets/api-KMi35npD.js +10 -0
  49. package/apps/web/dist/assets/{arrow-left-UpjOBfQp.js → arrow-left-hTN1VoH1.js} +1 -1
  50. package/apps/web/dist/assets/{arrow-right-CucQycEy.js → arrow-right-6FyN3e7D.js} +1 -1
  51. package/apps/web/dist/assets/changelog-03JgixQA.js +1 -0
  52. package/apps/web/dist/assets/check-CUpby_J9.js +1 -0
  53. package/apps/web/dist/assets/{createLucideIcon-DBu2Ovxj.js → createLucideIcon-q3MZMmnf.js} +1 -1
  54. package/apps/web/dist/assets/definition-DndaH5Ow.js +55 -0
  55. package/apps/web/dist/assets/engenty-Cm8yZLON.js +1 -0
  56. package/apps/web/dist/assets/esm-rJY59Ixx.js +7 -0
  57. package/apps/web/dist/assets/{external-link-CRg6DVdO.js → external-link-MAL7vJYj.js} +1 -1
  58. package/apps/web/dist/assets/{fluffy-engenty-CJ3wCQgT.js → fluffy-engenty-D7rFrNcJ.js} +2 -2
  59. package/apps/web/dist/assets/index-B9YVjvVY.css +1 -0
  60. package/apps/web/dist/assets/index-BmpnE7IO.js +10 -0
  61. package/apps/web/dist/assets/jsx-runtime-D3jfb0Ew.js +1 -0
  62. package/apps/web/dist/assets/meta-4R1Lnr25.js +1 -0
  63. package/apps/web/dist/assets/{mic-CeqQ89Dj.js → mic-Bvz4mA2j.js} +1 -1
  64. package/apps/web/dist/assets/oss-credits-roB62QJu.js +1 -0
  65. package/apps/web/dist/assets/{outputs-CHe6KRLc.js → outputs-COE_nvAw.js} +2 -2
  66. package/apps/web/dist/assets/plug-CLjyCoHB.js +1 -0
  67. package/apps/web/dist/assets/{plus-HA210wXA.js → plus-Du-Jx8aI.js} +1 -1
  68. package/apps/web/dist/assets/react-dom-DenslgJm.js +1 -0
  69. package/apps/web/dist/assets/session-B6-6VomQ.js +1 -0
  70. package/apps/web/dist/assets/type-Bj9H3eOK.js +1 -0
  71. package/apps/web/dist/assets/ui-Cs6lpsmj.js +1 -0
  72. package/apps/web/dist/assets/{upload-DsgLfQ3U.js → upload--J5bZhEM.js} +1 -1
  73. package/apps/web/dist/assets/{video-Dk1fuTDl.js → video-CjgmvRDk.js} +1 -1
  74. package/apps/web/dist/assets/{wand-sparkles-Bf97fs8T.js → wand-sparkles-CKxArWPY.js} +1 -1
  75. package/apps/web/dist/index.html +10 -7
  76. package/apps/web/dist/mcp/flow.html +748 -0
  77. package/modules/README.md +15 -0
  78. package/node_modules/@engenty-wizards/plugin-sdk/dist/index.d.ts +144 -0
  79. package/node_modules/@engenty-wizards/plugin-sdk/dist/index.js +4 -0
  80. package/node_modules/@engenty-wizards/plugin-sdk/dist/studio.d.ts +80 -0
  81. package/node_modules/@engenty-wizards/plugin-sdk/dist/studio.js +4 -0
  82. package/node_modules/@engenty-wizards/plugin-sdk/package.json +10 -0
  83. package/node_modules/@engenty-wizards/shared/dist/definition.d.ts +18 -6
  84. package/node_modules/@engenty-wizards/shared/dist/definition.js +22 -1
  85. package/package.json +6 -1
  86. package/plugin/.claude-plugin/plugin.json +1 -1
  87. package/plugin/skills/use-wizard/SKILL.md +18 -0
  88. package/apps/web/dist/assets/ChangelogDialog-DURK75KD.js +0 -1
  89. package/apps/web/dist/assets/ChatPanel-DZhZJZCP.js +0 -1
  90. package/apps/web/dist/assets/CreditsDialog-CLUOVBLG.js +0 -1
  91. package/apps/web/dist/assets/EditorPage-PGCEQdiC.js +0 -2
  92. package/apps/web/dist/assets/FlowPreview-CqJUNW13.js +0 -1
  93. package/apps/web/dist/assets/HomePage-CRkDMNM2.js +0 -1
  94. package/apps/web/dist/assets/ImportWizard-DX1YtFPv.js +0 -1
  95. package/apps/web/dist/assets/NewWizardPage-BPJrYi2m.js +0 -2
  96. package/apps/web/dist/assets/PublicRunner-B3T244Ry.js +0 -1
  97. package/apps/web/dist/assets/RunnerView-DgYaOHIH.js +0 -2
  98. package/apps/web/dist/assets/SettingsPage-LBVqEwXs.js +0 -2
  99. package/apps/web/dist/assets/SetupPage-DAyJs-hK.js +0 -1
  100. package/apps/web/dist/assets/SharePage-oKGavxJt.js +0 -1
  101. package/apps/web/dist/assets/api-DbPn6Dge.js +0 -10
  102. package/apps/web/dist/assets/changelog-BJkYErYt.js +0 -1
  103. package/apps/web/dist/assets/check-Bjx41xbB.js +0 -1
  104. package/apps/web/dist/assets/definition-cy7uvY5L.js +0 -55
  105. package/apps/web/dist/assets/engenty-CWIFpgKq.js +0 -1
  106. package/apps/web/dist/assets/esm-ZHEGGS6s.js +0 -7
  107. package/apps/web/dist/assets/index-BRy5sz4a.js +0 -10
  108. package/apps/web/dist/assets/index-CQ_q9iMO.css +0 -1
  109. package/apps/web/dist/assets/jsx-runtime-Dk72oS4N.js +0 -1
  110. package/apps/web/dist/assets/meta-2YMHa2hT.js +0 -1
  111. package/apps/web/dist/assets/oss-credits-cPuZUFHD.js +0 -1
  112. package/apps/web/dist/assets/type-BzYgVWKL.js +0 -1
  113. package/apps/web/dist/assets/ui-tO4ZXbfh.js +0 -1
@@ -0,0 +1,15 @@
1
+ # Modules
2
+
3
+ Plugins that ship with engenty wizards: every runtime loads what is in this folder, in a
4
+ checkout, in the npm package and in the Docker image. Each is a folder with an
5
+ `engenty.plugin.json`, as [docs/plugins.md](../docs/plugins.md) describes.
6
+
7
+ A module here is part of the open product. A plugin that is not goes into a folder of
8
+ `PLUGINS_DIR` instead.
9
+
10
+ - A module's server half may import what the runtime hands every plugin (the plugin SDK, `zod`,
11
+ `drizzle-orm`) and its own files. It has no `node_modules` of its own where it is installed.
12
+ - A module with a studio half is a workspace package whose `build` script is
13
+ `node ../../scripts/build-plugin.mjs .`, so `pnpm build` builds its `dist/`.
14
+ `apps/runtime/Dockerfile` copies each workspace package's `package.json` before it installs:
15
+ add the module's there.
@@ -0,0 +1,144 @@
1
+ import type { LibSQLDatabase } from "drizzle-orm/libsql";
2
+ import type { z } from "zod";
3
+ /**
4
+ * What the runtime hands a plugin's server half. A plugin is a file or a folder the runtime finds
5
+ * at start (docs/plugins.md); its default export is a factory that registers what it adds. The
6
+ * runtime remembers every registration under the plugin's id and takes it back when the plugin
7
+ * unloads or reloads.
8
+ */
9
+ /** `engenty.plugin.json`, the file an engenty module has too. A plugin of one file has none. */
10
+ export interface PluginManifest {
11
+ /** Lower case, digits and `-`: part of the plugin's addresses and of its tools' ids. */
12
+ id: string;
13
+ name: string;
14
+ version: string;
15
+ description?: string;
16
+ kind?: string;
17
+ provides?: string[];
18
+ requires?: string[];
19
+ /** The server half, from the plugin's folder. Default `src/plugin.ts`. */
20
+ server?: string;
21
+ /** The studio half, built. Default `dist/client.js`. */
22
+ studio?: string;
23
+ /** The studio half's styles, built. Default `dist/client.css`. */
24
+ styles?: string;
25
+ }
26
+ export type PluginRole = "owner" | "admin" | "member";
27
+ /** The signed-in person a request acts as. */
28
+ export interface PluginPrincipal {
29
+ id: string;
30
+ tenantId: string;
31
+ role: PluginRole;
32
+ name: string;
33
+ email: string;
34
+ }
35
+ export interface PluginRequest {
36
+ /** The web request as it came in. */
37
+ request: Request;
38
+ /** The address below the plugin's own: `/` for `/api/studio/plugins/<id>/`. */
39
+ path: string;
40
+ /** What `:name` parts of the route's path matched. */
41
+ params: Record<string, string>;
42
+ query: URLSearchParams;
43
+ user: PluginPrincipal;
44
+ /** The body as JSON; an empty body is `{}`. */
45
+ json<T = unknown>(): Promise<T>;
46
+ }
47
+ export type PluginHttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
48
+ /** A route below `/api/studio/plugins/<id>`: signed in, inside the person's tenant. */
49
+ export interface PluginRoute {
50
+ method: PluginHttpMethod;
51
+ /** `/`, `/items`, `/items/:id`. */
52
+ path: string;
53
+ /** `admin`: owners and admins only. Default: every member. */
54
+ role?: "member" | "admin";
55
+ /**
56
+ * Answers with a `Response`, or with a value that goes out as JSON. An error thrown with a
57
+ * `status` and a `code` goes out as `{ error, code }` with that status.
58
+ */
59
+ handler(request: PluginRequest): unknown | Promise<unknown>;
60
+ }
61
+ /** What a tool knows about the step that calls it. */
62
+ export interface PluginStepContext {
63
+ runId: string;
64
+ stepId: string;
65
+ tenantId: string;
66
+ project: {
67
+ id: string;
68
+ name: string;
69
+ };
70
+ wizard: {
71
+ title: string;
72
+ };
73
+ /** Aborted when the run is cancelled. */
74
+ signal: AbortSignal;
75
+ /** Tells the person what the step is doing right now. */
76
+ emit(message: string): Promise<void>;
77
+ }
78
+ /** A tool for agent steps. A step allowlists it as `<plugin id>.<name>`. */
79
+ export interface PluginTool<S extends z.ZodType = z.ZodType> {
80
+ /** Lower case, digits and `_`. */
81
+ name: string;
82
+ /** What the editor calls it; default: the name. */
83
+ title?: string;
84
+ /** For the model: what the tool does and when to use it. */
85
+ description: string;
86
+ inputSchema: S;
87
+ execute(input: z.infer<S>, ctx: PluginStepContext): unknown | Promise<unknown>;
88
+ }
89
+ /** A run that reached its end. It fires again when a finished run is redone and ends again. */
90
+ export interface PluginRunEvent {
91
+ run: {
92
+ id: string;
93
+ wizardId: string;
94
+ mode: "test" | "live";
95
+ status: "done" | "failed" | "cancelled";
96
+ };
97
+ wizard: {
98
+ id: string;
99
+ title: string;
100
+ projectId: string;
101
+ };
102
+ /** What the person answered, by field id. */
103
+ values: Record<string, unknown>;
104
+ }
105
+ export interface PluginEvents {
106
+ "run.done": PluginRunEvent;
107
+ "run.failed": PluginRunEvent;
108
+ "run.cancelled": PluginRunEvent;
109
+ }
110
+ /** The tenant's database. A plugin reads and writes its own tables with it. */
111
+ export type PluginDb = LibSQLDatabase<Record<string, never>>;
112
+ export interface PluginServerApi {
113
+ registerHttpRoute(route: PluginRoute): void;
114
+ registerTool<S extends z.ZodType>(tool: PluginTool<S>): void;
115
+ /**
116
+ * A folder of `.sql` files with the plugin's own tables. Every tenant database gets each file
117
+ * once, in the order of the file names. Nothing is taken back when the plugin unloads.
118
+ */
119
+ registerMigrations(folder: string): void;
120
+ /** The listener runs inside the tenant the event belongs to. */
121
+ on<E extends keyof PluginEvents>(event: E, listener: (payload: PluginEvents[E]) => void | Promise<void>): void;
122
+ /** The database of the tenant the current request, step or event belongs to. */
123
+ getTenantDb(): PluginDb;
124
+ /** Something to undo when the plugin unloads or reloads: a timer, a socket. */
125
+ onUnload(dispose: () => void | Promise<void>): void;
126
+ }
127
+ export interface WizardsPluginApi {
128
+ plugin: PluginManifest;
129
+ server: PluginServerApi;
130
+ /** Settings of this install: its `.env`. Name them after the plugin (`NOTIFY_URL`). */
131
+ config: {
132
+ get(key: string): string | undefined;
133
+ };
134
+ log: {
135
+ info(...args: unknown[]): void;
136
+ warn(...args: unknown[]): void;
137
+ error(...args: unknown[]): void;
138
+ };
139
+ /** A file of the plugin as an absolute path. */
140
+ resolvePath(relative: string): string;
141
+ }
142
+ export type WizardsPluginFactory = (wizards: WizardsPluginApi) => void | Promise<void>;
143
+ /** Types the factory; it does nothing else. */
144
+ export declare function definePlugin(factory: WizardsPluginFactory): WizardsPluginFactory;
@@ -0,0 +1,4 @@
1
+ /** Types the factory; it does nothing else. */
2
+ export function definePlugin(factory) {
3
+ return factory;
4
+ }
@@ -0,0 +1,80 @@
1
+ import type { ComponentType } from "react";
2
+ /**
3
+ * What the studio hands a plugin's studio half: the built `client.js` the studio loads after
4
+ * sign-in. Its default export registers pages, entries of the top bar and sections of the
5
+ * settings. React, the router and the studio's own components come from the studio
6
+ * (docs/plugins.md), so the page a plugin draws is part of the same app.
7
+ */
8
+ export type StudioLang = "de" | "en";
9
+ /** A plugin's words. `de` is the source: a key missing in `en` shows the German. */
10
+ export type StudioMessages = Record<StudioLang, Record<string, string>>;
11
+ type Icon = ComponentType<{
12
+ className?: string;
13
+ }>;
14
+ export interface StudioPage {
15
+ /** An address of the studio: `/contacts`, `/contacts/:id`. */
16
+ path: string;
17
+ component: ComponentType;
18
+ /** The page lays out columns of its own and takes the screen's width. */
19
+ wide?: boolean;
20
+ }
21
+ /** An icon in the top bar that opens a page. */
22
+ export interface StudioNavEntry {
23
+ to: string;
24
+ /** A function: the language can change while the studio is open. */
25
+ label: () => string;
26
+ icon: Icon;
27
+ }
28
+ export interface StudioSettingsSection {
29
+ /** Its address is `/settings/<id>`. */
30
+ id: string;
31
+ label: () => string;
32
+ icon: Icon;
33
+ component: ComponentType;
34
+ /** The user menu links to it directly. */
35
+ menu?: boolean;
36
+ }
37
+ export interface StudioMe {
38
+ user: {
39
+ id: string;
40
+ name: string;
41
+ email: string;
42
+ };
43
+ tenant: {
44
+ id: string;
45
+ role: "owner" | "admin" | "member";
46
+ };
47
+ /** `managed`: signed in at the Manage-App. `local`: the runtime runs alone. */
48
+ mode: "managed" | "local";
49
+ }
50
+ export interface StudioPluginContext {
51
+ plugin: {
52
+ id: string;
53
+ name: string;
54
+ version: string;
55
+ };
56
+ registerPage(page: StudioPage): void;
57
+ registerNav(entry: StudioNavEntry): void;
58
+ registerSettingsSection(section: StudioSettingsSection): void;
59
+ i18n: {
60
+ /** Takes the plugin's words and gives the function that reads them in the language in effect. */
61
+ register<M extends StudioMessages>(messages: M): (key: keyof M["de"] & string, vars?: Record<string, string | number>) => string;
62
+ lang(): StudioLang;
63
+ };
64
+ /** The plugin's own routes: `get("/")` asks `/api/studio/plugins/<id>/`. */
65
+ api: {
66
+ get<T>(path: string): Promise<T>;
67
+ post<T>(path: string, body?: unknown): Promise<T>;
68
+ put<T>(path: string, body?: unknown): Promise<T>;
69
+ patch<T>(path: string, body?: unknown): Promise<T>;
70
+ del<T>(path: string): Promise<T>;
71
+ };
72
+ /** The signed-in person. */
73
+ me(): StudioMe;
74
+ /** Something to undo when the plugin reloads. */
75
+ onUnload(dispose: () => void): void;
76
+ }
77
+ export type StudioPlugin = (studio: StudioPluginContext) => void;
78
+ /** Types the plugin; it does nothing else. */
79
+ export declare function defineStudioPlugin(plugin: StudioPlugin): StudioPlugin;
80
+ export {};
@@ -0,0 +1,4 @@
1
+ /** Types the plugin; it does nothing else. */
2
+ export function defineStudioPlugin(plugin) {
3
+ return plugin;
4
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "@engenty-wizards/plugin-sdk",
3
+ "version": "0.1.0",
4
+ "license": "FSL-1.1-MIT",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": "./dist/index.js",
8
+ "./studio": "./dist/studio.js"
9
+ }
10
+ }
@@ -29,6 +29,18 @@ export declare function locationText(v: LocationValue): string;
29
29
  /** A field takes at most this many files. */
30
30
  export declare const MAX_FILES = 30;
31
31
  export declare const TOOL_IDS: readonly ["web_search", "web_fetch", "browser", "sandbox", "image", "http"];
32
+ /**
33
+ * A tool a plugin of the runtime adds: `<plugin id>.<tool name>`. A wizard that names one runs
34
+ * only where that plugin is installed.
35
+ */
36
+ export declare const PLUGIN_ID: RegExp;
37
+ export declare const PLUGIN_TOOL_NAME: RegExp;
38
+ export type PluginToolId = `${string}.${string}`;
39
+ /** The plugin and the tool a step's tool id names, or null for one of the built-in tools. */
40
+ export declare function pluginToolOf(id: string): {
41
+ plugin: string;
42
+ tool: string;
43
+ } | null;
32
44
  /**
33
45
  * The kinds of model a step can ask for. A step names a class; which model serves it is bound
34
46
  * outside the wizard (the model-gateway, or the settings of a runtime that runs alone).
@@ -216,14 +228,14 @@ export declare const pageStepSchema: z.ZodObject<{
216
228
  export declare const agentStepSchema: z.ZodObject<{
217
229
  type: z.ZodLiteral<"agent">;
218
230
  instructions: z.ZodString;
219
- tools: z.ZodDefault<z.ZodArray<z.ZodEnum<{
231
+ tools: z.ZodDefault<z.ZodArray<z.ZodUnion<readonly [z.ZodEnum<{
220
232
  image: "image";
221
233
  web_search: "web_search";
222
234
  web_fetch: "web_fetch";
223
235
  browser: "browser";
224
236
  sandbox: "sandbox";
225
237
  http: "http";
226
- }>>>;
238
+ }>, z.ZodTemplateLiteral<`${string}.${string}`>]>>>;
227
239
  mcp: z.ZodOptional<z.ZodArray<z.ZodString>>;
228
240
  connections: z.ZodOptional<z.ZodArray<z.ZodString>>;
229
241
  output: z.ZodDefault<z.ZodObject<{
@@ -527,14 +539,14 @@ export declare const stepSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
527
539
  }, z.core.$strip>, z.ZodObject<{
528
540
  type: z.ZodLiteral<"agent">;
529
541
  instructions: z.ZodString;
530
- tools: z.ZodDefault<z.ZodArray<z.ZodEnum<{
542
+ tools: z.ZodDefault<z.ZodArray<z.ZodUnion<readonly [z.ZodEnum<{
531
543
  image: "image";
532
544
  web_search: "web_search";
533
545
  web_fetch: "web_fetch";
534
546
  browser: "browser";
535
547
  sandbox: "sandbox";
536
548
  http: "http";
537
- }>>>;
549
+ }>, z.ZodTemplateLiteral<`${string}.${string}`>]>>>;
538
550
  mcp: z.ZodOptional<z.ZodArray<z.ZodString>>;
539
551
  connections: z.ZodOptional<z.ZodArray<z.ZodString>>;
540
552
  output: z.ZodDefault<z.ZodObject<{
@@ -1139,14 +1151,14 @@ export declare const wizardSchema: z.ZodObject<{
1139
1151
  }, z.core.$strip>, z.ZodObject<{
1140
1152
  type: z.ZodLiteral<"agent">;
1141
1153
  instructions: z.ZodString;
1142
- tools: z.ZodDefault<z.ZodArray<z.ZodEnum<{
1154
+ tools: z.ZodDefault<z.ZodArray<z.ZodUnion<readonly [z.ZodEnum<{
1143
1155
  image: "image";
1144
1156
  web_search: "web_search";
1145
1157
  web_fetch: "web_fetch";
1146
1158
  browser: "browser";
1147
1159
  sandbox: "sandbox";
1148
1160
  http: "http";
1149
- }>>>;
1161
+ }>, z.ZodTemplateLiteral<`${string}.${string}`>]>>>;
1150
1162
  mcp: z.ZodOptional<z.ZodArray<z.ZodString>>;
1151
1163
  connections: z.ZodOptional<z.ZodArray<z.ZodString>>;
1152
1164
  output: z.ZodDefault<z.ZodObject<{
@@ -59,6 +59,22 @@ export function locationText(v) {
59
59
  /** A field takes at most this many files. */
60
60
  export const MAX_FILES = 30;
61
61
  export const TOOL_IDS = ["web_search", "web_fetch", "browser", "sandbox", "image", "http"];
62
+ /**
63
+ * A tool a plugin of the runtime adds: `<plugin id>.<tool name>`. A wizard that names one runs
64
+ * only where that plugin is installed.
65
+ */
66
+ export const PLUGIN_ID = /^[a-z][a-z0-9-]{0,39}$/;
67
+ export const PLUGIN_TOOL_NAME = /^[a-z][a-z0-9_]{0,39}$/;
68
+ /** The plugin and the tool a step's tool id names, or null for one of the built-in tools. */
69
+ export function pluginToolOf(id) {
70
+ const [plugin, tool, ...rest] = id.split(".");
71
+ return tool !== undefined &&
72
+ rest.length === 0 &&
73
+ PLUGIN_ID.test(plugin) &&
74
+ PLUGIN_TOOL_NAME.test(tool)
75
+ ? { plugin, tool }
76
+ : null;
77
+ }
62
78
  /**
63
79
  * The kinds of model a step can ask for. A step names a class; which model serves it is bound
64
80
  * outside the wizard (the model-gateway, or the settings of a runtime that runs alone).
@@ -170,7 +186,12 @@ export const agentStepSchema = z.object({
170
186
  type: z.literal("agent"),
171
187
  /** What the agent does. A template: {{field}}, {{steps.id}}, {{brand.name}}. */
172
188
  instructions: z.string().min(1),
173
- tools: z.array(z.enum(TOOL_IDS)).default([]),
189
+ tools: z
190
+ .array(z.union([
191
+ z.enum(TOOL_IDS),
192
+ z.templateLiteral([z.string().regex(PLUGIN_ID), ".", z.string().regex(PLUGIN_TOOL_NAME)]),
193
+ ]))
194
+ .default([]),
174
195
  /** Ids of project MCP servers this step may use. */
175
196
  mcp: z.array(z.string()).optional(),
176
197
  /** Ids of wizard connections (the person's accounts) this step may use. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wizards",
3
- "version": "0.1.11",
3
+ "version": "0.2.1",
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",
@@ -18,6 +18,7 @@
18
18
  "files": [
19
19
  "apps",
20
20
  "bin",
21
+ "modules",
21
22
  "plugin"
22
23
  ],
23
24
  "dependencies": {
@@ -25,6 +26,7 @@
25
26
  "@ai-sdk/gateway": "4.0.82",
26
27
  "@ai-sdk/openai": "4.0.67",
27
28
  "@clack/prompts": "1.8.1",
29
+ "@engenty-wizards/plugin-sdk": "0.1.0",
28
30
  "@engenty-wizards/shared": "0.1.0",
29
31
  "@executor-js/plugin-openapi": "1.6.8",
30
32
  "@hono/node-server": "2.1.3",
@@ -33,6 +35,7 @@
33
35
  "@mastra/docker": "0.8.0",
34
36
  "@mastra/mcp": "2.1.2",
35
37
  "@modelcontextprotocol/client": "2.2.0",
38
+ "@modelcontextprotocol/ext-apps": "2.0.3",
36
39
  "@modelcontextprotocol/server": "2.2.0",
37
40
  "@turbodocx/html-to-docx": "1.23.1",
38
41
  "ai": "7.0.102",
@@ -44,6 +47,7 @@
44
47
  "fflate": "0.8.3",
45
48
  "hono": "4.13.12",
46
49
  "imapflow": "2.2.1",
50
+ "jiti": "2.7.0",
47
51
  "jose": "6.2.12",
48
52
  "mammoth": "1.13.0",
49
53
  "marked": "18.0.14",
@@ -57,6 +61,7 @@
57
61
  "zod": "4.6.5"
58
62
  },
59
63
  "bundleDependencies": [
64
+ "@engenty-wizards/plugin-sdk",
60
65
  "@engenty-wizards/shared"
61
66
  ]
62
67
  }
@@ -2,7 +2,7 @@
2
2
  "name": "engenty-wizards",
3
3
  "displayName": "engenty wizards",
4
4
  "version": "{{VERSION}}",
5
- "description": "Build page-by-page AI wizards that people open on a shared link — designed, tested and published from Claude Code.",
5
+ "description": "Build page-by-page AI wizards that people open on a shared link — designed, tested and published from Claude Code — and run your published ones right in the chat.",
6
6
  "author": { "name": "engenty" },
7
7
  "homepage": "{{APP_URL}}",
8
8
  "keywords": ["wizards", "forms", "ai-workflows", "mcp"]
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: use-wizard
3
+ description: Run one of the person's published engenty wizards here in the chat — a social post with an image, a research briefing, an offer, a video ad … page by page, with its review and its downloads. Use when the person wants something one of their wizards makes, names a wizard, or asks what their wizards can do.
4
+ ---
5
+
6
+ # Use an engenty wizard
7
+
8
+ You work with the `engenty-wizards` MCP tools. The person you talk to runs the wizard; their answers fill its pages.
9
+
10
+ 1. **Find it.** `list_wizards` lists the person's wizards; only `published` ones run. `show_wizard` only when the person wants to see a wizard before running it: apps that show MCP Apps show it as it greets a person, with its flow one click away.
11
+ 2. **Start it.** `run_wizard` straight away; apps that show MCP Apps show the wizard itself, page by page, and the person may answer there. What the person already said for the first page goes in with `answer_page`, using the field ids in `waitingFor`. Runs spend credits like any run of the wizard.
12
+ 3. **Follow `waitingFor`.**
13
+ - `page`: ask for the fields with `inChat: true`, in the person's words, then `answer_page`. Fields with `inChat: false` (files, recordings, signatures, line items) need the run page: hand over `browserUrl`.
14
+ - `review`: show the outputs (texts, image links), then `review_step`: accept, or regenerate one with the person's note.
15
+ - `ask`: a step wants to change something in a connected account. Ask the person, then `answer_ask` with `allow` or `skip`. A sign-in happens on the run page (`browserUrl`).
16
+ - Nothing, status `running`: `get_run` with `waitSeconds: 45`, again until it changes.
17
+ 4. **In a widget.** When the app shows the run as a widget, the person may answer there instead of in the chat. Call `get_run` before you ask again, so you never ask for a page that is already answered.
18
+ 5. **Hand over.** When the status is `done`, give the outputs and their download links (valid one hour). `failed`: say what went wrong; `control_run` with `retry` tries the step again.
@@ -1 +0,0 @@
1
- import{i as e,n as t,t as n}from"./jsx-runtime-Dk72oS4N.js";import{t as r}from"./preload-helper-CNEI7N0N.js";import{a as i,d as a,h as o,i as s,s as c,v as l}from"./ui-tO4ZXbfh.js";var u=e(t(),1),d=n();function f(e){switch(e.group){case`Added`:return{label:`NEW`,dot:`bg-moss`};case`Fixed`:return{label:`FIXED`,dot:`bg-amber`};case`Changed`:return{label:`CHANGED`,dot:`bg-cobalt`};case`Performance`:return{label:`PERFORMANCE`,dot:`bg-ember`};case`Deploy`:return{label:`DEPLOY`,dot:`bg-ink-4`};case`Docs`:return{label:`DOCS`,dot:`bg-ink-4`};default:return{label:`OTHER`,dot:`bg-ink-4`}}}var p=e=>e.version?e.version.replace(/^v/,``):l(`about.unreleased`),m=e=>e.timestamp?new Date(e.timestamp*1e3).toISOString().slice(0,10):``,h=e=>e.charAt(0).toUpperCase()+e.slice(1);function g(e,t){let n=t.trim().toLowerCase();if(!n)return e;let r=[];for(let t of e){if(`${p(t)} ${m(t)}`.toLowerCase().includes(n)){r.push(t);continue}let e=t.commits.filter(e=>`${f(e).label} ${e.scope??``} ${e.message}`.toLowerCase().includes(n));e.length>0&&r.push({...t,commits:e})}return r}function _({open:e,onClose:t}){let[n,_]=(0,u.useState)(null),[v,y]=(0,u.useState)(``);(0,u.useEffect)(()=>{if(!e||n)return;let t=!1;return r(()=>import(`./changelog-BJkYErYt.js`).then(e=>{t||_(e.default)}),[]),()=>{t=!0}},[e,n]),(0,u.useEffect)(()=>{e||y(``)},[e]);let b=n?g(n,v):[];return(0,d.jsxs)(s,{open:e,onClose:t,title:l(`about.changelog`),wide:!0,children:[(0,d.jsx)(`p`,{className:`-mt-3 mb-4 text-[14px] text-ink-3`,children:l(`about.changelogHint`)}),n===null?(0,d.jsx)(`div`,{className:`flex justify-center py-10 text-ink-3`,children:(0,d.jsx)(a,{})}):n.length===0?(0,d.jsx)(i,{children:l(`about.changelogEmpty`)}):(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(c,{type:`search`,value:v,placeholder:l(`about.search`),onChange:e=>y(e.target.value)}),b.length===0?(0,d.jsx)(i,{children:l(`about.noMatches`)}):null,b.map(e=>(0,d.jsxs)(`section`,{className:`mt-6`,children:[(0,d.jsxs)(`h3`,{className:`flex items-baseline gap-3 border-border-soft border-b pb-2 font-display font-semibold text-[16px]`,children:[p(e),(0,d.jsx)(`span`,{className:`font-normal font-sans text-[13px] text-ink-3 tabular-nums`,children:m(e)})]}),(0,d.jsx)(`ul`,{className:`mt-3 flex flex-col gap-2`,children:e.commits.map(e=>{let t=f(e);return(0,d.jsxs)(`li`,{className:`flex items-start gap-2.5 text-[14px]`,children:[(0,d.jsx)(`span`,{className:o(`mt-[7px] size-1.5 shrink-0 rounded-full`,t.dot)}),(0,d.jsxs)(`span`,{className:`min-w-0 text-ink-2`,children:[(0,d.jsxs)(`span`,{className:`font-semibold text-[12px] text-ink tracking-wide`,children:[t.label,e.scope?` [${e.scope}]`:``]}),` `,h(e.message),e.breaking?(0,d.jsx)(`span`,{className:`ml-1.5 rounded-full bg-rose-tint px-1.5 py-0.5 font-medium text-[12px] text-rose`,children:l(`about.breaking`)}):null]})]},e.id)})})]},e.version??`unreleased`))]})]})}export{_ as ChangelogDialog};
@@ -1 +0,0 @@
1
- import{i as e,n as t,t as n}from"./jsx-runtime-Dk72oS4N.js";import{c as r,d as i,i as a,n as o,tt as s}from"./api-DbPn6Dge.js";import{t as c}from"./createLucideIcon-DBu2Ovxj.js";import{S as l,g as u,h as d,r as f,v as p}from"./outputs-CHe6KRLc.js";import{r as m}from"./wand-sparkles-Bf97fs8T.js";import{t as h}from"./plus-HA210wXA.js";import{t as g}from"./mic-CeqQ89Dj.js";import{d as _,g as v,h as y,o as b,v as x}from"./ui-tO4ZXbfh.js";import{d as S,u as C}from"./index-BRy5sz4a.js";var w={name:`chevron-up`,size:24,node:[[`path`,{d:`m18 15-6-6-6 6`,key:`153udz`}]]};w.node;var T=c(w),E=e(t(),1),D=!1;function O(){if(!(typeof window>`u`||D))return window.SpeechRecognition??window.webkitSpeechRecognition}var k=typeof navigator<`u`&&!!navigator.mediaDevices?.getUserMedia&&typeof MediaRecorder<`u`;function A(e,t){let n=e.trimEnd(),r=t.trim();return n&&r?`${n} ${r}`:n||r}function j(e,t){let[n,r]=(0,E.useState)(!1),[i,a]=(0,E.useState)(!1),[s,c]=(0,E.useState)(null),l=(0,E.useRef)(e);l.current=e;let u=(0,E.useRef)(t);u.current=t;let d=(0,E.useRef)(null);(0,E.useEffect)(()=>()=>d.current?.stop(),[]);let f=async()=>{let e=l.current,t;try{t=await navigator.mediaDevices.getUserMedia({audio:!0})}catch{c(`denied`);return}let n=[],i=new MediaRecorder(t);i.ondataavailable=e=>e.data.size&&n.push(e.data),i.onstop=async()=>{for(let e of t.getTracks())e.stop();d.current=null,r(!1);let s=(i.mimeType||`audio/webm`).split(`;`)[0],l=new File(n,`dictation`,{type:s});if(l.size){a(!0);try{let{text:t}=await o.upload(`/api/studio/transcribe`,l);t.trim()&&u.current(A(e,t))}catch(e){c(e.message)}finally{a(!1)}}},d.current={stop:()=>i.state!==`inactive`&&i.stop()},i.start(),r(!0)},p=e=>{let t=l.current,n=``,i=new e;i.continuous=!0,i.interimResults=!0,i.lang=v===`de`?`de-DE`:`en-US`,i.onresult=e=>{let r=``;for(let t=Math.max(0,e.resultIndex);t<e.results.length;t++){let i=e.results[t],a=i[0]?.transcript??``;i.isFinal?n=A(n,a):r+=a}u.current(A(t,A(n,r)))},i.onerror=e=>{if(e.error!==`aborted`&&e.error!==`no-speech`){if(e.error===`not-allowed`){c(`denied`);return}D=!0,k&&!n?(i.onend=null,d.current=null,f()):c(e.error)}},i.onend=()=>{d.current=null,r(!1)},d.current={stop:()=>i.stop()},i.start(),r(!0)};return{supported:!!O()||k,listening:n,processing:i,error:s,toggle:()=>{if(i)return;if(d.current){d.current.stop();return}c(null);let e=O();e?p(e):f()}}}var M=n(),N=/\.(png|jpe?g|gif|webp|avif|svg)$/i;function P(e){let t=e.filter(e=>e.type.startsWith(`image/`));return t.length?Object.fromEntries(t.map(e=>[e.name,URL.createObjectURL(e)])):void 0}function F(e){let t=e.match(/(?:^|\n\n)(?:Angehängt|Attached): ([^\n]+)$/);return t?{text:e.slice(0,t.index).trim(),names:t[1].split(`, `).filter(Boolean)}:{text:e,names:[]}}function I(e,t){if(e.name&&e.name!==`image.png`)return e;let n=e.type.split(`/`)[1]?.replace(`jpeg`,`jpg`)||`png`,r=new Date().toISOString().slice(0,19).replace(/[-:]/g,``).replace(`T`,`-`);return new File([e],`paste-${r}${t?`-${t+1}`:``}.${n}`,{type:e.type})}function L({url:e,label:t,children:n}){return(0,M.jsxs)(`div`,{className:`group relative`,title:t,children:[(0,M.jsx)(`img`,{src:e,alt:t,width:64,height:64,className:`size-16 rounded-lg bg-paper-2 object-cover ring-1 ring-border`}),n]})}function R({names:e,previews:t,fileUrl:n}){let r=e.filter(e=>t?.[e]||n&&N.test(e)),i=e.filter(e=>!r.includes(e));return(0,M.jsxs)(`div`,{className:`flex flex-col items-end gap-1.5`,children:[r.map(e=>{let r=t?.[e]??n?.(e)??``;return(0,M.jsx)(`a`,{href:r,target:`_blank`,rel:`noreferrer`,title:e,children:(0,M.jsx)(`img`,{src:r,alt:e,className:`max-h-60 w-auto max-w-full rounded-xl bg-paper-2 object-contain ring-1 ring-border`})},e)}),i.length?(0,M.jsx)(`div`,{className:`flex flex-wrap justify-end gap-1.5`,children:i.map(e=>(0,M.jsxs)(`span`,{className:`inline-flex max-w-full items-center gap-1.5 rounded-full bg-paper-2 px-2.5 py-1 text-[12px] text-ink-2`,children:[(0,M.jsx)(p,{className:`size-3 shrink-0 text-ink-4`}),(0,M.jsx)(`span`,{className:`truncate`,children:e})]},e))}):null]})}function z(e,t){let n=s(),[i,o]=(0,E.useState)([]),[c,l]=(0,E.useState)(`idle`),[u,d]=(0,E.useState)(null),[f,p]=(0,E.useState)(null),[m,h]=(0,E.useState)(null),[g,_]=(0,E.useState)(null),v=(0,E.useRef)(null);return(0,E.useEffect)(()=>{if(e){if(v.current!==e.id){v.current=e.id,o(e.messages);return}c===`idle`&&o(t=>e.messages.length>=t.length?e.messages:t)}},[e,c]),{messages:i,phase:c,activity:f,thought:m,startedAt:g,error:u,send:async(i,s=[])=>{if(!e||!(i.trim()||s.length)||c!==`idle`)return!1;if(d(null),_(Date.now()),h(null),s.length){l(`thinking`);try{for(let t of s){let n=await fetch(r(`/api/studio/wizards/${e.id}/files/${encodeURIComponent(t.name)}`),{method:`PUT`,credentials:`include`,headers:{"content-type":t.type||`application/octet-stream`},body:t});if(!n.ok){let e=await n.json().catch(()=>({}));throw Error(e.error??n.statusText)}}}catch(t){return d(t.message),l(`idle`),_(null),await n.invalidateQueries({queryKey:[`wizard`,e.id]}),!1}let t=`${x(`editor.attached`)}: ${s.map(e=>e.name).join(`, `)}`;i=i.trim()?`${i}\n\n${t}`:t}let u=`p-${Date.now()}`;o(e=>[...e,{id:`u-${Date.now()}`,role:`user`,content:i,previews:P(s)},{id:u,role:`assistant`,content:``,pending:!0}]),l(`thinking`),p(null);let f=!1;try{await a(`/api/studio/wizards/${e.id}/chat`,{message:i},(e,n)=>{if(e===`text`){let e=JSON.parse(n);o(t=>t.map(t=>t.id===u?{...t,content:t.content+e}:t))}else if(e===`activity`)p(JSON.parse(n));else if(e===`thought`)h(JSON.parse(n));else if(e===`building`)l(`building`);else if(e===`done`){f=!0;let e=JSON.parse(n);o(t=>t.map(t=>t.id===u?{...t,content:e.reply,changed:e.changed,pending:!1}:t)),e.changed&&t(e.draft,e.revision)}else e===`error`&&(f=!0,d(JSON.parse(n).message))}),f||d(x(`editor.chatBroken`))}catch(e){d(e.message)}finally{p(null),h(null),_(null),o(e=>e.filter(e=>!(e.id===u&&!e.content)).map(e=>({...e,pending:!1}))),l(`idle`),await n.invalidateQueries({queryKey:[`wizard`,e.id]}),await n.invalidateQueries({queryKey:[`me`]})}return!0},fileUrl:t=>r(`/api/studio/wizards/${e?.id}/files/${encodeURIComponent(t)}`)}}function B(e){let[t,n]=(0,E.useState)(()=>Date.now());return(0,E.useEffect)(()=>{if(e===null)return;n(Date.now());let t=setInterval(()=>n(Date.now()),1e3);return()=>clearInterval(t)},[e]),e===null?null:Math.max(0,Math.floor((t-e)/1e3))}function V(e){return e<60?`${e} s`:`${Math.floor(e/60)}:${String(e%60).padStart(2,`0`)} min`}function H({chat:e,thought:t,className:n,spinner:r=`size-3.5`}){let i=B(e.startedAt);return(0,M.jsxs)(`div`,{className:y(`min-w-0`,n),children:[(0,M.jsxs)(`div`,{className:`flex min-w-0 items-center gap-2`,children:[(0,M.jsx)(_,{className:y(`shrink-0`,r)}),(0,M.jsx)(`span`,{className:`min-w-0 truncate`,children:e.activity??(e.phase===`building`?x(`editor.building`):x(`editor.thinking`))}),i===null?null:(0,M.jsx)(`span`,{className:`shrink-0 text-ink-4 tabular-nums`,children:V(i)})]}),t&&e.thought?(0,M.jsx)(`p`,{className:`mt-0.5 truncate pl-5.5 text-[12px] text-ink-4`,children:e.thought}):null]})}function U({message:e,fileUrl:t}){let{text:n,names:r}=F(e.content);return(0,M.jsxs)(`div`,{className:`ml-8 flex flex-col items-end gap-1.5 self-end`,children:[r.length?(0,M.jsx)(R,{names:r,previews:e.previews,fileUrl:t}):null,n?(0,M.jsx)(`div`,{className:`rounded-xl rounded-br-md bg-paper-2 px-4 py-2.5 text-[14px] leading-relaxed`,children:(0,M.jsx)(`span`,{className:`whitespace-pre-wrap`,children:n})}):null]})}function W({chat:e,avatar:t,hello:n=x(`editor.chatHello`),placeholder:r=x(`editor.composer`),changedLabel:a=`Ablauf aktualisiert`,compact:o,intro:s}){let[c,v]=(0,E.useState)(!1),[w,D]=(0,E.useState)(``),[O,k]=(0,E.useState)([]),A=(0,E.useRef)(null),N=(0,E.useRef)(null),P=(0,E.useRef)(null),F=j(w,D);(0,E.useEffect)(()=>{A.current?.scrollTo({top:A.current.scrollHeight,behavior:`smooth`})},[e.messages,e.phase]),(0,E.useEffect)(()=>{let e=N.current;e&&(e.style.height=`auto`,e.style.height=`${Math.min(e.scrollHeight,200)}px`)},[w]);let R=(w.trim()||O.length>0)&&e.phase===`idle`,z=e=>k(t=>[...t.filter(t=>!e.some(e=>e.name===t.name)),...e]),[B,V]=(0,E.useState)(new Map);(0,E.useEffect)(()=>{let e=new Map(O.filter(e=>e.type.startsWith(`image/`)).map(e=>[e,URL.createObjectURL(e)]));return V(e),()=>{for(let t of e.values())URL.revokeObjectURL(t)}},[O]);let W=async()=>{if(!R)return;F.listening&&F.toggle();let t={text:w,files:O};D(``),k([]),await e.send(t.text.trim(),t.files)||(D(t.text),k(t.files))},G=!o||c,K=e.messages.at(-1);return(0,M.jsxs)(`div`,{className:`flex h-full min-h-0 flex-col`,children:[o&&(K||e.error)?(0,M.jsxs)(`button`,{type:`button`,"aria-expanded":c,"aria-label":x(`editor.thread`),onClick:()=>v(e=>!e),className:`flex items-center gap-2 px-4 pt-2.5 pb-0.5 text-left text-[13px] text-ink-3 transition hover:text-ink`,children:[!(e.error||c)&&K?.pending?(0,M.jsx)(H,{chat:e,className:`flex-1`}):(0,M.jsx)(`span`,{className:y(`min-w-0 flex-1 truncate`,e.error&&`text-rose`),children:e.error??(c?x(`editor.thread`):K?.content)}),c?(0,M.jsx)(m,{className:`size-4 shrink-0`}):(0,M.jsx)(T,{className:`size-4 shrink-0`})]}):null,(0,M.jsxs)(`div`,{ref:A,className:y(`min-h-0 flex-1 overflow-y-auto px-5 py-5`,!G&&`hidden`),children:[e.messages.length===0?s??(0,M.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,M.jsx)(i,{kind:t,size:32,interactive:!1}),(0,M.jsx)(`p`,{className:`pt-1 text-[14px] text-ink-2 leading-relaxed`,children:n})]}):null,(0,M.jsx)(`div`,{className:`flex flex-col gap-4`,children:e.messages.map(n=>n.role===`user`?(0,M.jsx)(U,{message:n,fileUrl:e.fileUrl},n.id):(0,M.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,M.jsx)(`div`,{className:`shrink-0`,children:(0,M.jsx)(i,{kind:t,size:28,interactive:!1})}),(0,M.jsxs)(`div`,{className:`min-w-0 pt-0.5 text-[14px]`,children:[n.source===`mcp`?(0,M.jsxs)(`div`,{className:`mb-1 inline-flex items-center gap-1.5 text-[12px] text-ink-3`,children:[(0,M.jsx)(S,{className:`size-3`}),` `,x(`editor.viaClient`,{client:n.client??`MCP`})]}):null,n.content?(0,M.jsx)(f,{text:n.content,className:`text-[14px]`}):null,n.pending?(0,M.jsx)(H,{chat:e,thought:!0,className:`mt-1 text-[13px] text-ink-3`}):null,n.changed?(0,M.jsxs)(`div`,{className:`mt-2 inline-flex items-center gap-1.5 rounded-full bg-ember-tint px-2.5 py-0.5 text-[12px] text-ember-strong`,children:[(0,M.jsx)(u,{className:`size-3`}),` `,a]}):null]})]},n.id))}),e.error?(0,M.jsx)(`div`,{className:`mt-4 rounded-lg bg-rose-tint px-3 py-2 text-[13px] text-rose`,children:e.error}):null]}),(0,M.jsxs)(`div`,{className:o?`p-2`:`p-3`,children:[(0,M.jsxs)(`div`,{className:`rounded-xl bg-card p-1.5 shadow-soft ring-1 ring-border focus-within:ring-focus`,children:[B.size?(0,M.jsx)(`div`,{className:`flex flex-wrap gap-2 px-1 pt-1 pb-1.5`,children:O.map((e,t)=>{let n=B.get(e);return n?(0,M.jsx)(L,{url:n,label:e.name,children:(0,M.jsx)(`button`,{type:`button`,"aria-label":x(`editor.detach`),onClick:()=>k(e=>e.filter((e,n)=>n!==t)),className:`-top-1.5 -right-1.5 absolute flex size-5 items-center justify-center rounded-full bg-ink text-paper opacity-0 shadow-soft transition focus-visible:opacity-100 group-hover:opacity-100`,children:(0,M.jsx)(C,{className:`size-3`})})},`${e.name}-${t}`):null})}):null,O.some(e=>!B.has(e))?(0,M.jsx)(`ul`,{className:`flex flex-wrap gap-1.5 px-1 pt-1 pb-1.5`,children:O.map((e,t)=>B.has(e)?null:(0,M.jsxs)(`li`,{className:`inline-flex max-w-full items-center gap-1.5 rounded-full bg-paper-2 py-1 pr-1 pl-2.5 text-[12px] text-ink-2`,children:[(0,M.jsx)(p,{className:`size-3 shrink-0 text-ink-4`}),(0,M.jsx)(`span`,{className:`truncate`,children:e.name}),(0,M.jsx)(`button`,{type:`button`,"aria-label":x(`editor.detach`),onClick:()=>k(e=>e.filter((e,n)=>n!==t)),className:`inline-flex size-5 shrink-0 items-center justify-center rounded-full text-ink-3 hover:bg-paper-3 hover:text-ink`,children:(0,M.jsx)(C,{className:`size-3`})})]},`${e.name}-${t}`))}):null,(0,M.jsxs)(`div`,{className:`flex items-end gap-1`,children:[(0,M.jsx)(b,{label:x(`editor.attach`),onClick:()=>P.current?.click(),children:(0,M.jsx)(h,{className:`size-4`})}),(0,M.jsx)(`input`,{ref:P,type:`file`,multiple:!0,hidden:!0,onChange:e=>{let t=Array.from(e.target.files??[]);e.target.value=``,z(t)}}),(0,M.jsx)(`textarea`,{ref:N,rows:1,value:w,onChange:e=>D(e.target.value),onPaste:e=>{let t=Array.from(e.clipboardData.files);t.length&&(e.preventDefault(),z(t.map(I)))},onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),W())},placeholder:F.listening?x(`editor.listening`):r,className:`max-h-[200px] min-h-[40px] flex-1 resize-none bg-transparent px-1.5 py-2 text-[14px] outline-none placeholder:text-ink-4`}),F.supported?(0,M.jsx)(b,{label:F.processing?x(`editor.transcribing`):F.listening?x(`editor.voiceStop`):x(`editor.voice`),"aria-pressed":F.listening,disabled:F.processing,onClick:F.toggle,className:y(F.listening&&`bg-rose-tint text-rose hover:bg-rose-tint hover:text-rose`),children:F.processing?(0,M.jsx)(_,{className:`size-4`}):F.listening?(0,M.jsx)(d,{className:`size-3.5 animate-pulse-dot fill-current`}):(0,M.jsx)(g,{className:`size-4`})}):null,(0,M.jsx)(`button`,{type:`button`,onClick:()=>void W(),disabled:!R,className:y(`inline-flex size-9 shrink-0 items-center justify-center rounded-full transition`,R?`bg-primary text-primary-foreground`:`bg-paper-2 text-ink-4`),"aria-label":`Send`,children:(0,M.jsx)(l,{className:`size-4`})})]})]}),F.error?(0,M.jsx)(`p`,{className:`mt-2 px-1 text-[12px] text-rose`,children:F.error===`denied`?x(`editor.micDenied`):F.error}):null]})]})}export{z as i,H as n,P as r,W as t};
@@ -1 +0,0 @@
1
- import{i as e,n as t,t as n}from"./jsx-runtime-Dk72oS4N.js";import{t as r}from"./preload-helper-CNEI7N0N.js";import{t as i}from"./external-link-CRg6DVdO.js";import{a,d as o,g as s,i as c,s as l,v as u}from"./ui-tO4ZXbfh.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=n(),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-[14px] 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-[14px] text-ink`,children:e}),n?(0,m.jsx)(`span`,{className:`text-[12px] text-ink-3 tabular-nums`,children:n}):null,(0,m.jsx)(`span`,{className:`text-[12px] text-ink-3`,children:r})]}),a?(0,m.jsx)(`p`,{className:`mt-0.5 text-[13px] 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-[16px]`,children:e}),t?(0,m.jsx)(`p`,{className:`mt-2 text-[13px] 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[s]},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-[12px] 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),[s,g]=(0,d.useState)(``);(0,d.useEffect)(()=>{if(!e||n)return;let t=!1;return r(()=>import(`./oss-credits-cPuZUFHD.js`).then(e=>{t||i(e.default)}),[]),()=>{t=!0}},[e,n]),(0,d.useEffect)(()=>{e||g(``)},[e]);let b=s.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:u(`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)(c,{open:e,onClose:t,title:u(`about.credits`),wide:!0,children:[(0,m.jsx)(`p`,{className:`-mt-3 mb-4 text-[14px] text-ink-3`,children:u(`about.creditsHint`)}),(0,m.jsx)(l,{type:`search`,value:s,placeholder:u(`about.search`),onChange:e=>g(e.target.value)}),C.length>0?(0,m.jsx)(_,{title:u(`about.creditsProduct`),children:(0,m.jsx)(v,{credits:C})}):null,w.length>0?(0,m.jsx)(_,{title:u(`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:u(`about.creditsDeps`),hint:b?void 0:u(`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:u(`about.noMatches`)}):null]})}export{b as CreditsDialog};