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
@@ -1,5 +1,7 @@
1
+ import { createHash } from "node:crypto";
2
+ import { statSync } from "node:fs";
1
3
  import { DEFINITION_VERSION, readable, wizardSchema, } from "@engenty-wizards/shared/definition";
2
- import { MARKETPLACE_LANGS, } from "@engenty-wizards/shared/marketplace";
4
+ import { capabilitiesOf, costTierOf, effortOf, formatsOf, MARKETPLACE_LANGS, pluginsOf, } from "@engenty-wizards/shared/marketplace";
3
5
  import { wizardOutline } from "@engenty-wizards/shared/marketplace-entry";
4
6
  import { searchEntries } from "@engenty-wizards/shared/marketplace-search";
5
7
  import { and, eq, inArray, notInArray } from "drizzle-orm";
@@ -9,14 +11,19 @@ import { missingCapabilities, optionalCapabilities, stepsWithoutModel, } from ".
9
11
  import { env } from "../env.js";
10
12
  import { managed } from "../manage.js";
11
13
  import { classCatalog, imageCostUsd, tokenCostUsd, videoCostUsd, WEB_SEARCH_COST_USD, } from "../models.js";
14
+ import { pluginIdsOf, pluginStartersOf } from "../plugins/registry.js";
12
15
  import { readSetting, writeSetting } from "../settings.js";
13
- import { LOCAL_TENANT } from "../tenants/tenant.js";
16
+ import { currentTenant, LOCAL_TENANT } from "../tenants/tenant.js";
14
17
  import { ServiceError } from "./errors.js";
15
18
  /**
16
19
  * The marketplace is an app of its own; this runtime is one of its clients
17
20
  * (docs/marketplace-contract.md). It searches the marketplace live and starts wizards from its
18
21
  * entries. Its starters and what people starred are kept in the control database, so the list
19
22
  * and starting a wizard work without a connection too.
23
+ *
24
+ * Beside them stand the starters the tenant's plugins bring (docs/content/dev/plugins/starters.md),
25
+ * listed first and never fetched. They are known as `<plugin id>.<starter id>`; a marketplace
26
+ * entry's id has no dot, so the two never meet.
20
27
  */
21
28
  export const asLang = (raw) => MARKETPLACE_LANGS.includes(raw ?? "") ? raw : "de";
22
29
  /** A search waits this long for the marketplace; then it searches what is kept here. */
@@ -84,6 +91,94 @@ function keptItem(e, lang) {
84
91
  const text = textIn(e, lang);
85
92
  return text ? { ...keptSummary(e, lang), definition: text.definition, files: e.files } : null;
86
93
  }
