@aigne/doc-smith 0.8.12-beta.6 → 0.8.12-beta.8

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 (91) hide show
  1. package/.aigne/doc-smith/config.yaml +1 -1
  2. package/.aigne/doc-smith/history.yaml +37 -0
  3. package/.aigne/doc-smith/media-description.yaml +91 -0
  4. package/.aigne/doc-smith/preferences.yml +12 -0
  5. package/.aigne/doc-smith/upload-cache.yaml +36 -69
  6. package/.release-please-manifest.json +1 -1
  7. package/CHANGELOG.md +24 -0
  8. package/agents/clear/choose-contents.mjs +14 -1
  9. package/agents/clear/clear-media-description.mjs +129 -0
  10. package/agents/clear/index.yaml +3 -1
  11. package/agents/evaluate/code-snippet.mjs +28 -24
  12. package/agents/evaluate/document-structure.yaml +0 -4
  13. package/agents/evaluate/document.yaml +1 -5
  14. package/agents/generate/index.yaml +1 -0
  15. package/agents/generate/update-document-structure.yaml +9 -3
  16. package/agents/history/view.mjs +5 -2
  17. package/agents/init/index.mjs +10 -0
  18. package/agents/media/batch-generate-media-description.yaml +44 -0
  19. package/agents/media/generate-media-description.yaml +47 -0
  20. package/agents/media/load-media-description.mjs +238 -0
  21. package/agents/update/generate-document.yaml +10 -4
  22. package/agents/update/index.yaml +1 -0
  23. package/agents/update/update-document-detail.yaml +9 -3
  24. package/agents/update/user-review-document.mjs +2 -1
  25. package/agents/utils/load-sources.mjs +103 -53
  26. package/aigne.yaml +6 -0
  27. package/assets/report-template/report.html +34 -34
  28. package/docs/configuration-initial-setup.md +74 -55
  29. package/docs/configuration.ja.md +59 -86
  30. package/docs/configuration.md +59 -86
  31. package/docs/configuration.zh-TW.md +59 -86
  32. package/docs/configuration.zh.md +59 -86
  33. package/docs/getting-started.ja.md +43 -24
  34. package/docs/getting-started.md +29 -10
  35. package/docs/getting-started.zh-TW.md +42 -23
  36. package/docs/getting-started.zh.md +39 -20
  37. package/docs/guides-cleaning-up.ja.md +16 -15
  38. package/docs/guides-cleaning-up.md +19 -17
  39. package/docs/guides-cleaning-up.zh-TW.md +16 -15
  40. package/docs/guides-cleaning-up.zh.md +12 -11
  41. package/docs/guides-evaluating-documents.md +70 -29
  42. package/docs/guides-generating-documentation.ja.md +34 -32
  43. package/docs/guides-generating-documentation.md +59 -119
  44. package/docs/guides-generating-documentation.zh-TW.md +34 -32
  45. package/docs/guides-generating-documentation.zh.md +30 -28
  46. package/docs/guides-interactive-chat.md +34 -26
  47. package/docs/guides-managing-history.ja.md +17 -20
  48. package/docs/guides-managing-history.md +19 -17
  49. package/docs/guides-managing-history.zh-TW.md +18 -21
  50. package/docs/guides-managing-history.zh.md +13 -16
  51. package/docs/guides-publishing-your-docs.md +40 -35
  52. package/docs/guides-translating-documentation.ja.md +17 -17
  53. package/docs/guides-translating-documentation.md +39 -34
  54. package/docs/guides-translating-documentation.zh-TW.md +21 -21
  55. package/docs/guides-translating-documentation.zh.md +18 -18
  56. package/docs/guides-updating-documentation.ja.md +35 -35
  57. package/docs/guides-updating-documentation.md +11 -9
  58. package/docs/guides-updating-documentation.zh-TW.md +27 -27
  59. package/docs/guides-updating-documentation.zh.md +26 -26
  60. package/docs/overview.ja.md +13 -13
  61. package/docs/overview.md +2 -2
  62. package/docs/overview.zh-TW.md +19 -19
  63. package/docs/overview.zh.md +16 -16
  64. package/docs/release-notes.md +60 -27
  65. package/package.json +2 -1
  66. package/prompts/common/afs/afs-tools-usage.md +5 -0
  67. package/prompts/common/afs/use-afs-instruction.md +1 -0
  68. package/prompts/detail/generate/system-prompt.md +0 -13
  69. package/prompts/detail/generate/user-prompt.md +7 -0
  70. package/prompts/detail/update/system-prompt.md +1 -2
  71. package/prompts/detail/update/user-prompt.md +7 -0
  72. package/prompts/evaluate/document-structure.md +6 -7
  73. package/prompts/evaluate/document.md +16 -25
  74. package/prompts/media/media-description/system-prompt.md +35 -0
  75. package/prompts/media/media-description/user-prompt.md +8 -0
  76. package/prompts/structure/generate/system-prompt.md +0 -19
  77. package/prompts/structure/generate/user-prompt.md +22 -1
  78. package/prompts/structure/update/system-prompt.md +0 -17
  79. package/prompts/structure/update/user-prompt.md +24 -0
  80. package/tests/agents/history/view.test.mjs +97 -0
  81. package/tests/utils/history-utils.test.mjs +125 -97
  82. package/utils/constants/index.mjs +0 -107
  83. package/utils/file-utils.mjs +42 -1
  84. package/utils/history-utils.mjs +3 -3
  85. package/agents/update/fs-tools/glob.mjs +0 -184
  86. package/agents/update/fs-tools/grep.mjs +0 -317
  87. package/agents/update/fs-tools/read-file.mjs +0 -309
  88. package/media.md +0 -19
  89. package/tests/agents/update/fs-tools/glob.test.mjs +0 -438
  90. package/tests/agents/update/fs-tools/grep.test.mjs +0 -279
  91. package/tests/agents/update/fs-tools/read-file.test.mjs +0 -549
