@aigne/doc-smith 0.8.15-beta.9 → 0.8.16-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 (72) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/agents/chat/chat-system.md +32 -0
  3. package/agents/chat/index.yaml +14 -22
  4. package/agents/chat/skills/generate-document.yaml +15 -0
  5. package/agents/chat/skills/update-document.yaml +24 -0
  6. package/agents/evaluate/document-structure.yaml +3 -1
  7. package/agents/evaluate/document.yaml +3 -1
  8. package/agents/generate/check-need-generate-structure.mjs +4 -0
  9. package/agents/generate/document-structure-tools/add-document.mjs +5 -1
  10. package/agents/generate/document-structure-tools/update-document.mjs +7 -0
  11. package/agents/generate/generate-structure.yaml +1 -5
  12. package/agents/generate/merge-diagram.yaml +4 -4
  13. package/agents/generate/update-document-structure.yaml +51 -45
  14. package/agents/generate/user-review-document-structure.mjs +47 -55
  15. package/agents/generate/utils/merge-document-structures.mjs +4 -4
  16. package/agents/init/check.mjs +1 -1
  17. package/agents/init/index.mjs +52 -2
  18. package/agents/init/validate.mjs +16 -0
  19. package/agents/publish/publish-docs.mjs +16 -10
  20. package/agents/schema/document-execution-structure.yaml +1 -1
  21. package/agents/schema/document-structure-item.yaml +1 -1
  22. package/agents/schema/document-structure.yaml +4 -2
  23. package/agents/update/check-generate-diagram.mjs +74 -16
  24. package/agents/update/generate-document.yaml +1 -13
  25. package/agents/update/handle-document-update.yaml +1 -1
  26. package/agents/update/pre-check-generate-diagram.yaml +44 -0
  27. package/agents/update/update-document-detail.yaml +64 -58
  28. package/agents/update/update-single-document.yaml +1 -1
  29. package/agents/update/user-review-document.mjs +58 -43
  30. package/agents/utils/analyze-feedback-intent.yaml +29 -0
  31. package/agents/utils/choose-docs.mjs +16 -6
  32. package/agents/utils/document-title-streamline.yaml +48 -0
  33. package/agents/utils/find-item-by-path.mjs +4 -2
  34. package/agents/utils/list-docs.mjs +15 -0
  35. package/agents/utils/load-sources.mjs +4 -4
  36. package/agents/utils/map-reasoning-effort-level.mjs +15 -0
  37. package/agents/utils/save-sidebar.mjs +12 -33
  38. package/agents/utils/streamline-document-titles-if-needed.mjs +88 -0
  39. package/agents/utils/{transform-detail-datasources.mjs → transform-detail-data-sources.mjs} +2 -2
  40. package/aigne.yaml +12 -4
  41. package/package.json +11 -9
  42. package/prompts/common/document/content-rules-core.md +5 -5
  43. package/prompts/common/document-structure/conflict-resolution-guidance.md +2 -2
  44. package/prompts/common/document-structure/document-structure-rules.md +8 -8
  45. package/prompts/common/document-structure/document-title-streamline.md +86 -0
  46. package/prompts/common/document-structure/output-constraints.md +3 -3
  47. package/prompts/detail/custom/custom-code-block.md +36 -1
  48. package/prompts/detail/custom/{custom-components.md → custom-components-usage-rules.md} +29 -7
  49. package/prompts/detail/d2-diagram/pre-check.md +23 -0
  50. package/prompts/detail/d2-diagram/rules.md +42 -24
  51. package/prompts/detail/d2-diagram/user-prompt.md +0 -20
  52. package/prompts/detail/generate/document-rules.md +2 -2
  53. package/prompts/detail/generate/system-prompt.md +3 -3
  54. package/prompts/detail/generate/user-prompt.md +5 -5
  55. package/prompts/detail/update/system-prompt.md +4 -3
  56. package/prompts/detail/update/user-prompt.md +8 -4
  57. package/prompts/evaluate/document.md +0 -4
  58. package/prompts/structure/check-document-structure.md +4 -4
  59. package/prompts/structure/generate/system-prompt.md +0 -1
  60. package/prompts/structure/generate/user-prompt.md +14 -9
  61. package/prompts/structure/review/structure-review-system.md +5 -2
  62. package/prompts/structure/update/system-prompt.md +0 -13
  63. package/prompts/structure/update/user-prompt.md +6 -5
  64. package/prompts/translate/translate-document.md +3 -3
  65. package/prompts/utils/analyze-feedback-intent.md +55 -0
  66. package/utils/constants/index.mjs +38 -0
  67. package/utils/deploy.mjs +3 -1
  68. package/utils/docs-finder-utils.mjs +37 -3
  69. package/utils/file-utils.mjs +97 -0
  70. package/utils/load-config.mjs +19 -0
  71. package/agents/utils/docs-fs-actor.yaml +0 -27
  72. package/agents/utils/fs.mjs +0 -60
