@aigne/doc-smith 0.8.12 → 0.8.13-beta
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/CHANGELOG.md +9 -0
- package/README.md +73 -74
- package/agents/clear/choose-contents.mjs +21 -28
- package/agents/evaluate/index.yaml +1 -0
- package/agents/generate/check-need-generate-structure.mjs +10 -18
- package/agents/generate/user-review-document-structure.mjs +4 -4
- package/agents/init/check.mjs +14 -0
- package/agents/init/index.mjs +40 -46
- package/agents/publish/index.yaml +1 -0
- package/agents/publish/publish-docs.mjs +43 -30
- package/agents/translate/choose-language.mjs +13 -13
- package/agents/translate/index.yaml +1 -0
- package/agents/update/check-update-is-single.mjs +7 -4
- package/agents/update/index.yaml +1 -0
- package/agents/utils/choose-docs.mjs +4 -2
- package/agents/utils/update-branding.mjs +3 -2
- package/package.json +1 -1
- package/utils/auth-utils.mjs +25 -26
- package/utils/blocklet.mjs +31 -5
- package/utils/conflict-detector.mjs +6 -4
- package/utils/constants/index.mjs +1 -0
- package/utils/d2-utils.mjs +7 -8
- package/utils/deploy.mjs +9 -10
- package/utils/history-utils.mjs +21 -21
- package/utils/kroki-utils.mjs +7 -8
- package/utils/load-config.mjs +5 -5
- package/utils/upload-files.mjs +2 -2
package/agents/init/index.mjs
CHANGED
|
@@ -21,14 +21,13 @@ import {
|
|
|
21
21
|
validatePath,
|
|
22
22
|
} from "../../utils/utils.mjs";
|
|
23
23
|
|
|
24
|
-
// UI constants
|
|
25
24
|
const _PRESS_ENTER_TO_FINISH = "Press Enter to finish";
|
|
26
25
|
|
|
27
26
|
/**
|
|
28
|
-
*
|
|
27
|
+
* Guides the user through a multi-turn dialog to generate a YAML configuration file.
|
|
29
28
|
* @param {Object} params
|
|
30
|
-
* @param {string} params.outputPath -
|
|
31
|
-
* @param {string} params.fileName -
|
|
29
|
+
* @param {string} params.outputPath - The path to the output file.
|
|
30
|
+
* @param {string} params.fileName - The name of the file.
|
|
32
31
|
* @returns {Promise<Object>}
|
|
33
32
|
*/
|
|
34
33
|
export default async function init(
|
|
@@ -47,7 +46,7 @@ export default async function init(
|
|
|
47
46
|
const configContent = await readFile(filePath, "utf8").catch(() => null);
|
|
48
47
|
|
|
49
48
|
if (!configContent || configContent.trim() === "") {
|
|
50
|
-
console.log(
|
|
49
|
+
console.log("⚠️ No configuration file found.");
|
|
51
50
|
console.log(
|
|
52
51
|
`🚀 Run ${chalk.cyan("aigne doc init")} to set up your documentation configuration.`,
|
|
53
52
|
);
|
|
@@ -71,14 +70,12 @@ export default async function init(
|
|
|
71
70
|
console.log("🚀 Welcome to AIGNE DocSmith!");
|
|
72
71
|
console.log("Let's set up your documentation preferences.\n");
|
|
73
72
|
|
|
74
|
-
// Collect user information
|
|
75
73
|
const input = {};
|
|
76
74
|
|
|
77
|
-
// 1. Primary purpose - what's the main outcome you want readers to achieve?
|
|
78
75
|
const purposeChoices = await options.prompts.checkbox({
|
|
79
76
|
message: "📝 [1/9]: What should your documentation help readers achieve?",
|
|
80
77
|
choices: Object.entries(DOCUMENT_STYLES)
|
|
81
|
-
.filter(([key]) => key !== "custom")
|
|
78
|
+
.filter(([key]) => key !== "custom")
|
|
82
79
|
.map(([key, style]) => ({
|
|
83
80
|
name: `${style.name}`,
|
|
84
81
|
description: style.description,
|
|
@@ -86,19 +83,18 @@ export default async function init(
|
|
|
86
83
|
})),
|
|
87
84
|
validate: (input) => {
|
|
88
85
|
if (input.length === 0) {
|
|
89
|
-
return "
|
|
86
|
+
return "You must choose at least one goal for your documentation.";
|
|
90
87
|
}
|
|
91
88
|
return true;
|
|
92
89
|
},
|
|
93
90
|
});
|
|
94
91
|
|
|
95
|
-
// Follow-up logic: If ONLY mixedPurpose selected, ask for priority ranking
|
|
96
92
|
let prioritizedPurposes = purposeChoices;
|
|
97
93
|
if (purposeChoices.length === 1 && purposeChoices.includes("mixedPurpose")) {
|
|
98
94
|
const topPriorities = await options.prompts.checkbox({
|
|
99
|
-
message: "🎯 Which is most important? (Select
|
|
95
|
+
message: "🎯 Which is most important? (Select up to 2 priorities)",
|
|
100
96
|
choices: Object.entries(DOCUMENT_STYLES)
|
|
101
|
-
.filter(([key]) => key !== "custom" && key !== "mixedPurpose")
|
|
97
|
+
.filter(([key]) => key !== "custom" && key !== "mixedPurpose")
|
|
102
98
|
.map(([key, style]) => ({
|
|
103
99
|
name: `${style.name}`,
|
|
104
100
|
description: style.description,
|
|
@@ -106,27 +102,24 @@ export default async function init(
|
|
|
106
102
|
})),
|
|
107
103
|
validate: (input) => {
|
|
108
104
|
if (input.length === 0) {
|
|
109
|
-
return "
|
|
105
|
+
return "You must choose at least one priority.";
|
|
110
106
|
}
|
|
111
107
|
if (input.length > 2) {
|
|
112
|
-
return "
|
|
108
|
+
return "You may only choose up to 2 priorities.";
|
|
113
109
|
}
|
|
114
110
|
return true;
|
|
115
111
|
},
|
|
116
112
|
});
|
|
117
113
|
|
|
118
|
-
// Replace mixedPurpose with selected priorities
|
|
119
114
|
prioritizedPurposes = topPriorities;
|
|
120
115
|
}
|
|
121
116
|
|
|
122
|
-
// Save document purpose choices as keys
|
|
123
117
|
input.documentPurpose = prioritizedPurposes;
|
|
124
118
|
|
|
125
|
-
// 2. Target audience - who will be reading this most often?
|
|
126
119
|
const audienceChoices = await options.prompts.checkbox({
|
|
127
120
|
message: "👥 [2/9]: Who will be reading your documentation?",
|
|
128
121
|
choices: Object.entries(TARGET_AUDIENCES)
|
|
129
|
-
.filter(([key]) => key !== "custom")
|
|
122
|
+
.filter(([key]) => key !== "custom")
|
|
130
123
|
.map(([key, audience]) => ({
|
|
131
124
|
name: `${audience.name}`,
|
|
132
125
|
description: audience.description,
|
|
@@ -134,23 +127,19 @@ export default async function init(
|
|
|
134
127
|
})),
|
|
135
128
|
validate: (input) => {
|
|
136
129
|
if (input.length === 0) {
|
|
137
|
-
return "
|
|
130
|
+
return "You must choose at least one audience.";
|
|
138
131
|
}
|
|
139
132
|
return true;
|
|
140
133
|
},
|
|
141
134
|
});
|
|
142
135
|
|
|
143
|
-
// Save target audience choices as keys
|
|
144
136
|
input.targetAudienceTypes = audienceChoices;
|
|
145
137
|
|
|
146
|
-
// 3. Reader knowledge level - what do readers typically know when they arrive?
|
|
147
|
-
// Determine default based on selected purposes using mapping
|
|
148
138
|
const mappedPurpose = prioritizedPurposes.find(
|
|
149
139
|
(purpose) => PURPOSE_TO_KNOWLEDGE_MAPPING[purpose],
|
|
150
140
|
);
|
|
151
141
|
const defaultKnowledge = mappedPurpose ? PURPOSE_TO_KNOWLEDGE_MAPPING[mappedPurpose] : null;
|
|
152
142
|
|
|
153
|
-
// Filter knowledge level options based on previous selections
|
|
154
143
|
const { filteredOptions: filteredKnowledgeOptions } = getFilteredOptions(
|
|
155
144
|
"readerKnowledgeLevel",
|
|
156
145
|
{ documentPurpose: prioritizedPurposes, targetAudienceTypes: audienceChoices },
|
|
@@ -158,7 +147,7 @@ export default async function init(
|
|
|
158
147
|
);
|
|
159
148
|
|
|
160
149
|
const knowledgeChoice = await options.prompts.select({
|
|
161
|
-
message: "🧠 [3/9]: How much do readers already know about your project?",
|
|
150
|
+
message: "🧠 [3/9]: How much do your readers already know about your project?",
|
|
162
151
|
choices: Object.entries(filteredKnowledgeOptions).map(([key, level]) => ({
|
|
163
152
|
name: `${level.name}`,
|
|
164
153
|
description: level.description,
|
|
@@ -221,7 +210,7 @@ export default async function init(
|
|
|
221
210
|
|
|
222
211
|
// Let user select primary language from supported list
|
|
223
212
|
const primaryLanguageChoice = await options.prompts.select({
|
|
224
|
-
message: "🌐 [5/9]: What
|
|
213
|
+
message: "🌐 [5/9]: What is the main language of your documentation?",
|
|
225
214
|
choices: SUPPORTED_LANGUAGES.map((lang) => ({
|
|
226
215
|
name: `${lang.label} - ${lang.sample}`,
|
|
227
216
|
value: lang.code,
|
|
@@ -238,7 +227,7 @@ export default async function init(
|
|
|
238
227
|
);
|
|
239
228
|
|
|
240
229
|
const translateLanguageChoices = await options.prompts.checkbox({
|
|
241
|
-
message: "🔄 [6/9]:
|
|
230
|
+
message: "🔄 [6/9]: What languages should we translate to?",
|
|
242
231
|
choices: availableTranslationLanguages.map((lang) => ({
|
|
243
232
|
name: `${lang.label} - ${lang.sample}`,
|
|
244
233
|
value: lang.code,
|
|
@@ -257,15 +246,17 @@ export default async function init(
|
|
|
257
246
|
// 8. Content sources
|
|
258
247
|
console.log("\n🔍 [8/9]: Content Sources");
|
|
259
248
|
console.log(
|
|
260
|
-
"
|
|
249
|
+
"Please specify the folders and files we should analyze to generate your documentation (e.g., ./src, ./docs, ./README.md).",
|
|
261
250
|
);
|
|
262
|
-
console.log(
|
|
263
|
-
|
|
251
|
+
console.log(
|
|
252
|
+
"💡 You can also use glob patterns like src/**/*.js or docs/**/*.md for more specific file matching.",
|
|
253
|
+
);
|
|
254
|
+
console.log("💡 If you leave this empty, we will scan the entire directory.");
|
|
264
255
|
|
|
265
256
|
const sourcePaths = [];
|
|
266
257
|
while (true) {
|
|
267
258
|
const selectedPath = await options.prompts.search({
|
|
268
|
-
message: "
|
|
259
|
+
message: "Please enter a file or folder path, or a glob pattern:",
|
|
269
260
|
source: async (input) => {
|
|
270
261
|
if (!input || input.trim() === "") {
|
|
271
262
|
return [
|
|
@@ -292,7 +283,7 @@ export default async function init(
|
|
|
292
283
|
options.push({
|
|
293
284
|
name: searchTerm,
|
|
294
285
|
value: searchTerm,
|
|
295
|
-
description: "
|
|
286
|
+
description: "Use this glob pattern for file matching.",
|
|
296
287
|
});
|
|
297
288
|
}
|
|
298
289
|
|
|
@@ -342,7 +333,7 @@ export default async function init(
|
|
|
342
333
|
// 9. Custom rules - any specific requirements for the documentation?
|
|
343
334
|
const rulesInput = await options.prompts.input({
|
|
344
335
|
message:
|
|
345
|
-
"📋 [9/9]:
|
|
336
|
+
"📋 [9/9]: Do you have any custom rules or requirements for your documentation? (Optional, press Enter to skip)",
|
|
346
337
|
default: "",
|
|
347
338
|
});
|
|
348
339
|
input.rules = rulesInput.trim();
|
|
@@ -365,22 +356,24 @@ export default async function init(
|
|
|
365
356
|
await mkdir(dirPath, { recursive: true });
|
|
366
357
|
|
|
367
358
|
await writeFile(filePath, yamlContent, "utf8");
|
|
368
|
-
console.log(
|
|
369
|
-
|
|
359
|
+
console.log(
|
|
360
|
+
`\n✅ Setup complete! Your configuration has been saved to: ${chalk.cyan(filePath)}`,
|
|
361
|
+
);
|
|
370
362
|
console.log(chalk.cyan("---"));
|
|
371
363
|
console.log(chalk.cyan(yamlContent));
|
|
372
364
|
console.log(chalk.cyan("---"));
|
|
373
|
-
console.log("💡 You can edit
|
|
374
|
-
console.log(`🚀
|
|
365
|
+
console.log("💡 You can edit this file at any time to change your settings.\n");
|
|
366
|
+
console.log(`🚀 To generate your documentation, run: ${chalk.cyan("aigne doc generate")}\n`);
|
|
375
367
|
|
|
376
|
-
// load config from file
|
|
377
368
|
if (skipIfExists) {
|
|
378
369
|
return loadConfig({ config: filePath, appUrl });
|
|
379
370
|
}
|
|
380
371
|
|
|
381
372
|
return {};
|
|
382
373
|
} catch (error) {
|
|
383
|
-
console.error(
|
|
374
|
+
console.error(
|
|
375
|
+
`❌ Sorry, I encountered an error while saving your configuration file: ${error.message}`,
|
|
376
|
+
);
|
|
384
377
|
return {
|
|
385
378
|
inputGeneratorStatus: false,
|
|
386
379
|
inputGeneratorError: error.message,
|
|
@@ -502,14 +495,15 @@ export function generateYAML(input) {
|
|
|
502
495
|
yaml += `${rulesSection.replace(/rules: ''/, "rules: |\n ")}\n\n`;
|
|
503
496
|
|
|
504
497
|
// Target Audience Description
|
|
505
|
-
yaml += "# Target Audience: Describe your specific target audience and their characteristics
|
|
498
|
+
yaml += "# Target Audience: Describe your specific target audience and their characteristics.\n";
|
|
506
499
|
const targetAudienceSection = yamlStringify({ targetAudience: config.targetAudience }).trim();
|
|
507
500
|
// Use literal style for multiline strings
|
|
508
501
|
yaml += `${targetAudienceSection.replace(/targetAudience: ''/, "targetAudience: |\n ")}\n\n`;
|
|
509
502
|
|
|
510
503
|
// Glossary Configuration
|
|
511
|
-
yaml += "# Glossary: Define project-specific terms and definitions
|
|
512
|
-
yaml +=
|
|
504
|
+
yaml += "# Glossary: Define project-specific terms and definitions.\n";
|
|
505
|
+
yaml +=
|
|
506
|
+
'# glossary: "@glossary.md" # Path to a markdown file containing glossary definitions.\n\n';
|
|
513
507
|
|
|
514
508
|
// Language settings - safely serialize
|
|
515
509
|
const localeSection = yamlStringify({ locale: config.locale }).trim();
|
|
@@ -522,25 +516,25 @@ export function generateYAML(input) {
|
|
|
522
516
|
}).trim();
|
|
523
517
|
yaml += `${translateLanguagesSection.replace(/^translateLanguages:/, "translateLanguages:")}\n`;
|
|
524
518
|
} else {
|
|
525
|
-
yaml += "# translateLanguages: #
|
|
519
|
+
yaml += "# translateLanguages: # A list of languages to translate the documentation to.\n";
|
|
526
520
|
yaml += "# - zh # Example: Chinese translation\n";
|
|
527
521
|
yaml += "# - en # Example: English translation\n";
|
|
528
522
|
}
|
|
529
523
|
|
|
530
524
|
// Directory and source path configurations - safely serialize
|
|
531
525
|
const docsDirSection = yamlStringify({ docsDir: config.docsDir }).trim();
|
|
532
|
-
yaml += `${docsDirSection.replace(/^docsDir:/, "docsDir:")} #
|
|
526
|
+
yaml += `${docsDirSection.replace(/^docsDir:/, "docsDir:")} # The directory where the generated documentation will be saved.\n`;
|
|
533
527
|
|
|
534
528
|
const sourcesPathSection = yamlStringify({ sourcesPath: config.sourcesPath }).trim();
|
|
535
|
-
yaml += `${sourcesPathSection.replace(/^sourcesPath:/, "sourcesPath: #
|
|
529
|
+
yaml += `${sourcesPathSection.replace(/^sourcesPath:/, "sourcesPath: # The source code paths to analyze.")}\n`;
|
|
536
530
|
|
|
537
531
|
// Image filtering settings
|
|
538
532
|
const mediaInfoSection = yamlStringify({
|
|
539
533
|
media: config.media,
|
|
540
534
|
}).trim();
|
|
541
|
-
yaml += `# minImageWidth: Only images wider than this value (in pixels) will be used in page generation
|
|
535
|
+
yaml += `# minImageWidth: Only images wider than this value (in pixels) will be used in the page generation.\n${mediaInfoSection}\n`;
|
|
542
536
|
|
|
543
537
|
return yaml;
|
|
544
538
|
}
|
|
545
539
|
|
|
546
|
-
init.description = "
|
|
540
|
+
init.description = "Create a configuration file for the documentation generation process.";
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import { basename, extname, join
|
|
2
|
-
import slugify from "slugify";
|
|
1
|
+
import { basename, extname, join } from "node:path";
|
|
3
2
|
import { publishDocs as publishDocsFn } from "@aigne/publish-docs";
|
|
4
3
|
import { BrokerClient } from "@blocklet/payment-broker-client/node";
|
|
5
4
|
import chalk from "chalk";
|
|
6
5
|
import fs from "fs-extra";
|
|
6
|
+
import slugify from "slugify";
|
|
7
7
|
|
|
8
|
-
import { getExtnameFromContentType } from "../../utils/file-utils.mjs";
|
|
9
|
-
import { isHttp } from "../../utils/utils.mjs";
|
|
10
8
|
import { getAccessToken, getOfficialAccessToken } from "../../utils/auth-utils.mjs";
|
|
11
9
|
import {
|
|
12
10
|
CLOUD_SERVICE_URL_PROD,
|
|
@@ -17,7 +15,14 @@ import {
|
|
|
17
15
|
} from "../../utils/constants/index.mjs";
|
|
18
16
|
import { beforePublishHook, ensureTmpDir } from "../../utils/d2-utils.mjs";
|
|
19
17
|
import { deploy } from "../../utils/deploy.mjs";
|
|
20
|
-
import {
|
|
18
|
+
import { getExtnameFromContentType } from "../../utils/file-utils.mjs";
|
|
19
|
+
import { uploadFiles } from "../../utils/upload-files.mjs";
|
|
20
|
+
import {
|
|
21
|
+
getGithubRepoUrl,
|
|
22
|
+
isHttp,
|
|
23
|
+
loadConfigFromFile,
|
|
24
|
+
saveValueToConfig,
|
|
25
|
+
} from "../../utils/utils.mjs";
|
|
21
26
|
import updateBranding from "../utils/update-branding.mjs";
|
|
22
27
|
|
|
23
28
|
const BASE_URL = process.env.DOC_SMITH_BASE_URL || CLOUD_SERVICE_URL_PROD;
|
|
@@ -86,16 +91,8 @@ export default async function publishDocs(
|
|
|
86
91
|
}
|
|
87
92
|
|
|
88
93
|
const choice = await options.prompts.select({
|
|
89
|
-
message: "
|
|
94
|
+
message: "Please select a platform to publish your documents:",
|
|
90
95
|
choices: [
|
|
91
|
-
{
|
|
92
|
-
name: `${chalk.blue("DocSmith Cloud (docsmith.aigne.io)")} – ${chalk.green("Free")} hosting. Your documents will be publicly accessible. Best for open-source projects or community sharing.`,
|
|
93
|
-
value: "default",
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
name: `${chalk.blue("Your existing website")} - Integrate and publish directly on your current site (setup required)`,
|
|
97
|
-
value: "custom",
|
|
98
|
-
},
|
|
99
96
|
...(sessionId
|
|
100
97
|
? [
|
|
101
98
|
{
|
|
@@ -104,6 +101,14 @@ export default async function publishDocs(
|
|
|
104
101
|
},
|
|
105
102
|
]
|
|
106
103
|
: []),
|
|
104
|
+
{
|
|
105
|
+
name: `${chalk.blue("DocSmith Cloud (docsmith.aigne.io)")} – ${chalk.green("Free")} hosting. Your documents will be publicly accessible. Best for open-source projects or community sharing.`,
|
|
106
|
+
value: "default",
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: `${chalk.blue("Your existing website")} - Integrate and publish directly on your current site (setup required)`,
|
|
110
|
+
value: "custom",
|
|
111
|
+
},
|
|
107
112
|
{
|
|
108
113
|
name: `${chalk.blue("New website")} - ${chalk.yellow("Paid service.")} We'll help you set up a brand-new website with custom domain and hosting. Great if you want a professional presence.`,
|
|
109
114
|
value: "new-instance",
|
|
@@ -117,7 +122,7 @@ export default async function publishDocs(
|
|
|
117
122
|
`Start here to run your own website:\n${chalk.cyan(DISCUSS_KIT_STORE_URL)}\n`,
|
|
118
123
|
);
|
|
119
124
|
const userInput = await options.prompts.input({
|
|
120
|
-
message: "Please enter your website
|
|
125
|
+
message: "Please enter the URL of your website:",
|
|
121
126
|
validate: (input) => {
|
|
122
127
|
try {
|
|
123
128
|
// Check if input contains protocol, if not, prepend https://
|
|
@@ -146,7 +151,7 @@ export default async function publishDocs(
|
|
|
146
151
|
paymentUrl = paymentLink;
|
|
147
152
|
console.log(`\nResuming your previous website setup...`);
|
|
148
153
|
} else {
|
|
149
|
-
console.log(`\nCreating new website for your documentation...`);
|
|
154
|
+
console.log(`\nCreating a new website for your documentation...`);
|
|
150
155
|
}
|
|
151
156
|
const { appUrl: homeUrl, token: ltToken } = (await deploy(id, paymentUrl)) || {};
|
|
152
157
|
|
|
@@ -155,7 +160,7 @@ export default async function publishDocs(
|
|
|
155
160
|
}
|
|
156
161
|
}
|
|
157
162
|
|
|
158
|
-
console.log(`\nPublishing
|
|
163
|
+
console.log(`\nPublishing your documentation to ${chalk.cyan(appUrl)}\n`);
|
|
159
164
|
|
|
160
165
|
const accessToken = await getAccessToken(appUrl, token);
|
|
161
166
|
|
|
@@ -192,8 +197,16 @@ export default async function publishDocs(
|
|
|
192
197
|
const finalPath = ext ? `${tempFilePath}.${ext}` : tempFilePath;
|
|
193
198
|
fs.writeFileSync(finalPath, buffer);
|
|
194
199
|
|
|
195
|
-
|
|
196
|
-
|
|
200
|
+
const filePath = join(process.cwd(), finalPath);
|
|
201
|
+
const { results: uploadResults } = await uploadFiles({
|
|
202
|
+
appUrl,
|
|
203
|
+
filePaths: [filePath],
|
|
204
|
+
accessToken,
|
|
205
|
+
concurrency: 1,
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// FIXME: 暂时保持使用绝对路径,需要修改为相对路径 @pengfei
|
|
209
|
+
projectInfo.icon = uploadResults?.[0]?.url || projectInfo.icon;
|
|
197
210
|
}
|
|
198
211
|
} catch (error) {
|
|
199
212
|
console.warn(`Failed to download project logo from ${projectInfo.icon}: ${error.message}`);
|
|
@@ -253,21 +266,21 @@ export default async function publishDocs(
|
|
|
253
266
|
} else {
|
|
254
267
|
// If the error is 401 or 403, it means the access token is invalid
|
|
255
268
|
if (error?.includes("401") || error?.includes("403")) {
|
|
256
|
-
message = `❌ Publishing failed
|
|
269
|
+
message = `❌ Publishing failed due to an authorization error. Please run ${chalk.cyan("aigne doc clear")} to reset your credentials and try again.`;
|
|
257
270
|
}
|
|
258
271
|
}
|
|
259
272
|
|
|
260
273
|
// clean up tmp work dir
|
|
261
274
|
await fs.rm(docsDir, { recursive: true, force: true });
|
|
262
275
|
} catch (error) {
|
|
263
|
-
message = `❌
|
|
276
|
+
message = `❌ Sorry, I encountered an error while publishing your documentation: ${error.message}`;
|
|
264
277
|
|
|
265
278
|
// clean up tmp work dir in case of error
|
|
266
279
|
try {
|
|
267
280
|
const docsDir = join(DOC_SMITH_DIR, TMP_DIR, TMP_DOCS_DIR);
|
|
268
281
|
await fs.rm(docsDir, { recursive: true, force: true });
|
|
269
282
|
} catch {
|
|
270
|
-
//
|
|
283
|
+
// Ignore cleanup errors
|
|
271
284
|
}
|
|
272
285
|
}
|
|
273
286
|
|
|
@@ -279,34 +292,34 @@ publishDocs.input_schema = {
|
|
|
279
292
|
properties: {
|
|
280
293
|
docsDir: {
|
|
281
294
|
type: "string",
|
|
282
|
-
description: "The directory of the
|
|
295
|
+
description: "The directory of the documentation.",
|
|
283
296
|
},
|
|
284
297
|
appUrl: {
|
|
285
298
|
type: "string",
|
|
286
|
-
description: "The
|
|
299
|
+
description: "The URL of the app.",
|
|
287
300
|
default: CLOUD_SERVICE_URL_PROD,
|
|
288
301
|
},
|
|
289
302
|
boardId: {
|
|
290
303
|
type: "string",
|
|
291
|
-
description: "The
|
|
304
|
+
description: "The ID of the board.",
|
|
292
305
|
},
|
|
293
306
|
"with-branding": {
|
|
294
307
|
type: "boolean",
|
|
295
|
-
description: "Update
|
|
308
|
+
description: "Update the website branding (title, description, and logo).",
|
|
296
309
|
},
|
|
297
310
|
projectName: {
|
|
298
311
|
type: "string",
|
|
299
|
-
description: "The name of the project",
|
|
312
|
+
description: "The name of the project.",
|
|
300
313
|
},
|
|
301
314
|
projectDesc: {
|
|
302
315
|
type: "string",
|
|
303
|
-
description: "
|
|
316
|
+
description: "A description of the project.",
|
|
304
317
|
},
|
|
305
318
|
projectLogo: {
|
|
306
319
|
type: "string",
|
|
307
|
-
description: "The logo
|
|
320
|
+
description: "The logo or icon of the project.",
|
|
308
321
|
},
|
|
309
322
|
},
|
|
310
323
|
};
|
|
311
324
|
|
|
312
|
-
publishDocs.description = "Publish the documentation to website";
|
|
325
|
+
publishDocs.description = "Publish the documentation to a website";
|
|
@@ -2,12 +2,12 @@ import { SUPPORTED_LANGUAGES } from "../../utils/constants/index.mjs";
|
|
|
2
2
|
import { loadConfigFromFile, saveValueToConfig } from "../../utils/utils.mjs";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* Interactively selects languages for translation.
|
|
6
6
|
* @param {Object} params
|
|
7
|
-
* @param {Array<string>} [params.langs] - Pre-selected languages
|
|
8
|
-
* @param {string} params.locale -
|
|
9
|
-
* @param {Object} options - Options object with prompts
|
|
10
|
-
* @returns {Promise<Object>}
|
|
7
|
+
* @param {Array<string>} [params.langs] - Pre-selected languages.
|
|
8
|
+
* @param {string} params.locale - The primary language code.
|
|
9
|
+
* @param {Object} options - Options object with prompts.
|
|
10
|
+
* @returns {Promise<Object>} The selected languages.
|
|
11
11
|
*/
|
|
12
12
|
export default async function chooseLanguage({ langs, locale, selectedDocs }, options) {
|
|
13
13
|
let selectedLanguages = [];
|
|
@@ -24,7 +24,7 @@ export default async function chooseLanguage({ langs, locale, selectedDocs }, op
|
|
|
24
24
|
(lang) => lang.code !== primaryLanguage,
|
|
25
25
|
);
|
|
26
26
|
|
|
27
|
-
// If languages are provided as parameter, validate
|
|
27
|
+
// If languages are provided as a parameter, validate them
|
|
28
28
|
if (langs && Array.isArray(langs) && langs.length > 0) {
|
|
29
29
|
const validLanguages = langs.filter((lang) =>
|
|
30
30
|
availableTranslationLanguages.some((availableLang) => availableLang.code === lang),
|
|
@@ -35,8 +35,7 @@ export default async function chooseLanguage({ langs, locale, selectedDocs }, op
|
|
|
35
35
|
} else {
|
|
36
36
|
console.log(`⚠️ Invalid languages provided: ${langs.join(", ")}`);
|
|
37
37
|
console.log(
|
|
38
|
-
|
|
39
|
-
availableTranslationLanguages.map((l) => l.code).join(", "),
|
|
38
|
+
`Available languages: ${availableTranslationLanguages.map((l) => l.code).join(", ")}`,
|
|
40
39
|
);
|
|
41
40
|
}
|
|
42
41
|
}
|
|
@@ -51,11 +50,11 @@ export default async function chooseLanguage({ langs, locale, selectedDocs }, op
|
|
|
51
50
|
}));
|
|
52
51
|
|
|
53
52
|
selectedLanguages = await options.prompts.checkbox({
|
|
54
|
-
message: "
|
|
53
|
+
message: "Please select the languages you'd like to translate to:",
|
|
55
54
|
choices: choices,
|
|
56
55
|
validate: (answer) => {
|
|
57
56
|
if (answer.length === 0) {
|
|
58
|
-
return "
|
|
57
|
+
return "You must select at least one language.";
|
|
59
58
|
}
|
|
60
59
|
return true;
|
|
61
60
|
},
|
|
@@ -63,7 +62,7 @@ export default async function chooseLanguage({ langs, locale, selectedDocs }, op
|
|
|
63
62
|
}
|
|
64
63
|
|
|
65
64
|
if (selectedLanguages.length === 0) {
|
|
66
|
-
throw new Error("
|
|
65
|
+
throw new Error("You must select at least one language to continue.");
|
|
67
66
|
}
|
|
68
67
|
|
|
69
68
|
// Find new languages that need to be added
|
|
@@ -98,12 +97,13 @@ chooseLanguage.input_schema = {
|
|
|
98
97
|
items: {
|
|
99
98
|
type: "string",
|
|
100
99
|
},
|
|
101
|
-
description: "
|
|
100
|
+
description: "A list of pre-selected languages for translation.",
|
|
102
101
|
},
|
|
103
102
|
|
|
104
103
|
locale: {
|
|
105
104
|
type: "string",
|
|
106
|
-
description:
|
|
105
|
+
description:
|
|
106
|
+
"The primary language code, which will be excluded from the translation options.",
|
|
107
107
|
},
|
|
108
108
|
},
|
|
109
109
|
required: [],
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export default async function checkUpdateIsSingle({ selectedDocs, ...rest }, options) {
|
|
2
2
|
if (!selectedDocs || !Array.isArray(selectedDocs)) {
|
|
3
|
-
throw new Error("
|
|
3
|
+
throw new Error("A list of documents to update must be provided.");
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
if (selectedDocs.length === 0) {
|
|
7
|
-
throw new Error("
|
|
7
|
+
throw new Error("You must select at least one document to update.");
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
let targetAgent;
|
|
@@ -20,7 +20,7 @@ export default async function checkUpdateIsSingle({ selectedDocs, ...rest }, opt
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
if (!targetAgent) {
|
|
23
|
-
throw new Error(`
|
|
23
|
+
throw new Error(`Sorry, I can't seem to find the "${agentName}" agent.`);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
try {
|
|
@@ -31,7 +31,10 @@ export default async function checkUpdateIsSingle({ selectedDocs, ...rest }, opt
|
|
|
31
31
|
|
|
32
32
|
return result;
|
|
33
33
|
} catch (error) {
|
|
34
|
-
console.error(
|
|
34
|
+
console.error(
|
|
35
|
+
`Sorry, I encountered an error while trying to run the ${agentName} agent:`,
|
|
36
|
+
error.message,
|
|
37
|
+
);
|
|
35
38
|
throw error;
|
|
36
39
|
}
|
|
37
40
|
}
|
package/agents/update/index.yaml
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
1
2
|
import {
|
|
2
3
|
addFeedbackToItems,
|
|
3
4
|
findItemByPath,
|
|
@@ -35,7 +36,7 @@ export default async function chooseDocs(
|
|
|
35
36
|
|
|
36
37
|
if (mainLanguageFiles.length === 0) {
|
|
37
38
|
throw new Error(
|
|
38
|
-
|
|
39
|
+
`No documents found in the docs directory. Please run ${chalk.yellow("`aigne doc generate`")} to generate the documents`,
|
|
39
40
|
);
|
|
40
41
|
}
|
|
41
42
|
|
|
@@ -80,9 +81,10 @@ export default async function chooseDocs(
|
|
|
80
81
|
// Process selected files and convert to found items
|
|
81
82
|
foundItems = await processSelectedFiles(selectedFiles, documentExecutionStructure, docsDir);
|
|
82
83
|
} catch (error) {
|
|
83
|
-
|
|
84
|
+
console.log(
|
|
84
85
|
getActionText(isTranslate, `\nFailed to select documents to {action}: ${error.message}`),
|
|
85
86
|
);
|
|
87
|
+
process.exit(0);
|
|
86
88
|
}
|
|
87
89
|
} else {
|
|
88
90
|
// Process the provided docs array
|
|
@@ -17,12 +17,13 @@ export default async function updateBranding({ appUrl, projectInfo, accessToken
|
|
|
17
17
|
try {
|
|
18
18
|
const origin = new URL(appUrl).origin;
|
|
19
19
|
if ([CLOUD_SERVICE_URL_PROD, CLOUD_SERVICE_URL_STAGING].includes(origin)) {
|
|
20
|
-
console.log("Skipped updating branding for official service\n");
|
|
20
|
+
console.log("ℹ️ Skipped updating branding for official service\n");
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
console.log(`🔄 Updating branding for ${chalk.cyan(origin)}`);
|
|
25
25
|
|
|
26
|
+
// Get component information and mount point
|
|
26
27
|
const componentInfo = await getComponentInfoWithMountPoint(origin, DISCUSS_KIT_DID);
|
|
27
28
|
const mountPoint = componentInfo.mountPoint || "/";
|
|
28
29
|
|
|
@@ -56,7 +57,7 @@ export default async function updateBranding({ appUrl, projectInfo, accessToken
|
|
|
56
57
|
endpoint: `${origin}/.well-known/service/blocklet/logo/upload/square/${componentInfo.did}`,
|
|
57
58
|
});
|
|
58
59
|
}
|
|
59
|
-
console.log("✅
|
|
60
|
+
console.log("✅ Branding has been successfully updated\n");
|
|
60
61
|
} catch (error) {
|
|
61
62
|
console.warn(`⚠️ Just failed to update logo: ${error.message}\n`);
|
|
62
63
|
}
|