@aigne/doc-smith 0.9.7 → 0.9.8-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.
Files changed (56) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/agents/create/analyze-diagram-type-llm.yaml +160 -0
  3. package/agents/create/analyze-diagram-type.mjs +297 -0
  4. package/agents/create/generate-diagram-image.yaml +60 -0
  5. package/agents/create/replace-d2-with-image.mjs +624 -0
  6. package/agents/create/utils/init-current-content.mjs +5 -9
  7. package/agents/evaluate/document.yaml +6 -0
  8. package/agents/evaluate/index.yaml +1 -0
  9. package/agents/init/index.mjs +16 -0
  10. package/agents/media/batch-generate-media-description.yaml +2 -0
  11. package/agents/media/generate-media-description.yaml +3 -0
  12. package/agents/media/load-media-description.mjs +44 -15
  13. package/agents/publish/publish-docs.mjs +1 -4
  14. package/agents/update/check-diagram-flag.mjs +116 -0
  15. package/agents/update/check-document.mjs +0 -1
  16. package/agents/update/check-generate-diagram.mjs +48 -30
  17. package/agents/update/check-sync-image-flag.mjs +55 -0
  18. package/agents/update/check-update-is-single.mjs +11 -0
  19. package/agents/update/generate-diagram.yaml +43 -9
  20. package/agents/update/generate-document.yaml +9 -0
  21. package/agents/update/handle-document-update.yaml +10 -8
  22. package/agents/update/index.yaml +16 -1
  23. package/agents/update/sync-images-and-exit.mjs +148 -0
  24. package/agents/update/update-single/update-single-document-detail.mjs +131 -17
  25. package/agents/utils/analyze-feedback-intent.mjs +136 -0
  26. package/agents/utils/choose-docs.mjs +183 -40
  27. package/agents/utils/generate-document-or-skip.mjs +41 -0
  28. package/agents/utils/handle-diagram-operations.mjs +263 -0
  29. package/agents/utils/load-all-document-content.mjs +30 -0
  30. package/agents/utils/load-sources.mjs +2 -2
  31. package/agents/utils/read-current-document-content.mjs +46 -0
  32. package/agents/utils/save-doc.mjs +42 -0
  33. package/agents/utils/skip-if-content-exists.mjs +27 -0
  34. package/aigne.yaml +6 -1
  35. package/assets/report-template/report.html +17 -17
  36. package/docs-mcp/read-doc-content.mjs +30 -1
  37. package/package.json +4 -4
  38. package/prompts/detail/diagram/generate-image-system.md +135 -0
  39. package/prompts/detail/diagram/generate-image-user.md +32 -0
  40. package/prompts/detail/generate/user-prompt.md +27 -13
  41. package/prompts/evaluate/document.md +23 -10
  42. package/prompts/media/media-description/system-prompt.md +10 -2
  43. package/prompts/media/media-description/user-prompt.md +9 -0
  44. package/utils/check-document-has-diagram.mjs +97 -0
  45. package/utils/constants/index.mjs +46 -0
  46. package/utils/d2-utils.mjs +114 -181
  47. package/utils/delete-diagram-images.mjs +103 -0
  48. package/utils/docs-finder-utils.mjs +34 -1
  49. package/utils/image-compress.mjs +75 -0
  50. package/utils/kroki-utils.mjs +2 -3
  51. package/utils/sync-diagram-to-translations.mjs +258 -0
  52. package/utils/utils.mjs +24 -0
  53. package/agents/create/check-diagram.mjs +0 -40
  54. package/agents/create/draw-diagram.yaml +0 -27
  55. package/agents/create/merge-diagram.yaml +0 -39
  56. package/agents/create/wrap-diagram-code.mjs +0 -35