94
+ // --- the plugins' starters ------------------------------------------------------------------
95
+ /** One of the starters the tenant's plugins bring, by its id; undefined for any other id. */
96
+ async function pluginStarter(id) {
97
+ if (!id.includes(".")) {
98
+ return undefined;
99
+ }
100
+ return (await pluginStartersOf(currentTenant())).find((s) => s.id === id);
101
+ }
102
+ /** A plugin's starter as the marketplace lists an entry, read from its definition. */
103
+ function pluginSummary({ id, plugin, starter }) {
104
+ const definition = starter.definition;
105
+ const { name, version } = plugin.source.manifest;
106
+ const capabilities = capabilitiesOf(definition);
107
+ const changed = statSync(plugin.source.entry ?? plugin.source.root, { throwIfNoEntry: false });
108
+ return {
109
+ id,
110
+ revision: 0,
111
+ hash: createHash("sha256")
112
+ .update(`${version}\n${JSON.stringify(definition)}`)
113
+ .digest("hex")
114
+ .slice(0, 16),
115
+ updatedAt: (changed?.mtime ?? new Date()).toISOString(),
116
+ starter: true,
117
+ language: starter.language ?? "de",
118
+ title: starter.title,
119
+ pitch: starter.description,
120
+ // Found by the plugin's name as well: "Termine" finds the appointment plugin's starters.
121
+ terms: [name],
122
+ avatar: definition.avatar,
123
+ formats: formatsOf(definition),
124
+ industries: ["any"],
125
+ useCases: [],
126
+ capabilities,
127
+ effort: effortOf(definition),
128
+ costTier: costTierOf(capabilities),
129
+ steps: definition.steps.length,
130
+ version: definition.version,
131
+ plugins: [plugin.source.id],
132
+ plan: "pro",
133
+ };
134
+ }
135
+ /** A plugin's starter as this app shows it: never starred, and marked with its plugin. */
136
+ function pluginEntry(found, unavailable) {
137
+ const { id, name } = found.plugin.source.manifest;
138
+ return {
139
+ ...asEntry(pluginSummary(found), new Set(), unavailable, optionalOf(found.starter.definition)),
140
+ plugin: { id, name },
141
+ };
142
+ }
143
+ /** Two searches' counts per option, added up. */
144
+ function addFacets(a, b) {
145
+ const add = (x = {}, y = {}) => {
146
+ const out = { ...x };
147
+ for (const [key, n] of Object.entries(y)) {
148
+ out[key] = (out[key] ?? 0) + n;
149
+ }
150
+ return out;
151
+ };
152
+ return {
153
+ useCase: add(a.useCase, b.useCase),
154
+ industry: add(a.industry, b.industry),
155
+ format: add(a.format, b.format),
156
+ capability: add(a.capability, b.capability),
157
+ plan: add(a.plan, b.plan),
158
+ };
159
+ }
160
+ /**
161
+ * The marketplace's entries as this tenant sees them: an entry that stands for a starter of a
162
+ * plugin it has is left out (the plugin's own is listed), and the others say which plugins they
163
+ * need that it does not have.
164
+ */
165
+ async function withPlugins(entries) {
166
+ if (!entries.some((e) => e.plugins?.length || e.pluginStarter)) {
167
+ return entries;
168
+ }
169
+ const tenant = currentTenant();
170
+ const [have, starters] = await Promise.all([
171
+ pluginIdsOf(tenant),
172
+ pluginStartersOf(tenant).then((list) => new Set(list.map((s) => s.id))),
173
+ ]);
174
+ return entries.flatMap((e) => {
175
+ if (e.pluginStarter && starters.has(e.pluginStarter)) {
176
+ return [];
177
+ }
178
+ const needs = (e.plugins ?? []).filter((id) => !have.has(id));
179
+ return [needs.length ? { ...e, needs } : e];
180
+ });
181
+ }
87
182
  // --- searching -----------------------------------------------------------------------------
88
183
  /** A summary as this app shows it: whether it can read and run it, and whether it is starred. */
89
184
  function asEntry(summary, starred, unavailable, optional = new Set()) {
@@ -120,8 +215,43 @@ async function keptOptional(ids, lang, unavailable) {
120
215
  }
121
216
  return out;
122
217
  }