@@ -90,17 +90,4 @@ Analyze the user feedback to determine the intended operation:
90
90
  </operation_output_constraints>
91
91
  </operation_execution_rules>
92
92
 
93
- <file_tool_usage>
94
- 1. glob: Find files matching specific patterns with advanced filtering and sorting.
95
-
96
- 2. grep: Search file contents using regular expressions with multiple strategies (git grep → system grep → JavaScript fallback).
97
-
98
- 3. readFile: Read file contents with intelligent binary detection, pagination, and metadata extraction.
99
-
100
- When to use Tools:
101
- - During document structure update, if the given context is missing or lacks referenced content, use glob/grep/readFile to obtain more context
102
- - When sourceIds or file content from <file_list> is needed but not provided in DataSources, use readFile to read the file content
103
- </file_tool_usage>
104
-
105
-
106
93
  {% include "../../common/document-structure/output-constraints.md" %}
@@ -6,10 +6,11 @@
6
6
  {{allFilesPaths}}
7
7
  </file_list>
8
8
 
9
- <datasources>
10
- {{ datasources }}
11
- </datasources>
12
-
9
+ {% if needDataSources %}
10
+ <data_sources>
11
+ {{ dataSourceChunk }}
12
+ </data_sources>
13
+ {% endif %}
13
14
 
14
15
  Initial Documentation Structure:
15
16
  <initial_document_structure>
@@ -38,5 +39,5 @@ Processing workflow:
38
39
 
39
40
  Rules:
40
41
  ** All changes must be made using Tools. **
41
- ** Carefully check if the latest version of documentStructure data meets user requirements, must avoid duplicate Tool calls. **
42
+ ** Carefully check if the latest version of `<document_structure>` data meets user requirements, must avoid duplicate Tool calls. **
42
43
  </instructions>
@@ -5,10 +5,10 @@ You are an **Elite Polyglot Localization and Translation Specialist** with exten
5
5
  Core Mandates:
6
6
 
7
7
  1. Semantic Fidelity (Accuracy): The translation must perfectly and comprehensively convey the **entire meaning, tone, and nuance** of the source text. **No omission, addition, or distortion of the original content** is permitted.
8
- 2. Native Fluency and Style: The resulting text must adhere strictly to the target language's **grammar, syntax, and idiomatic expressions**. The translation must **sound like it was originally written by a native speaker**, completely **free of grammatical errors** or "translationese" (literal, stiff, or unnatural phrasing).
8
+ 2. Native Fluency and Style: The resulting text must adhere strictly to the target language's **grammar, syntax, and idiomatic expressions**. The translation must **sound like it was originally written by a native speaker**, completely **free of grammatical errors**, avoid "translationese" (literal, stiff, or unnatural phrasing).
9
9
  3. Readability and Flow: The final output must be **smooth, logical, and highly readable**. Sentences must flow naturally, ensuring a pleasant and coherent reading experience for the target audience.
10
10
  4. Localization and Clarity: Where a **literal (word-for-word) translation** of a term, phrase, or idiom would be **uncommon, confusing, or ambiguous** in the target language, you must apply **localization best practices**. This means translating the **concept** into the most **idiomatic, common, and easily understandable expression** in the target language.
