plugin-build-guide-block 1.0.12 → 1.1.3

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 (35) hide show
  1. package/README.md +16 -74
  2. package/dist/client/components/SpaceSelect.d.ts +2 -0
  3. package/dist/client/index.js +9 -10
  4. package/dist/client/schemas/spacesSchema.d.ts +81 -0
  5. package/dist/externalVersion.js +7 -16
  6. package/dist/index.js +0 -9
  7. package/dist/locale/en-US.json +12 -4
  8. package/dist/locale/namespace.js +0 -9
  9. package/dist/locale/vi-VN.json +12 -4
  10. package/dist/locale/zh-CN.json +12 -4
  11. package/dist/server/actions/build.js +346 -80
  12. package/dist/server/actions/getHtml.js +0 -9
  13. package/dist/server/actions/getMarkdown.js +0 -9
  14. package/dist/server/collections/ai-build-guide-pages.d.ts +2 -0
  15. package/dist/server/collections/ai-build-guide-pages.js +81 -0
  16. package/dist/server/collections/ai-build-guide-spaces.js +33 -9
  17. package/dist/server/index.js +0 -9
  18. package/dist/server/plugin.d.ts +3 -0
  19. package/dist/server/plugin.js +50 -21
  20. package/package.json +1 -1
  21. package/src/client/UserGuideBlock.tsx +368 -53
  22. package/src/client/UserGuideBlockProvider.tsx +9 -8
  23. package/src/client/UserGuideManager.tsx +52 -23
  24. package/src/client/components/SpaceSelect.tsx +37 -0
  25. package/src/client/models/UserGuideBlockModel.ts +19 -29
  26. package/src/client/plugin.tsx +3 -2
  27. package/src/client/schemaSettings.ts +2 -12
  28. package/src/client/schemas/spacesSchema.ts +439 -357
  29. package/src/locale/en-US.json +12 -4
  30. package/src/locale/vi-VN.json +12 -4
  31. package/src/locale/zh-CN.json +12 -4
  32. package/src/server/actions/build.ts +501 -189
  33. package/src/server/collections/ai-build-guide-pages.ts +60 -0
  34. package/src/server/collections/ai-build-guide-spaces.ts +57 -24
  35. package/src/server/plugin.ts +58 -11
@@ -1,12 +1,3 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
1
  var __create = Object.create;
11
2
  var __defProp = Object.defineProperty;
12
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -44,7 +35,12 @@ var import_messages = require("@langchain/core/messages");
44
35
  var import_axios = __toESM(require("axios"));
45
36
  var import_fs = __toESM(require("fs"));
46
37
  var import_path = __toESM(require("path"));
38
+ var import_crypto = __toESM(require("crypto"));
47
39
  var import_marked = require("marked");
