@aigne/doc-smith 0.4.5 → 0.5.1
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 +19 -0
- package/agents/batch-translate.yaml +3 -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/manage-prefs.mjs +203 -0
- package/agents/publish-docs.mjs +1 -1
- package/agents/retranslate.yaml +3 -0
- package/agents/structure-planning.yaml +3 -0
- package/aigne.yaml +4 -0
- package/package.json +3 -2
- package/prompts/content-detail-generator.md +8 -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 +46 -82
- 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/constants.mjs +8 -8
- package/utils/preferences-utils.mjs +175 -0
- package/utils/utils.mjs +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.5.1](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.5.0...v0.5.1) (2025-08-26)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Miscellaneous Chores
|
|
7
|
+
|
|
8
|
+
* release 0.5.1 ([892d96e](https://github.com/AIGNE-io/aigne-doc-smith/commit/892d96e939a6404a42e8d2521f95bb7acfeabe27))
|
|
9
|
+
|
|
10
|
+
## [0.5.0](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.4.5...v0.5.0) (2025-08-26)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* 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))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* 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))
|
|
21
|
+
|
|
3
22
|
## [0.4.5](https://github.com/AIGNE-io/aigne-doc-smith/compare/v0.4.4...v0.4.5) (2025-08-25)
|
|
4
23
|
|
|
5
24
|
|
|
@@ -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
|
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { readPreferences, removeRule, writePreferences } from "../utils/preferences-utils.mjs";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* List all user preferences with formatted display
|
|
5
|
+
* @returns {Object} Result with formatted message
|
|
6
|
+
*/
|
|
7
|
+
function listPreferences() {
|
|
8
|
+
const preferences = readPreferences();
|
|
9
|
+
|
|
10
|
+
if (preferences.rules.length === 0) {
|
|
11
|
+
return { message: "No preferences found." };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let message = "# User Preferences\n\n";
|
|
15
|
+
|
|
16
|
+
// Add format explanation
|
|
17
|
+
message += "**Format explanation:**\n";
|
|
18
|
+
message += "- 🟢 = Active preference, ⚪ = Inactive preference\n";
|
|
19
|
+
message += "- [scope] = Preference scope (global, structure, document, translation)\n";
|
|
20
|
+
message += "- ID = Unique preference identifier\n";
|
|
21
|
+
message += "- Paths = Specific file paths (if applicable)\n\n";
|
|
22
|
+
|
|
23
|
+
preferences.rules.forEach((rule) => {
|
|
24
|
+
const status = rule.active ? "🟢" : "⚪";
|
|
25
|
+
const pathsInfo = rule.paths ? ` | Paths: ${rule.paths.join(", ")}` : "";
|
|
26
|
+
|
|
27
|
+
// First line: status, scope, ID and paths info
|
|
28
|
+
message += `${status} [${rule.scope}] ${rule.id}${pathsInfo}\n`;
|
|
29
|
+
|
|
30
|
+
// Second line: rule content (truncated if too long)
|
|
31
|
+
const maxRuleLength = 120;
|
|
32
|
+
const ruleText =
|
|
33
|
+
rule.rule.length > maxRuleLength ? `${rule.rule.substring(0, maxRuleLength)}...` : rule.rule;
|
|
34
|
+
message += ` ${ruleText}\n `;
|
|
35
|
+
|
|
36
|
+
// Add blank line after each record
|
|
37
|
+
message += `\n`;
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return { message };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Remove preferences by IDs or interactive selection
|
|
45
|
+
* @param {string[]} id - Array of preference IDs to remove
|
|
46
|
+
* @param {Object} options - Options with prompts interface
|
|
47
|
+
* @returns {Object} Result with success message
|
|
48
|
+
*/
|
|
49
|
+
async function removePreferences(id, options) {
|
|
50
|
+
const preferences = readPreferences();
|
|
51
|
+
let targetIds = id;
|
|
52
|
+
|
|
53
|
+
if (!targetIds || targetIds.length === 0) {
|
|
54
|
+
// Interactive selection
|
|
55
|
+
if (preferences.rules.length === 0) {
|
|
56
|
+
return { message: "No preferences found to remove." };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const choices = preferences.rules.map((rule) => ({
|
|
60
|
+
name: `${rule.active ? "🟢" : "⚪"} [${rule.scope}] ${rule.rule.substring(0, 60)}${rule.rule.length > 60 ? "..." : ""}`,
|
|
61
|
+
value: rule.id,
|
|
62
|
+
description: `ID: ${rule.id}`,
|
|
63
|
+
}));
|
|
64
|
+
|
|
65
|
+
targetIds = await options.prompts.checkbox({
|
|
66
|
+
message: "Select preferences to remove:",
|
|
67
|
+
choices,
|
|
68
|
+
validate: (answer) => {
|
|
69
|
+
if (answer.length === 0) {
|
|
70
|
+
return "Please select at least one preference to remove";
|
|
71
|
+
}
|
|
72
|
+
return true;
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
if (!targetIds || targetIds.length === 0) {
|
|
77
|
+
return { message: "No preferences selected for removal." };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Process the target IDs
|
|
82
|
+
const results = [];
|
|
83
|
+
for (const ruleId of targetIds) {
|
|
84
|
+
const success = removeRule(ruleId);
|
|
85
|
+
results.push({ id: ruleId, success });
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const successCount = results.filter((r) => r.success).length;
|
|
89
|
+
const failedCount = targetIds.length - successCount;
|
|
90
|
+
const message =
|
|
91
|
+
failedCount > 0
|
|
92
|
+
? `Successfully removed ${successCount} preferences, ${failedCount} failed.`
|
|
93
|
+
: `Successfully removed ${successCount} preferences.`;
|
|
94
|
+
|
|
95
|
+
return { message };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Toggle preferences active status by IDs or interactive selection
|
|
100
|
+
* @param {string[]} id - Array of preference IDs to toggle
|
|
101
|
+
* @param {Object} options - Options with prompts interface
|
|
102
|
+
* @returns {Object} Result with success message
|
|
103
|
+
*/
|
|
104
|
+
async function togglePreferences(id, options) {
|
|
105
|
+
const preferences = readPreferences();
|
|
106
|
+
let targetIds = id;
|
|
107
|
+
|
|
108
|
+
if (!targetIds || targetIds.length === 0) {
|
|
109
|
+
// Interactive selection
|
|
110
|
+
if (preferences.rules.length === 0) {
|
|
111
|
+
return { message: "No preferences found to toggle." };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const choices = preferences.rules.map((rule) => ({
|
|
115
|
+
name: `${rule.active ? "🟢" : "⚪"} [${rule.scope}] ${rule.rule.substring(0, 60)}${rule.rule.length > 60 ? "..." : ""}`,
|
|
116
|
+
value: rule.id,
|
|
117
|
+
description: `ID: ${rule.id}`,
|
|
118
|
+
}));
|
|
119
|
+
|
|
120
|
+
targetIds = await options.prompts.checkbox({
|
|
121
|
+
message: "Select preferences to toggle active status:",
|
|
122
|
+
choices,
|
|
123
|
+
validate: (answer) => {
|
|
124
|
+
if (answer.length === 0) {
|
|
125
|
+
return "Please select at least one preference to toggle";
|
|
126
|
+
}
|
|
127
|
+
return true;
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
if (!targetIds || targetIds.length === 0) {
|
|
132
|
+
return { message: "No preferences selected for toggling." };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Process the target IDs
|
|
137
|
+
const results = [];
|
|
138
|
+
const prefs = readPreferences();
|
|
139
|
+
|
|
140
|
+
for (const ruleId of targetIds) {
|
|
141
|
+
const rule = prefs.rules.find((r) => r.id === ruleId);
|
|
142
|
+
if (rule) {
|
|
143
|
+
rule.active = !rule.active;
|
|
144
|
+
results.push({ id: ruleId, success: true, newStatus: rule.active });
|
|
145
|
+
} else {
|
|
146
|
+
results.push({ id: ruleId, success: false, error: "Rule not found" });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
writePreferences(prefs);
|
|
151
|
+
|
|
152
|
+
const successCount = results.filter((r) => r.success).length;
|
|
153
|
+
const failedCount = targetIds.length - successCount;
|
|
154
|
+
const message =
|
|
155
|
+
failedCount > 0
|
|
156
|
+
? `Successfully toggled ${successCount} preferences, ${failedCount} failed.`
|
|
157
|
+
: `Successfully toggled ${successCount} preferences.`;
|
|
158
|
+
|
|
159
|
+
return { message };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export default async function prefs({ list, remove, toggle, id }, options) {
|
|
163
|
+
if (list) {
|
|
164
|
+
return listPreferences();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (remove) {
|
|
168
|
+
return await removePreferences(id, options);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (toggle) {
|
|
172
|
+
return await togglePreferences(id, options);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return { message: "Please specify an action: --list, --remove, or --toggle." };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
prefs.input_schema = {
|
|
179
|
+
type: "object",
|
|
180
|
+
properties: {
|
|
181
|
+
list: {
|
|
182
|
+
type: "boolean",
|
|
183
|
+
description: "List all preferences",
|
|
184
|
+
},
|
|
185
|
+
remove: {
|
|
186
|
+
type: "boolean",
|
|
187
|
+
description: "Remove preferences",
|
|
188
|
+
},
|
|
189
|
+
toggle: {
|
|
190
|
+
type: "boolean",
|
|
191
|
+
description: "Toggle preferences active status",
|
|
192
|
+
},
|
|
193
|
+
id: {
|
|
194
|
+
type: "array",
|
|
195
|
+
items: {
|
|
196
|
+
type: "string",
|
|
197
|
+
},
|
|
198
|
+
description: "Preference IDs to manage",
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
prefs.description = "Manage user preferences learned from feedback";
|
package/agents/publish-docs.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { publishDocs as publishDocsFn } from "@aigne/publish-docs";
|
|
|
3
3
|
import chalk from "chalk";
|
|
4
4
|
import { getAccessToken } from "../utils/auth-utils.mjs";
|
|
5
5
|
import { DISCUSS_KIT_STORE_URL } from "../utils/constants.mjs";
|
|
6
|
-
import { loadConfigFromFile, saveValueToConfig
|
|
6
|
+
import { getGithubRepoUrl, loadConfigFromFile, saveValueToConfig } from "../utils/utils.mjs";
|
|
7
7
|
|
|
8
8
|
const DEFAULT_APP_URL = "https://docsmith.aigne.io";
|
|
9
9
|
|
package/agents/retranslate.yaml
CHANGED
package/aigne.yaml
CHANGED
|
@@ -37,6 +37,9 @@ agents:
|
|
|
37
37
|
- ./docs-mcp/analyze-docs-relevance.yaml
|
|
38
38
|
- ./docs-mcp/read-doc-content.mjs
|
|
39
39
|
- ./docs-mcp/analyze-content-relevance.yaml
|
|
40
|
+
- ./agents/check-feedback-refiner.mjs
|
|
41
|
+
- ./agents/feedback-refiner.yaml
|
|
42
|
+
- ./agents/manage-prefs.mjs
|
|
40
43
|
cli:
|
|
41
44
|
agents:
|
|
42
45
|
- ./agents/input-generator.mjs
|
|
@@ -44,6 +47,7 @@ cli:
|
|
|
44
47
|
- ./agents/detail-regenerator.yaml
|
|
45
48
|
- ./agents/team-publish-docs.yaml
|
|
46
49
|
- ./agents/retranslate.yaml
|
|
50
|
+
- ./agents/manage-prefs.mjs
|
|
47
51
|
mcp_server:
|
|
48
52
|
agents:
|
|
49
53
|
- ./docs-mcp/get-docs-structure.mjs
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/doc-smith",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -39,7 +39,8 @@
|
|
|
39
39
|
"@biomejs/biome": "^2.1.4"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
|
-
"test": "
|
|
42
|
+
"test": "bun test",
|
|
43
|
+
"test:watch": "bun test --watch",
|
|
43
44
|
"lint": "biome check && pnpm -r run lint",
|
|
44
45
|
"update:deps": "npx -y taze major -r -w -f -n '/@abtnode|@aigne|@arcblock|@blocklet|@did-connect|@did-pay|@did-space|@nft-store|@nft-studio|@ocap/' && pnpm install && pnpm run deduplicate",
|
|
45
46
|
"deduplicate": "pnpm dedupe",
|
|
@@ -56,6 +56,14 @@ parentId: {{parentId}}
|
|
|
56
56
|
** 使用 {{ locale }} 语言输出内容 **
|
|
57
57
|
</user_rules>
|
|
58
58
|
|
|
59
|
+
<user_preferences>
|
|
60
|
+
{{userPreferences}}
|
|
61
|
+
|
|
62
|
+
用户偏好使用规则:
|
|
63
|
+
- 用户偏好来自用户之前操作中提供的反馈,生成结构规划中需要考虑用户的偏好,避免出现用户反馈的问题又重复出现
|
|
64
|
+
- 用户偏好的权重低于本次用户提交的反馈
|
|
65
|
+
</user_preferences>
|
|
66
|
+
|
|
59
67
|
<rules>
|
|
60
68
|
|
|
61
69
|
目标受众:{{targetAudience}}
|