@@ -0,0 +1,148 @@
1
+ import { syncDiagramToTranslations } from "../../utils/sync-diagram-to-translations.mjs";
2
+ import { readFileContent } from "../../utils/docs-finder-utils.mjs";
3
+ import { getFileName } from "../../utils/utils.mjs";
4
+ import { debug } from "../../utils/debug.mjs";
5
+
6
+ /**
7
+ * Sync images to translations and exit if shouldSyncImages is true
8
+ * Otherwise, passes through input for normal update flow
9
+ *
10
+ * This agent combines:
11
+ * - Image synchronization logic
12
+ * - Flow routing (sync vs normal update)
13
+ * - Early exit handling
14
+ */
15
+ export default async function syncImagesAndExit(input, options) {
16
+ // If shouldSyncImages is false, pass through for normal update flow
17
+ if (!input.shouldSyncImages) {
18
+ return input;
19
+ }
20
+
21
+ // Sync images flow
22
+ const { selectedDocs = [], docsDir, locale = "en" } = input;
23
+
24
+ if (!docsDir) {
25
+ throw new Error("docsDir is required for image sync. Please ensure config is loaded.");
26
+ }
27
+
28
+ if (!Array.isArray(selectedDocs) || selectedDocs.length === 0) {
29
+ const actionSuccessAgent = options.context?.agents?.["actionSuccess"];
30
+ if (actionSuccessAgent) {
31
+ await options.context.invoke(actionSuccessAgent, {
32
+ action: "ℹ️ No documents selected for image sync",
33
+ });
34
+ }
35
+ // Exit normally to prevent passing to next steps
36
+ process.exit(0);
37
+ }
38
+
39
+ const results = {
40
+ updated: 0,
41
+ skipped: 0,
42
+ errors: [],
43
+ };
44
+
45
+ // Process each document
46
+ for (const doc of selectedDocs) {
47
+ try {
48
+ // Use content from doc if available, otherwise read from file
49
+ let mainContent = doc.content;
50
+ if (!mainContent) {
51
+ const mainFileName = getFileName(doc.path, locale);
52
+ mainContent = await readFileContent(docsDir, mainFileName);
53
+ }
54
+
55
+ if (!mainContent) {
56
+ debug(`⚠️ Could not read main document: ${doc.path}`);
57
+ results.skipped++;
58
+ continue;
59
+ }
60
+
61
+ // Sync images to translation documents
62
+ const syncResult = await syncDiagramToTranslations(mainContent, doc.path, docsDir, locale);
63
+
64
+ results.updated += syncResult.updated;
65
+ results.skipped += syncResult.skipped;
66
+ results.errors.push(...syncResult.errors);
67
+
68
+ if (syncResult.updated > 0) {
69
+ debug(`✅ Synced images from ${doc.path} to ${syncResult.updated} translation file(s)`);
70
+ } else if (syncResult.skipped > 0) {
71
+ debug(
72
+ `⏭️ No changes needed for ${doc.path} (${syncResult.skipped} translation file(s) already in sync)`,
73
+ );
74
+ }
75
+ } catch (error) {
76
+ debug(`❌ Error syncing images for ${doc.path}: ${error.message}`);
77
+ results.errors.push({
78
+ doc: doc.path,
79
+ error: error.message,
80
+ });
81
+ }
82
+ }
83
+
84
+ // Generate success message
85
+ const message = `✅ Image sync completed: ${results.updated} translation file(s) updated, ${results.skipped} skipped${
86
+ results.errors.length > 0 ? `, ${results.errors.length} error(s)` : ""
87
+ }`;
88
+
89
+ // Show success message
90
+ const actionSuccessAgent = options.context?.agents?.["actionSuccess"];
91
+ if (actionSuccessAgent) {
92
+ await options.context.invoke(actionSuccessAgent, {
93
+ action: message,
94
+ });
95
+ }
96
+
97
+ // Exit normally to prevent passing to next steps and avoid validation errors
98
+ // This ensures a clean exit after successful image sync
99
+ process.exit(0);
100
+ }
101
+
102
+ syncImagesAndExit.input_schema = {
103
+ type: "object",
104
+ properties: {
105
+ shouldSyncImages: {
106
+ type: "boolean",
107
+ description: "Whether to trigger image sync to translations",
108
+ },
109
+ selectedDocs: {
110
+ type: "array",
111
+ description: "Array of selected documents to sync images from",
112
+ },
113
+ docsDir: {
114
+ type: "string",
115
+ description: "Documentation directory where documents are stored",
116
+ },
117
+ locale: {
118
+ type: "string",
119
+ description: "Main language locale (e.g., 'en', 'zh')",
120
+ default: "en",
121
+ },
122
+ },
123
+ required: ["shouldSyncImages"],
124
+ };
125
+
126
+ syncImagesAndExit.output_schema = {
127
+ type: "object",
128
+ properties: {
129
+ message: {
130
+ type: "string",
131
+ description: "Summary message of the sync operation",
132
+ },
133
+ updated: {
134
+ type: "number",
135
+ description: "Number of translation files successfully updated",
136
+ },
137
+ skipped: {
138
+ type: "number",
139
+ description: "Number of translation files skipped (no changes needed)",
140
+ },
141
+ errors: {
142
+ type: "array",
143
+ description: "Array of errors encountered during sync",
144
+ },
145
+ },
146
+ };
147
+
148
+ syncImagesAndExit.task_render_mode = "hide";
@@ -4,18 +4,72 @@ import z from "zod";
4
4
  import {
5
5
  DIAGRAM_PLACEHOLDER,
6
6
  replaceD2WithPlaceholder,
7
- replacePlaceholderWithD2,
7
+ replaceDiagramsWithPlaceholder,
8
8
  } from "../../../utils/d2-utils.mjs";
