@aigne/doc-smith 0.8.12-beta.5 → 0.8.12-beta.7

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 (58) hide show
  1. package/.aigne/doc-smith/history.yaml +37 -0
  2. package/.aigne/doc-smith/preferences.yml +12 -0
  3. package/.aigne/doc-smith/upload-cache.yaml +30 -0
  4. package/.release-please-manifest.json +1 -1
  5. package/CHANGELOG.md +19 -0
  6. package/agents/generate/update-document-structure.yaml +9 -3
  7. package/agents/history/view.mjs +5 -2
  8. package/agents/publish/publish-docs.mjs +12 -10
  9. package/agents/update/generate-document.yaml +10 -4
  10. package/agents/update/update-document-detail.yaml +9 -3
  11. package/agents/update/user-review-document.mjs +2 -1
  12. package/docs/guides-cleaning-up.ja.md +16 -15
  13. package/docs/guides-cleaning-up.md +5 -4
  14. package/docs/guides-cleaning-up.zh-TW.md +16 -15
  15. package/docs/guides-cleaning-up.zh.md +12 -11
  16. package/docs/guides-generating-documentation.ja.md +34 -32
  17. package/docs/guides-generating-documentation.md +15 -13
  18. package/docs/guides-generating-documentation.zh-TW.md +34 -32
  19. package/docs/guides-generating-documentation.zh.md +30 -28
  20. package/docs/guides-managing-history.ja.md +17 -20
  21. package/docs/guides-managing-history.md +5 -8
  22. package/docs/guides-managing-history.zh-TW.md +18 -21
  23. package/docs/guides-managing-history.zh.md +13 -16
  24. package/docs/guides-translating-documentation.ja.md +17 -17
  25. package/docs/guides-translating-documentation.md +1 -1
  26. package/docs/guides-translating-documentation.zh-TW.md +21 -21
  27. package/docs/guides-translating-documentation.zh.md +18 -18
  28. package/docs/guides-updating-documentation.ja.md +35 -35
  29. package/docs/guides-updating-documentation.md +4 -4
  30. package/docs/guides-updating-documentation.zh-TW.md +27 -27
  31. package/docs/guides-updating-documentation.zh.md +26 -26
  32. package/docs/overview.ja.md +13 -13
  33. package/docs/overview.md +1 -1
  34. package/docs/overview.zh-TW.md +19 -19
  35. package/docs/overview.zh.md +16 -16
  36. package/package.json +1 -1
  37. package/prompts/common/afs/afs-tools-usage.md +5 -0
  38. package/prompts/common/afs/use-afs-instruction.md +1 -0
  39. package/prompts/detail/generate/system-prompt.md +0 -13
  40. package/prompts/detail/generate/user-prompt.md +7 -0
  41. package/prompts/detail/update/system-prompt.md +1 -2
  42. package/prompts/detail/update/user-prompt.md +7 -0
  43. package/prompts/structure/generate/system-prompt.md +0 -19
  44. package/prompts/structure/generate/user-prompt.md +22 -1
  45. package/prompts/structure/update/system-prompt.md +0 -17
  46. package/prompts/structure/update/user-prompt.md +24 -0
  47. package/tests/agents/history/view.test.mjs +97 -0
  48. package/tests/agents/publish/publish-docs.test.mjs +0 -33
  49. package/tests/utils/history-utils.test.mjs +125 -97
  50. package/utils/auth-utils.mjs +2 -2
  51. package/utils/file-utils.mjs +1 -1
  52. package/utils/history-utils.mjs +3 -3
  53. package/agents/update/fs-tools/glob.mjs +0 -184
  54. package/agents/update/fs-tools/grep.mjs +0 -317
  55. package/agents/update/fs-tools/read-file.mjs +0 -309
  56. package/tests/agents/update/fs-tools/glob.test.mjs +0 -438
  57. package/tests/agents/update/fs-tools/grep.test.mjs +0 -279
  58. package/tests/agents/update/fs-tools/read-file.test.mjs +0 -549
