wizards 0.2.16 → 0.2.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/runtime/dist/agents/project-assistant.js +20 -2
- package/apps/runtime/dist/authoring/guide.js +6 -3
- package/apps/runtime/dist/credits/estimate.js +14 -8
- package/apps/runtime/dist/db/migrations/tenant/0008_run_event_note.sql +1 -0
- package/apps/runtime/dist/db/migrations/tenant/0009_knowledge.sql +104 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0008_snapshot.json +2019 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/0009_snapshot.json +2837 -0
- package/apps/runtime/dist/db/migrations/tenant/meta/_journal.json +14 -0
- package/apps/runtime/dist/db/schema.js +162 -8
- package/apps/runtime/dist/engine/events.js +14 -2
- package/apps/runtime/dist/engine/prepare.js +5 -2
- package/apps/runtime/dist/engine/requirements.js +108 -0
- package/apps/runtime/dist/engine/runner.js +2 -2
- package/apps/runtime/dist/engine/steps.js +21 -21
- package/apps/runtime/dist/engine/template.js +13 -10
- package/apps/runtime/dist/env.js +2 -0
- package/apps/runtime/dist/files/storage.js +15 -0
- package/apps/runtime/dist/models.js +38 -0
- package/apps/runtime/dist/plugins/loader.js +2 -0
- package/apps/runtime/dist/routes/studio.js +149 -8
- package/apps/runtime/dist/services/cloud.js +59 -1
- package/apps/runtime/dist/services/knowledge-model.js +558 -0
- package/apps/runtime/dist/services/knowledge.js +721 -0
- package/apps/runtime/dist/services/marketplace.js +2 -2
- package/apps/runtime/dist/services/project-files.js +114 -6
- package/apps/runtime/dist/services/project-index.js +632 -94
- package/apps/runtime/dist/services/relevance.js +90 -0
- package/apps/runtime/dist/services/space-categories.js +882 -0
- package/apps/runtime/dist/services/space-data.js +466 -38
- package/apps/runtime/dist/services/space-origin.js +164 -0
- package/apps/runtime/dist/services/spaces.js +155 -1
- package/apps/runtime/dist/tools/browser.js +12 -6
- package/apps/runtime/dist/tools/index.js +12 -6
- package/apps/runtime/dist/tools/mail.js +5 -2
- package/apps/runtime/dist/tools/pages.js +28 -23
- package/apps/runtime/dist/tools/project.js +132 -39
- package/apps/runtime/dist/tools/store.js +4 -4
- package/apps/runtime/dist/widgets/step.js +10 -4
- package/apps/web/dist/assets/{Account-BE_W101C.js → Account-Cp1cgqjV.js} +1 -1
- package/apps/web/dist/assets/{ChangelogDialog-DjKQJAos.js → ChangelogDialog-Chke1qUe.js} +1 -1
- package/apps/web/dist/assets/ChatPanel-DWrwewr6.js +1 -0
- package/apps/web/dist/assets/CreditsDialog-Ckema8Ss.js +1 -0
- package/apps/web/dist/assets/EditorPage-XX6pfHk5.js +2 -0
- package/apps/web/dist/assets/{FlowPreview-DK4RZqTW.js → FlowPreview-DS545n78.js} +1 -1
- package/apps/web/dist/assets/{Harness-DcI94f1U.js → Harness-H3yXP-2L.js} +2 -2
- package/apps/web/dist/assets/{HomePage-BBNFgryu.js → HomePage-Bds84ShK.js} +1 -1
- package/apps/web/dist/assets/{ImportWizard-BoYqovdl.js → ImportWizard-0_NkA8aS.js} +1 -1
- package/apps/web/dist/assets/LocalRuntime-DnABzTOe.js +1 -0
- package/apps/web/dist/assets/{NewWizardPage-tKV2S4eK.js → NewWizardPage-BqP75V9K.js} +2 -2
- package/apps/web/dist/assets/ProjectPage-DbOvwOdZ.js +5 -0
- package/apps/web/dist/assets/PublicRunner-CtZ7vxl_.js +1 -0
- package/apps/web/dist/assets/RunnerView-xV5bWclu.js +70 -0
- package/apps/web/dist/assets/SettingsPage-DKt55zFh.js +1 -0
- package/apps/web/dist/assets/{SetupPage-qxHvlf87.js → SetupPage-c6mMD9zN.js} +1 -1
- package/apps/web/dist/assets/SharePage-DTKIbMj-.js +1 -0
- package/apps/web/dist/assets/{api-t9_w1XNe.js → api-CVG-xDEn.js} +2 -2
- package/apps/web/dist/assets/changelog-CXXT0zsp.js +1 -0
- package/apps/web/dist/assets/{esm-D0YVMTdo.js → esm-DLM3jdbm.js} +1 -1
- package/apps/web/dist/assets/index-1gmaxDSk.js +10 -0
- package/apps/web/dist/assets/index-Bwyehu0k.css +1 -0
- package/apps/web/dist/assets/{meta-BJHYbMh7.js → meta-m947x6uG.js} +1 -1
- package/apps/web/dist/assets/{settings-menu-BqqUAvIY.js → settings-menu-DUY6__C3.js} +1 -1
- package/apps/web/dist/assets/ui-BPY2pIh0.js +1 -0
- package/apps/web/dist/index.html +4 -4
- package/apps/web/dist/mcp/flow.html +54 -54
- package/node_modules/@engenty-wizards/plugin-sdk/dist/index.d.ts +164 -0
- package/node_modules/@engenty-wizards/shared/dist/definition.d.ts +10 -0
- package/node_modules/@engenty-wizards/shared/dist/definition.js +25 -0
- package/node_modules/@engenty-wizards/shared/dist/knowledge.d.ts +199 -0
- package/node_modules/@engenty-wizards/shared/dist/knowledge.js +68 -0
- package/node_modules/@engenty-wizards/shared/dist/projects.d.ts +1 -16
- package/node_modules/@engenty-wizards/shared/dist/projects.js +1 -1
- package/node_modules/@engenty-wizards/shared/dist/run.d.ts +149 -0
- package/node_modules/@engenty-wizards/shared/dist/run.js +77 -1
- package/node_modules/@engenty-wizards/shared/dist/space-data.d.ts +20 -0
- package/node_modules/@engenty-wizards/shared/dist/space-data.js +2 -1
- package/package.json +1 -1
- package/apps/web/dist/assets/ChatPanel-BWrcDs4s.js +0 -1
- package/apps/web/dist/assets/CreditsDialog-DUjR5xkl.js +0 -1
- package/apps/web/dist/assets/EditorPage-CrOqikP2.js +0 -2
- package/apps/web/dist/assets/LocalRuntime-BD8zGN8w.js +0 -1
- package/apps/web/dist/assets/ProjectPage-voR0hvzy.js +0 -4
- package/apps/web/dist/assets/PublicRunner-CYZE_hSi.js +0 -1
- package/apps/web/dist/assets/RunnerView-D_C7hn81.js +0 -70
- package/apps/web/dist/assets/SettingsPage-DguoPF_3.js +0 -1
- package/apps/web/dist/assets/SharePage-Cf3i7KB-.js +0 -1
- package/apps/web/dist/assets/changelog-kz0DmHY4.js +0 -1
- package/apps/web/dist/assets/index-BPpKz65x.css +0 -1
- package/apps/web/dist/assets/index-D5w3fW1p.js +0 -10
- package/apps/web/dist/assets/ui-BHXO_e0e.js +0 -1
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { and, eq } from "drizzle-orm";
|
|
2
|
+
import { db, schema } from "../db/client.js";
|
|
3
|
+
import { UnreadableDocument } from "../documents/parse.js";
|
|
4
|
+
import { ServiceError } from "./errors.js";
|
|
5
|
+
import { filePaths, pageTree, tablePaths } from "./knowledge.js";
|
|
6
|
+
import { convertDocument, fillCategories, summarizeValues } from "./knowledge-model.js";
|
|
7
|
+
import { putOriginFile } from "./project-files.js";
|
|
8
|
+
import { queueIndex } from "./project-index.js";
|
|
9
|
+
import { putCategory, setItemCategories } from "./space-categories.js";
|
|
10
|
+
import { listOrigin, putOriginPage, putOriginTable, removeOrigin } from "./space-data.js";
|
|
11
|
+
/**
|
|
12
|
+
* `server.spaceData` of a plugin: Wissen it writes under keys of its own, with Kategorien. The
|
|
13
|
+
* plugin's id is the origin of everything it writes; a person who changes an item keeps it.
|
|
14
|
+
*/
|
|
15
|
+
export function originData(origin) {
|
|
16
|
+
return {
|
|
17
|
+
async putCategories({ space, categories, proposed }) {
|
|
18
|
+
for (const c of categories) {
|
|
19
|
+
let tableId = null;
|
|
20
|
+
if (c.column) {
|
|
21
|
+
const table = await db.query.spaceTable.findFirst({
|
|
22
|
+
where: and(eq(schema.spaceTable.projectId, space), eq(schema.spaceTable.origin, origin), eq(schema.spaceTable.originKey, c.column.table)),
|
|
23
|
+
columns: { id: true },
|
|
24
|
+
});
|
|
25
|
+
if (!table) {
|
|
26
|
+
throw new ServiceError("invalid", `There is no table with the key "${c.column.table}".`);
|
|
27
|
+
}
|
|
28
|
+
tableId = table.id;
|
|
29
|
+
}
|
|
30
|
+
await putCategory(space, {
|
|
31
|
+
name: c.name,
|
|
32
|
+
type: c.type,
|
|
33
|
+
unit: c.unit,
|
|
34
|
+
multiple: c.multiple,
|
|
35
|
+
ordered: c.ordered,
|
|
36
|
+
hint: c.hint,
|
|
37
|
+
values: c.values,
|
|
38
|
+
tableId,
|
|
39
|
+
columnId: c.column?.column ?? null,
|
|
40
|
+
}, { origin, proposed });
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
async putPage(input) {
|
|
44
|
+
const written = await putOriginPage(origin, {
|
|
45
|
+
...input,
|
|
46
|
+
categories: input.categories,
|
|
47
|
+
});
|
|
48
|
+
if (input.fill && written.state === "written") {
|
|
49
|
+
const changed = await fillCategories(input.space, { pageId: written.id }, input.markdown, input.title).catch((err) => {
|
|
50
|
+
console.error(`[plugin ${origin}] Kategorien`, err);
|
|
51
|
+
return false;
|
|
52
|
+
});
|
|
53
|
+
if (changed) {
|
|
54
|
+
queueIndex(`P:${written.id}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return { ...written, path: (await pageTree(input.space)).get(written.id)?.path ?? "" };
|
|
58
|
+
},
|
|
59
|
+
async putTable(input) {
|
|
60
|
+
const written = await putOriginTable(origin, {
|
|
61
|
+
...input,
|
|
62
|
+
categories: input.categories,
|
|
63
|
+
});
|
|
64
|
+
return { ...written, path: (await tablePaths(input.space)).get(written.id) ?? "" };
|
|
65
|
+
},
|
|
66
|
+
async putFile(input) {
|
|
67
|
+
const id = await putOriginFile(origin, {
|
|
68
|
+
...input,
|
|
69
|
+
categories: input.categories,
|
|
70
|
+
});
|
|
71
|
+
return { id, path: (await filePaths(input.space)).get(id) ?? "" };
|
|
72
|
+
},
|
|
73
|
+
async putDocument(input) {
|
|
74
|
+
const id = await putOriginFile(origin, { ...input, categories: undefined });
|
|
75
|
+
const file = await db.query.projectFile.findFirst({ where: eq(schema.projectFile.id, id) });
|
|
76
|
+
if (!file) {
|
|
77
|
+
throw new ServiceError("not_found", "The document went while it was read.");
|
|
78
|
+
}
|
|
79
|
+
const path = (await filePaths(input.space)).get(id) ?? "";
|
|
80
|
+
const kept = (await db.query.spacePage.findFirst({
|
|
81
|
+
where: and(eq(schema.spacePage.fileId, id), eq(schema.spacePage.kept, true)),
|
|
82
|
+
columns: { id: true },
|
|
83
|
+
})) ??
|
|
84
|
+
(await db.query.spaceTable.findFirst({
|
|
85
|
+
where: and(eq(schema.spaceTable.fileId, id), eq(schema.spaceTable.kept, true)),
|
|
86
|
+
columns: { id: true },
|
|
87
|
+
}));
|
|
88
|
+
if (kept) {
|
|
89
|
+
return { id, path, state: "kept", items: [], review: null };
|
|
90
|
+
}
|
|
91
|
+
let converted;
|
|
92
|
+
try {
|
|
93
|
+
converted = await convertDocument(file, input.data);
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
if (err instanceof UnreadableDocument) {
|
|
97
|
+
queueIndex(`f:${id}`);
|
|
98
|
+
return { id, path, state: "written", items: [], review: err.message };
|
|
99
|
+
}
|
|
100
|
+
throw err;
|
|
101
|
+
}
|
|
102
|
+
await db
|
|
103
|
+
.update(schema.projectFile)
|
|
104
|
+
.set({
|
|
105
|
+
textHash: converted.textHash,
|
|
106
|
+
pages: converted.pages,
|
|
107
|
+
chars: converted.chars,
|
|
108
|
+
updatedAt: new Date(),
|
|
109
|
+
})
|
|
110
|
+
.where(eq(schema.projectFile.id, id));
|
|
111
|
+
const [tree, tables] = await Promise.all([pageTree(input.space), tablePaths(input.space)]);
|
|
112
|
+
const items = await Promise.all(converted.items.map(async (key) => {
|
|
113
|
+
const itemId = key.slice(2);
|
|
114
|
+
if (key[0] === "p") {
|
|
115
|
+
const node = tree.get(itemId);
|
|
116
|
+
return {
|
|
117
|
+
kind: "page",
|
|
118
|
+
id: itemId,
|
|
119
|
+
path: node?.path ?? "",
|
|
120
|
+
title: node?.title ?? "",
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
const table = await db.query.spaceTable.findFirst({
|
|
124
|
+
where: eq(schema.spaceTable.id, itemId),
|
|
125
|
+
columns: { title: true },
|
|
126
|
+
});
|
|
127
|
+
return {
|
|
128
|
+
kind: "table",
|
|
129
|
+
id: itemId,
|
|
130
|
+
path: tables.get(itemId) ?? "",
|
|
131
|
+
title: table?.title ?? "",
|
|
132
|
+
};
|
|
133
|
+
}));
|
|
134
|
+
const first = items[0];
|
|
135
|
+
const ref = first
|
|
136
|
+
? first.kind === "page"
|
|
137
|
+
? { pageId: first.id }
|
|
138
|
+
: { tableId: first.id }
|
|
139
|
+
: { fileId: id };
|
|
140
|
+
if (input.categories) {
|
|
141
|
+
await setItemCategories(input.space, ref, input.categories, "origin");
|
|
142
|
+
}
|
|
143
|
+
if (input.fill) {
|
|
144
|
+
await fillCategories(input.space, ref, converted.text, input.name).catch((err) => {
|
|
145
|
+
console.error(`[plugin ${origin}] Kategorien`, err);
|
|
146
|
+
return false;
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
if (input.categories || input.fill) {
|
|
150
|
+
queueIndex(first ? `${first.kind === "page" ? "P" : "t"}:${first.id}` : `f:${id}`);
|
|
151
|
+
}
|
|
152
|
+
const review = first?.kind === "page"
|
|
153
|
+
? ((await db.query.spacePage.findFirst({
|
|
154
|
+
where: eq(schema.spacePage.id, first.id),
|
|
155
|
+
columns: { review: true },
|
|
156
|
+
}))?.review ?? null)
|
|
157
|
+
: null;
|
|
158
|
+
return { id, path, state: "written", items, review };
|
|
159
|
+
},
|
|
160
|
+
list: (space) => listOrigin(origin, space),
|
|
161
|
+
remove: (space, key) => removeOrigin(origin, space, key),
|
|
162
|
+
summarize: (space, category, value) => summarizeValues(space, category, value),
|
|
163
|
+
};
|
|
164
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { tableColumnsSchema } from "@engenty-wizards/shared/engenty/data-tables";
|
|
3
|
+
import { CATEGORY_TYPES } from "@engenty-wizards/shared/knowledge";
|
|
3
4
|
import { PROJECT_LIMITS } from "@engenty-wizards/shared/projects";
|
|
4
5
|
import { SPACE_DATA_LIMITS } from "@engenty-wizards/shared/space-data";
|
|
5
6
|
import { WORKSPACE_LIMITS } from "@engenty-wizards/shared/workspace";
|
|
@@ -17,6 +18,7 @@ import { emitDraftChanged } from "./draft-events.js";
|
|
|
17
18
|
import { notFound, ServiceError } from "./errors.js";
|
|
18
19
|
import { keepFiles, replaceFiles } from "./files.js";
|
|
19
20
|
import { addProjectFile, projectFiles, removeProjectFile } from "./project-files.js";
|
|
21
|
+
import { reindexSpace } from "./project-index.js";
|
|
20
22
|
import { brandColorSchema, projectFactSchema, projectLimit, removeProject, } from "./projects.js";
|
|
21
23
|
import { deleteWizard, draftIssues, parseDraft, rotateShareLink, shareUrl } from "./wizards.js";
|
|
22
24
|
/**
|
|
@@ -411,11 +413,15 @@ export async function removeSyncedSpace(rawSpaceId) {
|
|
|
411
413
|
// --- the space's own tables and pages --------------------------------------------
|
|
412
414
|
// What the admin made under Space → Daten on the install, not what a wizard keeps: those stay
|
|
413
415
|
// where their runs write them. Sent as a whole, it replaces what came before.
|
|
416
|
+
// Since Wissen: sub-pages, where an item came from, Kategorien and what has them. An install of
|
|
417
|
+
// before sends none of it.
|
|
414
418
|
export const syncDataSchema = z.object({
|
|
415
419
|
tables: z
|
|
416
420
|
.array(z.object({
|
|
417
421
|
id: syncedId,
|
|
418
422
|
title: z.string().min(1).max(120),
|
|
423
|
+
format: z.enum(["faq"]).nullish(),
|
|
424
|
+
originLabel: z.string().max(120).nullish(),
|
|
419
425
|
columns: tableColumnsSchema,
|
|
420
426
|
rows: z
|
|
421
427
|
.array(z.object({ id: syncedId, cells: z.record(z.string(), z.unknown()) }))
|
|
@@ -427,8 +433,48 @@ export const syncDataSchema = z.object({
|
|
|
427
433
|
id: syncedId,
|
|
428
434
|
title: z.string().min(1).max(200),
|
|
429
435
|
markdown: z.string().max(SPACE_DATA_LIMITS.pageChars),
|
|
436
|
+
parentId: syncedId.nullish(),
|
|
437
|
+
position: z.number().int().min(0).optional(),
|
|
438
|
+
originLabel: z.string().max(120).nullish(),
|
|
430
439
|
}))
|
|
431
440
|
.max(SPACE_DATA_LIMITS.pages),
|
|
441
|
+
categories: z
|
|
442
|
+
.array(z.object({
|
|
443
|
+
id: syncedId,
|
|
444
|
+
name: z.string().min(1).max(80),
|
|
445
|
+
type: z.enum(CATEGORY_TYPES),
|
|
446
|
+
unit: z.string().max(20).nullish(),
|
|
447
|
+
multiple: z.boolean(),
|
|
448
|
+
ordered: z.boolean(),
|
|
449
|
+
hint: z.string().max(120).nullish(),
|
|
450
|
+
tableId: syncedId.nullish(),
|
|
451
|
+
columnId: z.string().max(64).nullish(),
|
|
452
|
+
position: z.number().int().min(0),
|
|
453
|
+
values: z
|
|
454
|
+
.array(z.object({
|
|
455
|
+
id: syncedId,
|
|
456
|
+
value: z.string().min(1).max(200),
|
|
457
|
+
position: z.number().int().min(0),
|
|
458
|
+
summary: z.string().max(20_000).nullish(),
|
|
459
|
+
}))
|
|
460
|
+
.max(2000),
|
|
461
|
+
}))
|
|
462
|
+
.max(60)
|
|
463
|
+
.optional(),
|
|
464
|
+
/** `p:<page>`, `t:<table>`, `r:<row>`: files stay with the install. */
|
|
465
|
+
assignments: z
|
|
466
|
+
.array(z.object({
|
|
467
|
+
categoryId: syncedId,
|
|
468
|
+
item: z.string().regex(/^[ptr]:[A-Za-z0-9_-]{8,40}$/),
|
|
469
|
+
valueId: syncedId.nullish(),
|
|
470
|
+
text: z.string().max(300).nullish(),
|
|
471
|
+
num: z.number().nullish(),
|
|
472
|
+
at: z.number().int().nullish(),
|
|
473
|
+
bool: z.boolean().nullish(),
|
|
474
|
+
by: z.enum(["person", "origin", "model"]),
|
|
475
|
+
}))
|
|
476
|
+
.max(200_000)
|
|
477
|
+
.optional(),
|
|
432
478
|
});
|
|
433
479
|
/**
|
|
434
480
|
* Takes the space's own tables and pages a local install sent: those it no longer has go, the
|
|
@@ -491,12 +537,120 @@ export async function syncSpaceData(rawSpaceId, input) {
|
|
|
491
537
|
}
|
|
492
538
|
}
|
|
493
539
|
for (const page of input.pages) {
|
|
494
|
-
const values = {
|
|
540
|
+
const values = {
|
|
541
|
+
title: page.title,
|
|
542
|
+
markdown: page.markdown,
|
|
543
|
+
position: page.position ?? 0,
|
|
544
|
+
originLabel: page.originLabel ?? null,
|
|
545
|
+
// Its place comes after every page is there.
|
|
546
|
+
parentId: null,
|
|
547
|
+
slug: null,
|
|
548
|
+
updatedAt: now,
|
|
549
|
+
};
|
|
495
550
|
await db
|
|
496
551
|
.insert(schema.spacePage)
|
|
497
552
|
.values({ id: page.id, tenantId: currentTenant(), projectId: spaceId, ...values })
|
|
498
553
|
.onConflictDoUpdate({ target: schema.spacePage.id, set: values });
|
|
499
554
|
}
|
|
555
|
+
const pagesThere = new Set(pageIds);
|
|
556
|
+
for (const page of input.pages) {
|
|
557
|
+
if (page.parentId && pagesThere.has(page.parentId) && page.parentId !== page.id) {
|
|
558
|
+
await db
|
|
559
|
+
.update(schema.spacePage)
|
|
560
|
+
.set({ parentId: page.parentId })
|
|
561
|
+
.where(eq(schema.spacePage.id, page.id));
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
for (const table of input.tables) {
|
|
565
|
+
await db
|
|
566
|
+
.update(schema.spaceTable)
|
|
567
|
+
.set({ format: table.format ?? null, originLabel: table.originLabel ?? null, slug: null })
|
|
568
|
+
.where(eq(schema.spaceTable.id, table.id));
|
|
569
|
+
}
|
|
570
|
+
if (input.categories) {
|
|
571
|
+
await syncCategories(spaceId, input.categories, input.assignments ?? []);
|
|
572
|
+
}
|
|
500
573
|
});
|
|
574
|
+
await reindexSpace(spaceId);
|
|
501
575
|
return { tables: input.tables.length, pages: input.pages.length };
|
|
502
576
|
}
|
|
577
|
+
/** The Kategorien a local install sent, their values, and what has them: they replace these here. */
|
|
578
|
+
async function syncCategories(spaceId, categories, assignments) {
|
|
579
|
+
const ids = categories.map((c) => c.id);
|
|
580
|
+
const taken = ids.length
|
|
581
|
+
? await db.query.spaceCategory.findMany({
|
|
582
|
+
where: inArray(schema.spaceCategory.id, ids),
|
|
583
|
+
columns: { id: true, projectId: true },
|
|
584
|
+
})
|
|
585
|
+
: [];
|
|
586
|
+
if (taken.some((c) => c.projectId !== spaceId)) {
|
|
587
|
+
throw new ServiceError("refused", "Eine Kennung ist hier schon vergeben.", {
|
|
588
|
+
reason: "id_taken",
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
await db
|
|
592
|
+
.delete(schema.spaceCategory)
|
|
593
|
+
.where(and(eq(schema.spaceCategory.projectId, spaceId), ids.length ? notInArray(schema.spaceCategory.id, ids) : undefined));
|
|
594
|
+
await db.delete(schema.spaceItemCategory).where(eq(schema.spaceItemCategory.projectId, spaceId));
|
|
595
|
+
const tables = new Set((await db.query.spaceTable.findMany({
|
|
596
|
+
where: eq(schema.spaceTable.projectId, spaceId),
|
|
597
|
+
columns: { id: true },
|
|
598
|
+
})).map((t) => t.id));
|
|
599
|
+
const values = new Set();
|
|
600
|
+
for (const c of categories) {
|
|
601
|
+
const row = {
|
|
602
|
+
name: c.name,
|
|
603
|
+
type: c.type,
|
|
604
|
+
unit: c.unit ?? null,
|
|
605
|
+
multiple: c.multiple,
|
|
606
|
+
ordered: c.ordered,
|
|
607
|
+
hint: c.hint ?? null,
|
|
608
|
+
proposed: false,
|
|
609
|
+
tableId: c.tableId && tables.has(c.tableId) ? c.tableId : null,
|
|
610
|
+
columnId: c.tableId && tables.has(c.tableId) ? (c.columnId ?? null) : null,
|
|
611
|
+
position: c.position,
|
|
612
|
+
updatedAt: new Date(),
|
|
613
|
+
};
|
|
614
|
+
await db
|
|
615
|
+
.insert(schema.spaceCategory)
|
|
616
|
+
.values({ id: c.id, tenantId: currentTenant(), projectId: spaceId, ...row })
|
|
617
|
+
.onConflictDoUpdate({ target: schema.spaceCategory.id, set: row });
|
|
618
|
+
const valueIds = c.values.map((v) => v.id);
|
|
619
|
+
await db
|
|
620
|
+
.delete(schema.spaceCategoryValue)
|
|
621
|
+
.where(and(eq(schema.spaceCategoryValue.categoryId, c.id), valueIds.length ? notInArray(schema.spaceCategoryValue.id, valueIds) : undefined));
|
|
622
|
+
for (const v of c.values) {
|
|
623
|
+
const set = {
|
|
624
|
+
value: v.value,
|
|
625
|
+
position: v.position,
|
|
626
|
+
summary: v.summary ?? null,
|
|
627
|
+
summaryAt: v.summary ? new Date() : null,
|
|
628
|
+
};
|
|
629
|
+
await db
|
|
630
|
+
.insert(schema.spaceCategoryValue)
|
|
631
|
+
.values({ id: v.id, categoryId: c.id, ...set })
|
|
632
|
+
.onConflictDoUpdate({ target: schema.spaceCategoryValue.id, set });
|
|
633
|
+
values.add(v.id);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
const known = new Set(ids);
|
|
637
|
+
const rows = assignments.filter((a) => known.has(a.categoryId) && (!a.valueId || values.has(a.valueId)));
|
|
638
|
+
for (let i = 0; i < rows.length; i += 200) {
|
|
639
|
+
await db.insert(schema.spaceItemCategory).values(rows.slice(i, i + 200).map((a) => {
|
|
640
|
+
const id = a.item.slice(2);
|
|
641
|
+
return {
|
|
642
|
+
projectId: spaceId,
|
|
643
|
+
categoryId: a.categoryId,
|
|
644
|
+
pageId: a.item[0] === "p" ? id : null,
|
|
645
|
+
tableId: a.item[0] === "t" ? id : null,
|
|
646
|
+
rowId: a.item[0] === "r" ? id : null,
|
|
647
|
+
valueId: a.valueId ?? null,
|
|
648
|
+
text: a.text ?? null,
|
|
649
|
+
num: a.num ?? null,
|
|
650
|
+
at: a.at ?? null,
|
|
651
|
+
bool: a.bool ?? null,
|
|
652
|
+
by: a.by,
|
|
653
|
+
};
|
|
654
|
+
}));
|
|
655
|
+
}
|
|
656
|
+
}
|
|
@@ -141,7 +141,7 @@ export function browserTools(ctx, assets, files) {
|
|
|
141
141
|
inputSchema: z.object({ url: z.string() }),
|
|
142
142
|
execute: ({ url }) => inTurn(async () => {
|
|
143
143
|
const safe = await assertPublicUrl(url);
|
|
144
|
-
await ctx.emit("tool",
|
|
144
|
+
await ctx.emit("tool", { code: "opens", params: { name: safe.hostname } });
|
|
145
145
|
const p = await page();
|
|
146
146
|
await p.goto(safe.toString(), { waitUntil: "domcontentloaded", timeout: 30_000 });
|
|
147
147
|
await p.waitForLoadState("networkidle", { timeout: 5000 }).catch(() => undefined);
|
|
@@ -154,7 +154,7 @@ export function browserTools(ctx, assets, files) {
|
|
|
154
154
|
inputSchema: z.object({ ref: z.number() }),
|
|
155
155
|
execute: ({ ref: n }) => inTurn(async () => {
|
|
156
156
|
const p = await page();
|
|
157
|
-
await ctx.emit("tool",
|
|
157
|
+
await ctx.emit("tool", { code: "clicks" });
|
|
158
158
|
const popup = p
|
|
159
159
|
.context()
|
|
160
160
|
.waitForEvent("page", { timeout: 3000 })
|
|
@@ -176,7 +176,7 @@ export function browserTools(ctx, assets, files) {
|
|
|
176
176
|
inputSchema: z.object({ ref: z.number(), text: z.string(), submit: z.boolean().optional() }),
|
|
177
177
|
execute: ({ ref: n, text, submit }) => inTurn(async () => {
|
|
178
178
|
const p = await page();
|
|
179
|
-
await ctx.emit("tool",
|
|
179
|
+
await ctx.emit("tool", { code: "types" });
|
|
180
180
|
const el = p.locator(ref(n)).first();
|
|
181
181
|
await el.fill(text, { timeout: 10_000 });
|
|
182
182
|
if (submit) {
|
|
@@ -192,7 +192,7 @@ export function browserTools(ctx, assets, files) {
|
|
|
192
192
|
inputSchema: z.object({ save: z.boolean().optional(), name: z.string().optional() }),
|
|
193
193
|
execute: ({ save, name }) => inTurn(async () => {
|
|
194
194
|
const p = await page();
|
|
195
|
-
await ctx.emit("tool",
|
|
195
|
+
await ctx.emit("tool", { code: "looksAtPage" });
|
|
196
196
|
const png = await p.screenshot({ type: "png" });
|
|
197
197
|
let saved;
|
|
198
198
|
if (save) {
|
|
@@ -235,7 +235,10 @@ export function browserTools(ctx, assets, files) {
|
|
|
235
235
|
};
|
|
236
236
|
}
|
|
237
237
|
}
|
|
238
|
-
await ctx.emit("tool",
|
|
238
|
+
await ctx.emit("tool", {
|
|
239
|
+
code: "waitsForSignIn",
|
|
240
|
+
params: { name: new URL(origin).hostname },
|
|
241
|
+
});
|
|
239
242
|
const answer = await ctx.ask({
|
|
240
243
|
kind: "login",
|
|
241
244
|
reason: input.reason,
|
|
@@ -321,7 +324,10 @@ export function browserTools(ctx, assets, files) {
|
|
|
321
324
|
}),
|
|
322
325
|
execute: ({ ref: n, url, path, source }) => inTurn(async () => {
|
|
323
326
|
const p = await page();
|
|
324
|
-
await ctx.emit("tool",
|
|
327
|
+
await ctx.emit("tool", {
|
|
328
|
+
code: "downloads",
|
|
329
|
+
params: { name: path.split("/").pop() ?? "" },
|
|
330
|
+
});
|
|
325
331
|
let data;
|
|
326
332
|
let mime;
|
|
327
333
|
if (url) {
|
|
@@ -49,7 +49,7 @@ export async function buildStepTools(step, ctx, resolved, uploads) {
|
|
|
49
49
|
inputSchema: z.object({ url: z.string().describe("Absolute http(s) URL") }),
|
|
50
50
|
execute: async ({ url }) => {
|
|
51
51
|
const safe = await assertPublicUrl(url);
|
|
52
|
-
await ctx.emit("tool",
|
|
52
|
+
await ctx.emit("tool", { code: "reads", params: { name: safe.hostname } });
|
|
53
53
|
const res = await safeFetch(safe.toString(), {
|
|
54
54
|
signal: AbortSignal.any([ctx.signal, AbortSignal.timeout(20_000)]),
|
|
55
55
|
headers: { "user-agent": "Mozilla/5.0 (compatible; engenty-wizards/0.1)" },
|
|
@@ -115,7 +115,7 @@ export async function buildStepTools(step, ctx, resolved, uploads) {
|
|
|
115
115
|
description: shellToolDescription(sandbox),
|
|
116
116
|
inputSchema: z.object({ command: z.string(), timeoutSeconds: z.number().optional() }),
|
|
117
117
|
execute: async ({ command, timeoutSeconds }) => {
|
|
118
|
-
await ctx.emit("tool",
|
|
118
|
+
await ctx.emit("tool", { code: "runs", params: { command: command.slice(0, 80) } });
|
|
119
119
|
return report(await ctx.resources
|
|
120
120
|
.sandboxHandle()
|
|
121
121
|
.exec(command, { timeoutMs: timeoutMs(timeoutSeconds) }));
|
|
@@ -131,7 +131,7 @@ export async function buildStepTools(step, ctx, resolved, uploads) {
|
|
|
131
131
|
timeoutSeconds: z.number().optional(),
|
|
132
132
|
}),
|
|
133
133
|
execute: async ({ code, packages, timeoutSeconds }) => {
|
|
134
|
-
await ctx.emit("tool",
|
|
134
|
+
await ctx.emit("tool", { code: "python" });
|
|
135
135
|
return report(await ctx.resources.sandboxHandle().runPython(code, {
|
|
136
136
|
packages,
|
|
137
137
|
timeoutMs: timeoutMs(timeoutSeconds),
|
|
@@ -174,7 +174,7 @@ export async function buildStepTools(step, ctx, resolved, uploads) {
|
|
|
174
174
|
aspectRatio: z.enum(["1:1", "16:9", "9:16", "4:5", "3:2", "2:3"]).optional(),
|
|
175
175
|
}),
|
|
176
176
|
execute: async ({ prompt, aspectRatio }) => {
|
|
177
|
-
await ctx.emit("tool",
|
|
177
|
+
await ctx.emit("tool", { code: "drawing" });
|
|
178
178
|
const media = await generateImageMedia({
|
|
179
179
|
call: ctx.call,
|
|
180
180
|
prompt,
|
|
@@ -225,10 +225,16 @@ export async function buildStepTools(step, ctx, resolved, uploads) {
|
|
|
225
225
|
});
|
|
226
226
|
try {
|
|
227
227
|
Object.assign(tools, await mcp.listTools());
|
|
228
|
-
await ctx.emit("tool",
|
|
228
|
+
await ctx.emit("tool", {
|
|
229
|
+
code: "mcpConnected",
|
|
230
|
+
params: { names: servers.map((s) => s.name).join(", ") },
|
|
231
|
+
});
|
|
229
232
|
}
|
|
230
233
|
catch (err) {
|
|
231
|
-
await ctx.emit("info",
|
|
234
|
+
await ctx.emit("info", {
|
|
235
|
+
code: "mcpUnreachable",
|
|
236
|
+
params: { detail: err.message },
|
|
237
|
+
});
|
|
232
238
|
}
|
|
233
239
|
}
|
|
234
240
|
return {
|
|
@@ -29,7 +29,7 @@ export function mailTools(step, ctx, files) {
|
|
|
29
29
|
inputSchema: mailSearchInput,
|
|
30
30
|
execute: (input) => attempt(async () => {
|
|
31
31
|
const { connector, ctx: actionCtx, label } = await open();
|
|
32
|
-
await ctx.emit("tool",
|
|
32
|
+
await ctx.emit("tool", { code: "searchesMail", params: { label } });
|
|
33
33
|
const { mails } = await mailAction(connector, "search", input, actionCtx);
|
|
34
34
|
return {
|
|
35
35
|
mailbox: label,
|
|
@@ -64,7 +64,10 @@ export function mailTools(step, ctx, files) {
|
|
|
64
64
|
}),
|
|
65
65
|
execute: ({ items }) => attempt(async () => {
|
|
66
66
|
const { connector, ctx: actionCtx, label } = await open();
|
|
67
|
-
await ctx.emit("tool",
|
|
67
|
+
await ctx.emit("tool", {
|
|
68
|
+
code: "savesReceipts",
|
|
69
|
+
params: { count: items.length, label },
|
|
70
|
+
});
|
|
68
71
|
const saved = [];
|
|
69
72
|
for (const item of items) {
|
|
70
73
|
try {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { createTool } from "@mastra/core/tools";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { runPages, writeRunPage } from "../services/space-data.js";
|
|
4
|
+
import { pageReadInput, readKnowledgePage } from "./project.js";
|
|
4
5
|
import { attempt, clip } from "./shared.js";
|
|
5
6
|
/**
|
|
6
|
-
* Pages
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* Pages for a step that lists "pages": Markdown its wizard keeps for every run — notes, a log, a
|
|
8
|
+
* summary that grows — shown in the studio under Space → Daten. Its page_read also reads the
|
|
9
|
+
* pages of Wissen, by path.
|
|
9
10
|
*/
|
|
10
11
|
export function pageTools(ctx) {
|
|
11
12
|
const projectId = ctx.project.id;
|
|
@@ -13,29 +14,33 @@ export function pageTools(ctx) {
|
|
|
13
14
|
return {
|
|
14
15
|
page_read: createTool({
|
|
15
16
|
id: "page_read",
|
|
16
|
-
description: "Read a page
|
|
17
|
-
inputSchema: z.object({
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return {
|
|
23
|
-
pages: pages.map((p) => ({ title: p.title, of: of(p), chars: p.markdown.length })),
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
const page = pages.find((p) => p.title.toLowerCase() === title.trim().toLowerCase());
|
|
27
|
-
if (!page) {
|
|
28
|
-
return {
|
|
29
|
-
error: `No page "${title}".`,
|
|
30
|
-
pages: pages.map((p) => p.title),
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
return { title: page.title, of: of(page), markdown: clip(page.markdown, 40_000) };
|
|
17
|
+
description: "Read a page: one this wizard wrote, by its title, or a page of Wissen, by its path (pages/…). Without either it lists the wizard's pages.",
|
|
18
|
+
inputSchema: z.object({
|
|
19
|
+
title: z.string().optional().describe("A page this wizard wrote"),
|
|
20
|
+
path: pageReadInput.path.optional(),
|
|
21
|
+
section: pageReadInput.section,
|
|
22
|
+
from: pageReadInput.from,
|
|
34
23
|
}),
|
|
24
|
+
execute: ({ title, path, section, from }) => {
|
|
25
|
+
if (path?.trim()) {
|
|
26
|
+
return readKnowledgePage(ctx, { path, section, from });
|
|
27
|
+
}
|
|
28
|
+
return attempt(async () => {
|
|
29
|
+
const pages = await runPages(projectId, wizardId);
|
|
30
|
+
if (!title?.trim()) {
|
|
31
|
+
return { pages: pages.map((p) => ({ title: p.title, chars: p.markdown.length })) };
|
|
32
|
+
}
|
|
33
|
+
const page = pages.find((p) => p.title.toLowerCase() === title.trim().toLowerCase());
|
|
34
|
+
if (!page) {
|
|
35
|
+
return { error: `No page "${title}".`, pages: pages.map((p) => p.title) };
|
|
36
|
+
}
|
|
37
|
+
return { title: page.title, markdown: clip(page.markdown, 40_000) };
|
|
38
|
+
});
|
|
39
|
+
},
|
|
35
40
|
}),
|
|
36
41
|
page_write: createTool({
|
|
37
42
|
id: "page_write",
|
|
38
|
-
description: "Write a page of this wizard in Markdown, kept for every later run and shown to the admin in the studio. A page with the same title is replaced — or added to with append: true (a log, a list that grows).
|
|
43
|
+
description: "Write a page of this wizard in Markdown, kept for every later run and shown to the admin in the studio. A page with the same title is replaced — or added to with append: true (a log, a list that grows). Pages of Wissen are read-only.",
|
|
39
44
|
inputSchema: z.object({
|
|
40
45
|
title: z.string().min(1).max(200),
|
|
41
46
|
markdown: z.string().max(200_000),
|
|
@@ -43,7 +48,7 @@ export function pageTools(ctx) {
|
|
|
43
48
|
}),
|
|
44
49
|
execute: (input) => attempt(async () => {
|
|
45
50
|
const page = await writeRunPage(projectId, wizardId, input);
|
|
46
|
-
await ctx.emit("tool",
|
|
51
|
+
await ctx.emit("tool", { code: "writesPage", params: { title: page.title } });
|
|
47
52
|
return page;
|
|
48
53
|
}),
|
|
49
54
|
}),
|