9
9
  import { userContextAt } from "../../../utils/utils.mjs";
10
10
 
11
11
  async function getIntentType(input, options) {
12
12
  const instructions = `<role>
13
13
  You are a feedback intent analyzer. Your task is to determine which type of content modifications are needed based on the user's feedback.
14
+
15
+ You must analyze the user's feedback and classify it into one of the following intent types:
16
+ - addDiagram: User wants to add a new diagram/image/chart
17
+ - deleteDiagram: User wants to remove/delete a diagram/image/chart
18
+ - updateDiagram: User wants to modify/update an existing diagram/image/chart
19
+ - updateDocument: User wants to update document content (text, sections, etc.) without diagram operations
14
20
  </role>
15
21
 
22
+ <intent_classification_rules>
23
+ **deleteDiagram** - Use this when user explicitly wants to remove or delete a diagram/image/chart:
24
+ - Keywords: remove, delete, 删除, 移除, 去掉, 清除
25
+ - Combined with: diagram, image, picture, chart, graph, 图表, 图片, 图, 架构图
26
+ - Examples:
27
+ - "Remove the diagram"
28
+ - "Delete the image"
29
+ - "删除这张图片"
30
+ - "Remove the second diagram"
31
+ - "去掉架构图"
32
+ - "Remove image from page 3"
33
+ - "Delete the chart showing the flow"
34
+
35
+ **addDiagram** - Use this when user wants to add a new diagram:
36
+ - Keywords: add, create, insert, 添加, 创建, 插入
37
+ - Combined with: diagram, image, picture, chart, graph, 图表, 图片, 图
38
+ - Examples:
39
+ - "Add a diagram showing the architecture"
40
+ - "Create a flow chart"
41
+ - "添加一个架构图"
42
+
43
+ **updateDiagram** - Use this when user wants to modify an existing diagram:
44
+ - Keywords: update, modify, change, improve, 更新, 修改, 改进
45
+ - Combined with: diagram, image, picture, chart, graph, 图表, 图片, 图
46
+ - Examples:
47
+ - "Update the diagram to show the new process"
48
+ - "Modify the chart to include more details"
49
+ - "更新架构图"
50
+
51
+ **updateDocument** - Use this for all other content modifications:
52
+ - Text changes, section updates, content improvements
53
+ - No mention of diagrams/images/charts
54
+ - Examples:
55
+ - "Update the introduction section"
56
+ - "Fix the typo in paragraph 2"
57
+ - "Improve the explanation"
58
+ </intent_classification_rules>
59
+
16
60
  <user_feedback>
17
61
  {{feedback}}
18
- </user_feedback>`;
62
+ </user_feedback>
63
+
64
+ <analysis_guidelines>
65
+ 1. Pay close attention to action verbs (remove, delete, add, update, etc.)
66
+ 2. Identify the target object (diagram, image, chart, or general content)
67
+ 3. If feedback mentions removing/deleting a diagram/image/chart → deleteDiagram
68
+ 4. If feedback mentions adding a diagram/image/chart → addDiagram
69
+ 5. If feedback mentions updating a diagram/image/chart → updateDiagram
70
+ 6. If feedback is about general content without diagram references → updateDocument
71
+ 7. When in doubt, prioritize the most explicit action mentioned in the feedback
72
+ </analysis_guidelines>`;
19
73
  const analyzeUpdateFeedbackIntentAgent = AIAgent.from({
20
74
  name: "analyzeUpdateFeedbackIntent",
21
75
  description:
@@ -43,11 +97,12 @@ You are a feedback intent analyzer. Your task is to determine which type of cont
43
97
  return intentType;
44
98
  }
45
99
 
46
- async function saveDoc(input, options, { content }) {
100
+ async function saveDoc(input, options, { content, intentType }) {
47
101
  const saveAgent = options.context?.agents?.["saveDoc"];
48
102
  await options.context.invoke(saveAgent, {
49
103
  ...pick(input, ["path", "docsDir", "labels", "locale"]),
50
104
  content,
105
+ intentType, // Pass intentType so saveDoc can handle translation sync
51
106
  });
52
107
  }
53
108
 
@@ -56,42 +111,70 @@ async function addDiagram(input, options) {
56
111
  const currentContent = contentContext.get();
57
112
  const generateDiagramAgent = options.context.agents["checkGenerateDiagram"];
58
113
  const generateDiagramResult = await options.context.invoke(generateDiagramAgent, {
59
- ...pick(input, ["locale", "path", "diagramming", "feedback"]),
114
+ ...pick(input, ["locale", "path", "docsDir", "diagramming", "feedback"]),
60
115
  documentContent: currentContent,
116
+ originalContent: currentContent,
61
117
  });
62
118
  const content = generateDiagramResult.content;
63
119
  contentContext.set(content);
64
- await saveDoc(input, options, { content });
120
+ // Pass intentType to saveDoc so it can handle translation sync automatically
121
+ await saveDoc(input, options, { content, intentType: "addDiagram" });
65
122
  return { content };
66
123
  }
67
124
 
68
125
  async function updateDiagram(input, options) {
69
126
  const contentContext = userContextAt(options, `currentContents.${input.path}`);
70
127
  const currentContent = contentContext.get();
71
- let [content, previousDiagramContent] = replaceD2WithPlaceholder({
128
+ let [content] = replaceD2WithPlaceholder({
72
129
  content: currentContent,
73
130
  });
74
131
  const generateAgent = options.context?.agents?.["generateDiagram"];
75
- const { diagramSourceCode } = await options.context.invoke(generateAgent, {
132
+ const result = await options.context.invoke(generateAgent, {
76
133
  documentContent: content,
77
134
  locale: input.locale,
78
- previousDiagramContent,
135
+ diagramming: input.diagramming || {},
79
136
  feedback: input.feedback,
137
+ originalContent: currentContent, // Pass original content to find existing diagrams
138
+ path: input.path,
139
+ docsDir: input.docsDir,
80
140
  });
81
- content = replacePlaceholderWithD2({
82
- content,
83
- diagramSourceCode,
84
- });
141
+
142
+ // generateDiagram now returns { content } with image already inserted
143
+ // The image replaces DIAGRAM_PLACEHOLDER or D2 code blocks
144
+ if (result?.content) {
145
+ content = result.content;
146
+ }
147
+
85
148
  contentContext.set(content);
86
- await saveDoc(input, options, { content });
149
+ // Pass intentType to saveDoc so it can handle translation sync automatically
150
+ await saveDoc(input, options, { content, intentType: "updateDiagram" });
87
151
  return { content };
88
152
  }
89
153
 
90
154
  async function deleteDiagram(input, options) {
91
155
  const contentContext = userContextAt(options, `currentContents.${input.path}`);
92
156
  const currentContent = contentContext.get();
93
- const [documentContent] = replaceD2WithPlaceholder({
157
+
158
+ // Extract diagram index from feedback if provided
159
+ // This allows deleting a specific diagram when multiple diagrams exist
160
+ let diagramIndex = input.diagramIndex;
161
+ if (diagramIndex === undefined && input.feedback) {
162
+ // Import extractDiagramIndexFromFeedback from replace-d2-with-image.mjs
163
+ const { extractDiagramIndexFromFeedback } = await import(
164
+ "../../create/replace-d2-with-image.mjs"
165
+ );
166
+ const extractedIndex = extractDiagramIndexFromFeedback(input.feedback);
167
+ if (extractedIndex !== null) {
168
+ diagramIndex = extractedIndex;
169
+ }
170
+ }
171
+
172
+ // Replace all diagrams (D2 code blocks, generated images, Mermaid) with placeholder
173
+ // If diagramIndex is provided, only replace that specific diagram
174
+ // This ensures LLM can identify and remove the diagram regardless of its type
175
+ const documentContent = replaceDiagramsWithPlaceholder({
94
176
  content: currentContent,
177
+ diagramIndex,
95
178
  });
96
179
  const instructions = `<role>
97
180
  Your task is to remove ${DIAGRAM_PLACEHOLDER} and adjust the document context (based on the user's feedback) to make it easier to understand.
@@ -123,8 +206,24 @@ Your task is to remove ${DIAGRAM_PLACEHOLDER} and adjust the document context (b
123
206
  documentContent,
124
207
  feedback: input.feedback,
125
208
  });
209
+
210
+ // Delete associated diagram image files
211
+ if (input.docsDir) {
212
+ try {
213
+ const { deleteDiagramImages } = await import("../../../utils/delete-diagram-images.mjs");
214
+ const { deleted } = await deleteDiagramImages(currentContent, input.path, input.docsDir);
215
+ if (deleted > 0) {
216
+ console.log(`Deleted ${deleted} diagram image file(s) for ${input.path}`);
217
+ }
218
+ } catch (error) {
219
+ // Don't fail the operation if image deletion fails
220
+ console.warn(`Failed to delete diagram images: ${error.message}`);
221
+ }
222
+ }
223
+
126
224
  contentContext.set(content);
127
- await saveDoc(input, options, { content });
225
+ // Pass intentType to saveDoc so it can handle translation sync automatically
226
+ await saveDoc(input, options, { content, intentType: "deleteDiagram" });
128
227
 
129
228
  return { content };
130
229
  }