@@ -446,39 +446,6 @@ describe("publish-docs", () => {
446
446
  expect(saveValueToConfigSpy).not.toHaveBeenCalledWith("boardId", expect.anything());
447
447
  });
448
448
 
449
- // ERROR HANDLING TESTS
450
- test("should handle failed official access token (null)", async () => {
451
- loadConfigFromFileSpy.mockResolvedValue({});
452
- getOfficialAccessTokenSpy.mockResolvedValue(null);
453
- mockOptions.prompts.select.mockResolvedValue("default");
454
-
455
- const result = await publishDocs(
456
- {
457
- docsDir: "./docs",
458
- appUrl: "https://docsmith.aigne.io",
459
- },
460
- mockOptions,
461
- );
462
-
463
- expect(result.message).toBe("❌ Failed to publish docs: Failed to get official access token");
464
- });
465
-
466
- test("should handle failed official access token (undefined)", async () => {
467
- loadConfigFromFileSpy.mockResolvedValue({});
468
- getOfficialAccessTokenSpy.mockResolvedValue(undefined);
469
- mockOptions.prompts.select.mockResolvedValue("default");
470
-
471
- const result = await publishDocs(
472
- {
473
- docsDir: "./docs",
474
- appUrl: "https://docsmith.aigne.io",
475
- },
476
- mockOptions,
477
- );
478
-
479
- expect(result.message).toBe("❌ Failed to publish docs: Failed to get official access token");
480
- });
481
-
482
449
  test("should handle checkCacheSession failure", async () => {
483
450
  loadConfigFromFileSpy.mockResolvedValue({});
484
451
  getOfficialAccessTokenSpy.mockResolvedValue("valid-token");
@@ -1,14 +1,17 @@
1
- import { afterEach, beforeEach, describe, expect, test } from "bun:test";
1
+ import { afterEach, beforeEach, describe, expect, test, mock, spyOn } from "bun:test";
2
2
  import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
3
3
  import { join } from "node:path";
4
4
  import { DOC_SMITH_DIR } from "../../utils/constants/index.mjs";
5
- import { getHistory, isGitAvailable, recordUpdate } from "../../utils/history-utils.mjs";
5
+ import { recordUpdate, getHistory } from "../../utils/history-utils.mjs";
6
6
 
7
+ // Mock the child_process module
7
8
  const TEST_DIR = join(process.cwd(), `${DOC_SMITH_DIR}-test`);
8
9
  const ORIGINAL_CWD = process.cwd();
9
10
 
10
- describe("History Utils - Unified", () => {
11
- beforeEach(() => {
11
+ describe("History Utils", () => {
12
+ let execSyncMock;
13
+
14
+ beforeEach(async () => {
12
15
  // Clean up test directory
13
16
  if (existsSync(TEST_DIR)) {
14
17
  rmSync(TEST_DIR, { recursive: true });
@@ -17,6 +20,9 @@ describe("History Utils - Unified", () => {
17
20
 
18
21
  // Change to test directory
19
22
  process.chdir(TEST_DIR);
23
+
24
+ // Get the mocked execSync
25
+ execSyncMock = spyOn(await import("node:child_process"), "execSync");
20
26
  });
21
27
 
22
28
  afterEach(() => {
@@ -27,11 +33,8 @@ describe("History Utils - Unified", () => {
27
33
  if (existsSync(TEST_DIR)) {
28
34
  rmSync(TEST_DIR, { recursive: true });
29
35
  }
30
- });
31
36
 
32
- test("detects git availability", () => {
33
- const hasGit = isGitAvailable();
34
- expect(typeof hasGit).toBe("boolean");
37
+ mock.restore();
35
38
  });
36
39
 
37
40
  test("skips recording on empty feedback", () => {
@@ -46,133 +49,158 @@ describe("History Utils - Unified", () => {
46
49
  expect(history.entries.length).toBe(0);
47
50
  });
48
51
 
49
- test("records update in YAML", () => {
52
+ test("git not available - write to YAML only", () => {
53
+ // Mock git as not available
54
+ execSyncMock.mockImplementation((command) => {
55
+ if (command === "git --version") {
56
+ throw new Error("git: command not found");
57
+ }
58
+ throw new Error("Unknown command");
59
+ });
60
+
61
+ // Record update
50
62
  recordUpdate({
51
- operation: "structure_update",
63
+ operation: "document_update",
52
64
  feedback: "Test feedback",
65
+ documentPath: "/test",
53
66
  });
54
67
 
68
+ // Verify YAML record was created
55
69
  const history = getHistory();
56
70
  expect(history.entries.length).toBe(1);
57
71
  expect(history.entries[0].feedback).toBe("Test feedback");
58
- expect(history.entries[0].operation).toBe("structure_update");
72
+ expect(history.entries[0].operation).toBe("document_update");
73
+ expect(history.entries[0].documentPath).toBe("/test");
59
74
  expect(history.entries[0].timestamp).toBeDefined();
60
- });
61
-
62
- test("records document path when provided as string", () => {
63
- recordUpdate({
64
- operation: "document_update",
65
- feedback: "Update document",
66
- documentPath: "/getting-started",
67
- });
68
75
 
69
- const history = getHistory();
70
- expect(history.entries.length).toBe(1);
71
- expect(history.entries[0].documentPath).toBe("/getting-started");
76
+ // Verify no git repository was created
77
+ const gitDir = join(process.cwd(), DOC_SMITH_DIR, ".git");
78
+ expect(existsSync(gitDir)).toBe(false);
72
79
  });
73
80
 
74
- test("records single document path for each update", () => {
75
- recordUpdate({
76
- operation: "document_update",
77
- feedback: "Update single document",
78
- documentPath: "/getting-started",
81
+ test("current directory is git repo - skip git integration", () => {
82
+ // Mock git as available and in repo
83
+ execSyncMock.mockImplementation((command) => {
84
+ if (command === "git --version") {
85
+ return "git version 2.30.0";
86
+ }
87
+ if (command === "git rev-parse --is-inside-work-tree") {
88
+ return "true";
89
+ }
90
+ throw new Error("Unknown command");
79
91
  });
80
92
 
81
- const history = getHistory();
82
- expect(history.entries.length).toBe(1);
83
- expect(history.entries[0].feedback).toBe("Update single document");
84
- expect(history.entries[0].documentPath).toBe("/getting-started");
85
- });
86
-
87
- test("does not include documentPath field when documentPath is null", () => {
93
+ // Record update
88
94
  recordUpdate({
89
95
  operation: "structure_update",
90
- feedback: "Update structure",
91
- documentPath: null,
96
+ feedback: "Structure update",
92
97
  });
93
98
 
99
+ // Verify YAML record was created
94
100
  const history = getHistory();
95
101
  expect(history.entries.length).toBe(1);
96
- expect(history.entries[0].documentPath).toBeUndefined();
102
+ expect(history.entries[0].feedback).toBe("Structure update");
103
+
104
+ // Verify no new git repository was created (since we're already in a git repo)
105
+ const gitDir = join(process.cwd(), DOC_SMITH_DIR, ".git");
106
+ expect(existsSync(gitDir)).toBe(false);
97
107
  });
98
108
 
99
- test("maintains chronological order (newest first)", () => {
100
- recordUpdate({ operation: "structure_update", feedback: "First" });
101
- // Small delay to ensure different timestamps
102
- const now = Date.now();
103
- while (Date.now() === now) {
104
- // Wait for next millisecond
105
- }
106
- recordUpdate({ operation: "document_update", feedback: "Second" });
109
+ test("write YAML records and commit to git", () => {
110
+ // Ensure the DOC_SMITH_DIR exists
111
+ const docSmithDir = join(process.cwd(), DOC_SMITH_DIR);
112
+ mkdirSync(docSmithDir, { recursive: true });
113
+
114
+ // Mock git as available but not in repo
115
+ execSyncMock.mockImplementation((command) => {
116
+ if (command === "git --version") {
117
+ return "git version 2.30.0";
118
+ }
119
+ if (command === "git rev-parse --is-inside-work-tree") {
120
+ throw new Error("not a git repository");
121
+ }
122
+ if (command === "git init") {
123
+ return "Initialized empty Git repository";
124
+ }
125
+ if (command === 'git add .gitignore && git commit -m "Initialize doc-smith history"') {
126
+ return "Initial commit";
127
+ }
128
+ if (command === "git add docs/ config.yaml preferences.yml history.yaml") {
129
+ return "Files added";
130
+ }
131
+ if (command === "git diff --cached --quiet") {
132
+ throw new Error("Has changes");
133
+ }
134
+ if (command === 'git commit -m "First update"') {
135
+ return "Commit successful";
136
+ }
137
+ if (command === 'git commit -m "Second update"') {
138
+ return "Commit successful";
139
+ }
140
+ throw new Error("Unknown command: ", command);
141
+ });
107
142
 
108
- const history = getHistory();
109
- expect(history.entries.length).toBe(2);
110
- expect(history.entries[0].feedback).toBe("Second");
111
- expect(history.entries[1].feedback).toBe("First");
112
- });
143
+ // Record multiple updates - this should trigger git repo creation and commits
144
+ recordUpdate({
145
+ operation: "document_update",
146
+ feedback: "First update",
147
+ documentPath: "/first",
148
+ });
113
149
 
114
- test("handles multiple updates", () => {
115
- recordUpdate({ operation: "structure_update", feedback: "Update 1" });
116
- recordUpdate({ operation: "document_update", feedback: "Update 2", documentPath: "/home" });
117
- recordUpdate({ operation: "document_update", feedback: "Update 3", documentPath: "/about" });
118
150
  recordUpdate({
119
151
  operation: "translation_update",
120
- feedback: "Update 4",
121
- documentPath: "/api",
152
+ feedback: "Second update",
153
+ documentPath: "/second",
122
154
  });
123
155
 
156
+ // Verify YAML records
124
157
  const history = getHistory();
125
- expect(history.entries.length).toBe(4);
126
- expect(history.entries[0].feedback).toBe("Update 4");
127
- expect(history.entries[0].documentPath).toBe("/api");
128
- expect(history.entries[1].feedback).toBe("Update 3");
129
- expect(history.entries[1].documentPath).toBe("/about");
130
- expect(history.entries[2].feedback).toBe("Update 2");
131
- expect(history.entries[2].documentPath).toBe("/home");
132
- expect(history.entries[3].feedback).toBe("Update 1");
158
+ expect(history.entries.length).toBe(2);
159
+ expect(history.entries[0].feedback).toBe("Second update"); // Newest first
160
+ expect(history.entries[1].feedback).toBe("First update");
161
+
162
+ // Verify git commands were called
163
+ expect(execSyncMock).toHaveBeenCalledWith("git --version", { stdio: "ignore" });
164
+ expect(execSyncMock).toHaveBeenCalledWith("git rev-parse --is-inside-work-tree", {
165
+ cwd: process.cwd(),
166
+ stdio: "pipe",
167
+ encoding: "utf8",
168
+ });
169
+ expect(execSyncMock).toHaveBeenCalledWith("git init", {
170
+ cwd: join(process.cwd(), DOC_SMITH_DIR),
171
+ stdio: "ignore",
172
+ });
133
173
  });
134
174
 
135
- test("returns empty history when file does not exist", () => {
136
- const history = getHistory();
175
+ test("query history.yaml - handle various scenarios", () => {
176
+ // Test empty history
177
+ let history = getHistory();
137
178
  expect(history.entries).toBeDefined();
138
179
  expect(history.entries.length).toBe(0);
139
- });
140
180
 
141
- test("handles corrupted history file gracefully", () => {
142
- // Create corrupted YAML file
181
+ // Test corrupted YAML file
143
182
  const historyPath = join(process.cwd(), DOC_SMITH_DIR, "history.yaml");
144
183
  mkdirSync(join(process.cwd(), DOC_SMITH_DIR), { recursive: true });
145
- writeFileSync(historyPath, "invalid: yaml: content: [[[", "utf8");
184
+ writeFileSync(historyPath, "invalid: yaml: content: 「「「", "utf8");
146
185
 
147
- const history = getHistory();
186
+ history = getHistory();
148
187
  expect(history.entries).toBeDefined();
149
188
  expect(history.entries.length).toBe(0);
150
- });
151
-
152
- test(`creates ${DOC_SMITH_DIR} directory if not exists`, () => {
153
- recordUpdate({
154
- operation: "document_update",
155
- feedback: "Test",
156
- });
157
189
 
158
- const docSmithDir = join(process.cwd(), DOC_SMITH_DIR);
159
- expect(existsSync(docSmithDir)).toBe(true);
160
- });
161
-
162
- test("timestamp is in ISO 8601 format", () => {
163
- recordUpdate({
164
- operation: "structure_update",
165
- feedback: "Test timestamp",
166
- });
167
-
168
- const history = getHistory();
169
- const timestamp = history.entries[0].timestamp;
170
-
171
- // Validate ISO 8601 format
172
- expect(timestamp).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/);
173
-
174
- // Validate it's a valid date
175
- const date = new Date(timestamp);
176
- expect(date.toISOString()).toBe(timestamp);
190
+ // Test valid history
191
+ const validHistory = {
192
+ entries: [
193
+ {
194
+ timestamp: "2023-01-01T00:00:00.000Z",
195
+ operation: "document_update",
196
+ feedback: "Valid entry",
197
+ },
198
+ ],
199
+ };
200
+ writeFileSync(historyPath, JSON.stringify(validHistory), "utf8");
201
+
202
+ history = getHistory();
203
+ expect(history.entries.length).toBe(1);
204
+ expect(history.entries[0].feedback).toBe("Valid entry");
177
205
  });
178
206
  });
@@ -157,7 +157,7 @@ export async function getAccessToken(appUrl, ltToken = "") {
157
157
  * @param {string} baseUrl - The official service URL
158
158
  * @returns {Promise<string>} - The access token
159
159
  */
160
- export async function getOfficialAccessToken(baseUrl) {
160
+ export async function getOfficialAccessToken(baseUrl, openPage = true) {
161
161
  // Early parameter validation
162
162
  if (!baseUrl) {
163
163
  throw new Error("baseUrl parameter is required for getOfficialAccessToken.");
@@ -188,7 +188,7 @@ export async function getOfficialAccessToken(baseUrl) {
188
188
  }
189
189
 
190
190
  // If token is found, return it
191
- if (accessToken) {
191
+ if (accessToken || !openPage) {
192
192
  return accessToken;
193
193
  }
194
194
 
@@ -12,7 +12,7 @@ import { INTELLIGENT_SUGGESTION_TOKEN_THRESHOLD } from "./constants/index.mjs";
12
12
  * @param {string} dir - Directory path to check
13
13
  * @returns {boolean} True if inside a git repository
14
14
  */
15
- function isInGitRepository(dir) {
15
+ export function isInGitRepository(dir) {
16
16
  try {
17
17
  execSync("git rev-parse --is-inside-work-tree", {
18
18
  cwd: dir,
@@ -3,6 +3,7 @@ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
3
3
  import { join } from "node:path";
4
4
  import { parse, stringify } from "yaml";
5
5
  import { DOC_SMITH_DIR } from "./constants/index.mjs";
6
+ import { isInGitRepository } from "./file-utils.mjs";
6
7
 
7
8
  const HISTORY_FILE = "history.yaml";
8
9
 
@@ -161,9 +162,8 @@ export function recordUpdate({ operation, feedback, documentPath = null }) {
161
162
  // Always record in YAML
162
163
  recordUpdateYaml({ operation, feedback, documentPath });
163
164
 
164
- // Also record in git if available
165
- if (isGitAvailable()) {
166
- // Initialize git repo on first update if not exists
165
+ // Also record in git if git is available and not in a git repository
166
+ if (isGitAvailable() && !isInGitRepository(process.cwd())) {
167
167
  ensureGitRepo();
168
168
  recordUpdateGit({ feedback });
169
169
  } else {
@@ -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
- };