123
- /** Searches the marketplace; without an answer, what is kept here, scored the same way. */
218
+ /**
219
+ * Searches the tenant's plugins' starters and the marketplace, in that order: a page holds the
220
+ * plugins' starters the words and filters find, then the marketplace's entries.
221
+ */
124
222
  export async function searchMarketplace(search) {
223
+ const { q = "", starred, limit = 60, offset = 0, lang: _lang, ...filters } = search;
224
+ const own = starred ? [] : await pluginStartersOf(currentTenant());
225
+ if (!own.length) {
226
+ return searchListed(search);
227
+ }
228
+ const byId = new Map(own.map((s) => [s.id, s]));
229
+ const found = searchEntries(own.map(pluginSummary), q, filters, { limit: own.length });
230
+ const shown = found.entries.slice(offset, offset + limit);
231
+ // The marketplace fills what is left of the page, and counts from where its entries begin.
232
+ const room = limit - shown.length;
233
+ const listed = await searchListed({
234
+ ...search,
235
+ limit: Math.max(1, room),
236
+ offset: Math.max(0, offset - found.total),
237
+ });
238
+ const unavailable = new Set(listed.unavailable);
239
+ return {
240
+ ...listed,
241
+ entries: [
242
+ ...shown.flatMap((e) => {
243
+ const entry = byId.get(e.id);
244
+ return entry ? [pluginEntry(entry, unavailable)] : [];
245
+ }),
246
+ ...listed.entries.slice(0, room),
247
+ ],
248
+ total: found.total + listed.total,
249
+ all: own.length + listed.all,
250
+ facets: addFacets(listed.facets, found.facets),
251
+ };
252
+ }
253
+ /** Searches the marketplace; without an answer, what is kept here, scored the same way. */
254
+ async function searchListed(search) {
125
255
  const { q = "", lang, starred: onlyStarred, limit = 60, offset = 0, ...filters } = search;
126
256
  const stars = await starredIds();
127
257
  const starred = new Set(stars);
@@ -147,7 +277,7 @@ export async function searchMarketplace(search) {
147
277
  const optional = await keptOptional(remote.entries.map((e) => e.id), lang, unavailable);
148
278
  return {
149
279
  ...remote,
150
- entries: remote.entries.map((e) => asEntry(e, starred, unavailable, optional.get(e.id))),
280
+ entries: await withPlugins(remote.entries.map((e) => asEntry(e, starred, unavailable, optional.get(e.id)))),
151
281
  offline: false,
152
282
  unavailable: [...unavailable],
153
283
  };
@@ -159,7 +289,7 @@ export async function searchMarketplace(search) {
159
289
  const optional = await keptOptional(page.entries.map((e) => e.id), lang, unavailable);
160
290
  return {
161
291
  ...page,
162
- entries: page.entries.map((e) => asEntry(e, starred, unavailable, optional.get(e.id))),
292
+ entries: await withPlugins(page.entries.map((e) => asEntry(e, starred, unavailable, optional.get(e.id)))),
163
293
  offline: true,
164
294
  unavailable: [...unavailable],
165
295
  };
@@ -217,6 +347,15 @@ async function priced(definition) {
217
347
  }
218
348
  /** An entry in a language with its wizard read against this app; null where there is none. */
219
349
  export async function marketplaceDetail(id, lang) {
350
+ const own = await pluginStarter(id);
351
+ if (own) {
352
+ const definition = own.starter.definition;
353
+ return {
354
+ ...pluginEntry(own, await missingCapabilities()),
355
+ credits: await priced(definition),
356
+ ...wizardOutline(definition, Object.keys(own.starter.files ?? {}), lang),
357
+ };
358
+ }
220
359
  const found = await fetchItem(id, lang);
221
360
  if (!found) {
222
361
  return null;
@@ -242,6 +381,23 @@ export async function marketplaceDetail(id, lang) {
242
381
  }
243
382
  /** An entry's wizard and workspace in a language: what a wizard is made from. */
244
383
  export async function marketplaceWizard(id, lang) {
384
+ const own = await pluginStarter(id);
385
+ if (own) {
386
+ // A plugin's starter is in its one language, whatever is asked for.
387
+ const { starter, plugin } = own;
388
+ return {
389
+ id,
390
+ revision: null,
391
+ plugin: plugin.source.id,
392
+ title: starter.title,
393
+ language: starter.language ?? "de",
394
+ definition: structuredClone(starter.definition),
395
+ files: Object.fromEntries(Object.entries(starter.files ?? {}).map(([path, data]) => [
396
+ path,
397
+ typeof data === "string" ? Buffer.from(data, "utf8") : Buffer.from(data),
398
+ ])),
399
+ };
400
+ }
245
401
  const found = await fetchItem(id, lang);
246
402
  if (!found) {
247
403
  return null;
@@ -249,6 +405,12 @@ export async function marketplaceWizard(id, lang) {
249
405
  if (!readable(found.definition)) {
250
406
  throw new ServiceError("refused", "Diese Vorlage braucht eine neuere Version der App. Bitte aktualisiere die App.");
251
407
  }
408
+ // A wizard whose plugins are not here would stop at its first step that uses them.
409
+ const have = await pluginIdsOf(currentTenant());
410
+ const needs = pluginsOf(wizardSchema.parse(found.definition)).filter((p) => !have.has(p));
411
+ if (needs.length) {
412
+ throw new ServiceError("refused", `Diese Vorlage braucht ${needs.length === 1 ? "das Plugin" : "die Plugins"} ${needs.join(", ")}: mit Pro auf engenty.ai dabei.`);
413
+ }
252
414
  return {
253
415
  id: found.id,
254
416
  revision: found.revision,
@@ -1,4 +1,4 @@
1
- import { formatsFor } from "@engenty-wizards/shared/definition";
1
+ import { formatsFor, optionsFromData, slotText, wizardLang, } from "@engenty-wizards/shared/definition";
2
2
  import { and, count, desc, eq, gte, inArray, max, or, sql } from "drizzle-orm";
3
3
  import { canSpend, MICROS_PER_CREDIT } from "../credits/credits.js";
4
4
  import { db, schema } from "../db/client.js";
@@ -159,7 +159,31 @@ const CHAT_KINDS = new Set([
159
159
  "color",
160
160
  "items",
161
161
  "location",
162
+ "slot",
162
163
  ]);
164
+ /** A field's choices in this run: what its `optionsFrom` finds in earlier steps, else the fixed ones. */
165
+ function choicesOf(run, field) {
166
+ const found = field.optionsFrom ? optionsFromData(field.optionsFrom, run.state.outputs) : [];
167
+ return found.length ? found : field.options;
168
+ }
169
+ /**
170
+ * What a client needs besides the plain field: a slot's times as the person reads them, and the
171
+ * one value of them to send back.
172
+ */
173
+ function slotHints(run, field, options) {
174
+ if (field.kind !== "slot") {
175
+ return {};
176
+ }
177
+ const lang = wizardLang(run.definition);
178
+ const value = run.state.values[field.id];
179
+ return {
180
+ times: (options ?? []).map((o) => ({ value: o, label: slotText(o, lang) })),
181
+ ...(typeof value === "string" ? { valueText: slotText(value, lang) } : {}),
182
+ hint: options?.length
183
+ ? "One appointment time: show the person the labels, answer with the value of the one they pick, exactly as given."
184
+ : "No times are free right now: tell the person.",
185
+ };
186
+ }
163
187
  /** Where the person can go on in a browser: the run page of a live run, the studio for a test. */
164
188
  /** The live run's page — the wizard itself, never the studio. A test run has none. */
165
189
  async function browserUrl(run) {
@@ -197,20 +221,24 @@ function waitingFor(run, current) {
197
221
  return {
198
222
  page: current.id,
199
223
  title: current.title,
200
- fields: current.fields.map((f) => ({
201
- id: f.id,
202
- label: f.label,
203
- kind: f.kind,
204
- required: Boolean(f.required),
205
- options: f.options,
206
- placeholder: f.placeholder,
207
- help: f.help,
208
- default: f.default,
209
- value: run.state.values[f.id],
210
- columns: f.columns,
211
- // A file, a recording or a signature comes from the person's device: the run page.
212
- inChat: CHAT_KINDS.has(f.kind),
213
- })),
224
+ fields: current.fields.map((f) => {
225
+ const options = choicesOf(run, f);
226
+ return {
227
+ id: f.id,
228
+ label: f.label,
229
+ kind: f.kind,
230
+ required: Boolean(f.required),
231
+ options,
232
+ placeholder: f.placeholder,
233
+ help: f.help,
234
+ default: f.default,
235
+ value: run.state.values[f.id],
236
+ columns: f.columns,
237
+ // A file, a recording or a signature comes from the person's device: the run page.
238
+ inChat: CHAT_KINDS.has(f.kind),
239
+ ...slotHints(run, f, options),
240
+ };
241
+ }),
214
242
  };
215
243
  }
216
244
  if (current.type === "review") {
@@ -233,8 +233,10 @@ export async function createWizard(userId, input, writer = { source: "studio" })
233
233
  await putLink(shareToken, "wizard", id);
234
234
  if (fromStarter) {
235
235
  await seedFiles(id, fromStarter.files);
236
- // Counted at the marketplace, beside the request.
237
- void countInstall(fromStarter.id);
236
+ // Counted at the marketplace, beside the request; a plugin's starter is not the marketplace's.
237
+ if (!fromStarter.plugin) {
238
+ void countInstall(fromStarter.id);
239
+ }
238
240
  }
239
241
  if (input.note) {
240
242
  await addMessage(id, { role: "assistant", content: input.note, changed: true }, writer);
@@ -21,7 +21,8 @@ function stepTool(plugin, tool, ctx) {
21
21
  tenantId: ctx.tenantId,
22
22
  space,
23
23
  project: space,
24
- wizard: { title: ctx.def.title },
24
+ wizard: { id: ctx.store.wizardId, title: ctx.def.title },
25
+ mode: ctx.test ? "test" : "live",
25
26
  signal: ctx.signal,
26
27
  emit: (message) => ctx.emit("tool", message),
27
28
  })),
@@ -113,3 +114,30 @@ export async function assistantToolsOf(turn) {
113
114
  }
114
115
  return tools;
115
116
  }
117
+ /**
118
+ * The admin talks to the space assistant from a plugin's own page: what the plugin says that page
119
+ * holds now, and its name. `null` when the tenant has no such plugin.
120
+ */
121
+ export async function assistantPageOf(tenantId, pluginId, space) {
122
+ const plugin = (await pluginsOf(tenantId)).find((p) => p.source.id === pluginId);
123
+ if (!plugin) {
124
+ return null;
125
+ }
126
+ const blocks = [];
127
+ for (const page of plugin.assistantPages) {
128
+ try {
129
+ const text = await page.block(space);
130
+ if (text?.trim()) {
131
+ blocks.push(text.trim().slice(0, MAX_BLOCK));
132
+ }
133
+ }
134
+ catch (err) {
135
+ console.error(`[plugins] ${pluginId}: the assistant's page block failed:`, err);
136
+ }
137
+ }
138
+ return {
139
+ name: plugin.source.manifest.name,
140
+ description: plugin.source.manifest.description ?? null,
141
+ blocks,
142
+ };
143
+ }
@@ -0,0 +1 @@
1
+ import{a as e,n as t,t as n}from"./jsx-runtime-D3jfb0Ew.js";import{E as r,Z as i}from"./surface-BE-3Z1DP.js";import{D as a,G as o,H as s,c,f as l,g as u,h as d,j as f,k as p,n as ee,o as m,r as h,s as g,t as _,x as v}from"./ui-BZ01zr3i.js";import{n as y,r as b}from"./upload-U0i8fAW3.js";import{t as x}from"./external-link-BwCtn1nW.js";import{B as te,H as S,I as C,U as w,W as T,_t as E,at as D,ft as O}from"./index-DHM9S48l.js";import{n as k}from"./LocalRuntime-D7bzT40S.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=o(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=o(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=o(P),I=e(t(),1),L=e=>[`project-files`,e];function R(e){return r({queryKey:L(e),queryFn:()=>v.get(`/api/studio/projects/${e}/files`),refetchInterval:e=>e.state.data?.files.some(e=>e.status===`pending`)?2e3:!1})}function z(e,t){return a(`/api/studio/projects/${e}/files/${t}/content`)}function B(e,t=!1){let n=i(),[r,a]=(0,I.useState)(!1),[o,s]=(0,I.useState)(null),c=()=>n.invalidateQueries({queryKey:L(e)}),l=async e=>{s(null);try{await e()}catch(e){s(e.message)}finally{await c()}};return{busy:r,error:o,readOnly:t,upload:async(t,n)=>{a(!0),await l(async()=>{for(let r of n)await v.upload(`/api/studio/projects/${e}/files?kind=${t}`,r),await c()}),a(!1)},describe:(t,n)=>l(()=>v.patch(`/api/studio/projects/${e}/files/${t}`,{description:n})),remove:t=>l(()=>v.del(`/api/studio/projects/${e}/files/${t}`)),reindex:t=>l(()=>v.post(`/api/studio/projects/${e}/files/${t}/reindex`)),order:(t,n)=>l(()=>v.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)(l,{className:`size-3`}),` `,f(`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)(s,{className:`size-3.5`}),` `,f(`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)(ee,{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)(m,{label:f(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)(y,{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)(l,{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:u(`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=i(),[n,r]=(0,I.useState)(!1),a=E({mutationFn:e=>v.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:a,waiting:n}}function Q({link:e,waiting:t}){return e.isError?(0,W.jsx)(`p`,{className:`text-[0.8125rem] text-rose`,children:f(`local.accountFailed`)}):t?(0,W.jsxs)(`p`,{className:`flex items-center gap-2 text-[0.8125rem] text-ink-3`,children:[(0,W.jsx)(l,{className:`size-3.5`}),` `,f(`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:f(`account.local`)}),(0,W.jsx)(`p`,{className:`mt-1 text-[0.875rem] text-ink-3 leading-relaxed`,children:f(`account.localText`)})]})]}),w.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:f(`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)(b,{className:`mt-0.5 size-4 shrink-0 text-amber`}),f(`account.withCredits`)]}),(0,W.jsxs)(`li`,{className:`flex items-start gap-2.5`,children:[(0,W.jsx)(O,{className:`mt-0.5 size-4 shrink-0 text-cobalt`}),f(`account.withCloud`)]})]})]}),(0,W.jsx)(`div`,{children:(0,W.jsx)(_,{busy:t.isPending&&!t.variables?.signup,onClick:()=>t.mutate({}),children:f(`account.signIn`)})})]}):null,w.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:f(`account.new`)}),(0,W.jsx)(`p`,{className:`mt-1 text-[0.875rem] text-ink-3 leading-relaxed`,children:f(`account.newHint`)})]}),(0,W.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,W.jsx)(g,{value:n,maxLength:64,autoComplete:`off`,spellCheck:!1,placeholder:f(`account.code`),"aria-label":f(`account.code`),onChange:e=>r(e.target.value),className:`w-56 font-mono text-[0.875rem]`}),(0,W.jsx)(_,{type:`submit`,variant:`secondary`,className:`h-11`,busy:t.isPending&&!!t.variables?.signup,children:f(`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=i(),n=Z(e.signedIn),r=E({mutationFn:()=>v.del(`/api/studio/account`),onSuccess:()=>t.invalidateQueries({queryKey:[`me`]})}),a=new Intl.DateTimeFormat(p,{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)(h,{tone:`live`,children:f(`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)(_,{variant:`secondary`,onClick:()=>k(e.url),children:[f(`setup.openAccount`),` `,(0,W.jsx)(x,{className:`size-4`})]}),(0,W.jsxs)(_,{variant:`ghost`,busy:r.isPending,onClick:()=>r.mutate(),children:[(0,W.jsx)(D,{className:`size-4`}),` `,f(`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:f(`local.accountExpired`)}),(0,W.jsx)(`div`,{children:(0,W.jsx)(_,{busy:n.link.isPending,onClick:()=>n.link.mutate({}),children:f(`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:f(`account.credits`)}),(0,W.jsx)(`div`,{className:`font-display font-semibold text-[1.375rem] tabular-nums leading-tight`,children:f(`nav.credits`,{n:Math.floor(e.credits).toLocaleString()})})]}),(0,W.jsxs)(_,{variant:`secondary`,onClick:()=>k(`${e.url}/billing`),children:[f(`account.topUp`),` `,(0,W.jsx)(x,{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:[f(`account.expires`,{n:Math.floor(e.credits).toLocaleString(),date:a.format(new Date(e.expiresAt))}),$[e.kind]?(0,W.jsxs)(`span`,{className:`text-ink-4`,children:[` · `,f($[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)(O,{className:`mt-0.5 size-4 shrink-0 text-cobalt`}),(0,W.jsx)(`p`,{children:f(`account.cloud`,{host:C(e.cloudUrl)})})]})]})}function ie({me:e,fromAccount:t}){let n=i(),[r,a]=(0,I.useState)(e.profile),o=e=>a(t=>({...t,...e})),s=H(r,async e=>{await v.put(`/api/studio/profile`,e),await n.invalidateQueries({queryKey:[`me`]})});return(0,W.jsx)(K,{title:f(`account.profile`),hint:f(`account.hint`),save:s,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`}):T(r.name)||`?`}),(0,W.jsx)(`p`,{className:`text-center text-[0.75rem] text-ink-3 leading-snug`,children:f(`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)(c,{children:f(`account.name`)}),(0,W.jsx)(g,{value:r.name,maxLength:80,disabled:t,onChange:e=>o({name:e.target.value})}),(0,W.jsx)(`p`,{className:X,children:f(t?`account.fromAccount`:`account.nameHint`)})]}),(0,W.jsxs)(`div`,{children:[(0,W.jsx)(c,{children:f(`account.about`)}),(0,W.jsx)(d,{minRows:3,maxLength:2e3,value:r.about,onChange:e=>o({about:e.target.value})}),(0,W.jsx)(`p`,{className:X,children:f(`account.aboutHint`)})]}),(0,W.jsxs)(`div`,{className:`grid gap-5 sm:grid-cols-2`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(c,{children:f(`account.email`)}),(0,W.jsx)(g,{type:`email`,value:r.email,maxLength:200,disabled:t,onChange:e=>o({email:e.target.value})})]}),(0,W.jsxs)(`div`,{children:[(0,W.jsx)(c,{children:f(`account.phone`)}),(0,W.jsx)(g,{type:`tel`,value:r.phone,maxLength:40,onChange:e=>o({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:f(`account.connection`),hint:f(`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)(h,{tone:`live`,children:f(`account.linked`)})]}),(0,W.jsx)(`div`,{className:`truncate text-[0.875rem] text-ink-3`,children:e.user.email})]}),e.manageUrl?(0,W.jsxs)(_,{variant:`secondary`,onClick:()=>k(`${e.manageUrl}/account`),children:[f(`setup.openAccount`),` `,(0,W.jsx)(x,{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:f(`account.look`),hint:f(`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:f(`nav.language`)}),(0,W.jsx)(S,{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:f(`nav.theme`)}),(0,W.jsx)(te,{})]})]})})]})}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 +1 @@
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{a as i,f as a,g as o,i as s,s as c,x as l}from"./ui-BS348L4M.js";var u=e(t(),1),d=e(n(),1);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}async function _(e){if(e)try{let t=await fetch(`https://raw.githubusercontent.com/engenty/engenty-wizards/v${e}/apps/web/src/about/changelog.json`,{signal:AbortSignal.timeout(5e3)});if(t.ok)return await t.json()}catch{}return(await r(async()=>{let{default:e}=await import(`./changelog-COyL1B5X.js`);return{default:e}},[])).default}function v({open:e,onClose:t,version:n}){let[r,v]=(0,u.useState)(null),[y,b]=(0,u.useState)(``);(0,u.useEffect)(()=>{if(!e||r)return;let t=!1;return _(n).then(e=>{t||v(e)}),()=>{t=!0}},[e,r,n]),(0,u.useEffect)(()=>{e||b(``)},[e]);let x=r?g(r,y):[];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-[0.875rem] text-ink-3`,children:l(`about.changelogHint`)}),r===null?(0,d.jsx)(`div`,{className:`flex justify-center py-10 text-ink-3`,children:(0,d.jsx)(a,{})}):r.length===0?(0,d.jsx)(i,{children:l(`about.changelogEmpty`)}):(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(c,{type:`search`,value:y,placeholder:l(`about.search`),onChange:e=>b(e.target.value)}),x.length===0?(0,d.jsx)(i,{children:l(`about.noMatches`)}):null,x.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-[1rem]`,children:[p(e),(0,d.jsx)(`span`,{className:`font-normal font-sans text-[0.8125rem] 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-[0.875rem]`,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-[0.75rem] 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-[0.75rem] text-rose`,children:l(`about.breaking`)}):null]})]},e.id)})})]},e.version??`unreleased`))]})]})}export{v as ChangelogDialog};
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{a as i,f as a,g as o,i as s,j as c,s as l}from"./ui-BZ01zr3i.js";var u=e(t(),1),d=e(n(),1);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/,``):c(`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}async function _(e){if(e)try{let t=await fetch(`https://raw.githubusercontent.com/engenty/engenty-wizards/v${e}/apps/web/src/about/changelog.json`,{signal:AbortSignal.timeout(5e3)});if(t.ok)return await t.json()}catch{}return(await r(async()=>{let{default:e}=await import(`./changelog-C8wFW63z.js`);return{default:e}},[])).default}function v({open:e,onClose:t,version:n}){let[r,v]=(0,u.useState)(null),[y,b]=(0,u.useState)(``);(0,u.useEffect)(()=>{if(!e||r)return;let t=!1;return _(n).then(e=>{t||v(e)}),()=>{t=!0}},[e,r,n]),(0,u.useEffect)(()=>{e||b(``)},[e]);let x=r?g(r,y):[];return(0,d.jsxs)(s,{open:e,onClose:t,title:c(`about.changelog`),wide:!0,children:[(0,d.jsx)(`p`,{className:`-mt-3 mb-4 text-[0.875rem] text-ink-3`,children:c(`about.changelogHint`)}),r===null?(0,d.jsx)(`div`,{className:`flex justify-center py-10 text-ink-3`,children:(0,d.jsx)(a,{})}):r.length===0?(0,d.jsx)(i,{children:c(`about.changelogEmpty`)}):(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(l,{type:`search`,value:y,placeholder:c(`about.search`),onChange:e=>b(e.target.value)}),x.length===0?(0,d.jsx)(i,{children:c(`about.noMatches`)}):null,x.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-[1rem]`,children:[p(e),(0,d.jsx)(`span`,{className:`font-normal font-sans text-[0.8125rem] 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-[0.875rem]`,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-[0.75rem] 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-[0.75rem] text-rose`,children:c(`about.breaking`)}):null]})]},e.id)})})]},e.version??`unreleased`))]})]})}export{v as ChangelogDialog};
@@ -0,0 +1 @@
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{a as i,f as a,i as o,j as s,k as c,s as l}from"./ui-BZ01zr3i.js";import{t as u}from"./external-link-BwCtn1nW.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:i}){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)(u,{"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})]}),i?(0,m.jsx)(`p`,{className:`mt-0.5 text-[0.8125rem] text-ink-3`,children:i}):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[c]},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,c]=(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||c(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:s(`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)(o,{open:e,onClose:t,title:s(`about.credits`),wide:!0,children:[(0,m.jsx)(`p`,{className:`-mt-3 mb-4 text-[0.875rem] text-ink-3`,children:s(`about.creditsHint`)}),(0,m.jsx)(l,{type:`search`,value:u,placeholder:s(`about.search`),onChange:e=>g(e.target.value)}),C.length>0?(0,m.jsx)(_,{title:s(`about.creditsProduct`),children:(0,m.jsx)(v,{credits:C})}):null,w.length>0?(0,m.jsx)(_,{title:s(`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)(a,{})}):T.length>0?(0,m.jsx)(_,{title:s(`about.creditsDeps`),hint:b?void 0:s(`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)(i,{children:s(`about.noMatches`)}):null]})}export{b as CreditsDialog};