40
+ const MAX_SOURCE_CHARS = 9e4;
41
+ const MIN_CHAPTERS = 1;
42
+ const MAX_CHAPTERS = 12;
43
+ const DEFAULT_TARGET_CHAPTERS = 5;
48
44
  const SANITIZE_OPTIONS = {
49
45
  allowedTags: [
50
46
  "div",
@@ -78,7 +74,7 @@ const SANITIZE_OPTIONS = {
78
74
  allowedAttributes: {
79
75
  a: ["href", "target"],
80
76
  img: ["src", "alt", "width", "height"],
81
- "*": ["style", "class"]
77
+ "*": ["style", "class", "id"]
82
78
  },
83
79
  allowedStyles: {
84
80
  "*": {
@@ -89,6 +85,11 @@ const SANITIZE_OPTIONS = {
89
85
  }
90
86
  }
91
87
  };
88
+ function clampChapterCount(value) {
89
+ const count = Number(value);
90
+ if (!Number.isFinite(count)) return DEFAULT_TARGET_CHAPTERS;
91
+ return Math.max(MIN_CHAPTERS, Math.min(MAX_CHAPTERS, Math.round(count)));
92
+ }
92
93
  async function fetchFileContent(app, file) {
93
94
  const fileManager = app.pm.get("file-manager");
94
95
  if (!fileManager) return "";
@@ -97,20 +98,341 @@ async function fetchFileContent(app, file) {
97
98
  if (url.startsWith("http")) {
98
99
  const response = await import_axios.default.get(url, { responseType: "text", timeout: 15e3 });
99
100
  return response.data;
100
- } else {
101
- let localPath = url;
102
- if (process.env.APP_PUBLIC_PATH && localPath.startsWith(process.env.APP_PUBLIC_PATH)) {
103
- localPath = localPath.slice(process.env.APP_PUBLIC_PATH.length);
104
- }
105
- localPath = import_path.default.join(process.cwd(), localPath);
106
- const data = await import_fs.default.promises.readFile(localPath, "utf8");
107
- return data;
108
101
  }
102
+ let localPath = url;
103
+ if (process.env.APP_PUBLIC_PATH && localPath.startsWith(process.env.APP_PUBLIC_PATH)) {
104
+ localPath = localPath.slice(process.env.APP_PUBLIC_PATH.length);
105
+ }
106
+ localPath = import_path.default.join(process.cwd(), localPath);
107
+ return await import_fs.default.promises.readFile(localPath, "utf8");
109
108
  } catch (err) {
110
109
  app.log.error(`Failed to read file content for document ${file.id}`, err);
111
110
  return `[Failed to read document: ${file.filename}]`;
112
111
  }
113
112
  }
113
+ function toPlainText(value) {
114
+ if (typeof value === "string") return value;
115
+ if (Array.isArray(value)) {
116
+ return value.map((item) => {
117
+ if (typeof item === "string") return item;
118
+ if (typeof (item == null ? void 0 : item.text) === "string") return item.text;
119
+ if (typeof (item == null ? void 0 : item.content) === "string") return item.content;
120
+ return "";
121
+ }).filter(Boolean).join("\n");
122
+ }
123
+ if (value && typeof value === "object") {
124
+ const text = value.text || value.content;
125
+ if (typeof text === "string") return text;
126
+ }
127
+ return JSON.stringify(value);
128
+ }
129
+ function stripFence(text) {
130
+ return text.replace(/^```(?:json|markdown|md|html)?\s*/i, "").replace(/```\s*$/i, "").trim();
131
+ }
132
+ function slugify(text, fallback) {
133
+ const slug = text.toLowerCase().normalize("NFKD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
134
+ return slug || fallback;
135
+ }
136
+ function createFallbackPlan(guideTitle, targetChapterCount) {
137
+ const chapterTemplates = [
138
+ {
139
+ title: "Overview and scope",
140
+ goal: "Explain what the guide covers, who it is for, and the expected outcome."
141
+ },
142
+ {
143
+ title: "Prerequisites and preparation",
144
+ goal: "List required access, tools, input data, setup steps, and assumptions before starting."
145
+ },
146
+ {
147
+ title: "Initial setup",
148
+ goal: "Guide the user through the first required configuration or installation flow."
149
+ },
150
+ {
151
+ title: "Core workflow",
152
+ goal: "Describe the main task flow users need to complete successfully."
153
+ },
154
+ {
155
+ title: "Advanced usage and configuration",
156
+ goal: "Cover optional settings, variations, and deeper operational procedures."
157
+ },
158
+ {
159
+ title: "Verification and validation",
160
+ goal: "Show how to confirm that the setup or workflow is working correctly."
161
+ },
162
+ {
163
+ title: "Troubleshooting",
164
+ goal: "Document common problems, likely causes, and recovery steps."
165
+ },
166
+ {
167
+ title: "Reference and next steps",
168
+ goal: "Summarize related tasks, reference information, and recommended follow-up actions."
169
+ }
170
+ ];
171
+ return {
172
+ title: guideTitle,
173
+ chapters: Array.from({ length: targetChapterCount }, (_, index) => {
174
+ const template = chapterTemplates[index] || {
175
+ title: `Additional topic ${index + 1}`,
176
+ goal: "Expand an important topic from the source documents into a focused guide section."
177
+ };
178
+ return {
179
+ ...template,
180
+ sourceHints: []
181
+ };
182
+ })
183
+ };
184
+ }
185
+ function normalizePlan(rawText, guideTitle, targetChapterCount) {
186
+ const targetCount = clampChapterCount(targetChapterCount);
187
+ const cleanText = stripFence(rawText);
188
+ const jsonStart = cleanText.indexOf("{");
189
+ const jsonEnd = cleanText.lastIndexOf("}");
190
+ const jsonText = jsonStart >= 0 && jsonEnd > jsonStart ? cleanText.slice(jsonStart, jsonEnd + 1) : cleanText;
191
+ let parsed;
192
+ try {
193
+ parsed = JSON.parse(jsonText);
194
+ } catch {
195
+ return createFallbackPlan(guideTitle, targetCount);
196
+ }
197
+ const rawChapters = Array.isArray(parsed == null ? void 0 : parsed.chapters) ? parsed.chapters : [];
198
+ const planTitle = (parsed == null ? void 0 : parsed.title) ? String(parsed.title) : guideTitle;
199
+ const fallbackPlan = createFallbackPlan(planTitle, targetCount);
200
+ const chapters = fallbackPlan.chapters.map((fallback, index) => {
201
+ const item = rawChapters[index];
202
+ if (!item) return fallback;
203
+ const title = typeof item === "string" ? item : item == null ? void 0 : item.title;
204
+ const goal = typeof item === "object" ? item == null ? void 0 : item.goal : void 0;
205
+ const sourceHints = typeof item === "object" && Array.isArray(item == null ? void 0 : item.sourceHints) ? item.sourceHints : void 0;
206
+ return {
207
+ title: String(title || fallback.title),
208
+ goal: goal ? String(goal) : fallback.goal,
209
+ sourceHints: sourceHints ? sourceHints.map((hint) => String(hint)) : fallback.sourceHints
210
+ };
211
+ });
212
+ return {
213
+ title: planTitle,
214
+ chapters
215
+ };
216
+ }
217
+ async function getLLMProvider(app, llmService, model) {
218
+ const aiPlugin = app.pm.get("ai");
219
+ if (!aiPlugin) {
220
+ throw new Error("Plugin AI is not available");
221
+ }
222
+ const serviceData = await aiPlugin.aiManager.getLLMService({ llmService, model });
223
+ return serviceData.provider;
224
+ }
225
+ async function buildPlan(provider, space, documentsText) {
226
+ const { title, systemPrompt, targetChapterCount, chapterGuidance } = space.get();
227
+ const targetCount = clampChapterCount(targetChapterCount);
228
+ const messages = [];
229
+ if (systemPrompt) {
230
+ messages.push(new import_messages.SystemMessage(systemPrompt));
231
+ }
232
+ messages.push(
233
+ new import_messages.HumanMessage(`Create a concise breakdown plan for a multi-page user guide.
234
+
235
+ Return ONLY valid JSON with this shape:
236
+ {
237
+ "title": "Guide title",
238
+ "chapters": [
239
+ {
240
+ "title": "Chapter title",
241
+ "goal": "What this chapter should teach",
242
+ "sourceHints": ["Relevant topics, file names, or keywords"]
243
+ }
244
+ ]
245
+ }
246
+
247
+ Rules:
248
+ - Create exactly ${targetCount} chapter${targetCount === 1 ? "" : "s"}.
249
+ - If more than one chapter is requested, each chapter must cover a distinct user goal.
250
+ - Keep chapter titles user-facing and action-oriented.
251
+ - Do not include markdown fences or explanations.
252
+
253
+ Guide title: ${title || "User guide"}
254
+
255
+ Chapter guidance:
256
+ ${chapterGuidance || "Use the source document structure and split the guide into logical user-facing tasks."}
257
+
258
+ Source documents:
259
+ ${documentsText.slice(0, MAX_SOURCE_CHARS)}`)
260
+ );
261
+ const response = await provider.chatModel.invoke(messages);
262
+ return normalizePlan(toPlainText(response.content), title || "User guide", targetCount);
263
+ }
264
+ async function buildPageMarkdown(provider, space, plan, chapter, documentsText) {
265
+ const { title, systemPrompt } = space.get();
266
+ const messages = [];
267
+ if (systemPrompt) {
268
+ messages.push(new import_messages.SystemMessage(systemPrompt));
269
+ }
270
+ messages.push(
271
+ new import_messages.HumanMessage(`Write one chapter for a user guide in pure Markdown.
272
+
273
+ Output rules:
274
+ - Output ONLY Markdown content for this chapter.
275
+ - Start with a level-2 heading using the chapter title.
276
+ - Use clear steps, tables, and callouts when useful.
277
+ - Do not wrap the whole response in a code fence.
278
+ - Do not mention that this was generated by AI.
279
+
280
+ Guide title: ${plan.title || title || "User guide"}
281
+
282
+ Full chapter plan:
283
+ ${JSON.stringify(plan, null, 2)}
284
+
285
+ Chapter to write:
286
+ ${JSON.stringify(chapter, null, 2)}
287
+
288
+ Source documents:
289
+ ${documentsText.slice(0, MAX_SOURCE_CHARS)}`)
290
+ );
291
+ const response = await provider.chatModel.invoke(messages);
292
+ return stripFence(toPlainText(response.content));
293
+ }
294
+ async function markdownToCleanHtml(markdown) {
295
+ const renderedHtml = await import_marked.marked.parse(markdown, { async: true });
296
+ return (0, import_sanitize_html.default)(renderedHtml, SANITIZE_OPTIONS);
297
+ }
298
+ async function readDocuments(app, space) {
299
+ const documents = await space.getDocuments();
300
+ if (!documents || documents.length === 0) {
301
+ return "";
302
+ }
303
+ const texts = await Promise.all(
304
+ documents.map(async (doc) => {
305
+ const content = await fetchFileContent(app, doc);
306
+ return `--- Document: ${doc.filename || doc.id} ---
307
+ ${content}
308
+ `;
309
+ })
310
+ );
311
+ return texts.join("\n");
312
+ }
313
+ async function runBuild(app, db, filterByTk) {
314
+ const spaceRepo = db.getRepository("aiBuildGuideSpaces");
315
+ const pageRepo = db.getRepository("aiBuildGuidePages");
316
+ const space = await spaceRepo.findById(filterByTk);
317
+ if (!space) {
318
+ throw new Error("Space not found");
319
+ }
320
+ const { llmService, model } = space.get();
321
+ if (!llmService || !model) {
322
+ throw new Error("LLM Service or model is missing in space configuration");
323
+ }
324
+ await pageRepo.destroy({
325
+ filter: {
326
+ spaceId: filterByTk
327
+ }
328
+ });
329
+ await spaceRepo.update({
330
+ filterByTk,
331
+ values: {
332
+ buildPhase: "reading",
333
+ buildLog: "Reading source documents",
334
+ generatedHtml: null,
335
+ generatedMarkdown: null,
336
+ planJson: null,
337
+ pageCount: 0
338
+ }
339
+ });
340
+ const documentsText = await readDocuments(app, space);
341
+ const sourceHash = import_crypto.default.createHash("sha256").update(documentsText).digest("hex");
342
+ const provider = await getLLMProvider(app, llmService, model);
343
+ await spaceRepo.update({
344
+ filterByTk,
345
+ values: {
346
+ buildPhase: "planning",
347
+ buildLog: "Creating guide breakdown plan",
348
+ sourceHash
349
+ }
350
+ });
351
+ const plan = await buildPlan(provider, space, documentsText);
352
+ await spaceRepo.update({
353
+ filterByTk,
354
+ values: {
355
+ planJson: plan,
356
+ pageCount: plan.chapters.length,
357
+ buildPhase: "building_pages",
358
+ buildLog: `Plan created with ${plan.chapters.length} chapters`
359
+ }
360
+ });
361
+ const pageRecords = [];
362
+ for (const [index, chapter] of plan.chapters.entries()) {
363
+ const page = await pageRepo.create({
364
+ values: {
365
+ spaceId: filterByTk,
366
+ sort: index + 1,
367
+ title: chapter.title,
368
+ slug: slugify(chapter.title, `chapter-${index + 1}`),
369
+ goal: chapter.goal,
370
+ planItem: chapter,
371
+ status: "pending"
372
+ }
373
+ });
374
+ pageRecords.push(page);
375
+ }
376
+ for (const [index, page] of pageRecords.entries()) {
377
+ const chapter = plan.chapters[index];
378
+ const pageId = page.get("id");
379
+ await pageRepo.update({
380
+ filterByTk: pageId,
381
+ values: {
382
+ status: "building",
383
+ buildLog: "Building chapter with LLM"
384
+ }
385
+ });
386
+ await spaceRepo.update({
387
+ filterByTk,
388
+ values: {
389
+ buildPhase: "building_pages",
390
+ buildLog: `Building chapter ${index + 1}/${pageRecords.length}: ${chapter.title}`
391
+ }
392
+ });
393
+ try {
394
+ const markdown = await buildPageMarkdown(provider, space, plan, chapter, documentsText);
395
+ const html = await markdownToCleanHtml(markdown);
396
+ await pageRepo.update({
397
+ filterByTk: pageId,
398
+ values: {
399
+ status: "completed",
400
+ generatedMarkdown: markdown,
401
+ generatedHtml: html,
402
+ buildLog: null
403
+ }
404
+ });
405
+ } catch (error) {
406
+ await pageRepo.update({
407
+ filterByTk: pageId,
408
+ values: {
409
+ status: "error",
410
+ buildLog: error.message || String(error)
411
+ }
412
+ });
413
+ throw error;
414
+ }
415
+ }
416
+ const completedPages = await pageRepo.find({
417
+ filter: {
418
+ spaceId: filterByTk,
419
+ status: "completed"
420
+ },
421
+ sort: ["sort"]
422
+ });
423
+ const combinedMarkdown = completedPages.map((page) => page.get("generatedMarkdown")).filter(Boolean).join("\n\n---\n\n");
424
+ const combinedHtml = await markdownToCleanHtml(combinedMarkdown);
425
+ await spaceRepo.update({
426
+ filterByTk,
427
+ values: {
428
+ status: "completed",
429
+ buildPhase: "completed",
430
+ buildLog: `Built ${completedPages.length} chapters successfully`,
431
+ generatedMarkdown: combinedMarkdown,
432
+ generatedHtml: combinedHtml
433
+ }
434
+ });
435
+ }
114
436
  async function build(ctx, next) {
115
437
  const { filterByTk } = ctx.action.params;
116
438
  const repository = ctx.db.getRepository("aiBuildGuideSpaces");
@@ -128,75 +450,18 @@ async function build(ctx, next) {
128
450
  filterByTk,
129
451
  values: {
130
452
  status: "building",
131
- buildLog: null
453
+ buildPhase: "queued",
454
+ buildLog: "Build queued"
132
455
  }
133
456
  });
134
- const bgPromise = (async () => {
135
- const bgRepo = db.getRepository("aiBuildGuideSpaces");
136
- const documents = await space.getDocuments();
137
- let documentsText = "";
138
- if (documents && documents.length > 0) {
139
- const texts = await Promise.all(
140
- documents.map(async (doc) => {
141
- const content = await fetchFileContent(app, doc);
142
- return `--- Document: ${doc.filename} ---
143
- ${content}
144
- `;
145
- })
146
- );
147
- documentsText = texts.join("\n");
148
- }
149
- const aiPlugin = app.pm.get("ai");
150
- if (!aiPlugin) {
151
- throw new Error("Plugin AI is not available");
152
- }
153
- const { llmService, model, systemPrompt, outputFormat } = space.get();
154
- const format = outputFormat === "markdown" ? "markdown" : "html";
155
- if (!llmService || !model) {
156
- throw new Error("LLM Service or model is missing in space configuration");
157
- }
158
- const serviceData = await aiPlugin.aiManager.getLLMService({ llmService, model });
159
- const provider = serviceData.provider;
160
- const messages = [];
161
- if (systemPrompt) {
162
- messages.push(new import_messages.SystemMessage(systemPrompt));
163
- }
164
- const instruction = format === "markdown" ? `Please generate a comprehensive user guide in pure Markdown based on the following documents. Output ONLY Markdown content (no HTML wrappers, no code-fence around the whole document).
165
-
166
- Documents:
167
- ${documentsText}` : `Please generate an HTML user guide based on the following documents. Output ONLY valid HTML without Markdown blocks.
168
-
169
- Documents:
170
- ${documentsText}`;
171
- messages.push(new import_messages.HumanMessage(instruction));
172
- const response = await provider.chatModel.invoke(messages);
173
- const rawText = typeof response.content === "string" ? response.content : JSON.stringify(response.content);
174
- const updateValues = { status: "completed" };
175
- if (format === "markdown") {
176
- const rawMarkdown = rawText.replace(/^```(?:markdown|md)?\s*/, "").replace(/```\s*$/, "");
177
- const renderedHtml = await import_marked.marked.parse(rawMarkdown, { async: true });
178
- const cleanHtml = (0, import_sanitize_html.default)(renderedHtml, SANITIZE_OPTIONS);
179
- updateValues.generatedMarkdown = rawMarkdown;
180
- updateValues.generatedHtml = cleanHtml;
181
- } else {
182
- const rawHtml = rawText.replace(/^```html\s*/, "").replace(/```\s*$/, "");
183
- const cleanHtml = (0, import_sanitize_html.default)(rawHtml, SANITIZE_OPTIONS);
184
- updateValues.generatedHtml = cleanHtml;
185
- updateValues.generatedMarkdown = null;
186
- }
187
- await bgRepo.update({
188
- filterByTk,
189
- values: updateValues
190
- });
191
- })();
192
- bgPromise.catch(async (error) => {
457
+ runBuild(app, db, filterByTk).catch(async (error) => {
193
458
  app.log.error("Build Guide Background Error", error);
194
459
  try {
195
- const bgRepo = db.getRepository("aiBuildGuideSpaces");
196
- await bgRepo.update({
460
+ await repository.update({
197
461
  filterByTk,
198
462
  values: {
199
463
  status: "error",
464
+ buildPhase: "error",
200
465
  buildLog: error.message || String(error)
201
466
  }
202
467
  });
@@ -211,6 +476,7 @@ ${documentsText}`;
211
476
  filterByTk,
212
477
  values: {
213
478
  status: "error",
479
+ buildPhase: "error",
214
480
  buildLog: error.message || String(error)
215
481
  }
216
482
  });
@@ -1,12 +1,3 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
1
  var __defProp = Object.defineProperty;
11
2
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -1,12 +1,3 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
1
  var __defProp = Object.defineProperty;
11
2
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -0,0 +1,2 @@
1
+ declare const _default: import("@nocobase/database").CollectionOptions;
2
+ export default _default;
@@ -0,0 +1,81 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+ var ai_build_guide_pages_exports = {};
19
+ __export(ai_build_guide_pages_exports, {
20
+ default: () => ai_build_guide_pages_default
21
+ });
22
+ module.exports = __toCommonJS(ai_build_guide_pages_exports);
23
+ var import_database = require("@nocobase/database");
24
+ var ai_build_guide_pages_default = (0, import_database.defineCollection)({
25
+ name: "aiBuildGuidePages",
26
+ shared: true,
27
+ dumpRules: "required",
28
+ migrationRules: ["overwrite", "schema-only"],
29
+ timestamps: true,
30
+ fields: [
31
+ {
32
+ type: "uid",
33
+ name: "id",
34
+ primaryKey: true
35
+ },
36
+ {
37
+ type: "belongsTo",
38
+ name: "space",
39
+ target: "aiBuildGuideSpaces",
40
+ foreignKey: "spaceId"
41
+ },
42
+ {
43
+ type: "integer",
44
+ name: "sort",
45
+ defaultValue: 0
46
+ },
47
+ {
48
+ type: "string",
49
+ name: "title"
50
+ },
51
+ {
52
+ type: "string",
53
+ name: "slug"
54
+ },
55
+ {
56
+ type: "text",
57
+ name: "goal"
58
+ },
59
+ {
60
+ type: "json",
61
+ name: "planItem"
62
+ },
63
+ {
64
+ type: "string",
65
+ name: "status",
66
+ defaultValue: "pending"
67
+ },
68
+ {
69
+ type: "text",
70
+ name: "generatedHtml"
71
+ },
72
+ {
73
+ type: "text",
74
+ name: "generatedMarkdown"
75
+ },
76
+ {
77
+ type: "text",
78
+ name: "buildLog"
79
+ }
80
+ ]
81
+ });
@@ -1,12 +1,3 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
1
  var __defProp = Object.defineProperty;
11
2
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -63,6 +54,15 @@ var ai_build_guide_spaces_default = (0, import_database.defineCollection)({
63
54
  name: "outputFormat",
64
55
  defaultValue: "html"
65
56
  },
57
+ {
58
+ type: "integer",
59
+ name: "targetChapterCount",
60
+ defaultValue: 5
61
+ },
62
+ {
63
+ type: "text",
64
+ name: "chapterGuidance"
65
+ },
66
66
  {
67
67
  type: "text",
68
68
  name: "generatedHtml"
@@ -71,6 +71,24 @@ var ai_build_guide_spaces_default = (0, import_database.defineCollection)({
71
71
  type: "text",
72
72
  name: "generatedMarkdown"
73
73
  },
74
+ {
75
+ type: "json",
76
+ name: "planJson"
77
+ },
78
+ {
79
+ type: "string",
80
+ name: "buildPhase",
81
+ defaultValue: "idle"
82
+ },
83
+ {
84
+ type: "integer",
85
+ name: "pageCount",
86
+ defaultValue: 0
87
+ },
88
+ {
89
+ type: "string",
90
+ name: "sourceHash"
91
+ },
74
92
  {
75
93
  type: "string",
76
94
  name: "status",
@@ -84,6 +102,12 @@ var ai_build_guide_spaces_default = (0, import_database.defineCollection)({
84
102
  type: "belongsToMany",
85
103
  name: "documents",
86
104
  target: "attachments"
105
+ },
106
+ {
107
+ type: "hasMany",
108
+ name: "pages",
109
+ target: "aiBuildGuidePages",
110
+ foreignKey: "spaceId"
87
111
  }
88
112
  ]
89
113
  });
@@ -1,12 +1,3 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
1
  var __create = Object.create;
11
2
  var __defProp = Object.defineProperty;
12
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -1,8 +1,11 @@
1
1
  import { InstallOptions, Plugin } from '@nocobase/server';
2
2
  export declare class PluginBuildGuideBlockServer extends Plugin {
3
+ private readonly schemaCollections;
3
4
  afterAdd(): void;
4
5
  beforeLoad(): void;
5
6
  load(): Promise<void>;
7
+ private ensureCollectionSchema;
8
+ private ensureSchema;
6
9
  install(options?: InstallOptions): Promise<void>;
7
10
  upgrade(): Promise<void>;
8
11
  afterEnable(): Promise<void>;