@aigne/doc-smith 0.4.5 → 0.6.0
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 +26 -0
- package/agents/batch-translate.yaml +3 -0
- package/agents/check-detail-result.mjs +2 -1
- package/agents/check-detail.mjs +1 -0
- package/agents/check-feedback-refiner.mjs +79 -0
- package/agents/check-structure-plan.mjs +16 -0
- package/agents/detail-generator-and-translate.yaml +3 -0
- package/agents/detail-regenerator.yaml +3 -0
- package/agents/docs-generator.yaml +3 -0
- package/agents/feedback-refiner.yaml +48 -0
- package/agents/find-items-by-paths.mjs +5 -1
- package/agents/find-user-preferences-by-path.mjs +37 -0
- package/agents/input-generator.mjs +8 -9
- package/agents/load-sources.mjs +63 -9
- package/agents/manage-prefs.mjs +203 -0
- package/agents/publish-docs.mjs +3 -1
- package/agents/retranslate.yaml +3 -0
- package/agents/structure-planning.yaml +3 -0
- package/aigne.yaml +4 -0
- package/package.json +10 -9
- package/prompts/content-detail-generator.md +13 -1
- package/prompts/document/detail-generator.md +1 -0
- package/prompts/feedback-refiner.md +84 -0
- package/prompts/structure-planning.md +8 -0
- package/prompts/translator.md +8 -0
- package/tests/{test-all-validation-cases.mjs → all-validation-cases.test.mjs} +60 -137
- package/tests/check-detail-result.test.mjs +90 -77
- package/tests/load-sources.test.mjs +103 -291
- package/tests/preferences-utils.test.mjs +369 -0
- package/tests/{test-save-docs.mjs → save-docs.test.mjs} +29 -47
- package/tests/save-value-to-config.test.mjs +165 -288
- package/utils/auth-utils.mjs +1 -1
- package/utils/constants.mjs +22 -10
- package/utils/markdown-checker.mjs +89 -9
- package/utils/preferences-utils.mjs +175 -0
- package/utils/utils.mjs +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.6.0](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.5.1...v0.6.0) (2025-08-27)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* complete support for media processing before publish ([#63](https://github.com/AIGNE-io/aigne-doc-smith/issues/63)) ([5257ca1](https://github.com/AIGNE-io/aigne-doc-smith/commit/5257ca1756f47487b65a1813949e547b6fc51aca))
|
|
9
|
+
|
|
10
|
+
## [0.5.1](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.5.0...v0.5.1) (2025-08-26)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Miscellaneous Chores
|
|
14
|
+
|
|
15
|
+
* release 0.5.1 ([892d96e](https://github.com/AIGNE-io/aigne-doc-smith/commit/892d96e939a6404a42e8d2521f95bb7acfeabe27))
|
|
16
|
+
|
|
17
|
+
## [0.5.0](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.4.5...v0.5.0) (2025-08-26)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
* support persistent user feedback as preferences ([#57](https://github.com/AIGNE-io/aigne-doc-smith/issues/57)) ([761a583](https://github.com/AIGNE-io/aigne-doc-smith/commit/761a583297b397a12d848d10d26cd5b675f8a9e7))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Bug Fixes
|
|
26
|
+
|
|
27
|
+
* polish init question copy ([#65](https://github.com/AIGNE-io/aigne-doc-smith/issues/65)) ([d4e8762](https://github.com/AIGNE-io/aigne-doc-smith/commit/d4e8762f26fd757bde43427860a0c1dade384269))
|
|
28
|
+
|
|
3
29
|
## [0.4.5](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.4.4...v0.4.5) (2025-08-25)
|
|
4
30
|
|
|
5
31
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { checkMarkdown } from "../utils/markdown-checker.mjs";
|
|
2
2
|
|
|
3
|
-
export default async function checkDetailResult({ structurePlan, reviewContent }) {
|
|
3
|
+
export default async function checkDetailResult({ structurePlan, reviewContent, docsDir }) {
|
|
4
4
|
let isApproved = true;
|
|
5
5
|
const detailFeedback = [];
|
|
6
6
|
|
|
@@ -24,6 +24,7 @@ export default async function checkDetailResult({ structurePlan, reviewContent }
|
|
|
24
24
|
try {
|
|
25
25
|
const markdownErrors = await checkMarkdown(reviewContent, "result", {
|
|
26
26
|
allowedLinks,
|
|
27
|
+
baseDir: docsDir,
|
|
27
28
|
});
|
|
28
29
|
|
|
29
30
|
if (markdownErrors.length > 0) {
|
package/agents/check-detail.mjs
CHANGED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { stringify } from "yaml";
|
|
2
|
+
import { addPreferenceRule, readPreferences } from "../utils/preferences-utils.mjs";
|
|
3
|
+
|
|
4
|
+
export default async function checkFeedbackRefiner(
|
|
5
|
+
{ feedback, stage, selectedPaths, structurePlanFeedback },
|
|
6
|
+
options,
|
|
7
|
+
) {
|
|
8
|
+
// If feedback is empty, no need to save user preferences
|
|
9
|
+
if (!feedback && !structurePlanFeedback) {
|
|
10
|
+
return {};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Read existing preferences as context for deduplication
|
|
14
|
+
const existingPreferences = readPreferences();
|
|
15
|
+
const activePreferences = existingPreferences.rules?.filter((rule) => rule.active) || [];
|
|
16
|
+
|
|
17
|
+
// Convert active preferences to YAML string format for passing
|
|
18
|
+
const activePreferencesYaml =
|
|
19
|
+
activePreferences.length > 0 ? stringify({ rules: activePreferences }, { indent: 2 }) : "";
|
|
20
|
+
|
|
21
|
+
const feedbackToUse = feedback || structurePlanFeedback;
|
|
22
|
+
const result = await options.context.invoke(options.context.agents["feedbackRefiner"], {
|
|
23
|
+
feedback: feedbackToUse,
|
|
24
|
+
stage,
|
|
25
|
+
paths: selectedPaths,
|
|
26
|
+
existingPreferences: activePreferencesYaml,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// If preferences need to be saved, save them to the preference file
|
|
30
|
+
if (result?.save) {
|
|
31
|
+
try {
|
|
32
|
+
const savedRule = addPreferenceRule(result, feedbackToUse, selectedPaths);
|
|
33
|
+
|
|
34
|
+
// Add saved preference information to the return result
|
|
35
|
+
result.savedPreference = {
|
|
36
|
+
id: savedRule.id,
|
|
37
|
+
saved: true,
|
|
38
|
+
};
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error(
|
|
41
|
+
"Failed to save user preference rule:",
|
|
42
|
+
error.message,
|
|
43
|
+
"\nFeedback:",
|
|
44
|
+
feedbackToUse,
|
|
45
|
+
);
|
|
46
|
+
result.savedPreference = {
|
|
47
|
+
saved: false,
|
|
48
|
+
error: error.message,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
checkFeedbackRefiner.input_schema = {
|
|
57
|
+
type: "object",
|
|
58
|
+
properties: {
|
|
59
|
+
feedback: {
|
|
60
|
+
type: "string",
|
|
61
|
+
description: "User feedback to refine",
|
|
62
|
+
},
|
|
63
|
+
structurePlanFeedback: {
|
|
64
|
+
type: "string",
|
|
65
|
+
description: "Feedback from structure planning stage",
|
|
66
|
+
},
|
|
67
|
+
stage: {
|
|
68
|
+
type: "string",
|
|
69
|
+
description: "Stage of the feedback",
|
|
70
|
+
},
|
|
71
|
+
selectedPaths: {
|
|
72
|
+
type: "array",
|
|
73
|
+
items: {
|
|
74
|
+
type: "string",
|
|
75
|
+
},
|
|
76
|
+
description: "Selected paths of documents",
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { access } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
+
import { getActiveRulesForScope } from "../utils/preferences-utils.mjs";
|
|
3
4
|
import {
|
|
4
5
|
getCurrentGitHead,
|
|
5
6
|
getProjectInfo,
|
|
@@ -15,6 +16,7 @@ export default async function checkStructurePlan(
|
|
|
15
16
|
// Check if we need to regenerate structure plan
|
|
16
17
|
let shouldRegenerate = false;
|
|
17
18
|
let finalFeedback = feedback;
|
|
19
|
+
let submittedFeedback = feedback;
|
|
18
20
|
|
|
19
21
|
// Prompt for feedback if originalStructurePlan exists and no feedback provided
|
|
20
22
|
if (originalStructurePlan && !feedback) {
|
|
@@ -24,6 +26,7 @@ export default async function checkStructurePlan(
|
|
|
24
26
|
|
|
25
27
|
if (userFeedback?.trim()) {
|
|
26
28
|
finalFeedback = userFeedback.trim();
|
|
29
|
+
submittedFeedback = userFeedback.trim();
|
|
27
30
|
}
|
|
28
31
|
}
|
|
29
32
|
|
|
@@ -84,9 +87,21 @@ export default async function checkStructurePlan(
|
|
|
84
87
|
|
|
85
88
|
const panningAgent = options.context.agents["structurePlanning"];
|
|
86
89
|
|
|
90
|
+
// Get user preferences for structure planning and global scope
|
|
91
|
+
const structureRules = getActiveRulesForScope("structure", []);
|
|
92
|
+
const globalRules = getActiveRulesForScope("global", []);
|
|
93
|
+
|
|
94
|
+
// Combine structure and global rules, extract only rule text
|
|
95
|
+
const allApplicableRules = [...structureRules, ...globalRules];
|
|
96
|
+
const ruleTexts = allApplicableRules.map((rule) => rule.rule);
|
|
97
|
+
|
|
98
|
+
// Convert rule texts to string format for passing to the agent
|
|
99
|
+
const userPreferences = ruleTexts.length > 0 ? ruleTexts.join("\n\n") : "";
|
|
100
|
+
|
|
87
101
|
const result = await options.context.invoke(panningAgent, {
|
|
88
102
|
feedback: finalFeedback || "",
|
|
89
103
|
originalStructurePlan,
|
|
104
|
+
userPreferences,
|
|
90
105
|
...rest,
|
|
91
106
|
});
|
|
92
107
|
|
|
@@ -140,6 +155,7 @@ export default async function checkStructurePlan(
|
|
|
140
155
|
return {
|
|
141
156
|
...result,
|
|
142
157
|
feedback: "", // clear feedback
|
|
158
|
+
structurePlanFeedback: submittedFeedback,
|
|
143
159
|
projectInfoMessage: message,
|
|
144
160
|
originalStructurePlan: originalStructurePlan
|
|
145
161
|
? originalStructurePlan
|
|
@@ -34,6 +34,9 @@ skills:
|
|
|
34
34
|
- ./detail-generator-and-translate.yaml
|
|
35
35
|
iterate_on: selectedDocs
|
|
36
36
|
concurrency: 3
|
|
37
|
+
- url: ./check-feedback-refiner.mjs
|
|
38
|
+
default_input:
|
|
39
|
+
stage: document_refine
|
|
37
40
|
- url: ./action-success.mjs
|
|
38
41
|
default_input:
|
|
39
42
|
action: "Document updated"
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name: feedbackRefiner
|
|
2
|
+
description: Analyzes a user's specific feedback on generated documentation and refines it into a general, reusable preference rule for future use.
|
|
3
|
+
|
|
4
|
+
# The instructions file contains the core logic (the prompt) for this Agent.
|
|
5
|
+
instructions:
|
|
6
|
+
url: ../prompts/feedback-refiner.md
|
|
7
|
+
|
|
8
|
+
input_schema:
|
|
9
|
+
type: object
|
|
10
|
+
properties:
|
|
11
|
+
feedback:
|
|
12
|
+
type: string
|
|
13
|
+
description: User's original feedback
|
|
14
|
+
stage:
|
|
15
|
+
type: string
|
|
16
|
+
description: The command/scenario that generated the feedback (used to infer scope), possible values. structure_planning, document_refine, translation_refine
|
|
17
|
+
paths:
|
|
18
|
+
type: array
|
|
19
|
+
items:
|
|
20
|
+
type: string
|
|
21
|
+
description: Optional. Document paths specified by the user in the current command
|
|
22
|
+
existingPreferences:
|
|
23
|
+
type: string
|
|
24
|
+
description: Optional. YAML format string of currently saved user preference rules, used to avoid duplicate saving of similar rules
|
|
25
|
+
required:
|
|
26
|
+
- feedback
|
|
27
|
+
- stage
|
|
28
|
+
|
|
29
|
+
output_schema:
|
|
30
|
+
type: object
|
|
31
|
+
properties:
|
|
32
|
+
rule:
|
|
33
|
+
type: string
|
|
34
|
+
description: Refine and summarize user feedback into a general rule
|
|
35
|
+
scope:
|
|
36
|
+
type: string
|
|
37
|
+
description: Rule scope. global, structure, document, translation
|
|
38
|
+
save:
|
|
39
|
+
type: boolean
|
|
40
|
+
description: Whether to save as persistent preference (true=save; false=one-time, do not save)
|
|
41
|
+
limitToInputPaths:
|
|
42
|
+
type: boolean
|
|
43
|
+
description: Whether to limit to the "paths specified in current input" when used subsequently
|
|
44
|
+
required:
|
|
45
|
+
- rule
|
|
46
|
+
- scope
|
|
47
|
+
- save
|
|
48
|
+
- limitToInputPaths
|
|
@@ -95,5 +95,9 @@ export default async function selectedDocs(
|
|
|
95
95
|
// Add feedback to all results if provided
|
|
96
96
|
foundItems = addFeedbackToItems(foundItems, userFeedback);
|
|
97
97
|
|
|
98
|
-
return {
|
|
98
|
+
return {
|
|
99
|
+
selectedDocs: foundItems,
|
|
100
|
+
feedback: userFeedback,
|
|
101
|
+
selectedPaths: foundItems.map((item) => item.path),
|
|
102
|
+
};
|
|
99
103
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { getActiveRulesForScope } from "../utils/preferences-utils.mjs";
|
|
2
|
+
|
|
3
|
+
export default async function findUserPreferencesByPath({ path, scope }) {
|
|
4
|
+
// Get global rules (always applicable)
|
|
5
|
+
const globalRules = getActiveRulesForScope("global", []);
|
|
6
|
+
|
|
7
|
+
// Get scope-specific rules (document/translation based on scope parameter)
|
|
8
|
+
const scopeRules = getActiveRulesForScope(scope, path ? [path] : []);
|
|
9
|
+
|
|
10
|
+
// Combine all applicable rules
|
|
11
|
+
const allApplicableRules = [...globalRules, ...scopeRules];
|
|
12
|
+
|
|
13
|
+
// Extract only rule text and join with double newlines
|
|
14
|
+
const ruleTexts = allApplicableRules.map((rule) => rule.rule);
|
|
15
|
+
const userPreferences = ruleTexts.length > 0 ? ruleTexts.join("\n\n") : "";
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
userPreferences,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
findUserPreferencesByPath.input_schema = {
|
|
23
|
+
type: "object",
|
|
24
|
+
properties: {
|
|
25
|
+
path: {
|
|
26
|
+
type: "string",
|
|
27
|
+
description: "Document path to find preferences for",
|
|
28
|
+
},
|
|
29
|
+
scope: {
|
|
30
|
+
type: "string",
|
|
31
|
+
description:
|
|
32
|
+
"Preference scope: 'document' for update operations, 'translation' for translate operations",
|
|
33
|
+
enum: ["document", "translation"],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
required: ["scope"],
|
|
37
|
+
};
|
|
@@ -47,8 +47,7 @@ export default async function init(
|
|
|
47
47
|
|
|
48
48
|
// 1. Primary purpose - what's the main outcome you want readers to achieve?
|
|
49
49
|
const purposeChoices = await options.prompts.checkbox({
|
|
50
|
-
message:
|
|
51
|
-
"📝 Step 1/8: What's the main outcome you want readers to achieve? (Select all that apply)",
|
|
50
|
+
message: "📝 [1/8]: What is the primary goal for your readers? (Select all that apply)",
|
|
52
51
|
choices: Object.entries(DOCUMENT_STYLES)
|
|
53
52
|
.filter(([key]) => key !== "custom") // Remove custom option for multiselect
|
|
54
53
|
.map(([key, style]) => ({
|
|
@@ -96,7 +95,7 @@ export default async function init(
|
|
|
96
95
|
|
|
97
96
|
// 2. Target audience - who will be reading this most often?
|
|
98
97
|
const audienceChoices = await options.prompts.checkbox({
|
|
99
|
-
message: "👥
|
|
98
|
+
message: "👥 [2/8]: Who is the primary audience for this documentation?",
|
|
100
99
|
choices: Object.entries(TARGET_AUDIENCES)
|
|
101
100
|
.filter(([key]) => key !== "custom") // Remove custom option for multiselect
|
|
102
101
|
.map(([key, audience]) => ({
|
|
@@ -130,7 +129,7 @@ export default async function init(
|
|
|
130
129
|
);
|
|
131
130
|
|
|
132
131
|
const knowledgeChoice = await options.prompts.select({
|
|
133
|
-
message: "🧠
|
|
132
|
+
message: "🧠 [3/8]: What is your reader's typical starting knowledge level?",
|
|
134
133
|
choices: Object.entries(filteredKnowledgeOptions).map(([key, level]) => ({
|
|
135
134
|
name: `${level.name}`,
|
|
136
135
|
description: level.description,
|
|
@@ -175,7 +174,7 @@ export default async function init(
|
|
|
175
174
|
);
|
|
176
175
|
|
|
177
176
|
const depthChoice = await options.prompts.select({
|
|
178
|
-
message: "📊
|
|
177
|
+
message: "📊 [4/8]: How comprehensive should the documentation be?",
|
|
179
178
|
choices: Object.entries(filteredDepthOptions).map(([key, depth]) => ({
|
|
180
179
|
name: `${depth.name}`,
|
|
181
180
|
description: depth.description,
|
|
@@ -193,7 +192,7 @@ export default async function init(
|
|
|
193
192
|
|
|
194
193
|
// Let user select primary language from supported list
|
|
195
194
|
const primaryLanguageChoice = await options.prompts.select({
|
|
196
|
-
message: "🌐
|
|
195
|
+
message: "🌐 [5/8]: Choose primary documentation language:",
|
|
197
196
|
choices: SUPPORTED_LANGUAGES.map((lang) => ({
|
|
198
197
|
name: `${lang.label} - ${lang.sample}`,
|
|
199
198
|
value: lang.code,
|
|
@@ -210,7 +209,7 @@ export default async function init(
|
|
|
210
209
|
);
|
|
211
210
|
|
|
212
211
|
const translateLanguageChoices = await options.prompts.checkbox({
|
|
213
|
-
message: "🔄
|
|
212
|
+
message: "🔄 [6/8]: Select translation languages:",
|
|
214
213
|
choices: availableTranslationLanguages.map((lang) => ({
|
|
215
214
|
name: `${lang.label} - ${lang.sample}`,
|
|
216
215
|
value: lang.code,
|
|
@@ -221,13 +220,13 @@ export default async function init(
|
|
|
221
220
|
|
|
222
221
|
// 7. Documentation directory
|
|
223
222
|
const docsDirInput = await options.prompts.input({
|
|
224
|
-
message: `📁
|
|
223
|
+
message: `📁 [7/8]: Where to save generated docs:`,
|
|
225
224
|
default: `${outputPath}/docs`,
|
|
226
225
|
});
|
|
227
226
|
input.docsDir = docsDirInput.trim() || `${outputPath}/docs`;
|
|
228
227
|
|
|
229
228
|
// 8. Source code paths
|
|
230
|
-
console.log("\n🔍
|
|
229
|
+
console.log("\n🔍 [8/8]: Source Code Paths");
|
|
231
230
|
console.log("Enter paths to analyze for documentation (e.g., ./src, ./lib)");
|
|
232
231
|
console.log("💡 If no paths are configured, './' will be used as default");
|
|
233
232
|
|
package/agents/load-sources.mjs
CHANGED
|
@@ -86,17 +86,55 @@ export default async function loadSources({
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
files = [...new Set(files)];
|
|
89
|
+
|
|
90
|
+
// Define media file extensions
|
|
91
|
+
const mediaExtensions = [
|
|
92
|
+
".jpg",
|
|
93
|
+
".jpeg",
|
|
94
|
+
".png",
|
|
95
|
+
".gif",
|
|
96
|
+
".bmp",
|
|
97
|
+
".webp",
|
|
98
|
+
".svg",
|
|
99
|
+
".mp4",
|
|
100
|
+
".mov",
|
|
101
|
+
".avi",
|
|
102
|
+
".mkv",
|
|
103
|
+
".webm",
|
|
104
|
+
".m4v",
|
|
105
|
+
];
|
|
106
|
+
|
|
107
|
+
// Separate source files from media files
|
|
108
|
+
const sourceFiles = [];
|
|
109
|
+
const mediaFiles = [];
|
|
89
110
|
let allSources = "";
|
|
90
|
-
|
|
111
|
+
|
|
112
|
+
await Promise.all(
|
|
91
113
|
files.map(async (file) => {
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
114
|
+
const ext = path.extname(file).toLowerCase();
|
|
115
|
+
|
|
116
|
+
if (mediaExtensions.includes(ext)) {
|
|
117
|
+
// This is a media file
|
|
118
|
+
const relativePath = path.relative(docsDir, file);
|
|
119
|
+
const fileName = path.basename(file);
|
|
120
|
+
const description = path.parse(fileName).name;
|
|
121
|
+
|
|
122
|
+
mediaFiles.push({
|
|
123
|
+
name: fileName,
|
|
124
|
+
path: relativePath,
|
|
125
|
+
description,
|
|
126
|
+
});
|
|
127
|
+
} else {
|
|
128
|
+
// This is a source file
|
|
129
|
+
const content = await readFile(file, "utf8");
|
|
130
|
+
const relativePath = path.relative(process.cwd(), file);
|
|
131
|
+
allSources += `// sourceId: ${relativePath}\n${content}\n`;
|
|
132
|
+
|
|
133
|
+
sourceFiles.push({
|
|
134
|
+
sourceId: relativePath,
|
|
135
|
+
content,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
100
138
|
}),
|
|
101
139
|
);
|
|
102
140
|
|
|
@@ -164,6 +202,17 @@ export default async function loadSources({
|
|
|
164
202
|
}
|
|
165
203
|
}
|
|
166
204
|
|
|
205
|
+
// Generate assets content from media files
|
|
206
|
+
let assetsContent = "# Available Media Assets for Documentation\n\n";
|
|
207
|
+
|
|
208
|
+
if (mediaFiles.length > 0) {
|
|
209
|
+
const mediaMarkdown = mediaFiles
|
|
210
|
+
.map((file) => ``)
|
|
211
|
+
.join("\n\n");
|
|
212
|
+
|
|
213
|
+
assetsContent += mediaMarkdown;
|
|
214
|
+
}
|
|
215
|
+
|
|
167
216
|
// Count words and lines in allSources
|
|
168
217
|
let totalWords = 0;
|
|
169
218
|
let totalLines = 0;
|
|
@@ -188,6 +237,7 @@ export default async function loadSources({
|
|
|
188
237
|
modifiedFiles,
|
|
189
238
|
totalWords,
|
|
190
239
|
totalLines,
|
|
240
|
+
assetsContent,
|
|
191
241
|
};
|
|
192
242
|
}
|
|
193
243
|
|
|
@@ -257,6 +307,10 @@ loadSources.output_schema = {
|
|
|
257
307
|
items: { type: "string" },
|
|
258
308
|
description: "Array of modified files since last generation",
|
|
259
309
|
},
|
|
310
|
+
assetsContent: {
|
|
311
|
+
type: "string",
|
|
312
|
+
description: "Markdown content for available media assets",
|
|
313
|
+
},
|
|
260
314
|
},
|
|
261
315
|
};
|
|
262
316
|
|