@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 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
 
@@ -6,6 +6,9 @@ skills:
6
6
  task_render_mode: collapse
7
7
  name: translate
8
8
  skills:
9
+ - url: ./find-user-preferences-by-path.mjs
10
+ default_input:
11
+ scope: translation
9
12
  - ./translate.yaml
10
13
  - type: transform
11
14
  jsonata: |
@@ -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
@@ -7,6 +7,9 @@ skills:
7
7
  task_render_mode: collapse
8
8
  name: detailGenerate
9
9
  skills:
10
+ - url: ./find-user-preferences-by-path.mjs
11
+ default_input:
12
+ scope: document
10
13
  - ./content-detail-generator.yaml
11
14
  - type: transform
12
15
  jsonata: |
@@ -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"
@@ -37,6 +37,9 @@ skills:
37
37
  ])
38
38
  - ./format-structure-plan.mjs
39
39
  - ./batch-docs-detail-generator.yaml
40
+ - url: ./check-feedback-refiner.mjs
41
+ default_input:
42
+ stage: structure_planning
40
43
  - ./save-docs.mjs
41
44
 
42
45
  input_schema:
@@ -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 { selectedDocs: foundItems };
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: "👥 Step 2/8: Who will be reading this most often? (Select all that apply)",
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: "🧠 Step 3/8: What do readers typically know when they arrive?",
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: "📊 Step 4/8: How comprehensive should the documentation be?",
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: "🌐 Step 5/8: Choose primary documentation language:",
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: "🔄 Step 6/8: Select translation languages:",
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: `📁 Step 7/8: Where to save generated docs:`,
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🔍 Step 8/8: Source Code Paths");
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";
@@ -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, getGithubRepoUrl } from "../utils/utils.mjs";
6
+ import { getGithubRepoUrl, loadConfigFromFile, saveValueToConfig } from "../utils/utils.mjs";
7
7
 
8
8
  const DEFAULT_APP_URL = "https://docsmith.aigne.io";
9
9
 
@@ -37,6 +37,9 @@ skills:
37
37
  isTranslate: true
38
38
  iterate_on: selectedDocs
39
39
  concurrency: 3
40
+ - url: ./check-feedback-refiner.mjs
41
+ default_input:
42
+ stage: translation_refine
40
43
  - url: ./action-success.mjs
41
44
  default_input:
42
45
  action: "Document translated"
@@ -26,6 +26,9 @@ input_schema:
26
26
  feedback:
27
27
  type: string
28
28
  description: 结构规划的反馈
29
+ userPreferences:
30
+ type: string
31
+ description: 用户偏好规则,YAML格式的结构规划和全局范围偏好
29
32
  docsType:
30
33
  type: string
31
34
  description: 文档类型,支持:general、getting-started、reference、faq
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.4.5",
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": "echo \"Error: no test specified\" && exit 1",
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}}