11
- 5. Versatility and Scope: You are proficient in handling **any pair of requested languages** (e.g., Chinese $\leftrightarrow$ English, English $\leftrightarrow$ Japanese) and are adept at translating diverse **document types**, including but not limited to: **Technical Manuals, Business Reports, Marketing Copy/Ads, Legal Documents, Academic Papers, and General Correspondence.**
11
+ 5. Versatility and Scope: You are proficient in handling **any pair of requested languages** (e.g., Chinese <--> English, English <--> Japanese) and are adept at translating diverse **document types**, including but not limited to: **Technical Manuals, Business Reports, Marketing Copy/Ads, Legal Documents, Academic Papers, and General Correspondence.**
12
12
 
13
13
  </role_and_goal>
14
14
 
@@ -299,5 +299,5 @@ Original text as follows:
299
299
  </content>
300
300
 
301
301
  <output_constraints>
302
- Please **accurately** translate the content within <content> tags (excluding the outermost <content> tags) into **{{ language }}**, strictly following the translation requirements.
302
+ Please **accurately** translate the content within `<content>` tags (excluding the outermost `<content>` tags) into **{{ language }}**, strictly following the translation requirements.
303
303
  </output_constraints>
@@ -0,0 +1,55 @@
1
+ <role>
2
+ You are a feedback intent analyzer. Your task is to determine whether data sources are needed to fulfill the user's feedback about content modifications.
3
+ </role>
4
+
5
+ <input>
6
+ - feedback: {{feedback}}
7
+ </input>
8
+
9
+ <analysis_rules>
10
+ **Determining Data Source Necessity:**
11
+
12
+ You need to analyze the user's feedback and categorize it into different intent types. Based on the intent type, determine if data sources are required.
13
+
14
+ This analyzer is generic and can be used for any content modification scenarios (documentation structure, document content, translations, etc.).
15
+
16
+ **Intent Types:**
17
+
18
+ 1. **add** - Adding new items, sections, or content
19
+ - Requires data sources: **YES**
20
+ - Reason: Need sufficient context from codebase or related materials to generate accurate new content
21
+
22
+ 2. **edit** - Modifying existing content, descriptions, titles, or properties
23
+ - Requires data sources: **YES**
24
+ - Reason: Need context to ensure modifications are accurate and contextually appropriate
25
+
26
+ 3. **delete** - Removing items, sections, or content
27
+ - Requires data sources: **NO**
28
+ - Reason: Deletion only needs to identify what to remove, no new content generation needed
29
+
30
+ 4. **move** - Moving items to different positions or parent sections
31
+ - Requires data sources: **NO**
32
+ - Reason: Only changing item location in the structure, no content changes needed
33
+
34
+ 5. **reorder** - Changing the order of items at the same level
35
+ - Requires data sources: **NO**
36
+ - Reason: Only rearranging sequence, no content generation needed
37
+
38
+ 6. **mixed** - Combination of multiple intent types
39
+ - Requires data sources: **Depends on whether add/edit operations are included**
40
+ - Reason: If the feedback includes any add or edit operations, data sources are needed
41
+
42
+ **Decision Logic:**
43
+ - If the feedback contains ANY add or edit operations → `needDataSources = true`
44
+ - If the feedback ONLY contains delete, move, or reorder operations → `needDataSources = false`
45
+ - When in doubt, default to `needDataSources = true` to ensure sufficient context
46
+ </analysis_rules>
47
+
48
+ <output_rules>
49
+ Return a JSON object with:
50
+ - `needDataSources`: boolean indicating if data sources are required
51
+ - `intentType`: the primary intent type (add, edit, delete, move, reorder, or mixed)
52
+ - `reason`: clear explanation of why data sources are or aren't needed
53
+
54
+ Analyze the feedback carefully and be conservative - when uncertain, prefer `needDataSources: true` to ensure sufficient context is available.
55
+ </output_rules>
@@ -549,3 +549,41 @@ export const DOC_SMITH_DIR = ".aigne/doc-smith";
549
549
  export const TMP_DIR = ".tmp";
550
550
  export const TMP_DOCS_DIR = "docs";
551
551
  export const TMP_ASSETS_DIR = "assets";