@@ -1,184 +0,0 @@
1
- import fs from "node:fs";
2
- import fsPromises from "node:fs/promises";
3
- import path from "node:path";
4
-
5
- /**
6
- * Sorts files by modification time (newest first), then alphabetically
7
- */
8
- function sortFilesByModTime(files, basePath) {
9
- return files
10
- .map((file) => {
11
- const fullPath = path.isAbsolute(file) ? file : path.resolve(basePath, file);
12
- try {
13
- const stats = fs.statSync(fullPath);
14
- return {
15
- path: file,
16
- fullPath,
17
- mtime: stats.mtimeMs || 0,
18
- };
19
- } catch {
20
- return {
21
- path: file,
22
- fullPath,
23
- mtime: 0,
24
- };
25
- }
26
- })
27
- .sort((a, b) => {
28
- // Sort by modification time (newest first), then alphabetically
29
- if (b.mtime !== a.mtime) {
30
- return b.mtime - a.mtime;
31
- }
32
- return a.path.localeCompare(b.path);
33
- })
34
- .map((item) => item.path);
35
- }
36
-
37
- /**
38
- * Filters out common ignore patterns
39
- */
40
- function shouldIgnoreFile(filePath) {
41
- const ignorePatterns = [
42
- "node_modules",
43
- ".git",
44
- ".DS_Store",
45
- ".vscode",
46
- ".idea",
47
- "dist",
48
- "build",
49
- "*.log",
50
- "coverage",
51
- ".nyc_output",
52
- ".cache",
53
- ];
54
-
55
- const normalizedPath = filePath.replace(/\\/g, "/");
56
-
57
- return ignorePatterns.some((pattern) => {
58
- if (pattern.includes("*")) {
59
- // Simple wildcard matching for patterns like "*.log"
60
- const regex = new RegExp(pattern.replace(/\*/g, ".*"));
61
- return regex.test(path.basename(normalizedPath));
62
- } else {
63
- // Directory or file name matching
64
- return (
65
- normalizedPath.includes(`/${pattern}/`) ||
66
- normalizedPath.endsWith(`/${pattern}`) ||
67
- normalizedPath.startsWith(`${pattern}/`) ||
68
- normalizedPath === pattern
69
- );
70
- }
71
- });
72
- }
73
-
74
- export default async function glob({
75
- pattern,
76
- case_sensitive = false,
77
- respect_git_ignore = true,
78
- limit = 100,
79
- }) {
80
- let result = [];
81
- let error = null;
82
- const searchDir = process.cwd();
83
-
84
- try {
85
- // Validate required parameters
86
- if (!pattern || typeof pattern !== "string" || pattern.trim() === "") {
87
- throw new Error("Pattern parameter is required and cannot be empty");
88
- }
89
-
90
- // Use Node.js built-in glob
91
- const globOptions = {
92
- cwd: searchDir,
93
- nodir: true, // Only return files, not directories
94
- dot: true, // Include hidden files
95
- };
96
-
97
- // Note: Node.js fs.glob doesn't support case_sensitive option directly
98
- // We'll handle case sensitivity in post-processing if needed
99
- const iter = fsPromises.glob(pattern, globOptions);
100
- const files = [];
101
-
102
- for await (const file of iter) {
103
- if (files.length >= limit) break;
104
-
105
- // Apply ignore filters
106
- if (shouldIgnoreFile(file)) {
107
- continue;
108
- }
109
-
110
- // Handle case sensitivity if needed
111
- if (case_sensitive === false) {
112
- // Node.js glob is case-sensitive by default on most systems
113
- // For case-insensitive matching, we rely on the pattern itself
114
- // or the filesystem behavior
115
- }
116
-
117
- files.push(file);
118
- }
119
-
120
- // Sort files by modification time (newest first)
121
- const sortedFiles = sortFilesByModTime(files, searchDir);
122
-
123
- // Build result message
124
- let message;
125
- if (sortedFiles.length === 0) {
126
- message = `No files found matching pattern "${pattern}"`;
127
- } else {
128
- const fileCount = sortedFiles.length;
129
- const truncated = files.length >= limit;
130
- message = `Found ${fileCount}${truncated ? "+" : ""} file(s) matching "${pattern}"`;
131
- message += ", sorted by modification time (newest first):";
132
- }
133
-
134
- result = {
135
- files: sortedFiles,
136
- count: sortedFiles.length,
137
- message,
138
- truncated: files.length >= limit,
139
- };
140
- } catch (err) {
141
- error = err;
142
- result = {
143
- files: [],
144
- count: 0,
145
- message: `Error during glob search: ${err.message}`,
146
- truncated: false,
147
- };
148
- }
149
-
150
- return {
151
- command: "glob",
152
- arguments: {
153
- pattern,
154
- case_sensitive,
155
- respect_git_ignore,
156
- limit,
157
- },
158
- result,
159
- error: error && { message: error.message },
160
- };
161
- }
162
-
163
- glob.input_schema = {
164
- type: "object",
165
- properties: {
166
- pattern: {
167
- type: "string",
168
- description: 'The glob pattern to match files against (e.g., "**/*.js", "src/**/*.ts")',
169
- },
170
- case_sensitive: {
171
- type: "boolean",
172
- description: "Optional: Whether the search should be case-sensitive (defaults to false)",
173
- },
174
- respect_git_ignore: {
175
- type: "boolean",
176
- description: "Optional: Whether to respect .gitignore patterns (defaults to true)",
177
- },
178
- limit: {
179
- type: "number",
180
- description: "Optional: Maximum number of files to return (defaults to 100)",
181
- },
182
- },
183
- required: ["pattern"],
184
- };
@@ -1,317 +0,0 @@
1
- import childProcess from "node:child_process";
2
- import fs from "node:fs";
3
- import fsPromises from "node:fs/promises";
4
- import { EOL } from "node:os";
5
- import path from "node:path";
6
-
7
- /**
8
- * Checks if a command is available in the system's PATH
9
- */
10
- function isCommandAvailable(command) {
11
- return new Promise((resolve) => {
12
- const checkCommand = process.platform === "win32" ? "where" : "command";
13
- const checkArgs = process.platform === "win32" ? [command] : ["-v", command];
14
-
15
- try {
16
- const child = childProcess.spawn(checkCommand, checkArgs, {
17
- stdio: "ignore",
18
- shell: process.platform === "win32",
19
- });
20
- child.on("close", (code) => resolve(code === 0));
21
- child.on("error", () => resolve(false));
22
- } catch {
23
- resolve(false);
24
- }
25
- });
26
- }
27
-
28
- /**
29
- * Checks if a directory is a git repository
30
- */
31
- function isGitRepository(dir) {
32
- try {
33
- const gitDir = path.join(dir, ".git");
34
- return fs.existsSync(gitDir);
35
- } catch {
36
- return false;
37
- }
38
- }
39
-
40
- /**
41
- * Parses grep output in format: filePath:lineNumber:lineContent
42
- */
43
- function parseGrepOutput(output, basePath) {
44
- const results = [];
45
- if (!output) return results;
46
-
47
- const lines = output.split(EOL);
48
-
49
- for (const line of lines) {
50
- if (!line.trim()) continue;
51
-
52
- const firstColonIndex = line.indexOf(":");
53
- if (firstColonIndex === -1) continue;
54
-
55
- const secondColonIndex = line.indexOf(":", firstColonIndex + 1);
56
- if (secondColonIndex === -1) continue;
57
-
58
- const filePathRaw = line.substring(0, firstColonIndex);
59
- const lineNumberStr = line.substring(firstColonIndex + 1, secondColonIndex);
60
- const lineContent = line.substring(secondColonIndex + 1);
61
-
62
- const lineNumber = parseInt(lineNumberStr, 10);
63
- if (!Number.isNaN(lineNumber)) {
64
- const relativePath = path.relative(basePath, path.resolve(basePath, filePathRaw));
65
- results.push({
66
- filePath: relativePath || path.basename(filePathRaw),
67
- lineNumber,
68
- line: lineContent,
69
- });
70
- }
71
- }
72
- return results;
73
- }
74
-
75
- /**
76
- * Performs grep search using multiple strategies
77
- */
78
- async function performGrepSearch({ pattern, include }) {
79
- const absolutePath = path.resolve(".");
80
-
81
- // Strategy 1: git grep
82
- const isGit = isGitRepository(absolutePath);
83
- const gitAvailable = isGit && (await isCommandAvailable("git"));
84
-
85
- if (gitAvailable) {
86
- try {
87
- const gitArgs = ["grep", "--untracked", "-n", "-E", "--ignore-case", pattern];
88
- if (include) {
89
- gitArgs.push("--", include);
90
- }
91
-
92
- const output = await new Promise((resolve, reject) => {
93
- const child = childProcess.spawn("git", gitArgs, {
94
- cwd: absolutePath,
95
- windowsHide: true,
96
- });
97
-
98
- let stdout = "";
99
- let stderr = "";
100
-
101
- child.stdout.on("data", (chunk) => {
102
- stdout += chunk;
103
- });
104
- child.stderr.on("data", (chunk) => {
105
- stderr += chunk;
106
- });
107
- child.on("error", (err) => reject(new Error(`Failed to start git grep: ${err.message}`)));
108
- child.on("close", (code) => {
109
- if (code === 0) resolve(stdout);
110
- else if (code === 1)
111
- resolve(""); // No matches
112
- else reject(new Error(`git grep exited with code ${code}: ${stderr}`));
113
- });
114
- });
115
-
116
- return parseGrepOutput(output, absolutePath);
117
- } catch (gitError) {
118
- console.debug(`git grep failed: ${gitError.message}. Falling back...`);
119
- }
120
- }
121
-
122
- // Strategy 2: System grep
123
- const grepAvailable = await isCommandAvailable("grep");
124
- if (grepAvailable) {
125
- try {
126
- const grepArgs = [
127
- "-r",
128
- "-n",
129
- "-H",
130
- "-E",
131
- "-i",
132
- "--exclude-dir=node_modules",
133
- "--exclude-dir=.git",
134
- ];
135
- if (include) {
136
- grepArgs.push(`--include=${include}`);
137
- }
138
- grepArgs.push(pattern, ".");
139
-
140
- const output = await new Promise((resolve, reject) => {
141
- const child = childProcess.spawn("grep", grepArgs, {
142
- cwd: absolutePath,
143
- windowsHide: true,
144
- });
145
-
146
- let stdout = "";
147
- let stderr = "";
148
-
149
- child.stdout.on("data", (chunk) => {
150
- stdout += chunk;
151
- });
152
- child.stderr.on("data", (chunk) => {
153
- const stderrStr = chunk.toString();
154
- // Suppress common harmless stderr messages
155
- if (
156
- !stderrStr.includes("Permission denied") &&
157
- !/grep:.*: Is a directory/i.test(stderrStr)
158
- ) {
159
- stderr += chunk;
160
- }
161
- });
162
- child.on("error", (err) =>
163
- reject(new Error(`Failed to start system grep: ${err.message}`)),
164
- );
165
- child.on("close", (code) => {
166
- if (code === 0) resolve(stdout);
167
- else if (code === 1)
168
- resolve(""); // No matches
169
- else {
170
- if (stderr.trim()) reject(new Error(`System grep exited with code ${code}: ${stderr}`));
171
- else resolve(""); // Exit code > 1 but no stderr, likely just suppressed errors
172
- }
173
- });
174
- });
175
-
176
- return parseGrepOutput(output, absolutePath);
177
- } catch (grepError) {
178
- console.debug(`System grep failed: ${grepError.message}. Falling back...`);
179
- }
180
- }
181
-
182
- // Strategy 3: JavaScript fallback
183
- console.debug("Falling back to JavaScript grep implementation.");
184
- const matches = [];
185
-
186
- // Escape regex special characters in a string
187
- function escapeRegExp(str) {
188
- return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
189
- }
190
-
191
- try {
192
- const regex = new RegExp(pattern, "i");
193
-
194
- async function searchDirectory(dir) {
195
- const entries = await fsPromises.readdir(dir, { withFileTypes: true });
196
-
197
- for (const entry of entries) {
198
- if (entry.name.startsWith(".") && entry.name !== ".") continue;
199
- if (entry.name === "node_modules") continue;
200
-
201
- const fullPath = path.join(dir, entry.name);
202
-
203
- if (entry.isDirectory()) {
204
- await searchDirectory(fullPath);
205
- } else if (entry.isFile()) {
206
- // Apply include filter if specified
207
- if (include) {
208
- let patternStr = escapeRegExp(include);
209
- patternStr = patternStr.replace(/\\\*/g, ".*").replace(/\\\?/g, ".");
210
- const includePattern = `^${patternStr}$`;
211
- if (!new RegExp(includePattern).test(entry.name)) {
212
- continue;
213
- }
214
- }
215
-
216
- try {
217
- const content = await fsPromises.readFile(fullPath, "utf8");
218
- const lines = content.split(/\r?\n/);
219
-
220
- lines.forEach((line, index) => {
221
- if (regex.test(line)) {
222
- matches.push({
223
- filePath: path.relative(absolutePath, fullPath),
224
- lineNumber: index + 1,
225
- line,
226
- });
227
- }
228
- });
229
- } catch (_readError) {
230
- // Ignore read errors (binary files, permissions, etc.)
231
- }
232
- }
233
- }
234
- }
235
-
236
- await searchDirectory(absolutePath);
237
- return matches;
238
- } catch (error) {
239
- throw new Error(`JavaScript fallback failed: ${error.message}`);
240
- }
241
- }
242
-
243
- export default async function grep({ pattern, include }) {
244
- let result = "";
245
- let error = null;
246
-
247
- try {
248
- // Validate pattern parameter (allow empty string but not undefined/null)
249
- if (pattern === undefined || pattern === null) {
250
- throw new Error("Pattern parameter is required");
251
- }
252
-
253
- // Validate regex pattern
254
- try {
255
- new RegExp(pattern);
256
- } catch (regexError) {
257
- throw new Error(`Invalid regular expression pattern: ${pattern}. ${regexError.message}`);
258
- }
259
-
260
- const matches = await performGrepSearch({ pattern, include });
261
-
262
- if (matches.length === 0) {
263
- result = `No matches found for pattern "${pattern}"${include ? ` (filter: "${include}")` : ""}.`;
264
- } else {
265
- // Group matches by file
266
- const matchesByFile = matches.reduce((acc, match) => {
267
- if (!acc[match.filePath]) {
268
- acc[match.filePath] = [];
269
- }
270
- acc[match.filePath].push(match);
271
- acc[match.filePath].sort((a, b) => a.lineNumber - b.lineNumber);
272
- return acc;
273
- }, {});
274
-
275
- const matchCount = matches.length;
276
- const matchTerm = matchCount === 1 ? "match" : "matches";
277
-
278
- result = `Found ${matchCount} ${matchTerm} for pattern "${pattern}"${include ? ` (filter: "${include}")` : ""}:\n---\n`;
279
-
280
- for (const filePath in matchesByFile) {
281
- result += `File: ${filePath}\n`;
282
- matchesByFile[filePath].forEach((match) => {
283
- const trimmedLine = match.line.trim();
284
- result += `L${match.lineNumber}: ${trimmedLine}\n`;
285
- });
286
- result += "---\n";
287
- }
288
-
289
- result = result.trim();
290
- }
291
- } catch (e) {
292
- error = e;
293
- result = `Error during grep search: ${e.message}`;
294
- }
295
-
296
- return {
297
- command: "grep",
298
- arguments: { pattern, include },
299
- result,
300
- error: error && { message: error.message },
301
- };
302
- }
303
-
304
- grep.input_schema = {
305
- type: "object",
306
- properties: {
307
- pattern: {
308
- type: "string",
309
- description: "The regular expression pattern to search for in file contents",
310
- },
311
- include: {
312
- type: "string",
313
- description: 'Optional: File pattern to include in search (e.g. "*.js", "*.{ts,tsx}")',
314
- },
315
- },
316
- required: ["pattern"],
317
- };