@@ -149,7 +248,19 @@ async function updateDocument(input, options) {
149
248
  }
150
249
 
151
250
  export default async function updateSingleDocumentDetail(input, options) {
152
- const intentType = await getIntentType(input, options);
251
+ // Use intentType from input if available (analyzed in parent flow),
252
+ // otherwise fall back to analyzing it here (for backward compatibility)
253
+ let intentType = input.intentType;
254
+ if (!intentType && input.feedback) {
255
+ intentType = await getIntentType(input, options);
256
+ }
257
+
258
+ // If intentType is still null or undefined, default to updateDocument
259
+ // This ensures that some operation is always performed, even if intent analysis failed
260
+ // or no explicit intent was provided
261
+ if (!intentType) {
262
+ intentType = "updateDocument";
263
+ }
153
264
 
154
265
  const fnMap = {
155
266
  addDiagram,
@@ -162,5 +273,8 @@ export default async function updateSingleDocumentDetail(input, options) {
162
273
  const result = await fnMap[intentType](input, options);
163
274
  return result;
164
275
  }
165
- return {};
276
+
277
+ // Fallback: if intentType is not in fnMap, default to updateDocument
278
+ console.warn(`Unknown intentType: ${intentType}, defaulting to updateDocument`);
279
+ return await updateDocument(input, options);
166
280
  }
@@ -0,0 +1,136 @@
1
+ import { AIAgent } from "@aigne/core";
2
+ import z from "zod";
3
+
4
+ /**
5
+ * Analyze user feedback to determine the intent type for document updates
6
+ * Returns one of: "addDiagram", "deleteDiagram", "updateDiagram", "updateDocument"
7
+ * Returns null if feedback is empty or invalid
8
+ */
9
+ export default async function analyzeFeedbackIntent({ feedback, shouldUpdateDiagrams }, options) {
10
+ // Check if feedback exists and is not empty
11
+ // If feedback is empty and --diagram flag is set, default to updateDiagram
12
+ // Otherwise return null
13
+ if (!feedback || typeof feedback !== "string" || !feedback.trim()) {
14
+ // If --diagram flag is set, default to updateDiagram (user wants to update diagrams)
15
+ if (shouldUpdateDiagrams) {
16
+ return { intentType: "updateDiagram" };
17
+ }
18
+ return { intentType: null };
19
+ }
20
+
21
+ // Always analyze user feedback first, even if --diagram flag is set
22
+ // This ensures user's explicit intent (e.g., "remove image", "delete diagram") is respected
23
+ // The --diagram flag should only be a hint, not override explicit user commands
24
+
25
+ const instructions = `<role>
26
+ You are a feedback intent analyzer. Your task is to determine which type of content modifications are needed based on the user's feedback.
27
+
28
+ You must analyze the user's feedback and classify it into one of the following intent types:
29
+ - addDiagram: User wants to add a new diagram/image/chart
30
+ - deleteDiagram: User wants to remove/delete a diagram/image/chart
31
+ - updateDiagram: User wants to modify/update an existing diagram/image/chart
32
+ - updateDocument: User wants to update document content (text, sections, etc.) without diagram operations
33
+ </role>
34
+
35
+ <intent_classification_rules>
36
+ **deleteDiagram** - Use this when user explicitly wants to remove or delete a diagram/image/chart:
37
+ - Keywords: remove, delete, 删除, 移除, 去掉, 清除
38
+ - Combined with: diagram, image, picture, chart, graph, 图表, 图片, 图, 架构图
39
+ - Examples:
40
+ - "Remove the diagram"
41
+ - "Delete the image"
42
+ - "删除这张图片"
43
+ - "Remove the second diagram"
44
+ - "去掉架构图"
45
+ - "Remove image from page 3"
46
+ - "Delete the chart showing the flow"
47
+
48
+ **addDiagram** - Use this when user wants to add a new diagram:
49
+ - Keywords: add, create, insert, 添加, 创建, 插入
50
+ - Combined with: diagram, image, picture, chart, graph, 图表, 图片, 图
51
+ - Examples:
52
+ - "Add a diagram showing the architecture"
53
+ - "Create a flow chart"
54
+ - "添加一个架构图"
55
+
56
+ **updateDiagram** - Use this when user wants to modify an existing diagram:
57
+ - Keywords: update, modify, change, improve, 更新, 修改, 改进
58
+ - Combined with: diagram, image, picture, chart, graph, 图表, 图片, 图
59
+ - Examples:
60
+ - "Update the diagram to show the new process"
61
+ - "Modify the chart to include more details"
62
+ - "更新架构图"
63
+
64
+ **updateDocument** - Use this for all other content modifications:
65
+ - Text changes, section updates, content improvements
66
+ - No mention of diagrams/images/charts
67
+ - Examples:
68
+ - "Update the introduction section"
69
+ - "Fix the typo in paragraph 2"
70
+ - "Improve the explanation"
71
+ </intent_classification_rules>
72
+
73
+ <user_feedback>
74
+ {{feedback}}
75
+ </user_feedback>
76
+
77
+ <analysis_guidelines>
78
+ 1. Pay close attention to action verbs (remove, delete, add, update, etc.)
79
+ 2. Identify the target object (diagram, image, chart, or general content)
80
+ 3. If feedback mentions removing/deleting a diagram/image/chart → deleteDiagram
81
+ 4. If feedback mentions adding a diagram/image/chart → addDiagram
82
+ 5. If feedback mentions updating a diagram/image/chart → updateDiagram
83
+ 6. If feedback is about general content without diagram references → updateDocument
84
+ 7. When in doubt, prioritize the most explicit action mentioned in the feedback
85
+ </analysis_guidelines>`;
86
+
87
+ try {
88
+ const analyzeUpdateFeedbackIntentAgent = AIAgent.from({
89
+ name: "analyzeUpdateFeedbackIntent",
90
+ description:
91
+ "Analyze user feedback to determine if document are needed for content modifications",
92
+ task_render_mode: "hide",
93
+ instructions,
94
+ inputSchema: z.object({
95
+ feedback: z.string().describe("User feedback for content modifications"),
96
+ }),
97
+ outputSchema: z.object({
98
+ intentType: z
99
+ .enum(["addDiagram", "deleteDiagram", "updateDiagram", "updateDocument"])
100
+ .describe(
101
+ "The primary type of user intention: one of addDiagram, deleteDiagram, updateDiagram, updateDocument",
102
+ ),
103
+ }),
104
+ });
105
+
106
+ const { intentType } = await options.context.invoke(analyzeUpdateFeedbackIntentAgent, {
107
+ feedback: feedback.trim(),
108
+ });
109
+
110
+ // If --diagram flag is set and user didn't explicitly request delete/add,
111
+ // default to updateDiagram (for backward compatibility)
112
+ // But if user explicitly requested delete/add, respect that intent
113
+ if (
114
+ shouldUpdateDiagrams &&
115
+ intentType &&
116
+ !["deleteDiagram", "addDiagram"].includes(intentType)
117
+ ) {
118
+ return { intentType: "updateDiagram" };
119
+ }
120
+
121
+ return { intentType };
122
+ } catch (error) {
123
+ // If analysis fails and --diagram flag is set, default to updateDiagram
124
+ // Otherwise return null to fall back to default document update flow
125
+ if (shouldUpdateDiagrams) {
126
+ console.warn(
127
+ `Failed to analyze feedback intent, defaulting to updateDiagram due to --diagram flag: ${error.message}`,
128
+ );
129
+ return { intentType: "updateDiagram" };
130
+ }
131
+ console.warn(`Failed to analyze feedback intent: ${error.message}`);
132
+ return { intentType: null };
133
+ }
134
+ }
135
+
136
+ analyzeFeedbackIntent.task_render_mode = "hide";