552
+
553
+ export const DOC_ACTION = {
554
+ translate: "translate",
555
+ update: "update",
556
+ clear: "clear",
557
+ };
558
+
559
+ // Default thinking effort level, available options: 'lite', 'standard', 'pro'
560
+ // This level can be defined by the user in the config file to influence reasoning effort mapping
561
+ export const DEFAULT_THINKING_EFFORT_LEVEL = "standard";
562
+
563
+ // Default reasoning effort level, available options: 'minimal', 'low', 'medium', 'high'
564
+ export const DEFAULT_REASONING_EFFORT_LEVEL = "low";
565
+
566
+ export const DEFAULT_REASONING_EFFORT_VALUE = 500;
567
+
568
+ export const REASONING_EFFORT_LEVELS = {
569
+ minimal: {
570
+ lite: 100,
571
+ standard: 300,
572
+ pro: 500,
573
+ },
574
+ low: {
575
+ lite: 200,
576
+ standard: 500,
577
+ pro: 1000,
578
+ },
579
+ medium: {
580
+ lite: 300,
581
+ standard: 800,
582
+ pro: 1500,
583
+ },
584
+ high: {
585
+ lite: 500,
586
+ standard: 1000,
587
+ pro: 2000,
588
+ },
589
+ };
package/utils/deploy.mjs CHANGED
@@ -31,6 +31,7 @@ export async function deploy(id, cachedUrl) {
31
31
  const result = await client.deploy({
32
32
  cachedCheckoutId: id,
33
33
  cachedPaymentUrl: cachedUrl,
34
+ needShortUrl: true,
34
35
  pageInfo: { successMessage: SUCCESS_MESSAGE },
35
36
  hooks: {
36
37
  [STEPS.PAYMENT_PENDING]: async ({ sessionId, paymentUrl, isResuming }) => {
@@ -71,7 +72,7 @@ export async function deploy(id, cachedUrl) {
71
72
  },
72
73
  });
73
74
 
74
- const { appUrl, homeUrl, subscriptionUrl, dashboardUrl, vendors } = result;
75
+ const { appUrl, homeUrl, subscriptionUrl, dashboardUrl, vendors, sessionId } = result;
75
76
  const token = vendors?.[0]?.token;
76
77
 
77
78
  return {
@@ -80,5 +81,6 @@ export async function deploy(id, cachedUrl) {
80
81
  dashboardUrl,
81
82
  subscriptionUrl,
82
83
  token,
84
+ sessionId,
83
85
  };
84
86
  }
@@ -4,12 +4,11 @@ import { pathExists } from "./file-utils.mjs";
4
4
 
5
5
  /**
6
6
  * Get action-specific text based on isTranslate flag
7
- * @param {boolean} isTranslate - Whether this is a translation action
8
7
  * @param {string} baseText - Base text template with {action} placeholder
8
+ * @param {string} action - doc action type
9
9
  * @returns {string} Text with action replaced
10
10
  */
11
- export function getActionText(isTranslate, baseText) {
12
- const action = isTranslate ? "translate" : "update";
11
+ export function getActionText(baseText, action) {
13
12
  return baseText.replace("{action}", action);
14
13
  }
15
14
 
@@ -324,3 +323,38 @@ export async function loadDocumentStructure(outputDir) {
324
323
  return null;
325
324
  }
326
325
  }
326
+
327
+ /**
328
+ * Build a tree structure from a flat document structure array using parentId
329
+ * @param {Array} documentStructure - Flat array of document structure items with path and parentId
330
+ * @returns {Object} Object containing rootNodes (array of root nodes) and nodeMap (Map for lookups)
331
+ */
332
+ export function buildDocumentTree(documentStructure) {
333
+ // Create a map of nodes for easy lookup
334
+ const nodeMap = new Map();
335
+ const rootNodes = [];
336
+
337
+ // First pass: create node map
338
+ documentStructure.forEach((node) => {
339
+ nodeMap.set(node.path, {
340
+ ...node,
341
+ children: [],
342
+ });
343
+ });
344
+
345
+ // Build the tree structure using parentId
346
+ documentStructure.forEach((node) => {
347
+ if (node.parentId) {
348
+ const parent = nodeMap.get(node.parentId);
349
+ if (parent) {
350
+ parent.children.push(nodeMap.get(node.path));
351
+ } else {
352
+ rootNodes.push(nodeMap.get(node.path));
353
+ }
354
+ } else {
355
+ rootNodes.push(nodeMap.get(node.path));
356
+ }
357
+ });
358
+
359
+ return { rootNodes, nodeMap };
360
+ }
@@ -13,6 +13,7 @@ import { debug } from "./debug.mjs";
13
13
  import { isGlobPattern } from "./utils.mjs";
14
14
  import { uploadFiles } from "./upload-files.mjs";
15
15
  import { extractApi } from "./extract-api.mjs";
16
+ import { minimatch } from "minimatch";
16
17
 
17
18
  /**
18
19
  * Check if a directory is inside a git repository using git command
@@ -859,3 +860,99 @@ export async function downloadAndUploadImage(imageUrl, docsDir, appUrl, accessTo
859
860
  return { url: imageUrl, downloadFinalPath: null };
860
861
  }
861
862
  }
863
+
864
+ /**
865
+ * Extract the path prefix from a glob pattern until the first glob character
866
+ */
867
+ export function getPathPrefix(pattern) {
868
+ const segments = pattern.split("/");
869
+ const result = [];
870
+
871
+ for (const segment of segments) {
872
+ if (isGlobPattern(segment)) {
873
+ break;
874
+ }
875
+ result.push(segment);
876
+ }
877
+
878
+ return result.join("/") || ".";
879
+ }
880
+
881
+ /**
882
+ * Check if a dir matches any exclude pattern
883
+ */
884
+ export function isDirExcluded(dir, excludePatterns) {
885
+ if (!dir || typeof dir !== "string") {
886
+ return false;
887
+ }
888
+
889
+ let normalizedDir = dir.replace(/\\/g, "/").replace(/^\.\/+/, "");
890
+ normalizedDir = normalizedDir.endsWith("/") ? normalizedDir : `${normalizedDir}/`;
891
+
892
+ for (const excludePattern of excludePatterns) {
893
+ if (minimatch(normalizedDir, excludePattern, { dot: true })) {
894
+ return true;
895
+ }
896
+ }
897
+
898
+ return false;
899
+ }
900
+
901
+ /**
902
+ * Return source paths that would be excluded by exclude patterns (files are skipped, directories use minimatch, glob patterns use path prefix heuristic)
903
+ */
904
+ export async function findInvalidSourcePaths(sourcePaths, excludePatterns) {
905
+ if (!Array.isArray(sourcePaths) || sourcePaths.length === 0) {
906
+ return [];
907
+ }
908
+
909
+ if (!Array.isArray(excludePatterns) || excludePatterns.length === 0) {
910
+ return [];
911
+ }
912
+
913
+ const invalidPaths = [];
914
+
915
+ for (const sourcePath of sourcePaths) {
916
+ if (typeof sourcePath !== "string" || !sourcePath) {
917
+ continue;
918
+ }
919
+
920
+ // Skip paths starting with "!" (exclusion patterns)
921
+ if (sourcePath.startsWith("!")) {
922
+ continue;
923
+ }
924
+
925
+ // Skip remote URLs
926
+ if (isRemoteFile(sourcePath)) {
927
+ continue;
928
+ }
929
+
930
+ // Check glob pattern: use heuristic algorithm
931
+ if (isGlobPattern(sourcePath)) {
932
+ const representativePath = getPathPrefix(sourcePath);
933
+ if (isDirExcluded(representativePath, excludePatterns)) {
934
+ invalidPaths.push(sourcePath);
935
+ }
936
+ continue;
937
+ }
938
+
939
+ try {
940
+ const stats = await stat(sourcePath);
941
+ // Skip file
942
+ if (stats.isFile()) {
943
+ continue;
944
+ }
945
+ // Check dir with minimatch
946
+ if (stats.isDirectory()) {
947
+ if (isDirExcluded(sourcePath, excludePatterns)) {
948
+ invalidPaths.push(sourcePath);
949
+ }
950
+ }
951
+ } catch {
952
+ // Path doesn't exist
953
+ invalidPaths.push(sourcePath);
954
+ }
955
+ }
956
+
957
+ return invalidPaths;
958
+ }
@@ -1,7 +1,10 @@
1
1
  import fs from "node:fs/promises";
2
+ import chalk from "chalk";
2
3
  import path from "node:path";
3
4
  import { parse } from "yaml";
4
5
  import { processConfigFields, resolveFileReferences } from "./utils.mjs";
6
+ import { DEFAULT_EXCLUDE_PATTERNS } from "./constants/index.mjs";
7
+ import { findInvalidSourcePaths, toDisplayPath } from "./file-utils.mjs";
5
8
 
6
9
  export default async function loadConfig({ config, appUrl }) {
7
10
  const configPath = path.isAbsolute(config) ? config : path.join(process.cwd(), config);
@@ -30,6 +33,22 @@ export default async function loadConfig({ config, appUrl }) {
30
33
  // Parse new configuration fields and convert keys to actual content
31
34
  const processedConfig = await processConfigFields(parsedConfig);
32
35
 
36
+ // Validate sourcePaths against exclude patterns
37
+ const sourcesPath = processedConfig.sourcesPath || parsedConfig.sourcesPath;
38
+ if (sourcesPath) {
39
+ const excludePatterns = [
40
+ ...DEFAULT_EXCLUDE_PATTERNS,
41
+ ...(processedConfig.excludePatterns || parsedConfig.excludePatterns || []),
42
+ ];
43
+
44
+ const invalidPaths = await findInvalidSourcePaths(sourcesPath, excludePatterns);
45
+ if (invalidPaths.length > 0) {
46
+ console.warn(
47
+ `⚠️ Some source paths have been excluded and will not be processed:\n${invalidPaths.map((p) => ` - ${chalk.yellow(p)}`).join("\n")}\n💡 Tip: You can remove these paths in ${toDisplayPath(configPath)}\n`,
48
+ );
49
+ }
50
+ }
51
+
33
52
  return {
34
53
  lastGitHead: parsedConfig.lastGitHead || "",
35
54
  ...parsedConfig,
@@ -1,27 +0,0 @@
1
- type: team
2
- name: docs_fs_actor
3
- description: File system operations for documentation management
4
- skills:
5
- - url: ../init/index.mjs
6
- default_input:
7
- skipIfExists: true
8
- - url: ./fs.mjs
9
- default_input:
10
- rootDir:
11
- $get: docsDir
12
- input_schema:
13
- type: object
14
- properties:
15
- action:
16
- type: "string"
17
- enum: ["read_file", "write_file", "delete_file", "list_directory"]
18
- description:
19
- "The file system action to perform, available actions are: read_file, write_file, delete_file, list_directory"
20
- path:
21
- type: "string"
22
- description: "The path to the file or directory to operate on"
23
- content:
24
- type: "string"
25
- description: "The content to write to the file, required for write_file action"
26
- required: ["action", "path"]
27
- task_render_mode: hide
@@ -1,60 +0,0 @@
1
- import { mkdir, readdir, readFile, rm, writeFile } from "node:fs/promises";
2
- import { dirname, join } from "node:path";
3
-
4
- export default async function fs({ rootDir, action, path, content }) {
5
- if (!rootDir) throw new Error("Root directory is not specified");
6
-
7
- path = join(rootDir, path);
8
-
9
- switch (action) {
10
- case "read_file":
11
- return {
12
- status: "ok",
13
- path,
14
- content: await readFile(path, "utf-8"),
15
- };
16
- case "write_file": {
17
- await mkdir(dirname(path), { recursive: true });
18
- await writeFile(path, content || "");
19
- return {
20
- status: "ok",
21
- path,
22
- content,
23
- };
24
- }
25
- case "delete_file":
26
- await rm(path, { recursive: true, force: true });
27
- return {
28
- status: "ok",
29
- path,
30
- };
31
- case "list_directory":
32
- return {
33
- status: "ok",
34
- entries: await readdir(path, { withFileTypes: true }).then((list) =>
35
- list.map((entry) => ({
36
- path: join(entry.parentPath, entry.name),
37
- isDirectory: entry.isDirectory(),
38
- })),
39
- ),
40
- };
41
- }
42
- }
43
-
44
- fs.input_schema = {
45
- type: "object",
46
- properties: {
47
- action: {
48
- type: "string",
49
- enum: ["read_file", "write_file", "delete_file", "list_directory"],
50
- description:
51
- "The file system action to perform, available actions are: read_file, write_file, delete_file, list_directory",
52
- },
53
- path: { type: "string", description: "The path to the file or directory to operate on" },
54
- content: {
55
- type: "string",
56
- description: "The content to write to the file, required for write_file action",
57
- },
58
- },
59
- required: ["action", "path"],
60
- };