plugin-build-guide-block 1.0.11 → 1.1.2

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